From a9a4ff61c6e8b24dc59a13f226cde17169f67098 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Wed, 13 Dec 2017 17:01:39 +0100 Subject: [PATCH 01/59] :rotating_light: remove C4996 warnings #872 These were the remaining direct calls to alloc. --- src/json.hpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index b0c85dc1..ba533ccc 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -8028,7 +8028,6 @@ class basic_json static T* create(Args&& ... args) { AllocatorType alloc; - using AllocatorTraits = std::allocator_traits>; auto deleter = [&](T * object) @@ -10719,8 +10718,8 @@ class basic_json if (is_string()) { AllocatorType alloc; - alloc.destroy(m_value.string); - alloc.deallocate(m_value.string, 1); + std::allocator_traits::destroy(alloc, m_value.string); + std::allocator_traits::deallocate(alloc, m_value.string, 1); m_value.string = nullptr; } @@ -10825,8 +10824,8 @@ class basic_json if (is_string()) { AllocatorType alloc; - alloc.destroy(m_value.string); - alloc.deallocate(m_value.string, 1); + std::allocator_traits::destroy(alloc, m_value.string); + std::allocator_traits::deallocate(alloc, m_value.string, 1); m_value.string = nullptr; } From e8d9963abe34a5bd2ef0431f26a88cb0a6ddfac5 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Wed, 13 Dec 2017 22:15:53 +0100 Subject: [PATCH 02/59] :ok_hand: cosmetic changes and overworked spelling - All hex literals use upper case letters after the x. - Fixed sime typos. - Documented some more functions. --- src/json.hpp | 1422 +++++++++++++++++++++++++------------------------- 1 file changed, 703 insertions(+), 719 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index b0c85dc1..1f06b6dd 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -109,7 +109,7 @@ SOFTWARE. #define JSON_UNLIKELY(x) x #endif -// cpp language standard detection +// C++ language standard detection #if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 #define JSON_HAS_CPP_17 #define JSON_HAS_CPP_14 @@ -128,20 +128,18 @@ template struct adl_serializer; // forward declaration of basic_json (required to split the class) -template class ObjectType = - std::map, - template class ArrayType = std::vector, +template class ObjectType = std::map, + template class ArrayType = std::vector, class StringType = std::string, class BooleanType = bool, class NumberIntegerType = std::int64_t, class NumberUnsignedType = std::uint64_t, class NumberFloatType = double, - template class AllocatorType = std::allocator, - template class JSONSerializer = - adl_serializer> + template class AllocatorType = std::allocator, + template class JSONSerializer = adl_serializer> class basic_json; -// Ugly macros to avoid uglier copy-paste when specializing basic_json -// This is only temporary and will be removed in 3.0 +// Ugly macros to avoid uglier copy-paste when specializing basic_json. They +// may be removed in the future once the class is split. #define NLOHMANN_BASIC_JSON_TPL_DECLARATION \ template class ObjectType, \ @@ -248,7 +246,7 @@ json.exception.parse_error.107 | parse error: JSON pointer must be empty or begi json.exception.parse_error.108 | parse error: escape character '~' must be followed with '0' or '1' | In a JSON Pointer, only `~0` and `~1` are valid escape sequences. json.exception.parse_error.109 | parse error: array index 'one' is not a number | A JSON Pointer array index must be a number. json.exception.parse_error.110 | parse error at 1: cannot read 2 bytes from vector | When parsing CBOR or MessagePack, the byte vector ends before the complete value has been read. -json.exception.parse_error.112 | parse error at 1: error reading CBOR; last byte: 0xf8 | Not all types of CBOR or MessagePack are supported. This exception occurs if an unsupported byte was read. +json.exception.parse_error.112 | parse error at 1: error reading CBOR; last byte: 0xF8 | Not all types of CBOR or MessagePack are supported. This exception occurs if an unsupported byte was read. json.exception.parse_error.113 | parse error at 2: expected a CBOR string; last byte: 0x98 | While parsing a map key, a value that is not a string has been read. @note For an input with n bytes, 1 is the index of the first character and n+1 @@ -541,20 +539,14 @@ Returns an ordering that is similar to Python: inline bool operator<(const value_t lhs, const value_t rhs) noexcept { static constexpr std::array order = {{ - 0, // null - 3, // object - 4, // array - 5, // string - 1, // boolean - 2, // integer - 2, // unsigned - 2, // float + 0 /* null */, 3 /* object */, 4 /* array */, 5 /* string */, + 1 /* boolean */, 2 /* integer */, 2 /* unsigned */, 2 /* float */ } }; const auto l_index = static_cast(lhs); const auto r_index = static_cast(rhs); - return (l_index < order.size() and r_index < order.size() and order[l_index] < order[r_index]); + return l_index < order.size() and r_index < order.size() and order[l_index] < order[r_index]; } @@ -592,17 +584,15 @@ struct merge_and_renumber; template struct merge_and_renumber, index_sequence> - : index_sequence < I1..., (sizeof...(I1) + I2)... > - {}; + : index_sequence < I1..., (sizeof...(I1) + I2)... > {}; template struct make_index_sequence : merge_and_renumber < typename make_index_sequence < N / 2 >::type, - typename make_index_sequence < N - N / 2 >::type > -{}; + typename make_index_sequence < N - N / 2 >::type > {}; -template<> struct make_index_sequence<0> : index_sequence<> { }; -template<> struct make_index_sequence<1> : index_sequence<0> { }; +template<> struct make_index_sequence<0> : index_sequence<> {}; +template<> struct make_index_sequence<1> : index_sequence<0> {}; template using index_sequence_for = make_index_sequence; @@ -625,7 +615,7 @@ template struct conjunction : B1 {}; template struct conjunction : std::conditional, B1>::type {}; -template struct negation : std::integral_constant < bool, !B::value > {}; +template struct negation : std::integral_constant {}; // dispatch utility (taken from ranges-v3) template struct priority_tag : priority_tag < N - 1 > {}; @@ -726,8 +716,7 @@ struct external_constructor } template::value, + enable_if_t::value, int> = 0> static void construct(BasicJsonType& j, const CompatibleArrayType& arr) { @@ -783,8 +772,7 @@ struct external_constructor } template::value, int> = 0> + enable_if_t::value, int> = 0> static void construct(BasicJsonType& j, const CompatibleObjectType& obj) { using std::begin; @@ -897,7 +885,7 @@ struct is_compatible_integer_type is_compatible_integer_type_impl < std::is_integral::value and not std::is_same::value, - RealIntegerType, CompatibleNumberIntegerType > ::value; + RealIntegerType, CompatibleNumberIntegerType >::value; }; @@ -923,10 +911,8 @@ template struct has_non_default_from_json { private: - template < - typename U, - typename = enable_if_t::from_json(std::declval()))>::value >> + template::from_json(std::declval()))>::value>> static int detect(U&&); static void detect(...); @@ -955,22 +941,21 @@ struct has_to_json // to_json // ///////////// -template::value, int> = 0> +template::value, int> = 0> void to_json(BasicJsonType& j, T b) noexcept { external_constructor::construct(j, b); } template::value, int> = 0> + enable_if_t::value, int> = 0> void to_json(BasicJsonType& j, const CompatibleString& s) { external_constructor::construct(j, s); } -template +template void to_json(BasicJsonType& j, typename BasicJsonType::string_t&& s) { external_constructor::construct(j, std::move(s)); @@ -983,19 +968,15 @@ void to_json(BasicJsonType& j, FloatType val) noexcept external_constructor::construct(j, static_cast(val)); } -template < - typename BasicJsonType, typename CompatibleNumberUnsignedType, - enable_if_t::value, int> = 0 > +template::value, int> = 0> void to_json(BasicJsonType& j, CompatibleNumberUnsignedType val) noexcept { external_constructor::construct(j, static_cast(val)); } -template < - typename BasicJsonType, typename CompatibleNumberIntegerType, - enable_if_t::value, int> = 0 > +template::value, int> = 0> void to_json(BasicJsonType& j, CompatibleNumberIntegerType val) noexcept { external_constructor::construct(j, static_cast(val)); @@ -1015,49 +996,44 @@ void to_json(BasicJsonType& j, const std::vector& e) external_constructor::construct(j, e); } -template < - typename BasicJsonType, typename CompatibleArrayType, - enable_if_t < - is_compatible_array_type::value or - std::is_same::value, - int > = 0 > +template::value or + std::is_same::value, + int> = 0> void to_json(BasicJsonType& j, const CompatibleArrayType& arr) { external_constructor::construct(j, arr); } -template ::value, int> = 0> +template::value, int> = 0> void to_json(BasicJsonType& j, std::valarray arr) { external_constructor::construct(j, std::move(arr)); } -template +template void to_json(BasicJsonType& j, typename BasicJsonType::array_t&& arr) { external_constructor::construct(j, std::move(arr)); } -template < - typename BasicJsonType, typename CompatibleObjectType, - enable_if_t::value, - int> = 0 > +template::value, int> = 0> void to_json(BasicJsonType& j, const CompatibleObjectType& obj) { external_constructor::construct(j, obj); } -template +template void to_json(BasicJsonType& j, typename BasicJsonType::object_t&& obj) { external_constructor::construct(j, std::move(obj)); } template::value, - int> = 0> + enable_if_t::value, int> = 0> void to_json(BasicJsonType& j, T (&arr)[N]) { external_constructor::construct(j, arr); @@ -1088,8 +1064,7 @@ void to_json(BasicJsonType& j, const std::tuple& t) // overloads for basic_json template parameters template::value and - not std::is_same::value, + not std::is_same::value, int> = 0> void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val) { @@ -1354,10 +1329,10 @@ struct to_json_fn "could not find to_json() method in T's namespace"); #ifdef _MSC_VER - // Visual Studio does not show a stacktrace for the above assert. + // MSVC does not show a stacktrace for the above assert using decayed = uncvref_t; static_assert(sizeof(typename decayed::force_msvc_stacktrace) == 0, - "forcing msvc stacktrace to show which T we're talking about."); + "forcing MSVC stacktrace to show which T we're talking about."); #endif } @@ -1387,10 +1362,10 @@ struct from_json_fn static_assert(sizeof(BasicJsonType) == 0, "could not find from_json() method in T's namespace"); #ifdef _MSC_VER - // Visual Studio does not show a stacktrace for the above assert. + // MSVC does not show a stacktrace for the above assert using decayed = uncvref_t; static_assert(sizeof(typename decayed::force_msvc_stacktrace) == 0, - "forcing msvc stacktrace to show which T we're talking about."); + "forcing MSVC stacktrace to show which T we're talking about."); #endif } @@ -1462,7 +1437,7 @@ class input_stream_adapter : public input_adapter_protocol explicit input_stream_adapter(std::istream& i) : is(i), sb(*i.rdbuf()) { - // ignore Byte Order Mark at start of input + // skip byte order mark std::char_traits::int_type c; if ((c = get_character()) == 0xEF) { @@ -1486,7 +1461,7 @@ class input_stream_adapter : public input_adapter_protocol } else if (c != std::char_traits::eof()) { - is.unget(); // Not BOM. Process as usual. + is.unget(); // no byte order mark; process as usual } } @@ -1495,8 +1470,8 @@ class input_stream_adapter : public input_adapter_protocol input_stream_adapter& operator=(input_stream_adapter&) = delete; // std::istream/std::streambuf use std::char_traits::to_int_type, to - // ensure that std::char_traits::eof() and the character 0xff do not - // end up as the same value, eg. 0xffffffff. + // ensure that std::char_traits::eof() and the character 0xFF do not + // end up as the same value, eg. 0xFFFFFFFF. std::char_traits::int_type get_character() override { return sb.sbumpc(); @@ -1575,8 +1550,7 @@ class input_adapter template::value and - std::is_integral< - typename std::remove_pointer::type>::value and + std::is_integral::type>::value and sizeof(typename std::remove_pointer::type) == 1, int>::type = 0> input_adapter(CharT b, std::size_t l) @@ -1588,8 +1562,7 @@ class input_adapter template::value and - std::is_integral< - typename std::remove_pointer::type>::value and + std::is_integral::type>::value and sizeof(typename std::remove_pointer::type) == 1, int>::type = 0> input_adapter(CharT b) @@ -1599,8 +1572,7 @@ class input_adapter /// input adapter for iterator range with contiguous storage template::iterator_category, - std::random_access_iterator_tag>::value, + std::is_same::iterator_category, std::random_access_iterator_tag>::value, int>::type = 0> input_adapter(IteratorType first, IteratorType last) { @@ -1638,13 +1610,12 @@ class input_adapter : input_adapter(std::begin(array), std::end(array)) {} /// input adapter for contiguous container - template < - class ContiguousContainer, - typename std::enable_if < - not std::is_pointer::value and - std::is_base_of()))>::iterator_category>::value, - int >::type = 0 > + template::value and + std::is_base_of()))>::iterator_category>::value, + int>::type = 0> input_adapter(const ContiguousContainer& c) : input_adapter(std::begin(c), std::end(c)) {} @@ -1818,6 +1789,12 @@ class lexer checks if it is inside the range. If a violation was detected, set up an error message and return false. Otherwise, return true. + @param[in] ranges list of integers; interpreted as list of pairs of + inclusive lower and upper bound, respectively + + @pre The passed list @a ranges must have 2, 4, or 6 elements; that is, + 1, 2, or 3 pairs. This precondition is enforced by an assertion. + @return true if and only if no range violation was detected */ bool next_byte_in_range(std::initializer_list ranges) @@ -1984,19 +1961,19 @@ class lexer // result of the above calculation yields a proper codepoint assert(0x00 <= codepoint and codepoint <= 0x10FFFF); - // translate code point to bytes + // translate codepoint into bytes if (codepoint < 0x80) { // 1-byte characters: 0xxxxxxx (ASCII) add(codepoint); } - else if (codepoint <= 0x7ff) + else if (codepoint <= 0x7FF) { // 2-byte characters: 110xxxxx 10xxxxxx add(0xC0 | (codepoint >> 6)); add(0x80 | (codepoint & 0x3F)); } - else if (codepoint <= 0xffff) + else if (codepoint <= 0xFFFF) { // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx add(0xE0 | (codepoint >> 12)); @@ -2035,12 +2012,12 @@ class lexer case 0x07: case 0x08: case 0x09: - case 0x0a: - case 0x0b: - case 0x0c: - case 0x0d: - case 0x0e: - case 0x0f: + case 0x0A: + case 0x0B: + case 0x0C: + case 0x0D: + case 0x0E: + case 0x0F: case 0x10: case 0x11: case 0x12: @@ -2051,12 +2028,12 @@ class lexer case 0x17: case 0x18: case 0x19: - case 0x1a: - case 0x1b: - case 0x1c: - case 0x1d: - case 0x1e: - case 0x1f: + case 0x1A: + case 0x1B: + case 0x1C: + case 0x1D: + case 0x1E: + case 0x1F: { error_message = "invalid string: control character must be escaped"; return token_type::parse_error; @@ -2072,12 +2049,12 @@ class lexer case 0x27: case 0x28: case 0x29: - case 0x2a: - case 0x2b: - case 0x2c: - case 0x2d: - case 0x2e: - case 0x2f: + case 0x2A: + case 0x2B: + case 0x2C: + case 0x2D: + case 0x2E: + case 0x2F: case 0x30: case 0x31: case 0x32: @@ -2088,12 +2065,12 @@ class lexer case 0x37: case 0x38: case 0x39: - case 0x3a: - case 0x3b: - case 0x3c: - case 0x3d: - case 0x3e: - case 0x3f: + case 0x3A: + case 0x3B: + case 0x3C: + case 0x3D: + case 0x3E: + case 0x3F: case 0x40: case 0x41: case 0x42: @@ -2104,12 +2081,12 @@ class lexer case 0x47: case 0x48: case 0x49: - case 0x4a: - case 0x4b: - case 0x4c: - case 0x4d: - case 0x4e: - case 0x4f: + case 0x4A: + case 0x4B: + case 0x4C: + case 0x4D: + case 0x4E: + case 0x4F: case 0x50: case 0x51: case 0x52: @@ -2120,11 +2097,11 @@ class lexer case 0x57: case 0x58: case 0x59: - case 0x5a: - case 0x5b: - case 0x5d: - case 0x5e: - case 0x5f: + case 0x5A: + case 0x5B: + case 0x5D: + case 0x5E: + case 0x5F: case 0x60: case 0x61: case 0x62: @@ -2135,12 +2112,12 @@ class lexer case 0x67: case 0x68: case 0x69: - case 0x6a: - case 0x6b: - case 0x6c: - case 0x6d: - case 0x6e: - case 0x6f: + case 0x6A: + case 0x6B: + case 0x6C: + case 0x6D: + case 0x6E: + case 0x6F: case 0x70: case 0x71: case 0x72: @@ -2151,48 +2128,48 @@ class lexer case 0x77: case 0x78: case 0x79: - case 0x7a: - case 0x7b: - case 0x7c: - case 0x7d: - case 0x7e: - case 0x7f: + case 0x7A: + case 0x7B: + case 0x7C: + case 0x7D: + case 0x7E: + case 0x7F: { add(current); break; } // U+0080..U+07FF: bytes C2..DF 80..BF - case 0xc2: - case 0xc3: - case 0xc4: - case 0xc5: - case 0xc6: - case 0xc7: - case 0xc8: - case 0xc9: - case 0xca: - case 0xcb: - case 0xcc: - case 0xcd: - case 0xce: - case 0xcf: - case 0xd0: - case 0xd1: - case 0xd2: - case 0xd3: - case 0xd4: - case 0xd5: - case 0xd6: - case 0xd7: - case 0xd8: - case 0xd9: - case 0xda: - case 0xdb: - case 0xdc: - case 0xdd: - case 0xde: - case 0xdf: + case 0xC2: + case 0xC3: + case 0xC4: + case 0xC5: + case 0xC6: + case 0xC7: + case 0xC8: + case 0xC9: + case 0xCA: + case 0xCB: + case 0xCC: + case 0xCD: + case 0xCE: + case 0xCF: + case 0xD0: + case 0xD1: + case 0xD2: + case 0xD3: + case 0xD4: + case 0xD5: + case 0xD6: + case 0xD7: + case 0xD8: + case 0xD9: + case 0xDA: + case 0xDB: + case 0xDC: + case 0xDD: + case 0xDE: + case 0xDF: { if (JSON_UNLIKELY(not next_byte_in_range({0x80, 0xBF}))) { @@ -2202,7 +2179,7 @@ class lexer } // U+0800..U+0FFF: bytes E0 A0..BF 80..BF - case 0xe0: + case 0xE0: { if (JSON_UNLIKELY(not (next_byte_in_range({0xA0, 0xBF, 0x80, 0xBF})))) { @@ -2213,20 +2190,20 @@ class lexer // U+1000..U+CFFF: bytes E1..EC 80..BF 80..BF // U+E000..U+FFFF: bytes EE..EF 80..BF 80..BF - case 0xe1: - case 0xe2: - case 0xe3: - case 0xe4: - case 0xe5: - case 0xe6: - case 0xe7: - case 0xe8: - case 0xe9: - case 0xea: - case 0xeb: - case 0xec: - case 0xee: - case 0xef: + case 0xE1: + case 0xE2: + case 0xE3: + case 0xE4: + case 0xE5: + case 0xE6: + case 0xE7: + case 0xE8: + case 0xE9: + case 0xEA: + case 0xEB: + case 0xEC: + case 0xEE: + case 0xEF: { if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0xBF, 0x80, 0xBF})))) { @@ -2236,7 +2213,7 @@ class lexer } // U+D000..U+D7FF: bytes ED 80..9F 80..BF - case 0xed: + case 0xED: { if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0x9F, 0x80, 0xBF})))) { @@ -2246,7 +2223,7 @@ class lexer } // U+10000..U+3FFFF F0 90..BF 80..BF 80..BF - case 0xf0: + case 0xF0: { if (JSON_UNLIKELY(not (next_byte_in_range({0x90, 0xBF, 0x80, 0xBF, 0x80, 0xBF})))) { @@ -2256,9 +2233,9 @@ class lexer } // U+40000..U+FFFFF F1..F3 80..BF 80..BF 80..BF - case 0xf1: - case 0xf2: - case 0xf3: + case 0xF1: + case 0xF2: + case 0xF3: { if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0xBF, 0x80, 0xBF, 0x80, 0xBF})))) { @@ -2268,7 +2245,7 @@ class lexer } // U+100000..U+10FFFF F4 80..8F 80..BF 80..BF - case 0xf4: + case 0xF4: { if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0x8F, 0x80, 0xBF, 0x80, 0xBF})))) { @@ -2788,7 +2765,7 @@ scan_number_done: std::string result; for (auto c : token_string) { - if ('\x00' <= c and c <= '\x1f') + if ('\x00' <= c and c <= '\x1F') { // escape control characters std::stringstream ss; @@ -2891,10 +2868,10 @@ scan_number_done: std::size_t chars_read = 0; /// raw input token string (for error messages) - std::vector token_string { }; + std::vector token_string {}; /// buffer for variable-length tokens (numbers, strings) - std::string yytext { }; + std::string yytext {}; /// a description of occurred lexer errors const char* error_message = ""; @@ -4598,12 +4575,12 @@ class binary_reader case 0x07: case 0x08: case 0x09: - case 0x0a: - case 0x0b: - case 0x0c: - case 0x0d: - case 0x0e: - case 0x0f: + case 0x0A: + case 0x0B: + case 0x0C: + case 0x0D: + case 0x0E: + case 0x0F: case 0x10: case 0x11: case 0x12: @@ -4620,10 +4597,10 @@ class binary_reader case 0x19: // Unsigned integer (two-byte uint16_t follows) return get_number(); - case 0x1a: // Unsigned integer (four-byte uint32_t follows) + case 0x1A: // Unsigned integer (four-byte uint32_t follows) return get_number(); - case 0x1b: // Unsigned integer (eight-byte uint64_t follows) + case 0x1B: // Unsigned integer (eight-byte uint64_t follows) return get_number(); // Negative integer -1-0x00..-1-0x17 (-1..-24) @@ -4637,12 +4614,12 @@ class binary_reader case 0x27: case 0x28: case 0x29: - case 0x2a: - case 0x2b: - case 0x2c: - case 0x2d: - case 0x2e: - case 0x2f: + case 0x2A: + case 0x2B: + case 0x2C: + case 0x2D: + case 0x2E: + case 0x2F: case 0x30: case 0x31: case 0x32: @@ -4664,12 +4641,12 @@ class binary_reader return static_cast(-1) - get_number(); } - case 0x3a: // Negative integer -1-n (four-byte uint32_t follows) + case 0x3A: // Negative integer -1-n (four-byte uint32_t follows) { return static_cast(-1) - get_number(); } - case 0x3b: // Negative integer -1-n (eight-byte uint64_t follows) + case 0x3B: // Negative integer -1-n (eight-byte uint64_t follows) { return static_cast(-1) - static_cast(get_number()); @@ -4686,12 +4663,12 @@ class binary_reader case 0x67: case 0x68: case 0x69: - case 0x6a: - case 0x6b: - case 0x6c: - case 0x6d: - case 0x6e: - case 0x6f: + case 0x6A: + case 0x6B: + case 0x6C: + case 0x6D: + case 0x6E: + case 0x6F: case 0x70: case 0x71: case 0x72: @@ -4702,9 +4679,9 @@ class binary_reader case 0x77: case 0x78: // UTF-8 string (one-byte uint8_t for n follows) case 0x79: // UTF-8 string (two-byte uint16_t for n follow) - case 0x7a: // UTF-8 string (four-byte uint32_t for n follow) - case 0x7b: // UTF-8 string (eight-byte uint64_t for n follow) - case 0x7f: // UTF-8 string (indefinite length) + case 0x7A: // UTF-8 string (four-byte uint32_t for n follow) + case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow) + case 0x7F: // UTF-8 string (indefinite length) { return get_cbor_string(); } @@ -4720,12 +4697,12 @@ class binary_reader case 0x87: case 0x88: case 0x89: - case 0x8a: - case 0x8b: - case 0x8c: - case 0x8d: - case 0x8e: - case 0x8f: + case 0x8A: + case 0x8B: + case 0x8C: + case 0x8D: + case 0x8E: + case 0x8F: case 0x90: case 0x91: case 0x92: @@ -4735,7 +4712,7 @@ class binary_reader case 0x96: case 0x97: { - return get_cbor_array(current & 0x1f); + return get_cbor_array(current & 0x1F); } case 0x98: // array (one-byte uint8_t for n follows) @@ -4748,20 +4725,20 @@ class binary_reader return get_cbor_array(get_number()); } - case 0x9a: // array (four-byte uint32_t for n follow) + case 0x9A: // array (four-byte uint32_t for n follow) { return get_cbor_array(get_number()); } - case 0x9b: // array (eight-byte uint64_t for n follow) + case 0x9B: // array (eight-byte uint64_t for n follow) { return get_cbor_array(get_number()); } - case 0x9f: // array (indefinite length) + case 0x9F: // array (indefinite length) { BasicJsonType result = value_t::array; - while (get() != 0xff) + while (get() != 0xFF) { result.push_back(parse_cbor_internal(false)); } @@ -4769,58 +4746,58 @@ class binary_reader } // map (0x00..0x17 pairs of data items follow) - case 0xa0: - case 0xa1: - case 0xa2: - case 0xa3: - case 0xa4: - case 0xa5: - case 0xa6: - case 0xa7: - case 0xa8: - case 0xa9: - case 0xaa: - case 0xab: - case 0xac: - case 0xad: - case 0xae: - case 0xaf: - case 0xb0: - case 0xb1: - case 0xb2: - case 0xb3: - case 0xb4: - case 0xb5: - case 0xb6: - case 0xb7: + case 0xA0: + case 0xA1: + case 0xA2: + case 0xA3: + case 0xA4: + case 0xA5: + case 0xA6: + case 0xA7: + case 0xA8: + case 0xA9: + case 0xAA: + case 0xAB: + case 0xAC: + case 0xAD: + case 0xAE: + case 0xAF: + case 0xB0: + case 0xB1: + case 0xB2: + case 0xB3: + case 0xB4: + case 0xB5: + case 0xB6: + case 0xB7: { - return get_cbor_object(current & 0x1f); + return get_cbor_object(current & 0x1F); } - case 0xb8: // map (one-byte uint8_t for n follows) + case 0xB8: // map (one-byte uint8_t for n follows) { return get_cbor_object(get_number()); } - case 0xb9: // map (two-byte uint16_t for n follow) + case 0xB9: // map (two-byte uint16_t for n follow) { return get_cbor_object(get_number()); } - case 0xba: // map (four-byte uint32_t for n follow) + case 0xBA: // map (four-byte uint32_t for n follow) { return get_cbor_object(get_number()); } - case 0xbb: // map (eight-byte uint64_t for n follow) + case 0xBB: // map (eight-byte uint64_t for n follow) { return get_cbor_object(get_number()); } - case 0xbf: // map (indefinite length) + case 0xBF: // map (indefinite length) { BasicJsonType result = value_t::object; - while (get() != 0xff) + while (get() != 0xFF) { auto key = get_cbor_string(); result[key] = parse_cbor_internal(); @@ -4828,22 +4805,22 @@ class binary_reader return result; } - case 0xf4: // false + case 0xF4: // false { return false; } - case 0xf5: // true + case 0xF5: // true { return true; } - case 0xf6: // null + case 0xF6: // null { return value_t::null; } - case 0xf9: // Half-Precision Float (two-byte IEEE 754) + case 0xF9: // Half-Precision Float (two-byte IEEE 754) { const int byte1 = get(); check_eof(); @@ -4859,8 +4836,8 @@ class binary_reader // half-precision floating-point numbers in the C language // is shown in Fig. 3. const int half = (byte1 << 8) + byte2; - const int exp = (half >> 10) & 0x1f; - const int mant = half & 0x3ff; + const int exp = (half >> 10) & 0x1F; + const int mant = half & 0x3FF; double val; if (exp == 0) { @@ -4878,12 +4855,12 @@ class binary_reader return (half & 0x8000) != 0 ? -val : val; } - case 0xfa: // Single-Precision Float (four-byte IEEE 754) + case 0xFA: // Single-Precision Float (four-byte IEEE 754) { return get_number(); } - case 0xfb: // Double-Precision Float (eight-byte IEEE 754) + case 0xFB: // Double-Precision Float (eight-byte IEEE 754) { return get_number(); } @@ -4916,12 +4893,12 @@ class binary_reader case 0x07: case 0x08: case 0x09: - case 0x0a: - case 0x0b: - case 0x0c: - case 0x0d: - case 0x0e: - case 0x0f: + case 0x0A: + case 0x0B: + case 0x0C: + case 0x0D: + case 0x0E: + case 0x0F: case 0x10: case 0x11: case 0x12: @@ -4932,12 +4909,12 @@ class binary_reader case 0x17: case 0x18: case 0x19: - case 0x1a: - case 0x1b: - case 0x1c: - case 0x1d: - case 0x1e: - case 0x1f: + case 0x1A: + case 0x1B: + case 0x1C: + case 0x1D: + case 0x1E: + case 0x1F: case 0x20: case 0x21: case 0x22: @@ -4948,12 +4925,12 @@ class binary_reader case 0x27: case 0x28: case 0x29: - case 0x2a: - case 0x2b: - case 0x2c: - case 0x2d: - case 0x2e: - case 0x2f: + case 0x2A: + case 0x2B: + case 0x2C: + case 0x2D: + case 0x2E: + case 0x2F: case 0x30: case 0x31: case 0x32: @@ -4964,12 +4941,12 @@ class binary_reader case 0x37: case 0x38: case 0x39: - case 0x3a: - case 0x3b: - case 0x3c: - case 0x3d: - case 0x3e: - case 0x3f: + case 0x3A: + case 0x3B: + case 0x3C: + case 0x3D: + case 0x3E: + case 0x3F: case 0x40: case 0x41: case 0x42: @@ -4980,12 +4957,12 @@ class binary_reader case 0x47: case 0x48: case 0x49: - case 0x4a: - case 0x4b: - case 0x4c: - case 0x4d: - case 0x4e: - case 0x4f: + case 0x4A: + case 0x4B: + case 0x4C: + case 0x4D: + case 0x4E: + case 0x4F: case 0x50: case 0x51: case 0x52: @@ -4996,12 +4973,12 @@ class binary_reader case 0x57: case 0x58: case 0x59: - case 0x5a: - case 0x5b: - case 0x5c: - case 0x5d: - case 0x5e: - case 0x5f: + case 0x5A: + case 0x5B: + case 0x5C: + case 0x5D: + case 0x5E: + case 0x5F: case 0x60: case 0x61: case 0x62: @@ -5012,12 +4989,12 @@ class binary_reader case 0x67: case 0x68: case 0x69: - case 0x6a: - case 0x6b: - case 0x6c: - case 0x6d: - case 0x6e: - case 0x6f: + case 0x6A: + case 0x6B: + case 0x6C: + case 0x6D: + case 0x6E: + case 0x6F: case 0x70: case 0x71: case 0x72: @@ -5028,12 +5005,12 @@ class binary_reader case 0x77: case 0x78: case 0x79: - case 0x7a: - case 0x7b: - case 0x7c: - case 0x7d: - case 0x7e: - case 0x7f: + case 0x7A: + case 0x7B: + case 0x7C: + case 0x7D: + case 0x7E: + case 0x7F: return static_cast(current); // fixmap @@ -5047,14 +5024,14 @@ class binary_reader case 0x87: case 0x88: case 0x89: - case 0x8a: - case 0x8b: - case 0x8c: - case 0x8d: - case 0x8e: - case 0x8f: + case 0x8A: + case 0x8B: + case 0x8C: + case 0x8D: + case 0x8E: + case 0x8F: { - return get_msgpack_object(current & 0x0f); + return get_msgpack_object(current & 0x0F); } // fixarray @@ -5068,148 +5045,148 @@ class binary_reader case 0x97: case 0x98: case 0x99: - case 0x9a: - case 0x9b: - case 0x9c: - case 0x9d: - case 0x9e: - case 0x9f: + case 0x9A: + case 0x9B: + case 0x9C: + case 0x9D: + case 0x9E: + case 0x9F: { - return get_msgpack_array(current & 0x0f); + return get_msgpack_array(current & 0x0F); } // fixstr - case 0xa0: - case 0xa1: - case 0xa2: - case 0xa3: - case 0xa4: - case 0xa5: - case 0xa6: - case 0xa7: - case 0xa8: - case 0xa9: - case 0xaa: - case 0xab: - case 0xac: - case 0xad: - case 0xae: - case 0xaf: - case 0xb0: - case 0xb1: - case 0xb2: - case 0xb3: - case 0xb4: - case 0xb5: - case 0xb6: - case 0xb7: - case 0xb8: - case 0xb9: - case 0xba: - case 0xbb: - case 0xbc: - case 0xbd: - case 0xbe: - case 0xbf: + case 0xA0: + case 0xA1: + case 0xA2: + case 0xA3: + case 0xA4: + case 0xA5: + case 0xA6: + case 0xA7: + case 0xA8: + case 0xA9: + case 0xAA: + case 0xAB: + case 0xAC: + case 0xAD: + case 0xAE: + case 0xAF: + case 0xB0: + case 0xB1: + case 0xB2: + case 0xB3: + case 0xB4: + case 0xB5: + case 0xB6: + case 0xB7: + case 0xB8: + case 0xB9: + case 0xBA: + case 0xBB: + case 0xBC: + case 0xBD: + case 0xBE: + case 0xBF: return get_msgpack_string(); - case 0xc0: // nil + case 0xC0: // nil return value_t::null; - case 0xc2: // false + case 0xC2: // false return false; - case 0xc3: // true + case 0xC3: // true return true; - case 0xca: // float 32 + case 0xCA: // float 32 return get_number(); - case 0xcb: // float 64 + case 0xCB: // float 64 return get_number(); - case 0xcc: // uint 8 + case 0xCC: // uint 8 return get_number(); - case 0xcd: // uint 16 + case 0xCD: // uint 16 return get_number(); - case 0xce: // uint 32 + case 0xCE: // uint 32 return get_number(); - case 0xcf: // uint 64 + case 0xCF: // uint 64 return get_number(); - case 0xd0: // int 8 + case 0xD0: // int 8 return get_number(); - case 0xd1: // int 16 + case 0xD1: // int 16 return get_number(); - case 0xd2: // int 32 + case 0xD2: // int 32 return get_number(); - case 0xd3: // int 64 + case 0xD3: // int 64 return get_number(); - case 0xd9: // str 8 - case 0xda: // str 16 - case 0xdb: // str 32 + case 0xD9: // str 8 + case 0xDA: // str 16 + case 0xDB: // str 32 return get_msgpack_string(); - case 0xdc: // array 16 + case 0xDC: // array 16 { return get_msgpack_array(get_number()); } - case 0xdd: // array 32 + case 0xDD: // array 32 { return get_msgpack_array(get_number()); } - case 0xde: // map 16 + case 0xDE: // map 16 { return get_msgpack_object(get_number()); } - case 0xdf: // map 32 + case 0xDF: // map 32 { return get_msgpack_object(get_number()); } // positive fixint - case 0xe0: - case 0xe1: - case 0xe2: - case 0xe3: - case 0xe4: - case 0xe5: - case 0xe6: - case 0xe7: - case 0xe8: - case 0xe9: - case 0xea: - case 0xeb: - case 0xec: - case 0xed: - case 0xee: - case 0xef: - case 0xf0: - case 0xf1: - case 0xf2: - case 0xf3: - case 0xf4: - case 0xf5: - case 0xf6: - case 0xf7: - case 0xf8: - case 0xf9: - case 0xfa: - case 0xfb: - case 0xfc: - case 0xfd: - case 0xfe: - case 0xff: + case 0xE0: + case 0xE1: + case 0xE2: + case 0xE3: + case 0xE4: + case 0xE5: + case 0xE6: + case 0xE7: + case 0xE8: + case 0xE9: + case 0xEA: + case 0xEB: + case 0xEC: + case 0xED: + case 0xEE: + case 0xEF: + case 0xF0: + case 0xF1: + case 0xF2: + case 0xF3: + case 0xF4: + case 0xF5: + case 0xF6: + case 0xF7: + case 0xF8: + case 0xF9: + case 0xFA: + case 0xFB: + case 0xFC: + case 0xFD: + case 0xFE: + case 0xFF: return static_cast(current); default: // anything else @@ -5331,12 +5308,12 @@ class binary_reader case 0x67: case 0x68: case 0x69: - case 0x6a: - case 0x6b: - case 0x6c: - case 0x6d: - case 0x6e: - case 0x6f: + case 0x6A: + case 0x6B: + case 0x6C: + case 0x6D: + case 0x6E: + case 0x6F: case 0x70: case 0x71: case 0x72: @@ -5346,7 +5323,7 @@ class binary_reader case 0x76: case 0x77: { - return get_string(current & 0x1f); + return get_string(current & 0x1F); } case 0x78: // UTF-8 string (one-byte uint8_t for n follows) @@ -5359,20 +5336,20 @@ class binary_reader return get_string(get_number()); } - case 0x7a: // UTF-8 string (four-byte uint32_t for n follow) + case 0x7A: // UTF-8 string (four-byte uint32_t for n follow) { return get_string(get_number()); } - case 0x7b: // UTF-8 string (eight-byte uint64_t for n follow) + case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow) { return get_string(get_number()); } - case 0x7f: // UTF-8 string (indefinite length) + case 0x7F: // UTF-8 string (indefinite length) { std::string result; - while (get() != 0xff) + while (get() != 0xFF) { check_eof(); result.push_back(static_cast(current)); @@ -5434,53 +5411,53 @@ class binary_reader switch (current) { // fixstr - case 0xa0: - case 0xa1: - case 0xa2: - case 0xa3: - case 0xa4: - case 0xa5: - case 0xa6: - case 0xa7: - case 0xa8: - case 0xa9: - case 0xaa: - case 0xab: - case 0xac: - case 0xad: - case 0xae: - case 0xaf: - case 0xb0: - case 0xb1: - case 0xb2: - case 0xb3: - case 0xb4: - case 0xb5: - case 0xb6: - case 0xb7: - case 0xb8: - case 0xb9: - case 0xba: - case 0xbb: - case 0xbc: - case 0xbd: - case 0xbe: - case 0xbf: + case 0xA0: + case 0xA1: + case 0xA2: + case 0xA3: + case 0xA4: + case 0xA5: + case 0xA6: + case 0xA7: + case 0xA8: + case 0xA9: + case 0xAA: + case 0xAB: + case 0xAC: + case 0xAD: + case 0xAE: + case 0xAF: + case 0xB0: + case 0xB1: + case 0xB2: + case 0xB3: + case 0xB4: + case 0xB5: + case 0xB6: + case 0xB7: + case 0xB8: + case 0xB9: + case 0xBA: + case 0xBB: + case 0xBC: + case 0xBD: + case 0xBE: + case 0xBF: { - return get_string(current & 0x1f); + return get_string(current & 0x1F); } - case 0xd9: // str 8 + case 0xD9: // str 8 { return get_string(get_number()); } - case 0xda: // str 16 + case 0xDA: // str 16 { return get_string(get_number()); } - case 0xdb: // str 32 + case 0xDB: // str 32 { return get_string(get_number()); } @@ -5584,15 +5561,15 @@ class binary_writer { case value_t::null: { - oa->write_character(static_cast(0xf6)); + oa->write_character(static_cast(0xF6)); break; } case value_t::boolean: { oa->write_character(j.m_value.boolean - ? static_cast(0xf5) - : static_cast(0xf4)); + ? static_cast(0xF5) + : static_cast(0xF4)); break; } @@ -5619,12 +5596,12 @@ class binary_writer } else if (j.m_value.number_integer <= (std::numeric_limits::max)()) { - oa->write_character(static_cast(0x1a)); + oa->write_character(static_cast(0x1A)); write_number(static_cast(j.m_value.number_integer)); } else { - oa->write_character(static_cast(0x1b)); + oa->write_character(static_cast(0x1B)); write_number(static_cast(j.m_value.number_integer)); } } @@ -5649,12 +5626,12 @@ class binary_writer } else if (positive_number <= (std::numeric_limits::max)()) { - oa->write_character(static_cast(0x3a)); + oa->write_character(static_cast(0x3A)); write_number(static_cast(positive_number)); } else { - oa->write_character(static_cast(0x3b)); + oa->write_character(static_cast(0x3B)); write_number(static_cast(positive_number)); } } @@ -5679,12 +5656,12 @@ class binary_writer } else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) { - oa->write_character(static_cast(0x1a)); + oa->write_character(static_cast(0x1A)); write_number(static_cast(j.m_value.number_unsigned)); } else { - oa->write_character(static_cast(0x1b)); + oa->write_character(static_cast(0x1B)); write_number(static_cast(j.m_value.number_unsigned)); } break; @@ -5692,7 +5669,7 @@ class binary_writer case value_t::number_float: // Double-Precision Float { - oa->write_character(static_cast(0xfb)); + oa->write_character(static_cast(0xFB)); write_number(j.m_value.number_float); break; } @@ -5705,25 +5682,25 @@ class binary_writer { write_number(static_cast(0x60 + N)); } - else if (N <= 0xff) + else if (N <= 0xFF) { oa->write_character(static_cast(0x78)); write_number(static_cast(N)); } - else if (N <= 0xffff) + else if (N <= 0xFFFF) { oa->write_character(static_cast(0x79)); write_number(static_cast(N)); } - else if (N <= 0xffffffff) + else if (N <= 0xFFFFFFFF) { - oa->write_character(static_cast(0x7a)); + oa->write_character(static_cast(0x7A)); write_number(static_cast(N)); } // LCOV_EXCL_START - else if (N <= 0xffffffffffffffff) + else if (N <= 0xFFFFFFFFFFFFFFFF) { - oa->write_character(static_cast(0x7b)); + oa->write_character(static_cast(0x7B)); write_number(static_cast(N)); } // LCOV_EXCL_STOP @@ -5743,25 +5720,25 @@ class binary_writer { write_number(static_cast(0x80 + N)); } - else if (N <= 0xff) + else if (N <= 0xFF) { oa->write_character(static_cast(0x98)); write_number(static_cast(N)); } - else if (N <= 0xffff) + else if (N <= 0xFFFF) { oa->write_character(static_cast(0x99)); write_number(static_cast(N)); } - else if (N <= 0xffffffff) + else if (N <= 0xFFFFFFFF) { - oa->write_character(static_cast(0x9a)); + oa->write_character(static_cast(0x9A)); write_number(static_cast(N)); } // LCOV_EXCL_START - else if (N <= 0xffffffffffffffff) + else if (N <= 0xFFFFFFFFFFFFFFFF) { - oa->write_character(static_cast(0x9b)); + oa->write_character(static_cast(0x9B)); write_number(static_cast(N)); } // LCOV_EXCL_STOP @@ -5780,27 +5757,27 @@ class binary_writer const auto N = j.m_value.object->size(); if (N <= 0x17) { - write_number(static_cast(0xa0 + N)); + write_number(static_cast(0xA0 + N)); } - else if (N <= 0xff) + else if (N <= 0xFF) { - oa->write_character(static_cast(0xb8)); + oa->write_character(static_cast(0xB8)); write_number(static_cast(N)); } - else if (N <= 0xffff) + else if (N <= 0xFFFF) { - oa->write_character(static_cast(0xb9)); + oa->write_character(static_cast(0xB9)); write_number(static_cast(N)); } - else if (N <= 0xffffffff) + else if (N <= 0xFFFFFFFF) { - oa->write_character(static_cast(0xba)); + oa->write_character(static_cast(0xBA)); write_number(static_cast(N)); } // LCOV_EXCL_START - else if (N <= 0xffffffffffffffff) + else if (N <= 0xFFFFFFFFFFFFFFFF) { - oa->write_character(static_cast(0xbb)); + oa->write_character(static_cast(0xBB)); write_number(static_cast(N)); } // LCOV_EXCL_STOP @@ -5828,15 +5805,15 @@ class binary_writer { case value_t::null: // nil { - oa->write_character(static_cast(0xc0)); + oa->write_character(static_cast(0xC0)); break; } case value_t::boolean: // true and false { oa->write_character(j.m_value.boolean - ? static_cast(0xc3) - : static_cast(0xc2)); + ? static_cast(0xC3) + : static_cast(0xC2)); break; } @@ -5855,25 +5832,25 @@ class binary_writer else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) { // uint 8 - oa->write_character(static_cast(0xcc)); + oa->write_character(static_cast(0xCC)); write_number(static_cast(j.m_value.number_integer)); } else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) { // uint 16 - oa->write_character(static_cast(0xcd)); + oa->write_character(static_cast(0xCD)); write_number(static_cast(j.m_value.number_integer)); } else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) { // uint 32 - oa->write_character(static_cast(0xce)); + oa->write_character(static_cast(0xCE)); write_number(static_cast(j.m_value.number_integer)); } else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) { // uint 64 - oa->write_character(static_cast(0xcf)); + oa->write_character(static_cast(0xCF)); write_number(static_cast(j.m_value.number_integer)); } } @@ -5888,28 +5865,28 @@ class binary_writer j.m_value.number_integer <= (std::numeric_limits::max)()) { // int 8 - oa->write_character(static_cast(0xd0)); + oa->write_character(static_cast(0xD0)); write_number(static_cast(j.m_value.number_integer)); } else if (j.m_value.number_integer >= (std::numeric_limits::min)() and j.m_value.number_integer <= (std::numeric_limits::max)()) { // int 16 - oa->write_character(static_cast(0xd1)); + oa->write_character(static_cast(0xD1)); write_number(static_cast(j.m_value.number_integer)); } else if (j.m_value.number_integer >= (std::numeric_limits::min)() and j.m_value.number_integer <= (std::numeric_limits::max)()) { // int 32 - oa->write_character(static_cast(0xd2)); + oa->write_character(static_cast(0xD2)); write_number(static_cast(j.m_value.number_integer)); } else if (j.m_value.number_integer >= (std::numeric_limits::min)() and j.m_value.number_integer <= (std::numeric_limits::max)()) { // int 64 - oa->write_character(static_cast(0xd3)); + oa->write_character(static_cast(0xD3)); write_number(static_cast(j.m_value.number_integer)); } } @@ -5926,25 +5903,25 @@ class binary_writer else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) { // uint 8 - oa->write_character(static_cast(0xcc)); + oa->write_character(static_cast(0xCC)); write_number(static_cast(j.m_value.number_integer)); } else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) { // uint 16 - oa->write_character(static_cast(0xcd)); + oa->write_character(static_cast(0xCD)); write_number(static_cast(j.m_value.number_integer)); } else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) { // uint 32 - oa->write_character(static_cast(0xce)); + oa->write_character(static_cast(0xCE)); write_number(static_cast(j.m_value.number_integer)); } else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) { // uint 64 - oa->write_character(static_cast(0xcf)); + oa->write_character(static_cast(0xCF)); write_number(static_cast(j.m_value.number_integer)); } break; @@ -5952,7 +5929,7 @@ class binary_writer case value_t::number_float: // float 64 { - oa->write_character(static_cast(0xcb)); + oa->write_character(static_cast(0xCB)); write_number(j.m_value.number_float); break; } @@ -5964,24 +5941,24 @@ class binary_writer if (N <= 31) { // fixstr - write_number(static_cast(0xa0 | N)); + write_number(static_cast(0xA0 | N)); } else if (N <= 255) { // str 8 - oa->write_character(static_cast(0xd9)); + oa->write_character(static_cast(0xD9)); write_number(static_cast(N)); } else if (N <= 65535) { // str 16 - oa->write_character(static_cast(0xda)); + oa->write_character(static_cast(0xDA)); write_number(static_cast(N)); } else if (N <= 4294967295) { // str 32 - oa->write_character(static_cast(0xdb)); + oa->write_character(static_cast(0xDB)); write_number(static_cast(N)); } @@ -6001,16 +5978,16 @@ class binary_writer // fixarray write_number(static_cast(0x90 | N)); } - else if (N <= 0xffff) + else if (N <= 0xFFFF) { // array 16 - oa->write_character(static_cast(0xdc)); + oa->write_character(static_cast(0xDC)); write_number(static_cast(N)); } - else if (N <= 0xffffffff) + else if (N <= 0xFFFFFFFF) { // array 32 - oa->write_character(static_cast(0xdd)); + oa->write_character(static_cast(0xDD)); write_number(static_cast(N)); } @@ -6029,18 +6006,18 @@ class binary_writer if (N <= 15) { // fixmap - write_number(static_cast(0x80 | (N & 0xf))); + write_number(static_cast(0x80 | (N & 0xF))); } else if (N <= 65535) { // map 16 - oa->write_character(static_cast(0xde)); + oa->write_character(static_cast(0xDE)); write_number(static_cast(N)); } else if (N <= 4294967295) { // map 32 - oa->write_character(static_cast(0xdf)); + oa->write_character(static_cast(0xDF)); write_number(static_cast(N)); } @@ -6385,9 +6362,9 @@ class serializer case 0x05: case 0x06: case 0x07: - case 0x0b: - case 0x0e: - case 0x0f: + case 0x0B: + case 0x0E: + case 0x0F: case 0x10: case 0x11: case 0x12: @@ -6398,12 +6375,12 @@ class serializer case 0x17: case 0x18: case 0x19: - case 0x1a: - case 0x1b: - case 0x1c: - case 0x1d: - case 0x1e: - case 0x1f: + case 0x1A: + case 0x1B: + case 0x1C: + case 0x1D: + case 0x1E: + case 0x1F: { // from c (1 byte) to \uxxxx (6 bytes) res += 5; @@ -6534,7 +6511,7 @@ class serializer break; } - case '\\': // reverse solidus (0x5c) + case '\\': // reverse solidus (0x5C) { // nothing to change pos += 2; @@ -6548,21 +6525,21 @@ class serializer break; } - case '\f': // formfeed (0x0c) + case '\f': // formfeed (0x0C) { result[pos + 1] = 'f'; pos += 2; break; } - case '\n': // newline (0x0a) + case '\n': // newline (0x0A) { result[pos + 1] = 'n'; pos += 2; break; } - case '\r': // carriage return (0x0d) + case '\r': // carriage return (0x0D) { result[pos + 1] = 'r'; pos += 2; @@ -6657,11 +6634,10 @@ class serializer @param[in] x integer number (signed or unsigned) to dump @tparam NumberType either @a number_integer_t or @a number_unsigned_t */ - template < - typename NumberType, - detail::enable_if_t::value or - std::is_same::value, - int> = 0 > + template::value or + std::is_same::value, + int> = 0> void dump_integer(NumberType x) { // special case for "0" @@ -6784,15 +6760,15 @@ class serializer static const std::array utf8d = { { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00..1f - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20..3f - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 40..5f - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60..7f - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 80..9f - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // a0..bf - 8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // c0..df - 0xa, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3, 0x3, // e0..ef - 0xb, 0x6, 0x6, 0x6, 0x5, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, // f0..ff + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00..1F + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20..3F + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 40..5F + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60..7F + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 80..9F + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // A0..BF + 8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // C0..DF + 0xA, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3, 0x3, // E0..EF + 0xB, 0x6, 0x6, 0x6, 0x5, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, // F0..FF 0x0, 0x1, 0x2, 0x3, 0x5, 0x8, 0x7, 0x1, 0x1, 0x1, 0x4, 0x6, 0x1, 0x1, 0x1, 0x1, // s0..s0 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, // s1..s2 1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, // s3..s4 @@ -6868,27 +6844,20 @@ class json_ref using value_type = BasicJsonType; json_ref(value_type&& value) - : owned_value(std::move(value)), - value_ref(&owned_value), - is_rvalue(true) + : owned_value(std::move(value)), value_ref(&owned_value), is_rvalue(true) {} json_ref(const value_type& value) - : value_ref(const_cast(&value)), - is_rvalue(false) + : value_ref(const_cast(&value)), is_rvalue(false) {} json_ref(std::initializer_list init) - : owned_value(init), - value_ref(&owned_value), - is_rvalue(true) + : owned_value(init), value_ref(&owned_value), is_rvalue(true) {} - template + template json_ref(Args&& ... args) - : owned_value(std::forward(args)...), - value_ref(&owned_value), - is_rvalue(true) + : owned_value(std::forward(args)...), value_ref(&owned_value), is_rvalue(true) {} // class should be movable only @@ -7417,11 +7386,11 @@ class basic_json public: using value_t = detail::value_t; - // forward declarations + /// @copydoc nlohmann::json_pointer using json_pointer = ::nlohmann::json_pointer; template using json_serializer = JSONSerializer; - + /// helper type for initializer lists of basic_json values using initializer_list_t = std::initializer_list>; //////////////// @@ -7586,6 +7555,14 @@ class basic_json /// the template arguments passed to class @ref basic_json. /// @{ +#if defined(JSON_HAS_CPP_14) + // Use transparent comparator if possible, combined with perfect forwarding + // on find() and count() calls prevents unnecessary string construction. + using object_comparator_t = std::less<>; +#else + using object_comparator_t = std::less; +#endif + /*! @brief a type for an object @@ -7669,14 +7646,6 @@ class basic_json 7159](http://rfc7159.net/rfc7159), because any order implements the specified "unordered" nature of JSON objects. */ - -#if defined(JSON_HAS_CPP_14) - // Use transparent comparator if possible, combined with perfect forwarding - // on find() and count() calls prevents unnecessary string construction. - using object_comparator_t = std::less<>; -#else - using object_comparator_t = std::less; -#endif using object_t = ObjectType::type, - basic_json_t>::value, - int> = 0 > + template::type, basic_json_t>::value, + int> = 0> basic_json get() const { return *this; @@ -9656,14 +9641,12 @@ class basic_json @since version 2.1.0 */ - template < - typename ValueTypeCV, - typename ValueType = detail::uncvref_t, - detail::enable_if_t < - not std::is_same::value and - detail::has_from_json::value and - not detail::has_non_default_from_json::value, - int > = 0 > + template, + detail::enable_if_t < + not std::is_same::value and + detail::has_from_json::value and + not detail::has_non_default_from_json::value, + int> = 0> ValueType get() const noexcept(noexcept( JSONSerializer::from_json(std::declval(), std::declval()))) { @@ -9711,12 +9694,10 @@ class basic_json @since version 2.1.0 */ - template < - typename ValueTypeCV, - typename ValueType = detail::uncvref_t, - detail::enable_if_t::value and - detail::has_non_default_from_json::value, int> = 0 > + template, + detail::enable_if_t::value and + detail::has_non_default_from_json::value, + int> = 0> ValueType get() const noexcept(noexcept( JSONSerializer::from_json(std::declval()))) { @@ -10210,7 +10191,7 @@ class basic_json @return const reference to the element at index @a idx - @throw type_error.305 if the JSON value is not an array; in that cases, + @throw type_error.305 if the JSON value is not an array; in that case, using the [] operator with an index makes no sense. @complexity Constant. @@ -10293,7 +10274,7 @@ class basic_json @pre The element with key @a key must exist. **This precondition is enforced with an assertion.** - @throw type_error.305 if the JSON value is not an object; in that cases, + @throw type_error.305 if the JSON value is not an object; in that case, using the [] operator with a key makes no sense. @complexity Logarithmic in the size of the container. @@ -10382,7 +10363,7 @@ class basic_json @pre The element with key @a key must exist. **This precondition is enforced with an assertion.** - @throw type_error.305 if the JSON value is not an object; in that cases, + @throw type_error.305 if the JSON value is not an object; in that case, using the [] operator with a key makes no sense. @complexity Logarithmic in the size of the container. @@ -10442,7 +10423,7 @@ class basic_json @return copy of the element at key @a key or @a default_value if @a key is not found - @throw type_error.306 if the JSON value is not an object; in that cases, + @throw type_error.306 if the JSON value is not an object; in that case, using `value()` with a key makes no sense. @complexity Logarithmic in the size of the container. @@ -10515,7 +10496,7 @@ class basic_json @return copy of the element at key @a key or @a default_value if @a key is not found - @throw type_error.306 if the JSON value is not an objec; in that cases, + @throw type_error.306 if the JSON value is not an objec; in that case, using `value()` with a key makes no sense. @complexity Logarithmic in the size of the container. @@ -12441,7 +12422,7 @@ class basic_json [comparison function](https://github.com/mariokonrad/marnav/blob/master/src/marnav/math/floatingpoint.hpp#L34-#L39) could be used, for instance @code {.cpp} - template ::value, T>::type> + template::value, T>::type> inline bool is_same(T a, T b, T epsilon = std::numeric_limits::epsilon()) noexcept { return std::abs(a - b) <= epsilon; @@ -12879,6 +12860,9 @@ class basic_json @return the stream @a o + @throw type_error.316 if a string stored inside the JSON value is not + UTF-8 encoded + @complexity Linear. @liveexample{The example below shows the serialization with different @@ -13224,40 +13208,40 @@ class basic_json JSON value type | value/range | CBOR type | first byte --------------- | ------------------------------------------ | ---------------------------------- | --------------- - null | `null` | Null | 0xf6 - boolean | `true` | True | 0xf5 - boolean | `false` | False | 0xf4 - number_integer | -9223372036854775808..-2147483649 | Negative integer (8 bytes follow) | 0x3b - number_integer | -2147483648..-32769 | Negative integer (4 bytes follow) | 0x3a + null | `null` | Null | 0xF6 + boolean | `true` | True | 0xF5 + boolean | `false` | False | 0xF4 + number_integer | -9223372036854775808..-2147483649 | Negative integer (8 bytes follow) | 0x3B + number_integer | -2147483648..-32769 | Negative integer (4 bytes follow) | 0x3A number_integer | -32768..-129 | Negative integer (2 bytes follow) | 0x39 number_integer | -128..-25 | Negative integer (1 byte follow) | 0x38 number_integer | -24..-1 | Negative integer | 0x20..0x37 number_integer | 0..23 | Integer | 0x00..0x17 number_integer | 24..255 | Unsigned integer (1 byte follow) | 0x18 number_integer | 256..65535 | Unsigned integer (2 bytes follow) | 0x19 - number_integer | 65536..4294967295 | Unsigned integer (4 bytes follow) | 0x1a - number_integer | 4294967296..18446744073709551615 | Unsigned integer (8 bytes follow) | 0x1b + number_integer | 65536..4294967295 | Unsigned integer (4 bytes follow) | 0x1A + number_integer | 4294967296..18446744073709551615 | Unsigned integer (8 bytes follow) | 0x1B number_unsigned | 0..23 | Integer | 0x00..0x17 number_unsigned | 24..255 | Unsigned integer (1 byte follow) | 0x18 number_unsigned | 256..65535 | Unsigned integer (2 bytes follow) | 0x19 - number_unsigned | 65536..4294967295 | Unsigned integer (4 bytes follow) | 0x1a - number_unsigned | 4294967296..18446744073709551615 | Unsigned integer (8 bytes follow) | 0x1b - number_float | *any value* | Double-Precision Float | 0xfb + number_unsigned | 65536..4294967295 | Unsigned integer (4 bytes follow) | 0x1A + number_unsigned | 4294967296..18446744073709551615 | Unsigned integer (8 bytes follow) | 0x1B + number_float | *any value* | Double-Precision Float | 0xFB string | *length*: 0..23 | UTF-8 string | 0x60..0x77 string | *length*: 23..255 | UTF-8 string (1 byte follow) | 0x78 string | *length*: 256..65535 | UTF-8 string (2 bytes follow) | 0x79 - string | *length*: 65536..4294967295 | UTF-8 string (4 bytes follow) | 0x7a - string | *length*: 4294967296..18446744073709551615 | UTF-8 string (8 bytes follow) | 0x7b + string | *length*: 65536..4294967295 | UTF-8 string (4 bytes follow) | 0x7A + string | *length*: 4294967296..18446744073709551615 | UTF-8 string (8 bytes follow) | 0x7B array | *size*: 0..23 | array | 0x80..0x97 array | *size*: 23..255 | array (1 byte follow) | 0x98 array | *size*: 256..65535 | array (2 bytes follow) | 0x99 - array | *size*: 65536..4294967295 | array (4 bytes follow) | 0x9a - array | *size*: 4294967296..18446744073709551615 | array (8 bytes follow) | 0x9b - object | *size*: 0..23 | map | 0xa0..0xb7 - object | *size*: 23..255 | map (1 byte follow) | 0xb8 - object | *size*: 256..65535 | map (2 bytes follow) | 0xb9 - object | *size*: 65536..4294967295 | map (4 bytes follow) | 0xba - object | *size*: 4294967296..18446744073709551615 | map (8 bytes follow) | 0xbb + array | *size*: 65536..4294967295 | array (4 bytes follow) | 0x9A + array | *size*: 4294967296..18446744073709551615 | array (8 bytes follow) | 0x9B + object | *size*: 0..23 | map | 0xA0..0xB7 + object | *size*: 23..255 | map (1 byte follow) | 0xB8 + object | *size*: 256..65535 | map (2 bytes follow) | 0xB9 + object | *size*: 65536..4294967295 | map (4 bytes follow) | 0xBA + object | *size*: 4294967296..18446744073709551615 | map (8 bytes follow) | 0xBB @note The mapping is **complete** in the sense that any JSON value type can be converted to a CBOR value. @@ -13267,20 +13251,20 @@ class basic_json function which serializes NaN or Infinity to `null`. @note The following CBOR types are not used in the conversion: - - byte strings (0x40..0x5f) - - UTF-8 strings terminated by "break" (0x7f) - - arrays terminated by "break" (0x9f) - - maps terminated by "break" (0xbf) - - date/time (0xc0..0xc1) - - bignum (0xc2..0xc3) - - decimal fraction (0xc4) - - bigfloat (0xc5) - - tagged items (0xc6..0xd4, 0xd8..0xdb) - - expected conversions (0xd5..0xd7) - - simple values (0xe0..0xf3, 0xf8) - - undefined (0xf7) - - half and single-precision floats (0xf9-0xfa) - - break (0xff) + - byte strings (0x40..0x5F) + - UTF-8 strings terminated by "break" (0x7F) + - arrays terminated by "break" (0x9F) + - maps terminated by "break" (0xBF) + - date/time (0xC0..0xC1) + - bignum (0xC2..0xC3) + - decimal fraction (0xC4) + - bigfloat (0xC5) + - tagged items (0xC6..0xD4, 0xD8..0xDB) + - expected conversions (0xD5..0xD7) + - simple values (0xE0..0xF3, 0xF8) + - undefined (0xF7) + - half and single-precision floats (0xF9-0xFA) + - break (0xFF) @param[in] j JSON value to serialize @return MessagePack serialization as byte vector @@ -13326,35 +13310,35 @@ class basic_json JSON value type | value/range | MessagePack type | first byte --------------- | --------------------------------- | ---------------- | ---------- - null | `null` | nil | 0xc0 - boolean | `true` | true | 0xc3 - boolean | `false` | false | 0xc2 - number_integer | -9223372036854775808..-2147483649 | int64 | 0xd3 - number_integer | -2147483648..-32769 | int32 | 0xd2 - number_integer | -32768..-129 | int16 | 0xd1 - number_integer | -128..-33 | int8 | 0xd0 - number_integer | -32..-1 | negative fixint | 0xe0..0xff - number_integer | 0..127 | positive fixint | 0x00..0x7f - number_integer | 128..255 | uint 8 | 0xcc - number_integer | 256..65535 | uint 16 | 0xcd - number_integer | 65536..4294967295 | uint 32 | 0xce - number_integer | 4294967296..18446744073709551615 | uint 64 | 0xcf - number_unsigned | 0..127 | positive fixint | 0x00..0x7f - number_unsigned | 128..255 | uint 8 | 0xcc - number_unsigned | 256..65535 | uint 16 | 0xcd - number_unsigned | 65536..4294967295 | uint 32 | 0xce - number_unsigned | 4294967296..18446744073709551615 | uint 64 | 0xcf - number_float | *any value* | float 64 | 0xcb - string | *length*: 0..31 | fixstr | 0xa0..0xbf - string | *length*: 32..255 | str 8 | 0xd9 - string | *length*: 256..65535 | str 16 | 0xda - string | *length*: 65536..4294967295 | str 32 | 0xdb - array | *size*: 0..15 | fixarray | 0x90..0x9f - array | *size*: 16..65535 | array 16 | 0xdc - array | *size*: 65536..4294967295 | array 32 | 0xdd - object | *size*: 0..15 | fix map | 0x80..0x8f - object | *size*: 16..65535 | map 16 | 0xde - object | *size*: 65536..4294967295 | map 32 | 0xdf + null | `null` | nil | 0xC0 + boolean | `true` | true | 0xC3 + boolean | `false` | false | 0xC2 + number_integer | -9223372036854775808..-2147483649 | int64 | 0xD3 + number_integer | -2147483648..-32769 | int32 | 0xD2 + number_integer | -32768..-129 | int16 | 0xD1 + number_integer | -128..-33 | int8 | 0xD0 + number_integer | -32..-1 | negative fixint | 0xE0..0xFF + number_integer | 0..127 | positive fixint | 0x00..0x7F + number_integer | 128..255 | uint 8 | 0xCC + number_integer | 256..65535 | uint 16 | 0xCD + number_integer | 65536..4294967295 | uint 32 | 0xCE + number_integer | 4294967296..18446744073709551615 | uint 64 | 0xCF + number_unsigned | 0..127 | positive fixint | 0x00..0x7F + number_unsigned | 128..255 | uint 8 | 0xCC + number_unsigned | 256..65535 | uint 16 | 0xCD + number_unsigned | 65536..4294967295 | uint 32 | 0xCE + number_unsigned | 4294967296..18446744073709551615 | uint 64 | 0xCF + number_float | *any value* | float 64 | 0xCB + string | *length*: 0..31 | fixstr | 0xA0..0xBF + string | *length*: 32..255 | str 8 | 0xD9 + string | *length*: 256..65535 | str 16 | 0xDA + string | *length*: 65536..4294967295 | str 32 | 0xDB + array | *size*: 0..15 | fixarray | 0x90..0x9F + array | *size*: 16..65535 | array 16 | 0xDC + array | *size*: 65536..4294967295 | array 32 | 0xDD + object | *size*: 0..15 | fix map | 0x80..0x8F + object | *size*: 16..65535 | map 16 | 0xDE + object | *size*: 65536..4294967295 | map 32 | 0xDF @note The mapping is **complete** in the sense that any JSON value type can be converted to a MessagePack value. @@ -13365,10 +13349,10 @@ class basic_json - objects with more than 4294967295 elements @note The following MessagePack types are not used in the conversion: - - bin 8 - bin 32 (0xc4..0xc6) - - ext 8 - ext 32 (0xc7..0xc9) - - float 32 (0xca) - - fixext 1 - fixext 16 (0xd4..0xd8) + - bin 8 - bin 32 (0xC4..0xC6) + - ext 8 - ext 32 (0xC7..0xC9) + - float 32 (0xCA) + - fixext 1 - fixext 16 (0xD4..0xD8) @note Any MessagePack output created @ref to_msgpack can be successfully parsed by @ref from_msgpack. @@ -13422,51 +13406,51 @@ class basic_json Integer | number_unsigned | 0x00..0x17 Unsigned integer | number_unsigned | 0x18 Unsigned integer | number_unsigned | 0x19 - Unsigned integer | number_unsigned | 0x1a - Unsigned integer | number_unsigned | 0x1b + Unsigned integer | number_unsigned | 0x1A + Unsigned integer | number_unsigned | 0x1B Negative integer | number_integer | 0x20..0x37 Negative integer | number_integer | 0x38 Negative integer | number_integer | 0x39 - Negative integer | number_integer | 0x3a - Negative integer | number_integer | 0x3b + Negative integer | number_integer | 0x3A + Negative integer | number_integer | 0x3B Negative integer | number_integer | 0x40..0x57 UTF-8 string | string | 0x60..0x77 UTF-8 string | string | 0x78 UTF-8 string | string | 0x79 - UTF-8 string | string | 0x7a - UTF-8 string | string | 0x7b - UTF-8 string | string | 0x7f + UTF-8 string | string | 0x7A + UTF-8 string | string | 0x7B + UTF-8 string | string | 0x7F array | array | 0x80..0x97 array | array | 0x98 array | array | 0x99 - array | array | 0x9a - array | array | 0x9b - array | array | 0x9f - map | object | 0xa0..0xb7 - map | object | 0xb8 - map | object | 0xb9 - map | object | 0xba - map | object | 0xbb - map | object | 0xbf - False | `false` | 0xf4 - True | `true` | 0xf5 - Nill | `null` | 0xf6 - Half-Precision Float | number_float | 0xf9 - Single-Precision Float | number_float | 0xfa - Double-Precision Float | number_float | 0xfb + array | array | 0x9A + array | array | 0x9B + array | array | 0x9F + map | object | 0xA0..0xB7 + map | object | 0xB8 + map | object | 0xB9 + map | object | 0xBA + map | object | 0xBB + map | object | 0xBF + False | `false` | 0xF4 + True | `true` | 0xF5 + Nill | `null` | 0xF6 + Half-Precision Float | number_float | 0xF9 + Single-Precision Float | number_float | 0xFA + Double-Precision Float | number_float | 0xFB @warning The mapping is **incomplete** in the sense that not all CBOR types can be converted to a JSON value. The following CBOR types are not supported and will yield parse errors (parse_error.112): - - byte strings (0x40..0x5f) - - date/time (0xc0..0xc1) - - bignum (0xc2..0xc3) - - decimal fraction (0xc4) - - bigfloat (0xc5) - - tagged items (0xc6..0xd4, 0xd8..0xdb) - - expected conversions (0xd5..0xd7) - - simple values (0xe0..0xf3, 0xf8) - - undefined (0xf7) + - byte strings (0x40..0x5F) + - date/time (0xC0..0xC1) + - bignum (0xC2..0xC3) + - decimal fraction (0xC4) + - bigfloat (0xC5) + - tagged items (0xC6..0xD4, 0xD8..0xDB) + - expected conversions (0xD5..0xD7) + - simple values (0xE0..0xF3, 0xF8) + - undefined (0xF7) @warning CBOR allows map keys of any type, whereas JSON only allows strings as keys in object values. Therefore, CBOR maps with keys @@ -13526,38 +13510,38 @@ class basic_json MessagePack type | JSON value type | first byte ---------------- | --------------- | ---------- - positive fixint | number_unsigned | 0x00..0x7f - fixmap | object | 0x80..0x8f - fixarray | array | 0x90..0x9f - fixstr | string | 0xa0..0xbf - nil | `null` | 0xc0 - false | `false` | 0xc2 - true | `true` | 0xc3 - float 32 | number_float | 0xca - float 64 | number_float | 0xcb - uint 8 | number_unsigned | 0xcc - uint 16 | number_unsigned | 0xcd - uint 32 | number_unsigned | 0xce - uint 64 | number_unsigned | 0xcf - int 8 | number_integer | 0xd0 - int 16 | number_integer | 0xd1 - int 32 | number_integer | 0xd2 - int 64 | number_integer | 0xd3 - str 8 | string | 0xd9 - str 16 | string | 0xda - str 32 | string | 0xdb - array 16 | array | 0xdc - array 32 | array | 0xdd - map 16 | object | 0xde - map 32 | object | 0xdf - negative fixint | number_integer | 0xe0-0xff + positive fixint | number_unsigned | 0x00..0x7F + fixmap | object | 0x80..0x8F + fixarray | array | 0x90..0x9F + fixstr | string | 0xA0..0xBF + nil | `null` | 0xC0 + false | `false` | 0xC2 + true | `true` | 0xC3 + float 32 | number_float | 0xCA + float 64 | number_float | 0xCB + uint 8 | number_unsigned | 0xCC + uint 16 | number_unsigned | 0xCD + uint 32 | number_unsigned | 0xCE + uint 64 | number_unsigned | 0xCF + int 8 | number_integer | 0xD0 + int 16 | number_integer | 0xD1 + int 32 | number_integer | 0xD2 + int 64 | number_integer | 0xD3 + str 8 | string | 0xD9 + str 16 | string | 0xDA + str 32 | string | 0xDB + array 16 | array | 0xDC + array 32 | array | 0xDD + map 16 | object | 0xDE + map 32 | object | 0xDF + negative fixint | number_integer | 0xE0-0xFF @warning The mapping is **incomplete** in the sense that not all MessagePack types can be converted to a JSON value. The following MessagePack types are not supported and will yield parse errors: - - bin 8 - bin 32 (0xc4..0xc6) - - ext 8 - ext 32 (0xc7..0xc9) - - fixext 1 - fixext 16 (0xd4..0xd8) + - bin 8 - bin 32 (0xC4..0xC6) + - ext 8 - ext 32 (0xC7..0xC9) + - fixext 1 - fixext 16 (0xD4..0xD8) @note Any MessagePack output created @ref to_msgpack can be successfully parsed by @ref from_msgpack. From 293748a9a92126e5e3b054699fd1f40dc75a9d9c Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Wed, 13 Dec 2017 22:17:02 +0100 Subject: [PATCH 03/59] :memo: overworked README - Added recent contributors to thanks list. - Linked PGP key for private mails. - Updated compiler list. --- README.md | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 89ccb5a7..54f73a8d 100644 --- a/README.md +++ b/README.md @@ -741,11 +741,11 @@ json j_from_msgpack = json::from_msgpack(v_msgpack); Though it's 2016 already, the support for C++11 is still a bit sparse. Currently, the following compilers are known to work: -- GCC 4.9 - 7.1 (and possibly later) +- GCC 4.9 - 7.2 (and possibly later) - Clang 3.4 - 5.0 (and possibly later) - Intel C++ Compiler 17.0.2 (and possibly later) - Microsoft Visual C++ 2015 / Build Tools 14.0.25123.0 (and possibly later) -- Microsoft Visual C++ 2017 / Build Tools 15.1.548.43366 (and possibly later) +- Microsoft Visual C++ 2017 / Build Tools 15.5.180.51428 (and possibly later) I would be happy to learn about other compilers/versions. @@ -785,9 +785,11 @@ The following compilers are currently used in continuous integration at [Travis] | Clang Xcode 8.1 | Darwin Kernel Version 16.1.0 (macOS 10.12.1) | Apple LLVM version 8.0.0 (clang-800.0.42.1) | | Clang Xcode 8.2 | Darwin Kernel Version 16.1.0 (macOS 10.12.1) | Apple LLVM version 8.0.0 (clang-800.0.42.1) | | Clang Xcode 8.3 | Darwin Kernel Version 16.5.0 (macOS 10.12.4) | Apple LLVM version 8.1.0 (clang-802.0.38) | -| Clang Xcode 9 beta | Darwin Kernel Version 16.6.0 (macOS 10.12.5) | Apple LLVM version 9.0.0 (clang-900.0.26) | -| Visual Studio 14 2015 | Windows Server 2012 R2 (x64) | Microsoft (R) Build Engine version 14.0.25420.1 | -| Visual Studio 2017 | Windows Server 2016 | Microsoft (R) Build Engine version 15.1.1012.6693 | +| Clang Xcode 9.0 | Darwin Kernel Version 16.7.0 (macOS 10.12.6) | Apple LLVM version 9.0.0 (clang-900.0.37) | +| Clang Xcode 9.1 | Darwin Kernel Version 16.7.0 (macOS 10.12.6) | Apple LLVM version 9.0.0 (clang-900.0.38) | +| Clang Xcode 9.2 | Darwin Kernel Version 16.7.0 (macOS 10.12.6) | Apple LLVM version 8.1.0 (clang-900.0.39.2) | +| Visual Studio 14 2015 | Windows Server 2012 R2 (x64) | Microsoft (R) Build Engine version 14.0.25420.1, MSVC 19.0.24215.1 | +| Visual Studio 2017 | Windows Server 2016 | Microsoft (R) Build Engine version 15.5.180.51428, MSVC 19.12.25830.2 | ## License @@ -805,13 +807,13 @@ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR I * * * -The class contains the UTF-8 Decoder from Bjoern Hoehrmann which is licensed under the [MIT License](http://opensource.org/licenses/MIT) (see above). Copyright © 2008-2009 [Bjoern Hoehrmann](http://bjoern.hoehrmann.de/) +The class contains the UTF-8 Decoder from Bjoern Hoehrmann which is licensed under the [MIT License](http://opensource.org/licenses/MIT) (see above). Copyright © 2008-2009 [Björn Hoehrmann](http://bjoern.hoehrmann.de/) ## Contact If you have questions regarding the library, I would like to invite you to [open an issue at Github](https://github.com/nlohmann/json/issues/new). Please describe your request, problem, or question as detailed as possible, and also mention the version of the library you are using as well as the version of your compiler and operating system. Opening an issue at Github allows other users and contributors to this library to collaborate. For instance, I have little experience with MSVC, and most issues in this regard have been solved by a growing community. If you have a look at the [closed issues](https://github.com/nlohmann/json/issues?q=is%3Aissue+is%3Aclosed), you will see that we react quite timely in most cases. -Only if your request would contain confidential information, please [send me an email](mailto:mail@nlohmann.me). +Only if your request would contain confidential information, please [send me an email](mailto:mail@nlohmann.me). For encrypted messages, please usse [this key](https://keybase.io/nlohmann/pgp_keys.asc). ## Thanks @@ -910,6 +912,9 @@ I deeply appreciate the help of the following people. - [Pavel](https://github.com/crea7or) helped fixing some warnings in MSVC. - [Jamie Seward](https://github.com/jseward) avoided unneccessary string copies in `find()` and `count()`. - [Mitja](https://github.com/Itja) fixed some typos. +- [Jorrit Wronski](https://github.com/jowr) updated the Hunter package links. +- [Matthias Möller](https://github.com/TinyTinni) added a `.natvis` for the MSVC debug view. +- [bogemic](https://github.com/bogemic) fixed some C++17 deprecation warnings. Thanks a lot for helping out! Please [let me know](mailto:mail@nlohmann.me) if I forgot someone. @@ -954,7 +959,7 @@ The library is currently used in Apple macOS Sierra and iOS 10. I am not sure wh - As the exact type of a number is not defined in the [JSON specification](http://rfc7159.net/rfc7159), this library tries to choose the best fitting C++ number type automatically. As a result, the type `double` may be used to store numbers which may yield [**floating-point exceptions**](https://github.com/nlohmann/json/issues/181) in certain rare situations if floating-point exceptions have been unmasked in the calling code. These exceptions are not caused by the library and need to be fixed in the calling code, such as by re-masking the exceptions prior to calling library functions. - The library supports **Unicode input** as follows: - Only **UTF-8** encoded input is supported which is the default encoding for JSON according to [RFC 7159](http://rfc7159.net/rfc7159#rfc.section.8.1). - - Other encodings such as Latin-1, UTF-16, or UTF-32 are not supported and will yield parse errors. + - Other encodings such as Latin-1, UTF-16, or UTF-32 are not supported and will yield parse or serialization errors. - [Unicode noncharacters](http://www.unicode.org/faq/private_use.html#nonchar1) will not be replaced by the library. - Invalid surrogates (e.g., incomplete pairs such as `\uDEAD`) will yield parse errors. - The strings stored in the library are UTF-8 encoded. When using the default string type (`std::string`), note that its length/size functions return the number of stored bytes rather than the number of characters or glyphs. From 920f64c01c126e0664b3b1905c3f60872bd518cd Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Wed, 13 Dec 2017 22:18:05 +0100 Subject: [PATCH 04/59] :arrow_up: updated to Catch 2.0.1 Update required all CHECK_THROWS_AS macros to pass the exception type without reference, because this is now done by Catch2. --- test/src/unit-algorithms.cpp | 2 +- test/src/unit-allocator.cpp | 22 +- test/src/unit-cbor.cpp | 47 +- test/src/unit-class_const_iterator.cpp | 8 +- test/src/unit-class_iterator.cpp | 8 +- test/src/unit-class_parser.cpp | 240 +- test/src/unit-constructor1.cpp | 63 +- test/src/unit-conversions.cpp | 95 +- test/src/unit-deserialization.cpp | 62 +- test/src/unit-element_access1.cpp | 166 +- test/src/unit-element_access2.cpp | 168 +- test/src/unit-iterators1.cpp | 80 +- test/src/unit-iterators2.cpp | 232 +- test/src/unit-json_patch.cpp | 78 +- test/src/unit-json_pointer.cpp | 58 +- test/src/unit-modifiers.cpp | 70 +- test/src/unit-msgpack.cpp | 42 +- test/src/unit-readme.cpp | 1 + test/src/unit-reference_access.cpp | 84 +- test/src/unit-regression.cpp | 84 +- test/src/unit-testsuites.cpp | 8 +- test/src/unit-unicode.cpp | 26 +- test/thirdparty/catch/catch.hpp | 18000 ++++++++++++----------- 23 files changed, 10021 insertions(+), 9623 deletions(-) diff --git a/test/src/unit-algorithms.cpp b/test/src/unit-algorithms.cpp index bc108dcd..6136fefa 100644 --- a/test/src/unit-algorithms.cpp +++ b/test/src/unit-algorithms.cpp @@ -240,7 +240,7 @@ TEST_CASE("algorithms") SECTION("sorting an object") { json j({{"one", 1}, {"two", 2}}); - CHECK_THROWS_AS(std::sort(j.begin(), j.end()), json::invalid_iterator&); + CHECK_THROWS_AS(std::sort(j.begin(), j.end()), json::invalid_iterator); CHECK_THROWS_WITH(std::sort(j.begin(), j.end()), "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } diff --git a/test/src/unit-allocator.cpp b/test/src/unit-allocator.cpp index d2423a48..903d5950 100644 --- a/test/src/unit-allocator.cpp +++ b/test/src/unit-allocator.cpp @@ -59,7 +59,7 @@ TEST_CASE("bad_alloc") bad_allocator>; // creating an object should throw - CHECK_THROWS_AS(bad_json(bad_json::value_t::object), std::bad_alloc&); + CHECK_THROWS_AS(bad_json(bad_json::value_t::object), std::bad_alloc); } } @@ -143,7 +143,7 @@ TEST_CASE("controlled bad_alloc") auto t = my_json::value_t::object; CHECK_NOTHROW(my_allocator_clean_up(my_json::json_value(t).object)); next_construct_fails = true; - CHECK_THROWS_AS(my_json::json_value(t), std::bad_alloc&); + CHECK_THROWS_AS(my_json::json_value(t), std::bad_alloc); next_construct_fails = false; } SECTION("array") @@ -152,7 +152,7 @@ TEST_CASE("controlled bad_alloc") auto t = my_json::value_t::array; CHECK_NOTHROW(my_allocator_clean_up(my_json::json_value(t).array)); next_construct_fails = true; - CHECK_THROWS_AS(my_json::json_value(t), std::bad_alloc&); + CHECK_THROWS_AS(my_json::json_value(t), std::bad_alloc); next_construct_fails = false; } SECTION("string") @@ -161,7 +161,7 @@ TEST_CASE("controlled bad_alloc") auto t = my_json::value_t::string; CHECK_NOTHROW(my_allocator_clean_up(my_json::json_value(t).string)); next_construct_fails = true; - CHECK_THROWS_AS(my_json::json_value(t), std::bad_alloc&); + CHECK_THROWS_AS(my_json::json_value(t), std::bad_alloc); next_construct_fails = false; } } @@ -172,7 +172,7 @@ TEST_CASE("controlled bad_alloc") my_json::string_t v("foo"); CHECK_NOTHROW(my_allocator_clean_up(my_json::json_value(v).string)); next_construct_fails = true; - CHECK_THROWS_AS(my_json::json_value(v), std::bad_alloc&); + CHECK_THROWS_AS(my_json::json_value(v), std::bad_alloc); next_construct_fails = false; } @@ -183,7 +183,7 @@ TEST_CASE("controlled bad_alloc") my_json::object_t v {{"foo", "bar"}}; CHECK_NOTHROW(my_json::json_value j(v)); next_construct_fails = true; - CHECK_THROWS_AS(my_json::json_value j(v), std::bad_alloc&); + CHECK_THROWS_AS(my_json::json_value j(v), std::bad_alloc); next_construct_fails = false; } */ @@ -194,7 +194,7 @@ TEST_CASE("controlled bad_alloc") my_json::array_t v = {"foo", "bar", "baz"}; CHECK_NOTHROW(my_json::json_value j(v)); next_construct_fails = true; - CHECK_THROWS_AS(my_json::json_value j(v), std::bad_alloc&); + CHECK_THROWS_AS(my_json::json_value j(v), std::bad_alloc); next_construct_fails = false; } */ @@ -208,7 +208,7 @@ TEST_CASE("controlled bad_alloc") std::map v {{"foo", "bar"}}; CHECK_NOTHROW(my_json(v)); next_construct_fails = true; - CHECK_THROWS_AS(my_json(v), std::bad_alloc&); + CHECK_THROWS_AS(my_json(v), std::bad_alloc); next_construct_fails = false; } @@ -218,7 +218,7 @@ TEST_CASE("controlled bad_alloc") std::vector v {"foo", "bar", "baz"}; CHECK_NOTHROW(my_json(v)); next_construct_fails = true; - CHECK_THROWS_AS(my_json(v), std::bad_alloc&); + CHECK_THROWS_AS(my_json(v), std::bad_alloc); next_construct_fails = false; } @@ -227,7 +227,7 @@ TEST_CASE("controlled bad_alloc") next_construct_fails = false; CHECK_NOTHROW(my_json("foo")); next_construct_fails = true; - CHECK_THROWS_AS(my_json("foo"), std::bad_alloc&); + CHECK_THROWS_AS(my_json("foo"), std::bad_alloc); next_construct_fails = false; } @@ -237,7 +237,7 @@ TEST_CASE("controlled bad_alloc") std::string s("foo"); CHECK_NOTHROW(my_json(s)); next_construct_fails = true; - CHECK_THROWS_AS(my_json(s), std::bad_alloc&); + CHECK_THROWS_AS(my_json(s), std::bad_alloc); next_construct_fails = false; } } diff --git a/test/src/unit-cbor.cpp b/test/src/unit-cbor.cpp index 8d28f686..330b7ca1 100644 --- a/test/src/unit-cbor.cpp +++ b/test/src/unit-cbor.cpp @@ -31,6 +31,7 @@ SOFTWARE. #include "json.hpp" using nlohmann::json; +#include #include TEST_CASE("CBOR") @@ -739,13 +740,13 @@ TEST_CASE("CBOR") { SECTION("no byte follows") { - CHECK_THROWS_AS(json::from_cbor(std::vector({0xf9})), json::parse_error&); + CHECK_THROWS_AS(json::from_cbor(std::vector({0xf9})), json::parse_error); CHECK_THROWS_WITH(json::from_cbor(std::vector({0xf9})), "[json.exception.parse_error.110] parse error at 2: unexpected end of input"); } SECTION("only one byte follows") { - CHECK_THROWS_AS(json::from_cbor(std::vector({0xf9, 0x7c})), json::parse_error&); + CHECK_THROWS_AS(json::from_cbor(std::vector({0xf9, 0x7c})), json::parse_error); CHECK_THROWS_WITH(json::from_cbor(std::vector({0xf9, 0x7c})), "[json.exception.parse_error.110] parse error at 3: unexpected end of input"); } @@ -1226,28 +1227,28 @@ TEST_CASE("CBOR") { SECTION("empty byte vector") { - CHECK_THROWS_AS(json::from_cbor(std::vector()), json::parse_error&); + CHECK_THROWS_AS(json::from_cbor(std::vector()), json::parse_error); CHECK_THROWS_WITH(json::from_cbor(std::vector()), "[json.exception.parse_error.110] parse error at 1: unexpected end of input"); } SECTION("too short byte vector") { - CHECK_THROWS_AS(json::from_cbor(std::vector({0x18})), json::parse_error&); - CHECK_THROWS_AS(json::from_cbor(std::vector({0x19})), json::parse_error&); - CHECK_THROWS_AS(json::from_cbor(std::vector({0x19, 0x00})), json::parse_error&); - CHECK_THROWS_AS(json::from_cbor(std::vector({0x1a})), json::parse_error&); - CHECK_THROWS_AS(json::from_cbor(std::vector({0x1a, 0x00})), json::parse_error&); - CHECK_THROWS_AS(json::from_cbor(std::vector({0x1a, 0x00, 0x00})), json::parse_error&); - CHECK_THROWS_AS(json::from_cbor(std::vector({0x1a, 0x00, 0x00, 0x00})), json::parse_error&); - CHECK_THROWS_AS(json::from_cbor(std::vector({0x1b})), json::parse_error&); - CHECK_THROWS_AS(json::from_cbor(std::vector({0x1b, 0x00})), json::parse_error&); - CHECK_THROWS_AS(json::from_cbor(std::vector({0x1b, 0x00, 0x00})), json::parse_error&); - CHECK_THROWS_AS(json::from_cbor(std::vector({0x1b, 0x00, 0x00, 0x00})), json::parse_error&); - CHECK_THROWS_AS(json::from_cbor(std::vector({0x1b, 0x00, 0x00, 0x00, 0x00})), json::parse_error&); - CHECK_THROWS_AS(json::from_cbor(std::vector({0x1b, 0x00, 0x00, 0x00, 0x00, 0x00})), json::parse_error&); - CHECK_THROWS_AS(json::from_cbor(std::vector({0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})), json::parse_error&); - CHECK_THROWS_AS(json::from_cbor(std::vector({0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})), json::parse_error&); + CHECK_THROWS_AS(json::from_cbor(std::vector({0x18})), json::parse_error); + CHECK_THROWS_AS(json::from_cbor(std::vector({0x19})), json::parse_error); + CHECK_THROWS_AS(json::from_cbor(std::vector({0x19, 0x00})), json::parse_error); + CHECK_THROWS_AS(json::from_cbor(std::vector({0x1a})), json::parse_error); + CHECK_THROWS_AS(json::from_cbor(std::vector({0x1a, 0x00})), json::parse_error); + CHECK_THROWS_AS(json::from_cbor(std::vector({0x1a, 0x00, 0x00})), json::parse_error); + CHECK_THROWS_AS(json::from_cbor(std::vector({0x1a, 0x00, 0x00, 0x00})), json::parse_error); + CHECK_THROWS_AS(json::from_cbor(std::vector({0x1b})), json::parse_error); + CHECK_THROWS_AS(json::from_cbor(std::vector({0x1b, 0x00})), json::parse_error); + CHECK_THROWS_AS(json::from_cbor(std::vector({0x1b, 0x00, 0x00})), json::parse_error); + CHECK_THROWS_AS(json::from_cbor(std::vector({0x1b, 0x00, 0x00, 0x00})), json::parse_error); + CHECK_THROWS_AS(json::from_cbor(std::vector({0x1b, 0x00, 0x00, 0x00, 0x00})), json::parse_error); + CHECK_THROWS_AS(json::from_cbor(std::vector({0x1b, 0x00, 0x00, 0x00, 0x00, 0x00})), json::parse_error); + CHECK_THROWS_AS(json::from_cbor(std::vector({0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})), json::parse_error); + CHECK_THROWS_AS(json::from_cbor(std::vector({0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})), json::parse_error); CHECK_THROWS_WITH(json::from_cbor(std::vector({0x18})), "[json.exception.parse_error.110] parse error at 2: unexpected end of input"); @@ -1285,10 +1286,10 @@ TEST_CASE("CBOR") { SECTION("concrete examples") { - CHECK_THROWS_AS(json::from_cbor(std::vector({0x1c})), json::parse_error&); + CHECK_THROWS_AS(json::from_cbor(std::vector({0x1c})), json::parse_error); CHECK_THROWS_WITH(json::from_cbor(std::vector({0x1c})), "[json.exception.parse_error.112] parse error at 1: error reading CBOR; last byte: 0x1C"); - CHECK_THROWS_AS(json::from_cbor(std::vector({0xf8})), json::parse_error&); + CHECK_THROWS_AS(json::from_cbor(std::vector({0xf8})), json::parse_error); CHECK_THROWS_WITH(json::from_cbor(std::vector({0xf8})), "[json.exception.parse_error.112] parse error at 1: error reading CBOR; last byte: 0xF8"); } @@ -1339,14 +1340,14 @@ TEST_CASE("CBOR") 0xf8 }) { - CHECK_THROWS_AS(json::from_cbor(std::vector({static_cast(byte)})), json::parse_error&); + CHECK_THROWS_AS(json::from_cbor(std::vector({static_cast(byte)})), json::parse_error); } } } SECTION("invalid string in map") { - CHECK_THROWS_AS(json::from_cbor(std::vector({0xa1, 0xff, 0x01})), json::parse_error&); + CHECK_THROWS_AS(json::from_cbor(std::vector({0xa1, 0xff, 0x01})), json::parse_error); CHECK_THROWS_WITH(json::from_cbor(std::vector({0xa1, 0xff, 0x01})), "[json.exception.parse_error.113] parse error at 2: expected a CBOR string; last byte: 0xFF"); } @@ -1362,7 +1363,7 @@ TEST_CASE("CBOR") SECTION("strict mode") { - CHECK_THROWS_AS(json::from_cbor(vec), json::parse_error&); + CHECK_THROWS_AS(json::from_cbor(vec), json::parse_error); CHECK_THROWS_WITH(json::from_cbor(vec), "[json.exception.parse_error.110] parse error at 2: expected end of input"); } diff --git a/test/src/unit-class_const_iterator.cpp b/test/src/unit-class_const_iterator.cpp index 573e773b..5356fb35 100644 --- a/test/src/unit-class_const_iterator.cpp +++ b/test/src/unit-class_const_iterator.cpp @@ -147,7 +147,7 @@ TEST_CASE("const_iterator class") { json j(json::value_t::null); json::const_iterator it = j.cbegin(); - CHECK_THROWS_AS(*it, json::invalid_iterator&); + CHECK_THROWS_AS(*it, json::invalid_iterator); CHECK_THROWS_WITH(*it, "[json.exception.invalid_iterator.214] cannot get value"); } @@ -157,7 +157,7 @@ TEST_CASE("const_iterator class") json::const_iterator it = j.cbegin(); CHECK(*it == json(17)); it = j.cend(); - CHECK_THROWS_AS(*it, json::invalid_iterator&); + CHECK_THROWS_AS(*it, json::invalid_iterator); CHECK_THROWS_WITH(*it, "[json.exception.invalid_iterator.214] cannot get value"); } @@ -182,7 +182,7 @@ TEST_CASE("const_iterator class") { json j(json::value_t::null); json::const_iterator it = j.cbegin(); - CHECK_THROWS_AS(std::string(it->type_name()), json::invalid_iterator&); + CHECK_THROWS_AS(std::string(it->type_name()), json::invalid_iterator); CHECK_THROWS_WITH(std::string(it->type_name()), "[json.exception.invalid_iterator.214] cannot get value"); } @@ -192,7 +192,7 @@ TEST_CASE("const_iterator class") json::const_iterator it = j.cbegin(); CHECK(std::string(it->type_name()) == "number"); it = j.cend(); - CHECK_THROWS_AS(std::string(it->type_name()), json::invalid_iterator&); + CHECK_THROWS_AS(std::string(it->type_name()), json::invalid_iterator); CHECK_THROWS_WITH(std::string(it->type_name()), "[json.exception.invalid_iterator.214] cannot get value"); } diff --git a/test/src/unit-class_iterator.cpp b/test/src/unit-class_iterator.cpp index 1ef4a538..cb7f16a5 100644 --- a/test/src/unit-class_iterator.cpp +++ b/test/src/unit-class_iterator.cpp @@ -131,7 +131,7 @@ TEST_CASE("iterator class") { json j(json::value_t::null); json::iterator it = j.begin(); - CHECK_THROWS_AS(*it, json::invalid_iterator&); + CHECK_THROWS_AS(*it, json::invalid_iterator); CHECK_THROWS_WITH(*it, "[json.exception.invalid_iterator.214] cannot get value"); } @@ -141,7 +141,7 @@ TEST_CASE("iterator class") json::iterator it = j.begin(); CHECK(*it == json(17)); it = j.end(); - CHECK_THROWS_AS(*it, json::invalid_iterator&); + CHECK_THROWS_AS(*it, json::invalid_iterator); CHECK_THROWS_WITH(*it, "[json.exception.invalid_iterator.214] cannot get value"); } @@ -166,7 +166,7 @@ TEST_CASE("iterator class") { json j(json::value_t::null); json::iterator it = j.begin(); - CHECK_THROWS_AS(std::string(it->type_name()), json::invalid_iterator&); + CHECK_THROWS_AS(std::string(it->type_name()), json::invalid_iterator); CHECK_THROWS_WITH(std::string(it->type_name()), "[json.exception.invalid_iterator.214] cannot get value"); } @@ -176,7 +176,7 @@ TEST_CASE("iterator class") json::iterator it = j.begin(); CHECK(std::string(it->type_name()) == "number"); it = j.end(); - CHECK_THROWS_AS(std::string(it->type_name()), json::invalid_iterator&); + CHECK_THROWS_AS(std::string(it->type_name()), json::invalid_iterator); CHECK_THROWS_WITH(std::string(it->type_name()), "[json.exception.invalid_iterator.214] cannot get value"); } diff --git a/test/src/unit-class_parser.cpp b/test/src/unit-class_parser.cpp index 9afa7d26..7c4e635a 100644 --- a/test/src/unit-class_parser.cpp +++ b/test/src/unit-class_parser.cpp @@ -123,56 +123,56 @@ TEST_CASE("parser class") SECTION("errors") { // error: tab in string - CHECK_THROWS_AS(parser_helper("\"\t\""), json::parse_error&); + CHECK_THROWS_AS(parser_helper("\"\t\""), json::parse_error); CHECK_THROWS_WITH(parser_helper("\"\t\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); // error: newline in string - CHECK_THROWS_AS(parser_helper("\"\n\""), json::parse_error&); - CHECK_THROWS_AS(parser_helper("\"\r\""), json::parse_error&); + CHECK_THROWS_AS(parser_helper("\"\n\""), json::parse_error); + CHECK_THROWS_AS(parser_helper("\"\r\""), json::parse_error); CHECK_THROWS_WITH(parser_helper("\"\n\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); CHECK_THROWS_WITH(parser_helper("\"\r\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); // error: backspace in string - CHECK_THROWS_AS(parser_helper("\"\b\""), json::parse_error&); + CHECK_THROWS_AS(parser_helper("\"\b\""), json::parse_error); CHECK_THROWS_WITH(parser_helper("\"\b\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); // improve code coverage - CHECK_THROWS_AS(parser_helper("\uFF01"), json::parse_error&); - CHECK_THROWS_AS(parser_helper("[-4:1,]"), json::parse_error&); + CHECK_THROWS_AS(parser_helper("\uFF01"), json::parse_error); + CHECK_THROWS_AS(parser_helper("[-4:1,]"), json::parse_error); // unescaped control characters - CHECK_THROWS_AS(parser_helper("\"\x00\""), json::parse_error&); - CHECK_THROWS_AS(parser_helper("\"\x01\""), json::parse_error&); - CHECK_THROWS_AS(parser_helper("\"\x02\""), json::parse_error&); - CHECK_THROWS_AS(parser_helper("\"\x03\""), json::parse_error&); - CHECK_THROWS_AS(parser_helper("\"\x04\""), json::parse_error&); - CHECK_THROWS_AS(parser_helper("\"\x05\""), json::parse_error&); - CHECK_THROWS_AS(parser_helper("\"\x06\""), json::parse_error&); - CHECK_THROWS_AS(parser_helper("\"\x07\""), json::parse_error&); - CHECK_THROWS_AS(parser_helper("\"\x08\""), json::parse_error&); - CHECK_THROWS_AS(parser_helper("\"\x09\""), json::parse_error&); - CHECK_THROWS_AS(parser_helper("\"\x0a\""), json::parse_error&); - CHECK_THROWS_AS(parser_helper("\"\x0b\""), json::parse_error&); - CHECK_THROWS_AS(parser_helper("\"\x0c\""), json::parse_error&); - CHECK_THROWS_AS(parser_helper("\"\x0d\""), json::parse_error&); - CHECK_THROWS_AS(parser_helper("\"\x0e\""), json::parse_error&); - CHECK_THROWS_AS(parser_helper("\"\x0f\""), json::parse_error&); - CHECK_THROWS_AS(parser_helper("\"\x10\""), json::parse_error&); - CHECK_THROWS_AS(parser_helper("\"\x11\""), json::parse_error&); - CHECK_THROWS_AS(parser_helper("\"\x12\""), json::parse_error&); - CHECK_THROWS_AS(parser_helper("\"\x13\""), json::parse_error&); - CHECK_THROWS_AS(parser_helper("\"\x14\""), json::parse_error&); - CHECK_THROWS_AS(parser_helper("\"\x15\""), json::parse_error&); - CHECK_THROWS_AS(parser_helper("\"\x16\""), json::parse_error&); - CHECK_THROWS_AS(parser_helper("\"\x17\""), json::parse_error&); - CHECK_THROWS_AS(parser_helper("\"\x18\""), json::parse_error&); - CHECK_THROWS_AS(parser_helper("\"\x19\""), json::parse_error&); - CHECK_THROWS_AS(parser_helper("\"\x1a\""), json::parse_error&); - CHECK_THROWS_AS(parser_helper("\"\x1b\""), json::parse_error&); - CHECK_THROWS_AS(parser_helper("\"\x1c\""), json::parse_error&); - CHECK_THROWS_AS(parser_helper("\"\x1d\""), json::parse_error&); - CHECK_THROWS_AS(parser_helper("\"\x1e\""), json::parse_error&); - CHECK_THROWS_AS(parser_helper("\"\x1f\""), json::parse_error&); + CHECK_THROWS_AS(parser_helper("\"\x00\""), json::parse_error); + CHECK_THROWS_AS(parser_helper("\"\x01\""), json::parse_error); + CHECK_THROWS_AS(parser_helper("\"\x02\""), json::parse_error); + CHECK_THROWS_AS(parser_helper("\"\x03\""), json::parse_error); + CHECK_THROWS_AS(parser_helper("\"\x04\""), json::parse_error); + CHECK_THROWS_AS(parser_helper("\"\x05\""), json::parse_error); + CHECK_THROWS_AS(parser_helper("\"\x06\""), json::parse_error); + CHECK_THROWS_AS(parser_helper("\"\x07\""), json::parse_error); + CHECK_THROWS_AS(parser_helper("\"\x08\""), json::parse_error); + CHECK_THROWS_AS(parser_helper("\"\x09\""), json::parse_error); + CHECK_THROWS_AS(parser_helper("\"\x0a\""), json::parse_error); + CHECK_THROWS_AS(parser_helper("\"\x0b\""), json::parse_error); + CHECK_THROWS_AS(parser_helper("\"\x0c\""), json::parse_error); + CHECK_THROWS_AS(parser_helper("\"\x0d\""), json::parse_error); + CHECK_THROWS_AS(parser_helper("\"\x0e\""), json::parse_error); + CHECK_THROWS_AS(parser_helper("\"\x0f\""), json::parse_error); + CHECK_THROWS_AS(parser_helper("\"\x10\""), json::parse_error); + CHECK_THROWS_AS(parser_helper("\"\x11\""), json::parse_error); + CHECK_THROWS_AS(parser_helper("\"\x12\""), json::parse_error); + CHECK_THROWS_AS(parser_helper("\"\x13\""), json::parse_error); + CHECK_THROWS_AS(parser_helper("\"\x14\""), json::parse_error); + CHECK_THROWS_AS(parser_helper("\"\x15\""), json::parse_error); + CHECK_THROWS_AS(parser_helper("\"\x16\""), json::parse_error); + CHECK_THROWS_AS(parser_helper("\"\x17\""), json::parse_error); + CHECK_THROWS_AS(parser_helper("\"\x18\""), json::parse_error); + CHECK_THROWS_AS(parser_helper("\"\x19\""), json::parse_error); + CHECK_THROWS_AS(parser_helper("\"\x1a\""), json::parse_error); + CHECK_THROWS_AS(parser_helper("\"\x1b\""), json::parse_error); + CHECK_THROWS_AS(parser_helper("\"\x1c\""), json::parse_error); + CHECK_THROWS_AS(parser_helper("\"\x1d\""), json::parse_error); + CHECK_THROWS_AS(parser_helper("\"\x1e\""), json::parse_error); + CHECK_THROWS_AS(parser_helper("\"\x1f\""), json::parse_error); CHECK_THROWS_WITH(parser_helper("\"\x00\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: missing closing quote; last read: '\"'"); CHECK_THROWS_WITH(parser_helper("\"\x01\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); CHECK_THROWS_WITH(parser_helper("\"\x02\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); @@ -214,7 +214,7 @@ TEST_CASE("parser class") // uses an iterator range. std::string s = "\"1\""; s[1] = '\0'; - CHECK_THROWS_AS(json::parse(s.begin(), s.end()), json::parse_error&); + CHECK_THROWS_AS(json::parse(s.begin(), s.end()), json::parse_error); CHECK_THROWS_WITH(json::parse(s.begin(), s.end()), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); } } @@ -386,33 +386,33 @@ TEST_CASE("parser class") SECTION("overflow") { // overflows during parsing yield an exception - CHECK_THROWS_AS(parser_helper("1.18973e+4932") == json(), json::out_of_range&); + CHECK_THROWS_AS(parser_helper("1.18973e+4932") == json(), json::out_of_range); CHECK_THROWS_WITH(parser_helper("1.18973e+4932") == json(), "[json.exception.out_of_range.406] number overflow parsing '1.18973e+4932'"); } SECTION("invalid numbers") { - CHECK_THROWS_AS(parser_helper("01"), json::parse_error&); - CHECK_THROWS_AS(parser_helper("--1"), json::parse_error&); - CHECK_THROWS_AS(parser_helper("1."), json::parse_error&); - CHECK_THROWS_AS(parser_helper("1E"), json::parse_error&); - CHECK_THROWS_AS(parser_helper("1E-"), json::parse_error&); - CHECK_THROWS_AS(parser_helper("1.E1"), json::parse_error&); - CHECK_THROWS_AS(parser_helper("-1E"), json::parse_error&); - CHECK_THROWS_AS(parser_helper("-0E#"), json::parse_error&); - CHECK_THROWS_AS(parser_helper("-0E-#"), json::parse_error&); - CHECK_THROWS_AS(parser_helper("-0#"), json::parse_error&); - CHECK_THROWS_AS(parser_helper("-0.0:"), json::parse_error&); - CHECK_THROWS_AS(parser_helper("-0.0Z"), json::parse_error&); - CHECK_THROWS_AS(parser_helper("-0E123:"), json::parse_error&); - CHECK_THROWS_AS(parser_helper("-0e0-:"), json::parse_error&); - CHECK_THROWS_AS(parser_helper("-0e-:"), json::parse_error&); - CHECK_THROWS_AS(parser_helper("-0f"), json::parse_error&); + CHECK_THROWS_AS(parser_helper("01"), json::parse_error); + CHECK_THROWS_AS(parser_helper("--1"), json::parse_error); + CHECK_THROWS_AS(parser_helper("1."), json::parse_error); + CHECK_THROWS_AS(parser_helper("1E"), json::parse_error); + CHECK_THROWS_AS(parser_helper("1E-"), json::parse_error); + CHECK_THROWS_AS(parser_helper("1.E1"), json::parse_error); + CHECK_THROWS_AS(parser_helper("-1E"), json::parse_error); + CHECK_THROWS_AS(parser_helper("-0E#"), json::parse_error); + CHECK_THROWS_AS(parser_helper("-0E-#"), json::parse_error); + CHECK_THROWS_AS(parser_helper("-0#"), json::parse_error); + CHECK_THROWS_AS(parser_helper("-0.0:"), json::parse_error); + CHECK_THROWS_AS(parser_helper("-0.0Z"), json::parse_error); + CHECK_THROWS_AS(parser_helper("-0E123:"), json::parse_error); + CHECK_THROWS_AS(parser_helper("-0e0-:"), json::parse_error); + CHECK_THROWS_AS(parser_helper("-0e-:"), json::parse_error); + CHECK_THROWS_AS(parser_helper("-0f"), json::parse_error); // numbers must not begin with "+" - CHECK_THROWS_AS(parser_helper("+1"), json::parse_error&); - CHECK_THROWS_AS(parser_helper("+0"), json::parse_error&); + CHECK_THROWS_AS(parser_helper("+1"), json::parse_error); + CHECK_THROWS_AS(parser_helper("+0"), json::parse_error); CHECK_THROWS_WITH(parser_helper("01"), "[json.exception.parse_error.101] parse error at 2: syntax error - unexpected number literal; expected end of input"); @@ -717,20 +717,20 @@ TEST_CASE("parser class") SECTION("parse errors") { // unexpected end of number - CHECK_THROWS_AS(parser_helper("0."), json::parse_error&); - CHECK_THROWS_AS(parser_helper("-"), json::parse_error&); - CHECK_THROWS_AS(parser_helper("--"), json::parse_error&); - CHECK_THROWS_AS(parser_helper("-0."), json::parse_error&); - CHECK_THROWS_AS(parser_helper("-."), json::parse_error&); - CHECK_THROWS_AS(parser_helper("-:"), json::parse_error&); - CHECK_THROWS_AS(parser_helper("0.:"), json::parse_error&); - CHECK_THROWS_AS(parser_helper("e."), json::parse_error&); - CHECK_THROWS_AS(parser_helper("1e."), json::parse_error&); - CHECK_THROWS_AS(parser_helper("1e/"), json::parse_error&); - CHECK_THROWS_AS(parser_helper("1e:"), json::parse_error&); - CHECK_THROWS_AS(parser_helper("1E."), json::parse_error&); - CHECK_THROWS_AS(parser_helper("1E/"), json::parse_error&); - CHECK_THROWS_AS(parser_helper("1E:"), json::parse_error&); + CHECK_THROWS_AS(parser_helper("0."), json::parse_error); + CHECK_THROWS_AS(parser_helper("-"), json::parse_error); + CHECK_THROWS_AS(parser_helper("--"), json::parse_error); + CHECK_THROWS_AS(parser_helper("-0."), json::parse_error); + CHECK_THROWS_AS(parser_helper("-."), json::parse_error); + CHECK_THROWS_AS(parser_helper("-:"), json::parse_error); + CHECK_THROWS_AS(parser_helper("0.:"), json::parse_error); + CHECK_THROWS_AS(parser_helper("e."), json::parse_error); + CHECK_THROWS_AS(parser_helper("1e."), json::parse_error); + CHECK_THROWS_AS(parser_helper("1e/"), json::parse_error); + CHECK_THROWS_AS(parser_helper("1e:"), json::parse_error); + CHECK_THROWS_AS(parser_helper("1E."), json::parse_error); + CHECK_THROWS_AS(parser_helper("1E/"), json::parse_error); + CHECK_THROWS_AS(parser_helper("1E:"), json::parse_error); CHECK_THROWS_WITH(parser_helper("0."), "[json.exception.parse_error.101] parse error at 3: syntax error - invalid number; expected digit after '.'; last read: '0.'"); CHECK_THROWS_WITH(parser_helper("-"), @@ -761,11 +761,11 @@ TEST_CASE("parser class") "[json.exception.parse_error.101] parse error at 3: syntax error - invalid number; expected '+', '-', or digit after exponent; last read: '1E:'"); // unexpected end of null - CHECK_THROWS_AS(parser_helper("n"), json::parse_error&); - CHECK_THROWS_AS(parser_helper("nu"), json::parse_error&); - CHECK_THROWS_AS(parser_helper("nul"), json::parse_error&); - CHECK_THROWS_AS(parser_helper("nulk"), json::parse_error&); - CHECK_THROWS_AS(parser_helper("nulm"), json::parse_error&); + CHECK_THROWS_AS(parser_helper("n"), json::parse_error); + CHECK_THROWS_AS(parser_helper("nu"), json::parse_error); + CHECK_THROWS_AS(parser_helper("nul"), json::parse_error); + CHECK_THROWS_AS(parser_helper("nulk"), json::parse_error); + CHECK_THROWS_AS(parser_helper("nulm"), json::parse_error); CHECK_THROWS_WITH(parser_helper("n"), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid literal; last read: 'n'"); CHECK_THROWS_WITH(parser_helper("nu"), @@ -778,11 +778,11 @@ TEST_CASE("parser class") "[json.exception.parse_error.101] parse error at 4: syntax error - invalid literal; last read: 'nulm'"); // unexpected end of true - CHECK_THROWS_AS(parser_helper("t"), json::parse_error&); - CHECK_THROWS_AS(parser_helper("tr"), json::parse_error&); - CHECK_THROWS_AS(parser_helper("tru"), json::parse_error&); - CHECK_THROWS_AS(parser_helper("trud"), json::parse_error&); - CHECK_THROWS_AS(parser_helper("truf"), json::parse_error&); + CHECK_THROWS_AS(parser_helper("t"), json::parse_error); + CHECK_THROWS_AS(parser_helper("tr"), json::parse_error); + CHECK_THROWS_AS(parser_helper("tru"), json::parse_error); + CHECK_THROWS_AS(parser_helper("trud"), json::parse_error); + CHECK_THROWS_AS(parser_helper("truf"), json::parse_error); CHECK_THROWS_WITH(parser_helper("t"), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid literal; last read: 't'"); CHECK_THROWS_WITH(parser_helper("tr"), @@ -795,12 +795,12 @@ TEST_CASE("parser class") "[json.exception.parse_error.101] parse error at 4: syntax error - invalid literal; last read: 'truf'"); // unexpected end of false - CHECK_THROWS_AS(parser_helper("f"), json::parse_error&); - CHECK_THROWS_AS(parser_helper("fa"), json::parse_error&); - CHECK_THROWS_AS(parser_helper("fal"), json::parse_error&); - CHECK_THROWS_AS(parser_helper("fals"), json::parse_error&); - CHECK_THROWS_AS(parser_helper("falsd"), json::parse_error&); - CHECK_THROWS_AS(parser_helper("falsf"), json::parse_error&); + CHECK_THROWS_AS(parser_helper("f"), json::parse_error); + CHECK_THROWS_AS(parser_helper("fa"), json::parse_error); + CHECK_THROWS_AS(parser_helper("fal"), json::parse_error); + CHECK_THROWS_AS(parser_helper("fals"), json::parse_error); + CHECK_THROWS_AS(parser_helper("falsd"), json::parse_error); + CHECK_THROWS_AS(parser_helper("falsf"), json::parse_error); CHECK_THROWS_WITH(parser_helper("f"), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid literal; last read: 'f'"); CHECK_THROWS_WITH(parser_helper("fa"), @@ -815,11 +815,11 @@ TEST_CASE("parser class") "[json.exception.parse_error.101] parse error at 5: syntax error - invalid literal; last read: 'falsf'"); // missing/unexpected end of array - CHECK_THROWS_AS(parser_helper("["), json::parse_error&); - CHECK_THROWS_AS(parser_helper("[1"), json::parse_error&); - CHECK_THROWS_AS(parser_helper("[1,"), json::parse_error&); - CHECK_THROWS_AS(parser_helper("[1,]"), json::parse_error&); - CHECK_THROWS_AS(parser_helper("]"), json::parse_error&); + CHECK_THROWS_AS(parser_helper("["), json::parse_error); + CHECK_THROWS_AS(parser_helper("[1"), json::parse_error); + CHECK_THROWS_AS(parser_helper("[1,"), json::parse_error); + CHECK_THROWS_AS(parser_helper("[1,]"), json::parse_error); + CHECK_THROWS_AS(parser_helper("]"), json::parse_error); CHECK_THROWS_WITH(parser_helper("["), "[json.exception.parse_error.101] parse error at 2: syntax error - unexpected end of input; expected '[', '{', or a literal"); CHECK_THROWS_WITH(parser_helper("[1"), @@ -832,12 +832,12 @@ TEST_CASE("parser class") "[json.exception.parse_error.101] parse error at 1: syntax error - unexpected ']'; expected '[', '{', or a literal"); // missing/unexpected end of object - CHECK_THROWS_AS(parser_helper("{"), json::parse_error&); - CHECK_THROWS_AS(parser_helper("{\"foo\""), json::parse_error&); - CHECK_THROWS_AS(parser_helper("{\"foo\":"), json::parse_error&); - CHECK_THROWS_AS(parser_helper("{\"foo\":}"), json::parse_error&); - CHECK_THROWS_AS(parser_helper("{\"foo\":1,}"), json::parse_error&); - CHECK_THROWS_AS(parser_helper("}"), json::parse_error&); + CHECK_THROWS_AS(parser_helper("{"), json::parse_error); + CHECK_THROWS_AS(parser_helper("{\"foo\""), json::parse_error); + CHECK_THROWS_AS(parser_helper("{\"foo\":"), json::parse_error); + CHECK_THROWS_AS(parser_helper("{\"foo\":}"), json::parse_error); + CHECK_THROWS_AS(parser_helper("{\"foo\":1,}"), json::parse_error); + CHECK_THROWS_AS(parser_helper("}"), json::parse_error); CHECK_THROWS_WITH(parser_helper("{"), "[json.exception.parse_error.101] parse error at 2: syntax error - unexpected end of input; expected string literal"); CHECK_THROWS_WITH(parser_helper("{\"foo\""), @@ -852,16 +852,16 @@ TEST_CASE("parser class") "[json.exception.parse_error.101] parse error at 1: syntax error - unexpected '}'; expected '[', '{', or a literal"); // missing/unexpected end of string - CHECK_THROWS_AS(parser_helper("\""), json::parse_error&); - CHECK_THROWS_AS(parser_helper("\"\\\""), json::parse_error&); - CHECK_THROWS_AS(parser_helper("\"\\u\""), json::parse_error&); - CHECK_THROWS_AS(parser_helper("\"\\u0\""), json::parse_error&); - CHECK_THROWS_AS(parser_helper("\"\\u01\""), json::parse_error&); - CHECK_THROWS_AS(parser_helper("\"\\u012\""), json::parse_error&); - CHECK_THROWS_AS(parser_helper("\"\\u"), json::parse_error&); - CHECK_THROWS_AS(parser_helper("\"\\u0"), json::parse_error&); - CHECK_THROWS_AS(parser_helper("\"\\u01"), json::parse_error&); - CHECK_THROWS_AS(parser_helper("\"\\u012"), json::parse_error&); + CHECK_THROWS_AS(parser_helper("\""), json::parse_error); + CHECK_THROWS_AS(parser_helper("\"\\\""), json::parse_error); + CHECK_THROWS_AS(parser_helper("\"\\u\""), json::parse_error); + CHECK_THROWS_AS(parser_helper("\"\\u0\""), json::parse_error); + CHECK_THROWS_AS(parser_helper("\"\\u01\""), json::parse_error); + CHECK_THROWS_AS(parser_helper("\"\\u012\""), json::parse_error); + CHECK_THROWS_AS(parser_helper("\"\\u"), json::parse_error); + CHECK_THROWS_AS(parser_helper("\"\\u0"), json::parse_error); + CHECK_THROWS_AS(parser_helper("\"\\u01"), json::parse_error); + CHECK_THROWS_AS(parser_helper("\"\\u012"), json::parse_error); CHECK_THROWS_WITH(parser_helper("\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: missing closing quote; last read: '\"'"); CHECK_THROWS_WITH(parser_helper("\"\\\""), @@ -913,7 +913,7 @@ TEST_CASE("parser class") // any other combination of backslash and character is invalid default: { - CHECK_THROWS_AS(parser_helper(s.c_str()), json::parse_error&); + CHECK_THROWS_AS(parser_helper(s.c_str()), json::parse_error); // only check error message if c is not a control character if (c > 0x1f) { @@ -989,7 +989,7 @@ TEST_CASE("parser class") else { CAPTURE(s1); - CHECK_THROWS_AS(parser_helper(s1.c_str()), json::parse_error&); + CHECK_THROWS_AS(parser_helper(s1.c_str()), json::parse_error); // only check error message if c is not a control character if (c > 0x1f) { @@ -998,7 +998,7 @@ TEST_CASE("parser class") } CAPTURE(s2); - CHECK_THROWS_AS(parser_helper(s2.c_str()), json::parse_error&); + CHECK_THROWS_AS(parser_helper(s2.c_str()), json::parse_error); // only check error message if c is not a control character if (c > 0x1f) { @@ -1007,7 +1007,7 @@ TEST_CASE("parser class") } CAPTURE(s3); - CHECK_THROWS_AS(parser_helper(s3.c_str()), json::parse_error&); + CHECK_THROWS_AS(parser_helper(s3.c_str()), json::parse_error); // only check error message if c is not a control character if (c > 0x1f) { @@ -1016,7 +1016,7 @@ TEST_CASE("parser class") } CAPTURE(s4); - CHECK_THROWS_AS(parser_helper(s4.c_str()), json::parse_error&); + CHECK_THROWS_AS(parser_helper(s4.c_str()), json::parse_error); // only check error message if c is not a control character if (c > 0x1f) { @@ -1028,13 +1028,13 @@ TEST_CASE("parser class") } // missing part of a surrogate pair - CHECK_THROWS_AS(json::parse("\"\\uD80C\""), json::parse_error&); + CHECK_THROWS_AS(json::parse("\"\\uD80C\""), json::parse_error); CHECK_THROWS_WITH(json::parse("\"\\uD80C\""), "[json.exception.parse_error.101] parse error at 8: syntax error - invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF; last read: '\"\\uD80C\"'"); // invalid surrogate pair - CHECK_THROWS_AS(json::parse("\"\\uD80C\\uD80C\""), json::parse_error&); - CHECK_THROWS_AS(json::parse("\"\\uD80C\\u0000\""), json::parse_error&); - CHECK_THROWS_AS(json::parse("\"\\uD80C\\uFFFF\""), json::parse_error&); + CHECK_THROWS_AS(json::parse("\"\\uD80C\\uD80C\""), json::parse_error); + CHECK_THROWS_AS(json::parse("\"\\uD80C\\u0000\""), json::parse_error); + CHECK_THROWS_AS(json::parse("\"\\uD80C\\uFFFF\""), json::parse_error); CHECK_THROWS_WITH(json::parse("\"\\uD80C\\uD80C\""), "[json.exception.parse_error.101] parse error at 13: syntax error - invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF; last read: '\"\\uD80C\\uD80C'"); CHECK_THROWS_WITH(json::parse("\"\\uD80C\\u0000\""), @@ -1229,11 +1229,11 @@ TEST_CASE("parser class") SECTION("tests found by mutate++") { // test case to make sure no comma preceeds the first key - CHECK_THROWS_AS(parser_helper("{,\"key\": false}"), json::parse_error&); + CHECK_THROWS_AS(parser_helper("{,\"key\": false}"), json::parse_error); CHECK_THROWS_WITH(parser_helper("{,\"key\": false}"), "[json.exception.parse_error.101] parse error at 2: syntax error - unexpected ','; expected string literal"); // test case to make sure an object is properly closed - CHECK_THROWS_AS(parser_helper("[{\"key\": false true]"), json::parse_error&); + CHECK_THROWS_AS(parser_helper("[{\"key\": false true]"), json::parse_error); CHECK_THROWS_WITH(parser_helper("[{\"key\": false true]"), "[json.exception.parse_error.101] parse error at 19: syntax error - unexpected true literal; expected '}'"); diff --git a/test/src/unit-constructor1.cpp b/test/src/unit-constructor1.cpp index d8c9482c..8840fe7e 100644 --- a/test/src/unit-constructor1.cpp +++ b/test/src/unit-constructor1.cpp @@ -36,6 +36,7 @@ using nlohmann::json; #include #include #include +#include #include #include #include @@ -1049,7 +1050,7 @@ TEST_CASE("constructors") SECTION("object with error") { CHECK_THROWS_AS(json::object({ {"one", 1}, {"two", 1u}, {"three", 2.2}, {"four", false}, 13 }), - json::type_error&); + json::type_error); CHECK_THROWS_WITH(json::object({ {"one", 1}, {"two", 1u}, {"three", 2.2}, {"four", false}, 13 }), "[json.exception.type_error.301] cannot create object from initializer list"); } @@ -1263,16 +1264,16 @@ TEST_CASE("constructors") { json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}, {"d", false}, {"e", true}}; json jobject2 = {{"a", "a"}, {"b", 1}, {"c", 17u}}; - CHECK_THROWS_AS(json(jobject.begin(), jobject2.end()), json::invalid_iterator&); - CHECK_THROWS_AS(json(jobject2.begin(), jobject.end()), json::invalid_iterator&); + CHECK_THROWS_AS(json(jobject.begin(), jobject2.end()), json::invalid_iterator); + CHECK_THROWS_AS(json(jobject2.begin(), jobject.end()), json::invalid_iterator); CHECK_THROWS_WITH(json(jobject.begin(), jobject2.end()), "[json.exception.invalid_iterator.201] iterators are not compatible"); CHECK_THROWS_WITH(json(jobject2.begin(), jobject.end()), "[json.exception.invalid_iterator.201] iterators are not compatible"); } { json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}, {"d", false}, {"e", true}}; json jobject2 = {{"a", "a"}, {"b", 1}, {"c", 17u}}; - CHECK_THROWS_AS(json(jobject.cbegin(), jobject2.cend()), json::invalid_iterator&); - CHECK_THROWS_AS(json(jobject2.cbegin(), jobject.cend()), json::invalid_iterator&); + CHECK_THROWS_AS(json(jobject.cbegin(), jobject2.cend()), json::invalid_iterator); + CHECK_THROWS_AS(json(jobject2.cbegin(), jobject.cend()), json::invalid_iterator); CHECK_THROWS_WITH(json(jobject.cbegin(), jobject2.cend()), "[json.exception.invalid_iterator.201] iterators are not compatible"); CHECK_THROWS_WITH(json(jobject2.cbegin(), jobject.cend()), "[json.exception.invalid_iterator.201] iterators are not compatible"); } @@ -1328,16 +1329,16 @@ TEST_CASE("constructors") { json jarray = {1, 2, 3, 4}; json jarray2 = {2, 3, 4, 5}; - CHECK_THROWS_AS(json(jarray.begin(), jarray2.end()), json::invalid_iterator&); - CHECK_THROWS_AS(json(jarray2.begin(), jarray.end()), json::invalid_iterator&); + CHECK_THROWS_AS(json(jarray.begin(), jarray2.end()), json::invalid_iterator); + CHECK_THROWS_AS(json(jarray2.begin(), jarray.end()), json::invalid_iterator); CHECK_THROWS_WITH(json(jarray.begin(), jarray2.end()), "[json.exception.invalid_iterator.201] iterators are not compatible"); CHECK_THROWS_WITH(json(jarray2.begin(), jarray.end()), "[json.exception.invalid_iterator.201] iterators are not compatible"); } { json jarray = {1, 2, 3, 4}; json jarray2 = {2, 3, 4, 5}; - CHECK_THROWS_AS(json(jarray.cbegin(), jarray2.cend()), json::invalid_iterator&); - CHECK_THROWS_AS(json(jarray2.cbegin(), jarray.cend()), json::invalid_iterator&); + CHECK_THROWS_AS(json(jarray.cbegin(), jarray2.cend()), json::invalid_iterator); + CHECK_THROWS_AS(json(jarray2.cbegin(), jarray.cend()), json::invalid_iterator); CHECK_THROWS_WITH(json(jarray.cbegin(), jarray2.cend()), "[json.exception.invalid_iterator.201] iterators are not compatible"); CHECK_THROWS_WITH(json(jarray2.cbegin(), jarray.cend()), "[json.exception.invalid_iterator.201] iterators are not compatible"); } @@ -1352,13 +1353,13 @@ TEST_CASE("constructors") { { json j; - CHECK_THROWS_AS(json(j.begin(), j.end()), json::invalid_iterator&); + CHECK_THROWS_AS(json(j.begin(), j.end()), json::invalid_iterator); CHECK_THROWS_WITH(json(j.begin(), j.end()), "[json.exception.invalid_iterator.206] cannot construct with iterators from null"); } { json j; - CHECK_THROWS_AS(json(j.cbegin(), j.cend()), json::invalid_iterator&); + CHECK_THROWS_AS(json(j.cbegin(), j.cend()), json::invalid_iterator); CHECK_THROWS_WITH(json(j.cbegin(), j.cend()), "[json.exception.invalid_iterator.206] cannot construct with iterators from null"); } @@ -1441,15 +1442,15 @@ TEST_CASE("constructors") { { json j = "foo"; - CHECK_THROWS_AS(json(j.end(), j.end()), json::invalid_iterator&); - CHECK_THROWS_AS(json(j.begin(), j.begin()), json::invalid_iterator&); + CHECK_THROWS_AS(json(j.end(), j.end()), json::invalid_iterator); + CHECK_THROWS_AS(json(j.begin(), j.begin()), json::invalid_iterator); CHECK_THROWS_WITH(json(j.end(), j.end()), "[json.exception.invalid_iterator.204] iterators out of range"); CHECK_THROWS_WITH(json(j.begin(), j.begin()), "[json.exception.invalid_iterator.204] iterators out of range"); } { json j = "bar"; - CHECK_THROWS_AS(json(j.cend(), j.cend()), json::invalid_iterator&); - CHECK_THROWS_AS(json(j.cbegin(), j.cbegin()), json::invalid_iterator&); + CHECK_THROWS_AS(json(j.cend(), j.cend()), json::invalid_iterator); + CHECK_THROWS_AS(json(j.cbegin(), j.cbegin()), json::invalid_iterator); CHECK_THROWS_WITH(json(j.cend(), j.cend()), "[json.exception.invalid_iterator.204] iterators out of range"); CHECK_THROWS_WITH(json(j.cbegin(), j.cbegin()), "[json.exception.invalid_iterator.204] iterators out of range"); } @@ -1459,15 +1460,15 @@ TEST_CASE("constructors") { { json j = false; - CHECK_THROWS_AS(json(j.end(), j.end()), json::invalid_iterator&); - CHECK_THROWS_AS(json(j.begin(), j.begin()), json::invalid_iterator&); + CHECK_THROWS_AS(json(j.end(), j.end()), json::invalid_iterator); + CHECK_THROWS_AS(json(j.begin(), j.begin()), json::invalid_iterator); CHECK_THROWS_WITH(json(j.end(), j.end()), "[json.exception.invalid_iterator.204] iterators out of range"); CHECK_THROWS_WITH(json(j.begin(), j.begin()), "[json.exception.invalid_iterator.204] iterators out of range"); } { json j = true; - CHECK_THROWS_AS(json(j.cend(), j.cend()), json::invalid_iterator&); - CHECK_THROWS_AS(json(j.cbegin(), j.cbegin()), json::invalid_iterator&); + CHECK_THROWS_AS(json(j.cend(), j.cend()), json::invalid_iterator); + CHECK_THROWS_AS(json(j.cbegin(), j.cbegin()), json::invalid_iterator); CHECK_THROWS_WITH(json(j.cend(), j.cend()), "[json.exception.invalid_iterator.204] iterators out of range"); CHECK_THROWS_WITH(json(j.cbegin(), j.cbegin()), "[json.exception.invalid_iterator.204] iterators out of range"); } @@ -1477,15 +1478,15 @@ TEST_CASE("constructors") { { json j = 17; - CHECK_THROWS_AS(json(j.end(), j.end()), json::invalid_iterator&); - CHECK_THROWS_AS(json(j.begin(), j.begin()), json::invalid_iterator&); + CHECK_THROWS_AS(json(j.end(), j.end()), json::invalid_iterator); + CHECK_THROWS_AS(json(j.begin(), j.begin()), json::invalid_iterator); CHECK_THROWS_WITH(json(j.end(), j.end()), "[json.exception.invalid_iterator.204] iterators out of range"); CHECK_THROWS_WITH(json(j.begin(), j.begin()), "[json.exception.invalid_iterator.204] iterators out of range"); } { json j = 17; - CHECK_THROWS_AS(json(j.cend(), j.cend()), json::invalid_iterator&); - CHECK_THROWS_AS(json(j.cbegin(), j.cbegin()), json::invalid_iterator&); + CHECK_THROWS_AS(json(j.cend(), j.cend()), json::invalid_iterator); + CHECK_THROWS_AS(json(j.cbegin(), j.cbegin()), json::invalid_iterator); CHECK_THROWS_WITH(json(j.cend(), j.cend()), "[json.exception.invalid_iterator.204] iterators out of range"); CHECK_THROWS_WITH(json(j.cbegin(), j.cbegin()), "[json.exception.invalid_iterator.204] iterators out of range"); } @@ -1495,15 +1496,15 @@ TEST_CASE("constructors") { { json j = 17u; - CHECK_THROWS_AS(json(j.end(), j.end()), json::invalid_iterator&); - CHECK_THROWS_AS(json(j.begin(), j.begin()), json::invalid_iterator&); + CHECK_THROWS_AS(json(j.end(), j.end()), json::invalid_iterator); + CHECK_THROWS_AS(json(j.begin(), j.begin()), json::invalid_iterator); CHECK_THROWS_WITH(json(j.end(), j.end()), "[json.exception.invalid_iterator.204] iterators out of range"); CHECK_THROWS_WITH(json(j.begin(), j.begin()), "[json.exception.invalid_iterator.204] iterators out of range"); } { json j = 17u; - CHECK_THROWS_AS(json(j.cend(), j.cend()), json::invalid_iterator&); - CHECK_THROWS_AS(json(j.cbegin(), j.cbegin()), json::invalid_iterator&); + CHECK_THROWS_AS(json(j.cend(), j.cend()), json::invalid_iterator); + CHECK_THROWS_AS(json(j.cbegin(), j.cbegin()), json::invalid_iterator); CHECK_THROWS_WITH(json(j.cend(), j.cend()), "[json.exception.invalid_iterator.204] iterators out of range"); CHECK_THROWS_WITH(json(j.cbegin(), j.cbegin()), "[json.exception.invalid_iterator.204] iterators out of range"); } @@ -1513,15 +1514,15 @@ TEST_CASE("constructors") { { json j = 23.42; - CHECK_THROWS_AS(json(j.end(), j.end()), json::invalid_iterator&); - CHECK_THROWS_AS(json(j.begin(), j.begin()), json::invalid_iterator&); + CHECK_THROWS_AS(json(j.end(), j.end()), json::invalid_iterator); + CHECK_THROWS_AS(json(j.begin(), j.begin()), json::invalid_iterator); CHECK_THROWS_WITH(json(j.end(), j.end()), "[json.exception.invalid_iterator.204] iterators out of range"); CHECK_THROWS_WITH(json(j.begin(), j.begin()), "[json.exception.invalid_iterator.204] iterators out of range"); } { json j = 23.42; - CHECK_THROWS_AS(json(j.cend(), j.cend()), json::invalid_iterator&); - CHECK_THROWS_AS(json(j.cbegin(), j.cbegin()), json::invalid_iterator&); + CHECK_THROWS_AS(json(j.cend(), j.cend()), json::invalid_iterator); + CHECK_THROWS_AS(json(j.cbegin(), j.cbegin()), json::invalid_iterator); CHECK_THROWS_WITH(json(j.cend(), j.cend()), "[json.exception.invalid_iterator.204] iterators out of range"); CHECK_THROWS_WITH(json(j.cbegin(), j.cbegin()), "[json.exception.invalid_iterator.204] iterators out of range"); } diff --git a/test/src/unit-conversions.cpp b/test/src/unit-conversions.cpp index eafac320..fdbc7289 100644 --- a/test/src/unit-conversions.cpp +++ b/test/src/unit-conversions.cpp @@ -35,6 +35,7 @@ using nlohmann::json; #include #include #include +#include #include #include #include @@ -79,13 +80,13 @@ TEST_CASE("value conversion") SECTION("exception in case of a non-object type") { - CHECK_THROWS_AS(json(json::value_t::null).get(), json::type_error&); - CHECK_THROWS_AS(json(json::value_t::array).get(), json::type_error&); - CHECK_THROWS_AS(json(json::value_t::string).get(), json::type_error&); - CHECK_THROWS_AS(json(json::value_t::boolean).get(), json::type_error&); - CHECK_THROWS_AS(json(json::value_t::number_integer).get(), json::type_error&); - CHECK_THROWS_AS(json(json::value_t::number_unsigned).get(), json::type_error&); - CHECK_THROWS_AS(json(json::value_t::number_float).get(), json::type_error&); + CHECK_THROWS_AS(json(json::value_t::null).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::array).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::string).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::boolean).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::number_integer).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::number_unsigned).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::number_float).get(), json::type_error); CHECK_THROWS_WITH(json(json::value_t::null).get(), "[json.exception.type_error.302] type must be object, but is null"); @@ -162,7 +163,7 @@ TEST_CASE("value conversion") std::forward_list a = j.get>(); CHECK(json(a) == j); - CHECK_THROWS_AS(json(json::value_t::null).get>(), json::type_error&); + CHECK_THROWS_AS(json(json::value_t::null).get>(), json::type_error); CHECK_THROWS_WITH(json(json::value_t::null).get>(), "[json.exception.type_error.302] type must be array, but is null"); } @@ -172,7 +173,7 @@ TEST_CASE("value conversion") std::vector a = j.get>(); CHECK(json(a) == j); - CHECK_THROWS_AS(json(json::value_t::null).get>(), json::type_error&); + CHECK_THROWS_AS(json(json::value_t::null).get>(), json::type_error); CHECK_THROWS_WITH(json(json::value_t::null).get>(), "[json.exception.type_error.302] type must be array, but is null"); @@ -181,7 +182,7 @@ TEST_CASE("value conversion") { // making the call to from_json throw in order to check capacity std::vector v; - CHECK_THROWS_AS(nlohmann::from_json(j, v), json::type_error&); + CHECK_THROWS_AS(nlohmann::from_json(j, v), json::type_error); CHECK(v.capacity() == j.size()); // make sure all values are properly copied @@ -213,13 +214,13 @@ TEST_CASE("value conversion") SECTION("exception in case of a non-array type") { - CHECK_THROWS_AS(json(json::value_t::null).get(), json::type_error&); - CHECK_THROWS_AS(json(json::value_t::object).get(), json::type_error&); - CHECK_THROWS_AS(json(json::value_t::string).get(), json::type_error&); - CHECK_THROWS_AS(json(json::value_t::boolean).get(), json::type_error&); - CHECK_THROWS_AS(json(json::value_t::number_integer).get(), json::type_error&); - CHECK_THROWS_AS(json(json::value_t::number_unsigned).get(), json::type_error&); - CHECK_THROWS_AS(json(json::value_t::number_float).get(), json::type_error&); + CHECK_THROWS_AS(json(json::value_t::null).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::object).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::string).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::boolean).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::number_integer).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::number_unsigned).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::number_float).get(), json::type_error); CHECK_THROWS_WITH(json(json::value_t::object).get>(), "[json.exception.type_error.302] type must be array, but is object"); @@ -295,13 +296,13 @@ TEST_CASE("value conversion") SECTION("exception in case of a non-string type") { - CHECK_THROWS_AS(json(json::value_t::null).get(), json::type_error&); - CHECK_THROWS_AS(json(json::value_t::object).get(), json::type_error&); - CHECK_THROWS_AS(json(json::value_t::array).get(), json::type_error&); - CHECK_THROWS_AS(json(json::value_t::boolean).get(), json::type_error&); - CHECK_THROWS_AS(json(json::value_t::number_integer).get(), json::type_error&); - CHECK_THROWS_AS(json(json::value_t::number_unsigned).get(), json::type_error&); - CHECK_THROWS_AS(json(json::value_t::number_float).get(), json::type_error&); + CHECK_THROWS_AS(json(json::value_t::null).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::object).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::array).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::boolean).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::number_integer).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::number_unsigned).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::number_float).get(), json::type_error); CHECK_THROWS_WITH(json(json::value_t::null).get(), "[json.exception.type_error.302] type must be string, but is null"); @@ -357,13 +358,13 @@ TEST_CASE("value conversion") SECTION("exception in case of a non-string type") { - CHECK_THROWS_AS(json(json::value_t::null).get(), json::type_error&); - CHECK_THROWS_AS(json(json::value_t::object).get(), json::type_error&); - CHECK_THROWS_AS(json(json::value_t::array).get(), json::type_error&); - CHECK_THROWS_AS(json(json::value_t::string).get(), json::type_error&); - CHECK_THROWS_AS(json(json::value_t::number_integer).get(), json::type_error&); - CHECK_THROWS_AS(json(json::value_t::number_unsigned).get(), json::type_error&); - CHECK_THROWS_AS(json(json::value_t::number_float).get(), json::type_error&); + CHECK_THROWS_AS(json(json::value_t::null).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::object).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::array).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::string).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::number_integer).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::number_unsigned).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::number_float).get(), json::type_error); CHECK_THROWS_WITH(json(json::value_t::null).get(), "[json.exception.type_error.302] type must be boolean, but is null"); @@ -613,11 +614,11 @@ TEST_CASE("value conversion") SECTION("exception in case of a non-number type") { - CHECK_THROWS_AS(json(json::value_t::null).get(), json::type_error&); - CHECK_THROWS_AS(json(json::value_t::object).get(), json::type_error&); - CHECK_THROWS_AS(json(json::value_t::array).get(), json::type_error&); - CHECK_THROWS_AS(json(json::value_t::string).get(), json::type_error&); - CHECK_THROWS_AS(json(json::value_t::boolean).get(), json::type_error&); + CHECK_THROWS_AS(json(json::value_t::null).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::object).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::array).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::string).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::boolean).get(), json::type_error); CHECK_THROWS_WITH(json(json::value_t::null).get(), "[json.exception.type_error.302] type must be number, but is null"); @@ -872,11 +873,11 @@ TEST_CASE("value conversion") SECTION("exception in case of a non-string type") { - CHECK_THROWS_AS(json(json::value_t::null).get(), json::type_error&); - CHECK_THROWS_AS(json(json::value_t::object).get(), json::type_error&); - CHECK_THROWS_AS(json(json::value_t::array).get(), json::type_error&); - CHECK_THROWS_AS(json(json::value_t::string).get(), json::type_error&); - CHECK_THROWS_AS(json(json::value_t::boolean).get(), json::type_error&); + CHECK_THROWS_AS(json(json::value_t::null).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::object).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::array).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::string).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::boolean).get(), json::type_error); CHECK_THROWS_WITH(json(json::value_t::null).get(), "[json.exception.type_error.302] type must be number, but is null"); @@ -978,7 +979,7 @@ TEST_CASE("value conversion") SECTION("exception in case of a non-object type") { - CHECK_THROWS_AS((json().get>()), json::type_error&); + CHECK_THROWS_AS((json().get>()), json::type_error); CHECK_THROWS_WITH((json().get>()), "[json.exception.type_error.302] type must be object, but is null"); } } @@ -1080,11 +1081,11 @@ TEST_CASE("value conversion") SECTION("exception in case of a non-object type") { - CHECK_THROWS_AS((json().get>()), json::type_error&); - CHECK_THROWS_AS((json().get>()), json::type_error&); - CHECK_THROWS_AS((json().get>()), json::type_error&); - CHECK_THROWS_AS((json().get>()), json::type_error&); - CHECK_THROWS_AS((json().get>()), json::type_error&); + CHECK_THROWS_AS((json().get>()), json::type_error); + CHECK_THROWS_AS((json().get>()), json::type_error); + CHECK_THROWS_AS((json().get>()), json::type_error); + CHECK_THROWS_AS((json().get>()), json::type_error); + CHECK_THROWS_AS((json().get>()), json::type_error); // does type really must be an array? or it rather must not be null? // that's what I thought when other test like this one broke diff --git a/test/src/unit-deserialization.cpp b/test/src/unit-deserialization.cpp index 2798f102..eb347b59 100644 --- a/test/src/unit-deserialization.cpp +++ b/test/src/unit-deserialization.cpp @@ -97,7 +97,7 @@ TEST_CASE("deserialization") ss2 << "[\"foo\",1,2,3,false,{\"one\":1}"; ss3 << "[\"foo\",1,2,3,false,{\"one\":1}"; ss4 << "[\"foo\",1,2,3,false,{\"one\":1}"; - CHECK_THROWS_AS(json::parse(ss1), json::parse_error&); + CHECK_THROWS_AS(json::parse(ss1), json::parse_error); CHECK_THROWS_WITH(json::parse(ss2), "[json.exception.parse_error.101] parse error at 29: syntax error - unexpected end of input; expected ']'"); CHECK(not json::accept(ss3)); @@ -110,7 +110,7 @@ TEST_CASE("deserialization") SECTION("string") { json::string_t s = "[\"foo\",1,2,3,false,{\"one\":1}"; - CHECK_THROWS_AS(json::parse(s), json::parse_error&); + CHECK_THROWS_AS(json::parse(s), json::parse_error); CHECK_THROWS_WITH(json::parse(s), "[json.exception.parse_error.101] parse error at 29: syntax error - unexpected end of input; expected ']'"); CHECK(not json::accept(s)); @@ -126,7 +126,7 @@ TEST_CASE("deserialization") ss1 << "[\"foo\",1,2,3,false,{\"one\":1}"; ss2 << "[\"foo\",1,2,3,false,{\"one\":1}"; json j; - CHECK_THROWS_AS(j << ss1, json::parse_error&); + CHECK_THROWS_AS(j << ss1, json::parse_error); CHECK_THROWS_WITH(j << ss2, "[json.exception.parse_error.101] parse error at 29: syntax error - unexpected end of input; expected ']'"); } @@ -137,14 +137,14 @@ TEST_CASE("deserialization") ss1 << "[\"foo\",1,2,3,false,{\"one\":1}"; ss2 << "[\"foo\",1,2,3,false,{\"one\":1}"; json j; - CHECK_THROWS_AS(ss1 >> j, json::parse_error&); + CHECK_THROWS_AS(ss1 >> j, json::parse_error); CHECK_THROWS_WITH(ss2 >> j, "[json.exception.parse_error.101] parse error at 29: syntax error - unexpected end of input; expected ']'"); } SECTION("user-defined string literal") { - CHECK_THROWS_AS("[\"foo\",1,2,3,false,{\"one\":1}"_json, json::parse_error&); + CHECK_THROWS_AS("[\"foo\",1,2,3,false,{\"one\":1}"_json, json::parse_error); CHECK_THROWS_WITH("[\"foo\",1,2,3,false,{\"one\":1}"_json, "[json.exception.parse_error.101] parse error at 29: syntax error - unexpected end of input; expected ']'"); } @@ -205,7 +205,7 @@ TEST_CASE("deserialization") SECTION("empty container") { std::vector v; - CHECK_THROWS_AS(json::parse(v), json::parse_error&); + CHECK_THROWS_AS(json::parse(v), json::parse_error); CHECK(not json::accept(v)); } } @@ -257,7 +257,7 @@ TEST_CASE("deserialization") SECTION("with empty range") { std::vector v; - CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&); + CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error); CHECK(not json::accept(std::begin(v), std::end(v))); } } @@ -268,7 +268,7 @@ TEST_CASE("deserialization") SECTION("case 1") { uint8_t v[] = {'\"', 'a', 'a', 'a', 'a', 'a', 'a', '\\', 'u'}; - CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&); + CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error); CHECK(not json::accept(std::begin(v), std::end(v))); json j_error; @@ -279,7 +279,7 @@ TEST_CASE("deserialization") SECTION("case 2") { uint8_t v[] = {'\"', 'a', 'a', 'a', 'a', 'a', 'a', '\\', 'u', '1'}; - CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&); + CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error); CHECK(not json::accept(std::begin(v), std::end(v))); json j_error; @@ -290,7 +290,7 @@ TEST_CASE("deserialization") SECTION("case 3") { uint8_t v[] = {'\"', 'a', 'a', 'a', 'a', 'a', 'a', '\\', 'u', '1', '1', '1', '1', '1', '1', '1', '1'}; - CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&); + CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error); CHECK(not json::accept(std::begin(v), std::end(v))); json j_error; @@ -301,7 +301,7 @@ TEST_CASE("deserialization") SECTION("case 4") { uint8_t v[] = {'\"', 'a', 'a', 'a', 'a', 'a', 'a', 'u', '1', '1', '1', '1', '1', '1', '1', '1', '\\'}; - CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&); + CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error); CHECK(not json::accept(std::begin(v), std::end(v))); json j_error; @@ -312,7 +312,7 @@ TEST_CASE("deserialization") SECTION("case 5") { uint8_t v[] = {'\"', 0x7F, 0xC1}; - CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&); + CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error); CHECK(not json::accept(std::begin(v), std::end(v))); json j_error; @@ -323,7 +323,7 @@ TEST_CASE("deserialization") SECTION("case 6") { uint8_t v[] = {'\"', 0x7F, 0xDF, 0x7F}; - CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&); + CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error); CHECK_THROWS_WITH(json::parse(std::begin(v), std::end(v)), "[json.exception.parse_error.101] parse error at 4: syntax error - invalid string: ill-formed UTF-8 byte; last read: '\"\x7f\xdf\x7f'"); CHECK(not json::accept(std::begin(v), std::end(v))); @@ -336,7 +336,7 @@ TEST_CASE("deserialization") SECTION("case 7") { uint8_t v[] = {'\"', 0x7F, 0xDF, 0xC0}; - CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&); + CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error); CHECK(not json::accept(std::begin(v), std::end(v))); json j_error; @@ -347,7 +347,7 @@ TEST_CASE("deserialization") SECTION("case 8") { uint8_t v[] = {'\"', 0x7F, 0xE0, 0x9F}; - CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&); + CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error); CHECK(not json::accept(std::begin(v), std::end(v))); json j_error; @@ -358,7 +358,7 @@ TEST_CASE("deserialization") SECTION("case 9") { uint8_t v[] = {'\"', 0x7F, 0xEF, 0xC0}; - CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&); + CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error); CHECK(not json::accept(std::begin(v), std::end(v))); json j_error; @@ -369,7 +369,7 @@ TEST_CASE("deserialization") SECTION("case 10") { uint8_t v[] = {'\"', 0x7F, 0xED, 0x7F}; - CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&); + CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error); CHECK(not json::accept(std::begin(v), std::end(v))); json j_error; @@ -380,7 +380,7 @@ TEST_CASE("deserialization") SECTION("case 11") { uint8_t v[] = {'\"', 0x7F, 0xF0, 0x8F}; - CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&); + CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error); CHECK(not json::accept(std::begin(v), std::end(v))); json j_error; @@ -391,7 +391,7 @@ TEST_CASE("deserialization") SECTION("case 12") { uint8_t v[] = {'\"', 0x7F, 0xF0, 0xC0}; - CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&); + CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error); CHECK(not json::accept(std::begin(v), std::end(v))); json j_error; @@ -402,7 +402,7 @@ TEST_CASE("deserialization") SECTION("case 13") { uint8_t v[] = {'\"', 0x7F, 0xF3, 0x7F}; - CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&); + CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error); CHECK(not json::accept(std::begin(v), std::end(v))); json j_error; @@ -413,7 +413,7 @@ TEST_CASE("deserialization") SECTION("case 14") { uint8_t v[] = {'\"', 0x7F, 0xF3, 0xC0}; - CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&); + CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error); CHECK(not json::accept(std::begin(v), std::end(v))); json j_error; @@ -424,7 +424,7 @@ TEST_CASE("deserialization") SECTION("case 15") { uint8_t v[] = {'\"', 0x7F, 0xF4, 0x7F}; - CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&); + CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error); CHECK(not json::accept(std::begin(v), std::end(v))); json j_error; @@ -435,7 +435,7 @@ TEST_CASE("deserialization") SECTION("case 16") { uint8_t v[] = {'{', '\"', '\"', ':', '1', '1'}; - CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&); + CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error); CHECK(not json::accept(std::begin(v), std::end(v))); json j_error; @@ -451,11 +451,11 @@ TEST_CASE("deserialization") SECTION("BOM only") { - CHECK_THROWS_AS(json::parse(bom), json::parse_error&); + CHECK_THROWS_AS(json::parse(bom), json::parse_error); CHECK_THROWS_WITH(json::parse(bom), "[json.exception.parse_error.101] parse error at 1: syntax error - unexpected end of input; expected '[', '{', or a literal"); - CHECK_THROWS_AS(json::parse(std::istringstream(bom)), json::parse_error&); + CHECK_THROWS_AS(json::parse(std::istringstream(bom)), json::parse_error); CHECK_THROWS_WITH(json::parse(std::istringstream(bom)), "[json.exception.parse_error.101] parse error at 1: syntax error - unexpected end of input; expected '[', '{', or a literal"); } @@ -468,22 +468,22 @@ TEST_CASE("deserialization") SECTION("2 byte of BOM") { - CHECK_THROWS_AS(json::parse(bom.substr(0, 2)), json::parse_error&); + CHECK_THROWS_AS(json::parse(bom.substr(0, 2)), json::parse_error); CHECK_THROWS_WITH(json::parse(bom), "[json.exception.parse_error.101] parse error at 1: syntax error - unexpected end of input; expected '[', '{', or a literal"); - CHECK_THROWS_AS(json::parse(std::istringstream(bom.substr(0, 2))), json::parse_error&); + CHECK_THROWS_AS(json::parse(std::istringstream(bom.substr(0, 2))), json::parse_error); CHECK_THROWS_WITH(json::parse(std::istringstream(bom)), "[json.exception.parse_error.101] parse error at 1: syntax error - unexpected end of input; expected '[', '{', or a literal"); } SECTION("1 byte of BOM") { - CHECK_THROWS_AS(json::parse(bom.substr(0, 1)), json::parse_error&); + CHECK_THROWS_AS(json::parse(bom.substr(0, 1)), json::parse_error); CHECK_THROWS_WITH(json::parse(bom), "[json.exception.parse_error.101] parse error at 1: syntax error - unexpected end of input; expected '[', '{', or a literal"); - CHECK_THROWS_AS(json::parse(std::istringstream(bom.substr(0, 1))), json::parse_error&); + CHECK_THROWS_AS(json::parse(std::istringstream(bom.substr(0, 1))), json::parse_error); CHECK_THROWS_WITH(json::parse(std::istringstream(bom)), "[json.exception.parse_error.101] parse error at 1: syntax error - unexpected end of input; expected '[', '{', or a literal"); } @@ -517,8 +517,8 @@ TEST_CASE("deserialization") else { // any variation is an error - CHECK_THROWS_AS(json::parse(s + "null"), json::parse_error&); - CHECK_THROWS_AS(json::parse(std::istringstream(s + "null")), json::parse_error&); + CHECK_THROWS_AS(json::parse(s + "null"), json::parse_error); + CHECK_THROWS_AS(json::parse(std::istringstream(s + "null")), json::parse_error); } } } diff --git a/test/src/unit-element_access1.cpp b/test/src/unit-element_access1.cpp index 630b1a5e..eb4a92cb 100644 --- a/test/src/unit-element_access1.cpp +++ b/test/src/unit-element_access1.cpp @@ -63,8 +63,8 @@ TEST_CASE("element access 1") SECTION("access outside bounds") { - CHECK_THROWS_AS(j.at(8), json::out_of_range&); - CHECK_THROWS_AS(j_const.at(8), json::out_of_range&); + CHECK_THROWS_AS(j.at(8), json::out_of_range); + CHECK_THROWS_AS(j_const.at(8), json::out_of_range); CHECK_THROWS_WITH(j.at(8), "[json.exception.out_of_range.401] array index 8 is out of range"); @@ -78,8 +78,8 @@ TEST_CASE("element access 1") { json j_nonarray(json::value_t::null); const json j_nonarray_const(j_nonarray); - CHECK_THROWS_AS(j_nonarray.at(0), json::type_error&); - CHECK_THROWS_AS(j_nonarray_const.at(0), json::type_error&); + CHECK_THROWS_AS(j_nonarray.at(0), json::type_error); + CHECK_THROWS_AS(j_nonarray_const.at(0), json::type_error); CHECK_THROWS_WITH(j_nonarray.at(0), "[json.exception.type_error.304] cannot use at() with null"); CHECK_THROWS_WITH(j_nonarray_const.at(0), "[json.exception.type_error.304] cannot use at() with null"); @@ -89,8 +89,8 @@ TEST_CASE("element access 1") { json j_nonarray(json::value_t::boolean); const json j_nonarray_const(j_nonarray); - CHECK_THROWS_AS(j_nonarray.at(0), json::type_error&); - CHECK_THROWS_AS(j_nonarray_const.at(0), json::type_error&); + CHECK_THROWS_AS(j_nonarray.at(0), json::type_error); + CHECK_THROWS_AS(j_nonarray_const.at(0), json::type_error); CHECK_THROWS_WITH(j_nonarray.at(0), "[json.exception.type_error.304] cannot use at() with boolean"); CHECK_THROWS_WITH(j_nonarray_const.at(0), "[json.exception.type_error.304] cannot use at() with boolean"); @@ -100,8 +100,8 @@ TEST_CASE("element access 1") { json j_nonarray(json::value_t::string); const json j_nonarray_const(j_nonarray); - CHECK_THROWS_AS(j_nonarray.at(0), json::type_error&); - CHECK_THROWS_AS(j_nonarray_const.at(0), json::type_error&); + CHECK_THROWS_AS(j_nonarray.at(0), json::type_error); + CHECK_THROWS_AS(j_nonarray_const.at(0), json::type_error); CHECK_THROWS_WITH(j_nonarray.at(0), "[json.exception.type_error.304] cannot use at() with string"); CHECK_THROWS_WITH(j_nonarray_const.at(0), "[json.exception.type_error.304] cannot use at() with string"); @@ -111,8 +111,8 @@ TEST_CASE("element access 1") { json j_nonarray(json::value_t::object); const json j_nonarray_const(j_nonarray); - CHECK_THROWS_AS(j_nonarray.at(0), json::type_error&); - CHECK_THROWS_AS(j_nonarray_const.at(0), json::type_error&); + CHECK_THROWS_AS(j_nonarray.at(0), json::type_error); + CHECK_THROWS_AS(j_nonarray_const.at(0), json::type_error); CHECK_THROWS_WITH(j_nonarray.at(0), "[json.exception.type_error.304] cannot use at() with object"); CHECK_THROWS_WITH(j_nonarray_const.at(0), "[json.exception.type_error.304] cannot use at() with object"); @@ -122,8 +122,8 @@ TEST_CASE("element access 1") { json j_nonarray(json::value_t::number_integer); const json j_nonarray_const(j_nonarray); - CHECK_THROWS_AS(j_nonarray.at(0), json::type_error&); - CHECK_THROWS_AS(j_nonarray_const.at(0), json::type_error&); + CHECK_THROWS_AS(j_nonarray.at(0), json::type_error); + CHECK_THROWS_AS(j_nonarray_const.at(0), json::type_error); CHECK_THROWS_WITH(j_nonarray.at(0), "[json.exception.type_error.304] cannot use at() with number"); CHECK_THROWS_WITH(j_nonarray_const.at(0), "[json.exception.type_error.304] cannot use at() with number"); @@ -133,8 +133,8 @@ TEST_CASE("element access 1") { json j_nonarray(json::value_t::number_unsigned); const json j_nonarray_const(j_nonarray); - CHECK_THROWS_AS(j_nonarray.at(0), json::type_error&); - CHECK_THROWS_AS(j_nonarray_const.at(0), json::type_error&); + CHECK_THROWS_AS(j_nonarray.at(0), json::type_error); + CHECK_THROWS_AS(j_nonarray_const.at(0), json::type_error); CHECK_THROWS_WITH(j_nonarray.at(0), "[json.exception.type_error.304] cannot use at() with number"); CHECK_THROWS_WITH(j_nonarray_const.at(0), "[json.exception.type_error.304] cannot use at() with number"); @@ -144,8 +144,8 @@ TEST_CASE("element access 1") { json j_nonarray(json::value_t::number_float); const json j_nonarray_const(j_nonarray); - CHECK_THROWS_AS(j_nonarray.at(0), json::type_error&); - CHECK_THROWS_AS(j_nonarray_const.at(0), json::type_error&); + CHECK_THROWS_AS(j_nonarray.at(0), json::type_error); + CHECK_THROWS_AS(j_nonarray_const.at(0), json::type_error); CHECK_THROWS_WITH(j_nonarray.at(0), "[json.exception.type_error.304] cannot use at() with number"); CHECK_THROWS_WITH(j_nonarray_const.at(0), "[json.exception.type_error.304] cannot use at() with number"); @@ -193,7 +193,7 @@ TEST_CASE("element access 1") json j_nonarray(json::value_t::null); const json j_nonarray_const(j_nonarray); CHECK_NOTHROW(j_nonarray[0]); - CHECK_THROWS_AS(j_nonarray_const[0], json::type_error&); + CHECK_THROWS_AS(j_nonarray_const[0], json::type_error); CHECK_THROWS_WITH(j_nonarray_const[0], "[json.exception.type_error.305] cannot use operator[] with null"); } @@ -209,8 +209,8 @@ TEST_CASE("element access 1") { json j_nonarray(json::value_t::boolean); const json j_nonarray_const(j_nonarray); - CHECK_THROWS_AS(j_nonarray[0], json::type_error&); - CHECK_THROWS_AS(j_nonarray_const[0], json::type_error&); + CHECK_THROWS_AS(j_nonarray[0], json::type_error); + CHECK_THROWS_AS(j_nonarray_const[0], json::type_error); CHECK_THROWS_WITH(j_nonarray[0], "[json.exception.type_error.305] cannot use operator[] with boolean"); CHECK_THROWS_WITH(j_nonarray_const[0], "[json.exception.type_error.305] cannot use operator[] with boolean"); } @@ -219,8 +219,8 @@ TEST_CASE("element access 1") { json j_nonarray(json::value_t::string); const json j_nonarray_const(j_nonarray); - CHECK_THROWS_AS(j_nonarray[0], json::type_error&); - CHECK_THROWS_AS(j_nonarray_const[0], json::type_error&); + CHECK_THROWS_AS(j_nonarray[0], json::type_error); + CHECK_THROWS_AS(j_nonarray_const[0], json::type_error); CHECK_THROWS_WITH(j_nonarray[0], "[json.exception.type_error.305] cannot use operator[] with string"); CHECK_THROWS_WITH(j_nonarray_const[0], "[json.exception.type_error.305] cannot use operator[] with string"); } @@ -229,8 +229,8 @@ TEST_CASE("element access 1") { json j_nonarray(json::value_t::object); const json j_nonarray_const(j_nonarray); - CHECK_THROWS_AS(j_nonarray[0], json::type_error&); - CHECK_THROWS_AS(j_nonarray_const[0], json::type_error&); + CHECK_THROWS_AS(j_nonarray[0], json::type_error); + CHECK_THROWS_AS(j_nonarray_const[0], json::type_error); CHECK_THROWS_WITH(j_nonarray[0], "[json.exception.type_error.305] cannot use operator[] with object"); CHECK_THROWS_WITH(j_nonarray_const[0], "[json.exception.type_error.305] cannot use operator[] with object"); } @@ -239,8 +239,8 @@ TEST_CASE("element access 1") { json j_nonarray(json::value_t::number_integer); const json j_nonarray_const(j_nonarray); - CHECK_THROWS_AS(j_nonarray[0], json::type_error&); - CHECK_THROWS_AS(j_nonarray_const[0], json::type_error&); + CHECK_THROWS_AS(j_nonarray[0], json::type_error); + CHECK_THROWS_AS(j_nonarray_const[0], json::type_error); CHECK_THROWS_WITH(j_nonarray[0], "[json.exception.type_error.305] cannot use operator[] with number"); CHECK_THROWS_WITH(j_nonarray_const[0], "[json.exception.type_error.305] cannot use operator[] with number"); } @@ -249,8 +249,8 @@ TEST_CASE("element access 1") { json j_nonarray(json::value_t::number_unsigned); const json j_nonarray_const(j_nonarray); - CHECK_THROWS_AS(j_nonarray[0], json::type_error&); - CHECK_THROWS_AS(j_nonarray_const[0], json::type_error&); + CHECK_THROWS_AS(j_nonarray[0], json::type_error); + CHECK_THROWS_AS(j_nonarray_const[0], json::type_error); CHECK_THROWS_WITH(j_nonarray[0], "[json.exception.type_error.305] cannot use operator[] with number"); CHECK_THROWS_WITH(j_nonarray_const[0], "[json.exception.type_error.305] cannot use operator[] with number"); } @@ -259,8 +259,8 @@ TEST_CASE("element access 1") { json j_nonarray(json::value_t::number_float); const json j_nonarray_const(j_nonarray); - CHECK_THROWS_AS(j_nonarray[0], json::type_error&); - CHECK_THROWS_AS(j_nonarray_const[0], json::type_error&); + CHECK_THROWS_AS(j_nonarray[0], json::type_error); + CHECK_THROWS_AS(j_nonarray_const[0], json::type_error); CHECK_THROWS_WITH(j_nonarray[0], "[json.exception.type_error.305] cannot use operator[] with number"); CHECK_THROWS_WITH(j_nonarray_const[0], "[json.exception.type_error.305] cannot use operator[] with number"); } @@ -313,7 +313,7 @@ TEST_CASE("element access 1") } { json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; - CHECK_THROWS_AS(jarray.erase(8), json::out_of_range&); + CHECK_THROWS_AS(jarray.erase(8), json::out_of_range); CHECK_THROWS_WITH(jarray.erase(8), "[json.exception.out_of_range.401] array index 8 is out of range"); } @@ -408,10 +408,10 @@ TEST_CASE("element access 1") { json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; json jarray2 = {"foo", "bar"}; - CHECK_THROWS_AS(jarray.erase(jarray2.begin()), json::invalid_iterator&); - CHECK_THROWS_AS(jarray.erase(jarray.begin(), jarray2.end()), json::invalid_iterator&); - CHECK_THROWS_AS(jarray.erase(jarray2.begin(), jarray.end()), json::invalid_iterator&); - CHECK_THROWS_AS(jarray.erase(jarray2.begin(), jarray2.end()), json::invalid_iterator&); + CHECK_THROWS_AS(jarray.erase(jarray2.begin()), json::invalid_iterator); + CHECK_THROWS_AS(jarray.erase(jarray.begin(), jarray2.end()), json::invalid_iterator); + CHECK_THROWS_AS(jarray.erase(jarray2.begin(), jarray.end()), json::invalid_iterator); + CHECK_THROWS_AS(jarray.erase(jarray2.begin(), jarray2.end()), json::invalid_iterator); CHECK_THROWS_WITH(jarray.erase(jarray2.begin()), "[json.exception.invalid_iterator.202] iterator does not fit current value"); @@ -425,10 +425,10 @@ TEST_CASE("element access 1") { json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; json jarray2 = {"foo", "bar"}; - CHECK_THROWS_AS(jarray.erase(jarray2.cbegin()), json::invalid_iterator&); - CHECK_THROWS_AS(jarray.erase(jarray.cbegin(), jarray2.cend()), json::invalid_iterator&); - CHECK_THROWS_AS(jarray.erase(jarray2.cbegin(), jarray.cend()), json::invalid_iterator&); - CHECK_THROWS_AS(jarray.erase(jarray2.cbegin(), jarray2.cend()), json::invalid_iterator&); + CHECK_THROWS_AS(jarray.erase(jarray2.cbegin()), json::invalid_iterator); + CHECK_THROWS_AS(jarray.erase(jarray.cbegin(), jarray2.cend()), json::invalid_iterator); + CHECK_THROWS_AS(jarray.erase(jarray2.cbegin(), jarray.cend()), json::invalid_iterator); + CHECK_THROWS_AS(jarray.erase(jarray2.cbegin(), jarray2.cend()), json::invalid_iterator); CHECK_THROWS_WITH(jarray.erase(jarray2.cbegin()), "[json.exception.invalid_iterator.202] iterator does not fit current value"); @@ -447,7 +447,7 @@ TEST_CASE("element access 1") SECTION("null") { json j_nonobject(json::value_t::null); - CHECK_THROWS_AS(j_nonobject.erase(0), json::type_error&); + CHECK_THROWS_AS(j_nonobject.erase(0), json::type_error); CHECK_THROWS_WITH(j_nonobject.erase(0), "[json.exception.type_error.307] cannot use erase() with null"); } @@ -455,7 +455,7 @@ TEST_CASE("element access 1") SECTION("boolean") { json j_nonobject(json::value_t::boolean); - CHECK_THROWS_AS(j_nonobject.erase(0), json::type_error&); + CHECK_THROWS_AS(j_nonobject.erase(0), json::type_error); CHECK_THROWS_WITH(j_nonobject.erase(0), "[json.exception.type_error.307] cannot use erase() with boolean"); } @@ -463,7 +463,7 @@ TEST_CASE("element access 1") SECTION("string") { json j_nonobject(json::value_t::string); - CHECK_THROWS_AS(j_nonobject.erase(0), json::type_error&); + CHECK_THROWS_AS(j_nonobject.erase(0), json::type_error); CHECK_THROWS_WITH(j_nonobject.erase(0), "[json.exception.type_error.307] cannot use erase() with string"); } @@ -471,7 +471,7 @@ TEST_CASE("element access 1") SECTION("object") { json j_nonobject(json::value_t::object); - CHECK_THROWS_AS(j_nonobject.erase(0), json::type_error&); + CHECK_THROWS_AS(j_nonobject.erase(0), json::type_error); CHECK_THROWS_WITH(j_nonobject.erase(0), "[json.exception.type_error.307] cannot use erase() with object"); } @@ -479,7 +479,7 @@ TEST_CASE("element access 1") SECTION("number (integer)") { json j_nonobject(json::value_t::number_integer); - CHECK_THROWS_AS(j_nonobject.erase(0), json::type_error&); + CHECK_THROWS_AS(j_nonobject.erase(0), json::type_error); CHECK_THROWS_WITH(j_nonobject.erase(0), "[json.exception.type_error.307] cannot use erase() with number"); } @@ -487,7 +487,7 @@ TEST_CASE("element access 1") SECTION("number (unsigned)") { json j_nonobject(json::value_t::number_unsigned); - CHECK_THROWS_AS(j_nonobject.erase(0), json::type_error&); + CHECK_THROWS_AS(j_nonobject.erase(0), json::type_error); CHECK_THROWS_WITH(j_nonobject.erase(0), "[json.exception.type_error.307] cannot use erase() with number"); } @@ -495,7 +495,7 @@ TEST_CASE("element access 1") SECTION("number (floating-point)") { json j_nonobject(json::value_t::number_float); - CHECK_THROWS_AS(j_nonobject.erase(0), json::type_error&); + CHECK_THROWS_AS(j_nonobject.erase(0), json::type_error); CHECK_THROWS_WITH(j_nonobject.erase(0), "[json.exception.type_error.307] cannot use erase() with number"); } @@ -511,15 +511,15 @@ TEST_CASE("element access 1") { { json j; - CHECK_THROWS_AS(j.front(), json::invalid_iterator&); - CHECK_THROWS_AS(j.back(), json::invalid_iterator&); + CHECK_THROWS_AS(j.front(), json::invalid_iterator); + CHECK_THROWS_AS(j.back(), json::invalid_iterator); CHECK_THROWS_WITH(j.front(), "[json.exception.invalid_iterator.214] cannot get value"); CHECK_THROWS_WITH(j.back(), "[json.exception.invalid_iterator.214] cannot get value"); } { const json j{}; - CHECK_THROWS_AS(j.front(), json::invalid_iterator&); - CHECK_THROWS_AS(j.back(), json::invalid_iterator&); + CHECK_THROWS_AS(j.front(), json::invalid_iterator); + CHECK_THROWS_AS(j.back(), json::invalid_iterator); CHECK_THROWS_WITH(j.front(), "[json.exception.invalid_iterator.214] cannot get value"); CHECK_THROWS_WITH(j.back(), "[json.exception.invalid_iterator.214] cannot get value"); } @@ -602,13 +602,13 @@ TEST_CASE("element access 1") { { json j; - CHECK_THROWS_AS(j.erase(j.begin()), json::type_error&); + CHECK_THROWS_AS(j.erase(j.begin()), json::type_error); CHECK_THROWS_WITH(j.erase(j.begin()), "[json.exception.type_error.307] cannot use erase() with null"); } { json j; - CHECK_THROWS_AS(j.erase(j.cbegin()), json::type_error&); + CHECK_THROWS_AS(j.erase(j.cbegin()), json::type_error); CHECK_THROWS_WITH(j.erase(j.begin()), "[json.exception.type_error.307] cannot use erase() with null"); } @@ -701,13 +701,13 @@ TEST_CASE("element access 1") { { json j = "foo"; - CHECK_THROWS_AS(j.erase(j.end()), json::invalid_iterator&); + CHECK_THROWS_AS(j.erase(j.end()), json::invalid_iterator); CHECK_THROWS_WITH(j.erase(j.end()), "[json.exception.invalid_iterator.205] iterator out of range"); } { json j = "bar"; - CHECK_THROWS_AS(j.erase(j.cend()), json::invalid_iterator&); + CHECK_THROWS_AS(j.erase(j.cend()), json::invalid_iterator); CHECK_THROWS_WITH(j.erase(j.cend()), "[json.exception.invalid_iterator.205] iterator out of range"); } @@ -717,13 +717,13 @@ TEST_CASE("element access 1") { { json j = false; - CHECK_THROWS_AS(j.erase(j.end()), json::invalid_iterator&); + CHECK_THROWS_AS(j.erase(j.end()), json::invalid_iterator); CHECK_THROWS_WITH(j.erase(j.end()), "[json.exception.invalid_iterator.205] iterator out of range"); } { json j = true; - CHECK_THROWS_AS(j.erase(j.cend()), json::invalid_iterator&); + CHECK_THROWS_AS(j.erase(j.cend()), json::invalid_iterator); CHECK_THROWS_WITH(j.erase(j.cend()), "[json.exception.invalid_iterator.205] iterator out of range"); } @@ -733,13 +733,13 @@ TEST_CASE("element access 1") { { json j = 17; - CHECK_THROWS_AS(j.erase(j.end()), json::invalid_iterator&); + CHECK_THROWS_AS(j.erase(j.end()), json::invalid_iterator); CHECK_THROWS_WITH(j.erase(j.end()), "[json.exception.invalid_iterator.205] iterator out of range"); } { json j = 17; - CHECK_THROWS_AS(j.erase(j.cend()), json::invalid_iterator&); + CHECK_THROWS_AS(j.erase(j.cend()), json::invalid_iterator); CHECK_THROWS_WITH(j.erase(j.cend()), "[json.exception.invalid_iterator.205] iterator out of range"); } @@ -749,13 +749,13 @@ TEST_CASE("element access 1") { { json j = 17u; - CHECK_THROWS_AS(j.erase(j.end()), json::invalid_iterator&); + CHECK_THROWS_AS(j.erase(j.end()), json::invalid_iterator); CHECK_THROWS_WITH(j.erase(j.end()), "[json.exception.invalid_iterator.205] iterator out of range"); } { json j = 17u; - CHECK_THROWS_AS(j.erase(j.cend()), json::invalid_iterator&); + CHECK_THROWS_AS(j.erase(j.cend()), json::invalid_iterator); CHECK_THROWS_WITH(j.erase(j.cend()), "[json.exception.invalid_iterator.205] iterator out of range"); } @@ -765,13 +765,13 @@ TEST_CASE("element access 1") { { json j = 23.42; - CHECK_THROWS_AS(j.erase(j.end()), json::invalid_iterator&); + CHECK_THROWS_AS(j.erase(j.end()), json::invalid_iterator); CHECK_THROWS_WITH(j.erase(j.end()), "[json.exception.invalid_iterator.205] iterator out of range"); } { json j = 23.42; - CHECK_THROWS_AS(j.erase(j.cend()), json::invalid_iterator&); + CHECK_THROWS_AS(j.erase(j.cend()), json::invalid_iterator); CHECK_THROWS_WITH(j.erase(j.cend()), "[json.exception.invalid_iterator.205] iterator out of range"); } @@ -784,13 +784,13 @@ TEST_CASE("element access 1") { { json j; - CHECK_THROWS_AS(j.erase(j.begin(), j.end()), json::type_error&); + CHECK_THROWS_AS(j.erase(j.begin(), j.end()), json::type_error); CHECK_THROWS_WITH(j.erase(j.begin(), j.end()), "[json.exception.type_error.307] cannot use erase() with null"); } { json j; - CHECK_THROWS_AS(j.erase(j.cbegin(), j.cend()), json::type_error&); + CHECK_THROWS_AS(j.erase(j.cbegin(), j.cend()), json::type_error); CHECK_THROWS_WITH(j.erase(j.cbegin(), j.cend()), "[json.exception.type_error.307] cannot use erase() with null"); } @@ -883,15 +883,15 @@ TEST_CASE("element access 1") { { json j = "foo"; - CHECK_THROWS_AS(j.erase(j.end(), j.end()), json::invalid_iterator&); - CHECK_THROWS_AS(j.erase(j.begin(), j.begin()), json::invalid_iterator&); + CHECK_THROWS_AS(j.erase(j.end(), j.end()), json::invalid_iterator); + CHECK_THROWS_AS(j.erase(j.begin(), j.begin()), json::invalid_iterator); CHECK_THROWS_WITH(j.erase(j.end(), j.end()), "[json.exception.invalid_iterator.204] iterators out of range"); CHECK_THROWS_WITH(j.erase(j.begin(), j.begin()), "[json.exception.invalid_iterator.204] iterators out of range"); } { json j = "bar"; - CHECK_THROWS_AS(j.erase(j.cend(), j.cend()), json::invalid_iterator&); - CHECK_THROWS_AS(j.erase(j.cbegin(), j.cbegin()), json::invalid_iterator&); + CHECK_THROWS_AS(j.erase(j.cend(), j.cend()), json::invalid_iterator); + CHECK_THROWS_AS(j.erase(j.cbegin(), j.cbegin()), json::invalid_iterator); CHECK_THROWS_WITH(j.erase(j.cend(), j.cend()), "[json.exception.invalid_iterator.204] iterators out of range"); CHECK_THROWS_WITH(j.erase(j.cbegin(), j.cbegin()), "[json.exception.invalid_iterator.204] iterators out of range"); } @@ -901,15 +901,15 @@ TEST_CASE("element access 1") { { json j = false; - CHECK_THROWS_AS(j.erase(j.end(), j.end()), json::invalid_iterator&); - CHECK_THROWS_AS(j.erase(j.begin(), j.begin()), json::invalid_iterator&); + CHECK_THROWS_AS(j.erase(j.end(), j.end()), json::invalid_iterator); + CHECK_THROWS_AS(j.erase(j.begin(), j.begin()), json::invalid_iterator); CHECK_THROWS_WITH(j.erase(j.end(), j.end()), "[json.exception.invalid_iterator.204] iterators out of range"); CHECK_THROWS_WITH(j.erase(j.begin(), j.begin()), "[json.exception.invalid_iterator.204] iterators out of range"); } { json j = true; - CHECK_THROWS_AS(j.erase(j.cend(), j.cend()), json::invalid_iterator&); - CHECK_THROWS_AS(j.erase(j.cbegin(), j.cbegin()), json::invalid_iterator&); + CHECK_THROWS_AS(j.erase(j.cend(), j.cend()), json::invalid_iterator); + CHECK_THROWS_AS(j.erase(j.cbegin(), j.cbegin()), json::invalid_iterator); CHECK_THROWS_WITH(j.erase(j.cend(), j.cend()), "[json.exception.invalid_iterator.204] iterators out of range"); CHECK_THROWS_WITH(j.erase(j.cbegin(), j.cbegin()), "[json.exception.invalid_iterator.204] iterators out of range"); } @@ -919,15 +919,15 @@ TEST_CASE("element access 1") { { json j = 17; - CHECK_THROWS_AS(j.erase(j.end(), j.end()), json::invalid_iterator&); - CHECK_THROWS_AS(j.erase(j.begin(), j.begin()), json::invalid_iterator&); + CHECK_THROWS_AS(j.erase(j.end(), j.end()), json::invalid_iterator); + CHECK_THROWS_AS(j.erase(j.begin(), j.begin()), json::invalid_iterator); CHECK_THROWS_WITH(j.erase(j.end(), j.end()), "[json.exception.invalid_iterator.204] iterators out of range"); CHECK_THROWS_WITH(j.erase(j.begin(), j.begin()), "[json.exception.invalid_iterator.204] iterators out of range"); } { json j = 17; - CHECK_THROWS_AS(j.erase(j.cend(), j.cend()), json::invalid_iterator&); - CHECK_THROWS_AS(j.erase(j.cbegin(), j.cbegin()), json::invalid_iterator&); + CHECK_THROWS_AS(j.erase(j.cend(), j.cend()), json::invalid_iterator); + CHECK_THROWS_AS(j.erase(j.cbegin(), j.cbegin()), json::invalid_iterator); CHECK_THROWS_WITH(j.erase(j.cend(), j.cend()), "[json.exception.invalid_iterator.204] iterators out of range"); CHECK_THROWS_WITH(j.erase(j.cbegin(), j.cbegin()), "[json.exception.invalid_iterator.204] iterators out of range"); } @@ -937,15 +937,15 @@ TEST_CASE("element access 1") { { json j = 17u; - CHECK_THROWS_AS(j.erase(j.end(), j.end()), json::invalid_iterator&); - CHECK_THROWS_AS(j.erase(j.begin(), j.begin()), json::invalid_iterator&); + CHECK_THROWS_AS(j.erase(j.end(), j.end()), json::invalid_iterator); + CHECK_THROWS_AS(j.erase(j.begin(), j.begin()), json::invalid_iterator); CHECK_THROWS_WITH(j.erase(j.end(), j.end()), "[json.exception.invalid_iterator.204] iterators out of range"); CHECK_THROWS_WITH(j.erase(j.begin(), j.begin()), "[json.exception.invalid_iterator.204] iterators out of range"); } { json j = 17u; - CHECK_THROWS_AS(j.erase(j.cend(), j.cend()), json::invalid_iterator&); - CHECK_THROWS_AS(j.erase(j.cbegin(), j.cbegin()), json::invalid_iterator&); + CHECK_THROWS_AS(j.erase(j.cend(), j.cend()), json::invalid_iterator); + CHECK_THROWS_AS(j.erase(j.cbegin(), j.cbegin()), json::invalid_iterator); CHECK_THROWS_WITH(j.erase(j.cend(), j.cend()), "[json.exception.invalid_iterator.204] iterators out of range"); CHECK_THROWS_WITH(j.erase(j.cbegin(), j.cbegin()), "[json.exception.invalid_iterator.204] iterators out of range"); } @@ -955,15 +955,15 @@ TEST_CASE("element access 1") { { json j = 23.42; - CHECK_THROWS_AS(j.erase(j.end(), j.end()), json::invalid_iterator&); - CHECK_THROWS_AS(j.erase(j.begin(), j.begin()), json::invalid_iterator&); + CHECK_THROWS_AS(j.erase(j.end(), j.end()), json::invalid_iterator); + CHECK_THROWS_AS(j.erase(j.begin(), j.begin()), json::invalid_iterator); CHECK_THROWS_WITH(j.erase(j.end(), j.end()), "[json.exception.invalid_iterator.204] iterators out of range"); CHECK_THROWS_WITH(j.erase(j.begin(), j.begin()), "[json.exception.invalid_iterator.204] iterators out of range"); } { json j = 23.42; - CHECK_THROWS_AS(j.erase(j.cend(), j.cend()), json::invalid_iterator&); - CHECK_THROWS_AS(j.erase(j.cbegin(), j.cbegin()), json::invalid_iterator&); + CHECK_THROWS_AS(j.erase(j.cend(), j.cend()), json::invalid_iterator); + CHECK_THROWS_AS(j.erase(j.cbegin(), j.cbegin()), json::invalid_iterator); CHECK_THROWS_WITH(j.erase(j.cend(), j.cend()), "[json.exception.invalid_iterator.204] iterators out of range"); CHECK_THROWS_WITH(j.erase(j.cbegin(), j.cbegin()), "[json.exception.invalid_iterator.204] iterators out of range"); } diff --git a/test/src/unit-element_access2.cpp b/test/src/unit-element_access2.cpp index 5950349b..ec03507e 100644 --- a/test/src/unit-element_access2.cpp +++ b/test/src/unit-element_access2.cpp @@ -63,8 +63,8 @@ TEST_CASE("element access 2") SECTION("access outside bounds") { - CHECK_THROWS_AS(j.at("foo"), json::out_of_range&); - CHECK_THROWS_AS(j_const.at("foo"), json::out_of_range&); + CHECK_THROWS_AS(j.at("foo"), json::out_of_range); + CHECK_THROWS_AS(j_const.at("foo"), json::out_of_range); CHECK_THROWS_WITH(j.at("foo"), "[json.exception.out_of_range.403] key 'foo' not found"); CHECK_THROWS_WITH(j_const.at("foo"), @@ -77,8 +77,8 @@ TEST_CASE("element access 2") { json j_nonobject(json::value_t::null); const json j_nonobject_const(j_nonobject); - CHECK_THROWS_AS(j_nonobject.at("foo"), json::type_error&); - CHECK_THROWS_AS(j_nonobject_const.at("foo"), json::type_error&); + CHECK_THROWS_AS(j_nonobject.at("foo"), json::type_error); + CHECK_THROWS_AS(j_nonobject_const.at("foo"), json::type_error); CHECK_THROWS_WITH(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with null"); CHECK_THROWS_WITH(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with null"); } @@ -87,8 +87,8 @@ TEST_CASE("element access 2") { json j_nonobject(json::value_t::boolean); const json j_nonobject_const(j_nonobject); - CHECK_THROWS_AS(j_nonobject.at("foo"), json::type_error&); - CHECK_THROWS_AS(j_nonobject_const.at("foo"), json::type_error&); + CHECK_THROWS_AS(j_nonobject.at("foo"), json::type_error); + CHECK_THROWS_AS(j_nonobject_const.at("foo"), json::type_error); CHECK_THROWS_WITH(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with boolean"); CHECK_THROWS_WITH(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with boolean"); } @@ -97,8 +97,8 @@ TEST_CASE("element access 2") { json j_nonobject(json::value_t::string); const json j_nonobject_const(j_nonobject); - CHECK_THROWS_AS(j_nonobject.at("foo"), json::type_error&); - CHECK_THROWS_AS(j_nonobject_const.at("foo"), json::type_error&); + CHECK_THROWS_AS(j_nonobject.at("foo"), json::type_error); + CHECK_THROWS_AS(j_nonobject_const.at("foo"), json::type_error); CHECK_THROWS_WITH(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with string"); CHECK_THROWS_WITH(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with string"); } @@ -107,8 +107,8 @@ TEST_CASE("element access 2") { json j_nonobject(json::value_t::array); const json j_nonobject_const(j_nonobject); - CHECK_THROWS_AS(j_nonobject.at("foo"), json::type_error&); - CHECK_THROWS_AS(j_nonobject_const.at("foo"), json::type_error&); + CHECK_THROWS_AS(j_nonobject.at("foo"), json::type_error); + CHECK_THROWS_AS(j_nonobject_const.at("foo"), json::type_error); CHECK_THROWS_WITH(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with array"); CHECK_THROWS_WITH(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with array"); } @@ -117,8 +117,8 @@ TEST_CASE("element access 2") { json j_nonobject(json::value_t::number_integer); const json j_nonobject_const(j_nonobject); - CHECK_THROWS_AS(j_nonobject.at("foo"), json::type_error&); - CHECK_THROWS_AS(j_nonobject_const.at("foo"), json::type_error&); + CHECK_THROWS_AS(j_nonobject.at("foo"), json::type_error); + CHECK_THROWS_AS(j_nonobject_const.at("foo"), json::type_error); CHECK_THROWS_WITH(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with number"); CHECK_THROWS_WITH(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with number"); } @@ -127,8 +127,8 @@ TEST_CASE("element access 2") { json j_nonobject(json::value_t::number_unsigned); const json j_nonobject_const(j_nonobject); - CHECK_THROWS_AS(j_nonobject.at("foo"), json::type_error&); - CHECK_THROWS_AS(j_nonobject_const.at("foo"), json::type_error&); + CHECK_THROWS_AS(j_nonobject.at("foo"), json::type_error); + CHECK_THROWS_AS(j_nonobject_const.at("foo"), json::type_error); CHECK_THROWS_WITH(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with number"); CHECK_THROWS_WITH(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with number"); } @@ -137,8 +137,8 @@ TEST_CASE("element access 2") { json j_nonobject(json::value_t::number_float); const json j_nonobject_const(j_nonobject); - CHECK_THROWS_AS(j_nonobject.at("foo"), json::type_error&); - CHECK_THROWS_AS(j_nonobject_const.at("foo"), json::type_error&); + CHECK_THROWS_AS(j_nonobject.at("foo"), json::type_error); + CHECK_THROWS_AS(j_nonobject_const.at("foo"), json::type_error); CHECK_THROWS_WITH(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with number"); CHECK_THROWS_WITH(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with number"); } @@ -202,8 +202,8 @@ TEST_CASE("element access 2") { json j_nonobject(json::value_t::null); const json j_nonobject_const(j_nonobject); - CHECK_THROWS_AS(j_nonobject.value("foo", 1), json::type_error&); - CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), json::type_error&); + CHECK_THROWS_AS(j_nonobject.value("foo", 1), json::type_error); + CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), json::type_error); CHECK_THROWS_WITH(j_nonobject.value("foo", 1), "[json.exception.type_error.306] cannot use value() with null"); CHECK_THROWS_WITH(j_nonobject_const.value("foo", 1), @@ -214,8 +214,8 @@ TEST_CASE("element access 2") { json j_nonobject(json::value_t::boolean); const json j_nonobject_const(j_nonobject); - CHECK_THROWS_AS(j_nonobject.value("foo", 1), json::type_error&); - CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), json::type_error&); + CHECK_THROWS_AS(j_nonobject.value("foo", 1), json::type_error); + CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), json::type_error); CHECK_THROWS_WITH(j_nonobject.value("foo", 1), "[json.exception.type_error.306] cannot use value() with boolean"); CHECK_THROWS_WITH(j_nonobject_const.value("foo", 1), @@ -226,8 +226,8 @@ TEST_CASE("element access 2") { json j_nonobject(json::value_t::string); const json j_nonobject_const(j_nonobject); - CHECK_THROWS_AS(j_nonobject.value("foo", 1), json::type_error&); - CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), json::type_error&); + CHECK_THROWS_AS(j_nonobject.value("foo", 1), json::type_error); + CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), json::type_error); CHECK_THROWS_WITH(j_nonobject.value("foo", 1), "[json.exception.type_error.306] cannot use value() with string"); CHECK_THROWS_WITH(j_nonobject_const.value("foo", 1), @@ -238,8 +238,8 @@ TEST_CASE("element access 2") { json j_nonobject(json::value_t::array); const json j_nonobject_const(j_nonobject); - CHECK_THROWS_AS(j_nonobject.value("foo", 1), json::type_error&); - CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), json::type_error&); + CHECK_THROWS_AS(j_nonobject.value("foo", 1), json::type_error); + CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), json::type_error); CHECK_THROWS_WITH(j_nonobject.value("foo", 1), "[json.exception.type_error.306] cannot use value() with array"); CHECK_THROWS_WITH(j_nonobject_const.value("foo", 1), @@ -250,8 +250,8 @@ TEST_CASE("element access 2") { json j_nonobject(json::value_t::number_integer); const json j_nonobject_const(j_nonobject); - CHECK_THROWS_AS(j_nonobject.value("foo", 1), json::type_error&); - CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), json::type_error&); + CHECK_THROWS_AS(j_nonobject.value("foo", 1), json::type_error); + CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), json::type_error); CHECK_THROWS_WITH(j_nonobject.value("foo", 1), "[json.exception.type_error.306] cannot use value() with number"); CHECK_THROWS_WITH(j_nonobject_const.value("foo", 1), @@ -262,8 +262,8 @@ TEST_CASE("element access 2") { json j_nonobject(json::value_t::number_unsigned); const json j_nonobject_const(j_nonobject); - CHECK_THROWS_AS(j_nonobject.value("foo", 1), json::type_error&); - CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), json::type_error&); + CHECK_THROWS_AS(j_nonobject.value("foo", 1), json::type_error); + CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), json::type_error); CHECK_THROWS_WITH(j_nonobject.value("foo", 1), "[json.exception.type_error.306] cannot use value() with number"); CHECK_THROWS_WITH(j_nonobject_const.value("foo", 1), @@ -274,8 +274,8 @@ TEST_CASE("element access 2") { json j_nonobject(json::value_t::number_float); const json j_nonobject_const(j_nonobject); - CHECK_THROWS_AS(j_nonobject.value("foo", 1), json::type_error&); - CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), json::type_error&); + CHECK_THROWS_AS(j_nonobject.value("foo", 1), json::type_error); + CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), json::type_error); CHECK_THROWS_WITH(j_nonobject.value("foo", 1), "[json.exception.type_error.306] cannot use value() with number"); CHECK_THROWS_WITH(j_nonobject_const.value("foo", 1), @@ -320,8 +320,8 @@ TEST_CASE("element access 2") { json j_nonobject(json::value_t::null); const json j_nonobject_const(j_nonobject); - CHECK_THROWS_AS(j_nonobject.value("/foo"_json_pointer, 1), json::type_error&); - CHECK_THROWS_AS(j_nonobject_const.value("/foo"_json_pointer, 1), json::type_error&); + CHECK_THROWS_AS(j_nonobject.value("/foo"_json_pointer, 1), json::type_error); + CHECK_THROWS_AS(j_nonobject_const.value("/foo"_json_pointer, 1), json::type_error); CHECK_THROWS_WITH(j_nonobject.value("/foo"_json_pointer, 1), "[json.exception.type_error.306] cannot use value() with null"); CHECK_THROWS_WITH(j_nonobject_const.value("/foo"_json_pointer, 1), @@ -332,8 +332,8 @@ TEST_CASE("element access 2") { json j_nonobject(json::value_t::boolean); const json j_nonobject_const(j_nonobject); - CHECK_THROWS_AS(j_nonobject.value("/foo"_json_pointer, 1), json::type_error&); - CHECK_THROWS_AS(j_nonobject_const.value("/foo"_json_pointer, 1), json::type_error&); + CHECK_THROWS_AS(j_nonobject.value("/foo"_json_pointer, 1), json::type_error); + CHECK_THROWS_AS(j_nonobject_const.value("/foo"_json_pointer, 1), json::type_error); CHECK_THROWS_WITH(j_nonobject.value("/foo"_json_pointer, 1), "[json.exception.type_error.306] cannot use value() with boolean"); CHECK_THROWS_WITH(j_nonobject_const.value("/foo"_json_pointer, 1), @@ -344,8 +344,8 @@ TEST_CASE("element access 2") { json j_nonobject(json::value_t::string); const json j_nonobject_const(j_nonobject); - CHECK_THROWS_AS(j_nonobject.value("/foo"_json_pointer, 1), json::type_error&); - CHECK_THROWS_AS(j_nonobject_const.value("/foo"_json_pointer, 1), json::type_error&); + CHECK_THROWS_AS(j_nonobject.value("/foo"_json_pointer, 1), json::type_error); + CHECK_THROWS_AS(j_nonobject_const.value("/foo"_json_pointer, 1), json::type_error); CHECK_THROWS_WITH(j_nonobject.value("/foo"_json_pointer, 1), "[json.exception.type_error.306] cannot use value() with string"); CHECK_THROWS_WITH(j_nonobject_const.value("/foo"_json_pointer, 1), @@ -356,8 +356,8 @@ TEST_CASE("element access 2") { json j_nonobject(json::value_t::array); const json j_nonobject_const(j_nonobject); - CHECK_THROWS_AS(j_nonobject.value("/foo"_json_pointer, 1), json::type_error&); - CHECK_THROWS_AS(j_nonobject_const.value("/foo"_json_pointer, 1), json::type_error&); + CHECK_THROWS_AS(j_nonobject.value("/foo"_json_pointer, 1), json::type_error); + CHECK_THROWS_AS(j_nonobject_const.value("/foo"_json_pointer, 1), json::type_error); CHECK_THROWS_WITH(j_nonobject.value("/foo"_json_pointer, 1), "[json.exception.type_error.306] cannot use value() with array"); CHECK_THROWS_WITH(j_nonobject_const.value("/foo"_json_pointer, 1), @@ -368,8 +368,8 @@ TEST_CASE("element access 2") { json j_nonobject(json::value_t::number_integer); const json j_nonobject_const(j_nonobject); - CHECK_THROWS_AS(j_nonobject.value("/foo"_json_pointer, 1), json::type_error&); - CHECK_THROWS_AS(j_nonobject_const.value("/foo"_json_pointer, 1), json::type_error&); + CHECK_THROWS_AS(j_nonobject.value("/foo"_json_pointer, 1), json::type_error); + CHECK_THROWS_AS(j_nonobject_const.value("/foo"_json_pointer, 1), json::type_error); CHECK_THROWS_WITH(j_nonobject.value("/foo"_json_pointer, 1), "[json.exception.type_error.306] cannot use value() with number"); CHECK_THROWS_WITH(j_nonobject_const.value("/foo"_json_pointer, 1), @@ -380,8 +380,8 @@ TEST_CASE("element access 2") { json j_nonobject(json::value_t::number_unsigned); const json j_nonobject_const(j_nonobject); - CHECK_THROWS_AS(j_nonobject.value("/foo"_json_pointer, 1), json::type_error&); - CHECK_THROWS_AS(j_nonobject_const.value("/foo"_json_pointer, 1), json::type_error&); + CHECK_THROWS_AS(j_nonobject.value("/foo"_json_pointer, 1), json::type_error); + CHECK_THROWS_AS(j_nonobject_const.value("/foo"_json_pointer, 1), json::type_error); CHECK_THROWS_WITH(j_nonobject.value("/foo"_json_pointer, 1), "[json.exception.type_error.306] cannot use value() with number"); CHECK_THROWS_WITH(j_nonobject_const.value("/foo"_json_pointer, 1), @@ -392,8 +392,8 @@ TEST_CASE("element access 2") { json j_nonobject(json::value_t::number_float); const json j_nonobject_const(j_nonobject); - CHECK_THROWS_AS(j_nonobject.value("/foo"_json_pointer, 1), json::type_error&); - CHECK_THROWS_AS(j_nonobject_const.value("/foo"_json_pointer, 1), json::type_error&); + CHECK_THROWS_AS(j_nonobject.value("/foo"_json_pointer, 1), json::type_error); + CHECK_THROWS_AS(j_nonobject_const.value("/foo"_json_pointer, 1), json::type_error); CHECK_THROWS_WITH(j_nonobject.value("/foo"_json_pointer, 1), "[json.exception.type_error.306] cannot use value() with number"); CHECK_THROWS_WITH(j_nonobject_const.value("/foo"_json_pointer, 1), @@ -472,8 +472,8 @@ TEST_CASE("element access 2") const json j_const_nonobject(j_nonobject); CHECK_NOTHROW(j_nonobject["foo"]); CHECK_NOTHROW(j_nonobject2[json::object_t::key_type("foo")]); - CHECK_THROWS_AS(j_const_nonobject["foo"], json::type_error&); - CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], json::type_error&); + CHECK_THROWS_AS(j_const_nonobject["foo"], json::type_error); + CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], json::type_error); CHECK_THROWS_WITH(j_const_nonobject["foo"], "[json.exception.type_error.305] cannot use operator[] with null"); CHECK_THROWS_WITH(j_const_nonobject[json::object_t::key_type("foo")], "[json.exception.type_error.305] cannot use operator[] with null"); @@ -483,10 +483,10 @@ TEST_CASE("element access 2") { json j_nonobject(json::value_t::boolean); const json j_const_nonobject(j_nonobject); - CHECK_THROWS_AS(j_nonobject["foo"], json::type_error&); - CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], json::type_error&); - CHECK_THROWS_AS(j_const_nonobject["foo"], json::type_error&); - CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], json::type_error&); + CHECK_THROWS_AS(j_nonobject["foo"], json::type_error); + CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], json::type_error); + CHECK_THROWS_AS(j_const_nonobject["foo"], json::type_error); + CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], json::type_error); CHECK_THROWS_WITH(j_nonobject["foo"], "[json.exception.type_error.305] cannot use operator[] with boolean"); CHECK_THROWS_WITH(j_nonobject[json::object_t::key_type("foo")], @@ -501,10 +501,10 @@ TEST_CASE("element access 2") { json j_nonobject(json::value_t::string); const json j_const_nonobject(j_nonobject); - CHECK_THROWS_AS(j_nonobject["foo"], json::type_error&); - CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], json::type_error&); - CHECK_THROWS_AS(j_const_nonobject["foo"], json::type_error&); - CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], json::type_error&); + CHECK_THROWS_AS(j_nonobject["foo"], json::type_error); + CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], json::type_error); + CHECK_THROWS_AS(j_const_nonobject["foo"], json::type_error); + CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], json::type_error); CHECK_THROWS_WITH(j_nonobject["foo"], "[json.exception.type_error.305] cannot use operator[] with string"); CHECK_THROWS_WITH(j_nonobject[json::object_t::key_type("foo")], @@ -519,10 +519,10 @@ TEST_CASE("element access 2") { json j_nonobject(json::value_t::array); const json j_const_nonobject(j_nonobject); - CHECK_THROWS_AS(j_nonobject["foo"], json::type_error&); - CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], json::type_error&); - CHECK_THROWS_AS(j_const_nonobject["foo"], json::type_error&); - CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], json::type_error&); + CHECK_THROWS_AS(j_nonobject["foo"], json::type_error); + CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], json::type_error); + CHECK_THROWS_AS(j_const_nonobject["foo"], json::type_error); + CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], json::type_error); CHECK_THROWS_WITH(j_nonobject["foo"], "[json.exception.type_error.305] cannot use operator[] with array"); CHECK_THROWS_WITH(j_nonobject[json::object_t::key_type("foo")], "[json.exception.type_error.305] cannot use operator[] with array"); @@ -536,10 +536,10 @@ TEST_CASE("element access 2") { json j_nonobject(json::value_t::number_integer); const json j_const_nonobject(j_nonobject); - CHECK_THROWS_AS(j_nonobject["foo"], json::type_error&); - CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], json::type_error&); - CHECK_THROWS_AS(j_const_nonobject["foo"], json::type_error&); - CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], json::type_error&); + CHECK_THROWS_AS(j_nonobject["foo"], json::type_error); + CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], json::type_error); + CHECK_THROWS_AS(j_const_nonobject["foo"], json::type_error); + CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], json::type_error); CHECK_THROWS_WITH(j_nonobject["foo"], "[json.exception.type_error.305] cannot use operator[] with number"); CHECK_THROWS_WITH(j_nonobject[json::object_t::key_type("foo")], @@ -554,10 +554,10 @@ TEST_CASE("element access 2") { json j_nonobject(json::value_t::number_unsigned); const json j_const_nonobject(j_nonobject); - CHECK_THROWS_AS(j_nonobject["foo"], json::type_error&); - CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], json::type_error&); - CHECK_THROWS_AS(j_const_nonobject["foo"], json::type_error&); - CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], json::type_error&); + CHECK_THROWS_AS(j_nonobject["foo"], json::type_error); + CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], json::type_error); + CHECK_THROWS_AS(j_const_nonobject["foo"], json::type_error); + CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], json::type_error); CHECK_THROWS_WITH(j_nonobject["foo"], "[json.exception.type_error.305] cannot use operator[] with number"); CHECK_THROWS_WITH(j_nonobject[json::object_t::key_type("foo")], @@ -572,10 +572,10 @@ TEST_CASE("element access 2") { json j_nonobject(json::value_t::number_float); const json j_const_nonobject(j_nonobject); - CHECK_THROWS_AS(j_nonobject["foo"], json::type_error&); - CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], json::type_error&); - CHECK_THROWS_AS(j_const_nonobject["foo"], json::type_error&); - CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], json::type_error&); + CHECK_THROWS_AS(j_nonobject["foo"], json::type_error); + CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], json::type_error); + CHECK_THROWS_AS(j_const_nonobject["foo"], json::type_error); + CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], json::type_error); CHECK_THROWS_WITH(j_nonobject["foo"], "[json.exception.type_error.305] cannot use operator[] with number"); CHECK_THROWS_WITH(j_nonobject[json::object_t::key_type("foo")], @@ -722,10 +722,10 @@ TEST_CASE("element access 2") { json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}, {"d", false}, {"e", true}}; json jobject2 = {{"a", "a"}, {"b", 1}, {"c", 17u}}; - CHECK_THROWS_AS(jobject.erase(jobject2.begin()), json::invalid_iterator&); - CHECK_THROWS_AS(jobject.erase(jobject.begin(), jobject2.end()), json::invalid_iterator&); - CHECK_THROWS_AS(jobject.erase(jobject2.begin(), jobject.end()), json::invalid_iterator&); - CHECK_THROWS_AS(jobject.erase(jobject2.begin(), jobject2.end()), json::invalid_iterator&); + CHECK_THROWS_AS(jobject.erase(jobject2.begin()), json::invalid_iterator); + CHECK_THROWS_AS(jobject.erase(jobject.begin(), jobject2.end()), json::invalid_iterator); + CHECK_THROWS_AS(jobject.erase(jobject2.begin(), jobject.end()), json::invalid_iterator); + CHECK_THROWS_AS(jobject.erase(jobject2.begin(), jobject2.end()), json::invalid_iterator); CHECK_THROWS_WITH(jobject.erase(jobject2.begin()), "[json.exception.invalid_iterator.202] iterator does not fit current value"); CHECK_THROWS_WITH(jobject.erase(jobject.begin(), jobject2.end()), @@ -738,10 +738,10 @@ TEST_CASE("element access 2") { json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}, {"d", false}, {"e", true}}; json jobject2 = {{"a", "a"}, {"b", 1}, {"c", 17u}}; - CHECK_THROWS_AS(jobject.erase(jobject2.cbegin()), json::invalid_iterator&); - CHECK_THROWS_AS(jobject.erase(jobject.cbegin(), jobject2.cend()), json::invalid_iterator&); - CHECK_THROWS_AS(jobject.erase(jobject2.cbegin(), jobject.cend()), json::invalid_iterator&); - CHECK_THROWS_AS(jobject.erase(jobject2.cbegin(), jobject2.cend()), json::invalid_iterator&); + CHECK_THROWS_AS(jobject.erase(jobject2.cbegin()), json::invalid_iterator); + CHECK_THROWS_AS(jobject.erase(jobject.cbegin(), jobject2.cend()), json::invalid_iterator); + CHECK_THROWS_AS(jobject.erase(jobject2.cbegin(), jobject.cend()), json::invalid_iterator); + CHECK_THROWS_AS(jobject.erase(jobject2.cbegin(), jobject2.cend()), json::invalid_iterator); CHECK_THROWS_WITH(jobject.erase(jobject2.cbegin()), "[json.exception.invalid_iterator.202] iterator does not fit current value"); CHECK_THROWS_WITH(jobject.erase(jobject.cbegin(), jobject2.cend()), @@ -759,7 +759,7 @@ TEST_CASE("element access 2") SECTION("null") { json j_nonobject(json::value_t::null); - CHECK_THROWS_AS(j_nonobject.erase("foo"), json::type_error&); + CHECK_THROWS_AS(j_nonobject.erase("foo"), json::type_error); CHECK_THROWS_WITH(j_nonobject.erase("foo"), "[json.exception.type_error.307] cannot use erase() with null"); } @@ -767,7 +767,7 @@ TEST_CASE("element access 2") SECTION("boolean") { json j_nonobject(json::value_t::boolean); - CHECK_THROWS_AS(j_nonobject.erase("foo"), json::type_error&); + CHECK_THROWS_AS(j_nonobject.erase("foo"), json::type_error); CHECK_THROWS_WITH(j_nonobject.erase("foo"), "[json.exception.type_error.307] cannot use erase() with boolean"); } @@ -775,7 +775,7 @@ TEST_CASE("element access 2") SECTION("string") { json j_nonobject(json::value_t::string); - CHECK_THROWS_AS(j_nonobject.erase("foo"), json::type_error&); + CHECK_THROWS_AS(j_nonobject.erase("foo"), json::type_error); CHECK_THROWS_WITH(j_nonobject.erase("foo"), "[json.exception.type_error.307] cannot use erase() with string"); } @@ -783,7 +783,7 @@ TEST_CASE("element access 2") SECTION("array") { json j_nonobject(json::value_t::array); - CHECK_THROWS_AS(j_nonobject.erase("foo"), json::type_error&); + CHECK_THROWS_AS(j_nonobject.erase("foo"), json::type_error); CHECK_THROWS_WITH(j_nonobject.erase("foo"), "[json.exception.type_error.307] cannot use erase() with array"); } @@ -791,7 +791,7 @@ TEST_CASE("element access 2") SECTION("number (integer)") { json j_nonobject(json::value_t::number_integer); - CHECK_THROWS_AS(j_nonobject.erase("foo"), json::type_error&); + CHECK_THROWS_AS(j_nonobject.erase("foo"), json::type_error); CHECK_THROWS_WITH(j_nonobject.erase("foo"), "[json.exception.type_error.307] cannot use erase() with number"); } @@ -799,7 +799,7 @@ TEST_CASE("element access 2") SECTION("number (floating-point)") { json j_nonobject(json::value_t::number_float); - CHECK_THROWS_AS(j_nonobject.erase("foo"), json::type_error&); + CHECK_THROWS_AS(j_nonobject.erase("foo"), json::type_error); CHECK_THROWS_WITH(j_nonobject.erase("foo"), "[json.exception.type_error.307] cannot use erase() with number"); } diff --git a/test/src/unit-iterators1.cpp b/test/src/unit-iterators1.cpp index 66ffed22..c707b2d9 100644 --- a/test/src/unit-iterators1.cpp +++ b/test/src/unit-iterators1.cpp @@ -337,19 +337,19 @@ TEST_CASE("iterators 1") { auto it = j.begin(); auto cit = j_const.cbegin(); - CHECK_THROWS_AS(it.key(), json::invalid_iterator&); + CHECK_THROWS_AS(it.key(), json::invalid_iterator); CHECK_THROWS_WITH(it.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); CHECK(it.value() == json(true)); - CHECK_THROWS_AS(cit.key(), json::invalid_iterator&); + CHECK_THROWS_AS(cit.key(), json::invalid_iterator); CHECK_THROWS_WITH(cit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); CHECK(cit.value() == json(true)); auto rit = j.rend(); auto crit = j.crend(); - CHECK_THROWS_AS(rit.key(), json::invalid_iterator&); - CHECK_THROWS_AS(rit.value(), json::invalid_iterator&); - CHECK_THROWS_AS(crit.key(), json::invalid_iterator&); - CHECK_THROWS_AS(crit.value(), json::invalid_iterator&); + CHECK_THROWS_AS(rit.key(), json::invalid_iterator); + CHECK_THROWS_AS(rit.value(), json::invalid_iterator); + CHECK_THROWS_AS(crit.key(), json::invalid_iterator); + CHECK_THROWS_AS(crit.value(), json::invalid_iterator); CHECK_THROWS_WITH(rit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); CHECK_THROWS_WITH(rit.value(), "[json.exception.invalid_iterator.214] cannot get value"); CHECK_THROWS_WITH(crit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); @@ -541,19 +541,19 @@ TEST_CASE("iterators 1") { auto it = j.begin(); auto cit = j_const.cbegin(); - CHECK_THROWS_AS(it.key(), json::invalid_iterator&); + CHECK_THROWS_AS(it.key(), json::invalid_iterator); CHECK_THROWS_WITH(it.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); CHECK(it.value() == json("hello world")); - CHECK_THROWS_AS(cit.key(), json::invalid_iterator&); + CHECK_THROWS_AS(cit.key(), json::invalid_iterator); CHECK_THROWS_WITH(cit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); CHECK(cit.value() == json("hello world")); auto rit = j.rend(); auto crit = j.crend(); - CHECK_THROWS_AS(rit.key(), json::invalid_iterator&); - CHECK_THROWS_AS(rit.value(), json::invalid_iterator&); - CHECK_THROWS_AS(crit.key(), json::invalid_iterator&); - CHECK_THROWS_AS(crit.value(), json::invalid_iterator&); + CHECK_THROWS_AS(rit.key(), json::invalid_iterator); + CHECK_THROWS_AS(rit.value(), json::invalid_iterator); + CHECK_THROWS_AS(crit.key(), json::invalid_iterator); + CHECK_THROWS_AS(crit.value(), json::invalid_iterator); CHECK_THROWS_WITH(rit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); CHECK_THROWS_WITH(rit.value(), "[json.exception.invalid_iterator.214] cannot get value"); CHECK_THROWS_WITH(crit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); @@ -738,10 +738,10 @@ TEST_CASE("iterators 1") { auto it = j.begin(); auto cit = j_const.cbegin(); - CHECK_THROWS_AS(it.key(), json::invalid_iterator&); + CHECK_THROWS_AS(it.key(), json::invalid_iterator); CHECK_THROWS_WITH(it.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); CHECK(it.value() == json(1)); - CHECK_THROWS_AS(cit.key(), json::invalid_iterator&); + CHECK_THROWS_AS(cit.key(), json::invalid_iterator); CHECK_THROWS_WITH(cit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); CHECK(cit.value() == json(1)); } @@ -1115,19 +1115,19 @@ TEST_CASE("iterators 1") { auto it = j.begin(); auto cit = j_const.cbegin(); - CHECK_THROWS_AS(it.key(), json::invalid_iterator&); + CHECK_THROWS_AS(it.key(), json::invalid_iterator); CHECK_THROWS_WITH(it.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); CHECK(it.value() == json(23)); - CHECK_THROWS_AS(cit.key(), json::invalid_iterator&); + CHECK_THROWS_AS(cit.key(), json::invalid_iterator); CHECK_THROWS_WITH(cit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); CHECK(cit.value() == json(23)); auto rit = j.rend(); auto crit = j.crend(); - CHECK_THROWS_AS(rit.key(), json::invalid_iterator&); - CHECK_THROWS_AS(rit.value(), json::invalid_iterator&); - CHECK_THROWS_AS(crit.key(), json::invalid_iterator&); - CHECK_THROWS_AS(crit.value(), json::invalid_iterator&); + CHECK_THROWS_AS(rit.key(), json::invalid_iterator); + CHECK_THROWS_AS(rit.value(), json::invalid_iterator); + CHECK_THROWS_AS(crit.key(), json::invalid_iterator); + CHECK_THROWS_AS(crit.value(), json::invalid_iterator); CHECK_THROWS_WITH(rit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); CHECK_THROWS_WITH(rit.value(), "[json.exception.invalid_iterator.214] cannot get value"); CHECK_THROWS_WITH(crit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); @@ -1319,19 +1319,19 @@ TEST_CASE("iterators 1") { auto it = j.begin(); auto cit = j_const.cbegin(); - CHECK_THROWS_AS(it.key(), json::invalid_iterator&); + CHECK_THROWS_AS(it.key(), json::invalid_iterator); CHECK_THROWS_WITH(it.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); CHECK(it.value() == json(23)); - CHECK_THROWS_AS(cit.key(), json::invalid_iterator&); + CHECK_THROWS_AS(cit.key(), json::invalid_iterator); CHECK_THROWS_WITH(cit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); CHECK(cit.value() == json(23)); auto rit = j.rend(); auto crit = j.crend(); - CHECK_THROWS_AS(rit.key(), json::invalid_iterator&); - CHECK_THROWS_AS(rit.value(), json::invalid_iterator&); - CHECK_THROWS_AS(crit.key(), json::invalid_iterator&); - CHECK_THROWS_AS(crit.value(), json::invalid_iterator&); + CHECK_THROWS_AS(rit.key(), json::invalid_iterator); + CHECK_THROWS_AS(rit.value(), json::invalid_iterator); + CHECK_THROWS_AS(crit.key(), json::invalid_iterator); + CHECK_THROWS_AS(crit.value(), json::invalid_iterator); CHECK_THROWS_WITH(rit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); CHECK_THROWS_WITH(rit.value(), "[json.exception.invalid_iterator.214] cannot get value"); CHECK_THROWS_WITH(crit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); @@ -1523,19 +1523,19 @@ TEST_CASE("iterators 1") { auto it = j.begin(); auto cit = j_const.cbegin(); - CHECK_THROWS_AS(it.key(), json::invalid_iterator&); + CHECK_THROWS_AS(it.key(), json::invalid_iterator); CHECK_THROWS_WITH(it.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); CHECK(it.value() == json(23.42)); - CHECK_THROWS_AS(cit.key(), json::invalid_iterator&); + CHECK_THROWS_AS(cit.key(), json::invalid_iterator); CHECK_THROWS_WITH(cit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); CHECK(cit.value() == json(23.42)); auto rit = j.rend(); auto crit = j.crend(); - CHECK_THROWS_AS(rit.key(), json::invalid_iterator&); - CHECK_THROWS_AS(rit.value(), json::invalid_iterator&); - CHECK_THROWS_AS(crit.key(), json::invalid_iterator&); - CHECK_THROWS_AS(crit.value(), json::invalid_iterator&); + CHECK_THROWS_AS(rit.key(), json::invalid_iterator); + CHECK_THROWS_AS(rit.value(), json::invalid_iterator); + CHECK_THROWS_AS(crit.key(), json::invalid_iterator); + CHECK_THROWS_AS(crit.value(), json::invalid_iterator); CHECK_THROWS_WITH(rit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); CHECK_THROWS_WITH(rit.value(), "[json.exception.invalid_iterator.214] cannot get value"); CHECK_THROWS_WITH(crit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); @@ -1597,10 +1597,10 @@ TEST_CASE("iterators 1") { auto it = j.begin(); auto cit = j_const.cbegin(); - CHECK_THROWS_AS(it.key(), json::invalid_iterator&); - CHECK_THROWS_AS(it.value(), json::invalid_iterator&); - CHECK_THROWS_AS(cit.key(), json::invalid_iterator&); - CHECK_THROWS_AS(cit.value(), json::invalid_iterator&); + CHECK_THROWS_AS(it.key(), json::invalid_iterator); + CHECK_THROWS_AS(it.value(), json::invalid_iterator); + CHECK_THROWS_AS(cit.key(), json::invalid_iterator); + CHECK_THROWS_AS(cit.value(), json::invalid_iterator); CHECK_THROWS_WITH(it.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); CHECK_THROWS_WITH(it.value(), "[json.exception.invalid_iterator.214] cannot get value"); CHECK_THROWS_WITH(cit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); @@ -1608,10 +1608,10 @@ TEST_CASE("iterators 1") auto rit = j.rend(); auto crit = j.crend(); - CHECK_THROWS_AS(rit.key(), json::invalid_iterator&); - CHECK_THROWS_AS(rit.value(), json::invalid_iterator&); - CHECK_THROWS_AS(crit.key(), json::invalid_iterator&); - CHECK_THROWS_AS(crit.value(), json::invalid_iterator&); + CHECK_THROWS_AS(rit.key(), json::invalid_iterator); + CHECK_THROWS_AS(rit.value(), json::invalid_iterator); + CHECK_THROWS_AS(crit.key(), json::invalid_iterator); + CHECK_THROWS_AS(crit.value(), json::invalid_iterator); CHECK_THROWS_WITH(rit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); CHECK_THROWS_WITH(rit.value(), "[json.exception.invalid_iterator.214] cannot get value"); CHECK_THROWS_WITH(crit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); diff --git a/test/src/unit-iterators2.cpp b/test/src/unit-iterators2.cpp index be4e2770..29d134da 100644 --- a/test/src/unit-iterators2.cpp +++ b/test/src/unit-iterators2.cpp @@ -81,14 +81,14 @@ TEST_CASE("iterators 2") { if (j.type() == json::value_t::object) { - CHECK_THROWS_AS(it1 < it1, json::invalid_iterator&); - CHECK_THROWS_AS(it1 < it2, json::invalid_iterator&); - CHECK_THROWS_AS(it2 < it3, json::invalid_iterator&); - CHECK_THROWS_AS(it1 < it3, json::invalid_iterator&); - CHECK_THROWS_AS(it1_c < it1_c, json::invalid_iterator&); - CHECK_THROWS_AS(it1_c < it2_c, json::invalid_iterator&); - CHECK_THROWS_AS(it2_c < it3_c, json::invalid_iterator&); - CHECK_THROWS_AS(it1_c < it3_c, json::invalid_iterator&); + CHECK_THROWS_AS(it1 < it1, json::invalid_iterator); + CHECK_THROWS_AS(it1 < it2, json::invalid_iterator); + CHECK_THROWS_AS(it2 < it3, json::invalid_iterator); + CHECK_THROWS_AS(it1 < it3, json::invalid_iterator); + CHECK_THROWS_AS(it1_c < it1_c, json::invalid_iterator); + CHECK_THROWS_AS(it1_c < it2_c, json::invalid_iterator); + CHECK_THROWS_AS(it2_c < it3_c, json::invalid_iterator); + CHECK_THROWS_AS(it1_c < it3_c, json::invalid_iterator); CHECK_THROWS_WITH(it1 < it1, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); CHECK_THROWS_WITH(it1 < it2, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); CHECK_THROWS_WITH(it2 < it3, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); @@ -115,14 +115,14 @@ TEST_CASE("iterators 2") { if (j.type() == json::value_t::object) { - CHECK_THROWS_AS(it1 <= it1, json::invalid_iterator&); - CHECK_THROWS_AS(it1 <= it2, json::invalid_iterator&); - CHECK_THROWS_AS(it2 <= it3, json::invalid_iterator&); - CHECK_THROWS_AS(it1 <= it3, json::invalid_iterator&); - CHECK_THROWS_AS(it1_c <= it1_c, json::invalid_iterator&); - CHECK_THROWS_AS(it1_c <= it2_c, json::invalid_iterator&); - CHECK_THROWS_AS(it2_c <= it3_c, json::invalid_iterator&); - CHECK_THROWS_AS(it1_c <= it3_c, json::invalid_iterator&); + CHECK_THROWS_AS(it1 <= it1, json::invalid_iterator); + CHECK_THROWS_AS(it1 <= it2, json::invalid_iterator); + CHECK_THROWS_AS(it2 <= it3, json::invalid_iterator); + CHECK_THROWS_AS(it1 <= it3, json::invalid_iterator); + CHECK_THROWS_AS(it1_c <= it1_c, json::invalid_iterator); + CHECK_THROWS_AS(it1_c <= it2_c, json::invalid_iterator); + CHECK_THROWS_AS(it2_c <= it3_c, json::invalid_iterator); + CHECK_THROWS_AS(it1_c <= it3_c, json::invalid_iterator); CHECK_THROWS_WITH(it1 <= it1, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); CHECK_THROWS_WITH(it1 <= it2, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); CHECK_THROWS_WITH(it2 <= it3, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); @@ -150,14 +150,14 @@ TEST_CASE("iterators 2") { if (j.type() == json::value_t::object) { - CHECK_THROWS_AS(it1 > it1, json::invalid_iterator&); - CHECK_THROWS_AS(it1 > it2, json::invalid_iterator&); - CHECK_THROWS_AS(it2 > it3, json::invalid_iterator&); - CHECK_THROWS_AS(it1 > it3, json::invalid_iterator&); - CHECK_THROWS_AS(it1_c > it1_c, json::invalid_iterator&); - CHECK_THROWS_AS(it1_c > it2_c, json::invalid_iterator&); - CHECK_THROWS_AS(it2_c > it3_c, json::invalid_iterator&); - CHECK_THROWS_AS(it1_c > it3_c, json::invalid_iterator&); + CHECK_THROWS_AS(it1 > it1, json::invalid_iterator); + CHECK_THROWS_AS(it1 > it2, json::invalid_iterator); + CHECK_THROWS_AS(it2 > it3, json::invalid_iterator); + CHECK_THROWS_AS(it1 > it3, json::invalid_iterator); + CHECK_THROWS_AS(it1_c > it1_c, json::invalid_iterator); + CHECK_THROWS_AS(it1_c > it2_c, json::invalid_iterator); + CHECK_THROWS_AS(it2_c > it3_c, json::invalid_iterator); + CHECK_THROWS_AS(it1_c > it3_c, json::invalid_iterator); CHECK_THROWS_WITH(it1 > it1, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); CHECK_THROWS_WITH(it1 > it2, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); CHECK_THROWS_WITH(it2 > it3, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); @@ -185,14 +185,14 @@ TEST_CASE("iterators 2") { if (j.type() == json::value_t::object) { - CHECK_THROWS_AS(it1 >= it1, json::invalid_iterator&); - CHECK_THROWS_AS(it1 >= it2, json::invalid_iterator&); - CHECK_THROWS_AS(it2 >= it3, json::invalid_iterator&); - CHECK_THROWS_AS(it1 >= it3, json::invalid_iterator&); - CHECK_THROWS_AS(it1_c >= it1_c, json::invalid_iterator&); - CHECK_THROWS_AS(it1_c >= it2_c, json::invalid_iterator&); - CHECK_THROWS_AS(it2_c >= it3_c, json::invalid_iterator&); - CHECK_THROWS_AS(it1_c >= it3_c, json::invalid_iterator&); + CHECK_THROWS_AS(it1 >= it1, json::invalid_iterator); + CHECK_THROWS_AS(it1 >= it2, json::invalid_iterator); + CHECK_THROWS_AS(it2 >= it3, json::invalid_iterator); + CHECK_THROWS_AS(it1 >= it3, json::invalid_iterator); + CHECK_THROWS_AS(it1_c >= it1_c, json::invalid_iterator); + CHECK_THROWS_AS(it1_c >= it2_c, json::invalid_iterator); + CHECK_THROWS_AS(it2_c >= it3_c, json::invalid_iterator); + CHECK_THROWS_AS(it1_c >= it3_c, json::invalid_iterator); CHECK_THROWS_WITH(it1 >= it1, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); CHECK_THROWS_WITH(it1 >= it2, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); CHECK_THROWS_WITH(it2 >= it3, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); @@ -224,13 +224,13 @@ TEST_CASE("iterators 2") { if (j != k) { - CHECK_THROWS_AS(j.begin() == k.begin(), json::invalid_iterator&); - CHECK_THROWS_AS(j.cbegin() == k.cbegin(), json::invalid_iterator&); + CHECK_THROWS_AS(j.begin() == k.begin(), json::invalid_iterator); + CHECK_THROWS_AS(j.cbegin() == k.cbegin(), json::invalid_iterator); CHECK_THROWS_WITH(j.begin() == k.begin(), "[json.exception.invalid_iterator.212] cannot compare iterators of different containers"); CHECK_THROWS_WITH(j.cbegin() == k.cbegin(), "[json.exception.invalid_iterator.212] cannot compare iterators of different containers"); - CHECK_THROWS_AS(j.begin() < k.begin(), json::invalid_iterator&); - CHECK_THROWS_AS(j.cbegin() < k.cbegin(), json::invalid_iterator&); + CHECK_THROWS_AS(j.begin() < k.begin(), json::invalid_iterator); + CHECK_THROWS_AS(j.cbegin() < k.cbegin(), json::invalid_iterator); CHECK_THROWS_WITH(j.begin() < k.begin(), "[json.exception.invalid_iterator.212] cannot compare iterators of different containers"); CHECK_THROWS_WITH(j.cbegin() < k.cbegin(), "[json.exception.invalid_iterator.212] cannot compare iterators of different containers"); } @@ -251,62 +251,62 @@ TEST_CASE("iterators 2") { { auto it = j_object.begin(); - CHECK_THROWS_AS(it += 1, json::invalid_iterator&); + CHECK_THROWS_AS(it += 1, json::invalid_iterator); CHECK_THROWS_WITH(it += 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.cbegin(); - CHECK_THROWS_AS(it += 1, json::invalid_iterator&); + CHECK_THROWS_AS(it += 1, json::invalid_iterator); CHECK_THROWS_WITH(it += 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.begin(); - CHECK_THROWS_AS(it + 1, json::invalid_iterator&); + CHECK_THROWS_AS(it + 1, json::invalid_iterator); CHECK_THROWS_WITH(it + 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.cbegin(); - CHECK_THROWS_AS(it + 1, json::invalid_iterator&); + CHECK_THROWS_AS(it + 1, json::invalid_iterator); CHECK_THROWS_WITH(it + 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.begin(); - CHECK_THROWS_AS(1 + it, json::invalid_iterator&); + CHECK_THROWS_AS(1 + it, json::invalid_iterator); CHECK_THROWS_WITH(1 + it, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.cbegin(); - CHECK_THROWS_AS(1 + it, json::invalid_iterator&); + CHECK_THROWS_AS(1 + it, json::invalid_iterator); CHECK_THROWS_WITH(1 + it, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.begin(); - CHECK_THROWS_AS(it -= 1, json::invalid_iterator&); + CHECK_THROWS_AS(it -= 1, json::invalid_iterator); CHECK_THROWS_WITH(it -= 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.cbegin(); - CHECK_THROWS_AS(it -= 1, json::invalid_iterator&); + CHECK_THROWS_AS(it -= 1, json::invalid_iterator); CHECK_THROWS_WITH(it -= 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.begin(); - CHECK_THROWS_AS(it - 1, json::invalid_iterator&); + CHECK_THROWS_AS(it - 1, json::invalid_iterator); CHECK_THROWS_WITH(it - 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.cbegin(); - CHECK_THROWS_AS(it - 1, json::invalid_iterator&); + CHECK_THROWS_AS(it - 1, json::invalid_iterator); CHECK_THROWS_WITH(it - 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.begin(); - CHECK_THROWS_AS(it - it, json::invalid_iterator&); + CHECK_THROWS_AS(it - it, json::invalid_iterator); CHECK_THROWS_WITH(it - it, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.cbegin(); - CHECK_THROWS_AS(it - it, json::invalid_iterator&); + CHECK_THROWS_AS(it - it, json::invalid_iterator); CHECK_THROWS_WITH(it - it, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } } @@ -396,15 +396,15 @@ TEST_CASE("iterators 2") { { auto it = j_object.begin(); - CHECK_THROWS_AS(it[0], json::invalid_iterator&); - CHECK_THROWS_AS(it[1], json::invalid_iterator&); + CHECK_THROWS_AS(it[0], json::invalid_iterator); + CHECK_THROWS_AS(it[1], json::invalid_iterator); CHECK_THROWS_WITH(it[0], "[json.exception.invalid_iterator.208] cannot use operator[] for object iterators"); CHECK_THROWS_WITH(it[1], "[json.exception.invalid_iterator.208] cannot use operator[] for object iterators"); } { auto it = j_object.cbegin(); - CHECK_THROWS_AS(it[0], json::invalid_iterator&); - CHECK_THROWS_AS(it[1], json::invalid_iterator&); + CHECK_THROWS_AS(it[0], json::invalid_iterator); + CHECK_THROWS_AS(it[1], json::invalid_iterator); CHECK_THROWS_WITH(it[0], "[json.exception.invalid_iterator.208] cannot use operator[] for object iterators"); CHECK_THROWS_WITH(it[1], "[json.exception.invalid_iterator.208] cannot use operator[] for object iterators"); } @@ -436,15 +436,15 @@ TEST_CASE("iterators 2") { { auto it = j_null.begin(); - CHECK_THROWS_AS(it[0], json::invalid_iterator&); - CHECK_THROWS_AS(it[1], json::invalid_iterator&); + CHECK_THROWS_AS(it[0], json::invalid_iterator); + CHECK_THROWS_AS(it[1], json::invalid_iterator); CHECK_THROWS_WITH(it[0], "[json.exception.invalid_iterator.214] cannot get value"); CHECK_THROWS_WITH(it[1], "[json.exception.invalid_iterator.214] cannot get value"); } { auto it = j_null.cbegin(); - CHECK_THROWS_AS(it[0], json::invalid_iterator&); - CHECK_THROWS_AS(it[1], json::invalid_iterator&); + CHECK_THROWS_AS(it[0], json::invalid_iterator); + CHECK_THROWS_AS(it[1], json::invalid_iterator); CHECK_THROWS_WITH(it[0], "[json.exception.invalid_iterator.214] cannot get value"); CHECK_THROWS_WITH(it[1], "[json.exception.invalid_iterator.214] cannot get value"); } @@ -455,13 +455,13 @@ TEST_CASE("iterators 2") { auto it = j_value.begin(); CHECK(it[0] == json(42)); - CHECK_THROWS_AS(it[1], json::invalid_iterator&); + CHECK_THROWS_AS(it[1], json::invalid_iterator); CHECK_THROWS_WITH(it[1], "[json.exception.invalid_iterator.214] cannot get value"); } { auto it = j_value.cbegin(); CHECK(it[0] == json(42)); - CHECK_THROWS_AS(it[1], json::invalid_iterator&); + CHECK_THROWS_AS(it[1], json::invalid_iterator); CHECK_THROWS_WITH(it[1], "[json.exception.invalid_iterator.214] cannot get value"); } } @@ -516,14 +516,14 @@ TEST_CASE("iterators 2") { if (j.type() == json::value_t::object) { - CHECK_THROWS_AS(it1 < it1, json::invalid_iterator&); - CHECK_THROWS_AS(it1 < it2, json::invalid_iterator&); - CHECK_THROWS_AS(it2 < it3, json::invalid_iterator&); - CHECK_THROWS_AS(it1 < it3, json::invalid_iterator&); - CHECK_THROWS_AS(it1_c < it1_c, json::invalid_iterator&); - CHECK_THROWS_AS(it1_c < it2_c, json::invalid_iterator&); - CHECK_THROWS_AS(it2_c < it3_c, json::invalid_iterator&); - CHECK_THROWS_AS(it1_c < it3_c, json::invalid_iterator&); + CHECK_THROWS_AS(it1 < it1, json::invalid_iterator); + CHECK_THROWS_AS(it1 < it2, json::invalid_iterator); + CHECK_THROWS_AS(it2 < it3, json::invalid_iterator); + CHECK_THROWS_AS(it1 < it3, json::invalid_iterator); + CHECK_THROWS_AS(it1_c < it1_c, json::invalid_iterator); + CHECK_THROWS_AS(it1_c < it2_c, json::invalid_iterator); + CHECK_THROWS_AS(it2_c < it3_c, json::invalid_iterator); + CHECK_THROWS_AS(it1_c < it3_c, json::invalid_iterator); CHECK_THROWS_WITH(it1 < it1, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); CHECK_THROWS_WITH(it1 < it2, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); CHECK_THROWS_WITH(it2 < it3, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); @@ -550,14 +550,14 @@ TEST_CASE("iterators 2") { if (j.type() == json::value_t::object) { - CHECK_THROWS_AS(it1 <= it1, json::invalid_iterator&); - CHECK_THROWS_AS(it1 <= it2, json::invalid_iterator&); - CHECK_THROWS_AS(it2 <= it3, json::invalid_iterator&); - CHECK_THROWS_AS(it1 <= it3, json::invalid_iterator&); - CHECK_THROWS_AS(it1_c <= it1_c, json::invalid_iterator&); - CHECK_THROWS_AS(it1_c <= it2_c, json::invalid_iterator&); - CHECK_THROWS_AS(it2_c <= it3_c, json::invalid_iterator&); - CHECK_THROWS_AS(it1_c <= it3_c, json::invalid_iterator&); + CHECK_THROWS_AS(it1 <= it1, json::invalid_iterator); + CHECK_THROWS_AS(it1 <= it2, json::invalid_iterator); + CHECK_THROWS_AS(it2 <= it3, json::invalid_iterator); + CHECK_THROWS_AS(it1 <= it3, json::invalid_iterator); + CHECK_THROWS_AS(it1_c <= it1_c, json::invalid_iterator); + CHECK_THROWS_AS(it1_c <= it2_c, json::invalid_iterator); + CHECK_THROWS_AS(it2_c <= it3_c, json::invalid_iterator); + CHECK_THROWS_AS(it1_c <= it3_c, json::invalid_iterator); CHECK_THROWS_WITH(it1 <= it1, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); CHECK_THROWS_WITH(it1 <= it2, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); CHECK_THROWS_WITH(it2 <= it3, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); @@ -585,14 +585,14 @@ TEST_CASE("iterators 2") { if (j.type() == json::value_t::object) { - CHECK_THROWS_AS(it1 > it1, json::invalid_iterator&); - CHECK_THROWS_AS(it1 > it2, json::invalid_iterator&); - CHECK_THROWS_AS(it2 > it3, json::invalid_iterator&); - CHECK_THROWS_AS(it1 > it3, json::invalid_iterator&); - CHECK_THROWS_AS(it1_c > it1_c, json::invalid_iterator&); - CHECK_THROWS_AS(it1_c > it2_c, json::invalid_iterator&); - CHECK_THROWS_AS(it2_c > it3_c, json::invalid_iterator&); - CHECK_THROWS_AS(it1_c > it3_c, json::invalid_iterator&); + CHECK_THROWS_AS(it1 > it1, json::invalid_iterator); + CHECK_THROWS_AS(it1 > it2, json::invalid_iterator); + CHECK_THROWS_AS(it2 > it3, json::invalid_iterator); + CHECK_THROWS_AS(it1 > it3, json::invalid_iterator); + CHECK_THROWS_AS(it1_c > it1_c, json::invalid_iterator); + CHECK_THROWS_AS(it1_c > it2_c, json::invalid_iterator); + CHECK_THROWS_AS(it2_c > it3_c, json::invalid_iterator); + CHECK_THROWS_AS(it1_c > it3_c, json::invalid_iterator); CHECK_THROWS_WITH(it1 > it1, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); CHECK_THROWS_WITH(it1 > it2, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); CHECK_THROWS_WITH(it2 > it3, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); @@ -620,14 +620,14 @@ TEST_CASE("iterators 2") { if (j.type() == json::value_t::object) { - CHECK_THROWS_AS(it1 >= it1, json::invalid_iterator&); - CHECK_THROWS_AS(it1 >= it2, json::invalid_iterator&); - CHECK_THROWS_AS(it2 >= it3, json::invalid_iterator&); - CHECK_THROWS_AS(it1 >= it3, json::invalid_iterator&); - CHECK_THROWS_AS(it1_c >= it1_c, json::invalid_iterator&); - CHECK_THROWS_AS(it1_c >= it2_c, json::invalid_iterator&); - CHECK_THROWS_AS(it2_c >= it3_c, json::invalid_iterator&); - CHECK_THROWS_AS(it1_c >= it3_c, json::invalid_iterator&); + CHECK_THROWS_AS(it1 >= it1, json::invalid_iterator); + CHECK_THROWS_AS(it1 >= it2, json::invalid_iterator); + CHECK_THROWS_AS(it2 >= it3, json::invalid_iterator); + CHECK_THROWS_AS(it1 >= it3, json::invalid_iterator); + CHECK_THROWS_AS(it1_c >= it1_c, json::invalid_iterator); + CHECK_THROWS_AS(it1_c >= it2_c, json::invalid_iterator); + CHECK_THROWS_AS(it2_c >= it3_c, json::invalid_iterator); + CHECK_THROWS_AS(it1_c >= it3_c, json::invalid_iterator); CHECK_THROWS_WITH(it1 >= it1, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); CHECK_THROWS_WITH(it1 >= it2, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); CHECK_THROWS_WITH(it2 >= it3, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); @@ -659,13 +659,13 @@ TEST_CASE("iterators 2") { if (j != k) { - CHECK_THROWS_AS(j.rbegin() == k.rbegin(), json::invalid_iterator&); - CHECK_THROWS_AS(j.crbegin() == k.crbegin(), json::invalid_iterator&); + CHECK_THROWS_AS(j.rbegin() == k.rbegin(), json::invalid_iterator); + CHECK_THROWS_AS(j.crbegin() == k.crbegin(), json::invalid_iterator); CHECK_THROWS_WITH(j.rbegin() == k.rbegin(), "[json.exception.invalid_iterator.212] cannot compare iterators of different containers"); CHECK_THROWS_WITH(j.crbegin() == k.crbegin(), "[json.exception.invalid_iterator.212] cannot compare iterators of different containers"); - CHECK_THROWS_AS(j.rbegin() < k.rbegin(), json::invalid_iterator&); - CHECK_THROWS_AS(j.crbegin() < k.crbegin(), json::invalid_iterator&); + CHECK_THROWS_AS(j.rbegin() < k.rbegin(), json::invalid_iterator); + CHECK_THROWS_AS(j.crbegin() < k.crbegin(), json::invalid_iterator); CHECK_THROWS_WITH(j.rbegin() < k.rbegin(), "[json.exception.invalid_iterator.212] cannot compare iterators of different containers"); CHECK_THROWS_WITH(j.crbegin() < k.crbegin(), "[json.exception.invalid_iterator.212] cannot compare iterators of different containers"); } @@ -686,62 +686,62 @@ TEST_CASE("iterators 2") { { auto it = j_object.rbegin(); - CHECK_THROWS_AS(it += 1, json::invalid_iterator&); + CHECK_THROWS_AS(it += 1, json::invalid_iterator); CHECK_THROWS_WITH(it += 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.crbegin(); - CHECK_THROWS_AS(it += 1, json::invalid_iterator&); + CHECK_THROWS_AS(it += 1, json::invalid_iterator); CHECK_THROWS_WITH(it += 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.rbegin(); - CHECK_THROWS_AS(it + 1, json::invalid_iterator&); + CHECK_THROWS_AS(it + 1, json::invalid_iterator); CHECK_THROWS_WITH(it + 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.crbegin(); - CHECK_THROWS_AS(it + 1, json::invalid_iterator&); + CHECK_THROWS_AS(it + 1, json::invalid_iterator); CHECK_THROWS_WITH(it + 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.rbegin(); - CHECK_THROWS_AS(1 + it, json::invalid_iterator&); + CHECK_THROWS_AS(1 + it, json::invalid_iterator); CHECK_THROWS_WITH(1 + it, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.crbegin(); - CHECK_THROWS_AS(1 + it, json::invalid_iterator&); + CHECK_THROWS_AS(1 + it, json::invalid_iterator); CHECK_THROWS_WITH(1 + it, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.rbegin(); - CHECK_THROWS_AS(it -= 1, json::invalid_iterator&); + CHECK_THROWS_AS(it -= 1, json::invalid_iterator); CHECK_THROWS_WITH(it -= 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.crbegin(); - CHECK_THROWS_AS(it -= 1, json::invalid_iterator&); + CHECK_THROWS_AS(it -= 1, json::invalid_iterator); CHECK_THROWS_WITH(it -= 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.rbegin(); - CHECK_THROWS_AS(it - 1, json::invalid_iterator&); + CHECK_THROWS_AS(it - 1, json::invalid_iterator); CHECK_THROWS_WITH(it - 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.crbegin(); - CHECK_THROWS_AS(it - 1, json::invalid_iterator&); + CHECK_THROWS_AS(it - 1, json::invalid_iterator); CHECK_THROWS_WITH(it - 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.rbegin(); - CHECK_THROWS_AS(it - it, json::invalid_iterator&); + CHECK_THROWS_AS(it - it, json::invalid_iterator); CHECK_THROWS_WITH(it - it, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.crbegin(); - CHECK_THROWS_AS(it - it, json::invalid_iterator&); + CHECK_THROWS_AS(it - it, json::invalid_iterator); CHECK_THROWS_WITH(it - it, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } } @@ -831,15 +831,15 @@ TEST_CASE("iterators 2") { { auto it = j_object.rbegin(); - CHECK_THROWS_AS(it[0], json::invalid_iterator&); - CHECK_THROWS_AS(it[1], json::invalid_iterator&); + CHECK_THROWS_AS(it[0], json::invalid_iterator); + CHECK_THROWS_AS(it[1], json::invalid_iterator); CHECK_THROWS_WITH(it[0], "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); CHECK_THROWS_WITH(it[1], "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.crbegin(); - CHECK_THROWS_AS(it[0], json::invalid_iterator&); - CHECK_THROWS_AS(it[1], json::invalid_iterator&); + CHECK_THROWS_AS(it[0], json::invalid_iterator); + CHECK_THROWS_AS(it[1], json::invalid_iterator); CHECK_THROWS_WITH(it[0], "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); CHECK_THROWS_WITH(it[1], "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } @@ -871,15 +871,15 @@ TEST_CASE("iterators 2") { { auto it = j_null.rbegin(); - CHECK_THROWS_AS(it[0], json::invalid_iterator&); - CHECK_THROWS_AS(it[1], json::invalid_iterator&); + CHECK_THROWS_AS(it[0], json::invalid_iterator); + CHECK_THROWS_AS(it[1], json::invalid_iterator); CHECK_THROWS_WITH(it[0], "[json.exception.invalid_iterator.214] cannot get value"); CHECK_THROWS_WITH(it[1], "[json.exception.invalid_iterator.214] cannot get value"); } { auto it = j_null.crbegin(); - CHECK_THROWS_AS(it[0], json::invalid_iterator&); - CHECK_THROWS_AS(it[1], json::invalid_iterator&); + CHECK_THROWS_AS(it[0], json::invalid_iterator); + CHECK_THROWS_AS(it[1], json::invalid_iterator); CHECK_THROWS_WITH(it[0], "[json.exception.invalid_iterator.214] cannot get value"); CHECK_THROWS_WITH(it[1], "[json.exception.invalid_iterator.214] cannot get value"); } @@ -890,13 +890,13 @@ TEST_CASE("iterators 2") { auto it = j_value.rbegin(); CHECK(it[0] == json(42)); - CHECK_THROWS_AS(it[1], json::invalid_iterator&); + CHECK_THROWS_AS(it[1], json::invalid_iterator); CHECK_THROWS_WITH(it[1], "[json.exception.invalid_iterator.214] cannot get value"); } { auto it = j_value.crbegin(); CHECK(it[0] == json(42)); - CHECK_THROWS_AS(it[1], json::invalid_iterator&); + CHECK_THROWS_AS(it[1], json::invalid_iterator); CHECK_THROWS_WITH(it[1], "[json.exception.invalid_iterator.214] cannot get value"); } } diff --git a/test/src/unit-json_patch.cpp b/test/src/unit-json_patch.cpp index 636fa2bc..9ab86ea4 100644 --- a/test/src/unit-json_patch.cpp +++ b/test/src/unit-json_patch.cpp @@ -75,7 +75,7 @@ TEST_CASE("JSON patch") json doc2 = R"({ "q": { "bar": 2 } })"_json; // because "a" does not exist. - CHECK_THROWS_AS(doc2.patch(patch), json::out_of_range&); + CHECK_THROWS_AS(doc2.patch(patch), json::out_of_range); CHECK_THROWS_WITH(doc2.patch(patch), "[json.exception.out_of_range.403] key 'a' not found"); } @@ -337,7 +337,7 @@ TEST_CASE("JSON patch") )"_json; // check that evaluation throws - CHECK_THROWS_AS(doc.patch(patch), json::other_error&); + CHECK_THROWS_AS(doc.patch(patch), json::other_error); CHECK_THROWS_WITH(doc.patch(patch), "[json.exception.other_error.501] unsuccessful: " + patch[0].dump()); } @@ -421,7 +421,7 @@ TEST_CASE("JSON patch") // references neither the root of the document, nor a member of // an existing object, nor a member of an existing array. - CHECK_THROWS_AS(doc.patch(patch), json::out_of_range&); + CHECK_THROWS_AS(doc.patch(patch), json::out_of_range); CHECK_THROWS_WITH(doc.patch(patch), "[json.exception.out_of_range.403] key 'baz' not found"); } @@ -478,7 +478,7 @@ TEST_CASE("JSON patch") )"_json; // check that evaluation throws - CHECK_THROWS_AS(doc.patch(patch), json::other_error&); + CHECK_THROWS_AS(doc.patch(patch), json::other_error); CHECK_THROWS_WITH(doc.patch(patch), "[json.exception.other_error.501] unsuccessful: " + patch[0].dump()); } @@ -668,7 +668,7 @@ TEST_CASE("JSON patch") { json j; json patch = {{"op", "add"}, {"path", ""}, {"value", 1}}; - CHECK_THROWS_AS(j.patch(patch), json::parse_error&); + CHECK_THROWS_AS(j.patch(patch), json::parse_error); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.parse_error.104] parse error: JSON patch must be an array of objects"); } @@ -677,7 +677,7 @@ TEST_CASE("JSON patch") { json j; json patch = {"op", "add", "path", "", "value", 1}; - CHECK_THROWS_AS(j.patch(patch), json::parse_error&); + CHECK_THROWS_AS(j.patch(patch), json::parse_error); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.parse_error.104] parse error: JSON patch must be an array of objects"); } @@ -686,7 +686,7 @@ TEST_CASE("JSON patch") { json j; json patch = {{{"foo", "bar"}}}; - CHECK_THROWS_AS(j.patch(patch), json::parse_error&); + CHECK_THROWS_AS(j.patch(patch), json::parse_error); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.parse_error.105] parse error: operation must have member 'op'"); } @@ -695,7 +695,7 @@ TEST_CASE("JSON patch") { json j; json patch = {{{"op", 1}}}; - CHECK_THROWS_AS(j.patch(patch), json::parse_error&); + CHECK_THROWS_AS(j.patch(patch), json::parse_error); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.parse_error.105] parse error: operation must have string member 'op'"); } @@ -704,7 +704,7 @@ TEST_CASE("JSON patch") { json j; json patch = {{{"op", "foo"}, {"path", ""}}}; - CHECK_THROWS_AS(j.patch(patch), json::parse_error&); + CHECK_THROWS_AS(j.patch(patch), json::parse_error); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.parse_error.105] parse error: operation value 'foo' is invalid"); } @@ -716,7 +716,7 @@ TEST_CASE("JSON patch") { json j; json patch = {{{"op", "add"}}}; - CHECK_THROWS_AS(j.patch(patch), json::parse_error&); + CHECK_THROWS_AS(j.patch(patch), json::parse_error); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.parse_error.105] parse error: operation 'add' must have member 'path'"); } @@ -725,7 +725,7 @@ TEST_CASE("JSON patch") { json j; json patch = {{{"op", "add"}, {"path", 1}}}; - CHECK_THROWS_AS(j.patch(patch), json::parse_error&); + CHECK_THROWS_AS(j.patch(patch), json::parse_error); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.parse_error.105] parse error: operation 'add' must have string member 'path'"); } @@ -734,7 +734,7 @@ TEST_CASE("JSON patch") { json j; json patch = {{{"op", "add"}, {"path", ""}}}; - CHECK_THROWS_AS(j.patch(patch), json::parse_error&); + CHECK_THROWS_AS(j.patch(patch), json::parse_error); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.parse_error.105] parse error: operation 'add' must have member 'value'"); } @@ -743,7 +743,7 @@ TEST_CASE("JSON patch") { json j = {1, 2}; json patch = {{{"op", "add"}, {"path", "/4"}, {"value", 4}}}; - CHECK_THROWS_AS(j.patch(patch), json::out_of_range&); + CHECK_THROWS_AS(j.patch(patch), json::out_of_range); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.out_of_range.401] array index 4 is out of range"); } @@ -755,7 +755,7 @@ TEST_CASE("JSON patch") { json j; json patch = {{{"op", "remove"}}}; - CHECK_THROWS_AS(j.patch(patch), json::parse_error&); + CHECK_THROWS_AS(j.patch(patch), json::parse_error); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.parse_error.105] parse error: operation 'remove' must have member 'path'"); } @@ -764,7 +764,7 @@ TEST_CASE("JSON patch") { json j; json patch = {{{"op", "remove"}, {"path", 1}}}; - CHECK_THROWS_AS(j.patch(patch), json::parse_error&); + CHECK_THROWS_AS(j.patch(patch), json::parse_error); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.parse_error.105] parse error: operation 'remove' must have string member 'path'"); } @@ -773,7 +773,7 @@ TEST_CASE("JSON patch") { json j = {1, 2, 3}; json patch = {{{"op", "remove"}, {"path", "/17"}}}; - CHECK_THROWS_AS(j.patch(patch), json::out_of_range&); + CHECK_THROWS_AS(j.patch(patch), json::out_of_range); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.out_of_range.401] array index 17 is out of range"); } @@ -782,7 +782,7 @@ TEST_CASE("JSON patch") { json j = {{"foo", 1}, {"bar", 2}}; json patch = {{{"op", "remove"}, {"path", "/baz"}}}; - CHECK_THROWS_AS(j.patch(patch), json::out_of_range&); + CHECK_THROWS_AS(j.patch(patch), json::out_of_range); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.out_of_range.403] key 'baz' not found"); } @@ -791,7 +791,7 @@ TEST_CASE("JSON patch") { json j = "string"; json patch = {{{"op", "remove"}, {"path", ""}}}; - CHECK_THROWS_AS(j.patch(patch), json::out_of_range&); + CHECK_THROWS_AS(j.patch(patch), json::out_of_range); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.out_of_range.405] JSON pointer has no parent"); } @@ -803,7 +803,7 @@ TEST_CASE("JSON patch") { json j; json patch = {{{"op", "replace"}}}; - CHECK_THROWS_AS(j.patch(patch), json::parse_error&); + CHECK_THROWS_AS(j.patch(patch), json::parse_error); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.parse_error.105] parse error: operation 'replace' must have member 'path'"); } @@ -812,7 +812,7 @@ TEST_CASE("JSON patch") { json j; json patch = {{{"op", "replace"}, {"path", 1}}}; - CHECK_THROWS_AS(j.patch(patch), json::parse_error&); + CHECK_THROWS_AS(j.patch(patch), json::parse_error); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.parse_error.105] parse error: operation 'replace' must have string member 'path'"); } @@ -821,7 +821,7 @@ TEST_CASE("JSON patch") { json j; json patch = {{{"op", "replace"}, {"path", ""}}}; - CHECK_THROWS_AS(j.patch(patch), json::parse_error&); + CHECK_THROWS_AS(j.patch(patch), json::parse_error); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.parse_error.105] parse error: operation 'replace' must have member 'value'"); } @@ -830,7 +830,7 @@ TEST_CASE("JSON patch") { json j = {1, 2, 3}; json patch = {{{"op", "replace"}, {"path", "/17"}, {"value", 19}}}; - CHECK_THROWS_AS(j.patch(patch), json::out_of_range&); + CHECK_THROWS_AS(j.patch(patch), json::out_of_range); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.out_of_range.401] array index 17 is out of range"); } @@ -839,7 +839,7 @@ TEST_CASE("JSON patch") { json j = {{"foo", 1}, {"bar", 2}}; json patch = {{{"op", "replace"}, {"path", "/baz"}, {"value", 3}}}; - CHECK_THROWS_AS(j.patch(patch), json::out_of_range&); + CHECK_THROWS_AS(j.patch(patch), json::out_of_range); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.out_of_range.403] key 'baz' not found"); } @@ -851,7 +851,7 @@ TEST_CASE("JSON patch") { json j; json patch = {{{"op", "move"}}}; - CHECK_THROWS_AS(j.patch(patch), json::parse_error&); + CHECK_THROWS_AS(j.patch(patch), json::parse_error); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.parse_error.105] parse error: operation 'move' must have member 'path'"); } @@ -860,7 +860,7 @@ TEST_CASE("JSON patch") { json j; json patch = {{{"op", "move"}, {"path", 1}}}; - CHECK_THROWS_AS(j.patch(patch), json::parse_error&); + CHECK_THROWS_AS(j.patch(patch), json::parse_error); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.parse_error.105] parse error: operation 'move' must have string member 'path'"); } @@ -869,7 +869,7 @@ TEST_CASE("JSON patch") { json j; json patch = {{{"op", "move"}, {"path", ""}}}; - CHECK_THROWS_AS(j.patch(patch), json::parse_error&); + CHECK_THROWS_AS(j.patch(patch), json::parse_error); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.parse_error.105] parse error: operation 'move' must have member 'from'"); } @@ -878,7 +878,7 @@ TEST_CASE("JSON patch") { json j; json patch = {{{"op", "move"}, {"path", ""}, {"from", 1}}}; - CHECK_THROWS_AS(j.patch(patch), json::parse_error&); + CHECK_THROWS_AS(j.patch(patch), json::parse_error); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.parse_error.105] parse error: operation 'move' must have string member 'from'"); } @@ -887,7 +887,7 @@ TEST_CASE("JSON patch") { json j = {1, 2, 3}; json patch = {{{"op", "move"}, {"path", "/0"}, {"from", "/5"}}}; - CHECK_THROWS_AS(j.patch(patch), json::out_of_range&); + CHECK_THROWS_AS(j.patch(patch), json::out_of_range); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.out_of_range.401] array index 5 is out of range"); } @@ -896,7 +896,7 @@ TEST_CASE("JSON patch") { json j = {{"foo", 1}, {"bar", 2}}; json patch = {{{"op", "move"}, {"path", "/baz"}, {"from", "/baz"}}}; - CHECK_THROWS_AS(j.patch(patch), json::out_of_range&); + CHECK_THROWS_AS(j.patch(patch), json::out_of_range); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.out_of_range.403] key 'baz' not found"); } @@ -908,7 +908,7 @@ TEST_CASE("JSON patch") { json j; json patch = {{{"op", "copy"}}}; - CHECK_THROWS_AS(j.patch(patch), json::parse_error&); + CHECK_THROWS_AS(j.patch(patch), json::parse_error); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.parse_error.105] parse error: operation 'copy' must have member 'path'"); } @@ -917,7 +917,7 @@ TEST_CASE("JSON patch") { json j; json patch = {{{"op", "copy"}, {"path", 1}}}; - CHECK_THROWS_AS(j.patch(patch), json::parse_error&); + CHECK_THROWS_AS(j.patch(patch), json::parse_error); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.parse_error.105] parse error: operation 'copy' must have string member 'path'"); } @@ -926,7 +926,7 @@ TEST_CASE("JSON patch") { json j; json patch = {{{"op", "copy"}, {"path", ""}}}; - CHECK_THROWS_AS(j.patch(patch), json::parse_error&); + CHECK_THROWS_AS(j.patch(patch), json::parse_error); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.parse_error.105] parse error: operation 'copy' must have member 'from'"); } @@ -935,7 +935,7 @@ TEST_CASE("JSON patch") { json j; json patch = {{{"op", "copy"}, {"path", ""}, {"from", 1}}}; - CHECK_THROWS_AS(j.patch(patch), json::parse_error&); + CHECK_THROWS_AS(j.patch(patch), json::parse_error); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.parse_error.105] parse error: operation 'copy' must have string member 'from'"); } @@ -944,7 +944,7 @@ TEST_CASE("JSON patch") { json j = {1, 2, 3}; json patch = {{{"op", "copy"}, {"path", "/0"}, {"from", "/5"}}}; - CHECK_THROWS_AS(j.patch(patch), json::out_of_range&); + CHECK_THROWS_AS(j.patch(patch), json::out_of_range); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.out_of_range.401] array index 5 is out of range"); } @@ -953,7 +953,7 @@ TEST_CASE("JSON patch") { json j = {{"foo", 1}, {"bar", 2}}; json patch = {{{"op", "copy"}, {"path", "/fob"}, {"from", "/baz"}}}; - CHECK_THROWS_AS(j.patch(patch), json::out_of_range&); + CHECK_THROWS_AS(j.patch(patch), json::out_of_range); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.out_of_range.403] key 'baz' not found"); } @@ -965,7 +965,7 @@ TEST_CASE("JSON patch") { json j; json patch = {{{"op", "test"}}}; - CHECK_THROWS_AS(j.patch(patch), json::parse_error&); + CHECK_THROWS_AS(j.patch(patch), json::parse_error); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.parse_error.105] parse error: operation 'test' must have member 'path'"); } @@ -974,7 +974,7 @@ TEST_CASE("JSON patch") { json j; json patch = {{{"op", "test"}, {"path", 1}}}; - CHECK_THROWS_AS(j.patch(patch), json::parse_error&); + CHECK_THROWS_AS(j.patch(patch), json::parse_error); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.parse_error.105] parse error: operation 'test' must have string member 'path'"); } @@ -983,7 +983,7 @@ TEST_CASE("JSON patch") { json j; json patch = {{{"op", "test"}, {"path", ""}}}; - CHECK_THROWS_AS(j.patch(patch), json::parse_error&); + CHECK_THROWS_AS(j.patch(patch), json::parse_error); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.parse_error.105] parse error: operation 'test' must have member 'value'"); } @@ -1177,7 +1177,7 @@ TEST_CASE("JSON patch") )"_json; // the test will fail - CHECK_THROWS_AS(doc.patch(patch), json::other_error&); + CHECK_THROWS_AS(doc.patch(patch), json::other_error); CHECK_THROWS_WITH(doc.patch(patch), "[json.exception.other_error.501] unsuccessful: " + patch[0].dump()); } } diff --git a/test/src/unit-json_pointer.cpp b/test/src/unit-json_pointer.cpp index ee55dc58..d4280049 100644 --- a/test/src/unit-json_pointer.cpp +++ b/test/src/unit-json_pointer.cpp @@ -36,23 +36,23 @@ TEST_CASE("JSON pointers") { SECTION("errors") { - CHECK_THROWS_AS(json::json_pointer("foo"), json::parse_error&); + CHECK_THROWS_AS(json::json_pointer("foo"), json::parse_error); CHECK_THROWS_WITH(json::json_pointer("foo"), "[json.exception.parse_error.107] parse error at 1: JSON pointer must be empty or begin with '/' - was: 'foo'"); - CHECK_THROWS_AS(json::json_pointer("/~~"), json::parse_error&); + CHECK_THROWS_AS(json::json_pointer("/~~"), json::parse_error); CHECK_THROWS_WITH(json::json_pointer("/~~"), "[json.exception.parse_error.108] parse error: escape character '~' must be followed with '0' or '1'"); - CHECK_THROWS_AS(json::json_pointer("/~"), json::parse_error&); + CHECK_THROWS_AS(json::json_pointer("/~"), json::parse_error); CHECK_THROWS_WITH(json::json_pointer("/~"), "[json.exception.parse_error.108] parse error: escape character '~' must be followed with '0' or '1'"); json::json_pointer p; - CHECK_THROWS_AS(p.top(), json::out_of_range&); + CHECK_THROWS_AS(p.top(), json::out_of_range); CHECK_THROWS_WITH(p.top(), "[json.exception.out_of_range.405] JSON pointer has no parent"); - CHECK_THROWS_AS(p.pop_back(), json::out_of_range&); + CHECK_THROWS_AS(p.pop_back(), json::out_of_range); CHECK_THROWS_WITH(p.pop_back(), "[json.exception.out_of_range.405] JSON pointer has no parent"); } @@ -126,10 +126,10 @@ TEST_CASE("JSON pointers") // unresolved access json j_primitive = 1; - CHECK_THROWS_AS(j_primitive["/foo"_json_pointer], json::out_of_range&); + CHECK_THROWS_AS(j_primitive["/foo"_json_pointer], json::out_of_range); CHECK_THROWS_WITH(j_primitive["/foo"_json_pointer], "[json.exception.out_of_range.404] unresolved reference token 'foo'"); - CHECK_THROWS_AS(j_primitive.at("/foo"_json_pointer), json::out_of_range&); + CHECK_THROWS_AS(j_primitive.at("/foo"_json_pointer), json::out_of_range); CHECK_THROWS_WITH(j_primitive.at("/foo"_json_pointer), "[json.exception.out_of_range.404] unresolved reference token 'foo'"); } @@ -189,16 +189,16 @@ TEST_CASE("JSON pointers") CHECK(j[json::json_pointer("/m~0n")] == j["m~n"]); // unescaped access - CHECK_THROWS_AS(j.at(json::json_pointer("/a/b")), json::out_of_range&); + CHECK_THROWS_AS(j.at(json::json_pointer("/a/b")), json::out_of_range); CHECK_THROWS_WITH(j.at(json::json_pointer("/a/b")), "[json.exception.out_of_range.403] key 'a' not found"); // unresolved access const json j_primitive = 1; - CHECK_THROWS_AS(j_primitive["/foo"_json_pointer], json::out_of_range&); + CHECK_THROWS_AS(j_primitive["/foo"_json_pointer], json::out_of_range); CHECK_THROWS_WITH(j_primitive["/foo"_json_pointer], "[json.exception.out_of_range.404] unresolved reference token 'foo'"); - CHECK_THROWS_AS(j_primitive.at("/foo"_json_pointer), json::out_of_range&); + CHECK_THROWS_AS(j_primitive.at("/foo"_json_pointer), json::out_of_range); CHECK_THROWS_WITH(j_primitive.at("/foo"_json_pointer), "[json.exception.out_of_range.404] unresolved reference token 'foo'"); } @@ -255,35 +255,35 @@ TEST_CASE("JSON pointers") CHECK(j == json({1, 13, 3, 33, nullptr, 55})); // error with leading 0 - CHECK_THROWS_AS(j["/01"_json_pointer], json::parse_error&); + CHECK_THROWS_AS(j["/01"_json_pointer], json::parse_error); CHECK_THROWS_WITH(j["/01"_json_pointer], "[json.exception.parse_error.106] parse error: array index '01' must not begin with '0'"); - CHECK_THROWS_AS(j_const["/01"_json_pointer], json::parse_error&); + CHECK_THROWS_AS(j_const["/01"_json_pointer], json::parse_error); CHECK_THROWS_WITH(j_const["/01"_json_pointer], "[json.exception.parse_error.106] parse error: array index '01' must not begin with '0'"); - CHECK_THROWS_AS(j.at("/01"_json_pointer), json::parse_error&); + CHECK_THROWS_AS(j.at("/01"_json_pointer), json::parse_error); CHECK_THROWS_WITH(j.at("/01"_json_pointer), "[json.exception.parse_error.106] parse error: array index '01' must not begin with '0'"); - CHECK_THROWS_AS(j_const.at("/01"_json_pointer), json::parse_error&); + CHECK_THROWS_AS(j_const.at("/01"_json_pointer), json::parse_error); CHECK_THROWS_WITH(j_const.at("/01"_json_pointer), "[json.exception.parse_error.106] parse error: array index '01' must not begin with '0'"); // error with incorrect numbers - CHECK_THROWS_AS(j["/one"_json_pointer] = 1, json::parse_error&); + CHECK_THROWS_AS(j["/one"_json_pointer] = 1, json::parse_error); CHECK_THROWS_WITH(j["/one"_json_pointer] = 1, "[json.exception.parse_error.109] parse error: array index 'one' is not a number"); - CHECK_THROWS_AS(j_const["/one"_json_pointer] == 1, json::parse_error&); + CHECK_THROWS_AS(j_const["/one"_json_pointer] == 1, json::parse_error); CHECK_THROWS_WITH(j_const["/one"_json_pointer] == 1, "[json.exception.parse_error.109] parse error: array index 'one' is not a number"); - CHECK_THROWS_AS(j.at("/one"_json_pointer) = 1, json::parse_error&); + CHECK_THROWS_AS(j.at("/one"_json_pointer) = 1, json::parse_error); CHECK_THROWS_WITH(j.at("/one"_json_pointer) = 1, "[json.exception.parse_error.109] parse error: array index 'one' is not a number"); - CHECK_THROWS_AS(j_const.at("/one"_json_pointer) == 1, json::parse_error&); + CHECK_THROWS_AS(j_const.at("/one"_json_pointer) == 1, json::parse_error); CHECK_THROWS_WITH(j_const.at("/one"_json_pointer) == 1, "[json.exception.parse_error.109] parse error: array index 'one' is not a number"); - CHECK_THROWS_AS(json({{"/list/0", 1}, {"/list/1", 2}, {"/list/three", 3}}).unflatten(), json::parse_error&); + CHECK_THROWS_AS(json({{"/list/0", 1}, {"/list/1", 2}, {"/list/three", 3}}).unflatten(), json::parse_error); CHECK_THROWS_WITH(json({{"/list/0", 1}, {"/list/1", 2}, {"/list/three", 3}}).unflatten(), "[json.exception.parse_error.109] parse error: array index 'three' is not a number"); @@ -292,15 +292,15 @@ TEST_CASE("JSON pointers") CHECK(j == json({1, 13, 3, 33, nullptr, 55, 99})); // error when using "-" in const object - CHECK_THROWS_AS(j_const["/-"_json_pointer], json::out_of_range&); + CHECK_THROWS_AS(j_const["/-"_json_pointer], json::out_of_range); CHECK_THROWS_WITH(j_const["/-"_json_pointer], "[json.exception.out_of_range.402] array index '-' (3) is out of range"); // error when using "-" with at - CHECK_THROWS_AS(j.at("/-"_json_pointer), json::out_of_range&); + CHECK_THROWS_AS(j.at("/-"_json_pointer), json::out_of_range); CHECK_THROWS_WITH(j.at("/-"_json_pointer), "[json.exception.out_of_range.402] array index '-' (7) is out of range"); - CHECK_THROWS_AS(j_const.at("/-"_json_pointer), json::out_of_range&); + CHECK_THROWS_AS(j_const.at("/-"_json_pointer), json::out_of_range); CHECK_THROWS_WITH(j_const.at("/-"_json_pointer), "[json.exception.out_of_range.402] array index '-' (3) is out of range"); } @@ -315,20 +315,20 @@ TEST_CASE("JSON pointers") CHECK(j["/2"_json_pointer] == j[2]); // assign to nonexisting index - CHECK_THROWS_AS(j.at("/3"_json_pointer), json::out_of_range&); + CHECK_THROWS_AS(j.at("/3"_json_pointer), json::out_of_range); CHECK_THROWS_WITH(j.at("/3"_json_pointer), "[json.exception.out_of_range.401] array index 3 is out of range"); // assign to nonexisting index (with gap) - CHECK_THROWS_AS(j.at("/5"_json_pointer), json::out_of_range&); + CHECK_THROWS_AS(j.at("/5"_json_pointer), json::out_of_range); CHECK_THROWS_WITH(j.at("/5"_json_pointer), "[json.exception.out_of_range.401] array index 5 is out of range"); // assign to "-" - CHECK_THROWS_AS(j["/-"_json_pointer], json::out_of_range&); + CHECK_THROWS_AS(j["/-"_json_pointer], json::out_of_range); CHECK_THROWS_WITH(j["/-"_json_pointer], "[json.exception.out_of_range.402] array index '-' (3) is out of range"); - CHECK_THROWS_AS(j.at("/-"_json_pointer), json::out_of_range&); + CHECK_THROWS_AS(j.at("/-"_json_pointer), json::out_of_range); CHECK_THROWS_WITH(j.at("/-"_json_pointer), "[json.exception.out_of_range.402] array index '-' (3) is out of range"); } @@ -386,18 +386,18 @@ TEST_CASE("JSON pointers") CHECK(j_flatten.unflatten() == j); // error for nonobjects - CHECK_THROWS_AS(json(1).unflatten(), json::type_error&); + CHECK_THROWS_AS(json(1).unflatten(), json::type_error); CHECK_THROWS_WITH(json(1).unflatten(), "[json.exception.type_error.314] only objects can be unflattened"); // error for nonprimitve values - CHECK_THROWS_AS(json({{"/1", {1, 2, 3}}}).unflatten(), json::type_error&); + CHECK_THROWS_AS(json({{"/1", {1, 2, 3}}}).unflatten(), json::type_error); CHECK_THROWS_WITH(json({{"/1", {1, 2, 3}}}).unflatten(), "[json.exception.type_error.315] values in object must be primitive"); // error for conflicting values json j_error = {{"", 42}, {"/foo", 17}}; - CHECK_THROWS_AS(j_error.unflatten(), json::type_error&); + CHECK_THROWS_AS(j_error.unflatten(), json::type_error); CHECK_THROWS_WITH(j_error.unflatten(), "[json.exception.type_error.313] invalid value to unflatten"); diff --git a/test/src/unit-modifiers.cpp b/test/src/unit-modifiers.cpp index 01dfa415..f0eb09c6 100644 --- a/test/src/unit-modifiers.cpp +++ b/test/src/unit-modifiers.cpp @@ -172,7 +172,7 @@ TEST_CASE("modifiers") SECTION("other type") { json j = 1; - CHECK_THROWS_AS(j.push_back("Hello"), json::type_error&); + CHECK_THROWS_AS(j.push_back("Hello"), json::type_error); CHECK_THROWS_WITH(j.push_back("Hello"), "[json.exception.type_error.308] cannot use push_back() with number"); } } @@ -202,7 +202,7 @@ TEST_CASE("modifiers") { json j = 1; json k("Hello"); - CHECK_THROWS_AS(j.push_back(k), json::type_error&); + CHECK_THROWS_AS(j.push_back(k), json::type_error); CHECK_THROWS_WITH(j.push_back(k), "[json.exception.type_error.308] cannot use push_back() with number"); } } @@ -235,7 +235,7 @@ TEST_CASE("modifiers") { json j = 1; json k("Hello"); - CHECK_THROWS_AS(j.push_back(json::object_t::value_type({"one", 1})), json::type_error&); + CHECK_THROWS_AS(j.push_back(json::object_t::value_type({"one", 1})), json::type_error); CHECK_THROWS_WITH(j.push_back(json::object_t::value_type({"one", 1})), "[json.exception.type_error.308] cannot use push_back() with number"); } @@ -272,11 +272,11 @@ TEST_CASE("modifiers") CHECK(j == json({{"key1", 1}, {"key2", "bar"}})); // invalid values (no string/val pair) - CHECK_THROWS_AS(j.push_back({1}), json::type_error&); + CHECK_THROWS_AS(j.push_back({1}), json::type_error); CHECK_THROWS_WITH(j.push_back({1}), "[json.exception.type_error.308] cannot use push_back() with object"); - CHECK_THROWS_AS(j.push_back({1, 2}), json::type_error&); + CHECK_THROWS_AS(j.push_back({1, 2}), json::type_error); CHECK_THROWS_WITH(j.push_back({1, 2}), "[json.exception.type_error.308] cannot use push_back() with object"); - CHECK_THROWS_AS(j.push_back({1, 2, 3, 4}), json::type_error&); + CHECK_THROWS_AS(j.push_back({1, 2, 3, 4}), json::type_error); CHECK_THROWS_WITH(j.push_back({1, 2, 3, 4}), "[json.exception.type_error.308] cannot use push_back() with object"); } } @@ -315,7 +315,7 @@ TEST_CASE("modifiers") SECTION("other type") { json j = 1; - CHECK_THROWS_AS(j.emplace_back("Hello"), json::type_error&); + CHECK_THROWS_AS(j.emplace_back("Hello"), json::type_error); CHECK_THROWS_WITH(j.emplace_back("Hello"), "[json.exception.type_error.311] cannot use emplace_back() with number"); } @@ -375,7 +375,7 @@ TEST_CASE("modifiers") SECTION("other type") { json j = 1; - CHECK_THROWS_AS(j.emplace("foo", "bar"), json::type_error&); + CHECK_THROWS_AS(j.emplace("foo", "bar"), json::type_error); CHECK_THROWS_WITH(j.emplace("foo", "bar"), "[json.exception.type_error.311] cannot use emplace() with number"); } @@ -407,7 +407,7 @@ TEST_CASE("modifiers") SECTION("other type") { json j = 1; - CHECK_THROWS_AS(j += "Hello", json::type_error&); + CHECK_THROWS_AS(j += "Hello", json::type_error); CHECK_THROWS_WITH(j += "Hello", "[json.exception.type_error.308] cannot use push_back() with number"); } } @@ -437,7 +437,7 @@ TEST_CASE("modifiers") { json j = 1; json k("Hello"); - CHECK_THROWS_AS(j += k, json::type_error&); + CHECK_THROWS_AS(j += k, json::type_error); CHECK_THROWS_WITH(j += k, "[json.exception.type_error.308] cannot use push_back() with number"); } } @@ -470,7 +470,7 @@ TEST_CASE("modifiers") { json j = 1; json k("Hello"); - CHECK_THROWS_AS(j += json::object_t::value_type({"one", 1}), json::type_error&); + CHECK_THROWS_AS(j += json::object_t::value_type({"one", 1}), json::type_error); CHECK_THROWS_WITH(j += json::object_t::value_type({"one", 1}), "[json.exception.type_error.308] cannot use push_back() with number"); } @@ -507,7 +507,7 @@ TEST_CASE("modifiers") CHECK(j == json({{"key1", 1}, {"key2", "bar"}})); json k = {{"key1", 1}}; - CHECK_THROWS_AS((k += {1, 2, 3, 4}), json::type_error&); + CHECK_THROWS_AS((k += {1, 2, 3, 4}), json::type_error); CHECK_THROWS_WITH((k += {1, 2, 3, 4}), "[json.exception.type_error.308] cannot use push_back() with object"); } } @@ -644,9 +644,9 @@ TEST_CASE("modifiers") json j_other_array2 = {"first", "second"}; CHECK_THROWS_AS(j_array.insert(j_array.end(), j_array.begin(), j_array.end()), - json::invalid_iterator&); + json::invalid_iterator); CHECK_THROWS_AS(j_array.insert(j_array.end(), j_other_array.begin(), j_other_array2.end()), - json::invalid_iterator&); + json::invalid_iterator); CHECK_THROWS_WITH(j_array.insert(j_array.end(), j_array.begin(), j_array.end()), "[json.exception.invalid_iterator.211] passed iterators may not belong to container"); @@ -676,9 +676,9 @@ TEST_CASE("modifiers") { json j_other_array2 = {"first", "second"}; - CHECK_THROWS_AS(j_array.insert(j_object2.begin(), j_object2.end()), json::type_error&); - CHECK_THROWS_AS(j_object1.insert(j_object1.begin(), j_object2.end()), json::invalid_iterator&); - CHECK_THROWS_AS(j_object1.insert(j_array.begin(), j_array.end()), json::invalid_iterator&); + CHECK_THROWS_AS(j_array.insert(j_object2.begin(), j_object2.end()), json::type_error); + CHECK_THROWS_AS(j_object1.insert(j_object1.begin(), j_object2.end()), json::invalid_iterator); + CHECK_THROWS_AS(j_object1.insert(j_array.begin(), j_array.end()), json::invalid_iterator); CHECK_THROWS_WITH(j_array.insert(j_object2.begin(), j_object2.end()), "[json.exception.type_error.309] cannot use insert() with array"); @@ -724,11 +724,11 @@ TEST_CASE("modifiers") // pass iterator to a different array json j_another_array = {1, 2}; json j_yet_another_array = {"first", "second"}; - CHECK_THROWS_AS(j_array.insert(j_another_array.end(), 10), json::invalid_iterator&); - CHECK_THROWS_AS(j_array.insert(j_another_array.end(), j_value), json::invalid_iterator&); - CHECK_THROWS_AS(j_array.insert(j_another_array.end(), 10, 11), json::invalid_iterator&); - CHECK_THROWS_AS(j_array.insert(j_another_array.end(), j_yet_another_array.begin(), j_yet_another_array.end()), json::invalid_iterator&); - CHECK_THROWS_AS(j_array.insert(j_another_array.end(), {1, 2, 3, 4}), json::invalid_iterator&); + CHECK_THROWS_AS(j_array.insert(j_another_array.end(), 10), json::invalid_iterator); + CHECK_THROWS_AS(j_array.insert(j_another_array.end(), j_value), json::invalid_iterator); + CHECK_THROWS_AS(j_array.insert(j_another_array.end(), 10, 11), json::invalid_iterator); + CHECK_THROWS_AS(j_array.insert(j_another_array.end(), j_yet_another_array.begin(), j_yet_another_array.end()), json::invalid_iterator); + CHECK_THROWS_AS(j_array.insert(j_another_array.end(), {1, 2, 3, 4}), json::invalid_iterator); CHECK_THROWS_WITH(j_array.insert(j_another_array.end(), 10), "[json.exception.invalid_iterator.202] iterator does not fit current value"); @@ -747,12 +747,12 @@ TEST_CASE("modifiers") // call insert on a non-array type json j_nonarray = 3; json j_yet_another_array = {"first", "second"}; - CHECK_THROWS_AS(j_nonarray.insert(j_nonarray.end(), 10), json::type_error&); - CHECK_THROWS_AS(j_nonarray.insert(j_nonarray.end(), j_value), json::type_error&); - CHECK_THROWS_AS(j_nonarray.insert(j_nonarray.end(), 10, 11), json::type_error&); + CHECK_THROWS_AS(j_nonarray.insert(j_nonarray.end(), 10), json::type_error); + CHECK_THROWS_AS(j_nonarray.insert(j_nonarray.end(), j_value), json::type_error); + CHECK_THROWS_AS(j_nonarray.insert(j_nonarray.end(), 10, 11), json::type_error); CHECK_THROWS_AS(j_nonarray.insert(j_nonarray.end(), j_yet_another_array.begin(), - j_yet_another_array.end()), json::type_error&); - CHECK_THROWS_AS(j_nonarray.insert(j_nonarray.end(), {1, 2, 3, 4}), json::type_error&); + j_yet_another_array.end()), json::type_error); + CHECK_THROWS_AS(j_nonarray.insert(j_nonarray.end(), {1, 2, 3, 4}), json::type_error); CHECK_THROWS_WITH(j_nonarray.insert(j_nonarray.end(), 10), "[json.exception.type_error.309] cannot use insert() with number"); CHECK_THROWS_WITH(j_nonarray.insert(j_nonarray.end(), j_value), "[json.exception.type_error.309] cannot use insert() with number"); @@ -784,10 +784,10 @@ TEST_CASE("modifiers") SECTION("wrong types") { - CHECK_THROWS_AS(j_array.update(j_object1), json::type_error&); + CHECK_THROWS_AS(j_array.update(j_object1), json::type_error); CHECK_THROWS_WITH(j_array.update(j_object1), "[json.exception.type_error.312] cannot use update() with array"); - CHECK_THROWS_AS(j_object1.update(j_array), json::type_error&); + CHECK_THROWS_AS(j_object1.update(j_array), json::type_error); CHECK_THROWS_WITH(j_object1.update(j_array), "[json.exception.type_error.312] cannot use update() with array"); } } @@ -814,9 +814,9 @@ TEST_CASE("modifiers") { json j_other_array2 = {"first", "second"}; - CHECK_THROWS_AS(j_array.update(j_object2.begin(), j_object2.end()), json::type_error&); - CHECK_THROWS_AS(j_object1.update(j_object1.begin(), j_object2.end()), json::invalid_iterator&); - CHECK_THROWS_AS(j_object1.update(j_array.begin(), j_array.end()), json::invalid_iterator&); + CHECK_THROWS_AS(j_array.update(j_object2.begin(), j_object2.end()), json::type_error); + CHECK_THROWS_AS(j_object1.update(j_object1.begin(), j_object2.end()), json::invalid_iterator); + CHECK_THROWS_AS(j_object1.update(j_array.begin(), j_array.end()), json::invalid_iterator); CHECK_THROWS_WITH(j_array.update(j_object2.begin(), j_object2.end()), "[json.exception.type_error.312] cannot use update() with array"); @@ -876,7 +876,7 @@ TEST_CASE("modifiers") json j = 17; json::array_t a = {"foo", "bar", "baz"}; - CHECK_THROWS_AS(j.swap(a), json::type_error&); + CHECK_THROWS_AS(j.swap(a), json::type_error); CHECK_THROWS_WITH(j.swap(a), "[json.exception.type_error.310] cannot use swap() with number"); } } @@ -902,7 +902,7 @@ TEST_CASE("modifiers") json j = 17; json::object_t o = {{"cow", "Kuh"}, {"chicken", "Huhn"}}; - CHECK_THROWS_AS(j.swap(o), json::type_error&); + CHECK_THROWS_AS(j.swap(o), json::type_error); CHECK_THROWS_WITH(j.swap(o), "[json.exception.type_error.310] cannot use swap() with number"); } } @@ -928,7 +928,7 @@ TEST_CASE("modifiers") json j = 17; json::string_t s = "Hallo Welt"; - CHECK_THROWS_AS(j.swap(s), json::type_error&); + CHECK_THROWS_AS(j.swap(s), json::type_error); CHECK_THROWS_WITH(j.swap(s), "[json.exception.type_error.310] cannot use swap() with number"); } } diff --git a/test/src/unit-msgpack.cpp b/test/src/unit-msgpack.cpp index 148bb180..c363069f 100644 --- a/test/src/unit-msgpack.cpp +++ b/test/src/unit-msgpack.cpp @@ -1016,28 +1016,28 @@ TEST_CASE("MessagePack") { SECTION("empty byte vector") { - CHECK_THROWS_AS(json::from_msgpack(std::vector()), json::parse_error&); + CHECK_THROWS_AS(json::from_msgpack(std::vector()), json::parse_error); CHECK_THROWS_WITH(json::from_msgpack(std::vector()), "[json.exception.parse_error.110] parse error at 1: unexpected end of input"); } SECTION("too short byte vector") { - CHECK_THROWS_AS(json::from_msgpack(std::vector({0xcc})), json::parse_error&); - CHECK_THROWS_AS(json::from_msgpack(std::vector({0xcd})), json::parse_error&); - CHECK_THROWS_AS(json::from_msgpack(std::vector({0xcd, 0x00})), json::parse_error&); - CHECK_THROWS_AS(json::from_msgpack(std::vector({0xce})), json::parse_error&); - CHECK_THROWS_AS(json::from_msgpack(std::vector({0xce, 0x00})), json::parse_error&); - CHECK_THROWS_AS(json::from_msgpack(std::vector({0xce, 0x00, 0x00})), json::parse_error&); - CHECK_THROWS_AS(json::from_msgpack(std::vector({0xce, 0x00, 0x00, 0x00})), json::parse_error&); - CHECK_THROWS_AS(json::from_msgpack(std::vector({0xcf})), json::parse_error&); - CHECK_THROWS_AS(json::from_msgpack(std::vector({0xcf, 0x00})), json::parse_error&); - CHECK_THROWS_AS(json::from_msgpack(std::vector({0xcf, 0x00, 0x00})), json::parse_error&); - CHECK_THROWS_AS(json::from_msgpack(std::vector({0xcf, 0x00, 0x00, 0x00})), json::parse_error&); - CHECK_THROWS_AS(json::from_msgpack(std::vector({0xcf, 0x00, 0x00, 0x00, 0x00})), json::parse_error&); - CHECK_THROWS_AS(json::from_msgpack(std::vector({0xcf, 0x00, 0x00, 0x00, 0x00, 0x00})), json::parse_error&); - CHECK_THROWS_AS(json::from_msgpack(std::vector({0xcf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})), json::parse_error&); - CHECK_THROWS_AS(json::from_msgpack(std::vector({0xcf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})), json::parse_error&); + CHECK_THROWS_AS(json::from_msgpack(std::vector({0xcc})), json::parse_error); + CHECK_THROWS_AS(json::from_msgpack(std::vector({0xcd})), json::parse_error); + CHECK_THROWS_AS(json::from_msgpack(std::vector({0xcd, 0x00})), json::parse_error); + CHECK_THROWS_AS(json::from_msgpack(std::vector({0xce})), json::parse_error); + CHECK_THROWS_AS(json::from_msgpack(std::vector({0xce, 0x00})), json::parse_error); + CHECK_THROWS_AS(json::from_msgpack(std::vector({0xce, 0x00, 0x00})), json::parse_error); + CHECK_THROWS_AS(json::from_msgpack(std::vector({0xce, 0x00, 0x00, 0x00})), json::parse_error); + CHECK_THROWS_AS(json::from_msgpack(std::vector({0xcf})), json::parse_error); + CHECK_THROWS_AS(json::from_msgpack(std::vector({0xcf, 0x00})), json::parse_error); + CHECK_THROWS_AS(json::from_msgpack(std::vector({0xcf, 0x00, 0x00})), json::parse_error); + CHECK_THROWS_AS(json::from_msgpack(std::vector({0xcf, 0x00, 0x00, 0x00})), json::parse_error); + CHECK_THROWS_AS(json::from_msgpack(std::vector({0xcf, 0x00, 0x00, 0x00, 0x00})), json::parse_error); + CHECK_THROWS_AS(json::from_msgpack(std::vector({0xcf, 0x00, 0x00, 0x00, 0x00, 0x00})), json::parse_error); + CHECK_THROWS_AS(json::from_msgpack(std::vector({0xcf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})), json::parse_error); + CHECK_THROWS_AS(json::from_msgpack(std::vector({0xcf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})), json::parse_error); CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xcc})), "[json.exception.parse_error.110] parse error at 2: unexpected end of input"); @@ -1075,10 +1075,10 @@ TEST_CASE("MessagePack") { SECTION("concrete examples") { - CHECK_THROWS_AS(json::from_msgpack(std::vector({0xc1})), json::parse_error&); + CHECK_THROWS_AS(json::from_msgpack(std::vector({0xc1})), json::parse_error); CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xc1})), "[json.exception.parse_error.112] parse error at 1: error reading MessagePack; last byte: 0xC1"); - CHECK_THROWS_AS(json::from_msgpack(std::vector({0xc6})), json::parse_error&); + CHECK_THROWS_AS(json::from_msgpack(std::vector({0xc6})), json::parse_error); CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xc6})), "[json.exception.parse_error.112] parse error at 1: error reading MessagePack; last byte: 0xC6"); } @@ -1097,14 +1097,14 @@ TEST_CASE("MessagePack") 0xd4, 0xd5, 0xd6, 0xd7, 0xd8 }) { - CHECK_THROWS_AS(json::from_msgpack(std::vector({static_cast(byte)})), json::parse_error&); + CHECK_THROWS_AS(json::from_msgpack(std::vector({static_cast(byte)})), json::parse_error); } } } SECTION("invalid string in map") { - CHECK_THROWS_AS(json::from_msgpack(std::vector({0x81, 0xff, 0x01})), json::parse_error&); + CHECK_THROWS_AS(json::from_msgpack(std::vector({0x81, 0xff, 0x01})), json::parse_error); CHECK_THROWS_WITH(json::from_msgpack(std::vector({0x81, 0xff, 0x01})), "[json.exception.parse_error.113] parse error at 2: expected a MessagePack string; last byte: 0xFF"); } @@ -1120,7 +1120,7 @@ TEST_CASE("MessagePack") SECTION("strict mode") { - CHECK_THROWS_AS(json::from_msgpack(vec), json::parse_error&); + CHECK_THROWS_AS(json::from_msgpack(vec), json::parse_error); CHECK_THROWS_WITH(json::from_msgpack(vec), "[json.exception.parse_error.110] parse error at 2: expected end of input"); } diff --git a/test/src/unit-readme.cpp b/test/src/unit-readme.cpp index 1ce6ee1d..8d126824 100644 --- a/test/src/unit-readme.cpp +++ b/test/src/unit-readme.cpp @@ -31,6 +31,7 @@ SOFTWARE. #include "json.hpp" using nlohmann::json; +#include #include #include #include diff --git a/test/src/unit-reference_access.cpp b/test/src/unit-reference_access.cpp index c05ae723..2e1759d6 100644 --- a/test/src/unit-reference_access.cpp +++ b/test/src/unit-reference_access.cpp @@ -64,22 +64,22 @@ TEST_CASE("reference access") // check if mismatching references throw correctly CHECK_NOTHROW(value.get_ref()); - CHECK_THROWS_AS(value.get_ref(), json::type_error&); + CHECK_THROWS_AS(value.get_ref(), json::type_error); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is object"); - CHECK_THROWS_AS(value.get_ref(), json::type_error&); + CHECK_THROWS_AS(value.get_ref(), json::type_error); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is object"); - CHECK_THROWS_AS(value.get_ref(), json::type_error&); + CHECK_THROWS_AS(value.get_ref(), json::type_error); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is object"); - CHECK_THROWS_AS(value.get_ref(), json::type_error&); + CHECK_THROWS_AS(value.get_ref(), json::type_error); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is object"); - CHECK_THROWS_AS(value.get_ref(), json::type_error&); + CHECK_THROWS_AS(value.get_ref(), json::type_error); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is object"); - CHECK_THROWS_AS(value.get_ref(), json::type_error&); + CHECK_THROWS_AS(value.get_ref(), json::type_error); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is object"); } @@ -113,23 +113,23 @@ TEST_CASE("reference access") CHECK(p2 == value.get()); // check if mismatching references throw correctly - CHECK_THROWS_AS(value.get_ref(), json::type_error&); + CHECK_THROWS_AS(value.get_ref(), json::type_error); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is array"); CHECK_NOTHROW(value.get_ref()); - CHECK_THROWS_AS(value.get_ref(), json::type_error&); + CHECK_THROWS_AS(value.get_ref(), json::type_error); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is array"); - CHECK_THROWS_AS(value.get_ref(), json::type_error&); + CHECK_THROWS_AS(value.get_ref(), json::type_error); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is array"); - CHECK_THROWS_AS(value.get_ref(), json::type_error&); + CHECK_THROWS_AS(value.get_ref(), json::type_error); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is array"); - CHECK_THROWS_AS(value.get_ref(), json::type_error&); + CHECK_THROWS_AS(value.get_ref(), json::type_error); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is array"); - CHECK_THROWS_AS(value.get_ref(), json::type_error&); + CHECK_THROWS_AS(value.get_ref(), json::type_error); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is array"); } @@ -149,23 +149,23 @@ TEST_CASE("reference access") CHECK(p2 == value.get()); // check if mismatching references throw correctly - CHECK_THROWS_AS(value.get_ref(), json::type_error&); + CHECK_THROWS_AS(value.get_ref(), json::type_error); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is string"); - CHECK_THROWS_AS(value.get_ref(), json::type_error&); + CHECK_THROWS_AS(value.get_ref(), json::type_error); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is string"); CHECK_NOTHROW(value.get_ref()); - CHECK_THROWS_AS(value.get_ref(), json::type_error&); + CHECK_THROWS_AS(value.get_ref(), json::type_error); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is string"); - CHECK_THROWS_AS(value.get_ref(), json::type_error&); + CHECK_THROWS_AS(value.get_ref(), json::type_error); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is string"); - CHECK_THROWS_AS(value.get_ref(), json::type_error&); + CHECK_THROWS_AS(value.get_ref(), json::type_error); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is string"); - CHECK_THROWS_AS(value.get_ref(), json::type_error&); + CHECK_THROWS_AS(value.get_ref(), json::type_error); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is string"); } @@ -185,23 +185,23 @@ TEST_CASE("reference access") CHECK(p2 == value.get()); // check if mismatching references throw correctly - CHECK_THROWS_AS(value.get_ref(), json::type_error&); + CHECK_THROWS_AS(value.get_ref(), json::type_error); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is boolean"); - CHECK_THROWS_AS(value.get_ref(), json::type_error&); + CHECK_THROWS_AS(value.get_ref(), json::type_error); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is boolean"); - CHECK_THROWS_AS(value.get_ref(), json::type_error&); + CHECK_THROWS_AS(value.get_ref(), json::type_error); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is boolean"); CHECK_NOTHROW(value.get_ref()); - CHECK_THROWS_AS(value.get_ref(), json::type_error&); + CHECK_THROWS_AS(value.get_ref(), json::type_error); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is boolean"); - CHECK_THROWS_AS(value.get_ref(), json::type_error&); + CHECK_THROWS_AS(value.get_ref(), json::type_error); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is boolean"); - CHECK_THROWS_AS(value.get_ref(), json::type_error&); + CHECK_THROWS_AS(value.get_ref(), json::type_error); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is boolean"); } @@ -221,23 +221,23 @@ TEST_CASE("reference access") CHECK(p2 == value.get()); // check if mismatching references throw correctly - CHECK_THROWS_AS(value.get_ref(), json::type_error&); + CHECK_THROWS_AS(value.get_ref(), json::type_error); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number"); - CHECK_THROWS_AS(value.get_ref(), json::type_error&); + CHECK_THROWS_AS(value.get_ref(), json::type_error); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number"); - CHECK_THROWS_AS(value.get_ref(), json::type_error&); + CHECK_THROWS_AS(value.get_ref(), json::type_error); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number"); - CHECK_THROWS_AS(value.get_ref(), json::type_error&); + CHECK_THROWS_AS(value.get_ref(), json::type_error); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number"); CHECK_NOTHROW(value.get_ref()); - CHECK_THROWS_AS(value.get_ref(), json::type_error&); + CHECK_THROWS_AS(value.get_ref(), json::type_error); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number"); - CHECK_THROWS_AS(value.get_ref(), json::type_error&); + CHECK_THROWS_AS(value.get_ref(), json::type_error); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number"); } @@ -257,23 +257,23 @@ TEST_CASE("reference access") CHECK(p2 == value.get()); // check if mismatching references throw correctly - CHECK_THROWS_AS(value.get_ref(), json::type_error&); + CHECK_THROWS_AS(value.get_ref(), json::type_error); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number"); - CHECK_THROWS_AS(value.get_ref(), json::type_error&); + CHECK_THROWS_AS(value.get_ref(), json::type_error); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number"); - CHECK_THROWS_AS(value.get_ref(), json::type_error&); + CHECK_THROWS_AS(value.get_ref(), json::type_error); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number"); - CHECK_THROWS_AS(value.get_ref(), json::type_error&); + CHECK_THROWS_AS(value.get_ref(), json::type_error); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number"); - //CHECK_THROWS_AS(value.get_ref(), json::type_error&); + //CHECK_THROWS_AS(value.get_ref(), json::type_error); //CHECK_THROWS_WITH(value.get_ref(), // "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number"); CHECK_NOTHROW(value.get_ref()); - CHECK_THROWS_AS(value.get_ref(), json::type_error&); + CHECK_THROWS_AS(value.get_ref(), json::type_error); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number"); } @@ -293,22 +293,22 @@ TEST_CASE("reference access") CHECK(p2 == value.get()); // check if mismatching references throw correctly - CHECK_THROWS_AS(value.get_ref(), json::type_error&); + CHECK_THROWS_AS(value.get_ref(), json::type_error); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number"); - CHECK_THROWS_AS(value.get_ref(), json::type_error&); + CHECK_THROWS_AS(value.get_ref(), json::type_error); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number"); - CHECK_THROWS_AS(value.get_ref(), json::type_error&); + CHECK_THROWS_AS(value.get_ref(), json::type_error); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number"); - CHECK_THROWS_AS(value.get_ref(), json::type_error&); + CHECK_THROWS_AS(value.get_ref(), json::type_error); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number"); - CHECK_THROWS_AS(value.get_ref(), json::type_error&); + CHECK_THROWS_AS(value.get_ref(), json::type_error); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number"); - CHECK_THROWS_AS(value.get_ref(), json::type_error&); + CHECK_THROWS_AS(value.get_ref(), json::type_error); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number"); CHECK_NOTHROW(value.get_ref()); diff --git a/test/src/unit-regression.cpp b/test/src/unit-regression.cpp index 17728160..4fd3fb52 100644 --- a/test/src/unit-regression.cpp +++ b/test/src/unit-regression.cpp @@ -588,7 +588,7 @@ TEST_CASE("regression tests") SECTION("issue #329 - serialized value not always can be parsed") { - CHECK_THROWS_AS(json::parse("22e2222"), json::out_of_range&); + CHECK_THROWS_AS(json::parse("22e2222"), json::out_of_range); CHECK_THROWS_WITH(json::parse("22e2222"), "[json.exception.out_of_range.406] number overflow parsing '22e2222'"); } @@ -596,7 +596,7 @@ TEST_CASE("regression tests") SECTION("issue #366 - json::parse on failed stream gets stuck") { std::ifstream f("file_not_found.json"); - CHECK_THROWS_AS(json::parse(f), json::parse_error&); + CHECK_THROWS_AS(json::parse(f), json::parse_error); CHECK_THROWS_WITH(json::parse(f), "[json.exception.parse_error.101] parse error at 1: syntax error - unexpected end of input; expected '[', '{', or a literal"); } @@ -611,7 +611,7 @@ TEST_CASE("regression tests") // ss is not at EOF; this yielded an error before the fix // (threw basic_string::append). No, it should just throw // a parse error because of the EOF. - CHECK_THROWS_AS(ss >> j, json::parse_error&); + CHECK_THROWS_AS(ss >> j, json::parse_error); CHECK_THROWS_WITH(ss >> j, "[json.exception.parse_error.101] parse error at 1: syntax error - unexpected end of input; expected '[', '{', or a literal"); } @@ -622,7 +622,7 @@ TEST_CASE("regression tests") { std::stringstream ss; json j; - CHECK_THROWS_AS(ss >> j, json::parse_error&); + CHECK_THROWS_AS(ss >> j, json::parse_error); CHECK_THROWS_WITH(ss >> j, "[json.exception.parse_error.101] parse error at 1: syntax error - unexpected end of input; expected '[', '{', or a literal"); } @@ -632,7 +632,7 @@ TEST_CASE("regression tests") std::stringstream ss; ss << " "; json j; - CHECK_THROWS_AS(ss >> j, json::parse_error&); + CHECK_THROWS_AS(ss >> j, json::parse_error); CHECK_THROWS_WITH(ss >> j, "[json.exception.parse_error.101] parse error at 1: syntax error - unexpected end of input; expected '[', '{', or a literal"); } @@ -645,7 +645,7 @@ TEST_CASE("regression tests") CHECK_NOTHROW(ss >> j); CHECK(j == 111); - CHECK_THROWS_AS(ss >> j, json::parse_error&); + CHECK_THROWS_AS(ss >> j, json::parse_error); CHECK_THROWS_WITH(ss >> j, "[json.exception.parse_error.101] parse error at 1: syntax error - unexpected end of input; expected '[', '{', or a literal"); } @@ -658,7 +658,7 @@ TEST_CASE("regression tests") CHECK_NOTHROW(ss >> j); CHECK(j == 222); - CHECK_THROWS_AS(ss >> j, json::parse_error&); + CHECK_THROWS_AS(ss >> j, json::parse_error); CHECK_THROWS_WITH(ss >> j, "[json.exception.parse_error.101] parse error at 1: syntax error - unexpected end of input; expected '[', '{', or a literal"); } @@ -671,7 +671,7 @@ TEST_CASE("regression tests") CHECK_NOTHROW(ss >> j); CHECK(j == 333); - CHECK_THROWS_AS(ss >> j, json::parse_error&); + CHECK_THROWS_AS(ss >> j, json::parse_error); CHECK_THROWS_WITH(ss >> j, "[json.exception.parse_error.101] parse error at 1: syntax error - unexpected end of input; expected '[', '{', or a literal"); } @@ -688,7 +688,7 @@ TEST_CASE("regression tests") CHECK_NOTHROW(ss >> j); CHECK(j == 333); - CHECK_THROWS_AS(ss >> j, json::parse_error&); + CHECK_THROWS_AS(ss >> j, json::parse_error); CHECK_THROWS_WITH(ss >> j, "[json.exception.parse_error.101] parse error at 1: syntax error - unexpected end of input; expected '[', '{', or a literal"); } @@ -707,7 +707,7 @@ TEST_CASE("regression tests") CHECK_NOTHROW(ss >> j); CHECK(j == ""); - CHECK_THROWS_AS(ss >> j, json::parse_error&); + CHECK_THROWS_AS(ss >> j, json::parse_error); CHECK_THROWS_WITH(ss >> j, "[json.exception.parse_error.101] parse error at 1: syntax error - unexpected end of input; expected '[', '{', or a literal"); } @@ -722,7 +722,7 @@ TEST_CASE("regression tests") CHECK_NOTHROW(ss >> j); CHECK(j == json({{"three", 3}})); - CHECK_THROWS_AS(ss >> j, json::parse_error&); + CHECK_THROWS_AS(ss >> j, json::parse_error); CHECK_THROWS_WITH(ss >> j, "[json.exception.parse_error.101] parse error at 1: syntax error - unexpected end of input; expected '[', '{', or a literal"); } @@ -792,7 +792,7 @@ TEST_CASE("regression tests") { // original test case std::vector vec {0x65, 0xf5, 0x0a, 0x48, 0x21}; - CHECK_THROWS_AS(json::from_cbor(vec), json::parse_error&); + CHECK_THROWS_AS(json::from_cbor(vec), json::parse_error); CHECK_THROWS_WITH(json::from_cbor(vec), "[json.exception.parse_error.110] parse error at 6: unexpected end of input"); } @@ -801,31 +801,31 @@ TEST_CASE("regression tests") { // original test case: incomplete float64 std::vector vec1 {0xcb, 0x8f, 0x0a}; - CHECK_THROWS_AS(json::from_msgpack(vec1), json::parse_error&); + CHECK_THROWS_AS(json::from_msgpack(vec1), json::parse_error); CHECK_THROWS_WITH(json::from_msgpack(vec1), "[json.exception.parse_error.110] parse error at 4: unexpected end of input"); // related test case: incomplete float32 std::vector vec2 {0xca, 0x8f, 0x0a}; - CHECK_THROWS_AS(json::from_msgpack(vec2), json::parse_error&); + CHECK_THROWS_AS(json::from_msgpack(vec2), json::parse_error); CHECK_THROWS_WITH(json::from_msgpack(vec2), "[json.exception.parse_error.110] parse error at 4: unexpected end of input"); // related test case: incomplete Half-Precision Float (CBOR) std::vector vec3 {0xf9, 0x8f}; - CHECK_THROWS_AS(json::from_cbor(vec3), json::parse_error&); + CHECK_THROWS_AS(json::from_cbor(vec3), json::parse_error); CHECK_THROWS_WITH(json::from_cbor(vec3), "[json.exception.parse_error.110] parse error at 3: unexpected end of input"); // related test case: incomplete Single-Precision Float (CBOR) std::vector vec4 {0xfa, 0x8f, 0x0a}; - CHECK_THROWS_AS(json::from_cbor(vec4), json::parse_error&); + CHECK_THROWS_AS(json::from_cbor(vec4), json::parse_error); CHECK_THROWS_WITH(json::from_cbor(vec4), "[json.exception.parse_error.110] parse error at 4: unexpected end of input"); // related test case: incomplete Double-Precision Float (CBOR) std::vector vec5 {0xfb, 0x8f, 0x0a}; - CHECK_THROWS_AS(json::from_cbor(vec5), json::parse_error&); + CHECK_THROWS_AS(json::from_cbor(vec5), json::parse_error); CHECK_THROWS_WITH(json::from_cbor(vec5), "[json.exception.parse_error.110] parse error at 4: unexpected end of input"); } @@ -834,7 +834,7 @@ TEST_CASE("regression tests") { // original test case std::vector vec1 {0x87}; - CHECK_THROWS_AS(json::from_msgpack(vec1), json::parse_error&); + CHECK_THROWS_AS(json::from_msgpack(vec1), json::parse_error); CHECK_THROWS_WITH(json::from_msgpack(vec1), "[json.exception.parse_error.110] parse error at 2: unexpected end of input"); @@ -848,7 +848,7 @@ TEST_CASE("regression tests") }) { std::vector vec(1, static_cast(b)); - CHECK_THROWS_AS(json::from_msgpack(vec), json::parse_error&); + CHECK_THROWS_AS(json::from_msgpack(vec), json::parse_error); } // more test cases for CBOR @@ -863,15 +863,15 @@ TEST_CASE("regression tests") }) { std::vector vec(1, static_cast(b)); - CHECK_THROWS_AS(json::from_cbor(vec), json::parse_error&); + CHECK_THROWS_AS(json::from_cbor(vec), json::parse_error); } // special case: empty input std::vector vec2; - CHECK_THROWS_AS(json::from_cbor(vec2), json::parse_error&); + CHECK_THROWS_AS(json::from_cbor(vec2), json::parse_error); CHECK_THROWS_WITH(json::from_cbor(vec2), "[json.exception.parse_error.110] parse error at 1: unexpected end of input"); - CHECK_THROWS_AS(json::from_msgpack(vec2), json::parse_error&); + CHECK_THROWS_AS(json::from_msgpack(vec2), json::parse_error); CHECK_THROWS_WITH(json::from_msgpack(vec2), "[json.exception.parse_error.110] parse error at 1: unexpected end of input"); } @@ -880,19 +880,19 @@ TEST_CASE("regression tests") { // original test case: empty UTF-8 string (indefinite length) std::vector vec1 {0x7f}; - CHECK_THROWS_AS(json::from_cbor(vec1), json::parse_error&); + CHECK_THROWS_AS(json::from_cbor(vec1), json::parse_error); CHECK_THROWS_WITH(json::from_cbor(vec1), "[json.exception.parse_error.110] parse error at 2: unexpected end of input"); // related test case: empty array (indefinite length) std::vector vec2 {0x9f}; - CHECK_THROWS_AS(json::from_cbor(vec2), json::parse_error&); + CHECK_THROWS_AS(json::from_cbor(vec2), json::parse_error); CHECK_THROWS_WITH(json::from_cbor(vec2), "[json.exception.parse_error.110] parse error at 2: unexpected end of input"); // related test case: empty map (indefinite length) std::vector vec3 {0xbf}; - CHECK_THROWS_AS(json::from_cbor(vec3), json::parse_error&); + CHECK_THROWS_AS(json::from_cbor(vec3), json::parse_error); CHECK_THROWS_WITH(json::from_cbor(vec3), "[json.exception.parse_error.110] parse error at 2: unexpected end of input"); } @@ -920,25 +920,25 @@ TEST_CASE("regression tests") 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60 }; - CHECK_THROWS_AS(json::from_cbor(vec), json::parse_error&); + CHECK_THROWS_AS(json::from_cbor(vec), json::parse_error); CHECK_THROWS_WITH(json::from_cbor(vec), "[json.exception.parse_error.113] parse error at 2: expected a CBOR string; last byte: 0x98"); // related test case: nonempty UTF-8 string (indefinite length) std::vector vec1 {0x7f, 0x61, 0x61}; - CHECK_THROWS_AS(json::from_cbor(vec1), json::parse_error&); + CHECK_THROWS_AS(json::from_cbor(vec1), json::parse_error); CHECK_THROWS_WITH(json::from_cbor(vec1), "[json.exception.parse_error.110] parse error at 4: unexpected end of input"); // related test case: nonempty array (indefinite length) std::vector vec2 {0x9f, 0x01}; - CHECK_THROWS_AS(json::from_cbor(vec2), json::parse_error&); + CHECK_THROWS_AS(json::from_cbor(vec2), json::parse_error); CHECK_THROWS_WITH(json::from_cbor(vec2), "[json.exception.parse_error.110] parse error at 3: unexpected end of input"); // related test case: nonempty map (indefinite length) std::vector vec3 {0xbf, 0x61, 0x61, 0x01}; - CHECK_THROWS_AS(json::from_cbor(vec3), json::parse_error&); + CHECK_THROWS_AS(json::from_cbor(vec3), json::parse_error); CHECK_THROWS_WITH(json::from_cbor(vec3), "[json.exception.parse_error.110] parse error at 5: unexpected end of input"); } @@ -973,7 +973,7 @@ TEST_CASE("regression tests") 0x96, 0x96, 0xb4, 0xb4, 0xfa, 0x94, 0x94, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0xfa }; - CHECK_THROWS_AS(json::from_cbor(vec1), json::parse_error&); + CHECK_THROWS_AS(json::from_cbor(vec1), json::parse_error); CHECK_THROWS_WITH(json::from_cbor(vec1), "[json.exception.parse_error.113] parse error at 13: expected a CBOR string; last byte: 0xB4"); @@ -987,7 +987,7 @@ TEST_CASE("regression tests") 0x96, 0x96, 0xb4, 0xb4, 0xfa, 0x94, 0x94, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0xfb }; - CHECK_THROWS_AS(json::from_cbor(vec2), json::parse_error&); + CHECK_THROWS_AS(json::from_cbor(vec2), json::parse_error); CHECK_THROWS_WITH(json::from_cbor(vec2), "[json.exception.parse_error.113] parse error at 13: expected a CBOR string; last byte: 0xB4"); } @@ -995,7 +995,7 @@ TEST_CASE("regression tests") SECTION("issue #452 - Heap-buffer-overflow (OSS-Fuzz issue 585)") { std::vector vec = {'-', '0', '1', '2', '2', '7', '4'}; - CHECK_THROWS_AS(json::parse(vec), json::parse_error&); + CHECK_THROWS_AS(json::parse(vec), json::parse_error); } SECTION("issue #454 - doubles are printed as integers") @@ -1035,9 +1035,9 @@ TEST_CASE("regression tests") }; CHECK_NOTHROW(create(j_array)); - CHECK_THROWS_AS(create(j_number), json::type_error&); + CHECK_THROWS_AS(create(j_number), json::type_error); CHECK_THROWS_WITH(create(j_number), "[json.exception.type_error.302] type must be array, but is number"); - CHECK_THROWS_AS(create(j_null), json::type_error&); + CHECK_THROWS_AS(create(j_null), json::type_error); CHECK_THROWS_WITH(create(j_null), "[json.exception.type_error.302] type must be array, but is null"); } @@ -1049,9 +1049,9 @@ TEST_CASE("regression tests") }; CHECK_NOTHROW(create(j_array)); - CHECK_THROWS_AS(create(j_number), json::type_error&); + CHECK_THROWS_AS(create(j_number), json::type_error); CHECK_THROWS_WITH(create(j_number), "[json.exception.type_error.302] type must be array, but is number"); - CHECK_THROWS_AS(create(j_null), json::type_error&); + CHECK_THROWS_AS(create(j_null), json::type_error); CHECK_THROWS_WITH(create(j_null), "[json.exception.type_error.302] type must be array, but is null"); } @@ -1063,9 +1063,9 @@ TEST_CASE("regression tests") }; CHECK_NOTHROW(create(j_array)); - CHECK_THROWS_AS(create(j_number), json::type_error&); + CHECK_THROWS_AS(create(j_number), json::type_error); CHECK_THROWS_WITH(create(j_number), "[json.exception.type_error.302] type must be array, but is number"); - CHECK_THROWS_AS(create(j_null), json::type_error&); + CHECK_THROWS_AS(create(j_null), json::type_error); CHECK_THROWS_WITH(create(j_null), "[json.exception.type_error.302] type must be array, but is null"); } } @@ -1100,7 +1100,7 @@ TEST_CASE("regression tests") l.m_stream->setstate(std::ios_base::failbit); - CHECK_THROWS_AS(l.fill_line_buffer(), json::parse_error&); + CHECK_THROWS_AS(l.fill_line_buffer(), json::parse_error); CHECK_THROWS_WITH(l.fill_line_buffer(), "[json.exception.parse_error.111] parse error: bad input stream"); } @@ -1115,7 +1115,7 @@ TEST_CASE("regression tests") l.m_stream->setstate(std::ios_base::badbit); - CHECK_THROWS_AS(l.fill_line_buffer(), json::parse_error&); + CHECK_THROWS_AS(l.fill_line_buffer(), json::parse_error); CHECK_THROWS_WITH(l.fill_line_buffer(), "[json.exception.parse_error.111] parse error: bad input stream"); } } @@ -1179,7 +1179,7 @@ TEST_CASE("regression tests") SECTION("issue #575 - heap-buffer-overflow (OSS-Fuzz 1400)") { std::vector vec = {'"', '\\', '"', 'X', '"', '"'}; - CHECK_THROWS_AS(json::parse(vec), json::parse_error&); + CHECK_THROWS_AS(json::parse(vec), json::parse_error); } SECTION("issue #600 - how does one convert a map in Json back to std::map?") @@ -1244,7 +1244,7 @@ TEST_CASE("regression tests") CHECK(v[i] == j[i]); } - CHECK_THROWS_AS(json().get>(), json::type_error&); + CHECK_THROWS_AS(json().get>(), json::type_error); CHECK_THROWS_WITH(json().get>(), "[json.exception.type_error.302] type must be array, but is null"); } diff --git a/test/src/unit-testsuites.cpp b/test/src/unit-testsuites.cpp index d281c679..d3dbaf4b 100644 --- a/test/src/unit-testsuites.cpp +++ b/test/src/unit-testsuites.cpp @@ -78,7 +78,7 @@ TEST_CASE("compliance tests from json.org") { CAPTURE(filename); std::ifstream f(filename); - CHECK_THROWS_AS(json::parse(f), json::parse_error&); + CHECK_THROWS_AS(json::parse(f), json::parse_error); } } @@ -772,7 +772,7 @@ TEST_CASE("nst's JSONTestSuite") { CAPTURE(filename); std::ifstream f(filename); - CHECK_THROWS_AS(json::parse(f), json::parse_error&); + CHECK_THROWS_AS(json::parse(f), json::parse_error); } } @@ -848,7 +848,7 @@ TEST_CASE("nst's JSONTestSuite") CAPTURE(filename); std::ifstream f(filename); json j; - CHECK_THROWS_AS(f >> j, json::out_of_range&); + CHECK_THROWS_AS(f >> j, json::out_of_range); } } @@ -875,7 +875,7 @@ TEST_CASE("nst's JSONTestSuite") CAPTURE(filename); std::ifstream f(filename); json j; - CHECK_THROWS_AS(f >> j, json::parse_error&); + CHECK_THROWS_AS(f >> j, json::parse_error); } } } diff --git a/test/src/unit-unicode.cpp b/test/src/unit-unicode.cpp index b51a1579..9d4d65ca 100644 --- a/test/src/unit-unicode.cpp +++ b/test/src/unit-unicode.cpp @@ -81,7 +81,7 @@ void check_utf8string(bool success_expected, int byte1, int byte2 = -1, int byte } else { - CHECK_THROWS_AS(json::parse(json_string), json::parse_error&); + CHECK_THROWS_AS(json::parse(json_string), json::parse_error); } } @@ -928,31 +928,31 @@ TEST_CASE("Unicode", "[hide]") { SECTION("incorrect surrogate values") { - CHECK_THROWS_AS(json::parse("\"\\uDC00\\uDC00\""), json::parse_error&); + CHECK_THROWS_AS(json::parse("\"\\uDC00\\uDC00\""), json::parse_error); CHECK_THROWS_WITH(json::parse("\"\\uDC00\\uDC00\""), "[json.exception.parse_error.101] parse error at 7: syntax error - invalid string: surrogate U+DC00..U+DFFF must follow U+D800..U+DBFF; last read: '\"\\uDC00'"); - CHECK_THROWS_AS(json::parse("\"\\uD7FF\\uDC00\""), json::parse_error&); + CHECK_THROWS_AS(json::parse("\"\\uD7FF\\uDC00\""), json::parse_error); CHECK_THROWS_WITH(json::parse("\"\\uD7FF\\uDC00\""), "[json.exception.parse_error.101] parse error at 13: syntax error - invalid string: surrogate U+DC00..U+DFFF must follow U+D800..U+DBFF; last read: '\"\\uD7FF\\uDC00'"); - CHECK_THROWS_AS(json::parse("\"\\uD800]\""), json::parse_error&); + CHECK_THROWS_AS(json::parse("\"\\uD800]\""), json::parse_error); CHECK_THROWS_WITH(json::parse("\"\\uD800]\""), "[json.exception.parse_error.101] parse error at 8: syntax error - invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF; last read: '\"\\uD800]'"); - CHECK_THROWS_AS(json::parse("\"\\uD800\\v\""), json::parse_error&); + CHECK_THROWS_AS(json::parse("\"\\uD800\\v\""), json::parse_error); CHECK_THROWS_WITH(json::parse("\"\\uD800\\v\""), "[json.exception.parse_error.101] parse error at 9: syntax error - invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF; last read: '\"\\uD800\\v'"); - CHECK_THROWS_AS(json::parse("\"\\uD800\\u123\""), json::parse_error&); + CHECK_THROWS_AS(json::parse("\"\\uD800\\u123\""), json::parse_error); CHECK_THROWS_WITH(json::parse("\"\\uD800\\u123\""), "[json.exception.parse_error.101] parse error at 13: syntax error - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\uD800\\u123\"'"); - CHECK_THROWS_AS(json::parse("\"\\uD800\\uDBFF\""), json::parse_error&); + CHECK_THROWS_AS(json::parse("\"\\uD800\\uDBFF\""), json::parse_error); CHECK_THROWS_WITH(json::parse("\"\\uD800\\uDBFF\""), "[json.exception.parse_error.101] parse error at 13: syntax error - invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF; last read: '\"\\uD800\\uDBFF'"); - CHECK_THROWS_AS(json::parse("\"\\uD800\\uE000\""), json::parse_error&); + CHECK_THROWS_AS(json::parse("\"\\uD800\\uE000\""), json::parse_error); CHECK_THROWS_WITH(json::parse("\"\\uD800\\uE000\""), "[json.exception.parse_error.101] parse error at 13: syntax error - invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF; last read: '\"\\uD800\\uE000'"); } @@ -969,7 +969,7 @@ TEST_CASE("Unicode", "[hide]") { std::string json_text = "\"" + codepoint_to_unicode(cp) + "\""; CAPTURE(json_text); - CHECK_THROWS_AS(json::parse(json_text), json::parse_error&); + CHECK_THROWS_AS(json::parse(json_text), json::parse_error); } } @@ -988,7 +988,7 @@ TEST_CASE("Unicode", "[hide]") std::string json_text = "\"" + codepoint_to_unicode(cp1) + codepoint_to_unicode(cp2) + "\""; CAPTURE(json_text); - CHECK_THROWS_AS(json::parse(json_text), json::parse_error&); + CHECK_THROWS_AS(json::parse(json_text), json::parse_error); } } } @@ -1001,7 +1001,7 @@ TEST_CASE("Unicode", "[hide]") { std::string json_text = "\"" + codepoint_to_unicode(cp) + "\""; CAPTURE(json_text); - CHECK_THROWS_AS(json::parse(json_text), json::parse_error&); + CHECK_THROWS_AS(json::parse(json_text), json::parse_error); } } @@ -1072,7 +1072,7 @@ TEST_CASE("Unicode", "[hide]") SECTION("error for incomplete/wrong BOM") { - CHECK_THROWS_AS(json::parse("\xef\xbb"), json::parse_error&); - CHECK_THROWS_AS(json::parse("\xef\xbb\xbb"), json::parse_error&); + CHECK_THROWS_AS(json::parse("\xef\xbb"), json::parse_error); + CHECK_THROWS_AS(json::parse("\xef\xbb\xbb"), json::parse_error); } } diff --git a/test/thirdparty/catch/catch.hpp b/test/thirdparty/catch/catch.hpp index 7c351e93..362f8693 100644 --- a/test/thirdparty/catch/catch.hpp +++ b/test/thirdparty/catch/catch.hpp @@ -1,17 +1,17 @@ /* - * Catch v1.9.7 - * Generated: 2017-08-10 23:49:15.233907 + * Catch v2.0.1 + * Generated: 2017-11-03 11:53:39.642003 * ---------------------------------------------------------- * This file has been merged from multiple headers. Please don't edit it directly - * Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved. + * Copyright (c) 2017 Two Blue Cubes Ltd. All rights reserved. * * Distributed under the Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */ #ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED #define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED +// start catch.hpp -#define TWOBLUECUBES_CATCH_HPP_INCLUDED #ifdef __clang__ # pragma clang system_header @@ -19,7 +19,7 @@ # pragma GCC system_header #endif -// #included from: internal/catch_suppress_warnings.h +// start catch_suppress_warnings.h #ifdef __clang__ # ifdef __ICC // icpc defines the __clang__ macro @@ -32,8 +32,6 @@ # pragma clang diagnostic ignored "-Wunused-variable" # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wpadded" -# pragma clang diagnostic ignored "-Wc++98-compat" -# pragma clang diagnostic ignored "-Wc++98-compat-pedantic" # pragma clang diagnostic ignored "-Wswitch-enum" # pragma clang diagnostic ignored "-Wcovered-switch-default" # endif @@ -45,10 +43,33 @@ # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wpadded" #endif +// end catch_suppress_warnings.h #if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER) # define CATCH_IMPL +# define CATCH_CONFIG_EXTERNAL_INTERFACES +# if defined(CATCH_CONFIG_DISABLE_MATCHERS) +# undef CATCH_CONFIG_DISABLE_MATCHERS +# endif #endif +// start catch_platform.h + +#ifdef __APPLE__ +# include +# if TARGET_OS_MAC == 1 +# define CATCH_PLATFORM_MAC +# elif TARGET_OS_IPHONE == 1 +# define CATCH_PLATFORM_IPHONE +# endif + +#elif defined(linux) || defined(__linux) || defined(__linux__) +# define CATCH_PLATFORM_LINUX + +#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) +# define CATCH_PLATFORM_WINDOWS +#endif + +// end catch_platform.h #ifdef CATCH_IMPL # ifndef CLARA_CONFIG_MAIN # define CLARA_CONFIG_MAIN_NOT_DEFINED @@ -56,32 +77,15 @@ # endif #endif -// #included from: internal/catch_notimplemented_exception.h -#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_H_INCLUDED +// start catch_tag_alias_autoregistrar.h -// #included from: catch_common.h -#define TWOBLUECUBES_CATCH_COMMON_H_INCLUDED +// start catch_common.h -// #included from: catch_compiler_capabilities.h -#define TWOBLUECUBES_CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED +// start catch_compiler_capabilities.h -// Detect a number of compiler features - mostly C++11/14 conformance - by compiler +// Detect a number of compiler features - by compiler // The following features are defined: // -// CATCH_CONFIG_CPP11_NULLPTR : is nullptr supported? -// CATCH_CONFIG_CPP11_NOEXCEPT : is noexcept supported? -// CATCH_CONFIG_CPP11_GENERATED_METHODS : The delete and default keywords for compiler generated methods -// CATCH_CONFIG_CPP11_IS_ENUM : std::is_enum is supported? -// CATCH_CONFIG_CPP11_TUPLE : std::tuple is supported -// CATCH_CONFIG_CPP11_LONG_LONG : is long long supported? -// CATCH_CONFIG_CPP11_OVERRIDE : is override supported? -// CATCH_CONFIG_CPP11_UNIQUE_PTR : is unique_ptr supported (otherwise use auto_ptr) -// CATCH_CONFIG_CPP11_SHUFFLE : is std::shuffle supported? -// CATCH_CONFIG_CPP11_TYPE_TRAITS : are type_traits and enable_if supported? - -// CATCH_CONFIG_CPP11_OR_GREATER : Is C++11 supported? - -// CATCH_CONFIG_VARIADIC_MACROS : are variadic macros supported? // CATCH_CONFIG_COUNTER : is the __COUNTER__ macro supported? // CATCH_CONFIG_WINDOWS_SEH : is Windows SEH supported? // CATCH_CONFIG_POSIX_SIGNALS : are POSIX signals supported? @@ -91,18 +95,12 @@ // **************** // In general each macro has a _NO_ form -// (e.g. CATCH_CONFIG_CPP11_NO_NULLPTR) which disables the feature. +// (e.g. CATCH_CONFIG_NO_POSIX_SIGNALS) which disables the feature. // Many features, at point of detection, define an _INTERNAL_ macro, so they // can be combined, en-mass, with the _NO_ forms later. -// All the C++11 features can be disabled with CATCH_CONFIG_NO_CPP11 - #ifdef __cplusplus -# if __cplusplus >= 201103L -# define CATCH_CPP11_OR_GREATER -# endif - # if __cplusplus >= 201402L # define CATCH_CPP14_OR_GREATER # endif @@ -111,19 +109,11 @@ #ifdef __clang__ -# if __has_feature(cxx_nullptr) -# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR -# endif - -# if __has_feature(cxx_noexcept) -# define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT -# endif - -# if defined(CATCH_CPP11_OR_GREATER) -# define CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ +# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ _Pragma( "clang diagnostic push" ) \ - _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) -# define CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \ + _Pragma( "clang diagnostic ignored \"-Wglobal-constructors\"") +# define CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \ _Pragma( "clang diagnostic pop" ) # define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ @@ -131,7 +121,6 @@ _Pragma( "clang diagnostic ignored \"-Wparentheses\"" ) # define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \ _Pragma( "clang diagnostic pop" ) -# endif #endif // __clang__ @@ -160,167 +149,34 @@ #endif // __CYGWIN__ -//////////////////////////////////////////////////////////////////////////////// -// Borland -#ifdef __BORLANDC__ - -#endif // __BORLANDC__ - -//////////////////////////////////////////////////////////////////////////////// -// EDG -#ifdef __EDG_VERSION__ - -#endif // __EDG_VERSION__ - -//////////////////////////////////////////////////////////////////////////////// -// Digital Mars -#ifdef __DMC__ - -#endif // __DMC__ - -//////////////////////////////////////////////////////////////////////////////// -// GCC -#ifdef __GNUC__ - -# if __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__) -# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR -# endif - -// - otherwise more recent versions define __cplusplus >= 201103L -// and will get picked up below - -#endif // __GNUC__ - //////////////////////////////////////////////////////////////////////////////// // Visual C++ #ifdef _MSC_VER -#define CATCH_INTERNAL_CONFIG_WINDOWS_SEH - -#if (_MSC_VER >= 1600) -# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR -# define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR -#endif - -#if (_MSC_VER >= 1900 ) // (VC++ 13 (VS2015)) -#define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT -#define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS -#define CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE -#define CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS -#endif +// Universal Windows platform does not support SEH +// Or console colours (or console at all...) +# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) +# define CATCH_CONFIG_COLOUR_NONE +# else +# define CATCH_INTERNAL_CONFIG_WINDOWS_SEH +# endif #endif // _MSC_VER //////////////////////////////////////////////////////////////////////////////// -// Use variadic macros if the compiler supports them -#if ( defined _MSC_VER && _MSC_VER > 1400 && !defined __EDGE__) || \ - ( defined __WAVE__ && __WAVE_HAS_VARIADICS ) || \ - ( defined __GNUC__ && __GNUC__ >= 3 ) || \ - ( !defined __cplusplus && __STDC_VERSION__ >= 199901L || __cplusplus >= 201103L ) - -#define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS - +// Use of __COUNTER__ is suppressed during code analysis in +// CLion/AppCode 2017.2.x and former, because __COUNTER__ is not properly +// handled by it. +// Otherwise all supported compilers support COUNTER macro, +// but user still might want to turn it off +#if ( !defined(__JETBRAINS_IDE__) || __JETBRAINS_IDE__ >= 20170300L ) + #define CATCH_INTERNAL_CONFIG_COUNTER #endif -// Use __COUNTER__ if the compiler supports it -#if ( defined _MSC_VER && _MSC_VER >= 1300 ) || \ - ( defined __GNUC__ && ( __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3 )) ) || \ - ( defined __clang__ && __clang_major__ >= 3 ) - -#define CATCH_INTERNAL_CONFIG_COUNTER - -#endif - -//////////////////////////////////////////////////////////////////////////////// -// C++ language feature support - -// catch all support for C++11 -#if defined(CATCH_CPP11_OR_GREATER) - -# if !defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR) -# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR -# endif - -# ifndef CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT -# define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT -# endif - -# ifndef CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS -# define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS -# endif - -# ifndef CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM -# define CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM -# endif - -# ifndef CATCH_INTERNAL_CONFIG_CPP11_TUPLE -# define CATCH_INTERNAL_CONFIG_CPP11_TUPLE -# endif - -# ifndef CATCH_INTERNAL_CONFIG_VARIADIC_MACROS -# define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS -# endif - -# if !defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG) -# define CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG -# endif - -# if !defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE) -# define CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE -# endif -# if !defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) -# define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR -# endif -# if !defined(CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE) -# define CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE -# endif -# if !defined(CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS) -# define CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS -# endif - -#endif // __cplusplus >= 201103L - -// Now set the actual defines based on the above + anything the user has configured -#if defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NO_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_NO_CPP11) -# define CATCH_CONFIG_CPP11_NULLPTR -#endif -#if defined(CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NO_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_NO_CPP11) -# define CATCH_CONFIG_CPP11_NOEXCEPT -#endif -#if defined(CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_NO_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_NO_CPP11) -# define CATCH_CONFIG_CPP11_GENERATED_METHODS -#endif -#if defined(CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_NO_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_NO_CPP11) -# define CATCH_CONFIG_CPP11_IS_ENUM -#endif -#if defined(CATCH_INTERNAL_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_CPP11_NO_TUPLE) && !defined(CATCH_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_NO_CPP11) -# define CATCH_CONFIG_CPP11_TUPLE -#endif -#if defined(CATCH_INTERNAL_CONFIG_VARIADIC_MACROS) && !defined(CATCH_CONFIG_NO_VARIADIC_MACROS) && !defined(CATCH_CONFIG_VARIADIC_MACROS) -# define CATCH_CONFIG_VARIADIC_MACROS -#endif -#if defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_CPP11_NO_LONG_LONG) && !defined(CATCH_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_NO_CPP11) -# define CATCH_CONFIG_CPP11_LONG_LONG -#endif -#if defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_CPP11_NO_OVERRIDE) && !defined(CATCH_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_NO_CPP11) -# define CATCH_CONFIG_CPP11_OVERRIDE -#endif -#if defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_CPP11_NO_UNIQUE_PTR) && !defined(CATCH_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_NO_CPP11) -# define CATCH_CONFIG_CPP11_UNIQUE_PTR -#endif -// Use of __COUNTER__ is suppressed if __JETBRAINS_IDE__ is #defined (meaning we're being parsed by a JetBrains IDE for -// analytics) because, at time of writing, __COUNTER__ is not properly handled by it. -// This does not affect compilation -#if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER) && !defined(__JETBRAINS_IDE__) +#if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER) # define CATCH_CONFIG_COUNTER #endif -#if defined(CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE) && !defined(CATCH_CONFIG_CPP11_NO_SHUFFLE) && !defined(CATCH_CONFIG_CPP11_SHUFFLE) && !defined(CATCH_CONFIG_NO_CPP11) -# define CATCH_CONFIG_CPP11_SHUFFLE -#endif -# if defined(CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS) && !defined(CATCH_CONFIG_CPP11_NO_TYPE_TRAITS) && !defined(CATCH_CONFIG_CPP11_TYPE_TRAITS) && !defined(CATCH_CONFIG_NO_CPP11) -# define CATCH_CONFIG_CPP11_TYPE_TRAITS -# endif #if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH) # define CATCH_CONFIG_WINDOWS_SEH #endif @@ -333,41 +189,12 @@ # define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS # define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS #endif -#if !defined(CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS) -# define CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS -# define CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS -#endif - -// noexcept support: -#if defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_NOEXCEPT) -# define CATCH_NOEXCEPT noexcept -# define CATCH_NOEXCEPT_IS(x) noexcept(x) -#else -# define CATCH_NOEXCEPT throw() -# define CATCH_NOEXCEPT_IS(x) -#endif - -// nullptr support -#ifdef CATCH_CONFIG_CPP11_NULLPTR -# define CATCH_NULL nullptr -#else -# define CATCH_NULL NULL -#endif - -// override support -#ifdef CATCH_CONFIG_CPP11_OVERRIDE -# define CATCH_OVERRIDE override -#else -# define CATCH_OVERRIDE -#endif - -// unique_ptr support -#ifdef CATCH_CONFIG_CPP11_UNIQUE_PTR -# define CATCH_AUTO_PTR( T ) std::unique_ptr -#else -# define CATCH_AUTO_PTR( T ) std::auto_ptr +#if !defined(CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS +# define CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS #endif +// end catch_compiler_capabilities.h #define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line #define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) #ifdef CATCH_CONFIG_COUNTER @@ -376,95 +203,41 @@ # define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) #endif -#define INTERNAL_CATCH_STRINGIFY2( expr ) #expr -#define INTERNAL_CATCH_STRINGIFY( expr ) INTERNAL_CATCH_STRINGIFY2( expr ) - -#include -#include +#include +#include +#include namespace Catch { - struct IConfig; - struct CaseSensitive { enum Choice { Yes, No }; }; class NonCopyable { -#ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS NonCopyable( NonCopyable const& ) = delete; NonCopyable( NonCopyable && ) = delete; NonCopyable& operator = ( NonCopyable const& ) = delete; NonCopyable& operator = ( NonCopyable && ) = delete; -#else - NonCopyable( NonCopyable const& info ); - NonCopyable& operator = ( NonCopyable const& ); -#endif protected: - NonCopyable() {} + NonCopyable(); virtual ~NonCopyable(); }; - class SafeBool { - public: - typedef void (SafeBool::*type)() const; - - static type makeSafe( bool value ) { - return value ? &SafeBool::trueValue : 0; - } - private: - void trueValue() const {} - }; - - template - void deleteAll( ContainerT& container ) { - typename ContainerT::const_iterator it = container.begin(); - typename ContainerT::const_iterator itEnd = container.end(); - for(; it != itEnd; ++it ) - delete *it; - } - template - void deleteAllValues( AssociativeContainerT& container ) { - typename AssociativeContainerT::const_iterator it = container.begin(); - typename AssociativeContainerT::const_iterator itEnd = container.end(); - for(; it != itEnd; ++it ) - delete it->second; - } - - bool startsWith( std::string const& s, std::string const& prefix ); - bool startsWith( std::string const& s, char prefix ); - bool endsWith( std::string const& s, std::string const& suffix ); - bool endsWith( std::string const& s, char suffix ); - bool contains( std::string const& s, std::string const& infix ); - void toLowerInPlace( std::string& s ); - std::string toLower( std::string const& s ); - std::string trim( std::string const& str ); - bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ); - - struct pluralise { - pluralise( std::size_t count, std::string const& label ); - - friend std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ); - - std::size_t m_count; - std::string m_label; - }; - struct SourceLineInfo { - SourceLineInfo(); - SourceLineInfo( char const* _file, std::size_t _line ); -# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS - SourceLineInfo(SourceLineInfo const& other) = default; + SourceLineInfo() = delete; + SourceLineInfo( char const* _file, std::size_t _line ) noexcept; + + SourceLineInfo( SourceLineInfo const& other ) = default; SourceLineInfo( SourceLineInfo && ) = default; SourceLineInfo& operator = ( SourceLineInfo const& ) = default; SourceLineInfo& operator = ( SourceLineInfo && ) = default; -# endif - bool empty() const; - bool operator == ( SourceLineInfo const& other ) const; - bool operator < ( SourceLineInfo const& other ) const; + + bool empty() const noexcept; + bool operator == ( SourceLineInfo const& other ) const noexcept; + bool operator < ( SourceLineInfo const& other ) const noexcept; char const* file; std::size_t line; @@ -473,23 +246,16 @@ namespace Catch { std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ); // This is just here to avoid compiler warnings with macro constants and boolean literals - inline bool isTrue( bool value ){ return value; } - inline bool alwaysTrue() { return true; } - inline bool alwaysFalse() { return false; } - - void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ); - - void seedRng( IConfig const& config ); - unsigned int rngSeed(); + bool isTrue( bool value ); + bool alwaysTrue(); + bool alwaysFalse(); // Use this in variadic streaming macros to allow // >> +StreamEndStop // as well as // >> stuff +StreamEndStop struct StreamEndStop { - std::string operator+() { - return std::string(); - } + std::string operator+() const; }; template T const& operator + ( T const& value, StreamEndStop ) { @@ -497,193 +263,39 @@ namespace Catch { } } -#define CATCH_INTERNAL_LINEINFO ::Catch::SourceLineInfo( __FILE__, static_cast( __LINE__ ) ) -#define CATCH_INTERNAL_ERROR( msg ) ::Catch::throwLogicError( msg, CATCH_INTERNAL_LINEINFO ); +#define CATCH_INTERNAL_LINEINFO \ + ::Catch::SourceLineInfo( __FILE__, static_cast( __LINE__ ) ) +// end catch_common.h namespace Catch { - class NotImplementedException : public std::exception - { - public: - NotImplementedException( SourceLineInfo const& lineInfo ); - - virtual ~NotImplementedException() CATCH_NOEXCEPT {} - - virtual const char* what() const CATCH_NOEXCEPT; - - private: - std::string m_what; - SourceLineInfo m_lineInfo; + struct RegistrarForTagAliases { + RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); }; } // end namespace Catch -/////////////////////////////////////////////////////////////////////////////// -#define CATCH_NOT_IMPLEMENTED throw Catch::NotImplementedException( CATCH_INTERNAL_LINEINFO ) +#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } -// #included from: internal/catch_context.h -#define TWOBLUECUBES_CATCH_CONTEXT_H_INCLUDED +// end catch_tag_alias_autoregistrar.h +// start catch_test_registry.h -// #included from: catch_interfaces_generators.h -#define TWOBLUECUBES_CATCH_INTERFACES_GENERATORS_H_INCLUDED - -#include - -namespace Catch { - - struct IGeneratorInfo { - virtual ~IGeneratorInfo(); - virtual bool moveNext() = 0; - virtual std::size_t getCurrentIndex() const = 0; - }; - - struct IGeneratorsForTest { - virtual ~IGeneratorsForTest(); - - virtual IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) = 0; - virtual bool moveNext() = 0; - }; - - IGeneratorsForTest* createGeneratorsForTest(); - -} // end namespace Catch - -// #included from: catch_ptr.hpp -#define TWOBLUECUBES_CATCH_PTR_HPP_INCLUDED - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wpadded" -#endif - -namespace Catch { - - // An intrusive reference counting smart pointer. - // T must implement addRef() and release() methods - // typically implementing the IShared interface - template - class Ptr { - public: - Ptr() : m_p( CATCH_NULL ){} - Ptr( T* p ) : m_p( p ){ - if( m_p ) - m_p->addRef(); - } - Ptr( Ptr const& other ) : m_p( other.m_p ){ - if( m_p ) - m_p->addRef(); - } - ~Ptr(){ - if( m_p ) - m_p->release(); - } - void reset() { - if( m_p ) - m_p->release(); - m_p = CATCH_NULL; - } - Ptr& operator = ( T* p ){ - Ptr temp( p ); - swap( temp ); - return *this; - } - Ptr& operator = ( Ptr const& other ){ - Ptr temp( other ); - swap( temp ); - return *this; - } - void swap( Ptr& other ) { std::swap( m_p, other.m_p ); } - T* get() const{ return m_p; } - T& operator*() const { return *m_p; } - T* operator->() const { return m_p; } - bool operator !() const { return m_p == CATCH_NULL; } - operator SafeBool::type() const { return SafeBool::makeSafe( m_p != CATCH_NULL ); } - - private: - T* m_p; - }; - - struct IShared : NonCopyable { - virtual ~IShared(); - virtual void addRef() const = 0; - virtual void release() const = 0; - }; - - template - struct SharedImpl : T { - - SharedImpl() : m_rc( 0 ){} - - virtual void addRef() const { - ++m_rc; - } - virtual void release() const { - if( --m_rc == 0 ) - delete this; - } - - mutable unsigned int m_rc; - }; - -} // end namespace Catch - -#ifdef __clang__ -#pragma clang diagnostic pop -#endif - -namespace Catch { - - class TestCase; - class Stream; - struct IResultCapture; - struct IRunner; - struct IGeneratorsForTest; - struct IConfig; - - struct IContext - { - virtual ~IContext(); - - virtual IResultCapture* getResultCapture() = 0; - virtual IRunner* getRunner() = 0; - virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) = 0; - virtual bool advanceGeneratorsForCurrentTest() = 0; - virtual Ptr getConfig() const = 0; - }; - - struct IMutableContext : IContext - { - virtual ~IMutableContext(); - virtual void setResultCapture( IResultCapture* resultCapture ) = 0; - virtual void setRunner( IRunner* runner ) = 0; - virtual void setConfig( Ptr const& config ) = 0; - }; - - IContext& getCurrentContext(); - IMutableContext& getCurrentMutableContext(); - void cleanUpContext(); - Stream createStream( std::string const& streamName ); - -} - -// #included from: internal/catch_test_registry.hpp -#define TWOBLUECUBES_CATCH_TEST_REGISTRY_HPP_INCLUDED - -// #included from: catch_interfaces_testcase.h -#define TWOBLUECUBES_CATCH_INTERFACES_TESTCASE_H_INCLUDED +// start catch_interfaces_testcase.h #include +#include namespace Catch { class TestSpec; - struct ITestCase : IShared { + struct ITestInvoker { virtual void invoke () const = 0; - protected: - virtual ~ITestCase(); + virtual ~ITestInvoker(); }; + using ITestCasePtr = std::shared_ptr; + class TestCase; struct IConfig; @@ -699,814 +311,180 @@ namespace Catch { } +// end catch_interfaces_testcase.h +// start catch_stringref.h + +#include +#include +#include + +namespace Catch { + + class StringData; + + /// A non-owning string class (similar to the forthcoming std::string_view) + /// Note that, because a StringRef may be a substring of another string, + /// it may not be null terminated. c_str() must return a null terminated + /// string, however, and so the StringRef will internally take ownership + /// (taking a copy), if necessary. In theory this ownership is not externally + /// visible - but it does mean (substring) StringRefs should not be shared between + /// threads. + class StringRef { + friend struct StringRefTestAccess; + + using size_type = std::size_t; + + char const* m_start; + size_type m_size; + + char* m_data = nullptr; + + void takeOwnership(); + + public: // construction/ assignment + StringRef() noexcept; + StringRef( StringRef const& other ) noexcept; + StringRef( StringRef&& other ) noexcept; + StringRef( char const* rawChars ) noexcept; + StringRef( char const* rawChars, size_type size ) noexcept; + StringRef( std::string const& stdString ) noexcept; + ~StringRef() noexcept; + + auto operator = ( StringRef other ) noexcept -> StringRef&; + operator std::string() const; + + void swap( StringRef& other ) noexcept; + + public: // operators + auto operator == ( StringRef const& other ) const noexcept -> bool; + auto operator != ( StringRef const& other ) const noexcept -> bool; + + auto operator[] ( size_type index ) const noexcept -> char; + + public: // named queries + auto empty() const noexcept -> bool; + auto size() const noexcept -> size_type; + auto numberOfCharacters() const noexcept -> size_type; + auto c_str() const -> char const*; + + public: // substrings and searches + auto substr( size_type start, size_type size ) const noexcept -> StringRef; + + private: // ownership queries - may not be consistent between calls + auto isOwned() const noexcept -> bool; + auto isSubstring() const noexcept -> bool; + auto data() const noexcept -> char const*; + }; + + auto operator + ( StringRef const& lhs, StringRef const& rhs ) -> std::string; + auto operator + ( StringRef const& lhs, char const* rhs ) -> std::string; + auto operator + ( char const* lhs, StringRef const& rhs ) -> std::string; + + auto operator << ( std::ostream& os, StringRef const& sr ) -> std::ostream&; + +} // namespace Catch + +// end catch_stringref.h namespace Catch { template -class MethodTestCase : public SharedImpl { - +class TestInvokerAsMethod : public ITestInvoker { + void (C::*m_testAsMethod)(); public: - MethodTestCase( void (C::*method)() ) : m_method( method ) {} + TestInvokerAsMethod( void (C::*testAsMethod)() ) noexcept : m_testAsMethod( testAsMethod ) {} - virtual void invoke() const { + void invoke() const override { C obj; - (obj.*m_method)(); + (obj.*m_testAsMethod)(); } - -private: - virtual ~MethodTestCase() {} - - void (C::*m_method)(); }; -typedef void(*TestFunction)(); +auto makeTestInvoker( void(*testAsFunction)() ) noexcept -> ITestInvoker*; -struct NameAndDesc { - NameAndDesc( const char* _name = "", const char* _description= "" ) - : name( _name ), description( _description ) - {} +template +auto makeTestInvoker( void (C::*testAsMethod)() ) noexcept -> ITestInvoker* { + return new(std::nothrow) TestInvokerAsMethod( testAsMethod ); +} - const char* name; - const char* description; +struct NameAndTags { + NameAndTags( StringRef name_ = "", StringRef tags_ = "" ) noexcept; + StringRef name; + StringRef tags; }; -void registerTestCase - ( ITestCase* testCase, - char const* className, - NameAndDesc const& nameAndDesc, - SourceLineInfo const& lineInfo ); - -struct AutoReg { - - AutoReg - ( TestFunction function, - SourceLineInfo const& lineInfo, - NameAndDesc const& nameAndDesc ); - - template - AutoReg - ( void (C::*method)(), - char const* className, - NameAndDesc const& nameAndDesc, - SourceLineInfo const& lineInfo ) { - - registerTestCase - ( new MethodTestCase( method ), - className, - nameAndDesc, - lineInfo ); - } - +struct AutoReg : NonCopyable { + AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef classOrMethod, NameAndTags const& nameAndTags ) noexcept; ~AutoReg(); - -private: - AutoReg( AutoReg const& ); - void operator= ( AutoReg const& ); }; -void registerTestCaseFunction - ( TestFunction function, - SourceLineInfo const& lineInfo, - NameAndDesc const& nameAndDesc ); - } // end namespace Catch -#ifdef CATCH_CONFIG_VARIADIC_MACROS +#if defined(CATCH_CONFIG_DISABLE) + #define INTERNAL_CATCH_TESTCASE_NO_REGISTRATION( TestName, ... ) \ + static void TestName() + #define INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION( TestName, ClassName, ... ) \ + namespace{ \ + struct TestName : ClassName { \ + void test(); \ + }; \ + } \ + void TestName::test() + +#endif + /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TESTCASE2( TestName, ... ) \ static void TestName(); \ - CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ - namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &TestName, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); } /* NOLINT */ \ - CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &TestName ), CATCH_INTERNAL_LINEINFO, "", Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \ + CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \ static void TestName() #define INTERNAL_CATCH_TESTCASE( ... ) \ INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), __VA_ARGS__ ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \ - CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ - namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); } /* NOLINT */ \ - CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &QualifiedMethod ), CATCH_INTERNAL_LINEINFO, "&" #QualifiedMethod, Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \ + CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TEST_CASE_METHOD2( TestName, ClassName, ... )\ - CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ namespace{ \ struct TestName : ClassName{ \ void test(); \ }; \ - Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &TestName::test, #ClassName, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); /* NOLINT */ \ + Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( Catch::makeTestInvoker( &TestName::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \ } \ - CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \ + CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \ void TestName::test() #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... ) \ INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), ClassName, __VA_ARGS__ ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \ - CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ - Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); /* NOLINT */ \ - CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( Function ), CATCH_INTERNAL_LINEINFO, "", Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \ + CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS -#else - /////////////////////////////////////////////////////////////////////////////// - #define INTERNAL_CATCH_TESTCASE2( TestName, Name, Desc ) \ - static void TestName(); \ - CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ - namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &TestName, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); } /* NOLINT */ \ - CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \ - static void TestName() - #define INTERNAL_CATCH_TESTCASE( Name, Desc ) \ - INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), Name, Desc ) +// end catch_test_registry.h +// start catch_capture.hpp - /////////////////////////////////////////////////////////////////////////////// - #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, Name, Desc ) \ - CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ - namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( Name, Desc ), CATCH_INTERNAL_LINEINFO ); } /* NOLINT */ \ - CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS +// start catch_assertionhandler.h - /////////////////////////////////////////////////////////////////////////////// - #define INTERNAL_CATCH_TEST_CASE_METHOD2( TestCaseName, ClassName, TestName, Desc )\ - CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ - namespace{ \ - struct TestCaseName : ClassName{ \ - void test(); \ - }; \ - Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &TestCaseName::test, #ClassName, Catch::NameAndDesc( TestName, Desc ), CATCH_INTERNAL_LINEINFO ); /* NOLINT */ \ - } \ - CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \ - void TestCaseName::test() - #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, TestName, Desc )\ - INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), ClassName, TestName, Desc ) +// start catch_decomposer.h - /////////////////////////////////////////////////////////////////////////////// - #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, Name, Desc ) \ - CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ - Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); /* NOLINT */ \ - CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS - -#endif - -// #included from: internal/catch_capture.hpp -#define TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED - -// #included from: catch_result_builder.h -#define TWOBLUECUBES_CATCH_RESULT_BUILDER_H_INCLUDED - -// #included from: catch_result_type.h -#define TWOBLUECUBES_CATCH_RESULT_TYPE_H_INCLUDED - -namespace Catch { - - // ResultWas::OfType enum - struct ResultWas { enum OfType { - Unknown = -1, - Ok = 0, - Info = 1, - Warning = 2, - - FailureBit = 0x10, - - ExpressionFailed = FailureBit | 1, - ExplicitFailure = FailureBit | 2, - - Exception = 0x100 | FailureBit, - - ThrewException = Exception | 1, - DidntThrowException = Exception | 2, - - FatalErrorCondition = 0x200 | FailureBit - - }; }; - - inline bool isOk( ResultWas::OfType resultType ) { - return ( resultType & ResultWas::FailureBit ) == 0; - } - inline bool isJustInfo( int flags ) { - return flags == ResultWas::Info; - } - - // ResultDisposition::Flags enum - struct ResultDisposition { enum Flags { - Normal = 0x01, - - ContinueOnFailure = 0x02, // Failures fail test, but execution continues - FalseTest = 0x04, // Prefix expression with ! - SuppressFail = 0x08 // Failures are reported but do not fail the test - }; }; - - inline ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) { - return static_cast( static_cast( lhs ) | static_cast( rhs ) ); - } - - inline bool shouldContinueOnFailure( int flags ) { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; } - inline bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; } - inline bool shouldSuppressFailure( int flags ) { return ( flags & ResultDisposition::SuppressFail ) != 0; } - -} // end namespace Catch - -// #included from: catch_assertionresult.h -#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_H_INCLUDED - -#include - -namespace Catch { - - struct STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison; - - struct DecomposedExpression - { - virtual ~DecomposedExpression() {} - virtual bool isBinaryExpression() const { - return false; - } - virtual void reconstructExpression( std::string& dest ) const = 0; - - // Only simple binary comparisons can be decomposed. - // If more complex check is required then wrap sub-expressions in parentheses. - template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator + ( T const& ); - template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator - ( T const& ); - template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator * ( T const& ); - template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator / ( T const& ); - template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator % ( T const& ); - template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( T const& ); - template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( T const& ); - - private: - DecomposedExpression& operator = (DecomposedExpression const&); - }; - - struct AssertionInfo - { - AssertionInfo(); - AssertionInfo( char const * _macroName, - SourceLineInfo const& _lineInfo, - char const * _capturedExpression, - ResultDisposition::Flags _resultDisposition, - char const * _secondArg = ""); - - char const * macroName; - SourceLineInfo lineInfo; - char const * capturedExpression; - ResultDisposition::Flags resultDisposition; - char const * secondArg; - }; - - struct AssertionResultData - { - AssertionResultData() : decomposedExpression( CATCH_NULL ) - , resultType( ResultWas::Unknown ) - , negated( false ) - , parenthesized( false ) {} - - void negate( bool parenthesize ) { - negated = !negated; - parenthesized = parenthesize; - if( resultType == ResultWas::Ok ) - resultType = ResultWas::ExpressionFailed; - else if( resultType == ResultWas::ExpressionFailed ) - resultType = ResultWas::Ok; - } - - std::string const& reconstructExpression() const { - if( decomposedExpression != CATCH_NULL ) { - decomposedExpression->reconstructExpression( reconstructedExpression ); - if( parenthesized ) { - reconstructedExpression.insert( 0, 1, '(' ); - reconstructedExpression.append( 1, ')' ); - } - if( negated ) { - reconstructedExpression.insert( 0, 1, '!' ); - } - decomposedExpression = CATCH_NULL; - } - return reconstructedExpression; - } - - mutable DecomposedExpression const* decomposedExpression; - mutable std::string reconstructedExpression; - std::string message; - ResultWas::OfType resultType; - bool negated; - bool parenthesized; - }; - - class AssertionResult { - public: - AssertionResult(); - AssertionResult( AssertionInfo const& info, AssertionResultData const& data ); - ~AssertionResult(); -# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS - AssertionResult( AssertionResult const& ) = default; - AssertionResult( AssertionResult && ) = default; - AssertionResult& operator = ( AssertionResult const& ) = default; - AssertionResult& operator = ( AssertionResult && ) = default; -# endif - - bool isOk() const; - bool succeeded() const; - ResultWas::OfType getResultType() const; - bool hasExpression() const; - bool hasMessage() const; - std::string getExpression() const; - std::string getExpressionInMacro() const; - bool hasExpandedExpression() const; - std::string getExpandedExpression() const; - std::string getMessage() const; - SourceLineInfo getSourceInfo() const; - std::string getTestMacroName() const; - void discardDecomposedExpression() const; - void expandDecomposedExpression() const; - - protected: - AssertionInfo m_info; - AssertionResultData m_resultData; - }; - -} // end namespace Catch - -// #included from: catch_matchers.hpp -#define TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED - -namespace Catch { -namespace Matchers { - namespace Impl { - - template struct MatchAllOf; - template struct MatchAnyOf; - template struct MatchNotOf; - - class MatcherUntypedBase { - public: - std::string toString() const { - if( m_cachedToString.empty() ) - m_cachedToString = describe(); - return m_cachedToString; - } - - protected: - virtual ~MatcherUntypedBase(); - virtual std::string describe() const = 0; - mutable std::string m_cachedToString; - private: - MatcherUntypedBase& operator = ( MatcherUntypedBase const& ); - }; - - template - struct MatcherMethod { - virtual bool match( ObjectT const& arg ) const = 0; - }; - template - struct MatcherMethod { - virtual bool match( PtrT* arg ) const = 0; - }; - - template - struct MatcherBase : MatcherUntypedBase, MatcherMethod { - - MatchAllOf operator && ( MatcherBase const& other ) const; - MatchAnyOf operator || ( MatcherBase const& other ) const; - MatchNotOf operator ! () const; - }; - - template - struct MatchAllOf : MatcherBase { - virtual bool match( ArgT const& arg ) const CATCH_OVERRIDE { - for( std::size_t i = 0; i < m_matchers.size(); ++i ) { - if (!m_matchers[i]->match(arg)) - return false; - } - return true; - } - virtual std::string describe() const CATCH_OVERRIDE { - std::string description; - description.reserve( 4 + m_matchers.size()*32 ); - description += "( "; - for( std::size_t i = 0; i < m_matchers.size(); ++i ) { - if( i != 0 ) - description += " and "; - description += m_matchers[i]->toString(); - } - description += " )"; - return description; - } - - MatchAllOf& operator && ( MatcherBase const& other ) { - m_matchers.push_back( &other ); - return *this; - } - - std::vector const*> m_matchers; - }; - template - struct MatchAnyOf : MatcherBase { - - virtual bool match( ArgT const& arg ) const CATCH_OVERRIDE { - for( std::size_t i = 0; i < m_matchers.size(); ++i ) { - if (m_matchers[i]->match(arg)) - return true; - } - return false; - } - virtual std::string describe() const CATCH_OVERRIDE { - std::string description; - description.reserve( 4 + m_matchers.size()*32 ); - description += "( "; - for( std::size_t i = 0; i < m_matchers.size(); ++i ) { - if( i != 0 ) - description += " or "; - description += m_matchers[i]->toString(); - } - description += " )"; - return description; - } - - MatchAnyOf& operator || ( MatcherBase const& other ) { - m_matchers.push_back( &other ); - return *this; - } - - std::vector const*> m_matchers; - }; - - template - struct MatchNotOf : MatcherBase { - - MatchNotOf( MatcherBase const& underlyingMatcher ) : m_underlyingMatcher( underlyingMatcher ) {} - - virtual bool match( ArgT const& arg ) const CATCH_OVERRIDE { - return !m_underlyingMatcher.match( arg ); - } - - virtual std::string describe() const CATCH_OVERRIDE { - return "not " + m_underlyingMatcher.toString(); - } - MatcherBase const& m_underlyingMatcher; - }; - - template - MatchAllOf MatcherBase::operator && ( MatcherBase const& other ) const { - return MatchAllOf() && *this && other; - } - template - MatchAnyOf MatcherBase::operator || ( MatcherBase const& other ) const { - return MatchAnyOf() || *this || other; - } - template - MatchNotOf MatcherBase::operator ! () const { - return MatchNotOf( *this ); - } - - } // namespace Impl - - // The following functions create the actual matcher objects. - // This allows the types to be inferred - // - deprecated: prefer ||, && and ! - template - Impl::MatchNotOf Not( Impl::MatcherBase const& underlyingMatcher ) { - return Impl::MatchNotOf( underlyingMatcher ); - } - template - Impl::MatchAllOf AllOf( Impl::MatcherBase const& m1, Impl::MatcherBase const& m2 ) { - return Impl::MatchAllOf() && m1 && m2; - } - template - Impl::MatchAllOf AllOf( Impl::MatcherBase const& m1, Impl::MatcherBase const& m2, Impl::MatcherBase const& m3 ) { - return Impl::MatchAllOf() && m1 && m2 && m3; - } - template - Impl::MatchAnyOf AnyOf( Impl::MatcherBase const& m1, Impl::MatcherBase const& m2 ) { - return Impl::MatchAnyOf() || m1 || m2; - } - template - Impl::MatchAnyOf AnyOf( Impl::MatcherBase const& m1, Impl::MatcherBase const& m2, Impl::MatcherBase const& m3 ) { - return Impl::MatchAnyOf() || m1 || m2 || m3; - } - -} // namespace Matchers - -using namespace Matchers; -using Matchers::Impl::MatcherBase; - -} // namespace Catch - -namespace Catch { - - struct TestFailureException{}; - - template class ExpressionLhs; - - struct CopyableStream { - CopyableStream() {} - CopyableStream( CopyableStream const& other ) { - oss << other.oss.str(); - } - CopyableStream& operator=( CopyableStream const& other ) { - oss.str(std::string()); - oss << other.oss.str(); - return *this; - } - std::ostringstream oss; - }; - - class ResultBuilder : public DecomposedExpression { - public: - ResultBuilder( char const* macroName, - SourceLineInfo const& lineInfo, - char const* capturedExpression, - ResultDisposition::Flags resultDisposition, - char const* secondArg = "" ); - ~ResultBuilder(); - - template - ExpressionLhs operator <= ( T const& operand ); - ExpressionLhs operator <= ( bool value ); - - template - ResultBuilder& operator << ( T const& value ) { - stream().oss << value; - return *this; - } - - ResultBuilder& setResultType( ResultWas::OfType result ); - ResultBuilder& setResultType( bool result ); - - void endExpression( DecomposedExpression const& expr ); - - virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE; - - AssertionResult build() const; - AssertionResult build( DecomposedExpression const& expr ) const; - - void useActiveException( ResultDisposition::Flags resultDisposition = ResultDisposition::Normal ); - void captureResult( ResultWas::OfType resultType ); - void captureExpression(); - void captureExpectedException( std::string const& expectedMessage ); - void captureExpectedException( Matchers::Impl::MatcherBase const& matcher ); - void handleResult( AssertionResult const& result ); - void react(); - bool shouldDebugBreak() const; - bool allowThrows() const; - - template - void captureMatch( ArgT const& arg, MatcherT const& matcher, char const* matcherString ); - - void setExceptionGuard(); - void unsetExceptionGuard(); - - private: - AssertionInfo m_assertionInfo; - AssertionResultData m_data; - - CopyableStream &stream() - { - if(!m_usedStream) - { - m_usedStream = true; - m_stream().oss.str(""); - } - return m_stream(); - } - - static CopyableStream &m_stream() - { - static CopyableStream s; - return s; - } - - bool m_shouldDebugBreak; - bool m_shouldThrow; - bool m_guardException; - bool m_usedStream; - }; - -} // namespace Catch - -// Include after due to circular dependency: -// #included from: catch_expression_lhs.hpp -#define TWOBLUECUBES_CATCH_EXPRESSION_LHS_HPP_INCLUDED - -// #included from: catch_evaluate.hpp -#define TWOBLUECUBES_CATCH_EVALUATE_HPP_INCLUDED - -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable:4389) // '==' : signed/unsigned mismatch -#pragma warning(disable:4312) // Converting int to T* using reinterpret_cast (issue on x64 platform) -#endif - -#include - -namespace Catch { -namespace Internal { - - enum Operator { - IsEqualTo, - IsNotEqualTo, - IsLessThan, - IsGreaterThan, - IsLessThanOrEqualTo, - IsGreaterThanOrEqualTo - }; - - template struct OperatorTraits { static const char* getName(){ return "*error*"; } }; - template<> struct OperatorTraits { static const char* getName(){ return "=="; } }; - template<> struct OperatorTraits { static const char* getName(){ return "!="; } }; - template<> struct OperatorTraits { static const char* getName(){ return "<"; } }; - template<> struct OperatorTraits { static const char* getName(){ return ">"; } }; - template<> struct OperatorTraits { static const char* getName(){ return "<="; } }; - template<> struct OperatorTraits{ static const char* getName(){ return ">="; } }; - - template - T& opCast(T const& t) { return const_cast(t); } - -// nullptr_t support based on pull request #154 from Konstantin Baumann -#ifdef CATCH_CONFIG_CPP11_NULLPTR - inline std::nullptr_t opCast(std::nullptr_t) { return nullptr; } -#endif // CATCH_CONFIG_CPP11_NULLPTR - - // So the compare overloads can be operator agnostic we convey the operator as a template - // enum, which is used to specialise an Evaluator for doing the comparison. - template - struct Evaluator{}; - - template - struct Evaluator { - static bool evaluate( T1 const& lhs, T2 const& rhs) { - return bool( opCast( lhs ) == opCast( rhs ) ); - } - }; - template - struct Evaluator { - static bool evaluate( T1 const& lhs, T2 const& rhs ) { - return bool( opCast( lhs ) != opCast( rhs ) ); - } - }; - template - struct Evaluator { - static bool evaluate( T1 const& lhs, T2 const& rhs ) { - return bool( opCast( lhs ) < opCast( rhs ) ); - } - }; - template - struct Evaluator { - static bool evaluate( T1 const& lhs, T2 const& rhs ) { - return bool( opCast( lhs ) > opCast( rhs ) ); - } - }; - template - struct Evaluator { - static bool evaluate( T1 const& lhs, T2 const& rhs ) { - return bool( opCast( lhs ) >= opCast( rhs ) ); - } - }; - template - struct Evaluator { - static bool evaluate( T1 const& lhs, T2 const& rhs ) { - return bool( opCast( lhs ) <= opCast( rhs ) ); - } - }; - - template - bool applyEvaluator( T1 const& lhs, T2 const& rhs ) { - return Evaluator::evaluate( lhs, rhs ); - } - - // This level of indirection allows us to specialise for integer types - // to avoid signed/ unsigned warnings - - // "base" overload - template - bool compare( T1 const& lhs, T2 const& rhs ) { - return Evaluator::evaluate( lhs, rhs ); - } - - // unsigned X to int - template bool compare( unsigned int lhs, int rhs ) { - return applyEvaluator( lhs, static_cast( rhs ) ); - } - template bool compare( unsigned long lhs, int rhs ) { - return applyEvaluator( lhs, static_cast( rhs ) ); - } - template bool compare( unsigned char lhs, int rhs ) { - return applyEvaluator( lhs, static_cast( rhs ) ); - } - - // unsigned X to long - template bool compare( unsigned int lhs, long rhs ) { - return applyEvaluator( lhs, static_cast( rhs ) ); - } - template bool compare( unsigned long lhs, long rhs ) { - return applyEvaluator( lhs, static_cast( rhs ) ); - } - template bool compare( unsigned char lhs, long rhs ) { - return applyEvaluator( lhs, static_cast( rhs ) ); - } - - // int to unsigned X - template bool compare( int lhs, unsigned int rhs ) { - return applyEvaluator( static_cast( lhs ), rhs ); - } - template bool compare( int lhs, unsigned long rhs ) { - return applyEvaluator( static_cast( lhs ), rhs ); - } - template bool compare( int lhs, unsigned char rhs ) { - return applyEvaluator( static_cast( lhs ), rhs ); - } - - // long to unsigned X - template bool compare( long lhs, unsigned int rhs ) { - return applyEvaluator( static_cast( lhs ), rhs ); - } - template bool compare( long lhs, unsigned long rhs ) { - return applyEvaluator( static_cast( lhs ), rhs ); - } - template bool compare( long lhs, unsigned char rhs ) { - return applyEvaluator( static_cast( lhs ), rhs ); - } - - // pointer to long (when comparing against NULL) - template bool compare( long lhs, T* rhs ) { - return Evaluator::evaluate( reinterpret_cast( lhs ), rhs ); - } - template bool compare( T* lhs, long rhs ) { - return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); - } - - // pointer to int (when comparing against NULL) - template bool compare( int lhs, T* rhs ) { - return Evaluator::evaluate( reinterpret_cast( lhs ), rhs ); - } - template bool compare( T* lhs, int rhs ) { - return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); - } - -#ifdef CATCH_CONFIG_CPP11_LONG_LONG - // long long to unsigned X - template bool compare( long long lhs, unsigned int rhs ) { - return applyEvaluator( static_cast( lhs ), rhs ); - } - template bool compare( long long lhs, unsigned long rhs ) { - return applyEvaluator( static_cast( lhs ), rhs ); - } - template bool compare( long long lhs, unsigned long long rhs ) { - return applyEvaluator( static_cast( lhs ), rhs ); - } - template bool compare( long long lhs, unsigned char rhs ) { - return applyEvaluator( static_cast( lhs ), rhs ); - } - - // unsigned long long to X - template bool compare( unsigned long long lhs, int rhs ) { - return applyEvaluator( static_cast( lhs ), rhs ); - } - template bool compare( unsigned long long lhs, long rhs ) { - return applyEvaluator( static_cast( lhs ), rhs ); - } - template bool compare( unsigned long long lhs, long long rhs ) { - return applyEvaluator( static_cast( lhs ), rhs ); - } - template bool compare( unsigned long long lhs, char rhs ) { - return applyEvaluator( static_cast( lhs ), rhs ); - } - - // pointer to long long (when comparing against NULL) - template bool compare( long long lhs, T* rhs ) { - return Evaluator::evaluate( reinterpret_cast( lhs ), rhs ); - } - template bool compare( T* lhs, long long rhs ) { - return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); - } -#endif // CATCH_CONFIG_CPP11_LONG_LONG - -#ifdef CATCH_CONFIG_CPP11_NULLPTR - // pointer to nullptr_t (when comparing against nullptr) - template bool compare( std::nullptr_t, T* rhs ) { - return Evaluator::evaluate( nullptr, rhs ); - } - template bool compare( T* lhs, std::nullptr_t ) { - return Evaluator::evaluate( lhs, nullptr ); - } -#endif // CATCH_CONFIG_CPP11_NULLPTR - -} // end of namespace Internal -} // end of namespace Catch - -#ifdef _MSC_VER -#pragma warning(pop) -#endif - -// #included from: catch_tostring.h -#define TWOBLUECUBES_CATCH_TOSTRING_H_INCLUDED +// start catch_tostring.h #include -#include -#include #include #include +#include +#include #ifdef __OBJC__ -// #included from: catch_objc_arc.hpp -#define TWOBLUECUBES_CATCH_OBJC_ARC_HPP_INCLUDED +// start catch_objc_arc.hpp #import @@ -1548,451 +526,735 @@ inline id performOptionalSelector( id obj, SEL sel ) { #define CATCH_ARC_STRONG __strong #endif +// end catch_objc_arc.hpp #endif -#ifdef CATCH_CONFIG_CPP11_TUPLE -#include +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4180) // We attempt to stream a function (address) by const&, which MSVC complains about but is harmless #endif -#ifdef CATCH_CONFIG_CPP11_IS_ENUM -#include -#endif +// We need a dummy global operator<< so we can bring it into Catch namespace later +struct Catch_global_namespace_dummy; +std::ostream& operator<<(std::ostream&, Catch_global_namespace_dummy); namespace Catch { + // Bring in operator<< from global namespace into Catch namespace + using ::operator<<; -// Why we're here. -template -std::string toString( T const& value ); + namespace Detail { -// Built in overloads + extern const std::string unprintableString; -std::string toString( std::string const& value ); -std::string toString( std::wstring const& value ); -std::string toString( const char* const value ); -std::string toString( char* const value ); -std::string toString( const wchar_t* const value ); -std::string toString( wchar_t* const value ); -std::string toString( int value ); -std::string toString( unsigned long value ); -std::string toString( unsigned int value ); -std::string toString( const double value ); -std::string toString( const float value ); -std::string toString( bool value ); -std::string toString( char value ); -std::string toString( signed char value ); -std::string toString( unsigned char value ); + std::string rawMemoryToString( const void *object, std::size_t size ); -#ifdef CATCH_CONFIG_CPP11_LONG_LONG -std::string toString( long long value ); -std::string toString( unsigned long long value ); -#endif + template + std::string rawMemoryToString( const T& object ) { + return rawMemoryToString( &object, sizeof(object) ); + } -#ifdef CATCH_CONFIG_CPP11_NULLPTR -std::string toString( std::nullptr_t ); -#endif + template + class IsStreamInsertable { + template + static auto test(int) + -> decltype(std::declval() << std::declval(), std::true_type()); -#ifdef __OBJC__ - std::string toString( NSString const * const& nsstring ); - std::string toString( NSString * CATCH_ARC_STRONG & nsstring ); - std::string toString( NSObject* const& nsObject ); -#endif + template + static auto test(...)->std::false_type; -namespace Detail { + public: + static const bool value = decltype(test(0))::value; + }; - extern const std::string unprintableString; + } // namespace Detail - #if !defined(CATCH_CONFIG_CPP11_STREAM_INSERTABLE_CHECK) - struct BorgType { - template BorgType( T const& ); - }; + // If we decide for C++14, change these to enable_if_ts + template + struct StringMaker { + template + static + typename std::enable_if<::Catch::Detail::IsStreamInsertable::value, std::string>::type + convert(const Fake& t) { + std::ostringstream sstr; + sstr << t; + return sstr.str(); + } - struct TrueType { char sizer[1]; }; - struct FalseType { char sizer[2]; }; - - TrueType& testStreamable( std::ostream& ); - FalseType testStreamable( FalseType ); - - FalseType operator<<( std::ostream const&, BorgType const& ); - - template - struct IsStreamInsertable { - static std::ostream &s; - static T const&t; - enum { value = sizeof( testStreamable(s << t) ) == sizeof( TrueType ) }; - }; -#else - template - class IsStreamInsertable { - template - static auto test(int) - -> decltype( std::declval() << std::declval(), std::true_type() ); - - template - static auto test(...) -> std::false_type; - - public: - static const bool value = decltype(test(0))::value; - }; -#endif - -#if defined(CATCH_CONFIG_CPP11_IS_ENUM) - template::value - > - struct EnumStringMaker - { - static std::string convert( T const& ) { return unprintableString; } - }; - - template - struct EnumStringMaker - { - static std::string convert( T const& v ) - { - return ::Catch::toString( - static_cast::type>(v) - ); + template + static + typename std::enable_if::value, std::string>::type + convert(const Fake&) { + return Detail::unprintableString; } }; -#endif - template - struct StringMakerBase { -#if defined(CATCH_CONFIG_CPP11_IS_ENUM) - template - static std::string convert( T const& v ) - { - return EnumStringMaker::convert( v ); + + namespace Detail { + + // This function dispatches all stringification requests inside of Catch. + // Should be preferably called fully qualified, like ::Catch::Detail::stringify + template + std::string stringify(const T& e) { + return ::Catch::StringMaker::type>::type>::convert(e); } -#else - template - static std::string convert( T const& ) { return unprintableString; } -#endif + + } // namespace Detail + + // Some predefined specializations + + template<> + struct StringMaker { + static std::string convert(const std::string& str); + }; + template<> + struct StringMaker { + static std::string convert(const std::wstring& wstr); }; template<> - struct StringMakerBase { - template - static std::string convert( T const& _value ) { + struct StringMaker { + static std::string convert(char const * str); + }; + template<> + struct StringMaker { + static std::string convert(char * str); + }; + template<> + struct StringMaker { + static std::string convert(wchar_t const * str); + }; + template<> + struct StringMaker { + static std::string convert(wchar_t * str); + }; + + template + struct StringMaker { + static std::string convert(const char* str) { + return ::Catch::Detail::stringify(std::string{ str }); + } + }; + template + struct StringMaker { + static std::string convert(const char* str) { + return ::Catch::Detail::stringify(std::string{ str }); + } + }; + template + struct StringMaker { + static std::string convert(const char* str) { + return ::Catch::Detail::stringify(std::string{ str }); + } + }; + + template<> + struct StringMaker { + static std::string convert(int value); + }; + template<> + struct StringMaker { + static std::string convert(long value); + }; + template<> + struct StringMaker { + static std::string convert(long long value); + }; + template<> + struct StringMaker { + static std::string convert(unsigned int value); + }; + template<> + struct StringMaker { + static std::string convert(unsigned long value); + }; + template<> + struct StringMaker { + static std::string convert(unsigned long long value); + }; + + template<> + struct StringMaker { + static std::string convert(bool b); + }; + + template<> + struct StringMaker { + static std::string convert(char c); + }; + template<> + struct StringMaker { + static std::string convert(signed char c); + }; + template<> + struct StringMaker { + static std::string convert(unsigned char c); + }; + + template<> + struct StringMaker { + static std::string convert(std::nullptr_t); + }; + + template<> + struct StringMaker { + static std::string convert(float value); + }; + template<> + struct StringMaker { + static std::string convert(double value); + }; + + template + struct StringMaker { + template + static std::string convert(U* p) { + if (p) { + return ::Catch::Detail::rawMemoryToString(p); + } else { + return "nullptr"; + } + } + }; + + template + struct StringMaker { + static std::string convert(R C::* p) { + if (p) { + return ::Catch::Detail::rawMemoryToString(p); + } else { + return "nullptr"; + } + } + }; + + namespace Detail { + template + std::string rangeToString(InputIterator first, InputIterator last) { std::ostringstream oss; - oss << _value; + oss << "{ "; + if (first != last) { + oss << ::Catch::Detail::stringify(*first); + for (++first; first != last; ++first) + oss << ", " << ::Catch::Detail::stringify(*first); + } + oss << " }"; + return oss.str(); + } + } + + template + struct StringMaker > { + static std::string convert( std::vector const& v ) { + return ::Catch::Detail::rangeToString( v.begin(), v.end() ); + } + }; + + template + struct EnumStringMaker { + static std::string convert(const T& t) { + return ::Catch::Detail::stringify(static_cast::type>(t)); + } + }; + +#ifdef __OBJC__ + template<> + struct StringMaker { + static std::string convert(NSString * nsstring) { + if (!nsstring) + return "nil"; + return std::string("@") + [nsstring UTF8String]; + } + }; + template<> + struct StringMaker { + static std::string convert(NSObject* nsObject) { + return ::Catch::Detail::stringify([nsObject description]); + } + + }; + namespace Detail { + inline std::string stringify( NSString* nsstring ) { + return StringMaker::convert( nsstring ); + } + + } // namespace Detail +#endif // __OBJC__ + +} // namespace Catch + +////////////////////////////////////////////////////// +// Separate std-lib types stringification, so it can be selectively enabled +// This means that we do not bring in + +#if defined(CATCH_CONFIG_ENABLE_ALL_STRINGMAKERS) +# define CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER +# define CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER +# define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER +#endif + +// Separate std::pair specialization +#if defined(CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER) +#include +namespace Catch { + template + struct StringMaker > { + static std::string convert(const std::pair& pair) { + std::ostringstream oss; + oss << "{ " + << ::Catch::Detail::stringify(pair.first) + << ", " + << ::Catch::Detail::stringify(pair.second) + << " }"; + return oss.str(); + } + }; +} +#endif // CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER + +// Separate std::tuple specialization +#if defined(CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER) +#include +namespace Catch { + namespace Detail { + template< + typename Tuple, + std::size_t N = 0, + bool = (N < std::tuple_size::value) + > + struct TupleElementPrinter { + static void print(const Tuple& tuple, std::ostream& os) { + os << (N ? ", " : " ") + << ::Catch::Detail::stringify(std::get(tuple)); + TupleElementPrinter::print(tuple, os); + } + }; + + template< + typename Tuple, + std::size_t N + > + struct TupleElementPrinter { + static void print(const Tuple&, std::ostream&) {} + }; + + } + + template + struct StringMaker> { + static std::string convert(const std::tuple& tuple) { + std::ostringstream os; + os << '{'; + Detail::TupleElementPrinter>::print(tuple, os); + os << " }"; + return os.str(); + } + }; +} +#endif // CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER + +// Separate std::chrono::duration specialization +#if defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER) +#include +#include +#include + +template +struct ratio_string { + static std::string symbol(); +}; + +template +std::string ratio_string::symbol() { + std::ostringstream oss; + oss << '[' << Ratio::num << '/' + << Ratio::den << ']'; + return oss.str(); +} +template <> +struct ratio_string { + static std::string symbol() { return "a"; } +}; +template <> +struct ratio_string { + static std::string symbol() { return "f"; } +}; +template <> +struct ratio_string { + static std::string symbol() { return "p"; } +}; +template <> +struct ratio_string { + static std::string symbol() { return "n"; } +}; +template <> +struct ratio_string { + static std::string symbol() { return "u"; } +}; +template <> +struct ratio_string { + static std::string symbol() { return "m"; } +}; + +namespace Catch { + //////////// + // std::chrono::duration specializations + template + struct StringMaker> { + static std::string convert(std::chrono::duration const& duration) { + std::ostringstream oss; + oss << duration.count() << ' ' << ratio_string::symbol() << 's'; + return oss.str(); + } + }; + template + struct StringMaker>> { + static std::string convert(std::chrono::duration> const& duration) { + std::ostringstream oss; + oss << duration.count() << " s"; + return oss.str(); + } + }; + template + struct StringMaker>> { + static std::string convert(std::chrono::duration> const& duration) { + std::ostringstream oss; + oss << duration.count() << " m"; + return oss.str(); + } + }; + template + struct StringMaker>> { + static std::string convert(std::chrono::duration> const& duration) { + std::ostringstream oss; + oss << duration.count() << " h"; return oss.str(); } }; - std::string rawMemoryToString( const void *object, std::size_t size ); - - template - std::string rawMemoryToString( const T& object ) { - return rawMemoryToString( &object, sizeof(object) ); - } - -} // end namespace Detail - -template -struct StringMaker : - Detail::StringMakerBase::value> {}; - -template -struct StringMaker { - template - static std::string convert( U* p ) { - if( !p ) - return "NULL"; - else - return Detail::rawMemoryToString( p ); - } -}; - -template -struct StringMaker { - static std::string convert( R C::* p ) { - if( !p ) - return "NULL"; - else - return Detail::rawMemoryToString( p ); - } -}; - -namespace Detail { - template - std::string rangeToString( InputIterator first, InputIterator last ); -} - -//template -//struct StringMaker > { -// static std::string convert( std::vector const& v ) { -// return Detail::rangeToString( v.begin(), v.end() ); -// } -//}; - -template -std::string toString( std::vector const& v ) { - return Detail::rangeToString( v.begin(), v.end() ); -} - -#ifdef CATCH_CONFIG_CPP11_TUPLE - -// toString for tuples -namespace TupleDetail { - template< - typename Tuple, - std::size_t N = 0, - bool = (N < std::tuple_size::value) - > - struct ElementPrinter { - static void print( const Tuple& tuple, std::ostream& os ) - { - os << ( N ? ", " : " " ) - << Catch::toString(std::get(tuple)); - ElementPrinter::print(tuple,os); - } - }; - - template< - typename Tuple, - std::size_t N - > - struct ElementPrinter { - static void print( const Tuple&, std::ostream& ) {} - }; - -} - -template -struct StringMaker> { - - static std::string convert( const std::tuple& tuple ) - { - std::ostringstream os; - os << '{'; - TupleDetail::ElementPrinter>::print( tuple, os ); - os << " }"; - return os.str(); - } -}; -#endif // CATCH_CONFIG_CPP11_TUPLE - -namespace Detail { - template - std::string makeString( T const& value ) { - return StringMaker::convert( value ); - } -} // end namespace Detail - -/// \brief converts any type to a string -/// -/// The default template forwards on to ostringstream - except when an -/// ostringstream overload does not exist - in which case it attempts to detect -/// that and writes {?}. -/// Overload (not specialise) this template for custom typs that you don't want -/// to provide an ostream overload for. -template -std::string toString( T const& value ) { - return StringMaker::convert( value ); -} - - namespace Detail { - template - std::string rangeToString( InputIterator first, InputIterator last ) { - std::ostringstream oss; - oss << "{ "; - if( first != last ) { - oss << Catch::toString( *first ); - for( ++first ; first != last ; ++first ) - oss << ", " << Catch::toString( *first ); + //////////// + // std::chrono::time_point specialization + // Generic time_point cannot be specialized, only std::chrono::time_point + template + struct StringMaker> { + static std::string convert(std::chrono::time_point const& time_point) { + return ::Catch::Detail::stringify(time_point.time_since_epoch()) + " since epoch"; } - oss << " }"; - return oss.str(); - } + }; + // std::chrono::time_point specialization + template + struct StringMaker> { + static std::string convert(std::chrono::time_point const& time_point) { + auto converted = std::chrono::system_clock::to_time_t(time_point); + +#ifdef _MSC_VER + std::tm timeInfo = {}; + gmtime_s(&timeInfo, &converted); +#else + std::tm* timeInfo = std::gmtime(&converted); +#endif + + auto const timeStampSize = sizeof("2017-01-16T17:06:45Z"); + char timeStamp[timeStampSize]; + const char * const fmt = "%Y-%m-%dT%H:%M:%SZ"; + +#ifdef _MSC_VER + std::strftime(timeStamp, timeStampSize, fmt, &timeInfo); +#else + std::strftime(timeStamp, timeStampSize, fmt, timeInfo); +#endif + return std::string(timeStamp); + } + }; } +#endif // CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER -} // end namespace Catch +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +// end catch_tostring.h +#include + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4389) // '==' : signed/unsigned mismatch +#pragma warning(disable:4018) // more "signed/unsigned mismatch" +#pragma warning(disable:4312) // Converting int to T* using reinterpret_cast (issue on x64 platform) +#pragma warning(disable:4180) // qualifier applied to function type has no meaning +#endif namespace Catch { -template -class BinaryExpression; + struct ITransientExpression { + virtual auto isBinaryExpression() const -> bool = 0; + virtual auto getResult() const -> bool = 0; + virtual void streamReconstructedExpression( std::ostream &os ) const = 0; -template -class MatchExpression; + // We don't actually need a virtual destructore, but many static analysers + // complain if it's not here :-( + virtual ~ITransientExpression(); + }; -// Wraps the LHS of an expression and overloads comparison operators -// for also capturing those and RHS (if any) -template -class ExpressionLhs : public DecomposedExpression { -public: - ExpressionLhs( ResultBuilder& rb, T lhs ) : m_rb( rb ), m_lhs( lhs ), m_truthy(false) {} + void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs ); - ExpressionLhs& operator = ( const ExpressionLhs& ); + template + class BinaryExpr : public ITransientExpression { + bool m_result; + LhsT m_lhs; + StringRef m_op; + RhsT m_rhs; - template - BinaryExpression - operator == ( RhsT const& rhs ) { - return captureExpression( rhs ); - } + auto isBinaryExpression() const -> bool override { return true; } + auto getResult() const -> bool override { return m_result; } - template - BinaryExpression - operator != ( RhsT const& rhs ) { - return captureExpression( rhs ); - } + void streamReconstructedExpression( std::ostream &os ) const override { + formatReconstructedExpression + ( os, Catch::Detail::stringify( m_lhs ), m_op, Catch::Detail::stringify( m_rhs ) ); + } - template - BinaryExpression - operator < ( RhsT const& rhs ) { - return captureExpression( rhs ); - } + public: + BinaryExpr( bool comparisonResult, LhsT lhs, StringRef op, RhsT rhs ) + : m_result( comparisonResult ), + m_lhs( lhs ), + m_op( op ), + m_rhs( rhs ) + {} + }; - template - BinaryExpression - operator > ( RhsT const& rhs ) { - return captureExpression( rhs ); - } + template + class UnaryExpr : public ITransientExpression { + LhsT m_lhs; - template - BinaryExpression - operator <= ( RhsT const& rhs ) { - return captureExpression( rhs ); - } + auto isBinaryExpression() const -> bool override { return false; } + auto getResult() const -> bool override { return m_lhs ? true : false; } - template - BinaryExpression - operator >= ( RhsT const& rhs ) { - return captureExpression( rhs ); - } + void streamReconstructedExpression( std::ostream &os ) const override { + os << Catch::Detail::stringify( m_lhs ); + } - BinaryExpression operator == ( bool rhs ) { - return captureExpression( rhs ); - } + public: + UnaryExpr( LhsT lhs ) : m_lhs( lhs ) {} + }; - BinaryExpression operator != ( bool rhs ) { - return captureExpression( rhs ); - } + // Specialised comparison functions to handle equality comparisons between ints and pointers (NULL deduces as an int) + template + auto compareEqual( LhsT const& lhs, RhsT const& rhs ) -> bool { return lhs == rhs; }; + template + auto compareEqual( T* const& lhs, int rhs ) -> bool { return lhs == reinterpret_cast( rhs ); } + template + auto compareEqual( T* const& lhs, long rhs ) -> bool { return lhs == reinterpret_cast( rhs ); } + template + auto compareEqual( int lhs, T* const& rhs ) -> bool { return reinterpret_cast( lhs ) == rhs; } + template + auto compareEqual( long lhs, T* const& rhs ) -> bool { return reinterpret_cast( lhs ) == rhs; } - void endExpression() { - m_truthy = m_lhs ? true : false; - m_rb - .setResultType( m_truthy ) - .endExpression( *this ); - } + template + auto compareNotEqual( LhsT const& lhs, RhsT&& rhs ) -> bool { return lhs != rhs; }; + template + auto compareNotEqual( T* const& lhs, int rhs ) -> bool { return lhs != reinterpret_cast( rhs ); } + template + auto compareNotEqual( T* const& lhs, long rhs ) -> bool { return lhs != reinterpret_cast( rhs ); } + template + auto compareNotEqual( int lhs, T* const& rhs ) -> bool { return reinterpret_cast( lhs ) != rhs; } + template + auto compareNotEqual( long lhs, T* const& rhs ) -> bool { return reinterpret_cast( lhs ) != rhs; } - virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE { - dest = Catch::toString( m_lhs ); - } + template + class ExprLhs { + LhsT m_lhs; + public: + ExprLhs( LhsT lhs ) : m_lhs( lhs ) {} -private: - template - BinaryExpression captureExpression( RhsT& rhs ) const { - return BinaryExpression( m_rb, m_lhs, rhs ); - } + template + auto operator == ( RhsT const& rhs ) -> BinaryExpr const { + return BinaryExpr( compareEqual( m_lhs, rhs ), m_lhs, "==", rhs ); + } + auto operator == ( bool rhs ) -> BinaryExpr const { + return BinaryExpr( m_lhs == rhs, m_lhs, "==", rhs ); + } - template - BinaryExpression captureExpression( bool rhs ) const { - return BinaryExpression( m_rb, m_lhs, rhs ); - } + template + auto operator != ( RhsT const& rhs ) -> BinaryExpr const { + return BinaryExpr( compareNotEqual( m_lhs, rhs ), m_lhs, "!=", rhs ); + } + auto operator != ( bool rhs ) -> BinaryExpr const { + return BinaryExpr( m_lhs != rhs, m_lhs, "!=", rhs ); + } -private: - ResultBuilder& m_rb; - T m_lhs; - bool m_truthy; -}; + template + auto operator > ( RhsT const& rhs ) -> BinaryExpr const { + return BinaryExpr( m_lhs > rhs, m_lhs, ">", rhs ); + } + template + auto operator < ( RhsT const& rhs ) -> BinaryExpr const { + return BinaryExpr( m_lhs < rhs, m_lhs, "<", rhs ); + } + template + auto operator >= ( RhsT const& rhs ) -> BinaryExpr const { + return BinaryExpr( m_lhs >= rhs, m_lhs, ">=", rhs ); + } + template + auto operator <= ( RhsT const& rhs ) -> BinaryExpr const { + return BinaryExpr( m_lhs <= rhs, m_lhs, "<=", rhs ); + } -template -class BinaryExpression : public DecomposedExpression { -public: - BinaryExpression( ResultBuilder& rb, LhsT lhs, RhsT rhs ) - : m_rb( rb ), m_lhs( lhs ), m_rhs( rhs ) {} + auto makeUnaryExpr() const -> UnaryExpr { + return UnaryExpr( m_lhs ); + } + }; - BinaryExpression& operator = ( BinaryExpression& ); - - void endExpression() const { - m_rb - .setResultType( Internal::compare( m_lhs, m_rhs ) ) - .endExpression( *this ); - } - - virtual bool isBinaryExpression() const CATCH_OVERRIDE { - return true; - } - - virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE { - std::string lhs = Catch::toString( m_lhs ); - std::string rhs = Catch::toString( m_rhs ); - char delim = lhs.size() + rhs.size() < 40 && - lhs.find('\n') == std::string::npos && - rhs.find('\n') == std::string::npos ? ' ' : '\n'; - dest.reserve( 7 + lhs.size() + rhs.size() ); - // 2 for spaces around operator - // 2 for operator - // 2 for parentheses (conditionally added later) - // 1 for negation (conditionally added later) - dest = lhs; - dest += delim; - dest += Internal::OperatorTraits::getName(); - dest += delim; - dest += rhs; - } - -private: - ResultBuilder& m_rb; - LhsT m_lhs; - RhsT m_rhs; -}; - -template -class MatchExpression : public DecomposedExpression { -public: - MatchExpression( ArgT arg, MatcherT matcher, char const* matcherString ) - : m_arg( arg ), m_matcher( matcher ), m_matcherString( matcherString ) {} - - virtual bool isBinaryExpression() const CATCH_OVERRIDE { - return true; - } - - virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE { - std::string matcherAsString = m_matcher.toString(); - dest = Catch::toString( m_arg ); - dest += ' '; - if( matcherAsString == Detail::unprintableString ) - dest += m_matcherString; - else - dest += matcherAsString; - } - -private: - ArgT m_arg; - MatcherT m_matcher; - char const* m_matcherString; -}; - -} // end namespace Catch - - -namespace Catch { + void handleExpression( ITransientExpression const& expr ); template - ExpressionLhs ResultBuilder::operator <= ( T const& operand ) { - return ExpressionLhs( *this, operand ); + void handleExpression( ExprLhs const& expr ) { + handleExpression( expr.makeUnaryExpr() ); } - inline ExpressionLhs ResultBuilder::operator <= ( bool value ) { - return ExpressionLhs( *this, value ); - } + struct Decomposer { + template + auto operator <= ( T const& lhs ) -> ExprLhs { + return ExprLhs( lhs ); + } + auto operator <=( bool value ) -> ExprLhs { + return ExprLhs( value ); + } + }; - template - void ResultBuilder::captureMatch( ArgT const& arg, MatcherT const& matcher, - char const* matcherString ) { - MatchExpression expr( arg, matcher, matcherString ); - setResultType( matcher.match( arg ) ); - endExpression( expr ); - } +} // end namespace Catch + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +// end catch_decomposer.h +// start catch_assertioninfo.h + +// start catch_result_type.h + +namespace Catch { + + // ResultWas::OfType enum + struct ResultWas { enum OfType { + Unknown = -1, + Ok = 0, + Info = 1, + Warning = 2, + + FailureBit = 0x10, + + ExpressionFailed = FailureBit | 1, + ExplicitFailure = FailureBit | 2, + + Exception = 0x100 | FailureBit, + + ThrewException = Exception | 1, + DidntThrowException = Exception | 2, + + FatalErrorCondition = 0x200 | FailureBit + + }; }; + + bool isOk( ResultWas::OfType resultType ); + bool isJustInfo( int flags ); + + // ResultDisposition::Flags enum + struct ResultDisposition { enum Flags { + Normal = 0x01, + + ContinueOnFailure = 0x02, // Failures fail test, but execution continues + FalseTest = 0x04, // Prefix expression with ! + SuppressFail = 0x08 // Failures are reported but do not fail the test + }; }; + + ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ); + + bool shouldContinueOnFailure( int flags ); + bool isFalseTest( int flags ); + bool shouldSuppressFailure( int flags ); + +} // end namespace Catch + +// end catch_result_type.h +namespace Catch { + + struct AssertionInfo + { + StringRef macroName; + SourceLineInfo lineInfo; + StringRef capturedExpression; + ResultDisposition::Flags resultDisposition; + + // We want to delete this constructor but a compiler bug in 4.8 means + // the struct is then treated as non-aggregate + //AssertionInfo() = delete; + }; + +} // end namespace Catch + +// end catch_assertioninfo.h +namespace Catch { + + struct TestFailureException{}; + struct AssertionResultData; + + class LazyExpression { + friend class AssertionHandler; + friend struct AssertionStats; + + ITransientExpression const* m_transientExpression = nullptr; + bool m_isNegated; + public: + LazyExpression( bool isNegated ); + LazyExpression( LazyExpression const& other ); + LazyExpression& operator = ( LazyExpression const& ) = delete; + + explicit operator bool() const; + + friend auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream&; + }; + + class AssertionHandler { + AssertionInfo m_assertionInfo; + bool m_shouldDebugBreak = false; + bool m_shouldThrow = false; + bool m_inExceptionGuard = false; + + public: + AssertionHandler + ( StringRef macroName, + SourceLineInfo const& lineInfo, + StringRef capturedExpression, + ResultDisposition::Flags resultDisposition ); + ~AssertionHandler(); + + void handle( ITransientExpression const& expr ); + + template + void handle( ExprLhs const& expr ) { + handle( expr.makeUnaryExpr() ); + } + void handle( ResultWas::OfType resultType ); + void handle( ResultWas::OfType resultType, StringRef const& message ); + void handle( ResultWas::OfType resultType, ITransientExpression const* expr, bool negated ); + void handle( AssertionResultData const& resultData, ITransientExpression const* expr ); + + auto shouldDebugBreak() const -> bool; + auto allowThrows() const -> bool; + void reactWithDebugBreak() const; + void reactWithoutDebugBreak() const; + void useActiveException(); + void setExceptionGuard(); + void unsetExceptionGuard(); + }; + + void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef matcherString ); } // namespace Catch -// #included from: catch_message.h -#define TWOBLUECUBES_CATCH_MESSAGE_H_INCLUDED +// end catch_assertionhandler.h +// start catch_message.h #include +#include namespace Catch { @@ -2002,27 +1264,33 @@ namespace Catch { ResultWas::OfType _type ); std::string macroName; + std::string message; SourceLineInfo lineInfo; ResultWas::OfType type; - std::string message; unsigned int sequence; - bool operator == ( MessageInfo const& other ) const { - return sequence == other.sequence; - } - bool operator < ( MessageInfo const& other ) const { - return sequence < other.sequence; - } + bool operator == ( MessageInfo const& other ) const; + bool operator < ( MessageInfo const& other ) const; private: static unsigned int globalCount; }; - struct MessageBuilder { + struct MessageStream { + + template + MessageStream& operator << ( T const& value ) { + m_stream << value; + return *this; + } + + // !TBD reuse a global/ thread-local stream + std::ostringstream m_stream; + }; + + struct MessageBuilder : MessageStream { MessageBuilder( std::string const& macroName, SourceLineInfo const& lineInfo, - ResultWas::OfType type ) - : m_info( macroName, lineInfo, type ) - {} + ResultWas::OfType type ); template MessageBuilder& operator << ( T const& value ) { @@ -2031,13 +1299,11 @@ namespace Catch { } MessageInfo m_info; - std::ostringstream m_stream; }; class ScopedMessage { public: ScopedMessage( MessageBuilder const& builder ); - ScopedMessage( ScopedMessage const& other ); ~ScopedMessage(); MessageInfo m_info; @@ -2045,31 +1311,36 @@ namespace Catch { } // end namespace Catch -// #included from: catch_interfaces_capture.h -#define TWOBLUECUBES_CATCH_INTERFACES_CAPTURE_H_INCLUDED +// end catch_message.h +// start catch_interfaces_capture.h #include namespace Catch { - class TestCase; class AssertionResult; struct AssertionInfo; struct SectionInfo; struct SectionEndInfo; struct MessageInfo; - class ScopedMessageBuilder; struct Counts; + struct BenchmarkInfo; + struct BenchmarkStats; struct IResultCapture { virtual ~IResultCapture(); + virtual void assertionStarting( AssertionInfo const& info ) = 0; virtual void assertionEnded( AssertionResult const& result ) = 0; virtual bool sectionStarted( SectionInfo const& sectionInfo, Counts& assertions ) = 0; virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0; virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0; + + virtual void benchmarkStarting( BenchmarkInfo const& info ) = 0; + virtual void benchmarkEnded( BenchmarkStats const& stats ) = 0; + virtual void pushScopedMessage( MessageInfo const& message ) = 0; virtual void popScopedMessage( MessageInfo const& message ) = 0; @@ -2078,7 +1349,7 @@ namespace Catch { virtual void exceptionEarlyReported() = 0; - virtual void handleFatalErrorCondition( std::string const& message ) = 0; + virtual void handleFatalErrorCondition( StringRef message ) = 0; virtual bool lastAssertionPassed() = 0; virtual void assertionPassed() = 0; @@ -2088,47 +1359,16 @@ namespace Catch { IResultCapture& getResultCapture(); } -// #included from: catch_debugger.h -#define TWOBLUECUBES_CATCH_DEBUGGER_H_INCLUDED - -// #included from: catch_platform.h -#define TWOBLUECUBES_CATCH_PLATFORM_H_INCLUDED - -#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) -# define CATCH_PLATFORM_MAC -#elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED) -# define CATCH_PLATFORM_IPHONE -#elif defined(linux) || defined(__linux) || defined(__linux__) -# define CATCH_PLATFORM_LINUX -#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) -# define CATCH_PLATFORM_WINDOWS -# if !defined(NOMINMAX) && !defined(CATCH_CONFIG_NO_NOMINMAX) -# define CATCH_DEFINES_NOMINMAX -# endif -# if !defined(WIN32_LEAN_AND_MEAN) && !defined(CATCH_CONFIG_NO_WIN32_LEAN_AND_MEAN) -# define CATCH_DEFINES_WIN32_LEAN_AND_MEAN -# endif -#endif - -#include - -namespace Catch{ +// end catch_interfaces_capture.h +// start catch_debugger.h +namespace Catch { bool isDebuggerActive(); - void writeToDebugConsole( std::string const& text ); } #ifdef CATCH_PLATFORM_MAC - // The following code snippet based on: - // http://cocoawithlove.com/2008/03/break-into-debugger.html - #if defined(__ppc64__) || defined(__ppc__) - #define CATCH_TRAP() \ - __asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" \ - : : : "memory","r0","r3","r4" ) /* NOLINT */ - #else - #define CATCH_TRAP() __asm__("int $3\n" : : /* NOLINT */ ) - #endif + #define CATCH_TRAP() __asm__("int $3\n" : : ) /* NOLINT */ #elif defined(CATCH_PLATFORM_LINUX) // If we can use inline assembler, do it because this allows us to break @@ -2154,251 +1394,190 @@ namespace Catch{ #define CATCH_BREAK_INTO_DEBUGGER() Catch::alwaysTrue(); #endif -// #included from: catch_interfaces_runner.h -#define TWOBLUECUBES_CATCH_INTERFACES_RUNNER_H_INCLUDED +// end catch_debugger.h +#if !defined(CATCH_CONFIG_DISABLE) -namespace Catch { - class TestCase; - - struct IRunner { - virtual ~IRunner(); - virtual bool aborting() const = 0; - }; -} +#if !defined(CATCH_CONFIG_DISABLE_STRINGIFICATION) + #define CATCH_INTERNAL_STRINGIFY(...) #__VA_ARGS__ +#else + #define CATCH_INTERNAL_STRINGIFY(...) "Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION" +#endif #if defined(CATCH_CONFIG_FAST_COMPILE) /////////////////////////////////////////////////////////////////////////////// // We can speedup compilation significantly by breaking into debugger lower in // the callstack, because then we don't have to expand CATCH_BREAK_INTO_DEBUGGER // macro in each assertion -#define INTERNAL_CATCH_REACT( resultBuilder ) \ - resultBuilder.react(); +#define INTERNAL_CATCH_REACT( handler ) \ + handler.reactWithDebugBreak(); /////////////////////////////////////////////////////////////////////////////// // Another way to speed-up compilation is to omit local try-catch for REQUIRE* // macros. // This can potentially cause false negative, if the test code catches // the exception before it propagates back up to the runner. -#define INTERNAL_CATCH_TEST_NO_TRY( macroName, resultDisposition, expr ) \ - do { \ - Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ - __catchResult.setExceptionGuard(); \ - CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ - ( __catchResult <= expr ).endExpression(); \ - CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \ - __catchResult.unsetExceptionGuard(); \ - INTERNAL_CATCH_REACT( __catchResult ) \ - } while( Catch::isTrue( false && static_cast( !!(expr) ) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look -// The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&. +#define INTERNAL_CATCH_TRY( capturer ) capturer.setExceptionGuard(); +#define INTERNAL_CATCH_CATCH( capturer ) capturer.unsetExceptionGuard(); -#define INTERNAL_CHECK_THAT_NO_TRY( macroName, matcher, resultDisposition, arg ) \ - do { \ - Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg ", " #matcher, resultDisposition ); \ - __catchResult.setExceptionGuard(); \ - __catchResult.captureMatch( arg, matcher, #matcher ); \ - __catchResult.unsetExceptionGuard(); \ - INTERNAL_CATCH_REACT( __catchResult ) \ - } while( Catch::alwaysFalse() ) +#else // CATCH_CONFIG_FAST_COMPILE -#else /////////////////////////////////////////////////////////////////////////////// // In the event of a failure works out if the debugger needs to be invoked // and/or an exception thrown and takes appropriate action. // This needs to be done as a macro so the debugger will stop in the user // source code rather than in Catch library code -#define INTERNAL_CATCH_REACT( resultBuilder ) \ - if( resultBuilder.shouldDebugBreak() ) CATCH_BREAK_INTO_DEBUGGER(); \ - resultBuilder.react(); +#define INTERNAL_CATCH_REACT( handler ) \ + if( handler.shouldDebugBreak() ) CATCH_BREAK_INTO_DEBUGGER(); \ + handler.reactWithoutDebugBreak(); + +#define INTERNAL_CATCH_TRY( capturer ) try +#define INTERNAL_CATCH_CATCH( capturer ) catch(...) { capturer.useActiveException(); } + #endif /////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_TEST( macroName, resultDisposition, expr ) \ +#define INTERNAL_CATCH_TEST( macroName, resultDisposition, ... ) \ do { \ - Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ - try { \ + Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \ + INTERNAL_CATCH_TRY( catchAssertionHandler ) { \ CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ - ( __catchResult <= expr ).endExpression(); \ + catchAssertionHandler.handle( Catch::Decomposer() <= __VA_ARGS__ ); \ CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \ - } \ - catch( ... ) { \ - __catchResult.useActiveException( resultDisposition ); \ - } \ - INTERNAL_CATCH_REACT( __catchResult ) \ - } while( Catch::isTrue( false && static_cast( !!(expr) ) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look + } INTERNAL_CATCH_CATCH( catchAssertionHandler ) \ + INTERNAL_CATCH_REACT( catchAssertionHandler ) \ + } while( Catch::isTrue( false && static_cast( !!(__VA_ARGS__) ) ) ) // the expression here is never evaluated at runtime but it forces the compiler to give it a look // The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&. /////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_IF( macroName, resultDisposition, expr ) \ - INTERNAL_CATCH_TEST( macroName, resultDisposition, expr ); \ +#define INTERNAL_CATCH_IF( macroName, resultDisposition, ... ) \ + INTERNAL_CATCH_TEST( macroName, resultDisposition, __VA_ARGS__ ); \ if( Catch::getResultCapture().lastAssertionPassed() ) /////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_ELSE( macroName, resultDisposition, expr ) \ - INTERNAL_CATCH_TEST( macroName, resultDisposition, expr ); \ +#define INTERNAL_CATCH_ELSE( macroName, resultDisposition, ... ) \ + INTERNAL_CATCH_TEST( macroName, resultDisposition, __VA_ARGS__ ); \ if( !Catch::getResultCapture().lastAssertionPassed() ) /////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_NO_THROW( macroName, resultDisposition, expr ) \ +#define INTERNAL_CATCH_NO_THROW( macroName, resultDisposition, ... ) \ do { \ - Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ + Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \ try { \ - static_cast(expr); \ - __catchResult.captureResult( Catch::ResultWas::Ok ); \ + static_cast(__VA_ARGS__); \ + catchAssertionHandler.handle( Catch::ResultWas::Ok ); \ } \ catch( ... ) { \ - __catchResult.useActiveException( resultDisposition ); \ + catchAssertionHandler.useActiveException(); \ } \ - INTERNAL_CATCH_REACT( __catchResult ) \ + INTERNAL_CATCH_REACT( catchAssertionHandler ) \ } while( Catch::alwaysFalse() ) /////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_THROWS( macroName, resultDisposition, matcher, expr ) \ +#define INTERNAL_CATCH_THROWS( macroName, resultDisposition, ... ) \ do { \ - Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition, #matcher ); \ - if( __catchResult.allowThrows() ) \ + Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition); \ + if( catchAssertionHandler.allowThrows() ) \ try { \ - static_cast(expr); \ - __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \ + static_cast(__VA_ARGS__); \ + catchAssertionHandler.handle( Catch::ResultWas::DidntThrowException ); \ } \ catch( ... ) { \ - __catchResult.captureExpectedException( matcher ); \ + catchAssertionHandler.handle( Catch::ResultWas::Ok ); \ } \ else \ - __catchResult.captureResult( Catch::ResultWas::Ok ); \ - INTERNAL_CATCH_REACT( __catchResult ) \ + catchAssertionHandler.handle( Catch::ResultWas::Ok ); \ + INTERNAL_CATCH_REACT( catchAssertionHandler ) \ } while( Catch::alwaysFalse() ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_THROWS_AS( macroName, exceptionType, resultDisposition, expr ) \ do { \ - Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr ", " #exceptionType, resultDisposition ); \ - if( __catchResult.allowThrows() ) \ + Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr) ", " CATCH_INTERNAL_STRINGIFY(exceptionType), resultDisposition ); \ + if( catchAssertionHandler.allowThrows() ) \ try { \ static_cast(expr); \ - __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \ + catchAssertionHandler.handle( Catch::ResultWas::DidntThrowException ); \ } \ - catch( exceptionType ) { \ - __catchResult.captureResult( Catch::ResultWas::Ok ); \ + catch( exceptionType const& ) { \ + catchAssertionHandler.handle( Catch::ResultWas::Ok ); \ } \ catch( ... ) { \ - __catchResult.useActiveException( resultDisposition ); \ + catchAssertionHandler.useActiveException(); \ } \ else \ - __catchResult.captureResult( Catch::ResultWas::Ok ); \ - INTERNAL_CATCH_REACT( __catchResult ) \ + catchAssertionHandler.handle( Catch::ResultWas::Ok ); \ + INTERNAL_CATCH_REACT( catchAssertionHandler ) \ } while( Catch::alwaysFalse() ) /////////////////////////////////////////////////////////////////////////////// -#ifdef CATCH_CONFIG_VARIADIC_MACROS - #define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, ... ) \ - do { \ - Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \ - __catchResult << __VA_ARGS__ + ::Catch::StreamEndStop(); \ - __catchResult.captureResult( messageType ); \ - INTERNAL_CATCH_REACT( __catchResult ) \ - } while( Catch::alwaysFalse() ) -#else - #define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, log ) \ - do { \ - Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \ - __catchResult << log + ::Catch::StreamEndStop(); \ - __catchResult.captureResult( messageType ); \ - INTERNAL_CATCH_REACT( __catchResult ) \ - } while( Catch::alwaysFalse() ) -#endif +#define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, ... ) \ + do { \ + Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \ + catchAssertionHandler.handle( messageType, ( Catch::MessageStream() << __VA_ARGS__ + ::Catch::StreamEndStop() ).m_stream.str() ); \ + INTERNAL_CATCH_REACT( catchAssertionHandler ) \ + } while( Catch::alwaysFalse() ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_INFO( macroName, log ) \ Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage ) = Catch::MessageBuilder( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log; /////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CHECK_THAT( macroName, matcher, resultDisposition, arg ) \ +// Although this is matcher-based, it can be used with just a string +#define INTERNAL_CATCH_THROWS_STR_MATCHES( macroName, resultDisposition, matcher, ... ) \ do { \ - Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg ", " #matcher, resultDisposition ); \ - try { \ - __catchResult.captureMatch( arg, matcher, #matcher ); \ - } catch( ... ) { \ - __catchResult.useActiveException( resultDisposition | Catch::ResultDisposition::ContinueOnFailure ); \ - } \ - INTERNAL_CATCH_REACT( __catchResult ) \ + Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \ + if( catchAssertionHandler.allowThrows() ) \ + try { \ + static_cast(__VA_ARGS__); \ + catchAssertionHandler.handle( Catch::ResultWas::DidntThrowException ); \ + } \ + catch( ... ) { \ + handleExceptionMatchExpr( catchAssertionHandler, matcher, #matcher ); \ + } \ + else \ + catchAssertionHandler.handle( Catch::ResultWas::Ok ); \ + INTERNAL_CATCH_REACT( catchAssertionHandler ) \ } while( Catch::alwaysFalse() ) -// #included from: internal/catch_section.h -#define TWOBLUECUBES_CATCH_SECTION_H_INCLUDED +#endif // CATCH_CONFIG_DISABLE -// #included from: catch_section_info.h -#define TWOBLUECUBES_CATCH_SECTION_INFO_H_INCLUDED +// end catch_capture.hpp +// start catch_section.h -// #included from: catch_totals.hpp -#define TWOBLUECUBES_CATCH_TOTALS_HPP_INCLUDED +// start catch_section_info.h + +// start catch_totals.h #include namespace Catch { struct Counts { - Counts() : passed( 0 ), failed( 0 ), failedButOk( 0 ) {} + Counts operator - ( Counts const& other ) const; + Counts& operator += ( Counts const& other ); - Counts operator - ( Counts const& other ) const { - Counts diff; - diff.passed = passed - other.passed; - diff.failed = failed - other.failed; - diff.failedButOk = failedButOk - other.failedButOk; - return diff; - } - Counts& operator += ( Counts const& other ) { - passed += other.passed; - failed += other.failed; - failedButOk += other.failedButOk; - return *this; - } + std::size_t total() const; + bool allPassed() const; + bool allOk() const; - std::size_t total() const { - return passed + failed + failedButOk; - } - bool allPassed() const { - return failed == 0 && failedButOk == 0; - } - bool allOk() const { - return failed == 0; - } - - std::size_t passed; - std::size_t failed; - std::size_t failedButOk; + std::size_t passed = 0; + std::size_t failed = 0; + std::size_t failedButOk = 0; }; struct Totals { - Totals operator - ( Totals const& other ) const { - Totals diff; - diff.assertions = assertions - other.assertions; - diff.testCases = testCases - other.testCases; - return diff; - } + Totals operator - ( Totals const& other ) const; + Totals& operator += ( Totals const& other ); - Totals delta( Totals const& prevTotals ) const { - Totals diff = *this - prevTotals; - if( diff.assertions.failed > 0 ) - ++diff.testCases.failed; - else if( diff.assertions.failedButOk > 0 ) - ++diff.testCases.failedButOk; - else - ++diff.testCases.passed; - return diff; - } - - Totals& operator += ( Totals const& other ) { - assertions += other.assertions; - testCases += other.testCases; - return *this; - } + Totals delta( Totals const& prevTotals ) const; Counts assertions; Counts testCases; }; } +// end catch_totals.h #include namespace Catch { @@ -2415,9 +1594,7 @@ namespace Catch { }; struct SectionEndInfo { - SectionEndInfo( SectionInfo const& _sectionInfo, Counts const& _prevAssertions, double _durationInSeconds ) - : sectionInfo( _sectionInfo ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds ) - {} + SectionEndInfo( SectionInfo const& _sectionInfo, Counts const& _prevAssertions, double _durationInSeconds ); SectionInfo sectionInfo; Counts prevAssertions; @@ -2426,36 +1603,29 @@ namespace Catch { } // end namespace Catch -// #included from: catch_timer.h -#define TWOBLUECUBES_CATCH_TIMER_H_INCLUDED +// end catch_section_info.h +// start catch_timer.h -#ifdef _MSC_VER +#include namespace Catch { - typedef unsigned long long UInt64; -} -#else -#include -namespace Catch { - typedef uint64_t UInt64; -} -#endif -namespace Catch { + auto getCurrentNanosecondsSinceEpoch() -> uint64_t; + auto getEstimatedClockResolution() -> uint64_t; + class Timer { + uint64_t m_nanoseconds = 0; public: - Timer() : m_ticks( 0 ) {} void start(); - unsigned int getElapsedMicroseconds() const; - unsigned int getElapsedMilliseconds() const; - double getElapsedSeconds() const; - - private: - UInt64 m_ticks; + auto getElapsedNanoseconds() const -> unsigned int; + auto getElapsedMicroseconds() const -> unsigned int; + auto getElapsedMilliseconds() const -> unsigned int; + auto getElapsedSeconds() const -> double; }; } // namespace Catch +// end catch_timer.h #include namespace Catch { @@ -2466,7 +1636,7 @@ namespace Catch { ~Section(); // This indicates whether the section should be executed or not - operator bool() const; + explicit operator bool() const; private: SectionInfo m_info; @@ -2479,203 +1649,62 @@ namespace Catch { } // end namespace Catch -#ifdef CATCH_CONFIG_VARIADIC_MACROS #define INTERNAL_CATCH_SECTION( ... ) \ if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) -#else - #define INTERNAL_CATCH_SECTION( name, desc ) \ - if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, name, desc ) ) -#endif -// #included from: internal/catch_generators.hpp -#define TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED +// end catch_section.h +// start catch_benchmark.h -#include +#include #include -#include namespace Catch { -template -struct IGenerator { - virtual ~IGenerator() {} - virtual T getValue( std::size_t index ) const = 0; - virtual std::size_t size () const = 0; -}; + class BenchmarkLooper { -template -class BetweenGenerator : public IGenerator { -public: - BetweenGenerator( T from, T to ) : m_from( from ), m_to( to ){} + std::string m_name; + std::size_t m_count = 0; + std::size_t m_iterationsToRun = 1; + uint64_t m_resolution; + Timer m_timer; - virtual T getValue( std::size_t index ) const { - return m_from+static_cast( index ); - } - - virtual std::size_t size() const { - return static_cast( 1+m_to-m_from ); - } - -private: - - T m_from; - T m_to; -}; - -template -class ValuesGenerator : public IGenerator { -public: - ValuesGenerator(){} - - void add( T value ) { - m_values.push_back( value ); - } - - virtual T getValue( std::size_t index ) const { - return m_values[index]; - } - - virtual std::size_t size() const { - return m_values.size(); - } - -private: - std::vector m_values; -}; - -template -class CompositeGenerator { -public: - CompositeGenerator() : m_totalSize( 0 ) {} - - // *** Move semantics, similar to auto_ptr *** - CompositeGenerator( CompositeGenerator& other ) - : m_fileInfo( other.m_fileInfo ), - m_totalSize( 0 ) - { - move( other ); - } - - CompositeGenerator& setFileInfo( const char* fileInfo ) { - m_fileInfo = fileInfo; - return *this; - } - - ~CompositeGenerator() { - deleteAll( m_composed ); - } - - operator T () const { - size_t overallIndex = getCurrentContext().getGeneratorIndex( m_fileInfo, m_totalSize ); - - typename std::vector*>::const_iterator it = m_composed.begin(); - typename std::vector*>::const_iterator itEnd = m_composed.end(); - for( size_t index = 0; it != itEnd; ++it ) + static auto getResolution() -> uint64_t; + public: + // Keep most of this inline as it's on the code path that is being timed + BenchmarkLooper( StringRef name ) + : m_name( name ), + m_resolution( getResolution() ) { - const IGenerator* generator = *it; - if( overallIndex >= index && overallIndex < index + generator->size() ) - { - return generator->getValue( overallIndex-index ); - } - index += generator->size(); + reportStart(); + m_timer.start(); } - CATCH_INTERNAL_ERROR( "Indexed past end of generated range" ); - return T(); // Suppress spurious "not all control paths return a value" warning in Visual Studio - if you know how to fix this please do so - } - void add( const IGenerator* generator ) { - m_totalSize += generator->size(); - m_composed.push_back( generator ); - } + explicit operator bool() { + if( m_count < m_iterationsToRun ) + return true; + return needsMoreIterations(); + } - CompositeGenerator& then( CompositeGenerator& other ) { - move( other ); - return *this; - } + void increment() { + ++m_count; + } - CompositeGenerator& then( T value ) { - ValuesGenerator* valuesGen = new ValuesGenerator(); - valuesGen->add( value ); - add( valuesGen ); - return *this; - } - -private: - - void move( CompositeGenerator& other ) { - m_composed.insert( m_composed.end(), other.m_composed.begin(), other.m_composed.end() ); - m_totalSize += other.m_totalSize; - other.m_composed.clear(); - } - - std::vector*> m_composed; - std::string m_fileInfo; - size_t m_totalSize; -}; - -namespace Generators -{ - template - CompositeGenerator between( T from, T to ) { - CompositeGenerator generators; - generators.add( new BetweenGenerator( from, to ) ); - return generators; - } - - template - CompositeGenerator values( T val1, T val2 ) { - CompositeGenerator generators; - ValuesGenerator* valuesGen = new ValuesGenerator(); - valuesGen->add( val1 ); - valuesGen->add( val2 ); - generators.add( valuesGen ); - return generators; - } - - template - CompositeGenerator values( T val1, T val2, T val3 ){ - CompositeGenerator generators; - ValuesGenerator* valuesGen = new ValuesGenerator(); - valuesGen->add( val1 ); - valuesGen->add( val2 ); - valuesGen->add( val3 ); - generators.add( valuesGen ); - return generators; - } - - template - CompositeGenerator values( T val1, T val2, T val3, T val4 ) { - CompositeGenerator generators; - ValuesGenerator* valuesGen = new ValuesGenerator(); - valuesGen->add( val1 ); - valuesGen->add( val2 ); - valuesGen->add( val3 ); - valuesGen->add( val4 ); - generators.add( valuesGen ); - return generators; - } - -} // end namespace Generators - -using namespace Generators; + void reportStart(); + auto needsMoreIterations() -> bool; + }; } // end namespace Catch -#define INTERNAL_CATCH_LINESTR2( line ) #line -#define INTERNAL_CATCH_LINESTR( line ) INTERNAL_CATCH_LINESTR2( line ) +#define BENCHMARK( name ) \ + for( Catch::BenchmarkLooper looper( name ); looper; looper.increment() ) -#define INTERNAL_CATCH_GENERATE( expr ) expr.setFileInfo( __FILE__ "(" INTERNAL_CATCH_LINESTR( __LINE__ ) ")" ) +// end catch_benchmark.h +// start catch_interfaces_exception.h -// #included from: internal/catch_interfaces_exception.h -#define TWOBLUECUBES_CATCH_INTERFACES_EXCEPTION_H_INCLUDED - -#include -#include - -// #included from: catch_interfaces_registry_hub.h -#define TWOBLUECUBES_CATCH_INTERFACES_REGISTRY_HUB_H_INCLUDED +// start catch_interfaces_registry_hub.h #include +#include namespace Catch { @@ -2686,6 +1715,9 @@ namespace Catch { struct IReporterRegistry; struct IReporterFactory; struct ITagAliasRegistry; + class StartupExceptionRegistry; + + using IReporterFactoryPtr = std::shared_ptr; struct IRegistryHub { virtual ~IRegistryHub(); @@ -2695,15 +1727,18 @@ namespace Catch { virtual ITagAliasRegistry const& getTagAliasRegistry() const = 0; virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() = 0; + + virtual StartupExceptionRegistry const& getStartupExceptionRegistry() const = 0; }; struct IMutableRegistryHub { virtual ~IMutableRegistryHub(); - virtual void registerReporter( std::string const& name, Ptr const& factory ) = 0; - virtual void registerListener( Ptr const& factory ) = 0; + virtual void registerReporter( std::string const& name, IReporterFactoryPtr const& factory ) = 0; + virtual void registerListener( IReporterFactoryPtr const& factory ) = 0; virtual void registerTest( TestCase const& testInfo ) = 0; virtual void registerTranslator( const IExceptionTranslator* translator ) = 0; virtual void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) = 0; + virtual void registerStartupException() noexcept = 0; }; IRegistryHub& getRegistryHub(); @@ -2713,12 +1748,21 @@ namespace Catch { } -namespace Catch { +// end catch_interfaces_registry_hub.h +#if defined(CATCH_CONFIG_DISABLE) + #define INTERNAL_CATCH_TRANSLATE_EXCEPTION_NO_REG( translatorName, signature) \ + static std::string translatorName( signature ) +#endif - typedef std::string(*exceptionTranslateFunction)(); +#include +#include +#include + +namespace Catch { + using exceptionTranslateFunction = std::string(*)(); struct IExceptionTranslator; - typedef std::vector ExceptionTranslators; + using ExceptionTranslators = std::vector>; struct IExceptionTranslator { virtual ~IExceptionTranslator(); @@ -2740,10 +1784,10 @@ namespace Catch { : m_translateFunction( translateFunction ) {} - virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const CATCH_OVERRIDE { + std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const override { try { if( it == itEnd ) - throw; + std::rethrow_exception(std::current_exception()); else return (*it)->translate( it+1, itEnd ); } @@ -2773,36 +1817,40 @@ namespace Catch { #define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION2( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature ) -// #included from: internal/catch_approx.hpp -#define TWOBLUECUBES_CATCH_APPROX_HPP_INCLUDED +// end catch_interfaces_exception.h +// start catch_approx.h -#include -#include +// start catch_enforce.h -#if defined(CATCH_CONFIG_CPP11_TYPE_TRAITS) +#include +#include + +#define CATCH_PREPARE_EXCEPTION( type, msg ) \ + type( static_cast( std::ostringstream() << msg ).str() ) +#define CATCH_INTERNAL_ERROR( msg ) \ + throw CATCH_PREPARE_EXCEPTION( std::logic_error, CATCH_INTERNAL_LINEINFO << ": Internal Catch error: " << msg); +#define CATCH_ERROR( msg ) \ + throw CATCH_PREPARE_EXCEPTION( std::domain_error, msg ) +#define CATCH_ENFORCE( condition, msg ) \ + do{ if( !(condition) ) CATCH_ERROR( msg ); } while(false) + +// end catch_enforce.h #include -#endif namespace Catch { namespace Detail { class Approx { + private: + bool equalityComparisonImpl(double other) const; + public: - explicit Approx ( double value ) - : m_epsilon( std::numeric_limits::epsilon()*100 ), - m_margin( 0.0 ), - m_scale( 1.0 ), - m_value( value ) - {} + explicit Approx ( double value ); - static Approx custom() { - return Approx( 0 ); - } - -#if defined(CATCH_CONFIG_CPP11_TYPE_TRAITS) + static Approx custom(); template ::value>::type> - Approx operator()( T value ) { + Approx operator()( T const& value ) { Approx approx( static_cast(value) ); approx.epsilon( m_epsilon ); approx.margin( m_margin ); @@ -2811,18 +1859,13 @@ namespace Detail { } template ::value>::type> - explicit Approx( T value ): Approx(static_cast(value)) + explicit Approx( T const& value ): Approx(static_cast(value)) {} template ::value>::type> friend bool operator == ( const T& lhs, Approx const& rhs ) { - // Thanks to Richard Harris for his help refining this formula - auto lhs_v = double(lhs); - bool relativeOK = std::fabs(lhs_v - rhs.m_value) < rhs.m_epsilon * (rhs.m_scale + (std::max)(std::fabs(lhs_v), std::fabs(rhs.m_value))); - if (relativeOK) { - return true; - } - return std::fabs(lhs_v - rhs.m_value) < rhs.m_margin; + auto lhs_v = static_cast(lhs); + return rhs.equalityComparisonImpl(lhs_v); } template ::value>::type> @@ -2831,121 +1874,62 @@ namespace Detail { } template ::value>::type> - friend bool operator != ( T lhs, Approx const& rhs ) { + friend bool operator != ( T const& lhs, Approx const& rhs ) { return !operator==( lhs, rhs ); } template ::value>::type> - friend bool operator != ( Approx const& lhs, T rhs ) { + friend bool operator != ( Approx const& lhs, T const& rhs ) { return !operator==( rhs, lhs ); } template ::value>::type> - friend bool operator <= ( T lhs, Approx const& rhs ) { - return double(lhs) < rhs.m_value || lhs == rhs; + friend bool operator <= ( T const& lhs, Approx const& rhs ) { + return static_cast(lhs) < rhs.m_value || lhs == rhs; } template ::value>::type> - friend bool operator <= ( Approx const& lhs, T rhs ) { - return lhs.m_value < double(rhs) || lhs == rhs; + friend bool operator <= ( Approx const& lhs, T const& rhs ) { + return lhs.m_value < static_cast(rhs) || lhs == rhs; } template ::value>::type> - friend bool operator >= ( T lhs, Approx const& rhs ) { - return double(lhs) > rhs.m_value || lhs == rhs; + friend bool operator >= ( T const& lhs, Approx const& rhs ) { + return static_cast(lhs) > rhs.m_value || lhs == rhs; } template ::value>::type> - friend bool operator >= ( Approx const& lhs, T rhs ) { - return lhs.m_value > double(rhs) || lhs == rhs; + friend bool operator >= ( Approx const& lhs, T const& rhs ) { + return lhs.m_value > static_cast(rhs) || lhs == rhs; } template ::value>::type> - Approx& epsilon( T newEpsilon ) { - m_epsilon = double(newEpsilon); + Approx& epsilon( T const& newEpsilon ) { + double epsilonAsDouble = static_cast(newEpsilon); + CATCH_ENFORCE(epsilonAsDouble >= 0 && epsilonAsDouble <= 1.0, + "Invalid Approx::epsilon: " << epsilonAsDouble + << ", Approx::epsilon has to be between 0 and 1"); + m_epsilon = epsilonAsDouble; return *this; } template ::value>::type> - Approx& margin( T newMargin ) { - m_margin = double(newMargin); + Approx& margin( T const& newMargin ) { + double marginAsDouble = static_cast(newMargin); + CATCH_ENFORCE(marginAsDouble >= 0, + "Invalid Approx::margin: " << marginAsDouble + << ", Approx::Margin has to be non-negative."); + m_margin = marginAsDouble; return *this; } template ::value>::type> - Approx& scale( T newScale ) { - m_scale = double(newScale); + Approx& scale( T const& newScale ) { + m_scale = static_cast(newScale); return *this; } -#else - - Approx operator()( double value ) { - Approx approx( value ); - approx.epsilon( m_epsilon ); - approx.margin( m_margin ); - approx.scale( m_scale ); - return approx; - } - - friend bool operator == ( double lhs, Approx const& rhs ) { - // Thanks to Richard Harris for his help refining this formula - bool relativeOK = std::fabs( lhs - rhs.m_value ) < rhs.m_epsilon * (rhs.m_scale + (std::max)( std::fabs(lhs), std::fabs(rhs.m_value) ) ); - if (relativeOK) { - return true; - } - return std::fabs(lhs - rhs.m_value) < rhs.m_margin; - } - - friend bool operator == ( Approx const& lhs, double rhs ) { - return operator==( rhs, lhs ); - } - - friend bool operator != ( double lhs, Approx const& rhs ) { - return !operator==( lhs, rhs ); - } - - friend bool operator != ( Approx const& lhs, double rhs ) { - return !operator==( rhs, lhs ); - } - - friend bool operator <= ( double lhs, Approx const& rhs ) { - return lhs < rhs.m_value || lhs == rhs; - } - - friend bool operator <= ( Approx const& lhs, double rhs ) { - return lhs.m_value < rhs || lhs == rhs; - } - - friend bool operator >= ( double lhs, Approx const& rhs ) { - return lhs > rhs.m_value || lhs == rhs; - } - - friend bool operator >= ( Approx const& lhs, double rhs ) { - return lhs.m_value > rhs || lhs == rhs; - } - - Approx& epsilon( double newEpsilon ) { - m_epsilon = newEpsilon; - return *this; - } - - Approx& margin( double newMargin ) { - m_margin = newMargin; - return *this; - } - - Approx& scale( double newScale ) { - m_scale = newScale; - return *this; - } -#endif - - std::string toString() const { - std::ostringstream oss; - oss << "Approx( " << Catch::toString( m_value ) << " )"; - return oss.str(); - } + std::string toString() const; private: double m_epsilon; @@ -2956,14 +1940,194 @@ namespace Detail { } template<> -inline std::string toString( Detail::Approx const& value ) { - return value.toString(); -} +struct StringMaker { + static std::string convert(Catch::Detail::Approx const& value); +}; } // end namespace Catch -// #included from: internal/catch_matchers_string.h -#define TWOBLUECUBES_CATCH_MATCHERS_STRING_H_INCLUDED +// end catch_approx.h +// start catch_string_manip.h + +#include +#include + +namespace Catch { + + bool startsWith( std::string const& s, std::string const& prefix ); + bool startsWith( std::string const& s, char prefix ); + bool endsWith( std::string const& s, std::string const& suffix ); + bool endsWith( std::string const& s, char suffix ); + bool contains( std::string const& s, std::string const& infix ); + void toLowerInPlace( std::string& s ); + std::string toLower( std::string const& s ); + std::string trim( std::string const& str ); + bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ); + + struct pluralise { + pluralise( std::size_t count, std::string const& label ); + + friend std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ); + + std::size_t m_count; + std::string m_label; + }; +} + +// end catch_string_manip.h +#ifndef CATCH_CONFIG_DISABLE_MATCHERS +// start catch_capture_matchers.h + +// start catch_matchers.h + +#include +#include + +namespace Catch { +namespace Matchers { + namespace Impl { + + template struct MatchAllOf; + template struct MatchAnyOf; + template struct MatchNotOf; + + class MatcherUntypedBase { + public: + MatcherUntypedBase() = default; + MatcherUntypedBase ( MatcherUntypedBase const& ) = default; + MatcherUntypedBase& operator = ( MatcherUntypedBase const& ) = delete; + std::string toString() const; + + protected: + virtual ~MatcherUntypedBase(); + virtual std::string describe() const = 0; + mutable std::string m_cachedToString; + }; + + template + struct MatcherMethod { + virtual bool match( ObjectT const& arg ) const = 0; + }; + template + struct MatcherMethod { + virtual bool match( PtrT* arg ) const = 0; + }; + + template + struct MatcherBase : MatcherUntypedBase, MatcherMethod { + + MatchAllOf operator && ( MatcherBase const& other ) const; + MatchAnyOf operator || ( MatcherBase const& other ) const; + MatchNotOf operator ! () const; + }; + + template + struct MatchAllOf : MatcherBase { + bool match( ArgT const& arg ) const override { + for( auto matcher : m_matchers ) { + if (!matcher->match(arg)) + return false; + } + return true; + } + std::string describe() const override { + std::string description; + description.reserve( 4 + m_matchers.size()*32 ); + description += "( "; + bool first = true; + for( auto matcher : m_matchers ) { + if( first ) + first = false; + else + description += " and "; + description += matcher->toString(); + } + description += " )"; + return description; + } + + MatchAllOf& operator && ( MatcherBase const& other ) { + m_matchers.push_back( &other ); + return *this; + } + + std::vector const*> m_matchers; + }; + template + struct MatchAnyOf : MatcherBase { + + bool match( ArgT const& arg ) const override { + for( auto matcher : m_matchers ) { + if (matcher->match(arg)) + return true; + } + return false; + } + std::string describe() const override { + std::string description; + description.reserve( 4 + m_matchers.size()*32 ); + description += "( "; + bool first = true; + for( auto matcher : m_matchers ) { + if( first ) + first = false; + else + description += " or "; + description += matcher->toString(); + } + description += " )"; + return description; + } + + MatchAnyOf& operator || ( MatcherBase const& other ) { + m_matchers.push_back( &other ); + return *this; + } + + std::vector const*> m_matchers; + }; + + template + struct MatchNotOf : MatcherBase { + + MatchNotOf( MatcherBase const& underlyingMatcher ) : m_underlyingMatcher( underlyingMatcher ) {} + + bool match( ArgT const& arg ) const override { + return !m_underlyingMatcher.match( arg ); + } + + std::string describe() const override { + return "not " + m_underlyingMatcher.toString(); + } + MatcherBase const& m_underlyingMatcher; + }; + + template + MatchAllOf MatcherBase::operator && ( MatcherBase const& other ) const { + return MatchAllOf() && *this && other; + } + template + MatchAnyOf MatcherBase::operator || ( MatcherBase const& other ) const { + return MatchAnyOf() || *this || other; + } + template + MatchNotOf MatcherBase::operator ! () const { + return MatchNotOf( *this ); + } + + } // namespace Impl + +} // namespace Matchers + +using namespace Matchers; +using Matchers::Impl::MatcherBase; + +} // namespace Catch + +// end catch_matchers.h +// start catch_matchers_string.h + +#include namespace Catch { namespace Matchers { @@ -2982,7 +2146,7 @@ namespace Matchers { struct StringMatcherBase : MatcherBase { StringMatcherBase( std::string const& operation, CasedString const& comparator ); - virtual std::string describe() const CATCH_OVERRIDE; + std::string describe() const override; CasedString m_comparator; std::string m_operation; @@ -2990,19 +2154,19 @@ namespace Matchers { struct EqualsMatcher : StringMatcherBase { EqualsMatcher( CasedString const& comparator ); - virtual bool match( std::string const& source ) const CATCH_OVERRIDE; + bool match( std::string const& source ) const override; }; struct ContainsMatcher : StringMatcherBase { ContainsMatcher( CasedString const& comparator ); - virtual bool match( std::string const& source ) const CATCH_OVERRIDE; + bool match( std::string const& source ) const override; }; struct StartsWithMatcher : StringMatcherBase { StartsWithMatcher( CasedString const& comparator ); - virtual bool match( std::string const& source ) const CATCH_OVERRIDE; + bool match( std::string const& source ) const override; }; struct EndsWithMatcher : StringMatcherBase { EndsWithMatcher( CasedString const& comparator ); - virtual bool match( std::string const& source ) const CATCH_OVERRIDE; + bool match( std::string const& source ) const override; }; } // namespace StdString @@ -3018,8 +2182,8 @@ namespace Matchers { } // namespace Matchers } // namespace Catch -// #included from: internal/catch_matchers_vector.h -#define TWOBLUECUBES_CATCH_MATCHERS_VECTOR_H_INCLUDED +// end catch_matchers_string.h +// start catch_matchers_vector.h namespace Catch { namespace Matchers { @@ -3031,12 +2195,17 @@ namespace Matchers { ContainsElementMatcher(T const &comparator) : m_comparator( comparator) {} - bool match(std::vector const &v) const CATCH_OVERRIDE { - return std::find(v.begin(), v.end(), m_comparator) != v.end(); + bool match(std::vector const &v) const override { + for (auto const& el : v) { + if (el == m_comparator) { + return true; + } + } + return false; } - virtual std::string describe() const CATCH_OVERRIDE { - return "Contains: " + Catch::toString( m_comparator ); + std::string describe() const override { + return "Contains: " + ::Catch::Detail::stringify( m_comparator ); } T const& m_comparator; @@ -3047,17 +2216,26 @@ namespace Matchers { ContainsMatcher(std::vector const &comparator) : m_comparator( comparator ) {} - bool match(std::vector const &v) const CATCH_OVERRIDE { + bool match(std::vector const &v) const override { // !TBD: see note in EqualsMatcher if (m_comparator.size() > v.size()) return false; - for (size_t i = 0; i < m_comparator.size(); ++i) - if (std::find(v.begin(), v.end(), m_comparator[i]) == v.end()) + for (auto const& comparator : m_comparator) { + auto present = false; + for (const auto& el : v) { + if (el == comparator) { + present = true; + break; + } + } + if (!present) { return false; + } + } return true; } - virtual std::string describe() const CATCH_OVERRIDE { - return "Contains: " + Catch::toString( m_comparator ); + std::string describe() const override { + return "Contains: " + ::Catch::Detail::stringify( m_comparator ); } std::vector const& m_comparator; @@ -3068,20 +2246,20 @@ namespace Matchers { EqualsMatcher(std::vector const &comparator) : m_comparator( comparator ) {} - bool match(std::vector const &v) const CATCH_OVERRIDE { + bool match(std::vector const &v) const override { // !TBD: This currently works if all elements can be compared using != // - a more general approach would be via a compare template that defaults // to using !=. but could be specialised for, e.g. std::vector etc // - then just call that directly if (m_comparator.size() != v.size()) return false; - for (size_t i = 0; i < v.size(); ++i) + for (std::size_t i = 0; i < v.size(); ++i) if (m_comparator[i] != v[i]) return false; return true; } - virtual std::string describe() const CATCH_OVERRIDE { - return "Equals: " + Catch::toString( m_comparator ); + std::string describe() const override { + return "Equals: " + ::Catch::Detail::stringify( m_comparator ); } std::vector const& m_comparator; }; @@ -3109,124 +2287,87 @@ namespace Matchers { } // namespace Matchers } // namespace Catch -// #included from: internal/catch_interfaces_tag_alias_registry.h -#define TWOBLUECUBES_CATCH_INTERFACES_TAG_ALIAS_REGISTRY_H_INCLUDED - -// #included from: catch_tag_alias.h -#define TWOBLUECUBES_CATCH_TAG_ALIAS_H_INCLUDED - -#include - +// end catch_matchers_vector.h namespace Catch { - struct TagAlias { - TagAlias( std::string const& _tag, SourceLineInfo _lineInfo ) : tag( _tag ), lineInfo( _lineInfo ) {} - - std::string tag; - SourceLineInfo lineInfo; - }; - - struct RegistrarForTagAliases { - RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); - }; - -} // end namespace Catch - -#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } -// #included from: catch_option.hpp -#define TWOBLUECUBES_CATCH_OPTION_HPP_INCLUDED - -namespace Catch { - - // An optional type - template - class Option { + template + class MatchExpr : public ITransientExpression { + ArgT const& m_arg; + MatcherT m_matcher; + StringRef m_matcherString; + bool m_result; public: - Option() : nullableValue( CATCH_NULL ) {} - Option( T const& _value ) - : nullableValue( new( storage ) T( _value ) ) - {} - Option( Option const& _other ) - : nullableValue( _other ? new( storage ) T( *_other ) : CATCH_NULL ) + MatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef matcherString ) + : m_arg( arg ), + m_matcher( matcher ), + m_matcherString( matcherString ), + m_result( matcher.match( arg ) ) {} - ~Option() { - reset(); + auto isBinaryExpression() const -> bool override { return true; } + auto getResult() const -> bool override { return m_result; } + + void streamReconstructedExpression( std::ostream &os ) const override { + auto matcherAsString = m_matcher.toString(); + os << Catch::Detail::stringify( m_arg ) << ' '; + if( matcherAsString == Detail::unprintableString ) + os << m_matcherString; + else + os << matcherAsString; } + }; - Option& operator= ( Option const& _other ) { - if( &_other != this ) { - reset(); - if( _other ) - nullableValue = new( storage ) T( *_other ); - } - return *this; - } - Option& operator = ( T const& _value ) { - reset(); - nullableValue = new( storage ) T( _value ); - return *this; - } + using StringMatcher = Matchers::Impl::MatcherBase; - void reset() { - if( nullableValue ) - nullableValue->~T(); - nullableValue = CATCH_NULL; - } + void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef matcherString ); - T& operator*() { return *nullableValue; } - T const& operator*() const { return *nullableValue; } - T* operator->() { return nullableValue; } - const T* operator->() const { return nullableValue; } + template + auto makeMatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef matcherString ) -> MatchExpr { + return MatchExpr( arg, matcher, matcherString ); + } - T valueOr( T const& defaultValue ) const { - return nullableValue ? *nullableValue : defaultValue; - } +} // namespace Catch - bool some() const { return nullableValue != CATCH_NULL; } - bool none() const { return nullableValue == CATCH_NULL; } +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CHECK_THAT( macroName, matcher, resultDisposition, arg ) \ + do { \ + Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(arg) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \ + INTERNAL_CATCH_TRY( catchAssertionHandler ) { \ + catchAssertionHandler.handle( Catch::makeMatchExpr( arg, matcher, #matcher ) ); \ + } INTERNAL_CATCH_CATCH( catchAssertionHandler ) \ + INTERNAL_CATCH_REACT( catchAssertionHandler ) \ + } while( Catch::alwaysFalse() ) - bool operator !() const { return nullableValue == CATCH_NULL; } - operator SafeBool::type() const { - return SafeBool::makeSafe( some() ); - } +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_THROWS_MATCHES( macroName, exceptionType, resultDisposition, matcher, ... ) \ + do { \ + Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(exceptionType) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \ + if( catchAssertionHandler.allowThrows() ) \ + try { \ + static_cast(__VA_ARGS__ ); \ + catchAssertionHandler.handle( Catch::ResultWas::DidntThrowException ); \ + } \ + catch( exceptionType const& ex ) { \ + catchAssertionHandler.handle( Catch::makeMatchExpr( ex, matcher, #matcher ) ); \ + } \ + catch( ... ) { \ + catchAssertionHandler.useActiveException(); \ + } \ + else \ + catchAssertionHandler.handle( Catch::ResultWas::Ok ); \ + INTERNAL_CATCH_REACT( catchAssertionHandler ) \ + } while( Catch::alwaysFalse() ) - private: - T *nullableValue; - union { - char storage[sizeof(T)]; - - // These are here to force alignment for the storage - long double dummy1; - void (*dummy2)(); - long double dummy3; -#ifdef CATCH_CONFIG_CPP11_LONG_LONG - long long dummy4; +// end catch_capture_matchers.h #endif - }; - }; - -} // end namespace Catch - -namespace Catch { - - struct ITagAliasRegistry { - virtual ~ITagAliasRegistry(); - virtual Option find( std::string const& alias ) const = 0; - virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const = 0; - - static ITagAliasRegistry const& get(); - }; - -} // end namespace Catch // These files are included here so the single_include script doesn't put them // in the conditionally compiled sections -// #included from: internal/catch_test_case_info.h -#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_H_INCLUDED +// start catch_test_case_info.h #include -#include +#include +#include #ifdef __clang__ #pragma clang diagnostic push @@ -3235,7 +2376,7 @@ namespace Catch { namespace Catch { - struct ITestCase; + struct ITestInvoker; struct TestCaseInfo { enum SpecialProperties{ @@ -3244,30 +2385,30 @@ namespace Catch { ShouldFail = 1 << 2, MayFail = 1 << 3, Throws = 1 << 4, - NonPortable = 1 << 5 + NonPortable = 1 << 5, + Benchmark = 1 << 6 }; TestCaseInfo( std::string const& _name, std::string const& _className, std::string const& _description, - std::set const& _tags, + std::vector const& _tags, SourceLineInfo const& _lineInfo ); - TestCaseInfo( TestCaseInfo const& other ); - - friend void setTags( TestCaseInfo& testCaseInfo, std::set const& tags ); + friend void setTags( TestCaseInfo& testCaseInfo, std::vector tags ); bool isHidden() const; bool throws() const; bool okToFail() const; bool expectedToFail() const; + std::string tagsAsString() const; + std::string name; std::string className; std::string description; - std::set tags; - std::set lcaseTags; - std::string tagsAsString; + std::vector tags; + std::vector lcaseTags; SourceLineInfo lineInfo; SpecialProperties properties; }; @@ -3275,8 +2416,7 @@ namespace Catch { class TestCase : public TestCaseInfo { public: - TestCase( ITestCase* testCase, TestCaseInfo const& info ); - TestCase( TestCase const& other ); + TestCase( ITestInvoker* testCase, TestCaseInfo const& info ); TestCase withName( std::string const& _newName ) const; @@ -3284,16 +2424,14 @@ namespace Catch { TestCaseInfo const& getTestCaseInfo() const; - void swap( TestCase& other ); bool operator == ( TestCase const& other ) const; bool operator < ( TestCase const& other ) const; - TestCase& operator = ( TestCase const& other ); private: - Ptr test; + std::shared_ptr test; }; - TestCase makeTestCase( ITestCase* testCase, + TestCase makeTestCase( ITestInvoker* testCase, std::string const& className, std::string const& name, std::string const& description, @@ -3304,10 +2442,21 @@ namespace Catch { #pragma clang diagnostic pop #endif +// end catch_test_case_info.h +// start catch_interfaces_runner.h + +namespace Catch { + + struct IRunner { + virtual ~IRunner(); + virtual bool aborting() const = 0; + }; +} + +// end catch_interfaces_runner.h #ifdef __OBJC__ -// #included from: internal/catch_objc.hpp -#define TWOBLUECUBES_CATCH_OBJC_HPP_INCLUDED +// start catch_objc.hpp #import @@ -3331,7 +2480,7 @@ namespace Catch { namespace Catch { - class OcMethod : public SharedImpl { + class OcMethod : public ITestInvoker { public: OcMethod( Class cls, SEL sel ) : m_cls( cls ), m_sel( sel ) {} @@ -3367,9 +2516,9 @@ namespace Catch { } } - inline size_t registerTestMethods() { - size_t noTestMethods = 0; - int noClasses = objc_getClassList( CATCH_NULL, 0 ); + inline std::size_t registerTestMethods() { + std::size_t noTestMethods = 0; + int noClasses = objc_getClassList( nullptr, 0 ); Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses); objc_getClassList( classes, noClasses ); @@ -3388,7 +2537,7 @@ namespace Catch { std::string desc = Detail::getAnnotation( cls, "Description", testCaseName ); const char* className = class_getName( cls ); - getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, name.c_str(), desc.c_str(), SourceLineInfo() ) ); + getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, name.c_str(), desc.c_str(), SourceLineInfo("",0) ) ); noTestMethods++; } } @@ -3398,6 +2547,8 @@ namespace Catch { return noTestMethods; } +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) + namespace Matchers { namespace Impl { namespace NSStringMatchers { @@ -3409,61 +2560,61 @@ namespace Catch { arcSafeRelease( m_substr ); } - virtual bool match( NSString* arg ) const CATCH_OVERRIDE { + bool match( NSString* arg ) const override { return false; } - NSString* m_substr; + NSString* CATCH_ARC_STRONG m_substr; }; struct Equals : StringHolder { Equals( NSString* substr ) : StringHolder( substr ){} - virtual bool match( NSString* str ) const CATCH_OVERRIDE { + bool match( NSString* str ) const override { return (str != nil || m_substr == nil ) && [str isEqualToString:m_substr]; } - virtual std::string describe() const CATCH_OVERRIDE { - return "equals string: " + Catch::toString( m_substr ); + std::string describe() const override { + return "equals string: " + Catch::Detail::stringify( m_substr ); } }; struct Contains : StringHolder { Contains( NSString* substr ) : StringHolder( substr ){} - virtual bool match( NSString* str ) const { + bool match( NSString* str ) const { return (str != nil || m_substr == nil ) && [str rangeOfString:m_substr].location != NSNotFound; } - virtual std::string describe() const CATCH_OVERRIDE { - return "contains string: " + Catch::toString( m_substr ); + std::string describe() const override { + return "contains string: " + Catch::Detail::stringify( m_substr ); } }; struct StartsWith : StringHolder { StartsWith( NSString* substr ) : StringHolder( substr ){} - virtual bool match( NSString* str ) const { + bool match( NSString* str ) const override { return (str != nil || m_substr == nil ) && [str rangeOfString:m_substr].location == 0; } - virtual std::string describe() const CATCH_OVERRIDE { - return "starts with: " + Catch::toString( m_substr ); + std::string describe() const override { + return "starts with: " + Catch::Detail::stringify( m_substr ); } }; struct EndsWith : StringHolder { EndsWith( NSString* substr ) : StringHolder( substr ){} - virtual bool match( NSString* str ) const { + bool match( NSString* str ) const override { return (str != nil || m_substr == nil ) && [str rangeOfString:m_substr].location == [str length] - [m_substr length]; } - virtual std::string describe() const CATCH_OVERRIDE { - return "ends with: " + Catch::toString( m_substr ); + std::string describe() const override { + return "ends with: " + Catch::Detail::stringify( m_substr ); } }; @@ -3486,86 +2637,52 @@ namespace Catch { using namespace Matchers; +#endif // CATCH_CONFIG_DISABLE_MATCHERS + } // namespace Catch /////////////////////////////////////////////////////////////////////////////// -#define OC_TEST_CASE( name, desc )\ -+(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Name_test ) \ -{\ +#define OC_MAKE_UNIQUE_NAME( root, uniqueSuffix ) root##uniqueSuffix +#define OC_TEST_CASE2( name, desc, uniqueSuffix ) \ ++(NSString*) OC_MAKE_UNIQUE_NAME( Catch_Name_test_, uniqueSuffix ) \ +{ \ return @ name; \ -}\ -+(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Description_test ) \ +} \ ++(NSString*) OC_MAKE_UNIQUE_NAME( Catch_Description_test_, uniqueSuffix ) \ { \ return @ desc; \ } \ --(void) INTERNAL_CATCH_UNIQUE_NAME( Catch_TestCase_test ) +-(void) OC_MAKE_UNIQUE_NAME( Catch_TestCase_test_, uniqueSuffix ) +#define OC_TEST_CASE( name, desc ) OC_TEST_CASE2( name, desc, __LINE__ ) + +// end catch_objc.hpp #endif -#ifdef CATCH_IMPL +#ifdef CATCH_CONFIG_EXTERNAL_INTERFACES +// start catch_external_interfaces.h -// !TBD: Move the leak detector code into a separate header -#ifdef CATCH_CONFIG_WINDOWS_CRTDBG -#include -class LeakDetector { -public: - LeakDetector() { - int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); - flag |= _CRTDBG_LEAK_CHECK_DF; - flag |= _CRTDBG_ALLOC_MEM_DF; - _CrtSetDbgFlag(flag); - _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG); - _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR); - // Change this to leaking allocation's number to break there - _CrtSetBreakAlloc(-1); - } -}; -#else -class LeakDetector {}; -#endif +// start catch_reporter_bases.hpp -LeakDetector leakDetector; +// start catch_interfaces_reporter.h -// #included from: internal/catch_impl.hpp -#define TWOBLUECUBES_CATCH_IMPL_HPP_INCLUDED +// start catch_config.hpp -// Collect all the implementation files together here -// These are the equivalent of what would usually be cpp files - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wweak-vtables" -#endif - -// #included from: ../catch_session.hpp -#define TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED - -// #included from: internal/catch_commandline.hpp -#define TWOBLUECUBES_CATCH_COMMANDLINE_HPP_INCLUDED - -// #included from: catch_config.hpp -#define TWOBLUECUBES_CATCH_CONFIG_HPP_INCLUDED - -// #included from: catch_test_spec_parser.hpp -#define TWOBLUECUBES_CATCH_TEST_SPEC_PARSER_HPP_INCLUDED +// start catch_test_spec_parser.h #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wpadded" #endif -// #included from: catch_test_spec.hpp -#define TWOBLUECUBES_CATCH_TEST_SPEC_HPP_INCLUDED +// start catch_test_spec.h #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wpadded" #endif -// #included from: catch_wildcard_pattern.hpp -#define TWOBLUECUBES_CATCH_WILDCARD_PATTERN_HPP_INCLUDED - -#include +// start catch_wildcard_pattern.h namespace Catch { @@ -3579,119 +2696,68 @@ namespace Catch public: - WildcardPattern( std::string const& pattern, CaseSensitive::Choice caseSensitivity ) - : m_caseSensitivity( caseSensitivity ), - m_wildcard( NoWildcard ), - m_pattern( adjustCase( pattern ) ) - { - if( startsWith( m_pattern, '*' ) ) { - m_pattern = m_pattern.substr( 1 ); - m_wildcard = WildcardAtStart; - } - if( endsWith( m_pattern, '*' ) ) { - m_pattern = m_pattern.substr( 0, m_pattern.size()-1 ); - m_wildcard = static_cast( m_wildcard | WildcardAtEnd ); - } - } - virtual ~WildcardPattern(); - virtual bool matches( std::string const& str ) const { - switch( m_wildcard ) { - case NoWildcard: - return m_pattern == adjustCase( str ); - case WildcardAtStart: - return endsWith( adjustCase( str ), m_pattern ); - case WildcardAtEnd: - return startsWith( adjustCase( str ), m_pattern ); - case WildcardAtBothEnds: - return contains( adjustCase( str ), m_pattern ); - } + WildcardPattern( std::string const& pattern, CaseSensitive::Choice caseSensitivity ); + virtual ~WildcardPattern() = default; + virtual bool matches( std::string const& str ) const; -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunreachable-code" -#endif - throw std::logic_error( "Unknown enum" ); -#ifdef __clang__ -#pragma clang diagnostic pop -#endif - } private: - std::string adjustCase( std::string const& str ) const { - return m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str; - } + std::string adjustCase( std::string const& str ) const; CaseSensitive::Choice m_caseSensitivity; - WildcardPosition m_wildcard; + WildcardPosition m_wildcard = NoWildcard; std::string m_pattern; }; } +// end catch_wildcard_pattern.h #include #include +#include namespace Catch { class TestSpec { - struct Pattern : SharedImpl<> { + struct Pattern { virtual ~Pattern(); virtual bool matches( TestCaseInfo const& testCase ) const = 0; }; + using PatternPtr = std::shared_ptr; + class NamePattern : public Pattern { public: - NamePattern( std::string const& name ) - : m_wildcardPattern( toLower( name ), CaseSensitive::No ) - {} + NamePattern( std::string const& name ); virtual ~NamePattern(); - virtual bool matches( TestCaseInfo const& testCase ) const { - return m_wildcardPattern.matches( toLower( testCase.name ) ); - } + virtual bool matches( TestCaseInfo const& testCase ) const override; private: WildcardPattern m_wildcardPattern; }; class TagPattern : public Pattern { public: - TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {} + TagPattern( std::string const& tag ); virtual ~TagPattern(); - virtual bool matches( TestCaseInfo const& testCase ) const { - return testCase.lcaseTags.find( m_tag ) != testCase.lcaseTags.end(); - } + virtual bool matches( TestCaseInfo const& testCase ) const override; private: std::string m_tag; }; class ExcludedPattern : public Pattern { public: - ExcludedPattern( Ptr const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {} + ExcludedPattern( PatternPtr const& underlyingPattern ); virtual ~ExcludedPattern(); - virtual bool matches( TestCaseInfo const& testCase ) const { return !m_underlyingPattern->matches( testCase ); } + virtual bool matches( TestCaseInfo const& testCase ) const override; private: - Ptr m_underlyingPattern; + PatternPtr m_underlyingPattern; }; struct Filter { - std::vector > m_patterns; + std::vector m_patterns; - bool matches( TestCaseInfo const& testCase ) const { - // All patterns in a filter must match for the filter to be a match - for( std::vector >::const_iterator it = m_patterns.begin(), itEnd = m_patterns.end(); it != itEnd; ++it ) { - if( !(*it)->matches( testCase ) ) - return false; - } - return true; - } + bool matches( TestCaseInfo const& testCase ) const; }; public: - bool hasFilters() const { - return !m_filters.empty(); - } - bool matches( TestCaseInfo const& testCase ) const { - // A TestSpec matches if any filter matches - for( std::vector::const_iterator it = m_filters.begin(), itEnd = m_filters.end(); it != itEnd; ++it ) - if( it->matches( testCase ) ) - return true; - return false; - } + bool hasFilters() const; + bool matches( TestCaseInfo const& testCase ) const; private: std::vector m_filters; @@ -3704,87 +2770,56 @@ namespace Catch { #pragma clang diagnostic pop #endif +// end catch_test_spec.h +// start catch_interfaces_tag_alias_registry.h + +#include + +namespace Catch { + + struct TagAlias; + + struct ITagAliasRegistry { + virtual ~ITagAliasRegistry(); + // Nullptr if not present + virtual TagAlias const* find( std::string const& alias ) const = 0; + virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const = 0; + + static ITagAliasRegistry const& get(); + }; + +} // end namespace Catch + +// end catch_interfaces_tag_alias_registry.h namespace Catch { class TestSpecParser { enum Mode{ None, Name, QuotedName, Tag, EscapedName }; - Mode m_mode; - bool m_exclusion; - std::size_t m_start, m_pos; + Mode m_mode = None; + bool m_exclusion = false; + std::size_t m_start = std::string::npos, m_pos = 0; std::string m_arg; std::vector m_escapeChars; TestSpec::Filter m_currentFilter; TestSpec m_testSpec; - ITagAliasRegistry const* m_tagAliases; + ITagAliasRegistry const* m_tagAliases = nullptr; public: - TestSpecParser( ITagAliasRegistry const& tagAliases ) :m_mode(None), m_exclusion(false), m_start(0), m_pos(0), m_tagAliases( &tagAliases ) {} + TestSpecParser( ITagAliasRegistry const& tagAliases ); + + TestSpecParser& parse( std::string const& arg ); + TestSpec testSpec(); - TestSpecParser& parse( std::string const& arg ) { - m_mode = None; - m_exclusion = false; - m_start = std::string::npos; - m_arg = m_tagAliases->expandAliases( arg ); - m_escapeChars.clear(); - for( m_pos = 0; m_pos < m_arg.size(); ++m_pos ) - visitChar( m_arg[m_pos] ); - if( m_mode == Name ) - addPattern(); - return *this; - } - TestSpec testSpec() { - addFilter(); - return m_testSpec; - } private: - void visitChar( char c ) { - if( m_mode == None ) { - switch( c ) { - case ' ': return; - case '~': m_exclusion = true; return; - case '[': return startNewMode( Tag, ++m_pos ); - case '"': return startNewMode( QuotedName, ++m_pos ); - case '\\': return escape(); - default: startNewMode( Name, m_pos ); break; - } - } - if( m_mode == Name ) { - if( c == ',' ) { - addPattern(); - addFilter(); - } - else if( c == '[' ) { - if( subString() == "exclude:" ) - m_exclusion = true; - else - addPattern(); - startNewMode( Tag, ++m_pos ); - } - else if( c == '\\' ) - escape(); - } - else if( m_mode == EscapedName ) - m_mode = Name; - else if( m_mode == QuotedName && c == '"' ) - addPattern(); - else if( m_mode == Tag && c == ']' ) - addPattern(); - } - void startNewMode( Mode mode, std::size_t start ) { - m_mode = mode; - m_start = start; - } - void escape() { - if( m_mode == None ) - m_start = m_pos; - m_mode = EscapedName; - m_escapeChars.push_back( m_pos ); - } - std::string subString() const { return m_arg.substr( m_start, m_pos - m_start ); } + void visitChar( char c ); + void startNewMode( Mode mode, std::size_t start ); + void escape(); + std::string subString() const; + template void addPattern() { std::string token = subString(); - for( size_t i = 0; i < m_escapeChars.size(); ++i ) + for( std::size_t i = 0; i < m_escapeChars.size(); ++i ) token = token.substr( 0, m_escapeChars[i]-m_start-i ) + token.substr( m_escapeChars[i]-m_start-i+1 ); m_escapeChars.clear(); if( startsWith( token, "exclude:" ) ) { @@ -3792,24 +2827,18 @@ namespace Catch { token = token.substr( 8 ); } if( !token.empty() ) { - Ptr pattern = new T( token ); + TestSpec::PatternPtr pattern = std::make_shared( token ); if( m_exclusion ) - pattern = new TestSpec::ExcludedPattern( pattern ); + pattern = std::make_shared( pattern ); m_currentFilter.m_patterns.push_back( pattern ); } m_exclusion = false; m_mode = None; } - void addFilter() { - if( !m_currentFilter.m_patterns.empty() ) { - m_testSpec.m_filters.push_back( m_currentFilter ); - m_currentFilter = TestSpec::Filter(); - } - } + + void addFilter(); }; - inline TestSpec parseTestSpec( std::string const& arg ) { - return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec(); - } + TestSpec parseTestSpec( std::string const& arg ); } // namespace Catch @@ -3817,20 +2846,21 @@ namespace Catch { #pragma clang diagnostic pop #endif -// #included from: catch_interfaces_config.h -#define TWOBLUECUBES_CATCH_INTERFACES_CONFIG_H_INCLUDED +// end catch_test_spec_parser.h +// start catch_interfaces_config.h #include #include #include +#include namespace Catch { - struct Verbosity { enum Level { - NoOutput = 0, - Quiet, - Normal - }; }; + enum class Verbosity { + Quiet = 0, + Normal, + High + }; struct WarnAbout { enum What { Nothing = 0x00, @@ -3852,10 +2882,16 @@ namespace Catch { Yes, No }; }; + struct WaitForKeypress { enum When { + Never, + BeforeStart = 1, + BeforeExit = 2, + BeforeStartAndExit = BeforeStart | BeforeExit + }; }; class TestSpec; - struct IConfig : IShared { + struct IConfig : NonCopyable { virtual ~IConfig(); @@ -3871,17 +2907,20 @@ namespace Catch { virtual TestSpec const& testSpec() const = 0; virtual RunTests::InWhatOrder runOrder() const = 0; virtual unsigned int rngSeed() const = 0; + virtual int benchmarkResolutionMultiple() const = 0; virtual UseColour::YesOrNo useColour() const = 0; virtual std::vector const& getSectionsToRun() const = 0; - + virtual Verbosity verbosity() const = 0; }; + + using IConfigPtr = std::shared_ptr; } -// #included from: catch_stream.h -#define TWOBLUECUBES_CATCH_STREAM_H_INCLUDED +// end catch_interfaces_config.h +// Libstdc++ doesn't like incomplete classes for unique_ptr +// start catch_stream.h -// #included from: catch_streambuf.h -#define TWOBLUECUBES_CATCH_STREAMBUF_H_INCLUDED +// start catch_streambuf.h #include @@ -3889,10 +2928,11 @@ namespace Catch { class StreamBufBase : public std::streambuf { public: - virtual ~StreamBufBase() CATCH_NOEXCEPT; + virtual ~StreamBufBase(); }; } +// end catch_streambuf.h #include #include #include @@ -3905,7 +2945,7 @@ namespace Catch { std::ostream& clog(); struct IStream { - virtual ~IStream() CATCH_NOEXCEPT; + virtual ~IStream(); virtual std::ostream& stream() const = 0; }; @@ -3913,37 +2953,38 @@ namespace Catch { mutable std::ofstream m_ofs; public: FileStream( std::string const& filename ); - virtual ~FileStream() CATCH_NOEXCEPT; + ~FileStream() override = default; public: // IStream - virtual std::ostream& stream() const CATCH_OVERRIDE; + std::ostream& stream() const override; }; class CoutStream : public IStream { mutable std::ostream m_os; public: CoutStream(); - virtual ~CoutStream() CATCH_NOEXCEPT; + ~CoutStream() override = default; public: // IStream - virtual std::ostream& stream() const CATCH_OVERRIDE; + std::ostream& stream() const override; }; class DebugOutStream : public IStream { - CATCH_AUTO_PTR( StreamBufBase ) m_streamBuf; + std::unique_ptr m_streamBuf; mutable std::ostream m_os; public: DebugOutStream(); - virtual ~DebugOutStream() CATCH_NOEXCEPT; + ~DebugOutStream() override = default; public: // IStream - virtual std::ostream& stream() const CATCH_OVERRIDE; + std::ostream& stream() const override; }; } +// end catch_stream.h + #include #include #include -#include #ifndef CATCH_CONFIG_CONSOLE_WIDTH #define CATCH_CONFIG_CONSOLE_WIDTH 80 @@ -3951,50 +2992,32 @@ namespace Catch { namespace Catch { + struct IStream; + struct ConfigData { + bool listTests = false; + bool listTags = false; + bool listReporters = false; + bool listTestNamesOnly = false; - ConfigData() - : listTests( false ), - listTags( false ), - listReporters( false ), - listTestNamesOnly( false ), - listExtraInfo( false ), - showSuccessfulTests( false ), - shouldDebugBreak( false ), - noThrow( false ), - showHelp( false ), - showInvisibles( false ), - filenamesAsTags( false ), - abortAfter( -1 ), - rngSeed( 0 ), - verbosity( Verbosity::Normal ), - warnings( WarnAbout::Nothing ), - showDurations( ShowDurations::DefaultForReporter ), - runOrder( RunTests::InDeclarationOrder ), - useColour( UseColour::Auto ) - {} + bool showSuccessfulTests = false; + bool shouldDebugBreak = false; + bool noThrow = false; + bool showHelp = false; + bool showInvisibles = false; + bool filenamesAsTags = false; + bool libIdentify = false; - bool listTests; - bool listTags; - bool listReporters; - bool listTestNamesOnly; - bool listExtraInfo; + int abortAfter = -1; + unsigned int rngSeed = 0; + int benchmarkResolutionMultiple = 100; - bool showSuccessfulTests; - bool shouldDebugBreak; - bool noThrow; - bool showHelp; - bool showInvisibles; - bool filenamesAsTags; - - int abortAfter; - unsigned int rngSeed; - - Verbosity::Level verbosity; - WarnAbout::What warnings; - ShowDurations::OrNot showDurations; - RunTests::InWhatOrder runOrder; - UseColour::YesOrNo useColour; + Verbosity verbosity = Verbosity::Normal; + WarnAbout::What warnings = WarnAbout::Nothing; + ShowDurations::OrNot showDurations = ShowDurations::DefaultForReporter; + RunTests::InWhatOrder runOrder = RunTests::InDeclarationOrder; + UseColour::YesOrNo useColour = UseColour::Auto; + WaitForKeypress::When waitForKeypress = WaitForKeypress::Never; std::string outputFilename; std::string name; @@ -4005,1505 +3028,638 @@ namespace Catch { std::vector sectionsToRun; }; - class Config : public SharedImpl { - private: - Config( Config const& other ); - Config& operator = ( Config const& other ); - virtual void dummy(); + class Config : public IConfig { public: - Config() - {} + Config() = default; + Config( ConfigData const& data ); + virtual ~Config() = default; - Config( ConfigData const& data ) - : m_data( data ), - m_stream( openStream() ) - { - if( !data.testsOrTags.empty() ) { - TestSpecParser parser( ITagAliasRegistry::get() ); - for( std::size_t i = 0; i < data.testsOrTags.size(); ++i ) - parser.parse( data.testsOrTags[i] ); - m_testSpec = parser.testSpec(); - } - } + std::string const& getFilename() const; - virtual ~Config() {} + bool listTests() const; + bool listTestNamesOnly() const; + bool listTags() const; + bool listReporters() const; - std::string const& getFilename() const { - return m_data.outputFilename ; - } + std::string getProcessName() const; - bool listTests() const { return m_data.listTests; } - bool listTestNamesOnly() const { return m_data.listTestNamesOnly; } - bool listTags() const { return m_data.listTags; } - bool listReporters() const { return m_data.listReporters; } - bool listExtraInfo() const { return m_data.listExtraInfo; } + std::vector const& getReporterNames() const; + std::vector const& getSectionsToRun() const override; - std::string getProcessName() const { return m_data.processName; } + virtual TestSpec const& testSpec() const override; - std::vector const& getReporterNames() const { return m_data.reporterNames; } - std::vector const& getSectionsToRun() const CATCH_OVERRIDE { return m_data.sectionsToRun; } - - virtual TestSpec const& testSpec() const CATCH_OVERRIDE { return m_testSpec; } - - bool showHelp() const { return m_data.showHelp; } + bool showHelp() const; // IConfig interface - virtual bool allowThrows() const CATCH_OVERRIDE { return !m_data.noThrow; } - virtual std::ostream& stream() const CATCH_OVERRIDE { return m_stream->stream(); } - virtual std::string name() const CATCH_OVERRIDE { return m_data.name.empty() ? m_data.processName : m_data.name; } - virtual bool includeSuccessfulResults() const CATCH_OVERRIDE { return m_data.showSuccessfulTests; } - virtual bool warnAboutMissingAssertions() const CATCH_OVERRIDE { return m_data.warnings & WarnAbout::NoAssertions; } - virtual ShowDurations::OrNot showDurations() const CATCH_OVERRIDE { return m_data.showDurations; } - virtual RunTests::InWhatOrder runOrder() const CATCH_OVERRIDE { return m_data.runOrder; } - virtual unsigned int rngSeed() const CATCH_OVERRIDE { return m_data.rngSeed; } - virtual UseColour::YesOrNo useColour() const CATCH_OVERRIDE { return m_data.useColour; } - virtual bool shouldDebugBreak() const CATCH_OVERRIDE { return m_data.shouldDebugBreak; } - virtual int abortAfter() const CATCH_OVERRIDE { return m_data.abortAfter; } - virtual bool showInvisibles() const CATCH_OVERRIDE { return m_data.showInvisibles; } + bool allowThrows() const override; + std::ostream& stream() const override; + std::string name() const override; + bool includeSuccessfulResults() const override; + bool warnAboutMissingAssertions() const override; + ShowDurations::OrNot showDurations() const override; + RunTests::InWhatOrder runOrder() const override; + unsigned int rngSeed() const override; + int benchmarkResolutionMultiple() const override; + UseColour::YesOrNo useColour() const override; + bool shouldDebugBreak() const override; + int abortAfter() const override; + bool showInvisibles() const override; + Verbosity verbosity() const override; private: - IStream const* openStream() { - if( m_data.outputFilename.empty() ) - return new CoutStream(); - else if( m_data.outputFilename[0] == '%' ) { - if( m_data.outputFilename == "%debug" ) - return new DebugOutStream(); - else - throw std::domain_error( "Unrecognised stream: " + m_data.outputFilename ); - } - else - return new FileStream( m_data.outputFilename ); - } + IStream const* openStream(); ConfigData m_data; - CATCH_AUTO_PTR( IStream const ) m_stream; + std::unique_ptr m_stream; TestSpec m_testSpec; }; } // end namespace Catch -// #included from: catch_clara.h -#define TWOBLUECUBES_CATCH_CLARA_H_INCLUDED - -// Use Catch's value for console width (store Clara's off to the side, if present) -#ifdef CLARA_CONFIG_CONSOLE_WIDTH -#define CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH CLARA_CONFIG_CONSOLE_WIDTH -#undef CLARA_CONFIG_CONSOLE_WIDTH -#endif -#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH - -// Declare Clara inside the Catch namespace -#define STITCH_CLARA_OPEN_NAMESPACE namespace Catch { -// #included from: ../external/clara.h - -// Version 0.0.2.4 - -// Only use header guard if we are not using an outer namespace -#if !defined(TWOBLUECUBES_CLARA_H_INCLUDED) || defined(STITCH_CLARA_OPEN_NAMESPACE) - -#ifndef STITCH_CLARA_OPEN_NAMESPACE -#define TWOBLUECUBES_CLARA_H_INCLUDED -#define STITCH_CLARA_OPEN_NAMESPACE -#define STITCH_CLARA_CLOSE_NAMESPACE -#else -#define STITCH_CLARA_CLOSE_NAMESPACE } -#endif - -#define STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE STITCH_CLARA_OPEN_NAMESPACE - -// ----------- #included from tbc_text_format.h ----------- - -// Only use header guard if we are not using an outer namespace -#if !defined(TBC_TEXT_FORMAT_H_INCLUDED) || defined(STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE) -#ifndef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE -#define TBC_TEXT_FORMAT_H_INCLUDED -#endif +// end catch_config.hpp +// start catch_assertionresult.h #include -#include -#include -#include -#include - -// Use optional outer namespace -#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE -namespace STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE { -#endif - -namespace Tbc { - -#ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH - const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH; -#else - const unsigned int consoleWidth = 80; -#endif - - struct TextAttributes { - TextAttributes() - : initialIndent( std::string::npos ), - indent( 0 ), - width( consoleWidth-1 ), - tabChar( '\t' ) - {} - - TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; } - TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; } - TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; } - TextAttributes& setTabChar( char _value ) { tabChar = _value; return *this; } - - std::size_t initialIndent; // indent of first line, or npos - std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos - std::size_t width; // maximum width of text, including indent. Longer text will wrap - char tabChar; // If this char is seen the indent is changed to current pos - }; - - class Text { - public: - Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() ) - : attr( _attr ) - { - std::string wrappableChars = " [({.,/|\\-"; - std::size_t indent = _attr.initialIndent != std::string::npos - ? _attr.initialIndent - : _attr.indent; - std::string remainder = _str; - - while( !remainder.empty() ) { - if( lines.size() >= 1000 ) { - lines.push_back( "... message truncated due to excessive size" ); - return; - } - std::size_t tabPos = std::string::npos; - std::size_t width = (std::min)( remainder.size(), _attr.width - indent ); - std::size_t pos = remainder.find_first_of( '\n' ); - if( pos <= width ) { - width = pos; - } - pos = remainder.find_last_of( _attr.tabChar, width ); - if( pos != std::string::npos ) { - tabPos = pos; - if( remainder[width] == '\n' ) - width--; - remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 ); - } - - if( width == remainder.size() ) { - spliceLine( indent, remainder, width ); - } - else if( remainder[width] == '\n' ) { - spliceLine( indent, remainder, width ); - if( width <= 1 || remainder.size() != 1 ) - remainder = remainder.substr( 1 ); - indent = _attr.indent; - } - else { - pos = remainder.find_last_of( wrappableChars, width ); - if( pos != std::string::npos && pos > 0 ) { - spliceLine( indent, remainder, pos ); - if( remainder[0] == ' ' ) - remainder = remainder.substr( 1 ); - } - else { - spliceLine( indent, remainder, width-1 ); - lines.back() += "-"; - } - if( lines.size() == 1 ) - indent = _attr.indent; - if( tabPos != std::string::npos ) - indent += tabPos; - } - } - } - - void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) { - lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) ); - _remainder = _remainder.substr( _pos ); - } - - typedef std::vector::const_iterator const_iterator; - - const_iterator begin() const { return lines.begin(); } - const_iterator end() const { return lines.end(); } - std::string const& last() const { return lines.back(); } - std::size_t size() const { return lines.size(); } - std::string const& operator[]( std::size_t _index ) const { return lines[_index]; } - std::string toString() const { - std::ostringstream oss; - oss << *this; - return oss.str(); - } - - friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) { - for( Text::const_iterator it = _text.begin(), itEnd = _text.end(); - it != itEnd; ++it ) { - if( it != _text.begin() ) - _stream << "\n"; - _stream << *it; - } - return _stream; - } - - private: - std::string str; - TextAttributes attr; - std::vector lines; - }; - -} // end namespace Tbc - -#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE -} // end outer namespace -#endif - -#endif // TBC_TEXT_FORMAT_H_INCLUDED - -// ----------- end of #include from tbc_text_format.h ----------- -// ........... back in clara.h - -#undef STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE - -// ----------- #included from clara_compilers.h ----------- - -#ifndef TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED -#define TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED - -// Detect a number of compiler features - mostly C++11/14 conformance - by compiler -// The following features are defined: -// -// CLARA_CONFIG_CPP11_NULLPTR : is nullptr supported? -// CLARA_CONFIG_CPP11_NOEXCEPT : is noexcept supported? -// CLARA_CONFIG_CPP11_GENERATED_METHODS : The delete and default keywords for compiler generated methods -// CLARA_CONFIG_CPP11_OVERRIDE : is override supported? -// CLARA_CONFIG_CPP11_UNIQUE_PTR : is unique_ptr supported (otherwise use auto_ptr) - -// CLARA_CONFIG_CPP11_OR_GREATER : Is C++11 supported? - -// CLARA_CONFIG_VARIADIC_MACROS : are variadic macros supported? - -// In general each macro has a _NO_ form -// (e.g. CLARA_CONFIG_CPP11_NO_NULLPTR) which disables the feature. -// Many features, at point of detection, define an _INTERNAL_ macro, so they -// can be combined, en-mass, with the _NO_ forms later. - -// All the C++11 features can be disabled with CLARA_CONFIG_NO_CPP11 - -#ifdef __clang__ - -#if __has_feature(cxx_nullptr) -#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR -#endif - -#if __has_feature(cxx_noexcept) -#define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT -#endif - -#endif // __clang__ - -//////////////////////////////////////////////////////////////////////////////// -// GCC -#ifdef __GNUC__ - -#if __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__) -#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR -#endif - -// - otherwise more recent versions define __cplusplus >= 201103L -// and will get picked up below - -#endif // __GNUC__ - -//////////////////////////////////////////////////////////////////////////////// -// Visual C++ -#ifdef _MSC_VER - -#if (_MSC_VER >= 1600) -#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR -#define CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR -#endif - -#if (_MSC_VER >= 1900 ) // (VC++ 13 (VS2015)) -#define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT -#define CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS -#endif - -#endif // _MSC_VER - -//////////////////////////////////////////////////////////////////////////////// -// C++ language feature support - -// catch all support for C++11 -#if defined(__cplusplus) && __cplusplus >= 201103L - -#define CLARA_CPP11_OR_GREATER - -#if !defined(CLARA_INTERNAL_CONFIG_CPP11_NULLPTR) -#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR -#endif - -#ifndef CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT -#define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT -#endif - -#ifndef CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS -#define CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS -#endif - -#if !defined(CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE) -#define CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE -#endif -#if !defined(CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) -#define CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR -#endif - -#endif // __cplusplus >= 201103L - -// Now set the actual defines based on the above + anything the user has configured -#if defined(CLARA_INTERNAL_CONFIG_CPP11_NULLPTR) && !defined(CLARA_CONFIG_CPP11_NO_NULLPTR) && !defined(CLARA_CONFIG_CPP11_NULLPTR) && !defined(CLARA_CONFIG_NO_CPP11) -#define CLARA_CONFIG_CPP11_NULLPTR -#endif -#if defined(CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_CONFIG_CPP11_NO_NOEXCEPT) && !defined(CLARA_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_CONFIG_NO_CPP11) -#define CLARA_CONFIG_CPP11_NOEXCEPT -#endif -#if defined(CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS) && !defined(CLARA_CONFIG_CPP11_NO_GENERATED_METHODS) && !defined(CLARA_CONFIG_CPP11_GENERATED_METHODS) && !defined(CLARA_CONFIG_NO_CPP11) -#define CLARA_CONFIG_CPP11_GENERATED_METHODS -#endif -#if defined(CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE) && !defined(CLARA_CONFIG_NO_OVERRIDE) && !defined(CLARA_CONFIG_CPP11_OVERRIDE) && !defined(CLARA_CONFIG_NO_CPP11) -#define CLARA_CONFIG_CPP11_OVERRIDE -#endif -#if defined(CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) && !defined(CLARA_CONFIG_NO_UNIQUE_PTR) && !defined(CLARA_CONFIG_CPP11_UNIQUE_PTR) && !defined(CLARA_CONFIG_NO_CPP11) -#define CLARA_CONFIG_CPP11_UNIQUE_PTR -#endif - -// noexcept support: -#if defined(CLARA_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_NOEXCEPT) -#define CLARA_NOEXCEPT noexcept -# define CLARA_NOEXCEPT_IS(x) noexcept(x) -#else -#define CLARA_NOEXCEPT throw() -# define CLARA_NOEXCEPT_IS(x) -#endif - -// nullptr support -#ifdef CLARA_CONFIG_CPP11_NULLPTR -#define CLARA_NULL nullptr -#else -#define CLARA_NULL NULL -#endif - -// override support -#ifdef CLARA_CONFIG_CPP11_OVERRIDE -#define CLARA_OVERRIDE override -#else -#define CLARA_OVERRIDE -#endif - -// unique_ptr support -#ifdef CLARA_CONFIG_CPP11_UNIQUE_PTR -# define CLARA_AUTO_PTR( T ) std::unique_ptr -#else -# define CLARA_AUTO_PTR( T ) std::auto_ptr -#endif - -#endif // TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED - -// ----------- end of #include from clara_compilers.h ----------- -// ........... back in clara.h - -#include -#include -#include - -#if defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) -#define CLARA_PLATFORM_WINDOWS -#endif - -// Use optional outer namespace -#ifdef STITCH_CLARA_OPEN_NAMESPACE -STITCH_CLARA_OPEN_NAMESPACE -#endif - -namespace Clara { - - struct UnpositionalTag {}; - - extern UnpositionalTag _; - -#ifdef CLARA_CONFIG_MAIN - UnpositionalTag _; -#endif - - namespace Detail { - -#ifdef CLARA_CONSOLE_WIDTH - const unsigned int consoleWidth = CLARA_CONFIG_CONSOLE_WIDTH; -#else - const unsigned int consoleWidth = 80; -#endif - - using namespace Tbc; - - inline bool startsWith( std::string const& str, std::string const& prefix ) { - return str.size() >= prefix.size() && str.substr( 0, prefix.size() ) == prefix; - } - - template struct RemoveConstRef{ typedef T type; }; - template struct RemoveConstRef{ typedef T type; }; - template struct RemoveConstRef{ typedef T type; }; - template struct RemoveConstRef{ typedef T type; }; - - template struct IsBool { static const bool value = false; }; - template<> struct IsBool { static const bool value = true; }; - - template - void convertInto( std::string const& _source, T& _dest ) { - std::stringstream ss; - ss << _source; - ss >> _dest; - if( ss.fail() ) - throw std::runtime_error( "Unable to convert " + _source + " to destination type" ); - } - inline void convertInto( std::string const& _source, std::string& _dest ) { - _dest = _source; - } - char toLowerCh(char c) { - return static_cast( std::tolower( c ) ); - } - inline void convertInto( std::string const& _source, bool& _dest ) { - std::string sourceLC = _source; - std::transform( sourceLC.begin(), sourceLC.end(), sourceLC.begin(), toLowerCh ); - if( sourceLC == "y" || sourceLC == "1" || sourceLC == "true" || sourceLC == "yes" || sourceLC == "on" ) - _dest = true; - else if( sourceLC == "n" || sourceLC == "0" || sourceLC == "false" || sourceLC == "no" || sourceLC == "off" ) - _dest = false; - else - throw std::runtime_error( "Expected a boolean value but did not recognise:\n '" + _source + "'" ); - } - - template - struct IArgFunction { - virtual ~IArgFunction() {} -#ifdef CLARA_CONFIG_CPP11_GENERATED_METHODS - IArgFunction() = default; - IArgFunction( IArgFunction const& ) = default; -#endif - virtual void set( ConfigT& config, std::string const& value ) const = 0; - virtual bool takesArg() const = 0; - virtual IArgFunction* clone() const = 0; - }; - - template - class BoundArgFunction { - public: - BoundArgFunction() : functionObj( CLARA_NULL ) {} - BoundArgFunction( IArgFunction* _functionObj ) : functionObj( _functionObj ) {} - BoundArgFunction( BoundArgFunction const& other ) : functionObj( other.functionObj ? other.functionObj->clone() : CLARA_NULL ) {} - BoundArgFunction& operator = ( BoundArgFunction const& other ) { - IArgFunction* newFunctionObj = other.functionObj ? other.functionObj->clone() : CLARA_NULL; - delete functionObj; - functionObj = newFunctionObj; - return *this; - } - ~BoundArgFunction() { delete functionObj; } - - void set( ConfigT& config, std::string const& value ) const { - functionObj->set( config, value ); - } - bool takesArg() const { return functionObj->takesArg(); } - - bool isSet() const { - return functionObj != CLARA_NULL; - } - private: - IArgFunction* functionObj; - }; - - template - struct NullBinder : IArgFunction{ - virtual void set( C&, std::string const& ) const {} - virtual bool takesArg() const { return true; } - virtual IArgFunction* clone() const { return new NullBinder( *this ); } - }; - - template - struct BoundDataMember : IArgFunction{ - BoundDataMember( M C::* _member ) : member( _member ) {} - virtual void set( C& p, std::string const& stringValue ) const { - convertInto( stringValue, p.*member ); - } - virtual bool takesArg() const { return !IsBool::value; } - virtual IArgFunction* clone() const { return new BoundDataMember( *this ); } - M C::* member; - }; - template - struct BoundUnaryMethod : IArgFunction{ - BoundUnaryMethod( void (C::*_member)( M ) ) : member( _member ) {} - virtual void set( C& p, std::string const& stringValue ) const { - typename RemoveConstRef::type value; - convertInto( stringValue, value ); - (p.*member)( value ); - } - virtual bool takesArg() const { return !IsBool::value; } - virtual IArgFunction* clone() const { return new BoundUnaryMethod( *this ); } - void (C::*member)( M ); - }; - template - struct BoundNullaryMethod : IArgFunction{ - BoundNullaryMethod( void (C::*_member)() ) : member( _member ) {} - virtual void set( C& p, std::string const& stringValue ) const { - bool value; - convertInto( stringValue, value ); - if( value ) - (p.*member)(); - } - virtual bool takesArg() const { return false; } - virtual IArgFunction* clone() const { return new BoundNullaryMethod( *this ); } - void (C::*member)(); - }; - - template - struct BoundUnaryFunction : IArgFunction{ - BoundUnaryFunction( void (*_function)( C& ) ) : function( _function ) {} - virtual void set( C& obj, std::string const& stringValue ) const { - bool value; - convertInto( stringValue, value ); - if( value ) - function( obj ); - } - virtual bool takesArg() const { return false; } - virtual IArgFunction* clone() const { return new BoundUnaryFunction( *this ); } - void (*function)( C& ); - }; - - template - struct BoundBinaryFunction : IArgFunction{ - BoundBinaryFunction( void (*_function)( C&, T ) ) : function( _function ) {} - virtual void set( C& obj, std::string const& stringValue ) const { - typename RemoveConstRef::type value; - convertInto( stringValue, value ); - function( obj, value ); - } - virtual bool takesArg() const { return !IsBool::value; } - virtual IArgFunction* clone() const { return new BoundBinaryFunction( *this ); } - void (*function)( C&, T ); - }; - - } // namespace Detail - - inline std::vector argsToVector( int argc, char const* const* const argv ) { - std::vector args( static_cast( argc ) ); - for( std::size_t i = 0; i < static_cast( argc ); ++i ) - args[i] = argv[i]; - - return args; - } - - class Parser { - enum Mode { None, MaybeShortOpt, SlashOpt, ShortOpt, LongOpt, Positional }; - Mode mode; - std::size_t from; - bool inQuotes; - public: - - struct Token { - enum Type { Positional, ShortOpt, LongOpt }; - Token( Type _type, std::string const& _data ) : type( _type ), data( _data ) {} - Type type; - std::string data; - }; - - Parser() : mode( None ), from( 0 ), inQuotes( false ){} - - void parseIntoTokens( std::vector const& args, std::vector& tokens ) { - const std::string doubleDash = "--"; - for( std::size_t i = 1; i < args.size() && args[i] != doubleDash; ++i ) - parseIntoTokens( args[i], tokens); - } - - void parseIntoTokens( std::string const& arg, std::vector& tokens ) { - for( std::size_t i = 0; i < arg.size(); ++i ) { - char c = arg[i]; - if( c == '"' ) - inQuotes = !inQuotes; - mode = handleMode( i, c, arg, tokens ); - } - mode = handleMode( arg.size(), '\0', arg, tokens ); - } - Mode handleMode( std::size_t i, char c, std::string const& arg, std::vector& tokens ) { - switch( mode ) { - case None: return handleNone( i, c ); - case MaybeShortOpt: return handleMaybeShortOpt( i, c ); - case ShortOpt: - case LongOpt: - case SlashOpt: return handleOpt( i, c, arg, tokens ); - case Positional: return handlePositional( i, c, arg, tokens ); - default: throw std::logic_error( "Unknown mode" ); - } - } - - Mode handleNone( std::size_t i, char c ) { - if( inQuotes ) { - from = i; - return Positional; - } - switch( c ) { - case '-': return MaybeShortOpt; -#ifdef CLARA_PLATFORM_WINDOWS - case '/': from = i+1; return SlashOpt; -#endif - default: from = i; return Positional; - } - } - Mode handleMaybeShortOpt( std::size_t i, char c ) { - switch( c ) { - case '-': from = i+1; return LongOpt; - default: from = i; return ShortOpt; - } - } - - Mode handleOpt( std::size_t i, char c, std::string const& arg, std::vector& tokens ) { - if( std::string( ":=\0", 3 ).find( c ) == std::string::npos ) - return mode; - - std::string optName = arg.substr( from, i-from ); - if( mode == ShortOpt ) - for( std::size_t j = 0; j < optName.size(); ++j ) - tokens.push_back( Token( Token::ShortOpt, optName.substr( j, 1 ) ) ); - else if( mode == SlashOpt && optName.size() == 1 ) - tokens.push_back( Token( Token::ShortOpt, optName ) ); - else - tokens.push_back( Token( Token::LongOpt, optName ) ); - return None; - } - Mode handlePositional( std::size_t i, char c, std::string const& arg, std::vector& tokens ) { - if( inQuotes || std::string( "\0", 1 ).find( c ) == std::string::npos ) - return mode; - - std::string data = arg.substr( from, i-from ); - tokens.push_back( Token( Token::Positional, data ) ); - return None; - } - }; - - template - struct CommonArgProperties { - CommonArgProperties() {} - CommonArgProperties( Detail::BoundArgFunction const& _boundField ) : boundField( _boundField ) {} - - Detail::BoundArgFunction boundField; - std::string description; - std::string detail; - std::string placeholder; // Only value if boundField takes an arg - - bool takesArg() const { - return !placeholder.empty(); - } - void validate() const { - if( !boundField.isSet() ) - throw std::logic_error( "option not bound" ); - } - }; - struct OptionArgProperties { - std::vector shortNames; - std::string longName; - - bool hasShortName( std::string const& shortName ) const { - return std::find( shortNames.begin(), shortNames.end(), shortName ) != shortNames.end(); - } - bool hasLongName( std::string const& _longName ) const { - return _longName == longName; - } - }; - struct PositionalArgProperties { - PositionalArgProperties() : position( -1 ) {} - int position; // -1 means non-positional (floating) - - bool isFixedPositional() const { - return position != -1; - } - }; - - template - class CommandLine { - - struct Arg : CommonArgProperties, OptionArgProperties, PositionalArgProperties { - Arg() {} - Arg( Detail::BoundArgFunction const& _boundField ) : CommonArgProperties( _boundField ) {} - - using CommonArgProperties::placeholder; // !TBD - - std::string dbgName() const { - if( !longName.empty() ) - return "--" + longName; - if( !shortNames.empty() ) - return "-" + shortNames[0]; - return "positional args"; - } - std::string commands() const { - std::ostringstream oss; - bool first = true; - std::vector::const_iterator it = shortNames.begin(), itEnd = shortNames.end(); - for(; it != itEnd; ++it ) { - if( first ) - first = false; - else - oss << ", "; - oss << "-" << *it; - } - if( !longName.empty() ) { - if( !first ) - oss << ", "; - oss << "--" << longName; - } - if( !placeholder.empty() ) - oss << " <" << placeholder << ">"; - return oss.str(); - } - }; - - typedef CLARA_AUTO_PTR( Arg ) ArgAutoPtr; - - friend void addOptName( Arg& arg, std::string const& optName ) - { - if( optName.empty() ) - return; - if( Detail::startsWith( optName, "--" ) ) { - if( !arg.longName.empty() ) - throw std::logic_error( "Only one long opt may be specified. '" - + arg.longName - + "' already specified, now attempting to add '" - + optName + "'" ); - arg.longName = optName.substr( 2 ); - } - else if( Detail::startsWith( optName, "-" ) ) - arg.shortNames.push_back( optName.substr( 1 ) ); - else - throw std::logic_error( "option must begin with - or --. Option was: '" + optName + "'" ); - } - friend void setPositionalArg( Arg& arg, int position ) - { - arg.position = position; - } - - class ArgBuilder { - public: - ArgBuilder( Arg* arg ) : m_arg( arg ) {} - - // Bind a non-boolean data member (requires placeholder string) - template - void bind( M C::* field, std::string const& placeholder ) { - m_arg->boundField = new Detail::BoundDataMember( field ); - m_arg->placeholder = placeholder; - } - // Bind a boolean data member (no placeholder required) - template - void bind( bool C::* field ) { - m_arg->boundField = new Detail::BoundDataMember( field ); - } - - // Bind a method taking a single, non-boolean argument (requires a placeholder string) - template - void bind( void (C::* unaryMethod)( M ), std::string const& placeholder ) { - m_arg->boundField = new Detail::BoundUnaryMethod( unaryMethod ); - m_arg->placeholder = placeholder; - } - - // Bind a method taking a single, boolean argument (no placeholder string required) - template - void bind( void (C::* unaryMethod)( bool ) ) { - m_arg->boundField = new Detail::BoundUnaryMethod( unaryMethod ); - } - - // Bind a method that takes no arguments (will be called if opt is present) - template - void bind( void (C::* nullaryMethod)() ) { - m_arg->boundField = new Detail::BoundNullaryMethod( nullaryMethod ); - } - - // Bind a free function taking a single argument - the object to operate on (no placeholder string required) - template - void bind( void (* unaryFunction)( C& ) ) { - m_arg->boundField = new Detail::BoundUnaryFunction( unaryFunction ); - } - - // Bind a free function taking a single argument - the object to operate on (requires a placeholder string) - template - void bind( void (* binaryFunction)( C&, T ), std::string const& placeholder ) { - m_arg->boundField = new Detail::BoundBinaryFunction( binaryFunction ); - m_arg->placeholder = placeholder; - } - - ArgBuilder& describe( std::string const& description ) { - m_arg->description = description; - return *this; - } - ArgBuilder& detail( std::string const& detail ) { - m_arg->detail = detail; - return *this; - } - - protected: - Arg* m_arg; - }; - - class OptBuilder : public ArgBuilder { - public: - OptBuilder( Arg* arg ) : ArgBuilder( arg ) {} - OptBuilder( OptBuilder& other ) : ArgBuilder( other ) {} - - OptBuilder& operator[]( std::string const& optName ) { - addOptName( *ArgBuilder::m_arg, optName ); - return *this; - } - }; - - public: - - CommandLine() - : m_boundProcessName( new Detail::NullBinder() ), - m_highestSpecifiedArgPosition( 0 ), - m_throwOnUnrecognisedTokens( false ) - {} - CommandLine( CommandLine const& other ) - : m_boundProcessName( other.m_boundProcessName ), - m_options ( other.m_options ), - m_positionalArgs( other.m_positionalArgs ), - m_highestSpecifiedArgPosition( other.m_highestSpecifiedArgPosition ), - m_throwOnUnrecognisedTokens( other.m_throwOnUnrecognisedTokens ) - { - if( other.m_floatingArg.get() ) - m_floatingArg.reset( new Arg( *other.m_floatingArg ) ); - } - - CommandLine& setThrowOnUnrecognisedTokens( bool shouldThrow = true ) { - m_throwOnUnrecognisedTokens = shouldThrow; - return *this; - } - - OptBuilder operator[]( std::string const& optName ) { - m_options.push_back( Arg() ); - addOptName( m_options.back(), optName ); - OptBuilder builder( &m_options.back() ); - return builder; - } - - ArgBuilder operator[]( int position ) { - m_positionalArgs.insert( std::make_pair( position, Arg() ) ); - if( position > m_highestSpecifiedArgPosition ) - m_highestSpecifiedArgPosition = position; - setPositionalArg( m_positionalArgs[position], position ); - ArgBuilder builder( &m_positionalArgs[position] ); - return builder; - } - - // Invoke this with the _ instance - ArgBuilder operator[]( UnpositionalTag ) { - if( m_floatingArg.get() ) - throw std::logic_error( "Only one unpositional argument can be added" ); - m_floatingArg.reset( new Arg() ); - ArgBuilder builder( m_floatingArg.get() ); - return builder; - } - - template - void bindProcessName( M C::* field ) { - m_boundProcessName = new Detail::BoundDataMember( field ); - } - template - void bindProcessName( void (C::*_unaryMethod)( M ) ) { - m_boundProcessName = new Detail::BoundUnaryMethod( _unaryMethod ); - } - - void optUsage( std::ostream& os, std::size_t indent = 0, std::size_t width = Detail::consoleWidth ) const { - typename std::vector::const_iterator itBegin = m_options.begin(), itEnd = m_options.end(), it; - std::size_t maxWidth = 0; - for( it = itBegin; it != itEnd; ++it ) - maxWidth = (std::max)( maxWidth, it->commands().size() ); - - for( it = itBegin; it != itEnd; ++it ) { - Detail::Text usage( it->commands(), Detail::TextAttributes() - .setWidth( maxWidth+indent ) - .setIndent( indent ) ); - Detail::Text desc( it->description, Detail::TextAttributes() - .setWidth( width - maxWidth - 3 ) ); - - for( std::size_t i = 0; i < (std::max)( usage.size(), desc.size() ); ++i ) { - std::string usageCol = i < usage.size() ? usage[i] : ""; - os << usageCol; - - if( i < desc.size() && !desc[i].empty() ) - os << std::string( indent + 2 + maxWidth - usageCol.size(), ' ' ) - << desc[i]; - os << "\n"; - } - } - } - std::string optUsage() const { - std::ostringstream oss; - optUsage( oss ); - return oss.str(); - } - - void argSynopsis( std::ostream& os ) const { - for( int i = 1; i <= m_highestSpecifiedArgPosition; ++i ) { - if( i > 1 ) - os << " "; - typename std::map::const_iterator it = m_positionalArgs.find( i ); - if( it != m_positionalArgs.end() ) - os << "<" << it->second.placeholder << ">"; - else if( m_floatingArg.get() ) - os << "<" << m_floatingArg->placeholder << ">"; - else - throw std::logic_error( "non consecutive positional arguments with no floating args" ); - } - // !TBD No indication of mandatory args - if( m_floatingArg.get() ) { - if( m_highestSpecifiedArgPosition > 1 ) - os << " "; - os << "[<" << m_floatingArg->placeholder << "> ...]"; - } - } - std::string argSynopsis() const { - std::ostringstream oss; - argSynopsis( oss ); - return oss.str(); - } - - void usage( std::ostream& os, std::string const& procName ) const { - validate(); - os << "usage:\n " << procName << " "; - argSynopsis( os ); - if( !m_options.empty() ) { - os << " [options]\n\nwhere options are: \n"; - optUsage( os, 2 ); - } - os << "\n"; - } - std::string usage( std::string const& procName ) const { - std::ostringstream oss; - usage( oss, procName ); - return oss.str(); - } - - ConfigT parse( std::vector const& args ) const { - ConfigT config; - parseInto( args, config ); - return config; - } - - std::vector parseInto( std::vector const& args, ConfigT& config ) const { - std::string processName = args.empty() ? std::string() : args[0]; - std::size_t lastSlash = processName.find_last_of( "/\\" ); - if( lastSlash != std::string::npos ) - processName = processName.substr( lastSlash+1 ); - m_boundProcessName.set( config, processName ); - std::vector tokens; - Parser parser; - parser.parseIntoTokens( args, tokens ); - return populate( tokens, config ); - } - - std::vector populate( std::vector const& tokens, ConfigT& config ) const { - validate(); - std::vector unusedTokens = populateOptions( tokens, config ); - unusedTokens = populateFixedArgs( unusedTokens, config ); - unusedTokens = populateFloatingArgs( unusedTokens, config ); - return unusedTokens; - } - - std::vector populateOptions( std::vector const& tokens, ConfigT& config ) const { - std::vector unusedTokens; - std::vector errors; - for( std::size_t i = 0; i < tokens.size(); ++i ) { - Parser::Token const& token = tokens[i]; - typename std::vector::const_iterator it = m_options.begin(), itEnd = m_options.end(); - for(; it != itEnd; ++it ) { - Arg const& arg = *it; - - try { - if( ( token.type == Parser::Token::ShortOpt && arg.hasShortName( token.data ) ) || - ( token.type == Parser::Token::LongOpt && arg.hasLongName( token.data ) ) ) { - if( arg.takesArg() ) { - if( i == tokens.size()-1 || tokens[i+1].type != Parser::Token::Positional ) - errors.push_back( "Expected argument to option: " + token.data ); - else - arg.boundField.set( config, tokens[++i].data ); - } - else { - arg.boundField.set( config, "true" ); - } - break; - } - } - catch( std::exception& ex ) { - errors.push_back( std::string( ex.what() ) + "\n- while parsing: (" + arg.commands() + ")" ); - } - } - if( it == itEnd ) { - if( token.type == Parser::Token::Positional || !m_throwOnUnrecognisedTokens ) - unusedTokens.push_back( token ); - else if( errors.empty() && m_throwOnUnrecognisedTokens ) - errors.push_back( "unrecognised option: " + token.data ); - } - } - if( !errors.empty() ) { - std::ostringstream oss; - for( std::vector::const_iterator it = errors.begin(), itEnd = errors.end(); - it != itEnd; - ++it ) { - if( it != errors.begin() ) - oss << "\n"; - oss << *it; - } - throw std::runtime_error( oss.str() ); - } - return unusedTokens; - } - std::vector populateFixedArgs( std::vector const& tokens, ConfigT& config ) const { - std::vector unusedTokens; - int position = 1; - for( std::size_t i = 0; i < tokens.size(); ++i ) { - Parser::Token const& token = tokens[i]; - typename std::map::const_iterator it = m_positionalArgs.find( position ); - if( it != m_positionalArgs.end() ) - it->second.boundField.set( config, token.data ); - else - unusedTokens.push_back( token ); - if( token.type == Parser::Token::Positional ) - position++; - } - return unusedTokens; - } - std::vector populateFloatingArgs( std::vector const& tokens, ConfigT& config ) const { - if( !m_floatingArg.get() ) - return tokens; - std::vector unusedTokens; - for( std::size_t i = 0; i < tokens.size(); ++i ) { - Parser::Token const& token = tokens[i]; - if( token.type == Parser::Token::Positional ) - m_floatingArg->boundField.set( config, token.data ); - else - unusedTokens.push_back( token ); - } - return unusedTokens; - } - - void validate() const - { - if( m_options.empty() && m_positionalArgs.empty() && !m_floatingArg.get() ) - throw std::logic_error( "No options or arguments specified" ); - - for( typename std::vector::const_iterator it = m_options.begin(), - itEnd = m_options.end(); - it != itEnd; ++it ) - it->validate(); - } - - private: - Detail::BoundArgFunction m_boundProcessName; - std::vector m_options; - std::map m_positionalArgs; - ArgAutoPtr m_floatingArg; - int m_highestSpecifiedArgPosition; - bool m_throwOnUnrecognisedTokens; - }; - -} // end namespace Clara - -STITCH_CLARA_CLOSE_NAMESPACE -#undef STITCH_CLARA_OPEN_NAMESPACE -#undef STITCH_CLARA_CLOSE_NAMESPACE - -#endif // TWOBLUECUBES_CLARA_H_INCLUDED -#undef STITCH_CLARA_OPEN_NAMESPACE - -// Restore Clara's value for console width, if present -#ifdef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH -#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH -#undef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH -#endif - -#include -#include namespace Catch { - inline void abortAfterFirst( ConfigData& config ) { config.abortAfter = 1; } - inline void abortAfterX( ConfigData& config, int x ) { - if( x < 1 ) - throw std::runtime_error( "Value after -x or --abortAfter must be greater than zero" ); - config.abortAfter = x; - } - inline void addTestOrTags( ConfigData& config, std::string const& _testSpec ) { config.testsOrTags.push_back( _testSpec ); } - inline void addSectionToRun( ConfigData& config, std::string const& sectionName ) { config.sectionsToRun.push_back( sectionName ); } - inline void addReporterName( ConfigData& config, std::string const& _reporterName ) { config.reporterNames.push_back( _reporterName ); } + struct AssertionResultData + { + AssertionResultData() = delete; - inline void addWarning( ConfigData& config, std::string const& _warning ) { - if( _warning == "NoAssertions" ) - config.warnings = static_cast( config.warnings | WarnAbout::NoAssertions ); - else - throw std::runtime_error( "Unrecognised warning: '" + _warning + '\'' ); - } - inline void setOrder( ConfigData& config, std::string const& order ) { - if( startsWith( "declared", order ) ) - config.runOrder = RunTests::InDeclarationOrder; - else if( startsWith( "lexical", order ) ) - config.runOrder = RunTests::InLexicographicalOrder; - else if( startsWith( "random", order ) ) - config.runOrder = RunTests::InRandomOrder; - else - throw std::runtime_error( "Unrecognised ordering: '" + order + '\'' ); - } - inline void setRngSeed( ConfigData& config, std::string const& seed ) { - if( seed == "time" ) { - config.rngSeed = static_cast( std::time(0) ); - } - else { - std::stringstream ss; - ss << seed; - ss >> config.rngSeed; - if( ss.fail() ) - throw std::runtime_error( "Argument to --rng-seed should be the word 'time' or a number" ); - } - } - inline void setVerbosity( ConfigData& config, int level ) { - // !TBD: accept strings? - config.verbosity = static_cast( level ); - } - inline void setShowDurations( ConfigData& config, bool _showDurations ) { - config.showDurations = _showDurations - ? ShowDurations::Always - : ShowDurations::Never; - } - inline void setUseColour( ConfigData& config, std::string const& value ) { - std::string mode = toLower( value ); + AssertionResultData( ResultWas::OfType _resultType, LazyExpression const& _lazyExpression ); - if( mode == "yes" ) - config.useColour = UseColour::Yes; - else if( mode == "no" ) - config.useColour = UseColour::No; - else if( mode == "auto" ) - config.useColour = UseColour::Auto; - else - throw std::runtime_error( "colour mode must be one of: auto, yes or no" ); - } - inline void forceColour( ConfigData& config ) { - config.useColour = UseColour::Yes; - } - inline void loadTestNamesFromFile( ConfigData& config, std::string const& _filename ) { - std::ifstream f( _filename.c_str() ); - if( !f.is_open() ) - throw std::domain_error( "Unable to load input file: " + _filename ); + std::string message; + mutable std::string reconstructedExpression; + LazyExpression lazyExpression; + ResultWas::OfType resultType; - std::string line; - while( std::getline( f, line ) ) { - line = trim(line); - if( !line.empty() && !startsWith( line, '#' ) ) { - if( !startsWith( line, '"' ) ) - line = '"' + line + '"'; - addTestOrTags( config, line + ',' ); - } - } - } + std::string reconstructExpression() const; + }; - inline Clara::CommandLine makeCommandLineParser() { + class AssertionResult { + public: + AssertionResult() = delete; + AssertionResult( AssertionInfo const& info, AssertionResultData const& data ); - using namespace Clara; - CommandLine cli; + bool isOk() const; + bool succeeded() const; + ResultWas::OfType getResultType() const; + bool hasExpression() const; + bool hasMessage() const; + std::string getExpression() const; + std::string getExpressionInMacro() const; + bool hasExpandedExpression() const; + std::string getExpandedExpression() const; + std::string getMessage() const; + SourceLineInfo getSourceInfo() const; + std::string getTestMacroName() const; - cli.bindProcessName( &ConfigData::processName ); - - cli["-?"]["-h"]["--help"] - .describe( "display usage information" ) - .bind( &ConfigData::showHelp ); - - cli["-l"]["--list-tests"] - .describe( "list all/matching test cases" ) - .bind( &ConfigData::listTests ); - - cli["-t"]["--list-tags"] - .describe( "list all/matching tags" ) - .bind( &ConfigData::listTags ); - - cli["-s"]["--success"] - .describe( "include successful tests in output" ) - .bind( &ConfigData::showSuccessfulTests ); - - cli["-b"]["--break"] - .describe( "break into debugger on failure" ) - .bind( &ConfigData::shouldDebugBreak ); - - cli["-e"]["--nothrow"] - .describe( "skip exception tests" ) - .bind( &ConfigData::noThrow ); - - cli["-i"]["--invisibles"] - .describe( "show invisibles (tabs, newlines)" ) - .bind( &ConfigData::showInvisibles ); - - cli["-o"]["--out"] - .describe( "output filename" ) - .bind( &ConfigData::outputFilename, "filename" ); - - cli["-r"]["--reporter"] -// .placeholder( "name[:filename]" ) - .describe( "reporter to use (defaults to console)" ) - .bind( &addReporterName, "name" ); - - cli["-n"]["--name"] - .describe( "suite name" ) - .bind( &ConfigData::name, "name" ); - - cli["-a"]["--abort"] - .describe( "abort at first failure" ) - .bind( &abortAfterFirst ); - - cli["-x"]["--abortx"] - .describe( "abort after x failures" ) - .bind( &abortAfterX, "no. failures" ); - - cli["-w"]["--warn"] - .describe( "enable warnings" ) - .bind( &addWarning, "warning name" ); - -// - needs updating if reinstated -// cli.into( &setVerbosity ) -// .describe( "level of verbosity (0=no output)" ) -// .shortOpt( "v") -// .longOpt( "verbosity" ) -// .placeholder( "level" ); - - cli[_] - .describe( "which test or tests to use" ) - .bind( &addTestOrTags, "test name, pattern or tags" ); - - cli["-d"]["--durations"] - .describe( "show test durations" ) - .bind( &setShowDurations, "yes|no" ); - - cli["-f"]["--input-file"] - .describe( "load test names to run from a file" ) - .bind( &loadTestNamesFromFile, "filename" ); - - cli["-#"]["--filenames-as-tags"] - .describe( "adds a tag for the filename" ) - .bind( &ConfigData::filenamesAsTags ); - - cli["-c"]["--section"] - .describe( "specify section to run" ) - .bind( &addSectionToRun, "section name" ); - - // Less common commands which don't have a short form - cli["--list-test-names-only"] - .describe( "list all/matching test cases names only" ) - .bind( &ConfigData::listTestNamesOnly ); - - cli["--list-extra-info"] - .describe( "list all/matching test cases with more info" ) - .bind( &ConfigData::listExtraInfo ); - - cli["--list-reporters"] - .describe( "list all reporters" ) - .bind( &ConfigData::listReporters ); - - cli["--order"] - .describe( "test case order (defaults to decl)" ) - .bind( &setOrder, "decl|lex|rand" ); - - cli["--rng-seed"] - .describe( "set a specific seed for random numbers" ) - .bind( &setRngSeed, "'time'|number" ); - - cli["--force-colour"] - .describe( "force colourised output (deprecated)" ) - .bind( &forceColour ); - - cli["--use-colour"] - .describe( "should output be colourised" ) - .bind( &setUseColour, "yes|no" ); - - return cli; - } + //protected: + AssertionInfo m_info; + AssertionResultData m_resultData; + }; } // end namespace Catch -// #included from: internal/catch_list.hpp -#define TWOBLUECUBES_CATCH_LIST_HPP_INCLUDED +// end catch_assertionresult.h +// start catch_option.hpp -// #included from: catch_text.h -#define TWOBLUECUBES_CATCH_TEXT_H_INCLUDED +namespace Catch { -#define TBC_TEXT_FORMAT_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH - -#define CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE Catch -// #included from: ../external/tbc_text_format.h -// Only use header guard if we are not using an outer namespace -#ifndef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE -# ifdef TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED -# ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED -# define TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED -# endif -# else -# define TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED -# endif -#endif -#ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED -#include -#include -#include - -// Use optional outer namespace -#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE -namespace CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE { -#endif - -namespace Tbc { - -#ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH - const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH; -#else - const unsigned int consoleWidth = 80; -#endif - - struct TextAttributes { - TextAttributes() - : initialIndent( std::string::npos ), - indent( 0 ), - width( consoleWidth-1 ) + // An optional type + template + class Option { + public: + Option() : nullableValue( nullptr ) {} + Option( T const& _value ) + : nullableValue( new( storage ) T( _value ) ) + {} + Option( Option const& _other ) + : nullableValue( _other ? new( storage ) T( *_other ) : nullptr ) {} - TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; } - TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; } - TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; } - - std::size_t initialIndent; // indent of first line, or npos - std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos - std::size_t width; // maximum width of text, including indent. Longer text will wrap - }; - - class Text { - public: - Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() ) - : attr( _attr ) - { - const std::string wrappableBeforeChars = "[({<\t"; - const std::string wrappableAfterChars = "])}>-,./|\\"; - const std::string wrappableInsteadOfChars = " \n\r"; - std::string indent = _attr.initialIndent != std::string::npos - ? std::string( _attr.initialIndent, ' ' ) - : std::string( _attr.indent, ' ' ); - - typedef std::string::const_iterator iterator; - iterator it = _str.begin(); - const iterator strEnd = _str.end(); - - while( it != strEnd ) { - - if( lines.size() >= 1000 ) { - lines.push_back( "... message truncated due to excessive size" ); - return; - } - - std::string suffix; - std::size_t width = (std::min)( static_cast( strEnd-it ), _attr.width-static_cast( indent.size() ) ); - iterator itEnd = it+width; - iterator itNext = _str.end(); - - iterator itNewLine = std::find( it, itEnd, '\n' ); - if( itNewLine != itEnd ) - itEnd = itNewLine; - - if( itEnd != strEnd ) { - bool foundWrapPoint = false; - iterator findIt = itEnd; - do { - if( wrappableAfterChars.find( *findIt ) != std::string::npos && findIt != itEnd ) { - itEnd = findIt+1; - itNext = findIt+1; - foundWrapPoint = true; - } - else if( findIt > it && wrappableBeforeChars.find( *findIt ) != std::string::npos ) { - itEnd = findIt; - itNext = findIt; - foundWrapPoint = true; - } - else if( wrappableInsteadOfChars.find( *findIt ) != std::string::npos ) { - itNext = findIt+1; - itEnd = findIt; - foundWrapPoint = true; - } - if( findIt == it ) - break; - else - --findIt; - } - while( !foundWrapPoint ); - - if( !foundWrapPoint ) { - // No good wrap char, so we'll break mid word and add a hyphen - --itEnd; - itNext = itEnd; - suffix = "-"; - } - else { - while( itEnd > it && wrappableInsteadOfChars.find( *(itEnd-1) ) != std::string::npos ) - --itEnd; - } - } - lines.push_back( indent + std::string( it, itEnd ) + suffix ); - - if( indent.size() != _attr.indent ) - indent = std::string( _attr.indent, ' ' ); - it = itNext; - } + ~Option() { + reset(); } - typedef std::vector::const_iterator const_iterator; - - const_iterator begin() const { return lines.begin(); } - const_iterator end() const { return lines.end(); } - std::string const& last() const { return lines.back(); } - std::size_t size() const { return lines.size(); } - std::string const& operator[]( std::size_t _index ) const { return lines[_index]; } - std::string toString() const { - std::ostringstream oss; - oss << *this; - return oss.str(); + Option& operator= ( Option const& _other ) { + if( &_other != this ) { + reset(); + if( _other ) + nullableValue = new( storage ) T( *_other ); + } + return *this; + } + Option& operator = ( T const& _value ) { + reset(); + nullableValue = new( storage ) T( _value ); + return *this; } - inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) { - for( Text::const_iterator it = _text.begin(), itEnd = _text.end(); - it != itEnd; ++it ) { - if( it != _text.begin() ) - _stream << "\n"; - _stream << *it; - } - return _stream; + void reset() { + if( nullableValue ) + nullableValue->~T(); + nullableValue = nullptr; + } + + T& operator*() { return *nullableValue; } + T const& operator*() const { return *nullableValue; } + T* operator->() { return nullableValue; } + const T* operator->() const { return nullableValue; } + + T valueOr( T const& defaultValue ) const { + return nullableValue ? *nullableValue : defaultValue; + } + + bool some() const { return nullableValue != nullptr; } + bool none() const { return nullableValue == nullptr; } + + bool operator !() const { return nullableValue == nullptr; } + explicit operator bool() const { + return some(); } private: - std::string str; - TextAttributes attr; - std::vector lines; + T *nullableValue; + alignas(alignof(T)) char storage[sizeof(T)]; }; -} // end namespace Tbc +} // end namespace Catch -#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE -} // end outer namespace -#endif - -#endif // TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED -#undef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE +// end catch_option.hpp +#include +#include +#include +#include +#include namespace Catch { - using Tbc::Text; - using Tbc::TextAttributes; -} -// #included from: catch_console_colour.hpp -#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_HPP_INCLUDED + struct ReporterConfig { + explicit ReporterConfig( IConfigPtr const& _fullConfig ); + + ReporterConfig( IConfigPtr const& _fullConfig, std::ostream& _stream ); + + std::ostream& stream() const; + IConfigPtr fullConfig() const; + + private: + std::ostream* m_stream; + IConfigPtr m_fullConfig; + }; + + struct ReporterPreferences { + bool shouldRedirectStdOut = false; + }; + + template + struct LazyStat : Option { + LazyStat& operator=( T const& _value ) { + Option::operator=( _value ); + used = false; + return *this; + } + void reset() { + Option::reset(); + used = false; + } + bool used = false; + }; + + struct TestRunInfo { + TestRunInfo( std::string const& _name ); + std::string name; + }; + struct GroupInfo { + GroupInfo( std::string const& _name, + std::size_t _groupIndex, + std::size_t _groupsCount ); + + std::string name; + std::size_t groupIndex; + std::size_t groupsCounts; + }; + + struct AssertionStats { + AssertionStats( AssertionResult const& _assertionResult, + std::vector const& _infoMessages, + Totals const& _totals ); + + AssertionStats( AssertionStats const& ) = default; + AssertionStats( AssertionStats && ) = default; + AssertionStats& operator = ( AssertionStats const& ) = default; + AssertionStats& operator = ( AssertionStats && ) = default; + virtual ~AssertionStats(); + + AssertionResult assertionResult; + std::vector infoMessages; + Totals totals; + }; + + struct SectionStats { + SectionStats( SectionInfo const& _sectionInfo, + Counts const& _assertions, + double _durationInSeconds, + bool _missingAssertions ); + SectionStats( SectionStats const& ) = default; + SectionStats( SectionStats && ) = default; + SectionStats& operator = ( SectionStats const& ) = default; + SectionStats& operator = ( SectionStats && ) = default; + virtual ~SectionStats(); + + SectionInfo sectionInfo; + Counts assertions; + double durationInSeconds; + bool missingAssertions; + }; + + struct TestCaseStats { + TestCaseStats( TestCaseInfo const& _testInfo, + Totals const& _totals, + std::string const& _stdOut, + std::string const& _stdErr, + bool _aborting ); + + TestCaseStats( TestCaseStats const& ) = default; + TestCaseStats( TestCaseStats && ) = default; + TestCaseStats& operator = ( TestCaseStats const& ) = default; + TestCaseStats& operator = ( TestCaseStats && ) = default; + virtual ~TestCaseStats(); + + TestCaseInfo testInfo; + Totals totals; + std::string stdOut; + std::string stdErr; + bool aborting; + }; + + struct TestGroupStats { + TestGroupStats( GroupInfo const& _groupInfo, + Totals const& _totals, + bool _aborting ); + TestGroupStats( GroupInfo const& _groupInfo ); + + TestGroupStats( TestGroupStats const& ) = default; + TestGroupStats( TestGroupStats && ) = default; + TestGroupStats& operator = ( TestGroupStats const& ) = default; + TestGroupStats& operator = ( TestGroupStats && ) = default; + virtual ~TestGroupStats(); + + GroupInfo groupInfo; + Totals totals; + bool aborting; + }; + + struct TestRunStats { + TestRunStats( TestRunInfo const& _runInfo, + Totals const& _totals, + bool _aborting ); + + TestRunStats( TestRunStats const& ) = default; + TestRunStats( TestRunStats && ) = default; + TestRunStats& operator = ( TestRunStats const& ) = default; + TestRunStats& operator = ( TestRunStats && ) = default; + virtual ~TestRunStats(); + + TestRunInfo runInfo; + Totals totals; + bool aborting; + }; + + struct BenchmarkInfo { + std::string name; + }; + struct BenchmarkStats { + BenchmarkInfo info; + std::size_t iterations; + uint64_t elapsedTimeInNanoseconds; + }; + + struct IStreamingReporter { + virtual ~IStreamingReporter() = default; + + // Implementing class must also provide the following static methods: + // static std::string getDescription(); + // static std::set getSupportedVerbosities() + + virtual ReporterPreferences getPreferences() const = 0; + + virtual void noMatchingTestCases( std::string const& spec ) = 0; + + virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0; + virtual void testGroupStarting( GroupInfo const& groupInfo ) = 0; + + virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0; + virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0; + + // *** experimental *** + virtual void benchmarkStarting( BenchmarkInfo const& ) {} + + virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0; + + // The return value indicates if the messages buffer should be cleared: + virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0; + + // *** experimental *** + virtual void benchmarkEnded( BenchmarkStats const& ) {} + + virtual void sectionEnded( SectionStats const& sectionStats ) = 0; + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0; + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0; + virtual void testRunEnded( TestRunStats const& testRunStats ) = 0; + + virtual void skipTest( TestCaseInfo const& testInfo ) = 0; + + // Default empty implementation provided + virtual void fatalErrorEncountered( StringRef name ); + + virtual bool isMulti() const; + }; + using IStreamingReporterPtr = std::unique_ptr; + + struct IReporterFactory { + virtual ~IReporterFactory(); + virtual IStreamingReporterPtr create( ReporterConfig const& config ) const = 0; + virtual std::string getDescription() const = 0; + }; + using IReporterFactoryPtr = std::shared_ptr; + + struct IReporterRegistry { + using FactoryMap = std::map; + using Listeners = std::vector; + + virtual ~IReporterRegistry(); + virtual IStreamingReporterPtr create( std::string const& name, IConfigPtr const& config ) const = 0; + virtual FactoryMap const& getFactories() const = 0; + virtual Listeners const& getListeners() const = 0; + }; + + void addReporter( IStreamingReporterPtr& existingReporter, IStreamingReporterPtr&& additionalReporter ); + +} // end namespace Catch + +// end catch_interfaces_reporter.h +#include +#include +#include +#include +#include +#include + +namespace Catch { + void prepareExpandedExpression(AssertionResult& result); + + // Returns double formatted as %.3f (format expected on output) + std::string getFormattedDuration( double duration ); + + template + struct StreamingReporterBase : IStreamingReporter { + + StreamingReporterBase( ReporterConfig const& _config ) + : m_config( _config.fullConfig() ), + stream( _config.stream() ) + { + m_reporterPrefs.shouldRedirectStdOut = false; + CATCH_ENFORCE( DerivedT::getSupportedVerbosities().count( m_config->verbosity() ), "Verbosity level not supported by this reporter" ); + } + + ReporterPreferences getPreferences() const override { + return m_reporterPrefs; + } + + static std::set getSupportedVerbosities() { + return { Verbosity::Normal }; + } + + ~StreamingReporterBase() override = default; + + void noMatchingTestCases(std::string const&) override {} + + void testRunStarting(TestRunInfo const& _testRunInfo) override { + currentTestRunInfo = _testRunInfo; + } + void testGroupStarting(GroupInfo const& _groupInfo) override { + currentGroupInfo = _groupInfo; + } + + void testCaseStarting(TestCaseInfo const& _testInfo) override { + currentTestCaseInfo = _testInfo; + } + void sectionStarting(SectionInfo const& _sectionInfo) override { + m_sectionStack.push_back(_sectionInfo); + } + + void sectionEnded(SectionStats const& /* _sectionStats */) override { + m_sectionStack.pop_back(); + } + void testCaseEnded(TestCaseStats const& /* _testCaseStats */) override { + currentTestCaseInfo.reset(); + } + void testGroupEnded(TestGroupStats const& /* _testGroupStats */) override { + currentGroupInfo.reset(); + } + void testRunEnded(TestRunStats const& /* _testRunStats */) override { + currentTestCaseInfo.reset(); + currentGroupInfo.reset(); + currentTestRunInfo.reset(); + } + + void skipTest(TestCaseInfo const&) override { + // Don't do anything with this by default. + // It can optionally be overridden in the derived class. + } + + IConfigPtr m_config; + std::ostream& stream; + + LazyStat currentTestRunInfo; + LazyStat currentGroupInfo; + LazyStat currentTestCaseInfo; + + std::vector m_sectionStack; + ReporterPreferences m_reporterPrefs; + }; + + template + struct CumulativeReporterBase : IStreamingReporter { + template + struct Node { + explicit Node( T const& _value ) : value( _value ) {} + virtual ~Node() {} + + using ChildNodes = std::vector>; + T value; + ChildNodes children; + }; + struct SectionNode { + explicit SectionNode(SectionStats const& _stats) : stats(_stats) {} + virtual ~SectionNode() = default; + + bool operator == (SectionNode const& other) const { + return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo; + } + bool operator == (std::shared_ptr const& other) const { + return operator==(*other); + } + + SectionStats stats; + using ChildSections = std::vector>; + using Assertions = std::vector; + ChildSections childSections; + Assertions assertions; + std::string stdOut; + std::string stdErr; + }; + + struct BySectionInfo { + BySectionInfo( SectionInfo const& other ) : m_other( other ) {} + BySectionInfo( BySectionInfo const& other ) : m_other( other.m_other ) {} + bool operator() (std::shared_ptr const& node) const { + return ((node->stats.sectionInfo.name == m_other.name) && + (node->stats.sectionInfo.lineInfo == m_other.lineInfo)); + } + void operator=(BySectionInfo const&) = delete; + + private: + SectionInfo const& m_other; + }; + + using TestCaseNode = Node; + using TestGroupNode = Node; + using TestRunNode = Node; + + CumulativeReporterBase( ReporterConfig const& _config ) + : m_config( _config.fullConfig() ), + stream( _config.stream() ) + { + m_reporterPrefs.shouldRedirectStdOut = false; + CATCH_ENFORCE( DerivedT::getSupportedVerbosities().count( m_config->verbosity() ), "Verbosity level not supported by this reporter" ); + } + ~CumulativeReporterBase() override = default; + + ReporterPreferences getPreferences() const override { + return m_reporterPrefs; + } + + static std::set getSupportedVerbosities() { + return { Verbosity::Normal }; + } + + void testRunStarting( TestRunInfo const& ) override {} + void testGroupStarting( GroupInfo const& ) override {} + + void testCaseStarting( TestCaseInfo const& ) override {} + + void sectionStarting( SectionInfo const& sectionInfo ) override { + SectionStats incompleteStats( sectionInfo, Counts(), 0, false ); + std::shared_ptr node; + if( m_sectionStack.empty() ) { + if( !m_rootSection ) + m_rootSection = std::make_shared( incompleteStats ); + node = m_rootSection; + } + else { + SectionNode& parentNode = *m_sectionStack.back(); + auto it = + std::find_if( parentNode.childSections.begin(), + parentNode.childSections.end(), + BySectionInfo( sectionInfo ) ); + if( it == parentNode.childSections.end() ) { + node = std::make_shared( incompleteStats ); + parentNode.childSections.push_back( node ); + } + else + node = *it; + } + m_sectionStack.push_back( node ); + m_deepestSection = std::move(node); + } + + void assertionStarting(AssertionInfo const&) override {} + + bool assertionEnded(AssertionStats const& assertionStats) override { + assert(!m_sectionStack.empty()); + // AssertionResult holds a pointer to a temporary DecomposedExpression, + // which getExpandedExpression() calls to build the expression string. + // Our section stack copy of the assertionResult will likely outlive the + // temporary, so it must be expanded or discarded now to avoid calling + // a destroyed object later. + prepareExpandedExpression(const_cast( assertionStats.assertionResult ) ); + SectionNode& sectionNode = *m_sectionStack.back(); + sectionNode.assertions.push_back(assertionStats); + return true; + } + void sectionEnded(SectionStats const& sectionStats) override { + assert(!m_sectionStack.empty()); + SectionNode& node = *m_sectionStack.back(); + node.stats = sectionStats; + m_sectionStack.pop_back(); + } + void testCaseEnded(TestCaseStats const& testCaseStats) override { + auto node = std::make_shared(testCaseStats); + assert(m_sectionStack.size() == 0); + node->children.push_back(m_rootSection); + m_testCases.push_back(node); + m_rootSection.reset(); + + assert(m_deepestSection); + m_deepestSection->stdOut = testCaseStats.stdOut; + m_deepestSection->stdErr = testCaseStats.stdErr; + } + void testGroupEnded(TestGroupStats const& testGroupStats) override { + auto node = std::make_shared(testGroupStats); + node->children.swap(m_testCases); + m_testGroups.push_back(node); + } + void testRunEnded(TestRunStats const& testRunStats) override { + auto node = std::make_shared(testRunStats); + node->children.swap(m_testGroups); + m_testRuns.push_back(node); + testRunEndedCumulative(); + } + virtual void testRunEndedCumulative() = 0; + + void skipTest(TestCaseInfo const&) override {} + + IConfigPtr m_config; + std::ostream& stream; + std::vector m_assertions; + std::vector>> m_sections; + std::vector> m_testCases; + std::vector> m_testGroups; + + std::vector> m_testRuns; + + std::shared_ptr m_rootSection; + std::shared_ptr m_deepestSection; + std::vector> m_sectionStack; + ReporterPreferences m_reporterPrefs; + }; + + template + char const* getLineOfChars() { + static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0}; + if( !*line ) { + std::memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 ); + line[CATCH_CONFIG_CONSOLE_WIDTH-1] = 0; + } + return line; + } + + struct TestEventListenerBase : StreamingReporterBase { + TestEventListenerBase( ReporterConfig const& _config ); + + void assertionStarting(AssertionInfo const&) override; + bool assertionEnded(AssertionStats const&) override; + }; + +} // end namespace Catch + +// end catch_reporter_bases.hpp +// start catch_console_colour.h namespace Catch { @@ -5545,462 +3701,105 @@ namespace Catch { // Use constructed object for RAII guard Colour( Code _colourCode ); - Colour( Colour const& other ); + Colour( Colour&& other ) noexcept; + Colour& operator=( Colour&& other ) noexcept; ~Colour(); // Use static method for one-shot changes static void use( Code _colourCode ); private: - bool m_moved; + bool m_moved = false; }; - inline std::ostream& operator << ( std::ostream& os, Colour const& ) { return os; } + std::ostream& operator << ( std::ostream& os, Colour const& ); } // end namespace Catch -// #included from: catch_interfaces_reporter.h -#define TWOBLUECUBES_CATCH_INTERFACES_REPORTER_H_INCLUDED +// end catch_console_colour.h +// start catch_reporter_registrars.hpp -#include -#include -#include - -namespace Catch -{ - struct ReporterConfig { - explicit ReporterConfig( Ptr const& _fullConfig ) - : m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {} - - ReporterConfig( Ptr const& _fullConfig, std::ostream& _stream ) - : m_stream( &_stream ), m_fullConfig( _fullConfig ) {} - - std::ostream& stream() const { return *m_stream; } - Ptr fullConfig() const { return m_fullConfig; } - - private: - std::ostream* m_stream; - Ptr m_fullConfig; - }; - - struct ReporterPreferences { - ReporterPreferences() - : shouldRedirectStdOut( false ) - {} - - bool shouldRedirectStdOut; - }; - - template - struct LazyStat : Option { - LazyStat() : used( false ) {} - LazyStat& operator=( T const& _value ) { - Option::operator=( _value ); - used = false; - return *this; - } - void reset() { - Option::reset(); - used = false; - } - bool used; - }; - - struct TestRunInfo { - TestRunInfo( std::string const& _name ) : name( _name ) {} - std::string name; - }; - struct GroupInfo { - GroupInfo( std::string const& _name, - std::size_t _groupIndex, - std::size_t _groupsCount ) - : name( _name ), - groupIndex( _groupIndex ), - groupsCounts( _groupsCount ) - {} - - std::string name; - std::size_t groupIndex; - std::size_t groupsCounts; - }; - - struct AssertionStats { - AssertionStats( AssertionResult const& _assertionResult, - std::vector const& _infoMessages, - Totals const& _totals ) - : assertionResult( _assertionResult ), - infoMessages( _infoMessages ), - totals( _totals ) - { - if( assertionResult.hasMessage() ) { - // Copy message into messages list. - // !TBD This should have been done earlier, somewhere - MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() ); - builder << assertionResult.getMessage(); - builder.m_info.message = builder.m_stream.str(); - - infoMessages.push_back( builder.m_info ); - } - } - virtual ~AssertionStats(); - -# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS - AssertionStats( AssertionStats const& ) = default; - AssertionStats( AssertionStats && ) = default; - AssertionStats& operator = ( AssertionStats const& ) = default; - AssertionStats& operator = ( AssertionStats && ) = default; -# endif - - AssertionResult assertionResult; - std::vector infoMessages; - Totals totals; - }; - - struct SectionStats { - SectionStats( SectionInfo const& _sectionInfo, - Counts const& _assertions, - double _durationInSeconds, - bool _missingAssertions ) - : sectionInfo( _sectionInfo ), - assertions( _assertions ), - durationInSeconds( _durationInSeconds ), - missingAssertions( _missingAssertions ) - {} - virtual ~SectionStats(); -# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS - SectionStats( SectionStats const& ) = default; - SectionStats( SectionStats && ) = default; - SectionStats& operator = ( SectionStats const& ) = default; - SectionStats& operator = ( SectionStats && ) = default; -# endif - - SectionInfo sectionInfo; - Counts assertions; - double durationInSeconds; - bool missingAssertions; - }; - - struct TestCaseStats { - TestCaseStats( TestCaseInfo const& _testInfo, - Totals const& _totals, - std::string const& _stdOut, - std::string const& _stdErr, - bool _aborting ) - : testInfo( _testInfo ), - totals( _totals ), - stdOut( _stdOut ), - stdErr( _stdErr ), - aborting( _aborting ) - {} - virtual ~TestCaseStats(); - -# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS - TestCaseStats( TestCaseStats const& ) = default; - TestCaseStats( TestCaseStats && ) = default; - TestCaseStats& operator = ( TestCaseStats const& ) = default; - TestCaseStats& operator = ( TestCaseStats && ) = default; -# endif - - TestCaseInfo testInfo; - Totals totals; - std::string stdOut; - std::string stdErr; - bool aborting; - }; - - struct TestGroupStats { - TestGroupStats( GroupInfo const& _groupInfo, - Totals const& _totals, - bool _aborting ) - : groupInfo( _groupInfo ), - totals( _totals ), - aborting( _aborting ) - {} - TestGroupStats( GroupInfo const& _groupInfo ) - : groupInfo( _groupInfo ), - aborting( false ) - {} - virtual ~TestGroupStats(); - -# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS - TestGroupStats( TestGroupStats const& ) = default; - TestGroupStats( TestGroupStats && ) = default; - TestGroupStats& operator = ( TestGroupStats const& ) = default; - TestGroupStats& operator = ( TestGroupStats && ) = default; -# endif - - GroupInfo groupInfo; - Totals totals; - bool aborting; - }; - - struct TestRunStats { - TestRunStats( TestRunInfo const& _runInfo, - Totals const& _totals, - bool _aborting ) - : runInfo( _runInfo ), - totals( _totals ), - aborting( _aborting ) - {} - virtual ~TestRunStats(); - -# ifndef CATCH_CONFIG_CPP11_GENERATED_METHODS - TestRunStats( TestRunStats const& _other ) - : runInfo( _other.runInfo ), - totals( _other.totals ), - aborting( _other.aborting ) - {} -# else - TestRunStats( TestRunStats const& ) = default; - TestRunStats( TestRunStats && ) = default; - TestRunStats& operator = ( TestRunStats const& ) = default; - TestRunStats& operator = ( TestRunStats && ) = default; -# endif - - TestRunInfo runInfo; - Totals totals; - bool aborting; - }; - - class MultipleReporters; - - struct IStreamingReporter : IShared { - virtual ~IStreamingReporter(); - - // Implementing class must also provide the following static method: - // static std::string getDescription(); - - virtual ReporterPreferences getPreferences() const = 0; - - virtual void noMatchingTestCases( std::string const& spec ) = 0; - - virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0; - virtual void testGroupStarting( GroupInfo const& groupInfo ) = 0; - - virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0; - virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0; - - virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0; - - // The return value indicates if the messages buffer should be cleared: - virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0; - - virtual void sectionEnded( SectionStats const& sectionStats ) = 0; - virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0; - virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0; - virtual void testRunEnded( TestRunStats const& testRunStats ) = 0; - - virtual void skipTest( TestCaseInfo const& testInfo ) = 0; - - virtual MultipleReporters* tryAsMulti() { return CATCH_NULL; } - }; - - struct IReporterFactory : IShared { - virtual ~IReporterFactory(); - virtual IStreamingReporter* create( ReporterConfig const& config ) const = 0; - virtual std::string getDescription() const = 0; - }; - - struct IReporterRegistry { - typedef std::map > FactoryMap; - typedef std::vector > Listeners; - - virtual ~IReporterRegistry(); - virtual IStreamingReporter* create( std::string const& name, Ptr const& config ) const = 0; - virtual FactoryMap const& getFactories() const = 0; - virtual Listeners const& getListeners() const = 0; - }; - - Ptr addReporter( Ptr const& existingReporter, Ptr const& additionalReporter ); - -} - -#include -#include namespace Catch { - inline std::size_t listTests( Config const& config ) { + template + class ReporterRegistrar { - TestSpec testSpec = config.testSpec(); - if( config.testSpec().hasFilters() ) - Catch::cout() << "Matching test cases:\n"; - else { - Catch::cout() << "All available test cases:\n"; - testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); - } + class ReporterFactory : public IReporterFactory { - std::size_t matchedTests = 0; - TextAttributes nameAttr, descAttr, tagsAttr; - nameAttr.setInitialIndent( 2 ).setIndent( 4 ); - descAttr.setIndent( 4 ); - tagsAttr.setIndent( 6 ); - - std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); - for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); - it != itEnd; - ++it ) { - matchedTests++; - TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); - Colour::Code colour = testCaseInfo.isHidden() - ? Colour::SecondaryText - : Colour::None; - Colour colourGuard( colour ); - - Catch::cout() << Text( testCaseInfo.name, nameAttr ) << std::endl; - if( config.listExtraInfo() ) { - Catch::cout() << " " << testCaseInfo.lineInfo << std::endl; - std::string description = testCaseInfo.description; - if( description.empty() ) - description = "(NO DESCRIPTION)"; - Catch::cout() << Text( description, descAttr ) << std::endl; + virtual IStreamingReporterPtr create( ReporterConfig const& config ) const override { + return std::unique_ptr( new T( config ) ); } - if( !testCaseInfo.tags.empty() ) - Catch::cout() << Text( testCaseInfo.tagsAsString, tagsAttr ) << std::endl; - } - if( !config.testSpec().hasFilters() ) - Catch::cout() << pluralise( matchedTests, "test case" ) << '\n' << std::endl; - else - Catch::cout() << pluralise( matchedTests, "matching test case" ) << '\n' << std::endl; - return matchedTests; - } + virtual std::string getDescription() const override { + return T::getDescription(); + } + }; - inline std::size_t listTestsNamesOnly( Config const& config ) { - TestSpec testSpec = config.testSpec(); - if( !config.testSpec().hasFilters() ) - testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); - std::size_t matchedTests = 0; - std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); - for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); - it != itEnd; - ++it ) { - matchedTests++; - TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); - if( startsWith( testCaseInfo.name, '#' ) ) - Catch::cout() << '"' << testCaseInfo.name << '"'; - else - Catch::cout() << testCaseInfo.name; - if ( config.listExtraInfo() ) - Catch::cout() << "\t@" << testCaseInfo.lineInfo; - Catch::cout() << std::endl; - } - return matchedTests; - } + public: - struct TagInfo { - TagInfo() : count ( 0 ) {} - void add( std::string const& spelling ) { - ++count; - spellings.insert( spelling ); + ReporterRegistrar( std::string const& name ) { + getMutableRegistryHub().registerReporter( name, std::make_shared() ); } - std::string all() const { - std::string out; - for( std::set::const_iterator it = spellings.begin(), itEnd = spellings.end(); - it != itEnd; - ++it ) - out += "[" + *it + "]"; - return out; - } - std::set spellings; - std::size_t count; }; - inline std::size_t listTags( Config const& config ) { - TestSpec testSpec = config.testSpec(); - if( config.testSpec().hasFilters() ) - Catch::cout() << "Tags for matching test cases:\n"; - else { - Catch::cout() << "All available tags:\n"; - testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); - } + template + class ListenerRegistrar { - std::map tagCounts; + class ListenerFactory : public IReporterFactory { - std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); - for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); - it != itEnd; - ++it ) { - for( std::set::const_iterator tagIt = it->getTestCaseInfo().tags.begin(), - tagItEnd = it->getTestCaseInfo().tags.end(); - tagIt != tagItEnd; - ++tagIt ) { - std::string tagName = *tagIt; - std::string lcaseTagName = toLower( tagName ); - std::map::iterator countIt = tagCounts.find( lcaseTagName ); - if( countIt == tagCounts.end() ) - countIt = tagCounts.insert( std::make_pair( lcaseTagName, TagInfo() ) ).first; - countIt->second.add( tagName ); + virtual IStreamingReporterPtr create( ReporterConfig const& config ) const override { + return std::unique_ptr( new T( config ) ); } + virtual std::string getDescription() const override { + return std::string(); + } + }; + + public: + + ListenerRegistrar() { + getMutableRegistryHub().registerListener( std::make_shared() ); } + }; +} - for( std::map::const_iterator countIt = tagCounts.begin(), - countItEnd = tagCounts.end(); - countIt != countItEnd; - ++countIt ) { - std::ostringstream oss; - oss << " " << std::setw(2) << countIt->second.count << " "; - Text wrapper( countIt->second.all(), TextAttributes() - .setInitialIndent( 0 ) - .setIndent( oss.str().size() ) - .setWidth( CATCH_CONFIG_CONSOLE_WIDTH-10 ) ); - Catch::cout() << oss.str() << wrapper << '\n'; - } - Catch::cout() << pluralise( tagCounts.size(), "tag" ) << '\n' << std::endl; - return tagCounts.size(); - } +#if !defined(CATCH_CONFIG_DISABLE) - inline std::size_t listReporters( Config const& /*config*/ ) { - Catch::cout() << "Available reporters:\n"; - IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories(); - IReporterRegistry::FactoryMap::const_iterator itBegin = factories.begin(), itEnd = factories.end(), it; - std::size_t maxNameLen = 0; - for(it = itBegin; it != itEnd; ++it ) - maxNameLen = (std::max)( maxNameLen, it->first.size() ); +#define CATCH_REGISTER_REPORTER( name, reporterType ) \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + namespace{ Catch::ReporterRegistrar catch_internal_RegistrarFor##reporterType( name ); } \ + CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS - for(it = itBegin; it != itEnd; ++it ) { - Text wrapper( it->second->getDescription(), TextAttributes() - .setInitialIndent( 0 ) - .setIndent( 7+maxNameLen ) - .setWidth( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 ) ); - Catch::cout() << " " - << it->first - << ':' - << std::string( maxNameLen - it->first.size() + 2, ' ' ) - << wrapper << '\n'; - } - Catch::cout() << std::endl; - return factories.size(); - } +#define CATCH_REGISTER_LISTENER( listenerType ) \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + namespace{ Catch::ListenerRegistrar catch_internal_RegistrarFor##listenerType; } \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS +#else // CATCH_CONFIG_DISABLE - inline Option list( Config const& config ) { - Option listedCount; - if( config.listTests() || ( config.listExtraInfo() && !config.listTestNamesOnly() ) ) - listedCount = listedCount.valueOr(0) + listTests( config ); - if( config.listTestNamesOnly() ) - listedCount = listedCount.valueOr(0) + listTestsNamesOnly( config ); - if( config.listTags() ) - listedCount = listedCount.valueOr(0) + listTags( config ); - if( config.listReporters() ) - listedCount = listedCount.valueOr(0) + listReporters( config ); - return listedCount; - } +#define CATCH_REGISTER_REPORTER(name, reporterType) +#define CATCH_REGISTER_LISTENER(listenerType) -} // end namespace Catch +#endif // CATCH_CONFIG_DISABLE -// #included from: internal/catch_run_context.hpp -#define TWOBLUECUBES_CATCH_RUNNER_IMPL_HPP_INCLUDED +// end catch_reporter_registrars.hpp +// end catch_external_interfaces.h +#endif -// #included from: catch_test_case_tracker.hpp -#define TWOBLUECUBES_CATCH_TEST_CASE_TRACKER_HPP_INCLUDED +#ifdef CATCH_IMPL +// start catch_impl.hpp + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wweak-vtables" +#endif + +// Keep these here for external reporters +// start catch_test_case_tracker.h -#include #include -#include #include -#include - -CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS +#include namespace Catch { namespace TestCaseTracking { @@ -6009,13 +3808,14 @@ namespace TestCaseTracking { std::string name; SourceLineInfo location; - NameAndLocation( std::string const& _name, SourceLineInfo const& _location ) - : name( _name ), - location( _location ) - {} + NameAndLocation( std::string const& _name, SourceLineInfo const& _location ); }; - struct ITracker : SharedImpl<> { + struct ITracker; + + using ITrackerPtr = std::shared_ptr; + + struct ITracker { virtual ~ITracker(); // static queries @@ -6034,8 +3834,8 @@ namespace TestCaseTracking { virtual void fail() = 0; virtual void markAsNeedingAnotherRun() = 0; - virtual void addChild( Ptr const& child ) = 0; - virtual ITracker* findChild( NameAndLocation const& nameAndLocation ) = 0; + virtual void addChild( ITrackerPtr const& child ) = 0; + virtual ITrackerPtr findChild( NameAndLocation const& nameAndLocation ) = 0; virtual void openChild() = 0; // Debug/ checking @@ -6043,7 +3843,7 @@ namespace TestCaseTracking { virtual bool isIndexTracker() const = 0; }; - class TrackerContext { + class TrackerContext { enum RunState { NotStarted, @@ -6051,47 +3851,23 @@ namespace TestCaseTracking { CompletedCycle }; - Ptr m_rootTracker; - ITracker* m_currentTracker; - RunState m_runState; + ITrackerPtr m_rootTracker; + ITracker* m_currentTracker = nullptr; + RunState m_runState = NotStarted; public: - static TrackerContext& instance() { - static TrackerContext s_instance; - return s_instance; - } - - TrackerContext() - : m_currentTracker( CATCH_NULL ), - m_runState( NotStarted ) - {} + static TrackerContext& instance(); ITracker& startRun(); + void endRun(); - void endRun() { - m_rootTracker.reset(); - m_currentTracker = CATCH_NULL; - m_runState = NotStarted; - } + void startCycle(); + void completeCycle(); - void startCycle() { - m_currentTracker = m_rootTracker.get(); - m_runState = Executing; - } - void completeCycle() { - m_runState = CompletedCycle; - } - - bool completedCycle() const { - return m_runState == CompletedCycle; - } - ITracker& currentTracker() { - return *m_currentTracker; - } - void setCurrentTracker( ITracker* tracker ) { - m_currentTracker = tracker; - } + bool completedCycle() const; + ITracker& currentTracker(); + void setCurrentTracker( ITracker* tracker ); }; class TrackerBase : public ITracker { @@ -6104,240 +3880,82 @@ namespace TestCaseTracking { CompletedSuccessfully, Failed }; + class TrackerHasName { NameAndLocation m_nameAndLocation; public: - TrackerHasName( NameAndLocation const& nameAndLocation ) : m_nameAndLocation( nameAndLocation ) {} - bool operator ()( Ptr const& tracker ) { - return - tracker->nameAndLocation().name == m_nameAndLocation.name && - tracker->nameAndLocation().location == m_nameAndLocation.location; - } + TrackerHasName( NameAndLocation const& nameAndLocation ); + bool operator ()( ITrackerPtr const& tracker ) const; }; - typedef std::vector > Children; + + using Children = std::vector; NameAndLocation m_nameAndLocation; TrackerContext& m_ctx; ITracker* m_parent; Children m_children; - CycleState m_runState; + CycleState m_runState = NotStarted; + public: - TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ) - : m_nameAndLocation( nameAndLocation ), - m_ctx( ctx ), - m_parent( parent ), - m_runState( NotStarted ) - {} - virtual ~TrackerBase(); + TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ); - virtual NameAndLocation const& nameAndLocation() const CATCH_OVERRIDE { - return m_nameAndLocation; - } - virtual bool isComplete() const CATCH_OVERRIDE { - return m_runState == CompletedSuccessfully || m_runState == Failed; - } - virtual bool isSuccessfullyCompleted() const CATCH_OVERRIDE { - return m_runState == CompletedSuccessfully; - } - virtual bool isOpen() const CATCH_OVERRIDE { - return m_runState != NotStarted && !isComplete(); - } - virtual bool hasChildren() const CATCH_OVERRIDE { - return !m_children.empty(); - } + NameAndLocation const& nameAndLocation() const override; + bool isComplete() const override; + bool isSuccessfullyCompleted() const override; + bool isOpen() const override; + bool hasChildren() const override; - virtual void addChild( Ptr const& child ) CATCH_OVERRIDE { - m_children.push_back( child ); - } + void addChild( ITrackerPtr const& child ) override; - virtual ITracker* findChild( NameAndLocation const& nameAndLocation ) CATCH_OVERRIDE { - Children::const_iterator it = std::find_if( m_children.begin(), m_children.end(), TrackerHasName( nameAndLocation ) ); - return( it != m_children.end() ) - ? it->get() - : CATCH_NULL; - } - virtual ITracker& parent() CATCH_OVERRIDE { - assert( m_parent ); // Should always be non-null except for root - return *m_parent; - } + ITrackerPtr findChild( NameAndLocation const& nameAndLocation ) override; + ITracker& parent() override; - virtual void openChild() CATCH_OVERRIDE { - if( m_runState != ExecutingChildren ) { - m_runState = ExecutingChildren; - if( m_parent ) - m_parent->openChild(); - } - } + void openChild() override; - virtual bool isSectionTracker() const CATCH_OVERRIDE { return false; } - virtual bool isIndexTracker() const CATCH_OVERRIDE { return false; } + bool isSectionTracker() const override; + bool isIndexTracker() const override; - void open() { - m_runState = Executing; - moveToThis(); - if( m_parent ) - m_parent->openChild(); - } + void open(); - virtual void close() CATCH_OVERRIDE { + void close() override; + void fail() override; + void markAsNeedingAnotherRun() override; - // Close any still open children (e.g. generators) - while( &m_ctx.currentTracker() != this ) - m_ctx.currentTracker().close(); - - switch( m_runState ) { - case NotStarted: - case CompletedSuccessfully: - case Failed: - throw std::logic_error( "Illogical state" ); - - case NeedsAnotherRun: - break;; - - case Executing: - m_runState = CompletedSuccessfully; - break; - case ExecutingChildren: - if( m_children.empty() || m_children.back()->isComplete() ) - m_runState = CompletedSuccessfully; - break; - - default: - throw std::logic_error( "Unexpected state" ); - } - moveToParent(); - m_ctx.completeCycle(); - } - virtual void fail() CATCH_OVERRIDE { - m_runState = Failed; - if( m_parent ) - m_parent->markAsNeedingAnotherRun(); - moveToParent(); - m_ctx.completeCycle(); - } - virtual void markAsNeedingAnotherRun() CATCH_OVERRIDE { - m_runState = NeedsAnotherRun; - } private: - void moveToParent() { - assert( m_parent ); - m_ctx.setCurrentTracker( m_parent ); - } - void moveToThis() { - m_ctx.setCurrentTracker( this ); - } + void moveToParent(); + void moveToThis(); }; class SectionTracker : public TrackerBase { std::vector m_filters; public: - SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ) - : TrackerBase( nameAndLocation, ctx, parent ) - { - if( parent ) { - while( !parent->isSectionTracker() ) - parent = &parent->parent(); + SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ); - SectionTracker& parentSection = static_cast( *parent ); - addNextFilters( parentSection.m_filters ); - } - } - virtual ~SectionTracker(); + bool isSectionTracker() const override; - virtual bool isSectionTracker() const CATCH_OVERRIDE { return true; } + static SectionTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ); - static SectionTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ) { - SectionTracker* section = CATCH_NULL; + void tryOpen(); - ITracker& currentTracker = ctx.currentTracker(); - if( ITracker* childTracker = currentTracker.findChild( nameAndLocation ) ) { - assert( childTracker ); - assert( childTracker->isSectionTracker() ); - section = static_cast( childTracker ); - } - else { - section = new SectionTracker( nameAndLocation, ctx, ¤tTracker ); - currentTracker.addChild( section ); - } - if( !ctx.completedCycle() ) - section->tryOpen(); - return *section; - } - - void tryOpen() { - if( !isComplete() && (m_filters.empty() || m_filters[0].empty() || m_filters[0] == m_nameAndLocation.name ) ) - open(); - } - - void addInitialFilters( std::vector const& filters ) { - if( !filters.empty() ) { - m_filters.push_back(""); // Root - should never be consulted - m_filters.push_back(""); // Test Case - not a section filter - m_filters.insert( m_filters.end(), filters.begin(), filters.end() ); - } - } - void addNextFilters( std::vector const& filters ) { - if( filters.size() > 1 ) - m_filters.insert( m_filters.end(), ++filters.begin(), filters.end() ); - } + void addInitialFilters( std::vector const& filters ); + void addNextFilters( std::vector const& filters ); }; class IndexTracker : public TrackerBase { int m_size; - int m_index; + int m_index = -1; public: - IndexTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent, int size ) - : TrackerBase( nameAndLocation, ctx, parent ), - m_size( size ), - m_index( -1 ) - {} - virtual ~IndexTracker(); + IndexTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent, int size ); - virtual bool isIndexTracker() const CATCH_OVERRIDE { return true; } + bool isIndexTracker() const override; + void close() override; - static IndexTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation, int size ) { - IndexTracker* tracker = CATCH_NULL; + static IndexTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation, int size ); - ITracker& currentTracker = ctx.currentTracker(); - if( ITracker* childTracker = currentTracker.findChild( nameAndLocation ) ) { - assert( childTracker ); - assert( childTracker->isIndexTracker() ); - tracker = static_cast( childTracker ); - } - else { - tracker = new IndexTracker( nameAndLocation, ctx, ¤tTracker, size ); - currentTracker.addChild( tracker ); - } + int index() const; - if( !ctx.completedCycle() && !tracker->isComplete() ) { - if( tracker->m_runState != ExecutingChildren && tracker->m_runState != NeedsAnotherRun ) - tracker->moveNext(); - tracker->open(); - } - - return *tracker; - } - - int index() const { return m_index; } - - void moveNext() { - m_index++; - m_children.clear(); - } - - virtual void close() CATCH_OVERRIDE { - TrackerBase::close(); - if( m_runState == CompletedSuccessfully && m_index < m_size-1 ) - m_runState = Executing; - } + void moveNext(); }; - inline ITracker& TrackerContext::startRun() { - m_rootTracker = new SectionTracker( NameAndLocation( "{root}", CATCH_INTERNAL_LINEINFO ), *this, CATCH_NULL ); - m_currentTracker = CATCH_NULL; - m_runState = Executing; - return *m_rootTracker; - } - } // namespace TestCaseTracking using TestCaseTracking::ITracker; @@ -6347,31 +3965,1941 @@ using TestCaseTracking::IndexTracker; } // namespace Catch -CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS +// end catch_test_case_tracker.h -// #included from: catch_fatal_condition.hpp -#define TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED +// start catch_leak_detector.h namespace Catch { - // Report the error condition - inline void reportFatal( std::string const& message ) { - IContext& context = Catch::getCurrentContext(); - IResultCapture* resultCapture = context.getResultCapture(); - resultCapture->handleFatalErrorCondition( message ); + struct LeakDetector { + LeakDetector(); + }; + +} +// end catch_leak_detector.h +// Cpp files will be included in the single-header file here +// start catch_approx.cpp + +#include +#include + +namespace { + +// Performs equivalent check of std::fabs(lhs - rhs) <= margin +// But without the subtraction to allow for INFINITY in comparison +bool marginComparison(double lhs, double rhs, double margin) { + return (lhs + margin >= rhs) && (rhs + margin >= lhs); +} + +} + +namespace Catch { +namespace Detail { + + Approx::Approx ( double value ) + : m_epsilon( std::numeric_limits::epsilon()*100 ), + m_margin( 0.0 ), + m_scale( 0.0 ), + m_value( value ) + {} + + Approx Approx::custom() { + return Approx( 0 ); + } + + std::string Approx::toString() const { + std::ostringstream oss; + oss << "Approx( " << ::Catch::Detail::stringify( m_value ) << " )"; + return oss.str(); + } + + bool Approx::equalityComparisonImpl(const double other) const { + // First try with fixed margin, then compute margin based on epsilon, scale and Approx's value + // Thanks to Richard Harris for his help refining the scaled margin value + return marginComparison(m_value, other, m_margin) || marginComparison(m_value, other, m_epsilon * (m_scale + std::fabs(m_value))); + } + +} // end namespace Detail + +std::string StringMaker::convert(Catch::Detail::Approx const& value) { + return value.toString(); +} + +} // end namespace Catch +// end catch_approx.cpp +// start catch_assertionhandler.cpp + +// start catch_context.h + +#include + +namespace Catch { + + struct IResultCapture; + struct IRunner; + struct IConfig; + + using IConfigPtr = std::shared_ptr; + + struct IContext + { + virtual ~IContext(); + + virtual IResultCapture* getResultCapture() = 0; + virtual IRunner* getRunner() = 0; + virtual IConfigPtr getConfig() const = 0; + }; + + struct IMutableContext : IContext + { + virtual ~IMutableContext(); + virtual void setResultCapture( IResultCapture* resultCapture ) = 0; + virtual void setRunner( IRunner* runner ) = 0; + virtual void setConfig( IConfigPtr const& config ) = 0; + }; + + IContext& getCurrentContext(); + IMutableContext& getCurrentMutableContext(); + void cleanUpContext(); +} + +// end catch_context.h +#include + +namespace Catch { + + auto operator <<( std::ostream& os, ITransientExpression const& expr ) -> std::ostream& { + expr.streamReconstructedExpression( os ); + return os; + } + + LazyExpression::LazyExpression( bool isNegated ) + : m_isNegated( isNegated ) + {} + + LazyExpression::LazyExpression( LazyExpression const& other ) : m_isNegated( other.m_isNegated ) {} + + LazyExpression::operator bool() const { + return m_transientExpression != nullptr; + } + + auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream& { + if( lazyExpr.m_isNegated ) + os << "!"; + + if( lazyExpr ) { + if( lazyExpr.m_isNegated && lazyExpr.m_transientExpression->isBinaryExpression() ) + os << "(" << *lazyExpr.m_transientExpression << ")"; + else + os << *lazyExpr.m_transientExpression; + } + else { + os << "{** error - unchecked empty expression requested **}"; + } + return os; + } + + AssertionHandler::AssertionHandler + ( StringRef macroName, + SourceLineInfo const& lineInfo, + StringRef capturedExpression, + ResultDisposition::Flags resultDisposition ) + : m_assertionInfo{ macroName, lineInfo, capturedExpression, resultDisposition } + { + getCurrentContext().getResultCapture()->assertionStarting( m_assertionInfo ); + } + AssertionHandler::~AssertionHandler() { + if ( m_inExceptionGuard ) { + handle( ResultWas::ThrewException, "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE" ); + getCurrentContext().getResultCapture()->exceptionEarlyReported(); + } + } + + void AssertionHandler::handle( ITransientExpression const& expr ) { + + bool negated = isFalseTest( m_assertionInfo.resultDisposition ); + bool result = expr.getResult() != negated; + + handle( result ? ResultWas::Ok : ResultWas::ExpressionFailed, &expr, negated ); + } + void AssertionHandler::handle( ResultWas::OfType resultType ) { + handle( resultType, nullptr, false ); + } + void AssertionHandler::handle( ResultWas::OfType resultType, StringRef const& message ) { + AssertionResultData data( resultType, LazyExpression( false ) ); + data.message = message; + handle( data, nullptr ); + } + void AssertionHandler::handle( ResultWas::OfType resultType, ITransientExpression const* expr, bool negated ) { + AssertionResultData data( resultType, LazyExpression( negated ) ); + handle( data, expr ); + } + void AssertionHandler::handle( AssertionResultData const& resultData, ITransientExpression const* expr ) { + + getResultCapture().assertionRun(); + + AssertionResult assertionResult{ m_assertionInfo, resultData }; + assertionResult.m_resultData.lazyExpression.m_transientExpression = expr; + + getResultCapture().assertionEnded( assertionResult ); + + if( !assertionResult.isOk() ) { + m_shouldDebugBreak = getCurrentContext().getConfig()->shouldDebugBreak(); + m_shouldThrow = + getCurrentContext().getRunner()->aborting() || + (m_assertionInfo.resultDisposition & ResultDisposition::Normal); + } + } + + auto AssertionHandler::allowThrows() const -> bool { + return getCurrentContext().getConfig()->allowThrows(); + } + + auto AssertionHandler::shouldDebugBreak() const -> bool { + return m_shouldDebugBreak; + } + void AssertionHandler::reactWithDebugBreak() const { + if (m_shouldDebugBreak) { + /////////////////////////////////////////////////////////////////// + // To inspect the state during test, you need to go one level up the callstack + // To go back to the test and change execution, jump over the reactWithoutDebugBreak() call + /////////////////////////////////////////////////////////////////// + CATCH_BREAK_INTO_DEBUGGER(); + } + reactWithoutDebugBreak(); + } + void AssertionHandler::reactWithoutDebugBreak() const { + if( m_shouldThrow ) + throw Catch::TestFailureException(); + } + + void AssertionHandler::useActiveException() { + handle( ResultWas::ThrewException, Catch::translateActiveException() ); + } + + void AssertionHandler::setExceptionGuard() { + assert( m_inExceptionGuard == false ); + m_inExceptionGuard = true; + } + void AssertionHandler::unsetExceptionGuard() { + assert( m_inExceptionGuard == true ); + m_inExceptionGuard = false; + } + + // This is the overload that takes a string and infers the Equals matcher from it + // The more general overload, that takes any string matcher, is in catch_capture_matchers.cpp + void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef matcherString ) { + handleExceptionMatchExpr( handler, Matchers::Equals( str ), matcherString ); } } // namespace Catch +// end catch_assertionhandler.cpp +// start catch_assertionresult.cpp -#if defined ( CATCH_PLATFORM_WINDOWS ) ///////////////////////////////////////// -// #included from: catch_windows_h_proxy.h +namespace Catch { + AssertionResultData::AssertionResultData(ResultWas::OfType _resultType, LazyExpression const & _lazyExpression): + lazyExpression(_lazyExpression), + resultType(_resultType) {} -#define TWOBLUECUBES_CATCH_WINDOWS_H_PROXY_H_INCLUDED + std::string AssertionResultData::reconstructExpression() const { -#ifdef CATCH_DEFINES_NOMINMAX + if( reconstructedExpression.empty() ) { + if( lazyExpression ) { + // !TBD Use stringstream for now, but rework above to pass stream in + std::ostringstream oss; + oss << lazyExpression; + reconstructedExpression = oss.str(); + } + } + return reconstructedExpression; + } + + AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data ) + : m_info( info ), + m_resultData( data ) + {} + + // Result was a success + bool AssertionResult::succeeded() const { + return Catch::isOk( m_resultData.resultType ); + } + + // Result was a success, or failure is suppressed + bool AssertionResult::isOk() const { + return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition ); + } + + ResultWas::OfType AssertionResult::getResultType() const { + return m_resultData.resultType; + } + + bool AssertionResult::hasExpression() const { + return m_info.capturedExpression[0] != 0; + } + + bool AssertionResult::hasMessage() const { + return !m_resultData.message.empty(); + } + + std::string AssertionResult::getExpression() const { + if( isFalseTest( m_info.resultDisposition ) ) + return "!(" + std::string(m_info.capturedExpression) + ")"; + else + return m_info.capturedExpression; + } + + std::string AssertionResult::getExpressionInMacro() const { + std::string expr; + if( m_info.macroName[0] == 0 ) + expr = m_info.capturedExpression; + else { + expr.reserve( m_info.macroName.size() + m_info.capturedExpression.size() + 4 ); + expr += m_info.macroName; + expr += "( "; + expr += m_info.capturedExpression; + expr += " )"; + } + return expr; + } + + bool AssertionResult::hasExpandedExpression() const { + return hasExpression() && getExpandedExpression() != getExpression(); + } + + std::string AssertionResult::getExpandedExpression() const { + std::string expr = m_resultData.reconstructExpression(); + return expr.empty() + ? getExpression() + : expr; + } + + std::string AssertionResult::getMessage() const { + return m_resultData.message; + } + SourceLineInfo AssertionResult::getSourceInfo() const { + return m_info.lineInfo; + } + + std::string AssertionResult::getTestMacroName() const { + return m_info.macroName; + } + +} // end namespace Catch +// end catch_assertionresult.cpp +// start catch_benchmark.cpp + +namespace Catch { + + auto BenchmarkLooper::getResolution() -> uint64_t { + return getEstimatedClockResolution() * getCurrentContext().getConfig()->benchmarkResolutionMultiple(); + } + + void BenchmarkLooper::reportStart() { + getResultCapture().benchmarkStarting( { m_name } ); + } + auto BenchmarkLooper::needsMoreIterations() -> bool { + auto elapsed = m_timer.getElapsedNanoseconds(); + + // Exponentially increasing iterations until we're confident in our timer resolution + if( elapsed < m_resolution ) { + m_iterationsToRun *= 10; + return true; + } + + getResultCapture().benchmarkEnded( { { m_name }, m_count, elapsed } ); + return false; + } + +} // end namespace Catch +// end catch_benchmark.cpp +// start catch_capture_matchers.cpp + +namespace Catch { + + using StringMatcher = Matchers::Impl::MatcherBase; + + // This is the general overload that takes a any string matcher + // There is another overload, in catch_assertinhandler.h/.cpp, that only takes a string and infers + // the Equals matcher (so the header does not mention matchers) + void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef matcherString ) { + std::string exceptionMessage = Catch::translateActiveException(); + MatchExpr expr( exceptionMessage, matcher, matcherString ); + handler.handle( expr ); + } + +} // namespace Catch +// end catch_capture_matchers.cpp +// start catch_commandline.cpp + +// start catch_commandline.h + +// start catch_clara.h + +// Use Catch's value for console width (store Clara's off to the side, if present) +#ifdef CLARA_CONFIG_CONSOLE_WIDTH +#define CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH +#undef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH +#endif +#define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH-1 + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wweak-vtables" +#pragma clang diagnostic ignored "-Wexit-time-destructors" +#pragma clang diagnostic ignored "-Wshadow" +#endif + +// start clara.hpp +// v1.0-develop.2 +// See https://github.com/philsquared/Clara + + +#ifndef CATCH_CLARA_CONFIG_CONSOLE_WIDTH +#define CATCH_CLARA_CONFIG_CONSOLE_WIDTH 80 +#endif + +#ifndef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH +#define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_CLARA_CONFIG_CONSOLE_WIDTH +#endif + +// ----------- #included from clara_textflow.hpp ----------- + +// TextFlowCpp +// +// A single-header library for wrapping and laying out basic text, by Phil Nash +// +// This work is licensed under the BSD 2-Clause license. +// See the accompanying LICENSE file, or the one at https://opensource.org/licenses/BSD-2-Clause +// +// This project is hosted at https://github.com/philsquared/textflowcpp + + +#include +#include +#include +#include + +#ifndef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH +#define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH 80 +#endif + +namespace Catch { namespace clara { namespace TextFlow { + + inline auto isWhitespace( char c ) -> bool { + static std::string chars = " \t\n\r"; + return chars.find( c ) != std::string::npos; + } + inline auto isBreakableBefore( char c ) -> bool { + static std::string chars = "[({<|"; + return chars.find( c ) != std::string::npos; + } + inline auto isBreakableAfter( char c ) -> bool { + static std::string chars = "])}>.,:;*+-=&/\\"; + return chars.find( c ) != std::string::npos; + } + + class Columns; + + class Column { + std::vector m_strings; + size_t m_width = CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH; + size_t m_indent = 0; + size_t m_initialIndent = std::string::npos; + + public: + class iterator { + friend Column; + + Column const& m_column; + size_t m_stringIndex = 0; + size_t m_pos = 0; + + size_t m_len = 0; + size_t m_end = 0; + bool m_suffix = false; + + iterator( Column const& column, size_t stringIndex ) + : m_column( column ), + m_stringIndex( stringIndex ) + {} + + auto line() const -> std::string const& { return m_column.m_strings[m_stringIndex]; } + + auto isBoundary( size_t at ) const -> bool { + assert( at > 0 ); + assert( at <= line().size() ); + + return at == line().size() || + ( isWhitespace( line()[at] ) && !isWhitespace( line()[at-1] ) ) || + isBreakableBefore( line()[at] ) || + isBreakableAfter( line()[at-1] ); + } + + void calcLength() { + assert( m_stringIndex < m_column.m_strings.size() ); + + m_suffix = false; + auto width = m_column.m_width-indent(); + m_end = m_pos; + while( m_end < line().size() && line()[m_end] != '\n' ) + ++m_end; + + if( m_end < m_pos + width ) { + m_len = m_end - m_pos; + } + else { + size_t len = width; + while (len > 0 && !isBoundary(m_pos + len)) + --len; + while (len > 0 && isWhitespace( line()[m_pos + len - 1] )) + --len; + + if (len > 0) { + m_len = len; + } else { + m_suffix = true; + m_len = width - 1; + } + } + } + + auto indent() const -> size_t { + auto initial = m_pos == 0 && m_stringIndex == 0 ? m_column.m_initialIndent : std::string::npos; + return initial == std::string::npos ? m_column.m_indent : initial; + } + + auto addIndentAndSuffix(std::string const &plain) const -> std::string { + return std::string( indent(), ' ' ) + (m_suffix ? plain + "-" : plain); + } + + public: + explicit iterator( Column const& column ) : m_column( column ) { + assert( m_column.m_width > m_column.m_indent ); + assert( m_column.m_initialIndent == std::string::npos || m_column.m_width > m_column.m_initialIndent ); + calcLength(); + if( m_len == 0 ) + m_stringIndex++; // Empty string + } + + auto operator *() const -> std::string { + assert( m_stringIndex < m_column.m_strings.size() ); + assert( m_pos <= m_end ); + if( m_pos + m_column.m_width < m_end ) + return addIndentAndSuffix(line().substr(m_pos, m_len)); + else + return addIndentAndSuffix(line().substr(m_pos, m_end - m_pos)); + } + + auto operator ++() -> iterator& { + m_pos += m_len; + if( m_pos < line().size() && line()[m_pos] == '\n' ) + m_pos += 1; + else + while( m_pos < line().size() && isWhitespace( line()[m_pos] ) ) + ++m_pos; + + if( m_pos == line().size() ) { + m_pos = 0; + ++m_stringIndex; + } + if( m_stringIndex < m_column.m_strings.size() ) + calcLength(); + return *this; + } + auto operator ++(int) -> iterator { + iterator prev( *this ); + operator++(); + return prev; + } + + auto operator ==( iterator const& other ) const -> bool { + return + m_pos == other.m_pos && + m_stringIndex == other.m_stringIndex && + &m_column == &other.m_column; + } + auto operator !=( iterator const& other ) const -> bool { + return !operator==( other ); + } + }; + using const_iterator = iterator; + + explicit Column( std::string const& text ) { m_strings.push_back( text ); } + + auto width( size_t newWidth ) -> Column& { + assert( newWidth > 0 ); + m_width = newWidth; + return *this; + } + auto indent( size_t newIndent ) -> Column& { + m_indent = newIndent; + return *this; + } + auto initialIndent( size_t newIndent ) -> Column& { + m_initialIndent = newIndent; + return *this; + } + + auto width() const -> size_t { return m_width; } + auto begin() const -> iterator { return iterator( *this ); } + auto end() const -> iterator { return { *this, m_strings.size() }; } + + inline friend std::ostream& operator << ( std::ostream& os, Column const& col ) { + bool first = true; + for( auto line : col ) { + if( first ) + first = false; + else + os << "\n"; + os << line; + } + return os; + } + + auto operator + ( Column const& other ) -> Columns; + + auto toString() const -> std::string { + std::ostringstream oss; + oss << *this; + return oss.str(); + } + }; + + class Spacer : public Column { + + public: + explicit Spacer( size_t spaceWidth ) : Column( "" ) { + width( spaceWidth ); + } + }; + + class Columns { + std::vector m_columns; + + public: + + class iterator { + friend Columns; + struct EndTag {}; + + std::vector const& m_columns; + std::vector m_iterators; + size_t m_activeIterators; + + iterator( Columns const& columns, EndTag ) + : m_columns( columns.m_columns ), + m_activeIterators( 0 ) + { + m_iterators.reserve( m_columns.size() ); + + for( auto const& col : m_columns ) + m_iterators.push_back( col.end() ); + } + + public: + explicit iterator( Columns const& columns ) + : m_columns( columns.m_columns ), + m_activeIterators( m_columns.size() ) + { + m_iterators.reserve( m_columns.size() ); + + for( auto const& col : m_columns ) + m_iterators.push_back( col.begin() ); + } + + auto operator ==( iterator const& other ) const -> bool { + return m_iterators == other.m_iterators; + } + auto operator !=( iterator const& other ) const -> bool { + return m_iterators != other.m_iterators; + } + auto operator *() const -> std::string { + std::string row, padding; + + for( size_t i = 0; i < m_columns.size(); ++i ) { + auto width = m_columns[i].width(); + if( m_iterators[i] != m_columns[i].end() ) { + std::string col = *m_iterators[i]; + row += padding + col; + if( col.size() < width ) + padding = std::string( width - col.size(), ' ' ); + else + padding = ""; + } + else { + padding += std::string( width, ' ' ); + } + } + return row; + } + auto operator ++() -> iterator& { + for( size_t i = 0; i < m_columns.size(); ++i ) { + if (m_iterators[i] != m_columns[i].end()) + ++m_iterators[i]; + } + return *this; + } + auto operator ++(int) -> iterator { + iterator prev( *this ); + operator++(); + return prev; + } + }; + using const_iterator = iterator; + + auto begin() const -> iterator { return iterator( *this ); } + auto end() const -> iterator { return { *this, iterator::EndTag() }; } + + auto operator += ( Column const& col ) -> Columns& { + m_columns.push_back( col ); + return *this; + } + auto operator + ( Column const& col ) -> Columns { + Columns combined = *this; + combined += col; + return combined; + } + + inline friend std::ostream& operator << ( std::ostream& os, Columns const& cols ) { + + bool first = true; + for( auto line : cols ) { + if( first ) + first = false; + else + os << "\n"; + os << line; + } + return os; + } + + auto toString() const -> std::string { + std::ostringstream oss; + oss << *this; + return oss.str(); + } + }; + + inline auto Column::operator + ( Column const& other ) -> Columns { + Columns cols; + cols += *this; + cols += other; + return cols; + } +}}} // namespace Catch::clara::TextFlow + +// ----------- end of #include from clara_textflow.hpp ----------- +// ........... back in clara.hpp + +#include +#include +#include + +#if !defined(CATCH_PLATFORM_WINDOWS) && ( defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) ) +#define CATCH_PLATFORM_WINDOWS +#endif + +namespace Catch { namespace clara { +namespace detail { + + // Traits for extracting arg and return type of lambdas (for single argument lambdas) + template + struct UnaryLambdaTraits : UnaryLambdaTraits {}; + + template + struct UnaryLambdaTraits { + static const bool isValid = false; + }; + + template + struct UnaryLambdaTraits { + static const bool isValid = true; + using ArgType = typename std::remove_const::type>::type;; + using ReturnType = ReturnT; + }; + + class TokenStream; + + // Transport for raw args (copied from main args, or supplied via init list for testing) + class Args { + friend TokenStream; + std::string m_exeName; + std::vector m_args; + + public: + Args( int argc, char *argv[] ) { + m_exeName = argv[0]; + for( int i = 1; i < argc; ++i ) + m_args.push_back( argv[i] ); + } + + Args( std::initializer_list args ) + : m_exeName( *args.begin() ), + m_args( args.begin()+1, args.end() ) + {} + + auto exeName() const -> std::string { + return m_exeName; + } + }; + + // Wraps a token coming from a token stream. These may not directly correspond to strings as a single string + // may encode an option + its argument if the : or = form is used + enum class TokenType { + Option, Argument + }; + struct Token { + TokenType type; + std::string token; + }; + + inline auto isOptPrefix( char c ) -> bool { + return c == '-' +#ifdef CATCH_PLATFORM_WINDOWS + || c == '/' +#endif + ; + } + + // Abstracts iterators into args as a stream of tokens, with option arguments uniformly handled + class TokenStream { + using Iterator = std::vector::const_iterator; + Iterator it; + Iterator itEnd; + std::vector m_tokenBuffer; + + void loadBuffer() { + m_tokenBuffer.resize( 0 ); + + // Skip any empty strings + while( it != itEnd && it->empty() ) + ++it; + + if( it != itEnd ) { + auto const &next = *it; + if( isOptPrefix( next[0] ) ) { + auto delimiterPos = next.find_first_of( " :=" ); + if( delimiterPos != std::string::npos ) { + m_tokenBuffer.push_back( { TokenType::Option, next.substr( 0, delimiterPos ) } ); + m_tokenBuffer.push_back( { TokenType::Argument, next.substr( delimiterPos + 1 ) } ); + } else { + if( next[1] != '-' && next.size() > 2 ) { + std::string opt = "- "; + for( size_t i = 1; i < next.size(); ++i ) { + opt[1] = next[i]; + m_tokenBuffer.push_back( { TokenType::Option, opt } ); + } + } else { + m_tokenBuffer.push_back( { TokenType::Option, next } ); + } + } + } else { + m_tokenBuffer.push_back( { TokenType::Argument, next } ); + } + } + } + + public: + explicit TokenStream( Args const &args ) : TokenStream( args.m_args.begin(), args.m_args.end() ) {} + + TokenStream( Iterator it, Iterator itEnd ) : it( it ), itEnd( itEnd ) { + loadBuffer(); + } + + explicit operator bool() const { + return !m_tokenBuffer.empty() || it != itEnd; + } + + auto count() const -> size_t { return m_tokenBuffer.size() + (itEnd - it); } + + auto operator*() const -> Token { + assert( !m_tokenBuffer.empty() ); + return m_tokenBuffer.front(); + } + + auto operator->() const -> Token const * { + assert( !m_tokenBuffer.empty() ); + return &m_tokenBuffer.front(); + } + + auto operator++() -> TokenStream & { + if( m_tokenBuffer.size() >= 2 ) { + m_tokenBuffer.erase( m_tokenBuffer.begin() ); + } else { + if( it != itEnd ) + ++it; + loadBuffer(); + } + return *this; + } + }; + + class ResultBase { + public: + enum Type { + Ok, LogicError, RuntimeError + }; + + protected: + ResultBase( Type type ) : m_type( type ) {} + virtual ~ResultBase() = default; + + virtual void enforceOk() const = 0; + + Type m_type; + }; + + template + class ResultValueBase : public ResultBase { + public: + auto value() const -> T const & { + enforceOk(); + return m_value; + } + + protected: + ResultValueBase( Type type ) : ResultBase( type ) {} + + ResultValueBase( ResultValueBase const &other ) : ResultBase( other ) { + if( m_type == ResultBase::Ok ) + new( &m_value ) T( other.m_value ); + } + + ResultValueBase( Type, T const &value ) : ResultBase( Ok ) { + new( &m_value ) T( value ); + } + + auto operator=( ResultValueBase const &other ) -> ResultValueBase & { + if( m_type == ResultBase::Ok ) + m_value.~T(); + ResultBase::operator=(other); + if( m_type == ResultBase::Ok ) + new( &m_value ) T( other.m_value ); + return *this; + } + + ~ResultValueBase() { + if( m_type == Ok ) + m_value.~T(); + } + + union { + T m_value; + }; + }; + + template<> + class ResultValueBase : public ResultBase { + protected: + using ResultBase::ResultBase; + }; + + template + class BasicResult : public ResultValueBase { + public: + template + explicit BasicResult( BasicResult const &other ) + : ResultValueBase( other.type() ), + m_errorMessage( other.errorMessage() ) + { + assert( type() != ResultBase::Ok ); + } + + template + static auto ok( U const &value ) -> BasicResult { return { ResultBase::Ok, value }; } + static auto ok() -> BasicResult { return { ResultBase::Ok }; } + static auto logicError( std::string const &message ) -> BasicResult { return { ResultBase::LogicError, message }; } + static auto runtimeError( std::string const &message ) -> BasicResult { return { ResultBase::RuntimeError, message }; } + + explicit operator bool() const { return m_type == ResultBase::Ok; } + auto type() const -> ResultBase::Type { return m_type; } + auto errorMessage() const -> std::string { return m_errorMessage; } + + protected: + virtual void enforceOk() const { + // !TBD: If no exceptions, std::terminate here or something + switch( m_type ) { + case ResultBase::LogicError: + throw std::logic_error( m_errorMessage ); + case ResultBase::RuntimeError: + throw std::runtime_error( m_errorMessage ); + case ResultBase::Ok: + break; + } + } + + std::string m_errorMessage; // Only populated if resultType is an error + + BasicResult( ResultBase::Type type, std::string const &message ) + : ResultValueBase(type), + m_errorMessage(message) + { + assert( m_type != ResultBase::Ok ); + } + + using ResultValueBase::ResultValueBase; + using ResultBase::m_type; + }; + + enum class ParseResultType { + Matched, NoMatch, ShortCircuitAll, ShortCircuitSame + }; + + class ParseState { + public: + + ParseState( ParseResultType type, TokenStream const &remainingTokens ) + : m_type(type), + m_remainingTokens( remainingTokens ) + {} + + auto type() const -> ParseResultType { return m_type; } + auto remainingTokens() const -> TokenStream { return m_remainingTokens; } + + private: + ParseResultType m_type; + TokenStream m_remainingTokens; + }; + + using Result = BasicResult; + using ParserResult = BasicResult; + using InternalParseResult = BasicResult; + + struct HelpColumns { + std::string left; + std::string right; + }; + + template + inline auto convertInto( std::string const &source, T& target ) -> ParserResult { + std::stringstream ss; + ss << source; + ss >> target; + if( ss.fail() ) + return ParserResult::runtimeError( "Unable to convert '" + source + "' to destination type" ); + else + return ParserResult::ok( ParseResultType::Matched ); + } + inline auto convertInto( std::string const &source, std::string& target ) -> ParserResult { + target = source; + return ParserResult::ok( ParseResultType::Matched ); + } + inline auto convertInto( std::string const &source, bool &target ) -> ParserResult { + std::string srcLC = source; + std::transform( srcLC.begin(), srcLC.end(), srcLC.begin(), []( char c ) { return static_cast( ::tolower(c) ); } ); + if (srcLC == "y" || srcLC == "1" || srcLC == "true" || srcLC == "yes" || srcLC == "on") + target = true; + else if (srcLC == "n" || srcLC == "0" || srcLC == "false" || srcLC == "no" || srcLC == "off") + target = false; + else + return ParserResult::runtimeError( "Expected a boolean value but did not recognise: '" + source + "'" ); + return ParserResult::ok( ParseResultType::Matched ); + } + + struct BoundRefBase { + BoundRefBase() = default; + BoundRefBase( BoundRefBase const & ) = delete; + BoundRefBase( BoundRefBase && ) = delete; + BoundRefBase &operator=( BoundRefBase const & ) = delete; + BoundRefBase &operator=( BoundRefBase && ) = delete; + + virtual ~BoundRefBase() = default; + + virtual auto isFlag() const -> bool = 0; + virtual auto isContainer() const -> bool { return false; } + virtual auto setValue( std::string const &arg ) -> ParserResult = 0; + virtual auto setFlag( bool flag ) -> ParserResult = 0; + }; + + struct BoundValueRefBase : BoundRefBase { + auto isFlag() const -> bool override { return false; } + + auto setFlag( bool ) -> ParserResult override { + return ParserResult::logicError( "Flags can only be set on boolean fields" ); + } + }; + + struct BoundFlagRefBase : BoundRefBase { + auto isFlag() const -> bool override { return true; } + + auto setValue( std::string const &arg ) -> ParserResult override { + bool flag; + auto result = convertInto( arg, flag ); + if( result ) + setFlag( flag ); + return result; + } + }; + + template + struct BoundRef : BoundValueRefBase { + T &m_ref; + + explicit BoundRef( T &ref ) : m_ref( ref ) {} + + auto setValue( std::string const &arg ) -> ParserResult override { + return convertInto( arg, m_ref ); + } + }; + + template + struct BoundRef> : BoundValueRefBase { + std::vector &m_ref; + + explicit BoundRef( std::vector &ref ) : m_ref( ref ) {} + + auto isContainer() const -> bool override { return true; } + + auto setValue( std::string const &arg ) -> ParserResult override { + T temp; + auto result = convertInto( arg, temp ); + if( result ) + m_ref.push_back( temp ); + return result; + } + }; + + struct BoundFlagRef : BoundFlagRefBase { + bool &m_ref; + + explicit BoundFlagRef( bool &ref ) : m_ref( ref ) {} + + auto setFlag( bool flag ) -> ParserResult override { + m_ref = flag; + return ParserResult::ok( ParseResultType::Matched ); + } + }; + + template + struct LambdaInvoker { + static_assert( std::is_same::value, "Lambda must return void or clara::ParserResult" ); + + template + static auto invoke( L const &lambda, ArgType const &arg ) -> ParserResult { + return lambda( arg ); + } + }; + + template<> + struct LambdaInvoker { + template + static auto invoke( L const &lambda, ArgType const &arg ) -> ParserResult { + lambda( arg ); + return ParserResult::ok( ParseResultType::Matched ); + } + }; + + template + inline auto invokeLambda( L const &lambda, std::string const &arg ) -> ParserResult { + ArgType temp; + auto result = convertInto( arg, temp ); + return !result + ? result + : LambdaInvoker::ReturnType>::invoke( lambda, temp ); + }; + + template + struct BoundLambda : BoundValueRefBase { + L m_lambda; + + static_assert( UnaryLambdaTraits::isValid, "Supplied lambda must take exactly one argument" ); + explicit BoundLambda( L const &lambda ) : m_lambda( lambda ) {} + + auto setValue( std::string const &arg ) -> ParserResult override { + return invokeLambda::ArgType>( m_lambda, arg ); + } + }; + + template + struct BoundFlagLambda : BoundFlagRefBase { + L m_lambda; + + static_assert( UnaryLambdaTraits::isValid, "Supplied lambda must take exactly one argument" ); + static_assert( std::is_same::ArgType, bool>::value, "flags must be boolean" ); + + explicit BoundFlagLambda( L const &lambda ) : m_lambda( lambda ) {} + + auto setFlag( bool flag ) -> ParserResult override { + return LambdaInvoker::ReturnType>::invoke( m_lambda, flag ); + } + }; + + enum class Optionality { Optional, Required }; + + struct Parser; + + class ParserBase { + public: + virtual ~ParserBase() = default; + virtual auto validate() const -> Result { return Result::ok(); } + virtual auto parse( std::string const& exeName, TokenStream const &tokens) const -> InternalParseResult = 0; + virtual auto cardinality() const -> size_t { return 1; } + + auto parse( Args const &args ) const -> InternalParseResult { + return parse( args.exeName(), TokenStream( args ) ); + } + }; + + template + class ComposableParserImpl : public ParserBase { + public: + template + auto operator|( T const &other ) const -> Parser; + }; + + // Common code and state for Args and Opts + template + class ParserRefImpl : public ComposableParserImpl { + protected: + Optionality m_optionality = Optionality::Optional; + std::shared_ptr m_ref; + std::string m_hint; + std::string m_description; + + explicit ParserRefImpl( std::shared_ptr const &ref ) : m_ref( ref ) {} + + public: + template + ParserRefImpl( T &ref, std::string const &hint ) + : m_ref( std::make_shared>( ref ) ), + m_hint( hint ) + {} + + template + ParserRefImpl( LambdaT const &ref, std::string const &hint ) + : m_ref( std::make_shared>( ref ) ), + m_hint(hint) + {} + + auto operator()( std::string const &description ) -> DerivedT & { + m_description = description; + return static_cast( *this ); + } + + auto optional() -> DerivedT & { + m_optionality = Optionality::Optional; + return static_cast( *this ); + }; + + auto required() -> DerivedT & { + m_optionality = Optionality::Required; + return static_cast( *this ); + }; + + auto isOptional() const -> bool { + return m_optionality == Optionality::Optional; + } + + auto cardinality() const -> size_t override { + if( m_ref->isContainer() ) + return 0; + else + return 1; + } + + auto hint() const -> std::string { return m_hint; } + }; + + class ExeName : public ComposableParserImpl { + std::shared_ptr m_name; + std::shared_ptr m_ref; + + template + static auto makeRef(LambdaT const &lambda) -> std::shared_ptr { + return std::make_shared>( lambda) ; + } + + public: + ExeName() : m_name( std::make_shared( "" ) ) {} + + explicit ExeName( std::string &ref ) : ExeName() { + m_ref = std::make_shared>( ref ); + } + + template + explicit ExeName( LambdaT const& lambda ) : ExeName() { + m_ref = std::make_shared>( lambda ); + } + + // The exe name is not parsed out of the normal tokens, but is handled specially + auto parse( std::string const&, TokenStream const &tokens ) const -> InternalParseResult override { + return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, tokens ) ); + } + + auto name() const -> std::string { return *m_name; } + auto set( std::string const& newName ) -> ParserResult { + + auto lastSlash = newName.find_last_of( "\\/" ); + auto filename = ( lastSlash == std::string::npos ) + ? newName + : newName.substr( lastSlash+1 ); + + *m_name = filename; + if( m_ref ) + return m_ref->setValue( filename ); + else + return ParserResult::ok( ParseResultType::Matched ); + } + }; + + class Arg : public ParserRefImpl { + public: + using ParserRefImpl::ParserRefImpl; + + auto parse( std::string const &, TokenStream const &tokens ) const -> InternalParseResult override { + auto validationResult = validate(); + if( !validationResult ) + return InternalParseResult( validationResult ); + + auto remainingTokens = tokens; + auto const &token = *remainingTokens; + if( token.type != TokenType::Argument ) + return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) ); + + auto result = m_ref->setValue( remainingTokens->token ); + if( !result ) + return InternalParseResult( result ); + else + return InternalParseResult::ok( ParseState( ParseResultType::Matched, ++remainingTokens ) ); + } + }; + + inline auto normaliseOpt( std::string const &optName ) -> std::string { +#ifdef CATCH_PLATFORM_WINDOWS + if( optName[0] == '/' ) + return "-" + optName.substr( 1 ); + else +#endif + return optName; + } + + class Opt : public ParserRefImpl { + protected: + std::vector m_optNames; + + public: + template + explicit Opt( LambdaT const &ref ) : ParserRefImpl( std::make_shared>( ref ) ) {} + + explicit Opt( bool &ref ) : ParserRefImpl( std::make_shared( ref ) ) {} + + template + Opt( LambdaT const &ref, std::string const &hint ) : ParserRefImpl( ref, hint ) {} + + template + Opt( T &ref, std::string const &hint ) : ParserRefImpl( ref, hint ) {} + + auto operator[]( std::string const &optName ) -> Opt & { + m_optNames.push_back( optName ); + return *this; + } + + auto getHelpColumns() const -> std::vector { + std::ostringstream oss; + bool first = true; + for( auto const &opt : m_optNames ) { + if (first) + first = false; + else + oss << ", "; + oss << opt; + } + if( !m_hint.empty() ) + oss << " <" << m_hint << ">"; + return { { oss.str(), m_description } }; + } + + auto isMatch( std::string const &optToken ) const -> bool { + auto normalisedToken = normaliseOpt( optToken ); + for( auto const &name : m_optNames ) { + if( normaliseOpt( name ) == normalisedToken ) + return true; + } + return false; + } + + using ParserBase::parse; + + auto parse( std::string const&, TokenStream const &tokens ) const -> InternalParseResult override { + auto validationResult = validate(); + if( !validationResult ) + return InternalParseResult( validationResult ); + + auto remainingTokens = tokens; + if( remainingTokens && remainingTokens->type == TokenType::Option ) { + auto const &token = *remainingTokens; + if( isMatch(token.token ) ) { + if( m_ref->isFlag() ) { + auto result = m_ref->setFlag( true ); + if( !result ) + return InternalParseResult( result ); + if( result.value() == ParseResultType::ShortCircuitAll ) + return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) ); + } else { + ++remainingTokens; + if( !remainingTokens ) + return InternalParseResult::runtimeError( "Expected argument following " + token.token ); + auto const &argToken = *remainingTokens; + if( argToken.type != TokenType::Argument ) + return InternalParseResult::runtimeError( "Expected argument following " + token.token ); + auto result = m_ref->setValue( argToken.token ); + if( !result ) + return InternalParseResult( result ); + if( result.value() == ParseResultType::ShortCircuitAll ) + return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) ); + } + return InternalParseResult::ok( ParseState( ParseResultType::Matched, ++remainingTokens ) ); + } + } + return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) ); + } + + auto validate() const -> Result override { + if( m_optNames.empty() ) + return Result::logicError( "No options supplied to Opt" ); + for( auto const &name : m_optNames ) { + if( name.empty() ) + return Result::logicError( "Option name cannot be empty" ); +#ifdef CATCH_PLATFORM_WINDOWS + if( name[0] != '-' && name[0] != '/' ) + return Result::logicError( "Option name must begin with '-' or '/'" ); +#else + if( name[0] != '-' ) + return Result::logicError( "Option name must begin with '-'" ); +#endif + } + return ParserRefImpl::validate(); + } + }; + + struct Help : Opt { + Help( bool &showHelpFlag ) + : Opt([&]( bool flag ) { + showHelpFlag = flag; + return ParserResult::ok( ParseResultType::ShortCircuitAll ); + }) + { + static_cast( *this ) + ("display usage information") + ["-?"]["-h"]["--help"] + .optional(); + } + }; + + struct Parser : ParserBase { + + mutable ExeName m_exeName; + std::vector m_options; + std::vector m_args; + + auto operator|=( ExeName const &exeName ) -> Parser & { + m_exeName = exeName; + return *this; + } + + auto operator|=( Arg const &arg ) -> Parser & { + m_args.push_back(arg); + return *this; + } + + auto operator|=( Opt const &opt ) -> Parser & { + m_options.push_back(opt); + return *this; + } + + auto operator|=( Parser const &other ) -> Parser & { + m_options.insert(m_options.end(), other.m_options.begin(), other.m_options.end()); + m_args.insert(m_args.end(), other.m_args.begin(), other.m_args.end()); + return *this; + } + + template + auto operator|( T const &other ) const -> Parser { + return Parser( *this ) |= other; + } + + auto getHelpColumns() const -> std::vector { + std::vector cols; + for (auto const &o : m_options) { + auto childCols = o.getHelpColumns(); + cols.insert( cols.end(), childCols.begin(), childCols.end() ); + } + return cols; + } + + void writeToStream( std::ostream &os ) const { + if (!m_exeName.name().empty()) { + os << "usage:\n" << " " << m_exeName.name() << " "; + bool required = true, first = true; + for( auto const &arg : m_args ) { + if (first) + first = false; + else + os << " "; + if( arg.isOptional() && required ) { + os << "["; + required = false; + } + os << "<" << arg.hint() << ">"; + if( arg.cardinality() == 0 ) + os << " ... "; + } + if( !required ) + os << "]"; + if( !m_options.empty() ) + os << " options"; + os << "\n\nwhere options are:" << std::endl; + } + + auto rows = getHelpColumns(); + size_t consoleWidth = CATCH_CLARA_CONFIG_CONSOLE_WIDTH; + size_t optWidth = 0; + for( auto const &cols : rows ) + optWidth = (std::max)(optWidth, cols.left.size() + 2); + + for( auto const &cols : rows ) { + auto row = + TextFlow::Column( cols.left ).width( optWidth ).indent( 2 ) + + TextFlow::Spacer(4) + + TextFlow::Column( cols.right ).width( consoleWidth - 7 - optWidth ); + os << row << std::endl; + } + } + + friend auto operator<<( std::ostream &os, Parser const &parser ) -> std::ostream& { + parser.writeToStream( os ); + return os; + } + + auto validate() const -> Result override { + for( auto const &opt : m_options ) { + auto result = opt.validate(); + if( !result ) + return result; + } + for( auto const &arg : m_args ) { + auto result = arg.validate(); + if( !result ) + return result; + } + return Result::ok(); + } + + using ParserBase::parse; + + auto parse( std::string const& exeName, TokenStream const &tokens ) const -> InternalParseResult override { + + struct ParserInfo { + ParserBase const* parser = nullptr; + size_t count = 0; + }; + const size_t totalParsers = m_options.size() + m_args.size(); + assert( totalParsers < 512 ); + // ParserInfo parseInfos[totalParsers]; // <-- this is what we really want to do + ParserInfo parseInfos[512]; + + { + size_t i = 0; + for (auto const &opt : m_options) parseInfos[i++].parser = &opt; + for (auto const &arg : m_args) parseInfos[i++].parser = &arg; + } + + m_exeName.set( exeName ); + + auto result = InternalParseResult::ok( ParseState( ParseResultType::NoMatch, tokens ) ); + while( result.value().remainingTokens() ) { + bool tokenParsed = false; + + for( size_t i = 0; i < totalParsers; ++i ) { + auto& parseInfo = parseInfos[i]; + if( parseInfo.parser->cardinality() == 0 || parseInfo.count < parseInfo.parser->cardinality() ) { + result = parseInfo.parser->parse(exeName, result.value().remainingTokens()); + if (!result) + return result; + if (result.value().type() != ParseResultType::NoMatch) { + tokenParsed = true; + ++parseInfo.count; + break; + } + } + } + + if( result.value().type() == ParseResultType::ShortCircuitAll ) + return result; + if( !tokenParsed ) + return InternalParseResult::runtimeError( "Unrecognised token: " + result.value().remainingTokens()->token ); + } + // !TBD Check missing required options + return result; + } + }; + + template + template + auto ComposableParserImpl::operator|( T const &other ) const -> Parser { + return Parser() | static_cast( *this ) | other; + } +} // namespace detail + +// A Combined parser +using detail::Parser; + +// A parser for options +using detail::Opt; + +// A parser for arguments +using detail::Arg; + +// Wrapper for argc, argv from main() +using detail::Args; + +// Specifies the name of the executable +using detail::ExeName; + +// Convenience wrapper for option parser that specifies the help option +using detail::Help; + +// enum of result types from a parse +using detail::ParseResultType; + +// Result type for parser operation +using detail::ParserResult; + +}} // namespace Catch::clara + +// end clara.hpp +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +// Restore Clara's value for console width, if present +#ifdef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH +#define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH +#undef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH +#endif + +// end catch_clara.h +namespace Catch { + + clara::Parser makeCommandLineParser( ConfigData& config ); + +} // end namespace Catch + +// end catch_commandline.h +#include +#include + +namespace Catch { + + clara::Parser makeCommandLineParser( ConfigData& config ) { + + using namespace clara; + + auto const setWarning = [&]( std::string const& warning ) { + if( warning != "NoAssertions" ) + return ParserResult::runtimeError( "Unrecognised warning: '" + warning + "'" ); + config.warnings = static_cast( config.warnings | WarnAbout::NoAssertions ); + return ParserResult::ok( ParseResultType::Matched ); + }; + auto const loadTestNamesFromFile = [&]( std::string const& filename ) { + std::ifstream f( filename.c_str() ); + if( !f.is_open() ) + return ParserResult::runtimeError( "Unable to load input file: '" + filename + "'" ); + + std::string line; + while( std::getline( f, line ) ) { + line = trim(line); + if( !line.empty() && !startsWith( line, '#' ) ) { + if( !startsWith( line, '"' ) ) + line = '"' + line + '"'; + config.testsOrTags.push_back( line + ',' ); + } + } + return ParserResult::ok( ParseResultType::Matched ); + }; + auto const setTestOrder = [&]( std::string const& order ) { + if( startsWith( "declared", order ) ) + config.runOrder = RunTests::InDeclarationOrder; + else if( startsWith( "lexical", order ) ) + config.runOrder = RunTests::InLexicographicalOrder; + else if( startsWith( "random", order ) ) + config.runOrder = RunTests::InRandomOrder; + else + return clara::ParserResult::runtimeError( "Unrecognised ordering: '" + order + "'" ); + return ParserResult::ok( ParseResultType::Matched ); + }; + auto const setRngSeed = [&]( std::string const& seed ) { + if( seed != "time" ) + return clara::detail::convertInto( seed, config.rngSeed ); + config.rngSeed = static_cast( std::time(nullptr) ); + return ParserResult::ok( ParseResultType::Matched ); + }; + auto const setColourUsage = [&]( std::string const& useColour ) { + auto mode = toLower( useColour ); + + if( mode == "yes" ) + config.useColour = UseColour::Yes; + else if( mode == "no" ) + config.useColour = UseColour::No; + else if( mode == "auto" ) + config.useColour = UseColour::Auto; + else + return ParserResult::runtimeError( "colour mode must be one of: auto, yes or no. '" + useColour + "' not recognised" ); + return ParserResult::ok( ParseResultType::Matched ); + }; + auto const setWaitForKeypress = [&]( std::string const& keypress ) { + auto keypressLc = toLower( keypress ); + if( keypressLc == "start" ) + config.waitForKeypress = WaitForKeypress::BeforeStart; + else if( keypressLc == "exit" ) + config.waitForKeypress = WaitForKeypress::BeforeExit; + else if( keypressLc == "both" ) + config.waitForKeypress = WaitForKeypress::BeforeStartAndExit; + else + return ParserResult::runtimeError( "keypress argument must be one of: start, exit or both. '" + keypress + "' not recognised" ); + return ParserResult::ok( ParseResultType::Matched ); + }; + auto const setVerbosity = [&]( std::string const& verbosity ) { + auto lcVerbosity = toLower( verbosity ); + if( lcVerbosity == "quiet" ) + config.verbosity = Verbosity::Quiet; + else if( lcVerbosity == "normal" ) + config.verbosity = Verbosity::Normal; + else if( lcVerbosity == "high" ) + config.verbosity = Verbosity::High; + else + return ParserResult::runtimeError( "Unrecognised verbosity, '" + verbosity + "'" ); + return ParserResult::ok( ParseResultType::Matched ); + }; + + auto cli + = ExeName( config.processName ) + | Help( config.showHelp ) + | Opt( config.listTests ) + ["-l"]["--list-tests"] + ( "list all/matching test cases" ) + | Opt( config.listTags ) + ["-t"]["--list-tags"] + ( "list all/matching tags" ) + | Opt( config.showSuccessfulTests ) + ["-s"]["--success"] + ( "include successful tests in output" ) + | Opt( config.shouldDebugBreak ) + ["-b"]["--break"] + ( "break into debugger on failure" ) + | Opt( config.noThrow ) + ["-e"]["--nothrow"] + ( "skip exception tests" ) + | Opt( config.showInvisibles ) + ["-i"]["--invisibles"] + ( "show invisibles (tabs, newlines)" ) + | Opt( config.outputFilename, "filename" ) + ["-o"]["--out"] + ( "output filename" ) + | Opt( config.reporterNames, "name" ) + ["-r"]["--reporter"] + ( "reporter to use (defaults to console)" ) + | Opt( config.name, "name" ) + ["-n"]["--name"] + ( "suite name" ) + | Opt( [&]( bool ){ config.abortAfter = 1; } ) + ["-a"]["--abort"] + ( "abort at first failure" ) + | Opt( [&]( int x ){ config.abortAfter = x; }, "no. failures" ) + ["-x"]["--abortx"] + ( "abort after x failures" ) + | Opt( setWarning, "warning name" ) + ["-w"]["--warn"] + ( "enable warnings" ) + | Opt( [&]( bool flag ) { config.showDurations = flag ? ShowDurations::Always : ShowDurations::Never; }, "yes|no" ) + ["-d"]["--durations"] + ( "show test durations" ) + | Opt( loadTestNamesFromFile, "filename" ) + ["-f"]["--input-file"] + ( "load test names to run from a file" ) + | Opt( config.filenamesAsTags ) + ["-#"]["--filenames-as-tags"] + ( "adds a tag for the filename" ) + | Opt( config.sectionsToRun, "section name" ) + ["-c"]["--section"] + ( "specify section to run" ) + | Opt( setVerbosity, "quiet|normal|high" ) + ["-v"]["--verbosity"] + ( "set output verbosity" ) + | Opt( config.listTestNamesOnly ) + ["--list-test-names-only"] + ( "list all/matching test cases names only" ) + | Opt( config.listReporters ) + ["--list-reporters"] + ( "list all reporters" ) + | Opt( setTestOrder, "decl|lex|rand" ) + ["--order"] + ( "test case order (defaults to decl)" ) + | Opt( setRngSeed, "'time'|number" ) + ["--rng-seed"] + ( "set a specific seed for random numbers" ) + | Opt( setColourUsage, "yes|no" ) + ["--use-colour"] + ( "should output be colourised" ) + | Opt( config.libIdentify ) + ["--libidentify"] + ( "report name and version according to libidentify standard" ) + | Opt( setWaitForKeypress, "start|exit|both" ) + ["--wait-for-keypress"] + ( "waits for a keypress before exiting" ) + | Opt( config.benchmarkResolutionMultiple, "multiplier" ) + ["--benchmark-resolution-multiple"] + ( "multiple of clock resolution to run benchmarks" ) + + | Arg( config.testsOrTags, "test name|pattern|tags" ) + ( "which test or tests to use" ); + + return cli; + } + +} // end namespace Catch +// end catch_commandline.cpp +// start catch_common.cpp + +#include +#include + +namespace Catch { + + SourceLineInfo::SourceLineInfo( char const* _file, std::size_t _line ) noexcept + : file( _file ), + line( _line ) + {} + bool SourceLineInfo::empty() const noexcept { + return file[0] == '\0'; + } + bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const noexcept { + return line == other.line && (file == other.file || std::strcmp(file, other.file) == 0); + } + bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const noexcept { + return line < other.line || ( line == other.line && (std::strcmp(file, other.file) < 0)); + } + + std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) { +#ifndef __GNUG__ + os << info.file << '(' << info.line << ')'; +#else + os << info.file << ':' << info.line; +#endif + return os; + } + + bool isTrue( bool value ){ return value; } + bool alwaysTrue() { return true; } + bool alwaysFalse() { return false; } + + std::string StreamEndStop::operator+() const { + return std::string(); + } + + NonCopyable::NonCopyable() = default; + NonCopyable::~NonCopyable() = default; + +} +// end catch_common.cpp +// start catch_config.cpp + +namespace Catch { + + Config::Config( ConfigData const& data ) + : m_data( data ), + m_stream( openStream() ) + { + if( !data.testsOrTags.empty() ) { + TestSpecParser parser( ITagAliasRegistry::get() ); + for( auto const& testOrTags : data.testsOrTags ) + parser.parse( testOrTags ); + m_testSpec = parser.testSpec(); + } + } + + std::string const& Config::getFilename() const { + return m_data.outputFilename ; + } + + bool Config::listTests() const { return m_data.listTests; } + bool Config::listTestNamesOnly() const { return m_data.listTestNamesOnly; } + bool Config::listTags() const { return m_data.listTags; } + bool Config::listReporters() const { return m_data.listReporters; } + + std::string Config::getProcessName() const { return m_data.processName; } + + std::vector const& Config::getReporterNames() const { return m_data.reporterNames; } + std::vector const& Config::getSectionsToRun() const { return m_data.sectionsToRun; } + + TestSpec const& Config::testSpec() const { return m_testSpec; } + + bool Config::showHelp() const { return m_data.showHelp; } + + // IConfig interface + bool Config::allowThrows() const { return !m_data.noThrow; } + std::ostream& Config::stream() const { return m_stream->stream(); } + std::string Config::name() const { return m_data.name.empty() ? m_data.processName : m_data.name; } + bool Config::includeSuccessfulResults() const { return m_data.showSuccessfulTests; } + bool Config::warnAboutMissingAssertions() const { return m_data.warnings & WarnAbout::NoAssertions; } + ShowDurations::OrNot Config::showDurations() const { return m_data.showDurations; } + RunTests::InWhatOrder Config::runOrder() const { return m_data.runOrder; } + unsigned int Config::rngSeed() const { return m_data.rngSeed; } + int Config::benchmarkResolutionMultiple() const { return m_data.benchmarkResolutionMultiple; } + UseColour::YesOrNo Config::useColour() const { return m_data.useColour; } + bool Config::shouldDebugBreak() const { return m_data.shouldDebugBreak; } + int Config::abortAfter() const { return m_data.abortAfter; } + bool Config::showInvisibles() const { return m_data.showInvisibles; } + Verbosity Config::verbosity() const { return m_data.verbosity; } + + IStream const* Config::openStream() { + if( m_data.outputFilename.empty() ) + return new CoutStream(); + else if( m_data.outputFilename[0] == '%' ) { + if( m_data.outputFilename == "%debug" ) + return new DebugOutStream(); + else + CATCH_ERROR( "Unrecognised stream: '" << m_data.outputFilename << "'" ); + } + else + return new FileStream( m_data.outputFilename ); + } + +} // end namespace Catch +// end catch_config.cpp +// start catch_console_colour.cpp + +#if defined(__clang__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wexit-time-destructors" +#endif + +// start catch_errno_guard.h + +namespace Catch { + + class ErrnoGuard { + public: + ErrnoGuard(); + ~ErrnoGuard(); + private: + int m_oldErrno; + }; + +} + +// end catch_errno_guard.h +// start catch_windows_h_proxy.h + + +#if defined(CATCH_PLATFORM_WINDOWS) + +#if !defined(NOMINMAX) && !defined(CATCH_CONFIG_NO_NOMINMAX) +# define CATCH_DEFINED_NOMINMAX # define NOMINMAX #endif -#ifdef CATCH_DEFINES_WIN32_LEAN_AND_MEAN +#if !defined(WIN32_LEAN_AND_MEAN) && !defined(CATCH_CONFIG_NO_WIN32_LEAN_AND_MEAN) +# define CATCH_DEFINED_WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN #endif @@ -6381,1471 +5909,21 @@ namespace Catch { #include #endif -#ifdef CATCH_DEFINES_NOMINMAX +#ifdef CATCH_DEFINED_NOMINMAX # undef NOMINMAX #endif -#ifdef CATCH_DEFINES_WIN32_LEAN_AND_MEAN +#ifdef CATCH_DEFINED_WIN32_LEAN_AND_MEAN # undef WIN32_LEAN_AND_MEAN #endif +#endif // defined(CATCH_PLATFORM_WINDOWS) -# if !defined ( CATCH_CONFIG_WINDOWS_SEH ) - -namespace Catch { - struct FatalConditionHandler { - void reset() {} - }; -} - -# else // CATCH_CONFIG_WINDOWS_SEH is defined - -namespace Catch { - - struct SignalDefs { DWORD id; const char* name; }; - extern SignalDefs signalDefs[]; - // There is no 1-1 mapping between signals and windows exceptions. - // Windows can easily distinguish between SO and SigSegV, - // but SigInt, SigTerm, etc are handled differently. - SignalDefs signalDefs[] = { - { EXCEPTION_ILLEGAL_INSTRUCTION, "SIGILL - Illegal instruction signal" }, - { EXCEPTION_STACK_OVERFLOW, "SIGSEGV - Stack overflow" }, - { EXCEPTION_ACCESS_VIOLATION, "SIGSEGV - Segmentation violation signal" }, - { EXCEPTION_INT_DIVIDE_BY_ZERO, "Divide by zero error" }, - }; - - struct FatalConditionHandler { - - static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) { - for (int i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) { - if (ExceptionInfo->ExceptionRecord->ExceptionCode == signalDefs[i].id) { - reportFatal(signalDefs[i].name); - } - } - // If its not an exception we care about, pass it along. - // This stops us from eating debugger breaks etc. - return EXCEPTION_CONTINUE_SEARCH; - } - - FatalConditionHandler() { - isSet = true; - // 32k seems enough for Catch to handle stack overflow, - // but the value was found experimentally, so there is no strong guarantee - guaranteeSize = 32 * 1024; - exceptionHandlerHandle = CATCH_NULL; - // Register as first handler in current chain - exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException); - // Pass in guarantee size to be filled - SetThreadStackGuarantee(&guaranteeSize); - } - - static void reset() { - if (isSet) { - // Unregister handler and restore the old guarantee - RemoveVectoredExceptionHandler(exceptionHandlerHandle); - SetThreadStackGuarantee(&guaranteeSize); - exceptionHandlerHandle = CATCH_NULL; - isSet = false; - } - } - - ~FatalConditionHandler() { - reset(); - } - private: - static bool isSet; - static ULONG guaranteeSize; - static PVOID exceptionHandlerHandle; - }; - - bool FatalConditionHandler::isSet = false; - ULONG FatalConditionHandler::guaranteeSize = 0; - PVOID FatalConditionHandler::exceptionHandlerHandle = CATCH_NULL; - -} // namespace Catch - -# endif // CATCH_CONFIG_WINDOWS_SEH - -#else // Not Windows - assumed to be POSIX compatible ////////////////////////// - -# if !defined(CATCH_CONFIG_POSIX_SIGNALS) - -namespace Catch { - struct FatalConditionHandler { - void reset() {} - }; -} - -# else // CATCH_CONFIG_POSIX_SIGNALS is defined - -#include - -namespace Catch { - - struct SignalDefs { - int id; - const char* name; - }; - extern SignalDefs signalDefs[]; - SignalDefs signalDefs[] = { - { SIGINT, "SIGINT - Terminal interrupt signal" }, - { SIGILL, "SIGILL - Illegal instruction signal" }, - { SIGFPE, "SIGFPE - Floating point error signal" }, - { SIGSEGV, "SIGSEGV - Segmentation violation signal" }, - { SIGTERM, "SIGTERM - Termination request signal" }, - { SIGABRT, "SIGABRT - Abort (abnormal termination) signal" } - }; - - struct FatalConditionHandler { - - static bool isSet; - static struct sigaction oldSigActions [sizeof(signalDefs)/sizeof(SignalDefs)]; - static stack_t oldSigStack; - static char altStackMem[SIGSTKSZ]; - - static void handleSignal( int sig ) { - std::string name = ""; - for (std::size_t i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) { - SignalDefs &def = signalDefs[i]; - if (sig == def.id) { - name = def.name; - break; - } - } - reset(); - reportFatal(name); - raise( sig ); - } - - FatalConditionHandler() { - isSet = true; - stack_t sigStack; - sigStack.ss_sp = altStackMem; - sigStack.ss_size = SIGSTKSZ; - sigStack.ss_flags = 0; - sigaltstack(&sigStack, &oldSigStack); - struct sigaction sa = { 0 }; - - sa.sa_handler = handleSignal; - sa.sa_flags = SA_ONSTACK; - for (std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i) { - sigaction(signalDefs[i].id, &sa, &oldSigActions[i]); - } - } - - ~FatalConditionHandler() { - reset(); - } - static void reset() { - if( isSet ) { - // Set signals back to previous values -- hopefully nobody overwrote them in the meantime - for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) { - sigaction(signalDefs[i].id, &oldSigActions[i], CATCH_NULL); - } - // Return the old stack - sigaltstack(&oldSigStack, CATCH_NULL); - isSet = false; - } - } - }; - - bool FatalConditionHandler::isSet = false; - struct sigaction FatalConditionHandler::oldSigActions[sizeof(signalDefs)/sizeof(SignalDefs)] = {}; - stack_t FatalConditionHandler::oldSigStack = {}; - char FatalConditionHandler::altStackMem[SIGSTKSZ] = {}; - -} // namespace Catch - -# endif // CATCH_CONFIG_POSIX_SIGNALS - -#endif // not Windows - -#include -#include - -namespace Catch { - - class StreamRedirect { - - public: - StreamRedirect( std::ostream& stream, std::string& targetString ) - : m_stream( stream ), - m_prevBuf( stream.rdbuf() ), - m_targetString( targetString ) - { - stream.rdbuf( m_oss.rdbuf() ); - } - - ~StreamRedirect() { - m_targetString += m_oss.str(); - m_stream.rdbuf( m_prevBuf ); - } - - private: - std::ostream& m_stream; - std::streambuf* m_prevBuf; - std::ostringstream m_oss; - std::string& m_targetString; - }; - - // StdErr has two constituent streams in C++, std::cerr and std::clog - // This means that we need to redirect 2 streams into 1 to keep proper - // order of writes and cannot use StreamRedirect on its own - class StdErrRedirect { - public: - StdErrRedirect(std::string& targetString) - :m_cerrBuf( cerr().rdbuf() ), m_clogBuf(clog().rdbuf()), - m_targetString(targetString){ - cerr().rdbuf(m_oss.rdbuf()); - clog().rdbuf(m_oss.rdbuf()); - } - ~StdErrRedirect() { - m_targetString += m_oss.str(); - cerr().rdbuf(m_cerrBuf); - clog().rdbuf(m_clogBuf); - } - private: - std::streambuf* m_cerrBuf; - std::streambuf* m_clogBuf; - std::ostringstream m_oss; - std::string& m_targetString; - }; - - /////////////////////////////////////////////////////////////////////////// - - class RunContext : public IResultCapture, public IRunner { - - RunContext( RunContext const& ); - void operator =( RunContext const& ); - - public: - - explicit RunContext( Ptr const& _config, Ptr const& reporter ) - : m_runInfo( _config->name() ), - m_context( getCurrentMutableContext() ), - m_activeTestCase( CATCH_NULL ), - m_config( _config ), - m_reporter( reporter ), - m_shouldReportUnexpected ( true ) - { - m_context.setRunner( this ); - m_context.setConfig( m_config ); - m_context.setResultCapture( this ); - m_reporter->testRunStarting( m_runInfo ); - } - - virtual ~RunContext() { - m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, aborting() ) ); - } - - void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount ) { - m_reporter->testGroupStarting( GroupInfo( testSpec, groupIndex, groupsCount ) ); - } - void testGroupEnded( std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount ) { - m_reporter->testGroupEnded( TestGroupStats( GroupInfo( testSpec, groupIndex, groupsCount ), totals, aborting() ) ); - } - - Totals runTest( TestCase const& testCase ) { - Totals prevTotals = m_totals; - - std::string redirectedCout; - std::string redirectedCerr; - - TestCaseInfo testInfo = testCase.getTestCaseInfo(); - - m_reporter->testCaseStarting( testInfo ); - - m_activeTestCase = &testCase; - - do { - ITracker& rootTracker = m_trackerContext.startRun(); - assert( rootTracker.isSectionTracker() ); - static_cast( rootTracker ).addInitialFilters( m_config->getSectionsToRun() ); - do { - m_trackerContext.startCycle(); - m_testCaseTracker = &SectionTracker::acquire( m_trackerContext, TestCaseTracking::NameAndLocation( testInfo.name, testInfo.lineInfo ) ); - runCurrentTest( redirectedCout, redirectedCerr ); - } - while( !m_testCaseTracker->isSuccessfullyCompleted() && !aborting() ); - } - // !TBD: deprecated - this will be replaced by indexed trackers - while( getCurrentContext().advanceGeneratorsForCurrentTest() && !aborting() ); - - Totals deltaTotals = m_totals.delta( prevTotals ); - if( testInfo.expectedToFail() && deltaTotals.testCases.passed > 0 ) { - deltaTotals.assertions.failed++; - deltaTotals.testCases.passed--; - deltaTotals.testCases.failed++; - } - m_totals.testCases += deltaTotals.testCases; - m_reporter->testCaseEnded( TestCaseStats( testInfo, - deltaTotals, - redirectedCout, - redirectedCerr, - aborting() ) ); - - m_activeTestCase = CATCH_NULL; - m_testCaseTracker = CATCH_NULL; - - return deltaTotals; - } - - Ptr config() const { - return m_config; - } - - private: // IResultCapture - - virtual void assertionEnded( AssertionResult const& result ) { - if( result.getResultType() == ResultWas::Ok ) { - m_totals.assertions.passed++; - } - else if( !result.isOk() ) { - m_totals.assertions.failed++; - } - - // We have no use for the return value (whether messages should be cleared), because messages were made scoped - // and should be let to clear themselves out. - static_cast(m_reporter->assertionEnded(AssertionStats(result, m_messages, m_totals))); - - // Reset working state - m_lastAssertionInfo = AssertionInfo( "", m_lastAssertionInfo.lineInfo, "{Unknown expression after the reported line}" , m_lastAssertionInfo.resultDisposition ); - m_lastResult = result; - } - - virtual bool lastAssertionPassed() - { - return m_totals.assertions.passed == (m_prevPassed + 1); - } - - virtual void assertionPassed() - { - m_totals.assertions.passed++; - m_lastAssertionInfo.capturedExpression = "{Unknown expression after the reported line}"; - m_lastAssertionInfo.macroName = ""; - } - - virtual void assertionRun() - { - m_prevPassed = m_totals.assertions.passed; - } - - virtual bool sectionStarted ( - SectionInfo const& sectionInfo, - Counts& assertions - ) - { - ITracker& sectionTracker = SectionTracker::acquire( m_trackerContext, TestCaseTracking::NameAndLocation( sectionInfo.name, sectionInfo.lineInfo ) ); - if( !sectionTracker.isOpen() ) - return false; - m_activeSections.push_back( §ionTracker ); - - m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo; - - m_reporter->sectionStarting( sectionInfo ); - - assertions = m_totals.assertions; - - return true; - } - bool testForMissingAssertions( Counts& assertions ) { - if( assertions.total() != 0 ) - return false; - if( !m_config->warnAboutMissingAssertions() ) - return false; - if( m_trackerContext.currentTracker().hasChildren() ) - return false; - m_totals.assertions.failed++; - assertions.failed++; - return true; - } - - virtual void sectionEnded( SectionEndInfo const& endInfo ) { - Counts assertions = m_totals.assertions - endInfo.prevAssertions; - bool missingAssertions = testForMissingAssertions( assertions ); - - if( !m_activeSections.empty() ) { - m_activeSections.back()->close(); - m_activeSections.pop_back(); - } - - m_reporter->sectionEnded( SectionStats( endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions ) ); - m_messages.clear(); - } - - virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) { - if( m_unfinishedSections.empty() ) - m_activeSections.back()->fail(); - else - m_activeSections.back()->close(); - m_activeSections.pop_back(); - - m_unfinishedSections.push_back( endInfo ); - } - - virtual void pushScopedMessage( MessageInfo const& message ) { - m_messages.push_back( message ); - } - - virtual void popScopedMessage( MessageInfo const& message ) { - m_messages.erase( std::remove( m_messages.begin(), m_messages.end(), message ), m_messages.end() ); - } - - virtual std::string getCurrentTestName() const { - return m_activeTestCase - ? m_activeTestCase->getTestCaseInfo().name - : std::string(); - } - - virtual const AssertionResult* getLastResult() const { - return &m_lastResult; - } - - virtual void exceptionEarlyReported() { - m_shouldReportUnexpected = false; - } - - virtual void handleFatalErrorCondition( std::string const& message ) { - // Don't rebuild the result -- the stringification itself can cause more fatal errors - // Instead, fake a result data. - AssertionResultData tempResult; - tempResult.resultType = ResultWas::FatalErrorCondition; - tempResult.message = message; - AssertionResult result(m_lastAssertionInfo, tempResult); - - getResultCapture().assertionEnded(result); - - handleUnfinishedSections(); - - // Recreate section for test case (as we will lose the one that was in scope) - TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); - SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description ); - - Counts assertions; - assertions.failed = 1; - SectionStats testCaseSectionStats( testCaseSection, assertions, 0, false ); - m_reporter->sectionEnded( testCaseSectionStats ); - - TestCaseInfo testInfo = m_activeTestCase->getTestCaseInfo(); - - Totals deltaTotals; - deltaTotals.testCases.failed = 1; - deltaTotals.assertions.failed = 1; - m_reporter->testCaseEnded( TestCaseStats( testInfo, - deltaTotals, - std::string(), - std::string(), - false ) ); - m_totals.testCases.failed++; - testGroupEnded( std::string(), m_totals, 1, 1 ); - m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, false ) ); - } - - public: - // !TBD We need to do this another way! - bool aborting() const { - return m_totals.assertions.failed == static_cast( m_config->abortAfter() ); - } - - private: - - void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr ) { - TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); - SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description ); - m_reporter->sectionStarting( testCaseSection ); - Counts prevAssertions = m_totals.assertions; - double duration = 0; - m_shouldReportUnexpected = true; - try { - m_lastAssertionInfo = AssertionInfo( "TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal ); - - seedRng( *m_config ); - - Timer timer; - timer.start(); - if( m_reporter->getPreferences().shouldRedirectStdOut ) { - StreamRedirect coutRedir( Catch::cout(), redirectedCout ); - StdErrRedirect errRedir( redirectedCerr ); - invokeActiveTestCase(); - } - else { - invokeActiveTestCase(); - } - duration = timer.getElapsedSeconds(); - } - catch( TestFailureException& ) { - // This just means the test was aborted due to failure - } - catch(...) { - // Under CATCH_CONFIG_FAST_COMPILE, unexpected exceptions under REQUIRE assertions - // are reported without translation at the point of origin. - if (m_shouldReportUnexpected) { - makeUnexpectedResultBuilder().useActiveException(); - } - } - m_testCaseTracker->close(); - handleUnfinishedSections(); - m_messages.clear(); - - Counts assertions = m_totals.assertions - prevAssertions; - bool missingAssertions = testForMissingAssertions( assertions ); - - if( testCaseInfo.okToFail() ) { - std::swap( assertions.failedButOk, assertions.failed ); - m_totals.assertions.failed -= assertions.failedButOk; - m_totals.assertions.failedButOk += assertions.failedButOk; - } - - SectionStats testCaseSectionStats( testCaseSection, assertions, duration, missingAssertions ); - m_reporter->sectionEnded( testCaseSectionStats ); - } - - void invokeActiveTestCase() { - FatalConditionHandler fatalConditionHandler; // Handle signals - m_activeTestCase->invoke(); - fatalConditionHandler.reset(); - } - - private: - - ResultBuilder makeUnexpectedResultBuilder() const { - return ResultBuilder( m_lastAssertionInfo.macroName, - m_lastAssertionInfo.lineInfo, - m_lastAssertionInfo.capturedExpression, - m_lastAssertionInfo.resultDisposition ); - } - - void handleUnfinishedSections() { - // If sections ended prematurely due to an exception we stored their - // infos here so we can tear them down outside the unwind process. - for( std::vector::const_reverse_iterator it = m_unfinishedSections.rbegin(), - itEnd = m_unfinishedSections.rend(); - it != itEnd; - ++it ) - sectionEnded( *it ); - m_unfinishedSections.clear(); - } - - TestRunInfo m_runInfo; - IMutableContext& m_context; - TestCase const* m_activeTestCase; - ITracker* m_testCaseTracker; - ITracker* m_currentSectionTracker; - AssertionResult m_lastResult; - - Ptr m_config; - Totals m_totals; - Ptr m_reporter; - std::vector m_messages; - AssertionInfo m_lastAssertionInfo; - std::vector m_unfinishedSections; - std::vector m_activeSections; - TrackerContext m_trackerContext; - size_t m_prevPassed; - bool m_shouldReportUnexpected; - }; - - IResultCapture& getResultCapture() { - if( IResultCapture* capture = getCurrentContext().getResultCapture() ) - return *capture; - else - throw std::logic_error( "No result capture instance" ); - } - -} // end namespace Catch - -// #included from: internal/catch_version.h -#define TWOBLUECUBES_CATCH_VERSION_H_INCLUDED - -namespace Catch { - - // Versioning information - struct Version { - Version( unsigned int _majorVersion, - unsigned int _minorVersion, - unsigned int _patchNumber, - char const * const _branchName, - unsigned int _buildNumber ); - - unsigned int const majorVersion; - unsigned int const minorVersion; - unsigned int const patchNumber; - - // buildNumber is only used if branchName is not null - char const * const branchName; - unsigned int const buildNumber; - - friend std::ostream& operator << ( std::ostream& os, Version const& version ); - - private: - void operator=( Version const& ); - }; - - inline Version libraryVersion(); -} - -#include -#include -#include - -namespace Catch { - - Ptr createReporter( std::string const& reporterName, Ptr const& config ) { - Ptr reporter = getRegistryHub().getReporterRegistry().create( reporterName, config.get() ); - if( !reporter ) { - std::ostringstream oss; - oss << "No reporter registered with name: '" << reporterName << "'"; - throw std::domain_error( oss.str() ); - } - return reporter; - } - -#if !defined(CATCH_CONFIG_DEFAULT_REPORTER) -#define CATCH_CONFIG_DEFAULT_REPORTER "console" -#endif - - Ptr makeReporter( Ptr const& config ) { - std::vector reporters = config->getReporterNames(); - if( reporters.empty() ) - reporters.push_back( CATCH_CONFIG_DEFAULT_REPORTER ); - - Ptr reporter; - for( std::vector::const_iterator it = reporters.begin(), itEnd = reporters.end(); - it != itEnd; - ++it ) - reporter = addReporter( reporter, createReporter( *it, config ) ); - return reporter; - } - Ptr addListeners( Ptr const& config, Ptr reporters ) { - IReporterRegistry::Listeners listeners = getRegistryHub().getReporterRegistry().getListeners(); - for( IReporterRegistry::Listeners::const_iterator it = listeners.begin(), itEnd = listeners.end(); - it != itEnd; - ++it ) - reporters = addReporter(reporters, (*it)->create( ReporterConfig( config ) ) ); - return reporters; - } - - Totals runTests( Ptr const& config ) { - - Ptr iconfig = config.get(); - - Ptr reporter = makeReporter( config ); - reporter = addListeners( iconfig, reporter ); - - RunContext context( iconfig, reporter ); - - Totals totals; - - context.testGroupStarting( config->name(), 1, 1 ); - - TestSpec testSpec = config->testSpec(); - if( !testSpec.hasFilters() ) - testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "~[.]" ).testSpec(); // All not hidden tests - - std::vector const& allTestCases = getAllTestCasesSorted( *iconfig ); - for( std::vector::const_iterator it = allTestCases.begin(), itEnd = allTestCases.end(); - it != itEnd; - ++it ) { - if( !context.aborting() && matchTest( *it, testSpec, *iconfig ) ) - totals += context.runTest( *it ); - else - reporter->skipTest( *it ); - } - - context.testGroupEnded( iconfig->name(), totals, 1, 1 ); - return totals; - } - - void applyFilenamesAsTags( IConfig const& config ) { - std::vector const& tests = getAllTestCasesSorted( config ); - for(std::size_t i = 0; i < tests.size(); ++i ) { - TestCase& test = const_cast( tests[i] ); - std::set tags = test.tags; - - std::string filename = test.lineInfo.file; - std::string::size_type lastSlash = filename.find_last_of( "\\/" ); - if( lastSlash != std::string::npos ) - filename = filename.substr( lastSlash+1 ); - - std::string::size_type lastDot = filename.find_last_of( '.' ); - if( lastDot != std::string::npos ) - filename = filename.substr( 0, lastDot ); - - tags.insert( '#' + filename ); - setTags( test, tags ); - } - } - - class Session : NonCopyable { - static bool alreadyInstantiated; - - public: - - struct OnUnusedOptions { enum DoWhat { Ignore, Fail }; }; - - Session() - : m_cli( makeCommandLineParser() ) { - if( alreadyInstantiated ) { - std::string msg = "Only one instance of Catch::Session can ever be used"; - Catch::cerr() << msg << std::endl; - throw std::logic_error( msg ); - } - alreadyInstantiated = true; - } - ~Session() { - Catch::cleanUp(); - } - - void showHelp( std::string const& processName ) { - Catch::cout() << "\nCatch v" << libraryVersion() << "\n"; - - m_cli.usage( Catch::cout(), processName ); - Catch::cout() << "For more detail usage please see the project docs\n" << std::endl; - } - - int applyCommandLine( int argc, char const* const* const argv, OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) { - try { - m_cli.setThrowOnUnrecognisedTokens( unusedOptionBehaviour == OnUnusedOptions::Fail ); - m_unusedTokens = m_cli.parseInto( Clara::argsToVector( argc, argv ), m_configData ); - if( m_configData.showHelp ) - showHelp( m_configData.processName ); - m_config.reset(); - } - catch( std::exception& ex ) { - { - Colour colourGuard( Colour::Red ); - Catch::cerr() - << "\nError(s) in input:\n" - << Text( ex.what(), TextAttributes().setIndent(2) ) - << "\n\n"; - } - m_cli.usage( Catch::cout(), m_configData.processName ); - return (std::numeric_limits::max)(); - } - return 0; - } - - void useConfigData( ConfigData const& _configData ) { - m_configData = _configData; - m_config.reset(); - } - - int run( int argc, char const* const* const argv ) { - - int returnCode = applyCommandLine( argc, argv ); - if( returnCode == 0 ) - returnCode = run(); - return returnCode; - } - - #if defined(WIN32) && defined(UNICODE) - int run( int argc, wchar_t const* const* const argv ) { - - char **utf8Argv = new char *[ argc ]; - - for ( int i = 0; i < argc; ++i ) { - int bufSize = WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, NULL, 0, NULL, NULL ); - - utf8Argv[ i ] = new char[ bufSize ]; - - WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, NULL, NULL ); - } - - int returnCode = applyCommandLine( argc, utf8Argv ); - if( returnCode == 0 ) - returnCode = run(); - - for ( int i = 0; i < argc; ++i ) - delete [] utf8Argv[ i ]; - - delete [] utf8Argv; - - return returnCode; - } - #endif - - int run() { - if( m_configData.showHelp ) - return 0; - - try - { - config(); // Force config to be constructed - - seedRng( *m_config ); - - if( m_configData.filenamesAsTags ) - applyFilenamesAsTags( *m_config ); - - // Handle list request - if( Option listed = list( config() ) ) - return static_cast( *listed ); - - return static_cast( runTests( m_config ).assertions.failed ); - } - catch( std::exception& ex ) { - Catch::cerr() << ex.what() << std::endl; - return (std::numeric_limits::max)(); - } - } - - Clara::CommandLine const& cli() const { - return m_cli; - } - std::vector const& unusedTokens() const { - return m_unusedTokens; - } - ConfigData& configData() { - return m_configData; - } - Config& config() { - if( !m_config ) - m_config = new Config( m_configData ); - return *m_config; - } - private: - Clara::CommandLine m_cli; - std::vector m_unusedTokens; - ConfigData m_configData; - Ptr m_config; - }; - - bool Session::alreadyInstantiated = false; - -} // end namespace Catch - -// #included from: catch_registry_hub.hpp -#define TWOBLUECUBES_CATCH_REGISTRY_HUB_HPP_INCLUDED - -// #included from: catch_test_case_registry_impl.hpp -#define TWOBLUECUBES_CATCH_TEST_CASE_REGISTRY_IMPL_HPP_INCLUDED - -#include -#include -#include -#include - -namespace Catch { - - struct RandomNumberGenerator { - typedef std::ptrdiff_t result_type; - - result_type operator()( result_type n ) const { return std::rand() % n; } - -#ifdef CATCH_CONFIG_CPP11_SHUFFLE - static constexpr result_type min() { return 0; } - static constexpr result_type max() { return 1000000; } - result_type operator()() const { return std::rand() % max(); } -#endif - template - static void shuffle( V& vector ) { - RandomNumberGenerator rng; -#ifdef CATCH_CONFIG_CPP11_SHUFFLE - std::shuffle( vector.begin(), vector.end(), rng ); -#else - std::random_shuffle( vector.begin(), vector.end(), rng ); -#endif - } - }; - - inline std::vector sortTests( IConfig const& config, std::vector const& unsortedTestCases ) { - - std::vector sorted = unsortedTestCases; - - switch( config.runOrder() ) { - case RunTests::InLexicographicalOrder: - std::sort( sorted.begin(), sorted.end() ); - break; - case RunTests::InRandomOrder: - { - seedRng( config ); - RandomNumberGenerator::shuffle( sorted ); - } - break; - case RunTests::InDeclarationOrder: - // already in declaration order - break; - } - return sorted; - } - bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ) { - return testSpec.matches( testCase ) && ( config.allowThrows() || !testCase.throws() ); - } - - void enforceNoDuplicateTestCases( std::vector const& functions ) { - std::set seenFunctions; - for( std::vector::const_iterator it = functions.begin(), itEnd = functions.end(); - it != itEnd; - ++it ) { - std::pair::const_iterator, bool> prev = seenFunctions.insert( *it ); - if( !prev.second ) { - std::ostringstream ss; - - ss << Colour( Colour::Red ) - << "error: TEST_CASE( \"" << it->name << "\" ) already defined.\n" - << "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << '\n' - << "\tRedefined at " << it->getTestCaseInfo().lineInfo << std::endl; - - throw std::runtime_error(ss.str()); - } - } - } - - std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ) { - std::vector filtered; - filtered.reserve( testCases.size() ); - for( std::vector::const_iterator it = testCases.begin(), itEnd = testCases.end(); - it != itEnd; - ++it ) - if( matchTest( *it, testSpec, config ) ) - filtered.push_back( *it ); - return filtered; - } - std::vector const& getAllTestCasesSorted( IConfig const& config ) { - return getRegistryHub().getTestCaseRegistry().getAllTestsSorted( config ); - } - - class TestRegistry : public ITestCaseRegistry { - public: - TestRegistry() - : m_currentSortOrder( RunTests::InDeclarationOrder ), - m_unnamedCount( 0 ) - {} - virtual ~TestRegistry(); - - virtual void registerTest( TestCase const& testCase ) { - std::string name = testCase.getTestCaseInfo().name; - if( name.empty() ) { - std::ostringstream oss; - oss << "Anonymous test case " << ++m_unnamedCount; - return registerTest( testCase.withName( oss.str() ) ); - } - m_functions.push_back( testCase ); - } - - virtual std::vector const& getAllTests() const { - return m_functions; - } - virtual std::vector const& getAllTestsSorted( IConfig const& config ) const { - if( m_sortedFunctions.empty() ) - enforceNoDuplicateTestCases( m_functions ); - - if( m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty() ) { - m_sortedFunctions = sortTests( config, m_functions ); - m_currentSortOrder = config.runOrder(); - } - return m_sortedFunctions; - } - - private: - std::vector m_functions; - mutable RunTests::InWhatOrder m_currentSortOrder; - mutable std::vector m_sortedFunctions; - size_t m_unnamedCount; - std::ios_base::Init m_ostreamInit; // Forces cout/ cerr to be initialised - }; - - /////////////////////////////////////////////////////////////////////////// - - class FreeFunctionTestCase : public SharedImpl { - public: - - FreeFunctionTestCase( TestFunction fun ) : m_fun( fun ) {} - - virtual void invoke() const { - m_fun(); - } - - private: - virtual ~FreeFunctionTestCase(); - - TestFunction m_fun; - }; - - inline std::string extractClassName( std::string const& classOrQualifiedMethodName ) { - std::string className = classOrQualifiedMethodName; - if( startsWith( className, '&' ) ) - { - std::size_t lastColons = className.rfind( "::" ); - std::size_t penultimateColons = className.rfind( "::", lastColons-1 ); - if( penultimateColons == std::string::npos ) - penultimateColons = 1; - className = className.substr( penultimateColons, lastColons-penultimateColons ); - } - return className; - } - - void registerTestCase - ( ITestCase* testCase, - char const* classOrQualifiedMethodName, - NameAndDesc const& nameAndDesc, - SourceLineInfo const& lineInfo ) { - - getMutableRegistryHub().registerTest - ( makeTestCase - ( testCase, - extractClassName( classOrQualifiedMethodName ), - nameAndDesc.name, - nameAndDesc.description, - lineInfo ) ); - } - void registerTestCaseFunction - ( TestFunction function, - SourceLineInfo const& lineInfo, - NameAndDesc const& nameAndDesc ) { - registerTestCase( new FreeFunctionTestCase( function ), "", nameAndDesc, lineInfo ); - } - - /////////////////////////////////////////////////////////////////////////// - - AutoReg::AutoReg - ( TestFunction function, - SourceLineInfo const& lineInfo, - NameAndDesc const& nameAndDesc ) { - registerTestCaseFunction( function, lineInfo, nameAndDesc ); - } - - AutoReg::~AutoReg() {} - -} // end namespace Catch - -// #included from: catch_reporter_registry.hpp -#define TWOBLUECUBES_CATCH_REPORTER_REGISTRY_HPP_INCLUDED - -#include - -namespace Catch { - - class ReporterRegistry : public IReporterRegistry { - - public: - - virtual ~ReporterRegistry() CATCH_OVERRIDE {} - - virtual IStreamingReporter* create( std::string const& name, Ptr const& config ) const CATCH_OVERRIDE { - FactoryMap::const_iterator it = m_factories.find( name ); - if( it == m_factories.end() ) - return CATCH_NULL; - return it->second->create( ReporterConfig( config ) ); - } - - void registerReporter( std::string const& name, Ptr const& factory ) { - m_factories.insert( std::make_pair( name, factory ) ); - } - void registerListener( Ptr const& factory ) { - m_listeners.push_back( factory ); - } - - virtual FactoryMap const& getFactories() const CATCH_OVERRIDE { - return m_factories; - } - virtual Listeners const& getListeners() const CATCH_OVERRIDE { - return m_listeners; - } - - private: - FactoryMap m_factories; - Listeners m_listeners; - }; -} - -// #included from: catch_exception_translator_registry.hpp -#define TWOBLUECUBES_CATCH_EXCEPTION_TRANSLATOR_REGISTRY_HPP_INCLUDED - -#ifdef __OBJC__ -#import "Foundation/Foundation.h" -#endif - -namespace Catch { - - class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry { - public: - ~ExceptionTranslatorRegistry() { - deleteAll( m_translators ); - } - - virtual void registerTranslator( const IExceptionTranslator* translator ) { - m_translators.push_back( translator ); - } - - virtual std::string translateActiveException() const { - try { -#ifdef __OBJC__ - // In Objective-C try objective-c exceptions first - @try { - return tryTranslators(); - } - @catch (NSException *exception) { - return Catch::toString( [exception description] ); - } -#else - return tryTranslators(); -#endif - } - catch( TestFailureException& ) { - throw; - } - catch( std::exception& ex ) { - return ex.what(); - } - catch( std::string& msg ) { - return msg; - } - catch( const char* msg ) { - return msg; - } - catch(...) { - return "Unknown exception"; - } - } - - std::string tryTranslators() const { - if( m_translators.empty() ) - throw; - else - return m_translators[0]->translate( m_translators.begin()+1, m_translators.end() ); - } - - private: - std::vector m_translators; - }; -} - -// #included from: catch_tag_alias_registry.h -#define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_H_INCLUDED - -#include - -namespace Catch { - - class TagAliasRegistry : public ITagAliasRegistry { - public: - virtual ~TagAliasRegistry(); - virtual Option find( std::string const& alias ) const; - virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const; - void add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ); - - private: - std::map m_registry; - }; - -} // end namespace Catch - -namespace Catch { - - namespace { - - class RegistryHub : public IRegistryHub, public IMutableRegistryHub { - - RegistryHub( RegistryHub const& ); - void operator=( RegistryHub const& ); - - public: // IRegistryHub - RegistryHub() { - } - virtual IReporterRegistry const& getReporterRegistry() const CATCH_OVERRIDE { - return m_reporterRegistry; - } - virtual ITestCaseRegistry const& getTestCaseRegistry() const CATCH_OVERRIDE { - return m_testCaseRegistry; - } - virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() CATCH_OVERRIDE { - return m_exceptionTranslatorRegistry; - } - virtual ITagAliasRegistry const& getTagAliasRegistry() const CATCH_OVERRIDE { - return m_tagAliasRegistry; - } - - public: // IMutableRegistryHub - virtual void registerReporter( std::string const& name, Ptr const& factory ) CATCH_OVERRIDE { - m_reporterRegistry.registerReporter( name, factory ); - } - virtual void registerListener( Ptr const& factory ) CATCH_OVERRIDE { - m_reporterRegistry.registerListener( factory ); - } - virtual void registerTest( TestCase const& testInfo ) CATCH_OVERRIDE { - m_testCaseRegistry.registerTest( testInfo ); - } - virtual void registerTranslator( const IExceptionTranslator* translator ) CATCH_OVERRIDE { - m_exceptionTranslatorRegistry.registerTranslator( translator ); - } - virtual void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) CATCH_OVERRIDE { - m_tagAliasRegistry.add( alias, tag, lineInfo ); - } - - private: - TestRegistry m_testCaseRegistry; - ReporterRegistry m_reporterRegistry; - ExceptionTranslatorRegistry m_exceptionTranslatorRegistry; - TagAliasRegistry m_tagAliasRegistry; - }; - - // Single, global, instance - inline RegistryHub*& getTheRegistryHub() { - static RegistryHub* theRegistryHub = CATCH_NULL; - if( !theRegistryHub ) - theRegistryHub = new RegistryHub(); - return theRegistryHub; - } - } - - IRegistryHub& getRegistryHub() { - return *getTheRegistryHub(); - } - IMutableRegistryHub& getMutableRegistryHub() { - return *getTheRegistryHub(); - } - void cleanUp() { - delete getTheRegistryHub(); - getTheRegistryHub() = CATCH_NULL; - cleanUpContext(); - } - std::string translateActiveException() { - return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException(); - } - -} // end namespace Catch - -// #included from: catch_notimplemented_exception.hpp -#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_HPP_INCLUDED - -#include - -namespace Catch { - - NotImplementedException::NotImplementedException( SourceLineInfo const& lineInfo ) - : m_lineInfo( lineInfo ) { - std::ostringstream oss; - oss << lineInfo << ": function "; - oss << "not implemented"; - m_what = oss.str(); - } - - const char* NotImplementedException::what() const CATCH_NOEXCEPT { - return m_what.c_str(); - } - -} // end namespace Catch - -// #included from: catch_context_impl.hpp -#define TWOBLUECUBES_CATCH_CONTEXT_IMPL_HPP_INCLUDED - -// #included from: catch_stream.hpp -#define TWOBLUECUBES_CATCH_STREAM_HPP_INCLUDED - -#include -#include -#include - -namespace Catch { - - template - class StreamBufImpl : public StreamBufBase { - char data[bufferSize]; - WriterF m_writer; - - public: - StreamBufImpl() { - setp( data, data + sizeof(data) ); - } - - ~StreamBufImpl() CATCH_NOEXCEPT { - sync(); - } - - private: - int overflow( int c ) { - sync(); - - if( c != EOF ) { - if( pbase() == epptr() ) - m_writer( std::string( 1, static_cast( c ) ) ); - else - sputc( static_cast( c ) ); - } - return 0; - } - - int sync() { - if( pbase() != pptr() ) { - m_writer( std::string( pbase(), static_cast( pptr() - pbase() ) ) ); - setp( pbase(), epptr() ); - } - return 0; - } - }; - - /////////////////////////////////////////////////////////////////////////// - - FileStream::FileStream( std::string const& filename ) { - m_ofs.open( filename.c_str() ); - if( m_ofs.fail() ) { - std::ostringstream oss; - oss << "Unable to open file: '" << filename << '\''; - throw std::domain_error( oss.str() ); - } - } - - std::ostream& FileStream::stream() const { - return m_ofs; - } - - struct OutputDebugWriter { - - void operator()( std::string const&str ) { - writeToDebugConsole( str ); - } - }; - - DebugOutStream::DebugOutStream() - : m_streamBuf( new StreamBufImpl() ), - m_os( m_streamBuf.get() ) - {} - - std::ostream& DebugOutStream::stream() const { - return m_os; - } - - // Store the streambuf from cout up-front because - // cout may get redirected when running tests - CoutStream::CoutStream() - : m_os( Catch::cout().rdbuf() ) - {} - - std::ostream& CoutStream::stream() const { - return m_os; - } - -#ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement these functions - std::ostream& cout() { - return std::cout; - } - std::ostream& cerr() { - return std::cerr; - } - std::ostream& clog() { - return std::clog; - } -#endif -} - -namespace Catch { - - class Context : public IMutableContext { - - Context() : m_config( CATCH_NULL ), m_runner( CATCH_NULL ), m_resultCapture( CATCH_NULL ) {} - Context( Context const& ); - void operator=( Context const& ); - - public: - virtual ~Context() { - deleteAllValues( m_generatorsByTestName ); - } - - public: // IContext - virtual IResultCapture* getResultCapture() { - return m_resultCapture; - } - virtual IRunner* getRunner() { - return m_runner; - } - virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) { - return getGeneratorsForCurrentTest() - .getGeneratorInfo( fileInfo, totalSize ) - .getCurrentIndex(); - } - virtual bool advanceGeneratorsForCurrentTest() { - IGeneratorsForTest* generators = findGeneratorsForCurrentTest(); - return generators && generators->moveNext(); - } - - virtual Ptr getConfig() const { - return m_config; - } - - public: // IMutableContext - virtual void setResultCapture( IResultCapture* resultCapture ) { - m_resultCapture = resultCapture; - } - virtual void setRunner( IRunner* runner ) { - m_runner = runner; - } - virtual void setConfig( Ptr const& config ) { - m_config = config; - } - - friend IMutableContext& getCurrentMutableContext(); - - private: - IGeneratorsForTest* findGeneratorsForCurrentTest() { - std::string testName = getResultCapture()->getCurrentTestName(); - - std::map::const_iterator it = - m_generatorsByTestName.find( testName ); - return it != m_generatorsByTestName.end() - ? it->second - : CATCH_NULL; - } - - IGeneratorsForTest& getGeneratorsForCurrentTest() { - IGeneratorsForTest* generators = findGeneratorsForCurrentTest(); - if( !generators ) { - std::string testName = getResultCapture()->getCurrentTestName(); - generators = createGeneratorsForTest(); - m_generatorsByTestName.insert( std::make_pair( testName, generators ) ); - } - return *generators; - } - - private: - Ptr m_config; - IRunner* m_runner; - IResultCapture* m_resultCapture; - std::map m_generatorsByTestName; - }; - - namespace { - Context* currentContext = CATCH_NULL; - } - IMutableContext& getCurrentMutableContext() { - if( !currentContext ) - currentContext = new Context(); - return *currentContext; - } - IContext& getCurrentContext() { - return getCurrentMutableContext(); - } - - void cleanUpContext() { - delete currentContext; - currentContext = CATCH_NULL; - } -} - -// #included from: catch_console_colour_impl.hpp -#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_IMPL_HPP_INCLUDED - -// #included from: catch_errno_guard.hpp -#define TWOBLUECUBES_CATCH_ERRNO_GUARD_HPP_INCLUDED - -#include - -namespace Catch { - - class ErrnoGuard { - public: - ErrnoGuard():m_oldErrno(errno){} - ~ErrnoGuard() { errno = m_oldErrno; } - private: - int m_oldErrno; - }; - -} - +// end catch_windows_h_proxy.h namespace Catch { namespace { struct IColourImpl { - virtual ~IColourImpl() {} + virtual ~IColourImpl() = default; virtual void use( Colour::Code _colourCode ) = 0; }; @@ -7884,7 +5962,7 @@ namespace { originalBackgroundAttributes = csbiInfo.wAttributes & ~( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY ); } - virtual void use( Colour::Code _colourCode ) { + virtual void use( Colour::Code _colourCode ) override { switch( _colourCode ) { case Colour::None: return setTextAttribute( originalForegroundAttributes ); case Colour::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); @@ -7900,7 +5978,7 @@ namespace { case Colour::BrightGreen: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN ); case Colour::BrightWhite: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); - case Colour::Bright: throw std::logic_error( "not a colour" ); + case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" ); } } @@ -7916,14 +5994,12 @@ namespace { IColourImpl* platformColourInstance() { static Win32ColourImpl s_instance; - Ptr config = getCurrentContext().getConfig(); + IConfigPtr config = getCurrentContext().getConfig(); UseColour::YesOrNo colourMode = config ? config->useColour() : UseColour::Auto; if( colourMode == UseColour::Auto ) - colourMode = !isDebuggerActive() - ? UseColour::Yes - : UseColour::No; + colourMode = UseColour::Yes; return colourMode == UseColour::Yes ? &s_instance : NoColourImpl::instance(); @@ -7945,7 +6021,7 @@ namespace { // https://github.com/philsquared/Catch/pull/131 class PosixColourImpl : public IColourImpl { public: - virtual void use( Colour::Code _colourCode ) { + virtual void use( Colour::Code _colourCode ) override { switch( _colourCode ) { case Colour::None: case Colour::White: return setColour( "[0m" ); @@ -7961,7 +6037,7 @@ namespace { case Colour::BrightGreen: return setColour( "[1;32m" ); case Colour::BrightWhite: return setColour( "[1;37m" ); - case Colour::Bright: throw std::logic_error( "not a colour" ); + case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" ); } } static IColourImpl* instance() { @@ -7975,14 +6051,21 @@ namespace { } }; + bool useColourOnPlatform() { + return +#ifdef CATCH_PLATFORM_MAC + !isDebuggerActive() && +#endif + isatty(STDOUT_FILENO); + } IColourImpl* platformColourInstance() { ErrnoGuard guard; - Ptr config = getCurrentContext().getConfig(); + IConfigPtr config = getCurrentContext().getConfig(); UseColour::YesOrNo colourMode = config ? config->useColour() : UseColour::Auto; if( colourMode == UseColour::Auto ) - colourMode = (!isDebuggerActive() && isatty(STDOUT_FILENO) ) + colourMode = useColourOnPlatform() ? UseColour::Yes : UseColour::No; return colourMode == UseColour::Yes @@ -8005,8 +6088,17 @@ namespace Catch { namespace Catch { - Colour::Colour( Code _colourCode ) : m_moved( false ) { use( _colourCode ); } - Colour::Colour( Colour const& _other ) : m_moved( false ) { const_cast( _other ).m_moved = true; } + Colour::Colour( Code _colourCode ) { use( _colourCode ); } + Colour::Colour( Colour&& rhs ) noexcept { + m_moved = rhs.m_moved; + rhs.m_moved = true; + } + Colour& Colour::operator=( Colour&& rhs ) noexcept { + m_moved = rhs.m_moved; + rhs.m_moved = true; + return *this; + } + Colour::~Colour(){ if( !m_moved ) use( None ); } void Colour::use( Code _colourCode ) { @@ -8014,776 +6106,105 @@ namespace Catch { impl->use( _colourCode ); } -} // end namespace Catch - -// #included from: catch_generators_impl.hpp -#define TWOBLUECUBES_CATCH_GENERATORS_IMPL_HPP_INCLUDED - -#include -#include -#include - -namespace Catch { - - struct GeneratorInfo : IGeneratorInfo { - - GeneratorInfo( std::size_t size ) - : m_size( size ), - m_currentIndex( 0 ) - {} - - bool moveNext() { - if( ++m_currentIndex == m_size ) { - m_currentIndex = 0; - return false; - } - return true; - } - - std::size_t getCurrentIndex() const { - return m_currentIndex; - } - - std::size_t m_size; - std::size_t m_currentIndex; - }; - - /////////////////////////////////////////////////////////////////////////// - - class GeneratorsForTest : public IGeneratorsForTest { - - public: - ~GeneratorsForTest() { - deleteAll( m_generatorsInOrder ); - } - - IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) { - std::map::const_iterator it = m_generatorsByName.find( fileInfo ); - if( it == m_generatorsByName.end() ) { - IGeneratorInfo* info = new GeneratorInfo( size ); - m_generatorsByName.insert( std::make_pair( fileInfo, info ) ); - m_generatorsInOrder.push_back( info ); - return *info; - } - return *it->second; - } - - bool moveNext() { - std::vector::const_iterator it = m_generatorsInOrder.begin(); - std::vector::const_iterator itEnd = m_generatorsInOrder.end(); - for(; it != itEnd; ++it ) { - if( (*it)->moveNext() ) - return true; - } - return false; - } - - private: - std::map m_generatorsByName; - std::vector m_generatorsInOrder; - }; - - IGeneratorsForTest* createGeneratorsForTest() - { - return new GeneratorsForTest(); - } - -} // end namespace Catch - -// #included from: catch_assertionresult.hpp -#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_HPP_INCLUDED - -namespace Catch { - - AssertionInfo::AssertionInfo():macroName(""), capturedExpression(""), resultDisposition(ResultDisposition::Normal), secondArg(""){} - - AssertionInfo::AssertionInfo( char const * _macroName, - SourceLineInfo const& _lineInfo, - char const * _capturedExpression, - ResultDisposition::Flags _resultDisposition, - char const * _secondArg) - : macroName( _macroName ), - lineInfo( _lineInfo ), - capturedExpression( _capturedExpression ), - resultDisposition( _resultDisposition ), - secondArg( _secondArg ) - {} - - AssertionResult::AssertionResult() {} - - AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data ) - : m_info( info ), - m_resultData( data ) - {} - - AssertionResult::~AssertionResult() {} - - // Result was a success - bool AssertionResult::succeeded() const { - return Catch::isOk( m_resultData.resultType ); - } - - // Result was a success, or failure is suppressed - bool AssertionResult::isOk() const { - return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition ); - } - - ResultWas::OfType AssertionResult::getResultType() const { - return m_resultData.resultType; - } - - bool AssertionResult::hasExpression() const { - return m_info.capturedExpression[0] != 0; - } - - bool AssertionResult::hasMessage() const { - return !m_resultData.message.empty(); - } - - std::string capturedExpressionWithSecondArgument( char const * capturedExpression, char const * secondArg ) { - return (secondArg[0] == 0 || secondArg[0] == '"' && secondArg[1] == '"') - ? capturedExpression - : std::string(capturedExpression) + ", " + secondArg; - } - - std::string AssertionResult::getExpression() const { - if( isFalseTest( m_info.resultDisposition ) ) - return '!' + capturedExpressionWithSecondArgument(m_info.capturedExpression, m_info.secondArg); - else - return capturedExpressionWithSecondArgument(m_info.capturedExpression, m_info.secondArg); - } - std::string AssertionResult::getExpressionInMacro() const { - if( m_info.macroName[0] == 0 ) - return capturedExpressionWithSecondArgument(m_info.capturedExpression, m_info.secondArg); - else - return std::string(m_info.macroName) + "( " + capturedExpressionWithSecondArgument(m_info.capturedExpression, m_info.secondArg) + " )"; - } - - bool AssertionResult::hasExpandedExpression() const { - return hasExpression() && getExpandedExpression() != getExpression(); - } - - std::string AssertionResult::getExpandedExpression() const { - return m_resultData.reconstructExpression(); - } - - std::string AssertionResult::getMessage() const { - return m_resultData.message; - } - SourceLineInfo AssertionResult::getSourceInfo() const { - return m_info.lineInfo; - } - - std::string AssertionResult::getTestMacroName() const { - return m_info.macroName; - } - - void AssertionResult::discardDecomposedExpression() const { - m_resultData.decomposedExpression = CATCH_NULL; - } - - void AssertionResult::expandDecomposedExpression() const { - m_resultData.reconstructExpression(); - } - -} // end namespace Catch - -// #included from: catch_test_case_info.hpp -#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_HPP_INCLUDED - -#include - -namespace Catch { - - inline TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) { - if( startsWith( tag, '.' ) || - tag == "hide" || - tag == "!hide" ) - return TestCaseInfo::IsHidden; - else if( tag == "!throws" ) - return TestCaseInfo::Throws; - else if( tag == "!shouldfail" ) - return TestCaseInfo::ShouldFail; - else if( tag == "!mayfail" ) - return TestCaseInfo::MayFail; - else if( tag == "!nonportable" ) - return TestCaseInfo::NonPortable; - else - return TestCaseInfo::None; - } - inline bool isReservedTag( std::string const& tag ) { - return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !std::isalnum( tag[0] ); - } - inline void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) { - if( isReservedTag( tag ) ) { - std::ostringstream ss; - ss << Colour(Colour::Red) - << "Tag name [" << tag << "] not allowed.\n" - << "Tag names starting with non alpha-numeric characters are reserved\n" - << Colour(Colour::FileName) - << _lineInfo << '\n'; - throw std::runtime_error(ss.str()); - } - } - - TestCase makeTestCase( ITestCase* _testCase, - std::string const& _className, - std::string const& _name, - std::string const& _descOrTags, - SourceLineInfo const& _lineInfo ) - { - bool isHidden( startsWith( _name, "./" ) ); // Legacy support - - // Parse out tags - std::set tags; - std::string desc, tag; - bool inTag = false; - for( std::size_t i = 0; i < _descOrTags.size(); ++i ) { - char c = _descOrTags[i]; - if( !inTag ) { - if( c == '[' ) - inTag = true; - else - desc += c; - } - else { - if( c == ']' ) { - TestCaseInfo::SpecialProperties prop = parseSpecialTag( tag ); - if( prop == TestCaseInfo::IsHidden ) - isHidden = true; - else if( prop == TestCaseInfo::None ) - enforceNotReservedTag( tag, _lineInfo ); - - tags.insert( tag ); - tag.clear(); - inTag = false; - } - else - tag += c; - } - } - if( isHidden ) { - tags.insert( "hide" ); - tags.insert( "." ); - } - - TestCaseInfo info( _name, _className, desc, tags, _lineInfo ); - return TestCase( _testCase, info ); - } - - void setTags( TestCaseInfo& testCaseInfo, std::set const& tags ) - { - testCaseInfo.tags = tags; - testCaseInfo.lcaseTags.clear(); - - std::ostringstream oss; - for( std::set::const_iterator it = tags.begin(), itEnd = tags.end(); it != itEnd; ++it ) { - oss << '[' << *it << ']'; - std::string lcaseTag = toLower( *it ); - testCaseInfo.properties = static_cast( testCaseInfo.properties | parseSpecialTag( lcaseTag ) ); - testCaseInfo.lcaseTags.insert( lcaseTag ); - } - testCaseInfo.tagsAsString = oss.str(); - } - - TestCaseInfo::TestCaseInfo( std::string const& _name, - std::string const& _className, - std::string const& _description, - std::set const& _tags, - SourceLineInfo const& _lineInfo ) - : name( _name ), - className( _className ), - description( _description ), - lineInfo( _lineInfo ), - properties( None ) - { - setTags( *this, _tags ); - } - - TestCaseInfo::TestCaseInfo( TestCaseInfo const& other ) - : name( other.name ), - className( other.className ), - description( other.description ), - tags( other.tags ), - lcaseTags( other.lcaseTags ), - tagsAsString( other.tagsAsString ), - lineInfo( other.lineInfo ), - properties( other.properties ) - {} - - bool TestCaseInfo::isHidden() const { - return ( properties & IsHidden ) != 0; - } - bool TestCaseInfo::throws() const { - return ( properties & Throws ) != 0; - } - bool TestCaseInfo::okToFail() const { - return ( properties & (ShouldFail | MayFail ) ) != 0; - } - bool TestCaseInfo::expectedToFail() const { - return ( properties & (ShouldFail ) ) != 0; - } - - TestCase::TestCase( ITestCase* testCase, TestCaseInfo const& info ) : TestCaseInfo( info ), test( testCase ) {} - - TestCase::TestCase( TestCase const& other ) - : TestCaseInfo( other ), - test( other.test ) - {} - - TestCase TestCase::withName( std::string const& _newName ) const { - TestCase other( *this ); - other.name = _newName; - return other; - } - - void TestCase::swap( TestCase& other ) { - test.swap( other.test ); - name.swap( other.name ); - className.swap( other.className ); - description.swap( other.description ); - tags.swap( other.tags ); - lcaseTags.swap( other.lcaseTags ); - tagsAsString.swap( other.tagsAsString ); - std::swap( TestCaseInfo::properties, static_cast( other ).properties ); - std::swap( lineInfo, other.lineInfo ); - } - - void TestCase::invoke() const { - test->invoke(); - } - - bool TestCase::operator == ( TestCase const& other ) const { - return test.get() == other.test.get() && - name == other.name && - className == other.className; - } - - bool TestCase::operator < ( TestCase const& other ) const { - return name < other.name; - } - TestCase& TestCase::operator = ( TestCase const& other ) { - TestCase temp( other ); - swap( temp ); - return *this; - } - - TestCaseInfo const& TestCase::getTestCaseInfo() const - { - return *this; - } - -} // end namespace Catch - -// #included from: catch_version.hpp -#define TWOBLUECUBES_CATCH_VERSION_HPP_INCLUDED - -namespace Catch { - - Version::Version - ( unsigned int _majorVersion, - unsigned int _minorVersion, - unsigned int _patchNumber, - char const * const _branchName, - unsigned int _buildNumber ) - : majorVersion( _majorVersion ), - minorVersion( _minorVersion ), - patchNumber( _patchNumber ), - branchName( _branchName ), - buildNumber( _buildNumber ) - {} - - std::ostream& operator << ( std::ostream& os, Version const& version ) { - os << version.majorVersion << '.' - << version.minorVersion << '.' - << version.patchNumber; - // branchName is never null -> 0th char is \0 if it is empty - if (version.branchName[0]) { - os << '-' << version.branchName - << '.' << version.buildNumber; - } + std::ostream& operator << ( std::ostream& os, Colour const& ) { return os; } - inline Version libraryVersion() { - static Version version( 1, 9, 7, "", 0 ); - return version; - } - -} - -// #included from: catch_message.hpp -#define TWOBLUECUBES_CATCH_MESSAGE_HPP_INCLUDED - -namespace Catch { - - MessageInfo::MessageInfo( std::string const& _macroName, - SourceLineInfo const& _lineInfo, - ResultWas::OfType _type ) - : macroName( _macroName ), - lineInfo( _lineInfo ), - type( _type ), - sequence( ++globalCount ) - {} - - // This may need protecting if threading support is added - unsigned int MessageInfo::globalCount = 0; - - //////////////////////////////////////////////////////////////////////////// - - ScopedMessage::ScopedMessage( MessageBuilder const& builder ) - : m_info( builder.m_info ) - { - m_info.message = builder.m_stream.str(); - getResultCapture().pushScopedMessage( m_info ); - } - ScopedMessage::ScopedMessage( ScopedMessage const& other ) - : m_info( other.m_info ) - {} - - ScopedMessage::~ScopedMessage() { - if ( !std::uncaught_exception() ){ - getResultCapture().popScopedMessage(m_info); - } - } - } // end namespace Catch -// #included from: catch_legacy_reporter_adapter.hpp -#define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_HPP_INCLUDED - -// #included from: catch_legacy_reporter_adapter.h -#define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_H_INCLUDED - -namespace Catch -{ - // Deprecated - struct IReporter : IShared { - virtual ~IReporter(); - - virtual bool shouldRedirectStdout() const = 0; - - virtual void StartTesting() = 0; - virtual void EndTesting( Totals const& totals ) = 0; - virtual void StartGroup( std::string const& groupName ) = 0; - virtual void EndGroup( std::string const& groupName, Totals const& totals ) = 0; - virtual void StartTestCase( TestCaseInfo const& testInfo ) = 0; - virtual void EndTestCase( TestCaseInfo const& testInfo, Totals const& totals, std::string const& stdOut, std::string const& stdErr ) = 0; - virtual void StartSection( std::string const& sectionName, std::string const& description ) = 0; - virtual void EndSection( std::string const& sectionName, Counts const& assertions ) = 0; - virtual void NoAssertionsInSection( std::string const& sectionName ) = 0; - virtual void NoAssertionsInTestCase( std::string const& testName ) = 0; - virtual void Aborted() = 0; - virtual void Result( AssertionResult const& result ) = 0; - }; - - class LegacyReporterAdapter : public SharedImpl - { - public: - LegacyReporterAdapter( Ptr const& legacyReporter ); - virtual ~LegacyReporterAdapter(); - - virtual ReporterPreferences getPreferences() const; - virtual void noMatchingTestCases( std::string const& ); - virtual void testRunStarting( TestRunInfo const& ); - virtual void testGroupStarting( GroupInfo const& groupInfo ); - virtual void testCaseStarting( TestCaseInfo const& testInfo ); - virtual void sectionStarting( SectionInfo const& sectionInfo ); - virtual void assertionStarting( AssertionInfo const& ); - virtual bool assertionEnded( AssertionStats const& assertionStats ); - virtual void sectionEnded( SectionStats const& sectionStats ); - virtual void testCaseEnded( TestCaseStats const& testCaseStats ); - virtual void testGroupEnded( TestGroupStats const& testGroupStats ); - virtual void testRunEnded( TestRunStats const& testRunStats ); - virtual void skipTest( TestCaseInfo const& ); - - private: - Ptr m_legacyReporter; - }; -} - -namespace Catch -{ - LegacyReporterAdapter::LegacyReporterAdapter( Ptr const& legacyReporter ) - : m_legacyReporter( legacyReporter ) - {} - LegacyReporterAdapter::~LegacyReporterAdapter() {} - - ReporterPreferences LegacyReporterAdapter::getPreferences() const { - ReporterPreferences prefs; - prefs.shouldRedirectStdOut = m_legacyReporter->shouldRedirectStdout(); - return prefs; - } - - void LegacyReporterAdapter::noMatchingTestCases( std::string const& ) {} - void LegacyReporterAdapter::testRunStarting( TestRunInfo const& ) { - m_legacyReporter->StartTesting(); - } - void LegacyReporterAdapter::testGroupStarting( GroupInfo const& groupInfo ) { - m_legacyReporter->StartGroup( groupInfo.name ); - } - void LegacyReporterAdapter::testCaseStarting( TestCaseInfo const& testInfo ) { - m_legacyReporter->StartTestCase( testInfo ); - } - void LegacyReporterAdapter::sectionStarting( SectionInfo const& sectionInfo ) { - m_legacyReporter->StartSection( sectionInfo.name, sectionInfo.description ); - } - void LegacyReporterAdapter::assertionStarting( AssertionInfo const& ) { - // Not on legacy interface - } - - bool LegacyReporterAdapter::assertionEnded( AssertionStats const& assertionStats ) { - if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) { - for( std::vector::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end(); - it != itEnd; - ++it ) { - if( it->type == ResultWas::Info ) { - ResultBuilder rb( it->macroName.c_str(), it->lineInfo, "", ResultDisposition::Normal ); - rb << it->message; - rb.setResultType( ResultWas::Info ); - AssertionResult result = rb.build(); - m_legacyReporter->Result( result ); - } - } - } - m_legacyReporter->Result( assertionStats.assertionResult ); - return true; - } - void LegacyReporterAdapter::sectionEnded( SectionStats const& sectionStats ) { - if( sectionStats.missingAssertions ) - m_legacyReporter->NoAssertionsInSection( sectionStats.sectionInfo.name ); - m_legacyReporter->EndSection( sectionStats.sectionInfo.name, sectionStats.assertions ); - } - void LegacyReporterAdapter::testCaseEnded( TestCaseStats const& testCaseStats ) { - m_legacyReporter->EndTestCase - ( testCaseStats.testInfo, - testCaseStats.totals, - testCaseStats.stdOut, - testCaseStats.stdErr ); - } - void LegacyReporterAdapter::testGroupEnded( TestGroupStats const& testGroupStats ) { - if( testGroupStats.aborting ) - m_legacyReporter->Aborted(); - m_legacyReporter->EndGroup( testGroupStats.groupInfo.name, testGroupStats.totals ); - } - void LegacyReporterAdapter::testRunEnded( TestRunStats const& testRunStats ) { - m_legacyReporter->EndTesting( testRunStats.totals ); - } - void LegacyReporterAdapter::skipTest( TestCaseInfo const& ) { - } -} - -// #included from: catch_timer.hpp - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wc++11-long-long" +#if defined(__clang__) +# pragma clang diagnostic pop #endif -#ifdef CATCH_PLATFORM_WINDOWS - -#else - -#include - -#endif +// end catch_console_colour.cpp +// start catch_context.cpp namespace Catch { + class Context : public IMutableContext, NonCopyable { + + public: // IContext + virtual IResultCapture* getResultCapture() override { + return m_resultCapture; + } + virtual IRunner* getRunner() override { + return m_runner; + } + + virtual IConfigPtr getConfig() const override { + return m_config; + } + + virtual ~Context() override; + + public: // IMutableContext + virtual void setResultCapture( IResultCapture* resultCapture ) override { + m_resultCapture = resultCapture; + } + virtual void setRunner( IRunner* runner ) override { + m_runner = runner; + } + virtual void setConfig( IConfigPtr const& config ) override { + m_config = config; + } + + friend IMutableContext& getCurrentMutableContext(); + + private: + IConfigPtr m_config; + IRunner* m_runner = nullptr; + IResultCapture* m_resultCapture = nullptr; + }; + namespace { -#ifdef CATCH_PLATFORM_WINDOWS - UInt64 getCurrentTicks() { - static UInt64 hz=0, hzo=0; - if (!hz) { - QueryPerformanceFrequency( reinterpret_cast( &hz ) ); - QueryPerformanceCounter( reinterpret_cast( &hzo ) ); - } - UInt64 t; - QueryPerformanceCounter( reinterpret_cast( &t ) ); - return ((t-hzo)*1000000)/hz; - } -#else - UInt64 getCurrentTicks() { - timeval t; - gettimeofday(&t,CATCH_NULL); - return static_cast( t.tv_sec ) * 1000000ull + static_cast( t.tv_usec ); - } -#endif + Context* currentContext = nullptr; + } + IMutableContext& getCurrentMutableContext() { + if( !currentContext ) + currentContext = new Context(); + return *currentContext; + } + IContext& getCurrentContext() { + return getCurrentMutableContext(); } - void Timer::start() { - m_ticks = getCurrentTicks(); - } - unsigned int Timer::getElapsedMicroseconds() const { - return static_cast(getCurrentTicks() - m_ticks); - } - unsigned int Timer::getElapsedMilliseconds() const { - return static_cast(getElapsedMicroseconds()/1000); - } - double Timer::getElapsedSeconds() const { - return getElapsedMicroseconds()/1000000.0; + void cleanUpContext() { + delete currentContext; + currentContext = nullptr; } + IContext::~IContext() = default; + IMutableContext::~IMutableContext() = default; + Context::~Context() = default; +} +// end catch_context.cpp +// start catch_debug_console.cpp -} // namespace Catch +// start catch_debug_console.h -#ifdef __clang__ -#pragma clang diagnostic pop -#endif -// #included from: catch_common.hpp -#define TWOBLUECUBES_CATCH_COMMON_HPP_INCLUDED - -#include -#include +#include namespace Catch { - - bool startsWith( std::string const& s, std::string const& prefix ) { - return s.size() >= prefix.size() && std::equal(prefix.begin(), prefix.end(), s.begin()); - } - bool startsWith( std::string const& s, char prefix ) { - return !s.empty() && s[0] == prefix; - } - bool endsWith( std::string const& s, std::string const& suffix ) { - return s.size() >= suffix.size() && std::equal(suffix.rbegin(), suffix.rend(), s.rbegin()); - } - bool endsWith( std::string const& s, char suffix ) { - return !s.empty() && s[s.size()-1] == suffix; - } - bool contains( std::string const& s, std::string const& infix ) { - return s.find( infix ) != std::string::npos; - } - char toLowerCh(char c) { - return static_cast( std::tolower( c ) ); - } - void toLowerInPlace( std::string& s ) { - std::transform( s.begin(), s.end(), s.begin(), toLowerCh ); - } - std::string toLower( std::string const& s ) { - std::string lc = s; - toLowerInPlace( lc ); - return lc; - } - std::string trim( std::string const& str ) { - static char const* whitespaceChars = "\n\r\t "; - std::string::size_type start = str.find_first_not_of( whitespaceChars ); - std::string::size_type end = str.find_last_not_of( whitespaceChars ); - - return start != std::string::npos ? str.substr( start, 1+end-start ) : std::string(); - } - - bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) { - bool replaced = false; - std::size_t i = str.find( replaceThis ); - while( i != std::string::npos ) { - replaced = true; - str = str.substr( 0, i ) + withThis + str.substr( i+replaceThis.size() ); - if( i < str.size()-withThis.size() ) - i = str.find( replaceThis, i+withThis.size() ); - else - i = std::string::npos; - } - return replaced; - } - - pluralise::pluralise( std::size_t count, std::string const& label ) - : m_count( count ), - m_label( label ) - {} - - std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) { - os << pluraliser.m_count << ' ' << pluraliser.m_label; - if( pluraliser.m_count != 1 ) - os << 's'; - return os; - } - - SourceLineInfo::SourceLineInfo() : file(""), line( 0 ){} - SourceLineInfo::SourceLineInfo( char const* _file, std::size_t _line ) - : file( _file ), - line( _line ) - {} - bool SourceLineInfo::empty() const { - return file[0] == '\0'; - } - bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const { - return line == other.line && (file == other.file || std::strcmp(file, other.file) == 0); - } - bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const { - return line < other.line || ( line == other.line && (std::strcmp(file, other.file) < 0)); - } - - void seedRng( IConfig const& config ) { - if( config.rngSeed() != 0 ) - std::srand( config.rngSeed() ); - } - unsigned int rngSeed() { - return getCurrentContext().getConfig()->rngSeed(); - } - - std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) { -#ifndef __GNUG__ - os << info.file << '(' << info.line << ')'; -#else - os << info.file << ':' << info.line; -#endif - return os; - } - - void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ) { - std::ostringstream oss; - oss << locationInfo << ": Internal Catch error: '" << message << '\''; - if( alwaysTrue() ) - throw std::logic_error( oss.str() ); - } + void writeToDebugConsole( std::string const& text ); } -// #included from: catch_section.hpp -#define TWOBLUECUBES_CATCH_SECTION_HPP_INCLUDED +// end catch_debug_console.h +#ifdef CATCH_PLATFORM_WINDOWS -namespace Catch { - - SectionInfo::SectionInfo - ( SourceLineInfo const& _lineInfo, - std::string const& _name, - std::string const& _description ) - : name( _name ), - description( _description ), - lineInfo( _lineInfo ) - {} - - Section::Section( SectionInfo const& info ) - : m_info( info ), - m_sectionIncluded( getResultCapture().sectionStarted( m_info, m_assertions ) ) - { - m_timer.start(); - } - -#if defined(_MSC_VER) -#pragma warning(push) -#pragma warning(disable:4996) // std::uncaught_exception is deprecated in C++17 -#endif - Section::~Section() { - if( m_sectionIncluded ) { - SectionEndInfo endInfo( m_info, m_assertions, m_timer.getElapsedSeconds() ); - if( std::uncaught_exception() ) - getResultCapture().sectionEndedEarly( endInfo ); - else - getResultCapture().sectionEnded( endInfo ); + namespace Catch { + void writeToDebugConsole( std::string const& text ) { + ::OutputDebugStringA( text.c_str() ); } } -#if defined(_MSC_VER) -#pragma warning(pop) -#endif - - // This indicates whether the section should be executed or not - Section::operator bool() const { - return m_sectionIncluded; +#else + namespace Catch { + void writeToDebugConsole( std::string const& text ) { + // !TBD: Need a version for Mac/ XCode and other IDEs + Catch::cout() << text; + } } - -} // end namespace Catch - -// #included from: catch_debugger.hpp -#define TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED +#endif // Platform +// end catch_debug_console.cpp +// start catch_debugger.cpp #ifdef CATCH_PLATFORM_MAC @@ -8793,7 +6214,7 @@ namespace Catch { #include #include - namespace Catch{ + namespace Catch { // The following function is taken directly from the following technical note: // http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html @@ -8804,7 +6225,7 @@ namespace Catch { int mib[4]; struct kinfo_proc info; - size_t size; + std::size_t size; // Initialize the flags so that, if sysctl fails for some bizarre // reason, we get a predictable result. @@ -8822,7 +6243,7 @@ namespace Catch { // Call sysctl. size = sizeof(info); - if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, CATCH_NULL, 0) != 0 ) { + if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, nullptr, 0) != 0 ) { Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl; return false; } @@ -8879,449 +6300,778 @@ namespace Catch { } #else namespace Catch { - inline bool isDebuggerActive() { return false; } + bool isDebuggerActive() { return false; } } #endif // Platform - -#ifdef CATCH_PLATFORM_WINDOWS - - namespace Catch { - void writeToDebugConsole( std::string const& text ) { - ::OutputDebugStringA( text.c_str() ); - } - } -#else - namespace Catch { - void writeToDebugConsole( std::string const& text ) { - // !TBD: Need a version for Mac/ XCode and other IDEs - Catch::cout() << text; - } - } -#endif // Platform - -// #included from: catch_tostring.hpp -#define TWOBLUECUBES_CATCH_TOSTRING_HPP_INCLUDED +// end catch_debugger.cpp +// start catch_decomposer.cpp namespace Catch { -namespace Detail { + ITransientExpression::~ITransientExpression() = default; - const std::string unprintableString = "{?}"; - - namespace { - const int hexThreshold = 255; - - struct Endianness { - enum Arch { Big, Little }; - - static Arch which() { - union _{ - int asInt; - char asChar[sizeof (int)]; - } u; - - u.asInt = 1; - return ( u.asChar[sizeof(int)-1] == 1 ) ? Big : Little; - } - }; - } - - std::string rawMemoryToString( const void *object, std::size_t size ) - { - // Reverse order for little endian architectures - int i = 0, end = static_cast( size ), inc = 1; - if( Endianness::which() == Endianness::Little ) { - i = end-1; - end = inc = -1; - } - - unsigned char const *bytes = static_cast(object); - std::ostringstream os; - os << "0x" << std::setfill('0') << std::hex; - for( ; i != end; i += inc ) - os << std::setw(2) << static_cast(bytes[i]); - return os.str(); + void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs ) { + if( lhs.size() + rhs.size() < 40 && + lhs.find('\n') == std::string::npos && + rhs.find('\n') == std::string::npos ) + os << lhs << " " << op << " " << rhs; + else + os << lhs << "\n" << op << "\n" << rhs; } } +// end catch_decomposer.cpp +// start catch_errno_guard.cpp -std::string toString( std::string const& value ) { - std::string s = value; - if( getCurrentContext().getConfig()->showInvisibles() ) { - for(size_t i = 0; i < s.size(); ++i ) { - std::string subs; - switch( s[i] ) { - case '\n': subs = "\\n"; break; - case '\t': subs = "\\t"; break; - default: break; - } - if( !subs.empty() ) { - s = s.substr( 0, i ) + subs + s.substr( i+1 ); - ++i; - } - } - } - return '"' + s + '"'; +#include + +namespace Catch { + ErrnoGuard::ErrnoGuard():m_oldErrno(errno){} + ErrnoGuard::~ErrnoGuard() { errno = m_oldErrno; } } -std::string toString( std::wstring const& value ) { +// end catch_errno_guard.cpp +// start catch_exception_translator_registry.cpp - std::string s; - s.reserve( value.size() ); - for(size_t i = 0; i < value.size(); ++i ) - s += value[i] <= 0xff ? static_cast( value[i] ) : '?'; - return Catch::toString( s ); +// start catch_exception_translator_registry.h + +#include +#include +#include + +namespace Catch { + + class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry { + public: + ~ExceptionTranslatorRegistry(); + virtual void registerTranslator( const IExceptionTranslator* translator ); + virtual std::string translateActiveException() const override; + std::string tryTranslators() const; + + private: + std::vector> m_translators; + }; } -std::string toString( const char* const value ) { - return value ? Catch::toString( std::string( value ) ) : std::string( "{null string}" ); -} - -std::string toString( char* const value ) { - return Catch::toString( static_cast( value ) ); -} - -std::string toString( const wchar_t* const value ) -{ - return value ? Catch::toString( std::wstring(value) ) : std::string( "{null string}" ); -} - -std::string toString( wchar_t* const value ) -{ - return Catch::toString( static_cast( value ) ); -} - -std::string toString( int value ) { - std::ostringstream oss; - oss << value; - if( value > Detail::hexThreshold ) - oss << " (0x" << std::hex << value << ')'; - return oss.str(); -} - -std::string toString( unsigned long value ) { - std::ostringstream oss; - oss << value; - if( value > Detail::hexThreshold ) - oss << " (0x" << std::hex << value << ')'; - return oss.str(); -} - -std::string toString( unsigned int value ) { - return Catch::toString( static_cast( value ) ); -} - -template -std::string fpToString( T value, int precision ) { - std::ostringstream oss; - oss << std::setprecision( precision ) - << std::fixed - << value; - std::string d = oss.str(); - std::size_t i = d.find_last_not_of( '0' ); - if( i != std::string::npos && i != d.size()-1 ) { - if( d[i] == '.' ) - i++; - d = d.substr( 0, i+1 ); - } - return d; -} - -std::string toString( const double value ) { - return fpToString( value, 10 ); -} -std::string toString( const float value ) { - return fpToString( value, 5 ) + 'f'; -} - -std::string toString( bool value ) { - return value ? "true" : "false"; -} - -std::string toString( char value ) { - if ( value == '\r' ) - return "'\\r'"; - if ( value == '\f' ) - return "'\\f'"; - if ( value == '\n' ) - return "'\\n'"; - if ( value == '\t' ) - return "'\\t'"; - if ( '\0' <= value && value < ' ' ) - return toString( static_cast( value ) ); - char chstr[] = "' '"; - chstr[1] = value; - return chstr; -} - -std::string toString( signed char value ) { - return toString( static_cast( value ) ); -} - -std::string toString( unsigned char value ) { - return toString( static_cast( value ) ); -} - -#ifdef CATCH_CONFIG_CPP11_LONG_LONG -std::string toString( long long value ) { - std::ostringstream oss; - oss << value; - if( value > Detail::hexThreshold ) - oss << " (0x" << std::hex << value << ')'; - return oss.str(); -} -std::string toString( unsigned long long value ) { - std::ostringstream oss; - oss << value; - if( value > Detail::hexThreshold ) - oss << " (0x" << std::hex << value << ')'; - return oss.str(); -} -#endif - -#ifdef CATCH_CONFIG_CPP11_NULLPTR -std::string toString( std::nullptr_t ) { - return "nullptr"; -} -#endif - +// end catch_exception_translator_registry.h #ifdef __OBJC__ - std::string toString( NSString const * const& nsstring ) { - if( !nsstring ) - return "nil"; - return "@" + toString([nsstring UTF8String]); - } - std::string toString( NSString * CATCH_ARC_STRONG & nsstring ) { - if( !nsstring ) - return "nil"; - return "@" + toString([nsstring UTF8String]); - } - std::string toString( NSObject* const& nsObject ) { - return toString( [nsObject description] ); - } +#import "Foundation/Foundation.h" #endif +namespace Catch { + + ExceptionTranslatorRegistry::~ExceptionTranslatorRegistry() { + } + + void ExceptionTranslatorRegistry::registerTranslator( const IExceptionTranslator* translator ) { + m_translators.push_back( std::unique_ptr( translator ) ); + } + + std::string ExceptionTranslatorRegistry::translateActiveException() const { + try { +#ifdef __OBJC__ + // In Objective-C try objective-c exceptions first + @try { + return tryTranslators(); + } + @catch (NSException *exception) { + return Catch::Detail::stringify( [exception description] ); + } +#else + return tryTranslators(); +#endif + } + catch( TestFailureException& ) { + std::rethrow_exception(std::current_exception()); + } + catch( std::exception& ex ) { + return ex.what(); + } + catch( std::string& msg ) { + return msg; + } + catch( const char* msg ) { + return msg; + } + catch(...) { + return "Unknown exception"; + } + } + + std::string ExceptionTranslatorRegistry::tryTranslators() const { + if( m_translators.empty() ) + std::rethrow_exception(std::current_exception()); + else + return m_translators[0]->translate( m_translators.begin()+1, m_translators.end() ); + } +} +// end catch_exception_translator_registry.cpp +// start catch_fatal_condition.cpp + +// start catch_fatal_condition.h + +#include + +#if defined ( CATCH_PLATFORM_WINDOWS ) ///////////////////////////////////////// + +# if !defined ( CATCH_CONFIG_WINDOWS_SEH ) + +namespace Catch { + struct FatalConditionHandler { + void reset(); + }; +} + +# else // CATCH_CONFIG_WINDOWS_SEH is defined + +namespace Catch { + + struct FatalConditionHandler { + + static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo); + FatalConditionHandler(); + static void reset(); + ~FatalConditionHandler(); + + private: + static bool isSet; + static ULONG guaranteeSize; + static PVOID exceptionHandlerHandle; + }; + +} // namespace Catch + +# endif // CATCH_CONFIG_WINDOWS_SEH + +#else // Not Windows - assumed to be POSIX compatible ////////////////////////// + +# if !defined(CATCH_CONFIG_POSIX_SIGNALS) + +namespace Catch { + struct FatalConditionHandler { + void reset(); + }; +} + +# else // CATCH_CONFIG_POSIX_SIGNALS is defined + +#include + +namespace Catch { + + struct FatalConditionHandler { + + static bool isSet; + static struct sigaction oldSigActions[];// [sizeof(signalDefs) / sizeof(SignalDefs)]; + static stack_t oldSigStack; + static char altStackMem[]; + + static void handleSignal( int sig ); + + FatalConditionHandler(); + ~FatalConditionHandler(); + static void reset(); + }; + +} // namespace Catch + +# endif // CATCH_CONFIG_POSIX_SIGNALS + +#endif // not Windows + +// end catch_fatal_condition.h +namespace { + // Report the error condition + void reportFatal( char const * const message ) { + Catch::getCurrentContext().getResultCapture()->handleFatalErrorCondition( message ); + } +} + +#if defined ( CATCH_PLATFORM_WINDOWS ) ///////////////////////////////////////// + +# if !defined ( CATCH_CONFIG_WINDOWS_SEH ) + +namespace Catch { + void FatalConditionHandler::reset() {} +} + +# else // CATCH_CONFIG_WINDOWS_SEH is defined + +namespace Catch { + struct SignalDefs { DWORD id; const char* name; }; + + // There is no 1-1 mapping between signals and windows exceptions. + // Windows can easily distinguish between SO and SigSegV, + // but SigInt, SigTerm, etc are handled differently. + static SignalDefs signalDefs[] = { + { EXCEPTION_ILLEGAL_INSTRUCTION, "SIGILL - Illegal instruction signal" }, + { EXCEPTION_STACK_OVERFLOW, "SIGSEGV - Stack overflow" }, + { EXCEPTION_ACCESS_VIOLATION, "SIGSEGV - Segmentation violation signal" }, + { EXCEPTION_INT_DIVIDE_BY_ZERO, "Divide by zero error" }, + }; + + LONG CALLBACK FatalConditionHandler::handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) { + for (auto const& def : signalDefs) { + if (ExceptionInfo->ExceptionRecord->ExceptionCode == def.id) { + reportFatal(def.name); + } + } + // If its not an exception we care about, pass it along. + // This stops us from eating debugger breaks etc. + return EXCEPTION_CONTINUE_SEARCH; + } + + FatalConditionHandler::FatalConditionHandler() { + isSet = true; + // 32k seems enough for Catch to handle stack overflow, + // but the value was found experimentally, so there is no strong guarantee + guaranteeSize = 32 * 1024; + exceptionHandlerHandle = nullptr; + // Register as first handler in current chain + exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException); + // Pass in guarantee size to be filled + SetThreadStackGuarantee(&guaranteeSize); + } + + void FatalConditionHandler::reset() { + if (isSet) { + // Unregister handler and restore the old guarantee + RemoveVectoredExceptionHandler(exceptionHandlerHandle); + SetThreadStackGuarantee(&guaranteeSize); + exceptionHandlerHandle = nullptr; + isSet = false; + } + } + + FatalConditionHandler::~FatalConditionHandler() { + reset(); + } + +bool FatalConditionHandler::isSet = false; +ULONG FatalConditionHandler::guaranteeSize = 0; +PVOID FatalConditionHandler::exceptionHandlerHandle = nullptr; + +} // namespace Catch + +# endif // CATCH_CONFIG_WINDOWS_SEH + +#else // Not Windows - assumed to be POSIX compatible ////////////////////////// + +# if !defined(CATCH_CONFIG_POSIX_SIGNALS) + +namespace Catch { + void FatalConditionHandler::reset() {} +} + +# else // CATCH_CONFIG_POSIX_SIGNALS is defined + +#include + +namespace Catch { + + struct SignalDefs { + int id; + const char* name; + }; + static SignalDefs signalDefs[] = { + { SIGINT, "SIGINT - Terminal interrupt signal" }, + { SIGILL, "SIGILL - Illegal instruction signal" }, + { SIGFPE, "SIGFPE - Floating point error signal" }, + { SIGSEGV, "SIGSEGV - Segmentation violation signal" }, + { SIGTERM, "SIGTERM - Termination request signal" }, + { SIGABRT, "SIGABRT - Abort (abnormal termination) signal" } + }; + + void FatalConditionHandler::handleSignal( int sig ) { + char const * name = ""; + for (auto const& def : signalDefs) { + if (sig == def.id) { + name = def.name; + break; + } + } + reset(); + reportFatal(name); + raise( sig ); + } + + FatalConditionHandler::FatalConditionHandler() { + isSet = true; + stack_t sigStack; + sigStack.ss_sp = altStackMem; + sigStack.ss_size = SIGSTKSZ; + sigStack.ss_flags = 0; + sigaltstack(&sigStack, &oldSigStack); + struct sigaction sa = { }; + + sa.sa_handler = handleSignal; + sa.sa_flags = SA_ONSTACK; + for (std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i) { + sigaction(signalDefs[i].id, &sa, &oldSigActions[i]); + } + } + + FatalConditionHandler::~FatalConditionHandler() { + reset(); + } + + void FatalConditionHandler::reset() { + if( isSet ) { + // Set signals back to previous values -- hopefully nobody overwrote them in the meantime + for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) { + sigaction(signalDefs[i].id, &oldSigActions[i], nullptr); + } + // Return the old stack + sigaltstack(&oldSigStack, nullptr); + isSet = false; + } + } + + bool FatalConditionHandler::isSet = false; + struct sigaction FatalConditionHandler::oldSigActions[sizeof(signalDefs)/sizeof(SignalDefs)] = {}; + stack_t FatalConditionHandler::oldSigStack = {}; + char FatalConditionHandler::altStackMem[SIGSTKSZ] = {}; + +} // namespace Catch + +# endif // CATCH_CONFIG_POSIX_SIGNALS + +#endif // not Windows +// end catch_fatal_condition.cpp +// start catch_interfaces_capture.cpp + +namespace Catch { + IResultCapture::~IResultCapture() = default; +} +// end catch_interfaces_capture.cpp +// start catch_interfaces_config.cpp + +namespace Catch { + IConfig::~IConfig() = default; +} +// end catch_interfaces_config.cpp +// start catch_interfaces_exception.cpp + +namespace Catch { + IExceptionTranslator::~IExceptionTranslator() = default; + IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() = default; +} +// end catch_interfaces_exception.cpp +// start catch_interfaces_registry_hub.cpp + +namespace Catch { + IRegistryHub::~IRegistryHub() = default; + IMutableRegistryHub::~IMutableRegistryHub() = default; +} +// end catch_interfaces_registry_hub.cpp +// start catch_interfaces_reporter.cpp + +// start catch_reporter_multi.h + +namespace Catch { + + class MultipleReporters : public IStreamingReporter { + using Reporters = std::vector; + Reporters m_reporters; + + public: + void add( IStreamingReporterPtr&& reporter ); + + public: // IStreamingReporter + + ReporterPreferences getPreferences() const override; + + void noMatchingTestCases( std::string const& spec ) override; + + static std::set getSupportedVerbosities(); + + void benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) override; + void benchmarkEnded( BenchmarkStats const& benchmarkStats ) override; + + void testRunStarting( TestRunInfo const& testRunInfo ) override; + void testGroupStarting( GroupInfo const& groupInfo ) override; + void testCaseStarting( TestCaseInfo const& testInfo ) override; + void sectionStarting( SectionInfo const& sectionInfo ) override; + void assertionStarting( AssertionInfo const& assertionInfo ) override; + + // The return value indicates if the messages buffer should be cleared: + bool assertionEnded( AssertionStats const& assertionStats ) override; + void sectionEnded( SectionStats const& sectionStats ) override; + void testCaseEnded( TestCaseStats const& testCaseStats ) override; + void testGroupEnded( TestGroupStats const& testGroupStats ) override; + void testRunEnded( TestRunStats const& testRunStats ) override; + + void skipTest( TestCaseInfo const& testInfo ) override; + bool isMulti() const override; + + }; + } // end namespace Catch -// #included from: catch_result_builder.hpp -#define TWOBLUECUBES_CATCH_RESULT_BUILDER_HPP_INCLUDED - +// end catch_reporter_multi.h namespace Catch { - ResultBuilder::ResultBuilder( char const* macroName, - SourceLineInfo const& lineInfo, - char const* capturedExpression, - ResultDisposition::Flags resultDisposition, - char const* secondArg ) - : m_assertionInfo( macroName, lineInfo, capturedExpression, resultDisposition, secondArg ), - m_shouldDebugBreak( false ), - m_shouldThrow( false ), - m_guardException( false ), - m_usedStream( false ) + ReporterConfig::ReporterConfig( IConfigPtr const& _fullConfig ) + : m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {} + + ReporterConfig::ReporterConfig( IConfigPtr const& _fullConfig, std::ostream& _stream ) + : m_stream( &_stream ), m_fullConfig( _fullConfig ) {} + + std::ostream& ReporterConfig::stream() const { return *m_stream; } + IConfigPtr ReporterConfig::fullConfig() const { return m_fullConfig; } + + TestRunInfo::TestRunInfo( std::string const& _name ) : name( _name ) {} + + GroupInfo::GroupInfo( std::string const& _name, + std::size_t _groupIndex, + std::size_t _groupsCount ) + : name( _name ), + groupIndex( _groupIndex ), + groupsCounts( _groupsCount ) {} - ResultBuilder::~ResultBuilder() { -#if defined(CATCH_CONFIG_FAST_COMPILE) - if ( m_guardException ) { - stream().oss << "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE"; - captureResult( ResultWas::ThrewException ); - getCurrentContext().getResultCapture()->exceptionEarlyReported(); - } -#endif - } - - ResultBuilder& ResultBuilder::setResultType( ResultWas::OfType result ) { - m_data.resultType = result; - return *this; - } - ResultBuilder& ResultBuilder::setResultType( bool result ) { - m_data.resultType = result ? ResultWas::Ok : ResultWas::ExpressionFailed; - return *this; - } - - void ResultBuilder::endExpression( DecomposedExpression const& expr ) { - // Flip bool results if FalseTest flag is set - if( isFalseTest( m_assertionInfo.resultDisposition ) ) { - m_data.negate( expr.isBinaryExpression() ); - } - - getResultCapture().assertionRun(); - - if(getCurrentContext().getConfig()->includeSuccessfulResults() || m_data.resultType != ResultWas::Ok) - { - AssertionResult result = build( expr ); - handleResult( result ); - } - else - getResultCapture().assertionPassed(); - } - - void ResultBuilder::useActiveException( ResultDisposition::Flags resultDisposition ) { - m_assertionInfo.resultDisposition = resultDisposition; - stream().oss << Catch::translateActiveException(); - captureResult( ResultWas::ThrewException ); - } - - void ResultBuilder::captureResult( ResultWas::OfType resultType ) { - setResultType( resultType ); - captureExpression(); - } - - void ResultBuilder::captureExpectedException( std::string const& expectedMessage ) { - if( expectedMessage.empty() ) - captureExpectedException( Matchers::Impl::MatchAllOf() ); - else - captureExpectedException( Matchers::Equals( expectedMessage ) ); - } - - void ResultBuilder::captureExpectedException( Matchers::Impl::MatcherBase const& matcher ) { - - assert( !isFalseTest( m_assertionInfo.resultDisposition ) ); - AssertionResultData data = m_data; - data.resultType = ResultWas::Ok; - data.reconstructedExpression = capturedExpressionWithSecondArgument(m_assertionInfo.capturedExpression, m_assertionInfo.secondArg); - - std::string actualMessage = Catch::translateActiveException(); - if( !matcher.match( actualMessage ) ) { - data.resultType = ResultWas::ExpressionFailed; - data.reconstructedExpression = actualMessage; - } - AssertionResult result( m_assertionInfo, data ); - handleResult( result ); - } - - void ResultBuilder::captureExpression() { - AssertionResult result = build(); - handleResult( result ); - } - - void ResultBuilder::handleResult( AssertionResult const& result ) + AssertionStats::AssertionStats( AssertionResult const& _assertionResult, + std::vector const& _infoMessages, + Totals const& _totals ) + : assertionResult( _assertionResult ), + infoMessages( _infoMessages ), + totals( _totals ) { - getResultCapture().assertionEnded( result ); + assertionResult.m_resultData.lazyExpression.m_transientExpression = _assertionResult.m_resultData.lazyExpression.m_transientExpression; - if( !result.isOk() ) { - if( getCurrentContext().getConfig()->shouldDebugBreak() ) - m_shouldDebugBreak = true; - if( getCurrentContext().getRunner()->aborting() || (m_assertionInfo.resultDisposition & ResultDisposition::Normal) ) - m_shouldThrow = true; + if( assertionResult.hasMessage() ) { + // Copy message into messages list. + // !TBD This should have been done earlier, somewhere + MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() ); + builder << assertionResult.getMessage(); + builder.m_info.message = builder.m_stream.str(); + + infoMessages.push_back( builder.m_info ); } } - void ResultBuilder::react() { -#if defined(CATCH_CONFIG_FAST_COMPILE) - if (m_shouldDebugBreak) { - /////////////////////////////////////////////////////////////////// - // To inspect the state during test, you need to go one level up the callstack - // To go back to the test and change execution, jump over the throw statement - /////////////////////////////////////////////////////////////////// - CATCH_BREAK_INTO_DEBUGGER(); + AssertionStats::~AssertionStats() = default; + + SectionStats::SectionStats( SectionInfo const& _sectionInfo, + Counts const& _assertions, + double _durationInSeconds, + bool _missingAssertions ) + : sectionInfo( _sectionInfo ), + assertions( _assertions ), + durationInSeconds( _durationInSeconds ), + missingAssertions( _missingAssertions ) + {} + + SectionStats::~SectionStats() = default; + + TestCaseStats::TestCaseStats( TestCaseInfo const& _testInfo, + Totals const& _totals, + std::string const& _stdOut, + std::string const& _stdErr, + bool _aborting ) + : testInfo( _testInfo ), + totals( _totals ), + stdOut( _stdOut ), + stdErr( _stdErr ), + aborting( _aborting ) + {} + + TestCaseStats::~TestCaseStats() = default; + + TestGroupStats::TestGroupStats( GroupInfo const& _groupInfo, + Totals const& _totals, + bool _aborting ) + : groupInfo( _groupInfo ), + totals( _totals ), + aborting( _aborting ) + {} + + TestGroupStats::TestGroupStats( GroupInfo const& _groupInfo ) + : groupInfo( _groupInfo ), + aborting( false ) + {} + + TestGroupStats::~TestGroupStats() = default; + + TestRunStats::TestRunStats( TestRunInfo const& _runInfo, + Totals const& _totals, + bool _aborting ) + : runInfo( _runInfo ), + totals( _totals ), + aborting( _aborting ) + {} + + TestRunStats::~TestRunStats() = default; + + void IStreamingReporter::fatalErrorEncountered( StringRef ) {} + bool IStreamingReporter::isMulti() const { return false; } + + IReporterFactory::~IReporterFactory() = default; + IReporterRegistry::~IReporterRegistry() = default; + + void addReporter( IStreamingReporterPtr& existingReporter, IStreamingReporterPtr&& additionalReporter ) { + + if( !existingReporter ) { + existingReporter = std::move( additionalReporter ); + return; } -#endif - if( m_shouldThrow ) - throw Catch::TestFailureException(); - } - bool ResultBuilder::shouldDebugBreak() const { return m_shouldDebugBreak; } - bool ResultBuilder::allowThrows() const { return getCurrentContext().getConfig()->allowThrows(); } + MultipleReporters* multi = nullptr; - AssertionResult ResultBuilder::build() const - { - return build( *this ); - } - - // CAVEAT: The returned AssertionResult stores a pointer to the argument expr, - // a temporary DecomposedExpression, which in turn holds references to - // operands, possibly temporary as well. - // It should immediately be passed to handleResult; if the expression - // needs to be reported, its string expansion must be composed before - // the temporaries are destroyed. - AssertionResult ResultBuilder::build( DecomposedExpression const& expr ) const - { - assert( m_data.resultType != ResultWas::Unknown ); - AssertionResultData data = m_data; - - if(m_usedStream) - data.message = m_stream().oss.str(); - data.decomposedExpression = &expr; // for lazy reconstruction - return AssertionResult( m_assertionInfo, data ); - } - - void ResultBuilder::reconstructExpression( std::string& dest ) const { - dest = capturedExpressionWithSecondArgument(m_assertionInfo.capturedExpression, m_assertionInfo.secondArg); - } - - void ResultBuilder::setExceptionGuard() { - m_guardException = true; - } - void ResultBuilder::unsetExceptionGuard() { - m_guardException = false; + if( existingReporter->isMulti() ) { + multi = static_cast( existingReporter.get() ); + } + else { + auto newMulti = std::unique_ptr( new MultipleReporters ); + newMulti->add( std::move( existingReporter ) ); + multi = newMulti.get(); + existingReporter = std::move( newMulti ); + } + multi->add( std::move( additionalReporter ) ); } } // end namespace Catch +// end catch_interfaces_reporter.cpp +// start catch_interfaces_runner.cpp -// #included from: catch_tag_alias_registry.hpp -#define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_HPP_INCLUDED +namespace Catch { + IRunner::~IRunner() = default; +} +// end catch_interfaces_runner.cpp +// start catch_interfaces_testcase.cpp + +namespace Catch { + ITestInvoker::~ITestInvoker() = default; + ITestCaseRegistry::~ITestCaseRegistry() = default; +} +// end catch_interfaces_testcase.cpp +// start catch_leak_detector.cpp namespace Catch { - TagAliasRegistry::~TagAliasRegistry() {} +#ifdef CATCH_CONFIG_WINDOWS_CRTDBG +#include - Option TagAliasRegistry::find( std::string const& alias ) const { - std::map::const_iterator it = m_registry.find( alias ); - if( it != m_registry.end() ) - return it->second; - else - return Option(); - } + LeakDetector::LeakDetector() { + int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); + flag |= _CRTDBG_LEAK_CHECK_DF; + flag |= _CRTDBG_ALLOC_MEM_DF; + _CrtSetDbgFlag(flag); + _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG); + _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR); + // Change this to leaking allocation's number to break there + _CrtSetBreakAlloc(-1); + } - std::string TagAliasRegistry::expandAliases( std::string const& unexpandedTestSpec ) const { - std::string expandedTestSpec = unexpandedTestSpec; - for( std::map::const_iterator it = m_registry.begin(), itEnd = m_registry.end(); - it != itEnd; - ++it ) { - std::size_t pos = expandedTestSpec.find( it->first ); - if( pos != std::string::npos ) { - expandedTestSpec = expandedTestSpec.substr( 0, pos ) + - it->second.tag + - expandedTestSpec.substr( pos + it->first.size() ); - } - } - return expandedTestSpec; - } +#else - void TagAliasRegistry::add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) { + LeakDetector::LeakDetector(){} - if( !startsWith( alias, "[@" ) || !endsWith( alias, ']' ) ) { - std::ostringstream oss; - oss << Colour( Colour::Red ) - << "error: tag alias, \"" << alias << "\" is not of the form [@alias name].\n" - << Colour( Colour::FileName ) - << lineInfo << '\n'; - throw std::domain_error( oss.str().c_str() ); - } - if( !m_registry.insert( std::make_pair( alias, TagAlias( tag, lineInfo ) ) ).second ) { - std::ostringstream oss; - oss << Colour( Colour::Red ) - << "error: tag alias, \"" << alias << "\" already registered.\n" - << "\tFirst seen at " - << Colour( Colour::Red ) << find(alias)->lineInfo << '\n' - << Colour( Colour::Red ) << "\tRedefined at " - << Colour( Colour::FileName) << lineInfo << '\n'; - throw std::domain_error( oss.str().c_str() ); - } - } +#endif - ITagAliasRegistry::~ITagAliasRegistry() {} +} +// end catch_leak_detector.cpp +// start catch_list.cpp - ITagAliasRegistry const& ITagAliasRegistry::get() { - return getRegistryHub().getTagAliasRegistry(); - } +// start catch_list.h - RegistrarForTagAliases::RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) { - getMutableRegistryHub().registerTagAlias( alias, tag, lineInfo ); - } +#include + +namespace Catch { + + std::size_t listTests( Config const& config ); + + std::size_t listTestsNamesOnly( Config const& config ); + + struct TagInfo { + void add( std::string const& spelling ); + std::string all() const; + + std::set spellings; + std::size_t count = 0; + }; + + std::size_t listTags( Config const& config ); + + std::size_t listReporters( Config const& /*config*/ ); + + Option list( Config const& config ); } // end namespace Catch -// #included from: catch_matchers_string.hpp +// end catch_list.h +// start catch_text.h + +namespace Catch { + using namespace clara::TextFlow; +} + +// end catch_text.h +#include +#include +#include + +namespace Catch { + + std::size_t listTests( Config const& config ) { + TestSpec testSpec = config.testSpec(); + if( config.testSpec().hasFilters() ) + Catch::cout() << "Matching test cases:\n"; + else { + Catch::cout() << "All available test cases:\n"; + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); + } + + auto matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); + for( auto const& testCaseInfo : matchedTestCases ) { + Colour::Code colour = testCaseInfo.isHidden() + ? Colour::SecondaryText + : Colour::None; + Colour colourGuard( colour ); + + Catch::cout() << Column( testCaseInfo.name ).initialIndent( 2 ).indent( 4 ) << "\n"; + if( config.verbosity() >= Verbosity::High ) { + Catch::cout() << Column( Catch::Detail::stringify( testCaseInfo.lineInfo ) ).indent(4) << std::endl; + std::string description = testCaseInfo.description; + if( description.empty() ) + description = "(NO DESCRIPTION)"; + Catch::cout() << Column( description ).indent(4) << std::endl; + } + if( !testCaseInfo.tags.empty() ) + Catch::cout() << Column( testCaseInfo.tagsAsString() ).indent( 6 ) << "\n"; + } + + if( !config.testSpec().hasFilters() ) + Catch::cout() << pluralise( matchedTestCases.size(), "test case" ) << '\n' << std::endl; + else + Catch::cout() << pluralise( matchedTestCases.size(), "matching test case" ) << '\n' << std::endl; + return matchedTestCases.size(); + } + + std::size_t listTestsNamesOnly( Config const& config ) { + TestSpec testSpec = config.testSpec(); + if( !config.testSpec().hasFilters() ) + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); + std::size_t matchedTests = 0; + std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); + for( auto const& testCaseInfo : matchedTestCases ) { + matchedTests++; + if( startsWith( testCaseInfo.name, '#' ) ) + Catch::cout() << '"' << testCaseInfo.name << '"'; + else + Catch::cout() << testCaseInfo.name; + if ( config.verbosity() >= Verbosity::High ) + Catch::cout() << "\t@" << testCaseInfo.lineInfo; + Catch::cout() << std::endl; + } + return matchedTests; + } + + void TagInfo::add( std::string const& spelling ) { + ++count; + spellings.insert( spelling ); + } + + std::string TagInfo::all() const { + std::string out; + for( auto const& spelling : spellings ) + out += "[" + spelling + "]"; + return out; + } + + std::size_t listTags( Config const& config ) { + TestSpec testSpec = config.testSpec(); + if( config.testSpec().hasFilters() ) + Catch::cout() << "Tags for matching test cases:\n"; + else { + Catch::cout() << "All available tags:\n"; + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); + } + + std::map tagCounts; + + std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); + for( auto const& testCase : matchedTestCases ) { + for( auto const& tagName : testCase.getTestCaseInfo().tags ) { + std::string lcaseTagName = toLower( tagName ); + auto countIt = tagCounts.find( lcaseTagName ); + if( countIt == tagCounts.end() ) + countIt = tagCounts.insert( std::make_pair( lcaseTagName, TagInfo() ) ).first; + countIt->second.add( tagName ); + } + } + + for( auto const& tagCount : tagCounts ) { + std::ostringstream oss; + oss << " " << std::setw(2) << tagCount.second.count << " "; + auto wrapper = Column( tagCount.second.all() ) + .initialIndent( 0 ) + .indent( oss.str().size() ) + .width( CATCH_CONFIG_CONSOLE_WIDTH-10 ); + Catch::cout() << oss.str() << wrapper << '\n'; + } + Catch::cout() << pluralise( tagCounts.size(), "tag" ) << '\n' << std::endl; + return tagCounts.size(); + } + + std::size_t listReporters( Config const& /*config*/ ) { + Catch::cout() << "Available reporters:\n"; + IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories(); + std::size_t maxNameLen = 0; + for( auto const& factoryKvp : factories ) + maxNameLen = (std::max)( maxNameLen, factoryKvp.first.size() ); + + for( auto const& factoryKvp : factories ) { + Catch::cout() + << Column( factoryKvp.first + ":" ) + .indent(2) + .width( 5+maxNameLen ) + + Column( factoryKvp.second->getDescription() ) + .initialIndent(0) + .indent(2) + .width( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 ) + << "\n"; + } + Catch::cout() << std::endl; + return factories.size(); + } + + Option list( Config const& config ) { + Option listedCount; + if( config.listTests() ) + listedCount = listedCount.valueOr(0) + listTests( config ); + if( config.listTestNamesOnly() ) + listedCount = listedCount.valueOr(0) + listTestsNamesOnly( config ); + if( config.listTags() ) + listedCount = listedCount.valueOr(0) + listTags( config ); + if( config.listReporters() ) + listedCount = listedCount.valueOr(0) + listReporters( config ); + return listedCount; + } + +} // end namespace Catch +// end catch_list.cpp +// start catch_matchers.cpp + +namespace Catch { +namespace Matchers { + namespace Impl { + + std::string MatcherUntypedBase::toString() const { + if( m_cachedToString.empty() ) + m_cachedToString = describe(); + return m_cachedToString; + } + + MatcherUntypedBase::~MatcherUntypedBase() = default; + + } // namespace Impl +} // namespace Matchers + +using namespace Matchers; +using Matchers::Impl::MatcherBase; + +} // namespace Catch +// end catch_matchers.cpp +// start catch_matchers_string.cpp namespace Catch { namespace Matchers { @@ -9401,573 +7151,2744 @@ namespace Matchers { } // namespace Matchers } // namespace Catch -// #included from: ../reporters/catch_reporter_multi.hpp -#define TWOBLUECUBES_CATCH_REPORTER_MULTI_HPP_INCLUDED +// end catch_matchers_string.cpp +// start catch_message.cpp namespace Catch { -class MultipleReporters : public SharedImpl { - typedef std::vector > Reporters; - Reporters m_reporters; + MessageInfo::MessageInfo( std::string const& _macroName, + SourceLineInfo const& _lineInfo, + ResultWas::OfType _type ) + : macroName( _macroName ), + lineInfo( _lineInfo ), + type( _type ), + sequence( ++globalCount ) + {} -public: - void add( Ptr const& reporter ) { - m_reporters.push_back( reporter ); + bool MessageInfo::operator==( MessageInfo const& other ) const { + return sequence == other.sequence; } -public: // IStreamingReporter - - virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE { - return m_reporters[0]->getPreferences(); + bool MessageInfo::operator<( MessageInfo const& other ) const { + return sequence < other.sequence; } - virtual void noMatchingTestCases( std::string const& spec ) CATCH_OVERRIDE { - for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); - it != itEnd; - ++it ) - (*it)->noMatchingTestCases( spec ); + // This may need protecting if threading support is added + unsigned int MessageInfo::globalCount = 0; + + //////////////////////////////////////////////////////////////////////////// + + Catch::MessageBuilder::MessageBuilder( std::string const& macroName, + SourceLineInfo const& lineInfo, + ResultWas::OfType type ) + :m_info(macroName, lineInfo, type) {} + + //////////////////////////////////////////////////////////////////////////// + + ScopedMessage::ScopedMessage( MessageBuilder const& builder ) + : m_info( builder.m_info ) + { + m_info.message = builder.m_stream.str(); + getResultCapture().pushScopedMessage( m_info ); } - virtual void testRunStarting( TestRunInfo const& testRunInfo ) CATCH_OVERRIDE { - for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); - it != itEnd; - ++it ) - (*it)->testRunStarting( testRunInfo ); - } - - virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE { - for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); - it != itEnd; - ++it ) - (*it)->testGroupStarting( groupInfo ); - } - - virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { - for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); - it != itEnd; - ++it ) - (*it)->testCaseStarting( testInfo ); - } - - virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE { - for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); - it != itEnd; - ++it ) - (*it)->sectionStarting( sectionInfo ); - } - - virtual void assertionStarting( AssertionInfo const& assertionInfo ) CATCH_OVERRIDE { - for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); - it != itEnd; - ++it ) - (*it)->assertionStarting( assertionInfo ); - } - - // The return value indicates if the messages buffer should be cleared: - virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { - bool clearBuffer = false; - for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); - it != itEnd; - ++it ) - clearBuffer |= (*it)->assertionEnded( assertionStats ); - return clearBuffer; - } - - virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE { - for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); - it != itEnd; - ++it ) - (*it)->sectionEnded( sectionStats ); - } - - virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { - for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); - it != itEnd; - ++it ) - (*it)->testCaseEnded( testCaseStats ); - } - - virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { - for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); - it != itEnd; - ++it ) - (*it)->testGroupEnded( testGroupStats ); - } - - virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE { - for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); - it != itEnd; - ++it ) - (*it)->testRunEnded( testRunStats ); - } - - virtual void skipTest( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { - for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); - it != itEnd; - ++it ) - (*it)->skipTest( testInfo ); - } - - virtual MultipleReporters* tryAsMulti() CATCH_OVERRIDE { - return this; - } - -}; - -Ptr addReporter( Ptr const& existingReporter, Ptr const& additionalReporter ) { - Ptr resultingReporter; - - if( existingReporter ) { - MultipleReporters* multi = existingReporter->tryAsMulti(); - if( !multi ) { - multi = new MultipleReporters; - resultingReporter = Ptr( multi ); - if( existingReporter ) - multi->add( existingReporter ); + ScopedMessage::~ScopedMessage() { + if ( !std::uncaught_exception() ){ + getResultCapture().popScopedMessage(m_info); } - else - resultingReporter = existingReporter; - multi->add( additionalReporter ); } - else - resultingReporter = additionalReporter; - return resultingReporter; +} // end namespace Catch +// end catch_message.cpp +// start catch_random_number_generator.cpp + +// start catch_random_number_generator.h + +#include + +namespace Catch { + + struct IConfig; + + void seedRng( IConfig const& config ); + + unsigned int rngSeed(); + + struct RandomNumberGenerator { + using result_type = unsigned int; + + static constexpr result_type (min)() { return 0; } + static constexpr result_type (max)() { return 1000000; } + + result_type operator()( result_type n ) const; + result_type operator()() const; + + template + static void shuffle( V& vector ) { + RandomNumberGenerator rng; + std::shuffle( vector.begin(), vector.end(), rng ); + } + }; + } +// end catch_random_number_generator.h +#include + +namespace Catch { + + void seedRng( IConfig const& config ) { + if( config.rngSeed() != 0 ) + std::srand( config.rngSeed() ); + } + unsigned int rngSeed() { + return getCurrentContext().getConfig()->rngSeed(); + } + + RandomNumberGenerator::result_type RandomNumberGenerator::operator()( result_type n ) const { + return std::rand() % n; + } + RandomNumberGenerator::result_type RandomNumberGenerator::operator()() const { + return std::rand() % (max)(); + } + +} +// end catch_random_number_generator.cpp +// start catch_registry_hub.cpp + +// start catch_test_case_registry_impl.h + +#include +#include +#include +#include + +namespace Catch { + + class TestCase; + struct IConfig; + + std::vector sortTests( IConfig const& config, std::vector const& unsortedTestCases ); + bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); + + void enforceNoDuplicateTestCases( std::vector const& functions ); + + std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ); + std::vector const& getAllTestCasesSorted( IConfig const& config ); + + class TestRegistry : public ITestCaseRegistry { + public: + virtual ~TestRegistry() = default; + + virtual void registerTest( TestCase const& testCase ); + + std::vector const& getAllTests() const override; + std::vector const& getAllTestsSorted( IConfig const& config ) const override; + + private: + std::vector m_functions; + mutable RunTests::InWhatOrder m_currentSortOrder = RunTests::InDeclarationOrder; + mutable std::vector m_sortedFunctions; + std::size_t m_unnamedCount = 0; + std::ios_base::Init m_ostreamInit; // Forces cout/ cerr to be initialised + }; + + /////////////////////////////////////////////////////////////////////////// + + class TestInvokerAsFunction : public ITestInvoker { + void(*m_testAsFunction)(); + public: + TestInvokerAsFunction( void(*testAsFunction)() ) noexcept; + + void invoke() const override; + }; + + std::string extractClassName( std::string const& classOrQualifiedMethodName ); + + /////////////////////////////////////////////////////////////////////////// + } // end namespace Catch -// #included from: ../reporters/catch_reporter_xml.hpp -#define TWOBLUECUBES_CATCH_REPORTER_XML_HPP_INCLUDED +// end catch_test_case_registry_impl.h +// start catch_reporter_registry.h -// #included from: catch_reporter_bases.hpp -#define TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED +#include -#include -#include -#include -#include +namespace Catch { + class ReporterRegistry : public IReporterRegistry { + + public: + + ~ReporterRegistry() override; + + IStreamingReporterPtr create( std::string const& name, IConfigPtr const& config ) const override; + + void registerReporter( std::string const& name, IReporterFactoryPtr const& factory ); + void registerListener( IReporterFactoryPtr const& factory ); + + FactoryMap const& getFactories() const override; + Listeners const& getListeners() const override; + + private: + FactoryMap m_factories; + Listeners m_listeners; + }; +} + +// end catch_reporter_registry.h +// start catch_tag_alias_registry.h + +// start catch_tag_alias.h + +#include + +namespace Catch { + + struct TagAlias { + TagAlias(std::string const& _tag, SourceLineInfo _lineInfo); + + std::string tag; + SourceLineInfo lineInfo; + }; + +} // end namespace Catch + +// end catch_tag_alias.h +#include + +namespace Catch { + + class TagAliasRegistry : public ITagAliasRegistry { + public: + ~TagAliasRegistry() override; + TagAlias const* find( std::string const& alias ) const override; + std::string expandAliases( std::string const& unexpandedTestSpec ) const override; + void add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ); + + private: + std::map m_registry; + }; + +} // end namespace Catch + +// end catch_tag_alias_registry.h +// start catch_startup_exception_registry.h + +#include +#include + +namespace Catch { + + class StartupExceptionRegistry { + public: + void add(std::exception_ptr const& exception) noexcept; + std::vector const& getExceptions() const noexcept; + private: + std::vector m_exceptions; + }; + +} // end namespace Catch + +// end catch_startup_exception_registry.h namespace Catch { namespace { - // Because formatting using c++ streams is stateful, drop down to C is required - // Alternatively we could use stringstream, but its performance is... not good. - std::string getFormattedDuration( double duration ) { - // Max exponent + 1 is required to represent the whole part - // + 1 for decimal point - // + 3 for the 3 decimal places - // + 1 for null terminator - const size_t maxDoubleSize = DBL_MAX_10_EXP + 1 + 1 + 3 + 1; - char buffer[maxDoubleSize]; - // Save previous errno, to prevent sprintf from overwriting it - ErrnoGuard guard; -#ifdef _MSC_VER - sprintf_s(buffer, "%.3f", duration); -#else - sprintf(buffer, "%.3f", duration); -#endif - return std::string(buffer); - } - } + class RegistryHub : public IRegistryHub, public IMutableRegistryHub, + private NonCopyable { - struct StreamingReporterBase : SharedImpl { - - StreamingReporterBase( ReporterConfig const& _config ) - : m_config( _config.fullConfig() ), - stream( _config.stream() ) - { - m_reporterPrefs.shouldRedirectStdOut = false; - } - - virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE { - return m_reporterPrefs; - } - - virtual ~StreamingReporterBase() CATCH_OVERRIDE; - - virtual void noMatchingTestCases( std::string const& ) CATCH_OVERRIDE {} - - virtual void testRunStarting( TestRunInfo const& _testRunInfo ) CATCH_OVERRIDE { - currentTestRunInfo = _testRunInfo; - } - virtual void testGroupStarting( GroupInfo const& _groupInfo ) CATCH_OVERRIDE { - currentGroupInfo = _groupInfo; - } - - virtual void testCaseStarting( TestCaseInfo const& _testInfo ) CATCH_OVERRIDE { - currentTestCaseInfo = _testInfo; - } - virtual void sectionStarting( SectionInfo const& _sectionInfo ) CATCH_OVERRIDE { - m_sectionStack.push_back( _sectionInfo ); - } - - virtual void sectionEnded( SectionStats const& /* _sectionStats */ ) CATCH_OVERRIDE { - m_sectionStack.pop_back(); - } - virtual void testCaseEnded( TestCaseStats const& /* _testCaseStats */ ) CATCH_OVERRIDE { - currentTestCaseInfo.reset(); - } - virtual void testGroupEnded( TestGroupStats const& /* _testGroupStats */ ) CATCH_OVERRIDE { - currentGroupInfo.reset(); - } - virtual void testRunEnded( TestRunStats const& /* _testRunStats */ ) CATCH_OVERRIDE { - currentTestCaseInfo.reset(); - currentGroupInfo.reset(); - currentTestRunInfo.reset(); - } - - virtual void skipTest( TestCaseInfo const& ) CATCH_OVERRIDE { - // Don't do anything with this by default. - // It can optionally be overridden in the derived class. - } - - Ptr m_config; - std::ostream& stream; - - LazyStat currentTestRunInfo; - LazyStat currentGroupInfo; - LazyStat currentTestCaseInfo; - - std::vector m_sectionStack; - ReporterPreferences m_reporterPrefs; - }; - - struct CumulativeReporterBase : SharedImpl { - template - struct Node : SharedImpl<> { - explicit Node( T const& _value ) : value( _value ) {} - virtual ~Node() {} - - typedef std::vector > ChildNodes; - T value; - ChildNodes children; - }; - struct SectionNode : SharedImpl<> { - explicit SectionNode( SectionStats const& _stats ) : stats( _stats ) {} - virtual ~SectionNode(); - - bool operator == ( SectionNode const& other ) const { - return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo; + public: // IRegistryHub + RegistryHub() = default; + IReporterRegistry const& getReporterRegistry() const override { + return m_reporterRegistry; } - bool operator == ( Ptr const& other ) const { - return operator==( *other ); + ITestCaseRegistry const& getTestCaseRegistry() const override { + return m_testCaseRegistry; + } + IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() override { + return m_exceptionTranslatorRegistry; + } + ITagAliasRegistry const& getTagAliasRegistry() const override { + return m_tagAliasRegistry; + } + StartupExceptionRegistry const& getStartupExceptionRegistry() const override { + return m_exceptionRegistry; } - SectionStats stats; - typedef std::vector > ChildSections; - typedef std::vector Assertions; - ChildSections childSections; - Assertions assertions; - std::string stdOut; - std::string stdErr; - }; - - struct BySectionInfo { - BySectionInfo( SectionInfo const& other ) : m_other( other ) {} - BySectionInfo( BySectionInfo const& other ) : m_other( other.m_other ) {} - bool operator() ( Ptr const& node ) const { - return ((node->stats.sectionInfo.name == m_other.name) && - (node->stats.sectionInfo.lineInfo == m_other.lineInfo)); + public: // IMutableRegistryHub + void registerReporter( std::string const& name, IReporterFactoryPtr const& factory ) override { + m_reporterRegistry.registerReporter( name, factory ); } + void registerListener( IReporterFactoryPtr const& factory ) override { + m_reporterRegistry.registerListener( factory ); + } + void registerTest( TestCase const& testInfo ) override { + m_testCaseRegistry.registerTest( testInfo ); + } + void registerTranslator( const IExceptionTranslator* translator ) override { + m_exceptionTranslatorRegistry.registerTranslator( translator ); + } + void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) override { + m_tagAliasRegistry.add( alias, tag, lineInfo ); + } + void registerStartupException() noexcept override { + m_exceptionRegistry.add(std::current_exception()); + } + private: - void operator=( BySectionInfo const& ); - SectionInfo const& m_other; + TestRegistry m_testCaseRegistry; + ReporterRegistry m_reporterRegistry; + ExceptionTranslatorRegistry m_exceptionTranslatorRegistry; + TagAliasRegistry m_tagAliasRegistry; + StartupExceptionRegistry m_exceptionRegistry; }; - typedef Node TestCaseNode; - typedef Node TestGroupNode; - typedef Node TestRunNode; - - CumulativeReporterBase( ReporterConfig const& _config ) - : m_config( _config.fullConfig() ), - stream( _config.stream() ) - { - m_reporterPrefs.shouldRedirectStdOut = false; + // Single, global, instance + RegistryHub*& getTheRegistryHub() { + static RegistryHub* theRegistryHub = nullptr; + if( !theRegistryHub ) + theRegistryHub = new RegistryHub(); + return theRegistryHub; } - ~CumulativeReporterBase(); - - virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE { - return m_reporterPrefs; - } - - virtual void testRunStarting( TestRunInfo const& ) CATCH_OVERRIDE {} - virtual void testGroupStarting( GroupInfo const& ) CATCH_OVERRIDE {} - - virtual void testCaseStarting( TestCaseInfo const& ) CATCH_OVERRIDE {} - - virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE { - SectionStats incompleteStats( sectionInfo, Counts(), 0, false ); - Ptr node; - if( m_sectionStack.empty() ) { - if( !m_rootSection ) - m_rootSection = new SectionNode( incompleteStats ); - node = m_rootSection; - } - else { - SectionNode& parentNode = *m_sectionStack.back(); - SectionNode::ChildSections::const_iterator it = - std::find_if( parentNode.childSections.begin(), - parentNode.childSections.end(), - BySectionInfo( sectionInfo ) ); - if( it == parentNode.childSections.end() ) { - node = new SectionNode( incompleteStats ); - parentNode.childSections.push_back( node ); - } - else - node = *it; - } - m_sectionStack.push_back( node ); - m_deepestSection = node; - } - - virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {} - - virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { - assert( !m_sectionStack.empty() ); - SectionNode& sectionNode = *m_sectionStack.back(); - sectionNode.assertions.push_back( assertionStats ); - // AssertionResult holds a pointer to a temporary DecomposedExpression, - // which getExpandedExpression() calls to build the expression string. - // Our section stack copy of the assertionResult will likely outlive the - // temporary, so it must be expanded or discarded now to avoid calling - // a destroyed object later. - prepareExpandedExpression( sectionNode.assertions.back().assertionResult ); - return true; - } - virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE { - assert( !m_sectionStack.empty() ); - SectionNode& node = *m_sectionStack.back(); - node.stats = sectionStats; - m_sectionStack.pop_back(); - } - virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { - Ptr node = new TestCaseNode( testCaseStats ); - assert( m_sectionStack.size() == 0 ); - node->children.push_back( m_rootSection ); - m_testCases.push_back( node ); - m_rootSection.reset(); - - assert( m_deepestSection ); - m_deepestSection->stdOut = testCaseStats.stdOut; - m_deepestSection->stdErr = testCaseStats.stdErr; - } - virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { - Ptr node = new TestGroupNode( testGroupStats ); - node->children.swap( m_testCases ); - m_testGroups.push_back( node ); - } - virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE { - Ptr node = new TestRunNode( testRunStats ); - node->children.swap( m_testGroups ); - m_testRuns.push_back( node ); - testRunEndedCumulative(); - } - virtual void testRunEndedCumulative() = 0; - - virtual void skipTest( TestCaseInfo const& ) CATCH_OVERRIDE {} - - virtual void prepareExpandedExpression( AssertionResult& result ) const { - if( result.isOk() ) - result.discardDecomposedExpression(); - else - result.expandDecomposedExpression(); - } - - Ptr m_config; - std::ostream& stream; - std::vector m_assertions; - std::vector > > m_sections; - std::vector > m_testCases; - std::vector > m_testGroups; - - std::vector > m_testRuns; - - Ptr m_rootSection; - Ptr m_deepestSection; - std::vector > m_sectionStack; - ReporterPreferences m_reporterPrefs; - - }; - - template - char const* getLineOfChars() { - static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0}; - if( !*line ) { - std::memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 ); - line[CATCH_CONFIG_CONSOLE_WIDTH-1] = 0; - } - return line; } - struct TestEventListenerBase : StreamingReporterBase { - TestEventListenerBase( ReporterConfig const& _config ) - : StreamingReporterBase( _config ) - {} + IRegistryHub& getRegistryHub() { + return *getTheRegistryHub(); + } + IMutableRegistryHub& getMutableRegistryHub() { + return *getTheRegistryHub(); + } + void cleanUp() { + delete getTheRegistryHub(); + getTheRegistryHub() = nullptr; + cleanUpContext(); + } + std::string translateActiveException() { + return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException(); + } - virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {} - virtual bool assertionEnded( AssertionStats const& ) CATCH_OVERRIDE { - return false; +} // end namespace Catch +// end catch_registry_hub.cpp +// start catch_reporter_registry.cpp + +namespace Catch { + + ReporterRegistry::~ReporterRegistry() = default; + + IStreamingReporterPtr ReporterRegistry::create( std::string const& name, IConfigPtr const& config ) const { + auto it = m_factories.find( name ); + if( it == m_factories.end() ) + return nullptr; + return it->second->create( ReporterConfig( config ) ); + } + + void ReporterRegistry::registerReporter( std::string const& name, IReporterFactoryPtr const& factory ) { + m_factories.emplace(name, factory); + } + void ReporterRegistry::registerListener( IReporterFactoryPtr const& factory ) { + m_listeners.push_back( factory ); + } + + IReporterRegistry::FactoryMap const& ReporterRegistry::getFactories() const { + return m_factories; + } + IReporterRegistry::Listeners const& ReporterRegistry::getListeners() const { + return m_listeners; + } + +} +// end catch_reporter_registry.cpp +// start catch_result_type.cpp + +namespace Catch { + + bool isOk( ResultWas::OfType resultType ) { + return ( resultType & ResultWas::FailureBit ) == 0; + } + bool isJustInfo( int flags ) { + return flags == ResultWas::Info; + } + + ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) { + return static_cast( static_cast( lhs ) | static_cast( rhs ) ); + } + + bool shouldContinueOnFailure( int flags ) { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; } + bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; } + bool shouldSuppressFailure( int flags ) { return ( flags & ResultDisposition::SuppressFail ) != 0; } + +} // end namespace Catch +// end catch_result_type.cpp +// start catch_run_context.cpp +// start catch_run_context.h + +#include + +namespace Catch { + + struct IMutableContext; + + class StreamRedirect { + + public: + StreamRedirect(std::ostream& stream, std::string& targetString); + + ~StreamRedirect(); + + private: + std::ostream& m_stream; + std::streambuf* m_prevBuf; + std::ostringstream m_oss; + std::string& m_targetString; + }; + + // StdErr has two constituent streams in C++, std::cerr and std::clog + // This means that we need to redirect 2 streams into 1 to keep proper + // order of writes and cannot use StreamRedirect on its own + class StdErrRedirect { + public: + StdErrRedirect(std::string& targetString); + ~StdErrRedirect(); + private: + std::streambuf* m_cerrBuf; + std::streambuf* m_clogBuf; + std::ostringstream m_oss; + std::string& m_targetString; + }; + + /////////////////////////////////////////////////////////////////////////// + + class RunContext : public IResultCapture, public IRunner { + + public: + RunContext( RunContext const& ) = delete; + RunContext& operator =( RunContext const& ) = delete; + + explicit RunContext(IConfigPtr const& _config, IStreamingReporterPtr&& reporter); + + virtual ~RunContext(); + + void testGroupStarting(std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount); + void testGroupEnded(std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount); + + Totals runTest(TestCase const& testCase); + + IConfigPtr config() const; + IStreamingReporter& reporter() const; + + private: // IResultCapture + + void assertionStarting(AssertionInfo const& info) override; + void assertionEnded(AssertionResult const& result) override; + + bool sectionStarted( SectionInfo const& sectionInfo, Counts& assertions ) override; + bool testForMissingAssertions(Counts& assertions); + + void sectionEnded(SectionEndInfo const& endInfo) override; + void sectionEndedEarly(SectionEndInfo const& endInfo) override; + + void benchmarkStarting( BenchmarkInfo const& info ) override; + void benchmarkEnded( BenchmarkStats const& stats ) override; + + void pushScopedMessage(MessageInfo const& message) override; + void popScopedMessage(MessageInfo const& message) override; + + std::string getCurrentTestName() const override; + + const AssertionResult* getLastResult() const override; + + void exceptionEarlyReported() override; + + void handleFatalErrorCondition( StringRef message ) override; + + bool lastAssertionPassed() override; + + void assertionPassed() override; + + void assertionRun() override; + + public: + // !TBD We need to do this another way! + bool aborting() const override; + + private: + + void runCurrentTest(std::string& redirectedCout, std::string& redirectedCerr); + void invokeActiveTestCase(); + + private: + + void handleUnfinishedSections(); + + TestRunInfo m_runInfo; + IMutableContext& m_context; + TestCase const* m_activeTestCase = nullptr; + ITracker* m_testCaseTracker; + Option m_lastResult; + + IConfigPtr m_config; + Totals m_totals; + IStreamingReporterPtr m_reporter; + std::vector m_messages; + AssertionInfo m_lastAssertionInfo; + std::vector m_unfinishedSections; + std::vector m_activeSections; + TrackerContext m_trackerContext; + std::size_t m_prevPassed = 0; + bool m_shouldReportUnexpected = true; + }; + + IResultCapture& getResultCapture(); + +} // end namespace Catch + +// end catch_run_context.h + +#include +#include + +namespace Catch { + + StreamRedirect::StreamRedirect(std::ostream& stream, std::string& targetString) + : m_stream(stream), + m_prevBuf(stream.rdbuf()), + m_targetString(targetString) { + stream.rdbuf(m_oss.rdbuf()); + } + + StreamRedirect::~StreamRedirect() { + m_targetString += m_oss.str(); + m_stream.rdbuf(m_prevBuf); + } + + StdErrRedirect::StdErrRedirect(std::string & targetString) + :m_cerrBuf(cerr().rdbuf()), m_clogBuf(clog().rdbuf()), + m_targetString(targetString) { + cerr().rdbuf(m_oss.rdbuf()); + clog().rdbuf(m_oss.rdbuf()); + } + + StdErrRedirect::~StdErrRedirect() { + m_targetString += m_oss.str(); + cerr().rdbuf(m_cerrBuf); + clog().rdbuf(m_clogBuf); + } + + RunContext::RunContext(IConfigPtr const& _config, IStreamingReporterPtr&& reporter) + : m_runInfo(_config->name()), + m_context(getCurrentMutableContext()), + m_config(_config), + m_reporter(std::move(reporter)), + m_lastAssertionInfo{ "", SourceLineInfo("",0), "", ResultDisposition::Normal } + { + m_context.setRunner(this); + m_context.setConfig(m_config); + m_context.setResultCapture(this); + m_reporter->testRunStarting(m_runInfo); + } + + RunContext::~RunContext() { + m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, aborting())); + } + + void RunContext::testGroupStarting(std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount) { + m_reporter->testGroupStarting(GroupInfo(testSpec, groupIndex, groupsCount)); + } + + void RunContext::testGroupEnded(std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount) { + m_reporter->testGroupEnded(TestGroupStats(GroupInfo(testSpec, groupIndex, groupsCount), totals, aborting())); + } + + Totals RunContext::runTest(TestCase const& testCase) { + Totals prevTotals = m_totals; + + std::string redirectedCout; + std::string redirectedCerr; + + TestCaseInfo testInfo = testCase.getTestCaseInfo(); + + m_reporter->testCaseStarting(testInfo); + + m_activeTestCase = &testCase; + + ITracker& rootTracker = m_trackerContext.startRun(); + assert(rootTracker.isSectionTracker()); + static_cast(rootTracker).addInitialFilters(m_config->getSectionsToRun()); + do { + m_trackerContext.startCycle(); + m_testCaseTracker = &SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocation(testInfo.name, testInfo.lineInfo)); + runCurrentTest(redirectedCout, redirectedCerr); + } while (!m_testCaseTracker->isSuccessfullyCompleted() && !aborting()); + + Totals deltaTotals = m_totals.delta(prevTotals); + if (testInfo.expectedToFail() && deltaTotals.testCases.passed > 0) { + deltaTotals.assertions.failed++; + deltaTotals.testCases.passed--; + deltaTotals.testCases.failed++; } + m_totals.testCases += deltaTotals.testCases; + m_reporter->testCaseEnded(TestCaseStats(testInfo, + deltaTotals, + redirectedCout, + redirectedCerr, + aborting())); + + m_activeTestCase = nullptr; + m_testCaseTracker = nullptr; + + return deltaTotals; + } + + IConfigPtr RunContext::config() const { + return m_config; + } + + IStreamingReporter& RunContext::reporter() const { + return *m_reporter; + } + + void RunContext::assertionStarting(AssertionInfo const& info) { + m_reporter->assertionStarting( info ); + } + void RunContext::assertionEnded(AssertionResult const & result) { + if (result.getResultType() == ResultWas::Ok) { + m_totals.assertions.passed++; + } else if (!result.isOk()) { + if( m_activeTestCase->getTestCaseInfo().okToFail() ) + m_totals.assertions.failedButOk++; + else + m_totals.assertions.failed++; + } + + // We have no use for the return value (whether messages should be cleared), because messages were made scoped + // and should be let to clear themselves out. + static_cast(m_reporter->assertionEnded(AssertionStats(result, m_messages, m_totals))); + + // Reset working state + m_lastAssertionInfo = { "", m_lastAssertionInfo.lineInfo, "{Unknown expression after the reported line}", m_lastAssertionInfo.resultDisposition }; + m_lastResult = result; + } + + bool RunContext::sectionStarted(SectionInfo const & sectionInfo, Counts & assertions) { + ITracker& sectionTracker = SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocation(sectionInfo.name, sectionInfo.lineInfo)); + if (!sectionTracker.isOpen()) + return false; + m_activeSections.push_back(§ionTracker); + + m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo; + + m_reporter->sectionStarting(sectionInfo); + + assertions = m_totals.assertions; + + return true; + } + + bool RunContext::testForMissingAssertions(Counts& assertions) { + if (assertions.total() != 0) + return false; + if (!m_config->warnAboutMissingAssertions()) + return false; + if (m_trackerContext.currentTracker().hasChildren()) + return false; + m_totals.assertions.failed++; + assertions.failed++; + return true; + } + + void RunContext::sectionEnded(SectionEndInfo const & endInfo) { + Counts assertions = m_totals.assertions - endInfo.prevAssertions; + bool missingAssertions = testForMissingAssertions(assertions); + + if (!m_activeSections.empty()) { + m_activeSections.back()->close(); + m_activeSections.pop_back(); + } + + m_reporter->sectionEnded(SectionStats(endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions)); + m_messages.clear(); + } + + void RunContext::sectionEndedEarly(SectionEndInfo const & endInfo) { + if (m_unfinishedSections.empty()) + m_activeSections.back()->fail(); + else + m_activeSections.back()->close(); + m_activeSections.pop_back(); + + m_unfinishedSections.push_back(endInfo); + } + void RunContext::benchmarkStarting( BenchmarkInfo const& info ) { + m_reporter->benchmarkStarting( info ); + } + void RunContext::benchmarkEnded( BenchmarkStats const& stats ) { + m_reporter->benchmarkEnded( stats ); + } + + void RunContext::pushScopedMessage(MessageInfo const & message) { + m_messages.push_back(message); + } + + void RunContext::popScopedMessage(MessageInfo const & message) { + m_messages.erase(std::remove(m_messages.begin(), m_messages.end(), message), m_messages.end()); + } + + std::string RunContext::getCurrentTestName() const { + return m_activeTestCase + ? m_activeTestCase->getTestCaseInfo().name + : std::string(); + } + + const AssertionResult * RunContext::getLastResult() const { + return &(*m_lastResult); + } + + void RunContext::exceptionEarlyReported() { + m_shouldReportUnexpected = false; + } + + void RunContext::handleFatalErrorCondition( StringRef message ) { + // First notify reporter that bad things happened + m_reporter->fatalErrorEncountered(message); + + // Don't rebuild the result -- the stringification itself can cause more fatal errors + // Instead, fake a result data. + AssertionResultData tempResult( ResultWas::FatalErrorCondition, { false } ); + tempResult.message = message; + AssertionResult result(m_lastAssertionInfo, tempResult); + + getResultCapture().assertionEnded(result); + + handleUnfinishedSections(); + + // Recreate section for test case (as we will lose the one that was in scope) + auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); + SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description); + + Counts assertions; + assertions.failed = 1; + SectionStats testCaseSectionStats(testCaseSection, assertions, 0, false); + m_reporter->sectionEnded(testCaseSectionStats); + + auto const& testInfo = m_activeTestCase->getTestCaseInfo(); + + Totals deltaTotals; + deltaTotals.testCases.failed = 1; + deltaTotals.assertions.failed = 1; + m_reporter->testCaseEnded(TestCaseStats(testInfo, + deltaTotals, + std::string(), + std::string(), + false)); + m_totals.testCases.failed++; + testGroupEnded(std::string(), m_totals, 1, 1); + m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, false)); + } + + bool RunContext::lastAssertionPassed() { + return m_totals.assertions.passed == (m_prevPassed + 1); + } + + void RunContext::assertionPassed() { + ++m_totals.assertions.passed; + m_lastAssertionInfo.capturedExpression = "{Unknown expression after the reported line}"; + m_lastAssertionInfo.macroName = ""; + } + + void RunContext::assertionRun() { + m_prevPassed = m_totals.assertions.passed; + } + + bool RunContext::aborting() const { + return m_totals.assertions.failed == static_cast(m_config->abortAfter()); + } + + void RunContext::runCurrentTest(std::string & redirectedCout, std::string & redirectedCerr) { + auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); + SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description); + m_reporter->sectionStarting(testCaseSection); + Counts prevAssertions = m_totals.assertions; + double duration = 0; + m_shouldReportUnexpected = true; + try { + m_lastAssertionInfo = { "TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal }; + + seedRng(*m_config); + + Timer timer; + timer.start(); + if (m_reporter->getPreferences().shouldRedirectStdOut) { + StreamRedirect coutRedir(cout(), redirectedCout); + StdErrRedirect errRedir(redirectedCerr); + invokeActiveTestCase(); + } else { + invokeActiveTestCase(); + } + duration = timer.getElapsedSeconds(); + } catch (TestFailureException&) { + // This just means the test was aborted due to failure + } catch (...) { + // Under CATCH_CONFIG_FAST_COMPILE, unexpected exceptions under REQUIRE assertions + // are reported without translation at the point of origin. + if (m_shouldReportUnexpected) { + AssertionHandler + ( m_lastAssertionInfo.macroName, + m_lastAssertionInfo.lineInfo, + m_lastAssertionInfo.capturedExpression, + m_lastAssertionInfo.resultDisposition ).useActiveException(); + } + } + m_testCaseTracker->close(); + handleUnfinishedSections(); + m_messages.clear(); + + Counts assertions = m_totals.assertions - prevAssertions; + bool missingAssertions = testForMissingAssertions(assertions); + SectionStats testCaseSectionStats(testCaseSection, assertions, duration, missingAssertions); + m_reporter->sectionEnded(testCaseSectionStats); + } + + void RunContext::invokeActiveTestCase() { + FatalConditionHandler fatalConditionHandler; // Handle signals + m_activeTestCase->invoke(); + fatalConditionHandler.reset(); + } + + void RunContext::handleUnfinishedSections() { + // If sections ended prematurely due to an exception we stored their + // infos here so we can tear them down outside the unwind process. + for (auto it = m_unfinishedSections.rbegin(), + itEnd = m_unfinishedSections.rend(); + it != itEnd; + ++it) + sectionEnded(*it); + m_unfinishedSections.clear(); + } + + IResultCapture& getResultCapture() { + if (auto* capture = getCurrentContext().getResultCapture()) + return *capture; + else + CATCH_INTERNAL_ERROR("No result capture instance"); + } +} +// end catch_run_context.cpp +// start catch_section.cpp + +namespace Catch { + + Section::Section( SectionInfo const& info ) + : m_info( info ), + m_sectionIncluded( getResultCapture().sectionStarted( m_info, m_assertions ) ) + { + m_timer.start(); + } + +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable:4996) // std::uncaught_exception is deprecated in C++17 +#endif + Section::~Section() { + if( m_sectionIncluded ) { + SectionEndInfo endInfo( m_info, m_assertions, m_timer.getElapsedSeconds() ); + if( std::uncaught_exception() ) + getResultCapture().sectionEndedEarly( endInfo ); + else + getResultCapture().sectionEnded( endInfo ); + } + } +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + + // This indicates whether the section should be executed or not + Section::operator bool() const { + return m_sectionIncluded; + } + +} // end namespace Catch +// end catch_section.cpp +// start catch_section_info.cpp + +namespace Catch { + + SectionInfo::SectionInfo + ( SourceLineInfo const& _lineInfo, + std::string const& _name, + std::string const& _description ) + : name( _name ), + description( _description ), + lineInfo( _lineInfo ) + {} + + SectionEndInfo::SectionEndInfo( SectionInfo const& _sectionInfo, Counts const& _prevAssertions, double _durationInSeconds ) + : sectionInfo( _sectionInfo ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds ) + {} + +} // end namespace Catch +// end catch_section_info.cpp +// start catch_session.cpp + +// start catch_session.h + +#include + +namespace Catch { + + class Session : NonCopyable { + public: + + Session(); + ~Session() override; + + void showHelp() const; + void libIdentify(); + + int applyCommandLine( int argc, char* argv[] ); + + void useConfigData( ConfigData const& configData ); + + int run( int argc, char* argv[] ); + #if defined(WIN32) && defined(UNICODE) + int run( int argc, wchar_t* const argv[] ); + #endif + int run(); + + clara::Parser const& cli() const; + void cli( clara::Parser const& newParser ); + ConfigData& configData(); + Config& config(); + private: + int runInternal(); + + clara::Parser m_cli; + ConfigData m_configData; + std::shared_ptr m_config; + bool m_startupExceptions = false; }; } // end namespace Catch -// #included from: ../internal/catch_reporter_registrars.hpp -#define TWOBLUECUBES_CATCH_REPORTER_REGISTRARS_HPP_INCLUDED +// end catch_session.h +// start catch_version.h + +#include namespace Catch { - template - class LegacyReporterRegistrar { + // Versioning information + struct Version { + Version( Version const& ) = delete; + Version& operator=( Version const& ) = delete; + Version( unsigned int _majorVersion, + unsigned int _minorVersion, + unsigned int _patchNumber, + char const * const _branchName, + unsigned int _buildNumber ); - class ReporterFactory : public IReporterFactory { - virtual IStreamingReporter* create( ReporterConfig const& config ) const { - return new LegacyReporterAdapter( new T( config ) ); - } + unsigned int const majorVersion; + unsigned int const minorVersion; + unsigned int const patchNumber; - virtual std::string getDescription() const { - return T::getDescription(); - } - }; + // buildNumber is only used if branchName is not null + char const * const branchName; + unsigned int const buildNumber; - public: - - LegacyReporterRegistrar( std::string const& name ) { - getMutableRegistryHub().registerReporter( name, new ReporterFactory() ); - } + friend std::ostream& operator << ( std::ostream& os, Version const& version ); }; - template - class ReporterRegistrar { - - class ReporterFactory : public SharedImpl { - - // *** Please Note ***: - // - If you end up here looking at a compiler error because it's trying to register - // your custom reporter class be aware that the native reporter interface has changed - // to IStreamingReporter. The "legacy" interface, IReporter, is still supported via - // an adapter. Just use REGISTER_LEGACY_REPORTER to take advantage of the adapter. - // However please consider updating to the new interface as the old one is now - // deprecated and will probably be removed quite soon! - // Please contact me via github if you have any questions at all about this. - // In fact, ideally, please contact me anyway to let me know you've hit this - as I have - // no idea who is actually using custom reporters at all (possibly no-one!). - // The new interface is designed to minimise exposure to interface changes in the future. - virtual IStreamingReporter* create( ReporterConfig const& config ) const { - return new T( config ); - } - - virtual std::string getDescription() const { - return T::getDescription(); - } - }; - - public: - - ReporterRegistrar( std::string const& name ) { - getMutableRegistryHub().registerReporter( name, new ReporterFactory() ); - } - }; - - template - class ListenerRegistrar { - - class ListenerFactory : public SharedImpl { - - virtual IStreamingReporter* create( ReporterConfig const& config ) const { - return new T( config ); - } - virtual std::string getDescription() const { - return std::string(); - } - }; - - public: - - ListenerRegistrar() { - getMutableRegistryHub().registerListener( new ListenerFactory() ); - } - }; + Version const& libraryVersion(); } -#define INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) \ - namespace{ Catch::LegacyReporterRegistrar catch_internal_RegistrarFor##reporterType( name ); } +// end catch_version.h +#include +#include -#define INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) \ - namespace{ Catch::ReporterRegistrar catch_internal_RegistrarFor##reporterType( name ); } +namespace { + const int MaxExitCode = 255; + using Catch::IStreamingReporterPtr; + using Catch::IConfigPtr; + using Catch::Config; -// Deprecated - use the form without INTERNAL_ -#define INTERNAL_CATCH_REGISTER_LISTENER( listenerType ) \ - namespace{ Catch::ListenerRegistrar catch_internal_RegistrarFor##listenerType; } + IStreamingReporterPtr createReporter(std::string const& reporterName, IConfigPtr const& config) { + auto reporter = Catch::getRegistryHub().getReporterRegistry().create(reporterName, config); + CATCH_ENFORCE(reporter, "No reporter registered with name: '" << reporterName << "'"); -#define CATCH_REGISTER_LISTENER( listenerType ) \ - namespace{ Catch::ListenerRegistrar catch_internal_RegistrarFor##listenerType; } + return reporter; + } -// #included from: ../internal/catch_xmlwriter.hpp -#define TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED +#ifndef CATCH_CONFIG_DEFAULT_REPORTER +#define CATCH_CONFIG_DEFAULT_REPORTER "console" +#endif + + IStreamingReporterPtr makeReporter(std::shared_ptr const& config) { + auto const& reporterNames = config->getReporterNames(); + if (reporterNames.empty()) + return createReporter(CATCH_CONFIG_DEFAULT_REPORTER, config); + + IStreamingReporterPtr reporter; + for (auto const& name : reporterNames) + addReporter(reporter, createReporter(name, config)); + return reporter; + } + +#undef CATCH_CONFIG_DEFAULT_REPORTER + + void addListeners(IStreamingReporterPtr& reporters, IConfigPtr const& config) { + auto const& listeners = Catch::getRegistryHub().getReporterRegistry().getListeners(); + for (auto const& listener : listeners) + addReporter(reporters, listener->create(Catch::ReporterConfig(config))); + } + + Catch::Totals runTests(std::shared_ptr const& config) { + using namespace Catch; + IStreamingReporterPtr reporter = makeReporter(config); + addListeners(reporter, config); + + RunContext context(config, std::move(reporter)); + + Totals totals; + + context.testGroupStarting(config->name(), 1, 1); + + TestSpec testSpec = config->testSpec(); + if (!testSpec.hasFilters()) + testSpec = TestSpecParser(ITagAliasRegistry::get()).parse("~[.]").testSpec(); // All not hidden tests + + auto const& allTestCases = getAllTestCasesSorted(*config); + for (auto const& testCase : allTestCases) { + if (!context.aborting() && matchTest(testCase, testSpec, *config)) + totals += context.runTest(testCase); + else + context.reporter().skipTest(testCase); + } + + context.testGroupEnded(config->name(), totals, 1, 1); + return totals; + } + + void applyFilenamesAsTags(Catch::IConfig const& config) { + using namespace Catch; + auto& tests = const_cast&>(getAllTestCasesSorted(config)); + for (auto& testCase : tests) { + auto tags = testCase.tags; + + std::string filename = testCase.lineInfo.file; + auto lastSlash = filename.find_last_of("\\/"); + if (lastSlash != std::string::npos) { + filename.erase(0, lastSlash); + filename[0] = '#'; + } + + auto lastDot = filename.find_last_of('.'); + if (lastDot != std::string::npos) { + filename.erase(lastDot); + } + + tags.push_back(std::move(filename)); + setTags(testCase, tags); + } + } + +} + +namespace Catch { + + Session::Session() { + static bool alreadyInstantiated = false; + if( alreadyInstantiated ) { + try { CATCH_INTERNAL_ERROR( "Only one instance of Catch::Session can ever be used" ); } + catch(...) { getMutableRegistryHub().registerStartupException(); } + } + + const auto& exceptions = getRegistryHub().getStartupExceptionRegistry().getExceptions(); + if ( !exceptions.empty() ) { + m_startupExceptions = true; + Colour colourGuard( Colour::Red ); + Catch::cerr() << "Errors occured during startup!" << '\n'; + // iterate over all exceptions and notify user + for ( const auto& ex_ptr : exceptions ) { + try { + std::rethrow_exception(ex_ptr); + } catch ( std::exception const& ex ) { + Catch::cerr() << Column( ex.what() ).indent(2) << '\n'; + } + } + } + + alreadyInstantiated = true; + m_cli = makeCommandLineParser( m_configData ); + } + Session::~Session() { + Catch::cleanUp(); + } + + void Session::showHelp() const { + Catch::cout() + << "\nCatch v" << libraryVersion() << "\n" + << m_cli << std::endl + << "For more detailed usage please see the project docs\n" << std::endl; + } + void Session::libIdentify() { + Catch::cout() + << std::left << std::setw(16) << "description: " << "A Catch test executable\n" + << std::left << std::setw(16) << "category: " << "testframework\n" + << std::left << std::setw(16) << "framework: " << "Catch Test\n" + << std::left << std::setw(16) << "version: " << libraryVersion() << std::endl; + } + + int Session::applyCommandLine( int argc, char* argv[] ) { + if( m_startupExceptions ) + return 1; + + auto result = m_cli.parse( clara::Args( argc, argv ) ); + if( !result ) { + Catch::cerr() + << Colour( Colour::Red ) + << "\nError(s) in input:\n" + << Column( result.errorMessage() ).indent( 2 ) + << "\n\n"; + Catch::cerr() << "Run with -? for usage\n" << std::endl; + return MaxExitCode; + } + + if( m_configData.showHelp ) + showHelp(); + if( m_configData.libIdentify ) + libIdentify(); + m_config.reset(); + return 0; + } + + void Session::useConfigData( ConfigData const& configData ) { + m_configData = configData; + m_config.reset(); + } + + int Session::run( int argc, char* argv[] ) { + if( m_startupExceptions ) + return 1; + int returnCode = applyCommandLine( argc, argv ); + if( returnCode == 0 ) + returnCode = run(); + return returnCode; + } + +#if defined(WIN32) && defined(UNICODE) + int Session::run( int argc, wchar_t* const argv[] ) { + + char **utf8Argv = new char *[ argc ]; + + for ( int i = 0; i < argc; ++i ) { + int bufSize = WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, NULL, 0, NULL, NULL ); + + utf8Argv[ i ] = new char[ bufSize ]; + + WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, NULL, NULL ); + } + + int returnCode = run( argc, utf8Argv ); + + for ( int i = 0; i < argc; ++i ) + delete [] utf8Argv[ i ]; + + delete [] utf8Argv; + + return returnCode; + } +#endif + int Session::run() { + if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeStart ) != 0 ) { + Catch::cout() << "...waiting for enter/ return before starting" << std::endl; + static_cast(std::getchar()); + } + int exitCode = runInternal(); + if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeExit ) != 0 ) { + Catch::cout() << "...waiting for enter/ return before exiting, with code: " << exitCode << std::endl; + static_cast(std::getchar()); + } + return exitCode; + } + + clara::Parser const& Session::cli() const { + return m_cli; + } + void Session::cli( clara::Parser const& newParser ) { + m_cli = newParser; + } + ConfigData& Session::configData() { + return m_configData; + } + Config& Session::config() { + if( !m_config ) + m_config = std::make_shared( m_configData ); + return *m_config; + } + + int Session::runInternal() { + if( m_startupExceptions ) + return 1; + + if( m_configData.showHelp || m_configData.libIdentify ) + return 0; + + try + { + config(); // Force config to be constructed + + seedRng( *m_config ); + + if( m_configData.filenamesAsTags ) + applyFilenamesAsTags( *m_config ); + + // Handle list request + if( Option listed = list( config() ) ) + return static_cast( *listed ); + + return (std::min)( MaxExitCode, static_cast( runTests( m_config ).assertions.failed ) ); + } + catch( std::exception& ex ) { + Catch::cerr() << ex.what() << std::endl; + return MaxExitCode; + } + } + +} // end namespace Catch +// end catch_session.cpp +// start catch_startup_exception_registry.cpp + +namespace Catch { + void StartupExceptionRegistry::add( std::exception_ptr const& exception ) noexcept { + try { + m_exceptions.push_back(exception); + } + catch(...) { + // If we run out of memory during start-up there's really not a lot more we can do about it + std::terminate(); + } + } + + std::vector const& StartupExceptionRegistry::getExceptions() const noexcept { + return m_exceptions; + } + +} // end namespace Catch +// end catch_startup_exception_registry.cpp +// start catch_stream.cpp + +#include +#include +#include + +namespace Catch { + + template + class StreamBufImpl : public StreamBufBase { + char data[bufferSize]; + WriterF m_writer; + + public: + StreamBufImpl() { + setp( data, data + sizeof(data) ); + } + + ~StreamBufImpl() noexcept { + StreamBufImpl::sync(); + } + + private: + int overflow( int c ) override { + sync(); + + if( c != EOF ) { + if( pbase() == epptr() ) + m_writer( std::string( 1, static_cast( c ) ) ); + else + sputc( static_cast( c ) ); + } + return 0; + } + + int sync() override { + if( pbase() != pptr() ) { + m_writer( std::string( pbase(), static_cast( pptr() - pbase() ) ) ); + setp( pbase(), epptr() ); + } + return 0; + } + }; + + /////////////////////////////////////////////////////////////////////////// + + Catch::IStream::~IStream() = default; + + FileStream::FileStream( std::string const& filename ) { + m_ofs.open( filename.c_str() ); + CATCH_ENFORCE( !m_ofs.fail(), "Unable to open file: '" << filename << "'" ); + } + + std::ostream& FileStream::stream() const { + return m_ofs; + } + + struct OutputDebugWriter { + + void operator()( std::string const&str ) { + writeToDebugConsole( str ); + } + }; + + DebugOutStream::DebugOutStream() + : m_streamBuf( new StreamBufImpl() ), + m_os( m_streamBuf.get() ) + {} + + std::ostream& DebugOutStream::stream() const { + return m_os; + } + + // Store the streambuf from cout up-front because + // cout may get redirected when running tests + CoutStream::CoutStream() + : m_os( Catch::cout().rdbuf() ) + {} + + std::ostream& CoutStream::stream() const { + return m_os; + } + +#ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement these functions + std::ostream& cout() { + return std::cout; + } + std::ostream& cerr() { + return std::cerr; + } + std::ostream& clog() { + return std::clog; + } +#endif +} +// end catch_stream.cpp +// start catch_streambuf.cpp + +namespace Catch { + StreamBufBase::~StreamBufBase() = default; +} +// end catch_streambuf.cpp +// start catch_string_manip.cpp + +#include +#include +#include +#include + +namespace Catch { + + bool startsWith( std::string const& s, std::string const& prefix ) { + return s.size() >= prefix.size() && std::equal(prefix.begin(), prefix.end(), s.begin()); + } + bool startsWith( std::string const& s, char prefix ) { + return !s.empty() && s[0] == prefix; + } + bool endsWith( std::string const& s, std::string const& suffix ) { + return s.size() >= suffix.size() && std::equal(suffix.rbegin(), suffix.rend(), s.rbegin()); + } + bool endsWith( std::string const& s, char suffix ) { + return !s.empty() && s[s.size()-1] == suffix; + } + bool contains( std::string const& s, std::string const& infix ) { + return s.find( infix ) != std::string::npos; + } + char toLowerCh(char c) { + return static_cast( std::tolower( c ) ); + } + void toLowerInPlace( std::string& s ) { + std::transform( s.begin(), s.end(), s.begin(), toLowerCh ); + } + std::string toLower( std::string const& s ) { + std::string lc = s; + toLowerInPlace( lc ); + return lc; + } + std::string trim( std::string const& str ) { + static char const* whitespaceChars = "\n\r\t "; + std::string::size_type start = str.find_first_not_of( whitespaceChars ); + std::string::size_type end = str.find_last_not_of( whitespaceChars ); + + return start != std::string::npos ? str.substr( start, 1+end-start ) : std::string(); + } + + bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) { + bool replaced = false; + std::size_t i = str.find( replaceThis ); + while( i != std::string::npos ) { + replaced = true; + str = str.substr( 0, i ) + withThis + str.substr( i+replaceThis.size() ); + if( i < str.size()-withThis.size() ) + i = str.find( replaceThis, i+withThis.size() ); + else + i = std::string::npos; + } + return replaced; + } + + pluralise::pluralise( std::size_t count, std::string const& label ) + : m_count( count ), + m_label( label ) + {} + + std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) { + os << pluraliser.m_count << ' ' << pluraliser.m_label; + if( pluraliser.m_count != 1 ) + os << 's'; + return os; + } + +} +// end catch_string_manip.cpp +// start catch_stringref.cpp + +#if defined(__clang__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wexit-time-destructors" +#endif + +#include +#include +#include + +namespace Catch { + + auto getEmptyStringRef() -> StringRef { + static StringRef s_emptyStringRef(""); + return s_emptyStringRef; + } + + StringRef::StringRef() noexcept + : StringRef( getEmptyStringRef() ) + {} + + StringRef::StringRef( StringRef const& other ) noexcept + : m_start( other.m_start ), + m_size( other.m_size ) + {} + + StringRef::StringRef( StringRef&& other ) noexcept + : m_start( other.m_start ), + m_size( other.m_size ), + m_data( other.m_data ) + { + other.m_data = nullptr; + } + + StringRef::StringRef( char const* rawChars ) noexcept + : m_start( rawChars ), + m_size( static_cast( std::strlen( rawChars ) ) ) + { + assert( rawChars != nullptr ); + } + + StringRef::StringRef( char const* rawChars, size_type size ) noexcept + : m_start( rawChars ), + m_size( size ) + { + size_type rawSize = rawChars == nullptr ? 0 : static_cast( std::strlen( rawChars ) ); + if( rawSize < size ) + m_size = rawSize; + } + + StringRef::StringRef( std::string const& stdString ) noexcept + : m_start( stdString.c_str() ), + m_size( stdString.size() ) + {} + + StringRef::~StringRef() noexcept { + delete[] m_data; + } + + auto StringRef::operator = ( StringRef other ) noexcept -> StringRef& { + swap( other ); + return *this; + } + StringRef::operator std::string() const { + return std::string( m_start, m_size ); + } + + void StringRef::swap( StringRef& other ) noexcept { + std::swap( m_start, other.m_start ); + std::swap( m_size, other.m_size ); + std::swap( m_data, other.m_data ); + } + + auto StringRef::c_str() const -> char const* { + if( isSubstring() ) + const_cast( this )->takeOwnership(); + return m_start; + } + auto StringRef::data() const noexcept -> char const* { + return m_start; + } + + auto StringRef::isOwned() const noexcept -> bool { + return m_data != nullptr; + } + auto StringRef::isSubstring() const noexcept -> bool { + return m_start[m_size] != '\0'; + } + + void StringRef::takeOwnership() { + if( !isOwned() ) { + m_data = new char[m_size+1]; + memcpy( m_data, m_start, m_size ); + m_data[m_size] = '\0'; + m_start = m_data; + } + } + auto StringRef::substr( size_type start, size_type size ) const noexcept -> StringRef { + if( start < m_size ) + return StringRef( m_start+start, size ); + else + return StringRef(); + } + auto StringRef::operator == ( StringRef const& other ) const noexcept -> bool { + return + size() == other.size() && + (std::strncmp( m_start, other.m_start, size() ) == 0); + } + auto StringRef::operator != ( StringRef const& other ) const noexcept -> bool { + return !operator==( other ); + } + + auto StringRef::operator[](size_type index) const noexcept -> char { + return m_start[index]; + } + + auto StringRef::empty() const noexcept -> bool { + return m_size == 0; + } + + auto StringRef::size() const noexcept -> size_type { + return m_size; + } + auto StringRef::numberOfCharacters() const noexcept -> size_type { + size_type noChars = m_size; + // Make adjustments for uft encodings + for( size_type i=0; i < m_size; ++i ) { + char c = m_start[i]; + if( ( c & 0b11000000 ) == 0b11000000 ) { + if( ( c & 0b11100000 ) == 0b11000000 ) + noChars--; + else if( ( c & 0b11110000 ) == 0b11100000 ) + noChars-=2; + else if( ( c & 0b11111000 ) == 0b11110000 ) + noChars-=3; + } + } + return noChars; + } + + auto operator + ( StringRef const& lhs, StringRef const& rhs ) -> std::string { + std::string str; + str.reserve( lhs.size() + rhs.size() ); + str += lhs; + str += rhs; + return str; + } + auto operator + ( StringRef const& lhs, const char* rhs ) -> std::string { + return std::string( lhs ) + std::string( rhs ); + } + auto operator + ( char const* lhs, StringRef const& rhs ) -> std::string { + return std::string( lhs ) + std::string( rhs ); + } + + auto operator << ( std::ostream& os, StringRef const& str ) -> std::ostream& { + return os << str.c_str(); + } + +} // namespace Catch + +#if defined(__clang__) +# pragma clang diagnostic pop +#endif +// end catch_stringref.cpp +// start catch_tag_alias.cpp + +namespace Catch { + TagAlias::TagAlias(std::string const & _tag, SourceLineInfo _lineInfo): tag(_tag), lineInfo(_lineInfo) {} +} +// end catch_tag_alias.cpp +// start catch_tag_alias_autoregistrar.cpp + +namespace Catch { + + RegistrarForTagAliases::RegistrarForTagAliases(char const* alias, char const* tag, SourceLineInfo const& lineInfo) { + try { + getMutableRegistryHub().registerTagAlias(alias, tag, lineInfo); + } catch (...) { + // Do not throw when constructing global objects, instead register the exception to be processed later + getMutableRegistryHub().registerStartupException(); + } + } + +} +// end catch_tag_alias_autoregistrar.cpp +// start catch_tag_alias_registry.cpp + +namespace Catch { + + TagAliasRegistry::~TagAliasRegistry() {} + + TagAlias const* TagAliasRegistry::find( std::string const& alias ) const { + auto it = m_registry.find( alias ); + if( it != m_registry.end() ) + return &(it->second); + else + return nullptr; + } + + std::string TagAliasRegistry::expandAliases( std::string const& unexpandedTestSpec ) const { + std::string expandedTestSpec = unexpandedTestSpec; + for( auto const& registryKvp : m_registry ) { + std::size_t pos = expandedTestSpec.find( registryKvp.first ); + if( pos != std::string::npos ) { + expandedTestSpec = expandedTestSpec.substr( 0, pos ) + + registryKvp.second.tag + + expandedTestSpec.substr( pos + registryKvp.first.size() ); + } + } + return expandedTestSpec; + } + + void TagAliasRegistry::add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) { + CATCH_ENFORCE( startsWith(alias, "[@") && endsWith(alias, ']'), + "error: tag alias, '" << alias << "' is not of the form [@alias name].\n" << lineInfo ); + + CATCH_ENFORCE( m_registry.insert(std::make_pair(alias, TagAlias(tag, lineInfo))).second, + "error: tag alias, '" << alias << "' already registered.\n" + << "\tFirst seen at: " << find(alias)->lineInfo << "\n" + << "\tRedefined at: " << lineInfo ); + } + + ITagAliasRegistry::~ITagAliasRegistry() {} + + ITagAliasRegistry const& ITagAliasRegistry::get() { + return getRegistryHub().getTagAliasRegistry(); + } + +} // end namespace Catch +// end catch_tag_alias_registry.cpp +// start catch_test_case_info.cpp + +#include +#include +#include + +namespace Catch { + + TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) { + if( startsWith( tag, '.' ) || + tag == "!hide" ) + return TestCaseInfo::IsHidden; + else if( tag == "!throws" ) + return TestCaseInfo::Throws; + else if( tag == "!shouldfail" ) + return TestCaseInfo::ShouldFail; + else if( tag == "!mayfail" ) + return TestCaseInfo::MayFail; + else if( tag == "!nonportable" ) + return TestCaseInfo::NonPortable; + else if( tag == "!benchmark" ) + return static_cast( TestCaseInfo::Benchmark | TestCaseInfo::IsHidden ); + else + return TestCaseInfo::None; + } + bool isReservedTag( std::string const& tag ) { + return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !std::isalnum( tag[0] ); + } + void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) { + CATCH_ENFORCE( !isReservedTag(tag), + "Tag name: [" << tag << "] is not allowed.\n" + << "Tag names starting with non alpha-numeric characters are reserved\n" + << _lineInfo ); + } + + TestCase makeTestCase( ITestInvoker* _testCase, + std::string const& _className, + std::string const& _name, + std::string const& _descOrTags, + SourceLineInfo const& _lineInfo ) + { + bool isHidden = false; + + // Parse out tags + std::vector tags; + std::string desc, tag; + bool inTag = false; + for (char c : _descOrTags) { + if( !inTag ) { + if( c == '[' ) + inTag = true; + else + desc += c; + } + else { + if( c == ']' ) { + TestCaseInfo::SpecialProperties prop = parseSpecialTag( tag ); + if( ( prop & TestCaseInfo::IsHidden ) != 0 ) + isHidden = true; + else if( prop == TestCaseInfo::None ) + enforceNotReservedTag( tag, _lineInfo ); + + tags.push_back( tag ); + tag.clear(); + inTag = false; + } + else + tag += c; + } + } + if( isHidden ) { + tags.push_back( "." ); + } + + TestCaseInfo info( _name, _className, desc, tags, _lineInfo ); + return TestCase( _testCase, info ); + } + + void setTags( TestCaseInfo& testCaseInfo, std::vector tags ) { + std::sort(begin(tags), end(tags)); + tags.erase(std::unique(begin(tags), end(tags)), end(tags)); + testCaseInfo.lcaseTags.clear(); + + for( auto const& tag : tags ) { + std::string lcaseTag = toLower( tag ); + testCaseInfo.properties = static_cast( testCaseInfo.properties | parseSpecialTag( lcaseTag ) ); + testCaseInfo.lcaseTags.push_back( lcaseTag ); + } + testCaseInfo.tags = std::move(tags); + } + + TestCaseInfo::TestCaseInfo( std::string const& _name, + std::string const& _className, + std::string const& _description, + std::vector const& _tags, + SourceLineInfo const& _lineInfo ) + : name( _name ), + className( _className ), + description( _description ), + lineInfo( _lineInfo ), + properties( None ) + { + setTags( *this, _tags ); + } + + bool TestCaseInfo::isHidden() const { + return ( properties & IsHidden ) != 0; + } + bool TestCaseInfo::throws() const { + return ( properties & Throws ) != 0; + } + bool TestCaseInfo::okToFail() const { + return ( properties & (ShouldFail | MayFail ) ) != 0; + } + bool TestCaseInfo::expectedToFail() const { + return ( properties & (ShouldFail ) ) != 0; + } + + std::string TestCaseInfo::tagsAsString() const { + std::string ret; + // '[' and ']' per tag + std::size_t full_size = 2 * tags.size(); + for (const auto& tag : tags) { + full_size += tag.size(); + } + ret.reserve(full_size); + for (const auto& tag : tags) { + ret.push_back('['); + ret.append(tag); + ret.push_back(']'); + } + + return ret; + } + + TestCase::TestCase( ITestInvoker* testCase, TestCaseInfo const& info ) : TestCaseInfo( info ), test( testCase ) {} + + TestCase TestCase::withName( std::string const& _newName ) const { + TestCase other( *this ); + other.name = _newName; + return other; + } + + void TestCase::invoke() const { + test->invoke(); + } + + bool TestCase::operator == ( TestCase const& other ) const { + return test.get() == other.test.get() && + name == other.name && + className == other.className; + } + + bool TestCase::operator < ( TestCase const& other ) const { + return name < other.name; + } + + TestCaseInfo const& TestCase::getTestCaseInfo() const + { + return *this; + } + +} // end namespace Catch +// end catch_test_case_info.cpp +// start catch_test_case_registry_impl.cpp #include + +namespace Catch { + + std::vector sortTests( IConfig const& config, std::vector const& unsortedTestCases ) { + + std::vector sorted = unsortedTestCases; + + switch( config.runOrder() ) { + case RunTests::InLexicographicalOrder: + std::sort( sorted.begin(), sorted.end() ); + break; + case RunTests::InRandomOrder: + seedRng( config ); + RandomNumberGenerator::shuffle( sorted ); + break; + case RunTests::InDeclarationOrder: + // already in declaration order + break; + } + return sorted; + } + bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ) { + return testSpec.matches( testCase ) && ( config.allowThrows() || !testCase.throws() ); + } + + void enforceNoDuplicateTestCases( std::vector const& functions ) { + std::set seenFunctions; + for( auto const& function : functions ) { + auto prev = seenFunctions.insert( function ); + CATCH_ENFORCE( prev.second, + "error: TEST_CASE( \"" << function.name << "\" ) already defined.\n" + << "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << "\n" + << "\tRedefined at " << function.getTestCaseInfo().lineInfo ); + } + } + + std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ) { + std::vector filtered; + filtered.reserve( testCases.size() ); + for( auto const& testCase : testCases ) + if( matchTest( testCase, testSpec, config ) ) + filtered.push_back( testCase ); + return filtered; + } + std::vector const& getAllTestCasesSorted( IConfig const& config ) { + return getRegistryHub().getTestCaseRegistry().getAllTestsSorted( config ); + } + + void TestRegistry::registerTest( TestCase const& testCase ) { + std::string name = testCase.getTestCaseInfo().name; + if( name.empty() ) { + std::ostringstream oss; + oss << "Anonymous test case " << ++m_unnamedCount; + return registerTest( testCase.withName( oss.str() ) ); + } + m_functions.push_back( testCase ); + } + + std::vector const& TestRegistry::getAllTests() const { + return m_functions; + } + std::vector const& TestRegistry::getAllTestsSorted( IConfig const& config ) const { + if( m_sortedFunctions.empty() ) + enforceNoDuplicateTestCases( m_functions ); + + if( m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty() ) { + m_sortedFunctions = sortTests( config, m_functions ); + m_currentSortOrder = config.runOrder(); + } + return m_sortedFunctions; + } + + /////////////////////////////////////////////////////////////////////////// + TestInvokerAsFunction::TestInvokerAsFunction( void(*testAsFunction)() ) noexcept : m_testAsFunction( testAsFunction ) {} + + void TestInvokerAsFunction::invoke() const { + m_testAsFunction(); + } + + std::string extractClassName( std::string const& classOrQualifiedMethodName ) { + std::string className = classOrQualifiedMethodName; + if( startsWith( className, '&' ) ) + { + std::size_t lastColons = className.rfind( "::" ); + std::size_t penultimateColons = className.rfind( "::", lastColons-1 ); + if( penultimateColons == std::string::npos ) + penultimateColons = 1; + className = className.substr( penultimateColons, lastColons-penultimateColons ); + } + return className; + } + +} // end namespace Catch +// end catch_test_case_registry_impl.cpp +// start catch_test_case_tracker.cpp + +#include +#include +#include +#include + +#if defined(__clang__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wexit-time-destructors" +#endif + +namespace Catch { +namespace TestCaseTracking { + + NameAndLocation::NameAndLocation( std::string const& _name, SourceLineInfo const& _location ) + : name( _name ), + location( _location ) + {} + + ITracker::~ITracker() = default; + + TrackerContext& TrackerContext::instance() { + static TrackerContext s_instance; + return s_instance; + } + + ITracker& TrackerContext::startRun() { + m_rootTracker = std::make_shared( NameAndLocation( "{root}", CATCH_INTERNAL_LINEINFO ), *this, nullptr ); + m_currentTracker = nullptr; + m_runState = Executing; + return *m_rootTracker; + } + + void TrackerContext::endRun() { + m_rootTracker.reset(); + m_currentTracker = nullptr; + m_runState = NotStarted; + } + + void TrackerContext::startCycle() { + m_currentTracker = m_rootTracker.get(); + m_runState = Executing; + } + void TrackerContext::completeCycle() { + m_runState = CompletedCycle; + } + + bool TrackerContext::completedCycle() const { + return m_runState == CompletedCycle; + } + ITracker& TrackerContext::currentTracker() { + return *m_currentTracker; + } + void TrackerContext::setCurrentTracker( ITracker* tracker ) { + m_currentTracker = tracker; + } + + TrackerBase::TrackerHasName::TrackerHasName( NameAndLocation const& nameAndLocation ) : m_nameAndLocation( nameAndLocation ) {} + bool TrackerBase::TrackerHasName::operator ()( ITrackerPtr const& tracker ) const { + return + tracker->nameAndLocation().name == m_nameAndLocation.name && + tracker->nameAndLocation().location == m_nameAndLocation.location; + } + + TrackerBase::TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ) + : m_nameAndLocation( nameAndLocation ), + m_ctx( ctx ), + m_parent( parent ) + {} + + NameAndLocation const& TrackerBase::nameAndLocation() const { + return m_nameAndLocation; + } + bool TrackerBase::isComplete() const { + return m_runState == CompletedSuccessfully || m_runState == Failed; + } + bool TrackerBase::isSuccessfullyCompleted() const { + return m_runState == CompletedSuccessfully; + } + bool TrackerBase::isOpen() const { + return m_runState != NotStarted && !isComplete(); + } + bool TrackerBase::hasChildren() const { + return !m_children.empty(); + } + + void TrackerBase::addChild( ITrackerPtr const& child ) { + m_children.push_back( child ); + } + + ITrackerPtr TrackerBase::findChild( NameAndLocation const& nameAndLocation ) { + auto it = std::find_if( m_children.begin(), m_children.end(), TrackerHasName( nameAndLocation ) ); + return( it != m_children.end() ) + ? *it + : nullptr; + } + ITracker& TrackerBase::parent() { + assert( m_parent ); // Should always be non-null except for root + return *m_parent; + } + + void TrackerBase::openChild() { + if( m_runState != ExecutingChildren ) { + m_runState = ExecutingChildren; + if( m_parent ) + m_parent->openChild(); + } + } + + bool TrackerBase::isSectionTracker() const { return false; } + bool TrackerBase::isIndexTracker() const { return false; } + + void TrackerBase::open() { + m_runState = Executing; + moveToThis(); + if( m_parent ) + m_parent->openChild(); + } + + void TrackerBase::close() { + + // Close any still open children (e.g. generators) + while( &m_ctx.currentTracker() != this ) + m_ctx.currentTracker().close(); + + switch( m_runState ) { + case NeedsAnotherRun: + break; + + case Executing: + m_runState = CompletedSuccessfully; + break; + case ExecutingChildren: + if( m_children.empty() || m_children.back()->isComplete() ) + m_runState = CompletedSuccessfully; + break; + + case NotStarted: + case CompletedSuccessfully: + case Failed: + CATCH_INTERNAL_ERROR( "Illogical state: " << m_runState ); + + default: + CATCH_INTERNAL_ERROR( "Unknown state: " << m_runState ); + } + moveToParent(); + m_ctx.completeCycle(); + } + void TrackerBase::fail() { + m_runState = Failed; + if( m_parent ) + m_parent->markAsNeedingAnotherRun(); + moveToParent(); + m_ctx.completeCycle(); + } + void TrackerBase::markAsNeedingAnotherRun() { + m_runState = NeedsAnotherRun; + } + + void TrackerBase::moveToParent() { + assert( m_parent ); + m_ctx.setCurrentTracker( m_parent ); + } + void TrackerBase::moveToThis() { + m_ctx.setCurrentTracker( this ); + } + + SectionTracker::SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ) + : TrackerBase( nameAndLocation, ctx, parent ) + { + if( parent ) { + while( !parent->isSectionTracker() ) + parent = &parent->parent(); + + SectionTracker& parentSection = static_cast( *parent ); + addNextFilters( parentSection.m_filters ); + } + } + + bool SectionTracker::isSectionTracker() const { return true; } + + SectionTracker& SectionTracker::acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ) { + std::shared_ptr section; + + ITracker& currentTracker = ctx.currentTracker(); + if( ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) { + assert( childTracker ); + assert( childTracker->isSectionTracker() ); + section = std::static_pointer_cast( childTracker ); + } + else { + section = std::make_shared( nameAndLocation, ctx, ¤tTracker ); + currentTracker.addChild( section ); + } + if( !ctx.completedCycle() ) + section->tryOpen(); + return *section; + } + + void SectionTracker::tryOpen() { + if( !isComplete() && (m_filters.empty() || m_filters[0].empty() || m_filters[0] == m_nameAndLocation.name ) ) + open(); + } + + void SectionTracker::addInitialFilters( std::vector const& filters ) { + if( !filters.empty() ) { + m_filters.push_back(""); // Root - should never be consulted + m_filters.push_back(""); // Test Case - not a section filter + m_filters.insert( m_filters.end(), filters.begin(), filters.end() ); + } + } + void SectionTracker::addNextFilters( std::vector const& filters ) { + if( filters.size() > 1 ) + m_filters.insert( m_filters.end(), ++filters.begin(), filters.end() ); + } + + IndexTracker::IndexTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent, int size ) + : TrackerBase( nameAndLocation, ctx, parent ), + m_size( size ) + {} + + bool IndexTracker::isIndexTracker() const { return true; } + + IndexTracker& IndexTracker::acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation, int size ) { + std::shared_ptr tracker; + + ITracker& currentTracker = ctx.currentTracker(); + if( ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) { + assert( childTracker ); + assert( childTracker->isIndexTracker() ); + tracker = std::static_pointer_cast( childTracker ); + } + else { + tracker = std::make_shared( nameAndLocation, ctx, ¤tTracker, size ); + currentTracker.addChild( tracker ); + } + + if( !ctx.completedCycle() && !tracker->isComplete() ) { + if( tracker->m_runState != ExecutingChildren && tracker->m_runState != NeedsAnotherRun ) + tracker->moveNext(); + tracker->open(); + } + + return *tracker; + } + + int IndexTracker::index() const { return m_index; } + + void IndexTracker::moveNext() { + m_index++; + m_children.clear(); + } + + void IndexTracker::close() { + TrackerBase::close(); + if( m_runState == CompletedSuccessfully && m_index < m_size-1 ) + m_runState = Executing; + } + +} // namespace TestCaseTracking + +using TestCaseTracking::ITracker; +using TestCaseTracking::TrackerContext; +using TestCaseTracking::SectionTracker; +using TestCaseTracking::IndexTracker; + +} // namespace Catch + +#if defined(__clang__) +# pragma clang diagnostic pop +#endif +// end catch_test_case_tracker.cpp +// start catch_test_registry.cpp + +namespace Catch { + + auto makeTestInvoker( void(*testAsFunction)() ) noexcept -> ITestInvoker* { + return new(std::nothrow) TestInvokerAsFunction( testAsFunction ); + } + + NameAndTags::NameAndTags( StringRef name_ , StringRef tags_ ) noexcept : name( name_ ), tags( tags_ ) {} + + AutoReg::AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef classOrMethod, NameAndTags const& nameAndTags ) noexcept { + try { + getMutableRegistryHub() + .registerTest( + makeTestCase( + invoker, + extractClassName( classOrMethod ), + nameAndTags.name, + nameAndTags.tags, + lineInfo)); + } catch (...) { + // Do not throw when constructing global objects, instead register the exception to be processed later + getMutableRegistryHub().registerStartupException(); + } + } + + AutoReg::~AutoReg() = default; +} +// end catch_test_registry.cpp +// start catch_test_spec.cpp + +#include #include #include +#include + +namespace Catch { + + TestSpec::Pattern::~Pattern() = default; + TestSpec::NamePattern::~NamePattern() = default; + TestSpec::TagPattern::~TagPattern() = default; + TestSpec::ExcludedPattern::~ExcludedPattern() = default; + + TestSpec::NamePattern::NamePattern( std::string const& name ) + : m_wildcardPattern( toLower( name ), CaseSensitive::No ) + {} + bool TestSpec::NamePattern::matches( TestCaseInfo const& testCase ) const { + return m_wildcardPattern.matches( toLower( testCase.name ) ); + } + + TestSpec::TagPattern::TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {} + bool TestSpec::TagPattern::matches( TestCaseInfo const& testCase ) const { + return std::find(begin(testCase.lcaseTags), + end(testCase.lcaseTags), + m_tag) != end(testCase.lcaseTags); + } + + TestSpec::ExcludedPattern::ExcludedPattern( PatternPtr const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {} + bool TestSpec::ExcludedPattern::matches( TestCaseInfo const& testCase ) const { return !m_underlyingPattern->matches( testCase ); } + + bool TestSpec::Filter::matches( TestCaseInfo const& testCase ) const { + // All patterns in a filter must match for the filter to be a match + for( auto const& pattern : m_patterns ) { + if( !pattern->matches( testCase ) ) + return false; + } + return true; + } + + bool TestSpec::hasFilters() const { + return !m_filters.empty(); + } + bool TestSpec::matches( TestCaseInfo const& testCase ) const { + // A TestSpec matches if any filter matches + for( auto const& filter : m_filters ) + if( filter.matches( testCase ) ) + return true; + return false; + } +} +// end catch_test_spec.cpp +// start catch_test_spec_parser.cpp + +namespace Catch { + + TestSpecParser::TestSpecParser( ITagAliasRegistry const& tagAliases ) : m_tagAliases( &tagAliases ) {} + + TestSpecParser& TestSpecParser::parse( std::string const& arg ) { + m_mode = None; + m_exclusion = false; + m_start = std::string::npos; + m_arg = m_tagAliases->expandAliases( arg ); + m_escapeChars.clear(); + for( m_pos = 0; m_pos < m_arg.size(); ++m_pos ) + visitChar( m_arg[m_pos] ); + if( m_mode == Name ) + addPattern(); + return *this; + } + TestSpec TestSpecParser::testSpec() { + addFilter(); + return m_testSpec; + } + + void TestSpecParser::visitChar( char c ) { + if( m_mode == None ) { + switch( c ) { + case ' ': return; + case '~': m_exclusion = true; return; + case '[': return startNewMode( Tag, ++m_pos ); + case '"': return startNewMode( QuotedName, ++m_pos ); + case '\\': return escape(); + default: startNewMode( Name, m_pos ); break; + } + } + if( m_mode == Name ) { + if( c == ',' ) { + addPattern(); + addFilter(); + } + else if( c == '[' ) { + if( subString() == "exclude:" ) + m_exclusion = true; + else + addPattern(); + startNewMode( Tag, ++m_pos ); + } + else if( c == '\\' ) + escape(); + } + else if( m_mode == EscapedName ) + m_mode = Name; + else if( m_mode == QuotedName && c == '"' ) + addPattern(); + else if( m_mode == Tag && c == ']' ) + addPattern(); + } + void TestSpecParser::startNewMode( Mode mode, std::size_t start ) { + m_mode = mode; + m_start = start; + } + void TestSpecParser::escape() { + if( m_mode == None ) + m_start = m_pos; + m_mode = EscapedName; + m_escapeChars.push_back( m_pos ); + } + std::string TestSpecParser::subString() const { return m_arg.substr( m_start, m_pos - m_start ); } + + void TestSpecParser::addFilter() { + if( !m_currentFilter.m_patterns.empty() ) { + m_testSpec.m_filters.push_back( m_currentFilter ); + m_currentFilter = TestSpec::Filter(); + } + } + + TestSpec parseTestSpec( std::string const& arg ) { + return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec(); + } + +} // namespace Catch +// end catch_test_spec_parser.cpp +// start catch_timer.cpp + +#include + +namespace Catch { + + auto getCurrentNanosecondsSinceEpoch() -> uint64_t { + return std::chrono::duration_cast( std::chrono::high_resolution_clock::now().time_since_epoch() ).count(); + } + + auto estimateClockResolution() -> uint64_t { + uint64_t sum = 0; + static const uint64_t iterations = 1000000; + + for( std::size_t i = 0; i < iterations; ++i ) { + + uint64_t ticks; + uint64_t baseTicks = getCurrentNanosecondsSinceEpoch(); + do { + ticks = getCurrentNanosecondsSinceEpoch(); + } + while( ticks == baseTicks ); + + auto delta = ticks - baseTicks; + sum += delta; + } + + // We're just taking the mean, here. To do better we could take the std. dev and exclude outliers + // - and potentially do more iterations if there's a high variance. + return sum/iterations; + } + auto getEstimatedClockResolution() -> uint64_t { + static auto s_resolution = estimateClockResolution(); + return s_resolution; + } + + void Timer::start() { + m_nanoseconds = getCurrentNanosecondsSinceEpoch(); + } + auto Timer::getElapsedNanoseconds() const -> unsigned int { + return static_cast(getCurrentNanosecondsSinceEpoch() - m_nanoseconds); + } + auto Timer::getElapsedMicroseconds() const -> unsigned int { + return static_cast(getElapsedNanoseconds()/1000); + } + auto Timer::getElapsedMilliseconds() const -> unsigned int { + return static_cast(getElapsedMicroseconds()/1000); + } + auto Timer::getElapsedSeconds() const -> double { + return getElapsedMicroseconds()/1000000.0; + } + +} // namespace Catch +// end catch_timer.cpp +// start catch_tostring.cpp + +#if defined(__clang__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wexit-time-destructors" +# pragma clang diagnostic ignored "-Wglobal-constructors" +#endif + #include +namespace Catch { + +namespace Detail { + + const std::string unprintableString = "{?}"; + + namespace { + const int hexThreshold = 255; + + struct Endianness { + enum Arch { Big, Little }; + + static Arch which() { + union _{ + int asInt; + char asChar[sizeof (int)]; + } u; + + u.asInt = 1; + return ( u.asChar[sizeof(int)-1] == 1 ) ? Big : Little; + } + }; + } + + std::string rawMemoryToString( const void *object, std::size_t size ) { + // Reverse order for little endian architectures + int i = 0, end = static_cast( size ), inc = 1; + if( Endianness::which() == Endianness::Little ) { + i = end-1; + end = inc = -1; + } + + unsigned char const *bytes = static_cast(object); + std::ostringstream os; + os << "0x" << std::setfill('0') << std::hex; + for( ; i != end; i += inc ) + os << std::setw(2) << static_cast(bytes[i]); + return os.str(); + } +} + +template +std::string fpToString( T value, int precision ) { + std::ostringstream oss; + oss << std::setprecision( precision ) + << std::fixed + << value; + std::string d = oss.str(); + std::size_t i = d.find_last_not_of( '0' ); + if( i != std::string::npos && i != d.size()-1 ) { + if( d[i] == '.' ) + i++; + d = d.substr( 0, i+1 ); + } + return d; +} + +//// ======================================================= //// +// +// Out-of-line defs for full specialization of StringMaker +// +//// ======================================================= //// + +std::string StringMaker::convert(const std::string& str) { + if (!getCurrentContext().getConfig()->showInvisibles()) { + return '"' + str + '"'; + } + + std::string s("\""); + for (char c : str) { + switch (c) { + case '\n': + s.append("\\n"); + break; + case '\t': + s.append("\\t"); + break; + default: + s.push_back(c); + break; + } + } + s.append("\""); + return s; +} + +std::string StringMaker::convert(const std::wstring& wstr) { + std::string s; + s.reserve(wstr.size()); + for (auto c : wstr) { + s += (c <= 0xff) ? static_cast(c) : '?'; + } + return ::Catch::Detail::stringify(s); +} + +std::string StringMaker::convert(char const* str) { + if (str) { + return ::Catch::Detail::stringify(std::string{ str }); + } else { + return{ "{null string}" }; + } +} +std::string StringMaker::convert(char* str) { + if (str) { + return ::Catch::Detail::stringify(std::string{ str }); + } else { + return{ "{null string}" }; + } +} +std::string StringMaker::convert(wchar_t const * str) { + if (str) { + return ::Catch::Detail::stringify(std::wstring{ str }); + } else { + return{ "{null string}" }; + } +} +std::string StringMaker::convert(wchar_t * str) { + if (str) { + return ::Catch::Detail::stringify(std::wstring{ str }); + } else { + return{ "{null string}" }; + } +} + +std::string StringMaker::convert(int value) { + return ::Catch::Detail::stringify(static_cast(value)); +} +std::string StringMaker::convert(long value) { + return ::Catch::Detail::stringify(static_cast(value)); +} +std::string StringMaker::convert(long long value) { + std::ostringstream oss; + oss << value; + if (value > Detail::hexThreshold) { + oss << " (0x" << std::hex << value << ')'; + } + return oss.str(); +} + +std::string StringMaker::convert(unsigned int value) { + return ::Catch::Detail::stringify(static_cast(value)); +} +std::string StringMaker::convert(unsigned long value) { + return ::Catch::Detail::stringify(static_cast(value)); +} +std::string StringMaker::convert(unsigned long long value) { + std::ostringstream oss; + oss << value; + if (value > Detail::hexThreshold) { + oss << " (0x" << std::hex << value << ')'; + } + return oss.str(); +} + +std::string StringMaker::convert(bool b) { + return b ? "true" : "false"; +} + +std::string StringMaker::convert(char value) { + if (value == '\r') { + return "'\\r'"; + } else if (value == '\f') { + return "'\\f'"; + } else if (value == '\n') { + return "'\\n'"; + } else if (value == '\t') { + return "'\\t'"; + } else if ('\0' <= value && value < ' ') { + return ::Catch::Detail::stringify(static_cast(value)); + } else { + char chstr[] = "' '"; + chstr[1] = value; + return chstr; + } +} +std::string StringMaker::convert(signed char c) { + return ::Catch::Detail::stringify(static_cast(c)); +} +std::string StringMaker::convert(unsigned char c) { + return ::Catch::Detail::stringify(static_cast(c)); +} + +std::string StringMaker::convert(std::nullptr_t) { + return "nullptr"; +} + +std::string StringMaker::convert(float value) { + return fpToString(value, 5) + 'f'; +} +std::string StringMaker::convert(double value) { + return fpToString(value, 10); +} + +} // end namespace Catch + +#if defined(__clang__) +# pragma clang diagnostic pop +#endif + +// end catch_tostring.cpp +// start catch_totals.cpp + +namespace Catch { + + Counts Counts::operator - ( Counts const& other ) const { + Counts diff; + diff.passed = passed - other.passed; + diff.failed = failed - other.failed; + diff.failedButOk = failedButOk - other.failedButOk; + return diff; + } + + Counts& Counts::operator += ( Counts const& other ) { + passed += other.passed; + failed += other.failed; + failedButOk += other.failedButOk; + return *this; + } + + std::size_t Counts::total() const { + return passed + failed + failedButOk; + } + bool Counts::allPassed() const { + return failed == 0 && failedButOk == 0; + } + bool Counts::allOk() const { + return failed == 0; + } + + Totals Totals::operator - ( Totals const& other ) const { + Totals diff; + diff.assertions = assertions - other.assertions; + diff.testCases = testCases - other.testCases; + return diff; + } + + Totals& Totals::operator += ( Totals const& other ) { + assertions += other.assertions; + testCases += other.testCases; + return *this; + } + + Totals Totals::delta( Totals const& prevTotals ) const { + Totals diff = *this - prevTotals; + if( diff.assertions.failed > 0 ) + ++diff.testCases.failed; + else if( diff.assertions.failedButOk > 0 ) + ++diff.testCases.failedButOk; + else + ++diff.testCases.passed; + return diff; + } + +} +// end catch_totals.cpp +// start catch_version.cpp + +#include + +namespace Catch { + + Version::Version + ( unsigned int _majorVersion, + unsigned int _minorVersion, + unsigned int _patchNumber, + char const * const _branchName, + unsigned int _buildNumber ) + : majorVersion( _majorVersion ), + minorVersion( _minorVersion ), + patchNumber( _patchNumber ), + branchName( _branchName ), + buildNumber( _buildNumber ) + {} + + std::ostream& operator << ( std::ostream& os, Version const& version ) { + os << version.majorVersion << '.' + << version.minorVersion << '.' + << version.patchNumber; + // branchName is never null -> 0th char is \0 if it is empty + if (version.branchName[0]) { + os << '-' << version.branchName + << '.' << version.buildNumber; + } + return os; + } + + Version const& libraryVersion() { + static Version version( 2, 0, 1, "", 0 ); + return version; + } + +} +// end catch_version.cpp +// start catch_wildcard_pattern.cpp + +namespace Catch { + + WildcardPattern::WildcardPattern( std::string const& pattern, + CaseSensitive::Choice caseSensitivity ) + : m_caseSensitivity( caseSensitivity ), + m_pattern( adjustCase( pattern ) ) + { + if( startsWith( m_pattern, '*' ) ) { + m_pattern = m_pattern.substr( 1 ); + m_wildcard = WildcardAtStart; + } + if( endsWith( m_pattern, '*' ) ) { + m_pattern = m_pattern.substr( 0, m_pattern.size()-1 ); + m_wildcard = static_cast( m_wildcard | WildcardAtEnd ); + } + } + + bool WildcardPattern::matches( std::string const& str ) const { + switch( m_wildcard ) { + case NoWildcard: + return m_pattern == adjustCase( str ); + case WildcardAtStart: + return endsWith( adjustCase( str ), m_pattern ); + case WildcardAtEnd: + return startsWith( adjustCase( str ), m_pattern ); + case WildcardAtBothEnds: + return contains( adjustCase( str ), m_pattern ); + default: + CATCH_INTERNAL_ERROR( "Unknown enum" ); + } + } + + std::string WildcardPattern::adjustCase( std::string const& str ) const { + return m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str; + } +} +// end catch_wildcard_pattern.cpp +// start catch_xmlwriter.cpp + +// start catch_xmlwriter.h + +#include +#include + namespace Catch { class XmlEncode { public: enum ForWhat { ForTextNodes, ForAttributes }; - XmlEncode( std::string const& str, ForWhat forWhat = ForTextNodes ) - : m_str( str ), - m_forWhat( forWhat ) - {} + XmlEncode( std::string const& str, ForWhat forWhat = ForTextNodes ); - void encodeTo( std::ostream& os ) const { + void encodeTo( std::ostream& os ) const; - // Apostrophe escaping not necessary if we always use " to write attributes - // (see: http://www.w3.org/TR/xml/#syntax) - - for( std::size_t i = 0; i < m_str.size(); ++ i ) { - char c = m_str[i]; - switch( c ) { - case '<': os << "<"; break; - case '&': os << "&"; break; - - case '>': - // See: http://www.w3.org/TR/xml/#syntax - if( i > 2 && m_str[i-1] == ']' && m_str[i-2] == ']' ) - os << ">"; - else - os << c; - break; - - case '\"': - if( m_forWhat == ForAttributes ) - os << """; - else - os << c; - break; - - default: - // Escape control chars - based on contribution by @espenalb in PR #465 and - // by @mrpi PR #588 - if ( ( c >= 0 && c < '\x09' ) || ( c > '\x0D' && c < '\x20') || c=='\x7F' ) { - // see http://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0 - os << "\\x" << std::uppercase << std::hex << std::setfill('0') << std::setw(2) - << static_cast( c ); - } - else - os << c; - } - } - } - - friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) { - xmlEncode.encodeTo( os ); - return os; - } + friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ); private: std::string m_str; @@ -9979,24 +9900,14 @@ namespace Catch { class ScopedElement { public: - ScopedElement( XmlWriter* writer ) - : m_writer( writer ) - {} + ScopedElement( XmlWriter* writer ); - ScopedElement( ScopedElement const& other ) - : m_writer( other.m_writer ){ - other.m_writer = CATCH_NULL; - } + ScopedElement( ScopedElement&& other ) noexcept; + ScopedElement& operator=( ScopedElement&& other ) noexcept; - ~ScopedElement() { - if( m_writer ) - m_writer->endElement(); - } + ~ScopedElement(); - ScopedElement& writeText( std::string const& text, bool indent = true ) { - m_writer->writeText( text, indent ); - return *this; - } + ScopedElement& writeText( std::string const& text, bool indent = true ); template ScopedElement& writeAttribute( std::string const& name, T const& attribute ) { @@ -10005,622 +9916,790 @@ namespace Catch { } private: - mutable XmlWriter* m_writer; + mutable XmlWriter* m_writer = nullptr; }; - XmlWriter() - : m_tagIsOpen( false ), - m_needsNewline( false ), - m_os( Catch::cout() ) - { - writeDeclaration(); - } + XmlWriter( std::ostream& os = Catch::cout() ); + ~XmlWriter(); - XmlWriter( std::ostream& os ) - : m_tagIsOpen( false ), - m_needsNewline( false ), - m_os( os ) - { - writeDeclaration(); - } + XmlWriter( XmlWriter const& ) = delete; + XmlWriter& operator=( XmlWriter const& ) = delete; - ~XmlWriter() { - while( !m_tags.empty() ) - endElement(); - } + XmlWriter& startElement( std::string const& name ); - XmlWriter& startElement( std::string const& name ) { - ensureTagClosed(); - newlineIfNecessary(); - m_os << m_indent << '<' << name; - m_tags.push_back( name ); - m_indent += " "; - m_tagIsOpen = true; - return *this; - } + ScopedElement scopedElement( std::string const& name ); - ScopedElement scopedElement( std::string const& name ) { - ScopedElement scoped( this ); - startElement( name ); - return scoped; - } + XmlWriter& endElement(); - XmlWriter& endElement() { - newlineIfNecessary(); - m_indent = m_indent.substr( 0, m_indent.size()-2 ); - if( m_tagIsOpen ) { - m_os << "/>"; - m_tagIsOpen = false; - } - else { - m_os << m_indent << ""; - } - m_os << std::endl; - m_tags.pop_back(); - return *this; - } + XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ); - XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ) { - if( !name.empty() && !attribute.empty() ) - m_os << ' ' << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << '"'; - return *this; - } - - XmlWriter& writeAttribute( std::string const& name, bool attribute ) { - m_os << ' ' << name << "=\"" << ( attribute ? "true" : "false" ) << '"'; - return *this; - } + XmlWriter& writeAttribute( std::string const& name, bool attribute ); template XmlWriter& writeAttribute( std::string const& name, T const& attribute ) { - std::ostringstream oss; - oss << attribute; - return writeAttribute( name, oss.str() ); + m_oss.clear(); + m_oss.str(std::string()); + m_oss << attribute; + return writeAttribute( name, m_oss.str() ); } - XmlWriter& writeText( std::string const& text, bool indent = true ) { - if( !text.empty() ){ - bool tagWasOpen = m_tagIsOpen; - ensureTagClosed(); - if( tagWasOpen && indent ) - m_os << m_indent; - m_os << XmlEncode( text ); - m_needsNewline = true; - } - return *this; - } + XmlWriter& writeText( std::string const& text, bool indent = true ); - XmlWriter& writeComment( std::string const& text ) { - ensureTagClosed(); - m_os << m_indent << ""; - m_needsNewline = true; - return *this; - } + XmlWriter& writeComment( std::string const& text ); - void writeStylesheetRef( std::string const& url ) { - m_os << "\n"; - } + void writeStylesheetRef( std::string const& url ); - XmlWriter& writeBlankLine() { - ensureTagClosed(); - m_os << '\n'; - return *this; - } + XmlWriter& writeBlankLine(); - void ensureTagClosed() { - if( m_tagIsOpen ) { - m_os << ">" << std::endl; - m_tagIsOpen = false; - } - } + void ensureTagClosed(); private: - XmlWriter( XmlWriter const& ); - void operator=( XmlWriter const& ); - void writeDeclaration() { - m_os << "\n"; - } + void writeDeclaration(); - void newlineIfNecessary() { - if( m_needsNewline ) { - m_os << std::endl; - m_needsNewline = false; - } - } + void newlineIfNecessary(); - bool m_tagIsOpen; - bool m_needsNewline; + bool m_tagIsOpen = false; + bool m_needsNewline = false; std::vector m_tags; std::string m_indent; std::ostream& m_os; + std::ostringstream m_oss; }; } -namespace Catch { - class XmlReporter : public StreamingReporterBase { - public: - XmlReporter( ReporterConfig const& _config ) - : StreamingReporterBase( _config ), - m_xml(_config.stream()), - m_sectionDepth( 0 ) - { - m_reporterPrefs.shouldRedirectStdOut = true; - } +// end catch_xmlwriter.h +#include - virtual ~XmlReporter() CATCH_OVERRIDE; +namespace Catch { + + XmlEncode::XmlEncode( std::string const& str, ForWhat forWhat ) + : m_str( str ), + m_forWhat( forWhat ) + {} + + void XmlEncode::encodeTo( std::ostream& os ) const { + + // Apostrophe escaping not necessary if we always use " to write attributes + // (see: http://www.w3.org/TR/xml/#syntax) + + for( std::size_t i = 0; i < m_str.size(); ++ i ) { + char c = m_str[i]; + switch( c ) { + case '<': os << "<"; break; + case '&': os << "&"; break; + + case '>': + // See: http://www.w3.org/TR/xml/#syntax + if( i > 2 && m_str[i-1] == ']' && m_str[i-2] == ']' ) + os << ">"; + else + os << c; + break; + + case '\"': + if( m_forWhat == ForAttributes ) + os << """; + else + os << c; + break; + + default: + // Escape control chars - based on contribution by @espenalb in PR #465 and + // by @mrpi PR #588 + if ( ( c >= 0 && c < '\x09' ) || ( c > '\x0D' && c < '\x20') || c=='\x7F' ) { + // see http://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0 + os << "\\x" << std::uppercase << std::hex << std::setfill('0') << std::setw(2) + << static_cast( c ); + } + else + os << c; + } + } + } + + std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) { + xmlEncode.encodeTo( os ); + return os; + } + + XmlWriter::ScopedElement::ScopedElement( XmlWriter* writer ) + : m_writer( writer ) + {} + + XmlWriter::ScopedElement::ScopedElement( ScopedElement&& other ) noexcept + : m_writer( other.m_writer ){ + other.m_writer = nullptr; + } + XmlWriter::ScopedElement& XmlWriter::ScopedElement::operator=( ScopedElement&& other ) noexcept { + if ( m_writer ) { + m_writer->endElement(); + } + m_writer = other.m_writer; + other.m_writer = nullptr; + return *this; + } + + XmlWriter::ScopedElement::~ScopedElement() { + if( m_writer ) + m_writer->endElement(); + } + + XmlWriter::ScopedElement& XmlWriter::ScopedElement::writeText( std::string const& text, bool indent ) { + m_writer->writeText( text, indent ); + return *this; + } + + XmlWriter::XmlWriter( std::ostream& os ) : m_os( os ) + { + writeDeclaration(); + } + + XmlWriter::~XmlWriter() { + while( !m_tags.empty() ) + endElement(); + } + + XmlWriter& XmlWriter::startElement( std::string const& name ) { + ensureTagClosed(); + newlineIfNecessary(); + m_os << m_indent << '<' << name; + m_tags.push_back( name ); + m_indent += " "; + m_tagIsOpen = true; + return *this; + } + + XmlWriter::ScopedElement XmlWriter::scopedElement( std::string const& name ) { + ScopedElement scoped( this ); + startElement( name ); + return scoped; + } + + XmlWriter& XmlWriter::endElement() { + newlineIfNecessary(); + m_indent = m_indent.substr( 0, m_indent.size()-2 ); + if( m_tagIsOpen ) { + m_os << "/>"; + m_tagIsOpen = false; + } + else { + m_os << m_indent << ""; + } + m_os << std::endl; + m_tags.pop_back(); + return *this; + } + + XmlWriter& XmlWriter::writeAttribute( std::string const& name, std::string const& attribute ) { + if( !name.empty() && !attribute.empty() ) + m_os << ' ' << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << '"'; + return *this; + } + + XmlWriter& XmlWriter::writeAttribute( std::string const& name, bool attribute ) { + m_os << ' ' << name << "=\"" << ( attribute ? "true" : "false" ) << '"'; + return *this; + } + + XmlWriter& XmlWriter::writeText( std::string const& text, bool indent ) { + if( !text.empty() ){ + bool tagWasOpen = m_tagIsOpen; + ensureTagClosed(); + if( tagWasOpen && indent ) + m_os << m_indent; + m_os << XmlEncode( text ); + m_needsNewline = true; + } + return *this; + } + + XmlWriter& XmlWriter::writeComment( std::string const& text ) { + ensureTagClosed(); + m_os << m_indent << ""; + m_needsNewline = true; + return *this; + } + + void XmlWriter::writeStylesheetRef( std::string const& url ) { + m_os << "\n"; + } + + XmlWriter& XmlWriter::writeBlankLine() { + ensureTagClosed(); + m_os << '\n'; + return *this; + } + + void XmlWriter::ensureTagClosed() { + if( m_tagIsOpen ) { + m_os << ">" << std::endl; + m_tagIsOpen = false; + } + } + + void XmlWriter::writeDeclaration() { + m_os << "\n"; + } + + void XmlWriter::newlineIfNecessary() { + if( m_needsNewline ) { + m_os << std::endl; + m_needsNewline = false; + } + } +} +// end catch_xmlwriter.cpp +// start catch_reporter_bases.cpp + +#include +#include +#include +#include +#include + +namespace Catch { + void prepareExpandedExpression(AssertionResult& result) { + result.getExpandedExpression(); + } + + // Because formatting using c++ streams is stateful, drop down to C is required + // Alternatively we could use stringstream, but its performance is... not good. + std::string getFormattedDuration( double duration ) { + // Max exponent + 1 is required to represent the whole part + // + 1 for decimal point + // + 3 for the 3 decimal places + // + 1 for null terminator + const std::size_t maxDoubleSize = DBL_MAX_10_EXP + 1 + 1 + 3 + 1; + char buffer[maxDoubleSize]; + + // Save previous errno, to prevent sprintf from overwriting it + ErrnoGuard guard; +#ifdef _MSC_VER + sprintf_s(buffer, "%.3f", duration); +#else + sprintf(buffer, "%.3f", duration); +#endif + return std::string(buffer); + } + + TestEventListenerBase::TestEventListenerBase(ReporterConfig const & _config) + :StreamingReporterBase(_config) {} + + void TestEventListenerBase::assertionStarting(AssertionInfo const &) {} + + bool TestEventListenerBase::assertionEnded(AssertionStats const &) { + return false; + } + +} // end namespace Catch +// end catch_reporter_bases.cpp +// start catch_reporter_compact.cpp + +namespace { + +#ifdef CATCH_PLATFORM_MAC + const char* failedString() { return "FAILED"; } + const char* passedString() { return "PASSED"; } +#else + const char* failedString() { return "failed"; } + const char* passedString() { return "passed"; } +#endif + + // Colour::LightGrey + Catch::Colour::Code dimColour() { return Catch::Colour::FileName; } + + std::string bothOrAll( std::size_t count ) { + return count == 1 ? std::string() : + count == 2 ? "both " : "all " ; + } +} + +namespace Catch { + + struct CompactReporter : StreamingReporterBase { + + using StreamingReporterBase::StreamingReporterBase; + + ~CompactReporter() override; static std::string getDescription() { - return "Reports test results as an XML document"; + return "Reports test results on a single line, suitable for IDEs"; } - virtual std::string getStylesheetRef() const { - return std::string(); + ReporterPreferences getPreferences() const override { + ReporterPreferences prefs; + prefs.shouldRedirectStdOut = false; + return prefs; } - void writeSourceInfo( SourceLineInfo const& sourceInfo ) { - m_xml - .writeAttribute( "filename", sourceInfo.file ) - .writeAttribute( "line", sourceInfo.line ); + void noMatchingTestCases( std::string const& spec ) override { + stream << "No test cases matched '" << spec << '\'' << std::endl; } - public: // StreamingReporterBase + void assertionStarting( AssertionInfo const& ) override {} - virtual void noMatchingTestCases( std::string const& s ) CATCH_OVERRIDE { - StreamingReporterBase::noMatchingTestCases( s ); + bool assertionEnded( AssertionStats const& _assertionStats ) override { + AssertionResult const& result = _assertionStats.assertionResult; + + bool printInfoMessages = true; + + // Drop out if result was successful and we're not printing those + if( !m_config->includeSuccessfulResults() && result.isOk() ) { + if( result.getResultType() != ResultWas::Warning ) + return false; + printInfoMessages = false; + } + + AssertionPrinter printer( stream, _assertionStats, printInfoMessages ); + printer.print(); + + stream << std::endl; + return true; } - virtual void testRunStarting( TestRunInfo const& testInfo ) CATCH_OVERRIDE { - StreamingReporterBase::testRunStarting( testInfo ); - std::string stylesheetRef = getStylesheetRef(); - if( !stylesheetRef.empty() ) - m_xml.writeStylesheetRef( stylesheetRef ); - m_xml.startElement( "Catch" ); - if( !m_config->name().empty() ) - m_xml.writeAttribute( "name", m_config->name() ); - } - - virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE { - StreamingReporterBase::testGroupStarting( groupInfo ); - m_xml.startElement( "Group" ) - .writeAttribute( "name", groupInfo.name ); - } - - virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { - StreamingReporterBase::testCaseStarting(testInfo); - m_xml.startElement( "TestCase" ) - .writeAttribute( "name", trim( testInfo.name ) ) - .writeAttribute( "description", testInfo.description ) - .writeAttribute( "tags", testInfo.tagsAsString ); - - writeSourceInfo( testInfo.lineInfo ); - - if ( m_config->showDurations() == ShowDurations::Always ) - m_testCaseTimer.start(); - m_xml.ensureTagClosed(); - } - - virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE { - StreamingReporterBase::sectionStarting( sectionInfo ); - if( m_sectionDepth++ > 0 ) { - m_xml.startElement( "Section" ) - .writeAttribute( "name", trim( sectionInfo.name ) ) - .writeAttribute( "description", sectionInfo.description ); - writeSourceInfo( sectionInfo.lineInfo ); - m_xml.ensureTagClosed(); + void sectionEnded(SectionStats const& _sectionStats) override { + if (m_config->showDurations() == ShowDurations::Always) { + stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl; } } - virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE { } + void testRunEnded( TestRunStats const& _testRunStats ) override { + printTotals( _testRunStats.totals ); + stream << '\n' << std::endl; + StreamingReporterBase::testRunEnded( _testRunStats ); + } - virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { + private: + class AssertionPrinter { + public: + AssertionPrinter& operator= ( AssertionPrinter const& ) = delete; + AssertionPrinter( AssertionPrinter const& ) = delete; + AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages ) + : stream( _stream ) + , result( _stats.assertionResult ) + , messages( _stats.infoMessages ) + , itMessage( _stats.infoMessages.begin() ) + , printInfoMessages( _printInfoMessages ) + {} - AssertionResult const& result = assertionStats.assertionResult; + void print() { + printSourceInfo(); - bool includeResults = m_config->includeSuccessfulResults() || !result.isOk(); + itMessage = messages.begin(); - if( includeResults ) { - // Print any info messages in tags. - for( std::vector::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end(); - it != itEnd; - ++it ) { - if( it->type == ResultWas::Info ) { - m_xml.scopedElement( "Info" ) - .writeText( it->message ); - } else if ( it->type == ResultWas::Warning ) { - m_xml.scopedElement( "Warning" ) - .writeText( it->message ); + switch( result.getResultType() ) { + case ResultWas::Ok: + printResultType( Colour::ResultSuccess, passedString() ); + printOriginalExpression(); + printReconstructedExpression(); + if ( ! result.hasExpression() ) + printRemainingMessages( Colour::None ); + else + printRemainingMessages(); + break; + case ResultWas::ExpressionFailed: + if( result.isOk() ) + printResultType( Colour::ResultSuccess, failedString() + std::string( " - but was ok" ) ); + else + printResultType( Colour::Error, failedString() ); + printOriginalExpression(); + printReconstructedExpression(); + printRemainingMessages(); + break; + case ResultWas::ThrewException: + printResultType( Colour::Error, failedString() ); + printIssue( "unexpected exception with message:" ); + printMessage(); + printExpressionWas(); + printRemainingMessages(); + break; + case ResultWas::FatalErrorCondition: + printResultType( Colour::Error, failedString() ); + printIssue( "fatal error condition with message:" ); + printMessage(); + printExpressionWas(); + printRemainingMessages(); + break; + case ResultWas::DidntThrowException: + printResultType( Colour::Error, failedString() ); + printIssue( "expected exception, got none" ); + printExpressionWas(); + printRemainingMessages(); + break; + case ResultWas::Info: + printResultType( Colour::None, "info" ); + printMessage(); + printRemainingMessages(); + break; + case ResultWas::Warning: + printResultType( Colour::None, "warning" ); + printMessage(); + printRemainingMessages(); + break; + case ResultWas::ExplicitFailure: + printResultType( Colour::Error, failedString() ); + printIssue( "explicitly" ); + printRemainingMessages( Colour::None ); + break; + // These cases are here to prevent compiler warnings + case ResultWas::Unknown: + case ResultWas::FailureBit: + case ResultWas::Exception: + printResultType( Colour::Error, "** internal error **" ); + break; + } + } + + private: + void printSourceInfo() const { + Colour colourGuard( Colour::FileName ); + stream << result.getSourceInfo() << ':'; + } + + void printResultType( Colour::Code colour, std::string const& passOrFail ) const { + if( !passOrFail.empty() ) { + { + Colour colourGuard( colour ); + stream << ' ' << passOrFail; + } + stream << ':'; + } + } + + void printIssue( std::string const& issue ) const { + stream << ' ' << issue; + } + + void printExpressionWas() { + if( result.hasExpression() ) { + stream << ';'; + { + Colour colour( dimColour() ); + stream << " expression was:"; + } + printOriginalExpression(); + } + } + + void printOriginalExpression() const { + if( result.hasExpression() ) { + stream << ' ' << result.getExpression(); + } + } + + void printReconstructedExpression() const { + if( result.hasExpandedExpression() ) { + { + Colour colour( dimColour() ); + stream << " for: "; + } + stream << result.getExpandedExpression(); + } + } + + void printMessage() { + if ( itMessage != messages.end() ) { + stream << " '" << itMessage->message << '\''; + ++itMessage; + } + } + + void printRemainingMessages( Colour::Code colour = dimColour() ) { + if ( itMessage == messages.end() ) + return; + + // using messages.end() directly yields (or auto) compilation error: + std::vector::const_iterator itEnd = messages.end(); + const std::size_t N = static_cast( std::distance( itMessage, itEnd ) ); + + { + Colour colourGuard( colour ); + stream << " with " << pluralise( N, "message" ) << ':'; + } + + for(; itMessage != itEnd; ) { + // If this assertion is a warning ignore any INFO messages + if( printInfoMessages || itMessage->type != ResultWas::Info ) { + stream << " '" << itMessage->message << '\''; + if ( ++itMessage != itEnd ) { + Colour colourGuard( dimColour() ); + stream << " and"; + } } } } - // Drop out if result was successful but we're not printing them. - if( !includeResults && result.getResultType() != ResultWas::Warning ) - return true; + private: + std::ostream& stream; + AssertionResult const& result; + std::vector messages; + std::vector::const_iterator itMessage; + bool printInfoMessages; + }; - // Print the expression if there is one. - if( result.hasExpression() ) { - m_xml.startElement( "Expression" ) - .writeAttribute( "success", result.succeeded() ) - .writeAttribute( "type", result.getTestMacroName() ); + // Colour, message variants: + // - white: No tests ran. + // - red: Failed [both/all] N test cases, failed [both/all] M assertions. + // - white: Passed [both/all] N test cases (no assertions). + // - red: Failed N tests cases, failed M assertions. + // - green: Passed [both/all] N tests cases with M assertions. - writeSourceInfo( result.getSourceInfo() ); - - m_xml.scopedElement( "Original" ) - .writeText( result.getExpression() ); - m_xml.scopedElement( "Expanded" ) - .writeText( result.getExpandedExpression() ); + void printTotals( const Totals& totals ) const { + if( totals.testCases.total() == 0 ) { + stream << "No tests ran."; } - - // And... Print a result applicable to each result type. - switch( result.getResultType() ) { - case ResultWas::ThrewException: - m_xml.startElement( "Exception" ); - writeSourceInfo( result.getSourceInfo() ); - m_xml.writeText( result.getMessage() ); - m_xml.endElement(); - break; - case ResultWas::FatalErrorCondition: - m_xml.startElement( "FatalErrorCondition" ); - writeSourceInfo( result.getSourceInfo() ); - m_xml.writeText( result.getMessage() ); - m_xml.endElement(); - break; - case ResultWas::Info: - m_xml.scopedElement( "Info" ) - .writeText( result.getMessage() ); - break; - case ResultWas::Warning: - // Warning will already have been written - break; - case ResultWas::ExplicitFailure: - m_xml.startElement( "Failure" ); - writeSourceInfo( result.getSourceInfo() ); - m_xml.writeText( result.getMessage() ); - m_xml.endElement(); - break; - default: - break; + else if( totals.testCases.failed == totals.testCases.total() ) { + Colour colour( Colour::ResultError ); + const std::string qualify_assertions_failed = + totals.assertions.failed == totals.assertions.total() ? + bothOrAll( totals.assertions.failed ) : std::string(); + stream << + "Failed " << bothOrAll( totals.testCases.failed ) + << pluralise( totals.testCases.failed, "test case" ) << ", " + "failed " << qualify_assertions_failed << + pluralise( totals.assertions.failed, "assertion" ) << '.'; } - - if( result.hasExpression() ) - m_xml.endElement(); - - return true; - } - - virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE { - StreamingReporterBase::sectionEnded( sectionStats ); - if( --m_sectionDepth > 0 ) { - XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" ); - e.writeAttribute( "successes", sectionStats.assertions.passed ); - e.writeAttribute( "failures", sectionStats.assertions.failed ); - e.writeAttribute( "expectedFailures", sectionStats.assertions.failedButOk ); - - if ( m_config->showDurations() == ShowDurations::Always ) - e.writeAttribute( "durationInSeconds", sectionStats.durationInSeconds ); - - m_xml.endElement(); + else if( totals.assertions.total() == 0 ) { + stream << + "Passed " << bothOrAll( totals.testCases.total() ) + << pluralise( totals.testCases.total(), "test case" ) + << " (no assertions)."; + } + else if( totals.assertions.failed ) { + Colour colour( Colour::ResultError ); + stream << + "Failed " << pluralise( totals.testCases.failed, "test case" ) << ", " + "failed " << pluralise( totals.assertions.failed, "assertion" ) << '.'; + } + else { + Colour colour( Colour::ResultSuccess ); + stream << + "Passed " << bothOrAll( totals.testCases.passed ) + << pluralise( totals.testCases.passed, "test case" ) << + " with " << pluralise( totals.assertions.passed, "assertion" ) << '.'; } } - - virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { - StreamingReporterBase::testCaseEnded( testCaseStats ); - XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" ); - e.writeAttribute( "success", testCaseStats.totals.assertions.allOk() ); - - if ( m_config->showDurations() == ShowDurations::Always ) - e.writeAttribute( "durationInSeconds", m_testCaseTimer.getElapsedSeconds() ); - - if( !testCaseStats.stdOut.empty() ) - m_xml.scopedElement( "StdOut" ).writeText( trim( testCaseStats.stdOut ), false ); - if( !testCaseStats.stdErr.empty() ) - m_xml.scopedElement( "StdErr" ).writeText( trim( testCaseStats.stdErr ), false ); - - m_xml.endElement(); - } - - virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { - StreamingReporterBase::testGroupEnded( testGroupStats ); - // TODO: Check testGroupStats.aborting and act accordingly. - m_xml.scopedElement( "OverallResults" ) - .writeAttribute( "successes", testGroupStats.totals.assertions.passed ) - .writeAttribute( "failures", testGroupStats.totals.assertions.failed ) - .writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk ); - m_xml.endElement(); - } - - virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE { - StreamingReporterBase::testRunEnded( testRunStats ); - m_xml.scopedElement( "OverallResults" ) - .writeAttribute( "successes", testRunStats.totals.assertions.passed ) - .writeAttribute( "failures", testRunStats.totals.assertions.failed ) - .writeAttribute( "expectedFailures", testRunStats.totals.assertions.failedButOk ); - m_xml.endElement(); - } - - private: - Timer m_testCaseTimer; - XmlWriter m_xml; - int m_sectionDepth; }; - INTERNAL_CATCH_REGISTER_REPORTER( "xml", XmlReporter ) + CompactReporter::~CompactReporter() {} + + CATCH_REGISTER_REPORTER( "compact", CompactReporter ) } // end namespace Catch - -// #included from: ../reporters/catch_reporter_junit.hpp -#define TWOBLUECUBES_CATCH_REPORTER_JUNIT_HPP_INCLUDED - -#include - -namespace Catch { - - namespace { - std::string getCurrentTimestamp() { - // Beware, this is not reentrant because of backward compatibility issues - // Also, UTC only, again because of backward compatibility (%z is C++11) - time_t rawtime; - std::time(&rawtime); - const size_t timeStampSize = sizeof("2017-01-16T17:06:45Z"); - -#ifdef _MSC_VER - std::tm timeInfo = {}; - gmtime_s(&timeInfo, &rawtime); -#else - std::tm* timeInfo; - timeInfo = std::gmtime(&rawtime); -#endif - - char timeStamp[timeStampSize]; - const char * const fmt = "%Y-%m-%dT%H:%M:%SZ"; - -#ifdef _MSC_VER - std::strftime(timeStamp, timeStampSize, fmt, &timeInfo); -#else - std::strftime(timeStamp, timeStampSize, fmt, timeInfo); -#endif - return std::string(timeStamp); - } - - } - - class JunitReporter : public CumulativeReporterBase { - public: - JunitReporter( ReporterConfig const& _config ) - : CumulativeReporterBase( _config ), - xml( _config.stream() ), - unexpectedExceptions( 0 ), - m_okToFail( false ) - { - m_reporterPrefs.shouldRedirectStdOut = true; - } - - virtual ~JunitReporter() CATCH_OVERRIDE; - - static std::string getDescription() { - return "Reports test results in an XML format that looks like Ant's junitreport target"; - } - - virtual void noMatchingTestCases( std::string const& /*spec*/ ) CATCH_OVERRIDE {} - - virtual void testRunStarting( TestRunInfo const& runInfo ) CATCH_OVERRIDE { - CumulativeReporterBase::testRunStarting( runInfo ); - xml.startElement( "testsuites" ); - } - - virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE { - suiteTimer.start(); - stdOutForSuite.str(""); - stdErrForSuite.str(""); - unexpectedExceptions = 0; - CumulativeReporterBase::testGroupStarting( groupInfo ); - } - - virtual void testCaseStarting( TestCaseInfo const& testCaseInfo ) CATCH_OVERRIDE { - m_okToFail = testCaseInfo.okToFail(); - } - virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { - if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException && !m_okToFail ) - unexpectedExceptions++; - return CumulativeReporterBase::assertionEnded( assertionStats ); - } - - virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { - stdOutForSuite << testCaseStats.stdOut; - stdErrForSuite << testCaseStats.stdErr; - CumulativeReporterBase::testCaseEnded( testCaseStats ); - } - - virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { - double suiteTime = suiteTimer.getElapsedSeconds(); - CumulativeReporterBase::testGroupEnded( testGroupStats ); - writeGroup( *m_testGroups.back(), suiteTime ); - } - - virtual void testRunEndedCumulative() CATCH_OVERRIDE { - xml.endElement(); - } - - void writeGroup( TestGroupNode const& groupNode, double suiteTime ) { - XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" ); - TestGroupStats const& stats = groupNode.value; - xml.writeAttribute( "name", stats.groupInfo.name ); - xml.writeAttribute( "errors", unexpectedExceptions ); - xml.writeAttribute( "failures", stats.totals.assertions.failed-unexpectedExceptions ); - xml.writeAttribute( "tests", stats.totals.assertions.total() ); - xml.writeAttribute( "hostname", "tbd" ); // !TBD - if( m_config->showDurations() == ShowDurations::Never ) - xml.writeAttribute( "time", "" ); - else - xml.writeAttribute( "time", suiteTime ); - xml.writeAttribute( "timestamp", getCurrentTimestamp() ); - - // Write test cases - for( TestGroupNode::ChildNodes::const_iterator - it = groupNode.children.begin(), itEnd = groupNode.children.end(); - it != itEnd; - ++it ) - writeTestCase( **it ); - - xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite.str() ), false ); - xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite.str() ), false ); - } - - void writeTestCase( TestCaseNode const& testCaseNode ) { - TestCaseStats const& stats = testCaseNode.value; - - // All test cases have exactly one section - which represents the - // test case itself. That section may have 0-n nested sections - assert( testCaseNode.children.size() == 1 ); - SectionNode const& rootSection = *testCaseNode.children.front(); - - std::string className = stats.testInfo.className; - - if( className.empty() ) { - if( rootSection.childSections.empty() ) - className = "global"; - } - writeSection( className, "", rootSection ); - } - - void writeSection( std::string const& className, - std::string const& rootName, - SectionNode const& sectionNode ) { - std::string name = trim( sectionNode.stats.sectionInfo.name ); - if( !rootName.empty() ) - name = rootName + '/' + name; - - if( !sectionNode.assertions.empty() || - !sectionNode.stdOut.empty() || - !sectionNode.stdErr.empty() ) { - XmlWriter::ScopedElement e = xml.scopedElement( "testcase" ); - if( className.empty() ) { - xml.writeAttribute( "classname", name ); - xml.writeAttribute( "name", "root" ); - } - else { - xml.writeAttribute( "classname", className ); - xml.writeAttribute( "name", name ); - } - xml.writeAttribute( "time", Catch::toString( sectionNode.stats.durationInSeconds ) ); - - writeAssertions( sectionNode ); - - if( !sectionNode.stdOut.empty() ) - xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), false ); - if( !sectionNode.stdErr.empty() ) - xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), false ); - } - for( SectionNode::ChildSections::const_iterator - it = sectionNode.childSections.begin(), - itEnd = sectionNode.childSections.end(); - it != itEnd; - ++it ) - if( className.empty() ) - writeSection( name, "", **it ); - else - writeSection( className, name, **it ); - } - - void writeAssertions( SectionNode const& sectionNode ) { - for( SectionNode::Assertions::const_iterator - it = sectionNode.assertions.begin(), itEnd = sectionNode.assertions.end(); - it != itEnd; - ++it ) - writeAssertion( *it ); - } - void writeAssertion( AssertionStats const& stats ) { - AssertionResult const& result = stats.assertionResult; - if( !result.isOk() ) { - std::string elementName; - switch( result.getResultType() ) { - case ResultWas::ThrewException: - case ResultWas::FatalErrorCondition: - elementName = "error"; - break; - case ResultWas::ExplicitFailure: - elementName = "failure"; - break; - case ResultWas::ExpressionFailed: - elementName = "failure"; - break; - case ResultWas::DidntThrowException: - elementName = "failure"; - break; - - // We should never see these here: - case ResultWas::Info: - case ResultWas::Warning: - case ResultWas::Ok: - case ResultWas::Unknown: - case ResultWas::FailureBit: - case ResultWas::Exception: - elementName = "internalError"; - break; - } - - XmlWriter::ScopedElement e = xml.scopedElement( elementName ); - - xml.writeAttribute( "message", result.getExpandedExpression() ); - xml.writeAttribute( "type", result.getTestMacroName() ); - - std::ostringstream oss; - if( !result.getMessage().empty() ) - oss << result.getMessage() << '\n'; - for( std::vector::const_iterator - it = stats.infoMessages.begin(), - itEnd = stats.infoMessages.end(); - it != itEnd; - ++it ) - if( it->type == ResultWas::Info ) - oss << it->message << '\n'; - - oss << "at " << result.getSourceInfo(); - xml.writeText( oss.str(), false ); - } - } - - XmlWriter xml; - Timer suiteTimer; - std::ostringstream stdOutForSuite; - std::ostringstream stdErrForSuite; - unsigned int unexpectedExceptions; - bool m_okToFail; - }; - - INTERNAL_CATCH_REGISTER_REPORTER( "junit", JunitReporter ) - -} // end namespace Catch - -// #included from: ../reporters/catch_reporter_console.hpp -#define TWOBLUECUBES_CATCH_REPORTER_CONSOLE_HPP_INCLUDED +// end catch_reporter_compact.cpp +// start catch_reporter_console.cpp #include #include +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch + // Note that 4062 (not all labels are handled + // and default is missing) is enabled +#endif + namespace Catch { - struct ConsoleReporter : StreamingReporterBase { - ConsoleReporter( ReporterConfig const& _config ) - : StreamingReporterBase( _config ), - m_headerPrinted( false ) - {} + namespace { + std::size_t makeRatio( std::size_t number, std::size_t total ) { + std::size_t ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number/ total : 0; + return ( ratio == 0 && number > 0 ) ? 1 : ratio; + } - virtual ~ConsoleReporter() CATCH_OVERRIDE; + std::size_t& findMax( std::size_t& i, std::size_t& j, std::size_t& k ) { + if( i > j && i > k ) + return i; + else if( j > k ) + return j; + else + return k; + } + + struct ColumnInfo { + enum Justification { Left, Right }; + std::string name; + int width; + Justification justification; + }; + struct ColumnBreak {}; + struct RowBreak {}; + + class TablePrinter { + std::ostream& m_os; + std::vector m_columnInfos; + std::ostringstream m_oss; + int m_currentColumn = -1; + bool m_isOpen = false; + + public: + TablePrinter( std::ostream& os, std::vector const& columnInfos ) + : m_os( os ), + m_columnInfos( columnInfos ) + {} + + auto columnInfos() const -> std::vector const& { + return m_columnInfos; + } + + void open() { + if( !m_isOpen ) { + m_isOpen = true; + *this << RowBreak(); + for( auto const& info : m_columnInfos ) + *this << info.name << ColumnBreak(); + *this << RowBreak(); + m_os << Catch::getLineOfChars<'-'>() << "\n"; + } + } + void close() { + if( m_isOpen ) { + *this << RowBreak(); + m_os << std::endl; + m_isOpen = false; + } + } + + template + friend TablePrinter& operator << ( TablePrinter& tp, T const& value ) { + tp.m_oss << value; + return tp; + } + + friend TablePrinter& operator << ( TablePrinter& tp, ColumnBreak ) { + auto colStr = tp.m_oss.str(); + // This takes account of utf8 encodings + auto strSize = Catch::StringRef( colStr ).numberOfCharacters(); + tp.m_oss.str(""); + tp.open(); + if( tp.m_currentColumn == static_cast(tp.m_columnInfos.size()-1) ) { + tp.m_currentColumn = -1; + tp.m_os << "\n"; + } + tp.m_currentColumn++; + + auto colInfo = tp.m_columnInfos[tp.m_currentColumn]; + auto padding = ( strSize+2 < static_cast( colInfo.width ) ) + ? std::string( colInfo.width-(strSize+2), ' ' ) + : std::string(); + if( colInfo.justification == ColumnInfo::Left ) + tp.m_os << colStr << padding << " "; + else + tp.m_os << padding << colStr << " "; + return tp; + } + + friend TablePrinter& operator << ( TablePrinter& tp, RowBreak ) { + if( tp.m_currentColumn > 0 ) { + tp.m_os << "\n"; + tp.m_currentColumn = -1; + } + return tp; + } + }; + + class Duration { + enum class Unit { + Auto, + Nanoseconds, + Microseconds, + Milliseconds, + Seconds, + Minutes + }; + static const uint64_t s_nanosecondsInAMicrosecond = 1000; + static const uint64_t s_nanosecondsInAMillisecond = 1000*s_nanosecondsInAMicrosecond; + static const uint64_t s_nanosecondsInASecond = 1000*s_nanosecondsInAMillisecond; + static const uint64_t s_nanosecondsInAMinute = 60*s_nanosecondsInASecond; + + uint64_t m_inNanoseconds; + Unit m_units; + + public: + Duration( uint64_t inNanoseconds, Unit units = Unit::Auto ) + : m_inNanoseconds( inNanoseconds ), + m_units( units ) + { + if( m_units == Unit::Auto ) { + if( m_inNanoseconds < s_nanosecondsInAMicrosecond ) + m_units = Unit::Nanoseconds; + else if( m_inNanoseconds < s_nanosecondsInAMillisecond ) + m_units = Unit::Microseconds; + else if( m_inNanoseconds < s_nanosecondsInASecond ) + m_units = Unit::Milliseconds; + else if( m_inNanoseconds < s_nanosecondsInAMinute ) + m_units = Unit::Seconds; + else + m_units = Unit::Minutes; + } + + } + + auto value() const -> double { + switch( m_units ) { + case Unit::Microseconds: + return m_inNanoseconds / static_cast( s_nanosecondsInAMicrosecond ); + case Unit::Milliseconds: + return m_inNanoseconds / static_cast( s_nanosecondsInAMillisecond ); + case Unit::Seconds: + return m_inNanoseconds / static_cast( s_nanosecondsInASecond ); + case Unit::Minutes: + return m_inNanoseconds / static_cast( s_nanosecondsInAMinute ); + default: + return static_cast( m_inNanoseconds ); + } + } + auto unitsAsString() const -> std::string { + switch( m_units ) { + case Unit::Nanoseconds: + return "ns"; + case Unit::Microseconds: + return "µs"; + case Unit::Milliseconds: + return "ms"; + case Unit::Seconds: + return "s"; + case Unit::Minutes: + return "m"; + default: + return "** internal error **"; + } + + } + friend auto operator << ( std::ostream& os, Duration const& duration ) -> std::ostream& { + return os << duration.value() << " " << duration.unitsAsString(); + } + }; + } // end anon namespace + + struct ConsoleReporter : StreamingReporterBase { + TablePrinter m_tablePrinter; + + ConsoleReporter( ReporterConfig const& config ) + : StreamingReporterBase( config ), + m_tablePrinter( config.stream(), + { + { "benchmark name", CATCH_CONFIG_CONSOLE_WIDTH-32, ColumnInfo::Left }, + { "iters", 8, ColumnInfo::Right }, + { "elapsed ns", 14, ColumnInfo::Right }, + { "average", 14, ColumnInfo::Right } + } ) + {} + ~ConsoleReporter() override; static std::string getDescription() { return "Reports test results as plain lines of text"; } - virtual void noMatchingTestCases( std::string const& spec ) CATCH_OVERRIDE { + void noMatchingTestCases( std::string const& spec ) override { stream << "No test cases matched '" << spec << '\'' << std::endl; } - virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE { + void assertionStarting( AssertionInfo const& ) override { } - virtual bool assertionEnded( AssertionStats const& _assertionStats ) CATCH_OVERRIDE { + bool assertionEnded( AssertionStats const& _assertionStats ) override { AssertionResult const& result = _assertionStats.assertionResult; bool includeResults = m_config->includeSuccessfulResults() || !result.isOk(); @@ -10637,11 +10716,12 @@ namespace Catch { return true; } - virtual void sectionStarting( SectionInfo const& _sectionInfo ) CATCH_OVERRIDE { + void sectionStarting( SectionInfo const& _sectionInfo ) override { m_headerPrinted = false; StreamingReporterBase::sectionStarting( _sectionInfo ); } - virtual void sectionEnded( SectionStats const& _sectionStats ) CATCH_OVERRIDE { + void sectionEnded( SectionStats const& _sectionStats ) override { + m_tablePrinter.close(); if( _sectionStats.missingAssertions ) { lazyPrint(); Colour colour( Colour::ResultError ); @@ -10660,11 +10740,35 @@ namespace Catch { StreamingReporterBase::sectionEnded( _sectionStats ); } - virtual void testCaseEnded( TestCaseStats const& _testCaseStats ) CATCH_OVERRIDE { + void benchmarkStarting( BenchmarkInfo const& info ) override { + lazyPrintWithoutClosingBenchmarkTable(); + + auto nameCol = Column( info.name ).width( m_tablePrinter.columnInfos()[0].width-2 ); + + bool firstLine = true; + for( auto line : nameCol ) { + if( !firstLine ) + m_tablePrinter << ColumnBreak() << ColumnBreak() << ColumnBreak(); + else + firstLine = false; + + m_tablePrinter << line << ColumnBreak(); + } + } + void benchmarkEnded( BenchmarkStats const& stats ) override { + Duration average( stats.elapsedTimeInNanoseconds/stats.iterations ); + m_tablePrinter + << stats.iterations << ColumnBreak() + << stats.elapsedTimeInNanoseconds << ColumnBreak() + << average << ColumnBreak(); + } + + void testCaseEnded( TestCaseStats const& _testCaseStats ) override { + m_tablePrinter.close(); StreamingReporterBase::testCaseEnded( _testCaseStats ); m_headerPrinted = false; } - virtual void testGroupEnded( TestGroupStats const& _testGroupStats ) CATCH_OVERRIDE { + void testGroupEnded( TestGroupStats const& _testGroupStats ) override { if( currentGroupInfo.used ) { printSummaryDivider(); stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n"; @@ -10673,7 +10777,7 @@ namespace Catch { } StreamingReporterBase::testGroupEnded( _testGroupStats ); } - virtual void testRunEnded( TestRunStats const& _testRunStats ) CATCH_OVERRIDE { + void testRunEnded( TestRunStats const& _testRunStats ) override { printTotalsDivider( _testRunStats.totals ); printTotals( _testRunStats.totals ); stream << std::endl; @@ -10683,8 +10787,9 @@ namespace Catch { private: class AssertionPrinter { - void operator= ( AssertionPrinter const& ); public: + AssertionPrinter& operator= ( AssertionPrinter const& ) = delete; + AssertionPrinter( AssertionPrinter const& ) = delete; AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages ) : stream( _stream ), stats( _stats ), @@ -10795,18 +10900,16 @@ namespace Catch { if( result.hasExpandedExpression() ) { stream << "with expansion:\n"; Colour colourGuard( Colour::ReconstructedExpression ); - stream << Text( result.getExpandedExpression(), TextAttributes().setIndent(2) ) << '\n'; + stream << Column( result.getExpandedExpression() ).indent(2) << '\n'; } } void printMessage() const { if( !messageLabel.empty() ) stream << messageLabel << ':' << '\n'; - for( std::vector::const_iterator it = messages.begin(), itEnd = messages.end(); - it != itEnd; - ++it ) { + for( auto const& msg : messages ) { // If this assertion is a warning ignore any INFO messages - if( printInfoMessages || it->type != ResultWas::Info ) - stream << Text( it->message, TextAttributes().setIndent(2) ) << '\n'; + if( printInfoMessages || msg.type != ResultWas::Info ) + stream << Column( msg.message ).indent(2) << '\n'; } } void printSourceInfo() const { @@ -10827,6 +10930,12 @@ namespace Catch { void lazyPrint() { + m_tablePrinter.close(); + lazyPrintWithoutClosingBenchmarkTable(); + } + + void lazyPrintWithoutClosingBenchmarkTable() { + if( !currentTestRunInfo.used ) lazyPrintRunInfo(); if( !currentGroupInfo.used ) @@ -10862,7 +10971,7 @@ namespace Catch { if( m_sectionStack.size() > 1 ) { Colour colourGuard( Colour::Headers ); - std::vector::const_iterator + auto it = m_sectionStack.begin()+1, // Skip first section (test case) itEnd = m_sectionStack.end(); for( ; it != itEnd; ++it ) @@ -10899,9 +11008,7 @@ namespace Catch { i+=2; else i = 0; - stream << Text( _string, TextAttributes() - .setIndent( indent+i) - .setInitialIndent( indent ) ) << '\n'; + stream << Column( _string ).indent( indent+i ).initialIndent( indent ) << '\n'; } struct SummaryColumn { @@ -10914,10 +11021,10 @@ namespace Catch { std::ostringstream oss; oss << count; std::string row = oss.str(); - for( std::vector::iterator it = rows.begin(); it != rows.end(); ++it ) { - while( it->size() < row.size() ) - *it = ' ' + *it; - while( it->size() > row.size() ) + for( auto& oldRow : rows ) { + while( oldRow.size() < row.size() ) + oldRow = ' ' + oldRow; + while( oldRow.size() > row.size() ) row = ' ' + row; } rows.push_back( row ); @@ -10962,9 +11069,9 @@ namespace Catch { } } void printSummaryRow( std::string const& label, std::vector const& cols, std::size_t row ) { - for( std::vector::const_iterator it = cols.begin(); it != cols.end(); ++it ) { - std::string value = it->rows[row]; - if( it->label.empty() ) { + for( auto col : cols ) { + std::string value = col.rows[row]; + if( col.label.empty() ) { stream << label << ": "; if( value != "0" ) stream << value; @@ -10973,26 +11080,13 @@ namespace Catch { } else if( value != "0" ) { stream << Colour( Colour::LightGrey ) << " | "; - stream << Colour( it->colour ) - << value << ' ' << it->label; + stream << Colour( col.colour ) + << value << ' ' << col.label; } } stream << '\n'; } - static std::size_t makeRatio( std::size_t number, std::size_t total ) { - std::size_t ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number/ total : 0; - return ( ratio == 0 && number > 0 ) ? 1 : ratio; - } - static std::size_t& findMax( std::size_t& i, std::size_t& j, std::size_t& k ) { - if( i > j && i > k ) - return i; - else if( j > k ) - return j; - else - return k; - } - void printTotalsDivider( Totals const& totals ) { if( totals.testCases.total() > 0 ) { std::size_t failedRatio = makeRatio( totals.testCases.failed, totals.testCases.total() ); @@ -11020,374 +11114,594 @@ namespace Catch { } private: - bool m_headerPrinted; + bool m_headerPrinted = false; }; - INTERNAL_CATCH_REGISTER_REPORTER( "console", ConsoleReporter ) + CATCH_REGISTER_REPORTER( "console", ConsoleReporter ) + + ConsoleReporter::~ConsoleReporter() {} } // end namespace Catch -// #included from: ../reporters/catch_reporter_compact.hpp -#define TWOBLUECUBES_CATCH_REPORTER_COMPACT_HPP_INCLUDED +#if defined(_MSC_VER) +#pragma warning(pop) +#endif +// end catch_reporter_console.cpp +// start catch_reporter_junit.cpp + +#include + +#include +#include namespace Catch { - struct CompactReporter : StreamingReporterBase { + namespace { + std::string getCurrentTimestamp() { + // Beware, this is not reentrant because of backward compatibility issues + // Also, UTC only, again because of backward compatibility (%z is C++11) + time_t rawtime; + std::time(&rawtime); + auto const timeStampSize = sizeof("2017-01-16T17:06:45Z"); - CompactReporter( ReporterConfig const& _config ) - : StreamingReporterBase( _config ) - {} +#ifdef _MSC_VER + std::tm timeInfo = {}; + gmtime_s(&timeInfo, &rawtime); +#else + std::tm* timeInfo; + timeInfo = std::gmtime(&rawtime); +#endif - virtual ~CompactReporter(); + char timeStamp[timeStampSize]; + const char * const fmt = "%Y-%m-%dT%H:%M:%SZ"; + +#ifdef _MSC_VER + std::strftime(timeStamp, timeStampSize, fmt, &timeInfo); +#else + std::strftime(timeStamp, timeStampSize, fmt, timeInfo); +#endif + return std::string(timeStamp); + } + + std::string fileNameTag(const std::vector &tags) { + auto it = std::find_if(begin(tags), + end(tags), + [] (std::string const& tag) {return tag.front() == '#'; }); + if (it != tags.end()) + return it->substr(1); + return std::string(); + } + } + + class JunitReporter : public CumulativeReporterBase { + public: + JunitReporter( ReporterConfig const& _config ) + : CumulativeReporterBase( _config ), + xml( _config.stream() ) + { + m_reporterPrefs.shouldRedirectStdOut = true; + } + + ~JunitReporter() override; static std::string getDescription() { - return "Reports test results on a single line, suitable for IDEs"; + return "Reports test results in an XML format that looks like Ant's junitreport target"; } - virtual ReporterPreferences getPreferences() const { - ReporterPreferences prefs; - prefs.shouldRedirectStdOut = false; - return prefs; + void noMatchingTestCases( std::string const& /*spec*/ ) override {} + + void testRunStarting( TestRunInfo const& runInfo ) override { + CumulativeReporterBase::testRunStarting( runInfo ); + xml.startElement( "testsuites" ); } - virtual void noMatchingTestCases( std::string const& spec ) { - stream << "No test cases matched '" << spec << '\'' << std::endl; + void testGroupStarting( GroupInfo const& groupInfo ) override { + suiteTimer.start(); + stdOutForSuite.str(""); + stdErrForSuite.str(""); + unexpectedExceptions = 0; + CumulativeReporterBase::testGroupStarting( groupInfo ); } - virtual void assertionStarting( AssertionInfo const& ) {} + void testCaseStarting( TestCaseInfo const& testCaseInfo ) override { + m_okToFail = testCaseInfo.okToFail(); + } + bool assertionEnded( AssertionStats const& assertionStats ) override { + if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException && !m_okToFail ) + unexpectedExceptions++; + return CumulativeReporterBase::assertionEnded( assertionStats ); + } - virtual bool assertionEnded( AssertionStats const& _assertionStats ) { - AssertionResult const& result = _assertionStats.assertionResult; + void testCaseEnded( TestCaseStats const& testCaseStats ) override { + stdOutForSuite << testCaseStats.stdOut; + stdErrForSuite << testCaseStats.stdErr; + CumulativeReporterBase::testCaseEnded( testCaseStats ); + } - bool printInfoMessages = true; + void testGroupEnded( TestGroupStats const& testGroupStats ) override { + double suiteTime = suiteTimer.getElapsedSeconds(); + CumulativeReporterBase::testGroupEnded( testGroupStats ); + writeGroup( *m_testGroups.back(), suiteTime ); + } - // Drop out if result was successful and we're not printing those - if( !m_config->includeSuccessfulResults() && result.isOk() ) { - if( result.getResultType() != ResultWas::Warning ) - return false; - printInfoMessages = false; + void testRunEndedCumulative() override { + xml.endElement(); + } + + void writeGroup( TestGroupNode const& groupNode, double suiteTime ) { + XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" ); + TestGroupStats const& stats = groupNode.value; + xml.writeAttribute( "name", stats.groupInfo.name ); + xml.writeAttribute( "errors", unexpectedExceptions ); + xml.writeAttribute( "failures", stats.totals.assertions.failed-unexpectedExceptions ); + xml.writeAttribute( "tests", stats.totals.assertions.total() ); + xml.writeAttribute( "hostname", "tbd" ); // !TBD + if( m_config->showDurations() == ShowDurations::Never ) + xml.writeAttribute( "time", "" ); + else + xml.writeAttribute( "time", suiteTime ); + xml.writeAttribute( "timestamp", getCurrentTimestamp() ); + + // Write test cases + for( auto const& child : groupNode.children ) + writeTestCase( *child ); + + xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite.str() ), false ); + xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite.str() ), false ); + } + + void writeTestCase( TestCaseNode const& testCaseNode ) { + TestCaseStats const& stats = testCaseNode.value; + + // All test cases have exactly one section - which represents the + // test case itself. That section may have 0-n nested sections + assert( testCaseNode.children.size() == 1 ); + SectionNode const& rootSection = *testCaseNode.children.front(); + + std::string className = stats.testInfo.className; + + if( className.empty() ) { + className = fileNameTag(stats.testInfo.tags); + if ( className.empty() ) + className = "global"; } - AssertionPrinter printer( stream, _assertionStats, printInfoMessages ); - printer.print(); + if ( !m_config->name().empty() ) + className = m_config->name() + "." + className; - stream << std::endl; - return true; + writeSection( className, "", rootSection ); } - virtual void sectionEnded(SectionStats const& _sectionStats) CATCH_OVERRIDE { - if (m_config->showDurations() == ShowDurations::Always) { - stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl; + void writeSection( std::string const& className, + std::string const& rootName, + SectionNode const& sectionNode ) { + std::string name = trim( sectionNode.stats.sectionInfo.name ); + if( !rootName.empty() ) + name = rootName + '/' + name; + + if( !sectionNode.assertions.empty() || + !sectionNode.stdOut.empty() || + !sectionNode.stdErr.empty() ) { + XmlWriter::ScopedElement e = xml.scopedElement( "testcase" ); + if( className.empty() ) { + xml.writeAttribute( "classname", name ); + xml.writeAttribute( "name", "root" ); + } + else { + xml.writeAttribute( "classname", className ); + xml.writeAttribute( "name", name ); + } + xml.writeAttribute( "time", ::Catch::Detail::stringify( sectionNode.stats.durationInSeconds ) ); + + writeAssertions( sectionNode ); + + if( !sectionNode.stdOut.empty() ) + xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), false ); + if( !sectionNode.stdErr.empty() ) + xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), false ); } + for( auto const& childNode : sectionNode.childSections ) + if( className.empty() ) + writeSection( name, "", *childNode ); + else + writeSection( className, name, *childNode ); } - virtual void testRunEnded( TestRunStats const& _testRunStats ) { - printTotals( _testRunStats.totals ); - stream << '\n' << std::endl; - StreamingReporterBase::testRunEnded( _testRunStats ); + void writeAssertions( SectionNode const& sectionNode ) { + for( auto const& assertion : sectionNode.assertions ) + writeAssertion( assertion ); } - - private: - class AssertionPrinter { - void operator= ( AssertionPrinter const& ); - public: - AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages ) - : stream( _stream ) - , stats( _stats ) - , result( _stats.assertionResult ) - , messages( _stats.infoMessages ) - , itMessage( _stats.infoMessages.begin() ) - , printInfoMessages( _printInfoMessages ) - {} - - void print() { - printSourceInfo(); - - itMessage = messages.begin(); - + void writeAssertion( AssertionStats const& stats ) { + AssertionResult const& result = stats.assertionResult; + if( !result.isOk() ) { + std::string elementName; switch( result.getResultType() ) { - case ResultWas::Ok: - printResultType( Colour::ResultSuccess, passedString() ); - printOriginalExpression(); - printReconstructedExpression(); - if ( ! result.hasExpression() ) - printRemainingMessages( Colour::None ); - else - printRemainingMessages(); - break; - case ResultWas::ExpressionFailed: - if( result.isOk() ) - printResultType( Colour::ResultSuccess, failedString() + std::string( " - but was ok" ) ); - else - printResultType( Colour::Error, failedString() ); - printOriginalExpression(); - printReconstructedExpression(); - printRemainingMessages(); - break; case ResultWas::ThrewException: - printResultType( Colour::Error, failedString() ); - printIssue( "unexpected exception with message:" ); - printMessage(); - printExpressionWas(); - printRemainingMessages(); - break; case ResultWas::FatalErrorCondition: - printResultType( Colour::Error, failedString() ); - printIssue( "fatal error condition with message:" ); - printMessage(); - printExpressionWas(); - printRemainingMessages(); - break; - case ResultWas::DidntThrowException: - printResultType( Colour::Error, failedString() ); - printIssue( "expected exception, got none" ); - printExpressionWas(); - printRemainingMessages(); - break; - case ResultWas::Info: - printResultType( Colour::None, "info" ); - printMessage(); - printRemainingMessages(); - break; - case ResultWas::Warning: - printResultType( Colour::None, "warning" ); - printMessage(); - printRemainingMessages(); + elementName = "error"; break; case ResultWas::ExplicitFailure: - printResultType( Colour::Error, failedString() ); - printIssue( "explicitly" ); - printRemainingMessages( Colour::None ); + elementName = "failure"; break; - // These cases are here to prevent compiler warnings + case ResultWas::ExpressionFailed: + elementName = "failure"; + break; + case ResultWas::DidntThrowException: + elementName = "failure"; + break; + + // We should never see these here: + case ResultWas::Info: + case ResultWas::Warning: + case ResultWas::Ok: case ResultWas::Unknown: case ResultWas::FailureBit: case ResultWas::Exception: - printResultType( Colour::Error, "** internal error **" ); + elementName = "internalError"; break; } - } - private: - // Colour::LightGrey + XmlWriter::ScopedElement e = xml.scopedElement( elementName ); - static Colour::Code dimColour() { return Colour::FileName; } + xml.writeAttribute( "message", result.getExpandedExpression() ); + xml.writeAttribute( "type", result.getTestMacroName() ); -#ifdef CATCH_PLATFORM_MAC - static const char* failedString() { return "FAILED"; } - static const char* passedString() { return "PASSED"; } -#else - static const char* failedString() { return "failed"; } - static const char* passedString() { return "passed"; } -#endif + std::ostringstream oss; + if( !result.getMessage().empty() ) + oss << result.getMessage() << '\n'; + for( auto const& msg : stats.infoMessages ) + if( msg.type == ResultWas::Info ) + oss << msg.message << '\n'; - void printSourceInfo() const { - Colour colourGuard( Colour::FileName ); - stream << result.getSourceInfo() << ':'; - } - - void printResultType( Colour::Code colour, std::string const& passOrFail ) const { - if( !passOrFail.empty() ) { - { - Colour colourGuard( colour ); - stream << ' ' << passOrFail; - } - stream << ':'; - } - } - - void printIssue( std::string const& issue ) const { - stream << ' ' << issue; - } - - void printExpressionWas() { - if( result.hasExpression() ) { - stream << ';'; - { - Colour colour( dimColour() ); - stream << " expression was:"; - } - printOriginalExpression(); - } - } - - void printOriginalExpression() const { - if( result.hasExpression() ) { - stream << ' ' << result.getExpression(); - } - } - - void printReconstructedExpression() const { - if( result.hasExpandedExpression() ) { - { - Colour colour( dimColour() ); - stream << " for: "; - } - stream << result.getExpandedExpression(); - } - } - - void printMessage() { - if ( itMessage != messages.end() ) { - stream << " '" << itMessage->message << '\''; - ++itMessage; - } - } - - void printRemainingMessages( Colour::Code colour = dimColour() ) { - if ( itMessage == messages.end() ) - return; - - // using messages.end() directly yields compilation error: - std::vector::const_iterator itEnd = messages.end(); - const std::size_t N = static_cast( std::distance( itMessage, itEnd ) ); - - { - Colour colourGuard( colour ); - stream << " with " << pluralise( N, "message" ) << ':'; - } - - for(; itMessage != itEnd; ) { - // If this assertion is a warning ignore any INFO messages - if( printInfoMessages || itMessage->type != ResultWas::Info ) { - stream << " '" << itMessage->message << '\''; - if ( ++itMessage != itEnd ) { - Colour colourGuard( dimColour() ); - stream << " and"; - } - } - } - } - - private: - std::ostream& stream; - AssertionStats const& stats; - AssertionResult const& result; - std::vector messages; - std::vector::const_iterator itMessage; - bool printInfoMessages; - }; - - // Colour, message variants: - // - white: No tests ran. - // - red: Failed [both/all] N test cases, failed [both/all] M assertions. - // - white: Passed [both/all] N test cases (no assertions). - // - red: Failed N tests cases, failed M assertions. - // - green: Passed [both/all] N tests cases with M assertions. - - std::string bothOrAll( std::size_t count ) const { - return count == 1 ? std::string() : count == 2 ? "both " : "all " ; - } - - void printTotals( const Totals& totals ) const { - if( totals.testCases.total() == 0 ) { - stream << "No tests ran."; - } - else if( totals.testCases.failed == totals.testCases.total() ) { - Colour colour( Colour::ResultError ); - const std::string qualify_assertions_failed = - totals.assertions.failed == totals.assertions.total() ? - bothOrAll( totals.assertions.failed ) : std::string(); - stream << - "Failed " << bothOrAll( totals.testCases.failed ) - << pluralise( totals.testCases.failed, "test case" ) << ", " - "failed " << qualify_assertions_failed << - pluralise( totals.assertions.failed, "assertion" ) << '.'; - } - else if( totals.assertions.total() == 0 ) { - stream << - "Passed " << bothOrAll( totals.testCases.total() ) - << pluralise( totals.testCases.total(), "test case" ) - << " (no assertions)."; - } - else if( totals.assertions.failed ) { - Colour colour( Colour::ResultError ); - stream << - "Failed " << pluralise( totals.testCases.failed, "test case" ) << ", " - "failed " << pluralise( totals.assertions.failed, "assertion" ) << '.'; - } - else { - Colour colour( Colour::ResultSuccess ); - stream << - "Passed " << bothOrAll( totals.testCases.passed ) - << pluralise( totals.testCases.passed, "test case" ) << - " with " << pluralise( totals.assertions.passed, "assertion" ) << '.'; + oss << "at " << result.getSourceInfo(); + xml.writeText( oss.str(), false ); } } + + XmlWriter xml; + Timer suiteTimer; + std::ostringstream stdOutForSuite; + std::ostringstream stdErrForSuite; + unsigned int unexpectedExceptions = 0; + bool m_okToFail = false; }; - INTERNAL_CATCH_REGISTER_REPORTER( "compact", CompactReporter ) + JunitReporter::~JunitReporter() {} + CATCH_REGISTER_REPORTER( "junit", JunitReporter ) + +} // end namespace Catch +// end catch_reporter_junit.cpp +// start catch_reporter_multi.cpp + +namespace Catch { + + void MultipleReporters::add( IStreamingReporterPtr&& reporter ) { + m_reporters.push_back( std::move( reporter ) ); + } + + ReporterPreferences MultipleReporters::getPreferences() const { + return m_reporters[0]->getPreferences(); + } + + std::set MultipleReporters::getSupportedVerbosities() { + return std::set{ }; + } + + void MultipleReporters::noMatchingTestCases( std::string const& spec ) { + for( auto const& reporter : m_reporters ) + reporter->noMatchingTestCases( spec ); + } + + void MultipleReporters::benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) { + for( auto const& reporter : m_reporters ) + reporter->benchmarkStarting( benchmarkInfo ); + } + void MultipleReporters::benchmarkEnded( BenchmarkStats const& benchmarkStats ) { + for( auto const& reporter : m_reporters ) + reporter->benchmarkEnded( benchmarkStats ); + } + + void MultipleReporters::testRunStarting( TestRunInfo const& testRunInfo ) { + for( auto const& reporter : m_reporters ) + reporter->testRunStarting( testRunInfo ); + } + + void MultipleReporters::testGroupStarting( GroupInfo const& groupInfo ) { + for( auto const& reporter : m_reporters ) + reporter->testGroupStarting( groupInfo ); + } + + void MultipleReporters::testCaseStarting( TestCaseInfo const& testInfo ) { + for( auto const& reporter : m_reporters ) + reporter->testCaseStarting( testInfo ); + } + + void MultipleReporters::sectionStarting( SectionInfo const& sectionInfo ) { + for( auto const& reporter : m_reporters ) + reporter->sectionStarting( sectionInfo ); + } + + void MultipleReporters::assertionStarting( AssertionInfo const& assertionInfo ) { + for( auto const& reporter : m_reporters ) + reporter->assertionStarting( assertionInfo ); + } + + // The return value indicates if the messages buffer should be cleared: + bool MultipleReporters::assertionEnded( AssertionStats const& assertionStats ) { + bool clearBuffer = false; + for( auto const& reporter : m_reporters ) + clearBuffer |= reporter->assertionEnded( assertionStats ); + return clearBuffer; + } + + void MultipleReporters::sectionEnded( SectionStats const& sectionStats ) { + for( auto const& reporter : m_reporters ) + reporter->sectionEnded( sectionStats ); + } + + void MultipleReporters::testCaseEnded( TestCaseStats const& testCaseStats ) { + for( auto const& reporter : m_reporters ) + reporter->testCaseEnded( testCaseStats ); + } + + void MultipleReporters::testGroupEnded( TestGroupStats const& testGroupStats ) { + for( auto const& reporter : m_reporters ) + reporter->testGroupEnded( testGroupStats ); + } + + void MultipleReporters::testRunEnded( TestRunStats const& testRunStats ) { + for( auto const& reporter : m_reporters ) + reporter->testRunEnded( testRunStats ); + } + + void MultipleReporters::skipTest( TestCaseInfo const& testInfo ) { + for( auto const& reporter : m_reporters ) + reporter->skipTest( testInfo ); + } + + bool MultipleReporters::isMulti() const { + return true; + } + +} // end namespace Catch +// end catch_reporter_multi.cpp +// start catch_reporter_xml.cpp + +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch + // Note that 4062 (not all labels are handled + // and default is missing) is enabled +#endif + +namespace Catch { + class XmlReporter : public StreamingReporterBase { + public: + XmlReporter( ReporterConfig const& _config ) + : StreamingReporterBase( _config ), + m_xml(_config.stream()) + { + m_reporterPrefs.shouldRedirectStdOut = true; + } + + ~XmlReporter() override; + + static std::string getDescription() { + return "Reports test results as an XML document"; + } + + virtual std::string getStylesheetRef() const { + return std::string(); + } + + void writeSourceInfo( SourceLineInfo const& sourceInfo ) { + m_xml + .writeAttribute( "filename", sourceInfo.file ) + .writeAttribute( "line", sourceInfo.line ); + } + + public: // StreamingReporterBase + + void noMatchingTestCases( std::string const& s ) override { + StreamingReporterBase::noMatchingTestCases( s ); + } + + void testRunStarting( TestRunInfo const& testInfo ) override { + StreamingReporterBase::testRunStarting( testInfo ); + std::string stylesheetRef = getStylesheetRef(); + if( !stylesheetRef.empty() ) + m_xml.writeStylesheetRef( stylesheetRef ); + m_xml.startElement( "Catch" ); + if( !m_config->name().empty() ) + m_xml.writeAttribute( "name", m_config->name() ); + } + + void testGroupStarting( GroupInfo const& groupInfo ) override { + StreamingReporterBase::testGroupStarting( groupInfo ); + m_xml.startElement( "Group" ) + .writeAttribute( "name", groupInfo.name ); + } + + void testCaseStarting( TestCaseInfo const& testInfo ) override { + StreamingReporterBase::testCaseStarting(testInfo); + m_xml.startElement( "TestCase" ) + .writeAttribute( "name", trim( testInfo.name ) ) + .writeAttribute( "description", testInfo.description ) + .writeAttribute( "tags", testInfo.tagsAsString() ); + + writeSourceInfo( testInfo.lineInfo ); + + if ( m_config->showDurations() == ShowDurations::Always ) + m_testCaseTimer.start(); + m_xml.ensureTagClosed(); + } + + void sectionStarting( SectionInfo const& sectionInfo ) override { + StreamingReporterBase::sectionStarting( sectionInfo ); + if( m_sectionDepth++ > 0 ) { + m_xml.startElement( "Section" ) + .writeAttribute( "name", trim( sectionInfo.name ) ) + .writeAttribute( "description", sectionInfo.description ); + writeSourceInfo( sectionInfo.lineInfo ); + m_xml.ensureTagClosed(); + } + } + + void assertionStarting( AssertionInfo const& ) override { } + + bool assertionEnded( AssertionStats const& assertionStats ) override { + + AssertionResult const& result = assertionStats.assertionResult; + + bool includeResults = m_config->includeSuccessfulResults() || !result.isOk(); + + if( includeResults ) { + // Print any info messages in tags. + for( auto const& msg : assertionStats.infoMessages ) { + if( msg.type == ResultWas::Info ) { + m_xml.scopedElement( "Info" ) + .writeText( msg.message ); + } else if ( msg.type == ResultWas::Warning ) { + m_xml.scopedElement( "Warning" ) + .writeText( msg.message ); + } + } + } + + // Drop out if result was successful but we're not printing them. + if( !includeResults && result.getResultType() != ResultWas::Warning ) + return true; + + // Print the expression if there is one. + if( result.hasExpression() ) { + m_xml.startElement( "Expression" ) + .writeAttribute( "success", result.succeeded() ) + .writeAttribute( "type", result.getTestMacroName() ); + + writeSourceInfo( result.getSourceInfo() ); + + m_xml.scopedElement( "Original" ) + .writeText( result.getExpression() ); + m_xml.scopedElement( "Expanded" ) + .writeText( result.getExpandedExpression() ); + } + + // And... Print a result applicable to each result type. + switch( result.getResultType() ) { + case ResultWas::ThrewException: + m_xml.startElement( "Exception" ); + writeSourceInfo( result.getSourceInfo() ); + m_xml.writeText( result.getMessage() ); + m_xml.endElement(); + break; + case ResultWas::FatalErrorCondition: + m_xml.startElement( "FatalErrorCondition" ); + writeSourceInfo( result.getSourceInfo() ); + m_xml.writeText( result.getMessage() ); + m_xml.endElement(); + break; + case ResultWas::Info: + m_xml.scopedElement( "Info" ) + .writeText( result.getMessage() ); + break; + case ResultWas::Warning: + // Warning will already have been written + break; + case ResultWas::ExplicitFailure: + m_xml.startElement( "Failure" ); + writeSourceInfo( result.getSourceInfo() ); + m_xml.writeText( result.getMessage() ); + m_xml.endElement(); + break; + default: + break; + } + + if( result.hasExpression() ) + m_xml.endElement(); + + return true; + } + + void sectionEnded( SectionStats const& sectionStats ) override { + StreamingReporterBase::sectionEnded( sectionStats ); + if( --m_sectionDepth > 0 ) { + XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" ); + e.writeAttribute( "successes", sectionStats.assertions.passed ); + e.writeAttribute( "failures", sectionStats.assertions.failed ); + e.writeAttribute( "expectedFailures", sectionStats.assertions.failedButOk ); + + if ( m_config->showDurations() == ShowDurations::Always ) + e.writeAttribute( "durationInSeconds", sectionStats.durationInSeconds ); + + m_xml.endElement(); + } + } + + void testCaseEnded( TestCaseStats const& testCaseStats ) override { + StreamingReporterBase::testCaseEnded( testCaseStats ); + XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" ); + e.writeAttribute( "success", testCaseStats.totals.assertions.allOk() ); + + if ( m_config->showDurations() == ShowDurations::Always ) + e.writeAttribute( "durationInSeconds", m_testCaseTimer.getElapsedSeconds() ); + + if( !testCaseStats.stdOut.empty() ) + m_xml.scopedElement( "StdOut" ).writeText( trim( testCaseStats.stdOut ), false ); + if( !testCaseStats.stdErr.empty() ) + m_xml.scopedElement( "StdErr" ).writeText( trim( testCaseStats.stdErr ), false ); + + m_xml.endElement(); + } + + void testGroupEnded( TestGroupStats const& testGroupStats ) override { + StreamingReporterBase::testGroupEnded( testGroupStats ); + // TODO: Check testGroupStats.aborting and act accordingly. + m_xml.scopedElement( "OverallResults" ) + .writeAttribute( "successes", testGroupStats.totals.assertions.passed ) + .writeAttribute( "failures", testGroupStats.totals.assertions.failed ) + .writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk ); + m_xml.endElement(); + } + + void testRunEnded( TestRunStats const& testRunStats ) override { + StreamingReporterBase::testRunEnded( testRunStats ); + m_xml.scopedElement( "OverallResults" ) + .writeAttribute( "successes", testRunStats.totals.assertions.passed ) + .writeAttribute( "failures", testRunStats.totals.assertions.failed ) + .writeAttribute( "expectedFailures", testRunStats.totals.assertions.failedButOk ); + m_xml.endElement(); + } + + private: + Timer m_testCaseTimer; + XmlWriter m_xml; + int m_sectionDepth = 0; + }; + + XmlReporter::~XmlReporter() {} + CATCH_REGISTER_REPORTER( "xml", XmlReporter ) } // end namespace Catch +#if defined(_MSC_VER) +#pragma warning(pop) +#endif +// end catch_reporter_xml.cpp + namespace Catch { - // These are all here to avoid warnings about not having any out of line - // virtual methods - NonCopyable::~NonCopyable() {} - IShared::~IShared() {} - IStream::~IStream() CATCH_NOEXCEPT {} - FileStream::~FileStream() CATCH_NOEXCEPT {} - CoutStream::~CoutStream() CATCH_NOEXCEPT {} - DebugOutStream::~DebugOutStream() CATCH_NOEXCEPT {} - StreamBufBase::~StreamBufBase() CATCH_NOEXCEPT {} - IContext::~IContext() {} - IResultCapture::~IResultCapture() {} - ITestCase::~ITestCase() {} - ITestCaseRegistry::~ITestCaseRegistry() {} - IRegistryHub::~IRegistryHub() {} - IMutableRegistryHub::~IMutableRegistryHub() {} - IExceptionTranslator::~IExceptionTranslator() {} - IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() {} - IReporter::~IReporter() {} - IReporterFactory::~IReporterFactory() {} - IReporterRegistry::~IReporterRegistry() {} - IStreamingReporter::~IStreamingReporter() {} - AssertionStats::~AssertionStats() {} - SectionStats::~SectionStats() {} - TestCaseStats::~TestCaseStats() {} - TestGroupStats::~TestGroupStats() {} - TestRunStats::~TestRunStats() {} - CumulativeReporterBase::SectionNode::~SectionNode() {} - CumulativeReporterBase::~CumulativeReporterBase() {} - - StreamingReporterBase::~StreamingReporterBase() {} - ConsoleReporter::~ConsoleReporter() {} - CompactReporter::~CompactReporter() {} - IRunner::~IRunner() {} - IMutableContext::~IMutableContext() {} - IConfig::~IConfig() {} - XmlReporter::~XmlReporter() {} - JunitReporter::~JunitReporter() {} - TestRegistry::~TestRegistry() {} - FreeFunctionTestCase::~FreeFunctionTestCase() {} - IGeneratorInfo::~IGeneratorInfo() {} - IGeneratorsForTest::~IGeneratorsForTest() {} - WildcardPattern::~WildcardPattern() {} - TestSpec::Pattern::~Pattern() {} - TestSpec::NamePattern::~NamePattern() {} - TestSpec::TagPattern::~TagPattern() {} - TestSpec::ExcludedPattern::~ExcludedPattern() {} - Matchers::Impl::MatcherUntypedBase::~MatcherUntypedBase() {} - - void Config::dummy() {} - - namespace TestCaseTracking { - ITracker::~ITracker() {} - TrackerBase::~TrackerBase() {} - SectionTracker::~SectionTracker() {} - IndexTracker::~IndexTracker() {} - } + LeakDetector leakDetector; } #ifdef __clang__ #pragma clang diagnostic pop #endif +// end catch_impl.hpp #endif #ifdef CATCH_CONFIG_MAIN -// #included from: internal/catch_default_main.hpp -#define TWOBLUECUBES_CATCH_DEFAULT_MAIN_HPP_INCLUDED +// start catch_default_main.hpp #ifndef __OBJC__ @@ -11399,8 +11713,7 @@ extern "C" int wmain (int argc, wchar_t * argv[], wchar_t * []) { int main (int argc, char * argv[]) { #endif - int result = Catch::Session().run( argc, argv ); - return ( result < 0xff ? result : 0xff ); + return Catch::Session().run( argc, argv ); } #else // __OBJC__ @@ -11412,149 +11725,122 @@ int main (int argc, char * const argv[]) { #endif Catch::registerTestMethods(); - int result = Catch::Session().run( argc, (char* const*)argv ); + int result = Catch::Session().run( argc, (char**)argv ); #if !CATCH_ARC_ENABLED [pool drain]; #endif - return ( result < 0xff ? result : 0xff ); + return result; } #endif // __OBJC__ +// end catch_default_main.hpp #endif #ifdef CLARA_CONFIG_MAIN_NOT_DEFINED # undef CLARA_CONFIG_MAIN #endif +#if !defined(CATCH_CONFIG_DISABLE) ////// - // If this config identifier is defined then all CATCH macros are prefixed with CATCH_ #ifdef CATCH_CONFIG_PREFIX_ALL -#if defined(CATCH_CONFIG_FAST_COMPILE) -#define CATCH_REQUIRE( expr ) INTERNAL_CATCH_TEST_NO_TRY( "CATCH_REQUIRE", Catch::ResultDisposition::Normal, expr ) -#define CATCH_REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST_NO_TRY( "CATCH_REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, expr ) -#else -#define CATCH_REQUIRE( expr ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE", Catch::ResultDisposition::Normal, expr ) -#define CATCH_REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, expr ) -#endif +#define CATCH_REQUIRE( ... ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE", Catch::ResultDisposition::Normal, __VA_ARGS__ ) +#define CATCH_REQUIRE_FALSE( ... ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, __VA_ARGS__ ) -#define CATCH_REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS", Catch::ResultDisposition::Normal, "", expr ) +#define CATCH_REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS", Catch::ResultDisposition::Normal, "", __VA_ARGS__ ) #define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr ) -#define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr ) -#define CATCH_REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( "CATCH_REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, expr ) +#define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CATCH_REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr ) +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) +#define CATCH_REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CATCH_REQUIRE_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::Normal, matcher, expr ) +#endif// CATCH_CONFIG_DISABLE_MATCHERS +#define CATCH_REQUIRE_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CATCH_REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, __VA_ARGS__ ) -#define CATCH_CHECK( expr ) INTERNAL_CATCH_TEST( "CATCH_CHECK", Catch::ResultDisposition::ContinueOnFailure, expr ) -#define CATCH_CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( "CATCH_CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, expr ) -#define CATCH_CHECKED_IF( expr ) INTERNAL_CATCH_IF( "CATCH_CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure, expr ) -#define CATCH_CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( "CATCH_CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, expr ) -#define CATCH_CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( "CATCH_CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, expr ) +#define CATCH_CHECK( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) +#define CATCH_CHECK_FALSE( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, __VA_ARGS__ ) +#define CATCH_CHECKED_IF( ... ) INTERNAL_CATCH_IF( "CATCH_CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) +#define CATCH_CHECKED_ELSE( ... ) INTERNAL_CATCH_ELSE( "CATCH_CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) +#define CATCH_CHECK_NOFAIL( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ ) -#define CATCH_CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, "", expr ) +#define CATCH_CHECK_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, "", __VA_ARGS__ ) #define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr ) -#define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) -#define CATCH_CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( "CATCH_CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, expr ) +#define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CATCH_CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) +#define CATCH_CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CATCH_CHECK_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) +#endif // CATCH_CONFIG_DISABLE_MATCHERS +#define CATCH_CHECK_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CATCH_CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) #define CATCH_CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg ) -#if defined(CATCH_CONFIG_FAST_COMPILE) -#define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT_NO_TRY( "CATCH_REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg ) -#else #define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg ) -#endif +#endif // CATCH_CONFIG_DISABLE_MATCHERS #define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( "CATCH_INFO", msg ) #define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( "CATCH_WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg ) -#define CATCH_SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( "CATCH_INFO", msg ) -#define CATCH_CAPTURE( msg ) INTERNAL_CATCH_INFO( "CATCH_CAPTURE", #msg " := " << Catch::toString(msg) ) -#define CATCH_SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( "CATCH_CAPTURE", #msg " := " << Catch::toString(msg) ) +#define CATCH_CAPTURE( msg ) INTERNAL_CATCH_INFO( "CATCH_CAPTURE", #msg " := " << ::Catch::Detail::stringify(msg) ) -#ifdef CATCH_CONFIG_VARIADIC_MACROS - #define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) - #define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) - #define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) - #define CATCH_REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ ) - #define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) - #define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ ) - #define CATCH_FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) - #define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( "CATCH_SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) -#else - #define CATCH_TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description ) - #define CATCH_TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description ) - #define CATCH_METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description ) - #define CATCH_REGISTER_TEST_CASE( function, name, description ) INTERNAL_CATCH_REGISTER_TESTCASE( function, name, description ) - #define CATCH_SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description ) - #define CATCH_FAIL( msg ) INTERNAL_CATCH_MSG( "CATCH_FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, msg ) - #define CATCH_FAIL_CHECK( msg ) INTERNAL_CATCH_MSG( "CATCH_FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, msg ) - #define CATCH_SUCCEED( msg ) INTERNAL_CATCH_MSG( "CATCH_SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, msg ) -#endif -#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" ) +#define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) +#define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) +#define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) +#define CATCH_REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ ) +#define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) +#define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ ) +#define CATCH_FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) +#define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( "CATCH_SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) -#define CATCH_REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) -#define CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) - -#define CATCH_GENERATE( expr) INTERNAL_CATCH_GENERATE( expr ) +#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE() // "BDD-style" convenience wrappers -#ifdef CATCH_CONFIG_VARIADIC_MACROS #define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ ) #define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) -#else -#define CATCH_SCENARIO( name, tags ) CATCH_TEST_CASE( "Scenario: " name, tags ) -#define CATCH_SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags ) -#endif -#define CATCH_GIVEN( desc ) CATCH_SECTION( std::string( "Given: ") + desc, "" ) -#define CATCH_WHEN( desc ) CATCH_SECTION( std::string( " When: ") + desc, "" ) -#define CATCH_AND_WHEN( desc ) CATCH_SECTION( std::string( " And: ") + desc, "" ) -#define CATCH_THEN( desc ) CATCH_SECTION( std::string( " Then: ") + desc, "" ) -#define CATCH_AND_THEN( desc ) CATCH_SECTION( std::string( " And: ") + desc, "" ) +#define CATCH_GIVEN( desc ) CATCH_SECTION( std::string( "Given: ") + desc ) +#define CATCH_WHEN( desc ) CATCH_SECTION( std::string( " When: ") + desc ) +#define CATCH_AND_WHEN( desc ) CATCH_SECTION( std::string( " And: ") + desc ) +#define CATCH_THEN( desc ) CATCH_SECTION( std::string( " Then: ") + desc ) +#define CATCH_AND_THEN( desc ) CATCH_SECTION( std::string( " And: ") + desc ) // If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required #else -#if defined(CATCH_CONFIG_FAST_COMPILE) -#define REQUIRE( expr ) INTERNAL_CATCH_TEST_NO_TRY( "REQUIRE", Catch::ResultDisposition::Normal, expr ) -#define REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST_NO_TRY( "REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, expr ) +#define REQUIRE( ... ) INTERNAL_CATCH_TEST( "REQUIRE", Catch::ResultDisposition::Normal, __VA_ARGS__ ) +#define REQUIRE_FALSE( ... ) INTERNAL_CATCH_TEST( "REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, __VA_ARGS__ ) -#else -#define REQUIRE( expr ) INTERNAL_CATCH_TEST( "REQUIRE", Catch::ResultDisposition::Normal, expr ) -#define REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( "REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, expr ) -#endif - -#define REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( "REQUIRE_THROWS", Catch::ResultDisposition::Normal, "", expr ) +#define REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "REQUIRE_THROWS", Catch::ResultDisposition::Normal, __VA_ARGS__ ) #define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr ) -#define REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( "REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr ) -#define REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( "REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, expr ) +#define REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr ) +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) +#define REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "REQUIRE_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::Normal, matcher, expr ) +#endif // CATCH_CONFIG_DISABLE_MATCHERS +#define REQUIRE_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, __VA_ARGS__ ) -#define CHECK( expr ) INTERNAL_CATCH_TEST( "CHECK", Catch::ResultDisposition::ContinueOnFailure, expr ) -#define CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( "CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, expr ) -#define CHECKED_IF( expr ) INTERNAL_CATCH_IF( "CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure, expr ) -#define CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( "CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, expr ) -#define CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( "CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, expr ) +#define CHECK( ... ) INTERNAL_CATCH_TEST( "CHECK", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) +#define CHECK_FALSE( ... ) INTERNAL_CATCH_TEST( "CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, __VA_ARGS__ ) +#define CHECKED_IF( ... ) INTERNAL_CATCH_IF( "CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) +#define CHECKED_ELSE( ... ) INTERNAL_CATCH_ELSE( "CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) +#define CHECK_NOFAIL( ... ) INTERNAL_CATCH_TEST( "CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ ) -#define CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( "CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, "", expr ) +#define CHECK_THROWS( ... ) INTERNAL_CATCH_THROWS( "CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) #define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr ) -#define CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( "CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) -#define CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( "CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, expr ) +#define CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) +#define CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CHECK_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) +#endif // CATCH_CONFIG_DISABLE_MATCHERS +#define CHECK_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) #define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg ) -#if defined(CATCH_CONFIG_FAST_COMPILE) -#define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT_NO_TRY( "REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg ) -#else #define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg ) -#endif +#endif // CATCH_CONFIG_DISABLE_MATCHERS #define INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg ) #define WARN( msg ) INTERNAL_CATCH_MSG( "WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg ) -#define SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg ) -#define CAPTURE( msg ) INTERNAL_CATCH_INFO( "CAPTURE", #msg " := " << Catch::toString(msg) ) -#define SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( "CAPTURE", #msg " := " << Catch::toString(msg) ) +#define CAPTURE( msg ) INTERNAL_CATCH_INFO( "CAPTURE", #msg " := " << ::Catch::Detail::stringify(msg) ) -#ifdef CATCH_CONFIG_VARIADIC_MACROS #define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) #define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) #define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) @@ -11563,46 +11849,152 @@ int main (int argc, char * const argv[]) { #define FAIL( ... ) INTERNAL_CATCH_MSG( "FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ ) #define FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) #define SUCCEED( ... ) INTERNAL_CATCH_MSG( "SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) -#else -#define TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description ) - #define TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description ) - #define METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description ) - #define REGISTER_TEST_CASE( method, name, description ) INTERNAL_CATCH_REGISTER_TESTCASE( method, name, description ) - #define SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description ) - #define FAIL( msg ) INTERNAL_CATCH_MSG( "FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, msg ) - #define FAIL_CHECK( msg ) INTERNAL_CATCH_MSG( "FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, msg ) - #define SUCCEED( msg ) INTERNAL_CATCH_MSG( "SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, msg ) -#endif -#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" ) - -#define REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) -#define REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) - -#define GENERATE( expr) INTERNAL_CATCH_GENERATE( expr ) +#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE() #endif #define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) // "BDD-style" convenience wrappers -#ifdef CATCH_CONFIG_VARIADIC_MACROS #define SCENARIO( ... ) TEST_CASE( "Scenario: " __VA_ARGS__ ) #define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) -#else -#define SCENARIO( name, tags ) TEST_CASE( "Scenario: " name, tags ) -#define SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags ) -#endif -#define GIVEN( desc ) SECTION( std::string(" Given: ") + desc, "" ) -#define WHEN( desc ) SECTION( std::string(" When: ") + desc, "" ) -#define AND_WHEN( desc ) SECTION( std::string("And when: ") + desc, "" ) -#define THEN( desc ) SECTION( std::string(" Then: ") + desc, "" ) -#define AND_THEN( desc ) SECTION( std::string(" And: ") + desc, "" ) + +#define GIVEN( desc ) SECTION( std::string(" Given: ") + desc ) +#define WHEN( desc ) SECTION( std::string(" When: ") + desc ) +#define AND_WHEN( desc ) SECTION( std::string("And when: ") + desc ) +#define THEN( desc ) SECTION( std::string(" Then: ") + desc ) +#define AND_THEN( desc ) SECTION( std::string(" And: ") + desc ) using Catch::Detail::Approx; -// #included from: internal/catch_reenable_warnings.h +#else +////// +// If this config identifier is defined then all CATCH macros are prefixed with CATCH_ +#ifdef CATCH_CONFIG_PREFIX_ALL + +#define CATCH_REQUIRE( ... ) (void)(0) +#define CATCH_REQUIRE_FALSE( ... ) (void)(0) + +#define CATCH_REQUIRE_THROWS( ... ) (void)(0) +#define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) (void)(0) +#define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) (void)(0) +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) +#define CATCH_REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0) +#endif// CATCH_CONFIG_DISABLE_MATCHERS +#define CATCH_REQUIRE_NOTHROW( ... ) (void)(0) + +#define CATCH_CHECK( ... ) (void)(0) +#define CATCH_CHECK_FALSE( ... ) (void)(0) +#define CATCH_CHECKED_IF( ... ) if (__VA_ARGS__) +#define CATCH_CHECKED_ELSE( ... ) if (!(__VA_ARGS__)) +#define CATCH_CHECK_NOFAIL( ... ) (void)(0) + +#define CATCH_CHECK_THROWS( ... ) (void)(0) +#define CATCH_CHECK_THROWS_AS( expr, exceptionType ) (void)(0) +#define CATCH_CHECK_THROWS_WITH( expr, matcher ) (void)(0) +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) +#define CATCH_CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0) +#endif // CATCH_CONFIG_DISABLE_MATCHERS +#define CATCH_CHECK_NOTHROW( ... ) (void)(0) + +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) +#define CATCH_CHECK_THAT( arg, matcher ) (void)(0) + +#define CATCH_REQUIRE_THAT( arg, matcher ) (void)(0) +#endif // CATCH_CONFIG_DISABLE_MATCHERS + +#define CATCH_INFO( msg ) (void)(0) +#define CATCH_WARN( msg ) (void)(0) +#define CATCH_CAPTURE( msg ) (void)(0) + +#define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) +#define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) +#define CATCH_METHOD_AS_TEST_CASE( method, ... ) +#define CATCH_REGISTER_TEST_CASE( Function, ... ) (void)(0) +#define CATCH_SECTION( ... ) +#define CATCH_FAIL( ... ) (void)(0) +#define CATCH_FAIL_CHECK( ... ) (void)(0) +#define CATCH_SUCCEED( ... ) (void)(0) + +#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) + +// "BDD-style" convenience wrappers +#define CATCH_SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) +#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), className ) +#define CATCH_GIVEN( desc ) +#define CATCH_WHEN( desc ) +#define CATCH_AND_WHEN( desc ) +#define CATCH_THEN( desc ) +#define CATCH_AND_THEN( desc ) + +// If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required +#else + +#define REQUIRE( ... ) (void)(0) +#define REQUIRE_FALSE( ... ) (void)(0) + +#define REQUIRE_THROWS( ... ) (void)(0) +#define REQUIRE_THROWS_AS( expr, exceptionType ) (void)(0) +#define REQUIRE_THROWS_WITH( expr, matcher ) (void)(0) +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) +#define REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0) +#endif // CATCH_CONFIG_DISABLE_MATCHERS +#define REQUIRE_NOTHROW( ... ) (void)(0) + +#define CHECK( ... ) (void)(0) +#define CHECK_FALSE( ... ) (void)(0) +#define CHECKED_IF( ... ) if (__VA_ARGS__) +#define CHECKED_ELSE( ... ) if (!(__VA_ARGS__)) +#define CHECK_NOFAIL( ... ) (void)(0) + +#define CHECK_THROWS( ... ) (void)(0) +#define CHECK_THROWS_AS( expr, exceptionType ) (void)(0) +#define CHECK_THROWS_WITH( expr, matcher ) (void)(0) +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) +#define CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0) +#endif // CATCH_CONFIG_DISABLE_MATCHERS +#define CHECK_NOTHROW( ... ) (void)(0) + +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) +#define CHECK_THAT( arg, matcher ) (void)(0) + +#define REQUIRE_THAT( arg, matcher ) (void)(0) +#endif // CATCH_CONFIG_DISABLE_MATCHERS + +#define INFO( msg ) (void)(0) +#define WARN( msg ) (void)(0) +#define CAPTURE( msg ) (void)(0) + +#define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) +#define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) +#define METHOD_AS_TEST_CASE( method, ... ) +#define REGISTER_TEST_CASE( Function, ... ) (void)(0) +#define SECTION( ... ) +#define FAIL( ... ) (void)(0) +#define FAIL_CHECK( ... ) (void)(0) +#define SUCCEED( ... ) (void)(0) +#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) + +#endif + +#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION_NO_REG( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature ) + +// "BDD-style" convenience wrappers +#define SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) ) +#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), className ) + +#define GIVEN( desc ) +#define WHEN( desc ) +#define AND_WHEN( desc ) +#define THEN( desc ) +#define AND_THEN( desc ) + +using Catch::Detail::Approx; + +#endif + +// start catch_reenable_warnings.h -#define TWOBLUECUBES_CATCH_REENABLE_WARNINGS_H_INCLUDED #ifdef __clang__ # ifdef __ICC // icpc defines the __clang__ macro @@ -11614,5 +12006,7 @@ using Catch::Detail::Approx; # pragma GCC diagnostic pop #endif +// end catch_reenable_warnings.h +// end catch.hpp #endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED From fb8482db767bf46c65c56a984238ed8564e829de Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Wed, 13 Dec 2017 23:44:53 +0100 Subject: [PATCH 05/59] :ok_hand: fixed some issues from the last commit #875 --- README.md | 2 +- src/json.hpp | 15 ++++++--------- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 54f73a8d..7b50c841 100644 --- a/README.md +++ b/README.md @@ -813,7 +813,7 @@ The class contains the UTF-8 Decoder from Bjoern Hoehrmann which is licensed und If you have questions regarding the library, I would like to invite you to [open an issue at Github](https://github.com/nlohmann/json/issues/new). Please describe your request, problem, or question as detailed as possible, and also mention the version of the library you are using as well as the version of your compiler and operating system. Opening an issue at Github allows other users and contributors to this library to collaborate. For instance, I have little experience with MSVC, and most issues in this regard have been solved by a growing community. If you have a look at the [closed issues](https://github.com/nlohmann/json/issues?q=is%3Aissue+is%3Aclosed), you will see that we react quite timely in most cases. -Only if your request would contain confidential information, please [send me an email](mailto:mail@nlohmann.me). For encrypted messages, please usse [this key](https://keybase.io/nlohmann/pgp_keys.asc). +Only if your request would contain confidential information, please [send me an email](mailto:mail@nlohmann.me). For encrypted messages, please use [this key](https://keybase.io/nlohmann/pgp_keys.asc). ## Thanks diff --git a/src/json.hpp b/src/json.hpp index 1f06b6dd..0eed04f7 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -997,10 +997,9 @@ void to_json(BasicJsonType& j, const std::vector& e) } template::value or - std::is_same::value, - int> = 0> + enable_if_t::value or + std::is_same::value, + int> = 0> void to_json(BasicJsonType& j, const CompatibleArrayType& arr) { external_constructor::construct(j, arr); @@ -1611,11 +1610,9 @@ class input_adapter /// input adapter for contiguous container template::value and - std::is_base_of()))>::iterator_category>::value, - int>::type = 0> + std::enable_if::value and + std::is_base_of()))>::iterator_category>::value, + int>::type = 0> input_adapter(const ContiguousContainer& c) : input_adapter(std::begin(c), std::end(c)) {} From 9a70c60fa5edc8d4a28cc1ee57e6679cade3bef6 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Thu, 14 Dec 2017 07:49:16 +0100 Subject: [PATCH 06/59] Revert ":arrow_up: updated to Catch 2.0.1" This reverts commit 920f64c01c126e0664b3b1905c3f60872bd518cd. --- test/src/unit-algorithms.cpp | 2 +- test/src/unit-allocator.cpp | 22 +- test/src/unit-cbor.cpp | 47 +- test/src/unit-class_const_iterator.cpp | 8 +- test/src/unit-class_iterator.cpp | 8 +- test/src/unit-class_parser.cpp | 240 +- test/src/unit-constructor1.cpp | 63 +- test/src/unit-conversions.cpp | 95 +- test/src/unit-deserialization.cpp | 62 +- test/src/unit-element_access1.cpp | 166 +- test/src/unit-element_access2.cpp | 168 +- test/src/unit-iterators1.cpp | 80 +- test/src/unit-iterators2.cpp | 232 +- test/src/unit-json_patch.cpp | 78 +- test/src/unit-json_pointer.cpp | 58 +- test/src/unit-modifiers.cpp | 70 +- test/src/unit-msgpack.cpp | 42 +- test/src/unit-readme.cpp | 1 - test/src/unit-reference_access.cpp | 84 +- test/src/unit-regression.cpp | 84 +- test/src/unit-testsuites.cpp | 8 +- test/src/unit-unicode.cpp | 26 +- test/thirdparty/catch/catch.hpp | 17832 +++++++++++------------ 23 files changed, 9539 insertions(+), 9937 deletions(-) diff --git a/test/src/unit-algorithms.cpp b/test/src/unit-algorithms.cpp index 6136fefa..bc108dcd 100644 --- a/test/src/unit-algorithms.cpp +++ b/test/src/unit-algorithms.cpp @@ -240,7 +240,7 @@ TEST_CASE("algorithms") SECTION("sorting an object") { json j({{"one", 1}, {"two", 2}}); - CHECK_THROWS_AS(std::sort(j.begin(), j.end()), json::invalid_iterator); + CHECK_THROWS_AS(std::sort(j.begin(), j.end()), json::invalid_iterator&); CHECK_THROWS_WITH(std::sort(j.begin(), j.end()), "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } diff --git a/test/src/unit-allocator.cpp b/test/src/unit-allocator.cpp index 903d5950..d2423a48 100644 --- a/test/src/unit-allocator.cpp +++ b/test/src/unit-allocator.cpp @@ -59,7 +59,7 @@ TEST_CASE("bad_alloc") bad_allocator>; // creating an object should throw - CHECK_THROWS_AS(bad_json(bad_json::value_t::object), std::bad_alloc); + CHECK_THROWS_AS(bad_json(bad_json::value_t::object), std::bad_alloc&); } } @@ -143,7 +143,7 @@ TEST_CASE("controlled bad_alloc") auto t = my_json::value_t::object; CHECK_NOTHROW(my_allocator_clean_up(my_json::json_value(t).object)); next_construct_fails = true; - CHECK_THROWS_AS(my_json::json_value(t), std::bad_alloc); + CHECK_THROWS_AS(my_json::json_value(t), std::bad_alloc&); next_construct_fails = false; } SECTION("array") @@ -152,7 +152,7 @@ TEST_CASE("controlled bad_alloc") auto t = my_json::value_t::array; CHECK_NOTHROW(my_allocator_clean_up(my_json::json_value(t).array)); next_construct_fails = true; - CHECK_THROWS_AS(my_json::json_value(t), std::bad_alloc); + CHECK_THROWS_AS(my_json::json_value(t), std::bad_alloc&); next_construct_fails = false; } SECTION("string") @@ -161,7 +161,7 @@ TEST_CASE("controlled bad_alloc") auto t = my_json::value_t::string; CHECK_NOTHROW(my_allocator_clean_up(my_json::json_value(t).string)); next_construct_fails = true; - CHECK_THROWS_AS(my_json::json_value(t), std::bad_alloc); + CHECK_THROWS_AS(my_json::json_value(t), std::bad_alloc&); next_construct_fails = false; } } @@ -172,7 +172,7 @@ TEST_CASE("controlled bad_alloc") my_json::string_t v("foo"); CHECK_NOTHROW(my_allocator_clean_up(my_json::json_value(v).string)); next_construct_fails = true; - CHECK_THROWS_AS(my_json::json_value(v), std::bad_alloc); + CHECK_THROWS_AS(my_json::json_value(v), std::bad_alloc&); next_construct_fails = false; } @@ -183,7 +183,7 @@ TEST_CASE("controlled bad_alloc") my_json::object_t v {{"foo", "bar"}}; CHECK_NOTHROW(my_json::json_value j(v)); next_construct_fails = true; - CHECK_THROWS_AS(my_json::json_value j(v), std::bad_alloc); + CHECK_THROWS_AS(my_json::json_value j(v), std::bad_alloc&); next_construct_fails = false; } */ @@ -194,7 +194,7 @@ TEST_CASE("controlled bad_alloc") my_json::array_t v = {"foo", "bar", "baz"}; CHECK_NOTHROW(my_json::json_value j(v)); next_construct_fails = true; - CHECK_THROWS_AS(my_json::json_value j(v), std::bad_alloc); + CHECK_THROWS_AS(my_json::json_value j(v), std::bad_alloc&); next_construct_fails = false; } */ @@ -208,7 +208,7 @@ TEST_CASE("controlled bad_alloc") std::map v {{"foo", "bar"}}; CHECK_NOTHROW(my_json(v)); next_construct_fails = true; - CHECK_THROWS_AS(my_json(v), std::bad_alloc); + CHECK_THROWS_AS(my_json(v), std::bad_alloc&); next_construct_fails = false; } @@ -218,7 +218,7 @@ TEST_CASE("controlled bad_alloc") std::vector v {"foo", "bar", "baz"}; CHECK_NOTHROW(my_json(v)); next_construct_fails = true; - CHECK_THROWS_AS(my_json(v), std::bad_alloc); + CHECK_THROWS_AS(my_json(v), std::bad_alloc&); next_construct_fails = false; } @@ -227,7 +227,7 @@ TEST_CASE("controlled bad_alloc") next_construct_fails = false; CHECK_NOTHROW(my_json("foo")); next_construct_fails = true; - CHECK_THROWS_AS(my_json("foo"), std::bad_alloc); + CHECK_THROWS_AS(my_json("foo"), std::bad_alloc&); next_construct_fails = false; } @@ -237,7 +237,7 @@ TEST_CASE("controlled bad_alloc") std::string s("foo"); CHECK_NOTHROW(my_json(s)); next_construct_fails = true; - CHECK_THROWS_AS(my_json(s), std::bad_alloc); + CHECK_THROWS_AS(my_json(s), std::bad_alloc&); next_construct_fails = false; } } diff --git a/test/src/unit-cbor.cpp b/test/src/unit-cbor.cpp index 330b7ca1..8d28f686 100644 --- a/test/src/unit-cbor.cpp +++ b/test/src/unit-cbor.cpp @@ -31,7 +31,6 @@ SOFTWARE. #include "json.hpp" using nlohmann::json; -#include #include TEST_CASE("CBOR") @@ -740,13 +739,13 @@ TEST_CASE("CBOR") { SECTION("no byte follows") { - CHECK_THROWS_AS(json::from_cbor(std::vector({0xf9})), json::parse_error); + CHECK_THROWS_AS(json::from_cbor(std::vector({0xf9})), json::parse_error&); CHECK_THROWS_WITH(json::from_cbor(std::vector({0xf9})), "[json.exception.parse_error.110] parse error at 2: unexpected end of input"); } SECTION("only one byte follows") { - CHECK_THROWS_AS(json::from_cbor(std::vector({0xf9, 0x7c})), json::parse_error); + CHECK_THROWS_AS(json::from_cbor(std::vector({0xf9, 0x7c})), json::parse_error&); CHECK_THROWS_WITH(json::from_cbor(std::vector({0xf9, 0x7c})), "[json.exception.parse_error.110] parse error at 3: unexpected end of input"); } @@ -1227,28 +1226,28 @@ TEST_CASE("CBOR") { SECTION("empty byte vector") { - CHECK_THROWS_AS(json::from_cbor(std::vector()), json::parse_error); + CHECK_THROWS_AS(json::from_cbor(std::vector()), json::parse_error&); CHECK_THROWS_WITH(json::from_cbor(std::vector()), "[json.exception.parse_error.110] parse error at 1: unexpected end of input"); } SECTION("too short byte vector") { - CHECK_THROWS_AS(json::from_cbor(std::vector({0x18})), json::parse_error); - CHECK_THROWS_AS(json::from_cbor(std::vector({0x19})), json::parse_error); - CHECK_THROWS_AS(json::from_cbor(std::vector({0x19, 0x00})), json::parse_error); - CHECK_THROWS_AS(json::from_cbor(std::vector({0x1a})), json::parse_error); - CHECK_THROWS_AS(json::from_cbor(std::vector({0x1a, 0x00})), json::parse_error); - CHECK_THROWS_AS(json::from_cbor(std::vector({0x1a, 0x00, 0x00})), json::parse_error); - CHECK_THROWS_AS(json::from_cbor(std::vector({0x1a, 0x00, 0x00, 0x00})), json::parse_error); - CHECK_THROWS_AS(json::from_cbor(std::vector({0x1b})), json::parse_error); - CHECK_THROWS_AS(json::from_cbor(std::vector({0x1b, 0x00})), json::parse_error); - CHECK_THROWS_AS(json::from_cbor(std::vector({0x1b, 0x00, 0x00})), json::parse_error); - CHECK_THROWS_AS(json::from_cbor(std::vector({0x1b, 0x00, 0x00, 0x00})), json::parse_error); - CHECK_THROWS_AS(json::from_cbor(std::vector({0x1b, 0x00, 0x00, 0x00, 0x00})), json::parse_error); - CHECK_THROWS_AS(json::from_cbor(std::vector({0x1b, 0x00, 0x00, 0x00, 0x00, 0x00})), json::parse_error); - CHECK_THROWS_AS(json::from_cbor(std::vector({0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})), json::parse_error); - CHECK_THROWS_AS(json::from_cbor(std::vector({0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})), json::parse_error); + CHECK_THROWS_AS(json::from_cbor(std::vector({0x18})), json::parse_error&); + CHECK_THROWS_AS(json::from_cbor(std::vector({0x19})), json::parse_error&); + CHECK_THROWS_AS(json::from_cbor(std::vector({0x19, 0x00})), json::parse_error&); + CHECK_THROWS_AS(json::from_cbor(std::vector({0x1a})), json::parse_error&); + CHECK_THROWS_AS(json::from_cbor(std::vector({0x1a, 0x00})), json::parse_error&); + CHECK_THROWS_AS(json::from_cbor(std::vector({0x1a, 0x00, 0x00})), json::parse_error&); + CHECK_THROWS_AS(json::from_cbor(std::vector({0x1a, 0x00, 0x00, 0x00})), json::parse_error&); + CHECK_THROWS_AS(json::from_cbor(std::vector({0x1b})), json::parse_error&); + CHECK_THROWS_AS(json::from_cbor(std::vector({0x1b, 0x00})), json::parse_error&); + CHECK_THROWS_AS(json::from_cbor(std::vector({0x1b, 0x00, 0x00})), json::parse_error&); + CHECK_THROWS_AS(json::from_cbor(std::vector({0x1b, 0x00, 0x00, 0x00})), json::parse_error&); + CHECK_THROWS_AS(json::from_cbor(std::vector({0x1b, 0x00, 0x00, 0x00, 0x00})), json::parse_error&); + CHECK_THROWS_AS(json::from_cbor(std::vector({0x1b, 0x00, 0x00, 0x00, 0x00, 0x00})), json::parse_error&); + CHECK_THROWS_AS(json::from_cbor(std::vector({0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})), json::parse_error&); + CHECK_THROWS_AS(json::from_cbor(std::vector({0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})), json::parse_error&); CHECK_THROWS_WITH(json::from_cbor(std::vector({0x18})), "[json.exception.parse_error.110] parse error at 2: unexpected end of input"); @@ -1286,10 +1285,10 @@ TEST_CASE("CBOR") { SECTION("concrete examples") { - CHECK_THROWS_AS(json::from_cbor(std::vector({0x1c})), json::parse_error); + CHECK_THROWS_AS(json::from_cbor(std::vector({0x1c})), json::parse_error&); CHECK_THROWS_WITH(json::from_cbor(std::vector({0x1c})), "[json.exception.parse_error.112] parse error at 1: error reading CBOR; last byte: 0x1C"); - CHECK_THROWS_AS(json::from_cbor(std::vector({0xf8})), json::parse_error); + CHECK_THROWS_AS(json::from_cbor(std::vector({0xf8})), json::parse_error&); CHECK_THROWS_WITH(json::from_cbor(std::vector({0xf8})), "[json.exception.parse_error.112] parse error at 1: error reading CBOR; last byte: 0xF8"); } @@ -1340,14 +1339,14 @@ TEST_CASE("CBOR") 0xf8 }) { - CHECK_THROWS_AS(json::from_cbor(std::vector({static_cast(byte)})), json::parse_error); + CHECK_THROWS_AS(json::from_cbor(std::vector({static_cast(byte)})), json::parse_error&); } } } SECTION("invalid string in map") { - CHECK_THROWS_AS(json::from_cbor(std::vector({0xa1, 0xff, 0x01})), json::parse_error); + CHECK_THROWS_AS(json::from_cbor(std::vector({0xa1, 0xff, 0x01})), json::parse_error&); CHECK_THROWS_WITH(json::from_cbor(std::vector({0xa1, 0xff, 0x01})), "[json.exception.parse_error.113] parse error at 2: expected a CBOR string; last byte: 0xFF"); } @@ -1363,7 +1362,7 @@ TEST_CASE("CBOR") SECTION("strict mode") { - CHECK_THROWS_AS(json::from_cbor(vec), json::parse_error); + CHECK_THROWS_AS(json::from_cbor(vec), json::parse_error&); CHECK_THROWS_WITH(json::from_cbor(vec), "[json.exception.parse_error.110] parse error at 2: expected end of input"); } diff --git a/test/src/unit-class_const_iterator.cpp b/test/src/unit-class_const_iterator.cpp index 5356fb35..573e773b 100644 --- a/test/src/unit-class_const_iterator.cpp +++ b/test/src/unit-class_const_iterator.cpp @@ -147,7 +147,7 @@ TEST_CASE("const_iterator class") { json j(json::value_t::null); json::const_iterator it = j.cbegin(); - CHECK_THROWS_AS(*it, json::invalid_iterator); + CHECK_THROWS_AS(*it, json::invalid_iterator&); CHECK_THROWS_WITH(*it, "[json.exception.invalid_iterator.214] cannot get value"); } @@ -157,7 +157,7 @@ TEST_CASE("const_iterator class") json::const_iterator it = j.cbegin(); CHECK(*it == json(17)); it = j.cend(); - CHECK_THROWS_AS(*it, json::invalid_iterator); + CHECK_THROWS_AS(*it, json::invalid_iterator&); CHECK_THROWS_WITH(*it, "[json.exception.invalid_iterator.214] cannot get value"); } @@ -182,7 +182,7 @@ TEST_CASE("const_iterator class") { json j(json::value_t::null); json::const_iterator it = j.cbegin(); - CHECK_THROWS_AS(std::string(it->type_name()), json::invalid_iterator); + CHECK_THROWS_AS(std::string(it->type_name()), json::invalid_iterator&); CHECK_THROWS_WITH(std::string(it->type_name()), "[json.exception.invalid_iterator.214] cannot get value"); } @@ -192,7 +192,7 @@ TEST_CASE("const_iterator class") json::const_iterator it = j.cbegin(); CHECK(std::string(it->type_name()) == "number"); it = j.cend(); - CHECK_THROWS_AS(std::string(it->type_name()), json::invalid_iterator); + CHECK_THROWS_AS(std::string(it->type_name()), json::invalid_iterator&); CHECK_THROWS_WITH(std::string(it->type_name()), "[json.exception.invalid_iterator.214] cannot get value"); } diff --git a/test/src/unit-class_iterator.cpp b/test/src/unit-class_iterator.cpp index cb7f16a5..1ef4a538 100644 --- a/test/src/unit-class_iterator.cpp +++ b/test/src/unit-class_iterator.cpp @@ -131,7 +131,7 @@ TEST_CASE("iterator class") { json j(json::value_t::null); json::iterator it = j.begin(); - CHECK_THROWS_AS(*it, json::invalid_iterator); + CHECK_THROWS_AS(*it, json::invalid_iterator&); CHECK_THROWS_WITH(*it, "[json.exception.invalid_iterator.214] cannot get value"); } @@ -141,7 +141,7 @@ TEST_CASE("iterator class") json::iterator it = j.begin(); CHECK(*it == json(17)); it = j.end(); - CHECK_THROWS_AS(*it, json::invalid_iterator); + CHECK_THROWS_AS(*it, json::invalid_iterator&); CHECK_THROWS_WITH(*it, "[json.exception.invalid_iterator.214] cannot get value"); } @@ -166,7 +166,7 @@ TEST_CASE("iterator class") { json j(json::value_t::null); json::iterator it = j.begin(); - CHECK_THROWS_AS(std::string(it->type_name()), json::invalid_iterator); + CHECK_THROWS_AS(std::string(it->type_name()), json::invalid_iterator&); CHECK_THROWS_WITH(std::string(it->type_name()), "[json.exception.invalid_iterator.214] cannot get value"); } @@ -176,7 +176,7 @@ TEST_CASE("iterator class") json::iterator it = j.begin(); CHECK(std::string(it->type_name()) == "number"); it = j.end(); - CHECK_THROWS_AS(std::string(it->type_name()), json::invalid_iterator); + CHECK_THROWS_AS(std::string(it->type_name()), json::invalid_iterator&); CHECK_THROWS_WITH(std::string(it->type_name()), "[json.exception.invalid_iterator.214] cannot get value"); } diff --git a/test/src/unit-class_parser.cpp b/test/src/unit-class_parser.cpp index 7c4e635a..9afa7d26 100644 --- a/test/src/unit-class_parser.cpp +++ b/test/src/unit-class_parser.cpp @@ -123,56 +123,56 @@ TEST_CASE("parser class") SECTION("errors") { // error: tab in string - CHECK_THROWS_AS(parser_helper("\"\t\""), json::parse_error); + CHECK_THROWS_AS(parser_helper("\"\t\""), json::parse_error&); CHECK_THROWS_WITH(parser_helper("\"\t\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); // error: newline in string - CHECK_THROWS_AS(parser_helper("\"\n\""), json::parse_error); - CHECK_THROWS_AS(parser_helper("\"\r\""), json::parse_error); + CHECK_THROWS_AS(parser_helper("\"\n\""), json::parse_error&); + CHECK_THROWS_AS(parser_helper("\"\r\""), json::parse_error&); CHECK_THROWS_WITH(parser_helper("\"\n\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); CHECK_THROWS_WITH(parser_helper("\"\r\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); // error: backspace in string - CHECK_THROWS_AS(parser_helper("\"\b\""), json::parse_error); + CHECK_THROWS_AS(parser_helper("\"\b\""), json::parse_error&); CHECK_THROWS_WITH(parser_helper("\"\b\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); // improve code coverage - CHECK_THROWS_AS(parser_helper("\uFF01"), json::parse_error); - CHECK_THROWS_AS(parser_helper("[-4:1,]"), json::parse_error); + CHECK_THROWS_AS(parser_helper("\uFF01"), json::parse_error&); + CHECK_THROWS_AS(parser_helper("[-4:1,]"), json::parse_error&); // unescaped control characters - CHECK_THROWS_AS(parser_helper("\"\x00\""), json::parse_error); - CHECK_THROWS_AS(parser_helper("\"\x01\""), json::parse_error); - CHECK_THROWS_AS(parser_helper("\"\x02\""), json::parse_error); - CHECK_THROWS_AS(parser_helper("\"\x03\""), json::parse_error); - CHECK_THROWS_AS(parser_helper("\"\x04\""), json::parse_error); - CHECK_THROWS_AS(parser_helper("\"\x05\""), json::parse_error); - CHECK_THROWS_AS(parser_helper("\"\x06\""), json::parse_error); - CHECK_THROWS_AS(parser_helper("\"\x07\""), json::parse_error); - CHECK_THROWS_AS(parser_helper("\"\x08\""), json::parse_error); - CHECK_THROWS_AS(parser_helper("\"\x09\""), json::parse_error); - CHECK_THROWS_AS(parser_helper("\"\x0a\""), json::parse_error); - CHECK_THROWS_AS(parser_helper("\"\x0b\""), json::parse_error); - CHECK_THROWS_AS(parser_helper("\"\x0c\""), json::parse_error); - CHECK_THROWS_AS(parser_helper("\"\x0d\""), json::parse_error); - CHECK_THROWS_AS(parser_helper("\"\x0e\""), json::parse_error); - CHECK_THROWS_AS(parser_helper("\"\x0f\""), json::parse_error); - CHECK_THROWS_AS(parser_helper("\"\x10\""), json::parse_error); - CHECK_THROWS_AS(parser_helper("\"\x11\""), json::parse_error); - CHECK_THROWS_AS(parser_helper("\"\x12\""), json::parse_error); - CHECK_THROWS_AS(parser_helper("\"\x13\""), json::parse_error); - CHECK_THROWS_AS(parser_helper("\"\x14\""), json::parse_error); - CHECK_THROWS_AS(parser_helper("\"\x15\""), json::parse_error); - CHECK_THROWS_AS(parser_helper("\"\x16\""), json::parse_error); - CHECK_THROWS_AS(parser_helper("\"\x17\""), json::parse_error); - CHECK_THROWS_AS(parser_helper("\"\x18\""), json::parse_error); - CHECK_THROWS_AS(parser_helper("\"\x19\""), json::parse_error); - CHECK_THROWS_AS(parser_helper("\"\x1a\""), json::parse_error); - CHECK_THROWS_AS(parser_helper("\"\x1b\""), json::parse_error); - CHECK_THROWS_AS(parser_helper("\"\x1c\""), json::parse_error); - CHECK_THROWS_AS(parser_helper("\"\x1d\""), json::parse_error); - CHECK_THROWS_AS(parser_helper("\"\x1e\""), json::parse_error); - CHECK_THROWS_AS(parser_helper("\"\x1f\""), json::parse_error); + CHECK_THROWS_AS(parser_helper("\"\x00\""), json::parse_error&); + CHECK_THROWS_AS(parser_helper("\"\x01\""), json::parse_error&); + CHECK_THROWS_AS(parser_helper("\"\x02\""), json::parse_error&); + CHECK_THROWS_AS(parser_helper("\"\x03\""), json::parse_error&); + CHECK_THROWS_AS(parser_helper("\"\x04\""), json::parse_error&); + CHECK_THROWS_AS(parser_helper("\"\x05\""), json::parse_error&); + CHECK_THROWS_AS(parser_helper("\"\x06\""), json::parse_error&); + CHECK_THROWS_AS(parser_helper("\"\x07\""), json::parse_error&); + CHECK_THROWS_AS(parser_helper("\"\x08\""), json::parse_error&); + CHECK_THROWS_AS(parser_helper("\"\x09\""), json::parse_error&); + CHECK_THROWS_AS(parser_helper("\"\x0a\""), json::parse_error&); + CHECK_THROWS_AS(parser_helper("\"\x0b\""), json::parse_error&); + CHECK_THROWS_AS(parser_helper("\"\x0c\""), json::parse_error&); + CHECK_THROWS_AS(parser_helper("\"\x0d\""), json::parse_error&); + CHECK_THROWS_AS(parser_helper("\"\x0e\""), json::parse_error&); + CHECK_THROWS_AS(parser_helper("\"\x0f\""), json::parse_error&); + CHECK_THROWS_AS(parser_helper("\"\x10\""), json::parse_error&); + CHECK_THROWS_AS(parser_helper("\"\x11\""), json::parse_error&); + CHECK_THROWS_AS(parser_helper("\"\x12\""), json::parse_error&); + CHECK_THROWS_AS(parser_helper("\"\x13\""), json::parse_error&); + CHECK_THROWS_AS(parser_helper("\"\x14\""), json::parse_error&); + CHECK_THROWS_AS(parser_helper("\"\x15\""), json::parse_error&); + CHECK_THROWS_AS(parser_helper("\"\x16\""), json::parse_error&); + CHECK_THROWS_AS(parser_helper("\"\x17\""), json::parse_error&); + CHECK_THROWS_AS(parser_helper("\"\x18\""), json::parse_error&); + CHECK_THROWS_AS(parser_helper("\"\x19\""), json::parse_error&); + CHECK_THROWS_AS(parser_helper("\"\x1a\""), json::parse_error&); + CHECK_THROWS_AS(parser_helper("\"\x1b\""), json::parse_error&); + CHECK_THROWS_AS(parser_helper("\"\x1c\""), json::parse_error&); + CHECK_THROWS_AS(parser_helper("\"\x1d\""), json::parse_error&); + CHECK_THROWS_AS(parser_helper("\"\x1e\""), json::parse_error&); + CHECK_THROWS_AS(parser_helper("\"\x1f\""), json::parse_error&); CHECK_THROWS_WITH(parser_helper("\"\x00\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: missing closing quote; last read: '\"'"); CHECK_THROWS_WITH(parser_helper("\"\x01\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); CHECK_THROWS_WITH(parser_helper("\"\x02\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); @@ -214,7 +214,7 @@ TEST_CASE("parser class") // uses an iterator range. std::string s = "\"1\""; s[1] = '\0'; - CHECK_THROWS_AS(json::parse(s.begin(), s.end()), json::parse_error); + CHECK_THROWS_AS(json::parse(s.begin(), s.end()), json::parse_error&); CHECK_THROWS_WITH(json::parse(s.begin(), s.end()), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); } } @@ -386,33 +386,33 @@ TEST_CASE("parser class") SECTION("overflow") { // overflows during parsing yield an exception - CHECK_THROWS_AS(parser_helper("1.18973e+4932") == json(), json::out_of_range); + CHECK_THROWS_AS(parser_helper("1.18973e+4932") == json(), json::out_of_range&); CHECK_THROWS_WITH(parser_helper("1.18973e+4932") == json(), "[json.exception.out_of_range.406] number overflow parsing '1.18973e+4932'"); } SECTION("invalid numbers") { - CHECK_THROWS_AS(parser_helper("01"), json::parse_error); - CHECK_THROWS_AS(parser_helper("--1"), json::parse_error); - CHECK_THROWS_AS(parser_helper("1."), json::parse_error); - CHECK_THROWS_AS(parser_helper("1E"), json::parse_error); - CHECK_THROWS_AS(parser_helper("1E-"), json::parse_error); - CHECK_THROWS_AS(parser_helper("1.E1"), json::parse_error); - CHECK_THROWS_AS(parser_helper("-1E"), json::parse_error); - CHECK_THROWS_AS(parser_helper("-0E#"), json::parse_error); - CHECK_THROWS_AS(parser_helper("-0E-#"), json::parse_error); - CHECK_THROWS_AS(parser_helper("-0#"), json::parse_error); - CHECK_THROWS_AS(parser_helper("-0.0:"), json::parse_error); - CHECK_THROWS_AS(parser_helper("-0.0Z"), json::parse_error); - CHECK_THROWS_AS(parser_helper("-0E123:"), json::parse_error); - CHECK_THROWS_AS(parser_helper("-0e0-:"), json::parse_error); - CHECK_THROWS_AS(parser_helper("-0e-:"), json::parse_error); - CHECK_THROWS_AS(parser_helper("-0f"), json::parse_error); + CHECK_THROWS_AS(parser_helper("01"), json::parse_error&); + CHECK_THROWS_AS(parser_helper("--1"), json::parse_error&); + CHECK_THROWS_AS(parser_helper("1."), json::parse_error&); + CHECK_THROWS_AS(parser_helper("1E"), json::parse_error&); + CHECK_THROWS_AS(parser_helper("1E-"), json::parse_error&); + CHECK_THROWS_AS(parser_helper("1.E1"), json::parse_error&); + CHECK_THROWS_AS(parser_helper("-1E"), json::parse_error&); + CHECK_THROWS_AS(parser_helper("-0E#"), json::parse_error&); + CHECK_THROWS_AS(parser_helper("-0E-#"), json::parse_error&); + CHECK_THROWS_AS(parser_helper("-0#"), json::parse_error&); + CHECK_THROWS_AS(parser_helper("-0.0:"), json::parse_error&); + CHECK_THROWS_AS(parser_helper("-0.0Z"), json::parse_error&); + CHECK_THROWS_AS(parser_helper("-0E123:"), json::parse_error&); + CHECK_THROWS_AS(parser_helper("-0e0-:"), json::parse_error&); + CHECK_THROWS_AS(parser_helper("-0e-:"), json::parse_error&); + CHECK_THROWS_AS(parser_helper("-0f"), json::parse_error&); // numbers must not begin with "+" - CHECK_THROWS_AS(parser_helper("+1"), json::parse_error); - CHECK_THROWS_AS(parser_helper("+0"), json::parse_error); + CHECK_THROWS_AS(parser_helper("+1"), json::parse_error&); + CHECK_THROWS_AS(parser_helper("+0"), json::parse_error&); CHECK_THROWS_WITH(parser_helper("01"), "[json.exception.parse_error.101] parse error at 2: syntax error - unexpected number literal; expected end of input"); @@ -717,20 +717,20 @@ TEST_CASE("parser class") SECTION("parse errors") { // unexpected end of number - CHECK_THROWS_AS(parser_helper("0."), json::parse_error); - CHECK_THROWS_AS(parser_helper("-"), json::parse_error); - CHECK_THROWS_AS(parser_helper("--"), json::parse_error); - CHECK_THROWS_AS(parser_helper("-0."), json::parse_error); - CHECK_THROWS_AS(parser_helper("-."), json::parse_error); - CHECK_THROWS_AS(parser_helper("-:"), json::parse_error); - CHECK_THROWS_AS(parser_helper("0.:"), json::parse_error); - CHECK_THROWS_AS(parser_helper("e."), json::parse_error); - CHECK_THROWS_AS(parser_helper("1e."), json::parse_error); - CHECK_THROWS_AS(parser_helper("1e/"), json::parse_error); - CHECK_THROWS_AS(parser_helper("1e:"), json::parse_error); - CHECK_THROWS_AS(parser_helper("1E."), json::parse_error); - CHECK_THROWS_AS(parser_helper("1E/"), json::parse_error); - CHECK_THROWS_AS(parser_helper("1E:"), json::parse_error); + CHECK_THROWS_AS(parser_helper("0."), json::parse_error&); + CHECK_THROWS_AS(parser_helper("-"), json::parse_error&); + CHECK_THROWS_AS(parser_helper("--"), json::parse_error&); + CHECK_THROWS_AS(parser_helper("-0."), json::parse_error&); + CHECK_THROWS_AS(parser_helper("-."), json::parse_error&); + CHECK_THROWS_AS(parser_helper("-:"), json::parse_error&); + CHECK_THROWS_AS(parser_helper("0.:"), json::parse_error&); + CHECK_THROWS_AS(parser_helper("e."), json::parse_error&); + CHECK_THROWS_AS(parser_helper("1e."), json::parse_error&); + CHECK_THROWS_AS(parser_helper("1e/"), json::parse_error&); + CHECK_THROWS_AS(parser_helper("1e:"), json::parse_error&); + CHECK_THROWS_AS(parser_helper("1E."), json::parse_error&); + CHECK_THROWS_AS(parser_helper("1E/"), json::parse_error&); + CHECK_THROWS_AS(parser_helper("1E:"), json::parse_error&); CHECK_THROWS_WITH(parser_helper("0."), "[json.exception.parse_error.101] parse error at 3: syntax error - invalid number; expected digit after '.'; last read: '0.'"); CHECK_THROWS_WITH(parser_helper("-"), @@ -761,11 +761,11 @@ TEST_CASE("parser class") "[json.exception.parse_error.101] parse error at 3: syntax error - invalid number; expected '+', '-', or digit after exponent; last read: '1E:'"); // unexpected end of null - CHECK_THROWS_AS(parser_helper("n"), json::parse_error); - CHECK_THROWS_AS(parser_helper("nu"), json::parse_error); - CHECK_THROWS_AS(parser_helper("nul"), json::parse_error); - CHECK_THROWS_AS(parser_helper("nulk"), json::parse_error); - CHECK_THROWS_AS(parser_helper("nulm"), json::parse_error); + CHECK_THROWS_AS(parser_helper("n"), json::parse_error&); + CHECK_THROWS_AS(parser_helper("nu"), json::parse_error&); + CHECK_THROWS_AS(parser_helper("nul"), json::parse_error&); + CHECK_THROWS_AS(parser_helper("nulk"), json::parse_error&); + CHECK_THROWS_AS(parser_helper("nulm"), json::parse_error&); CHECK_THROWS_WITH(parser_helper("n"), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid literal; last read: 'n'"); CHECK_THROWS_WITH(parser_helper("nu"), @@ -778,11 +778,11 @@ TEST_CASE("parser class") "[json.exception.parse_error.101] parse error at 4: syntax error - invalid literal; last read: 'nulm'"); // unexpected end of true - CHECK_THROWS_AS(parser_helper("t"), json::parse_error); - CHECK_THROWS_AS(parser_helper("tr"), json::parse_error); - CHECK_THROWS_AS(parser_helper("tru"), json::parse_error); - CHECK_THROWS_AS(parser_helper("trud"), json::parse_error); - CHECK_THROWS_AS(parser_helper("truf"), json::parse_error); + CHECK_THROWS_AS(parser_helper("t"), json::parse_error&); + CHECK_THROWS_AS(parser_helper("tr"), json::parse_error&); + CHECK_THROWS_AS(parser_helper("tru"), json::parse_error&); + CHECK_THROWS_AS(parser_helper("trud"), json::parse_error&); + CHECK_THROWS_AS(parser_helper("truf"), json::parse_error&); CHECK_THROWS_WITH(parser_helper("t"), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid literal; last read: 't'"); CHECK_THROWS_WITH(parser_helper("tr"), @@ -795,12 +795,12 @@ TEST_CASE("parser class") "[json.exception.parse_error.101] parse error at 4: syntax error - invalid literal; last read: 'truf'"); // unexpected end of false - CHECK_THROWS_AS(parser_helper("f"), json::parse_error); - CHECK_THROWS_AS(parser_helper("fa"), json::parse_error); - CHECK_THROWS_AS(parser_helper("fal"), json::parse_error); - CHECK_THROWS_AS(parser_helper("fals"), json::parse_error); - CHECK_THROWS_AS(parser_helper("falsd"), json::parse_error); - CHECK_THROWS_AS(parser_helper("falsf"), json::parse_error); + CHECK_THROWS_AS(parser_helper("f"), json::parse_error&); + CHECK_THROWS_AS(parser_helper("fa"), json::parse_error&); + CHECK_THROWS_AS(parser_helper("fal"), json::parse_error&); + CHECK_THROWS_AS(parser_helper("fals"), json::parse_error&); + CHECK_THROWS_AS(parser_helper("falsd"), json::parse_error&); + CHECK_THROWS_AS(parser_helper("falsf"), json::parse_error&); CHECK_THROWS_WITH(parser_helper("f"), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid literal; last read: 'f'"); CHECK_THROWS_WITH(parser_helper("fa"), @@ -815,11 +815,11 @@ TEST_CASE("parser class") "[json.exception.parse_error.101] parse error at 5: syntax error - invalid literal; last read: 'falsf'"); // missing/unexpected end of array - CHECK_THROWS_AS(parser_helper("["), json::parse_error); - CHECK_THROWS_AS(parser_helper("[1"), json::parse_error); - CHECK_THROWS_AS(parser_helper("[1,"), json::parse_error); - CHECK_THROWS_AS(parser_helper("[1,]"), json::parse_error); - CHECK_THROWS_AS(parser_helper("]"), json::parse_error); + CHECK_THROWS_AS(parser_helper("["), json::parse_error&); + CHECK_THROWS_AS(parser_helper("[1"), json::parse_error&); + CHECK_THROWS_AS(parser_helper("[1,"), json::parse_error&); + CHECK_THROWS_AS(parser_helper("[1,]"), json::parse_error&); + CHECK_THROWS_AS(parser_helper("]"), json::parse_error&); CHECK_THROWS_WITH(parser_helper("["), "[json.exception.parse_error.101] parse error at 2: syntax error - unexpected end of input; expected '[', '{', or a literal"); CHECK_THROWS_WITH(parser_helper("[1"), @@ -832,12 +832,12 @@ TEST_CASE("parser class") "[json.exception.parse_error.101] parse error at 1: syntax error - unexpected ']'; expected '[', '{', or a literal"); // missing/unexpected end of object - CHECK_THROWS_AS(parser_helper("{"), json::parse_error); - CHECK_THROWS_AS(parser_helper("{\"foo\""), json::parse_error); - CHECK_THROWS_AS(parser_helper("{\"foo\":"), json::parse_error); - CHECK_THROWS_AS(parser_helper("{\"foo\":}"), json::parse_error); - CHECK_THROWS_AS(parser_helper("{\"foo\":1,}"), json::parse_error); - CHECK_THROWS_AS(parser_helper("}"), json::parse_error); + CHECK_THROWS_AS(parser_helper("{"), json::parse_error&); + CHECK_THROWS_AS(parser_helper("{\"foo\""), json::parse_error&); + CHECK_THROWS_AS(parser_helper("{\"foo\":"), json::parse_error&); + CHECK_THROWS_AS(parser_helper("{\"foo\":}"), json::parse_error&); + CHECK_THROWS_AS(parser_helper("{\"foo\":1,}"), json::parse_error&); + CHECK_THROWS_AS(parser_helper("}"), json::parse_error&); CHECK_THROWS_WITH(parser_helper("{"), "[json.exception.parse_error.101] parse error at 2: syntax error - unexpected end of input; expected string literal"); CHECK_THROWS_WITH(parser_helper("{\"foo\""), @@ -852,16 +852,16 @@ TEST_CASE("parser class") "[json.exception.parse_error.101] parse error at 1: syntax error - unexpected '}'; expected '[', '{', or a literal"); // missing/unexpected end of string - CHECK_THROWS_AS(parser_helper("\""), json::parse_error); - CHECK_THROWS_AS(parser_helper("\"\\\""), json::parse_error); - CHECK_THROWS_AS(parser_helper("\"\\u\""), json::parse_error); - CHECK_THROWS_AS(parser_helper("\"\\u0\""), json::parse_error); - CHECK_THROWS_AS(parser_helper("\"\\u01\""), json::parse_error); - CHECK_THROWS_AS(parser_helper("\"\\u012\""), json::parse_error); - CHECK_THROWS_AS(parser_helper("\"\\u"), json::parse_error); - CHECK_THROWS_AS(parser_helper("\"\\u0"), json::parse_error); - CHECK_THROWS_AS(parser_helper("\"\\u01"), json::parse_error); - CHECK_THROWS_AS(parser_helper("\"\\u012"), json::parse_error); + CHECK_THROWS_AS(parser_helper("\""), json::parse_error&); + CHECK_THROWS_AS(parser_helper("\"\\\""), json::parse_error&); + CHECK_THROWS_AS(parser_helper("\"\\u\""), json::parse_error&); + CHECK_THROWS_AS(parser_helper("\"\\u0\""), json::parse_error&); + CHECK_THROWS_AS(parser_helper("\"\\u01\""), json::parse_error&); + CHECK_THROWS_AS(parser_helper("\"\\u012\""), json::parse_error&); + CHECK_THROWS_AS(parser_helper("\"\\u"), json::parse_error&); + CHECK_THROWS_AS(parser_helper("\"\\u0"), json::parse_error&); + CHECK_THROWS_AS(parser_helper("\"\\u01"), json::parse_error&); + CHECK_THROWS_AS(parser_helper("\"\\u012"), json::parse_error&); CHECK_THROWS_WITH(parser_helper("\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: missing closing quote; last read: '\"'"); CHECK_THROWS_WITH(parser_helper("\"\\\""), @@ -913,7 +913,7 @@ TEST_CASE("parser class") // any other combination of backslash and character is invalid default: { - CHECK_THROWS_AS(parser_helper(s.c_str()), json::parse_error); + CHECK_THROWS_AS(parser_helper(s.c_str()), json::parse_error&); // only check error message if c is not a control character if (c > 0x1f) { @@ -989,7 +989,7 @@ TEST_CASE("parser class") else { CAPTURE(s1); - CHECK_THROWS_AS(parser_helper(s1.c_str()), json::parse_error); + CHECK_THROWS_AS(parser_helper(s1.c_str()), json::parse_error&); // only check error message if c is not a control character if (c > 0x1f) { @@ -998,7 +998,7 @@ TEST_CASE("parser class") } CAPTURE(s2); - CHECK_THROWS_AS(parser_helper(s2.c_str()), json::parse_error); + CHECK_THROWS_AS(parser_helper(s2.c_str()), json::parse_error&); // only check error message if c is not a control character if (c > 0x1f) { @@ -1007,7 +1007,7 @@ TEST_CASE("parser class") } CAPTURE(s3); - CHECK_THROWS_AS(parser_helper(s3.c_str()), json::parse_error); + CHECK_THROWS_AS(parser_helper(s3.c_str()), json::parse_error&); // only check error message if c is not a control character if (c > 0x1f) { @@ -1016,7 +1016,7 @@ TEST_CASE("parser class") } CAPTURE(s4); - CHECK_THROWS_AS(parser_helper(s4.c_str()), json::parse_error); + CHECK_THROWS_AS(parser_helper(s4.c_str()), json::parse_error&); // only check error message if c is not a control character if (c > 0x1f) { @@ -1028,13 +1028,13 @@ TEST_CASE("parser class") } // missing part of a surrogate pair - CHECK_THROWS_AS(json::parse("\"\\uD80C\""), json::parse_error); + CHECK_THROWS_AS(json::parse("\"\\uD80C\""), json::parse_error&); CHECK_THROWS_WITH(json::parse("\"\\uD80C\""), "[json.exception.parse_error.101] parse error at 8: syntax error - invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF; last read: '\"\\uD80C\"'"); // invalid surrogate pair - CHECK_THROWS_AS(json::parse("\"\\uD80C\\uD80C\""), json::parse_error); - CHECK_THROWS_AS(json::parse("\"\\uD80C\\u0000\""), json::parse_error); - CHECK_THROWS_AS(json::parse("\"\\uD80C\\uFFFF\""), json::parse_error); + CHECK_THROWS_AS(json::parse("\"\\uD80C\\uD80C\""), json::parse_error&); + CHECK_THROWS_AS(json::parse("\"\\uD80C\\u0000\""), json::parse_error&); + CHECK_THROWS_AS(json::parse("\"\\uD80C\\uFFFF\""), json::parse_error&); CHECK_THROWS_WITH(json::parse("\"\\uD80C\\uD80C\""), "[json.exception.parse_error.101] parse error at 13: syntax error - invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF; last read: '\"\\uD80C\\uD80C'"); CHECK_THROWS_WITH(json::parse("\"\\uD80C\\u0000\""), @@ -1229,11 +1229,11 @@ TEST_CASE("parser class") SECTION("tests found by mutate++") { // test case to make sure no comma preceeds the first key - CHECK_THROWS_AS(parser_helper("{,\"key\": false}"), json::parse_error); + CHECK_THROWS_AS(parser_helper("{,\"key\": false}"), json::parse_error&); CHECK_THROWS_WITH(parser_helper("{,\"key\": false}"), "[json.exception.parse_error.101] parse error at 2: syntax error - unexpected ','; expected string literal"); // test case to make sure an object is properly closed - CHECK_THROWS_AS(parser_helper("[{\"key\": false true]"), json::parse_error); + CHECK_THROWS_AS(parser_helper("[{\"key\": false true]"), json::parse_error&); CHECK_THROWS_WITH(parser_helper("[{\"key\": false true]"), "[json.exception.parse_error.101] parse error at 19: syntax error - unexpected true literal; expected '}'"); diff --git a/test/src/unit-constructor1.cpp b/test/src/unit-constructor1.cpp index 8840fe7e..d8c9482c 100644 --- a/test/src/unit-constructor1.cpp +++ b/test/src/unit-constructor1.cpp @@ -36,7 +36,6 @@ using nlohmann::json; #include #include #include -#include #include #include #include @@ -1050,7 +1049,7 @@ TEST_CASE("constructors") SECTION("object with error") { CHECK_THROWS_AS(json::object({ {"one", 1}, {"two", 1u}, {"three", 2.2}, {"four", false}, 13 }), - json::type_error); + json::type_error&); CHECK_THROWS_WITH(json::object({ {"one", 1}, {"two", 1u}, {"three", 2.2}, {"four", false}, 13 }), "[json.exception.type_error.301] cannot create object from initializer list"); } @@ -1264,16 +1263,16 @@ TEST_CASE("constructors") { json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}, {"d", false}, {"e", true}}; json jobject2 = {{"a", "a"}, {"b", 1}, {"c", 17u}}; - CHECK_THROWS_AS(json(jobject.begin(), jobject2.end()), json::invalid_iterator); - CHECK_THROWS_AS(json(jobject2.begin(), jobject.end()), json::invalid_iterator); + CHECK_THROWS_AS(json(jobject.begin(), jobject2.end()), json::invalid_iterator&); + CHECK_THROWS_AS(json(jobject2.begin(), jobject.end()), json::invalid_iterator&); CHECK_THROWS_WITH(json(jobject.begin(), jobject2.end()), "[json.exception.invalid_iterator.201] iterators are not compatible"); CHECK_THROWS_WITH(json(jobject2.begin(), jobject.end()), "[json.exception.invalid_iterator.201] iterators are not compatible"); } { json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}, {"d", false}, {"e", true}}; json jobject2 = {{"a", "a"}, {"b", 1}, {"c", 17u}}; - CHECK_THROWS_AS(json(jobject.cbegin(), jobject2.cend()), json::invalid_iterator); - CHECK_THROWS_AS(json(jobject2.cbegin(), jobject.cend()), json::invalid_iterator); + CHECK_THROWS_AS(json(jobject.cbegin(), jobject2.cend()), json::invalid_iterator&); + CHECK_THROWS_AS(json(jobject2.cbegin(), jobject.cend()), json::invalid_iterator&); CHECK_THROWS_WITH(json(jobject.cbegin(), jobject2.cend()), "[json.exception.invalid_iterator.201] iterators are not compatible"); CHECK_THROWS_WITH(json(jobject2.cbegin(), jobject.cend()), "[json.exception.invalid_iterator.201] iterators are not compatible"); } @@ -1329,16 +1328,16 @@ TEST_CASE("constructors") { json jarray = {1, 2, 3, 4}; json jarray2 = {2, 3, 4, 5}; - CHECK_THROWS_AS(json(jarray.begin(), jarray2.end()), json::invalid_iterator); - CHECK_THROWS_AS(json(jarray2.begin(), jarray.end()), json::invalid_iterator); + CHECK_THROWS_AS(json(jarray.begin(), jarray2.end()), json::invalid_iterator&); + CHECK_THROWS_AS(json(jarray2.begin(), jarray.end()), json::invalid_iterator&); CHECK_THROWS_WITH(json(jarray.begin(), jarray2.end()), "[json.exception.invalid_iterator.201] iterators are not compatible"); CHECK_THROWS_WITH(json(jarray2.begin(), jarray.end()), "[json.exception.invalid_iterator.201] iterators are not compatible"); } { json jarray = {1, 2, 3, 4}; json jarray2 = {2, 3, 4, 5}; - CHECK_THROWS_AS(json(jarray.cbegin(), jarray2.cend()), json::invalid_iterator); - CHECK_THROWS_AS(json(jarray2.cbegin(), jarray.cend()), json::invalid_iterator); + CHECK_THROWS_AS(json(jarray.cbegin(), jarray2.cend()), json::invalid_iterator&); + CHECK_THROWS_AS(json(jarray2.cbegin(), jarray.cend()), json::invalid_iterator&); CHECK_THROWS_WITH(json(jarray.cbegin(), jarray2.cend()), "[json.exception.invalid_iterator.201] iterators are not compatible"); CHECK_THROWS_WITH(json(jarray2.cbegin(), jarray.cend()), "[json.exception.invalid_iterator.201] iterators are not compatible"); } @@ -1353,13 +1352,13 @@ TEST_CASE("constructors") { { json j; - CHECK_THROWS_AS(json(j.begin(), j.end()), json::invalid_iterator); + CHECK_THROWS_AS(json(j.begin(), j.end()), json::invalid_iterator&); CHECK_THROWS_WITH(json(j.begin(), j.end()), "[json.exception.invalid_iterator.206] cannot construct with iterators from null"); } { json j; - CHECK_THROWS_AS(json(j.cbegin(), j.cend()), json::invalid_iterator); + CHECK_THROWS_AS(json(j.cbegin(), j.cend()), json::invalid_iterator&); CHECK_THROWS_WITH(json(j.cbegin(), j.cend()), "[json.exception.invalid_iterator.206] cannot construct with iterators from null"); } @@ -1442,15 +1441,15 @@ TEST_CASE("constructors") { { json j = "foo"; - CHECK_THROWS_AS(json(j.end(), j.end()), json::invalid_iterator); - CHECK_THROWS_AS(json(j.begin(), j.begin()), json::invalid_iterator); + CHECK_THROWS_AS(json(j.end(), j.end()), json::invalid_iterator&); + CHECK_THROWS_AS(json(j.begin(), j.begin()), json::invalid_iterator&); CHECK_THROWS_WITH(json(j.end(), j.end()), "[json.exception.invalid_iterator.204] iterators out of range"); CHECK_THROWS_WITH(json(j.begin(), j.begin()), "[json.exception.invalid_iterator.204] iterators out of range"); } { json j = "bar"; - CHECK_THROWS_AS(json(j.cend(), j.cend()), json::invalid_iterator); - CHECK_THROWS_AS(json(j.cbegin(), j.cbegin()), json::invalid_iterator); + CHECK_THROWS_AS(json(j.cend(), j.cend()), json::invalid_iterator&); + CHECK_THROWS_AS(json(j.cbegin(), j.cbegin()), json::invalid_iterator&); CHECK_THROWS_WITH(json(j.cend(), j.cend()), "[json.exception.invalid_iterator.204] iterators out of range"); CHECK_THROWS_WITH(json(j.cbegin(), j.cbegin()), "[json.exception.invalid_iterator.204] iterators out of range"); } @@ -1460,15 +1459,15 @@ TEST_CASE("constructors") { { json j = false; - CHECK_THROWS_AS(json(j.end(), j.end()), json::invalid_iterator); - CHECK_THROWS_AS(json(j.begin(), j.begin()), json::invalid_iterator); + CHECK_THROWS_AS(json(j.end(), j.end()), json::invalid_iterator&); + CHECK_THROWS_AS(json(j.begin(), j.begin()), json::invalid_iterator&); CHECK_THROWS_WITH(json(j.end(), j.end()), "[json.exception.invalid_iterator.204] iterators out of range"); CHECK_THROWS_WITH(json(j.begin(), j.begin()), "[json.exception.invalid_iterator.204] iterators out of range"); } { json j = true; - CHECK_THROWS_AS(json(j.cend(), j.cend()), json::invalid_iterator); - CHECK_THROWS_AS(json(j.cbegin(), j.cbegin()), json::invalid_iterator); + CHECK_THROWS_AS(json(j.cend(), j.cend()), json::invalid_iterator&); + CHECK_THROWS_AS(json(j.cbegin(), j.cbegin()), json::invalid_iterator&); CHECK_THROWS_WITH(json(j.cend(), j.cend()), "[json.exception.invalid_iterator.204] iterators out of range"); CHECK_THROWS_WITH(json(j.cbegin(), j.cbegin()), "[json.exception.invalid_iterator.204] iterators out of range"); } @@ -1478,15 +1477,15 @@ TEST_CASE("constructors") { { json j = 17; - CHECK_THROWS_AS(json(j.end(), j.end()), json::invalid_iterator); - CHECK_THROWS_AS(json(j.begin(), j.begin()), json::invalid_iterator); + CHECK_THROWS_AS(json(j.end(), j.end()), json::invalid_iterator&); + CHECK_THROWS_AS(json(j.begin(), j.begin()), json::invalid_iterator&); CHECK_THROWS_WITH(json(j.end(), j.end()), "[json.exception.invalid_iterator.204] iterators out of range"); CHECK_THROWS_WITH(json(j.begin(), j.begin()), "[json.exception.invalid_iterator.204] iterators out of range"); } { json j = 17; - CHECK_THROWS_AS(json(j.cend(), j.cend()), json::invalid_iterator); - CHECK_THROWS_AS(json(j.cbegin(), j.cbegin()), json::invalid_iterator); + CHECK_THROWS_AS(json(j.cend(), j.cend()), json::invalid_iterator&); + CHECK_THROWS_AS(json(j.cbegin(), j.cbegin()), json::invalid_iterator&); CHECK_THROWS_WITH(json(j.cend(), j.cend()), "[json.exception.invalid_iterator.204] iterators out of range"); CHECK_THROWS_WITH(json(j.cbegin(), j.cbegin()), "[json.exception.invalid_iterator.204] iterators out of range"); } @@ -1496,15 +1495,15 @@ TEST_CASE("constructors") { { json j = 17u; - CHECK_THROWS_AS(json(j.end(), j.end()), json::invalid_iterator); - CHECK_THROWS_AS(json(j.begin(), j.begin()), json::invalid_iterator); + CHECK_THROWS_AS(json(j.end(), j.end()), json::invalid_iterator&); + CHECK_THROWS_AS(json(j.begin(), j.begin()), json::invalid_iterator&); CHECK_THROWS_WITH(json(j.end(), j.end()), "[json.exception.invalid_iterator.204] iterators out of range"); CHECK_THROWS_WITH(json(j.begin(), j.begin()), "[json.exception.invalid_iterator.204] iterators out of range"); } { json j = 17u; - CHECK_THROWS_AS(json(j.cend(), j.cend()), json::invalid_iterator); - CHECK_THROWS_AS(json(j.cbegin(), j.cbegin()), json::invalid_iterator); + CHECK_THROWS_AS(json(j.cend(), j.cend()), json::invalid_iterator&); + CHECK_THROWS_AS(json(j.cbegin(), j.cbegin()), json::invalid_iterator&); CHECK_THROWS_WITH(json(j.cend(), j.cend()), "[json.exception.invalid_iterator.204] iterators out of range"); CHECK_THROWS_WITH(json(j.cbegin(), j.cbegin()), "[json.exception.invalid_iterator.204] iterators out of range"); } @@ -1514,15 +1513,15 @@ TEST_CASE("constructors") { { json j = 23.42; - CHECK_THROWS_AS(json(j.end(), j.end()), json::invalid_iterator); - CHECK_THROWS_AS(json(j.begin(), j.begin()), json::invalid_iterator); + CHECK_THROWS_AS(json(j.end(), j.end()), json::invalid_iterator&); + CHECK_THROWS_AS(json(j.begin(), j.begin()), json::invalid_iterator&); CHECK_THROWS_WITH(json(j.end(), j.end()), "[json.exception.invalid_iterator.204] iterators out of range"); CHECK_THROWS_WITH(json(j.begin(), j.begin()), "[json.exception.invalid_iterator.204] iterators out of range"); } { json j = 23.42; - CHECK_THROWS_AS(json(j.cend(), j.cend()), json::invalid_iterator); - CHECK_THROWS_AS(json(j.cbegin(), j.cbegin()), json::invalid_iterator); + CHECK_THROWS_AS(json(j.cend(), j.cend()), json::invalid_iterator&); + CHECK_THROWS_AS(json(j.cbegin(), j.cbegin()), json::invalid_iterator&); CHECK_THROWS_WITH(json(j.cend(), j.cend()), "[json.exception.invalid_iterator.204] iterators out of range"); CHECK_THROWS_WITH(json(j.cbegin(), j.cbegin()), "[json.exception.invalid_iterator.204] iterators out of range"); } diff --git a/test/src/unit-conversions.cpp b/test/src/unit-conversions.cpp index fdbc7289..eafac320 100644 --- a/test/src/unit-conversions.cpp +++ b/test/src/unit-conversions.cpp @@ -35,7 +35,6 @@ using nlohmann::json; #include #include #include -#include #include #include #include @@ -80,13 +79,13 @@ TEST_CASE("value conversion") SECTION("exception in case of a non-object type") { - CHECK_THROWS_AS(json(json::value_t::null).get(), json::type_error); - CHECK_THROWS_AS(json(json::value_t::array).get(), json::type_error); - CHECK_THROWS_AS(json(json::value_t::string).get(), json::type_error); - CHECK_THROWS_AS(json(json::value_t::boolean).get(), json::type_error); - CHECK_THROWS_AS(json(json::value_t::number_integer).get(), json::type_error); - CHECK_THROWS_AS(json(json::value_t::number_unsigned).get(), json::type_error); - CHECK_THROWS_AS(json(json::value_t::number_float).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::null).get(), json::type_error&); + CHECK_THROWS_AS(json(json::value_t::array).get(), json::type_error&); + CHECK_THROWS_AS(json(json::value_t::string).get(), json::type_error&); + CHECK_THROWS_AS(json(json::value_t::boolean).get(), json::type_error&); + CHECK_THROWS_AS(json(json::value_t::number_integer).get(), json::type_error&); + CHECK_THROWS_AS(json(json::value_t::number_unsigned).get(), json::type_error&); + CHECK_THROWS_AS(json(json::value_t::number_float).get(), json::type_error&); CHECK_THROWS_WITH(json(json::value_t::null).get(), "[json.exception.type_error.302] type must be object, but is null"); @@ -163,7 +162,7 @@ TEST_CASE("value conversion") std::forward_list a = j.get>(); CHECK(json(a) == j); - CHECK_THROWS_AS(json(json::value_t::null).get>(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::null).get>(), json::type_error&); CHECK_THROWS_WITH(json(json::value_t::null).get>(), "[json.exception.type_error.302] type must be array, but is null"); } @@ -173,7 +172,7 @@ TEST_CASE("value conversion") std::vector a = j.get>(); CHECK(json(a) == j); - CHECK_THROWS_AS(json(json::value_t::null).get>(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::null).get>(), json::type_error&); CHECK_THROWS_WITH(json(json::value_t::null).get>(), "[json.exception.type_error.302] type must be array, but is null"); @@ -182,7 +181,7 @@ TEST_CASE("value conversion") { // making the call to from_json throw in order to check capacity std::vector v; - CHECK_THROWS_AS(nlohmann::from_json(j, v), json::type_error); + CHECK_THROWS_AS(nlohmann::from_json(j, v), json::type_error&); CHECK(v.capacity() == j.size()); // make sure all values are properly copied @@ -214,13 +213,13 @@ TEST_CASE("value conversion") SECTION("exception in case of a non-array type") { - CHECK_THROWS_AS(json(json::value_t::null).get(), json::type_error); - CHECK_THROWS_AS(json(json::value_t::object).get(), json::type_error); - CHECK_THROWS_AS(json(json::value_t::string).get(), json::type_error); - CHECK_THROWS_AS(json(json::value_t::boolean).get(), json::type_error); - CHECK_THROWS_AS(json(json::value_t::number_integer).get(), json::type_error); - CHECK_THROWS_AS(json(json::value_t::number_unsigned).get(), json::type_error); - CHECK_THROWS_AS(json(json::value_t::number_float).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::null).get(), json::type_error&); + CHECK_THROWS_AS(json(json::value_t::object).get(), json::type_error&); + CHECK_THROWS_AS(json(json::value_t::string).get(), json::type_error&); + CHECK_THROWS_AS(json(json::value_t::boolean).get(), json::type_error&); + CHECK_THROWS_AS(json(json::value_t::number_integer).get(), json::type_error&); + CHECK_THROWS_AS(json(json::value_t::number_unsigned).get(), json::type_error&); + CHECK_THROWS_AS(json(json::value_t::number_float).get(), json::type_error&); CHECK_THROWS_WITH(json(json::value_t::object).get>(), "[json.exception.type_error.302] type must be array, but is object"); @@ -296,13 +295,13 @@ TEST_CASE("value conversion") SECTION("exception in case of a non-string type") { - CHECK_THROWS_AS(json(json::value_t::null).get(), json::type_error); - CHECK_THROWS_AS(json(json::value_t::object).get(), json::type_error); - CHECK_THROWS_AS(json(json::value_t::array).get(), json::type_error); - CHECK_THROWS_AS(json(json::value_t::boolean).get(), json::type_error); - CHECK_THROWS_AS(json(json::value_t::number_integer).get(), json::type_error); - CHECK_THROWS_AS(json(json::value_t::number_unsigned).get(), json::type_error); - CHECK_THROWS_AS(json(json::value_t::number_float).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::null).get(), json::type_error&); + CHECK_THROWS_AS(json(json::value_t::object).get(), json::type_error&); + CHECK_THROWS_AS(json(json::value_t::array).get(), json::type_error&); + CHECK_THROWS_AS(json(json::value_t::boolean).get(), json::type_error&); + CHECK_THROWS_AS(json(json::value_t::number_integer).get(), json::type_error&); + CHECK_THROWS_AS(json(json::value_t::number_unsigned).get(), json::type_error&); + CHECK_THROWS_AS(json(json::value_t::number_float).get(), json::type_error&); CHECK_THROWS_WITH(json(json::value_t::null).get(), "[json.exception.type_error.302] type must be string, but is null"); @@ -358,13 +357,13 @@ TEST_CASE("value conversion") SECTION("exception in case of a non-string type") { - CHECK_THROWS_AS(json(json::value_t::null).get(), json::type_error); - CHECK_THROWS_AS(json(json::value_t::object).get(), json::type_error); - CHECK_THROWS_AS(json(json::value_t::array).get(), json::type_error); - CHECK_THROWS_AS(json(json::value_t::string).get(), json::type_error); - CHECK_THROWS_AS(json(json::value_t::number_integer).get(), json::type_error); - CHECK_THROWS_AS(json(json::value_t::number_unsigned).get(), json::type_error); - CHECK_THROWS_AS(json(json::value_t::number_float).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::null).get(), json::type_error&); + CHECK_THROWS_AS(json(json::value_t::object).get(), json::type_error&); + CHECK_THROWS_AS(json(json::value_t::array).get(), json::type_error&); + CHECK_THROWS_AS(json(json::value_t::string).get(), json::type_error&); + CHECK_THROWS_AS(json(json::value_t::number_integer).get(), json::type_error&); + CHECK_THROWS_AS(json(json::value_t::number_unsigned).get(), json::type_error&); + CHECK_THROWS_AS(json(json::value_t::number_float).get(), json::type_error&); CHECK_THROWS_WITH(json(json::value_t::null).get(), "[json.exception.type_error.302] type must be boolean, but is null"); @@ -614,11 +613,11 @@ TEST_CASE("value conversion") SECTION("exception in case of a non-number type") { - CHECK_THROWS_AS(json(json::value_t::null).get(), json::type_error); - CHECK_THROWS_AS(json(json::value_t::object).get(), json::type_error); - CHECK_THROWS_AS(json(json::value_t::array).get(), json::type_error); - CHECK_THROWS_AS(json(json::value_t::string).get(), json::type_error); - CHECK_THROWS_AS(json(json::value_t::boolean).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::null).get(), json::type_error&); + CHECK_THROWS_AS(json(json::value_t::object).get(), json::type_error&); + CHECK_THROWS_AS(json(json::value_t::array).get(), json::type_error&); + CHECK_THROWS_AS(json(json::value_t::string).get(), json::type_error&); + CHECK_THROWS_AS(json(json::value_t::boolean).get(), json::type_error&); CHECK_THROWS_WITH(json(json::value_t::null).get(), "[json.exception.type_error.302] type must be number, but is null"); @@ -873,11 +872,11 @@ TEST_CASE("value conversion") SECTION("exception in case of a non-string type") { - CHECK_THROWS_AS(json(json::value_t::null).get(), json::type_error); - CHECK_THROWS_AS(json(json::value_t::object).get(), json::type_error); - CHECK_THROWS_AS(json(json::value_t::array).get(), json::type_error); - CHECK_THROWS_AS(json(json::value_t::string).get(), json::type_error); - CHECK_THROWS_AS(json(json::value_t::boolean).get(), json::type_error); + CHECK_THROWS_AS(json(json::value_t::null).get(), json::type_error&); + CHECK_THROWS_AS(json(json::value_t::object).get(), json::type_error&); + CHECK_THROWS_AS(json(json::value_t::array).get(), json::type_error&); + CHECK_THROWS_AS(json(json::value_t::string).get(), json::type_error&); + CHECK_THROWS_AS(json(json::value_t::boolean).get(), json::type_error&); CHECK_THROWS_WITH(json(json::value_t::null).get(), "[json.exception.type_error.302] type must be number, but is null"); @@ -979,7 +978,7 @@ TEST_CASE("value conversion") SECTION("exception in case of a non-object type") { - CHECK_THROWS_AS((json().get>()), json::type_error); + CHECK_THROWS_AS((json().get>()), json::type_error&); CHECK_THROWS_WITH((json().get>()), "[json.exception.type_error.302] type must be object, but is null"); } } @@ -1081,11 +1080,11 @@ TEST_CASE("value conversion") SECTION("exception in case of a non-object type") { - CHECK_THROWS_AS((json().get>()), json::type_error); - CHECK_THROWS_AS((json().get>()), json::type_error); - CHECK_THROWS_AS((json().get>()), json::type_error); - CHECK_THROWS_AS((json().get>()), json::type_error); - CHECK_THROWS_AS((json().get>()), json::type_error); + CHECK_THROWS_AS((json().get>()), json::type_error&); + CHECK_THROWS_AS((json().get>()), json::type_error&); + CHECK_THROWS_AS((json().get>()), json::type_error&); + CHECK_THROWS_AS((json().get>()), json::type_error&); + CHECK_THROWS_AS((json().get>()), json::type_error&); // does type really must be an array? or it rather must not be null? // that's what I thought when other test like this one broke diff --git a/test/src/unit-deserialization.cpp b/test/src/unit-deserialization.cpp index eb347b59..2798f102 100644 --- a/test/src/unit-deserialization.cpp +++ b/test/src/unit-deserialization.cpp @@ -97,7 +97,7 @@ TEST_CASE("deserialization") ss2 << "[\"foo\",1,2,3,false,{\"one\":1}"; ss3 << "[\"foo\",1,2,3,false,{\"one\":1}"; ss4 << "[\"foo\",1,2,3,false,{\"one\":1}"; - CHECK_THROWS_AS(json::parse(ss1), json::parse_error); + CHECK_THROWS_AS(json::parse(ss1), json::parse_error&); CHECK_THROWS_WITH(json::parse(ss2), "[json.exception.parse_error.101] parse error at 29: syntax error - unexpected end of input; expected ']'"); CHECK(not json::accept(ss3)); @@ -110,7 +110,7 @@ TEST_CASE("deserialization") SECTION("string") { json::string_t s = "[\"foo\",1,2,3,false,{\"one\":1}"; - CHECK_THROWS_AS(json::parse(s), json::parse_error); + CHECK_THROWS_AS(json::parse(s), json::parse_error&); CHECK_THROWS_WITH(json::parse(s), "[json.exception.parse_error.101] parse error at 29: syntax error - unexpected end of input; expected ']'"); CHECK(not json::accept(s)); @@ -126,7 +126,7 @@ TEST_CASE("deserialization") ss1 << "[\"foo\",1,2,3,false,{\"one\":1}"; ss2 << "[\"foo\",1,2,3,false,{\"one\":1}"; json j; - CHECK_THROWS_AS(j << ss1, json::parse_error); + CHECK_THROWS_AS(j << ss1, json::parse_error&); CHECK_THROWS_WITH(j << ss2, "[json.exception.parse_error.101] parse error at 29: syntax error - unexpected end of input; expected ']'"); } @@ -137,14 +137,14 @@ TEST_CASE("deserialization") ss1 << "[\"foo\",1,2,3,false,{\"one\":1}"; ss2 << "[\"foo\",1,2,3,false,{\"one\":1}"; json j; - CHECK_THROWS_AS(ss1 >> j, json::parse_error); + CHECK_THROWS_AS(ss1 >> j, json::parse_error&); CHECK_THROWS_WITH(ss2 >> j, "[json.exception.parse_error.101] parse error at 29: syntax error - unexpected end of input; expected ']'"); } SECTION("user-defined string literal") { - CHECK_THROWS_AS("[\"foo\",1,2,3,false,{\"one\":1}"_json, json::parse_error); + CHECK_THROWS_AS("[\"foo\",1,2,3,false,{\"one\":1}"_json, json::parse_error&); CHECK_THROWS_WITH("[\"foo\",1,2,3,false,{\"one\":1}"_json, "[json.exception.parse_error.101] parse error at 29: syntax error - unexpected end of input; expected ']'"); } @@ -205,7 +205,7 @@ TEST_CASE("deserialization") SECTION("empty container") { std::vector v; - CHECK_THROWS_AS(json::parse(v), json::parse_error); + CHECK_THROWS_AS(json::parse(v), json::parse_error&); CHECK(not json::accept(v)); } } @@ -257,7 +257,7 @@ TEST_CASE("deserialization") SECTION("with empty range") { std::vector v; - CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error); + CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&); CHECK(not json::accept(std::begin(v), std::end(v))); } } @@ -268,7 +268,7 @@ TEST_CASE("deserialization") SECTION("case 1") { uint8_t v[] = {'\"', 'a', 'a', 'a', 'a', 'a', 'a', '\\', 'u'}; - CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error); + CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&); CHECK(not json::accept(std::begin(v), std::end(v))); json j_error; @@ -279,7 +279,7 @@ TEST_CASE("deserialization") SECTION("case 2") { uint8_t v[] = {'\"', 'a', 'a', 'a', 'a', 'a', 'a', '\\', 'u', '1'}; - CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error); + CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&); CHECK(not json::accept(std::begin(v), std::end(v))); json j_error; @@ -290,7 +290,7 @@ TEST_CASE("deserialization") SECTION("case 3") { uint8_t v[] = {'\"', 'a', 'a', 'a', 'a', 'a', 'a', '\\', 'u', '1', '1', '1', '1', '1', '1', '1', '1'}; - CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error); + CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&); CHECK(not json::accept(std::begin(v), std::end(v))); json j_error; @@ -301,7 +301,7 @@ TEST_CASE("deserialization") SECTION("case 4") { uint8_t v[] = {'\"', 'a', 'a', 'a', 'a', 'a', 'a', 'u', '1', '1', '1', '1', '1', '1', '1', '1', '\\'}; - CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error); + CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&); CHECK(not json::accept(std::begin(v), std::end(v))); json j_error; @@ -312,7 +312,7 @@ TEST_CASE("deserialization") SECTION("case 5") { uint8_t v[] = {'\"', 0x7F, 0xC1}; - CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error); + CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&); CHECK(not json::accept(std::begin(v), std::end(v))); json j_error; @@ -323,7 +323,7 @@ TEST_CASE("deserialization") SECTION("case 6") { uint8_t v[] = {'\"', 0x7F, 0xDF, 0x7F}; - CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error); + CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&); CHECK_THROWS_WITH(json::parse(std::begin(v), std::end(v)), "[json.exception.parse_error.101] parse error at 4: syntax error - invalid string: ill-formed UTF-8 byte; last read: '\"\x7f\xdf\x7f'"); CHECK(not json::accept(std::begin(v), std::end(v))); @@ -336,7 +336,7 @@ TEST_CASE("deserialization") SECTION("case 7") { uint8_t v[] = {'\"', 0x7F, 0xDF, 0xC0}; - CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error); + CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&); CHECK(not json::accept(std::begin(v), std::end(v))); json j_error; @@ -347,7 +347,7 @@ TEST_CASE("deserialization") SECTION("case 8") { uint8_t v[] = {'\"', 0x7F, 0xE0, 0x9F}; - CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error); + CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&); CHECK(not json::accept(std::begin(v), std::end(v))); json j_error; @@ -358,7 +358,7 @@ TEST_CASE("deserialization") SECTION("case 9") { uint8_t v[] = {'\"', 0x7F, 0xEF, 0xC0}; - CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error); + CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&); CHECK(not json::accept(std::begin(v), std::end(v))); json j_error; @@ -369,7 +369,7 @@ TEST_CASE("deserialization") SECTION("case 10") { uint8_t v[] = {'\"', 0x7F, 0xED, 0x7F}; - CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error); + CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&); CHECK(not json::accept(std::begin(v), std::end(v))); json j_error; @@ -380,7 +380,7 @@ TEST_CASE("deserialization") SECTION("case 11") { uint8_t v[] = {'\"', 0x7F, 0xF0, 0x8F}; - CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error); + CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&); CHECK(not json::accept(std::begin(v), std::end(v))); json j_error; @@ -391,7 +391,7 @@ TEST_CASE("deserialization") SECTION("case 12") { uint8_t v[] = {'\"', 0x7F, 0xF0, 0xC0}; - CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error); + CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&); CHECK(not json::accept(std::begin(v), std::end(v))); json j_error; @@ -402,7 +402,7 @@ TEST_CASE("deserialization") SECTION("case 13") { uint8_t v[] = {'\"', 0x7F, 0xF3, 0x7F}; - CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error); + CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&); CHECK(not json::accept(std::begin(v), std::end(v))); json j_error; @@ -413,7 +413,7 @@ TEST_CASE("deserialization") SECTION("case 14") { uint8_t v[] = {'\"', 0x7F, 0xF3, 0xC0}; - CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error); + CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&); CHECK(not json::accept(std::begin(v), std::end(v))); json j_error; @@ -424,7 +424,7 @@ TEST_CASE("deserialization") SECTION("case 15") { uint8_t v[] = {'\"', 0x7F, 0xF4, 0x7F}; - CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error); + CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&); CHECK(not json::accept(std::begin(v), std::end(v))); json j_error; @@ -435,7 +435,7 @@ TEST_CASE("deserialization") SECTION("case 16") { uint8_t v[] = {'{', '\"', '\"', ':', '1', '1'}; - CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error); + CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&); CHECK(not json::accept(std::begin(v), std::end(v))); json j_error; @@ -451,11 +451,11 @@ TEST_CASE("deserialization") SECTION("BOM only") { - CHECK_THROWS_AS(json::parse(bom), json::parse_error); + CHECK_THROWS_AS(json::parse(bom), json::parse_error&); CHECK_THROWS_WITH(json::parse(bom), "[json.exception.parse_error.101] parse error at 1: syntax error - unexpected end of input; expected '[', '{', or a literal"); - CHECK_THROWS_AS(json::parse(std::istringstream(bom)), json::parse_error); + CHECK_THROWS_AS(json::parse(std::istringstream(bom)), json::parse_error&); CHECK_THROWS_WITH(json::parse(std::istringstream(bom)), "[json.exception.parse_error.101] parse error at 1: syntax error - unexpected end of input; expected '[', '{', or a literal"); } @@ -468,22 +468,22 @@ TEST_CASE("deserialization") SECTION("2 byte of BOM") { - CHECK_THROWS_AS(json::parse(bom.substr(0, 2)), json::parse_error); + CHECK_THROWS_AS(json::parse(bom.substr(0, 2)), json::parse_error&); CHECK_THROWS_WITH(json::parse(bom), "[json.exception.parse_error.101] parse error at 1: syntax error - unexpected end of input; expected '[', '{', or a literal"); - CHECK_THROWS_AS(json::parse(std::istringstream(bom.substr(0, 2))), json::parse_error); + CHECK_THROWS_AS(json::parse(std::istringstream(bom.substr(0, 2))), json::parse_error&); CHECK_THROWS_WITH(json::parse(std::istringstream(bom)), "[json.exception.parse_error.101] parse error at 1: syntax error - unexpected end of input; expected '[', '{', or a literal"); } SECTION("1 byte of BOM") { - CHECK_THROWS_AS(json::parse(bom.substr(0, 1)), json::parse_error); + CHECK_THROWS_AS(json::parse(bom.substr(0, 1)), json::parse_error&); CHECK_THROWS_WITH(json::parse(bom), "[json.exception.parse_error.101] parse error at 1: syntax error - unexpected end of input; expected '[', '{', or a literal"); - CHECK_THROWS_AS(json::parse(std::istringstream(bom.substr(0, 1))), json::parse_error); + CHECK_THROWS_AS(json::parse(std::istringstream(bom.substr(0, 1))), json::parse_error&); CHECK_THROWS_WITH(json::parse(std::istringstream(bom)), "[json.exception.parse_error.101] parse error at 1: syntax error - unexpected end of input; expected '[', '{', or a literal"); } @@ -517,8 +517,8 @@ TEST_CASE("deserialization") else { // any variation is an error - CHECK_THROWS_AS(json::parse(s + "null"), json::parse_error); - CHECK_THROWS_AS(json::parse(std::istringstream(s + "null")), json::parse_error); + CHECK_THROWS_AS(json::parse(s + "null"), json::parse_error&); + CHECK_THROWS_AS(json::parse(std::istringstream(s + "null")), json::parse_error&); } } } diff --git a/test/src/unit-element_access1.cpp b/test/src/unit-element_access1.cpp index eb4a92cb..630b1a5e 100644 --- a/test/src/unit-element_access1.cpp +++ b/test/src/unit-element_access1.cpp @@ -63,8 +63,8 @@ TEST_CASE("element access 1") SECTION("access outside bounds") { - CHECK_THROWS_AS(j.at(8), json::out_of_range); - CHECK_THROWS_AS(j_const.at(8), json::out_of_range); + CHECK_THROWS_AS(j.at(8), json::out_of_range&); + CHECK_THROWS_AS(j_const.at(8), json::out_of_range&); CHECK_THROWS_WITH(j.at(8), "[json.exception.out_of_range.401] array index 8 is out of range"); @@ -78,8 +78,8 @@ TEST_CASE("element access 1") { json j_nonarray(json::value_t::null); const json j_nonarray_const(j_nonarray); - CHECK_THROWS_AS(j_nonarray.at(0), json::type_error); - CHECK_THROWS_AS(j_nonarray_const.at(0), json::type_error); + CHECK_THROWS_AS(j_nonarray.at(0), json::type_error&); + CHECK_THROWS_AS(j_nonarray_const.at(0), json::type_error&); CHECK_THROWS_WITH(j_nonarray.at(0), "[json.exception.type_error.304] cannot use at() with null"); CHECK_THROWS_WITH(j_nonarray_const.at(0), "[json.exception.type_error.304] cannot use at() with null"); @@ -89,8 +89,8 @@ TEST_CASE("element access 1") { json j_nonarray(json::value_t::boolean); const json j_nonarray_const(j_nonarray); - CHECK_THROWS_AS(j_nonarray.at(0), json::type_error); - CHECK_THROWS_AS(j_nonarray_const.at(0), json::type_error); + CHECK_THROWS_AS(j_nonarray.at(0), json::type_error&); + CHECK_THROWS_AS(j_nonarray_const.at(0), json::type_error&); CHECK_THROWS_WITH(j_nonarray.at(0), "[json.exception.type_error.304] cannot use at() with boolean"); CHECK_THROWS_WITH(j_nonarray_const.at(0), "[json.exception.type_error.304] cannot use at() with boolean"); @@ -100,8 +100,8 @@ TEST_CASE("element access 1") { json j_nonarray(json::value_t::string); const json j_nonarray_const(j_nonarray); - CHECK_THROWS_AS(j_nonarray.at(0), json::type_error); - CHECK_THROWS_AS(j_nonarray_const.at(0), json::type_error); + CHECK_THROWS_AS(j_nonarray.at(0), json::type_error&); + CHECK_THROWS_AS(j_nonarray_const.at(0), json::type_error&); CHECK_THROWS_WITH(j_nonarray.at(0), "[json.exception.type_error.304] cannot use at() with string"); CHECK_THROWS_WITH(j_nonarray_const.at(0), "[json.exception.type_error.304] cannot use at() with string"); @@ -111,8 +111,8 @@ TEST_CASE("element access 1") { json j_nonarray(json::value_t::object); const json j_nonarray_const(j_nonarray); - CHECK_THROWS_AS(j_nonarray.at(0), json::type_error); - CHECK_THROWS_AS(j_nonarray_const.at(0), json::type_error); + CHECK_THROWS_AS(j_nonarray.at(0), json::type_error&); + CHECK_THROWS_AS(j_nonarray_const.at(0), json::type_error&); CHECK_THROWS_WITH(j_nonarray.at(0), "[json.exception.type_error.304] cannot use at() with object"); CHECK_THROWS_WITH(j_nonarray_const.at(0), "[json.exception.type_error.304] cannot use at() with object"); @@ -122,8 +122,8 @@ TEST_CASE("element access 1") { json j_nonarray(json::value_t::number_integer); const json j_nonarray_const(j_nonarray); - CHECK_THROWS_AS(j_nonarray.at(0), json::type_error); - CHECK_THROWS_AS(j_nonarray_const.at(0), json::type_error); + CHECK_THROWS_AS(j_nonarray.at(0), json::type_error&); + CHECK_THROWS_AS(j_nonarray_const.at(0), json::type_error&); CHECK_THROWS_WITH(j_nonarray.at(0), "[json.exception.type_error.304] cannot use at() with number"); CHECK_THROWS_WITH(j_nonarray_const.at(0), "[json.exception.type_error.304] cannot use at() with number"); @@ -133,8 +133,8 @@ TEST_CASE("element access 1") { json j_nonarray(json::value_t::number_unsigned); const json j_nonarray_const(j_nonarray); - CHECK_THROWS_AS(j_nonarray.at(0), json::type_error); - CHECK_THROWS_AS(j_nonarray_const.at(0), json::type_error); + CHECK_THROWS_AS(j_nonarray.at(0), json::type_error&); + CHECK_THROWS_AS(j_nonarray_const.at(0), json::type_error&); CHECK_THROWS_WITH(j_nonarray.at(0), "[json.exception.type_error.304] cannot use at() with number"); CHECK_THROWS_WITH(j_nonarray_const.at(0), "[json.exception.type_error.304] cannot use at() with number"); @@ -144,8 +144,8 @@ TEST_CASE("element access 1") { json j_nonarray(json::value_t::number_float); const json j_nonarray_const(j_nonarray); - CHECK_THROWS_AS(j_nonarray.at(0), json::type_error); - CHECK_THROWS_AS(j_nonarray_const.at(0), json::type_error); + CHECK_THROWS_AS(j_nonarray.at(0), json::type_error&); + CHECK_THROWS_AS(j_nonarray_const.at(0), json::type_error&); CHECK_THROWS_WITH(j_nonarray.at(0), "[json.exception.type_error.304] cannot use at() with number"); CHECK_THROWS_WITH(j_nonarray_const.at(0), "[json.exception.type_error.304] cannot use at() with number"); @@ -193,7 +193,7 @@ TEST_CASE("element access 1") json j_nonarray(json::value_t::null); const json j_nonarray_const(j_nonarray); CHECK_NOTHROW(j_nonarray[0]); - CHECK_THROWS_AS(j_nonarray_const[0], json::type_error); + CHECK_THROWS_AS(j_nonarray_const[0], json::type_error&); CHECK_THROWS_WITH(j_nonarray_const[0], "[json.exception.type_error.305] cannot use operator[] with null"); } @@ -209,8 +209,8 @@ TEST_CASE("element access 1") { json j_nonarray(json::value_t::boolean); const json j_nonarray_const(j_nonarray); - CHECK_THROWS_AS(j_nonarray[0], json::type_error); - CHECK_THROWS_AS(j_nonarray_const[0], json::type_error); + CHECK_THROWS_AS(j_nonarray[0], json::type_error&); + CHECK_THROWS_AS(j_nonarray_const[0], json::type_error&); CHECK_THROWS_WITH(j_nonarray[0], "[json.exception.type_error.305] cannot use operator[] with boolean"); CHECK_THROWS_WITH(j_nonarray_const[0], "[json.exception.type_error.305] cannot use operator[] with boolean"); } @@ -219,8 +219,8 @@ TEST_CASE("element access 1") { json j_nonarray(json::value_t::string); const json j_nonarray_const(j_nonarray); - CHECK_THROWS_AS(j_nonarray[0], json::type_error); - CHECK_THROWS_AS(j_nonarray_const[0], json::type_error); + CHECK_THROWS_AS(j_nonarray[0], json::type_error&); + CHECK_THROWS_AS(j_nonarray_const[0], json::type_error&); CHECK_THROWS_WITH(j_nonarray[0], "[json.exception.type_error.305] cannot use operator[] with string"); CHECK_THROWS_WITH(j_nonarray_const[0], "[json.exception.type_error.305] cannot use operator[] with string"); } @@ -229,8 +229,8 @@ TEST_CASE("element access 1") { json j_nonarray(json::value_t::object); const json j_nonarray_const(j_nonarray); - CHECK_THROWS_AS(j_nonarray[0], json::type_error); - CHECK_THROWS_AS(j_nonarray_const[0], json::type_error); + CHECK_THROWS_AS(j_nonarray[0], json::type_error&); + CHECK_THROWS_AS(j_nonarray_const[0], json::type_error&); CHECK_THROWS_WITH(j_nonarray[0], "[json.exception.type_error.305] cannot use operator[] with object"); CHECK_THROWS_WITH(j_nonarray_const[0], "[json.exception.type_error.305] cannot use operator[] with object"); } @@ -239,8 +239,8 @@ TEST_CASE("element access 1") { json j_nonarray(json::value_t::number_integer); const json j_nonarray_const(j_nonarray); - CHECK_THROWS_AS(j_nonarray[0], json::type_error); - CHECK_THROWS_AS(j_nonarray_const[0], json::type_error); + CHECK_THROWS_AS(j_nonarray[0], json::type_error&); + CHECK_THROWS_AS(j_nonarray_const[0], json::type_error&); CHECK_THROWS_WITH(j_nonarray[0], "[json.exception.type_error.305] cannot use operator[] with number"); CHECK_THROWS_WITH(j_nonarray_const[0], "[json.exception.type_error.305] cannot use operator[] with number"); } @@ -249,8 +249,8 @@ TEST_CASE("element access 1") { json j_nonarray(json::value_t::number_unsigned); const json j_nonarray_const(j_nonarray); - CHECK_THROWS_AS(j_nonarray[0], json::type_error); - CHECK_THROWS_AS(j_nonarray_const[0], json::type_error); + CHECK_THROWS_AS(j_nonarray[0], json::type_error&); + CHECK_THROWS_AS(j_nonarray_const[0], json::type_error&); CHECK_THROWS_WITH(j_nonarray[0], "[json.exception.type_error.305] cannot use operator[] with number"); CHECK_THROWS_WITH(j_nonarray_const[0], "[json.exception.type_error.305] cannot use operator[] with number"); } @@ -259,8 +259,8 @@ TEST_CASE("element access 1") { json j_nonarray(json::value_t::number_float); const json j_nonarray_const(j_nonarray); - CHECK_THROWS_AS(j_nonarray[0], json::type_error); - CHECK_THROWS_AS(j_nonarray_const[0], json::type_error); + CHECK_THROWS_AS(j_nonarray[0], json::type_error&); + CHECK_THROWS_AS(j_nonarray_const[0], json::type_error&); CHECK_THROWS_WITH(j_nonarray[0], "[json.exception.type_error.305] cannot use operator[] with number"); CHECK_THROWS_WITH(j_nonarray_const[0], "[json.exception.type_error.305] cannot use operator[] with number"); } @@ -313,7 +313,7 @@ TEST_CASE("element access 1") } { json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; - CHECK_THROWS_AS(jarray.erase(8), json::out_of_range); + CHECK_THROWS_AS(jarray.erase(8), json::out_of_range&); CHECK_THROWS_WITH(jarray.erase(8), "[json.exception.out_of_range.401] array index 8 is out of range"); } @@ -408,10 +408,10 @@ TEST_CASE("element access 1") { json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; json jarray2 = {"foo", "bar"}; - CHECK_THROWS_AS(jarray.erase(jarray2.begin()), json::invalid_iterator); - CHECK_THROWS_AS(jarray.erase(jarray.begin(), jarray2.end()), json::invalid_iterator); - CHECK_THROWS_AS(jarray.erase(jarray2.begin(), jarray.end()), json::invalid_iterator); - CHECK_THROWS_AS(jarray.erase(jarray2.begin(), jarray2.end()), json::invalid_iterator); + CHECK_THROWS_AS(jarray.erase(jarray2.begin()), json::invalid_iterator&); + CHECK_THROWS_AS(jarray.erase(jarray.begin(), jarray2.end()), json::invalid_iterator&); + CHECK_THROWS_AS(jarray.erase(jarray2.begin(), jarray.end()), json::invalid_iterator&); + CHECK_THROWS_AS(jarray.erase(jarray2.begin(), jarray2.end()), json::invalid_iterator&); CHECK_THROWS_WITH(jarray.erase(jarray2.begin()), "[json.exception.invalid_iterator.202] iterator does not fit current value"); @@ -425,10 +425,10 @@ TEST_CASE("element access 1") { json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; json jarray2 = {"foo", "bar"}; - CHECK_THROWS_AS(jarray.erase(jarray2.cbegin()), json::invalid_iterator); - CHECK_THROWS_AS(jarray.erase(jarray.cbegin(), jarray2.cend()), json::invalid_iterator); - CHECK_THROWS_AS(jarray.erase(jarray2.cbegin(), jarray.cend()), json::invalid_iterator); - CHECK_THROWS_AS(jarray.erase(jarray2.cbegin(), jarray2.cend()), json::invalid_iterator); + CHECK_THROWS_AS(jarray.erase(jarray2.cbegin()), json::invalid_iterator&); + CHECK_THROWS_AS(jarray.erase(jarray.cbegin(), jarray2.cend()), json::invalid_iterator&); + CHECK_THROWS_AS(jarray.erase(jarray2.cbegin(), jarray.cend()), json::invalid_iterator&); + CHECK_THROWS_AS(jarray.erase(jarray2.cbegin(), jarray2.cend()), json::invalid_iterator&); CHECK_THROWS_WITH(jarray.erase(jarray2.cbegin()), "[json.exception.invalid_iterator.202] iterator does not fit current value"); @@ -447,7 +447,7 @@ TEST_CASE("element access 1") SECTION("null") { json j_nonobject(json::value_t::null); - CHECK_THROWS_AS(j_nonobject.erase(0), json::type_error); + CHECK_THROWS_AS(j_nonobject.erase(0), json::type_error&); CHECK_THROWS_WITH(j_nonobject.erase(0), "[json.exception.type_error.307] cannot use erase() with null"); } @@ -455,7 +455,7 @@ TEST_CASE("element access 1") SECTION("boolean") { json j_nonobject(json::value_t::boolean); - CHECK_THROWS_AS(j_nonobject.erase(0), json::type_error); + CHECK_THROWS_AS(j_nonobject.erase(0), json::type_error&); CHECK_THROWS_WITH(j_nonobject.erase(0), "[json.exception.type_error.307] cannot use erase() with boolean"); } @@ -463,7 +463,7 @@ TEST_CASE("element access 1") SECTION("string") { json j_nonobject(json::value_t::string); - CHECK_THROWS_AS(j_nonobject.erase(0), json::type_error); + CHECK_THROWS_AS(j_nonobject.erase(0), json::type_error&); CHECK_THROWS_WITH(j_nonobject.erase(0), "[json.exception.type_error.307] cannot use erase() with string"); } @@ -471,7 +471,7 @@ TEST_CASE("element access 1") SECTION("object") { json j_nonobject(json::value_t::object); - CHECK_THROWS_AS(j_nonobject.erase(0), json::type_error); + CHECK_THROWS_AS(j_nonobject.erase(0), json::type_error&); CHECK_THROWS_WITH(j_nonobject.erase(0), "[json.exception.type_error.307] cannot use erase() with object"); } @@ -479,7 +479,7 @@ TEST_CASE("element access 1") SECTION("number (integer)") { json j_nonobject(json::value_t::number_integer); - CHECK_THROWS_AS(j_nonobject.erase(0), json::type_error); + CHECK_THROWS_AS(j_nonobject.erase(0), json::type_error&); CHECK_THROWS_WITH(j_nonobject.erase(0), "[json.exception.type_error.307] cannot use erase() with number"); } @@ -487,7 +487,7 @@ TEST_CASE("element access 1") SECTION("number (unsigned)") { json j_nonobject(json::value_t::number_unsigned); - CHECK_THROWS_AS(j_nonobject.erase(0), json::type_error); + CHECK_THROWS_AS(j_nonobject.erase(0), json::type_error&); CHECK_THROWS_WITH(j_nonobject.erase(0), "[json.exception.type_error.307] cannot use erase() with number"); } @@ -495,7 +495,7 @@ TEST_CASE("element access 1") SECTION("number (floating-point)") { json j_nonobject(json::value_t::number_float); - CHECK_THROWS_AS(j_nonobject.erase(0), json::type_error); + CHECK_THROWS_AS(j_nonobject.erase(0), json::type_error&); CHECK_THROWS_WITH(j_nonobject.erase(0), "[json.exception.type_error.307] cannot use erase() with number"); } @@ -511,15 +511,15 @@ TEST_CASE("element access 1") { { json j; - CHECK_THROWS_AS(j.front(), json::invalid_iterator); - CHECK_THROWS_AS(j.back(), json::invalid_iterator); + CHECK_THROWS_AS(j.front(), json::invalid_iterator&); + CHECK_THROWS_AS(j.back(), json::invalid_iterator&); CHECK_THROWS_WITH(j.front(), "[json.exception.invalid_iterator.214] cannot get value"); CHECK_THROWS_WITH(j.back(), "[json.exception.invalid_iterator.214] cannot get value"); } { const json j{}; - CHECK_THROWS_AS(j.front(), json::invalid_iterator); - CHECK_THROWS_AS(j.back(), json::invalid_iterator); + CHECK_THROWS_AS(j.front(), json::invalid_iterator&); + CHECK_THROWS_AS(j.back(), json::invalid_iterator&); CHECK_THROWS_WITH(j.front(), "[json.exception.invalid_iterator.214] cannot get value"); CHECK_THROWS_WITH(j.back(), "[json.exception.invalid_iterator.214] cannot get value"); } @@ -602,13 +602,13 @@ TEST_CASE("element access 1") { { json j; - CHECK_THROWS_AS(j.erase(j.begin()), json::type_error); + CHECK_THROWS_AS(j.erase(j.begin()), json::type_error&); CHECK_THROWS_WITH(j.erase(j.begin()), "[json.exception.type_error.307] cannot use erase() with null"); } { json j; - CHECK_THROWS_AS(j.erase(j.cbegin()), json::type_error); + CHECK_THROWS_AS(j.erase(j.cbegin()), json::type_error&); CHECK_THROWS_WITH(j.erase(j.begin()), "[json.exception.type_error.307] cannot use erase() with null"); } @@ -701,13 +701,13 @@ TEST_CASE("element access 1") { { json j = "foo"; - CHECK_THROWS_AS(j.erase(j.end()), json::invalid_iterator); + CHECK_THROWS_AS(j.erase(j.end()), json::invalid_iterator&); CHECK_THROWS_WITH(j.erase(j.end()), "[json.exception.invalid_iterator.205] iterator out of range"); } { json j = "bar"; - CHECK_THROWS_AS(j.erase(j.cend()), json::invalid_iterator); + CHECK_THROWS_AS(j.erase(j.cend()), json::invalid_iterator&); CHECK_THROWS_WITH(j.erase(j.cend()), "[json.exception.invalid_iterator.205] iterator out of range"); } @@ -717,13 +717,13 @@ TEST_CASE("element access 1") { { json j = false; - CHECK_THROWS_AS(j.erase(j.end()), json::invalid_iterator); + CHECK_THROWS_AS(j.erase(j.end()), json::invalid_iterator&); CHECK_THROWS_WITH(j.erase(j.end()), "[json.exception.invalid_iterator.205] iterator out of range"); } { json j = true; - CHECK_THROWS_AS(j.erase(j.cend()), json::invalid_iterator); + CHECK_THROWS_AS(j.erase(j.cend()), json::invalid_iterator&); CHECK_THROWS_WITH(j.erase(j.cend()), "[json.exception.invalid_iterator.205] iterator out of range"); } @@ -733,13 +733,13 @@ TEST_CASE("element access 1") { { json j = 17; - CHECK_THROWS_AS(j.erase(j.end()), json::invalid_iterator); + CHECK_THROWS_AS(j.erase(j.end()), json::invalid_iterator&); CHECK_THROWS_WITH(j.erase(j.end()), "[json.exception.invalid_iterator.205] iterator out of range"); } { json j = 17; - CHECK_THROWS_AS(j.erase(j.cend()), json::invalid_iterator); + CHECK_THROWS_AS(j.erase(j.cend()), json::invalid_iterator&); CHECK_THROWS_WITH(j.erase(j.cend()), "[json.exception.invalid_iterator.205] iterator out of range"); } @@ -749,13 +749,13 @@ TEST_CASE("element access 1") { { json j = 17u; - CHECK_THROWS_AS(j.erase(j.end()), json::invalid_iterator); + CHECK_THROWS_AS(j.erase(j.end()), json::invalid_iterator&); CHECK_THROWS_WITH(j.erase(j.end()), "[json.exception.invalid_iterator.205] iterator out of range"); } { json j = 17u; - CHECK_THROWS_AS(j.erase(j.cend()), json::invalid_iterator); + CHECK_THROWS_AS(j.erase(j.cend()), json::invalid_iterator&); CHECK_THROWS_WITH(j.erase(j.cend()), "[json.exception.invalid_iterator.205] iterator out of range"); } @@ -765,13 +765,13 @@ TEST_CASE("element access 1") { { json j = 23.42; - CHECK_THROWS_AS(j.erase(j.end()), json::invalid_iterator); + CHECK_THROWS_AS(j.erase(j.end()), json::invalid_iterator&); CHECK_THROWS_WITH(j.erase(j.end()), "[json.exception.invalid_iterator.205] iterator out of range"); } { json j = 23.42; - CHECK_THROWS_AS(j.erase(j.cend()), json::invalid_iterator); + CHECK_THROWS_AS(j.erase(j.cend()), json::invalid_iterator&); CHECK_THROWS_WITH(j.erase(j.cend()), "[json.exception.invalid_iterator.205] iterator out of range"); } @@ -784,13 +784,13 @@ TEST_CASE("element access 1") { { json j; - CHECK_THROWS_AS(j.erase(j.begin(), j.end()), json::type_error); + CHECK_THROWS_AS(j.erase(j.begin(), j.end()), json::type_error&); CHECK_THROWS_WITH(j.erase(j.begin(), j.end()), "[json.exception.type_error.307] cannot use erase() with null"); } { json j; - CHECK_THROWS_AS(j.erase(j.cbegin(), j.cend()), json::type_error); + CHECK_THROWS_AS(j.erase(j.cbegin(), j.cend()), json::type_error&); CHECK_THROWS_WITH(j.erase(j.cbegin(), j.cend()), "[json.exception.type_error.307] cannot use erase() with null"); } @@ -883,15 +883,15 @@ TEST_CASE("element access 1") { { json j = "foo"; - CHECK_THROWS_AS(j.erase(j.end(), j.end()), json::invalid_iterator); - CHECK_THROWS_AS(j.erase(j.begin(), j.begin()), json::invalid_iterator); + CHECK_THROWS_AS(j.erase(j.end(), j.end()), json::invalid_iterator&); + CHECK_THROWS_AS(j.erase(j.begin(), j.begin()), json::invalid_iterator&); CHECK_THROWS_WITH(j.erase(j.end(), j.end()), "[json.exception.invalid_iterator.204] iterators out of range"); CHECK_THROWS_WITH(j.erase(j.begin(), j.begin()), "[json.exception.invalid_iterator.204] iterators out of range"); } { json j = "bar"; - CHECK_THROWS_AS(j.erase(j.cend(), j.cend()), json::invalid_iterator); - CHECK_THROWS_AS(j.erase(j.cbegin(), j.cbegin()), json::invalid_iterator); + CHECK_THROWS_AS(j.erase(j.cend(), j.cend()), json::invalid_iterator&); + CHECK_THROWS_AS(j.erase(j.cbegin(), j.cbegin()), json::invalid_iterator&); CHECK_THROWS_WITH(j.erase(j.cend(), j.cend()), "[json.exception.invalid_iterator.204] iterators out of range"); CHECK_THROWS_WITH(j.erase(j.cbegin(), j.cbegin()), "[json.exception.invalid_iterator.204] iterators out of range"); } @@ -901,15 +901,15 @@ TEST_CASE("element access 1") { { json j = false; - CHECK_THROWS_AS(j.erase(j.end(), j.end()), json::invalid_iterator); - CHECK_THROWS_AS(j.erase(j.begin(), j.begin()), json::invalid_iterator); + CHECK_THROWS_AS(j.erase(j.end(), j.end()), json::invalid_iterator&); + CHECK_THROWS_AS(j.erase(j.begin(), j.begin()), json::invalid_iterator&); CHECK_THROWS_WITH(j.erase(j.end(), j.end()), "[json.exception.invalid_iterator.204] iterators out of range"); CHECK_THROWS_WITH(j.erase(j.begin(), j.begin()), "[json.exception.invalid_iterator.204] iterators out of range"); } { json j = true; - CHECK_THROWS_AS(j.erase(j.cend(), j.cend()), json::invalid_iterator); - CHECK_THROWS_AS(j.erase(j.cbegin(), j.cbegin()), json::invalid_iterator); + CHECK_THROWS_AS(j.erase(j.cend(), j.cend()), json::invalid_iterator&); + CHECK_THROWS_AS(j.erase(j.cbegin(), j.cbegin()), json::invalid_iterator&); CHECK_THROWS_WITH(j.erase(j.cend(), j.cend()), "[json.exception.invalid_iterator.204] iterators out of range"); CHECK_THROWS_WITH(j.erase(j.cbegin(), j.cbegin()), "[json.exception.invalid_iterator.204] iterators out of range"); } @@ -919,15 +919,15 @@ TEST_CASE("element access 1") { { json j = 17; - CHECK_THROWS_AS(j.erase(j.end(), j.end()), json::invalid_iterator); - CHECK_THROWS_AS(j.erase(j.begin(), j.begin()), json::invalid_iterator); + CHECK_THROWS_AS(j.erase(j.end(), j.end()), json::invalid_iterator&); + CHECK_THROWS_AS(j.erase(j.begin(), j.begin()), json::invalid_iterator&); CHECK_THROWS_WITH(j.erase(j.end(), j.end()), "[json.exception.invalid_iterator.204] iterators out of range"); CHECK_THROWS_WITH(j.erase(j.begin(), j.begin()), "[json.exception.invalid_iterator.204] iterators out of range"); } { json j = 17; - CHECK_THROWS_AS(j.erase(j.cend(), j.cend()), json::invalid_iterator); - CHECK_THROWS_AS(j.erase(j.cbegin(), j.cbegin()), json::invalid_iterator); + CHECK_THROWS_AS(j.erase(j.cend(), j.cend()), json::invalid_iterator&); + CHECK_THROWS_AS(j.erase(j.cbegin(), j.cbegin()), json::invalid_iterator&); CHECK_THROWS_WITH(j.erase(j.cend(), j.cend()), "[json.exception.invalid_iterator.204] iterators out of range"); CHECK_THROWS_WITH(j.erase(j.cbegin(), j.cbegin()), "[json.exception.invalid_iterator.204] iterators out of range"); } @@ -937,15 +937,15 @@ TEST_CASE("element access 1") { { json j = 17u; - CHECK_THROWS_AS(j.erase(j.end(), j.end()), json::invalid_iterator); - CHECK_THROWS_AS(j.erase(j.begin(), j.begin()), json::invalid_iterator); + CHECK_THROWS_AS(j.erase(j.end(), j.end()), json::invalid_iterator&); + CHECK_THROWS_AS(j.erase(j.begin(), j.begin()), json::invalid_iterator&); CHECK_THROWS_WITH(j.erase(j.end(), j.end()), "[json.exception.invalid_iterator.204] iterators out of range"); CHECK_THROWS_WITH(j.erase(j.begin(), j.begin()), "[json.exception.invalid_iterator.204] iterators out of range"); } { json j = 17u; - CHECK_THROWS_AS(j.erase(j.cend(), j.cend()), json::invalid_iterator); - CHECK_THROWS_AS(j.erase(j.cbegin(), j.cbegin()), json::invalid_iterator); + CHECK_THROWS_AS(j.erase(j.cend(), j.cend()), json::invalid_iterator&); + CHECK_THROWS_AS(j.erase(j.cbegin(), j.cbegin()), json::invalid_iterator&); CHECK_THROWS_WITH(j.erase(j.cend(), j.cend()), "[json.exception.invalid_iterator.204] iterators out of range"); CHECK_THROWS_WITH(j.erase(j.cbegin(), j.cbegin()), "[json.exception.invalid_iterator.204] iterators out of range"); } @@ -955,15 +955,15 @@ TEST_CASE("element access 1") { { json j = 23.42; - CHECK_THROWS_AS(j.erase(j.end(), j.end()), json::invalid_iterator); - CHECK_THROWS_AS(j.erase(j.begin(), j.begin()), json::invalid_iterator); + CHECK_THROWS_AS(j.erase(j.end(), j.end()), json::invalid_iterator&); + CHECK_THROWS_AS(j.erase(j.begin(), j.begin()), json::invalid_iterator&); CHECK_THROWS_WITH(j.erase(j.end(), j.end()), "[json.exception.invalid_iterator.204] iterators out of range"); CHECK_THROWS_WITH(j.erase(j.begin(), j.begin()), "[json.exception.invalid_iterator.204] iterators out of range"); } { json j = 23.42; - CHECK_THROWS_AS(j.erase(j.cend(), j.cend()), json::invalid_iterator); - CHECK_THROWS_AS(j.erase(j.cbegin(), j.cbegin()), json::invalid_iterator); + CHECK_THROWS_AS(j.erase(j.cend(), j.cend()), json::invalid_iterator&); + CHECK_THROWS_AS(j.erase(j.cbegin(), j.cbegin()), json::invalid_iterator&); CHECK_THROWS_WITH(j.erase(j.cend(), j.cend()), "[json.exception.invalid_iterator.204] iterators out of range"); CHECK_THROWS_WITH(j.erase(j.cbegin(), j.cbegin()), "[json.exception.invalid_iterator.204] iterators out of range"); } diff --git a/test/src/unit-element_access2.cpp b/test/src/unit-element_access2.cpp index ec03507e..5950349b 100644 --- a/test/src/unit-element_access2.cpp +++ b/test/src/unit-element_access2.cpp @@ -63,8 +63,8 @@ TEST_CASE("element access 2") SECTION("access outside bounds") { - CHECK_THROWS_AS(j.at("foo"), json::out_of_range); - CHECK_THROWS_AS(j_const.at("foo"), json::out_of_range); + CHECK_THROWS_AS(j.at("foo"), json::out_of_range&); + CHECK_THROWS_AS(j_const.at("foo"), json::out_of_range&); CHECK_THROWS_WITH(j.at("foo"), "[json.exception.out_of_range.403] key 'foo' not found"); CHECK_THROWS_WITH(j_const.at("foo"), @@ -77,8 +77,8 @@ TEST_CASE("element access 2") { json j_nonobject(json::value_t::null); const json j_nonobject_const(j_nonobject); - CHECK_THROWS_AS(j_nonobject.at("foo"), json::type_error); - CHECK_THROWS_AS(j_nonobject_const.at("foo"), json::type_error); + CHECK_THROWS_AS(j_nonobject.at("foo"), json::type_error&); + CHECK_THROWS_AS(j_nonobject_const.at("foo"), json::type_error&); CHECK_THROWS_WITH(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with null"); CHECK_THROWS_WITH(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with null"); } @@ -87,8 +87,8 @@ TEST_CASE("element access 2") { json j_nonobject(json::value_t::boolean); const json j_nonobject_const(j_nonobject); - CHECK_THROWS_AS(j_nonobject.at("foo"), json::type_error); - CHECK_THROWS_AS(j_nonobject_const.at("foo"), json::type_error); + CHECK_THROWS_AS(j_nonobject.at("foo"), json::type_error&); + CHECK_THROWS_AS(j_nonobject_const.at("foo"), json::type_error&); CHECK_THROWS_WITH(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with boolean"); CHECK_THROWS_WITH(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with boolean"); } @@ -97,8 +97,8 @@ TEST_CASE("element access 2") { json j_nonobject(json::value_t::string); const json j_nonobject_const(j_nonobject); - CHECK_THROWS_AS(j_nonobject.at("foo"), json::type_error); - CHECK_THROWS_AS(j_nonobject_const.at("foo"), json::type_error); + CHECK_THROWS_AS(j_nonobject.at("foo"), json::type_error&); + CHECK_THROWS_AS(j_nonobject_const.at("foo"), json::type_error&); CHECK_THROWS_WITH(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with string"); CHECK_THROWS_WITH(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with string"); } @@ -107,8 +107,8 @@ TEST_CASE("element access 2") { json j_nonobject(json::value_t::array); const json j_nonobject_const(j_nonobject); - CHECK_THROWS_AS(j_nonobject.at("foo"), json::type_error); - CHECK_THROWS_AS(j_nonobject_const.at("foo"), json::type_error); + CHECK_THROWS_AS(j_nonobject.at("foo"), json::type_error&); + CHECK_THROWS_AS(j_nonobject_const.at("foo"), json::type_error&); CHECK_THROWS_WITH(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with array"); CHECK_THROWS_WITH(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with array"); } @@ -117,8 +117,8 @@ TEST_CASE("element access 2") { json j_nonobject(json::value_t::number_integer); const json j_nonobject_const(j_nonobject); - CHECK_THROWS_AS(j_nonobject.at("foo"), json::type_error); - CHECK_THROWS_AS(j_nonobject_const.at("foo"), json::type_error); + CHECK_THROWS_AS(j_nonobject.at("foo"), json::type_error&); + CHECK_THROWS_AS(j_nonobject_const.at("foo"), json::type_error&); CHECK_THROWS_WITH(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with number"); CHECK_THROWS_WITH(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with number"); } @@ -127,8 +127,8 @@ TEST_CASE("element access 2") { json j_nonobject(json::value_t::number_unsigned); const json j_nonobject_const(j_nonobject); - CHECK_THROWS_AS(j_nonobject.at("foo"), json::type_error); - CHECK_THROWS_AS(j_nonobject_const.at("foo"), json::type_error); + CHECK_THROWS_AS(j_nonobject.at("foo"), json::type_error&); + CHECK_THROWS_AS(j_nonobject_const.at("foo"), json::type_error&); CHECK_THROWS_WITH(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with number"); CHECK_THROWS_WITH(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with number"); } @@ -137,8 +137,8 @@ TEST_CASE("element access 2") { json j_nonobject(json::value_t::number_float); const json j_nonobject_const(j_nonobject); - CHECK_THROWS_AS(j_nonobject.at("foo"), json::type_error); - CHECK_THROWS_AS(j_nonobject_const.at("foo"), json::type_error); + CHECK_THROWS_AS(j_nonobject.at("foo"), json::type_error&); + CHECK_THROWS_AS(j_nonobject_const.at("foo"), json::type_error&); CHECK_THROWS_WITH(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with number"); CHECK_THROWS_WITH(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with number"); } @@ -202,8 +202,8 @@ TEST_CASE("element access 2") { json j_nonobject(json::value_t::null); const json j_nonobject_const(j_nonobject); - CHECK_THROWS_AS(j_nonobject.value("foo", 1), json::type_error); - CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), json::type_error); + CHECK_THROWS_AS(j_nonobject.value("foo", 1), json::type_error&); + CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), json::type_error&); CHECK_THROWS_WITH(j_nonobject.value("foo", 1), "[json.exception.type_error.306] cannot use value() with null"); CHECK_THROWS_WITH(j_nonobject_const.value("foo", 1), @@ -214,8 +214,8 @@ TEST_CASE("element access 2") { json j_nonobject(json::value_t::boolean); const json j_nonobject_const(j_nonobject); - CHECK_THROWS_AS(j_nonobject.value("foo", 1), json::type_error); - CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), json::type_error); + CHECK_THROWS_AS(j_nonobject.value("foo", 1), json::type_error&); + CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), json::type_error&); CHECK_THROWS_WITH(j_nonobject.value("foo", 1), "[json.exception.type_error.306] cannot use value() with boolean"); CHECK_THROWS_WITH(j_nonobject_const.value("foo", 1), @@ -226,8 +226,8 @@ TEST_CASE("element access 2") { json j_nonobject(json::value_t::string); const json j_nonobject_const(j_nonobject); - CHECK_THROWS_AS(j_nonobject.value("foo", 1), json::type_error); - CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), json::type_error); + CHECK_THROWS_AS(j_nonobject.value("foo", 1), json::type_error&); + CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), json::type_error&); CHECK_THROWS_WITH(j_nonobject.value("foo", 1), "[json.exception.type_error.306] cannot use value() with string"); CHECK_THROWS_WITH(j_nonobject_const.value("foo", 1), @@ -238,8 +238,8 @@ TEST_CASE("element access 2") { json j_nonobject(json::value_t::array); const json j_nonobject_const(j_nonobject); - CHECK_THROWS_AS(j_nonobject.value("foo", 1), json::type_error); - CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), json::type_error); + CHECK_THROWS_AS(j_nonobject.value("foo", 1), json::type_error&); + CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), json::type_error&); CHECK_THROWS_WITH(j_nonobject.value("foo", 1), "[json.exception.type_error.306] cannot use value() with array"); CHECK_THROWS_WITH(j_nonobject_const.value("foo", 1), @@ -250,8 +250,8 @@ TEST_CASE("element access 2") { json j_nonobject(json::value_t::number_integer); const json j_nonobject_const(j_nonobject); - CHECK_THROWS_AS(j_nonobject.value("foo", 1), json::type_error); - CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), json::type_error); + CHECK_THROWS_AS(j_nonobject.value("foo", 1), json::type_error&); + CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), json::type_error&); CHECK_THROWS_WITH(j_nonobject.value("foo", 1), "[json.exception.type_error.306] cannot use value() with number"); CHECK_THROWS_WITH(j_nonobject_const.value("foo", 1), @@ -262,8 +262,8 @@ TEST_CASE("element access 2") { json j_nonobject(json::value_t::number_unsigned); const json j_nonobject_const(j_nonobject); - CHECK_THROWS_AS(j_nonobject.value("foo", 1), json::type_error); - CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), json::type_error); + CHECK_THROWS_AS(j_nonobject.value("foo", 1), json::type_error&); + CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), json::type_error&); CHECK_THROWS_WITH(j_nonobject.value("foo", 1), "[json.exception.type_error.306] cannot use value() with number"); CHECK_THROWS_WITH(j_nonobject_const.value("foo", 1), @@ -274,8 +274,8 @@ TEST_CASE("element access 2") { json j_nonobject(json::value_t::number_float); const json j_nonobject_const(j_nonobject); - CHECK_THROWS_AS(j_nonobject.value("foo", 1), json::type_error); - CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), json::type_error); + CHECK_THROWS_AS(j_nonobject.value("foo", 1), json::type_error&); + CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), json::type_error&); CHECK_THROWS_WITH(j_nonobject.value("foo", 1), "[json.exception.type_error.306] cannot use value() with number"); CHECK_THROWS_WITH(j_nonobject_const.value("foo", 1), @@ -320,8 +320,8 @@ TEST_CASE("element access 2") { json j_nonobject(json::value_t::null); const json j_nonobject_const(j_nonobject); - CHECK_THROWS_AS(j_nonobject.value("/foo"_json_pointer, 1), json::type_error); - CHECK_THROWS_AS(j_nonobject_const.value("/foo"_json_pointer, 1), json::type_error); + CHECK_THROWS_AS(j_nonobject.value("/foo"_json_pointer, 1), json::type_error&); + CHECK_THROWS_AS(j_nonobject_const.value("/foo"_json_pointer, 1), json::type_error&); CHECK_THROWS_WITH(j_nonobject.value("/foo"_json_pointer, 1), "[json.exception.type_error.306] cannot use value() with null"); CHECK_THROWS_WITH(j_nonobject_const.value("/foo"_json_pointer, 1), @@ -332,8 +332,8 @@ TEST_CASE("element access 2") { json j_nonobject(json::value_t::boolean); const json j_nonobject_const(j_nonobject); - CHECK_THROWS_AS(j_nonobject.value("/foo"_json_pointer, 1), json::type_error); - CHECK_THROWS_AS(j_nonobject_const.value("/foo"_json_pointer, 1), json::type_error); + CHECK_THROWS_AS(j_nonobject.value("/foo"_json_pointer, 1), json::type_error&); + CHECK_THROWS_AS(j_nonobject_const.value("/foo"_json_pointer, 1), json::type_error&); CHECK_THROWS_WITH(j_nonobject.value("/foo"_json_pointer, 1), "[json.exception.type_error.306] cannot use value() with boolean"); CHECK_THROWS_WITH(j_nonobject_const.value("/foo"_json_pointer, 1), @@ -344,8 +344,8 @@ TEST_CASE("element access 2") { json j_nonobject(json::value_t::string); const json j_nonobject_const(j_nonobject); - CHECK_THROWS_AS(j_nonobject.value("/foo"_json_pointer, 1), json::type_error); - CHECK_THROWS_AS(j_nonobject_const.value("/foo"_json_pointer, 1), json::type_error); + CHECK_THROWS_AS(j_nonobject.value("/foo"_json_pointer, 1), json::type_error&); + CHECK_THROWS_AS(j_nonobject_const.value("/foo"_json_pointer, 1), json::type_error&); CHECK_THROWS_WITH(j_nonobject.value("/foo"_json_pointer, 1), "[json.exception.type_error.306] cannot use value() with string"); CHECK_THROWS_WITH(j_nonobject_const.value("/foo"_json_pointer, 1), @@ -356,8 +356,8 @@ TEST_CASE("element access 2") { json j_nonobject(json::value_t::array); const json j_nonobject_const(j_nonobject); - CHECK_THROWS_AS(j_nonobject.value("/foo"_json_pointer, 1), json::type_error); - CHECK_THROWS_AS(j_nonobject_const.value("/foo"_json_pointer, 1), json::type_error); + CHECK_THROWS_AS(j_nonobject.value("/foo"_json_pointer, 1), json::type_error&); + CHECK_THROWS_AS(j_nonobject_const.value("/foo"_json_pointer, 1), json::type_error&); CHECK_THROWS_WITH(j_nonobject.value("/foo"_json_pointer, 1), "[json.exception.type_error.306] cannot use value() with array"); CHECK_THROWS_WITH(j_nonobject_const.value("/foo"_json_pointer, 1), @@ -368,8 +368,8 @@ TEST_CASE("element access 2") { json j_nonobject(json::value_t::number_integer); const json j_nonobject_const(j_nonobject); - CHECK_THROWS_AS(j_nonobject.value("/foo"_json_pointer, 1), json::type_error); - CHECK_THROWS_AS(j_nonobject_const.value("/foo"_json_pointer, 1), json::type_error); + CHECK_THROWS_AS(j_nonobject.value("/foo"_json_pointer, 1), json::type_error&); + CHECK_THROWS_AS(j_nonobject_const.value("/foo"_json_pointer, 1), json::type_error&); CHECK_THROWS_WITH(j_nonobject.value("/foo"_json_pointer, 1), "[json.exception.type_error.306] cannot use value() with number"); CHECK_THROWS_WITH(j_nonobject_const.value("/foo"_json_pointer, 1), @@ -380,8 +380,8 @@ TEST_CASE("element access 2") { json j_nonobject(json::value_t::number_unsigned); const json j_nonobject_const(j_nonobject); - CHECK_THROWS_AS(j_nonobject.value("/foo"_json_pointer, 1), json::type_error); - CHECK_THROWS_AS(j_nonobject_const.value("/foo"_json_pointer, 1), json::type_error); + CHECK_THROWS_AS(j_nonobject.value("/foo"_json_pointer, 1), json::type_error&); + CHECK_THROWS_AS(j_nonobject_const.value("/foo"_json_pointer, 1), json::type_error&); CHECK_THROWS_WITH(j_nonobject.value("/foo"_json_pointer, 1), "[json.exception.type_error.306] cannot use value() with number"); CHECK_THROWS_WITH(j_nonobject_const.value("/foo"_json_pointer, 1), @@ -392,8 +392,8 @@ TEST_CASE("element access 2") { json j_nonobject(json::value_t::number_float); const json j_nonobject_const(j_nonobject); - CHECK_THROWS_AS(j_nonobject.value("/foo"_json_pointer, 1), json::type_error); - CHECK_THROWS_AS(j_nonobject_const.value("/foo"_json_pointer, 1), json::type_error); + CHECK_THROWS_AS(j_nonobject.value("/foo"_json_pointer, 1), json::type_error&); + CHECK_THROWS_AS(j_nonobject_const.value("/foo"_json_pointer, 1), json::type_error&); CHECK_THROWS_WITH(j_nonobject.value("/foo"_json_pointer, 1), "[json.exception.type_error.306] cannot use value() with number"); CHECK_THROWS_WITH(j_nonobject_const.value("/foo"_json_pointer, 1), @@ -472,8 +472,8 @@ TEST_CASE("element access 2") const json j_const_nonobject(j_nonobject); CHECK_NOTHROW(j_nonobject["foo"]); CHECK_NOTHROW(j_nonobject2[json::object_t::key_type("foo")]); - CHECK_THROWS_AS(j_const_nonobject["foo"], json::type_error); - CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], json::type_error); + CHECK_THROWS_AS(j_const_nonobject["foo"], json::type_error&); + CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], json::type_error&); CHECK_THROWS_WITH(j_const_nonobject["foo"], "[json.exception.type_error.305] cannot use operator[] with null"); CHECK_THROWS_WITH(j_const_nonobject[json::object_t::key_type("foo")], "[json.exception.type_error.305] cannot use operator[] with null"); @@ -483,10 +483,10 @@ TEST_CASE("element access 2") { json j_nonobject(json::value_t::boolean); const json j_const_nonobject(j_nonobject); - CHECK_THROWS_AS(j_nonobject["foo"], json::type_error); - CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], json::type_error); - CHECK_THROWS_AS(j_const_nonobject["foo"], json::type_error); - CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], json::type_error); + CHECK_THROWS_AS(j_nonobject["foo"], json::type_error&); + CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], json::type_error&); + CHECK_THROWS_AS(j_const_nonobject["foo"], json::type_error&); + CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], json::type_error&); CHECK_THROWS_WITH(j_nonobject["foo"], "[json.exception.type_error.305] cannot use operator[] with boolean"); CHECK_THROWS_WITH(j_nonobject[json::object_t::key_type("foo")], @@ -501,10 +501,10 @@ TEST_CASE("element access 2") { json j_nonobject(json::value_t::string); const json j_const_nonobject(j_nonobject); - CHECK_THROWS_AS(j_nonobject["foo"], json::type_error); - CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], json::type_error); - CHECK_THROWS_AS(j_const_nonobject["foo"], json::type_error); - CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], json::type_error); + CHECK_THROWS_AS(j_nonobject["foo"], json::type_error&); + CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], json::type_error&); + CHECK_THROWS_AS(j_const_nonobject["foo"], json::type_error&); + CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], json::type_error&); CHECK_THROWS_WITH(j_nonobject["foo"], "[json.exception.type_error.305] cannot use operator[] with string"); CHECK_THROWS_WITH(j_nonobject[json::object_t::key_type("foo")], @@ -519,10 +519,10 @@ TEST_CASE("element access 2") { json j_nonobject(json::value_t::array); const json j_const_nonobject(j_nonobject); - CHECK_THROWS_AS(j_nonobject["foo"], json::type_error); - CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], json::type_error); - CHECK_THROWS_AS(j_const_nonobject["foo"], json::type_error); - CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], json::type_error); + CHECK_THROWS_AS(j_nonobject["foo"], json::type_error&); + CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], json::type_error&); + CHECK_THROWS_AS(j_const_nonobject["foo"], json::type_error&); + CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], json::type_error&); CHECK_THROWS_WITH(j_nonobject["foo"], "[json.exception.type_error.305] cannot use operator[] with array"); CHECK_THROWS_WITH(j_nonobject[json::object_t::key_type("foo")], "[json.exception.type_error.305] cannot use operator[] with array"); @@ -536,10 +536,10 @@ TEST_CASE("element access 2") { json j_nonobject(json::value_t::number_integer); const json j_const_nonobject(j_nonobject); - CHECK_THROWS_AS(j_nonobject["foo"], json::type_error); - CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], json::type_error); - CHECK_THROWS_AS(j_const_nonobject["foo"], json::type_error); - CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], json::type_error); + CHECK_THROWS_AS(j_nonobject["foo"], json::type_error&); + CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], json::type_error&); + CHECK_THROWS_AS(j_const_nonobject["foo"], json::type_error&); + CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], json::type_error&); CHECK_THROWS_WITH(j_nonobject["foo"], "[json.exception.type_error.305] cannot use operator[] with number"); CHECK_THROWS_WITH(j_nonobject[json::object_t::key_type("foo")], @@ -554,10 +554,10 @@ TEST_CASE("element access 2") { json j_nonobject(json::value_t::number_unsigned); const json j_const_nonobject(j_nonobject); - CHECK_THROWS_AS(j_nonobject["foo"], json::type_error); - CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], json::type_error); - CHECK_THROWS_AS(j_const_nonobject["foo"], json::type_error); - CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], json::type_error); + CHECK_THROWS_AS(j_nonobject["foo"], json::type_error&); + CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], json::type_error&); + CHECK_THROWS_AS(j_const_nonobject["foo"], json::type_error&); + CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], json::type_error&); CHECK_THROWS_WITH(j_nonobject["foo"], "[json.exception.type_error.305] cannot use operator[] with number"); CHECK_THROWS_WITH(j_nonobject[json::object_t::key_type("foo")], @@ -572,10 +572,10 @@ TEST_CASE("element access 2") { json j_nonobject(json::value_t::number_float); const json j_const_nonobject(j_nonobject); - CHECK_THROWS_AS(j_nonobject["foo"], json::type_error); - CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], json::type_error); - CHECK_THROWS_AS(j_const_nonobject["foo"], json::type_error); - CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], json::type_error); + CHECK_THROWS_AS(j_nonobject["foo"], json::type_error&); + CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], json::type_error&); + CHECK_THROWS_AS(j_const_nonobject["foo"], json::type_error&); + CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], json::type_error&); CHECK_THROWS_WITH(j_nonobject["foo"], "[json.exception.type_error.305] cannot use operator[] with number"); CHECK_THROWS_WITH(j_nonobject[json::object_t::key_type("foo")], @@ -722,10 +722,10 @@ TEST_CASE("element access 2") { json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}, {"d", false}, {"e", true}}; json jobject2 = {{"a", "a"}, {"b", 1}, {"c", 17u}}; - CHECK_THROWS_AS(jobject.erase(jobject2.begin()), json::invalid_iterator); - CHECK_THROWS_AS(jobject.erase(jobject.begin(), jobject2.end()), json::invalid_iterator); - CHECK_THROWS_AS(jobject.erase(jobject2.begin(), jobject.end()), json::invalid_iterator); - CHECK_THROWS_AS(jobject.erase(jobject2.begin(), jobject2.end()), json::invalid_iterator); + CHECK_THROWS_AS(jobject.erase(jobject2.begin()), json::invalid_iterator&); + CHECK_THROWS_AS(jobject.erase(jobject.begin(), jobject2.end()), json::invalid_iterator&); + CHECK_THROWS_AS(jobject.erase(jobject2.begin(), jobject.end()), json::invalid_iterator&); + CHECK_THROWS_AS(jobject.erase(jobject2.begin(), jobject2.end()), json::invalid_iterator&); CHECK_THROWS_WITH(jobject.erase(jobject2.begin()), "[json.exception.invalid_iterator.202] iterator does not fit current value"); CHECK_THROWS_WITH(jobject.erase(jobject.begin(), jobject2.end()), @@ -738,10 +738,10 @@ TEST_CASE("element access 2") { json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}, {"d", false}, {"e", true}}; json jobject2 = {{"a", "a"}, {"b", 1}, {"c", 17u}}; - CHECK_THROWS_AS(jobject.erase(jobject2.cbegin()), json::invalid_iterator); - CHECK_THROWS_AS(jobject.erase(jobject.cbegin(), jobject2.cend()), json::invalid_iterator); - CHECK_THROWS_AS(jobject.erase(jobject2.cbegin(), jobject.cend()), json::invalid_iterator); - CHECK_THROWS_AS(jobject.erase(jobject2.cbegin(), jobject2.cend()), json::invalid_iterator); + CHECK_THROWS_AS(jobject.erase(jobject2.cbegin()), json::invalid_iterator&); + CHECK_THROWS_AS(jobject.erase(jobject.cbegin(), jobject2.cend()), json::invalid_iterator&); + CHECK_THROWS_AS(jobject.erase(jobject2.cbegin(), jobject.cend()), json::invalid_iterator&); + CHECK_THROWS_AS(jobject.erase(jobject2.cbegin(), jobject2.cend()), json::invalid_iterator&); CHECK_THROWS_WITH(jobject.erase(jobject2.cbegin()), "[json.exception.invalid_iterator.202] iterator does not fit current value"); CHECK_THROWS_WITH(jobject.erase(jobject.cbegin(), jobject2.cend()), @@ -759,7 +759,7 @@ TEST_CASE("element access 2") SECTION("null") { json j_nonobject(json::value_t::null); - CHECK_THROWS_AS(j_nonobject.erase("foo"), json::type_error); + CHECK_THROWS_AS(j_nonobject.erase("foo"), json::type_error&); CHECK_THROWS_WITH(j_nonobject.erase("foo"), "[json.exception.type_error.307] cannot use erase() with null"); } @@ -767,7 +767,7 @@ TEST_CASE("element access 2") SECTION("boolean") { json j_nonobject(json::value_t::boolean); - CHECK_THROWS_AS(j_nonobject.erase("foo"), json::type_error); + CHECK_THROWS_AS(j_nonobject.erase("foo"), json::type_error&); CHECK_THROWS_WITH(j_nonobject.erase("foo"), "[json.exception.type_error.307] cannot use erase() with boolean"); } @@ -775,7 +775,7 @@ TEST_CASE("element access 2") SECTION("string") { json j_nonobject(json::value_t::string); - CHECK_THROWS_AS(j_nonobject.erase("foo"), json::type_error); + CHECK_THROWS_AS(j_nonobject.erase("foo"), json::type_error&); CHECK_THROWS_WITH(j_nonobject.erase("foo"), "[json.exception.type_error.307] cannot use erase() with string"); } @@ -783,7 +783,7 @@ TEST_CASE("element access 2") SECTION("array") { json j_nonobject(json::value_t::array); - CHECK_THROWS_AS(j_nonobject.erase("foo"), json::type_error); + CHECK_THROWS_AS(j_nonobject.erase("foo"), json::type_error&); CHECK_THROWS_WITH(j_nonobject.erase("foo"), "[json.exception.type_error.307] cannot use erase() with array"); } @@ -791,7 +791,7 @@ TEST_CASE("element access 2") SECTION("number (integer)") { json j_nonobject(json::value_t::number_integer); - CHECK_THROWS_AS(j_nonobject.erase("foo"), json::type_error); + CHECK_THROWS_AS(j_nonobject.erase("foo"), json::type_error&); CHECK_THROWS_WITH(j_nonobject.erase("foo"), "[json.exception.type_error.307] cannot use erase() with number"); } @@ -799,7 +799,7 @@ TEST_CASE("element access 2") SECTION("number (floating-point)") { json j_nonobject(json::value_t::number_float); - CHECK_THROWS_AS(j_nonobject.erase("foo"), json::type_error); + CHECK_THROWS_AS(j_nonobject.erase("foo"), json::type_error&); CHECK_THROWS_WITH(j_nonobject.erase("foo"), "[json.exception.type_error.307] cannot use erase() with number"); } diff --git a/test/src/unit-iterators1.cpp b/test/src/unit-iterators1.cpp index c707b2d9..66ffed22 100644 --- a/test/src/unit-iterators1.cpp +++ b/test/src/unit-iterators1.cpp @@ -337,19 +337,19 @@ TEST_CASE("iterators 1") { auto it = j.begin(); auto cit = j_const.cbegin(); - CHECK_THROWS_AS(it.key(), json::invalid_iterator); + CHECK_THROWS_AS(it.key(), json::invalid_iterator&); CHECK_THROWS_WITH(it.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); CHECK(it.value() == json(true)); - CHECK_THROWS_AS(cit.key(), json::invalid_iterator); + CHECK_THROWS_AS(cit.key(), json::invalid_iterator&); CHECK_THROWS_WITH(cit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); CHECK(cit.value() == json(true)); auto rit = j.rend(); auto crit = j.crend(); - CHECK_THROWS_AS(rit.key(), json::invalid_iterator); - CHECK_THROWS_AS(rit.value(), json::invalid_iterator); - CHECK_THROWS_AS(crit.key(), json::invalid_iterator); - CHECK_THROWS_AS(crit.value(), json::invalid_iterator); + CHECK_THROWS_AS(rit.key(), json::invalid_iterator&); + CHECK_THROWS_AS(rit.value(), json::invalid_iterator&); + CHECK_THROWS_AS(crit.key(), json::invalid_iterator&); + CHECK_THROWS_AS(crit.value(), json::invalid_iterator&); CHECK_THROWS_WITH(rit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); CHECK_THROWS_WITH(rit.value(), "[json.exception.invalid_iterator.214] cannot get value"); CHECK_THROWS_WITH(crit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); @@ -541,19 +541,19 @@ TEST_CASE("iterators 1") { auto it = j.begin(); auto cit = j_const.cbegin(); - CHECK_THROWS_AS(it.key(), json::invalid_iterator); + CHECK_THROWS_AS(it.key(), json::invalid_iterator&); CHECK_THROWS_WITH(it.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); CHECK(it.value() == json("hello world")); - CHECK_THROWS_AS(cit.key(), json::invalid_iterator); + CHECK_THROWS_AS(cit.key(), json::invalid_iterator&); CHECK_THROWS_WITH(cit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); CHECK(cit.value() == json("hello world")); auto rit = j.rend(); auto crit = j.crend(); - CHECK_THROWS_AS(rit.key(), json::invalid_iterator); - CHECK_THROWS_AS(rit.value(), json::invalid_iterator); - CHECK_THROWS_AS(crit.key(), json::invalid_iterator); - CHECK_THROWS_AS(crit.value(), json::invalid_iterator); + CHECK_THROWS_AS(rit.key(), json::invalid_iterator&); + CHECK_THROWS_AS(rit.value(), json::invalid_iterator&); + CHECK_THROWS_AS(crit.key(), json::invalid_iterator&); + CHECK_THROWS_AS(crit.value(), json::invalid_iterator&); CHECK_THROWS_WITH(rit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); CHECK_THROWS_WITH(rit.value(), "[json.exception.invalid_iterator.214] cannot get value"); CHECK_THROWS_WITH(crit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); @@ -738,10 +738,10 @@ TEST_CASE("iterators 1") { auto it = j.begin(); auto cit = j_const.cbegin(); - CHECK_THROWS_AS(it.key(), json::invalid_iterator); + CHECK_THROWS_AS(it.key(), json::invalid_iterator&); CHECK_THROWS_WITH(it.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); CHECK(it.value() == json(1)); - CHECK_THROWS_AS(cit.key(), json::invalid_iterator); + CHECK_THROWS_AS(cit.key(), json::invalid_iterator&); CHECK_THROWS_WITH(cit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); CHECK(cit.value() == json(1)); } @@ -1115,19 +1115,19 @@ TEST_CASE("iterators 1") { auto it = j.begin(); auto cit = j_const.cbegin(); - CHECK_THROWS_AS(it.key(), json::invalid_iterator); + CHECK_THROWS_AS(it.key(), json::invalid_iterator&); CHECK_THROWS_WITH(it.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); CHECK(it.value() == json(23)); - CHECK_THROWS_AS(cit.key(), json::invalid_iterator); + CHECK_THROWS_AS(cit.key(), json::invalid_iterator&); CHECK_THROWS_WITH(cit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); CHECK(cit.value() == json(23)); auto rit = j.rend(); auto crit = j.crend(); - CHECK_THROWS_AS(rit.key(), json::invalid_iterator); - CHECK_THROWS_AS(rit.value(), json::invalid_iterator); - CHECK_THROWS_AS(crit.key(), json::invalid_iterator); - CHECK_THROWS_AS(crit.value(), json::invalid_iterator); + CHECK_THROWS_AS(rit.key(), json::invalid_iterator&); + CHECK_THROWS_AS(rit.value(), json::invalid_iterator&); + CHECK_THROWS_AS(crit.key(), json::invalid_iterator&); + CHECK_THROWS_AS(crit.value(), json::invalid_iterator&); CHECK_THROWS_WITH(rit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); CHECK_THROWS_WITH(rit.value(), "[json.exception.invalid_iterator.214] cannot get value"); CHECK_THROWS_WITH(crit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); @@ -1319,19 +1319,19 @@ TEST_CASE("iterators 1") { auto it = j.begin(); auto cit = j_const.cbegin(); - CHECK_THROWS_AS(it.key(), json::invalid_iterator); + CHECK_THROWS_AS(it.key(), json::invalid_iterator&); CHECK_THROWS_WITH(it.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); CHECK(it.value() == json(23)); - CHECK_THROWS_AS(cit.key(), json::invalid_iterator); + CHECK_THROWS_AS(cit.key(), json::invalid_iterator&); CHECK_THROWS_WITH(cit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); CHECK(cit.value() == json(23)); auto rit = j.rend(); auto crit = j.crend(); - CHECK_THROWS_AS(rit.key(), json::invalid_iterator); - CHECK_THROWS_AS(rit.value(), json::invalid_iterator); - CHECK_THROWS_AS(crit.key(), json::invalid_iterator); - CHECK_THROWS_AS(crit.value(), json::invalid_iterator); + CHECK_THROWS_AS(rit.key(), json::invalid_iterator&); + CHECK_THROWS_AS(rit.value(), json::invalid_iterator&); + CHECK_THROWS_AS(crit.key(), json::invalid_iterator&); + CHECK_THROWS_AS(crit.value(), json::invalid_iterator&); CHECK_THROWS_WITH(rit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); CHECK_THROWS_WITH(rit.value(), "[json.exception.invalid_iterator.214] cannot get value"); CHECK_THROWS_WITH(crit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); @@ -1523,19 +1523,19 @@ TEST_CASE("iterators 1") { auto it = j.begin(); auto cit = j_const.cbegin(); - CHECK_THROWS_AS(it.key(), json::invalid_iterator); + CHECK_THROWS_AS(it.key(), json::invalid_iterator&); CHECK_THROWS_WITH(it.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); CHECK(it.value() == json(23.42)); - CHECK_THROWS_AS(cit.key(), json::invalid_iterator); + CHECK_THROWS_AS(cit.key(), json::invalid_iterator&); CHECK_THROWS_WITH(cit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); CHECK(cit.value() == json(23.42)); auto rit = j.rend(); auto crit = j.crend(); - CHECK_THROWS_AS(rit.key(), json::invalid_iterator); - CHECK_THROWS_AS(rit.value(), json::invalid_iterator); - CHECK_THROWS_AS(crit.key(), json::invalid_iterator); - CHECK_THROWS_AS(crit.value(), json::invalid_iterator); + CHECK_THROWS_AS(rit.key(), json::invalid_iterator&); + CHECK_THROWS_AS(rit.value(), json::invalid_iterator&); + CHECK_THROWS_AS(crit.key(), json::invalid_iterator&); + CHECK_THROWS_AS(crit.value(), json::invalid_iterator&); CHECK_THROWS_WITH(rit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); CHECK_THROWS_WITH(rit.value(), "[json.exception.invalid_iterator.214] cannot get value"); CHECK_THROWS_WITH(crit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); @@ -1597,10 +1597,10 @@ TEST_CASE("iterators 1") { auto it = j.begin(); auto cit = j_const.cbegin(); - CHECK_THROWS_AS(it.key(), json::invalid_iterator); - CHECK_THROWS_AS(it.value(), json::invalid_iterator); - CHECK_THROWS_AS(cit.key(), json::invalid_iterator); - CHECK_THROWS_AS(cit.value(), json::invalid_iterator); + CHECK_THROWS_AS(it.key(), json::invalid_iterator&); + CHECK_THROWS_AS(it.value(), json::invalid_iterator&); + CHECK_THROWS_AS(cit.key(), json::invalid_iterator&); + CHECK_THROWS_AS(cit.value(), json::invalid_iterator&); CHECK_THROWS_WITH(it.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); CHECK_THROWS_WITH(it.value(), "[json.exception.invalid_iterator.214] cannot get value"); CHECK_THROWS_WITH(cit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); @@ -1608,10 +1608,10 @@ TEST_CASE("iterators 1") auto rit = j.rend(); auto crit = j.crend(); - CHECK_THROWS_AS(rit.key(), json::invalid_iterator); - CHECK_THROWS_AS(rit.value(), json::invalid_iterator); - CHECK_THROWS_AS(crit.key(), json::invalid_iterator); - CHECK_THROWS_AS(crit.value(), json::invalid_iterator); + CHECK_THROWS_AS(rit.key(), json::invalid_iterator&); + CHECK_THROWS_AS(rit.value(), json::invalid_iterator&); + CHECK_THROWS_AS(crit.key(), json::invalid_iterator&); + CHECK_THROWS_AS(crit.value(), json::invalid_iterator&); CHECK_THROWS_WITH(rit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); CHECK_THROWS_WITH(rit.value(), "[json.exception.invalid_iterator.214] cannot get value"); CHECK_THROWS_WITH(crit.key(), "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators"); diff --git a/test/src/unit-iterators2.cpp b/test/src/unit-iterators2.cpp index 29d134da..be4e2770 100644 --- a/test/src/unit-iterators2.cpp +++ b/test/src/unit-iterators2.cpp @@ -81,14 +81,14 @@ TEST_CASE("iterators 2") { if (j.type() == json::value_t::object) { - CHECK_THROWS_AS(it1 < it1, json::invalid_iterator); - CHECK_THROWS_AS(it1 < it2, json::invalid_iterator); - CHECK_THROWS_AS(it2 < it3, json::invalid_iterator); - CHECK_THROWS_AS(it1 < it3, json::invalid_iterator); - CHECK_THROWS_AS(it1_c < it1_c, json::invalid_iterator); - CHECK_THROWS_AS(it1_c < it2_c, json::invalid_iterator); - CHECK_THROWS_AS(it2_c < it3_c, json::invalid_iterator); - CHECK_THROWS_AS(it1_c < it3_c, json::invalid_iterator); + CHECK_THROWS_AS(it1 < it1, json::invalid_iterator&); + CHECK_THROWS_AS(it1 < it2, json::invalid_iterator&); + CHECK_THROWS_AS(it2 < it3, json::invalid_iterator&); + CHECK_THROWS_AS(it1 < it3, json::invalid_iterator&); + CHECK_THROWS_AS(it1_c < it1_c, json::invalid_iterator&); + CHECK_THROWS_AS(it1_c < it2_c, json::invalid_iterator&); + CHECK_THROWS_AS(it2_c < it3_c, json::invalid_iterator&); + CHECK_THROWS_AS(it1_c < it3_c, json::invalid_iterator&); CHECK_THROWS_WITH(it1 < it1, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); CHECK_THROWS_WITH(it1 < it2, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); CHECK_THROWS_WITH(it2 < it3, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); @@ -115,14 +115,14 @@ TEST_CASE("iterators 2") { if (j.type() == json::value_t::object) { - CHECK_THROWS_AS(it1 <= it1, json::invalid_iterator); - CHECK_THROWS_AS(it1 <= it2, json::invalid_iterator); - CHECK_THROWS_AS(it2 <= it3, json::invalid_iterator); - CHECK_THROWS_AS(it1 <= it3, json::invalid_iterator); - CHECK_THROWS_AS(it1_c <= it1_c, json::invalid_iterator); - CHECK_THROWS_AS(it1_c <= it2_c, json::invalid_iterator); - CHECK_THROWS_AS(it2_c <= it3_c, json::invalid_iterator); - CHECK_THROWS_AS(it1_c <= it3_c, json::invalid_iterator); + CHECK_THROWS_AS(it1 <= it1, json::invalid_iterator&); + CHECK_THROWS_AS(it1 <= it2, json::invalid_iterator&); + CHECK_THROWS_AS(it2 <= it3, json::invalid_iterator&); + CHECK_THROWS_AS(it1 <= it3, json::invalid_iterator&); + CHECK_THROWS_AS(it1_c <= it1_c, json::invalid_iterator&); + CHECK_THROWS_AS(it1_c <= it2_c, json::invalid_iterator&); + CHECK_THROWS_AS(it2_c <= it3_c, json::invalid_iterator&); + CHECK_THROWS_AS(it1_c <= it3_c, json::invalid_iterator&); CHECK_THROWS_WITH(it1 <= it1, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); CHECK_THROWS_WITH(it1 <= it2, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); CHECK_THROWS_WITH(it2 <= it3, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); @@ -150,14 +150,14 @@ TEST_CASE("iterators 2") { if (j.type() == json::value_t::object) { - CHECK_THROWS_AS(it1 > it1, json::invalid_iterator); - CHECK_THROWS_AS(it1 > it2, json::invalid_iterator); - CHECK_THROWS_AS(it2 > it3, json::invalid_iterator); - CHECK_THROWS_AS(it1 > it3, json::invalid_iterator); - CHECK_THROWS_AS(it1_c > it1_c, json::invalid_iterator); - CHECK_THROWS_AS(it1_c > it2_c, json::invalid_iterator); - CHECK_THROWS_AS(it2_c > it3_c, json::invalid_iterator); - CHECK_THROWS_AS(it1_c > it3_c, json::invalid_iterator); + CHECK_THROWS_AS(it1 > it1, json::invalid_iterator&); + CHECK_THROWS_AS(it1 > it2, json::invalid_iterator&); + CHECK_THROWS_AS(it2 > it3, json::invalid_iterator&); + CHECK_THROWS_AS(it1 > it3, json::invalid_iterator&); + CHECK_THROWS_AS(it1_c > it1_c, json::invalid_iterator&); + CHECK_THROWS_AS(it1_c > it2_c, json::invalid_iterator&); + CHECK_THROWS_AS(it2_c > it3_c, json::invalid_iterator&); + CHECK_THROWS_AS(it1_c > it3_c, json::invalid_iterator&); CHECK_THROWS_WITH(it1 > it1, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); CHECK_THROWS_WITH(it1 > it2, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); CHECK_THROWS_WITH(it2 > it3, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); @@ -185,14 +185,14 @@ TEST_CASE("iterators 2") { if (j.type() == json::value_t::object) { - CHECK_THROWS_AS(it1 >= it1, json::invalid_iterator); - CHECK_THROWS_AS(it1 >= it2, json::invalid_iterator); - CHECK_THROWS_AS(it2 >= it3, json::invalid_iterator); - CHECK_THROWS_AS(it1 >= it3, json::invalid_iterator); - CHECK_THROWS_AS(it1_c >= it1_c, json::invalid_iterator); - CHECK_THROWS_AS(it1_c >= it2_c, json::invalid_iterator); - CHECK_THROWS_AS(it2_c >= it3_c, json::invalid_iterator); - CHECK_THROWS_AS(it1_c >= it3_c, json::invalid_iterator); + CHECK_THROWS_AS(it1 >= it1, json::invalid_iterator&); + CHECK_THROWS_AS(it1 >= it2, json::invalid_iterator&); + CHECK_THROWS_AS(it2 >= it3, json::invalid_iterator&); + CHECK_THROWS_AS(it1 >= it3, json::invalid_iterator&); + CHECK_THROWS_AS(it1_c >= it1_c, json::invalid_iterator&); + CHECK_THROWS_AS(it1_c >= it2_c, json::invalid_iterator&); + CHECK_THROWS_AS(it2_c >= it3_c, json::invalid_iterator&); + CHECK_THROWS_AS(it1_c >= it3_c, json::invalid_iterator&); CHECK_THROWS_WITH(it1 >= it1, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); CHECK_THROWS_WITH(it1 >= it2, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); CHECK_THROWS_WITH(it2 >= it3, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); @@ -224,13 +224,13 @@ TEST_CASE("iterators 2") { if (j != k) { - CHECK_THROWS_AS(j.begin() == k.begin(), json::invalid_iterator); - CHECK_THROWS_AS(j.cbegin() == k.cbegin(), json::invalid_iterator); + CHECK_THROWS_AS(j.begin() == k.begin(), json::invalid_iterator&); + CHECK_THROWS_AS(j.cbegin() == k.cbegin(), json::invalid_iterator&); CHECK_THROWS_WITH(j.begin() == k.begin(), "[json.exception.invalid_iterator.212] cannot compare iterators of different containers"); CHECK_THROWS_WITH(j.cbegin() == k.cbegin(), "[json.exception.invalid_iterator.212] cannot compare iterators of different containers"); - CHECK_THROWS_AS(j.begin() < k.begin(), json::invalid_iterator); - CHECK_THROWS_AS(j.cbegin() < k.cbegin(), json::invalid_iterator); + CHECK_THROWS_AS(j.begin() < k.begin(), json::invalid_iterator&); + CHECK_THROWS_AS(j.cbegin() < k.cbegin(), json::invalid_iterator&); CHECK_THROWS_WITH(j.begin() < k.begin(), "[json.exception.invalid_iterator.212] cannot compare iterators of different containers"); CHECK_THROWS_WITH(j.cbegin() < k.cbegin(), "[json.exception.invalid_iterator.212] cannot compare iterators of different containers"); } @@ -251,62 +251,62 @@ TEST_CASE("iterators 2") { { auto it = j_object.begin(); - CHECK_THROWS_AS(it += 1, json::invalid_iterator); + CHECK_THROWS_AS(it += 1, json::invalid_iterator&); CHECK_THROWS_WITH(it += 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.cbegin(); - CHECK_THROWS_AS(it += 1, json::invalid_iterator); + CHECK_THROWS_AS(it += 1, json::invalid_iterator&); CHECK_THROWS_WITH(it += 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.begin(); - CHECK_THROWS_AS(it + 1, json::invalid_iterator); + CHECK_THROWS_AS(it + 1, json::invalid_iterator&); CHECK_THROWS_WITH(it + 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.cbegin(); - CHECK_THROWS_AS(it + 1, json::invalid_iterator); + CHECK_THROWS_AS(it + 1, json::invalid_iterator&); CHECK_THROWS_WITH(it + 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.begin(); - CHECK_THROWS_AS(1 + it, json::invalid_iterator); + CHECK_THROWS_AS(1 + it, json::invalid_iterator&); CHECK_THROWS_WITH(1 + it, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.cbegin(); - CHECK_THROWS_AS(1 + it, json::invalid_iterator); + CHECK_THROWS_AS(1 + it, json::invalid_iterator&); CHECK_THROWS_WITH(1 + it, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.begin(); - CHECK_THROWS_AS(it -= 1, json::invalid_iterator); + CHECK_THROWS_AS(it -= 1, json::invalid_iterator&); CHECK_THROWS_WITH(it -= 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.cbegin(); - CHECK_THROWS_AS(it -= 1, json::invalid_iterator); + CHECK_THROWS_AS(it -= 1, json::invalid_iterator&); CHECK_THROWS_WITH(it -= 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.begin(); - CHECK_THROWS_AS(it - 1, json::invalid_iterator); + CHECK_THROWS_AS(it - 1, json::invalid_iterator&); CHECK_THROWS_WITH(it - 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.cbegin(); - CHECK_THROWS_AS(it - 1, json::invalid_iterator); + CHECK_THROWS_AS(it - 1, json::invalid_iterator&); CHECK_THROWS_WITH(it - 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.begin(); - CHECK_THROWS_AS(it - it, json::invalid_iterator); + CHECK_THROWS_AS(it - it, json::invalid_iterator&); CHECK_THROWS_WITH(it - it, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.cbegin(); - CHECK_THROWS_AS(it - it, json::invalid_iterator); + CHECK_THROWS_AS(it - it, json::invalid_iterator&); CHECK_THROWS_WITH(it - it, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } } @@ -396,15 +396,15 @@ TEST_CASE("iterators 2") { { auto it = j_object.begin(); - CHECK_THROWS_AS(it[0], json::invalid_iterator); - CHECK_THROWS_AS(it[1], json::invalid_iterator); + CHECK_THROWS_AS(it[0], json::invalid_iterator&); + CHECK_THROWS_AS(it[1], json::invalid_iterator&); CHECK_THROWS_WITH(it[0], "[json.exception.invalid_iterator.208] cannot use operator[] for object iterators"); CHECK_THROWS_WITH(it[1], "[json.exception.invalid_iterator.208] cannot use operator[] for object iterators"); } { auto it = j_object.cbegin(); - CHECK_THROWS_AS(it[0], json::invalid_iterator); - CHECK_THROWS_AS(it[1], json::invalid_iterator); + CHECK_THROWS_AS(it[0], json::invalid_iterator&); + CHECK_THROWS_AS(it[1], json::invalid_iterator&); CHECK_THROWS_WITH(it[0], "[json.exception.invalid_iterator.208] cannot use operator[] for object iterators"); CHECK_THROWS_WITH(it[1], "[json.exception.invalid_iterator.208] cannot use operator[] for object iterators"); } @@ -436,15 +436,15 @@ TEST_CASE("iterators 2") { { auto it = j_null.begin(); - CHECK_THROWS_AS(it[0], json::invalid_iterator); - CHECK_THROWS_AS(it[1], json::invalid_iterator); + CHECK_THROWS_AS(it[0], json::invalid_iterator&); + CHECK_THROWS_AS(it[1], json::invalid_iterator&); CHECK_THROWS_WITH(it[0], "[json.exception.invalid_iterator.214] cannot get value"); CHECK_THROWS_WITH(it[1], "[json.exception.invalid_iterator.214] cannot get value"); } { auto it = j_null.cbegin(); - CHECK_THROWS_AS(it[0], json::invalid_iterator); - CHECK_THROWS_AS(it[1], json::invalid_iterator); + CHECK_THROWS_AS(it[0], json::invalid_iterator&); + CHECK_THROWS_AS(it[1], json::invalid_iterator&); CHECK_THROWS_WITH(it[0], "[json.exception.invalid_iterator.214] cannot get value"); CHECK_THROWS_WITH(it[1], "[json.exception.invalid_iterator.214] cannot get value"); } @@ -455,13 +455,13 @@ TEST_CASE("iterators 2") { auto it = j_value.begin(); CHECK(it[0] == json(42)); - CHECK_THROWS_AS(it[1], json::invalid_iterator); + CHECK_THROWS_AS(it[1], json::invalid_iterator&); CHECK_THROWS_WITH(it[1], "[json.exception.invalid_iterator.214] cannot get value"); } { auto it = j_value.cbegin(); CHECK(it[0] == json(42)); - CHECK_THROWS_AS(it[1], json::invalid_iterator); + CHECK_THROWS_AS(it[1], json::invalid_iterator&); CHECK_THROWS_WITH(it[1], "[json.exception.invalid_iterator.214] cannot get value"); } } @@ -516,14 +516,14 @@ TEST_CASE("iterators 2") { if (j.type() == json::value_t::object) { - CHECK_THROWS_AS(it1 < it1, json::invalid_iterator); - CHECK_THROWS_AS(it1 < it2, json::invalid_iterator); - CHECK_THROWS_AS(it2 < it3, json::invalid_iterator); - CHECK_THROWS_AS(it1 < it3, json::invalid_iterator); - CHECK_THROWS_AS(it1_c < it1_c, json::invalid_iterator); - CHECK_THROWS_AS(it1_c < it2_c, json::invalid_iterator); - CHECK_THROWS_AS(it2_c < it3_c, json::invalid_iterator); - CHECK_THROWS_AS(it1_c < it3_c, json::invalid_iterator); + CHECK_THROWS_AS(it1 < it1, json::invalid_iterator&); + CHECK_THROWS_AS(it1 < it2, json::invalid_iterator&); + CHECK_THROWS_AS(it2 < it3, json::invalid_iterator&); + CHECK_THROWS_AS(it1 < it3, json::invalid_iterator&); + CHECK_THROWS_AS(it1_c < it1_c, json::invalid_iterator&); + CHECK_THROWS_AS(it1_c < it2_c, json::invalid_iterator&); + CHECK_THROWS_AS(it2_c < it3_c, json::invalid_iterator&); + CHECK_THROWS_AS(it1_c < it3_c, json::invalid_iterator&); CHECK_THROWS_WITH(it1 < it1, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); CHECK_THROWS_WITH(it1 < it2, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); CHECK_THROWS_WITH(it2 < it3, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); @@ -550,14 +550,14 @@ TEST_CASE("iterators 2") { if (j.type() == json::value_t::object) { - CHECK_THROWS_AS(it1 <= it1, json::invalid_iterator); - CHECK_THROWS_AS(it1 <= it2, json::invalid_iterator); - CHECK_THROWS_AS(it2 <= it3, json::invalid_iterator); - CHECK_THROWS_AS(it1 <= it3, json::invalid_iterator); - CHECK_THROWS_AS(it1_c <= it1_c, json::invalid_iterator); - CHECK_THROWS_AS(it1_c <= it2_c, json::invalid_iterator); - CHECK_THROWS_AS(it2_c <= it3_c, json::invalid_iterator); - CHECK_THROWS_AS(it1_c <= it3_c, json::invalid_iterator); + CHECK_THROWS_AS(it1 <= it1, json::invalid_iterator&); + CHECK_THROWS_AS(it1 <= it2, json::invalid_iterator&); + CHECK_THROWS_AS(it2 <= it3, json::invalid_iterator&); + CHECK_THROWS_AS(it1 <= it3, json::invalid_iterator&); + CHECK_THROWS_AS(it1_c <= it1_c, json::invalid_iterator&); + CHECK_THROWS_AS(it1_c <= it2_c, json::invalid_iterator&); + CHECK_THROWS_AS(it2_c <= it3_c, json::invalid_iterator&); + CHECK_THROWS_AS(it1_c <= it3_c, json::invalid_iterator&); CHECK_THROWS_WITH(it1 <= it1, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); CHECK_THROWS_WITH(it1 <= it2, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); CHECK_THROWS_WITH(it2 <= it3, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); @@ -585,14 +585,14 @@ TEST_CASE("iterators 2") { if (j.type() == json::value_t::object) { - CHECK_THROWS_AS(it1 > it1, json::invalid_iterator); - CHECK_THROWS_AS(it1 > it2, json::invalid_iterator); - CHECK_THROWS_AS(it2 > it3, json::invalid_iterator); - CHECK_THROWS_AS(it1 > it3, json::invalid_iterator); - CHECK_THROWS_AS(it1_c > it1_c, json::invalid_iterator); - CHECK_THROWS_AS(it1_c > it2_c, json::invalid_iterator); - CHECK_THROWS_AS(it2_c > it3_c, json::invalid_iterator); - CHECK_THROWS_AS(it1_c > it3_c, json::invalid_iterator); + CHECK_THROWS_AS(it1 > it1, json::invalid_iterator&); + CHECK_THROWS_AS(it1 > it2, json::invalid_iterator&); + CHECK_THROWS_AS(it2 > it3, json::invalid_iterator&); + CHECK_THROWS_AS(it1 > it3, json::invalid_iterator&); + CHECK_THROWS_AS(it1_c > it1_c, json::invalid_iterator&); + CHECK_THROWS_AS(it1_c > it2_c, json::invalid_iterator&); + CHECK_THROWS_AS(it2_c > it3_c, json::invalid_iterator&); + CHECK_THROWS_AS(it1_c > it3_c, json::invalid_iterator&); CHECK_THROWS_WITH(it1 > it1, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); CHECK_THROWS_WITH(it1 > it2, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); CHECK_THROWS_WITH(it2 > it3, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); @@ -620,14 +620,14 @@ TEST_CASE("iterators 2") { if (j.type() == json::value_t::object) { - CHECK_THROWS_AS(it1 >= it1, json::invalid_iterator); - CHECK_THROWS_AS(it1 >= it2, json::invalid_iterator); - CHECK_THROWS_AS(it2 >= it3, json::invalid_iterator); - CHECK_THROWS_AS(it1 >= it3, json::invalid_iterator); - CHECK_THROWS_AS(it1_c >= it1_c, json::invalid_iterator); - CHECK_THROWS_AS(it1_c >= it2_c, json::invalid_iterator); - CHECK_THROWS_AS(it2_c >= it3_c, json::invalid_iterator); - CHECK_THROWS_AS(it1_c >= it3_c, json::invalid_iterator); + CHECK_THROWS_AS(it1 >= it1, json::invalid_iterator&); + CHECK_THROWS_AS(it1 >= it2, json::invalid_iterator&); + CHECK_THROWS_AS(it2 >= it3, json::invalid_iterator&); + CHECK_THROWS_AS(it1 >= it3, json::invalid_iterator&); + CHECK_THROWS_AS(it1_c >= it1_c, json::invalid_iterator&); + CHECK_THROWS_AS(it1_c >= it2_c, json::invalid_iterator&); + CHECK_THROWS_AS(it2_c >= it3_c, json::invalid_iterator&); + CHECK_THROWS_AS(it1_c >= it3_c, json::invalid_iterator&); CHECK_THROWS_WITH(it1 >= it1, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); CHECK_THROWS_WITH(it1 >= it2, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); CHECK_THROWS_WITH(it2 >= it3, "[json.exception.invalid_iterator.213] cannot compare order of object iterators"); @@ -659,13 +659,13 @@ TEST_CASE("iterators 2") { if (j != k) { - CHECK_THROWS_AS(j.rbegin() == k.rbegin(), json::invalid_iterator); - CHECK_THROWS_AS(j.crbegin() == k.crbegin(), json::invalid_iterator); + CHECK_THROWS_AS(j.rbegin() == k.rbegin(), json::invalid_iterator&); + CHECK_THROWS_AS(j.crbegin() == k.crbegin(), json::invalid_iterator&); CHECK_THROWS_WITH(j.rbegin() == k.rbegin(), "[json.exception.invalid_iterator.212] cannot compare iterators of different containers"); CHECK_THROWS_WITH(j.crbegin() == k.crbegin(), "[json.exception.invalid_iterator.212] cannot compare iterators of different containers"); - CHECK_THROWS_AS(j.rbegin() < k.rbegin(), json::invalid_iterator); - CHECK_THROWS_AS(j.crbegin() < k.crbegin(), json::invalid_iterator); + CHECK_THROWS_AS(j.rbegin() < k.rbegin(), json::invalid_iterator&); + CHECK_THROWS_AS(j.crbegin() < k.crbegin(), json::invalid_iterator&); CHECK_THROWS_WITH(j.rbegin() < k.rbegin(), "[json.exception.invalid_iterator.212] cannot compare iterators of different containers"); CHECK_THROWS_WITH(j.crbegin() < k.crbegin(), "[json.exception.invalid_iterator.212] cannot compare iterators of different containers"); } @@ -686,62 +686,62 @@ TEST_CASE("iterators 2") { { auto it = j_object.rbegin(); - CHECK_THROWS_AS(it += 1, json::invalid_iterator); + CHECK_THROWS_AS(it += 1, json::invalid_iterator&); CHECK_THROWS_WITH(it += 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.crbegin(); - CHECK_THROWS_AS(it += 1, json::invalid_iterator); + CHECK_THROWS_AS(it += 1, json::invalid_iterator&); CHECK_THROWS_WITH(it += 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.rbegin(); - CHECK_THROWS_AS(it + 1, json::invalid_iterator); + CHECK_THROWS_AS(it + 1, json::invalid_iterator&); CHECK_THROWS_WITH(it + 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.crbegin(); - CHECK_THROWS_AS(it + 1, json::invalid_iterator); + CHECK_THROWS_AS(it + 1, json::invalid_iterator&); CHECK_THROWS_WITH(it + 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.rbegin(); - CHECK_THROWS_AS(1 + it, json::invalid_iterator); + CHECK_THROWS_AS(1 + it, json::invalid_iterator&); CHECK_THROWS_WITH(1 + it, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.crbegin(); - CHECK_THROWS_AS(1 + it, json::invalid_iterator); + CHECK_THROWS_AS(1 + it, json::invalid_iterator&); CHECK_THROWS_WITH(1 + it, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.rbegin(); - CHECK_THROWS_AS(it -= 1, json::invalid_iterator); + CHECK_THROWS_AS(it -= 1, json::invalid_iterator&); CHECK_THROWS_WITH(it -= 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.crbegin(); - CHECK_THROWS_AS(it -= 1, json::invalid_iterator); + CHECK_THROWS_AS(it -= 1, json::invalid_iterator&); CHECK_THROWS_WITH(it -= 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.rbegin(); - CHECK_THROWS_AS(it - 1, json::invalid_iterator); + CHECK_THROWS_AS(it - 1, json::invalid_iterator&); CHECK_THROWS_WITH(it - 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.crbegin(); - CHECK_THROWS_AS(it - 1, json::invalid_iterator); + CHECK_THROWS_AS(it - 1, json::invalid_iterator&); CHECK_THROWS_WITH(it - 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.rbegin(); - CHECK_THROWS_AS(it - it, json::invalid_iterator); + CHECK_THROWS_AS(it - it, json::invalid_iterator&); CHECK_THROWS_WITH(it - it, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.crbegin(); - CHECK_THROWS_AS(it - it, json::invalid_iterator); + CHECK_THROWS_AS(it - it, json::invalid_iterator&); CHECK_THROWS_WITH(it - it, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } } @@ -831,15 +831,15 @@ TEST_CASE("iterators 2") { { auto it = j_object.rbegin(); - CHECK_THROWS_AS(it[0], json::invalid_iterator); - CHECK_THROWS_AS(it[1], json::invalid_iterator); + CHECK_THROWS_AS(it[0], json::invalid_iterator&); + CHECK_THROWS_AS(it[1], json::invalid_iterator&); CHECK_THROWS_WITH(it[0], "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); CHECK_THROWS_WITH(it[1], "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } { auto it = j_object.crbegin(); - CHECK_THROWS_AS(it[0], json::invalid_iterator); - CHECK_THROWS_AS(it[1], json::invalid_iterator); + CHECK_THROWS_AS(it[0], json::invalid_iterator&); + CHECK_THROWS_AS(it[1], json::invalid_iterator&); CHECK_THROWS_WITH(it[0], "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); CHECK_THROWS_WITH(it[1], "[json.exception.invalid_iterator.209] cannot use offsets with object iterators"); } @@ -871,15 +871,15 @@ TEST_CASE("iterators 2") { { auto it = j_null.rbegin(); - CHECK_THROWS_AS(it[0], json::invalid_iterator); - CHECK_THROWS_AS(it[1], json::invalid_iterator); + CHECK_THROWS_AS(it[0], json::invalid_iterator&); + CHECK_THROWS_AS(it[1], json::invalid_iterator&); CHECK_THROWS_WITH(it[0], "[json.exception.invalid_iterator.214] cannot get value"); CHECK_THROWS_WITH(it[1], "[json.exception.invalid_iterator.214] cannot get value"); } { auto it = j_null.crbegin(); - CHECK_THROWS_AS(it[0], json::invalid_iterator); - CHECK_THROWS_AS(it[1], json::invalid_iterator); + CHECK_THROWS_AS(it[0], json::invalid_iterator&); + CHECK_THROWS_AS(it[1], json::invalid_iterator&); CHECK_THROWS_WITH(it[0], "[json.exception.invalid_iterator.214] cannot get value"); CHECK_THROWS_WITH(it[1], "[json.exception.invalid_iterator.214] cannot get value"); } @@ -890,13 +890,13 @@ TEST_CASE("iterators 2") { auto it = j_value.rbegin(); CHECK(it[0] == json(42)); - CHECK_THROWS_AS(it[1], json::invalid_iterator); + CHECK_THROWS_AS(it[1], json::invalid_iterator&); CHECK_THROWS_WITH(it[1], "[json.exception.invalid_iterator.214] cannot get value"); } { auto it = j_value.crbegin(); CHECK(it[0] == json(42)); - CHECK_THROWS_AS(it[1], json::invalid_iterator); + CHECK_THROWS_AS(it[1], json::invalid_iterator&); CHECK_THROWS_WITH(it[1], "[json.exception.invalid_iterator.214] cannot get value"); } } diff --git a/test/src/unit-json_patch.cpp b/test/src/unit-json_patch.cpp index 9ab86ea4..636fa2bc 100644 --- a/test/src/unit-json_patch.cpp +++ b/test/src/unit-json_patch.cpp @@ -75,7 +75,7 @@ TEST_CASE("JSON patch") json doc2 = R"({ "q": { "bar": 2 } })"_json; // because "a" does not exist. - CHECK_THROWS_AS(doc2.patch(patch), json::out_of_range); + CHECK_THROWS_AS(doc2.patch(patch), json::out_of_range&); CHECK_THROWS_WITH(doc2.patch(patch), "[json.exception.out_of_range.403] key 'a' not found"); } @@ -337,7 +337,7 @@ TEST_CASE("JSON patch") )"_json; // check that evaluation throws - CHECK_THROWS_AS(doc.patch(patch), json::other_error); + CHECK_THROWS_AS(doc.patch(patch), json::other_error&); CHECK_THROWS_WITH(doc.patch(patch), "[json.exception.other_error.501] unsuccessful: " + patch[0].dump()); } @@ -421,7 +421,7 @@ TEST_CASE("JSON patch") // references neither the root of the document, nor a member of // an existing object, nor a member of an existing array. - CHECK_THROWS_AS(doc.patch(patch), json::out_of_range); + CHECK_THROWS_AS(doc.patch(patch), json::out_of_range&); CHECK_THROWS_WITH(doc.patch(patch), "[json.exception.out_of_range.403] key 'baz' not found"); } @@ -478,7 +478,7 @@ TEST_CASE("JSON patch") )"_json; // check that evaluation throws - CHECK_THROWS_AS(doc.patch(patch), json::other_error); + CHECK_THROWS_AS(doc.patch(patch), json::other_error&); CHECK_THROWS_WITH(doc.patch(patch), "[json.exception.other_error.501] unsuccessful: " + patch[0].dump()); } @@ -668,7 +668,7 @@ TEST_CASE("JSON patch") { json j; json patch = {{"op", "add"}, {"path", ""}, {"value", 1}}; - CHECK_THROWS_AS(j.patch(patch), json::parse_error); + CHECK_THROWS_AS(j.patch(patch), json::parse_error&); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.parse_error.104] parse error: JSON patch must be an array of objects"); } @@ -677,7 +677,7 @@ TEST_CASE("JSON patch") { json j; json patch = {"op", "add", "path", "", "value", 1}; - CHECK_THROWS_AS(j.patch(patch), json::parse_error); + CHECK_THROWS_AS(j.patch(patch), json::parse_error&); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.parse_error.104] parse error: JSON patch must be an array of objects"); } @@ -686,7 +686,7 @@ TEST_CASE("JSON patch") { json j; json patch = {{{"foo", "bar"}}}; - CHECK_THROWS_AS(j.patch(patch), json::parse_error); + CHECK_THROWS_AS(j.patch(patch), json::parse_error&); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.parse_error.105] parse error: operation must have member 'op'"); } @@ -695,7 +695,7 @@ TEST_CASE("JSON patch") { json j; json patch = {{{"op", 1}}}; - CHECK_THROWS_AS(j.patch(patch), json::parse_error); + CHECK_THROWS_AS(j.patch(patch), json::parse_error&); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.parse_error.105] parse error: operation must have string member 'op'"); } @@ -704,7 +704,7 @@ TEST_CASE("JSON patch") { json j; json patch = {{{"op", "foo"}, {"path", ""}}}; - CHECK_THROWS_AS(j.patch(patch), json::parse_error); + CHECK_THROWS_AS(j.patch(patch), json::parse_error&); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.parse_error.105] parse error: operation value 'foo' is invalid"); } @@ -716,7 +716,7 @@ TEST_CASE("JSON patch") { json j; json patch = {{{"op", "add"}}}; - CHECK_THROWS_AS(j.patch(patch), json::parse_error); + CHECK_THROWS_AS(j.patch(patch), json::parse_error&); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.parse_error.105] parse error: operation 'add' must have member 'path'"); } @@ -725,7 +725,7 @@ TEST_CASE("JSON patch") { json j; json patch = {{{"op", "add"}, {"path", 1}}}; - CHECK_THROWS_AS(j.patch(patch), json::parse_error); + CHECK_THROWS_AS(j.patch(patch), json::parse_error&); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.parse_error.105] parse error: operation 'add' must have string member 'path'"); } @@ -734,7 +734,7 @@ TEST_CASE("JSON patch") { json j; json patch = {{{"op", "add"}, {"path", ""}}}; - CHECK_THROWS_AS(j.patch(patch), json::parse_error); + CHECK_THROWS_AS(j.patch(patch), json::parse_error&); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.parse_error.105] parse error: operation 'add' must have member 'value'"); } @@ -743,7 +743,7 @@ TEST_CASE("JSON patch") { json j = {1, 2}; json patch = {{{"op", "add"}, {"path", "/4"}, {"value", 4}}}; - CHECK_THROWS_AS(j.patch(patch), json::out_of_range); + CHECK_THROWS_AS(j.patch(patch), json::out_of_range&); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.out_of_range.401] array index 4 is out of range"); } @@ -755,7 +755,7 @@ TEST_CASE("JSON patch") { json j; json patch = {{{"op", "remove"}}}; - CHECK_THROWS_AS(j.patch(patch), json::parse_error); + CHECK_THROWS_AS(j.patch(patch), json::parse_error&); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.parse_error.105] parse error: operation 'remove' must have member 'path'"); } @@ -764,7 +764,7 @@ TEST_CASE("JSON patch") { json j; json patch = {{{"op", "remove"}, {"path", 1}}}; - CHECK_THROWS_AS(j.patch(patch), json::parse_error); + CHECK_THROWS_AS(j.patch(patch), json::parse_error&); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.parse_error.105] parse error: operation 'remove' must have string member 'path'"); } @@ -773,7 +773,7 @@ TEST_CASE("JSON patch") { json j = {1, 2, 3}; json patch = {{{"op", "remove"}, {"path", "/17"}}}; - CHECK_THROWS_AS(j.patch(patch), json::out_of_range); + CHECK_THROWS_AS(j.patch(patch), json::out_of_range&); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.out_of_range.401] array index 17 is out of range"); } @@ -782,7 +782,7 @@ TEST_CASE("JSON patch") { json j = {{"foo", 1}, {"bar", 2}}; json patch = {{{"op", "remove"}, {"path", "/baz"}}}; - CHECK_THROWS_AS(j.patch(patch), json::out_of_range); + CHECK_THROWS_AS(j.patch(patch), json::out_of_range&); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.out_of_range.403] key 'baz' not found"); } @@ -791,7 +791,7 @@ TEST_CASE("JSON patch") { json j = "string"; json patch = {{{"op", "remove"}, {"path", ""}}}; - CHECK_THROWS_AS(j.patch(patch), json::out_of_range); + CHECK_THROWS_AS(j.patch(patch), json::out_of_range&); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.out_of_range.405] JSON pointer has no parent"); } @@ -803,7 +803,7 @@ TEST_CASE("JSON patch") { json j; json patch = {{{"op", "replace"}}}; - CHECK_THROWS_AS(j.patch(patch), json::parse_error); + CHECK_THROWS_AS(j.patch(patch), json::parse_error&); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.parse_error.105] parse error: operation 'replace' must have member 'path'"); } @@ -812,7 +812,7 @@ TEST_CASE("JSON patch") { json j; json patch = {{{"op", "replace"}, {"path", 1}}}; - CHECK_THROWS_AS(j.patch(patch), json::parse_error); + CHECK_THROWS_AS(j.patch(patch), json::parse_error&); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.parse_error.105] parse error: operation 'replace' must have string member 'path'"); } @@ -821,7 +821,7 @@ TEST_CASE("JSON patch") { json j; json patch = {{{"op", "replace"}, {"path", ""}}}; - CHECK_THROWS_AS(j.patch(patch), json::parse_error); + CHECK_THROWS_AS(j.patch(patch), json::parse_error&); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.parse_error.105] parse error: operation 'replace' must have member 'value'"); } @@ -830,7 +830,7 @@ TEST_CASE("JSON patch") { json j = {1, 2, 3}; json patch = {{{"op", "replace"}, {"path", "/17"}, {"value", 19}}}; - CHECK_THROWS_AS(j.patch(patch), json::out_of_range); + CHECK_THROWS_AS(j.patch(patch), json::out_of_range&); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.out_of_range.401] array index 17 is out of range"); } @@ -839,7 +839,7 @@ TEST_CASE("JSON patch") { json j = {{"foo", 1}, {"bar", 2}}; json patch = {{{"op", "replace"}, {"path", "/baz"}, {"value", 3}}}; - CHECK_THROWS_AS(j.patch(patch), json::out_of_range); + CHECK_THROWS_AS(j.patch(patch), json::out_of_range&); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.out_of_range.403] key 'baz' not found"); } @@ -851,7 +851,7 @@ TEST_CASE("JSON patch") { json j; json patch = {{{"op", "move"}}}; - CHECK_THROWS_AS(j.patch(patch), json::parse_error); + CHECK_THROWS_AS(j.patch(patch), json::parse_error&); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.parse_error.105] parse error: operation 'move' must have member 'path'"); } @@ -860,7 +860,7 @@ TEST_CASE("JSON patch") { json j; json patch = {{{"op", "move"}, {"path", 1}}}; - CHECK_THROWS_AS(j.patch(patch), json::parse_error); + CHECK_THROWS_AS(j.patch(patch), json::parse_error&); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.parse_error.105] parse error: operation 'move' must have string member 'path'"); } @@ -869,7 +869,7 @@ TEST_CASE("JSON patch") { json j; json patch = {{{"op", "move"}, {"path", ""}}}; - CHECK_THROWS_AS(j.patch(patch), json::parse_error); + CHECK_THROWS_AS(j.patch(patch), json::parse_error&); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.parse_error.105] parse error: operation 'move' must have member 'from'"); } @@ -878,7 +878,7 @@ TEST_CASE("JSON patch") { json j; json patch = {{{"op", "move"}, {"path", ""}, {"from", 1}}}; - CHECK_THROWS_AS(j.patch(patch), json::parse_error); + CHECK_THROWS_AS(j.patch(patch), json::parse_error&); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.parse_error.105] parse error: operation 'move' must have string member 'from'"); } @@ -887,7 +887,7 @@ TEST_CASE("JSON patch") { json j = {1, 2, 3}; json patch = {{{"op", "move"}, {"path", "/0"}, {"from", "/5"}}}; - CHECK_THROWS_AS(j.patch(patch), json::out_of_range); + CHECK_THROWS_AS(j.patch(patch), json::out_of_range&); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.out_of_range.401] array index 5 is out of range"); } @@ -896,7 +896,7 @@ TEST_CASE("JSON patch") { json j = {{"foo", 1}, {"bar", 2}}; json patch = {{{"op", "move"}, {"path", "/baz"}, {"from", "/baz"}}}; - CHECK_THROWS_AS(j.patch(patch), json::out_of_range); + CHECK_THROWS_AS(j.patch(patch), json::out_of_range&); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.out_of_range.403] key 'baz' not found"); } @@ -908,7 +908,7 @@ TEST_CASE("JSON patch") { json j; json patch = {{{"op", "copy"}}}; - CHECK_THROWS_AS(j.patch(patch), json::parse_error); + CHECK_THROWS_AS(j.patch(patch), json::parse_error&); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.parse_error.105] parse error: operation 'copy' must have member 'path'"); } @@ -917,7 +917,7 @@ TEST_CASE("JSON patch") { json j; json patch = {{{"op", "copy"}, {"path", 1}}}; - CHECK_THROWS_AS(j.patch(patch), json::parse_error); + CHECK_THROWS_AS(j.patch(patch), json::parse_error&); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.parse_error.105] parse error: operation 'copy' must have string member 'path'"); } @@ -926,7 +926,7 @@ TEST_CASE("JSON patch") { json j; json patch = {{{"op", "copy"}, {"path", ""}}}; - CHECK_THROWS_AS(j.patch(patch), json::parse_error); + CHECK_THROWS_AS(j.patch(patch), json::parse_error&); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.parse_error.105] parse error: operation 'copy' must have member 'from'"); } @@ -935,7 +935,7 @@ TEST_CASE("JSON patch") { json j; json patch = {{{"op", "copy"}, {"path", ""}, {"from", 1}}}; - CHECK_THROWS_AS(j.patch(patch), json::parse_error); + CHECK_THROWS_AS(j.patch(patch), json::parse_error&); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.parse_error.105] parse error: operation 'copy' must have string member 'from'"); } @@ -944,7 +944,7 @@ TEST_CASE("JSON patch") { json j = {1, 2, 3}; json patch = {{{"op", "copy"}, {"path", "/0"}, {"from", "/5"}}}; - CHECK_THROWS_AS(j.patch(patch), json::out_of_range); + CHECK_THROWS_AS(j.patch(patch), json::out_of_range&); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.out_of_range.401] array index 5 is out of range"); } @@ -953,7 +953,7 @@ TEST_CASE("JSON patch") { json j = {{"foo", 1}, {"bar", 2}}; json patch = {{{"op", "copy"}, {"path", "/fob"}, {"from", "/baz"}}}; - CHECK_THROWS_AS(j.patch(patch), json::out_of_range); + CHECK_THROWS_AS(j.patch(patch), json::out_of_range&); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.out_of_range.403] key 'baz' not found"); } @@ -965,7 +965,7 @@ TEST_CASE("JSON patch") { json j; json patch = {{{"op", "test"}}}; - CHECK_THROWS_AS(j.patch(patch), json::parse_error); + CHECK_THROWS_AS(j.patch(patch), json::parse_error&); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.parse_error.105] parse error: operation 'test' must have member 'path'"); } @@ -974,7 +974,7 @@ TEST_CASE("JSON patch") { json j; json patch = {{{"op", "test"}, {"path", 1}}}; - CHECK_THROWS_AS(j.patch(patch), json::parse_error); + CHECK_THROWS_AS(j.patch(patch), json::parse_error&); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.parse_error.105] parse error: operation 'test' must have string member 'path'"); } @@ -983,7 +983,7 @@ TEST_CASE("JSON patch") { json j; json patch = {{{"op", "test"}, {"path", ""}}}; - CHECK_THROWS_AS(j.patch(patch), json::parse_error); + CHECK_THROWS_AS(j.patch(patch), json::parse_error&); CHECK_THROWS_WITH(j.patch(patch), "[json.exception.parse_error.105] parse error: operation 'test' must have member 'value'"); } @@ -1177,7 +1177,7 @@ TEST_CASE("JSON patch") )"_json; // the test will fail - CHECK_THROWS_AS(doc.patch(patch), json::other_error); + CHECK_THROWS_AS(doc.patch(patch), json::other_error&); CHECK_THROWS_WITH(doc.patch(patch), "[json.exception.other_error.501] unsuccessful: " + patch[0].dump()); } } diff --git a/test/src/unit-json_pointer.cpp b/test/src/unit-json_pointer.cpp index d4280049..ee55dc58 100644 --- a/test/src/unit-json_pointer.cpp +++ b/test/src/unit-json_pointer.cpp @@ -36,23 +36,23 @@ TEST_CASE("JSON pointers") { SECTION("errors") { - CHECK_THROWS_AS(json::json_pointer("foo"), json::parse_error); + CHECK_THROWS_AS(json::json_pointer("foo"), json::parse_error&); CHECK_THROWS_WITH(json::json_pointer("foo"), "[json.exception.parse_error.107] parse error at 1: JSON pointer must be empty or begin with '/' - was: 'foo'"); - CHECK_THROWS_AS(json::json_pointer("/~~"), json::parse_error); + CHECK_THROWS_AS(json::json_pointer("/~~"), json::parse_error&); CHECK_THROWS_WITH(json::json_pointer("/~~"), "[json.exception.parse_error.108] parse error: escape character '~' must be followed with '0' or '1'"); - CHECK_THROWS_AS(json::json_pointer("/~"), json::parse_error); + CHECK_THROWS_AS(json::json_pointer("/~"), json::parse_error&); CHECK_THROWS_WITH(json::json_pointer("/~"), "[json.exception.parse_error.108] parse error: escape character '~' must be followed with '0' or '1'"); json::json_pointer p; - CHECK_THROWS_AS(p.top(), json::out_of_range); + CHECK_THROWS_AS(p.top(), json::out_of_range&); CHECK_THROWS_WITH(p.top(), "[json.exception.out_of_range.405] JSON pointer has no parent"); - CHECK_THROWS_AS(p.pop_back(), json::out_of_range); + CHECK_THROWS_AS(p.pop_back(), json::out_of_range&); CHECK_THROWS_WITH(p.pop_back(), "[json.exception.out_of_range.405] JSON pointer has no parent"); } @@ -126,10 +126,10 @@ TEST_CASE("JSON pointers") // unresolved access json j_primitive = 1; - CHECK_THROWS_AS(j_primitive["/foo"_json_pointer], json::out_of_range); + CHECK_THROWS_AS(j_primitive["/foo"_json_pointer], json::out_of_range&); CHECK_THROWS_WITH(j_primitive["/foo"_json_pointer], "[json.exception.out_of_range.404] unresolved reference token 'foo'"); - CHECK_THROWS_AS(j_primitive.at("/foo"_json_pointer), json::out_of_range); + CHECK_THROWS_AS(j_primitive.at("/foo"_json_pointer), json::out_of_range&); CHECK_THROWS_WITH(j_primitive.at("/foo"_json_pointer), "[json.exception.out_of_range.404] unresolved reference token 'foo'"); } @@ -189,16 +189,16 @@ TEST_CASE("JSON pointers") CHECK(j[json::json_pointer("/m~0n")] == j["m~n"]); // unescaped access - CHECK_THROWS_AS(j.at(json::json_pointer("/a/b")), json::out_of_range); + CHECK_THROWS_AS(j.at(json::json_pointer("/a/b")), json::out_of_range&); CHECK_THROWS_WITH(j.at(json::json_pointer("/a/b")), "[json.exception.out_of_range.403] key 'a' not found"); // unresolved access const json j_primitive = 1; - CHECK_THROWS_AS(j_primitive["/foo"_json_pointer], json::out_of_range); + CHECK_THROWS_AS(j_primitive["/foo"_json_pointer], json::out_of_range&); CHECK_THROWS_WITH(j_primitive["/foo"_json_pointer], "[json.exception.out_of_range.404] unresolved reference token 'foo'"); - CHECK_THROWS_AS(j_primitive.at("/foo"_json_pointer), json::out_of_range); + CHECK_THROWS_AS(j_primitive.at("/foo"_json_pointer), json::out_of_range&); CHECK_THROWS_WITH(j_primitive.at("/foo"_json_pointer), "[json.exception.out_of_range.404] unresolved reference token 'foo'"); } @@ -255,35 +255,35 @@ TEST_CASE("JSON pointers") CHECK(j == json({1, 13, 3, 33, nullptr, 55})); // error with leading 0 - CHECK_THROWS_AS(j["/01"_json_pointer], json::parse_error); + CHECK_THROWS_AS(j["/01"_json_pointer], json::parse_error&); CHECK_THROWS_WITH(j["/01"_json_pointer], "[json.exception.parse_error.106] parse error: array index '01' must not begin with '0'"); - CHECK_THROWS_AS(j_const["/01"_json_pointer], json::parse_error); + CHECK_THROWS_AS(j_const["/01"_json_pointer], json::parse_error&); CHECK_THROWS_WITH(j_const["/01"_json_pointer], "[json.exception.parse_error.106] parse error: array index '01' must not begin with '0'"); - CHECK_THROWS_AS(j.at("/01"_json_pointer), json::parse_error); + CHECK_THROWS_AS(j.at("/01"_json_pointer), json::parse_error&); CHECK_THROWS_WITH(j.at("/01"_json_pointer), "[json.exception.parse_error.106] parse error: array index '01' must not begin with '0'"); - CHECK_THROWS_AS(j_const.at("/01"_json_pointer), json::parse_error); + CHECK_THROWS_AS(j_const.at("/01"_json_pointer), json::parse_error&); CHECK_THROWS_WITH(j_const.at("/01"_json_pointer), "[json.exception.parse_error.106] parse error: array index '01' must not begin with '0'"); // error with incorrect numbers - CHECK_THROWS_AS(j["/one"_json_pointer] = 1, json::parse_error); + CHECK_THROWS_AS(j["/one"_json_pointer] = 1, json::parse_error&); CHECK_THROWS_WITH(j["/one"_json_pointer] = 1, "[json.exception.parse_error.109] parse error: array index 'one' is not a number"); - CHECK_THROWS_AS(j_const["/one"_json_pointer] == 1, json::parse_error); + CHECK_THROWS_AS(j_const["/one"_json_pointer] == 1, json::parse_error&); CHECK_THROWS_WITH(j_const["/one"_json_pointer] == 1, "[json.exception.parse_error.109] parse error: array index 'one' is not a number"); - CHECK_THROWS_AS(j.at("/one"_json_pointer) = 1, json::parse_error); + CHECK_THROWS_AS(j.at("/one"_json_pointer) = 1, json::parse_error&); CHECK_THROWS_WITH(j.at("/one"_json_pointer) = 1, "[json.exception.parse_error.109] parse error: array index 'one' is not a number"); - CHECK_THROWS_AS(j_const.at("/one"_json_pointer) == 1, json::parse_error); + CHECK_THROWS_AS(j_const.at("/one"_json_pointer) == 1, json::parse_error&); CHECK_THROWS_WITH(j_const.at("/one"_json_pointer) == 1, "[json.exception.parse_error.109] parse error: array index 'one' is not a number"); - CHECK_THROWS_AS(json({{"/list/0", 1}, {"/list/1", 2}, {"/list/three", 3}}).unflatten(), json::parse_error); + CHECK_THROWS_AS(json({{"/list/0", 1}, {"/list/1", 2}, {"/list/three", 3}}).unflatten(), json::parse_error&); CHECK_THROWS_WITH(json({{"/list/0", 1}, {"/list/1", 2}, {"/list/three", 3}}).unflatten(), "[json.exception.parse_error.109] parse error: array index 'three' is not a number"); @@ -292,15 +292,15 @@ TEST_CASE("JSON pointers") CHECK(j == json({1, 13, 3, 33, nullptr, 55, 99})); // error when using "-" in const object - CHECK_THROWS_AS(j_const["/-"_json_pointer], json::out_of_range); + CHECK_THROWS_AS(j_const["/-"_json_pointer], json::out_of_range&); CHECK_THROWS_WITH(j_const["/-"_json_pointer], "[json.exception.out_of_range.402] array index '-' (3) is out of range"); // error when using "-" with at - CHECK_THROWS_AS(j.at("/-"_json_pointer), json::out_of_range); + CHECK_THROWS_AS(j.at("/-"_json_pointer), json::out_of_range&); CHECK_THROWS_WITH(j.at("/-"_json_pointer), "[json.exception.out_of_range.402] array index '-' (7) is out of range"); - CHECK_THROWS_AS(j_const.at("/-"_json_pointer), json::out_of_range); + CHECK_THROWS_AS(j_const.at("/-"_json_pointer), json::out_of_range&); CHECK_THROWS_WITH(j_const.at("/-"_json_pointer), "[json.exception.out_of_range.402] array index '-' (3) is out of range"); } @@ -315,20 +315,20 @@ TEST_CASE("JSON pointers") CHECK(j["/2"_json_pointer] == j[2]); // assign to nonexisting index - CHECK_THROWS_AS(j.at("/3"_json_pointer), json::out_of_range); + CHECK_THROWS_AS(j.at("/3"_json_pointer), json::out_of_range&); CHECK_THROWS_WITH(j.at("/3"_json_pointer), "[json.exception.out_of_range.401] array index 3 is out of range"); // assign to nonexisting index (with gap) - CHECK_THROWS_AS(j.at("/5"_json_pointer), json::out_of_range); + CHECK_THROWS_AS(j.at("/5"_json_pointer), json::out_of_range&); CHECK_THROWS_WITH(j.at("/5"_json_pointer), "[json.exception.out_of_range.401] array index 5 is out of range"); // assign to "-" - CHECK_THROWS_AS(j["/-"_json_pointer], json::out_of_range); + CHECK_THROWS_AS(j["/-"_json_pointer], json::out_of_range&); CHECK_THROWS_WITH(j["/-"_json_pointer], "[json.exception.out_of_range.402] array index '-' (3) is out of range"); - CHECK_THROWS_AS(j.at("/-"_json_pointer), json::out_of_range); + CHECK_THROWS_AS(j.at("/-"_json_pointer), json::out_of_range&); CHECK_THROWS_WITH(j.at("/-"_json_pointer), "[json.exception.out_of_range.402] array index '-' (3) is out of range"); } @@ -386,18 +386,18 @@ TEST_CASE("JSON pointers") CHECK(j_flatten.unflatten() == j); // error for nonobjects - CHECK_THROWS_AS(json(1).unflatten(), json::type_error); + CHECK_THROWS_AS(json(1).unflatten(), json::type_error&); CHECK_THROWS_WITH(json(1).unflatten(), "[json.exception.type_error.314] only objects can be unflattened"); // error for nonprimitve values - CHECK_THROWS_AS(json({{"/1", {1, 2, 3}}}).unflatten(), json::type_error); + CHECK_THROWS_AS(json({{"/1", {1, 2, 3}}}).unflatten(), json::type_error&); CHECK_THROWS_WITH(json({{"/1", {1, 2, 3}}}).unflatten(), "[json.exception.type_error.315] values in object must be primitive"); // error for conflicting values json j_error = {{"", 42}, {"/foo", 17}}; - CHECK_THROWS_AS(j_error.unflatten(), json::type_error); + CHECK_THROWS_AS(j_error.unflatten(), json::type_error&); CHECK_THROWS_WITH(j_error.unflatten(), "[json.exception.type_error.313] invalid value to unflatten"); diff --git a/test/src/unit-modifiers.cpp b/test/src/unit-modifiers.cpp index f0eb09c6..01dfa415 100644 --- a/test/src/unit-modifiers.cpp +++ b/test/src/unit-modifiers.cpp @@ -172,7 +172,7 @@ TEST_CASE("modifiers") SECTION("other type") { json j = 1; - CHECK_THROWS_AS(j.push_back("Hello"), json::type_error); + CHECK_THROWS_AS(j.push_back("Hello"), json::type_error&); CHECK_THROWS_WITH(j.push_back("Hello"), "[json.exception.type_error.308] cannot use push_back() with number"); } } @@ -202,7 +202,7 @@ TEST_CASE("modifiers") { json j = 1; json k("Hello"); - CHECK_THROWS_AS(j.push_back(k), json::type_error); + CHECK_THROWS_AS(j.push_back(k), json::type_error&); CHECK_THROWS_WITH(j.push_back(k), "[json.exception.type_error.308] cannot use push_back() with number"); } } @@ -235,7 +235,7 @@ TEST_CASE("modifiers") { json j = 1; json k("Hello"); - CHECK_THROWS_AS(j.push_back(json::object_t::value_type({"one", 1})), json::type_error); + CHECK_THROWS_AS(j.push_back(json::object_t::value_type({"one", 1})), json::type_error&); CHECK_THROWS_WITH(j.push_back(json::object_t::value_type({"one", 1})), "[json.exception.type_error.308] cannot use push_back() with number"); } @@ -272,11 +272,11 @@ TEST_CASE("modifiers") CHECK(j == json({{"key1", 1}, {"key2", "bar"}})); // invalid values (no string/val pair) - CHECK_THROWS_AS(j.push_back({1}), json::type_error); + CHECK_THROWS_AS(j.push_back({1}), json::type_error&); CHECK_THROWS_WITH(j.push_back({1}), "[json.exception.type_error.308] cannot use push_back() with object"); - CHECK_THROWS_AS(j.push_back({1, 2}), json::type_error); + CHECK_THROWS_AS(j.push_back({1, 2}), json::type_error&); CHECK_THROWS_WITH(j.push_back({1, 2}), "[json.exception.type_error.308] cannot use push_back() with object"); - CHECK_THROWS_AS(j.push_back({1, 2, 3, 4}), json::type_error); + CHECK_THROWS_AS(j.push_back({1, 2, 3, 4}), json::type_error&); CHECK_THROWS_WITH(j.push_back({1, 2, 3, 4}), "[json.exception.type_error.308] cannot use push_back() with object"); } } @@ -315,7 +315,7 @@ TEST_CASE("modifiers") SECTION("other type") { json j = 1; - CHECK_THROWS_AS(j.emplace_back("Hello"), json::type_error); + CHECK_THROWS_AS(j.emplace_back("Hello"), json::type_error&); CHECK_THROWS_WITH(j.emplace_back("Hello"), "[json.exception.type_error.311] cannot use emplace_back() with number"); } @@ -375,7 +375,7 @@ TEST_CASE("modifiers") SECTION("other type") { json j = 1; - CHECK_THROWS_AS(j.emplace("foo", "bar"), json::type_error); + CHECK_THROWS_AS(j.emplace("foo", "bar"), json::type_error&); CHECK_THROWS_WITH(j.emplace("foo", "bar"), "[json.exception.type_error.311] cannot use emplace() with number"); } @@ -407,7 +407,7 @@ TEST_CASE("modifiers") SECTION("other type") { json j = 1; - CHECK_THROWS_AS(j += "Hello", json::type_error); + CHECK_THROWS_AS(j += "Hello", json::type_error&); CHECK_THROWS_WITH(j += "Hello", "[json.exception.type_error.308] cannot use push_back() with number"); } } @@ -437,7 +437,7 @@ TEST_CASE("modifiers") { json j = 1; json k("Hello"); - CHECK_THROWS_AS(j += k, json::type_error); + CHECK_THROWS_AS(j += k, json::type_error&); CHECK_THROWS_WITH(j += k, "[json.exception.type_error.308] cannot use push_back() with number"); } } @@ -470,7 +470,7 @@ TEST_CASE("modifiers") { json j = 1; json k("Hello"); - CHECK_THROWS_AS(j += json::object_t::value_type({"one", 1}), json::type_error); + CHECK_THROWS_AS(j += json::object_t::value_type({"one", 1}), json::type_error&); CHECK_THROWS_WITH(j += json::object_t::value_type({"one", 1}), "[json.exception.type_error.308] cannot use push_back() with number"); } @@ -507,7 +507,7 @@ TEST_CASE("modifiers") CHECK(j == json({{"key1", 1}, {"key2", "bar"}})); json k = {{"key1", 1}}; - CHECK_THROWS_AS((k += {1, 2, 3, 4}), json::type_error); + CHECK_THROWS_AS((k += {1, 2, 3, 4}), json::type_error&); CHECK_THROWS_WITH((k += {1, 2, 3, 4}), "[json.exception.type_error.308] cannot use push_back() with object"); } } @@ -644,9 +644,9 @@ TEST_CASE("modifiers") json j_other_array2 = {"first", "second"}; CHECK_THROWS_AS(j_array.insert(j_array.end(), j_array.begin(), j_array.end()), - json::invalid_iterator); + json::invalid_iterator&); CHECK_THROWS_AS(j_array.insert(j_array.end(), j_other_array.begin(), j_other_array2.end()), - json::invalid_iterator); + json::invalid_iterator&); CHECK_THROWS_WITH(j_array.insert(j_array.end(), j_array.begin(), j_array.end()), "[json.exception.invalid_iterator.211] passed iterators may not belong to container"); @@ -676,9 +676,9 @@ TEST_CASE("modifiers") { json j_other_array2 = {"first", "second"}; - CHECK_THROWS_AS(j_array.insert(j_object2.begin(), j_object2.end()), json::type_error); - CHECK_THROWS_AS(j_object1.insert(j_object1.begin(), j_object2.end()), json::invalid_iterator); - CHECK_THROWS_AS(j_object1.insert(j_array.begin(), j_array.end()), json::invalid_iterator); + CHECK_THROWS_AS(j_array.insert(j_object2.begin(), j_object2.end()), json::type_error&); + CHECK_THROWS_AS(j_object1.insert(j_object1.begin(), j_object2.end()), json::invalid_iterator&); + CHECK_THROWS_AS(j_object1.insert(j_array.begin(), j_array.end()), json::invalid_iterator&); CHECK_THROWS_WITH(j_array.insert(j_object2.begin(), j_object2.end()), "[json.exception.type_error.309] cannot use insert() with array"); @@ -724,11 +724,11 @@ TEST_CASE("modifiers") // pass iterator to a different array json j_another_array = {1, 2}; json j_yet_another_array = {"first", "second"}; - CHECK_THROWS_AS(j_array.insert(j_another_array.end(), 10), json::invalid_iterator); - CHECK_THROWS_AS(j_array.insert(j_another_array.end(), j_value), json::invalid_iterator); - CHECK_THROWS_AS(j_array.insert(j_another_array.end(), 10, 11), json::invalid_iterator); - CHECK_THROWS_AS(j_array.insert(j_another_array.end(), j_yet_another_array.begin(), j_yet_another_array.end()), json::invalid_iterator); - CHECK_THROWS_AS(j_array.insert(j_another_array.end(), {1, 2, 3, 4}), json::invalid_iterator); + CHECK_THROWS_AS(j_array.insert(j_another_array.end(), 10), json::invalid_iterator&); + CHECK_THROWS_AS(j_array.insert(j_another_array.end(), j_value), json::invalid_iterator&); + CHECK_THROWS_AS(j_array.insert(j_another_array.end(), 10, 11), json::invalid_iterator&); + CHECK_THROWS_AS(j_array.insert(j_another_array.end(), j_yet_another_array.begin(), j_yet_another_array.end()), json::invalid_iterator&); + CHECK_THROWS_AS(j_array.insert(j_another_array.end(), {1, 2, 3, 4}), json::invalid_iterator&); CHECK_THROWS_WITH(j_array.insert(j_another_array.end(), 10), "[json.exception.invalid_iterator.202] iterator does not fit current value"); @@ -747,12 +747,12 @@ TEST_CASE("modifiers") // call insert on a non-array type json j_nonarray = 3; json j_yet_another_array = {"first", "second"}; - CHECK_THROWS_AS(j_nonarray.insert(j_nonarray.end(), 10), json::type_error); - CHECK_THROWS_AS(j_nonarray.insert(j_nonarray.end(), j_value), json::type_error); - CHECK_THROWS_AS(j_nonarray.insert(j_nonarray.end(), 10, 11), json::type_error); + CHECK_THROWS_AS(j_nonarray.insert(j_nonarray.end(), 10), json::type_error&); + CHECK_THROWS_AS(j_nonarray.insert(j_nonarray.end(), j_value), json::type_error&); + CHECK_THROWS_AS(j_nonarray.insert(j_nonarray.end(), 10, 11), json::type_error&); CHECK_THROWS_AS(j_nonarray.insert(j_nonarray.end(), j_yet_another_array.begin(), - j_yet_another_array.end()), json::type_error); - CHECK_THROWS_AS(j_nonarray.insert(j_nonarray.end(), {1, 2, 3, 4}), json::type_error); + j_yet_another_array.end()), json::type_error&); + CHECK_THROWS_AS(j_nonarray.insert(j_nonarray.end(), {1, 2, 3, 4}), json::type_error&); CHECK_THROWS_WITH(j_nonarray.insert(j_nonarray.end(), 10), "[json.exception.type_error.309] cannot use insert() with number"); CHECK_THROWS_WITH(j_nonarray.insert(j_nonarray.end(), j_value), "[json.exception.type_error.309] cannot use insert() with number"); @@ -784,10 +784,10 @@ TEST_CASE("modifiers") SECTION("wrong types") { - CHECK_THROWS_AS(j_array.update(j_object1), json::type_error); + CHECK_THROWS_AS(j_array.update(j_object1), json::type_error&); CHECK_THROWS_WITH(j_array.update(j_object1), "[json.exception.type_error.312] cannot use update() with array"); - CHECK_THROWS_AS(j_object1.update(j_array), json::type_error); + CHECK_THROWS_AS(j_object1.update(j_array), json::type_error&); CHECK_THROWS_WITH(j_object1.update(j_array), "[json.exception.type_error.312] cannot use update() with array"); } } @@ -814,9 +814,9 @@ TEST_CASE("modifiers") { json j_other_array2 = {"first", "second"}; - CHECK_THROWS_AS(j_array.update(j_object2.begin(), j_object2.end()), json::type_error); - CHECK_THROWS_AS(j_object1.update(j_object1.begin(), j_object2.end()), json::invalid_iterator); - CHECK_THROWS_AS(j_object1.update(j_array.begin(), j_array.end()), json::invalid_iterator); + CHECK_THROWS_AS(j_array.update(j_object2.begin(), j_object2.end()), json::type_error&); + CHECK_THROWS_AS(j_object1.update(j_object1.begin(), j_object2.end()), json::invalid_iterator&); + CHECK_THROWS_AS(j_object1.update(j_array.begin(), j_array.end()), json::invalid_iterator&); CHECK_THROWS_WITH(j_array.update(j_object2.begin(), j_object2.end()), "[json.exception.type_error.312] cannot use update() with array"); @@ -876,7 +876,7 @@ TEST_CASE("modifiers") json j = 17; json::array_t a = {"foo", "bar", "baz"}; - CHECK_THROWS_AS(j.swap(a), json::type_error); + CHECK_THROWS_AS(j.swap(a), json::type_error&); CHECK_THROWS_WITH(j.swap(a), "[json.exception.type_error.310] cannot use swap() with number"); } } @@ -902,7 +902,7 @@ TEST_CASE("modifiers") json j = 17; json::object_t o = {{"cow", "Kuh"}, {"chicken", "Huhn"}}; - CHECK_THROWS_AS(j.swap(o), json::type_error); + CHECK_THROWS_AS(j.swap(o), json::type_error&); CHECK_THROWS_WITH(j.swap(o), "[json.exception.type_error.310] cannot use swap() with number"); } } @@ -928,7 +928,7 @@ TEST_CASE("modifiers") json j = 17; json::string_t s = "Hallo Welt"; - CHECK_THROWS_AS(j.swap(s), json::type_error); + CHECK_THROWS_AS(j.swap(s), json::type_error&); CHECK_THROWS_WITH(j.swap(s), "[json.exception.type_error.310] cannot use swap() with number"); } } diff --git a/test/src/unit-msgpack.cpp b/test/src/unit-msgpack.cpp index c363069f..148bb180 100644 --- a/test/src/unit-msgpack.cpp +++ b/test/src/unit-msgpack.cpp @@ -1016,28 +1016,28 @@ TEST_CASE("MessagePack") { SECTION("empty byte vector") { - CHECK_THROWS_AS(json::from_msgpack(std::vector()), json::parse_error); + CHECK_THROWS_AS(json::from_msgpack(std::vector()), json::parse_error&); CHECK_THROWS_WITH(json::from_msgpack(std::vector()), "[json.exception.parse_error.110] parse error at 1: unexpected end of input"); } SECTION("too short byte vector") { - CHECK_THROWS_AS(json::from_msgpack(std::vector({0xcc})), json::parse_error); - CHECK_THROWS_AS(json::from_msgpack(std::vector({0xcd})), json::parse_error); - CHECK_THROWS_AS(json::from_msgpack(std::vector({0xcd, 0x00})), json::parse_error); - CHECK_THROWS_AS(json::from_msgpack(std::vector({0xce})), json::parse_error); - CHECK_THROWS_AS(json::from_msgpack(std::vector({0xce, 0x00})), json::parse_error); - CHECK_THROWS_AS(json::from_msgpack(std::vector({0xce, 0x00, 0x00})), json::parse_error); - CHECK_THROWS_AS(json::from_msgpack(std::vector({0xce, 0x00, 0x00, 0x00})), json::parse_error); - CHECK_THROWS_AS(json::from_msgpack(std::vector({0xcf})), json::parse_error); - CHECK_THROWS_AS(json::from_msgpack(std::vector({0xcf, 0x00})), json::parse_error); - CHECK_THROWS_AS(json::from_msgpack(std::vector({0xcf, 0x00, 0x00})), json::parse_error); - CHECK_THROWS_AS(json::from_msgpack(std::vector({0xcf, 0x00, 0x00, 0x00})), json::parse_error); - CHECK_THROWS_AS(json::from_msgpack(std::vector({0xcf, 0x00, 0x00, 0x00, 0x00})), json::parse_error); - CHECK_THROWS_AS(json::from_msgpack(std::vector({0xcf, 0x00, 0x00, 0x00, 0x00, 0x00})), json::parse_error); - CHECK_THROWS_AS(json::from_msgpack(std::vector({0xcf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})), json::parse_error); - CHECK_THROWS_AS(json::from_msgpack(std::vector({0xcf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})), json::parse_error); + CHECK_THROWS_AS(json::from_msgpack(std::vector({0xcc})), json::parse_error&); + CHECK_THROWS_AS(json::from_msgpack(std::vector({0xcd})), json::parse_error&); + CHECK_THROWS_AS(json::from_msgpack(std::vector({0xcd, 0x00})), json::parse_error&); + CHECK_THROWS_AS(json::from_msgpack(std::vector({0xce})), json::parse_error&); + CHECK_THROWS_AS(json::from_msgpack(std::vector({0xce, 0x00})), json::parse_error&); + CHECK_THROWS_AS(json::from_msgpack(std::vector({0xce, 0x00, 0x00})), json::parse_error&); + CHECK_THROWS_AS(json::from_msgpack(std::vector({0xce, 0x00, 0x00, 0x00})), json::parse_error&); + CHECK_THROWS_AS(json::from_msgpack(std::vector({0xcf})), json::parse_error&); + CHECK_THROWS_AS(json::from_msgpack(std::vector({0xcf, 0x00})), json::parse_error&); + CHECK_THROWS_AS(json::from_msgpack(std::vector({0xcf, 0x00, 0x00})), json::parse_error&); + CHECK_THROWS_AS(json::from_msgpack(std::vector({0xcf, 0x00, 0x00, 0x00})), json::parse_error&); + CHECK_THROWS_AS(json::from_msgpack(std::vector({0xcf, 0x00, 0x00, 0x00, 0x00})), json::parse_error&); + CHECK_THROWS_AS(json::from_msgpack(std::vector({0xcf, 0x00, 0x00, 0x00, 0x00, 0x00})), json::parse_error&); + CHECK_THROWS_AS(json::from_msgpack(std::vector({0xcf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})), json::parse_error&); + CHECK_THROWS_AS(json::from_msgpack(std::vector({0xcf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})), json::parse_error&); CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xcc})), "[json.exception.parse_error.110] parse error at 2: unexpected end of input"); @@ -1075,10 +1075,10 @@ TEST_CASE("MessagePack") { SECTION("concrete examples") { - CHECK_THROWS_AS(json::from_msgpack(std::vector({0xc1})), json::parse_error); + CHECK_THROWS_AS(json::from_msgpack(std::vector({0xc1})), json::parse_error&); CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xc1})), "[json.exception.parse_error.112] parse error at 1: error reading MessagePack; last byte: 0xC1"); - CHECK_THROWS_AS(json::from_msgpack(std::vector({0xc6})), json::parse_error); + CHECK_THROWS_AS(json::from_msgpack(std::vector({0xc6})), json::parse_error&); CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xc6})), "[json.exception.parse_error.112] parse error at 1: error reading MessagePack; last byte: 0xC6"); } @@ -1097,14 +1097,14 @@ TEST_CASE("MessagePack") 0xd4, 0xd5, 0xd6, 0xd7, 0xd8 }) { - CHECK_THROWS_AS(json::from_msgpack(std::vector({static_cast(byte)})), json::parse_error); + CHECK_THROWS_AS(json::from_msgpack(std::vector({static_cast(byte)})), json::parse_error&); } } } SECTION("invalid string in map") { - CHECK_THROWS_AS(json::from_msgpack(std::vector({0x81, 0xff, 0x01})), json::parse_error); + CHECK_THROWS_AS(json::from_msgpack(std::vector({0x81, 0xff, 0x01})), json::parse_error&); CHECK_THROWS_WITH(json::from_msgpack(std::vector({0x81, 0xff, 0x01})), "[json.exception.parse_error.113] parse error at 2: expected a MessagePack string; last byte: 0xFF"); } @@ -1120,7 +1120,7 @@ TEST_CASE("MessagePack") SECTION("strict mode") { - CHECK_THROWS_AS(json::from_msgpack(vec), json::parse_error); + CHECK_THROWS_AS(json::from_msgpack(vec), json::parse_error&); CHECK_THROWS_WITH(json::from_msgpack(vec), "[json.exception.parse_error.110] parse error at 2: expected end of input"); } diff --git a/test/src/unit-readme.cpp b/test/src/unit-readme.cpp index 8d126824..1ce6ee1d 100644 --- a/test/src/unit-readme.cpp +++ b/test/src/unit-readme.cpp @@ -31,7 +31,6 @@ SOFTWARE. #include "json.hpp" using nlohmann::json; -#include #include #include #include diff --git a/test/src/unit-reference_access.cpp b/test/src/unit-reference_access.cpp index 2e1759d6..c05ae723 100644 --- a/test/src/unit-reference_access.cpp +++ b/test/src/unit-reference_access.cpp @@ -64,22 +64,22 @@ TEST_CASE("reference access") // check if mismatching references throw correctly CHECK_NOTHROW(value.get_ref()); - CHECK_THROWS_AS(value.get_ref(), json::type_error); + CHECK_THROWS_AS(value.get_ref(), json::type_error&); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is object"); - CHECK_THROWS_AS(value.get_ref(), json::type_error); + CHECK_THROWS_AS(value.get_ref(), json::type_error&); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is object"); - CHECK_THROWS_AS(value.get_ref(), json::type_error); + CHECK_THROWS_AS(value.get_ref(), json::type_error&); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is object"); - CHECK_THROWS_AS(value.get_ref(), json::type_error); + CHECK_THROWS_AS(value.get_ref(), json::type_error&); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is object"); - CHECK_THROWS_AS(value.get_ref(), json::type_error); + CHECK_THROWS_AS(value.get_ref(), json::type_error&); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is object"); - CHECK_THROWS_AS(value.get_ref(), json::type_error); + CHECK_THROWS_AS(value.get_ref(), json::type_error&); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is object"); } @@ -113,23 +113,23 @@ TEST_CASE("reference access") CHECK(p2 == value.get()); // check if mismatching references throw correctly - CHECK_THROWS_AS(value.get_ref(), json::type_error); + CHECK_THROWS_AS(value.get_ref(), json::type_error&); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is array"); CHECK_NOTHROW(value.get_ref()); - CHECK_THROWS_AS(value.get_ref(), json::type_error); + CHECK_THROWS_AS(value.get_ref(), json::type_error&); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is array"); - CHECK_THROWS_AS(value.get_ref(), json::type_error); + CHECK_THROWS_AS(value.get_ref(), json::type_error&); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is array"); - CHECK_THROWS_AS(value.get_ref(), json::type_error); + CHECK_THROWS_AS(value.get_ref(), json::type_error&); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is array"); - CHECK_THROWS_AS(value.get_ref(), json::type_error); + CHECK_THROWS_AS(value.get_ref(), json::type_error&); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is array"); - CHECK_THROWS_AS(value.get_ref(), json::type_error); + CHECK_THROWS_AS(value.get_ref(), json::type_error&); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is array"); } @@ -149,23 +149,23 @@ TEST_CASE("reference access") CHECK(p2 == value.get()); // check if mismatching references throw correctly - CHECK_THROWS_AS(value.get_ref(), json::type_error); + CHECK_THROWS_AS(value.get_ref(), json::type_error&); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is string"); - CHECK_THROWS_AS(value.get_ref(), json::type_error); + CHECK_THROWS_AS(value.get_ref(), json::type_error&); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is string"); CHECK_NOTHROW(value.get_ref()); - CHECK_THROWS_AS(value.get_ref(), json::type_error); + CHECK_THROWS_AS(value.get_ref(), json::type_error&); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is string"); - CHECK_THROWS_AS(value.get_ref(), json::type_error); + CHECK_THROWS_AS(value.get_ref(), json::type_error&); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is string"); - CHECK_THROWS_AS(value.get_ref(), json::type_error); + CHECK_THROWS_AS(value.get_ref(), json::type_error&); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is string"); - CHECK_THROWS_AS(value.get_ref(), json::type_error); + CHECK_THROWS_AS(value.get_ref(), json::type_error&); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is string"); } @@ -185,23 +185,23 @@ TEST_CASE("reference access") CHECK(p2 == value.get()); // check if mismatching references throw correctly - CHECK_THROWS_AS(value.get_ref(), json::type_error); + CHECK_THROWS_AS(value.get_ref(), json::type_error&); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is boolean"); - CHECK_THROWS_AS(value.get_ref(), json::type_error); + CHECK_THROWS_AS(value.get_ref(), json::type_error&); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is boolean"); - CHECK_THROWS_AS(value.get_ref(), json::type_error); + CHECK_THROWS_AS(value.get_ref(), json::type_error&); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is boolean"); CHECK_NOTHROW(value.get_ref()); - CHECK_THROWS_AS(value.get_ref(), json::type_error); + CHECK_THROWS_AS(value.get_ref(), json::type_error&); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is boolean"); - CHECK_THROWS_AS(value.get_ref(), json::type_error); + CHECK_THROWS_AS(value.get_ref(), json::type_error&); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is boolean"); - CHECK_THROWS_AS(value.get_ref(), json::type_error); + CHECK_THROWS_AS(value.get_ref(), json::type_error&); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is boolean"); } @@ -221,23 +221,23 @@ TEST_CASE("reference access") CHECK(p2 == value.get()); // check if mismatching references throw correctly - CHECK_THROWS_AS(value.get_ref(), json::type_error); + CHECK_THROWS_AS(value.get_ref(), json::type_error&); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number"); - CHECK_THROWS_AS(value.get_ref(), json::type_error); + CHECK_THROWS_AS(value.get_ref(), json::type_error&); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number"); - CHECK_THROWS_AS(value.get_ref(), json::type_error); + CHECK_THROWS_AS(value.get_ref(), json::type_error&); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number"); - CHECK_THROWS_AS(value.get_ref(), json::type_error); + CHECK_THROWS_AS(value.get_ref(), json::type_error&); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number"); CHECK_NOTHROW(value.get_ref()); - CHECK_THROWS_AS(value.get_ref(), json::type_error); + CHECK_THROWS_AS(value.get_ref(), json::type_error&); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number"); - CHECK_THROWS_AS(value.get_ref(), json::type_error); + CHECK_THROWS_AS(value.get_ref(), json::type_error&); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number"); } @@ -257,23 +257,23 @@ TEST_CASE("reference access") CHECK(p2 == value.get()); // check if mismatching references throw correctly - CHECK_THROWS_AS(value.get_ref(), json::type_error); + CHECK_THROWS_AS(value.get_ref(), json::type_error&); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number"); - CHECK_THROWS_AS(value.get_ref(), json::type_error); + CHECK_THROWS_AS(value.get_ref(), json::type_error&); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number"); - CHECK_THROWS_AS(value.get_ref(), json::type_error); + CHECK_THROWS_AS(value.get_ref(), json::type_error&); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number"); - CHECK_THROWS_AS(value.get_ref(), json::type_error); + CHECK_THROWS_AS(value.get_ref(), json::type_error&); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number"); - //CHECK_THROWS_AS(value.get_ref(), json::type_error); + //CHECK_THROWS_AS(value.get_ref(), json::type_error&); //CHECK_THROWS_WITH(value.get_ref(), // "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number"); CHECK_NOTHROW(value.get_ref()); - CHECK_THROWS_AS(value.get_ref(), json::type_error); + CHECK_THROWS_AS(value.get_ref(), json::type_error&); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number"); } @@ -293,22 +293,22 @@ TEST_CASE("reference access") CHECK(p2 == value.get()); // check if mismatching references throw correctly - CHECK_THROWS_AS(value.get_ref(), json::type_error); + CHECK_THROWS_AS(value.get_ref(), json::type_error&); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number"); - CHECK_THROWS_AS(value.get_ref(), json::type_error); + CHECK_THROWS_AS(value.get_ref(), json::type_error&); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number"); - CHECK_THROWS_AS(value.get_ref(), json::type_error); + CHECK_THROWS_AS(value.get_ref(), json::type_error&); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number"); - CHECK_THROWS_AS(value.get_ref(), json::type_error); + CHECK_THROWS_AS(value.get_ref(), json::type_error&); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number"); - CHECK_THROWS_AS(value.get_ref(), json::type_error); + CHECK_THROWS_AS(value.get_ref(), json::type_error&); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number"); - CHECK_THROWS_AS(value.get_ref(), json::type_error); + CHECK_THROWS_AS(value.get_ref(), json::type_error&); CHECK_THROWS_WITH(value.get_ref(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number"); CHECK_NOTHROW(value.get_ref()); diff --git a/test/src/unit-regression.cpp b/test/src/unit-regression.cpp index 4fd3fb52..17728160 100644 --- a/test/src/unit-regression.cpp +++ b/test/src/unit-regression.cpp @@ -588,7 +588,7 @@ TEST_CASE("regression tests") SECTION("issue #329 - serialized value not always can be parsed") { - CHECK_THROWS_AS(json::parse("22e2222"), json::out_of_range); + CHECK_THROWS_AS(json::parse("22e2222"), json::out_of_range&); CHECK_THROWS_WITH(json::parse("22e2222"), "[json.exception.out_of_range.406] number overflow parsing '22e2222'"); } @@ -596,7 +596,7 @@ TEST_CASE("regression tests") SECTION("issue #366 - json::parse on failed stream gets stuck") { std::ifstream f("file_not_found.json"); - CHECK_THROWS_AS(json::parse(f), json::parse_error); + CHECK_THROWS_AS(json::parse(f), json::parse_error&); CHECK_THROWS_WITH(json::parse(f), "[json.exception.parse_error.101] parse error at 1: syntax error - unexpected end of input; expected '[', '{', or a literal"); } @@ -611,7 +611,7 @@ TEST_CASE("regression tests") // ss is not at EOF; this yielded an error before the fix // (threw basic_string::append). No, it should just throw // a parse error because of the EOF. - CHECK_THROWS_AS(ss >> j, json::parse_error); + CHECK_THROWS_AS(ss >> j, json::parse_error&); CHECK_THROWS_WITH(ss >> j, "[json.exception.parse_error.101] parse error at 1: syntax error - unexpected end of input; expected '[', '{', or a literal"); } @@ -622,7 +622,7 @@ TEST_CASE("regression tests") { std::stringstream ss; json j; - CHECK_THROWS_AS(ss >> j, json::parse_error); + CHECK_THROWS_AS(ss >> j, json::parse_error&); CHECK_THROWS_WITH(ss >> j, "[json.exception.parse_error.101] parse error at 1: syntax error - unexpected end of input; expected '[', '{', or a literal"); } @@ -632,7 +632,7 @@ TEST_CASE("regression tests") std::stringstream ss; ss << " "; json j; - CHECK_THROWS_AS(ss >> j, json::parse_error); + CHECK_THROWS_AS(ss >> j, json::parse_error&); CHECK_THROWS_WITH(ss >> j, "[json.exception.parse_error.101] parse error at 1: syntax error - unexpected end of input; expected '[', '{', or a literal"); } @@ -645,7 +645,7 @@ TEST_CASE("regression tests") CHECK_NOTHROW(ss >> j); CHECK(j == 111); - CHECK_THROWS_AS(ss >> j, json::parse_error); + CHECK_THROWS_AS(ss >> j, json::parse_error&); CHECK_THROWS_WITH(ss >> j, "[json.exception.parse_error.101] parse error at 1: syntax error - unexpected end of input; expected '[', '{', or a literal"); } @@ -658,7 +658,7 @@ TEST_CASE("regression tests") CHECK_NOTHROW(ss >> j); CHECK(j == 222); - CHECK_THROWS_AS(ss >> j, json::parse_error); + CHECK_THROWS_AS(ss >> j, json::parse_error&); CHECK_THROWS_WITH(ss >> j, "[json.exception.parse_error.101] parse error at 1: syntax error - unexpected end of input; expected '[', '{', or a literal"); } @@ -671,7 +671,7 @@ TEST_CASE("regression tests") CHECK_NOTHROW(ss >> j); CHECK(j == 333); - CHECK_THROWS_AS(ss >> j, json::parse_error); + CHECK_THROWS_AS(ss >> j, json::parse_error&); CHECK_THROWS_WITH(ss >> j, "[json.exception.parse_error.101] parse error at 1: syntax error - unexpected end of input; expected '[', '{', or a literal"); } @@ -688,7 +688,7 @@ TEST_CASE("regression tests") CHECK_NOTHROW(ss >> j); CHECK(j == 333); - CHECK_THROWS_AS(ss >> j, json::parse_error); + CHECK_THROWS_AS(ss >> j, json::parse_error&); CHECK_THROWS_WITH(ss >> j, "[json.exception.parse_error.101] parse error at 1: syntax error - unexpected end of input; expected '[', '{', or a literal"); } @@ -707,7 +707,7 @@ TEST_CASE("regression tests") CHECK_NOTHROW(ss >> j); CHECK(j == ""); - CHECK_THROWS_AS(ss >> j, json::parse_error); + CHECK_THROWS_AS(ss >> j, json::parse_error&); CHECK_THROWS_WITH(ss >> j, "[json.exception.parse_error.101] parse error at 1: syntax error - unexpected end of input; expected '[', '{', or a literal"); } @@ -722,7 +722,7 @@ TEST_CASE("regression tests") CHECK_NOTHROW(ss >> j); CHECK(j == json({{"three", 3}})); - CHECK_THROWS_AS(ss >> j, json::parse_error); + CHECK_THROWS_AS(ss >> j, json::parse_error&); CHECK_THROWS_WITH(ss >> j, "[json.exception.parse_error.101] parse error at 1: syntax error - unexpected end of input; expected '[', '{', or a literal"); } @@ -792,7 +792,7 @@ TEST_CASE("regression tests") { // original test case std::vector vec {0x65, 0xf5, 0x0a, 0x48, 0x21}; - CHECK_THROWS_AS(json::from_cbor(vec), json::parse_error); + CHECK_THROWS_AS(json::from_cbor(vec), json::parse_error&); CHECK_THROWS_WITH(json::from_cbor(vec), "[json.exception.parse_error.110] parse error at 6: unexpected end of input"); } @@ -801,31 +801,31 @@ TEST_CASE("regression tests") { // original test case: incomplete float64 std::vector vec1 {0xcb, 0x8f, 0x0a}; - CHECK_THROWS_AS(json::from_msgpack(vec1), json::parse_error); + CHECK_THROWS_AS(json::from_msgpack(vec1), json::parse_error&); CHECK_THROWS_WITH(json::from_msgpack(vec1), "[json.exception.parse_error.110] parse error at 4: unexpected end of input"); // related test case: incomplete float32 std::vector vec2 {0xca, 0x8f, 0x0a}; - CHECK_THROWS_AS(json::from_msgpack(vec2), json::parse_error); + CHECK_THROWS_AS(json::from_msgpack(vec2), json::parse_error&); CHECK_THROWS_WITH(json::from_msgpack(vec2), "[json.exception.parse_error.110] parse error at 4: unexpected end of input"); // related test case: incomplete Half-Precision Float (CBOR) std::vector vec3 {0xf9, 0x8f}; - CHECK_THROWS_AS(json::from_cbor(vec3), json::parse_error); + CHECK_THROWS_AS(json::from_cbor(vec3), json::parse_error&); CHECK_THROWS_WITH(json::from_cbor(vec3), "[json.exception.parse_error.110] parse error at 3: unexpected end of input"); // related test case: incomplete Single-Precision Float (CBOR) std::vector vec4 {0xfa, 0x8f, 0x0a}; - CHECK_THROWS_AS(json::from_cbor(vec4), json::parse_error); + CHECK_THROWS_AS(json::from_cbor(vec4), json::parse_error&); CHECK_THROWS_WITH(json::from_cbor(vec4), "[json.exception.parse_error.110] parse error at 4: unexpected end of input"); // related test case: incomplete Double-Precision Float (CBOR) std::vector vec5 {0xfb, 0x8f, 0x0a}; - CHECK_THROWS_AS(json::from_cbor(vec5), json::parse_error); + CHECK_THROWS_AS(json::from_cbor(vec5), json::parse_error&); CHECK_THROWS_WITH(json::from_cbor(vec5), "[json.exception.parse_error.110] parse error at 4: unexpected end of input"); } @@ -834,7 +834,7 @@ TEST_CASE("regression tests") { // original test case std::vector vec1 {0x87}; - CHECK_THROWS_AS(json::from_msgpack(vec1), json::parse_error); + CHECK_THROWS_AS(json::from_msgpack(vec1), json::parse_error&); CHECK_THROWS_WITH(json::from_msgpack(vec1), "[json.exception.parse_error.110] parse error at 2: unexpected end of input"); @@ -848,7 +848,7 @@ TEST_CASE("regression tests") }) { std::vector vec(1, static_cast(b)); - CHECK_THROWS_AS(json::from_msgpack(vec), json::parse_error); + CHECK_THROWS_AS(json::from_msgpack(vec), json::parse_error&); } // more test cases for CBOR @@ -863,15 +863,15 @@ TEST_CASE("regression tests") }) { std::vector vec(1, static_cast(b)); - CHECK_THROWS_AS(json::from_cbor(vec), json::parse_error); + CHECK_THROWS_AS(json::from_cbor(vec), json::parse_error&); } // special case: empty input std::vector vec2; - CHECK_THROWS_AS(json::from_cbor(vec2), json::parse_error); + CHECK_THROWS_AS(json::from_cbor(vec2), json::parse_error&); CHECK_THROWS_WITH(json::from_cbor(vec2), "[json.exception.parse_error.110] parse error at 1: unexpected end of input"); - CHECK_THROWS_AS(json::from_msgpack(vec2), json::parse_error); + CHECK_THROWS_AS(json::from_msgpack(vec2), json::parse_error&); CHECK_THROWS_WITH(json::from_msgpack(vec2), "[json.exception.parse_error.110] parse error at 1: unexpected end of input"); } @@ -880,19 +880,19 @@ TEST_CASE("regression tests") { // original test case: empty UTF-8 string (indefinite length) std::vector vec1 {0x7f}; - CHECK_THROWS_AS(json::from_cbor(vec1), json::parse_error); + CHECK_THROWS_AS(json::from_cbor(vec1), json::parse_error&); CHECK_THROWS_WITH(json::from_cbor(vec1), "[json.exception.parse_error.110] parse error at 2: unexpected end of input"); // related test case: empty array (indefinite length) std::vector vec2 {0x9f}; - CHECK_THROWS_AS(json::from_cbor(vec2), json::parse_error); + CHECK_THROWS_AS(json::from_cbor(vec2), json::parse_error&); CHECK_THROWS_WITH(json::from_cbor(vec2), "[json.exception.parse_error.110] parse error at 2: unexpected end of input"); // related test case: empty map (indefinite length) std::vector vec3 {0xbf}; - CHECK_THROWS_AS(json::from_cbor(vec3), json::parse_error); + CHECK_THROWS_AS(json::from_cbor(vec3), json::parse_error&); CHECK_THROWS_WITH(json::from_cbor(vec3), "[json.exception.parse_error.110] parse error at 2: unexpected end of input"); } @@ -920,25 +920,25 @@ TEST_CASE("regression tests") 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60 }; - CHECK_THROWS_AS(json::from_cbor(vec), json::parse_error); + CHECK_THROWS_AS(json::from_cbor(vec), json::parse_error&); CHECK_THROWS_WITH(json::from_cbor(vec), "[json.exception.parse_error.113] parse error at 2: expected a CBOR string; last byte: 0x98"); // related test case: nonempty UTF-8 string (indefinite length) std::vector vec1 {0x7f, 0x61, 0x61}; - CHECK_THROWS_AS(json::from_cbor(vec1), json::parse_error); + CHECK_THROWS_AS(json::from_cbor(vec1), json::parse_error&); CHECK_THROWS_WITH(json::from_cbor(vec1), "[json.exception.parse_error.110] parse error at 4: unexpected end of input"); // related test case: nonempty array (indefinite length) std::vector vec2 {0x9f, 0x01}; - CHECK_THROWS_AS(json::from_cbor(vec2), json::parse_error); + CHECK_THROWS_AS(json::from_cbor(vec2), json::parse_error&); CHECK_THROWS_WITH(json::from_cbor(vec2), "[json.exception.parse_error.110] parse error at 3: unexpected end of input"); // related test case: nonempty map (indefinite length) std::vector vec3 {0xbf, 0x61, 0x61, 0x01}; - CHECK_THROWS_AS(json::from_cbor(vec3), json::parse_error); + CHECK_THROWS_AS(json::from_cbor(vec3), json::parse_error&); CHECK_THROWS_WITH(json::from_cbor(vec3), "[json.exception.parse_error.110] parse error at 5: unexpected end of input"); } @@ -973,7 +973,7 @@ TEST_CASE("regression tests") 0x96, 0x96, 0xb4, 0xb4, 0xfa, 0x94, 0x94, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0xfa }; - CHECK_THROWS_AS(json::from_cbor(vec1), json::parse_error); + CHECK_THROWS_AS(json::from_cbor(vec1), json::parse_error&); CHECK_THROWS_WITH(json::from_cbor(vec1), "[json.exception.parse_error.113] parse error at 13: expected a CBOR string; last byte: 0xB4"); @@ -987,7 +987,7 @@ TEST_CASE("regression tests") 0x96, 0x96, 0xb4, 0xb4, 0xfa, 0x94, 0x94, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0xfb }; - CHECK_THROWS_AS(json::from_cbor(vec2), json::parse_error); + CHECK_THROWS_AS(json::from_cbor(vec2), json::parse_error&); CHECK_THROWS_WITH(json::from_cbor(vec2), "[json.exception.parse_error.113] parse error at 13: expected a CBOR string; last byte: 0xB4"); } @@ -995,7 +995,7 @@ TEST_CASE("regression tests") SECTION("issue #452 - Heap-buffer-overflow (OSS-Fuzz issue 585)") { std::vector vec = {'-', '0', '1', '2', '2', '7', '4'}; - CHECK_THROWS_AS(json::parse(vec), json::parse_error); + CHECK_THROWS_AS(json::parse(vec), json::parse_error&); } SECTION("issue #454 - doubles are printed as integers") @@ -1035,9 +1035,9 @@ TEST_CASE("regression tests") }; CHECK_NOTHROW(create(j_array)); - CHECK_THROWS_AS(create(j_number), json::type_error); + CHECK_THROWS_AS(create(j_number), json::type_error&); CHECK_THROWS_WITH(create(j_number), "[json.exception.type_error.302] type must be array, but is number"); - CHECK_THROWS_AS(create(j_null), json::type_error); + CHECK_THROWS_AS(create(j_null), json::type_error&); CHECK_THROWS_WITH(create(j_null), "[json.exception.type_error.302] type must be array, but is null"); } @@ -1049,9 +1049,9 @@ TEST_CASE("regression tests") }; CHECK_NOTHROW(create(j_array)); - CHECK_THROWS_AS(create(j_number), json::type_error); + CHECK_THROWS_AS(create(j_number), json::type_error&); CHECK_THROWS_WITH(create(j_number), "[json.exception.type_error.302] type must be array, but is number"); - CHECK_THROWS_AS(create(j_null), json::type_error); + CHECK_THROWS_AS(create(j_null), json::type_error&); CHECK_THROWS_WITH(create(j_null), "[json.exception.type_error.302] type must be array, but is null"); } @@ -1063,9 +1063,9 @@ TEST_CASE("regression tests") }; CHECK_NOTHROW(create(j_array)); - CHECK_THROWS_AS(create(j_number), json::type_error); + CHECK_THROWS_AS(create(j_number), json::type_error&); CHECK_THROWS_WITH(create(j_number), "[json.exception.type_error.302] type must be array, but is number"); - CHECK_THROWS_AS(create(j_null), json::type_error); + CHECK_THROWS_AS(create(j_null), json::type_error&); CHECK_THROWS_WITH(create(j_null), "[json.exception.type_error.302] type must be array, but is null"); } } @@ -1100,7 +1100,7 @@ TEST_CASE("regression tests") l.m_stream->setstate(std::ios_base::failbit); - CHECK_THROWS_AS(l.fill_line_buffer(), json::parse_error); + CHECK_THROWS_AS(l.fill_line_buffer(), json::parse_error&); CHECK_THROWS_WITH(l.fill_line_buffer(), "[json.exception.parse_error.111] parse error: bad input stream"); } @@ -1115,7 +1115,7 @@ TEST_CASE("regression tests") l.m_stream->setstate(std::ios_base::badbit); - CHECK_THROWS_AS(l.fill_line_buffer(), json::parse_error); + CHECK_THROWS_AS(l.fill_line_buffer(), json::parse_error&); CHECK_THROWS_WITH(l.fill_line_buffer(), "[json.exception.parse_error.111] parse error: bad input stream"); } } @@ -1179,7 +1179,7 @@ TEST_CASE("regression tests") SECTION("issue #575 - heap-buffer-overflow (OSS-Fuzz 1400)") { std::vector vec = {'"', '\\', '"', 'X', '"', '"'}; - CHECK_THROWS_AS(json::parse(vec), json::parse_error); + CHECK_THROWS_AS(json::parse(vec), json::parse_error&); } SECTION("issue #600 - how does one convert a map in Json back to std::map?") @@ -1244,7 +1244,7 @@ TEST_CASE("regression tests") CHECK(v[i] == j[i]); } - CHECK_THROWS_AS(json().get>(), json::type_error); + CHECK_THROWS_AS(json().get>(), json::type_error&); CHECK_THROWS_WITH(json().get>(), "[json.exception.type_error.302] type must be array, but is null"); } diff --git a/test/src/unit-testsuites.cpp b/test/src/unit-testsuites.cpp index d3dbaf4b..d281c679 100644 --- a/test/src/unit-testsuites.cpp +++ b/test/src/unit-testsuites.cpp @@ -78,7 +78,7 @@ TEST_CASE("compliance tests from json.org") { CAPTURE(filename); std::ifstream f(filename); - CHECK_THROWS_AS(json::parse(f), json::parse_error); + CHECK_THROWS_AS(json::parse(f), json::parse_error&); } } @@ -772,7 +772,7 @@ TEST_CASE("nst's JSONTestSuite") { CAPTURE(filename); std::ifstream f(filename); - CHECK_THROWS_AS(json::parse(f), json::parse_error); + CHECK_THROWS_AS(json::parse(f), json::parse_error&); } } @@ -848,7 +848,7 @@ TEST_CASE("nst's JSONTestSuite") CAPTURE(filename); std::ifstream f(filename); json j; - CHECK_THROWS_AS(f >> j, json::out_of_range); + CHECK_THROWS_AS(f >> j, json::out_of_range&); } } @@ -875,7 +875,7 @@ TEST_CASE("nst's JSONTestSuite") CAPTURE(filename); std::ifstream f(filename); json j; - CHECK_THROWS_AS(f >> j, json::parse_error); + CHECK_THROWS_AS(f >> j, json::parse_error&); } } } diff --git a/test/src/unit-unicode.cpp b/test/src/unit-unicode.cpp index 9d4d65ca..b51a1579 100644 --- a/test/src/unit-unicode.cpp +++ b/test/src/unit-unicode.cpp @@ -81,7 +81,7 @@ void check_utf8string(bool success_expected, int byte1, int byte2 = -1, int byte } else { - CHECK_THROWS_AS(json::parse(json_string), json::parse_error); + CHECK_THROWS_AS(json::parse(json_string), json::parse_error&); } } @@ -928,31 +928,31 @@ TEST_CASE("Unicode", "[hide]") { SECTION("incorrect surrogate values") { - CHECK_THROWS_AS(json::parse("\"\\uDC00\\uDC00\""), json::parse_error); + CHECK_THROWS_AS(json::parse("\"\\uDC00\\uDC00\""), json::parse_error&); CHECK_THROWS_WITH(json::parse("\"\\uDC00\\uDC00\""), "[json.exception.parse_error.101] parse error at 7: syntax error - invalid string: surrogate U+DC00..U+DFFF must follow U+D800..U+DBFF; last read: '\"\\uDC00'"); - CHECK_THROWS_AS(json::parse("\"\\uD7FF\\uDC00\""), json::parse_error); + CHECK_THROWS_AS(json::parse("\"\\uD7FF\\uDC00\""), json::parse_error&); CHECK_THROWS_WITH(json::parse("\"\\uD7FF\\uDC00\""), "[json.exception.parse_error.101] parse error at 13: syntax error - invalid string: surrogate U+DC00..U+DFFF must follow U+D800..U+DBFF; last read: '\"\\uD7FF\\uDC00'"); - CHECK_THROWS_AS(json::parse("\"\\uD800]\""), json::parse_error); + CHECK_THROWS_AS(json::parse("\"\\uD800]\""), json::parse_error&); CHECK_THROWS_WITH(json::parse("\"\\uD800]\""), "[json.exception.parse_error.101] parse error at 8: syntax error - invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF; last read: '\"\\uD800]'"); - CHECK_THROWS_AS(json::parse("\"\\uD800\\v\""), json::parse_error); + CHECK_THROWS_AS(json::parse("\"\\uD800\\v\""), json::parse_error&); CHECK_THROWS_WITH(json::parse("\"\\uD800\\v\""), "[json.exception.parse_error.101] parse error at 9: syntax error - invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF; last read: '\"\\uD800\\v'"); - CHECK_THROWS_AS(json::parse("\"\\uD800\\u123\""), json::parse_error); + CHECK_THROWS_AS(json::parse("\"\\uD800\\u123\""), json::parse_error&); CHECK_THROWS_WITH(json::parse("\"\\uD800\\u123\""), "[json.exception.parse_error.101] parse error at 13: syntax error - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\uD800\\u123\"'"); - CHECK_THROWS_AS(json::parse("\"\\uD800\\uDBFF\""), json::parse_error); + CHECK_THROWS_AS(json::parse("\"\\uD800\\uDBFF\""), json::parse_error&); CHECK_THROWS_WITH(json::parse("\"\\uD800\\uDBFF\""), "[json.exception.parse_error.101] parse error at 13: syntax error - invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF; last read: '\"\\uD800\\uDBFF'"); - CHECK_THROWS_AS(json::parse("\"\\uD800\\uE000\""), json::parse_error); + CHECK_THROWS_AS(json::parse("\"\\uD800\\uE000\""), json::parse_error&); CHECK_THROWS_WITH(json::parse("\"\\uD800\\uE000\""), "[json.exception.parse_error.101] parse error at 13: syntax error - invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF; last read: '\"\\uD800\\uE000'"); } @@ -969,7 +969,7 @@ TEST_CASE("Unicode", "[hide]") { std::string json_text = "\"" + codepoint_to_unicode(cp) + "\""; CAPTURE(json_text); - CHECK_THROWS_AS(json::parse(json_text), json::parse_error); + CHECK_THROWS_AS(json::parse(json_text), json::parse_error&); } } @@ -988,7 +988,7 @@ TEST_CASE("Unicode", "[hide]") std::string json_text = "\"" + codepoint_to_unicode(cp1) + codepoint_to_unicode(cp2) + "\""; CAPTURE(json_text); - CHECK_THROWS_AS(json::parse(json_text), json::parse_error); + CHECK_THROWS_AS(json::parse(json_text), json::parse_error&); } } } @@ -1001,7 +1001,7 @@ TEST_CASE("Unicode", "[hide]") { std::string json_text = "\"" + codepoint_to_unicode(cp) + "\""; CAPTURE(json_text); - CHECK_THROWS_AS(json::parse(json_text), json::parse_error); + CHECK_THROWS_AS(json::parse(json_text), json::parse_error&); } } @@ -1072,7 +1072,7 @@ TEST_CASE("Unicode", "[hide]") SECTION("error for incomplete/wrong BOM") { - CHECK_THROWS_AS(json::parse("\xef\xbb"), json::parse_error); - CHECK_THROWS_AS(json::parse("\xef\xbb\xbb"), json::parse_error); + CHECK_THROWS_AS(json::parse("\xef\xbb"), json::parse_error&); + CHECK_THROWS_AS(json::parse("\xef\xbb\xbb"), json::parse_error&); } } diff --git a/test/thirdparty/catch/catch.hpp b/test/thirdparty/catch/catch.hpp index 362f8693..7c351e93 100644 --- a/test/thirdparty/catch/catch.hpp +++ b/test/thirdparty/catch/catch.hpp @@ -1,17 +1,17 @@ /* - * Catch v2.0.1 - * Generated: 2017-11-03 11:53:39.642003 + * Catch v1.9.7 + * Generated: 2017-08-10 23:49:15.233907 * ---------------------------------------------------------- * This file has been merged from multiple headers. Please don't edit it directly - * Copyright (c) 2017 Two Blue Cubes Ltd. All rights reserved. + * Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved. * * Distributed under the Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */ #ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED #define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED -// start catch.hpp +#define TWOBLUECUBES_CATCH_HPP_INCLUDED #ifdef __clang__ # pragma clang system_header @@ -19,7 +19,7 @@ # pragma GCC system_header #endif -// start catch_suppress_warnings.h +// #included from: internal/catch_suppress_warnings.h #ifdef __clang__ # ifdef __ICC // icpc defines the __clang__ macro @@ -32,6 +32,8 @@ # pragma clang diagnostic ignored "-Wunused-variable" # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wpadded" +# pragma clang diagnostic ignored "-Wc++98-compat" +# pragma clang diagnostic ignored "-Wc++98-compat-pedantic" # pragma clang diagnostic ignored "-Wswitch-enum" # pragma clang diagnostic ignored "-Wcovered-switch-default" # endif @@ -43,33 +45,10 @@ # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wpadded" #endif -// end catch_suppress_warnings.h #if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER) # define CATCH_IMPL -# define CATCH_CONFIG_EXTERNAL_INTERFACES -# if defined(CATCH_CONFIG_DISABLE_MATCHERS) -# undef CATCH_CONFIG_DISABLE_MATCHERS -# endif #endif -// start catch_platform.h - -#ifdef __APPLE__ -# include -# if TARGET_OS_MAC == 1 -# define CATCH_PLATFORM_MAC -# elif TARGET_OS_IPHONE == 1 -# define CATCH_PLATFORM_IPHONE -# endif - -#elif defined(linux) || defined(__linux) || defined(__linux__) -# define CATCH_PLATFORM_LINUX - -#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) -# define CATCH_PLATFORM_WINDOWS -#endif - -// end catch_platform.h #ifdef CATCH_IMPL # ifndef CLARA_CONFIG_MAIN # define CLARA_CONFIG_MAIN_NOT_DEFINED @@ -77,15 +56,32 @@ # endif #endif -// start catch_tag_alias_autoregistrar.h +// #included from: internal/catch_notimplemented_exception.h +#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_H_INCLUDED -// start catch_common.h +// #included from: catch_common.h +#define TWOBLUECUBES_CATCH_COMMON_H_INCLUDED -// start catch_compiler_capabilities.h +// #included from: catch_compiler_capabilities.h +#define TWOBLUECUBES_CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED -// Detect a number of compiler features - by compiler +// Detect a number of compiler features - mostly C++11/14 conformance - by compiler // The following features are defined: // +// CATCH_CONFIG_CPP11_NULLPTR : is nullptr supported? +// CATCH_CONFIG_CPP11_NOEXCEPT : is noexcept supported? +// CATCH_CONFIG_CPP11_GENERATED_METHODS : The delete and default keywords for compiler generated methods +// CATCH_CONFIG_CPP11_IS_ENUM : std::is_enum is supported? +// CATCH_CONFIG_CPP11_TUPLE : std::tuple is supported +// CATCH_CONFIG_CPP11_LONG_LONG : is long long supported? +// CATCH_CONFIG_CPP11_OVERRIDE : is override supported? +// CATCH_CONFIG_CPP11_UNIQUE_PTR : is unique_ptr supported (otherwise use auto_ptr) +// CATCH_CONFIG_CPP11_SHUFFLE : is std::shuffle supported? +// CATCH_CONFIG_CPP11_TYPE_TRAITS : are type_traits and enable_if supported? + +// CATCH_CONFIG_CPP11_OR_GREATER : Is C++11 supported? + +// CATCH_CONFIG_VARIADIC_MACROS : are variadic macros supported? // CATCH_CONFIG_COUNTER : is the __COUNTER__ macro supported? // CATCH_CONFIG_WINDOWS_SEH : is Windows SEH supported? // CATCH_CONFIG_POSIX_SIGNALS : are POSIX signals supported? @@ -95,12 +91,18 @@ // **************** // In general each macro has a _NO_ form -// (e.g. CATCH_CONFIG_NO_POSIX_SIGNALS) which disables the feature. +// (e.g. CATCH_CONFIG_CPP11_NO_NULLPTR) which disables the feature. // Many features, at point of detection, define an _INTERNAL_ macro, so they // can be combined, en-mass, with the _NO_ forms later. +// All the C++11 features can be disabled with CATCH_CONFIG_NO_CPP11 + #ifdef __cplusplus +# if __cplusplus >= 201103L +# define CATCH_CPP11_OR_GREATER +# endif + # if __cplusplus >= 201402L # define CATCH_CPP14_OR_GREATER # endif @@ -109,11 +111,19 @@ #ifdef __clang__ -# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ +# if __has_feature(cxx_nullptr) +# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR +# endif + +# if __has_feature(cxx_noexcept) +# define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT +# endif + +# if defined(CATCH_CPP11_OR_GREATER) +# define CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ _Pragma( "clang diagnostic push" ) \ - _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \ - _Pragma( "clang diagnostic ignored \"-Wglobal-constructors\"") -# define CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) +# define CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \ _Pragma( "clang diagnostic pop" ) # define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ @@ -121,6 +131,7 @@ _Pragma( "clang diagnostic ignored \"-Wparentheses\"" ) # define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \ _Pragma( "clang diagnostic pop" ) +# endif #endif // __clang__ @@ -149,34 +160,167 @@ #endif // __CYGWIN__ +//////////////////////////////////////////////////////////////////////////////// +// Borland +#ifdef __BORLANDC__ + +#endif // __BORLANDC__ + +//////////////////////////////////////////////////////////////////////////////// +// EDG +#ifdef __EDG_VERSION__ + +#endif // __EDG_VERSION__ + +//////////////////////////////////////////////////////////////////////////////// +// Digital Mars +#ifdef __DMC__ + +#endif // __DMC__ + +//////////////////////////////////////////////////////////////////////////////// +// GCC +#ifdef __GNUC__ + +# if __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__) +# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR +# endif + +// - otherwise more recent versions define __cplusplus >= 201103L +// and will get picked up below + +#endif // __GNUC__ + //////////////////////////////////////////////////////////////////////////////// // Visual C++ #ifdef _MSC_VER -// Universal Windows platform does not support SEH -// Or console colours (or console at all...) -# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) -# define CATCH_CONFIG_COLOUR_NONE -# else -# define CATCH_INTERNAL_CONFIG_WINDOWS_SEH -# endif +#define CATCH_INTERNAL_CONFIG_WINDOWS_SEH + +#if (_MSC_VER >= 1600) +# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR +# define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR +#endif + +#if (_MSC_VER >= 1900 ) // (VC++ 13 (VS2015)) +#define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT +#define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +#define CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE +#define CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS +#endif #endif // _MSC_VER //////////////////////////////////////////////////////////////////////////////// -// Use of __COUNTER__ is suppressed during code analysis in -// CLion/AppCode 2017.2.x and former, because __COUNTER__ is not properly -// handled by it. -// Otherwise all supported compilers support COUNTER macro, -// but user still might want to turn it off -#if ( !defined(__JETBRAINS_IDE__) || __JETBRAINS_IDE__ >= 20170300L ) - #define CATCH_INTERNAL_CONFIG_COUNTER +// Use variadic macros if the compiler supports them +#if ( defined _MSC_VER && _MSC_VER > 1400 && !defined __EDGE__) || \ + ( defined __WAVE__ && __WAVE_HAS_VARIADICS ) || \ + ( defined __GNUC__ && __GNUC__ >= 3 ) || \ + ( !defined __cplusplus && __STDC_VERSION__ >= 199901L || __cplusplus >= 201103L ) + +#define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS + #endif -#if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER) +// Use __COUNTER__ if the compiler supports it +#if ( defined _MSC_VER && _MSC_VER >= 1300 ) || \ + ( defined __GNUC__ && ( __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3 )) ) || \ + ( defined __clang__ && __clang_major__ >= 3 ) + +#define CATCH_INTERNAL_CONFIG_COUNTER + +#endif + +//////////////////////////////////////////////////////////////////////////////// +// C++ language feature support + +// catch all support for C++11 +#if defined(CATCH_CPP11_OR_GREATER) + +# if !defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR) +# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR +# endif + +# ifndef CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT +# define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT +# endif + +# ifndef CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +# define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +# endif + +# ifndef CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM +# define CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM +# endif + +# ifndef CATCH_INTERNAL_CONFIG_CPP11_TUPLE +# define CATCH_INTERNAL_CONFIG_CPP11_TUPLE +# endif + +# ifndef CATCH_INTERNAL_CONFIG_VARIADIC_MACROS +# define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS +# endif + +# if !defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG) +# define CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG +# endif + +# if !defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE) +# define CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE +# endif +# if !defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) +# define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR +# endif +# if !defined(CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE) +# define CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE +# endif +# if !defined(CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS) +# define CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS +# endif + +#endif // __cplusplus >= 201103L + +// Now set the actual defines based on the above + anything the user has configured +#if defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NO_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_NULLPTR +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NO_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_NOEXCEPT +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_NO_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_GENERATED_METHODS +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_NO_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_IS_ENUM +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_CPP11_NO_TUPLE) && !defined(CATCH_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_TUPLE +#endif +#if defined(CATCH_INTERNAL_CONFIG_VARIADIC_MACROS) && !defined(CATCH_CONFIG_NO_VARIADIC_MACROS) && !defined(CATCH_CONFIG_VARIADIC_MACROS) +# define CATCH_CONFIG_VARIADIC_MACROS +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_CPP11_NO_LONG_LONG) && !defined(CATCH_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_LONG_LONG +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_CPP11_NO_OVERRIDE) && !defined(CATCH_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_OVERRIDE +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_CPP11_NO_UNIQUE_PTR) && !defined(CATCH_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_UNIQUE_PTR +#endif +// Use of __COUNTER__ is suppressed if __JETBRAINS_IDE__ is #defined (meaning we're being parsed by a JetBrains IDE for +// analytics) because, at time of writing, __COUNTER__ is not properly handled by it. +// This does not affect compilation +#if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER) && !defined(__JETBRAINS_IDE__) # define CATCH_CONFIG_COUNTER #endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE) && !defined(CATCH_CONFIG_CPP11_NO_SHUFFLE) && !defined(CATCH_CONFIG_CPP11_SHUFFLE) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_SHUFFLE +#endif +# if defined(CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS) && !defined(CATCH_CONFIG_CPP11_NO_TYPE_TRAITS) && !defined(CATCH_CONFIG_CPP11_TYPE_TRAITS) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_TYPE_TRAITS +# endif #if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH) # define CATCH_CONFIG_WINDOWS_SEH #endif @@ -189,12 +333,41 @@ # define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS # define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS #endif -#if !defined(CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS) -# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS -# define CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS +#if !defined(CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS +# define CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS +#endif + +// noexcept support: +#if defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_NOEXCEPT) +# define CATCH_NOEXCEPT noexcept +# define CATCH_NOEXCEPT_IS(x) noexcept(x) +#else +# define CATCH_NOEXCEPT throw() +# define CATCH_NOEXCEPT_IS(x) +#endif + +// nullptr support +#ifdef CATCH_CONFIG_CPP11_NULLPTR +# define CATCH_NULL nullptr +#else +# define CATCH_NULL NULL +#endif + +// override support +#ifdef CATCH_CONFIG_CPP11_OVERRIDE +# define CATCH_OVERRIDE override +#else +# define CATCH_OVERRIDE +#endif + +// unique_ptr support +#ifdef CATCH_CONFIG_CPP11_UNIQUE_PTR +# define CATCH_AUTO_PTR( T ) std::unique_ptr +#else +# define CATCH_AUTO_PTR( T ) std::auto_ptr #endif -// end catch_compiler_capabilities.h #define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line #define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) #ifdef CATCH_CONFIG_COUNTER @@ -203,41 +376,95 @@ # define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) #endif -#include -#include -#include +#define INTERNAL_CATCH_STRINGIFY2( expr ) #expr +#define INTERNAL_CATCH_STRINGIFY( expr ) INTERNAL_CATCH_STRINGIFY2( expr ) + +#include +#include namespace Catch { + struct IConfig; + struct CaseSensitive { enum Choice { Yes, No }; }; class NonCopyable { +#ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS NonCopyable( NonCopyable const& ) = delete; NonCopyable( NonCopyable && ) = delete; NonCopyable& operator = ( NonCopyable const& ) = delete; NonCopyable& operator = ( NonCopyable && ) = delete; +#else + NonCopyable( NonCopyable const& info ); + NonCopyable& operator = ( NonCopyable const& ); +#endif protected: - NonCopyable(); + NonCopyable() {} virtual ~NonCopyable(); }; + class SafeBool { + public: + typedef void (SafeBool::*type)() const; + + static type makeSafe( bool value ) { + return value ? &SafeBool::trueValue : 0; + } + private: + void trueValue() const {} + }; + + template + void deleteAll( ContainerT& container ) { + typename ContainerT::const_iterator it = container.begin(); + typename ContainerT::const_iterator itEnd = container.end(); + for(; it != itEnd; ++it ) + delete *it; + } + template + void deleteAllValues( AssociativeContainerT& container ) { + typename AssociativeContainerT::const_iterator it = container.begin(); + typename AssociativeContainerT::const_iterator itEnd = container.end(); + for(; it != itEnd; ++it ) + delete it->second; + } + + bool startsWith( std::string const& s, std::string const& prefix ); + bool startsWith( std::string const& s, char prefix ); + bool endsWith( std::string const& s, std::string const& suffix ); + bool endsWith( std::string const& s, char suffix ); + bool contains( std::string const& s, std::string const& infix ); + void toLowerInPlace( std::string& s ); + std::string toLower( std::string const& s ); + std::string trim( std::string const& str ); + bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ); + + struct pluralise { + pluralise( std::size_t count, std::string const& label ); + + friend std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ); + + std::size_t m_count; + std::string m_label; + }; + struct SourceLineInfo { - SourceLineInfo() = delete; - SourceLineInfo( char const* _file, std::size_t _line ) noexcept; - - SourceLineInfo( SourceLineInfo const& other ) = default; + SourceLineInfo(); + SourceLineInfo( char const* _file, std::size_t _line ); +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + SourceLineInfo(SourceLineInfo const& other) = default; SourceLineInfo( SourceLineInfo && ) = default; SourceLineInfo& operator = ( SourceLineInfo const& ) = default; SourceLineInfo& operator = ( SourceLineInfo && ) = default; - - bool empty() const noexcept; - bool operator == ( SourceLineInfo const& other ) const noexcept; - bool operator < ( SourceLineInfo const& other ) const noexcept; +# endif + bool empty() const; + bool operator == ( SourceLineInfo const& other ) const; + bool operator < ( SourceLineInfo const& other ) const; char const* file; std::size_t line; @@ -246,16 +473,23 @@ namespace Catch { std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ); // This is just here to avoid compiler warnings with macro constants and boolean literals - bool isTrue( bool value ); - bool alwaysTrue(); - bool alwaysFalse(); + inline bool isTrue( bool value ){ return value; } + inline bool alwaysTrue() { return true; } + inline bool alwaysFalse() { return false; } + + void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ); + + void seedRng( IConfig const& config ); + unsigned int rngSeed(); // Use this in variadic streaming macros to allow // >> +StreamEndStop // as well as // >> stuff +StreamEndStop struct StreamEndStop { - std::string operator+() const; + std::string operator+() { + return std::string(); + } }; template T const& operator + ( T const& value, StreamEndStop ) { @@ -263,39 +497,193 @@ namespace Catch { } } -#define CATCH_INTERNAL_LINEINFO \ - ::Catch::SourceLineInfo( __FILE__, static_cast( __LINE__ ) ) +#define CATCH_INTERNAL_LINEINFO ::Catch::SourceLineInfo( __FILE__, static_cast( __LINE__ ) ) +#define CATCH_INTERNAL_ERROR( msg ) ::Catch::throwLogicError( msg, CATCH_INTERNAL_LINEINFO ); -// end catch_common.h namespace Catch { - struct RegistrarForTagAliases { - RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); + class NotImplementedException : public std::exception + { + public: + NotImplementedException( SourceLineInfo const& lineInfo ); + + virtual ~NotImplementedException() CATCH_NOEXCEPT {} + + virtual const char* what() const CATCH_NOEXCEPT; + + private: + std::string m_what; + SourceLineInfo m_lineInfo; }; } // end namespace Catch -#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } +/////////////////////////////////////////////////////////////////////////////// +#define CATCH_NOT_IMPLEMENTED throw Catch::NotImplementedException( CATCH_INTERNAL_LINEINFO ) -// end catch_tag_alias_autoregistrar.h -// start catch_test_registry.h +// #included from: internal/catch_context.h +#define TWOBLUECUBES_CATCH_CONTEXT_H_INCLUDED -// start catch_interfaces_testcase.h +// #included from: catch_interfaces_generators.h +#define TWOBLUECUBES_CATCH_INTERFACES_GENERATORS_H_INCLUDED + +#include + +namespace Catch { + + struct IGeneratorInfo { + virtual ~IGeneratorInfo(); + virtual bool moveNext() = 0; + virtual std::size_t getCurrentIndex() const = 0; + }; + + struct IGeneratorsForTest { + virtual ~IGeneratorsForTest(); + + virtual IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) = 0; + virtual bool moveNext() = 0; + }; + + IGeneratorsForTest* createGeneratorsForTest(); + +} // end namespace Catch + +// #included from: catch_ptr.hpp +#define TWOBLUECUBES_CATCH_PTR_HPP_INCLUDED + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +namespace Catch { + + // An intrusive reference counting smart pointer. + // T must implement addRef() and release() methods + // typically implementing the IShared interface + template + class Ptr { + public: + Ptr() : m_p( CATCH_NULL ){} + Ptr( T* p ) : m_p( p ){ + if( m_p ) + m_p->addRef(); + } + Ptr( Ptr const& other ) : m_p( other.m_p ){ + if( m_p ) + m_p->addRef(); + } + ~Ptr(){ + if( m_p ) + m_p->release(); + } + void reset() { + if( m_p ) + m_p->release(); + m_p = CATCH_NULL; + } + Ptr& operator = ( T* p ){ + Ptr temp( p ); + swap( temp ); + return *this; + } + Ptr& operator = ( Ptr const& other ){ + Ptr temp( other ); + swap( temp ); + return *this; + } + void swap( Ptr& other ) { std::swap( m_p, other.m_p ); } + T* get() const{ return m_p; } + T& operator*() const { return *m_p; } + T* operator->() const { return m_p; } + bool operator !() const { return m_p == CATCH_NULL; } + operator SafeBool::type() const { return SafeBool::makeSafe( m_p != CATCH_NULL ); } + + private: + T* m_p; + }; + + struct IShared : NonCopyable { + virtual ~IShared(); + virtual void addRef() const = 0; + virtual void release() const = 0; + }; + + template + struct SharedImpl : T { + + SharedImpl() : m_rc( 0 ){} + + virtual void addRef() const { + ++m_rc; + } + virtual void release() const { + if( --m_rc == 0 ) + delete this; + } + + mutable unsigned int m_rc; + }; + +} // end namespace Catch + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +namespace Catch { + + class TestCase; + class Stream; + struct IResultCapture; + struct IRunner; + struct IGeneratorsForTest; + struct IConfig; + + struct IContext + { + virtual ~IContext(); + + virtual IResultCapture* getResultCapture() = 0; + virtual IRunner* getRunner() = 0; + virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) = 0; + virtual bool advanceGeneratorsForCurrentTest() = 0; + virtual Ptr getConfig() const = 0; + }; + + struct IMutableContext : IContext + { + virtual ~IMutableContext(); + virtual void setResultCapture( IResultCapture* resultCapture ) = 0; + virtual void setRunner( IRunner* runner ) = 0; + virtual void setConfig( Ptr const& config ) = 0; + }; + + IContext& getCurrentContext(); + IMutableContext& getCurrentMutableContext(); + void cleanUpContext(); + Stream createStream( std::string const& streamName ); + +} + +// #included from: internal/catch_test_registry.hpp +#define TWOBLUECUBES_CATCH_TEST_REGISTRY_HPP_INCLUDED + +// #included from: catch_interfaces_testcase.h +#define TWOBLUECUBES_CATCH_INTERFACES_TESTCASE_H_INCLUDED #include -#include namespace Catch { class TestSpec; - struct ITestInvoker { + struct ITestCase : IShared { virtual void invoke () const = 0; - virtual ~ITestInvoker(); + protected: + virtual ~ITestCase(); }; - using ITestCasePtr = std::shared_ptr; - class TestCase; struct IConfig; @@ -311,180 +699,814 @@ namespace Catch { } -// end catch_interfaces_testcase.h -// start catch_stringref.h - -#include -#include -#include - -namespace Catch { - - class StringData; - - /// A non-owning string class (similar to the forthcoming std::string_view) - /// Note that, because a StringRef may be a substring of another string, - /// it may not be null terminated. c_str() must return a null terminated - /// string, however, and so the StringRef will internally take ownership - /// (taking a copy), if necessary. In theory this ownership is not externally - /// visible - but it does mean (substring) StringRefs should not be shared between - /// threads. - class StringRef { - friend struct StringRefTestAccess; - - using size_type = std::size_t; - - char const* m_start; - size_type m_size; - - char* m_data = nullptr; - - void takeOwnership(); - - public: // construction/ assignment - StringRef() noexcept; - StringRef( StringRef const& other ) noexcept; - StringRef( StringRef&& other ) noexcept; - StringRef( char const* rawChars ) noexcept; - StringRef( char const* rawChars, size_type size ) noexcept; - StringRef( std::string const& stdString ) noexcept; - ~StringRef() noexcept; - - auto operator = ( StringRef other ) noexcept -> StringRef&; - operator std::string() const; - - void swap( StringRef& other ) noexcept; - - public: // operators - auto operator == ( StringRef const& other ) const noexcept -> bool; - auto operator != ( StringRef const& other ) const noexcept -> bool; - - auto operator[] ( size_type index ) const noexcept -> char; - - public: // named queries - auto empty() const noexcept -> bool; - auto size() const noexcept -> size_type; - auto numberOfCharacters() const noexcept -> size_type; - auto c_str() const -> char const*; - - public: // substrings and searches - auto substr( size_type start, size_type size ) const noexcept -> StringRef; - - private: // ownership queries - may not be consistent between calls - auto isOwned() const noexcept -> bool; - auto isSubstring() const noexcept -> bool; - auto data() const noexcept -> char const*; - }; - - auto operator + ( StringRef const& lhs, StringRef const& rhs ) -> std::string; - auto operator + ( StringRef const& lhs, char const* rhs ) -> std::string; - auto operator + ( char const* lhs, StringRef const& rhs ) -> std::string; - - auto operator << ( std::ostream& os, StringRef const& sr ) -> std::ostream&; - -} // namespace Catch - -// end catch_stringref.h namespace Catch { template -class TestInvokerAsMethod : public ITestInvoker { - void (C::*m_testAsMethod)(); +class MethodTestCase : public SharedImpl { + public: - TestInvokerAsMethod( void (C::*testAsMethod)() ) noexcept : m_testAsMethod( testAsMethod ) {} + MethodTestCase( void (C::*method)() ) : m_method( method ) {} - void invoke() const override { + virtual void invoke() const { C obj; - (obj.*m_testAsMethod)(); + (obj.*m_method)(); } + +private: + virtual ~MethodTestCase() {} + + void (C::*m_method)(); }; -auto makeTestInvoker( void(*testAsFunction)() ) noexcept -> ITestInvoker*; +typedef void(*TestFunction)(); -template -auto makeTestInvoker( void (C::*testAsMethod)() ) noexcept -> ITestInvoker* { - return new(std::nothrow) TestInvokerAsMethod( testAsMethod ); -} +struct NameAndDesc { + NameAndDesc( const char* _name = "", const char* _description= "" ) + : name( _name ), description( _description ) + {} -struct NameAndTags { - NameAndTags( StringRef name_ = "", StringRef tags_ = "" ) noexcept; - StringRef name; - StringRef tags; + const char* name; + const char* description; }; -struct AutoReg : NonCopyable { - AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef classOrMethod, NameAndTags const& nameAndTags ) noexcept; +void registerTestCase + ( ITestCase* testCase, + char const* className, + NameAndDesc const& nameAndDesc, + SourceLineInfo const& lineInfo ); + +struct AutoReg { + + AutoReg + ( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ); + + template + AutoReg + ( void (C::*method)(), + char const* className, + NameAndDesc const& nameAndDesc, + SourceLineInfo const& lineInfo ) { + + registerTestCase + ( new MethodTestCase( method ), + className, + nameAndDesc, + lineInfo ); + } + ~AutoReg(); + +private: + AutoReg( AutoReg const& ); + void operator= ( AutoReg const& ); }; +void registerTestCaseFunction + ( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ); + } // end namespace Catch -#if defined(CATCH_CONFIG_DISABLE) - #define INTERNAL_CATCH_TESTCASE_NO_REGISTRATION( TestName, ... ) \ - static void TestName() - #define INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION( TestName, ClassName, ... ) \ - namespace{ \ - struct TestName : ClassName { \ - void test(); \ - }; \ - } \ - void TestName::test() - -#endif - +#ifdef CATCH_CONFIG_VARIADIC_MACROS /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TESTCASE2( TestName, ... ) \ static void TestName(); \ - CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ - namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &TestName ), CATCH_INTERNAL_LINEINFO, "", Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \ - CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \ + CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &TestName, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); } /* NOLINT */ \ + CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \ static void TestName() #define INTERNAL_CATCH_TESTCASE( ... ) \ INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), __VA_ARGS__ ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \ - CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ - namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &QualifiedMethod ), CATCH_INTERNAL_LINEINFO, "&" #QualifiedMethod, Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \ - CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS + CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); } /* NOLINT */ \ + CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TEST_CASE_METHOD2( TestName, ClassName, ... )\ - CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ namespace{ \ struct TestName : ClassName{ \ void test(); \ }; \ - Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( Catch::makeTestInvoker( &TestName::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \ + Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &TestName::test, #ClassName, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); /* NOLINT */ \ } \ - CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \ + CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \ void TestName::test() #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... ) \ INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), ClassName, __VA_ARGS__ ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \ - CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ - Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( Function ), CATCH_INTERNAL_LINEINFO, "", Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \ - CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS + CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ + Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); /* NOLINT */ \ + CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS -// end catch_test_registry.h -// start catch_capture.hpp +#else + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_TESTCASE2( TestName, Name, Desc ) \ + static void TestName(); \ + CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &TestName, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); } /* NOLINT */ \ + CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \ + static void TestName() + #define INTERNAL_CATCH_TESTCASE( Name, Desc ) \ + INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), Name, Desc ) -// start catch_assertionhandler.h + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, Name, Desc ) \ + CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( Name, Desc ), CATCH_INTERNAL_LINEINFO ); } /* NOLINT */ \ + CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS -// start catch_decomposer.h + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_TEST_CASE_METHOD2( TestCaseName, ClassName, TestName, Desc )\ + CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ + namespace{ \ + struct TestCaseName : ClassName{ \ + void test(); \ + }; \ + Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &TestCaseName::test, #ClassName, Catch::NameAndDesc( TestName, Desc ), CATCH_INTERNAL_LINEINFO ); /* NOLINT */ \ + } \ + CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \ + void TestCaseName::test() + #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, TestName, Desc )\ + INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), ClassName, TestName, Desc ) -// start catch_tostring.h + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, Name, Desc ) \ + CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ + Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); /* NOLINT */ \ + CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS + +#endif + +// #included from: internal/catch_capture.hpp +#define TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED + +// #included from: catch_result_builder.h +#define TWOBLUECUBES_CATCH_RESULT_BUILDER_H_INCLUDED + +// #included from: catch_result_type.h +#define TWOBLUECUBES_CATCH_RESULT_TYPE_H_INCLUDED + +namespace Catch { + + // ResultWas::OfType enum + struct ResultWas { enum OfType { + Unknown = -1, + Ok = 0, + Info = 1, + Warning = 2, + + FailureBit = 0x10, + + ExpressionFailed = FailureBit | 1, + ExplicitFailure = FailureBit | 2, + + Exception = 0x100 | FailureBit, + + ThrewException = Exception | 1, + DidntThrowException = Exception | 2, + + FatalErrorCondition = 0x200 | FailureBit + + }; }; + + inline bool isOk( ResultWas::OfType resultType ) { + return ( resultType & ResultWas::FailureBit ) == 0; + } + inline bool isJustInfo( int flags ) { + return flags == ResultWas::Info; + } + + // ResultDisposition::Flags enum + struct ResultDisposition { enum Flags { + Normal = 0x01, + + ContinueOnFailure = 0x02, // Failures fail test, but execution continues + FalseTest = 0x04, // Prefix expression with ! + SuppressFail = 0x08 // Failures are reported but do not fail the test + }; }; + + inline ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) { + return static_cast( static_cast( lhs ) | static_cast( rhs ) ); + } + + inline bool shouldContinueOnFailure( int flags ) { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; } + inline bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; } + inline bool shouldSuppressFailure( int flags ) { return ( flags & ResultDisposition::SuppressFail ) != 0; } + +} // end namespace Catch + +// #included from: catch_assertionresult.h +#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_H_INCLUDED -#include -#include -#include -#include #include +namespace Catch { + + struct STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison; + + struct DecomposedExpression + { + virtual ~DecomposedExpression() {} + virtual bool isBinaryExpression() const { + return false; + } + virtual void reconstructExpression( std::string& dest ) const = 0; + + // Only simple binary comparisons can be decomposed. + // If more complex check is required then wrap sub-expressions in parentheses. + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator + ( T const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator - ( T const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator * ( T const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator / ( T const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator % ( T const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( T const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( T const& ); + + private: + DecomposedExpression& operator = (DecomposedExpression const&); + }; + + struct AssertionInfo + { + AssertionInfo(); + AssertionInfo( char const * _macroName, + SourceLineInfo const& _lineInfo, + char const * _capturedExpression, + ResultDisposition::Flags _resultDisposition, + char const * _secondArg = ""); + + char const * macroName; + SourceLineInfo lineInfo; + char const * capturedExpression; + ResultDisposition::Flags resultDisposition; + char const * secondArg; + }; + + struct AssertionResultData + { + AssertionResultData() : decomposedExpression( CATCH_NULL ) + , resultType( ResultWas::Unknown ) + , negated( false ) + , parenthesized( false ) {} + + void negate( bool parenthesize ) { + negated = !negated; + parenthesized = parenthesize; + if( resultType == ResultWas::Ok ) + resultType = ResultWas::ExpressionFailed; + else if( resultType == ResultWas::ExpressionFailed ) + resultType = ResultWas::Ok; + } + + std::string const& reconstructExpression() const { + if( decomposedExpression != CATCH_NULL ) { + decomposedExpression->reconstructExpression( reconstructedExpression ); + if( parenthesized ) { + reconstructedExpression.insert( 0, 1, '(' ); + reconstructedExpression.append( 1, ')' ); + } + if( negated ) { + reconstructedExpression.insert( 0, 1, '!' ); + } + decomposedExpression = CATCH_NULL; + } + return reconstructedExpression; + } + + mutable DecomposedExpression const* decomposedExpression; + mutable std::string reconstructedExpression; + std::string message; + ResultWas::OfType resultType; + bool negated; + bool parenthesized; + }; + + class AssertionResult { + public: + AssertionResult(); + AssertionResult( AssertionInfo const& info, AssertionResultData const& data ); + ~AssertionResult(); +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + AssertionResult( AssertionResult const& ) = default; + AssertionResult( AssertionResult && ) = default; + AssertionResult& operator = ( AssertionResult const& ) = default; + AssertionResult& operator = ( AssertionResult && ) = default; +# endif + + bool isOk() const; + bool succeeded() const; + ResultWas::OfType getResultType() const; + bool hasExpression() const; + bool hasMessage() const; + std::string getExpression() const; + std::string getExpressionInMacro() const; + bool hasExpandedExpression() const; + std::string getExpandedExpression() const; + std::string getMessage() const; + SourceLineInfo getSourceInfo() const; + std::string getTestMacroName() const; + void discardDecomposedExpression() const; + void expandDecomposedExpression() const; + + protected: + AssertionInfo m_info; + AssertionResultData m_resultData; + }; + +} // end namespace Catch + +// #included from: catch_matchers.hpp +#define TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED + +namespace Catch { +namespace Matchers { + namespace Impl { + + template struct MatchAllOf; + template struct MatchAnyOf; + template struct MatchNotOf; + + class MatcherUntypedBase { + public: + std::string toString() const { + if( m_cachedToString.empty() ) + m_cachedToString = describe(); + return m_cachedToString; + } + + protected: + virtual ~MatcherUntypedBase(); + virtual std::string describe() const = 0; + mutable std::string m_cachedToString; + private: + MatcherUntypedBase& operator = ( MatcherUntypedBase const& ); + }; + + template + struct MatcherMethod { + virtual bool match( ObjectT const& arg ) const = 0; + }; + template + struct MatcherMethod { + virtual bool match( PtrT* arg ) const = 0; + }; + + template + struct MatcherBase : MatcherUntypedBase, MatcherMethod { + + MatchAllOf operator && ( MatcherBase const& other ) const; + MatchAnyOf operator || ( MatcherBase const& other ) const; + MatchNotOf operator ! () const; + }; + + template + struct MatchAllOf : MatcherBase { + virtual bool match( ArgT const& arg ) const CATCH_OVERRIDE { + for( std::size_t i = 0; i < m_matchers.size(); ++i ) { + if (!m_matchers[i]->match(arg)) + return false; + } + return true; + } + virtual std::string describe() const CATCH_OVERRIDE { + std::string description; + description.reserve( 4 + m_matchers.size()*32 ); + description += "( "; + for( std::size_t i = 0; i < m_matchers.size(); ++i ) { + if( i != 0 ) + description += " and "; + description += m_matchers[i]->toString(); + } + description += " )"; + return description; + } + + MatchAllOf& operator && ( MatcherBase const& other ) { + m_matchers.push_back( &other ); + return *this; + } + + std::vector const*> m_matchers; + }; + template + struct MatchAnyOf : MatcherBase { + + virtual bool match( ArgT const& arg ) const CATCH_OVERRIDE { + for( std::size_t i = 0; i < m_matchers.size(); ++i ) { + if (m_matchers[i]->match(arg)) + return true; + } + return false; + } + virtual std::string describe() const CATCH_OVERRIDE { + std::string description; + description.reserve( 4 + m_matchers.size()*32 ); + description += "( "; + for( std::size_t i = 0; i < m_matchers.size(); ++i ) { + if( i != 0 ) + description += " or "; + description += m_matchers[i]->toString(); + } + description += " )"; + return description; + } + + MatchAnyOf& operator || ( MatcherBase const& other ) { + m_matchers.push_back( &other ); + return *this; + } + + std::vector const*> m_matchers; + }; + + template + struct MatchNotOf : MatcherBase { + + MatchNotOf( MatcherBase const& underlyingMatcher ) : m_underlyingMatcher( underlyingMatcher ) {} + + virtual bool match( ArgT const& arg ) const CATCH_OVERRIDE { + return !m_underlyingMatcher.match( arg ); + } + + virtual std::string describe() const CATCH_OVERRIDE { + return "not " + m_underlyingMatcher.toString(); + } + MatcherBase const& m_underlyingMatcher; + }; + + template + MatchAllOf MatcherBase::operator && ( MatcherBase const& other ) const { + return MatchAllOf() && *this && other; + } + template + MatchAnyOf MatcherBase::operator || ( MatcherBase const& other ) const { + return MatchAnyOf() || *this || other; + } + template + MatchNotOf MatcherBase::operator ! () const { + return MatchNotOf( *this ); + } + + } // namespace Impl + + // The following functions create the actual matcher objects. + // This allows the types to be inferred + // - deprecated: prefer ||, && and ! + template + Impl::MatchNotOf Not( Impl::MatcherBase const& underlyingMatcher ) { + return Impl::MatchNotOf( underlyingMatcher ); + } + template + Impl::MatchAllOf AllOf( Impl::MatcherBase const& m1, Impl::MatcherBase const& m2 ) { + return Impl::MatchAllOf() && m1 && m2; + } + template + Impl::MatchAllOf AllOf( Impl::MatcherBase const& m1, Impl::MatcherBase const& m2, Impl::MatcherBase const& m3 ) { + return Impl::MatchAllOf() && m1 && m2 && m3; + } + template + Impl::MatchAnyOf AnyOf( Impl::MatcherBase const& m1, Impl::MatcherBase const& m2 ) { + return Impl::MatchAnyOf() || m1 || m2; + } + template + Impl::MatchAnyOf AnyOf( Impl::MatcherBase const& m1, Impl::MatcherBase const& m2, Impl::MatcherBase const& m3 ) { + return Impl::MatchAnyOf() || m1 || m2 || m3; + } + +} // namespace Matchers + +using namespace Matchers; +using Matchers::Impl::MatcherBase; + +} // namespace Catch + +namespace Catch { + + struct TestFailureException{}; + + template class ExpressionLhs; + + struct CopyableStream { + CopyableStream() {} + CopyableStream( CopyableStream const& other ) { + oss << other.oss.str(); + } + CopyableStream& operator=( CopyableStream const& other ) { + oss.str(std::string()); + oss << other.oss.str(); + return *this; + } + std::ostringstream oss; + }; + + class ResultBuilder : public DecomposedExpression { + public: + ResultBuilder( char const* macroName, + SourceLineInfo const& lineInfo, + char const* capturedExpression, + ResultDisposition::Flags resultDisposition, + char const* secondArg = "" ); + ~ResultBuilder(); + + template + ExpressionLhs operator <= ( T const& operand ); + ExpressionLhs operator <= ( bool value ); + + template + ResultBuilder& operator << ( T const& value ) { + stream().oss << value; + return *this; + } + + ResultBuilder& setResultType( ResultWas::OfType result ); + ResultBuilder& setResultType( bool result ); + + void endExpression( DecomposedExpression const& expr ); + + virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE; + + AssertionResult build() const; + AssertionResult build( DecomposedExpression const& expr ) const; + + void useActiveException( ResultDisposition::Flags resultDisposition = ResultDisposition::Normal ); + void captureResult( ResultWas::OfType resultType ); + void captureExpression(); + void captureExpectedException( std::string const& expectedMessage ); + void captureExpectedException( Matchers::Impl::MatcherBase const& matcher ); + void handleResult( AssertionResult const& result ); + void react(); + bool shouldDebugBreak() const; + bool allowThrows() const; + + template + void captureMatch( ArgT const& arg, MatcherT const& matcher, char const* matcherString ); + + void setExceptionGuard(); + void unsetExceptionGuard(); + + private: + AssertionInfo m_assertionInfo; + AssertionResultData m_data; + + CopyableStream &stream() + { + if(!m_usedStream) + { + m_usedStream = true; + m_stream().oss.str(""); + } + return m_stream(); + } + + static CopyableStream &m_stream() + { + static CopyableStream s; + return s; + } + + bool m_shouldDebugBreak; + bool m_shouldThrow; + bool m_guardException; + bool m_usedStream; + }; + +} // namespace Catch + +// Include after due to circular dependency: +// #included from: catch_expression_lhs.hpp +#define TWOBLUECUBES_CATCH_EXPRESSION_LHS_HPP_INCLUDED + +// #included from: catch_evaluate.hpp +#define TWOBLUECUBES_CATCH_EVALUATE_HPP_INCLUDED + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4389) // '==' : signed/unsigned mismatch +#pragma warning(disable:4312) // Converting int to T* using reinterpret_cast (issue on x64 platform) +#endif + +#include + +namespace Catch { +namespace Internal { + + enum Operator { + IsEqualTo, + IsNotEqualTo, + IsLessThan, + IsGreaterThan, + IsLessThanOrEqualTo, + IsGreaterThanOrEqualTo + }; + + template struct OperatorTraits { static const char* getName(){ return "*error*"; } }; + template<> struct OperatorTraits { static const char* getName(){ return "=="; } }; + template<> struct OperatorTraits { static const char* getName(){ return "!="; } }; + template<> struct OperatorTraits { static const char* getName(){ return "<"; } }; + template<> struct OperatorTraits { static const char* getName(){ return ">"; } }; + template<> struct OperatorTraits { static const char* getName(){ return "<="; } }; + template<> struct OperatorTraits{ static const char* getName(){ return ">="; } }; + + template + T& opCast(T const& t) { return const_cast(t); } + +// nullptr_t support based on pull request #154 from Konstantin Baumann +#ifdef CATCH_CONFIG_CPP11_NULLPTR + inline std::nullptr_t opCast(std::nullptr_t) { return nullptr; } +#endif // CATCH_CONFIG_CPP11_NULLPTR + + // So the compare overloads can be operator agnostic we convey the operator as a template + // enum, which is used to specialise an Evaluator for doing the comparison. + template + struct Evaluator{}; + + template + struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs) { + return bool( opCast( lhs ) == opCast( rhs ) ); + } + }; + template + struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return bool( opCast( lhs ) != opCast( rhs ) ); + } + }; + template + struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return bool( opCast( lhs ) < opCast( rhs ) ); + } + }; + template + struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return bool( opCast( lhs ) > opCast( rhs ) ); + } + }; + template + struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return bool( opCast( lhs ) >= opCast( rhs ) ); + } + }; + template + struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return bool( opCast( lhs ) <= opCast( rhs ) ); + } + }; + + template + bool applyEvaluator( T1 const& lhs, T2 const& rhs ) { + return Evaluator::evaluate( lhs, rhs ); + } + + // This level of indirection allows us to specialise for integer types + // to avoid signed/ unsigned warnings + + // "base" overload + template + bool compare( T1 const& lhs, T2 const& rhs ) { + return Evaluator::evaluate( lhs, rhs ); + } + + // unsigned X to int + template bool compare( unsigned int lhs, int rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); + } + template bool compare( unsigned long lhs, int rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); + } + template bool compare( unsigned char lhs, int rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); + } + + // unsigned X to long + template bool compare( unsigned int lhs, long rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); + } + template bool compare( unsigned long lhs, long rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); + } + template bool compare( unsigned char lhs, long rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); + } + + // int to unsigned X + template bool compare( int lhs, unsigned int rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( int lhs, unsigned long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( int lhs, unsigned char rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + + // long to unsigned X + template bool compare( long lhs, unsigned int rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( long lhs, unsigned long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( long lhs, unsigned char rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + + // pointer to long (when comparing against NULL) + template bool compare( long lhs, T* rhs ) { + return Evaluator::evaluate( reinterpret_cast( lhs ), rhs ); + } + template bool compare( T* lhs, long rhs ) { + return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); + } + + // pointer to int (when comparing against NULL) + template bool compare( int lhs, T* rhs ) { + return Evaluator::evaluate( reinterpret_cast( lhs ), rhs ); + } + template bool compare( T* lhs, int rhs ) { + return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); + } + +#ifdef CATCH_CONFIG_CPP11_LONG_LONG + // long long to unsigned X + template bool compare( long long lhs, unsigned int rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( long long lhs, unsigned long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( long long lhs, unsigned long long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( long long lhs, unsigned char rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + + // unsigned long long to X + template bool compare( unsigned long long lhs, int rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( unsigned long long lhs, long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( unsigned long long lhs, long long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( unsigned long long lhs, char rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + + // pointer to long long (when comparing against NULL) + template bool compare( long long lhs, T* rhs ) { + return Evaluator::evaluate( reinterpret_cast( lhs ), rhs ); + } + template bool compare( T* lhs, long long rhs ) { + return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); + } +#endif // CATCH_CONFIG_CPP11_LONG_LONG + +#ifdef CATCH_CONFIG_CPP11_NULLPTR + // pointer to nullptr_t (when comparing against nullptr) + template bool compare( std::nullptr_t, T* rhs ) { + return Evaluator::evaluate( nullptr, rhs ); + } + template bool compare( T* lhs, std::nullptr_t ) { + return Evaluator::evaluate( lhs, nullptr ); + } +#endif // CATCH_CONFIG_CPP11_NULLPTR + +} // end of namespace Internal +} // end of namespace Catch + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +// #included from: catch_tostring.h +#define TWOBLUECUBES_CATCH_TOSTRING_H_INCLUDED + +#include +#include +#include +#include +#include + #ifdef __OBJC__ -// start catch_objc_arc.hpp +// #included from: catch_objc_arc.hpp +#define TWOBLUECUBES_CATCH_OBJC_ARC_HPP_INCLUDED #import @@ -526,735 +1548,451 @@ inline id performOptionalSelector( id obj, SEL sel ) { #define CATCH_ARC_STRONG __strong #endif -// end catch_objc_arc.hpp #endif -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable:4180) // We attempt to stream a function (address) by const&, which MSVC complains about but is harmless +#ifdef CATCH_CONFIG_CPP11_TUPLE +#include #endif -// We need a dummy global operator<< so we can bring it into Catch namespace later -struct Catch_global_namespace_dummy; -std::ostream& operator<<(std::ostream&, Catch_global_namespace_dummy); +#ifdef CATCH_CONFIG_CPP11_IS_ENUM +#include +#endif namespace Catch { - // Bring in operator<< from global namespace into Catch namespace - using ::operator<<; - namespace Detail { +// Why we're here. +template +std::string toString( T const& value ); - extern const std::string unprintableString; +// Built in overloads - std::string rawMemoryToString( const void *object, std::size_t size ); +std::string toString( std::string const& value ); +std::string toString( std::wstring const& value ); +std::string toString( const char* const value ); +std::string toString( char* const value ); +std::string toString( const wchar_t* const value ); +std::string toString( wchar_t* const value ); +std::string toString( int value ); +std::string toString( unsigned long value ); +std::string toString( unsigned int value ); +std::string toString( const double value ); +std::string toString( const float value ); +std::string toString( bool value ); +std::string toString( char value ); +std::string toString( signed char value ); +std::string toString( unsigned char value ); - template - std::string rawMemoryToString( const T& object ) { - return rawMemoryToString( &object, sizeof(object) ); - } +#ifdef CATCH_CONFIG_CPP11_LONG_LONG +std::string toString( long long value ); +std::string toString( unsigned long long value ); +#endif - template - class IsStreamInsertable { - template - static auto test(int) - -> decltype(std::declval() << std::declval(), std::true_type()); - - template - static auto test(...)->std::false_type; - - public: - static const bool value = decltype(test(0))::value; - }; - - } // namespace Detail - - // If we decide for C++14, change these to enable_if_ts - template - struct StringMaker { - template - static - typename std::enable_if<::Catch::Detail::IsStreamInsertable::value, std::string>::type - convert(const Fake& t) { - std::ostringstream sstr; - sstr << t; - return sstr.str(); - } - - template - static - typename std::enable_if::value, std::string>::type - convert(const Fake&) { - return Detail::unprintableString; - } - }; - - namespace Detail { - - // This function dispatches all stringification requests inside of Catch. - // Should be preferably called fully qualified, like ::Catch::Detail::stringify - template - std::string stringify(const T& e) { - return ::Catch::StringMaker::type>::type>::convert(e); - } - - } // namespace Detail - - // Some predefined specializations - - template<> - struct StringMaker { - static std::string convert(const std::string& str); - }; - template<> - struct StringMaker { - static std::string convert(const std::wstring& wstr); - }; - - template<> - struct StringMaker { - static std::string convert(char const * str); - }; - template<> - struct StringMaker { - static std::string convert(char * str); - }; - template<> - struct StringMaker { - static std::string convert(wchar_t const * str); - }; - template<> - struct StringMaker { - static std::string convert(wchar_t * str); - }; - - template - struct StringMaker { - static std::string convert(const char* str) { - return ::Catch::Detail::stringify(std::string{ str }); - } - }; - template - struct StringMaker { - static std::string convert(const char* str) { - return ::Catch::Detail::stringify(std::string{ str }); - } - }; - template - struct StringMaker { - static std::string convert(const char* str) { - return ::Catch::Detail::stringify(std::string{ str }); - } - }; - - template<> - struct StringMaker { - static std::string convert(int value); - }; - template<> - struct StringMaker { - static std::string convert(long value); - }; - template<> - struct StringMaker { - static std::string convert(long long value); - }; - template<> - struct StringMaker { - static std::string convert(unsigned int value); - }; - template<> - struct StringMaker { - static std::string convert(unsigned long value); - }; - template<> - struct StringMaker { - static std::string convert(unsigned long long value); - }; - - template<> - struct StringMaker { - static std::string convert(bool b); - }; - - template<> - struct StringMaker { - static std::string convert(char c); - }; - template<> - struct StringMaker { - static std::string convert(signed char c); - }; - template<> - struct StringMaker { - static std::string convert(unsigned char c); - }; - - template<> - struct StringMaker { - static std::string convert(std::nullptr_t); - }; - - template<> - struct StringMaker { - static std::string convert(float value); - }; - template<> - struct StringMaker { - static std::string convert(double value); - }; - - template - struct StringMaker { - template - static std::string convert(U* p) { - if (p) { - return ::Catch::Detail::rawMemoryToString(p); - } else { - return "nullptr"; - } - } - }; - - template - struct StringMaker { - static std::string convert(R C::* p) { - if (p) { - return ::Catch::Detail::rawMemoryToString(p); - } else { - return "nullptr"; - } - } - }; - - namespace Detail { - template - std::string rangeToString(InputIterator first, InputIterator last) { - std::ostringstream oss; - oss << "{ "; - if (first != last) { - oss << ::Catch::Detail::stringify(*first); - for (++first; first != last; ++first) - oss << ", " << ::Catch::Detail::stringify(*first); - } - oss << " }"; - return oss.str(); - } - } - - template - struct StringMaker > { - static std::string convert( std::vector const& v ) { - return ::Catch::Detail::rangeToString( v.begin(), v.end() ); - } - }; - - template - struct EnumStringMaker { - static std::string convert(const T& t) { - return ::Catch::Detail::stringify(static_cast::type>(t)); - } - }; +#ifdef CATCH_CONFIG_CPP11_NULLPTR +std::string toString( std::nullptr_t ); +#endif #ifdef __OBJC__ - template<> - struct StringMaker { - static std::string convert(NSString * nsstring) { - if (!nsstring) - return "nil"; - return std::string("@") + [nsstring UTF8String]; - } - }; - template<> - struct StringMaker { - static std::string convert(NSObject* nsObject) { - return ::Catch::Detail::stringify([nsObject description]); - } - - }; - namespace Detail { - inline std::string stringify( NSString* nsstring ) { - return StringMaker::convert( nsstring ); - } - - } // namespace Detail -#endif // __OBJC__ - -} // namespace Catch - -////////////////////////////////////////////////////// -// Separate std-lib types stringification, so it can be selectively enabled -// This means that we do not bring in - -#if defined(CATCH_CONFIG_ENABLE_ALL_STRINGMAKERS) -# define CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER -# define CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER -# define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER + std::string toString( NSString const * const& nsstring ); + std::string toString( NSString * CATCH_ARC_STRONG & nsstring ); + std::string toString( NSObject* const& nsObject ); #endif -// Separate std::pair specialization -#if defined(CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER) -#include -namespace Catch { - template - struct StringMaker > { - static std::string convert(const std::pair& pair) { - std::ostringstream oss; - oss << "{ " - << ::Catch::Detail::stringify(pair.first) - << ", " - << ::Catch::Detail::stringify(pair.second) - << " }"; - return oss.str(); - } - }; -} -#endif // CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER +namespace Detail { -// Separate std::tuple specialization -#if defined(CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER) -#include -namespace Catch { - namespace Detail { - template< - typename Tuple, - std::size_t N = 0, - bool = (N < std::tuple_size::value) - > - struct TupleElementPrinter { - static void print(const Tuple& tuple, std::ostream& os) { - os << (N ? ", " : " ") - << ::Catch::Detail::stringify(std::get(tuple)); - TupleElementPrinter::print(tuple, os); - } - }; + extern const std::string unprintableString; - template< - typename Tuple, - std::size_t N - > - struct TupleElementPrinter { - static void print(const Tuple&, std::ostream&) {} - }; - - } - - template - struct StringMaker> { - static std::string convert(const std::tuple& tuple) { - std::ostringstream os; - os << '{'; - Detail::TupleElementPrinter>::print(tuple, os); - os << " }"; - return os.str(); - } - }; -} -#endif // CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER - -// Separate std::chrono::duration specialization -#if defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER) -#include -#include -#include - -template -struct ratio_string { - static std::string symbol(); -}; - -template -std::string ratio_string::symbol() { - std::ostringstream oss; - oss << '[' << Ratio::num << '/' - << Ratio::den << ']'; - return oss.str(); -} -template <> -struct ratio_string { - static std::string symbol() { return "a"; } -}; -template <> -struct ratio_string { - static std::string symbol() { return "f"; } -}; -template <> -struct ratio_string { - static std::string symbol() { return "p"; } -}; -template <> -struct ratio_string { - static std::string symbol() { return "n"; } -}; -template <> -struct ratio_string { - static std::string symbol() { return "u"; } -}; -template <> -struct ratio_string { - static std::string symbol() { return "m"; } -}; - -namespace Catch { - //////////// - // std::chrono::duration specializations - template - struct StringMaker> { - static std::string convert(std::chrono::duration const& duration) { - std::ostringstream oss; - oss << duration.count() << ' ' << ratio_string::symbol() << 's'; - return oss.str(); - } - }; - template - struct StringMaker>> { - static std::string convert(std::chrono::duration> const& duration) { - std::ostringstream oss; - oss << duration.count() << " s"; - return oss.str(); - } - }; - template - struct StringMaker>> { - static std::string convert(std::chrono::duration> const& duration) { - std::ostringstream oss; - oss << duration.count() << " m"; - return oss.str(); - } - }; - template - struct StringMaker>> { - static std::string convert(std::chrono::duration> const& duration) { - std::ostringstream oss; - oss << duration.count() << " h"; - return oss.str(); - } + #if !defined(CATCH_CONFIG_CPP11_STREAM_INSERTABLE_CHECK) + struct BorgType { + template BorgType( T const& ); }; - //////////// - // std::chrono::time_point specialization - // Generic time_point cannot be specialized, only std::chrono::time_point - template - struct StringMaker> { - static std::string convert(std::chrono::time_point const& time_point) { - return ::Catch::Detail::stringify(time_point.time_since_epoch()) + " since epoch"; - } - }; - // std::chrono::time_point specialization - template - struct StringMaker> { - static std::string convert(std::chrono::time_point const& time_point) { - auto converted = std::chrono::system_clock::to_time_t(time_point); + struct TrueType { char sizer[1]; }; + struct FalseType { char sizer[2]; }; -#ifdef _MSC_VER - std::tm timeInfo = {}; - gmtime_s(&timeInfo, &converted); + TrueType& testStreamable( std::ostream& ); + FalseType testStreamable( FalseType ); + + FalseType operator<<( std::ostream const&, BorgType const& ); + + template + struct IsStreamInsertable { + static std::ostream &s; + static T const&t; + enum { value = sizeof( testStreamable(s << t) ) == sizeof( TrueType ) }; + }; #else - std::tm* timeInfo = std::gmtime(&converted); -#endif + template + class IsStreamInsertable { + template + static auto test(int) + -> decltype( std::declval() << std::declval(), std::true_type() ); - auto const timeStampSize = sizeof("2017-01-16T17:06:45Z"); - char timeStamp[timeStampSize]; - const char * const fmt = "%Y-%m-%dT%H:%M:%SZ"; - -#ifdef _MSC_VER - std::strftime(timeStamp, timeStampSize, fmt, &timeInfo); -#else - std::strftime(timeStamp, timeStampSize, fmt, timeInfo); -#endif - return std::string(timeStamp); - } - }; -} -#endif // CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER - -#ifdef _MSC_VER -#pragma warning(pop) -#endif - -// end catch_tostring.h -#include - -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable:4389) // '==' : signed/unsigned mismatch -#pragma warning(disable:4018) // more "signed/unsigned mismatch" -#pragma warning(disable:4312) // Converting int to T* using reinterpret_cast (issue on x64 platform) -#pragma warning(disable:4180) // qualifier applied to function type has no meaning -#endif - -namespace Catch { - - struct ITransientExpression { - virtual auto isBinaryExpression() const -> bool = 0; - virtual auto getResult() const -> bool = 0; - virtual void streamReconstructedExpression( std::ostream &os ) const = 0; - - // We don't actually need a virtual destructore, but many static analysers - // complain if it's not here :-( - virtual ~ITransientExpression(); - }; - - void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs ); - - template - class BinaryExpr : public ITransientExpression { - bool m_result; - LhsT m_lhs; - StringRef m_op; - RhsT m_rhs; - - auto isBinaryExpression() const -> bool override { return true; } - auto getResult() const -> bool override { return m_result; } - - void streamReconstructedExpression( std::ostream &os ) const override { - formatReconstructedExpression - ( os, Catch::Detail::stringify( m_lhs ), m_op, Catch::Detail::stringify( m_rhs ) ); - } + template + static auto test(...) -> std::false_type; public: - BinaryExpr( bool comparisonResult, LhsT lhs, StringRef op, RhsT rhs ) - : m_result( comparisonResult ), - m_lhs( lhs ), - m_op( op ), - m_rhs( rhs ) - {} + static const bool value = decltype(test(0))::value; }; - - template - class UnaryExpr : public ITransientExpression { - LhsT m_lhs; - - auto isBinaryExpression() const -> bool override { return false; } - auto getResult() const -> bool override { return m_lhs ? true : false; } - - void streamReconstructedExpression( std::ostream &os ) const override { - os << Catch::Detail::stringify( m_lhs ); - } - - public: - UnaryExpr( LhsT lhs ) : m_lhs( lhs ) {} - }; - - // Specialised comparison functions to handle equality comparisons between ints and pointers (NULL deduces as an int) - template - auto compareEqual( LhsT const& lhs, RhsT const& rhs ) -> bool { return lhs == rhs; }; - template - auto compareEqual( T* const& lhs, int rhs ) -> bool { return lhs == reinterpret_cast( rhs ); } - template - auto compareEqual( T* const& lhs, long rhs ) -> bool { return lhs == reinterpret_cast( rhs ); } - template - auto compareEqual( int lhs, T* const& rhs ) -> bool { return reinterpret_cast( lhs ) == rhs; } - template - auto compareEqual( long lhs, T* const& rhs ) -> bool { return reinterpret_cast( lhs ) == rhs; } - - template - auto compareNotEqual( LhsT const& lhs, RhsT&& rhs ) -> bool { return lhs != rhs; }; - template - auto compareNotEqual( T* const& lhs, int rhs ) -> bool { return lhs != reinterpret_cast( rhs ); } - template - auto compareNotEqual( T* const& lhs, long rhs ) -> bool { return lhs != reinterpret_cast( rhs ); } - template - auto compareNotEqual( int lhs, T* const& rhs ) -> bool { return reinterpret_cast( lhs ) != rhs; } - template - auto compareNotEqual( long lhs, T* const& rhs ) -> bool { return reinterpret_cast( lhs ) != rhs; } - - template - class ExprLhs { - LhsT m_lhs; - public: - ExprLhs( LhsT lhs ) : m_lhs( lhs ) {} - - template - auto operator == ( RhsT const& rhs ) -> BinaryExpr const { - return BinaryExpr( compareEqual( m_lhs, rhs ), m_lhs, "==", rhs ); - } - auto operator == ( bool rhs ) -> BinaryExpr const { - return BinaryExpr( m_lhs == rhs, m_lhs, "==", rhs ); - } - - template - auto operator != ( RhsT const& rhs ) -> BinaryExpr const { - return BinaryExpr( compareNotEqual( m_lhs, rhs ), m_lhs, "!=", rhs ); - } - auto operator != ( bool rhs ) -> BinaryExpr const { - return BinaryExpr( m_lhs != rhs, m_lhs, "!=", rhs ); - } - - template - auto operator > ( RhsT const& rhs ) -> BinaryExpr const { - return BinaryExpr( m_lhs > rhs, m_lhs, ">", rhs ); - } - template - auto operator < ( RhsT const& rhs ) -> BinaryExpr const { - return BinaryExpr( m_lhs < rhs, m_lhs, "<", rhs ); - } - template - auto operator >= ( RhsT const& rhs ) -> BinaryExpr const { - return BinaryExpr( m_lhs >= rhs, m_lhs, ">=", rhs ); - } - template - auto operator <= ( RhsT const& rhs ) -> BinaryExpr const { - return BinaryExpr( m_lhs <= rhs, m_lhs, "<=", rhs ); - } - - auto makeUnaryExpr() const -> UnaryExpr { - return UnaryExpr( m_lhs ); - } - }; - - void handleExpression( ITransientExpression const& expr ); - - template - void handleExpression( ExprLhs const& expr ) { - handleExpression( expr.makeUnaryExpr() ); - } - - struct Decomposer { - template - auto operator <= ( T const& lhs ) -> ExprLhs { - return ExprLhs( lhs ); - } - auto operator <=( bool value ) -> ExprLhs { - return ExprLhs( value ); - } - }; - -} // end namespace Catch - -#ifdef _MSC_VER -#pragma warning(pop) #endif -// end catch_decomposer.h -// start catch_assertioninfo.h - -// start catch_result_type.h - -namespace Catch { - - // ResultWas::OfType enum - struct ResultWas { enum OfType { - Unknown = -1, - Ok = 0, - Info = 1, - Warning = 2, - - FailureBit = 0x10, - - ExpressionFailed = FailureBit | 1, - ExplicitFailure = FailureBit | 2, - - Exception = 0x100 | FailureBit, - - ThrewException = Exception | 1, - DidntThrowException = Exception | 2, - - FatalErrorCondition = 0x200 | FailureBit - - }; }; - - bool isOk( ResultWas::OfType resultType ); - bool isJustInfo( int flags ); - - // ResultDisposition::Flags enum - struct ResultDisposition { enum Flags { - Normal = 0x01, - - ContinueOnFailure = 0x02, // Failures fail test, but execution continues - FalseTest = 0x04, // Prefix expression with ! - SuppressFail = 0x08 // Failures are reported but do not fail the test - }; }; - - ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ); - - bool shouldContinueOnFailure( int flags ); - bool isFalseTest( int flags ); - bool shouldSuppressFailure( int flags ); - -} // end namespace Catch - -// end catch_result_type.h -namespace Catch { - - struct AssertionInfo +#if defined(CATCH_CONFIG_CPP11_IS_ENUM) + template::value + > + struct EnumStringMaker { - StringRef macroName; - SourceLineInfo lineInfo; - StringRef capturedExpression; - ResultDisposition::Flags resultDisposition; - - // We want to delete this constructor but a compiler bug in 4.8 means - // the struct is then treated as non-aggregate - //AssertionInfo() = delete; + static std::string convert( T const& ) { return unprintableString; } }; + template + struct EnumStringMaker + { + static std::string convert( T const& v ) + { + return ::Catch::toString( + static_cast::type>(v) + ); + } + }; +#endif + template + struct StringMakerBase { +#if defined(CATCH_CONFIG_CPP11_IS_ENUM) + template + static std::string convert( T const& v ) + { + return EnumStringMaker::convert( v ); + } +#else + template + static std::string convert( T const& ) { return unprintableString; } +#endif + }; + + template<> + struct StringMakerBase { + template + static std::string convert( T const& _value ) { + std::ostringstream oss; + oss << _value; + return oss.str(); + } + }; + + std::string rawMemoryToString( const void *object, std::size_t size ); + + template + std::string rawMemoryToString( const T& object ) { + return rawMemoryToString( &object, sizeof(object) ); + } + +} // end namespace Detail + +template +struct StringMaker : + Detail::StringMakerBase::value> {}; + +template +struct StringMaker { + template + static std::string convert( U* p ) { + if( !p ) + return "NULL"; + else + return Detail::rawMemoryToString( p ); + } +}; + +template +struct StringMaker { + static std::string convert( R C::* p ) { + if( !p ) + return "NULL"; + else + return Detail::rawMemoryToString( p ); + } +}; + +namespace Detail { + template + std::string rangeToString( InputIterator first, InputIterator last ); +} + +//template +//struct StringMaker > { +// static std::string convert( std::vector const& v ) { +// return Detail::rangeToString( v.begin(), v.end() ); +// } +//}; + +template +std::string toString( std::vector const& v ) { + return Detail::rangeToString( v.begin(), v.end() ); +} + +#ifdef CATCH_CONFIG_CPP11_TUPLE + +// toString for tuples +namespace TupleDetail { + template< + typename Tuple, + std::size_t N = 0, + bool = (N < std::tuple_size::value) + > + struct ElementPrinter { + static void print( const Tuple& tuple, std::ostream& os ) + { + os << ( N ? ", " : " " ) + << Catch::toString(std::get(tuple)); + ElementPrinter::print(tuple,os); + } + }; + + template< + typename Tuple, + std::size_t N + > + struct ElementPrinter { + static void print( const Tuple&, std::ostream& ) {} + }; + +} + +template +struct StringMaker> { + + static std::string convert( const std::tuple& tuple ) + { + std::ostringstream os; + os << '{'; + TupleDetail::ElementPrinter>::print( tuple, os ); + os << " }"; + return os.str(); + } +}; +#endif // CATCH_CONFIG_CPP11_TUPLE + +namespace Detail { + template + std::string makeString( T const& value ) { + return StringMaker::convert( value ); + } +} // end namespace Detail + +/// \brief converts any type to a string +/// +/// The default template forwards on to ostringstream - except when an +/// ostringstream overload does not exist - in which case it attempts to detect +/// that and writes {?}. +/// Overload (not specialise) this template for custom typs that you don't want +/// to provide an ostream overload for. +template +std::string toString( T const& value ) { + return StringMaker::convert( value ); +} + + namespace Detail { + template + std::string rangeToString( InputIterator first, InputIterator last ) { + std::ostringstream oss; + oss << "{ "; + if( first != last ) { + oss << Catch::toString( *first ); + for( ++first ; first != last ; ++first ) + oss << ", " << Catch::toString( *first ); + } + oss << " }"; + return oss.str(); + } +} + } // end namespace Catch -// end catch_assertioninfo.h namespace Catch { - struct TestFailureException{}; - struct AssertionResultData; +template +class BinaryExpression; - class LazyExpression { - friend class AssertionHandler; - friend struct AssertionStats; +template +class MatchExpression; - ITransientExpression const* m_transientExpression = nullptr; - bool m_isNegated; - public: - LazyExpression( bool isNegated ); - LazyExpression( LazyExpression const& other ); - LazyExpression& operator = ( LazyExpression const& ) = delete; +// Wraps the LHS of an expression and overloads comparison operators +// for also capturing those and RHS (if any) +template +class ExpressionLhs : public DecomposedExpression { +public: + ExpressionLhs( ResultBuilder& rb, T lhs ) : m_rb( rb ), m_lhs( lhs ), m_truthy(false) {} - explicit operator bool() const; + ExpressionLhs& operator = ( const ExpressionLhs& ); - friend auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream&; - }; + template + BinaryExpression + operator == ( RhsT const& rhs ) { + return captureExpression( rhs ); + } - class AssertionHandler { - AssertionInfo m_assertionInfo; - bool m_shouldDebugBreak = false; - bool m_shouldThrow = false; - bool m_inExceptionGuard = false; + template + BinaryExpression + operator != ( RhsT const& rhs ) { + return captureExpression( rhs ); + } - public: - AssertionHandler - ( StringRef macroName, - SourceLineInfo const& lineInfo, - StringRef capturedExpression, - ResultDisposition::Flags resultDisposition ); - ~AssertionHandler(); + template + BinaryExpression + operator < ( RhsT const& rhs ) { + return captureExpression( rhs ); + } - void handle( ITransientExpression const& expr ); + template + BinaryExpression + operator > ( RhsT const& rhs ) { + return captureExpression( rhs ); + } - template - void handle( ExprLhs const& expr ) { - handle( expr.makeUnaryExpr() ); - } - void handle( ResultWas::OfType resultType ); - void handle( ResultWas::OfType resultType, StringRef const& message ); - void handle( ResultWas::OfType resultType, ITransientExpression const* expr, bool negated ); - void handle( AssertionResultData const& resultData, ITransientExpression const* expr ); + template + BinaryExpression + operator <= ( RhsT const& rhs ) { + return captureExpression( rhs ); + } - auto shouldDebugBreak() const -> bool; - auto allowThrows() const -> bool; - void reactWithDebugBreak() const; - void reactWithoutDebugBreak() const; - void useActiveException(); - void setExceptionGuard(); - void unsetExceptionGuard(); - }; + template + BinaryExpression + operator >= ( RhsT const& rhs ) { + return captureExpression( rhs ); + } - void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef matcherString ); + BinaryExpression operator == ( bool rhs ) { + return captureExpression( rhs ); + } + + BinaryExpression operator != ( bool rhs ) { + return captureExpression( rhs ); + } + + void endExpression() { + m_truthy = m_lhs ? true : false; + m_rb + .setResultType( m_truthy ) + .endExpression( *this ); + } + + virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE { + dest = Catch::toString( m_lhs ); + } + +private: + template + BinaryExpression captureExpression( RhsT& rhs ) const { + return BinaryExpression( m_rb, m_lhs, rhs ); + } + + template + BinaryExpression captureExpression( bool rhs ) const { + return BinaryExpression( m_rb, m_lhs, rhs ); + } + +private: + ResultBuilder& m_rb; + T m_lhs; + bool m_truthy; +}; + +template +class BinaryExpression : public DecomposedExpression { +public: + BinaryExpression( ResultBuilder& rb, LhsT lhs, RhsT rhs ) + : m_rb( rb ), m_lhs( lhs ), m_rhs( rhs ) {} + + BinaryExpression& operator = ( BinaryExpression& ); + + void endExpression() const { + m_rb + .setResultType( Internal::compare( m_lhs, m_rhs ) ) + .endExpression( *this ); + } + + virtual bool isBinaryExpression() const CATCH_OVERRIDE { + return true; + } + + virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE { + std::string lhs = Catch::toString( m_lhs ); + std::string rhs = Catch::toString( m_rhs ); + char delim = lhs.size() + rhs.size() < 40 && + lhs.find('\n') == std::string::npos && + rhs.find('\n') == std::string::npos ? ' ' : '\n'; + dest.reserve( 7 + lhs.size() + rhs.size() ); + // 2 for spaces around operator + // 2 for operator + // 2 for parentheses (conditionally added later) + // 1 for negation (conditionally added later) + dest = lhs; + dest += delim; + dest += Internal::OperatorTraits::getName(); + dest += delim; + dest += rhs; + } + +private: + ResultBuilder& m_rb; + LhsT m_lhs; + RhsT m_rhs; +}; + +template +class MatchExpression : public DecomposedExpression { +public: + MatchExpression( ArgT arg, MatcherT matcher, char const* matcherString ) + : m_arg( arg ), m_matcher( matcher ), m_matcherString( matcherString ) {} + + virtual bool isBinaryExpression() const CATCH_OVERRIDE { + return true; + } + + virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE { + std::string matcherAsString = m_matcher.toString(); + dest = Catch::toString( m_arg ); + dest += ' '; + if( matcherAsString == Detail::unprintableString ) + dest += m_matcherString; + else + dest += matcherAsString; + } + +private: + ArgT m_arg; + MatcherT m_matcher; + char const* m_matcherString; +}; + +} // end namespace Catch + + +namespace Catch { + + template + ExpressionLhs ResultBuilder::operator <= ( T const& operand ) { + return ExpressionLhs( *this, operand ); + } + + inline ExpressionLhs ResultBuilder::operator <= ( bool value ) { + return ExpressionLhs( *this, value ); + } + + template + void ResultBuilder::captureMatch( ArgT const& arg, MatcherT const& matcher, + char const* matcherString ) { + MatchExpression expr( arg, matcher, matcherString ); + setResultType( matcher.match( arg ) ); + endExpression( expr ); + } } // namespace Catch -// end catch_assertionhandler.h -// start catch_message.h +// #included from: catch_message.h +#define TWOBLUECUBES_CATCH_MESSAGE_H_INCLUDED #include -#include namespace Catch { @@ -1264,33 +2002,27 @@ namespace Catch { ResultWas::OfType _type ); std::string macroName; - std::string message; SourceLineInfo lineInfo; ResultWas::OfType type; + std::string message; unsigned int sequence; - bool operator == ( MessageInfo const& other ) const; - bool operator < ( MessageInfo const& other ) const; + bool operator == ( MessageInfo const& other ) const { + return sequence == other.sequence; + } + bool operator < ( MessageInfo const& other ) const { + return sequence < other.sequence; + } private: static unsigned int globalCount; }; - struct MessageStream { - - template - MessageStream& operator << ( T const& value ) { - m_stream << value; - return *this; - } - - // !TBD reuse a global/ thread-local stream - std::ostringstream m_stream; - }; - - struct MessageBuilder : MessageStream { + struct MessageBuilder { MessageBuilder( std::string const& macroName, SourceLineInfo const& lineInfo, - ResultWas::OfType type ); + ResultWas::OfType type ) + : m_info( macroName, lineInfo, type ) + {} template MessageBuilder& operator << ( T const& value ) { @@ -1299,11 +2031,13 @@ namespace Catch { } MessageInfo m_info; + std::ostringstream m_stream; }; class ScopedMessage { public: ScopedMessage( MessageBuilder const& builder ); + ScopedMessage( ScopedMessage const& other ); ~ScopedMessage(); MessageInfo m_info; @@ -1311,36 +2045,31 @@ namespace Catch { } // end namespace Catch -// end catch_message.h -// start catch_interfaces_capture.h +// #included from: catch_interfaces_capture.h +#define TWOBLUECUBES_CATCH_INTERFACES_CAPTURE_H_INCLUDED #include namespace Catch { + class TestCase; class AssertionResult; struct AssertionInfo; struct SectionInfo; struct SectionEndInfo; struct MessageInfo; + class ScopedMessageBuilder; struct Counts; - struct BenchmarkInfo; - struct BenchmarkStats; struct IResultCapture { virtual ~IResultCapture(); - virtual void assertionStarting( AssertionInfo const& info ) = 0; virtual void assertionEnded( AssertionResult const& result ) = 0; virtual bool sectionStarted( SectionInfo const& sectionInfo, Counts& assertions ) = 0; virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0; virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0; - - virtual void benchmarkStarting( BenchmarkInfo const& info ) = 0; - virtual void benchmarkEnded( BenchmarkStats const& stats ) = 0; - virtual void pushScopedMessage( MessageInfo const& message ) = 0; virtual void popScopedMessage( MessageInfo const& message ) = 0; @@ -1349,7 +2078,7 @@ namespace Catch { virtual void exceptionEarlyReported() = 0; - virtual void handleFatalErrorCondition( StringRef message ) = 0; + virtual void handleFatalErrorCondition( std::string const& message ) = 0; virtual bool lastAssertionPassed() = 0; virtual void assertionPassed() = 0; @@ -1359,16 +2088,47 @@ namespace Catch { IResultCapture& getResultCapture(); } -// end catch_interfaces_capture.h -// start catch_debugger.h +// #included from: catch_debugger.h +#define TWOBLUECUBES_CATCH_DEBUGGER_H_INCLUDED + +// #included from: catch_platform.h +#define TWOBLUECUBES_CATCH_PLATFORM_H_INCLUDED + +#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) +# define CATCH_PLATFORM_MAC +#elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED) +# define CATCH_PLATFORM_IPHONE +#elif defined(linux) || defined(__linux) || defined(__linux__) +# define CATCH_PLATFORM_LINUX +#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) +# define CATCH_PLATFORM_WINDOWS +# if !defined(NOMINMAX) && !defined(CATCH_CONFIG_NO_NOMINMAX) +# define CATCH_DEFINES_NOMINMAX +# endif +# if !defined(WIN32_LEAN_AND_MEAN) && !defined(CATCH_CONFIG_NO_WIN32_LEAN_AND_MEAN) +# define CATCH_DEFINES_WIN32_LEAN_AND_MEAN +# endif +#endif + +#include + +namespace Catch{ -namespace Catch { bool isDebuggerActive(); + void writeToDebugConsole( std::string const& text ); } #ifdef CATCH_PLATFORM_MAC - #define CATCH_TRAP() __asm__("int $3\n" : : ) /* NOLINT */ + // The following code snippet based on: + // http://cocoawithlove.com/2008/03/break-into-debugger.html + #if defined(__ppc64__) || defined(__ppc__) + #define CATCH_TRAP() \ + __asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" \ + : : : "memory","r0","r3","r4" ) /* NOLINT */ + #else + #define CATCH_TRAP() __asm__("int $3\n" : : /* NOLINT */ ) + #endif #elif defined(CATCH_PLATFORM_LINUX) // If we can use inline assembler, do it because this allows us to break @@ -1394,190 +2154,251 @@ namespace Catch { #define CATCH_BREAK_INTO_DEBUGGER() Catch::alwaysTrue(); #endif -// end catch_debugger.h -#if !defined(CATCH_CONFIG_DISABLE) +// #included from: catch_interfaces_runner.h +#define TWOBLUECUBES_CATCH_INTERFACES_RUNNER_H_INCLUDED -#if !defined(CATCH_CONFIG_DISABLE_STRINGIFICATION) - #define CATCH_INTERNAL_STRINGIFY(...) #__VA_ARGS__ -#else - #define CATCH_INTERNAL_STRINGIFY(...) "Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION" -#endif +namespace Catch { + class TestCase; + + struct IRunner { + virtual ~IRunner(); + virtual bool aborting() const = 0; + }; +} #if defined(CATCH_CONFIG_FAST_COMPILE) /////////////////////////////////////////////////////////////////////////////// // We can speedup compilation significantly by breaking into debugger lower in // the callstack, because then we don't have to expand CATCH_BREAK_INTO_DEBUGGER // macro in each assertion -#define INTERNAL_CATCH_REACT( handler ) \ - handler.reactWithDebugBreak(); +#define INTERNAL_CATCH_REACT( resultBuilder ) \ + resultBuilder.react(); /////////////////////////////////////////////////////////////////////////////// // Another way to speed-up compilation is to omit local try-catch for REQUIRE* // macros. // This can potentially cause false negative, if the test code catches // the exception before it propagates back up to the runner. -#define INTERNAL_CATCH_TRY( capturer ) capturer.setExceptionGuard(); -#define INTERNAL_CATCH_CATCH( capturer ) capturer.unsetExceptionGuard(); +#define INTERNAL_CATCH_TEST_NO_TRY( macroName, resultDisposition, expr ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ + __catchResult.setExceptionGuard(); \ + CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ + ( __catchResult <= expr ).endExpression(); \ + CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \ + __catchResult.unsetExceptionGuard(); \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::isTrue( false && static_cast( !!(expr) ) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look +// The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&. -#else // CATCH_CONFIG_FAST_COMPILE +#define INTERNAL_CHECK_THAT_NO_TRY( macroName, matcher, resultDisposition, arg ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg ", " #matcher, resultDisposition ); \ + __catchResult.setExceptionGuard(); \ + __catchResult.captureMatch( arg, matcher, #matcher ); \ + __catchResult.unsetExceptionGuard(); \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) +#else /////////////////////////////////////////////////////////////////////////////// // In the event of a failure works out if the debugger needs to be invoked // and/or an exception thrown and takes appropriate action. // This needs to be done as a macro so the debugger will stop in the user // source code rather than in Catch library code -#define INTERNAL_CATCH_REACT( handler ) \ - if( handler.shouldDebugBreak() ) CATCH_BREAK_INTO_DEBUGGER(); \ - handler.reactWithoutDebugBreak(); - -#define INTERNAL_CATCH_TRY( capturer ) try -#define INTERNAL_CATCH_CATCH( capturer ) catch(...) { capturer.useActiveException(); } - +#define INTERNAL_CATCH_REACT( resultBuilder ) \ + if( resultBuilder.shouldDebugBreak() ) CATCH_BREAK_INTO_DEBUGGER(); \ + resultBuilder.react(); #endif /////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_TEST( macroName, resultDisposition, ... ) \ +#define INTERNAL_CATCH_TEST( macroName, resultDisposition, expr ) \ do { \ - Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \ - INTERNAL_CATCH_TRY( catchAssertionHandler ) { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ + try { \ CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ - catchAssertionHandler.handle( Catch::Decomposer() <= __VA_ARGS__ ); \ + ( __catchResult <= expr ).endExpression(); \ CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \ - } INTERNAL_CATCH_CATCH( catchAssertionHandler ) \ - INTERNAL_CATCH_REACT( catchAssertionHandler ) \ - } while( Catch::isTrue( false && static_cast( !!(__VA_ARGS__) ) ) ) // the expression here is never evaluated at runtime but it forces the compiler to give it a look + } \ + catch( ... ) { \ + __catchResult.useActiveException( resultDisposition ); \ + } \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::isTrue( false && static_cast( !!(expr) ) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look // The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&. /////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_IF( macroName, resultDisposition, ... ) \ - INTERNAL_CATCH_TEST( macroName, resultDisposition, __VA_ARGS__ ); \ +#define INTERNAL_CATCH_IF( macroName, resultDisposition, expr ) \ + INTERNAL_CATCH_TEST( macroName, resultDisposition, expr ); \ if( Catch::getResultCapture().lastAssertionPassed() ) /////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_ELSE( macroName, resultDisposition, ... ) \ - INTERNAL_CATCH_TEST( macroName, resultDisposition, __VA_ARGS__ ); \ +#define INTERNAL_CATCH_ELSE( macroName, resultDisposition, expr ) \ + INTERNAL_CATCH_TEST( macroName, resultDisposition, expr ); \ if( !Catch::getResultCapture().lastAssertionPassed() ) /////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_NO_THROW( macroName, resultDisposition, ... ) \ +#define INTERNAL_CATCH_NO_THROW( macroName, resultDisposition, expr ) \ do { \ - Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ try { \ - static_cast(__VA_ARGS__); \ - catchAssertionHandler.handle( Catch::ResultWas::Ok ); \ + static_cast(expr); \ + __catchResult.captureResult( Catch::ResultWas::Ok ); \ } \ catch( ... ) { \ - catchAssertionHandler.useActiveException(); \ + __catchResult.useActiveException( resultDisposition ); \ } \ - INTERNAL_CATCH_REACT( catchAssertionHandler ) \ + INTERNAL_CATCH_REACT( __catchResult ) \ } while( Catch::alwaysFalse() ) /////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_THROWS( macroName, resultDisposition, ... ) \ +#define INTERNAL_CATCH_THROWS( macroName, resultDisposition, matcher, expr ) \ do { \ - Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition); \ - if( catchAssertionHandler.allowThrows() ) \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition, #matcher ); \ + if( __catchResult.allowThrows() ) \ try { \ - static_cast(__VA_ARGS__); \ - catchAssertionHandler.handle( Catch::ResultWas::DidntThrowException ); \ + static_cast(expr); \ + __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \ } \ catch( ... ) { \ - catchAssertionHandler.handle( Catch::ResultWas::Ok ); \ + __catchResult.captureExpectedException( matcher ); \ } \ else \ - catchAssertionHandler.handle( Catch::ResultWas::Ok ); \ - INTERNAL_CATCH_REACT( catchAssertionHandler ) \ + __catchResult.captureResult( Catch::ResultWas::Ok ); \ + INTERNAL_CATCH_REACT( __catchResult ) \ } while( Catch::alwaysFalse() ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_THROWS_AS( macroName, exceptionType, resultDisposition, expr ) \ do { \ - Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr) ", " CATCH_INTERNAL_STRINGIFY(exceptionType), resultDisposition ); \ - if( catchAssertionHandler.allowThrows() ) \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr ", " #exceptionType, resultDisposition ); \ + if( __catchResult.allowThrows() ) \ try { \ static_cast(expr); \ - catchAssertionHandler.handle( Catch::ResultWas::DidntThrowException ); \ + __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \ } \ - catch( exceptionType const& ) { \ - catchAssertionHandler.handle( Catch::ResultWas::Ok ); \ + catch( exceptionType ) { \ + __catchResult.captureResult( Catch::ResultWas::Ok ); \ } \ catch( ... ) { \ - catchAssertionHandler.useActiveException(); \ + __catchResult.useActiveException( resultDisposition ); \ } \ else \ - catchAssertionHandler.handle( Catch::ResultWas::Ok ); \ - INTERNAL_CATCH_REACT( catchAssertionHandler ) \ + __catchResult.captureResult( Catch::ResultWas::Ok ); \ + INTERNAL_CATCH_REACT( __catchResult ) \ } while( Catch::alwaysFalse() ) /////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, ... ) \ - do { \ - Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \ - catchAssertionHandler.handle( messageType, ( Catch::MessageStream() << __VA_ARGS__ + ::Catch::StreamEndStop() ).m_stream.str() ); \ - INTERNAL_CATCH_REACT( catchAssertionHandler ) \ - } while( Catch::alwaysFalse() ) +#ifdef CATCH_CONFIG_VARIADIC_MACROS + #define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, ... ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \ + __catchResult << __VA_ARGS__ + ::Catch::StreamEndStop(); \ + __catchResult.captureResult( messageType ); \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) +#else + #define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, log ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \ + __catchResult << log + ::Catch::StreamEndStop(); \ + __catchResult.captureResult( messageType ); \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) +#endif /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_INFO( macroName, log ) \ Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage ) = Catch::MessageBuilder( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log; /////////////////////////////////////////////////////////////////////////////// -// Although this is matcher-based, it can be used with just a string -#define INTERNAL_CATCH_THROWS_STR_MATCHES( macroName, resultDisposition, matcher, ... ) \ +#define INTERNAL_CHECK_THAT( macroName, matcher, resultDisposition, arg ) \ do { \ - Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \ - if( catchAssertionHandler.allowThrows() ) \ - try { \ - static_cast(__VA_ARGS__); \ - catchAssertionHandler.handle( Catch::ResultWas::DidntThrowException ); \ - } \ - catch( ... ) { \ - handleExceptionMatchExpr( catchAssertionHandler, matcher, #matcher ); \ - } \ - else \ - catchAssertionHandler.handle( Catch::ResultWas::Ok ); \ - INTERNAL_CATCH_REACT( catchAssertionHandler ) \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg ", " #matcher, resultDisposition ); \ + try { \ + __catchResult.captureMatch( arg, matcher, #matcher ); \ + } catch( ... ) { \ + __catchResult.useActiveException( resultDisposition | Catch::ResultDisposition::ContinueOnFailure ); \ + } \ + INTERNAL_CATCH_REACT( __catchResult ) \ } while( Catch::alwaysFalse() ) -#endif // CATCH_CONFIG_DISABLE +// #included from: internal/catch_section.h +#define TWOBLUECUBES_CATCH_SECTION_H_INCLUDED -// end catch_capture.hpp -// start catch_section.h +// #included from: catch_section_info.h +#define TWOBLUECUBES_CATCH_SECTION_INFO_H_INCLUDED -// start catch_section_info.h - -// start catch_totals.h +// #included from: catch_totals.hpp +#define TWOBLUECUBES_CATCH_TOTALS_HPP_INCLUDED #include namespace Catch { struct Counts { - Counts operator - ( Counts const& other ) const; - Counts& operator += ( Counts const& other ); + Counts() : passed( 0 ), failed( 0 ), failedButOk( 0 ) {} - std::size_t total() const; - bool allPassed() const; - bool allOk() const; + Counts operator - ( Counts const& other ) const { + Counts diff; + diff.passed = passed - other.passed; + diff.failed = failed - other.failed; + diff.failedButOk = failedButOk - other.failedButOk; + return diff; + } + Counts& operator += ( Counts const& other ) { + passed += other.passed; + failed += other.failed; + failedButOk += other.failedButOk; + return *this; + } - std::size_t passed = 0; - std::size_t failed = 0; - std::size_t failedButOk = 0; + std::size_t total() const { + return passed + failed + failedButOk; + } + bool allPassed() const { + return failed == 0 && failedButOk == 0; + } + bool allOk() const { + return failed == 0; + } + + std::size_t passed; + std::size_t failed; + std::size_t failedButOk; }; struct Totals { - Totals operator - ( Totals const& other ) const; - Totals& operator += ( Totals const& other ); + Totals operator - ( Totals const& other ) const { + Totals diff; + diff.assertions = assertions - other.assertions; + diff.testCases = testCases - other.testCases; + return diff; + } - Totals delta( Totals const& prevTotals ) const; + Totals delta( Totals const& prevTotals ) const { + Totals diff = *this - prevTotals; + if( diff.assertions.failed > 0 ) + ++diff.testCases.failed; + else if( diff.assertions.failedButOk > 0 ) + ++diff.testCases.failedButOk; + else + ++diff.testCases.passed; + return diff; + } + + Totals& operator += ( Totals const& other ) { + assertions += other.assertions; + testCases += other.testCases; + return *this; + } Counts assertions; Counts testCases; }; } -// end catch_totals.h #include namespace Catch { @@ -1594,7 +2415,9 @@ namespace Catch { }; struct SectionEndInfo { - SectionEndInfo( SectionInfo const& _sectionInfo, Counts const& _prevAssertions, double _durationInSeconds ); + SectionEndInfo( SectionInfo const& _sectionInfo, Counts const& _prevAssertions, double _durationInSeconds ) + : sectionInfo( _sectionInfo ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds ) + {} SectionInfo sectionInfo; Counts prevAssertions; @@ -1603,29 +2426,36 @@ namespace Catch { } // end namespace Catch -// end catch_section_info.h -// start catch_timer.h +// #included from: catch_timer.h +#define TWOBLUECUBES_CATCH_TIMER_H_INCLUDED -#include +#ifdef _MSC_VER namespace Catch { + typedef unsigned long long UInt64; +} +#else +#include +namespace Catch { + typedef uint64_t UInt64; +} +#endif - auto getCurrentNanosecondsSinceEpoch() -> uint64_t; - auto getEstimatedClockResolution() -> uint64_t; - +namespace Catch { class Timer { - uint64_t m_nanoseconds = 0; public: + Timer() : m_ticks( 0 ) {} void start(); - auto getElapsedNanoseconds() const -> unsigned int; - auto getElapsedMicroseconds() const -> unsigned int; - auto getElapsedMilliseconds() const -> unsigned int; - auto getElapsedSeconds() const -> double; + unsigned int getElapsedMicroseconds() const; + unsigned int getElapsedMilliseconds() const; + double getElapsedSeconds() const; + + private: + UInt64 m_ticks; }; } // namespace Catch -// end catch_timer.h #include namespace Catch { @@ -1636,7 +2466,7 @@ namespace Catch { ~Section(); // This indicates whether the section should be executed or not - explicit operator bool() const; + operator bool() const; private: SectionInfo m_info; @@ -1649,62 +2479,203 @@ namespace Catch { } // end namespace Catch +#ifdef CATCH_CONFIG_VARIADIC_MACROS #define INTERNAL_CATCH_SECTION( ... ) \ if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) +#else + #define INTERNAL_CATCH_SECTION( name, desc ) \ + if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, name, desc ) ) +#endif -// end catch_section.h -// start catch_benchmark.h +// #included from: internal/catch_generators.hpp +#define TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED -#include +#include #include +#include namespace Catch { - class BenchmarkLooper { +template +struct IGenerator { + virtual ~IGenerator() {} + virtual T getValue( std::size_t index ) const = 0; + virtual std::size_t size () const = 0; +}; - std::string m_name; - std::size_t m_count = 0; - std::size_t m_iterationsToRun = 1; - uint64_t m_resolution; - Timer m_timer; +template +class BetweenGenerator : public IGenerator { +public: + BetweenGenerator( T from, T to ) : m_from( from ), m_to( to ){} - static auto getResolution() -> uint64_t; - public: - // Keep most of this inline as it's on the code path that is being timed - BenchmarkLooper( StringRef name ) - : m_name( name ), - m_resolution( getResolution() ) + virtual T getValue( std::size_t index ) const { + return m_from+static_cast( index ); + } + + virtual std::size_t size() const { + return static_cast( 1+m_to-m_from ); + } + +private: + + T m_from; + T m_to; +}; + +template +class ValuesGenerator : public IGenerator { +public: + ValuesGenerator(){} + + void add( T value ) { + m_values.push_back( value ); + } + + virtual T getValue( std::size_t index ) const { + return m_values[index]; + } + + virtual std::size_t size() const { + return m_values.size(); + } + +private: + std::vector m_values; +}; + +template +class CompositeGenerator { +public: + CompositeGenerator() : m_totalSize( 0 ) {} + + // *** Move semantics, similar to auto_ptr *** + CompositeGenerator( CompositeGenerator& other ) + : m_fileInfo( other.m_fileInfo ), + m_totalSize( 0 ) + { + move( other ); + } + + CompositeGenerator& setFileInfo( const char* fileInfo ) { + m_fileInfo = fileInfo; + return *this; + } + + ~CompositeGenerator() { + deleteAll( m_composed ); + } + + operator T () const { + size_t overallIndex = getCurrentContext().getGeneratorIndex( m_fileInfo, m_totalSize ); + + typename std::vector*>::const_iterator it = m_composed.begin(); + typename std::vector*>::const_iterator itEnd = m_composed.end(); + for( size_t index = 0; it != itEnd; ++it ) { - reportStart(); - m_timer.start(); + const IGenerator* generator = *it; + if( overallIndex >= index && overallIndex < index + generator->size() ) + { + return generator->getValue( overallIndex-index ); + } + index += generator->size(); } + CATCH_INTERNAL_ERROR( "Indexed past end of generated range" ); + return T(); // Suppress spurious "not all control paths return a value" warning in Visual Studio - if you know how to fix this please do so + } - explicit operator bool() { - if( m_count < m_iterationsToRun ) - return true; - return needsMoreIterations(); - } + void add( const IGenerator* generator ) { + m_totalSize += generator->size(); + m_composed.push_back( generator ); + } - void increment() { - ++m_count; - } + CompositeGenerator& then( CompositeGenerator& other ) { + move( other ); + return *this; + } - void reportStart(); - auto needsMoreIterations() -> bool; - }; + CompositeGenerator& then( T value ) { + ValuesGenerator* valuesGen = new ValuesGenerator(); + valuesGen->add( value ); + add( valuesGen ); + return *this; + } + +private: + + void move( CompositeGenerator& other ) { + m_composed.insert( m_composed.end(), other.m_composed.begin(), other.m_composed.end() ); + m_totalSize += other.m_totalSize; + other.m_composed.clear(); + } + + std::vector*> m_composed; + std::string m_fileInfo; + size_t m_totalSize; +}; + +namespace Generators +{ + template + CompositeGenerator between( T from, T to ) { + CompositeGenerator generators; + generators.add( new BetweenGenerator( from, to ) ); + return generators; + } + + template + CompositeGenerator values( T val1, T val2 ) { + CompositeGenerator generators; + ValuesGenerator* valuesGen = new ValuesGenerator(); + valuesGen->add( val1 ); + valuesGen->add( val2 ); + generators.add( valuesGen ); + return generators; + } + + template + CompositeGenerator values( T val1, T val2, T val3 ){ + CompositeGenerator generators; + ValuesGenerator* valuesGen = new ValuesGenerator(); + valuesGen->add( val1 ); + valuesGen->add( val2 ); + valuesGen->add( val3 ); + generators.add( valuesGen ); + return generators; + } + + template + CompositeGenerator values( T val1, T val2, T val3, T val4 ) { + CompositeGenerator generators; + ValuesGenerator* valuesGen = new ValuesGenerator(); + valuesGen->add( val1 ); + valuesGen->add( val2 ); + valuesGen->add( val3 ); + valuesGen->add( val4 ); + generators.add( valuesGen ); + return generators; + } + +} // end namespace Generators + +using namespace Generators; } // end namespace Catch -#define BENCHMARK( name ) \ - for( Catch::BenchmarkLooper looper( name ); looper; looper.increment() ) +#define INTERNAL_CATCH_LINESTR2( line ) #line +#define INTERNAL_CATCH_LINESTR( line ) INTERNAL_CATCH_LINESTR2( line ) -// end catch_benchmark.h -// start catch_interfaces_exception.h +#define INTERNAL_CATCH_GENERATE( expr ) expr.setFileInfo( __FILE__ "(" INTERNAL_CATCH_LINESTR( __LINE__ ) ")" ) -// start catch_interfaces_registry_hub.h +// #included from: internal/catch_interfaces_exception.h +#define TWOBLUECUBES_CATCH_INTERFACES_EXCEPTION_H_INCLUDED + +#include +#include + +// #included from: catch_interfaces_registry_hub.h +#define TWOBLUECUBES_CATCH_INTERFACES_REGISTRY_HUB_H_INCLUDED #include -#include namespace Catch { @@ -1715,9 +2686,6 @@ namespace Catch { struct IReporterRegistry; struct IReporterFactory; struct ITagAliasRegistry; - class StartupExceptionRegistry; - - using IReporterFactoryPtr = std::shared_ptr; struct IRegistryHub { virtual ~IRegistryHub(); @@ -1727,18 +2695,15 @@ namespace Catch { virtual ITagAliasRegistry const& getTagAliasRegistry() const = 0; virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() = 0; - - virtual StartupExceptionRegistry const& getStartupExceptionRegistry() const = 0; }; struct IMutableRegistryHub { virtual ~IMutableRegistryHub(); - virtual void registerReporter( std::string const& name, IReporterFactoryPtr const& factory ) = 0; - virtual void registerListener( IReporterFactoryPtr const& factory ) = 0; + virtual void registerReporter( std::string const& name, Ptr const& factory ) = 0; + virtual void registerListener( Ptr const& factory ) = 0; virtual void registerTest( TestCase const& testInfo ) = 0; virtual void registerTranslator( const IExceptionTranslator* translator ) = 0; virtual void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) = 0; - virtual void registerStartupException() noexcept = 0; }; IRegistryHub& getRegistryHub(); @@ -1748,21 +2713,12 @@ namespace Catch { } -// end catch_interfaces_registry_hub.h -#if defined(CATCH_CONFIG_DISABLE) - #define INTERNAL_CATCH_TRANSLATE_EXCEPTION_NO_REG( translatorName, signature) \ - static std::string translatorName( signature ) -#endif - -#include -#include -#include - namespace Catch { - using exceptionTranslateFunction = std::string(*)(); + + typedef std::string(*exceptionTranslateFunction)(); struct IExceptionTranslator; - using ExceptionTranslators = std::vector>; + typedef std::vector ExceptionTranslators; struct IExceptionTranslator { virtual ~IExceptionTranslator(); @@ -1784,10 +2740,10 @@ namespace Catch { : m_translateFunction( translateFunction ) {} - std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const override { + virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const CATCH_OVERRIDE { try { if( it == itEnd ) - std::rethrow_exception(std::current_exception()); + throw; else return (*it)->translate( it+1, itEnd ); } @@ -1817,40 +2773,36 @@ namespace Catch { #define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION2( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature ) -// end catch_interfaces_exception.h -// start catch_approx.h +// #included from: internal/catch_approx.hpp +#define TWOBLUECUBES_CATCH_APPROX_HPP_INCLUDED -// start catch_enforce.h +#include +#include -#include -#include - -#define CATCH_PREPARE_EXCEPTION( type, msg ) \ - type( static_cast( std::ostringstream() << msg ).str() ) -#define CATCH_INTERNAL_ERROR( msg ) \ - throw CATCH_PREPARE_EXCEPTION( std::logic_error, CATCH_INTERNAL_LINEINFO << ": Internal Catch error: " << msg); -#define CATCH_ERROR( msg ) \ - throw CATCH_PREPARE_EXCEPTION( std::domain_error, msg ) -#define CATCH_ENFORCE( condition, msg ) \ - do{ if( !(condition) ) CATCH_ERROR( msg ); } while(false) - -// end catch_enforce.h +#if defined(CATCH_CONFIG_CPP11_TYPE_TRAITS) #include +#endif namespace Catch { namespace Detail { class Approx { - private: - bool equalityComparisonImpl(double other) const; - public: - explicit Approx ( double value ); + explicit Approx ( double value ) + : m_epsilon( std::numeric_limits::epsilon()*100 ), + m_margin( 0.0 ), + m_scale( 1.0 ), + m_value( value ) + {} - static Approx custom(); + static Approx custom() { + return Approx( 0 ); + } + +#if defined(CATCH_CONFIG_CPP11_TYPE_TRAITS) template ::value>::type> - Approx operator()( T const& value ) { + Approx operator()( T value ) { Approx approx( static_cast(value) ); approx.epsilon( m_epsilon ); approx.margin( m_margin ); @@ -1859,13 +2811,18 @@ namespace Detail { } template ::value>::type> - explicit Approx( T const& value ): Approx(static_cast(value)) + explicit Approx( T value ): Approx(static_cast(value)) {} template ::value>::type> friend bool operator == ( const T& lhs, Approx const& rhs ) { - auto lhs_v = static_cast(lhs); - return rhs.equalityComparisonImpl(lhs_v); + // Thanks to Richard Harris for his help refining this formula + auto lhs_v = double(lhs); + bool relativeOK = std::fabs(lhs_v - rhs.m_value) < rhs.m_epsilon * (rhs.m_scale + (std::max)(std::fabs(lhs_v), std::fabs(rhs.m_value))); + if (relativeOK) { + return true; + } + return std::fabs(lhs_v - rhs.m_value) < rhs.m_margin; } template ::value>::type> @@ -1874,62 +2831,121 @@ namespace Detail { } template ::value>::type> - friend bool operator != ( T const& lhs, Approx const& rhs ) { + friend bool operator != ( T lhs, Approx const& rhs ) { return !operator==( lhs, rhs ); } template ::value>::type> - friend bool operator != ( Approx const& lhs, T const& rhs ) { + friend bool operator != ( Approx const& lhs, T rhs ) { return !operator==( rhs, lhs ); } template ::value>::type> - friend bool operator <= ( T const& lhs, Approx const& rhs ) { - return static_cast(lhs) < rhs.m_value || lhs == rhs; + friend bool operator <= ( T lhs, Approx const& rhs ) { + return double(lhs) < rhs.m_value || lhs == rhs; } template ::value>::type> - friend bool operator <= ( Approx const& lhs, T const& rhs ) { - return lhs.m_value < static_cast(rhs) || lhs == rhs; + friend bool operator <= ( Approx const& lhs, T rhs ) { + return lhs.m_value < double(rhs) || lhs == rhs; } template ::value>::type> - friend bool operator >= ( T const& lhs, Approx const& rhs ) { - return static_cast(lhs) > rhs.m_value || lhs == rhs; + friend bool operator >= ( T lhs, Approx const& rhs ) { + return double(lhs) > rhs.m_value || lhs == rhs; } template ::value>::type> - friend bool operator >= ( Approx const& lhs, T const& rhs ) { - return lhs.m_value > static_cast(rhs) || lhs == rhs; + friend bool operator >= ( Approx const& lhs, T rhs ) { + return lhs.m_value > double(rhs) || lhs == rhs; } template ::value>::type> - Approx& epsilon( T const& newEpsilon ) { - double epsilonAsDouble = static_cast(newEpsilon); - CATCH_ENFORCE(epsilonAsDouble >= 0 && epsilonAsDouble <= 1.0, - "Invalid Approx::epsilon: " << epsilonAsDouble - << ", Approx::epsilon has to be between 0 and 1"); - m_epsilon = epsilonAsDouble; + Approx& epsilon( T newEpsilon ) { + m_epsilon = double(newEpsilon); return *this; } template ::value>::type> - Approx& margin( T const& newMargin ) { - double marginAsDouble = static_cast(newMargin); - CATCH_ENFORCE(marginAsDouble >= 0, - "Invalid Approx::margin: " << marginAsDouble - << ", Approx::Margin has to be non-negative."); - m_margin = marginAsDouble; + Approx& margin( T newMargin ) { + m_margin = double(newMargin); return *this; } template ::value>::type> - Approx& scale( T const& newScale ) { - m_scale = static_cast(newScale); + Approx& scale( T newScale ) { + m_scale = double(newScale); return *this; } - std::string toString() const; +#else + + Approx operator()( double value ) { + Approx approx( value ); + approx.epsilon( m_epsilon ); + approx.margin( m_margin ); + approx.scale( m_scale ); + return approx; + } + + friend bool operator == ( double lhs, Approx const& rhs ) { + // Thanks to Richard Harris for his help refining this formula + bool relativeOK = std::fabs( lhs - rhs.m_value ) < rhs.m_epsilon * (rhs.m_scale + (std::max)( std::fabs(lhs), std::fabs(rhs.m_value) ) ); + if (relativeOK) { + return true; + } + return std::fabs(lhs - rhs.m_value) < rhs.m_margin; + } + + friend bool operator == ( Approx const& lhs, double rhs ) { + return operator==( rhs, lhs ); + } + + friend bool operator != ( double lhs, Approx const& rhs ) { + return !operator==( lhs, rhs ); + } + + friend bool operator != ( Approx const& lhs, double rhs ) { + return !operator==( rhs, lhs ); + } + + friend bool operator <= ( double lhs, Approx const& rhs ) { + return lhs < rhs.m_value || lhs == rhs; + } + + friend bool operator <= ( Approx const& lhs, double rhs ) { + return lhs.m_value < rhs || lhs == rhs; + } + + friend bool operator >= ( double lhs, Approx const& rhs ) { + return lhs > rhs.m_value || lhs == rhs; + } + + friend bool operator >= ( Approx const& lhs, double rhs ) { + return lhs.m_value > rhs || lhs == rhs; + } + + Approx& epsilon( double newEpsilon ) { + m_epsilon = newEpsilon; + return *this; + } + + Approx& margin( double newMargin ) { + m_margin = newMargin; + return *this; + } + + Approx& scale( double newScale ) { + m_scale = newScale; + return *this; + } +#endif + + std::string toString() const { + std::ostringstream oss; + oss << "Approx( " << Catch::toString( m_value ) << " )"; + return oss.str(); + } private: double m_epsilon; @@ -1940,194 +2956,14 @@ namespace Detail { } template<> -struct StringMaker { - static std::string convert(Catch::Detail::Approx const& value); -}; +inline std::string toString( Detail::Approx const& value ) { + return value.toString(); +} } // end namespace Catch -// end catch_approx.h -// start catch_string_manip.h - -#include -#include - -namespace Catch { - - bool startsWith( std::string const& s, std::string const& prefix ); - bool startsWith( std::string const& s, char prefix ); - bool endsWith( std::string const& s, std::string const& suffix ); - bool endsWith( std::string const& s, char suffix ); - bool contains( std::string const& s, std::string const& infix ); - void toLowerInPlace( std::string& s ); - std::string toLower( std::string const& s ); - std::string trim( std::string const& str ); - bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ); - - struct pluralise { - pluralise( std::size_t count, std::string const& label ); - - friend std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ); - - std::size_t m_count; - std::string m_label; - }; -} - -// end catch_string_manip.h -#ifndef CATCH_CONFIG_DISABLE_MATCHERS -// start catch_capture_matchers.h - -// start catch_matchers.h - -#include -#include - -namespace Catch { -namespace Matchers { - namespace Impl { - - template struct MatchAllOf; - template struct MatchAnyOf; - template struct MatchNotOf; - - class MatcherUntypedBase { - public: - MatcherUntypedBase() = default; - MatcherUntypedBase ( MatcherUntypedBase const& ) = default; - MatcherUntypedBase& operator = ( MatcherUntypedBase const& ) = delete; - std::string toString() const; - - protected: - virtual ~MatcherUntypedBase(); - virtual std::string describe() const = 0; - mutable std::string m_cachedToString; - }; - - template - struct MatcherMethod { - virtual bool match( ObjectT const& arg ) const = 0; - }; - template - struct MatcherMethod { - virtual bool match( PtrT* arg ) const = 0; - }; - - template - struct MatcherBase : MatcherUntypedBase, MatcherMethod { - - MatchAllOf operator && ( MatcherBase const& other ) const; - MatchAnyOf operator || ( MatcherBase const& other ) const; - MatchNotOf operator ! () const; - }; - - template - struct MatchAllOf : MatcherBase { - bool match( ArgT const& arg ) const override { - for( auto matcher : m_matchers ) { - if (!matcher->match(arg)) - return false; - } - return true; - } - std::string describe() const override { - std::string description; - description.reserve( 4 + m_matchers.size()*32 ); - description += "( "; - bool first = true; - for( auto matcher : m_matchers ) { - if( first ) - first = false; - else - description += " and "; - description += matcher->toString(); - } - description += " )"; - return description; - } - - MatchAllOf& operator && ( MatcherBase const& other ) { - m_matchers.push_back( &other ); - return *this; - } - - std::vector const*> m_matchers; - }; - template - struct MatchAnyOf : MatcherBase { - - bool match( ArgT const& arg ) const override { - for( auto matcher : m_matchers ) { - if (matcher->match(arg)) - return true; - } - return false; - } - std::string describe() const override { - std::string description; - description.reserve( 4 + m_matchers.size()*32 ); - description += "( "; - bool first = true; - for( auto matcher : m_matchers ) { - if( first ) - first = false; - else - description += " or "; - description += matcher->toString(); - } - description += " )"; - return description; - } - - MatchAnyOf& operator || ( MatcherBase const& other ) { - m_matchers.push_back( &other ); - return *this; - } - - std::vector const*> m_matchers; - }; - - template - struct MatchNotOf : MatcherBase { - - MatchNotOf( MatcherBase const& underlyingMatcher ) : m_underlyingMatcher( underlyingMatcher ) {} - - bool match( ArgT const& arg ) const override { - return !m_underlyingMatcher.match( arg ); - } - - std::string describe() const override { - return "not " + m_underlyingMatcher.toString(); - } - MatcherBase const& m_underlyingMatcher; - }; - - template - MatchAllOf MatcherBase::operator && ( MatcherBase const& other ) const { - return MatchAllOf() && *this && other; - } - template - MatchAnyOf MatcherBase::operator || ( MatcherBase const& other ) const { - return MatchAnyOf() || *this || other; - } - template - MatchNotOf MatcherBase::operator ! () const { - return MatchNotOf( *this ); - } - - } // namespace Impl - -} // namespace Matchers - -using namespace Matchers; -using Matchers::Impl::MatcherBase; - -} // namespace Catch - -// end catch_matchers.h -// start catch_matchers_string.h - -#include +// #included from: internal/catch_matchers_string.h +#define TWOBLUECUBES_CATCH_MATCHERS_STRING_H_INCLUDED namespace Catch { namespace Matchers { @@ -2146,7 +2982,7 @@ namespace Matchers { struct StringMatcherBase : MatcherBase { StringMatcherBase( std::string const& operation, CasedString const& comparator ); - std::string describe() const override; + virtual std::string describe() const CATCH_OVERRIDE; CasedString m_comparator; std::string m_operation; @@ -2154,19 +2990,19 @@ namespace Matchers { struct EqualsMatcher : StringMatcherBase { EqualsMatcher( CasedString const& comparator ); - bool match( std::string const& source ) const override; + virtual bool match( std::string const& source ) const CATCH_OVERRIDE; }; struct ContainsMatcher : StringMatcherBase { ContainsMatcher( CasedString const& comparator ); - bool match( std::string const& source ) const override; + virtual bool match( std::string const& source ) const CATCH_OVERRIDE; }; struct StartsWithMatcher : StringMatcherBase { StartsWithMatcher( CasedString const& comparator ); - bool match( std::string const& source ) const override; + virtual bool match( std::string const& source ) const CATCH_OVERRIDE; }; struct EndsWithMatcher : StringMatcherBase { EndsWithMatcher( CasedString const& comparator ); - bool match( std::string const& source ) const override; + virtual bool match( std::string const& source ) const CATCH_OVERRIDE; }; } // namespace StdString @@ -2182,8 +3018,8 @@ namespace Matchers { } // namespace Matchers } // namespace Catch -// end catch_matchers_string.h -// start catch_matchers_vector.h +// #included from: internal/catch_matchers_vector.h +#define TWOBLUECUBES_CATCH_MATCHERS_VECTOR_H_INCLUDED namespace Catch { namespace Matchers { @@ -2195,17 +3031,12 @@ namespace Matchers { ContainsElementMatcher(T const &comparator) : m_comparator( comparator) {} - bool match(std::vector const &v) const override { - for (auto const& el : v) { - if (el == m_comparator) { - return true; - } - } - return false; + bool match(std::vector const &v) const CATCH_OVERRIDE { + return std::find(v.begin(), v.end(), m_comparator) != v.end(); } - std::string describe() const override { - return "Contains: " + ::Catch::Detail::stringify( m_comparator ); + virtual std::string describe() const CATCH_OVERRIDE { + return "Contains: " + Catch::toString( m_comparator ); } T const& m_comparator; @@ -2216,26 +3047,17 @@ namespace Matchers { ContainsMatcher(std::vector const &comparator) : m_comparator( comparator ) {} - bool match(std::vector const &v) const override { + bool match(std::vector const &v) const CATCH_OVERRIDE { // !TBD: see note in EqualsMatcher if (m_comparator.size() > v.size()) return false; - for (auto const& comparator : m_comparator) { - auto present = false; - for (const auto& el : v) { - if (el == comparator) { - present = true; - break; - } - } - if (!present) { + for (size_t i = 0; i < m_comparator.size(); ++i) + if (std::find(v.begin(), v.end(), m_comparator[i]) == v.end()) return false; - } - } return true; } - std::string describe() const override { - return "Contains: " + ::Catch::Detail::stringify( m_comparator ); + virtual std::string describe() const CATCH_OVERRIDE { + return "Contains: " + Catch::toString( m_comparator ); } std::vector const& m_comparator; @@ -2246,20 +3068,20 @@ namespace Matchers { EqualsMatcher(std::vector const &comparator) : m_comparator( comparator ) {} - bool match(std::vector const &v) const override { + bool match(std::vector const &v) const CATCH_OVERRIDE { // !TBD: This currently works if all elements can be compared using != // - a more general approach would be via a compare template that defaults // to using !=. but could be specialised for, e.g. std::vector etc // - then just call that directly if (m_comparator.size() != v.size()) return false; - for (std::size_t i = 0; i < v.size(); ++i) + for (size_t i = 0; i < v.size(); ++i) if (m_comparator[i] != v[i]) return false; return true; } - std::string describe() const override { - return "Equals: " + ::Catch::Detail::stringify( m_comparator ); + virtual std::string describe() const CATCH_OVERRIDE { + return "Equals: " + Catch::toString( m_comparator ); } std::vector const& m_comparator; }; @@ -2287,87 +3109,124 @@ namespace Matchers { } // namespace Matchers } // namespace Catch -// end catch_matchers_vector.h +// #included from: internal/catch_interfaces_tag_alias_registry.h +#define TWOBLUECUBES_CATCH_INTERFACES_TAG_ALIAS_REGISTRY_H_INCLUDED + +// #included from: catch_tag_alias.h +#define TWOBLUECUBES_CATCH_TAG_ALIAS_H_INCLUDED + +#include + namespace Catch { - template - class MatchExpr : public ITransientExpression { - ArgT const& m_arg; - MatcherT m_matcher; - StringRef m_matcherString; - bool m_result; - public: - MatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef matcherString ) - : m_arg( arg ), - m_matcher( matcher ), - m_matcherString( matcherString ), - m_result( matcher.match( arg ) ) - {} + struct TagAlias { + TagAlias( std::string const& _tag, SourceLineInfo _lineInfo ) : tag( _tag ), lineInfo( _lineInfo ) {} - auto isBinaryExpression() const -> bool override { return true; } - auto getResult() const -> bool override { return m_result; } - - void streamReconstructedExpression( std::ostream &os ) const override { - auto matcherAsString = m_matcher.toString(); - os << Catch::Detail::stringify( m_arg ) << ' '; - if( matcherAsString == Detail::unprintableString ) - os << m_matcherString; - else - os << matcherAsString; - } + std::string tag; + SourceLineInfo lineInfo; }; - using StringMatcher = Matchers::Impl::MatcherBase; + struct RegistrarForTagAliases { + RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); + }; - void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef matcherString ); +} // end namespace Catch - template - auto makeMatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef matcherString ) -> MatchExpr { - return MatchExpr( arg, matcher, matcherString ); - } +#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } +// #included from: catch_option.hpp +#define TWOBLUECUBES_CATCH_OPTION_HPP_INCLUDED -} // namespace Catch +namespace Catch { -/////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CHECK_THAT( macroName, matcher, resultDisposition, arg ) \ - do { \ - Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(arg) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \ - INTERNAL_CATCH_TRY( catchAssertionHandler ) { \ - catchAssertionHandler.handle( Catch::makeMatchExpr( arg, matcher, #matcher ) ); \ - } INTERNAL_CATCH_CATCH( catchAssertionHandler ) \ - INTERNAL_CATCH_REACT( catchAssertionHandler ) \ - } while( Catch::alwaysFalse() ) + // An optional type + template + class Option { + public: + Option() : nullableValue( CATCH_NULL ) {} + Option( T const& _value ) + : nullableValue( new( storage ) T( _value ) ) + {} + Option( Option const& _other ) + : nullableValue( _other ? new( storage ) T( *_other ) : CATCH_NULL ) + {} -/////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_THROWS_MATCHES( macroName, exceptionType, resultDisposition, matcher, ... ) \ - do { \ - Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(exceptionType) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \ - if( catchAssertionHandler.allowThrows() ) \ - try { \ - static_cast(__VA_ARGS__ ); \ - catchAssertionHandler.handle( Catch::ResultWas::DidntThrowException ); \ - } \ - catch( exceptionType const& ex ) { \ - catchAssertionHandler.handle( Catch::makeMatchExpr( ex, matcher, #matcher ) ); \ - } \ - catch( ... ) { \ - catchAssertionHandler.useActiveException(); \ - } \ - else \ - catchAssertionHandler.handle( Catch::ResultWas::Ok ); \ - INTERNAL_CATCH_REACT( catchAssertionHandler ) \ - } while( Catch::alwaysFalse() ) + ~Option() { + reset(); + } -// end catch_capture_matchers.h + Option& operator= ( Option const& _other ) { + if( &_other != this ) { + reset(); + if( _other ) + nullableValue = new( storage ) T( *_other ); + } + return *this; + } + Option& operator = ( T const& _value ) { + reset(); + nullableValue = new( storage ) T( _value ); + return *this; + } + + void reset() { + if( nullableValue ) + nullableValue->~T(); + nullableValue = CATCH_NULL; + } + + T& operator*() { return *nullableValue; } + T const& operator*() const { return *nullableValue; } + T* operator->() { return nullableValue; } + const T* operator->() const { return nullableValue; } + + T valueOr( T const& defaultValue ) const { + return nullableValue ? *nullableValue : defaultValue; + } + + bool some() const { return nullableValue != CATCH_NULL; } + bool none() const { return nullableValue == CATCH_NULL; } + + bool operator !() const { return nullableValue == CATCH_NULL; } + operator SafeBool::type() const { + return SafeBool::makeSafe( some() ); + } + + private: + T *nullableValue; + union { + char storage[sizeof(T)]; + + // These are here to force alignment for the storage + long double dummy1; + void (*dummy2)(); + long double dummy3; +#ifdef CATCH_CONFIG_CPP11_LONG_LONG + long long dummy4; #endif + }; + }; + +} // end namespace Catch + +namespace Catch { + + struct ITagAliasRegistry { + virtual ~ITagAliasRegistry(); + virtual Option find( std::string const& alias ) const = 0; + virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const = 0; + + static ITagAliasRegistry const& get(); + }; + +} // end namespace Catch // These files are included here so the single_include script doesn't put them // in the conditionally compiled sections -// start catch_test_case_info.h +// #included from: internal/catch_test_case_info.h +#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_H_INCLUDED #include -#include -#include +#include #ifdef __clang__ #pragma clang diagnostic push @@ -2376,7 +3235,7 @@ namespace Catch { namespace Catch { - struct ITestInvoker; + struct ITestCase; struct TestCaseInfo { enum SpecialProperties{ @@ -2385,30 +3244,30 @@ namespace Catch { ShouldFail = 1 << 2, MayFail = 1 << 3, Throws = 1 << 4, - NonPortable = 1 << 5, - Benchmark = 1 << 6 + NonPortable = 1 << 5 }; TestCaseInfo( std::string const& _name, std::string const& _className, std::string const& _description, - std::vector const& _tags, + std::set const& _tags, SourceLineInfo const& _lineInfo ); - friend void setTags( TestCaseInfo& testCaseInfo, std::vector tags ); + TestCaseInfo( TestCaseInfo const& other ); + + friend void setTags( TestCaseInfo& testCaseInfo, std::set const& tags ); bool isHidden() const; bool throws() const; bool okToFail() const; bool expectedToFail() const; - std::string tagsAsString() const; - std::string name; std::string className; std::string description; - std::vector tags; - std::vector lcaseTags; + std::set tags; + std::set lcaseTags; + std::string tagsAsString; SourceLineInfo lineInfo; SpecialProperties properties; }; @@ -2416,7 +3275,8 @@ namespace Catch { class TestCase : public TestCaseInfo { public: - TestCase( ITestInvoker* testCase, TestCaseInfo const& info ); + TestCase( ITestCase* testCase, TestCaseInfo const& info ); + TestCase( TestCase const& other ); TestCase withName( std::string const& _newName ) const; @@ -2424,14 +3284,16 @@ namespace Catch { TestCaseInfo const& getTestCaseInfo() const; + void swap( TestCase& other ); bool operator == ( TestCase const& other ) const; bool operator < ( TestCase const& other ) const; + TestCase& operator = ( TestCase const& other ); private: - std::shared_ptr test; + Ptr test; }; - TestCase makeTestCase( ITestInvoker* testCase, + TestCase makeTestCase( ITestCase* testCase, std::string const& className, std::string const& name, std::string const& description, @@ -2442,21 +3304,10 @@ namespace Catch { #pragma clang diagnostic pop #endif -// end catch_test_case_info.h -// start catch_interfaces_runner.h - -namespace Catch { - - struct IRunner { - virtual ~IRunner(); - virtual bool aborting() const = 0; - }; -} - -// end catch_interfaces_runner.h #ifdef __OBJC__ -// start catch_objc.hpp +// #included from: internal/catch_objc.hpp +#define TWOBLUECUBES_CATCH_OBJC_HPP_INCLUDED #import @@ -2480,7 +3331,7 @@ namespace Catch { namespace Catch { - class OcMethod : public ITestInvoker { + class OcMethod : public SharedImpl { public: OcMethod( Class cls, SEL sel ) : m_cls( cls ), m_sel( sel ) {} @@ -2516,9 +3367,9 @@ namespace Catch { } } - inline std::size_t registerTestMethods() { - std::size_t noTestMethods = 0; - int noClasses = objc_getClassList( nullptr, 0 ); + inline size_t registerTestMethods() { + size_t noTestMethods = 0; + int noClasses = objc_getClassList( CATCH_NULL, 0 ); Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses); objc_getClassList( classes, noClasses ); @@ -2537,7 +3388,7 @@ namespace Catch { std::string desc = Detail::getAnnotation( cls, "Description", testCaseName ); const char* className = class_getName( cls ); - getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, name.c_str(), desc.c_str(), SourceLineInfo("",0) ) ); + getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, name.c_str(), desc.c_str(), SourceLineInfo() ) ); noTestMethods++; } } @@ -2547,8 +3398,6 @@ namespace Catch { return noTestMethods; } -#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) - namespace Matchers { namespace Impl { namespace NSStringMatchers { @@ -2560,61 +3409,61 @@ namespace Catch { arcSafeRelease( m_substr ); } - bool match( NSString* arg ) const override { + virtual bool match( NSString* arg ) const CATCH_OVERRIDE { return false; } - NSString* CATCH_ARC_STRONG m_substr; + NSString* m_substr; }; struct Equals : StringHolder { Equals( NSString* substr ) : StringHolder( substr ){} - bool match( NSString* str ) const override { + virtual bool match( NSString* str ) const CATCH_OVERRIDE { return (str != nil || m_substr == nil ) && [str isEqualToString:m_substr]; } - std::string describe() const override { - return "equals string: " + Catch::Detail::stringify( m_substr ); + virtual std::string describe() const CATCH_OVERRIDE { + return "equals string: " + Catch::toString( m_substr ); } }; struct Contains : StringHolder { Contains( NSString* substr ) : StringHolder( substr ){} - bool match( NSString* str ) const { + virtual bool match( NSString* str ) const { return (str != nil || m_substr == nil ) && [str rangeOfString:m_substr].location != NSNotFound; } - std::string describe() const override { - return "contains string: " + Catch::Detail::stringify( m_substr ); + virtual std::string describe() const CATCH_OVERRIDE { + return "contains string: " + Catch::toString( m_substr ); } }; struct StartsWith : StringHolder { StartsWith( NSString* substr ) : StringHolder( substr ){} - bool match( NSString* str ) const override { + virtual bool match( NSString* str ) const { return (str != nil || m_substr == nil ) && [str rangeOfString:m_substr].location == 0; } - std::string describe() const override { - return "starts with: " + Catch::Detail::stringify( m_substr ); + virtual std::string describe() const CATCH_OVERRIDE { + return "starts with: " + Catch::toString( m_substr ); } }; struct EndsWith : StringHolder { EndsWith( NSString* substr ) : StringHolder( substr ){} - bool match( NSString* str ) const override { + virtual bool match( NSString* str ) const { return (str != nil || m_substr == nil ) && [str rangeOfString:m_substr].location == [str length] - [m_substr length]; } - std::string describe() const override { - return "ends with: " + Catch::Detail::stringify( m_substr ); + virtual std::string describe() const CATCH_OVERRIDE { + return "ends with: " + Catch::toString( m_substr ); } }; @@ -2637,52 +3486,86 @@ namespace Catch { using namespace Matchers; -#endif // CATCH_CONFIG_DISABLE_MATCHERS - } // namespace Catch /////////////////////////////////////////////////////////////////////////////// -#define OC_MAKE_UNIQUE_NAME( root, uniqueSuffix ) root##uniqueSuffix -#define OC_TEST_CASE2( name, desc, uniqueSuffix ) \ -+(NSString*) OC_MAKE_UNIQUE_NAME( Catch_Name_test_, uniqueSuffix ) \ -{ \ +#define OC_TEST_CASE( name, desc )\ ++(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Name_test ) \ +{\ return @ name; \ -} \ -+(NSString*) OC_MAKE_UNIQUE_NAME( Catch_Description_test_, uniqueSuffix ) \ +}\ ++(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Description_test ) \ { \ return @ desc; \ } \ --(void) OC_MAKE_UNIQUE_NAME( Catch_TestCase_test_, uniqueSuffix ) +-(void) INTERNAL_CATCH_UNIQUE_NAME( Catch_TestCase_test ) -#define OC_TEST_CASE( name, desc ) OC_TEST_CASE2( name, desc, __LINE__ ) - -// end catch_objc.hpp #endif -#ifdef CATCH_CONFIG_EXTERNAL_INTERFACES -// start catch_external_interfaces.h +#ifdef CATCH_IMPL -// start catch_reporter_bases.hpp +// !TBD: Move the leak detector code into a separate header +#ifdef CATCH_CONFIG_WINDOWS_CRTDBG +#include +class LeakDetector { +public: + LeakDetector() { + int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); + flag |= _CRTDBG_LEAK_CHECK_DF; + flag |= _CRTDBG_ALLOC_MEM_DF; + _CrtSetDbgFlag(flag); + _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG); + _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR); + // Change this to leaking allocation's number to break there + _CrtSetBreakAlloc(-1); + } +}; +#else +class LeakDetector {}; +#endif -// start catch_interfaces_reporter.h +LeakDetector leakDetector; -// start catch_config.hpp +// #included from: internal/catch_impl.hpp +#define TWOBLUECUBES_CATCH_IMPL_HPP_INCLUDED -// start catch_test_spec_parser.h +// Collect all the implementation files together here +// These are the equivalent of what would usually be cpp files + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wweak-vtables" +#endif + +// #included from: ../catch_session.hpp +#define TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED + +// #included from: internal/catch_commandline.hpp +#define TWOBLUECUBES_CATCH_COMMANDLINE_HPP_INCLUDED + +// #included from: catch_config.hpp +#define TWOBLUECUBES_CATCH_CONFIG_HPP_INCLUDED + +// #included from: catch_test_spec_parser.hpp +#define TWOBLUECUBES_CATCH_TEST_SPEC_PARSER_HPP_INCLUDED #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wpadded" #endif -// start catch_test_spec.h +// #included from: catch_test_spec.hpp +#define TWOBLUECUBES_CATCH_TEST_SPEC_HPP_INCLUDED #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wpadded" #endif -// start catch_wildcard_pattern.h +// #included from: catch_wildcard_pattern.hpp +#define TWOBLUECUBES_CATCH_WILDCARD_PATTERN_HPP_INCLUDED + +#include namespace Catch { @@ -2696,68 +3579,119 @@ namespace Catch public: - WildcardPattern( std::string const& pattern, CaseSensitive::Choice caseSensitivity ); - virtual ~WildcardPattern() = default; - virtual bool matches( std::string const& str ) const; + WildcardPattern( std::string const& pattern, CaseSensitive::Choice caseSensitivity ) + : m_caseSensitivity( caseSensitivity ), + m_wildcard( NoWildcard ), + m_pattern( adjustCase( pattern ) ) + { + if( startsWith( m_pattern, '*' ) ) { + m_pattern = m_pattern.substr( 1 ); + m_wildcard = WildcardAtStart; + } + if( endsWith( m_pattern, '*' ) ) { + m_pattern = m_pattern.substr( 0, m_pattern.size()-1 ); + m_wildcard = static_cast( m_wildcard | WildcardAtEnd ); + } + } + virtual ~WildcardPattern(); + virtual bool matches( std::string const& str ) const { + switch( m_wildcard ) { + case NoWildcard: + return m_pattern == adjustCase( str ); + case WildcardAtStart: + return endsWith( adjustCase( str ), m_pattern ); + case WildcardAtEnd: + return startsWith( adjustCase( str ), m_pattern ); + case WildcardAtBothEnds: + return contains( adjustCase( str ), m_pattern ); + } +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunreachable-code" +#endif + throw std::logic_error( "Unknown enum" ); +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + } private: - std::string adjustCase( std::string const& str ) const; + std::string adjustCase( std::string const& str ) const { + return m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str; + } CaseSensitive::Choice m_caseSensitivity; - WildcardPosition m_wildcard = NoWildcard; + WildcardPosition m_wildcard; std::string m_pattern; }; } -// end catch_wildcard_pattern.h #include #include -#include namespace Catch { class TestSpec { - struct Pattern { + struct Pattern : SharedImpl<> { virtual ~Pattern(); virtual bool matches( TestCaseInfo const& testCase ) const = 0; }; - using PatternPtr = std::shared_ptr; - class NamePattern : public Pattern { public: - NamePattern( std::string const& name ); + NamePattern( std::string const& name ) + : m_wildcardPattern( toLower( name ), CaseSensitive::No ) + {} virtual ~NamePattern(); - virtual bool matches( TestCaseInfo const& testCase ) const override; + virtual bool matches( TestCaseInfo const& testCase ) const { + return m_wildcardPattern.matches( toLower( testCase.name ) ); + } private: WildcardPattern m_wildcardPattern; }; class TagPattern : public Pattern { public: - TagPattern( std::string const& tag ); + TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {} virtual ~TagPattern(); - virtual bool matches( TestCaseInfo const& testCase ) const override; + virtual bool matches( TestCaseInfo const& testCase ) const { + return testCase.lcaseTags.find( m_tag ) != testCase.lcaseTags.end(); + } private: std::string m_tag; }; class ExcludedPattern : public Pattern { public: - ExcludedPattern( PatternPtr const& underlyingPattern ); + ExcludedPattern( Ptr const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {} virtual ~ExcludedPattern(); - virtual bool matches( TestCaseInfo const& testCase ) const override; + virtual bool matches( TestCaseInfo const& testCase ) const { return !m_underlyingPattern->matches( testCase ); } private: - PatternPtr m_underlyingPattern; + Ptr m_underlyingPattern; }; struct Filter { - std::vector m_patterns; + std::vector > m_patterns; - bool matches( TestCaseInfo const& testCase ) const; + bool matches( TestCaseInfo const& testCase ) const { + // All patterns in a filter must match for the filter to be a match + for( std::vector >::const_iterator it = m_patterns.begin(), itEnd = m_patterns.end(); it != itEnd; ++it ) { + if( !(*it)->matches( testCase ) ) + return false; + } + return true; + } }; public: - bool hasFilters() const; - bool matches( TestCaseInfo const& testCase ) const; + bool hasFilters() const { + return !m_filters.empty(); + } + bool matches( TestCaseInfo const& testCase ) const { + // A TestSpec matches if any filter matches + for( std::vector::const_iterator it = m_filters.begin(), itEnd = m_filters.end(); it != itEnd; ++it ) + if( it->matches( testCase ) ) + return true; + return false; + } private: std::vector m_filters; @@ -2770,56 +3704,87 @@ namespace Catch { #pragma clang diagnostic pop #endif -// end catch_test_spec.h -// start catch_interfaces_tag_alias_registry.h - -#include - -namespace Catch { - - struct TagAlias; - - struct ITagAliasRegistry { - virtual ~ITagAliasRegistry(); - // Nullptr if not present - virtual TagAlias const* find( std::string const& alias ) const = 0; - virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const = 0; - - static ITagAliasRegistry const& get(); - }; - -} // end namespace Catch - -// end catch_interfaces_tag_alias_registry.h namespace Catch { class TestSpecParser { enum Mode{ None, Name, QuotedName, Tag, EscapedName }; - Mode m_mode = None; - bool m_exclusion = false; - std::size_t m_start = std::string::npos, m_pos = 0; + Mode m_mode; + bool m_exclusion; + std::size_t m_start, m_pos; std::string m_arg; std::vector m_escapeChars; TestSpec::Filter m_currentFilter; TestSpec m_testSpec; - ITagAliasRegistry const* m_tagAliases = nullptr; + ITagAliasRegistry const* m_tagAliases; public: - TestSpecParser( ITagAliasRegistry const& tagAliases ); - - TestSpecParser& parse( std::string const& arg ); - TestSpec testSpec(); + TestSpecParser( ITagAliasRegistry const& tagAliases ) :m_mode(None), m_exclusion(false), m_start(0), m_pos(0), m_tagAliases( &tagAliases ) {} + TestSpecParser& parse( std::string const& arg ) { + m_mode = None; + m_exclusion = false; + m_start = std::string::npos; + m_arg = m_tagAliases->expandAliases( arg ); + m_escapeChars.clear(); + for( m_pos = 0; m_pos < m_arg.size(); ++m_pos ) + visitChar( m_arg[m_pos] ); + if( m_mode == Name ) + addPattern(); + return *this; + } + TestSpec testSpec() { + addFilter(); + return m_testSpec; + } private: - void visitChar( char c ); - void startNewMode( Mode mode, std::size_t start ); - void escape(); - std::string subString() const; - + void visitChar( char c ) { + if( m_mode == None ) { + switch( c ) { + case ' ': return; + case '~': m_exclusion = true; return; + case '[': return startNewMode( Tag, ++m_pos ); + case '"': return startNewMode( QuotedName, ++m_pos ); + case '\\': return escape(); + default: startNewMode( Name, m_pos ); break; + } + } + if( m_mode == Name ) { + if( c == ',' ) { + addPattern(); + addFilter(); + } + else if( c == '[' ) { + if( subString() == "exclude:" ) + m_exclusion = true; + else + addPattern(); + startNewMode( Tag, ++m_pos ); + } + else if( c == '\\' ) + escape(); + } + else if( m_mode == EscapedName ) + m_mode = Name; + else if( m_mode == QuotedName && c == '"' ) + addPattern(); + else if( m_mode == Tag && c == ']' ) + addPattern(); + } + void startNewMode( Mode mode, std::size_t start ) { + m_mode = mode; + m_start = start; + } + void escape() { + if( m_mode == None ) + m_start = m_pos; + m_mode = EscapedName; + m_escapeChars.push_back( m_pos ); + } + std::string subString() const { return m_arg.substr( m_start, m_pos - m_start ); } template void addPattern() { std::string token = subString(); - for( std::size_t i = 0; i < m_escapeChars.size(); ++i ) + for( size_t i = 0; i < m_escapeChars.size(); ++i ) token = token.substr( 0, m_escapeChars[i]-m_start-i ) + token.substr( m_escapeChars[i]-m_start-i+1 ); m_escapeChars.clear(); if( startsWith( token, "exclude:" ) ) { @@ -2827,18 +3792,24 @@ namespace Catch { token = token.substr( 8 ); } if( !token.empty() ) { - TestSpec::PatternPtr pattern = std::make_shared( token ); + Ptr pattern = new T( token ); if( m_exclusion ) - pattern = std::make_shared( pattern ); + pattern = new TestSpec::ExcludedPattern( pattern ); m_currentFilter.m_patterns.push_back( pattern ); } m_exclusion = false; m_mode = None; } - - void addFilter(); + void addFilter() { + if( !m_currentFilter.m_patterns.empty() ) { + m_testSpec.m_filters.push_back( m_currentFilter ); + m_currentFilter = TestSpec::Filter(); + } + } }; - TestSpec parseTestSpec( std::string const& arg ); + inline TestSpec parseTestSpec( std::string const& arg ) { + return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec(); + } } // namespace Catch @@ -2846,21 +3817,20 @@ namespace Catch { #pragma clang diagnostic pop #endif -// end catch_test_spec_parser.h -// start catch_interfaces_config.h +// #included from: catch_interfaces_config.h +#define TWOBLUECUBES_CATCH_INTERFACES_CONFIG_H_INCLUDED #include #include #include -#include namespace Catch { - enum class Verbosity { - Quiet = 0, - Normal, - High - }; + struct Verbosity { enum Level { + NoOutput = 0, + Quiet, + Normal + }; }; struct WarnAbout { enum What { Nothing = 0x00, @@ -2882,16 +3852,10 @@ namespace Catch { Yes, No }; }; - struct WaitForKeypress { enum When { - Never, - BeforeStart = 1, - BeforeExit = 2, - BeforeStartAndExit = BeforeStart | BeforeExit - }; }; class TestSpec; - struct IConfig : NonCopyable { + struct IConfig : IShared { virtual ~IConfig(); @@ -2907,20 +3871,17 @@ namespace Catch { virtual TestSpec const& testSpec() const = 0; virtual RunTests::InWhatOrder runOrder() const = 0; virtual unsigned int rngSeed() const = 0; - virtual int benchmarkResolutionMultiple() const = 0; virtual UseColour::YesOrNo useColour() const = 0; virtual std::vector const& getSectionsToRun() const = 0; - virtual Verbosity verbosity() const = 0; - }; - using IConfigPtr = std::shared_ptr; + }; } -// end catch_interfaces_config.h -// Libstdc++ doesn't like incomplete classes for unique_ptr -// start catch_stream.h +// #included from: catch_stream.h +#define TWOBLUECUBES_CATCH_STREAM_H_INCLUDED -// start catch_streambuf.h +// #included from: catch_streambuf.h +#define TWOBLUECUBES_CATCH_STREAMBUF_H_INCLUDED #include @@ -2928,11 +3889,10 @@ namespace Catch { class StreamBufBase : public std::streambuf { public: - virtual ~StreamBufBase(); + virtual ~StreamBufBase() CATCH_NOEXCEPT; }; } -// end catch_streambuf.h #include #include #include @@ -2945,7 +3905,7 @@ namespace Catch { std::ostream& clog(); struct IStream { - virtual ~IStream(); + virtual ~IStream() CATCH_NOEXCEPT; virtual std::ostream& stream() const = 0; }; @@ -2953,38 +3913,37 @@ namespace Catch { mutable std::ofstream m_ofs; public: FileStream( std::string const& filename ); - ~FileStream() override = default; + virtual ~FileStream() CATCH_NOEXCEPT; public: // IStream - std::ostream& stream() const override; + virtual std::ostream& stream() const CATCH_OVERRIDE; }; class CoutStream : public IStream { mutable std::ostream m_os; public: CoutStream(); - ~CoutStream() override = default; + virtual ~CoutStream() CATCH_NOEXCEPT; public: // IStream - std::ostream& stream() const override; + virtual std::ostream& stream() const CATCH_OVERRIDE; }; class DebugOutStream : public IStream { - std::unique_ptr m_streamBuf; + CATCH_AUTO_PTR( StreamBufBase ) m_streamBuf; mutable std::ostream m_os; public: DebugOutStream(); - ~DebugOutStream() override = default; + virtual ~DebugOutStream() CATCH_NOEXCEPT; public: // IStream - std::ostream& stream() const override; + virtual std::ostream& stream() const CATCH_OVERRIDE; }; } -// end catch_stream.h - #include #include #include +#include #ifndef CATCH_CONFIG_CONSOLE_WIDTH #define CATCH_CONFIG_CONSOLE_WIDTH 80 @@ -2992,32 +3951,50 @@ namespace Catch { namespace Catch { - struct IStream; - struct ConfigData { - bool listTests = false; - bool listTags = false; - bool listReporters = false; - bool listTestNamesOnly = false; - bool showSuccessfulTests = false; - bool shouldDebugBreak = false; - bool noThrow = false; - bool showHelp = false; - bool showInvisibles = false; - bool filenamesAsTags = false; - bool libIdentify = false; + ConfigData() + : listTests( false ), + listTags( false ), + listReporters( false ), + listTestNamesOnly( false ), + listExtraInfo( false ), + showSuccessfulTests( false ), + shouldDebugBreak( false ), + noThrow( false ), + showHelp( false ), + showInvisibles( false ), + filenamesAsTags( false ), + abortAfter( -1 ), + rngSeed( 0 ), + verbosity( Verbosity::Normal ), + warnings( WarnAbout::Nothing ), + showDurations( ShowDurations::DefaultForReporter ), + runOrder( RunTests::InDeclarationOrder ), + useColour( UseColour::Auto ) + {} - int abortAfter = -1; - unsigned int rngSeed = 0; - int benchmarkResolutionMultiple = 100; + bool listTests; + bool listTags; + bool listReporters; + bool listTestNamesOnly; + bool listExtraInfo; - Verbosity verbosity = Verbosity::Normal; - WarnAbout::What warnings = WarnAbout::Nothing; - ShowDurations::OrNot showDurations = ShowDurations::DefaultForReporter; - RunTests::InWhatOrder runOrder = RunTests::InDeclarationOrder; - UseColour::YesOrNo useColour = UseColour::Auto; - WaitForKeypress::When waitForKeypress = WaitForKeypress::Never; + bool showSuccessfulTests; + bool shouldDebugBreak; + bool noThrow; + bool showHelp; + bool showInvisibles; + bool filenamesAsTags; + + int abortAfter; + unsigned int rngSeed; + + Verbosity::Level verbosity; + WarnAbout::What warnings; + ShowDurations::OrNot showDurations; + RunTests::InWhatOrder runOrder; + UseColour::YesOrNo useColour; std::string outputFilename; std::string name; @@ -3028,638 +4005,1505 @@ namespace Catch { std::vector sectionsToRun; }; - class Config : public IConfig { + class Config : public SharedImpl { + private: + Config( Config const& other ); + Config& operator = ( Config const& other ); + virtual void dummy(); public: - Config() = default; - Config( ConfigData const& data ); - virtual ~Config() = default; + Config() + {} - std::string const& getFilename() const; + Config( ConfigData const& data ) + : m_data( data ), + m_stream( openStream() ) + { + if( !data.testsOrTags.empty() ) { + TestSpecParser parser( ITagAliasRegistry::get() ); + for( std::size_t i = 0; i < data.testsOrTags.size(); ++i ) + parser.parse( data.testsOrTags[i] ); + m_testSpec = parser.testSpec(); + } + } - bool listTests() const; - bool listTestNamesOnly() const; - bool listTags() const; - bool listReporters() const; + virtual ~Config() {} - std::string getProcessName() const; + std::string const& getFilename() const { + return m_data.outputFilename ; + } - std::vector const& getReporterNames() const; - std::vector const& getSectionsToRun() const override; + bool listTests() const { return m_data.listTests; } + bool listTestNamesOnly() const { return m_data.listTestNamesOnly; } + bool listTags() const { return m_data.listTags; } + bool listReporters() const { return m_data.listReporters; } + bool listExtraInfo() const { return m_data.listExtraInfo; } - virtual TestSpec const& testSpec() const override; + std::string getProcessName() const { return m_data.processName; } - bool showHelp() const; + std::vector const& getReporterNames() const { return m_data.reporterNames; } + std::vector const& getSectionsToRun() const CATCH_OVERRIDE { return m_data.sectionsToRun; } + + virtual TestSpec const& testSpec() const CATCH_OVERRIDE { return m_testSpec; } + + bool showHelp() const { return m_data.showHelp; } // IConfig interface - bool allowThrows() const override; - std::ostream& stream() const override; - std::string name() const override; - bool includeSuccessfulResults() const override; - bool warnAboutMissingAssertions() const override; - ShowDurations::OrNot showDurations() const override; - RunTests::InWhatOrder runOrder() const override; - unsigned int rngSeed() const override; - int benchmarkResolutionMultiple() const override; - UseColour::YesOrNo useColour() const override; - bool shouldDebugBreak() const override; - int abortAfter() const override; - bool showInvisibles() const override; - Verbosity verbosity() const override; + virtual bool allowThrows() const CATCH_OVERRIDE { return !m_data.noThrow; } + virtual std::ostream& stream() const CATCH_OVERRIDE { return m_stream->stream(); } + virtual std::string name() const CATCH_OVERRIDE { return m_data.name.empty() ? m_data.processName : m_data.name; } + virtual bool includeSuccessfulResults() const CATCH_OVERRIDE { return m_data.showSuccessfulTests; } + virtual bool warnAboutMissingAssertions() const CATCH_OVERRIDE { return m_data.warnings & WarnAbout::NoAssertions; } + virtual ShowDurations::OrNot showDurations() const CATCH_OVERRIDE { return m_data.showDurations; } + virtual RunTests::InWhatOrder runOrder() const CATCH_OVERRIDE { return m_data.runOrder; } + virtual unsigned int rngSeed() const CATCH_OVERRIDE { return m_data.rngSeed; } + virtual UseColour::YesOrNo useColour() const CATCH_OVERRIDE { return m_data.useColour; } + virtual bool shouldDebugBreak() const CATCH_OVERRIDE { return m_data.shouldDebugBreak; } + virtual int abortAfter() const CATCH_OVERRIDE { return m_data.abortAfter; } + virtual bool showInvisibles() const CATCH_OVERRIDE { return m_data.showInvisibles; } private: - IStream const* openStream(); + IStream const* openStream() { + if( m_data.outputFilename.empty() ) + return new CoutStream(); + else if( m_data.outputFilename[0] == '%' ) { + if( m_data.outputFilename == "%debug" ) + return new DebugOutStream(); + else + throw std::domain_error( "Unrecognised stream: " + m_data.outputFilename ); + } + else + return new FileStream( m_data.outputFilename ); + } ConfigData m_data; - std::unique_ptr m_stream; + CATCH_AUTO_PTR( IStream const ) m_stream; TestSpec m_testSpec; }; } // end namespace Catch -// end catch_config.hpp -// start catch_assertionresult.h +// #included from: catch_clara.h +#define TWOBLUECUBES_CATCH_CLARA_H_INCLUDED + +// Use Catch's value for console width (store Clara's off to the side, if present) +#ifdef CLARA_CONFIG_CONSOLE_WIDTH +#define CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH CLARA_CONFIG_CONSOLE_WIDTH +#undef CLARA_CONFIG_CONSOLE_WIDTH +#endif +#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH + +// Declare Clara inside the Catch namespace +#define STITCH_CLARA_OPEN_NAMESPACE namespace Catch { +// #included from: ../external/clara.h + +// Version 0.0.2.4 + +// Only use header guard if we are not using an outer namespace +#if !defined(TWOBLUECUBES_CLARA_H_INCLUDED) || defined(STITCH_CLARA_OPEN_NAMESPACE) + +#ifndef STITCH_CLARA_OPEN_NAMESPACE +#define TWOBLUECUBES_CLARA_H_INCLUDED +#define STITCH_CLARA_OPEN_NAMESPACE +#define STITCH_CLARA_CLOSE_NAMESPACE +#else +#define STITCH_CLARA_CLOSE_NAMESPACE } +#endif + +#define STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE STITCH_CLARA_OPEN_NAMESPACE + +// ----------- #included from tbc_text_format.h ----------- + +// Only use header guard if we are not using an outer namespace +#if !defined(TBC_TEXT_FORMAT_H_INCLUDED) || defined(STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE) +#ifndef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE +#define TBC_TEXT_FORMAT_H_INCLUDED +#endif #include - -namespace Catch { - - struct AssertionResultData - { - AssertionResultData() = delete; - - AssertionResultData( ResultWas::OfType _resultType, LazyExpression const& _lazyExpression ); - - std::string message; - mutable std::string reconstructedExpression; - LazyExpression lazyExpression; - ResultWas::OfType resultType; - - std::string reconstructExpression() const; - }; - - class AssertionResult { - public: - AssertionResult() = delete; - AssertionResult( AssertionInfo const& info, AssertionResultData const& data ); - - bool isOk() const; - bool succeeded() const; - ResultWas::OfType getResultType() const; - bool hasExpression() const; - bool hasMessage() const; - std::string getExpression() const; - std::string getExpressionInMacro() const; - bool hasExpandedExpression() const; - std::string getExpandedExpression() const; - std::string getMessage() const; - SourceLineInfo getSourceInfo() const; - std::string getTestMacroName() const; - - //protected: - AssertionInfo m_info; - AssertionResultData m_resultData; - }; - -} // end namespace Catch - -// end catch_assertionresult.h -// start catch_option.hpp - -namespace Catch { - - // An optional type - template - class Option { - public: - Option() : nullableValue( nullptr ) {} - Option( T const& _value ) - : nullableValue( new( storage ) T( _value ) ) - {} - Option( Option const& _other ) - : nullableValue( _other ? new( storage ) T( *_other ) : nullptr ) - {} - - ~Option() { - reset(); - } - - Option& operator= ( Option const& _other ) { - if( &_other != this ) { - reset(); - if( _other ) - nullableValue = new( storage ) T( *_other ); - } - return *this; - } - Option& operator = ( T const& _value ) { - reset(); - nullableValue = new( storage ) T( _value ); - return *this; - } - - void reset() { - if( nullableValue ) - nullableValue->~T(); - nullableValue = nullptr; - } - - T& operator*() { return *nullableValue; } - T const& operator*() const { return *nullableValue; } - T* operator->() { return nullableValue; } - const T* operator->() const { return nullableValue; } - - T valueOr( T const& defaultValue ) const { - return nullableValue ? *nullableValue : defaultValue; - } - - bool some() const { return nullableValue != nullptr; } - bool none() const { return nullableValue == nullptr; } - - bool operator !() const { return nullableValue == nullptr; } - explicit operator bool() const { - return some(); - } - - private: - T *nullableValue; - alignas(alignof(T)) char storage[sizeof(T)]; - }; - -} // end namespace Catch - -// end catch_option.hpp -#include -#include -#include -#include -#include - -namespace Catch { - - struct ReporterConfig { - explicit ReporterConfig( IConfigPtr const& _fullConfig ); - - ReporterConfig( IConfigPtr const& _fullConfig, std::ostream& _stream ); - - std::ostream& stream() const; - IConfigPtr fullConfig() const; - - private: - std::ostream* m_stream; - IConfigPtr m_fullConfig; - }; - - struct ReporterPreferences { - bool shouldRedirectStdOut = false; - }; - - template - struct LazyStat : Option { - LazyStat& operator=( T const& _value ) { - Option::operator=( _value ); - used = false; - return *this; - } - void reset() { - Option::reset(); - used = false; - } - bool used = false; - }; - - struct TestRunInfo { - TestRunInfo( std::string const& _name ); - std::string name; - }; - struct GroupInfo { - GroupInfo( std::string const& _name, - std::size_t _groupIndex, - std::size_t _groupsCount ); - - std::string name; - std::size_t groupIndex; - std::size_t groupsCounts; - }; - - struct AssertionStats { - AssertionStats( AssertionResult const& _assertionResult, - std::vector const& _infoMessages, - Totals const& _totals ); - - AssertionStats( AssertionStats const& ) = default; - AssertionStats( AssertionStats && ) = default; - AssertionStats& operator = ( AssertionStats const& ) = default; - AssertionStats& operator = ( AssertionStats && ) = default; - virtual ~AssertionStats(); - - AssertionResult assertionResult; - std::vector infoMessages; - Totals totals; - }; - - struct SectionStats { - SectionStats( SectionInfo const& _sectionInfo, - Counts const& _assertions, - double _durationInSeconds, - bool _missingAssertions ); - SectionStats( SectionStats const& ) = default; - SectionStats( SectionStats && ) = default; - SectionStats& operator = ( SectionStats const& ) = default; - SectionStats& operator = ( SectionStats && ) = default; - virtual ~SectionStats(); - - SectionInfo sectionInfo; - Counts assertions; - double durationInSeconds; - bool missingAssertions; - }; - - struct TestCaseStats { - TestCaseStats( TestCaseInfo const& _testInfo, - Totals const& _totals, - std::string const& _stdOut, - std::string const& _stdErr, - bool _aborting ); - - TestCaseStats( TestCaseStats const& ) = default; - TestCaseStats( TestCaseStats && ) = default; - TestCaseStats& operator = ( TestCaseStats const& ) = default; - TestCaseStats& operator = ( TestCaseStats && ) = default; - virtual ~TestCaseStats(); - - TestCaseInfo testInfo; - Totals totals; - std::string stdOut; - std::string stdErr; - bool aborting; - }; - - struct TestGroupStats { - TestGroupStats( GroupInfo const& _groupInfo, - Totals const& _totals, - bool _aborting ); - TestGroupStats( GroupInfo const& _groupInfo ); - - TestGroupStats( TestGroupStats const& ) = default; - TestGroupStats( TestGroupStats && ) = default; - TestGroupStats& operator = ( TestGroupStats const& ) = default; - TestGroupStats& operator = ( TestGroupStats && ) = default; - virtual ~TestGroupStats(); - - GroupInfo groupInfo; - Totals totals; - bool aborting; - }; - - struct TestRunStats { - TestRunStats( TestRunInfo const& _runInfo, - Totals const& _totals, - bool _aborting ); - - TestRunStats( TestRunStats const& ) = default; - TestRunStats( TestRunStats && ) = default; - TestRunStats& operator = ( TestRunStats const& ) = default; - TestRunStats& operator = ( TestRunStats && ) = default; - virtual ~TestRunStats(); - - TestRunInfo runInfo; - Totals totals; - bool aborting; - }; - - struct BenchmarkInfo { - std::string name; - }; - struct BenchmarkStats { - BenchmarkInfo info; - std::size_t iterations; - uint64_t elapsedTimeInNanoseconds; - }; - - struct IStreamingReporter { - virtual ~IStreamingReporter() = default; - - // Implementing class must also provide the following static methods: - // static std::string getDescription(); - // static std::set getSupportedVerbosities() - - virtual ReporterPreferences getPreferences() const = 0; - - virtual void noMatchingTestCases( std::string const& spec ) = 0; - - virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0; - virtual void testGroupStarting( GroupInfo const& groupInfo ) = 0; - - virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0; - virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0; - - // *** experimental *** - virtual void benchmarkStarting( BenchmarkInfo const& ) {} - - virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0; - - // The return value indicates if the messages buffer should be cleared: - virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0; - - // *** experimental *** - virtual void benchmarkEnded( BenchmarkStats const& ) {} - - virtual void sectionEnded( SectionStats const& sectionStats ) = 0; - virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0; - virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0; - virtual void testRunEnded( TestRunStats const& testRunStats ) = 0; - - virtual void skipTest( TestCaseInfo const& testInfo ) = 0; - - // Default empty implementation provided - virtual void fatalErrorEncountered( StringRef name ); - - virtual bool isMulti() const; - }; - using IStreamingReporterPtr = std::unique_ptr; - - struct IReporterFactory { - virtual ~IReporterFactory(); - virtual IStreamingReporterPtr create( ReporterConfig const& config ) const = 0; - virtual std::string getDescription() const = 0; - }; - using IReporterFactoryPtr = std::shared_ptr; - - struct IReporterRegistry { - using FactoryMap = std::map; - using Listeners = std::vector; - - virtual ~IReporterRegistry(); - virtual IStreamingReporterPtr create( std::string const& name, IConfigPtr const& config ) const = 0; - virtual FactoryMap const& getFactories() const = 0; - virtual Listeners const& getListeners() const = 0; - }; - - void addReporter( IStreamingReporterPtr& existingReporter, IStreamingReporterPtr&& additionalReporter ); - -} // end namespace Catch - -// end catch_interfaces_reporter.h +#include +#include #include -#include -#include -#include -#include +#include + +// Use optional outer namespace +#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE +namespace STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE { +#endif + +namespace Tbc { + +#ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH + const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH; +#else + const unsigned int consoleWidth = 80; +#endif + + struct TextAttributes { + TextAttributes() + : initialIndent( std::string::npos ), + indent( 0 ), + width( consoleWidth-1 ), + tabChar( '\t' ) + {} + + TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; } + TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; } + TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; } + TextAttributes& setTabChar( char _value ) { tabChar = _value; return *this; } + + std::size_t initialIndent; // indent of first line, or npos + std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos + std::size_t width; // maximum width of text, including indent. Longer text will wrap + char tabChar; // If this char is seen the indent is changed to current pos + }; + + class Text { + public: + Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() ) + : attr( _attr ) + { + std::string wrappableChars = " [({.,/|\\-"; + std::size_t indent = _attr.initialIndent != std::string::npos + ? _attr.initialIndent + : _attr.indent; + std::string remainder = _str; + + while( !remainder.empty() ) { + if( lines.size() >= 1000 ) { + lines.push_back( "... message truncated due to excessive size" ); + return; + } + std::size_t tabPos = std::string::npos; + std::size_t width = (std::min)( remainder.size(), _attr.width - indent ); + std::size_t pos = remainder.find_first_of( '\n' ); + if( pos <= width ) { + width = pos; + } + pos = remainder.find_last_of( _attr.tabChar, width ); + if( pos != std::string::npos ) { + tabPos = pos; + if( remainder[width] == '\n' ) + width--; + remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 ); + } + + if( width == remainder.size() ) { + spliceLine( indent, remainder, width ); + } + else if( remainder[width] == '\n' ) { + spliceLine( indent, remainder, width ); + if( width <= 1 || remainder.size() != 1 ) + remainder = remainder.substr( 1 ); + indent = _attr.indent; + } + else { + pos = remainder.find_last_of( wrappableChars, width ); + if( pos != std::string::npos && pos > 0 ) { + spliceLine( indent, remainder, pos ); + if( remainder[0] == ' ' ) + remainder = remainder.substr( 1 ); + } + else { + spliceLine( indent, remainder, width-1 ); + lines.back() += "-"; + } + if( lines.size() == 1 ) + indent = _attr.indent; + if( tabPos != std::string::npos ) + indent += tabPos; + } + } + } + + void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) { + lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) ); + _remainder = _remainder.substr( _pos ); + } + + typedef std::vector::const_iterator const_iterator; + + const_iterator begin() const { return lines.begin(); } + const_iterator end() const { return lines.end(); } + std::string const& last() const { return lines.back(); } + std::size_t size() const { return lines.size(); } + std::string const& operator[]( std::size_t _index ) const { return lines[_index]; } + std::string toString() const { + std::ostringstream oss; + oss << *this; + return oss.str(); + } + + friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) { + for( Text::const_iterator it = _text.begin(), itEnd = _text.end(); + it != itEnd; ++it ) { + if( it != _text.begin() ) + _stream << "\n"; + _stream << *it; + } + return _stream; + } + + private: + std::string str; + TextAttributes attr; + std::vector lines; + }; + +} // end namespace Tbc + +#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE +} // end outer namespace +#endif + +#endif // TBC_TEXT_FORMAT_H_INCLUDED + +// ----------- end of #include from tbc_text_format.h ----------- +// ........... back in clara.h + +#undef STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE + +// ----------- #included from clara_compilers.h ----------- + +#ifndef TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED +#define TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED + +// Detect a number of compiler features - mostly C++11/14 conformance - by compiler +// The following features are defined: +// +// CLARA_CONFIG_CPP11_NULLPTR : is nullptr supported? +// CLARA_CONFIG_CPP11_NOEXCEPT : is noexcept supported? +// CLARA_CONFIG_CPP11_GENERATED_METHODS : The delete and default keywords for compiler generated methods +// CLARA_CONFIG_CPP11_OVERRIDE : is override supported? +// CLARA_CONFIG_CPP11_UNIQUE_PTR : is unique_ptr supported (otherwise use auto_ptr) + +// CLARA_CONFIG_CPP11_OR_GREATER : Is C++11 supported? + +// CLARA_CONFIG_VARIADIC_MACROS : are variadic macros supported? + +// In general each macro has a _NO_ form +// (e.g. CLARA_CONFIG_CPP11_NO_NULLPTR) which disables the feature. +// Many features, at point of detection, define an _INTERNAL_ macro, so they +// can be combined, en-mass, with the _NO_ forms later. + +// All the C++11 features can be disabled with CLARA_CONFIG_NO_CPP11 + +#ifdef __clang__ + +#if __has_feature(cxx_nullptr) +#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR +#endif + +#if __has_feature(cxx_noexcept) +#define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT +#endif + +#endif // __clang__ + +//////////////////////////////////////////////////////////////////////////////// +// GCC +#ifdef __GNUC__ + +#if __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__) +#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR +#endif + +// - otherwise more recent versions define __cplusplus >= 201103L +// and will get picked up below + +#endif // __GNUC__ + +//////////////////////////////////////////////////////////////////////////////// +// Visual C++ +#ifdef _MSC_VER + +#if (_MSC_VER >= 1600) +#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR +#define CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR +#endif + +#if (_MSC_VER >= 1900 ) // (VC++ 13 (VS2015)) +#define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT +#define CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +#endif + +#endif // _MSC_VER + +//////////////////////////////////////////////////////////////////////////////// +// C++ language feature support + +// catch all support for C++11 +#if defined(__cplusplus) && __cplusplus >= 201103L + +#define CLARA_CPP11_OR_GREATER + +#if !defined(CLARA_INTERNAL_CONFIG_CPP11_NULLPTR) +#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR +#endif + +#ifndef CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT +#define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT +#endif + +#ifndef CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +#define CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +#endif + +#if !defined(CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE) +#define CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE +#endif +#if !defined(CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) +#define CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR +#endif + +#endif // __cplusplus >= 201103L + +// Now set the actual defines based on the above + anything the user has configured +#if defined(CLARA_INTERNAL_CONFIG_CPP11_NULLPTR) && !defined(CLARA_CONFIG_CPP11_NO_NULLPTR) && !defined(CLARA_CONFIG_CPP11_NULLPTR) && !defined(CLARA_CONFIG_NO_CPP11) +#define CLARA_CONFIG_CPP11_NULLPTR +#endif +#if defined(CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_CONFIG_CPP11_NO_NOEXCEPT) && !defined(CLARA_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_CONFIG_NO_CPP11) +#define CLARA_CONFIG_CPP11_NOEXCEPT +#endif +#if defined(CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS) && !defined(CLARA_CONFIG_CPP11_NO_GENERATED_METHODS) && !defined(CLARA_CONFIG_CPP11_GENERATED_METHODS) && !defined(CLARA_CONFIG_NO_CPP11) +#define CLARA_CONFIG_CPP11_GENERATED_METHODS +#endif +#if defined(CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE) && !defined(CLARA_CONFIG_NO_OVERRIDE) && !defined(CLARA_CONFIG_CPP11_OVERRIDE) && !defined(CLARA_CONFIG_NO_CPP11) +#define CLARA_CONFIG_CPP11_OVERRIDE +#endif +#if defined(CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) && !defined(CLARA_CONFIG_NO_UNIQUE_PTR) && !defined(CLARA_CONFIG_CPP11_UNIQUE_PTR) && !defined(CLARA_CONFIG_NO_CPP11) +#define CLARA_CONFIG_CPP11_UNIQUE_PTR +#endif + +// noexcept support: +#if defined(CLARA_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_NOEXCEPT) +#define CLARA_NOEXCEPT noexcept +# define CLARA_NOEXCEPT_IS(x) noexcept(x) +#else +#define CLARA_NOEXCEPT throw() +# define CLARA_NOEXCEPT_IS(x) +#endif + +// nullptr support +#ifdef CLARA_CONFIG_CPP11_NULLPTR +#define CLARA_NULL nullptr +#else +#define CLARA_NULL NULL +#endif + +// override support +#ifdef CLARA_CONFIG_CPP11_OVERRIDE +#define CLARA_OVERRIDE override +#else +#define CLARA_OVERRIDE +#endif + +// unique_ptr support +#ifdef CLARA_CONFIG_CPP11_UNIQUE_PTR +# define CLARA_AUTO_PTR( T ) std::unique_ptr +#else +# define CLARA_AUTO_PTR( T ) std::auto_ptr +#endif + +#endif // TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED + +// ----------- end of #include from clara_compilers.h ----------- +// ........... back in clara.h + +#include +#include #include -namespace Catch { - void prepareExpandedExpression(AssertionResult& result); +#if defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) +#define CLARA_PLATFORM_WINDOWS +#endif - // Returns double formatted as %.3f (format expected on output) - std::string getFormattedDuration( double duration ); +// Use optional outer namespace +#ifdef STITCH_CLARA_OPEN_NAMESPACE +STITCH_CLARA_OPEN_NAMESPACE +#endif - template - struct StreamingReporterBase : IStreamingReporter { +namespace Clara { - StreamingReporterBase( ReporterConfig const& _config ) - : m_config( _config.fullConfig() ), - stream( _config.stream() ) - { - m_reporterPrefs.shouldRedirectStdOut = false; - CATCH_ENFORCE( DerivedT::getSupportedVerbosities().count( m_config->verbosity() ), "Verbosity level not supported by this reporter" ); + struct UnpositionalTag {}; + + extern UnpositionalTag _; + +#ifdef CLARA_CONFIG_MAIN + UnpositionalTag _; +#endif + + namespace Detail { + +#ifdef CLARA_CONSOLE_WIDTH + const unsigned int consoleWidth = CLARA_CONFIG_CONSOLE_WIDTH; +#else + const unsigned int consoleWidth = 80; +#endif + + using namespace Tbc; + + inline bool startsWith( std::string const& str, std::string const& prefix ) { + return str.size() >= prefix.size() && str.substr( 0, prefix.size() ) == prefix; } - ReporterPreferences getPreferences() const override { - return m_reporterPrefs; + template struct RemoveConstRef{ typedef T type; }; + template struct RemoveConstRef{ typedef T type; }; + template struct RemoveConstRef{ typedef T type; }; + template struct RemoveConstRef{ typedef T type; }; + + template struct IsBool { static const bool value = false; }; + template<> struct IsBool { static const bool value = true; }; + + template + void convertInto( std::string const& _source, T& _dest ) { + std::stringstream ss; + ss << _source; + ss >> _dest; + if( ss.fail() ) + throw std::runtime_error( "Unable to convert " + _source + " to destination type" ); + } + inline void convertInto( std::string const& _source, std::string& _dest ) { + _dest = _source; + } + char toLowerCh(char c) { + return static_cast( std::tolower( c ) ); + } + inline void convertInto( std::string const& _source, bool& _dest ) { + std::string sourceLC = _source; + std::transform( sourceLC.begin(), sourceLC.end(), sourceLC.begin(), toLowerCh ); + if( sourceLC == "y" || sourceLC == "1" || sourceLC == "true" || sourceLC == "yes" || sourceLC == "on" ) + _dest = true; + else if( sourceLC == "n" || sourceLC == "0" || sourceLC == "false" || sourceLC == "no" || sourceLC == "off" ) + _dest = false; + else + throw std::runtime_error( "Expected a boolean value but did not recognise:\n '" + _source + "'" ); } - static std::set getSupportedVerbosities() { - return { Verbosity::Normal }; - } - - ~StreamingReporterBase() override = default; - - void noMatchingTestCases(std::string const&) override {} - - void testRunStarting(TestRunInfo const& _testRunInfo) override { - currentTestRunInfo = _testRunInfo; - } - void testGroupStarting(GroupInfo const& _groupInfo) override { - currentGroupInfo = _groupInfo; - } - - void testCaseStarting(TestCaseInfo const& _testInfo) override { - currentTestCaseInfo = _testInfo; - } - void sectionStarting(SectionInfo const& _sectionInfo) override { - m_sectionStack.push_back(_sectionInfo); - } - - void sectionEnded(SectionStats const& /* _sectionStats */) override { - m_sectionStack.pop_back(); - } - void testCaseEnded(TestCaseStats const& /* _testCaseStats */) override { - currentTestCaseInfo.reset(); - } - void testGroupEnded(TestGroupStats const& /* _testGroupStats */) override { - currentGroupInfo.reset(); - } - void testRunEnded(TestRunStats const& /* _testRunStats */) override { - currentTestCaseInfo.reset(); - currentGroupInfo.reset(); - currentTestRunInfo.reset(); - } - - void skipTest(TestCaseInfo const&) override { - // Don't do anything with this by default. - // It can optionally be overridden in the derived class. - } - - IConfigPtr m_config; - std::ostream& stream; - - LazyStat currentTestRunInfo; - LazyStat currentGroupInfo; - LazyStat currentTestCaseInfo; - - std::vector m_sectionStack; - ReporterPreferences m_reporterPrefs; - }; - - template - struct CumulativeReporterBase : IStreamingReporter { - template - struct Node { - explicit Node( T const& _value ) : value( _value ) {} - virtual ~Node() {} - - using ChildNodes = std::vector>; - T value; - ChildNodes children; - }; - struct SectionNode { - explicit SectionNode(SectionStats const& _stats) : stats(_stats) {} - virtual ~SectionNode() = default; - - bool operator == (SectionNode const& other) const { - return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo; - } - bool operator == (std::shared_ptr const& other) const { - return operator==(*other); - } - - SectionStats stats; - using ChildSections = std::vector>; - using Assertions = std::vector; - ChildSections childSections; - Assertions assertions; - std::string stdOut; - std::string stdErr; + template + struct IArgFunction { + virtual ~IArgFunction() {} +#ifdef CLARA_CONFIG_CPP11_GENERATED_METHODS + IArgFunction() = default; + IArgFunction( IArgFunction const& ) = default; +#endif + virtual void set( ConfigT& config, std::string const& value ) const = 0; + virtual bool takesArg() const = 0; + virtual IArgFunction* clone() const = 0; }; - struct BySectionInfo { - BySectionInfo( SectionInfo const& other ) : m_other( other ) {} - BySectionInfo( BySectionInfo const& other ) : m_other( other.m_other ) {} - bool operator() (std::shared_ptr const& node) const { - return ((node->stats.sectionInfo.name == m_other.name) && - (node->stats.sectionInfo.lineInfo == m_other.lineInfo)); + template + class BoundArgFunction { + public: + BoundArgFunction() : functionObj( CLARA_NULL ) {} + BoundArgFunction( IArgFunction* _functionObj ) : functionObj( _functionObj ) {} + BoundArgFunction( BoundArgFunction const& other ) : functionObj( other.functionObj ? other.functionObj->clone() : CLARA_NULL ) {} + BoundArgFunction& operator = ( BoundArgFunction const& other ) { + IArgFunction* newFunctionObj = other.functionObj ? other.functionObj->clone() : CLARA_NULL; + delete functionObj; + functionObj = newFunctionObj; + return *this; } - void operator=(BySectionInfo const&) = delete; + ~BoundArgFunction() { delete functionObj; } + void set( ConfigT& config, std::string const& value ) const { + functionObj->set( config, value ); + } + bool takesArg() const { return functionObj->takesArg(); } + + bool isSet() const { + return functionObj != CLARA_NULL; + } private: - SectionInfo const& m_other; + IArgFunction* functionObj; }; - using TestCaseNode = Node; - using TestGroupNode = Node; - using TestRunNode = Node; + template + struct NullBinder : IArgFunction{ + virtual void set( C&, std::string const& ) const {} + virtual bool takesArg() const { return true; } + virtual IArgFunction* clone() const { return new NullBinder( *this ); } + }; - CumulativeReporterBase( ReporterConfig const& _config ) - : m_config( _config.fullConfig() ), - stream( _config.stream() ) - { - m_reporterPrefs.shouldRedirectStdOut = false; - CATCH_ENFORCE( DerivedT::getSupportedVerbosities().count( m_config->verbosity() ), "Verbosity level not supported by this reporter" ); - } - ~CumulativeReporterBase() override = default; - - ReporterPreferences getPreferences() const override { - return m_reporterPrefs; - } - - static std::set getSupportedVerbosities() { - return { Verbosity::Normal }; - } - - void testRunStarting( TestRunInfo const& ) override {} - void testGroupStarting( GroupInfo const& ) override {} - - void testCaseStarting( TestCaseInfo const& ) override {} - - void sectionStarting( SectionInfo const& sectionInfo ) override { - SectionStats incompleteStats( sectionInfo, Counts(), 0, false ); - std::shared_ptr node; - if( m_sectionStack.empty() ) { - if( !m_rootSection ) - m_rootSection = std::make_shared( incompleteStats ); - node = m_rootSection; + template + struct BoundDataMember : IArgFunction{ + BoundDataMember( M C::* _member ) : member( _member ) {} + virtual void set( C& p, std::string const& stringValue ) const { + convertInto( stringValue, p.*member ); } - else { - SectionNode& parentNode = *m_sectionStack.back(); - auto it = - std::find_if( parentNode.childSections.begin(), - parentNode.childSections.end(), - BySectionInfo( sectionInfo ) ); - if( it == parentNode.childSections.end() ) { - node = std::make_shared( incompleteStats ); - parentNode.childSections.push_back( node ); - } - else - node = *it; + virtual bool takesArg() const { return !IsBool::value; } + virtual IArgFunction* clone() const { return new BoundDataMember( *this ); } + M C::* member; + }; + template + struct BoundUnaryMethod : IArgFunction{ + BoundUnaryMethod( void (C::*_member)( M ) ) : member( _member ) {} + virtual void set( C& p, std::string const& stringValue ) const { + typename RemoveConstRef::type value; + convertInto( stringValue, value ); + (p.*member)( value ); } - m_sectionStack.push_back( node ); - m_deepestSection = std::move(node); - } + virtual bool takesArg() const { return !IsBool::value; } + virtual IArgFunction* clone() const { return new BoundUnaryMethod( *this ); } + void (C::*member)( M ); + }; + template + struct BoundNullaryMethod : IArgFunction{ + BoundNullaryMethod( void (C::*_member)() ) : member( _member ) {} + virtual void set( C& p, std::string const& stringValue ) const { + bool value; + convertInto( stringValue, value ); + if( value ) + (p.*member)(); + } + virtual bool takesArg() const { return false; } + virtual IArgFunction* clone() const { return new BoundNullaryMethod( *this ); } + void (C::*member)(); + }; - void assertionStarting(AssertionInfo const&) override {} + template + struct BoundUnaryFunction : IArgFunction{ + BoundUnaryFunction( void (*_function)( C& ) ) : function( _function ) {} + virtual void set( C& obj, std::string const& stringValue ) const { + bool value; + convertInto( stringValue, value ); + if( value ) + function( obj ); + } + virtual bool takesArg() const { return false; } + virtual IArgFunction* clone() const { return new BoundUnaryFunction( *this ); } + void (*function)( C& ); + }; - bool assertionEnded(AssertionStats const& assertionStats) override { - assert(!m_sectionStack.empty()); - // AssertionResult holds a pointer to a temporary DecomposedExpression, - // which getExpandedExpression() calls to build the expression string. - // Our section stack copy of the assertionResult will likely outlive the - // temporary, so it must be expanded or discarded now to avoid calling - // a destroyed object later. - prepareExpandedExpression(const_cast( assertionStats.assertionResult ) ); - SectionNode& sectionNode = *m_sectionStack.back(); - sectionNode.assertions.push_back(assertionStats); - return true; - } - void sectionEnded(SectionStats const& sectionStats) override { - assert(!m_sectionStack.empty()); - SectionNode& node = *m_sectionStack.back(); - node.stats = sectionStats; - m_sectionStack.pop_back(); - } - void testCaseEnded(TestCaseStats const& testCaseStats) override { - auto node = std::make_shared(testCaseStats); - assert(m_sectionStack.size() == 0); - node->children.push_back(m_rootSection); - m_testCases.push_back(node); - m_rootSection.reset(); + template + struct BoundBinaryFunction : IArgFunction{ + BoundBinaryFunction( void (*_function)( C&, T ) ) : function( _function ) {} + virtual void set( C& obj, std::string const& stringValue ) const { + typename RemoveConstRef::type value; + convertInto( stringValue, value ); + function( obj, value ); + } + virtual bool takesArg() const { return !IsBool::value; } + virtual IArgFunction* clone() const { return new BoundBinaryFunction( *this ); } + void (*function)( C&, T ); + }; - assert(m_deepestSection); - m_deepestSection->stdOut = testCaseStats.stdOut; - m_deepestSection->stdErr = testCaseStats.stdErr; - } - void testGroupEnded(TestGroupStats const& testGroupStats) override { - auto node = std::make_shared(testGroupStats); - node->children.swap(m_testCases); - m_testGroups.push_back(node); - } - void testRunEnded(TestRunStats const& testRunStats) override { - auto node = std::make_shared(testRunStats); - node->children.swap(m_testGroups); - m_testRuns.push_back(node); - testRunEndedCumulative(); - } - virtual void testRunEndedCumulative() = 0; + } // namespace Detail - void skipTest(TestCaseInfo const&) override {} + inline std::vector argsToVector( int argc, char const* const* const argv ) { + std::vector args( static_cast( argc ) ); + for( std::size_t i = 0; i < static_cast( argc ); ++i ) + args[i] = argv[i]; - IConfigPtr m_config; - std::ostream& stream; - std::vector m_assertions; - std::vector>> m_sections; - std::vector> m_testCases; - std::vector> m_testGroups; - - std::vector> m_testRuns; - - std::shared_ptr m_rootSection; - std::shared_ptr m_deepestSection; - std::vector> m_sectionStack; - ReporterPreferences m_reporterPrefs; - }; - - template - char const* getLineOfChars() { - static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0}; - if( !*line ) { - std::memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 ); - line[CATCH_CONFIG_CONSOLE_WIDTH-1] = 0; - } - return line; + return args; } - struct TestEventListenerBase : StreamingReporterBase { - TestEventListenerBase( ReporterConfig const& _config ); + class Parser { + enum Mode { None, MaybeShortOpt, SlashOpt, ShortOpt, LongOpt, Positional }; + Mode mode; + std::size_t from; + bool inQuotes; + public: - void assertionStarting(AssertionInfo const&) override; - bool assertionEnded(AssertionStats const&) override; + struct Token { + enum Type { Positional, ShortOpt, LongOpt }; + Token( Type _type, std::string const& _data ) : type( _type ), data( _data ) {} + Type type; + std::string data; + }; + + Parser() : mode( None ), from( 0 ), inQuotes( false ){} + + void parseIntoTokens( std::vector const& args, std::vector& tokens ) { + const std::string doubleDash = "--"; + for( std::size_t i = 1; i < args.size() && args[i] != doubleDash; ++i ) + parseIntoTokens( args[i], tokens); + } + + void parseIntoTokens( std::string const& arg, std::vector& tokens ) { + for( std::size_t i = 0; i < arg.size(); ++i ) { + char c = arg[i]; + if( c == '"' ) + inQuotes = !inQuotes; + mode = handleMode( i, c, arg, tokens ); + } + mode = handleMode( arg.size(), '\0', arg, tokens ); + } + Mode handleMode( std::size_t i, char c, std::string const& arg, std::vector& tokens ) { + switch( mode ) { + case None: return handleNone( i, c ); + case MaybeShortOpt: return handleMaybeShortOpt( i, c ); + case ShortOpt: + case LongOpt: + case SlashOpt: return handleOpt( i, c, arg, tokens ); + case Positional: return handlePositional( i, c, arg, tokens ); + default: throw std::logic_error( "Unknown mode" ); + } + } + + Mode handleNone( std::size_t i, char c ) { + if( inQuotes ) { + from = i; + return Positional; + } + switch( c ) { + case '-': return MaybeShortOpt; +#ifdef CLARA_PLATFORM_WINDOWS + case '/': from = i+1; return SlashOpt; +#endif + default: from = i; return Positional; + } + } + Mode handleMaybeShortOpt( std::size_t i, char c ) { + switch( c ) { + case '-': from = i+1; return LongOpt; + default: from = i; return ShortOpt; + } + } + + Mode handleOpt( std::size_t i, char c, std::string const& arg, std::vector& tokens ) { + if( std::string( ":=\0", 3 ).find( c ) == std::string::npos ) + return mode; + + std::string optName = arg.substr( from, i-from ); + if( mode == ShortOpt ) + for( std::size_t j = 0; j < optName.size(); ++j ) + tokens.push_back( Token( Token::ShortOpt, optName.substr( j, 1 ) ) ); + else if( mode == SlashOpt && optName.size() == 1 ) + tokens.push_back( Token( Token::ShortOpt, optName ) ); + else + tokens.push_back( Token( Token::LongOpt, optName ) ); + return None; + } + Mode handlePositional( std::size_t i, char c, std::string const& arg, std::vector& tokens ) { + if( inQuotes || std::string( "\0", 1 ).find( c ) == std::string::npos ) + return mode; + + std::string data = arg.substr( from, i-from ); + tokens.push_back( Token( Token::Positional, data ) ); + return None; + } }; + template + struct CommonArgProperties { + CommonArgProperties() {} + CommonArgProperties( Detail::BoundArgFunction const& _boundField ) : boundField( _boundField ) {} + + Detail::BoundArgFunction boundField; + std::string description; + std::string detail; + std::string placeholder; // Only value if boundField takes an arg + + bool takesArg() const { + return !placeholder.empty(); + } + void validate() const { + if( !boundField.isSet() ) + throw std::logic_error( "option not bound" ); + } + }; + struct OptionArgProperties { + std::vector shortNames; + std::string longName; + + bool hasShortName( std::string const& shortName ) const { + return std::find( shortNames.begin(), shortNames.end(), shortName ) != shortNames.end(); + } + bool hasLongName( std::string const& _longName ) const { + return _longName == longName; + } + }; + struct PositionalArgProperties { + PositionalArgProperties() : position( -1 ) {} + int position; // -1 means non-positional (floating) + + bool isFixedPositional() const { + return position != -1; + } + }; + + template + class CommandLine { + + struct Arg : CommonArgProperties, OptionArgProperties, PositionalArgProperties { + Arg() {} + Arg( Detail::BoundArgFunction const& _boundField ) : CommonArgProperties( _boundField ) {} + + using CommonArgProperties::placeholder; // !TBD + + std::string dbgName() const { + if( !longName.empty() ) + return "--" + longName; + if( !shortNames.empty() ) + return "-" + shortNames[0]; + return "positional args"; + } + std::string commands() const { + std::ostringstream oss; + bool first = true; + std::vector::const_iterator it = shortNames.begin(), itEnd = shortNames.end(); + for(; it != itEnd; ++it ) { + if( first ) + first = false; + else + oss << ", "; + oss << "-" << *it; + } + if( !longName.empty() ) { + if( !first ) + oss << ", "; + oss << "--" << longName; + } + if( !placeholder.empty() ) + oss << " <" << placeholder << ">"; + return oss.str(); + } + }; + + typedef CLARA_AUTO_PTR( Arg ) ArgAutoPtr; + + friend void addOptName( Arg& arg, std::string const& optName ) + { + if( optName.empty() ) + return; + if( Detail::startsWith( optName, "--" ) ) { + if( !arg.longName.empty() ) + throw std::logic_error( "Only one long opt may be specified. '" + + arg.longName + + "' already specified, now attempting to add '" + + optName + "'" ); + arg.longName = optName.substr( 2 ); + } + else if( Detail::startsWith( optName, "-" ) ) + arg.shortNames.push_back( optName.substr( 1 ) ); + else + throw std::logic_error( "option must begin with - or --. Option was: '" + optName + "'" ); + } + friend void setPositionalArg( Arg& arg, int position ) + { + arg.position = position; + } + + class ArgBuilder { + public: + ArgBuilder( Arg* arg ) : m_arg( arg ) {} + + // Bind a non-boolean data member (requires placeholder string) + template + void bind( M C::* field, std::string const& placeholder ) { + m_arg->boundField = new Detail::BoundDataMember( field ); + m_arg->placeholder = placeholder; + } + // Bind a boolean data member (no placeholder required) + template + void bind( bool C::* field ) { + m_arg->boundField = new Detail::BoundDataMember( field ); + } + + // Bind a method taking a single, non-boolean argument (requires a placeholder string) + template + void bind( void (C::* unaryMethod)( M ), std::string const& placeholder ) { + m_arg->boundField = new Detail::BoundUnaryMethod( unaryMethod ); + m_arg->placeholder = placeholder; + } + + // Bind a method taking a single, boolean argument (no placeholder string required) + template + void bind( void (C::* unaryMethod)( bool ) ) { + m_arg->boundField = new Detail::BoundUnaryMethod( unaryMethod ); + } + + // Bind a method that takes no arguments (will be called if opt is present) + template + void bind( void (C::* nullaryMethod)() ) { + m_arg->boundField = new Detail::BoundNullaryMethod( nullaryMethod ); + } + + // Bind a free function taking a single argument - the object to operate on (no placeholder string required) + template + void bind( void (* unaryFunction)( C& ) ) { + m_arg->boundField = new Detail::BoundUnaryFunction( unaryFunction ); + } + + // Bind a free function taking a single argument - the object to operate on (requires a placeholder string) + template + void bind( void (* binaryFunction)( C&, T ), std::string const& placeholder ) { + m_arg->boundField = new Detail::BoundBinaryFunction( binaryFunction ); + m_arg->placeholder = placeholder; + } + + ArgBuilder& describe( std::string const& description ) { + m_arg->description = description; + return *this; + } + ArgBuilder& detail( std::string const& detail ) { + m_arg->detail = detail; + return *this; + } + + protected: + Arg* m_arg; + }; + + class OptBuilder : public ArgBuilder { + public: + OptBuilder( Arg* arg ) : ArgBuilder( arg ) {} + OptBuilder( OptBuilder& other ) : ArgBuilder( other ) {} + + OptBuilder& operator[]( std::string const& optName ) { + addOptName( *ArgBuilder::m_arg, optName ); + return *this; + } + }; + + public: + + CommandLine() + : m_boundProcessName( new Detail::NullBinder() ), + m_highestSpecifiedArgPosition( 0 ), + m_throwOnUnrecognisedTokens( false ) + {} + CommandLine( CommandLine const& other ) + : m_boundProcessName( other.m_boundProcessName ), + m_options ( other.m_options ), + m_positionalArgs( other.m_positionalArgs ), + m_highestSpecifiedArgPosition( other.m_highestSpecifiedArgPosition ), + m_throwOnUnrecognisedTokens( other.m_throwOnUnrecognisedTokens ) + { + if( other.m_floatingArg.get() ) + m_floatingArg.reset( new Arg( *other.m_floatingArg ) ); + } + + CommandLine& setThrowOnUnrecognisedTokens( bool shouldThrow = true ) { + m_throwOnUnrecognisedTokens = shouldThrow; + return *this; + } + + OptBuilder operator[]( std::string const& optName ) { + m_options.push_back( Arg() ); + addOptName( m_options.back(), optName ); + OptBuilder builder( &m_options.back() ); + return builder; + } + + ArgBuilder operator[]( int position ) { + m_positionalArgs.insert( std::make_pair( position, Arg() ) ); + if( position > m_highestSpecifiedArgPosition ) + m_highestSpecifiedArgPosition = position; + setPositionalArg( m_positionalArgs[position], position ); + ArgBuilder builder( &m_positionalArgs[position] ); + return builder; + } + + // Invoke this with the _ instance + ArgBuilder operator[]( UnpositionalTag ) { + if( m_floatingArg.get() ) + throw std::logic_error( "Only one unpositional argument can be added" ); + m_floatingArg.reset( new Arg() ); + ArgBuilder builder( m_floatingArg.get() ); + return builder; + } + + template + void bindProcessName( M C::* field ) { + m_boundProcessName = new Detail::BoundDataMember( field ); + } + template + void bindProcessName( void (C::*_unaryMethod)( M ) ) { + m_boundProcessName = new Detail::BoundUnaryMethod( _unaryMethod ); + } + + void optUsage( std::ostream& os, std::size_t indent = 0, std::size_t width = Detail::consoleWidth ) const { + typename std::vector::const_iterator itBegin = m_options.begin(), itEnd = m_options.end(), it; + std::size_t maxWidth = 0; + for( it = itBegin; it != itEnd; ++it ) + maxWidth = (std::max)( maxWidth, it->commands().size() ); + + for( it = itBegin; it != itEnd; ++it ) { + Detail::Text usage( it->commands(), Detail::TextAttributes() + .setWidth( maxWidth+indent ) + .setIndent( indent ) ); + Detail::Text desc( it->description, Detail::TextAttributes() + .setWidth( width - maxWidth - 3 ) ); + + for( std::size_t i = 0; i < (std::max)( usage.size(), desc.size() ); ++i ) { + std::string usageCol = i < usage.size() ? usage[i] : ""; + os << usageCol; + + if( i < desc.size() && !desc[i].empty() ) + os << std::string( indent + 2 + maxWidth - usageCol.size(), ' ' ) + << desc[i]; + os << "\n"; + } + } + } + std::string optUsage() const { + std::ostringstream oss; + optUsage( oss ); + return oss.str(); + } + + void argSynopsis( std::ostream& os ) const { + for( int i = 1; i <= m_highestSpecifiedArgPosition; ++i ) { + if( i > 1 ) + os << " "; + typename std::map::const_iterator it = m_positionalArgs.find( i ); + if( it != m_positionalArgs.end() ) + os << "<" << it->second.placeholder << ">"; + else if( m_floatingArg.get() ) + os << "<" << m_floatingArg->placeholder << ">"; + else + throw std::logic_error( "non consecutive positional arguments with no floating args" ); + } + // !TBD No indication of mandatory args + if( m_floatingArg.get() ) { + if( m_highestSpecifiedArgPosition > 1 ) + os << " "; + os << "[<" << m_floatingArg->placeholder << "> ...]"; + } + } + std::string argSynopsis() const { + std::ostringstream oss; + argSynopsis( oss ); + return oss.str(); + } + + void usage( std::ostream& os, std::string const& procName ) const { + validate(); + os << "usage:\n " << procName << " "; + argSynopsis( os ); + if( !m_options.empty() ) { + os << " [options]\n\nwhere options are: \n"; + optUsage( os, 2 ); + } + os << "\n"; + } + std::string usage( std::string const& procName ) const { + std::ostringstream oss; + usage( oss, procName ); + return oss.str(); + } + + ConfigT parse( std::vector const& args ) const { + ConfigT config; + parseInto( args, config ); + return config; + } + + std::vector parseInto( std::vector const& args, ConfigT& config ) const { + std::string processName = args.empty() ? std::string() : args[0]; + std::size_t lastSlash = processName.find_last_of( "/\\" ); + if( lastSlash != std::string::npos ) + processName = processName.substr( lastSlash+1 ); + m_boundProcessName.set( config, processName ); + std::vector tokens; + Parser parser; + parser.parseIntoTokens( args, tokens ); + return populate( tokens, config ); + } + + std::vector populate( std::vector const& tokens, ConfigT& config ) const { + validate(); + std::vector unusedTokens = populateOptions( tokens, config ); + unusedTokens = populateFixedArgs( unusedTokens, config ); + unusedTokens = populateFloatingArgs( unusedTokens, config ); + return unusedTokens; + } + + std::vector populateOptions( std::vector const& tokens, ConfigT& config ) const { + std::vector unusedTokens; + std::vector errors; + for( std::size_t i = 0; i < tokens.size(); ++i ) { + Parser::Token const& token = tokens[i]; + typename std::vector::const_iterator it = m_options.begin(), itEnd = m_options.end(); + for(; it != itEnd; ++it ) { + Arg const& arg = *it; + + try { + if( ( token.type == Parser::Token::ShortOpt && arg.hasShortName( token.data ) ) || + ( token.type == Parser::Token::LongOpt && arg.hasLongName( token.data ) ) ) { + if( arg.takesArg() ) { + if( i == tokens.size()-1 || tokens[i+1].type != Parser::Token::Positional ) + errors.push_back( "Expected argument to option: " + token.data ); + else + arg.boundField.set( config, tokens[++i].data ); + } + else { + arg.boundField.set( config, "true" ); + } + break; + } + } + catch( std::exception& ex ) { + errors.push_back( std::string( ex.what() ) + "\n- while parsing: (" + arg.commands() + ")" ); + } + } + if( it == itEnd ) { + if( token.type == Parser::Token::Positional || !m_throwOnUnrecognisedTokens ) + unusedTokens.push_back( token ); + else if( errors.empty() && m_throwOnUnrecognisedTokens ) + errors.push_back( "unrecognised option: " + token.data ); + } + } + if( !errors.empty() ) { + std::ostringstream oss; + for( std::vector::const_iterator it = errors.begin(), itEnd = errors.end(); + it != itEnd; + ++it ) { + if( it != errors.begin() ) + oss << "\n"; + oss << *it; + } + throw std::runtime_error( oss.str() ); + } + return unusedTokens; + } + std::vector populateFixedArgs( std::vector const& tokens, ConfigT& config ) const { + std::vector unusedTokens; + int position = 1; + for( std::size_t i = 0; i < tokens.size(); ++i ) { + Parser::Token const& token = tokens[i]; + typename std::map::const_iterator it = m_positionalArgs.find( position ); + if( it != m_positionalArgs.end() ) + it->second.boundField.set( config, token.data ); + else + unusedTokens.push_back( token ); + if( token.type == Parser::Token::Positional ) + position++; + } + return unusedTokens; + } + std::vector populateFloatingArgs( std::vector const& tokens, ConfigT& config ) const { + if( !m_floatingArg.get() ) + return tokens; + std::vector unusedTokens; + for( std::size_t i = 0; i < tokens.size(); ++i ) { + Parser::Token const& token = tokens[i]; + if( token.type == Parser::Token::Positional ) + m_floatingArg->boundField.set( config, token.data ); + else + unusedTokens.push_back( token ); + } + return unusedTokens; + } + + void validate() const + { + if( m_options.empty() && m_positionalArgs.empty() && !m_floatingArg.get() ) + throw std::logic_error( "No options or arguments specified" ); + + for( typename std::vector::const_iterator it = m_options.begin(), + itEnd = m_options.end(); + it != itEnd; ++it ) + it->validate(); + } + + private: + Detail::BoundArgFunction m_boundProcessName; + std::vector m_options; + std::map m_positionalArgs; + ArgAutoPtr m_floatingArg; + int m_highestSpecifiedArgPosition; + bool m_throwOnUnrecognisedTokens; + }; + +} // end namespace Clara + +STITCH_CLARA_CLOSE_NAMESPACE +#undef STITCH_CLARA_OPEN_NAMESPACE +#undef STITCH_CLARA_CLOSE_NAMESPACE + +#endif // TWOBLUECUBES_CLARA_H_INCLUDED +#undef STITCH_CLARA_OPEN_NAMESPACE + +// Restore Clara's value for console width, if present +#ifdef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH +#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH +#undef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH +#endif + +#include +#include + +namespace Catch { + + inline void abortAfterFirst( ConfigData& config ) { config.abortAfter = 1; } + inline void abortAfterX( ConfigData& config, int x ) { + if( x < 1 ) + throw std::runtime_error( "Value after -x or --abortAfter must be greater than zero" ); + config.abortAfter = x; + } + inline void addTestOrTags( ConfigData& config, std::string const& _testSpec ) { config.testsOrTags.push_back( _testSpec ); } + inline void addSectionToRun( ConfigData& config, std::string const& sectionName ) { config.sectionsToRun.push_back( sectionName ); } + inline void addReporterName( ConfigData& config, std::string const& _reporterName ) { config.reporterNames.push_back( _reporterName ); } + + inline void addWarning( ConfigData& config, std::string const& _warning ) { + if( _warning == "NoAssertions" ) + config.warnings = static_cast( config.warnings | WarnAbout::NoAssertions ); + else + throw std::runtime_error( "Unrecognised warning: '" + _warning + '\'' ); + } + inline void setOrder( ConfigData& config, std::string const& order ) { + if( startsWith( "declared", order ) ) + config.runOrder = RunTests::InDeclarationOrder; + else if( startsWith( "lexical", order ) ) + config.runOrder = RunTests::InLexicographicalOrder; + else if( startsWith( "random", order ) ) + config.runOrder = RunTests::InRandomOrder; + else + throw std::runtime_error( "Unrecognised ordering: '" + order + '\'' ); + } + inline void setRngSeed( ConfigData& config, std::string const& seed ) { + if( seed == "time" ) { + config.rngSeed = static_cast( std::time(0) ); + } + else { + std::stringstream ss; + ss << seed; + ss >> config.rngSeed; + if( ss.fail() ) + throw std::runtime_error( "Argument to --rng-seed should be the word 'time' or a number" ); + } + } + inline void setVerbosity( ConfigData& config, int level ) { + // !TBD: accept strings? + config.verbosity = static_cast( level ); + } + inline void setShowDurations( ConfigData& config, bool _showDurations ) { + config.showDurations = _showDurations + ? ShowDurations::Always + : ShowDurations::Never; + } + inline void setUseColour( ConfigData& config, std::string const& value ) { + std::string mode = toLower( value ); + + if( mode == "yes" ) + config.useColour = UseColour::Yes; + else if( mode == "no" ) + config.useColour = UseColour::No; + else if( mode == "auto" ) + config.useColour = UseColour::Auto; + else + throw std::runtime_error( "colour mode must be one of: auto, yes or no" ); + } + inline void forceColour( ConfigData& config ) { + config.useColour = UseColour::Yes; + } + inline void loadTestNamesFromFile( ConfigData& config, std::string const& _filename ) { + std::ifstream f( _filename.c_str() ); + if( !f.is_open() ) + throw std::domain_error( "Unable to load input file: " + _filename ); + + std::string line; + while( std::getline( f, line ) ) { + line = trim(line); + if( !line.empty() && !startsWith( line, '#' ) ) { + if( !startsWith( line, '"' ) ) + line = '"' + line + '"'; + addTestOrTags( config, line + ',' ); + } + } + } + + inline Clara::CommandLine makeCommandLineParser() { + + using namespace Clara; + CommandLine cli; + + cli.bindProcessName( &ConfigData::processName ); + + cli["-?"]["-h"]["--help"] + .describe( "display usage information" ) + .bind( &ConfigData::showHelp ); + + cli["-l"]["--list-tests"] + .describe( "list all/matching test cases" ) + .bind( &ConfigData::listTests ); + + cli["-t"]["--list-tags"] + .describe( "list all/matching tags" ) + .bind( &ConfigData::listTags ); + + cli["-s"]["--success"] + .describe( "include successful tests in output" ) + .bind( &ConfigData::showSuccessfulTests ); + + cli["-b"]["--break"] + .describe( "break into debugger on failure" ) + .bind( &ConfigData::shouldDebugBreak ); + + cli["-e"]["--nothrow"] + .describe( "skip exception tests" ) + .bind( &ConfigData::noThrow ); + + cli["-i"]["--invisibles"] + .describe( "show invisibles (tabs, newlines)" ) + .bind( &ConfigData::showInvisibles ); + + cli["-o"]["--out"] + .describe( "output filename" ) + .bind( &ConfigData::outputFilename, "filename" ); + + cli["-r"]["--reporter"] +// .placeholder( "name[:filename]" ) + .describe( "reporter to use (defaults to console)" ) + .bind( &addReporterName, "name" ); + + cli["-n"]["--name"] + .describe( "suite name" ) + .bind( &ConfigData::name, "name" ); + + cli["-a"]["--abort"] + .describe( "abort at first failure" ) + .bind( &abortAfterFirst ); + + cli["-x"]["--abortx"] + .describe( "abort after x failures" ) + .bind( &abortAfterX, "no. failures" ); + + cli["-w"]["--warn"] + .describe( "enable warnings" ) + .bind( &addWarning, "warning name" ); + +// - needs updating if reinstated +// cli.into( &setVerbosity ) +// .describe( "level of verbosity (0=no output)" ) +// .shortOpt( "v") +// .longOpt( "verbosity" ) +// .placeholder( "level" ); + + cli[_] + .describe( "which test or tests to use" ) + .bind( &addTestOrTags, "test name, pattern or tags" ); + + cli["-d"]["--durations"] + .describe( "show test durations" ) + .bind( &setShowDurations, "yes|no" ); + + cli["-f"]["--input-file"] + .describe( "load test names to run from a file" ) + .bind( &loadTestNamesFromFile, "filename" ); + + cli["-#"]["--filenames-as-tags"] + .describe( "adds a tag for the filename" ) + .bind( &ConfigData::filenamesAsTags ); + + cli["-c"]["--section"] + .describe( "specify section to run" ) + .bind( &addSectionToRun, "section name" ); + + // Less common commands which don't have a short form + cli["--list-test-names-only"] + .describe( "list all/matching test cases names only" ) + .bind( &ConfigData::listTestNamesOnly ); + + cli["--list-extra-info"] + .describe( "list all/matching test cases with more info" ) + .bind( &ConfigData::listExtraInfo ); + + cli["--list-reporters"] + .describe( "list all reporters" ) + .bind( &ConfigData::listReporters ); + + cli["--order"] + .describe( "test case order (defaults to decl)" ) + .bind( &setOrder, "decl|lex|rand" ); + + cli["--rng-seed"] + .describe( "set a specific seed for random numbers" ) + .bind( &setRngSeed, "'time'|number" ); + + cli["--force-colour"] + .describe( "force colourised output (deprecated)" ) + .bind( &forceColour ); + + cli["--use-colour"] + .describe( "should output be colourised" ) + .bind( &setUseColour, "yes|no" ); + + return cli; + } + } // end namespace Catch -// end catch_reporter_bases.hpp -// start catch_console_colour.h +// #included from: internal/catch_list.hpp +#define TWOBLUECUBES_CATCH_LIST_HPP_INCLUDED + +// #included from: catch_text.h +#define TWOBLUECUBES_CATCH_TEXT_H_INCLUDED + +#define TBC_TEXT_FORMAT_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH + +#define CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE Catch +// #included from: ../external/tbc_text_format.h +// Only use header guard if we are not using an outer namespace +#ifndef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE +# ifdef TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED +# ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +# define TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +# endif +# else +# define TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED +# endif +#endif +#ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +#include +#include +#include + +// Use optional outer namespace +#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE +namespace CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE { +#endif + +namespace Tbc { + +#ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH + const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH; +#else + const unsigned int consoleWidth = 80; +#endif + + struct TextAttributes { + TextAttributes() + : initialIndent( std::string::npos ), + indent( 0 ), + width( consoleWidth-1 ) + {} + + TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; } + TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; } + TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; } + + std::size_t initialIndent; // indent of first line, or npos + std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos + std::size_t width; // maximum width of text, including indent. Longer text will wrap + }; + + class Text { + public: + Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() ) + : attr( _attr ) + { + const std::string wrappableBeforeChars = "[({<\t"; + const std::string wrappableAfterChars = "])}>-,./|\\"; + const std::string wrappableInsteadOfChars = " \n\r"; + std::string indent = _attr.initialIndent != std::string::npos + ? std::string( _attr.initialIndent, ' ' ) + : std::string( _attr.indent, ' ' ); + + typedef std::string::const_iterator iterator; + iterator it = _str.begin(); + const iterator strEnd = _str.end(); + + while( it != strEnd ) { + + if( lines.size() >= 1000 ) { + lines.push_back( "... message truncated due to excessive size" ); + return; + } + + std::string suffix; + std::size_t width = (std::min)( static_cast( strEnd-it ), _attr.width-static_cast( indent.size() ) ); + iterator itEnd = it+width; + iterator itNext = _str.end(); + + iterator itNewLine = std::find( it, itEnd, '\n' ); + if( itNewLine != itEnd ) + itEnd = itNewLine; + + if( itEnd != strEnd ) { + bool foundWrapPoint = false; + iterator findIt = itEnd; + do { + if( wrappableAfterChars.find( *findIt ) != std::string::npos && findIt != itEnd ) { + itEnd = findIt+1; + itNext = findIt+1; + foundWrapPoint = true; + } + else if( findIt > it && wrappableBeforeChars.find( *findIt ) != std::string::npos ) { + itEnd = findIt; + itNext = findIt; + foundWrapPoint = true; + } + else if( wrappableInsteadOfChars.find( *findIt ) != std::string::npos ) { + itNext = findIt+1; + itEnd = findIt; + foundWrapPoint = true; + } + if( findIt == it ) + break; + else + --findIt; + } + while( !foundWrapPoint ); + + if( !foundWrapPoint ) { + // No good wrap char, so we'll break mid word and add a hyphen + --itEnd; + itNext = itEnd; + suffix = "-"; + } + else { + while( itEnd > it && wrappableInsteadOfChars.find( *(itEnd-1) ) != std::string::npos ) + --itEnd; + } + } + lines.push_back( indent + std::string( it, itEnd ) + suffix ); + + if( indent.size() != _attr.indent ) + indent = std::string( _attr.indent, ' ' ); + it = itNext; + } + } + + typedef std::vector::const_iterator const_iterator; + + const_iterator begin() const { return lines.begin(); } + const_iterator end() const { return lines.end(); } + std::string const& last() const { return lines.back(); } + std::size_t size() const { return lines.size(); } + std::string const& operator[]( std::size_t _index ) const { return lines[_index]; } + std::string toString() const { + std::ostringstream oss; + oss << *this; + return oss.str(); + } + + inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) { + for( Text::const_iterator it = _text.begin(), itEnd = _text.end(); + it != itEnd; ++it ) { + if( it != _text.begin() ) + _stream << "\n"; + _stream << *it; + } + return _stream; + } + + private: + std::string str; + TextAttributes attr; + std::vector lines; + }; + +} // end namespace Tbc + +#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE +} // end outer namespace +#endif + +#endif // TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +#undef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE + +namespace Catch { + using Tbc::Text; + using Tbc::TextAttributes; +} + +// #included from: catch_console_colour.hpp +#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_HPP_INCLUDED namespace Catch { @@ -3701,105 +5545,462 @@ namespace Catch { // Use constructed object for RAII guard Colour( Code _colourCode ); - Colour( Colour&& other ) noexcept; - Colour& operator=( Colour&& other ) noexcept; + Colour( Colour const& other ); ~Colour(); // Use static method for one-shot changes static void use( Code _colourCode ); private: - bool m_moved = false; + bool m_moved; }; - std::ostream& operator << ( std::ostream& os, Colour const& ); + inline std::ostream& operator << ( std::ostream& os, Colour const& ) { return os; } } // end namespace Catch -// end catch_console_colour.h -// start catch_reporter_registrars.hpp +// #included from: catch_interfaces_reporter.h +#define TWOBLUECUBES_CATCH_INTERFACES_REPORTER_H_INCLUDED +#include +#include +#include + +namespace Catch +{ + struct ReporterConfig { + explicit ReporterConfig( Ptr const& _fullConfig ) + : m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {} + + ReporterConfig( Ptr const& _fullConfig, std::ostream& _stream ) + : m_stream( &_stream ), m_fullConfig( _fullConfig ) {} + + std::ostream& stream() const { return *m_stream; } + Ptr fullConfig() const { return m_fullConfig; } + + private: + std::ostream* m_stream; + Ptr m_fullConfig; + }; + + struct ReporterPreferences { + ReporterPreferences() + : shouldRedirectStdOut( false ) + {} + + bool shouldRedirectStdOut; + }; + + template + struct LazyStat : Option { + LazyStat() : used( false ) {} + LazyStat& operator=( T const& _value ) { + Option::operator=( _value ); + used = false; + return *this; + } + void reset() { + Option::reset(); + used = false; + } + bool used; + }; + + struct TestRunInfo { + TestRunInfo( std::string const& _name ) : name( _name ) {} + std::string name; + }; + struct GroupInfo { + GroupInfo( std::string const& _name, + std::size_t _groupIndex, + std::size_t _groupsCount ) + : name( _name ), + groupIndex( _groupIndex ), + groupsCounts( _groupsCount ) + {} + + std::string name; + std::size_t groupIndex; + std::size_t groupsCounts; + }; + + struct AssertionStats { + AssertionStats( AssertionResult const& _assertionResult, + std::vector const& _infoMessages, + Totals const& _totals ) + : assertionResult( _assertionResult ), + infoMessages( _infoMessages ), + totals( _totals ) + { + if( assertionResult.hasMessage() ) { + // Copy message into messages list. + // !TBD This should have been done earlier, somewhere + MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() ); + builder << assertionResult.getMessage(); + builder.m_info.message = builder.m_stream.str(); + + infoMessages.push_back( builder.m_info ); + } + } + virtual ~AssertionStats(); + +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + AssertionStats( AssertionStats const& ) = default; + AssertionStats( AssertionStats && ) = default; + AssertionStats& operator = ( AssertionStats const& ) = default; + AssertionStats& operator = ( AssertionStats && ) = default; +# endif + + AssertionResult assertionResult; + std::vector infoMessages; + Totals totals; + }; + + struct SectionStats { + SectionStats( SectionInfo const& _sectionInfo, + Counts const& _assertions, + double _durationInSeconds, + bool _missingAssertions ) + : sectionInfo( _sectionInfo ), + assertions( _assertions ), + durationInSeconds( _durationInSeconds ), + missingAssertions( _missingAssertions ) + {} + virtual ~SectionStats(); +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + SectionStats( SectionStats const& ) = default; + SectionStats( SectionStats && ) = default; + SectionStats& operator = ( SectionStats const& ) = default; + SectionStats& operator = ( SectionStats && ) = default; +# endif + + SectionInfo sectionInfo; + Counts assertions; + double durationInSeconds; + bool missingAssertions; + }; + + struct TestCaseStats { + TestCaseStats( TestCaseInfo const& _testInfo, + Totals const& _totals, + std::string const& _stdOut, + std::string const& _stdErr, + bool _aborting ) + : testInfo( _testInfo ), + totals( _totals ), + stdOut( _stdOut ), + stdErr( _stdErr ), + aborting( _aborting ) + {} + virtual ~TestCaseStats(); + +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + TestCaseStats( TestCaseStats const& ) = default; + TestCaseStats( TestCaseStats && ) = default; + TestCaseStats& operator = ( TestCaseStats const& ) = default; + TestCaseStats& operator = ( TestCaseStats && ) = default; +# endif + + TestCaseInfo testInfo; + Totals totals; + std::string stdOut; + std::string stdErr; + bool aborting; + }; + + struct TestGroupStats { + TestGroupStats( GroupInfo const& _groupInfo, + Totals const& _totals, + bool _aborting ) + : groupInfo( _groupInfo ), + totals( _totals ), + aborting( _aborting ) + {} + TestGroupStats( GroupInfo const& _groupInfo ) + : groupInfo( _groupInfo ), + aborting( false ) + {} + virtual ~TestGroupStats(); + +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + TestGroupStats( TestGroupStats const& ) = default; + TestGroupStats( TestGroupStats && ) = default; + TestGroupStats& operator = ( TestGroupStats const& ) = default; + TestGroupStats& operator = ( TestGroupStats && ) = default; +# endif + + GroupInfo groupInfo; + Totals totals; + bool aborting; + }; + + struct TestRunStats { + TestRunStats( TestRunInfo const& _runInfo, + Totals const& _totals, + bool _aborting ) + : runInfo( _runInfo ), + totals( _totals ), + aborting( _aborting ) + {} + virtual ~TestRunStats(); + +# ifndef CATCH_CONFIG_CPP11_GENERATED_METHODS + TestRunStats( TestRunStats const& _other ) + : runInfo( _other.runInfo ), + totals( _other.totals ), + aborting( _other.aborting ) + {} +# else + TestRunStats( TestRunStats const& ) = default; + TestRunStats( TestRunStats && ) = default; + TestRunStats& operator = ( TestRunStats const& ) = default; + TestRunStats& operator = ( TestRunStats && ) = default; +# endif + + TestRunInfo runInfo; + Totals totals; + bool aborting; + }; + + class MultipleReporters; + + struct IStreamingReporter : IShared { + virtual ~IStreamingReporter(); + + // Implementing class must also provide the following static method: + // static std::string getDescription(); + + virtual ReporterPreferences getPreferences() const = 0; + + virtual void noMatchingTestCases( std::string const& spec ) = 0; + + virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0; + virtual void testGroupStarting( GroupInfo const& groupInfo ) = 0; + + virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0; + virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0; + + virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0; + + // The return value indicates if the messages buffer should be cleared: + virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0; + + virtual void sectionEnded( SectionStats const& sectionStats ) = 0; + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0; + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0; + virtual void testRunEnded( TestRunStats const& testRunStats ) = 0; + + virtual void skipTest( TestCaseInfo const& testInfo ) = 0; + + virtual MultipleReporters* tryAsMulti() { return CATCH_NULL; } + }; + + struct IReporterFactory : IShared { + virtual ~IReporterFactory(); + virtual IStreamingReporter* create( ReporterConfig const& config ) const = 0; + virtual std::string getDescription() const = 0; + }; + + struct IReporterRegistry { + typedef std::map > FactoryMap; + typedef std::vector > Listeners; + + virtual ~IReporterRegistry(); + virtual IStreamingReporter* create( std::string const& name, Ptr const& config ) const = 0; + virtual FactoryMap const& getFactories() const = 0; + virtual Listeners const& getListeners() const = 0; + }; + + Ptr addReporter( Ptr const& existingReporter, Ptr const& additionalReporter ); + +} + +#include +#include namespace Catch { - template - class ReporterRegistrar { + inline std::size_t listTests( Config const& config ) { - class ReporterFactory : public IReporterFactory { - - virtual IStreamingReporterPtr create( ReporterConfig const& config ) const override { - return std::unique_ptr( new T( config ) ); - } - - virtual std::string getDescription() const override { - return T::getDescription(); - } - }; - - public: - - ReporterRegistrar( std::string const& name ) { - getMutableRegistryHub().registerReporter( name, std::make_shared() ); + TestSpec testSpec = config.testSpec(); + if( config.testSpec().hasFilters() ) + Catch::cout() << "Matching test cases:\n"; + else { + Catch::cout() << "All available test cases:\n"; + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); } + + std::size_t matchedTests = 0; + TextAttributes nameAttr, descAttr, tagsAttr; + nameAttr.setInitialIndent( 2 ).setIndent( 4 ); + descAttr.setIndent( 4 ); + tagsAttr.setIndent( 6 ); + + std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); + for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); + it != itEnd; + ++it ) { + matchedTests++; + TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); + Colour::Code colour = testCaseInfo.isHidden() + ? Colour::SecondaryText + : Colour::None; + Colour colourGuard( colour ); + + Catch::cout() << Text( testCaseInfo.name, nameAttr ) << std::endl; + if( config.listExtraInfo() ) { + Catch::cout() << " " << testCaseInfo.lineInfo << std::endl; + std::string description = testCaseInfo.description; + if( description.empty() ) + description = "(NO DESCRIPTION)"; + Catch::cout() << Text( description, descAttr ) << std::endl; + } + if( !testCaseInfo.tags.empty() ) + Catch::cout() << Text( testCaseInfo.tagsAsString, tagsAttr ) << std::endl; + } + + if( !config.testSpec().hasFilters() ) + Catch::cout() << pluralise( matchedTests, "test case" ) << '\n' << std::endl; + else + Catch::cout() << pluralise( matchedTests, "matching test case" ) << '\n' << std::endl; + return matchedTests; + } + + inline std::size_t listTestsNamesOnly( Config const& config ) { + TestSpec testSpec = config.testSpec(); + if( !config.testSpec().hasFilters() ) + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); + std::size_t matchedTests = 0; + std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); + for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); + it != itEnd; + ++it ) { + matchedTests++; + TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); + if( startsWith( testCaseInfo.name, '#' ) ) + Catch::cout() << '"' << testCaseInfo.name << '"'; + else + Catch::cout() << testCaseInfo.name; + if ( config.listExtraInfo() ) + Catch::cout() << "\t@" << testCaseInfo.lineInfo; + Catch::cout() << std::endl; + } + return matchedTests; + } + + struct TagInfo { + TagInfo() : count ( 0 ) {} + void add( std::string const& spelling ) { + ++count; + spellings.insert( spelling ); + } + std::string all() const { + std::string out; + for( std::set::const_iterator it = spellings.begin(), itEnd = spellings.end(); + it != itEnd; + ++it ) + out += "[" + *it + "]"; + return out; + } + std::set spellings; + std::size_t count; }; - template - class ListenerRegistrar { - - class ListenerFactory : public IReporterFactory { - - virtual IStreamingReporterPtr create( ReporterConfig const& config ) const override { - return std::unique_ptr( new T( config ) ); - } - virtual std::string getDescription() const override { - return std::string(); - } - }; - - public: - - ListenerRegistrar() { - getMutableRegistryHub().registerListener( std::make_shared() ); + inline std::size_t listTags( Config const& config ) { + TestSpec testSpec = config.testSpec(); + if( config.testSpec().hasFilters() ) + Catch::cout() << "Tags for matching test cases:\n"; + else { + Catch::cout() << "All available tags:\n"; + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); } - }; -} -#if !defined(CATCH_CONFIG_DISABLE) + std::map tagCounts; -#define CATCH_REGISTER_REPORTER( name, reporterType ) \ - CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ - namespace{ Catch::ReporterRegistrar catch_internal_RegistrarFor##reporterType( name ); } \ - CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS + std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); + for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); + it != itEnd; + ++it ) { + for( std::set::const_iterator tagIt = it->getTestCaseInfo().tags.begin(), + tagItEnd = it->getTestCaseInfo().tags.end(); + tagIt != tagItEnd; + ++tagIt ) { + std::string tagName = *tagIt; + std::string lcaseTagName = toLower( tagName ); + std::map::iterator countIt = tagCounts.find( lcaseTagName ); + if( countIt == tagCounts.end() ) + countIt = tagCounts.insert( std::make_pair( lcaseTagName, TagInfo() ) ).first; + countIt->second.add( tagName ); + } + } -#define CATCH_REGISTER_LISTENER( listenerType ) \ - CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ - namespace{ Catch::ListenerRegistrar catch_internal_RegistrarFor##listenerType; } \ - CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS -#else // CATCH_CONFIG_DISABLE + for( std::map::const_iterator countIt = tagCounts.begin(), + countItEnd = tagCounts.end(); + countIt != countItEnd; + ++countIt ) { + std::ostringstream oss; + oss << " " << std::setw(2) << countIt->second.count << " "; + Text wrapper( countIt->second.all(), TextAttributes() + .setInitialIndent( 0 ) + .setIndent( oss.str().size() ) + .setWidth( CATCH_CONFIG_CONSOLE_WIDTH-10 ) ); + Catch::cout() << oss.str() << wrapper << '\n'; + } + Catch::cout() << pluralise( tagCounts.size(), "tag" ) << '\n' << std::endl; + return tagCounts.size(); + } -#define CATCH_REGISTER_REPORTER(name, reporterType) -#define CATCH_REGISTER_LISTENER(listenerType) + inline std::size_t listReporters( Config const& /*config*/ ) { + Catch::cout() << "Available reporters:\n"; + IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories(); + IReporterRegistry::FactoryMap::const_iterator itBegin = factories.begin(), itEnd = factories.end(), it; + std::size_t maxNameLen = 0; + for(it = itBegin; it != itEnd; ++it ) + maxNameLen = (std::max)( maxNameLen, it->first.size() ); -#endif // CATCH_CONFIG_DISABLE + for(it = itBegin; it != itEnd; ++it ) { + Text wrapper( it->second->getDescription(), TextAttributes() + .setInitialIndent( 0 ) + .setIndent( 7+maxNameLen ) + .setWidth( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 ) ); + Catch::cout() << " " + << it->first + << ':' + << std::string( maxNameLen - it->first.size() + 2, ' ' ) + << wrapper << '\n'; + } + Catch::cout() << std::endl; + return factories.size(); + } -// end catch_reporter_registrars.hpp -// end catch_external_interfaces.h -#endif + inline Option list( Config const& config ) { + Option listedCount; + if( config.listTests() || ( config.listExtraInfo() && !config.listTestNamesOnly() ) ) + listedCount = listedCount.valueOr(0) + listTests( config ); + if( config.listTestNamesOnly() ) + listedCount = listedCount.valueOr(0) + listTestsNamesOnly( config ); + if( config.listTags() ) + listedCount = listedCount.valueOr(0) + listTags( config ); + if( config.listReporters() ) + listedCount = listedCount.valueOr(0) + listReporters( config ); + return listedCount; + } -#ifdef CATCH_IMPL -// start catch_impl.hpp +} // end namespace Catch -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wweak-vtables" -#endif +// #included from: internal/catch_run_context.hpp +#define TWOBLUECUBES_CATCH_RUNNER_IMPL_HPP_INCLUDED -// Keep these here for external reporters -// start catch_test_case_tracker.h +// #included from: catch_test_case_tracker.hpp +#define TWOBLUECUBES_CATCH_TEST_CASE_TRACKER_HPP_INCLUDED +#include #include +#include #include -#include +#include + +CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS namespace Catch { namespace TestCaseTracking { @@ -3808,14 +6009,13 @@ namespace TestCaseTracking { std::string name; SourceLineInfo location; - NameAndLocation( std::string const& _name, SourceLineInfo const& _location ); + NameAndLocation( std::string const& _name, SourceLineInfo const& _location ) + : name( _name ), + location( _location ) + {} }; - struct ITracker; - - using ITrackerPtr = std::shared_ptr; - - struct ITracker { + struct ITracker : SharedImpl<> { virtual ~ITracker(); // static queries @@ -3834,8 +6034,8 @@ namespace TestCaseTracking { virtual void fail() = 0; virtual void markAsNeedingAnotherRun() = 0; - virtual void addChild( ITrackerPtr const& child ) = 0; - virtual ITrackerPtr findChild( NameAndLocation const& nameAndLocation ) = 0; + virtual void addChild( Ptr const& child ) = 0; + virtual ITracker* findChild( NameAndLocation const& nameAndLocation ) = 0; virtual void openChild() = 0; // Debug/ checking @@ -3843,7 +6043,7 @@ namespace TestCaseTracking { virtual bool isIndexTracker() const = 0; }; - class TrackerContext { + class TrackerContext { enum RunState { NotStarted, @@ -3851,23 +6051,47 @@ namespace TestCaseTracking { CompletedCycle }; - ITrackerPtr m_rootTracker; - ITracker* m_currentTracker = nullptr; - RunState m_runState = NotStarted; + Ptr m_rootTracker; + ITracker* m_currentTracker; + RunState m_runState; public: - static TrackerContext& instance(); + static TrackerContext& instance() { + static TrackerContext s_instance; + return s_instance; + } + + TrackerContext() + : m_currentTracker( CATCH_NULL ), + m_runState( NotStarted ) + {} ITracker& startRun(); - void endRun(); - void startCycle(); - void completeCycle(); + void endRun() { + m_rootTracker.reset(); + m_currentTracker = CATCH_NULL; + m_runState = NotStarted; + } - bool completedCycle() const; - ITracker& currentTracker(); - void setCurrentTracker( ITracker* tracker ); + void startCycle() { + m_currentTracker = m_rootTracker.get(); + m_runState = Executing; + } + void completeCycle() { + m_runState = CompletedCycle; + } + + bool completedCycle() const { + return m_runState == CompletedCycle; + } + ITracker& currentTracker() { + return *m_currentTracker; + } + void setCurrentTracker( ITracker* tracker ) { + m_currentTracker = tracker; + } }; class TrackerBase : public ITracker { @@ -3880,82 +6104,240 @@ namespace TestCaseTracking { CompletedSuccessfully, Failed }; - class TrackerHasName { NameAndLocation m_nameAndLocation; public: - TrackerHasName( NameAndLocation const& nameAndLocation ); - bool operator ()( ITrackerPtr const& tracker ) const; + TrackerHasName( NameAndLocation const& nameAndLocation ) : m_nameAndLocation( nameAndLocation ) {} + bool operator ()( Ptr const& tracker ) { + return + tracker->nameAndLocation().name == m_nameAndLocation.name && + tracker->nameAndLocation().location == m_nameAndLocation.location; + } }; - - using Children = std::vector; + typedef std::vector > Children; NameAndLocation m_nameAndLocation; TrackerContext& m_ctx; ITracker* m_parent; Children m_children; - CycleState m_runState = NotStarted; - + CycleState m_runState; public: - TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ); + TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ) + : m_nameAndLocation( nameAndLocation ), + m_ctx( ctx ), + m_parent( parent ), + m_runState( NotStarted ) + {} + virtual ~TrackerBase(); - NameAndLocation const& nameAndLocation() const override; - bool isComplete() const override; - bool isSuccessfullyCompleted() const override; - bool isOpen() const override; - bool hasChildren() const override; + virtual NameAndLocation const& nameAndLocation() const CATCH_OVERRIDE { + return m_nameAndLocation; + } + virtual bool isComplete() const CATCH_OVERRIDE { + return m_runState == CompletedSuccessfully || m_runState == Failed; + } + virtual bool isSuccessfullyCompleted() const CATCH_OVERRIDE { + return m_runState == CompletedSuccessfully; + } + virtual bool isOpen() const CATCH_OVERRIDE { + return m_runState != NotStarted && !isComplete(); + } + virtual bool hasChildren() const CATCH_OVERRIDE { + return !m_children.empty(); + } - void addChild( ITrackerPtr const& child ) override; + virtual void addChild( Ptr const& child ) CATCH_OVERRIDE { + m_children.push_back( child ); + } - ITrackerPtr findChild( NameAndLocation const& nameAndLocation ) override; - ITracker& parent() override; + virtual ITracker* findChild( NameAndLocation const& nameAndLocation ) CATCH_OVERRIDE { + Children::const_iterator it = std::find_if( m_children.begin(), m_children.end(), TrackerHasName( nameAndLocation ) ); + return( it != m_children.end() ) + ? it->get() + : CATCH_NULL; + } + virtual ITracker& parent() CATCH_OVERRIDE { + assert( m_parent ); // Should always be non-null except for root + return *m_parent; + } - void openChild() override; + virtual void openChild() CATCH_OVERRIDE { + if( m_runState != ExecutingChildren ) { + m_runState = ExecutingChildren; + if( m_parent ) + m_parent->openChild(); + } + } - bool isSectionTracker() const override; - bool isIndexTracker() const override; + virtual bool isSectionTracker() const CATCH_OVERRIDE { return false; } + virtual bool isIndexTracker() const CATCH_OVERRIDE { return false; } - void open(); + void open() { + m_runState = Executing; + moveToThis(); + if( m_parent ) + m_parent->openChild(); + } - void close() override; - void fail() override; - void markAsNeedingAnotherRun() override; + virtual void close() CATCH_OVERRIDE { + // Close any still open children (e.g. generators) + while( &m_ctx.currentTracker() != this ) + m_ctx.currentTracker().close(); + + switch( m_runState ) { + case NotStarted: + case CompletedSuccessfully: + case Failed: + throw std::logic_error( "Illogical state" ); + + case NeedsAnotherRun: + break;; + + case Executing: + m_runState = CompletedSuccessfully; + break; + case ExecutingChildren: + if( m_children.empty() || m_children.back()->isComplete() ) + m_runState = CompletedSuccessfully; + break; + + default: + throw std::logic_error( "Unexpected state" ); + } + moveToParent(); + m_ctx.completeCycle(); + } + virtual void fail() CATCH_OVERRIDE { + m_runState = Failed; + if( m_parent ) + m_parent->markAsNeedingAnotherRun(); + moveToParent(); + m_ctx.completeCycle(); + } + virtual void markAsNeedingAnotherRun() CATCH_OVERRIDE { + m_runState = NeedsAnotherRun; + } private: - void moveToParent(); - void moveToThis(); + void moveToParent() { + assert( m_parent ); + m_ctx.setCurrentTracker( m_parent ); + } + void moveToThis() { + m_ctx.setCurrentTracker( this ); + } }; class SectionTracker : public TrackerBase { std::vector m_filters; public: - SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ); + SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ) + : TrackerBase( nameAndLocation, ctx, parent ) + { + if( parent ) { + while( !parent->isSectionTracker() ) + parent = &parent->parent(); - bool isSectionTracker() const override; + SectionTracker& parentSection = static_cast( *parent ); + addNextFilters( parentSection.m_filters ); + } + } + virtual ~SectionTracker(); - static SectionTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ); + virtual bool isSectionTracker() const CATCH_OVERRIDE { return true; } - void tryOpen(); + static SectionTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ) { + SectionTracker* section = CATCH_NULL; - void addInitialFilters( std::vector const& filters ); - void addNextFilters( std::vector const& filters ); + ITracker& currentTracker = ctx.currentTracker(); + if( ITracker* childTracker = currentTracker.findChild( nameAndLocation ) ) { + assert( childTracker ); + assert( childTracker->isSectionTracker() ); + section = static_cast( childTracker ); + } + else { + section = new SectionTracker( nameAndLocation, ctx, ¤tTracker ); + currentTracker.addChild( section ); + } + if( !ctx.completedCycle() ) + section->tryOpen(); + return *section; + } + + void tryOpen() { + if( !isComplete() && (m_filters.empty() || m_filters[0].empty() || m_filters[0] == m_nameAndLocation.name ) ) + open(); + } + + void addInitialFilters( std::vector const& filters ) { + if( !filters.empty() ) { + m_filters.push_back(""); // Root - should never be consulted + m_filters.push_back(""); // Test Case - not a section filter + m_filters.insert( m_filters.end(), filters.begin(), filters.end() ); + } + } + void addNextFilters( std::vector const& filters ) { + if( filters.size() > 1 ) + m_filters.insert( m_filters.end(), ++filters.begin(), filters.end() ); + } }; class IndexTracker : public TrackerBase { int m_size; - int m_index = -1; + int m_index; public: - IndexTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent, int size ); + IndexTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent, int size ) + : TrackerBase( nameAndLocation, ctx, parent ), + m_size( size ), + m_index( -1 ) + {} + virtual ~IndexTracker(); - bool isIndexTracker() const override; - void close() override; + virtual bool isIndexTracker() const CATCH_OVERRIDE { return true; } - static IndexTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation, int size ); + static IndexTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation, int size ) { + IndexTracker* tracker = CATCH_NULL; - int index() const; + ITracker& currentTracker = ctx.currentTracker(); + if( ITracker* childTracker = currentTracker.findChild( nameAndLocation ) ) { + assert( childTracker ); + assert( childTracker->isIndexTracker() ); + tracker = static_cast( childTracker ); + } + else { + tracker = new IndexTracker( nameAndLocation, ctx, ¤tTracker, size ); + currentTracker.addChild( tracker ); + } - void moveNext(); + if( !ctx.completedCycle() && !tracker->isComplete() ) { + if( tracker->m_runState != ExecutingChildren && tracker->m_runState != NeedsAnotherRun ) + tracker->moveNext(); + tracker->open(); + } + + return *tracker; + } + + int index() const { return m_index; } + + void moveNext() { + m_index++; + m_children.clear(); + } + + virtual void close() CATCH_OVERRIDE { + TrackerBase::close(); + if( m_runState == CompletedSuccessfully && m_index < m_size-1 ) + m_runState = Executing; + } }; + inline ITracker& TrackerContext::startRun() { + m_rootTracker = new SectionTracker( NameAndLocation( "{root}", CATCH_INTERNAL_LINEINFO ), *this, CATCH_NULL ); + m_currentTracker = CATCH_NULL; + m_runState = Executing; + return *m_rootTracker; + } + } // namespace TestCaseTracking using TestCaseTracking::ITracker; @@ -3965,1941 +6347,31 @@ using TestCaseTracking::IndexTracker; } // namespace Catch -// end catch_test_case_tracker.h +CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS -// start catch_leak_detector.h +// #included from: catch_fatal_condition.hpp +#define TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED namespace Catch { - struct LeakDetector { - LeakDetector(); - }; - -} -// end catch_leak_detector.h -// Cpp files will be included in the single-header file here -// start catch_approx.cpp - -#include -#include - -namespace { - -// Performs equivalent check of std::fabs(lhs - rhs) <= margin -// But without the subtraction to allow for INFINITY in comparison -bool marginComparison(double lhs, double rhs, double margin) { - return (lhs + margin >= rhs) && (rhs + margin >= lhs); -} - -} - -namespace Catch { -namespace Detail { - - Approx::Approx ( double value ) - : m_epsilon( std::numeric_limits::epsilon()*100 ), - m_margin( 0.0 ), - m_scale( 0.0 ), - m_value( value ) - {} - - Approx Approx::custom() { - return Approx( 0 ); - } - - std::string Approx::toString() const { - std::ostringstream oss; - oss << "Approx( " << ::Catch::Detail::stringify( m_value ) << " )"; - return oss.str(); - } - - bool Approx::equalityComparisonImpl(const double other) const { - // First try with fixed margin, then compute margin based on epsilon, scale and Approx's value - // Thanks to Richard Harris for his help refining the scaled margin value - return marginComparison(m_value, other, m_margin) || marginComparison(m_value, other, m_epsilon * (m_scale + std::fabs(m_value))); - } - -} // end namespace Detail - -std::string StringMaker::convert(Catch::Detail::Approx const& value) { - return value.toString(); -} - -} // end namespace Catch -// end catch_approx.cpp -// start catch_assertionhandler.cpp - -// start catch_context.h - -#include - -namespace Catch { - - struct IResultCapture; - struct IRunner; - struct IConfig; - - using IConfigPtr = std::shared_ptr; - - struct IContext - { - virtual ~IContext(); - - virtual IResultCapture* getResultCapture() = 0; - virtual IRunner* getRunner() = 0; - virtual IConfigPtr getConfig() const = 0; - }; - - struct IMutableContext : IContext - { - virtual ~IMutableContext(); - virtual void setResultCapture( IResultCapture* resultCapture ) = 0; - virtual void setRunner( IRunner* runner ) = 0; - virtual void setConfig( IConfigPtr const& config ) = 0; - }; - - IContext& getCurrentContext(); - IMutableContext& getCurrentMutableContext(); - void cleanUpContext(); -} - -// end catch_context.h -#include - -namespace Catch { - - auto operator <<( std::ostream& os, ITransientExpression const& expr ) -> std::ostream& { - expr.streamReconstructedExpression( os ); - return os; - } - - LazyExpression::LazyExpression( bool isNegated ) - : m_isNegated( isNegated ) - {} - - LazyExpression::LazyExpression( LazyExpression const& other ) : m_isNegated( other.m_isNegated ) {} - - LazyExpression::operator bool() const { - return m_transientExpression != nullptr; - } - - auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream& { - if( lazyExpr.m_isNegated ) - os << "!"; - - if( lazyExpr ) { - if( lazyExpr.m_isNegated && lazyExpr.m_transientExpression->isBinaryExpression() ) - os << "(" << *lazyExpr.m_transientExpression << ")"; - else - os << *lazyExpr.m_transientExpression; - } - else { - os << "{** error - unchecked empty expression requested **}"; - } - return os; - } - - AssertionHandler::AssertionHandler - ( StringRef macroName, - SourceLineInfo const& lineInfo, - StringRef capturedExpression, - ResultDisposition::Flags resultDisposition ) - : m_assertionInfo{ macroName, lineInfo, capturedExpression, resultDisposition } - { - getCurrentContext().getResultCapture()->assertionStarting( m_assertionInfo ); - } - AssertionHandler::~AssertionHandler() { - if ( m_inExceptionGuard ) { - handle( ResultWas::ThrewException, "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE" ); - getCurrentContext().getResultCapture()->exceptionEarlyReported(); - } - } - - void AssertionHandler::handle( ITransientExpression const& expr ) { - - bool negated = isFalseTest( m_assertionInfo.resultDisposition ); - bool result = expr.getResult() != negated; - - handle( result ? ResultWas::Ok : ResultWas::ExpressionFailed, &expr, negated ); - } - void AssertionHandler::handle( ResultWas::OfType resultType ) { - handle( resultType, nullptr, false ); - } - void AssertionHandler::handle( ResultWas::OfType resultType, StringRef const& message ) { - AssertionResultData data( resultType, LazyExpression( false ) ); - data.message = message; - handle( data, nullptr ); - } - void AssertionHandler::handle( ResultWas::OfType resultType, ITransientExpression const* expr, bool negated ) { - AssertionResultData data( resultType, LazyExpression( negated ) ); - handle( data, expr ); - } - void AssertionHandler::handle( AssertionResultData const& resultData, ITransientExpression const* expr ) { - - getResultCapture().assertionRun(); - - AssertionResult assertionResult{ m_assertionInfo, resultData }; - assertionResult.m_resultData.lazyExpression.m_transientExpression = expr; - - getResultCapture().assertionEnded( assertionResult ); - - if( !assertionResult.isOk() ) { - m_shouldDebugBreak = getCurrentContext().getConfig()->shouldDebugBreak(); - m_shouldThrow = - getCurrentContext().getRunner()->aborting() || - (m_assertionInfo.resultDisposition & ResultDisposition::Normal); - } - } - - auto AssertionHandler::allowThrows() const -> bool { - return getCurrentContext().getConfig()->allowThrows(); - } - - auto AssertionHandler::shouldDebugBreak() const -> bool { - return m_shouldDebugBreak; - } - void AssertionHandler::reactWithDebugBreak() const { - if (m_shouldDebugBreak) { - /////////////////////////////////////////////////////////////////// - // To inspect the state during test, you need to go one level up the callstack - // To go back to the test and change execution, jump over the reactWithoutDebugBreak() call - /////////////////////////////////////////////////////////////////// - CATCH_BREAK_INTO_DEBUGGER(); - } - reactWithoutDebugBreak(); - } - void AssertionHandler::reactWithoutDebugBreak() const { - if( m_shouldThrow ) - throw Catch::TestFailureException(); - } - - void AssertionHandler::useActiveException() { - handle( ResultWas::ThrewException, Catch::translateActiveException() ); - } - - void AssertionHandler::setExceptionGuard() { - assert( m_inExceptionGuard == false ); - m_inExceptionGuard = true; - } - void AssertionHandler::unsetExceptionGuard() { - assert( m_inExceptionGuard == true ); - m_inExceptionGuard = false; - } - - // This is the overload that takes a string and infers the Equals matcher from it - // The more general overload, that takes any string matcher, is in catch_capture_matchers.cpp - void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef matcherString ) { - handleExceptionMatchExpr( handler, Matchers::Equals( str ), matcherString ); + // Report the error condition + inline void reportFatal( std::string const& message ) { + IContext& context = Catch::getCurrentContext(); + IResultCapture* resultCapture = context.getResultCapture(); + resultCapture->handleFatalErrorCondition( message ); } } // namespace Catch -// end catch_assertionhandler.cpp -// start catch_assertionresult.cpp -namespace Catch { - AssertionResultData::AssertionResultData(ResultWas::OfType _resultType, LazyExpression const & _lazyExpression): - lazyExpression(_lazyExpression), - resultType(_resultType) {} +#if defined ( CATCH_PLATFORM_WINDOWS ) ///////////////////////////////////////// +// #included from: catch_windows_h_proxy.h - std::string AssertionResultData::reconstructExpression() const { +#define TWOBLUECUBES_CATCH_WINDOWS_H_PROXY_H_INCLUDED - if( reconstructedExpression.empty() ) { - if( lazyExpression ) { - // !TBD Use stringstream for now, but rework above to pass stream in - std::ostringstream oss; - oss << lazyExpression; - reconstructedExpression = oss.str(); - } - } - return reconstructedExpression; - } - - AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data ) - : m_info( info ), - m_resultData( data ) - {} - - // Result was a success - bool AssertionResult::succeeded() const { - return Catch::isOk( m_resultData.resultType ); - } - - // Result was a success, or failure is suppressed - bool AssertionResult::isOk() const { - return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition ); - } - - ResultWas::OfType AssertionResult::getResultType() const { - return m_resultData.resultType; - } - - bool AssertionResult::hasExpression() const { - return m_info.capturedExpression[0] != 0; - } - - bool AssertionResult::hasMessage() const { - return !m_resultData.message.empty(); - } - - std::string AssertionResult::getExpression() const { - if( isFalseTest( m_info.resultDisposition ) ) - return "!(" + std::string(m_info.capturedExpression) + ")"; - else - return m_info.capturedExpression; - } - - std::string AssertionResult::getExpressionInMacro() const { - std::string expr; - if( m_info.macroName[0] == 0 ) - expr = m_info.capturedExpression; - else { - expr.reserve( m_info.macroName.size() + m_info.capturedExpression.size() + 4 ); - expr += m_info.macroName; - expr += "( "; - expr += m_info.capturedExpression; - expr += " )"; - } - return expr; - } - - bool AssertionResult::hasExpandedExpression() const { - return hasExpression() && getExpandedExpression() != getExpression(); - } - - std::string AssertionResult::getExpandedExpression() const { - std::string expr = m_resultData.reconstructExpression(); - return expr.empty() - ? getExpression() - : expr; - } - - std::string AssertionResult::getMessage() const { - return m_resultData.message; - } - SourceLineInfo AssertionResult::getSourceInfo() const { - return m_info.lineInfo; - } - - std::string AssertionResult::getTestMacroName() const { - return m_info.macroName; - } - -} // end namespace Catch -// end catch_assertionresult.cpp -// start catch_benchmark.cpp - -namespace Catch { - - auto BenchmarkLooper::getResolution() -> uint64_t { - return getEstimatedClockResolution() * getCurrentContext().getConfig()->benchmarkResolutionMultiple(); - } - - void BenchmarkLooper::reportStart() { - getResultCapture().benchmarkStarting( { m_name } ); - } - auto BenchmarkLooper::needsMoreIterations() -> bool { - auto elapsed = m_timer.getElapsedNanoseconds(); - - // Exponentially increasing iterations until we're confident in our timer resolution - if( elapsed < m_resolution ) { - m_iterationsToRun *= 10; - return true; - } - - getResultCapture().benchmarkEnded( { { m_name }, m_count, elapsed } ); - return false; - } - -} // end namespace Catch -// end catch_benchmark.cpp -// start catch_capture_matchers.cpp - -namespace Catch { - - using StringMatcher = Matchers::Impl::MatcherBase; - - // This is the general overload that takes a any string matcher - // There is another overload, in catch_assertinhandler.h/.cpp, that only takes a string and infers - // the Equals matcher (so the header does not mention matchers) - void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef matcherString ) { - std::string exceptionMessage = Catch::translateActiveException(); - MatchExpr expr( exceptionMessage, matcher, matcherString ); - handler.handle( expr ); - } - -} // namespace Catch -// end catch_capture_matchers.cpp -// start catch_commandline.cpp - -// start catch_commandline.h - -// start catch_clara.h - -// Use Catch's value for console width (store Clara's off to the side, if present) -#ifdef CLARA_CONFIG_CONSOLE_WIDTH -#define CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH -#undef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH -#endif -#define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH-1 - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wweak-vtables" -#pragma clang diagnostic ignored "-Wexit-time-destructors" -#pragma clang diagnostic ignored "-Wshadow" -#endif - -// start clara.hpp -// v1.0-develop.2 -// See https://github.com/philsquared/Clara - - -#ifndef CATCH_CLARA_CONFIG_CONSOLE_WIDTH -#define CATCH_CLARA_CONFIG_CONSOLE_WIDTH 80 -#endif - -#ifndef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH -#define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_CLARA_CONFIG_CONSOLE_WIDTH -#endif - -// ----------- #included from clara_textflow.hpp ----------- - -// TextFlowCpp -// -// A single-header library for wrapping and laying out basic text, by Phil Nash -// -// This work is licensed under the BSD 2-Clause license. -// See the accompanying LICENSE file, or the one at https://opensource.org/licenses/BSD-2-Clause -// -// This project is hosted at https://github.com/philsquared/textflowcpp - - -#include -#include -#include -#include - -#ifndef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH -#define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH 80 -#endif - -namespace Catch { namespace clara { namespace TextFlow { - - inline auto isWhitespace( char c ) -> bool { - static std::string chars = " \t\n\r"; - return chars.find( c ) != std::string::npos; - } - inline auto isBreakableBefore( char c ) -> bool { - static std::string chars = "[({<|"; - return chars.find( c ) != std::string::npos; - } - inline auto isBreakableAfter( char c ) -> bool { - static std::string chars = "])}>.,:;*+-=&/\\"; - return chars.find( c ) != std::string::npos; - } - - class Columns; - - class Column { - std::vector m_strings; - size_t m_width = CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH; - size_t m_indent = 0; - size_t m_initialIndent = std::string::npos; - - public: - class iterator { - friend Column; - - Column const& m_column; - size_t m_stringIndex = 0; - size_t m_pos = 0; - - size_t m_len = 0; - size_t m_end = 0; - bool m_suffix = false; - - iterator( Column const& column, size_t stringIndex ) - : m_column( column ), - m_stringIndex( stringIndex ) - {} - - auto line() const -> std::string const& { return m_column.m_strings[m_stringIndex]; } - - auto isBoundary( size_t at ) const -> bool { - assert( at > 0 ); - assert( at <= line().size() ); - - return at == line().size() || - ( isWhitespace( line()[at] ) && !isWhitespace( line()[at-1] ) ) || - isBreakableBefore( line()[at] ) || - isBreakableAfter( line()[at-1] ); - } - - void calcLength() { - assert( m_stringIndex < m_column.m_strings.size() ); - - m_suffix = false; - auto width = m_column.m_width-indent(); - m_end = m_pos; - while( m_end < line().size() && line()[m_end] != '\n' ) - ++m_end; - - if( m_end < m_pos + width ) { - m_len = m_end - m_pos; - } - else { - size_t len = width; - while (len > 0 && !isBoundary(m_pos + len)) - --len; - while (len > 0 && isWhitespace( line()[m_pos + len - 1] )) - --len; - - if (len > 0) { - m_len = len; - } else { - m_suffix = true; - m_len = width - 1; - } - } - } - - auto indent() const -> size_t { - auto initial = m_pos == 0 && m_stringIndex == 0 ? m_column.m_initialIndent : std::string::npos; - return initial == std::string::npos ? m_column.m_indent : initial; - } - - auto addIndentAndSuffix(std::string const &plain) const -> std::string { - return std::string( indent(), ' ' ) + (m_suffix ? plain + "-" : plain); - } - - public: - explicit iterator( Column const& column ) : m_column( column ) { - assert( m_column.m_width > m_column.m_indent ); - assert( m_column.m_initialIndent == std::string::npos || m_column.m_width > m_column.m_initialIndent ); - calcLength(); - if( m_len == 0 ) - m_stringIndex++; // Empty string - } - - auto operator *() const -> std::string { - assert( m_stringIndex < m_column.m_strings.size() ); - assert( m_pos <= m_end ); - if( m_pos + m_column.m_width < m_end ) - return addIndentAndSuffix(line().substr(m_pos, m_len)); - else - return addIndentAndSuffix(line().substr(m_pos, m_end - m_pos)); - } - - auto operator ++() -> iterator& { - m_pos += m_len; - if( m_pos < line().size() && line()[m_pos] == '\n' ) - m_pos += 1; - else - while( m_pos < line().size() && isWhitespace( line()[m_pos] ) ) - ++m_pos; - - if( m_pos == line().size() ) { - m_pos = 0; - ++m_stringIndex; - } - if( m_stringIndex < m_column.m_strings.size() ) - calcLength(); - return *this; - } - auto operator ++(int) -> iterator { - iterator prev( *this ); - operator++(); - return prev; - } - - auto operator ==( iterator const& other ) const -> bool { - return - m_pos == other.m_pos && - m_stringIndex == other.m_stringIndex && - &m_column == &other.m_column; - } - auto operator !=( iterator const& other ) const -> bool { - return !operator==( other ); - } - }; - using const_iterator = iterator; - - explicit Column( std::string const& text ) { m_strings.push_back( text ); } - - auto width( size_t newWidth ) -> Column& { - assert( newWidth > 0 ); - m_width = newWidth; - return *this; - } - auto indent( size_t newIndent ) -> Column& { - m_indent = newIndent; - return *this; - } - auto initialIndent( size_t newIndent ) -> Column& { - m_initialIndent = newIndent; - return *this; - } - - auto width() const -> size_t { return m_width; } - auto begin() const -> iterator { return iterator( *this ); } - auto end() const -> iterator { return { *this, m_strings.size() }; } - - inline friend std::ostream& operator << ( std::ostream& os, Column const& col ) { - bool first = true; - for( auto line : col ) { - if( first ) - first = false; - else - os << "\n"; - os << line; - } - return os; - } - - auto operator + ( Column const& other ) -> Columns; - - auto toString() const -> std::string { - std::ostringstream oss; - oss << *this; - return oss.str(); - } - }; - - class Spacer : public Column { - - public: - explicit Spacer( size_t spaceWidth ) : Column( "" ) { - width( spaceWidth ); - } - }; - - class Columns { - std::vector m_columns; - - public: - - class iterator { - friend Columns; - struct EndTag {}; - - std::vector const& m_columns; - std::vector m_iterators; - size_t m_activeIterators; - - iterator( Columns const& columns, EndTag ) - : m_columns( columns.m_columns ), - m_activeIterators( 0 ) - { - m_iterators.reserve( m_columns.size() ); - - for( auto const& col : m_columns ) - m_iterators.push_back( col.end() ); - } - - public: - explicit iterator( Columns const& columns ) - : m_columns( columns.m_columns ), - m_activeIterators( m_columns.size() ) - { - m_iterators.reserve( m_columns.size() ); - - for( auto const& col : m_columns ) - m_iterators.push_back( col.begin() ); - } - - auto operator ==( iterator const& other ) const -> bool { - return m_iterators == other.m_iterators; - } - auto operator !=( iterator const& other ) const -> bool { - return m_iterators != other.m_iterators; - } - auto operator *() const -> std::string { - std::string row, padding; - - for( size_t i = 0; i < m_columns.size(); ++i ) { - auto width = m_columns[i].width(); - if( m_iterators[i] != m_columns[i].end() ) { - std::string col = *m_iterators[i]; - row += padding + col; - if( col.size() < width ) - padding = std::string( width - col.size(), ' ' ); - else - padding = ""; - } - else { - padding += std::string( width, ' ' ); - } - } - return row; - } - auto operator ++() -> iterator& { - for( size_t i = 0; i < m_columns.size(); ++i ) { - if (m_iterators[i] != m_columns[i].end()) - ++m_iterators[i]; - } - return *this; - } - auto operator ++(int) -> iterator { - iterator prev( *this ); - operator++(); - return prev; - } - }; - using const_iterator = iterator; - - auto begin() const -> iterator { return iterator( *this ); } - auto end() const -> iterator { return { *this, iterator::EndTag() }; } - - auto operator += ( Column const& col ) -> Columns& { - m_columns.push_back( col ); - return *this; - } - auto operator + ( Column const& col ) -> Columns { - Columns combined = *this; - combined += col; - return combined; - } - - inline friend std::ostream& operator << ( std::ostream& os, Columns const& cols ) { - - bool first = true; - for( auto line : cols ) { - if( first ) - first = false; - else - os << "\n"; - os << line; - } - return os; - } - - auto toString() const -> std::string { - std::ostringstream oss; - oss << *this; - return oss.str(); - } - }; - - inline auto Column::operator + ( Column const& other ) -> Columns { - Columns cols; - cols += *this; - cols += other; - return cols; - } -}}} // namespace Catch::clara::TextFlow - -// ----------- end of #include from clara_textflow.hpp ----------- -// ........... back in clara.hpp - -#include -#include -#include - -#if !defined(CATCH_PLATFORM_WINDOWS) && ( defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) ) -#define CATCH_PLATFORM_WINDOWS -#endif - -namespace Catch { namespace clara { -namespace detail { - - // Traits for extracting arg and return type of lambdas (for single argument lambdas) - template - struct UnaryLambdaTraits : UnaryLambdaTraits {}; - - template - struct UnaryLambdaTraits { - static const bool isValid = false; - }; - - template - struct UnaryLambdaTraits { - static const bool isValid = true; - using ArgType = typename std::remove_const::type>::type;; - using ReturnType = ReturnT; - }; - - class TokenStream; - - // Transport for raw args (copied from main args, or supplied via init list for testing) - class Args { - friend TokenStream; - std::string m_exeName; - std::vector m_args; - - public: - Args( int argc, char *argv[] ) { - m_exeName = argv[0]; - for( int i = 1; i < argc; ++i ) - m_args.push_back( argv[i] ); - } - - Args( std::initializer_list args ) - : m_exeName( *args.begin() ), - m_args( args.begin()+1, args.end() ) - {} - - auto exeName() const -> std::string { - return m_exeName; - } - }; - - // Wraps a token coming from a token stream. These may not directly correspond to strings as a single string - // may encode an option + its argument if the : or = form is used - enum class TokenType { - Option, Argument - }; - struct Token { - TokenType type; - std::string token; - }; - - inline auto isOptPrefix( char c ) -> bool { - return c == '-' -#ifdef CATCH_PLATFORM_WINDOWS - || c == '/' -#endif - ; - } - - // Abstracts iterators into args as a stream of tokens, with option arguments uniformly handled - class TokenStream { - using Iterator = std::vector::const_iterator; - Iterator it; - Iterator itEnd; - std::vector m_tokenBuffer; - - void loadBuffer() { - m_tokenBuffer.resize( 0 ); - - // Skip any empty strings - while( it != itEnd && it->empty() ) - ++it; - - if( it != itEnd ) { - auto const &next = *it; - if( isOptPrefix( next[0] ) ) { - auto delimiterPos = next.find_first_of( " :=" ); - if( delimiterPos != std::string::npos ) { - m_tokenBuffer.push_back( { TokenType::Option, next.substr( 0, delimiterPos ) } ); - m_tokenBuffer.push_back( { TokenType::Argument, next.substr( delimiterPos + 1 ) } ); - } else { - if( next[1] != '-' && next.size() > 2 ) { - std::string opt = "- "; - for( size_t i = 1; i < next.size(); ++i ) { - opt[1] = next[i]; - m_tokenBuffer.push_back( { TokenType::Option, opt } ); - } - } else { - m_tokenBuffer.push_back( { TokenType::Option, next } ); - } - } - } else { - m_tokenBuffer.push_back( { TokenType::Argument, next } ); - } - } - } - - public: - explicit TokenStream( Args const &args ) : TokenStream( args.m_args.begin(), args.m_args.end() ) {} - - TokenStream( Iterator it, Iterator itEnd ) : it( it ), itEnd( itEnd ) { - loadBuffer(); - } - - explicit operator bool() const { - return !m_tokenBuffer.empty() || it != itEnd; - } - - auto count() const -> size_t { return m_tokenBuffer.size() + (itEnd - it); } - - auto operator*() const -> Token { - assert( !m_tokenBuffer.empty() ); - return m_tokenBuffer.front(); - } - - auto operator->() const -> Token const * { - assert( !m_tokenBuffer.empty() ); - return &m_tokenBuffer.front(); - } - - auto operator++() -> TokenStream & { - if( m_tokenBuffer.size() >= 2 ) { - m_tokenBuffer.erase( m_tokenBuffer.begin() ); - } else { - if( it != itEnd ) - ++it; - loadBuffer(); - } - return *this; - } - }; - - class ResultBase { - public: - enum Type { - Ok, LogicError, RuntimeError - }; - - protected: - ResultBase( Type type ) : m_type( type ) {} - virtual ~ResultBase() = default; - - virtual void enforceOk() const = 0; - - Type m_type; - }; - - template - class ResultValueBase : public ResultBase { - public: - auto value() const -> T const & { - enforceOk(); - return m_value; - } - - protected: - ResultValueBase( Type type ) : ResultBase( type ) {} - - ResultValueBase( ResultValueBase const &other ) : ResultBase( other ) { - if( m_type == ResultBase::Ok ) - new( &m_value ) T( other.m_value ); - } - - ResultValueBase( Type, T const &value ) : ResultBase( Ok ) { - new( &m_value ) T( value ); - } - - auto operator=( ResultValueBase const &other ) -> ResultValueBase & { - if( m_type == ResultBase::Ok ) - m_value.~T(); - ResultBase::operator=(other); - if( m_type == ResultBase::Ok ) - new( &m_value ) T( other.m_value ); - return *this; - } - - ~ResultValueBase() { - if( m_type == Ok ) - m_value.~T(); - } - - union { - T m_value; - }; - }; - - template<> - class ResultValueBase : public ResultBase { - protected: - using ResultBase::ResultBase; - }; - - template - class BasicResult : public ResultValueBase { - public: - template - explicit BasicResult( BasicResult const &other ) - : ResultValueBase( other.type() ), - m_errorMessage( other.errorMessage() ) - { - assert( type() != ResultBase::Ok ); - } - - template - static auto ok( U const &value ) -> BasicResult { return { ResultBase::Ok, value }; } - static auto ok() -> BasicResult { return { ResultBase::Ok }; } - static auto logicError( std::string const &message ) -> BasicResult { return { ResultBase::LogicError, message }; } - static auto runtimeError( std::string const &message ) -> BasicResult { return { ResultBase::RuntimeError, message }; } - - explicit operator bool() const { return m_type == ResultBase::Ok; } - auto type() const -> ResultBase::Type { return m_type; } - auto errorMessage() const -> std::string { return m_errorMessage; } - - protected: - virtual void enforceOk() const { - // !TBD: If no exceptions, std::terminate here or something - switch( m_type ) { - case ResultBase::LogicError: - throw std::logic_error( m_errorMessage ); - case ResultBase::RuntimeError: - throw std::runtime_error( m_errorMessage ); - case ResultBase::Ok: - break; - } - } - - std::string m_errorMessage; // Only populated if resultType is an error - - BasicResult( ResultBase::Type type, std::string const &message ) - : ResultValueBase(type), - m_errorMessage(message) - { - assert( m_type != ResultBase::Ok ); - } - - using ResultValueBase::ResultValueBase; - using ResultBase::m_type; - }; - - enum class ParseResultType { - Matched, NoMatch, ShortCircuitAll, ShortCircuitSame - }; - - class ParseState { - public: - - ParseState( ParseResultType type, TokenStream const &remainingTokens ) - : m_type(type), - m_remainingTokens( remainingTokens ) - {} - - auto type() const -> ParseResultType { return m_type; } - auto remainingTokens() const -> TokenStream { return m_remainingTokens; } - - private: - ParseResultType m_type; - TokenStream m_remainingTokens; - }; - - using Result = BasicResult; - using ParserResult = BasicResult; - using InternalParseResult = BasicResult; - - struct HelpColumns { - std::string left; - std::string right; - }; - - template - inline auto convertInto( std::string const &source, T& target ) -> ParserResult { - std::stringstream ss; - ss << source; - ss >> target; - if( ss.fail() ) - return ParserResult::runtimeError( "Unable to convert '" + source + "' to destination type" ); - else - return ParserResult::ok( ParseResultType::Matched ); - } - inline auto convertInto( std::string const &source, std::string& target ) -> ParserResult { - target = source; - return ParserResult::ok( ParseResultType::Matched ); - } - inline auto convertInto( std::string const &source, bool &target ) -> ParserResult { - std::string srcLC = source; - std::transform( srcLC.begin(), srcLC.end(), srcLC.begin(), []( char c ) { return static_cast( ::tolower(c) ); } ); - if (srcLC == "y" || srcLC == "1" || srcLC == "true" || srcLC == "yes" || srcLC == "on") - target = true; - else if (srcLC == "n" || srcLC == "0" || srcLC == "false" || srcLC == "no" || srcLC == "off") - target = false; - else - return ParserResult::runtimeError( "Expected a boolean value but did not recognise: '" + source + "'" ); - return ParserResult::ok( ParseResultType::Matched ); - } - - struct BoundRefBase { - BoundRefBase() = default; - BoundRefBase( BoundRefBase const & ) = delete; - BoundRefBase( BoundRefBase && ) = delete; - BoundRefBase &operator=( BoundRefBase const & ) = delete; - BoundRefBase &operator=( BoundRefBase && ) = delete; - - virtual ~BoundRefBase() = default; - - virtual auto isFlag() const -> bool = 0; - virtual auto isContainer() const -> bool { return false; } - virtual auto setValue( std::string const &arg ) -> ParserResult = 0; - virtual auto setFlag( bool flag ) -> ParserResult = 0; - }; - - struct BoundValueRefBase : BoundRefBase { - auto isFlag() const -> bool override { return false; } - - auto setFlag( bool ) -> ParserResult override { - return ParserResult::logicError( "Flags can only be set on boolean fields" ); - } - }; - - struct BoundFlagRefBase : BoundRefBase { - auto isFlag() const -> bool override { return true; } - - auto setValue( std::string const &arg ) -> ParserResult override { - bool flag; - auto result = convertInto( arg, flag ); - if( result ) - setFlag( flag ); - return result; - } - }; - - template - struct BoundRef : BoundValueRefBase { - T &m_ref; - - explicit BoundRef( T &ref ) : m_ref( ref ) {} - - auto setValue( std::string const &arg ) -> ParserResult override { - return convertInto( arg, m_ref ); - } - }; - - template - struct BoundRef> : BoundValueRefBase { - std::vector &m_ref; - - explicit BoundRef( std::vector &ref ) : m_ref( ref ) {} - - auto isContainer() const -> bool override { return true; } - - auto setValue( std::string const &arg ) -> ParserResult override { - T temp; - auto result = convertInto( arg, temp ); - if( result ) - m_ref.push_back( temp ); - return result; - } - }; - - struct BoundFlagRef : BoundFlagRefBase { - bool &m_ref; - - explicit BoundFlagRef( bool &ref ) : m_ref( ref ) {} - - auto setFlag( bool flag ) -> ParserResult override { - m_ref = flag; - return ParserResult::ok( ParseResultType::Matched ); - } - }; - - template - struct LambdaInvoker { - static_assert( std::is_same::value, "Lambda must return void or clara::ParserResult" ); - - template - static auto invoke( L const &lambda, ArgType const &arg ) -> ParserResult { - return lambda( arg ); - } - }; - - template<> - struct LambdaInvoker { - template - static auto invoke( L const &lambda, ArgType const &arg ) -> ParserResult { - lambda( arg ); - return ParserResult::ok( ParseResultType::Matched ); - } - }; - - template - inline auto invokeLambda( L const &lambda, std::string const &arg ) -> ParserResult { - ArgType temp; - auto result = convertInto( arg, temp ); - return !result - ? result - : LambdaInvoker::ReturnType>::invoke( lambda, temp ); - }; - - template - struct BoundLambda : BoundValueRefBase { - L m_lambda; - - static_assert( UnaryLambdaTraits::isValid, "Supplied lambda must take exactly one argument" ); - explicit BoundLambda( L const &lambda ) : m_lambda( lambda ) {} - - auto setValue( std::string const &arg ) -> ParserResult override { - return invokeLambda::ArgType>( m_lambda, arg ); - } - }; - - template - struct BoundFlagLambda : BoundFlagRefBase { - L m_lambda; - - static_assert( UnaryLambdaTraits::isValid, "Supplied lambda must take exactly one argument" ); - static_assert( std::is_same::ArgType, bool>::value, "flags must be boolean" ); - - explicit BoundFlagLambda( L const &lambda ) : m_lambda( lambda ) {} - - auto setFlag( bool flag ) -> ParserResult override { - return LambdaInvoker::ReturnType>::invoke( m_lambda, flag ); - } - }; - - enum class Optionality { Optional, Required }; - - struct Parser; - - class ParserBase { - public: - virtual ~ParserBase() = default; - virtual auto validate() const -> Result { return Result::ok(); } - virtual auto parse( std::string const& exeName, TokenStream const &tokens) const -> InternalParseResult = 0; - virtual auto cardinality() const -> size_t { return 1; } - - auto parse( Args const &args ) const -> InternalParseResult { - return parse( args.exeName(), TokenStream( args ) ); - } - }; - - template - class ComposableParserImpl : public ParserBase { - public: - template - auto operator|( T const &other ) const -> Parser; - }; - - // Common code and state for Args and Opts - template - class ParserRefImpl : public ComposableParserImpl { - protected: - Optionality m_optionality = Optionality::Optional; - std::shared_ptr m_ref; - std::string m_hint; - std::string m_description; - - explicit ParserRefImpl( std::shared_ptr const &ref ) : m_ref( ref ) {} - - public: - template - ParserRefImpl( T &ref, std::string const &hint ) - : m_ref( std::make_shared>( ref ) ), - m_hint( hint ) - {} - - template - ParserRefImpl( LambdaT const &ref, std::string const &hint ) - : m_ref( std::make_shared>( ref ) ), - m_hint(hint) - {} - - auto operator()( std::string const &description ) -> DerivedT & { - m_description = description; - return static_cast( *this ); - } - - auto optional() -> DerivedT & { - m_optionality = Optionality::Optional; - return static_cast( *this ); - }; - - auto required() -> DerivedT & { - m_optionality = Optionality::Required; - return static_cast( *this ); - }; - - auto isOptional() const -> bool { - return m_optionality == Optionality::Optional; - } - - auto cardinality() const -> size_t override { - if( m_ref->isContainer() ) - return 0; - else - return 1; - } - - auto hint() const -> std::string { return m_hint; } - }; - - class ExeName : public ComposableParserImpl { - std::shared_ptr m_name; - std::shared_ptr m_ref; - - template - static auto makeRef(LambdaT const &lambda) -> std::shared_ptr { - return std::make_shared>( lambda) ; - } - - public: - ExeName() : m_name( std::make_shared( "" ) ) {} - - explicit ExeName( std::string &ref ) : ExeName() { - m_ref = std::make_shared>( ref ); - } - - template - explicit ExeName( LambdaT const& lambda ) : ExeName() { - m_ref = std::make_shared>( lambda ); - } - - // The exe name is not parsed out of the normal tokens, but is handled specially - auto parse( std::string const&, TokenStream const &tokens ) const -> InternalParseResult override { - return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, tokens ) ); - } - - auto name() const -> std::string { return *m_name; } - auto set( std::string const& newName ) -> ParserResult { - - auto lastSlash = newName.find_last_of( "\\/" ); - auto filename = ( lastSlash == std::string::npos ) - ? newName - : newName.substr( lastSlash+1 ); - - *m_name = filename; - if( m_ref ) - return m_ref->setValue( filename ); - else - return ParserResult::ok( ParseResultType::Matched ); - } - }; - - class Arg : public ParserRefImpl { - public: - using ParserRefImpl::ParserRefImpl; - - auto parse( std::string const &, TokenStream const &tokens ) const -> InternalParseResult override { - auto validationResult = validate(); - if( !validationResult ) - return InternalParseResult( validationResult ); - - auto remainingTokens = tokens; - auto const &token = *remainingTokens; - if( token.type != TokenType::Argument ) - return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) ); - - auto result = m_ref->setValue( remainingTokens->token ); - if( !result ) - return InternalParseResult( result ); - else - return InternalParseResult::ok( ParseState( ParseResultType::Matched, ++remainingTokens ) ); - } - }; - - inline auto normaliseOpt( std::string const &optName ) -> std::string { -#ifdef CATCH_PLATFORM_WINDOWS - if( optName[0] == '/' ) - return "-" + optName.substr( 1 ); - else -#endif - return optName; - } - - class Opt : public ParserRefImpl { - protected: - std::vector m_optNames; - - public: - template - explicit Opt( LambdaT const &ref ) : ParserRefImpl( std::make_shared>( ref ) ) {} - - explicit Opt( bool &ref ) : ParserRefImpl( std::make_shared( ref ) ) {} - - template - Opt( LambdaT const &ref, std::string const &hint ) : ParserRefImpl( ref, hint ) {} - - template - Opt( T &ref, std::string const &hint ) : ParserRefImpl( ref, hint ) {} - - auto operator[]( std::string const &optName ) -> Opt & { - m_optNames.push_back( optName ); - return *this; - } - - auto getHelpColumns() const -> std::vector { - std::ostringstream oss; - bool first = true; - for( auto const &opt : m_optNames ) { - if (first) - first = false; - else - oss << ", "; - oss << opt; - } - if( !m_hint.empty() ) - oss << " <" << m_hint << ">"; - return { { oss.str(), m_description } }; - } - - auto isMatch( std::string const &optToken ) const -> bool { - auto normalisedToken = normaliseOpt( optToken ); - for( auto const &name : m_optNames ) { - if( normaliseOpt( name ) == normalisedToken ) - return true; - } - return false; - } - - using ParserBase::parse; - - auto parse( std::string const&, TokenStream const &tokens ) const -> InternalParseResult override { - auto validationResult = validate(); - if( !validationResult ) - return InternalParseResult( validationResult ); - - auto remainingTokens = tokens; - if( remainingTokens && remainingTokens->type == TokenType::Option ) { - auto const &token = *remainingTokens; - if( isMatch(token.token ) ) { - if( m_ref->isFlag() ) { - auto result = m_ref->setFlag( true ); - if( !result ) - return InternalParseResult( result ); - if( result.value() == ParseResultType::ShortCircuitAll ) - return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) ); - } else { - ++remainingTokens; - if( !remainingTokens ) - return InternalParseResult::runtimeError( "Expected argument following " + token.token ); - auto const &argToken = *remainingTokens; - if( argToken.type != TokenType::Argument ) - return InternalParseResult::runtimeError( "Expected argument following " + token.token ); - auto result = m_ref->setValue( argToken.token ); - if( !result ) - return InternalParseResult( result ); - if( result.value() == ParseResultType::ShortCircuitAll ) - return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) ); - } - return InternalParseResult::ok( ParseState( ParseResultType::Matched, ++remainingTokens ) ); - } - } - return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) ); - } - - auto validate() const -> Result override { - if( m_optNames.empty() ) - return Result::logicError( "No options supplied to Opt" ); - for( auto const &name : m_optNames ) { - if( name.empty() ) - return Result::logicError( "Option name cannot be empty" ); -#ifdef CATCH_PLATFORM_WINDOWS - if( name[0] != '-' && name[0] != '/' ) - return Result::logicError( "Option name must begin with '-' or '/'" ); -#else - if( name[0] != '-' ) - return Result::logicError( "Option name must begin with '-'" ); -#endif - } - return ParserRefImpl::validate(); - } - }; - - struct Help : Opt { - Help( bool &showHelpFlag ) - : Opt([&]( bool flag ) { - showHelpFlag = flag; - return ParserResult::ok( ParseResultType::ShortCircuitAll ); - }) - { - static_cast( *this ) - ("display usage information") - ["-?"]["-h"]["--help"] - .optional(); - } - }; - - struct Parser : ParserBase { - - mutable ExeName m_exeName; - std::vector m_options; - std::vector m_args; - - auto operator|=( ExeName const &exeName ) -> Parser & { - m_exeName = exeName; - return *this; - } - - auto operator|=( Arg const &arg ) -> Parser & { - m_args.push_back(arg); - return *this; - } - - auto operator|=( Opt const &opt ) -> Parser & { - m_options.push_back(opt); - return *this; - } - - auto operator|=( Parser const &other ) -> Parser & { - m_options.insert(m_options.end(), other.m_options.begin(), other.m_options.end()); - m_args.insert(m_args.end(), other.m_args.begin(), other.m_args.end()); - return *this; - } - - template - auto operator|( T const &other ) const -> Parser { - return Parser( *this ) |= other; - } - - auto getHelpColumns() const -> std::vector { - std::vector cols; - for (auto const &o : m_options) { - auto childCols = o.getHelpColumns(); - cols.insert( cols.end(), childCols.begin(), childCols.end() ); - } - return cols; - } - - void writeToStream( std::ostream &os ) const { - if (!m_exeName.name().empty()) { - os << "usage:\n" << " " << m_exeName.name() << " "; - bool required = true, first = true; - for( auto const &arg : m_args ) { - if (first) - first = false; - else - os << " "; - if( arg.isOptional() && required ) { - os << "["; - required = false; - } - os << "<" << arg.hint() << ">"; - if( arg.cardinality() == 0 ) - os << " ... "; - } - if( !required ) - os << "]"; - if( !m_options.empty() ) - os << " options"; - os << "\n\nwhere options are:" << std::endl; - } - - auto rows = getHelpColumns(); - size_t consoleWidth = CATCH_CLARA_CONFIG_CONSOLE_WIDTH; - size_t optWidth = 0; - for( auto const &cols : rows ) - optWidth = (std::max)(optWidth, cols.left.size() + 2); - - for( auto const &cols : rows ) { - auto row = - TextFlow::Column( cols.left ).width( optWidth ).indent( 2 ) + - TextFlow::Spacer(4) + - TextFlow::Column( cols.right ).width( consoleWidth - 7 - optWidth ); - os << row << std::endl; - } - } - - friend auto operator<<( std::ostream &os, Parser const &parser ) -> std::ostream& { - parser.writeToStream( os ); - return os; - } - - auto validate() const -> Result override { - for( auto const &opt : m_options ) { - auto result = opt.validate(); - if( !result ) - return result; - } - for( auto const &arg : m_args ) { - auto result = arg.validate(); - if( !result ) - return result; - } - return Result::ok(); - } - - using ParserBase::parse; - - auto parse( std::string const& exeName, TokenStream const &tokens ) const -> InternalParseResult override { - - struct ParserInfo { - ParserBase const* parser = nullptr; - size_t count = 0; - }; - const size_t totalParsers = m_options.size() + m_args.size(); - assert( totalParsers < 512 ); - // ParserInfo parseInfos[totalParsers]; // <-- this is what we really want to do - ParserInfo parseInfos[512]; - - { - size_t i = 0; - for (auto const &opt : m_options) parseInfos[i++].parser = &opt; - for (auto const &arg : m_args) parseInfos[i++].parser = &arg; - } - - m_exeName.set( exeName ); - - auto result = InternalParseResult::ok( ParseState( ParseResultType::NoMatch, tokens ) ); - while( result.value().remainingTokens() ) { - bool tokenParsed = false; - - for( size_t i = 0; i < totalParsers; ++i ) { - auto& parseInfo = parseInfos[i]; - if( parseInfo.parser->cardinality() == 0 || parseInfo.count < parseInfo.parser->cardinality() ) { - result = parseInfo.parser->parse(exeName, result.value().remainingTokens()); - if (!result) - return result; - if (result.value().type() != ParseResultType::NoMatch) { - tokenParsed = true; - ++parseInfo.count; - break; - } - } - } - - if( result.value().type() == ParseResultType::ShortCircuitAll ) - return result; - if( !tokenParsed ) - return InternalParseResult::runtimeError( "Unrecognised token: " + result.value().remainingTokens()->token ); - } - // !TBD Check missing required options - return result; - } - }; - - template - template - auto ComposableParserImpl::operator|( T const &other ) const -> Parser { - return Parser() | static_cast( *this ) | other; - } -} // namespace detail - -// A Combined parser -using detail::Parser; - -// A parser for options -using detail::Opt; - -// A parser for arguments -using detail::Arg; - -// Wrapper for argc, argv from main() -using detail::Args; - -// Specifies the name of the executable -using detail::ExeName; - -// Convenience wrapper for option parser that specifies the help option -using detail::Help; - -// enum of result types from a parse -using detail::ParseResultType; - -// Result type for parser operation -using detail::ParserResult; - -}} // namespace Catch::clara - -// end clara.hpp -#ifdef __clang__ -#pragma clang diagnostic pop -#endif - -// Restore Clara's value for console width, if present -#ifdef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH -#define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH -#undef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH -#endif - -// end catch_clara.h -namespace Catch { - - clara::Parser makeCommandLineParser( ConfigData& config ); - -} // end namespace Catch - -// end catch_commandline.h -#include -#include - -namespace Catch { - - clara::Parser makeCommandLineParser( ConfigData& config ) { - - using namespace clara; - - auto const setWarning = [&]( std::string const& warning ) { - if( warning != "NoAssertions" ) - return ParserResult::runtimeError( "Unrecognised warning: '" + warning + "'" ); - config.warnings = static_cast( config.warnings | WarnAbout::NoAssertions ); - return ParserResult::ok( ParseResultType::Matched ); - }; - auto const loadTestNamesFromFile = [&]( std::string const& filename ) { - std::ifstream f( filename.c_str() ); - if( !f.is_open() ) - return ParserResult::runtimeError( "Unable to load input file: '" + filename + "'" ); - - std::string line; - while( std::getline( f, line ) ) { - line = trim(line); - if( !line.empty() && !startsWith( line, '#' ) ) { - if( !startsWith( line, '"' ) ) - line = '"' + line + '"'; - config.testsOrTags.push_back( line + ',' ); - } - } - return ParserResult::ok( ParseResultType::Matched ); - }; - auto const setTestOrder = [&]( std::string const& order ) { - if( startsWith( "declared", order ) ) - config.runOrder = RunTests::InDeclarationOrder; - else if( startsWith( "lexical", order ) ) - config.runOrder = RunTests::InLexicographicalOrder; - else if( startsWith( "random", order ) ) - config.runOrder = RunTests::InRandomOrder; - else - return clara::ParserResult::runtimeError( "Unrecognised ordering: '" + order + "'" ); - return ParserResult::ok( ParseResultType::Matched ); - }; - auto const setRngSeed = [&]( std::string const& seed ) { - if( seed != "time" ) - return clara::detail::convertInto( seed, config.rngSeed ); - config.rngSeed = static_cast( std::time(nullptr) ); - return ParserResult::ok( ParseResultType::Matched ); - }; - auto const setColourUsage = [&]( std::string const& useColour ) { - auto mode = toLower( useColour ); - - if( mode == "yes" ) - config.useColour = UseColour::Yes; - else if( mode == "no" ) - config.useColour = UseColour::No; - else if( mode == "auto" ) - config.useColour = UseColour::Auto; - else - return ParserResult::runtimeError( "colour mode must be one of: auto, yes or no. '" + useColour + "' not recognised" ); - return ParserResult::ok( ParseResultType::Matched ); - }; - auto const setWaitForKeypress = [&]( std::string const& keypress ) { - auto keypressLc = toLower( keypress ); - if( keypressLc == "start" ) - config.waitForKeypress = WaitForKeypress::BeforeStart; - else if( keypressLc == "exit" ) - config.waitForKeypress = WaitForKeypress::BeforeExit; - else if( keypressLc == "both" ) - config.waitForKeypress = WaitForKeypress::BeforeStartAndExit; - else - return ParserResult::runtimeError( "keypress argument must be one of: start, exit or both. '" + keypress + "' not recognised" ); - return ParserResult::ok( ParseResultType::Matched ); - }; - auto const setVerbosity = [&]( std::string const& verbosity ) { - auto lcVerbosity = toLower( verbosity ); - if( lcVerbosity == "quiet" ) - config.verbosity = Verbosity::Quiet; - else if( lcVerbosity == "normal" ) - config.verbosity = Verbosity::Normal; - else if( lcVerbosity == "high" ) - config.verbosity = Verbosity::High; - else - return ParserResult::runtimeError( "Unrecognised verbosity, '" + verbosity + "'" ); - return ParserResult::ok( ParseResultType::Matched ); - }; - - auto cli - = ExeName( config.processName ) - | Help( config.showHelp ) - | Opt( config.listTests ) - ["-l"]["--list-tests"] - ( "list all/matching test cases" ) - | Opt( config.listTags ) - ["-t"]["--list-tags"] - ( "list all/matching tags" ) - | Opt( config.showSuccessfulTests ) - ["-s"]["--success"] - ( "include successful tests in output" ) - | Opt( config.shouldDebugBreak ) - ["-b"]["--break"] - ( "break into debugger on failure" ) - | Opt( config.noThrow ) - ["-e"]["--nothrow"] - ( "skip exception tests" ) - | Opt( config.showInvisibles ) - ["-i"]["--invisibles"] - ( "show invisibles (tabs, newlines)" ) - | Opt( config.outputFilename, "filename" ) - ["-o"]["--out"] - ( "output filename" ) - | Opt( config.reporterNames, "name" ) - ["-r"]["--reporter"] - ( "reporter to use (defaults to console)" ) - | Opt( config.name, "name" ) - ["-n"]["--name"] - ( "suite name" ) - | Opt( [&]( bool ){ config.abortAfter = 1; } ) - ["-a"]["--abort"] - ( "abort at first failure" ) - | Opt( [&]( int x ){ config.abortAfter = x; }, "no. failures" ) - ["-x"]["--abortx"] - ( "abort after x failures" ) - | Opt( setWarning, "warning name" ) - ["-w"]["--warn"] - ( "enable warnings" ) - | Opt( [&]( bool flag ) { config.showDurations = flag ? ShowDurations::Always : ShowDurations::Never; }, "yes|no" ) - ["-d"]["--durations"] - ( "show test durations" ) - | Opt( loadTestNamesFromFile, "filename" ) - ["-f"]["--input-file"] - ( "load test names to run from a file" ) - | Opt( config.filenamesAsTags ) - ["-#"]["--filenames-as-tags"] - ( "adds a tag for the filename" ) - | Opt( config.sectionsToRun, "section name" ) - ["-c"]["--section"] - ( "specify section to run" ) - | Opt( setVerbosity, "quiet|normal|high" ) - ["-v"]["--verbosity"] - ( "set output verbosity" ) - | Opt( config.listTestNamesOnly ) - ["--list-test-names-only"] - ( "list all/matching test cases names only" ) - | Opt( config.listReporters ) - ["--list-reporters"] - ( "list all reporters" ) - | Opt( setTestOrder, "decl|lex|rand" ) - ["--order"] - ( "test case order (defaults to decl)" ) - | Opt( setRngSeed, "'time'|number" ) - ["--rng-seed"] - ( "set a specific seed for random numbers" ) - | Opt( setColourUsage, "yes|no" ) - ["--use-colour"] - ( "should output be colourised" ) - | Opt( config.libIdentify ) - ["--libidentify"] - ( "report name and version according to libidentify standard" ) - | Opt( setWaitForKeypress, "start|exit|both" ) - ["--wait-for-keypress"] - ( "waits for a keypress before exiting" ) - | Opt( config.benchmarkResolutionMultiple, "multiplier" ) - ["--benchmark-resolution-multiple"] - ( "multiple of clock resolution to run benchmarks" ) - - | Arg( config.testsOrTags, "test name|pattern|tags" ) - ( "which test or tests to use" ); - - return cli; - } - -} // end namespace Catch -// end catch_commandline.cpp -// start catch_common.cpp - -#include -#include - -namespace Catch { - - SourceLineInfo::SourceLineInfo( char const* _file, std::size_t _line ) noexcept - : file( _file ), - line( _line ) - {} - bool SourceLineInfo::empty() const noexcept { - return file[0] == '\0'; - } - bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const noexcept { - return line == other.line && (file == other.file || std::strcmp(file, other.file) == 0); - } - bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const noexcept { - return line < other.line || ( line == other.line && (std::strcmp(file, other.file) < 0)); - } - - std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) { -#ifndef __GNUG__ - os << info.file << '(' << info.line << ')'; -#else - os << info.file << ':' << info.line; -#endif - return os; - } - - bool isTrue( bool value ){ return value; } - bool alwaysTrue() { return true; } - bool alwaysFalse() { return false; } - - std::string StreamEndStop::operator+() const { - return std::string(); - } - - NonCopyable::NonCopyable() = default; - NonCopyable::~NonCopyable() = default; - -} -// end catch_common.cpp -// start catch_config.cpp - -namespace Catch { - - Config::Config( ConfigData const& data ) - : m_data( data ), - m_stream( openStream() ) - { - if( !data.testsOrTags.empty() ) { - TestSpecParser parser( ITagAliasRegistry::get() ); - for( auto const& testOrTags : data.testsOrTags ) - parser.parse( testOrTags ); - m_testSpec = parser.testSpec(); - } - } - - std::string const& Config::getFilename() const { - return m_data.outputFilename ; - } - - bool Config::listTests() const { return m_data.listTests; } - bool Config::listTestNamesOnly() const { return m_data.listTestNamesOnly; } - bool Config::listTags() const { return m_data.listTags; } - bool Config::listReporters() const { return m_data.listReporters; } - - std::string Config::getProcessName() const { return m_data.processName; } - - std::vector const& Config::getReporterNames() const { return m_data.reporterNames; } - std::vector const& Config::getSectionsToRun() const { return m_data.sectionsToRun; } - - TestSpec const& Config::testSpec() const { return m_testSpec; } - - bool Config::showHelp() const { return m_data.showHelp; } - - // IConfig interface - bool Config::allowThrows() const { return !m_data.noThrow; } - std::ostream& Config::stream() const { return m_stream->stream(); } - std::string Config::name() const { return m_data.name.empty() ? m_data.processName : m_data.name; } - bool Config::includeSuccessfulResults() const { return m_data.showSuccessfulTests; } - bool Config::warnAboutMissingAssertions() const { return m_data.warnings & WarnAbout::NoAssertions; } - ShowDurations::OrNot Config::showDurations() const { return m_data.showDurations; } - RunTests::InWhatOrder Config::runOrder() const { return m_data.runOrder; } - unsigned int Config::rngSeed() const { return m_data.rngSeed; } - int Config::benchmarkResolutionMultiple() const { return m_data.benchmarkResolutionMultiple; } - UseColour::YesOrNo Config::useColour() const { return m_data.useColour; } - bool Config::shouldDebugBreak() const { return m_data.shouldDebugBreak; } - int Config::abortAfter() const { return m_data.abortAfter; } - bool Config::showInvisibles() const { return m_data.showInvisibles; } - Verbosity Config::verbosity() const { return m_data.verbosity; } - - IStream const* Config::openStream() { - if( m_data.outputFilename.empty() ) - return new CoutStream(); - else if( m_data.outputFilename[0] == '%' ) { - if( m_data.outputFilename == "%debug" ) - return new DebugOutStream(); - else - CATCH_ERROR( "Unrecognised stream: '" << m_data.outputFilename << "'" ); - } - else - return new FileStream( m_data.outputFilename ); - } - -} // end namespace Catch -// end catch_config.cpp -// start catch_console_colour.cpp - -#if defined(__clang__) -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wexit-time-destructors" -#endif - -// start catch_errno_guard.h - -namespace Catch { - - class ErrnoGuard { - public: - ErrnoGuard(); - ~ErrnoGuard(); - private: - int m_oldErrno; - }; - -} - -// end catch_errno_guard.h -// start catch_windows_h_proxy.h - - -#if defined(CATCH_PLATFORM_WINDOWS) - -#if !defined(NOMINMAX) && !defined(CATCH_CONFIG_NO_NOMINMAX) -# define CATCH_DEFINED_NOMINMAX +#ifdef CATCH_DEFINES_NOMINMAX # define NOMINMAX #endif -#if !defined(WIN32_LEAN_AND_MEAN) && !defined(CATCH_CONFIG_NO_WIN32_LEAN_AND_MEAN) -# define CATCH_DEFINED_WIN32_LEAN_AND_MEAN +#ifdef CATCH_DEFINES_WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN #endif @@ -5909,21 +6381,1471 @@ namespace Catch { #include #endif -#ifdef CATCH_DEFINED_NOMINMAX +#ifdef CATCH_DEFINES_NOMINMAX # undef NOMINMAX #endif -#ifdef CATCH_DEFINED_WIN32_LEAN_AND_MEAN +#ifdef CATCH_DEFINES_WIN32_LEAN_AND_MEAN # undef WIN32_LEAN_AND_MEAN #endif -#endif // defined(CATCH_PLATFORM_WINDOWS) -// end catch_windows_h_proxy.h +# if !defined ( CATCH_CONFIG_WINDOWS_SEH ) + +namespace Catch { + struct FatalConditionHandler { + void reset() {} + }; +} + +# else // CATCH_CONFIG_WINDOWS_SEH is defined + +namespace Catch { + + struct SignalDefs { DWORD id; const char* name; }; + extern SignalDefs signalDefs[]; + // There is no 1-1 mapping between signals and windows exceptions. + // Windows can easily distinguish between SO and SigSegV, + // but SigInt, SigTerm, etc are handled differently. + SignalDefs signalDefs[] = { + { EXCEPTION_ILLEGAL_INSTRUCTION, "SIGILL - Illegal instruction signal" }, + { EXCEPTION_STACK_OVERFLOW, "SIGSEGV - Stack overflow" }, + { EXCEPTION_ACCESS_VIOLATION, "SIGSEGV - Segmentation violation signal" }, + { EXCEPTION_INT_DIVIDE_BY_ZERO, "Divide by zero error" }, + }; + + struct FatalConditionHandler { + + static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) { + for (int i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) { + if (ExceptionInfo->ExceptionRecord->ExceptionCode == signalDefs[i].id) { + reportFatal(signalDefs[i].name); + } + } + // If its not an exception we care about, pass it along. + // This stops us from eating debugger breaks etc. + return EXCEPTION_CONTINUE_SEARCH; + } + + FatalConditionHandler() { + isSet = true; + // 32k seems enough for Catch to handle stack overflow, + // but the value was found experimentally, so there is no strong guarantee + guaranteeSize = 32 * 1024; + exceptionHandlerHandle = CATCH_NULL; + // Register as first handler in current chain + exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException); + // Pass in guarantee size to be filled + SetThreadStackGuarantee(&guaranteeSize); + } + + static void reset() { + if (isSet) { + // Unregister handler and restore the old guarantee + RemoveVectoredExceptionHandler(exceptionHandlerHandle); + SetThreadStackGuarantee(&guaranteeSize); + exceptionHandlerHandle = CATCH_NULL; + isSet = false; + } + } + + ~FatalConditionHandler() { + reset(); + } + private: + static bool isSet; + static ULONG guaranteeSize; + static PVOID exceptionHandlerHandle; + }; + + bool FatalConditionHandler::isSet = false; + ULONG FatalConditionHandler::guaranteeSize = 0; + PVOID FatalConditionHandler::exceptionHandlerHandle = CATCH_NULL; + +} // namespace Catch + +# endif // CATCH_CONFIG_WINDOWS_SEH + +#else // Not Windows - assumed to be POSIX compatible ////////////////////////// + +# if !defined(CATCH_CONFIG_POSIX_SIGNALS) + +namespace Catch { + struct FatalConditionHandler { + void reset() {} + }; +} + +# else // CATCH_CONFIG_POSIX_SIGNALS is defined + +#include + +namespace Catch { + + struct SignalDefs { + int id; + const char* name; + }; + extern SignalDefs signalDefs[]; + SignalDefs signalDefs[] = { + { SIGINT, "SIGINT - Terminal interrupt signal" }, + { SIGILL, "SIGILL - Illegal instruction signal" }, + { SIGFPE, "SIGFPE - Floating point error signal" }, + { SIGSEGV, "SIGSEGV - Segmentation violation signal" }, + { SIGTERM, "SIGTERM - Termination request signal" }, + { SIGABRT, "SIGABRT - Abort (abnormal termination) signal" } + }; + + struct FatalConditionHandler { + + static bool isSet; + static struct sigaction oldSigActions [sizeof(signalDefs)/sizeof(SignalDefs)]; + static stack_t oldSigStack; + static char altStackMem[SIGSTKSZ]; + + static void handleSignal( int sig ) { + std::string name = ""; + for (std::size_t i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) { + SignalDefs &def = signalDefs[i]; + if (sig == def.id) { + name = def.name; + break; + } + } + reset(); + reportFatal(name); + raise( sig ); + } + + FatalConditionHandler() { + isSet = true; + stack_t sigStack; + sigStack.ss_sp = altStackMem; + sigStack.ss_size = SIGSTKSZ; + sigStack.ss_flags = 0; + sigaltstack(&sigStack, &oldSigStack); + struct sigaction sa = { 0 }; + + sa.sa_handler = handleSignal; + sa.sa_flags = SA_ONSTACK; + for (std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i) { + sigaction(signalDefs[i].id, &sa, &oldSigActions[i]); + } + } + + ~FatalConditionHandler() { + reset(); + } + static void reset() { + if( isSet ) { + // Set signals back to previous values -- hopefully nobody overwrote them in the meantime + for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) { + sigaction(signalDefs[i].id, &oldSigActions[i], CATCH_NULL); + } + // Return the old stack + sigaltstack(&oldSigStack, CATCH_NULL); + isSet = false; + } + } + }; + + bool FatalConditionHandler::isSet = false; + struct sigaction FatalConditionHandler::oldSigActions[sizeof(signalDefs)/sizeof(SignalDefs)] = {}; + stack_t FatalConditionHandler::oldSigStack = {}; + char FatalConditionHandler::altStackMem[SIGSTKSZ] = {}; + +} // namespace Catch + +# endif // CATCH_CONFIG_POSIX_SIGNALS + +#endif // not Windows + +#include +#include + +namespace Catch { + + class StreamRedirect { + + public: + StreamRedirect( std::ostream& stream, std::string& targetString ) + : m_stream( stream ), + m_prevBuf( stream.rdbuf() ), + m_targetString( targetString ) + { + stream.rdbuf( m_oss.rdbuf() ); + } + + ~StreamRedirect() { + m_targetString += m_oss.str(); + m_stream.rdbuf( m_prevBuf ); + } + + private: + std::ostream& m_stream; + std::streambuf* m_prevBuf; + std::ostringstream m_oss; + std::string& m_targetString; + }; + + // StdErr has two constituent streams in C++, std::cerr and std::clog + // This means that we need to redirect 2 streams into 1 to keep proper + // order of writes and cannot use StreamRedirect on its own + class StdErrRedirect { + public: + StdErrRedirect(std::string& targetString) + :m_cerrBuf( cerr().rdbuf() ), m_clogBuf(clog().rdbuf()), + m_targetString(targetString){ + cerr().rdbuf(m_oss.rdbuf()); + clog().rdbuf(m_oss.rdbuf()); + } + ~StdErrRedirect() { + m_targetString += m_oss.str(); + cerr().rdbuf(m_cerrBuf); + clog().rdbuf(m_clogBuf); + } + private: + std::streambuf* m_cerrBuf; + std::streambuf* m_clogBuf; + std::ostringstream m_oss; + std::string& m_targetString; + }; + + /////////////////////////////////////////////////////////////////////////// + + class RunContext : public IResultCapture, public IRunner { + + RunContext( RunContext const& ); + void operator =( RunContext const& ); + + public: + + explicit RunContext( Ptr const& _config, Ptr const& reporter ) + : m_runInfo( _config->name() ), + m_context( getCurrentMutableContext() ), + m_activeTestCase( CATCH_NULL ), + m_config( _config ), + m_reporter( reporter ), + m_shouldReportUnexpected ( true ) + { + m_context.setRunner( this ); + m_context.setConfig( m_config ); + m_context.setResultCapture( this ); + m_reporter->testRunStarting( m_runInfo ); + } + + virtual ~RunContext() { + m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, aborting() ) ); + } + + void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount ) { + m_reporter->testGroupStarting( GroupInfo( testSpec, groupIndex, groupsCount ) ); + } + void testGroupEnded( std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount ) { + m_reporter->testGroupEnded( TestGroupStats( GroupInfo( testSpec, groupIndex, groupsCount ), totals, aborting() ) ); + } + + Totals runTest( TestCase const& testCase ) { + Totals prevTotals = m_totals; + + std::string redirectedCout; + std::string redirectedCerr; + + TestCaseInfo testInfo = testCase.getTestCaseInfo(); + + m_reporter->testCaseStarting( testInfo ); + + m_activeTestCase = &testCase; + + do { + ITracker& rootTracker = m_trackerContext.startRun(); + assert( rootTracker.isSectionTracker() ); + static_cast( rootTracker ).addInitialFilters( m_config->getSectionsToRun() ); + do { + m_trackerContext.startCycle(); + m_testCaseTracker = &SectionTracker::acquire( m_trackerContext, TestCaseTracking::NameAndLocation( testInfo.name, testInfo.lineInfo ) ); + runCurrentTest( redirectedCout, redirectedCerr ); + } + while( !m_testCaseTracker->isSuccessfullyCompleted() && !aborting() ); + } + // !TBD: deprecated - this will be replaced by indexed trackers + while( getCurrentContext().advanceGeneratorsForCurrentTest() && !aborting() ); + + Totals deltaTotals = m_totals.delta( prevTotals ); + if( testInfo.expectedToFail() && deltaTotals.testCases.passed > 0 ) { + deltaTotals.assertions.failed++; + deltaTotals.testCases.passed--; + deltaTotals.testCases.failed++; + } + m_totals.testCases += deltaTotals.testCases; + m_reporter->testCaseEnded( TestCaseStats( testInfo, + deltaTotals, + redirectedCout, + redirectedCerr, + aborting() ) ); + + m_activeTestCase = CATCH_NULL; + m_testCaseTracker = CATCH_NULL; + + return deltaTotals; + } + + Ptr config() const { + return m_config; + } + + private: // IResultCapture + + virtual void assertionEnded( AssertionResult const& result ) { + if( result.getResultType() == ResultWas::Ok ) { + m_totals.assertions.passed++; + } + else if( !result.isOk() ) { + m_totals.assertions.failed++; + } + + // We have no use for the return value (whether messages should be cleared), because messages were made scoped + // and should be let to clear themselves out. + static_cast(m_reporter->assertionEnded(AssertionStats(result, m_messages, m_totals))); + + // Reset working state + m_lastAssertionInfo = AssertionInfo( "", m_lastAssertionInfo.lineInfo, "{Unknown expression after the reported line}" , m_lastAssertionInfo.resultDisposition ); + m_lastResult = result; + } + + virtual bool lastAssertionPassed() + { + return m_totals.assertions.passed == (m_prevPassed + 1); + } + + virtual void assertionPassed() + { + m_totals.assertions.passed++; + m_lastAssertionInfo.capturedExpression = "{Unknown expression after the reported line}"; + m_lastAssertionInfo.macroName = ""; + } + + virtual void assertionRun() + { + m_prevPassed = m_totals.assertions.passed; + } + + virtual bool sectionStarted ( + SectionInfo const& sectionInfo, + Counts& assertions + ) + { + ITracker& sectionTracker = SectionTracker::acquire( m_trackerContext, TestCaseTracking::NameAndLocation( sectionInfo.name, sectionInfo.lineInfo ) ); + if( !sectionTracker.isOpen() ) + return false; + m_activeSections.push_back( §ionTracker ); + + m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo; + + m_reporter->sectionStarting( sectionInfo ); + + assertions = m_totals.assertions; + + return true; + } + bool testForMissingAssertions( Counts& assertions ) { + if( assertions.total() != 0 ) + return false; + if( !m_config->warnAboutMissingAssertions() ) + return false; + if( m_trackerContext.currentTracker().hasChildren() ) + return false; + m_totals.assertions.failed++; + assertions.failed++; + return true; + } + + virtual void sectionEnded( SectionEndInfo const& endInfo ) { + Counts assertions = m_totals.assertions - endInfo.prevAssertions; + bool missingAssertions = testForMissingAssertions( assertions ); + + if( !m_activeSections.empty() ) { + m_activeSections.back()->close(); + m_activeSections.pop_back(); + } + + m_reporter->sectionEnded( SectionStats( endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions ) ); + m_messages.clear(); + } + + virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) { + if( m_unfinishedSections.empty() ) + m_activeSections.back()->fail(); + else + m_activeSections.back()->close(); + m_activeSections.pop_back(); + + m_unfinishedSections.push_back( endInfo ); + } + + virtual void pushScopedMessage( MessageInfo const& message ) { + m_messages.push_back( message ); + } + + virtual void popScopedMessage( MessageInfo const& message ) { + m_messages.erase( std::remove( m_messages.begin(), m_messages.end(), message ), m_messages.end() ); + } + + virtual std::string getCurrentTestName() const { + return m_activeTestCase + ? m_activeTestCase->getTestCaseInfo().name + : std::string(); + } + + virtual const AssertionResult* getLastResult() const { + return &m_lastResult; + } + + virtual void exceptionEarlyReported() { + m_shouldReportUnexpected = false; + } + + virtual void handleFatalErrorCondition( std::string const& message ) { + // Don't rebuild the result -- the stringification itself can cause more fatal errors + // Instead, fake a result data. + AssertionResultData tempResult; + tempResult.resultType = ResultWas::FatalErrorCondition; + tempResult.message = message; + AssertionResult result(m_lastAssertionInfo, tempResult); + + getResultCapture().assertionEnded(result); + + handleUnfinishedSections(); + + // Recreate section for test case (as we will lose the one that was in scope) + TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); + SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description ); + + Counts assertions; + assertions.failed = 1; + SectionStats testCaseSectionStats( testCaseSection, assertions, 0, false ); + m_reporter->sectionEnded( testCaseSectionStats ); + + TestCaseInfo testInfo = m_activeTestCase->getTestCaseInfo(); + + Totals deltaTotals; + deltaTotals.testCases.failed = 1; + deltaTotals.assertions.failed = 1; + m_reporter->testCaseEnded( TestCaseStats( testInfo, + deltaTotals, + std::string(), + std::string(), + false ) ); + m_totals.testCases.failed++; + testGroupEnded( std::string(), m_totals, 1, 1 ); + m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, false ) ); + } + + public: + // !TBD We need to do this another way! + bool aborting() const { + return m_totals.assertions.failed == static_cast( m_config->abortAfter() ); + } + + private: + + void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr ) { + TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); + SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description ); + m_reporter->sectionStarting( testCaseSection ); + Counts prevAssertions = m_totals.assertions; + double duration = 0; + m_shouldReportUnexpected = true; + try { + m_lastAssertionInfo = AssertionInfo( "TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal ); + + seedRng( *m_config ); + + Timer timer; + timer.start(); + if( m_reporter->getPreferences().shouldRedirectStdOut ) { + StreamRedirect coutRedir( Catch::cout(), redirectedCout ); + StdErrRedirect errRedir( redirectedCerr ); + invokeActiveTestCase(); + } + else { + invokeActiveTestCase(); + } + duration = timer.getElapsedSeconds(); + } + catch( TestFailureException& ) { + // This just means the test was aborted due to failure + } + catch(...) { + // Under CATCH_CONFIG_FAST_COMPILE, unexpected exceptions under REQUIRE assertions + // are reported without translation at the point of origin. + if (m_shouldReportUnexpected) { + makeUnexpectedResultBuilder().useActiveException(); + } + } + m_testCaseTracker->close(); + handleUnfinishedSections(); + m_messages.clear(); + + Counts assertions = m_totals.assertions - prevAssertions; + bool missingAssertions = testForMissingAssertions( assertions ); + + if( testCaseInfo.okToFail() ) { + std::swap( assertions.failedButOk, assertions.failed ); + m_totals.assertions.failed -= assertions.failedButOk; + m_totals.assertions.failedButOk += assertions.failedButOk; + } + + SectionStats testCaseSectionStats( testCaseSection, assertions, duration, missingAssertions ); + m_reporter->sectionEnded( testCaseSectionStats ); + } + + void invokeActiveTestCase() { + FatalConditionHandler fatalConditionHandler; // Handle signals + m_activeTestCase->invoke(); + fatalConditionHandler.reset(); + } + + private: + + ResultBuilder makeUnexpectedResultBuilder() const { + return ResultBuilder( m_lastAssertionInfo.macroName, + m_lastAssertionInfo.lineInfo, + m_lastAssertionInfo.capturedExpression, + m_lastAssertionInfo.resultDisposition ); + } + + void handleUnfinishedSections() { + // If sections ended prematurely due to an exception we stored their + // infos here so we can tear them down outside the unwind process. + for( std::vector::const_reverse_iterator it = m_unfinishedSections.rbegin(), + itEnd = m_unfinishedSections.rend(); + it != itEnd; + ++it ) + sectionEnded( *it ); + m_unfinishedSections.clear(); + } + + TestRunInfo m_runInfo; + IMutableContext& m_context; + TestCase const* m_activeTestCase; + ITracker* m_testCaseTracker; + ITracker* m_currentSectionTracker; + AssertionResult m_lastResult; + + Ptr m_config; + Totals m_totals; + Ptr m_reporter; + std::vector m_messages; + AssertionInfo m_lastAssertionInfo; + std::vector m_unfinishedSections; + std::vector m_activeSections; + TrackerContext m_trackerContext; + size_t m_prevPassed; + bool m_shouldReportUnexpected; + }; + + IResultCapture& getResultCapture() { + if( IResultCapture* capture = getCurrentContext().getResultCapture() ) + return *capture; + else + throw std::logic_error( "No result capture instance" ); + } + +} // end namespace Catch + +// #included from: internal/catch_version.h +#define TWOBLUECUBES_CATCH_VERSION_H_INCLUDED + +namespace Catch { + + // Versioning information + struct Version { + Version( unsigned int _majorVersion, + unsigned int _minorVersion, + unsigned int _patchNumber, + char const * const _branchName, + unsigned int _buildNumber ); + + unsigned int const majorVersion; + unsigned int const minorVersion; + unsigned int const patchNumber; + + // buildNumber is only used if branchName is not null + char const * const branchName; + unsigned int const buildNumber; + + friend std::ostream& operator << ( std::ostream& os, Version const& version ); + + private: + void operator=( Version const& ); + }; + + inline Version libraryVersion(); +} + +#include +#include +#include + +namespace Catch { + + Ptr createReporter( std::string const& reporterName, Ptr const& config ) { + Ptr reporter = getRegistryHub().getReporterRegistry().create( reporterName, config.get() ); + if( !reporter ) { + std::ostringstream oss; + oss << "No reporter registered with name: '" << reporterName << "'"; + throw std::domain_error( oss.str() ); + } + return reporter; + } + +#if !defined(CATCH_CONFIG_DEFAULT_REPORTER) +#define CATCH_CONFIG_DEFAULT_REPORTER "console" +#endif + + Ptr makeReporter( Ptr const& config ) { + std::vector reporters = config->getReporterNames(); + if( reporters.empty() ) + reporters.push_back( CATCH_CONFIG_DEFAULT_REPORTER ); + + Ptr reporter; + for( std::vector::const_iterator it = reporters.begin(), itEnd = reporters.end(); + it != itEnd; + ++it ) + reporter = addReporter( reporter, createReporter( *it, config ) ); + return reporter; + } + Ptr addListeners( Ptr const& config, Ptr reporters ) { + IReporterRegistry::Listeners listeners = getRegistryHub().getReporterRegistry().getListeners(); + for( IReporterRegistry::Listeners::const_iterator it = listeners.begin(), itEnd = listeners.end(); + it != itEnd; + ++it ) + reporters = addReporter(reporters, (*it)->create( ReporterConfig( config ) ) ); + return reporters; + } + + Totals runTests( Ptr const& config ) { + + Ptr iconfig = config.get(); + + Ptr reporter = makeReporter( config ); + reporter = addListeners( iconfig, reporter ); + + RunContext context( iconfig, reporter ); + + Totals totals; + + context.testGroupStarting( config->name(), 1, 1 ); + + TestSpec testSpec = config->testSpec(); + if( !testSpec.hasFilters() ) + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "~[.]" ).testSpec(); // All not hidden tests + + std::vector const& allTestCases = getAllTestCasesSorted( *iconfig ); + for( std::vector::const_iterator it = allTestCases.begin(), itEnd = allTestCases.end(); + it != itEnd; + ++it ) { + if( !context.aborting() && matchTest( *it, testSpec, *iconfig ) ) + totals += context.runTest( *it ); + else + reporter->skipTest( *it ); + } + + context.testGroupEnded( iconfig->name(), totals, 1, 1 ); + return totals; + } + + void applyFilenamesAsTags( IConfig const& config ) { + std::vector const& tests = getAllTestCasesSorted( config ); + for(std::size_t i = 0; i < tests.size(); ++i ) { + TestCase& test = const_cast( tests[i] ); + std::set tags = test.tags; + + std::string filename = test.lineInfo.file; + std::string::size_type lastSlash = filename.find_last_of( "\\/" ); + if( lastSlash != std::string::npos ) + filename = filename.substr( lastSlash+1 ); + + std::string::size_type lastDot = filename.find_last_of( '.' ); + if( lastDot != std::string::npos ) + filename = filename.substr( 0, lastDot ); + + tags.insert( '#' + filename ); + setTags( test, tags ); + } + } + + class Session : NonCopyable { + static bool alreadyInstantiated; + + public: + + struct OnUnusedOptions { enum DoWhat { Ignore, Fail }; }; + + Session() + : m_cli( makeCommandLineParser() ) { + if( alreadyInstantiated ) { + std::string msg = "Only one instance of Catch::Session can ever be used"; + Catch::cerr() << msg << std::endl; + throw std::logic_error( msg ); + } + alreadyInstantiated = true; + } + ~Session() { + Catch::cleanUp(); + } + + void showHelp( std::string const& processName ) { + Catch::cout() << "\nCatch v" << libraryVersion() << "\n"; + + m_cli.usage( Catch::cout(), processName ); + Catch::cout() << "For more detail usage please see the project docs\n" << std::endl; + } + + int applyCommandLine( int argc, char const* const* const argv, OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) { + try { + m_cli.setThrowOnUnrecognisedTokens( unusedOptionBehaviour == OnUnusedOptions::Fail ); + m_unusedTokens = m_cli.parseInto( Clara::argsToVector( argc, argv ), m_configData ); + if( m_configData.showHelp ) + showHelp( m_configData.processName ); + m_config.reset(); + } + catch( std::exception& ex ) { + { + Colour colourGuard( Colour::Red ); + Catch::cerr() + << "\nError(s) in input:\n" + << Text( ex.what(), TextAttributes().setIndent(2) ) + << "\n\n"; + } + m_cli.usage( Catch::cout(), m_configData.processName ); + return (std::numeric_limits::max)(); + } + return 0; + } + + void useConfigData( ConfigData const& _configData ) { + m_configData = _configData; + m_config.reset(); + } + + int run( int argc, char const* const* const argv ) { + + int returnCode = applyCommandLine( argc, argv ); + if( returnCode == 0 ) + returnCode = run(); + return returnCode; + } + + #if defined(WIN32) && defined(UNICODE) + int run( int argc, wchar_t const* const* const argv ) { + + char **utf8Argv = new char *[ argc ]; + + for ( int i = 0; i < argc; ++i ) { + int bufSize = WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, NULL, 0, NULL, NULL ); + + utf8Argv[ i ] = new char[ bufSize ]; + + WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, NULL, NULL ); + } + + int returnCode = applyCommandLine( argc, utf8Argv ); + if( returnCode == 0 ) + returnCode = run(); + + for ( int i = 0; i < argc; ++i ) + delete [] utf8Argv[ i ]; + + delete [] utf8Argv; + + return returnCode; + } + #endif + + int run() { + if( m_configData.showHelp ) + return 0; + + try + { + config(); // Force config to be constructed + + seedRng( *m_config ); + + if( m_configData.filenamesAsTags ) + applyFilenamesAsTags( *m_config ); + + // Handle list request + if( Option listed = list( config() ) ) + return static_cast( *listed ); + + return static_cast( runTests( m_config ).assertions.failed ); + } + catch( std::exception& ex ) { + Catch::cerr() << ex.what() << std::endl; + return (std::numeric_limits::max)(); + } + } + + Clara::CommandLine const& cli() const { + return m_cli; + } + std::vector const& unusedTokens() const { + return m_unusedTokens; + } + ConfigData& configData() { + return m_configData; + } + Config& config() { + if( !m_config ) + m_config = new Config( m_configData ); + return *m_config; + } + private: + Clara::CommandLine m_cli; + std::vector m_unusedTokens; + ConfigData m_configData; + Ptr m_config; + }; + + bool Session::alreadyInstantiated = false; + +} // end namespace Catch + +// #included from: catch_registry_hub.hpp +#define TWOBLUECUBES_CATCH_REGISTRY_HUB_HPP_INCLUDED + +// #included from: catch_test_case_registry_impl.hpp +#define TWOBLUECUBES_CATCH_TEST_CASE_REGISTRY_IMPL_HPP_INCLUDED + +#include +#include +#include +#include + +namespace Catch { + + struct RandomNumberGenerator { + typedef std::ptrdiff_t result_type; + + result_type operator()( result_type n ) const { return std::rand() % n; } + +#ifdef CATCH_CONFIG_CPP11_SHUFFLE + static constexpr result_type min() { return 0; } + static constexpr result_type max() { return 1000000; } + result_type operator()() const { return std::rand() % max(); } +#endif + template + static void shuffle( V& vector ) { + RandomNumberGenerator rng; +#ifdef CATCH_CONFIG_CPP11_SHUFFLE + std::shuffle( vector.begin(), vector.end(), rng ); +#else + std::random_shuffle( vector.begin(), vector.end(), rng ); +#endif + } + }; + + inline std::vector sortTests( IConfig const& config, std::vector const& unsortedTestCases ) { + + std::vector sorted = unsortedTestCases; + + switch( config.runOrder() ) { + case RunTests::InLexicographicalOrder: + std::sort( sorted.begin(), sorted.end() ); + break; + case RunTests::InRandomOrder: + { + seedRng( config ); + RandomNumberGenerator::shuffle( sorted ); + } + break; + case RunTests::InDeclarationOrder: + // already in declaration order + break; + } + return sorted; + } + bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ) { + return testSpec.matches( testCase ) && ( config.allowThrows() || !testCase.throws() ); + } + + void enforceNoDuplicateTestCases( std::vector const& functions ) { + std::set seenFunctions; + for( std::vector::const_iterator it = functions.begin(), itEnd = functions.end(); + it != itEnd; + ++it ) { + std::pair::const_iterator, bool> prev = seenFunctions.insert( *it ); + if( !prev.second ) { + std::ostringstream ss; + + ss << Colour( Colour::Red ) + << "error: TEST_CASE( \"" << it->name << "\" ) already defined.\n" + << "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << '\n' + << "\tRedefined at " << it->getTestCaseInfo().lineInfo << std::endl; + + throw std::runtime_error(ss.str()); + } + } + } + + std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ) { + std::vector filtered; + filtered.reserve( testCases.size() ); + for( std::vector::const_iterator it = testCases.begin(), itEnd = testCases.end(); + it != itEnd; + ++it ) + if( matchTest( *it, testSpec, config ) ) + filtered.push_back( *it ); + return filtered; + } + std::vector const& getAllTestCasesSorted( IConfig const& config ) { + return getRegistryHub().getTestCaseRegistry().getAllTestsSorted( config ); + } + + class TestRegistry : public ITestCaseRegistry { + public: + TestRegistry() + : m_currentSortOrder( RunTests::InDeclarationOrder ), + m_unnamedCount( 0 ) + {} + virtual ~TestRegistry(); + + virtual void registerTest( TestCase const& testCase ) { + std::string name = testCase.getTestCaseInfo().name; + if( name.empty() ) { + std::ostringstream oss; + oss << "Anonymous test case " << ++m_unnamedCount; + return registerTest( testCase.withName( oss.str() ) ); + } + m_functions.push_back( testCase ); + } + + virtual std::vector const& getAllTests() const { + return m_functions; + } + virtual std::vector const& getAllTestsSorted( IConfig const& config ) const { + if( m_sortedFunctions.empty() ) + enforceNoDuplicateTestCases( m_functions ); + + if( m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty() ) { + m_sortedFunctions = sortTests( config, m_functions ); + m_currentSortOrder = config.runOrder(); + } + return m_sortedFunctions; + } + + private: + std::vector m_functions; + mutable RunTests::InWhatOrder m_currentSortOrder; + mutable std::vector m_sortedFunctions; + size_t m_unnamedCount; + std::ios_base::Init m_ostreamInit; // Forces cout/ cerr to be initialised + }; + + /////////////////////////////////////////////////////////////////////////// + + class FreeFunctionTestCase : public SharedImpl { + public: + + FreeFunctionTestCase( TestFunction fun ) : m_fun( fun ) {} + + virtual void invoke() const { + m_fun(); + } + + private: + virtual ~FreeFunctionTestCase(); + + TestFunction m_fun; + }; + + inline std::string extractClassName( std::string const& classOrQualifiedMethodName ) { + std::string className = classOrQualifiedMethodName; + if( startsWith( className, '&' ) ) + { + std::size_t lastColons = className.rfind( "::" ); + std::size_t penultimateColons = className.rfind( "::", lastColons-1 ); + if( penultimateColons == std::string::npos ) + penultimateColons = 1; + className = className.substr( penultimateColons, lastColons-penultimateColons ); + } + return className; + } + + void registerTestCase + ( ITestCase* testCase, + char const* classOrQualifiedMethodName, + NameAndDesc const& nameAndDesc, + SourceLineInfo const& lineInfo ) { + + getMutableRegistryHub().registerTest + ( makeTestCase + ( testCase, + extractClassName( classOrQualifiedMethodName ), + nameAndDesc.name, + nameAndDesc.description, + lineInfo ) ); + } + void registerTestCaseFunction + ( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ) { + registerTestCase( new FreeFunctionTestCase( function ), "", nameAndDesc, lineInfo ); + } + + /////////////////////////////////////////////////////////////////////////// + + AutoReg::AutoReg + ( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ) { + registerTestCaseFunction( function, lineInfo, nameAndDesc ); + } + + AutoReg::~AutoReg() {} + +} // end namespace Catch + +// #included from: catch_reporter_registry.hpp +#define TWOBLUECUBES_CATCH_REPORTER_REGISTRY_HPP_INCLUDED + +#include + +namespace Catch { + + class ReporterRegistry : public IReporterRegistry { + + public: + + virtual ~ReporterRegistry() CATCH_OVERRIDE {} + + virtual IStreamingReporter* create( std::string const& name, Ptr const& config ) const CATCH_OVERRIDE { + FactoryMap::const_iterator it = m_factories.find( name ); + if( it == m_factories.end() ) + return CATCH_NULL; + return it->second->create( ReporterConfig( config ) ); + } + + void registerReporter( std::string const& name, Ptr const& factory ) { + m_factories.insert( std::make_pair( name, factory ) ); + } + void registerListener( Ptr const& factory ) { + m_listeners.push_back( factory ); + } + + virtual FactoryMap const& getFactories() const CATCH_OVERRIDE { + return m_factories; + } + virtual Listeners const& getListeners() const CATCH_OVERRIDE { + return m_listeners; + } + + private: + FactoryMap m_factories; + Listeners m_listeners; + }; +} + +// #included from: catch_exception_translator_registry.hpp +#define TWOBLUECUBES_CATCH_EXCEPTION_TRANSLATOR_REGISTRY_HPP_INCLUDED + +#ifdef __OBJC__ +#import "Foundation/Foundation.h" +#endif + +namespace Catch { + + class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry { + public: + ~ExceptionTranslatorRegistry() { + deleteAll( m_translators ); + } + + virtual void registerTranslator( const IExceptionTranslator* translator ) { + m_translators.push_back( translator ); + } + + virtual std::string translateActiveException() const { + try { +#ifdef __OBJC__ + // In Objective-C try objective-c exceptions first + @try { + return tryTranslators(); + } + @catch (NSException *exception) { + return Catch::toString( [exception description] ); + } +#else + return tryTranslators(); +#endif + } + catch( TestFailureException& ) { + throw; + } + catch( std::exception& ex ) { + return ex.what(); + } + catch( std::string& msg ) { + return msg; + } + catch( const char* msg ) { + return msg; + } + catch(...) { + return "Unknown exception"; + } + } + + std::string tryTranslators() const { + if( m_translators.empty() ) + throw; + else + return m_translators[0]->translate( m_translators.begin()+1, m_translators.end() ); + } + + private: + std::vector m_translators; + }; +} + +// #included from: catch_tag_alias_registry.h +#define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_H_INCLUDED + +#include + +namespace Catch { + + class TagAliasRegistry : public ITagAliasRegistry { + public: + virtual ~TagAliasRegistry(); + virtual Option find( std::string const& alias ) const; + virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const; + void add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ); + + private: + std::map m_registry; + }; + +} // end namespace Catch + +namespace Catch { + + namespace { + + class RegistryHub : public IRegistryHub, public IMutableRegistryHub { + + RegistryHub( RegistryHub const& ); + void operator=( RegistryHub const& ); + + public: // IRegistryHub + RegistryHub() { + } + virtual IReporterRegistry const& getReporterRegistry() const CATCH_OVERRIDE { + return m_reporterRegistry; + } + virtual ITestCaseRegistry const& getTestCaseRegistry() const CATCH_OVERRIDE { + return m_testCaseRegistry; + } + virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() CATCH_OVERRIDE { + return m_exceptionTranslatorRegistry; + } + virtual ITagAliasRegistry const& getTagAliasRegistry() const CATCH_OVERRIDE { + return m_tagAliasRegistry; + } + + public: // IMutableRegistryHub + virtual void registerReporter( std::string const& name, Ptr const& factory ) CATCH_OVERRIDE { + m_reporterRegistry.registerReporter( name, factory ); + } + virtual void registerListener( Ptr const& factory ) CATCH_OVERRIDE { + m_reporterRegistry.registerListener( factory ); + } + virtual void registerTest( TestCase const& testInfo ) CATCH_OVERRIDE { + m_testCaseRegistry.registerTest( testInfo ); + } + virtual void registerTranslator( const IExceptionTranslator* translator ) CATCH_OVERRIDE { + m_exceptionTranslatorRegistry.registerTranslator( translator ); + } + virtual void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) CATCH_OVERRIDE { + m_tagAliasRegistry.add( alias, tag, lineInfo ); + } + + private: + TestRegistry m_testCaseRegistry; + ReporterRegistry m_reporterRegistry; + ExceptionTranslatorRegistry m_exceptionTranslatorRegistry; + TagAliasRegistry m_tagAliasRegistry; + }; + + // Single, global, instance + inline RegistryHub*& getTheRegistryHub() { + static RegistryHub* theRegistryHub = CATCH_NULL; + if( !theRegistryHub ) + theRegistryHub = new RegistryHub(); + return theRegistryHub; + } + } + + IRegistryHub& getRegistryHub() { + return *getTheRegistryHub(); + } + IMutableRegistryHub& getMutableRegistryHub() { + return *getTheRegistryHub(); + } + void cleanUp() { + delete getTheRegistryHub(); + getTheRegistryHub() = CATCH_NULL; + cleanUpContext(); + } + std::string translateActiveException() { + return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException(); + } + +} // end namespace Catch + +// #included from: catch_notimplemented_exception.hpp +#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_HPP_INCLUDED + +#include + +namespace Catch { + + NotImplementedException::NotImplementedException( SourceLineInfo const& lineInfo ) + : m_lineInfo( lineInfo ) { + std::ostringstream oss; + oss << lineInfo << ": function "; + oss << "not implemented"; + m_what = oss.str(); + } + + const char* NotImplementedException::what() const CATCH_NOEXCEPT { + return m_what.c_str(); + } + +} // end namespace Catch + +// #included from: catch_context_impl.hpp +#define TWOBLUECUBES_CATCH_CONTEXT_IMPL_HPP_INCLUDED + +// #included from: catch_stream.hpp +#define TWOBLUECUBES_CATCH_STREAM_HPP_INCLUDED + +#include +#include +#include + +namespace Catch { + + template + class StreamBufImpl : public StreamBufBase { + char data[bufferSize]; + WriterF m_writer; + + public: + StreamBufImpl() { + setp( data, data + sizeof(data) ); + } + + ~StreamBufImpl() CATCH_NOEXCEPT { + sync(); + } + + private: + int overflow( int c ) { + sync(); + + if( c != EOF ) { + if( pbase() == epptr() ) + m_writer( std::string( 1, static_cast( c ) ) ); + else + sputc( static_cast( c ) ); + } + return 0; + } + + int sync() { + if( pbase() != pptr() ) { + m_writer( std::string( pbase(), static_cast( pptr() - pbase() ) ) ); + setp( pbase(), epptr() ); + } + return 0; + } + }; + + /////////////////////////////////////////////////////////////////////////// + + FileStream::FileStream( std::string const& filename ) { + m_ofs.open( filename.c_str() ); + if( m_ofs.fail() ) { + std::ostringstream oss; + oss << "Unable to open file: '" << filename << '\''; + throw std::domain_error( oss.str() ); + } + } + + std::ostream& FileStream::stream() const { + return m_ofs; + } + + struct OutputDebugWriter { + + void operator()( std::string const&str ) { + writeToDebugConsole( str ); + } + }; + + DebugOutStream::DebugOutStream() + : m_streamBuf( new StreamBufImpl() ), + m_os( m_streamBuf.get() ) + {} + + std::ostream& DebugOutStream::stream() const { + return m_os; + } + + // Store the streambuf from cout up-front because + // cout may get redirected when running tests + CoutStream::CoutStream() + : m_os( Catch::cout().rdbuf() ) + {} + + std::ostream& CoutStream::stream() const { + return m_os; + } + +#ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement these functions + std::ostream& cout() { + return std::cout; + } + std::ostream& cerr() { + return std::cerr; + } + std::ostream& clog() { + return std::clog; + } +#endif +} + +namespace Catch { + + class Context : public IMutableContext { + + Context() : m_config( CATCH_NULL ), m_runner( CATCH_NULL ), m_resultCapture( CATCH_NULL ) {} + Context( Context const& ); + void operator=( Context const& ); + + public: + virtual ~Context() { + deleteAllValues( m_generatorsByTestName ); + } + + public: // IContext + virtual IResultCapture* getResultCapture() { + return m_resultCapture; + } + virtual IRunner* getRunner() { + return m_runner; + } + virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) { + return getGeneratorsForCurrentTest() + .getGeneratorInfo( fileInfo, totalSize ) + .getCurrentIndex(); + } + virtual bool advanceGeneratorsForCurrentTest() { + IGeneratorsForTest* generators = findGeneratorsForCurrentTest(); + return generators && generators->moveNext(); + } + + virtual Ptr getConfig() const { + return m_config; + } + + public: // IMutableContext + virtual void setResultCapture( IResultCapture* resultCapture ) { + m_resultCapture = resultCapture; + } + virtual void setRunner( IRunner* runner ) { + m_runner = runner; + } + virtual void setConfig( Ptr const& config ) { + m_config = config; + } + + friend IMutableContext& getCurrentMutableContext(); + + private: + IGeneratorsForTest* findGeneratorsForCurrentTest() { + std::string testName = getResultCapture()->getCurrentTestName(); + + std::map::const_iterator it = + m_generatorsByTestName.find( testName ); + return it != m_generatorsByTestName.end() + ? it->second + : CATCH_NULL; + } + + IGeneratorsForTest& getGeneratorsForCurrentTest() { + IGeneratorsForTest* generators = findGeneratorsForCurrentTest(); + if( !generators ) { + std::string testName = getResultCapture()->getCurrentTestName(); + generators = createGeneratorsForTest(); + m_generatorsByTestName.insert( std::make_pair( testName, generators ) ); + } + return *generators; + } + + private: + Ptr m_config; + IRunner* m_runner; + IResultCapture* m_resultCapture; + std::map m_generatorsByTestName; + }; + + namespace { + Context* currentContext = CATCH_NULL; + } + IMutableContext& getCurrentMutableContext() { + if( !currentContext ) + currentContext = new Context(); + return *currentContext; + } + IContext& getCurrentContext() { + return getCurrentMutableContext(); + } + + void cleanUpContext() { + delete currentContext; + currentContext = CATCH_NULL; + } +} + +// #included from: catch_console_colour_impl.hpp +#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_IMPL_HPP_INCLUDED + +// #included from: catch_errno_guard.hpp +#define TWOBLUECUBES_CATCH_ERRNO_GUARD_HPP_INCLUDED + +#include + +namespace Catch { + + class ErrnoGuard { + public: + ErrnoGuard():m_oldErrno(errno){} + ~ErrnoGuard() { errno = m_oldErrno; } + private: + int m_oldErrno; + }; + +} + namespace Catch { namespace { struct IColourImpl { - virtual ~IColourImpl() = default; + virtual ~IColourImpl() {} virtual void use( Colour::Code _colourCode ) = 0; }; @@ -5962,7 +7884,7 @@ namespace { originalBackgroundAttributes = csbiInfo.wAttributes & ~( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY ); } - virtual void use( Colour::Code _colourCode ) override { + virtual void use( Colour::Code _colourCode ) { switch( _colourCode ) { case Colour::None: return setTextAttribute( originalForegroundAttributes ); case Colour::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); @@ -5978,7 +7900,7 @@ namespace { case Colour::BrightGreen: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN ); case Colour::BrightWhite: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); - case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" ); + case Colour::Bright: throw std::logic_error( "not a colour" ); } } @@ -5994,12 +7916,14 @@ namespace { IColourImpl* platformColourInstance() { static Win32ColourImpl s_instance; - IConfigPtr config = getCurrentContext().getConfig(); + Ptr config = getCurrentContext().getConfig(); UseColour::YesOrNo colourMode = config ? config->useColour() : UseColour::Auto; if( colourMode == UseColour::Auto ) - colourMode = UseColour::Yes; + colourMode = !isDebuggerActive() + ? UseColour::Yes + : UseColour::No; return colourMode == UseColour::Yes ? &s_instance : NoColourImpl::instance(); @@ -6021,7 +7945,7 @@ namespace { // https://github.com/philsquared/Catch/pull/131 class PosixColourImpl : public IColourImpl { public: - virtual void use( Colour::Code _colourCode ) override { + virtual void use( Colour::Code _colourCode ) { switch( _colourCode ) { case Colour::None: case Colour::White: return setColour( "[0m" ); @@ -6037,7 +7961,7 @@ namespace { case Colour::BrightGreen: return setColour( "[1;32m" ); case Colour::BrightWhite: return setColour( "[1;37m" ); - case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" ); + case Colour::Bright: throw std::logic_error( "not a colour" ); } } static IColourImpl* instance() { @@ -6051,21 +7975,14 @@ namespace { } }; - bool useColourOnPlatform() { - return -#ifdef CATCH_PLATFORM_MAC - !isDebuggerActive() && -#endif - isatty(STDOUT_FILENO); - } IColourImpl* platformColourInstance() { ErrnoGuard guard; - IConfigPtr config = getCurrentContext().getConfig(); + Ptr config = getCurrentContext().getConfig(); UseColour::YesOrNo colourMode = config ? config->useColour() : UseColour::Auto; if( colourMode == UseColour::Auto ) - colourMode = useColourOnPlatform() + colourMode = (!isDebuggerActive() && isatty(STDOUT_FILENO) ) ? UseColour::Yes : UseColour::No; return colourMode == UseColour::Yes @@ -6088,17 +8005,8 @@ namespace Catch { namespace Catch { - Colour::Colour( Code _colourCode ) { use( _colourCode ); } - Colour::Colour( Colour&& rhs ) noexcept { - m_moved = rhs.m_moved; - rhs.m_moved = true; - } - Colour& Colour::operator=( Colour&& rhs ) noexcept { - m_moved = rhs.m_moved; - rhs.m_moved = true; - return *this; - } - + Colour::Colour( Code _colourCode ) : m_moved( false ) { use( _colourCode ); } + Colour::Colour( Colour const& _other ) : m_moved( false ) { const_cast( _other ).m_moved = true; } Colour::~Colour(){ if( !m_moved ) use( None ); } void Colour::use( Code _colourCode ) { @@ -6106,105 +8014,776 @@ namespace Catch { impl->use( _colourCode ); } - std::ostream& operator << ( std::ostream& os, Colour const& ) { - return os; +} // end namespace Catch + +// #included from: catch_generators_impl.hpp +#define TWOBLUECUBES_CATCH_GENERATORS_IMPL_HPP_INCLUDED + +#include +#include +#include + +namespace Catch { + + struct GeneratorInfo : IGeneratorInfo { + + GeneratorInfo( std::size_t size ) + : m_size( size ), + m_currentIndex( 0 ) + {} + + bool moveNext() { + if( ++m_currentIndex == m_size ) { + m_currentIndex = 0; + return false; + } + return true; + } + + std::size_t getCurrentIndex() const { + return m_currentIndex; + } + + std::size_t m_size; + std::size_t m_currentIndex; + }; + + /////////////////////////////////////////////////////////////////////////// + + class GeneratorsForTest : public IGeneratorsForTest { + + public: + ~GeneratorsForTest() { + deleteAll( m_generatorsInOrder ); + } + + IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) { + std::map::const_iterator it = m_generatorsByName.find( fileInfo ); + if( it == m_generatorsByName.end() ) { + IGeneratorInfo* info = new GeneratorInfo( size ); + m_generatorsByName.insert( std::make_pair( fileInfo, info ) ); + m_generatorsInOrder.push_back( info ); + return *info; + } + return *it->second; + } + + bool moveNext() { + std::vector::const_iterator it = m_generatorsInOrder.begin(); + std::vector::const_iterator itEnd = m_generatorsInOrder.end(); + for(; it != itEnd; ++it ) { + if( (*it)->moveNext() ) + return true; + } + return false; + } + + private: + std::map m_generatorsByName; + std::vector m_generatorsInOrder; + }; + + IGeneratorsForTest* createGeneratorsForTest() + { + return new GeneratorsForTest(); } } // end namespace Catch -#if defined(__clang__) -# pragma clang diagnostic pop -#endif - -// end catch_console_colour.cpp -// start catch_context.cpp +// #included from: catch_assertionresult.hpp +#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_HPP_INCLUDED namespace Catch { - class Context : public IMutableContext, NonCopyable { + AssertionInfo::AssertionInfo():macroName(""), capturedExpression(""), resultDisposition(ResultDisposition::Normal), secondArg(""){} - public: // IContext - virtual IResultCapture* getResultCapture() override { - return m_resultCapture; + AssertionInfo::AssertionInfo( char const * _macroName, + SourceLineInfo const& _lineInfo, + char const * _capturedExpression, + ResultDisposition::Flags _resultDisposition, + char const * _secondArg) + : macroName( _macroName ), + lineInfo( _lineInfo ), + capturedExpression( _capturedExpression ), + resultDisposition( _resultDisposition ), + secondArg( _secondArg ) + {} + + AssertionResult::AssertionResult() {} + + AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data ) + : m_info( info ), + m_resultData( data ) + {} + + AssertionResult::~AssertionResult() {} + + // Result was a success + bool AssertionResult::succeeded() const { + return Catch::isOk( m_resultData.resultType ); + } + + // Result was a success, or failure is suppressed + bool AssertionResult::isOk() const { + return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition ); + } + + ResultWas::OfType AssertionResult::getResultType() const { + return m_resultData.resultType; + } + + bool AssertionResult::hasExpression() const { + return m_info.capturedExpression[0] != 0; + } + + bool AssertionResult::hasMessage() const { + return !m_resultData.message.empty(); + } + + std::string capturedExpressionWithSecondArgument( char const * capturedExpression, char const * secondArg ) { + return (secondArg[0] == 0 || secondArg[0] == '"' && secondArg[1] == '"') + ? capturedExpression + : std::string(capturedExpression) + ", " + secondArg; + } + + std::string AssertionResult::getExpression() const { + if( isFalseTest( m_info.resultDisposition ) ) + return '!' + capturedExpressionWithSecondArgument(m_info.capturedExpression, m_info.secondArg); + else + return capturedExpressionWithSecondArgument(m_info.capturedExpression, m_info.secondArg); + } + std::string AssertionResult::getExpressionInMacro() const { + if( m_info.macroName[0] == 0 ) + return capturedExpressionWithSecondArgument(m_info.capturedExpression, m_info.secondArg); + else + return std::string(m_info.macroName) + "( " + capturedExpressionWithSecondArgument(m_info.capturedExpression, m_info.secondArg) + " )"; + } + + bool AssertionResult::hasExpandedExpression() const { + return hasExpression() && getExpandedExpression() != getExpression(); + } + + std::string AssertionResult::getExpandedExpression() const { + return m_resultData.reconstructExpression(); + } + + std::string AssertionResult::getMessage() const { + return m_resultData.message; + } + SourceLineInfo AssertionResult::getSourceInfo() const { + return m_info.lineInfo; + } + + std::string AssertionResult::getTestMacroName() const { + return m_info.macroName; + } + + void AssertionResult::discardDecomposedExpression() const { + m_resultData.decomposedExpression = CATCH_NULL; + } + + void AssertionResult::expandDecomposedExpression() const { + m_resultData.reconstructExpression(); + } + +} // end namespace Catch + +// #included from: catch_test_case_info.hpp +#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_HPP_INCLUDED + +#include + +namespace Catch { + + inline TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) { + if( startsWith( tag, '.' ) || + tag == "hide" || + tag == "!hide" ) + return TestCaseInfo::IsHidden; + else if( tag == "!throws" ) + return TestCaseInfo::Throws; + else if( tag == "!shouldfail" ) + return TestCaseInfo::ShouldFail; + else if( tag == "!mayfail" ) + return TestCaseInfo::MayFail; + else if( tag == "!nonportable" ) + return TestCaseInfo::NonPortable; + else + return TestCaseInfo::None; + } + inline bool isReservedTag( std::string const& tag ) { + return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !std::isalnum( tag[0] ); + } + inline void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) { + if( isReservedTag( tag ) ) { + std::ostringstream ss; + ss << Colour(Colour::Red) + << "Tag name [" << tag << "] not allowed.\n" + << "Tag names starting with non alpha-numeric characters are reserved\n" + << Colour(Colour::FileName) + << _lineInfo << '\n'; + throw std::runtime_error(ss.str()); } - virtual IRunner* getRunner() override { - return m_runner; + } + + TestCase makeTestCase( ITestCase* _testCase, + std::string const& _className, + std::string const& _name, + std::string const& _descOrTags, + SourceLineInfo const& _lineInfo ) + { + bool isHidden( startsWith( _name, "./" ) ); // Legacy support + + // Parse out tags + std::set tags; + std::string desc, tag; + bool inTag = false; + for( std::size_t i = 0; i < _descOrTags.size(); ++i ) { + char c = _descOrTags[i]; + if( !inTag ) { + if( c == '[' ) + inTag = true; + else + desc += c; + } + else { + if( c == ']' ) { + TestCaseInfo::SpecialProperties prop = parseSpecialTag( tag ); + if( prop == TestCaseInfo::IsHidden ) + isHidden = true; + else if( prop == TestCaseInfo::None ) + enforceNotReservedTag( tag, _lineInfo ); + + tags.insert( tag ); + tag.clear(); + inTag = false; + } + else + tag += c; + } + } + if( isHidden ) { + tags.insert( "hide" ); + tags.insert( "." ); } - virtual IConfigPtr getConfig() const override { - return m_config; - } + TestCaseInfo info( _name, _className, desc, tags, _lineInfo ); + return TestCase( _testCase, info ); + } - virtual ~Context() override; + void setTags( TestCaseInfo& testCaseInfo, std::set const& tags ) + { + testCaseInfo.tags = tags; + testCaseInfo.lcaseTags.clear(); - public: // IMutableContext - virtual void setResultCapture( IResultCapture* resultCapture ) override { - m_resultCapture = resultCapture; - } - virtual void setRunner( IRunner* runner ) override { - m_runner = runner; - } - virtual void setConfig( IConfigPtr const& config ) override { - m_config = config; + std::ostringstream oss; + for( std::set::const_iterator it = tags.begin(), itEnd = tags.end(); it != itEnd; ++it ) { + oss << '[' << *it << ']'; + std::string lcaseTag = toLower( *it ); + testCaseInfo.properties = static_cast( testCaseInfo.properties | parseSpecialTag( lcaseTag ) ); + testCaseInfo.lcaseTags.insert( lcaseTag ); } + testCaseInfo.tagsAsString = oss.str(); + } - friend IMutableContext& getCurrentMutableContext(); + TestCaseInfo::TestCaseInfo( std::string const& _name, + std::string const& _className, + std::string const& _description, + std::set const& _tags, + SourceLineInfo const& _lineInfo ) + : name( _name ), + className( _className ), + description( _description ), + lineInfo( _lineInfo ), + properties( None ) + { + setTags( *this, _tags ); + } - private: - IConfigPtr m_config; - IRunner* m_runner = nullptr; - IResultCapture* m_resultCapture = nullptr; + TestCaseInfo::TestCaseInfo( TestCaseInfo const& other ) + : name( other.name ), + className( other.className ), + description( other.description ), + tags( other.tags ), + lcaseTags( other.lcaseTags ), + tagsAsString( other.tagsAsString ), + lineInfo( other.lineInfo ), + properties( other.properties ) + {} + + bool TestCaseInfo::isHidden() const { + return ( properties & IsHidden ) != 0; + } + bool TestCaseInfo::throws() const { + return ( properties & Throws ) != 0; + } + bool TestCaseInfo::okToFail() const { + return ( properties & (ShouldFail | MayFail ) ) != 0; + } + bool TestCaseInfo::expectedToFail() const { + return ( properties & (ShouldFail ) ) != 0; + } + + TestCase::TestCase( ITestCase* testCase, TestCaseInfo const& info ) : TestCaseInfo( info ), test( testCase ) {} + + TestCase::TestCase( TestCase const& other ) + : TestCaseInfo( other ), + test( other.test ) + {} + + TestCase TestCase::withName( std::string const& _newName ) const { + TestCase other( *this ); + other.name = _newName; + return other; + } + + void TestCase::swap( TestCase& other ) { + test.swap( other.test ); + name.swap( other.name ); + className.swap( other.className ); + description.swap( other.description ); + tags.swap( other.tags ); + lcaseTags.swap( other.lcaseTags ); + tagsAsString.swap( other.tagsAsString ); + std::swap( TestCaseInfo::properties, static_cast( other ).properties ); + std::swap( lineInfo, other.lineInfo ); + } + + void TestCase::invoke() const { + test->invoke(); + } + + bool TestCase::operator == ( TestCase const& other ) const { + return test.get() == other.test.get() && + name == other.name && + className == other.className; + } + + bool TestCase::operator < ( TestCase const& other ) const { + return name < other.name; + } + TestCase& TestCase::operator = ( TestCase const& other ) { + TestCase temp( other ); + swap( temp ); + return *this; + } + + TestCaseInfo const& TestCase::getTestCaseInfo() const + { + return *this; + } + +} // end namespace Catch + +// #included from: catch_version.hpp +#define TWOBLUECUBES_CATCH_VERSION_HPP_INCLUDED + +namespace Catch { + + Version::Version + ( unsigned int _majorVersion, + unsigned int _minorVersion, + unsigned int _patchNumber, + char const * const _branchName, + unsigned int _buildNumber ) + : majorVersion( _majorVersion ), + minorVersion( _minorVersion ), + patchNumber( _patchNumber ), + branchName( _branchName ), + buildNumber( _buildNumber ) + {} + + std::ostream& operator << ( std::ostream& os, Version const& version ) { + os << version.majorVersion << '.' + << version.minorVersion << '.' + << version.patchNumber; + // branchName is never null -> 0th char is \0 if it is empty + if (version.branchName[0]) { + os << '-' << version.branchName + << '.' << version.buildNumber; + } + return os; + } + + inline Version libraryVersion() { + static Version version( 1, 9, 7, "", 0 ); + return version; + } + +} + +// #included from: catch_message.hpp +#define TWOBLUECUBES_CATCH_MESSAGE_HPP_INCLUDED + +namespace Catch { + + MessageInfo::MessageInfo( std::string const& _macroName, + SourceLineInfo const& _lineInfo, + ResultWas::OfType _type ) + : macroName( _macroName ), + lineInfo( _lineInfo ), + type( _type ), + sequence( ++globalCount ) + {} + + // This may need protecting if threading support is added + unsigned int MessageInfo::globalCount = 0; + + //////////////////////////////////////////////////////////////////////////// + + ScopedMessage::ScopedMessage( MessageBuilder const& builder ) + : m_info( builder.m_info ) + { + m_info.message = builder.m_stream.str(); + getResultCapture().pushScopedMessage( m_info ); + } + ScopedMessage::ScopedMessage( ScopedMessage const& other ) + : m_info( other.m_info ) + {} + + ScopedMessage::~ScopedMessage() { + if ( !std::uncaught_exception() ){ + getResultCapture().popScopedMessage(m_info); + } + } + +} // end namespace Catch + +// #included from: catch_legacy_reporter_adapter.hpp +#define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_HPP_INCLUDED + +// #included from: catch_legacy_reporter_adapter.h +#define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_H_INCLUDED + +namespace Catch +{ + // Deprecated + struct IReporter : IShared { + virtual ~IReporter(); + + virtual bool shouldRedirectStdout() const = 0; + + virtual void StartTesting() = 0; + virtual void EndTesting( Totals const& totals ) = 0; + virtual void StartGroup( std::string const& groupName ) = 0; + virtual void EndGroup( std::string const& groupName, Totals const& totals ) = 0; + virtual void StartTestCase( TestCaseInfo const& testInfo ) = 0; + virtual void EndTestCase( TestCaseInfo const& testInfo, Totals const& totals, std::string const& stdOut, std::string const& stdErr ) = 0; + virtual void StartSection( std::string const& sectionName, std::string const& description ) = 0; + virtual void EndSection( std::string const& sectionName, Counts const& assertions ) = 0; + virtual void NoAssertionsInSection( std::string const& sectionName ) = 0; + virtual void NoAssertionsInTestCase( std::string const& testName ) = 0; + virtual void Aborted() = 0; + virtual void Result( AssertionResult const& result ) = 0; }; - namespace { - Context* currentContext = nullptr; - } - IMutableContext& getCurrentMutableContext() { - if( !currentContext ) - currentContext = new Context(); - return *currentContext; - } - IContext& getCurrentContext() { - return getCurrentMutableContext(); - } + class LegacyReporterAdapter : public SharedImpl + { + public: + LegacyReporterAdapter( Ptr const& legacyReporter ); + virtual ~LegacyReporterAdapter(); - void cleanUpContext() { - delete currentContext; - currentContext = nullptr; - } - IContext::~IContext() = default; - IMutableContext::~IMutableContext() = default; - Context::~Context() = default; -} -// end catch_context.cpp -// start catch_debug_console.cpp + virtual ReporterPreferences getPreferences() const; + virtual void noMatchingTestCases( std::string const& ); + virtual void testRunStarting( TestRunInfo const& ); + virtual void testGroupStarting( GroupInfo const& groupInfo ); + virtual void testCaseStarting( TestCaseInfo const& testInfo ); + virtual void sectionStarting( SectionInfo const& sectionInfo ); + virtual void assertionStarting( AssertionInfo const& ); + virtual bool assertionEnded( AssertionStats const& assertionStats ); + virtual void sectionEnded( SectionStats const& sectionStats ); + virtual void testCaseEnded( TestCaseStats const& testCaseStats ); + virtual void testGroupEnded( TestGroupStats const& testGroupStats ); + virtual void testRunEnded( TestRunStats const& testRunStats ); + virtual void skipTest( TestCaseInfo const& ); -// start catch_debug_console.h - -#include - -namespace Catch { - void writeToDebugConsole( std::string const& text ); + private: + Ptr m_legacyReporter; + }; } -// end catch_debug_console.h +namespace Catch +{ + LegacyReporterAdapter::LegacyReporterAdapter( Ptr const& legacyReporter ) + : m_legacyReporter( legacyReporter ) + {} + LegacyReporterAdapter::~LegacyReporterAdapter() {} + + ReporterPreferences LegacyReporterAdapter::getPreferences() const { + ReporterPreferences prefs; + prefs.shouldRedirectStdOut = m_legacyReporter->shouldRedirectStdout(); + return prefs; + } + + void LegacyReporterAdapter::noMatchingTestCases( std::string const& ) {} + void LegacyReporterAdapter::testRunStarting( TestRunInfo const& ) { + m_legacyReporter->StartTesting(); + } + void LegacyReporterAdapter::testGroupStarting( GroupInfo const& groupInfo ) { + m_legacyReporter->StartGroup( groupInfo.name ); + } + void LegacyReporterAdapter::testCaseStarting( TestCaseInfo const& testInfo ) { + m_legacyReporter->StartTestCase( testInfo ); + } + void LegacyReporterAdapter::sectionStarting( SectionInfo const& sectionInfo ) { + m_legacyReporter->StartSection( sectionInfo.name, sectionInfo.description ); + } + void LegacyReporterAdapter::assertionStarting( AssertionInfo const& ) { + // Not on legacy interface + } + + bool LegacyReporterAdapter::assertionEnded( AssertionStats const& assertionStats ) { + if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) { + for( std::vector::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end(); + it != itEnd; + ++it ) { + if( it->type == ResultWas::Info ) { + ResultBuilder rb( it->macroName.c_str(), it->lineInfo, "", ResultDisposition::Normal ); + rb << it->message; + rb.setResultType( ResultWas::Info ); + AssertionResult result = rb.build(); + m_legacyReporter->Result( result ); + } + } + } + m_legacyReporter->Result( assertionStats.assertionResult ); + return true; + } + void LegacyReporterAdapter::sectionEnded( SectionStats const& sectionStats ) { + if( sectionStats.missingAssertions ) + m_legacyReporter->NoAssertionsInSection( sectionStats.sectionInfo.name ); + m_legacyReporter->EndSection( sectionStats.sectionInfo.name, sectionStats.assertions ); + } + void LegacyReporterAdapter::testCaseEnded( TestCaseStats const& testCaseStats ) { + m_legacyReporter->EndTestCase + ( testCaseStats.testInfo, + testCaseStats.totals, + testCaseStats.stdOut, + testCaseStats.stdErr ); + } + void LegacyReporterAdapter::testGroupEnded( TestGroupStats const& testGroupStats ) { + if( testGroupStats.aborting ) + m_legacyReporter->Aborted(); + m_legacyReporter->EndGroup( testGroupStats.groupInfo.name, testGroupStats.totals ); + } + void LegacyReporterAdapter::testRunEnded( TestRunStats const& testRunStats ) { + m_legacyReporter->EndTesting( testRunStats.totals ); + } + void LegacyReporterAdapter::skipTest( TestCaseInfo const& ) { + } +} + +// #included from: catch_timer.hpp + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wc++11-long-long" +#endif + #ifdef CATCH_PLATFORM_WINDOWS - namespace Catch { - void writeToDebugConsole( std::string const& text ) { - ::OutputDebugStringA( text.c_str() ); - } - } #else - namespace Catch { - void writeToDebugConsole( std::string const& text ) { - // !TBD: Need a version for Mac/ XCode and other IDEs - Catch::cout() << text; + +#include + +#endif + +namespace Catch { + + namespace { +#ifdef CATCH_PLATFORM_WINDOWS + UInt64 getCurrentTicks() { + static UInt64 hz=0, hzo=0; + if (!hz) { + QueryPerformanceFrequency( reinterpret_cast( &hz ) ); + QueryPerformanceCounter( reinterpret_cast( &hzo ) ); + } + UInt64 t; + QueryPerformanceCounter( reinterpret_cast( &t ) ); + return ((t-hzo)*1000000)/hz; + } +#else + UInt64 getCurrentTicks() { + timeval t; + gettimeofday(&t,CATCH_NULL); + return static_cast( t.tv_sec ) * 1000000ull + static_cast( t.tv_usec ); + } +#endif + } + + void Timer::start() { + m_ticks = getCurrentTicks(); + } + unsigned int Timer::getElapsedMicroseconds() const { + return static_cast(getCurrentTicks() - m_ticks); + } + unsigned int Timer::getElapsedMilliseconds() const { + return static_cast(getElapsedMicroseconds()/1000); + } + double Timer::getElapsedSeconds() const { + return getElapsedMicroseconds()/1000000.0; + } + +} // namespace Catch + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif +// #included from: catch_common.hpp +#define TWOBLUECUBES_CATCH_COMMON_HPP_INCLUDED + +#include +#include + +namespace Catch { + + bool startsWith( std::string const& s, std::string const& prefix ) { + return s.size() >= prefix.size() && std::equal(prefix.begin(), prefix.end(), s.begin()); + } + bool startsWith( std::string const& s, char prefix ) { + return !s.empty() && s[0] == prefix; + } + bool endsWith( std::string const& s, std::string const& suffix ) { + return s.size() >= suffix.size() && std::equal(suffix.rbegin(), suffix.rend(), s.rbegin()); + } + bool endsWith( std::string const& s, char suffix ) { + return !s.empty() && s[s.size()-1] == suffix; + } + bool contains( std::string const& s, std::string const& infix ) { + return s.find( infix ) != std::string::npos; + } + char toLowerCh(char c) { + return static_cast( std::tolower( c ) ); + } + void toLowerInPlace( std::string& s ) { + std::transform( s.begin(), s.end(), s.begin(), toLowerCh ); + } + std::string toLower( std::string const& s ) { + std::string lc = s; + toLowerInPlace( lc ); + return lc; + } + std::string trim( std::string const& str ) { + static char const* whitespaceChars = "\n\r\t "; + std::string::size_type start = str.find_first_not_of( whitespaceChars ); + std::string::size_type end = str.find_last_not_of( whitespaceChars ); + + return start != std::string::npos ? str.substr( start, 1+end-start ) : std::string(); + } + + bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) { + bool replaced = false; + std::size_t i = str.find( replaceThis ); + while( i != std::string::npos ) { + replaced = true; + str = str.substr( 0, i ) + withThis + str.substr( i+replaceThis.size() ); + if( i < str.size()-withThis.size() ) + i = str.find( replaceThis, i+withThis.size() ); + else + i = std::string::npos; + } + return replaced; + } + + pluralise::pluralise( std::size_t count, std::string const& label ) + : m_count( count ), + m_label( label ) + {} + + std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) { + os << pluraliser.m_count << ' ' << pluraliser.m_label; + if( pluraliser.m_count != 1 ) + os << 's'; + return os; + } + + SourceLineInfo::SourceLineInfo() : file(""), line( 0 ){} + SourceLineInfo::SourceLineInfo( char const* _file, std::size_t _line ) + : file( _file ), + line( _line ) + {} + bool SourceLineInfo::empty() const { + return file[0] == '\0'; + } + bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const { + return line == other.line && (file == other.file || std::strcmp(file, other.file) == 0); + } + bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const { + return line < other.line || ( line == other.line && (std::strcmp(file, other.file) < 0)); + } + + void seedRng( IConfig const& config ) { + if( config.rngSeed() != 0 ) + std::srand( config.rngSeed() ); + } + unsigned int rngSeed() { + return getCurrentContext().getConfig()->rngSeed(); + } + + std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) { +#ifndef __GNUG__ + os << info.file << '(' << info.line << ')'; +#else + os << info.file << ':' << info.line; +#endif + return os; + } + + void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ) { + std::ostringstream oss; + oss << locationInfo << ": Internal Catch error: '" << message << '\''; + if( alwaysTrue() ) + throw std::logic_error( oss.str() ); + } +} + +// #included from: catch_section.hpp +#define TWOBLUECUBES_CATCH_SECTION_HPP_INCLUDED + +namespace Catch { + + SectionInfo::SectionInfo + ( SourceLineInfo const& _lineInfo, + std::string const& _name, + std::string const& _description ) + : name( _name ), + description( _description ), + lineInfo( _lineInfo ) + {} + + Section::Section( SectionInfo const& info ) + : m_info( info ), + m_sectionIncluded( getResultCapture().sectionStarted( m_info, m_assertions ) ) + { + m_timer.start(); + } + +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable:4996) // std::uncaught_exception is deprecated in C++17 +#endif + Section::~Section() { + if( m_sectionIncluded ) { + SectionEndInfo endInfo( m_info, m_assertions, m_timer.getElapsedSeconds() ); + if( std::uncaught_exception() ) + getResultCapture().sectionEndedEarly( endInfo ); + else + getResultCapture().sectionEnded( endInfo ); } } -#endif // Platform -// end catch_debug_console.cpp -// start catch_debugger.cpp +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + + // This indicates whether the section should be executed or not + Section::operator bool() const { + return m_sectionIncluded; + } + +} // end namespace Catch + +// #included from: catch_debugger.hpp +#define TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED #ifdef CATCH_PLATFORM_MAC @@ -6214,7 +8793,7 @@ namespace Catch { #include #include - namespace Catch { + namespace Catch{ // The following function is taken directly from the following technical note: // http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html @@ -6225,7 +8804,7 @@ namespace Catch { int mib[4]; struct kinfo_proc info; - std::size_t size; + size_t size; // Initialize the flags so that, if sysctl fails for some bizarre // reason, we get a predictable result. @@ -6243,7 +8822,7 @@ namespace Catch { // Call sysctl. size = sizeof(info); - if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, nullptr, 0) != 0 ) { + if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, CATCH_NULL, 0) != 0 ) { Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl; return false; } @@ -6300,778 +8879,449 @@ namespace Catch { } #else namespace Catch { - bool isDebuggerActive() { return false; } + inline bool isDebuggerActive() { return false; } } #endif // Platform -// end catch_debugger.cpp -// start catch_decomposer.cpp -namespace Catch { +#ifdef CATCH_PLATFORM_WINDOWS - ITransientExpression::~ITransientExpression() = default; - - void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs ) { - if( lhs.size() + rhs.size() < 40 && - lhs.find('\n') == std::string::npos && - rhs.find('\n') == std::string::npos ) - os << lhs << " " << op << " " << rhs; - else - os << lhs << "\n" << op << "\n" << rhs; + namespace Catch { + void writeToDebugConsole( std::string const& text ) { + ::OutputDebugStringA( text.c_str() ); + } } -} -// end catch_decomposer.cpp -// start catch_errno_guard.cpp - -#include - -namespace Catch { - ErrnoGuard::ErrnoGuard():m_oldErrno(errno){} - ErrnoGuard::~ErrnoGuard() { errno = m_oldErrno; } -} -// end catch_errno_guard.cpp -// start catch_exception_translator_registry.cpp - -// start catch_exception_translator_registry.h - -#include -#include -#include - -namespace Catch { - - class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry { - public: - ~ExceptionTranslatorRegistry(); - virtual void registerTranslator( const IExceptionTranslator* translator ); - virtual std::string translateActiveException() const override; - std::string tryTranslators() const; - - private: - std::vector> m_translators; - }; -} - -// end catch_exception_translator_registry.h -#ifdef __OBJC__ -#import "Foundation/Foundation.h" -#endif - -namespace Catch { - - ExceptionTranslatorRegistry::~ExceptionTranslatorRegistry() { - } - - void ExceptionTranslatorRegistry::registerTranslator( const IExceptionTranslator* translator ) { - m_translators.push_back( std::unique_ptr( translator ) ); - } - - std::string ExceptionTranslatorRegistry::translateActiveException() const { - try { -#ifdef __OBJC__ - // In Objective-C try objective-c exceptions first - @try { - return tryTranslators(); - } - @catch (NSException *exception) { - return Catch::Detail::stringify( [exception description] ); - } #else - return tryTranslators(); -#endif - } - catch( TestFailureException& ) { - std::rethrow_exception(std::current_exception()); - } - catch( std::exception& ex ) { - return ex.what(); - } - catch( std::string& msg ) { - return msg; - } - catch( const char* msg ) { - return msg; - } - catch(...) { - return "Unknown exception"; + namespace Catch { + void writeToDebugConsole( std::string const& text ) { + // !TBD: Need a version for Mac/ XCode and other IDEs + Catch::cout() << text; } } +#endif // Platform - std::string ExceptionTranslatorRegistry::tryTranslators() const { - if( m_translators.empty() ) - std::rethrow_exception(std::current_exception()); - else - return m_translators[0]->translate( m_translators.begin()+1, m_translators.end() ); - } -} -// end catch_exception_translator_registry.cpp -// start catch_fatal_condition.cpp - -// start catch_fatal_condition.h - -#include - -#if defined ( CATCH_PLATFORM_WINDOWS ) ///////////////////////////////////////// - -# if !defined ( CATCH_CONFIG_WINDOWS_SEH ) - -namespace Catch { - struct FatalConditionHandler { - void reset(); - }; -} - -# else // CATCH_CONFIG_WINDOWS_SEH is defined +// #included from: catch_tostring.hpp +#define TWOBLUECUBES_CATCH_TOSTRING_HPP_INCLUDED namespace Catch { - struct FatalConditionHandler { +namespace Detail { - static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo); - FatalConditionHandler(); - static void reset(); - ~FatalConditionHandler(); + const std::string unprintableString = "{?}"; - private: - static bool isSet; - static ULONG guaranteeSize; - static PVOID exceptionHandlerHandle; - }; + namespace { + const int hexThreshold = 255; -} // namespace Catch + struct Endianness { + enum Arch { Big, Little }; -# endif // CATCH_CONFIG_WINDOWS_SEH + static Arch which() { + union _{ + int asInt; + char asChar[sizeof (int)]; + } u; -#else // Not Windows - assumed to be POSIX compatible ////////////////////////// - -# if !defined(CATCH_CONFIG_POSIX_SIGNALS) - -namespace Catch { - struct FatalConditionHandler { - void reset(); - }; -} - -# else // CATCH_CONFIG_POSIX_SIGNALS is defined - -#include - -namespace Catch { - - struct FatalConditionHandler { - - static bool isSet; - static struct sigaction oldSigActions[];// [sizeof(signalDefs) / sizeof(SignalDefs)]; - static stack_t oldSigStack; - static char altStackMem[]; - - static void handleSignal( int sig ); - - FatalConditionHandler(); - ~FatalConditionHandler(); - static void reset(); - }; - -} // namespace Catch - -# endif // CATCH_CONFIG_POSIX_SIGNALS - -#endif // not Windows - -// end catch_fatal_condition.h -namespace { - // Report the error condition - void reportFatal( char const * const message ) { - Catch::getCurrentContext().getResultCapture()->handleFatalErrorCondition( message ); - } -} - -#if defined ( CATCH_PLATFORM_WINDOWS ) ///////////////////////////////////////// - -# if !defined ( CATCH_CONFIG_WINDOWS_SEH ) - -namespace Catch { - void FatalConditionHandler::reset() {} -} - -# else // CATCH_CONFIG_WINDOWS_SEH is defined - -namespace Catch { - struct SignalDefs { DWORD id; const char* name; }; - - // There is no 1-1 mapping between signals and windows exceptions. - // Windows can easily distinguish between SO and SigSegV, - // but SigInt, SigTerm, etc are handled differently. - static SignalDefs signalDefs[] = { - { EXCEPTION_ILLEGAL_INSTRUCTION, "SIGILL - Illegal instruction signal" }, - { EXCEPTION_STACK_OVERFLOW, "SIGSEGV - Stack overflow" }, - { EXCEPTION_ACCESS_VIOLATION, "SIGSEGV - Segmentation violation signal" }, - { EXCEPTION_INT_DIVIDE_BY_ZERO, "Divide by zero error" }, - }; - - LONG CALLBACK FatalConditionHandler::handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) { - for (auto const& def : signalDefs) { - if (ExceptionInfo->ExceptionRecord->ExceptionCode == def.id) { - reportFatal(def.name); + u.asInt = 1; + return ( u.asChar[sizeof(int)-1] == 1 ) ? Big : Little; } - } - // If its not an exception we care about, pass it along. - // This stops us from eating debugger breaks etc. - return EXCEPTION_CONTINUE_SEARCH; + }; } - FatalConditionHandler::FatalConditionHandler() { - isSet = true; - // 32k seems enough for Catch to handle stack overflow, - // but the value was found experimentally, so there is no strong guarantee - guaranteeSize = 32 * 1024; - exceptionHandlerHandle = nullptr; - // Register as first handler in current chain - exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException); - // Pass in guarantee size to be filled - SetThreadStackGuarantee(&guaranteeSize); - } - - void FatalConditionHandler::reset() { - if (isSet) { - // Unregister handler and restore the old guarantee - RemoveVectoredExceptionHandler(exceptionHandlerHandle); - SetThreadStackGuarantee(&guaranteeSize); - exceptionHandlerHandle = nullptr; - isSet = false; - } - } - - FatalConditionHandler::~FatalConditionHandler() { - reset(); - } - -bool FatalConditionHandler::isSet = false; -ULONG FatalConditionHandler::guaranteeSize = 0; -PVOID FatalConditionHandler::exceptionHandlerHandle = nullptr; - -} // namespace Catch - -# endif // CATCH_CONFIG_WINDOWS_SEH - -#else // Not Windows - assumed to be POSIX compatible ////////////////////////// - -# if !defined(CATCH_CONFIG_POSIX_SIGNALS) - -namespace Catch { - void FatalConditionHandler::reset() {} -} - -# else // CATCH_CONFIG_POSIX_SIGNALS is defined - -#include - -namespace Catch { - - struct SignalDefs { - int id; - const char* name; - }; - static SignalDefs signalDefs[] = { - { SIGINT, "SIGINT - Terminal interrupt signal" }, - { SIGILL, "SIGILL - Illegal instruction signal" }, - { SIGFPE, "SIGFPE - Floating point error signal" }, - { SIGSEGV, "SIGSEGV - Segmentation violation signal" }, - { SIGTERM, "SIGTERM - Termination request signal" }, - { SIGABRT, "SIGABRT - Abort (abnormal termination) signal" } - }; - - void FatalConditionHandler::handleSignal( int sig ) { - char const * name = ""; - for (auto const& def : signalDefs) { - if (sig == def.id) { - name = def.name; - break; - } - } - reset(); - reportFatal(name); - raise( sig ); - } - - FatalConditionHandler::FatalConditionHandler() { - isSet = true; - stack_t sigStack; - sigStack.ss_sp = altStackMem; - sigStack.ss_size = SIGSTKSZ; - sigStack.ss_flags = 0; - sigaltstack(&sigStack, &oldSigStack); - struct sigaction sa = { }; - - sa.sa_handler = handleSignal; - sa.sa_flags = SA_ONSTACK; - for (std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i) { - sigaction(signalDefs[i].id, &sa, &oldSigActions[i]); - } - } - - FatalConditionHandler::~FatalConditionHandler() { - reset(); - } - - void FatalConditionHandler::reset() { - if( isSet ) { - // Set signals back to previous values -- hopefully nobody overwrote them in the meantime - for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) { - sigaction(signalDefs[i].id, &oldSigActions[i], nullptr); - } - // Return the old stack - sigaltstack(&oldSigStack, nullptr); - isSet = false; - } - } - - bool FatalConditionHandler::isSet = false; - struct sigaction FatalConditionHandler::oldSigActions[sizeof(signalDefs)/sizeof(SignalDefs)] = {}; - stack_t FatalConditionHandler::oldSigStack = {}; - char FatalConditionHandler::altStackMem[SIGSTKSZ] = {}; - -} // namespace Catch - -# endif // CATCH_CONFIG_POSIX_SIGNALS - -#endif // not Windows -// end catch_fatal_condition.cpp -// start catch_interfaces_capture.cpp - -namespace Catch { - IResultCapture::~IResultCapture() = default; -} -// end catch_interfaces_capture.cpp -// start catch_interfaces_config.cpp - -namespace Catch { - IConfig::~IConfig() = default; -} -// end catch_interfaces_config.cpp -// start catch_interfaces_exception.cpp - -namespace Catch { - IExceptionTranslator::~IExceptionTranslator() = default; - IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() = default; -} -// end catch_interfaces_exception.cpp -// start catch_interfaces_registry_hub.cpp - -namespace Catch { - IRegistryHub::~IRegistryHub() = default; - IMutableRegistryHub::~IMutableRegistryHub() = default; -} -// end catch_interfaces_registry_hub.cpp -// start catch_interfaces_reporter.cpp - -// start catch_reporter_multi.h - -namespace Catch { - - class MultipleReporters : public IStreamingReporter { - using Reporters = std::vector; - Reporters m_reporters; - - public: - void add( IStreamingReporterPtr&& reporter ); - - public: // IStreamingReporter - - ReporterPreferences getPreferences() const override; - - void noMatchingTestCases( std::string const& spec ) override; - - static std::set getSupportedVerbosities(); - - void benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) override; - void benchmarkEnded( BenchmarkStats const& benchmarkStats ) override; - - void testRunStarting( TestRunInfo const& testRunInfo ) override; - void testGroupStarting( GroupInfo const& groupInfo ) override; - void testCaseStarting( TestCaseInfo const& testInfo ) override; - void sectionStarting( SectionInfo const& sectionInfo ) override; - void assertionStarting( AssertionInfo const& assertionInfo ) override; - - // The return value indicates if the messages buffer should be cleared: - bool assertionEnded( AssertionStats const& assertionStats ) override; - void sectionEnded( SectionStats const& sectionStats ) override; - void testCaseEnded( TestCaseStats const& testCaseStats ) override; - void testGroupEnded( TestGroupStats const& testGroupStats ) override; - void testRunEnded( TestRunStats const& testRunStats ) override; - - void skipTest( TestCaseInfo const& testInfo ) override; - bool isMulti() const override; - - }; - -} // end namespace Catch - -// end catch_reporter_multi.h -namespace Catch { - - ReporterConfig::ReporterConfig( IConfigPtr const& _fullConfig ) - : m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {} - - ReporterConfig::ReporterConfig( IConfigPtr const& _fullConfig, std::ostream& _stream ) - : m_stream( &_stream ), m_fullConfig( _fullConfig ) {} - - std::ostream& ReporterConfig::stream() const { return *m_stream; } - IConfigPtr ReporterConfig::fullConfig() const { return m_fullConfig; } - - TestRunInfo::TestRunInfo( std::string const& _name ) : name( _name ) {} - - GroupInfo::GroupInfo( std::string const& _name, - std::size_t _groupIndex, - std::size_t _groupsCount ) - : name( _name ), - groupIndex( _groupIndex ), - groupsCounts( _groupsCount ) - {} - - AssertionStats::AssertionStats( AssertionResult const& _assertionResult, - std::vector const& _infoMessages, - Totals const& _totals ) - : assertionResult( _assertionResult ), - infoMessages( _infoMessages ), - totals( _totals ) + std::string rawMemoryToString( const void *object, std::size_t size ) { - assertionResult.m_resultData.lazyExpression.m_transientExpression = _assertionResult.m_resultData.lazyExpression.m_transientExpression; + // Reverse order for little endian architectures + int i = 0, end = static_cast( size ), inc = 1; + if( Endianness::which() == Endianness::Little ) { + i = end-1; + end = inc = -1; + } - if( assertionResult.hasMessage() ) { - // Copy message into messages list. - // !TBD This should have been done earlier, somewhere - MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() ); - builder << assertionResult.getMessage(); - builder.m_info.message = builder.m_stream.str(); + unsigned char const *bytes = static_cast(object); + std::ostringstream os; + os << "0x" << std::setfill('0') << std::hex; + for( ; i != end; i += inc ) + os << std::setw(2) << static_cast(bytes[i]); + return os.str(); + } +} - infoMessages.push_back( builder.m_info ); +std::string toString( std::string const& value ) { + std::string s = value; + if( getCurrentContext().getConfig()->showInvisibles() ) { + for(size_t i = 0; i < s.size(); ++i ) { + std::string subs; + switch( s[i] ) { + case '\n': subs = "\\n"; break; + case '\t': subs = "\\t"; break; + default: break; + } + if( !subs.empty() ) { + s = s.substr( 0, i ) + subs + s.substr( i+1 ); + ++i; + } } } + return '"' + s + '"'; +} +std::string toString( std::wstring const& value ) { - AssertionStats::~AssertionStats() = default; + std::string s; + s.reserve( value.size() ); + for(size_t i = 0; i < value.size(); ++i ) + s += value[i] <= 0xff ? static_cast( value[i] ) : '?'; + return Catch::toString( s ); +} - SectionStats::SectionStats( SectionInfo const& _sectionInfo, - Counts const& _assertions, - double _durationInSeconds, - bool _missingAssertions ) - : sectionInfo( _sectionInfo ), - assertions( _assertions ), - durationInSeconds( _durationInSeconds ), - missingAssertions( _missingAssertions ) - {} +std::string toString( const char* const value ) { + return value ? Catch::toString( std::string( value ) ) : std::string( "{null string}" ); +} - SectionStats::~SectionStats() = default; +std::string toString( char* const value ) { + return Catch::toString( static_cast( value ) ); +} - TestCaseStats::TestCaseStats( TestCaseInfo const& _testInfo, - Totals const& _totals, - std::string const& _stdOut, - std::string const& _stdErr, - bool _aborting ) - : testInfo( _testInfo ), - totals( _totals ), - stdOut( _stdOut ), - stdErr( _stdErr ), - aborting( _aborting ) - {} +std::string toString( const wchar_t* const value ) +{ + return value ? Catch::toString( std::wstring(value) ) : std::string( "{null string}" ); +} - TestCaseStats::~TestCaseStats() = default; +std::string toString( wchar_t* const value ) +{ + return Catch::toString( static_cast( value ) ); +} - TestGroupStats::TestGroupStats( GroupInfo const& _groupInfo, - Totals const& _totals, - bool _aborting ) - : groupInfo( _groupInfo ), - totals( _totals ), - aborting( _aborting ) - {} +std::string toString( int value ) { + std::ostringstream oss; + oss << value; + if( value > Detail::hexThreshold ) + oss << " (0x" << std::hex << value << ')'; + return oss.str(); +} - TestGroupStats::TestGroupStats( GroupInfo const& _groupInfo ) - : groupInfo( _groupInfo ), - aborting( false ) - {} +std::string toString( unsigned long value ) { + std::ostringstream oss; + oss << value; + if( value > Detail::hexThreshold ) + oss << " (0x" << std::hex << value << ')'; + return oss.str(); +} - TestGroupStats::~TestGroupStats() = default; +std::string toString( unsigned int value ) { + return Catch::toString( static_cast( value ) ); +} - TestRunStats::TestRunStats( TestRunInfo const& _runInfo, - Totals const& _totals, - bool _aborting ) - : runInfo( _runInfo ), - totals( _totals ), - aborting( _aborting ) - {} - - TestRunStats::~TestRunStats() = default; - - void IStreamingReporter::fatalErrorEncountered( StringRef ) {} - bool IStreamingReporter::isMulti() const { return false; } - - IReporterFactory::~IReporterFactory() = default; - IReporterRegistry::~IReporterRegistry() = default; - - void addReporter( IStreamingReporterPtr& existingReporter, IStreamingReporterPtr&& additionalReporter ) { - - if( !existingReporter ) { - existingReporter = std::move( additionalReporter ); - return; - } - - MultipleReporters* multi = nullptr; - - if( existingReporter->isMulti() ) { - multi = static_cast( existingReporter.get() ); - } - else { - auto newMulti = std::unique_ptr( new MultipleReporters ); - newMulti->add( std::move( existingReporter ) ); - multi = newMulti.get(); - existingReporter = std::move( newMulti ); - } - multi->add( std::move( additionalReporter ) ); +template +std::string fpToString( T value, int precision ) { + std::ostringstream oss; + oss << std::setprecision( precision ) + << std::fixed + << value; + std::string d = oss.str(); + std::size_t i = d.find_last_not_of( '0' ); + if( i != std::string::npos && i != d.size()-1 ) { + if( d[i] == '.' ) + i++; + d = d.substr( 0, i+1 ); } - -} // end namespace Catch -// end catch_interfaces_reporter.cpp -// start catch_interfaces_runner.cpp - -namespace Catch { - IRunner::~IRunner() = default; + return d; } -// end catch_interfaces_runner.cpp -// start catch_interfaces_testcase.cpp -namespace Catch { - ITestInvoker::~ITestInvoker() = default; - ITestCaseRegistry::~ITestCaseRegistry() = default; +std::string toString( const double value ) { + return fpToString( value, 10 ); +} +std::string toString( const float value ) { + return fpToString( value, 5 ) + 'f'; } -// end catch_interfaces_testcase.cpp -// start catch_leak_detector.cpp -namespace Catch { +std::string toString( bool value ) { + return value ? "true" : "false"; +} -#ifdef CATCH_CONFIG_WINDOWS_CRTDBG -#include +std::string toString( char value ) { + if ( value == '\r' ) + return "'\\r'"; + if ( value == '\f' ) + return "'\\f'"; + if ( value == '\n' ) + return "'\\n'"; + if ( value == '\t' ) + return "'\\t'"; + if ( '\0' <= value && value < ' ' ) + return toString( static_cast( value ) ); + char chstr[] = "' '"; + chstr[1] = value; + return chstr; +} - LeakDetector::LeakDetector() { - int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); - flag |= _CRTDBG_LEAK_CHECK_DF; - flag |= _CRTDBG_ALLOC_MEM_DF; - _CrtSetDbgFlag(flag); - _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG); - _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR); - // Change this to leaking allocation's number to break there - _CrtSetBreakAlloc(-1); - } +std::string toString( signed char value ) { + return toString( static_cast( value ) ); +} -#else - - LeakDetector::LeakDetector(){} +std::string toString( unsigned char value ) { + return toString( static_cast( value ) ); +} +#ifdef CATCH_CONFIG_CPP11_LONG_LONG +std::string toString( long long value ) { + std::ostringstream oss; + oss << value; + if( value > Detail::hexThreshold ) + oss << " (0x" << std::hex << value << ')'; + return oss.str(); +} +std::string toString( unsigned long long value ) { + std::ostringstream oss; + oss << value; + if( value > Detail::hexThreshold ) + oss << " (0x" << std::hex << value << ')'; + return oss.str(); +} #endif +#ifdef CATCH_CONFIG_CPP11_NULLPTR +std::string toString( std::nullptr_t ) { + return "nullptr"; } -// end catch_leak_detector.cpp -// start catch_list.cpp +#endif -// start catch_list.h - -#include - -namespace Catch { - - std::size_t listTests( Config const& config ); - - std::size_t listTestsNamesOnly( Config const& config ); - - struct TagInfo { - void add( std::string const& spelling ); - std::string all() const; - - std::set spellings; - std::size_t count = 0; - }; - - std::size_t listTags( Config const& config ); - - std::size_t listReporters( Config const& /*config*/ ); - - Option list( Config const& config ); +#ifdef __OBJC__ + std::string toString( NSString const * const& nsstring ) { + if( !nsstring ) + return "nil"; + return "@" + toString([nsstring UTF8String]); + } + std::string toString( NSString * CATCH_ARC_STRONG & nsstring ) { + if( !nsstring ) + return "nil"; + return "@" + toString([nsstring UTF8String]); + } + std::string toString( NSObject* const& nsObject ) { + return toString( [nsObject description] ); + } +#endif } // end namespace Catch -// end catch_list.h -// start catch_text.h - -namespace Catch { - using namespace clara::TextFlow; -} - -// end catch_text.h -#include -#include -#include +// #included from: catch_result_builder.hpp +#define TWOBLUECUBES_CATCH_RESULT_BUILDER_HPP_INCLUDED namespace Catch { - std::size_t listTests( Config const& config ) { - TestSpec testSpec = config.testSpec(); - if( config.testSpec().hasFilters() ) - Catch::cout() << "Matching test cases:\n"; - else { - Catch::cout() << "All available test cases:\n"; - testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); + ResultBuilder::ResultBuilder( char const* macroName, + SourceLineInfo const& lineInfo, + char const* capturedExpression, + ResultDisposition::Flags resultDisposition, + char const* secondArg ) + : m_assertionInfo( macroName, lineInfo, capturedExpression, resultDisposition, secondArg ), + m_shouldDebugBreak( false ), + m_shouldThrow( false ), + m_guardException( false ), + m_usedStream( false ) + {} + + ResultBuilder::~ResultBuilder() { +#if defined(CATCH_CONFIG_FAST_COMPILE) + if ( m_guardException ) { + stream().oss << "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE"; + captureResult( ResultWas::ThrewException ); + getCurrentContext().getResultCapture()->exceptionEarlyReported(); + } +#endif + } + + ResultBuilder& ResultBuilder::setResultType( ResultWas::OfType result ) { + m_data.resultType = result; + return *this; + } + ResultBuilder& ResultBuilder::setResultType( bool result ) { + m_data.resultType = result ? ResultWas::Ok : ResultWas::ExpressionFailed; + return *this; + } + + void ResultBuilder::endExpression( DecomposedExpression const& expr ) { + // Flip bool results if FalseTest flag is set + if( isFalseTest( m_assertionInfo.resultDisposition ) ) { + m_data.negate( expr.isBinaryExpression() ); } - auto matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); - for( auto const& testCaseInfo : matchedTestCases ) { - Colour::Code colour = testCaseInfo.isHidden() - ? Colour::SecondaryText - : Colour::None; - Colour colourGuard( colour ); + getResultCapture().assertionRun(); - Catch::cout() << Column( testCaseInfo.name ).initialIndent( 2 ).indent( 4 ) << "\n"; - if( config.verbosity() >= Verbosity::High ) { - Catch::cout() << Column( Catch::Detail::stringify( testCaseInfo.lineInfo ) ).indent(4) << std::endl; - std::string description = testCaseInfo.description; - if( description.empty() ) - description = "(NO DESCRIPTION)"; - Catch::cout() << Column( description ).indent(4) << std::endl; - } - if( !testCaseInfo.tags.empty() ) - Catch::cout() << Column( testCaseInfo.tagsAsString() ).indent( 6 ) << "\n"; + if(getCurrentContext().getConfig()->includeSuccessfulResults() || m_data.resultType != ResultWas::Ok) + { + AssertionResult result = build( expr ); + handleResult( result ); } - - if( !config.testSpec().hasFilters() ) - Catch::cout() << pluralise( matchedTestCases.size(), "test case" ) << '\n' << std::endl; else - Catch::cout() << pluralise( matchedTestCases.size(), "matching test case" ) << '\n' << std::endl; - return matchedTestCases.size(); + getResultCapture().assertionPassed(); } - std::size_t listTestsNamesOnly( Config const& config ) { - TestSpec testSpec = config.testSpec(); - if( !config.testSpec().hasFilters() ) - testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); - std::size_t matchedTests = 0; - std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); - for( auto const& testCaseInfo : matchedTestCases ) { - matchedTests++; - if( startsWith( testCaseInfo.name, '#' ) ) - Catch::cout() << '"' << testCaseInfo.name << '"'; - else - Catch::cout() << testCaseInfo.name; - if ( config.verbosity() >= Verbosity::High ) - Catch::cout() << "\t@" << testCaseInfo.lineInfo; - Catch::cout() << std::endl; + void ResultBuilder::useActiveException( ResultDisposition::Flags resultDisposition ) { + m_assertionInfo.resultDisposition = resultDisposition; + stream().oss << Catch::translateActiveException(); + captureResult( ResultWas::ThrewException ); + } + + void ResultBuilder::captureResult( ResultWas::OfType resultType ) { + setResultType( resultType ); + captureExpression(); + } + + void ResultBuilder::captureExpectedException( std::string const& expectedMessage ) { + if( expectedMessage.empty() ) + captureExpectedException( Matchers::Impl::MatchAllOf() ); + else + captureExpectedException( Matchers::Equals( expectedMessage ) ); + } + + void ResultBuilder::captureExpectedException( Matchers::Impl::MatcherBase const& matcher ) { + + assert( !isFalseTest( m_assertionInfo.resultDisposition ) ); + AssertionResultData data = m_data; + data.resultType = ResultWas::Ok; + data.reconstructedExpression = capturedExpressionWithSecondArgument(m_assertionInfo.capturedExpression, m_assertionInfo.secondArg); + + std::string actualMessage = Catch::translateActiveException(); + if( !matcher.match( actualMessage ) ) { + data.resultType = ResultWas::ExpressionFailed; + data.reconstructedExpression = actualMessage; } - return matchedTests; + AssertionResult result( m_assertionInfo, data ); + handleResult( result ); } - void TagInfo::add( std::string const& spelling ) { - ++count; - spellings.insert( spelling ); + void ResultBuilder::captureExpression() { + AssertionResult result = build(); + handleResult( result ); } - std::string TagInfo::all() const { - std::string out; - for( auto const& spelling : spellings ) - out += "[" + spelling + "]"; - return out; - } + void ResultBuilder::handleResult( AssertionResult const& result ) + { + getResultCapture().assertionEnded( result ); - std::size_t listTags( Config const& config ) { - TestSpec testSpec = config.testSpec(); - if( config.testSpec().hasFilters() ) - Catch::cout() << "Tags for matching test cases:\n"; - else { - Catch::cout() << "All available tags:\n"; - testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); + if( !result.isOk() ) { + if( getCurrentContext().getConfig()->shouldDebugBreak() ) + m_shouldDebugBreak = true; + if( getCurrentContext().getRunner()->aborting() || (m_assertionInfo.resultDisposition & ResultDisposition::Normal) ) + m_shouldThrow = true; } - - std::map tagCounts; - - std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); - for( auto const& testCase : matchedTestCases ) { - for( auto const& tagName : testCase.getTestCaseInfo().tags ) { - std::string lcaseTagName = toLower( tagName ); - auto countIt = tagCounts.find( lcaseTagName ); - if( countIt == tagCounts.end() ) - countIt = tagCounts.insert( std::make_pair( lcaseTagName, TagInfo() ) ).first; - countIt->second.add( tagName ); - } - } - - for( auto const& tagCount : tagCounts ) { - std::ostringstream oss; - oss << " " << std::setw(2) << tagCount.second.count << " "; - auto wrapper = Column( tagCount.second.all() ) - .initialIndent( 0 ) - .indent( oss.str().size() ) - .width( CATCH_CONFIG_CONSOLE_WIDTH-10 ); - Catch::cout() << oss.str() << wrapper << '\n'; - } - Catch::cout() << pluralise( tagCounts.size(), "tag" ) << '\n' << std::endl; - return tagCounts.size(); } - std::size_t listReporters( Config const& /*config*/ ) { - Catch::cout() << "Available reporters:\n"; - IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories(); - std::size_t maxNameLen = 0; - for( auto const& factoryKvp : factories ) - maxNameLen = (std::max)( maxNameLen, factoryKvp.first.size() ); - - for( auto const& factoryKvp : factories ) { - Catch::cout() - << Column( factoryKvp.first + ":" ) - .indent(2) - .width( 5+maxNameLen ) - + Column( factoryKvp.second->getDescription() ) - .initialIndent(0) - .indent(2) - .width( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 ) - << "\n"; + void ResultBuilder::react() { +#if defined(CATCH_CONFIG_FAST_COMPILE) + if (m_shouldDebugBreak) { + /////////////////////////////////////////////////////////////////// + // To inspect the state during test, you need to go one level up the callstack + // To go back to the test and change execution, jump over the throw statement + /////////////////////////////////////////////////////////////////// + CATCH_BREAK_INTO_DEBUGGER(); } - Catch::cout() << std::endl; - return factories.size(); +#endif + if( m_shouldThrow ) + throw Catch::TestFailureException(); } - Option list( Config const& config ) { - Option listedCount; - if( config.listTests() ) - listedCount = listedCount.valueOr(0) + listTests( config ); - if( config.listTestNamesOnly() ) - listedCount = listedCount.valueOr(0) + listTestsNamesOnly( config ); - if( config.listTags() ) - listedCount = listedCount.valueOr(0) + listTags( config ); - if( config.listReporters() ) - listedCount = listedCount.valueOr(0) + listReporters( config ); - return listedCount; + bool ResultBuilder::shouldDebugBreak() const { return m_shouldDebugBreak; } + bool ResultBuilder::allowThrows() const { return getCurrentContext().getConfig()->allowThrows(); } + + AssertionResult ResultBuilder::build() const + { + return build( *this ); + } + + // CAVEAT: The returned AssertionResult stores a pointer to the argument expr, + // a temporary DecomposedExpression, which in turn holds references to + // operands, possibly temporary as well. + // It should immediately be passed to handleResult; if the expression + // needs to be reported, its string expansion must be composed before + // the temporaries are destroyed. + AssertionResult ResultBuilder::build( DecomposedExpression const& expr ) const + { + assert( m_data.resultType != ResultWas::Unknown ); + AssertionResultData data = m_data; + + if(m_usedStream) + data.message = m_stream().oss.str(); + data.decomposedExpression = &expr; // for lazy reconstruction + return AssertionResult( m_assertionInfo, data ); + } + + void ResultBuilder::reconstructExpression( std::string& dest ) const { + dest = capturedExpressionWithSecondArgument(m_assertionInfo.capturedExpression, m_assertionInfo.secondArg); + } + + void ResultBuilder::setExceptionGuard() { + m_guardException = true; + } + void ResultBuilder::unsetExceptionGuard() { + m_guardException = false; } } // end namespace Catch -// end catch_list.cpp -// start catch_matchers.cpp + +// #included from: catch_tag_alias_registry.hpp +#define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_HPP_INCLUDED namespace Catch { -namespace Matchers { - namespace Impl { - std::string MatcherUntypedBase::toString() const { - if( m_cachedToString.empty() ) - m_cachedToString = describe(); - return m_cachedToString; + TagAliasRegistry::~TagAliasRegistry() {} + + Option TagAliasRegistry::find( std::string const& alias ) const { + std::map::const_iterator it = m_registry.find( alias ); + if( it != m_registry.end() ) + return it->second; + else + return Option(); + } + + std::string TagAliasRegistry::expandAliases( std::string const& unexpandedTestSpec ) const { + std::string expandedTestSpec = unexpandedTestSpec; + for( std::map::const_iterator it = m_registry.begin(), itEnd = m_registry.end(); + it != itEnd; + ++it ) { + std::size_t pos = expandedTestSpec.find( it->first ); + if( pos != std::string::npos ) { + expandedTestSpec = expandedTestSpec.substr( 0, pos ) + + it->second.tag + + expandedTestSpec.substr( pos + it->first.size() ); + } } + return expandedTestSpec; + } - MatcherUntypedBase::~MatcherUntypedBase() = default; + void TagAliasRegistry::add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) { - } // namespace Impl -} // namespace Matchers + if( !startsWith( alias, "[@" ) || !endsWith( alias, ']' ) ) { + std::ostringstream oss; + oss << Colour( Colour::Red ) + << "error: tag alias, \"" << alias << "\" is not of the form [@alias name].\n" + << Colour( Colour::FileName ) + << lineInfo << '\n'; + throw std::domain_error( oss.str().c_str() ); + } + if( !m_registry.insert( std::make_pair( alias, TagAlias( tag, lineInfo ) ) ).second ) { + std::ostringstream oss; + oss << Colour( Colour::Red ) + << "error: tag alias, \"" << alias << "\" already registered.\n" + << "\tFirst seen at " + << Colour( Colour::Red ) << find(alias)->lineInfo << '\n' + << Colour( Colour::Red ) << "\tRedefined at " + << Colour( Colour::FileName) << lineInfo << '\n'; + throw std::domain_error( oss.str().c_str() ); + } + } -using namespace Matchers; -using Matchers::Impl::MatcherBase; + ITagAliasRegistry::~ITagAliasRegistry() {} -} // namespace Catch -// end catch_matchers.cpp -// start catch_matchers_string.cpp + ITagAliasRegistry const& ITagAliasRegistry::get() { + return getRegistryHub().getTagAliasRegistry(); + } + + RegistrarForTagAliases::RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) { + getMutableRegistryHub().registerTagAlias( alias, tag, lineInfo ); + } + +} // end namespace Catch + +// #included from: catch_matchers_string.hpp namespace Catch { namespace Matchers { @@ -7151,2732 +9401,517 @@ namespace Matchers { } // namespace Matchers } // namespace Catch -// end catch_matchers_string.cpp -// start catch_message.cpp +// #included from: ../reporters/catch_reporter_multi.hpp +#define TWOBLUECUBES_CATCH_REPORTER_MULTI_HPP_INCLUDED namespace Catch { - MessageInfo::MessageInfo( std::string const& _macroName, - SourceLineInfo const& _lineInfo, - ResultWas::OfType _type ) - : macroName( _macroName ), - lineInfo( _lineInfo ), - type( _type ), - sequence( ++globalCount ) - {} +class MultipleReporters : public SharedImpl { + typedef std::vector > Reporters; + Reporters m_reporters; - bool MessageInfo::operator==( MessageInfo const& other ) const { - return sequence == other.sequence; +public: + void add( Ptr const& reporter ) { + m_reporters.push_back( reporter ); } - bool MessageInfo::operator<( MessageInfo const& other ) const { - return sequence < other.sequence; +public: // IStreamingReporter + + virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE { + return m_reporters[0]->getPreferences(); } - // This may need protecting if threading support is added - unsigned int MessageInfo::globalCount = 0; - - //////////////////////////////////////////////////////////////////////////// - - Catch::MessageBuilder::MessageBuilder( std::string const& macroName, - SourceLineInfo const& lineInfo, - ResultWas::OfType type ) - :m_info(macroName, lineInfo, type) {} - - //////////////////////////////////////////////////////////////////////////// - - ScopedMessage::ScopedMessage( MessageBuilder const& builder ) - : m_info( builder.m_info ) - { - m_info.message = builder.m_stream.str(); - getResultCapture().pushScopedMessage( m_info ); + virtual void noMatchingTestCases( std::string const& spec ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->noMatchingTestCases( spec ); } - ScopedMessage::~ScopedMessage() { - if ( !std::uncaught_exception() ){ - getResultCapture().popScopedMessage(m_info); + virtual void testRunStarting( TestRunInfo const& testRunInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testRunStarting( testRunInfo ); + } + + virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testGroupStarting( groupInfo ); + } + + virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testCaseStarting( testInfo ); + } + + virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->sectionStarting( sectionInfo ); + } + + virtual void assertionStarting( AssertionInfo const& assertionInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->assertionStarting( assertionInfo ); + } + + // The return value indicates if the messages buffer should be cleared: + virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { + bool clearBuffer = false; + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + clearBuffer |= (*it)->assertionEnded( assertionStats ); + return clearBuffer; + } + + virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->sectionEnded( sectionStats ); + } + + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testCaseEnded( testCaseStats ); + } + + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testGroupEnded( testGroupStats ); + } + + virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testRunEnded( testRunStats ); + } + + virtual void skipTest( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->skipTest( testInfo ); + } + + virtual MultipleReporters* tryAsMulti() CATCH_OVERRIDE { + return this; + } + +}; + +Ptr addReporter( Ptr const& existingReporter, Ptr const& additionalReporter ) { + Ptr resultingReporter; + + if( existingReporter ) { + MultipleReporters* multi = existingReporter->tryAsMulti(); + if( !multi ) { + multi = new MultipleReporters; + resultingReporter = Ptr( multi ); + if( existingReporter ) + multi->add( existingReporter ); } + else + resultingReporter = existingReporter; + multi->add( additionalReporter ); } + else + resultingReporter = additionalReporter; -} // end namespace Catch -// end catch_message.cpp -// start catch_random_number_generator.cpp - -// start catch_random_number_generator.h - -#include - -namespace Catch { - - struct IConfig; - - void seedRng( IConfig const& config ); - - unsigned int rngSeed(); - - struct RandomNumberGenerator { - using result_type = unsigned int; - - static constexpr result_type (min)() { return 0; } - static constexpr result_type (max)() { return 1000000; } - - result_type operator()( result_type n ) const; - result_type operator()() const; - - template - static void shuffle( V& vector ) { - RandomNumberGenerator rng; - std::shuffle( vector.begin(), vector.end(), rng ); - } - }; - + return resultingReporter; } -// end catch_random_number_generator.h -#include - -namespace Catch { - - void seedRng( IConfig const& config ) { - if( config.rngSeed() != 0 ) - std::srand( config.rngSeed() ); - } - unsigned int rngSeed() { - return getCurrentContext().getConfig()->rngSeed(); - } - - RandomNumberGenerator::result_type RandomNumberGenerator::operator()( result_type n ) const { - return std::rand() % n; - } - RandomNumberGenerator::result_type RandomNumberGenerator::operator()() const { - return std::rand() % (max)(); - } - -} -// end catch_random_number_generator.cpp -// start catch_registry_hub.cpp - -// start catch_test_case_registry_impl.h - -#include -#include -#include -#include - -namespace Catch { - - class TestCase; - struct IConfig; - - std::vector sortTests( IConfig const& config, std::vector const& unsortedTestCases ); - bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); - - void enforceNoDuplicateTestCases( std::vector const& functions ); - - std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ); - std::vector const& getAllTestCasesSorted( IConfig const& config ); - - class TestRegistry : public ITestCaseRegistry { - public: - virtual ~TestRegistry() = default; - - virtual void registerTest( TestCase const& testCase ); - - std::vector const& getAllTests() const override; - std::vector const& getAllTestsSorted( IConfig const& config ) const override; - - private: - std::vector m_functions; - mutable RunTests::InWhatOrder m_currentSortOrder = RunTests::InDeclarationOrder; - mutable std::vector m_sortedFunctions; - std::size_t m_unnamedCount = 0; - std::ios_base::Init m_ostreamInit; // Forces cout/ cerr to be initialised - }; - - /////////////////////////////////////////////////////////////////////////// - - class TestInvokerAsFunction : public ITestInvoker { - void(*m_testAsFunction)(); - public: - TestInvokerAsFunction( void(*testAsFunction)() ) noexcept; - - void invoke() const override; - }; - - std::string extractClassName( std::string const& classOrQualifiedMethodName ); - - /////////////////////////////////////////////////////////////////////////// - } // end namespace Catch -// end catch_test_case_registry_impl.h -// start catch_reporter_registry.h +// #included from: ../reporters/catch_reporter_xml.hpp +#define TWOBLUECUBES_CATCH_REPORTER_XML_HPP_INCLUDED -#include +// #included from: catch_reporter_bases.hpp +#define TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED -namespace Catch { +#include +#include +#include +#include - class ReporterRegistry : public IReporterRegistry { - - public: - - ~ReporterRegistry() override; - - IStreamingReporterPtr create( std::string const& name, IConfigPtr const& config ) const override; - - void registerReporter( std::string const& name, IReporterFactoryPtr const& factory ); - void registerListener( IReporterFactoryPtr const& factory ); - - FactoryMap const& getFactories() const override; - Listeners const& getListeners() const override; - - private: - FactoryMap m_factories; - Listeners m_listeners; - }; -} - -// end catch_reporter_registry.h -// start catch_tag_alias_registry.h - -// start catch_tag_alias.h - -#include - -namespace Catch { - - struct TagAlias { - TagAlias(std::string const& _tag, SourceLineInfo _lineInfo); - - std::string tag; - SourceLineInfo lineInfo; - }; - -} // end namespace Catch - -// end catch_tag_alias.h -#include - -namespace Catch { - - class TagAliasRegistry : public ITagAliasRegistry { - public: - ~TagAliasRegistry() override; - TagAlias const* find( std::string const& alias ) const override; - std::string expandAliases( std::string const& unexpandedTestSpec ) const override; - void add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ); - - private: - std::map m_registry; - }; - -} // end namespace Catch - -// end catch_tag_alias_registry.h -// start catch_startup_exception_registry.h - -#include -#include - -namespace Catch { - - class StartupExceptionRegistry { - public: - void add(std::exception_ptr const& exception) noexcept; - std::vector const& getExceptions() const noexcept; - private: - std::vector m_exceptions; - }; - -} // end namespace Catch - -// end catch_startup_exception_registry.h namespace Catch { namespace { + // Because formatting using c++ streams is stateful, drop down to C is required + // Alternatively we could use stringstream, but its performance is... not good. + std::string getFormattedDuration( double duration ) { + // Max exponent + 1 is required to represent the whole part + // + 1 for decimal point + // + 3 for the 3 decimal places + // + 1 for null terminator + const size_t maxDoubleSize = DBL_MAX_10_EXP + 1 + 1 + 3 + 1; + char buffer[maxDoubleSize]; - class RegistryHub : public IRegistryHub, public IMutableRegistryHub, - private NonCopyable { + // Save previous errno, to prevent sprintf from overwriting it + ErrnoGuard guard; +#ifdef _MSC_VER + sprintf_s(buffer, "%.3f", duration); +#else + sprintf(buffer, "%.3f", duration); +#endif + return std::string(buffer); + } + } - public: // IRegistryHub - RegistryHub() = default; - IReporterRegistry const& getReporterRegistry() const override { - return m_reporterRegistry; + struct StreamingReporterBase : SharedImpl { + + StreamingReporterBase( ReporterConfig const& _config ) + : m_config( _config.fullConfig() ), + stream( _config.stream() ) + { + m_reporterPrefs.shouldRedirectStdOut = false; + } + + virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE { + return m_reporterPrefs; + } + + virtual ~StreamingReporterBase() CATCH_OVERRIDE; + + virtual void noMatchingTestCases( std::string const& ) CATCH_OVERRIDE {} + + virtual void testRunStarting( TestRunInfo const& _testRunInfo ) CATCH_OVERRIDE { + currentTestRunInfo = _testRunInfo; + } + virtual void testGroupStarting( GroupInfo const& _groupInfo ) CATCH_OVERRIDE { + currentGroupInfo = _groupInfo; + } + + virtual void testCaseStarting( TestCaseInfo const& _testInfo ) CATCH_OVERRIDE { + currentTestCaseInfo = _testInfo; + } + virtual void sectionStarting( SectionInfo const& _sectionInfo ) CATCH_OVERRIDE { + m_sectionStack.push_back( _sectionInfo ); + } + + virtual void sectionEnded( SectionStats const& /* _sectionStats */ ) CATCH_OVERRIDE { + m_sectionStack.pop_back(); + } + virtual void testCaseEnded( TestCaseStats const& /* _testCaseStats */ ) CATCH_OVERRIDE { + currentTestCaseInfo.reset(); + } + virtual void testGroupEnded( TestGroupStats const& /* _testGroupStats */ ) CATCH_OVERRIDE { + currentGroupInfo.reset(); + } + virtual void testRunEnded( TestRunStats const& /* _testRunStats */ ) CATCH_OVERRIDE { + currentTestCaseInfo.reset(); + currentGroupInfo.reset(); + currentTestRunInfo.reset(); + } + + virtual void skipTest( TestCaseInfo const& ) CATCH_OVERRIDE { + // Don't do anything with this by default. + // It can optionally be overridden in the derived class. + } + + Ptr m_config; + std::ostream& stream; + + LazyStat currentTestRunInfo; + LazyStat currentGroupInfo; + LazyStat currentTestCaseInfo; + + std::vector m_sectionStack; + ReporterPreferences m_reporterPrefs; + }; + + struct CumulativeReporterBase : SharedImpl { + template + struct Node : SharedImpl<> { + explicit Node( T const& _value ) : value( _value ) {} + virtual ~Node() {} + + typedef std::vector > ChildNodes; + T value; + ChildNodes children; + }; + struct SectionNode : SharedImpl<> { + explicit SectionNode( SectionStats const& _stats ) : stats( _stats ) {} + virtual ~SectionNode(); + + bool operator == ( SectionNode const& other ) const { + return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo; } - ITestCaseRegistry const& getTestCaseRegistry() const override { - return m_testCaseRegistry; - } - IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() override { - return m_exceptionTranslatorRegistry; - } - ITagAliasRegistry const& getTagAliasRegistry() const override { - return m_tagAliasRegistry; - } - StartupExceptionRegistry const& getStartupExceptionRegistry() const override { - return m_exceptionRegistry; + bool operator == ( Ptr const& other ) const { + return operator==( *other ); } - public: // IMutableRegistryHub - void registerReporter( std::string const& name, IReporterFactoryPtr const& factory ) override { - m_reporterRegistry.registerReporter( name, factory ); - } - void registerListener( IReporterFactoryPtr const& factory ) override { - m_reporterRegistry.registerListener( factory ); - } - void registerTest( TestCase const& testInfo ) override { - m_testCaseRegistry.registerTest( testInfo ); - } - void registerTranslator( const IExceptionTranslator* translator ) override { - m_exceptionTranslatorRegistry.registerTranslator( translator ); - } - void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) override { - m_tagAliasRegistry.add( alias, tag, lineInfo ); - } - void registerStartupException() noexcept override { - m_exceptionRegistry.add(std::current_exception()); - } - - private: - TestRegistry m_testCaseRegistry; - ReporterRegistry m_reporterRegistry; - ExceptionTranslatorRegistry m_exceptionTranslatorRegistry; - TagAliasRegistry m_tagAliasRegistry; - StartupExceptionRegistry m_exceptionRegistry; + SectionStats stats; + typedef std::vector > ChildSections; + typedef std::vector Assertions; + ChildSections childSections; + Assertions assertions; + std::string stdOut; + std::string stdErr; }; - // Single, global, instance - RegistryHub*& getTheRegistryHub() { - static RegistryHub* theRegistryHub = nullptr; - if( !theRegistryHub ) - theRegistryHub = new RegistryHub(); - return theRegistryHub; - } - } - - IRegistryHub& getRegistryHub() { - return *getTheRegistryHub(); - } - IMutableRegistryHub& getMutableRegistryHub() { - return *getTheRegistryHub(); - } - void cleanUp() { - delete getTheRegistryHub(); - getTheRegistryHub() = nullptr; - cleanUpContext(); - } - std::string translateActiveException() { - return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException(); - } - -} // end namespace Catch -// end catch_registry_hub.cpp -// start catch_reporter_registry.cpp - -namespace Catch { - - ReporterRegistry::~ReporterRegistry() = default; - - IStreamingReporterPtr ReporterRegistry::create( std::string const& name, IConfigPtr const& config ) const { - auto it = m_factories.find( name ); - if( it == m_factories.end() ) - return nullptr; - return it->second->create( ReporterConfig( config ) ); - } - - void ReporterRegistry::registerReporter( std::string const& name, IReporterFactoryPtr const& factory ) { - m_factories.emplace(name, factory); - } - void ReporterRegistry::registerListener( IReporterFactoryPtr const& factory ) { - m_listeners.push_back( factory ); - } - - IReporterRegistry::FactoryMap const& ReporterRegistry::getFactories() const { - return m_factories; - } - IReporterRegistry::Listeners const& ReporterRegistry::getListeners() const { - return m_listeners; - } - -} -// end catch_reporter_registry.cpp -// start catch_result_type.cpp - -namespace Catch { - - bool isOk( ResultWas::OfType resultType ) { - return ( resultType & ResultWas::FailureBit ) == 0; - } - bool isJustInfo( int flags ) { - return flags == ResultWas::Info; - } - - ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) { - return static_cast( static_cast( lhs ) | static_cast( rhs ) ); - } - - bool shouldContinueOnFailure( int flags ) { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; } - bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; } - bool shouldSuppressFailure( int flags ) { return ( flags & ResultDisposition::SuppressFail ) != 0; } - -} // end namespace Catch -// end catch_result_type.cpp -// start catch_run_context.cpp -// start catch_run_context.h - -#include - -namespace Catch { - - struct IMutableContext; - - class StreamRedirect { - - public: - StreamRedirect(std::ostream& stream, std::string& targetString); - - ~StreamRedirect(); - - private: - std::ostream& m_stream; - std::streambuf* m_prevBuf; - std::ostringstream m_oss; - std::string& m_targetString; - }; - - // StdErr has two constituent streams in C++, std::cerr and std::clog - // This means that we need to redirect 2 streams into 1 to keep proper - // order of writes and cannot use StreamRedirect on its own - class StdErrRedirect { - public: - StdErrRedirect(std::string& targetString); - ~StdErrRedirect(); - private: - std::streambuf* m_cerrBuf; - std::streambuf* m_clogBuf; - std::ostringstream m_oss; - std::string& m_targetString; - }; - - /////////////////////////////////////////////////////////////////////////// - - class RunContext : public IResultCapture, public IRunner { - - public: - RunContext( RunContext const& ) = delete; - RunContext& operator =( RunContext const& ) = delete; - - explicit RunContext(IConfigPtr const& _config, IStreamingReporterPtr&& reporter); - - virtual ~RunContext(); - - void testGroupStarting(std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount); - void testGroupEnded(std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount); - - Totals runTest(TestCase const& testCase); - - IConfigPtr config() const; - IStreamingReporter& reporter() const; - - private: // IResultCapture - - void assertionStarting(AssertionInfo const& info) override; - void assertionEnded(AssertionResult const& result) override; - - bool sectionStarted( SectionInfo const& sectionInfo, Counts& assertions ) override; - bool testForMissingAssertions(Counts& assertions); - - void sectionEnded(SectionEndInfo const& endInfo) override; - void sectionEndedEarly(SectionEndInfo const& endInfo) override; - - void benchmarkStarting( BenchmarkInfo const& info ) override; - void benchmarkEnded( BenchmarkStats const& stats ) override; - - void pushScopedMessage(MessageInfo const& message) override; - void popScopedMessage(MessageInfo const& message) override; - - std::string getCurrentTestName() const override; - - const AssertionResult* getLastResult() const override; - - void exceptionEarlyReported() override; - - void handleFatalErrorCondition( StringRef message ) override; - - bool lastAssertionPassed() override; - - void assertionPassed() override; - - void assertionRun() override; - - public: - // !TBD We need to do this another way! - bool aborting() const override; - - private: - - void runCurrentTest(std::string& redirectedCout, std::string& redirectedCerr); - void invokeActiveTestCase(); - - private: - - void handleUnfinishedSections(); - - TestRunInfo m_runInfo; - IMutableContext& m_context; - TestCase const* m_activeTestCase = nullptr; - ITracker* m_testCaseTracker; - Option m_lastResult; - - IConfigPtr m_config; - Totals m_totals; - IStreamingReporterPtr m_reporter; - std::vector m_messages; - AssertionInfo m_lastAssertionInfo; - std::vector m_unfinishedSections; - std::vector m_activeSections; - TrackerContext m_trackerContext; - std::size_t m_prevPassed = 0; - bool m_shouldReportUnexpected = true; - }; - - IResultCapture& getResultCapture(); - -} // end namespace Catch - -// end catch_run_context.h - -#include -#include - -namespace Catch { - - StreamRedirect::StreamRedirect(std::ostream& stream, std::string& targetString) - : m_stream(stream), - m_prevBuf(stream.rdbuf()), - m_targetString(targetString) { - stream.rdbuf(m_oss.rdbuf()); - } - - StreamRedirect::~StreamRedirect() { - m_targetString += m_oss.str(); - m_stream.rdbuf(m_prevBuf); - } - - StdErrRedirect::StdErrRedirect(std::string & targetString) - :m_cerrBuf(cerr().rdbuf()), m_clogBuf(clog().rdbuf()), - m_targetString(targetString) { - cerr().rdbuf(m_oss.rdbuf()); - clog().rdbuf(m_oss.rdbuf()); - } - - StdErrRedirect::~StdErrRedirect() { - m_targetString += m_oss.str(); - cerr().rdbuf(m_cerrBuf); - clog().rdbuf(m_clogBuf); - } - - RunContext::RunContext(IConfigPtr const& _config, IStreamingReporterPtr&& reporter) - : m_runInfo(_config->name()), - m_context(getCurrentMutableContext()), - m_config(_config), - m_reporter(std::move(reporter)), - m_lastAssertionInfo{ "", SourceLineInfo("",0), "", ResultDisposition::Normal } - { - m_context.setRunner(this); - m_context.setConfig(m_config); - m_context.setResultCapture(this); - m_reporter->testRunStarting(m_runInfo); - } - - RunContext::~RunContext() { - m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, aborting())); - } - - void RunContext::testGroupStarting(std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount) { - m_reporter->testGroupStarting(GroupInfo(testSpec, groupIndex, groupsCount)); - } - - void RunContext::testGroupEnded(std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount) { - m_reporter->testGroupEnded(TestGroupStats(GroupInfo(testSpec, groupIndex, groupsCount), totals, aborting())); - } - - Totals RunContext::runTest(TestCase const& testCase) { - Totals prevTotals = m_totals; - - std::string redirectedCout; - std::string redirectedCerr; - - TestCaseInfo testInfo = testCase.getTestCaseInfo(); - - m_reporter->testCaseStarting(testInfo); - - m_activeTestCase = &testCase; - - ITracker& rootTracker = m_trackerContext.startRun(); - assert(rootTracker.isSectionTracker()); - static_cast(rootTracker).addInitialFilters(m_config->getSectionsToRun()); - do { - m_trackerContext.startCycle(); - m_testCaseTracker = &SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocation(testInfo.name, testInfo.lineInfo)); - runCurrentTest(redirectedCout, redirectedCerr); - } while (!m_testCaseTracker->isSuccessfullyCompleted() && !aborting()); - - Totals deltaTotals = m_totals.delta(prevTotals); - if (testInfo.expectedToFail() && deltaTotals.testCases.passed > 0) { - deltaTotals.assertions.failed++; - deltaTotals.testCases.passed--; - deltaTotals.testCases.failed++; - } - m_totals.testCases += deltaTotals.testCases; - m_reporter->testCaseEnded(TestCaseStats(testInfo, - deltaTotals, - redirectedCout, - redirectedCerr, - aborting())); - - m_activeTestCase = nullptr; - m_testCaseTracker = nullptr; - - return deltaTotals; - } - - IConfigPtr RunContext::config() const { - return m_config; - } - - IStreamingReporter& RunContext::reporter() const { - return *m_reporter; - } - - void RunContext::assertionStarting(AssertionInfo const& info) { - m_reporter->assertionStarting( info ); - } - void RunContext::assertionEnded(AssertionResult const & result) { - if (result.getResultType() == ResultWas::Ok) { - m_totals.assertions.passed++; - } else if (!result.isOk()) { - if( m_activeTestCase->getTestCaseInfo().okToFail() ) - m_totals.assertions.failedButOk++; - else - m_totals.assertions.failed++; - } - - // We have no use for the return value (whether messages should be cleared), because messages were made scoped - // and should be let to clear themselves out. - static_cast(m_reporter->assertionEnded(AssertionStats(result, m_messages, m_totals))); - - // Reset working state - m_lastAssertionInfo = { "", m_lastAssertionInfo.lineInfo, "{Unknown expression after the reported line}", m_lastAssertionInfo.resultDisposition }; - m_lastResult = result; - } - - bool RunContext::sectionStarted(SectionInfo const & sectionInfo, Counts & assertions) { - ITracker& sectionTracker = SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocation(sectionInfo.name, sectionInfo.lineInfo)); - if (!sectionTracker.isOpen()) - return false; - m_activeSections.push_back(§ionTracker); - - m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo; - - m_reporter->sectionStarting(sectionInfo); - - assertions = m_totals.assertions; - - return true; - } - - bool RunContext::testForMissingAssertions(Counts& assertions) { - if (assertions.total() != 0) - return false; - if (!m_config->warnAboutMissingAssertions()) - return false; - if (m_trackerContext.currentTracker().hasChildren()) - return false; - m_totals.assertions.failed++; - assertions.failed++; - return true; - } - - void RunContext::sectionEnded(SectionEndInfo const & endInfo) { - Counts assertions = m_totals.assertions - endInfo.prevAssertions; - bool missingAssertions = testForMissingAssertions(assertions); - - if (!m_activeSections.empty()) { - m_activeSections.back()->close(); - m_activeSections.pop_back(); - } - - m_reporter->sectionEnded(SectionStats(endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions)); - m_messages.clear(); - } - - void RunContext::sectionEndedEarly(SectionEndInfo const & endInfo) { - if (m_unfinishedSections.empty()) - m_activeSections.back()->fail(); - else - m_activeSections.back()->close(); - m_activeSections.pop_back(); - - m_unfinishedSections.push_back(endInfo); - } - void RunContext::benchmarkStarting( BenchmarkInfo const& info ) { - m_reporter->benchmarkStarting( info ); - } - void RunContext::benchmarkEnded( BenchmarkStats const& stats ) { - m_reporter->benchmarkEnded( stats ); - } - - void RunContext::pushScopedMessage(MessageInfo const & message) { - m_messages.push_back(message); - } - - void RunContext::popScopedMessage(MessageInfo const & message) { - m_messages.erase(std::remove(m_messages.begin(), m_messages.end(), message), m_messages.end()); - } - - std::string RunContext::getCurrentTestName() const { - return m_activeTestCase - ? m_activeTestCase->getTestCaseInfo().name - : std::string(); - } - - const AssertionResult * RunContext::getLastResult() const { - return &(*m_lastResult); - } - - void RunContext::exceptionEarlyReported() { - m_shouldReportUnexpected = false; - } - - void RunContext::handleFatalErrorCondition( StringRef message ) { - // First notify reporter that bad things happened - m_reporter->fatalErrorEncountered(message); - - // Don't rebuild the result -- the stringification itself can cause more fatal errors - // Instead, fake a result data. - AssertionResultData tempResult( ResultWas::FatalErrorCondition, { false } ); - tempResult.message = message; - AssertionResult result(m_lastAssertionInfo, tempResult); - - getResultCapture().assertionEnded(result); - - handleUnfinishedSections(); - - // Recreate section for test case (as we will lose the one that was in scope) - auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); - SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description); - - Counts assertions; - assertions.failed = 1; - SectionStats testCaseSectionStats(testCaseSection, assertions, 0, false); - m_reporter->sectionEnded(testCaseSectionStats); - - auto const& testInfo = m_activeTestCase->getTestCaseInfo(); - - Totals deltaTotals; - deltaTotals.testCases.failed = 1; - deltaTotals.assertions.failed = 1; - m_reporter->testCaseEnded(TestCaseStats(testInfo, - deltaTotals, - std::string(), - std::string(), - false)); - m_totals.testCases.failed++; - testGroupEnded(std::string(), m_totals, 1, 1); - m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, false)); - } - - bool RunContext::lastAssertionPassed() { - return m_totals.assertions.passed == (m_prevPassed + 1); - } - - void RunContext::assertionPassed() { - ++m_totals.assertions.passed; - m_lastAssertionInfo.capturedExpression = "{Unknown expression after the reported line}"; - m_lastAssertionInfo.macroName = ""; - } - - void RunContext::assertionRun() { - m_prevPassed = m_totals.assertions.passed; - } - - bool RunContext::aborting() const { - return m_totals.assertions.failed == static_cast(m_config->abortAfter()); - } - - void RunContext::runCurrentTest(std::string & redirectedCout, std::string & redirectedCerr) { - auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); - SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description); - m_reporter->sectionStarting(testCaseSection); - Counts prevAssertions = m_totals.assertions; - double duration = 0; - m_shouldReportUnexpected = true; - try { - m_lastAssertionInfo = { "TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal }; - - seedRng(*m_config); - - Timer timer; - timer.start(); - if (m_reporter->getPreferences().shouldRedirectStdOut) { - StreamRedirect coutRedir(cout(), redirectedCout); - StdErrRedirect errRedir(redirectedCerr); - invokeActiveTestCase(); - } else { - invokeActiveTestCase(); + struct BySectionInfo { + BySectionInfo( SectionInfo const& other ) : m_other( other ) {} + BySectionInfo( BySectionInfo const& other ) : m_other( other.m_other ) {} + bool operator() ( Ptr const& node ) const { + return ((node->stats.sectionInfo.name == m_other.name) && + (node->stats.sectionInfo.lineInfo == m_other.lineInfo)); } - duration = timer.getElapsedSeconds(); - } catch (TestFailureException&) { - // This just means the test was aborted due to failure - } catch (...) { - // Under CATCH_CONFIG_FAST_COMPILE, unexpected exceptions under REQUIRE assertions - // are reported without translation at the point of origin. - if (m_shouldReportUnexpected) { - AssertionHandler - ( m_lastAssertionInfo.macroName, - m_lastAssertionInfo.lineInfo, - m_lastAssertionInfo.capturedExpression, - m_lastAssertionInfo.resultDisposition ).useActiveException(); - } - } - m_testCaseTracker->close(); - handleUnfinishedSections(); - m_messages.clear(); - - Counts assertions = m_totals.assertions - prevAssertions; - bool missingAssertions = testForMissingAssertions(assertions); - SectionStats testCaseSectionStats(testCaseSection, assertions, duration, missingAssertions); - m_reporter->sectionEnded(testCaseSectionStats); - } - - void RunContext::invokeActiveTestCase() { - FatalConditionHandler fatalConditionHandler; // Handle signals - m_activeTestCase->invoke(); - fatalConditionHandler.reset(); - } - - void RunContext::handleUnfinishedSections() { - // If sections ended prematurely due to an exception we stored their - // infos here so we can tear them down outside the unwind process. - for (auto it = m_unfinishedSections.rbegin(), - itEnd = m_unfinishedSections.rend(); - it != itEnd; - ++it) - sectionEnded(*it); - m_unfinishedSections.clear(); - } - - IResultCapture& getResultCapture() { - if (auto* capture = getCurrentContext().getResultCapture()) - return *capture; - else - CATCH_INTERNAL_ERROR("No result capture instance"); - } -} -// end catch_run_context.cpp -// start catch_section.cpp - -namespace Catch { - - Section::Section( SectionInfo const& info ) - : m_info( info ), - m_sectionIncluded( getResultCapture().sectionStarted( m_info, m_assertions ) ) - { - m_timer.start(); - } - -#if defined(_MSC_VER) -#pragma warning(push) -#pragma warning(disable:4996) // std::uncaught_exception is deprecated in C++17 -#endif - Section::~Section() { - if( m_sectionIncluded ) { - SectionEndInfo endInfo( m_info, m_assertions, m_timer.getElapsedSeconds() ); - if( std::uncaught_exception() ) - getResultCapture().sectionEndedEarly( endInfo ); - else - getResultCapture().sectionEnded( endInfo ); - } - } -#if defined(_MSC_VER) -#pragma warning(pop) -#endif - - // This indicates whether the section should be executed or not - Section::operator bool() const { - return m_sectionIncluded; - } - -} // end namespace Catch -// end catch_section.cpp -// start catch_section_info.cpp - -namespace Catch { - - SectionInfo::SectionInfo - ( SourceLineInfo const& _lineInfo, - std::string const& _name, - std::string const& _description ) - : name( _name ), - description( _description ), - lineInfo( _lineInfo ) - {} - - SectionEndInfo::SectionEndInfo( SectionInfo const& _sectionInfo, Counts const& _prevAssertions, double _durationInSeconds ) - : sectionInfo( _sectionInfo ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds ) - {} - -} // end namespace Catch -// end catch_section_info.cpp -// start catch_session.cpp - -// start catch_session.h - -#include - -namespace Catch { - - class Session : NonCopyable { - public: - - Session(); - ~Session() override; - - void showHelp() const; - void libIdentify(); - - int applyCommandLine( int argc, char* argv[] ); - - void useConfigData( ConfigData const& configData ); - - int run( int argc, char* argv[] ); - #if defined(WIN32) && defined(UNICODE) - int run( int argc, wchar_t* const argv[] ); - #endif - int run(); - - clara::Parser const& cli() const; - void cli( clara::Parser const& newParser ); - ConfigData& configData(); - Config& config(); - private: - int runInternal(); - - clara::Parser m_cli; - ConfigData m_configData; - std::shared_ptr m_config; - bool m_startupExceptions = false; - }; - -} // end namespace Catch - -// end catch_session.h -// start catch_version.h - -#include - -namespace Catch { - - // Versioning information - struct Version { - Version( Version const& ) = delete; - Version& operator=( Version const& ) = delete; - Version( unsigned int _majorVersion, - unsigned int _minorVersion, - unsigned int _patchNumber, - char const * const _branchName, - unsigned int _buildNumber ); - - unsigned int const majorVersion; - unsigned int const minorVersion; - unsigned int const patchNumber; - - // buildNumber is only used if branchName is not null - char const * const branchName; - unsigned int const buildNumber; - - friend std::ostream& operator << ( std::ostream& os, Version const& version ); - }; - - Version const& libraryVersion(); -} - -// end catch_version.h -#include -#include - -namespace { - const int MaxExitCode = 255; - using Catch::IStreamingReporterPtr; - using Catch::IConfigPtr; - using Catch::Config; - - IStreamingReporterPtr createReporter(std::string const& reporterName, IConfigPtr const& config) { - auto reporter = Catch::getRegistryHub().getReporterRegistry().create(reporterName, config); - CATCH_ENFORCE(reporter, "No reporter registered with name: '" << reporterName << "'"); - - return reporter; - } - -#ifndef CATCH_CONFIG_DEFAULT_REPORTER -#define CATCH_CONFIG_DEFAULT_REPORTER "console" -#endif - - IStreamingReporterPtr makeReporter(std::shared_ptr const& config) { - auto const& reporterNames = config->getReporterNames(); - if (reporterNames.empty()) - return createReporter(CATCH_CONFIG_DEFAULT_REPORTER, config); - - IStreamingReporterPtr reporter; - for (auto const& name : reporterNames) - addReporter(reporter, createReporter(name, config)); - return reporter; - } - -#undef CATCH_CONFIG_DEFAULT_REPORTER - - void addListeners(IStreamingReporterPtr& reporters, IConfigPtr const& config) { - auto const& listeners = Catch::getRegistryHub().getReporterRegistry().getListeners(); - for (auto const& listener : listeners) - addReporter(reporters, listener->create(Catch::ReporterConfig(config))); - } - - Catch::Totals runTests(std::shared_ptr const& config) { - using namespace Catch; - IStreamingReporterPtr reporter = makeReporter(config); - addListeners(reporter, config); - - RunContext context(config, std::move(reporter)); - - Totals totals; - - context.testGroupStarting(config->name(), 1, 1); - - TestSpec testSpec = config->testSpec(); - if (!testSpec.hasFilters()) - testSpec = TestSpecParser(ITagAliasRegistry::get()).parse("~[.]").testSpec(); // All not hidden tests - - auto const& allTestCases = getAllTestCasesSorted(*config); - for (auto const& testCase : allTestCases) { - if (!context.aborting() && matchTest(testCase, testSpec, *config)) - totals += context.runTest(testCase); - else - context.reporter().skipTest(testCase); - } - - context.testGroupEnded(config->name(), totals, 1, 1); - return totals; - } - - void applyFilenamesAsTags(Catch::IConfig const& config) { - using namespace Catch; - auto& tests = const_cast&>(getAllTestCasesSorted(config)); - for (auto& testCase : tests) { - auto tags = testCase.tags; - - std::string filename = testCase.lineInfo.file; - auto lastSlash = filename.find_last_of("\\/"); - if (lastSlash != std::string::npos) { - filename.erase(0, lastSlash); - filename[0] = '#'; - } - - auto lastDot = filename.find_last_of('.'); - if (lastDot != std::string::npos) { - filename.erase(lastDot); - } - - tags.push_back(std::move(filename)); - setTags(testCase, tags); - } - } - -} - -namespace Catch { - - Session::Session() { - static bool alreadyInstantiated = false; - if( alreadyInstantiated ) { - try { CATCH_INTERNAL_ERROR( "Only one instance of Catch::Session can ever be used" ); } - catch(...) { getMutableRegistryHub().registerStartupException(); } - } - - const auto& exceptions = getRegistryHub().getStartupExceptionRegistry().getExceptions(); - if ( !exceptions.empty() ) { - m_startupExceptions = true; - Colour colourGuard( Colour::Red ); - Catch::cerr() << "Errors occured during startup!" << '\n'; - // iterate over all exceptions and notify user - for ( const auto& ex_ptr : exceptions ) { - try { - std::rethrow_exception(ex_ptr); - } catch ( std::exception const& ex ) { - Catch::cerr() << Column( ex.what() ).indent(2) << '\n'; - } - } - } - - alreadyInstantiated = true; - m_cli = makeCommandLineParser( m_configData ); - } - Session::~Session() { - Catch::cleanUp(); - } - - void Session::showHelp() const { - Catch::cout() - << "\nCatch v" << libraryVersion() << "\n" - << m_cli << std::endl - << "For more detailed usage please see the project docs\n" << std::endl; - } - void Session::libIdentify() { - Catch::cout() - << std::left << std::setw(16) << "description: " << "A Catch test executable\n" - << std::left << std::setw(16) << "category: " << "testframework\n" - << std::left << std::setw(16) << "framework: " << "Catch Test\n" - << std::left << std::setw(16) << "version: " << libraryVersion() << std::endl; - } - - int Session::applyCommandLine( int argc, char* argv[] ) { - if( m_startupExceptions ) - return 1; - - auto result = m_cli.parse( clara::Args( argc, argv ) ); - if( !result ) { - Catch::cerr() - << Colour( Colour::Red ) - << "\nError(s) in input:\n" - << Column( result.errorMessage() ).indent( 2 ) - << "\n\n"; - Catch::cerr() << "Run with -? for usage\n" << std::endl; - return MaxExitCode; - } - - if( m_configData.showHelp ) - showHelp(); - if( m_configData.libIdentify ) - libIdentify(); - m_config.reset(); - return 0; - } - - void Session::useConfigData( ConfigData const& configData ) { - m_configData = configData; - m_config.reset(); - } - - int Session::run( int argc, char* argv[] ) { - if( m_startupExceptions ) - return 1; - int returnCode = applyCommandLine( argc, argv ); - if( returnCode == 0 ) - returnCode = run(); - return returnCode; - } - -#if defined(WIN32) && defined(UNICODE) - int Session::run( int argc, wchar_t* const argv[] ) { - - char **utf8Argv = new char *[ argc ]; - - for ( int i = 0; i < argc; ++i ) { - int bufSize = WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, NULL, 0, NULL, NULL ); - - utf8Argv[ i ] = new char[ bufSize ]; - - WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, NULL, NULL ); - } - - int returnCode = run( argc, utf8Argv ); - - for ( int i = 0; i < argc; ++i ) - delete [] utf8Argv[ i ]; - - delete [] utf8Argv; - - return returnCode; - } -#endif - int Session::run() { - if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeStart ) != 0 ) { - Catch::cout() << "...waiting for enter/ return before starting" << std::endl; - static_cast(std::getchar()); - } - int exitCode = runInternal(); - if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeExit ) != 0 ) { - Catch::cout() << "...waiting for enter/ return before exiting, with code: " << exitCode << std::endl; - static_cast(std::getchar()); - } - return exitCode; - } - - clara::Parser const& Session::cli() const { - return m_cli; - } - void Session::cli( clara::Parser const& newParser ) { - m_cli = newParser; - } - ConfigData& Session::configData() { - return m_configData; - } - Config& Session::config() { - if( !m_config ) - m_config = std::make_shared( m_configData ); - return *m_config; - } - - int Session::runInternal() { - if( m_startupExceptions ) - return 1; - - if( m_configData.showHelp || m_configData.libIdentify ) - return 0; - - try + private: + void operator=( BySectionInfo const& ); + SectionInfo const& m_other; + }; + + typedef Node TestCaseNode; + typedef Node TestGroupNode; + typedef Node TestRunNode; + + CumulativeReporterBase( ReporterConfig const& _config ) + : m_config( _config.fullConfig() ), + stream( _config.stream() ) { - config(); // Force config to be constructed - - seedRng( *m_config ); - - if( m_configData.filenamesAsTags ) - applyFilenamesAsTags( *m_config ); - - // Handle list request - if( Option listed = list( config() ) ) - return static_cast( *listed ); - - return (std::min)( MaxExitCode, static_cast( runTests( m_config ).assertions.failed ) ); + m_reporterPrefs.shouldRedirectStdOut = false; } - catch( std::exception& ex ) { - Catch::cerr() << ex.what() << std::endl; - return MaxExitCode; - } - } + ~CumulativeReporterBase(); -} // end namespace Catch -// end catch_session.cpp -// start catch_startup_exception_registry.cpp - -namespace Catch { - void StartupExceptionRegistry::add( std::exception_ptr const& exception ) noexcept { - try { - m_exceptions.push_back(exception); - } - catch(...) { - // If we run out of memory during start-up there's really not a lot more we can do about it - std::terminate(); - } - } - - std::vector const& StartupExceptionRegistry::getExceptions() const noexcept { - return m_exceptions; - } - -} // end namespace Catch -// end catch_startup_exception_registry.cpp -// start catch_stream.cpp - -#include -#include -#include - -namespace Catch { - - template - class StreamBufImpl : public StreamBufBase { - char data[bufferSize]; - WriterF m_writer; - - public: - StreamBufImpl() { - setp( data, data + sizeof(data) ); + virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE { + return m_reporterPrefs; } - ~StreamBufImpl() noexcept { - StreamBufImpl::sync(); - } + virtual void testRunStarting( TestRunInfo const& ) CATCH_OVERRIDE {} + virtual void testGroupStarting( GroupInfo const& ) CATCH_OVERRIDE {} - private: - int overflow( int c ) override { - sync(); + virtual void testCaseStarting( TestCaseInfo const& ) CATCH_OVERRIDE {} - if( c != EOF ) { - if( pbase() == epptr() ) - m_writer( std::string( 1, static_cast( c ) ) ); - else - sputc( static_cast( c ) ); - } - return 0; - } - - int sync() override { - if( pbase() != pptr() ) { - m_writer( std::string( pbase(), static_cast( pptr() - pbase() ) ) ); - setp( pbase(), epptr() ); - } - return 0; - } - }; - - /////////////////////////////////////////////////////////////////////////// - - Catch::IStream::~IStream() = default; - - FileStream::FileStream( std::string const& filename ) { - m_ofs.open( filename.c_str() ); - CATCH_ENFORCE( !m_ofs.fail(), "Unable to open file: '" << filename << "'" ); - } - - std::ostream& FileStream::stream() const { - return m_ofs; - } - - struct OutputDebugWriter { - - void operator()( std::string const&str ) { - writeToDebugConsole( str ); - } - }; - - DebugOutStream::DebugOutStream() - : m_streamBuf( new StreamBufImpl() ), - m_os( m_streamBuf.get() ) - {} - - std::ostream& DebugOutStream::stream() const { - return m_os; - } - - // Store the streambuf from cout up-front because - // cout may get redirected when running tests - CoutStream::CoutStream() - : m_os( Catch::cout().rdbuf() ) - {} - - std::ostream& CoutStream::stream() const { - return m_os; - } - -#ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement these functions - std::ostream& cout() { - return std::cout; - } - std::ostream& cerr() { - return std::cerr; - } - std::ostream& clog() { - return std::clog; - } -#endif -} -// end catch_stream.cpp -// start catch_streambuf.cpp - -namespace Catch { - StreamBufBase::~StreamBufBase() = default; -} -// end catch_streambuf.cpp -// start catch_string_manip.cpp - -#include -#include -#include -#include - -namespace Catch { - - bool startsWith( std::string const& s, std::string const& prefix ) { - return s.size() >= prefix.size() && std::equal(prefix.begin(), prefix.end(), s.begin()); - } - bool startsWith( std::string const& s, char prefix ) { - return !s.empty() && s[0] == prefix; - } - bool endsWith( std::string const& s, std::string const& suffix ) { - return s.size() >= suffix.size() && std::equal(suffix.rbegin(), suffix.rend(), s.rbegin()); - } - bool endsWith( std::string const& s, char suffix ) { - return !s.empty() && s[s.size()-1] == suffix; - } - bool contains( std::string const& s, std::string const& infix ) { - return s.find( infix ) != std::string::npos; - } - char toLowerCh(char c) { - return static_cast( std::tolower( c ) ); - } - void toLowerInPlace( std::string& s ) { - std::transform( s.begin(), s.end(), s.begin(), toLowerCh ); - } - std::string toLower( std::string const& s ) { - std::string lc = s; - toLowerInPlace( lc ); - return lc; - } - std::string trim( std::string const& str ) { - static char const* whitespaceChars = "\n\r\t "; - std::string::size_type start = str.find_first_not_of( whitespaceChars ); - std::string::size_type end = str.find_last_not_of( whitespaceChars ); - - return start != std::string::npos ? str.substr( start, 1+end-start ) : std::string(); - } - - bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) { - bool replaced = false; - std::size_t i = str.find( replaceThis ); - while( i != std::string::npos ) { - replaced = true; - str = str.substr( 0, i ) + withThis + str.substr( i+replaceThis.size() ); - if( i < str.size()-withThis.size() ) - i = str.find( replaceThis, i+withThis.size() ); - else - i = std::string::npos; - } - return replaced; - } - - pluralise::pluralise( std::size_t count, std::string const& label ) - : m_count( count ), - m_label( label ) - {} - - std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) { - os << pluraliser.m_count << ' ' << pluraliser.m_label; - if( pluraliser.m_count != 1 ) - os << 's'; - return os; - } - -} -// end catch_string_manip.cpp -// start catch_stringref.cpp - -#if defined(__clang__) -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wexit-time-destructors" -#endif - -#include -#include -#include - -namespace Catch { - - auto getEmptyStringRef() -> StringRef { - static StringRef s_emptyStringRef(""); - return s_emptyStringRef; - } - - StringRef::StringRef() noexcept - : StringRef( getEmptyStringRef() ) - {} - - StringRef::StringRef( StringRef const& other ) noexcept - : m_start( other.m_start ), - m_size( other.m_size ) - {} - - StringRef::StringRef( StringRef&& other ) noexcept - : m_start( other.m_start ), - m_size( other.m_size ), - m_data( other.m_data ) - { - other.m_data = nullptr; - } - - StringRef::StringRef( char const* rawChars ) noexcept - : m_start( rawChars ), - m_size( static_cast( std::strlen( rawChars ) ) ) - { - assert( rawChars != nullptr ); - } - - StringRef::StringRef( char const* rawChars, size_type size ) noexcept - : m_start( rawChars ), - m_size( size ) - { - size_type rawSize = rawChars == nullptr ? 0 : static_cast( std::strlen( rawChars ) ); - if( rawSize < size ) - m_size = rawSize; - } - - StringRef::StringRef( std::string const& stdString ) noexcept - : m_start( stdString.c_str() ), - m_size( stdString.size() ) - {} - - StringRef::~StringRef() noexcept { - delete[] m_data; - } - - auto StringRef::operator = ( StringRef other ) noexcept -> StringRef& { - swap( other ); - return *this; - } - StringRef::operator std::string() const { - return std::string( m_start, m_size ); - } - - void StringRef::swap( StringRef& other ) noexcept { - std::swap( m_start, other.m_start ); - std::swap( m_size, other.m_size ); - std::swap( m_data, other.m_data ); - } - - auto StringRef::c_str() const -> char const* { - if( isSubstring() ) - const_cast( this )->takeOwnership(); - return m_start; - } - auto StringRef::data() const noexcept -> char const* { - return m_start; - } - - auto StringRef::isOwned() const noexcept -> bool { - return m_data != nullptr; - } - auto StringRef::isSubstring() const noexcept -> bool { - return m_start[m_size] != '\0'; - } - - void StringRef::takeOwnership() { - if( !isOwned() ) { - m_data = new char[m_size+1]; - memcpy( m_data, m_start, m_size ); - m_data[m_size] = '\0'; - m_start = m_data; - } - } - auto StringRef::substr( size_type start, size_type size ) const noexcept -> StringRef { - if( start < m_size ) - return StringRef( m_start+start, size ); - else - return StringRef(); - } - auto StringRef::operator == ( StringRef const& other ) const noexcept -> bool { - return - size() == other.size() && - (std::strncmp( m_start, other.m_start, size() ) == 0); - } - auto StringRef::operator != ( StringRef const& other ) const noexcept -> bool { - return !operator==( other ); - } - - auto StringRef::operator[](size_type index) const noexcept -> char { - return m_start[index]; - } - - auto StringRef::empty() const noexcept -> bool { - return m_size == 0; - } - - auto StringRef::size() const noexcept -> size_type { - return m_size; - } - auto StringRef::numberOfCharacters() const noexcept -> size_type { - size_type noChars = m_size; - // Make adjustments for uft encodings - for( size_type i=0; i < m_size; ++i ) { - char c = m_start[i]; - if( ( c & 0b11000000 ) == 0b11000000 ) { - if( ( c & 0b11100000 ) == 0b11000000 ) - noChars--; - else if( ( c & 0b11110000 ) == 0b11100000 ) - noChars-=2; - else if( ( c & 0b11111000 ) == 0b11110000 ) - noChars-=3; - } - } - return noChars; - } - - auto operator + ( StringRef const& lhs, StringRef const& rhs ) -> std::string { - std::string str; - str.reserve( lhs.size() + rhs.size() ); - str += lhs; - str += rhs; - return str; - } - auto operator + ( StringRef const& lhs, const char* rhs ) -> std::string { - return std::string( lhs ) + std::string( rhs ); - } - auto operator + ( char const* lhs, StringRef const& rhs ) -> std::string { - return std::string( lhs ) + std::string( rhs ); - } - - auto operator << ( std::ostream& os, StringRef const& str ) -> std::ostream& { - return os << str.c_str(); - } - -} // namespace Catch - -#if defined(__clang__) -# pragma clang diagnostic pop -#endif -// end catch_stringref.cpp -// start catch_tag_alias.cpp - -namespace Catch { - TagAlias::TagAlias(std::string const & _tag, SourceLineInfo _lineInfo): tag(_tag), lineInfo(_lineInfo) {} -} -// end catch_tag_alias.cpp -// start catch_tag_alias_autoregistrar.cpp - -namespace Catch { - - RegistrarForTagAliases::RegistrarForTagAliases(char const* alias, char const* tag, SourceLineInfo const& lineInfo) { - try { - getMutableRegistryHub().registerTagAlias(alias, tag, lineInfo); - } catch (...) { - // Do not throw when constructing global objects, instead register the exception to be processed later - getMutableRegistryHub().registerStartupException(); - } - } - -} -// end catch_tag_alias_autoregistrar.cpp -// start catch_tag_alias_registry.cpp - -namespace Catch { - - TagAliasRegistry::~TagAliasRegistry() {} - - TagAlias const* TagAliasRegistry::find( std::string const& alias ) const { - auto it = m_registry.find( alias ); - if( it != m_registry.end() ) - return &(it->second); - else - return nullptr; - } - - std::string TagAliasRegistry::expandAliases( std::string const& unexpandedTestSpec ) const { - std::string expandedTestSpec = unexpandedTestSpec; - for( auto const& registryKvp : m_registry ) { - std::size_t pos = expandedTestSpec.find( registryKvp.first ); - if( pos != std::string::npos ) { - expandedTestSpec = expandedTestSpec.substr( 0, pos ) + - registryKvp.second.tag + - expandedTestSpec.substr( pos + registryKvp.first.size() ); - } - } - return expandedTestSpec; - } - - void TagAliasRegistry::add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) { - CATCH_ENFORCE( startsWith(alias, "[@") && endsWith(alias, ']'), - "error: tag alias, '" << alias << "' is not of the form [@alias name].\n" << lineInfo ); - - CATCH_ENFORCE( m_registry.insert(std::make_pair(alias, TagAlias(tag, lineInfo))).second, - "error: tag alias, '" << alias << "' already registered.\n" - << "\tFirst seen at: " << find(alias)->lineInfo << "\n" - << "\tRedefined at: " << lineInfo ); - } - - ITagAliasRegistry::~ITagAliasRegistry() {} - - ITagAliasRegistry const& ITagAliasRegistry::get() { - return getRegistryHub().getTagAliasRegistry(); - } - -} // end namespace Catch -// end catch_tag_alias_registry.cpp -// start catch_test_case_info.cpp - -#include -#include -#include - -namespace Catch { - - TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) { - if( startsWith( tag, '.' ) || - tag == "!hide" ) - return TestCaseInfo::IsHidden; - else if( tag == "!throws" ) - return TestCaseInfo::Throws; - else if( tag == "!shouldfail" ) - return TestCaseInfo::ShouldFail; - else if( tag == "!mayfail" ) - return TestCaseInfo::MayFail; - else if( tag == "!nonportable" ) - return TestCaseInfo::NonPortable; - else if( tag == "!benchmark" ) - return static_cast( TestCaseInfo::Benchmark | TestCaseInfo::IsHidden ); - else - return TestCaseInfo::None; - } - bool isReservedTag( std::string const& tag ) { - return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !std::isalnum( tag[0] ); - } - void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) { - CATCH_ENFORCE( !isReservedTag(tag), - "Tag name: [" << tag << "] is not allowed.\n" - << "Tag names starting with non alpha-numeric characters are reserved\n" - << _lineInfo ); - } - - TestCase makeTestCase( ITestInvoker* _testCase, - std::string const& _className, - std::string const& _name, - std::string const& _descOrTags, - SourceLineInfo const& _lineInfo ) - { - bool isHidden = false; - - // Parse out tags - std::vector tags; - std::string desc, tag; - bool inTag = false; - for (char c : _descOrTags) { - if( !inTag ) { - if( c == '[' ) - inTag = true; - else - desc += c; + virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE { + SectionStats incompleteStats( sectionInfo, Counts(), 0, false ); + Ptr node; + if( m_sectionStack.empty() ) { + if( !m_rootSection ) + m_rootSection = new SectionNode( incompleteStats ); + node = m_rootSection; } else { - if( c == ']' ) { - TestCaseInfo::SpecialProperties prop = parseSpecialTag( tag ); - if( ( prop & TestCaseInfo::IsHidden ) != 0 ) - isHidden = true; - else if( prop == TestCaseInfo::None ) - enforceNotReservedTag( tag, _lineInfo ); - - tags.push_back( tag ); - tag.clear(); - inTag = false; + SectionNode& parentNode = *m_sectionStack.back(); + SectionNode::ChildSections::const_iterator it = + std::find_if( parentNode.childSections.begin(), + parentNode.childSections.end(), + BySectionInfo( sectionInfo ) ); + if( it == parentNode.childSections.end() ) { + node = new SectionNode( incompleteStats ); + parentNode.childSections.push_back( node ); } else - tag += c; + node = *it; } - } - if( isHidden ) { - tags.push_back( "." ); + m_sectionStack.push_back( node ); + m_deepestSection = node; } - TestCaseInfo info( _name, _className, desc, tags, _lineInfo ); - return TestCase( _testCase, info ); - } + virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {} - void setTags( TestCaseInfo& testCaseInfo, std::vector tags ) { - std::sort(begin(tags), end(tags)); - tags.erase(std::unique(begin(tags), end(tags)), end(tags)); - testCaseInfo.lcaseTags.clear(); - - for( auto const& tag : tags ) { - std::string lcaseTag = toLower( tag ); - testCaseInfo.properties = static_cast( testCaseInfo.properties | parseSpecialTag( lcaseTag ) ); - testCaseInfo.lcaseTags.push_back( lcaseTag ); + virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { + assert( !m_sectionStack.empty() ); + SectionNode& sectionNode = *m_sectionStack.back(); + sectionNode.assertions.push_back( assertionStats ); + // AssertionResult holds a pointer to a temporary DecomposedExpression, + // which getExpandedExpression() calls to build the expression string. + // Our section stack copy of the assertionResult will likely outlive the + // temporary, so it must be expanded or discarded now to avoid calling + // a destroyed object later. + prepareExpandedExpression( sectionNode.assertions.back().assertionResult ); + return true; } - testCaseInfo.tags = std::move(tags); - } - - TestCaseInfo::TestCaseInfo( std::string const& _name, - std::string const& _className, - std::string const& _description, - std::vector const& _tags, - SourceLineInfo const& _lineInfo ) - : name( _name ), - className( _className ), - description( _description ), - lineInfo( _lineInfo ), - properties( None ) - { - setTags( *this, _tags ); - } - - bool TestCaseInfo::isHidden() const { - return ( properties & IsHidden ) != 0; - } - bool TestCaseInfo::throws() const { - return ( properties & Throws ) != 0; - } - bool TestCaseInfo::okToFail() const { - return ( properties & (ShouldFail | MayFail ) ) != 0; - } - bool TestCaseInfo::expectedToFail() const { - return ( properties & (ShouldFail ) ) != 0; - } - - std::string TestCaseInfo::tagsAsString() const { - std::string ret; - // '[' and ']' per tag - std::size_t full_size = 2 * tags.size(); - for (const auto& tag : tags) { - full_size += tag.size(); + virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE { + assert( !m_sectionStack.empty() ); + SectionNode& node = *m_sectionStack.back(); + node.stats = sectionStats; + m_sectionStack.pop_back(); } - ret.reserve(full_size); - for (const auto& tag : tags) { - ret.push_back('['); - ret.append(tag); - ret.push_back(']'); + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { + Ptr node = new TestCaseNode( testCaseStats ); + assert( m_sectionStack.size() == 0 ); + node->children.push_back( m_rootSection ); + m_testCases.push_back( node ); + m_rootSection.reset(); + + assert( m_deepestSection ); + m_deepestSection->stdOut = testCaseStats.stdOut; + m_deepestSection->stdErr = testCaseStats.stdErr; + } + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { + Ptr node = new TestGroupNode( testGroupStats ); + node->children.swap( m_testCases ); + m_testGroups.push_back( node ); + } + virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE { + Ptr node = new TestRunNode( testRunStats ); + node->children.swap( m_testGroups ); + m_testRuns.push_back( node ); + testRunEndedCumulative(); + } + virtual void testRunEndedCumulative() = 0; + + virtual void skipTest( TestCaseInfo const& ) CATCH_OVERRIDE {} + + virtual void prepareExpandedExpression( AssertionResult& result ) const { + if( result.isOk() ) + result.discardDecomposedExpression(); + else + result.expandDecomposedExpression(); } - return ret; + Ptr m_config; + std::ostream& stream; + std::vector m_assertions; + std::vector > > m_sections; + std::vector > m_testCases; + std::vector > m_testGroups; + + std::vector > m_testRuns; + + Ptr m_rootSection; + Ptr m_deepestSection; + std::vector > m_sectionStack; + ReporterPreferences m_reporterPrefs; + + }; + + template + char const* getLineOfChars() { + static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0}; + if( !*line ) { + std::memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 ); + line[CATCH_CONFIG_CONSOLE_WIDTH-1] = 0; + } + return line; } - TestCase::TestCase( ITestInvoker* testCase, TestCaseInfo const& info ) : TestCaseInfo( info ), test( testCase ) {} + struct TestEventListenerBase : StreamingReporterBase { + TestEventListenerBase( ReporterConfig const& _config ) + : StreamingReporterBase( _config ) + {} - TestCase TestCase::withName( std::string const& _newName ) const { - TestCase other( *this ); - other.name = _newName; - return other; - } - - void TestCase::invoke() const { - test->invoke(); - } - - bool TestCase::operator == ( TestCase const& other ) const { - return test.get() == other.test.get() && - name == other.name && - className == other.className; - } - - bool TestCase::operator < ( TestCase const& other ) const { - return name < other.name; - } - - TestCaseInfo const& TestCase::getTestCaseInfo() const - { - return *this; - } + virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {} + virtual bool assertionEnded( AssertionStats const& ) CATCH_OVERRIDE { + return false; + } + }; } // end namespace Catch -// end catch_test_case_info.cpp -// start catch_test_case_registry_impl.cpp -#include +// #included from: ../internal/catch_reporter_registrars.hpp +#define TWOBLUECUBES_CATCH_REPORTER_REGISTRARS_HPP_INCLUDED namespace Catch { - std::vector sortTests( IConfig const& config, std::vector const& unsortedTestCases ) { + template + class LegacyReporterRegistrar { - std::vector sorted = unsortedTestCases; - - switch( config.runOrder() ) { - case RunTests::InLexicographicalOrder: - std::sort( sorted.begin(), sorted.end() ); - break; - case RunTests::InRandomOrder: - seedRng( config ); - RandomNumberGenerator::shuffle( sorted ); - break; - case RunTests::InDeclarationOrder: - // already in declaration order - break; - } - return sorted; - } - bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ) { - return testSpec.matches( testCase ) && ( config.allowThrows() || !testCase.throws() ); - } - - void enforceNoDuplicateTestCases( std::vector const& functions ) { - std::set seenFunctions; - for( auto const& function : functions ) { - auto prev = seenFunctions.insert( function ); - CATCH_ENFORCE( prev.second, - "error: TEST_CASE( \"" << function.name << "\" ) already defined.\n" - << "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << "\n" - << "\tRedefined at " << function.getTestCaseInfo().lineInfo ); - } - } - - std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ) { - std::vector filtered; - filtered.reserve( testCases.size() ); - for( auto const& testCase : testCases ) - if( matchTest( testCase, testSpec, config ) ) - filtered.push_back( testCase ); - return filtered; - } - std::vector const& getAllTestCasesSorted( IConfig const& config ) { - return getRegistryHub().getTestCaseRegistry().getAllTestsSorted( config ); - } - - void TestRegistry::registerTest( TestCase const& testCase ) { - std::string name = testCase.getTestCaseInfo().name; - if( name.empty() ) { - std::ostringstream oss; - oss << "Anonymous test case " << ++m_unnamedCount; - return registerTest( testCase.withName( oss.str() ) ); - } - m_functions.push_back( testCase ); - } - - std::vector const& TestRegistry::getAllTests() const { - return m_functions; - } - std::vector const& TestRegistry::getAllTestsSorted( IConfig const& config ) const { - if( m_sortedFunctions.empty() ) - enforceNoDuplicateTestCases( m_functions ); - - if( m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty() ) { - m_sortedFunctions = sortTests( config, m_functions ); - m_currentSortOrder = config.runOrder(); - } - return m_sortedFunctions; - } - - /////////////////////////////////////////////////////////////////////////// - TestInvokerAsFunction::TestInvokerAsFunction( void(*testAsFunction)() ) noexcept : m_testAsFunction( testAsFunction ) {} - - void TestInvokerAsFunction::invoke() const { - m_testAsFunction(); - } - - std::string extractClassName( std::string const& classOrQualifiedMethodName ) { - std::string className = classOrQualifiedMethodName; - if( startsWith( className, '&' ) ) - { - std::size_t lastColons = className.rfind( "::" ); - std::size_t penultimateColons = className.rfind( "::", lastColons-1 ); - if( penultimateColons == std::string::npos ) - penultimateColons = 1; - className = className.substr( penultimateColons, lastColons-penultimateColons ); - } - return className; - } - -} // end namespace Catch -// end catch_test_case_registry_impl.cpp -// start catch_test_case_tracker.cpp - -#include -#include -#include -#include - -#if defined(__clang__) -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wexit-time-destructors" -#endif - -namespace Catch { -namespace TestCaseTracking { - - NameAndLocation::NameAndLocation( std::string const& _name, SourceLineInfo const& _location ) - : name( _name ), - location( _location ) - {} - - ITracker::~ITracker() = default; - - TrackerContext& TrackerContext::instance() { - static TrackerContext s_instance; - return s_instance; - } - - ITracker& TrackerContext::startRun() { - m_rootTracker = std::make_shared( NameAndLocation( "{root}", CATCH_INTERNAL_LINEINFO ), *this, nullptr ); - m_currentTracker = nullptr; - m_runState = Executing; - return *m_rootTracker; - } - - void TrackerContext::endRun() { - m_rootTracker.reset(); - m_currentTracker = nullptr; - m_runState = NotStarted; - } - - void TrackerContext::startCycle() { - m_currentTracker = m_rootTracker.get(); - m_runState = Executing; - } - void TrackerContext::completeCycle() { - m_runState = CompletedCycle; - } - - bool TrackerContext::completedCycle() const { - return m_runState == CompletedCycle; - } - ITracker& TrackerContext::currentTracker() { - return *m_currentTracker; - } - void TrackerContext::setCurrentTracker( ITracker* tracker ) { - m_currentTracker = tracker; - } - - TrackerBase::TrackerHasName::TrackerHasName( NameAndLocation const& nameAndLocation ) : m_nameAndLocation( nameAndLocation ) {} - bool TrackerBase::TrackerHasName::operator ()( ITrackerPtr const& tracker ) const { - return - tracker->nameAndLocation().name == m_nameAndLocation.name && - tracker->nameAndLocation().location == m_nameAndLocation.location; - } - - TrackerBase::TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ) - : m_nameAndLocation( nameAndLocation ), - m_ctx( ctx ), - m_parent( parent ) - {} - - NameAndLocation const& TrackerBase::nameAndLocation() const { - return m_nameAndLocation; - } - bool TrackerBase::isComplete() const { - return m_runState == CompletedSuccessfully || m_runState == Failed; - } - bool TrackerBase::isSuccessfullyCompleted() const { - return m_runState == CompletedSuccessfully; - } - bool TrackerBase::isOpen() const { - return m_runState != NotStarted && !isComplete(); - } - bool TrackerBase::hasChildren() const { - return !m_children.empty(); - } - - void TrackerBase::addChild( ITrackerPtr const& child ) { - m_children.push_back( child ); - } - - ITrackerPtr TrackerBase::findChild( NameAndLocation const& nameAndLocation ) { - auto it = std::find_if( m_children.begin(), m_children.end(), TrackerHasName( nameAndLocation ) ); - return( it != m_children.end() ) - ? *it - : nullptr; - } - ITracker& TrackerBase::parent() { - assert( m_parent ); // Should always be non-null except for root - return *m_parent; - } - - void TrackerBase::openChild() { - if( m_runState != ExecutingChildren ) { - m_runState = ExecutingChildren; - if( m_parent ) - m_parent->openChild(); - } - } - - bool TrackerBase::isSectionTracker() const { return false; } - bool TrackerBase::isIndexTracker() const { return false; } - - void TrackerBase::open() { - m_runState = Executing; - moveToThis(); - if( m_parent ) - m_parent->openChild(); - } - - void TrackerBase::close() { - - // Close any still open children (e.g. generators) - while( &m_ctx.currentTracker() != this ) - m_ctx.currentTracker().close(); - - switch( m_runState ) { - case NeedsAnotherRun: - break; - - case Executing: - m_runState = CompletedSuccessfully; - break; - case ExecutingChildren: - if( m_children.empty() || m_children.back()->isComplete() ) - m_runState = CompletedSuccessfully; - break; - - case NotStarted: - case CompletedSuccessfully: - case Failed: - CATCH_INTERNAL_ERROR( "Illogical state: " << m_runState ); - - default: - CATCH_INTERNAL_ERROR( "Unknown state: " << m_runState ); - } - moveToParent(); - m_ctx.completeCycle(); - } - void TrackerBase::fail() { - m_runState = Failed; - if( m_parent ) - m_parent->markAsNeedingAnotherRun(); - moveToParent(); - m_ctx.completeCycle(); - } - void TrackerBase::markAsNeedingAnotherRun() { - m_runState = NeedsAnotherRun; - } - - void TrackerBase::moveToParent() { - assert( m_parent ); - m_ctx.setCurrentTracker( m_parent ); - } - void TrackerBase::moveToThis() { - m_ctx.setCurrentTracker( this ); - } - - SectionTracker::SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ) - : TrackerBase( nameAndLocation, ctx, parent ) - { - if( parent ) { - while( !parent->isSectionTracker() ) - parent = &parent->parent(); - - SectionTracker& parentSection = static_cast( *parent ); - addNextFilters( parentSection.m_filters ); - } - } - - bool SectionTracker::isSectionTracker() const { return true; } - - SectionTracker& SectionTracker::acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ) { - std::shared_ptr section; - - ITracker& currentTracker = ctx.currentTracker(); - if( ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) { - assert( childTracker ); - assert( childTracker->isSectionTracker() ); - section = std::static_pointer_cast( childTracker ); - } - else { - section = std::make_shared( nameAndLocation, ctx, ¤tTracker ); - currentTracker.addChild( section ); - } - if( !ctx.completedCycle() ) - section->tryOpen(); - return *section; - } - - void SectionTracker::tryOpen() { - if( !isComplete() && (m_filters.empty() || m_filters[0].empty() || m_filters[0] == m_nameAndLocation.name ) ) - open(); - } - - void SectionTracker::addInitialFilters( std::vector const& filters ) { - if( !filters.empty() ) { - m_filters.push_back(""); // Root - should never be consulted - m_filters.push_back(""); // Test Case - not a section filter - m_filters.insert( m_filters.end(), filters.begin(), filters.end() ); - } - } - void SectionTracker::addNextFilters( std::vector const& filters ) { - if( filters.size() > 1 ) - m_filters.insert( m_filters.end(), ++filters.begin(), filters.end() ); - } - - IndexTracker::IndexTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent, int size ) - : TrackerBase( nameAndLocation, ctx, parent ), - m_size( size ) - {} - - bool IndexTracker::isIndexTracker() const { return true; } - - IndexTracker& IndexTracker::acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation, int size ) { - std::shared_ptr tracker; - - ITracker& currentTracker = ctx.currentTracker(); - if( ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) { - assert( childTracker ); - assert( childTracker->isIndexTracker() ); - tracker = std::static_pointer_cast( childTracker ); - } - else { - tracker = std::make_shared( nameAndLocation, ctx, ¤tTracker, size ); - currentTracker.addChild( tracker ); - } - - if( !ctx.completedCycle() && !tracker->isComplete() ) { - if( tracker->m_runState != ExecutingChildren && tracker->m_runState != NeedsAnotherRun ) - tracker->moveNext(); - tracker->open(); - } - - return *tracker; - } - - int IndexTracker::index() const { return m_index; } - - void IndexTracker::moveNext() { - m_index++; - m_children.clear(); - } - - void IndexTracker::close() { - TrackerBase::close(); - if( m_runState == CompletedSuccessfully && m_index < m_size-1 ) - m_runState = Executing; - } - -} // namespace TestCaseTracking - -using TestCaseTracking::ITracker; -using TestCaseTracking::TrackerContext; -using TestCaseTracking::SectionTracker; -using TestCaseTracking::IndexTracker; - -} // namespace Catch - -#if defined(__clang__) -# pragma clang diagnostic pop -#endif -// end catch_test_case_tracker.cpp -// start catch_test_registry.cpp - -namespace Catch { - - auto makeTestInvoker( void(*testAsFunction)() ) noexcept -> ITestInvoker* { - return new(std::nothrow) TestInvokerAsFunction( testAsFunction ); - } - - NameAndTags::NameAndTags( StringRef name_ , StringRef tags_ ) noexcept : name( name_ ), tags( tags_ ) {} - - AutoReg::AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef classOrMethod, NameAndTags const& nameAndTags ) noexcept { - try { - getMutableRegistryHub() - .registerTest( - makeTestCase( - invoker, - extractClassName( classOrMethod ), - nameAndTags.name, - nameAndTags.tags, - lineInfo)); - } catch (...) { - // Do not throw when constructing global objects, instead register the exception to be processed later - getMutableRegistryHub().registerStartupException(); - } - } - - AutoReg::~AutoReg() = default; -} -// end catch_test_registry.cpp -// start catch_test_spec.cpp - -#include -#include -#include -#include - -namespace Catch { - - TestSpec::Pattern::~Pattern() = default; - TestSpec::NamePattern::~NamePattern() = default; - TestSpec::TagPattern::~TagPattern() = default; - TestSpec::ExcludedPattern::~ExcludedPattern() = default; - - TestSpec::NamePattern::NamePattern( std::string const& name ) - : m_wildcardPattern( toLower( name ), CaseSensitive::No ) - {} - bool TestSpec::NamePattern::matches( TestCaseInfo const& testCase ) const { - return m_wildcardPattern.matches( toLower( testCase.name ) ); - } - - TestSpec::TagPattern::TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {} - bool TestSpec::TagPattern::matches( TestCaseInfo const& testCase ) const { - return std::find(begin(testCase.lcaseTags), - end(testCase.lcaseTags), - m_tag) != end(testCase.lcaseTags); - } - - TestSpec::ExcludedPattern::ExcludedPattern( PatternPtr const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {} - bool TestSpec::ExcludedPattern::matches( TestCaseInfo const& testCase ) const { return !m_underlyingPattern->matches( testCase ); } - - bool TestSpec::Filter::matches( TestCaseInfo const& testCase ) const { - // All patterns in a filter must match for the filter to be a match - for( auto const& pattern : m_patterns ) { - if( !pattern->matches( testCase ) ) - return false; - } - return true; - } - - bool TestSpec::hasFilters() const { - return !m_filters.empty(); - } - bool TestSpec::matches( TestCaseInfo const& testCase ) const { - // A TestSpec matches if any filter matches - for( auto const& filter : m_filters ) - if( filter.matches( testCase ) ) - return true; - return false; - } -} -// end catch_test_spec.cpp -// start catch_test_spec_parser.cpp - -namespace Catch { - - TestSpecParser::TestSpecParser( ITagAliasRegistry const& tagAliases ) : m_tagAliases( &tagAliases ) {} - - TestSpecParser& TestSpecParser::parse( std::string const& arg ) { - m_mode = None; - m_exclusion = false; - m_start = std::string::npos; - m_arg = m_tagAliases->expandAliases( arg ); - m_escapeChars.clear(); - for( m_pos = 0; m_pos < m_arg.size(); ++m_pos ) - visitChar( m_arg[m_pos] ); - if( m_mode == Name ) - addPattern(); - return *this; - } - TestSpec TestSpecParser::testSpec() { - addFilter(); - return m_testSpec; - } - - void TestSpecParser::visitChar( char c ) { - if( m_mode == None ) { - switch( c ) { - case ' ': return; - case '~': m_exclusion = true; return; - case '[': return startNewMode( Tag, ++m_pos ); - case '"': return startNewMode( QuotedName, ++m_pos ); - case '\\': return escape(); - default: startNewMode( Name, m_pos ); break; + class ReporterFactory : public IReporterFactory { + virtual IStreamingReporter* create( ReporterConfig const& config ) const { + return new LegacyReporterAdapter( new T( config ) ); } - } - if( m_mode == Name ) { - if( c == ',' ) { - addPattern(); - addFilter(); - } - else if( c == '[' ) { - if( subString() == "exclude:" ) - m_exclusion = true; - else - addPattern(); - startNewMode( Tag, ++m_pos ); - } - else if( c == '\\' ) - escape(); - } - else if( m_mode == EscapedName ) - m_mode = Name; - else if( m_mode == QuotedName && c == '"' ) - addPattern(); - else if( m_mode == Tag && c == ']' ) - addPattern(); - } - void TestSpecParser::startNewMode( Mode mode, std::size_t start ) { - m_mode = mode; - m_start = start; - } - void TestSpecParser::escape() { - if( m_mode == None ) - m_start = m_pos; - m_mode = EscapedName; - m_escapeChars.push_back( m_pos ); - } - std::string TestSpecParser::subString() const { return m_arg.substr( m_start, m_pos - m_start ); } - void TestSpecParser::addFilter() { - if( !m_currentFilter.m_patterns.empty() ) { - m_testSpec.m_filters.push_back( m_currentFilter ); - m_currentFilter = TestSpec::Filter(); - } - } - - TestSpec parseTestSpec( std::string const& arg ) { - return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec(); - } - -} // namespace Catch -// end catch_test_spec_parser.cpp -// start catch_timer.cpp - -#include - -namespace Catch { - - auto getCurrentNanosecondsSinceEpoch() -> uint64_t { - return std::chrono::duration_cast( std::chrono::high_resolution_clock::now().time_since_epoch() ).count(); - } - - auto estimateClockResolution() -> uint64_t { - uint64_t sum = 0; - static const uint64_t iterations = 1000000; - - for( std::size_t i = 0; i < iterations; ++i ) { - - uint64_t ticks; - uint64_t baseTicks = getCurrentNanosecondsSinceEpoch(); - do { - ticks = getCurrentNanosecondsSinceEpoch(); - } - while( ticks == baseTicks ); - - auto delta = ticks - baseTicks; - sum += delta; - } - - // We're just taking the mean, here. To do better we could take the std. dev and exclude outliers - // - and potentially do more iterations if there's a high variance. - return sum/iterations; - } - auto getEstimatedClockResolution() -> uint64_t { - static auto s_resolution = estimateClockResolution(); - return s_resolution; - } - - void Timer::start() { - m_nanoseconds = getCurrentNanosecondsSinceEpoch(); - } - auto Timer::getElapsedNanoseconds() const -> unsigned int { - return static_cast(getCurrentNanosecondsSinceEpoch() - m_nanoseconds); - } - auto Timer::getElapsedMicroseconds() const -> unsigned int { - return static_cast(getElapsedNanoseconds()/1000); - } - auto Timer::getElapsedMilliseconds() const -> unsigned int { - return static_cast(getElapsedMicroseconds()/1000); - } - auto Timer::getElapsedSeconds() const -> double { - return getElapsedMicroseconds()/1000000.0; - } - -} // namespace Catch -// end catch_timer.cpp -// start catch_tostring.cpp - -#if defined(__clang__) -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wexit-time-destructors" -# pragma clang diagnostic ignored "-Wglobal-constructors" -#endif - -#include - -namespace Catch { - -namespace Detail { - - const std::string unprintableString = "{?}"; - - namespace { - const int hexThreshold = 255; - - struct Endianness { - enum Arch { Big, Little }; - - static Arch which() { - union _{ - int asInt; - char asChar[sizeof (int)]; - } u; - - u.asInt = 1; - return ( u.asChar[sizeof(int)-1] == 1 ) ? Big : Little; + virtual std::string getDescription() const { + return T::getDescription(); } }; - } - std::string rawMemoryToString( const void *object, std::size_t size ) { - // Reverse order for little endian architectures - int i = 0, end = static_cast( size ), inc = 1; - if( Endianness::which() == Endianness::Little ) { - i = end-1; - end = inc = -1; + public: + + LegacyReporterRegistrar( std::string const& name ) { + getMutableRegistryHub().registerReporter( name, new ReporterFactory() ); } + }; - unsigned char const *bytes = static_cast(object); - std::ostringstream os; - os << "0x" << std::setfill('0') << std::hex; - for( ; i != end; i += inc ) - os << std::setw(2) << static_cast(bytes[i]); - return os.str(); - } -} + template + class ReporterRegistrar { -template -std::string fpToString( T value, int precision ) { - std::ostringstream oss; - oss << std::setprecision( precision ) - << std::fixed - << value; - std::string d = oss.str(); - std::size_t i = d.find_last_not_of( '0' ); - if( i != std::string::npos && i != d.size()-1 ) { - if( d[i] == '.' ) - i++; - d = d.substr( 0, i+1 ); - } - return d; -} + class ReporterFactory : public SharedImpl { -//// ======================================================= //// -// -// Out-of-line defs for full specialization of StringMaker -// -//// ======================================================= //// + // *** Please Note ***: + // - If you end up here looking at a compiler error because it's trying to register + // your custom reporter class be aware that the native reporter interface has changed + // to IStreamingReporter. The "legacy" interface, IReporter, is still supported via + // an adapter. Just use REGISTER_LEGACY_REPORTER to take advantage of the adapter. + // However please consider updating to the new interface as the old one is now + // deprecated and will probably be removed quite soon! + // Please contact me via github if you have any questions at all about this. + // In fact, ideally, please contact me anyway to let me know you've hit this - as I have + // no idea who is actually using custom reporters at all (possibly no-one!). + // The new interface is designed to minimise exposure to interface changes in the future. + virtual IStreamingReporter* create( ReporterConfig const& config ) const { + return new T( config ); + } -std::string StringMaker::convert(const std::string& str) { - if (!getCurrentContext().getConfig()->showInvisibles()) { - return '"' + str + '"'; - } + virtual std::string getDescription() const { + return T::getDescription(); + } + }; - std::string s("\""); - for (char c : str) { - switch (c) { - case '\n': - s.append("\\n"); - break; - case '\t': - s.append("\\t"); - break; - default: - s.push_back(c); - break; + public: + + ReporterRegistrar( std::string const& name ) { + getMutableRegistryHub().registerReporter( name, new ReporterFactory() ); } - } - s.append("\""); - return s; -} + }; -std::string StringMaker::convert(const std::wstring& wstr) { - std::string s; - s.reserve(wstr.size()); - for (auto c : wstr) { - s += (c <= 0xff) ? static_cast(c) : '?'; - } - return ::Catch::Detail::stringify(s); -} + template + class ListenerRegistrar { -std::string StringMaker::convert(char const* str) { - if (str) { - return ::Catch::Detail::stringify(std::string{ str }); - } else { - return{ "{null string}" }; - } -} -std::string StringMaker::convert(char* str) { - if (str) { - return ::Catch::Detail::stringify(std::string{ str }); - } else { - return{ "{null string}" }; - } -} -std::string StringMaker::convert(wchar_t const * str) { - if (str) { - return ::Catch::Detail::stringify(std::wstring{ str }); - } else { - return{ "{null string}" }; - } -} -std::string StringMaker::convert(wchar_t * str) { - if (str) { - return ::Catch::Detail::stringify(std::wstring{ str }); - } else { - return{ "{null string}" }; - } -} + class ListenerFactory : public SharedImpl { -std::string StringMaker::convert(int value) { - return ::Catch::Detail::stringify(static_cast(value)); -} -std::string StringMaker::convert(long value) { - return ::Catch::Detail::stringify(static_cast(value)); -} -std::string StringMaker::convert(long long value) { - std::ostringstream oss; - oss << value; - if (value > Detail::hexThreshold) { - oss << " (0x" << std::hex << value << ')'; - } - return oss.str(); -} + virtual IStreamingReporter* create( ReporterConfig const& config ) const { + return new T( config ); + } + virtual std::string getDescription() const { + return std::string(); + } + }; -std::string StringMaker::convert(unsigned int value) { - return ::Catch::Detail::stringify(static_cast(value)); -} -std::string StringMaker::convert(unsigned long value) { - return ::Catch::Detail::stringify(static_cast(value)); -} -std::string StringMaker::convert(unsigned long long value) { - std::ostringstream oss; - oss << value; - if (value > Detail::hexThreshold) { - oss << " (0x" << std::hex << value << ')'; - } - return oss.str(); -} + public: -std::string StringMaker::convert(bool b) { - return b ? "true" : "false"; -} - -std::string StringMaker::convert(char value) { - if (value == '\r') { - return "'\\r'"; - } else if (value == '\f') { - return "'\\f'"; - } else if (value == '\n') { - return "'\\n'"; - } else if (value == '\t') { - return "'\\t'"; - } else if ('\0' <= value && value < ' ') { - return ::Catch::Detail::stringify(static_cast(value)); - } else { - char chstr[] = "' '"; - chstr[1] = value; - return chstr; - } -} -std::string StringMaker::convert(signed char c) { - return ::Catch::Detail::stringify(static_cast(c)); -} -std::string StringMaker::convert(unsigned char c) { - return ::Catch::Detail::stringify(static_cast(c)); -} - -std::string StringMaker::convert(std::nullptr_t) { - return "nullptr"; -} - -std::string StringMaker::convert(float value) { - return fpToString(value, 5) + 'f'; -} -std::string StringMaker::convert(double value) { - return fpToString(value, 10); -} - -} // end namespace Catch - -#if defined(__clang__) -# pragma clang diagnostic pop -#endif - -// end catch_tostring.cpp -// start catch_totals.cpp - -namespace Catch { - - Counts Counts::operator - ( Counts const& other ) const { - Counts diff; - diff.passed = passed - other.passed; - diff.failed = failed - other.failed; - diff.failedButOk = failedButOk - other.failedButOk; - return diff; - } - - Counts& Counts::operator += ( Counts const& other ) { - passed += other.passed; - failed += other.failed; - failedButOk += other.failedButOk; - return *this; - } - - std::size_t Counts::total() const { - return passed + failed + failedButOk; - } - bool Counts::allPassed() const { - return failed == 0 && failedButOk == 0; - } - bool Counts::allOk() const { - return failed == 0; - } - - Totals Totals::operator - ( Totals const& other ) const { - Totals diff; - diff.assertions = assertions - other.assertions; - diff.testCases = testCases - other.testCases; - return diff; - } - - Totals& Totals::operator += ( Totals const& other ) { - assertions += other.assertions; - testCases += other.testCases; - return *this; - } - - Totals Totals::delta( Totals const& prevTotals ) const { - Totals diff = *this - prevTotals; - if( diff.assertions.failed > 0 ) - ++diff.testCases.failed; - else if( diff.assertions.failedButOk > 0 ) - ++diff.testCases.failedButOk; - else - ++diff.testCases.passed; - return diff; - } - -} -// end catch_totals.cpp -// start catch_version.cpp - -#include - -namespace Catch { - - Version::Version - ( unsigned int _majorVersion, - unsigned int _minorVersion, - unsigned int _patchNumber, - char const * const _branchName, - unsigned int _buildNumber ) - : majorVersion( _majorVersion ), - minorVersion( _minorVersion ), - patchNumber( _patchNumber ), - branchName( _branchName ), - buildNumber( _buildNumber ) - {} - - std::ostream& operator << ( std::ostream& os, Version const& version ) { - os << version.majorVersion << '.' - << version.minorVersion << '.' - << version.patchNumber; - // branchName is never null -> 0th char is \0 if it is empty - if (version.branchName[0]) { - os << '-' << version.branchName - << '.' << version.buildNumber; + ListenerRegistrar() { + getMutableRegistryHub().registerListener( new ListenerFactory() ); } - return os; - } - - Version const& libraryVersion() { - static Version version( 2, 0, 1, "", 0 ); - return version; - } - + }; } -// end catch_version.cpp -// start catch_wildcard_pattern.cpp -namespace Catch { +#define INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) \ + namespace{ Catch::LegacyReporterRegistrar catch_internal_RegistrarFor##reporterType( name ); } - WildcardPattern::WildcardPattern( std::string const& pattern, - CaseSensitive::Choice caseSensitivity ) - : m_caseSensitivity( caseSensitivity ), - m_pattern( adjustCase( pattern ) ) - { - if( startsWith( m_pattern, '*' ) ) { - m_pattern = m_pattern.substr( 1 ); - m_wildcard = WildcardAtStart; - } - if( endsWith( m_pattern, '*' ) ) { - m_pattern = m_pattern.substr( 0, m_pattern.size()-1 ); - m_wildcard = static_cast( m_wildcard | WildcardAtEnd ); - } - } +#define INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) \ + namespace{ Catch::ReporterRegistrar catch_internal_RegistrarFor##reporterType( name ); } - bool WildcardPattern::matches( std::string const& str ) const { - switch( m_wildcard ) { - case NoWildcard: - return m_pattern == adjustCase( str ); - case WildcardAtStart: - return endsWith( adjustCase( str ), m_pattern ); - case WildcardAtEnd: - return startsWith( adjustCase( str ), m_pattern ); - case WildcardAtBothEnds: - return contains( adjustCase( str ), m_pattern ); - default: - CATCH_INTERNAL_ERROR( "Unknown enum" ); - } - } +// Deprecated - use the form without INTERNAL_ +#define INTERNAL_CATCH_REGISTER_LISTENER( listenerType ) \ + namespace{ Catch::ListenerRegistrar catch_internal_RegistrarFor##listenerType; } - std::string WildcardPattern::adjustCase( std::string const& str ) const { - return m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str; - } -} -// end catch_wildcard_pattern.cpp -// start catch_xmlwriter.cpp +#define CATCH_REGISTER_LISTENER( listenerType ) \ + namespace{ Catch::ListenerRegistrar catch_internal_RegistrarFor##listenerType; } -// start catch_xmlwriter.h +// #included from: ../internal/catch_xmlwriter.hpp +#define TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED #include +#include #include +#include namespace Catch { @@ -9884,11 +9919,55 @@ namespace Catch { public: enum ForWhat { ForTextNodes, ForAttributes }; - XmlEncode( std::string const& str, ForWhat forWhat = ForTextNodes ); + XmlEncode( std::string const& str, ForWhat forWhat = ForTextNodes ) + : m_str( str ), + m_forWhat( forWhat ) + {} - void encodeTo( std::ostream& os ) const; + void encodeTo( std::ostream& os ) const { - friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ); + // Apostrophe escaping not necessary if we always use " to write attributes + // (see: http://www.w3.org/TR/xml/#syntax) + + for( std::size_t i = 0; i < m_str.size(); ++ i ) { + char c = m_str[i]; + switch( c ) { + case '<': os << "<"; break; + case '&': os << "&"; break; + + case '>': + // See: http://www.w3.org/TR/xml/#syntax + if( i > 2 && m_str[i-1] == ']' && m_str[i-2] == ']' ) + os << ">"; + else + os << c; + break; + + case '\"': + if( m_forWhat == ForAttributes ) + os << """; + else + os << c; + break; + + default: + // Escape control chars - based on contribution by @espenalb in PR #465 and + // by @mrpi PR #588 + if ( ( c >= 0 && c < '\x09' ) || ( c > '\x0D' && c < '\x20') || c=='\x7F' ) { + // see http://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0 + os << "\\x" << std::uppercase << std::hex << std::setfill('0') << std::setw(2) + << static_cast( c ); + } + else + os << c; + } + } + } + + friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) { + xmlEncode.encodeTo( os ); + return os; + } private: std::string m_str; @@ -9900,14 +9979,24 @@ namespace Catch { class ScopedElement { public: - ScopedElement( XmlWriter* writer ); + ScopedElement( XmlWriter* writer ) + : m_writer( writer ) + {} - ScopedElement( ScopedElement&& other ) noexcept; - ScopedElement& operator=( ScopedElement&& other ) noexcept; + ScopedElement( ScopedElement const& other ) + : m_writer( other.m_writer ){ + other.m_writer = CATCH_NULL; + } - ~ScopedElement(); + ~ScopedElement() { + if( m_writer ) + m_writer->endElement(); + } - ScopedElement& writeText( std::string const& text, bool indent = true ); + ScopedElement& writeText( std::string const& text, bool indent = true ) { + m_writer->writeText( text, indent ); + return *this; + } template ScopedElement& writeAttribute( std::string const& name, T const& attribute ) { @@ -9916,790 +10005,622 @@ namespace Catch { } private: - mutable XmlWriter* m_writer = nullptr; + mutable XmlWriter* m_writer; }; - XmlWriter( std::ostream& os = Catch::cout() ); - ~XmlWriter(); + XmlWriter() + : m_tagIsOpen( false ), + m_needsNewline( false ), + m_os( Catch::cout() ) + { + writeDeclaration(); + } - XmlWriter( XmlWriter const& ) = delete; - XmlWriter& operator=( XmlWriter const& ) = delete; + XmlWriter( std::ostream& os ) + : m_tagIsOpen( false ), + m_needsNewline( false ), + m_os( os ) + { + writeDeclaration(); + } - XmlWriter& startElement( std::string const& name ); + ~XmlWriter() { + while( !m_tags.empty() ) + endElement(); + } - ScopedElement scopedElement( std::string const& name ); + XmlWriter& startElement( std::string const& name ) { + ensureTagClosed(); + newlineIfNecessary(); + m_os << m_indent << '<' << name; + m_tags.push_back( name ); + m_indent += " "; + m_tagIsOpen = true; + return *this; + } - XmlWriter& endElement(); + ScopedElement scopedElement( std::string const& name ) { + ScopedElement scoped( this ); + startElement( name ); + return scoped; + } - XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ); + XmlWriter& endElement() { + newlineIfNecessary(); + m_indent = m_indent.substr( 0, m_indent.size()-2 ); + if( m_tagIsOpen ) { + m_os << "/>"; + m_tagIsOpen = false; + } + else { + m_os << m_indent << ""; + } + m_os << std::endl; + m_tags.pop_back(); + return *this; + } - XmlWriter& writeAttribute( std::string const& name, bool attribute ); + XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ) { + if( !name.empty() && !attribute.empty() ) + m_os << ' ' << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << '"'; + return *this; + } + + XmlWriter& writeAttribute( std::string const& name, bool attribute ) { + m_os << ' ' << name << "=\"" << ( attribute ? "true" : "false" ) << '"'; + return *this; + } template XmlWriter& writeAttribute( std::string const& name, T const& attribute ) { - m_oss.clear(); - m_oss.str(std::string()); - m_oss << attribute; - return writeAttribute( name, m_oss.str() ); + std::ostringstream oss; + oss << attribute; + return writeAttribute( name, oss.str() ); } - XmlWriter& writeText( std::string const& text, bool indent = true ); + XmlWriter& writeText( std::string const& text, bool indent = true ) { + if( !text.empty() ){ + bool tagWasOpen = m_tagIsOpen; + ensureTagClosed(); + if( tagWasOpen && indent ) + m_os << m_indent; + m_os << XmlEncode( text ); + m_needsNewline = true; + } + return *this; + } - XmlWriter& writeComment( std::string const& text ); + XmlWriter& writeComment( std::string const& text ) { + ensureTagClosed(); + m_os << m_indent << ""; + m_needsNewline = true; + return *this; + } - void writeStylesheetRef( std::string const& url ); + void writeStylesheetRef( std::string const& url ) { + m_os << "\n"; + } - XmlWriter& writeBlankLine(); + XmlWriter& writeBlankLine() { + ensureTagClosed(); + m_os << '\n'; + return *this; + } - void ensureTagClosed(); + void ensureTagClosed() { + if( m_tagIsOpen ) { + m_os << ">" << std::endl; + m_tagIsOpen = false; + } + } private: + XmlWriter( XmlWriter const& ); + void operator=( XmlWriter const& ); - void writeDeclaration(); + void writeDeclaration() { + m_os << "\n"; + } - void newlineIfNecessary(); + void newlineIfNecessary() { + if( m_needsNewline ) { + m_os << std::endl; + m_needsNewline = false; + } + } - bool m_tagIsOpen = false; - bool m_needsNewline = false; + bool m_tagIsOpen; + bool m_needsNewline; std::vector m_tags; std::string m_indent; std::ostream& m_os; - std::ostringstream m_oss; }; } -// end catch_xmlwriter.h -#include - namespace Catch { - - XmlEncode::XmlEncode( std::string const& str, ForWhat forWhat ) - : m_str( str ), - m_forWhat( forWhat ) - {} - - void XmlEncode::encodeTo( std::ostream& os ) const { - - // Apostrophe escaping not necessary if we always use " to write attributes - // (see: http://www.w3.org/TR/xml/#syntax) - - for( std::size_t i = 0; i < m_str.size(); ++ i ) { - char c = m_str[i]; - switch( c ) { - case '<': os << "<"; break; - case '&': os << "&"; break; - - case '>': - // See: http://www.w3.org/TR/xml/#syntax - if( i > 2 && m_str[i-1] == ']' && m_str[i-2] == ']' ) - os << ">"; - else - os << c; - break; - - case '\"': - if( m_forWhat == ForAttributes ) - os << """; - else - os << c; - break; - - default: - // Escape control chars - based on contribution by @espenalb in PR #465 and - // by @mrpi PR #588 - if ( ( c >= 0 && c < '\x09' ) || ( c > '\x0D' && c < '\x20') || c=='\x7F' ) { - // see http://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0 - os << "\\x" << std::uppercase << std::hex << std::setfill('0') << std::setw(2) - << static_cast( c ); - } - else - os << c; - } + class XmlReporter : public StreamingReporterBase { + public: + XmlReporter( ReporterConfig const& _config ) + : StreamingReporterBase( _config ), + m_xml(_config.stream()), + m_sectionDepth( 0 ) + { + m_reporterPrefs.shouldRedirectStdOut = true; } - } - std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) { - xmlEncode.encodeTo( os ); - return os; - } - - XmlWriter::ScopedElement::ScopedElement( XmlWriter* writer ) - : m_writer( writer ) - {} - - XmlWriter::ScopedElement::ScopedElement( ScopedElement&& other ) noexcept - : m_writer( other.m_writer ){ - other.m_writer = nullptr; - } - XmlWriter::ScopedElement& XmlWriter::ScopedElement::operator=( ScopedElement&& other ) noexcept { - if ( m_writer ) { - m_writer->endElement(); - } - m_writer = other.m_writer; - other.m_writer = nullptr; - return *this; - } - - XmlWriter::ScopedElement::~ScopedElement() { - if( m_writer ) - m_writer->endElement(); - } - - XmlWriter::ScopedElement& XmlWriter::ScopedElement::writeText( std::string const& text, bool indent ) { - m_writer->writeText( text, indent ); - return *this; - } - - XmlWriter::XmlWriter( std::ostream& os ) : m_os( os ) - { - writeDeclaration(); - } - - XmlWriter::~XmlWriter() { - while( !m_tags.empty() ) - endElement(); - } - - XmlWriter& XmlWriter::startElement( std::string const& name ) { - ensureTagClosed(); - newlineIfNecessary(); - m_os << m_indent << '<' << name; - m_tags.push_back( name ); - m_indent += " "; - m_tagIsOpen = true; - return *this; - } - - XmlWriter::ScopedElement XmlWriter::scopedElement( std::string const& name ) { - ScopedElement scoped( this ); - startElement( name ); - return scoped; - } - - XmlWriter& XmlWriter::endElement() { - newlineIfNecessary(); - m_indent = m_indent.substr( 0, m_indent.size()-2 ); - if( m_tagIsOpen ) { - m_os << "/>"; - m_tagIsOpen = false; - } - else { - m_os << m_indent << ""; - } - m_os << std::endl; - m_tags.pop_back(); - return *this; - } - - XmlWriter& XmlWriter::writeAttribute( std::string const& name, std::string const& attribute ) { - if( !name.empty() && !attribute.empty() ) - m_os << ' ' << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << '"'; - return *this; - } - - XmlWriter& XmlWriter::writeAttribute( std::string const& name, bool attribute ) { - m_os << ' ' << name << "=\"" << ( attribute ? "true" : "false" ) << '"'; - return *this; - } - - XmlWriter& XmlWriter::writeText( std::string const& text, bool indent ) { - if( !text.empty() ){ - bool tagWasOpen = m_tagIsOpen; - ensureTagClosed(); - if( tagWasOpen && indent ) - m_os << m_indent; - m_os << XmlEncode( text ); - m_needsNewline = true; - } - return *this; - } - - XmlWriter& XmlWriter::writeComment( std::string const& text ) { - ensureTagClosed(); - m_os << m_indent << ""; - m_needsNewline = true; - return *this; - } - - void XmlWriter::writeStylesheetRef( std::string const& url ) { - m_os << "\n"; - } - - XmlWriter& XmlWriter::writeBlankLine() { - ensureTagClosed(); - m_os << '\n'; - return *this; - } - - void XmlWriter::ensureTagClosed() { - if( m_tagIsOpen ) { - m_os << ">" << std::endl; - m_tagIsOpen = false; - } - } - - void XmlWriter::writeDeclaration() { - m_os << "\n"; - } - - void XmlWriter::newlineIfNecessary() { - if( m_needsNewline ) { - m_os << std::endl; - m_needsNewline = false; - } - } -} -// end catch_xmlwriter.cpp -// start catch_reporter_bases.cpp - -#include -#include -#include -#include -#include - -namespace Catch { - void prepareExpandedExpression(AssertionResult& result) { - result.getExpandedExpression(); - } - - // Because formatting using c++ streams is stateful, drop down to C is required - // Alternatively we could use stringstream, but its performance is... not good. - std::string getFormattedDuration( double duration ) { - // Max exponent + 1 is required to represent the whole part - // + 1 for decimal point - // + 3 for the 3 decimal places - // + 1 for null terminator - const std::size_t maxDoubleSize = DBL_MAX_10_EXP + 1 + 1 + 3 + 1; - char buffer[maxDoubleSize]; - - // Save previous errno, to prevent sprintf from overwriting it - ErrnoGuard guard; -#ifdef _MSC_VER - sprintf_s(buffer, "%.3f", duration); -#else - sprintf(buffer, "%.3f", duration); -#endif - return std::string(buffer); - } - - TestEventListenerBase::TestEventListenerBase(ReporterConfig const & _config) - :StreamingReporterBase(_config) {} - - void TestEventListenerBase::assertionStarting(AssertionInfo const &) {} - - bool TestEventListenerBase::assertionEnded(AssertionStats const &) { - return false; - } - -} // end namespace Catch -// end catch_reporter_bases.cpp -// start catch_reporter_compact.cpp - -namespace { - -#ifdef CATCH_PLATFORM_MAC - const char* failedString() { return "FAILED"; } - const char* passedString() { return "PASSED"; } -#else - const char* failedString() { return "failed"; } - const char* passedString() { return "passed"; } -#endif - - // Colour::LightGrey - Catch::Colour::Code dimColour() { return Catch::Colour::FileName; } - - std::string bothOrAll( std::size_t count ) { - return count == 1 ? std::string() : - count == 2 ? "both " : "all " ; - } -} - -namespace Catch { - - struct CompactReporter : StreamingReporterBase { - - using StreamingReporterBase::StreamingReporterBase; - - ~CompactReporter() override; + virtual ~XmlReporter() CATCH_OVERRIDE; static std::string getDescription() { - return "Reports test results on a single line, suitable for IDEs"; + return "Reports test results as an XML document"; } - ReporterPreferences getPreferences() const override { - ReporterPreferences prefs; - prefs.shouldRedirectStdOut = false; - return prefs; + virtual std::string getStylesheetRef() const { + return std::string(); } - void noMatchingTestCases( std::string const& spec ) override { - stream << "No test cases matched '" << spec << '\'' << std::endl; + void writeSourceInfo( SourceLineInfo const& sourceInfo ) { + m_xml + .writeAttribute( "filename", sourceInfo.file ) + .writeAttribute( "line", sourceInfo.line ); } - void assertionStarting( AssertionInfo const& ) override {} + public: // StreamingReporterBase - bool assertionEnded( AssertionStats const& _assertionStats ) override { - AssertionResult const& result = _assertionStats.assertionResult; + virtual void noMatchingTestCases( std::string const& s ) CATCH_OVERRIDE { + StreamingReporterBase::noMatchingTestCases( s ); + } - bool printInfoMessages = true; + virtual void testRunStarting( TestRunInfo const& testInfo ) CATCH_OVERRIDE { + StreamingReporterBase::testRunStarting( testInfo ); + std::string stylesheetRef = getStylesheetRef(); + if( !stylesheetRef.empty() ) + m_xml.writeStylesheetRef( stylesheetRef ); + m_xml.startElement( "Catch" ); + if( !m_config->name().empty() ) + m_xml.writeAttribute( "name", m_config->name() ); + } - // Drop out if result was successful and we're not printing those - if( !m_config->includeSuccessfulResults() && result.isOk() ) { - if( result.getResultType() != ResultWas::Warning ) - return false; - printInfoMessages = false; + virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE { + StreamingReporterBase::testGroupStarting( groupInfo ); + m_xml.startElement( "Group" ) + .writeAttribute( "name", groupInfo.name ); + } + + virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { + StreamingReporterBase::testCaseStarting(testInfo); + m_xml.startElement( "TestCase" ) + .writeAttribute( "name", trim( testInfo.name ) ) + .writeAttribute( "description", testInfo.description ) + .writeAttribute( "tags", testInfo.tagsAsString ); + + writeSourceInfo( testInfo.lineInfo ); + + if ( m_config->showDurations() == ShowDurations::Always ) + m_testCaseTimer.start(); + m_xml.ensureTagClosed(); + } + + virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE { + StreamingReporterBase::sectionStarting( sectionInfo ); + if( m_sectionDepth++ > 0 ) { + m_xml.startElement( "Section" ) + .writeAttribute( "name", trim( sectionInfo.name ) ) + .writeAttribute( "description", sectionInfo.description ); + writeSourceInfo( sectionInfo.lineInfo ); + m_xml.ensureTagClosed(); + } + } + + virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE { } + + virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { + + AssertionResult const& result = assertionStats.assertionResult; + + bool includeResults = m_config->includeSuccessfulResults() || !result.isOk(); + + if( includeResults ) { + // Print any info messages in tags. + for( std::vector::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end(); + it != itEnd; + ++it ) { + if( it->type == ResultWas::Info ) { + m_xml.scopedElement( "Info" ) + .writeText( it->message ); + } else if ( it->type == ResultWas::Warning ) { + m_xml.scopedElement( "Warning" ) + .writeText( it->message ); + } + } } - AssertionPrinter printer( stream, _assertionStats, printInfoMessages ); - printer.print(); + // Drop out if result was successful but we're not printing them. + if( !includeResults && result.getResultType() != ResultWas::Warning ) + return true; + + // Print the expression if there is one. + if( result.hasExpression() ) { + m_xml.startElement( "Expression" ) + .writeAttribute( "success", result.succeeded() ) + .writeAttribute( "type", result.getTestMacroName() ); + + writeSourceInfo( result.getSourceInfo() ); + + m_xml.scopedElement( "Original" ) + .writeText( result.getExpression() ); + m_xml.scopedElement( "Expanded" ) + .writeText( result.getExpandedExpression() ); + } + + // And... Print a result applicable to each result type. + switch( result.getResultType() ) { + case ResultWas::ThrewException: + m_xml.startElement( "Exception" ); + writeSourceInfo( result.getSourceInfo() ); + m_xml.writeText( result.getMessage() ); + m_xml.endElement(); + break; + case ResultWas::FatalErrorCondition: + m_xml.startElement( "FatalErrorCondition" ); + writeSourceInfo( result.getSourceInfo() ); + m_xml.writeText( result.getMessage() ); + m_xml.endElement(); + break; + case ResultWas::Info: + m_xml.scopedElement( "Info" ) + .writeText( result.getMessage() ); + break; + case ResultWas::Warning: + // Warning will already have been written + break; + case ResultWas::ExplicitFailure: + m_xml.startElement( "Failure" ); + writeSourceInfo( result.getSourceInfo() ); + m_xml.writeText( result.getMessage() ); + m_xml.endElement(); + break; + default: + break; + } + + if( result.hasExpression() ) + m_xml.endElement(); - stream << std::endl; return true; } - void sectionEnded(SectionStats const& _sectionStats) override { - if (m_config->showDurations() == ShowDurations::Always) { - stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl; + virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE { + StreamingReporterBase::sectionEnded( sectionStats ); + if( --m_sectionDepth > 0 ) { + XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" ); + e.writeAttribute( "successes", sectionStats.assertions.passed ); + e.writeAttribute( "failures", sectionStats.assertions.failed ); + e.writeAttribute( "expectedFailures", sectionStats.assertions.failedButOk ); + + if ( m_config->showDurations() == ShowDurations::Always ) + e.writeAttribute( "durationInSeconds", sectionStats.durationInSeconds ); + + m_xml.endElement(); } } - void testRunEnded( TestRunStats const& _testRunStats ) override { - printTotals( _testRunStats.totals ); - stream << '\n' << std::endl; - StreamingReporterBase::testRunEnded( _testRunStats ); + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { + StreamingReporterBase::testCaseEnded( testCaseStats ); + XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" ); + e.writeAttribute( "success", testCaseStats.totals.assertions.allOk() ); + + if ( m_config->showDurations() == ShowDurations::Always ) + e.writeAttribute( "durationInSeconds", m_testCaseTimer.getElapsedSeconds() ); + + if( !testCaseStats.stdOut.empty() ) + m_xml.scopedElement( "StdOut" ).writeText( trim( testCaseStats.stdOut ), false ); + if( !testCaseStats.stdErr.empty() ) + m_xml.scopedElement( "StdErr" ).writeText( trim( testCaseStats.stdErr ), false ); + + m_xml.endElement(); + } + + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { + StreamingReporterBase::testGroupEnded( testGroupStats ); + // TODO: Check testGroupStats.aborting and act accordingly. + m_xml.scopedElement( "OverallResults" ) + .writeAttribute( "successes", testGroupStats.totals.assertions.passed ) + .writeAttribute( "failures", testGroupStats.totals.assertions.failed ) + .writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk ); + m_xml.endElement(); + } + + virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE { + StreamingReporterBase::testRunEnded( testRunStats ); + m_xml.scopedElement( "OverallResults" ) + .writeAttribute( "successes", testRunStats.totals.assertions.passed ) + .writeAttribute( "failures", testRunStats.totals.assertions.failed ) + .writeAttribute( "expectedFailures", testRunStats.totals.assertions.failedButOk ); + m_xml.endElement(); } private: - class AssertionPrinter { - public: - AssertionPrinter& operator= ( AssertionPrinter const& ) = delete; - AssertionPrinter( AssertionPrinter const& ) = delete; - AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages ) - : stream( _stream ) - , result( _stats.assertionResult ) - , messages( _stats.infoMessages ) - , itMessage( _stats.infoMessages.begin() ) - , printInfoMessages( _printInfoMessages ) - {} - - void print() { - printSourceInfo(); - - itMessage = messages.begin(); - - switch( result.getResultType() ) { - case ResultWas::Ok: - printResultType( Colour::ResultSuccess, passedString() ); - printOriginalExpression(); - printReconstructedExpression(); - if ( ! result.hasExpression() ) - printRemainingMessages( Colour::None ); - else - printRemainingMessages(); - break; - case ResultWas::ExpressionFailed: - if( result.isOk() ) - printResultType( Colour::ResultSuccess, failedString() + std::string( " - but was ok" ) ); - else - printResultType( Colour::Error, failedString() ); - printOriginalExpression(); - printReconstructedExpression(); - printRemainingMessages(); - break; - case ResultWas::ThrewException: - printResultType( Colour::Error, failedString() ); - printIssue( "unexpected exception with message:" ); - printMessage(); - printExpressionWas(); - printRemainingMessages(); - break; - case ResultWas::FatalErrorCondition: - printResultType( Colour::Error, failedString() ); - printIssue( "fatal error condition with message:" ); - printMessage(); - printExpressionWas(); - printRemainingMessages(); - break; - case ResultWas::DidntThrowException: - printResultType( Colour::Error, failedString() ); - printIssue( "expected exception, got none" ); - printExpressionWas(); - printRemainingMessages(); - break; - case ResultWas::Info: - printResultType( Colour::None, "info" ); - printMessage(); - printRemainingMessages(); - break; - case ResultWas::Warning: - printResultType( Colour::None, "warning" ); - printMessage(); - printRemainingMessages(); - break; - case ResultWas::ExplicitFailure: - printResultType( Colour::Error, failedString() ); - printIssue( "explicitly" ); - printRemainingMessages( Colour::None ); - break; - // These cases are here to prevent compiler warnings - case ResultWas::Unknown: - case ResultWas::FailureBit: - case ResultWas::Exception: - printResultType( Colour::Error, "** internal error **" ); - break; - } - } - - private: - void printSourceInfo() const { - Colour colourGuard( Colour::FileName ); - stream << result.getSourceInfo() << ':'; - } - - void printResultType( Colour::Code colour, std::string const& passOrFail ) const { - if( !passOrFail.empty() ) { - { - Colour colourGuard( colour ); - stream << ' ' << passOrFail; - } - stream << ':'; - } - } - - void printIssue( std::string const& issue ) const { - stream << ' ' << issue; - } - - void printExpressionWas() { - if( result.hasExpression() ) { - stream << ';'; - { - Colour colour( dimColour() ); - stream << " expression was:"; - } - printOriginalExpression(); - } - } - - void printOriginalExpression() const { - if( result.hasExpression() ) { - stream << ' ' << result.getExpression(); - } - } - - void printReconstructedExpression() const { - if( result.hasExpandedExpression() ) { - { - Colour colour( dimColour() ); - stream << " for: "; - } - stream << result.getExpandedExpression(); - } - } - - void printMessage() { - if ( itMessage != messages.end() ) { - stream << " '" << itMessage->message << '\''; - ++itMessage; - } - } - - void printRemainingMessages( Colour::Code colour = dimColour() ) { - if ( itMessage == messages.end() ) - return; - - // using messages.end() directly yields (or auto) compilation error: - std::vector::const_iterator itEnd = messages.end(); - const std::size_t N = static_cast( std::distance( itMessage, itEnd ) ); - - { - Colour colourGuard( colour ); - stream << " with " << pluralise( N, "message" ) << ':'; - } - - for(; itMessage != itEnd; ) { - // If this assertion is a warning ignore any INFO messages - if( printInfoMessages || itMessage->type != ResultWas::Info ) { - stream << " '" << itMessage->message << '\''; - if ( ++itMessage != itEnd ) { - Colour colourGuard( dimColour() ); - stream << " and"; - } - } - } - } - - private: - std::ostream& stream; - AssertionResult const& result; - std::vector messages; - std::vector::const_iterator itMessage; - bool printInfoMessages; - }; - - // Colour, message variants: - // - white: No tests ran. - // - red: Failed [both/all] N test cases, failed [both/all] M assertions. - // - white: Passed [both/all] N test cases (no assertions). - // - red: Failed N tests cases, failed M assertions. - // - green: Passed [both/all] N tests cases with M assertions. - - void printTotals( const Totals& totals ) const { - if( totals.testCases.total() == 0 ) { - stream << "No tests ran."; - } - else if( totals.testCases.failed == totals.testCases.total() ) { - Colour colour( Colour::ResultError ); - const std::string qualify_assertions_failed = - totals.assertions.failed == totals.assertions.total() ? - bothOrAll( totals.assertions.failed ) : std::string(); - stream << - "Failed " << bothOrAll( totals.testCases.failed ) - << pluralise( totals.testCases.failed, "test case" ) << ", " - "failed " << qualify_assertions_failed << - pluralise( totals.assertions.failed, "assertion" ) << '.'; - } - else if( totals.assertions.total() == 0 ) { - stream << - "Passed " << bothOrAll( totals.testCases.total() ) - << pluralise( totals.testCases.total(), "test case" ) - << " (no assertions)."; - } - else if( totals.assertions.failed ) { - Colour colour( Colour::ResultError ); - stream << - "Failed " << pluralise( totals.testCases.failed, "test case" ) << ", " - "failed " << pluralise( totals.assertions.failed, "assertion" ) << '.'; - } - else { - Colour colour( Colour::ResultSuccess ); - stream << - "Passed " << bothOrAll( totals.testCases.passed ) - << pluralise( totals.testCases.passed, "test case" ) << - " with " << pluralise( totals.assertions.passed, "assertion" ) << '.'; - } - } + Timer m_testCaseTimer; + XmlWriter m_xml; + int m_sectionDepth; }; - CompactReporter::~CompactReporter() {} - - CATCH_REGISTER_REPORTER( "compact", CompactReporter ) + INTERNAL_CATCH_REGISTER_REPORTER( "xml", XmlReporter ) } // end namespace Catch -// end catch_reporter_compact.cpp -// start catch_reporter_console.cpp -#include -#include +// #included from: ../reporters/catch_reporter_junit.hpp +#define TWOBLUECUBES_CATCH_REPORTER_JUNIT_HPP_INCLUDED -#if defined(_MSC_VER) -#pragma warning(push) -#pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch - // Note that 4062 (not all labels are handled - // and default is missing) is enabled -#endif +#include namespace Catch { namespace { - std::size_t makeRatio( std::size_t number, std::size_t total ) { - std::size_t ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number/ total : 0; - return ( ratio == 0 && number > 0 ) ? 1 : ratio; + std::string getCurrentTimestamp() { + // Beware, this is not reentrant because of backward compatibility issues + // Also, UTC only, again because of backward compatibility (%z is C++11) + time_t rawtime; + std::time(&rawtime); + const size_t timeStampSize = sizeof("2017-01-16T17:06:45Z"); + +#ifdef _MSC_VER + std::tm timeInfo = {}; + gmtime_s(&timeInfo, &rawtime); +#else + std::tm* timeInfo; + timeInfo = std::gmtime(&rawtime); +#endif + + char timeStamp[timeStampSize]; + const char * const fmt = "%Y-%m-%dT%H:%M:%SZ"; + +#ifdef _MSC_VER + std::strftime(timeStamp, timeStampSize, fmt, &timeInfo); +#else + std::strftime(timeStamp, timeStampSize, fmt, timeInfo); +#endif + return std::string(timeStamp); } - std::size_t& findMax( std::size_t& i, std::size_t& j, std::size_t& k ) { - if( i > j && i > k ) - return i; - else if( j > k ) - return j; + } + + class JunitReporter : public CumulativeReporterBase { + public: + JunitReporter( ReporterConfig const& _config ) + : CumulativeReporterBase( _config ), + xml( _config.stream() ), + unexpectedExceptions( 0 ), + m_okToFail( false ) + { + m_reporterPrefs.shouldRedirectStdOut = true; + } + + virtual ~JunitReporter() CATCH_OVERRIDE; + + static std::string getDescription() { + return "Reports test results in an XML format that looks like Ant's junitreport target"; + } + + virtual void noMatchingTestCases( std::string const& /*spec*/ ) CATCH_OVERRIDE {} + + virtual void testRunStarting( TestRunInfo const& runInfo ) CATCH_OVERRIDE { + CumulativeReporterBase::testRunStarting( runInfo ); + xml.startElement( "testsuites" ); + } + + virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE { + suiteTimer.start(); + stdOutForSuite.str(""); + stdErrForSuite.str(""); + unexpectedExceptions = 0; + CumulativeReporterBase::testGroupStarting( groupInfo ); + } + + virtual void testCaseStarting( TestCaseInfo const& testCaseInfo ) CATCH_OVERRIDE { + m_okToFail = testCaseInfo.okToFail(); + } + virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { + if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException && !m_okToFail ) + unexpectedExceptions++; + return CumulativeReporterBase::assertionEnded( assertionStats ); + } + + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { + stdOutForSuite << testCaseStats.stdOut; + stdErrForSuite << testCaseStats.stdErr; + CumulativeReporterBase::testCaseEnded( testCaseStats ); + } + + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { + double suiteTime = suiteTimer.getElapsedSeconds(); + CumulativeReporterBase::testGroupEnded( testGroupStats ); + writeGroup( *m_testGroups.back(), suiteTime ); + } + + virtual void testRunEndedCumulative() CATCH_OVERRIDE { + xml.endElement(); + } + + void writeGroup( TestGroupNode const& groupNode, double suiteTime ) { + XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" ); + TestGroupStats const& stats = groupNode.value; + xml.writeAttribute( "name", stats.groupInfo.name ); + xml.writeAttribute( "errors", unexpectedExceptions ); + xml.writeAttribute( "failures", stats.totals.assertions.failed-unexpectedExceptions ); + xml.writeAttribute( "tests", stats.totals.assertions.total() ); + xml.writeAttribute( "hostname", "tbd" ); // !TBD + if( m_config->showDurations() == ShowDurations::Never ) + xml.writeAttribute( "time", "" ); else - return k; + xml.writeAttribute( "time", suiteTime ); + xml.writeAttribute( "timestamp", getCurrentTimestamp() ); + + // Write test cases + for( TestGroupNode::ChildNodes::const_iterator + it = groupNode.children.begin(), itEnd = groupNode.children.end(); + it != itEnd; + ++it ) + writeTestCase( **it ); + + xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite.str() ), false ); + xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite.str() ), false ); } - struct ColumnInfo { - enum Justification { Left, Right }; - std::string name; - int width; - Justification justification; - }; - struct ColumnBreak {}; - struct RowBreak {}; + void writeTestCase( TestCaseNode const& testCaseNode ) { + TestCaseStats const& stats = testCaseNode.value; - class TablePrinter { - std::ostream& m_os; - std::vector m_columnInfos; - std::ostringstream m_oss; - int m_currentColumn = -1; - bool m_isOpen = false; + // All test cases have exactly one section - which represents the + // test case itself. That section may have 0-n nested sections + assert( testCaseNode.children.size() == 1 ); + SectionNode const& rootSection = *testCaseNode.children.front(); - public: - TablePrinter( std::ostream& os, std::vector const& columnInfos ) - : m_os( os ), - m_columnInfos( columnInfos ) - {} + std::string className = stats.testInfo.className; - auto columnInfos() const -> std::vector const& { - return m_columnInfos; + if( className.empty() ) { + if( rootSection.childSections.empty() ) + className = "global"; } + writeSection( className, "", rootSection ); + } - void open() { - if( !m_isOpen ) { - m_isOpen = true; - *this << RowBreak(); - for( auto const& info : m_columnInfos ) - *this << info.name << ColumnBreak(); - *this << RowBreak(); - m_os << Catch::getLineOfChars<'-'>() << "\n"; + void writeSection( std::string const& className, + std::string const& rootName, + SectionNode const& sectionNode ) { + std::string name = trim( sectionNode.stats.sectionInfo.name ); + if( !rootName.empty() ) + name = rootName + '/' + name; + + if( !sectionNode.assertions.empty() || + !sectionNode.stdOut.empty() || + !sectionNode.stdErr.empty() ) { + XmlWriter::ScopedElement e = xml.scopedElement( "testcase" ); + if( className.empty() ) { + xml.writeAttribute( "classname", name ); + xml.writeAttribute( "name", "root" ); } - } - void close() { - if( m_isOpen ) { - *this << RowBreak(); - m_os << std::endl; - m_isOpen = false; + else { + xml.writeAttribute( "classname", className ); + xml.writeAttribute( "name", name ); } + xml.writeAttribute( "time", Catch::toString( sectionNode.stats.durationInSeconds ) ); + + writeAssertions( sectionNode ); + + if( !sectionNode.stdOut.empty() ) + xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), false ); + if( !sectionNode.stdErr.empty() ) + xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), false ); } - - template - friend TablePrinter& operator << ( TablePrinter& tp, T const& value ) { - tp.m_oss << value; - return tp; - } - - friend TablePrinter& operator << ( TablePrinter& tp, ColumnBreak ) { - auto colStr = tp.m_oss.str(); - // This takes account of utf8 encodings - auto strSize = Catch::StringRef( colStr ).numberOfCharacters(); - tp.m_oss.str(""); - tp.open(); - if( tp.m_currentColumn == static_cast(tp.m_columnInfos.size()-1) ) { - tp.m_currentColumn = -1; - tp.m_os << "\n"; - } - tp.m_currentColumn++; - - auto colInfo = tp.m_columnInfos[tp.m_currentColumn]; - auto padding = ( strSize+2 < static_cast( colInfo.width ) ) - ? std::string( colInfo.width-(strSize+2), ' ' ) - : std::string(); - if( colInfo.justification == ColumnInfo::Left ) - tp.m_os << colStr << padding << " "; + for( SectionNode::ChildSections::const_iterator + it = sectionNode.childSections.begin(), + itEnd = sectionNode.childSections.end(); + it != itEnd; + ++it ) + if( className.empty() ) + writeSection( name, "", **it ); else - tp.m_os << padding << colStr << " "; - return tp; - } + writeSection( className, name, **it ); + } - friend TablePrinter& operator << ( TablePrinter& tp, RowBreak ) { - if( tp.m_currentColumn > 0 ) { - tp.m_os << "\n"; - tp.m_currentColumn = -1; - } - return tp; - } - }; + void writeAssertions( SectionNode const& sectionNode ) { + for( SectionNode::Assertions::const_iterator + it = sectionNode.assertions.begin(), itEnd = sectionNode.assertions.end(); + it != itEnd; + ++it ) + writeAssertion( *it ); + } + void writeAssertion( AssertionStats const& stats ) { + AssertionResult const& result = stats.assertionResult; + if( !result.isOk() ) { + std::string elementName; + switch( result.getResultType() ) { + case ResultWas::ThrewException: + case ResultWas::FatalErrorCondition: + elementName = "error"; + break; + case ResultWas::ExplicitFailure: + elementName = "failure"; + break; + case ResultWas::ExpressionFailed: + elementName = "failure"; + break; + case ResultWas::DidntThrowException: + elementName = "failure"; + break; - class Duration { - enum class Unit { - Auto, - Nanoseconds, - Microseconds, - Milliseconds, - Seconds, - Minutes - }; - static const uint64_t s_nanosecondsInAMicrosecond = 1000; - static const uint64_t s_nanosecondsInAMillisecond = 1000*s_nanosecondsInAMicrosecond; - static const uint64_t s_nanosecondsInASecond = 1000*s_nanosecondsInAMillisecond; - static const uint64_t s_nanosecondsInAMinute = 60*s_nanosecondsInASecond; - - uint64_t m_inNanoseconds; - Unit m_units; - - public: - Duration( uint64_t inNanoseconds, Unit units = Unit::Auto ) - : m_inNanoseconds( inNanoseconds ), - m_units( units ) - { - if( m_units == Unit::Auto ) { - if( m_inNanoseconds < s_nanosecondsInAMicrosecond ) - m_units = Unit::Nanoseconds; - else if( m_inNanoseconds < s_nanosecondsInAMillisecond ) - m_units = Unit::Microseconds; - else if( m_inNanoseconds < s_nanosecondsInASecond ) - m_units = Unit::Milliseconds; - else if( m_inNanoseconds < s_nanosecondsInAMinute ) - m_units = Unit::Seconds; - else - m_units = Unit::Minutes; + // We should never see these here: + case ResultWas::Info: + case ResultWas::Warning: + case ResultWas::Ok: + case ResultWas::Unknown: + case ResultWas::FailureBit: + case ResultWas::Exception: + elementName = "internalError"; + break; } - } + XmlWriter::ScopedElement e = xml.scopedElement( elementName ); - auto value() const -> double { - switch( m_units ) { - case Unit::Microseconds: - return m_inNanoseconds / static_cast( s_nanosecondsInAMicrosecond ); - case Unit::Milliseconds: - return m_inNanoseconds / static_cast( s_nanosecondsInAMillisecond ); - case Unit::Seconds: - return m_inNanoseconds / static_cast( s_nanosecondsInASecond ); - case Unit::Minutes: - return m_inNanoseconds / static_cast( s_nanosecondsInAMinute ); - default: - return static_cast( m_inNanoseconds ); - } - } - auto unitsAsString() const -> std::string { - switch( m_units ) { - case Unit::Nanoseconds: - return "ns"; - case Unit::Microseconds: - return "µs"; - case Unit::Milliseconds: - return "ms"; - case Unit::Seconds: - return "s"; - case Unit::Minutes: - return "m"; - default: - return "** internal error **"; - } + xml.writeAttribute( "message", result.getExpandedExpression() ); + xml.writeAttribute( "type", result.getTestMacroName() ); - } - friend auto operator << ( std::ostream& os, Duration const& duration ) -> std::ostream& { - return os << duration.value() << " " << duration.unitsAsString(); - } - }; - } // end anon namespace + std::ostringstream oss; + if( !result.getMessage().empty() ) + oss << result.getMessage() << '\n'; + for( std::vector::const_iterator + it = stats.infoMessages.begin(), + itEnd = stats.infoMessages.end(); + it != itEnd; + ++it ) + if( it->type == ResultWas::Info ) + oss << it->message << '\n'; - struct ConsoleReporter : StreamingReporterBase { - TablePrinter m_tablePrinter; + oss << "at " << result.getSourceInfo(); + xml.writeText( oss.str(), false ); + } + } - ConsoleReporter( ReporterConfig const& config ) - : StreamingReporterBase( config ), - m_tablePrinter( config.stream(), - { - { "benchmark name", CATCH_CONFIG_CONSOLE_WIDTH-32, ColumnInfo::Left }, - { "iters", 8, ColumnInfo::Right }, - { "elapsed ns", 14, ColumnInfo::Right }, - { "average", 14, ColumnInfo::Right } - } ) + XmlWriter xml; + Timer suiteTimer; + std::ostringstream stdOutForSuite; + std::ostringstream stdErrForSuite; + unsigned int unexpectedExceptions; + bool m_okToFail; + }; + + INTERNAL_CATCH_REGISTER_REPORTER( "junit", JunitReporter ) + +} // end namespace Catch + +// #included from: ../reporters/catch_reporter_console.hpp +#define TWOBLUECUBES_CATCH_REPORTER_CONSOLE_HPP_INCLUDED + +#include +#include + +namespace Catch { + + struct ConsoleReporter : StreamingReporterBase { + ConsoleReporter( ReporterConfig const& _config ) + : StreamingReporterBase( _config ), + m_headerPrinted( false ) {} - ~ConsoleReporter() override; + + virtual ~ConsoleReporter() CATCH_OVERRIDE; static std::string getDescription() { return "Reports test results as plain lines of text"; } - void noMatchingTestCases( std::string const& spec ) override { + virtual void noMatchingTestCases( std::string const& spec ) CATCH_OVERRIDE { stream << "No test cases matched '" << spec << '\'' << std::endl; } - void assertionStarting( AssertionInfo const& ) override { + virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE { } - bool assertionEnded( AssertionStats const& _assertionStats ) override { + virtual bool assertionEnded( AssertionStats const& _assertionStats ) CATCH_OVERRIDE { AssertionResult const& result = _assertionStats.assertionResult; bool includeResults = m_config->includeSuccessfulResults() || !result.isOk(); @@ -10716,12 +10637,11 @@ namespace Catch { return true; } - void sectionStarting( SectionInfo const& _sectionInfo ) override { + virtual void sectionStarting( SectionInfo const& _sectionInfo ) CATCH_OVERRIDE { m_headerPrinted = false; StreamingReporterBase::sectionStarting( _sectionInfo ); } - void sectionEnded( SectionStats const& _sectionStats ) override { - m_tablePrinter.close(); + virtual void sectionEnded( SectionStats const& _sectionStats ) CATCH_OVERRIDE { if( _sectionStats.missingAssertions ) { lazyPrint(); Colour colour( Colour::ResultError ); @@ -10740,35 +10660,11 @@ namespace Catch { StreamingReporterBase::sectionEnded( _sectionStats ); } - void benchmarkStarting( BenchmarkInfo const& info ) override { - lazyPrintWithoutClosingBenchmarkTable(); - - auto nameCol = Column( info.name ).width( m_tablePrinter.columnInfos()[0].width-2 ); - - bool firstLine = true; - for( auto line : nameCol ) { - if( !firstLine ) - m_tablePrinter << ColumnBreak() << ColumnBreak() << ColumnBreak(); - else - firstLine = false; - - m_tablePrinter << line << ColumnBreak(); - } - } - void benchmarkEnded( BenchmarkStats const& stats ) override { - Duration average( stats.elapsedTimeInNanoseconds/stats.iterations ); - m_tablePrinter - << stats.iterations << ColumnBreak() - << stats.elapsedTimeInNanoseconds << ColumnBreak() - << average << ColumnBreak(); - } - - void testCaseEnded( TestCaseStats const& _testCaseStats ) override { - m_tablePrinter.close(); + virtual void testCaseEnded( TestCaseStats const& _testCaseStats ) CATCH_OVERRIDE { StreamingReporterBase::testCaseEnded( _testCaseStats ); m_headerPrinted = false; } - void testGroupEnded( TestGroupStats const& _testGroupStats ) override { + virtual void testGroupEnded( TestGroupStats const& _testGroupStats ) CATCH_OVERRIDE { if( currentGroupInfo.used ) { printSummaryDivider(); stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n"; @@ -10777,7 +10673,7 @@ namespace Catch { } StreamingReporterBase::testGroupEnded( _testGroupStats ); } - void testRunEnded( TestRunStats const& _testRunStats ) override { + virtual void testRunEnded( TestRunStats const& _testRunStats ) CATCH_OVERRIDE { printTotalsDivider( _testRunStats.totals ); printTotals( _testRunStats.totals ); stream << std::endl; @@ -10787,9 +10683,8 @@ namespace Catch { private: class AssertionPrinter { + void operator= ( AssertionPrinter const& ); public: - AssertionPrinter& operator= ( AssertionPrinter const& ) = delete; - AssertionPrinter( AssertionPrinter const& ) = delete; AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages ) : stream( _stream ), stats( _stats ), @@ -10900,16 +10795,18 @@ namespace Catch { if( result.hasExpandedExpression() ) { stream << "with expansion:\n"; Colour colourGuard( Colour::ReconstructedExpression ); - stream << Column( result.getExpandedExpression() ).indent(2) << '\n'; + stream << Text( result.getExpandedExpression(), TextAttributes().setIndent(2) ) << '\n'; } } void printMessage() const { if( !messageLabel.empty() ) stream << messageLabel << ':' << '\n'; - for( auto const& msg : messages ) { + for( std::vector::const_iterator it = messages.begin(), itEnd = messages.end(); + it != itEnd; + ++it ) { // If this assertion is a warning ignore any INFO messages - if( printInfoMessages || msg.type != ResultWas::Info ) - stream << Column( msg.message ).indent(2) << '\n'; + if( printInfoMessages || it->type != ResultWas::Info ) + stream << Text( it->message, TextAttributes().setIndent(2) ) << '\n'; } } void printSourceInfo() const { @@ -10930,12 +10827,6 @@ namespace Catch { void lazyPrint() { - m_tablePrinter.close(); - lazyPrintWithoutClosingBenchmarkTable(); - } - - void lazyPrintWithoutClosingBenchmarkTable() { - if( !currentTestRunInfo.used ) lazyPrintRunInfo(); if( !currentGroupInfo.used ) @@ -10971,7 +10862,7 @@ namespace Catch { if( m_sectionStack.size() > 1 ) { Colour colourGuard( Colour::Headers ); - auto + std::vector::const_iterator it = m_sectionStack.begin()+1, // Skip first section (test case) itEnd = m_sectionStack.end(); for( ; it != itEnd; ++it ) @@ -11008,7 +10899,9 @@ namespace Catch { i+=2; else i = 0; - stream << Column( _string ).indent( indent+i ).initialIndent( indent ) << '\n'; + stream << Text( _string, TextAttributes() + .setIndent( indent+i) + .setInitialIndent( indent ) ) << '\n'; } struct SummaryColumn { @@ -11021,10 +10914,10 @@ namespace Catch { std::ostringstream oss; oss << count; std::string row = oss.str(); - for( auto& oldRow : rows ) { - while( oldRow.size() < row.size() ) - oldRow = ' ' + oldRow; - while( oldRow.size() > row.size() ) + for( std::vector::iterator it = rows.begin(); it != rows.end(); ++it ) { + while( it->size() < row.size() ) + *it = ' ' + *it; + while( it->size() > row.size() ) row = ' ' + row; } rows.push_back( row ); @@ -11069,9 +10962,9 @@ namespace Catch { } } void printSummaryRow( std::string const& label, std::vector const& cols, std::size_t row ) { - for( auto col : cols ) { - std::string value = col.rows[row]; - if( col.label.empty() ) { + for( std::vector::const_iterator it = cols.begin(); it != cols.end(); ++it ) { + std::string value = it->rows[row]; + if( it->label.empty() ) { stream << label << ": "; if( value != "0" ) stream << value; @@ -11080,13 +10973,26 @@ namespace Catch { } else if( value != "0" ) { stream << Colour( Colour::LightGrey ) << " | "; - stream << Colour( col.colour ) - << value << ' ' << col.label; + stream << Colour( it->colour ) + << value << ' ' << it->label; } } stream << '\n'; } + static std::size_t makeRatio( std::size_t number, std::size_t total ) { + std::size_t ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number/ total : 0; + return ( ratio == 0 && number > 0 ) ? 1 : ratio; + } + static std::size_t& findMax( std::size_t& i, std::size_t& j, std::size_t& k ) { + if( i > j && i > k ) + return i; + else if( j > k ) + return j; + else + return k; + } + void printTotalsDivider( Totals const& totals ) { if( totals.testCases.total() > 0 ) { std::size_t failedRatio = makeRatio( totals.testCases.failed, totals.testCases.total() ); @@ -11114,594 +11020,374 @@ namespace Catch { } private: - bool m_headerPrinted = false; + bool m_headerPrinted; }; - CATCH_REGISTER_REPORTER( "console", ConsoleReporter ) - - ConsoleReporter::~ConsoleReporter() {} + INTERNAL_CATCH_REGISTER_REPORTER( "console", ConsoleReporter ) } // end namespace Catch -#if defined(_MSC_VER) -#pragma warning(pop) -#endif -// end catch_reporter_console.cpp -// start catch_reporter_junit.cpp - -#include - -#include -#include +// #included from: ../reporters/catch_reporter_compact.hpp +#define TWOBLUECUBES_CATCH_REPORTER_COMPACT_HPP_INCLUDED namespace Catch { - namespace { - std::string getCurrentTimestamp() { - // Beware, this is not reentrant because of backward compatibility issues - // Also, UTC only, again because of backward compatibility (%z is C++11) - time_t rawtime; - std::time(&rawtime); - auto const timeStampSize = sizeof("2017-01-16T17:06:45Z"); + struct CompactReporter : StreamingReporterBase { -#ifdef _MSC_VER - std::tm timeInfo = {}; - gmtime_s(&timeInfo, &rawtime); -#else - std::tm* timeInfo; - timeInfo = std::gmtime(&rawtime); -#endif + CompactReporter( ReporterConfig const& _config ) + : StreamingReporterBase( _config ) + {} - char timeStamp[timeStampSize]; - const char * const fmt = "%Y-%m-%dT%H:%M:%SZ"; - -#ifdef _MSC_VER - std::strftime(timeStamp, timeStampSize, fmt, &timeInfo); -#else - std::strftime(timeStamp, timeStampSize, fmt, timeInfo); -#endif - return std::string(timeStamp); - } - - std::string fileNameTag(const std::vector &tags) { - auto it = std::find_if(begin(tags), - end(tags), - [] (std::string const& tag) {return tag.front() == '#'; }); - if (it != tags.end()) - return it->substr(1); - return std::string(); - } - } - - class JunitReporter : public CumulativeReporterBase { - public: - JunitReporter( ReporterConfig const& _config ) - : CumulativeReporterBase( _config ), - xml( _config.stream() ) - { - m_reporterPrefs.shouldRedirectStdOut = true; - } - - ~JunitReporter() override; + virtual ~CompactReporter(); static std::string getDescription() { - return "Reports test results in an XML format that looks like Ant's junitreport target"; + return "Reports test results on a single line, suitable for IDEs"; } - void noMatchingTestCases( std::string const& /*spec*/ ) override {} - - void testRunStarting( TestRunInfo const& runInfo ) override { - CumulativeReporterBase::testRunStarting( runInfo ); - xml.startElement( "testsuites" ); + virtual ReporterPreferences getPreferences() const { + ReporterPreferences prefs; + prefs.shouldRedirectStdOut = false; + return prefs; } - void testGroupStarting( GroupInfo const& groupInfo ) override { - suiteTimer.start(); - stdOutForSuite.str(""); - stdErrForSuite.str(""); - unexpectedExceptions = 0; - CumulativeReporterBase::testGroupStarting( groupInfo ); + virtual void noMatchingTestCases( std::string const& spec ) { + stream << "No test cases matched '" << spec << '\'' << std::endl; } - void testCaseStarting( TestCaseInfo const& testCaseInfo ) override { - m_okToFail = testCaseInfo.okToFail(); - } - bool assertionEnded( AssertionStats const& assertionStats ) override { - if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException && !m_okToFail ) - unexpectedExceptions++; - return CumulativeReporterBase::assertionEnded( assertionStats ); - } + virtual void assertionStarting( AssertionInfo const& ) {} - void testCaseEnded( TestCaseStats const& testCaseStats ) override { - stdOutForSuite << testCaseStats.stdOut; - stdErrForSuite << testCaseStats.stdErr; - CumulativeReporterBase::testCaseEnded( testCaseStats ); - } + virtual bool assertionEnded( AssertionStats const& _assertionStats ) { + AssertionResult const& result = _assertionStats.assertionResult; - void testGroupEnded( TestGroupStats const& testGroupStats ) override { - double suiteTime = suiteTimer.getElapsedSeconds(); - CumulativeReporterBase::testGroupEnded( testGroupStats ); - writeGroup( *m_testGroups.back(), suiteTime ); - } + bool printInfoMessages = true; - void testRunEndedCumulative() override { - xml.endElement(); - } - - void writeGroup( TestGroupNode const& groupNode, double suiteTime ) { - XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" ); - TestGroupStats const& stats = groupNode.value; - xml.writeAttribute( "name", stats.groupInfo.name ); - xml.writeAttribute( "errors", unexpectedExceptions ); - xml.writeAttribute( "failures", stats.totals.assertions.failed-unexpectedExceptions ); - xml.writeAttribute( "tests", stats.totals.assertions.total() ); - xml.writeAttribute( "hostname", "tbd" ); // !TBD - if( m_config->showDurations() == ShowDurations::Never ) - xml.writeAttribute( "time", "" ); - else - xml.writeAttribute( "time", suiteTime ); - xml.writeAttribute( "timestamp", getCurrentTimestamp() ); - - // Write test cases - for( auto const& child : groupNode.children ) - writeTestCase( *child ); - - xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite.str() ), false ); - xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite.str() ), false ); - } - - void writeTestCase( TestCaseNode const& testCaseNode ) { - TestCaseStats const& stats = testCaseNode.value; - - // All test cases have exactly one section - which represents the - // test case itself. That section may have 0-n nested sections - assert( testCaseNode.children.size() == 1 ); - SectionNode const& rootSection = *testCaseNode.children.front(); - - std::string className = stats.testInfo.className; - - if( className.empty() ) { - className = fileNameTag(stats.testInfo.tags); - if ( className.empty() ) - className = "global"; + // Drop out if result was successful and we're not printing those + if( !m_config->includeSuccessfulResults() && result.isOk() ) { + if( result.getResultType() != ResultWas::Warning ) + return false; + printInfoMessages = false; } - if ( !m_config->name().empty() ) - className = m_config->name() + "." + className; + AssertionPrinter printer( stream, _assertionStats, printInfoMessages ); + printer.print(); - writeSection( className, "", rootSection ); + stream << std::endl; + return true; } - void writeSection( std::string const& className, - std::string const& rootName, - SectionNode const& sectionNode ) { - std::string name = trim( sectionNode.stats.sectionInfo.name ); - if( !rootName.empty() ) - name = rootName + '/' + name; - - if( !sectionNode.assertions.empty() || - !sectionNode.stdOut.empty() || - !sectionNode.stdErr.empty() ) { - XmlWriter::ScopedElement e = xml.scopedElement( "testcase" ); - if( className.empty() ) { - xml.writeAttribute( "classname", name ); - xml.writeAttribute( "name", "root" ); - } - else { - xml.writeAttribute( "classname", className ); - xml.writeAttribute( "name", name ); - } - xml.writeAttribute( "time", ::Catch::Detail::stringify( sectionNode.stats.durationInSeconds ) ); - - writeAssertions( sectionNode ); - - if( !sectionNode.stdOut.empty() ) - xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), false ); - if( !sectionNode.stdErr.empty() ) - xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), false ); + virtual void sectionEnded(SectionStats const& _sectionStats) CATCH_OVERRIDE { + if (m_config->showDurations() == ShowDurations::Always) { + stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl; } - for( auto const& childNode : sectionNode.childSections ) - if( className.empty() ) - writeSection( name, "", *childNode ); - else - writeSection( className, name, *childNode ); } - void writeAssertions( SectionNode const& sectionNode ) { - for( auto const& assertion : sectionNode.assertions ) - writeAssertion( assertion ); + virtual void testRunEnded( TestRunStats const& _testRunStats ) { + printTotals( _testRunStats.totals ); + stream << '\n' << std::endl; + StreamingReporterBase::testRunEnded( _testRunStats ); } - void writeAssertion( AssertionStats const& stats ) { - AssertionResult const& result = stats.assertionResult; - if( !result.isOk() ) { - std::string elementName; + + private: + class AssertionPrinter { + void operator= ( AssertionPrinter const& ); + public: + AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages ) + : stream( _stream ) + , stats( _stats ) + , result( _stats.assertionResult ) + , messages( _stats.infoMessages ) + , itMessage( _stats.infoMessages.begin() ) + , printInfoMessages( _printInfoMessages ) + {} + + void print() { + printSourceInfo(); + + itMessage = messages.begin(); + switch( result.getResultType() ) { - case ResultWas::ThrewException: - case ResultWas::FatalErrorCondition: - elementName = "error"; - break; - case ResultWas::ExplicitFailure: - elementName = "failure"; + case ResultWas::Ok: + printResultType( Colour::ResultSuccess, passedString() ); + printOriginalExpression(); + printReconstructedExpression(); + if ( ! result.hasExpression() ) + printRemainingMessages( Colour::None ); + else + printRemainingMessages(); break; case ResultWas::ExpressionFailed: - elementName = "failure"; + if( result.isOk() ) + printResultType( Colour::ResultSuccess, failedString() + std::string( " - but was ok" ) ); + else + printResultType( Colour::Error, failedString() ); + printOriginalExpression(); + printReconstructedExpression(); + printRemainingMessages(); + break; + case ResultWas::ThrewException: + printResultType( Colour::Error, failedString() ); + printIssue( "unexpected exception with message:" ); + printMessage(); + printExpressionWas(); + printRemainingMessages(); + break; + case ResultWas::FatalErrorCondition: + printResultType( Colour::Error, failedString() ); + printIssue( "fatal error condition with message:" ); + printMessage(); + printExpressionWas(); + printRemainingMessages(); break; case ResultWas::DidntThrowException: - elementName = "failure"; + printResultType( Colour::Error, failedString() ); + printIssue( "expected exception, got none" ); + printExpressionWas(); + printRemainingMessages(); break; - - // We should never see these here: case ResultWas::Info: + printResultType( Colour::None, "info" ); + printMessage(); + printRemainingMessages(); + break; case ResultWas::Warning: - case ResultWas::Ok: + printResultType( Colour::None, "warning" ); + printMessage(); + printRemainingMessages(); + break; + case ResultWas::ExplicitFailure: + printResultType( Colour::Error, failedString() ); + printIssue( "explicitly" ); + printRemainingMessages( Colour::None ); + break; + // These cases are here to prevent compiler warnings case ResultWas::Unknown: case ResultWas::FailureBit: case ResultWas::Exception: - elementName = "internalError"; + printResultType( Colour::Error, "** internal error **" ); break; } - - XmlWriter::ScopedElement e = xml.scopedElement( elementName ); - - xml.writeAttribute( "message", result.getExpandedExpression() ); - xml.writeAttribute( "type", result.getTestMacroName() ); - - std::ostringstream oss; - if( !result.getMessage().empty() ) - oss << result.getMessage() << '\n'; - for( auto const& msg : stats.infoMessages ) - if( msg.type == ResultWas::Info ) - oss << msg.message << '\n'; - - oss << "at " << result.getSourceInfo(); - xml.writeText( oss.str(), false ); } - } - XmlWriter xml; - Timer suiteTimer; - std::ostringstream stdOutForSuite; - std::ostringstream stdErrForSuite; - unsigned int unexpectedExceptions = 0; - bool m_okToFail = false; - }; + private: + // Colour::LightGrey - JunitReporter::~JunitReporter() {} - CATCH_REGISTER_REPORTER( "junit", JunitReporter ) + static Colour::Code dimColour() { return Colour::FileName; } -} // end namespace Catch -// end catch_reporter_junit.cpp -// start catch_reporter_multi.cpp - -namespace Catch { - - void MultipleReporters::add( IStreamingReporterPtr&& reporter ) { - m_reporters.push_back( std::move( reporter ) ); - } - - ReporterPreferences MultipleReporters::getPreferences() const { - return m_reporters[0]->getPreferences(); - } - - std::set MultipleReporters::getSupportedVerbosities() { - return std::set{ }; - } - - void MultipleReporters::noMatchingTestCases( std::string const& spec ) { - for( auto const& reporter : m_reporters ) - reporter->noMatchingTestCases( spec ); - } - - void MultipleReporters::benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) { - for( auto const& reporter : m_reporters ) - reporter->benchmarkStarting( benchmarkInfo ); - } - void MultipleReporters::benchmarkEnded( BenchmarkStats const& benchmarkStats ) { - for( auto const& reporter : m_reporters ) - reporter->benchmarkEnded( benchmarkStats ); - } - - void MultipleReporters::testRunStarting( TestRunInfo const& testRunInfo ) { - for( auto const& reporter : m_reporters ) - reporter->testRunStarting( testRunInfo ); - } - - void MultipleReporters::testGroupStarting( GroupInfo const& groupInfo ) { - for( auto const& reporter : m_reporters ) - reporter->testGroupStarting( groupInfo ); - } - - void MultipleReporters::testCaseStarting( TestCaseInfo const& testInfo ) { - for( auto const& reporter : m_reporters ) - reporter->testCaseStarting( testInfo ); - } - - void MultipleReporters::sectionStarting( SectionInfo const& sectionInfo ) { - for( auto const& reporter : m_reporters ) - reporter->sectionStarting( sectionInfo ); - } - - void MultipleReporters::assertionStarting( AssertionInfo const& assertionInfo ) { - for( auto const& reporter : m_reporters ) - reporter->assertionStarting( assertionInfo ); - } - - // The return value indicates if the messages buffer should be cleared: - bool MultipleReporters::assertionEnded( AssertionStats const& assertionStats ) { - bool clearBuffer = false; - for( auto const& reporter : m_reporters ) - clearBuffer |= reporter->assertionEnded( assertionStats ); - return clearBuffer; - } - - void MultipleReporters::sectionEnded( SectionStats const& sectionStats ) { - for( auto const& reporter : m_reporters ) - reporter->sectionEnded( sectionStats ); - } - - void MultipleReporters::testCaseEnded( TestCaseStats const& testCaseStats ) { - for( auto const& reporter : m_reporters ) - reporter->testCaseEnded( testCaseStats ); - } - - void MultipleReporters::testGroupEnded( TestGroupStats const& testGroupStats ) { - for( auto const& reporter : m_reporters ) - reporter->testGroupEnded( testGroupStats ); - } - - void MultipleReporters::testRunEnded( TestRunStats const& testRunStats ) { - for( auto const& reporter : m_reporters ) - reporter->testRunEnded( testRunStats ); - } - - void MultipleReporters::skipTest( TestCaseInfo const& testInfo ) { - for( auto const& reporter : m_reporters ) - reporter->skipTest( testInfo ); - } - - bool MultipleReporters::isMulti() const { - return true; - } - -} // end namespace Catch -// end catch_reporter_multi.cpp -// start catch_reporter_xml.cpp - -#if defined(_MSC_VER) -#pragma warning(push) -#pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch - // Note that 4062 (not all labels are handled - // and default is missing) is enabled +#ifdef CATCH_PLATFORM_MAC + static const char* failedString() { return "FAILED"; } + static const char* passedString() { return "PASSED"; } +#else + static const char* failedString() { return "failed"; } + static const char* passedString() { return "passed"; } #endif -namespace Catch { - class XmlReporter : public StreamingReporterBase { - public: - XmlReporter( ReporterConfig const& _config ) - : StreamingReporterBase( _config ), - m_xml(_config.stream()) - { - m_reporterPrefs.shouldRedirectStdOut = true; - } - - ~XmlReporter() override; - - static std::string getDescription() { - return "Reports test results as an XML document"; - } - - virtual std::string getStylesheetRef() const { - return std::string(); - } - - void writeSourceInfo( SourceLineInfo const& sourceInfo ) { - m_xml - .writeAttribute( "filename", sourceInfo.file ) - .writeAttribute( "line", sourceInfo.line ); - } - - public: // StreamingReporterBase - - void noMatchingTestCases( std::string const& s ) override { - StreamingReporterBase::noMatchingTestCases( s ); - } - - void testRunStarting( TestRunInfo const& testInfo ) override { - StreamingReporterBase::testRunStarting( testInfo ); - std::string stylesheetRef = getStylesheetRef(); - if( !stylesheetRef.empty() ) - m_xml.writeStylesheetRef( stylesheetRef ); - m_xml.startElement( "Catch" ); - if( !m_config->name().empty() ) - m_xml.writeAttribute( "name", m_config->name() ); - } - - void testGroupStarting( GroupInfo const& groupInfo ) override { - StreamingReporterBase::testGroupStarting( groupInfo ); - m_xml.startElement( "Group" ) - .writeAttribute( "name", groupInfo.name ); - } - - void testCaseStarting( TestCaseInfo const& testInfo ) override { - StreamingReporterBase::testCaseStarting(testInfo); - m_xml.startElement( "TestCase" ) - .writeAttribute( "name", trim( testInfo.name ) ) - .writeAttribute( "description", testInfo.description ) - .writeAttribute( "tags", testInfo.tagsAsString() ); - - writeSourceInfo( testInfo.lineInfo ); - - if ( m_config->showDurations() == ShowDurations::Always ) - m_testCaseTimer.start(); - m_xml.ensureTagClosed(); - } - - void sectionStarting( SectionInfo const& sectionInfo ) override { - StreamingReporterBase::sectionStarting( sectionInfo ); - if( m_sectionDepth++ > 0 ) { - m_xml.startElement( "Section" ) - .writeAttribute( "name", trim( sectionInfo.name ) ) - .writeAttribute( "description", sectionInfo.description ); - writeSourceInfo( sectionInfo.lineInfo ); - m_xml.ensureTagClosed(); + void printSourceInfo() const { + Colour colourGuard( Colour::FileName ); + stream << result.getSourceInfo() << ':'; } - } - void assertionStarting( AssertionInfo const& ) override { } + void printResultType( Colour::Code colour, std::string const& passOrFail ) const { + if( !passOrFail.empty() ) { + { + Colour colourGuard( colour ); + stream << ' ' << passOrFail; + } + stream << ':'; + } + } - bool assertionEnded( AssertionStats const& assertionStats ) override { + void printIssue( std::string const& issue ) const { + stream << ' ' << issue; + } - AssertionResult const& result = assertionStats.assertionResult; + void printExpressionWas() { + if( result.hasExpression() ) { + stream << ';'; + { + Colour colour( dimColour() ); + stream << " expression was:"; + } + printOriginalExpression(); + } + } - bool includeResults = m_config->includeSuccessfulResults() || !result.isOk(); + void printOriginalExpression() const { + if( result.hasExpression() ) { + stream << ' ' << result.getExpression(); + } + } - if( includeResults ) { - // Print any info messages in tags. - for( auto const& msg : assertionStats.infoMessages ) { - if( msg.type == ResultWas::Info ) { - m_xml.scopedElement( "Info" ) - .writeText( msg.message ); - } else if ( msg.type == ResultWas::Warning ) { - m_xml.scopedElement( "Warning" ) - .writeText( msg.message ); + void printReconstructedExpression() const { + if( result.hasExpandedExpression() ) { + { + Colour colour( dimColour() ); + stream << " for: "; + } + stream << result.getExpandedExpression(); + } + } + + void printMessage() { + if ( itMessage != messages.end() ) { + stream << " '" << itMessage->message << '\''; + ++itMessage; + } + } + + void printRemainingMessages( Colour::Code colour = dimColour() ) { + if ( itMessage == messages.end() ) + return; + + // using messages.end() directly yields compilation error: + std::vector::const_iterator itEnd = messages.end(); + const std::size_t N = static_cast( std::distance( itMessage, itEnd ) ); + + { + Colour colourGuard( colour ); + stream << " with " << pluralise( N, "message" ) << ':'; + } + + for(; itMessage != itEnd; ) { + // If this assertion is a warning ignore any INFO messages + if( printInfoMessages || itMessage->type != ResultWas::Info ) { + stream << " '" << itMessage->message << '\''; + if ( ++itMessage != itEnd ) { + Colour colourGuard( dimColour() ); + stream << " and"; + } } } } - // Drop out if result was successful but we're not printing them. - if( !includeResults && result.getResultType() != ResultWas::Warning ) - return true; + private: + std::ostream& stream; + AssertionStats const& stats; + AssertionResult const& result; + std::vector messages; + std::vector::const_iterator itMessage; + bool printInfoMessages; + }; - // Print the expression if there is one. - if( result.hasExpression() ) { - m_xml.startElement( "Expression" ) - .writeAttribute( "success", result.succeeded() ) - .writeAttribute( "type", result.getTestMacroName() ); + // Colour, message variants: + // - white: No tests ran. + // - red: Failed [both/all] N test cases, failed [both/all] M assertions. + // - white: Passed [both/all] N test cases (no assertions). + // - red: Failed N tests cases, failed M assertions. + // - green: Passed [both/all] N tests cases with M assertions. - writeSourceInfo( result.getSourceInfo() ); - - m_xml.scopedElement( "Original" ) - .writeText( result.getExpression() ); - m_xml.scopedElement( "Expanded" ) - .writeText( result.getExpandedExpression() ); - } - - // And... Print a result applicable to each result type. - switch( result.getResultType() ) { - case ResultWas::ThrewException: - m_xml.startElement( "Exception" ); - writeSourceInfo( result.getSourceInfo() ); - m_xml.writeText( result.getMessage() ); - m_xml.endElement(); - break; - case ResultWas::FatalErrorCondition: - m_xml.startElement( "FatalErrorCondition" ); - writeSourceInfo( result.getSourceInfo() ); - m_xml.writeText( result.getMessage() ); - m_xml.endElement(); - break; - case ResultWas::Info: - m_xml.scopedElement( "Info" ) - .writeText( result.getMessage() ); - break; - case ResultWas::Warning: - // Warning will already have been written - break; - case ResultWas::ExplicitFailure: - m_xml.startElement( "Failure" ); - writeSourceInfo( result.getSourceInfo() ); - m_xml.writeText( result.getMessage() ); - m_xml.endElement(); - break; - default: - break; - } - - if( result.hasExpression() ) - m_xml.endElement(); - - return true; + std::string bothOrAll( std::size_t count ) const { + return count == 1 ? std::string() : count == 2 ? "both " : "all " ; } - void sectionEnded( SectionStats const& sectionStats ) override { - StreamingReporterBase::sectionEnded( sectionStats ); - if( --m_sectionDepth > 0 ) { - XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" ); - e.writeAttribute( "successes", sectionStats.assertions.passed ); - e.writeAttribute( "failures", sectionStats.assertions.failed ); - e.writeAttribute( "expectedFailures", sectionStats.assertions.failedButOk ); - - if ( m_config->showDurations() == ShowDurations::Always ) - e.writeAttribute( "durationInSeconds", sectionStats.durationInSeconds ); - - m_xml.endElement(); + void printTotals( const Totals& totals ) const { + if( totals.testCases.total() == 0 ) { + stream << "No tests ran."; + } + else if( totals.testCases.failed == totals.testCases.total() ) { + Colour colour( Colour::ResultError ); + const std::string qualify_assertions_failed = + totals.assertions.failed == totals.assertions.total() ? + bothOrAll( totals.assertions.failed ) : std::string(); + stream << + "Failed " << bothOrAll( totals.testCases.failed ) + << pluralise( totals.testCases.failed, "test case" ) << ", " + "failed " << qualify_assertions_failed << + pluralise( totals.assertions.failed, "assertion" ) << '.'; + } + else if( totals.assertions.total() == 0 ) { + stream << + "Passed " << bothOrAll( totals.testCases.total() ) + << pluralise( totals.testCases.total(), "test case" ) + << " (no assertions)."; + } + else if( totals.assertions.failed ) { + Colour colour( Colour::ResultError ); + stream << + "Failed " << pluralise( totals.testCases.failed, "test case" ) << ", " + "failed " << pluralise( totals.assertions.failed, "assertion" ) << '.'; + } + else { + Colour colour( Colour::ResultSuccess ); + stream << + "Passed " << bothOrAll( totals.testCases.passed ) + << pluralise( totals.testCases.passed, "test case" ) << + " with " << pluralise( totals.assertions.passed, "assertion" ) << '.'; } } - - void testCaseEnded( TestCaseStats const& testCaseStats ) override { - StreamingReporterBase::testCaseEnded( testCaseStats ); - XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" ); - e.writeAttribute( "success", testCaseStats.totals.assertions.allOk() ); - - if ( m_config->showDurations() == ShowDurations::Always ) - e.writeAttribute( "durationInSeconds", m_testCaseTimer.getElapsedSeconds() ); - - if( !testCaseStats.stdOut.empty() ) - m_xml.scopedElement( "StdOut" ).writeText( trim( testCaseStats.stdOut ), false ); - if( !testCaseStats.stdErr.empty() ) - m_xml.scopedElement( "StdErr" ).writeText( trim( testCaseStats.stdErr ), false ); - - m_xml.endElement(); - } - - void testGroupEnded( TestGroupStats const& testGroupStats ) override { - StreamingReporterBase::testGroupEnded( testGroupStats ); - // TODO: Check testGroupStats.aborting and act accordingly. - m_xml.scopedElement( "OverallResults" ) - .writeAttribute( "successes", testGroupStats.totals.assertions.passed ) - .writeAttribute( "failures", testGroupStats.totals.assertions.failed ) - .writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk ); - m_xml.endElement(); - } - - void testRunEnded( TestRunStats const& testRunStats ) override { - StreamingReporterBase::testRunEnded( testRunStats ); - m_xml.scopedElement( "OverallResults" ) - .writeAttribute( "successes", testRunStats.totals.assertions.passed ) - .writeAttribute( "failures", testRunStats.totals.assertions.failed ) - .writeAttribute( "expectedFailures", testRunStats.totals.assertions.failedButOk ); - m_xml.endElement(); - } - - private: - Timer m_testCaseTimer; - XmlWriter m_xml; - int m_sectionDepth = 0; }; - XmlReporter::~XmlReporter() {} - CATCH_REGISTER_REPORTER( "xml", XmlReporter ) + INTERNAL_CATCH_REGISTER_REPORTER( "compact", CompactReporter ) } // end namespace Catch -#if defined(_MSC_VER) -#pragma warning(pop) -#endif -// end catch_reporter_xml.cpp - namespace Catch { - LeakDetector leakDetector; + // These are all here to avoid warnings about not having any out of line + // virtual methods + NonCopyable::~NonCopyable() {} + IShared::~IShared() {} + IStream::~IStream() CATCH_NOEXCEPT {} + FileStream::~FileStream() CATCH_NOEXCEPT {} + CoutStream::~CoutStream() CATCH_NOEXCEPT {} + DebugOutStream::~DebugOutStream() CATCH_NOEXCEPT {} + StreamBufBase::~StreamBufBase() CATCH_NOEXCEPT {} + IContext::~IContext() {} + IResultCapture::~IResultCapture() {} + ITestCase::~ITestCase() {} + ITestCaseRegistry::~ITestCaseRegistry() {} + IRegistryHub::~IRegistryHub() {} + IMutableRegistryHub::~IMutableRegistryHub() {} + IExceptionTranslator::~IExceptionTranslator() {} + IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() {} + IReporter::~IReporter() {} + IReporterFactory::~IReporterFactory() {} + IReporterRegistry::~IReporterRegistry() {} + IStreamingReporter::~IStreamingReporter() {} + AssertionStats::~AssertionStats() {} + SectionStats::~SectionStats() {} + TestCaseStats::~TestCaseStats() {} + TestGroupStats::~TestGroupStats() {} + TestRunStats::~TestRunStats() {} + CumulativeReporterBase::SectionNode::~SectionNode() {} + CumulativeReporterBase::~CumulativeReporterBase() {} + + StreamingReporterBase::~StreamingReporterBase() {} + ConsoleReporter::~ConsoleReporter() {} + CompactReporter::~CompactReporter() {} + IRunner::~IRunner() {} + IMutableContext::~IMutableContext() {} + IConfig::~IConfig() {} + XmlReporter::~XmlReporter() {} + JunitReporter::~JunitReporter() {} + TestRegistry::~TestRegistry() {} + FreeFunctionTestCase::~FreeFunctionTestCase() {} + IGeneratorInfo::~IGeneratorInfo() {} + IGeneratorsForTest::~IGeneratorsForTest() {} + WildcardPattern::~WildcardPattern() {} + TestSpec::Pattern::~Pattern() {} + TestSpec::NamePattern::~NamePattern() {} + TestSpec::TagPattern::~TagPattern() {} + TestSpec::ExcludedPattern::~ExcludedPattern() {} + Matchers::Impl::MatcherUntypedBase::~MatcherUntypedBase() {} + + void Config::dummy() {} + + namespace TestCaseTracking { + ITracker::~ITracker() {} + TrackerBase::~TrackerBase() {} + SectionTracker::~SectionTracker() {} + IndexTracker::~IndexTracker() {} + } } #ifdef __clang__ #pragma clang diagnostic pop #endif -// end catch_impl.hpp #endif #ifdef CATCH_CONFIG_MAIN -// start catch_default_main.hpp +// #included from: internal/catch_default_main.hpp +#define TWOBLUECUBES_CATCH_DEFAULT_MAIN_HPP_INCLUDED #ifndef __OBJC__ @@ -11713,7 +11399,8 @@ extern "C" int wmain (int argc, wchar_t * argv[], wchar_t * []) { int main (int argc, char * argv[]) { #endif - return Catch::Session().run( argc, argv ); + int result = Catch::Session().run( argc, argv ); + return ( result < 0xff ? result : 0xff ); } #else // __OBJC__ @@ -11725,122 +11412,149 @@ int main (int argc, char * const argv[]) { #endif Catch::registerTestMethods(); - int result = Catch::Session().run( argc, (char**)argv ); + int result = Catch::Session().run( argc, (char* const*)argv ); #if !CATCH_ARC_ENABLED [pool drain]; #endif - return result; + return ( result < 0xff ? result : 0xff ); } #endif // __OBJC__ -// end catch_default_main.hpp #endif #ifdef CLARA_CONFIG_MAIN_NOT_DEFINED # undef CLARA_CONFIG_MAIN #endif -#if !defined(CATCH_CONFIG_DISABLE) ////// + // If this config identifier is defined then all CATCH macros are prefixed with CATCH_ #ifdef CATCH_CONFIG_PREFIX_ALL -#define CATCH_REQUIRE( ... ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE", Catch::ResultDisposition::Normal, __VA_ARGS__ ) -#define CATCH_REQUIRE_FALSE( ... ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, __VA_ARGS__ ) +#if defined(CATCH_CONFIG_FAST_COMPILE) +#define CATCH_REQUIRE( expr ) INTERNAL_CATCH_TEST_NO_TRY( "CATCH_REQUIRE", Catch::ResultDisposition::Normal, expr ) +#define CATCH_REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST_NO_TRY( "CATCH_REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, expr ) +#else +#define CATCH_REQUIRE( expr ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE", Catch::ResultDisposition::Normal, expr ) +#define CATCH_REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, expr ) +#endif -#define CATCH_REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS", Catch::ResultDisposition::Normal, "", __VA_ARGS__ ) +#define CATCH_REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS", Catch::ResultDisposition::Normal, "", expr ) #define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr ) -#define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CATCH_REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr ) -#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) -#define CATCH_REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CATCH_REQUIRE_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::Normal, matcher, expr ) -#endif// CATCH_CONFIG_DISABLE_MATCHERS -#define CATCH_REQUIRE_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CATCH_REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, __VA_ARGS__ ) +#define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr ) +#define CATCH_REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( "CATCH_REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, expr ) -#define CATCH_CHECK( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) -#define CATCH_CHECK_FALSE( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, __VA_ARGS__ ) -#define CATCH_CHECKED_IF( ... ) INTERNAL_CATCH_IF( "CATCH_CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) -#define CATCH_CHECKED_ELSE( ... ) INTERNAL_CATCH_ELSE( "CATCH_CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) -#define CATCH_CHECK_NOFAIL( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ ) +#define CATCH_CHECK( expr ) INTERNAL_CATCH_TEST( "CATCH_CHECK", Catch::ResultDisposition::ContinueOnFailure, expr ) +#define CATCH_CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( "CATCH_CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, expr ) +#define CATCH_CHECKED_IF( expr ) INTERNAL_CATCH_IF( "CATCH_CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure, expr ) +#define CATCH_CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( "CATCH_CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, expr ) +#define CATCH_CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( "CATCH_CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, expr ) -#define CATCH_CHECK_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, "", __VA_ARGS__ ) +#define CATCH_CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, "", expr ) #define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr ) -#define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CATCH_CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) -#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) -#define CATCH_CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CATCH_CHECK_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) -#endif // CATCH_CONFIG_DISABLE_MATCHERS -#define CATCH_CHECK_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CATCH_CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) +#define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) +#define CATCH_CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( "CATCH_CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, expr ) -#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) #define CATCH_CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg ) +#if defined(CATCH_CONFIG_FAST_COMPILE) +#define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT_NO_TRY( "CATCH_REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg ) +#else #define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg ) -#endif // CATCH_CONFIG_DISABLE_MATCHERS +#endif #define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( "CATCH_INFO", msg ) #define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( "CATCH_WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg ) -#define CATCH_CAPTURE( msg ) INTERNAL_CATCH_INFO( "CATCH_CAPTURE", #msg " := " << ::Catch::Detail::stringify(msg) ) +#define CATCH_SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( "CATCH_INFO", msg ) +#define CATCH_CAPTURE( msg ) INTERNAL_CATCH_INFO( "CATCH_CAPTURE", #msg " := " << Catch::toString(msg) ) +#define CATCH_SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( "CATCH_CAPTURE", #msg " := " << Catch::toString(msg) ) -#define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) -#define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) -#define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) -#define CATCH_REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ ) -#define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) -#define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ ) -#define CATCH_FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) -#define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( "CATCH_SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) +#ifdef CATCH_CONFIG_VARIADIC_MACROS + #define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) + #define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) + #define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) + #define CATCH_REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ ) + #define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) + #define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ ) + #define CATCH_FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) + #define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( "CATCH_SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) +#else + #define CATCH_TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description ) + #define CATCH_TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description ) + #define CATCH_METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description ) + #define CATCH_REGISTER_TEST_CASE( function, name, description ) INTERNAL_CATCH_REGISTER_TESTCASE( function, name, description ) + #define CATCH_SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description ) + #define CATCH_FAIL( msg ) INTERNAL_CATCH_MSG( "CATCH_FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, msg ) + #define CATCH_FAIL_CHECK( msg ) INTERNAL_CATCH_MSG( "CATCH_FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, msg ) + #define CATCH_SUCCEED( msg ) INTERNAL_CATCH_MSG( "CATCH_SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, msg ) +#endif +#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" ) -#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE() +#define CATCH_REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) +#define CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) + +#define CATCH_GENERATE( expr) INTERNAL_CATCH_GENERATE( expr ) // "BDD-style" convenience wrappers +#ifdef CATCH_CONFIG_VARIADIC_MACROS #define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ ) #define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) -#define CATCH_GIVEN( desc ) CATCH_SECTION( std::string( "Given: ") + desc ) -#define CATCH_WHEN( desc ) CATCH_SECTION( std::string( " When: ") + desc ) -#define CATCH_AND_WHEN( desc ) CATCH_SECTION( std::string( " And: ") + desc ) -#define CATCH_THEN( desc ) CATCH_SECTION( std::string( " Then: ") + desc ) -#define CATCH_AND_THEN( desc ) CATCH_SECTION( std::string( " And: ") + desc ) +#else +#define CATCH_SCENARIO( name, tags ) CATCH_TEST_CASE( "Scenario: " name, tags ) +#define CATCH_SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags ) +#endif +#define CATCH_GIVEN( desc ) CATCH_SECTION( std::string( "Given: ") + desc, "" ) +#define CATCH_WHEN( desc ) CATCH_SECTION( std::string( " When: ") + desc, "" ) +#define CATCH_AND_WHEN( desc ) CATCH_SECTION( std::string( " And: ") + desc, "" ) +#define CATCH_THEN( desc ) CATCH_SECTION( std::string( " Then: ") + desc, "" ) +#define CATCH_AND_THEN( desc ) CATCH_SECTION( std::string( " And: ") + desc, "" ) // If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required #else -#define REQUIRE( ... ) INTERNAL_CATCH_TEST( "REQUIRE", Catch::ResultDisposition::Normal, __VA_ARGS__ ) -#define REQUIRE_FALSE( ... ) INTERNAL_CATCH_TEST( "REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, __VA_ARGS__ ) +#if defined(CATCH_CONFIG_FAST_COMPILE) +#define REQUIRE( expr ) INTERNAL_CATCH_TEST_NO_TRY( "REQUIRE", Catch::ResultDisposition::Normal, expr ) +#define REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST_NO_TRY( "REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, expr ) -#define REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "REQUIRE_THROWS", Catch::ResultDisposition::Normal, __VA_ARGS__ ) +#else +#define REQUIRE( expr ) INTERNAL_CATCH_TEST( "REQUIRE", Catch::ResultDisposition::Normal, expr ) +#define REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( "REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, expr ) +#endif + +#define REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( "REQUIRE_THROWS", Catch::ResultDisposition::Normal, "", expr ) #define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr ) -#define REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr ) -#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) -#define REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "REQUIRE_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::Normal, matcher, expr ) -#endif // CATCH_CONFIG_DISABLE_MATCHERS -#define REQUIRE_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, __VA_ARGS__ ) +#define REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( "REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr ) +#define REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( "REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, expr ) -#define CHECK( ... ) INTERNAL_CATCH_TEST( "CHECK", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) -#define CHECK_FALSE( ... ) INTERNAL_CATCH_TEST( "CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, __VA_ARGS__ ) -#define CHECKED_IF( ... ) INTERNAL_CATCH_IF( "CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) -#define CHECKED_ELSE( ... ) INTERNAL_CATCH_ELSE( "CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) -#define CHECK_NOFAIL( ... ) INTERNAL_CATCH_TEST( "CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ ) +#define CHECK( expr ) INTERNAL_CATCH_TEST( "CHECK", Catch::ResultDisposition::ContinueOnFailure, expr ) +#define CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( "CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, expr ) +#define CHECKED_IF( expr ) INTERNAL_CATCH_IF( "CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure, expr ) +#define CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( "CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, expr ) +#define CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( "CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, expr ) -#define CHECK_THROWS( ... ) INTERNAL_CATCH_THROWS( "CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) +#define CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( "CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, "", expr ) #define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr ) -#define CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) -#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) -#define CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CHECK_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) -#endif // CATCH_CONFIG_DISABLE_MATCHERS -#define CHECK_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) +#define CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( "CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) +#define CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( "CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, expr ) -#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) #define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg ) +#if defined(CATCH_CONFIG_FAST_COMPILE) +#define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT_NO_TRY( "REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg ) +#else #define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg ) -#endif // CATCH_CONFIG_DISABLE_MATCHERS +#endif #define INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg ) #define WARN( msg ) INTERNAL_CATCH_MSG( "WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg ) -#define CAPTURE( msg ) INTERNAL_CATCH_INFO( "CAPTURE", #msg " := " << ::Catch::Detail::stringify(msg) ) +#define SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg ) +#define CAPTURE( msg ) INTERNAL_CATCH_INFO( "CAPTURE", #msg " := " << Catch::toString(msg) ) +#define SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( "CAPTURE", #msg " := " << Catch::toString(msg) ) +#ifdef CATCH_CONFIG_VARIADIC_MACROS #define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) #define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) #define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) @@ -11849,152 +11563,46 @@ int main (int argc, char * const argv[]) { #define FAIL( ... ) INTERNAL_CATCH_MSG( "FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ ) #define FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) #define SUCCEED( ... ) INTERNAL_CATCH_MSG( "SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) -#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE() +#else +#define TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description ) + #define TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description ) + #define METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description ) + #define REGISTER_TEST_CASE( method, name, description ) INTERNAL_CATCH_REGISTER_TESTCASE( method, name, description ) + #define SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description ) + #define FAIL( msg ) INTERNAL_CATCH_MSG( "FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, msg ) + #define FAIL_CHECK( msg ) INTERNAL_CATCH_MSG( "FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, msg ) + #define SUCCEED( msg ) INTERNAL_CATCH_MSG( "SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, msg ) +#endif +#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" ) + +#define REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) +#define REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) + +#define GENERATE( expr) INTERNAL_CATCH_GENERATE( expr ) #endif #define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) // "BDD-style" convenience wrappers +#ifdef CATCH_CONFIG_VARIADIC_MACROS #define SCENARIO( ... ) TEST_CASE( "Scenario: " __VA_ARGS__ ) #define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) - -#define GIVEN( desc ) SECTION( std::string(" Given: ") + desc ) -#define WHEN( desc ) SECTION( std::string(" When: ") + desc ) -#define AND_WHEN( desc ) SECTION( std::string("And when: ") + desc ) -#define THEN( desc ) SECTION( std::string(" Then: ") + desc ) -#define AND_THEN( desc ) SECTION( std::string(" And: ") + desc ) +#else +#define SCENARIO( name, tags ) TEST_CASE( "Scenario: " name, tags ) +#define SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags ) +#endif +#define GIVEN( desc ) SECTION( std::string(" Given: ") + desc, "" ) +#define WHEN( desc ) SECTION( std::string(" When: ") + desc, "" ) +#define AND_WHEN( desc ) SECTION( std::string("And when: ") + desc, "" ) +#define THEN( desc ) SECTION( std::string(" Then: ") + desc, "" ) +#define AND_THEN( desc ) SECTION( std::string(" And: ") + desc, "" ) using Catch::Detail::Approx; -#else -////// -// If this config identifier is defined then all CATCH macros are prefixed with CATCH_ -#ifdef CATCH_CONFIG_PREFIX_ALL - -#define CATCH_REQUIRE( ... ) (void)(0) -#define CATCH_REQUIRE_FALSE( ... ) (void)(0) - -#define CATCH_REQUIRE_THROWS( ... ) (void)(0) -#define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) (void)(0) -#define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) (void)(0) -#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) -#define CATCH_REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0) -#endif// CATCH_CONFIG_DISABLE_MATCHERS -#define CATCH_REQUIRE_NOTHROW( ... ) (void)(0) - -#define CATCH_CHECK( ... ) (void)(0) -#define CATCH_CHECK_FALSE( ... ) (void)(0) -#define CATCH_CHECKED_IF( ... ) if (__VA_ARGS__) -#define CATCH_CHECKED_ELSE( ... ) if (!(__VA_ARGS__)) -#define CATCH_CHECK_NOFAIL( ... ) (void)(0) - -#define CATCH_CHECK_THROWS( ... ) (void)(0) -#define CATCH_CHECK_THROWS_AS( expr, exceptionType ) (void)(0) -#define CATCH_CHECK_THROWS_WITH( expr, matcher ) (void)(0) -#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) -#define CATCH_CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0) -#endif // CATCH_CONFIG_DISABLE_MATCHERS -#define CATCH_CHECK_NOTHROW( ... ) (void)(0) - -#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) -#define CATCH_CHECK_THAT( arg, matcher ) (void)(0) - -#define CATCH_REQUIRE_THAT( arg, matcher ) (void)(0) -#endif // CATCH_CONFIG_DISABLE_MATCHERS - -#define CATCH_INFO( msg ) (void)(0) -#define CATCH_WARN( msg ) (void)(0) -#define CATCH_CAPTURE( msg ) (void)(0) - -#define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) -#define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) -#define CATCH_METHOD_AS_TEST_CASE( method, ... ) -#define CATCH_REGISTER_TEST_CASE( Function, ... ) (void)(0) -#define CATCH_SECTION( ... ) -#define CATCH_FAIL( ... ) (void)(0) -#define CATCH_FAIL_CHECK( ... ) (void)(0) -#define CATCH_SUCCEED( ... ) (void)(0) - -#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) - -// "BDD-style" convenience wrappers -#define CATCH_SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) -#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), className ) -#define CATCH_GIVEN( desc ) -#define CATCH_WHEN( desc ) -#define CATCH_AND_WHEN( desc ) -#define CATCH_THEN( desc ) -#define CATCH_AND_THEN( desc ) - -// If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required -#else - -#define REQUIRE( ... ) (void)(0) -#define REQUIRE_FALSE( ... ) (void)(0) - -#define REQUIRE_THROWS( ... ) (void)(0) -#define REQUIRE_THROWS_AS( expr, exceptionType ) (void)(0) -#define REQUIRE_THROWS_WITH( expr, matcher ) (void)(0) -#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) -#define REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0) -#endif // CATCH_CONFIG_DISABLE_MATCHERS -#define REQUIRE_NOTHROW( ... ) (void)(0) - -#define CHECK( ... ) (void)(0) -#define CHECK_FALSE( ... ) (void)(0) -#define CHECKED_IF( ... ) if (__VA_ARGS__) -#define CHECKED_ELSE( ... ) if (!(__VA_ARGS__)) -#define CHECK_NOFAIL( ... ) (void)(0) - -#define CHECK_THROWS( ... ) (void)(0) -#define CHECK_THROWS_AS( expr, exceptionType ) (void)(0) -#define CHECK_THROWS_WITH( expr, matcher ) (void)(0) -#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) -#define CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0) -#endif // CATCH_CONFIG_DISABLE_MATCHERS -#define CHECK_NOTHROW( ... ) (void)(0) - -#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) -#define CHECK_THAT( arg, matcher ) (void)(0) - -#define REQUIRE_THAT( arg, matcher ) (void)(0) -#endif // CATCH_CONFIG_DISABLE_MATCHERS - -#define INFO( msg ) (void)(0) -#define WARN( msg ) (void)(0) -#define CAPTURE( msg ) (void)(0) - -#define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) -#define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) -#define METHOD_AS_TEST_CASE( method, ... ) -#define REGISTER_TEST_CASE( Function, ... ) (void)(0) -#define SECTION( ... ) -#define FAIL( ... ) (void)(0) -#define FAIL_CHECK( ... ) (void)(0) -#define SUCCEED( ... ) (void)(0) -#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) - -#endif - -#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION_NO_REG( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature ) - -// "BDD-style" convenience wrappers -#define SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) ) -#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), className ) - -#define GIVEN( desc ) -#define WHEN( desc ) -#define AND_WHEN( desc ) -#define THEN( desc ) -#define AND_THEN( desc ) - -using Catch::Detail::Approx; - -#endif - -// start catch_reenable_warnings.h +// #included from: internal/catch_reenable_warnings.h +#define TWOBLUECUBES_CATCH_REENABLE_WARNINGS_H_INCLUDED #ifdef __clang__ # ifdef __ICC // icpc defines the __clang__ macro @@ -12006,7 +11614,5 @@ using Catch::Detail::Approx; # pragma GCC diagnostic pop #endif -// end catch_reenable_warnings.h -// end catch.hpp #endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED From 261caec2de8cbec09829fadd3a5d6e38919b18e4 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Thu, 14 Dec 2017 22:29:39 +0100 Subject: [PATCH 07/59] :busts_in_silhouette: added contributor image --- README.md | 2 ++ doc/avatars.png | Bin 0 -> 543063 bytes 2 files changed, 2 insertions(+) create mode 100644 doc/avatars.png diff --git a/README.md b/README.md index 7b50c841..e6a68626 100644 --- a/README.md +++ b/README.md @@ -820,6 +820,8 @@ Only if your request would contain confidential information, please [send me an I deeply appreciate the help of the following people. +![Contributors](https://raw.githubusercontent.com/nlohmann/json/develop/doc/avatars.png) + - [Teemperor](https://github.com/Teemperor) implemented CMake support and lcov integration, realized escape and Unicode handling in the string parser, and fixed the JSON serialization. - [elliotgoodrich](https://github.com/elliotgoodrich) fixed an issue with double deletion in the iterator classes. - [kirkshoop](https://github.com/kirkshoop) made the iterators of the class composable to other libraries. diff --git a/doc/avatars.png b/doc/avatars.png new file mode 100644 index 0000000000000000000000000000000000000000..b416a2854c9485ea1afa5204e8599075d1595bb6 GIT binary patch literal 543063 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ðwtxoJ9(bh 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

!DFFc3mJlEOEBgN|>!i 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�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 z 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 Ef`X8P!2kdN literal 0 HcmV?d00001 From c23f5dcea6013442bec72dfe26a78a65eaa5e3ea Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Fri, 15 Dec 2017 23:49:37 +0100 Subject: [PATCH 08/59] :memo: fixed year --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e6a68626..7e68f862 100644 --- a/README.md +++ b/README.md @@ -739,7 +739,7 @@ json j_from_msgpack = json::from_msgpack(v_msgpack); ## Supported compilers -Though it's 2016 already, the support for C++11 is still a bit sparse. Currently, the following compilers are known to work: +Though it's 2017 already, the support for C++11 is still a bit sparse. Currently, the following compilers are known to work: - GCC 4.9 - 7.2 (and possibly later) - Clang 3.4 - 5.0 (and possibly later) From 4c871c58f80babe0a486c01c8f1987f96719a581 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sat, 16 Dec 2017 11:16:34 +0100 Subject: [PATCH 09/59] :white_check_mark: re-added tests for algorithms --- test/src/unit-algorithms.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/test/src/unit-algorithms.cpp b/test/src/unit-algorithms.cpp index bc108dcd..5a106b6a 100644 --- a/test/src/unit-algorithms.cpp +++ b/test/src/unit-algorithms.cpp @@ -256,7 +256,6 @@ TEST_CASE("algorithms") SECTION("set operations") { - /* SECTION("std::merge") { { @@ -268,7 +267,6 @@ TEST_CASE("algorithms") CHECK(j3 == json({1, 2, 2, 3, 4, 5, 6, 7, 8})); } } - */ SECTION("std::set_difference") { @@ -290,7 +288,6 @@ TEST_CASE("algorithms") CHECK(j3 == json({1, 2, 3, 5, 7})); } - /* SECTION("std::set_union") { json j1 = {2, 4, 6, 8}; @@ -310,7 +307,6 @@ TEST_CASE("algorithms") std::set_symmetric_difference(j1.begin(), j1.end(), j2.begin(), j2.end(), std::back_inserter(j3)); CHECK(j3 == json({1, 3, 4, 5, 6, 7, 8})); } - */ } SECTION("heap operations") From f3bd755cab0f47791f9039354f1836f11578b78b Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sat, 16 Dec 2017 12:37:25 +0100 Subject: [PATCH 10/59] :heavy_minus_sign: removing header --- doc/examples/README.cpp | 1 - doc/examples/README.link | 2 +- doc/examples/diff.cpp | 1 - doc/examples/diff.link | 2 +- doc/examples/flatten.cpp | 1 - doc/examples/flatten.link | 2 +- doc/examples/from_cbor.cpp | 1 - doc/examples/from_cbor.link | 2 +- doc/examples/from_msgpack.cpp | 1 - doc/examples/from_msgpack.link | 2 +- doc/examples/meta.cpp | 1 - doc/examples/meta.link | 2 +- doc/examples/meta.output | 2 +- doc/examples/operator_deserialize.cpp | 1 - doc/examples/operator_deserialize.link | 2 +- doc/examples/operator_serialize.cpp | 1 - doc/examples/operator_serialize.link | 2 +- doc/examples/operatorarray__key_type.cpp | 1 - doc/examples/operatorarray__key_type.link | 2 +- doc/examples/parse__array__parser_callback_t.cpp | 1 - doc/examples/parse__array__parser_callback_t.link | 2 +- doc/examples/parse__contiguouscontainer__parser_callback_t.cpp | 1 - doc/examples/parse__contiguouscontainer__parser_callback_t.link | 2 +- doc/examples/parse__istream__parser_callback_t.cpp | 1 - doc/examples/parse__istream__parser_callback_t.link | 2 +- doc/examples/parse__iteratortype__parser_callback_t.cpp | 1 - doc/examples/parse__iteratortype__parser_callback_t.link | 2 +- doc/examples/parse__string__parser_callback_t.cpp | 1 - doc/examples/parse__string__parser_callback_t.link | 2 +- doc/examples/patch.cpp | 1 - doc/examples/patch.link | 2 +- doc/examples/to_cbor.cpp | 1 - doc/examples/to_cbor.link | 2 +- doc/examples/to_msgpack.cpp | 1 - doc/examples/to_msgpack.link | 2 +- doc/examples/unflatten.cpp | 1 - doc/examples/unflatten.link | 2 +- 37 files changed, 19 insertions(+), 37 deletions(-) diff --git a/doc/examples/README.cpp b/doc/examples/README.cpp index 00c93b5d..5a8ab38f 100644 --- a/doc/examples/README.cpp +++ b/doc/examples/README.cpp @@ -1,5 +1,4 @@ #include -#include // for std::setw #include "json.hpp" using json = nlohmann::json; diff --git a/doc/examples/README.link b/doc/examples/README.link index 19e3976a..06add2ac 100644 --- a/doc/examples/README.link +++ b/doc/examples/README.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/examples/diff.cpp b/doc/examples/diff.cpp index ee0aefc0..274e56bf 100644 --- a/doc/examples/diff.cpp +++ b/doc/examples/diff.cpp @@ -1,5 +1,4 @@ #include -#include // for std::setw #include "json.hpp" using json = nlohmann::json; diff --git a/doc/examples/diff.link b/doc/examples/diff.link index e1cfdb8d..a02ddbdb 100644 --- a/doc/examples/diff.link +++ b/doc/examples/diff.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/examples/flatten.cpp b/doc/examples/flatten.cpp index a69c31d4..908b371d 100644 --- a/doc/examples/flatten.cpp +++ b/doc/examples/flatten.cpp @@ -1,5 +1,4 @@ #include -#include // for std::setw #include "json.hpp" using json = nlohmann::json; diff --git a/doc/examples/flatten.link b/doc/examples/flatten.link index 4d03de6b..d32588fe 100644 --- a/doc/examples/flatten.link +++ b/doc/examples/flatten.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/examples/from_cbor.cpp b/doc/examples/from_cbor.cpp index b0340f17..b37b375a 100644 --- a/doc/examples/from_cbor.cpp +++ b/doc/examples/from_cbor.cpp @@ -1,5 +1,4 @@ #include -#include // for std::setw #include "json.hpp" using json = nlohmann::json; diff --git a/doc/examples/from_cbor.link b/doc/examples/from_cbor.link index 129e0332..6e1f4e24 100644 --- a/doc/examples/from_cbor.link +++ b/doc/examples/from_cbor.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/examples/from_msgpack.cpp b/doc/examples/from_msgpack.cpp index 5df9ef3e..84c7d1f1 100644 --- a/doc/examples/from_msgpack.cpp +++ b/doc/examples/from_msgpack.cpp @@ -1,5 +1,4 @@ #include -#include // for std::setw #include "json.hpp" using json = nlohmann::json; diff --git a/doc/examples/from_msgpack.link b/doc/examples/from_msgpack.link index 7d3a1438..493f4435 100644 --- a/doc/examples/from_msgpack.link +++ b/doc/examples/from_msgpack.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/examples/meta.cpp b/doc/examples/meta.cpp index 5a762322..9194beae 100644 --- a/doc/examples/meta.cpp +++ b/doc/examples/meta.cpp @@ -1,5 +1,4 @@ #include -#include // for std::setw #include "json.hpp" using json = nlohmann::json; diff --git a/doc/examples/meta.link b/doc/examples/meta.link index ca563582..f1d8c869 100644 --- a/doc/examples/meta.link +++ b/doc/examples/meta.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/examples/meta.output b/doc/examples/meta.output index d5ef8260..ae8cca63 100644 --- a/doc/examples/meta.output +++ b/doc/examples/meta.output @@ -2,7 +2,7 @@ "compiler": { "c++": "201103", "family": "clang", - "version": "8.1.0 (clang-802.0.42)" + "version": "9.0.0 (clang-900.0.37)" }, "copyright": "(C) 2013-2017 Niels Lohmann", "name": "JSON for Modern C++", diff --git a/doc/examples/operator_deserialize.cpp b/doc/examples/operator_deserialize.cpp index b553cf67..7a2cf23a 100644 --- a/doc/examples/operator_deserialize.cpp +++ b/doc/examples/operator_deserialize.cpp @@ -1,5 +1,4 @@ #include -#include // for std::setw #include "json.hpp" using json = nlohmann::json; diff --git a/doc/examples/operator_deserialize.link b/doc/examples/operator_deserialize.link index 407b40e1..d60e5301 100644 --- a/doc/examples/operator_deserialize.link +++ b/doc/examples/operator_deserialize.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/examples/operator_serialize.cpp b/doc/examples/operator_serialize.cpp index d808e869..7f556383 100644 --- a/doc/examples/operator_serialize.cpp +++ b/doc/examples/operator_serialize.cpp @@ -1,5 +1,4 @@ #include -#include // for std::setw #include "json.hpp" using json = nlohmann::json; diff --git a/doc/examples/operator_serialize.link b/doc/examples/operator_serialize.link index 9d5d0102..f078934f 100644 --- a/doc/examples/operator_serialize.link +++ b/doc/examples/operator_serialize.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/examples/operatorarray__key_type.cpp b/doc/examples/operatorarray__key_type.cpp index a42335a3..43ff8ad8 100644 --- a/doc/examples/operatorarray__key_type.cpp +++ b/doc/examples/operatorarray__key_type.cpp @@ -1,5 +1,4 @@ #include -#include // for std::setw #include "json.hpp" using json = nlohmann::json; diff --git a/doc/examples/operatorarray__key_type.link b/doc/examples/operatorarray__key_type.link index 82961705..68a7a9c8 100644 --- a/doc/examples/operatorarray__key_type.link +++ b/doc/examples/operatorarray__key_type.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/examples/parse__array__parser_callback_t.cpp b/doc/examples/parse__array__parser_callback_t.cpp index 5681178d..0857f9ae 100644 --- a/doc/examples/parse__array__parser_callback_t.cpp +++ b/doc/examples/parse__array__parser_callback_t.cpp @@ -1,5 +1,4 @@ #include -#include // for std::setw #include "json.hpp" using json = nlohmann::json; diff --git a/doc/examples/parse__array__parser_callback_t.link b/doc/examples/parse__array__parser_callback_t.link index 0830fdac..2c4a7687 100644 --- a/doc/examples/parse__array__parser_callback_t.link +++ b/doc/examples/parse__array__parser_callback_t.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/examples/parse__contiguouscontainer__parser_callback_t.cpp b/doc/examples/parse__contiguouscontainer__parser_callback_t.cpp index ab551b0c..29b54811 100644 --- a/doc/examples/parse__contiguouscontainer__parser_callback_t.cpp +++ b/doc/examples/parse__contiguouscontainer__parser_callback_t.cpp @@ -1,5 +1,4 @@ #include -#include // for std::setw #include "json.hpp" using json = nlohmann::json; diff --git a/doc/examples/parse__contiguouscontainer__parser_callback_t.link b/doc/examples/parse__contiguouscontainer__parser_callback_t.link index 1e65c1f0..2e7f62e1 100644 --- a/doc/examples/parse__contiguouscontainer__parser_callback_t.link +++ b/doc/examples/parse__contiguouscontainer__parser_callback_t.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/examples/parse__istream__parser_callback_t.cpp b/doc/examples/parse__istream__parser_callback_t.cpp index 562ab968..a20e81f5 100644 --- a/doc/examples/parse__istream__parser_callback_t.cpp +++ b/doc/examples/parse__istream__parser_callback_t.cpp @@ -1,5 +1,4 @@ #include -#include // for std::setw #include "json.hpp" using json = nlohmann::json; diff --git a/doc/examples/parse__istream__parser_callback_t.link b/doc/examples/parse__istream__parser_callback_t.link index 737c8dda..7afa48bc 100644 --- a/doc/examples/parse__istream__parser_callback_t.link +++ b/doc/examples/parse__istream__parser_callback_t.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/examples/parse__iteratortype__parser_callback_t.cpp b/doc/examples/parse__iteratortype__parser_callback_t.cpp index 9a3e12e4..6044021c 100644 --- a/doc/examples/parse__iteratortype__parser_callback_t.cpp +++ b/doc/examples/parse__iteratortype__parser_callback_t.cpp @@ -1,5 +1,4 @@ #include -#include // for std::setw #include "json.hpp" using json = nlohmann::json; diff --git a/doc/examples/parse__iteratortype__parser_callback_t.link b/doc/examples/parse__iteratortype__parser_callback_t.link index e49ebc8d..093a2d18 100644 --- a/doc/examples/parse__iteratortype__parser_callback_t.link +++ b/doc/examples/parse__iteratortype__parser_callback_t.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/examples/parse__string__parser_callback_t.cpp b/doc/examples/parse__string__parser_callback_t.cpp index ea02c330..37ea6df7 100644 --- a/doc/examples/parse__string__parser_callback_t.cpp +++ b/doc/examples/parse__string__parser_callback_t.cpp @@ -1,5 +1,4 @@ #include -#include // for std::setw #include "json.hpp" using json = nlohmann::json; diff --git a/doc/examples/parse__string__parser_callback_t.link b/doc/examples/parse__string__parser_callback_t.link index 535ecd2b..94643bb7 100644 --- a/doc/examples/parse__string__parser_callback_t.link +++ b/doc/examples/parse__string__parser_callback_t.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/examples/patch.cpp b/doc/examples/patch.cpp index c844b970..fd0e6bf5 100644 --- a/doc/examples/patch.cpp +++ b/doc/examples/patch.cpp @@ -1,6 +1,5 @@ #include #include "json.hpp" -#include // for std::setw using json = nlohmann::json; diff --git a/doc/examples/patch.link b/doc/examples/patch.link index 7844cd94..7038cda6 100644 --- a/doc/examples/patch.link +++ b/doc/examples/patch.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/examples/to_cbor.cpp b/doc/examples/to_cbor.cpp index bdffe5eb..335a320a 100644 --- a/doc/examples/to_cbor.cpp +++ b/doc/examples/to_cbor.cpp @@ -1,5 +1,4 @@ #include -#include // for std::setw #include "json.hpp" using json = nlohmann::json; diff --git a/doc/examples/to_cbor.link b/doc/examples/to_cbor.link index ab658253..9c9f7a83 100644 --- a/doc/examples/to_cbor.link +++ b/doc/examples/to_cbor.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/examples/to_msgpack.cpp b/doc/examples/to_msgpack.cpp index 7756a9e6..d0fd9816 100644 --- a/doc/examples/to_msgpack.cpp +++ b/doc/examples/to_msgpack.cpp @@ -1,5 +1,4 @@ #include -#include // for std::setw #include "json.hpp" using json = nlohmann::json; diff --git a/doc/examples/to_msgpack.link b/doc/examples/to_msgpack.link index 12014fb0..ad0c6ce3 100644 --- a/doc/examples/to_msgpack.link +++ b/doc/examples/to_msgpack.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/examples/unflatten.cpp b/doc/examples/unflatten.cpp index 6318f859..cc672b5f 100644 --- a/doc/examples/unflatten.cpp +++ b/doc/examples/unflatten.cpp @@ -1,5 +1,4 @@ #include -#include // for std::setw #include "json.hpp" using json = nlohmann::json; diff --git a/doc/examples/unflatten.link b/doc/examples/unflatten.link index 6caa6a57..20582c9d 100644 --- a/doc/examples/unflatten.link +++ b/doc/examples/unflatten.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file From 980795b6442ee6f56e796dddfe97fc59bceeac47 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sat, 16 Dec 2017 12:37:44 +0100 Subject: [PATCH 11/59] :pencil2: fixed typos --- src/json.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index 4c29153d..e494baad 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -9051,7 +9051,7 @@ class basic_json @see https://docs.python.org/2/library/json.html#json.dump - @since version 1.0.0; indentation character @a indent_char and option + @since version 1.0.0; indentation character @a indent_char, option @a ensure_ascii and exceptions added in version 3.0.0 */ string_t dump(const int indent = -1, const char indent_char = ' ', @@ -12846,7 +12846,7 @@ class basic_json `std::setw(4)` on @a o sets the indentation level to `4` and the serialization result is the same as calling `dump(4)`. - - The indentation characrer can be controlled with the member variable + - The indentation character can be controlled with the member variable `fill` of the output stream @a o. For instance, the manipulator `std::setfill('\\t')` sets indentation to use a tab character rather than the default space character. @@ -12864,7 +12864,7 @@ class basic_json @liveexample{The example below shows the serialization with different parameters to `width` to adjust the indentation level.,operator_serialize} - @since version 1.0.0; indentaction character added in version 3.0.0 + @since version 1.0.0; indentation character added in version 3.0.0 */ friend std::ostream& operator<<(std::ostream& o, const basic_json& j) { From 9a51fb4da21516bcfd6d13d2d980a8d93202f72a Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sat, 16 Dec 2017 22:19:30 +0100 Subject: [PATCH 12/59] :rotating_light: fixed some warnings --- Makefile | 2 +- src/json.hpp | 2 +- test/src/unit-conversions.cpp | 120 +++++++++++++++++----------------- 3 files changed, 62 insertions(+), 62 deletions(-) diff --git a/Makefile b/Makefile index 4038f97e..b07fb6b0 100644 --- a/Makefile +++ b/Makefile @@ -95,7 +95,7 @@ pedantic_clang: # calling GCC with most warnings pedantic_gcc: - $(MAKE) json_unit CXX=g++ CXXFLAGS="\ + $(MAKE) json_unit CXXFLAGS="\ -std=c++11 \ -Wno-deprecated-declarations \ -Werror \ diff --git a/src/json.hpp b/src/json.hpp index e494baad..8cc3c4a5 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -6775,7 +6775,7 @@ class serializer }; const uint8_t type = utf8d[byte]; - state = utf8d[256 + state * 16 + type]; + state = utf8d[256u + state * 16u + type]; } /*! diff --git a/test/src/unit-conversions.cpp b/test/src/unit-conversions.cpp index eafac320..307fbe97 100644 --- a/test/src/unit-conversions.cpp +++ b/test/src/unit-conversions.cpp @@ -939,40 +939,40 @@ TEST_CASE("value conversion") SECTION("std::map") { - auto m1 = j1.get>(); - auto m2 = j2.get>(); - auto m3 = j3.get>(); - auto m4 = j4.get>(); - //auto m5 = j5.get>(); + j1.get>(); + j2.get>(); + j3.get>(); + j4.get>(); + j5.get>(); } SECTION("std::unordered_map") { - auto m1 = j1.get>(); - auto m2 = j2.get>(); - auto m3 = j3.get>(); - auto m4 = j4.get>(); - //auto m5 = j5.get>(); + j1.get>(); + j2.get>(); + j3.get>(); + j4.get>(); + j5.get>(); //CHECK(m5["one"] == "eins"); } SECTION("std::multimap") { - auto m1 = j1.get>(); - auto m2 = j2.get>(); - auto m3 = j3.get>(); - auto m4 = j4.get>(); - //auto m5 = j5.get>(); + j1.get>(); + j2.get>(); + j3.get>(); + j4.get>(); + j5.get>(); //CHECK(m5["one"] == "eins"); } SECTION("std::unordered_multimap") { - auto m1 = j1.get>(); - auto m2 = j2.get>(); - auto m3 = j3.get>(); - auto m4 = j4.get>(); - //auto m5 = j5.get>(); + j1.get>(); + j2.get>(); + j3.get>(); + j4.get>(); + j5.get>(); //CHECK(m5["one"] == "eins"); } @@ -993,29 +993,29 @@ TEST_CASE("value conversion") SECTION("std::list") { - auto m1 = j1.get>(); - auto m2 = j2.get>(); - auto m3 = j3.get>(); - auto m4 = j4.get>(); - auto m5 = j5.get>(); + j1.get>(); + j2.get>(); + j3.get>(); + j4.get>(); + j5.get>(); } SECTION("std::forward_list") { - auto m1 = j1.get>(); - auto m2 = j2.get>(); - auto m3 = j3.get>(); - auto m4 = j4.get>(); - auto m5 = j5.get>(); + j1.get>(); + j2.get>(); + j3.get>(); + j4.get>(); + j5.get>(); } SECTION("std::array") { - auto m1 = j1.get>(); - auto m2 = j2.get>(); - auto m3 = j3.get>(); - auto m4 = j4.get>(); - auto m5 = j5.get>(); + j1.get>(); + j2.get>(); + j3.get>(); + j4.get>(); + j5.get>(); SECTION("std::array is larger than JSON") { @@ -1035,47 +1035,47 @@ TEST_CASE("value conversion") SECTION("std::valarray") { - auto m1 = j1.get>(); - auto m2 = j2.get>(); - auto m3 = j3.get>(); - auto m4 = j4.get>(); - auto m5 = j5.get>(); + j1.get>(); + j2.get>(); + j3.get>(); + j4.get>(); + j5.get>(); } SECTION("std::vector") { - auto m1 = j1.get>(); - auto m2 = j2.get>(); - auto m3 = j3.get>(); - auto m4 = j4.get>(); - auto m5 = j5.get>(); + j1.get>(); + j2.get>(); + j3.get>(); + j4.get>(); + j5.get>(); } SECTION("std::deque") { - auto m1 = j1.get>(); - auto m2 = j2.get>(); - auto m3 = j2.get>(); - auto m4 = j4.get>(); - auto m5 = j5.get>(); + j1.get>(); + j2.get>(); + j2.get>(); + j4.get>(); + j5.get>(); } SECTION("std::set") { - auto m1 = j1.get>(); - auto m2 = j2.get>(); - auto m3 = j3.get>(); - auto m4 = j4.get>(); - auto m5 = j5.get>(); + j1.get>(); + j2.get>(); + j3.get>(); + j4.get>(); + j5.get>(); } SECTION("std::unordered_set") { - auto m1 = j1.get>(); - auto m2 = j2.get>(); - auto m3 = j3.get>(); - auto m4 = j4.get>(); - auto m5 = j5.get>(); + j1.get>(); + j2.get>(); + j3.get>(); + j4.get>(); + j5.get>(); } SECTION("exception in case of a non-object type") From 314e4e7699087b96c6fbdc4d8d3458ef11a2a16c Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sat, 16 Dec 2017 23:58:10 +0100 Subject: [PATCH 13/59] :memo: improved documentation for dump and iterator_wrapper --- doc/examples/dump.cpp | 11 +++++++++ doc/examples/dump.link | 2 +- doc/examples/dump.output | 1 + src/json.hpp | 48 ++++++++++++++++++++++++++++++++++++---- 4 files changed, 57 insertions(+), 5 deletions(-) diff --git a/doc/examples/dump.cpp b/doc/examples/dump.cpp index 4440f91c..1c485972 100644 --- a/doc/examples/dump.cpp +++ b/doc/examples/dump.cpp @@ -28,4 +28,15 @@ int main() std::cout << "strings:" << '\n' << j_string.dump() << '\n' << j_string.dump(-1, ' ', true) << '\n'; + + // create JSON value with invalid UTF-8 byte sequence + json j_invalid = "\xF0\xA4\xAD\xC0"; + try + { + std::cout << j_invalid.dump() << std::endl; + } + catch (json::type_error& e) + { + std::cout << e.what() << std::endl; + } } diff --git a/doc/examples/dump.link b/doc/examples/dump.link index c02a4126..4de70343 100644 --- a/doc/examples/dump.link +++ b/doc/examples/dump.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/examples/dump.output b/doc/examples/dump.output index 8c6998bb..c94eeb02 100644 --- a/doc/examples/dump.output +++ b/doc/examples/dump.output @@ -50,3 +50,4 @@ arrays: strings: "Hellö 😀!" "Hell\u00f6 \ud83d\ude00!" +[json.exception.type_error.316] invalid UTF-8 byte at index 3: 0xC0 diff --git a/src/json.hpp b/src/json.hpp index 8cc3c4a5..31429f81 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -11297,22 +11297,62 @@ class basic_json reference to the JSON values is returned, so there is no access to the underlying iterator. + For loop without iterator_wrapper: + + @code{cpp} + for (auto it = j_object.begin(); it != j_object.end(); ++it) + { + std::cout << "key: " << it.key() << ", value:" << it.value() << '\n'; + } + @endcode + + Range-based for loop without iterator proxy: + + @code{cpp} + for (auto it : j_object) + { + // "it" is of type json::reference and has no key() member + std::cout << "value: " << it << '\n'; + } + @endcode + + Range-based for loop with iterator proxy: + + @code{cpp} + for (auto it : json::iterator_wrapper(j_object)) + { + std::cout << "key: " << it.key() << ", value:" << it.value() << '\n'; + } + @endcode + + @note When iterating over an array, `key()` will return the index of the + element as string (see example). + + @param[in] ref reference to a JSON value + @return iteration proxy object wrapping @a ref with an interface to use in + range-based for loops + @liveexample{The following code shows how the wrapper is used,iterator_wrapper} + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Constant. + @note The name of this function is not yet final and may change in the future. */ - static iteration_proxy iterator_wrapper(reference cont) + static iteration_proxy iterator_wrapper(reference ref) { - return iteration_proxy(cont); + return iteration_proxy(ref); } /*! @copydoc iterator_wrapper(reference) */ - static iteration_proxy iterator_wrapper(const_reference cont) + static iteration_proxy iterator_wrapper(const_reference ref) { - return iteration_proxy(cont); + return iteration_proxy(ref); } /// @} From 9e3c4ad11f0733b5374dbf9ee562e405abc019bb Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sun, 17 Dec 2017 08:31:18 +0100 Subject: [PATCH 14/59] :bookmark: set version to 3.0.0 --- CMakeLists.txt | 2 +- ChangeLog.md | 397 ++++++++++++++++++++++++- doc/Doxyfile | 2 +- doc/examples/meta.output | 10 +- doc/index.md | 2 +- doc/json.gif | Bin 1457468 -> 1457923 bytes src/json.hpp | 6 +- test/src/fuzzer-driver_afl.cpp | 2 +- test/src/fuzzer-parse_cbor.cpp | 2 +- test/src/fuzzer-parse_json.cpp | 2 +- test/src/fuzzer-parse_msgpack.cpp | 2 +- test/src/unit-algorithms.cpp | 2 +- test/src/unit-allocator.cpp | 2 +- test/src/unit-capacity.cpp | 2 +- test/src/unit-cbor.cpp | 2 +- test/src/unit-class_const_iterator.cpp | 2 +- test/src/unit-class_iterator.cpp | 2 +- test/src/unit-class_lexer.cpp | 2 +- test/src/unit-class_parser.cpp | 2 +- test/src/unit-comparison.cpp | 2 +- test/src/unit-concepts.cpp | 2 +- test/src/unit-constructor1.cpp | 2 +- test/src/unit-constructor2.cpp | 2 +- test/src/unit-convenience.cpp | 2 +- test/src/unit-conversions.cpp | 2 +- test/src/unit-deserialization.cpp | 2 +- test/src/unit-element_access1.cpp | 2 +- test/src/unit-element_access2.cpp | 2 +- test/src/unit-inspection.cpp | 2 +- test/src/unit-iterator_wrapper.cpp | 2 +- test/src/unit-iterators1.cpp | 2 +- test/src/unit-iterators2.cpp | 2 +- test/src/unit-json_patch.cpp | 2 +- test/src/unit-json_pointer.cpp | 2 +- test/src/unit-meta.cpp | 10 +- test/src/unit-modifiers.cpp | 2 +- test/src/unit-msgpack.cpp | 2 +- test/src/unit-noexcept.cpp | 2 +- test/src/unit-pointer_access.cpp | 2 +- test/src/unit-readme.cpp | 2 +- test/src/unit-reference_access.cpp | 2 +- test/src/unit-regression.cpp | 2 +- test/src/unit-serialization.cpp | 2 +- test/src/unit-testsuites.cpp | 2 +- test/src/unit-udt.cpp | 2 +- test/src/unit-unicode.cpp | 2 +- test/src/unit.cpp | 2 +- 47 files changed, 451 insertions(+), 56 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1ad03e6e..334dec27 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 3.0.0) ## PROJECT ## name and version ## -project(nlohmann_json VERSION 2.1.1 LANGUAGES CXX) +project(nlohmann_json VERSION 3.0.0 LANGUAGES CXX) ## ## OPTIONS diff --git a/ChangeLog.md b/ChangeLog.md index 76244c5d..9db27833 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,6 +1,402 @@ # Change Log All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). +## [v3.0.0](https://github.com/nlohmann/json/releases/tag/v3.0.0) (2017-12-17) +[Full Changelog](https://github.com/nlohmann/json/compare/v2.1.1...v3.0.0) + +- unicode strings [\#878](https://github.com/nlohmann/json/issues/878) +- Visual Studio 2017 15.5 C++17 std::allocator deprecations [\#872](https://github.com/nlohmann/json/issues/872) +- Typo "excpetion" [\#869](https://github.com/nlohmann/json/issues/869) +- Explicit array example in README.md incorrect [\#867](https://github.com/nlohmann/json/issues/867) +- why don't you release this from Feb. ? [\#865](https://github.com/nlohmann/json/issues/865) +- json::parse throws std::invalid\_argument when processing string generated by json::dump\(\) [\#863](https://github.com/nlohmann/json/issues/863) +- code analysis: potential bug? [\#859](https://github.com/nlohmann/json/issues/859) +- MSVC2017, 15.5 new issues. [\#857](https://github.com/nlohmann/json/issues/857) +- very basic: fetching string value/content without quotes [\#853](https://github.com/nlohmann/json/issues/853) +- Ambiguous function call to get with pointer type and constant json object in VS2015 \(15.4.4\) [\#852](https://github.com/nlohmann/json/issues/852) +- How to put object in the array as a member? [\#850](https://github.com/nlohmann/json/issues/850) +- misclick, please ignore [\#849](https://github.com/nlohmann/json/issues/849) +- Make XML great again. [\#847](https://github.com/nlohmann/json/issues/847) +- Converting to array not working [\#843](https://github.com/nlohmann/json/issues/843) +- Iteration weirdness [\#842](https://github.com/nlohmann/json/issues/842) +- Use reference or pointer as Object value [\#841](https://github.com/nlohmann/json/issues/841) +- Ambiguity in parsing nested maps [\#840](https://github.com/nlohmann/json/issues/840) +- could not find from\_json\(\) method in T's namespace [\#839](https://github.com/nlohmann/json/issues/839) +- Incorrect parse error with binary data in keys? [\#838](https://github.com/nlohmann/json/issues/838) +- using dump\(\) when std::wstring is StringType with VS2017 [\#836](https://github.com/nlohmann/json/issues/836) +- Show the path of the currently parsed value when an error occurs [\#835](https://github.com/nlohmann/json/issues/835) +- Repetitive data type while reading [\#833](https://github.com/nlohmann/json/issues/833) +- Stack-overflow \(OSS-Fuzz 4234\) [\#832](https://github.com/nlohmann/json/issues/832) +- Storing multiple types inside map [\#831](https://github.com/nlohmann/json/issues/831) +- Application terminating [\#830](https://github.com/nlohmann/json/issues/830) +- Missing CMake hunter package? [\#828](https://github.com/nlohmann/json/issues/828) +- std::map\ from json object yields C2665: 'std::pair\::pair': none of the 2 overloads could convert all the argument types [\#827](https://github.com/nlohmann/json/issues/827) +- object.dump gives quoted string, want to use .dump\(\) to generate javascripts. [\#826](https://github.com/nlohmann/json/issues/826) +- Assertion failed on \["NoExistKey"\] of an not existing key of const json& [\#825](https://github.com/nlohmann/json/issues/825) +- vs2015 error : static member will remain uninitialized at runtime but use in constant-expressions is supported [\#824](https://github.com/nlohmann/json/issues/824) +- Code Checking Warnings from json.hpp on VS2017 Community [\#821](https://github.com/nlohmann/json/issues/821) +- Missing iostream in try online [\#820](https://github.com/nlohmann/json/issues/820) +- Floating point value loses decimal point during dump [\#818](https://github.com/nlohmann/json/issues/818) +- Conan package for the library [\#817](https://github.com/nlohmann/json/issues/817) +- stream error [\#815](https://github.com/nlohmann/json/issues/815) +- Link error when using find\(\) on the latest commit [\#814](https://github.com/nlohmann/json/issues/814) +- ABI issue with json object between 2 shared libraries [\#813](https://github.com/nlohmann/json/issues/813) +- scan\_string\(\) return token\_type::parse\_error; when parse ansi file [\#812](https://github.com/nlohmann/json/issues/812) +- segfault when using fifo\_map with json [\#810](https://github.com/nlohmann/json/issues/810) +- This shit is shit [\#809](https://github.com/nlohmann/json/issues/809) +- \_finite and \_isnan are no members of "std" [\#808](https://github.com/nlohmann/json/issues/808) +- how to print out the line which causing exception? [\#806](https://github.com/nlohmann/json/issues/806) +- {} uses copy constructor, while = does not [\#805](https://github.com/nlohmann/json/issues/805) +- json.hpp:8955: multiple definition of function that is not defined twice or more. [\#804](https://github.com/nlohmann/json/issues/804) +- \[question\] to\_json for base and derived class [\#803](https://github.com/nlohmann/json/issues/803) +- Misleading error message - unexpected '"' - on incorrect utf-8 symbol [\#802](https://github.com/nlohmann/json/issues/802) +- json data = std::string\_view\("hi"\); doesn't work? [\#801](https://github.com/nlohmann/json/issues/801) +- Thread safety of parse\(\) [\#800](https://github.com/nlohmann/json/issues/800) +- Numbers as strings [\#799](https://github.com/nlohmann/json/issues/799) +- Tests failing on arm [\#797](https://github.com/nlohmann/json/issues/797) +- Using your library \(without modification\) in another library [\#796](https://github.com/nlohmann/json/issues/796) +- Iterating over sub-object [\#794](https://github.com/nlohmann/json/issues/794) +- how to get the json object again from which printed by the method of dump\(\) [\#792](https://github.com/nlohmann/json/issues/792) +- ppa to include source [\#791](https://github.com/nlohmann/json/issues/791) +- Different include paths in macOS and Ubuntu [\#790](https://github.com/nlohmann/json/issues/790) +- Missing break after line 12886 in switch/case [\#789](https://github.com/nlohmann/json/issues/789) +- All unit tests fail? [\#787](https://github.com/nlohmann/json/issues/787) +- More use of move semantics in deserialization [\#786](https://github.com/nlohmann/json/issues/786) +- warning C4706 - Visual Studio 2017 \(/W4\) [\#784](https://github.com/nlohmann/json/issues/784) +- Compile error in clang 5.0 [\#782](https://github.com/nlohmann/json/issues/782) +- Error Installing appium\_lib with Ruby v2.4.2 Due to JSON [\#781](https://github.com/nlohmann/json/issues/781) +- ::get\\(\) fails in new\(er\) release \[MSVC\] [\#780](https://github.com/nlohmann/json/issues/780) +- Type Conversion [\#779](https://github.com/nlohmann/json/issues/779) +- Segfault on nested parsing [\#778](https://github.com/nlohmann/json/issues/778) +- Build warnings: shadowing exception id [\#776](https://github.com/nlohmann/json/issues/776) +- multi-level JSON support. [\#775](https://github.com/nlohmann/json/issues/775) +- SIGABRT on dump\(\) [\#773](https://github.com/nlohmann/json/issues/773) +- \[Question\] Custom StringType template parameter \(possibility for a KeyType template parameter\) [\#772](https://github.com/nlohmann/json/issues/772) +- constexpr ALL the Things! [\#771](https://github.com/nlohmann/json/issues/771) +- error: ‘BasicJsonType’ in namespace ‘::’ does not name a type [\#770](https://github.com/nlohmann/json/issues/770) +- Program calls abort function [\#769](https://github.com/nlohmann/json/issues/769) +- \[Question\] Floating point resolution config during dump\(\) ? [\#768](https://github.com/nlohmann/json/issues/768) +- make check - no test ran [\#767](https://github.com/nlohmann/json/issues/767) +- The library cannot work properly with custom allocator based containers [\#766](https://github.com/nlohmann/json/issues/766) +- Documentation or feature request. [\#763](https://github.com/nlohmann/json/issues/763) +- warnings in msvc about mix/max macro while windows.h is used in the project [\#762](https://github.com/nlohmann/json/issues/762) +- std::signbit ambiguous [\#761](https://github.com/nlohmann/json/issues/761) +- How to use value for std::experimental::optional type? [\#760](https://github.com/nlohmann/json/issues/760) +- Cannot load json file properly [\#759](https://github.com/nlohmann/json/issues/759) +- Compilation error with unordered\_map\< int, int \> [\#758](https://github.com/nlohmann/json/issues/758) +- CBOR string [\#757](https://github.com/nlohmann/json/issues/757) +- Proposal: out\_of\_range should be a subclass of std::out\_of\_range [\#756](https://github.com/nlohmann/json/issues/756) +- Compiling with icpc [\#755](https://github.com/nlohmann/json/issues/755) +- Getter is setting the value to null if the key does not exist [\#754](https://github.com/nlohmann/json/issues/754) +- parsing works sometimes and crashes others [\#752](https://github.com/nlohmann/json/issues/752) +- Static\_assert failed "incompatible pointer type" with Xcode [\#751](https://github.com/nlohmann/json/issues/751) +- user-defined literal operator not found [\#750](https://github.com/nlohmann/json/issues/750) +- getting clean string from it.key\(\) [\#748](https://github.com/nlohmann/json/issues/748) +- Best method for exploring and obtaining values of nested json objects when the names are not known beforehand? [\#747](https://github.com/nlohmann/json/issues/747) +- null char at the end of string [\#746](https://github.com/nlohmann/json/issues/746) +- Incorrect sample for operator \>\> in docs [\#745](https://github.com/nlohmann/json/issues/745) +- User-friendly documentation [\#744](https://github.com/nlohmann/json/issues/744) +- Retrieve all values that match a json path [\#743](https://github.com/nlohmann/json/issues/743) +- Compilation issue with gcc 7.2 [\#742](https://github.com/nlohmann/json/issues/742) +- CMake target nlohmann\_json does not have src into its interface includes [\#741](https://github.com/nlohmann/json/issues/741) +- Error when serializing empty json: type must be string, but is object [\#740](https://github.com/nlohmann/json/issues/740) +- Conversion error for std::map\ [\#739](https://github.com/nlohmann/json/issues/739) +- Dumping Json to file as array [\#738](https://github.com/nlohmann/json/issues/738) +- nesting json objects [\#737](https://github.com/nlohmann/json/issues/737) +- where to find general help? [\#736](https://github.com/nlohmann/json/issues/736) +- Compilation Error on Clang 5.0 Upgrade [\#735](https://github.com/nlohmann/json/issues/735) +- Compilation error with std::map\ on vs 2015 [\#734](https://github.com/nlohmann/json/issues/734) +- Benchmarks for Binary formats [\#733](https://github.com/nlohmann/json/issues/733) +- Move test blobs to a submodule? [\#732](https://github.com/nlohmann/json/issues/732) +- Support \n symbols in json string. [\#731](https://github.com/nlohmann/json/issues/731) +- Project's name is too generic and hard to search for [\#730](https://github.com/nlohmann/json/issues/730) +- Visual Studio 2015 IntelliTrace problems [\#729](https://github.com/nlohmann/json/issues/729) +- How to erase nested objects inside other objects? [\#728](https://github.com/nlohmann/json/issues/728) +- How to prevent alphabetical sorting of data? [\#727](https://github.com/nlohmann/json/issues/727) +- Serialization for CBOR [\#726](https://github.com/nlohmann/json/issues/726) +- Using json Object as value in a map [\#725](https://github.com/nlohmann/json/issues/725) +- std::regex and nlohmann::json value [\#724](https://github.com/nlohmann/json/issues/724) +- Warnings when compiling with VisualStudio 2015 [\#723](https://github.com/nlohmann/json/issues/723) +- Has this lib the unicode \(wstring\) support? [\#722](https://github.com/nlohmann/json/issues/722) +- When will be 3.0 in master? [\#721](https://github.com/nlohmann/json/issues/721) +- Determine the type from error message. [\#720](https://github.com/nlohmann/json/issues/720) +- Compile-Error C2100 \(MS VS2015\) in line 887 json.hpp [\#719](https://github.com/nlohmann/json/issues/719) +- from\_json not working for boost::optional example [\#718](https://github.com/nlohmann/json/issues/718) +- about from\_json and to\_json function [\#717](https://github.com/nlohmann/json/issues/717) +- How to deserialize array with derived objects [\#716](https://github.com/nlohmann/json/issues/716) +- How to detect parse failure? [\#715](https://github.com/nlohmann/json/issues/715) +- Parse throw std::ios\_base::failure exception when failbit set to true [\#714](https://github.com/nlohmann/json/issues/714) +- Is there a way of format just making a pretty print without changing the key's orders ? [\#713](https://github.com/nlohmann/json/issues/713) +- Serialization of array of not same model items [\#712](https://github.com/nlohmann/json/issues/712) +- pointer to json parse vector [\#711](https://github.com/nlohmann/json/issues/711) +- Gtest SEH Exception [\#709](https://github.com/nlohmann/json/issues/709) +- broken from\_json implementation for pair and tuple [\#707](https://github.com/nlohmann/json/issues/707) +- Unevaluated lambda in assert breaks gcc 7 build [\#705](https://github.com/nlohmann/json/issues/705) +- Issues when adding values to firebase database [\#704](https://github.com/nlohmann/json/issues/704) +- Floating point equality - revisited [\#703](https://github.com/nlohmann/json/issues/703) +- Conversion from valarray\ to json fails to build [\#702](https://github.com/nlohmann/json/issues/702) +- internal compiler error \(gcc7\) [\#701](https://github.com/nlohmann/json/issues/701) +- One build system to rule them all [\#698](https://github.com/nlohmann/json/issues/698) +- Generated nlohmann\_jsonConfig.cmake does not set JSON\_INCLUDE\_DIR [\#695](https://github.com/nlohmann/json/issues/695) +- support the Chinese language in json string [\#694](https://github.com/nlohmann/json/issues/694) +- NaN problem within develop branch [\#693](https://github.com/nlohmann/json/issues/693) +- Please post example of specialization for boost::filesystem [\#692](https://github.com/nlohmann/json/issues/692) +- Impossible to do an array of composite objects [\#691](https://github.com/nlohmann/json/issues/691) +- How to save json to file? [\#690](https://github.com/nlohmann/json/issues/690) +- my simple json parser [\#689](https://github.com/nlohmann/json/issues/689) +- problem with new struct parsing syntax [\#688](https://github.com/nlohmann/json/issues/688) +- Parse error while parse the json string contains UTF 8 encoded document bytes string [\#684](https://github.com/nlohmann/json/issues/684) +- \[question\] how to get a string value by pointer [\#683](https://github.com/nlohmann/json/issues/683) +- create json object from string variable [\#681](https://github.com/nlohmann/json/issues/681) +- adl\_serializer and CRTP [\#680](https://github.com/nlohmann/json/issues/680) +- Is there a way to control the precision of serialized floating point numbers? [\#677](https://github.com/nlohmann/json/issues/677) +- Is there a way to get the path of a value? [\#676](https://github.com/nlohmann/json/issues/676) +- Could the parser locate errors to line? [\#675](https://github.com/nlohmann/json/issues/675) +- There is performance inefficiency found by coverity tool json2.1.1/include/nlohmann/json.hpp [\#673](https://github.com/nlohmann/json/issues/673) +- include problem, when cmake on osx [\#672](https://github.com/nlohmann/json/issues/672) +- Operator= ambiguous in C++1z and GCC 7.1.1 [\#670](https://github.com/nlohmann/json/issues/670) +- should't the cmake install target be to nlohman/json.hpp [\#668](https://github.com/nlohmann/json/issues/668) +- deserialise from `std::vector` [\#667](https://github.com/nlohmann/json/issues/667) +- How to iterate? [\#665](https://github.com/nlohmann/json/issues/665) +- could this json lib work on windows? [\#664](https://github.com/nlohmann/json/issues/664) +- How does from\_json work? [\#662](https://github.com/nlohmann/json/issues/662) +- insert\(or merge\) object should replace same key , not ignore [\#661](https://github.com/nlohmann/json/issues/661) +- Why is an object ordering values by Alphabetical Order? [\#660](https://github.com/nlohmann/json/issues/660) +- Parse method doesn't handle newlines. [\#659](https://github.com/nlohmann/json/issues/659) +- Compilation "note" on GCC 6 ARM [\#658](https://github.com/nlohmann/json/issues/658) +- Adding additional push\_back/operator+= rvalue overloads for JSON object [\#657](https://github.com/nlohmann/json/issues/657) +- dump's parameter "ensure\_ascii" creates too long sequences [\#656](https://github.com/nlohmann/json/issues/656) +- Question: parsing `void \*` [\#655](https://github.com/nlohmann/json/issues/655) +- how should I check a string is valid JSON string ? [\#653](https://github.com/nlohmann/json/issues/653) +- Question: thread safety of read only accesses [\#651](https://github.com/nlohmann/json/issues/651) +- Eclipse: Method 'size' could not be resolved [\#649](https://github.com/nlohmann/json/issues/649) +- Update/Add object fields [\#648](https://github.com/nlohmann/json/issues/648) +- No exception raised for Out Of Range input of numbers [\#647](https://github.com/nlohmann/json/issues/647) +- Package Name [\#646](https://github.com/nlohmann/json/issues/646) +- What is the meaning of operator\[\]\(T\* key\) [\#645](https://github.com/nlohmann/json/issues/645) +- Which is the correct way to json objects as parameters to functions? [\#644](https://github.com/nlohmann/json/issues/644) +- Method to get string representations of values [\#642](https://github.com/nlohmann/json/issues/642) +- CBOR serialization of a given JSON value does not serialize [\#641](https://github.com/nlohmann/json/issues/641) +- Are we forced to use "-fexceptions" flag in android ndk project [\#640](https://github.com/nlohmann/json/issues/640) +- Comparison of objects containing floats [\#639](https://github.com/nlohmann/json/issues/639) +- 'localeconv' is not supported by NDK for SDK \<=20 [\#638](https://github.com/nlohmann/json/issues/638) +- \[Question\] cLion integration [\#637](https://github.com/nlohmann/json/issues/637) +- How to construct an iteratable usage in nlohmann json? [\#636](https://github.com/nlohmann/json/issues/636) +- \[Question\] copy assign json-container to vector [\#635](https://github.com/nlohmann/json/issues/635) +- Get size without .dump\(\) [\#634](https://github.com/nlohmann/json/issues/634) +- Segmentation fault when parsing invalid json file [\#633](https://github.com/nlohmann/json/issues/633) +- How to serialize from json to vector\? [\#632](https://github.com/nlohmann/json/issues/632) +- no member named 'thousands\_sep' in 'lconv' [\#631](https://github.com/nlohmann/json/issues/631) +- \[Question\] Any fork for \(the unsupported\) Visual Studio 2012 version? [\#628](https://github.com/nlohmann/json/issues/628) +- Dependency injection in serializer [\#627](https://github.com/nlohmann/json/issues/627) +- from\_json for std::array [\#625](https://github.com/nlohmann/json/issues/625) +- Discussion: How to structure the parsing function families [\#623](https://github.com/nlohmann/json/issues/623) +- Question: How to erase subtree [\#622](https://github.com/nlohmann/json/issues/622) +- Insertion into nested json field [\#621](https://github.com/nlohmann/json/issues/621) +- \[Question\] When using this as git submodule, will it clone the whole thing include test data and benchmark? [\#620](https://github.com/nlohmann/json/issues/620) +- Question: return static json object from function [\#618](https://github.com/nlohmann/json/issues/618) +- icc16 error [\#617](https://github.com/nlohmann/json/issues/617) +- \[-Wdeprecated-declarations\] in row `j \>\> ss;` in file `json.hpp:7405:26` and FAILED unit tests with MinGWx64! [\#616](https://github.com/nlohmann/json/issues/616) +- to\_json for pairs, tuples [\#614](https://github.com/nlohmann/json/issues/614) +- Using uninitialized memory 'buf' in line 11173 v2.1.1? [\#613](https://github.com/nlohmann/json/issues/613) +- How to parse multiple same Keys of JSON and save them? [\#612](https://github.com/nlohmann/json/issues/612) +- "Multiple declarations" error when using types defined with `typedef` [\#611](https://github.com/nlohmann/json/issues/611) +- 2.1.1+ breaks compilation of shared\_ptr\ == 0 [\#610](https://github.com/nlohmann/json/issues/610) +- a bug of inheritance ? [\#608](https://github.com/nlohmann/json/issues/608) +- std::map key conversion with to\_json [\#607](https://github.com/nlohmann/json/issues/607) +- json.hpp:6384:62: error: wrong number of template arguments \(1, should be 2\) [\#606](https://github.com/nlohmann/json/issues/606) +- Incremental parsing: Where's the push version? [\#605](https://github.com/nlohmann/json/issues/605) +- Is there a way to validate the structure of a json object ? [\#604](https://github.com/nlohmann/json/issues/604) +- \[Question\] Issue when using Appveyor when compiling library [\#603](https://github.com/nlohmann/json/issues/603) +- BOM not skipped when using json:parse\(iterator\) [\#602](https://github.com/nlohmann/json/issues/602) +- Use of the binary type in CBOR and Message Pack [\#601](https://github.com/nlohmann/json/issues/601) +- Newbie issue: how does one convert a map in Json back to std::map? [\#600](https://github.com/nlohmann/json/issues/600) +- Plugin system [\#599](https://github.com/nlohmann/json/issues/599) +- Feature request: Comments [\#597](https://github.com/nlohmann/json/issues/597) +- Using custom types for scalars? [\#596](https://github.com/nlohmann/json/issues/596) +- Issues with the arithmetic in iterator and reverse iterator [\#593](https://github.com/nlohmann/json/issues/593) +- not enough examples [\#592](https://github.com/nlohmann/json/issues/592) +- in-class initialization for type 'const T' is not yet implemented [\#591](https://github.com/nlohmann/json/issues/591) +- compiling with gcc 7 -\> error on bool operator \< [\#590](https://github.com/nlohmann/json/issues/590) +- Parsing from stream leads to an array [\#589](https://github.com/nlohmann/json/issues/589) +- Buggy support for binary string data [\#587](https://github.com/nlohmann/json/issues/587) +- C++17's ambiguous conversion [\#586](https://github.com/nlohmann/json/issues/586) +- How does the messagepack encoding/decoding compare to msgpack-cpp in terms of performance? [\#585](https://github.com/nlohmann/json/issues/585) +- is it possible to check existence of a value deep in hierarchy? [\#584](https://github.com/nlohmann/json/issues/584) +- loading from a stream and exceptions [\#582](https://github.com/nlohmann/json/issues/582) +- Visual Studio seems not to have all min\(\) function versions [\#581](https://github.com/nlohmann/json/issues/581) +- Supporting of the json schema [\#580](https://github.com/nlohmann/json/issues/580) +- Stack-overflow \(OSS-Fuzz 1444\) [\#577](https://github.com/nlohmann/json/issues/577) +- Heap-buffer-overflow \(OSS-Fuzz 1400\) [\#575](https://github.com/nlohmann/json/issues/575) +- JSON escape quotes [\#574](https://github.com/nlohmann/json/issues/574) +- error: static\_assert failed [\#573](https://github.com/nlohmann/json/issues/573) +- Storing floats, and round trip serialisation/deserialisation diffs [\#572](https://github.com/nlohmann/json/issues/572) +- JSON.getLong produces inconsistent results [\#571](https://github.com/nlohmann/json/issues/571) +- Request: Object.at\(\) with default return value [\#570](https://github.com/nlohmann/json/issues/570) +- Internal structure gets corrupted while parsing [\#569](https://github.com/nlohmann/json/issues/569) +- create template \ basic\_json from\_cbor\(Iter begin, Iter end\) [\#568](https://github.com/nlohmann/json/issues/568) +- Need to improve ignores.. [\#567](https://github.com/nlohmann/json/issues/567) +- Conan.io [\#566](https://github.com/nlohmann/json/issues/566) +- contradictory documentation regarding json::find [\#565](https://github.com/nlohmann/json/issues/565) +- Unexpected '\"' in middle of array [\#564](https://github.com/nlohmann/json/issues/564) +- Support parse std::pair to Json object [\#563](https://github.com/nlohmann/json/issues/563) +- json and Microsoft Visual c++ Compiler Nov 2012 CTP [\#562](https://github.com/nlohmann/json/issues/562) +- from\_json declaration order and exceptions [\#561](https://github.com/nlohmann/json/issues/561) +- Tip: Don't upgrade to VS2017 if using json initializer list constructs [\#559](https://github.com/nlohmann/json/issues/559) +- parse error - unexpected end of input [\#558](https://github.com/nlohmann/json/issues/558) +- Cant modify existing numbers inside a json object [\#557](https://github.com/nlohmann/json/issues/557) +- Minimal repository \(current size very large\) [\#556](https://github.com/nlohmann/json/issues/556) +- Better support for SAX style serialize and deserialize in new version? [\#554](https://github.com/nlohmann/json/issues/554) +- Cannot convert from json array to std::array [\#553](https://github.com/nlohmann/json/issues/553) +- Do not define an unnamed namespace in a header file \(DCL59-CPP\) [\#552](https://github.com/nlohmann/json/issues/552) +- Parse error on known good json file [\#551](https://github.com/nlohmann/json/issues/551) +- Warning on Intel compiler \(icc 17\) [\#550](https://github.com/nlohmann/json/issues/550) +- multiple versions of 'vsnprintf' [\#549](https://github.com/nlohmann/json/issues/549) +- illegal indirection [\#548](https://github.com/nlohmann/json/issues/548) +- Ambiguous compare operators with clang-5.0 [\#547](https://github.com/nlohmann/json/issues/547) +- Using tsl::ordered\_map [\#546](https://github.com/nlohmann/json/issues/546) +- Compiler support errors are inconvenient [\#544](https://github.com/nlohmann/json/issues/544) +- Head Elements Sorting [\#543](https://github.com/nlohmann/json/issues/543) +- Duplicate symbols error happens while to\_json/from\_json method implemented inside entity definition header file [\#542](https://github.com/nlohmann/json/issues/542) +- consider adding a bool json::is\_valid\(std::string const&\) non-member function [\#541](https://github.com/nlohmann/json/issues/541) +- Help request [\#539](https://github.com/nlohmann/json/issues/539) +- How to deal with missing keys in `from\_json`? [\#538](https://github.com/nlohmann/json/issues/538) +- recursive from\_msgpack implementation will stack overflow [\#537](https://github.com/nlohmann/json/issues/537) +- Exception objects must be nothrow copy constructible \(ERR60-CPP\) [\#531](https://github.com/nlohmann/json/issues/531) +- Support for multiple root elements [\#529](https://github.com/nlohmann/json/issues/529) +- Port has\_shape from dropbox/json11 [\#528](https://github.com/nlohmann/json/issues/528) +- dump\_float: truncation from ptrdiff\_t to long [\#527](https://github.com/nlohmann/json/issues/527) +- Make exception base class visible in basic\_json [\#525](https://github.com/nlohmann/json/issues/525) +- msgpack unit test failures on ppc64 arch [\#524](https://github.com/nlohmann/json/issues/524) +- How about split the implementation out, and only leave the interface? [\#523](https://github.com/nlohmann/json/issues/523) +- VC++2017 not enough actual parameters for macro 'max' [\#522](https://github.com/nlohmann/json/issues/522) +- crash on empty ifstream [\#521](https://github.com/nlohmann/json/issues/521) +- Suggestion: Support tabs for indentation when serializing to stream. [\#520](https://github.com/nlohmann/json/issues/520) +- Abrt in get\_number \(OSS-Fuzz 885\) [\#519](https://github.com/nlohmann/json/issues/519) +- Abrt on unknown address \(OSS-Fuzz 884\) [\#518](https://github.com/nlohmann/json/issues/518) +- Stack-overflow \(OSS-Fuzz 869\) [\#517](https://github.com/nlohmann/json/issues/517) +- Assertion error \(OSS-Fuzz 868\) [\#516](https://github.com/nlohmann/json/issues/516) +- NaN to json and back [\#515](https://github.com/nlohmann/json/issues/515) +- Comparison of NaN [\#514](https://github.com/nlohmann/json/issues/514) +- why it's not possible to serialize c++11 enums directly [\#513](https://github.com/nlohmann/json/issues/513) +- clang compile error: use of overloaded operator '\<=' is ambiguous with \(nlohmann::json{{"a", 5}}\)\["a"\] \<= 10 [\#512](https://github.com/nlohmann/json/issues/512) +- Why not also look inside the type for \(static\) to\_json and from\_json funtions? [\#511](https://github.com/nlohmann/json/issues/511) +- Parser issues [\#509](https://github.com/nlohmann/json/issues/509) +- I may not understand [\#507](https://github.com/nlohmann/json/issues/507) +- VS2017 min / max problem for 2.1.1 [\#506](https://github.com/nlohmann/json/issues/506) +- CBOR/MessagePack is not read until the end [\#505](https://github.com/nlohmann/json/issues/505) +- Assertion error \(OSS-Fuzz 856\) [\#504](https://github.com/nlohmann/json/issues/504) +- Return position in parse error exceptions [\#503](https://github.com/nlohmann/json/issues/503) +- conversion from/to C array is not supported [\#502](https://github.com/nlohmann/json/issues/502) +- error C2338: could not find to\_json\(\) method in T's namespace [\#501](https://github.com/nlohmann/json/issues/501) +- Test suite fails in en\_GB.UTF-8 [\#500](https://github.com/nlohmann/json/issues/500) +- cannot use operator\[\] with number [\#499](https://github.com/nlohmann/json/issues/499) +- consider using \_\_cpp\_exceptions and/or \_\_EXCEPTIONS to disable/enable exception support [\#498](https://github.com/nlohmann/json/issues/498) +- Stack-overflow \(OSS-Fuzz issue 814\) [\#497](https://github.com/nlohmann/json/issues/497) +- Using in Unreal Engine - handling custom types conversion [\#495](https://github.com/nlohmann/json/issues/495) +- Conversion from vector\ to json fails to build [\#494](https://github.com/nlohmann/json/issues/494) +- fill\_line\_buffer incorrectly tests m\_stream for eof but not fail or bad bits [\#493](https://github.com/nlohmann/json/issues/493) +- Compiling with \_GLIBCXX\_DEBUG yields iterator-comparison warnings during tests [\#492](https://github.com/nlohmann/json/issues/492) +- crapy interface [\#491](https://github.com/nlohmann/json/issues/491) +- Fix Visual Studo 2013 builds. [\#490](https://github.com/nlohmann/json/issues/490) +- Failed to compile with -D\_GLIBCXX\_PARALLEL [\#489](https://github.com/nlohmann/json/issues/489) +- Input several field with the same name [\#488](https://github.com/nlohmann/json/issues/488) +- read in .json file yields strange sizes [\#487](https://github.com/nlohmann/json/issues/487) +- json::value\_t can't be a map's key type in VC++ 2015 [\#486](https://github.com/nlohmann/json/issues/486) +- Using fifo\_map [\#485](https://github.com/nlohmann/json/issues/485) +- Cannot get float pointer for value stored as `0` [\#484](https://github.com/nlohmann/json/issues/484) +- byte string support [\#483](https://github.com/nlohmann/json/issues/483) +- For a header-only library you have to clone 214MB [\#482](https://github.com/nlohmann/json/issues/482) +- https://github.com/nlohmann/json\#execute-unit-tests [\#481](https://github.com/nlohmann/json/issues/481) +- Remove deprecated constructor basic\_json\(std::istream&\) [\#480](https://github.com/nlohmann/json/issues/480) +- writing the binary json file? [\#479](https://github.com/nlohmann/json/issues/479) +- CBOR/MessagePack from uint8\_t \* and size [\#478](https://github.com/nlohmann/json/issues/478) +- Streaming binary representations [\#477](https://github.com/nlohmann/json/issues/477) +- Reuse memory in to\_cbor and to\_msgpack functions [\#476](https://github.com/nlohmann/json/issues/476) +- Error Using JSON Library with arrays C++ [\#475](https://github.com/nlohmann/json/issues/475) +- Moving forward to version 3.0.0 [\#474](https://github.com/nlohmann/json/issues/474) +- Inconsistent behavior in conversion to array type [\#473](https://github.com/nlohmann/json/issues/473) +- Create a \[key:member\_pointer\] map to ease parsing custom types [\#471](https://github.com/nlohmann/json/issues/471) +- MSVC 2015 update 2 [\#469](https://github.com/nlohmann/json/issues/469) +- VS2017 implicit to std::string conversion fix. [\#464](https://github.com/nlohmann/json/issues/464) +- How to make sure a string or string literal is a valid JSON? [\#458](https://github.com/nlohmann/json/issues/458) +- basic\_json templated on a "policy" class [\#456](https://github.com/nlohmann/json/issues/456) +- json::value\(const json\_pointer&, ValueType\) requires exceptions to return the default value. [\#440](https://github.com/nlohmann/json/issues/440) +- is it possible merge two json object [\#428](https://github.com/nlohmann/json/issues/428) +- Is it possible to turn this into a shared library? [\#420](https://github.com/nlohmann/json/issues/420) +- Further thoughts on performance improvements [\#418](https://github.com/nlohmann/json/issues/418) +- nan number stored as null [\#388](https://github.com/nlohmann/json/issues/388) +- Behavior of operator\>\> should more closely resemble that of built-in overloads. [\#367](https://github.com/nlohmann/json/issues/367) +- Request: range-based-for over a json-object to expose .first/.second [\#350](https://github.com/nlohmann/json/issues/350) +- feature wish: JSONPath [\#343](https://github.com/nlohmann/json/issues/343) +- UTF-8/Unicode escape and dump [\#330](https://github.com/nlohmann/json/issues/330) +- Serialized value not always can be parsed. [\#329](https://github.com/nlohmann/json/issues/329) +- Is there a way to forward declare nlohmann::json? [\#314](https://github.com/nlohmann/json/issues/314) +- Exception line [\#301](https://github.com/nlohmann/json/issues/301) +- Do not throw exception when default\_value's type does not match the actual type [\#278](https://github.com/nlohmann/json/issues/278) +- dump\(\) method doesn't work with a custom allocator [\#268](https://github.com/nlohmann/json/issues/268) +- Readme documentation enhancements [\#248](https://github.com/nlohmann/json/issues/248) +- Use user-defined exceptions [\#244](https://github.com/nlohmann/json/issues/244) +- Incorrect C++11 allocator model support [\#161](https://github.com/nlohmann/json/issues/161) + +- :white\_check\_mark: re-added tests for algorithms [\#879](https://github.com/nlohmann/json/pull/879) ([nlohmann](https://github.com/nlohmann)) +- Overworked library toward 3.0.0 release [\#875](https://github.com/nlohmann/json/pull/875) ([nlohmann](https://github.com/nlohmann)) +- :rotating\_light: remove C4996 warnings \#872 [\#873](https://github.com/nlohmann/json/pull/873) ([nlohmann](https://github.com/nlohmann)) +- :boom: throwing an exception in case dump encounters a non-UTF-8 string \#838 [\#870](https://github.com/nlohmann/json/pull/870) ([nlohmann](https://github.com/nlohmann)) +- :memo: fixing documentation \#867 [\#868](https://github.com/nlohmann/json/pull/868) ([nlohmann](https://github.com/nlohmann)) +- iter\_impl template conformance with C++17 [\#860](https://github.com/nlohmann/json/pull/860) ([bogemic](https://github.com/bogemic)) +- Std allocator conformance cpp17 [\#856](https://github.com/nlohmann/json/pull/856) ([bogemic](https://github.com/bogemic)) +- cmake: use BUILD\_INTERFACE/INSTALL\_INTERFACE [\#855](https://github.com/nlohmann/json/pull/855) ([theodelrieu](https://github.com/theodelrieu)) +- to/from\_json: add a MSVC-specific static\_assert to force a stacktrace [\#854](https://github.com/nlohmann/json/pull/854) ([theodelrieu](https://github.com/theodelrieu)) +- Add .natvis for MSVC debug view [\#844](https://github.com/nlohmann/json/pull/844) ([TinyTinni](https://github.com/TinyTinni)) +- Updated hunter package links [\#829](https://github.com/nlohmann/json/pull/829) ([jowr](https://github.com/jowr)) +- Typos README [\#811](https://github.com/nlohmann/json/pull/811) ([Itja](https://github.com/Itja)) +- add forwarding references to json\_ref constructor [\#807](https://github.com/nlohmann/json/pull/807) ([theodelrieu](https://github.com/theodelrieu)) +- Add transparent comparator and perfect forwarding support to find\(\) and count\(\) [\#795](https://github.com/nlohmann/json/pull/795) ([jseward](https://github.com/jseward)) +- Error : 'identifier "size\_t" is undefined' in linux [\#793](https://github.com/nlohmann/json/pull/793) ([sonulohani](https://github.com/sonulohani)) +- Fix Visual Studio 2017 warnings [\#788](https://github.com/nlohmann/json/pull/788) ([jseward](https://github.com/jseward)) +- Fix warning C4706 on Visual Studio 2017 [\#785](https://github.com/nlohmann/json/pull/785) ([jseward](https://github.com/jseward)) +- Set GENERATE\_TAGFILE in Doxyfile [\#783](https://github.com/nlohmann/json/pull/783) ([eld00d](https://github.com/eld00d)) +- using more CMake [\#765](https://github.com/nlohmann/json/pull/765) ([nlohmann](https://github.com/nlohmann)) +- Simplified istream handing \#367 [\#764](https://github.com/nlohmann/json/pull/764) ([pjkundert](https://github.com/pjkundert)) +- Add info for the vcpkg package. [\#753](https://github.com/nlohmann/json/pull/753) ([gregmarr](https://github.com/gregmarr)) +- fix from\_json implementation for pair/tuple [\#708](https://github.com/nlohmann/json/pull/708) ([theodelrieu](https://github.com/theodelrieu)) +- Update json.hpp [\#686](https://github.com/nlohmann/json/pull/686) ([GoWebProd](https://github.com/GoWebProd)) +- Remove duplicate word [\#685](https://github.com/nlohmann/json/pull/685) ([daixtrose](https://github.com/daixtrose)) +- To fix compilation issue for intel OSX compiler [\#682](https://github.com/nlohmann/json/pull/682) ([kbthomp1](https://github.com/kbthomp1)) +- Digraph warning [\#679](https://github.com/nlohmann/json/pull/679) ([traits](https://github.com/traits)) +- massage -\> message [\#678](https://github.com/nlohmann/json/pull/678) ([DmitryKuk](https://github.com/DmitryKuk)) +- Fix "not constraint" grammar in docs [\#674](https://github.com/nlohmann/json/pull/674) ([wincent](https://github.com/wincent)) +- Add documentation for integration with CMake and hunter [\#671](https://github.com/nlohmann/json/pull/671) ([dan-42](https://github.com/dan-42)) +- REFACTOR: rewrite CMakeLists.txt for better inlcude and reuse [\#669](https://github.com/nlohmann/json/pull/669) ([dan-42](https://github.com/dan-42)) +- enable\_testing only if the JSON\_BuildTests is ON [\#666](https://github.com/nlohmann/json/pull/666) ([effolkronium](https://github.com/effolkronium)) +- Support moving from rvalues in std::initializer\_list [\#663](https://github.com/nlohmann/json/pull/663) ([himikof](https://github.com/himikof)) +- add ensure\_ascii parameter to dump. \#330 [\#654](https://github.com/nlohmann/json/pull/654) ([ryanjmulder](https://github.com/ryanjmulder)) +- Rename BuildTests to JSON\_BuildTests [\#652](https://github.com/nlohmann/json/pull/652) ([olegendo](https://github.com/olegendo)) +- Don't include \, use std::make\_shared [\#650](https://github.com/nlohmann/json/pull/650) ([olegendo](https://github.com/olegendo)) +- Refacto/split basic json [\#643](https://github.com/nlohmann/json/pull/643) ([theodelrieu](https://github.com/theodelrieu)) +- fix typo in operator\_\_notequal example [\#630](https://github.com/nlohmann/json/pull/630) ([Chocobo1](https://github.com/Chocobo1)) +- Fix MSVC warning C4819 [\#629](https://github.com/nlohmann/json/pull/629) ([Chocobo1](https://github.com/Chocobo1)) +- \[BugFix\] Add parentheses around std::min [\#626](https://github.com/nlohmann/json/pull/626) ([koemeet](https://github.com/koemeet)) +- add pair/tuple conversions [\#624](https://github.com/nlohmann/json/pull/624) ([theodelrieu](https://github.com/theodelrieu)) +- remove std::pair support [\#615](https://github.com/nlohmann/json/pull/615) ([theodelrieu](https://github.com/theodelrieu)) +- Add pair support, fix CompatibleObject conversions \(fixes \#600\) [\#609](https://github.com/nlohmann/json/pull/609) ([theodelrieu](https://github.com/theodelrieu)) +- \#550 Fix iterator related compiling issues for Intel icc [\#598](https://github.com/nlohmann/json/pull/598) ([HenryRLee](https://github.com/HenryRLee)) +- Issue \#593 Fix the arithmetic operators in the iterator and reverse iterator [\#595](https://github.com/nlohmann/json/pull/595) ([HenryRLee](https://github.com/HenryRLee)) +- fix doxygen error of basic\_json::get\(\) [\#583](https://github.com/nlohmann/json/pull/583) ([zhaohuaxishi](https://github.com/zhaohuaxishi)) +- Fixing assignement for iterator wrapper second, and adding unit test [\#579](https://github.com/nlohmann/json/pull/579) ([Type1J](https://github.com/Type1J)) +- Adding first and second properties to iteration\_proxy\_internal [\#578](https://github.com/nlohmann/json/pull/578) ([Type1J](https://github.com/Type1J)) +- Adding support for Meson. [\#576](https://github.com/nlohmann/json/pull/576) ([Type1J](https://github.com/Type1J)) +- add enum class default conversions [\#545](https://github.com/nlohmann/json/pull/545) ([theodelrieu](https://github.com/theodelrieu)) +- Properly pop diagnostics [\#540](https://github.com/nlohmann/json/pull/540) ([tinloaf](https://github.com/tinloaf)) +- Add Visual Studio 17 image to appveyor build matrix [\#536](https://github.com/nlohmann/json/pull/536) ([vpetrigo](https://github.com/vpetrigo)) +- UTF8 encoding enhancement [\#534](https://github.com/nlohmann/json/pull/534) ([TedLyngmo](https://github.com/TedLyngmo)) +- Fix typo [\#530](https://github.com/nlohmann/json/pull/530) ([berkus](https://github.com/berkus)) +- Make exception base class visible in basic\_json [\#526](https://github.com/nlohmann/json/pull/526) ([krzysztofwos](https://github.com/krzysztofwos)) +- :art: Namespace `uint8\_t` from the C++ stdlib [\#510](https://github.com/nlohmann/json/pull/510) ([alex-weej](https://github.com/alex-weej)) +- add to\_json method for C arrays [\#508](https://github.com/nlohmann/json/pull/508) ([theodelrieu](https://github.com/theodelrieu)) +- Fix -Weffc++ warnings \(GNU 6.3.1\) [\#496](https://github.com/nlohmann/json/pull/496) ([TedLyngmo](https://github.com/TedLyngmo)) + ## [v2.1.1](https://github.com/nlohmann/json/releases/tag/v2.1.1) (2017-02-25) [Full Changelog](https://github.com/nlohmann/json/compare/v2.1.0...v2.1.1) @@ -129,7 +525,6 @@ All notable changes to this project will be documented in this file. This projec - Performance improvements [\#365](https://github.com/nlohmann/json/issues/365) - 'to\_string' is not a member of 'std' [\#364](https://github.com/nlohmann/json/issues/364) - Optional comment support. [\#363](https://github.com/nlohmann/json/issues/363) -- Loss of precision when serializing \ [\#360](https://github.com/nlohmann/json/issues/360) - Crash in dump\(\) from a static object [\#359](https://github.com/nlohmann/json/issues/359) - json::parse\(...\) vs json j; j.parse\(...\) [\#357](https://github.com/nlohmann/json/issues/357) - Hi, is there any method to dump json to string with the insert order rather than alphabets [\#356](https://github.com/nlohmann/json/issues/356) diff --git a/doc/Doxyfile b/doc/Doxyfile index bb38b979..56a8c589 100644 --- a/doc/Doxyfile +++ b/doc/Doxyfile @@ -5,7 +5,7 @@ #--------------------------------------------------------------------------- DOXYFILE_ENCODING = UTF-8 PROJECT_NAME = "JSON for Modern C++" -PROJECT_NUMBER = 2.1.1 +PROJECT_NUMBER = 3.0.0 PROJECT_BRIEF = PROJECT_LOGO = OUTPUT_DIRECTORY = . diff --git a/doc/examples/meta.output b/doc/examples/meta.output index ae8cca63..287d4380 100644 --- a/doc/examples/meta.output +++ b/doc/examples/meta.output @@ -2,16 +2,16 @@ "compiler": { "c++": "201103", "family": "clang", - "version": "9.0.0 (clang-900.0.37)" + "version": "9.0.0 (clang-900.0.39.2)" }, "copyright": "(C) 2013-2017 Niels Lohmann", "name": "JSON for Modern C++", "platform": "apple", "url": "https://github.com/nlohmann/json", "version": { - "major": 2, - "minor": 1, - "patch": 1, - "string": "2.1.1" + "major": 3, + "minor": 0, + "patch": 0, + "string": "3.0.0" } } diff --git a/doc/index.md b/doc/index.md index 0a7b45c8..36bde60b 100644 --- a/doc/index.md +++ b/doc/index.md @@ -278,4 +278,4 @@ The container functions known from STL have been extended to support the differe @author [Niels Lohmann](http://nlohmann.me) @see https://github.com/nlohmann/json to download the source code -@version 2.1.1 +@version 3.0.0 diff --git a/doc/json.gif b/doc/json.gif index 2fbcde638d0883d9db4636ea5caa9cec1bef33e8..dea04382abd37641c3334fd5437860aaf09f8436 100644 GIT binary patch delta 35950 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 YSh{e!fW%?FDVhlHM3mv3)>DZ81DP%fQUCw| delta 35614 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�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 diff --git a/src/json.hpp b/src/json.hpp index 31429f81..91cd2a29 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ -| | |__ | | | | | | version 2.1.1 +| | |__ | | | | | | version 3.0.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . @@ -7499,7 +7499,7 @@ class basic_json result["url"] = "https://github.com/nlohmann/json"; result["version"] = { - {"string", "2.1.1"}, {"major", 2}, {"minor", 1}, {"patch", 1} + {"string", "3.0.0"}, {"major", 3}, {"minor", 0}, {"patch", 0} }; #ifdef _WIN32 @@ -8119,7 +8119,7 @@ class basic_json object = nullptr; // silence warning, see #821 if (JSON_UNLIKELY(t == value_t::null)) { - JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 2.1.1")); // LCOV_EXCL_LINE + JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.0.0")); // LCOV_EXCL_LINE } break; } diff --git a/test/src/fuzzer-driver_afl.cpp b/test/src/fuzzer-driver_afl.cpp index 92e91475..e4eb4a13 100644 --- a/test/src/fuzzer-driver_afl.cpp +++ b/test/src/fuzzer-driver_afl.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (fuzz test support) -| | |__ | | | | | | version 2.1.1 +| | |__ | | | | | | version 3.0.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json This file implements a driver for American Fuzzy Lop (afl-fuzz). It relies on diff --git a/test/src/fuzzer-parse_cbor.cpp b/test/src/fuzzer-parse_cbor.cpp index 4bcfc7ef..cf2ce821 100644 --- a/test/src/fuzzer-parse_cbor.cpp +++ b/test/src/fuzzer-parse_cbor.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (fuzz test support) -| | |__ | | | | | | version 2.1.1 +| | |__ | | | | | | version 3.0.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json This file implements a parser test suitable for fuzz testing. Given a byte diff --git a/test/src/fuzzer-parse_json.cpp b/test/src/fuzzer-parse_json.cpp index fdaf96a7..bacf628a 100644 --- a/test/src/fuzzer-parse_json.cpp +++ b/test/src/fuzzer-parse_json.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (fuzz test support) -| | |__ | | | | | | version 2.1.1 +| | |__ | | | | | | version 3.0.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json This file implements a parser test suitable for fuzz testing. Given a byte diff --git a/test/src/fuzzer-parse_msgpack.cpp b/test/src/fuzzer-parse_msgpack.cpp index 667a68d6..ae9534f6 100644 --- a/test/src/fuzzer-parse_msgpack.cpp +++ b/test/src/fuzzer-parse_msgpack.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (fuzz test support) -| | |__ | | | | | | version 2.1.1 +| | |__ | | | | | | version 3.0.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json This file implements a parser test suitable for fuzz testing. Given a byte diff --git a/test/src/unit-algorithms.cpp b/test/src/unit-algorithms.cpp index 5a106b6a..b3f534d6 100644 --- a/test/src/unit-algorithms.cpp +++ b/test/src/unit-algorithms.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 2.1.1 +| | |__ | | | | | | version 3.0.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-allocator.cpp b/test/src/unit-allocator.cpp index d2423a48..183336e9 100644 --- a/test/src/unit-allocator.cpp +++ b/test/src/unit-allocator.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 2.1.1 +| | |__ | | | | | | version 3.0.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-capacity.cpp b/test/src/unit-capacity.cpp index db5166a5..971068ec 100644 --- a/test/src/unit-capacity.cpp +++ b/test/src/unit-capacity.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 2.1.1 +| | |__ | | | | | | version 3.0.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-cbor.cpp b/test/src/unit-cbor.cpp index 8d28f686..638ccefb 100644 --- a/test/src/unit-cbor.cpp +++ b/test/src/unit-cbor.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 2.1.1 +| | |__ | | | | | | version 3.0.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-class_const_iterator.cpp b/test/src/unit-class_const_iterator.cpp index 573e773b..631656d6 100644 --- a/test/src/unit-class_const_iterator.cpp +++ b/test/src/unit-class_const_iterator.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 2.1.1 +| | |__ | | | | | | version 3.0.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-class_iterator.cpp b/test/src/unit-class_iterator.cpp index 1ef4a538..875f309e 100644 --- a/test/src/unit-class_iterator.cpp +++ b/test/src/unit-class_iterator.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 2.1.1 +| | |__ | | | | | | version 3.0.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-class_lexer.cpp b/test/src/unit-class_lexer.cpp index fbb98b58..3f2d77cf 100644 --- a/test/src/unit-class_lexer.cpp +++ b/test/src/unit-class_lexer.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 2.1.1 +| | |__ | | | | | | version 3.0.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-class_parser.cpp b/test/src/unit-class_parser.cpp index 9afa7d26..008ef432 100644 --- a/test/src/unit-class_parser.cpp +++ b/test/src/unit-class_parser.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 2.1.1 +| | |__ | | | | | | version 3.0.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-comparison.cpp b/test/src/unit-comparison.cpp index 587ee3d2..7b1aa6e7 100644 --- a/test/src/unit-comparison.cpp +++ b/test/src/unit-comparison.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 2.1.1 +| | |__ | | | | | | version 3.0.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-concepts.cpp b/test/src/unit-concepts.cpp index 971651e0..981c89e1 100644 --- a/test/src/unit-concepts.cpp +++ b/test/src/unit-concepts.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 2.1.1 +| | |__ | | | | | | version 3.0.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-constructor1.cpp b/test/src/unit-constructor1.cpp index d8c9482c..b216540a 100644 --- a/test/src/unit-constructor1.cpp +++ b/test/src/unit-constructor1.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 2.1.1 +| | |__ | | | | | | version 3.0.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-constructor2.cpp b/test/src/unit-constructor2.cpp index 7259edfb..cf5e39f5 100644 --- a/test/src/unit-constructor2.cpp +++ b/test/src/unit-constructor2.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 2.1.1 +| | |__ | | | | | | version 3.0.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-convenience.cpp b/test/src/unit-convenience.cpp index 3301a4e4..fc9f299d 100644 --- a/test/src/unit-convenience.cpp +++ b/test/src/unit-convenience.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 2.1.1 +| | |__ | | | | | | version 3.0.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-conversions.cpp b/test/src/unit-conversions.cpp index 307fbe97..81978499 100644 --- a/test/src/unit-conversions.cpp +++ b/test/src/unit-conversions.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 2.1.1 +| | |__ | | | | | | version 3.0.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-deserialization.cpp b/test/src/unit-deserialization.cpp index 2798f102..2181bc4e 100644 --- a/test/src/unit-deserialization.cpp +++ b/test/src/unit-deserialization.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 2.1.1 +| | |__ | | | | | | version 3.0.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-element_access1.cpp b/test/src/unit-element_access1.cpp index 630b1a5e..0a7f9645 100644 --- a/test/src/unit-element_access1.cpp +++ b/test/src/unit-element_access1.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 2.1.1 +| | |__ | | | | | | version 3.0.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-element_access2.cpp b/test/src/unit-element_access2.cpp index 5950349b..40cd8119 100644 --- a/test/src/unit-element_access2.cpp +++ b/test/src/unit-element_access2.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 2.1.1 +| | |__ | | | | | | version 3.0.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-inspection.cpp b/test/src/unit-inspection.cpp index e322dbe7..82fbf727 100644 --- a/test/src/unit-inspection.cpp +++ b/test/src/unit-inspection.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 2.1.1 +| | |__ | | | | | | version 3.0.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-iterator_wrapper.cpp b/test/src/unit-iterator_wrapper.cpp index b8e00659..137aca8a 100644 --- a/test/src/unit-iterator_wrapper.cpp +++ b/test/src/unit-iterator_wrapper.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 2.1.1 +| | |__ | | | | | | version 3.0.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-iterators1.cpp b/test/src/unit-iterators1.cpp index 66ffed22..d5d61932 100644 --- a/test/src/unit-iterators1.cpp +++ b/test/src/unit-iterators1.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 2.1.1 +| | |__ | | | | | | version 3.0.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-iterators2.cpp b/test/src/unit-iterators2.cpp index be4e2770..2ef5c0a8 100644 --- a/test/src/unit-iterators2.cpp +++ b/test/src/unit-iterators2.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 2.1.1 +| | |__ | | | | | | version 3.0.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-json_patch.cpp b/test/src/unit-json_patch.cpp index 636fa2bc..15f3d015 100644 --- a/test/src/unit-json_patch.cpp +++ b/test/src/unit-json_patch.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 2.1.1 +| | |__ | | | | | | version 3.0.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-json_pointer.cpp b/test/src/unit-json_pointer.cpp index ee55dc58..4af379c4 100644 --- a/test/src/unit-json_pointer.cpp +++ b/test/src/unit-json_pointer.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 2.1.1 +| | |__ | | | | | | version 3.0.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-meta.cpp b/test/src/unit-meta.cpp index ce502626..015e84be 100644 --- a/test/src/unit-meta.cpp +++ b/test/src/unit-meta.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 2.1.1 +| | |__ | | | | | | version 3.0.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . @@ -42,10 +42,10 @@ TEST_CASE("version information") CHECK(j["url"] == "https://github.com/nlohmann/json"); CHECK(j["version"] == json( { - {"string", "2.1.1"}, - {"major", 2}, - {"minor", 1}, - {"patch", 1} + {"string", "3.0.0"}, + {"major", 3}, + {"minor", 0}, + {"patch", 0} })); CHECK(j.find("platform") != j.end()); diff --git a/test/src/unit-modifiers.cpp b/test/src/unit-modifiers.cpp index 01dfa415..e439c2f0 100644 --- a/test/src/unit-modifiers.cpp +++ b/test/src/unit-modifiers.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 2.1.1 +| | |__ | | | | | | version 3.0.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-msgpack.cpp b/test/src/unit-msgpack.cpp index 148bb180..18bdbfec 100644 --- a/test/src/unit-msgpack.cpp +++ b/test/src/unit-msgpack.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 2.1.1 +| | |__ | | | | | | version 3.0.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-noexcept.cpp b/test/src/unit-noexcept.cpp index 8269574e..ed294250 100644 --- a/test/src/unit-noexcept.cpp +++ b/test/src/unit-noexcept.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 2.1.1 +| | |__ | | | | | | version 3.0.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-pointer_access.cpp b/test/src/unit-pointer_access.cpp index f3830e5d..068330c6 100644 --- a/test/src/unit-pointer_access.cpp +++ b/test/src/unit-pointer_access.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 2.1.1 +| | |__ | | | | | | version 3.0.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-readme.cpp b/test/src/unit-readme.cpp index 1ce6ee1d..8f9f7e0a 100644 --- a/test/src/unit-readme.cpp +++ b/test/src/unit-readme.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 2.1.1 +| | |__ | | | | | | version 3.0.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-reference_access.cpp b/test/src/unit-reference_access.cpp index c05ae723..fd020221 100644 --- a/test/src/unit-reference_access.cpp +++ b/test/src/unit-reference_access.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 2.1.1 +| | |__ | | | | | | version 3.0.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-regression.cpp b/test/src/unit-regression.cpp index 17728160..a24ff539 100644 --- a/test/src/unit-regression.cpp +++ b/test/src/unit-regression.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 2.1.1 +| | |__ | | | | | | version 3.0.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-serialization.cpp b/test/src/unit-serialization.cpp index fb500ed9..ce48b551 100644 --- a/test/src/unit-serialization.cpp +++ b/test/src/unit-serialization.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 2.1.1 +| | |__ | | | | | | version 3.0.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-testsuites.cpp b/test/src/unit-testsuites.cpp index d281c679..861419b5 100644 --- a/test/src/unit-testsuites.cpp +++ b/test/src/unit-testsuites.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 2.1.1 +| | |__ | | | | | | version 3.0.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-udt.cpp b/test/src/unit-udt.cpp index 409cac83..f32acbbe 100644 --- a/test/src/unit-udt.cpp +++ b/test/src/unit-udt.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 2.1.1 +| | |__ | | | | | | version 3.0.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-unicode.cpp b/test/src/unit-unicode.cpp index b51a1579..24b13f95 100644 --- a/test/src/unit-unicode.cpp +++ b/test/src/unit-unicode.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 2.1.1 +| | |__ | | | | | | version 3.0.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit.cpp b/test/src/unit.cpp index 38f2d5b4..b08408d3 100644 --- a/test/src/unit.cpp +++ b/test/src/unit.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 2.1.1 +| | |__ | | | | | | version 3.0.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . From 9eb5e2c27129e479c96bcb4ebd8b993c36361649 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sun, 17 Dec 2017 08:40:19 +0100 Subject: [PATCH 15/59] :bookmark: set version to 3.0.0 --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7e68f862..37fd0249 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [![Coverage Status](https://img.shields.io/coveralls/nlohmann/json.svg)](https://coveralls.io/r/nlohmann/json) [![Coverity Scan Build Status](https://scan.coverity.com/projects/5550/badge.svg)](https://scan.coverity.com/projects/nlohmann-json) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/f3732b3327e34358a0e9d1fe9f661f08)](https://www.codacy.com/app/nlohmann/json?utm_source=github.com&utm_medium=referral&utm_content=nlohmann/json&utm_campaign=Badge_Grade) -[![Try online](https://img.shields.io/badge/try-online-blue.svg)](https://wandbox.org/permlink/yCTCvQi0ZVxGuL3L) +[![Try online](https://img.shields.io/badge/try-online-blue.svg)](https://wandbox.org/permlink/TZS6TQdqmEUcN8WW) [![Documentation](https://img.shields.io/badge/docs-doxygen-blue.svg)](http://nlohmann.github.io/json) [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/nlohmann/json/master/LICENSE.MIT) [![Github Releases](https://img.shields.io/github/release/nlohmann/json.svg)](https://github.com/nlohmann/json/releases) @@ -947,7 +947,7 @@ The library itself contains of a single header file licensed under the MIT licen - [**send_to_wandbox**](https://github.com/nlohmann/json/blob/develop/doc/scripts/send_to_wandbox.py) to send code examples to [Wandbox](http://melpon.org/wandbox) - [**Travis**](https://travis-ci.org) for [continuous integration](https://travis-ci.org/nlohmann/json) on Linux and macOS - [**Valgrind**](http://valgrind.org) to check for correct memory management -- [**Wandbox**](http://melpon.org/wandbox) for [online examples](https://wandbox.org/permlink/yCTCvQi0ZVxGuL3L) +- [**Wandbox**](http://melpon.org/wandbox) for [online examples](https://wandbox.org/permlink/TZS6TQdqmEUcN8WW) ## Projects using JSON for Modern C++ From 106f9f5436f6726006627ce3122fddf7fc9ca330 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sun, 17 Dec 2017 10:20:30 +0100 Subject: [PATCH 16/59] :arrow_up: updated git-update-ghpages script --- doc/Makefile | 2 +- doc/scripts/git-update-ghpages | 374 +++++++++++++++------------------ 2 files changed, 174 insertions(+), 202 deletions(-) diff --git a/doc/Makefile b/doc/Makefile index c900bdea..886378a4 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -63,7 +63,7 @@ doxygen: create_output create_links $(SED) -i 's@< ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType, JSONSerializer >@@g' html/*.html upload: clean doxygen check_output - cd html ; ../scripts/git-update-ghpages nlohmann/json + scripts/git-update-ghpages nlohmann/json html rm -fr html open http://nlohmann.github.io/json/ diff --git a/doc/scripts/git-update-ghpages b/doc/scripts/git-update-ghpages index f9760fee..393650c1 100755 --- a/doc/scripts/git-update-ghpages +++ b/doc/scripts/git-update-ghpages @@ -1,221 +1,193 @@ -#!/usr/bin/env ruby -# git update-ghpages user/repo -b gh-pages -p manual/ -i +#!/usr/bin/env bash +set -o errexit -require 'fileutils' -require 'tmpdir' +copy_contents() { + local source="$1" + status "Copying contents from $source" + if [[ ! "$dryrun" == "1" ]]; then + (cd "$source" >/dev/null && tar c .) | tar xv + else + _ "(cd \"$source\" >/dev/null && tar c .) | tar xv" + fi +} -module Params - def extract(what) i = index(what) and slice!(i, 2)[1] end; - def first_is(what) shift if what.include?(self.first); end - def self.[](*what) what.extend Params; end - def ===(argv) argv.first_is(self); end -end +# Sets git config +set_config() { + if [ -n "$GIT_NAME" ]; then _ git config user.name "$GIT_NAME"; fi + if [ -n "$GIT_EMAIL" ]; then _ git config user.email "$GIT_EMAIL"; fi +} -# ============================================================================ +# Runs the deployment +run() { + if [ ! -d "$source" ]; then + echo "Source is not a directory: $source" + exit 1 + fi -ARGV.extend Params + local tmpdir="$(mktemp -d)" -class CLI - # CLI options - attr_reader :prefix #=> "doc/" - attr_reader :input #=> "/home/me/projects/foo" - attr_reader :message #=> "Updated" - attr_reader :repo #=> "git@github.com:me/project.git" - attr_reader :url #=> "http://me.github.com/project" - attr_reader :branch #=> "gh-pages" + if [[ "$force" == "1" ]]; then + _ cd "$tmpdir" + _ git init + _ git checkout -b "$branch" + copy_contents "$source" + if [[ "$useenv" == "1" ]]; then set_config; fi + _ git add -A . + git_commit + git_push --force + else + _ cd "$tmpdir" + _ git clone "$repo" . -b "$branch" || ( \ + _ git init && \ + _ git checkout -b "$branch") + if [[ "$keep" == "0" ]]; then _ rm -rf ./*; fi + copy_contents "$source" + if [[ "$useenv" == "1" ]]; then set_config; fi + _ git add -A . + git_commit || true + git_push + fi + _ rm -rf "$tmpdir" + status_ "Done" +} - def verbose?() @verbose; end - def force?() @force; end - def simulate?() @simulate; end +git_commit() { + if [ -z "$author" ]; then + _ git commit -m "$message" + else + _ git commit -m "$message" --author "$author" + fi +} - def initialize - # Switches - @verbose = !! (ARGV.extract('--verbose') || ARGV.delete('-v')) - @simulate = !! (ARGV.extract('--simulate') || ARGV.delete('-s')) - @force = !! (ARGV.delete('--force') || ARGV.delete('-f')) +git_push() { + if [ -z "$GITHUB_TOKEN" ]; then + _ git push "${repo}" "$branch" "$@" + else + status "Pushing via \$GITHUB_TOKEN $@" + _ git push "https://${GITHUB_TOKEN}@github.com/${repospec}.git" "$branch" "$@" \ + --quiet >/dev/null 2>&1 || \ + ( status_ "Failed to push"; exit 1 ) + fi +} - # Stuff - @prefix = ARGV.extract('--prefix') || ARGV.extract('-p') || '' - @input = File.expand_path(ARGV.extract('--input') || ARGV.extract('-i') || '.') - @message = ARGV.extract('--message') || ARGV.extract('-m') || 'Update' +status() { + echo -e "\n\033[34m==>\033[0;1m" "$@\033[0m" +} +status_() { + echo -e "\033[33;1m==>\033[0m" "$@" +} - # Github info - branch = ARGV.extract('--branch') || ARGV.extract('-b') || nil - @repo, @url, @branch = get_github_info(ARGV.shift, branch) - end +_() { + echo "" + status_ "$@" + if [[ ! "$dryrun" == "1" ]]; then "$@"; fi +} - def git_current_branch - `git rev-parse --abbrev-ref HEAD`.strip - end +help() { + local cmd="$(basename $0)" + echo 'Usage:' + echo " $cmd " + echo '' + echo 'Parameters:' + echo " REPO repository to push to in 'user/repo' form" + echo " SOURCE path to upload to repository's gh-pages branch" + echo '' + echo 'Options:' + echo ' -h, --help show help screen' + echo ' -f, --force force push' + echo ' -n, --dry-run run in simulation mode' + echo ' -e, --use-env pick up arguments from environment variables' + echo ' -b, --branch use this branch name (default: gh-pages)' + echo ' -a, --author set the author' + echo ' -k, --keep keep existing files in the repo' + echo '' + echo 'Env var options:' + echo ' GITHUB_TOKEN if set, use this to push to the repo' + echo '' + echo 'Optional env vars:' + echo " Run with '-e' to enable the use of these variables." + echo " GIT_NAME set this as the repos user.name" + echo ' GIT_EMAIL set this as the repos user.email' + echo ' GITHUB_REPO substitute as the REPO (1st argument)' + echo ' GIT_SOURCE substitute as the SOURCE (2nd argument)' + echo ' GIT_BRANCH use this branch name (--branch)' + echo '' + echo 'Example:' + echo " $cmd rstacruz/myproject doc" + echo " # pushes './doc' into the gh-pages branch of rstacruz/myproject" + echo '' + echo " export GITHUB_REPO='xyz/abc'" + echo " export GIT_SOURCE='docs'" + echo " $cmd -e" + echo " # pushes './doc' into the gh-pages branch of xyz/abc" +} - def git_deploy - in_temp_path do |temppath| - status "Cloning repository" - system! "git clone #{repo} -b #{branch} #{temppath}" +# +# Defaults +# - if git_current_branch != branch - status "Warning: No #{branch} branch found in repo, creating one." - return git_deploy_force - end +force=0 +dryrun=0 +repospec= +source= +branch= +message="Update" +useenv=0 +author="" +keep=0 - copy_files input, File.join(temppath, prefix) +# +# Parse args +# - status "Committing files" - system! "git add .; git add -u; git commit -m #{message.to_s.inspect}" +while [[ "$1" =~ ^- && ! "$1" == '--' ]]; do case $1 in + -h | --help ) + help + exit + ;; + -b | --branch ) + shift + branch="$1" + ;; + -n | --dry-run ) + dryrun=1 + ;; + -e | --use-env ) + useenv=1 + ;; + -k | --keep ) + keep=1 + ;; + -a | --author) + shift + author="$1" + ;; + -f | --force ) + force=1 + ;; +esac; shift; done +if [[ "$1" == '--' ]]; then shift; fi - unless simulate? - status "Updating repo" - system! "git push origin #{branch}" - end - true - end - end +if [[ "$useenv" == "1" ]] && [[ -n "$GIT_BRANCH" ]] && [[ -z "$branch" ]]; then + branch="$GIT_BRANCH" +fi - def git_deploy_force - in_temp_path do |temppath| - status "Creating new repository" - system! "git init ." - system! "git checkout -b gh-pages" +if [[ "$useenv" == "1" ]] && [[ -n "$GITHUB_REPO" ]] && [[ -n "$GIT_SOURCE" ]] && [[ -z "$2" ]]; then + repospec="$GITHUB_REPO" + source="$GIT_SOURCE" +else + repospec="$1" + source="$2" +fi - copy_files input, File.join(temppath, prefix) +: ${branch:="gh-pages"} - status "Committing files" - system! "git add . && git commit -m #{message.to_s.inspect}" +if [ -z "$source" ]; then + help + exit 1 +fi - unless simulate? - status "Updating repo" - system! "git push #{repo} gh-pages:#{branch} --force" - end - true - end - end +source="`pwd -LP`/$source" +repo="https://github.com/${repospec}.git" - def get_github_info(repo, branch=nil, prefix=nil) - if github_format?(repo) - user, repo_name = repo.split('/') - r = "git@github.com:#{repo}.git" - - # User page or project page? - if repo_name =~ /\.github\.com/ - [r, "http://#{repo_name}/#{prefix}", branch || 'master' ] - else - [r, "http://#{user}.github.com/#{repo_name}/#{prefix}", branch || 'gh-pages' ] - end - else - [repo, nil, branch] - end - end - - def run! - unless repo - print_help - exit 128 - end - - status "Deploying to #{repo} (branch #{branch})" - msg "NOTE: Running in simulation mode." if simulate? - msg "WARNING: If the repository has gh-pages history, it with be overriden." if force? && !simulate? - - result = force? ? git_deploy_force : git_deploy - - if result - puts "" - status "Done." - msg "See: #{url}" if url && !simulate? - else - tip "Failed." - exit 1 - end - end - - def status(str) - puts "#{c('===>',34)} #{c(str, 32)}" - end - - def msg(str) - puts " #{c(str, 32)}" - end - - def c(str, color) - "\033[#{color}m#{str}\033[0m" - end - - def print_help - tip \ - %{Usage: git update-ghpages username/repository [options] - - Flags: - -f, --force Force an update (WARNING: kills the history!) - -s, --simulate Creates the repository, but doesn't push. - -v, --verbose Verbose mode - - Options: - -p PATH, --prefix The prefix - -i PATH, --input Input (defaults to current directory) - -b BRANCH, --branch The branch to deploy to (defaults to gh-pages) - -m MSG, --message Commit message (defaults to 'Update') - - Examples: - - Update the repo 'coffee' of github user 'james' with the files from the - current directory. The files will be in http://james.github.com/coffee. - - $ git update-ghpages james/coffee - - Same as above, but take the files from 'doc/'. - - $ git update-ghpages james/coffee -i doc - - Same as the first, but the files will instead be in - http://james.github.com/coffee/manual. - - $ git update-ghpages james/coffee -i doc -p manual - }.gsub(/^ {4}/, '') - end - -private # Helpers - - def tip(msg) - $stderr.write "#{msg}\n" - end - - def github_format?(str) - str =~ /^([A-Za-z0-9\-_]+)\/([A-Za-z0-9\-_\.]+)$/ - end - - # Performs actions inside a temp path. - def in_temp_path(&blk) - require 'tmpdir' - Dir.mktmpdir do |dir| - Dir.chdir(dir) { yield dir } - end - end - - def system!(str) - puts `#{str} 2>&1`.strip.gsub(/^/, " ") - raise "Failed with exit code #{$?.to_i}" unless $?.to_i == 0 - end - - # Returns the current branch name - def git_branch - `git symbolic-ref HEAD`.strip.split('/').last - end - - # Copy files from source folder to another - def copy_files(from, to) - status "Copying files #{from} => #{to}..." if verbose? - - Dir["#{from}/**/*"].each do |f| - next unless File.file?(f) - - target = File.join(to, f.gsub(/^#{Regexp.escape from}/, '')) - - FileUtils.mkdir_p File.dirname(target) - msg "%20s => %-20s" % [f, target] if verbose? - FileUtils.cp f, target - end - end - -end - -CLI.new.run! +run From 1856f38c85925e178d2513726a900aeceb2176e1 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sun, 17 Dec 2017 11:22:35 +0100 Subject: [PATCH 17/59] :memo: removed paragraph on version 3.0.0 --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 37fd0249..684161d5 100644 --- a/README.md +++ b/README.md @@ -75,8 +75,6 @@ If you are using [hunter](https://github.com/ruslo/hunter/) on your project for If you are using [vcpkg](https://github.com/Microsoft/vcpkg/) on your project for external dependencies, then you can use the [nlohmann-json package](https://github.com/Microsoft/vcpkg/tree/master/ports/nlohmann-json). Please see the vcpkg project for any issues regarding the packaging. -:warning: [Version 3.0.0](https://github.com/nlohmann/json/wiki/Road-toward-3.0.0) is currently under development. Branch `develop` is used for the ongoing work and is probably **unstable**. Please use the `master` branch for the last stable version 2.1.1. - ## Examples From ab0e8b2f3aed7f871f756ce3dc7d2ca8d02d7483 Mon Sep 17 00:00:00 2001 From: Eren Okka Date: Sun, 17 Dec 2017 18:02:55 +0300 Subject: [PATCH 18/59] Fix MSVC warning C4819 Replaces a U+00A0 character with regular space, and fixes a typo. --- src/json.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/json.hpp b/src/json.hpp index 91cd2a29..1f7e8dca 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -6564,7 +6564,7 @@ class serializer // check that the additional bytes are present assert(i + bytes < s.size()); - // to use \uxxxx escaping, we first need to caluclate + // to use \uxxxx escaping, we first need to calculate // the codepoint from the UTF-8 bytes int codepoint = 0; From 88ddb12afc7d12ec32d3f935b25d701ee14ecb81 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Mon, 18 Dec 2017 19:46:53 +0100 Subject: [PATCH 19/59] :memo: fix for #883 - Adjusted table to user-defined exceptions. This was forgotten in the 3.0.0 update. - Added update function to the table. --- doc/index.md | 55 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 22 deletions(-) diff --git a/doc/index.md b/doc/index.md index 36bde60b..3c23b3a9 100644 --- a/doc/index.md +++ b/doc/index.md @@ -45,6 +45,8 @@ These pages contain the API documentation of JSON for Modern C++, a C++11 header The container functions known from STL have been extended to support the different value types from JSON. However, not all functions can be applied to all value types. Note that the signature of some functions differ between the types; for instance, `at` may be called with either a string to address a key in an object or with an integer to address a value in an array. +Note that this table only lists those exceptions thrown due to the type. For instance, the @link nlohmann::basic_json::at(const typename object_t::key_type & key) `at` @endlink function will always throw a @link nlohmann::basic_json::type_error `json::type_error` @endlink exception when called for a string type. When called for an array, it *may* throw an @link nlohmann::basic_json::out_of_range `json::out_of_range` @endlink exception if the passed index is invalid. + - - - - + + + + - - - + + + @@ -158,7 +160,7 @@ The container functions known from STL have been extended to support the differe - + @@ -167,7 +169,7 @@ The container functions known from STL have been extended to support the differe - + @@ -198,7 +200,7 @@ The container functions known from STL have been extended to support the differe - + @@ -209,12 +211,12 @@ The container functions known from STL have been extended to support the differe - + - - - - + + + + @@ -223,26 +225,35 @@ The container functions known from STL have been extended to support the differe - + - - - + + + - - - + + + + + + + + + + + + From d1cda6888e6d57107a459d7a5bb4b77bdc371b96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20M=C3=B6ller?= Date: Wed, 20 Dec 2017 17:54:45 +0100 Subject: [PATCH 20/59] includes CTest module resp. BUILD_TESTING option --- CMakeLists.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 334dec27..cf0bbb61 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,7 +9,7 @@ project(nlohmann_json VERSION 3.0.0 LANGUAGES CXX) ## ## OPTIONS ## -option(JSON_BuildTests "Build the unit tests" ON) +option(JSON_BuildTests "Build the unit tests when BUILD_TESTING is enabled." ON) ## ## CONFIGURATION @@ -54,7 +54,9 @@ endif() ## TESTS ## create and configure the unit test target ## -if(JSON_BuildTests) +include(CTest) #adds option BUILD_TESTING (default ON) + +if(BUILD_TESTING AND JSON_BuildTests) enable_testing() include_directories(${NLOHMANN_JSON_SOURCE_DIR}) add_subdirectory(test) From 3113a52a7d148d7ad9567cf9d67fa67960beb3f1 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sat, 23 Dec 2017 18:38:18 +0100 Subject: [PATCH 21/59] :memo: added exception 403 to documentation of at (#888) The at function throws json::out_of_range.403 when a nonexistent object key is provided (just like the usual at function). This was not documented and users could assume json::out_of_range.404 would be thrown instead. - Updated documentation. - Added example code. --- doc/examples/at_json_pointer.cpp | 11 +++++++++++ doc/examples/at_json_pointer.link | 2 +- doc/examples/at_json_pointer.output | 1 + doc/examples/at_json_pointer_const.cpp | 11 +++++++++++ doc/examples/at_json_pointer_const.link | 2 +- doc/examples/at_json_pointer_const.output | 1 + doc/index.md | 6 ++++++ src/json.hpp | 7 ++++++- 8 files changed, 38 insertions(+), 3 deletions(-) diff --git a/doc/examples/at_json_pointer.cpp b/doc/examples/at_json_pointer.cpp index 80ed6c15..f43b1bcc 100644 --- a/doc/examples/at_json_pointer.cpp +++ b/doc/examples/at_json_pointer.cpp @@ -79,6 +79,17 @@ int main() std::cout << e.what() << '\n'; } + // out_of_range.403 + try + { + // try to use a JSON pointer to an nonexistent object key + json::const_reference ref = j.at("/foo"_json_pointer); + } + catch (json::out_of_range& e) + { + std::cout << e.what() << '\n'; + } + // out_of_range.404 try { diff --git a/doc/examples/at_json_pointer.link b/doc/examples/at_json_pointer.link index 61a4410a..99ebf019 100644 --- a/doc/examples/at_json_pointer.link +++ b/doc/examples/at_json_pointer.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/examples/at_json_pointer.output b/doc/examples/at_json_pointer.output index 505792f2..1d29893e 100644 --- a/doc/examples/at_json_pointer.output +++ b/doc/examples/at_json_pointer.output @@ -8,4 +8,5 @@ [json.exception.parse_error.109] parse error: array index 'one' is not a number [json.exception.out_of_range.401] array index 4 is out of range [json.exception.out_of_range.402] array index '-' (2) is out of range +[json.exception.out_of_range.403] key 'foo' not found [json.exception.out_of_range.404] unresolved reference token 'foo' diff --git a/doc/examples/at_json_pointer_const.cpp b/doc/examples/at_json_pointer_const.cpp index 1496aa5a..8009e95f 100644 --- a/doc/examples/at_json_pointer_const.cpp +++ b/doc/examples/at_json_pointer_const.cpp @@ -55,6 +55,17 @@ int main() std::cout << e.what() << '\n'; } + // out_of_range.403 + try + { + // try to use a JSON pointer to an nonexistent object key + json::const_reference ref = j.at("/foo"_json_pointer); + } + catch (json::out_of_range& e) + { + std::cout << e.what() << '\n'; + } + // out_of_range.404 try { diff --git a/doc/examples/at_json_pointer_const.link b/doc/examples/at_json_pointer_const.link index 31e0bb08..9011b99b 100644 --- a/doc/examples/at_json_pointer_const.link +++ b/doc/examples/at_json_pointer_const.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/examples/at_json_pointer_const.output b/doc/examples/at_json_pointer_const.output index b3361f04..aaf8f187 100644 --- a/doc/examples/at_json_pointer_const.output +++ b/doc/examples/at_json_pointer_const.output @@ -5,4 +5,5 @@ [json.exception.parse_error.109] parse error: array index 'one' is not a number [json.exception.out_of_range.401] array index 4 is out of range [json.exception.out_of_range.402] array index '-' (2) is out of range +[json.exception.out_of_range.403] key 'foo' not found [json.exception.out_of_range.404] unresolved reference token 'foo' diff --git a/doc/index.md b/doc/index.md index 3c23b3a9..122e8e6d 100644 --- a/doc/index.md +++ b/doc/index.md @@ -28,6 +28,12 @@ These pages contain the API documentation of JSON for Modern C++, a C++11 header - @link nlohmann::basic_json::get_ref get_ref @endlink -- get a value reference - @link nlohmann::basic_json::operator ValueType() const operator ValueType @endlink -- get a value (implicit conversion) - @link nlohmann::basic_json::value value @endlink -- get a value from an object and return default value if key is not present + - exceptions + - @link nlohmann::basic_json::parse_error parse_error @endlink for exceptions indicating a parse error + - @link nlohmann::basic_json::invalid_iterator invalid_iterator @endlink for exceptions indicating errors with iterators + - @link nlohmann::basic_json::type_error type_error @endlink for exceptions indicating executing a member function with a wrong type + - @link nlohmann::basic_json::out_of_range out_of_range @endlink for exceptions indicating access out of the defined range + - @link nlohmann::basic_json::other_error other_error @endlink for exceptions indicating other library errors - lexicographical comparison operators - serialization - deserialization diff --git a/src/json.hpp b/src/json.hpp index 1f7e8dca..ae363ba7 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -456,7 +456,6 @@ Exceptions have ids 5xx. name / id | example message | description ------------------------------ | --------------- | ------------------------- json.exception.other_error.501 | unsuccessful: {"op":"test","path":"/baz", "value":"bar"} | A JSON Patch operation 'test' failed. The unsuccessful operation is also printed. -json.exception.other_error.502 | invalid object size for conversion | Some conversions to user-defined types impose constraints on the object size (e.g. std::pair) @sa @ref exception for the base class of the library exceptions @sa @ref parse_error for exceptions indicating a parse error @@ -13721,6 +13720,9 @@ class basic_json pointer @a ptr. As `at` provides checked access (and no elements are implicitly inserted), the index '-' is always invalid. See example below. + @throw out_of_range.403 if the JSON pointer describes a key of an object + which cannot be found. See example below. + @throw out_of_range.404 if the JSON pointer @a ptr can not be resolved. See example below. @@ -13761,6 +13763,9 @@ class basic_json pointer @a ptr. As `at` provides checked access (and no elements are implicitly inserted), the index '-' is always invalid. See example below. + @throw out_of_range.403 if the JSON pointer describes a key of an object + which cannot be found. See example below. + @throw out_of_range.404 if the JSON pointer @a ptr can not be resolved. See example below. From 72bff90ed955421f4db98f272648afca565b72c8 Mon Sep 17 00:00:00 2001 From: "Matthew K. Gumbel" Date: Mon, 4 Dec 2017 15:42:08 -0800 Subject: [PATCH 22/59] :wrench: Fix up a few more effc++ items --- src/json.hpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index ae363ba7..4ffe5a6a 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -3526,7 +3526,7 @@ class primitive_iterator_t return *this; } - primitive_iterator_t operator++(int) + primitive_iterator_t const operator++(int) { auto result = *this; m_it++; @@ -3539,7 +3539,7 @@ class primitive_iterator_t return *this; } - primitive_iterator_t operator--(int) + primitive_iterator_t const operator--(int) { auto result = *this; m_it--; @@ -3850,7 +3850,7 @@ class iter_impl @brief post-increment (it++) @pre The iterator is initialized; i.e. `m_object != nullptr`. */ - iter_impl operator++(int) + iter_impl const operator++(int) { auto result = *this; ++(*this); @@ -3893,7 +3893,7 @@ class iter_impl @brief post-decrement (it--) @pre The iterator is initialized; i.e. `m_object != nullptr`. */ - iter_impl operator--(int) + iter_impl const operator--(int) { auto result = *this; --(*this); @@ -4299,7 +4299,7 @@ class json_reverse_iterator : public std::reverse_iterator json_reverse_iterator(const base_iterator& it) noexcept : base_iterator(it) {} /// post-increment (it++) - json_reverse_iterator operator++(int) + json_reverse_iterator const operator++(int) { return static_cast(base_iterator::operator++(1)); } @@ -4311,7 +4311,7 @@ class json_reverse_iterator : public std::reverse_iterator } /// post-decrement (it--) - json_reverse_iterator operator--(int) + json_reverse_iterator const operator--(int) { return static_cast(base_iterator::operator--(1)); } @@ -6567,7 +6567,8 @@ class serializer // the codepoint from the UTF-8 bytes int codepoint = 0; - assert(0 <= bytes and bytes <= 3); + // bytes is unsigned type: + assert(bytes <= 3); switch (bytes) { case 0: @@ -7046,7 +7047,6 @@ class json_pointer return result; } - /*! @brief create and return a reference to the pointed to value From 3b3b6e8e69ddbaf1f2a0e6b792be5d11bf4866a6 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Thu, 28 Dec 2017 13:52:23 +0100 Subject: [PATCH 23/59] :ambulance: fix for #894 - Implemented "copy" in terms of "add". - Added check for JSON Pointer array indices to make sure the complete reference token was processed. - Added test suite from https://github.com/json-patch/json-patch-tests --- src/json.hpp | 61 ++- test/data/json-patch-tests/README.md | 75 ++++ test/data/json-patch-tests/spec_tests.json | 233 +++++++++++ test/data/json-patch-tests/tests.json | 434 +++++++++++++++++++++ test/src/unit-json_patch.cpp | 40 ++ test/src/unit-regression.cpp | 28 ++ 6 files changed, 853 insertions(+), 18 deletions(-) create mode 100755 test/data/json-patch-tests/README.md create mode 100755 test/data/json-patch-tests/spec_tests.json create mode 100755 test/data/json-patch-tests/tests.json diff --git a/src/json.hpp b/src/json.hpp index ae363ba7..325c019c 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -732,7 +732,7 @@ struct external_constructor j.m_type = value_t::array; j.m_value = value_t::array; j.m_value.array->reserve(arr.size()); - for (bool x : arr) + for (const bool x : arr) { j.m_value.array->push_back(x); } @@ -2759,7 +2759,7 @@ scan_number_done: { // escape control characters std::string result; - for (auto c : token_string) + for (const auto c : token_string) { if ('\x00' <= c and c <= '\x1F') { @@ -7011,6 +7011,27 @@ class json_pointer return to_string(); } + /*! + @param[in] s reference token to be converted into an array index + + @return integer representation of @a s + + @throw out_of_range.404 if string @a s could not be converted to an integer + */ + static int array_index(const std::string& s) + { + size_t processed_chars = 0; + const int res = std::stoi(s, &processed_chars); + + // check if the string was completely read + if (JSON_UNLIKELY(processed_chars != s.size())) + { + JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + s + "'")); + } + + return res; + } + private: /*! @brief remove and return last reference pointer @@ -7046,7 +7067,6 @@ class json_pointer return result; } - /*! @brief create and return a reference to the pointed to value @@ -12236,7 +12256,7 @@ class basic_json JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(j.type_name()))); } - for (auto it = j.begin(); it != j.end(); ++it) + for (auto it = j.cbegin(); it != j.cend(); ++it) { m_value.object->operator[](it.key()) = it.value(); } @@ -13981,7 +14001,7 @@ class basic_json } else { - const auto idx = std::stoi(last_path); + const auto idx = json_pointer::array_index(last_path); if (JSON_UNLIKELY(static_cast(idx) > parent.size())) { // avoid undefined behavior @@ -14029,7 +14049,7 @@ class basic_json else if (parent.is_array()) { // note erase performs range check - parent.erase(static_cast(std::stoi(last_path))); + parent.erase(static_cast(json_pointer::array_index(last_path))); } }; @@ -14120,12 +14140,17 @@ class basic_json case patch_operations::copy: { - const std::string from_path = get_value("copy", "from", true); - const json_pointer from_ptr(from_path); + const std::string from_path = get_value("copy", "from", true); + const json_pointer from_ptr(from_path); - // the "from" location must exist - use at() - result[ptr] = result.at(from_ptr); - break; + // the "from" location must exist - use at() + basic_json v = result.at(from_ptr); + + // The copy is functionally identical to an "add" + // operation at the target location using the value + // specified in the "from" member. + operation_add(ptr, v); + break; } case patch_operations::test: @@ -14266,7 +14291,7 @@ class basic_json case value_t::object: { // first pass: traverse this object's elements - for (auto it = source.begin(); it != source.end(); ++it) + for (auto it = source.cbegin(); it != source.cend(); ++it) { // escape the key name to be used in a JSON patch const auto key = json_pointer::escape(it.key()); @@ -14288,7 +14313,7 @@ class basic_json } // second pass: traverse other object's elements - for (auto it = target.begin(); it != target.end(); ++it) + for (auto it = target.cbegin(); it != target.cend(); ++it) { if (source.find(it.key()) == source.end()) { @@ -14381,7 +14406,7 @@ json_pointer::get_and_create(NLOHMANN_BASIC_JSON_TPL& j) const // create an entry in the array JSON_TRY { - result = &result->operator[](static_cast(std::stoi(reference_token))); + result = &result->operator[](static_cast(array_index(reference_token))); } JSON_CATCH(std::invalid_argument&) { @@ -14458,7 +14483,7 @@ json_pointer::get_unchecked(NLOHMANN_BASIC_JSON_TPL* ptr) const JSON_TRY { ptr = &ptr->operator[]( - static_cast(std::stoi(reference_token))); + static_cast(array_index(reference_token))); } JSON_CATCH(std::invalid_argument&) { @@ -14513,7 +14538,7 @@ json_pointer::get_checked(NLOHMANN_BASIC_JSON_TPL* ptr) const // note: at performs range check JSON_TRY { - ptr = &ptr->at(static_cast(std::stoi(reference_token))); + ptr = &ptr->at(static_cast(array_index(reference_token))); } JSON_CATCH(std::invalid_argument&) { @@ -14568,7 +14593,7 @@ json_pointer::get_unchecked(const NLOHMANN_BASIC_JSON_TPL* ptr) const JSON_TRY { ptr = &ptr->operator[]( - static_cast(std::stoi(reference_token))); + static_cast(array_index(reference_token))); } JSON_CATCH(std::invalid_argument&) { @@ -14622,7 +14647,7 @@ json_pointer::get_checked(const NLOHMANN_BASIC_JSON_TPL* ptr) const // note: at performs range check JSON_TRY { - ptr = &ptr->at(static_cast(std::stoi(reference_token))); + ptr = &ptr->at(static_cast(array_index(reference_token))); } JSON_CATCH(std::invalid_argument&) { diff --git a/test/data/json-patch-tests/README.md b/test/data/json-patch-tests/README.md new file mode 100755 index 00000000..fb9e4478 --- /dev/null +++ b/test/data/json-patch-tests/README.md @@ -0,0 +1,75 @@ +JSON Patch Tests +================ + +These are test cases for implementations of [IETF JSON Patch (RFC6902)](http://tools.ietf.org/html/rfc6902). + +Some implementations can be found at [jsonpatch.com](http://jsonpatch.com). + + +Test Format +----------- + +Each test file is a JSON document that contains an array of test records. A +test record is an object with the following members: + +- doc: The JSON document to test against +- patch: The patch(es) to apply +- expected: The expected resulting document, OR +- error: A string describing an expected error +- comment: A string describing the test +- disabled: True if the test should be skipped + +All fields except 'doc' and 'patch' are optional. Test records consisting only +of a comment are also OK. + + +Files +----- + +- tests.json: the main test file +- spec_tests.json: tests from the RFC6902 spec + + +Writing Tests +------------- + +All tests should have a descriptive comment. Tests should be as +simple as possible - just what's required to test a specific piece of +behavior. If you want to test interacting behaviors, create tests for +each behavior as well as the interaction. + +If an 'error' member is specified, the error text should describe the +error the implementation should raise - *not* what's being tested. +Implementation error strings will vary, but the suggested error should +be easily matched to the implementation error string. Try to avoid +creating error tests that might pass because an incorrect error was +reported. + +Please feel free to contribute! + + +Credits +------- + +The seed test set was adapted from Byron Ruth's +[jsonpatch-js](https://github.com/bruth/jsonpatch-js/blob/master/test.js) and +extended by [Mike McCabe](https://github.com/mikemccabe). + + +License +------- + + Copyright 2014 The Authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/test/data/json-patch-tests/spec_tests.json b/test/data/json-patch-tests/spec_tests.json new file mode 100755 index 00000000..c160535b --- /dev/null +++ b/test/data/json-patch-tests/spec_tests.json @@ -0,0 +1,233 @@ +[ + { + "comment": "4.1. add with missing object", + "doc": { "q": { "bar": 2 } }, + "patch": [ {"op": "add", "path": "/a/b", "value": 1} ], + "error": + "path /a does not exist -- missing objects are not created recursively" + }, + + { + "comment": "A.1. Adding an Object Member", + "doc": { + "foo": "bar" +}, + "patch": [ + { "op": "add", "path": "/baz", "value": "qux" } +], + "expected": { + "baz": "qux", + "foo": "bar" +} + }, + + { + "comment": "A.2. Adding an Array Element", + "doc": { + "foo": [ "bar", "baz" ] +}, + "patch": [ + { "op": "add", "path": "/foo/1", "value": "qux" } +], + "expected": { + "foo": [ "bar", "qux", "baz" ] +} + }, + + { + "comment": "A.3. Removing an Object Member", + "doc": { + "baz": "qux", + "foo": "bar" +}, + "patch": [ + { "op": "remove", "path": "/baz" } +], + "expected": { + "foo": "bar" +} + }, + + { + "comment": "A.4. Removing an Array Element", + "doc": { + "foo": [ "bar", "qux", "baz" ] +}, + "patch": [ + { "op": "remove", "path": "/foo/1" } +], + "expected": { + "foo": [ "bar", "baz" ] +} + }, + + { + "comment": "A.5. Replacing a Value", + "doc": { + "baz": "qux", + "foo": "bar" +}, + "patch": [ + { "op": "replace", "path": "/baz", "value": "boo" } +], + "expected": { + "baz": "boo", + "foo": "bar" +} + }, + + { + "comment": "A.6. Moving a Value", + "doc": { + "foo": { + "bar": "baz", + "waldo": "fred" + }, + "qux": { + "corge": "grault" + } +}, + "patch": [ + { "op": "move", "from": "/foo/waldo", "path": "/qux/thud" } +], + "expected": { + "foo": { + "bar": "baz" + }, + "qux": { + "corge": "grault", + "thud": "fred" + } +} + }, + + { + "comment": "A.7. Moving an Array Element", + "doc": { + "foo": [ "all", "grass", "cows", "eat" ] +}, + "patch": [ + { "op": "move", "from": "/foo/1", "path": "/foo/3" } +], + "expected": { + "foo": [ "all", "cows", "eat", "grass" ] +} + + }, + + { + "comment": "A.8. Testing a Value: Success", + "doc": { + "baz": "qux", + "foo": [ "a", 2, "c" ] +}, + "patch": [ + { "op": "test", "path": "/baz", "value": "qux" }, + { "op": "test", "path": "/foo/1", "value": 2 } +], + "expected": { + "baz": "qux", + "foo": [ "a", 2, "c" ] + } + }, + + { + "comment": "A.9. Testing a Value: Error", + "doc": { + "baz": "qux" +}, + "patch": [ + { "op": "test", "path": "/baz", "value": "bar" } +], + "error": "string not equivalent" + }, + + { + "comment": "A.10. Adding a nested Member Object", + "doc": { + "foo": "bar" +}, + "patch": [ + { "op": "add", "path": "/child", "value": { "grandchild": { } } } +], + "expected": { + "foo": "bar", + "child": { + "grandchild": { + } + } +} + }, + + { + "comment": "A.11. Ignoring Unrecognized Elements", + "doc": { + "foo":"bar" +}, + "patch": [ + { "op": "add", "path": "/baz", "value": "qux", "xyz": 123 } +], + "expected": { + "foo":"bar", + "baz":"qux" +} + }, + + { + "comment": "A.12. Adding to a Non-existent Target", + "doc": { + "foo": "bar" +}, + "patch": [ + { "op": "add", "path": "/baz/bat", "value": "qux" } +], + "error": "add to a non-existent target" + }, + + { + "comment": "A.13 Invalid JSON Patch Document", + "doc": { + "foo": "bar" + }, + "patch": [ + { "op": "add", "path": "/baz", "value": "qux", "op": "remove" } +], + "error": "operation has two 'op' members", + "disabled": true + }, + + { + "comment": "A.14. ~ Escape Ordering", + "doc": { + "/": 9, + "~1": 10 + }, + "patch": [{"op": "test", "path": "/~01", "value": 10}], + "expected": { + "/": 9, + "~1": 10 + } + }, + + { + "comment": "A.15. Comparing Strings and Numbers", + "doc": { + "/": 9, + "~1": 10 + }, + "patch": [{"op": "test", "path": "/~01", "value": "10"}], + "error": "number is not equal to string" + }, + + { + "comment": "A.16. Adding an Array Value", + "doc": { + "foo": ["bar"] + }, + "patch": [{ "op": "add", "path": "/foo/-", "value": ["abc", "def"] }], + "expected": { + "foo": ["bar", ["abc", "def"]] + } + } + +] diff --git a/test/data/json-patch-tests/tests.json b/test/data/json-patch-tests/tests.json new file mode 100755 index 00000000..86305c16 --- /dev/null +++ b/test/data/json-patch-tests/tests.json @@ -0,0 +1,434 @@ +[ + { "comment": "empty list, empty docs", + "doc": {}, + "patch": [], + "expected": {} }, + + { "comment": "empty patch list", + "doc": {"foo": 1}, + "patch": [], + "expected": {"foo": 1} }, + + { "comment": "rearrangements OK?", + "doc": {"foo": 1, "bar": 2}, + "patch": [], + "expected": {"bar":2, "foo": 1} }, + + { "comment": "rearrangements OK? How about one level down ... array", + "doc": [{"foo": 1, "bar": 2}], + "patch": [], + "expected": [{"bar":2, "foo": 1}] }, + + { "comment": "rearrangements OK? How about one level down...", + "doc": {"foo":{"foo": 1, "bar": 2}}, + "patch": [], + "expected": {"foo":{"bar":2, "foo": 1}} }, + + { "comment": "add replaces any existing field", + "doc": {"foo": null}, + "patch": [{"op": "add", "path": "/foo", "value":1}], + "expected": {"foo": 1} }, + + { "comment": "toplevel array", + "doc": [], + "patch": [{"op": "add", "path": "/0", "value": "foo"}], + "expected": ["foo"] }, + + { "comment": "toplevel array, no change", + "doc": ["foo"], + "patch": [], + "expected": ["foo"] }, + + { "comment": "toplevel object, numeric string", + "doc": {}, + "patch": [{"op": "add", "path": "/foo", "value": "1"}], + "expected": {"foo":"1"} }, + + { "comment": "toplevel object, integer", + "doc": {}, + "patch": [{"op": "add", "path": "/foo", "value": 1}], + "expected": {"foo":1} }, + + { "comment": "Toplevel scalar values OK?", + "doc": "foo", + "patch": [{"op": "replace", "path": "", "value": "bar"}], + "expected": "bar", + "disabled": true }, + + { "comment": "replace object document with array document?", + "doc": {}, + "patch": [{"op": "add", "path": "", "value": []}], + "expected": [] }, + + { "comment": "replace array document with object document?", + "doc": [], + "patch": [{"op": "add", "path": "", "value": {}}], + "expected": {} }, + + { "comment": "append to root array document?", + "doc": [], + "patch": [{"op": "add", "path": "/-", "value": "hi"}], + "expected": ["hi"] }, + + { "comment": "Add, / target", + "doc": {}, + "patch": [ {"op": "add", "path": "/", "value":1 } ], + "expected": {"":1} }, + + { "comment": "Add, /foo/ deep target (trailing slash)", + "doc": {"foo": {}}, + "patch": [ {"op": "add", "path": "/foo/", "value":1 } ], + "expected": {"foo":{"": 1}} }, + + { "comment": "Add composite value at top level", + "doc": {"foo": 1}, + "patch": [{"op": "add", "path": "/bar", "value": [1, 2]}], + "expected": {"foo": 1, "bar": [1, 2]} }, + + { "comment": "Add into composite value", + "doc": {"foo": 1, "baz": [{"qux": "hello"}]}, + "patch": [{"op": "add", "path": "/baz/0/foo", "value": "world"}], + "expected": {"foo": 1, "baz": [{"qux": "hello", "foo": "world"}]} }, + + { "doc": {"bar": [1, 2]}, + "patch": [{"op": "add", "path": "/bar/8", "value": "5"}], + "error": "Out of bounds (upper)" }, + + { "doc": {"bar": [1, 2]}, + "patch": [{"op": "add", "path": "/bar/-1", "value": "5"}], + "error": "Out of bounds (lower)" }, + + { "doc": {"foo": 1}, + "patch": [{"op": "add", "path": "/bar", "value": true}], + "expected": {"foo": 1, "bar": true} }, + + { "doc": {"foo": 1}, + "patch": [{"op": "add", "path": "/bar", "value": false}], + "expected": {"foo": 1, "bar": false} }, + + { "doc": {"foo": 1}, + "patch": [{"op": "add", "path": "/bar", "value": null}], + "expected": {"foo": 1, "bar": null} }, + + { "comment": "0 can be an array index or object element name", + "doc": {"foo": 1}, + "patch": [{"op": "add", "path": "/0", "value": "bar"}], + "expected": {"foo": 1, "0": "bar" } }, + + { "doc": ["foo"], + "patch": [{"op": "add", "path": "/1", "value": "bar"}], + "expected": ["foo", "bar"] }, + + { "doc": ["foo", "sil"], + "patch": [{"op": "add", "path": "/1", "value": "bar"}], + "expected": ["foo", "bar", "sil"] }, + + { "doc": ["foo", "sil"], + "patch": [{"op": "add", "path": "/0", "value": "bar"}], + "expected": ["bar", "foo", "sil"] }, + + { "comment": "push item to array via last index + 1", + "doc": ["foo", "sil"], + "patch": [{"op":"add", "path": "/2", "value": "bar"}], + "expected": ["foo", "sil", "bar"] }, + + { "comment": "add item to array at index > length should fail", + "doc": ["foo", "sil"], + "patch": [{"op":"add", "path": "/3", "value": "bar"}], + "error": "index is greater than number of items in array" }, + + { "comment": "test against implementation-specific numeric parsing", + "doc": {"1e0": "foo"}, + "patch": [{"op": "test", "path": "/1e0", "value": "foo"}], + "expected": {"1e0": "foo"} }, + + { "comment": "test with bad number should fail", + "doc": ["foo", "bar"], + "patch": [{"op": "test", "path": "/1e0", "value": "bar"}], + "error": "test op shouldn't get array element 1" }, + + { "doc": ["foo", "sil"], + "patch": [{"op": "add", "path": "/bar", "value": 42}], + "error": "Object operation on array target" }, + + { "doc": ["foo", "sil"], + "patch": [{"op": "add", "path": "/1", "value": ["bar", "baz"]}], + "expected": ["foo", ["bar", "baz"], "sil"], + "comment": "value in array add not flattened" }, + + { "doc": {"foo": 1, "bar": [1, 2, 3, 4]}, + "patch": [{"op": "remove", "path": "/bar"}], + "expected": {"foo": 1} }, + + { "doc": {"foo": 1, "baz": [{"qux": "hello"}]}, + "patch": [{"op": "remove", "path": "/baz/0/qux"}], + "expected": {"foo": 1, "baz": [{}]} }, + + { "doc": {"foo": 1, "baz": [{"qux": "hello"}]}, + "patch": [{"op": "replace", "path": "/foo", "value": [1, 2, 3, 4]}], + "expected": {"foo": [1, 2, 3, 4], "baz": [{"qux": "hello"}]} }, + + { "doc": {"foo": [1, 2, 3, 4], "baz": [{"qux": "hello"}]}, + "patch": [{"op": "replace", "path": "/baz/0/qux", "value": "world"}], + "expected": {"foo": [1, 2, 3, 4], "baz": [{"qux": "world"}]} }, + + { "doc": ["foo"], + "patch": [{"op": "replace", "path": "/0", "value": "bar"}], + "expected": ["bar"] }, + + { "doc": [""], + "patch": [{"op": "replace", "path": "/0", "value": 0}], + "expected": [0] }, + + { "doc": [""], + "patch": [{"op": "replace", "path": "/0", "value": true}], + "expected": [true] }, + + { "doc": [""], + "patch": [{"op": "replace", "path": "/0", "value": false}], + "expected": [false] }, + + { "doc": [""], + "patch": [{"op": "replace", "path": "/0", "value": null}], + "expected": [null] }, + + { "doc": ["foo", "sil"], + "patch": [{"op": "replace", "path": "/1", "value": ["bar", "baz"]}], + "expected": ["foo", ["bar", "baz"]], + "comment": "value in array replace not flattened" }, + + { "comment": "replace whole document", + "doc": {"foo": "bar"}, + "patch": [{"op": "replace", "path": "", "value": {"baz": "qux"}}], + "expected": {"baz": "qux"} }, + + { "comment": "test replace with missing parent key should fail", + "doc": {"bar": "baz"}, + "patch": [{"op": "replace", "path": "/foo/bar", "value": false}], + "error": "replace op should fail with missing parent key" }, + + { "comment": "spurious patch properties", + "doc": {"foo": 1}, + "patch": [{"op": "test", "path": "/foo", "value": 1, "spurious": 1}], + "expected": {"foo": 1} }, + + { "doc": {"foo": null}, + "patch": [{"op": "test", "path": "/foo", "value": null}], + "comment": "null value should be valid obj property" }, + + { "doc": {"foo": null}, + "patch": [{"op": "replace", "path": "/foo", "value": "truthy"}], + "expected": {"foo": "truthy"}, + "comment": "null value should be valid obj property to be replaced with something truthy" }, + + { "doc": {"foo": null}, + "patch": [{"op": "move", "from": "/foo", "path": "/bar"}], + "expected": {"bar": null}, + "comment": "null value should be valid obj property to be moved" }, + + { "doc": {"foo": null}, + "patch": [{"op": "copy", "from": "/foo", "path": "/bar"}], + "expected": {"foo": null, "bar": null}, + "comment": "null value should be valid obj property to be copied" }, + + { "doc": {"foo": null}, + "patch": [{"op": "remove", "path": "/foo"}], + "expected": {}, + "comment": "null value should be valid obj property to be removed" }, + + { "doc": {"foo": "bar"}, + "patch": [{"op": "replace", "path": "/foo", "value": null}], + "expected": {"foo": null}, + "comment": "null value should still be valid obj property replace other value" }, + + { "doc": {"foo": {"foo": 1, "bar": 2}}, + "patch": [{"op": "test", "path": "/foo", "value": {"bar": 2, "foo": 1}}], + "comment": "test should pass despite rearrangement" }, + + { "doc": {"foo": [{"foo": 1, "bar": 2}]}, + "patch": [{"op": "test", "path": "/foo", "value": [{"bar": 2, "foo": 1}]}], + "comment": "test should pass despite (nested) rearrangement" }, + + { "doc": {"foo": {"bar": [1, 2, 5, 4]}}, + "patch": [{"op": "test", "path": "/foo", "value": {"bar": [1, 2, 5, 4]}}], + "comment": "test should pass - no error" }, + + { "doc": {"foo": {"bar": [1, 2, 5, 4]}}, + "patch": [{"op": "test", "path": "/foo", "value": [1, 2]}], + "error": "test op should fail" }, + + { "comment": "Whole document", + "doc": { "foo": 1 }, + "patch": [{"op": "test", "path": "", "value": {"foo": 1}}], + "disabled": true }, + + { "comment": "Empty-string element", + "doc": { "": 1 }, + "patch": [{"op": "test", "path": "/", "value": 1}] }, + + { "doc": { + "foo": ["bar", "baz"], + "": 0, + "a/b": 1, + "c%d": 2, + "e^f": 3, + "g|h": 4, + "i\\j": 5, + "k\"l": 6, + " ": 7, + "m~n": 8 + }, + "patch": [{"op": "test", "path": "/foo", "value": ["bar", "baz"]}, + {"op": "test", "path": "/foo/0", "value": "bar"}, + {"op": "test", "path": "/", "value": 0}, + {"op": "test", "path": "/a~1b", "value": 1}, + {"op": "test", "path": "/c%d", "value": 2}, + {"op": "test", "path": "/e^f", "value": 3}, + {"op": "test", "path": "/g|h", "value": 4}, + {"op": "test", "path": "/i\\j", "value": 5}, + {"op": "test", "path": "/k\"l", "value": 6}, + {"op": "test", "path": "/ ", "value": 7}, + {"op": "test", "path": "/m~0n", "value": 8}] }, + + { "comment": "Move to same location has no effect", + "doc": {"foo": 1}, + "patch": [{"op": "move", "from": "/foo", "path": "/foo"}], + "expected": {"foo": 1} }, + + { "doc": {"foo": 1, "baz": [{"qux": "hello"}]}, + "patch": [{"op": "move", "from": "/foo", "path": "/bar"}], + "expected": {"baz": [{"qux": "hello"}], "bar": 1} }, + + { "doc": {"baz": [{"qux": "hello"}], "bar": 1}, + "patch": [{"op": "move", "from": "/baz/0/qux", "path": "/baz/1"}], + "expected": {"baz": [{}, "hello"], "bar": 1} }, + + { "doc": {"baz": [{"qux": "hello"}], "bar": 1}, + "patch": [{"op": "copy", "from": "/baz/0", "path": "/boo"}], + "expected": {"baz":[{"qux":"hello"}],"bar":1,"boo":{"qux":"hello"}} }, + + { "comment": "replacing the root of the document is possible with add", + "doc": {"foo": "bar"}, + "patch": [{"op": "add", "path": "", "value": {"baz": "qux"}}], + "expected": {"baz":"qux"}}, + + { "comment": "Adding to \"/-\" adds to the end of the array", + "doc": [ 1, 2 ], + "patch": [ { "op": "add", "path": "/-", "value": { "foo": [ "bar", "baz" ] } } ], + "expected": [ 1, 2, { "foo": [ "bar", "baz" ] } ]}, + + { "comment": "Adding to \"/-\" adds to the end of the array, even n levels down", + "doc": [ 1, 2, [ 3, [ 4, 5 ] ] ], + "patch": [ { "op": "add", "path": "/2/1/-", "value": { "foo": [ "bar", "baz" ] } } ], + "expected": [ 1, 2, [ 3, [ 4, 5, { "foo": [ "bar", "baz" ] } ] ] ]}, + + { "comment": "test remove with bad number should fail", + "doc": {"foo": 1, "baz": [{"qux": "hello"}]}, + "patch": [{"op": "remove", "path": "/baz/1e0/qux"}], + "error": "remove op shouldn't remove from array with bad number" }, + + { "comment": "test remove on array", + "doc": [1, 2, 3, 4], + "patch": [{"op": "remove", "path": "/0"}], + "expected": [2, 3, 4] }, + + { "comment": "test repeated removes", + "doc": [1, 2, 3, 4], + "patch": [{ "op": "remove", "path": "/1" }, + { "op": "remove", "path": "/2" }], + "expected": [1, 3] }, + + { "comment": "test remove with bad index should fail", + "doc": [1, 2, 3, 4], + "patch": [{"op": "remove", "path": "/1e0"}], + "error": "remove op shouldn't remove from array with bad number" }, + + { "comment": "test replace with bad number should fail", + "doc": [""], + "patch": [{"op": "replace", "path": "/1e0", "value": false}], + "error": "replace op shouldn't replace in array with bad number" }, + + { "comment": "test copy with bad number should fail", + "doc": {"baz": [1,2,3], "bar": 1}, + "patch": [{"op": "copy", "from": "/baz/1e0", "path": "/boo"}], + "error": "copy op shouldn't work with bad number" }, + + { "comment": "test move with bad number should fail", + "doc": {"foo": 1, "baz": [1,2,3,4]}, + "patch": [{"op": "move", "from": "/baz/1e0", "path": "/foo"}], + "error": "move op shouldn't work with bad number" }, + + { "comment": "test add with bad number should fail", + "doc": ["foo", "sil"], + "patch": [{"op": "add", "path": "/1e0", "value": "bar"}], + "error": "add op shouldn't add to array with bad number" }, + + { "comment": "missing 'value' parameter to add", + "doc": [ 1 ], + "patch": [ { "op": "add", "path": "/-" } ], + "error": "missing 'value' parameter" }, + + { "comment": "missing 'value' parameter to replace", + "doc": [ 1 ], + "patch": [ { "op": "replace", "path": "/0" } ], + "error": "missing 'value' parameter" }, + + { "comment": "missing 'value' parameter to test", + "doc": [ null ], + "patch": [ { "op": "test", "path": "/0" } ], + "error": "missing 'value' parameter" }, + + { "comment": "missing value parameter to test - where undef is falsy", + "doc": [ false ], + "patch": [ { "op": "test", "path": "/0" } ], + "error": "missing 'value' parameter" }, + + { "comment": "missing from parameter to copy", + "doc": [ 1 ], + "patch": [ { "op": "copy", "path": "/-" } ], + "error": "missing 'from' parameter" }, + + { "comment": "missing from parameter to move", + "doc": { "foo": 1 }, + "patch": [ { "op": "move", "path": "" } ], + "error": "missing 'from' parameter" }, + + { "comment": "duplicate ops", + "doc": { "foo": "bar" }, + "patch": [ { "op": "add", "path": "/baz", "value": "qux", + "op": "move", "from":"/foo" } ], + "error": "patch has two 'op' members", + "disabled": true }, + + { "comment": "unrecognized op should fail", + "doc": {"foo": 1}, + "patch": [{"op": "spam", "path": "/foo", "value": 1}], + "error": "Unrecognized op 'spam'" }, + + { "comment": "test with bad array number that has leading zeros", + "doc": ["foo", "bar"], + "patch": [{"op": "test", "path": "/00", "value": "foo"}], + "error": "test op should reject the array value, it has leading zeros" }, + + { "comment": "test with bad array number that has leading zeros", + "doc": ["foo", "bar"], + "patch": [{"op": "test", "path": "/01", "value": "bar"}], + "error": "test op should reject the array value, it has leading zeros" }, + + { "comment": "Removing nonexistent field", + "doc": {"foo" : "bar"}, + "patch": [{"op": "remove", "path": "/baz"}], + "error": "removing a nonexistent field should fail" }, + + { "comment": "Removing nonexistent index", + "doc": ["foo", "bar"], + "patch": [{"op": "remove", "path": "/2"}], + "error": "removing a nonexistent index should fail" }, + + { "comment": "Patch with different capitalisation than doc", + "doc": {"foo":"bar"}, + "patch": [{"op": "add", "path": "/FOO", "value": "BAR"}], + "expected": {"foo": "bar", "FOO": "BAR"} + } + +] diff --git a/test/src/unit-json_patch.cpp b/test/src/unit-json_patch.cpp index 15f3d015..782853ad 100644 --- a/test/src/unit-json_patch.cpp +++ b/test/src/unit-json_patch.cpp @@ -31,6 +31,8 @@ SOFTWARE. #include "json.hpp" using nlohmann::json; +#include + TEST_CASE("JSON patch") { SECTION("examples from RFC 6902") @@ -1250,4 +1252,42 @@ TEST_CASE("JSON patch") R"( [{"op": "test", "path": "/foo", "value": "bar"}] )"_json)); } } + + SECTION("Tests from github.com/json-patch/json-patch-tests") + { + for (auto filename : + {"test/data/json-patch-tests/spec_tests.json", + "test/data/json-patch-tests/tests.json" + }) + { + CAPTURE(filename); + std::ifstream f(filename); + json suite = json::parse(f); + + for (const auto& test : suite) + { + CAPTURE(test.value("comment", "")) + + // skip tests marked as disabled + if (test.value("disabled", false)) + { + continue; + } + + const auto& doc = test["doc"]; + const auto& patch = test["patch"]; + + if (test.count("error") == 0) + { + // if an expected value is given, use it; use doc otherwise + const auto& expected = test.value("expected", doc); + CHECK(doc.patch(patch) == expected); + } + else + { + CHECK_THROWS(doc.patch(patch)); + } + } + } + } } diff --git a/test/src/unit-regression.cpp b/test/src/unit-regression.cpp index a24ff539..1a93db28 100644 --- a/test/src/unit-regression.cpp +++ b/test/src/unit-regression.cpp @@ -1322,4 +1322,32 @@ TEST_CASE("regression tests") j = ar; ar = j; } + + SECTION("issue #894 - invalid RFC6902 copy operation succeeds") + { + auto model = R"({ + "one": { + "two": { + "three": "hello", + "four": 42 + } + } + })"_json; + + CHECK_THROWS_AS(model.patch(R"([{"op": "move", + "from": "/one/two/three", + "path": "/a/b/c"}])"_json), json::out_of_range); + CHECK_THROWS_WITH(model.patch(R"([{"op": "move", + "from": "/one/two/three", + "path": "/a/b/c"}])"_json), + "[json.exception.out_of_range.403] key 'a' not found"); + + CHECK_THROWS_AS(model.patch(R"([{"op": "copy", + "from": "/one/two/three", + "path": "/a/b/c"}])"_json), json::out_of_range); + CHECK_THROWS_WITH(model.patch(R"([{"op": "copy", + "from": "/one/two/three", + "path": "/a/b/c"}])"_json), + "[json.exception.out_of_range.403] key 'a' not found"); + } } From 3c76ff353da7b30fa7265e8794b08bd3731cf9c2 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Fri, 29 Dec 2017 16:52:09 +0100 Subject: [PATCH 24/59] :memo: updated docs after PRs --- README.md | 3 ++- doc/avatars.png | Bin 543063 -> 570573 bytes 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 684161d5..c400ade1 100644 --- a/README.md +++ b/README.md @@ -915,6 +915,7 @@ I deeply appreciate the help of the following people. - [Jorrit Wronski](https://github.com/jowr) updated the Hunter package links. - [Matthias Möller](https://github.com/TinyTinni) added a `.natvis` for the MSVC debug view. - [bogemic](https://github.com/bogemic) fixed some C++17 deprecation warnings. +- [Eren Okka](https://github.com/erengy) fixed some MSVC warnings. Thanks a lot for helping out! Please [let me know](mailto:mail@nlohmann.me) if I forgot someone. @@ -977,7 +978,7 @@ $ mkdir build $ cd build $ cmake .. $ cmake --build . -$ ctest +$ ctest --output-on-failure ``` For more information, have a look at the file [.travis.yml](https://github.com/nlohmann/json/blob/master/.travis.yml). diff --git a/doc/avatars.png b/doc/avatars.png index b416a2854c9485ea1afa5204e8599075d1595bb6..45513172998a55108961d31070ffd0820c7e7bc3 100644 GIT binary patch literal 570573 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

PC72#ie- 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

!{dZpdV-a1(fo&qz#s%_t)i$*Ldo38*^}kG z?^c(rNpzzzw0^3lH`CAIJCNYm~v4og|+evuDRUbdpY~fzxdT( z`RrHjX#j}T)~WgVq3y2$aw0@9gw`SmW_Ij^Kmg&Gbm(2YcS{~(DoeM%`h|m~g(&nk zt!r*tKaQ-hxXv%9Uz<#Fa%fzSPyXG!IS^(J@5Iu_q=;`>6ouD2gTL_ z#=supqsSiwP#~^AR=_zxvAj8F+I*gHB?^5aPEDR$WWYk93lY6Q8_Ri`N(r65lR^QY zH3peIApnTkRyBtxbEe}i>g7m~Ev+uK7TSx0^!e9aJ~Z0AAxZCj;4!B}P%EGA#sgxq zS+!JR8I13_!Vf|_$c0h`VZ}NF07@x9Hpa1IYpt=?ktiI>15a9_G|ie7EtT|rvLv^ZX8NA{9!lEnbt5B8-0SxPiA*lb@{-n>O$R*)WevP^lUUub zp*&~2m1B#8&dT=9nuYAaTSll(!!b1(EHFA_qY0K;OR?uC}fci60PM6U--NiKL2uv2Vg7|jECX@@*|x5s#nsN@(n^v!M;zx)NoZC|+t!Z+9wzNJFbBT> zkM|#)>t-*$aN?nbQ}mqnx*$i+QPGFzd!ZJ{M48E@kWt`QN`cLl5)=;-1eOR0XiYAq z45KK^O`0ZIn)C<#T778a)YPd{rw;eJwMJtQ_lCws8ug*h%Ifm+lIQDMtywOYd%a#1 zgi*TAK5*W_fa3~HFNu}dFu9RL!sP($3+b%2?3^O>gD4DyKqe&O z+!$j?Y3&DE34vghWr0}o6^5lk5>5(%5&*%u3{fyU=QxlWjP?Df+wIsa6@e`JPz$o{ zIodn313;-%zt{TYM?U`J|Mq7bIjwzX9SVU`3ov<}8)Jn)cJ9i{F50?#*Sp^JS9|yF zfwL_5B0ugN3FW=x?>=o#Jy6>7z1d?Q&EhU>xMtzhedgY`bL$}l6e7^dUtNCW&;R^g zfBDWoc=X_j-};lkUR*l;6F>5OJ9lkcU1=K|D=8(4EXj;>VaZ>dpZUZmKRn-0U;er` zPpunYZM9JdEfi~w>A;qOAir2Xkg7O0fj&b)Tq{>)xYKH3qJq$Uw!pY|JQ}3 zmCYMB?YVGg*^lPu7w=|JCk-vER`1WniSt%&P^T$0RtyVN<<9Y>9$8l#{i+%?`L_|Xg22N7h0|Mh7D81FzELO zgMkqExzByB+wER@>7|uQb!uvgnCp#txl&qQS!uObd;M;?QVBd?Dz&<@VvQYY4uxTf z$farQ`+mXNUN=7R@S~3yV~XCpV!`tq=)e;~I%g)TUMr)1GB7Sj=F{`bygE(P2TDX*42&}w)qHITEmM1V<9OPsbm#NIfJ)=z+hm%yzfM6 z?NbVP0Bfx_=a21~NJ#PTf8k$mzx|89`qK3_9iRgwD^vrdfz15GwqRzUJt9Uah>2{` z@I&mB@Ej5v<&|+Z#{Y2J?8@$o|M2gB`-NA%9014>Ab(?yvu^|VO@OOGtZHtTWXJGA z$1Tj+WYs~&UBg+H*D4? zQa7u3#p9efx9l;@I#?Z8hzSM+J%&|+0RsX&n!}2N3p{8FAO;Db1%wD?RO?jZj7+|P zBm6GDJ6VsmK~g%U zL%O>=q(c}j0@5WN(kb2D-Cf`N?GM;>?b`Od_x+r6ey2v4ZcIBt#iI?J)Z5c*0_x&B zWGd~bNx=+Zk1+kQ&0ga&YPDThRi-`|v!j{erkR%cV3aef_$E6VZ$q@)WDEc4`(}4F zeB2ip9Nl|5gzrd=3%~57=H72w&{S~A4Cmur1r<`NJ~N=XbnArKkE*$`-6H&s=98U+V}n7lKTbEu)9 zJ&-r+pWOhTRwmo2gP_khJ*-O}=RK)}iP_Hpa2Nw6lA%DoXlG2&aSQs$kG)lk@M&b+ zCHrpco3E0`NT~s$VYF;?1RU325B$=e;ld=j$tylKKOel;7DLLf&Jz6=^p{rH6Qww^ zceY+Mah$7Y@WOP?R;jx?=&EJf6|>3gD0x>tWNVdHg-@aIRspoRHtrTR(Epk znf2M+!otGc9UoI#N=pAcQo|eI(3tE1z7b&Z_SzlI8X6h`nht_G4S_3iko|cN-v2ZB zYoJ&Nc(?;WevBORDdrdtKcId8{OrfruF$2C&(Ll5u18KC`@Kv}CpnU=cfH+oGGzs6 zL5L>WCRjLJE6B1F1UJf%-EJ-iKNsJ45JHy z&NL=ZPt#p|6pr3Z3wZ7rs>w_bhYJA87PmZp))mzb$4JteM;n)DSa++*fA1CK3+S@{ z+_X6#;E&pD9w4^nabXG$mT)*pTR;Y1{wH+4ZYx2Ryp>^MY}Ym-?48;x-Oc8;%# z_dyc5_ytO0UL0fpW?=~vxrS!+?y_FUajwvFWn`GjulBa?dpcW4Y|6N;_9{98ij16k(WdjOZ^or*%ssnY4%OAXC z9MFS}3ZFI`81jc+SG|7v6{i9MTx1mzj@sctGG55EiN~^p(~h&fiKzEe!2A%4ej5jK z5j_4dGknEYHmkpHSbdI9Je_z;ru=r=!r}lj@9EZB|M_TL+n(HOK;dK`UWzvXu~3_c z+lt@)8?T+Ftlz8i%jjU5ERqF3`}1lN6)~4b#MD@Hp7w{gw=AReHQLCXvt z8mSuU2c?YKLmjLhRM?AZNpI8(q=oPQHt5$o4NJoa%N1=`_ZVdx;Y6_f<;bZnwKCW! z&`iFLYuz+4uP)%}Hy|(B%6v7Jw?f~RrN1gEmXB2w5EgkOCQuXZL&#YIRJYIzfxsEM2nD1kO81#m0kmtalN<`W&{O(l{Okx4; z&KO;_14YFCW@!5!%{_p7h8>OyPp?P}Vqk4n8R;)03kN()t(oGD5s=g&!{3SaDn*Qt zw)}4XEM&q_e9PpjO1T3s#qEy4a!-MjlQ|OMAIps^ExgQwtpIq zoWLSTpR1-|P%8j|3MCw6B$RkRR=$%9Hi{t8F$a$r{Sq`Fvd;GQshr!e+zGGnO2&uX z%Wd2b?UgNo}Tq87vXbSliHT^Os2hZ z_}}z|?>lnEqgvl7mR!Hv_x8v`EDd^RoxpYl#6mM_o1cZ!c_HFo!}AiL3DDn89%hr& zm@}C9WJnSHSce$ILfkSn6{i8+Yhf>kc1z1c!>sL_oQvgiXev1fw4=x<`3M!X-gI3* z#4^|vJ?B1ks5+ViSF7##kW4e`G`#&;1bEo5v+%wxH+nf)Bg&7CqJofI$tR|0KSk9+ zKfzw6TBW5J#(x;J6xA%a(l&IjV4s9lP!&Z$#5%A&Mhu*ISAE+=&yN+$cyWb~=-V?R zs72Ng<8Mo$gmlZ#MD(5A4jU%mBVjeMHt zblO^~#ESA*v37}|piA{vXe6Gt`f#|EvpROUq)ikmnsTL6rmjhk9Gi@@a9MYQ$WU0T zE(D>$c~A~kQIaxOeKk+!96R_dye%@$$GO)B+r6$4%^*ryLl^jpY!W^Fi^em9T6w+b zeSsPQe_6q97$93b(?#a}`u&kvGB3HJl?z>v_Nwqo@Xd^6&%`CZOrD`gSg>56_@@~x zG*D-n^W%8vxdbHDoZ&ZHwW0UKMBF@ur$jKr!^UpgRmtoUf8#fuhD9Jv7$OC-j!44{ zDf-JaR>S3WeAxDS>-Wra+H_f}q35QM@)Oj7E`}OW`Da4Ny$_F^?g#Sf=>~4yY2O4c z@h}^HhkqyB+h{}yLHD%);g`}lpCis}pYiL|r!K|koPpfw1IuHoY8vB#Un0mxcW<+w zfnv`6Hv%jz>w}Dl6NYSOwa6XXa_Hdi45D=K);K~kZ^DQBbKr0S8E}t5xx1n%j#lD7 z3i;m3djj|bfK9JoYi;dR>uu=Uri^l7^GD@^h7t}7ldqq7Yjn$G0ti-2Omi)-BjuNt z5(L!IUIZo<;iW8+tcqwM3SaKNZVu`g{EZF1OMRCBR7C=@{A0>I)uPXwswumv1`Zyr z>dl+6tjM`Me0=oDOtd{+aR`8x?E!OZUiQpaW=NKYA&XYJ9M&gqC)+l-^`)NdISUA1 zs|uS&SIv;}JLl+E7`RMN14BWwT+gkKb(zW_pGMgXh&*;va4d>;{QMk<>S81fDno;3 zb|i2l$1g4}wwhe>jq~r@S{9Fi#1y_*M8A;f%X5?a0?L(*|CI}m!4IiyGiu-ZPu*NR zxhcz2$=+27^DiJJCE*bo21Qgc{g@HWf=^h@1XmnHp4AklR?GfS0>`fV+>yhHS`ACJ zBete^~HGgvl;Zhu<7H&g&xyYmjA6uJ0;f>sy;Ak0;Q|!csk4fdU z&}wR!w4>JX^)b=#?}j7L_mf=Kcx$G~%COf6l909>n%fa*=^f{Y7_wf=+ez+t2bF@#D7cr2Rk9H43&^Sd?FnL~$V^e)-^ac*xQ(>m@c3=d`rc^3fp>{1y)Ua9h~OLp zrTLwm=QH@=Nsv)QM)%f+|I%*}0>3E%3ruti1te^!6$HaDB{A?N$T-uHO%1w&1Tg?sChBP*I^T zPU7I5UdM5%-prpK#cHAw#=mR2_iBrfg8t~zbH;O)!4xEuE)LQZ`GQz$LeV%SN9RkdkSj%$JVXZMWPmI#K24_* z>QK-|fgYHH|RE z>Zh!&O~Q_Y<^|l=0%ZyTbX~WOlprlq1RDg>%~eAQ?*M;~+LzM$H|_(+WHdl6$bf3i*^u}`#ta9j)VjSS6*!|$XK(4nBRLV zG5evGED8VLmhIupH?e*(#0Q6Gd?YCoLmJbD+3YNV{Ey${W9fo#I5q=+U7aiX?sP{a zdaKmg|;RbRw##`dK?O)`=k~fwMuR&i(b}0q%^)eS-Au?>0XB_13#21ch^< zv&lCG;d$hBnafWDkEXn*j|RxTnu()`@y^sia)5;Z)qfa68OG-`we3-?a{Zj6Qc`Vb z9$g_}ZaQw}0Yz%t&BgVwEmUC$C;p*Qhlyx9c3W08`rXj%>!D4t8iR*#%Fgi$c>_Uw zGMz%kR_~p1<&l?YG_1Q zn3xnS9s}>xd`v{__&|zHQ}R`s*OCU+CDD&DX)b z`BVx_HgoH_hb{qD_OJl>b!>b2eV%&1zc+0L!2B% zqfETW-M^D?_Aq70lCk&)qHkJrR0x>r3ZS7&Rq2z-zf{UUxE{5U+cqqseJX40skTz7 zm!b6=VKivuwJ?RHwBebD?wU&@CvQF5h2wiu zP9lRQ-@T9u;`Y-U_~myCY{mL77bM1sfEDtF`llc_YMH6qNa;;?m#~BLO%;`!u&eXQ z@RFQ0P2=`P6uVO#Om|-R<80LApLPkU%mu%VdyTj_4GnItjffr1k=uHCTjo^m)S#P_ z2MNDkfl`6oXWZa&4A-MXgvtU#%W&uE5M1R-bJ~eb?pb-51ZELJb=d z(q@aVKCasz@J^R}=6gp#m28~1HFhuSZ?HFeqVHhBetkfgr_RAg|UO!eLzBtmbRj=83q-O79cuZ3|U zbTh{y0+&;VZ2n#k=U0*l6#eK^>%!qeRFUhFH#-XpYGRPYU=|$~X%t#=i85t|mdp~3 z1JD7uVf;4Qpryuj&%)X_{@<7jB#X1s`{z!vM*EW#1m5iD(i~G_IFrbCkqG%{reK`# zemWGb9GpG0!_1)#(XPVpG03(4U__8)V_+s^*o_aAt zcb)aip0m~=>PiC@E;x_Q5W$**S%PMw@ZTkuim1l@Ld_8e2mBDzSTm0KgXemLL~-^$ z2G!6J%oh)x+ttiaIid*n42VbxHkwv$J;tB%5dMwv^zhsnrolVH2;3X3@TP&}ov;5C z)78};MJJ#XOYWA1?v44rpb^&XMhsL*6>Dp0YBCS7)x?Grr?jqHneI#xYz~uuc08o+ z>LKFMZ#Qpt*w?kLQ%3phHu9B}!8M`#Olbrw3nmnQTQea;(h>D|u2hq5rUla(<%Rep zYUTcOJV6|nD@`qc2kY+BwEDgty4IsmV6Eq}mSTmLbRK;rDnI~#2O2^-5+&)>{^Bcj zo5y<6eqMZ@=uguSu=<9iucf4YQ`mM^ZSi8l@28y{y45dLNf5}yG*FOaG%=tZ)s`at znKfI;^P$MVY5Ho(${*v4EE>}U@oveHqK>WfnqUzx5-qP?=*D4h!zy(ey)0eqm`=y0 zU=fqo0j`|Pz=SF7NFvi%KOcoDK9V*Hf|;Y-02^d6>tyLDv&b7x1!6e>7jSBA9Bqt- z{%ot`RmqOP7GcwA&zr!wMLQ{A+1>YD$LRZ=-&r*|IkN|Hx=m!->i zh(ePK@GOL{f*{HP5?^i6-+ZyIdEhBAonpWTh-C90kbCAwcn~PB-x8I++WD;W)^81O<%TTzBKSLk zh5QCeVNim@DBLH-HxpNZdIE0xz5p-n)UKlSg`YwVMkL}Yp}$4qeb*h>z`4XNTJx5J z1{8}N2KNy(@Es0MU&|jNjX~CS32XMf-}SSY?2UQWU*%U)!QwNMQWGCp$d41c2zdLF zwfd|5!b@M{+th~18WYM_iSKf`ptov;DxW~&AQ7x!uqdigW}-i;7CThnjeiP-%M#gC z$+n(Ok&yG_Gws+<^HjmH)oKUt<-ILEz-drmcCp|vD0RDAB4vwcn z)@9|=>Dnn(RieNSVb>!~%nHl0s05t^YT$ZsNQIV^fQUJnG5l98lK=JL?5;-}utWe9 zq4vwymdhxErw!OgFQ9HG=^~WKmQFnyq_kIuN`XqiZpMQCd4gK&upFCCi9FD0^wvl5 zfA~;pmlFN|L7F5K~FxR zjakDQ%$j`l4t}dQM4LA-p-5xG`9qBqm@i1}PSyPdATN88Sa!5AMh*Y)E?aK+ezkp?ue0eOqz*E$(x$PJPS>ndS5%qt4&8 z9hZkel#i&>!AKu-sq<04%KVi}KG9@({!uafx+48DcH4F(JqMTj*xPgh3tvS5`G*CZ z%I!-Gb>{Va*~p^-LT-j2L8e@^O0mi{!*Q{$985}t2`G6j2@`KWL@+o56avNCO2Gaa z%6e2JpqQakf1uOwIITpixWpAC;oSnu#Qd$z`%M&H^NlHBaEA*5ok6wHhcHsq+&Ww( z8T^YFb-jLdb0($2IXbT5i$7#T3t>3i}TT9S%*?qWuwKlZ0 zUm>Ib^N;@at=l@YJwH z`iHztL7ps}(p)>HhDR-1`p*f!)EFc&GnplF$)Oj&g~4DsLnNkA3Q-E@#+}9Ho7}t} z4IGYiZga!On=9==0`~u zrKLktH84_#-We0i8Ccn;6b1u#RDTXvn)M$h@LFHq2wO~SJxRpZVExlR^rJkz5kLx0 zGOb_58x}E$)45NI2_Q(uYJ06^$DrJ8Ez9tV1yi|LCUi0)tF;ppcibm?1y810A zJ*!CWw-wAISd)+l4)-BA=R$C2LN(Gm`j`K54apKDq>gqV%W3a1xhf(HK&S1wr53#v z?5Bl?t23K~yOVpfVQW{F56a>!986i-vdp*(AVbKV5+(idxj|aKP8-o28c^Gv8J;$% z{ENnQ^Cc&n15@BDPS#7LLpphG0g{wC35>ZjvIdUTiGlz;tajC(CsJvmDwpsZXc*(B zG}8(VXJlkFAI;R#*7kfpG-&_x=a1ziEs!l&J80t2?JJB=x;p2g;UPCnqP{@1ol8CQ{qfAecaR#ZSQF!`A>X z@&Wb_iGX^s+6kaa0M`<4h`53FuF=ualldBRPft%vOG`kW=!+v;t^c+N04f2W(LfVt z(dXA8hBb<=V=^5S%JX9j5-9}pd6Q`OHuR%eczBC$pPYLH4jDzu(2iTg- zutD^goRkPka;OyHGK__SWp&aL7)lIRqB`aSThrRpswK<&b^OO{kZgP3Iq_4c0T^C@(kHRG{QXg-y$Mm}|(cYcSD|5|(yM zJ7HWpPnP?wK@zOdW(4W47s0+pn+#t)Q;aBq3{A4hU4di}9+H?`E>4hX5_zx#Mp_6I zrf!*W?`yvvtLMNY@WE>Wt>8QAKPof|_Y8@QT`gL*Jv4f!M6cw%tFEsDhe#?9;W1LC z7TzSuU0((V61R8k%k`R@)kp}x)p-R`--s!C@GH~^4&~7Su+!sr)3P`n^0DafjLZZg zpG*hRmt=BL6%px80j!wfT=JKyDcmCULbPYE-R0fe=Gm5xq#@YukSNc=%>~}KQY7)_ zC-RcnzJUIsM1|xdVUEiVy&~zb>lxXa=dOb(Xs;}g?H*Lh$y2HIU0iYV`?}g^=Vfoy zv^u)3R#B=(mu1yJ)^@VN+-J7C;d{a)s{{*coxcCLK781AD~9Z1NQNMX37l~c2aK<0 zXQ{%E|E5CEFO=LbraJQKij%fITkw&Up9#uSomhB&x-%CT((W!5hlKcM9<5Y+Jl-&; zq^Au{AM{=)4tsmMy4J0Jo3Yk{`JJ>q+BQBMIN~EHi%7&+HFEyKQqKIDtRf*1_R~C% ze2$l0h=ZFj1dem{zMpDV-&uLjqtN2GSfZO(*6%Xa*K%iSxCh?F>D!Piv6i!xP=LD* z;u+|-NJzE$2Abd1G~UV;SU1zue2$%vDpH$?v$ES&U_!QL(aP_LwIN3B0?o~^ReQ0i z%;ohN4bADV!0iHWuRfA2?(J@+c2@^p7k2m&04WPtny*F)5J8d+$HEL}uBLMA2eslq z!powk@J$dzZ6agv2r5F9&p!klYxNiIUOYwoW#goK8|R(d?9BD$MfHHJ<>vT=D9hl5 zUL-h7XyQUl)R~lnSBoX?V41Z-_|5ZKdZ)k2hC^R_Ux&ZP_^2w56p7E9;?zuRv1`6l zMKXcgpDK}%^nrON*{7l@SeE1wg?0z={x^&lo(&8$0JNFg-EziKQV0$UT;FMWu^EM2EpNdG;o7S`4{rIcb%Df=F`J18$x~ z*qzKWja^U9BS4t__D+g4#Ft|R@JNQB3hMc+BJ^SOiN7n({C;janQlJ*dmMx-sZ_Bm5wyrEJmhbI7>UMwY2~Xe?*&Ye7G0#WH&GYTuCXl+ZtZ-OW|JE%|8p7m@ z6tsERsPcJymnMQ@{)_1SK$lpn`Wv}z*U~JrVs%ZDlH{<1*na#;OE<4)AwE(9%h=dh zv!FDBph}Z)=RH1jANn*1;-4Zr305nwRDh%@4S1?!@bu2c-!9KErGA1TH0)#sK!Dr1 zbOKR-6HcCw!mE4^R_hldbzY=`IiH#ItKEK#TqNJ$v-;l0&n`U#!WXGa(WTT#w^YUO zGjZzRU?KQBF$H5M5EQ&`P@MYAe1n{RJ#PEwK?=cMLZ#dxCA%K}ZG23Wt3i%bsB&=; z+E-Khjmub!Rlzjn!vmMu>bhMmU0{%`*7cZprb3|A>KfIu4pvLHlJu9EpjJTkuo2&< zG(bZf`c#yrww8*Qy38PNRE0&`j432t)>Xq(w^9A zCZ|yf8M83*QLh97nVig}+Hdz&UV*3&RVO>64Ey-~e2R#W2|i?W?R)UJ_Io9cUn@E0 z=o*CY0NWID_ZCw;qKT3U3Pt}PHgxYR1T9&aSiuMze`RnUg?ajK_@T_5pTsF@w3DJI z()~yHZDs?v!4k>5j6@+S$tO=28U`eV3;!(y`Qnei(5@4aJIUz<)J z0S9fV!SkTrtiD?odn2@qSAFVokZq_?Dqz{4~M&J~g}#^1+Q^I<^8ckPQR z5qEjLcH4~Hz|!|RfGEM9=GL}3w)zO1j}N^>2ChS&!lW~fZHxN9a0pQ1`j0wjGJD~w zc1KsG*7ng}iHvkmGBl4D;N`sml}sPRwOvcUB@=3CY5ASB(BknaWm`4@cOaE% zD4HEHY~l8KLz1`;Kns{QPao6@0LdK&6=4;I!lWb>2GcSULPAvU_BC}hij>q;;p<|> z=Pp*g8>ZM~qaziA)EB=KgU47=bjbX&=5c%J`ux>RJ;BI_=#GFg32a;gI$=E z=x_qCv@$rU{FX89-e-$bOJm1G0NNI7`+bq$&RF>(@0XJ!TQlJ{<2}97pN`u**{@`N z6W|8)nFhYkc#Q~OPpac ziOY>PI%O~`BEWn7IyoWDmepu2S{LE$coUQ5@=nWjRRp|F&;bIozki%BeCC_KL>19= zeWT|qYTV~>hzpU)jQdi-jHrqQ%Xl@CSf~4O=-sJ&qwsGn`<~9d`UOkzL)vj-9uWe$ zeVf(UEcfb_=eI&N;5Q>KJmv(!`Od`KJEQf3NaRc`j)a{Zjn=$|X{b6_7K{@txt$ra z8J%8taXH-mtj2~G(2<~3Lj{WeDT{UMlqj1E!eP*gKzM`bsOs@DjP>c_FDN*?Mpv%* z*+2b)Nuegd$<@@w^q&EJve=;wP7LwK2m8l`-PC7>tm#z7&!>D+s>_(6b6#mO_y{6;CehVcpbHTS!#FCKe5$tkJir?mCHNChM$g&CD zy(T8i_@>3XTD*fgz_vy4bNYo1pQ_(p_II(B`z;!R&T@6kYCjgu&}fI?o0^V&zKco7um>$ zKd)Y|&YFn8u6RUfhgf>dO$-H5Mya(pfHbtI@tQ^-nwQOw+nQ}YJfeexKh6C7LZ%8V zY4Qs?x|TzgKpLpnhxK>T$J_`T*n5dB57_R#yl%xT^B>U^vyWy{g#}6sV+twel3par zE2ni(ni}%29esbXb*X;(JJoBJ@a-Cwy?+ZlDtGDK9x9C-pU&YOK3gwaaK(~-TmS-T zS3h}{9fz2K?FHC`=G%Ol0SG{`R6e_q(8{sv?dhtpkdP3t{T#b)^1{;6Eb6p-)8q;# ztm=N(8R0V&s%vQU_4XDd-L80@+P&V``E6ilgZv*)+h4W(VqL#tHvJx;a6aCivZf9Jca2{v+_zVvSYJ}Vbin%?KO(Ps zJ`dN3fX0L?SVo0Wz-#g_VZx$-J0xmUiud}bht}CY{cpc5yhg3wCBh~s_x<o`^`sMa)8dJ>>QgZY@h~g(RbfeP=l1M2x&J(9+W?H#5p+!Y4 z>+>k6(uYvlx_Hi*^zzc;0W=>tG(|5tS>tFGhG@Cgm7K*>>tp(2VgY(3#iQE0s0JWNarx$j|z|XL(xOZ6hu)Tqz6q&D%F*80*HG92^!-Qs-!ha zvDC6~^0Fzs9LbJaG8DvrqD2hV)3o4R)KjVG!@S!u5$2+LtirNRp>S4tzXP0bH>Qp( zMc8_2Eh!61K1eI!E&m7{K-uCNb8=005VN2Gk~0IGsXDG}T)zZ41Lw~s_Pu>OnSO^S zesgMKRSM*(KRJ#4_w&ti6gTZ#;%JuDW@E0NQU%hb){-mPD^}!$|3+@B20HA6k`t zN?z(_cO87lD6M9!o9!nXqp{#+=t<&TK0}NgH@(_KmUy`jJTeF{6czCj3ybQC>O`C+ zwqzjdC{+$$-Zj9leoc@zTMq&ikK3fcH*rLcEY37{+(1&-PiNK$PpzFJ9T+g$G0N{^Z{d4+!-lmx_Z%JNbAqX6 zV^qy#92es_Kc#66lH^U%e?qBeVprOu^XuH!d2j8wqu<6epqqlIJv=rdS!hw^@>Ci} z{E3;X^xaj#P12`H1+Q|8-`SDPAI-}U&OQpeVZ?W08n0v0bp|Af$%JZ9(#yYKO0k1;c)ck_uCs@QvaF3by}KXH9-4)QJHtPG7K z7N$@}e;Zf#xUAA6?Bv;-W^dWZT!d)|KL`ohs+~m-E(&MF_}Prs zT$+zzxzp;iKs-IDQth<&-pY+HCb4@*g}z<+1Q4VDXwYkXq_4MKfM6j9!BJKvltuwA z7-3HoH$tpv0JBfBZ^$i_UO6hDE;0q#1 zF41?I=IrT}xT@1*?M-7EiDds{F=<(+;{n6|VV1AWpdn^(+sr5mCH(7;AY(}=U04Do z59#ef?$I*CRpF>n(?;v;rX_OkfZOQ0Dz05Is@>1ghy@p_xmfh0eab(4-$gD_SXb1- zb`h9x>LrFsAxNKeldL|7ZyrNLlEwSM$;#ICgz3HWH@S~?he&ybYq<)CpEm!tu0%=) z>cLQMNaRrX2u8Cip)x&3#Ihzmqo!IJZ;>{Q^OdJhuLNW{M3gUTV<$!Zpr3N{$u+e! z^S(RN1%L|8HpG$!fQVdU9n(P7(C;B)S?hjN8Uiq{2u%P!A{7W#uv8aOac_s3l0IZ$ zcoh&=eD51rK)C^y3Os~4O7D>j3r%42%L4VsjSrD-ZHLPmdM#ZI zt@lc8_|6}n7{rMR`tmO_orIEbQUJJ{-ReaN2&W6j_a_p+HkOV9nEx-cROUNCq@Ad| zZRf(b;s^Q%8aV{Vz`|XMpcgjD~{82A%N{|8L`tP)M|J+=X_)ZtPp@h z!v;eb$Z|S$17y=u@sZpe`$>KQE-o%^?im|yK%4>6kMJUL#Q-mme8ceH?1J$|V8(Z9 zS>m^XtWdF}p>4*B7LM4>#>Pf21*o#MUjGVMgu*8xe0a;lcU?50yGs2aK8$Ro#Wbp@ zm1zh>jw((eQRR_h+IEU83IeGN78VwU^z`&$5WCm+2{=|65NfdOzK>de$6<%S;rSZ|?dbjEvl&WWtsP$eyH1rT zM2>!2J~Vt`604IhkpS5rH5eO*@TP^9fpM547A2+VYcD1_EKC4{rH{+D45d(M-qJV;p z8ct!3pU?qvLefTf2PY=#|NT=Xdifta8bKN#<)nXR6UoS4MU?AVv&%mM%FDmq&!n7; z!oe|38VAkKnPO#U!i#o9k0c2@iyQY%GRLNm$ZQ`dx4d}YTT7|+y5cpt@yoQo5%zm? zc)+6(s1Q5iF^0v-_dtjyb{MVp6?zK{gA-j?+q8+`XrsdmatLNbnK2X#M}YRLqe}PFgl|P2^JyN~2%bQp0T$+@ckHR--n%@!uo34^~VI+BX(@ zE|Hl;T!P;sq7*CrA`g$Q>eW1E97`R@F|YBhn59px5p92+dkHIV-Uyw_==*>&db5s+ z6J0MBlcBJq4bS4`o6?j#En1`hw&nNg;WUvP1O+6IFi37iz4a9z(N{NX+eQI8`a^nnb!o8c>Xs*lZN()bG=-e&O6u$2*%2NLB;?5fK8AM&6q+(eX z*`sgkh!g%tYW$yeMS1<_kxY7x60v?Jg`YEudO$QOsB_I``WU5IM}YXBn6tpKbwz7r zzwa76S@@)cr)h35ySjgWj44i;YsKRs0*Kv`1@a15h-<4 z=e1|_nRZ}VInO1+`8N@N5R}+Al!HbQrkr#$Dtwl4BXq58aQ}zY+#*?A$<-( z4j7Zpk#MGE{@|vdcaAo^BN#UJ+5Kf$@3r-V&yNd+UF%CzU@3H0FZxW+>^y!guiO~G zAVw>qRg587cd&7gZtGPyMGya;Fqz$>qIn9R@N>2E%W%ZN8=Z&<1S^ufFY-9=JrZ`d zRk)UZ-9E7ADSqc@Ix!Rx!JQR64i-u5rj4MUC6ATwJ`py$z@;k3h&=KY#qpr+sq2+d;Qj z4OI(3MFYJc`;$exySp*$ASH%mb#--GTH0v#{QP{mVphNVq4sN?c9%X9Hwk4mmQ=X4 zxYxV5{{d$Wt;gT+^qj}jInDWjHeEGB0s;a;!mm4kbdxU~2NbteFCLp|aRbS1r`^%l z>{gz*nxm#c@mX!JQ_iLP8Qp2Uj}22Q)}%}W3E$=~1VKpXX(C_*Fp8}E77g{8*hT*p zse=sgN@IuPoI^@9M|V$RUQA#bnwcwu?Pi1tWINqd&OC0aHJB>EsELVu+ErZkXIhI! zy>Ika8`|uA{(pUpq%6DEtMHzV)e|7~JQ{CzMbOWj=+QsiB?B8+%g2k#qimXg?awBH zb|I`Y!Eb*t&&@ za{-Q-7HKVNz$Dk|+}u=r@zjCS;!YB~Wl?oi+W;15POEQCS^B8E={sJEWOYmBjAXp1 z8o;I~#3rGVDUea7PeoBnIl;t)N=(c}a|q+Eb77nc*UXm}m6;s_OcxNl)Rz)9`e!-g z1E^9I12flOPAqrLQT|G)=?d3-{=&P)RkQ6zX0_~hrrlZC*($^zRpBYW-A4_DUq(k& z#7h0yi@Yd!M~WW$S9INGOUs5X=^cgHpxAoUcZp>3>gqo;8Tg+Vzffagk%?szidJ=C zN-lu;4JC#WuEW#^e&NRivrjEvr=aC7F5-|#Uh_IIoQ9J391K1j^fFjLjU?ru8Z%y& z#+1dqB7;$DGX=_sQlguJ?shIT3eKnq@?t9j5Y*{`zc0fK*{27IKgI_}*gjD49N8bM zU$SQJnTzjL{26CiwEB`rechP><_an=82!+qf^<~Aj6B1Wv8HI^DqdJ?&minXu^6ol z7|;Zj&$lm|c^;oLKW+tN(qVt0`dbjoZ0qXvEXb&aV~HIinAYvRQA^;{v08ci#Erd! z#XjPE?X8Z^VO1{&mOd3U_MkkZQ-UaZImfzJukk zTsUQ=m+fZ|l2(0fTa}$JDTp#3<$Uhm>Bn+8d#GgeOa-8GmeClPY*LniL@=*I;X!{+ zs-L~;NAxtcKDPf+TTwgtb3+JHk}I>ZIhyBA?PZ4>{wxpbm~wvvDm+eK@=u?0$zHl0 zC70PeClas=ap*~}ts8V5mfd`8}E#bs5AQodpNbFTN;Dp9`2k@{sb!QEaH$s|HI zQV63k;Bf{4lh>Ypm650?kN5l}>XurJj#qHE%6-PY<)Q)AMRNa&fWcUX4r~Iec~tF) zgXyGQs2#@c7Z(c-;o_z2xQ)7xKgVF8)LO^1R2FHd|7;jj_#Ed!gpl^p8QBLD9|P&S zmY*&%=H(y0stFaPRqbKT7W9- z8JoGAi}L9(D4_I+Oysl*Gu%8$U1nt*#Mjls+be~ZN#<0C9MmLza>ajU4^x^JJj-aw zmp_jQGmGEKE=Ft;-hGxu;7GD^4Q`J{oR*Pr7Uxi6aXJJ^O4zh`l=(9|LnvXQ)+jwfVj9pqcx^{o) z%3BbunTyMu_{W@1KcZRZ`#=lpuA?m&Ejd+`)zO1)$@wF(sUb(0wQPM0NfO$YD@qAj z3}4G6iPG`yC>GZ(phfYvQzbQ%vf9PmI>}P1YHF79YSwj2xCJpkWlDJ?qjOXS@yjIV z9u3P33>I~@wHYIq(&&OkD&G~HN9%8cKwy(v*&ntwih_AiVh^bx%JNDGPNM74uY$mN z9rKUKXGU}TE{`@@LmPQ2Rjt%I28)^o%N_l6T;yp0rSnTZ78H8LlJwvN?OY4dLQPtV zcnguE?d>}~;$D*n< zEU&}FJbexViX^_+xqn$F2KCAk7mYuzTq3`2r}}++b>V5-Y=60ABEktGg@7EPtSuk> zQHTjg7IGiSeEZt(<_F*fqVnfNr8>gjQR-~K*~5v5xgg+-gX%ete!CKmM1pP};Uxj> z?1;2demYP1c@F-^UnWLwK||Q$ipavd?B1V0eKH7%)zJ6BhyhuIf7(RYeCAn~y%G+@(#q77qm91padb=* zR`rAS)*$-GK)&FP8C;69!NH5Jt_}C*m~f}X`WVH}0JvPP@N4vpcB=She_G-8wt6Wd zC_syGyEQv4Ee)3OAlER9w;|PaqSf**o5uJKE6_(B*_!%nUgPNKgH}vHHzlG{hOS>) zRliATo@S^JC;v)yjR^>e(zZ7Oit+mvrq#hW243NyxT4SxnW4r_Y1AsMJseRsH<=A< z$-p!!Vb8KE*8C2~cM}=YmOk)wfWCo5SNg=q~RK<`vthljRs0i zLq&ODiO7PW7RdhbR#|+Epns2G+cJDGq!Vr2{no^tlwTO~HQQ1egX*jTgp zQM$?@A%qV8m%C$w3TGi%^c`I?{Y-KcAV-Klojj~S7!ssu^=0o`&)it)(+J&AlFEoW z5he{AKf+&s)cWYQ?Cw<|Nd>yD;lj|r0FM{&-T3|^a^=4#uaW$|6!M~kM4;sg2ZkUR zz3;#SLiNsT$*)3%cKY;RQr?8C(VZrPd+|Y{U=!*P$@sU@KJn1N+YNy9e_&NOaqO0? z4tm<+eA6I^AtEtBO?uPpwsKz`aX!QPeDPY@3CAEd6&dI>E!Wi2a=vCx*76Y9THil7 z$GK!BgSz5Xs7CJ*k+=6FvICxunTzJN1fRnUYdz1s9GNXo^YD@qJ?!brND#Db1_dX5 zkh6k}GLMCsYnvd8EkqU{>Z0~u)u*0vSR>;+0&jqmvRrYPBHmsE!Ma8nQzBiv2D7>g zGk`tFD9-035|jK2i3rceyT3=^R-?-E$<+J6!=P0zB%QC3MwioZOSSKy-T1rQ#662+2&Anrs za(|+VOMClNUN5XBR;Ut8NA$e8%{A^JwaqNw53x+%0#(XFp zU-Uofd*XdT==|o>&bgbvY2QZFJ-3LLQ?hF6bL&9`A zav4NAiqorVBCidJ4#+!GlsFyO6ues4aIF`M$U6Fc*=nxg?R_$^Y46dy|31cVxBcN@ zzp@FbQS!X99CJL_u5G>SC^Wbg6TU+rkL)y>pZs*4=|t5!d#JnFmx<6oYM>YfpUv>f z?X9ZC=Dce3_nR*?2E%J0=v0W&=bS#1x3duu*|oKrdyB5duDzZ_AQrCYduiz?9s7%) z47Yp1m95)F{ISbq%5EEyJx7 zP@?vszNkl)SX1bob6oyU%b}st0+L3W&`ba0Zx0_lrn1Kxu8V-c^~ImXL!V4_Yh1Jl zFo=q(u?G)Q{57Dey*fR`U``3Rc?5O9;SkAqbO;oL(_5Qcp)MePdVSp7TuY0Ap@q<# z_+?3-B|qwSgkNaIrg&1x{Ql~?v-UyXXQSRL7Fe%{FKbNqg|BQ%qEzd|g4?7p1|~it z4TZ_j8DRq;MvJi=@gfhjPi@al#qKfkv(S`+G~k6#^RtM8V9!xM0e)>~D5yA}wX|Qy znt+b~OWP&ciKv~}OzigMLwCENqtASHrRF`$dj>;jhn;`8s?Why^ZUkco@^?Cr;*Zn zh#V0wwPCuP^z=ypItC|}lN{Gc#`wdPbS@h%ndSot=u*3>hx6e%57czMs^=gkZY#nf zWb3Z_rai}bSGXHI`VK1o1Xx9Tn0`7f*}h2UdlTy3a$)0wn$;98vFEao((4s@q&RU*j52g!ZZ%RsfmvJI;Iwm^wqCP!F9tB!*xIfrID4U3 z`0O82d=nFs-5*eu%p#mY9AVdtSLH`kvIDI(H7nU>QtwI!>WQQ*nlGc7)sloQ5|!SW zXrK>~*c?4j^EWGR%h?L-+TZF*oMg5?EVUgbd-r7~Cl@A1a9nf^1oGyGelT{WR!Ms? zrL%oUkF)yBYQ%8km8tCTCpG)xbvUeT}Au-grK3nzT!6@HoyBQ)Whxq=!|^CK0?7GYGyHGknsk(T980#jF|Y# zBZ|P0ln&LJ$ydr_<;j>8MHPc&uSm?=rk)a(C&Ax+suLJ%&~IV#kWy7mA_wryi`Dg< z@AHg*Sh$qu4~Tp#(xHw~BDG6?K;RXAsHkt4-VJU_P$U?7rc0!puR6#{Cl#JoO3BA6 zglL%h95^G24pIsTkyWAkij>D3!e@{)2n=J-@n;g)1;ZLC-iyPN3 zRiD@+PtSn^_|o5>Pri)TN`ZqR?I$noZ`S%HHtsum<|vw-E5>X%^@T2@9#81IXqC6}`PSXKxjkyq7GJn5+2zwvlkDx1c%-Ls}{#vP)PcJ(Iww2f`d3bold zI#ot~c>i#pT0g%JX8_d8utTqN{SO~Lu)NO-|2Lz9ClkC0U_b_UdbmU9+xy!R zrVTW%C~1}{YG-7nr9l|W5eT-z6Zo4la>}a+c?Mv4OCKv2u2MOjz+_;!q@|~4Q?DcH zelSyQ8U|5*|2|v9m7TX}%Ek&Yi0+=C{w2S4iFR)hIUgl2`#eBN(E4Rz`#8RU$i)^`cv&py9iWXvZN*@}S8cOQ?$jrFCqSn=!Lq;vk^Xvdhx?CXpXli`8of~2kwH8BfaAS-jhjqQ)h635^C_BZ{{ z9%fvVMgY*=ym>@XPi7-e3#1?ZNUj_{S0|O>^wj+=z0Y4;5 zG8qI)!C1q`&5e|V5WoJYI09Y!E=8r)_Po%wQX}p51@({>lt@P^6Gj=1#tELGm)eth zItft=qUr=ufiXsB0yS3^CsHk#k8(EeFZhp8r>E%)!fp7kU|qH30$|lwFNAikvC$a~ zvU+`}6*w#*ZL>BZP??#}>*cR`9Z4dtSYxwXwGBKp!EQRc9nr97{{L)P$wOk~f`#cs z-Pmc@zpzUNg(xgHJ4lsIv4+I+Dg~Mx%k45%u*Zye5yM{m`(S#G((Q7{Tmw%6Ng!1cHKJLa``h(V5_kAgC75JgP}; zWdF6&&1)($C&wxdOCMZ3Jy#GB%mPw*?lShoA*!*PR}=#VoMhN=#5VOD7Pa3Dpf%0Y z+PGmM7ymSWZT|BlbYy^19DE`E)glxfEOoWb(f~5D6b?U1N~iQ@fM~N}hKDCH@i5|m z-l$~M*l>%FWn^Xw-}Mj|l4H9A_z_Qr-#D;WQBf4=9v1a^G4)dbw*3Tfhn%`UE+hBl z-l&!*qcVPG(oT?)RyF~6`E(t>$ncEeqWXrqJq|Ogk!B00`fDs~zreBUNC~C0!cB3l zpDx6H$OZXtFWbSgN`kECHUvt~GC8`|nI1j0pCFzV@?$(5=(+HPXpIo)RS7s`^uOpZUk7r zox#{~^sj(aWcqGJi=CgJpPSnS;HDIIS{ndHY?&S^QfZH?m9Q8dU{t4}rQJREl8>bm zc376oC|d6Y)*tTehrWm2Ti?TgcuOikDmzJSZ}qXLon1hBUmpMK_dlleKkoOx>-XRJ z;kVN;Z#O?P!}?=qJ*n!i9neK@P-ziuDUb=gB@QDnuLD2ivW^D}%}-86*;P-bV>`Tw zN4W&(k(7~szD}H$?{=CZi&fZ;I*Gz;dL!OU=-9Z}xHuTZ|31}A!{K>HB4r}k&;2`c z?DGr*zJSP+!gpn}*6qaAe>+-DBDco5z#;vI9)sU@u}rfpWb3=W(ktyl+ItnRy+% zo-1)jnh>f#VGwn9lLGzo>eY!Vz#Jo|Z{>4bl|d)Lbuh{&OJ^ku9hZ~DYAF7~4aRkR zThEjVtZv(uExXyV7RgQ)9 zQxj5Hp)Vr4GC&lsa@lI0JAkmBVV(R@T1}5ANfr{RtC@2N_P@MrJ5O$0XhUsZ{Iu>K zTb|n`YFm4zN$+*_oz||Yx@7f3@Cef4E>3J)YoO2`BvaSg_Ry2gH~)jHBpQ=g!0Yd# zk&q}451%;CZ)ecV9#Ka9&bp|3PLqRiQq1q0^N7>UOS?>tdv{Q-D4oV?THOU>w4koz zCwd7_Uf!`B+ghKogXPK4(^}Gh@jP<7!v>f6-+Xfum=JRRZtiafL#kA?2t;5^G}I3xNm8NQNlD@L|v(ZkYm*Rx~_cc3EwrudoXVCwaF# z%ik}6=n=iN$=Qur_&%#->vVar(!eIvIJBJgxbd|;xqo#Q?@dPl%`pOmWpYP>p%{EGYxho$UIP`on98N0B z@#f9u;$vzmL(|>z`Lt|IoddmA9SUfjduCY9uc!i6r4!!m4K|~Qhu&$d5vf8Q?g+ja z!;~(yw6=#w%$IZqt7@88BJ)x#tZD!D(@OyCHdx3%(!}hT^TNVsruenGy4nbJDHYat$ zvJ<+Bs%)C;c=6ByUA73ijM7A|p^x3z$l~?A|D&sY`7`E_BeKLkmI>LV=c>92lK5ud zAndY*-L*VkGYpdnNwRp=vC+gYNEE0M1n5sUS21JEarR1vK0br1!O-Ojm1sjhud;$d zJC>iAhI4!*E`GV&DST1^u`_+Wv#+6pu+Eo+O6{_utE0Rbph+4s`)>18d|L#+SuoL3 zP(G=9C2x|P1>r7?tona_&);2gmE&V)7Ux6t2w~AUvRLH7Al*-W^W}+Z+QOxkjGdy(*O`FNb^hpvKX?5sSm-$T&xRd8*L zM*}%fDJkNY&DaJ`yDyTJtjO-KA8#fM9}e5c)6yR`0jj5H!ziJE=%*yLH6$s6bXCYQ zA|_Et7;U`c^0g2>v->AXJP4 zmunRRtxVxv15IaB=T*bBp6BVX{hZIh1ZiBeCyaBg99g;h`b^%olJG_k#r> zvF)^rXrvc%=uPMQkwy)Qi3s0XXs(Ts^Y!#>p0WZMor9e7{*U+HgdOj$>ZkQBqP2B( zbqx$SYZ+;W`+$cl;KNWWeT6d6*MH@8)-y9Rb3Sdz&|A%ObGH3~CH9-gTD<&0)BOd8 zCf!Vftu7CZ@TM2iE`Ia&a{o1a6N#FWiAVjHV)XG5i#6?k|6RJE=9j&j-Ni2Qu}#B+ zsoy61b9YxKH1`YK{bybfNHjcI1E$m3he*&~mW0D>AnyB%&laZu{r+YC$x4ZHKL<0X z4TbD)VX9fWP%3hgF9C2yrGKmuW&0GB(#A-|;HDa;2yw8rFI1zrP31GkgdapEB6iIC zD7u9Ctn-?;Y`;u~+8=^0asBl1tflRrsQ-qA-vzeB5v2sO@?z)9V@ylm!|LQ5QQOL} z<$>S7l;cIn!!gF+Z+?f~_U#8|i{1#ss=RbB!G#u#N!cY2A|uRFFpqR(0OVtkA}Eym zdw>~7r(IS6nq(&!4FjJlR$J(h(X<%)mc1AP25~__=+RW-?erDYALjWZnbnS(g6Pqh zz(|na8+U97cOeX<4xxb%1Qi9*1j>ek+JrYam#!47BdVY!V-BCPM|~)T#|Jt{WIydY z2+@H@5KkCGRf)1J3LSiW@B^ZTo;ki065X;V{E{g<5~6CvQcUM$1K)hDgJ4I`hs8## z@kHlJ&^;4zTB zFl#ImH~R83)9xRNC>d}X@^Yj(kJZOmRfXyXxnge7v`9^WNA0;6y|)3QrP%W^GB?MS z0t)iln6%p_SA&m2?V8`nr4}|wT4IKK=JduJUoZy1KtQdUI%5-S$?ldVJr}>r~MK5ZpQzp0*Y-i6+ z#ZT+XGQ!#*pj?MTFNU2NgOyECNDxkq|1$=a=KLPrx^NJZV^DdhFBu9_DWc@7s^Z23 zpNynd)OR^4^51=uPkcitr*(l%(wTx7qwp-L^E$bbl4-DC5~sokXbJyKo&q#6`}2+8 zgd9zroSe+e%*@RJguJT|U5Y&|VVGx5B?18)dI6V-UpoLur1v@M1l)3NE%(d8Lh8 zh~py@`mTE9EPCjaCisY%_^VNigh40lh|i`W!P2%aS-P29J+-9dn9tIQGPSFL$*)I~ z_Ik$%ntruoZP#?!scdOlhmsZON$c-t8Od%@5yw{w1~Yvkgm(o-KykFStn=##8Ivwi z%dg;mx4T^4XZ%0*l~&~+cc$q@7b{UebgB{JcaE303?gUti>SK;!NdE;cE`1Bh9?Vt zRR)&bU6vV{Srsx>E@uOVdRi^V{caTbd}I4MEgHr`1p z49e~cxapVtv73z|B76`;(rkoI@>89f?x?=ZTQY(kdY}C#G~BENG7#L-kEwO<#U0oy z`@IcrGk(jwk##hZCKRs?$9;oL;F+&%+35>oxTz=dy}4aH)}5a?+pItyFSljS{%S+R zQZILS^E-^GBPSibe~QT=otP_VAgCjn71U#fQNc_;BTrs?`FrUu)DYOK_^qXIT>Nn4 zMcEYAlJ;uNt8+Bhn>_Kpj4`ahqYV9{T!hPMM^OW!*{QuFIjXhefcsn0j&R}O8~$13 z1tmaMcn51E{qZc&I=w5y^$yT}OXWcVEUFeGV8ql2vXo&?+<3jQ_WK*(+YJlx(~jWt zUnQSx-4GLoK#Gqb6`(~XdjkxI+pBm!kw~8nnhY5kYbIl9TU%9H`&}Vn*R>vVdxzzp z!H8qWQ32^E=zPwzM4!l*ep8v&X=nsG=b(QtTA+mdDW2j`6ssfTy^N+kCkVMc^k-6f zs@mEtKGWjto-*5V=n3PBWF05Z2Bov|j(lO|&7|EOnKQ4&0nzC}7&-J_#&B4g)H!jc zu|_5;SY{V|_H|%n$nkDU*PswgeOhS6ttWn?ve{LlKy64CTA$Nh#roAD$zsZi0DOX< zG|oKkX#k_P`0kLCUUshJp6`F^diu?4tLZXUtI*QSq_uY)eAqh{gX( z-v6!}z>hlJC93rKL>3nqe6vq^8F?@#XX><&2G#@7=7PFII0Rx{p2dMMJ_jgBSw*fF z`lM-I8io#$v|2T=l{oQC>bxjFZ`;TATYFdOpAAXf%eFCdm)NCg`_q3Jibc#*1;LFB z0L(r=GnnrE3j|#HR{i->cvw-# zgF#G&oq02uEQ25-Jv%3ps*FW3WB@+m*$;XSqIq@Og}t#ngXcvgB^v>!+vwd3=hqJEZ9*>aIi!O<<8zVGDCJ=W3P#PTpM+_Ow%r{y; zG_)ApFZrKO+qc{|utx4$)`+veFF*G=T&sTC56Oc)4e8MRZ6e7H`aWgHY>5uqck`b4 zdnYJy>+J4-6L|ROEpbz1e=87dEc6=zewv%)G{RvdJNFsV0lms@zk1_;ckpn7o*n3N1=SQz>j2C+jPQYEUe+mEnw!Rs}6c`h{AF#`}fK{=@5` zc;qe7o|waIyacA@x?CRol~v__ zlaQnz0mR%!b6zEyc|uy7o70&h!WTUL#r%KN%+T+89ccdq@Iyd)ta5r65Qv3bchnIY znc3O;OL~Xr*n&$w69<1=>LN!Cn;iCLs_W~gLVH7X?V8Q3ynu0+IZte~6)!V06KLOf z4VP?kSdlI`?<}jRL1~muxs{Pit7L>LP_ZYMUb-!{-5YNHy?mLk8sobnZG<3$;fArI zy5pw=PVjkJs?8A-yF?<_#hHn`D|y)2&h!ykctbT+b>?ZYVqW%beh0C;oQDA1@ZlD^4Hghf)TDZ_L3IJUf^Scyx+4nDBN#0t2W(y~t1Cs|aNxs*0bRq62 z4+_X7#to!@Ehx!Yb?|+VyDV@jg&BlKj@zO2*21~@^0<`&hR7>fe!zWk*b~FU>7@i} z8kMA13kgK`ACvfi_X&THuDqYhkm=|_P^!RsL_7aop^0?+x0ZOUfvneoP=_P{$3P!o zaS z#wrvn^wlB9J+Ub}&gPRE>9*Klq(dhr;KF5zueT z6RkFgTq7G%b9qOcU}DM>Rf+kn4eQMA^Tp!K>*2P)TP+3@CmkBC1avdlIPZl(d=R_l zlWK_3ul{%lUl%1)IXVo&M90WjVpSiQhMsbc1ICG_5|Zg7>-}uybjR|r68BBi9azXb ziy(oBHz|~Lq?%Jad#ROCWa~;-TgALD95B$>b{(^HQzR(icr{>g;1Aa`gs{RG zg*I^|dpp7ho{$t|2w$u?d<_(jF!K4mD4S&ksNaQstHB^H`JOg#ehH^ zRIO`I4axk3WEkGoODP~@>YKMw?tZtlkL^T@^V?@&NjA82Cgtw#u9--bBz4(tG8{qn zwT3ZE$k)xy>!(4Px#yTwT%jXB%~?;{_sc*`m1JROoo%7_xE9HI;|;|cWlV~CWT-Gu zVET*XqPb#Fgzy=H*6SnRSrNxv90D2O*aQ5d0>|Xi2Wr1c8Y4`(WTZPhK?J{z3UwwN znFhMY20lMEs*@{pE!{N;#E?-p%kz}^NkZHV(!nH5QqSWbfl`WQvmTIk`NeLPWx|7UZ-Kj&y?$}b%L9=$KtNG{blQ=l2NbI}N978z&pBS_04J}x z;e)o#w#4j}Z+CMo6<(WMrvA{MQIZOQ)X>n-H`F30H@LDo#-St()B;1?z-dgEqj?mt1-oK6g82g2|WdUbU&!! zysfqG{qBFyPIe~Oa_5E5j=m#P4N*CC9M`hMax!35$dpofJ$uwyA1jNLOx^&K;_57A zAQcm@p=H9wqg(My_W4cPf(aY;%q4NbcIUehO+)XEo&=(D{EL?Su>nS$Fj&Bd@TOh@ zlWM_5lnXBRtMS~v&<0mxy+=+;N?~0&XiF+wcd~)o}4K)Si^_v(uxKCa9rzLB&MDP>R7$97-xG47B`&+~RMce)M*2Cpw)} z1?v8(mLGLRni0;lS^=L2lfR)U1{D_r_9F@ZLl$wr>C8p`ErLL(Rvk}(nxcuUf)c-F zCeTYFx_C0`clVUxW;x8@v2U6()P9m?ij@XEh|x{z11wQgYW zUhDL~NPMgk;kk`9e4OIA*r$t;OCb*7h>uKUjWRv@LyHebm)#c&<} zcoaKW(YmVacP=<8_TYh7RDoeJqR%|X(@&8NG%?BzSe3+G&R4m;s$Scy7((QOlSq}Z zD$|xU+Aoi;SqNX<^n7pkSh{sPTx#*XY}@9r_v*dSAM7XUXG*pGHY51=VNm|PgojBd zq;>6Ne|kSng_SNGDZ}j7Z99E1CqBWjG1Y7<*nU0VVAJ%F@trl2$p7j!Fm;-mnqm_j zWMyTQtFtfOGAU-&o_poDevAbQgUjjx4<8SY-`Um}AmIqbzFwY29=HO-uAZ(gz)}Z7 zH8TL+3eaZ&Xh9k9)eReI1{xP$zI;VT2rwfbLPHBXjXb)~r=I|y9T;HEEi9lVQ#KV9 z6)|7(^H__Re|#Mf)?D)>lfCr2nFt=+ip0QXW?{~921ynqsYz+E(ZuWl&*W+EM_f5bl_-`&+mize{I_zr0{Bbt#bf5~#2|M2fp!e>{%vP^mO`ExG$ISd?j z`0`A^{O=4BCP-ieIEjStd7eU@+$J4KyfpbMA{QEB-qY2&Yl&N;_LD)u1}u!*Ly8~t znO*blMfPoK^ddPDBJH>S_h+I)A(T~@2PAzsI=DLc^ZYUp;nyK5&x+x7I8T#Aq}Nx4 zGC-zQqou}BT^4P;uQ*KLk3lKup(-rJPnkf((r=+?pVJg`?U(DiLcfOKSh3+%oPR7>!IF}ElTvV^jmp%4Wq%8@=5SV=Aelf}wrqkZleJ*yKGt}2 zbo?*EM&VCCD3)645X4Sv0J8@w%T=|2+_Esqoe&C*n0@L9X$GY?<>e``k+Vdca|-BK zzU9CPGm6p+s_`U*$*dutXczYkkFnaTf5@zi6P!@BUk_>oPAhNqE~%B@jkq_Om2v#2 zsxs38`!Ke>uKILfRE9swiayX0IEFdS=s}dt_)T~JN4!7**+s{j!i<7sRG%i)FTJD1mqg)JYdVtlMv?!ZtQ#`X)P2_t2a+yIcZ4G#JWMBAGnDNM&zAE?e(L+{{i%rFwRP?FU-GLnJZPCuYaSrwoy|gNR{aCLGIWwHZd=TC(RXOmbVL-ln%!vE>eJy54y1w!3tyZfi9G<{ePm2pDt4BqY9VUN0;xtghyvysWHnL0QfSjolb~AJZQb zKs+FvCPuEAQKqiB*%P=AnAds&#tr|6({B=vt3An@2A&st&HRWgQU8Yzmy5UXz)N_W zIi$AHj{htlO^foQwVXA?t_dh8c27p78v5n(g~a*n<*cv{Mzxkt^;-gJZ;efEjD`$4 z9RE3qG&i%-go~r6nXSHcsG}OrUYIr~-A#VH>dgLmt9!*jdaw7cuR=moLJ@ji{e?Ig zN@q7Mu&ygA$X$kePN*aIBWOv&DXY#QLgXn%N*Vr(Qj!S z-cQPnSU8#6*}3Uk7*eN56OuHNsv7yS>;v7DQo#gKI4;V8W2s+qLqxHjXQ#A=L&q!q zeO68^-{d1ZkRW@#l)VbKa$SG; zz}NBc&ReB~w+;O%sOc}B56@oXVP)9gUI_M-;}TLmLpLfir~mn=>TwqFD|K;pxM1K` zhGs==XCS43jCl5@8sm06B4XaI>0ro$zWn9*M4b3tprQ9Bt^e}vz2)+v2=pl*EY6|)wbXLcF9?`AIen~z^KHf|QV={5YQw-}x2@9MPKWgv?3riVz zJ}5EwuTg$`wN6%h)vvAbnYxXQ8PAJ`30ksd(&b6$n}Mi69vl#95Ral_F{CFO#9Y!( z!Rs=u=X^hgebD@e3shx8C{WD|HFFWIh>N6CRls43%uge;EVQmK9xKL|7iMH14uHVG%~HpXZx3D^vUr&{ z&iwf2Y3X%;W5Q2U6`)4eU(JIBPT(JoqQk){CIOl}=%hhXF_f8ro=Qa!iM*6TUw4B9 zjIhg6L4%~xKjkgUp`_skCE>3njVUy~)Qvfs0A&*j#CU9xN#kZIv`~@~1U`inNIkO1 z+?+l6_wV1OJaQa!PWpZgMW4*!&t%||>=h`T`}2=-_z(&(j7k>T;kgOr+XRC!VAxow z_zI>-ZOk}!={%*CFNBs`Ul>0VtCL}JcH7h8!mPL$FWbI?O7Xv`#T*M~^HnQW_W-0sb zZZkL}M)ez6Iuuv^m2DA7OPYNPq(!Ad5J(xiDB<~ce07G1lU#JZ8iFl#SX0J1-}c1V z5b4D1yoodvb6ef3CI!aGTe~LXi{G@C+n+d!jLq$rBwWw$sPamCN+%fDVutJB__hBK zf1UYe2h9H-WIlE(PxUjW`zi{bCc;Soa^c)`+d%{iVP!?d`?qhCewtd_&TdZbU%2hh zVS;3mihd0Z4Ta)ua<%N$cp)7h?m~b4Dlw>RY;6TRSJeQSF_A@CPW8VBqV0Uc?LkYW zMwzUt3*c^36(=EDU_id& z6+lSAFM~v+$P0rMWBSy@w2z#OSVM5*4IEz23auMSqk&wg$T|cFUVT{y?c(cyf#sr+ zfMpap1&kj*5^Wgv@WDo3I2Wr&L!7G`2FjfoC5P~Bpn{}Yim^m=3j1g)e%hZ2a*i@e+85DZ%`m`>L2xdgs>RuXEgN<4vY7i8 zZbTCJN!G`VR#y_6%36n%{f1^_(HJ_Z^85X*bAb+%mx{@1&!v8MNTYF;gV?U35@8Ms zObY09Gu{pw{CXMP3faW zVSB{zsn}rmj=7s(No|AWbc^f{Yw!H8qN7sMU!j~|+M+-hxT~_B#~SK#)HoyLO*8bG zxJ1Qd;f%ULUP?!3f~W((5N8>CEUm4xLSZ4fxvy+COs4*E-nfpY^V zg)-LJ4j3%0tWJOn^P9MDsSW}#jslI}kpn|RZ>b#t3+D_9Y*wYHSS?6j$ZgAq+Ygt>BY%j zQKp^8F}feIAuTwhmpn&%)#~+29OBoNe0utW*ug?2a>+MoB~!6E*dPWUe{Po%TH6GE z+qf9nZbr7ky{+XV$30a`L%5D z=V{tMBBTehPsKxE=;3BL1Z?WKY3YGDBsgDIJJec_OD|Fv+9;2Mx`bo(zDKn=%O0ri z<~+Ih${GNc{0a@i4qVPgMN(_gu?<8KtNzjAQ531UI16?D$4(rY0Ra=2q!fMlFaa3( z)6$+)3iRvjr|Tdh;H(XK>yszr782ffu8pWEo4=IzpW}Uu0*P+6At)t;a%eZ}c7Q*9r+#jq3uNnn_hVBcS-ft}t^EGwC=2uSI~$rE_InftzFr%Lt^by7 z-LDem>lM=m(hBlLyxUAcXdsZHjFh?+2gA)?g%09RLA12_BrcfKoG>1e8uLKsQ#e+- z|I>z9*zx=T88F)^dgyV~&G6UpUyNwc{Q2a}`O9DOh4rs6o??I)8I!B&&`CftXy`TE z#FM*YS7*#Un{in)Zuj+-cb)CN2c6gkHz|S}&6D-aeW=*Kc-Fp~0H=d;3H*>AkQOYX zyH5!Zz>+bH9y5Z*>;wlMV#5O4z1sV0I2=mJl=DnLUyo#E8`ZQ8MG)95;b~0AYaX=0 zhlDi-l@g-0`=uBy^ZQB*bkA+=nZ#OTvW}aE)Yu!e<2A6PMhk{l9WIEmu3KG9UdUCxV6RCi(k$@jq$2oHp*sj^J+fNS4B~k z?KSy-sHz{dEOP@t}) z!rrEi+1$&39U&r8sRI74fr!`G{rjGTmWVO(UA%Y1SlDuKrRIE$*YNy%i$C@+T@&Q= zGb<|*aai|qvWC_EOUKTeZ9at0LvriI9qtiC3zvcWORuo6Q(CZb(dEqT4nMXKO4ehg zhYe@p72SJFayWcn+RYYf{1ol~i;%s`M(ibqr7nMjmYV9KKEa|O&G~H{efFy>n%5nS zK8$#4l_Z866&?oK-AW|49gGeFLtn&H`aYZDTGyjUf&$27iPgpnK$2gnx=&Z|H7>Ge4=NMV6G|OVOo@M&= zB)uCwBt)rK(dzA9mZ^CqEE3*TQ@uys^Un-p<}(zwl})vLPjl1nBgTuE36C|{C3 z0)rUqDG7C=9F{NlTLoq)tK1XWlsXK03b(XoJLV8!OMWb ziqFGk)R_tT1D76N+28(Rxc6pw7$h=qzugr-*_MAYuVqRc5`sqcRSMDx%2km3L*%n# zuz8X_y>Qk2xb~x>`9@NJ>P(vT(x1BIX;2p=P|LXNuh7ZzclWy?iQ(u6mi7nQ?)BRC z)2PS&1yW@Yh>f(r`nNo&DU#o|IGIwHqAY-dky0!E=wQxFnV&P2{%*xI-`}B@d?GSX zKttYr(Pj2c1=8pI&zRsl!S_Uap;@U~oHjN-58Vt84VsHC!{oJp-=|`JLGkd#pM4QP zm6md-l6itCXb8U`-(ODo@Aey>+#I4q;repcJ&yRGLainpgm@g~;Nus-Iyw)acK|Kr zo2zXJClS`~06XATcpqt899sVc1N&t**)Ct|uZ6h>YpG|2_Y$*|z$R;Zdd* z2v=}WQc!&9UePL>Ef$Q-3(qT_n0@|jy4Kmb-in-f(3yOBm5M~^yP({tJod~qWeB_= zvPhnf;>Ma)zCMqVQ)j;$OURu3+O0 zSab-a3qOZCq5!h0uRu^mX)pVVp{2dt-T$EWa-Y?T!BF`&aQV1ibF`4F1?TbX2y5{e z*=XQxab$oz+IL5Qep`B~AYU!Sg$g_8Otwx2$f+Ie!oD!(p4=~ADv96B9xq0Y7LF+s zNlYFuO@>DJoo*HL&=-PoRwe6>*FXGZLD^E4-8#+n6Jvf<8W0GUgPO*>)RYpP<%qcq zs~|xy2$ezLXK2QqYQK8GQcSQY7PEx2uIAp*#LWQ~y#A4)z4VgF!RAMbfD)!^5$F_KQI}Ty!oso>tCp?Bi6p95crK zG%pM9Fe;Bq>Z_`%jZFnbupQ5DLD76XJdQwL&m27I1KR^Jv>+jhbsIuf{K89e{k`bF zH=H%SD?Au*662$`0eNQL=K%pa{V0)L=_~j%xW{3m?L1Izb_vX;dd|ZyhuY@%#qW-~ z3t#ly1J={Q7mZL=gog77a9FezqHEAWSk-%-to;JE9CnQ@?uQ12lQ%av!9?O$HL1uw z0(*~cBW~99&x|3!>(@OE$bh1HU@_=TMA_V3vtCiRm6emjiC6}T*>=u<)&s?=DNjfF zEJkeX?CRzbv$N?XC2SV^QQ*a>tBj84i-V&-m{~cdy_|g zO>Bk_$Y6mXzhsyPYoS!h<~Yv_l4A29&`2>#V%f;>zPW$0@yXvmDOt+m)+r_k#k#zF z2mWO1`>sS`8&N>XphXNL4ui_78fRC1Mw%70$YSI0@LHM_T?k(9UD1LHT-zmB%U#7m zdG)9_AQ_6|&Zlg<$VG46kKkTO(XUMKJS|tb6*tA8M_*>B2@H`*xNz|EZ_YA zc>~(ljOJxeKQPLoC{+vI2v>}6ShW3cGat?}q$^~jlc*(@vk}SG{F`R?O<-^{YJ?<9 zFCdN~!ie4Lddk@}J2&516kvrA|Z)p!Bca7uU`j?TA>uE$k8Vaucjh7j+=)^$ ze-L=z^-w*Gy>9LuN+!VyIX|=tffGz})4xScysYp~oE?Xii*rs0=46dy){2S+bdu4d z=TIsTc43tt8oSveGwFC2qR2GJcA01WSN& zYRDLRnQbnD;N1p1F7T0O%zhU4snpAt7AGC=nd(O>4x`4I*gp~^M611+Pd`EzA)HoLl6w98Rk=%Y8cYEX3##F)0 z%E3k;S+GROe1COFX5)3{c|OzF9tJdXcqxyid zUg9e`Ht2a3oazW-LfkZ>6|6$W5fuIy@nI=qm=|aGhlJ)^?f`x;qSuyImP3mtAym~+ zg}_w^-6=jVQZe!29XY>yG1u@l*D?S3ef@-q_Yb$4fyufb1@9MK6EVN$IjG$&^B7^$ z@_v7>6m6!cuU&MqJeojOqPyFD2(!ICx##}^mu13J`Ua8Q?bh#=il`p^*k~1HX=MKo z^^+Pp9`6UqOp=OEA30JJyw40@^=ovPesLXL3!cR&r17^^RW&r%d9Cd{I(y%1!QM}< zc=Zpxz|q#0_`LEO?7i)95R~FWiezTOI_Z%Jt>CxbXH)&S>GC-PD5?5pvsW3(ChF?L z6-cb@>8%71VGKfhaw&&%V$D59yeDUZNEXxS)vjqeQj-PGzcznPz2otrRf;+x& z>Esr%V`6uqv5a13%~4?o_tA?FQiCw?l+0Hmixl-*(MYL@B*`H469J4axFNjqzgwl^ zFc|Zr8&Kn<0|G*%s9h70q7D0*kKJl@EBmE6hA>fCB+{H2!=w#0xoG^TMa5<;jIBJ5 zw*L_T4l%Ru(gXzJPgvwkASu2(9JrS57)40XLy)Y9HZ#IQ6N)v^gD4s{RP+l z!5T)|NPy4JGaU5BKa8W7=F4XSH(UGDdDxA7w&ipzI9ke=QM!JaSC7h4!FEl05g7-p zfs>J0PxNxYlI!CFLhT#M#^I zQhn9&xE}2jMe))GBQz8l0i_!hzHY$e%QAS;9vMgVBq`(yfbSeQd6me>RlCqYw8B&# z41FWkt7TlH9=p}AXZAvT&OP<7dmYbQQ7ez3La!rhS^~f?fq=3a+sf6Ax|4f5dDzYAx*J=?$<%O?6)Rn^3Ekg#pWAobum7vP zyf(8Pj%d%UP`C9sj%azG3is!i!-xApje%=Jayg}V+Mk4$GnCk_?BCwM*L!q+J!<>7G!R-_wtK;fi;JF8bqmwf+8hi6yPW?q)c7$+n|y?ikzsSq28! zwL^;PNh2g=f6G3yv<#c+sQE*xTOC8<-+%rlHC#prXsJu-M`TnvST(t*-M(wHG~$DN z5z+QENae(S=2?Wk>7t;citGbbjv6`DlYC?r;^dH}hAI{-l-Z_fYObgT9J>tqHZLeQ2J`ywU->kNxRJr#zQuMa%$!?_GKEd4G)HDBdZ-{+mKqtIBp!5J1NC5#M377ZmSZL(YZbUN$aH*MmxLrRDs1v*4l z^Fe|7fV1T%)#4l%*K%^@B~W^Vvxchh^y6p<&Jj^WDE0km2b)xJJ0YX!Av z5d`e>a=0UcTm%91?Z1OCu(HmISp+FHOcaF}c-sO%^kNSe;b`s2tOG%-JN$J$H0VpL zB-O;quw48A>M+6x3C+YEn38sRl^wW&Z=YJ)NZA09FcHE{4@elrq~dAoE!u2;&_P&{ zAqJ;X9vOT|TKZ?70`!A=(xTH?%IwR2pd9^sUk|I?(==VA2UA1BJeryu{-`CVrpzbn zzcZh8K3+lti51lK7$EC^s<#45(dn>cPk&}WMMoBEz8%C+E<+*aX;ib)CB264CjZ zU8F==j^M(<@;sy2fCT~?1X(Z{$%58c0q0AnCsi=ww`jD}=3AojxnBXFvOZ~D=Y?-( z)m)?DP0{|GrOCq86^mC6AVK_Xg`GjmN<%M(*Z14NP%N*$-Ry0M0_@-Kqm@J|G(>-z zWB$3Rhvq5MwQIgpm=5fPiBAbQ&(cANpkfIUs_7v5F?NKkhy*%x{cp6hH)=^G5hkkS zxnU)B{iVx70uWz`1jn#wzq3(r>Wo0(F1}T+BS55I@FV{_Zz3dnizZw2u;cxdVz(9G^d* z16?ZoVs^PLZe18`u;%FMUnJ1I^!*I}mSlJ>EKIwu#mFrRdC`tAD(B`YX&G7p-M zE@eQLno?gDZ=x0k4rp01n0xTr4ReI;1LF#6zL(cXiiMP_wo6pdz+OXbU&E;YnqIU^ zVDuge0$!|rBubq!)7NV>s-sHhWm)HBDZ8J=O|9k~*K{h8$3^f&wVvV%s+m;D-~T*& zHf>v5XUxRvQ%YyTIZ40Mveax2K0E|R53-HtZ-jHTU&RD%X`t_Ol= z{&LV<55!DuHm_CB9aB9o`gRU7Vl54)9qiCf!fxm{i_;j#ouzCQgFOQE2$Eznc-afu9iTe=?C@lw%YkM*={ z^zc9)CJ?t$eP>1M+0b0ug|@C=1km{8_R)*OD=!f=095Ed%^lCdFGMtSec!%2s1oap zZFfpI^)!#3jUO!bbFMyjJ>uxN?`WO0s({j*^&FbfS$!aa_iqI{ER*9clTon3C0 z<$vIpU5eoIx(jBUs$EshWlt7#nHkKM^ur$I(b`^Mjk9%msh|+&0U@#?Vsz*q())yneb0kXyk~<|E{!lcJ}kPfx`NyE1iee6RnLh_RiPcX7&lbAMJl1xmE3Sy&8-ouq1H#Pvu$m)L>V}s^ZV(NAL5b zj!T`j8Hbrf#E&F{%yt349nd$(^*pBzT?T@C*yTzVqfsG@(chF4KK^9In>5={jUgr= zIL7sQxU6k#HJ^KO!rA!u&qAS?Tl+|~uX2$;uJ$Qe0r3q4&ypoFBje^R9t3aCCH`lk z0J*QE(iIVQ4N4n+pm0DQ76~OyPH&gHY4ZT)&8#c&V2FIgpyjwsLJKTe%p5!a+mxAN z%mi<-8r-^^2<24vv7pnp&Gamuni@hcCKX2;iBFqud{2)HjaE}J;Zzbc=KaKou)a>m zO4C;jsG6i=^XM^fmf_dZG(&8H_AC#7;>C%x`sV9G7L-%)xlM?~SHG_NX$JLpbxa|_ zEu|^>P17@+V*3~vP^5HgrLiqV14)u045%XA>!SFU2p3?`(SIV@#OPR4wY3o@wGQAl zMsywR;yrHf!3QNxW+<}0!g~R)t6s_1&9SwIn?}F@PhkGWZq?jShJ(*+<*nt~V=^Em zcX&FB>A#q%b-x+C!DPzo#cgyFUZ6(L7l?-ttpb0Di$tJ*zqGPU+lfj1$tpDi0klWi zt3*iG)5SVz@i;uJ_wthY1UMlYnRKrQsqXh)x7oa3d~Z80Z)b_$e2a~=U5liDj=;9O zB$KKDX5o1r(W;Q1R*yVJFsMFqWE7CBfbswK}`A(!2W4S_y}a$0heLf%?4xB?88D4^lgK{=fD$Me+9#bxoijhhv_kCyXVSB6 z&^teC9+eclEtQV_KMISa7KqC+11wVM*m#R&<{`n$$xR0h++^jRv7O5P=o)ep&A8lSnBL z%Zm@&bg{Pf{PnAwx3R9(VLglq;AFO}oB&VN5AWZX)dSDs%-7|;x1LAUOqETWJ1pL= z`X|@CQ34nHN5kJr7qs>CKIE9>#`H>O?18G9tFwXdE$k4wgG>BKi)i0mg7poUrs|&t zxY#jRjtMoD1WAx@*4sX&DNAs(%Iex#h^CZSaP)x-a~$|m{zX#4!yRnzj{-5HDp}qb z8V-L${He^9Q0>(iNAhL9=r5`mB+v&PJ&;>p>Fhy<>(U>p533~P%!74!{5r`#aqFXz zsY*Gl$bt$(PSfo``Ni3?6JVuIsqC8-z&$j190x!~15w7EZ)9ar8@ahcn6 zU;JM$?njQ-uKkw^ol&T!=Y%yqn_b93onE4bMPy$;B!(ORq-~1;3HW{k4!he100%4u z8H1V*3_|QD?nyNnVf7&k7SC^%XVtF)(L>(#LHU^fK3J3X(iR!-x z&+?w;)2G=-h5(B_s2Bia(|{vO{fDVVjX06$>Vug9C6WXHP>>7$-^zy7R)P|sb6339 z`R+fTN%6W>G1j+L*l!$YOa;)!8KZ3%fz-c=x*VlioYafaF_?%8Ml2eHB zpg=nZUJ*Vj8uO8egv}ouCJ9vv66bgC9`+Rt?iB4R=QDlQ;Hy|Hnj5nWl`$j`4tn}@{a=VB@10e&kE5o7w^a2FpSRyk)` z53^wU?`uPeh2H=*HH-l@B)2!@Ax_AHMZ@bLqOtYyUFL&~LNoEX=%zH$e&MTyWze19 z%kxK}dD90XA5nl_ms!8Omk#HA?-IijNsWiMM*#wUW*~6@L>?Yywe;MsXVin& z)z#GMW~Zj6awq8JRQA%8Er7(6mDM*(9U!!jtX?=pN=3C+YZ^5RH2yv^Gqcuyem{13 z;maW?sJj{sP<4F)JVcUnOl%#~98JJ_8aWm!@P^Pwa_R}ZyXfiR(v($HAf5pX6CfYq zd6wyZ7DJ5Q`jOhN_6rYj+lhN2E&o(c0*%bUmiHg8&2xj;Np*TcFE46Pr7cH)-OUBo z0T*HxUZ!;$q%*X&POYUH=Go^CLL_9S+IRYu$f9SvOG-$(=Qo7OMK-@Nu%kQPTOeA1 zNG}#UTLPMd-=^9BOp7lA=)jB6(0Aq7Y?k>LrsA}6Of*%_A|zt-JbP_&TTOPOf#YR! zeXxiPv#R#y;snt=h@a!9P(!h>@X_vQ0d)X)=m|uSL0DLR#`_`qcG)~!rS6!Y$PYef zW?Dt0y&jhxTeRvqu^!W*Yua$E;ICSxf4eu+9dk#}mzJ7aUB8(9 zmrU;TN4W1-0YburxY|55{q#XNeJHtooH)1J{v{^g?G;&Z>%-ya>xMg|%yv7Q8D>+r zM~#-GV1P7W)q<~ZLIzLMaNnM4v*5Kiv40j-5c<{b{5*QUvUQ!yL>{;0sB~ql7D#bc zkw?^La4F<<`ZYKzjFJPd5Kf>zIy^i&{7qiIVeuGNo|t!FuWF}l5Zq(XF$WOhG;}m| zV4Aux9iCKM9P&UR5}lj2wV2lf|HrjjKUl(dQPA1OKf*u&dMs01-v0)Au^5C=rc?{% z5NN64r4aORshRm97oH>6?fPjzOGjNnhbw|Qi(4jk#ksAf+P+}Hs(mxqJH$5)^Kwo{ z!1-_cN%vsZl)snl#`HvD&1^Hh%AW;cnuhj{x=Af5rPrl&gy*Gg< zA_xu6$2X(jQ|sOAGe_8*Mt5g5iPLa%`H^2FaJvZ3!2u-x@tZ-iE!-fo-nFkha2kf( ziwtLKh%l7Z?dJNOelNI4#AXuShKP%&D@>}$Lt=~rlEN6!KT9)C_VJO*kJWaZ`7Rh@ zKT9$)teMC`76ECZzmOs0Ih~#5{TXW}ZsY)~oWs>#N|5WVFO!AEvk@! z(CvG7U=yfib0kyw!go35hR*h13I>W$)JNUKo`)=||6He|;{8HO@-CG)SKgL>Cy+CF z_ULGVu`?!^aC|~lYEw=p%iO=>^D&r&`7 z!s8+dBZ!SVBk;a#sT8Pc9KaC4IZBB109$=kx*H}E93mTWqsUW}dtC4vu{TMmn-ua` z%Uto;n!(6l(-CrX;u*Wttwfp}m0YMj88iJ;nFwtGB9xA=J6(@&@75)4+u=m6hB;QV z4>=43n7-eR=2bFUz2e!}NL8pZ)qW!Sih$nflzlRSGaaiP?^jPn8OM2_YPCls$F%P! zzF0NhRt8~FZ!&8==HA*R3L!lQ(E~Tk=gCx0sbk$Z7~%!)V}-;okCloP2trftVtpN3 zE4lYE%E-GY>l$XybuOzBN}CDNHTq>C$)NI z!-v#*kLZ}GQ2FA|oQDpzR=pJGFD?{oZERbJ1yF|MD>QvW?{2elt`5@E;fr0pXm+4jdt2 z9evL7y4WK0c%abnQeL^>I`ee;(s6n>Eh!`qtN+lS_(mO~v^_cXy2%qr=HpD+l!lV- z?BlY3mR+YSE2k|z6;~*~m^1HvZ~T6M>UELN`!>D9ZGBYzIU@6}I;vw2_hr-j#lY5{ zK*|4eE_3BvDQNJX8DUDT#Ml}!K6^Vnwdh0h-P3frx9f8UyR=-(@E_lh=ZvEP%G>l8 zsrVAE)j#fKG5@Wedf&B|I*;l(_B>%Xo<^~!!(fm5djKENx-Ujl6jDurVIW!}@wrKK zZY#=kdzFfB%*Q1_76| z^?Z>DbzI;3Q``P2*s_W&dv})dkw6Mddu8s6_st96Y7Lwjw}0(c$MX2sqCn$F`BbV2 z`(#mz^vS?HA-SPSH;b?+ZopY!K!AseuPyaoWKq_1?rcL=o2CId(HdhdHOl&f>s7wS z%=TN|9ZzrXBfhN|c0<_)Bg4(T%NRlD8y?e4$64JS9b4Co_>AUiY7vsN`O?E&mdYUC z^{F=?1Zps8rfa|30Le_P+;!7{Y(YE*4Ry}v-Iqt9Mj*=Q*0y?jYgxYt;E!y}Q9$L_ z0Q*xuga3QwT)A_RYD$4L1+h3#qN{HJ9&R;XI5>cP--Jc|?jA76&uNvvfwu2_v`tP) zIdp1)Ry8%Tcd&Xt9ycZtN&v!XK<}Z+DV*ojqEqr;yxgCnU;V>1=TzRh*87%vNGxNX z6+Xyi_DH58(MZ3ly2P8EQH?@kpL2WI-lt2jO<3sO(ZSEP3M~_e?g}*~V?^`>E@#cZ>0LOzBOj%233Z{Uqyx+}l7pB(h^s`aR7?b`ptiZo%RHs1%fL>#Lu!K8^2lp7nfr6SPqR5DBo&x{1 zy}lS$VxAUaR^MfbG>V3g%Df^>3Xz@*Rzaw+Ry=qg09r>tMU+KI6af3o=z|jlm{G<- z&3;PQwWw}bxya}u>C_@ppd6O!uaL9KBr598A-9mW040^zjpQUfUwswmv~#)8y``xj zS)AMZKojXklLdlyh-(aecUY`tf%n6p0Vhp3Co);ay({(Z5BPqnX;25=#=%SeZ>eE! zz0rGnI>Kl97;L{d!H^@`SGN^2-yy84*S^B!FLuHWBj~ zMgWROj*?))X;>Qx0YkvW1Le*lhC_r zUo=c%{L&U^H){b!|26a9#pm_r!}Y{8kd5 z9E=IN6n{%X;yGiK7`5Y*3|UqKyIZ_Y+?$V$W^uF=?RP~@JlB5dRy9(zy0DDe(h`UI z*r6M2#3m^O>=btqiJ5??{3c;4Wdd>6(U%vS7cDPydcQto&hwkFsh3a7Q}K|l-5)I3 zcpHaUCmM?@8ELBR?r`t5I(Iy}pK91%m(C2%mTUc=s?g?s(HWT;AeBGT8U=I-H`JO>Fu#^ zx;l}6OrR~lW^rZ1QbsUO(%0`V|c50D*}@ zTq*uk$bJ_K6doC=YlVad-0)2mD)8;q0etF9T!E|c@$qP7i__J%dYI$SbB~slW2eVw zuS)uhO0+XUTs&4h`Qbi~K#;C>c9ZB>X+XbyU&t&$U(*oE8Auq^ov`!)^cAM}kDb~l zoW*;I#fSg4>ye+Sb);>i>*pEC0sHZ%TioSy zDo`R)wgF5y1%rzGf_&kYcD7V#z(2XvSZL>5PsDc$6X`0mGj2ioYW59-ld;>==Ae3C^Cjg?EGz&wW z_J%Sngz3+-R^|rzQ^yC{5C84#ulCE=F=?q`Qjor-i*xBLiVa#H3ar24fD}tc-c6O7 z6e}WE{qm|>yqs${V&AUVmujI~=~}1qgx>(Xl$7GnhB~u)aORQB_HU_M_+6&k+6#sT0+|DVZob{!c@9VD0f>>X8_A3y2+; zs*iE@>FK!Mp}*W2KCi#YW^L4q6Kw9L`cruP#=THszPn=8{m-kfAqMn%iYt9ZsP%GS zGHXUNYE$N(a4`FQ(hw6fFEwZ9WVN~ zz;=4y1k(vMF_oi03!wjU@7Ch#%l3j#tRc3PUPb{Vtr5|jAaf>RH+Q-wkUCRfdf>4aXQbMdM ziv%oiq;6N*%{E+$!4?Ffo+rObn3NizvD4Q_g`WSql$)EjOt7&9foA_qwhatR<1<=wV}la0&5R%9$$Lid$Zg0ZpFy=Jxzvvw-j{Y(7Wq}SkloJ zRpt0c(aVr$opt-XuZGh4c@^n?z^7%_fG9E$iN}Q8L8J`-3cLOw+}-=^g9d_TseGxw zyC8Kz^r1%BuE|bfA<7+bTMpr4I$qb#*^+3Red|Cjol{aTl5y>(^8mFmx z!mRg@XnaG|{PMs}8OmgILlkN)D-$q^3y=ExFZ{Z`{1%Q{Mbj-p4oNhz>yrJ!;)abg z9nU4HCWVC=;+2E>!<-=`*-t%GkN<@3Y&!-ro8aP=o(bi)h&UlhZ*DOejo)*!DKa1; zQ~Qu?Bc?{qirZS-oot)s-kiluIj2pny|M|ZSLV^7^#3I*Hl5wjAp_k_hMjQ_vFHf} z56m8J#F+gO{gk@$Uer8XCeVwDTbse>R-5QT(Fa{arjnN$Tt(jn`hhi5Ds9D{<6^3G zAdJ$i-)tupzMXE#P8+I1kROq4fYaql%qccaT|WEBX@SEP16Fc}PttNI^+HD%TIt=M zbuAp|LPOXQ(J_M+HA?Fy8I@&den`(@(f=fzA-|@Tc58e42%;Zeee-w6D^44~63~gV zH`5j4EX{_g;eA1>35lK!$O|rxxYXH`X?lyu}t}jH%cxkjv@mGrHOSSgTrvcOv>V)7!Su`RxCPVpj z?(+#;ue+Al3EVos`c!vGVJ>5Nt+3*Jr|@z&CYf@s@U$Ei{_UHiyMKqkneXhv6p+ox z55Ual@Jq6}3+c^3$l_s7>#ZJQn=DW+rWA5Bn!0l_G`qW-$OYK&t1Z@h01C44c?50s zd6DX++OneMVWs0dHEQ{B!KScqvt$-syw6=||5}dX`yqjW*U!NPjH<6Sh^R)Hg#C=E zul*cCOy=)!tQK}F__kq&3l{0q-@PBt+J@5q&aKsXnz-yuZ&Tt@xXu;6C9QZ*_OqF7 z{C&k=r45iO2miXkY)5~AG&r)i!LFVN`j|*cqD}NmKMs@tVK%l|tbc`a*0u!}SKhHz{kQSu@wLwIvb}O$#p?rzpU}v2 z#Mxb0b|Qf;h%Sl*i4dzCWF3UzE6NH&r4|hj<@n@yN0+KP)II6b!bGEY<256zmBoTU z`y1~Euc{O|-C~|%98k&yBYFbocd$N0f=I)c4)?RDXw~+{A&DwhIw(X@q=*I!uUF4) zncdV`bBqlUcK%MHU~AV{M*~ZlCO7&aTmQ31U`uQC3#mw!Me9AL8Y$)wQGPoLH^&yS z=W-ItZ+H2Md)-Q7>+Bd0@Zx`Io@o+;`;cDED6-Z@nxgvUnr$n?V`i(t9 zp>(3<*Q4|Ey^d&=#H;j{ePc^J2*{xEcLZ4owAmnyKYOInp`wthE*e7Q09XJDJ8FaL z#PI`r=%hv=S;8djGqk3tQ-oh@3<-__Pd6r?*ZP+}lGcba?^k{qXbPW4{mCriv+#R7 z5Y{p|ZUE}SH2Ol^?E?J)VUYi(8pBA|MVPo zwSeP!i;d08X>QsxAGU!CY1G-57gG?;bo+j%v7!4IRnDTrm%4P%^I_ycOoW@l3R|(f zZ_D!m3f76ru_ROfe#OAr5+g@uc$eCsm<`6@Gmg606Ti% z87dnz%sj-HAanmUF)0bS9RTSY86o4ruOEQUhc6OZ$qZoQTfDluT3*(!Pw^7)xg`wo zsr{7?dV8=pXLys}`I|e23FU14x6*$ezL%s3O?xL(nwoH4OLROjQN`ghxxi2i31;m) zX@)N_b@(-~xZS%4T@HwiWbaN6{>s>?hqb|^rHi{C=p$pK#K?fMV#VAk&tB=spO0T? z$!s|NozrdRc417zHOxc5nTJAIBY%|FP$R_AwODJRNr?UAwr4lUAblT zYO8U{n#C9u-%VZSRt4lOK{RMkcY)izUH>o9kK-Lg7dl-toUuy&F#fR`=CFJr5>-Z` ze20v^QJylfhAM@(UYqmh1pZ}9@SR}^^B(9RNmaNE6RJaon3b*uyb4E&0@LSnfm)^d zWZfLRKn&yGAMK{1nINIZyRC`=hOit(RjFMqrU;X5D=ig?^&b7sp9%iUxBK@kxZXza zXi>?8e7}4e{NGtnnOKsC975lL=fbCRuevwW7JUk7m!&8+8Hf$DPHCJ^eW$B{W$KuD z@}L3r*~8P=(b1rMZAbt<+^z2;>v^(M)ld;t{=P6>cmIAO#tXYxbK_DeSs5P-iinJA zJXr@DQ+uOj{nSa3ez>1>QlZ18RV=42;oPgjXZNfB>Gl5XzC?c2V`!L9XzTQ@cY(Dq z{>Jb+?}IeIYG$aBWo|8DCHa>~|DjJGb=(FcM}T){gHOjtCNQ}vb}SFbLan!6`9#%h zBH>r!TJ?3&tP>gBha6{x?aQFgP#kP7Td(tvr)_&%rKY^Ly~iC-eBMuYT&-TON4xX? z!JSTH3ptO?oj+uTvO+{+dBb*3+8bkNT@6Zo=*u>z->CTvs;K-MK>&r&eI|y0euHuX z*8M=S)QF7u5=Qy>w08c?#gSHj?)$phPXFF8@&rTCh2`RuFzB)Q8n+^!8LhK8CHkLd z{-Uit#vF6$5r5z67rJjg@N{>2+dAv6kP^1+tTy-cZHR~^r8?u75Zb2t8-V=fZ-(sI z#V`Pp`UAN)!03OHK;8`OAzrN&qXvKF2HhzK!HLq1HSOxGWaMXb-$Wzh1)^vWDsQaJ zju^HyT95sXXiC3rr#Kc@Qe`wx+>ykgBDcWOvp-`*(9qF4A7$)b>~;CM(s+I10V2pF zfd`mV;BuKayvyWY(fj8~#=zhoNz1&55 zVO`h#u!sML#0GRv2rWbr18I=Q(gGpki!gNsIg7e$!tb#$=MOVlHm#R&nLzN@bjkml zqD`~wT4?R@deW))k;@CS=vmSje)#H{3`J`FTVZ~i zyAC`tbhhq2svrOd%t!})p5f6=D`mJlGmWAsSfF}!ey!20tRBcGqERpDaW`?#AeXuS z1B~yA44~*j8BCA2&>S$RYPz%KsLu1`rqHTvlUzuW2AwTig3es@C)t4%p43?v&mIQ( z2Wbk)A|HgMV~AhWmRM??GGV>N42fZQ+GPQJLc^ zSA#7jC1qptsZ)z_c-LO@<)_dDs3?Aya7Yp8Ka2WBAiW5n7`#q~7nrHI;T2igflwbQ zA1p-Q{6&h?#hR^uJAwbzi6U=6S{t9ss>}(|v*|^mn+!;vsfTnrX(Q!~Xr(?d{qg@s z$eD8epjcx0bE6F_4SU@u=4-T~%UD^RpU6qS^HIt|yS-tR4!&di6_4ISKV5Pau^$C7 zvoE%Dn)2!6kaNc&xlJWUa7@0g>}Vy{%hB!X^>%Ki`!l)T<>p*#qS)e!{6{%k_a6A_ z^-W`8NV92qmuqW0c`_(LxLGHI$I)Z|-?>O-Wxe?G0#1#uF4u3=wD#W9NOMQ2E+&Zp>b6FEoa*!k2e&{PWp4(D+*~IKMaU` zgG!|ReY$Q@#g(?fokj0CZC72deN%NG7X2$9P~~E9Ga!3=yFj^6GS6+rhETj7_AxBS zq8^s$z2Yz>2LOlZf_t;S0!L?Fhnu5?E`3Pt5RYmUxu?E<7V=KR z$F#lE?(V1Q=_~Qi1Cmspbqf@WwWhX8ggXJ7nD5QN*-u*~r8fc(`|rdE#g%|f)l}Vb zuB4>I?A+{VhCqw)&>NGR)kjELJzX;s9^j?*Ix?hM0?7S9iL!>7iH^K(*56AgU>ttk zl72FyPNgVD{Ba4NIMw;H?4PCMzds4Z^-z=7*RVBC`8+etK!^tDG~BzT77fAl zG#x*nA`a!7y#3mz2nGpO`v!B`oD0tTt^>(Tg_<}Yua%d~#h^9_(n9IE^YCZ1Yt zAAcC$%*aT*xO(Jo+-X~1{*!a+2mIW_QXHhDq?AU@BfmQ#7{HW=Y3T@tA}DglXV^e{ z%T9lbf_}$LV8pVvKnR7w5T8zWG#?oT!*C`Fd}JqR)&MwwR$7FH@%wgjh|6i{IFH&O zeSWJmpo(90H$i~p=dQCNH$UH~TQ9PcAu`PmEH&L}A?v>bX3;-$h;Civ~%^_;BNZ|`@O;BnSXLffjCJf7qcVXQX*oU;(gwJDNx^B@k> zA#qBshl_uQGjvi?ygvUY7_r6C&@0u^|!j;1ehjGW?(t zub!5u@yL3oM$8}q5$`2YDOL^3Apu?nZ{MoPIP#_!7o(d9x?XGpR2(YLtLib&llIWi z(8={92VP^33g#~rYNeWqpD*|K%}8aa0N>re4M5NVd;~TyH6ua~;7dI(~zglc0UQzvC=Dlc}crCnP`G$0t0jPI=oC4+9>`6eInE zfJScY8&_};uqkIuz^H{xoQ{*K8xb+OfbvFc8itTHo1%$mpC7BH zGD2gu)Kh%Iti! ze4oGCiI5G>{nAGr3{`_ti{i(Tl1QatDGzHm?4qX1mCSPte88}fE?1^vIubVZ8||&` zl6kHaeENsm_S&ZX_kgpkpZo1xsu^?4T=9@+Y=L;jUOQa~hTNcLOXlkB_U8GH&=RMK z6}v>uHzo0z*c>VpF{TaG)Y+!9oVWbgeX=56C8XMT(t#D82MvREp4P?_DDhcOSxMz} zbLz(n;+MV3E>=337J)8Bn#D78wapvVKi#&NSM8sS%C0V+{Dc!Yxrcp8_*u=CQuL;> zJugijJ=Z=z*Qo2VRXY;Ofj@yQZ(P=Q%hiuFAN_^AFRDKf8=AG={W&i#*t6kORthvV z?RhzvNm^@%s|!H^U<$u^DxG6IN`8}6@cQOCpI(eSc+Dwv53%g}h9AeWjdSa*rjUDe#*1(8o0kKHmnrAA%k-~{ z@n2~J6i4BO*l+QCyOVhSl&IvRej)q=|GD;DKoGVsxDewVwv1CM zS;2Vdc2%?3vmB3*-s`Y_!N>K(b2iPh%=x|oWa|;krH03_JQ#E#iCTte7Xgxagvla<%?Fd z8Wc-VRau3Kbd~*!s_fN>`sooaZ&c=6(E7LKG~lUXIStK)rHicH7=%dV{u2v|C&3Sg z648=$&aFP=;I7;=oLY6PNwXhVSlA0qeuLLrbR-eYlBxW=^w=AopSQE{FmvXueYX`H zncjYR(osHJ!rRo8^esGU+3gI(h_%&Pl||)pwXc|aKK!eZC2W#u#cKL>q2u}Q>t##F z^NrBccw_s;`mX<+uY7rZ6AcEU4#l^GxyGi=9wE z^H{K`c5#NDMpYm=`O-AS+lEm#;WX7U7O4bWKM|jpfM&ajD)D5x^{>Lnl*tPtsVrPx zoN7wQ_-9yUVGJYpngQdT*h66MUL|zM6dfIQ%en4Ra>t4au+{BG8!cHU?ca#=a+R|9e8^n1XRPE zdwYBD%ahxuGlds1lV?dmr?t%2f0?JtY|m4#Cxt=%1rKc%YJ>l6`vYV(g4s zDfWo~n_Q+(IJ?R}q~euNpL2y=$1>Xpgdyn2=^qh;>E(5w59b72pH3dBn$&Tz(QJht z+iwLt_Ex%f8Ou@mAc@x;a2;Qn2zhza=dO#VCn-DLH#;H-H}!t&FORd0UJh`05S>eT zfWTclJx9XFzXRWR4Lfv-PfuF-1kcwCsd&|_$jkdfOVp%+fd=o>t?N+3aqW_`&1#$N znj@Ej&8iwX+3G$o4p=JhEzgw{X|$GYeL+ECaBy(x%;Ckw#gOjJ|C|5DbhnYp0QG9t zq8=bT22*+6-KVmua|;U&sq7GQdwWTv4FGCJCPL51{UAx7mws_)UorXl1gJl$Din?{S|UE*=7#CEU0C z8iXipd#}mF+JmPj2y`khbP1(Ao3EHy`2nw$WA&6D&?Tc18md_lgLgzGC9wJ%n zG*!4hjfz*B39UlThh~)mY`kx|u`ZU;sKUZUtnBQMuhnKhh?$K3(i8I1$n?rDzdZ@#K?BDye$VrTd4(+F*Cg!>D8 z4u@P3VquYhn4%%T=e!F+PZLJTF78CcdKWGhjRH7D^}kI?nLBw&~6MI9C2w_Sau zQj{as?I+B)|9fnE8-q*^`D_Qa+A5H@oN=rDmqfxx!Z~f741r`#cQdIZ`QkxH_^Iic z4c)>KasERP7bEmRj`~SmE`?{|kE%(7`u&f59)GqdecXD^Jq4xaCmn zBfoh?RCshCk}bUj%7(BHGk_~;qEYPwF~29p3ftLP9XM0XD`lRZ=V-U>AFYjgE0}5g z_0jpJb~RRqGJ!OlnjHNUJovb5jRsSw2drM_K7qP95P6>poErom3_FV$Sm(`6yuQe9CDz^-BpRtz~ z+N#J>F>K_fcrwicaB_?TV$+{LleQmkFS|Bl`n65PH|L80Z&cmd(A2Uy1b%_V>2|x`6@aMVgRJ62)#>T)Zh>w*#5Vai`9tJw^LR60rBp9tx zue)kAiUDa)-uM=vwXm<7v9EjGIiphamRKxP)WyQr_iibiZr{D>KWKAs1Yi+SQ#!l3 z10MOMNVY5h8^mJOy*`+p=`s(Hd(X;|Sf@Le+p-GyxH13^L?NgSv7bqZFye(-{bCG6 zT3c@y>f4J7OHI<5Rq~zbWy&?_6@%$yP3V(18W?{}QlZH+?b+x~TTW;&F{>QaVWH16 zP81VlX%L|nPdb|Hi%`{gG&oq=io~ejqI3u+nqNw(on)XtFIlG-n-J~s@&!hyiioIz zeVZpfH8%$j?qs_Mj zC(Jk9P|~5)e-&Vi0zsX0Y+BLeYVVdVtR|bvIxB-xb9YEVn4R|#`l-6stUJ9S zbMZqiCzME+S-r5)WnJ#RLwkAk)|l=l=iq*RrtRi=UGpkpQe{Y92?JDR^4kk(#TBPZ z5hBgY@6|8C@5mbQ!smfh^lIwWdbWgjjdB9!gaDS+3 zQ}?wU>NM$S}wLF8jyXsY)f#MZ-2l>4WJ9fb^bZ=Cor$u=iJ5?K0=M&uYL zCVSrp3(GwpCdXIBkJanSea1mw9b*p#-;a%v#f7wEm*E>LkJ22G3>Xrt(=P{^zsEfG ztMJ|!s6~zI?uV?63HTgH5Rsx^JTG5O1u(5RL^4o#Sa>+93g@@hcIMWXiOKA4imBgW zCzWyVv$nIarM7yH0+YY+?=YC5U6Uf8e#P^>X4JVCwE||A zee=oT;moF+4mSM~n`rB0p8x@M2H;r|cv2vUsmKV1W9t#c{7riuJg=7b(+5BoDK34I zDVIuOex)){bA7j@cUNfh1R_nvrm8=i#qwudw)8LI-9M>@hmrn=!&rZZnPC5;A72dk zYfRbTH6WOdnr)x+qo+Fm)^lc_Ai1Ap8QhPutv}tGuz%>tZrVz-F_EJ?|1>!-vG->@ zfumJEFanctARvPIv({I|V)+)maxGJHC=muJ#QTe7FevWg1|Sxd6~-6m7gFtTR8bRn zw#d=xWG$THk120Yi8w)MU{1>j2GiD7{4D@Rm$Cvz=m&dO0#|FdfLoC{hTDDvYA_J$! zT^z;bY+rO`c-L~WU4jw8GeZ7W)yKN^i7{7W(*c$;hcz)N*WJV5 zg(Iv5-*Hr(+f0jlQ$YCL00l$q=ziaCV_8Bn}WocC`S zaWMTecSOs4^Ioks9rE&?>DALbCAZ--+{y|!-gH?^{zm$9Ffr@zr)PR zw+uz)G1kk;%`DWO-2|jHTv9OC%`G;4`@6e1P;HV*JD1E8ay_V&ZFC@6JueZRrol7~ zXD2%|K6$+0+rRTL?tfc3T$h26h7c(xV-gTb-A3?Q0QxClz#C3T7n2K|9>DB!b+IED zPux`>c_aWu#3VCn`5bUCI>ve{L zKp_-aR2=R@(J?VkxF6S{^?`}#t}W>OZ;tV5E{(7@qC(!P?7fyc=$!rN>0{3~@@pS28wABFm1i`$FIPRuDTr zfjTzGO}64!=We3qlT2fph640OLhNih6?EIMfOdx zf3>b)(ySPp|MSsTeyc_BkiXhKjS@zEy7(JdIGe+w+u&x&WT*d_bYYJuq_NlX%iOz8+myhDBp+h!lVsMY1a#Q(+<*n6!C3vjPwu_9|KKM7V};S3q!z)X-N3Z zh?*K3I~YPQ6M=!*{sQ|O6hk55hl=(7&a|%otGF}%u|M5a0MJamlQ&kOwlUun+bB8v`2poX;T~WY1yMi zF`*{1xd~*Msp_%~3=k#ceo*^>QSl-JpDZ4G1#5&_M_9KgCOw!etbHE$$y0nX>ULdA zELh+tdbA6K!I2%iI*`S&ULpH8BhA+rhkX$sTg??GN{4}{+$kDf^=&Su95+#R!5T}; z8ZG}d&8j)Whv0{!oyVDQCGP*lZ3rYjrJG4;SdEy>xP|FCIffpH<&vi3xk` zpB_!NoD0@9Z~juH5j_UD7%wu7|23HIL<<|#nfE85dr04p>@g$=g~2i;y+62`b;GB< zjiWFkBebTGgdnOn@av^v@zaLk*)J%!x1^7?!+9>aKK84GSJVQ_7nC)|y$j^vbEg&= zCj;m1_E3mfm8f1xPq5ayFK-L-!-&2Msz$~Jdx|LDB}e=-(n1n9k* zj%||3P5*svoXJRtqECr%`0&uNKtpl-6j+5=Sy=%VnE`Kyt?hWY)NQ=JgYQ%%NiV>< zE3EOGY?^*_vY(6M1-W25uh%wbjpF1tV^S&eMZZm#j{@@OSp$c~DR&VMlwH%Wtui3#Y* zM#}?xkGqw6S^n1HNi}eK?_mpBVKojNsP&oLx*zU4uDm6F^~mW>kmOu8gn>cMF)h5sX~qIxYa{pCo_ys$XQ8Ui0!28o&vlGMgUm z9bRQU=1@dHQ7$oZG?OvenPOhc)#RG-45rT7p2Jj3ivb~eoErvaKj0Xzuelh5pl@e? zM~M+i@YS_eoA$3C@g~dgdbc>sWFN?v6euo^~J1^t6|AMyU|R z_{;eIH=KW80YB7My$aU1E+RuG%6HRbT%t@XJo1J442^Xj?=?$!w9Z%dYJ0nz|2{u4 z`LVURS@^sv+HQv0l<9EJp=E#aVdE8uOQw7EY*V4c|JJe<`D3o+c1KD)BYpHo)GsSl z)f_dGC5nN{Doej(^82p2gUe5bZ0J^OD*ayfuamo*d#NH)rFQ%h*CW78xi00PtyFBw ziaa~D`Jwu&F|uWp=B4+kXSIXF?WYBC|Js(Tc=@$*I=u77u4~{@;?uvg;Cw@E zovcL8d>A(LM}7}8;F~NY-_7atGu{(Wh$GW`#k>Q{scA0(fH6U)G4=ss>uCvBqnz0) z6F<^1fYn4Pl7^IivwpehD&;iUqAO^)b3Xsm``Fv4k}x6d!0j9C5f5)K6{q0)0x?>d zs5B;`PPT))0iP7RsFFbu7yVDKcLVsF4b zJ95BGAgrJ@_0OOjqfL)Cr{3F}FZXN1TvASS9KgPGr#9c`SJDIn_4qkNb{FFLqfGQ8 ztnDaRA$XYa-26L{z70kK^O%#F!Fyw$LlEOjW08$$UUFQN%MeB4#;2;3Hq_LK!4|XkTZyNJWm;@3tkA6^H!;FckIp%*)-^ie0iV zl;}xa>*{ogyTe`Z!i^jl4-wO9g5OB2zs}e%q5xUe4Um487u}=75VTQ_l=$1%&E0Cj zP0{kR*~f9=9P8#B!TKX#ulRc&!R{O{znF`?)!qtStII*zUb=_!ix(LSeA7N>(ZbXP zRi)aVMCac+4PzzJzAm8#os{a0$~p4oTf(@MwtoMPziX=X+YxSFHocJiiL`bG$Rd`* zgGE+mny}s;coBgtqUS^O9^G}H{evQ8{N?TBq&$4e`Z;x)fE%CV9oAbY1@`zoyYS?jC*`2Ozk(8ur z^j*-!eh*V)O#5cJR}?$6;GYHjO49w#pF516BJ~<9-$E`2rijD@HM16V2}HU5Z(PeT-!TE-f)*P?r% z@jooXeK_3XYrVtrg_8CE;Kl|p`Sb7g$P5;cCdW-g=o$CC~m`1!}<$4tan0Faz4 z#$lTOd?Y>@-JbkNIEo$=AZ@~Wo<_j*5oO@d!z%%V-j`X(#DM7%vu% zMi+H{y#p_q5Iu|Hgh$DM%z65%(TW*(O6qYeeaYGwew9~PKdn}!PySgqxt9sQFOAlr zna;UC7U;t>A&22_Koh>5$ED$jvMuelm&?`yn^<8&gm?D`{$QU6?T2wy&1HyM1Z3$X zv6?+9f!NZ=$A^bP{BkiEIAP4E%l})WN0pYYBJEK%Xv_d!fD!``Rr9SH&HGchvk@l; zuxj+mO8QSOF@L|KG@G(#cqKr&pN##@S;l=cfg%e%t=9w~mVwTVDyN|2OZOLIUmo+x z$}%4KF1FL(bpTrOMG5{`2deDM)VXG4RZVSDd6UkncCjXawgQ_Sywe5-52miL91U|{ zGUL;wsHEnf18+ciU0r%M4>hVXVeIgip6Gb{Z}YC3r?Z-?)xYN>_NhR8V2` zwmxC;mpKDH1j6orwC~|_o_O)Qf%*jzEHiDgId@bJLW)WwFK0f7h|@lS*u$fM8mulIxT z=XuGqL=_>a8u4VDftrg8OSnx#w2Eu z!*xL3O_^rDxSsoV_Q#r&3>7bynZg$ZkJln#4y61(q6b!ksuKlS&|PP)U4F0{4t$PA z)Y;74y_TzAUq@#|4;Z$1`}z3+UiAL{{xz8Ztb?hljo(b+7yI*X(ITX1Rz+f29YaHw zTwwVP`2FDbz}qoFfxpD)C={qQvIJO?|8*Bf!mL8$DQRh^1SIG8Tv1h$o~U=v{%yAG zx$D89Y+KjU&gcU^?*g7^(*toV*!+dpojfY5u$aLSu`Ut57?lg5NzefZ@ip!*VsrI= zH!U~U4PpI&Hg9}W)IDJ2amu$WdR3#56$;U?C9G=a??x%3rZ+98-hl4>JL^e^45ofgpW zM^S^x;P+pGp?n`{i>wNWah=(r#kc=P?QP6QxUDZ}Mcr)Gdv=uZqSsU$@?SW#Sf8FX zC5-0u9A3Vu5lztC9Jt-y{Q8u#m>ZR$FV^O{Y3AqI>VKQTc!bCbq<`O&`uJ}BG6Ey} zso40{-o*g7YuBuGUAi0#7qT9dAPWWfo-_{qsgI2N$kUP5aF!qrFeXCPMhjXZX%g+6N*t zQx97!dkc3n;eHo)u|78?L&_||IT(ST8e#QL5%7W}H=%4}0r_A?G9xi0>)td&yH?R% z@x!&ge);q}S~?W4QmcfA7aA9#ncq@nqbjamQm`T?XT6nQ%8gu?rXY-dIKn-+Uu2WS zQ8f2vc9`eS`20j4KVKkNTRndal9)u$a(VM`^hFYRuL8nm48acr=YYu{OmnDD z4(g9;)9qV!2>rGu=K)zYdroWwBOWB6jTjpll%@bOX85M#90?Qh0bxJypOUxauBx|*=unBKT4m*EH=GvbbRm|B?l=y9PatN@H{hYR9bXR$J4TYb&9?i{Pi<=rFVRFq>b(3!t;;}fVz*YG z4!Qdq`1@WOdWh3Boh$tM`{NnIPe&<_OuwVURCM&hvBbhf*TPF)am_+T@x-OQPd$fO zZ}Hn$)xzSHHdK*8%rXdYK}7+hxyF;U&ng_n%k4q3@nheUWKRiNbscgwh8p!y7GruT zq-A}NS(P|t`f#uo^yusfnDQ$46n7hu?4>eu8)uzYrHeB5furk)wwYq#SDZCzTGP06 zK}-lxE@Ye;h;%)rrOnJrQ{i+k3UV!C)kAaadzHcO;qV+TvVuzAY?#) zua*ZrfkJZo2;z&GBQLU&G?bp@e*5NF_Spgwq-eU+Oi%xs9hhu;NsLU)7(ZmfD=$(Y zpi5bX#f=7{auGjB|MA^1%Df_YilpyfE!IS3aRXEMt;rhN|Ad59Ni4HWBP=2g0&1yZ zjd5tXJ0JF4&FfeT$WQty6d+XB=GmL=zstkO0fxU|3WBo_5Co+ewAHQr2%a=_>FSj_ zoOF>ZO}D(IYfv3rYqLne8O)t~)IX7HJz!eJ*Vs|@9< z?-*x-yJq4&Ib*X0Y{GZ<4}SS#m(dR==l&LPSyYoD|80kL038~27=TPh1G(5?Eso^M z%F6JkULW1u+?<_{+XJzHv@Lpir8hQP%D?sRum~VdO?j@L75?bNQph#JZ)4OJ**g$>-{s#qV9a~gRAka2gKLu6fe|4s zd-xqo_U`zvFyb1Z&M*-F+o-5nVF2~n~FdgS;$no6(3v&cE|n$6AaZkgmxS)+AE`kwA}@=RzEktLd{)rm>-yrH|GAwWj1dGO3FP4mkdapHU}}_> zkCZvY3kbq&{(2r5Fwn^rQ($sH`7iGzp^C6WjEr-DV1NQs3?fr8FdcxugM(?yoXzJj z;%slbtqBXHM8tt~Ulg*+b+oE&wv@1puAc60Je8O(C3u%E_k^dWv*p9iKX3w#gvW7N ztZ(kzmVy7tV*^-XqA9R2dI#_qCI*G)Y^!{n%>-me*$b&snH6o^NDH1W()wS<_@R+! zHpW}c*qCIMXiPcV+z1}U9hZ$E-{Tn7ED68;#aiEIRA2N*tU(YJDbY(H!13(;!Dlp>;}Dz5g2R~P z+&8!R?*b79(Nt5xRj!T4o9M}m=hDB-gAw_9DEFp0u6|ZFHUPcy>eVZc{aNHe%LU^y zP*?t!gayVQ{QM`a7cCAC_je^FCB3n93yp3&V`Cb1GlqtSb3n+w_-)bjo;wVon_{=n znwbiS(t#j8CEshe7QmD)Am9opm1}AQiA4SHZ%tz*&<7WJ?9*-j4=b@!e#_mFOG`_D z#(BoRX)nurUw5ZWIkgx7y1RMLkuMzQdhfU53Iem4LMyM8XyF$xUi`OX=H{c@XPcu= z1p4F%k7<^nCt{ERSy1#mybpFj4Xtm_E~Wh5rnREnfF#@*G(Y}o#?6f21+?Bpucc;e&aQ$T+r zF7#e~hY?2=it{wGcIt)9MxK96() zbEXfJBI82O3d00yHvFPX2Ooc@N29H7P(7*e>Az1NIfs2R6sc|*Xr*4h4;>9`t}oV`1}LmCu6a@33DsMJaxotSWuI?Jr{znz!! zpnGYT$&F^Yu=gU4Z+>o@@KGT>TRdJuXfk`}ZGoN?Z(HN+pSr=ACxox?U%!^$GMp(q zVSL!Tko0@_?Z^CUt6`}7FT0ehyWqy`&ZM%Sz28K~jFBp`=p^2I{bAzm;M4xcaT}SNHt9ZN?xQfy@a$Zcc>0uLUkv9G28ZVGODBQZG?BFw= zJ~YhjvtO0%dpIhWU1G77elg^?5iKlLVY1+R;5a``s!D^~`uz?Y*sH0iu120{PMqDv%l*?E1<|Cl zt5kI?#;DFOU`E9WhgL;kIy-GCb?Fk?L|XMSJ15hkFQv81}Vbn&l|W z9JtTGV_!DeiTK|5UukpSl?mV1Wk0MHT--iNAS8fXV)Cmp1ke{i9SSo= z2XHBb5ArlJ1X55u!oaS845ZZBr?M&w)eX=D5#|sqo@KgBSd)TgQ0`Sz|C*6wWRiSo zsVt6%Gzi6#i67e3!6J6rbqzjG6Bw&f0=aTeB0ws zSV7b{qoyL0r-{-~%+uj~r#Q|YmCG&zhoP0;aYPCc(Ob!qm!1Sl>vMNwC?ZqDsXrBV8Jv%in%XL%)Gh zlaM4tm<6{!=K|Tz)jkh#JfGFwu+tU14E3K26{e53k0Ho>nML~I_{BF3**G!%X=y#1 zb!Z%5M*8aNh|V2*$x{VMsP$WfW9FQ7c1kabsx8tpc&6*$+(})(Z91nlv&c=TJINgx z-OxWCIC6R4oMUjb~%$$e$d*m-4Wiu2}~1f5^_IzsM+XZ6B*^%=xbvH$UWjY2A$RKaVx03u3>!ddm4LIMc=a{$MCm%+kUF z*oVmST#i&JI*DGmjCMfw>jTGIzp$~#oLj8K`M>`T9$+5~_~Q0WxHSxo;5h-tjTifK zpCX)KqBf$Qxv#Z^;y-=xERZ56Lb(lERGETg91wCCx)M!Bk2s{7KxZEDtK}*0~SM}L~#g5IYDX}5TZWGHu)IO?k@@gUJqH^ zo$l;%2^VDN-b~E|%Vd0yS%sE*Qg^N#+@v$)?38;W-?yxQ1_GzVve%INc+iMRbWhc8 zW61@<`L18ZCPMxTlbqGruG_LGxZv#JYJ5TRaPd{!gSj?aqxR?vv%`)=!n-lTg`2yZ zB8wVH@wkVhzUA_kjlHOC2G5}Ko-RYYI3_M^M@*t1@{jByABq+Exyy9eB&7+|SSYY( z^POmp3gs!^W5`9M!I>z)(cg$5^sEs?9|9=eGqeYVKM9tB;4ucRfe6=6(|)9>OOlWV z(m|>zv?$RO(*%@QjBwDKZxjTlDa}>><-6hKR?Jq`pNT%ugRwhud0rl{%kKC<8Pug0 zoxiNzEiy5V_oL&~UdaSHVaG=?l03!{%^^1HM`-XW{-Tf2`1q!KU>=aSWo^v!V-&Kg ztDAj#Y`+2(Ck~~LM3;7p;(}WI$QhD+gnK?BBGIG;XMeVj4Luf|Ryt;SdfBA1d!CW6 zKJHf%hq3?K=C*~>2ZRu81|Z}c|Ltv)D_3V zt&|ZDwsggiZExQVl?lPlcO{km9aAwH@cLhZu$CB@%)~Mn9j`Gh#?biDuZn#o`CliY z`cH?+eOxK$$>T9Tczl^Q3ph_xy?&61gyyo!W8tQIsY{(@uF}n=DsA4gf6)JYm zvSn*}CoP$yF(`<;^kB-U&O!f9hW>Ikn9y%r*xwX}Xpu3dd`=UzVx7b;Q@dnJcXbHp zFXBSB*DDn%U<^8s`!MxJuac9|*Vbdh+Y#{h7k>w|tuy>+{iWUq$BeJ98Ixc{*$mo& zDq0#o`93Y%i;+6*kjrlMFb7&a?ernv11LkuoXVhq*GznNELZI|I5bQ@T zhdAsS8ayPRTz2L5oB?$ZCY)gD@J`|Dx)^9%svj#KAM=j^g5CsBFoE zo`J#cnb%OmV7jpP0T4Q$JGhwHJ5N-V)J18bYJh|l;Ej#swQzD8r5HcBI1%TLl6~d| zxIL1SllNxo00+C@c~$mvqzJGFMolf|cYAqx=~xuFSK0fgF@hF-b&DZJk>X(5%8_hVoL9goyISvui2k0Esj3q0v z#H`$#K$}%RpaQU}6ih5rr>;ys6Jw0wL}YA$p2mUV5wK#B7}>)R4Om&);%1yyM6Mu+ zUec0o^Vh}$SGn<)-SGYH5ou5I^f_jYs3&eN91i)SJy|u|`;O$5ASj1EjaP)OAc}P3 zihi_Ecyn81O#TL{`Nk~iQD1xv53f=jZ4TKOG$o~&{qcd(mtTQ`leY-mHFeeC@M3>q*%T5UMi8OEsm zW#+hTp8w+Q!&+ue)49X_TwB|QDV_InWN)vq^6mY>Lr2?X>chrJ&a0JbXTVM9g>t{Y zMZ&jTo1~6Z{YtZE4(@OlMz=To&x`zPtZY{kvzx;smPPCZsA9#B`;>*}3>*afR>S=+ zSF#%~VwwQ>N2-yr;oZT*on71EN!wzfsrH>UMkzmoSoQa=ytjTlY>d_Psb>*%%*NhJimI zKlr}ic}L9zI4!A4HO}vSt$ySfm}~Skgowv;X;IMzJi@9NmR6(u z_Gq9R(#6?!Ho-4!l*k(S<6WY)pu%RRp{6c3uRvPij~ZK530d8q2nO(x28PS(-?85l zWN~FYei!`?1S_U@e(_KY2ox_6oIr2WZ=+Vs+_f@zRO$NhvT}T5MpA(36eAUjrH6$5 zGd%%Vy4u8Mj@B#R`Q){O_Zer5|Nh8*dYPXWx4|r{(bu~*?0WxVurx>-OsunavScms z1ZFe$WHuo{c(>$s?V+dcUe5EPP04}sD0bHJ1nqKjz43$yR{Y*g%n+MLmIi_uL5#x? z!XtB9PlydwXA$b8q2PSS&oA)~)+(MuiYQAup0_eDJuBdFZW^C!unFgNQip+}QZf2& z)XIgY_k@DWh2?L$(!DpnrR1K-=;**HWDh}qpP5yc%{w~oVr6rZX-{*vU2%jj#fa@s zDAkBzk#X3mJ?aoEQhSM#)PjHmXfUJb8FLi2dT)Q|;SCdN%^1EbmOMPHwD&fTBfS%+ z17Hkpb3=PgJwLOsj_B%F65U69*9LE1B8LYwTaVD>%B(94^m_h6#vAOSP}=WlQKmC{ z8_4xQPt*jSB#&dAlr*AfgG}mXaRr>Pfh1P@hX>zuDUn9DzP?KNs_T}P$9XFj6Mj{lt4!Rt*)m z#JYa%&{@FFX{yBfiinjS+YH9>o?tbDGfMW>t5i9GxdX0iQKQkb$sS{KmSfFA8kgIL zqsu*fth6}Y=V?oTqXpONo##ggG`W?4Y8&T9l@n2ZO~QRtXL?O@7+_|AhzU#Nv*%%N zjt)R^{wW&n_=ti=CPjVTa(~(4R}QGTH%Pajouoa4puU2YSKx>@dFrYw|HxBVenEX4 z^EEq^#NSmDNwcC9rl7VE43M<6)ke_Zr+s>S_FPi@N`S-<$7I9+R{Z80Hn#PRPprvg z*mo$p!c^~Ng{4r#+2>GcB{y9hO(+di!18?O`s2+23DPn$8ADUybg}3_;^{^fz@Ou8XHvP$KDuPAhiZW)?8grKMmtHAFJ=_E;nR>+L~i~ zon{X%h$@ZB>t^=uO?Y0;a=j(_BW%FsH}h3(V671aLmvFs@Oikq(6<4uj&3Q{7V7{& zL4!hcBSMq7R|z<1b@4SCO@2&l12fi=iN^cuokV8!D0oPOk`OuLhjr&O00aIE0iVAa z1I6U_c^mT=PVV?dww!h@iJm`^QCLRIoJM0f%63L`Ek4XEH_U$ zC*&<;8ZfbBx6H}qHUF^xazZHfhG}a2g(b>^LYW!KL?b+5AiUpwyQ2t0QF6#H+=FKP zc``)Pj14)^ypdL4uwZo&UZ|h6U-&>u0SK&=aF#3=o`brq_A>4GMXC=~F9ak_=bjf| zuluf)w+Nk_bf7ug9EblrUho;$Z#%=4T`XruT11LrfJ_X((Jqz-(~qcq69mgBpNG`t z{Tjq2cKn9H0g;Pfib#j;p|;+>$j95JN(AGO264!~?Fb13wS(RT@nZ7^VNvjKc~US^ zFhVe+ct}K&V%zfhc=J@uf6gB*f@q|T7n{SM2Frg0>~@S16cU_?pFbR?~u3+iGpZimH}O1mr(8RkX)@2kcQ%qHzDjsaHwxa zno;k02ix+v-tMP%j$>xHhFNI9$7o{Ac*Y>{enk6M3PpW3V6@5X$%B`H|0ap>xSpzs z27f0)?U^PRZO#C^!Dbw{O+C1?MBLUJgM|-fJigtM4&=Vp&*!Ql1H}d8h61%i5(JN! zn4U-0#Ed?K{*83!YO^e@rZhXhln@!tRGh^Eq%$(4Jw`pmFraj*2M<@tEAQYgWOK1fZBFx;~^|a9UMukSwZ-4do zlthy&>=R*HoP@)S0I3L1#3B1D&0Vd7Z`b|ZWa~cl0_e?)h?9BHqaW-shp?QV_*r4VDsfD6>APY;`+(0=d@m~NV{jem5(K53y4bVpg|E(6Tz_> z_Jf(@8EBvaQPl=LMI7uy>OZ`S%1|bvI6fkJ4%rR74a|7Vf8QrL_fpxTQc_aNTCc4c z^>lRsbtC|>ty}QB370(0Q7PgFAlb;1b+LnH7i()JH~Iro^D)`z=;|0cgx z_4Oird_Z$Ob^2XlD5|`ikdRQ{2FS=xqS0dl&!7Khj{JR=5ujK*D(^EJBe(t8*_I2xviQNH{A((%w0u#<+a*voU69ps6JeC z-|sHmhd&%X+_ycfx7}_$G$T*Y@_E2G?l*9Rcs!gLOPybuIu%r!TWtSk%c?&rOgB2s z{nD*?+$~2)Tfd&x{zmEH+~Hw^R=i zD~|h2HmYy@9=RpgR%&yzd?)O@4`MAWoWDiaHD93|8aB$>d>?Qn9li7l{qAQRW?OgS zd!L4W(j7zRsRuztOdx61xG~mNZq~U!t@P}ugmQ(2UwJei>(id@TH92#e)pQ=xT)8D z9em+pdDp4P#f6V2Mx^!)b8JS+b28OvK7vDA`0W1o_Q`HpAll2UF2A|TK|q|bo3&rl*sQ`xj`Y5DB2goCFZ zcLj+y#0ptjB*j!~CD8WhbOCj&*bus{y3b`&rH*rA60-pbww?MuV7`UgH-}ya^Vg4zKp{sWkpR3n- z63@;%A!2Pg)F@sN%Phkj`yz&sK|^+TDn|}uSWT(T^St9mMm=H-Q$vKUJ$3N42O0lG zV~ao})=6S`ERBdGKmJNs(SvAA_VGjM*vDzQOVw%{3npZMI#igLUHe!2Gy5xOdlgj6jx7ItGY-X+u0)6(8J63=2EGr)mpS{)ExRbYN_pP3HC_bpG*ir7TwMO^M*J6dAZs^W zhX(mb7GFPmZBU>w1q@1oPflJGBl|m)O9yo%>tHZRR&Zn9Opn50O42_T6_`sq8dl}KTS43mX?Y2C z4e^fw5z=5-1ZL^-@s*=JS2OaHOqfDNpbo}t+E-=*hQwwD$A)@$3ZSuP-Av}qmB7%qm^C^Qu z{W1M{r&crZ>W0V&(MXhs@h<#OcHzP1335G7mWI>Pw|C7+FQ0U9IT98ro5INLvm_(% zbITnE?X1T;u-hCRJxcWRqUXDSvae$;2qc6I>^v)ZR0f_gp{{{K zR~gBCY$goQAiKd`Vx)r!;es_vlg_iMxWcK{gN?+*%2#rX=Djv6Z(_0~<((Ofii`J(J~#Fus8%nIy+ zkgrpbV6tD!f&I2b4fGwjT22>yVcN~yJd}lMX zl?Z>HZ|w{orJB<;4cpVf2M_JIWZLMw?`hqF4qe;Z+jDdcH~$h}F}tKWHHzx;KJr{& z1gu))+&@){T54-M(UkG1bfG!NiFXs$g4}qy<>QNzqyq-9?=bQ4Hq~wfgR$Kx%Q^N9 z&8YZXg0xxo>k945S)35s8-gQevZp@JHp=aUTgik=TR3-rWfQK*wAEF#HiKcpVd)H> z;8$Rw3-rcrG;dmU)Hy5w0Ni+{S7pG|r>3Sxs{|-;8-S7vh&=$EYCtO3>xA?K2Q)M^ z02lh49EJnmwgt9afRbP<1VDC^G=S^-41n7P?0SHPnv(L_yVJ6^`)i;@?Z5ptJ1s4Z zu>b(^qH2Kqy_uOAkd^`x7*al$hnt(53nic|9)j5PR9eN1#V?EBT*-Qh2FZB{j1F(G z2y7%s5Tm5)L7=aXcdoE8FyBzTHFyDF_Ki#i#C_Z2wBQ_IbvXSSC88WhXbOE`KLM3V zfb+#EKYt=1*lv8d$MtHl{~t+b9TZjHhT)}`5En@aSr(*Ikd|^mx}`&;8>G8sN$HYK zi6w*ur5hwwx~03jzw^$=%+Bx^FvIRSzwCy`?Nen9)l*Eiq3i?EnfHhauO8UhwHCP^#PEF6h z?rqZno5>(nw<-PPWxCjCu#*FQcP18A2qx|`IVX&WvHFxeROR(qUN}>@q-ZcVcSt}7kiHduSX|?=l-fGUt$#L`$2B@LrARzKxHFev12%O&iM{mWCkK3Nm z)rl+^RcW(&HQxa`)yLbVfSvJD@0N$r$Lmp7;Vc!uoyEMojY;Gj5HJU(>gF>a{GHQ- z=WqWQmCOy-?(KOC&c9Ba({gN?O=2wJ+350^ciu-$9n936`aJfuDYIFpml^zh^M=F0 z*;%K2bY6>Aayz-}7R@uYV1-G47)+WTo7@w?@xG$M55?EWw*TeK(8 z@0V*j+u%^ZyMq9Ss6kL)sI!*ttlK94w#rgj4^wcX-C#5|OO;1$(Nu%*639A#=y@GY z|Gn=U)lS|fzqh@#r<$uNU*e)X&-<NZTanDj0D zL*vog`!G;C2oB*!$i*9nfOIg_L*Ipdsil6scgXi=`*wWv#n34ICZZkvkIN@3I#!0Y ze?)<@;cO+w(6~60nXiieDyq&DXA?S|&&xGB$4F%P0?*K3xs*P~tswZo+i8B@au7!N ztE4?H#C)30Os9n|QIE;sEBU9R*H^bc!{rR^c1|s9U?9Z$)K4RAD&~SU_eNfL6MPx7I`)G7n{s;O|jNtxS z6^TcYD2ta1_2%d-HnE!eNcXbD`7L9o9D<(v-FsWZlx#%m9Fg|zkK#U$ zG*D~z3Ece6OdoM_e)_*!7S}svm6bM*;|n_}_Huy?aXFIHVUoc-P3;G{eRE-07TMG0 z7G$0n1?fRSCcxZ2v|Co{8OI#bVdkQ~`PZjyUSHphMW2z|RT+!a+0r5hy26svckkhA zmM}4wHkZ-SOc%DOceHPE&RxaobTjb4=+7+%Lj$Gb!=25(cM1v&#k`ItuzOCb%x}x2 zqR_@2vdj&|0?Efu+6WHOu;99}{Eh!?p_bDr)$)l=}?_a5qX47w_mJgMZGKPL~kZk<|cJWQTCtVLOvU)piY8Umm= z@jV?zoAq*Rwg4b%X(yE7HA;K8I6XbxV}HasS@91r80VZ}W#7EcwuOG?9n0K28o$Gl zjDEt%lx^=uv|t6--{i*2iEYD#21_0(4b#mC<;7#GNI=5kNaO$N?J~y}NZ`nuYyH791v#oko-1OE*b^ivin0T0iyWq?122+XjJ+v3{`{8ifaBYsCa5)KZHJ_ zIIK8ir!4pbYgM;ys)hUTu_Gx*oks;6{iXldob?ey9{#j}JOp(XH zXGNsX-Y5JJ*gFfq?`Kfc3F7W=@=}{-kV^_twWhHG8cq<`5t7MQQX~9>ul^1M4Z4K< zi+*1GmT@_2j#GErb@7}lV10DyQee23LL>^V;$V9mJ@q9Q1Oac#nwVb%63U01hDUZ} z1aM+F@+A_zBN6pq^84a@o}Joqfg}FdkmI>Td$;V}bXshD*Q0Or_;z2J3DUZKUUmPk z;LAnR8-@ki4eJ#B#99>S16G}S7|L|`c+Tj)tB+9p;^^%q6uVGUm9@!4Km|t@jpbzF zT$KpotrZ9OrPM>eHK*H9U`k1569%l`1Y~*Kre*tFo%!$KO*~_!7LLNu6SWh&m|)YG z13L#9GJcNdLr?n50Wrd5B=6m9edWbl9b-VIAOlKQKv(*lS51c*p=m>VH(|Wsyj^r_ zeCcg_pBSZ_CHnKn51pzhASzPtxCBItfiHl1|A9L#C+ExRblZWeaMv;fR1DP2?Ph`z z))~MJeM}=Ths=-svz2_RM>uOd2SAKvuHN3()^>9=Cjbalzwp1xOI^H4I6ihp;|cq@x#&aAX>e7O z)4UNu%M6K8GgmH$Ib=)|G^qHP60?KcB%zaI21w?p?pc7!it+ zNC|6?6vTG5BVm@@yp5^7n*FgvWhb^MfeCgl*iLe@uu_j820ZK=-L%(yw7?O2xG4}OLF0I-g031r29gl&N+hfX{`{C?$z=D5?sQ<+SeK}Xapn_xL2LHxk=$!+vuZZ=br>-P3 zF#{&9T(qh-)6J*KmyT(;s?~*>(xro}L>L~h1F9(+^`_06zy-p$PzX94Y)c>$NTf$N zNi7%}0iuwgGXn`p5H4bfJLwQwqw)&}xMfr|AfQ5YhW78czwrV^F~TGyG9qtC({&8%ruEkWr|R>U8iPK_p<2ZhN?@efeQp>EZhmZi{9er zO0w5dUEHv?GviAB7Q#hmm41Sx<7)K!9B8GuRAXdF1I4$qF$ZC`cXe$AnLST_h#&=n zd2Z8-J&Gj0V=^dXQjivKM?RD3RCA_%XMcqGVXYjqbHs~{?(k}LzZo7Vpy^G;Op_3I z7zh%DO%_a1MM0yzZITBkP!n1i>p`*cP8v5=M2bf6&eW0NtfuNRpAdzHA+%-fFQWWy zb=(54-;kw}YDj2O01ips2!+1X(MZBJ-%-D+ANvyl=dEo3fuE{DS>?6mW;@B-#8j#n z(^JcbzP`tUi&0;P%hr4Loi7ioIqZgl9wyFtb32Nfef28C`~&BzB%3lpWM<`g$!_HO z<@b{0$eBs27xRs#4!iT&+bK%C0lytdT)X-*+K1-Ci3rKZl-+E-E&9q9cUSq4R-8fb|aN5O&BGg&# zJ3D=^XrvkXM_4W1t zh-WT2xATDW4!E`ehyS`s;Dajed6e6?NEy=`hEM*vYx#-5{L##)|HY)fqkY3%mU4+! zIq>k|useyIuz7EbM2WfWXj1px`-_9o;q0k{x+y)*c1VuMkNhq@ zHMysI3xI+1zs%dqRD(~z_W-G#1}GmVCMI?*JNf!HPwg54Vqk3}uk}m9z;Mjse_sQt zk5_1I{CD+|{DGu}{U-2k`HuGRUcsC{x6p@Tnxoqxd%} zT=*5n*dsr(?db$_%a73!i&$d4jG(uL4)Q+b?RGYZR0vEW^(rL6_bOI?mW*W4p%(n; zu4|H6TX3i(vGenVET-8qqBB73ewFHMjS0y{e=y6d$O``UZ{^&y>T0={EhntHeWhZ$ zEub6+lh1Cmv$R2}^+uPBI6nAEi<2?e?>xy=s;L9>KxTGy2|PZQIW7u3cjgsYd|lbG ze7#b@1TV|Rfv$?wRG}6ZQ!B$_1^oe=&alLU{-Y3m7otXy&KLO>Z#HNEFT9SyNA^aP*mzh-_KK6d- z6&pp8LdQZ0AJ^9$ybdA$pYP>Svq;z|@ZKOJC$Hs`h8O+!XvsO#q-~8%K5%PlyBmD8 z^*O&=R+&%lt^s#D>#)8AZUg}+t*BMO$Q5I+sV1@0?YX|Myf65V9K>}~0v=9jXPPdb z?al)?hk%=sfStFrH%A9=e9Dqfif*|K_4T9jt?b?W6s_X0jlH(cp57f@Ae%DWr`)#V~(Dwx8Aoyxj8TOi8*>N zu^RuLat9yab^8xTeA=ObYZl#`mKTPn`N0(eCt@-GE_&$x9SdVZCzYcjGs{MK_Y?70 zo;`<2IYt-VMpz(57>Sjn1)955{KJ~xmz+bwU|C0{{HeA(N^&jF-_Fv-U>;61Scn#A zk6Qm79Ey-fR(O2cd`4#(rT4mYWQ0PqkTf?CqDKc)-2#W0a9Q!OCB{VU8pwXY7dx80 z>6nV~)A0D+L)UuWKi1P=fBRel^evuGup?xICU80olvG=Ro-H%MrFi7=_9o!VTl@Sg zef|#P?JbX)hvdMIDVzCS^hJS&ThJf-92W+^UOXzC-EZn-XGGw^KIVr!|Js@n(_t&6 zNRv%Ulw=KM45=vVU;m@{6t^P8;$_Cy7qo;Lpd+`pTy6MW5V$L(qG1x49`v%8sN^{C z_2vuixZTLJQQ9A*3VFFclQh$1WiNCS$1MtoSlZPwKn_YjMQcLQ7x)n^O~m9DlQ^*TJOxgk9Rpe z?w5zU=XC_h;F60fshsRwH6nFR4{Yx?m5h4}cxcK5Bf6jr>IAS(Nr({V=Po*4TT-(6 z-*TE&+NLpkp6>Z_dh*WQonW&Hj?_UIHKt@Xc_gU2(n8CikJ2*lTWDF~jz^B5_h99q zyd;IRDdAOrDeq8h5@qrB-JP|k1;d`4#6qov6>uFryE6Uq(5-TRHl%Zv<9`a^F0zox z@&*(HsInAEHMO;-;@w*h#VWsx2XXJEcZ|I@K*cuzbaZw(!q~HH-8R%fF+}p2*wKHr zmK_Ef6>O7U>l`=o)woajnq!YYv@-AFQD$-!$@9Si^S4wUAs$rQD+~w%F~|p?Rn<*|i1DOc#WXPVM)`R}_G2ubGJ^gvpSj zvwfxR@5k;9&e&CXX}9poG3$4EEXneE;qKgZS^#SzG|0JKDmb#ghOI&=<`71^ z-!*j0xc_T;)6zo=2IHXzP3nQ-X&RdHP^tpPqHYt1cO}{nd*x!c#z-aAVabvRS>9xc$=Q?t3+d|eRN;T{_5b<>~DpF%hUl^S>l(Y zw4T*suWf8SuC{6h38{}XF5mcEjPITc#!8!+m`K7Wr=~_Tg$j}y_r4DTNBC^>8Q>}z zODokpm z(rR;5AP1Sj`&U<#28t`~`@fDk~|WwF4N{6pmVL1LvOm%cX$Z67ln1fmUk=hjK)y^BoXWJd3~x zY?rZcjI?x&%{d35H z)P9%$gnt;n97+8nJuUEUKG5iS2bvWgq(6;18HOh_NDqxm{RR6_pgty>h0-e3izzq% zur zwIEO%UY`p5=Ex*@Bh<}+j@_E`JlfWZ`5VzVDPNLJS(cKXi4Mos>#+!` z$o;Ns{EI&t_kCQ2PpOATkd4=-KZl+k!zb%oqrfCS-?XkBt=cuk}ENsXcf>p^wu~*YvR=BMlbF1rk;AZEAQlq_j%} z&ao0~px;59ugEde3V3?W(*H!l&!8N$wubJku?5gTsHU_Dq{W&W?-gP!FHRkyvxY6P zZg$&ZV!)C-__BxxoWxDe$dqfBw(ceHJ4iAlx1xq~Q&5rmyG!TDlQI7UOq2Wy6qq5n z_+PG({Aqnqrx1&x*pS}0=ks7Z|KPs*<0k%-CnQ9eXE6eP0fs~tlIjEKAqYxTD>}?p zx{e$Dnj?YqD)M%xx2T;a_7mK z=8W(ldSGWLTJ@)N1)O0E)4^c@_7_4m&2^%@uljz59vJ{n(QK!yg{CzjUuU20nY-nUy>a~^@M(*um zBYCzq#957@>C*0Tv+a&u0hf34xj)YAXaP7ew!!dGVYD%=DqPgiJE)s8Xa2VLm!G3I zf3%9uwCLq^YCo^-VXMR8^kJrcn)t*Z9w}p9QUNpI@p!wiX>K0F)4Q?KuM;kbnCR7M zn4@t$b?+G5Mb-$;tER?wSfk;6xUu-bJFe#3& z02pQ%H@*myA~O}KGMqhf1t7~cx$k?g#lHhU=I;Bm$qaH7pJQZJ@r|!KySw2j<|2TX z!`K)Y%3jV_oo;=rTlC&VwirDH0SYM^kNM*kjDOdVhl>;7E0qgK}qdS7h~es-Sn`XLd? z5@tlVuKHTeXZ9f}N+MENoOyYd)n)b@N59>#z!gRX5FRmrgV_hs0BUCGuWg{K3OBO~ zpPXhUz~WYMA^R02NO*Qd704}s>VK~XAS*eDaUlWnVRuh zsM_z@G%LThLl0l=HALd~6MJ#FlsR~@=b-+g``#6gdLwF4%;jJ{Mqt5pWlavVOe?YU z*G9LJUNb{DoK%s7mxdEXBQD_jSI=GX8Q#x5)y)3DV`$|0EUO<^z#H%mM zBPrqU)0PWVq}B3WSi~_S47hq{rHj|vPF0Er9Of8%&lF|3Q%P3-ylL#H21>5FM9;rw zg5O?_7^gMe)MMPQ4mu!A-+P(~U5(QpS-?QkK*yo#ezpoNkSo`7de3@v%B6cV`{p`v z?~5UH_MFaK8%N|M7Lw9w3E}Wap^cCPWoD{wBy5%#_x@@JDe!tOPXu}tk;7m`4)o+41EfwS3{@j zg)rnzOZH!R;s_~IufEnn%NK9t2FM8Z%$kjU9&eCqTh>#EjCbo54CBCshrdJdu)X3N zki;(v(^=72bZ{O zS$gy<`esyyocDMfxxam4_0>H0*AwiuLQrPK`+Ue@mhqg=uY*zll>(2Y^GSW$`7!M2#Oxn}6ee=2nNYBl_9dbCaYXiJOXqnWnq)I(Sk@)L&stD0Xx{ zv)o6TEoK%GOFUCFT(o=!vJPf>ZghbA+33;KQm3ZM3CUrC@pm10X zr-BA4W-EO$*FAI5`&?O~c=W)0X5USWO@mTRyaKC-q36a_-UAWsOn!{eyuS@g4-s>Z z7l}>9Wfo~K)qWanqLPzQsALBLxg;csJ{r?HnT6 zX$Ypx^-3cmEDC181rox6v0`Uav=2430Zjs=^AfGuf{rSWDOq?cW;g0ZogL}7NIA5m zs;|pigT`mPp%I;3PsLoXmct#r2j`5g3mj>x-j8M(6D0o7Wz%S5DX}8~6Ub&Urjr;^4|*Qb#W=_`Uwt@}#7Ak?N+sbIGojZVyy-JH86G5669zvEON8khX0OK|ImV3;&cU%fSvcCMRNH$=oa3{fjjhYzjg zu6a2&xR4@nf3&=GAGVY(i}Sd8D)P8aYmieKF&S3$rFoTn@nq@2^>{qpXYn%imB4Ld zPQd21i)Bk#?0;}L;C|Hc!KshNgZnfJNcrVFUgxx}M6x9?patTSbNXHn8jHCCDw#iN z+5Y^lPd?Ock2X-EpD1;~jN8yIhy8*8RI=^<{CwuSLwNUCar*OQ^uS@U_^->vZNpEc z3ysRdO{Nd(6xL5Za34LlYg*9N)!nYw*W0a;Nu;T&tk5bymki(*;}PTG2|~PRxxMNW zU!*Qy0&a7?6dELI6hJD+s6m96cU98EqH9QC$@g>z2$>HI0Bq*Q1ps}e()Y{LDE#rd zui^I!6kO+u%{U0pBsQ^B%dAO}BxsVbg=hvN2xNolFNz`g2#@)msPfM%YR{B4DZ+w) zhg(|gY*wtu<~V5(QJp&UFXe?0x+FX-Xc8#GXw8b(eiD0~u9Y{LrmGbRx6@kd;Kthg zJo!230`X7a*3_>`*CM-O#QWA2c@|sRB2p~l@NKDv-x>!5`oQ@)BSa3X<1>1d6t|4# zd*Zj>Dnx267RAM{&Vogbt^7@R#C=A5LxTTkY*LUL(p2?@7x_9n>aH}=SD`V2pJ~OKAW_ER&4j`l`oYIN2pb$ zo;Q}7esD)u4zE!skqL51h>8e?PR66K)mW7DT&95WGE3o<0>1NP1~c9Y!$OL z0b7yL_-H}qM8CfPZXk|VVw0wRZgmqwmwP(AgnF$8;T!zpiqxsEwq4k4(SyR2(PgA|VKNwHnd^+gF5-G7wrWBE}{TTFSSgy#)-*cmu_P$>M z7%Ei(dvPyo^Yyd4ZTIq)I!}`_t(JB3hP|b>fZe^xr;iiH#)3lPykaPG-%qTiTAKZS z82vI)e>$xq{V(k-{eDv=1y#;|KRs#jL8h1?K(VoA5}<03N&goL(6a@qa+H0?K(B7xq2VdD;J?hK z)mV{?VGAJU0#JW0DFZL>uY3px+1Vq{n2%q=e&eCNiyec(=(}FRicnyS zSok2K1lDN$0!X?W1S*lSu@}l0^v@G1tc67P)Sy4-Py}Va%wDZ;eH>~QBncuc7;00)1ej(v-2JWO+HXEb{@f{ ztJQ#x@BmIpZjqv3_Th-6*UCf@A%dJ9KHF)zjNe%$*5VOpaNA*ac`Uq+3~C;3M!}|P z@9jz4&F{aUZ4N4TD0&;~_J2S6@qd>Ix85%tK4d-h-NG1DAb;2%eH^a|KfEmnsnwl(?6gJRxU@Ka+sa@Qn75rg;zPzf?_qPYD@wQ{JWVEy9 z;Vht87VCRyqfc4jDpoX;{RP#5?WszuQ|(Nm<7w3j1>z=Zw|t()=Q=3ewsP^)0xFq< zH(uV3KhD403R$4Db@^kec1A)dWRhj~_wz%`&`@<&k#XnJyQAe=<2SyncqqAr2M#5$ z{72sQIC$u59(+OQOFf=^$F-m!>}9Suo(S%vUs4%_E|wvJpRAQbA03o@@1=8a3tI|nX?$kaR6SuKo)T^tkCCk^~E{1b3( zwrQL5RL{;G@Hi0u@Zgd{+cI>{{#Yg#x@V(3Pw{x{^SySe(PxU$fBoIVaV%|o!Rh7F zV^0;Z5Xr60g;2-ND`0{n&>TM#>TdaLO$QJT_8jgPI)y6(C; zX}vj3(t{oN&IIyYL(pB?NRxHl8!1LXP)7(nP1a3jDUa$=Nyn2kNGUf@ zOWSTxPAMCpBy*l@gpR`rWV2QOrM=c~@a9y@Alc9z8EQ>rhY4?Hy7(_{SG)(ws_+kc z>IuvqHvagy#NXGGGP6djvJi*DKL0yC!tt6p^Q*xA$Dg&;*_6Eelhs%r8ZIAyVnIgv z6V=@+m?P^xm<%c5$@V7TsbP&D6snO3I)7fi`uit?mDTxtdV9wrho^6xjzOSWXw*9%A~oBhI`^UW zz;F7E%#f?;J*2FkIxy^< zoHxY=Dn9pi*>cz=ayf#2Cs~J{n^Bx!7n;@wf?dMO^vW7#=)fTlPS!s$^5gixTIJ@_ zxk-2h%mn$JX+~8{=m0gSnEBPFB84i&N0bqA!Zrwx1pif^^U=SM%LTv7g)0B^asZNj zNjG;TuX4(7Z5L(ZBE9L`=0^qsO~?fOi@@?zQ8}!m$7HTHA8plsC}_}1R8O&xLy5kx zd=^BiDNC$xF))0L3d0J53LNY=>^GHD`khaoL>b@xMY=SJoe0qOpXSjrxIv~xPg{&y zXIA$5gYnT`{zhjEhhQjYeyWlfdG5TQ%nW0jcALYv z4^?GTB{SZVMH&KV2Z}6RE1N17sbBxfx%&n1o9x{OnUm%JJJgMjlfY!uFh_@yZX5`V z7mg%mH(oMP$%_Pdc#1l@BoB)lRwP>Sf7MO7UcbHfFV!6QySF!Ux))jFZ3q|6BIJFi zCdjX~RO8ZQxrixw1X#o$&&J1r4U>7(#L4Za5nbC|RE7&7|G~UqEC5)QgxA*APR4g1oUhDD5CkBC@IYECc zKPyXOeZQ+KPHX{{nq@xol4F<3uuP#rdv2ko6Puu3Bq}2IbKU`YK07Q={Y*OA zE))O8dPo!wB9a(iO2C>guE7C>SohSy(%@~80L%TSdF#1@|3H}_XdULplk69SZ5jUO zonx*a%3|ND$GQfF;9Kj<}xydqBlcvDRJ>|Ew9Kk>& zhB}G%p9mY|x)J>Com?86ErudjW;j|{H85XJKZJi!GGwyw{noUOGDcC>gv1)? zHF^!)B!Qu9frLl7m}yW3?dhat3iif#gG8OW3e=vg!6p{0oSK-=B}p#cQe%LaO?ZeC zW3I<6N3zA9r?QbTxNufm^G35duYAJjoSe}^@(YRmIdtXPE~E>)6hGU#)+jM?&_^0+ z$m?r3WvFQNmEFppD&RK+tR#M+5k4EB^*kRmzBmEW@t{xC(z*^KSwgpckH_M)0ek%i z$hl3%5_+1z<%)h%e5}IcSNz6$M%!G-^A1HNr5E!p9?g2gF=$~vTyp}oZu~A-%%dYW z4^Qq4DMwGcm!%)YmJkXry$F$3(t?90qFj*IL@Y>zCgeSZpsZ~W<%SiF2--0Fq@GDZ zT-G#H(?nKys`G>NboxXxe%SNRtbEcYx{zP=?g&}Eh-we>Y3RFW?Zily+M#L}XhCJ# z4@pOp4U5{D-E-FDf%Q~lBNA!qK7ge7AAABh^tC8g&e#Fjqf@}mmYtqnI<=c~J!Ae_5EPKDZyUz*kHZfD|_(+-nql0U<&PhYjM}z>@Ch+;Tz{X^FiIC3L z-;H)z6lOYEGt(?oonBg8`f_L%%Gyux^b->an8l2(vvV?y8h1Jkz`jsi+}c}cBl&Pb z>h!E7C@lTRpbP{B+$^b?nrs%NI zKg6)aI9|{Gn&9%?ud&^5@{Vf0m+-RpTscdn{i3*@=hE}$)YfIL-j?Rl=k1;uPtwB~ zmslNg{1Hi;)oc^sGIcOv5OAPv+_2xB*Y|kDH5=fqKZx_Vp$uXq zNKil9JiPyw-_9dJvEX+3hHFuVHI`Pt;y^55nMV6>wgOej3#XhLo5KvY;GBmDg}=#r z^M5YVSN|-0SsOGY?|V%VEt~4k>chjdTl%uc5lkWa>;7a;6Y4MjClsDptK-0DbW#;y z?mhaVdT5_BM@Xa4u!e;a2lNq15Wc2^=0g#uL{|^u|4pm2`9p|Ead^4=3YdMtMFiv$ zlK5!nQA)v(T69?jP(K-5wLLFR3J(Jp9j^|r6SY41wuFqD6=KG7F7u{RW#;47Z5Y@_ zjSNeI1UHf`SYlVOeUq={A)F>5$}I3F`V(H5vjiD!^mScg5PDj{)=2Y}I)bJ*AY-e` zn8SZ>!TwZ%$T!(|o)hexeBGtzrc- zh^>VowuuZxWc(v}_NdujlA&Vt^61x$bNkBK8U9s?q@~Wm^5LxD)ig*1Nf}Wg2!GUgH2J|U z*R@FflR87hq-5K~4q1A2;yeMk{W9QmNNBeLg^ep&p+zCX8sYZS0Fc0&P&^CKA-7Hr zRb!&L`|qrCK4olNHN~~VcfnWVb+2l$pX1Zs=&K1LTVfkjNox^vD_}o(=?Ba23R`_g z+qilP1Q@^W2uHll64@dc<3=$2%U@V>UQgafO&qM8cnjR`nBvNcU}i}-_QMzLIiCwvDms~vg+p`zQF|MtB6qo?vkFxb8SlHS*1>xMad zQ3a2X!wsN57t+yAivy~jv_ZaM%HXo`yDaoE8~+Jzulj4p58Oop1b+j?wh;e-vr*52 zdO&co%nkTN%O`BsKY49dW~q^&OHlXycXwl5KVbt%Jj+f{m`A{I6xYx5Nr#5=Bpbf3 z{)a=<(tm)C(VI)(eV_{=4Z-YM<|ZhZm`DatZimxqK0%$rxF9G;<`fq%#&_)gnY=@s zJv#zP5*aA;UotlpM=pO^;G$+MNI+OR9$g}doeewdG)NusA)QD!&exbVtlMF{*8}_< z|6TgV{0{V+W?2z*4@AbFI7BuQS^?o{_(|{=;f&~q$rFh`MRiNlbHG+y9Ey+aqn6M? zf%3Q+gv$DYw#yA<{Eu58Z*HkK_xII7IZ}>Kylt;fXHg*0VT$Xdt0y4Pl@jPm%=_}` z%ZmME`Hq#3#jgJbO$r&f3(IY~QJT09kZIY%oiHUblF<8fNy4C8Y53Z? zeCK9+GcPhbayra@w`R+z+^DvOi* z)=slrcao}D*CEP=!nKhD&fG)V9dmO^>;R*e@7>rJvPld?fH1c};A!#cc&v#2@>g%H z-Z2Mu({JF2V4h|CRAZw(n&J1EcNm9AWrkx&2HppQsKx=^<0AJc=KN6v(Tm}Q^a?gb zA?B#TuM-LCX;hqHjRs}!Mt)SNBE*tkb*@CyIo-Ru+rfSwNMDMb^@r7NLh55*+em#Q za@|lZed98xkbF`ab{cSF{J_BZlDAgBx7VhaSs3YH>xQgYW#ekG6D?&~ZFlP62Nm(@ zIos~qMwJgHtgj{yWG~dt)jM$DsJ$d$>is(W>$p1e>}BnPryp0DS{rS^W6(EA&hJ>> z84ysN^rW8tAo48)iE?`egRszl#0p{V;4@FHml5EIpC1@W7B%PSKbB9-w)kA$-Q59EOLFNy zz`3oKeenAp5?IEjww@I+M^-lOl(7#2yJph9p0gIB=LFr1L4>_5RFJvbOp8;*{SGRgft zyacd?RG*jMT+SzMUSI6bq2(G?8GEfKdu5BC^waOV-`?z2Edd5!fO!b$wzagh8W#?h zyTaR^{__(D*7iiuNUEA?U(zm~Tm49B_S!&nb!J$n1Sa#ke32$6V7UTj5*(yL)WBLR~GA6wS4Fi=8##A8Hvd<>OI|gMZbj z^-YOt3`*;GqrN3g4gm|I5=#rhH@$FKGqfiNX#B75+yrv*wSY>^~Rk!2@aLt zql!=w9LH>zPuvgjx_e#OUmxWgyzA=!#U$q#Ey(LR#hwKqB%2qrCTcf7kQXc=F521r^KH>kM8i=LhUtTvr(!B{raiM?(f z>N6gyU^dLq=Db9fPp;))mr}Vf z$%j{`WrZe7R}GHJVG8Bx#_f&JFi8kCzS~QEVWbne${G?H*kIrzUF}z*D;U*MdDK5b z9*7{phXm15$oX9ogUt}!n9R7{KeRZ+tFCo_U|Y-YgLDBxkbe4KV+_;I;S{(>%?3={2+TDdNAoa?SWNe%Jv@#uRGkag*8n+ zcq@|2W}#cN5Glq`m@-nywP@K_xmBRDhhD-8`-McPi*+-!Y~NS)Tk}!MYgEncx-|iq zKz|ccyObw>1tK6Qy!XRTjkM16dDbxanv%@BFw@6C*O5w&8W-l@`)*@=q-e0n{BO*7 z7B39#V~e<-MOPS_VSsNIK_5npb?_R8-F$X<*kKZbT5PCis8UD&K= zP;tY$O~6BM^}$Wdk?=TG;yfVru$kN)6p6`@Vf89XTa{Es-r3w2R*yyQMYav3j7f!T zr9;txysX8DP)YKu;;l`Kv|=x#y)>JlkyvrpV!=A6i)Ty|s@fsd&!lVD<-^A|#r%!f zzsym0z~L-z8}sN-wf*m&R5jl=JSd>lZTNNq{FY`^#5^r*3pCl11C@GR9f}qP<~?hb z1NY`9E!IzFW{m^RN3>hd$i$;X_b+nX&HVowx0Pe~34D^+#6va_U zla54}-~@6cAtqv0Ome76tB(*pTiey)zdEGs9#bOs4)5|f?9{56bLCNmq|$Pt@8xHa zT3Tl7s@n2Ic=?2WT%?xBzq4uRnJ(;7@>nK7W+&ubAyjq9=vAydfH?$O^DSb|bDrMJDRfz5a4oL9$_ zIv#ehYtq-ALK-7@jAb&Wx_=1`D@!bdy$kUJ>I`GXm95Ympjui@0>i;JMVFnHT ztLch4_IPV+P6P)-p(fP}oGZCoTw7MryR{Twtlu*}vrzfz!O)N1xwx7H#{uQWNrq;< ztxG8@$2aAB>D9}aDrM&DQ|HQBOZKsd5V1#mkdtYAHB@4;c=WkPB}d$4V+gnjB{Cd` zC#3^%BjDLz+RWVCoSOnuQk6AXH0UxxfitKiw|Qybd99zQ>g_q^_hGjE6@?LTGl3mrPc-4qQBq<>a(vhHp3R_}Hu!O-g ze(S7yu6YXxM}U~^G$G0IL4PHtX)c5}y_>jN>a?mj8nm$tQmDu_Gbi*&>$w+NN4yY> zjPg*-n@Vj7F(D(LyND@r* z*B(pY1`5@+-H%44M58g_b|GZr6C~b}^n?m?eOhG)xU>5eHT+CctLxlIcFwTE_u1!4 z9Uz0!UNs5bUOg#&3R0{VBd+0BZFp*C_SsZDu_3vXpO^m*sAmw;d`huUqyE|r4ykqE ztByi|(NDfP9uO~wdt=LhNTlFPp}oZJak>%+RS-2oP!++@Pw$Nu8z(~HWgCl^^ddY_ z?awnAfK>-EDUL@UwIs_ve!_eg`nTVQ02<5<{3ZVsKUY$ezi*e6#*vb*od{es4v&BH z8Uim{HTCg0eB-q?4M+L!DhULvx89O*vJ3JPClZ_4%NCNJA!l06IhkKtYLg+4P6h^k zx>$Bfuo1XB%!vtzWeIlXDXBjHfXMGx}gU2r)<)$|%2sDu$YnY*<5V_UnjxCIvAs z)D4I%EOPE}5r;pbK(HUB^zeCK4kI6Jl63m@ZZuFHqdFYCbuzES56G}%bweT9^H1|9 zY~BDz95s?2=e-!}Oqc)a)m2lb78Wn4sBBSsz!VJ-M3cp9m9J-t0HLgOUP}v0OQ0wR zd`0|Mjr%Wy@|}GbuwSdQC}}*MC6zXb)-^P20XCk^j=m5~Ae7G;`Ejb!P|sEzOGi%+ zID5eoic2pOt0%R}CxC)ZE%5V!shpa8mav=6U<$`ol=$N-(&BR4O+8x+ubOWR6Kqw} zWZL8M4L&<-kqFLQr=R7RD0>ZJ{rXhBmW~sf#z~{*lMLGi#gP}@TZm7d=j*9e$QO=t zC>L_|#ID8rxhLuVWGZ|YH2!zlFcFk_vq6Nc?dzde7}o(<4i%*g1Pt934# zXW5xwvkZ*IJtih_d_v9zwO|(Z`H z=Y^i(G7=0HwxtOH3HBk*vIA}(90z00?>!xkMcPh9vN^NNXDrUOSk`rG;ATiHki~_e zBD{NPSgPf=}3Fz)*F}vrsX3Yyodpij#j*X|f`KqgvgjMl7IM}#+-`V`; zUj|&UR;Lfg^@qEi_l((!9uC^>>j%HrZfaX@_NJNZ9MyBgjP+?^52`qGSkamb?7l=Su?=BckT9no1P}Ce{Y>FkD0QG zv9ivq-Au5z+#uhX*jee^`Q*^MJ7I4+K{I?}(_~pUvX^V=^dlukNgyATs?~^gqEnD` zIhLDXcHfC6t;Rzgm;1sI6M5m}+dOM{C?og1Zu0sIU>_FoK@%PId^CPcm-+}nVn|VY zRhfdA*;4`$b%)Lj?Sa9;t>nD%AZCyZ0~(Boi7*rqm}KFMmuwy-p_^hX*zkMzEKQE( z&1>F;G#j{ceuye~h6k2_7fJ&HT?@Be#wbj(f ziMn2}&R7h1ynj$LEY+-=1TyK;C_TSf)Ls8k@c5revO`KjoUFy~#IHgpUe;h~G(PzUPhpB0%O&ex< zx^vUr9dmTorekKBVcHwRbRHek&2;;{KHuM8{=rS0+v_~9=k<8p?~+byGP8-;)x(D0 zr4Y4U<=?A&sR#s3B_L8nqWK6ji*;O$p{J{rPs+w`4xDTJX086KX8z(1BcztqtE*5l zRG$mTTVCXa{meFeMzugx6nPyS0d$T3O8YX|tPiVK?fX28ELO7HE?IckRI0P|rB*12 zZbrR9qS1gpLO=yZ`}Y&4ySz-apGssmYHc~P4QlJRdUC`>swka*5v%Op{k8u^X1D0& zrFL^%0&MFA9#T#awkSu~&;iXTlzWf|bka`nSP(*B>~0>zWWrO&ITc_#^XIqw+3@p9 zr0DtB19H`O%x>xpu^dYUIWy>44~T*p6HW>}U!v*+5c0pmk;-Y+1FRKHjAURj7ScokJ7V^H7%^2%1ubCL)=hQW9D$ zovi2TbZn__+wBg4T*kiooW|Oop?()jequ3$K zds2nJQdH1&@0^9e9Q?~=d9&4_wAS8nCrjU$Kb)mY{%aTcv!oQ^{Z`KvJ1c!PRY$ws zr--MA`#%~?kB7PK`2q&}mncdt;ECO0x)sG|Jm4%EgO?DbNmoq4wo~=+U;g{E?I7fw zkf~gC8Zj4cH;6n0iHWE<{~mC_F7QzCBUMgahM5f%MTVy%`(6HG(l2BCLa~Y3hF@8; zOA$t=`UOfKB5!L8i`2~P;);5gk3!p(D3gfDM^PV{gp8L~uaX~=Dk?VpAB*#PsWWQg}7`Ota zoag4ioPT@k)3S8w!Tq@Nfa(YkKrm|}Ax1h%-~D)>Kbte<4$6aeVuqvrrhLq_V3XjrSE__fpmW;;DI)sPgXiRsGRjCg0J zWX6)p)5bz5a9PGG36)W^s37R(!k1pD=29RD6n$5mTXoAL*S!l1RIAs5>A=3v{;)}sF1xadcpMAn-n=4<8r|La5zLqnH$p_!$TfQ(45 zO{-E93JS~SMF~}*UV>$2ht@5^UIi`{>Vnv~gFe3MTr<&J!+@eOfdLZRD-^8{QNrm5 zRz!Wiz{~SqUMhQA931{3aRH%qa2^uEpPiNS@#$dPQEHy;x#PU%tu__aCAm!=u__0o z@RIy1PH4oate58L^0lgrgxA%pr+CWytT&V%NUzL;Gv$2iZ%k-G95xS)O~weB++!Ar z0+4JZM3FQJ1x->{lvk5bBxVT-lA-@Z0}UQ!BLAEG2T8>h_###K0L)7Jjd+e7m>&ZK*8KknA^bs{}~fT!41-rZ*vI`Cy62_A#-h zz5VfeJw8{^+05R4nD-rkCj3B%;OSLTR(1g7P)Hyq^JDtQ6#zXob8)FP;0QdlH5LJA zMtyHCYqq^HJ7`ClDm!k9S9YsTS_`-n-^$la#08SUd99ilcp}Q3Bydtd?c1``CkJ!WqJ}J~ zt2tQ0+iCNS?Q5&?j|Wfu)U(x^YLaeOOpn+7^nsq!1e}J(HvYS>O3;6E`rce-+6%l) zb>7-JPkgIrnnUT<_x6o>y`JvT@xoF+=I&HO>6V+j-+qpw>(;>6!0Vm|S|RuABNacN zi+V?|g;;@6vHNM29C2r1P9?5}K@Um~<#=NkC&#l1?Z91EPrvhrK#xOm?Z+`91D}~} zPn+pk@86rYcqR016_-GT!z%4*cZn!aV|!m9U|rzo*LvK_M+=tp)J0d72~lr78iZ;cWrSr>GgnkzZ(?lFUHDiK@HZ)uG(zReC{kU%ajcGZ~nK0n;Ri3-=+f zt%)=K@m8sY8Mni8*~!MzBaARO5$&a-eabf$5ZsLVt*q(2SNj~vY}qfx;xOG-#&W%i z+wo->DMV6@ELG7`kQ%yM(Eos~BBPLGryjg6ctnJ$XKONYssy>$?1E`8>$K=XN8cNQZR-ajR+Qq`WO`mm`RcllgLP6N|H%!X6=M;CSUk;4k=9`o@~+Dv1~lR!IxywIxo*GL1_O% zXZ>{XyhYZ%HLIlCH+}_U>`M-F`at9>%n@+12V?e^FUvgcb6s8G^&Yl&N2LWYnM51@ zuc%W3fn}cs`>NajT}zLJ5(!&JvMyEH@X=36)BKq_Ki^GmSQvNaX=+aspd$X^WG5vF zNfmt7;Imnw(XISSG4W+kSlC$z897QEVa-1?0Y=Kz=Wod>AMFbqcY98 z41_0g;@AT!_&x&hngJzGdSSt>7Qk;yt#2ho=7B1p9X>@2pZ(I*lFXASo%-@8Pcu?l z78V{E6{5~gs2w%Db%?Y;%g8S($YV5%#dViZC8Gchrp_i!&gXwj4}}$i-;&)5rE<&d zs&2Fx1J2l=m-oDJ~No!5Zh}OWRgORK>v82hmBo;kfgvYVqg)njq2iH=OF84 zGuAOMG!&4nscmg{`kTecBd0b6%LNu_v0Jk}8&gB5rrsXGa5TJ7E>Hm}nG^jhswenK zEB`ZHc@X$Ii9#$g7<>|Tb0Pu0cNzjn(44E*?Gce<;9D=<4qV}!(hEKPBfosEcuI79$CtPp_ z=Am#Y9J1Yh?v)31A(j!;(llh>pr$k*Ega+daE+_nM7w%B^=sgIw&V%b zlX{-Dnay7n^&=*!^_L`35n6-gM0CnSBc&j1&Q&KITO!WVfv)*~O%>K6=o#5_8q>V4 z=GzT%hinI`=js*Uch)odrLsm8l*cXQJo1xrO>y5LDXxSvI$oBW{nA9sB56C#9GV8k zMh=li&yqHHeN#DZ5N~+z)}oPc8{(3B63K09&}siZj)~@uWNyZq>_E~s_V8_ZEVn7l zhak9-vk`SW5bbDiz-zLd70B$@T`BbSchzw1`0w01uL9}Nn2-MiS&i;auRrs?LMSo^ zA@e2hf3=$?Gw^^9A;gj#^E2PgcHXkB)NcJDs1oRS9s=%(B@~?dOqvW<4YHC+B1cn& zx1wFxKSC3?4O{Obpa5e#s~WxLVHtyqpGfm1kxn@wIw(~Y%F_?({$3Db!22;Nfh-Sf ziw-x>;zUnU2M&;Kr6f9?NeIn@>LMK1y0lH+)Ct9oVaYe?eBE8e&h|)df*EA75l8A8 z$bdL+FoqxXF)Trp##=3$&V9*%!|oZ*G2j&7QvLpZG1*&*#U_<_xRselnAYC{tDT7Kf`aLPPU`hYMOZ z|1If=Z;hqX#g+6L8ysMk2nW#NP`=5Ly2eJOUM3B!Qohz%8V4lo29uYczap2JlJ8$t zP@_ma3n7MXl5*u%M`G92qwwS*v&7u`y1KSBVvR1Ri+W9Z{x`9Ajr@I4Y#Nel#4e^U zD86N13Lo+f@>tQyno`R-t5#@z1H5D3`U)AwgC}H|LzXkrWfRRjP;SBXw}| zuagdIs*HudzrUT`kSF2UTq$j#AI!Xf`Lr{sB=Ls+Tm9uV>br#!J>w!@M# zpsEZB>VM&ELS_;80*3w8JleApTr&auv?#O|c{q>^~rP0X?x!3YVL9|~c{&G?TF zfgANyc#TD!hs`W!1tn7p0tX?!sKQ`9#8Hks+hzF39pC;tzc+E~aBRQZLsS0IV!Unu ziLesgsL2Zam<7xrASvTJ`&uChj$K|4tTmaVjH(3q`M2V2Dzwl+wiV)d!&Z|*+mX!y z7d189+l#}PczF$i+~W7@gv1}FJOUH0*>lOnVfsNXu1gpD(z;|T1^t(dKD(REyFAf!&< z%t_d|*LHn@*i4!Pq+(?TcaWWtsF5a6Xv4w!k!>0nRinb@mr+qQwCQjAFYEWlCrUoc6dZ@e- z06f&!d!$)yZ!e_UD1@US3bmZ6waU0L24K-hG!pbP`GB`OLeIh^fDSVsiwObo=S`Qz z*7GZ704nV7*?yIGEz{ZK7yKeLAUti0b^b?OgOG?Zyt zlZGN&0oTLglb`A#_}>etRkUrV^(+yQtj>IbPIEm2iZj1#>bWOvsnw)k= zn&j$g-f%66F1b7T`U=^iCPgC@>(jO$1X*8~T;&MgPv>6$6F6*N8}OU8Q68z};P@%> zFrE4qAS$)F&P@5J+%m=U_t_SNq_>^_hJrfg5D{{ zd2mq|yy?*TBGxcqXF28K4l*0>o>SZ16^5JmKuV3Kic=@84%xUNU(HntLz+nF{KbAn zMy+Nf>r_~{_t6gPq~(N@zYI43aMqc#Nv_V7F_`9T`+6Mnqj=74&M5aT^nlzAUoWn? ze}gwr`vHc(+G!i&zdb!Y!RS~=Emua^-F)wX+K~y@ED&q}F3vrU7X5F}0hld|O2fy- z1)w>tW6qkY*kq8Co4ZnPI|EFD88@ecRq%ql3N3v-y)T)Wx<*EE z1s{3;oQwZwxS`Ren>|~eF!pT|GoKJ3>`Fqt+7w{l1>;y#U5eF9(}54ATAbQtn}ShY zTruxH&_w8(3b%oC`a#&l^;$B&SlogMeza9}ifjX8&Hs`_K$Q_l@oU*=$U~I+;;D&J zN*NM+RVCoq5a-v2o+A6QRse9#&2H}B?|L$_{#acDMm4CP@Kpl4A6Oiz0p$1lykD3vfjoHpNt} zn?~6kg63wRjyAd@5Sk0A;dZ&+LkPsf`VS;?M^<3k88#M4ENie_7DzS$6?~KczKpr+ibn zvHZ%g;6tJqS2K3~Z6(uG3N$cZp)eKZLBDX-1ST=#X&UMOqP*8uNk-z^?;5`jG`(*f zCbfD1Rn)(@AwgQ`Ze^XZtBC5OY)u|0{JxS_Wwz?)7mK6^rS zoZQ8(d+{zbppH5&U&CuJ@&@aECLsQtC8_IoNy0GHmKb-T1*bhq6Aq2@VulKgcq2k6 zH?7KbKLooV2&t1X zM$lji`N7nE35vJ1cPpO7vw12 zNSuNOhuxNcz9fEB-`e*f$DME%kRqV7 z{dTU?;ztqIodIDWAY}f&S*!F&tomuyU3=!MJ5-`;*hhpe4x5g-vyfv%egLO1nP6|9 zv@dYu@e2H(`AYjNWVwBFwzckmI0@tHaN}RVUiQ4o-B(1(|${@0Cj{g9%kw*&d75~1a5~AEiACq@h8lYN~I<(fQN_nR`z8F;;y$?JhRSVo6z0 zjS7#gs>-dovaY(pz1ir8yuH=J9BF(-{m7nA@iYfVIXRH0q%?dYvBivt_w(^Fi^eUR zT)!KrcQ%L9lwWDhpnoNZ`0qbMQXY?o`9FOK*I=8^*)PMrmyds{#7{Sbr9QL8g{Bk6 zY5iy!$rhuO6&+vvEgu9{;$eLuHhyWI?0^YsCpJ(Q{up*0ld+^GJ%b7v7@-5A=tqOf zwPD7>;RBx$m;k95a`MO>o{knHhcgG`h7gm-d4VCFz*)d{UpWZ$8j0?LcmX~qcm?fQ zX`lc>rmjBwUX1BXDDpx;dN5-9w5pZ>>bH7e7sWz=4VzFl?E~OWQvPHvs;i=cHleD& zQhFfGB0J6`6@<0lUVT$|3x`QirwR?)IIF*w9jBGc7p`xhcxx)U47>EjD~p~+zD|OD zC2)z|ka%9dx99UprhJ!6{YPIfKHj!LXI{cPMRn{~)7&$&>v3WRs1${_Zk(K1ox5Ee zJ;L#tajLaRgi0m3`D&j)m_i5#CvIv`32~fcs!4ga`#`baxJ4ZqwX7P8x{sfY*}waV zh^JqHM^5*nftxR*ciS4o0}9f`ytMa^;yFg`%2eVh?}!}c+H4oP_G&WQ^eMGQ5?wSj zG^RiMZK&MQ-qfwve^I_ehv>8J2c#wL*hJzg3FX;@PrfjnrNZ34^T_FsnM8%uW4fOd43 z4cdpX=+}a^EVw^K+K$H9IU2RK^miqc)C3z$p(LyfI0(bi6zfL*%4VOZhNdQY4YKsm z?G=yk5(@_NQ_MU9S?(X&(`CZisbe#Sx}yo3bNhg zvC#~sfc-Io;=t5I5F~WLYEl@89se^~=x@511SwT;j?Ws1hReaip1FXLk?|hX?hO(P z8W@_knU=Qf%>WMU#VOpqfjj?=!?8u-+oVD2r5hNovTD$ACqcK7>HQ1E;%ED!=+S zn44%Blm{B$*~40qp(6fm?xnJ`^)`Wc42cW;T|vZXlKg^!R4i?dMqyO9qR`VoGR&fJ z19Z78I+dlgVW7;!KQ1W_R6a+d#*h08D~1;J3=MUKR~)NElF{&3j_;YZ%C&-V3%Dxz z`bxe`@;ZNVtMVVb;T^zS##Ev1e!tzR_FF3f5{ZO{VPoTrJsr=OL31~CpaeU`Z3q=X zOkXb|QMT=TT{=!r2pWZH2tf*ALQqh~Gn`arV&_#S^j+!mH|*7PObBARDVdF|QBm@` z&{&p^xAREmxOJ;KA%1?~MFzY`!a&79VXYl7icJEw*byRCxK_scR3Hx}CQy`H zli~TZ{K$LkwHsT79)zKDKkx5J`nwkw0V)JVxrSv}-rTs_B4Cg(*cRjPOtaBOJQ6qo ztHC04)xsnNg>+R|>6j5rAPQof`VV=0%$y#KW=_K6Ee-E;Xc{m}O`VG9#wB5_4Gr}! z##>nh35VEva74vBWlU%L5WyGcDB#?8v`}{uxOmeU8eeJbDSJWtG!!4%HL@qfWMIJj zMZ>lXZ!nas`dUUX|J?`|U*UeCO~{Tfog? zKGFRR*7EhOc9uw;$KByo$B{i}$KzhvNY%gMS#BwI{DvK zS}5)PYPRPx4hVn~O`33BKdd}G05@kx^YykqKJ!8|wD?hMuWEHpfhOpOd8$i3Uo%hqnD;y%cINkN7SjAB0{U zls~h7EaH^6WYcyO5pYtMdyD_k3(#_%B&D~x?B2H$uJ2d1r`#VN`+YAx7>%*<>eJY*0B16o^nR1ITk+H-Sr zXF$+a3Ph)i^h#5{ee3J{>MmtzPX{&m4oSpxSicc=Awit_^TGH>XdDtMWG(FM4wBwo z`b2t@g*&qlhMd&ArG;99X==%1RFfH{(6macS!@(!AyEZ8_;sgZoV4Vb5K_$` zNyp|69B}dk6)8)Vvo>?*2v6N6n7Do-O3JpJbY_2{hzz4A2rSiwWU$LFfPx})wOCVs zZ0Z4?C&{gj&!*9Ay%dTO`C22e(FZ9A+B^BU-z4BXXr8n!d*q~oWyMm(hcaQDeTBt? zt6SYKSot3CrN}2QNdNKN3`mg#Nuo)SpuBs%t+J)fXN4P3EEphVojV76Y&q(v z^e!(Q{XFIzd(Z=g8AEGWiNdh6bVwZKheP9&6XR7~iahJ3I{^cKbVOhpdw*T|)712t z=n6Hx-=Vu}=S8aR9CXNAVq{?n6oi@|O!haFX2AeTiS_wB%R0mlc7ddf=Wod0sI_NY zSjDhJArwfS@R94+1>VHB&x7NKy~B}H&-JtF>c1gmG>hbG%q7$nqXilI2tCj!7-^e= zLgCG!P2-Yqwu2bgo8n9Yv!RHQ%mTYJhR##F6&5VLmt!jEs;R1L&dd=PLi!neuZ1L_ zpJz8o

aPPFSY3T7yFwu|q^Xv1K`VHwE_yd=x+-X1Lm^ibB=h0kl2eJDtaUQOP$I zJpy0S+Q*uS)WbI1C%?;6$A7a#Vl$Ws5Zr~)ByER=RKwAtv7wP7_dA7G{=4nwOxv-; zSf6ZY($^Dy3#s*1PdtZ3Ax5J>YO|L4glAnCUz*#F01VHZMv3ubXjSF{w{T-9&f$i{d4@n!25ox2ygdf3twQ1uQ~puQyb4 zGBV2#N1h#bOUD5VKt%Ly;Q8AbBj3Z{gRKXaoW65_)IH9#6&+N|CgQ#~6-mnU!vB0c z0*Jx^;k@RD%LT`dhfBSR%Ms7^Gn!+sJ^;PB>OBR2Tzd!I*n6+2ILEv&XL)-oU zJk^rw^FmE5OZ`XFX=goej;5@N#?f9eSXVG2h&sH&JFGE@k=6BS#PV=d{ur|1VD?in z3tYt#*L&7RoJ{7o-u$N&vtl+V297yl(;((&ijlcCSHO*T_kfmeBl2x=;tAoe9*&RXIGDW`I!!{mCU(a7LV?F^SR1HZIK0DlwGz$8cLlB z0FU)@ebv|3AsE^l?-TF18qj7p6nxytS21=zc{!zG_MU|IFQK<<~6H^|HyNb}y%un4^^Q z*O-Q3@XA(hdpqdLjo3Rz8OL`QCl2-_0D96)d907~l0>?bEhrB{js*8(kb%d)YYDpi zAeKpi(n(Z~FPzF42~Vvm?+@{;t@h zR^et(?4c10AY!X~;8A0>lJKcwhcbJ15fs2FYfIDZllYDf?y7cT^;FCh)YJb?x1}_~ zVp0LcS#wKBSBylm7Zt9wDmlJcpXs<*UCIS6>^Rvf8*h@(eTAcIVd>)kw6BzvUbJtz7k^#m z*42wSZYuQMiFO**ru97tzF>|y)r1-}eq{_UL$Qi}4}P6AV>eDjRkKs1H@zgujv&kn z*(lpBAloH4EGI8{kk&0r=oexFp@7k`>&<_YdUx&S*z)aKKcH&Kza$1v%{soCtthfm z%l@5k@z|!MZGT)vk?fILYblR#R+hWFV9Be2OpBx{GQlswLkU}BG~cW_f5yEKJG-Uz z`$Il+&}ddIuSU&`KveWUw~ZzPiOo#M)Aho{i|l^v`+4lOQTVf)@akSjhha^$ZpH;- zj(>kuGN&1&YwKS;J=oO6b#UPmu*COXjAOG60WuM!?sY!MeauN2JH8qP81}ox=?()F z0^66XxiBQ8U(jqFfdJnSL(p_mNapfFu|eDka8^t-Qw!?I0<~9d4b7+h_x^w#>y3!` zik>|=Kdr5@f$vgu!||;1(fy5bW1FSb{`pkeZs~4PB{v?+OT@sj^@duv44C>>ffAuh zY@!NRT5YrA-`d87ba9ap=f?W(j0jQo{rje%M%`z0y7qx*8Gl9Eb2*f6uoj5@0DF}R ztyigvX_k8X(h-F3m6QPDuvMKdM>=5Ag*yBDFLk>tC%C#ABYy#aV8<`k6|w8T^eRv` z_5Yaw%bvE4aayN}`Uo#H_#jV5q9X?f57m7GB*0ZyHPKp)OyosPEpjY40U^N^9$7Fe zG@?$5DF{19gZ{S{1TQufKXwxy{#PS9`moV2EP#UH@fqs;O8D0O@86%z&EIUJ1P~B7dtNU4>c^C_SjtR=9Q^k`_~DhSOls7jC)T>g#h+cw@C|D2XnNH! zXo6QeBnb}h|KMv?m9g~LnXgfy6+vJ^6RQx9HiG?M7yW#Ll#(cZe(bUav z-nu$>VwsxVW@_=Kn2*|NnAQ^>X(}sT`^p?c6PcTwOOuMa?_;VgKmD}qdp}Ujp?$G? zSfVU`8NTqe|DMzP;*a@Nj-cP^p=02ZyMV#J6YVz!%a^BIxGL0Q!ggou0)}^y@qv{y z$ASOi&a@5gCfpvnGW!VMswsR_#3Gy(J5;#o1cr!)#W?^q63$NrDMfziilRIcAvaTxqvyU`;PY4(~q*sfcr5zS!VE((eZ3} za+UAH{_<5Yk>B4l&-=Bf`%xfC_b@4bVGex#lS)>~nJ8uAdrz$S9fr*_mARd$!~MUC zEbpN*lBPdV%_%9LcdHk6LpCo`FRWZoftFA97l)K&ICiyOY@<@ljE#9%!}NY5)~6zK zbAP5d;=xSp6fgo?6CxGIz6uyR)j(>O2g_nWiH4Jt%udm{P3CqevhdS9XR3L0hzzbS z3(e>JJUsbbt{W_R5fznTZ5hKlL~ z&NrGgwzV4_KaIp`Gf}ONkPlHLh6VQvAS4_II6C!MUh(zU2`bCz#H-k;Y1-7MC3<;y zD2DS_PI0!K4^%A%UTfq&mdE{Q;as6i-|IF_B(K!WVR)Ba7d^78ZlLSPPHquTEzWP0 zLtUmd+8_cJ9m10Pk!S)lsnZ3QR+TIj@omL)A62VAUum=TX$2f~BAyQyGmdjSp7*mj z6o51Wb$8^Ox9~JSaJ%*&I+pf~mdp;oNedpHik9*ne7b zaj?+`zuVfX!PKd{@Ppdr@zV#X4QYzt?!6G2pNP|2i7^-X#m` z1eQ_3rDlq26;~h#j1Q=bXtW@K<$pD$mFPjDqisLs`Pr6Qqlpm?&6c-BoR!C*&Pa_u zf2mM1<_bAN+8yxW&1#&V8ioWCTrA3xl2|btgq?!x_EG^Hpl;O%bC7Kv8ey@v;#xw&XsYM2O!5Hh}S`Pjye5 zjCRM4&4O{9Er9KSqvhbDDo_jrGvC_Y?zsNV`8ZDdFy3+J`E*3|bV9Upza;>)8lP?- zAMQF{e_Fkr$7P8az|@Pz#v}PW1j_4zPYJsXt&U69sFCf#xxT4Jv56!+(E_4CD}9gY zhywE%A?^7lm+8_U$>!Td4#isUc%;y9AZg*hiu&rk!}{7_ch6R?at^oca^9b`^tQvy z%|oE_%qBQc67^Ra?j)#d-}WE%*^{v}jIl^DNu ztcL8pL#r3JN}cURnV&f$DW4+*<~#&m*vdeER#hGRtP5fC3@5Cts9-zL&-kHaQJMtf zQ0|t~udsKJj9Ush9m5(l5j z<|;WI;{?;6hR%TU1IuRf30Kck)|*~24Fg*0&ok9^U9M+M>w&-U9DAmG$7SynDdSOJ ziodF0`uS?xBk1*CxM!JU2wJM~V2y}SX2OVP;n;HBO4#zu8PCReHe!&gXeIcVCaO|z zICUXr5)hnDe5=*DO&uwvkr3S3-w^yFWzbM%C?O%6U*seuI!2foRPnsFdxOI0)1#F{ zWEUl8%T3<3RvLK+;&TLCaYX*mGG3_G@@vQHy7VdEC%#}Z3OBk0HbvX_rF>gzP3o-n z4FbGF(jyOG?ii0R3Jw$fq$ZinCKY2}6gB7UnR+{i?#qvU(`?0-`Vqe(=}hP6yj=>Y zGGf)&*L-lP>gP`pAT}vR?ex(^ONE?_(MzH%R>_;x74r3lE15s|o#XM)0WsW!YBt2* zXoNI~;!T)pq^j$m`AT+0Elu3-LC3bU60gc>@ci+Z%MB&y{q={-%T?c$#HHWAG>&^6 zmR_pGo^?CRbbR$&C(YVC)n@+CzWlKKOSVAU&B*12|I>o;(*TXIZz=fd8pG>9z7t2#F3mh!yI-+@ACPv ziOPB zesp)gIQiQRTD4hXj*@dTm*mTnhU-{>Oa7}P>|K~d_Y_FcVB!v?lRQx3)PPqbE)4y;a*dm7;dormlPY8iZ(m;R*Xp zXzq%Sza1+Mq{+b5OiWD449+hn|A*Uf-5z;ne$>2Q$%Rk!LUi`{YLYKIH@CxOa{w^J z7!<3qrpnpk+Exs%xQjnKOo|qFtDyy|qRO+|V{<-jN6M1|JkW=ommZ;2%MvE3PrB^a zl=uK1z%o_+&+}JBd?=mbSbpq}l65sXMV*wrtmYN!;q)Cpr0&|!{a5}JL(Iso*Gbod z$uujpe5Z?xU)^0D8yhT&ODKUf6DOffAgczH4t>#y*vecZZeJxjxSHe3^PtF}%<>xi zgTqz+CKEcye|-lt;A?Xv>;14DM$l~ zSnTi3!pE_9J~GWOH&W;+4+nDlDB8Dm5=+8qCe@v zB_B)=^LTq9&n1&2f<)hkZIjER!QTtabT;*Rtf>Z6{}FRu;_ikeAiegc2qd9dLax2U$V~6CU)3nsqo#=s`CAmB}U{j+JF z1fLggQjz6#IZh_^6*i2`E3L@-*3YRRCnrOwPS4J0-?Jst{Xo92?Zvs0#BB~7{IeH~ zepg&etL@NKqxB;-y{c;2weKI5WBbhk>D675I$cPo?*o-l)nq_Ro6o+Xr=#O*@r!@r zIhpx3?n+cteP1!}(m5NqDNEX)0t3!cqg9NAbDzu6$@qJ4%pbHKq5c>d8wqzbIgaN9 z-1GL%qxY!{k8tMrAN&*F{j>WFKcuufdJ|8@|65h>57V2)-H4~vZlZvhg?Put#+BQp zm6c)N!25rbwD+$szRl473UDapH!5MS{cPm%Nc+CadL#?jvH;AP+{ej4pUnYsnS-l4 z!qcjm{Y{sqg~K-|o#^qR_b0$>tbKiFoK&H9VRvkV@c2l*P9Zz)&l!Fm-k2NR-Vi?A zSnQn8BtbJGtn#PZ0TrdAh@eX62yJ9G6@otBwGNAH!;A@(S%JwV6Qa6TF#D-~Qc$i_ zy;PG`R?Al9_C;Y09B1hZN(hd}{k^xMeh2l41Rcn`i@NzffAIlg)u1O&f(^E;$x@Dc zAERw+J({z$IM@CcU?sw`#RHEH9q$?rv$KKUl=4YuT3KWp#KJmvI(zo&LM@KEWe)s=;+Ai@rPO4UJDv!O6n(9np zpDKW+`rD=5@nka#mN01*MnsZQk~|3vv}DYTm zTL}G;I`+ek{m95rj~$;ki8AcP&Cm#^%SkSjL`|o~y3z`?^?-FbI`ZC8V1~c3g~2AV z$f0cR@TcNtQbGZBYM1&SQp9N&;@#ZGcm|mKsYTvne`gNF) z84u~=_pQBU>Ci*O6lwZV5qu`Nyfl}SlWpgI_7LGPqW;Tecj7O4wA8AVhNGvj5M|?{ z2j0t;ciVS5Zu8k5Eajg~Wyb8M9+WT@!w%?oe$6;EcqDI5UzQeb`je*K4_tb=ucYG5 zG$-RQH`R|ncBhVBCJoOQ{p*rgu&{2-{kGiXIv87HQ>yt#9l0(zto|YBIHF?2p&pPf zZPJ(dls>;n9FCPLRNIhE%IK<1mGTnCCV+fKSk9FZS;dfzf1Uh2ho^nBJ=h$|zh0M@*eP?;FHK5}#9F6Ob3GeCp zB0g`xQl6h4gv8FvWV&BvUw8FT!Pss6{2A5uw|@loSvNZ_2NP7uyCy$2VritvA~u?y zGu|xETb%N&Gg+R&t*Cw=L7sg6u;bis=2zl`Ym)6~a%JfHGKze~VUIdI@z>|7g;z|+ zuyI7j&EE)GctH{qySk}_yn=j4IavS;E4`kzj|CbUj&q)Wf)tztM+y;N#2N0CqY;KJ z69R&vg~J(0f)1pV&|=A*OQ`Z&TB8H1m|UcLWRAwMQMHm1(4Y`MnJy?d^9=OAT2fXC zOGPNI?Xg75lmU^{q>klnz0as$6-I z7@#OLH%x~IB(hg$^vXkE=4od=*Y9ZY!zq&CTPEVvz*FLr^oDMyBH4389ZX9C9^t1= z1{StzrXsb^v2Xj!%F>@!rD=Wcd^=p9YP#o}xoG9^Vh;L$qeIi@NbqEAVKk%O%pD>C zp~dmO*YOwQxO{+sW>xo&kM9S&+=EQ7VcsA&B7kM;?8B0R=cUM|s00lscvk0yS* zQ`qrz*YUJ`)jl(hbQ%pp)85C>kFE9_Jp-=reE`oC?c-nC$BLEPivJr2kMBp0{|`}E zbw5zm3IzV{7`a40i*oXa1A;72X_x#nc#tK18z`7T!9?n3FDnT++)eEVGR3<0Oj?SE z0-HH@{r8PO$t}5x_~XuvO2GZ3`-+Im^+{vL;bF&ZS%)6c{h2lA@>3>fz|~dYwpHsU ztAa_xXN*M4!G7lcj{rGJhk5hn4L9WviG~4KdJi7R&OY&#l)9o}YZ7(VS#Q~QzI3q` zdhap~nH;h=5?Xf0Uqb61&8DjoS9ULb{?=!(3^y$eL>aut3f?_3+Nq$;iLZ3ni!S>l zbdneg;pA{D1k0ihFAt`?)+aX4_J<#XSyU)>@O}@Sms1{z2+s7i&M(e!&l?Gy6?biw z*JJ%_|Hle*bpJHB!9Sc*J?B;E_HQxt%kcf;k{-E4!KA_AMS~LYvDi4LRQcPLj;WXK z=SgLMTb3$A|9NEu;DRdA*SK2SD1Vee3z%JGtY+$I(TI%iC|rx{T1XAcXd+i{L@E2o z(5<2meo@ERNrH6DFfDMX;iN%U9y^Aec0vBsg7eRUz)gL>@baE9gs9}PVPncw2Sw>r zYmDbpL%Q&H?4DD%v2Qb+G z6yNM13p2MOMqZn>KFnpOFHz$tS@j)#nmYdR_2BmfIu|_u&+vQ%>b*mP(Zsr(iRDA4 z$)y;t?*|`+wBZ>lUUPE{jjWAHEPK%QL6uLqp6+|ZSmZw zx{$6e^ZicJ|KsQ^!=h@}Fgi3yBPk$V(v37oHz+lW<6NA*1Hg7spu zcG;q~Hkm@$^~dC1z%`r=C4?l+-<}^sDMf}wd)L9!g~L&6xokFot|ydb^tE(2q{p+y zp!=t&CI+5Z`42^xgw1sy-`CXK*_~RknIXt=;QV7b*XefNxK6eY^eh^MTyj=T^YcfL z@P16{OC(&xkZHS(!!1V(ivxLa8XCQ8Br?>0%B%{$6NAx0r${s`tgmEDkkgKIE@JY7 zir=L6+HJhk)oh}V5*@|#H$i7Xe*gEYn||fAoth2=mabL5=xF_Q=HTjjVlb4N8Gxp` z>MH@vXuR?Ff{jyrCHFuo&^D_%0+Y76H^*;U^R*$WLAoVJ*l1>lNP@gIKDXw)Z%LJRP?d zoXQsWu0>fCwBXjC3h=2_r_LwN9R*huE-;l@%gASSD~#J*xA%BgACM%xcaFSv!cmg7 zULn`~b2#Y0+Ll7<+x#q@dl>~{=kW#+f9oua$#abs794Hi5{0DNYa#@9u`O!?T5Gz9 z*SwKt3Nl-+cS-VZeeU;4f^H*&ZZiV+G6Vz!D46~BCK$Zl#c>0;spf~{76a(a=4Nrx z1EK6%&Dm0CepZ$%BSjhjEPO|1zAof>T98_!RVpMHC2-W=3KD7u zo?FA-4yB2#(AaO3U(L>MGfDxB8Qk^2)f!n^b#K%8ltOTsgR>*gfztcBe@yy?yhSig zC4?%S0WkS(J4>`&+x9~sOe;x-7VG!)!1>hy;I-C}Z8E$LFliLElcu5gaS~Q0fF2;@ ze$OxeAX$&ZkJ^#9b$5}@)Is;+L)z?$E&3DBI5BU~&yY3eFjsEeYba`S2wcvs2rP8D zY4MW<9OAA-;aa628X92gEoaFj%e?-?DAe(SCm&}?${}Z}*CPDg33Sbk>xBIF`P4vo z@vC`_|K7y@1QD(_j3V?Rk-~jLbZ7qvk&_`97Q29lXhToM04iv^Je;(jO?UEJwlBLn zBiUnW&#S)4aG^(htEG>&L-HLD1@zvJfgTkPIfUtzWhzkzbyA(#DihSw<}|*Gce!rP zk;#ppTY}e!-LEN;q*7qC^7>v0Xc%Hwo1zX9YvMI4W1^x_pn%!&$c&t@g#{)hllrlc z`@S46>9cG-KKg4C4qMeu?g7OjP{-6%DzAozo>AHKp}R03m*(T+BX8UMi3mwmZXK*C z2gU`Tl|A>Ko}MM&NwCQK_x(dq9eY>T_4})XcB(Nh=58^m`={s2{~q_eog+_jkYP@m z{qlc+2%wds=61M0N}^}OQ?yf30{@##Z#x*CoOicA=p5fC zOH9$mE98nsGOzqIqw|qi;+C7kl~m)CNtGBm!@R}2@MJPUy9 zv_S==(#cZ?US4Xwj88n@?GPwvJ|r%!9HN+&a%)=EJ3wi;4nMDA)8Zw9ls5dC_87oq zCWNN*p?DLd!(BCK_{EpSoc>bKI858D$Sq;}6yl$4OB^Tq=-9BqcqBf@d+>JXTg%Fr|N2^QMuuOd&qe^OM`bf%c$m|PF9YuD`83zg zvbZ|8q#gLww?6?%c)F%q_3S!adpaL_J=*%<{5S^nYV$O2y6XEni$hhePb^Zl`1)dU zT!#IZfU&#qQs>gj%G>$kmvzqP^{a!~S~ig{|2ndP#WlHe>-anta77D&K&>pQuuWYGhimME}2>l`9d z2sK7jI=i0SpiS;k4DsmTJmusxqP{)!RKXRZ@wexCW`F}vmm9AJ4OTV z)!E1gJ@@V>if|>G8-?J_o=1Wbx7l);Y@7=JCeoC(`oPe~2dbyt`}>8Vq00}r68-^q z0Fi~e$9v*o8TYyVQo;Lq^l1qWHZ*MXz4}eK{+jAVugS1}2xfPMM0L9Yl&Mxzw3P1r z;17OzJ3xQZ_3oQiX(I!KBy8o?E$KXR>V z^BG4h&?9U9Xm(m4kj@Kzba|UtWuqa0RfdUbwM|q0ujWkh>t$%IZZ=v^Z*Q-?H7Dn? z>;7(MxUCT(*00#J#AHLGM%Ms;|HF>Q;+Y5qwh$ogex0_f&FU=}KMjQG zi78*q&&JHEW?X}@geD7p2AyDJSd+Yp3mrFoczFf*jn~(ulX|bfVu-nry-e$osgj*u z`^g!ZjgOPF6^`XlD12+!d9h^gvI)}`j{Pn_TmMug$ZxB)rn%~D``8sP+(VO9*w@Q| z%z!JNx#v~BFr?y>dKK-rK4(#rk-6BO=*nKcK2*??<;pN9U;t;<2MSZ+asfu7| z1?->SR*!|OZCz||4$0lr<{wqT6##YE-ZDwEKRhy$I-vRHh9~VtJN@?(rQ>Lo)hC>2 zw97soW++ki+((30WjQKZ^K7iCT6E3H{7#PjeKw?eyos`ra#ak}rfM-^{g&p$Pl0)t z`smUG6;|$z@%%ktdu*`Td=(y20|HH0b$kN<4|%eucZj5tl9Y>n@BHe+3IY@nWF)zn zct5Xi2fO~0Km*~TpMhtBT3ZYlZH*B+`~u9Qsl9CjdO!r#&}gRS7D&dTA@y}!-dWKi zer-mP>HDZ-6*v+3lNJ#*BB29rSXx8;=+RSC49JD7r0Z9Sl#8eqb_-F9eNbZtMWLJw zmc}n>%ccQWZNl(zRLxf`;X@O17at@+3hJe2OaFM4sNLfEbz?mi@l z%9zdD$ufs>Mg1AeNJdZU+j8?=`PEHJgIqwNk|ZO;Y&!> z*~q__zDqN}1R>CXxRaPLAXJ0{HQL0n)33hcLFoCw7zrSn(YmNm7|cHZ{%JL6$1CvW zc_WgY2Z2l=wAc(8h`cJHfBy1|6oFEILacx3wQp+pv2S=qQG=K46G_xsQ@dH|r~B>e z&L^Xn$NZNId8&X*0E1-xvTyQKHZncdcCXa2xT|=wt8kou3=KR*3p)LeL#_VUt?qxG zlK&V&b&Fts^sxH!>`d4-80}g5$@Ni7IzJ38Ht&*8uc})OTkUPA)Yt+u&6u8JIZEdY z53T;NL*}@ZzSqM7v6YyFa+Yr896e^Motyp5S>#)`@W7v+1Sgf1S)=GR^vs}UiruD} zWYCZDA%uUbEUlz$;sh$hEJC7E#}#6udcdPMQ0}4D=A^>uwaT=pfqN` z!xI)=BU|AqP+`l^yZ^B6RNJ?>e7rC-@{v<`meVg@&Tw1P&nB@oe7AX%j(0N&quo#L zpR$Zc(NE*No#Wg|K94;{&aw-)E|{&{>XjNs9%7+7$7F5rI*pZ`E`B@u5 zM9E+p(>NUjcZ7O@{FeykQMff+>*?NOO zmUHgJM1APTT>UY`0Ir-bZ|*+fiYh*P0zBkv=l8ywdX5ESvU&Ovggz}kYu`!+G`k~W zbV%&9rN##Dku|QrRx6d#Hbs+?c$=~<*uoYmwaLrS%O|HWKv)KYJxZN{o8-(w)apu= zrqXhRTI8p7N$qTYmT*EaP1%GwrD{ez>u-{KLx^aGpKTUH+K=QnWMg3kf#dAtX~A{o zYxwwwzY8nY-L@tgIhAx9IL%zkry70CnTGtvtGh~80#UWtW8n!WT)&)wA2wTH<8DtRyb+xcX#dEo7PfzTH8p~5yB)#{p7TQ;~21GoV*=ORsNUT_uiMyFX zNv1R8HJ|n!?ENo;QS|hvJQk25CHJnl$cn%^g43`xOS|M0n# zK1PQs+$)h)&0IVRjRgA_67==wL|xQnui1H# z3Mo~J9m;+8lQ<==A)^W)n(?ecFbi2vU>16aG}u*GAYKRhAwezxVa)5%$bbU0G|LOD-ru`f zd3s(0)+3zIAInZ6i7;TEV+QOSj?T_>pDSlELxC~A(F9K#5V##4AIFOmMkEwFm*YuW zl+~80FYuufRE9q8L%ufoPX?^w3GXVa|D!I9z>5=*)f9>;?YMynH1RA4(n3;sVri9X zTQ#alyydbB`;zd&b8<6>W0r0L2rPoTxW>ThDyp!o78eS^o}OTR1>1R^TCD+Q?3q_m zn+tYdDdj+z7UTRuN2b_f`(_~Pasb;}C-9 zDKb2B?Bv%leRRDpbmlJ+TS(3JJ`HHy7aOq8*zvF43~UjMQ@cB!yu=quZianT1Mjdg z_(+y_ni<%2j3Wf^+`JeFO#`I+GR%^EC&vm|NMauvJ%MCs6fy`=(Y4J3;~yWMsR9q3 zZ*cIBb6VXd^k1v1ZKszTkxq>s{;mrPotLLqhdqOZUSDekggg|!Qh_OcRiP0CVG0Qv z*ZQRIe-3P|!%If746DRe`xO0wH=12drzB~rJ(Fy7$9lw(0&c%w82}jT-!}UD>Q_4c ztY$AiAT+R_>tN zfrInE$JyC=)($3TUT(;7_Vx|rftNCRTO}daRS-Q?DBcYBXy~FeaXJq`fPcd5@9A1SSbT@hNv~fHiqK+TNWXUlyFTI7w7F z6LaMGNk)S!+iVr|rhWFmLC)^_zuDcIh(C5_JGK1%z9*#5unufc4kzx)%s##MebiXm zV@_c^gx@XN3pzL-$Hvix_b<5zteqOUAYNS5?r&dyV|uIR`*Vg%9|2d?{jM@#Rpg>V z;K@mF`1QNA&|A!W-`lB>GpgGpzuAo0-+IRI`^!#quNm_ENgb!-FhL6DD-jW(<%0R@ z&kio-g}nGVzHVUS8z5W&zwmkjQ>(opL&-@ebk+Gaj*AP6t!VrzAilzT7$aW}(eoa&S}A`(An{zBk93;se+&Ptk1! zT%5jDfAYjhi>{E<{MUQ}^R@dkVkXV6&d&Hov!?_EGKv>JptXFX%}=hRnP!LRxRxnV3ZY^2?wWt2lrl^A=2J?Xu%*wI?k08ke)jgzNx=P& zYs`*(Xqm$`^Od~W%;TR-XbI66T`LHJt`=ug!L1kl%AQ*Se) zYHL;tLiDKMbm+;qV^45=Yr~QsxqX1U3nP|T8DY{F$z&8ZU8RNWm`kYVX!y?EJ}o zx+#cQI8S1 zJ`3+V9x1dMlpM^CF`5?4Q8Q1dCUQA9?{KI}=`F&}AtIo!41ZZ?ws5-qAj25rh~6fX`L7XZ zlZQ@gKzSDAt=%h~!yn^Y#K6rWKStUHKGZ77D|&ioU(C6nI7z6U^L^B>NaN{H3GS0d zmy$+LKu3_mq6mDC6{-Yzg9>3jFYXp)P1UK8iI8Hh=q|vrNv+t?kZZuLNI5Wu&B&Sd z?|&l7)6Jr)tXotC;om}N1*gC5Z9J5$H#%!G?0LBw$(V78>6D@B(PMz@ujjN_VT)|I zLu!cCGw(j?3-)*R@ua0`SYU-V*SEn6V&s@d4Gph8By2lb$jmgi`3JNa*p!tM=24qt zk%e%uBEGjC!^#sBLYHCgzdNJj_Llb5dWHsF4wPJwQ-zTx-Y9|cP|_;{Jq~HeWH2TB z-h_Xl*9Xy!`J9tRj^HKoo3i;87{WcDir`mC_6KFssKT?LL}FpQ36ex|$Q&|#@Hlf> zIfE2xEP_>xPEjIr;=Bz(l*+&xMN$&|O|+J5^8A+#iTjFslQMNxQUPR*xzD@IAvW_k z1gCslKR}Lo4U#TmY)lH2-?mcdL)Ov~qK;=e#5&`O98Hdj?$6C-0&W=v2&E0%{qI(v zT7tZGa=o5Yg3i@*>ZhkUmYr@o(Wv|n3|9A@PTPV;VocN8mMNfDfIdiG;(q)F{_>Q6 z+szcX8yUC@IDZ;e16!Wt&QIUL#$LY-=6VAhjr{&~Jl@U;@giYb-;RPh20ELyKy*qp zb917z^wfg}%*7|#i_q-==YTGWXFrLXg4L(ZKi;<0I?o*qK@U_Cr$e4@CERUixX*VI zkJB%g*%CmW-@n%n&aNpY88?Ke@JcJaZSaTDMz!YV9{23)GWC>*98t>jeflXB z1iARb$+B@RY|#9sVRFwxU*PxDG9|ZbAH`LpyzvJ=Gtr$m0pEczGd+$B+wb}ND`PH7 zO94A}h7EVde(IM-0WYE`X&w5y>l&|zVq-t3^7H;MV;l~ad~?XL!0=;IMHjz5WZi5x z7ljY&%~)eRRWQu3^HHuUvOgZ__Rzty!}`l)IOWs!DHj>&prg6%_4(WJl^7gh4api> z%R3?j(c3qI#7Ii1L@a}xxc?B4d`%|Baimg_dEuhLOzg6p&$p$&3V-ETg)n4x%aVSI z7D|%l3q4me@%rIh%B&CPT6o95HvMSGt51dSwS#2Ey)@l!T2nCz5|#XIe1TrAwFci- zv!F4b5k@UKQPs}Gn@uk(YES|7N--AX$I|BnbiDId%2JTGG^9O7j(x60I=M-4GNsFg zwpJL%n}eY5eO);Wev_Km+6%g4+@n8q)h2Z+gH#idSL;#~;l-FvEH+y{%dRv^E`m6; zoQ$b`TWs3QU+H>#MgsT)ulM4*L0ug4>!b+<=GGmPlUL8vo0560H1Gkk1U&`UdKnvaTma>t?j?hdGm? zCw;@BtwHJHF=Y){5H@1&7`v?7R=(sFr79d#qd1QFFsWUBg8^!H-hs_}+albofR3`s)U|PDm(jSuwWdZyzI|h!BR4g_G#y3}ddqG>Bk;Xxz%SuEY4hTsK zTvk5EI93!lahh?})y$+CjeYYi%_%5sQ9g;7BHmvX3trZ2u+%CJX0Q~hi+0|0NzO-p zU>oK!2%%Ms+1k1~I?5f);OuE@XYyAc0Pts8dS_3;8ZwX?^REP?Qh`gO=6#cOzdk8x z64L6?>h>aaO4^)@`uKkV-=XZ%#{Sv@#eYKgoZ@`g9^s<}+voZ1mu_GCLJ2^@n6G64 z{3%C8NEme|SLzel*9y+Bs0j2LyRXd(_(^SBpxc?f?XJ6@qF3rAXomKKYv2a&4Exd$tGE^OUa~* zdbDqwxS(LCa3X$xr;&m!}h;q`2ie&#oKvG#m7!Y;r&G=g%L2(eZMt>g=0RCY!6siL1># zv+(WPH$USWVbj3#$GafSvZt@~-(vfL>Fm8^$amhI(G)>6+&%z6E0rnI(i5@I?hEUa~6POaE|j0^uD{OcXYlE4IvFb70EpgzaRlvpcn3VX-wf30yz1u zRJ2jwU4W?HwJ-1F>zIpLLqdDySyuC_yT9Sdmqb+v2fq0o9Rs4cUit@mt@L3#iXgcV zIda0}I1q?e>BKySI1_&i$KmbJ56rbhTgaz2ov&uKPSgYPpG~3DfbvioG67M}sA0>{ zA}vbO($Aw?zp@9G5DU#M&;Ji-oWByx2+;G6ul{eEH#eC?mYV-ZtI`T|drrU-g zswUM;111|kmYbbRnxEO?8<2*f$n`3Z)Y(1ec?a$tR5|&)DDebe`C>!$#sKFjyi^Vk zv^eDIF{S3dijE-D7Zq%gSz@*A1V7@~>)#m>pFZeydr+6dhnlpGowx&#O>vY06OIh> z>EBFYEOjQ)#U~`h4=(wd=rplD?Lp^%Rz|3avMCgLDoha4e?seWi~* zHzc0_e5h=>3RBMk8iSD{X&P{KkUN%+If( zFU6HmB{mXLRa0BrMqo9Wf>~fv3HUR9P5nyX9#B>$!Cm)nSzd1N?vR!(KO|iEEv;+E zu!`H@wWyzmNk&?=tC`1?AbL-Y;lNkuDKc6!byJe1pKOrA3V})SDfG!1VD{J`$C&nk zX>qs{BVwf-Jql8F1P0S)K>uh+Wllv$*_DmN`HN`iYi#0R=#s>2RdjFzrpRO|JcaWm zEL_u&jvuPp=`BB4xuR_P@$hL1WF2G6vJl2d9r?fy?<6Y7IznL`oRRs}C=WFw>6Pa= zRYj!jqQN&%2Pb$uO60?$$pE_y=;4n*Avs+Q)Sx1vuxja|ze&GYE`n~SdAc31aP_3c zVTWEdhITf*eujq&XCH%D8fUTyBMFii8a5I);Mi1d4^txb9nj-?gCI9#BA@Gd!GZ(n zE-IZ|W34D#f5X}XrvLnPVivWIel&4d+l=i&dhX8;gc%(!jKr|;X{?Ym#MtTr&iTTq zhso*F?#Eb&Gnvv>%*r$~;Rh6fku1udWF+wML%!aslhPiOY)DkdB?6arJ)r`N zs0`;jZA8x9ZdDLZy~aCv#(LC5wpX*U1Z)%1K3eGcb(;DG10fCVzE|r_gEvE?dxcdM zrKs^IgBg-O=i{RMr*m>O%J;tO zI(JihJ)4`HFV`u>bmRWy zLIUOEQTNpS;YU@{<~^Q=b*=hO5>3$k#??&lpXdkgF){O)5jciEA|`bVBie4woLM#Y z7{PZ0G~zm0Oe7-8kgE_f1?=>yskL2YoBV%=o_vA^IQUq>sJgmXZ=2(Z21mVcIwx$T zmc_D9X70qLb8pM$0i_DqaTx&>YtdoG{FRKq(qEuyfwUjyAeF14RB z7$mrK^DkoO-vgLXs-SyiMgs|NEyjRD7?3)?TMwx8J8FQRsghJ0-3}oI`MSSA2U!Pq zDny@~XIIaSPJBnFSq<{xFCli8Dw$54j$5)X>Dg)=CPrm~c0L^CFo;&utTUy!I2_i* z4-dM(oZK^!-(}QBy*W1gQ0s+%fCoajj{e|@| zyJ8}sckTb&DIWE66#f0jD^S2XGq`1iG_n0}c~tJWs}zP5VdaOc8E zL3s6Rw4Tb!8$8Q`@r+MbYYpJDVo@B_9t81|2UYS_GN8il zk2zC?yyllTb3N2_u@NW7A1nNnH}M8p&r#y+0bUvR1mv?dS;j~iAZXN42zaP&APfuL zYpi`f(-1bia!XI*n2KVr4pI4kDeRRNf{6LQxD|&h-^96Qr+D!gNoA;u_Zj$Uds8+Y5>IEfZ#AyG}DMLA_T8=uAnvt4T z>d!?n9-@X&J0lm^N?8tFKu*7?yh@HVk(wb(n)X8$qYgw}?2-rs7WJN^w3|f^fGmH3 z&e6QP6wOYIFkLxiI%YllA*Rr$Q${g!Rs5 zq$n@;2M7*vOGo;J5N=GSjf#GG{u91CC%y4c=GOc~sBwkgB(VAJQmHaSe`95}ImUM^ z+f5fALCB;eB4ON+Dm4u!IVPM?A^fkU%X(^mSp?03sdt>3_a z1pv2T`(r|abViL|I_G)pq5t*hF6RM*)93}CDkRnR4JP;Zqgu8Dcj4pynzlA5Y-N7l zg(W+RG-7RODaVg1t`TwBsbSfvg(=*PG;my>Y=o;4^zTWZWR}%w#Oe6H7PC?J5Y#qd z96a}7AYtGv6G(dO;IUP(zo6ql zZ6Yd=yVbw)an(Tpz@3(9RhYn^3vdH~qsUWN&@Jxjv1?%{rOm=yvpmbwk;5^eh&#^%m00`l=^U0Ak zEi5a67l-3u!{kn)I;EeWl&6vyX7=V6{Y-iB8#!d*q+(3iATB&C={`wbJvl^uQe)%Q zc}GumioERA2Isr`tHNao?_E<%yCqtrP-H|;Tr1CyzqlEPd2ZBM!UQ5Tf8aSJDg4RX zNu@^k5Z!~9<0szKCDyz&B>HF65DFCUtIc}>dt{~YG?=dD!oh9i@mNqKS1oTRCME`8 zhyoj<##$fJ`S-EnPMo^^9vy~6!V4kzm|spYO(Cax_cZ-rnX!w`nw`m|_R_{xhWhY- zpE5gMQOYHVdtASqy*xeujLWB|5AyM%0mn*3;47rcDu-ARQ@|`mD{SDe6ytB@v}%9s z8_;I#b3F8#bue2VC!b9glAC)VVnF`qA{;M|No< zKill_g3mVSQ8`IbBK7IZzT@$`JV=jNa%b8(za9rB_79xIUCulF3$VV0R0Pbq)0oQR zBb(O$%kt{OQmA;nzMit2Gpb<2p8E8!%{kDhGGm5(D{f|FdTY1{bFxV%3O#i9E)7|) z-U0h-QlIPH{eAc5+_lpS_Dwtcme3xHa^65{>i3`7(*xx*Jn>yloPPUfC0+tvzPao( zVj54ai!BHB2An2FN+L!kT5SRlAgGZ0I42)iQdRDTMXwLZT2>vKpVHeJS;SrSnQgP? zl-TjpY%*-w;jdhtp9h1%MtV8Io|mV3P+jQkXdYbeo%RLWjsLf9#dP1iNSUM`TT6rW zUrzbA-?llwq!U}nm{2)bhGCDry z;-KJKY1emTgAO6F+^C(T*u;P&WPvngi>&&yDdbaf}@LolpH4WbvxokE=yMRDbN2hQ7;n>VZo0#(|E%{=)f^ zXxp6{>6falYs`mUe8wQn);C?teK)H?FJ~LQtLNzrry4p35iM{4Vy57W-gUlp6L@m- zJPf}BRyuDVlYqG>gTt93>aFbfe|0q=G%N;$Uw7dzH!siDf!o&Yfpo)T`I3Y)k}w_t zG5%Fs2K}GXt5j9pqzLGmv>*bJqjm=KId23qY18v>NQ`te0{1;4@h?w7_wc8~^K_<7 zw4j3q@>+BFa|_&cGyN-cWxF7I+jCu2nufmVm-CqMHG*%A4CDieA{Sy|#wIinY zr?qF}B8O&n*raUhCy{6=VQk;qRlIWZ;9WUhQ|n!F*I4l!lmDoc6u!ANT&FtLo;AhT z>S>Zj_uk;!D~6gn-Sbuo*^(0c+Sw(&f_R5&HDBKv4&QLc)H2C1wr$-}*h}eOw zH0@8yMW^3tN!fFpzO*A3di@(jtM}3@ZLlQ1l)5+JX6RcWL0^~OlA#V)Ex*T2=DVlQ0o^S(>@)4RfOMy-eaYx#!Cl7WkR$%93;6-7DeO zo0L-7axiTE&;yuG=Lgl{J4Pq>|FJ?7#4nmKGb&D2gZ}MLD|@X3kS`3-C5T>2y!=B8 zd}t5{D&6>QJ}j(L-!_;=^MWb}V=eo)xb$O5ab|mG4&(2s`aF!TFo9^Gd}Lg+yuTC%LhrGm4dL4j2s7JN7zP%%cg(`N z#%M<}nyHqV2XpCzma_`E+1Un0M%qeo2?-DFCqLTb;;?smzC{62S*$Ln1_Qv_wp?*> zOX+jkyi$>Ey`(E>h*QU_=oXPvCC|5XaswdcF>T4YzaW^Jw#CNob}#msveAaPcY61! z5a;4ekY#Y07DR8wj2?01HoS`oO~!MzGHcHNS+)pG8}>}L>kN%!8Dz%#3gE_1*(W`{ zZq^|lYnY&si_kc!)V|C9grK@l(d{Q_&&~9sdL;>8N;eM~9R@jGg|Lb65;C3AAe%!y z&~)sVZTJSZctApe57g-I(xOiuTqx|J0Ee8r$Fghcz$4N(PdwlrSmttI#v#O2bL=@J zKJ1`lNAX2T)ON5%0axS~yb>4x3206LGlqzmm=Q|HnA)kx!GkLQD&J zIXNoH-A3eogK6;Mu5f&Jzc#0mje7_nMW0@9E!r$Xk>W0jGx7lP?mWMkeB&*IM{U{v+VoHh%ZdsoX+?nFJoNt6+88IzRtl z65xM#?>jLnHd;#{%EEvWiU@Jfvj%Qn9nyA#E+cmJ6&BRB$zTLBZKQOJJRF#Ep3)-nA)beeo zrYV+mUE3$nJe3TyiQ@(nEs#Pmr!or=u~JfLPaO-sUqr%hn_MB{;_uf)*Ihv8&E|Jn zu^~nYPmsUwkv2L?l&GnjEL3EY*(|>=hBm$|q@WqJZDOid5Iz+W-yyd75{(|Yla;LthRxCLl3g@boP48d%+GYXB z(NHy`-kB@1w)v$Oh4Z_OlYqaxl?$ss!K0MQ}W-W-sZI46a{cx>%*qo{7jPljtm zmGf)|GrvaKvpwG5I%NI4xIlxuzA%-P^afs&JSPlnKIg(Fb=4$ln(wC?+8m90hbJzj z+k^w|Ce9C5T^}>$N5!8`=}v%;2--XCH@s-LTfmQ0o{;9;cs8{oe({ZtDPF4-y!m^1 zX~_^?S6_41ksRWaMgGHCwZRF`QdyHp6 znESdyfL8id@SIYA~4r3wkeu1SgPyhLV zcYv$iZ*VD>TSd)`XYI5@$l7$;k&q%F#;sR^3bLy}+d$hUkf0_Y;6Hs9%_htarR<)$Zu{fRB|QVm6Zgej`lFrM3rng`Wv~a{pqrCtPKm3OoA#|E#TKJ?vbq8d zezsPzWJGjBv0r-{#l26*$WQ$2A%;GO)s@CZ&Gn5hbB+ygE8DyEg>!8wd<+XK`|p`$ zFr_x|RoLtSqivR~S?VSkHMa03=iV<-&R7J}M5l;ZhUUQVfI!w>f|@Sn42=qBhpBg4 zDUmmp`fG1mCoUdbw*8VWK_Jp{OJ!!Wj#)E`g?lWLpGX4{WiH4+P!b7xnSKv_ad;`% z;V=X*31UP^@-zm=BCHOwxr94$ZH7op)$WmQl~&Wws*rJh<_ zi3w;sJN?Z*SoBHOo0RbB3i%KtD0aQ|fU+;xx;@f6c6l$NU%~p(+`07zHku;_<)OTR z4M>qwMx0-Zm`I3mUyt0ho;=?1w(nf|<^ljBay($pKe1)iXH-+P$I`xap<30BIO^blVm#fZfnrN%rl{$ViK>zQ_`yCx<|*sTC5dkh9_h^h;6tonsdqStZ_&YW`w4l5OzA3Se|28!DycDt4Ysnhf%GWYbQsf#f1CvOm32f2=gXbqm=>Nnpp5;f2*P!a7Fl`K~EzGCTem@FADX6b+b_?t@!gCz-CR1X4? zW6L;TS99HygEUN#OPcH_U^zKF9`4zv8kjHqD~@%pK)rrs%0@Dt;j@)4&oR`YJ#B5p z)644yD5l@FpFD_rp*8)CWi|OvtM#9B>$a2Xu@hiNlUyMJ5DtJ>wQ@hx@CR?gZ#=st za2J3uuHLlYJS_%2I7>XP;r{=dHtSsA^V~GerXEizkz;A+>bl=U?i>}`N6HXpfjJaK z9XyW1Ci%USQUCLJpGNXdEkhl$Bx1)0GOvwhX7$Ll*KTN2xqsE4mqthO!E<&_pY=T_ zKD}DyA@Kd9R6kVAM_%tRmyCzxgiBoub5K;WG(6hnqQM+O1SO7PqW>b40X+^e#3{Hv zgd(|#+jD3caMd|F&3k5LV%gLXL!EkARlg%n{z{=grf;mCuZ?I^g_A>AMAsJz{sOtPl=x@}nmw_B-CuIlC*^1ZtFK@BJJS(I2v zdgV|;7rmqG)hjxc=RdK0N>&{UM`X95JdklS6|q!8?Yg$X8y4n6N80Ys$8nS=90A`B z8=jAdFx?~V$k`_LiiAa)Zkr^$zL*YsN};uK0ylkc0n18l@*^5<%*VLYT854n6=QLa z=kA_(QLm@_Zxc5l6QG{@n`(vNY-hD=_(0s^qG9(z)bD;T+o{#d&d#Tm$L(tPTx9LJ zJ{9UFx3lt6f=eag-dd{%9<+>xWMv8K7SSF!*LXKlm#h=z8}r)Gg)e;W@%bJpiQbiF z5QV~B(u7l{{x57y)yjrmi~MX%p=3=fPt?;Sf1x#p=*PQjw?oSUH|WCte6?+rQ}gPQ z%}`x~Zdxu~&nI2FDzG;dCSsR=gi`rKHNu`x(Apl+;wMKA6@r|hqiV@`MhhZ zQk-(~p!$P7^q+f6ti0J)!QJDQ<@;npW|JyJONt+;aWuGs=y@UeIMdwgfJF89ye~{vOlMn=rsCQTxOSYZN= z=legg0;}!=xs@nA%$;}0&A&ust}wwv&% zymk)IF(Qok*WFyS^?!^PX0?t8JRGf46UDW+p|V z%+d!b;;B!&5v@`9Mb(;M#jneUv*jTpGKNsvXN`40-U3ukhG6i7hGuCDMuDgrEJ(Q+ z|5hr=eWi^883FO1G?NQ8NuVN87;6e119B;y6~8ITyZx)7$ZA^{UD2fdf)7kl}%T+2pJas~G!;LBcV*^>B1L&wf-W*PZX?$&&l&>y{@SLdo7$wbKer`-%% z2fG4`yE>P5WAkrV#~s)-jhpAQa;Yj)+IBgOXj!f&MmdSkD&UTYh*jv_x(`VJRXc?Q zwJZtnNo6}WM@Cp$LgMGXRiwI5c(kklI!&NR2K1<|8mStpPQ=Iv_)2?#F9&F3ZywHe zc6JUA4}oGenSqp?T;IT;4i2z21Y$jebH7vjd%isPDHnTRj0uPouB(=8Ld0<;9;^OG zuEf-+uhhp~R5z57%S{1!E{+{f?h5C()SDeo8<0Qo`;217X;< zMhfw;u84?uT6smt!6sIIR5z})Y~klKjjxZhWU`11wUUUW@d~We0}}Q zJp7Gyqk7x*uN#(zF59cAAI}2#VJE%AsRM|ETsdC1$8)WgXOlq_zW23iqIWdBY5-91 z!`kg65^l8 z)Qqv8`4y~TB7s#`iX>Ix`!)basrZ$k;b?E~yRVrC*44c|K6!R5!PpVwjCL$N@ckNH z;A{f%sgL`pS}&YCp)h3tQPay-D)lqQ%7@9@VN9J0NRhpOLlQGTr=yBDOGQSISqlN)Tk^Y0m;Kh#yQ6Dx`O{Qa@Uj4-6JQOwE~Q;i*i z-Cclpn0ywBLXI9y2Xen&3}H$~+V`9wk+LpKceXA%dCp`Q0%96~s|kn04bD#PkyO=p z>nRaDxkJmBBgNeh0dR)6&vm&z%AtcuWBbjodeYLf9HGfy&n_se-lK6$3N)|{$=f99 zqBG^fD$6g9Nkb#|D9E;JhnM|3^=XaSMK2x3w*oISH*F_NtLHm3C8LWhpWv#xHXjE!tEa7@xfRcuQY_-UCigSFWV={NWfYQ>k=e+zA#byC z?aE>oZRjk@P+2H9V{%8-s}`^-U+~%87N0ynzXYtLWB+`0PJqnTkS!RAX{|mg7)5;o_=l_3LFpO%c#SK7-K z(2wepB==DFnC_OEnzmWiH@FmDeiQu_^3eWADgMABlkrIE%UJ9=rj4v zk2mcuB@03UHa3oqYvzUZf_z#|F-QD!=@o{*1z3TdpeA4PfnD}77oBX%yIZ78^~M|& zEXk}_A*nP7BtJ}|)86Y!ngDL4jRz_atv9wddKqTTgvu6sh#Uip*cw(hHy)zF()dN_ zk&_3hrUoas4P|rdij@8IdQH}_MmHX}C2ja0K z=4>FGUPOd1P3=HF zYC4cspKzdXELXx_BlK^&c0nKec@ zvBri1irH`t$op$(S&Et53L`oRH0+Y3b)(ChsAh|?{Q&?*eF-p(vg$ZOT65X2NX~{{ z{U$ELjtJ(c`Ia`Vp5yyouP+YzdOa6> z#Se~l_7x?W81`yhPFLAHsNF zUj<5!l7KQmVkWOT0|yt8zM!k}%}wSYbIU+Pa8HF$B@wyfym1GSOxFf?F%3$u)7zg* zQ-(tVh z)MZTv@oL$K3IBoiOo@yof!U8O zXv8-sj+I4w@`NtaZ&8jU9uKJ>cLHwXjc?D9sGt5grIS1FEb|#&f7%}$(4gmTKPsBo z@oIa0AHyIP1WL;s+*4-9vl|1g1H)6DC~2&MqPeSJR?u4|(@u{GjUc#{`$~82d>5=Jz!9MlH^`uUX)qE9Y;G=Z=8$z+ktd-UUBIq7(9ihrr2RW;03z;Y{<7g-W+jGQd=gD_ zN>3=QKL!s*!Nm~kQvVfWd;Jhxbb=B#43%5EfNRf*pH;`RAFfI8z3-tx!04i*)knq? zwN9hqZAJ9cUSXMEy<0)4-{`$81RpE{0dTv!#O`B_pDa5U!+WyYK! zP+stH5V;Fcm7*(c`ypMJN>Vhnqt=Er z(&}4~OQf}nkY8zkVmK5fAvXwaMS&LvL?|IBRbEMk?Y>@?mi=5>5rdgVv<0kROXi{r zfb7_TH^jRWc^#L4FSIS0Np02bCRZa0D6GbFyp92!H51?$SrM2!x}0Wktj`ML6mEks zoQM1XG!odBv88ZZNQ(Ut$jfxs@kvx087U|JJEud%BHDV_$Hbp~#UlU@QcuL=Sh*yR zJWQ!szfxy_3`RF0(9poP?d)wSUDi5xz*d~}4!7qQ7NHU^L^u%6{F#_ldCn6hLU3wDpN%`cI zX#z#6#y2g5(=K1cjJ?|lgDCnpt1U+4?KsTxKI!&=iKJC%7bs7eG2s=)LIL-gTdl2SPYGIW6_z_WVqYjN!+o=pc<@?>3{#xtpUU zkMk`hkaMkO5`#{Kfs5L!n`{vgk^dDNqoW_vES8p*^wLt5->t_Q8G7}`NKH)H7}HU;H- znWIebjvmvE5FXchs^Dn_ii%CuO?LnRolVZj-qF78#Han>F$@bkP%-+!a>A(5fHSq9 z?8>rCX3)RXJ{BgArmjbH$F?xZ<7ZhAh%HV}5$>2&x?7&W-TaSz^s~U3iSk$$S9lKD&M=HXg$} z8s0^+MlkE$v=n*4Fek)jd{1P|AUqNMj*Cg}?z+Y4#{6+TPrSKqwe8^5z=VVgfXDk| z=Uofq<if8* z)u#}Dv+iua>%~QhR`+95+TO?Krp5WolYmpVnVGIL&4xPnjm&|(r+KD&qlaeZEL|RM zAz^$@+c_@}iOWeDKqB`9Ik|%XGzhef_%~HHS(aR+I72hwmhMvOfjq396U8J#by~{^ zBu!q>BEc8`wX(z@s|D}r7SAWwmIch<^W}CwzL^b6E*G1@}FP+aw#WVnCqD1}g zHT?MeYMb0iu)4k8{o7r$%q!8?U{V!H*?wK7FHCQcuyF$eG2YQ(NP|pd`)as%rl+s6 z9YuNEZcm5%*lY{;2#x~AUh$t&<^l9UbPY0)B#pN;YCEomcli(^A0lo9zaRyDcty68 zf&{U&py|-BOcSV>>y{!QE^ytBDpNV)uIiahpeJ$q;&RshaO^fT z78lhe!>2*=*Uiz2B5(DnSIT%I`hvmMjs%-KIR$cpW%tpe0Sm<^NW<2?oYl9Zw#{s= zL0LV+eY%Day!&z{@N(f^dk1&&@%hA72pWruTu_Wea5dtH&+}e7VA_r6Bhe1K+~yE? z1Dn3xKks9rdU0LV8HJN+Bs!7my32Ce-!T-R>d*DRBM&v<2i)#jTjg}(3QrB+k(`}f)_HphQ# zO$#+ryARy&;fu>8dqa`n*~M<~0a?$#a{7d>Ql6YwDEg8jLU3TkM*MTYG+vVu*EeWo zyt?)4-EjYoa>-of=Y3q!(^P^1)sHc1d`Z;Ee`^xj18i~HwG_{fBqD~ z0LkEednCbTEGlnr+w=9cd&P&Wta0$g{S|B%(qdWuORL1P#O}?9MLT29V+uTIr6ZM? zdy#gbzeZp}8M$40T7~%{GOd8VVKMFTjuy9kOcr#M5CnNfjM4r# z8s5RW-h*jT(zXus1s16F5C#@*>^5#}-#v_>3TUKxsL2HV2(YI%_sUPv=m*OugqkQJ z@zFI=3G)!p(PA)2Nsgxzym0l&zl;dxXvXe(RkU=;B(EjjTggh0R<|xa9mB`n%YYXF zc1nGDj!FT+KR#Px{_r9c5-b`;I{XAnHWX#rq7gafbJ6|^;y;B|=GeFGAsFiDWJ4i% zQ+fek+4Y~(fsS!vM5^&#uTf0pFF8U9czvl1TGJ?~Q z0Eoh0C!&CQP)U`J%PYmt<_Vb9Ni%Zn1E=Km>im0>)tN(Ra&ofvVN20yxFK3A?hW8l z{Gm^Z8$R}9jx82$xjUsIA>mj^F@cNLyQ(N~fOD$H;&+{C<=C>x9~2S(ssEHD1|fsT*I?RxcR zhyaUnfH%|OKl4%G={El5)+}CZhr+Jo>dC%g3B)ZX_Eb~Z3_DPv6$TLWlp_3#N9ikY zhuf^V)_!P$#BCSus>hn2@vhO+#a3PA4EHWxX5KV+4 zI*!aP8SG2y2%DGohw;0Sh(I;5 z(lK-=TC*6@bv!z(Z}81$tSTcE_S!`}E69;tyVcNfrFQ05j(1N*0{mTeWq0j&%%>Jc z=BdJ!?k!J<^&$)X72q5OM3Fb>np`k&u2J~{A>Zb#AZ%DNi^yyfLGrACuiNLtdxbyH zsZtLtA_a)^Fwwl(J2Wo#U@u&&HLci+BB~Xv3Nm-EhGOl&yvPS8_?K0VSIGYKyKJc#danIz3^G^LB=to*Fy zJ-i2v)5!Sv(wmRq>MA$2yQozC?T>Esk4l!jbcn_&!aZ==VjI4= zcGtKp*6G8j)TwPDs!SVu#}r>7amGy{`c8r$?s+68ApS6_%(a*Fg9+lj^Il-(JcRo8 z`8%~=uifXqm`B(|fNPD$cR|1V%o+PTrsw{6NXOSHut;sy$zvE$^Xx)|-FC!I9&w6i z^;aMJ8;9Kxwg+WAAk(fGK>chMzFA-B8e_otajTFm^S$ zRlJzbwNLvI3{W?wF+tiAY|C8Dus&F%nYU%Dtrm%7`*-L>-tOED?cZMR-@}!23aPyy z%wdG7$}UO0k*-)`cEu=lh;)NMmuWJ3IRVvUg@xqvpqySSY zH6VpjZfa?XjyQ79&h%RY%;2gj)$Q%=O-*~O(}HoirHj42y?{rxS z!q>{m3J7jedc9kwS^62!PyzNLH`SIEDvljWvbuDK^<~N$_G}1*ikiB^{|TTSSIpYR zksbal#BZB}?wWS$(2-0OS5?*A@7X>f(t*g#Bx_CUO%hR(PVPRjp`aYNH*ihL)G6~NvV?8W=|gOY)GfruVp z$N4zZF~4x4Pu zEUX;H#&Hi%>=VCJf75?_oj4=n-ePFy00VzBC9P6;CBd%jvW_DrYt639@YO*wD8;I8 z`22ph%#Mvse@wdr>;NDeR9lErr7fb|8!TXFt(oj&-IH9Y!@3O|Rm(IpXcDw6d+KIw@ACuBO)O05B!d+y4ynWh1(whsGTZH5d^v){GJj9H zvtzpZxcq#*c5~n4eSTl@lLxM?4<&8ZclbREbLZaf)Ft7-#{09IF0n59Ipfah<)|Zf z_inYodEP12Ym% zJ2yMKvbh64ub+l!)EAKWy5$E9O7>907f6a}3 zFadBhpwL+03(z$DpVB8^NCId>B5FhfmfDp5q7Rd}N;NC};4)%1hVrG|Y9R3}BrtI6u)|q;G&g#@~ za8-B>1zh0XWsX1E*T<`*X)5_OR8tlofe-9V(gY&xY$rsVQebB%vFzCj9%08R8gid3 z1zB3Y4wquX>tsO4F-ww@{RGdFE_g?-sPY90Q%AI}=B(RZ`HWdzlch!0 zzj!}c#32`K+Pt$wqYMy9m6(c~evE2K7CLD}Bc;Z%85 zag$!Jef}lo=Ms4t+dr>{Tydep8y`zPs&X8(x$vi{{qy1F4?UI0=B%-natj}bQmn#K z-YG}7oIJHl+^)R5i_$7Ft2EFHxWR4ny*|EQD50V?+Gz*Lpv5geL4y&M%DapE=MV?gn9(=-6MSJiMT5%+Rt zOa+~97m|=&)i;OTsVjpuqfbuID^V_VnW+;l#k-UgJ}@q6tw6YP=iJOx2Ym>S#&CJL zy{<~EB}}`_8?uXmv3T2FnFx?If!Or-JgY`VtDry_EEah2_w`w*m_&$nu_g*oSZ>uU z9mP%Yxb5%{3ew7aS;pi9bsNk8! zxJ{?A+gPMbAjujSFMX(a{Ij)XGMS$F7DMyOax8hwyX`aUncW}qSLhBA8zmCgdjr&d z_ZF4jSC^v(wL<9(Hg4rv7NxUbZPvh;4^t}PSKwIU$Ma&ovgi?)9E>LV@@;8!950BS zSvNOepnBhL4W*kPzkbN6ra46`ocH(JKmj>RYs?ob&&%UAJoIl*bxKQ zQv^c;ix8v~0be8fD)~=izrTm%#{LQ|M&iu@mKJ7M7)3>n4fD&(sAjn|3i^B`vBIBYue)#duDk8@$=PLjo&yPIwge=hT|&xgWKbB(k4bsEVu$>%X$PWATFi!xy(sVC+?|r1Z?GIQ zB{@mVaxfxeXn8puEt#%f0R>ph$s2;5Y)a7a>NBO+^KN^KlOMQakL)zvh~)R|@9Z6l z+Ie;C9M}{jwfH~}1hQhExELGPE@=@{-faD3jScS4;FitdlXbFsZ5hK3mW{&>Oh%FE z>;m&vB;xeHmWGt*9m}Z$0Os*byw@(@_txta9AA69+aP~0=96VDX%{nVPWnSb*^W-i zyo;<1Di4Y?;h^L0|3u1)sedj=Plw2off9pkV7w>MTGt=?PENZ*J}prSZVgjtGZLn# zW{yzK=K+@*I9J4S>Kqg+f3rw1Aji28$Oh&nV`B2yO5XmTaO@#`;l*^aYOK6~_b9Oj z^(|W+Oq=|;=TD;GGn-Ss4MOK@nQ-QacR$|Bgmx|)IKAgqeG_$fV82M#DzgL$ukANk-`>Aq&S&zy@pl z1~D4^>*>SVf-MXbsCGNx{;f;oq1XHR}s%QsGK8~koOd!rvtR5y2QB=O@-AMHo zFat@|YiDsD)=(e-;$=hP@jGD8kl+&+_uv0hns;BC=MCTx0qG<_Bz)O*@*2^PXit>9 zNvBj3zheM3CS>o%5q}z4QH*KZbN((MBI5IK)DUnMZ4AVSJj3IE*G^^TLd5(Ass*X2 zM4e4+U8l2x>A4B}1N9XW5D@h&h<4s!)rISw%90Gy9F)23azc&P44Rtn|Lt~w?XOeo zpdoGnCjrlL9QmMrQbKLgI%I7+FfaNKAx)E}S?sUHpIz&C?OuUor84YN_eWU`V_Dx< z_J@8-Ypj>OJS~i;6!!J>Z5509{stPEdfDpvIaC;1*+^i_ifqF-+3#*|^@{*`W$j*? zfWT&+{&3RhYdSo>ABm<}WV{A@t?F!%297v2j`29-p<(r#{*y%R=yzW~Q}u#*pQ|V0 zha;Gn4#py^kjoDCymLO&;Vl2zuTiv5?2Fd#l9zhh#cNTrRFIC1-uBy^DkO>PT$x8~ zXcOPY0>*2toA|cfL_2^0ag2&rp``*}m0?4dP-D1F^mBt;5c#5#Pv%b_1OA5gL$M}( zi))aym1>QSq{P~p=s^NS;P<-1o{$w1QQio$PSeYNIz8DSTa&9N?C?;nDk}uRYMz4k zp_{*uzNF(njPgTOeu82X2;|<71fu?Q2MJl>_OpY~+AYplCwb2WE!Wjl`-{3xpAgyvP=9vX2~~1 zU}jH9|CALY>wBB+|?Ro4W0M zYj3FkXyAHGRbaxfSx`iMpEC}7n_`d{pXp1MX%|*8mcIF!bIL)tWK_Fc7pO^d0MQou z%2kaEE#RWmHDfO-Gs;o{yNXuOJo9_hUP8!1ygBq(|7dzi*3&EQMEO z!&>aS9)woF{Cn0Gko^Ja%l#R^4)NVbYX94fE|V%4Y&*pZ1|HM16BZa`P_h(qCIf4HK6qFiW_Fhx;32o4i15qfAp=PAx(*t23Wsrvk4@u>|3mPU)47bFuZ&;5^-t=GtlB?K zznnK{Dqb+032OEipu}~j_0xVxW>568AHw_e^YeR5HR_7?tu4{?yt^5+2_~iUyNQ73 zt)b-Ow-g2&H9rkjA-i5V7e_ zQ!GWq^Icn;pI1zpzYwjNJh*ZHOaAc-EK(VPW}@bBICW&q8>(IE8i!rY9OWtKyGQAv zt-O5|3log9o88Y3LF)$t$N;#dUO$P5_vLAEG;yBq-?Nru@4aWFhsI6@r5aI>p}(qe z>zub;CN%D9W3jK;YupDcLk4ZsJQSC!REiKR(f_J9H&y3i&q#5N^KGl_-}r12m}zP{ z;0(r7=^5)WP0J^*ONqv$vKDYJ3kYx)rx?*R&K+EdtU!3&U0jsxHXoj?byL_F$C4t? zv=bMYsQg~5uGPGBit6WlL|9pn3 z8a$sCr#6`!MZ?KUKl>=4v=q#fzXZk{-QFP{^0XH3>J>ZYv5g7L?=#*ewHGT3Gb@z({X5$MrNlf*W zbsYe>5ePW8^1m~F>IiracqDIFaX-kcwE~_(9k*~bQ9nx;ukCvMIEk~-rXIAL*!Q+d zM%c|u1T)`gi?vxu^+^rF{XxqG7p`Dx6`i3}8J@nT>mly0-&P6mEqDlc)Zr$OeV z57uVR0}v8~L=4(@UV~ykWrE(0Hx?tH8R{bA1mo+;nc}`l}#1c0aIDI3=F8jl&VRq@%?e0&?{G;cR zS|iECoZpOHeTK$PVCi-&%7K}4AmI(N_B==zY9DMXPEy4;l2Y;xJGW!EZB}6wbWGMV~UBqcLYW9Zs!qM1DS-GjX{`ySK_wV44i0YcR4@s&b;|$;TnXef?UGkGutt|d5?BCT$ z9NL#x{&WeJG`Taf3&V;-zw$OD)g)Br-EoV|!A;U-3Cr0AV|7Jj*qx|sVC}Sa#lWK6 z>CAE*5QP%P<@~vqBL|QeK+A6Hg@(Ag{m2P&>lzV!bDY!}Sya?zeJ=Zkb^^#98$f*d{#2eS#6BJ0i`6XAl$a0@HA3 zd=#0DTjBAP3IE~+m1sCgtMuK*dbpv^$jhSy!x@6*1lPg6|x4%=1&s+otVletqr_#{{Es{W? zZ^sicwh$YgnWh>Ey;T@LM$xg=@z|JR%E5t&G1=mUxfN%wqOxNmfuht0?k*uZq`+Na zYdRVqsfFEV*Gp_kBs24}HW zAj06ny8~B3mQ+%$b0KW3tI_Gdx1I~c*myBKE?IE8cmyy_F=no15YxLvDH>4C8+>+R z{tr}H~)?ymPdZB4kuxwThKDjE%|YLk|0`* zOyhX2W;~~Ur_zzw)Bdo}n>jGsSoy+ItsrDsIO4>Gu6I7n+#$bK+Afti5x}J+<)U3nh6tw-+ zL;SEF-smiRP*p|jj8^7vbKMZl2xVp=98;xE`hh{@YMILF8(u+t zE4bHfgYycE(}^(nHx(=WN#m1K{L{$I^TCGla$G+_u8%r{E8oA%dIgztW|d9*6lYp+ zEc{pAUV?<5pWqA*id8fBSXA4M`Ca0OyV++&hFnx}S6&*yO>v$b2gedfyt}UF;Jc}& zZ!jM2qfcpc619yr&2m@gu-Ro9B{GT2;^V36`xav!J`qZ8>I5Hh%Cncd-kDtJ#vVa2 z--t`Za{4o~W^F8Y9N*qZABWcOTXXxgOz(wCRFV&921~Ch6j;c~kg#hFh_evSUWpTN z`Tn#PkR49#08LuI0|p;JqH~R4oFRW;%WIPcMC4 zWqkz}=i}hScNP}-FE!l1oP~5LQVfMr)CH&uWC4*mZ&pT#X9OpWK2@nh;%n#-R2Kg< zI`{Vm)n$EHxX`B=kSl$2UwWmDRjQ)-dvPo1{K|cFn7=#$d(rH@-P6&Cj!NwB;mmO@ zivWU6(=-O{FWhrU>L1_k^~#bXqivQbDOX`?JMV0x7IIII;@lT}=HxJB_j`Ogu%b3L zna_0;XvvM0c(@%<&1?Vm?Hdw)5uwC2y#$ygJx|obUAJi4cKdWg=BT>5ukWqIDPVrm zfmT!+>bBp;QF||$aOVhdFI1$|e{VA@QM2tm33!Niys?Mz>)DOxh&^1g8DB)D7GItC zUECNo))=q|h`$s+q^G5i8++eRcG2&0<#1V-3*}Na(`%*7l9_fmq4wl>QYWd`E_~f{ zktb&);nj;H8&P2k6l@4EQnrEq4Kg3q%~p#~S39=jtmxH*S~6^2SdBx(o8n2|3-HY~ z)!lb$?%qtK?J|Oisf4JxTQA^+zc#P}&U%--;9pf7t}hS*6LLamiByKm-sb5IW$I*^ zHu2l7TuL*ojn>sbP(fAF=ngSF@Mu{`NzR>tr?MSFFwfV1T%bEl=QIS`M940s@Ylfw z%ZiGM>xZYYv9T_bPi3<}E)6jFy}$QPvw-Xhd7dN#uZsT>&7A3gI1X5dMf?Nw3iJhl zSH20imt}}7RvyTh>c8|BD^4jyUnYsHMq6howzRT}F1Wockr3nOzwVKE?9ofh6>^hT zR%)S(X|owP?qAoNTxXW<^bqooi9iqtOdDL#LBz8S`EhPV<^L&Z@0&=QD$@vG|6tPM z@he|a)jvySu$|G~t(|*qCTcx8I)-)Rz)?_Rry6|*c9G6ma5q~DE3#D>zYAp6+{WhY z9%xIs`P@G7`^I5|&^cba(n-^4fO?1I81U$l-lpU9kpRp-sCL=XQ8Qx-!KxN3k(EWJ zMP|sP?^=ApKfb)XQ4?-F18&uhTQ>>szmv?rkv2<4{?GNUQzPp&32`5aXp zL|*N*HJyGF4|@VDSGUE*2TNxF2?k|-x%Yq8)yGu{gtJa6TeXGz6HlNm==s7k}M`0;5e7YA=o`8~FbRhBvQN=z-Km`QB+ zGl$?v4MUvS7P|SSl&Fx9dg*64Tqm8Fcz0(fgr-Vfi6v%A>Ggv@2m~(O9Eb-Fd#CF= zRr5hb3l5cVE3By+2(6uVh#cIbgz|)G*kpBAxRvfcfI1T}INy=j*)(|4xJIeX>nBzZ zMip{ItSqT~II-Yjif}j?%NC`_s{h7v*s;6EWPI5+FFr4xIrC6*9m!9d zse@OkJUW#eZ8P&o;w~W+(?LYre zXG)xXc=Mnp@pSqB(*o6A=|0=n>A0t-zKe(+aNB8)sbBbOK-dCdXlZTm^8I9p7>#b!*ilklH zAt^lPal_~ruIfz0xz}bB0BZ_y^Yo*bA-)II^WjHQgw0c(wW*C3o^n{K@|_*7_+_%h zGa#D`^6ccvKT;5FUu9^c%@uJxzV+xVGy!(^n^1zDSx;Cuu*gSlTT2d@QvJ zFElL_Gliy3V-;#-#mI*|yWw9txyceG4Zd|A&qP&;;^9Oe0*52_veTh`B$%}+_tL$*n;iWr#adGXJJY<%v&gV@OaUoU&xOY$h{vmWnfN9>~0RZ>Ab zzf)ACXktwPSo&tk2_?2S}QMQ^|y9(+S+CIz2Z%NL-V{e$TCpYr~th(ej=LWxnG8Gpcr^ zju)Q*_W_moigFy?cRS-d=^c;Tz&=8`0L0lg-(>o4EsiF#; zZ<^FQ-bOU%IB{$14AUGZDM%t(2THu)+*u)l5=XXXut|B9X9zJ+pZwplppBI>Va`B6$_h2fH%W41n;udnVc?ZQ%9fHgmt0rLO(Xi?yQHLG0&pGrpcEokac_9;@pDrq zv^C>*yxx!4)L6E;3NFsdJ|$Z>N(>3h{-moO?vLRUqK|iBZt-F2rK|Ro;$CWY-t8i~ zQ7wk=DPo#)3ltT4@NKucDO2CNT9)*K4NE^8z!*vR`jx8-8`PD_U4=B+Col&lk|B~H zvsfNXcWK+e{7nS#fK`piZ@-e6ZwbgpL+N-^WQgW)5{vQ_WYAK`?Vm2aKfPg}`ze+M z#Q2051$j5Z1ghL}FuJ=k_e`O>21a|h-)C(zNz7v6-?JTiUI(JanP3zV_Vx;(|3)V< zGv|Igy+rIs0W_R4E+4F4srWL&R#bVnQ z!UX(D>kz-`mIN1$LnMGqhFc9_P*72UFL^gpc7 zk6-gPe~!}}fX~4vI4;RHE@jJHU+Ck-9#1tl&0wjiV+&1tcXu+mt3OsCs}d&?S6fJT zRVt|b+Lfy=|8aB{4o&@U8y=k!0@7c)y9A`W1O#c2kY+T}-65S)qq`(Vr@-hCB&2)N z-SwW|yFXz&JLf!~=f1D&akb1**!@=QR)-C$K_PK5aLqn~f_spLQIr448)6;KiHDa% ziflfwT{%plRT)ge4Qr(}g%!^9w(`I(NnM+InP_=V9CDXTjN55{;f>JZA{G7MnSV#- zQT>V?v`b-zhRXzIM<8)a8syzglnnB_>Sh_eK8{Uo$mO`5FwRA|JPTi%{np=;{UQMUz|&6sSe@}xQufm{ z77ZqP{xD3QNq(KMS0%3btdkeuH~gFb5BB3TUdM;I%mbnB(9kOiM6(*oIC+3@Q88_R z6_i5`l0-$8O~)fO7l~7m4HhhB#BETqV#)&3@RVz~qTYtve~g(vq1oWE{e1Qdnd_N=Z&PkB?CO_N073SlqwT2(TKKn-BiyOC`t%kKf-97RxksI<<$;QsHJ67 zr}}Tbg(-)|-+d=&LHim^VkPA)<}-!lvCjE4Lw)XI&HEj6zA+Odcdh)OAO# zkX`*VHD3&xemZ&4M>Ai;?26H}ne6QBes&Gm5%-X%vIYztqdH}nFFxX99 z`7l=!s&K>N0P4Gk(ZOQ@8YzsM<{#IbOkjQg^&84QKis@C|3FL2-SwyJz{~#yb+nc5 zyI;q8p2h&VtoQ%qYn<2os;@8Wua8Q}fQ;sGCHi6z_tt;kqhtN$vzTY=X@&0ve0yf? zn~{l8s<`5aR(jl40JVMz#V#XSgEX!Fc2=n@X#6cmUtULc_vZDc=XL4zoGaimJvw^% zw0j#Z;3#s)`VbnuRO6X@ztm;_A2| z%cS#A2bF}UjkNt8iEcRAW_mfaF8S<+;01z>c;ovaOD5Sq`#br5zarW8vyB>PEFyrG z9Q#2(Q{>gI2b4by-~Vo#>-=IKRH}nnvniML=djSA;S2cC{rCP%2@#aYcj)lN>&wk= z_A3Ex8MXq0P+;K(QO1oIG!Fc!kK@kR=lZogi{Pqp-SbIT;%uO#|Yb(z7J!>i@7II?v-5s zbtkC703FRSf;? zFp`L;p;j6}@~4I8H?Q${&oI+y z(ZUalNqb=XUXyA-_x+&2+pD&V_bE%y@~Z}{w&z7V5i0vX-<&6PsI)6&m*b`Y1Og> zLYWy{yDs9)8TB2&FGI%Fb8CFIn>MDq<@N1sTI%PYeS0b)ewS2L?fJzaiSxm~`_JH_ zwZW1@DD{J(#G^#O!IZ>h-s^^c;LT8Ahy|69+cWgG)AjzSAx^pHM&wlrU7u6;#Q*Qu z%ZTsm-wH!Dj}`?d?@L49t|Mrj|KRl@meN|sVSENBSIq+W8US#<>2i3!qRTk-8no~5 zBm9+SMgvwA8I2^d`T9|rC2aTtJBdb7`yVqq{ub=v-8NptnwPJUZAy8o0q3gcLQ+ED z37Ft|bmfnQK=QI-*GOAGy!KlBwfC=a>ALIIJCi#XE{;e6^CM#M*MB-a%y9y@$9X68 z9=3_RFi{*x!gT{zMY-2YeZ~DWA31q;k-Qeh7TP->N;w#2Q_QChM{kXtV~>tG`@>&| zXeuy+llR~>Wy|$$f52-61VLS08;tAtU_jiJa>Co+-{04_WBGV;e4Ikm%UOux1I?FY z`p~`&00otqn|m#K`lsSEz$ZD0L_)*4^68>is+>DmT>No49=i=tPddb_+1OnKM{Q2u zfy(FX9DM^{p6=-*~iiAeC~@x3WPb!YqkI z5YOk)-I6hDSY_WR%m=bpq#-II;C_A~4Iz9iD?ON-@oE$n6v^J*zj3y4Rl%Mj_LbCU4lHFsc{yI!;xts z7+ieS+)<=iu@yOIwlcKn(fklSV8!t?C8C4S)YX=Y-BHZD?`?qryaAEi{vgCD`kLd$h$qa;6xV^lEh9S|e)Y_Jh9xl^ z!aVFyI)dIOL~O)q($&!2%*!XzbJ=$if+kpq?mMBnD0S*6y0uzM&Le9~c%az$Z7OMR zcXA_%%jBSJ{L-a+bFNd-c8==;YP`aX;%%U}hre$(d^<-zk*ph}>?#ukUPhv6oxHl% zvi%7mOpk?DXY4F}t+gk${aP3?{Mi!Z5jz$XM6_x$$)9>KBZF2 zUd!R|t%Pa#t*deE{4@1|W6k;x^q1oV<<(oIeCX(+5t1`%Zx8{sfy{}abeQxRkdt1U z%@Ex$kTb`?mktYZVJRQ*%1oNFXa21)#g$){w$+Qyk>oy79yTeHg6CEe!(TA$~fT$DkEO;BMZl@9S*z@`>Nk zi$p7&s4h;SpDm* z_x_)&J7Njn*I>FxL{hw&qo=Fu!MO90znhwn&+f0&&Bvxt2xmM31m znYiPSn?@HCfW49x;Pfu{dx5B@+!nPd?G^WJ9ik{QW_Pu@gKj~cw<6!3@t8o9y)x4| ziR5SDx-8lhWl|tTuGC#+W1Ed=sBkbeEayJp(+RfVtso30V-oqbIF|IC<<*bK(R_Gh z@;65kbWTNl%_-VK1{DhYYNGN!kWBoFeH^Mo%BZr8RzpDG*kLuYN?iVzvEPbTNbwc; zrcrd;vDGwtGwVqJ0OXf@@|Teo;_~_h!9_#5R83&Af*KqHW)DtWTu=_v06|WVX6B%mQtlz5#BN2YKx)L%CA!eY#id@Ss_Q_z?t|~mQ8*T{=v1gv(^Y3Z z3VagUkCjO{{E5~8M0*t)Lq>mI?t3)w`vk@vW4Bt>JA`f!!+jQM1O~ z?2Z1kflFy4J3i!-x8G(3+A#qxcanBh8aqp}MPl*D&pgt`GT9ZLZ@Yd9KW9&Gzk~?r zeVVtM$+_gl+~S{T{D>|U7V9>3DWu@g1YP>8iU7hRZ8RS|M32tlS@?h;*%TH_Un>VXp484bl2U{xM``~Kk*$!e`s~2UmaqRdpZojr1xYw+ zoNg2b#~dX-2pBI|d16pY78g##^d!(h7@40jPdwC}ha~iJI(NT8O0%K@sustlYK?993hfQ%1tUpl&epIx(eG%gMsaBeM7 z#ZU9k`27oA*n9w4Uv`pYThbyG6(lKOK|2Pev5XKi=)SHpa~=c(B4Z;U-8`LCkNbUwPr#{^$LCOu64B0=sAE=hfnI#uTz zCHZOHC5p(Z`Pud9%iL*41!f|`yZN<+93OB09I>)a7m%UVMC1Z7CU|jT{1H!*;68T! zs>_fz?>zD$cL;5HN*9jTYdEyGWSkE{!fWqQwwU@AX=F?c;)aFcLEzzLUUXi2S(PB_ zFlX#kv3`Cq2dz+C1Nbd>Joaw`Vt&@B-seu;@8k`!7?R&G)rzppZGsL2wyEjE0V|z*;8TX`snFnQR=N*ZrC;8N3zC$3|Z?5hxaDO1@q}kg#tifU^`;vf)gxov* z))m4~RF>D7&!Gqt!`G>rJGpS5$ud(y%*$M=(~dPAO=E3j$7Ic9NhjtsHWck?2CQqg zKb4VOxlCh21?EXqK=Vtqi45PB4W)U}EkNj`LG|=alUzAsjiELe=Pvv9z()GfXb$pBUB&h{RBLO7bKqd)djOB zvKfP)86tck3jcZUlm$MN^)#~oTJ4TlU0Ly~Pw@ZOSJ!=_T82g7v10YGV~lXCk;oB81u`IAm6H} zvhF_nTgT2(3#vC)i0?Y8rTZMow5LXKME@KTQ+f5P93qK~jQGu9z$J+pH@TC!h4o)O z`&7V-)5}WzzIo3xTaSK!BI$VeghPaU@Z*b*DBnXr)$`q-Ba8HdZ3VBYQPg@IvDsSr z!)JQBX;gIz%*W_a=rGC;{%bLv*a2DLl_P5?_q6wkZ#DjwEZ>Jlo@(prX}J>Z^&=d{ zvclbxrwhBM%etK0+UQS-SJiLmW`MwfvVP~qe0_p=_s*jpy?!h=-=^hqNFrih?hh`@ zOwNc8HtCG8@OpMCR?Ldu)uQd41#z|lD&htSnZJ%qPka{^FDsZyCE#%egzRoR*=-hl#_D@lIN~W?>6YU?9NvF1v{1ix-KK;PWaaq<&LQ{%aN>lgG>@|1>G94#4~)ktJA4)Y0 zu1ZGWRpfe_)&ACXz`umkydRy{ch0FmoNaab@(}tkb1_=elJjt$(UtAH_O~og__YFe zDs`S%{=O(dY!$#X0uhIvZ}-v~5$C?nqIttL-?w+4~uex~%VMg`Y-kI9nOOv4|m=ZMNSR z$={^TC>a~+8`Y#L=X~c^!lnEHp>$#Zd}Pf%gec)kM1<-ltrTVLgg^J?=}AmTugVZN z3mg_k8P*-`Z{BZN=oOnu(kRR*GxHfcs3lCG|B2%rOOe*Y4$rL{-Hj@vD`MCWAyr$V z#z#hgh`YDyV5Bl$3G-sv;0fas%4t;1t=Qwq;nM=539v((5n~|`+I4K{sISK#s!wgu zsR}m}qQL1`<%F-)7XaA~VK@*U(PC}uwgYz1ig*ac(C-q7BF-bHtl3T>r?)F#>YSU%t4X9?lm%f-<+*F+;!QCrLH_R^D!% z4u?OATSHDWSSd)@zBYtp7(NQTWuP1D6zo1Yk$4&hDt)&S=g|r4&kY@0^emX#Rdb-; z%+GU&*UBYZI3pv>lvvqO$|cFm5u%=jzK~#3j+B7yI0;|3#R&8+YC}J(yA6d;5rS>F z=I>QT%ZxvNxM$5~nu@$USN(j9!mNb*$wxe&nH0?@6f6=PNLTyG^32-kE9eM{BWp@v*51#{C zG^;?1>iZhkAUTFI(x%^K&cP7&po$r$PeCWl-t@7mOE5fDtV z*Xn{x%-zh*q4|7AHPzP#CCcG4fj?50<7&KC4Im_MdPAqDK9*w72Dy|r6qgHz80ia+ z9bLtACjbfml&)OzdL8&|!j=|u*#Gu-nfP@@csNQ~*W%imRV)yq zCBS95=R;)>0es(k!wbn9|%- zy>>!aBH-!njl#I%?r)VfinWKOZ2xD<-t_pFEu>;z$p8XmY=l^;sg8SOOO6MrfE%{^ zL9{$#Q947Pd)$}@AzSwpb86|$K9hLt7*h@}1mB@`u)nT;9rV3mOn1@p=b+UpX6$~Q zs{O}+GrJ+VNi`o;Ig;riokqAh$MCp%>R9GYlnWvMyB|*Hp4@R08 z#Of-{%a-PmE)W9o&3kqFJf$x*Gdbl}n3M~QVJ)Pmm^mh6XD<9zEFBuk^Zq8Rc9Hqa zWO6O$wC~`6-TaPZu)pRzF{e=$L|lu|xahr90rB13zVNaQ4riWzr_bi?`c407`>nQ9 zHF8SeT}O{TCHZBc9Ybp1+2QLlrDxB6uEaCeA=Z>p;9m5lHN@{>gdx}JacNn>QN;Ob z@?O*OgfFle+Uk7Y3v=(!2B=Szj^P@+40T?I3gUN3Xgxmu_I_Z?5r`0}-ty^96#-uy zI79yO(m~?x17>%9{bp?>aPYpA4Ww<_kDHe%l!glg1X0eC>HqfU7$tIB#}d3Dt-^Al zkVGT|$pne_$_0&qpr;fOk-dPxr&uwCeGFI@<&emL0e?;~zrG~QZ{2!04H22XQ1fq! zsB-(77WgANy?ntCBF=ktNuniQMq~oH;gB`v1ar$?Y;DdTrjz}a3!jqQXi6v;^dUsa z_fQ{q-_~3!Ico>A!hkR|{6qyEYMTvgyhJxEY>>+&Wy+k=)(Ucmb<3V&mxmx|Dp)%b zhq7VbxXpD?%wp=T42$~^r6)QK0J1`05_hZSTE7*BL*PVmo7lZ6^cW$%m!fczu#WzH z86fpO!!PD{cec2=2!tTCTYxWA{MPkE=>CmTZ;sohl1gz6iX%}mJ{PIFGgz?B$c%l| z_k3pQtF>Fv7p~JhGL@OHA`{VOAOwpFmRJo^L_D9RwR>+L#y9 zM8+5%d5bR&+ebW2^AM((!fE9;aKcf%zU9ArQ}j2-^hI>&oW*Axw&1I^T}+ULz_GAH zie)T;!O!6!a`2a2i`+8A<;K6reLvrNKT8Gr6?*K=3>Klms!FB-fdPe}U70R!E7RVx z{xt?^K9meUE6%P+KM&#{as3DCmXU77xNJ&z!d;sPN}Wfi7uIvl-&gAyNNNNjU<~eD zHCc#`HC#`ec$9_e8MQY|+od)s>FNsJoJt)0h)#1Y5qqCbx{byj>y>p2eZR1f&cs-H zF;`R5ch+50rWXJGK2!l`yonsRdX2NP{M?|LtiFi)L6YsC-fT1{5$rL{FMjxWI+l>v z<#nD#_$k{a%Isa#!Nox-RoLw3&(OEtoj)>bDa84UF4$3Nv*Wjd;o*@ur&RIpeft9- z%bFt@((MTtq}$^u|3Y~!__qM4a{&{*D{2&W(Eob3G~uSq4tVIMQUc2H&|@U9qO7-0 z{`rU(g_{ExE5@f=f*YBu74b=%DBIO8&o?wMFy^0k^r7Q6a4W{wn!c{)3-+b3Ei zZdsc*``E%e@=|@(JjG38h$n;LjEtlzjkLPnL~OeTe5#t(pJbE?6h;R0@ILDHXL@j8 zhL&-0-L@=jYs5#v3{WLUOD(D`+j!G|)CZ;Wp^lq>T%Ib|_ZW#K zmr#kOh!b%lOYBOR8|)gtI8D4~Eh*RHt;8!d;?(6d_Gw}!!~-X&?^TivVpxY@?PKkG zSAVj72Zz}N1zq+!mtH18b%;i@LR_q(4Qn)hPVU)}mGNHn+ISL?F@2GfHs8*%sD!vXJXp=TX4qTIraa)KBEj$JA_cziPM47>t1)ggx2|)} z-1&MYZL0J29O~u#Fn9aXtNwDQ1@>^Wd{&pZDTq6)x@XSJ%Y1^I`u49xw^f~|qa4n) z=@Q^=47`k}V8P##S6PICWPZNONBxBJG`>xl_Oh}5zs!cyb3)G(RS6d_ht7gS)yERv z^^d$Lv7az;`==e_V=exTRBKr#HY$$Ryb)N0?d3SSWmRW1=xMX|{ZMW(=aV2H#Igm zyc>i(;Hj+A@&*NY19XB(3m*g(bJ5vKBiUeJfl#PH*rp#pA}as1afz$vY2r(V_cr%c z83!Qv7iGc#$&~kj|byGmX2T9GDb98ZARv=@mXBUYjs^qr6OJ<6x!kAkAs;G{L8wj9aiG77f zx@-x<%@*G<*$49f?sk|Xxj(8_V_6KK_6KXczfj4yuYSvk?7E-9_Tl>wD}l?(g6+ru zusWFuX#}H^k@)i6nL7=%l#}8#wJ{4D2v_~Ia6+WZw3z$w5!H#fN1JrW^(*amb;bz3 z$E3mGv=;ZHC9MRb?CMy{S=G>+1QYKqOcVVY0dU&L$f(!dc)$9Z2iyVLAYn8zBKWmI zYvUbWv%+AxjX^MW08J^_xF@8B-=+R$sqb z`INdmEoyKc&nAcmT#vf88MQrHa`}!NmrdsQ`)rQxrlsxDtK!(Rzg+j+NOT^ku3wHM z1Y9TtZYcy_uA&9(3^{G)H8-?gbDg~YTGS)w&=2j!G@reMzxyBmS!CJH{OiH| zdBsRRVfRb7?(T<|iS-4uSkfZcA+_-sb!=6% z%IZ*E>kJ!d@aPcl=}9&;&dt61W8L$CXRh+S%Ir2l`*8JK!RZ_u5e9v4tWN|eSgIoI zbB*(t!-97a2clLh&@!L;bYwJe9H66}GLHpx+6BgSEe0Ixw_lEU;C}Y@ z*6UGb+Y z>A>iqoI#X~@i1w{VAchSzKl-l6bpTpGx6K-sqPow^_g;Y+Y({8EGR$6jJgrRppuW# ziq&#@?c<0;EZzFzUZdl7-lcZ3XT<+S1=zHmroM_fp7_OF5z+Y@l9}hf&8GHxljpyGkj55*RdWTTxU1%3wij=o zD=Ju8IFIg^5PEI+r3V0CxvPf>e+x#Yz1q58sNB0}MNeH5MO5i@If1{B#u4|2p>Ql64&)?!B7Eum$jDs$3 zJ2W8gc%_WnKmj( z`^t=U-?QFs<&rJ%7{%_C_ z7?a6!jk!*4e9Z6$lq#Xovw(%g-PfO5j4b|w-nND8!^Hf8pt96rrR)UrO42APWS&=> zP+tQeAigQ~hU~@&vCS1XM$?;TYKtqx&ohUMFkfHlHa=22fN2V!;656X8-VdB zgn8AGcQN5Jcxe`!QK*7F`P4&%~xxNNB zA7Kug>La6nNu>%H!?x;MA7N}-$a#!}PWr-hp#Y!d#}N~CO@^Ntz}}xe4kTll@<(lc zFp=M2D^_1cMCwB;(hY4PG+sIIQfDYGJdcfi70^@lEFW{Svm14Koo_}`dEf<53_;)m zWN&n<{{v>$*?m1Q;KVbYPXasUd~lD63Zee-;|K8Ap1OQm0#H_CV`e0bN?SJylbl}s zWcW#qluJlwqq_|%Z(YfmX~NuWyU(ZfOYTLLY>{I>lckI@0~K`aUL;+T?x63C$vXLv zKwmlfgY7~wPlE9EwMcNc`%J%^F+|E&CqVE`P;WVLXjR}C68?ATuHzaffKrxw?BE^x zE!ho1KXNxPFa~hurvQ_N8KE#V?!C|JxR)n4YpT2~sA(RcZ&YeUKA*HCvz^yq%OP9H zOqmbxqu01qu_LLS9F9ei$V7*DYoqcFG0pZ}dq<=|&hQNibY;|LO63Zo2{5C}hw~dC zc-4yW$htQVb1v%>St%4U(1&*3uF{V%w|?#;_WPV3#cxq_2$YW7aL z$cb@lr_b}!XpMPf^uJK5r;YzDe8a=Tf$BNbpk;Z^z-@9WN7xOX>lv{bpZ>261c>f@ zA4GMlZ+yB$r^H~*AY%=}Q>A2=AY@bIX{1F|FS=gV-X3I75Ebg(MvMQm-uGSCina2A zqJWm!Q;!a{GfB=W?9AnA1C^>OHj6~J_~QOyg{m?`bLGSEiDNA`8GF%6Z5dnyOq7*N z!iD9ozMG$TvG64u$(mFFRCW{y@m-E-Up3T;g*=UBquzPOScY&>Al&K1mnjo|2=a5^^>bqG*rypNbgrKU#J4rYKg_@4rr z?uG6f=IdIMU1FP|ub)zqxLVJ-4xGlsPoczjhb|smF zGP%2}YtBF5(eK-!wh&ttbm}l}SxFtXv;u9Ecy<0FMaKPMLY~Ckk054q{v`JuqM+OW zA!1s!uPhc2_^=)cDsujJ+9|9wqS!We8A)UoF=~E;)4B0h0tC}&kSG3o+6L2H-(bV~ z8Ym|N*t&~WK3%II8|v)d*wMPy)6{xVs=F%H(LvQ>u%?$X?dY+364SB`afq%K=w?cw zTz`d|cy}&Ov0By&v~iojymKn1Gc=vMI;@1n7AG4)ctKwOexrS_j_RbwEE1iFC~~O5 zCN9)*`sN#Y37_)6Dx$K)KJ^=^F(cV$*EcZusm0D|OqYt5K-uQCxiomF@_CkkkLW{J zo$$g{*H5j=_ZE2XWrLzZk}PJJ$7WJ@l~Rdjy|dT?Y#O|~jlY~;&l<_0_9oIct{xNH z!vER#o4Y_M7?c9t-Rs{%5q1tnF96ybfc(cw^DeM(wQ}%YzAV8DK__u*Wlq5nWMk)+ zq?N@Mog!f1OvKW~NlKl$?COQ%Eob;yqb{El2cBFU;T&ZXay@vDqo4;Nu{N}( z2)Ma{PP4nkzNJH__|PTsi7fJPdqd%Vd%if2YVHah2y!PkVo71f5Tz)-f(a3jz_r`#dI6IvKMBIe&r2>LV!n4nVkLM7M;wI{B#LT zgmI7}?KcS3j44pcxwMIPLo&SyrG`OfObDLC&La!lDe>X+dhs?;fzh2}#1T4m=3O?f9FZTI(n^gS?r2q$9CZvHE{v__NJRZ@5UV~QTtA*(|xJ4UL=Nn-k5 zxlptGjjM%ilA(F)4)*Wam78X{y33r#Q0&A$lZ%VHo1ry?m8+X<`!;kA5>NZ6$z76R zL`1SG5Wes-@XTf3Mf@%u3g6YoRD@9NDQ(@GL6>Y2)RkesFD><&^;hi2DTGo%8Woy` z`X-7IEcnR5>vqjapVLc<%&0KUgOi0Oqo6q|@v<%P^1S}~ z{QoMqo=}qIkrXC`4S?&=?sHvf&gWkSS*a)uIBW?3`}+fYtJZCtMF&p5Sq+W^N^vj0 zqCo#@%5dH@Q3zaz99vY$g53b5lpfTt(;}n!r_2s$3%>oh?zWIiz?U}ha&6$AVNmb^(1F==3dw4zSk`i=OcVZ0!LNqx`BwKbVBDf0?(MJ0FwH%?%I?8=~LwC^KPBr z{bmMbu9&cxb)CZ#Ro?w~!IwMS?x!zKm=^g}GE-bwTgsNFUhrk^&)0h_k{Uz!*-~snkb&D@wZr5PKul<3yd2Zn57S*Kv>RuN@E)ktC2bD}yLp2Rl$c3vx z{6ptfvOgL=)X696w=%@2{dXfM=$`JuE17oh*L;Da<< z{oq->wg0YRo}Qq@-cop5t`JIVqvM5vJ@quc=Vo5Qn_@O#C18JZ$zNv2Ol3%l66^40 z+$RIQbt<~pA)(Qus=L9q8TEdx&5P5jSs{G6|K?`8LrkK*%V1u6bJz9$-|wQv#zuf; z0HoBP0|L28gsgHJ6+*uVupaL&9+%3T63sfxtgJS|8khCnDpJ#aI8`8&T-y8^*2`|d zFWH+IM9s)A8&nKpM?_?iq{YUgi)egD-@u`w3z|g4Xh4*U7?7HvK{QJM^&0e&{6M7} z0qmdNn4K!^2*p9o_zW8810dnvwW|hQqK(?@cTC0BKt^2hz?1Bj`U& zWaRASY$UIA`*_I?+(7Y=1lsInIMSKNTHl*cUC|N6{T%+E)YDeXdK*flDcam$hZE17 zy^qpm%9_wW@*XgT)@%-6%E~>|aBtYWziux7gUFd8)x#5rHM!b+b49%MyHxY<)1M<# zS=%MzoTlAg1orJ56{+5G`oF1v7V7HeFItU8CrtVERxq>7Rje}#=S8y(73(x^TFYk`#SH8T*Uu}&Gr`?B>kH(Lzk~xlox9ZR- z(dV7@hrfA-`}Te>Y=Oq$CTpC8*JqQvz`eF-6LGI+qB1*)rgfFbq4&)R4%M8xzlOOK zE+cUw|8A&G$OYb1Fiqw@Kw4JMhXOA|%G7f2Mwc|}_=EzEdTYuOdX6BzRDMSRlSTb# zOs`w!0SoIt$ zrMOT=m7j~P`})dJ8hFgWa@WJBQTN=XQYp_&^?nQ&qAl}p4vQs<2o9`ta$ zw;pa8(E0w&GazEAK?q$wuBfQ+>FPe5#fe|afw$rPx;CzXp6G&{|7K1WEJZiv$jB7^ zc6M>(JP+a7^EmxkH6B$s+*S|h0<~Gw_V@RJF>V3D<=G_C<4E|j72B#MVJZBaJ(&T9 z4;pC?3!H@8)^2VrcZYhJWi}=_E7I6JjSW_wof#Z52~Hup0{wDNHDIlACh}93`WJ`PSUWIPwt>Mt9?IY$4(cOHat%vBaZh zIEos(86n9# zaz#2UatJJl#MWUR9W7s~bjNmGlj&Q{jf14{(%Ihp1eWS-X$_i~QL(=rzYETjAvNVa z{VD64t}?kFt;o#epXyjW2}VM@V5f7ac@O(x++)I$Ay=VA$Xbu0FiE;@_?-hG#JySt zL<<&N5KPZV7hGt8BG4;t5rV?0-o3APNsddNCg=(fya*e)uqRw7rXs2XR9Yh<(DOd8-IG~uqsBJG>+x@M< z|1J20JWo~tLJhD?+S_9^A7{wcVNC=2>dGZEHvAW&z+CZobL{pNOE+JKm54ZE!G<5_ zKT#nG3AU1isJ!PRYmr>FDuB(Ub5e4fHSF8C4gvH(=xCvRH#ava0ORoJ5cUtQBt>JI z^X>c^yAxjjqkTWLM;y-teUpy1Mv-U=YoqUbUVgVr`Bukr*j+sMbmiy#LwAo;KrJ)o z3&qjI?>;AC_k$58$iHtNYHuw$yrsuuTR1stKj8ld(gPQ|GQ=s|3=UVDn9^f-<gt0oGFND&V=M$sg33LdNCuL^7^0wdwJA~i>kZK78DMYzY7XRK^4WAht6 zE*br;2CkFyK?_fpK{sd;C}uD_^W;_e5jMS-?8UsiIF&Vb6a@fGFKN$$e@d@D3N>U8+hgfb4@ba|v2 z0WoN)_WRx|(#D5gv>pPI{}ACJQxocS?Cdy^`xi3}SYh%5{9}kFt=>Sq-ND~I4ue}> z@E}c7s}ZH7z+lmMYHNUXYvcNx#6=c`5~%|w1tF>HRNe4eewk`PGzKi3%e_EeU+o>z zCIN_=`d2xXV0L=q==Fms_ZAENs)l9O5Bk(}>_*995@&kUx8chx9o%hVg=cZ%VvcF! z4fept&aQHH|LV~n@S_5Q#T)uzDe7e>E(@2Gu>zhd6C?DwD2EM*z zW@ZB6gCSu?S{mS>-}X8Tt9F$V_5+yO0p-E}D(5S0Za@v4pH^N2S#WxA#b9HygYYdW zU705uglN!L2am_LA?Q0upLf4lhiQZHY_oCgQK7FEvFic|bQ&J?}=feUtIdH*2L1$sUN&${H0Wpvm;gz_GV%K+$VO=0? z5jk0oQY>tI|L^uOhlkUGg>XDxRQ(3+{MQU>MnU*hbXi_h;em%!Q((aQW)a$9+J~L~ zjFp=iO$R@7x6OT~T5BZ#yFXskqrqEIA?Cv@rvEVZMyNqBLqH zlN0J+sIEGS`t0w+0R4Qw(3;Vz9!I!+J0+m0PO31jQ^}vq@jZCjRY~@?a0~PEaiwBe z1Nv&?#X|@|`m(ZC_#7D0lk^}SpeT~yjg8FowpR$wEXmzR3YP{U4)vN^cyFQw@EpX+ zv+Ppzl`@VgC}|MNDlf0x{vvRAUDSgRWnC)5@5NfypOIes*FUtLe(G7?gh(td-Es9? zpZ1)=skpppnEHfo^*}Zpc34^Li2~_SQTPP{=*W``yKSG}uAaTBzFw{VCnyGbnm2w% zNxu^7O?LbTe`bJTiJqZWzP2c*V21Sm?LIa0s>Rsa3lV!7_wI9Ya9~i{TB-w~_tv1m zrb(pfC!^4XWxm$B^a*)h#?v&^p4NYdks`x>P&Zga^ZZPYcy2WqRW8tImo)7r=9a}0 zdEOFZYZmiB?VW7-!H0@XlsFSZBQyEKOxB{w1sjnQFL;)-QN|gj$ZBcoSz8Y>pBNoW zpp*wEp2s;djR;uBN{&yB1L2yVWHAv#^k{wPy=ouTCSuh&?YT%AzIvYaCDNQUb&|qO z+0C(?%Ot|1B%Z@Q9Jk4Z$KK!%TJbmNUH^9VremPo+OR*}z+#`H;oGZs~8^ImRmM{pX=7-I1B z)8WV-U^h2^I-;l&k_yqZ9(bJ1y|V_m5utXzv7lM$3}wxV00wkXiKjC(iPt2F7ro5Bj_y-|mb@R$ z{8~Cl6+%4oZ)FN<-Zk*8T?OtF2OO+FM*I=tk5$?Smj=T70A7CeFaPH4jGcP5G_%Tg2~>&T{3L}tt}2IV(9ZcYFFXIR zit`|Bu6x&=&jo*NY?dAHb-c7UsChIL3CuNG^8TwB&h+WxW7gRcfY=%tQc7^Y3|RkBD?%ub$@oF=r4yV!qrM z60&53NI5B@bF?0kJ#}`24LVZOEiEP52bCMqUqDz&E6B4q!e$9shMv|CQ2+}jLmLun zigJ&d`FUB5J5GN< zl0*|Bl~YEQs(t2~RYSY0|H;nPQ#W1c;GD6hsz_FxsEX+7$B8J?I1o1lq2}Q)Di@;3 zV=M=r=gnIa-@S^o`h$Y!&#Hl|6APKD-I8@%nhrtfHviZ2eHiA~&eEB>}`pLCd< zCrR8FwLKHWc^r1@c5M;|p1)qtF+ZmT@(1L)*j}w$p%xj$qS5 zF=%`HXjoRB@Htb@>u}flXR&WsMh1o!0a@|+yMnR5VR|jZM7(Fu4ZpQWiehODHAIZJ z4P2-T*;OO@14_u=Q9_#_%V0xe-FYGM@(75oPBxkrKT0#})A^LrFZ7l}M*q9?lKRMqLTb(cmmWPo_t3%= zY;GaQMeVlcSYBK_a7U9}QRU6KWR59L)lcUDM1~w3!op5fb3j>XQu%kA$p^B(0A&Pt zUG57-Q-_G|f27W}r;RCOj>$2S`9GS@f-B0lYr_Ll3JL>5r+{>KcQ+_4p>%^FDJ|VC z-ObP?Fm!i!cO%{K-Osz$#}6204a~i+Ywzss^0>=rKqrTH*hE2LLJV(* z&-w%+HwE|e2}Vyiy(CkI53;M#4GCy-8Z&lk*g+6gn|XyetC*FJ19paRE0}Ji0=PPx zHbYSnDmAp@g9A|`jo$_M^z(j^Pf)V^O{7)cP6sML%N}IT;P>d0*B9+p!N`(?4>S*E zAV3NS^L12<{-E>LoQ#sn1x9ll_Vd9J=d5ozRDd4 zy^7JwQ|8f3cJB+6CEl(E*WtinsOTDoFLYX$+4VSBqEY7NeW9Z_Lb+#=Wi<4LJoXQW z)qO2Tsy_Dk)ZrQE$MA;karMIz-k&N7DUUSNQQFuN93AmAd0Ip;ol$H{O7`l$I6Qxrc{Tj{bw@Oc;W`R~E zac5Ud}e*fN?OkGh?!H5;5t?;=;Gk6vwjimt*;|V0=@t04Jyk)+jTal?{}@}z8I`q45;$&cE+uC3`7=F zUd*lF<-ROIZL13BzF+#Wd1;v zkLioqPOLCt>vnmU!SjVt=0msU?O9yVhq3ols`+0t1#YT;{H?G1$AO;^Ia{u;Kd(jq zyg%0RBK$N&-S*T|GjcQea$xA}d;&qlE4h?$5XTt5$veT?8Kf zvHN>5pPEDoy28|M_I7(Vx{zO<9L;F@G;$yAnf05VSC=xpj=`U|Ki7PI{6MU$yZACm z{dxr*kwvGa4gC30&M40AeuDII8u?{uhCa!*?Pz5@Oi@lk^z>1FHc_|ge2?$Y#nU)l+0ACy57(h z5R2jY!}U=TlRjrJd@Oa(_I5YGf@t7N_ro8^(qU4UL`1bxWR?4DQ2B*6fgVNdePeYM z+A^8WsHZ&FNazoU1sOB}e&ja-z*e#UQ_jGwsHi~3!u;-Mtl2Z93@6rk%LZmjxKRuX0FnKmeu@FUM2 zLn!<}^7qc$@qK|4YPW1h6Er-dT23h$+TTtu&mbQfC}+5%d?Jd#*wEy#&O3Mmi#Op8 z9YBUsgMBjtH#$HJm!A=+Lzp>5`Z*Ss8};|c*5U95=`j+YE>iHSM}0aPO)q6xgu0j4 z*4bY_Sk_GZ6J-7uz}1TflU9N!7x|usT9w-ikWZu|21Km<5$aWpBKDJ^r(~n_z8teZ z0?}A$73#KgKP_UP!1)Ya*t>(tFxBox9`N9_jJo3*WRC~MFT!8t0VD@1mdCR6P z`CvI|^JUC)SNOT`)%A3eSNp;f4Z|mH%!fT51V2u|@eb7{O`iykvc`b=+w*Im_u2-P zVuJ*tDBuHM4&U_?$1?($Q_ju)9b`k*0%Lks2`K3st@P-PmthS6quo{>G{N{|6qa;y z&VXkG3NMoqAsgx6O+LM@m&+%Um599)CClIY7+3D(Typ~i4(ev%B2e0+E#!^MDDBC? z@_BXew0LG-#R^3{7R=G@K6vnKQo%&fx^^D%fAHEjCb>BA0L3ELvu5f@cL{B$yZcVd zYWP-gV8HmT&YM_XgWPIrcm!Gj$v}L=ZeEJ@tZ{R(0-#4Xi3Yq7?eC3FojvxhcJqRf z`Im|LC-1YkR~vMRNTPm%%6=Xm4Q{g7IuRTmoq3%zhbtdegoONLjOwq&y)Y8oW!!8u z3Lm0&X-ZSZI5v^Z3^f0XqP40Xa}0FpE~S0R?BLEH0q$BC;#Ma#_y`%K_h4>QPe*Zl z^-{$v3-)M+u{xYT5ns$ajl5pNXQ;S8EOVk5GHQ|6?lz0QZ3H(NHPgm&ub%Sx{3l^~ z84$jwW|CW3akQ`)*x`sD+A+9KFqqJJ?I3;fU25`9HB9w~*)^Zke=bx47++ogJ=nZ% z%)D>-H{mu9|JXJ>VhNvPDSf?;bZOaI@9_6%KDXoZ+8}Lt6eqpk|GdZa>y>}i{!EaW zG08agnn8OYV4DOP2?t-yHev?_4SWCKxyC#A3%1@Ugk%U$(V#UX)J7*Uq7~eyt0? ztj63w2Mvy(x9n-QXn59)k9{@RzxMDx+k5R@yFbWW=OPYoN=&V-*A$zBQ$~pIMFETNyVPCzFxcWh5#EyvDIprVWPrKGLZi4qo+Srn+F#V{U{vG}%avsIceLfi}DSYH&;GHbv^JbWN)=Fd@rMrS!%o9ECQR(2YQ27j>G&v?KJP{PzK$; zkl?y?)J*6hN0F8VD(s~$?7vveJsNtMoOmSKxZfrU>?}SZtZK!!F=P)|oVHT52U>P}jkEgby71v^Be@+c zLwB=T+%&O^t`^ogTv`Ty(3ku(R=yINl*2(`|F7{QlB|>BXu^I-E~>dg0!;)xvQn{|ANil5st~RSiN>nd>(;f`xS8vd)vTyAIK$XH zIoyb)RmA47T-5UYYj+^hH_BDBbizjhBIim4f?}LT0O%HABQZs}egD1*aD5$jCBwqP z9Eg;al$w&M7m3A!C(Nf$oR?0V|9)LvUUtF)FbgFbrJ@)Lii$v;8i;_6@jLFKfm*gd zFa8*AWNxt6F^zUMiJe3Y(K_ zZTKrlw%)s_f}pWr>*7%&^zqHv@y?JYPWexFe=#^S0klE2J9uB;nO^hKAL%%M2SdZ% zmbXaY*+x5Ag5eF`8!?IE8>Z{J-pQWPTY;Lw(;OK#by~T-=7TI2leg%I6I;cpaG?M0II=Yz<*}lH?RLDCY z*>`49a%_=7zFOc7X!Osv7)mKBRpXj%gmgB86I>t+FtDeL>>6^kxL?Z&95)as+Psq( zz_)d2!1tG{OQWR7=UD2g!ZQ+GM@M$ZWlb~=Sx}jg#{V0ri1Jn2o68<-^vFv-XY~A$B1EE6Y4+*8ttMtRXeXica|M?g#5ZhZfjJ&SX zE0ku+VRNfiP~N_$2!r6*yUqXrpMnbTca|n6)zlLK4O6hj7UjXMyNUX&RWWggvDzVJ zAo2J2Hh=Bg6JIga6Nsazwj3;+zN*i%X|6hZygBPh;2MeL3EeH!nX2Pqh0v=Ua}+Zu zL1^Q;sn}FwD=)je)-WtEBov$=0{>*epqx+wBKe%h8P}4jiAC21KF~s>-rI;KsB?Nh zm-y2Wuk_M&l%p39k;XkjI*Sa(CR@!voD@8Z&)Di}>>#>m>Eu7+1%3rd0v|zS!MDd^ zY3OfaveR94MRVUjPGqg6F4aBm1YPATdlh=PJX2u2rTvAXw5?kwZwtve)EB93iZi7iwGb#d@xjEdMbA3RGlkLA)pUV|CipDNnk8wkKb{P15Vk!X z9Y4eTt{wIlhyPK)V_%Wn$ zP+X4#bThuEfd=RL%lYRo2gkJhg$yO)%Z#~Bly($&5ptPe9j)NX+EI@ozpVIMp>G2! zeV;FtRK08Vpkorddy`>FV~6WedvFNYgwVj7qkIU0wsYm#2i9zc3xA6JFuKf~ZNGP03x4JlZ_IXs-ojPR(5ejJcm1bTgP-YnbFh%C(co<|wmN&d(j3(F zZ9U?7%KHI0%dGnX;|2~z>D(ArQw{>byLEr*NTRpTsbrm~M7b;t2zz)&!xw{tJE*u^ zZ~!Od_0b%HN#M*>ceJ93;seL#gVat4@_HOg3MywQkKES578q1XarD-9Sg%PDSr9vfyL_=IB;B1QOo-N-vve1LTAxG2bk@B1dS z)*??^vF|Sy4!Rg9IIr^;A!yZ}8d2B7RLE%`&}%q2fGegfA5Xv}SnV4EW2D|s4riVa zN$wS=&xUuL1Q9^`MJhLD@7|Eb6_Ct0vz>HKrxzR;viwn?`p9V4*Nz4D7dks$sA+aN z^ZM^N3plsD92{5?4iG!t{{z0^(8D!DTkH6&#RoLeQyon`r z^k)lrTQCqA9Ve~)o^_E21RqIt5gh0GZZu!_jtJ8d`xxK1o|5r5jl`;l8f6Q%NdW&b zme{wORc-?97O?Qm@j;hIA;5YMVG~KVo#8*})%e+&1@X-}ZzPC#1X9LqK;TEeX5~-v zA%|668IG02SS)2#UwhcFlbrpQeU0l*pg@*6RDim zxV4Emb;f9GU8WDKr@ z5mRc#_hgGUW4Gx@s~>zihcW7}P=f#T1`28wGtjFII-2NZV<7x3q5D2AvoGNGqhlyO zxI>u}GneirLtb8$vRq+nv8oFhBb-Yoj}BE@%0e=Dy`#nvTzqdTZ((d`6t0#BaXXi@ zAeXv$7a%LClWQbFmd`R-Uevi7i=9QWE~hd2oawaq+9`$7gAEqLs1FBHg#K^KCGs@O z^?AL$z>20Y#JKGMyLt$Z!H!#sJxn8vA_po27mA034zJ@D%9@c9Vdr*YKTeFsEd~1- zU<{Gu6J^Z{?f}at7O-D76F+X453h2j6w_1jO%8vRtD9K4(g(G(gWkdWyNG~{TW(** zaQ2_ErL|0N&epuw+kL4sT)(p=TYIW3u`Xs$Tz6wBA1~I?FFPF_9ldTEJcYgfBYo+T z7P^R8FT(FT2lAa`Xh{BRkFYghgzD`@tZ(kx29!hHwgF)0uYVo?Wox}2m)1y1l7+|k z-(U6uDf-(CUPr2b8Gvxx%WzNpPN($xEC=fN>g>^)5;8)yFFh`^}Fbc@X2DL;y zrL2gDILEXx+uIFwI8)AEJR|rxrl%0K68(x>cR>lXIq!Ae3_%aB@l$vqOp>SfQDtU$CGJN^YY|bgFI{`wlfRCw839bDIN|ubqZQkhv)4;hLHtT`2j4k`}F2 z{YopL+c(jEOYIRFL4ps#99&PmI=r;A>7VlS?UrRQLC)}4XCIvTs5fg%C$oFKcxg*Q z*7navi&D{pu*wWPsccV7%)aB@{~9T3ie_HvzCkiFjVRDMr7dgNdRp8xTrWeJqcBeu z7trTC2cQ!$Yh$mqx&&O(*UyjpX7*=K8x5`J?{AkK?O;=GcjtYBC13xnxIEo;IF~Ni zD(Ja8%v%~0Oz)%Zyi7)t%?63Qwp+oFnkhNJOMgSu5?uW(uoy-@3FN-`e!nhA?QE^ zC@TGdX)KTZ`fxHJ!Tv0IS=G|g^8br^lJC)e3hzPAV#f`5bldm{qNp^+8f0keaM;D5 zb#soqf16=r*l|o`kzuj5QsiQsco9CL3cu=>=ry@281?9(CZk& zo-YG?I2C%>8+wk89tHeUKTTT1yD@{Y&0;1-BapY)=MtI98KR`O8er#jBko9`Yj=Nb zzg-5W15nn4`S0=KO0j_XSQSw)&~T_EK6>;%5|z-_VJ_|TI7)XMrIv;7XoDBA`ngtm zW-~o`Zmtrq&L}_h-RZp3J$HfUm;Knq4;chxXc7NDcK3<1hX6?~sMsb;obpPdLa*7h zv?MW4U7L4rlSj&LaFHgmcCw;%FJoqBN3Yo#b`W9rRbSifxT?>#^?o;1DXqo*#B#k} z*GijmsCvR2frf7O#9F5>umKw5r@E;$$KX^qSbZ_d3%oB`n9yjSr0PctNdg4&T-86_ zJyanOyzuZzISU)|@sf$;LxmBPM@nttTlaNhHXm2;M`AuvKZ#J3hzwgLX;nz$HiIAB zSr_q5lr<_sn{m#-(@fZ*J^%6epV)bOMiV3?DG{-{6-HyQ^JvT@XcP81yA5xi?|1@^ zPU4Hfrr28$xrdca&nn-Z_8%DXIi%Jx`xCVq_RLLlds32!lU_<)%NMRFUml4(I#qx8 zw{=i!ibx!SYf6onO-eS2?S@Ho_<_X!BC-u~2cIk%8DBiHpzQ^AvZi@+8x|ZH0V2IW zLiH|=mxEb)R$sMsNO4VcG3>JJO<=t_)U!PKM+lXE@39~OBmWy#$&u?bAsoRy3bMaWl7nd!~-z17W{y&k*7=80h@ zC16qGGZmYTq+AZxb;ZE|{niATQc_a(f1grFmFuapol}#{tCgFoEwi2_m6nZ1>wDjo zPC)FuP|1+KZ>ul(mzQQ-@*Q-CDDLu zY1l{;nLUZ?VU>xgJc*)of=XwMaX4b=X`pY^O}}Mp)TpNUF!TOu3d;KiOvLxYeqK-7 zfV{-3p`ohkV%EjWN+(rO=kjwpdrYVXcc1dFr>o`Vo~5Wd{pS=-?!rO?*xC4WypYR7 zz)Ew9*;vauemDT=P11i|)b#FnJve^ytf_IVfIS|z>Mg|K9*ZfA2{vC$PtApbS6wur z6UoX)FN|kyT^9+`x%(;yTMN!@l*dFZTY_sBFJmtg)NiRSJ^J?aX&4F%GurH@M(VWY z{H8$cz^oVyeAc?knL@CZ7Bo=yKVUuwq%RaIanK9H>!--Yw7)}PzwR&U=r!q}XE^se z6EYZ3wRi1EZLDCV`TIpy*DyG=c9?hMDKQ9mKwk>5vtJf)!wx2xh3c#R@{-_gZLk3s zLGqk}{+i0`lVpv?QU0mVvTthlUU;!C}#j3C&6;1 z9L2Qx37zS*9JQOBQ-Oy4jC&EJY0semn88HVX@zo8M~|e(mwE-4C;m z2|OOx@L!7*{Z8gpvXr7$R|jE!RL#pSi6@sQoBdcKdmtYf=xj_}{r$b4T-1;p1{U~IdOo(0`5`bUCp;!Vo?6@EN!vzvK5N6@f3VCGvaCROW ztb)H&41^A9?`h6yT*!VBYhE1TAxHO<8766%3KPtA88v_7=cSd!e$9Fw^S(T`7=NYg3;Y4`*#Im$z?9dqcTeTwXvq=rf z%#;Lcc9z=c$H?BEi;Km@L7j!AGK@HPs??e3FJa7#yIZV}y~b+wsTSq3iS-)Yif zum{sr9se>x1@CBka1Ri>=3|2%29>GIp(O&$!(*=r=&LWU_c7jDrJM*~L}>)jI7-Ze?q zRR6dnW}f3?;)BBGAB>I_S?LNEckhcJzgofov*KYOs!>wdgkbyO%=40}X-(B8Du?Po znbu27-eILVGC>x;4K6XQVaMfB(ZMBj@=!rBGs55c3X;(rh0cTCR^D#ni~dH0!xJFG zP+|1##-O2uDE=vup*KRHiO8V|$)S;rqls+St-ROJGdf|EzD?KD_Ppw>hI69nbv^Qp zxBhhbNsbm9JLYEsO^ytHxFpr62e#2px;jd|wGG2-rrYT&ITCzLgP#r@o5#4^#}4Os z3zJJ~5;toVhm_tK8KR|RjZ*b7q*Os@+~50T1|^j=k(|vyth&|~89uqKln@FiO8cxX z9aodK-FsbjF6MDorR3`fEA2^0?5}a|cQvND84ZZpG;|zq`K9x*3<%!eQ&yDWmScp( zbnk*vI8b!mlBL%S+6#SAKmft^F5~Pz1Ko39T==m@_z}>De%3is`9&n?ekD%&Fb;G! zyiex5PO^hY9@deC@0eeA+MWOz;By=>pVO?+AE`cGYI|Pt-s1M!B5d6t1d$o%A;(T+ zzP5Lo-bs6HOAFmpMF~D%O#$fl*CSwiN$j0r_5ryd{^8O4_00QeixhpO8F&L{ZYNd- zgjyB`TbExOU4MQvom;zGwRUY3Gj}|g3J;7$ij8P z3s5F#n+{#~z8`4w=(FjI@M|Hc8VZ46vOdy;l-091XFjZ~z3!7f%M#Lf-&Nr%r$1)5J$A*#JZ}l#Z`!@~+Lc#W z|GI2myWh=yeBvR|Q0dXCqM#%`@L0RE9ZHP;-LQ?DQT8dE1Ox{x_9R5Vtgv2Di-fq| zz=H-QHp{T+;e%{%NwjJcW5s!+XfR6XZaR+_VsB$qb$Tu%a4qix=$MDfZN`3z^r3lFWv~5};!~W!oQY)U z_xF#kXi)}n#0plA!}{KSeq2m{{sa)qx7(MN@clgeVtyP@podcNKZPJMAB3x&y!!87 zx6|dn0OlL$-e5e_kgKboEYz3*s7^?FN8roD+%sRfLKk_5D=}DAAeT%Bf}@H;l8re{ z4#K1bA+IB1$WUq z!GiPsp_kpbL`&&{MT)uS@)0_BsuXvQmPoAzqC2{Z@@MfcF`2g9hr@9S4QhwwwtQ35 zvAB|Ll|qsU{?JcU69ol7DIz~9F&!S3kQy(Nku_nCe~J4R9!4M|%T}Vr5w`0rSOv@z zkH1it&n7wcZAX+ow9-v7)E_RY@QOQ&rY98zoOdfWKUKq=zIoa@yRV(D#I-n$(nehC zXberdCtg2#LhVi69~3LRw*Z2FZu4p5bNdTSQq|fTO%PIZStpN6mBf@zqP(2%IHbw! zoG>XVwBTa+0;H+<*RE11q<35Y1&HRj<1#aO_BD7KEqL!&c;C9D3%S_N4WA-U-hcM~ zXU>X0QcLPRwzPIdPkO%-<#`-O`Ve`>_iNiQR?=Ue)1VnSC*tqcHT@1&w92%*QF(24^nKT^y-$3VbAsWmBDAyay4meU6a9 z!3cT`ViRrkF%fzoHmZs_&AhGcmpF||4~0Rtsu|#@hM$-1cIU?&v^o(QAyK_~J`$By zO%vvILF%?TQ?pauiNQK@{g*_=JS}$e$zT;0=yj{-W2faLaPMmq9;#N!0v42&)ey-E z%Q`<6`f*dB2Mq}rB?3vPLUN8lA`;aMOE3?YSjrCh!nvb>z|2|q*O%uYbW&hvvUScg zcDd5*V$kf&XuS?pf`A`*CqlXJ%aKQSm}O_!w0_Vl1F#`RJ{f`^V%$4Z^f@LN%}h~Q znGw#=m-rC|{BR^cHoPd&nW5OFh=pppupcPxoe5B+SSgbD%K#TFt0A7yI2}Q@6oj`3 z;ENxdEmJX*ku4^My4sZHI9mhx@_UiQZR%P+2zZE+?Z{HZRc0ch;J3wi0whtuCN&oT z2od-e61@vl`T0gEL-|BeT2emINbwHsL48IGlEf{HjfQ zYr>ufO@#nV_wn1T&YI)xiZ(PcDWJ|7P*`>#lkTrLT@GMTUkZ#-$5k`H>Vp4JSqPR= zTOg6GYJgmyb%@3OU|@tOK-3eihlhjZ`1?lPt?(ymT+@3;`OeB*%uDG?dmxrkGOEU# z927=!XKzKMt7Zw{w5?hGeKSR|eWuBiA+pNzYT!>DE2aDfCpOP^xu#KKSks-7G)#3+^Ang(O(s-Qq6|e^-&ezDi4+%}#Y0oQ z{HnDYI0rV;^|*~4H|XVn&gCZ(nAw3y97@AOo$de&X5KSAd>+IHBB>2Q^dRq~VYP^L z7lr$@2^MShH$(a!>vI%Bmdz6+Gpo^UsFIB{=9hy3i8XaN?(z7Z=$sf#>f9`jgpluF zNPow8PLV?f#}aT$*)p<+{Z_*i*bfqZ2+Cf-NwMc=3yU^|eD!uV*XP$R{8-Pv4+Z{% z#ueBv%{i)PkJblVz!V#bBcaFMpQ+ zh0q|b8%@cxn+&CdEfPYI-Bw~#P}Vj}4Id0dw# zj;&PPAM`OnZHZD6-M3X)eX8O8lq9;rG(7^&3E1cF;)8E2;r}TBLoHm6V2v0M1pb&) z4&WFq61&}HCUzRwhBDXeEj z_{Mp>lj(7{$mr5Gr+z* z)NhWH9Scc*-7UX(E-a(nP&A!n_-it!{lGbMAF&cTPi_0PyHIo6di@i&@niF1wfCyL ztKstnep#>g)%m5|^5g1j;Lse`n1NPW`iL_P7^I@Eo@fHqIQoy0`MA6{$?^V^fp#L` zt{AE=17;+1$t)igsN%fZ+M1el)YVHT{unRZRsg!$*-f6wCQP`!&a@p+XVTisI}A&B z45oPDnwZ^0Bzanl$w(jJ6i4?A0MZx%$`NHSi`ERWeDrm#|M+{*)Yk$AN>@hNk2Rl;D`b%MdjQiP3Bn zRGu^69^^)Sk!`-p7?21E!WQOAI{hR8k+_1V@spw*tDhqky4t=hWd53wVQGqr4nBE-e2xzxZNa|l(eV=(hN!q)5Qq)Htu6| zv5*9-IG&0HD|D}MQYW2r9#ZKlCCC`nz?bGJLM0_Z$61Y>{-36)F3UgqHekq@SUX-V z)%7>~TguGPvNyEq>cLDF%2te1C#H-eC6kSMqWX~i1ae(Llo!g$YK zgYqWVkO-DTeQgl=%0k)CCz;g2Cc!alFE8@t-MUFcF}R|b zm;rhA{6Dc&LqOyKEBzX_1irUogOz4DN6B!sW75xFUxunXvb61t7xB)XmF`JWoWC`p z%YT0(q1Id{RRV`KPot~J@_@u zSS4^t)aqGp?OMl8Gl(rA;Iuyu+}*sNfnN6`;FAY94$rr1 zugz_b&6#)I)bL5a+}-((WrVM?(VwrBU#})|rM*x0yiScsAGMlSUQn~$0@(nn`u}LM zKyk8R+57dm?LM{b{=eVo8+=uVg#;&3Z-W3@?;?G%-&fgndodEeF?v1De6FduZAVGC zyl>Rvq5@97?hW&eYe)XLlfNZCU?6CKTmflKc{9s-FK@C{}UwT`C;DF+-gfK zNy9f=UOnoj7AzC)=PT3GIV>d|ya~%fuD5McZz%t6g- zd+vvMKm7UHSm|YRzxD#mI4-1L#2Y1F@1ol7j7Xo_t?Y!IO;`pCa3j+M^dWA^Ns2~j zR-IWoM&MxJwkIMozU1VDP9?{(a&r;Lc=*n?Sb09oCy8;D&+PhcVM@O3HH3N9*@ep+IzmQ|pq0w_=yo6Q0 z{%$CYZ+MRe8ph zvL9FnRsJ!gDLgkMwUJ0Y+p#;r18=ZOQdAwm@hqxH1QG#^VH>8@r887soufYv1}6<` zn`+tS>Jj~!xsdC>61Y>;369K4Wjqcztqi}{Tg<(z;$tB&(AL#|T=up!;K8;qfZ0D> z@vlDA-zTpml`~b8+turi3_h04Rx;FY=FrT|HFb5k&J&I(C_}#?!G1HaU(od!wc7H?Y1h0%(Pq?kcjdhR`>|dnow4d^>~5Q_9YGb< za%U__UlU}j$i~%J-PCF4xp#CineKKzIN=|3bGC4M7gtE)dWU*2y-4i*ZP(mt?)YO{ z>sN@nP%$XY(V8BeET1`qa!5@@CypRIkY?PLgTWOaJKfnM`jOu1h_0N`woC~y0e7;1 z15IJ9_~_CB6hUDOnpDuNjKF4`J=llDzFqu}7`$|*~p&d^wpf-?dRWb-?0C)W=UHTq%f)i0T5tHn#?mWd(@54L(*mxZdsEob0(Y z*(n`->jB4xQcfe)HBeNkK0}HYI{C2C{r<9QV%*j^@H?g8dl5gJWlGX*lT&TYIN47* z;6sOaDIGkNp9r(1jSSF<0y=pEZNy&>f6dlz>Tlt;68(uO$WcNuT+iF_c3Jnnf=0q} zP%_0KlAvfx*?Dkqzafi{%`ZnDqS3JtVqve%sIyliIC}*Zbf zU#lVdJ=~=Enjbw~W0{^SApq_o?Ub>?Yj}Bf+x4@FXk(=O5Y&q%WZpV7SI=qMIPO0|rG{ zLvX@nz;yx5B@NrPPNJ!W>X$L$*UsVL;Z|6)?#b>TfYuuv^nLRv?cZT8@I~%z&81Qd z9VM~^#&C6BS;_VFPYEKGdb<9+65(#Bf#W6|q#}IChVl9IHatIalNw5ztB*|WQW($$|C;1C?a%WlH}rqfqD8ZHLnYlzvW z3JFT;oJP?CiYv99{WPH=L$Me>!7^@r3?zu{taKOc!P|oV7%^gFWJ3S0DDtYm-)tgM z2Pk4u5Pi3=FGKbLiw@07JPPb%HkgF#4eG7tv!-zR|B@*zu6fn@y zDJcQc)4NF6o@bk~mmL9&0 z38_HxS*f5iQ)T55_*Yzg{z6{wX)&c}BV-`;p=gymwZZRD;8e2F@nf^1Wq!vqaL3kN zSC6vMhRx%Fs>Z^oG|e)HgR*d^i)Sw_sx7iLH4;9TP3zjF2rXpz$#}BD zTi_L9XO$DBcB&%!An1I~mb>C&H}_456~aP@vd?dEoY@ zpZ7S@n^ibfFfn;=xp?v87jtn*cg^f&x_wPO?pJJ}ve+_eJHHH3A{cRpWec#@q*&yk zXVQ@ZL^2oH#-06mT>$k8kNx)Dg0lWU=fBM{W5aV%q?zT=5y6)`b~}%i5&x>MdM+!c zl#wG&gi{hTHRkTN8(VGHgm#{1&3n~x*Eb!?&l`4`Esu#e=Kg||T@m8acKq&_Hf^^@ zq=N3-D9r=rwIw}zExrD4PuD~FJs)@?H8nI=Z|WO74?kzVlh^-a)VyMAztD4ZA)TNG z)u0b0hm%Qf<{XojvoN9w728{Lvx6&tZE8(6gS)Da+0C@EKG#5u?&mM(&Urlbn3*sN z!o^K`T=7aslK3;Tbx=GyygYo^YpTB;q00d|rJmsU zNlF`>Lm6^i1dnwjz}!&8X%dmv$K;!%y9SN+-%L$S zfzSrJ;MITo0lTJy0(#AIV6|;FmZ7qQ9@LdXLl7ZVv%oOK_AdllXQCaL-Var&sdn1=|IuKuhRqE52qRO zIpJBZ=bIPoW{J0_$zChz(qJA5ED!1ko!XYB)`QYyXCvn(i*#%x(BioQ2Kd{zXbwg9 zxK=6z3{Ug5R-?YilNFfN_zID7=;WepL+Z??c+iIe3+UVtlfJwLZcIKKL&B#cBPvoe z?ZTAD*KZa!{+Dw6>O%@b416PhSDKyFl`g(_%9WSv`}U93Mn(1Yl*1kgA|9s3gow>} zgdNG13N+_}%*Ha0uIHT3l7((NCreN7+fkLhVo{~wZZc5t1zDoiics({>WAC?Pi1^D zzCn79dlFwRel(otas{Cie3!bgZVu-`E9( zHPktL|A0&;7af3+W+o~&QRKUc7u?y*xd_5wA+YI`iqyu4QAz!SL8fNPMxtn9BUz$m zISdL{HJ*3m+}E`lV!+A=G;bA5dg+#Ry4Ot=bZ12g95p%`%+EFs|Hsi;Mn%=OQF!PP zl#-GLk(Ne48fm1vyGy!D8tIbmhM~JdK)O4nyJ6`0&innFU(A}tIZxbs?`uoUZO6rP zNTJcEd_aPG6C`sd6w65%7ZRn1QBhTxdN?b6Vq2+xHJm$KXXc>i1Ode_`ygl4fUO{OFjTXA?iHS*Y?J3YZJ~W{(C>NB?*zcFQQBU%@dfu= zQXPQ5=o5VIBYXHO0V0pc1HSKd4g+?9p)YU#L^znmj|LtWO#>spz&T=zh3BB17$TE* zkD74P!J4vR4}}cs0ypb!t1ib5`Yvt93mkOsO}8?`4rr+UDFGq26Nu7m+5`j1 zmv6&zWmM5^`C0hZh;M&=DRPXA_=2(qe;N+$xP)xn^awtl#=OjRJ-j>^aHyB_@hFvZRlc*uE&HeTA6?&HD#cJc*6W8ZFH>9u2dLe z%3G`)OxCa192S4oK@pNDiRekor9tjQlSx%6J&jJJZa1vW{E135@>#1*_P`Kx`!Xd= z3!>)F=SunQC%L%wnpFefBqn=n4Cw1N$)*o~KgJ+Ntd5K6;fUqPpuD}bZi%J+gax>Bv!)K{gxIFK9)FGi~~Di6wC;61}VcK4${Jtit+tr z`bUt6@Z;c}r0fsIpCHm91Pc%fHz*Z%e*eYE zl@hktrxZg&8Tyv1uaqX$YGyN9Ws}uMPgdLq`7SllAE&nIF>u>tu@wrDhSF}!(!jzv zh2aO5yS!S|aXX{n@dSt>Te{i4iH?STY-*$v)==7Y$q?TA_jLMu2~y0`#EKlUtCT}7 z6r^}uPDl=kSKWde=>_3VQOHDt>G<0t%yu_ls%G;_z3jTI7oJy@i?cd@*glLdDG$mK z^LrfYHjL}wq()cO4t(66a(~zwwwCK`HMGhoEsTmvEj?UVciKowy1v!wOR1p01+a4I z1DfK>6Iq(;UKXdSP`OM#-=|Iatgkhw@;9VkS)c)?V&gOxSGqG?vR}kwfN7qa?*(s> z+bP-g@EDCe(=D@pd%gR~;1gJcG*PURl zw`xeFj4H`^k4Fz7i!3XgyAAXr?9lT&Jc>}mvf!jM%;(jda5+=x=ElRDm~TqIEu$aT zJx&6Fq}vUJg$$Nab&)UJ*T7V(3UOyab7P~UL6T-5Fq3$$5CrHKkfRB*W^>As3q}1B z`?itE96hoJ(r@kS``R6Vponw2(j+fhsn_w9GzQCIP`q@_4kbibGZ`T1-89-Go{a|Z z3I_P+8ear|d?VfoDgnF!h{4fZUpu}3_3kaBdfkDyhfEsTO(`3`9PFvS!DCd-cc{!m zrjANVn)~L3(eGe067ELuky1UMZKAy08C}&#t4+`S-=U|pQ>L7KbzC7Uxfpfr7F#6! z#K}}EWq2L?gdjWVZC%B7|HlA#L?O5sNm}|*+Mn8HqPfom=%E3j0b!YP#f&2?0Voh{ z|GIoy!W*x#MOu-GS}&+b#aPwL^7->ksGo_t)>Ene>m1rhc}v~Q?ITy`-un3y1KFaA zR9Dk<$^frjXX*7#VS__3VtQZC)S44)2E+GYU*J(f?|>_+I5@f2%Ii^EK)yicS zzNq~c-_D55fSxQ_)U~XCzGjOuCOM{(ZTJEN*8zf~wl=TBwUnZ#i%tq(=%-|60~M5jKM5GO{;9pd+~ z(>Rua4@LkB&wyN9O z?P}dbw0J&1z2rS>zy33n0K}1bcuD2gALh9Pul^d>gdD29e*OZ)0-OXQ6l%a=wUds&uIN$VSQ}xF5@8-;M^}PR4D=hyno?T?aAFk+ zTExF1vfG;rZ)nx-2qt-w)q>uvLtirc!EM4}Z^9;X}x zBh=V!P}fb(gNGEl&3)u5AumvK13mNAO`Z=qe$jsjoFHA@poSpxfHn(v%VxgI0T+p; z_U-j=G&_eYwD*tL-i)5xppRINH z-Ho{$|x?IN4RGq$J41Nf*GoKPT4CP+i4Gi3!Qb~rgxB@2A5o2jLXNoB>&6qr8gkAnbV!;E|D)DI8zdF@NN zH@_^{3YGKMCn;2V$xDQD&ChkJ?QshW>Is8mF-siR(L`&69l!>OBH|#mFiC%Z#=LrQ zOhk-sI0paIvR6QFo#2P+NPem)Lv2L6Coz(s-F71&1>7PLc{zQ08XC>+mz3=K9iF!} zgQRW8m2K1sQWw0sdV1(CPv}TI1YST#L|Iv8SnTn+W{VsQf6$?6h2Q7V`F<{1|8En_ z4K^uPW~37NtDSz>NU8PTAJNC{?B~AMkMa@`lA5eos{Qjs5^vK!K$5`fs=NH5a_e%{ zWO0t;!S$c4%d0^iU9uKAH_iu*mV3-n9qE07I2_GCFg$er;z-728-=;wm#{PjinhGOAD7pUe}+@4mTtqHH*Ifs$9bZ+{rr1@pM4SHhr`j5u9OOO_G%87$%3=JQT zrbW=_Y`FK?IfFwjnTxPN%5Um4CaKgnR8cXlEl_1men6TDc z)7Ol&3KxcL6`tuz@Vb%OKM&K$Y5R?k48~6x%so!$ZVTPxGyH`=!4i2V9YjhD7gsc? zJq;g(ibIdW@7S?dvrc25L^inox@Q_wGH+si`yRZY6?~?<`ONCIUojs7Ul!2a+bfM3OpN^%{{{sP zRS_H^1osG<|HwiI+8oAxnev4E77d5%rHu&c_rPENTu)*|M%(&zYG;uujpnDcm?ERf zPf7@fS2@;VZFFM8Cxb9VOi{K0P)-=i@r;)D$m$6)KEFCdM;kEcywb`?er@(z2ng1_ z)w1=my&WE&E(914|6KF=^(T&^O7wnNhcB(!b@;;mMXQQo<7*Hahpf{Dex*$Kb8F_r zLYJgev^LB66OC4~!Bu%~roOspf!(%6~-m8AyBBY~!|47OFfD5+{ zzJH-d2t+Fb(HSUozx5CL3kIroPoQ4IRJ$hp%*f-)JfuA5ST4!^G;*tT&`l|8TTZ5x z85BJ9aquBu_UIUCXQTJ)5)F_?E%yE9qjkE{@$@Hr1$xTAUS_(J=|0s!UB}+K7bVGA z+Wo%YVv7T!+91VqawqW(jZiql>A^%pHTh?84CRRL$b#k{kMph&f=Fh+I)aGCAJ!+B z25xFE)c{^V|8=+P+U<25pfN%k0CQ|8;NfEiGCyR`J!EfNeG6y(9_3+gKtBb)h55cw zce$79(8HL3;mcjTA$i}c|8BKFT@wNbC~`s(eEx^A;ksh0-+<=c7cd-dj3pXYA03PvMoueyp%)o( zbUQ!>`&SIxu6lm7K5u~P4Pjf;PGk|M_imsUlZJuLh!!Y$3Vug6`dz4y$<(-7=(5Vjt3zSeO}<9Fou z_)2!~r+;dfbqaai>&xzXAhCb$hWctZEpRR$gmgY%;G_P@Q@Yil!5S1tllk03g&WmN zjLR6DS|&X1O8GOoDI-oJNCtye?$e*7y3r&^@l=p}0~@niwpZuT z-qGKl$L}=J#&_3Ezx8bS?n~p8$BHiX-gsf<{B=j(?T7nj6p5VfH9@LS=g%z^rDb`Z zT2FmxATv8PGV#0JCa9I?M5C9^j)M?r7XbpUfFTDB@t0h2o&84VrTa-n`NFZVIx1)$ zn7I+{umRm8J%uK|zP_%mcYotP0*v~<*L;jzyy8-T?lUAea`9IcfdQAj>JUpbD zmN*GdYI&^HMN@zjdsra9C_wrLX*E38KYDfdV2`dpB2p80eNuvjuBzEiTK#g59=H;k zI27{)4nIK&wN|uU4D5ZvJfO2=o(IBQs@B|_xe|xZy;cvUN%h$$(j~m(WPXoByGe5^ z=R7*uBr#c3 z-_?T*+V!1nNY662q(4zjU*R5mzdRXLAo3%b`n11`L_ui{&@o)4s zEvlI$)?2FZ4ya-Q97{w(8Dm7Ag0#Ob=9qKT3P1S^gMv_QGdS65Cmf3v^KjM$wH+Wx$gCe8TAuq9&sa9CG~4Qw zCQ8pZhZ2-0qB;j$yyZPiH%tcew`7WaJ{bV`lMj27*$Q@Eh&bI^ZNT7uX=#c4-2G~Z z23S4b&u`^?M$fA!ae|x{`ju0Vy-I*L-+;pX1Nwi_2>3lN<)zRjdMkah+>#ouCBQ&S zZ=;f?RJNWcmrAQR8sm=UfO7)+cG-MPU_Enlb7uzM0;dW8T0l%DW>w1L=HlH=s}&7Z zt2mRkdVh!D2IT$q!c($x^09Te9KL+-w2u01G0fg$3f!H%&o9IRPnlQCxXlfCdOP&& zt*oR);X|;iugvOFO*Oe?zeZH*@!4zC7kxv4z8iS)dyaX%`(e7v>vzz14jX_9df&NO zOTAnzAJk3gzgkmE)tQas&Fo#P3wH30N?D$-Y6AceL66OUyz(bcWUxmr*omLV-DKRy zek!sU8mai%9;V<4lifu)UDeOv~HwDgXl4Hlj%DJ-;&OkWtn2E;v7+Ub>O&G>O z?up5c575pNoTT(MJkEkaAzo~82Hhh*7%55-1RsPb8YChr^3UZHcQ@kaQkUcomvPm? z>m)Zd(F*81k1MGVpO@|TjwS!opZlL+b|j1AT>5gY%RE021BK$=_(+Ui_p&nxp%GhS zCkwMuPV)HH|7_`A@)*q)Z_&I~6Yq>`DI zhKeR!A_(}$|C?b}-f>66kz1Viwv%jKraU}9Tpu4>cj(E}HPqK<6dkU)ZFIPuuNM{; zR?`OU>uYE%Hra2uj!bGE!y6EO4TF@5V8;;(j)li^P_ubJje!#qxy5a| zIN4#a(L!R0V6B8ZBuZG+{{m~@nUIY<3c20CE0KP!N?D7L^*B6xdE+g5&(`J z)gbNAu=$q2r@K39IJpZr(>W~~O`QD=59yNPWt_G`IuaTnhdlHC}~nwS3_^qCTqT46zQw3HkV53tX`It zDvAoHFe+2_t z(XD;!c7C?E9bfILqD;BXujldfVw~OV``*Xm*PDcmE64^LQ^a~TjnTq9nl-1es3&(; zFY%2MWVD;p=lts<%MzaqdC)CKwR)SU0yb_rk|KzK_}7V_B$Kx zJu6ZxV?;^nx4%z5_uk8uXSTg>>Ns9OC+l$E?LDjzmQ)TPs=v0km<>M6o3e-$|G2LM zQA^LvMDo9M=Oc`&pSMg4LH0X1BX>foR!~jzz}XYt`{{Aw!=wZXs=6BKI=REae54ix zU!*b*M!`OIJAq*LHYOi!}$XTqXLE|6&r|2Vu_}G6ba(uv#lhcawRDG8grS(QN zNhG7+K?i!gzOvO_S&(|fkd7NBf(Yq;EMr$4tgSsMB%N~}!$U`sc;TZi3=Y%;w+VcXrUh2uFRSQ5lo}L@*1&ZP~ zGC7Gl1|hM+w~z7dA{%rlo=N>q{T~Tzb#--b53oR+17g&9^L8{)Qw21bc%B0$V3Cr4 zav6FMwfAv72AG2m$)-JgK(@obABo&Lv=D1P(X-=q>lZV6=(j~ZZG<|YyG^3c@&`x_ z^jRZrwa?Si51QY_PJfkG!V-?H@)J`cj+Ht(f3hA;(OXQBoc{d7l*c(j0sXkGdW!Z5 zEl7CvXXm#o>v$^Z!?M}{xb2Flys*rwVfxW2-g`rE)R%$w>&$b$YM4KWJ3ZU?au$s_ z19=mq0rIyYI{sx->}NBT)5}5Ct?i_Ek%o;WBH;UDW1oy)7B!!Hop=}JZdAwf)krTm z$F^pkWQ~`MfuA@kV))K0FdqfafA)LZoTc4vBz(MxNo;V-Ql4T^pkjfEwhFeKD6K`3 z$TTt-CmwvDXFp>xXW0}@Dp21Z?;qdMwx8vR#Uv5*W#??=Z0X=mp8rJ@$Lm=7j%w>gyt7rn`+3%>X>{z4W}6q|)bsVo{S&n9 zcuMg$IuOPsEE2j(qz4?xzS4roox+LQ<78==8e@WvcdE@ztyRuM^G=w5nR? z*KD}768Uue4R}_rSx$zuHFfVNHuf4m2_v48(#fP#k0P z+#AN7zd9LR??Z{fa{5HjWFBi-?OV8@jZm00KNEHMbmlSk8t7G}*UCp=o7M50Va&CW zDl3&*ksBM)p1q&nyO&_3g1h~%ARGUidX%v&W20b(5YB?psb~anv_xs}j41d+LCFU1 zF9Evjezk5a+aTrrWpux{yQDji(qnKD1G^M_ozs7rtDc7ak$*;HmzR}A(wvTYS&Vr( zs(Q6Lm^e*@U*MweegCRnYyJl1nO*Rjee~J>b*u}ZhQCa0JVG`e|NCJ7)M&q=__^I1 z=$ZQur+d+j@LzElnb%28f4>+ASk-t1fcv!Hf4!gF%T@f)vqvm3p!Qt?^ua)ZttQNI ze&N`~{$c-huFL1KXK)=h-qg7_{&Cl$uT?SLY9z#Gc-%vs0{OR@>pa~UY7Kp+k~Z~b zZ(cpT66&nGia6>PtrB%D`FrPKQTQzXpq>PYI}(=olz{AZXjPZr#%Gjl-;!>1ga)2BCN)c)We`P)f0St`7>{!^5f46nM}KKE%*WX|7e3GsT|Rcc zF~`9m-{weO;-ebCE$<)J%E%ORtAvluMYmmg8?H^{O6G0_QM8YV1(0z~CvmA-UUmNK zC967n)L-(0(~OB^C(3!;{`E}U>v6F{WEv>x{EIbSuJoF~vG&@dd z(5mWu4f3oja}*>k5*HKG9Kw4?sbj;dmdZUj>yx{)<#o1@yPn`ECad(Sfp^N@0eVB+yuaOS9}xK?K6ibt7rkI z_g83UDA5~__M@Yyh(SMl$>PAPzlY`P{eyDg#_TRpP2r__hcV|;I1IEGb3j{g4#Cal z!8BXO&S4_GF0o%Gabl5Gf3i$c_o0>uT%bzg=Ykl6-4HfVyFo|>DN2ZL#Ozh)yS5A$ zSV9*gn&R*!4$oW7%Owg^GM6N9R5yh&Zv9gt&f8w$Vskfp`)yo*La4Z*;j{AdL*7Gg zFJ#CV{oM%!cp34~9JsJi*bdUlGD~z}H_CC#D_Kqq*6Sk%5H7|6%QDxwC@gczQ^lsp z-x@8wJh_iI-}Pjyqv;}8ql+jiZ@)-kNg;KAN>CU18B&@+#dE(-wcs&VR_Id_b=4kL zeHFI6L+W@+0>5m9R3^OiOZB9EQC619r27*9bgZ@O9Surh;V@bv z>zCQVZ8Rz=94nQU*3I}nHwS%g(B6Z7@xA=*>%_uTl;1pKInIfJ!QeFrQLOX8%DXvf zsU!EE2|yTgR{yw^w9+&4d)!q#Gr?WuVZ0B>ki`hzPM+wr&DkZ1HMqOrg3elx&t!g2 zEa^`9xV0Cu*L5X-_qi6lf0}TW*m&87b?r*8-!|I&J_ZzD8F90(gl`wDoh3HfG^MAn zjVTw8-_Ezb`EyL98*(9aBN*OH)>Rg?8{uf-!!u(OK z5*nw3yo+_3otU#UuNfaG|Kq_&eCBMq$eQm3?{`mXblJ&!b;ieBhTD}2gb0LEdc3Os zx=*}SQrm6lFGs;xL$tsY5h(^)2qPn}7SSWO7-Ci+woL(iQtoI-1E2y%07qIJjr|@F z5DATvNcebtZQlXCGiTN@I2W58`sPIj_{a2Lx5?UE@3x>Fx9`mL`J7zpxY<^sDYrRw zwU>mrI(;_05xY;!XQ(QNVQ1;UMs=lW0E2*4C*s0WvGce%u@p%E1Bk9swMysO6xxVr; zJ^R?A%MNI#6`$|i)zxr=^}@J*XLDm`i@D(jV583BZ{wYrks?mOM_ww5@H(z=H#7lZ z-jEZ16DI-lO4Vw72&UiU#zU;12Y&~p(JG~UAYu4U$q~^&iHMEC43+|Eq0kp4lnaV;xL&^e`J;U^-M zw)f8}-#D8&fX=x|%n%hfB~5p!EkpHD3r|)X&N)KTQZ_H13W-t$QL?^ay{@|2XwCasGvx23N5KT z^|H9uL#kQcyRQX>ulK``1A94D^-RC=xKc)CC$ds9*A~h+83R}lv;+zFf}=;x1U!8k z+}()6=-^O88vzu#ocjPXq6V#=W&TAp z-4@4Ppm+qx8U~Cy43fC5`asuW1RhJE>pUZjs;ZfM9#=$NmqdLLP9(DL;Zuk$$a0(9 zUXtJoPOo@K?S4)(zn^}CDW!UJM_g~FZx}+(G|0E=E|!$aGPkT^-Sf^z6Z4Og%Pvw^ zi+3P389a-z4trZn=gFcgI$2eR2Ks!*^u4s(KxcwO#y`I(Qc_BH8uKi=_CUzl*>6~K z2bIgR8|CYAqzu`NrXo2eRKITp4+rO8P(3^+CJtt3cV2iytf@+v zWY`IRU=w+Rc~;4{|Cl(faVnFQU_Us zFv3&ijXCZF#cP1_G7MD`K}sXD?k!x;Ho13l4H#pd$1U)+-_h&mH+!0teQXaH%EOJY zq^D(Xd|ASCtvCp0#zLCD%$*d}c)wotv+u9pMB6tzUrz5{FUYOC#DkyK3PpwWBJrwj z(X&SFT3$Mz{9x*MW<_>9v9(B|xNszbUt!BDs}I-ds0XR$Or(N0Jo?eT0Jq)k@QD5C zu0egCB-tZ=3AT+7bUJ!>EV%q4Dt26Hc6=QU*KG(6E)6AZaozdRSlp+$-05w3eKZ&4 z=C|2-_Lx+9IDh_fm*BSUbg(#PtWIeDt7UC)f8a* zq&24*NCd3Lsyu(BsqpDix+(%fHG=I$Pa2O_L6XJSBx_8dXI_6z|9AfK@ZKmO(DQqL zSo6!v$RPTJSNXnZ*jvd6%v3DQAV~^x14WfDRp?{_zKRL!@;}L?K-xoWe>+X&I+7siJ?w5t6{tEGh=f2hreISPU(gus~=|2Ief}N|Oxd z%}`8`SIm7O!Qmu3+6*HW@Oqe9Ssi5poD?9G*Hu%4b+Jw|zy}JF(*u*&&m#k>2#fpU zVe!W6U6bD?0@;0`{$t^P7?y+~6BYu1&ub1e^8(~1KqUdnkwWdKPF;_0TUn_&_J0N! zHGGN4%lwU2MF1YW^?bQGoB@)%o}I6a!=EHW6a#2MiWUB0C8`sPT2!B<<6zs)Cj4aDGO3#IW|#Q`4P)JQC0>v!D+ zLhT?SjV#e1#4D+FqR7xbMVwT|Xz-EaMM+|?IWpN721>mYR`7dF7OE-=3i<{lG-Hb` zI8;RK_k*=8YpvUR2>49;YfaXVe|q@ilG%UHgUd$`hBZMds2C^O)k!k(qJTvqRspkb zxK+239Ap)wR{pQueD5?dwYvvd2W2X{LNa@jv>|+^mEmb-HVsx%dNsQ zBRcn4IgUBa^j$bUYju8{?H`d*R#b|sjZb=TFIv+hVp^$H5iQt^8_YJcrVbWaqlhYG z28?!Fa@pE${RND5=2@-W!(3rZ{kNr5vUQJ%5t-a>x5JORO&RWwsmwSDS9dELFTDv} z+jMi%tYEB<5g4VZ2NWebO`11(ASvXv+lq$j$x?pUNhx5=Khu@0z=xBnS5#Z)=6xD1 zocnWG^Fa9Trl#-m+;4BlzS;Qh?!`%bd!JOm@Axx{0Cd#JvV#BD#k^Ujlo$Nwk6%Bh zaqj)YXt$Oa4B-4Z!fS7itqsUGU-Bn5V)euQlT@C@vd*nxNxz$*2HJU0?Z6nn0@xHz z0+DA9xlj;R@4FqqI2(jMjL59+FfU(RJYCO=lS z3N0pwpZ{vjV79M=bRdSQNTEjAgQm)No!tJ$A1m{k7yJuchfj$iM2T(oqhU9TiZTl< z)b6zIwT~pkVPpRI6~MI{65CQa;B6f@%uAL?A`!zi@)GxTE({}BFry1qu((&0VGB!F z^5xadYnch#^9M+hyYIQy2`(R?7xCWmvu9S!WQ~N@goksPFW+i)%v-uf`it0^jkU;` zySkPgP6rRD#80l;Si80=%jDxvWTslVeP6ZUDw5aL(m8}^Mf!t3v~SNPHH1SD-w5lv z?*)(j1LKUEKyG($d#L1B-YJngAnQ*Eb%&yu@8VLWPzp&B&b_mb{o#`}p{|#~xOP7Q zhdG(^*h;vlotR?qj*2uO<%8&=db;&mZM_qKQE2&_mg!*F@wtKloS$yr);42Rn^S7) z%BQFQ)$Mi~P0ZAB(liM_kf}9qrXriqx3{h-T6494K=ZwWp9Ze0>GtyU)|QsN3pe3X z?M>x$#E~W+FK>UAc*`7mk4HYOTz>UB15&PugeYZywQ0{IXXn@t2`VYalf{~k648Gg z+B-X6XO-n45J<4L**@!NMZ;@@{!@efW0C!TM5%)e>!y`zlBoYT+`zWv{g__g;26lmOg-C{oDqp`V8|FJ@_Z_P)F^cf?0DmOB$L9OO?6R~&? zJ;Up9w(8lwtJ=QuwFx%BWpRFWMj!tTQWpQ0mJ)ePGGZy5#jDYj?r%-Fh@!TtYHW_z z1W1%SI+99r=I8q%YXyc}6@oY9Xgt-uLIf06=fa@D{+;=!v*yDr-Y25t6B*ez{lkQ$ z`w5annHCp-r2LOJ?QMh#^50QfVy|;&GLsB-7k0|ERJjDtkNPo?1eH=ftkf5p;=N*9 zxA2imZ$5yk;I$XNJE1o-;zNKT(_^CZo$&NAo6nKQ<$41q>*R$DN^qF9lGHt(Dp)>9 zR-ViH7^CBZGW~#JI|i-Bf$cICM-}9OTUw6yV9*m?RVl zWBgKY82fZ~lL;#oBnW+1~EjePRB;P zQbhj`e0hVD^ef9xXdncux8t1#h|%jfB#*IeH;j>OIZ715Rz}Vu2B@bRWw<>QN9d2# zSD+on>W_K`2WZs(bU9*W-HZ`}7`4$Hn1Ui1V7Nsv1@cXR2?hxCwi`r+GkxADbeCzo z;rjGkOQhUie+TTc%r10 z-^D)~Ha2RRNhPJmd?27MVf}*2GE-FHjZZo9RYaGIVk!ruE{m1BOt^DM&a7`bk2xq!NQBH^o zi7cuWD_L=z6}cVywU$kq1>qYYvSz}(ES=Q*&K4h&h%l3>X_J)hAO6LR9 z=(ujXr=Dq1EkcBe(`;9}cMH#2D_!fM?#9KK7dkQQB(Up0iNqQH;bD5sWpHfcc47TF z+wYtmpIMJp=GTKoFAuxq>DklkKaAHgHHPwXKDL)M<++ruOKm}_rCA-y<7#JbXpcme zdwY7-6Qka;PWgoMY8sV~?k&mh`B(iCbVqnM&(l;}D-6R6>FPKj2`y) zFR3wLlg5ZwwQldM6r0bh+c5(PK3IQnjKIyP^~Q5@!CEQb!trNKO`jEhx97|e2B@IJ zqpn+~_h3g;7N19$lILb{`IyvgXSZGp%B zEi$mm5JoM>^+{lmeWmOjGh2C>CgA)axA;(x$5425`?xhcyf649giQl(c3Y@Sm(R-B zdHBJ-+~&3c&?rolXbYW9I7%}KD^^ZJSgNZ-zq(&+9vxW$rcUqsi{W8u90>r{UL`( zM+(CFL*<|*AJ8E}Tk&fPtoU9y&m}J>^*}r*id))+I8Fqkmy{#SpSE#aO3z=RV=Cjw zIUZz-GFWM7gj`U3GFzw8jc3YMs|-QSZ7t? z<6rf7LZ8F-;1-#mb~dwQ*x)o#a&sXJ?Z#O!Dma`24mqh$viR|IQ$I|5K7zT0&Gd;T0AK?_ z2lI8&GC9gKmrkISd;7`iOpsggq-qqr%Chjk%V!lX=W%OQ{M=m%TsqO2_h{*TBBn7} z`o0&_%Vvg}72?=ppsPQ->$YvnP~sJS<%w}fq;(BNVM-MjbsPlaLMEH0_J_r1fCrxW zmL5bq!Zzz`NCCEO$$5DPX=C9GCS6C*H?p#_GBgDIx3MK$gi*=K$*pU4B?dDb?{2NC zagP7P16f#El>u07ubOnb)J~Nzeo`)$USD%pSEY=edBjEcolm0 zj=-N_s|3O8;@!hg7T^Ad;ul-NGIMA+L~j^`Il#>@!N>M|19R9Gq>1;&?mE(4>NrpE zzF|YE2GP+CtZh8L84BexU?GqAJofx=zUi62Iqo_Jd_a(WKYNfm5i>)$c5xxL*#_&n z)|^?q!qv@rjr<0BV?&YsoTMjk!}ZmhR%XeG<8>0oO~X|ZWzT|HQ&wjG(#_SiJ7({_ z8NmEH?)RwCj4hYx`MTQT1Y}?7e{Cfh9rY%KggL}xZUN}<-?0s@Kz3zk=)Jtar3o<& z4xa~->zEt_8gk;}E`r6XNc>4NHRh5b&6f=XE*7Pe{1gwbLY@qol3;v80rI3U6C$Ue z7W!2Cl>Ac6WdD3rr@r1;%+5R4UOOK{GlwEi{P)+@)b)rtK399u8v7UlZBeaVJq7l^ z)D(IQwG=R?2t{68ZKu9AZWAidAUn7Hw@BGn+o3G==f^L;< zHA^kFR*k9a?JMh-%X=r4Euo~|XUW@3PBOdlud^>3k7queiwD17JGt5~p@Mh8-YjWv zndXXI(Q>2nsm972{5&UKcXt~W+HcR4C$cLSwukP(pG?7FBr$^kuIeR@>>-Y;^D;`f zjFaH)&y1!uI{=G&5R9*PKWZ-E1hg=9zX8Wek7gi5iV6LJQ=!~-J+?bWtD&qF?ForW z#S((67`)6JcxF^gXaS{w2>k64-0_7lHhW#6XM=FBLs3jundee;SOEt9jV{{3VkqGy z^yLor?pKRgma5*rsj%YJ$YU}XyUcmg8>?ap28T1Mb~0}L|! zey`64EX|I)!{eyfKl9+NKjUNs?BLtk`m@xa+-pVTS$s*iOauB}(1e-b7ZmRh=C}z0 zLzLk_CE!fx)c9UP>xFhC$1PpFB3PWq~vJwMRe~q%3$0i#X4&o`o}-p z;-jXTY;9#_qACYb$ou;wj)t)qgvKHU7gy8Meye(Ilfry1QZmq$2)@!3b{@ zgxq<<-XltuLhQg>zk_a8OvT6>RZLwhCcYP&)p8qF4zw((J9r0sIdrfm3ncP__`BnDxKr%RXj7JMClJ1YZ*-0P=HI);Gb@!(`@y zENL6y(LAxOYV*3?6vye8G{PZX?D}D`p(3DV-w&WZuOIshabvJb{$NK^zohHAn4`*7@67KVFxjobsSDmJHEZL)P7YQs!kK5lLy1JO?=PU4)40nX` z`lk`3e8Q~!8BA>>c8+O@`hz^oy}p-F6wJ!zVA6T^ww>VPDqcp13B9rqaumu0mt(I9 zCW>C5G^-SguT;XfMkzr*JZRFfcu-&Bn zPh%!h>&5Kz_*u(K<105xc~V41Z>ic2L%M~_Oif>~?8%>^20&a}NNaGMK99L-P9_y} z{ZZYy#6TUFGoupkw*K3chZrL%JUDm>O$bL~bX{x3V*WimP}j|N=9_eUX!=p)CE}&Q zHt~evxkY^XJ}FU2|NNFY3yI*{5oJyF6RZxpuh^)o?nBGBuVvj-3{m!Rd(vx#9+lNG z4#j_FjEuB3qC|ir!k)$y$KLPQiQDAc^kVkikYGEAzaXdjBPT+RY-7W+IFP*hw{~vv zsBNW5wP{(oSg=jodhFq)rc8Pv{&V_3fC5Q~%PKih>42wfzWBZF z`@I6=fqN9dHk`rZwD&KR%=czWg3RYe5o%DQ8r1$+qBHJ%fALS=d+WX1s>9$4Ffl!U zJv$e0-1*CJ;KnrbsK)JKg7jVz1Bs1jIt0FpF!r&#>j@(pHe1}aKjzkc8EyOvU;Z(- z${Su~__~2}IaZ-mB`ZOGb^uQd@18Vpc0RU@N_d%%oT!r{rHXRq1X9GyZ1f4vX6+|VfBZVza~!sv%s4LK zeIx;K5JvSFY&sf2H>so=KZWQxt{yr^lky)a?fX34wJ^2kD>SbtNCQmCI>z+W)Sl0A zCD!aur}J|QH`T*nLLqhyoGcTe#!>hnczO`3kcni93?u6NYsRWu!=x-?iz#w=hw z5J7~jDUOmqp#~fQ*Yvj^pkL|^C!ma=B6_+HGMDeDm{L>T+4sTpU*EA>BZE|x%Bb}D zyT1jDFGX|K`OLAMr`aTnQQ^=f>dWUT=Z5K}3M%+jPsuTm#$8&)@4LzGBc*Z>QKfFJ z=KT$#WCjN(X6*-%|7*&(D&zYkDLpd%+qVQ!vOjt0fbWWuqJUiJQ&PpA$_)Y*TTFrt2}QrN)}zS<;6RhiqWOu=|BEZpMUI|2Zf*{i36 zR1=+-f?QdHC=HcUW?LFe77W}^OIos=a zfBe(R=ikw%?7-S&a&xllR+1rxZER{vVKhTz%9^ONL+Eig6^PY-reZa4dpyP5F~DLG zcaAGADXkHJ?~R4aYgpUAOVvzSx&Gp?^np+G5Z9q@Ev4vSXI%VXztGZjq*R3{(-jk( z_JI;-qL?e?-g|@D3?yz?G*#`oiVW-Mdp9Wfl*g5Tpyn})Yb6| z2<)RMbC7>C6|5Dr^wYwC)Q>HO^ze`h0(Ud_1-F(JX&7 zkzOvv42Zpq#18MdwgidC{}XtenZC~BXdJN_Yiy1VsoO@TihSrepdcm)BBjec))k`P0{dHc|1=F4Y}RKcU`zCKxS zP#wc19|_j|laCr<3F*=IQ=rfCIO`@(h5|q4m=IOG3|Ngxikno4r}%#ub+)UPgmjDW z&^W1WmXvA`A|qn@+p@pmI$Q6UYU(Q%-;;Z1D@R_VXxopEPCxPxXupsmFHUmXN&gCL zs>Q-EC&^-~G0>ulfs|;*c$oxFNb9pUHfPS+bt|njWd0xo`{flwaIZ*Y)a#3Mm zYiiaW@?i=H4LCrMJw-bI@lVsU&JfRXGdr@iv5N{x8}2Bf;rOqae_vR|LWP4sOhqCj zSbD4z)$f-|Yr@@>FUs^w8%vJUc`P(FH8Z+Obg#bze_~0__{hRjs{;odGCFYAt%2mJ zscL|6r04tO(j@i#Tj}F3rByN>^52mXjRb2ov^Q6u@PFtYjPjAKeh3t(5WAjwB}DTu z{F!}wINx^(DTeJHA?~T+l@J*JX(lLw`#VAi1D@9g!gB4*D_q*Jcv-KdPML0>OLz=+ zFgUP%b(wGF!uMsU6>`3=@x$YMJ%H1=_3zOfs=17Or_fJ|!bPrX)`&oR==UrVcB#q`462H%;f%ftvCH6hrvBp0C5Dsw zyKJc67vL9gL=G-8%?M{MQ~&zSbV}?KYZb5@?HArZAbJc*icHc*Co6ZS-j+a_*!f~q z$Zw}rWEW1Hw70`E%2`6X>?%h~-mB^PBF+=+d@pO%!W9k1I7g)|jun=Z{7I@w7FUK= zK7YNQ2YTjvhL&F?!m6IrRlGfX6qRNwXs#!OBHw%%T95y`UtEy5Bk(G5_{i>X_CxDI z-|QW0(O4MV^>R|<-R>3jUB`vPOFMM|@AgTPjjMS>%e3CC=OJYl8e16DJ43^3^)#HR zeY10fHh1 z&*!O}1}%r~RQzp-V_+Htka@G2+m5swvsgr$LSZsD)Y`o0Jt8DGCduLS$+xUr?acrP z1*kO;Zb7tusD_|tH@`~I3tw9!NaXSFfmbA-^kLFC`)_a`NA)tjf-Ddsl2N1C_ZHml z6`In~x5sr!v6cfny%p3vxlZiT;={o}CL5Wvgd~;H$yet{q7#bYlcuY&Aky#bj>!5! z%X)`GFh4SwGsAZ74&A#}-);w+6JjL4o>sezkRZ2P(i+(t=c&B-vOGK6ckx)#cD0|D_d=$**bMtJN_OAvkdVs~Fa>^Rmt_h#_y#fAJIzhm6z~B=wj#>Q}866e8 ztiMp>NF5wG?DS6vw`>&igCENz&;$GpAb^>#(pX{K7>Y8Z!CG3EnVt@_bxo9^@+qMB z?w4hA=H7w?TEPYJVp218DoXlUM$y_>4KAyo(ZT}Y!hKUB_PtETl7;{iHLCopHYBCf z#~%tJr(2$W^R;xN>YtkJvEJ}@&*zr&+n%1}aBB!VLk~9r!f)h73Wk^q&X89qIRpm-;@$Lr7?lGqSIFpCca)i+D_XtgWib zR?UNSCj_sPYn#SdFnFddcj=hS!3ER2(+bH0x4Wi|Q`I3dGBSBxnnm4)iFuyqmzYcT zwHhT)r?E{k0WZn<*{w%cwV{Zk`gL5QL@_Dk&C>%hPnBENi{zIp-)@$E!$Po-zs6tR z+Z-G~?~SY|G<3)dDFt2Y-U>(ROA6SOz(qZ;B^*pl%+1#~Vdh{-9o;oEHNtHxds5-o z2_fQHtihe{QfZTAp7PigUi+(}k-CO*ec;h4QPC&Un=&**FA;1xfDwxjAfE_1K7ILI zD#X$3H}?ueE5^(~@0q1Bpe})ygG5(`ES{;;sXh3|#yFB>o(8oGv(XEb3l=(ZhFGZ&uatZ+P-wnQB*Cmuy73mAZC7njA>p zpC(Akm8_^tu34%uD9(5Nn_**{$CY0Mugh+$(XRtPyFY3M7AV&ixBz}onqy~Wnepj8 z>M09yz|rVV^4ev9UiUGJ>HMVoDDaN0te@YzOvvL3340%pKm%*jK}=#3QVqcCPY}CA z64>mxex$}rZ?AX_DW*Y|RRn@a7I5Ak`)c#W`Ks_qMmnMtG?cwEp55e1Yuf?XFQg$? z1=5}?Lh#o-{GP8>{~WYUfF{gr9|L&H!Tmg{LU`u4|iOM zI(fKR_WaMUy)1ar_ly{p^l~Tqvg3Pm^1So_EdGE)_67UK zBW#E7ol1O5Re;Fz?Ci|pi?Vu7c^DK)QNEBShOBwy^yM!7#pZ53QuI#6*S0}zznBA= z1x>@Y7%zccH>p6Ct8z?QJ{%&nrEONDDqQnV%J5Zww5la`20G_yl13IAmUbKgPvsLG z`?pR&YnXGp!FWb`fnsHP4xo5cgipR~4XRC_}xY_!Jsom?=C*|u6#5)eR%i9~F-*_nO z*z~lrY?Izz{$;@dE4A(td=~bP5{ol}d_)g6mqKjrNoz{!TIE$(Ww+kF{06t?#extY(JkAs%sklS`=UDYseV|A1-kDiUwN)VzQ(5ABqZj6%Rb z=mMdo7FGR;G-AeQSWC^AV%pf$k8Y68G@k#;10{*>oY_Xb>2Y_0}T+1iExd zG3LvC^DIr}a?H@`!w>4^^SR%~1yn>5tJ_|s$~0-WQ+);g{Yifkrlmqpn3n*vAT^QMoeC-EIyYW0R>oxQv}lLLoyas<*+KP;RW=wG43`a-Py21%arIV|V1hXfy)#`IrbWL}Qx%1$J07KOvZf?ONC+R49li7LpZG zbb*!RRZ|8Wvwr0M9FN&u{IxO|d3rvz<(kh!b!5%)uH|+W^C-HC7k^|#aprHb(3W>) zuZ0Zm`=60!XAq*nYMl?G;}%(-$A1X;)M#IZN1uFsj%Iu}0Q}2PAg+(qnU}}Q(~8T9 zu*2V!BH(QI(^ObmC*(AEg&HU7t+=;+g+#Bz{Oj9_`ifj<>^JMB%{!w^*^1~B~l zQNPEi&6r%bas%`9|)JG^p|I%rl45)d3sPbalG0`RcFn)yKBy?d76WBb6s zz(%a-a|mA(ZH&oha))VHNU@>Cw`v$QEoodhz0(f{Okz$nMnc69jE_r3_%uWxw(8px zAi?cjvcji!!B!QbL_XPv;f zWY5<>9^4)5#H@@GUL(+-7%y+?G;FP7Xn3nt9&uRQ&@-X?sw{7O_v2DL3RmI(B!hco~5pxq*5Be4`H$tXdusXTr?E5%NtrVq#HGVkMk4c=> z`0Yh^J1HmH^7E7EWA*2i87t2Z-f)L+n;^6xBE=GC zNkaX9a@_QkcAGx_d?P2M*o+PE=`G;*xzW%cl1$#)^MFWC-(MfDuV2bmPjQx9>TX%P zH1Q_mJdi($%>4CX=CCV1reJlp=PW4^bus&`lWp^khVnY&2L$h|CM#dv4PkQ_XLxWg zSa+e;hOQ;V_A7h9>3l+0cnRQ=<;!;U^w%9N)o%vG*^6n^HTd(nkVRXEm*-bcJ}1D2 z666QGNr7nHB0zvNF);zu?+$>nU{4;lPQ@8?>AiP8#f24JE-$xo6AnS^pg{vNw(R=D zD;`HzI}2D7P1~RrAH*9a+*Qu!)4lh&FS`1Zl=qu`IUjpwH50o} zf$cr&0yAgq0g!$PSPxSkfuw2uxDul`SA4ew94L${cv5`QvjgeKA@Y}O))it2Y&%^c zeHb}}m|}=C@-nnZaZdIxlkA8^R7_9DF*?kYjG;0cot`*X4PT1t_5SKm*?)UzBb5D{ zERngLQ;r3)e6v{$8ni40_xBIE~y>{6j1HG5>JKJx-q)ex30>=mnsE;uK#hv#>(UH zzC6D|v-UmPr*2HnlA2zD8S3oUYlj{W>mzax;i6uf%e4S)ZD(7*R(GBcm=e4dy`EUS z)+ri3ZmR&uBnK^_Etg&E$%aOOOrJx@2X~}REM1+K^6S&(D@BC_c>Slp@ud_^Q5xK@ z^MtA#B33aGLrnnx? zo<+9aMiLMZ9M8`lFWZ(%)ot}v1MmX-+67zQkE15J0q(0L-$4tnniiE#D4vw%H{5$J zqN)w;e!1|VxlUS(F4^J(&9NJA&M^j(qxwC58>9`iD&mLRY8@hzGCebsv@>P%Ueb{m zb)KCCL*UMw5Q2;$DkhCBrACmeVO3DI5-h1J%p(kQDIY&J?a3v~0wZ!UnY@cD&tbXK z*9#*YQ;NkfG(?g_C^^BEjf&8wLkyfI6egfy5ZK$ypeQE@I=mscBdLA<*lWmX_vQ zH8eFH(yNSSi;D8`0W(29US7TZ7~Kwu;|u}#_tA?AHs^!Z$o_sgNg?2!eLcOw%be=m z@ZRX5Ww}MDPiM_JNZ>?24l39SJ8DrE0*=$-cbh<;7IN6)-Z!iZ9=OQJFVJGI?c zfemZ7N|ij7TR`vQWD}_aCktMi-L-`2jU=pf8hF%=k=!kxc<*#|O$PI%0(2O+-G(={ z6oTh>)xi@?qn3&CR{4zi(k$F6sB#r}atYGrb7j>n@#a#5ngwFIU~avJ?^&-ylUWF% z7Vb99+E|h0XOude$l~eg=S`6srHHe(8M zM7)qj*PkqWk3R<*vmVcT18xDux-tytl&XWlnrSkV>cs|FBN^BOtfNtvA zw^=U4Z~$?GOrYCazp2E+=rH1xPI-b{GtG3XJ|p4#+Sh)Krglca^F#0r+u)DkEBjhO z3dWM&24q2^AvPEYJhGumBcPW8_Jf3L@zZ`PmqSG{4=-3GAi)z$bny~3=kDQ`rppD< z)2%Cc(g3yvQk;-Le=1T0P}2C)3v_@BtJaBgXk17^osN#N{Z~@2jv%(m@AnGrAPF=( zxWY|%6dk=T8WLlqVT;rK&{3~FrR}9N_wTLpz48inl+UF&f2UY5NN4_r&2L+oX#}EWze@iov9RW-}!g){3@%g@G-69QPt3a;Pjf8x}p2-VuB(l6$E2YH9Zk|g}X7e(Md#or$Bs4{V zQT>M{yAxBsMaRySr$*nK5y6vhb3HZPGvy||_RUw*K!UqXiKc_g>!xwV8-P``K3|n` zCd*Ij%=iyn=rLcZyzGfi>9n4BpExH8n&SklF37YxU!7j>9&b>;+_pZ|zFY&VT@jzh zTL2>Tat8Fq$bQ+k;n{UZH4Dla{AaqYSGq^84}i(?v5QG$jV$x{^}yCSP#Xc)t|b5{ zQdu6Liv!wXpUvOYPrICt9h{2*c&+uEwe`H4)938Q=i~-xc*A|qRi49H;keWQAmR3` z5%^{q-%FX&C#+U`E=yYBBDDbOu4t9#wLlf&>)G<9i4*TpH72UhubEC6Coii}|h zQenPv{}3nHx9@&+oBezc6-f3+=;S?efeF^?es?l_BsGg+U2sWC+shJg**%^rU7n#NMYG zc6lgz!69Sf;@6L6)^t@3V46HtVssB^kF!a8JLUaZB}7dAwaiy;5-sDT^RXQdn+I1# z>S9P7JDITCwZCooLzhgphpXW$+}r}9+z}ezZEQY2qe4wZB_~?)D9#Qi@GSG^`>(ha_D>i$Rwvodajvc zV^SRs?Z0X6$jj=oCgef;SLa~7U6e`$f9rn|NVv<~iZAu>XGUL(6e~nuPxDJQ8r>yq zviw|p7KHp=9Q`qZH<%eOUNfEkb=eZJW(kf5JNgyBMzEYMBgvc&re65q1Nlbtr0Ht3 z{MV~SL=%{+G6Gg?g84t--a|re8JnjW@NAJ(UR31KOiPZIrbKe)u<8a_m znr3UaIEPCDQY-_ZhtrZwXJ`=LveWvPm79^Ke=l1feI1X7`dL;tP39z)@olDM^|6tlxwBl;X|J zZLKjt#s1yqI~^TXtmg}*f)Y!|{gwGE-yX{M`ri_2!J`yPlg#_)c!0%}vMb7G3pY=h z7(Pa~pdNjAtm4~BM{M;q?2vGwL1JY`bmpv7z=@$|ry3BkQry*Cr19?255j-}PYU(F}dM zBqNIHUTc6up1rAum3K<9KAr=ij7Tg+cRLGXcZ5BZ>VBe-bK|FI*q;yAZ2-)|E;mJX zIoc45g*h5{vT#A!>sHbZ+#AIAsQb)mm5F0-GTb z&yzKczJ&pJXkl>PKZabN0WS|{DZr#;AC8U|8g(5Sv5T14}^rhNwQ89?276`G_zN<;8(1mV~$w+^)Dnb zBO%DYARAjS(3Y1x-FC9$U#f)VWl2?IKG9G4S%`)plev`Y(>V`ugdVvKCLHtkg#_d2%!bT#27d9PH$)2wrDqdgd>#iR7Hw*-jYFR-jH2?1kc}nrkm&To*ziL@yEpw!p z_hZD$FrzD2unVZXRj0AxElqig+f59e!&6^);7yB9_VKmv8c%HYzN*EOwL{vUUATyE z0x$&EEOrg$8=iK3pSxAUHpBWkg+u2R6d7q%lAF@1&%a@=|LEULmG@%w;h#R7+VUr& zRkAhk?YsaYo@aB`$%B2psywi;y=!T$sX+k&CqDqm9)eM8ir|;TjTQi`Z>x0RKxnH( zvuI>^_{yU>Kg;7k+1oKPrPV0qkn2)aFue(Fn;n`2#DeeOI=+Y&Q-||z4=xwJ;aWVX4x&DpZ#Ecg&D=dKPT~E@WnaNOnrG;RoG7Ks= zQN=r7clC$7<$RLo;Apud{i_N5t+}x=Tg-3Mf1IBvlvDFGe88{WpUD`?%moLpm0ASe zbYp(hP1QG4?A4+F!eylpF^4ORf-)%KXC_Ujk`p^nnoLG;<;{I;EW*P$|0G^1sg@tac9QT)VD z_{gRCS}}(s0;TNnOz*WBL0t0a(qjc-#(4tc1qS@iBE?B=hs$4|Ts+-QvRN=nG!6z+ zfBrUsZPXsJV2vtM0!M1srGWF33pzNWFPC)cs`y}Yuw;=PA~Amu6S}cc35dQdvOS&l z`k8!Q1dp36PrDb3-#T${3{i%q~#9UHxFG_E`%#x%z^kcnZbV)ld**dk(q2|X?`0Ab6BoqjZl{&0W8NO_>SDd0U!or!K8+X8hdrK|zIc5D z7<%9PakL$QsGoJ%mD(5W?X`0IaM$@6cXVqCchHbF6}ynsH$5SF$(kgI#8RU=)L0Ul zs>{^UaPxRlO#12(?i#3}_FX-bGe?}u8wh#uk76lV_`7*o@KBf-B0HJ_1aa8^65(7( z?w3%22%bMjRa_TVL6E0HA0oDVl2uBehI`h<`!Ls3TS4j-;0yWUFlM}pG+2Plih%F4*N;E)g+iki78VGrz`?)_PCA8gr`2RV=Ei(a zCbDoQHD(JG2jlYg6)nMiSj!nsdJG5}X;u!4z6G;pg9S680^{*vC$^~9f3d2y)t zcORB{Mn#h81E-}~PseVwh_!cP_r8_2G>~EDum}5SMaU}vlKa4J9wrq&zG>@ZLs!=T zZ0rYga53ME&QVNKR?Xp^k5&n(Ngwo=7sG4a>3LIaMpX#)0=%SLAZF`U;|-}T8yt>< zLIcajdaowHqiKvn$QGCXhukR2;Bn|AbwIT4Wwl)MCbtbkK0zLh7I9Aj-H33}_3?;L z&o_SunH4iqWtvLpsq3S{XXWmk@qh0(b&n{>ux5?kM+vRy>K`1RZv92VF`=U<{M51& zjry|?nZhuKwHo8Cmg`5~RU0I#^e`m9PLOS8{;+|+_#X$gq5IPH1!DVhNBQ?vTa>xg z$_Z5~)B@;Aa7=Ua6bYJ27kWAnSTO+^U*MP*gh`7ahIZ{eW4{?sxhy* zb?xErC*Fl0zB1vZ6C@sIvxR(u-Kpng6>cXy;e}k15n-Cq}CH3RYxNNhU zpre;N|6<)DH2JL+%G~~xPW5s@&q!VB?DqWEo&`>!hsSu6P#~w}J^E%EiZK|57`5bz z=L0v~21c$AC#^5QW@wIx(z;q_B;Uf$?r5_=(Vp*Is1y>R>(G1!G@CAP2y9YD)hPj=Ou2<2VYJ+W@fzK-=v*9j+{j0?&gG21+af^{SRgVd>{lr z097hO<-Un&aN8jxdOx;u8@+P7wDPnBeBxHkqUMGTM?0;-zFZ1T@78Mv-?bHhkR0l> z-t6o9a@c41?_CnIJYk9%p?{nNcP=5~Y#c*m7!q4vRBqo}KV*#A+=2$9pX87f)=#y? zTOkC0>_tbhgC#UrUW>&+*zv-Khx@lg+;d=1wv6^Tm$^I}jz&G6K}=8_G_1hLZw|e^ zQmS->PNED&Vr{1Fcfn8)M9hd^?Pqrb2>xF8pCO(*Ee}Qabb{Nr~J!dWkbj;-&m4&`kuB-x}!h=TzN@59QC z!{e}YQ1Fqm5Y4+GX!IT}KYP9`94?P6*RyiFvtD|h4tFfM4M3e1^=)S!^N8?XyN5KC!(o2jbph!$;a>$@xM_oa3^68t_^)ZOD#L$Wx`_u?`^}ftK)gUm8lbmEpvxPz z6{922A-Di{@fA5p1x(Zy^b0J6V%$fH#f^w2y@>R>RcMrFB?{w4R3@qIT3sCyi#?D- zBu^v1`3t|Ss|}_7@zBMM!no=h4U;sG=o;t}6;vlt;iJ%dfY39kP56F#}bVet!FB4QJAxws&(<3S`4< zs`R{8zMA0L^LW4+Dt>n{>UG_YxibpWzHhS-ad&swNSRsj9*pKQsND$heJJ&P?sgs> z8XBf(IA%1ofm3Dw%@D4=j9+=^;(U4VrAEFIG;q5iKlZ%1;-eHlq{r9sJz{muk}(Tel|)5n)H~)Z9bP7^4HdMBH&iTp z?(VU^(o7!v0qM5M)Xa${Xe7dsZ$&Rb0==8IpRtudL&arWwc8fZf1|V))hG`G5awUB zv>Zi#D6<3psw)rS9ox-^=fgub9!_@lEq4(Sk(MKu&4vbh*nCOVmxzNOmG;43U4OE& zvc7rq2B;)rfZ;9$0BNyba~frdFm`dN)-P32Q5hW`ZjSNj+i~X|ijJXssr7le8R5`dep`EBU7Ma> zwQw>yP_D#nSMlpz#33e~Sm2Ox;yhx&YdTEuPaiD_)4j4KD?DAt*ChVGMRW{7%xGbJ zd;__Vb^fgM^shhEj@jzmvjPV`%p&12$O-W9FmyU`A3i-%-`b1wlp70_uA#GgYWs8;5H+Ua;&;l#$RmX%a~S3;$lML>yl<$9p> z+oa`0_-UwYP7k-^^!|-Z%jNDyYAM^|w{-}?6-u*^%5Mk?*u;dO*{61C9w7c>{SMwL zN-lWE%R3O&@GqDng6#&D57)LTIaz217(v25tFLrxis2)etl+#L2|>#b=tgnD7sQO* zF&{^VQli+gUU@?0XrIcE4nG_ap|?TNi2~At!^TEa_>@I10#wEIN1eYbq8kweQ58c6m)}^ zz&)Ycb6jP4krE);QDTYu5lRFB`&=-@aFAvY?&k-gQAo`6bX)OQ{bTTS^>X{_UgT#8#_ z&(v-!mxtr~s8l{qRXUze&)%}ydhqzMY>!PjqV_L*D~4m&jZ04#CQnmS)`z87i4#Sc z)cj2ommwYhBw^R(k)N-VBpIUq^!A=ly*HbD4(|zeCQg-bzIaY=wo18YR7ec3b25FW zGc=)`9gN>s^}f@2LPm@>BQ50sx&BI9e(vC^=8|Rj`lm}{py$t+8!X)fV@X0Jf8G7e z*`EFVzdYVm(=pM}^;DKW{s0-8^=_Su>DuMbgxwdTqS^Fv0022V8$M%`EMGqpx%dZ+ zO|1TxIG>Dh`TQ{&V^4{pDF}M60b)_&UGG=2-7&mSC&rj4~=K;QqL6soWV^ zak*Jq`8rA-9JdnYgIdP?;Cs0{mY?l0aKtZ{AapiW+OpO1AT&By@tD425EWo(_M1lp z$}Z)fbUqG*&i{qQVR9FYbFzoJ|mWchv0LR^En@C)9$;T7NfRoY?~_&fqd-xB0NI^ zGn6Yg^_=<$;H56AIUe4jM0HJ!^!bL-zIzQZX_{Z%LV*q=_T-FD#Le6AzQEB zX_{uq=jO{^neW-fXtt31WAw^h=Eg+-VM+MQjlq*O{GHQ+UGy(~0bi@PVjmh!)^T4} z6Zw`MpDr&&c;W$DbIi$Hl{hmm_!k9)qQ_%8o9u6z9Gjwg>Glm1MwT> zWb2WUl20tCA)Pb0DBhC61-09BRj}dp=X$FQGs==pTtt2>!^k;!$w$WN( zys#Qs#hB|~8Fe)TT0AK%ZY`i5T zjY>1WAiQ0m_(y#B3YX_gTud+%Y|^&ah&d@imo#(H*v$?$9ph6A&&b|!uh&BX^>(%Z z;^F6~2iD{P3(O5reZ19S9QE(FGti*&w-)Wyq%(*-+QxPR*xV1}o`>C-Y81eUj6UK0w2oa=Qr}Qt>EXU@s?V{LSeJOh^xrG- zEV>xb1uK?(boq!>S~#z#R2U1|I^Bfup=S$O@fC+b%cQlP5Rj<`R#od)ZcQ8{BH?I zwN3351;drZn$rp_{KoQ0y<{VjY3nC?_>6U~-f*;dA&^u2rF_t(V^c?yg8x<_Dc_5( z9m(dv2Kp)Ny)_t7x|hz}NmUcyaXlq4;E?#`w)5(KWv-dCFSJOa2hvu~C86yxVJE7} znLJaPv45kxDNpX{i73j5}Op6%2tiekifpDDY;4CIoUxaB!1Rs@b1E(yOy=)LpRQYA>4(z zw6mc>X;7y#N(^6IcJHm0dCfFUuDT5Zkp!A_QU@_&kl~g);+PI12b-=mJuSr-;@LCO zMa}B|ec<9mp#O{EImj=4B6k-`|FNBRJfVLu~lg3ndQl6coG=#01V;UuJYx{lF&Ma5KCRC$hLJ>d zH3+Dwt1103{NmPc4wd#xA@wh&m6SB5?8Zp1uE`=UV=x3ulvQIH8mK3jGzztx^^mvj zc(yQMeGKiqFU-C##PvB1{Ex5nU)kBY15`Cx? zeQ3w^0fUOGMeh@E@eRlLOfZi3jn`i~RqPGAywFm$R z3W{Er$1VYJ;WDY0&+^{K&e^X(GR%%zd3Ja|KQ~R*7|#MXw@0-r&%o5HMh7nayBwYb zfn}tp*S|bJv>r6J8~}}}e8Og`?_KJDqR*+PXgc<;%iY^x^+8~5`vR3`=$TB? zaD+UH87FK410w}s*)VG0ryDB7{ZzBH*5;}tgrfHk_2_IdGp5M*vzN=j2-;e!`=JhDNfy@@&me)` z+y||?>%*Wq?4NN%y`5)X*`kltu}#nI19x{e@D9zy?rL>P?yvk59VydIZ~rVDA-3J# z-d;0olAYCcS2^m&+7P`l&f4L~_UQ)4hoJ=e51vH79T^D<)6zM`6B3i;9fJCy&;vFF ztS(tBq~bIMGZNQXSEEhyKDL3RIc~B`Au&@LG(T^oH*y4sw6c9{pny|!3NG%CpjEup znYV6n(;yWd@VH3GeT_0>plMtfJ_#w3AJ08I2+Pl=8r=}L&4(2f(7I^^VwoC4jQr#8 zLrae;BjlTA!--+z6E%?d^)93{^e^V%V5U8j9Nz0o-oHoHlSJa+WCmBZ@+tpPIu&gN zL^IXD(pzPQ83I)|A;qodn{SBG<;0pbS|X$frLXjAAD$Kob5vPa;MWaNNiXS8;%Hd@kQ9wliq@R8k9uET;CkN$tG{gdhx*v0-NE<|uNI1I zKC6YrTkp*-Q_A2{Ebz$n+IyOSyPn#AVQ^Do&3H7obbG+Yk8WCSXD8CpgVWQpDI1S! zDArRH`R?V4qZv(-6LiQ;6l;0n##gF6Ex;bqZQYTW0By%L)E%Zd>SWW8fwWg}j)+`_ ztA*alb-D1w@x~)7TU#CzJ3$Wlv*6ur+WtX7vrg0y)rZ>CNee1L_12r7ui4q(zpm}8 z-oANFR55i-r0I_p1_u!$ipiSPV8@AJ$muq+SG>tzCvw6xv|;$l8e2K^jZ(|zC>WEN z;(n^ycqu}yXbOi)NUL-vkY?AlQ9A|x-_0e%%#@3k|B=~1JLlr`c7*PXkBdjE1X`$s z<6z8=dkjLxPJJg)UEnvKrr_XUAV-B7D}_2Qh9KJ}QU;Q1qY>j$|8b+!9IcnHNak1B z!PpSyO_=pgYCAX!)|8Fo{Tf!Nq&`p~u1wbakEE$=ex5|t$!sajNdFRe-}3~EOY#En zAUcq_DUt@3qG7tNPM$w8x+Jq23m7p{yrrcADasH8Bmbd8L+ICKm=3n$r|9{5SSB-U z&NIl}YcqEp;FRYq`R#O5p24zO$1_IH_pB(kSik;!h=+4?9=xEp1HH3-w;9as@f{%9 zvOc}JS$w*!96eg9AH4LCUQ1RMJ-%_%Fn*g$DvPM6Z8s7XbxU=P`fC1sc!|-vQH6i7 z;+<0F_wD=p`;kmRc=gEBh#mAr9hIQEft4=Pgh9gq!y|}4X+d;Mhp!!(qs9VOHwp-bG%5KL?;P0UVH3j%Jy>Vjro$O zPLOZ}tfi|pw7%?i=oICdB8m+{f>c}Lrmb(%3Gfgt)xUE)!ZM*$7)I}Oi}1wUF(^c$ za#H1y#QkI?bTh4ngBgm{zeE)ovh+(2PVL=gKG6esm#wj}=8H#CR0daH6&Brr+F=a3obGj?RY#+BA8rNn-BYJ%D; z@-+lTD~q0xo#s__O^^Bd$HO%8+HG7f{-OnNZ70ENE{9RLIGH+2YJ-iv?ch+3*k~oD zxqoCfkre(x2P-)=5*3DeofvHi;zSFJZ_ODM@*z2;^ct-^6){s$hO);>x{G#1K}0aQ~l{7C%YV_DOhQ^PwPq8m;{=P!$8I1 z{3qg?@84(sZZpc^OT~kMy*8!5w}LUtss+2yJ0JubyDQz+x0$ci^+50W6Js7+lTI<5oDJQ(>kLU6Q%``Gr21Wpb9N>4@*mq zEj=}E)EK{6d;$n_5*YeHi-n6vcMvi89K^-+2E$#mzq?{-Y@E+b12>RiSA~!4s{j73 z>Zi-l!2Z4I@4SvS#y@1!#+;=dDYJ^774WUN-yejN#y$zr+Bq|Wlev*1KWoBD2Ou#z z4tZ=PLEI1fub*lSn55s3XrTpz7`G?2a+F$^A}#(LKP=Zif|2RYGyQ)B3s>i$K)a3T}vZJ4tB_7J9k1+^4|CLJB z>cdTHo-Dst`*QFgc=X&oVR7<20)U?Ed@-?wuWqSFkHa`J+(i^TJ>8D@eb3UZKe1ph zjjV?J=4r`(&v&27Q8L{l?RxxUez$l;am1qYnEL7ZWU?psNyfk-#2eN`P`f;@Yj;zv z-RM!cB(Shhcg`o`Bci3N0Kj_BJ^>Zjh+uG1XS-n|(_RzR;#DOj2hTUKQ9cJxU&W_f zUNMw5&^8(RFcyuJV%kM6SIY`D^+`+=mzems2SZf^OF8B|LfwzF3Z}JOSyjycEz37yXknWZe7Tw+5-5t^m();^2!vQl49Kd|>KF@t$ z*E$&3dtwRS+KgSSe%wQlwST4waZDa5^e)8d5fg_yRI|c&)wp?j(NBx3o5{~lbkd^> z>B*yYv0RKp7^$9w3l!U+sBRkf$4`KhTw4?!;`^NfjxuCddoQitCvT#v%JE!G8iX{h zYWQHb1X&MEWzky^bh3jhdZ};2Xqo#DRtBVHA^)+Y9wz*J&)3@&gswNcfyA8)0fZt@Ndsn=K&O9Y znsjAW_&&uhVXHo4-yBI8G{W#paneY@9v z)ytWNQ3pOl(Aj*$ea-nLx9!tG_VX+bd_E>Ae6#d%;TBQz#K^z)P)p4uyyz?*jr7Q` z>#C&unF$~mQX~rU>iSBznJklQoO(1{q@PA{glwXJqM~j~i?aRGz#bj!j<_lT&e!m6 z5S*zGiGHdmD{OYLeMWWb^9Nl&9Ob%|APEz4g4*LbdX}IVRSH%9ee*A0@S}WYK8?yp#zaPY zUzw1+&59YcpU>~)G9bgOi8QR79&yZ=j_eIfnbgi$xu!9Ot4JurY|ep&E(!}Jfld5S z9~|{Pk#v-%R(%|roZrkg3`S+LRKV192fw%G1veCGJo8Pz*OQRmwcqD%R3a%At`f`>Rh1i_0#Lv$T>NQ_cDlov8a$UUl(Pfw??Oea+l_-2OwjXXLYuR_Q;uWmsa*^; zoZ%e)&~%p1hUSHgCvyvDKR0)C32<51+S#(7O8=1%*&8{bW)m)$X>~F(SmD&Z6KhF& zhJk{C34MYz0b}-s;-V!`;>o>=$xl&)-@&od#?tVA1cz`r<*4Q@dFYdaq!NagaRM!E ztyK_2upYs|*pp!+e{`OH3cmT>VMePCMRtaPkyD1qJr+nh>@Tkhbf9|SU`{UHRju5- zNEHxlD!8%NmVv%2>@TvBD4iM6SDEcu58U7^k^n{qT~ZL)sy?MphX!2$vvao+tFe7+`l*s++cuK#dl}2UvK^sBo7g90iHQGL}$W{$N$s~3Z~w= zQAc&0C95mXX8>|(!uPI*Mlq`u5H;01GjL=5m)UQ-UvB|8(uazEk3eGhSwm)ZDmGQJ z{rP0#ndEKby!|?fQhgQG$H3Jc2M?V*ZA9 zb=DO_Jk<^yH;^~SoR6czNgh6Ee;mz%eUj{#(6J&6W|?QJRvXrVMeF^D8KwoX&#(%I zVs`6X!EWpwM~CE?<|L>LlTiBmqxFKYL9uA;IWFj+fKG;9>dWD!PGANCJ_a(L^%GSz zzvmHP{z$rEWbvKD;Et!o3PXx1DWM{7m#X;#h4aAmnWDMe;*h6O!cbn1r|G#a6`5k5T>WZC;sqv0@$e*R9_WY$LxzuLULs`ul6= zUwk*{Jk?9p|LOEmntwt=Skc!|kR5wJ#}c8$Q)<6Sqy%g6AreFufRAjY+Ca>ERZxb^ z`L#K;n`R3J?l1hNoxVbP)@pDHs&H4YD1xy359&=3To4-~1_6aI2^rjI0F@Z2A)Y_n z;KLr*M=aRDMGiJYQyFTO~>%!5{G3rdUzDC*d~e zmc0|l`g3B$-&2XO;}i^4W)=XXjL4w4^Ltw?lsXpMc~ktn1vxKig-9tCY;07dNqVt% z62M`wwF2@XLVxaO2^YFd|2g4XGIy+F{B31!QOGB=*@aIYVI=uOd4_?t+-!`#JMqAh zYs)*G4>a~X8I(P3Uiq2)6$anFw3)Oo+Z#M~_ax(`y@+|eGb_S#KUsSJ^-{}@k|z2n z>Q|fl+vbMXM9i~KehXpg=OTUYLm;BA|Lu%;^>$nZSAKj#&+qtlF9PptR>bjgj>U~i zoSs!h2cQkun>n!m;=R^~s;TdN^%F5Bb)~&j2fw?lmz0!WU)(P!u_Ij>P!RSKe|Xu)H>tI8;nz60dZCO zm#b|mf`13h21w#U7yjo{rC72zI3<9~R zu%LlxkwCrkY_HW^6|$$zYvr(wJo!u42NQlt|(U1%W^SS5FH` zSMa!chCi}03u=A8Xws2L5o2m>*F7be6seYlh*H?Un>}((guGXYkhWI(7Bhhabqg|e zW81b&>)GZj6zi*0(vObXubO2#dX6;-;b_!lRo%jJ^}Ka4vC5t{x~sHG)W`;(C2H&#vhrL~T}U-h_)5zRlYjG~NVk z{QKL|@pk%`PHZ<ilji)EN7x z2JPd97!C>zjp^Q#A{mnN7znovYZl}i@ znYs*rO$@Ow{l*l6cy}T-V_K^p^(90jNX?%?2}!)*cW8>M=T{@@0m&nZ#ZwGw3Rdjx z6LC&Vo-bV15gALE@s#}EZWT^S5=ZK=bx5`@)?aLXe59&K)d5!rV-p2tp!UjYwiHbW z6f)9gce%@Y2Uke`Gjrtqc@7jnr!pe|BM7M;NE2qLGSlkZwrL;3A0oo#z5 z6xH)Q{*dFQ*ZF1~O}=CFS7-?`#iyn0GTC!<`wbWa#^Q0PqzA|JWDlzfR0ap!5atFA zjtHlzX?$`D3uQ06Wt?2A)>^(-KQ2)rP2r=W@tVt-=Pzk1X4R@SpWcSfCnZCRZ=SS? z#Q08bmSt`EItMW$70wnLwR|tT55MqBC}eAAXZ>I~S&-!sBD`n4>efhmKi@y&tlE;i z(s6h0dpdaQEc^2_MgDa|+hNN>QgW8}jkDj))P~>4ihalN*^}UHD9PJsQHRqCaRtBI zP8Iuvz#8GO$7m9OB=aCrC>o?+p$w*bf|Us=w} zoKm2AGH$1(#JtUlKHDKlDjLU}Wa1^Y4)wKfkEeGPa&iBaaJAj{6F3KM0Q>~M{n1n)$Dw0!hHGnU z`@DYsvfi@sat6F~-aWkl->^n(cztRYBEl$0uu5xAcGW0U81It5Y(T%0DVPS3eOx1a1vxpiYNMD|ti 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�pWRZxCgn?q}E7HQDuxNpK}vQQFF40FTfyWCs>~| z$t~EX!kn6dv$O=t2++j@AAEWoI_iy^H4X%z{S)(<0}qw|$;8p)Kd3k|;O@bJnfpzo(eXYufOKdBSCEaA0;LuguI{gl5GkO7;&L={mR+8P8Dc}0muoKs_YiQ6 zv+kPOH?EkU|5AzG51loyJzlLldhFd+Co?DEt9uKqJXUT;^{;EyPup@oENKPT{Z)QC zP;ZR5Z55Vb&GIcUEPs)bp1ybGJXyKwxsZuX(R%xP($B-f&%b^;D~r+29S=T)`AegH z8#%6RU&G04@4sxE6&DU@0*czPlQH!RQ*Ahgxw4;z$lo+DMbkV!iirn-1 z=OE9kZ@w=+xY_yI(bO)vXp$1C0Yn?3-Cwt1s=D-INRonQY6L-lNm8Am!s{`Dp=(tc z_omQkx6V+f)~w<^0G-?DcD&vhF8HsxHgspsC*gFuec7u2k!h6Eosa*K>R_u-+dXrz z{P2dSdWVlVltpSfFc>W}1|XO_Rd0OiyS){zZhLH_Vdmv+F8&_?k3n$0J^$SKbC=IQ zx4gP?=vAP1EDI@TrY4q_SF%hOg<+tHiDtXieC*lhjvU;3XwRIn znvIbXhgn`O1?^_jTINL>OKHUFA&m`h$sjJrdizG-t6@Ho~-WOcceBo!?KAaHy2ixmmXlfIxmmq7$?ZGbfR}mz?npoRmA?L8!T3v7 zPk-gb*Diu3JkJMU=U0hLzVuyB7$h-Ul57PTV~IdpYe)-E0!kqi5GQG}-rGi?(4Smi zTFZuUR4wN=?~g_+D@zv^R@S$>{n04T^E}Il7+7js=pxJW0sw@NWZ-J%8Z%qAQc6UD zD5XFYAW)1aUuQU=lmZZW|)z6I&>>@EgB6+7tb!f_O2V-(-VV1eEIz1{zC`LQ8~*}tzHXkQ=O zf75h*wxC=?Zj9dATp9GcRv<7KooQk+MvKs|)RYt?01?4?NUJSfru`u!MVQtb?fllj9)61oa*$I^uGXL zHyZHJp+l>ytMKwSEnhpB2?2y;CXE6MwjfXlp~-4%PzcMU7=Me#fKol62O2a&# zoSyit5C6w=XD|QU|M?5w_w8@E{^*=dhrUw876hi2PhYz7&bQoEKxzdGmW-CzN|d?L zECn$!ATTQM0xv)x1{Vs7z@nSXap6A$QIe9jlL2dNY586jX_pt zm*ao-%fI*jcfIxd{+IXt`R5<_%44V2x8u`imv1?-@3klQEqD3(rKO8mS037v^oA?j zgW1{Xd{}zso+oabnXb-E=YXC@IbClY+_QE1q6|V}qk_m7R-T7N5gnf0`^G!ak3=?% z*cR(?k*dbTEa!%dHP*5KCKi&SS_5=`U!F(HDhOa-eLFSxFB{f z?!O4TGQMmDPmn)DE)YM>>74I!8Hh;@H5ta?Iu zRODb2X0p07%F0%NheM{!Xdx6@@__{^jaDi!tS4mDE2xi|u_OpIa$FQpuBJtv8fum6 zEvsw3`2Vr@-{F>KSA8J7)(&qv@#cH0ZspM3)j6rV)lm^iAPFH0FhVH9p|bx&P7`MrN;*IVwoXPB*g_EVo!dH1jU zyYu!tUV8PV)8}8h=GxuwfB$zkrWTIebZ9Eu5)1b?4y9Aa1&DMC-m`H*lZEP&vb^A@P93N7i%CNlq#ziIg z@t4l6Y-E*Dp+Y4>;d2%c5+e{O)IzYORx{2Dr0aO5~0 z=J_x)!)jxBqu0&2kfW`EwG{%O(hOBmRZIlH6{GX_sSrR0*#QVCHG;5?0G!uRFzAGo zen;l3)N~QC+wESta;4Ync?C;<_THuw8RL7VX_{_rZFzE@N5FWlm%)o!AbXEzCz}sgtLBQx(67jI#TVBTL$;no0 z^6cpohmKs!F3>?pD3ns3%C?i<*$W^WQzc2VzP@(m%(;n)_U*UdssXxGe_6xfaC38W z|Ngz3o1L#KX?+`Xk$1x6g)PcjtsY2if)WsYZ8jJVhQq=9{HgUr%Q7AwZ!aLFW9l6MJA?2>Q`6@3~ zH`aqV0_PY|YYhyH#E1y!6|TJYl$64YJyul}1R*n3l>uh&_W|3}ukG+8coqUd8B@*7 zE&TY8|Mbk>#f@PH5lNsCl54x{Omu4b)guhexS2F)V{?@Ov<`^`0t>-PNb*)PMThNLcv& zAZY|9cFqMsT#SaGWNE5q6c<&wnddW<7)o<%K$;Zt0+>u`&^ZE$tl25TtTd@JI*xk7 z%rK2oV;Q}6=Jw#w*J9&0uydf@?tX$dT6tY0(pPj}^=`+=+Hrk2{-(wqB-k-g_JA-i z!0R)7zu!m1Mx!Bi!dg34&h+oi0}qQ{>plwYoXh`+5BrlPvi%|PZIoQUb`Vho^fXt4W*^xs5!Vp)Ei^>8agQ|#2Lkh&@jbf`{2xVg!G;0wv z1G7Msf{Vf(-dq36-@CUKMSCa18xGVD%r{V?Gd4i`7vHnDuK9iU%upC{fw2ZHSt<~M zHF6wkCK*PuRa2v3Ha!zrV>-RT?%g*@YmLi=k_cf{<<=U7dTLT+MU^z;iAhY7=_2nq zvvKxR_vX9rnO)rb^y9zUg9EQU|4gghy5{D6wKywB<%>^0a?>66wwmqDl~w8T_Qbpc zZnwnd@);Ff|JHZEZ?L)9+Ou%+nUhEEx-Kn}Ua!l=M$zw0eB;u;FM26V__yb!X zV74sZxw7)fiHUx_zI^4%(@#Hr}~S?5@3&`wl795Rrz#RjcJX-dHm2e+bDE~G zGbZ%rAiP7o^KZkSKEBGia6C!%Z}Px_gNpw*f@edg?2-umXLX5*8eczE~T-4DF!p-bn_yz`ykWi5T?GoP;2 zlDsJU{nYjbYb%|8r(c+=-D(y^X^b(pXttVn+;RJ@x8FH6H3{gDm}uKdU^E(4RTalc zkyi*}a$;(IKl^ulhbbhp##buVPyEil6< z($^e0xG>R-f>5f^+G=BST>#a>;L*n(d-?3SANkQg|J~pHT}mPd&7c?+k;z7#ax~I9 zK=jkoufSXJ>xzU7OgkMe24C$7<)4L!0zB{o1hYoLAeh;Lr`<6EFup#r1_lrgyvF5K z7ByeFYYQMIK!2xzhi0*P{lPo&&DjJ0G`@lGrEm~vKm8Q~9a$lTWRgM%1P4eg<#y>{ zjI{#LS!*kY5`h@23K>8O7N!#1sMc3VO-DMmdRh01ciz8NCQJdGoD{H5ixVu=N^ zWB_NY9bVry*+&QgL>y>qjAw(B+lG7Od9kvxQmfrNHz%g1t=~t7qd}|Dnw*G?7a^8n zb!9Ej^Jb%txFb5lEO&4Wz>KtgANs~FFcGi-!A!g@B=RTs#eb86c}MnDNDm_g00!qV zmX;i`Kt{8*THAe3**)9a>@;ghy*bw(Y+kr{c44kCb}~v(i@t+dc7+%W5G90lDMZ+q z5GE7ppsaFYhf=ZE0nopEHD&{4(2epbuq z&}otkESN#yA1?zjv){|bj**WqKEBaU51^{5UawcL*T+_5-^3Hb?+-tQEQ+F5t9>J{ zb>P5(&wlo^up@f#^#!7I&H=C#L~I$jtV|Ro4BkneBnU6?i=GR--J(EX1geHFT73I!VF93xiFRYE96!5|YA zB!SLH#mSe?zx4bIyLat6a^2DC*_lB)vM3$0MoHE&kwioxUEy4oef%T89VbCmQZ^bf zgAfXlw8YKc;Ftc*f4=_EuJ3!_L!lC1_~O$lj=uEV*%N2h-gMuw@4j* z;Xo^lpi$q|yd?T3PPT8nCaN_+AgXBQ_M@E>XBmVJ0+do4X5kzZlSk%BNsUf{theg@ z zX_`9cJP*%L>3r=wF0XsNUJwN1xt*_Qz1Zd$4eeVbzNGg3cSKxYU-!T_xT?a2tNKk| z7SA`7VdoyQ{C`x>o@V!v+Zf&<7eykpPzrfpDp1gUARP zxQ!SRZ!q+kM-0xZ{xbjq5j#X%q00dikTJLbxgtt|`wRtw1aN|hxQ9pp0Wcv%h>|&l zZIA>qg$N1Y2C!vsb;{%&L%q=XcXT-CiZlg8qbPQc2CGa}pm>jvmCJ` zZ`h0n{lVMc^yZ)W8*jhy#(Vz7FaE~yr+(^tzH4&v2)Myhvgkt01nVwduhOoKp4GTl z-8bF3m~-^GM_(Ic1%psws6#~p7(fyeaTMsrWD;sS*_s@7w#brBYSv^xMsPw7 z!a$9B8)r@y)=_7(w>YCi(GDV>ss)|RY;r1$qL#Imn2j|6($m^4O9VyEIU;6N8EY!b z>`G%Zhd@ls);J}IEdnFEuMlk6+S*!MTN@6CMN#-%K|5|1i0EBI!Z56=YJGj(i(dNh ztrP!XrBocpT5GR9G&wmrJ3H(5Rxg<8b5vDTKCNAiPVkw^bG)2$%gf7Gll;bD1w>p~ zSs9H+&1RFyIVJ{?4F_9mm(#6vQx;`D0%wS=kcwR;1xnOeX_S;i+kiO&VgyGPj2Ha| zAaK?R;S{qLLWY5<%CgL?DJ@qj)WXTK%G0b1%z@I@RR};#S_Fu+BNdK@*a8R^%;+3j z=b$RKI-5e^LXobnEwv{mlB700Gb;sp5Jr+DzLL>e`F6m`lc(0!R+`P`4L2S;bm&l3 z7CO-N#&w_iNx0?Urzx?(+2Pcl~nVXq_sxpIW zvk}I%IHpMSyWK0B8vukTMp?eOzJ(;}_11v{`}@7Vb5s`T{QT_c(`QbcI{BuD-nO~f znVp>-6D58A_ocWO9`AIvJO|=CI)XS}URz7*bronSC0UzQ*)Z+x*)<=9!86Z1zh`mR zYps^pb> zusyJO{hx&hlE^mO6MyAr|7RQ2mOGnCpj}mv0kTjqxwsz9Uw?Vy;%qr;x0+LemY0{) ztQ0CLEnB8qtU@6zA&Bj%OdLdPokQ1dN5(QUgn=G^(a~$K zU0=RJ)|I1SRa#?=lo%zU2(=UfoFm7r$;tcPc<-Z+KIS=m2oNQ497jRmr+2S^9dK0@ zgn*LKE7mYGdMM>raf7^JFOv#{k}^@c2(-0Upe`yW1={f@KU)vpU)$CG!?HoUF1^A++Bd=--HYBrw#>zD>H zE*I%4x4f~U1Mi^Flu|x*dpUPsyZVM~Q53#X^@F-IXU=$4SYwRe6g*I4+}I7n&~vYi zF`Z6lG#X7zOiWEp`AYR0xb^=u{$ztc`teV`>A?s5nsLrfPfhlRqs~@udTOGo3;;+W z0=Y`0M=9$jLK@c$C(lBCYXX$4U}LVNR$jLguw2|zVXKSAmIMU+;pg=gf5*G z2tup*1SPZ7*oXpaso*4F@6$bf}ag)S;>;xVUFOFbvbpT5~=M#OB7*!mb5V zYGGk8>JR%{7td^hOp=5&!tAc3*I!+|n4Ws+l%>X--}A1gzx0_4mx`bKo9|jZ@f;WH zH{WtSnc~9v6E2)WfTGO$!__Z;>AxO0bX%3$txj*EJ>95d=hB6Z&SrBqm|WO({^Ysb z=%gLb?wdM)=D7pM?gGR{qZx*iag>DNK&Z-;6;agh_oN8AolaQ}*Ecp6_Fd;>QdN}{ zLP$wjW}bLrn+7ALQi`Rt%oRX|SOJWGIe;O6a_;U<=P`hy*?jhyXN)o49Fd4TbjB+; zz*h?YI_J)vJ!{IclrnJcyYl=%S*`#ih{GqI*laYCJl8?sk!oW&f=_+^tX&kvr$7Da zzxVh4-p~L1&jWxGQb{Ekl#qc|6_F593IzZHi39_2B$W~(3WK)bmCgR_-UA$l(lL?i zb~d9>*J?=^#SkTgm=@JWXKR$pyeh19j=?$y0Q42iVs_SDWz)mJLZFgTkt>VB=&*8* zmDXVp3a=_oguveVWc!dUkO{^T$IR^U5aS;2c>lV3AO|~iZKYJR+03%6-|wF}b7uek z{aR~}>VvCTcVq7C)%JnTxzT7e{$2pUTI+3P;3^W{c-l9X@gIYd$M|EA;-%v+TVoF$ zK6LEbV|i&l^V!chR|Y{iF*zG1u@K>&g@xo;^5Toft8rESL8?!U>K>&kZ_pZC{df~+v&YZsV+A9~WO`|Yic0mxPX+cDecz*ZdTi){EHP;-8 z;|2max2^1Et+{$fvzCml27`W*G!XhrmzIZV#lT9#;+{QAOG|m4v*T=-RYe6L7^EPB zI~=U-Q4xAEY(x|cT$F`1&N+6#4xp&YqN=1;MV?9KTB9M9&a$ksX0x-kXMO>gtwRKk z;wXvHIs!(4z|78V_i%s^rO1jh8>SQOI*>p>U__7%V9MMYMkWzq9L8n)}`1Dh=t>*mH)I?Hi zBsFcanf7Fw=Dpq^isKdrx;-gKEU#~{jCH-%PNcLhg5k}O9IeHie6r;|1LVZhy?xgnc>DXm8#HEV z9%?OxGG$d&B?5%tUU}guZ3Y_~gQ_xN5Jz#~>uuvIWwBWcUOl^V{-6HVpZ)%~_HR7) z(yOQ2jpm>-|K$@;zw3?H{I$RNvqkAH|LcD}h-PLNnv!|)#sgO_tYl}GYPTG-3?@$} zj_sd2GQaZbQhj!g9TJ#4Ehg{3u6}eeMkR#CiHYpWVAo=^*^p~jMhHM`iP>j2f$S=* z050c)w_h`R;K;s>&fvQ5d+Q5l`*wL%tI!hp#q2pNgtU*-Z<9x-^tiAj^lB0j5{I^Ue=Ap|IqOXdot2DZQ{VlJ>kFu;}+ zB3nTQph9pAs8}`FDFKe%2su*Rc2ojbW`h(nSp*57Jaz$*mORFsTz^O^O1jDk~~Rj8rm^aHV1$ zsMHpws2p&hf+tjbErAeLQt)dcKJP}Ig-1(AP&BhUlf_12BSypy(XR3U0_u>fJ zz3$*MpZsjMyY|on_cjk4ys+L|*qh#Rh;<^x82w8Wf3$-t_l)y^7P4n^XtFX*z-TFna$7r`;R<$@9eRAf6QHa zN~&3oZo+sD%Qz_J8Jp+;bPj44=mKO3(Pe1vcKJ-eE^+NV%?y;oRX06b0Gi&G2E}`( zXD(b^swXveC4!P7v_-Xd@9f@v^EV!vID2vU{P9cYmNxSe3__z3gwOI=1iH!;7Q-+AA+#Kw!aQ|3bKHCdrE4u&$axSc{2ZL_`7s z&^GFIr6n+uQCV6#2T>TwK#L#{s09c{EUKIwTL;FN(%G^son^Np<6(^PBe9|=#zT7V ztU1n6KD~^axp|%gKvh-aauE@|t}iotKRn-u9gRlY#}XmDvr!m^p7LH41pq`*JfIGk(U;I(qn;4~2^`Bx0BZ@Z+wEOiIy=e+O2I9+-P7%DMoGgM zQ>)d+h-M+g@#8O_J9lpP?%ns_fB(Y5f+MrEv=oNH%*-@1-*?}=U--f!?|kQXdn0oI z@X7ql*>iWl;SKxt?*GmI@atbb`PA+E=WjZ=2PKxmHe=Q%+g!Qy{PEYAp*_*g(vdY} zDBE<{u5^37g<7&_Vd2WkYJZgWhNC!+ zT8(-;jFM1cAd)yyEUdAp0!U)ARj9Evu2LkB!EnxUl-Zn^02F`{Tu;J@X1!jE1F5X3 zOlgp8UX(~s5>%Dj9Ga`U4;yQ1Wm#;EM(t*u9OOl10HjoNyLSDV_rL$SCm%;C({v<) zSffHAK#8i#qgvzBpZMrs{P7=8(?STOZBtJnh04)g?rO;ZT1SAK<>`0@uMfv78z4=#uLr9b zX!-5mt`ZCSiXJNf`+eH+F(sm+D2BtKS4;EdsHc6@>-E{$*_oM{D2n1Zw$^4@ z=9l_#IP}&>ilA+4D0~lVK2`z~Lxe+vwP;DDpgvVOz*XeZl`(iYxm;pgHT0s~I zWI`4~NG~xf6v_~61X##u1f{_tF#<^;5G624fr5#gFb)eTz_}8jvmDv$&pk- zNNJ5rq-@s%scV2JwOO25EJqu&yY@s$i)EOPRu*RWuPmP*jW*x5B*xbxw|L|FvDk_-BK-h+dJorEbnag z19di3v5Lg<2Aw~BHjrj@t+?)%8`rL!-*fm_zMjssqSf{OM0?ScYrU-{r2nk_1_2-iDj}s8*aI1akuz3m zA+%Nk141QL9O!K6l2Q@s*bpe^kkOec&=Sd6Q%Ofe95C0la=CCqI1`t(c^Smrn5ynw7sw>oBOWc`4I3@?Ag!UiT_~KuMkN4rX1~0+^ zJD6j?O(aR;v$~(*c@<4@mDuvt=#4QP#GeTKi;mszuAcdgfA>|f|B?T|`6}HYt@SIf zy(mR+^DQ^;-E-*piC4Sb)q1nFd(YupZ@ooHsg-WFCSG~@m5=_;?<_1V{`n97=*1JS z{m0+@&FgNwdEem!Cto`qCBf0d2d5_6Wme40%+1V98Dpiuwbg9U??h3;mVcE!(r+ip+F!4Z({Qm*dRtBrI6&X|vHBj_Dx2}vQ9Eb^k+h^HqT{bAu%vy=i^X64Mx?%rVVsZT#L7!Y8D zLIFBrtCU0pc5bpgV-H@lzP!9~`a-PK&jNhD-LDG?{p zLvMcQ#S`aVJ+}fZe&ttwBQJ^{|4Tm-gvvQ17_`>q(BSL5I|2MUKnVc66qGb2!J=OacNOjwzSp~2_#n)nIjNFp%-X1T$PzuXkpl173d8!{TT#NZU;*V zhz^mZ&>*yR4w#9y-C}9BMz*r9gnFPR8W)w!vg*`{?`B#=MT^x?8_T+4cn+~-=7S>4wAr)}hA8ZV|D_JoFXHf7~ zcPr1b$}&fdsL^m$B>=)Obk?T5e%2eVEM0glZp_Zl?b|aq*={Jojtuz`G*|$E0F30= zD$q>dMhHqG@*-eKlK85EzcuMm2;q;f-{5s_zWL_QfBy5|;6>)9Tb-?uM3oik{r6x0 z3;*C39{tku4}b2mq}0h!S;$dK6$Z60fdR_Yl4!7u!cTW-4lDGXP^FD_?hqe{`Y9ioHOKDD`_fLN*A5w^)t`^(EHx_>EC^! z-iQ$uA|y$@R!dr~B#Ct-u#tpkme)V~yBHKfgFNJ=HJe z)ZDH;(|aSW1lm?O_44UU&Fl7C9Xo5vC_ebsyQCYT5-gCd)G*mRwiwqMB2X-4#BScI z>-OJxV(*oUXD%eQge@a5BQt<=QG_zU9x_rDwxd(i?)18g{_iMNy1vS=ec~ zc#hq;mKaM|z*XH7Ywg1iKMVjj-E4AbLRBv(_33x zyu+m)*V$tk4gYffb-f_oSgMG>5_RqaBgxJ&coA_Hp`bv*9)WGZ4nU@Ooq!pqk*@#) z!W2LSLP}OhL&6SYPjJRqFqe!~p02IKE+At6>0ot$SRr(zkl>}f^IwqhDF`1m)vz)T4L>LIE zs3b%%@BxmGc|w5 zr@!!tZhElqy_Tk_lwxjfZhm(5i;sTsy6djH?Y8Sr zo;q{!{L<{~T$W}3;P3q6R;PP|NS8i!>G^;DJGVZVP~5?0yX052zLn^LfR+*G1WVxz zVh@@LHzNpKWlW=%#C6-A(%oVz3`X@yOC}y=rKIG{xs}r=Uwy}09;(M=39oGQ3JV%V zv9-Rt-P||3=cdE6=Pz$v*chH)9iBaV*#b-@urSxS=D_Tgjr9lay#C%BcWte&8j}X0 zMy52)s(e(_QUN8+Muh@Iz(S;>EH8$&K*?5^Bw?NvNnB@kBDM-43ZpaEs9t5vrq&5PVQB8uZA$%>2}Dy^;nKOp6wcT#lAHV(M5iySAcDp^MO$0$OKR+Kukv}NHPQ%ytbNz^@ zD2j9E&UxZR5CmS3(FbIiAC<73Zi3~dfDiBg5DhUE5OLERA0U=6)KuM06NEjAM zl2@-I>Gd`dr2r0n0)EDT#3C=uNhCeqss$&1UoL*|RGv zEA#X7cieIN?Ch+Ra&2v`+v{kpwVv#Ddr=g(CtBAXyY}3<^GA;!X*3$X6WZ_h!!R6; z(#eU||MI{6os+MfdieJ~d+~+yGp)ELl@Q|YV+SUYUU=cvMzeO`J$F@>sV(;F)7cX2qa`>p1uuIc4NfJcd+}tdRGLEBuzvl_!f1;W1n-j}d zR%d6Yz4hQkyH&5(>-9#r+gso4?AyC{YO*~XjqbeTj+b6OJ{o2F_w5d&(C?L3E?)+u z#l3q^ojhHXWt=P^LKH>qb~{beZod}?q366JB9T{>2WBLK&5cf@Q3HUPnVBaZf1=fF zO-xMmdVL+}q?Tx@$&oc>prWEog+QgW7o_!Ur@>$d0K@)}$nI!30sx=@1R)R@(K!14 zAN=4=x8F4?ZJ@#=sttx|Wv$kl8LE;LT1RFerI^{9r?vjz@`4Vhr{|>Tc1LA*kaY)H zGm7f9D6S`s3S6ucfvDI?3fU;jg~O7Z5-2NaggU>pLd=1bfzQ6IBYhOS{zAW zW``(>yr@RQ!jz^c3v0$bcm`-sO#|xA=9MIgiJjC^X(gp9^Fk?o^yrZbXI}#V2?C@- z0a;!w%+G)N6CeE_{>Pt`Dx8^V7-wmlgT_MQ#KgpNFTVJ%fAv>>=BIwj0!C5ITHEXQ zgg^nl%L2}N008<9jg%_Siv9Z!zUw{j`S3@6bN`;b{lTc!YPXu%^0F7J-{zdXUIpP! zYi8VlBSw$M1-z{1{H`fz1_-ii=-`^dHZhM5sq06P>6 z(&KUIDuv9is_w?Nf8!dJuOeq`H=1^?aP|N9EmyCxHr_t`R2z3}3p^SF5&ay_ry40` z6h$7cF(z&MEylwIyzGSMXRoiXf724dpT>XpkW&61|L6br{Dn*V_wD)Y=f3dyN50r- z)R$M*zx2d22lg$F((LT{i&A$pySTC*voDzdc5vv1b)4gic{Ap|fF`xS~H3Agpq z6be8EOyJ0BC#6&f?IKhLDov=BF=Q*+cIrlS77C$+Wy9o1I%m5DDJC7#(`VDmTb;er z$+e3U?T`=Z5(lFwU@(0T43O;vfpOb0mYtOv)1oDWj zX4iY|*{A0B+ z-G1};{BS*KzVO7ytSOpx-Rl;OS~A#LUS03qa`z3t^SP&w?4mTKVZYOiMUm%|Q+t4I z7^o!D*WbLqG}*9ozT0Td?Y~~Ft~Q&Evc$X`kS+778V-l-oDG8F%o#Zxdhk7Y1&z^0yTJ?I}kNmG@fB|!NbMx%Qijbx5g7!c zY&PpEP*s%+!>NL1;|C;By|LJ(t z$IM|E`U#&e@&UkF>vO)Jp8B)K_|O46?m0jFBOg3);NZf-{N~2SLvMZK?DTvT#r0Y} zNfIe=Yh&}*fBipx>QkS-=Z$y0>z&{8*q0vtosWO`t~>6({@~G%{g?mxfgk#F>ubyV z_w9T2)stJB8%px7UGs~JyY9R1u0gN!_+!tUJG8>u9UHX{z4#R*O(?)$_bUhQd@qsOP7ryTgHC zM5%hc(MG3t-N8M*QATXfEUji~acFU_UaQA(C;=Q<0ceO%UbyVY9lP!*GFVGeNV2rK z*%d+%7$#Iw?OK>8B1hzi6)0ft_Is7B;;<$_0!tO^U@***TJgx2o_Ou#Srp0#RUk z=EbY8y|%VF>h|(_bH-Zw)qne&L8w3YBkvDn+va@!+$f!j7;U&*9HA-3^W+ZyO{ zhZXB(qnMclA^_6=3nm!f;jul#0>LB!APj0+DJcb`bwqN!GLY0l5}K+a zAqhwjA#EFk=7n>vu#SwS%I0jrId;xEawt$B3Y3+fx1m9FC=`Na1~1=9-aH*pN+qR| zQYy8*3wo&xatv$%fQbD7&tbrT$mlBTDl3%?rLYWX=Co2$LKG&%=&bYnU1qT(^9zUq z7(gf?g>xje^xy+2$xvRkXR@l|p$SAR;(Nu;T#= z0KiO4esILV%+{ZvEeiquRzQCq`;Lw{3eu{y)>tW#%Q%Tc9acp}&M_b}MiD&q*oznX z-CN)BhUHU_$MZ)gXKr@Ab9IecH}>qkUZ``IFP~dpS(<1~$5E7(xhcy?2}icbi)=Iy zToJHhXH7L6b_RJaqM3HwDr}*Iu+9>ZP#OtAh=7sG^ve0OD_52#CMOo=X69xaNvM$7 zS_CE*0)UW_nfcr4^Y>+nw`vH(&>QxAE5>+;=t)=K;B{tZW>!~M`~7~a)w+5J^v8;y z`O)wFN5A;*2G0J^Kl>N|*8l!LrUUq;@Baxyma58Hs_8_l*s;+Hyd_!Ys<*xU{uiEo zzSGUGJ85R4+aI?9<0D4o3L{ z58U?n(=Ri-)zytWFTeQmdQqM`a_q)yXD0-397oQYy?geL3bS$YZ0nYrQ?gX#&0Pz3 z-~R?EMOx;O(x(E578XPpqf$c1Ib#nbvy}+%d(%VDz3^`ea)Tc`Nu#0@e3C&+;h)8 z`}XY{3(yxu;UD9p)9IW(efs3dlgrD?UL5agISbhFI~l*qIQ$#)Yju1a8Y|TMpOQor zQV=t-sz?^b)uc0kj`*S#CBhoPq7Vpl$*JAaj))5ZCBT*wJwX|B#pubxOn_p$6($8( z25`(m0D4_Oc@OzJ9PsZnHHD14of#VKeKOUnwBmx2TK>0H~XWF%2;qhqF{~# zk;rINR0u){6wH#b6i}pP7&VBBVq{xkj7o&a6FS&+%ha-4J9qA~5+bS9;wWC;SQ7#V z!(LmoC+4P)?mGOY+aKIqb1yxAF;Af$w_1&v&-}-aK6vAN3zMJ{jCAt!87XDE)vl`Q z5#I0|68zhYKFpH9KQ&j>S zpd=Pul*F`-qK!cb&|U6#kKS<8U;iI|=;#d%UElw~ANecKeD1ZI?_5|o7DRde=*Lg& z+MP7p^{w?zW!#A~S4OsEcI;G^bGC7%EQ@RQHr{&wjW0g8d~!nGefRZ;56p)cnF&NA#(uo+6^_uDf<_Znmt-e!uTq-cb}y&rAceF(wGYqR89r zb`&OY95Iu((3_Z;$n!jo<54;q4D;)*yZ+|e?l^bx{Q2`|r>AC?E?@f8laC*pQ0G>* z?tjz$^YimtX;rHwQfd_kMVSedQKTzl(lo<@_wC(#=FArdgMpN?-EMoWq<+88%u1Os z46@9O6;}Ubv)?x!o10tn3v=yOdpH^~*(lU;7>8l7y0&)Y(4lsFV(H42>yI9+HJa8s zt#ud%VHj1F+X&X9B-vQqO5*s~4cCnZqcqLN-i@tx%R2&iMa{{{38ez1bX8en?1>X6 z7Z(@2y6ooW=IPU?uf6u#D2mciW{pjf1W^dVLZXzyIU{8xg!DrZW^OcUX_jwpb(B(3 z5?JGm11SXp2w)-QsHooa{vUYP_r7OT7{MaTa_d+~RjMQ# zY)+U#lBkv#N+tTkQD>NLWMyMunqj(`sCtwnvH*p#MhT(<%&e`fbrtu^tyeEBDG6~c z2&8T_;#Q*`M_OxTtkH2~3=M|Esw|sH+)O4b>-GtCWu*hKJ^86O+qc~Pzza{16X>Z0 zfPf&R(B$0Y)XY|I(-BLJK$vExJvsHUPk!b{|H6*|jzMw0WEI|OHH}u;6Tmb;k!8Q*Mg`gb@huG27{3-*aG4)~G!@asJyt+E&9SM-}?l9)< zji-7+5cpR3_*r9ejQ>B4M#HNv`|{F5ClRsTZV!h;&(#>$p8(*c;DaEj*X!TxWbmi) z-!FW#KF{-i{xANOCpOe-2>?hbmRHxWtgZorltM}mV5ebs3&2|telwc}+jlfFkr?y} z(GH_fNMaD+7rwV8B}uZ5p~ldJBgGiXA~(IVGR7f-CC4lskppso2xJ{)6@)^s^jwyw zvy+iCI6tZP&+A4K-hOQ~J0UFU(@R?y*35;#D ziwCZmKX_>GYfrxXuJ^tF%<(Upl1?n8w@|;=x%{>d{Al;ei=%9?c4_IJyZ4-5ubzMI z$*r|>YwK6GdRuvxJ1Un~HXpd_*utzRveFcCqFFQLB?B`TF23N5v?g0TFz;A}^{IGTTbp1WAKDB=Ol_%%+T+^P}mG(Bzp1rXDznkVN(VuxQ5m6>4g^6IhLaPM zOq^Famjzm#H^a6=>J7Oxjrr-3tAtPmpkO2Y%+CRmK&?DNgOQ^s)LEGqrC<~S9K(+9 zhKB@$L}WxFVgPVLuocQ!s_Bw!B!mEBaE_!15N%#%Wv^69B~k2EB_#?5$IKoT#5;UD z56JVIf=|(7>hl=MHx?!xtKa)lu&S!lr%&(MvuA2*igwICeD?NRgLgLdpbg%EBYT%$ zud6&(bnve`mLP&1$v1z#xElHQxBs_)SW6OXZJdO)T1`l$5SVy08m_LbKKtBLPd@$l zyWa8MTkp8@cR%*=FFf+_HAil||A7bo(Ler&A9(){y!zsE3%h0>|MC~tH`W2@&O2@! zj?zK5d*|)9+;shQ*Is+Wg>y^wMs5Fr#ofCW!Z^%|l9`;f;5ZC4F;!&=Kn&!Z19Zli ztSHtuH%6mueQiVQU~+o;>F1t4bokKix8M5Wi_cf3>Gy_>Mx$P9n933nAhT!gcyk&= z1T2cGJIu<`qGPQCA)rx@s!BK_L{w5mL1-#dRjw$lakP}L$xsRBlvGln)IuUOYg(zK zyESUhC*7^?pf_6BHJy$!se-j(Z)Ihpoy6B1K7eQ)gH{0pv4Z(sGp4GDaM15%c}naW z^#(C^y8S%s?OmKMy2WO1G&K>#QUkF<5R(%V%gZaD_{76y3C3CHSRxo(Rz;4)N^1mU z>qr0!RiBs+YISRkan-Qb?QN{DpI=gvYc(}HHCqD-PRMdAGZfApnOrz$d0}Kk<+Fuy4`zzvE(OIRJx`N-8Bn9SBLp(&uNykVq>*sD22mprw zD5VA`1+o$)5i@PW<*Xw|m9-@qLR5&3h$Lzugh1h(wZ<@8Ar!L&u)ru#di4!N2f$Ja zrL;$VdOrq%ih%$ukz_W2z$|>zN6Szt%?3tQ!9+p?N^*ag6_pc8GNTZ3d*)1*2!+td z3_E*e8DZx_9J=5OtuG63%%HD+(<;>sy1~KzYvk&RiN% z03eWKA{NNxfY1>;X9Nm%7Lauqp#%0g^INc*{-9O*En2-wshX0OjIjm;IC7;k1csbL z5e8a4`SgpAJb8S2U)@;Sn%H;w^rNG#1JiqMNYRD)%gYz6Q36Q< zsUToeF&k%@I77BJuPR#<0F{d->r<7pN+r&fuCgc;Frm=Q4q2c;Apw|so1NZP|Kg>1 zW_D_Rw%JM&p$P~bBLfKHZz~4g)yGuNkPE}m3n_f-*m&PaNGZ3rwmO~8H!{F`@0)K| zR{XmUfBgHt@4e0Tkze{JKYxCGts&tJx8L};|JT3uvETm8umAhshy?bFs$Hv(vf*3b z{?LE;t$+K=|LmXt^}qK|Ta7k2^)LVNKZov>2fp|IeAEq+MrliwBo(j|QPf^uUM;wo znVZ|nyTAa_-}r2eLqKa?QC4x70O024mSvg^+QPzGXJev0%av`_n(SPh)XE|!$yHt; zK$aCB`}AWXr62g=cc;To0zgG3&#OEumRD9$s&i*4ih_EeFI>93(Jwlk?%UtK>&U+O zr=NYLmPDp3n4J`|*X=Q*WCCZEf+UG=!0;czrai*)Po z!5Mn=rDKKptiV1p)7P`2#toD)#`(n;Up#m2+%?x+bNKM#iHV6QipBIpP&fAVx`Npc2*p*-(!o|iN(y$uGAU)_z(uHlsHWhu5Lh~a zVp7>tfElm^C;@Ze0f>R5jKKgRKqSFfl)#cbik!)}?*JSU31k8mz|8D`tzcx<3`5|d zpT;q31Ob2m8Nd*sU>E`*Km!zjRjQMsv5SI!O% zTO}ryUaZQu z0sx`0Z_BNW0xk0@i*-=s=E_Fj8p|LqE}dJ?axEn?G?aG4R!0M(k*gd)n}oF`kwpg* zI5TApbX(xsaI~vdf2|n3v|0R(n^L_Tzu&)Y{`OJ@Nd}>w~S$&3C@@yHVn(O0TSMUb?a} zH#aFHg3!*|QI=MPsnzSNmo8@;XMgGkA3Anyk0G1(iXe<{yzaoKKmE+3&%D-Fed{LI zM)#{#a>y1VO0DK#Fd3kwtb@ln@pFecy(9xqu zXJ==lDDr1=kDE5e42Q$PVBnb+{?)@U^fW;)p$@$||Wh>(xBLc8O4FHZEIuDH9p>b zo1N7DfOF@oub#Z-@FAhGDhnk&VBAW?t!~#DTTkMutV9sRQMkIce8cremDFJvO;1mC zyPaNdc=p1Dn{PZu#*!mnjD=x1J3HHKHjTBfy!xs@EX#6jZS9s@ZVdu`@#00Llv3j5 zmtVg1)?2N$`}gl}HJgn_0}-WCqv4Q#EH-6xUKR75Vp@S-~m;r=BK`0cU$hb6Op9T? z*sM#4L!mM5=V`wv^TIj=%#tb+?Z^{Q4}c|hhY?j zjYcidg30y!U27c?2XQPyX@EtbXJ@CRieTHm4{c@QTGDJ!+jIbcWF0$)$S8zXh(gTF zEaYWwjB(aBCR?BX?C1XO|Ng&Td*txGy?c^oz0qpKQKEGe27wm9fI+AmN!;1$j)ud@ ziS{EGmo|Fowbxy59GNmjX2(KF@~(ZJW+9~V9=Wad#6S7PU&@Q@*!9Q8OXX{VoaDAi z!B?#{kI(kUSpe@L>g?3iASP2;5EvYO@pF>1o6b!)7 zY&Ltn-dG-O{4Cf}V(^duDjwc=!siP@X7;%nc1U~vI(|3tn#p6#;`p5iA)3vmHv+$! zjp1Ktb92)Z^2VKIZzSo^?-~Toc5s-+m*SGDq&>@cRb7n>&B?JQ45G=A*LdKy%!V%ko1Rx}y01-Z(Wq8Ey@2Z;*9IcGv8}fBNLPnW@_G^M!!yZ~f2_u$F`r0+<;Y zog+dIY9s=(*0AG1YGgE)5YSnuN|Schy8SF^PM293$ZB)_e0yd;QNFdga`@Vt7j_>^ z^P=cq*|m4EIkD%#x4!%Nryo0f%?*y-OOHO8QS1EbB^@QN9Y6l)=bwK2+wPGvZCrEk z*sb^f@BiTcdg@ERckKE-OBdH)d-m~LZ@pc~sN3D#bKv^k@~cIaPE9qw{P@Xb4?Xnr zKmYSzHN67>rM1!;h43D_L7?a6<^@1rWl%XMWD(%Z&=ob2Us;h+9E9P>IIT4q0|J65 zGJwVr`>jrCs0^_KA;Tb4D!0Y~`0oAo-5~@r!B^;NA|OKy!U035YGKU80Ej|ZYd`{m zL>8v9Bb%1S7S^`g?LccKmCvjG2mk=a7{3+zavcDIAQ(3Xu2$n1|Jip2JOaZQbMfNE zs;YMF+U0fvb};Ls(TH~B#QmM+PaJ#|8{5NnaL0WRceFbF*5DuGuj%Xm>DhT^7D7s| zMoHulPyp&+VrqV~Q{Mf?hwgd9gRh);`NYXnH{5*l2fpw7f9aS0>7m1ibr3xJ+;ayH zeb0wJ^jmxO?bBMEzj$%^@`a;^4_v;y((7;RKX~Ac_uV!-GcTl+0vx*}iLJG)H4-~7 zJ-U-ZOy#7|SvEX(=KM3yJ-4~JB~Yc=@bKZoQi(?&d*Y@WuRnP3&`U4AT$U9x2SLzk zwYuFcU_wR#9(u#fq;%XJ464emuC7N?p%ly{1zJZ^DgZFXrg`q2q-t?kTH9#V(!szX zGmw<(%Id0G*cC;Asoa6Rvr5WQy^*G)et!hODzFO^tzGSQqY)AbYe7h{+3gMbX;oDy zSb&sL6P0n20Q1IHr`c?4i4%)6K^Qh_jb=k@9XMMNf*MwNGuF?&@YLl?mjwsTR^+5Y z;ffNN9ia9zVPIfz#t~vwIIY8WtJ$u#=4N)6WwEunNmahlGgYl>)RHI=HXoSoupPI% zMKt0l2!b}1Q*m4I$fD>CQn%GtN>5KV*;bCMkTOgfoEJ=G(rQ>GPhVa-d-0-Ujj9D& z$Ry&9?)B2&{Ed&@a^o#g6jVjgNJ8!#V&^+g+w<_NbOsPTHIG1$0AfI-?OX44!E{fs z^Vsrj$QC;<_cVs*@7$}~kgBT$VR02l~@1GeNSqMLX z_Uf))h=V=e3K0S5vOwqzI^G~QEz2-_YHAlS0LtPwieZ!i$`bLQx}#mon2qK)X!2T z5~#Loc3U|vL1+x(JWXq@c_~C`DQ>lf%O{DA0^!f8?1kgOdl`~Ii3nv{UOc~g`O12` z*_fSfOtx!DEf(kxVy~+((T-{G7@PCW{hUdbu#~qdqPv{$$@6?0h)aU3cB= z?CdvqDVMJPx$nJi|DM@@^7nu4ogaALhkom~cTLa!y}$c2@B6-YCiV6||7X8CawZOw zzxI=V>C)xP|NbMt^TR*Nn{2fM*?J?ms*ERoP^<-S5JTW3y;n&9#AY4 z2uYGH6LDFV3?PMY&SvTGt~cL)&EbRX$(prx&)&J~kL-H>h0})BV3Y$uAK=XK)5A1< z`EtJ%Cq-6#^rN4vCAHxw%Zt*xWFkTk#{J%Cy4kSK)#Hc(P|Is4r(Za6Zu0J1oT&O# zZ6wKl3)l>^y^ZPl$%>6)8EVz;=dD3GG1X8gthIN)@!rEz)LA*dl~$e2{-B?gm37WJ zGEo@y2kCph=fPG|FCO}y^WFbiJ^q~3A%DI6ci-$73tUJkvn+e&nP*;j;e{{^lO*v} zJa6TlW!d;HqaAyIt1;9bALq%YfB5T;8#H5G3q*9yfCU0ehvEw3aA3Em{}lrfDvw6&oBTZ69W;8oT&l; zK=L9e3{HS#$dP*h0zo1gU`J>WkXZo^01*6~?<-OB<6y&75Gnd&k5>_>B(DA&&-$ic zzXEG5L@ZPotQT3wRnuXJ794;z6v|KvnBiDJ(X)98Pz$5nR4lNGdO!vhCP6eP^R%o2 z<_sVX>W2?BHoE-)AP9rJvbHi*I&d;~gj&Y7>TC>Zfe=_)Dd&QqYfM@d4OOoNSh>oQ zv?yXmARbmUH5s&2M*RWa9@|nHH-7dXNtA0)L1?0TC^}TH8DTm zo}Qg~=DFwh>^-pm=={SEKbmE!ki6OHJ@@>pNmO6o7}Z-`Yqt7Z`EWEmbnp;U@!og7 zb*tYS4DxQj9FEf6Q`7B6WsBKXmg*-ye^cJM<#K-LfVlZ>0{8+{7ok4Ox{bQNGBqFo z0RR9=L_t(R4hS~@XN7qhz;JMdY!t!)H(38Oi>vG|zk2e-d)@krNhYe(uco% zyk5Wi#ph29hUvS%`_{SkM5yCuj-S79X)Ug|GE>}n)9zib5Qywp z3E|J=jYgx{Xi6z3CML?Vtj<;*hwIab*QmLA%=RBuUaVU0+`} z#>8 zl!mO3I2w+EP-{zhKurgvIR2V1RHuiuZNP$@MUjFMWS zwGINE=fz+!XtyUuqoJq7nX1aOA`HWqUw-+TYmRyx&uBENstOU>?TII!eDaf@{KWqK z`%auV(d!NGx$}+n+SK#MPcH7=|BiRPW3oMQ_Tti`kA8V$W8?0-@45Hh`6!Jll{8KBysXt4TFY*?d*Hx<_4RdEnccf~ZES8XFE1ZBaG+kRojP@5eqnxM zqJ8@8>60f;0CTv#RcPybA6*%E|WR@N|rV*+mtr*#}BqtVb-1^~dJ;((bMoDh~m)q{x+wD5xhjWFY58!yzIW zQxsyluGH!S?4SfZPUgObQn0M)XPJDee9(w%&Fh2Tpd(MPs#C~8Xs|}3A*C$KayT50o5DV;gke~# z)x4Lgf4tvE{AK;z&Yu&%aT|iK4yHdaeF?#)gl{qA)Ece|mWsdKxXl8gD%t$E>f1kV z@Yk}m|L+Nw9j|I;kWx5n2Ll^U)}<2L4HZNL6gxLGN+O9wCX-|m=_(YZLlVv*OK{AR zMdhdhWRQf;5%f#j9og=%eERI*$ybI-VY{X`b5U9pfPs{M=AlKld7o6P77!6K5Tj%7 zctj{zYgLvO5ruL>Izr`d?Lg@hCof`PWmIdlXSP;PuP&c0%DgNTD_NGqBG0SgW}f#J z_Z?|XFWS5_>h<3G{hiQ}xFld3bSBwr6&+itl>x%@4ihyHCAxdNqk{;ihJzY%nZRd)Iw8 z=H0i=OzoYS-)k?O==auk%^f*<(_5s3L1!&ZM_JbG_cq#%X={dq!N65j83dfBup^B^ zJ8(-cmH9dY53!We27!~(S_?#i$N}ssiVJ1gbxujCgTQmSq!29SVz+z0bN2}`VQmj! z9iRX(LKq>e5Qe#Qj<==n00ABZcmx0d9(m-EtJld_{dF9uWP5TV2*UoL-y06*rl+Km z*)X-%F_9ILQG}(dv>9%0w2vMrol}V53;+{I6w)z+BSS2m^HVZpAXE4qUlKSXrG&NH z$O&df;n_O?2#mmpNRW`IfFOAV_P8!RF;49i;7cyHRiWYW(WN z?t21b8B9-i8@ma@RgmBDw&Wk9SP3tKn0+5W>^4y?}@R7?o1P z;V?;JW4xd#mStJ1)xt2$vJ7^H{Y6n&V;jxww@pNj5fKd$0E%sjIXNJugXQy=+f&nT zdh44mom)P8>CCQud+xpW-j9Clw+F+`2OfCv(MKP<
(d+u4kE3L1uPfbk_!Jwap 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 z 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ðwtxoJ9(bh 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

!DFFc3mJlEOEBgN|>!i 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�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 z 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 Ef`X8P!2kdN From ebc6849b7171ea2d9ea5dac3d338ecf9b23d6f19 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Fri, 29 Dec 2017 16:53:04 +0100 Subject: [PATCH 25/59] :white_check_mark: added test for #894 --- test/src/unit-json_pointer.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/src/unit-json_pointer.cpp b/test/src/unit-json_pointer.cpp index 4af379c4..77851f6a 100644 --- a/test/src/unit-json_pointer.cpp +++ b/test/src/unit-json_pointer.cpp @@ -55,6 +55,15 @@ TEST_CASE("JSON pointers") CHECK_THROWS_AS(p.pop_back(), json::out_of_range&); CHECK_THROWS_WITH(p.pop_back(), "[json.exception.out_of_range.405] JSON pointer has no parent"); + + SECTION("array index error") + { + json v = {1, 2, 3, 4}; + json::json_pointer ptr("/10e"); + CHECK_THROWS_AS(v[ptr], json::out_of_range); + CHECK_THROWS_WITH(v[ptr], + "[json.exception.out_of_range.404] unresolved reference token '10e'"); + } } SECTION("examples from RFC 6901") From 92484f0caf635bdabef9a5182beea3502132f1b8 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Fri, 29 Dec 2017 18:31:13 +0100 Subject: [PATCH 26/59] :bookmark: set version to 3.0.1 --- CMakeLists.txt | 2 +- ChangeLog.md | 23 +++++++++++++++++++++++ README.md | 4 ++-- doc/Doxyfile | 2 +- doc/examples/README.link | 2 +- doc/examples/meta.output | 4 ++-- doc/index.md | 2 +- doc/json.gif | Bin 1457923 -> 4372509 bytes src/json.hpp | 24 ++++++++++++------------ test/src/fuzzer-driver_afl.cpp | 2 +- test/src/fuzzer-parse_cbor.cpp | 2 +- test/src/fuzzer-parse_json.cpp | 2 +- test/src/fuzzer-parse_msgpack.cpp | 2 +- test/src/unit-algorithms.cpp | 2 +- test/src/unit-allocator.cpp | 2 +- test/src/unit-capacity.cpp | 2 +- test/src/unit-cbor.cpp | 2 +- test/src/unit-class_const_iterator.cpp | 2 +- test/src/unit-class_iterator.cpp | 2 +- test/src/unit-class_lexer.cpp | 2 +- test/src/unit-class_parser.cpp | 2 +- test/src/unit-comparison.cpp | 2 +- test/src/unit-concepts.cpp | 2 +- test/src/unit-constructor1.cpp | 2 +- test/src/unit-constructor2.cpp | 2 +- test/src/unit-convenience.cpp | 2 +- test/src/unit-conversions.cpp | 2 +- test/src/unit-deserialization.cpp | 2 +- test/src/unit-element_access1.cpp | 2 +- test/src/unit-element_access2.cpp | 2 +- test/src/unit-inspection.cpp | 2 +- test/src/unit-iterator_wrapper.cpp | 2 +- test/src/unit-iterators1.cpp | 2 +- test/src/unit-iterators2.cpp | 2 +- test/src/unit-json_patch.cpp | 2 +- test/src/unit-json_pointer.cpp | 2 +- test/src/unit-meta.cpp | 6 +++--- test/src/unit-modifiers.cpp | 2 +- test/src/unit-msgpack.cpp | 2 +- test/src/unit-noexcept.cpp | 2 +- test/src/unit-pointer_access.cpp | 2 +- test/src/unit-readme.cpp | 2 +- test/src/unit-reference_access.cpp | 2 +- test/src/unit-regression.cpp | 2 +- test/src/unit-serialization.cpp | 2 +- test/src/unit-testsuites.cpp | 2 +- test/src/unit-udt.cpp | 2 +- test/src/unit-unicode.cpp | 2 +- test/src/unit.cpp | 2 +- 49 files changed, 85 insertions(+), 62 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cf0bbb61..257bee82 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 3.0.0) ## PROJECT ## name and version ## -project(nlohmann_json VERSION 3.0.0 LANGUAGES CXX) +project(nlohmann_json VERSION 3.0.1 LANGUAGES CXX) ## ## OPTIONS diff --git a/ChangeLog.md b/ChangeLog.md index 9db27833..bb95f937 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,6 +1,29 @@ # Change Log All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). +## [v3.0.1](https://github.com/nlohmann/json/releases/tag/v3.0.1) (2017-12-29) +[Full Changelog](https://github.com/nlohmann/json/compare/v3.0.0...v3.0.1) + +- Problem parsing array to global vector [\#896](https://github.com/nlohmann/json/issues/896) +- Invalid RFC6902 copy operation succeeds [\#894](https://github.com/nlohmann/json/issues/894) +- How to rename a key during looping? [\#893](https://github.com/nlohmann/json/issues/893) +- clang++-6.0 \(6.0.0-svn321357-1\) warning [\#892](https://github.com/nlohmann/json/issues/892) +- Make json.hpp aware of the modules TS? [\#891](https://github.com/nlohmann/json/issues/891) +- All enum values not handled in switch cases. \( -Wswitch-enum \) [\#889](https://github.com/nlohmann/json/issues/889) +- JSON Pointer resolve failure resulting in incorrect exception code [\#888](https://github.com/nlohmann/json/issues/888) +- Unexpected nested arrays from std::vector [\#886](https://github.com/nlohmann/json/issues/886) +- erase multiple elements from a json object [\#884](https://github.com/nlohmann/json/issues/884) +- Container function overview in Doxygen is not updated [\#883](https://github.com/nlohmann/json/issues/883) +- How to use this for binary file uploads [\#881](https://github.com/nlohmann/json/issues/881) +- Allow setting JSON\_BuildTests=OFF from parent CMakeLists.txt [\#846](https://github.com/nlohmann/json/issues/846) +- Unit test fails for local-independent str-to-num [\#845](https://github.com/nlohmann/json/issues/845) +- Another idea about type support [\#774](https://github.com/nlohmann/json/issues/774) + +- Includes CTest module/adds BUILD\_TESTING option [\#885](https://github.com/nlohmann/json/pull/885) ([TinyTinni](https://github.com/TinyTinni)) +- Fix MSVC warning C4819 [\#882](https://github.com/nlohmann/json/pull/882) ([erengy](https://github.com/erengy)) +- Merge branch 'develop' into coverity\_scan [\#880](https://github.com/nlohmann/json/pull/880) ([nlohmann](https://github.com/nlohmann)) +- :wrench: Fix up a few more effc++ items [\#858](https://github.com/nlohmann/json/pull/858) ([mattismyname](https://github.com/mattismyname)) + ## [v3.0.0](https://github.com/nlohmann/json/releases/tag/v3.0.0) (2017-12-17) [Full Changelog](https://github.com/nlohmann/json/compare/v2.1.1...v3.0.0) diff --git a/README.md b/README.md index c400ade1..256409e3 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [![Coverage Status](https://img.shields.io/coveralls/nlohmann/json.svg)](https://coveralls.io/r/nlohmann/json) [![Coverity Scan Build Status](https://scan.coverity.com/projects/5550/badge.svg)](https://scan.coverity.com/projects/nlohmann-json) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/f3732b3327e34358a0e9d1fe9f661f08)](https://www.codacy.com/app/nlohmann/json?utm_source=github.com&utm_medium=referral&utm_content=nlohmann/json&utm_campaign=Badge_Grade) -[![Try online](https://img.shields.io/badge/try-online-blue.svg)](https://wandbox.org/permlink/TZS6TQdqmEUcN8WW) +[![Try online](https://img.shields.io/badge/try-online-blue.svg)](https://wandbox.org/permlink/Op57X0V7fTf2tdwl) [![Documentation](https://img.shields.io/badge/docs-doxygen-blue.svg)](http://nlohmann.github.io/json) [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/nlohmann/json/master/LICENSE.MIT) [![Github Releases](https://img.shields.io/github/release/nlohmann/json.svg)](https://github.com/nlohmann/json/releases) @@ -946,7 +946,7 @@ The library itself contains of a single header file licensed under the MIT licen - [**send_to_wandbox**](https://github.com/nlohmann/json/blob/develop/doc/scripts/send_to_wandbox.py) to send code examples to [Wandbox](http://melpon.org/wandbox) - [**Travis**](https://travis-ci.org) for [continuous integration](https://travis-ci.org/nlohmann/json) on Linux and macOS - [**Valgrind**](http://valgrind.org) to check for correct memory management -- [**Wandbox**](http://melpon.org/wandbox) for [online examples](https://wandbox.org/permlink/TZS6TQdqmEUcN8WW) +- [**Wandbox**](http://melpon.org/wandbox) for [online examples](https://wandbox.org/permlink/Op57X0V7fTf2tdwl) ## Projects using JSON for Modern C++ diff --git a/doc/Doxyfile b/doc/Doxyfile index 56a8c589..878ee2ad 100644 --- a/doc/Doxyfile +++ b/doc/Doxyfile @@ -5,7 +5,7 @@ #--------------------------------------------------------------------------- DOXYFILE_ENCODING = UTF-8 PROJECT_NAME = "JSON for Modern C++" -PROJECT_NUMBER = 3.0.0 +PROJECT_NUMBER = 3.0.1 PROJECT_BRIEF = PROJECT_LOGO = OUTPUT_DIRECTORY = . diff --git a/doc/examples/README.link b/doc/examples/README.link index 06add2ac..5403e0d8 100644 --- a/doc/examples/README.link +++ b/doc/examples/README.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/examples/meta.output b/doc/examples/meta.output index 287d4380..1b3e2aa1 100644 --- a/doc/examples/meta.output +++ b/doc/examples/meta.output @@ -11,7 +11,7 @@ "version": { "major": 3, "minor": 0, - "patch": 0, - "string": "3.0.0" + "patch": 1, + "string": "3.0.1" } } diff --git a/doc/index.md b/doc/index.md index 122e8e6d..a72d9654 100644 --- a/doc/index.md +++ b/doc/index.md @@ -295,4 +295,4 @@ Note that this table only lists those exceptions thrown due to the type. For ins @author [Niels Lohmann](http://nlohmann.me) @see https://github.com/nlohmann/json to download the source code -@version 3.0.0 +@version 3.0.1 diff --git a/doc/json.gif b/doc/json.gif index dea04382abd37641c3334fd5437860aaf09f8436..2b5b5883009e2502f32f6fb7331db171cd019894 100644 GIT binary patch delta 101345 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

  • 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
  • 8$hw4KxUVg7$t+)A&ww@&}%sp|#29rz=! zcq>c90S=Ds3%^@LGqun5)dgZbAl3(B10Xg8Vk00n24WK+HU(lcAT|eL3m~=xVk;oF a24Wi^wgqB4Ahri$2OxIbKHJx+DGLCSj=`b; diff --git a/src/json.hpp b/src/json.hpp index 2da39903..5b0b0ea5 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ -| | |__ | | | | | | version 3.0.0 +| | |__ | | | | | | version 3.0.1 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . @@ -7519,7 +7519,7 @@ class basic_json result["url"] = "https://github.com/nlohmann/json"; result["version"] = { - {"string", "3.0.0"}, {"major", 3}, {"minor", 0}, {"patch", 0} + {"string", "3.0.1"}, {"major", 3}, {"minor", 0}, {"patch", 1} }; #ifdef _WIN32 @@ -8139,7 +8139,7 @@ class basic_json object = nullptr; // silence warning, see #821 if (JSON_UNLIKELY(t == value_t::null)) { - JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.0.0")); // LCOV_EXCL_LINE + JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.0.1")); // LCOV_EXCL_LINE } break; } @@ -14141,17 +14141,17 @@ class basic_json case patch_operations::copy: { - const std::string from_path = get_value("copy", "from", true); - const json_pointer from_ptr(from_path); + const std::string from_path = get_value("copy", "from", true); + const json_pointer from_ptr(from_path); - // the "from" location must exist - use at() - basic_json v = result.at(from_ptr); + // the "from" location must exist - use at() + basic_json v = result.at(from_ptr); - // The copy is functionally identical to an "add" - // operation at the target location using the value - // specified in the "from" member. - operation_add(ptr, v); - break; + // The copy is functionally identical to an "add" + // operation at the target location using the value + // specified in the "from" member. + operation_add(ptr, v); + break; } case patch_operations::test: diff --git a/test/src/fuzzer-driver_afl.cpp b/test/src/fuzzer-driver_afl.cpp index e4eb4a13..69fcec7c 100644 --- a/test/src/fuzzer-driver_afl.cpp +++ b/test/src/fuzzer-driver_afl.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (fuzz test support) -| | |__ | | | | | | version 3.0.0 +| | |__ | | | | | | version 3.0.1 |_____|_____|_____|_|___| https://github.com/nlohmann/json This file implements a driver for American Fuzzy Lop (afl-fuzz). It relies on diff --git a/test/src/fuzzer-parse_cbor.cpp b/test/src/fuzzer-parse_cbor.cpp index cf2ce821..576407bb 100644 --- a/test/src/fuzzer-parse_cbor.cpp +++ b/test/src/fuzzer-parse_cbor.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (fuzz test support) -| | |__ | | | | | | version 3.0.0 +| | |__ | | | | | | version 3.0.1 |_____|_____|_____|_|___| https://github.com/nlohmann/json This file implements a parser test suitable for fuzz testing. Given a byte diff --git a/test/src/fuzzer-parse_json.cpp b/test/src/fuzzer-parse_json.cpp index bacf628a..6b2b1154 100644 --- a/test/src/fuzzer-parse_json.cpp +++ b/test/src/fuzzer-parse_json.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (fuzz test support) -| | |__ | | | | | | version 3.0.0 +| | |__ | | | | | | version 3.0.1 |_____|_____|_____|_|___| https://github.com/nlohmann/json This file implements a parser test suitable for fuzz testing. Given a byte diff --git a/test/src/fuzzer-parse_msgpack.cpp b/test/src/fuzzer-parse_msgpack.cpp index ae9534f6..c3f9eb5d 100644 --- a/test/src/fuzzer-parse_msgpack.cpp +++ b/test/src/fuzzer-parse_msgpack.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (fuzz test support) -| | |__ | | | | | | version 3.0.0 +| | |__ | | | | | | version 3.0.1 |_____|_____|_____|_|___| https://github.com/nlohmann/json This file implements a parser test suitable for fuzz testing. Given a byte diff --git a/test/src/unit-algorithms.cpp b/test/src/unit-algorithms.cpp index b3f534d6..f74ca72e 100644 --- a/test/src/unit-algorithms.cpp +++ b/test/src/unit-algorithms.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.0.0 +| | |__ | | | | | | version 3.0.1 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-allocator.cpp b/test/src/unit-allocator.cpp index 183336e9..a182d989 100644 --- a/test/src/unit-allocator.cpp +++ b/test/src/unit-allocator.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.0.0 +| | |__ | | | | | | version 3.0.1 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-capacity.cpp b/test/src/unit-capacity.cpp index 971068ec..4df512a8 100644 --- a/test/src/unit-capacity.cpp +++ b/test/src/unit-capacity.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.0.0 +| | |__ | | | | | | version 3.0.1 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-cbor.cpp b/test/src/unit-cbor.cpp index 638ccefb..1e37a982 100644 --- a/test/src/unit-cbor.cpp +++ b/test/src/unit-cbor.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.0.0 +| | |__ | | | | | | version 3.0.1 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-class_const_iterator.cpp b/test/src/unit-class_const_iterator.cpp index 631656d6..5ecc9d6a 100644 --- a/test/src/unit-class_const_iterator.cpp +++ b/test/src/unit-class_const_iterator.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.0.0 +| | |__ | | | | | | version 3.0.1 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-class_iterator.cpp b/test/src/unit-class_iterator.cpp index 875f309e..45f28ef6 100644 --- a/test/src/unit-class_iterator.cpp +++ b/test/src/unit-class_iterator.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.0.0 +| | |__ | | | | | | version 3.0.1 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-class_lexer.cpp b/test/src/unit-class_lexer.cpp index 3f2d77cf..45355cd7 100644 --- a/test/src/unit-class_lexer.cpp +++ b/test/src/unit-class_lexer.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.0.0 +| | |__ | | | | | | version 3.0.1 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-class_parser.cpp b/test/src/unit-class_parser.cpp index 008ef432..91fd1819 100644 --- a/test/src/unit-class_parser.cpp +++ b/test/src/unit-class_parser.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.0.0 +| | |__ | | | | | | version 3.0.1 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-comparison.cpp b/test/src/unit-comparison.cpp index 7b1aa6e7..dbd7788b 100644 --- a/test/src/unit-comparison.cpp +++ b/test/src/unit-comparison.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.0.0 +| | |__ | | | | | | version 3.0.1 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-concepts.cpp b/test/src/unit-concepts.cpp index 981c89e1..dea1238d 100644 --- a/test/src/unit-concepts.cpp +++ b/test/src/unit-concepts.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.0.0 +| | |__ | | | | | | version 3.0.1 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-constructor1.cpp b/test/src/unit-constructor1.cpp index b216540a..9d93f6f5 100644 --- a/test/src/unit-constructor1.cpp +++ b/test/src/unit-constructor1.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.0.0 +| | |__ | | | | | | version 3.0.1 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-constructor2.cpp b/test/src/unit-constructor2.cpp index cf5e39f5..58545ad0 100644 --- a/test/src/unit-constructor2.cpp +++ b/test/src/unit-constructor2.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.0.0 +| | |__ | | | | | | version 3.0.1 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-convenience.cpp b/test/src/unit-convenience.cpp index fc9f299d..2bfef0fc 100644 --- a/test/src/unit-convenience.cpp +++ b/test/src/unit-convenience.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.0.0 +| | |__ | | | | | | version 3.0.1 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-conversions.cpp b/test/src/unit-conversions.cpp index 81978499..fb0ab4eb 100644 --- a/test/src/unit-conversions.cpp +++ b/test/src/unit-conversions.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.0.0 +| | |__ | | | | | | version 3.0.1 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-deserialization.cpp b/test/src/unit-deserialization.cpp index 2181bc4e..1da791a9 100644 --- a/test/src/unit-deserialization.cpp +++ b/test/src/unit-deserialization.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.0.0 +| | |__ | | | | | | version 3.0.1 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-element_access1.cpp b/test/src/unit-element_access1.cpp index 0a7f9645..e288cb5c 100644 --- a/test/src/unit-element_access1.cpp +++ b/test/src/unit-element_access1.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.0.0 +| | |__ | | | | | | version 3.0.1 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-element_access2.cpp b/test/src/unit-element_access2.cpp index 40cd8119..8f628f69 100644 --- a/test/src/unit-element_access2.cpp +++ b/test/src/unit-element_access2.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.0.0 +| | |__ | | | | | | version 3.0.1 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-inspection.cpp b/test/src/unit-inspection.cpp index 82fbf727..0043a9ec 100644 --- a/test/src/unit-inspection.cpp +++ b/test/src/unit-inspection.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.0.0 +| | |__ | | | | | | version 3.0.1 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-iterator_wrapper.cpp b/test/src/unit-iterator_wrapper.cpp index 137aca8a..e16ce16d 100644 --- a/test/src/unit-iterator_wrapper.cpp +++ b/test/src/unit-iterator_wrapper.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.0.0 +| | |__ | | | | | | version 3.0.1 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-iterators1.cpp b/test/src/unit-iterators1.cpp index d5d61932..8c5eddba 100644 --- a/test/src/unit-iterators1.cpp +++ b/test/src/unit-iterators1.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.0.0 +| | |__ | | | | | | version 3.0.1 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-iterators2.cpp b/test/src/unit-iterators2.cpp index 2ef5c0a8..d872890f 100644 --- a/test/src/unit-iterators2.cpp +++ b/test/src/unit-iterators2.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.0.0 +| | |__ | | | | | | version 3.0.1 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-json_patch.cpp b/test/src/unit-json_patch.cpp index 782853ad..3490f704 100644 --- a/test/src/unit-json_patch.cpp +++ b/test/src/unit-json_patch.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.0.0 +| | |__ | | | | | | version 3.0.1 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-json_pointer.cpp b/test/src/unit-json_pointer.cpp index 77851f6a..b6b83760 100644 --- a/test/src/unit-json_pointer.cpp +++ b/test/src/unit-json_pointer.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.0.0 +| | |__ | | | | | | version 3.0.1 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-meta.cpp b/test/src/unit-meta.cpp index 015e84be..f6e9d6f4 100644 --- a/test/src/unit-meta.cpp +++ b/test/src/unit-meta.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.0.0 +| | |__ | | | | | | version 3.0.1 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . @@ -42,10 +42,10 @@ TEST_CASE("version information") CHECK(j["url"] == "https://github.com/nlohmann/json"); CHECK(j["version"] == json( { - {"string", "3.0.0"}, + {"string", "3.0.1"}, {"major", 3}, {"minor", 0}, - {"patch", 0} + {"patch", 1} })); CHECK(j.find("platform") != j.end()); diff --git a/test/src/unit-modifiers.cpp b/test/src/unit-modifiers.cpp index e439c2f0..44b9cf2b 100644 --- a/test/src/unit-modifiers.cpp +++ b/test/src/unit-modifiers.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.0.0 +| | |__ | | | | | | version 3.0.1 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-msgpack.cpp b/test/src/unit-msgpack.cpp index 18bdbfec..531012b7 100644 --- a/test/src/unit-msgpack.cpp +++ b/test/src/unit-msgpack.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.0.0 +| | |__ | | | | | | version 3.0.1 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-noexcept.cpp b/test/src/unit-noexcept.cpp index ed294250..56ca4a41 100644 --- a/test/src/unit-noexcept.cpp +++ b/test/src/unit-noexcept.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.0.0 +| | |__ | | | | | | version 3.0.1 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-pointer_access.cpp b/test/src/unit-pointer_access.cpp index 068330c6..19254907 100644 --- a/test/src/unit-pointer_access.cpp +++ b/test/src/unit-pointer_access.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.0.0 +| | |__ | | | | | | version 3.0.1 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-readme.cpp b/test/src/unit-readme.cpp index 8f9f7e0a..ebf10583 100644 --- a/test/src/unit-readme.cpp +++ b/test/src/unit-readme.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.0.0 +| | |__ | | | | | | version 3.0.1 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-reference_access.cpp b/test/src/unit-reference_access.cpp index fd020221..ea84c9e7 100644 --- a/test/src/unit-reference_access.cpp +++ b/test/src/unit-reference_access.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.0.0 +| | |__ | | | | | | version 3.0.1 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-regression.cpp b/test/src/unit-regression.cpp index 1a93db28..a119ed72 100644 --- a/test/src/unit-regression.cpp +++ b/test/src/unit-regression.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.0.0 +| | |__ | | | | | | version 3.0.1 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-serialization.cpp b/test/src/unit-serialization.cpp index ce48b551..5668b7ba 100644 --- a/test/src/unit-serialization.cpp +++ b/test/src/unit-serialization.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.0.0 +| | |__ | | | | | | version 3.0.1 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-testsuites.cpp b/test/src/unit-testsuites.cpp index 861419b5..aad2b1d8 100644 --- a/test/src/unit-testsuites.cpp +++ b/test/src/unit-testsuites.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.0.0 +| | |__ | | | | | | version 3.0.1 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-udt.cpp b/test/src/unit-udt.cpp index f32acbbe..4fd6f7ec 100644 --- a/test/src/unit-udt.cpp +++ b/test/src/unit-udt.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.0.0 +| | |__ | | | | | | version 3.0.1 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-unicode.cpp b/test/src/unit-unicode.cpp index 24b13f95..3b2a239b 100644 --- a/test/src/unit-unicode.cpp +++ b/test/src/unit-unicode.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.0.0 +| | |__ | | | | | | version 3.0.1 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit.cpp b/test/src/unit.cpp index b08408d3..1ad77ce2 100644 --- a/test/src/unit.cpp +++ b/test/src/unit.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.0.0 +| | |__ | | | | | | version 3.0.1 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . From ba2316372abc57f7981fafe1833020102e66d838 Mon Sep 17 00:00:00 2001 From: Tobias Hermann Date: Wed, 3 Jan 2018 11:06:32 +0100 Subject: [PATCH 27/59] fix link to the documentation of the emplace function --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 256409e3..d64bbe1d 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,7 @@ If you are using [vcpkg](https://github.com/Microsoft/vcpkg/) on your project fo ## Examples -Beside the examples below, you may want to check the [documentation](https://nlohmann.github.io/json/) where each function contains a separate code example (e.g., check out [`emplace()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a602f275f0359ab181221384989810604.html#a602f275f0359ab181221384989810604)). All [example files](https://github.com/nlohmann/json/tree/develop/doc/examples) can be compiled and executed on their own (e.g., file [emplace.cpp](https://github.com/nlohmann/json/blob/develop/doc/examples/emplace.cpp)). +Beside the examples below, you may want to check the [documentation](https://nlohmann.github.io/json/) where each function contains a separate code example (e.g., check out [`emplace()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a5338e282d1d02bed389d852dd670d98d.html#a5338e282d1d02bed389d852dd670d98d)). All [example files](https://github.com/nlohmann/json/tree/develop/doc/examples) can be compiled and executed on their own (e.g., file [emplace.cpp](https://github.com/nlohmann/json/blob/develop/doc/examples/emplace.cpp)). ### JSON as first-class data type From 96b40b27a50c26d89527b7c74eb702667ff24472 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Fri, 5 Jan 2018 18:33:42 +0100 Subject: [PATCH 28/59] :memo: fixed Doxygen warnings Apparently, using "\n" inside an alias is an error now, but "^^" basically means the same. --- doc/Doxyfile | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/doc/Doxyfile b/doc/Doxyfile index 878ee2ad..4c64dd6f 100644 --- a/doc/Doxyfile +++ b/doc/Doxyfile @@ -1,4 +1,4 @@ -# Doxyfile 1.8.14 +# Doxyfile 1.8.15 #--------------------------------------------------------------------------- # Project related configuration options @@ -12,6 +12,7 @@ OUTPUT_DIRECTORY = . CREATE_SUBDIRS = NO ALLOW_UNICODE_NAMES = NO OUTPUT_LANGUAGE = English +OUTPUT_TEXT_DIRECTION = None BRIEF_MEMBER_DESC = YES REPEAT_BRIEF = NO ABBREVIATE_BRIEF = @@ -27,11 +28,11 @@ MULTILINE_CPP_IS_BRIEF = NO INHERIT_DOCS = YES SEPARATE_MEMBER_PAGES = YES TAB_SIZE = 4 -ALIASES = "complexity=@par Complexity\n" \ - "liveexample{2}=@par Example\n \1 \n @includelineno \2.cpp \n Output (play with this example @htmlinclude \2.link):\n @verbinclude \2.output \n The example code above can be translated with @verbatim g++ -std=c++11 -Isrc doc/examples/\2.cpp -o \2 @endverbatim" \ - "requirement=@par Requirements\n" \ - "exceptionsafety=@par Exception safety\n" \ - "iterators=@par Iterator validity\n" +ALIASES = "complexity=@par Complexity^^" \ + "liveexample{2}=@par Example^^ \1 ^^ @includelineno \2.cpp \n Output (play with this example @htmlinclude \2.link):^^ @verbinclude \2.output ^^ The example code above can be translated with @verbatim g++ -std=c++11 -Isrc doc/examples/\2.cpp -o \2 @endverbatim" \ + "requirement=@par Requirements^^" \ + "exceptionsafety=@par Exception safety^^" \ + "iterators=@par Iterator validity^^" TCL_SUBST = OPTIMIZE_OUTPUT_FOR_C = NO OPTIMIZE_OUTPUT_JAVA = NO @@ -107,7 +108,8 @@ WARN_LOGFILE = # Configuration options related to the input files #--------------------------------------------------------------------------- INPUT = ../src/json.hpp \ - index.md faq.md + index.md \ + faq.md INPUT_ENCODING = UTF-8 FILE_PATTERNS = RECURSIVE = NO @@ -138,6 +140,7 @@ USE_HTAGS = NO VERBATIM_HEADERS = NO CLANG_ASSISTED_PARSING = YES CLANG_OPTIONS = -std=c++11 +CLANG_COMPILATION_DATABASE_PATH = 0 #--------------------------------------------------------------------------- # Configuration options related to the alphabetical class index #--------------------------------------------------------------------------- From 78f8f837e6bd8fb0c3537bd08d0595505045290a Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Fri, 5 Jan 2018 18:34:10 +0100 Subject: [PATCH 29/59] added items() function #874 --- doc/examples/items.cpp | 23 + doc/examples/items.link | 1 + doc/examples/items.output | 7 + src/json.hpp | 62 +++ test/src/unit-iterator_wrapper.cpp | 697 +++++++++++++++++++++++++++++ 5 files changed, 790 insertions(+) create mode 100644 doc/examples/items.cpp create mode 100644 doc/examples/items.link create mode 100644 doc/examples/items.output diff --git a/doc/examples/items.cpp b/doc/examples/items.cpp new file mode 100644 index 00000000..b2224d60 --- /dev/null +++ b/doc/examples/items.cpp @@ -0,0 +1,23 @@ +#include +#include "json.hpp" + +using json = nlohmann::json; + +int main() +{ + // create JSON values + json j_object = {{"one", 1}, {"two", 2}}; + json j_array = {1, 2, 4, 8, 16}; + + // example for an object + for (auto& x : j_object.items()) + { + std::cout << "key: " << x.key() << ", value: " << x.value() << '\n'; + } + + // example for an array + for (auto& x : j_array.items()) + { + std::cout << "key: " << x.key() << ", value: " << x.value() << '\n'; + } +} diff --git a/doc/examples/items.link b/doc/examples/items.link new file mode 100644 index 00000000..0b74c5b3 --- /dev/null +++ b/doc/examples/items.link @@ -0,0 +1 @@ +online \ No newline at end of file diff --git a/doc/examples/items.output b/doc/examples/items.output new file mode 100644 index 00000000..89b09f52 --- /dev/null +++ b/doc/examples/items.output @@ -0,0 +1,7 @@ +key: one, value: 1 +key: two, value: 2 +key: 0, value: 1 +key: 1, value: 2 +key: 2, value: 4 +key: 3, value: 8 +key: 4, value: 16 diff --git a/src/json.hpp b/src/json.hpp index 5b0b0ea5..a12fcbe3 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -11375,6 +11375,68 @@ class basic_json return iteration_proxy(ref); } + /*! + @brief helper to access iterator member functions in range-based for + + This function allows to access @ref iterator::key() and @ref + iterator::value() during range-based for loops. In these loops, a + reference to the JSON values is returned, so there is no access to the + underlying iterator. + + For loop without `items()` function: + + @code{cpp} + for (auto it = j_object.begin(); it != j_object.end(); ++it) + { + std::cout << "key: " << it.key() << ", value:" << it.value() << '\n'; + } + @endcode + + Range-based for loop without `items()` function: + + @code{cpp} + for (auto it : j_object) + { + // "it" is of type json::reference and has no key() member + std::cout << "value: " << it << '\n'; + } + @endcode + + Range-based for loop with `items()` function: + + @code{cpp} + for (auto it : j_object.items()) + { + std::cout << "key: " << it.key() << ", value:" << it.value() << '\n'; + } + @endcode + + @note When iterating over an array, `key()` will return the index of the + element as string (see example). + + @return iteration proxy object wrapping @a ref with an interface to use in + range-based for loops + + @liveexample{The following code shows how the function is used.,items} + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Constant. + */ + iteration_proxy items() + { + return iteration_proxy(*this); + } + + /*! + @copydoc items() + */ + iteration_proxy items() const + { + return iteration_proxy(*this); + } + /// @} diff --git a/test/src/unit-iterator_wrapper.cpp b/test/src/unit-iterator_wrapper.cpp index e16ce16d..4f5bd15d 100644 --- a/test/src/unit-iterator_wrapper.cpp +++ b/test/src/unit-iterator_wrapper.cpp @@ -727,3 +727,700 @@ TEST_CASE("iterator_wrapper") } } } + +TEST_CASE("items()") +{ + SECTION("object") + { + SECTION("value") + { + json j = {{"A", 1}, {"B", 2}}; + int counter = 1; + + for (auto i : j.items()) + { + switch (counter++) + { + case 1: + { + CHECK(i.key() == "A"); + CHECK(i.value() == json(1)); + break; + } + + case 2: + { + CHECK(i.key() == "B"); + CHECK(i.value() == json(2)); + break; + } + + default: + { + break; + } + } + } + + CHECK(counter == 3); + } + + SECTION("reference") + { + json j = {{"A", 1}, {"B", 2}}; + int counter = 1; + + for (auto& i : j.items()) + { + switch (counter++) + { + case 1: + { + CHECK(i.key() == "A"); + CHECK(i.value() == json(1)); + + // change the value + i.value() = json(11); + CHECK(i.value() == json(11)); + break; + } + + case 2: + { + CHECK(i.key() == "B"); + CHECK(i.value() == json(2)); + + // change the value + i.value() = json(22); + CHECK(i.value() == json(22)); + break; + } + + default: + { + break; + } + } + } + + CHECK(counter == 3); + + // check if values where changed + CHECK(j == json({{"A", 11}, {"B", 22}})); + } + + SECTION("const value") + { + json j = {{"A", 1}, {"B", 2}}; + int counter = 1; + + for (const auto i : j.items()) + { + switch (counter++) + { + case 1: + { + CHECK(i.key() == "A"); + CHECK(i.value() == json(1)); + break; + } + + case 2: + { + CHECK(i.key() == "B"); + CHECK(i.value() == json(2)); + break; + } + + default: + { + break; + } + } + } + + CHECK(counter == 3); + } + + SECTION("const reference") + { + json j = {{"A", 1}, {"B", 2}}; + int counter = 1; + + for (const auto& i : j.items()) + { + switch (counter++) + { + case 1: + { + CHECK(i.key() == "A"); + CHECK(i.value() == json(1)); + break; + } + + case 2: + { + CHECK(i.key() == "B"); + CHECK(i.value() == json(2)); + break; + } + + default: + { + break; + } + } + } + + CHECK(counter == 3); + } + } + + SECTION("const object") + { + SECTION("value") + { + const json j = {{"A", 1}, {"B", 2}}; + int counter = 1; + + for (auto i : j.items()) + { + switch (counter++) + { + case 1: + { + CHECK(i.key() == "A"); + CHECK(i.value() == json(1)); + break; + } + + case 2: + { + CHECK(i.key() == "B"); + CHECK(i.value() == json(2)); + break; + } + + default: + { + break; + } + } + } + + CHECK(counter == 3); + } + + SECTION("reference") + { + const json j = {{"A", 1}, {"B", 2}}; + int counter = 1; + + for (auto& i : j.items()) + { + switch (counter++) + { + case 1: + { + CHECK(i.key() == "A"); + CHECK(i.value() == json(1)); + break; + } + + case 2: + { + CHECK(i.key() == "B"); + CHECK(i.value() == json(2)); + break; + } + + default: + { + break; + } + } + } + + CHECK(counter == 3); + } + + SECTION("const value") + { + const json j = {{"A", 1}, {"B", 2}}; + int counter = 1; + + for (const auto i : j.items()) + { + switch (counter++) + { + case 1: + { + CHECK(i.key() == "A"); + CHECK(i.value() == json(1)); + break; + } + + case 2: + { + CHECK(i.key() == "B"); + CHECK(i.value() == json(2)); + break; + } + + default: + { + break; + } + } + } + + CHECK(counter == 3); + } + + SECTION("const reference") + { + const json j = {{"A", 1}, {"B", 2}}; + int counter = 1; + + for (const auto& i : j.items()) + { + switch (counter++) + { + case 1: + { + CHECK(i.key() == "A"); + CHECK(i.value() == json(1)); + break; + } + + case 2: + { + CHECK(i.key() == "B"); + CHECK(i.value() == json(2)); + break; + } + + default: + { + break; + } + } + } + + CHECK(counter == 3); + } + } + + SECTION("array") + { + SECTION("value") + { + json j = {"A", "B"}; + int counter = 1; + + for (auto i : j.items()) + { + switch (counter++) + { + case 1: + { + CHECK(i.key() == "0"); + CHECK(i.value() == "A"); + break; + } + + case 2: + { + CHECK(i.key() == "1"); + CHECK(i.value() == "B"); + break; + } + + default: + { + break; + } + } + } + + CHECK(counter == 3); + } + + SECTION("reference") + { + json j = {"A", "B"}; + int counter = 1; + + for (auto& i : j.items()) + { + switch (counter++) + { + case 1: + { + CHECK(i.key() == "0"); + CHECK(i.value() == "A"); + + // change the value + i.value() = "AA"; + CHECK(i.value() == "AA"); + break; + } + + case 2: + { + CHECK(i.key() == "1"); + CHECK(i.value() == "B"); + + // change the value + i.value() = "BB"; + CHECK(i.value() == "BB"); + break; + } + + default: + { + break; + } + } + } + + CHECK(counter == 3); + + // check if values where changed + CHECK(j == json({"AA", "BB"})); + } + + SECTION("const value") + { + json j = {"A", "B"}; + int counter = 1; + + for (const auto i : j.items()) + { + switch (counter++) + { + case 1: + { + CHECK(i.key() == "0"); + CHECK(i.value() == "A"); + break; + } + + case 2: + { + CHECK(i.key() == "1"); + CHECK(i.value() == "B"); + break; + } + + default: + { + break; + } + } + } + + CHECK(counter == 3); + } + + SECTION("const reference") + { + json j = {"A", "B"}; + int counter = 1; + + for (const auto& i : j.items()) + { + switch (counter++) + { + case 1: + { + CHECK(i.key() == "0"); + CHECK(i.value() == "A"); + break; + } + + case 2: + { + CHECK(i.key() == "1"); + CHECK(i.value() == "B"); + break; + } + + default: + { + break; + } + } + } + + CHECK(counter == 3); + } + } + + SECTION("const array") + { + SECTION("value") + { + const json j = {"A", "B"}; + int counter = 1; + + for (auto i : j.items()) + { + switch (counter++) + { + case 1: + { + CHECK(i.key() == "0"); + CHECK(i.value() == "A"); + break; + } + + case 2: + { + CHECK(i.key() == "1"); + CHECK(i.value() == "B"); + break; + } + + default: + { + break; + } + } + } + + CHECK(counter == 3); + } + + SECTION("reference") + { + const json j = {"A", "B"}; + int counter = 1; + + for (auto& i : j.items()) + { + switch (counter++) + { + case 1: + { + CHECK(i.key() == "0"); + CHECK(i.value() == "A"); + break; + } + + case 2: + { + CHECK(i.key() == "1"); + CHECK(i.value() == "B"); + break; + } + + default: + { + break; + } + } + } + + CHECK(counter == 3); + } + + SECTION("const value") + { + const json j = {"A", "B"}; + int counter = 1; + + for (const auto i : j.items()) + { + switch (counter++) + { + case 1: + { + CHECK(i.key() == "0"); + CHECK(i.value() == "A"); + break; + } + + case 2: + { + CHECK(i.key() == "1"); + CHECK(i.value() == "B"); + break; + } + + default: + { + break; + } + } + } + + CHECK(counter == 3); + } + + SECTION("const reference") + { + const json j = {"A", "B"}; + int counter = 1; + + for (const auto& i : j.items()) + { + switch (counter++) + { + case 1: + { + CHECK(i.key() == "0"); + CHECK(i.value() == "A"); + break; + } + + case 2: + { + CHECK(i.key() == "1"); + CHECK(i.value() == "B"); + break; + } + + default: + { + break; + } + } + } + + CHECK(counter == 3); + } + } + + SECTION("primitive") + { + SECTION("value") + { + json j = 1; + int counter = 1; + + for (auto i : j.items()) + { + ++counter; + CHECK(i.key() == ""); + CHECK(i.value() == json(1)); + } + + CHECK(counter == 2); + } + + SECTION("reference") + { + json j = 1; + int counter = 1; + + for (auto& i : j.items()) + { + ++counter; + CHECK(i.key() == ""); + CHECK(i.value() == json(1)); + + // change value + i.value() = json(2); + } + + CHECK(counter == 2); + + // check if value has changed + CHECK(j == json(2)); + } + + SECTION("const value") + { + json j = 1; + int counter = 1; + + for (const auto i : j.items()) + { + ++counter; + CHECK(i.key() == ""); + CHECK(i.value() == json(1)); + } + + CHECK(counter == 2); + } + + SECTION("const reference") + { + json j = 1; + int counter = 1; + + for (const auto& i : j.items()) + { + ++counter; + CHECK(i.key() == ""); + CHECK(i.value() == json(1)); + } + + CHECK(counter == 2); + } + } + + SECTION("const primitive") + { + SECTION("value") + { + const json j = 1; + int counter = 1; + + for (auto i : j.items()) + { + ++counter; + CHECK(i.key() == ""); + CHECK(i.value() == json(1)); + } + + CHECK(counter == 2); + } + + SECTION("reference") + { + const json j = 1; + int counter = 1; + + for (auto& i : j.items()) + { + ++counter; + CHECK(i.key() == ""); + CHECK(i.value() == json(1)); + } + + CHECK(counter == 2); + } + + SECTION("const value") + { + const json j = 1; + int counter = 1; + + for (const auto i : j.items()) + { + ++counter; + CHECK(i.key() == ""); + CHECK(i.value() == json(1)); + } + + CHECK(counter == 2); + } + + SECTION("const reference") + { + const json j = 1; + int counter = 1; + + for (const auto& i : j.items()) + { + ++counter; + CHECK(i.key() == ""); + CHECK(i.value() == json(1)); + } + + CHECK(counter == 2); + } + } +} From 15b6421d0789a5402275358d43719f4b37979929 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Fri, 5 Jan 2018 23:26:22 +0100 Subject: [PATCH 30/59] :white_check_mark: added UTF-8 decoder capability and stress test As described in http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt; Markus Kuhn - 2015-08-28 - CC BY 4.0 --- test/data/markus_kuhn/UTF-8-test.txt | Bin 0 -> 22781 bytes test/src/unit-unicode.cpp | 392 +++++++++++++++++++++++++++ 2 files changed, 392 insertions(+) create mode 100644 test/data/markus_kuhn/UTF-8-test.txt diff --git a/test/data/markus_kuhn/UTF-8-test.txt b/test/data/markus_kuhn/UTF-8-test.txt new file mode 100644 index 0000000000000000000000000000000000000000..a5b5d50e6b61eb9a3b751b3954f83e61bb59db9b GIT binary patch literal 22781 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 literal 0 HcmV?d00001 diff --git a/test/src/unit-unicode.cpp b/test/src/unit-unicode.cpp index 3b2a239b..97fc2751 100644 --- a/test/src/unit-unicode.cpp +++ b/test/src/unit-unicode.cpp @@ -1076,3 +1076,395 @@ TEST_CASE("Unicode", "[hide]") CHECK_THROWS_AS(json::parse("\xef\xbb\xbb"), json::parse_error&); } } + +void roundtrip(bool success_expected, const std::string& s); + +void roundtrip(bool success_expected, const std::string& s) +{ + CAPTURE(s); + + // create JSON string value + json j = s; + // create JSON text + std::string ps = std::string("\"") + s + "\""; + + if (success_expected) + { + // serialization succeeds + CHECK_NOTHROW(j.dump()); + + // exclude parse test for U+0000 + if (s[0] != '\0') + { + // parsing JSON text succeeds + CHECK_NOTHROW(json::parse(ps)); + } + + // roundtrip succeeds + CHECK_NOTHROW(json::parse(j.dump())); + + // after roundtrip, the same string is stored + json jr = json::parse(j.dump()); + CHECK(jr.get() == s); + } + else + { + // serialization fails + CHECK_THROWS_AS(j.dump(), json::type_error&); + + // parsing JSON text fails + CHECK_THROWS_AS(json::parse(ps), json::parse_error&); + } +} + +TEST_CASE("Markus Kuhn's UTF-8 decoder capability and stress test") +{ + // Markus Kuhn - 2015-08-28 - CC BY 4.0 + // http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt + + SECTION("1 Some correct UTF-8 text") + { + roundtrip(true, "κόσμε"); + } + + SECTION("2 Boundary condition test cases") + { + SECTION("2.1 First possible sequence of a certain length") + { + // 2.1.1 1 byte (U-00000000) + roundtrip(true, std::string("\0", 1)); + // 2.1.2 2 bytes (U-00000080) + roundtrip(true, "\xc2\x80"); + // 2.1.3 3 bytes (U-00000800) + roundtrip(true, "\xe0\xa0\x80"); + // 2.1.4 4 bytes (U-00010000) + roundtrip(true, "\xf0\x90\x80\x80"); + + // 2.1.5 5 bytes (U-00200000) + roundtrip(false, "\xF8\x88\x80\x80\x80"); + // 2.1.6 6 bytes (U-04000000) + roundtrip(false, "\xFC\x84\x80\x80\x80\x80"); + } + + SECTION("2.2 Last possible sequence of a certain length") + { + // 2.2.1 1 byte (U-0000007F) + roundtrip(true, "\x7f"); + // 2.2.2 2 bytes (U-000007FF) + roundtrip(true, "\xdf\xbf"); + // 2.2.3 3 bytes (U-0000FFFF) + roundtrip(true, "\xef\xbf\xbf"); + + // 2.2.4 4 bytes (U-001FFFFF) + roundtrip(false, "\xF7\xBF\xBF\xBF"); + // 2.2.5 5 bytes (U-03FFFFFF) + roundtrip(false, "\xFB\xBF\xBF\xBF\xBF"); + // 2.2.6 6 bytes (U-7FFFFFFF) + roundtrip(false, "\xFD\xBF\xBF\xBF\xBF\xBF"); + } + + SECTION("2.3 Other boundary conditions") + { + // 2.3.1 U-0000D7FF = ed 9f bf + roundtrip(true, "\xed\x9f\xbf"); + // 2.3.2 U-0000E000 = ee 80 80 + roundtrip(true, "\xee\x80\x80"); + // 2.3.3 U-0000FFFD = ef bf bd + roundtrip(true, "\xef\xbf\xbd"); + // 2.3.4 U-0010FFFF = f4 8f bf bf + roundtrip(true, "\xf4\x8f\xbf\xbf"); + + // 2.3.5 U-00110000 = f4 90 80 80 + roundtrip(false, "\xf4\x90\x80\x80"); + } + } + + SECTION("3 Malformed sequences") + { + SECTION("3.1 Unexpected continuation bytes") + { + // Each unexpected continuation byte should be separately signalled as a + // malformed sequence of its own. + + // 3.1.1 First continuation byte 0x80 + roundtrip(false, "\x80"); + // 3.1.2 Last continuation byte 0xbf + roundtrip(false, "\xbf"); + + // 3.1.3 2 continuation bytes + roundtrip(false, "\x80\xbf"); + // 3.1.4 3 continuation bytes + roundtrip(false, "\x80\xbf\x80"); + // 3.1.5 4 continuation bytes + roundtrip(false, "\x80\xbf\x80\xbf"); + // 3.1.6 5 continuation bytes + roundtrip(false, "\x80\xbf\x80\xbf\x80"); + // 3.1.7 6 continuation bytes + roundtrip(false, "\x80\xbf\x80\xbf\x80\xbf"); + // 3.1.8 7 continuation bytes + roundtrip(false, "\x80\xbf\x80\xbf\x80\xbf\x80"); + + // 3.1.9 Sequence of all 64 possible continuation bytes (0x80-0xbf) + roundtrip(false, "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"); + } + + SECTION("3.2 Lonely start characters") + { + // 3.2.1 All 32 first bytes of 2-byte sequences (0xc0-0xdf) + roundtrip(false, "\xc0 \xc1 \xc2 \xc3 \xc4 \xc5 \xc6 \xc7 \xc8 \xc9 \xca \xcb \xcc \xcd \xce \xcf \xd0 \xd1 \xd2 \xd3 \xd4 \xd5 \xd6 \xd7 \xd8 \xd9 \xda \xdb \xdc \xdd \xde \xdf"); + // 3.2.2 All 16 first bytes of 3-byte sequences (0xe0-0xef) + roundtrip(false, "\xe0 \xe1 \xe2 \xe3 \xe4 \xe5 \xe6 \xe7 \xe8 \xe9 \xea \xeb \xec \xed \xee \xef"); + // 3.2.3 All 8 first bytes of 4-byte sequences (0xf0-0xf7) + roundtrip(false, "\xf0 \xf1 \xf2 \xf3 \xf4 \xf5 \xf6 \xf7"); + // 3.2.4 All 4 first bytes of 5-byte sequences (0xf8-0xfb) + roundtrip(false, "\xf8 \xf9 \xfa \xfb"); + // 3.2.5 All 2 first bytes of 6-byte sequences (0xfc-0xfd) + roundtrip(false, "\xfc \xfd"); + } + + SECTION("3.3 Sequences with last continuation byte missing") + { + // All bytes of an incomplete sequence should be signalled as a single + // malformed sequence, i.e., you should see only a single replacement + // character in each of the next 10 tests. (Characters as in section 2) + + // 3.3.1 2-byte sequence with last byte missing (U+0000) + roundtrip(false, "\xc0"); + // 3.3.2 3-byte sequence with last byte missing (U+0000) + roundtrip(false, "\xe0\x80"); + // 3.3.3 4-byte sequence with last byte missing (U+0000) + roundtrip(false, "\xf0\x80\x80"); + // 3.3.4 5-byte sequence with last byte missing (U+0000) + roundtrip(false, "\xf8\x80\x80\x80"); + // 3.3.5 6-byte sequence with last byte missing (U+0000) + roundtrip(false, "\xfc\x80\x80\x80\x80"); + // 3.3.6 2-byte sequence with last byte missing (U-000007FF) + roundtrip(false, "\xdf"); + // 3.3.7 3-byte sequence with last byte missing (U-0000FFFF) + roundtrip(false, "\xef\xbf"); + // 3.3.8 4-byte sequence with last byte missing (U-001FFFFF) + roundtrip(false, "\xf7\xbf\xbf"); + // 3.3.9 5-byte sequence with last byte missing (U-03FFFFFF) + roundtrip(false, "\xfb\xbf\xbf\xbf"); + // 3.3.10 6-byte sequence with last byte missing (U-7FFFFFFF) + roundtrip(false, "\xfd\xbf\xbf\xbf\xbf"); + } + + SECTION("3.4 Concatenation of incomplete sequences") + { + // All the 10 sequences of 3.3 concatenated, you should see 10 malformed + // sequences being signalled: + roundtrip(false, "\xc0\xe0\x80\xf0\x80\x80\xf8\x80\x80\x80\xfc\x80\x80\x80\x80\xdf\xef\xbf\xf7\xbf\xbf\xfb\xbf\xbf\xbf\xfd\xbf\xbf\xbf\xbf"); + } + + SECTION("3.5 Impossible bytes") + { + // The following two bytes cannot appear in a correct UTF-8 string + + // 3.5.1 fe + roundtrip(false, "\xfe"); + // 3.5.2 ff + roundtrip(false, "\xff"); + // 3.5.3 fe fe ff ff + roundtrip(false, "\xfe\xfe\xff\xff"); + } + } + + SECTION("4 Overlong sequences") + { + // The following sequences are not malformed according to the letter of + // the Unicode 2.0 standard. However, they are longer then necessary and + // a correct UTF-8 encoder is not allowed to produce them. A "safe UTF-8 + // decoder" should reject them just like malformed sequences for two + // reasons: (1) It helps to debug applications if overlong sequences are + // not treated as valid representations of characters, because this helps + // to spot problems more quickly. (2) Overlong sequences provide + // alternative representations of characters, that could maliciously be + // used to bypass filters that check only for ASCII characters. For + // instance, a 2-byte encoded line feed (LF) would not be caught by a + // line counter that counts only 0x0a bytes, but it would still be + // processed as a line feed by an unsafe UTF-8 decoder later in the + // pipeline. From a security point of view, ASCII compatibility of UTF-8 + // sequences means also, that ASCII characters are *only* allowed to be + // represented by ASCII bytes in the range 0x00-0x7f. To ensure this + // aspect of ASCII compatibility, use only "safe UTF-8 decoders" that + // reject overlong UTF-8 sequences for which a shorter encoding exists. + + SECTION("4.1 Examples of an overlong ASCII character") + { + // With a safe UTF-8 decoder, all of the following five overlong + // representations of the ASCII character slash ("/") should be rejected + // like a malformed UTF-8 sequence, for instance by substituting it with + // a replacement character. If you see a slash below, you do not have a + // safe UTF-8 decoder! + + // 4.1.1 U+002F = c0 af + roundtrip(false, "\xc0\xaf"); + // 4.1.2 U+002F = e0 80 af + roundtrip(false, "\xe0\x80\xaf"); + // 4.1.3 U+002F = f0 80 80 af + roundtrip(false, "\xf0\x80\x80\xaf"); + // 4.1.4 U+002F = f8 80 80 80 af + roundtrip(false, "\xf8\x80\x80\x80\xaf"); + // 4.1.5 U+002F = fc 80 80 80 80 af + roundtrip(false, "\xfc\x80\x80\x80\x80\xaf"); + } + + SECTION("4.2 Maximum overlong sequences") + { + // Below you see the highest Unicode value that is still resulting in an + // overlong sequence if represented with the given number of bytes. This + // is a boundary test for safe UTF-8 decoders. All five characters should + // be rejected like malformed UTF-8 sequences. + + // 4.2.1 U-0000007F = c1 bf + roundtrip(false, "\xc1\xbf"); + // 4.2.2 U-000007FF = e0 9f bf + roundtrip(false, "\xe0\x9f\xbf"); + // 4.2.3 U-0000FFFF = f0 8f bf bf + roundtrip(false, "\xf0\x8f\xbf\xbf"); + // 4.2.4 U-001FFFFF = f8 87 bf bf bf + roundtrip(false, "\xf8\x87\xbf\xbf\xbf"); + // 4.2.5 U-03FFFFFF = fc 83 bf bf bf bf + roundtrip(false, "\xfc\x83\xbf\xbf\xbf\xbf"); + } + + SECTION("4.3 Overlong representation of the NUL character") + { + // The following five sequences should also be rejected like malformed + // UTF-8 sequences and should not be treated like the ASCII NUL + // character. + + // 4.3.1 U+0000 = c0 80 + roundtrip(false, "\xc0\x80"); + // 4.3.2 U+0000 = e0 80 80 + roundtrip(false, "\xe0\x80\x80"); + // 4.3.3 U+0000 = f0 80 80 80 + roundtrip(false, "\xf0\x80\x80\x80"); + // 4.3.4 U+0000 = f8 80 80 80 80 + roundtrip(false, "\xf8\x80\x80\x80\x80"); + // 4.3.5 U+0000 = fc 80 80 80 80 80 + roundtrip(false, "\xfc\x80\x80\x80\x80\x80"); + } + } + + SECTION("5 Illegal code positions") + { + // The following UTF-8 sequences should be rejected like malformed + // sequences, because they never represent valid ISO 10646 characters and + // a UTF-8 decoder that accepts them might introduce security problems + // comparable to overlong UTF-8 sequences. + + SECTION("5.1 Single UTF-16 surrogates") + { + // 5.1.1 U+D800 = ed a0 80 + roundtrip(false, "\xed\xa0\x80"); + // 5.1.2 U+DB7F = ed ad bf + roundtrip(false, "\xed\xad\xbf"); + // 5.1.3 U+DB80 = ed ae 80 + roundtrip(false, "\xed\xae\x80"); + // 5.1.4 U+DBFF = ed af bf + roundtrip(false, "\xed\xaf\xbf"); + // 5.1.5 U+DC00 = ed b0 80 + roundtrip(false, "\xed\xb0\x80"); + // 5.1.6 U+DF80 = ed be 80 + roundtrip(false, "\xed\xbe\x80"); + // 5.1.7 U+DFFF = ed bf bf + roundtrip(false, "\xed\xbf\xbf"); + } + + SECTION("5.2 Paired UTF-16 surrogates") + { + // 5.2.1 U+D800 U+DC00 = ed a0 80 ed b0 80 + roundtrip(false, "\xed\xa0\x80\xed\xb0\x80"); + // 5.2.2 U+D800 U+DFFF = ed a0 80 ed bf bf + roundtrip(false, "\xed\xa0\x80\xed\xbf\xbf"); + // 5.2.3 U+DB7F U+DC00 = ed ad bf ed b0 80 + roundtrip(false, "\xed\xad\xbf\xed\xb0\x80"); + // 5.2.4 U+DB7F U+DFFF = ed ad bf ed bf bf + roundtrip(false, "\xed\xad\xbf\xed\xbf\xbf"); + // 5.2.5 U+DB80 U+DC00 = ed ae 80 ed b0 80 + roundtrip(false, "\xed\xae\x80\xed\xb0\x80"); + // 5.2.6 U+DB80 U+DFFF = ed ae 80 ed bf bf + roundtrip(false, "\xed\xae\x80\xed\xbf\xbf"); + // 5.2.7 U+DBFF U+DC00 = ed af bf ed b0 80 + roundtrip(false, "\xed\xaf\xbf\xed\xb0\x80"); + // 5.2.8 U+DBFF U+DFFF = ed af bf ed bf bf + roundtrip(false, "\xed\xaf\xbf\xed\xbf\xbf"); + } + + SECTION("5.3 Noncharacter code positions") + { + // The following "noncharacters" are "reserved for internal use" by + // applications, and according to older versions of the Unicode Standard + // "should never be interchanged". Unicode Corrigendum #9 dropped the + // latter restriction. Nevertheless, their presence in incoming UTF-8 data + // can remain a potential security risk, depending on what use is made of + // these codes subsequently. Examples of such internal use: + // + // - Some file APIs with 16-bit characters may use the integer value -1 + // = U+FFFF to signal an end-of-file (EOF) or error condition. + // + // - In some UTF-16 receivers, code point U+FFFE might trigger a + // byte-swap operation (to convert between UTF-16LE and UTF-16BE). + // + // With such internal use of noncharacters, it may be desirable and safer + // to block those code points in UTF-8 decoders, as they should never + // occur legitimately in incoming UTF-8 data, and could trigger unsafe + // behaviour in subsequent processing. + + // Particularly problematic noncharacters in 16-bit applications: + + // 5.3.1 U+FFFE = ef bf be + roundtrip(true, "\xef\xbf\xbe"); + // 5.3.2 U+FFFF = ef bf bf + roundtrip(true, "\xef\xbf\xbf"); + + // 5.3.3 U+FDD0 .. U+FDEF + roundtrip(true, "\xEF\xB7\x90"); + roundtrip(true, "\xEF\xB7\x91"); + roundtrip(true, "\xEF\xB7\x92"); + roundtrip(true, "\xEF\xB7\x93"); + roundtrip(true, "\xEF\xB7\x94"); + roundtrip(true, "\xEF\xB7\x95"); + roundtrip(true, "\xEF\xB7\x96"); + roundtrip(true, "\xEF\xB7\x97"); + roundtrip(true, "\xEF\xB7\x98"); + roundtrip(true, "\xEF\xB7\x99"); + roundtrip(true, "\xEF\xB7\x9A"); + roundtrip(true, "\xEF\xB7\x9B"); + roundtrip(true, "\xEF\xB7\x9C"); + roundtrip(true, "\xEF\xB7\x9D"); + roundtrip(true, "\xEF\xB7\x9E"); + roundtrip(true, "\xEF\xB7\x9F"); + roundtrip(true, "\xEF\xB7\xA0"); + roundtrip(true, "\xEF\xB7\xA1"); + roundtrip(true, "\xEF\xB7\xA2"); + roundtrip(true, "\xEF\xB7\xA3"); + roundtrip(true, "\xEF\xB7\xA4"); + roundtrip(true, "\xEF\xB7\xA5"); + roundtrip(true, "\xEF\xB7\xA6"); + roundtrip(true, "\xEF\xB7\xA7"); + roundtrip(true, "\xEF\xB7\xA8"); + roundtrip(true, "\xEF\xB7\xA9"); + roundtrip(true, "\xEF\xB7\xAA"); + roundtrip(true, "\xEF\xB7\xAB"); + roundtrip(true, "\xEF\xB7\xAC"); + roundtrip(true, "\xEF\xB7\xAD"); + roundtrip(true, "\xEF\xB7\xAE"); + roundtrip(true, "\xEF\xB7\xAF"); + + // 5.3.4 U+nFFFE U+nFFFF (for n = 1..10) + roundtrip(true, "\xF0\x9F\xBF\xBF"); + roundtrip(true, "\xF0\xAF\xBF\xBF"); + roundtrip(true, "\xF0\xBF\xBF\xBF"); + roundtrip(true, "\xF1\x8F\xBF\xBF"); + roundtrip(true, "\xF1\x9F\xBF\xBF"); + roundtrip(true, "\xF1\xAF\xBF\xBF"); + roundtrip(true, "\xF1\xBF\xBF\xBF"); + roundtrip(true, "\xF2\x8F\xBF\xBF"); + roundtrip(true, "\xF2\x9F\xBF\xBF"); + roundtrip(true, "\xF2\xAF\xBF\xBF"); + } + } +} From 5bffc95773c6dc57c9a1e6162fa7ff81389373ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20DELRIEU?= Date: Mon, 14 Aug 2017 14:41:01 +0200 Subject: [PATCH 31/59] add json_fwd.hpp --- Makefile | 8 ++++-- src/json.hpp | 54 ++--------------------------------------- src/json_fwd.hpp | 63 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+), 54 deletions(-) create mode 100644 src/json_fwd.hpp diff --git a/Makefile b/Makefile index b07fb6b0..b8b74628 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,10 @@ .PHONY: pretty clean ChangeLog.md +SRCDIR = src +SRCS = ${SRCDIR}/json.hpp \ + ${SRCDIR}/json_fwd.hpp + +# main target all: @echo "ChangeLog.md - generate ChangeLog file" @echo "check - compile and execute test suite" @@ -218,10 +223,9 @@ pretty: --indent-col1-comments --pad-oper --pad-header --align-pointer=type \ --align-reference=type --add-brackets --convert-tabs --close-templates \ --lineend=linux --preserve-date --suffix=none --formatted \ - src/json.hpp test/src/*.cpp \ + $(SRCS) test/src/*.cpp \ benchmarks/src/benchmarks.cpp doc/examples/*.cpp - ########################################################################## # changelog ########################################################################## diff --git a/src/json.hpp b/src/json.hpp index a12fcbe3..3768af0a 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -36,7 +36,6 @@ SOFTWARE. #include // lconv, localeconv #include // isfinite, labs, ldexp, signbit #include // nullptr_t, ptrdiff_t, size_t -#include // int64_t, uint64_t #include // abort, strtod, strtof, strtold, strtoul, strtoll, strtoull #include // memcpy, strlen #include // forward_list @@ -47,15 +46,13 @@ SOFTWARE. #include // advance, begin, back_inserter, bidirectional_iterator_tag, distance, end, inserter, iterator, iterator_traits, next, random_access_iterator_tag, reverse_iterator #include // numeric_limits #include // locale -#include // map -#include // addressof, allocator, allocator_traits, unique_ptr #include // accumulate #include // stringstream -#include // getline, stoi, string, to_string #include // add_pointer, conditional, decay, enable_if, false_type, integral_constant, is_arithmetic, is_base_of, is_const, is_constructible, is_convertible, is_default_constructible, is_enum, is_floating_point, is_integral, is_nothrow_move_assignable, is_nothrow_move_constructible, is_pointer, is_reference, is_same, is_scalar, is_signed, remove_const, remove_cv, remove_pointer, remove_reference, true_type, underlying_type #include // declval, forward, make_pair, move, pair, swap #include // valarray -#include // vector + +#include "json_fwd.hpp" // exclude unsupported compilers #if defined(__clang__) @@ -124,20 +121,6 @@ SOFTWARE. */ namespace nlohmann { -template -struct adl_serializer; - -// forward declaration of basic_json (required to split the class) -template class ObjectType = std::map, - template class ArrayType = std::vector, - class StringType = std::string, class BooleanType = bool, - class NumberIntegerType = std::int64_t, - class NumberUnsignedType = std::uint64_t, - class NumberFloatType = double, - template class AllocatorType = std::allocator, - template class JSONSerializer = adl_serializer> -class basic_json; - // Ugly macros to avoid uglier copy-paste when specializing basic_json. They // may be removed in the future once the class is split. @@ -6896,14 +6879,6 @@ constexpr const auto& to_json = detail::static_const::value; constexpr const auto& from_json = detail::static_const::value; } - -/*! -@brief default JSONSerializer template argument - -This serializer ignores the template arguments and uses ADL -([argument-dependent lookup](http://en.cppreference.com/w/cpp/language/adl)) -for serialization. -*/ template struct adl_serializer { @@ -6940,17 +6915,6 @@ struct adl_serializer } }; -/*! -@brief JSON Pointer - -A JSON pointer defines a string syntax for identifying a specific value -within a JSON document. It can be used with functions `at` and -`operator[]`. Furthermore, JSON pointers are the base for JSON patches. - -@sa [RFC 6901](https://tools.ietf.org/html/rfc6901) - -@since version 2.0.0 -*/ class json_pointer { /// allow basic_json to access private members @@ -14411,20 +14375,6 @@ class basic_json /// @} }; -///////////// -// presets // -///////////// - -/*! -@brief default JSON class - -This type is the default specialization of the @ref basic_json class which -uses the standard template types. - -@since version 1.0.0 -*/ -using json = basic_json<>; - ////////////////// // json_pointer // ////////////////// diff --git a/src/json_fwd.hpp b/src/json_fwd.hpp new file mode 100644 index 00000000..a068da18 --- /dev/null +++ b/src/json_fwd.hpp @@ -0,0 +1,63 @@ +#ifndef NLOHMANN_JSON_FWD_HPP +#define NLOHMANN_JSON_FWD_HPP + +#include // int64_t, uint64_t +#include // map +#include // addressof, allocator, allocator_traits, unique_ptr +#include // getline, stoi, string, to_string +#include // vector + +/*! +@brief namespace for Niels Lohmann +@see https://github.com/nlohmann +@since version 1.0.0 +*/ +namespace nlohmann +{ +/*! +@brief default JSONSerializer template argument + +This serializer ignores the template arguments and uses ADL +([argument-dependent lookup](http://en.cppreference.com/w/cpp/language/adl)) +for serialization. +*/ +template +struct adl_serializer; + +template class ObjectType = + std::map, + template class ArrayType = std::vector, + class StringType = std::string, class BooleanType = bool, + class NumberIntegerType = std::int64_t, + class NumberUnsignedType = std::uint64_t, + class NumberFloatType = double, + template class AllocatorType = std::allocator, + template class JSONSerializer = + adl_serializer> +class basic_json; + +/*! +@brief JSON Pointer + +A JSON pointer defines a string syntax for identifying a specific value +within a JSON document. It can be used with functions `at` and +`operator[]`. Furthermore, JSON pointers are the base for JSON patches. + +@sa [RFC 6901](https://tools.ietf.org/html/rfc6901) + +@since version 2.0.0 +*/ +class json_pointer; + +/*! +@brief default JSON class + +This type is the default specialization of the @ref basic_json class which +uses the standard template types. + +@since version 1.0.0 +*/ +using json = basic_json<>; +} + +#endif From d686713f9138dd728b55a89af9738c755aea22f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20DELRIEU?= Date: Mon, 14 Aug 2017 14:59:17 +0200 Subject: [PATCH 32/59] add detail/macro_{un}scope.hpp --- Makefile | 4 +- src/detail/macro_scope.hpp | 104 ++++++++++++++++++++++++++++++ src/detail/macro_unscope.hpp | 25 ++++++++ src/json.hpp | 120 +---------------------------------- 4 files changed, 134 insertions(+), 119 deletions(-) create mode 100644 src/detail/macro_scope.hpp create mode 100644 src/detail/macro_unscope.hpp diff --git a/Makefile b/Makefile index b8b74628..3f1e3337 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,9 @@ SRCDIR = src SRCS = ${SRCDIR}/json.hpp \ - ${SRCDIR}/json_fwd.hpp + ${SRCDIR}/json_fwd.hpp \ + ${SRCDIR}/detail/macro_scope.hpp \ + ${SRCDIR}/detail/macro_unscope.hpp # main target all: diff --git a/src/detail/macro_scope.hpp b/src/detail/macro_scope.hpp new file mode 100644 index 00000000..b2ac7742 --- /dev/null +++ b/src/detail/macro_scope.hpp @@ -0,0 +1,104 @@ +#ifndef NLOHMANN_JSON_MACRO_SCOPE_HPP +#define NLOHMANN_JSON_MACRO_SCOPE_HPP + +// This file contains all internal macro definitions +// You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them + +// exclude unsupported compilers +#if defined(__clang__) + #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400 + #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" + #endif +#elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER)) + #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40900 + #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" + #endif +#endif + +// disable float-equal warnings on GCC/clang +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wfloat-equal" +#endif + +// disable documentation warnings on clang +#if defined(__clang__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wdocumentation" +#endif + +// allow for portable deprecation warnings +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #define JSON_DEPRECATED __attribute__((deprecated)) +#elif defined(_MSC_VER) + #define JSON_DEPRECATED __declspec(deprecated) +#else + #define JSON_DEPRECATED +#endif + +// allow to disable exceptions +#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && not defined(JSON_NOEXCEPTION) + #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 + +// manual branch prediction +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #define JSON_LIKELY(x) __builtin_expect(!!(x), 1) + #define JSON_UNLIKELY(x) __builtin_expect(!!(x), 0) +#else + #define JSON_LIKELY(x) x + #define JSON_UNLIKELY(x) x +#endif + +// C++ language standard detection +#if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 + #define JSON_HAS_CPP_17 + #define JSON_HAS_CPP_14 +#elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) + #define JSON_HAS_CPP_14 +#endif + +// Ugly macros to avoid uglier copy-paste when specializing basic_json. They +// may be removed in the future once the class is split. + +#define NLOHMANN_BASIC_JSON_TPL_DECLARATION \ + template class ObjectType, \ + template class ArrayType, \ + class StringType, class BooleanType, class NumberIntegerType, \ + class NumberUnsignedType, class NumberFloatType, \ + template class AllocatorType, \ + template class JSONSerializer> + +#define NLOHMANN_BASIC_JSON_TPL \ + basic_json + +/*! +@brief Helper to determine whether there's a key_type for T. + +This helper is used to tell associative containers apart from other containers +such as sequence containers. For instance, `std::map` passes the test as it +contains a `mapped_type`, whereas `std::vector` fails the test. + +@sa http://stackoverflow.com/a/7728728/266378 +@since version 1.0.0, overworked in version 2.0.6 +*/ +#define NLOHMANN_JSON_HAS_HELPER(type) \ + template struct has_##type { \ + private: \ + template \ + static int detect(U &&); \ + static void detect(...); \ + public: \ + static constexpr bool value = \ + std::is_integral()))>::value; \ + } + +#endif diff --git a/src/detail/macro_unscope.hpp b/src/detail/macro_unscope.hpp new file mode 100644 index 00000000..9b8cf7b9 --- /dev/null +++ b/src/detail/macro_unscope.hpp @@ -0,0 +1,25 @@ +#ifndef NLOHMANN_JSON_DETAIL_MACRO_UNSCOPE_HPP +#define NLOHMANN_JSON_DETAIL_MACRO_UNSCOPE_HPP + +// restore GCC/clang diagnostic settings +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #pragma GCC diagnostic pop +#endif +#if defined(__clang__) + #pragma GCC diagnostic pop +#endif + +// clean up +#undef JSON_CATCH +#undef JSON_THROW +#undef JSON_TRY +#undef JSON_LIKELY +#undef JSON_UNLIKELY +#undef JSON_DEPRECATED +#undef JSON_HAS_CPP_14 +#undef JSON_HAS_CPP_17 +#undef NLOHMANN_BASIC_JSON_TPL_DECLARATION +#undef NLOHMANN_BASIC_JSON_TPL +#undef NLOHMANN_JSON_HAS_HELPER + +#endif diff --git a/src/json.hpp b/src/json.hpp index 3768af0a..3555400a 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -53,66 +53,7 @@ SOFTWARE. #include // valarray #include "json_fwd.hpp" - -// exclude unsupported compilers -#if defined(__clang__) - #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400 - #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" - #endif -#elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER)) - #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40900 - #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" - #endif -#endif - -// disable float-equal warnings on GCC/clang -#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wfloat-equal" -#endif - -// disable documentation warnings on clang -#if defined(__clang__) - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wdocumentation" -#endif - -// allow for portable deprecation warnings -#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) - #define JSON_DEPRECATED __attribute__((deprecated)) -#elif defined(_MSC_VER) - #define JSON_DEPRECATED __declspec(deprecated) -#else - #define JSON_DEPRECATED -#endif - -// allow to disable exceptions -#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && not defined(JSON_NOEXCEPTION) - #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 - -// manual branch prediction -#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) - #define JSON_LIKELY(x) __builtin_expect(!!(x), 1) - #define JSON_UNLIKELY(x) __builtin_expect(!!(x), 0) -#else - #define JSON_LIKELY(x) x - #define JSON_UNLIKELY(x) x -#endif - -// C++ language standard detection -#if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 - #define JSON_HAS_CPP_17 - #define JSON_HAS_CPP_14 -#elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) - #define JSON_HAS_CPP_14 -#endif +#include "detail/macro_scope.hpp" /*! @brief namespace for Niels Lohmann @@ -121,23 +62,6 @@ SOFTWARE. */ namespace nlohmann { -// Ugly macros to avoid uglier copy-paste when specializing basic_json. They -// may be removed in the future once the class is split. - -#define NLOHMANN_BASIC_JSON_TPL_DECLARATION \ - template class ObjectType, \ - template class ArrayType, \ - class StringType, class BooleanType, class NumberIntegerType, \ - class NumberUnsignedType, class NumberFloatType, \ - template class AllocatorType, \ - template class JSONSerializer> - -#define NLOHMANN_BASIC_JSON_TPL \ - basic_json - - /*! @brief unnamed namespace with internal helper functions @@ -771,35 +695,11 @@ struct external_constructor // has_/is_ functions // //////////////////////// -/*! -@brief Helper to determine whether there's a key_type for T. - -This helper is used to tell associative containers apart from other containers -such as sequence containers. For instance, `std::map` passes the test as it -contains a `mapped_type`, whereas `std::vector` fails the test. - -@sa http://stackoverflow.com/a/7728728/266378 -@since version 1.0.0, overworked in version 2.0.6 -*/ -#define NLOHMANN_JSON_HAS_HELPER(type) \ - template struct has_##type { \ - private: \ - template \ - static int detect(U &&); \ - static void detect(...); \ - public: \ - static constexpr bool value = \ - std::is_integral()))>::value; \ - } - NLOHMANN_JSON_HAS_HELPER(mapped_type); NLOHMANN_JSON_HAS_HELPER(key_type); NLOHMANN_JSON_HAS_HELPER(value_type); NLOHMANN_JSON_HAS_HELPER(iterator); -#undef NLOHMANN_JSON_HAS_HELPER - - template struct is_compatible_object_type_impl : std::false_type {}; @@ -14865,22 +14765,6 @@ inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std return nlohmann::json::json_pointer(std::string(s, n)); } -// restore GCC/clang diagnostic settings -#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) - #pragma GCC diagnostic pop -#endif -#if defined(__clang__) - #pragma GCC diagnostic pop -#endif - -// clean up -#undef JSON_CATCH -#undef JSON_THROW -#undef JSON_TRY -#undef JSON_LIKELY -#undef JSON_UNLIKELY -#undef JSON_DEPRECATED -#undef NLOHMANN_BASIC_JSON_TPL_DECLARATION -#undef NLOHMANN_BASIC_JSON_TPL +#include "detail/macro_unscope.hpp" #endif From f364f5ac5a4aa17c2af5a2d94d7b7f478e58ac43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20DELRIEU?= Date: Mon, 14 Aug 2017 15:06:35 +0200 Subject: [PATCH 33/59] add detail/meta.hpp --- Makefile | 4 +- src/detail/meta.hpp | 226 ++++++++++++++++++++++++++++++++++++++++++++ src/json.hpp | 212 +---------------------------------------- 3 files changed, 230 insertions(+), 212 deletions(-) create mode 100644 src/detail/meta.hpp diff --git a/Makefile b/Makefile index 3f1e3337..6600e00b 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,9 @@ SRCDIR = src SRCS = ${SRCDIR}/json.hpp \ ${SRCDIR}/json_fwd.hpp \ ${SRCDIR}/detail/macro_scope.hpp \ - ${SRCDIR}/detail/macro_unscope.hpp + ${SRCDIR}/detail/macro_unscope.hpp \ + ${SRCDIR}/detail/meta.hpp + # main target all: diff --git a/src/detail/meta.hpp b/src/detail/meta.hpp new file mode 100644 index 00000000..9a3a97fa --- /dev/null +++ b/src/detail/meta.hpp @@ -0,0 +1,226 @@ +#ifndef NLOHMANN_JSON_DETAIL_META_HPP +#define NLOHMANN_JSON_DETAIL_META_HPP + +#include +#include +#include // add_pointer, conditional, decay, enable_if, false_type, integral_constant, is_arithmetic, is_base_of, is_const, is_constructible, is_convertible, is_default_constructible, is_enum, is_floating_point, is_integral, is_nothrow_move_assignable, is_nothrow_move_constructible, is_pointer, is_reference, is_same, is_scalar, is_signed, remove_const, remove_cv, remove_pointer, remove_reference, true_type, underlying_type +#include + +#include "json_fwd.hpp" +#include "detail/macro_scope.hpp" + +namespace nlohmann +{ +/*! +@brief detail namespace with internal helper functions + +This namespace collects functions that should not be exposed, +implementations of some @ref basic_json methods, and meta-programming helpers. + +@since version 2.1.0 +*/ +namespace detail +{ +///////////// +// helpers // +///////////// + +template struct is_basic_json : std::false_type {}; + +NLOHMANN_BASIC_JSON_TPL_DECLARATION +struct is_basic_json : std::true_type {}; + +// alias templates to reduce boilerplate +template +using enable_if_t = typename std::enable_if::type; + +template +using uncvref_t = typename std::remove_cv::type>::type; + +// implementation of C++14 index_sequence and affiliates +// source: https://stackoverflow.com/a/32223343 +template +struct index_sequence +{ + using type = index_sequence; + using value_type = std::size_t; + static constexpr std::size_t size() noexcept + { + return sizeof...(Ints); + } +}; + +template +struct merge_and_renumber; + +template +struct merge_and_renumber, index_sequence> + : index_sequence < I1..., (sizeof...(I1) + I2)... > {}; + +template +struct make_index_sequence + : merge_and_renumber < typename make_index_sequence < N / 2 >::type, + typename make_index_sequence < N - N / 2 >::type > {}; + +template<> struct make_index_sequence<0> : index_sequence<> {}; +template<> struct make_index_sequence<1> : index_sequence<0> {}; + +template +using index_sequence_for = make_index_sequence; + +/* +Implementation of two C++17 constructs: conjunction, negation. This is needed +to avoid evaluating all the traits in a condition + +For example: not std::is_same::value and has_value_type::value +will not compile when T = void (on MSVC at least). Whereas +conjunction>, has_value_type>::value will +stop evaluating if negation<...>::value == false + +Please note that those constructs must be used with caution, since symbols can +become very long quickly (which can slow down compilation and cause MSVC +internal compiler errors). Only use it when you have to (see example ahead). +*/ +template struct conjunction : std::true_type {}; +template struct conjunction : B1 {}; +template +struct conjunction : std::conditional, B1>::type {}; + +template struct negation : std::integral_constant {}; + +// dispatch utility (taken from ranges-v3) +template struct priority_tag : priority_tag < N - 1 > {}; +template<> struct priority_tag<0> {}; + +//////////////////////// +// has_/is_ functions // +//////////////////////// + +NLOHMANN_JSON_HAS_HELPER(mapped_type); +NLOHMANN_JSON_HAS_HELPER(key_type); +NLOHMANN_JSON_HAS_HELPER(value_type); +NLOHMANN_JSON_HAS_HELPER(iterator); + +template +struct is_compatible_object_type_impl : std::false_type {}; + +template +struct is_compatible_object_type_impl +{ + static constexpr auto value = + std::is_constructible::value and + std::is_constructible::value; +}; + +template +struct is_compatible_object_type +{ + static auto constexpr value = is_compatible_object_type_impl < + conjunction>, + has_mapped_type, + has_key_type>::value, + typename BasicJsonType::object_t, CompatibleObjectType >::value; +}; + +template +struct is_basic_json_nested_type +{ + static auto constexpr value = std::is_same::value or + std::is_same::value or + std::is_same::value or + std::is_same::value; +}; + +template +struct is_compatible_array_type +{ + static auto constexpr value = + conjunction>, + negation>, + negation>, + negation>, + has_value_type, + has_iterator>::value; +}; + +template +struct is_compatible_integer_type_impl : std::false_type {}; + +template +struct is_compatible_integer_type_impl +{ + // is there an assert somewhere on overflows? + using RealLimits = std::numeric_limits; + using CompatibleLimits = std::numeric_limits; + + static constexpr auto value = + std::is_constructible::value and + CompatibleLimits::is_integer and + RealLimits::is_signed == CompatibleLimits::is_signed; +}; + +template +struct is_compatible_integer_type +{ + static constexpr auto value = + is_compatible_integer_type_impl < + std::is_integral::value and + not std::is_same::value, + RealIntegerType, CompatibleNumberIntegerType > ::value; +}; + + +// trait checking if JSONSerializer::from_json(json const&, udt&) exists +template +struct has_from_json +{ + private: + // also check the return type of from_json + template::from_json( + std::declval(), std::declval()))>::value>> + static int detect(U&&); + static void detect(...); + + public: + static constexpr bool value = std::is_integral>()))>::value; +}; + +// This trait checks if JSONSerializer::from_json(json const&) exists +// this overload is used for non-default-constructible user-defined-types +template +struct has_non_default_from_json +{ + private: + template < + typename U, + typename = enable_if_t::from_json(std::declval()))>::value >> + static int detect(U&&); + static void detect(...); + + public: + static constexpr bool value = std::is_integral>()))>::value; +}; + +// This trait checks if BasicJsonType::json_serializer::to_json exists +template +struct has_to_json +{ + private: + template::to_json( + std::declval(), std::declval()))> + static int detect(U&&); + static void detect(...); + + public: + static constexpr bool value = std::is_integral>()))>::value; +}; +} +} + +#endif diff --git a/src/json.hpp b/src/json.hpp index 3555400a..7b37521a 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -48,12 +48,12 @@ SOFTWARE. #include // locale #include // accumulate #include // stringstream -#include // add_pointer, conditional, decay, enable_if, false_type, integral_constant, is_arithmetic, is_base_of, is_const, is_constructible, is_convertible, is_default_constructible, is_enum, is_floating_point, is_integral, is_nothrow_move_assignable, is_nothrow_move_constructible, is_pointer, is_reference, is_same, is_scalar, is_signed, remove_const, remove_cv, remove_pointer, remove_reference, true_type, underlying_type #include // declval, forward, make_pair, move, pair, swap #include // valarray #include "json_fwd.hpp" #include "detail/macro_scope.hpp" +#include "detail/meta.hpp" /*! @brief namespace for Niels Lohmann @@ -62,14 +62,6 @@ SOFTWARE. */ namespace nlohmann { -/*! -@brief unnamed namespace with internal helper functions - -This namespace collects some functions that could not be defined inside the -@ref basic_json class. - -@since version 2.1.0 -*/ namespace detail { //////////////// @@ -455,79 +447,6 @@ inline bool operator<(const value_t lhs, const value_t rhs) noexcept return l_index < order.size() and r_index < order.size() and order[l_index] < order[r_index]; } - -///////////// -// helpers // -///////////// - -template struct is_basic_json : std::false_type {}; - -NLOHMANN_BASIC_JSON_TPL_DECLARATION -struct is_basic_json : std::true_type {}; - -// alias templates to reduce boilerplate -template -using enable_if_t = typename std::enable_if::type; - -template -using uncvref_t = typename std::remove_cv::type>::type; - -// implementation of C++14 index_sequence and affiliates -// source: https://stackoverflow.com/a/32223343 -template -struct index_sequence -{ - using type = index_sequence; - using value_type = std::size_t; - static constexpr std::size_t size() noexcept - { - return sizeof...(Ints); - } -}; - -template -struct merge_and_renumber; - -template -struct merge_and_renumber, index_sequence> - : index_sequence < I1..., (sizeof...(I1) + I2)... > {}; - -template -struct make_index_sequence - : merge_and_renumber < typename make_index_sequence < N / 2 >::type, - typename make_index_sequence < N - N / 2 >::type > {}; - -template<> struct make_index_sequence<0> : index_sequence<> {}; -template<> struct make_index_sequence<1> : index_sequence<0> {}; - -template -using index_sequence_for = make_index_sequence; - -/* -Implementation of two C++17 constructs: conjunction, negation. This is needed -to avoid evaluating all the traits in a condition - -For example: not std::is_same::value and has_value_type::value -will not compile when T = void (on MSVC at least). Whereas -conjunction>, has_value_type>::value will -stop evaluating if negation<...>::value == false - -Please note that those constructs must be used with caution, since symbols can -become very long quickly (which can slow down compilation and cause MSVC -internal compiler errors). Only use it when you have to (see example ahead). -*/ -template struct conjunction : std::true_type {}; -template struct conjunction : B1 {}; -template -struct conjunction : std::conditional, B1>::type {}; - -template struct negation : std::integral_constant {}; - -// dispatch utility (taken from ranges-v3) -template struct priority_tag : priority_tag < N - 1 > {}; -template<> struct priority_tag<0> {}; - - ////////////////// // constructors // ////////////////// @@ -690,135 +609,6 @@ struct external_constructor } }; - -//////////////////////// -// has_/is_ functions // -//////////////////////// - -NLOHMANN_JSON_HAS_HELPER(mapped_type); -NLOHMANN_JSON_HAS_HELPER(key_type); -NLOHMANN_JSON_HAS_HELPER(value_type); -NLOHMANN_JSON_HAS_HELPER(iterator); - -template -struct is_compatible_object_type_impl : std::false_type {}; - -template -struct is_compatible_object_type_impl -{ - static constexpr auto value = - std::is_constructible::value and - std::is_constructible::value; -}; - -template -struct is_compatible_object_type -{ - static auto constexpr value = is_compatible_object_type_impl < - conjunction>, - has_mapped_type, - has_key_type>::value, - typename BasicJsonType::object_t, CompatibleObjectType >::value; -}; - -template -struct is_basic_json_nested_type -{ - static auto constexpr value = std::is_same::value or - std::is_same::value or - std::is_same::value or - std::is_same::value; -}; - -template -struct is_compatible_array_type -{ - static auto constexpr value = - conjunction>, - negation>, - negation>, - negation>, - has_value_type, - has_iterator>::value; -}; - -template -struct is_compatible_integer_type_impl : std::false_type {}; - -template -struct is_compatible_integer_type_impl -{ - // is there an assert somewhere on overflows? - using RealLimits = std::numeric_limits; - using CompatibleLimits = std::numeric_limits; - - static constexpr auto value = - std::is_constructible::value and - CompatibleLimits::is_integer and - RealLimits::is_signed == CompatibleLimits::is_signed; -}; - -template -struct is_compatible_integer_type -{ - static constexpr auto value = - is_compatible_integer_type_impl < - std::is_integral::value and - not std::is_same::value, - RealIntegerType, CompatibleNumberIntegerType >::value; -}; - - -// trait checking if JSONSerializer::from_json(json const&, udt&) exists -template -struct has_from_json -{ - private: - // also check the return type of from_json - template::from_json( - std::declval(), std::declval()))>::value>> - static int detect(U&&); - static void detect(...); - - public: - static constexpr bool value = std::is_integral>()))>::value; -}; - -// This trait checks if JSONSerializer::from_json(json const&) exists -// this overload is used for non-default-constructible user-defined-types -template -struct has_non_default_from_json -{ - private: - template::from_json(std::declval()))>::value>> - static int detect(U&&); - static void detect(...); - - public: - static constexpr bool value = std::is_integral>()))>::value; -}; - -// This trait checks if BasicJsonType::json_serializer::to_json exists -template -struct has_to_json -{ - private: - template::to_json( - std::declval(), std::declval()))> - static int detect(U&&); - static void detect(...); - - public: - static constexpr bool value = std::is_integral>()))>::value; -}; - - ///////////// // to_json // ///////////// From 8c555db970c557d25e6e0a02915998a12a4ffa04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20DELRIEU?= Date: Mon, 14 Aug 2017 15:19:40 +0200 Subject: [PATCH 34/59] add detail/exceptions.hpp --- Makefile | 4 +- src/detail/exceptions.hpp | 331 ++++++++++++++++++++++++++++++++++++++ src/json.hpp | 320 +----------------------------------- 3 files changed, 335 insertions(+), 320 deletions(-) create mode 100644 src/detail/exceptions.hpp diff --git a/Makefile b/Makefile index 6600e00b..b2ab6f72 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,9 @@ SRCS = ${SRCDIR}/json.hpp \ ${SRCDIR}/json_fwd.hpp \ ${SRCDIR}/detail/macro_scope.hpp \ ${SRCDIR}/detail/macro_unscope.hpp \ - ${SRCDIR}/detail/meta.hpp + ${SRCDIR}/detail/meta.hpp \ + ${SRCDIR}/detail/exceptions.hpp + # main target diff --git a/src/detail/exceptions.hpp b/src/detail/exceptions.hpp new file mode 100644 index 00000000..8eee702a --- /dev/null +++ b/src/detail/exceptions.hpp @@ -0,0 +1,331 @@ +#ifndef NLOHMANN_JSON_DETAIL_EXCEPTIONS_HPP +#define NLOHMANN_JSON_DETAIL_EXCEPTIONS_HPP + +#include // exception +#include // runtime_error +#include // to_string + +namespace nlohmann +{ +namespace detail +{ +//////////////// +// exceptions // +//////////////// + +/*! +@brief general exception of the @ref basic_json class + +This class is an extension of `std::exception` objects with a member @a id for +exception ids. It is used as the base class for all exceptions thrown by the +@ref basic_json class. This class can hence be used as "wildcard" to catch +exceptions. + +Subclasses: +- @ref parse_error for exceptions indicating a parse error +- @ref invalid_iterator for exceptions indicating errors with iterators +- @ref type_error for exceptions indicating executing a member function with + a wrong type +- @ref out_of_range for exceptions indicating access out of the defined range +- @ref other_error for exceptions indicating other library errors + +@internal +@note To have nothrow-copy-constructible exceptions, we internally use + `std::runtime_error` which can cope with arbitrary-length error messages. + Intermediate strings are built with static functions and then passed to + the actual constructor. +@endinternal + +@liveexample{The following code shows how arbitrary library exceptions can be +caught.,exception} + +@since version 3.0.0 +*/ +class exception : public std::exception +{ + public: + /// returns the explanatory string + const char* what() const noexcept override + { + return m.what(); + } + + /// the id of the exception + const int id; + + protected: + exception(int id_, const char* what_arg) : id(id_), m(what_arg) {} + + static std::string name(const std::string& ename, int id_) + { + return "[json.exception." + ename + "." + std::to_string(id_) + "] "; + } + + private: + /// an exception object as storage for error messages + std::runtime_error m; +}; + +/*! +@brief exception indicating a parse error + +This exception is thrown by the library when a parse error occurs. Parse errors +can occur during the deserialization of JSON text, CBOR, MessagePack, as well +as when using JSON Patch. + +Member @a byte holds the byte index of the last read character in the input +file. + +Exceptions have ids 1xx. + +name / id | example message | description +------------------------------ | --------------- | ------------------------- +json.exception.parse_error.101 | parse error at 2: unexpected end of input; expected string literal | This error indicates a syntax error while deserializing a JSON text. The error message describes that an unexpected token (character) was encountered, and the member @a byte indicates the error position. +json.exception.parse_error.102 | parse error at 14: missing or wrong low surrogate | JSON uses the `\uxxxx` format to describe Unicode characters. Code points above above 0xFFFF are split into two `\uxxxx` entries ("surrogate pairs"). This error indicates that the surrogate pair is incomplete or contains an invalid code point. +json.exception.parse_error.103 | parse error: code points above 0x10FFFF are invalid | Unicode supports code points up to 0x10FFFF. Code points above 0x10FFFF are invalid. +json.exception.parse_error.104 | parse error: JSON patch must be an array of objects | [RFC 6902](https://tools.ietf.org/html/rfc6902) requires a JSON Patch document to be a JSON document that represents an array of objects. +json.exception.parse_error.105 | parse error: operation must have string member 'op' | An operation of a JSON Patch document must contain exactly one "op" member, whose value indicates the operation to perform. Its value must be one of "add", "remove", "replace", "move", "copy", or "test"; other values are errors. +json.exception.parse_error.106 | parse error: array index '01' must not begin with '0' | An array index in a JSON Pointer ([RFC 6901](https://tools.ietf.org/html/rfc6901)) may be `0` or any number without a leading `0`. +json.exception.parse_error.107 | parse error: JSON pointer must be empty or begin with '/' - was: 'foo' | A JSON Pointer must be a Unicode string containing a sequence of zero or more reference tokens, each prefixed by a `/` character. +json.exception.parse_error.108 | parse error: escape character '~' must be followed with '0' or '1' | In a JSON Pointer, only `~0` and `~1` are valid escape sequences. +json.exception.parse_error.109 | parse error: array index 'one' is not a number | A JSON Pointer array index must be a number. +json.exception.parse_error.110 | parse error at 1: cannot read 2 bytes from vector | When parsing CBOR or MessagePack, the byte vector ends before the complete value has been read. +json.exception.parse_error.112 | parse error at 1: error reading CBOR; last byte: 0xF8 | Not all types of CBOR or MessagePack are supported. This exception occurs if an unsupported byte was read. +json.exception.parse_error.113 | parse error at 2: expected a CBOR string; last byte: 0x98 | While parsing a map key, a value that is not a string has been read. + +@note For an input with n bytes, 1 is the index of the first character and n+1 + is the index of the terminating null byte or the end of file. This also + holds true when reading a byte vector (CBOR or MessagePack). + +@liveexample{The following code shows how a `parse_error` exception can be +caught.,parse_error} + +@sa @ref exception for the base class of the library exceptions +@sa @ref invalid_iterator for exceptions indicating errors with iterators +@sa @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa @ref out_of_range for exceptions indicating access out of the defined range +@sa @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class parse_error : public exception +{ + public: + /*! + @brief create a parse error exception + @param[in] id_ the id of the exception + @param[in] byte_ the byte index where the error occurred (or 0 if the + position cannot be determined) + @param[in] what_arg the explanatory string + @return parse_error object + */ + static parse_error create(int id_, std::size_t byte_, const std::string& what_arg) + { + std::string w = exception::name("parse_error", id_) + "parse error" + + (byte_ != 0 ? (" at " + std::to_string(byte_)) : "") + + ": " + what_arg; + return parse_error(id_, byte_, w.c_str()); + } + + /*! + @brief byte index of the parse error + + The byte index of the last read character in the input file. + + @note For an input with n bytes, 1 is the index of the first character and + n+1 is the index of the terminating null byte or the end of file. + This also holds true when reading a byte vector (CBOR or MessagePack). + */ + const std::size_t byte; + + private: + parse_error(int id_, std::size_t byte_, const char* what_arg) + : exception(id_, what_arg), byte(byte_) {} +}; + +/*! +@brief exception indicating errors with iterators + +This exception is thrown if iterators passed to a library function do not match +the expected semantics. + +Exceptions have ids 2xx. + +name / id | example message | description +----------------------------------- | --------------- | ------------------------- +json.exception.invalid_iterator.201 | iterators are not compatible | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. +json.exception.invalid_iterator.202 | iterator does not fit current value | In an erase or insert function, the passed iterator @a pos does not belong to the JSON value for which the function was called. It hence does not define a valid position for the deletion/insertion. +json.exception.invalid_iterator.203 | iterators do not fit current value | Either iterator passed to function @ref erase(IteratorType first, IteratorType last) does not belong to the JSON value from which values shall be erased. It hence does not define a valid range to delete values from. +json.exception.invalid_iterator.204 | iterators out of range | When an iterator range for a primitive type (number, boolean, or string) is passed to a constructor or an erase function, this range has to be exactly (@ref begin(), @ref end()), because this is the only way the single stored value is expressed. All other ranges are invalid. +json.exception.invalid_iterator.205 | iterator out of range | When an iterator for a primitive type (number, boolean, or string) is passed to an erase function, the iterator has to be the @ref begin() iterator, because it is the only way to address the stored value. All other iterators are invalid. +json.exception.invalid_iterator.206 | cannot construct with iterators from null | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) belong to a JSON null value and hence to not define a valid range. +json.exception.invalid_iterator.207 | cannot use key() for non-object iterators | The key() member function can only be used on iterators belonging to a JSON object, because other types do not have a concept of a key. +json.exception.invalid_iterator.208 | cannot use operator[] for object iterators | The operator[] to specify a concrete offset cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. +json.exception.invalid_iterator.209 | cannot use offsets with object iterators | The offset operators (+, -, +=, -=) cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. +json.exception.invalid_iterator.210 | iterators do not fit | The iterator range passed to the insert function are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. +json.exception.invalid_iterator.211 | passed iterators may not belong to container | The iterator range passed to the insert function must not be a subrange of the container to insert to. +json.exception.invalid_iterator.212 | cannot compare iterators of different containers | When two iterators are compared, they must belong to the same container. +json.exception.invalid_iterator.213 | cannot compare order of object iterators | The order of object iterators cannot be compared, because JSON objects are unordered. +json.exception.invalid_iterator.214 | cannot get value | Cannot get value for iterator: Either the iterator belongs to a null value or it is an iterator to a primitive type (number, boolean, or string), but the iterator is different to @ref begin(). + +@liveexample{The following code shows how an `invalid_iterator` exception can be +caught.,invalid_iterator} + +@sa @ref exception for the base class of the library exceptions +@sa @ref parse_error for exceptions indicating a parse error +@sa @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa @ref out_of_range for exceptions indicating access out of the defined range +@sa @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class invalid_iterator : public exception +{ + public: + static invalid_iterator create(int id_, const std::string& what_arg) + { + std::string w = exception::name("invalid_iterator", id_) + what_arg; + return invalid_iterator(id_, w.c_str()); + } + + private: + invalid_iterator(int id_, const char* what_arg) + : exception(id_, what_arg) {} +}; + +/*! +@brief exception indicating executing a member function with a wrong type + +This exception is thrown in case of a type error; that is, a library function is +executed on a JSON value whose type does not match the expected semantics. + +Exceptions have ids 3xx. + +name / id | example message | description +----------------------------- | --------------- | ------------------------- +json.exception.type_error.301 | cannot create object from initializer list | To create an object from an initializer list, the initializer list must consist only of a list of pairs whose first element is a string. When this constraint is violated, an array is created instead. +json.exception.type_error.302 | type must be object, but is array | During implicit or explicit value conversion, the JSON type must be compatible to the target type. For instance, a JSON string can only be converted into string types, but not into numbers or boolean types. +json.exception.type_error.303 | incompatible ReferenceType for get_ref, actual type is object | To retrieve a reference to a value stored in a @ref basic_json object with @ref get_ref, the type of the reference must match the value type. For instance, for a JSON array, the @a ReferenceType must be @ref array_t&. +json.exception.type_error.304 | cannot use at() with string | The @ref at() member functions can only be executed for certain JSON types. +json.exception.type_error.305 | cannot use operator[] with string | The @ref operator[] member functions can only be executed for certain JSON types. +json.exception.type_error.306 | cannot use value() with string | The @ref value() member functions can only be executed for certain JSON types. +json.exception.type_error.307 | cannot use erase() with string | The @ref erase() member functions can only be executed for certain JSON types. +json.exception.type_error.308 | cannot use push_back() with string | The @ref push_back() and @ref operator+= member functions can only be executed for certain JSON types. +json.exception.type_error.309 | cannot use insert() with | The @ref insert() member functions can only be executed for certain JSON types. +json.exception.type_error.310 | cannot use swap() with number | The @ref swap() member functions can only be executed for certain JSON types. +json.exception.type_error.311 | cannot use emplace_back() with string | The @ref emplace_back() member function can only be executed for certain JSON types. +json.exception.type_error.312 | cannot use update() with string | The @ref update() member functions can only be executed for certain JSON types. +json.exception.type_error.313 | invalid value to unflatten | The @ref unflatten function converts an object whose keys are JSON Pointers back into an arbitrary nested JSON value. The JSON Pointers must not overlap, because then the resulting value would not be well defined. +json.exception.type_error.314 | only objects can be unflattened | The @ref unflatten function only works for an object whose keys are JSON Pointers. +json.exception.type_error.315 | values in object must be primitive | The @ref unflatten function only works for an object whose keys are JSON Pointers and whose values are primitive. +json.exception.type_error.316 | invalid UTF-8 byte at index 10: 0x7E | The @ref dump function only works with UTF-8 encoded strings; that is, if you assign a `std::string` to a JSON value, make sure it is UTF-8 encoded. | + +@liveexample{The following code shows how a `type_error` exception can be +caught.,type_error} + +@sa @ref exception for the base class of the library exceptions +@sa @ref parse_error for exceptions indicating a parse error +@sa @ref invalid_iterator for exceptions indicating errors with iterators +@sa @ref out_of_range for exceptions indicating access out of the defined range +@sa @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class type_error : public exception +{ + public: + static type_error create(int id_, const std::string& what_arg) + { + std::string w = exception::name("type_error", id_) + what_arg; + return type_error(id_, w.c_str()); + } + + private: + type_error(int id_, const char* what_arg) : exception(id_, what_arg) {} +}; + +/*! +@brief exception indicating access out of the defined range + +This exception is thrown in case a library function is called on an input +parameter that exceeds the expected range, for instance in case of array +indices or nonexisting object keys. + +Exceptions have ids 4xx. + +name / id | example message | description +------------------------------- | --------------- | ------------------------- +json.exception.out_of_range.401 | array index 3 is out of range | The provided array index @a i is larger than @a size-1. +json.exception.out_of_range.402 | array index '-' (3) is out of range | The special array index `-` in a JSON Pointer never describes a valid element of the array, but the index past the end. That is, it can only be used to add elements at this position, but not to read it. +json.exception.out_of_range.403 | key 'foo' not found | The provided key was not found in the JSON object. +json.exception.out_of_range.404 | unresolved reference token 'foo' | A reference token in a JSON Pointer could not be resolved. +json.exception.out_of_range.405 | JSON pointer has no parent | The JSON Patch operations 'remove' and 'add' can not be applied to the root element of the JSON value. +json.exception.out_of_range.406 | number overflow parsing '10E1000' | A parsed number could not be stored as without changing it to NaN or INF. + +@liveexample{The following code shows how an `out_of_range` exception can be +caught.,out_of_range} + +@sa @ref exception for the base class of the library exceptions +@sa @ref parse_error for exceptions indicating a parse error +@sa @ref invalid_iterator for exceptions indicating errors with iterators +@sa @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class out_of_range : public exception +{ + public: + static out_of_range create(int id_, const std::string& what_arg) + { + std::string w = exception::name("out_of_range", id_) + what_arg; + return out_of_range(id_, w.c_str()); + } + + private: + out_of_range(int id_, const char* what_arg) : exception(id_, what_arg) {} +}; + +/*! +@brief exception indicating other library errors + +This exception is thrown in case of errors that cannot be classified with the +other exception types. + +Exceptions have ids 5xx. + +name / id | example message | description +------------------------------ | --------------- | ------------------------- +json.exception.other_error.501 | unsuccessful: {"op":"test","path":"/baz", "value":"bar"} | A JSON Patch operation 'test' failed. The unsuccessful operation is also printed. + +@sa @ref exception for the base class of the library exceptions +@sa @ref parse_error for exceptions indicating a parse error +@sa @ref invalid_iterator for exceptions indicating errors with iterators +@sa @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa @ref out_of_range for exceptions indicating access out of the defined range + +@liveexample{The following code shows how an `other_error` exception can be +caught.,other_error} + +@since version 3.0.0 +*/ +class other_error : public exception +{ + public: + static other_error create(int id_, const std::string& what_arg) + { + std::string w = exception::name("other_error", id_) + what_arg; + return other_error(id_, w.c_str()); + } + + private: + other_error(int id_, const char* what_arg) : exception(id_, what_arg) {} +}; +} +} + +#endif diff --git a/src/json.hpp b/src/json.hpp index 7b37521a..48074c81 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -54,6 +54,7 @@ SOFTWARE. #include "json_fwd.hpp" #include "detail/macro_scope.hpp" #include "detail/meta.hpp" +#include "detail/exceptions.hpp" /*! @brief namespace for Niels Lohmann @@ -64,325 +65,6 @@ namespace nlohmann { namespace detail { -//////////////// -// exceptions // -//////////////// - -/*! -@brief general exception of the @ref basic_json class - -This class is an extension of `std::exception` objects with a member @a id for -exception ids. It is used as the base class for all exceptions thrown by the -@ref basic_json class. This class can hence be used as "wildcard" to catch -exceptions. - -Subclasses: -- @ref parse_error for exceptions indicating a parse error -- @ref invalid_iterator for exceptions indicating errors with iterators -- @ref type_error for exceptions indicating executing a member function with - a wrong type -- @ref out_of_range for exceptions indicating access out of the defined range -- @ref other_error for exceptions indicating other library errors - -@internal -@note To have nothrow-copy-constructible exceptions, we internally use - `std::runtime_error` which can cope with arbitrary-length error messages. - Intermediate strings are built with static functions and then passed to - the actual constructor. -@endinternal - -@liveexample{The following code shows how arbitrary library exceptions can be -caught.,exception} - -@since version 3.0.0 -*/ -class exception : public std::exception -{ - public: - /// returns the explanatory string - const char* what() const noexcept override - { - return m.what(); - } - - /// the id of the exception - const int id; - - protected: - exception(int id_, const char* what_arg) : id(id_), m(what_arg) {} - - static std::string name(const std::string& ename, int id_) - { - return "[json.exception." + ename + "." + std::to_string(id_) + "] "; - } - - private: - /// an exception object as storage for error messages - std::runtime_error m; -}; - -/*! -@brief exception indicating a parse error - -This exception is thrown by the library when a parse error occurs. Parse errors -can occur during the deserialization of JSON text, CBOR, MessagePack, as well -as when using JSON Patch. - -Member @a byte holds the byte index of the last read character in the input -file. - -Exceptions have ids 1xx. - -name / id | example message | description ------------------------------- | --------------- | ------------------------- -json.exception.parse_error.101 | parse error at 2: unexpected end of input; expected string literal | This error indicates a syntax error while deserializing a JSON text. The error message describes that an unexpected token (character) was encountered, and the member @a byte indicates the error position. -json.exception.parse_error.102 | parse error at 14: missing or wrong low surrogate | JSON uses the `\uxxxx` format to describe Unicode characters. Code points above above 0xFFFF are split into two `\uxxxx` entries ("surrogate pairs"). This error indicates that the surrogate pair is incomplete or contains an invalid code point. -json.exception.parse_error.103 | parse error: code points above 0x10FFFF are invalid | Unicode supports code points up to 0x10FFFF. Code points above 0x10FFFF are invalid. -json.exception.parse_error.104 | parse error: JSON patch must be an array of objects | [RFC 6902](https://tools.ietf.org/html/rfc6902) requires a JSON Patch document to be a JSON document that represents an array of objects. -json.exception.parse_error.105 | parse error: operation must have string member 'op' | An operation of a JSON Patch document must contain exactly one "op" member, whose value indicates the operation to perform. Its value must be one of "add", "remove", "replace", "move", "copy", or "test"; other values are errors. -json.exception.parse_error.106 | parse error: array index '01' must not begin with '0' | An array index in a JSON Pointer ([RFC 6901](https://tools.ietf.org/html/rfc6901)) may be `0` or any number without a leading `0`. -json.exception.parse_error.107 | parse error: JSON pointer must be empty or begin with '/' - was: 'foo' | A JSON Pointer must be a Unicode string containing a sequence of zero or more reference tokens, each prefixed by a `/` character. -json.exception.parse_error.108 | parse error: escape character '~' must be followed with '0' or '1' | In a JSON Pointer, only `~0` and `~1` are valid escape sequences. -json.exception.parse_error.109 | parse error: array index 'one' is not a number | A JSON Pointer array index must be a number. -json.exception.parse_error.110 | parse error at 1: cannot read 2 bytes from vector | When parsing CBOR or MessagePack, the byte vector ends before the complete value has been read. -json.exception.parse_error.112 | parse error at 1: error reading CBOR; last byte: 0xF8 | Not all types of CBOR or MessagePack are supported. This exception occurs if an unsupported byte was read. -json.exception.parse_error.113 | parse error at 2: expected a CBOR string; last byte: 0x98 | While parsing a map key, a value that is not a string has been read. - -@note For an input with n bytes, 1 is the index of the first character and n+1 - is the index of the terminating null byte or the end of file. This also - holds true when reading a byte vector (CBOR or MessagePack). - -@liveexample{The following code shows how a `parse_error` exception can be -caught.,parse_error} - -@sa @ref exception for the base class of the library exceptions -@sa @ref invalid_iterator for exceptions indicating errors with iterators -@sa @ref type_error for exceptions indicating executing a member function with - a wrong type -@sa @ref out_of_range for exceptions indicating access out of the defined range -@sa @ref other_error for exceptions indicating other library errors - -@since version 3.0.0 -*/ -class parse_error : public exception -{ - public: - /*! - @brief create a parse error exception - @param[in] id_ the id of the exception - @param[in] byte_ the byte index where the error occurred (or 0 if the - position cannot be determined) - @param[in] what_arg the explanatory string - @return parse_error object - */ - static parse_error create(int id_, std::size_t byte_, const std::string& what_arg) - { - std::string w = exception::name("parse_error", id_) + "parse error" + - (byte_ != 0 ? (" at " + std::to_string(byte_)) : "") + - ": " + what_arg; - return parse_error(id_, byte_, w.c_str()); - } - - /*! - @brief byte index of the parse error - - The byte index of the last read character in the input file. - - @note For an input with n bytes, 1 is the index of the first character and - n+1 is the index of the terminating null byte or the end of file. - This also holds true when reading a byte vector (CBOR or MessagePack). - */ - const std::size_t byte; - - private: - parse_error(int id_, std::size_t byte_, const char* what_arg) - : exception(id_, what_arg), byte(byte_) {} -}; - -/*! -@brief exception indicating errors with iterators - -This exception is thrown if iterators passed to a library function do not match -the expected semantics. - -Exceptions have ids 2xx. - -name / id | example message | description ------------------------------------ | --------------- | ------------------------- -json.exception.invalid_iterator.201 | iterators are not compatible | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. -json.exception.invalid_iterator.202 | iterator does not fit current value | In an erase or insert function, the passed iterator @a pos does not belong to the JSON value for which the function was called. It hence does not define a valid position for the deletion/insertion. -json.exception.invalid_iterator.203 | iterators do not fit current value | Either iterator passed to function @ref erase(IteratorType first, IteratorType last) does not belong to the JSON value from which values shall be erased. It hence does not define a valid range to delete values from. -json.exception.invalid_iterator.204 | iterators out of range | When an iterator range for a primitive type (number, boolean, or string) is passed to a constructor or an erase function, this range has to be exactly (@ref begin(), @ref end()), because this is the only way the single stored value is expressed. All other ranges are invalid. -json.exception.invalid_iterator.205 | iterator out of range | When an iterator for a primitive type (number, boolean, or string) is passed to an erase function, the iterator has to be the @ref begin() iterator, because it is the only way to address the stored value. All other iterators are invalid. -json.exception.invalid_iterator.206 | cannot construct with iterators from null | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) belong to a JSON null value and hence to not define a valid range. -json.exception.invalid_iterator.207 | cannot use key() for non-object iterators | The key() member function can only be used on iterators belonging to a JSON object, because other types do not have a concept of a key. -json.exception.invalid_iterator.208 | cannot use operator[] for object iterators | The operator[] to specify a concrete offset cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. -json.exception.invalid_iterator.209 | cannot use offsets with object iterators | The offset operators (+, -, +=, -=) cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. -json.exception.invalid_iterator.210 | iterators do not fit | The iterator range passed to the insert function are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. -json.exception.invalid_iterator.211 | passed iterators may not belong to container | The iterator range passed to the insert function must not be a subrange of the container to insert to. -json.exception.invalid_iterator.212 | cannot compare iterators of different containers | When two iterators are compared, they must belong to the same container. -json.exception.invalid_iterator.213 | cannot compare order of object iterators | The order of object iterators cannot be compared, because JSON objects are unordered. -json.exception.invalid_iterator.214 | cannot get value | Cannot get value for iterator: Either the iterator belongs to a null value or it is an iterator to a primitive type (number, boolean, or string), but the iterator is different to @ref begin(). - -@liveexample{The following code shows how an `invalid_iterator` exception can be -caught.,invalid_iterator} - -@sa @ref exception for the base class of the library exceptions -@sa @ref parse_error for exceptions indicating a parse error -@sa @ref type_error for exceptions indicating executing a member function with - a wrong type -@sa @ref out_of_range for exceptions indicating access out of the defined range -@sa @ref other_error for exceptions indicating other library errors - -@since version 3.0.0 -*/ -class invalid_iterator : public exception -{ - public: - static invalid_iterator create(int id_, const std::string& what_arg) - { - std::string w = exception::name("invalid_iterator", id_) + what_arg; - return invalid_iterator(id_, w.c_str()); - } - - private: - invalid_iterator(int id_, const char* what_arg) - : exception(id_, what_arg) {} -}; - -/*! -@brief exception indicating executing a member function with a wrong type - -This exception is thrown in case of a type error; that is, a library function is -executed on a JSON value whose type does not match the expected semantics. - -Exceptions have ids 3xx. - -name / id | example message | description ------------------------------ | --------------- | ------------------------- -json.exception.type_error.301 | cannot create object from initializer list | To create an object from an initializer list, the initializer list must consist only of a list of pairs whose first element is a string. When this constraint is violated, an array is created instead. -json.exception.type_error.302 | type must be object, but is array | During implicit or explicit value conversion, the JSON type must be compatible to the target type. For instance, a JSON string can only be converted into string types, but not into numbers or boolean types. -json.exception.type_error.303 | incompatible ReferenceType for get_ref, actual type is object | To retrieve a reference to a value stored in a @ref basic_json object with @ref get_ref, the type of the reference must match the value type. For instance, for a JSON array, the @a ReferenceType must be @ref array_t&. -json.exception.type_error.304 | cannot use at() with string | The @ref at() member functions can only be executed for certain JSON types. -json.exception.type_error.305 | cannot use operator[] with string | The @ref operator[] member functions can only be executed for certain JSON types. -json.exception.type_error.306 | cannot use value() with string | The @ref value() member functions can only be executed for certain JSON types. -json.exception.type_error.307 | cannot use erase() with string | The @ref erase() member functions can only be executed for certain JSON types. -json.exception.type_error.308 | cannot use push_back() with string | The @ref push_back() and @ref operator+= member functions can only be executed for certain JSON types. -json.exception.type_error.309 | cannot use insert() with | The @ref insert() member functions can only be executed for certain JSON types. -json.exception.type_error.310 | cannot use swap() with number | The @ref swap() member functions can only be executed for certain JSON types. -json.exception.type_error.311 | cannot use emplace_back() with string | The @ref emplace_back() member function can only be executed for certain JSON types. -json.exception.type_error.312 | cannot use update() with string | The @ref update() member functions can only be executed for certain JSON types. -json.exception.type_error.313 | invalid value to unflatten | The @ref unflatten function converts an object whose keys are JSON Pointers back into an arbitrary nested JSON value. The JSON Pointers must not overlap, because then the resulting value would not be well defined. -json.exception.type_error.314 | only objects can be unflattened | The @ref unflatten function only works for an object whose keys are JSON Pointers. -json.exception.type_error.315 | values in object must be primitive | The @ref unflatten function only works for an object whose keys are JSON Pointers and whose values are primitive. -json.exception.type_error.316 | invalid UTF-8 byte at index 10: 0x7E | The @ref dump function only works with UTF-8 encoded strings; that is, if you assign a `std::string` to a JSON value, make sure it is UTF-8 encoded. | - -@liveexample{The following code shows how a `type_error` exception can be -caught.,type_error} - -@sa @ref exception for the base class of the library exceptions -@sa @ref parse_error for exceptions indicating a parse error -@sa @ref invalid_iterator for exceptions indicating errors with iterators -@sa @ref out_of_range for exceptions indicating access out of the defined range -@sa @ref other_error for exceptions indicating other library errors - -@since version 3.0.0 -*/ -class type_error : public exception -{ - public: - static type_error create(int id_, const std::string& what_arg) - { - std::string w = exception::name("type_error", id_) + what_arg; - return type_error(id_, w.c_str()); - } - - private: - type_error(int id_, const char* what_arg) : exception(id_, what_arg) {} -}; - -/*! -@brief exception indicating access out of the defined range - -This exception is thrown in case a library function is called on an input -parameter that exceeds the expected range, for instance in case of array -indices or nonexisting object keys. - -Exceptions have ids 4xx. - -name / id | example message | description -------------------------------- | --------------- | ------------------------- -json.exception.out_of_range.401 | array index 3 is out of range | The provided array index @a i is larger than @a size-1. -json.exception.out_of_range.402 | array index '-' (3) is out of range | The special array index `-` in a JSON Pointer never describes a valid element of the array, but the index past the end. That is, it can only be used to add elements at this position, but not to read it. -json.exception.out_of_range.403 | key 'foo' not found | The provided key was not found in the JSON object. -json.exception.out_of_range.404 | unresolved reference token 'foo' | A reference token in a JSON Pointer could not be resolved. -json.exception.out_of_range.405 | JSON pointer has no parent | The JSON Patch operations 'remove' and 'add' can not be applied to the root element of the JSON value. -json.exception.out_of_range.406 | number overflow parsing '10E1000' | A parsed number could not be stored as without changing it to NaN or INF. - -@liveexample{The following code shows how an `out_of_range` exception can be -caught.,out_of_range} - -@sa @ref exception for the base class of the library exceptions -@sa @ref parse_error for exceptions indicating a parse error -@sa @ref invalid_iterator for exceptions indicating errors with iterators -@sa @ref type_error for exceptions indicating executing a member function with - a wrong type -@sa @ref other_error for exceptions indicating other library errors - -@since version 3.0.0 -*/ -class out_of_range : public exception -{ - public: - static out_of_range create(int id_, const std::string& what_arg) - { - std::string w = exception::name("out_of_range", id_) + what_arg; - return out_of_range(id_, w.c_str()); - } - - private: - out_of_range(int id_, const char* what_arg) : exception(id_, what_arg) {} -}; - -/*! -@brief exception indicating other library errors - -This exception is thrown in case of errors that cannot be classified with the -other exception types. - -Exceptions have ids 5xx. - -name / id | example message | description ------------------------------- | --------------- | ------------------------- -json.exception.other_error.501 | unsuccessful: {"op":"test","path":"/baz", "value":"bar"} | A JSON Patch operation 'test' failed. The unsuccessful operation is also printed. - -@sa @ref exception for the base class of the library exceptions -@sa @ref parse_error for exceptions indicating a parse error -@sa @ref invalid_iterator for exceptions indicating errors with iterators -@sa @ref type_error for exceptions indicating executing a member function with - a wrong type -@sa @ref out_of_range for exceptions indicating access out of the defined range - -@liveexample{The following code shows how an `other_error` exception can be -caught.,other_error} - -@since version 3.0.0 -*/ -class other_error : public exception -{ - public: - static other_error create(int id_, const std::string& what_arg) - { - std::string w = exception::name("other_error", id_) + what_arg; - return other_error(id_, w.c_str()); - } - - private: - other_error(int id_, const char* what_arg) : exception(id_, what_arg) {} -}; - - - /////////////////////////// // JSON type enumeration // /////////////////////////// From 7056b375c43ec048cd5c7b2e93eb1e45c5a251e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20DELRIEU?= Date: Mon, 14 Aug 2017 15:58:56 +0200 Subject: [PATCH 35/59] add detail/value_t.hpp --- Makefile | 3 +- src/detail/value_t.hpp | 78 ++++++++++++++++++++++++++++++++++++++++++ src/json.hpp | 65 +---------------------------------- 3 files changed, 81 insertions(+), 65 deletions(-) create mode 100644 src/detail/value_t.hpp diff --git a/Makefile b/Makefile index b2ab6f72..f10899f5 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,8 @@ SRCS = ${SRCDIR}/json.hpp \ ${SRCDIR}/detail/macro_scope.hpp \ ${SRCDIR}/detail/macro_unscope.hpp \ ${SRCDIR}/detail/meta.hpp \ - ${SRCDIR}/detail/exceptions.hpp + ${SRCDIR}/detail/exceptions.hpp \ + ${SRCDIR}/detail/value_t.hpp diff --git a/src/detail/value_t.hpp b/src/detail/value_t.hpp new file mode 100644 index 00000000..dbfffd47 --- /dev/null +++ b/src/detail/value_t.hpp @@ -0,0 +1,78 @@ +#ifndef NLOHMANN_JSON_DETAIL_VALUE_T_HPP +#define NLOHMANN_JSON_DETAIL_VALUE_T_HPP + +#include // and +#include // size_t +#include // uint8_t + +namespace nlohmann +{ +namespace detail +{ +/////////////////////////// +// JSON type enumeration // +/////////////////////////// + +/*! +@brief the JSON type enumeration + +This enumeration collects the different JSON types. It is internally used to +distinguish the stored values, and the functions @ref basic_json::is_null(), +@ref basic_json::is_object(), @ref basic_json::is_array(), +@ref basic_json::is_string(), @ref basic_json::is_boolean(), +@ref basic_json::is_number() (with @ref basic_json::is_number_integer(), +@ref basic_json::is_number_unsigned(), and @ref basic_json::is_number_float()), +@ref basic_json::is_discarded(), @ref basic_json::is_primitive(), and +@ref basic_json::is_structured() rely on it. + +@note There are three enumeration entries (number_integer, number_unsigned, and +number_float), because the library distinguishes these three types for numbers: +@ref basic_json::number_unsigned_t is used for unsigned integers, +@ref basic_json::number_integer_t is used for signed integers, and +@ref basic_json::number_float_t is used for floating-point numbers or to +approximate integers which do not fit in the limits of their respective type. + +@sa @ref basic_json::basic_json(const value_t value_type) -- create a JSON +value with the default value for a given type + +@since version 1.0.0 +*/ +enum class value_t : uint8_t +{ + null, ///< null value + object, ///< object (unordered set of name/value pairs) + array, ///< array (ordered collection of values) + string, ///< string value + boolean, ///< boolean value + number_integer, ///< number value (signed integer) + number_unsigned, ///< number value (unsigned integer) + number_float, ///< number value (floating-point) + discarded ///< discarded by the the parser callback function +}; + +/*! +@brief comparison operator for JSON types + +Returns an ordering that is similar to Python: +- order: null < boolean < number < object < array < string +- furthermore, each type is not smaller than itself +- discarded values are not comparable + +@since version 1.0.0 +*/ +inline bool operator<(const value_t lhs, const value_t rhs) noexcept +{ + static constexpr std::array order = {{ + 0 /* null */, 3 /* object */, 4 /* array */, 5 /* string */, + 1 /* boolean */, 2 /* integer */, 2 /* unsigned */, 2 /* float */ + } + }; + + const auto l_index = static_cast(lhs); + const auto r_index = static_cast(rhs); + return l_index < order.size() and r_index < order.size() and order[l_index] < order[r_index]; +} +} +} + +#endif diff --git a/src/json.hpp b/src/json.hpp index 48074c81..6d50dff2 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -55,6 +55,7 @@ SOFTWARE. #include "detail/macro_scope.hpp" #include "detail/meta.hpp" #include "detail/exceptions.hpp" +#include "detail/value_t.hpp" /*! @brief namespace for Niels Lohmann @@ -65,70 +66,6 @@ namespace nlohmann { namespace detail { -/////////////////////////// -// JSON type enumeration // -/////////////////////////// - -/*! -@brief the JSON type enumeration - -This enumeration collects the different JSON types. It is internally used to -distinguish the stored values, and the functions @ref basic_json::is_null(), -@ref basic_json::is_object(), @ref basic_json::is_array(), -@ref basic_json::is_string(), @ref basic_json::is_boolean(), -@ref basic_json::is_number() (with @ref basic_json::is_number_integer(), -@ref basic_json::is_number_unsigned(), and @ref basic_json::is_number_float()), -@ref basic_json::is_discarded(), @ref basic_json::is_primitive(), and -@ref basic_json::is_structured() rely on it. - -@note There are three enumeration entries (number_integer, number_unsigned, and -number_float), because the library distinguishes these three types for numbers: -@ref basic_json::number_unsigned_t is used for unsigned integers, -@ref basic_json::number_integer_t is used for signed integers, and -@ref basic_json::number_float_t is used for floating-point numbers or to -approximate integers which do not fit in the limits of their respective type. - -@sa @ref basic_json::basic_json(const value_t value_type) -- create a JSON -value with the default value for a given type - -@since version 1.0.0 -*/ -enum class value_t : uint8_t -{ - null, ///< null value - object, ///< object (unordered set of name/value pairs) - array, ///< array (ordered collection of values) - string, ///< string value - boolean, ///< boolean value - number_integer, ///< number value (signed integer) - number_unsigned, ///< number value (unsigned integer) - number_float, ///< number value (floating-point) - discarded ///< discarded by the the parser callback function -}; - -/*! -@brief comparison operator for JSON types - -Returns an ordering that is similar to Python: -- order: null < boolean < number < object < array < string -- furthermore, each type is not smaller than itself -- discarded values are not comparable - -@since version 1.0.0 -*/ -inline bool operator<(const value_t lhs, const value_t rhs) noexcept -{ - static constexpr std::array order = {{ - 0 /* null */, 3 /* object */, 4 /* array */, 5 /* string */, - 1 /* boolean */, 2 /* integer */, 2 /* unsigned */, 2 /* float */ - } - }; - - const auto l_index = static_cast(lhs); - const auto r_index = static_cast(rhs); - return l_index < order.size() and r_index < order.size() and order[l_index] < order[r_index]; -} - ////////////////// // constructors // ////////////////// From e0c02c14f0106037c526ae52d594fdbd7627d0ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20DELRIEU?= Date: Mon, 14 Aug 2017 16:33:55 +0200 Subject: [PATCH 36/59] add detail/conversions/from_json.hpp --- Makefile | 4 +- src/detail/conversions/from_json.hpp | 316 +++++++++++++++++++++++++++ src/detail/meta.hpp | 10 + src/json.hpp | 302 +------------------------ 4 files changed, 331 insertions(+), 301 deletions(-) create mode 100644 src/detail/conversions/from_json.hpp diff --git a/Makefile b/Makefile index f10899f5..22df2ff2 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,9 @@ SRCS = ${SRCDIR}/json.hpp \ ${SRCDIR}/detail/macro_unscope.hpp \ ${SRCDIR}/detail/meta.hpp \ ${SRCDIR}/detail/exceptions.hpp \ - ${SRCDIR}/detail/value_t.hpp + ${SRCDIR}/detail/value_t.hpp \ + ${SRCDIR}/detail/conversions/from_json.hpp + diff --git a/src/detail/conversions/from_json.hpp b/src/detail/conversions/from_json.hpp new file mode 100644 index 00000000..471c1320 --- /dev/null +++ b/src/detail/conversions/from_json.hpp @@ -0,0 +1,316 @@ +#ifndef NLOHMANN_JSON_DETAIL_CONVERSIONS_FROM_JSON_HPP +#define NLOHMANN_JSON_DETAIL_CONVERSIONS_FROM_JSON_HPP + +#include +#include +#include +#include + +#include "detail/exceptions.hpp" +#include "detail/macro_scope.hpp" +#include "detail/meta.hpp" +#include "detail/value_t.hpp" + +namespace nlohmann +{ +namespace detail +{ +/////////////// +// from_json // +/////////////// + +// overloads for basic_json template parameters +template::value and + not std::is_same::value, + int> = 0> +void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val) +{ + switch (static_cast(j)) + { + case value_t::number_unsigned: + { + val = static_cast(*j.template get_ptr()); + break; + } + case value_t::number_integer: + { + val = static_cast(*j.template get_ptr()); + break; + } + case value_t::number_float: + { + val = static_cast(*j.template get_ptr()); + break; + } + + default: + JSON_THROW(type_error::create(302, "type must be number, but is " + std::string(j.type_name()))); + } +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b) +{ + if (JSON_UNLIKELY(not j.is_boolean())) + { + JSON_THROW(type_error::create(302, "type must be boolean, but is " + std::string(j.type_name()))); + } + b = *j.template get_ptr(); +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s) +{ + if (JSON_UNLIKELY(not j.is_string())) + { + JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name()))); + } + s = *j.template get_ptr(); +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::number_float_t& val) +{ + get_arithmetic_value(j, val); +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::number_unsigned_t& val) +{ + get_arithmetic_value(j, val); +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::number_integer_t& val) +{ + get_arithmetic_value(j, val); +} + +template::value, int> = 0> +void from_json(const BasicJsonType& j, EnumType& e) +{ + typename std::underlying_type::type val; + get_arithmetic_value(j, val); + e = static_cast(val); +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::array_t& arr) +{ + if (JSON_UNLIKELY(not j.is_array())) + { + JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); + } + arr = *j.template get_ptr(); +} + +// forward_list doesn't have an insert method +template::value, int> = 0> +void from_json(const BasicJsonType& j, std::forward_list& l) +{ + if (JSON_UNLIKELY(not j.is_array())) + { + JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); + } + std::transform(j.rbegin(), j.rend(), + std::front_inserter(l), [](const BasicJsonType & i) + { + return i.template get(); + }); +} + +// valarray doesn't have an insert method +template::value, int> = 0> +void from_json(const BasicJsonType& j, std::valarray& l) +{ + if (JSON_UNLIKELY(not j.is_array())) + { + JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); + } + l.resize(j.size()); + std::copy(j.m_value.array->begin(), j.m_value.array->end(), std::begin(l)); +} + +template +void from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, priority_tag<0> /*unused*/) +{ + using std::end; + + std::transform(j.begin(), j.end(), + std::inserter(arr, end(arr)), [](const BasicJsonType & i) + { + // get() returns *this, this won't call a from_json + // method when value_type is BasicJsonType + return i.template get(); + }); +} + +template +auto from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, priority_tag<1> /*unused*/) +-> decltype( + arr.reserve(std::declval()), + void()) +{ + using std::end; + + arr.reserve(j.size()); + std::transform(j.begin(), j.end(), + std::inserter(arr, end(arr)), [](const BasicJsonType & i) + { + // get() returns *this, this won't call a from_json + // method when value_type is BasicJsonType + return i.template get(); + }); +} + +template +void from_json_array_impl(const BasicJsonType& j, std::array& arr, priority_tag<2> /*unused*/) +{ + for (std::size_t i = 0; i < N; ++i) + { + arr[i] = j.at(i).template get(); + } +} + +template::value and + std::is_convertible::value and + not std::is_same::value, int> = 0> +void from_json(const BasicJsonType& j, CompatibleArrayType& arr) +{ + if (JSON_UNLIKELY(not j.is_array())) + { + JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); + } + + from_json_array_impl(j, arr, priority_tag<2> {}); +} + +template::value, int> = 0> +void from_json(const BasicJsonType& j, CompatibleObjectType& obj) +{ + if (JSON_UNLIKELY(not j.is_object())) + { + JSON_THROW(type_error::create(302, "type must be object, but is " + std::string(j.type_name()))); + } + + auto inner_object = j.template get_ptr(); + using value_type = typename CompatibleObjectType::value_type; + std::transform( + inner_object->begin(), inner_object->end(), + std::inserter(obj, obj.begin()), + [](typename BasicJsonType::object_t::value_type const & p) + { + return value_type(p.first, p.second.template get()); + }); +} + +// overload for arithmetic types, not chosen for basic_json template arguments +// (BooleanType, etc..); note: Is it really necessary to provide explicit +// overloads for boolean_t etc. in case of a custom BooleanType which is not +// an arithmetic type? +template::value and + not std::is_same::value and + not std::is_same::value and + not std::is_same::value and + not std::is_same::value, + int> = 0> +void from_json(const BasicJsonType& j, ArithmeticType& val) +{ + switch (static_cast(j)) + { + case value_t::number_unsigned: + { + val = static_cast(*j.template get_ptr()); + break; + } + case value_t::number_integer: + { + val = static_cast(*j.template get_ptr()); + break; + } + case value_t::number_float: + { + val = static_cast(*j.template get_ptr()); + break; + } + case value_t::boolean: + { + val = static_cast(*j.template get_ptr()); + break; + } + + default: + JSON_THROW(type_error::create(302, "type must be number, but is " + std::string(j.type_name()))); + } +} + +template +void from_json(const BasicJsonType& j, std::pair& p) +{ + p = {j.at(0).template get(), j.at(1).template get()}; +} + +template +void from_json_tuple_impl(const BasicJsonType& j, Tuple& t, index_sequence) +{ + t = std::make_tuple(j.at(Idx).template get::type>()...); +} + +template +void from_json(const BasicJsonType& j, std::tuple& t) +{ + from_json_tuple_impl(j, t, index_sequence_for {}); +} + +struct from_json_fn +{ + private: + template + auto call(const BasicJsonType& j, T& val, priority_tag<1> /*unused*/) const + noexcept(noexcept(from_json(j, val))) + -> decltype(from_json(j, val), void()) + { + return from_json(j, val); + } + + template + void call(const BasicJsonType& /*unused*/, T& /*unused*/, priority_tag<0> /*unused*/) const noexcept + { + static_assert(sizeof(BasicJsonType) == 0, + "could not find from_json() method in T's namespace"); +#ifdef _MSC_VER + // MSVC does not show a stacktrace for the above assert + using decayed = uncvref_t; + static_assert(sizeof(typename decayed::force_msvc_stacktrace) == 0, + "forcing MSVC stacktrace to show which T we're talking about."); +#endif + } + + public: + template + void operator()(const BasicJsonType& j, T& val) const + noexcept(noexcept(std::declval().call(j, val, priority_tag<1> {}))) + { + return call(j, val, priority_tag<1> {}); + } +}; +} + +/// namespace to hold default `from_json` function +/// to see why this is required: +/// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html +namespace +{ +constexpr const auto& from_json = detail::static_const::value; +} +} + +#endif diff --git a/src/detail/meta.hpp b/src/detail/meta.hpp index 9a3a97fa..a9b20443 100644 --- a/src/detail/meta.hpp +++ b/src/detail/meta.hpp @@ -220,6 +220,16 @@ struct has_to_json static constexpr bool value = std::is_integral>()))>::value; }; + +// taken from ranges-v3 +template +struct static_const +{ + static constexpr T value{}; +}; + +template +constexpr T static_const::value; } } diff --git a/src/json.hpp b/src/json.hpp index 6d50dff2..e7ce109a 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -56,6 +56,7 @@ SOFTWARE. #include "detail/meta.hpp" #include "detail/exceptions.hpp" #include "detail/value_t.hpp" +#include "detail/conversions/from_json.hpp" /*! @brief namespace for Niels Lohmann @@ -347,261 +348,6 @@ void to_json(BasicJsonType& j, const std::tuple& t) to_json_tuple_impl(j, t, index_sequence_for {}); } -/////////////// -// from_json // -/////////////// - -// overloads for basic_json template parameters -template::value and - not std::is_same::value, - int> = 0> -void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val) -{ - switch (static_cast(j)) - { - case value_t::number_unsigned: - { - val = static_cast(*j.template get_ptr()); - break; - } - case value_t::number_integer: - { - val = static_cast(*j.template get_ptr()); - break; - } - case value_t::number_float: - { - val = static_cast(*j.template get_ptr()); - break; - } - - default: - JSON_THROW(type_error::create(302, "type must be number, but is " + std::string(j.type_name()))); - } -} - -template -void from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b) -{ - if (JSON_UNLIKELY(not j.is_boolean())) - { - JSON_THROW(type_error::create(302, "type must be boolean, but is " + std::string(j.type_name()))); - } - b = *j.template get_ptr(); -} - -template -void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s) -{ - if (JSON_UNLIKELY(not j.is_string())) - { - JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name()))); - } - s = *j.template get_ptr(); -} - -template -void from_json(const BasicJsonType& j, typename BasicJsonType::number_float_t& val) -{ - get_arithmetic_value(j, val); -} - -template -void from_json(const BasicJsonType& j, typename BasicJsonType::number_unsigned_t& val) -{ - get_arithmetic_value(j, val); -} - -template -void from_json(const BasicJsonType& j, typename BasicJsonType::number_integer_t& val) -{ - get_arithmetic_value(j, val); -} - -template::value, int> = 0> -void from_json(const BasicJsonType& j, EnumType& e) -{ - typename std::underlying_type::type val; - get_arithmetic_value(j, val); - e = static_cast(val); -} - -template -void from_json(const BasicJsonType& j, typename BasicJsonType::array_t& arr) -{ - if (JSON_UNLIKELY(not j.is_array())) - { - JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); - } - arr = *j.template get_ptr(); -} - -// forward_list doesn't have an insert method -template::value, int> = 0> -void from_json(const BasicJsonType& j, std::forward_list& l) -{ - if (JSON_UNLIKELY(not j.is_array())) - { - JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); - } - std::transform(j.rbegin(), j.rend(), - std::front_inserter(l), [](const BasicJsonType & i) - { - return i.template get(); - }); -} - -// valarray doesn't have an insert method -template::value, int> = 0> -void from_json(const BasicJsonType& j, std::valarray& l) -{ - if (JSON_UNLIKELY(not j.is_array())) - { - JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); - } - l.resize(j.size()); - std::copy(j.m_value.array->begin(), j.m_value.array->end(), std::begin(l)); -} - -template -void from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, priority_tag<0> /*unused*/) -{ - using std::end; - - std::transform(j.begin(), j.end(), - std::inserter(arr, end(arr)), [](const BasicJsonType & i) - { - // get() returns *this, this won't call a from_json - // method when value_type is BasicJsonType - return i.template get(); - }); -} - -template -auto from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, priority_tag<1> /*unused*/) --> decltype( - arr.reserve(std::declval()), - void()) -{ - using std::end; - - arr.reserve(j.size()); - std::transform(j.begin(), j.end(), - std::inserter(arr, end(arr)), [](const BasicJsonType & i) - { - // get() returns *this, this won't call a from_json - // method when value_type is BasicJsonType - return i.template get(); - }); -} - -template -void from_json_array_impl(const BasicJsonType& j, std::array& arr, priority_tag<2> /*unused*/) -{ - for (std::size_t i = 0; i < N; ++i) - { - arr[i] = j.at(i).template get(); - } -} - -template::value and - std::is_convertible::value and - not std::is_same::value, int> = 0> -void from_json(const BasicJsonType& j, CompatibleArrayType& arr) -{ - if (JSON_UNLIKELY(not j.is_array())) - { - JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); - } - - from_json_array_impl(j, arr, priority_tag<2> {}); -} - -template::value, int> = 0> -void from_json(const BasicJsonType& j, CompatibleObjectType& obj) -{ - if (JSON_UNLIKELY(not j.is_object())) - { - JSON_THROW(type_error::create(302, "type must be object, but is " + std::string(j.type_name()))); - } - - auto inner_object = j.template get_ptr(); - using value_type = typename CompatibleObjectType::value_type; - std::transform( - inner_object->begin(), inner_object->end(), - std::inserter(obj, obj.begin()), - [](typename BasicJsonType::object_t::value_type const & p) - { - return value_type(p.first, p.second.template get()); - }); -} - -// overload for arithmetic types, not chosen for basic_json template arguments -// (BooleanType, etc..); note: Is it really necessary to provide explicit -// overloads for boolean_t etc. in case of a custom BooleanType which is not -// an arithmetic type? -template::value and - not std::is_same::value and - not std::is_same::value and - not std::is_same::value and - not std::is_same::value, - int> = 0> -void from_json(const BasicJsonType& j, ArithmeticType& val) -{ - switch (static_cast(j)) - { - case value_t::number_unsigned: - { - val = static_cast(*j.template get_ptr()); - break; - } - case value_t::number_integer: - { - val = static_cast(*j.template get_ptr()); - break; - } - case value_t::number_float: - { - val = static_cast(*j.template get_ptr()); - break; - } - case value_t::boolean: - { - val = static_cast(*j.template get_ptr()); - break; - } - - default: - JSON_THROW(type_error::create(302, "type must be number, but is " + std::string(j.type_name()))); - } -} - -template -void from_json(const BasicJsonType& j, std::pair& p) -{ - p = {j.at(0).template get(), j.at(1).template get()}; -} - -template -void from_json_tuple_impl(const BasicJsonType& j, Tuple& t, index_sequence) -{ - t = std::make_tuple(j.at(Idx).template get::type>()...); -} - -template -void from_json(const BasicJsonType& j, std::tuple& t) -{ - from_json_tuple_impl(j, t, index_sequence_for {}); -} - struct to_json_fn { private: @@ -635,49 +381,6 @@ struct to_json_fn } }; -struct from_json_fn -{ - private: - template - auto call(const BasicJsonType& j, T& val, priority_tag<1> /*unused*/) const - noexcept(noexcept(from_json(j, val))) - -> decltype(from_json(j, val), void()) - { - return from_json(j, val); - } - - template - void call(const BasicJsonType& /*unused*/, T& /*unused*/, priority_tag<0> /*unused*/) const noexcept - { - static_assert(sizeof(BasicJsonType) == 0, - "could not find from_json() method in T's namespace"); -#ifdef _MSC_VER - // MSVC does not show a stacktrace for the above assert - using decayed = uncvref_t; - static_assert(sizeof(typename decayed::force_msvc_stacktrace) == 0, - "forcing MSVC stacktrace to show which T we're talking about."); -#endif - } - - public: - template - void operator()(const BasicJsonType& j, T& val) const - noexcept(noexcept(std::declval().call(j, val, priority_tag<1> {}))) - { - return call(j, val, priority_tag<1> {}); - } -}; - -// taken from ranges-v3 -template -struct static_const -{ - static constexpr T value{}; -}; - -template -constexpr T static_const::value; - //////////////////// // input adapters // //////////////////// @@ -6181,11 +5884,10 @@ class json_ref } // namespace detail -/// namespace to hold default `to_json` / `from_json` functions +/// namespace to hold default `to_json` function namespace { constexpr const auto& to_json = detail::static_const::value; -constexpr const auto& from_json = detail::static_const::value; } template From 21881606f23b91764be76631471fd629a7a0e440 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20DELRIEU?= Date: Mon, 14 Aug 2017 16:40:38 +0200 Subject: [PATCH 37/59] add detail/conversions/to_json.hpp --- Makefile | 3 +- src/detail/conversions/to_json.hpp | 337 +++++++++++++++++++++++++++++ src/json.hpp | 322 +-------------------------- 3 files changed, 340 insertions(+), 322 deletions(-) create mode 100644 src/detail/conversions/to_json.hpp diff --git a/Makefile b/Makefile index 22df2ff2..0e6a8b39 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,8 @@ SRCS = ${SRCDIR}/json.hpp \ ${SRCDIR}/detail/meta.hpp \ ${SRCDIR}/detail/exceptions.hpp \ ${SRCDIR}/detail/value_t.hpp \ - ${SRCDIR}/detail/conversions/from_json.hpp + ${SRCDIR}/detail/conversions/from_json.hpp \ + ${SRCDIR}/detail/conversions/to_json.hpp diff --git a/src/detail/conversions/to_json.hpp b/src/detail/conversions/to_json.hpp new file mode 100644 index 00000000..0c6d4749 --- /dev/null +++ b/src/detail/conversions/to_json.hpp @@ -0,0 +1,337 @@ +#ifndef NLOHMANN_JSON_DETAIL_CONVERSIONS_TO_JSON_HPP +#define NLOHMANN_JSON_DETAIL_CONVERSIONS_TO_JSON_HPP + +#include +#include +#include + +#include "detail/meta.hpp" +#include "detail/value_t.hpp" + +namespace nlohmann +{ +namespace detail +{ +////////////////// +// constructors // +////////////////// + +template struct external_constructor; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, typename BasicJsonType::boolean_t b) noexcept + { + j.m_type = value_t::boolean; + j.m_value = b; + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, const typename BasicJsonType::string_t& s) + { + j.m_type = value_t::string; + j.m_value = s; + j.assert_invariant(); + } + + template + static void construct(BasicJsonType& j, typename BasicJsonType::string_t&& s) + { + j.m_type = value_t::string; + j.m_value = std::move(s); + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, typename BasicJsonType::number_float_t val) noexcept + { + j.m_type = value_t::number_float; + j.m_value = val; + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, typename BasicJsonType::number_unsigned_t val) noexcept + { + j.m_type = value_t::number_unsigned; + j.m_value = val; + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, typename BasicJsonType::number_integer_t val) noexcept + { + j.m_type = value_t::number_integer; + j.m_value = val; + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, const typename BasicJsonType::array_t& arr) + { + j.m_type = value_t::array; + j.m_value = arr; + j.assert_invariant(); + } + + template + static void construct(BasicJsonType& j, typename BasicJsonType::array_t&& arr) + { + j.m_type = value_t::array; + j.m_value = std::move(arr); + j.assert_invariant(); + } + + template::value, + int> = 0> + static void construct(BasicJsonType& j, const CompatibleArrayType& arr) + { + using std::begin; + using std::end; + j.m_type = value_t::array; + j.m_value.array = j.template create(begin(arr), end(arr)); + j.assert_invariant(); + } + + template + static void construct(BasicJsonType& j, const std::vector& arr) + { + j.m_type = value_t::array; + j.m_value = value_t::array; + j.m_value.array->reserve(arr.size()); + for (const bool x : arr) + { + j.m_value.array->push_back(x); + } + j.assert_invariant(); + } + + template::value, int> = 0> + static void construct(BasicJsonType& j, const std::valarray& arr) + { + j.m_type = value_t::array; + j.m_value = value_t::array; + j.m_value.array->resize(arr.size()); + std::copy(std::begin(arr), std::end(arr), j.m_value.array->begin()); + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, const typename BasicJsonType::object_t& obj) + { + j.m_type = value_t::object; + j.m_value = obj; + j.assert_invariant(); + } + + template + static void construct(BasicJsonType& j, typename BasicJsonType::object_t&& obj) + { + j.m_type = value_t::object; + j.m_value = std::move(obj); + j.assert_invariant(); + } + + template::value, int> = 0> + static void construct(BasicJsonType& j, const CompatibleObjectType& obj) + { + using std::begin; + using std::end; + + j.m_type = value_t::object; + j.m_value.object = j.template create(begin(obj), end(obj)); + j.assert_invariant(); + } +}; + +///////////// +// to_json // +///////////// + +template::value, int> = 0> +void to_json(BasicJsonType& j, T b) noexcept +{ + external_constructor::construct(j, b); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, const CompatibleString& s) +{ + external_constructor::construct(j, s); +} + +template +void to_json(BasicJsonType& j, typename BasicJsonType::string_t&& s) +{ + external_constructor::construct(j, std::move(s)); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, FloatType val) noexcept +{ + external_constructor::construct(j, static_cast(val)); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, CompatibleNumberUnsignedType val) noexcept +{ + external_constructor::construct(j, static_cast(val)); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, CompatibleNumberIntegerType val) noexcept +{ + external_constructor::construct(j, static_cast(val)); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, EnumType e) noexcept +{ + using underlying_type = typename std::underlying_type::type; + external_constructor::construct(j, static_cast(e)); +} + +template +void to_json(BasicJsonType& j, const std::vector& e) +{ + external_constructor::construct(j, e); +} + +template::value or + std::is_same::value, + int> = 0> +void to_json(BasicJsonType& j, const CompatibleArrayType& arr) +{ + external_constructor::construct(j, arr); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, std::valarray arr) +{ + external_constructor::construct(j, std::move(arr)); +} + +template +void to_json(BasicJsonType& j, typename BasicJsonType::array_t&& arr) +{ + external_constructor::construct(j, std::move(arr)); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, const CompatibleObjectType& obj) +{ + external_constructor::construct(j, obj); +} + +template +void to_json(BasicJsonType& j, typename BasicJsonType::object_t&& obj) +{ + external_constructor::construct(j, std::move(obj)); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, T (&arr)[N]) +{ + external_constructor::construct(j, arr); +} + +template +void to_json(BasicJsonType& j, const std::pair& p) +{ + j = {p.first, p.second}; +} + +template +void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence) +{ + j = {std::get(t)...}; +} + +template +void to_json(BasicJsonType& j, const std::tuple& t) +{ + to_json_tuple_impl(j, t, index_sequence_for {}); +} + +struct to_json_fn +{ + private: + template + auto call(BasicJsonType& j, T&& val, priority_tag<1> /*unused*/) const noexcept(noexcept(to_json(j, std::forward(val)))) + -> decltype(to_json(j, std::forward(val)), void()) + { + return to_json(j, std::forward(val)); + } + + template + void call(BasicJsonType& /*unused*/, T&& /*unused*/, priority_tag<0> /*unused*/) const noexcept + { + static_assert(sizeof(BasicJsonType) == 0, + "could not find to_json() method in T's namespace"); + +#ifdef _MSC_VER + // MSVC does not show a stacktrace for the above assert + using decayed = uncvref_t; + static_assert(sizeof(typename decayed::force_msvc_stacktrace) == 0, + "forcing MSVC stacktrace to show which T we're talking about."); +#endif + } + + public: + template + void operator()(BasicJsonType& j, T&& val) const + noexcept(noexcept(std::declval().call(j, std::forward(val), priority_tag<1> {}))) + { + return call(j, std::forward(val), priority_tag<1> {}); + } +}; +} + +/// namespace to hold default `to_json` function +namespace +{ +constexpr const auto& to_json = detail::static_const::value; +} +} + +#endif diff --git a/src/json.hpp b/src/json.hpp index e7ce109a..ae7d727e 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -49,7 +49,6 @@ SOFTWARE. #include // accumulate #include // stringstream #include // declval, forward, make_pair, move, pair, swap -#include // valarray #include "json_fwd.hpp" #include "detail/macro_scope.hpp" @@ -57,6 +56,7 @@ SOFTWARE. #include "detail/exceptions.hpp" #include "detail/value_t.hpp" #include "detail/conversions/from_json.hpp" +#include "detail/conversions/to_json.hpp" /*! @brief namespace for Niels Lohmann @@ -67,320 +67,6 @@ namespace nlohmann { namespace detail { -////////////////// -// constructors // -////////////////// - -template struct external_constructor; - -template<> -struct external_constructor -{ - template - static void construct(BasicJsonType& j, typename BasicJsonType::boolean_t b) noexcept - { - j.m_type = value_t::boolean; - j.m_value = b; - j.assert_invariant(); - } -}; - -template<> -struct external_constructor -{ - template - static void construct(BasicJsonType& j, const typename BasicJsonType::string_t& s) - { - j.m_type = value_t::string; - j.m_value = s; - j.assert_invariant(); - } - - template - static void construct(BasicJsonType& j, typename BasicJsonType::string_t&& s) - { - j.m_type = value_t::string; - j.m_value = std::move(s); - j.assert_invariant(); - } -}; - -template<> -struct external_constructor -{ - template - static void construct(BasicJsonType& j, typename BasicJsonType::number_float_t val) noexcept - { - j.m_type = value_t::number_float; - j.m_value = val; - j.assert_invariant(); - } -}; - -template<> -struct external_constructor -{ - template - static void construct(BasicJsonType& j, typename BasicJsonType::number_unsigned_t val) noexcept - { - j.m_type = value_t::number_unsigned; - j.m_value = val; - j.assert_invariant(); - } -}; - -template<> -struct external_constructor -{ - template - static void construct(BasicJsonType& j, typename BasicJsonType::number_integer_t val) noexcept - { - j.m_type = value_t::number_integer; - j.m_value = val; - j.assert_invariant(); - } -}; - -template<> -struct external_constructor -{ - template - static void construct(BasicJsonType& j, const typename BasicJsonType::array_t& arr) - { - j.m_type = value_t::array; - j.m_value = arr; - j.assert_invariant(); - } - - template - static void construct(BasicJsonType& j, typename BasicJsonType::array_t&& arr) - { - j.m_type = value_t::array; - j.m_value = std::move(arr); - j.assert_invariant(); - } - - template::value, - int> = 0> - static void construct(BasicJsonType& j, const CompatibleArrayType& arr) - { - using std::begin; - using std::end; - j.m_type = value_t::array; - j.m_value.array = j.template create(begin(arr), end(arr)); - j.assert_invariant(); - } - - template - static void construct(BasicJsonType& j, const std::vector& arr) - { - j.m_type = value_t::array; - j.m_value = value_t::array; - j.m_value.array->reserve(arr.size()); - for (const bool x : arr) - { - j.m_value.array->push_back(x); - } - j.assert_invariant(); - } - - template::value, int> = 0> - static void construct(BasicJsonType& j, const std::valarray& arr) - { - j.m_type = value_t::array; - j.m_value = value_t::array; - j.m_value.array->resize(arr.size()); - std::copy(std::begin(arr), std::end(arr), j.m_value.array->begin()); - j.assert_invariant(); - } -}; - -template<> -struct external_constructor -{ - template - static void construct(BasicJsonType& j, const typename BasicJsonType::object_t& obj) - { - j.m_type = value_t::object; - j.m_value = obj; - j.assert_invariant(); - } - - template - static void construct(BasicJsonType& j, typename BasicJsonType::object_t&& obj) - { - j.m_type = value_t::object; - j.m_value = std::move(obj); - j.assert_invariant(); - } - - template::value, int> = 0> - static void construct(BasicJsonType& j, const CompatibleObjectType& obj) - { - using std::begin; - using std::end; - - j.m_type = value_t::object; - j.m_value.object = j.template create(begin(obj), end(obj)); - j.assert_invariant(); - } -}; - -///////////// -// to_json // -///////////// - -template::value, int> = 0> -void to_json(BasicJsonType& j, T b) noexcept -{ - external_constructor::construct(j, b); -} - -template::value, int> = 0> -void to_json(BasicJsonType& j, const CompatibleString& s) -{ - external_constructor::construct(j, s); -} - -template -void to_json(BasicJsonType& j, typename BasicJsonType::string_t&& s) -{ - external_constructor::construct(j, std::move(s)); -} - -template::value, int> = 0> -void to_json(BasicJsonType& j, FloatType val) noexcept -{ - external_constructor::construct(j, static_cast(val)); -} - -template::value, int> = 0> -void to_json(BasicJsonType& j, CompatibleNumberUnsignedType val) noexcept -{ - external_constructor::construct(j, static_cast(val)); -} - -template::value, int> = 0> -void to_json(BasicJsonType& j, CompatibleNumberIntegerType val) noexcept -{ - external_constructor::construct(j, static_cast(val)); -} - -template::value, int> = 0> -void to_json(BasicJsonType& j, EnumType e) noexcept -{ - using underlying_type = typename std::underlying_type::type; - external_constructor::construct(j, static_cast(e)); -} - -template -void to_json(BasicJsonType& j, const std::vector& e) -{ - external_constructor::construct(j, e); -} - -template::value or - std::is_same::value, - int> = 0> -void to_json(BasicJsonType& j, const CompatibleArrayType& arr) -{ - external_constructor::construct(j, arr); -} - -template::value, int> = 0> -void to_json(BasicJsonType& j, std::valarray arr) -{ - external_constructor::construct(j, std::move(arr)); -} - -template -void to_json(BasicJsonType& j, typename BasicJsonType::array_t&& arr) -{ - external_constructor::construct(j, std::move(arr)); -} - -template::value, int> = 0> -void to_json(BasicJsonType& j, const CompatibleObjectType& obj) -{ - external_constructor::construct(j, obj); -} - -template -void to_json(BasicJsonType& j, typename BasicJsonType::object_t&& obj) -{ - external_constructor::construct(j, std::move(obj)); -} - -template::value, int> = 0> -void to_json(BasicJsonType& j, T (&arr)[N]) -{ - external_constructor::construct(j, arr); -} - -template -void to_json(BasicJsonType& j, const std::pair& p) -{ - j = {p.first, p.second}; -} - -template -void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence) -{ - j = {std::get(t)...}; -} - -template -void to_json(BasicJsonType& j, const std::tuple& t) -{ - to_json_tuple_impl(j, t, index_sequence_for {}); -} - -struct to_json_fn -{ - private: - template - auto call(BasicJsonType& j, T&& val, priority_tag<1> /*unused*/) const noexcept(noexcept(to_json(j, std::forward(val)))) - -> decltype(to_json(j, std::forward(val)), void()) - { - return to_json(j, std::forward(val)); - } - - template - void call(BasicJsonType& /*unused*/, T&& /*unused*/, priority_tag<0> /*unused*/) const noexcept - { - static_assert(sizeof(BasicJsonType) == 0, - "could not find to_json() method in T's namespace"); - -#ifdef _MSC_VER - // MSVC does not show a stacktrace for the above assert - using decayed = uncvref_t; - static_assert(sizeof(typename decayed::force_msvc_stacktrace) == 0, - "forcing MSVC stacktrace to show which T we're talking about."); -#endif - } - - public: - template - void operator()(BasicJsonType& j, T&& val) const - noexcept(noexcept(std::declval().call(j, std::forward(val), priority_tag<1> {}))) - { - return call(j, std::forward(val), priority_tag<1> {}); - } -}; - //////////////////// // input adapters // //////////////////// @@ -5884,12 +5570,6 @@ class json_ref } // namespace detail -/// namespace to hold default `to_json` function -namespace -{ -constexpr const auto& to_json = detail::static_const::value; -} - template struct adl_serializer { From 7ab3e8d7b3007747a0da9e4ef9cff4e2f5c6d870 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20DELRIEU?= Date: Mon, 14 Aug 2017 16:48:55 +0200 Subject: [PATCH 38/59] add detail/parsing/input_adapters.hpp --- Makefile | 3 +- src/detail/parsing/input_adapters.hpp | 258 ++++++++++++++++++++++++++ src/json.hpp | 240 +----------------------- 3 files changed, 261 insertions(+), 240 deletions(-) create mode 100644 src/detail/parsing/input_adapters.hpp diff --git a/Makefile b/Makefile index 0e6a8b39..9a3060af 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,8 @@ SRCS = ${SRCDIR}/json.hpp \ ${SRCDIR}/detail/exceptions.hpp \ ${SRCDIR}/detail/value_t.hpp \ ${SRCDIR}/detail/conversions/from_json.hpp \ - ${SRCDIR}/detail/conversions/to_json.hpp + ${SRCDIR}/detail/conversions/to_json.hpp \ + ${SRCDIR}/detail/parsing/input_adapters.hpp diff --git a/src/detail/parsing/input_adapters.hpp b/src/detail/parsing/input_adapters.hpp new file mode 100644 index 00000000..17cf5892 --- /dev/null +++ b/src/detail/parsing/input_adapters.hpp @@ -0,0 +1,258 @@ +#ifndef NLOHMANN_JSON_DETAIL_PARSING_INPUT_ADAPTERS_HPP +#define NLOHMANN_JSON_DETAIL_PARSING_INPUT_ADAPTERS_HPP + +#include +#include +#include +#include +#include +#include + +#include "detail/macro_scope.hpp" + +namespace nlohmann +{ +namespace detail +{ +//////////////////// +// input adapters // +//////////////////// + +/*! +@brief abstract input adapter interface + +Produces a stream of std::char_traits::int_type characters from a +std::istream, a buffer, or some other input type. Accepts the return of exactly +one non-EOF character for future input. The int_type characters returned +consist of all valid char values as positive values (typically unsigned char), +plus an EOF value outside that range, specified by the value of the function +std::char_traits::eof(). This value is typically -1, but could be any +arbitrary value which is not a valid char value. +*/ +struct input_adapter_protocol +{ + /// get a character [0,255] or std::char_traits::eof(). + virtual std::char_traits::int_type get_character() = 0; + /// restore the last non-eof() character to input + virtual void unget_character() = 0; + virtual ~input_adapter_protocol() = default; +}; + +/// a type to simplify interfaces +using input_adapter_t = std::shared_ptr; + +/*! +Input adapter for a (caching) istream. Ignores a UFT Byte Order Mark at +beginning of input. Does not support changing the underlying std::streambuf +in mid-input. Maintains underlying std::istream and std::streambuf to support +subsequent use of standard std::istream operations to process any input +characters following those used in parsing the JSON input. Clears the +std::istream flags; any input errors (e.g., EOF) will be detected by the first +subsequent call for input from the std::istream. +*/ +class input_stream_adapter : public input_adapter_protocol +{ + public: + ~input_stream_adapter() override + { + // clear stream flags; we use underlying streambuf I/O, do not + // maintain ifstream flags + is.clear(); + } + + explicit input_stream_adapter(std::istream& i) + : is(i), sb(*i.rdbuf()) + { + // skip byte order mark + std::char_traits::int_type c; + if ((c = get_character()) == 0xEF) + { + if ((c = get_character()) == 0xBB) + { + if ((c = get_character()) == 0xBF) + { + return; // Ignore BOM + } + else if (c != std::char_traits::eof()) + { + is.unget(); + } + is.putback('\xBB'); + } + else if (c != std::char_traits::eof()) + { + is.unget(); + } + is.putback('\xEF'); + } + else if (c != std::char_traits::eof()) + { + is.unget(); // no byte order mark; process as usual + } + } + + // delete because of pointer members + input_stream_adapter(const input_stream_adapter&) = delete; + input_stream_adapter& operator=(input_stream_adapter&) = delete; + + // std::istream/std::streambuf use std::char_traits::to_int_type, to + // ensure that std::char_traits::eof() and the character 0xFF do not + // end up as the same value, eg. 0xFFFFFFFF. + std::char_traits::int_type get_character() override + { + return sb.sbumpc(); + } + + void unget_character() override + { + sb.sungetc(); // is.unget() avoided for performance + } + + private: + /// the associated input stream + std::istream& is; + std::streambuf& sb; +}; + +/// input adapter for buffer input +class input_buffer_adapter : public input_adapter_protocol +{ + public: + input_buffer_adapter(const char* b, const std::size_t l) + : cursor(b), limit(b + l), start(b) + { + // skip byte order mark + if (l >= 3 and b[0] == '\xEF' and b[1] == '\xBB' and b[2] == '\xBF') + { + cursor += 3; + } + } + + // delete because of pointer members + input_buffer_adapter(const input_buffer_adapter&) = delete; + input_buffer_adapter& operator=(input_buffer_adapter&) = delete; + + std::char_traits::int_type get_character() noexcept override + { + if (JSON_LIKELY(cursor < limit)) + { + return std::char_traits::to_int_type(*(cursor++)); + } + + return std::char_traits::eof(); + } + + void unget_character() noexcept override + { + if (JSON_LIKELY(cursor > start)) + { + --cursor; + } + } + + private: + /// pointer to the current character + const char* cursor; + /// pointer past the last character + const char* limit; + /// pointer to the first character + const char* start; +}; + +class input_adapter +{ + public: + // native support + + /// input adapter for input stream + input_adapter(std::istream& i) + : ia(std::make_shared(i)) {} + + /// input adapter for input stream + input_adapter(std::istream&& i) + : ia(std::make_shared(i)) {} + + /// input adapter for buffer + template::value and + std::is_integral::type>::value and + sizeof(typename std::remove_pointer::type) == 1, + int>::type = 0> + input_adapter(CharT b, std::size_t l) + : ia(std::make_shared(reinterpret_cast(b), l)) {} + + // derived support + + /// input adapter for string literal + template::value and + std::is_integral::type>::value and + sizeof(typename std::remove_pointer::type) == 1, + int>::type = 0> + input_adapter(CharT b) + : input_adapter(reinterpret_cast(b), + std::strlen(reinterpret_cast(b))) {} + + /// input adapter for iterator range with contiguous storage + template::iterator_category, std::random_access_iterator_tag>::value, + int>::type = 0> + input_adapter(IteratorType first, IteratorType last) + { + // assertion to check that the iterator range is indeed contiguous, + // see http://stackoverflow.com/a/35008842/266378 for more discussion + assert(std::accumulate( + first, last, std::pair(true, 0), + [&first](std::pair res, decltype(*first) val) + { + res.first &= (val == *(std::next(std::addressof(*first), res.second++))); + return res; + }).first); + + // assertion to check that each element is 1 byte long + static_assert( + sizeof(typename std::iterator_traits::value_type) == 1, + "each element in the iterator range must have the size of 1 byte"); + + const auto len = static_cast(std::distance(first, last)); + if (JSON_LIKELY(len > 0)) + { + // there is at least one element: use the address of first + ia = std::make_shared(reinterpret_cast(&(*first)), len); + } + else + { + // the address of first cannot be used: use nullptr + ia = std::make_shared(nullptr, len); + } + } + + /// input adapter for array + template + input_adapter(T (&array)[N]) + : input_adapter(std::begin(array), std::end(array)) {} + + /// input adapter for contiguous container + template::value and + std::is_base_of()))>::iterator_category>::value, + int>::type = 0> + input_adapter(const ContiguousContainer& c) + : input_adapter(std::begin(c), std::end(c)) {} + + operator input_adapter_t() + { + return ia; + } + + private: + /// the actual adapter + input_adapter_t ia = nullptr; +}; +} +} + +#endif diff --git a/src/json.hpp b/src/json.hpp index ae7d727e..f3fea0b8 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -57,6 +57,7 @@ SOFTWARE. #include "detail/value_t.hpp" #include "detail/conversions/from_json.hpp" #include "detail/conversions/to_json.hpp" +#include "detail/parsing/input_adapters.hpp" /*! @brief namespace for Niels Lohmann @@ -67,245 +68,6 @@ namespace nlohmann { namespace detail { -//////////////////// -// input adapters // -//////////////////// - -/*! -@brief abstract input adapter interface - -Produces a stream of std::char_traits::int_type characters from a -std::istream, a buffer, or some other input type. Accepts the return of exactly -one non-EOF character for future input. The int_type characters returned -consist of all valid char values as positive values (typically unsigned char), -plus an EOF value outside that range, specified by the value of the function -std::char_traits::eof(). This value is typically -1, but could be any -arbitrary value which is not a valid char value. -*/ -struct input_adapter_protocol -{ - /// get a character [0,255] or std::char_traits::eof(). - virtual std::char_traits::int_type get_character() = 0; - /// restore the last non-eof() character to input - virtual void unget_character() = 0; - virtual ~input_adapter_protocol() = default; -}; - -/// a type to simplify interfaces -using input_adapter_t = std::shared_ptr; - -/*! -Input adapter for a (caching) istream. Ignores a UFT Byte Order Mark at -beginning of input. Does not support changing the underlying std::streambuf -in mid-input. Maintains underlying std::istream and std::streambuf to support -subsequent use of standard std::istream operations to process any input -characters following those used in parsing the JSON input. Clears the -std::istream flags; any input errors (e.g., EOF) will be detected by the first -subsequent call for input from the std::istream. -*/ -class input_stream_adapter : public input_adapter_protocol -{ - public: - ~input_stream_adapter() override - { - // clear stream flags; we use underlying streambuf I/O, do not - // maintain ifstream flags - is.clear(); - } - - explicit input_stream_adapter(std::istream& i) - : is(i), sb(*i.rdbuf()) - { - // skip byte order mark - std::char_traits::int_type c; - if ((c = get_character()) == 0xEF) - { - if ((c = get_character()) == 0xBB) - { - if ((c = get_character()) == 0xBF) - { - return; // Ignore BOM - } - else if (c != std::char_traits::eof()) - { - is.unget(); - } - is.putback('\xBB'); - } - else if (c != std::char_traits::eof()) - { - is.unget(); - } - is.putback('\xEF'); - } - else if (c != std::char_traits::eof()) - { - is.unget(); // no byte order mark; process as usual - } - } - - // delete because of pointer members - input_stream_adapter(const input_stream_adapter&) = delete; - input_stream_adapter& operator=(input_stream_adapter&) = delete; - - // std::istream/std::streambuf use std::char_traits::to_int_type, to - // ensure that std::char_traits::eof() and the character 0xFF do not - // end up as the same value, eg. 0xFFFFFFFF. - std::char_traits::int_type get_character() override - { - return sb.sbumpc(); - } - - void unget_character() override - { - sb.sungetc(); // is.unget() avoided for performance - } - - private: - /// the associated input stream - std::istream& is; - std::streambuf& sb; -}; - -/// input adapter for buffer input -class input_buffer_adapter : public input_adapter_protocol -{ - public: - input_buffer_adapter(const char* b, const std::size_t l) - : cursor(b), limit(b + l), start(b) - { - // skip byte order mark - if (l >= 3 and b[0] == '\xEF' and b[1] == '\xBB' and b[2] == '\xBF') - { - cursor += 3; - } - } - - // delete because of pointer members - input_buffer_adapter(const input_buffer_adapter&) = delete; - input_buffer_adapter& operator=(input_buffer_adapter&) = delete; - - std::char_traits::int_type get_character() noexcept override - { - if (JSON_LIKELY(cursor < limit)) - { - return std::char_traits::to_int_type(*(cursor++)); - } - - return std::char_traits::eof(); - } - - void unget_character() noexcept override - { - if (JSON_LIKELY(cursor > start)) - { - --cursor; - } - } - - private: - /// pointer to the current character - const char* cursor; - /// pointer past the last character - const char* limit; - /// pointer to the first character - const char* start; -}; - -class input_adapter -{ - public: - // native support - - /// input adapter for input stream - input_adapter(std::istream& i) - : ia(std::make_shared(i)) {} - - /// input adapter for input stream - input_adapter(std::istream&& i) - : ia(std::make_shared(i)) {} - - /// input adapter for buffer - template::value and - std::is_integral::type>::value and - sizeof(typename std::remove_pointer::type) == 1, - int>::type = 0> - input_adapter(CharT b, std::size_t l) - : ia(std::make_shared(reinterpret_cast(b), l)) {} - - // derived support - - /// input adapter for string literal - template::value and - std::is_integral::type>::value and - sizeof(typename std::remove_pointer::type) == 1, - int>::type = 0> - input_adapter(CharT b) - : input_adapter(reinterpret_cast(b), - std::strlen(reinterpret_cast(b))) {} - - /// input adapter for iterator range with contiguous storage - template::iterator_category, std::random_access_iterator_tag>::value, - int>::type = 0> - input_adapter(IteratorType first, IteratorType last) - { - // assertion to check that the iterator range is indeed contiguous, - // see http://stackoverflow.com/a/35008842/266378 for more discussion - assert(std::accumulate( - first, last, std::pair(true, 0), - [&first](std::pair res, decltype(*first) val) - { - res.first &= (val == *(std::next(std::addressof(*first), res.second++))); - return res; - }).first); - - // assertion to check that each element is 1 byte long - static_assert( - sizeof(typename std::iterator_traits::value_type) == 1, - "each element in the iterator range must have the size of 1 byte"); - - const auto len = static_cast(std::distance(first, last)); - if (JSON_LIKELY(len > 0)) - { - // there is at least one element: use the address of first - ia = std::make_shared(reinterpret_cast(&(*first)), len); - } - else - { - // the address of first cannot be used: use nullptr - ia = std::make_shared(nullptr, len); - } - } - - /// input adapter for array - template - input_adapter(T (&array)[N]) - : input_adapter(std::begin(array), std::end(array)) {} - - /// input adapter for contiguous container - template::value and - std::is_base_of()))>::iterator_category>::value, - int>::type = 0> - input_adapter(const ContiguousContainer& c) - : input_adapter(std::begin(c), std::end(c)) {} - - operator input_adapter_t() - { - return ia; - } - - private: - /// the actual adapter - input_adapter_t ia = nullptr; -}; - ////////////////////// // lexer and parser // ////////////////////// From 3a0743db9726b65b8c2fd3d12ed772076680650c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20DELRIEU?= Date: Mon, 14 Aug 2017 16:54:16 +0200 Subject: [PATCH 39/59] add detail/parsing/lexer.hpp --- Makefile | 3 +- src/detail/parsing/lexer.hpp | 1273 ++++++++++++++++++++++++++++++++++ src/json.hpp | 1259 +-------------------------------- 3 files changed, 1279 insertions(+), 1256 deletions(-) create mode 100644 src/detail/parsing/lexer.hpp diff --git a/Makefile b/Makefile index 9a3060af..aacaa00f 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,8 @@ SRCS = ${SRCDIR}/json.hpp \ ${SRCDIR}/detail/value_t.hpp \ ${SRCDIR}/detail/conversions/from_json.hpp \ ${SRCDIR}/detail/conversions/to_json.hpp \ - ${SRCDIR}/detail/parsing/input_adapters.hpp + ${SRCDIR}/detail/parsing/input_adapters.hpp \ + ${SRCDIR}/detail/parsing/lexer.hpp diff --git a/src/detail/parsing/lexer.hpp b/src/detail/parsing/lexer.hpp new file mode 100644 index 00000000..b1232db0 --- /dev/null +++ b/src/detail/parsing/lexer.hpp @@ -0,0 +1,1273 @@ +#ifndef NLOHMANN_JSON_DETAIL_PARSING_LEXER_HPP +#define NLOHMANN_JSON_DETAIL_PARSING_LEXER_HPP + +#include +#include +#include + +#include "detail/macro_scope.hpp" +#include "detail/parsing/input_adapters.hpp" + +namespace nlohmann +{ +namespace detail +{ +/////////// +// lexer // +/////////// + +/*! +@brief lexical analysis + +This class organizes the lexical analysis during JSON deserialization. +*/ +template +class lexer +{ + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + + public: + /// token types for the parser + enum class token_type + { + uninitialized, ///< indicating the scanner is uninitialized + literal_true, ///< the `true` literal + literal_false, ///< the `false` literal + literal_null, ///< the `null` literal + value_string, ///< a string -- use get_string() for actual value + value_unsigned, ///< an unsigned integer -- use get_number_unsigned() for actual value + value_integer, ///< a signed integer -- use get_number_integer() for actual value + value_float, ///< an floating point number -- use get_number_float() for actual value + begin_array, ///< the character for array begin `[` + begin_object, ///< the character for object begin `{` + end_array, ///< the character for array end `]` + end_object, ///< the character for object end `}` + name_separator, ///< the name separator `:` + value_separator, ///< the value separator `,` + parse_error, ///< indicating a parse error + end_of_input, ///< indicating the end of the input buffer + literal_or_value ///< a literal or the begin of a value (only for diagnostics) + }; + + /// return name of values of type token_type (only used for errors) + static const char* token_type_name(const token_type t) noexcept + { + switch (t) + { + case token_type::uninitialized: + return ""; + case token_type::literal_true: + return "true literal"; + case token_type::literal_false: + return "false literal"; + case token_type::literal_null: + return "null literal"; + case token_type::value_string: + return "string literal"; + case lexer::token_type::value_unsigned: + case lexer::token_type::value_integer: + case lexer::token_type::value_float: + return "number literal"; + case token_type::begin_array: + return "'['"; + case token_type::begin_object: + return "'{'"; + case token_type::end_array: + return "']'"; + case token_type::end_object: + return "'}'"; + case token_type::name_separator: + return "':'"; + case token_type::value_separator: + return "','"; + case token_type::parse_error: + return ""; + case token_type::end_of_input: + return "end of input"; + case token_type::literal_or_value: + return "'[', '{', or a literal"; + default: // catch non-enum values + return "unknown token"; // LCOV_EXCL_LINE + } + } + + explicit lexer(detail::input_adapter_t adapter) + : ia(std::move(adapter)), decimal_point_char(get_decimal_point()) {} + + // delete because of pointer members + lexer(const lexer&) = delete; + lexer& operator=(lexer&) = delete; + + private: + ///////////////////// + // locales + ///////////////////// + + /// return the locale-dependent decimal point + static char get_decimal_point() noexcept + { + const auto loc = localeconv(); + assert(loc != nullptr); + return (loc->decimal_point == nullptr) ? '.' : *(loc->decimal_point); + } + + ///////////////////// + // scan functions + ///////////////////// + + /*! + @brief get codepoint from 4 hex characters following `\u` + + For input "\u c1 c2 c3 c4" the codepoint is: + (c1 * 0x1000) + (c2 * 0x0100) + (c3 * 0x0010) + c4 + = (c1 << 12) + (c2 << 8) + (c3 << 4) + (c4 << 0) + + Furthermore, the possible characters '0'..'9', 'A'..'F', and 'a'..'f' + must be converted to the integers 0x0..0x9, 0xA..0xF, 0xA..0xF, resp. The + conversion is done by subtracting the offset (0x30, 0x37, and 0x57) + between the ASCII value of the character and the desired integer value. + + @return codepoint (0x0000..0xFFFF) or -1 in case of an error (e.g. EOF or + non-hex character) + */ + int get_codepoint() + { + // this function only makes sense after reading `\u` + assert(current == 'u'); + int codepoint = 0; + + const auto factors = { 12, 8, 4, 0 }; + for (const auto factor : factors) + { + get(); + + if (current >= '0' and current <= '9') + { + codepoint += ((current - 0x30) << factor); + } + else if (current >= 'A' and current <= 'F') + { + codepoint += ((current - 0x37) << factor); + } + else if (current >= 'a' and current <= 'f') + { + codepoint += ((current - 0x57) << factor); + } + else + { + return -1; + } + } + + assert(0x0000 <= codepoint and codepoint <= 0xFFFF); + return codepoint; + } + + /*! + @brief check if the next byte(s) are inside a given range + + Adds the current byte and, for each passed range, reads a new byte and + checks if it is inside the range. If a violation was detected, set up an + error message and return false. Otherwise, return true. + + @param[in] ranges list of integers; interpreted as list of pairs of + inclusive lower and upper bound, respectively + + @pre The passed list @a ranges must have 2, 4, or 6 elements; that is, + 1, 2, or 3 pairs. This precondition is enforced by an assertion. + + @return true if and only if no range violation was detected + */ + bool next_byte_in_range(std::initializer_list ranges) + { + assert(ranges.size() == 2 or ranges.size() == 4 or ranges.size() == 6); + add(current); + + for (auto range = ranges.begin(); range != ranges.end(); ++range) + { + get(); + if (JSON_LIKELY(*range <= current and current <= *(++range))) + { + add(current); + } + else + { + error_message = "invalid string: ill-formed UTF-8 byte"; + return false; + } + } + + return true; + } + + /*! + @brief scan a string literal + + This function scans a string according to Sect. 7 of RFC 7159. While + scanning, bytes are escaped and copied into buffer yytext. Then the function + returns successfully, yytext is *not* null-terminated (as it may contain \0 + bytes), and yytext.size() is the number of bytes in the string. + + @return token_type::value_string if string could be successfully scanned, + token_type::parse_error otherwise + + @note In case of errors, variable error_message contains a textual + description. + */ + token_type scan_string() + { + // reset yytext (ignore opening quote) + reset(); + + // we entered the function by reading an open quote + assert(current == '\"'); + + while (true) + { + // get next character + switch (get()) + { + // end of file while parsing string + case std::char_traits::eof(): + { + error_message = "invalid string: missing closing quote"; + return token_type::parse_error; + } + + // closing quote + case '\"': + { + return token_type::value_string; + } + + // escapes + case '\\': + { + switch (get()) + { + // quotation mark + case '\"': + add('\"'); + break; + // reverse solidus + case '\\': + add('\\'); + break; + // solidus + case '/': + add('/'); + break; + // backspace + case 'b': + add('\b'); + break; + // form feed + case 'f': + add('\f'); + break; + // line feed + case 'n': + add('\n'); + break; + // carriage return + case 'r': + add('\r'); + break; + // tab + case 't': + add('\t'); + break; + + // unicode escapes + case 'u': + { + const int codepoint1 = get_codepoint(); + int codepoint = codepoint1; // start with codepoint1 + + if (JSON_UNLIKELY(codepoint1 == -1)) + { + error_message = "invalid string: '\\u' must be followed by 4 hex digits"; + return token_type::parse_error; + } + + // check if code point is a high surrogate + if (0xD800 <= codepoint1 and codepoint1 <= 0xDBFF) + { + // expect next \uxxxx entry + if (JSON_LIKELY(get() == '\\' and get() == 'u')) + { + const int codepoint2 = get_codepoint(); + + if (JSON_UNLIKELY(codepoint2 == -1)) + { + error_message = "invalid string: '\\u' must be followed by 4 hex digits"; + return token_type::parse_error; + } + + // check if codepoint2 is a low surrogate + if (JSON_LIKELY(0xDC00 <= codepoint2 and codepoint2 <= 0xDFFF)) + { + // overwrite codepoint + codepoint = + // high surrogate occupies the most significant 22 bits + (codepoint1 << 10) + // low surrogate occupies the least significant 15 bits + + codepoint2 + // there is still the 0xD800, 0xDC00 and 0x10000 noise + // in the result so we have to subtract with: + // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00 + - 0x35FDC00; + } + else + { + error_message = "invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF"; + return token_type::parse_error; + } + } + else + { + error_message = "invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF"; + return token_type::parse_error; + } + } + else + { + if (JSON_UNLIKELY(0xDC00 <= codepoint1 and codepoint1 <= 0xDFFF)) + { + error_message = "invalid string: surrogate U+DC00..U+DFFF must follow U+D800..U+DBFF"; + return token_type::parse_error; + } + } + + // result of the above calculation yields a proper codepoint + assert(0x00 <= codepoint and codepoint <= 0x10FFFF); + + // translate codepoint into bytes + if (codepoint < 0x80) + { + // 1-byte characters: 0xxxxxxx (ASCII) + add(codepoint); + } + else if (codepoint <= 0x7FF) + { + // 2-byte characters: 110xxxxx 10xxxxxx + add(0xC0 | (codepoint >> 6)); + add(0x80 | (codepoint & 0x3F)); + } + else if (codepoint <= 0xFFFF) + { + // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx + add(0xE0 | (codepoint >> 12)); + add(0x80 | ((codepoint >> 6) & 0x3F)); + add(0x80 | (codepoint & 0x3F)); + } + else + { + // 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + add(0xF0 | (codepoint >> 18)); + add(0x80 | ((codepoint >> 12) & 0x3F)); + add(0x80 | ((codepoint >> 6) & 0x3F)); + add(0x80 | (codepoint & 0x3F)); + } + + break; + } + + // other characters after escape + default: + error_message = "invalid string: forbidden character after backslash"; + return token_type::parse_error; + } + + break; + } + + // invalid control characters + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + case 0x09: + case 0x0A: + case 0x0B: + case 0x0C: + case 0x0D: + case 0x0E: + case 0x0F: + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + case 0x1A: + case 0x1B: + case 0x1C: + case 0x1D: + case 0x1E: + case 0x1F: + { + error_message = "invalid string: control character must be escaped"; + return token_type::parse_error; + } + + // U+0020..U+007F (except U+0022 (quote) and U+005C (backspace)) + case 0x20: + case 0x21: + case 0x23: + case 0x24: + case 0x25: + case 0x26: + case 0x27: + case 0x28: + case 0x29: + case 0x2A: + case 0x2B: + case 0x2C: + case 0x2D: + case 0x2E: + case 0x2F: + case 0x30: + case 0x31: + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: + case 0x38: + case 0x39: + case 0x3A: + case 0x3B: + case 0x3C: + case 0x3D: + case 0x3E: + case 0x3F: + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + case 0x48: + case 0x49: + case 0x4A: + case 0x4B: + case 0x4C: + case 0x4D: + case 0x4E: + case 0x4F: + case 0x50: + case 0x51: + case 0x52: + case 0x53: + case 0x54: + case 0x55: + case 0x56: + case 0x57: + case 0x58: + case 0x59: + case 0x5A: + case 0x5B: + case 0x5D: + case 0x5E: + case 0x5F: + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: + case 0x68: + case 0x69: + case 0x6A: + case 0x6B: + case 0x6C: + case 0x6D: + case 0x6E: + case 0x6F: + case 0x70: + case 0x71: + case 0x72: + case 0x73: + case 0x74: + case 0x75: + case 0x76: + case 0x77: + case 0x78: + case 0x79: + case 0x7A: + case 0x7B: + case 0x7C: + case 0x7D: + case 0x7E: + case 0x7F: + { + add(current); + break; + } + + // U+0080..U+07FF: bytes C2..DF 80..BF + case 0xC2: + case 0xC3: + case 0xC4: + case 0xC5: + case 0xC6: + case 0xC7: + case 0xC8: + case 0xC9: + case 0xCA: + case 0xCB: + case 0xCC: + case 0xCD: + case 0xCE: + case 0xCF: + case 0xD0: + case 0xD1: + case 0xD2: + case 0xD3: + case 0xD4: + case 0xD5: + case 0xD6: + case 0xD7: + case 0xD8: + case 0xD9: + case 0xDA: + case 0xDB: + case 0xDC: + case 0xDD: + case 0xDE: + case 0xDF: + { + if (JSON_UNLIKELY(not next_byte_in_range({0x80, 0xBF}))) + { + return token_type::parse_error; + } + break; + } + + // U+0800..U+0FFF: bytes E0 A0..BF 80..BF + case 0xE0: + { + if (JSON_UNLIKELY(not (next_byte_in_range({0xA0, 0xBF, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // U+1000..U+CFFF: bytes E1..EC 80..BF 80..BF + // U+E000..U+FFFF: bytes EE..EF 80..BF 80..BF + case 0xE1: + case 0xE2: + case 0xE3: + case 0xE4: + case 0xE5: + case 0xE6: + case 0xE7: + case 0xE8: + case 0xE9: + case 0xEA: + case 0xEB: + case 0xEC: + case 0xEE: + case 0xEF: + { + if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0xBF, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // U+D000..U+D7FF: bytes ED 80..9F 80..BF + case 0xED: + { + if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0x9F, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // U+10000..U+3FFFF F0 90..BF 80..BF 80..BF + case 0xF0: + { + if (JSON_UNLIKELY(not (next_byte_in_range({0x90, 0xBF, 0x80, 0xBF, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // U+40000..U+FFFFF F1..F3 80..BF 80..BF 80..BF + case 0xF1: + case 0xF2: + case 0xF3: + { + if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0xBF, 0x80, 0xBF, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // U+100000..U+10FFFF F4 80..8F 80..BF 80..BF + case 0xF4: + { + if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0x8F, 0x80, 0xBF, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // remaining bytes (80..C1 and F5..FF) are ill-formed + default: + { + error_message = "invalid string: ill-formed UTF-8 byte"; + return token_type::parse_error; + } + } + } + } + + static void strtof(float& f, const char* str, char** endptr) noexcept + { + f = std::strtof(str, endptr); + } + + static void strtof(double& f, const char* str, char** endptr) noexcept + { + f = std::strtod(str, endptr); + } + + static void strtof(long double& f, const char* str, char** endptr) noexcept + { + f = std::strtold(str, endptr); + } + + /*! + @brief scan a number literal + + This function scans a string according to Sect. 6 of RFC 7159. + + The function is realized with a deterministic finite state machine derived + from the grammar described in RFC 7159. Starting in state "init", the + input is read and used to determined the next state. Only state "done" + accepts the number. State "error" is a trap state to model errors. In the + table below, "anything" means any character but the ones listed before. + + state | 0 | 1-9 | e E | + | - | . | anything + ---------|----------|----------|----------|---------|---------|----------|----------- + init | zero | any1 | [error] | [error] | minus | [error] | [error] + minus | zero | any1 | [error] | [error] | [error] | [error] | [error] + zero | done | done | exponent | done | done | decimal1 | done + any1 | any1 | any1 | exponent | done | done | decimal1 | done + decimal1 | decimal2 | [error] | [error] | [error] | [error] | [error] | [error] + decimal2 | decimal2 | decimal2 | exponent | done | done | done | done + exponent | any2 | any2 | [error] | sign | sign | [error] | [error] + sign | any2 | any2 | [error] | [error] | [error] | [error] | [error] + any2 | any2 | any2 | done | done | done | done | done + + The state machine is realized with one label per state (prefixed with + "scan_number_") and `goto` statements between them. The state machine + contains cycles, but any cycle can be left when EOF is read. Therefore, + the function is guaranteed to terminate. + + During scanning, the read bytes are stored in yytext. This string is + then converted to a signed integer, an unsigned integer, or a + floating-point number. + + @return token_type::value_unsigned, token_type::value_integer, or + token_type::value_float if number could be successfully scanned, + token_type::parse_error otherwise + + @note The scanner is independent of the current locale. Internally, the + locale's decimal point is used instead of `.` to work with the + locale-dependent converters. + */ + token_type scan_number() + { + // reset yytext to store the number's bytes + reset(); + + // the type of the parsed number; initially set to unsigned; will be + // changed if minus sign, decimal point or exponent is read + token_type number_type = token_type::value_unsigned; + + // state (init): we just found out we need to scan a number + switch (current) + { + case '-': + { + add(current); + goto scan_number_minus; + } + + case '0': + { + add(current); + goto scan_number_zero; + } + + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any1; + } + + default: + { + // all other characters are rejected outside scan_number() + assert(false); // LCOV_EXCL_LINE + } + } + +scan_number_minus: + // state: we just parsed a leading minus sign + number_type = token_type::value_integer; + switch (get()) + { + case '0': + { + add(current); + goto scan_number_zero; + } + + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any1; + } + + default: + { + error_message = "invalid number; expected digit after '-'"; + return token_type::parse_error; + } + } + +scan_number_zero: + // state: we just parse a zero (maybe with a leading minus sign) + switch (get()) + { + case '.': + { + add(decimal_point_char); + goto scan_number_decimal1; + } + + case 'e': + case 'E': + { + add(current); + goto scan_number_exponent; + } + + default: + goto scan_number_done; + } + +scan_number_any1: + // state: we just parsed a number 0-9 (maybe with a leading minus sign) + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any1; + } + + case '.': + { + add(decimal_point_char); + goto scan_number_decimal1; + } + + case 'e': + case 'E': + { + add(current); + goto scan_number_exponent; + } + + default: + goto scan_number_done; + } + +scan_number_decimal1: + // state: we just parsed a decimal point + number_type = token_type::value_float; + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_decimal2; + } + + default: + { + error_message = "invalid number; expected digit after '.'"; + return token_type::parse_error; + } + } + +scan_number_decimal2: + // we just parsed at least one number after a decimal point + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_decimal2; + } + + case 'e': + case 'E': + { + add(current); + goto scan_number_exponent; + } + + default: + goto scan_number_done; + } + +scan_number_exponent: + // we just parsed an exponent + number_type = token_type::value_float; + switch (get()) + { + case '+': + case '-': + { + add(current); + goto scan_number_sign; + } + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any2; + } + + default: + { + error_message = + "invalid number; expected '+', '-', or digit after exponent"; + return token_type::parse_error; + } + } + +scan_number_sign: + // we just parsed an exponent sign + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any2; + } + + default: + { + error_message = "invalid number; expected digit after exponent sign"; + return token_type::parse_error; + } + } + +scan_number_any2: + // we just parsed a number after the exponent or exponent sign + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any2; + } + + default: + goto scan_number_done; + } + +scan_number_done: + // unget the character after the number (we only read it to know that + // we are done scanning a number) + unget(); + + char* endptr = nullptr; + errno = 0; + + // try to parse integers first and fall back to floats + if (number_type == token_type::value_unsigned) + { + const auto x = std::strtoull(yytext.data(), &endptr, 10); + + // we checked the number format before + assert(endptr == yytext.data() + yytext.size()); + + if (errno == 0) + { + value_unsigned = static_cast(x); + if (value_unsigned == x) + { + return token_type::value_unsigned; + } + } + } + else if (number_type == token_type::value_integer) + { + const auto x = std::strtoll(yytext.data(), &endptr, 10); + + // we checked the number format before + assert(endptr == yytext.data() + yytext.size()); + + if (errno == 0) + { + value_integer = static_cast(x); + if (value_integer == x) + { + return token_type::value_integer; + } + } + } + + // this code is reached if we parse a floating-point number or if an + // integer conversion above failed + strtof(value_float, yytext.data(), &endptr); + + // we checked the number format before + assert(endptr == yytext.data() + yytext.size()); + + return token_type::value_float; + } + + /*! + @param[in] literal_text the literal text to expect + @param[in] length the length of the passed literal text + @param[in] return_type the token type to return on success + */ + token_type scan_literal(const char* literal_text, const std::size_t length, + token_type return_type) + { + assert(current == literal_text[0]); + for (std::size_t i = 1; i < length; ++i) + { + if (JSON_UNLIKELY(get() != literal_text[i])) + { + error_message = "invalid literal"; + return token_type::parse_error; + } + } + return return_type; + } + + ///////////////////// + // input management + ///////////////////// + + /// reset yytext; current character is beginning of token + void reset() noexcept + { + yytext.clear(); + token_string.clear(); + token_string.push_back(std::char_traits::to_char_type(current)); + } + + /* + @brief get next character from the input + + This function provides the interface to the used input adapter. It does + not throw in case the input reached EOF, but returns a + `std::char_traits::eof()` in that case. Stores the scanned characters + for use in error messages. + + @return character read from the input + */ + std::char_traits::int_type get() + { + ++chars_read; + current = ia->get_character(); + if (JSON_LIKELY(current != std::char_traits::eof())) + { + token_string.push_back(std::char_traits::to_char_type(current)); + } + return current; + } + + /// unget current character (return it again on next get) + void unget() + { + --chars_read; + if (JSON_LIKELY(current != std::char_traits::eof())) + { + ia->unget_character(); + assert(token_string.size() != 0); + token_string.pop_back(); + } + } + + /// add a character to yytext + void add(int c) + { + yytext.push_back(std::char_traits::to_char_type(c)); + } + + public: + ///////////////////// + // value getters + ///////////////////// + + /// return integer value + constexpr number_integer_t get_number_integer() const noexcept + { + return value_integer; + } + + /// return unsigned integer value + constexpr number_unsigned_t get_number_unsigned() const noexcept + { + return value_unsigned; + } + + /// return floating-point value + constexpr number_float_t get_number_float() const noexcept + { + return value_float; + } + + /// return current string value (implicitly resets the token; useful only once) + std::string move_string() + { + return std::move(yytext); + } + + ///////////////////// + // diagnostics + ///////////////////// + + /// return position of last read token + constexpr std::size_t get_position() const noexcept + { + return chars_read; + } + + /// return the last read token (for errors only). Will never contain EOF + /// (an arbitrary value that is not a valid char value, often -1), because + /// 255 may legitimately occur. May contain NUL, which should be escaped. + std::string get_token_string() const + { + // escape control characters + std::string result; + for (const auto c : token_string) + { + if ('\x00' <= c and c <= '\x1F') + { + // escape control characters + std::stringstream ss; + ss << "(c) << ">"; + result += ss.str(); + } + else + { + // add character as is + result.push_back(c); + } + } + + return result; + } + + /// return syntax error message + constexpr const char* get_error_message() const noexcept + { + return error_message; + } + + ///////////////////// + // actual scanner + ///////////////////// + + token_type scan() + { + // read next character and ignore whitespace + do + { + get(); + } + while (current == ' ' or current == '\t' or current == '\n' or current == '\r'); + + switch (current) + { + // structural characters + case '[': + return token_type::begin_array; + case ']': + return token_type::end_array; + case '{': + return token_type::begin_object; + case '}': + return token_type::end_object; + case ':': + return token_type::name_separator; + case ',': + return token_type::value_separator; + + // literals + case 't': + return scan_literal("true", 4, token_type::literal_true); + case 'f': + return scan_literal("false", 5, token_type::literal_false); + case 'n': + return scan_literal("null", 4, token_type::literal_null); + + // string + case '\"': + return scan_string(); + + // number + case '-': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + return scan_number(); + + // end of input (the null byte is needed when parsing from + // string literals) + case '\0': + case std::char_traits::eof(): + return token_type::end_of_input; + + // error + default: + error_message = "invalid literal"; + return token_type::parse_error; + } + } + + private: + /// input adapter + detail::input_adapter_t ia = nullptr; + + /// the current character + std::char_traits::int_type current = std::char_traits::eof(); + + /// the number of characters read + std::size_t chars_read = 0; + + /// raw input token string (for error messages) + std::vector token_string {}; + + /// buffer for variable-length tokens (numbers, strings) + std::string yytext {}; + + /// a description of occurred lexer errors + const char* error_message = ""; + + // number values + number_integer_t value_integer = 0; + number_unsigned_t value_unsigned = 0; + number_float_t value_float = 0; + + /// the decimal point + const char decimal_point_char = '.'; +}; +} +} + +#endif diff --git a/src/json.hpp b/src/json.hpp index f3fea0b8..d93ba316 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -58,6 +58,7 @@ SOFTWARE. #include "detail/conversions/from_json.hpp" #include "detail/conversions/to_json.hpp" #include "detail/parsing/input_adapters.hpp" +#include "detail/parsing/lexer.hpp" /*! @brief namespace for Niels Lohmann @@ -68,1261 +69,9 @@ namespace nlohmann { namespace detail { -////////////////////// -// lexer and parser // -////////////////////// - -/*! -@brief lexical analysis - -This class organizes the lexical analysis during JSON deserialization. -*/ -template -class lexer -{ - using number_integer_t = typename BasicJsonType::number_integer_t; - using number_unsigned_t = typename BasicJsonType::number_unsigned_t; - using number_float_t = typename BasicJsonType::number_float_t; - - public: - /// token types for the parser - enum class token_type - { - uninitialized, ///< indicating the scanner is uninitialized - literal_true, ///< the `true` literal - literal_false, ///< the `false` literal - literal_null, ///< the `null` literal - value_string, ///< a string -- use get_string() for actual value - value_unsigned, ///< an unsigned integer -- use get_number_unsigned() for actual value - value_integer, ///< a signed integer -- use get_number_integer() for actual value - value_float, ///< an floating point number -- use get_number_float() for actual value - begin_array, ///< the character for array begin `[` - begin_object, ///< the character for object begin `{` - end_array, ///< the character for array end `]` - end_object, ///< the character for object end `}` - name_separator, ///< the name separator `:` - value_separator, ///< the value separator `,` - parse_error, ///< indicating a parse error - end_of_input, ///< indicating the end of the input buffer - literal_or_value ///< a literal or the begin of a value (only for diagnostics) - }; - - /// return name of values of type token_type (only used for errors) - static const char* token_type_name(const token_type t) noexcept - { - switch (t) - { - case token_type::uninitialized: - return ""; - case token_type::literal_true: - return "true literal"; - case token_type::literal_false: - return "false literal"; - case token_type::literal_null: - return "null literal"; - case token_type::value_string: - return "string literal"; - case lexer::token_type::value_unsigned: - case lexer::token_type::value_integer: - case lexer::token_type::value_float: - return "number literal"; - case token_type::begin_array: - return "'['"; - case token_type::begin_object: - return "'{'"; - case token_type::end_array: - return "']'"; - case token_type::end_object: - return "'}'"; - case token_type::name_separator: - return "':'"; - case token_type::value_separator: - return "','"; - case token_type::parse_error: - return ""; - case token_type::end_of_input: - return "end of input"; - case token_type::literal_or_value: - return "'[', '{', or a literal"; - default: // catch non-enum values - return "unknown token"; // LCOV_EXCL_LINE - } - } - - explicit lexer(detail::input_adapter_t adapter) - : ia(std::move(adapter)), decimal_point_char(get_decimal_point()) {} - - // delete because of pointer members - lexer(const lexer&) = delete; - lexer& operator=(lexer&) = delete; - - private: - ///////////////////// - // locales - ///////////////////// - - /// return the locale-dependent decimal point - static char get_decimal_point() noexcept - { - const auto loc = localeconv(); - assert(loc != nullptr); - return (loc->decimal_point == nullptr) ? '.' : *(loc->decimal_point); - } - - ///////////////////// - // scan functions - ///////////////////// - - /*! - @brief get codepoint from 4 hex characters following `\u` - - For input "\u c1 c2 c3 c4" the codepoint is: - (c1 * 0x1000) + (c2 * 0x0100) + (c3 * 0x0010) + c4 - = (c1 << 12) + (c2 << 8) + (c3 << 4) + (c4 << 0) - - Furthermore, the possible characters '0'..'9', 'A'..'F', and 'a'..'f' - must be converted to the integers 0x0..0x9, 0xA..0xF, 0xA..0xF, resp. The - conversion is done by subtracting the offset (0x30, 0x37, and 0x57) - between the ASCII value of the character and the desired integer value. - - @return codepoint (0x0000..0xFFFF) or -1 in case of an error (e.g. EOF or - non-hex character) - */ - int get_codepoint() - { - // this function only makes sense after reading `\u` - assert(current == 'u'); - int codepoint = 0; - - const auto factors = { 12, 8, 4, 0 }; - for (const auto factor : factors) - { - get(); - - if (current >= '0' and current <= '9') - { - codepoint += ((current - 0x30) << factor); - } - else if (current >= 'A' and current <= 'F') - { - codepoint += ((current - 0x37) << factor); - } - else if (current >= 'a' and current <= 'f') - { - codepoint += ((current - 0x57) << factor); - } - else - { - return -1; - } - } - - assert(0x0000 <= codepoint and codepoint <= 0xFFFF); - return codepoint; - } - - /*! - @brief check if the next byte(s) are inside a given range - - Adds the current byte and, for each passed range, reads a new byte and - checks if it is inside the range. If a violation was detected, set up an - error message and return false. Otherwise, return true. - - @param[in] ranges list of integers; interpreted as list of pairs of - inclusive lower and upper bound, respectively - - @pre The passed list @a ranges must have 2, 4, or 6 elements; that is, - 1, 2, or 3 pairs. This precondition is enforced by an assertion. - - @return true if and only if no range violation was detected - */ - bool next_byte_in_range(std::initializer_list ranges) - { - assert(ranges.size() == 2 or ranges.size() == 4 or ranges.size() == 6); - add(current); - - for (auto range = ranges.begin(); range != ranges.end(); ++range) - { - get(); - if (JSON_LIKELY(*range <= current and current <= *(++range))) - { - add(current); - } - else - { - error_message = "invalid string: ill-formed UTF-8 byte"; - return false; - } - } - - return true; - } - - /*! - @brief scan a string literal - - This function scans a string according to Sect. 7 of RFC 7159. While - scanning, bytes are escaped and copied into buffer yytext. Then the function - returns successfully, yytext is *not* null-terminated (as it may contain \0 - bytes), and yytext.size() is the number of bytes in the string. - - @return token_type::value_string if string could be successfully scanned, - token_type::parse_error otherwise - - @note In case of errors, variable error_message contains a textual - description. - */ - token_type scan_string() - { - // reset yytext (ignore opening quote) - reset(); - - // we entered the function by reading an open quote - assert(current == '\"'); - - while (true) - { - // get next character - switch (get()) - { - // end of file while parsing string - case std::char_traits::eof(): - { - error_message = "invalid string: missing closing quote"; - return token_type::parse_error; - } - - // closing quote - case '\"': - { - return token_type::value_string; - } - - // escapes - case '\\': - { - switch (get()) - { - // quotation mark - case '\"': - add('\"'); - break; - // reverse solidus - case '\\': - add('\\'); - break; - // solidus - case '/': - add('/'); - break; - // backspace - case 'b': - add('\b'); - break; - // form feed - case 'f': - add('\f'); - break; - // line feed - case 'n': - add('\n'); - break; - // carriage return - case 'r': - add('\r'); - break; - // tab - case 't': - add('\t'); - break; - - // unicode escapes - case 'u': - { - const int codepoint1 = get_codepoint(); - int codepoint = codepoint1; // start with codepoint1 - - if (JSON_UNLIKELY(codepoint1 == -1)) - { - error_message = "invalid string: '\\u' must be followed by 4 hex digits"; - return token_type::parse_error; - } - - // check if code point is a high surrogate - if (0xD800 <= codepoint1 and codepoint1 <= 0xDBFF) - { - // expect next \uxxxx entry - if (JSON_LIKELY(get() == '\\' and get() == 'u')) - { - const int codepoint2 = get_codepoint(); - - if (JSON_UNLIKELY(codepoint2 == -1)) - { - error_message = "invalid string: '\\u' must be followed by 4 hex digits"; - return token_type::parse_error; - } - - // check if codepoint2 is a low surrogate - if (JSON_LIKELY(0xDC00 <= codepoint2 and codepoint2 <= 0xDFFF)) - { - // overwrite codepoint - codepoint = - // high surrogate occupies the most significant 22 bits - (codepoint1 << 10) - // low surrogate occupies the least significant 15 bits - + codepoint2 - // there is still the 0xD800, 0xDC00 and 0x10000 noise - // in the result so we have to subtract with: - // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00 - - 0x35FDC00; - } - else - { - error_message = "invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF"; - return token_type::parse_error; - } - } - else - { - error_message = "invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF"; - return token_type::parse_error; - } - } - else - { - if (JSON_UNLIKELY(0xDC00 <= codepoint1 and codepoint1 <= 0xDFFF)) - { - error_message = "invalid string: surrogate U+DC00..U+DFFF must follow U+D800..U+DBFF"; - return token_type::parse_error; - } - } - - // result of the above calculation yields a proper codepoint - assert(0x00 <= codepoint and codepoint <= 0x10FFFF); - - // translate codepoint into bytes - if (codepoint < 0x80) - { - // 1-byte characters: 0xxxxxxx (ASCII) - add(codepoint); - } - else if (codepoint <= 0x7FF) - { - // 2-byte characters: 110xxxxx 10xxxxxx - add(0xC0 | (codepoint >> 6)); - add(0x80 | (codepoint & 0x3F)); - } - else if (codepoint <= 0xFFFF) - { - // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx - add(0xE0 | (codepoint >> 12)); - add(0x80 | ((codepoint >> 6) & 0x3F)); - add(0x80 | (codepoint & 0x3F)); - } - else - { - // 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - add(0xF0 | (codepoint >> 18)); - add(0x80 | ((codepoint >> 12) & 0x3F)); - add(0x80 | ((codepoint >> 6) & 0x3F)); - add(0x80 | (codepoint & 0x3F)); - } - - break; - } - - // other characters after escape - default: - error_message = "invalid string: forbidden character after backslash"; - return token_type::parse_error; - } - - break; - } - - // invalid control characters - case 0x00: - case 0x01: - case 0x02: - case 0x03: - case 0x04: - case 0x05: - case 0x06: - case 0x07: - case 0x08: - case 0x09: - case 0x0A: - case 0x0B: - case 0x0C: - case 0x0D: - case 0x0E: - case 0x0F: - case 0x10: - case 0x11: - case 0x12: - case 0x13: - case 0x14: - case 0x15: - case 0x16: - case 0x17: - case 0x18: - case 0x19: - case 0x1A: - case 0x1B: - case 0x1C: - case 0x1D: - case 0x1E: - case 0x1F: - { - error_message = "invalid string: control character must be escaped"; - return token_type::parse_error; - } - - // U+0020..U+007F (except U+0022 (quote) and U+005C (backspace)) - case 0x20: - case 0x21: - case 0x23: - case 0x24: - case 0x25: - case 0x26: - case 0x27: - case 0x28: - case 0x29: - case 0x2A: - case 0x2B: - case 0x2C: - case 0x2D: - case 0x2E: - case 0x2F: - case 0x30: - case 0x31: - case 0x32: - case 0x33: - case 0x34: - case 0x35: - case 0x36: - case 0x37: - case 0x38: - case 0x39: - case 0x3A: - case 0x3B: - case 0x3C: - case 0x3D: - case 0x3E: - case 0x3F: - case 0x40: - case 0x41: - case 0x42: - case 0x43: - case 0x44: - case 0x45: - case 0x46: - case 0x47: - case 0x48: - case 0x49: - case 0x4A: - case 0x4B: - case 0x4C: - case 0x4D: - case 0x4E: - case 0x4F: - case 0x50: - case 0x51: - case 0x52: - case 0x53: - case 0x54: - case 0x55: - case 0x56: - case 0x57: - case 0x58: - case 0x59: - case 0x5A: - case 0x5B: - case 0x5D: - case 0x5E: - case 0x5F: - case 0x60: - case 0x61: - case 0x62: - case 0x63: - case 0x64: - case 0x65: - case 0x66: - case 0x67: - case 0x68: - case 0x69: - case 0x6A: - case 0x6B: - case 0x6C: - case 0x6D: - case 0x6E: - case 0x6F: - case 0x70: - case 0x71: - case 0x72: - case 0x73: - case 0x74: - case 0x75: - case 0x76: - case 0x77: - case 0x78: - case 0x79: - case 0x7A: - case 0x7B: - case 0x7C: - case 0x7D: - case 0x7E: - case 0x7F: - { - add(current); - break; - } - - // U+0080..U+07FF: bytes C2..DF 80..BF - case 0xC2: - case 0xC3: - case 0xC4: - case 0xC5: - case 0xC6: - case 0xC7: - case 0xC8: - case 0xC9: - case 0xCA: - case 0xCB: - case 0xCC: - case 0xCD: - case 0xCE: - case 0xCF: - case 0xD0: - case 0xD1: - case 0xD2: - case 0xD3: - case 0xD4: - case 0xD5: - case 0xD6: - case 0xD7: - case 0xD8: - case 0xD9: - case 0xDA: - case 0xDB: - case 0xDC: - case 0xDD: - case 0xDE: - case 0xDF: - { - if (JSON_UNLIKELY(not next_byte_in_range({0x80, 0xBF}))) - { - return token_type::parse_error; - } - break; - } - - // U+0800..U+0FFF: bytes E0 A0..BF 80..BF - case 0xE0: - { - if (JSON_UNLIKELY(not (next_byte_in_range({0xA0, 0xBF, 0x80, 0xBF})))) - { - return token_type::parse_error; - } - break; - } - - // U+1000..U+CFFF: bytes E1..EC 80..BF 80..BF - // U+E000..U+FFFF: bytes EE..EF 80..BF 80..BF - case 0xE1: - case 0xE2: - case 0xE3: - case 0xE4: - case 0xE5: - case 0xE6: - case 0xE7: - case 0xE8: - case 0xE9: - case 0xEA: - case 0xEB: - case 0xEC: - case 0xEE: - case 0xEF: - { - if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0xBF, 0x80, 0xBF})))) - { - return token_type::parse_error; - } - break; - } - - // U+D000..U+D7FF: bytes ED 80..9F 80..BF - case 0xED: - { - if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0x9F, 0x80, 0xBF})))) - { - return token_type::parse_error; - } - break; - } - - // U+10000..U+3FFFF F0 90..BF 80..BF 80..BF - case 0xF0: - { - if (JSON_UNLIKELY(not (next_byte_in_range({0x90, 0xBF, 0x80, 0xBF, 0x80, 0xBF})))) - { - return token_type::parse_error; - } - break; - } - - // U+40000..U+FFFFF F1..F3 80..BF 80..BF 80..BF - case 0xF1: - case 0xF2: - case 0xF3: - { - if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0xBF, 0x80, 0xBF, 0x80, 0xBF})))) - { - return token_type::parse_error; - } - break; - } - - // U+100000..U+10FFFF F4 80..8F 80..BF 80..BF - case 0xF4: - { - if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0x8F, 0x80, 0xBF, 0x80, 0xBF})))) - { - return token_type::parse_error; - } - break; - } - - // remaining bytes (80..C1 and F5..FF) are ill-formed - default: - { - error_message = "invalid string: ill-formed UTF-8 byte"; - return token_type::parse_error; - } - } - } - } - - static void strtof(float& f, const char* str, char** endptr) noexcept - { - f = std::strtof(str, endptr); - } - - static void strtof(double& f, const char* str, char** endptr) noexcept - { - f = std::strtod(str, endptr); - } - - static void strtof(long double& f, const char* str, char** endptr) noexcept - { - f = std::strtold(str, endptr); - } - - /*! - @brief scan a number literal - - This function scans a string according to Sect. 6 of RFC 7159. - - The function is realized with a deterministic finite state machine derived - from the grammar described in RFC 7159. Starting in state "init", the - input is read and used to determined the next state. Only state "done" - accepts the number. State "error" is a trap state to model errors. In the - table below, "anything" means any character but the ones listed before. - - state | 0 | 1-9 | e E | + | - | . | anything - ---------|----------|----------|----------|---------|---------|----------|----------- - init | zero | any1 | [error] | [error] | minus | [error] | [error] - minus | zero | any1 | [error] | [error] | [error] | [error] | [error] - zero | done | done | exponent | done | done | decimal1 | done - any1 | any1 | any1 | exponent | done | done | decimal1 | done - decimal1 | decimal2 | [error] | [error] | [error] | [error] | [error] | [error] - decimal2 | decimal2 | decimal2 | exponent | done | done | done | done - exponent | any2 | any2 | [error] | sign | sign | [error] | [error] - sign | any2 | any2 | [error] | [error] | [error] | [error] | [error] - any2 | any2 | any2 | done | done | done | done | done - - The state machine is realized with one label per state (prefixed with - "scan_number_") and `goto` statements between them. The state machine - contains cycles, but any cycle can be left when EOF is read. Therefore, - the function is guaranteed to terminate. - - During scanning, the read bytes are stored in yytext. This string is - then converted to a signed integer, an unsigned integer, or a - floating-point number. - - @return token_type::value_unsigned, token_type::value_integer, or - token_type::value_float if number could be successfully scanned, - token_type::parse_error otherwise - - @note The scanner is independent of the current locale. Internally, the - locale's decimal point is used instead of `.` to work with the - locale-dependent converters. - */ - token_type scan_number() - { - // reset yytext to store the number's bytes - reset(); - - // the type of the parsed number; initially set to unsigned; will be - // changed if minus sign, decimal point or exponent is read - token_type number_type = token_type::value_unsigned; - - // state (init): we just found out we need to scan a number - switch (current) - { - case '-': - { - add(current); - goto scan_number_minus; - } - - case '0': - { - add(current); - goto scan_number_zero; - } - - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_any1; - } - - default: - { - // all other characters are rejected outside scan_number() - assert(false); // LCOV_EXCL_LINE - } - } - -scan_number_minus: - // state: we just parsed a leading minus sign - number_type = token_type::value_integer; - switch (get()) - { - case '0': - { - add(current); - goto scan_number_zero; - } - - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_any1; - } - - default: - { - error_message = "invalid number; expected digit after '-'"; - return token_type::parse_error; - } - } - -scan_number_zero: - // state: we just parse a zero (maybe with a leading minus sign) - switch (get()) - { - case '.': - { - add(decimal_point_char); - goto scan_number_decimal1; - } - - case 'e': - case 'E': - { - add(current); - goto scan_number_exponent; - } - - default: - goto scan_number_done; - } - -scan_number_any1: - // state: we just parsed a number 0-9 (maybe with a leading minus sign) - switch (get()) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_any1; - } - - case '.': - { - add(decimal_point_char); - goto scan_number_decimal1; - } - - case 'e': - case 'E': - { - add(current); - goto scan_number_exponent; - } - - default: - goto scan_number_done; - } - -scan_number_decimal1: - // state: we just parsed a decimal point - number_type = token_type::value_float; - switch (get()) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_decimal2; - } - - default: - { - error_message = "invalid number; expected digit after '.'"; - return token_type::parse_error; - } - } - -scan_number_decimal2: - // we just parsed at least one number after a decimal point - switch (get()) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_decimal2; - } - - case 'e': - case 'E': - { - add(current); - goto scan_number_exponent; - } - - default: - goto scan_number_done; - } - -scan_number_exponent: - // we just parsed an exponent - number_type = token_type::value_float; - switch (get()) - { - case '+': - case '-': - { - add(current); - goto scan_number_sign; - } - - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_any2; - } - - default: - { - error_message = - "invalid number; expected '+', '-', or digit after exponent"; - return token_type::parse_error; - } - } - -scan_number_sign: - // we just parsed an exponent sign - switch (get()) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_any2; - } - - default: - { - error_message = "invalid number; expected digit after exponent sign"; - return token_type::parse_error; - } - } - -scan_number_any2: - // we just parsed a number after the exponent or exponent sign - switch (get()) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_any2; - } - - default: - goto scan_number_done; - } - -scan_number_done: - // unget the character after the number (we only read it to know that - // we are done scanning a number) - unget(); - - char* endptr = nullptr; - errno = 0; - - // try to parse integers first and fall back to floats - if (number_type == token_type::value_unsigned) - { - const auto x = std::strtoull(yytext.data(), &endptr, 10); - - // we checked the number format before - assert(endptr == yytext.data() + yytext.size()); - - if (errno == 0) - { - value_unsigned = static_cast(x); - if (value_unsigned == x) - { - return token_type::value_unsigned; - } - } - } - else if (number_type == token_type::value_integer) - { - const auto x = std::strtoll(yytext.data(), &endptr, 10); - - // we checked the number format before - assert(endptr == yytext.data() + yytext.size()); - - if (errno == 0) - { - value_integer = static_cast(x); - if (value_integer == x) - { - return token_type::value_integer; - } - } - } - - // this code is reached if we parse a floating-point number or if an - // integer conversion above failed - strtof(value_float, yytext.data(), &endptr); - - // we checked the number format before - assert(endptr == yytext.data() + yytext.size()); - - return token_type::value_float; - } - - /*! - @param[in] literal_text the literal text to expect - @param[in] length the length of the passed literal text - @param[in] return_type the token type to return on success - */ - token_type scan_literal(const char* literal_text, const std::size_t length, - token_type return_type) - { - assert(current == literal_text[0]); - for (std::size_t i = 1; i < length; ++i) - { - if (JSON_UNLIKELY(get() != literal_text[i])) - { - error_message = "invalid literal"; - return token_type::parse_error; - } - } - return return_type; - } - - ///////////////////// - // input management - ///////////////////// - - /// reset yytext; current character is beginning of token - void reset() noexcept - { - yytext.clear(); - token_string.clear(); - token_string.push_back(std::char_traits::to_char_type(current)); - } - - /* - @brief get next character from the input - - This function provides the interface to the used input adapter. It does - not throw in case the input reached EOF, but returns a - `std::char_traits::eof()` in that case. Stores the scanned characters - for use in error messages. - - @return character read from the input - */ - std::char_traits::int_type get() - { - ++chars_read; - current = ia->get_character(); - if (JSON_LIKELY(current != std::char_traits::eof())) - { - token_string.push_back(std::char_traits::to_char_type(current)); - } - return current; - } - - /// unget current character (return it again on next get) - void unget() - { - --chars_read; - if (JSON_LIKELY(current != std::char_traits::eof())) - { - ia->unget_character(); - assert(token_string.size() != 0); - token_string.pop_back(); - } - } - - /// add a character to yytext - void add(int c) - { - yytext.push_back(std::char_traits::to_char_type(c)); - } - - public: - ///////////////////// - // value getters - ///////////////////// - - /// return integer value - constexpr number_integer_t get_number_integer() const noexcept - { - return value_integer; - } - - /// return unsigned integer value - constexpr number_unsigned_t get_number_unsigned() const noexcept - { - return value_unsigned; - } - - /// return floating-point value - constexpr number_float_t get_number_float() const noexcept - { - return value_float; - } - - /// return current string value (implicitly resets the token; useful only once) - std::string move_string() - { - return std::move(yytext); - } - - ///////////////////// - // diagnostics - ///////////////////// - - /// return position of last read token - constexpr std::size_t get_position() const noexcept - { - return chars_read; - } - - /// return the last read token (for errors only). Will never contain EOF - /// (an arbitrary value that is not a valid char value, often -1), because - /// 255 may legitimately occur. May contain NUL, which should be escaped. - std::string get_token_string() const - { - // escape control characters - std::string result; - for (const auto c : token_string) - { - if ('\x00' <= c and c <= '\x1F') - { - // escape control characters - std::stringstream ss; - ss << "(c) << ">"; - result += ss.str(); - } - else - { - // add character as is - result.push_back(c); - } - } - - return result; - } - - /// return syntax error message - constexpr const char* get_error_message() const noexcept - { - return error_message; - } - - ///////////////////// - // actual scanner - ///////////////////// - - token_type scan() - { - // read next character and ignore whitespace - do - { - get(); - } - while (current == ' ' or current == '\t' or current == '\n' or current == '\r'); - - switch (current) - { - // structural characters - case '[': - return token_type::begin_array; - case ']': - return token_type::end_array; - case '{': - return token_type::begin_object; - case '}': - return token_type::end_object; - case ':': - return token_type::name_separator; - case ',': - return token_type::value_separator; - - // literals - case 't': - return scan_literal("true", 4, token_type::literal_true); - case 'f': - return scan_literal("false", 5, token_type::literal_false); - case 'n': - return scan_literal("null", 4, token_type::literal_null); - - // string - case '\"': - return scan_string(); - - // number - case '-': - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - return scan_number(); - - // end of input (the null byte is needed when parsing from - // string literals) - case '\0': - case std::char_traits::eof(): - return token_type::end_of_input; - - // error - default: - error_message = "invalid literal"; - return token_type::parse_error; - } - } - - private: - /// input adapter - detail::input_adapter_t ia = nullptr; - - /// the current character - std::char_traits::int_type current = std::char_traits::eof(); - - /// the number of characters read - std::size_t chars_read = 0; - - /// raw input token string (for error messages) - std::vector token_string {}; - - /// buffer for variable-length tokens (numbers, strings) - std::string yytext {}; - - /// a description of occurred lexer errors - const char* error_message = ""; - - // number values - number_integer_t value_integer = 0; - number_unsigned_t value_unsigned = 0; - number_float_t value_float = 0; - - /// the decimal point - const char decimal_point_char = '.'; -}; +//////////// +// parser // +//////////// /*! @brief syntax analysis From 9ea25685a8020555510a7bc862655839d489dcd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20DELRIEU?= Date: Mon, 14 Aug 2017 17:02:40 +0200 Subject: [PATCH 40/59] add detail/parsing/parser.hpp --- Makefile | 3 +- src/detail/parsing/parser.hpp | 589 ++++++++++++++++++++++++++++++++++ src/json.hpp | 570 +------------------------------- 3 files changed, 592 insertions(+), 570 deletions(-) create mode 100644 src/detail/parsing/parser.hpp diff --git a/Makefile b/Makefile index aacaa00f..69421ace 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,8 @@ SRCS = ${SRCDIR}/json.hpp \ ${SRCDIR}/detail/conversions/from_json.hpp \ ${SRCDIR}/detail/conversions/to_json.hpp \ ${SRCDIR}/detail/parsing/input_adapters.hpp \ - ${SRCDIR}/detail/parsing/lexer.hpp + ${SRCDIR}/detail/parsing/lexer.hpp \ + ${SRCDIR}/detail/parsing/parser.hpp diff --git a/src/detail/parsing/parser.hpp b/src/detail/parsing/parser.hpp new file mode 100644 index 00000000..c82c2f6d --- /dev/null +++ b/src/detail/parsing/parser.hpp @@ -0,0 +1,589 @@ +#ifndef NLOHMANN_JSON_DETAIL_PARSING_PARSER_HPP +#define NLOHMANN_JSON_DETAIL_PARSING_PARSER_HPP + +#include +#include +#include +#include + +#include "detail/exceptions.hpp" +#include "detail/macro_scope.hpp" +#include "detail/parsing/input_adapters.hpp" +#include "detail/parsing/lexer.hpp" + +namespace nlohmann +{ +namespace detail +{ +//////////// +// parser // +//////////// + +/*! +@brief syntax analysis + +This class implements a recursive decent parser. +*/ +template +class parser +{ + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + using lexer_t = lexer; + using token_type = typename lexer_t::token_type; + + public: + enum class parse_event_t : uint8_t + { + /// the parser read `{` and started to process a JSON object + object_start, + /// the parser read `}` and finished processing a JSON object + object_end, + /// the parser read `[` and started to process a JSON array + array_start, + /// the parser read `]` and finished processing a JSON array + array_end, + /// the parser read a key of a value in an object + key, + /// the parser finished reading a JSON value + value + }; + + using parser_callback_t = + std::function; + + /// a parser reading from an input adapter + explicit parser(detail::input_adapter_t adapter, + const parser_callback_t cb = nullptr, + const bool allow_exceptions_ = true) + : callback(cb), m_lexer(adapter), allow_exceptions(allow_exceptions_) + {} + + /*! + @brief public parser interface + + @param[in] strict whether to expect the last token to be EOF + @param[in,out] result parsed JSON value + + @throw parse_error.101 in case of an unexpected token + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + */ + void parse(const bool strict, BasicJsonType& result) + { + // read first token + get_token(); + + parse_internal(true, result); + result.assert_invariant(); + + // in strict mode, input must be completely read + if (strict) + { + get_token(); + expect(token_type::end_of_input); + } + + // in case of an error, return discarded value + if (errored) + { + result = value_t::discarded; + return; + } + + // set top-level value to null if it was discarded by the callback + // function + if (result.is_discarded()) + { + result = nullptr; + } + } + + /*! + @brief public accept interface + + @param[in] strict whether to expect the last token to be EOF + @return whether the input is a proper JSON text + */ + bool accept(const bool strict = true) + { + // read first token + get_token(); + + if (not accept_internal()) + { + return false; + } + + // strict => last token must be EOF + return not strict or (get_token() == token_type::end_of_input); + } + + private: + /*! + @brief the actual parser + @throw parse_error.101 in case of an unexpected token + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + */ + void parse_internal(bool keep, BasicJsonType& result) + { + // never parse after a parse error was detected + assert(not errored); + + // start with a discarded value + if (not result.is_discarded()) + { + result.m_value.destroy(result.m_type); + result.m_type = value_t::discarded; + } + + switch (last_token) + { + case token_type::begin_object: + { + if (keep) + { + if (callback) + { + keep = callback(depth++, parse_event_t::object_start, result); + } + + if (not callback or keep) + { + // explicitly set result to object to cope with {} + result.m_type = value_t::object; + result.m_value = value_t::object; + } + } + + // read next token + get_token(); + + // closing } -> we are done + if (last_token == token_type::end_object) + { + if (keep and callback and not callback(--depth, parse_event_t::object_end, result)) + { + result.m_value.destroy(result.m_type); + result.m_type = value_t::discarded; + } + break; + } + + // parse values + std::string key; + BasicJsonType value; + while (true) + { + // store key + if (not expect(token_type::value_string)) + { + return; + } + key = m_lexer.move_string(); + + bool keep_tag = false; + if (keep) + { + if (callback) + { + BasicJsonType k(key); + keep_tag = callback(depth, parse_event_t::key, k); + } + else + { + keep_tag = true; + } + } + + // parse separator (:) + get_token(); + if (not expect(token_type::name_separator)) + { + return; + } + + // parse and add value + get_token(); + value.m_value.destroy(value.m_type); + value.m_type = value_t::discarded; + parse_internal(keep, value); + + if (JSON_UNLIKELY(errored)) + { + return; + } + + if (keep and keep_tag and not value.is_discarded()) + { + result.m_value.object->emplace(std::move(key), std::move(value)); + } + + // comma -> next value + get_token(); + if (last_token == token_type::value_separator) + { + get_token(); + continue; + } + + // closing } + if (not expect(token_type::end_object)) + { + return; + } + break; + } + + if (keep and callback and not callback(--depth, parse_event_t::object_end, result)) + { + result.m_value.destroy(result.m_type); + result.m_type = value_t::discarded; + } + break; + } + + case token_type::begin_array: + { + if (keep) + { + if (callback) + { + keep = callback(depth++, parse_event_t::array_start, result); + } + + if (not callback or keep) + { + // explicitly set result to array to cope with [] + result.m_type = value_t::array; + result.m_value = value_t::array; + } + } + + // read next token + get_token(); + + // closing ] -> we are done + if (last_token == token_type::end_array) + { + if (callback and not callback(--depth, parse_event_t::array_end, result)) + { + result.m_value.destroy(result.m_type); + result.m_type = value_t::discarded; + } + break; + } + + // parse values + BasicJsonType value; + while (true) + { + // parse value + value.m_value.destroy(value.m_type); + value.m_type = value_t::discarded; + parse_internal(keep, value); + + if (JSON_UNLIKELY(errored)) + { + return; + } + + if (keep and not value.is_discarded()) + { + result.m_value.array->push_back(std::move(value)); + } + + // comma -> next value + get_token(); + if (last_token == token_type::value_separator) + { + get_token(); + continue; + } + + // closing ] + if (not expect(token_type::end_array)) + { + return; + } + break; + } + + if (keep and callback and not callback(--depth, parse_event_t::array_end, result)) + { + result.m_value.destroy(result.m_type); + result.m_type = value_t::discarded; + } + break; + } + + case token_type::literal_null: + { + result.m_type = value_t::null; + break; + } + + case token_type::value_string: + { + result.m_type = value_t::string; + result.m_value = m_lexer.move_string(); + break; + } + + case token_type::literal_true: + { + result.m_type = value_t::boolean; + result.m_value = true; + break; + } + + case token_type::literal_false: + { + result.m_type = value_t::boolean; + result.m_value = false; + break; + } + + case token_type::value_unsigned: + { + result.m_type = value_t::number_unsigned; + result.m_value = m_lexer.get_number_unsigned(); + break; + } + + case token_type::value_integer: + { + result.m_type = value_t::number_integer; + result.m_value = m_lexer.get_number_integer(); + break; + } + + case token_type::value_float: + { + result.m_type = value_t::number_float; + result.m_value = m_lexer.get_number_float(); + + // throw in case of infinity or NAN + if (JSON_UNLIKELY(not std::isfinite(result.m_value.number_float))) + { + if (allow_exceptions) + { + JSON_THROW(out_of_range::create(406, "number overflow parsing '" + + m_lexer.get_token_string() + "'")); + } + expect(token_type::uninitialized); + } + break; + } + + case token_type::parse_error: + { + // using "uninitialized" to avoid "expected" message + if (not expect(token_type::uninitialized)) + { + return; + } + break; // LCOV_EXCL_LINE + } + + default: + { + // the last token was unexpected; we expected a value + if (not expect(token_type::literal_or_value)) + { + return; + } + break; // LCOV_EXCL_LINE + } + } + + if (keep and callback and not callback(depth, parse_event_t::value, result)) + { + result.m_type = value_t::discarded; + } + } + + /*! + @brief the actual acceptor + + @invariant 1. The last token is not yet processed. Therefore, the caller + of this function must make sure a token has been read. + 2. When this function returns, the last token is processed. + That is, the last read character was already considered. + + This invariant makes sure that no token needs to be "unput". + */ + bool accept_internal() + { + switch (last_token) + { + case token_type::begin_object: + { + // read next token + get_token(); + + // closing } -> we are done + if (last_token == token_type::end_object) + { + return true; + } + + // parse values + while (true) + { + // parse key + if (last_token != token_type::value_string) + { + return false; + } + + // parse separator (:) + get_token(); + if (last_token != token_type::name_separator) + { + return false; + } + + // parse value + get_token(); + if (not accept_internal()) + { + return false; + } + + // comma -> next value + get_token(); + if (last_token == token_type::value_separator) + { + get_token(); + continue; + } + + // closing } + return (last_token == token_type::end_object); + } + } + + case token_type::begin_array: + { + // read next token + get_token(); + + // closing ] -> we are done + if (last_token == token_type::end_array) + { + return true; + } + + // parse values + while (true) + { + // parse value + if (not accept_internal()) + { + return false; + } + + // comma -> next value + get_token(); + if (last_token == token_type::value_separator) + { + get_token(); + continue; + } + + // closing ] + return (last_token == token_type::end_array); + } + } + + case token_type::value_float: + { + // reject infinity or NAN + return std::isfinite(m_lexer.get_number_float()); + } + + case token_type::literal_false: + case token_type::literal_null: + case token_type::literal_true: + case token_type::value_integer: + case token_type::value_string: + case token_type::value_unsigned: + return true; + + default: // the last token was unexpected + return false; + } + } + + /// get next token from lexer + token_type get_token() + { + return (last_token = m_lexer.scan()); + } + + /*! + @throw parse_error.101 if expected token did not occur + */ + bool expect(token_type t) + { + if (JSON_UNLIKELY(t != last_token)) + { + errored = true; + expected = t; + if (allow_exceptions) + { + throw_exception(); + } + else + { + return false; + } + } + + return true; + } + + [[noreturn]] void throw_exception() const + { + std::string error_msg = "syntax error - "; + if (last_token == token_type::parse_error) + { + error_msg += std::string(m_lexer.get_error_message()) + "; last read: '" + + m_lexer.get_token_string() + "'"; + } + else + { + error_msg += "unexpected " + std::string(lexer_t::token_type_name(last_token)); + } + + if (expected != token_type::uninitialized) + { + error_msg += "; expected " + std::string(lexer_t::token_type_name(expected)); + } + + JSON_THROW(parse_error::create(101, m_lexer.get_position(), error_msg)); + } + + private: + /// current level of recursion + int depth = 0; + /// callback function + const parser_callback_t callback = nullptr; + /// the type of the last read token + token_type last_token = token_type::uninitialized; + /// the lexer + lexer_t m_lexer; + /// whether a syntax error occurred + bool errored = false; + /// possible reason for the syntax error + token_type expected = token_type::uninitialized; + /// whether to throw exceptions in case of errors + const bool allow_exceptions = true; +}; +} +} + +#endif diff --git a/src/json.hpp b/src/json.hpp index d93ba316..326589ef 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -59,6 +59,7 @@ SOFTWARE. #include "detail/conversions/to_json.hpp" #include "detail/parsing/input_adapters.hpp" #include "detail/parsing/lexer.hpp" +#include "detail/parsing/parser.hpp" /*! @brief namespace for Niels Lohmann @@ -69,575 +70,6 @@ namespace nlohmann { namespace detail { -//////////// -// parser // -//////////// - -/*! -@brief syntax analysis - -This class implements a recursive decent parser. -*/ -template -class parser -{ - using number_integer_t = typename BasicJsonType::number_integer_t; - using number_unsigned_t = typename BasicJsonType::number_unsigned_t; - using number_float_t = typename BasicJsonType::number_float_t; - using lexer_t = lexer; - using token_type = typename lexer_t::token_type; - - public: - enum class parse_event_t : uint8_t - { - /// the parser read `{` and started to process a JSON object - object_start, - /// the parser read `}` and finished processing a JSON object - object_end, - /// the parser read `[` and started to process a JSON array - array_start, - /// the parser read `]` and finished processing a JSON array - array_end, - /// the parser read a key of a value in an object - key, - /// the parser finished reading a JSON value - value - }; - - using parser_callback_t = - std::function; - - /// a parser reading from an input adapter - explicit parser(detail::input_adapter_t adapter, - const parser_callback_t cb = nullptr, - const bool allow_exceptions_ = true) - : callback(cb), m_lexer(adapter), allow_exceptions(allow_exceptions_) - {} - - /*! - @brief public parser interface - - @param[in] strict whether to expect the last token to be EOF - @param[in,out] result parsed JSON value - - @throw parse_error.101 in case of an unexpected token - @throw parse_error.102 if to_unicode fails or surrogate error - @throw parse_error.103 if to_unicode fails - */ - void parse(const bool strict, BasicJsonType& result) - { - // read first token - get_token(); - - parse_internal(true, result); - result.assert_invariant(); - - // in strict mode, input must be completely read - if (strict) - { - get_token(); - expect(token_type::end_of_input); - } - - // in case of an error, return discarded value - if (errored) - { - result = value_t::discarded; - return; - } - - // set top-level value to null if it was discarded by the callback - // function - if (result.is_discarded()) - { - result = nullptr; - } - } - - /*! - @brief public accept interface - - @param[in] strict whether to expect the last token to be EOF - @return whether the input is a proper JSON text - */ - bool accept(const bool strict = true) - { - // read first token - get_token(); - - if (not accept_internal()) - { - return false; - } - - // strict => last token must be EOF - return not strict or (get_token() == token_type::end_of_input); - } - - private: - /*! - @brief the actual parser - @throw parse_error.101 in case of an unexpected token - @throw parse_error.102 if to_unicode fails or surrogate error - @throw parse_error.103 if to_unicode fails - */ - void parse_internal(bool keep, BasicJsonType& result) - { - // never parse after a parse error was detected - assert(not errored); - - // start with a discarded value - if (not result.is_discarded()) - { - result.m_value.destroy(result.m_type); - result.m_type = value_t::discarded; - } - - switch (last_token) - { - case token_type::begin_object: - { - if (keep) - { - if (callback) - { - keep = callback(depth++, parse_event_t::object_start, result); - } - - if (not callback or keep) - { - // explicitly set result to object to cope with {} - result.m_type = value_t::object; - result.m_value = value_t::object; - } - } - - // read next token - get_token(); - - // closing } -> we are done - if (last_token == token_type::end_object) - { - if (keep and callback and not callback(--depth, parse_event_t::object_end, result)) - { - result.m_value.destroy(result.m_type); - result.m_type = value_t::discarded; - } - break; - } - - // parse values - std::string key; - BasicJsonType value; - while (true) - { - // store key - if (not expect(token_type::value_string)) - { - return; - } - key = m_lexer.move_string(); - - bool keep_tag = false; - if (keep) - { - if (callback) - { - BasicJsonType k(key); - keep_tag = callback(depth, parse_event_t::key, k); - } - else - { - keep_tag = true; - } - } - - // parse separator (:) - get_token(); - if (not expect(token_type::name_separator)) - { - return; - } - - // parse and add value - get_token(); - value.m_value.destroy(value.m_type); - value.m_type = value_t::discarded; - parse_internal(keep, value); - - if (JSON_UNLIKELY(errored)) - { - return; - } - - if (keep and keep_tag and not value.is_discarded()) - { - result.m_value.object->emplace(std::move(key), std::move(value)); - } - - // comma -> next value - get_token(); - if (last_token == token_type::value_separator) - { - get_token(); - continue; - } - - // closing } - if (not expect(token_type::end_object)) - { - return; - } - break; - } - - if (keep and callback and not callback(--depth, parse_event_t::object_end, result)) - { - result.m_value.destroy(result.m_type); - result.m_type = value_t::discarded; - } - break; - } - - case token_type::begin_array: - { - if (keep) - { - if (callback) - { - keep = callback(depth++, parse_event_t::array_start, result); - } - - if (not callback or keep) - { - // explicitly set result to array to cope with [] - result.m_type = value_t::array; - result.m_value = value_t::array; - } - } - - // read next token - get_token(); - - // closing ] -> we are done - if (last_token == token_type::end_array) - { - if (callback and not callback(--depth, parse_event_t::array_end, result)) - { - result.m_value.destroy(result.m_type); - result.m_type = value_t::discarded; - } - break; - } - - // parse values - BasicJsonType value; - while (true) - { - // parse value - value.m_value.destroy(value.m_type); - value.m_type = value_t::discarded; - parse_internal(keep, value); - - if (JSON_UNLIKELY(errored)) - { - return; - } - - if (keep and not value.is_discarded()) - { - result.m_value.array->push_back(std::move(value)); - } - - // comma -> next value - get_token(); - if (last_token == token_type::value_separator) - { - get_token(); - continue; - } - - // closing ] - if (not expect(token_type::end_array)) - { - return; - } - break; - } - - if (keep and callback and not callback(--depth, parse_event_t::array_end, result)) - { - result.m_value.destroy(result.m_type); - result.m_type = value_t::discarded; - } - break; - } - - case token_type::literal_null: - { - result.m_type = value_t::null; - break; - } - - case token_type::value_string: - { - result.m_type = value_t::string; - result.m_value = m_lexer.move_string(); - break; - } - - case token_type::literal_true: - { - result.m_type = value_t::boolean; - result.m_value = true; - break; - } - - case token_type::literal_false: - { - result.m_type = value_t::boolean; - result.m_value = false; - break; - } - - case token_type::value_unsigned: - { - result.m_type = value_t::number_unsigned; - result.m_value = m_lexer.get_number_unsigned(); - break; - } - - case token_type::value_integer: - { - result.m_type = value_t::number_integer; - result.m_value = m_lexer.get_number_integer(); - break; - } - - case token_type::value_float: - { - result.m_type = value_t::number_float; - result.m_value = m_lexer.get_number_float(); - - // throw in case of infinity or NAN - if (JSON_UNLIKELY(not std::isfinite(result.m_value.number_float))) - { - if (allow_exceptions) - { - JSON_THROW(out_of_range::create(406, "number overflow parsing '" + - m_lexer.get_token_string() + "'")); - } - expect(token_type::uninitialized); - } - break; - } - - case token_type::parse_error: - { - // using "uninitialized" to avoid "expected" message - if (not expect(token_type::uninitialized)) - { - return; - } - break; // LCOV_EXCL_LINE - } - - default: - { - // the last token was unexpected; we expected a value - if (not expect(token_type::literal_or_value)) - { - return; - } - break; // LCOV_EXCL_LINE - } - } - - if (keep and callback and not callback(depth, parse_event_t::value, result)) - { - result.m_type = value_t::discarded; - } - } - - /*! - @brief the actual acceptor - - @invariant 1. The last token is not yet processed. Therefore, the caller - of this function must make sure a token has been read. - 2. When this function returns, the last token is processed. - That is, the last read character was already considered. - - This invariant makes sure that no token needs to be "unput". - */ - bool accept_internal() - { - switch (last_token) - { - case token_type::begin_object: - { - // read next token - get_token(); - - // closing } -> we are done - if (last_token == token_type::end_object) - { - return true; - } - - // parse values - while (true) - { - // parse key - if (last_token != token_type::value_string) - { - return false; - } - - // parse separator (:) - get_token(); - if (last_token != token_type::name_separator) - { - return false; - } - - // parse value - get_token(); - if (not accept_internal()) - { - return false; - } - - // comma -> next value - get_token(); - if (last_token == token_type::value_separator) - { - get_token(); - continue; - } - - // closing } - return (last_token == token_type::end_object); - } - } - - case token_type::begin_array: - { - // read next token - get_token(); - - // closing ] -> we are done - if (last_token == token_type::end_array) - { - return true; - } - - // parse values - while (true) - { - // parse value - if (not accept_internal()) - { - return false; - } - - // comma -> next value - get_token(); - if (last_token == token_type::value_separator) - { - get_token(); - continue; - } - - // closing ] - return (last_token == token_type::end_array); - } - } - - case token_type::value_float: - { - // reject infinity or NAN - return std::isfinite(m_lexer.get_number_float()); - } - - case token_type::literal_false: - case token_type::literal_null: - case token_type::literal_true: - case token_type::value_integer: - case token_type::value_string: - case token_type::value_unsigned: - return true; - - default: // the last token was unexpected - return false; - } - } - - /// get next token from lexer - token_type get_token() - { - return (last_token = m_lexer.scan()); - } - - /*! - @throw parse_error.101 if expected token did not occur - */ - bool expect(token_type t) - { - if (JSON_UNLIKELY(t != last_token)) - { - errored = true; - expected = t; - if (allow_exceptions) - { - throw_exception(); - } - else - { - return false; - } - } - - return true; - } - - [[noreturn]] void throw_exception() const - { - std::string error_msg = "syntax error - "; - if (last_token == token_type::parse_error) - { - error_msg += std::string(m_lexer.get_error_message()) + "; last read: '" + - m_lexer.get_token_string() + "'"; - } - else - { - error_msg += "unexpected " + std::string(lexer_t::token_type_name(last_token)); - } - - if (expected != token_type::uninitialized) - { - error_msg += "; expected " + std::string(lexer_t::token_type_name(expected)); - } - - JSON_THROW(parse_error::create(101, m_lexer.get_position(), error_msg)); - } - - private: - /// current level of recursion - int depth = 0; - /// callback function - const parser_callback_t callback = nullptr; - /// the type of the last read token - token_type last_token = token_type::uninitialized; - /// the lexer - lexer_t m_lexer; - /// whether a syntax error occurred - bool errored = false; - /// possible reason for the syntax error - token_type expected = token_type::uninitialized; - /// whether to throw exceptions in case of errors - const bool allow_exceptions = true; -}; - /////////////// // iterators // /////////////// From 51ecc31db71ba01bc6c2595e77df08146ea887bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20DELRIEU?= Date: Mon, 14 Aug 2017 17:10:32 +0200 Subject: [PATCH 41/59] add detail/iterators/primitive_iterator.hpp --- Makefile | 3 +- src/detail/iterators/primitive_iterator.hpp | 130 ++++++++++++++++++++ src/json.hpp | 117 +----------------- 3 files changed, 133 insertions(+), 117 deletions(-) create mode 100644 src/detail/iterators/primitive_iterator.hpp diff --git a/Makefile b/Makefile index 69421ace..4f5e9249 100644 --- a/Makefile +++ b/Makefile @@ -12,7 +12,8 @@ SRCS = ${SRCDIR}/json.hpp \ ${SRCDIR}/detail/conversions/to_json.hpp \ ${SRCDIR}/detail/parsing/input_adapters.hpp \ ${SRCDIR}/detail/parsing/lexer.hpp \ - ${SRCDIR}/detail/parsing/parser.hpp + ${SRCDIR}/detail/parsing/parser.hpp \ + ${SRCDIR}/detail/iterators/primitive_iterator.hpp diff --git a/src/detail/iterators/primitive_iterator.hpp b/src/detail/iterators/primitive_iterator.hpp new file mode 100644 index 00000000..8ebafe0e --- /dev/null +++ b/src/detail/iterators/primitive_iterator.hpp @@ -0,0 +1,130 @@ +#ifndef NLOHMANN_JSON_DETAIL_ITERATORS_PRIMITIVE_ITERATOR_HPP +#define NLOHMANN_JSON_DETAIL_ITERATORS_PRIMITIVE_ITERATOR_HPP + +#include +#include +#include + +namespace nlohmann +{ +namespace detail +{ +/* +@brief an iterator for primitive JSON types + +This class models an iterator for primitive JSON types (boolean, number, +string). It's only purpose is to allow the iterator/const_iterator classes +to "iterate" over primitive values. Internally, the iterator is modeled by +a `difference_type` variable. Value begin_value (`0`) models the begin, +end_value (`1`) models past the end. +*/ +class primitive_iterator_t +{ + public: + using difference_type = std::ptrdiff_t; + + constexpr difference_type get_value() const noexcept + { + return m_it; + } + + /// set iterator to a defined beginning + void set_begin() noexcept + { + m_it = begin_value; + } + + /// set iterator to a defined past the end + void set_end() noexcept + { + m_it = end_value; + } + + /// return whether the iterator can be dereferenced + constexpr bool is_begin() const noexcept + { + return m_it == begin_value; + } + + /// return whether the iterator is at end + constexpr bool is_end() const noexcept + { + return m_it == end_value; + } + + friend constexpr bool operator==(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept + { + return lhs.m_it == rhs.m_it; + } + + friend constexpr bool operator<(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept + { + return lhs.m_it < rhs.m_it; + } + + primitive_iterator_t operator+(difference_type i) + { + auto result = *this; + result += i; + return result; + } + + friend constexpr difference_type operator-(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept + { + return lhs.m_it - rhs.m_it; + } + + friend std::ostream& operator<<(std::ostream& os, primitive_iterator_t it) + { + return os << it.m_it; + } + + primitive_iterator_t& operator++() + { + ++m_it; + return *this; + } + + primitive_iterator_t const operator++(int) + { + auto result = *this; + m_it++; + return result; + } + + primitive_iterator_t& operator--() + { + --m_it; + return *this; + } + + primitive_iterator_t const operator--(int) + { + auto result = *this; + m_it--; + return result; + } + + primitive_iterator_t& operator+=(difference_type n) + { + m_it += n; + return *this; + } + + primitive_iterator_t& operator-=(difference_type n) + { + m_it -= n; + return *this; + } + + private: + static constexpr difference_type begin_value = 0; + static constexpr difference_type end_value = begin_value + 1; + + /// iterator as signed integer type + difference_type m_it = (std::numeric_limits::min)(); +}; +} +} + +#endif diff --git a/src/json.hpp b/src/json.hpp index 326589ef..3d4eddd3 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -60,6 +60,7 @@ SOFTWARE. #include "detail/parsing/input_adapters.hpp" #include "detail/parsing/lexer.hpp" #include "detail/parsing/parser.hpp" +#include "detail/iterators/primitive_iterator.hpp" /*! @brief namespace for Niels Lohmann @@ -74,122 +75,6 @@ namespace detail // iterators // /////////////// -/*! -@brief an iterator for primitive JSON types - -This class models an iterator for primitive JSON types (boolean, number, -string). It's only purpose is to allow the iterator/const_iterator classes -to "iterate" over primitive values. Internally, the iterator is modeled by -a `difference_type` variable. Value begin_value (`0`) models the begin, -end_value (`1`) models past the end. -*/ -class primitive_iterator_t -{ - public: - using difference_type = std::ptrdiff_t; - - constexpr difference_type get_value() const noexcept - { - return m_it; - } - - /// set iterator to a defined beginning - void set_begin() noexcept - { - m_it = begin_value; - } - - /// set iterator to a defined past the end - void set_end() noexcept - { - m_it = end_value; - } - - /// return whether the iterator can be dereferenced - constexpr bool is_begin() const noexcept - { - return m_it == begin_value; - } - - /// return whether the iterator is at end - constexpr bool is_end() const noexcept - { - return m_it == end_value; - } - - friend constexpr bool operator==(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept - { - return lhs.m_it == rhs.m_it; - } - - friend constexpr bool operator<(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept - { - return lhs.m_it < rhs.m_it; - } - - primitive_iterator_t operator+(difference_type i) - { - auto result = *this; - result += i; - return result; - } - - friend constexpr difference_type operator-(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept - { - return lhs.m_it - rhs.m_it; - } - - friend std::ostream& operator<<(std::ostream& os, primitive_iterator_t it) - { - return os << it.m_it; - } - - primitive_iterator_t& operator++() - { - ++m_it; - return *this; - } - - primitive_iterator_t const operator++(int) - { - auto result = *this; - m_it++; - return result; - } - - primitive_iterator_t& operator--() - { - --m_it; - return *this; - } - - primitive_iterator_t const operator--(int) - { - auto result = *this; - m_it--; - return result; - } - - primitive_iterator_t& operator+=(difference_type n) - { - m_it += n; - return *this; - } - - primitive_iterator_t& operator-=(difference_type n) - { - m_it -= n; - return *this; - } - - private: - static constexpr difference_type begin_value = 0; - static constexpr difference_type end_value = begin_value + 1; - - /// iterator as signed integer type - difference_type m_it = (std::numeric_limits::min)(); -}; - /*! @brief an iterator value From 3e65a652905610f0cc28109ad35a911befdb2b61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20DELRIEU?= Date: Mon, 14 Aug 2017 17:18:07 +0200 Subject: [PATCH 42/59] add detail/iterators/internal_iterator.hpp --- Makefile | 3 ++- src/detail/iterators/internal_iterator.hpp | 28 ++++++++++++++++++++++ src/json.hpp | 17 +------------ 3 files changed, 31 insertions(+), 17 deletions(-) create mode 100644 src/detail/iterators/internal_iterator.hpp diff --git a/Makefile b/Makefile index 4f5e9249..d587f051 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,8 @@ SRCS = ${SRCDIR}/json.hpp \ ${SRCDIR}/detail/parsing/input_adapters.hpp \ ${SRCDIR}/detail/parsing/lexer.hpp \ ${SRCDIR}/detail/parsing/parser.hpp \ - ${SRCDIR}/detail/iterators/primitive_iterator.hpp + ${SRCDIR}/detail/iterators/primitive_iterator.hpp \ + ${SRCDIR}/detail/iterators/internal_iterator.hpp diff --git a/src/detail/iterators/internal_iterator.hpp b/src/detail/iterators/internal_iterator.hpp new file mode 100644 index 00000000..25763355 --- /dev/null +++ b/src/detail/iterators/internal_iterator.hpp @@ -0,0 +1,28 @@ +#ifndef NLOHMANN_JSON_DETAIL_ITERATORS_INTERNAL_ITERATOR_HPP +#define NLOHMANN_JSON_DETAIL_ITERATORS_INTERNAL_ITERATOR_HPP + +#include "detail/iterators/primitive_iterator.hpp" + +namespace nlohmann +{ +namespace detail +{ +/*! +@brief an iterator value + +@note This structure could easily be a union, but MSVC currently does not allow +unions members with complex constructors, see https://github.com/nlohmann/json/pull/105. +*/ +template struct internal_iterator +{ + /// iterator for JSON objects + typename BasicJsonType::object_t::iterator object_iterator {}; + /// iterator for JSON arrays + typename BasicJsonType::array_t::iterator array_iterator {}; + /// generic iterator for all other types + primitive_iterator_t primitive_iterator {}; +}; +} +} + +#endif diff --git a/src/json.hpp b/src/json.hpp index 3d4eddd3..561761dc 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -61,6 +61,7 @@ SOFTWARE. #include "detail/parsing/lexer.hpp" #include "detail/parsing/parser.hpp" #include "detail/iterators/primitive_iterator.hpp" +#include "detail/iterators/internal_iterator.hpp" /*! @brief namespace for Niels Lohmann @@ -75,22 +76,6 @@ namespace detail // iterators // /////////////// -/*! -@brief an iterator value - -@note This structure could easily be a union, but MSVC currently does not allow -unions members with complex constructors, see https://github.com/nlohmann/json/pull/105. -*/ -template struct internal_iterator -{ - /// iterator for JSON objects - typename BasicJsonType::object_t::iterator object_iterator {}; - /// iterator for JSON arrays - typename BasicJsonType::array_t::iterator array_iterator {}; - /// generic iterator for all other types - primitive_iterator_t primitive_iterator {}; -}; - template class iteration_proxy; /*! From bf06cf6c22b128cfe7ea06d3f4c37d434b575245 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20DELRIEU?= Date: Mon, 14 Aug 2017 17:23:15 +0200 Subject: [PATCH 43/59] add detail/iterators/iter_impl.hpp --- Makefile | 3 +- src/detail/iterators/iter_impl.hpp | 612 +++++++++++++++++++++++++++++ src/json.hpp | 596 +--------------------------- 3 files changed, 615 insertions(+), 596 deletions(-) create mode 100644 src/detail/iterators/iter_impl.hpp diff --git a/Makefile b/Makefile index d587f051..f5e18015 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,8 @@ SRCS = ${SRCDIR}/json.hpp \ ${SRCDIR}/detail/parsing/lexer.hpp \ ${SRCDIR}/detail/parsing/parser.hpp \ ${SRCDIR}/detail/iterators/primitive_iterator.hpp \ - ${SRCDIR}/detail/iterators/internal_iterator.hpp + ${SRCDIR}/detail/iterators/internal_iterator.hpp \ + ${SRCDIR}/detail/iterators/iter_impl.hpp diff --git a/src/detail/iterators/iter_impl.hpp b/src/detail/iterators/iter_impl.hpp new file mode 100644 index 00000000..79b11b33 --- /dev/null +++ b/src/detail/iterators/iter_impl.hpp @@ -0,0 +1,612 @@ +#ifndef NLOHMANN_JSON_DETAIL_ITERATORS_ITER_IMPL_HPP +#define NLOHMANN_JSON_DETAIL_ITERATORS_ITER_IMPL_HPP + +#include +#include + +#include "detail/exceptions.hpp" +#include "detail/macro_scope.hpp" + +namespace nlohmann +{ +namespace detail +{ +// forward declare, to be able to friend it later on +template class iteration_proxy; + +/*! +@brief a template for a bidirectional iterator for the @ref basic_json class + +This class implements a both iterators (iterator and const_iterator) for the +@ref basic_json class. + +@note An iterator is called *initialized* when a pointer to a JSON value has + been set (e.g., by a constructor or a copy assignment). If the iterator is + default-constructed, it is *uninitialized* and most methods are undefined. + **The library uses assertions to detect calls on uninitialized iterators.** + +@requirement The class satisfies the following concept requirements: +- +[BidirectionalIterator](http://en.cppreference.com/w/cpp/concept/BidirectionalIterator): + The iterator that can be moved can be moved in both directions (i.e. + incremented and decremented). + +@since version 1.0.0, simplified in version 2.0.9, change to bidirectional + iterators in version 3.0.0 (see https://github.com/nlohmann/json/issues/593) +*/ +template +class iter_impl +{ + /// allow basic_json to access private members + friend iter_impl::value, typename std::remove_const::type, const BasicJsonType>::type>; + friend BasicJsonType; + friend iteration_proxy; + + using object_t = typename BasicJsonType::object_t; + using array_t = typename BasicJsonType::array_t; + // make sure BasicJsonType is basic_json or const basic_json + static_assert(is_basic_json::type>::value, + "iter_impl only accepts (const) basic_json"); + + public: + + /// The std::iterator class template (used as a base class to provide typedefs) is deprecated in C++17. + /// The C++ Standard has never required user-defined iterators to derive from std::iterator. + /// A user-defined iterator should provide publicly accessible typedefs named + /// iterator_category, value_type, difference_type, pointer, and reference. + /// Note that value_type is required to be non-const, even for constant iterators. + using iterator_category = std::bidirectional_iterator_tag; + + /// the type of the values when the iterator is dereferenced + using value_type = typename BasicJsonType::value_type; + /// a type to represent differences between iterators + using difference_type = typename BasicJsonType::difference_type; + /// defines a pointer to the type iterated over (value_type) + using pointer = typename std::conditional::value, + typename BasicJsonType::const_pointer, + typename BasicJsonType::pointer>::type; + /// defines a reference to the type iterated over (value_type) + using reference = + typename std::conditional::value, + typename BasicJsonType::const_reference, + typename BasicJsonType::reference>::type; + + /// default constructor + iter_impl() = default; + + /*! + @brief constructor for a given JSON instance + @param[in] object pointer to a JSON object for this iterator + @pre object != nullptr + @post The iterator is initialized; i.e. `m_object != nullptr`. + */ + explicit iter_impl(pointer object) noexcept : m_object(object) + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + { + m_it.object_iterator = typename object_t::iterator(); + break; + } + + case value_t::array: + { + m_it.array_iterator = typename array_t::iterator(); + break; + } + + default: + { + m_it.primitive_iterator = primitive_iterator_t(); + break; + } + } + } + + /*! + @note The conventional copy constructor and copy assignment are implicitly + defined. Combined with the following converting constructor and + assignment, they support: (1) copy from iterator to iterator, (2) + copy from const iterator to const iterator, and (3) conversion from + iterator to const iterator. However conversion from const iterator + to iterator is not defined. + */ + + /*! + @brief converting constructor + @param[in] other non-const iterator to copy from + @note It is not checked whether @a other is initialized. + */ + iter_impl(const iter_impl::type>& other) noexcept + : m_object(other.m_object), m_it(other.m_it) {} + + /*! + @brief converting assignment + @param[in,out] other non-const iterator to copy from + @return const/non-const iterator + @note It is not checked whether @a other is initialized. + */ + iter_impl& operator=(const iter_impl::type>& other) noexcept + { + m_object = other.m_object; + m_it = other.m_it; + return *this; + } + + private: + /*! + @brief set the iterator to the first value + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + void set_begin() noexcept + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + { + m_it.object_iterator = m_object->m_value.object->begin(); + break; + } + + case value_t::array: + { + m_it.array_iterator = m_object->m_value.array->begin(); + break; + } + + case value_t::null: + { + // set to end so begin()==end() is true: null is empty + m_it.primitive_iterator.set_end(); + break; + } + + default: + { + m_it.primitive_iterator.set_begin(); + break; + } + } + } + + /*! + @brief set the iterator past the last value + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + void set_end() noexcept + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + { + m_it.object_iterator = m_object->m_value.object->end(); + break; + } + + case value_t::array: + { + m_it.array_iterator = m_object->m_value.array->end(); + break; + } + + default: + { + m_it.primitive_iterator.set_end(); + break; + } + } + } + + public: + /*! + @brief return a reference to the value pointed to by the iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + reference operator*() const + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + { + assert(m_it.object_iterator != m_object->m_value.object->end()); + return m_it.object_iterator->second; + } + + case value_t::array: + { + assert(m_it.array_iterator != m_object->m_value.array->end()); + return *m_it.array_iterator; + } + + case value_t::null: + JSON_THROW(invalid_iterator::create(214, "cannot get value")); + + default: + { + if (JSON_LIKELY(m_it.primitive_iterator.is_begin())) + { + return *m_object; + } + + JSON_THROW(invalid_iterator::create(214, "cannot get value")); + } + } + } + + /*! + @brief dereference the iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + pointer operator->() const + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + { + assert(m_it.object_iterator != m_object->m_value.object->end()); + return &(m_it.object_iterator->second); + } + + case value_t::array: + { + assert(m_it.array_iterator != m_object->m_value.array->end()); + return &*m_it.array_iterator; + } + + default: + { + if (JSON_LIKELY(m_it.primitive_iterator.is_begin())) + { + return m_object; + } + + JSON_THROW(invalid_iterator::create(214, "cannot get value")); + } + } + } + + /*! + @brief post-increment (it++) + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl const operator++(int) + { + auto result = *this; + ++(*this); + return result; + } + + /*! + @brief pre-increment (++it) + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl& operator++() + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + { + std::advance(m_it.object_iterator, 1); + break; + } + + case value_t::array: + { + std::advance(m_it.array_iterator, 1); + break; + } + + default: + { + ++m_it.primitive_iterator; + break; + } + } + + return *this; + } + + /*! + @brief post-decrement (it--) + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl const operator--(int) + { + auto result = *this; + --(*this); + return result; + } + + /*! + @brief pre-decrement (--it) + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl& operator--() + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + { + std::advance(m_it.object_iterator, -1); + break; + } + + case value_t::array: + { + std::advance(m_it.array_iterator, -1); + break; + } + + default: + { + --m_it.primitive_iterator; + break; + } + } + + return *this; + } + + /*! + @brief comparison: equal + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + bool operator==(const iter_impl& other) const + { + // if objects are not the same, the comparison is undefined + if (JSON_UNLIKELY(m_object != other.m_object)) + { + JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers")); + } + + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + return (m_it.object_iterator == other.m_it.object_iterator); + + case value_t::array: + return (m_it.array_iterator == other.m_it.array_iterator); + + default: + return (m_it.primitive_iterator == other.m_it.primitive_iterator); + } + } + + /*! + @brief comparison: not equal + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + bool operator!=(const iter_impl& other) const + { + return not operator==(other); + } + + /*! + @brief comparison: smaller + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + bool operator<(const iter_impl& other) const + { + // if objects are not the same, the comparison is undefined + if (JSON_UNLIKELY(m_object != other.m_object)) + { + JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers")); + } + + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + JSON_THROW(invalid_iterator::create(213, "cannot compare order of object iterators")); + + case value_t::array: + return (m_it.array_iterator < other.m_it.array_iterator); + + default: + return (m_it.primitive_iterator < other.m_it.primitive_iterator); + } + } + + /*! + @brief comparison: less than or equal + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + bool operator<=(const iter_impl& other) const + { + return not other.operator < (*this); + } + + /*! + @brief comparison: greater than + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + bool operator>(const iter_impl& other) const + { + return not operator<=(other); + } + + /*! + @brief comparison: greater than or equal + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + bool operator>=(const iter_impl& other) const + { + return not operator<(other); + } + + /*! + @brief add to iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl& operator+=(difference_type i) + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators")); + + case value_t::array: + { + std::advance(m_it.array_iterator, i); + break; + } + + default: + { + m_it.primitive_iterator += i; + break; + } + } + + return *this; + } + + /*! + @brief subtract from iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl& operator-=(difference_type i) + { + return operator+=(-i); + } + + /*! + @brief add to iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl operator+(difference_type i) const + { + auto result = *this; + result += i; + return result; + } + + /*! + @brief addition of distance and iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + friend iter_impl operator+(difference_type i, const iter_impl& it) + { + auto result = it; + result += i; + return result; + } + + /*! + @brief subtract from iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl operator-(difference_type i) const + { + auto result = *this; + result -= i; + return result; + } + + /*! + @brief return difference + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + difference_type operator-(const iter_impl& other) const + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators")); + + case value_t::array: + return m_it.array_iterator - other.m_it.array_iterator; + + default: + return m_it.primitive_iterator - other.m_it.primitive_iterator; + } + } + + /*! + @brief access to successor + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + reference operator[](difference_type n) const + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + JSON_THROW(invalid_iterator::create(208, "cannot use operator[] for object iterators")); + + case value_t::array: + return *std::next(m_it.array_iterator, n); + + case value_t::null: + JSON_THROW(invalid_iterator::create(214, "cannot get value")); + + default: + { + if (JSON_LIKELY(m_it.primitive_iterator.get_value() == -n)) + { + return *m_object; + } + + JSON_THROW(invalid_iterator::create(214, "cannot get value")); + } + } + } + + /*! + @brief return the key of an object iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + typename object_t::key_type key() const + { + assert(m_object != nullptr); + + if (JSON_LIKELY(m_object->is_object())) + { + return m_it.object_iterator->first; + } + + JSON_THROW(invalid_iterator::create(207, "cannot use key() for non-object iterators")); + } + + /*! + @brief return the value of an iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + reference value() const + { + return operator*(); + } + + private: + /// associated JSON instance + pointer m_object = nullptr; + /// the actual iterator of the associated instance + internal_iterator::type> m_it = {}; +}; +} +} + +#endif diff --git a/src/json.hpp b/src/json.hpp index 561761dc..fbaffd87 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -62,6 +62,7 @@ SOFTWARE. #include "detail/parsing/parser.hpp" #include "detail/iterators/primitive_iterator.hpp" #include "detail/iterators/internal_iterator.hpp" +#include "detail/iterators/iter_impl.hpp" /*! @brief namespace for Niels Lohmann @@ -76,601 +77,6 @@ namespace detail // iterators // /////////////// -template class iteration_proxy; - -/*! -@brief a template for a bidirectional iterator for the @ref basic_json class - -This class implements a both iterators (iterator and const_iterator) for the -@ref basic_json class. - -@note An iterator is called *initialized* when a pointer to a JSON value has - been set (e.g., by a constructor or a copy assignment). If the iterator is - default-constructed, it is *uninitialized* and most methods are undefined. - **The library uses assertions to detect calls on uninitialized iterators.** - -@requirement The class satisfies the following concept requirements: -- -[BidirectionalIterator](http://en.cppreference.com/w/cpp/concept/BidirectionalIterator): - The iterator that can be moved can be moved in both directions (i.e. - incremented and decremented). - -@since version 1.0.0, simplified in version 2.0.9, change to bidirectional - iterators in version 3.0.0 (see https://github.com/nlohmann/json/issues/593) -*/ -template -class iter_impl -{ - /// allow basic_json to access private members - friend iter_impl::value, typename std::remove_const::type, const BasicJsonType>::type>; - friend BasicJsonType; - friend iteration_proxy; - - using object_t = typename BasicJsonType::object_t; - using array_t = typename BasicJsonType::array_t; - // make sure BasicJsonType is basic_json or const basic_json - static_assert(is_basic_json::type>::value, - "iter_impl only accepts (const) basic_json"); - - public: - - /// The std::iterator class template (used as a base class to provide typedefs) is deprecated in C++17. - /// The C++ Standard has never required user-defined iterators to derive from std::iterator. - /// A user-defined iterator should provide publicly accessible typedefs named - /// iterator_category, value_type, difference_type, pointer, and reference. - /// Note that value_type is required to be non-const, even for constant iterators. - using iterator_category = std::bidirectional_iterator_tag; - - /// the type of the values when the iterator is dereferenced - using value_type = typename BasicJsonType::value_type; - /// a type to represent differences between iterators - using difference_type = typename BasicJsonType::difference_type; - /// defines a pointer to the type iterated over (value_type) - using pointer = typename std::conditional::value, - typename BasicJsonType::const_pointer, - typename BasicJsonType::pointer>::type; - /// defines a reference to the type iterated over (value_type) - using reference = - typename std::conditional::value, - typename BasicJsonType::const_reference, - typename BasicJsonType::reference>::type; - - /// default constructor - iter_impl() = default; - - /*! - @brief constructor for a given JSON instance - @param[in] object pointer to a JSON object for this iterator - @pre object != nullptr - @post The iterator is initialized; i.e. `m_object != nullptr`. - */ - explicit iter_impl(pointer object) noexcept : m_object(object) - { - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case value_t::object: - { - m_it.object_iterator = typename object_t::iterator(); - break; - } - - case value_t::array: - { - m_it.array_iterator = typename array_t::iterator(); - break; - } - - default: - { - m_it.primitive_iterator = primitive_iterator_t(); - break; - } - } - } - - /*! - @note The conventional copy constructor and copy assignment are implicitly - defined. Combined with the following converting constructor and - assignment, they support: (1) copy from iterator to iterator, (2) - copy from const iterator to const iterator, and (3) conversion from - iterator to const iterator. However conversion from const iterator - to iterator is not defined. - */ - - /*! - @brief converting constructor - @param[in] other non-const iterator to copy from - @note It is not checked whether @a other is initialized. - */ - iter_impl(const iter_impl::type>& other) noexcept - : m_object(other.m_object), m_it(other.m_it) {} - - /*! - @brief converting assignment - @param[in,out] other non-const iterator to copy from - @return const/non-const iterator - @note It is not checked whether @a other is initialized. - */ - iter_impl& operator=(const iter_impl::type>& other) noexcept - { - m_object = other.m_object; - m_it = other.m_it; - return *this; - } - - private: - /*! - @brief set the iterator to the first value - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - void set_begin() noexcept - { - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case value_t::object: - { - m_it.object_iterator = m_object->m_value.object->begin(); - break; - } - - case value_t::array: - { - m_it.array_iterator = m_object->m_value.array->begin(); - break; - } - - case value_t::null: - { - // set to end so begin()==end() is true: null is empty - m_it.primitive_iterator.set_end(); - break; - } - - default: - { - m_it.primitive_iterator.set_begin(); - break; - } - } - } - - /*! - @brief set the iterator past the last value - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - void set_end() noexcept - { - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case value_t::object: - { - m_it.object_iterator = m_object->m_value.object->end(); - break; - } - - case value_t::array: - { - m_it.array_iterator = m_object->m_value.array->end(); - break; - } - - default: - { - m_it.primitive_iterator.set_end(); - break; - } - } - } - - public: - /*! - @brief return a reference to the value pointed to by the iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - reference operator*() const - { - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case value_t::object: - { - assert(m_it.object_iterator != m_object->m_value.object->end()); - return m_it.object_iterator->second; - } - - case value_t::array: - { - assert(m_it.array_iterator != m_object->m_value.array->end()); - return *m_it.array_iterator; - } - - case value_t::null: - JSON_THROW(invalid_iterator::create(214, "cannot get value")); - - default: - { - if (JSON_LIKELY(m_it.primitive_iterator.is_begin())) - { - return *m_object; - } - - JSON_THROW(invalid_iterator::create(214, "cannot get value")); - } - } - } - - /*! - @brief dereference the iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - pointer operator->() const - { - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case value_t::object: - { - assert(m_it.object_iterator != m_object->m_value.object->end()); - return &(m_it.object_iterator->second); - } - - case value_t::array: - { - assert(m_it.array_iterator != m_object->m_value.array->end()); - return &*m_it.array_iterator; - } - - default: - { - if (JSON_LIKELY(m_it.primitive_iterator.is_begin())) - { - return m_object; - } - - JSON_THROW(invalid_iterator::create(214, "cannot get value")); - } - } - } - - /*! - @brief post-increment (it++) - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - iter_impl const operator++(int) - { - auto result = *this; - ++(*this); - return result; - } - - /*! - @brief pre-increment (++it) - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - iter_impl& operator++() - { - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case value_t::object: - { - std::advance(m_it.object_iterator, 1); - break; - } - - case value_t::array: - { - std::advance(m_it.array_iterator, 1); - break; - } - - default: - { - ++m_it.primitive_iterator; - break; - } - } - - return *this; - } - - /*! - @brief post-decrement (it--) - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - iter_impl const operator--(int) - { - auto result = *this; - --(*this); - return result; - } - - /*! - @brief pre-decrement (--it) - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - iter_impl& operator--() - { - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case value_t::object: - { - std::advance(m_it.object_iterator, -1); - break; - } - - case value_t::array: - { - std::advance(m_it.array_iterator, -1); - break; - } - - default: - { - --m_it.primitive_iterator; - break; - } - } - - return *this; - } - - /*! - @brief comparison: equal - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - bool operator==(const iter_impl& other) const - { - // if objects are not the same, the comparison is undefined - if (JSON_UNLIKELY(m_object != other.m_object)) - { - JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers")); - } - - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case value_t::object: - return (m_it.object_iterator == other.m_it.object_iterator); - - case value_t::array: - return (m_it.array_iterator == other.m_it.array_iterator); - - default: - return (m_it.primitive_iterator == other.m_it.primitive_iterator); - } - } - - /*! - @brief comparison: not equal - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - bool operator!=(const iter_impl& other) const - { - return not operator==(other); - } - - /*! - @brief comparison: smaller - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - bool operator<(const iter_impl& other) const - { - // if objects are not the same, the comparison is undefined - if (JSON_UNLIKELY(m_object != other.m_object)) - { - JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers")); - } - - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case value_t::object: - JSON_THROW(invalid_iterator::create(213, "cannot compare order of object iterators")); - - case value_t::array: - return (m_it.array_iterator < other.m_it.array_iterator); - - default: - return (m_it.primitive_iterator < other.m_it.primitive_iterator); - } - } - - /*! - @brief comparison: less than or equal - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - bool operator<=(const iter_impl& other) const - { - return not other.operator < (*this); - } - - /*! - @brief comparison: greater than - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - bool operator>(const iter_impl& other) const - { - return not operator<=(other); - } - - /*! - @brief comparison: greater than or equal - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - bool operator>=(const iter_impl& other) const - { - return not operator<(other); - } - - /*! - @brief add to iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - iter_impl& operator+=(difference_type i) - { - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case value_t::object: - JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators")); - - case value_t::array: - { - std::advance(m_it.array_iterator, i); - break; - } - - default: - { - m_it.primitive_iterator += i; - break; - } - } - - return *this; - } - - /*! - @brief subtract from iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - iter_impl& operator-=(difference_type i) - { - return operator+=(-i); - } - - /*! - @brief add to iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - iter_impl operator+(difference_type i) const - { - auto result = *this; - result += i; - return result; - } - - /*! - @brief addition of distance and iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - friend iter_impl operator+(difference_type i, const iter_impl& it) - { - auto result = it; - result += i; - return result; - } - - /*! - @brief subtract from iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - iter_impl operator-(difference_type i) const - { - auto result = *this; - result -= i; - return result; - } - - /*! - @brief return difference - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - difference_type operator-(const iter_impl& other) const - { - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case value_t::object: - JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators")); - - case value_t::array: - return m_it.array_iterator - other.m_it.array_iterator; - - default: - return m_it.primitive_iterator - other.m_it.primitive_iterator; - } - } - - /*! - @brief access to successor - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - reference operator[](difference_type n) const - { - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case value_t::object: - JSON_THROW(invalid_iterator::create(208, "cannot use operator[] for object iterators")); - - case value_t::array: - return *std::next(m_it.array_iterator, n); - - case value_t::null: - JSON_THROW(invalid_iterator::create(214, "cannot get value")); - - default: - { - if (JSON_LIKELY(m_it.primitive_iterator.get_value() == -n)) - { - return *m_object; - } - - JSON_THROW(invalid_iterator::create(214, "cannot get value")); - } - } - } - - /*! - @brief return the key of an object iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - typename object_t::key_type key() const - { - assert(m_object != nullptr); - - if (JSON_LIKELY(m_object->is_object())) - { - return m_it.object_iterator->first; - } - - JSON_THROW(invalid_iterator::create(207, "cannot use key() for non-object iterators")); - } - - /*! - @brief return the value of an iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - reference value() const - { - return operator*(); - } - - private: - /// associated JSON instance - pointer m_object = nullptr; - /// the actual iterator of the associated instance - internal_iterator::type> m_it = {}; -}; - /// proxy class for the iterator_wrapper functions template class iteration_proxy { From 5fc9ef2b901d24b312b2fd4bf787b678e30c4599 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20DELRIEU?= Date: Mon, 14 Aug 2017 17:26:22 +0200 Subject: [PATCH 44/59] add detail/iterators/iteration_proxy.hpp --- Makefile | 3 +- src/detail/iterators/iteration_proxy.hpp | 99 ++++++++++++++++++++++++ src/json.hpp | 87 +-------------------- 3 files changed, 102 insertions(+), 87 deletions(-) create mode 100644 src/detail/iterators/iteration_proxy.hpp diff --git a/Makefile b/Makefile index f5e18015..cbe650e9 100644 --- a/Makefile +++ b/Makefile @@ -15,7 +15,8 @@ SRCS = ${SRCDIR}/json.hpp \ ${SRCDIR}/detail/parsing/parser.hpp \ ${SRCDIR}/detail/iterators/primitive_iterator.hpp \ ${SRCDIR}/detail/iterators/internal_iterator.hpp \ - ${SRCDIR}/detail/iterators/iter_impl.hpp + ${SRCDIR}/detail/iterators/iter_impl.hpp \ + ${SRCDIR}/detail/iterators/iteration_proxy.hpp diff --git a/src/detail/iterators/iteration_proxy.hpp b/src/detail/iterators/iteration_proxy.hpp new file mode 100644 index 00000000..6a13f39d --- /dev/null +++ b/src/detail/iterators/iteration_proxy.hpp @@ -0,0 +1,99 @@ +#ifndef NLOHMANN_JSON_DETAIL_ITERATORS_ITERATION_PROXY_HPP +#define NLOHMANN_JSON_DETAIL_ITERATORS_ITERATION_PROXY_HPP + +#include +#include + +namespace nlohmann +{ +namespace detail +{ +/// proxy class for the iterator_wrapper functions +template class iteration_proxy +{ + private: + /// helper class for iteration + class iteration_proxy_internal + { + private: + /// the iterator + IteratorType anchor; + /// an index for arrays (used to create key names) + std::size_t array_index = 0; + + public: + explicit iteration_proxy_internal(IteratorType it) noexcept : anchor(it) {} + + /// dereference operator (needed for range-based for) + iteration_proxy_internal& operator*() + { + return *this; + } + + /// increment operator (needed for range-based for) + iteration_proxy_internal& operator++() + { + ++anchor; + ++array_index; + + return *this; + } + + /// inequality operator (needed for range-based for) + bool operator!=(const iteration_proxy_internal& o) const noexcept + { + return anchor != o.anchor; + } + + /// return key of the iterator + std::string key() const + { + assert(anchor.m_object != nullptr); + + switch (anchor.m_object->type()) + { + // use integer array index as key + case value_t::array: + return std::to_string(array_index); + + // use key from the object + case value_t::object: + return anchor.key(); + + // use an empty key for all primitive types + default: + return ""; + } + } + + /// return value of the iterator + typename IteratorType::reference value() const + { + return anchor.value(); + } + }; + + /// the container to iterate + typename IteratorType::reference container; + + public: + /// construct iteration proxy from a container + explicit iteration_proxy(typename IteratorType::reference cont) + : container(cont) {} + + /// return iterator begin (needed for range-based for) + iteration_proxy_internal begin() noexcept + { + return iteration_proxy_internal(container.begin()); + } + + /// return iterator end (needed for range-based for) + iteration_proxy_internal end() noexcept + { + return iteration_proxy_internal(container.end()); + } +}; +} +} + +#endif diff --git a/src/json.hpp b/src/json.hpp index fbaffd87..eb61f34a 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -63,6 +63,7 @@ SOFTWARE. #include "detail/iterators/primitive_iterator.hpp" #include "detail/iterators/internal_iterator.hpp" #include "detail/iterators/iter_impl.hpp" +#include "detail/iterators/iteration_proxy.hpp" /*! @brief namespace for Niels Lohmann @@ -77,92 +78,6 @@ namespace detail // iterators // /////////////// -/// proxy class for the iterator_wrapper functions -template class iteration_proxy -{ - private: - /// helper class for iteration - class iteration_proxy_internal - { - private: - /// the iterator - IteratorType anchor; - /// an index for arrays (used to create key names) - std::size_t array_index = 0; - - public: - explicit iteration_proxy_internal(IteratorType it) noexcept : anchor(it) {} - - /// dereference operator (needed for range-based for) - iteration_proxy_internal& operator*() - { - return *this; - } - - /// increment operator (needed for range-based for) - iteration_proxy_internal& operator++() - { - ++anchor; - ++array_index; - - return *this; - } - - /// inequality operator (needed for range-based for) - bool operator!=(const iteration_proxy_internal& o) const noexcept - { - return anchor != o.anchor; - } - - /// return key of the iterator - std::string key() const - { - assert(anchor.m_object != nullptr); - - switch (anchor.m_object->type()) - { - // use integer array index as key - case value_t::array: - return std::to_string(array_index); - - // use key from the object - case value_t::object: - return anchor.key(); - - // use an empty key for all primitive types - default: - return ""; - } - } - - /// return value of the iterator - typename IteratorType::reference value() const - { - return anchor.value(); - } - }; - - /// the container to iterate - typename IteratorType::reference container; - - public: - /// construct iteration proxy from a container - explicit iteration_proxy(typename IteratorType::reference cont) - : container(cont) {} - - /// return iterator begin (needed for range-based for) - iteration_proxy_internal begin() noexcept - { - return iteration_proxy_internal(container.begin()); - } - - /// return iterator end (needed for range-based for) - iteration_proxy_internal end() noexcept - { - return iteration_proxy_internal(container.end()); - } -}; - /*! @brief a template for a reverse iterator class From ae6f66048cf99e8bc07644e9e83404f70879b639 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20DELRIEU?= Date: Mon, 14 Aug 2017 17:29:55 +0200 Subject: [PATCH 45/59] add detail/iterators/json_reverse_iterator.hpp --- Makefile | 3 +- .../iterators/json_reverse_iterator.hpp | 122 ++++++++++++++++++ src/json.hpp | 109 +--------------- 3 files changed, 125 insertions(+), 109 deletions(-) create mode 100644 src/detail/iterators/json_reverse_iterator.hpp diff --git a/Makefile b/Makefile index cbe650e9..1b947462 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,8 @@ SRCS = ${SRCDIR}/json.hpp \ ${SRCDIR}/detail/iterators/primitive_iterator.hpp \ ${SRCDIR}/detail/iterators/internal_iterator.hpp \ ${SRCDIR}/detail/iterators/iter_impl.hpp \ - ${SRCDIR}/detail/iterators/iteration_proxy.hpp + ${SRCDIR}/detail/iterators/iteration_proxy.hpp \ + ${SRCDIR}/detail/iterators/json_reverse_iterator.hpp diff --git a/src/detail/iterators/json_reverse_iterator.hpp b/src/detail/iterators/json_reverse_iterator.hpp new file mode 100644 index 00000000..52862d38 --- /dev/null +++ b/src/detail/iterators/json_reverse_iterator.hpp @@ -0,0 +1,122 @@ +#ifndef NLOHMANN_JSON_DETAIL_ITERATORS_JSON_REVERSE_ITERATOR_HPP +#define NLOHMANN_JSON_DETAIL_ITERATORS_JSON_REVERSE_ITERATOR_HPP + +#include +#include +#include + +namespace nlohmann +{ +namespace detail +{ +////////////////////// +// reverse_iterator // +////////////////////// + +/*! +@brief a template for a reverse iterator class + +@tparam Base the base iterator type to reverse. Valid types are @ref +iterator (to create @ref reverse_iterator) and @ref const_iterator (to +create @ref const_reverse_iterator). + +@requirement The class satisfies the following concept requirements: +- +[BidirectionalIterator](http://en.cppreference.com/w/cpp/concept/BidirectionalIterator): + The iterator that can be moved can be moved in both directions (i.e. + incremented and decremented). +- [OutputIterator](http://en.cppreference.com/w/cpp/concept/OutputIterator): + It is possible to write to the pointed-to element (only if @a Base is + @ref iterator). + +@since version 1.0.0 +*/ +template +class json_reverse_iterator : public std::reverse_iterator +{ + public: + using difference_type = std::ptrdiff_t; + /// shortcut to the reverse iterator adapter + using base_iterator = std::reverse_iterator; + /// the reference type for the pointed-to element + using reference = typename Base::reference; + + /// create reverse iterator from iterator + json_reverse_iterator(const typename base_iterator::iterator_type& it) noexcept + : base_iterator(it) {} + + /// create reverse iterator from base class + json_reverse_iterator(const base_iterator& it) noexcept : base_iterator(it) {} + + /// post-increment (it++) + json_reverse_iterator const operator++(int) + { + return static_cast(base_iterator::operator++(1)); + } + + /// pre-increment (++it) + json_reverse_iterator& operator++() + { + return static_cast(base_iterator::operator++()); + } + + /// post-decrement (it--) + json_reverse_iterator const operator--(int) + { + return static_cast(base_iterator::operator--(1)); + } + + /// pre-decrement (--it) + json_reverse_iterator& operator--() + { + return static_cast(base_iterator::operator--()); + } + + /// add to iterator + json_reverse_iterator& operator+=(difference_type i) + { + return static_cast(base_iterator::operator+=(i)); + } + + /// add to iterator + json_reverse_iterator operator+(difference_type i) const + { + return static_cast(base_iterator::operator+(i)); + } + + /// subtract from iterator + json_reverse_iterator operator-(difference_type i) const + { + return static_cast(base_iterator::operator-(i)); + } + + /// return difference + difference_type operator-(const json_reverse_iterator& other) const + { + return base_iterator(*this) - base_iterator(other); + } + + /// access to successor + reference operator[](difference_type n) const + { + return *(this->operator+(n)); + } + + /// return the key of an object iterator + auto key() const -> decltype(std::declval().key()) + { + auto it = --this->base(); + return it.key(); + } + + /// return the value of an iterator + reference value() const + { + auto it = --this->base(); + return it.operator * (); + } +}; +} +} + +#endif diff --git a/src/json.hpp b/src/json.hpp index eb61f34a..3cf317f7 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -64,6 +64,7 @@ SOFTWARE. #include "detail/iterators/internal_iterator.hpp" #include "detail/iterators/iter_impl.hpp" #include "detail/iterators/iteration_proxy.hpp" +#include "detail/iterators/json_reverse_iterator.hpp" /*! @brief namespace for Niels Lohmann @@ -74,114 +75,6 @@ namespace nlohmann { namespace detail { -/////////////// -// iterators // -/////////////// - -/*! -@brief a template for a reverse iterator class - -@tparam Base the base iterator type to reverse. Valid types are @ref -iterator (to create @ref reverse_iterator) and @ref const_iterator (to -create @ref const_reverse_iterator). - -@requirement The class satisfies the following concept requirements: -- -[BidirectionalIterator](http://en.cppreference.com/w/cpp/concept/BidirectionalIterator): - The iterator that can be moved can be moved in both directions (i.e. - incremented and decremented). -- [OutputIterator](http://en.cppreference.com/w/cpp/concept/OutputIterator): - It is possible to write to the pointed-to element (only if @a Base is - @ref iterator). - -@since version 1.0.0 -*/ -template -class json_reverse_iterator : public std::reverse_iterator -{ - public: - using difference_type = std::ptrdiff_t; - /// shortcut to the reverse iterator adapter - using base_iterator = std::reverse_iterator; - /// the reference type for the pointed-to element - using reference = typename Base::reference; - - /// create reverse iterator from iterator - json_reverse_iterator(const typename base_iterator::iterator_type& it) noexcept - : base_iterator(it) {} - - /// create reverse iterator from base class - json_reverse_iterator(const base_iterator& it) noexcept : base_iterator(it) {} - - /// post-increment (it++) - json_reverse_iterator const operator++(int) - { - return static_cast(base_iterator::operator++(1)); - } - - /// pre-increment (++it) - json_reverse_iterator& operator++() - { - return static_cast(base_iterator::operator++()); - } - - /// post-decrement (it--) - json_reverse_iterator const operator--(int) - { - return static_cast(base_iterator::operator--(1)); - } - - /// pre-decrement (--it) - json_reverse_iterator& operator--() - { - return static_cast(base_iterator::operator--()); - } - - /// add to iterator - json_reverse_iterator& operator+=(difference_type i) - { - return static_cast(base_iterator::operator+=(i)); - } - - /// add to iterator - json_reverse_iterator operator+(difference_type i) const - { - return static_cast(base_iterator::operator+(i)); - } - - /// subtract from iterator - json_reverse_iterator operator-(difference_type i) const - { - return static_cast(base_iterator::operator-(i)); - } - - /// return difference - difference_type operator-(const json_reverse_iterator& other) const - { - return base_iterator(*this) - base_iterator(other); - } - - /// access to successor - reference operator[](difference_type n) const - { - return *(this->operator+(n)); - } - - /// return the key of an object iterator - auto key() const -> decltype(std::declval().key()) - { - auto it = --this->base(); - return it.key(); - } - - /// return the value of an iterator - reference value() const - { - auto it = --this->base(); - return it.operator * (); - } -}; - ///////////////////// // output adapters // ///////////////////// From 4dbb433a79e44058d4702a1a73f1838f0a25d6de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20DELRIEU?= Date: Mon, 14 Aug 2017 17:41:23 +0200 Subject: [PATCH 46/59] add detail/parsing/output_adapters.hpp --- Makefile | 3 +- src/detail/parsing/output_adapters.hpp | 114 +++++++++++++++++++++++++ src/json.hpp | 102 +--------------------- 3 files changed, 117 insertions(+), 102 deletions(-) create mode 100644 src/detail/parsing/output_adapters.hpp diff --git a/Makefile b/Makefile index 1b947462..bf4e5b67 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,8 @@ SRCS = ${SRCDIR}/json.hpp \ ${SRCDIR}/detail/iterators/internal_iterator.hpp \ ${SRCDIR}/detail/iterators/iter_impl.hpp \ ${SRCDIR}/detail/iterators/iteration_proxy.hpp \ - ${SRCDIR}/detail/iterators/json_reverse_iterator.hpp + ${SRCDIR}/detail/iterators/json_reverse_iterator.hpp \ + ${SRCDIR}/detail/parsing/output_adapters.hpp diff --git a/src/detail/parsing/output_adapters.hpp b/src/detail/parsing/output_adapters.hpp new file mode 100644 index 00000000..5cbc11b9 --- /dev/null +++ b/src/detail/parsing/output_adapters.hpp @@ -0,0 +1,114 @@ +#ifndef NLOHMANN_JSON_DETAIL_PARSING_OUTPUT_ADAPTERS_HPP +#define NLOHMANN_JSON_DETAIL_PARSING_OUTPUT_ADAPTERS_HPP + +#include +#include +#include +#include +#include +#include + +namespace nlohmann +{ +namespace detail +{ +/// abstract output adapter interface +template struct output_adapter_protocol +{ + virtual void write_character(CharType c) = 0; + virtual void write_characters(const CharType* s, std::size_t length) = 0; + virtual ~output_adapter_protocol() = default; +}; + +/// a type to simplify interfaces +template +using output_adapter_t = std::shared_ptr>; + +/// output adapter for byte vectors +template +class output_vector_adapter : public output_adapter_protocol +{ + public: + explicit output_vector_adapter(std::vector& vec) : v(vec) {} + + void write_character(CharType c) override + { + v.push_back(c); + } + + void write_characters(const CharType* s, std::size_t length) override + { + std::copy(s, s + length, std::back_inserter(v)); + } + + private: + std::vector& v; +}; + +/// output adapter for output streams +template +class output_stream_adapter : public output_adapter_protocol +{ + public: + explicit output_stream_adapter(std::basic_ostream& s) : stream(s) {} + + void write_character(CharType c) override + { + stream.put(c); + } + + void write_characters(const CharType* s, std::size_t length) override + { + stream.write(s, static_cast(length)); + } + + private: + std::basic_ostream& stream; +}; + +/// output adapter for basic_string +template +class output_string_adapter : public output_adapter_protocol +{ + public: + explicit output_string_adapter(std::basic_string& s) : str(s) {} + + void write_character(CharType c) override + { + str.push_back(c); + } + + void write_characters(const CharType* s, std::size_t length) override + { + str.append(s, length); + } + + private: + std::basic_string& str; +}; + +template +class output_adapter +{ + public: + output_adapter(std::vector& vec) + : oa(std::make_shared>(vec)) {} + + output_adapter(std::basic_ostream& s) + : oa(std::make_shared>(s)) {} + + output_adapter(std::basic_string& s) + : oa(std::make_shared>(s)) {} + + operator output_adapter_t() + { + return oa; + } + + private: + output_adapter_t oa = nullptr; +}; +} +} + +#endif diff --git a/src/json.hpp b/src/json.hpp index 3cf317f7..7d62e412 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -65,6 +65,7 @@ SOFTWARE. #include "detail/iterators/iter_impl.hpp" #include "detail/iterators/iteration_proxy.hpp" #include "detail/iterators/json_reverse_iterator.hpp" +#include "detail/parsing/output_adapters.hpp" /*! @brief namespace for Niels Lohmann @@ -75,107 +76,6 @@ namespace nlohmann { namespace detail { -///////////////////// -// output adapters // -///////////////////// - -/// abstract output adapter interface -template struct output_adapter_protocol -{ - virtual void write_character(CharType c) = 0; - virtual void write_characters(const CharType* s, std::size_t length) = 0; - virtual ~output_adapter_protocol() = default; -}; - -/// a type to simplify interfaces -template -using output_adapter_t = std::shared_ptr>; - -/// output adapter for byte vectors -template -class output_vector_adapter : public output_adapter_protocol -{ - public: - explicit output_vector_adapter(std::vector& vec) : v(vec) {} - - void write_character(CharType c) override - { - v.push_back(c); - } - - void write_characters(const CharType* s, std::size_t length) override - { - std::copy(s, s + length, std::back_inserter(v)); - } - - private: - std::vector& v; -}; - -/// output adapter for output streams -template -class output_stream_adapter : public output_adapter_protocol -{ - public: - explicit output_stream_adapter(std::basic_ostream& s) : stream(s) {} - - void write_character(CharType c) override - { - stream.put(c); - } - - void write_characters(const CharType* s, std::size_t length) override - { - stream.write(s, static_cast(length)); - } - - private: - std::basic_ostream& stream; -}; - -/// output adapter for basic_string -template -class output_string_adapter : public output_adapter_protocol -{ - public: - explicit output_string_adapter(std::basic_string& s) : str(s) {} - - void write_character(CharType c) override - { - str.push_back(c); - } - - void write_characters(const CharType* s, std::size_t length) override - { - str.append(s, length); - } - - private: - std::basic_string& str; -}; - -template -class output_adapter -{ - public: - output_adapter(std::vector& vec) - : oa(std::make_shared>(vec)) {} - - output_adapter(std::basic_ostream& s) - : oa(std::make_shared>(s)) {} - - output_adapter(std::basic_string& s) - : oa(std::make_shared>(s)) {} - - operator output_adapter_t() - { - return oa; - } - - private: - output_adapter_t oa = nullptr; -}; - ////////////////////////////// // binary reader and writer // ////////////////////////////// From d620f76f0db9599e208390c6c4103bcf31e4b3d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20DELRIEU?= Date: Mon, 14 Aug 2017 17:50:24 +0200 Subject: [PATCH 47/59] add detail/parsing/binary_reader.hpp --- Makefile | 6 +- src/detail/parsing/binary_reader.hpp | 1087 ++++++++++++++++++++++++++ src/json.hpp | 1066 +------------------------ 3 files changed, 1093 insertions(+), 1066 deletions(-) create mode 100644 src/detail/parsing/binary_reader.hpp diff --git a/Makefile b/Makefile index bf4e5b67..6fa61613 100644 --- a/Makefile +++ b/Makefile @@ -18,10 +18,8 @@ SRCS = ${SRCDIR}/json.hpp \ ${SRCDIR}/detail/iterators/iter_impl.hpp \ ${SRCDIR}/detail/iterators/iteration_proxy.hpp \ ${SRCDIR}/detail/iterators/json_reverse_iterator.hpp \ - ${SRCDIR}/detail/parsing/output_adapters.hpp - - - + ${SRCDIR}/detail/parsing/output_adapters.hpp \ + ${SRCDIR}/detail/parsing/binary_reader.hpp # main target all: diff --git a/src/detail/parsing/binary_reader.hpp b/src/detail/parsing/binary_reader.hpp new file mode 100644 index 00000000..0d8ce4ad --- /dev/null +++ b/src/detail/parsing/binary_reader.hpp @@ -0,0 +1,1087 @@ +#ifndef NLOHMANN_JSON_DETAIL_PARSING_BINARY_READER_HPP +#define NLOHMANN_JSON_DETAIL_PARSING_BINARY_READER_HPP + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "detail/exceptions.hpp" +#include "detail/macro_scope.hpp" +#include "detail/parsing/input_adapters.hpp" +#include "detail/value_t.hpp" + +namespace nlohmann +{ +namespace detail +{ +/////////////////// +// binary reader // +/////////////////// + +/*! +@brief deserialization of CBOR and MessagePack values +*/ +template +class binary_reader +{ + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + + public: + /*! + @brief create a binary reader + + @param[in] adapter input adapter to read from + */ + explicit binary_reader(input_adapter_t adapter) : ia(std::move(adapter)) + { + assert(ia); + } + + /*! + @brief create a JSON value from CBOR input + + @param[in] strict whether to expect the input to be consumed completed + @return JSON value created from CBOR input + + @throw parse_error.110 if input ended unexpectedly or the end of file was + not reached when @a strict was set to true + @throw parse_error.112 if unsupported byte was read + */ + BasicJsonType parse_cbor(const bool strict) + { + const auto res = parse_cbor_internal(); + if (strict) + { + get(); + check_eof(true); + } + return res; + } + + /*! + @brief create a JSON value from MessagePack input + + @param[in] strict whether to expect the input to be consumed completed + @return JSON value created from MessagePack input + + @throw parse_error.110 if input ended unexpectedly or the end of file was + not reached when @a strict was set to true + @throw parse_error.112 if unsupported byte was read + */ + BasicJsonType parse_msgpack(const bool strict) + { + const auto res = parse_msgpack_internal(); + if (strict) + { + get(); + check_eof(true); + } + return res; + } + + /*! + @brief determine system byte order + + @return true if and only if system's byte order is little endian + + @note from http://stackoverflow.com/a/1001328/266378 + */ + static constexpr bool little_endianess(int num = 1) noexcept + { + return (*reinterpret_cast(&num) == 1); + } + + private: + /*! + @param[in] get_char whether a new character should be retrieved from the + input (true, default) or whether the last read + character should be considered instead + */ + BasicJsonType parse_cbor_internal(const bool get_char = true) + { + switch (get_char ? get() : current) + { + // EOF + case std::char_traits::eof(): + JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input")); + + // Integer 0x00..0x17 (0..23) + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + case 0x09: + case 0x0A: + case 0x0B: + case 0x0C: + case 0x0D: + case 0x0E: + case 0x0F: + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + return static_cast(current); + + case 0x18: // Unsigned integer (one-byte uint8_t follows) + return get_number(); + + case 0x19: // Unsigned integer (two-byte uint16_t follows) + return get_number(); + + case 0x1A: // Unsigned integer (four-byte uint32_t follows) + return get_number(); + + case 0x1B: // Unsigned integer (eight-byte uint64_t follows) + return get_number(); + + // Negative integer -1-0x00..-1-0x17 (-1..-24) + case 0x20: + case 0x21: + case 0x22: + case 0x23: + case 0x24: + case 0x25: + case 0x26: + case 0x27: + case 0x28: + case 0x29: + case 0x2A: + case 0x2B: + case 0x2C: + case 0x2D: + case 0x2E: + case 0x2F: + case 0x30: + case 0x31: + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: + return static_cast(0x20 - 1 - current); + + case 0x38: // Negative integer (one-byte uint8_t follows) + { + // must be uint8_t ! + return static_cast(-1) - get_number(); + } + + case 0x39: // Negative integer -1-n (two-byte uint16_t follows) + { + return static_cast(-1) - get_number(); + } + + case 0x3A: // Negative integer -1-n (four-byte uint32_t follows) + { + return static_cast(-1) - get_number(); + } + + case 0x3B: // Negative integer -1-n (eight-byte uint64_t follows) + { + return static_cast(-1) - + static_cast(get_number()); + } + + // UTF-8 string (0x00..0x17 bytes follow) + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: + case 0x68: + case 0x69: + case 0x6A: + case 0x6B: + case 0x6C: + case 0x6D: + case 0x6E: + case 0x6F: + case 0x70: + case 0x71: + case 0x72: + case 0x73: + case 0x74: + case 0x75: + case 0x76: + case 0x77: + case 0x78: // UTF-8 string (one-byte uint8_t for n follows) + case 0x79: // UTF-8 string (two-byte uint16_t for n follow) + case 0x7A: // UTF-8 string (four-byte uint32_t for n follow) + case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow) + case 0x7F: // UTF-8 string (indefinite length) + { + return get_cbor_string(); + } + + // array (0x00..0x17 data items follow) + case 0x80: + case 0x81: + case 0x82: + case 0x83: + case 0x84: + case 0x85: + case 0x86: + case 0x87: + case 0x88: + case 0x89: + case 0x8A: + case 0x8B: + case 0x8C: + case 0x8D: + case 0x8E: + case 0x8F: + case 0x90: + case 0x91: + case 0x92: + case 0x93: + case 0x94: + case 0x95: + case 0x96: + case 0x97: + { + return get_cbor_array(current & 0x1F); + } + + case 0x98: // array (one-byte uint8_t for n follows) + { + return get_cbor_array(get_number()); + } + + case 0x99: // array (two-byte uint16_t for n follow) + { + return get_cbor_array(get_number()); + } + + case 0x9A: // array (four-byte uint32_t for n follow) + { + return get_cbor_array(get_number()); + } + + case 0x9B: // array (eight-byte uint64_t for n follow) + { + return get_cbor_array(get_number()); + } + + case 0x9F: // array (indefinite length) + { + BasicJsonType result = value_t::array; + while (get() != 0xFF) + { + result.push_back(parse_cbor_internal(false)); + } + return result; + } + + // map (0x00..0x17 pairs of data items follow) + case 0xA0: + case 0xA1: + case 0xA2: + case 0xA3: + case 0xA4: + case 0xA5: + case 0xA6: + case 0xA7: + case 0xA8: + case 0xA9: + case 0xAA: + case 0xAB: + case 0xAC: + case 0xAD: + case 0xAE: + case 0xAF: + case 0xB0: + case 0xB1: + case 0xB2: + case 0xB3: + case 0xB4: + case 0xB5: + case 0xB6: + case 0xB7: + { + return get_cbor_object(current & 0x1F); + } + + case 0xB8: // map (one-byte uint8_t for n follows) + { + return get_cbor_object(get_number()); + } + + case 0xB9: // map (two-byte uint16_t for n follow) + { + return get_cbor_object(get_number()); + } + + case 0xBA: // map (four-byte uint32_t for n follow) + { + return get_cbor_object(get_number()); + } + + case 0xBB: // map (eight-byte uint64_t for n follow) + { + return get_cbor_object(get_number()); + } + + case 0xBF: // map (indefinite length) + { + BasicJsonType result = value_t::object; + while (get() != 0xFF) + { + auto key = get_cbor_string(); + result[key] = parse_cbor_internal(); + } + return result; + } + + case 0xF4: // false + { + return false; + } + + case 0xF5: // true + { + return true; + } + + case 0xF6: // null + { + return value_t::null; + } + + case 0xF9: // Half-Precision Float (two-byte IEEE 754) + { + const int byte1 = get(); + check_eof(); + const int byte2 = get(); + check_eof(); + + // code from RFC 7049, Appendix D, Figure 3: + // As half-precision floating-point numbers were only added + // to IEEE 754 in 2008, today's programming platforms often + // still only have limited support for them. It is very + // easy to include at least decoding support for them even + // without such support. An example of a small decoder for + // half-precision floating-point numbers in the C language + // is shown in Fig. 3. + const int half = (byte1 << 8) + byte2; + const int exp = (half >> 10) & 0x1F; + const int mant = half & 0x3FF; + double val; + if (exp == 0) + { + val = std::ldexp(mant, -24); + } + else if (exp != 31) + { + val = std::ldexp(mant + 1024, exp - 25); + } + else + { + val = (mant == 0) ? std::numeric_limits::infinity() + : std::numeric_limits::quiet_NaN(); + } + return (half & 0x8000) != 0 ? -val : val; + } + + case 0xFA: // Single-Precision Float (four-byte IEEE 754) + { + return get_number(); + } + + case 0xFB: // Double-Precision Float (eight-byte IEEE 754) + { + return get_number(); + } + + default: // anything else (0xFF is handled inside the other types) + { + std::stringstream ss; + ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; + JSON_THROW(parse_error::create(112, chars_read, "error reading CBOR; last byte: 0x" + ss.str())); + } + } + } + + BasicJsonType parse_msgpack_internal() + { + switch (get()) + { + // EOF + case std::char_traits::eof(): + JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input")); + + // positive fixint + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + case 0x09: + case 0x0A: + case 0x0B: + case 0x0C: + case 0x0D: + case 0x0E: + case 0x0F: + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + case 0x1A: + case 0x1B: + case 0x1C: + case 0x1D: + case 0x1E: + case 0x1F: + case 0x20: + case 0x21: + case 0x22: + case 0x23: + case 0x24: + case 0x25: + case 0x26: + case 0x27: + case 0x28: + case 0x29: + case 0x2A: + case 0x2B: + case 0x2C: + case 0x2D: + case 0x2E: + case 0x2F: + case 0x30: + case 0x31: + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: + case 0x38: + case 0x39: + case 0x3A: + case 0x3B: + case 0x3C: + case 0x3D: + case 0x3E: + case 0x3F: + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + case 0x48: + case 0x49: + case 0x4A: + case 0x4B: + case 0x4C: + case 0x4D: + case 0x4E: + case 0x4F: + case 0x50: + case 0x51: + case 0x52: + case 0x53: + case 0x54: + case 0x55: + case 0x56: + case 0x57: + case 0x58: + case 0x59: + case 0x5A: + case 0x5B: + case 0x5C: + case 0x5D: + case 0x5E: + case 0x5F: + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: + case 0x68: + case 0x69: + case 0x6A: + case 0x6B: + case 0x6C: + case 0x6D: + case 0x6E: + case 0x6F: + case 0x70: + case 0x71: + case 0x72: + case 0x73: + case 0x74: + case 0x75: + case 0x76: + case 0x77: + case 0x78: + case 0x79: + case 0x7A: + case 0x7B: + case 0x7C: + case 0x7D: + case 0x7E: + case 0x7F: + return static_cast(current); + + // fixmap + case 0x80: + case 0x81: + case 0x82: + case 0x83: + case 0x84: + case 0x85: + case 0x86: + case 0x87: + case 0x88: + case 0x89: + case 0x8A: + case 0x8B: + case 0x8C: + case 0x8D: + case 0x8E: + case 0x8F: + { + return get_msgpack_object(current & 0x0F); + } + + // fixarray + case 0x90: + case 0x91: + case 0x92: + case 0x93: + case 0x94: + case 0x95: + case 0x96: + case 0x97: + case 0x98: + case 0x99: + case 0x9A: + case 0x9B: + case 0x9C: + case 0x9D: + case 0x9E: + case 0x9F: + { + return get_msgpack_array(current & 0x0F); + } + + // fixstr + case 0xA0: + case 0xA1: + case 0xA2: + case 0xA3: + case 0xA4: + case 0xA5: + case 0xA6: + case 0xA7: + case 0xA8: + case 0xA9: + case 0xAA: + case 0xAB: + case 0xAC: + case 0xAD: + case 0xAE: + case 0xAF: + case 0xB0: + case 0xB1: + case 0xB2: + case 0xB3: + case 0xB4: + case 0xB5: + case 0xB6: + case 0xB7: + case 0xB8: + case 0xB9: + case 0xBA: + case 0xBB: + case 0xBC: + case 0xBD: + case 0xBE: + case 0xBF: + return get_msgpack_string(); + + case 0xC0: // nil + return value_t::null; + + case 0xC2: // false + return false; + + case 0xC3: // true + return true; + + case 0xCA: // float 32 + return get_number(); + + case 0xCB: // float 64 + return get_number(); + + case 0xCC: // uint 8 + return get_number(); + + case 0xCD: // uint 16 + return get_number(); + + case 0xCE: // uint 32 + return get_number(); + + case 0xCF: // uint 64 + return get_number(); + + case 0xD0: // int 8 + return get_number(); + + case 0xD1: // int 16 + return get_number(); + + case 0xD2: // int 32 + return get_number(); + + case 0xD3: // int 64 + return get_number(); + + case 0xD9: // str 8 + case 0xDA: // str 16 + case 0xDB: // str 32 + return get_msgpack_string(); + + case 0xDC: // array 16 + { + return get_msgpack_array(get_number()); + } + + case 0xDD: // array 32 + { + return get_msgpack_array(get_number()); + } + + case 0xDE: // map 16 + { + return get_msgpack_object(get_number()); + } + + case 0xDF: // map 32 + { + return get_msgpack_object(get_number()); + } + + // positive fixint + case 0xE0: + case 0xE1: + case 0xE2: + case 0xE3: + case 0xE4: + case 0xE5: + case 0xE6: + case 0xE7: + case 0xE8: + case 0xE9: + case 0xEA: + case 0xEB: + case 0xEC: + case 0xED: + case 0xEE: + case 0xEF: + case 0xF0: + case 0xF1: + case 0xF2: + case 0xF3: + case 0xF4: + case 0xF5: + case 0xF6: + case 0xF7: + case 0xF8: + case 0xF9: + case 0xFA: + case 0xFB: + case 0xFC: + case 0xFD: + case 0xFE: + case 0xFF: + return static_cast(current); + + default: // anything else + { + std::stringstream ss; + ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; + JSON_THROW(parse_error::create(112, chars_read, + "error reading MessagePack; last byte: 0x" + ss.str())); + } + } + } + + /*! + @brief get next character from the input + + This function provides the interface to the used input adapter. It does + not throw in case the input reached EOF, but returns a -'ve valued + `std::char_traits::eof()` in that case. + + @return character read from the input + */ + int get() + { + ++chars_read; + return (current = ia->get_character()); + } + + /* + @brief read a number from the input + + @tparam NumberType the type of the number + + @return number of type @a NumberType + + @note This function needs to respect the system's endianess, because + bytes in CBOR and MessagePack are stored in network order (big + endian) and therefore need reordering on little endian systems. + + @throw parse_error.110 if input has less than `sizeof(NumberType)` bytes + */ + template NumberType get_number() + { + // step 1: read input into array with system's byte order + std::array vec; + for (std::size_t i = 0; i < sizeof(NumberType); ++i) + { + get(); + check_eof(); + + // reverse byte order prior to conversion if necessary + if (is_little_endian) + { + vec[sizeof(NumberType) - i - 1] = static_cast(current); + } + else + { + vec[i] = static_cast(current); // LCOV_EXCL_LINE + } + } + + // step 2: convert array into number of type T and return + NumberType result; + std::memcpy(&result, vec.data(), sizeof(NumberType)); + return result; + } + + /*! + @brief create a string by reading characters from the input + + @param[in] len number of bytes to read + + @note We can not reserve @a len bytes for the result, because @a len + may be too large. Usually, @ref check_eof() detects the end of + the input before we run out of string memory. + + @return string created by reading @a len bytes + + @throw parse_error.110 if input has less than @a len bytes + */ + template + std::string get_string(const NumberType len) + { + std::string result; + std::generate_n(std::back_inserter(result), len, [this]() + { + get(); + check_eof(); + return static_cast(current); + }); + return result; + } + + /*! + @brief reads a CBOR string + + This function first reads starting bytes to determine the expected + string length and then copies this number of bytes into a string. + Additionally, CBOR's strings with indefinite lengths are supported. + + @return string + + @throw parse_error.110 if input ended + @throw parse_error.113 if an unexpected byte is read + */ + std::string get_cbor_string() + { + check_eof(); + + switch (current) + { + // UTF-8 string (0x00..0x17 bytes follow) + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: + case 0x68: + case 0x69: + case 0x6A: + case 0x6B: + case 0x6C: + case 0x6D: + case 0x6E: + case 0x6F: + case 0x70: + case 0x71: + case 0x72: + case 0x73: + case 0x74: + case 0x75: + case 0x76: + case 0x77: + { + return get_string(current & 0x1F); + } + + case 0x78: // UTF-8 string (one-byte uint8_t for n follows) + { + return get_string(get_number()); + } + + case 0x79: // UTF-8 string (two-byte uint16_t for n follow) + { + return get_string(get_number()); + } + + case 0x7A: // UTF-8 string (four-byte uint32_t for n follow) + { + return get_string(get_number()); + } + + case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow) + { + return get_string(get_number()); + } + + case 0x7F: // UTF-8 string (indefinite length) + { + std::string result; + while (get() != 0xFF) + { + check_eof(); + result.push_back(static_cast(current)); + } + return result; + } + + default: + { + std::stringstream ss; + ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; + JSON_THROW(parse_error::create(113, chars_read, "expected a CBOR string; last byte: 0x" + ss.str())); + } + } + } + + template + BasicJsonType get_cbor_array(const NumberType len) + { + BasicJsonType result = value_t::array; + std::generate_n(std::back_inserter(*result.m_value.array), len, [this]() + { + return parse_cbor_internal(); + }); + return result; + } + + template + BasicJsonType get_cbor_object(const NumberType len) + { + BasicJsonType result = value_t::object; + std::generate_n(std::inserter(*result.m_value.object, + result.m_value.object->end()), + len, [this]() + { + get(); + auto key = get_cbor_string(); + auto val = parse_cbor_internal(); + return std::make_pair(std::move(key), std::move(val)); + }); + return result; + } + + /*! + @brief reads a MessagePack string + + This function first reads starting bytes to determine the expected + string length and then copies this number of bytes into a string. + + @return string + + @throw parse_error.110 if input ended + @throw parse_error.113 if an unexpected byte is read + */ + std::string get_msgpack_string() + { + check_eof(); + + switch (current) + { + // fixstr + case 0xA0: + case 0xA1: + case 0xA2: + case 0xA3: + case 0xA4: + case 0xA5: + case 0xA6: + case 0xA7: + case 0xA8: + case 0xA9: + case 0xAA: + case 0xAB: + case 0xAC: + case 0xAD: + case 0xAE: + case 0xAF: + case 0xB0: + case 0xB1: + case 0xB2: + case 0xB3: + case 0xB4: + case 0xB5: + case 0xB6: + case 0xB7: + case 0xB8: + case 0xB9: + case 0xBA: + case 0xBB: + case 0xBC: + case 0xBD: + case 0xBE: + case 0xBF: + { + return get_string(current & 0x1F); + } + + case 0xD9: // str 8 + { + return get_string(get_number()); + } + + case 0xDA: // str 16 + { + return get_string(get_number()); + } + + case 0xDB: // str 32 + { + return get_string(get_number()); + } + + default: + { + std::stringstream ss; + ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; + JSON_THROW(parse_error::create(113, chars_read, + "expected a MessagePack string; last byte: 0x" + ss.str())); + } + } + } + + template + BasicJsonType get_msgpack_array(const NumberType len) + { + BasicJsonType result = value_t::array; + std::generate_n(std::back_inserter(*result.m_value.array), len, [this]() + { + return parse_msgpack_internal(); + }); + return result; + } + + template + BasicJsonType get_msgpack_object(const NumberType len) + { + BasicJsonType result = value_t::object; + std::generate_n(std::inserter(*result.m_value.object, + result.m_value.object->end()), + len, [this]() + { + get(); + auto key = get_msgpack_string(); + auto val = parse_msgpack_internal(); + return std::make_pair(std::move(key), std::move(val)); + }); + return result; + } + + /*! + @brief check if input ended + @throw parse_error.110 if input ended + */ + void check_eof(const bool expect_eof = false) const + { + if (expect_eof) + { + if (JSON_UNLIKELY(current != std::char_traits::eof())) + { + JSON_THROW(parse_error::create(110, chars_read, "expected end of input")); + } + } + else + { + if (JSON_UNLIKELY(current == std::char_traits::eof())) + { + JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input")); + } + } + } + + private: + /// input adapter + input_adapter_t ia = nullptr; + + /// the current character + int current = std::char_traits::eof(); + + /// the number of characters read + std::size_t chars_read = 0; + + /// whether we can assume little endianess + const bool is_little_endian = little_endianess(); +}; +} +} + +#endif diff --git a/src/json.hpp b/src/json.hpp index 7d62e412..171377b7 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -66,6 +66,7 @@ SOFTWARE. #include "detail/iterators/iteration_proxy.hpp" #include "detail/iterators/json_reverse_iterator.hpp" #include "detail/parsing/output_adapters.hpp" +#include "detail/parsing/binary_reader.hpp" /*! @brief namespace for Niels Lohmann @@ -76,1068 +77,9 @@ namespace nlohmann { namespace detail { -////////////////////////////// -// binary reader and writer // -////////////////////////////// - -/*! -@brief deserialization of CBOR and MessagePack values -*/ -template -class binary_reader -{ - using number_integer_t = typename BasicJsonType::number_integer_t; - using number_unsigned_t = typename BasicJsonType::number_unsigned_t; - - public: - /*! - @brief create a binary reader - - @param[in] adapter input adapter to read from - */ - explicit binary_reader(input_adapter_t adapter) : ia(std::move(adapter)) - { - assert(ia); - } - - /*! - @brief create a JSON value from CBOR input - - @param[in] strict whether to expect the input to be consumed completed - @return JSON value created from CBOR input - - @throw parse_error.110 if input ended unexpectedly or the end of file was - not reached when @a strict was set to true - @throw parse_error.112 if unsupported byte was read - */ - BasicJsonType parse_cbor(const bool strict) - { - const auto res = parse_cbor_internal(); - if (strict) - { - get(); - check_eof(true); - } - return res; - } - - /*! - @brief create a JSON value from MessagePack input - - @param[in] strict whether to expect the input to be consumed completed - @return JSON value created from MessagePack input - - @throw parse_error.110 if input ended unexpectedly or the end of file was - not reached when @a strict was set to true - @throw parse_error.112 if unsupported byte was read - */ - BasicJsonType parse_msgpack(const bool strict) - { - const auto res = parse_msgpack_internal(); - if (strict) - { - get(); - check_eof(true); - } - return res; - } - - /*! - @brief determine system byte order - - @return true if and only if system's byte order is little endian - - @note from http://stackoverflow.com/a/1001328/266378 - */ - static constexpr bool little_endianess(int num = 1) noexcept - { - return (*reinterpret_cast(&num) == 1); - } - - private: - /*! - @param[in] get_char whether a new character should be retrieved from the - input (true, default) or whether the last read - character should be considered instead - */ - BasicJsonType parse_cbor_internal(const bool get_char = true) - { - switch (get_char ? get() : current) - { - // EOF - case std::char_traits::eof(): - JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input")); - - // Integer 0x00..0x17 (0..23) - case 0x00: - case 0x01: - case 0x02: - case 0x03: - case 0x04: - case 0x05: - case 0x06: - case 0x07: - case 0x08: - case 0x09: - case 0x0A: - case 0x0B: - case 0x0C: - case 0x0D: - case 0x0E: - case 0x0F: - case 0x10: - case 0x11: - case 0x12: - case 0x13: - case 0x14: - case 0x15: - case 0x16: - case 0x17: - return static_cast(current); - - case 0x18: // Unsigned integer (one-byte uint8_t follows) - return get_number(); - - case 0x19: // Unsigned integer (two-byte uint16_t follows) - return get_number(); - - case 0x1A: // Unsigned integer (four-byte uint32_t follows) - return get_number(); - - case 0x1B: // Unsigned integer (eight-byte uint64_t follows) - return get_number(); - - // Negative integer -1-0x00..-1-0x17 (-1..-24) - case 0x20: - case 0x21: - case 0x22: - case 0x23: - case 0x24: - case 0x25: - case 0x26: - case 0x27: - case 0x28: - case 0x29: - case 0x2A: - case 0x2B: - case 0x2C: - case 0x2D: - case 0x2E: - case 0x2F: - case 0x30: - case 0x31: - case 0x32: - case 0x33: - case 0x34: - case 0x35: - case 0x36: - case 0x37: - return static_cast(0x20 - 1 - current); - - case 0x38: // Negative integer (one-byte uint8_t follows) - { - // must be uint8_t ! - return static_cast(-1) - get_number(); - } - - case 0x39: // Negative integer -1-n (two-byte uint16_t follows) - { - return static_cast(-1) - get_number(); - } - - case 0x3A: // Negative integer -1-n (four-byte uint32_t follows) - { - return static_cast(-1) - get_number(); - } - - case 0x3B: // Negative integer -1-n (eight-byte uint64_t follows) - { - return static_cast(-1) - - static_cast(get_number()); - } - - // UTF-8 string (0x00..0x17 bytes follow) - case 0x60: - case 0x61: - case 0x62: - case 0x63: - case 0x64: - case 0x65: - case 0x66: - case 0x67: - case 0x68: - case 0x69: - case 0x6A: - case 0x6B: - case 0x6C: - case 0x6D: - case 0x6E: - case 0x6F: - case 0x70: - case 0x71: - case 0x72: - case 0x73: - case 0x74: - case 0x75: - case 0x76: - case 0x77: - case 0x78: // UTF-8 string (one-byte uint8_t for n follows) - case 0x79: // UTF-8 string (two-byte uint16_t for n follow) - case 0x7A: // UTF-8 string (four-byte uint32_t for n follow) - case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow) - case 0x7F: // UTF-8 string (indefinite length) - { - return get_cbor_string(); - } - - // array (0x00..0x17 data items follow) - case 0x80: - case 0x81: - case 0x82: - case 0x83: - case 0x84: - case 0x85: - case 0x86: - case 0x87: - case 0x88: - case 0x89: - case 0x8A: - case 0x8B: - case 0x8C: - case 0x8D: - case 0x8E: - case 0x8F: - case 0x90: - case 0x91: - case 0x92: - case 0x93: - case 0x94: - case 0x95: - case 0x96: - case 0x97: - { - return get_cbor_array(current & 0x1F); - } - - case 0x98: // array (one-byte uint8_t for n follows) - { - return get_cbor_array(get_number()); - } - - case 0x99: // array (two-byte uint16_t for n follow) - { - return get_cbor_array(get_number()); - } - - case 0x9A: // array (four-byte uint32_t for n follow) - { - return get_cbor_array(get_number()); - } - - case 0x9B: // array (eight-byte uint64_t for n follow) - { - return get_cbor_array(get_number()); - } - - case 0x9F: // array (indefinite length) - { - BasicJsonType result = value_t::array; - while (get() != 0xFF) - { - result.push_back(parse_cbor_internal(false)); - } - return result; - } - - // map (0x00..0x17 pairs of data items follow) - case 0xA0: - case 0xA1: - case 0xA2: - case 0xA3: - case 0xA4: - case 0xA5: - case 0xA6: - case 0xA7: - case 0xA8: - case 0xA9: - case 0xAA: - case 0xAB: - case 0xAC: - case 0xAD: - case 0xAE: - case 0xAF: - case 0xB0: - case 0xB1: - case 0xB2: - case 0xB3: - case 0xB4: - case 0xB5: - case 0xB6: - case 0xB7: - { - return get_cbor_object(current & 0x1F); - } - - case 0xB8: // map (one-byte uint8_t for n follows) - { - return get_cbor_object(get_number()); - } - - case 0xB9: // map (two-byte uint16_t for n follow) - { - return get_cbor_object(get_number()); - } - - case 0xBA: // map (four-byte uint32_t for n follow) - { - return get_cbor_object(get_number()); - } - - case 0xBB: // map (eight-byte uint64_t for n follow) - { - return get_cbor_object(get_number()); - } - - case 0xBF: // map (indefinite length) - { - BasicJsonType result = value_t::object; - while (get() != 0xFF) - { - auto key = get_cbor_string(); - result[key] = parse_cbor_internal(); - } - return result; - } - - case 0xF4: // false - { - return false; - } - - case 0xF5: // true - { - return true; - } - - case 0xF6: // null - { - return value_t::null; - } - - case 0xF9: // Half-Precision Float (two-byte IEEE 754) - { - const int byte1 = get(); - check_eof(); - const int byte2 = get(); - check_eof(); - - // code from RFC 7049, Appendix D, Figure 3: - // As half-precision floating-point numbers were only added - // to IEEE 754 in 2008, today's programming platforms often - // still only have limited support for them. It is very - // easy to include at least decoding support for them even - // without such support. An example of a small decoder for - // half-precision floating-point numbers in the C language - // is shown in Fig. 3. - const int half = (byte1 << 8) + byte2; - const int exp = (half >> 10) & 0x1F; - const int mant = half & 0x3FF; - double val; - if (exp == 0) - { - val = std::ldexp(mant, -24); - } - else if (exp != 31) - { - val = std::ldexp(mant + 1024, exp - 25); - } - else - { - val = (mant == 0) ? std::numeric_limits::infinity() - : std::numeric_limits::quiet_NaN(); - } - return (half & 0x8000) != 0 ? -val : val; - } - - case 0xFA: // Single-Precision Float (four-byte IEEE 754) - { - return get_number(); - } - - case 0xFB: // Double-Precision Float (eight-byte IEEE 754) - { - return get_number(); - } - - default: // anything else (0xFF is handled inside the other types) - { - std::stringstream ss; - ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; - JSON_THROW(parse_error::create(112, chars_read, "error reading CBOR; last byte: 0x" + ss.str())); - } - } - } - - BasicJsonType parse_msgpack_internal() - { - switch (get()) - { - // EOF - case std::char_traits::eof(): - JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input")); - - // positive fixint - case 0x00: - case 0x01: - case 0x02: - case 0x03: - case 0x04: - case 0x05: - case 0x06: - case 0x07: - case 0x08: - case 0x09: - case 0x0A: - case 0x0B: - case 0x0C: - case 0x0D: - case 0x0E: - case 0x0F: - case 0x10: - case 0x11: - case 0x12: - case 0x13: - case 0x14: - case 0x15: - case 0x16: - case 0x17: - case 0x18: - case 0x19: - case 0x1A: - case 0x1B: - case 0x1C: - case 0x1D: - case 0x1E: - case 0x1F: - case 0x20: - case 0x21: - case 0x22: - case 0x23: - case 0x24: - case 0x25: - case 0x26: - case 0x27: - case 0x28: - case 0x29: - case 0x2A: - case 0x2B: - case 0x2C: - case 0x2D: - case 0x2E: - case 0x2F: - case 0x30: - case 0x31: - case 0x32: - case 0x33: - case 0x34: - case 0x35: - case 0x36: - case 0x37: - case 0x38: - case 0x39: - case 0x3A: - case 0x3B: - case 0x3C: - case 0x3D: - case 0x3E: - case 0x3F: - case 0x40: - case 0x41: - case 0x42: - case 0x43: - case 0x44: - case 0x45: - case 0x46: - case 0x47: - case 0x48: - case 0x49: - case 0x4A: - case 0x4B: - case 0x4C: - case 0x4D: - case 0x4E: - case 0x4F: - case 0x50: - case 0x51: - case 0x52: - case 0x53: - case 0x54: - case 0x55: - case 0x56: - case 0x57: - case 0x58: - case 0x59: - case 0x5A: - case 0x5B: - case 0x5C: - case 0x5D: - case 0x5E: - case 0x5F: - case 0x60: - case 0x61: - case 0x62: - case 0x63: - case 0x64: - case 0x65: - case 0x66: - case 0x67: - case 0x68: - case 0x69: - case 0x6A: - case 0x6B: - case 0x6C: - case 0x6D: - case 0x6E: - case 0x6F: - case 0x70: - case 0x71: - case 0x72: - case 0x73: - case 0x74: - case 0x75: - case 0x76: - case 0x77: - case 0x78: - case 0x79: - case 0x7A: - case 0x7B: - case 0x7C: - case 0x7D: - case 0x7E: - case 0x7F: - return static_cast(current); - - // fixmap - case 0x80: - case 0x81: - case 0x82: - case 0x83: - case 0x84: - case 0x85: - case 0x86: - case 0x87: - case 0x88: - case 0x89: - case 0x8A: - case 0x8B: - case 0x8C: - case 0x8D: - case 0x8E: - case 0x8F: - { - return get_msgpack_object(current & 0x0F); - } - - // fixarray - case 0x90: - case 0x91: - case 0x92: - case 0x93: - case 0x94: - case 0x95: - case 0x96: - case 0x97: - case 0x98: - case 0x99: - case 0x9A: - case 0x9B: - case 0x9C: - case 0x9D: - case 0x9E: - case 0x9F: - { - return get_msgpack_array(current & 0x0F); - } - - // fixstr - case 0xA0: - case 0xA1: - case 0xA2: - case 0xA3: - case 0xA4: - case 0xA5: - case 0xA6: - case 0xA7: - case 0xA8: - case 0xA9: - case 0xAA: - case 0xAB: - case 0xAC: - case 0xAD: - case 0xAE: - case 0xAF: - case 0xB0: - case 0xB1: - case 0xB2: - case 0xB3: - case 0xB4: - case 0xB5: - case 0xB6: - case 0xB7: - case 0xB8: - case 0xB9: - case 0xBA: - case 0xBB: - case 0xBC: - case 0xBD: - case 0xBE: - case 0xBF: - return get_msgpack_string(); - - case 0xC0: // nil - return value_t::null; - - case 0xC2: // false - return false; - - case 0xC3: // true - return true; - - case 0xCA: // float 32 - return get_number(); - - case 0xCB: // float 64 - return get_number(); - - case 0xCC: // uint 8 - return get_number(); - - case 0xCD: // uint 16 - return get_number(); - - case 0xCE: // uint 32 - return get_number(); - - case 0xCF: // uint 64 - return get_number(); - - case 0xD0: // int 8 - return get_number(); - - case 0xD1: // int 16 - return get_number(); - - case 0xD2: // int 32 - return get_number(); - - case 0xD3: // int 64 - return get_number(); - - case 0xD9: // str 8 - case 0xDA: // str 16 - case 0xDB: // str 32 - return get_msgpack_string(); - - case 0xDC: // array 16 - { - return get_msgpack_array(get_number()); - } - - case 0xDD: // array 32 - { - return get_msgpack_array(get_number()); - } - - case 0xDE: // map 16 - { - return get_msgpack_object(get_number()); - } - - case 0xDF: // map 32 - { - return get_msgpack_object(get_number()); - } - - // positive fixint - case 0xE0: - case 0xE1: - case 0xE2: - case 0xE3: - case 0xE4: - case 0xE5: - case 0xE6: - case 0xE7: - case 0xE8: - case 0xE9: - case 0xEA: - case 0xEB: - case 0xEC: - case 0xED: - case 0xEE: - case 0xEF: - case 0xF0: - case 0xF1: - case 0xF2: - case 0xF3: - case 0xF4: - case 0xF5: - case 0xF6: - case 0xF7: - case 0xF8: - case 0xF9: - case 0xFA: - case 0xFB: - case 0xFC: - case 0xFD: - case 0xFE: - case 0xFF: - return static_cast(current); - - default: // anything else - { - std::stringstream ss; - ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; - JSON_THROW(parse_error::create(112, chars_read, - "error reading MessagePack; last byte: 0x" + ss.str())); - } - } - } - - /*! - @brief get next character from the input - - This function provides the interface to the used input adapter. It does - not throw in case the input reached EOF, but returns a -'ve valued - `std::char_traits::eof()` in that case. - - @return character read from the input - */ - int get() - { - ++chars_read; - return (current = ia->get_character()); - } - - /* - @brief read a number from the input - - @tparam NumberType the type of the number - - @return number of type @a NumberType - - @note This function needs to respect the system's endianess, because - bytes in CBOR and MessagePack are stored in network order (big - endian) and therefore need reordering on little endian systems. - - @throw parse_error.110 if input has less than `sizeof(NumberType)` bytes - */ - template NumberType get_number() - { - // step 1: read input into array with system's byte order - std::array vec; - for (std::size_t i = 0; i < sizeof(NumberType); ++i) - { - get(); - check_eof(); - - // reverse byte order prior to conversion if necessary - if (is_little_endian) - { - vec[sizeof(NumberType) - i - 1] = static_cast(current); - } - else - { - vec[i] = static_cast(current); // LCOV_EXCL_LINE - } - } - - // step 2: convert array into number of type T and return - NumberType result; - std::memcpy(&result, vec.data(), sizeof(NumberType)); - return result; - } - - /*! - @brief create a string by reading characters from the input - - @param[in] len number of bytes to read - - @note We can not reserve @a len bytes for the result, because @a len - may be too large. Usually, @ref check_eof() detects the end of - the input before we run out of string memory. - - @return string created by reading @a len bytes - - @throw parse_error.110 if input has less than @a len bytes - */ - template - std::string get_string(const NumberType len) - { - std::string result; - std::generate_n(std::back_inserter(result), len, [this]() - { - get(); - check_eof(); - return static_cast(current); - }); - return result; - } - - /*! - @brief reads a CBOR string - - This function first reads starting bytes to determine the expected - string length and then copies this number of bytes into a string. - Additionally, CBOR's strings with indefinite lengths are supported. - - @return string - - @throw parse_error.110 if input ended - @throw parse_error.113 if an unexpected byte is read - */ - std::string get_cbor_string() - { - check_eof(); - - switch (current) - { - // UTF-8 string (0x00..0x17 bytes follow) - case 0x60: - case 0x61: - case 0x62: - case 0x63: - case 0x64: - case 0x65: - case 0x66: - case 0x67: - case 0x68: - case 0x69: - case 0x6A: - case 0x6B: - case 0x6C: - case 0x6D: - case 0x6E: - case 0x6F: - case 0x70: - case 0x71: - case 0x72: - case 0x73: - case 0x74: - case 0x75: - case 0x76: - case 0x77: - { - return get_string(current & 0x1F); - } - - case 0x78: // UTF-8 string (one-byte uint8_t for n follows) - { - return get_string(get_number()); - } - - case 0x79: // UTF-8 string (two-byte uint16_t for n follow) - { - return get_string(get_number()); - } - - case 0x7A: // UTF-8 string (four-byte uint32_t for n follow) - { - return get_string(get_number()); - } - - case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow) - { - return get_string(get_number()); - } - - case 0x7F: // UTF-8 string (indefinite length) - { - std::string result; - while (get() != 0xFF) - { - check_eof(); - result.push_back(static_cast(current)); - } - return result; - } - - default: - { - std::stringstream ss; - ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; - JSON_THROW(parse_error::create(113, chars_read, "expected a CBOR string; last byte: 0x" + ss.str())); - } - } - } - - template - BasicJsonType get_cbor_array(const NumberType len) - { - BasicJsonType result = value_t::array; - std::generate_n(std::back_inserter(*result.m_value.array), len, [this]() - { - return parse_cbor_internal(); - }); - return result; - } - - template - BasicJsonType get_cbor_object(const NumberType len) - { - BasicJsonType result = value_t::object; - std::generate_n(std::inserter(*result.m_value.object, - result.m_value.object->end()), - len, [this]() - { - get(); - auto key = get_cbor_string(); - auto val = parse_cbor_internal(); - return std::make_pair(std::move(key), std::move(val)); - }); - return result; - } - - /*! - @brief reads a MessagePack string - - This function first reads starting bytes to determine the expected - string length and then copies this number of bytes into a string. - - @return string - - @throw parse_error.110 if input ended - @throw parse_error.113 if an unexpected byte is read - */ - std::string get_msgpack_string() - { - check_eof(); - - switch (current) - { - // fixstr - case 0xA0: - case 0xA1: - case 0xA2: - case 0xA3: - case 0xA4: - case 0xA5: - case 0xA6: - case 0xA7: - case 0xA8: - case 0xA9: - case 0xAA: - case 0xAB: - case 0xAC: - case 0xAD: - case 0xAE: - case 0xAF: - case 0xB0: - case 0xB1: - case 0xB2: - case 0xB3: - case 0xB4: - case 0xB5: - case 0xB6: - case 0xB7: - case 0xB8: - case 0xB9: - case 0xBA: - case 0xBB: - case 0xBC: - case 0xBD: - case 0xBE: - case 0xBF: - { - return get_string(current & 0x1F); - } - - case 0xD9: // str 8 - { - return get_string(get_number()); - } - - case 0xDA: // str 16 - { - return get_string(get_number()); - } - - case 0xDB: // str 32 - { - return get_string(get_number()); - } - - default: - { - std::stringstream ss; - ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; - JSON_THROW(parse_error::create(113, chars_read, - "expected a MessagePack string; last byte: 0x" + ss.str())); - } - } - } - - template - BasicJsonType get_msgpack_array(const NumberType len) - { - BasicJsonType result = value_t::array; - std::generate_n(std::back_inserter(*result.m_value.array), len, [this]() - { - return parse_msgpack_internal(); - }); - return result; - } - - template - BasicJsonType get_msgpack_object(const NumberType len) - { - BasicJsonType result = value_t::object; - std::generate_n(std::inserter(*result.m_value.object, - result.m_value.object->end()), - len, [this]() - { - get(); - auto key = get_msgpack_string(); - auto val = parse_msgpack_internal(); - return std::make_pair(std::move(key), std::move(val)); - }); - return result; - } - - /*! - @brief check if input ended - @throw parse_error.110 if input ended - */ - void check_eof(const bool expect_eof = false) const - { - if (expect_eof) - { - if (JSON_UNLIKELY(current != std::char_traits::eof())) - { - JSON_THROW(parse_error::create(110, chars_read, "expected end of input")); - } - } - else - { - if (JSON_UNLIKELY(current == std::char_traits::eof())) - { - JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input")); - } - } - } - - private: - /// input adapter - input_adapter_t ia = nullptr; - - /// the current character - int current = std::char_traits::eof(); - - /// the number of characters read - std::size_t chars_read = 0; - - /// whether we can assume little endianess - const bool is_little_endian = little_endianess(); -}; +/////////////////// +// binary writer // +/////////////////// /*! @brief serialization to CBOR and MessagePack values From c117515e3141d6708dc7a4daec9cbfe2d61be179 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20DELRIEU?= Date: Mon, 14 Aug 2017 17:55:06 +0200 Subject: [PATCH 48/59] add detail/parsing/binary_writer.hpp --- Makefile | 3 +- src/detail/parsing/binary_writer.hpp | 558 +++++++++++++++++++++++++++ src/json.hpp | 540 +------------------------- 3 files changed, 561 insertions(+), 540 deletions(-) create mode 100644 src/detail/parsing/binary_writer.hpp diff --git a/Makefile b/Makefile index 6fa61613..928f37d8 100644 --- a/Makefile +++ b/Makefile @@ -19,7 +19,8 @@ SRCS = ${SRCDIR}/json.hpp \ ${SRCDIR}/detail/iterators/iteration_proxy.hpp \ ${SRCDIR}/detail/iterators/json_reverse_iterator.hpp \ ${SRCDIR}/detail/parsing/output_adapters.hpp \ - ${SRCDIR}/detail/parsing/binary_reader.hpp + ${SRCDIR}/detail/parsing/binary_reader.hpp \ + ${SRCDIR}/detail/parsing/binary_writer.hpp # main target all: diff --git a/src/detail/parsing/binary_writer.hpp b/src/detail/parsing/binary_writer.hpp new file mode 100644 index 00000000..25badd89 --- /dev/null +++ b/src/detail/parsing/binary_writer.hpp @@ -0,0 +1,558 @@ +#ifndef NLOHMANN_JSON_DETAIL_PARSING_BINARY_WRITER_HPP +#define NLOHMANN_JSON_DETAIL_PARSING_BINARY_WRITER_HPP + +#include +#include +#include +#include +#include + +#include "detail/parsing/binary_reader.hpp" +#include "detail/parsing/output_adapters.hpp" + +namespace nlohmann +{ +namespace detail +{ +/////////////////// +// binary writer // +/////////////////// + +/*! +@brief serialization to CBOR and MessagePack values +*/ +template +class binary_writer +{ + public: + /*! + @brief create a binary writer + + @param[in] adapter output adapter to write to + */ + explicit binary_writer(output_adapter_t adapter) : oa(adapter) + { + assert(oa); + } + + /*! + @brief[in] j JSON value to serialize + */ + void write_cbor(const BasicJsonType& j) + { + switch (j.type()) + { + case value_t::null: + { + oa->write_character(static_cast(0xF6)); + break; + } + + case value_t::boolean: + { + oa->write_character(j.m_value.boolean + ? static_cast(0xF5) + : static_cast(0xF4)); + break; + } + + case value_t::number_integer: + { + if (j.m_value.number_integer >= 0) + { + // CBOR does not differentiate between positive signed + // integers and unsigned integers. Therefore, we used the + // code from the value_t::number_unsigned case here. + if (j.m_value.number_integer <= 0x17) + { + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_integer <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0x18)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_integer <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0x19)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_integer <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0x1A)); + write_number(static_cast(j.m_value.number_integer)); + } + else + { + oa->write_character(static_cast(0x1B)); + write_number(static_cast(j.m_value.number_integer)); + } + } + else + { + // The conversions below encode the sign in the first + // byte, and the value is converted to a positive number. + const auto positive_number = -1 - j.m_value.number_integer; + if (j.m_value.number_integer >= -24) + { + write_number(static_cast(0x20 + positive_number)); + } + else if (positive_number <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0x38)); + write_number(static_cast(positive_number)); + } + else if (positive_number <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0x39)); + write_number(static_cast(positive_number)); + } + else if (positive_number <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0x3A)); + write_number(static_cast(positive_number)); + } + else + { + oa->write_character(static_cast(0x3B)); + write_number(static_cast(positive_number)); + } + } + break; + } + + case value_t::number_unsigned: + { + if (j.m_value.number_unsigned <= 0x17) + { + write_number(static_cast(j.m_value.number_unsigned)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0x18)); + write_number(static_cast(j.m_value.number_unsigned)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0x19)); + write_number(static_cast(j.m_value.number_unsigned)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0x1A)); + write_number(static_cast(j.m_value.number_unsigned)); + } + else + { + oa->write_character(static_cast(0x1B)); + write_number(static_cast(j.m_value.number_unsigned)); + } + break; + } + + case value_t::number_float: // Double-Precision Float + { + oa->write_character(static_cast(0xFB)); + write_number(j.m_value.number_float); + break; + } + + case value_t::string: + { + // step 1: write control byte and the string length + const auto N = j.m_value.string->size(); + if (N <= 0x17) + { + write_number(static_cast(0x60 + N)); + } + else if (N <= 0xFF) + { + oa->write_character(static_cast(0x78)); + write_number(static_cast(N)); + } + else if (N <= 0xFFFF) + { + oa->write_character(static_cast(0x79)); + write_number(static_cast(N)); + } + else if (N <= 0xFFFFFFFF) + { + oa->write_character(static_cast(0x7A)); + write_number(static_cast(N)); + } + // LCOV_EXCL_START + else if (N <= 0xFFFFFFFFFFFFFFFF) + { + oa->write_character(static_cast(0x7B)); + write_number(static_cast(N)); + } + // LCOV_EXCL_STOP + + // step 2: write the string + oa->write_characters( + reinterpret_cast(j.m_value.string->c_str()), + j.m_value.string->size()); + break; + } + + case value_t::array: + { + // step 1: write control byte and the array size + const auto N = j.m_value.array->size(); + if (N <= 0x17) + { + write_number(static_cast(0x80 + N)); + } + else if (N <= 0xFF) + { + oa->write_character(static_cast(0x98)); + write_number(static_cast(N)); + } + else if (N <= 0xFFFF) + { + oa->write_character(static_cast(0x99)); + write_number(static_cast(N)); + } + else if (N <= 0xFFFFFFFF) + { + oa->write_character(static_cast(0x9A)); + write_number(static_cast(N)); + } + // LCOV_EXCL_START + else if (N <= 0xFFFFFFFFFFFFFFFF) + { + oa->write_character(static_cast(0x9B)); + write_number(static_cast(N)); + } + // LCOV_EXCL_STOP + + // step 2: write each element + for (const auto& el : *j.m_value.array) + { + write_cbor(el); + } + break; + } + + case value_t::object: + { + // step 1: write control byte and the object size + const auto N = j.m_value.object->size(); + if (N <= 0x17) + { + write_number(static_cast(0xA0 + N)); + } + else if (N <= 0xFF) + { + oa->write_character(static_cast(0xB8)); + write_number(static_cast(N)); + } + else if (N <= 0xFFFF) + { + oa->write_character(static_cast(0xB9)); + write_number(static_cast(N)); + } + else if (N <= 0xFFFFFFFF) + { + oa->write_character(static_cast(0xBA)); + write_number(static_cast(N)); + } + // LCOV_EXCL_START + else if (N <= 0xFFFFFFFFFFFFFFFF) + { + oa->write_character(static_cast(0xBB)); + write_number(static_cast(N)); + } + // LCOV_EXCL_STOP + + // step 2: write each element + for (const auto& el : *j.m_value.object) + { + write_cbor(el.first); + write_cbor(el.second); + } + break; + } + + default: + break; + } + } + + /*! + @brief[in] j JSON value to serialize + */ + void write_msgpack(const BasicJsonType& j) + { + switch (j.type()) + { + case value_t::null: // nil + { + oa->write_character(static_cast(0xC0)); + break; + } + + case value_t::boolean: // true and false + { + oa->write_character(j.m_value.boolean + ? static_cast(0xC3) + : static_cast(0xC2)); + break; + } + + case value_t::number_integer: + { + if (j.m_value.number_integer >= 0) + { + // MessagePack does not differentiate between positive + // signed integers and unsigned integers. Therefore, we used + // the code from the value_t::number_unsigned case here. + if (j.m_value.number_unsigned < 128) + { + // positive fixnum + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 8 + oa->write_character(static_cast(0xCC)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 16 + oa->write_character(static_cast(0xCD)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 32 + oa->write_character(static_cast(0xCE)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 64 + oa->write_character(static_cast(0xCF)); + write_number(static_cast(j.m_value.number_integer)); + } + } + else + { + if (j.m_value.number_integer >= -32) + { + // negative fixnum + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_integer >= (std::numeric_limits::min)() and + j.m_value.number_integer <= (std::numeric_limits::max)()) + { + // int 8 + oa->write_character(static_cast(0xD0)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_integer >= (std::numeric_limits::min)() and + j.m_value.number_integer <= (std::numeric_limits::max)()) + { + // int 16 + oa->write_character(static_cast(0xD1)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_integer >= (std::numeric_limits::min)() and + j.m_value.number_integer <= (std::numeric_limits::max)()) + { + // int 32 + oa->write_character(static_cast(0xD2)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_integer >= (std::numeric_limits::min)() and + j.m_value.number_integer <= (std::numeric_limits::max)()) + { + // int 64 + oa->write_character(static_cast(0xD3)); + write_number(static_cast(j.m_value.number_integer)); + } + } + break; + } + + case value_t::number_unsigned: + { + if (j.m_value.number_unsigned < 128) + { + // positive fixnum + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 8 + oa->write_character(static_cast(0xCC)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 16 + oa->write_character(static_cast(0xCD)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 32 + oa->write_character(static_cast(0xCE)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 64 + oa->write_character(static_cast(0xCF)); + write_number(static_cast(j.m_value.number_integer)); + } + break; + } + + case value_t::number_float: // float 64 + { + oa->write_character(static_cast(0xCB)); + write_number(j.m_value.number_float); + break; + } + + case value_t::string: + { + // step 1: write control byte and the string length + const auto N = j.m_value.string->size(); + if (N <= 31) + { + // fixstr + write_number(static_cast(0xA0 | N)); + } + else if (N <= 255) + { + // str 8 + oa->write_character(static_cast(0xD9)); + write_number(static_cast(N)); + } + else if (N <= 65535) + { + // str 16 + oa->write_character(static_cast(0xDA)); + write_number(static_cast(N)); + } + else if (N <= 4294967295) + { + // str 32 + oa->write_character(static_cast(0xDB)); + write_number(static_cast(N)); + } + + // step 2: write the string + oa->write_characters( + reinterpret_cast(j.m_value.string->c_str()), + j.m_value.string->size()); + break; + } + + case value_t::array: + { + // step 1: write control byte and the array size + const auto N = j.m_value.array->size(); + if (N <= 15) + { + // fixarray + write_number(static_cast(0x90 | N)); + } + else if (N <= 0xFFFF) + { + // array 16 + oa->write_character(static_cast(0xDC)); + write_number(static_cast(N)); + } + else if (N <= 0xFFFFFFFF) + { + // array 32 + oa->write_character(static_cast(0xDD)); + write_number(static_cast(N)); + } + + // step 2: write each element + for (const auto& el : *j.m_value.array) + { + write_msgpack(el); + } + break; + } + + case value_t::object: + { + // step 1: write control byte and the object size + const auto N = j.m_value.object->size(); + if (N <= 15) + { + // fixmap + write_number(static_cast(0x80 | (N & 0xF))); + } + else if (N <= 65535) + { + // map 16 + oa->write_character(static_cast(0xDE)); + write_number(static_cast(N)); + } + else if (N <= 4294967295) + { + // map 32 + oa->write_character(static_cast(0xDF)); + write_number(static_cast(N)); + } + + // step 2: write each element + for (const auto& el : *j.m_value.object) + { + write_msgpack(el.first); + write_msgpack(el.second); + } + break; + } + + default: + break; + } + } + + private: + /* + @brief write a number to output input + + @param[in] n number of type @a NumberType + @tparam NumberType the type of the number + + @note This function needs to respect the system's endianess, because bytes + in CBOR and MessagePack are stored in network order (big endian) and + therefore need reordering on little endian systems. + */ + template void write_number(NumberType n) + { + // step 1: write number to array of length NumberType + std::array vec; + std::memcpy(vec.data(), &n, sizeof(NumberType)); + + // step 2: write array to output (with possible reordering) + if (is_little_endian) + { + // reverse byte order prior to conversion if necessary + std::reverse(vec.begin(), vec.end()); + } + + oa->write_characters(vec.data(), sizeof(NumberType)); + } + + private: + /// whether we can assume little endianess + const bool is_little_endian = binary_reader::little_endianess(); + + /// the output + output_adapter_t oa = nullptr; +}; +} +} + +#endif diff --git a/src/json.hpp b/src/json.hpp index 171377b7..ff1af030 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -67,6 +67,7 @@ SOFTWARE. #include "detail/iterators/json_reverse_iterator.hpp" #include "detail/parsing/output_adapters.hpp" #include "detail/parsing/binary_reader.hpp" +#include "detail/parsing/binary_writer.hpp" /*! @brief namespace for Niels Lohmann @@ -77,545 +78,6 @@ namespace nlohmann { namespace detail { -/////////////////// -// binary writer // -/////////////////// - -/*! -@brief serialization to CBOR and MessagePack values -*/ -template -class binary_writer -{ - public: - /*! - @brief create a binary writer - - @param[in] adapter output adapter to write to - */ - explicit binary_writer(output_adapter_t adapter) : oa(adapter) - { - assert(oa); - } - - /*! - @brief[in] j JSON value to serialize - */ - void write_cbor(const BasicJsonType& j) - { - switch (j.type()) - { - case value_t::null: - { - oa->write_character(static_cast(0xF6)); - break; - } - - case value_t::boolean: - { - oa->write_character(j.m_value.boolean - ? static_cast(0xF5) - : static_cast(0xF4)); - break; - } - - case value_t::number_integer: - { - if (j.m_value.number_integer >= 0) - { - // CBOR does not differentiate between positive signed - // integers and unsigned integers. Therefore, we used the - // code from the value_t::number_unsigned case here. - if (j.m_value.number_integer <= 0x17) - { - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_integer <= (std::numeric_limits::max)()) - { - oa->write_character(static_cast(0x18)); - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_integer <= (std::numeric_limits::max)()) - { - oa->write_character(static_cast(0x19)); - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_integer <= (std::numeric_limits::max)()) - { - oa->write_character(static_cast(0x1A)); - write_number(static_cast(j.m_value.number_integer)); - } - else - { - oa->write_character(static_cast(0x1B)); - write_number(static_cast(j.m_value.number_integer)); - } - } - else - { - // The conversions below encode the sign in the first - // byte, and the value is converted to a positive number. - const auto positive_number = -1 - j.m_value.number_integer; - if (j.m_value.number_integer >= -24) - { - write_number(static_cast(0x20 + positive_number)); - } - else if (positive_number <= (std::numeric_limits::max)()) - { - oa->write_character(static_cast(0x38)); - write_number(static_cast(positive_number)); - } - else if (positive_number <= (std::numeric_limits::max)()) - { - oa->write_character(static_cast(0x39)); - write_number(static_cast(positive_number)); - } - else if (positive_number <= (std::numeric_limits::max)()) - { - oa->write_character(static_cast(0x3A)); - write_number(static_cast(positive_number)); - } - else - { - oa->write_character(static_cast(0x3B)); - write_number(static_cast(positive_number)); - } - } - break; - } - - case value_t::number_unsigned: - { - if (j.m_value.number_unsigned <= 0x17) - { - write_number(static_cast(j.m_value.number_unsigned)); - } - else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) - { - oa->write_character(static_cast(0x18)); - write_number(static_cast(j.m_value.number_unsigned)); - } - else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) - { - oa->write_character(static_cast(0x19)); - write_number(static_cast(j.m_value.number_unsigned)); - } - else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) - { - oa->write_character(static_cast(0x1A)); - write_number(static_cast(j.m_value.number_unsigned)); - } - else - { - oa->write_character(static_cast(0x1B)); - write_number(static_cast(j.m_value.number_unsigned)); - } - break; - } - - case value_t::number_float: // Double-Precision Float - { - oa->write_character(static_cast(0xFB)); - write_number(j.m_value.number_float); - break; - } - - case value_t::string: - { - // step 1: write control byte and the string length - const auto N = j.m_value.string->size(); - if (N <= 0x17) - { - write_number(static_cast(0x60 + N)); - } - else if (N <= 0xFF) - { - oa->write_character(static_cast(0x78)); - write_number(static_cast(N)); - } - else if (N <= 0xFFFF) - { - oa->write_character(static_cast(0x79)); - write_number(static_cast(N)); - } - else if (N <= 0xFFFFFFFF) - { - oa->write_character(static_cast(0x7A)); - write_number(static_cast(N)); - } - // LCOV_EXCL_START - else if (N <= 0xFFFFFFFFFFFFFFFF) - { - oa->write_character(static_cast(0x7B)); - write_number(static_cast(N)); - } - // LCOV_EXCL_STOP - - // step 2: write the string - oa->write_characters( - reinterpret_cast(j.m_value.string->c_str()), - j.m_value.string->size()); - break; - } - - case value_t::array: - { - // step 1: write control byte and the array size - const auto N = j.m_value.array->size(); - if (N <= 0x17) - { - write_number(static_cast(0x80 + N)); - } - else if (N <= 0xFF) - { - oa->write_character(static_cast(0x98)); - write_number(static_cast(N)); - } - else if (N <= 0xFFFF) - { - oa->write_character(static_cast(0x99)); - write_number(static_cast(N)); - } - else if (N <= 0xFFFFFFFF) - { - oa->write_character(static_cast(0x9A)); - write_number(static_cast(N)); - } - // LCOV_EXCL_START - else if (N <= 0xFFFFFFFFFFFFFFFF) - { - oa->write_character(static_cast(0x9B)); - write_number(static_cast(N)); - } - // LCOV_EXCL_STOP - - // step 2: write each element - for (const auto& el : *j.m_value.array) - { - write_cbor(el); - } - break; - } - - case value_t::object: - { - // step 1: write control byte and the object size - const auto N = j.m_value.object->size(); - if (N <= 0x17) - { - write_number(static_cast(0xA0 + N)); - } - else if (N <= 0xFF) - { - oa->write_character(static_cast(0xB8)); - write_number(static_cast(N)); - } - else if (N <= 0xFFFF) - { - oa->write_character(static_cast(0xB9)); - write_number(static_cast(N)); - } - else if (N <= 0xFFFFFFFF) - { - oa->write_character(static_cast(0xBA)); - write_number(static_cast(N)); - } - // LCOV_EXCL_START - else if (N <= 0xFFFFFFFFFFFFFFFF) - { - oa->write_character(static_cast(0xBB)); - write_number(static_cast(N)); - } - // LCOV_EXCL_STOP - - // step 2: write each element - for (const auto& el : *j.m_value.object) - { - write_cbor(el.first); - write_cbor(el.second); - } - break; - } - - default: - break; - } - } - - /*! - @brief[in] j JSON value to serialize - */ - void write_msgpack(const BasicJsonType& j) - { - switch (j.type()) - { - case value_t::null: // nil - { - oa->write_character(static_cast(0xC0)); - break; - } - - case value_t::boolean: // true and false - { - oa->write_character(j.m_value.boolean - ? static_cast(0xC3) - : static_cast(0xC2)); - break; - } - - case value_t::number_integer: - { - if (j.m_value.number_integer >= 0) - { - // MessagePack does not differentiate between positive - // signed integers and unsigned integers. Therefore, we used - // the code from the value_t::number_unsigned case here. - if (j.m_value.number_unsigned < 128) - { - // positive fixnum - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) - { - // uint 8 - oa->write_character(static_cast(0xCC)); - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) - { - // uint 16 - oa->write_character(static_cast(0xCD)); - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) - { - // uint 32 - oa->write_character(static_cast(0xCE)); - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) - { - // uint 64 - oa->write_character(static_cast(0xCF)); - write_number(static_cast(j.m_value.number_integer)); - } - } - else - { - if (j.m_value.number_integer >= -32) - { - // negative fixnum - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_integer >= (std::numeric_limits::min)() and - j.m_value.number_integer <= (std::numeric_limits::max)()) - { - // int 8 - oa->write_character(static_cast(0xD0)); - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_integer >= (std::numeric_limits::min)() and - j.m_value.number_integer <= (std::numeric_limits::max)()) - { - // int 16 - oa->write_character(static_cast(0xD1)); - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_integer >= (std::numeric_limits::min)() and - j.m_value.number_integer <= (std::numeric_limits::max)()) - { - // int 32 - oa->write_character(static_cast(0xD2)); - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_integer >= (std::numeric_limits::min)() and - j.m_value.number_integer <= (std::numeric_limits::max)()) - { - // int 64 - oa->write_character(static_cast(0xD3)); - write_number(static_cast(j.m_value.number_integer)); - } - } - break; - } - - case value_t::number_unsigned: - { - if (j.m_value.number_unsigned < 128) - { - // positive fixnum - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) - { - // uint 8 - oa->write_character(static_cast(0xCC)); - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) - { - // uint 16 - oa->write_character(static_cast(0xCD)); - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) - { - // uint 32 - oa->write_character(static_cast(0xCE)); - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) - { - // uint 64 - oa->write_character(static_cast(0xCF)); - write_number(static_cast(j.m_value.number_integer)); - } - break; - } - - case value_t::number_float: // float 64 - { - oa->write_character(static_cast(0xCB)); - write_number(j.m_value.number_float); - break; - } - - case value_t::string: - { - // step 1: write control byte and the string length - const auto N = j.m_value.string->size(); - if (N <= 31) - { - // fixstr - write_number(static_cast(0xA0 | N)); - } - else if (N <= 255) - { - // str 8 - oa->write_character(static_cast(0xD9)); - write_number(static_cast(N)); - } - else if (N <= 65535) - { - // str 16 - oa->write_character(static_cast(0xDA)); - write_number(static_cast(N)); - } - else if (N <= 4294967295) - { - // str 32 - oa->write_character(static_cast(0xDB)); - write_number(static_cast(N)); - } - - // step 2: write the string - oa->write_characters( - reinterpret_cast(j.m_value.string->c_str()), - j.m_value.string->size()); - break; - } - - case value_t::array: - { - // step 1: write control byte and the array size - const auto N = j.m_value.array->size(); - if (N <= 15) - { - // fixarray - write_number(static_cast(0x90 | N)); - } - else if (N <= 0xFFFF) - { - // array 16 - oa->write_character(static_cast(0xDC)); - write_number(static_cast(N)); - } - else if (N <= 0xFFFFFFFF) - { - // array 32 - oa->write_character(static_cast(0xDD)); - write_number(static_cast(N)); - } - - // step 2: write each element - for (const auto& el : *j.m_value.array) - { - write_msgpack(el); - } - break; - } - - case value_t::object: - { - // step 1: write control byte and the object size - const auto N = j.m_value.object->size(); - if (N <= 15) - { - // fixmap - write_number(static_cast(0x80 | (N & 0xF))); - } - else if (N <= 65535) - { - // map 16 - oa->write_character(static_cast(0xDE)); - write_number(static_cast(N)); - } - else if (N <= 4294967295) - { - // map 32 - oa->write_character(static_cast(0xDF)); - write_number(static_cast(N)); - } - - // step 2: write each element - for (const auto& el : *j.m_value.object) - { - write_msgpack(el.first); - write_msgpack(el.second); - } - break; - } - - default: - break; - } - } - - private: - /* - @brief write a number to output input - - @param[in] n number of type @a NumberType - @tparam NumberType the type of the number - - @note This function needs to respect the system's endianess, because bytes - in CBOR and MessagePack are stored in network order (big endian) and - therefore need reordering on little endian systems. - */ - template void write_number(NumberType n) - { - // step 1: write number to array of length NumberType - std::array vec; - std::memcpy(vec.data(), &n, sizeof(NumberType)); - - // step 2: write array to output (with possible reordering) - if (is_little_endian) - { - // reverse byte order prior to conversion if necessary - std::reverse(vec.begin(), vec.end()); - } - - oa->write_characters(vec.data(), sizeof(NumberType)); - } - - private: - /// whether we can assume little endianess - const bool is_little_endian = binary_reader::little_endianess(); - - /// the output - output_adapter_t oa = nullptr; -}; - /////////////////// // serialization // /////////////////// From a3473fda6acae16682a10051c1f092e039c19826 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20DELRIEU?= Date: Mon, 14 Aug 2017 18:04:51 +0200 Subject: [PATCH 49/59] add detail/serializer.hpp --- Makefile | 3 +- src/detail/serializer.hpp | 794 ++++++++++++++++++++++++++++++++++++++ src/json.hpp | 769 +----------------------------------- 3 files changed, 797 insertions(+), 769 deletions(-) create mode 100644 src/detail/serializer.hpp diff --git a/Makefile b/Makefile index 928f37d8..b646081d 100644 --- a/Makefile +++ b/Makefile @@ -20,7 +20,8 @@ SRCS = ${SRCDIR}/json.hpp \ ${SRCDIR}/detail/iterators/json_reverse_iterator.hpp \ ${SRCDIR}/detail/parsing/output_adapters.hpp \ ${SRCDIR}/detail/parsing/binary_reader.hpp \ - ${SRCDIR}/detail/parsing/binary_writer.hpp + ${SRCDIR}/detail/parsing/binary_writer.hpp \ + ${SRCDIR}/detail/serializer.hpp # main target all: diff --git a/src/detail/serializer.hpp b/src/detail/serializer.hpp new file mode 100644 index 00000000..955a3eac --- /dev/null +++ b/src/detail/serializer.hpp @@ -0,0 +1,794 @@ +#ifndef NLOHMANN_JSON_DETAIL_SERIALIZER_HPP +#define NLOHMANN_JSON_DETAIL_SERIALIZER_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "detail/macro_scope.hpp" +#include "detail/meta.hpp" +#include "detail/parsing/output_adapters.hpp" + +namespace nlohmann +{ +namespace detail +{ +/////////////////// +// serialization // +/////////////////// + +template +class serializer +{ + using string_t = typename BasicJsonType::string_t; + using number_float_t = typename BasicJsonType::number_float_t; + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + public: + /*! + @param[in] s output stream to serialize to + @param[in] ichar indentation character to use + */ + serializer(output_adapter_t s, const char ichar) + : o(std::move(s)), loc(std::localeconv()), + thousands_sep(loc->thousands_sep == nullptr ? '\0' : * (loc->thousands_sep)), + decimal_point(loc->decimal_point == nullptr ? '\0' : * (loc->decimal_point)), + indent_char(ichar), indent_string(512, indent_char) {} + + // delete because of pointer members + serializer(const serializer&) = delete; + serializer& operator=(const serializer&) = delete; + + /*! + @brief internal implementation of the serialization function + + This function is called by the public member function dump and organizes + the serialization internally. The indentation level is propagated as + additional parameter. In case of arrays and objects, the function is + called recursively. + + - strings and object keys are escaped using `escape_string()` + - integer numbers are converted implicitly via `operator<<` + - floating-point numbers are converted to a string using `"%g"` format + + @param[in] val value to serialize + @param[in] pretty_print whether the output shall be pretty-printed + @param[in] indent_step the indent level + @param[in] current_indent the current indent level (only used internally) + */ + void dump(const BasicJsonType& val, const bool pretty_print, + const bool ensure_ascii, + const unsigned int indent_step, + const unsigned int current_indent = 0) + { + switch (val.m_type) + { + case value_t::object: + { + if (val.m_value.object->empty()) + { + o->write_characters("{}", 2); + return; + } + + if (pretty_print) + { + o->write_characters("{\n", 2); + + // variable to hold indentation for recursive calls + const auto new_indent = current_indent + indent_step; + if (JSON_UNLIKELY(indent_string.size() < new_indent)) + { + indent_string.resize(indent_string.size() * 2, ' '); + } + + // first n-1 elements + auto i = val.m_value.object->cbegin(); + for (std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i) + { + o->write_characters(indent_string.c_str(), new_indent); + o->write_character('\"'); + dump_escaped(i->first, ensure_ascii); + o->write_characters("\": ", 3); + dump(i->second, true, ensure_ascii, indent_step, new_indent); + o->write_characters(",\n", 2); + } + + // last element + assert(i != val.m_value.object->cend()); + assert(std::next(i) == val.m_value.object->cend()); + o->write_characters(indent_string.c_str(), new_indent); + o->write_character('\"'); + dump_escaped(i->first, ensure_ascii); + o->write_characters("\": ", 3); + dump(i->second, true, ensure_ascii, indent_step, new_indent); + + o->write_character('\n'); + o->write_characters(indent_string.c_str(), current_indent); + o->write_character('}'); + } + else + { + o->write_character('{'); + + // first n-1 elements + auto i = val.m_value.object->cbegin(); + for (std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i) + { + o->write_character('\"'); + dump_escaped(i->first, ensure_ascii); + o->write_characters("\":", 2); + dump(i->second, false, ensure_ascii, indent_step, current_indent); + o->write_character(','); + } + + // last element + assert(i != val.m_value.object->cend()); + assert(std::next(i) == val.m_value.object->cend()); + o->write_character('\"'); + dump_escaped(i->first, ensure_ascii); + o->write_characters("\":", 2); + dump(i->second, false, ensure_ascii, indent_step, current_indent); + + o->write_character('}'); + } + + return; + } + + case value_t::array: + { + if (val.m_value.array->empty()) + { + o->write_characters("[]", 2); + return; + } + + if (pretty_print) + { + o->write_characters("[\n", 2); + + // variable to hold indentation for recursive calls + const auto new_indent = current_indent + indent_step; + if (JSON_UNLIKELY(indent_string.size() < new_indent)) + { + indent_string.resize(indent_string.size() * 2, ' '); + } + + // first n-1 elements + for (auto i = val.m_value.array->cbegin(); + i != val.m_value.array->cend() - 1; ++i) + { + o->write_characters(indent_string.c_str(), new_indent); + dump(*i, true, ensure_ascii, indent_step, new_indent); + o->write_characters(",\n", 2); + } + + // last element + assert(not val.m_value.array->empty()); + o->write_characters(indent_string.c_str(), new_indent); + dump(val.m_value.array->back(), true, ensure_ascii, indent_step, new_indent); + + o->write_character('\n'); + o->write_characters(indent_string.c_str(), current_indent); + o->write_character(']'); + } + else + { + o->write_character('['); + + // first n-1 elements + for (auto i = val.m_value.array->cbegin(); + i != val.m_value.array->cend() - 1; ++i) + { + dump(*i, false, ensure_ascii, indent_step, current_indent); + o->write_character(','); + } + + // last element + assert(not val.m_value.array->empty()); + dump(val.m_value.array->back(), false, ensure_ascii, indent_step, current_indent); + + o->write_character(']'); + } + + return; + } + + case value_t::string: + { + o->write_character('\"'); + dump_escaped(*val.m_value.string, ensure_ascii); + o->write_character('\"'); + return; + } + + case value_t::boolean: + { + if (val.m_value.boolean) + { + o->write_characters("true", 4); + } + else + { + o->write_characters("false", 5); + } + return; + } + + case value_t::number_integer: + { + dump_integer(val.m_value.number_integer); + return; + } + + case value_t::number_unsigned: + { + dump_integer(val.m_value.number_unsigned); + return; + } + + case value_t::number_float: + { + dump_float(val.m_value.number_float); + return; + } + + case value_t::discarded: + { + o->write_characters("", 11); + return; + } + + case value_t::null: + { + o->write_characters("null", 4); + return; + } + } + } + + private: + /*! + @brief returns the number of expected bytes following in UTF-8 string + + @param[in] u the first byte of a UTF-8 string + @return the number of expected bytes following + */ + static constexpr std::size_t bytes_following(const uint8_t u) + { + return ((u <= 127) ? 0 + : ((192 <= u and u <= 223) ? 1 + : ((224 <= u and u <= 239) ? 2 + : ((240 <= u and u <= 247) ? 3 : std::string::npos)))); + } + + /*! + @brief calculates the extra space to escape a JSON string + + @param[in] s the string to escape + @param[in] ensure_ascii whether to escape non-ASCII characters with + \uXXXX sequences + @return the number of characters required to escape string @a s + + @complexity Linear in the length of string @a s. + */ + static std::size_t extra_space(const string_t& s, + const bool ensure_ascii) noexcept + { + std::size_t res = 0; + + for (std::size_t i = 0; i < s.size(); ++i) + { + switch (s[i]) + { + // control characters that can be escaped with a backslash + case '"': + case '\\': + case '\b': + case '\f': + case '\n': + case '\r': + case '\t': + { + // from c (1 byte) to \x (2 bytes) + res += 1; + break; + } + + // control characters that need \uxxxx escaping + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x0B: + case 0x0E: + case 0x0F: + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + case 0x1A: + case 0x1B: + case 0x1C: + case 0x1D: + case 0x1E: + case 0x1F: + { + // from c (1 byte) to \uxxxx (6 bytes) + res += 5; + break; + } + + default: + { + if (ensure_ascii and (s[i] & 0x80 or s[i] == 0x7F)) + { + const auto bytes = bytes_following(static_cast(s[i])); + // invalid characters will be detected by throw_if_invalid_utf8 + assert (bytes != std::string::npos); + + if (bytes == 3) + { + // codepoints that need 4 bytes (i.e., 3 additional + // bytes) in UTF-8 need a surrogate pair when \u + // escaping is used: from 4 bytes to \uxxxx\uxxxx + // (12 bytes) + res += (12 - bytes - 1); + } + else + { + // from x bytes to \uxxxx (6 bytes) + res += (6 - bytes - 1); + } + + // skip the additional bytes + i += bytes; + } + break; + } + } + } + + return res; + } + + static void escape_codepoint(int codepoint, string_t& result, std::size_t& pos) + { + // expecting a proper codepoint + assert(0x00 <= codepoint and codepoint <= 0x10FFFF); + + // the last written character was the backslash before the 'u' + assert(result[pos] == '\\'); + + // write the 'u' + result[++pos] = 'u'; + + // convert a number 0..15 to its hex representation (0..f) + static const std::array hexify = + { + { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' + } + }; + + if (codepoint < 0x10000) + { + // codepoints U+0000..U+FFFF can be represented as \uxxxx. + result[++pos] = hexify[(codepoint >> 12) & 0x0F]; + result[++pos] = hexify[(codepoint >> 8) & 0x0F]; + result[++pos] = hexify[(codepoint >> 4) & 0x0F]; + result[++pos] = hexify[codepoint & 0x0F]; + } + else + { + // codepoints U+10000..U+10FFFF need a surrogate pair to be + // represented as \uxxxx\uxxxx. + // http://www.unicode.org/faq/utf_bom.html#utf16-4 + codepoint -= 0x10000; + const int high_surrogate = 0xD800 | ((codepoint >> 10) & 0x3FF); + const int low_surrogate = 0xDC00 | (codepoint & 0x3FF); + result[++pos] = hexify[(high_surrogate >> 12) & 0x0F]; + result[++pos] = hexify[(high_surrogate >> 8) & 0x0F]; + result[++pos] = hexify[(high_surrogate >> 4) & 0x0F]; + result[++pos] = hexify[high_surrogate & 0x0F]; + ++pos; // backslash is already in output + result[++pos] = 'u'; + result[++pos] = hexify[(low_surrogate >> 12) & 0x0F]; + result[++pos] = hexify[(low_surrogate >> 8) & 0x0F]; + result[++pos] = hexify[(low_surrogate >> 4) & 0x0F]; + result[++pos] = hexify[low_surrogate & 0x0F]; + } + + ++pos; + } + + /*! + @brief dump escaped string + + Escape a string by replacing certain special characters by a sequence of an + escape character (backslash) and another character and other control + characters by a sequence of "\u" followed by a four-digit hex + representation. The escaped string is written to output stream @a o. + + @param[in] s the string to escape + @param[in] ensure_ascii whether to escape non-ASCII characters with + \uXXXX sequences + + @complexity Linear in the length of string @a s. + */ + void dump_escaped(const string_t& s, const bool ensure_ascii) const + { + throw_if_invalid_utf8(s); + + const auto space = extra_space(s, ensure_ascii); + if (space == 0) + { + o->write_characters(s.c_str(), s.size()); + return; + } + + // create a result string of necessary size + string_t result(s.size() + space, '\\'); + std::size_t pos = 0; + + for (std::size_t i = 0; i < s.size(); ++i) + { + switch (s[i]) + { + case '"': // quotation mark (0x22) + { + result[pos + 1] = '"'; + pos += 2; + break; + } + + case '\\': // reverse solidus (0x5C) + { + // nothing to change + pos += 2; + break; + } + + case '\b': // backspace (0x08) + { + result[pos + 1] = 'b'; + pos += 2; + break; + } + + case '\f': // formfeed (0x0C) + { + result[pos + 1] = 'f'; + pos += 2; + break; + } + + case '\n': // newline (0x0A) + { + result[pos + 1] = 'n'; + pos += 2; + break; + } + + case '\r': // carriage return (0x0D) + { + result[pos + 1] = 'r'; + pos += 2; + break; + } + + case '\t': // horizontal tab (0x09) + { + result[pos + 1] = 't'; + pos += 2; + break; + } + + default: + { + // escape control characters (0x00..0x1F) or, if + // ensure_ascii parameter is used, non-ASCII characters + if ((0x00 <= s[i] and s[i] <= 0x1F) or + (ensure_ascii and (s[i] & 0x80 or s[i] == 0x7F))) + { + const auto bytes = bytes_following(static_cast(s[i])); + // invalid characters will be detected by throw_if_invalid_utf8 + assert (bytes != std::string::npos); + + // check that the additional bytes are present + assert(i + bytes < s.size()); + + // to use \uxxxx escaping, we first need to calculate + // the codepoint from the UTF-8 bytes + int codepoint = 0; + + // bytes is unsigned type: + assert(bytes <= 3); + switch (bytes) + { + case 0: + { + codepoint = s[i] & 0xFF; + break; + } + + case 1: + { + codepoint = ((s[i] & 0x3F) << 6) + + (s[i + 1] & 0x7F); + break; + } + + case 2: + { + codepoint = ((s[i] & 0x1F) << 12) + + ((s[i + 1] & 0x7F) << 6) + + (s[i + 2] & 0x7F); + break; + } + + case 3: + { + codepoint = ((s[i] & 0xF) << 18) + + ((s[i + 1] & 0x7F) << 12) + + ((s[i + 2] & 0x7F) << 6) + + (s[i + 3] & 0x7F); + break; + } + + default: + break; // LCOV_EXCL_LINE + } + + escape_codepoint(codepoint, result, pos); + i += bytes; + } + else + { + // all other characters are added as-is + result[pos++] = s[i]; + } + break; + } + } + } + + assert(pos == result.size()); + o->write_characters(result.c_str(), result.size()); + } + + /*! + @brief dump an integer + + Dump a given integer to output stream @a o. Works internally with + @a number_buffer. + + @param[in] x integer number (signed or unsigned) to dump + @tparam NumberType either @a number_integer_t or @a number_unsigned_t + */ + template::value or + std::is_same::value, + int> = 0> + void dump_integer(NumberType x) + { + // special case for "0" + if (x == 0) + { + o->write_character('0'); + return; + } + + const bool is_negative = (x <= 0) and (x != 0); // see issue #755 + std::size_t i = 0; + + while (x != 0) + { + // spare 1 byte for '\0' + assert(i < number_buffer.size() - 1); + + const auto digit = std::labs(static_cast(x % 10)); + number_buffer[i++] = static_cast('0' + digit); + x /= 10; + } + + if (is_negative) + { + // make sure there is capacity for the '-' + assert(i < number_buffer.size() - 2); + number_buffer[i++] = '-'; + } + + std::reverse(number_buffer.begin(), number_buffer.begin() + i); + o->write_characters(number_buffer.data(), i); + } + + /*! + @brief dump a floating-point number + + Dump a given floating-point number to output stream @a o. Works internally + with @a number_buffer. + + @param[in] x floating-point number to dump + */ + void dump_float(number_float_t x) + { + // NaN / inf + if (not std::isfinite(x) or std::isnan(x)) + { + o->write_characters("null", 4); + return; + } + + // get number of digits for a text -> float -> text round-trip + static constexpr auto d = std::numeric_limits::digits10; + + // the actual conversion + std::ptrdiff_t len = snprintf(number_buffer.data(), number_buffer.size(), "%.*g", d, x); + + // negative value indicates an error + assert(len > 0); + // check if buffer was large enough + assert(static_cast(len) < number_buffer.size()); + + // erase thousands separator + if (thousands_sep != '\0') + { + const auto end = std::remove(number_buffer.begin(), + number_buffer.begin() + len, thousands_sep); + std::fill(end, number_buffer.end(), '\0'); + assert((end - number_buffer.begin()) <= len); + len = (end - number_buffer.begin()); + } + + // convert decimal point to '.' + if (decimal_point != '\0' and decimal_point != '.') + { + const auto dec_pos = std::find(number_buffer.begin(), number_buffer.end(), decimal_point); + if (dec_pos != number_buffer.end()) + { + *dec_pos = '.'; + } + } + + o->write_characters(number_buffer.data(), static_cast(len)); + + // determine if need to append ".0" + const bool value_is_int_like = + std::none_of(number_buffer.begin(), number_buffer.begin() + len + 1, + [](char c) + { + return (c == '.' or c == 'e'); + }); + + if (value_is_int_like) + { + o->write_characters(".0", 2); + } + } + + /*! + @brief check whether a string is UTF-8 encoded + + The function checks each byte of a string whether it is UTF-8 encoded. The + result of the check is stored in the @a state parameter. The function must + be called initially with state 0 (accept). State 1 means the string must + be rejected, because the current byte is not allowed. If the string is + completely processed, but the state is non-zero, the string ended + prematurely; that is, the last byte indicated more bytes should have + followed. + + @param[in,out] state the state of the decoding + @param[in] byte next byte to decode + + @note The function has been edited: a std::array is used and the code + point is not calculated. + + @copyright Copyright (c) 2008-2009 Bjoern Hoehrmann + @sa http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ + */ + static void decode(uint8_t& state, const uint8_t byte) + { + static const std::array utf8d = + { + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00..1F + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20..3F + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 40..5F + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60..7F + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 80..9F + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // A0..BF + 8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // C0..DF + 0xA, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3, 0x3, // E0..EF + 0xB, 0x6, 0x6, 0x6, 0x5, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, // F0..FF + 0x0, 0x1, 0x2, 0x3, 0x5, 0x8, 0x7, 0x1, 0x1, 0x1, 0x4, 0x6, 0x1, 0x1, 0x1, 0x1, // s0..s0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, // s1..s2 + 1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, // s3..s4 + 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, // s5..s6 + 1, 3, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // s7..s8 + } + }; + + const uint8_t type = utf8d[byte]; + state = utf8d[256u + state * 16u + type]; + } + + /*! + @brief throw an exception if a string is not UTF-8 encoded + + @param[in] str UTF-8 string to check + @throw type_error.316 if passed string is not UTF-8 encoded + + @since version 3.0.0 + */ + static void throw_if_invalid_utf8(const std::string& str) + { + // start with state 0 (= accept) + uint8_t state = 0; + + for (size_t i = 0; i < str.size(); ++i) + { + const auto byte = static_cast(str[i]); + decode(state, byte); + if (state == 1) + { + // state 1 means reject + std::stringstream ss; + ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << static_cast(byte); + JSON_THROW(type_error::create(316, "invalid UTF-8 byte at index " + std::to_string(i) + ": 0x" + ss.str())); + } + } + + if (state != 0) + { + // we finish reading, but do not accept: string was incomplete + std::stringstream ss; + ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << static_cast(static_cast(str.back())); + JSON_THROW(type_error::create(316, "incomplete UTF-8 string; last byte: 0x" + ss.str())); + } + } + + private: + /// the output of the serializer + output_adapter_t o = nullptr; + + /// a (hopefully) large enough character buffer + std::array number_buffer{{}}; + + /// the locale + const std::lconv* loc = nullptr; + /// the locale's thousand separator character + const char thousands_sep = '\0'; + /// the locale's decimal point character + const char decimal_point = '\0'; + + /// the indentation character + const char indent_char; + + /// the indentation string + string_t indent_string; +}; +} +} + +#endif diff --git a/src/json.hpp b/src/json.hpp index ff1af030..d52d6e83 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -68,6 +68,7 @@ SOFTWARE. #include "detail/parsing/output_adapters.hpp" #include "detail/parsing/binary_reader.hpp" #include "detail/parsing/binary_writer.hpp" +#include "detail/serializer.hpp" /*! @brief namespace for Niels Lohmann @@ -78,774 +79,6 @@ namespace nlohmann { namespace detail { -/////////////////// -// serialization // -/////////////////// - -template -class serializer -{ - using string_t = typename BasicJsonType::string_t; - using number_float_t = typename BasicJsonType::number_float_t; - using number_integer_t = typename BasicJsonType::number_integer_t; - using number_unsigned_t = typename BasicJsonType::number_unsigned_t; - public: - /*! - @param[in] s output stream to serialize to - @param[in] ichar indentation character to use - */ - serializer(output_adapter_t s, const char ichar) - : o(std::move(s)), loc(std::localeconv()), - thousands_sep(loc->thousands_sep == nullptr ? '\0' : * (loc->thousands_sep)), - decimal_point(loc->decimal_point == nullptr ? '\0' : * (loc->decimal_point)), - indent_char(ichar), indent_string(512, indent_char) {} - - // delete because of pointer members - serializer(const serializer&) = delete; - serializer& operator=(const serializer&) = delete; - - /*! - @brief internal implementation of the serialization function - - This function is called by the public member function dump and organizes - the serialization internally. The indentation level is propagated as - additional parameter. In case of arrays and objects, the function is - called recursively. - - - strings and object keys are escaped using `escape_string()` - - integer numbers are converted implicitly via `operator<<` - - floating-point numbers are converted to a string using `"%g"` format - - @param[in] val value to serialize - @param[in] pretty_print whether the output shall be pretty-printed - @param[in] indent_step the indent level - @param[in] current_indent the current indent level (only used internally) - */ - void dump(const BasicJsonType& val, const bool pretty_print, - const bool ensure_ascii, - const unsigned int indent_step, - const unsigned int current_indent = 0) - { - switch (val.m_type) - { - case value_t::object: - { - if (val.m_value.object->empty()) - { - o->write_characters("{}", 2); - return; - } - - if (pretty_print) - { - o->write_characters("{\n", 2); - - // variable to hold indentation for recursive calls - const auto new_indent = current_indent + indent_step; - if (JSON_UNLIKELY(indent_string.size() < new_indent)) - { - indent_string.resize(indent_string.size() * 2, ' '); - } - - // first n-1 elements - auto i = val.m_value.object->cbegin(); - for (std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i) - { - o->write_characters(indent_string.c_str(), new_indent); - o->write_character('\"'); - dump_escaped(i->first, ensure_ascii); - o->write_characters("\": ", 3); - dump(i->second, true, ensure_ascii, indent_step, new_indent); - o->write_characters(",\n", 2); - } - - // last element - assert(i != val.m_value.object->cend()); - assert(std::next(i) == val.m_value.object->cend()); - o->write_characters(indent_string.c_str(), new_indent); - o->write_character('\"'); - dump_escaped(i->first, ensure_ascii); - o->write_characters("\": ", 3); - dump(i->second, true, ensure_ascii, indent_step, new_indent); - - o->write_character('\n'); - o->write_characters(indent_string.c_str(), current_indent); - o->write_character('}'); - } - else - { - o->write_character('{'); - - // first n-1 elements - auto i = val.m_value.object->cbegin(); - for (std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i) - { - o->write_character('\"'); - dump_escaped(i->first, ensure_ascii); - o->write_characters("\":", 2); - dump(i->second, false, ensure_ascii, indent_step, current_indent); - o->write_character(','); - } - - // last element - assert(i != val.m_value.object->cend()); - assert(std::next(i) == val.m_value.object->cend()); - o->write_character('\"'); - dump_escaped(i->first, ensure_ascii); - o->write_characters("\":", 2); - dump(i->second, false, ensure_ascii, indent_step, current_indent); - - o->write_character('}'); - } - - return; - } - - case value_t::array: - { - if (val.m_value.array->empty()) - { - o->write_characters("[]", 2); - return; - } - - if (pretty_print) - { - o->write_characters("[\n", 2); - - // variable to hold indentation for recursive calls - const auto new_indent = current_indent + indent_step; - if (JSON_UNLIKELY(indent_string.size() < new_indent)) - { - indent_string.resize(indent_string.size() * 2, ' '); - } - - // first n-1 elements - for (auto i = val.m_value.array->cbegin(); - i != val.m_value.array->cend() - 1; ++i) - { - o->write_characters(indent_string.c_str(), new_indent); - dump(*i, true, ensure_ascii, indent_step, new_indent); - o->write_characters(",\n", 2); - } - - // last element - assert(not val.m_value.array->empty()); - o->write_characters(indent_string.c_str(), new_indent); - dump(val.m_value.array->back(), true, ensure_ascii, indent_step, new_indent); - - o->write_character('\n'); - o->write_characters(indent_string.c_str(), current_indent); - o->write_character(']'); - } - else - { - o->write_character('['); - - // first n-1 elements - for (auto i = val.m_value.array->cbegin(); - i != val.m_value.array->cend() - 1; ++i) - { - dump(*i, false, ensure_ascii, indent_step, current_indent); - o->write_character(','); - } - - // last element - assert(not val.m_value.array->empty()); - dump(val.m_value.array->back(), false, ensure_ascii, indent_step, current_indent); - - o->write_character(']'); - } - - return; - } - - case value_t::string: - { - o->write_character('\"'); - dump_escaped(*val.m_value.string, ensure_ascii); - o->write_character('\"'); - return; - } - - case value_t::boolean: - { - if (val.m_value.boolean) - { - o->write_characters("true", 4); - } - else - { - o->write_characters("false", 5); - } - return; - } - - case value_t::number_integer: - { - dump_integer(val.m_value.number_integer); - return; - } - - case value_t::number_unsigned: - { - dump_integer(val.m_value.number_unsigned); - return; - } - - case value_t::number_float: - { - dump_float(val.m_value.number_float); - return; - } - - case value_t::discarded: - { - o->write_characters("", 11); - return; - } - - case value_t::null: - { - o->write_characters("null", 4); - return; - } - } - } - - private: - /*! - @brief returns the number of expected bytes following in UTF-8 string - - @param[in] u the first byte of a UTF-8 string - @return the number of expected bytes following - */ - static constexpr std::size_t bytes_following(const uint8_t u) - { - return ((u <= 127) ? 0 - : ((192 <= u and u <= 223) ? 1 - : ((224 <= u and u <= 239) ? 2 - : ((240 <= u and u <= 247) ? 3 : std::string::npos)))); - } - - /*! - @brief calculates the extra space to escape a JSON string - - @param[in] s the string to escape - @param[in] ensure_ascii whether to escape non-ASCII characters with - \uXXXX sequences - @return the number of characters required to escape string @a s - - @complexity Linear in the length of string @a s. - */ - static std::size_t extra_space(const string_t& s, - const bool ensure_ascii) noexcept - { - std::size_t res = 0; - - for (std::size_t i = 0; i < s.size(); ++i) - { - switch (s[i]) - { - // control characters that can be escaped with a backslash - case '"': - case '\\': - case '\b': - case '\f': - case '\n': - case '\r': - case '\t': - { - // from c (1 byte) to \x (2 bytes) - res += 1; - break; - } - - // control characters that need \uxxxx escaping - case 0x00: - case 0x01: - case 0x02: - case 0x03: - case 0x04: - case 0x05: - case 0x06: - case 0x07: - case 0x0B: - case 0x0E: - case 0x0F: - case 0x10: - case 0x11: - case 0x12: - case 0x13: - case 0x14: - case 0x15: - case 0x16: - case 0x17: - case 0x18: - case 0x19: - case 0x1A: - case 0x1B: - case 0x1C: - case 0x1D: - case 0x1E: - case 0x1F: - { - // from c (1 byte) to \uxxxx (6 bytes) - res += 5; - break; - } - - default: - { - if (ensure_ascii and (s[i] & 0x80 or s[i] == 0x7F)) - { - const auto bytes = bytes_following(static_cast(s[i])); - // invalid characters will be detected by throw_if_invalid_utf8 - assert (bytes != std::string::npos); - - if (bytes == 3) - { - // codepoints that need 4 bytes (i.e., 3 additional - // bytes) in UTF-8 need a surrogate pair when \u - // escaping is used: from 4 bytes to \uxxxx\uxxxx - // (12 bytes) - res += (12 - bytes - 1); - } - else - { - // from x bytes to \uxxxx (6 bytes) - res += (6 - bytes - 1); - } - - // skip the additional bytes - i += bytes; - } - break; - } - } - } - - return res; - } - - static void escape_codepoint(int codepoint, string_t& result, std::size_t& pos) - { - // expecting a proper codepoint - assert(0x00 <= codepoint and codepoint <= 0x10FFFF); - - // the last written character was the backslash before the 'u' - assert(result[pos] == '\\'); - - // write the 'u' - result[++pos] = 'u'; - - // convert a number 0..15 to its hex representation (0..f) - static const std::array hexify = - { - { - '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' - } - }; - - if (codepoint < 0x10000) - { - // codepoints U+0000..U+FFFF can be represented as \uxxxx. - result[++pos] = hexify[(codepoint >> 12) & 0x0F]; - result[++pos] = hexify[(codepoint >> 8) & 0x0F]; - result[++pos] = hexify[(codepoint >> 4) & 0x0F]; - result[++pos] = hexify[codepoint & 0x0F]; - } - else - { - // codepoints U+10000..U+10FFFF need a surrogate pair to be - // represented as \uxxxx\uxxxx. - // http://www.unicode.org/faq/utf_bom.html#utf16-4 - codepoint -= 0x10000; - const int high_surrogate = 0xD800 | ((codepoint >> 10) & 0x3FF); - const int low_surrogate = 0xDC00 | (codepoint & 0x3FF); - result[++pos] = hexify[(high_surrogate >> 12) & 0x0F]; - result[++pos] = hexify[(high_surrogate >> 8) & 0x0F]; - result[++pos] = hexify[(high_surrogate >> 4) & 0x0F]; - result[++pos] = hexify[high_surrogate & 0x0F]; - ++pos; // backslash is already in output - result[++pos] = 'u'; - result[++pos] = hexify[(low_surrogate >> 12) & 0x0F]; - result[++pos] = hexify[(low_surrogate >> 8) & 0x0F]; - result[++pos] = hexify[(low_surrogate >> 4) & 0x0F]; - result[++pos] = hexify[low_surrogate & 0x0F]; - } - - ++pos; - } - - /*! - @brief dump escaped string - - Escape a string by replacing certain special characters by a sequence of an - escape character (backslash) and another character and other control - characters by a sequence of "\u" followed by a four-digit hex - representation. The escaped string is written to output stream @a o. - - @param[in] s the string to escape - @param[in] ensure_ascii whether to escape non-ASCII characters with - \uXXXX sequences - - @complexity Linear in the length of string @a s. - */ - void dump_escaped(const string_t& s, const bool ensure_ascii) const - { - throw_if_invalid_utf8(s); - - const auto space = extra_space(s, ensure_ascii); - if (space == 0) - { - o->write_characters(s.c_str(), s.size()); - return; - } - - // create a result string of necessary size - string_t result(s.size() + space, '\\'); - std::size_t pos = 0; - - for (std::size_t i = 0; i < s.size(); ++i) - { - switch (s[i]) - { - case '"': // quotation mark (0x22) - { - result[pos + 1] = '"'; - pos += 2; - break; - } - - case '\\': // reverse solidus (0x5C) - { - // nothing to change - pos += 2; - break; - } - - case '\b': // backspace (0x08) - { - result[pos + 1] = 'b'; - pos += 2; - break; - } - - case '\f': // formfeed (0x0C) - { - result[pos + 1] = 'f'; - pos += 2; - break; - } - - case '\n': // newline (0x0A) - { - result[pos + 1] = 'n'; - pos += 2; - break; - } - - case '\r': // carriage return (0x0D) - { - result[pos + 1] = 'r'; - pos += 2; - break; - } - - case '\t': // horizontal tab (0x09) - { - result[pos + 1] = 't'; - pos += 2; - break; - } - - default: - { - // escape control characters (0x00..0x1F) or, if - // ensure_ascii parameter is used, non-ASCII characters - if ((0x00 <= s[i] and s[i] <= 0x1F) or - (ensure_ascii and (s[i] & 0x80 or s[i] == 0x7F))) - { - const auto bytes = bytes_following(static_cast(s[i])); - // invalid characters will be detected by throw_if_invalid_utf8 - assert (bytes != std::string::npos); - - // check that the additional bytes are present - assert(i + bytes < s.size()); - - // to use \uxxxx escaping, we first need to calculate - // the codepoint from the UTF-8 bytes - int codepoint = 0; - - // bytes is unsigned type: - assert(bytes <= 3); - switch (bytes) - { - case 0: - { - codepoint = s[i] & 0xFF; - break; - } - - case 1: - { - codepoint = ((s[i] & 0x3F) << 6) - + (s[i + 1] & 0x7F); - break; - } - - case 2: - { - codepoint = ((s[i] & 0x1F) << 12) - + ((s[i + 1] & 0x7F) << 6) - + (s[i + 2] & 0x7F); - break; - } - - case 3: - { - codepoint = ((s[i] & 0xF) << 18) - + ((s[i + 1] & 0x7F) << 12) - + ((s[i + 2] & 0x7F) << 6) - + (s[i + 3] & 0x7F); - break; - } - - default: - break; // LCOV_EXCL_LINE - } - - escape_codepoint(codepoint, result, pos); - i += bytes; - } - else - { - // all other characters are added as-is - result[pos++] = s[i]; - } - break; - } - } - } - - assert(pos == result.size()); - o->write_characters(result.c_str(), result.size()); - } - - /*! - @brief dump an integer - - Dump a given integer to output stream @a o. Works internally with - @a number_buffer. - - @param[in] x integer number (signed or unsigned) to dump - @tparam NumberType either @a number_integer_t or @a number_unsigned_t - */ - template::value or - std::is_same::value, - int> = 0> - void dump_integer(NumberType x) - { - // special case for "0" - if (x == 0) - { - o->write_character('0'); - return; - } - - const bool is_negative = (x <= 0) and (x != 0); // see issue #755 - std::size_t i = 0; - - while (x != 0) - { - // spare 1 byte for '\0' - assert(i < number_buffer.size() - 1); - - const auto digit = std::labs(static_cast(x % 10)); - number_buffer[i++] = static_cast('0' + digit); - x /= 10; - } - - if (is_negative) - { - // make sure there is capacity for the '-' - assert(i < number_buffer.size() - 2); - number_buffer[i++] = '-'; - } - - std::reverse(number_buffer.begin(), number_buffer.begin() + i); - o->write_characters(number_buffer.data(), i); - } - - /*! - @brief dump a floating-point number - - Dump a given floating-point number to output stream @a o. Works internally - with @a number_buffer. - - @param[in] x floating-point number to dump - */ - void dump_float(number_float_t x) - { - // NaN / inf - if (not std::isfinite(x) or std::isnan(x)) - { - o->write_characters("null", 4); - return; - } - - // get number of digits for a text -> float -> text round-trip - static constexpr auto d = std::numeric_limits::digits10; - - // the actual conversion - std::ptrdiff_t len = snprintf(number_buffer.data(), number_buffer.size(), "%.*g", d, x); - - // negative value indicates an error - assert(len > 0); - // check if buffer was large enough - assert(static_cast(len) < number_buffer.size()); - - // erase thousands separator - if (thousands_sep != '\0') - { - const auto end = std::remove(number_buffer.begin(), - number_buffer.begin() + len, thousands_sep); - std::fill(end, number_buffer.end(), '\0'); - assert((end - number_buffer.begin()) <= len); - len = (end - number_buffer.begin()); - } - - // convert decimal point to '.' - if (decimal_point != '\0' and decimal_point != '.') - { - const auto dec_pos = std::find(number_buffer.begin(), number_buffer.end(), decimal_point); - if (dec_pos != number_buffer.end()) - { - *dec_pos = '.'; - } - } - - o->write_characters(number_buffer.data(), static_cast(len)); - - // determine if need to append ".0" - const bool value_is_int_like = - std::none_of(number_buffer.begin(), number_buffer.begin() + len + 1, - [](char c) - { - return (c == '.' or c == 'e'); - }); - - if (value_is_int_like) - { - o->write_characters(".0", 2); - } - } - - /*! - @brief check whether a string is UTF-8 encoded - - The function checks each byte of a string whether it is UTF-8 encoded. The - result of the check is stored in the @a state parameter. The function must - be called initially with state 0 (accept). State 1 means the string must - be rejected, because the current byte is not allowed. If the string is - completely processed, but the state is non-zero, the string ended - prematurely; that is, the last byte indicated more bytes should have - followed. - - @param[in,out] state the state of the decoding - @param[in] byte next byte to decode - - @note The function has been edited: a std::array is used and the code - point is not calculated. - - @copyright Copyright (c) 2008-2009 Bjoern Hoehrmann - @sa http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ - */ - static void decode(uint8_t& state, const uint8_t byte) - { - static const std::array utf8d = - { - { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00..1F - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20..3F - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 40..5F - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60..7F - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 80..9F - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // A0..BF - 8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // C0..DF - 0xA, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3, 0x3, // E0..EF - 0xB, 0x6, 0x6, 0x6, 0x5, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, // F0..FF - 0x0, 0x1, 0x2, 0x3, 0x5, 0x8, 0x7, 0x1, 0x1, 0x1, 0x4, 0x6, 0x1, 0x1, 0x1, 0x1, // s0..s0 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, // s1..s2 - 1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, // s3..s4 - 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, // s5..s6 - 1, 3, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // s7..s8 - } - }; - - const uint8_t type = utf8d[byte]; - state = utf8d[256u + state * 16u + type]; - } - - /*! - @brief throw an exception if a string is not UTF-8 encoded - - @param[in] str UTF-8 string to check - @throw type_error.316 if passed string is not UTF-8 encoded - - @since version 3.0.0 - */ - static void throw_if_invalid_utf8(const std::string& str) - { - // start with state 0 (= accept) - uint8_t state = 0; - - for (size_t i = 0; i < str.size(); ++i) - { - const auto byte = static_cast(str[i]); - decode(state, byte); - if (state == 1) - { - // state 1 means reject - std::stringstream ss; - ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << static_cast(byte); - JSON_THROW(type_error::create(316, "invalid UTF-8 byte at index " + std::to_string(i) + ": 0x" + ss.str())); - } - } - - if (state != 0) - { - // we finish reading, but do not accept: string was incomplete - std::stringstream ss; - ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << static_cast(static_cast(str.back())); - JSON_THROW(type_error::create(316, "incomplete UTF-8 string; last byte: 0x" + ss.str())); - } - } - - private: - /// the output of the serializer - output_adapter_t o = nullptr; - - /// a (hopefully) large enough character buffer - std::array number_buffer{{}}; - - /// the locale - const std::lconv* loc = nullptr; - /// the locale's thousand separator character - const char thousands_sep = '\0'; - /// the locale's decimal point character - const char decimal_point = '\0'; - - /// the indentation character - const char indent_char; - - /// the indentation string - string_t indent_string; -}; - template class json_ref { From 8e9714fe3dae9725011083096bdd1b115e9c1a61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20DELRIEU?= Date: Mon, 14 Aug 2017 18:14:27 +0200 Subject: [PATCH 50/59] add detail/json_ref.hpp --- Makefile | 3 +- src/detail/json_ref.hpp | 66 +++++++++++++++++++++++++++++++++++++++++ src/json.hpp | 58 +----------------------------------- 3 files changed, 69 insertions(+), 58 deletions(-) create mode 100644 src/detail/json_ref.hpp diff --git a/Makefile b/Makefile index b646081d..a2c73dbf 100644 --- a/Makefile +++ b/Makefile @@ -21,7 +21,8 @@ SRCS = ${SRCDIR}/json.hpp \ ${SRCDIR}/detail/parsing/output_adapters.hpp \ ${SRCDIR}/detail/parsing/binary_reader.hpp \ ${SRCDIR}/detail/parsing/binary_writer.hpp \ - ${SRCDIR}/detail/serializer.hpp + ${SRCDIR}/detail/serializer.hpp \ + ${SRCDIR}/detail/json_ref.hpp # main target all: diff --git a/src/detail/json_ref.hpp b/src/detail/json_ref.hpp new file mode 100644 index 00000000..ec120c02 --- /dev/null +++ b/src/detail/json_ref.hpp @@ -0,0 +1,66 @@ +#ifndef NLOHMANN_JSON_DETAIL_JSON_REF_HPP +#define NLOHMANN_JSON_DETAIL_JSON_REF_HPP + +#include +#include + +namespace nlohmann +{ +namespace detail +{ +template +class json_ref +{ + public: + using value_type = BasicJsonType; + + json_ref(value_type&& value) + : owned_value(std::move(value)), value_ref(&owned_value), is_rvalue(true) + {} + + json_ref(const value_type& value) + : value_ref(const_cast(&value)), is_rvalue(false) + {} + + json_ref(std::initializer_list init) + : owned_value(init), value_ref(&owned_value), is_rvalue(true) + {} + + template + json_ref(Args&& ... args) + : owned_value(std::forward(args)...), value_ref(&owned_value), is_rvalue(true) + {} + + // class should be movable only + json_ref(json_ref&&) = default; + json_ref(const json_ref&) = delete; + json_ref& operator=(const json_ref&) = delete; + + value_type moved_or_copied() const + { + if (is_rvalue) + { + return std::move(*value_ref); + } + return *value_ref; + } + + value_type const& operator*() const + { + return *static_cast(value_ref); + } + + value_type const* operator->() const + { + return static_cast(value_ref); + } + + private: + mutable value_type owned_value = nullptr; + value_type* value_ref = nullptr; + const bool is_rvalue; +}; +} +} + +#endif diff --git a/src/json.hpp b/src/json.hpp index d52d6e83..32051d7e 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -69,6 +69,7 @@ SOFTWARE. #include "detail/parsing/binary_reader.hpp" #include "detail/parsing/binary_writer.hpp" #include "detail/serializer.hpp" +#include "detail/json_ref.hpp" /*! @brief namespace for Niels Lohmann @@ -77,63 +78,6 @@ SOFTWARE. */ namespace nlohmann { -namespace detail -{ -template -class json_ref -{ - public: - using value_type = BasicJsonType; - - json_ref(value_type&& value) - : owned_value(std::move(value)), value_ref(&owned_value), is_rvalue(true) - {} - - json_ref(const value_type& value) - : value_ref(const_cast(&value)), is_rvalue(false) - {} - - json_ref(std::initializer_list init) - : owned_value(init), value_ref(&owned_value), is_rvalue(true) - {} - - template - json_ref(Args&& ... args) - : owned_value(std::forward(args)...), value_ref(&owned_value), is_rvalue(true) - {} - - // class should be movable only - json_ref(json_ref&&) = default; - json_ref(const json_ref&) = delete; - json_ref& operator=(const json_ref&) = delete; - - value_type moved_or_copied() const - { - if (is_rvalue) - { - return std::move(*value_ref); - } - return *value_ref; - } - - value_type const& operator*() const - { - return *static_cast(value_ref); - } - - value_type const* operator->() const - { - return static_cast(value_ref); - } - - private: - mutable value_type owned_value = nullptr; - value_type* value_ref = nullptr; - const bool is_rvalue; -}; - -} // namespace detail - template struct adl_serializer { From 9cab30cfceda84aead05a78653dbb519fd00c2c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20DELRIEU?= Date: Mon, 14 Aug 2017 18:22:49 +0200 Subject: [PATCH 51/59] add adl_serializer.hpp --- Makefile | 3 ++- src/adl_serializer.hpp | 48 ++++++++++++++++++++++++++++++++++++++++++ src/json.hpp | 38 +-------------------------------- 3 files changed, 51 insertions(+), 38 deletions(-) create mode 100644 src/adl_serializer.hpp diff --git a/Makefile b/Makefile index a2c73dbf..289080c7 100644 --- a/Makefile +++ b/Makefile @@ -22,7 +22,8 @@ SRCS = ${SRCDIR}/json.hpp \ ${SRCDIR}/detail/parsing/binary_reader.hpp \ ${SRCDIR}/detail/parsing/binary_writer.hpp \ ${SRCDIR}/detail/serializer.hpp \ - ${SRCDIR}/detail/json_ref.hpp + ${SRCDIR}/detail/json_ref.hpp \ + ${SRCDIR}/adl_serializer.hpp # main target all: diff --git a/src/adl_serializer.hpp b/src/adl_serializer.hpp new file mode 100644 index 00000000..c2ad371c --- /dev/null +++ b/src/adl_serializer.hpp @@ -0,0 +1,48 @@ +#ifndef NLOHMANN_JSON_ADL_SERIALIZER_HPP +#define NLOHMANN_JSON_ADL_SERIALIZER_HPP + +#include + +#include "detail/conversions/from_json.hpp" +#include "detail/conversions/to_json.hpp" + +namespace nlohmann +{ +template +struct adl_serializer +{ + /*! + @brief convert a JSON value to any value type + + This function is usually called by the `get()` function of the + @ref basic_json class (either explicit or via conversion operators). + + @param[in] j JSON value to read from + @param[in,out] val value to write to + */ + template + static void from_json(BasicJsonType&& j, ValueType& val) noexcept( + noexcept(::nlohmann::from_json(std::forward(j), val))) + { + ::nlohmann::from_json(std::forward(j), val); + } + + /*! + @brief convert any value type to a JSON value + + This function is usually called by the constructors of the @ref basic_json + class. + + @param[in,out] j JSON value to write to + @param[in] val value to read from + */ + template + static void to_json(BasicJsonType& j, ValueType&& val) noexcept( + noexcept(::nlohmann::to_json(j, std::forward(val)))) + { + ::nlohmann::to_json(j, std::forward(val)); + } +}; +} + +#endif diff --git a/src/json.hpp b/src/json.hpp index 32051d7e..4eb7ec79 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -70,6 +70,7 @@ SOFTWARE. #include "detail/parsing/binary_writer.hpp" #include "detail/serializer.hpp" #include "detail/json_ref.hpp" +#include "adl_serializer.hpp" /*! @brief namespace for Niels Lohmann @@ -78,42 +79,6 @@ SOFTWARE. */ namespace nlohmann { -template -struct adl_serializer -{ - /*! - @brief convert a JSON value to any value type - - This function is usually called by the `get()` function of the - @ref basic_json class (either explicit or via conversion operators). - - @param[in] j JSON value to read from - @param[in,out] val value to write to - */ - template - static void from_json(BasicJsonType&& j, ValueType& val) noexcept( - noexcept(::nlohmann::from_json(std::forward(j), val))) - { - ::nlohmann::from_json(std::forward(j), val); - } - - /*! - @brief convert any value type to a JSON value - - This function is usually called by the constructors of the @ref basic_json - class. - - @param[in,out] j JSON value to write to - @param[in] val value to read from - */ - template - static void to_json(BasicJsonType& j, ValueType&& val) noexcept( - noexcept(::nlohmann::to_json(j, std::forward(val)))) - { - ::nlohmann::to_json(j, std::forward(val)); - } -}; - class json_pointer { /// allow basic_json to access private members @@ -7969,7 +7934,6 @@ inline bool operator!=(json_pointer const& lhs, json_pointer const& rhs) noexcep } } // namespace nlohmann - /////////////////////// // nonmember support // /////////////////////// From 57d822b6e20b1d7c96e535a37511de56df3d3679 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20DELRIEU?= Date: Mon, 14 Aug 2017 19:28:01 +0200 Subject: [PATCH 52/59] add missing includes, put back include comments --- src/detail/conversions/from_json.hpp | 18 +++++++------ src/detail/conversions/to_json.hpp | 10 +++++--- src/detail/iterators/iter_impl.hpp | 9 +++++-- src/detail/iterators/iteration_proxy.hpp | 6 +++-- .../iterators/json_reverse_iterator.hpp | 6 ++--- src/detail/iterators/primitive_iterator.hpp | 7 +++--- src/detail/macro_scope.hpp | 2 ++ src/detail/meta.hpp | 9 ++++--- src/detail/parsing/binary_reader.hpp | 22 ++++++++++------ src/detail/parsing/binary_writer.hpp | 10 ++++---- src/detail/parsing/input_adapters.hpp | 19 +++++++++----- src/detail/parsing/lexer.hpp | 12 ++++++--- src/detail/parsing/output_adapters.hpp | 14 ++++++----- src/detail/parsing/parser.hpp | 11 +++++--- src/detail/serializer.hpp | 25 +++++++++++-------- src/detail/value_t.hpp | 5 ++-- src/json.hpp | 21 +++++----------- src/json_fwd.hpp | 4 +-- 18 files changed, 123 insertions(+), 87 deletions(-) diff --git a/src/detail/conversions/from_json.hpp b/src/detail/conversions/from_json.hpp index 471c1320..55925464 100644 --- a/src/detail/conversions/from_json.hpp +++ b/src/detail/conversions/from_json.hpp @@ -1,10 +1,16 @@ #ifndef NLOHMANN_JSON_DETAIL_CONVERSIONS_FROM_JSON_HPP #define NLOHMANN_JSON_DETAIL_CONVERSIONS_FROM_JSON_HPP -#include -#include -#include -#include +#include // transform +#include // array +#include // and, not +#include // forward_list +#include // inserter, front_inserter, end +#include // string +#include // tuple, make_tuple +#include // is_arithmetic, is_same, is_enum, underlying_type, is_convertible +#include // pair, declval +#include // valarray #include "detail/exceptions.hpp" #include "detail/macro_scope.hpp" @@ -15,10 +21,6 @@ namespace nlohmann { namespace detail { -/////////////// -// from_json // -/////////////// - // overloads for basic_json template parameters template::value and diff --git a/src/detail/conversions/to_json.hpp b/src/detail/conversions/to_json.hpp index 0c6d4749..0153b13d 100644 --- a/src/detail/conversions/to_json.hpp +++ b/src/detail/conversions/to_json.hpp @@ -1,9 +1,13 @@ #ifndef NLOHMANN_JSON_DETAIL_CONVERSIONS_TO_JSON_HPP #define NLOHMANN_JSON_DETAIL_CONVERSIONS_TO_JSON_HPP -#include -#include -#include +#include // or, and, not +#include // begin, end +#include // tuple, get +#include // is_same, is_constructible, is_floating_point, is_enum, underlying_type +#include // move, forward, declval, pair +#include // valarray +#include // vector #include "detail/meta.hpp" #include "detail/value_t.hpp" diff --git a/src/detail/iterators/iter_impl.hpp b/src/detail/iterators/iter_impl.hpp index 79b11b33..e11412c6 100644 --- a/src/detail/iterators/iter_impl.hpp +++ b/src/detail/iterators/iter_impl.hpp @@ -1,11 +1,16 @@ #ifndef NLOHMANN_JSON_DETAIL_ITERATORS_ITER_IMPL_HPP #define NLOHMANN_JSON_DETAIL_ITERATORS_ITER_IMPL_HPP -#include -#include +#include // not +#include // iterator, random_access_iterator_tag, bidirectional_iterator_tag, advance, next +#include // conditional, is_const, remove_const #include "detail/exceptions.hpp" +#include "detail/iterators/internal_iterator.hpp" +#include "detail/iterators/primitive_iterator.hpp" #include "detail/macro_scope.hpp" +#include "detail/meta.hpp" +#include "detail/value_t.hpp" namespace nlohmann { diff --git a/src/detail/iterators/iteration_proxy.hpp b/src/detail/iterators/iteration_proxy.hpp index 6a13f39d..e4ce84e4 100644 --- a/src/detail/iterators/iteration_proxy.hpp +++ b/src/detail/iterators/iteration_proxy.hpp @@ -1,8 +1,10 @@ #ifndef NLOHMANN_JSON_DETAIL_ITERATORS_ITERATION_PROXY_HPP #define NLOHMANN_JSON_DETAIL_ITERATORS_ITERATION_PROXY_HPP -#include -#include +#include // size_t +#include // string, to_string + +#include "detail/value_t.hpp" namespace nlohmann { diff --git a/src/detail/iterators/json_reverse_iterator.hpp b/src/detail/iterators/json_reverse_iterator.hpp index 52862d38..b0f4effe 100644 --- a/src/detail/iterators/json_reverse_iterator.hpp +++ b/src/detail/iterators/json_reverse_iterator.hpp @@ -1,9 +1,9 @@ #ifndef NLOHMANN_JSON_DETAIL_ITERATORS_JSON_REVERSE_ITERATOR_HPP #define NLOHMANN_JSON_DETAIL_ITERATORS_JSON_REVERSE_ITERATOR_HPP -#include -#include -#include +#include // ptrdiff_t +#include // reverse_iterator +#include // declval namespace nlohmann { diff --git a/src/detail/iterators/primitive_iterator.hpp b/src/detail/iterators/primitive_iterator.hpp index 8ebafe0e..c5cd4031 100644 --- a/src/detail/iterators/primitive_iterator.hpp +++ b/src/detail/iterators/primitive_iterator.hpp @@ -1,9 +1,10 @@ #ifndef NLOHMANN_JSON_DETAIL_ITERATORS_PRIMITIVE_ITERATOR_HPP #define NLOHMANN_JSON_DETAIL_ITERATORS_PRIMITIVE_ITERATOR_HPP -#include -#include -#include +#include // not +#include // ptrdiff_t +#include // numeric_limits +#include // ostream namespace nlohmann { diff --git a/src/detail/macro_scope.hpp b/src/detail/macro_scope.hpp index b2ac7742..f20cc667 100644 --- a/src/detail/macro_scope.hpp +++ b/src/detail/macro_scope.hpp @@ -1,6 +1,8 @@ #ifndef NLOHMANN_JSON_MACRO_SCOPE_HPP #define NLOHMANN_JSON_MACRO_SCOPE_HPP +#include // not + // This file contains all internal macro definitions // You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them diff --git a/src/detail/meta.hpp b/src/detail/meta.hpp index a9b20443..35705183 100644 --- a/src/detail/meta.hpp +++ b/src/detail/meta.hpp @@ -1,10 +1,11 @@ #ifndef NLOHMANN_JSON_DETAIL_META_HPP #define NLOHMANN_JSON_DETAIL_META_HPP -#include -#include -#include // add_pointer, conditional, decay, enable_if, false_type, integral_constant, is_arithmetic, is_base_of, is_const, is_constructible, is_convertible, is_default_constructible, is_enum, is_floating_point, is_integral, is_nothrow_move_assignable, is_nothrow_move_constructible, is_pointer, is_reference, is_same, is_scalar, is_signed, remove_const, remove_cv, remove_pointer, remove_reference, true_type, underlying_type -#include +#include // not +#include // size_t +#include // numeric_limits +#include // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type +#include // declval #include "json_fwd.hpp" #include "detail/macro_scope.hpp" diff --git a/src/detail/parsing/binary_reader.hpp b/src/detail/parsing/binary_reader.hpp index 0d8ce4ad..a1195393 100644 --- a/src/detail/parsing/binary_reader.hpp +++ b/src/detail/parsing/binary_reader.hpp @@ -1,14 +1,20 @@ #ifndef NLOHMANN_JSON_DETAIL_PARSING_BINARY_READER_HPP #define NLOHMANN_JSON_DETAIL_PARSING_BINARY_READER_HPP -#include -#include -#include -#include -#include -#include -#include -#include +#include // generate_n +#include // array +#include // assert +#include // ldexp +#include // size_t +#include // uint8_t, uint16_t, uint32_t, uint64_t +#include // memcpy +#include // setw, setfill +#include // hex +#include // back_inserter +#include // numeric_limits +#include // stringstream +#include // char_traits, string +#include // make_pair, move #include "detail/exceptions.hpp" #include "detail/macro_scope.hpp" diff --git a/src/detail/parsing/binary_writer.hpp b/src/detail/parsing/binary_writer.hpp index 25badd89..59583b9c 100644 --- a/src/detail/parsing/binary_writer.hpp +++ b/src/detail/parsing/binary_writer.hpp @@ -1,11 +1,11 @@ #ifndef NLOHMANN_JSON_DETAIL_PARSING_BINARY_WRITER_HPP #define NLOHMANN_JSON_DETAIL_PARSING_BINARY_WRITER_HPP -#include -#include -#include -#include -#include +#include // reverse +#include // array +#include // uint8_t, uint16_t, uint32_t, uint64_t +#include // memcpy +#include // numeric_limits #include "detail/parsing/binary_reader.hpp" #include "detail/parsing/output_adapters.hpp" diff --git a/src/detail/parsing/input_adapters.hpp b/src/detail/parsing/input_adapters.hpp index 17cf5892..7d4f2dee 100644 --- a/src/detail/parsing/input_adapters.hpp +++ b/src/detail/parsing/input_adapters.hpp @@ -1,12 +1,19 @@ #ifndef NLOHMANN_JSON_DETAIL_PARSING_INPUT_ADAPTERS_HPP #define NLOHMANN_JSON_DETAIL_PARSING_INPUT_ADAPTERS_HPP -#include -#include -#include -#include -#include -#include +#include // min +#include // array +#include // assert +#include // size_t +#include // strlen +#include // streamsize, streamoff, streampos +#include // istream +#include // begin, end, iterator_traits, random_access_iterator_tag, distance, next +#include // shared_ptr, make_shared, addressof +#include // accumulate +#include // string, char_traits +#include // enable_if, is_base_of, is_pointer, is_integral, remove_pointer +#include // pair, declval #include "detail/macro_scope.hpp" diff --git a/src/detail/parsing/lexer.hpp b/src/detail/parsing/lexer.hpp index b1232db0..f50b0521 100644 --- a/src/detail/parsing/lexer.hpp +++ b/src/detail/parsing/lexer.hpp @@ -1,9 +1,15 @@ #ifndef NLOHMANN_JSON_DETAIL_PARSING_LEXER_HPP #define NLOHMANN_JSON_DETAIL_PARSING_LEXER_HPP -#include -#include -#include +#include // localeconv +#include // size_t +#include // strtof, strtod, strtold, strtoll, strtoull +#include // initializer_list +#include // hex, uppercase +#include // setw, setfill +#include // stringstream +#include // char_traits, string +#include // vector #include "detail/macro_scope.hpp" #include "detail/parsing/input_adapters.hpp" diff --git a/src/detail/parsing/output_adapters.hpp b/src/detail/parsing/output_adapters.hpp index 5cbc11b9..71099038 100644 --- a/src/detail/parsing/output_adapters.hpp +++ b/src/detail/parsing/output_adapters.hpp @@ -1,12 +1,14 @@ #ifndef NLOHMANN_JSON_DETAIL_PARSING_OUTPUT_ADAPTERS_HPP #define NLOHMANN_JSON_DETAIL_PARSING_OUTPUT_ADAPTERS_HPP -#include -#include -#include -#include -#include -#include +#include // copy +#include // size_t +#include // streamsize +#include // back_inserter +#include // shared_ptr, make_shared +#include // basic_ostream +#include // basic_string +#include // vector namespace nlohmann { diff --git a/src/detail/parsing/parser.hpp b/src/detail/parsing/parser.hpp index c82c2f6d..52a9c4fe 100644 --- a/src/detail/parsing/parser.hpp +++ b/src/detail/parsing/parser.hpp @@ -1,15 +1,18 @@ #ifndef NLOHMANN_JSON_DETAIL_PARSING_PARSER_HPP #define NLOHMANN_JSON_DETAIL_PARSING_PARSER_HPP -#include -#include -#include -#include +#include // assert +#include // isfinite +#include // uint8_t +#include // function +#include // string +#include // move #include "detail/exceptions.hpp" #include "detail/macro_scope.hpp" #include "detail/parsing/input_adapters.hpp" #include "detail/parsing/lexer.hpp" +#include "detail/value_t.hpp" namespace nlohmann { diff --git a/src/detail/serializer.hpp b/src/detail/serializer.hpp index 955a3eac..0d3303d9 100644 --- a/src/detail/serializer.hpp +++ b/src/detail/serializer.hpp @@ -1,21 +1,24 @@ #ifndef NLOHMANN_JSON_DETAIL_SERIALIZER_HPP #define NLOHMANN_JSON_DETAIL_SERIALIZER_HPP -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include // reverse, remove, fill, find, none_of +#include // array +#include // assert +#include // and, or +#include // localeconv, lconv +#include // labs, isfinite, isnan, signbit +#include // size_t, ptrdiff_t +#include // uint8_t +#include // snprintf +#include // next +#include // numeric_limits +#include // string +#include // is_same #include "detail/macro_scope.hpp" #include "detail/meta.hpp" #include "detail/parsing/output_adapters.hpp" +#include "detail/value_t.hpp" namespace nlohmann { diff --git a/src/detail/value_t.hpp b/src/detail/value_t.hpp index dbfffd47..b96f294b 100644 --- a/src/detail/value_t.hpp +++ b/src/detail/value_t.hpp @@ -1,6 +1,7 @@ #ifndef NLOHMANN_JSON_DETAIL_VALUE_T_HPP #define NLOHMANN_JSON_DETAIL_VALUE_T_HPP +#include // array #include // and #include // size_t #include // uint8_t @@ -37,7 +38,7 @@ value with the default value for a given type @since version 1.0.0 */ -enum class value_t : uint8_t +enum class value_t : std::uint8_t { null, ///< null value object, ///< object (unordered set of name/value pairs) @@ -62,7 +63,7 @@ Returns an ordering that is similar to Python: */ inline bool operator<(const value_t lhs, const value_t rhs) noexcept { - static constexpr std::array order = {{ + static constexpr std::array order = {{ 0 /* null */, 3 /* object */, 4 /* array */, 5 /* string */, 1 /* boolean */, 2 /* integer */, 2 /* unsigned */, 2 /* float */ } diff --git a/src/json.hpp b/src/json.hpp index 4eb7ec79..f4c139e4 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -29,26 +29,17 @@ SOFTWARE. #ifndef NLOHMANN_JSON_HPP #define NLOHMANN_JSON_HPP -#include // all_of, copy, fill, find, for_each, generate_n, none_of, remove, reverse, transform -#include // array +#include // all_of, find, for_each #include // assert #include // and, not, or -#include // lconv, localeconv -#include // isfinite, labs, ldexp, signbit #include // nullptr_t, ptrdiff_t, size_t -#include // abort, strtod, strtof, strtold, strtoul, strtoll, strtoull -#include // memcpy, strlen -#include // forward_list -#include // function, hash, less +#include // hash, less #include // initializer_list -#include // hex -#include // istream, ostream -#include // advance, begin, back_inserter, bidirectional_iterator_tag, distance, end, inserter, iterator, iterator_traits, next, random_access_iterator_tag, reverse_iterator -#include // numeric_limits -#include // locale +#include // istream, ostream +#include // iterator_traits, random_access_iterator_tag #include // accumulate -#include // stringstream -#include // declval, forward, make_pair, move, pair, swap +#include // string, stoi, to_string +#include // declval, forward, move, pair, swap #include "json_fwd.hpp" #include "detail/macro_scope.hpp" diff --git a/src/json_fwd.hpp b/src/json_fwd.hpp index a068da18..f2a6b0f2 100644 --- a/src/json_fwd.hpp +++ b/src/json_fwd.hpp @@ -3,8 +3,8 @@ #include // int64_t, uint64_t #include // map -#include // addressof, allocator, allocator_traits, unique_ptr -#include // getline, stoi, string, to_string +#include // allocator +#include // string #include // vector /*! From 7e4ee23f4078b424dd4eae6b5dfff5f549eb1cf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20DELRIEU?= Date: Mon, 14 Aug 2017 20:45:33 +0200 Subject: [PATCH 53/59] add single_header CMake target --- .gitignore | 3 + CMakeLists.txt | 21 +- Makefile | 53 +- single_header/json.hpp | 19067 +++++++++++++++++++++++++++++++++++++++ test/Makefile | 2 +- 5 files changed, 19119 insertions(+), 27 deletions(-) create mode 100644 single_header/json.hpp diff --git a/.gitignore b/.gitignore index 8157f1a9..bfd2e6ee 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,6 @@ benchmarks/files/numbers/*.json cmake-build-debug test/test-* +amalgamate +single_include +third_party/Amalgamate diff --git a/CMakeLists.txt b/CMakeLists.txt index 257bee82..9cbe3501 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,6 +6,12 @@ cmake_minimum_required(VERSION 3.0.0) ## project(nlohmann_json VERSION 3.0.1 LANGUAGES CXX) +## +## INCLUDE +## +## +include(ExternalProject) + ## ## OPTIONS ## @@ -15,7 +21,7 @@ option(JSON_BuildTests "Build the unit tests when BUILD_TESTING is enabled." ON) ## CONFIGURATION ## set(NLOHMANN_JSON_TARGET_NAME ${PROJECT_NAME}) -set(NLOHMANN_JSON_SOURCE_DIR "src/") +set(NLOHMANN_JSON_SOURCE_DIR "src") set(NLOHMANN_JSON_CONFIG_INSTALL_DIR "lib/cmake/${PROJECT_NAME}") set(NLOHMANN_JSON_INCLUDE_INSTALL_DIR "include") set(NLOHMANN_JSON_HEADER_INSTALL_DIR "${NLOHMANN_JSON_INCLUDE_INSTALL_DIR}/nlohmann") @@ -62,6 +68,19 @@ if(BUILD_TESTING AND JSON_BuildTests) add_subdirectory(test) endif() +ExternalProject_Add(amalgamate + GIT_REPOSITORY "https://github.com/theodelrieu/Amalgamate" + CMAKE_ARGS "-DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR}" +) + +# There is no way to tell amalgamate to force-write the output file even if it already exists... +add_custom_target(single_header ALL rm -f "${CMAKE_SOURCE_DIR}/single_header/json.hpp" + COMMENT "Amalgamating json.hpp..." + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/${NLOHMANN_JSON_SOURCE_DIR} + DEPENDS amalgamate + COMMAND "${CMAKE_BINARY_DIR}/bin/amalgamate" -w '*.hpp' -i . json.hpp "${CMAKE_SOURCE_DIR}/single_header/json.hpp" +) + ## ## INSTALL ## install header files, generate and install cmake config files for find_package() diff --git a/Makefile b/Makefile index 289080c7..8165aa9f 100644 --- a/Makefile +++ b/Makefile @@ -1,29 +1,32 @@ .PHONY: pretty clean ChangeLog.md -SRCDIR = src -SRCS = ${SRCDIR}/json.hpp \ - ${SRCDIR}/json_fwd.hpp \ - ${SRCDIR}/detail/macro_scope.hpp \ - ${SRCDIR}/detail/macro_unscope.hpp \ - ${SRCDIR}/detail/meta.hpp \ - ${SRCDIR}/detail/exceptions.hpp \ - ${SRCDIR}/detail/value_t.hpp \ - ${SRCDIR}/detail/conversions/from_json.hpp \ - ${SRCDIR}/detail/conversions/to_json.hpp \ - ${SRCDIR}/detail/parsing/input_adapters.hpp \ - ${SRCDIR}/detail/parsing/lexer.hpp \ - ${SRCDIR}/detail/parsing/parser.hpp \ - ${SRCDIR}/detail/iterators/primitive_iterator.hpp \ - ${SRCDIR}/detail/iterators/internal_iterator.hpp \ - ${SRCDIR}/detail/iterators/iter_impl.hpp \ - ${SRCDIR}/detail/iterators/iteration_proxy.hpp \ - ${SRCDIR}/detail/iterators/json_reverse_iterator.hpp \ - ${SRCDIR}/detail/parsing/output_adapters.hpp \ - ${SRCDIR}/detail/parsing/binary_reader.hpp \ - ${SRCDIR}/detail/parsing/binary_writer.hpp \ - ${SRCDIR}/detail/serializer.hpp \ - ${SRCDIR}/detail/json_ref.hpp \ - ${SRCDIR}/adl_serializer.hpp +SRCDIR = ./src +SRCS = $(SRCDIR)/json.hpp \ + $(SRCDIR)/json_fwd.hpp \ + $(SRCDIR)/detail/macro_scope.hpp \ + $(SRCDIR)/detail/macro_unscope.hpp \ + $(SRCDIR)/detail/meta.hpp \ + $(SRCDIR)/detail/exceptions.hpp \ + $(SRCDIR)/detail/value_t.hpp \ + $(SRCDIR)/detail/conversions/from_json.hpp \ + $(SRCDIR)/detail/conversions/to_json.hpp \ + $(SRCDIR)/detail/parsing/input_adapters.hpp \ + $(SRCDIR)/detail/parsing/lexer.hpp \ + $(SRCDIR)/detail/parsing/parser.hpp \ + $(SRCDIR)/detail/iterators/primitive_iterator.hpp \ + $(SRCDIR)/detail/iterators/internal_iterator.hpp \ + $(SRCDIR)/detail/iterators/iter_impl.hpp \ + $(SRCDIR)/detail/iterators/iteration_proxy.hpp \ + $(SRCDIR)/detail/iterators/json_reverse_iterator.hpp \ + $(SRCDIR)/detail/parsing/output_adapters.hpp \ + $(SRCDIR)/detail/parsing/binary_reader.hpp \ + $(SRCDIR)/detail/parsing/binary_writer.hpp \ + $(SRCDIR)/detail/serializer.hpp \ + $(SRCDIR)/detail/json_ref.hpp \ + $(SRCDIR)/adl_serializer.hpp + +UNAME = $(shell uname) +CXX=clang++ # main target all: @@ -42,7 +45,6 @@ all: @echo "pedantic_gcc - run GCC with maximal warning flags" @echo "pretty - beautify code with Artistic Style" - ########################################################################## # unit tests ########################################################################## @@ -247,6 +249,7 @@ pretty: $(SRCS) test/src/*.cpp \ benchmarks/src/benchmarks.cpp doc/examples/*.cpp + ########################################################################## # changelog ########################################################################## diff --git a/single_header/json.hpp b/single_header/json.hpp new file mode 100644 index 00000000..e6fe5fc1 --- /dev/null +++ b/single_header/json.hpp @@ -0,0 +1,19067 @@ +/* + __ _____ _____ _____ + __| | __| | | | JSON for Modern C++ +| | |__ | | | | | | version 3.0.0 +|_____|_____|_____|_|___| https://github.com/nlohmann/json + +Licensed under the MIT License . +Copyright (c) 2013-2017 Niels Lohmann . + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#ifndef NLOHMANN_JSON_HPP +#define NLOHMANN_JSON_HPP + +#include // all_of, find, for_each +#include // assert +#include // and, not, or +#include // nullptr_t, ptrdiff_t, size_t +#include // hash, less +#include // initializer_list +#include // istream, ostream +#include // iterator_traits, random_access_iterator_tag +#include // accumulate +#include // string, stoi, to_string +#include // declval, forward, move, pair, swap + + +/*** Start of inlined file: json_fwd.hpp ***/ +#ifndef NLOHMANN_JSON_FWD_HPP +#define NLOHMANN_JSON_FWD_HPP + +#include // int64_t, uint64_t +#include // map +#include // allocator +#include // string +#include // vector + +/*! +@brief namespace for Niels Lohmann +@see https://github.com/nlohmann +@since version 1.0.0 +*/ +namespace nlohmann +{ +/*! +@brief default JSONSerializer template argument + +This serializer ignores the template arguments and uses ADL +([argument-dependent lookup](http://en.cppreference.com/w/cpp/language/adl)) +for serialization. +*/ +template +struct adl_serializer; + +template class ObjectType = + std::map, + template class ArrayType = std::vector, + class StringType = std::string, class BooleanType = bool, + class NumberIntegerType = std::int64_t, + class NumberUnsignedType = std::uint64_t, + class NumberFloatType = double, + template class AllocatorType = std::allocator, + template class JSONSerializer = + adl_serializer> +class basic_json; + +/*! +@brief JSON Pointer + +A JSON pointer defines a string syntax for identifying a specific value +within a JSON document. It can be used with functions `at` and +`operator[]`. Furthermore, JSON pointers are the base for JSON patches. + +@sa [RFC 6901](https://tools.ietf.org/html/rfc6901) + +@since version 2.0.0 +*/ +class json_pointer; + +/*! +@brief default JSON class + +This type is the default specialization of the @ref basic_json class which +uses the standard template types. + +@since version 1.0.0 +*/ +using json = basic_json<>; +} + +#endif + +/*** End of inlined file: json_fwd.hpp ***/ + + +/*** Start of inlined file: macro_scope.hpp ***/ +#ifndef NLOHMANN_JSON_MACRO_SCOPE_HPP +#define NLOHMANN_JSON_MACRO_SCOPE_HPP + +#include // not + +// This file contains all internal macro definitions +// You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them + +// exclude unsupported compilers +#if defined(__clang__) + #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400 + #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" + #endif +#elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER)) + #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40900 + #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" + #endif +#endif + +// disable float-equal warnings on GCC/clang +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wfloat-equal" +#endif + +// disable documentation warnings on clang +#if defined(__clang__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wdocumentation" +#endif + +// allow for portable deprecation warnings +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #define JSON_DEPRECATED __attribute__((deprecated)) +#elif defined(_MSC_VER) + #define JSON_DEPRECATED __declspec(deprecated) +#else + #define JSON_DEPRECATED +#endif + +// allow to disable exceptions +#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && not defined(JSON_NOEXCEPTION) + #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 + +// manual branch prediction +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #define JSON_LIKELY(x) __builtin_expect(!!(x), 1) + #define JSON_UNLIKELY(x) __builtin_expect(!!(x), 0) +#else + #define JSON_LIKELY(x) x + #define JSON_UNLIKELY(x) x +#endif + +// C++ language standard detection +#if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 + #define JSON_HAS_CPP_17 + #define JSON_HAS_CPP_14 +#elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) + #define JSON_HAS_CPP_14 +#endif + +// Ugly macros to avoid uglier copy-paste when specializing basic_json. They +// may be removed in the future once the class is split. + +#define NLOHMANN_BASIC_JSON_TPL_DECLARATION \ + template class ObjectType, \ + template class ArrayType, \ + class StringType, class BooleanType, class NumberIntegerType, \ + class NumberUnsignedType, class NumberFloatType, \ + template class AllocatorType, \ + template class JSONSerializer> + +#define NLOHMANN_BASIC_JSON_TPL \ + basic_json + +/*! +@brief Helper to determine whether there's a key_type for T. + +This helper is used to tell associative containers apart from other containers +such as sequence containers. For instance, `std::map` passes the test as it +contains a `mapped_type`, whereas `std::vector` fails the test. + +@sa http://stackoverflow.com/a/7728728/266378 +@since version 1.0.0, overworked in version 2.0.6 +*/ +#define NLOHMANN_JSON_HAS_HELPER(type) \ + template struct has_##type { \ + private: \ + template \ + static int detect(U &&); \ + static void detect(...); \ + public: \ + static constexpr bool value = \ + std::is_integral()))>::value; \ + } + +#endif + +/*** End of inlined file: macro_scope.hpp ***/ + + +/*** Start of inlined file: meta.hpp ***/ +#ifndef NLOHMANN_JSON_DETAIL_META_HPP +#define NLOHMANN_JSON_DETAIL_META_HPP + +#include // not +#include // size_t +#include // numeric_limits +#include // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type +#include // declval + + +/*** Start of inlined file: json_fwd.hpp ***/ +#ifndef NLOHMANN_JSON_FWD_HPP +#define NLOHMANN_JSON_FWD_HPP + +#include // int64_t, uint64_t +#include // map +#include // allocator +#include // string +#include // vector + +/*! +@brief namespace for Niels Lohmann +@see https://github.com/nlohmann +@since version 1.0.0 +*/ +namespace nlohmann +{ +/*! +@brief default JSONSerializer template argument + +This serializer ignores the template arguments and uses ADL +([argument-dependent lookup](http://en.cppreference.com/w/cpp/language/adl)) +for serialization. +*/ +template +struct adl_serializer; + +template class ObjectType = + std::map, + template class ArrayType = std::vector, + class StringType = std::string, class BooleanType = bool, + class NumberIntegerType = std::int64_t, + class NumberUnsignedType = std::uint64_t, + class NumberFloatType = double, + template class AllocatorType = std::allocator, + template class JSONSerializer = + adl_serializer> +class basic_json; + +/*! +@brief JSON Pointer + +A JSON pointer defines a string syntax for identifying a specific value +within a JSON document. It can be used with functions `at` and +`operator[]`. Furthermore, JSON pointers are the base for JSON patches. + +@sa [RFC 6901](https://tools.ietf.org/html/rfc6901) + +@since version 2.0.0 +*/ +class json_pointer; + +/*! +@brief default JSON class + +This type is the default specialization of the @ref basic_json class which +uses the standard template types. + +@since version 1.0.0 +*/ +using json = basic_json<>; +} + +#endif + +/*** End of inlined file: json_fwd.hpp ***/ + + +/*** Start of inlined file: macro_scope.hpp ***/ +#ifndef NLOHMANN_JSON_MACRO_SCOPE_HPP +#define NLOHMANN_JSON_MACRO_SCOPE_HPP + +#include // not + +// This file contains all internal macro definitions +// You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them + +// exclude unsupported compilers +#if defined(__clang__) + #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400 + #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" + #endif +#elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER)) + #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40900 + #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" + #endif +#endif + +// disable float-equal warnings on GCC/clang +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wfloat-equal" +#endif + +// disable documentation warnings on clang +#if defined(__clang__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wdocumentation" +#endif + +// allow for portable deprecation warnings +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #define JSON_DEPRECATED __attribute__((deprecated)) +#elif defined(_MSC_VER) + #define JSON_DEPRECATED __declspec(deprecated) +#else + #define JSON_DEPRECATED +#endif + +// allow to disable exceptions +#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && not defined(JSON_NOEXCEPTION) + #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 + +// manual branch prediction +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #define JSON_LIKELY(x) __builtin_expect(!!(x), 1) + #define JSON_UNLIKELY(x) __builtin_expect(!!(x), 0) +#else + #define JSON_LIKELY(x) x + #define JSON_UNLIKELY(x) x +#endif + +// C++ language standard detection +#if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 + #define JSON_HAS_CPP_17 + #define JSON_HAS_CPP_14 +#elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) + #define JSON_HAS_CPP_14 +#endif + +// Ugly macros to avoid uglier copy-paste when specializing basic_json. They +// may be removed in the future once the class is split. + +#define NLOHMANN_BASIC_JSON_TPL_DECLARATION \ + template class ObjectType, \ + template class ArrayType, \ + class StringType, class BooleanType, class NumberIntegerType, \ + class NumberUnsignedType, class NumberFloatType, \ + template class AllocatorType, \ + template class JSONSerializer> + +#define NLOHMANN_BASIC_JSON_TPL \ + basic_json + +/*! +@brief Helper to determine whether there's a key_type for T. + +This helper is used to tell associative containers apart from other containers +such as sequence containers. For instance, `std::map` passes the test as it +contains a `mapped_type`, whereas `std::vector` fails the test. + +@sa http://stackoverflow.com/a/7728728/266378 +@since version 1.0.0, overworked in version 2.0.6 +*/ +#define NLOHMANN_JSON_HAS_HELPER(type) \ + template struct has_##type { \ + private: \ + template \ + static int detect(U &&); \ + static void detect(...); \ + public: \ + static constexpr bool value = \ + std::is_integral()))>::value; \ + } + +#endif + +/*** End of inlined file: macro_scope.hpp ***/ + +namespace nlohmann +{ +/*! +@brief detail namespace with internal helper functions + +This namespace collects functions that should not be exposed, +implementations of some @ref basic_json methods, and meta-programming helpers. + +@since version 2.1.0 +*/ +namespace detail +{ +///////////// +// helpers // +///////////// + +template struct is_basic_json : std::false_type {}; + +NLOHMANN_BASIC_JSON_TPL_DECLARATION +struct is_basic_json : std::true_type {}; + +// alias templates to reduce boilerplate +template +using enable_if_t = typename std::enable_if::type; + +template +using uncvref_t = typename std::remove_cv::type>::type; + +// implementation of C++14 index_sequence and affiliates +// source: https://stackoverflow.com/a/32223343 +template +struct index_sequence +{ + using type = index_sequence; + using value_type = std::size_t; + static constexpr std::size_t size() noexcept + { + return sizeof...(Ints); + } +}; + +template +struct merge_and_renumber; + +template +struct merge_and_renumber, index_sequence> + : index_sequence < I1..., (sizeof...(I1) + I2)... > {}; + +template +struct make_index_sequence + : merge_and_renumber < typename make_index_sequence < N / 2 >::type, + typename make_index_sequence < N - N / 2 >::type > {}; + +template<> struct make_index_sequence<0> : index_sequence<> {}; +template<> struct make_index_sequence<1> : index_sequence<0> {}; + +template +using index_sequence_for = make_index_sequence; + +/* +Implementation of two C++17 constructs: conjunction, negation. This is needed +to avoid evaluating all the traits in a condition + +For example: not std::is_same::value and has_value_type::value +will not compile when T = void (on MSVC at least). Whereas +conjunction>, has_value_type>::value will +stop evaluating if negation<...>::value == false + +Please note that those constructs must be used with caution, since symbols can +become very long quickly (which can slow down compilation and cause MSVC +internal compiler errors). Only use it when you have to (see example ahead). +*/ +template struct conjunction : std::true_type {}; +template struct conjunction : B1 {}; +template +struct conjunction : std::conditional, B1>::type {}; + +template struct negation : std::integral_constant {}; + +// dispatch utility (taken from ranges-v3) +template struct priority_tag : priority_tag < N - 1 > {}; +template<> struct priority_tag<0> {}; + +//////////////////////// +// has_/is_ functions // +//////////////////////// + +NLOHMANN_JSON_HAS_HELPER(mapped_type); +NLOHMANN_JSON_HAS_HELPER(key_type); +NLOHMANN_JSON_HAS_HELPER(value_type); +NLOHMANN_JSON_HAS_HELPER(iterator); + +template +struct is_compatible_object_type_impl : std::false_type {}; + +template +struct is_compatible_object_type_impl +{ + static constexpr auto value = + std::is_constructible::value and + std::is_constructible::value; +}; + +template +struct is_compatible_object_type +{ + static auto constexpr value = is_compatible_object_type_impl < + conjunction>, + has_mapped_type, + has_key_type>::value, + typename BasicJsonType::object_t, CompatibleObjectType >::value; +}; + +template +struct is_basic_json_nested_type +{ + static auto constexpr value = std::is_same::value or + std::is_same::value or + std::is_same::value or + std::is_same::value; +}; + +template +struct is_compatible_array_type +{ + static auto constexpr value = + conjunction>, + negation>, + negation>, + negation>, + has_value_type, + has_iterator>::value; +}; + +template +struct is_compatible_integer_type_impl : std::false_type {}; + +template +struct is_compatible_integer_type_impl +{ + // is there an assert somewhere on overflows? + using RealLimits = std::numeric_limits; + using CompatibleLimits = std::numeric_limits; + + static constexpr auto value = + std::is_constructible::value and + CompatibleLimits::is_integer and + RealLimits::is_signed == CompatibleLimits::is_signed; +}; + +template +struct is_compatible_integer_type +{ + static constexpr auto value = + is_compatible_integer_type_impl < + std::is_integral::value and + not std::is_same::value, + RealIntegerType, CompatibleNumberIntegerType > ::value; +}; + +// trait checking if JSONSerializer::from_json(json const&, udt&) exists +template +struct has_from_json +{ + private: + // also check the return type of from_json + template::from_json( + std::declval(), std::declval()))>::value>> + static int detect(U&&); + static void detect(...); + + public: + static constexpr bool value = std::is_integral>()))>::value; +}; + +// This trait checks if JSONSerializer::from_json(json const&) exists +// this overload is used for non-default-constructible user-defined-types +template +struct has_non_default_from_json +{ + private: + template < + typename U, + typename = enable_if_t::from_json(std::declval()))>::value >> + static int detect(U&&); + static void detect(...); + + public: + static constexpr bool value = std::is_integral>()))>::value; +}; + +// This trait checks if BasicJsonType::json_serializer::to_json exists +template +struct has_to_json +{ + private: + template::to_json( + std::declval(), std::declval()))> + static int detect(U&&); + static void detect(...); + + public: + static constexpr bool value = std::is_integral>()))>::value; +}; + +// taken from ranges-v3 +template +struct static_const +{ + static constexpr T value{}; +}; + +template +constexpr T static_const::value; +} +} + +#endif + +/*** End of inlined file: meta.hpp ***/ + + +/*** Start of inlined file: exceptions.hpp ***/ +#ifndef NLOHMANN_JSON_DETAIL_EXCEPTIONS_HPP +#define NLOHMANN_JSON_DETAIL_EXCEPTIONS_HPP + +#include // exception +#include // runtime_error +#include // to_string + +namespace nlohmann +{ +namespace detail +{ +//////////////// +// exceptions // +//////////////// + +/*! +@brief general exception of the @ref basic_json class + +This class is an extension of `std::exception` objects with a member @a id for +exception ids. It is used as the base class for all exceptions thrown by the +@ref basic_json class. This class can hence be used as "wildcard" to catch +exceptions. + +Subclasses: +- @ref parse_error for exceptions indicating a parse error +- @ref invalid_iterator for exceptions indicating errors with iterators +- @ref type_error for exceptions indicating executing a member function with + a wrong type +- @ref out_of_range for exceptions indicating access out of the defined range +- @ref other_error for exceptions indicating other library errors + +@internal +@note To have nothrow-copy-constructible exceptions, we internally use + `std::runtime_error` which can cope with arbitrary-length error messages. + Intermediate strings are built with static functions and then passed to + the actual constructor. +@endinternal + +@liveexample{The following code shows how arbitrary library exceptions can be +caught.,exception} + +@since version 3.0.0 +*/ +class exception : public std::exception +{ + public: + /// returns the explanatory string + const char* what() const noexcept override + { + return m.what(); + } + + /// the id of the exception + const int id; + + protected: + exception(int id_, const char* what_arg) : id(id_), m(what_arg) {} + + static std::string name(const std::string& ename, int id_) + { + return "[json.exception." + ename + "." + std::to_string(id_) + "] "; + } + + private: + /// an exception object as storage for error messages + std::runtime_error m; +}; + +/*! +@brief exception indicating a parse error + +This exception is thrown by the library when a parse error occurs. Parse errors +can occur during the deserialization of JSON text, CBOR, MessagePack, as well +as when using JSON Patch. + +Member @a byte holds the byte index of the last read character in the input +file. + +Exceptions have ids 1xx. + +name / id | example message | description +------------------------------ | --------------- | ------------------------- +json.exception.parse_error.101 | parse error at 2: unexpected end of input; expected string literal | This error indicates a syntax error while deserializing a JSON text. The error message describes that an unexpected token (character) was encountered, and the member @a byte indicates the error position. +json.exception.parse_error.102 | parse error at 14: missing or wrong low surrogate | JSON uses the `\uxxxx` format to describe Unicode characters. Code points above above 0xFFFF are split into two `\uxxxx` entries ("surrogate pairs"). This error indicates that the surrogate pair is incomplete or contains an invalid code point. +json.exception.parse_error.103 | parse error: code points above 0x10FFFF are invalid | Unicode supports code points up to 0x10FFFF. Code points above 0x10FFFF are invalid. +json.exception.parse_error.104 | parse error: JSON patch must be an array of objects | [RFC 6902](https://tools.ietf.org/html/rfc6902) requires a JSON Patch document to be a JSON document that represents an array of objects. +json.exception.parse_error.105 | parse error: operation must have string member 'op' | An operation of a JSON Patch document must contain exactly one "op" member, whose value indicates the operation to perform. Its value must be one of "add", "remove", "replace", "move", "copy", or "test"; other values are errors. +json.exception.parse_error.106 | parse error: array index '01' must not begin with '0' | An array index in a JSON Pointer ([RFC 6901](https://tools.ietf.org/html/rfc6901)) may be `0` or any number without a leading `0`. +json.exception.parse_error.107 | parse error: JSON pointer must be empty or begin with '/' - was: 'foo' | A JSON Pointer must be a Unicode string containing a sequence of zero or more reference tokens, each prefixed by a `/` character. +json.exception.parse_error.108 | parse error: escape character '~' must be followed with '0' or '1' | In a JSON Pointer, only `~0` and `~1` are valid escape sequences. +json.exception.parse_error.109 | parse error: array index 'one' is not a number | A JSON Pointer array index must be a number. +json.exception.parse_error.110 | parse error at 1: cannot read 2 bytes from vector | When parsing CBOR or MessagePack, the byte vector ends before the complete value has been read. +json.exception.parse_error.112 | parse error at 1: error reading CBOR; last byte: 0xF8 | Not all types of CBOR or MessagePack are supported. This exception occurs if an unsupported byte was read. +json.exception.parse_error.113 | parse error at 2: expected a CBOR string; last byte: 0x98 | While parsing a map key, a value that is not a string has been read. + +@note For an input with n bytes, 1 is the index of the first character and n+1 + is the index of the terminating null byte or the end of file. This also + holds true when reading a byte vector (CBOR or MessagePack). + +@liveexample{The following code shows how a `parse_error` exception can be +caught.,parse_error} + +@sa @ref exception for the base class of the library exceptions +@sa @ref invalid_iterator for exceptions indicating errors with iterators +@sa @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa @ref out_of_range for exceptions indicating access out of the defined range +@sa @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class parse_error : public exception +{ + public: + /*! + @brief create a parse error exception + @param[in] id_ the id of the exception + @param[in] byte_ the byte index where the error occurred (or 0 if the + position cannot be determined) + @param[in] what_arg the explanatory string + @return parse_error object + */ + static parse_error create(int id_, std::size_t byte_, const std::string& what_arg) + { + std::string w = exception::name("parse_error", id_) + "parse error" + + (byte_ != 0 ? (" at " + std::to_string(byte_)) : "") + + ": " + what_arg; + return parse_error(id_, byte_, w.c_str()); + } + + /*! + @brief byte index of the parse error + + The byte index of the last read character in the input file. + + @note For an input with n bytes, 1 is the index of the first character and + n+1 is the index of the terminating null byte or the end of file. + This also holds true when reading a byte vector (CBOR or MessagePack). + */ + const std::size_t byte; + + private: + parse_error(int id_, std::size_t byte_, const char* what_arg) + : exception(id_, what_arg), byte(byte_) {} +}; + +/*! +@brief exception indicating errors with iterators + +This exception is thrown if iterators passed to a library function do not match +the expected semantics. + +Exceptions have ids 2xx. + +name / id | example message | description +----------------------------------- | --------------- | ------------------------- +json.exception.invalid_iterator.201 | iterators are not compatible | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. +json.exception.invalid_iterator.202 | iterator does not fit current value | In an erase or insert function, the passed iterator @a pos does not belong to the JSON value for which the function was called. It hence does not define a valid position for the deletion/insertion. +json.exception.invalid_iterator.203 | iterators do not fit current value | Either iterator passed to function @ref erase(IteratorType first, IteratorType last) does not belong to the JSON value from which values shall be erased. It hence does not define a valid range to delete values from. +json.exception.invalid_iterator.204 | iterators out of range | When an iterator range for a primitive type (number, boolean, or string) is passed to a constructor or an erase function, this range has to be exactly (@ref begin(), @ref end()), because this is the only way the single stored value is expressed. All other ranges are invalid. +json.exception.invalid_iterator.205 | iterator out of range | When an iterator for a primitive type (number, boolean, or string) is passed to an erase function, the iterator has to be the @ref begin() iterator, because it is the only way to address the stored value. All other iterators are invalid. +json.exception.invalid_iterator.206 | cannot construct with iterators from null | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) belong to a JSON null value and hence to not define a valid range. +json.exception.invalid_iterator.207 | cannot use key() for non-object iterators | The key() member function can only be used on iterators belonging to a JSON object, because other types do not have a concept of a key. +json.exception.invalid_iterator.208 | cannot use operator[] for object iterators | The operator[] to specify a concrete offset cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. +json.exception.invalid_iterator.209 | cannot use offsets with object iterators | The offset operators (+, -, +=, -=) cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. +json.exception.invalid_iterator.210 | iterators do not fit | The iterator range passed to the insert function are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. +json.exception.invalid_iterator.211 | passed iterators may not belong to container | The iterator range passed to the insert function must not be a subrange of the container to insert to. +json.exception.invalid_iterator.212 | cannot compare iterators of different containers | When two iterators are compared, they must belong to the same container. +json.exception.invalid_iterator.213 | cannot compare order of object iterators | The order of object iterators cannot be compared, because JSON objects are unordered. +json.exception.invalid_iterator.214 | cannot get value | Cannot get value for iterator: Either the iterator belongs to a null value or it is an iterator to a primitive type (number, boolean, or string), but the iterator is different to @ref begin(). + +@liveexample{The following code shows how an `invalid_iterator` exception can be +caught.,invalid_iterator} + +@sa @ref exception for the base class of the library exceptions +@sa @ref parse_error for exceptions indicating a parse error +@sa @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa @ref out_of_range for exceptions indicating access out of the defined range +@sa @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class invalid_iterator : public exception +{ + public: + static invalid_iterator create(int id_, const std::string& what_arg) + { + std::string w = exception::name("invalid_iterator", id_) + what_arg; + return invalid_iterator(id_, w.c_str()); + } + + private: + invalid_iterator(int id_, const char* what_arg) + : exception(id_, what_arg) {} +}; + +/*! +@brief exception indicating executing a member function with a wrong type + +This exception is thrown in case of a type error; that is, a library function is +executed on a JSON value whose type does not match the expected semantics. + +Exceptions have ids 3xx. + +name / id | example message | description +----------------------------- | --------------- | ------------------------- +json.exception.type_error.301 | cannot create object from initializer list | To create an object from an initializer list, the initializer list must consist only of a list of pairs whose first element is a string. When this constraint is violated, an array is created instead. +json.exception.type_error.302 | type must be object, but is array | During implicit or explicit value conversion, the JSON type must be compatible to the target type. For instance, a JSON string can only be converted into string types, but not into numbers or boolean types. +json.exception.type_error.303 | incompatible ReferenceType for get_ref, actual type is object | To retrieve a reference to a value stored in a @ref basic_json object with @ref get_ref, the type of the reference must match the value type. For instance, for a JSON array, the @a ReferenceType must be @ref array_t&. +json.exception.type_error.304 | cannot use at() with string | The @ref at() member functions can only be executed for certain JSON types. +json.exception.type_error.305 | cannot use operator[] with string | The @ref operator[] member functions can only be executed for certain JSON types. +json.exception.type_error.306 | cannot use value() with string | The @ref value() member functions can only be executed for certain JSON types. +json.exception.type_error.307 | cannot use erase() with string | The @ref erase() member functions can only be executed for certain JSON types. +json.exception.type_error.308 | cannot use push_back() with string | The @ref push_back() and @ref operator+= member functions can only be executed for certain JSON types. +json.exception.type_error.309 | cannot use insert() with | The @ref insert() member functions can only be executed for certain JSON types. +json.exception.type_error.310 | cannot use swap() with number | The @ref swap() member functions can only be executed for certain JSON types. +json.exception.type_error.311 | cannot use emplace_back() with string | The @ref emplace_back() member function can only be executed for certain JSON types. +json.exception.type_error.312 | cannot use update() with string | The @ref update() member functions can only be executed for certain JSON types. +json.exception.type_error.313 | invalid value to unflatten | The @ref unflatten function converts an object whose keys are JSON Pointers back into an arbitrary nested JSON value. The JSON Pointers must not overlap, because then the resulting value would not be well defined. +json.exception.type_error.314 | only objects can be unflattened | The @ref unflatten function only works for an object whose keys are JSON Pointers. +json.exception.type_error.315 | values in object must be primitive | The @ref unflatten function only works for an object whose keys are JSON Pointers and whose values are primitive. +json.exception.type_error.316 | invalid UTF-8 byte at index 10: 0x7E | The @ref dump function only works with UTF-8 encoded strings; that is, if you assign a `std::string` to a JSON value, make sure it is UTF-8 encoded. | + +@liveexample{The following code shows how a `type_error` exception can be +caught.,type_error} + +@sa @ref exception for the base class of the library exceptions +@sa @ref parse_error for exceptions indicating a parse error +@sa @ref invalid_iterator for exceptions indicating errors with iterators +@sa @ref out_of_range for exceptions indicating access out of the defined range +@sa @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class type_error : public exception +{ + public: + static type_error create(int id_, const std::string& what_arg) + { + std::string w = exception::name("type_error", id_) + what_arg; + return type_error(id_, w.c_str()); + } + + private: + type_error(int id_, const char* what_arg) : exception(id_, what_arg) {} +}; + +/*! +@brief exception indicating access out of the defined range + +This exception is thrown in case a library function is called on an input +parameter that exceeds the expected range, for instance in case of array +indices or nonexisting object keys. + +Exceptions have ids 4xx. + +name / id | example message | description +------------------------------- | --------------- | ------------------------- +json.exception.out_of_range.401 | array index 3 is out of range | The provided array index @a i is larger than @a size-1. +json.exception.out_of_range.402 | array index '-' (3) is out of range | The special array index `-` in a JSON Pointer never describes a valid element of the array, but the index past the end. That is, it can only be used to add elements at this position, but not to read it. +json.exception.out_of_range.403 | key 'foo' not found | The provided key was not found in the JSON object. +json.exception.out_of_range.404 | unresolved reference token 'foo' | A reference token in a JSON Pointer could not be resolved. +json.exception.out_of_range.405 | JSON pointer has no parent | The JSON Patch operations 'remove' and 'add' can not be applied to the root element of the JSON value. +json.exception.out_of_range.406 | number overflow parsing '10E1000' | A parsed number could not be stored as without changing it to NaN or INF. + +@liveexample{The following code shows how an `out_of_range` exception can be +caught.,out_of_range} + +@sa @ref exception for the base class of the library exceptions +@sa @ref parse_error for exceptions indicating a parse error +@sa @ref invalid_iterator for exceptions indicating errors with iterators +@sa @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class out_of_range : public exception +{ + public: + static out_of_range create(int id_, const std::string& what_arg) + { + std::string w = exception::name("out_of_range", id_) + what_arg; + return out_of_range(id_, w.c_str()); + } + + private: + out_of_range(int id_, const char* what_arg) : exception(id_, what_arg) {} +}; + +/*! +@brief exception indicating other library errors + +This exception is thrown in case of errors that cannot be classified with the +other exception types. + +Exceptions have ids 5xx. + +name / id | example message | description +------------------------------ | --------------- | ------------------------- +json.exception.other_error.501 | unsuccessful: {"op":"test","path":"/baz", "value":"bar"} | A JSON Patch operation 'test' failed. The unsuccessful operation is also printed. + +@sa @ref exception for the base class of the library exceptions +@sa @ref parse_error for exceptions indicating a parse error +@sa @ref invalid_iterator for exceptions indicating errors with iterators +@sa @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa @ref out_of_range for exceptions indicating access out of the defined range + +@liveexample{The following code shows how an `other_error` exception can be +caught.,other_error} + +@since version 3.0.0 +*/ +class other_error : public exception +{ + public: + static other_error create(int id_, const std::string& what_arg) + { + std::string w = exception::name("other_error", id_) + what_arg; + return other_error(id_, w.c_str()); + } + + private: + other_error(int id_, const char* what_arg) : exception(id_, what_arg) {} +}; +} +} + +#endif + +/*** End of inlined file: exceptions.hpp ***/ + + +/*** Start of inlined file: value_t.hpp ***/ +#ifndef NLOHMANN_JSON_DETAIL_VALUE_T_HPP +#define NLOHMANN_JSON_DETAIL_VALUE_T_HPP + +#include // array +#include // and +#include // size_t +#include // uint8_t + +namespace nlohmann +{ +namespace detail +{ +/////////////////////////// +// JSON type enumeration // +/////////////////////////// + +/*! +@brief the JSON type enumeration + +This enumeration collects the different JSON types. It is internally used to +distinguish the stored values, and the functions @ref basic_json::is_null(), +@ref basic_json::is_object(), @ref basic_json::is_array(), +@ref basic_json::is_string(), @ref basic_json::is_boolean(), +@ref basic_json::is_number() (with @ref basic_json::is_number_integer(), +@ref basic_json::is_number_unsigned(), and @ref basic_json::is_number_float()), +@ref basic_json::is_discarded(), @ref basic_json::is_primitive(), and +@ref basic_json::is_structured() rely on it. + +@note There are three enumeration entries (number_integer, number_unsigned, and +number_float), because the library distinguishes these three types for numbers: +@ref basic_json::number_unsigned_t is used for unsigned integers, +@ref basic_json::number_integer_t is used for signed integers, and +@ref basic_json::number_float_t is used for floating-point numbers or to +approximate integers which do not fit in the limits of their respective type. + +@sa @ref basic_json::basic_json(const value_t value_type) -- create a JSON +value with the default value for a given type + +@since version 1.0.0 +*/ +enum class value_t : std::uint8_t +{ + null, ///< null value + object, ///< object (unordered set of name/value pairs) + array, ///< array (ordered collection of values) + string, ///< string value + boolean, ///< boolean value + number_integer, ///< number value (signed integer) + number_unsigned, ///< number value (unsigned integer) + number_float, ///< number value (floating-point) + discarded ///< discarded by the the parser callback function +}; + +/*! +@brief comparison operator for JSON types + +Returns an ordering that is similar to Python: +- order: null < boolean < number < object < array < string +- furthermore, each type is not smaller than itself +- discarded values are not comparable + +@since version 1.0.0 +*/ +inline bool operator<(const value_t lhs, const value_t rhs) noexcept +{ + static constexpr std::array order = {{ + 0 /* null */, 3 /* object */, 4 /* array */, 5 /* string */, + 1 /* boolean */, 2 /* integer */, 2 /* unsigned */, 2 /* float */ + } + }; + + const auto l_index = static_cast(lhs); + const auto r_index = static_cast(rhs); + return l_index < order.size() and r_index < order.size() and order[l_index] < order[r_index]; +} +} +} + +#endif + +/*** End of inlined file: value_t.hpp ***/ + + +/*** Start of inlined file: from_json.hpp ***/ +#ifndef NLOHMANN_JSON_DETAIL_CONVERSIONS_FROM_JSON_HPP +#define NLOHMANN_JSON_DETAIL_CONVERSIONS_FROM_JSON_HPP + +#include // transform +#include // array +#include // and, not +#include // forward_list +#include // inserter, front_inserter, end +#include // string +#include // tuple, make_tuple +#include // is_arithmetic, is_same, is_enum, underlying_type, is_convertible +#include // pair, declval +#include // valarray + + +/*** Start of inlined file: exceptions.hpp ***/ +#ifndef NLOHMANN_JSON_DETAIL_EXCEPTIONS_HPP +#define NLOHMANN_JSON_DETAIL_EXCEPTIONS_HPP + +#include // exception +#include // runtime_error +#include // to_string + +namespace nlohmann +{ +namespace detail +{ +//////////////// +// exceptions // +//////////////// + +/*! +@brief general exception of the @ref basic_json class + +This class is an extension of `std::exception` objects with a member @a id for +exception ids. It is used as the base class for all exceptions thrown by the +@ref basic_json class. This class can hence be used as "wildcard" to catch +exceptions. + +Subclasses: +- @ref parse_error for exceptions indicating a parse error +- @ref invalid_iterator for exceptions indicating errors with iterators +- @ref type_error for exceptions indicating executing a member function with + a wrong type +- @ref out_of_range for exceptions indicating access out of the defined range +- @ref other_error for exceptions indicating other library errors + +@internal +@note To have nothrow-copy-constructible exceptions, we internally use + `std::runtime_error` which can cope with arbitrary-length error messages. + Intermediate strings are built with static functions and then passed to + the actual constructor. +@endinternal + +@liveexample{The following code shows how arbitrary library exceptions can be +caught.,exception} + +@since version 3.0.0 +*/ +class exception : public std::exception +{ + public: + /// returns the explanatory string + const char* what() const noexcept override + { + return m.what(); + } + + /// the id of the exception + const int id; + + protected: + exception(int id_, const char* what_arg) : id(id_), m(what_arg) {} + + static std::string name(const std::string& ename, int id_) + { + return "[json.exception." + ename + "." + std::to_string(id_) + "] "; + } + + private: + /// an exception object as storage for error messages + std::runtime_error m; +}; + +/*! +@brief exception indicating a parse error + +This exception is thrown by the library when a parse error occurs. Parse errors +can occur during the deserialization of JSON text, CBOR, MessagePack, as well +as when using JSON Patch. + +Member @a byte holds the byte index of the last read character in the input +file. + +Exceptions have ids 1xx. + +name / id | example message | description +------------------------------ | --------------- | ------------------------- +json.exception.parse_error.101 | parse error at 2: unexpected end of input; expected string literal | This error indicates a syntax error while deserializing a JSON text. The error message describes that an unexpected token (character) was encountered, and the member @a byte indicates the error position. +json.exception.parse_error.102 | parse error at 14: missing or wrong low surrogate | JSON uses the `\uxxxx` format to describe Unicode characters. Code points above above 0xFFFF are split into two `\uxxxx` entries ("surrogate pairs"). This error indicates that the surrogate pair is incomplete or contains an invalid code point. +json.exception.parse_error.103 | parse error: code points above 0x10FFFF are invalid | Unicode supports code points up to 0x10FFFF. Code points above 0x10FFFF are invalid. +json.exception.parse_error.104 | parse error: JSON patch must be an array of objects | [RFC 6902](https://tools.ietf.org/html/rfc6902) requires a JSON Patch document to be a JSON document that represents an array of objects. +json.exception.parse_error.105 | parse error: operation must have string member 'op' | An operation of a JSON Patch document must contain exactly one "op" member, whose value indicates the operation to perform. Its value must be one of "add", "remove", "replace", "move", "copy", or "test"; other values are errors. +json.exception.parse_error.106 | parse error: array index '01' must not begin with '0' | An array index in a JSON Pointer ([RFC 6901](https://tools.ietf.org/html/rfc6901)) may be `0` or any number without a leading `0`. +json.exception.parse_error.107 | parse error: JSON pointer must be empty or begin with '/' - was: 'foo' | A JSON Pointer must be a Unicode string containing a sequence of zero or more reference tokens, each prefixed by a `/` character. +json.exception.parse_error.108 | parse error: escape character '~' must be followed with '0' or '1' | In a JSON Pointer, only `~0` and `~1` are valid escape sequences. +json.exception.parse_error.109 | parse error: array index 'one' is not a number | A JSON Pointer array index must be a number. +json.exception.parse_error.110 | parse error at 1: cannot read 2 bytes from vector | When parsing CBOR or MessagePack, the byte vector ends before the complete value has been read. +json.exception.parse_error.112 | parse error at 1: error reading CBOR; last byte: 0xF8 | Not all types of CBOR or MessagePack are supported. This exception occurs if an unsupported byte was read. +json.exception.parse_error.113 | parse error at 2: expected a CBOR string; last byte: 0x98 | While parsing a map key, a value that is not a string has been read. + +@note For an input with n bytes, 1 is the index of the first character and n+1 + is the index of the terminating null byte or the end of file. This also + holds true when reading a byte vector (CBOR or MessagePack). + +@liveexample{The following code shows how a `parse_error` exception can be +caught.,parse_error} + +@sa @ref exception for the base class of the library exceptions +@sa @ref invalid_iterator for exceptions indicating errors with iterators +@sa @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa @ref out_of_range for exceptions indicating access out of the defined range +@sa @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class parse_error : public exception +{ + public: + /*! + @brief create a parse error exception + @param[in] id_ the id of the exception + @param[in] byte_ the byte index where the error occurred (or 0 if the + position cannot be determined) + @param[in] what_arg the explanatory string + @return parse_error object + */ + static parse_error create(int id_, std::size_t byte_, const std::string& what_arg) + { + std::string w = exception::name("parse_error", id_) + "parse error" + + (byte_ != 0 ? (" at " + std::to_string(byte_)) : "") + + ": " + what_arg; + return parse_error(id_, byte_, w.c_str()); + } + + /*! + @brief byte index of the parse error + + The byte index of the last read character in the input file. + + @note For an input with n bytes, 1 is the index of the first character and + n+1 is the index of the terminating null byte or the end of file. + This also holds true when reading a byte vector (CBOR or MessagePack). + */ + const std::size_t byte; + + private: + parse_error(int id_, std::size_t byte_, const char* what_arg) + : exception(id_, what_arg), byte(byte_) {} +}; + +/*! +@brief exception indicating errors with iterators + +This exception is thrown if iterators passed to a library function do not match +the expected semantics. + +Exceptions have ids 2xx. + +name / id | example message | description +----------------------------------- | --------------- | ------------------------- +json.exception.invalid_iterator.201 | iterators are not compatible | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. +json.exception.invalid_iterator.202 | iterator does not fit current value | In an erase or insert function, the passed iterator @a pos does not belong to the JSON value for which the function was called. It hence does not define a valid position for the deletion/insertion. +json.exception.invalid_iterator.203 | iterators do not fit current value | Either iterator passed to function @ref erase(IteratorType first, IteratorType last) does not belong to the JSON value from which values shall be erased. It hence does not define a valid range to delete values from. +json.exception.invalid_iterator.204 | iterators out of range | When an iterator range for a primitive type (number, boolean, or string) is passed to a constructor or an erase function, this range has to be exactly (@ref begin(), @ref end()), because this is the only way the single stored value is expressed. All other ranges are invalid. +json.exception.invalid_iterator.205 | iterator out of range | When an iterator for a primitive type (number, boolean, or string) is passed to an erase function, the iterator has to be the @ref begin() iterator, because it is the only way to address the stored value. All other iterators are invalid. +json.exception.invalid_iterator.206 | cannot construct with iterators from null | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) belong to a JSON null value and hence to not define a valid range. +json.exception.invalid_iterator.207 | cannot use key() for non-object iterators | The key() member function can only be used on iterators belonging to a JSON object, because other types do not have a concept of a key. +json.exception.invalid_iterator.208 | cannot use operator[] for object iterators | The operator[] to specify a concrete offset cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. +json.exception.invalid_iterator.209 | cannot use offsets with object iterators | The offset operators (+, -, +=, -=) cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. +json.exception.invalid_iterator.210 | iterators do not fit | The iterator range passed to the insert function are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. +json.exception.invalid_iterator.211 | passed iterators may not belong to container | The iterator range passed to the insert function must not be a subrange of the container to insert to. +json.exception.invalid_iterator.212 | cannot compare iterators of different containers | When two iterators are compared, they must belong to the same container. +json.exception.invalid_iterator.213 | cannot compare order of object iterators | The order of object iterators cannot be compared, because JSON objects are unordered. +json.exception.invalid_iterator.214 | cannot get value | Cannot get value for iterator: Either the iterator belongs to a null value or it is an iterator to a primitive type (number, boolean, or string), but the iterator is different to @ref begin(). + +@liveexample{The following code shows how an `invalid_iterator` exception can be +caught.,invalid_iterator} + +@sa @ref exception for the base class of the library exceptions +@sa @ref parse_error for exceptions indicating a parse error +@sa @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa @ref out_of_range for exceptions indicating access out of the defined range +@sa @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class invalid_iterator : public exception +{ + public: + static invalid_iterator create(int id_, const std::string& what_arg) + { + std::string w = exception::name("invalid_iterator", id_) + what_arg; + return invalid_iterator(id_, w.c_str()); + } + + private: + invalid_iterator(int id_, const char* what_arg) + : exception(id_, what_arg) {} +}; + +/*! +@brief exception indicating executing a member function with a wrong type + +This exception is thrown in case of a type error; that is, a library function is +executed on a JSON value whose type does not match the expected semantics. + +Exceptions have ids 3xx. + +name / id | example message | description +----------------------------- | --------------- | ------------------------- +json.exception.type_error.301 | cannot create object from initializer list | To create an object from an initializer list, the initializer list must consist only of a list of pairs whose first element is a string. When this constraint is violated, an array is created instead. +json.exception.type_error.302 | type must be object, but is array | During implicit or explicit value conversion, the JSON type must be compatible to the target type. For instance, a JSON string can only be converted into string types, but not into numbers or boolean types. +json.exception.type_error.303 | incompatible ReferenceType for get_ref, actual type is object | To retrieve a reference to a value stored in a @ref basic_json object with @ref get_ref, the type of the reference must match the value type. For instance, for a JSON array, the @a ReferenceType must be @ref array_t&. +json.exception.type_error.304 | cannot use at() with string | The @ref at() member functions can only be executed for certain JSON types. +json.exception.type_error.305 | cannot use operator[] with string | The @ref operator[] member functions can only be executed for certain JSON types. +json.exception.type_error.306 | cannot use value() with string | The @ref value() member functions can only be executed for certain JSON types. +json.exception.type_error.307 | cannot use erase() with string | The @ref erase() member functions can only be executed for certain JSON types. +json.exception.type_error.308 | cannot use push_back() with string | The @ref push_back() and @ref operator+= member functions can only be executed for certain JSON types. +json.exception.type_error.309 | cannot use insert() with | The @ref insert() member functions can only be executed for certain JSON types. +json.exception.type_error.310 | cannot use swap() with number | The @ref swap() member functions can only be executed for certain JSON types. +json.exception.type_error.311 | cannot use emplace_back() with string | The @ref emplace_back() member function can only be executed for certain JSON types. +json.exception.type_error.312 | cannot use update() with string | The @ref update() member functions can only be executed for certain JSON types. +json.exception.type_error.313 | invalid value to unflatten | The @ref unflatten function converts an object whose keys are JSON Pointers back into an arbitrary nested JSON value. The JSON Pointers must not overlap, because then the resulting value would not be well defined. +json.exception.type_error.314 | only objects can be unflattened | The @ref unflatten function only works for an object whose keys are JSON Pointers. +json.exception.type_error.315 | values in object must be primitive | The @ref unflatten function only works for an object whose keys are JSON Pointers and whose values are primitive. +json.exception.type_error.316 | invalid UTF-8 byte at index 10: 0x7E | The @ref dump function only works with UTF-8 encoded strings; that is, if you assign a `std::string` to a JSON value, make sure it is UTF-8 encoded. | + +@liveexample{The following code shows how a `type_error` exception can be +caught.,type_error} + +@sa @ref exception for the base class of the library exceptions +@sa @ref parse_error for exceptions indicating a parse error +@sa @ref invalid_iterator for exceptions indicating errors with iterators +@sa @ref out_of_range for exceptions indicating access out of the defined range +@sa @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class type_error : public exception +{ + public: + static type_error create(int id_, const std::string& what_arg) + { + std::string w = exception::name("type_error", id_) + what_arg; + return type_error(id_, w.c_str()); + } + + private: + type_error(int id_, const char* what_arg) : exception(id_, what_arg) {} +}; + +/*! +@brief exception indicating access out of the defined range + +This exception is thrown in case a library function is called on an input +parameter that exceeds the expected range, for instance in case of array +indices or nonexisting object keys. + +Exceptions have ids 4xx. + +name / id | example message | description +------------------------------- | --------------- | ------------------------- +json.exception.out_of_range.401 | array index 3 is out of range | The provided array index @a i is larger than @a size-1. +json.exception.out_of_range.402 | array index '-' (3) is out of range | The special array index `-` in a JSON Pointer never describes a valid element of the array, but the index past the end. That is, it can only be used to add elements at this position, but not to read it. +json.exception.out_of_range.403 | key 'foo' not found | The provided key was not found in the JSON object. +json.exception.out_of_range.404 | unresolved reference token 'foo' | A reference token in a JSON Pointer could not be resolved. +json.exception.out_of_range.405 | JSON pointer has no parent | The JSON Patch operations 'remove' and 'add' can not be applied to the root element of the JSON value. +json.exception.out_of_range.406 | number overflow parsing '10E1000' | A parsed number could not be stored as without changing it to NaN or INF. + +@liveexample{The following code shows how an `out_of_range` exception can be +caught.,out_of_range} + +@sa @ref exception for the base class of the library exceptions +@sa @ref parse_error for exceptions indicating a parse error +@sa @ref invalid_iterator for exceptions indicating errors with iterators +@sa @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class out_of_range : public exception +{ + public: + static out_of_range create(int id_, const std::string& what_arg) + { + std::string w = exception::name("out_of_range", id_) + what_arg; + return out_of_range(id_, w.c_str()); + } + + private: + out_of_range(int id_, const char* what_arg) : exception(id_, what_arg) {} +}; + +/*! +@brief exception indicating other library errors + +This exception is thrown in case of errors that cannot be classified with the +other exception types. + +Exceptions have ids 5xx. + +name / id | example message | description +------------------------------ | --------------- | ------------------------- +json.exception.other_error.501 | unsuccessful: {"op":"test","path":"/baz", "value":"bar"} | A JSON Patch operation 'test' failed. The unsuccessful operation is also printed. + +@sa @ref exception for the base class of the library exceptions +@sa @ref parse_error for exceptions indicating a parse error +@sa @ref invalid_iterator for exceptions indicating errors with iterators +@sa @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa @ref out_of_range for exceptions indicating access out of the defined range + +@liveexample{The following code shows how an `other_error` exception can be +caught.,other_error} + +@since version 3.0.0 +*/ +class other_error : public exception +{ + public: + static other_error create(int id_, const std::string& what_arg) + { + std::string w = exception::name("other_error", id_) + what_arg; + return other_error(id_, w.c_str()); + } + + private: + other_error(int id_, const char* what_arg) : exception(id_, what_arg) {} +}; +} +} + +#endif + +/*** End of inlined file: exceptions.hpp ***/ + + +/*** Start of inlined file: meta.hpp ***/ +#ifndef NLOHMANN_JSON_DETAIL_META_HPP +#define NLOHMANN_JSON_DETAIL_META_HPP + +#include // not +#include // size_t +#include // numeric_limits +#include // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type +#include // declval + +namespace nlohmann +{ +/*! +@brief detail namespace with internal helper functions + +This namespace collects functions that should not be exposed, +implementations of some @ref basic_json methods, and meta-programming helpers. + +@since version 2.1.0 +*/ +namespace detail +{ +///////////// +// helpers // +///////////// + +template struct is_basic_json : std::false_type {}; + +NLOHMANN_BASIC_JSON_TPL_DECLARATION +struct is_basic_json : std::true_type {}; + +// alias templates to reduce boilerplate +template +using enable_if_t = typename std::enable_if::type; + +template +using uncvref_t = typename std::remove_cv::type>::type; + +// implementation of C++14 index_sequence and affiliates +// source: https://stackoverflow.com/a/32223343 +template +struct index_sequence +{ + using type = index_sequence; + using value_type = std::size_t; + static constexpr std::size_t size() noexcept + { + return sizeof...(Ints); + } +}; + +template +struct merge_and_renumber; + +template +struct merge_and_renumber, index_sequence> + : index_sequence < I1..., (sizeof...(I1) + I2)... > {}; + +template +struct make_index_sequence + : merge_and_renumber < typename make_index_sequence < N / 2 >::type, + typename make_index_sequence < N - N / 2 >::type > {}; + +template<> struct make_index_sequence<0> : index_sequence<> {}; +template<> struct make_index_sequence<1> : index_sequence<0> {}; + +template +using index_sequence_for = make_index_sequence; + +/* +Implementation of two C++17 constructs: conjunction, negation. This is needed +to avoid evaluating all the traits in a condition + +For example: not std::is_same::value and has_value_type::value +will not compile when T = void (on MSVC at least). Whereas +conjunction>, has_value_type>::value will +stop evaluating if negation<...>::value == false + +Please note that those constructs must be used with caution, since symbols can +become very long quickly (which can slow down compilation and cause MSVC +internal compiler errors). Only use it when you have to (see example ahead). +*/ +template struct conjunction : std::true_type {}; +template struct conjunction : B1 {}; +template +struct conjunction : std::conditional, B1>::type {}; + +template struct negation : std::integral_constant {}; + +// dispatch utility (taken from ranges-v3) +template struct priority_tag : priority_tag < N - 1 > {}; +template<> struct priority_tag<0> {}; + +//////////////////////// +// has_/is_ functions // +//////////////////////// + +NLOHMANN_JSON_HAS_HELPER(mapped_type); +NLOHMANN_JSON_HAS_HELPER(key_type); +NLOHMANN_JSON_HAS_HELPER(value_type); +NLOHMANN_JSON_HAS_HELPER(iterator); + +template +struct is_compatible_object_type_impl : std::false_type {}; + +template +struct is_compatible_object_type_impl +{ + static constexpr auto value = + std::is_constructible::value and + std::is_constructible::value; +}; + +template +struct is_compatible_object_type +{ + static auto constexpr value = is_compatible_object_type_impl < + conjunction>, + has_mapped_type, + has_key_type>::value, + typename BasicJsonType::object_t, CompatibleObjectType >::value; +}; + +template +struct is_basic_json_nested_type +{ + static auto constexpr value = std::is_same::value or + std::is_same::value or + std::is_same::value or + std::is_same::value; +}; + +template +struct is_compatible_array_type +{ + static auto constexpr value = + conjunction>, + negation>, + negation>, + negation>, + has_value_type, + has_iterator>::value; +}; + +template +struct is_compatible_integer_type_impl : std::false_type {}; + +template +struct is_compatible_integer_type_impl +{ + // is there an assert somewhere on overflows? + using RealLimits = std::numeric_limits; + using CompatibleLimits = std::numeric_limits; + + static constexpr auto value = + std::is_constructible::value and + CompatibleLimits::is_integer and + RealLimits::is_signed == CompatibleLimits::is_signed; +}; + +template +struct is_compatible_integer_type +{ + static constexpr auto value = + is_compatible_integer_type_impl < + std::is_integral::value and + not std::is_same::value, + RealIntegerType, CompatibleNumberIntegerType > ::value; +}; + +// trait checking if JSONSerializer::from_json(json const&, udt&) exists +template +struct has_from_json +{ + private: + // also check the return type of from_json + template::from_json( + std::declval(), std::declval()))>::value>> + static int detect(U&&); + static void detect(...); + + public: + static constexpr bool value = std::is_integral>()))>::value; +}; + +// This trait checks if JSONSerializer::from_json(json const&) exists +// this overload is used for non-default-constructible user-defined-types +template +struct has_non_default_from_json +{ + private: + template < + typename U, + typename = enable_if_t::from_json(std::declval()))>::value >> + static int detect(U&&); + static void detect(...); + + public: + static constexpr bool value = std::is_integral>()))>::value; +}; + +// This trait checks if BasicJsonType::json_serializer::to_json exists +template +struct has_to_json +{ + private: + template::to_json( + std::declval(), std::declval()))> + static int detect(U&&); + static void detect(...); + + public: + static constexpr bool value = std::is_integral>()))>::value; +}; + +// taken from ranges-v3 +template +struct static_const +{ + static constexpr T value{}; +}; + +template +constexpr T static_const::value; +} +} + +#endif + +/*** End of inlined file: meta.hpp ***/ + + +/*** Start of inlined file: value_t.hpp ***/ +#ifndef NLOHMANN_JSON_DETAIL_VALUE_T_HPP +#define NLOHMANN_JSON_DETAIL_VALUE_T_HPP + +#include // array +#include // and +#include // size_t +#include // uint8_t + +namespace nlohmann +{ +namespace detail +{ +/////////////////////////// +// JSON type enumeration // +/////////////////////////// + +/*! +@brief the JSON type enumeration + +This enumeration collects the different JSON types. It is internally used to +distinguish the stored values, and the functions @ref basic_json::is_null(), +@ref basic_json::is_object(), @ref basic_json::is_array(), +@ref basic_json::is_string(), @ref basic_json::is_boolean(), +@ref basic_json::is_number() (with @ref basic_json::is_number_integer(), +@ref basic_json::is_number_unsigned(), and @ref basic_json::is_number_float()), +@ref basic_json::is_discarded(), @ref basic_json::is_primitive(), and +@ref basic_json::is_structured() rely on it. + +@note There are three enumeration entries (number_integer, number_unsigned, and +number_float), because the library distinguishes these three types for numbers: +@ref basic_json::number_unsigned_t is used for unsigned integers, +@ref basic_json::number_integer_t is used for signed integers, and +@ref basic_json::number_float_t is used for floating-point numbers or to +approximate integers which do not fit in the limits of their respective type. + +@sa @ref basic_json::basic_json(const value_t value_type) -- create a JSON +value with the default value for a given type + +@since version 1.0.0 +*/ +enum class value_t : std::uint8_t +{ + null, ///< null value + object, ///< object (unordered set of name/value pairs) + array, ///< array (ordered collection of values) + string, ///< string value + boolean, ///< boolean value + number_integer, ///< number value (signed integer) + number_unsigned, ///< number value (unsigned integer) + number_float, ///< number value (floating-point) + discarded ///< discarded by the the parser callback function +}; + +/*! +@brief comparison operator for JSON types + +Returns an ordering that is similar to Python: +- order: null < boolean < number < object < array < string +- furthermore, each type is not smaller than itself +- discarded values are not comparable + +@since version 1.0.0 +*/ +inline bool operator<(const value_t lhs, const value_t rhs) noexcept +{ + static constexpr std::array order = {{ + 0 /* null */, 3 /* object */, 4 /* array */, 5 /* string */, + 1 /* boolean */, 2 /* integer */, 2 /* unsigned */, 2 /* float */ + } + }; + + const auto l_index = static_cast(lhs); + const auto r_index = static_cast(rhs); + return l_index < order.size() and r_index < order.size() and order[l_index] < order[r_index]; +} +} +} + +#endif + +/*** End of inlined file: value_t.hpp ***/ + +namespace nlohmann +{ +namespace detail +{ +// overloads for basic_json template parameters +template::value and + not std::is_same::value, + int> = 0> +void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val) +{ + switch (static_cast(j)) + { + case value_t::number_unsigned: + { + val = static_cast(*j.template get_ptr()); + break; + } + case value_t::number_integer: + { + val = static_cast(*j.template get_ptr()); + break; + } + case value_t::number_float: + { + val = static_cast(*j.template get_ptr()); + break; + } + + default: + JSON_THROW(type_error::create(302, "type must be number, but is " + std::string(j.type_name()))); + } +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b) +{ + if (JSON_UNLIKELY(not j.is_boolean())) + { + JSON_THROW(type_error::create(302, "type must be boolean, but is " + std::string(j.type_name()))); + } + b = *j.template get_ptr(); +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s) +{ + if (JSON_UNLIKELY(not j.is_string())) + { + JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name()))); + } + s = *j.template get_ptr(); +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::number_float_t& val) +{ + get_arithmetic_value(j, val); +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::number_unsigned_t& val) +{ + get_arithmetic_value(j, val); +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::number_integer_t& val) +{ + get_arithmetic_value(j, val); +} + +template::value, int> = 0> +void from_json(const BasicJsonType& j, EnumType& e) +{ + typename std::underlying_type::type val; + get_arithmetic_value(j, val); + e = static_cast(val); +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::array_t& arr) +{ + if (JSON_UNLIKELY(not j.is_array())) + { + JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); + } + arr = *j.template get_ptr(); +} + +// forward_list doesn't have an insert method +template::value, int> = 0> +void from_json(const BasicJsonType& j, std::forward_list& l) +{ + if (JSON_UNLIKELY(not j.is_array())) + { + JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); + } + std::transform(j.rbegin(), j.rend(), + std::front_inserter(l), [](const BasicJsonType & i) + { + return i.template get(); + }); +} + +// valarray doesn't have an insert method +template::value, int> = 0> +void from_json(const BasicJsonType& j, std::valarray& l) +{ + if (JSON_UNLIKELY(not j.is_array())) + { + JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); + } + l.resize(j.size()); + std::copy(j.m_value.array->begin(), j.m_value.array->end(), std::begin(l)); +} + +template +void from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, priority_tag<0> /*unused*/) +{ + using std::end; + + std::transform(j.begin(), j.end(), + std::inserter(arr, end(arr)), [](const BasicJsonType & i) + { + // get() returns *this, this won't call a from_json + // method when value_type is BasicJsonType + return i.template get(); + }); +} + +template +auto from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, priority_tag<1> /*unused*/) +-> decltype( + arr.reserve(std::declval()), + void()) +{ + using std::end; + + arr.reserve(j.size()); + std::transform(j.begin(), j.end(), + std::inserter(arr, end(arr)), [](const BasicJsonType & i) + { + // get() returns *this, this won't call a from_json + // method when value_type is BasicJsonType + return i.template get(); + }); +} + +template +void from_json_array_impl(const BasicJsonType& j, std::array& arr, priority_tag<2> /*unused*/) +{ + for (std::size_t i = 0; i < N; ++i) + { + arr[i] = j.at(i).template get(); + } +} + +template::value and + std::is_convertible::value and + not std::is_same::value, int> = 0> +void from_json(const BasicJsonType& j, CompatibleArrayType& arr) +{ + if (JSON_UNLIKELY(not j.is_array())) + { + JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); + } + + from_json_array_impl(j, arr, priority_tag<2> {}); +} + +template::value, int> = 0> +void from_json(const BasicJsonType& j, CompatibleObjectType& obj) +{ + if (JSON_UNLIKELY(not j.is_object())) + { + JSON_THROW(type_error::create(302, "type must be object, but is " + std::string(j.type_name()))); + } + + auto inner_object = j.template get_ptr(); + using value_type = typename CompatibleObjectType::value_type; + std::transform( + inner_object->begin(), inner_object->end(), + std::inserter(obj, obj.begin()), + [](typename BasicJsonType::object_t::value_type const & p) + { + return value_type(p.first, p.second.template get()); + }); +} + +// overload for arithmetic types, not chosen for basic_json template arguments +// (BooleanType, etc..); note: Is it really necessary to provide explicit +// overloads for boolean_t etc. in case of a custom BooleanType which is not +// an arithmetic type? +template::value and + not std::is_same::value and + not std::is_same::value and + not std::is_same::value and + not std::is_same::value, + int> = 0> +void from_json(const BasicJsonType& j, ArithmeticType& val) +{ + switch (static_cast(j)) + { + case value_t::number_unsigned: + { + val = static_cast(*j.template get_ptr()); + break; + } + case value_t::number_integer: + { + val = static_cast(*j.template get_ptr()); + break; + } + case value_t::number_float: + { + val = static_cast(*j.template get_ptr()); + break; + } + case value_t::boolean: + { + val = static_cast(*j.template get_ptr()); + break; + } + + default: + JSON_THROW(type_error::create(302, "type must be number, but is " + std::string(j.type_name()))); + } +} + +template +void from_json(const BasicJsonType& j, std::pair& p) +{ + p = {j.at(0).template get(), j.at(1).template get()}; +} + +template +void from_json_tuple_impl(const BasicJsonType& j, Tuple& t, index_sequence) +{ + t = std::make_tuple(j.at(Idx).template get::type>()...); +} + +template +void from_json(const BasicJsonType& j, std::tuple& t) +{ + from_json_tuple_impl(j, t, index_sequence_for {}); +} + +struct from_json_fn +{ + private: + template + auto call(const BasicJsonType& j, T& val, priority_tag<1> /*unused*/) const + noexcept(noexcept(from_json(j, val))) + -> decltype(from_json(j, val), void()) + { + return from_json(j, val); + } + + template + void call(const BasicJsonType& /*unused*/, T& /*unused*/, priority_tag<0> /*unused*/) const noexcept + { + static_assert(sizeof(BasicJsonType) == 0, + "could not find from_json() method in T's namespace"); +#ifdef _MSC_VER + // MSVC does not show a stacktrace for the above assert + using decayed = uncvref_t; + static_assert(sizeof(typename decayed::force_msvc_stacktrace) == 0, + "forcing MSVC stacktrace to show which T we're talking about."); +#endif + } + + public: + template + void operator()(const BasicJsonType& j, T& val) const + noexcept(noexcept(std::declval().call(j, val, priority_tag<1> {}))) + { + return call(j, val, priority_tag<1> {}); + } +}; +} + +/// namespace to hold default `from_json` function +/// to see why this is required: +/// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html +namespace +{ +constexpr const auto& from_json = detail::static_const::value; +} +} + +#endif + +/*** End of inlined file: from_json.hpp ***/ + + +/*** Start of inlined file: to_json.hpp ***/ +#ifndef NLOHMANN_JSON_DETAIL_CONVERSIONS_TO_JSON_HPP +#define NLOHMANN_JSON_DETAIL_CONVERSIONS_TO_JSON_HPP + +#include // or, and, not +#include // begin, end +#include // tuple, get +#include // is_same, is_constructible, is_floating_point, is_enum, underlying_type +#include // move, forward, declval, pair +#include // valarray +#include // vector + +namespace nlohmann +{ +namespace detail +{ +////////////////// +// constructors // +////////////////// + +template struct external_constructor; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, typename BasicJsonType::boolean_t b) noexcept + { + j.m_type = value_t::boolean; + j.m_value = b; + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, const typename BasicJsonType::string_t& s) + { + j.m_type = value_t::string; + j.m_value = s; + j.assert_invariant(); + } + + template + static void construct(BasicJsonType& j, typename BasicJsonType::string_t&& s) + { + j.m_type = value_t::string; + j.m_value = std::move(s); + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, typename BasicJsonType::number_float_t val) noexcept + { + j.m_type = value_t::number_float; + j.m_value = val; + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, typename BasicJsonType::number_unsigned_t val) noexcept + { + j.m_type = value_t::number_unsigned; + j.m_value = val; + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, typename BasicJsonType::number_integer_t val) noexcept + { + j.m_type = value_t::number_integer; + j.m_value = val; + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, const typename BasicJsonType::array_t& arr) + { + j.m_type = value_t::array; + j.m_value = arr; + j.assert_invariant(); + } + + template + static void construct(BasicJsonType& j, typename BasicJsonType::array_t&& arr) + { + j.m_type = value_t::array; + j.m_value = std::move(arr); + j.assert_invariant(); + } + + template::value, + int> = 0> + static void construct(BasicJsonType& j, const CompatibleArrayType& arr) + { + using std::begin; + using std::end; + j.m_type = value_t::array; + j.m_value.array = j.template create(begin(arr), end(arr)); + j.assert_invariant(); + } + + template + static void construct(BasicJsonType& j, const std::vector& arr) + { + j.m_type = value_t::array; + j.m_value = value_t::array; + j.m_value.array->reserve(arr.size()); + for (const bool x : arr) + { + j.m_value.array->push_back(x); + } + j.assert_invariant(); + } + + template::value, int> = 0> + static void construct(BasicJsonType& j, const std::valarray& arr) + { + j.m_type = value_t::array; + j.m_value = value_t::array; + j.m_value.array->resize(arr.size()); + std::copy(std::begin(arr), std::end(arr), j.m_value.array->begin()); + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, const typename BasicJsonType::object_t& obj) + { + j.m_type = value_t::object; + j.m_value = obj; + j.assert_invariant(); + } + + template + static void construct(BasicJsonType& j, typename BasicJsonType::object_t&& obj) + { + j.m_type = value_t::object; + j.m_value = std::move(obj); + j.assert_invariant(); + } + + template::value, int> = 0> + static void construct(BasicJsonType& j, const CompatibleObjectType& obj) + { + using std::begin; + using std::end; + + j.m_type = value_t::object; + j.m_value.object = j.template create(begin(obj), end(obj)); + j.assert_invariant(); + } +}; + +///////////// +// to_json // +///////////// + +template::value, int> = 0> +void to_json(BasicJsonType& j, T b) noexcept +{ + external_constructor::construct(j, b); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, const CompatibleString& s) +{ + external_constructor::construct(j, s); +} + +template +void to_json(BasicJsonType& j, typename BasicJsonType::string_t&& s) +{ + external_constructor::construct(j, std::move(s)); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, FloatType val) noexcept +{ + external_constructor::construct(j, static_cast(val)); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, CompatibleNumberUnsignedType val) noexcept +{ + external_constructor::construct(j, static_cast(val)); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, CompatibleNumberIntegerType val) noexcept +{ + external_constructor::construct(j, static_cast(val)); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, EnumType e) noexcept +{ + using underlying_type = typename std::underlying_type::type; + external_constructor::construct(j, static_cast(e)); +} + +template +void to_json(BasicJsonType& j, const std::vector& e) +{ + external_constructor::construct(j, e); +} + +template::value or + std::is_same::value, + int> = 0> +void to_json(BasicJsonType& j, const CompatibleArrayType& arr) +{ + external_constructor::construct(j, arr); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, std::valarray arr) +{ + external_constructor::construct(j, std::move(arr)); +} + +template +void to_json(BasicJsonType& j, typename BasicJsonType::array_t&& arr) +{ + external_constructor::construct(j, std::move(arr)); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, const CompatibleObjectType& obj) +{ + external_constructor::construct(j, obj); +} + +template +void to_json(BasicJsonType& j, typename BasicJsonType::object_t&& obj) +{ + external_constructor::construct(j, std::move(obj)); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, T (&arr)[N]) +{ + external_constructor::construct(j, arr); +} + +template +void to_json(BasicJsonType& j, const std::pair& p) +{ + j = {p.first, p.second}; +} + +template +void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence) +{ + j = {std::get(t)...}; +} + +template +void to_json(BasicJsonType& j, const std::tuple& t) +{ + to_json_tuple_impl(j, t, index_sequence_for {}); +} + +struct to_json_fn +{ + private: + template + auto call(BasicJsonType& j, T&& val, priority_tag<1> /*unused*/) const noexcept(noexcept(to_json(j, std::forward(val)))) + -> decltype(to_json(j, std::forward(val)), void()) + { + return to_json(j, std::forward(val)); + } + + template + void call(BasicJsonType& /*unused*/, T&& /*unused*/, priority_tag<0> /*unused*/) const noexcept + { + static_assert(sizeof(BasicJsonType) == 0, + "could not find to_json() method in T's namespace"); + +#ifdef _MSC_VER + // MSVC does not show a stacktrace for the above assert + using decayed = uncvref_t; + static_assert(sizeof(typename decayed::force_msvc_stacktrace) == 0, + "forcing MSVC stacktrace to show which T we're talking about."); +#endif + } + + public: + template + void operator()(BasicJsonType& j, T&& val) const + noexcept(noexcept(std::declval().call(j, std::forward(val), priority_tag<1> {}))) + { + return call(j, std::forward(val), priority_tag<1> {}); + } +}; +} + +/// namespace to hold default `to_json` function +namespace +{ +constexpr const auto& to_json = detail::static_const::value; +} +} + +#endif + +/*** End of inlined file: to_json.hpp ***/ + + +/*** Start of inlined file: input_adapters.hpp ***/ +#ifndef NLOHMANN_JSON_DETAIL_PARSING_INPUT_ADAPTERS_HPP +#define NLOHMANN_JSON_DETAIL_PARSING_INPUT_ADAPTERS_HPP + +#include // min +#include // array +#include // assert +#include // size_t +#include // strlen +#include // streamsize, streamoff, streampos +#include // istream +#include // begin, end, iterator_traits, random_access_iterator_tag, distance, next +#include // shared_ptr, make_shared, addressof +#include // accumulate +#include // string, char_traits +#include // enable_if, is_base_of, is_pointer, is_integral, remove_pointer +#include // pair, declval + +namespace nlohmann +{ +namespace detail +{ +//////////////////// +// input adapters // +//////////////////// + +/*! +@brief abstract input adapter interface + +Produces a stream of std::char_traits::int_type characters from a +std::istream, a buffer, or some other input type. Accepts the return of exactly +one non-EOF character for future input. The int_type characters returned +consist of all valid char values as positive values (typically unsigned char), +plus an EOF value outside that range, specified by the value of the function +std::char_traits::eof(). This value is typically -1, but could be any +arbitrary value which is not a valid char value. +*/ +struct input_adapter_protocol +{ + /// get a character [0,255] or std::char_traits::eof(). + virtual std::char_traits::int_type get_character() = 0; + /// restore the last non-eof() character to input + virtual void unget_character() = 0; + virtual ~input_adapter_protocol() = default; +}; + +/// a type to simplify interfaces +using input_adapter_t = std::shared_ptr; + +/*! +Input adapter for a (caching) istream. Ignores a UFT Byte Order Mark at +beginning of input. Does not support changing the underlying std::streambuf +in mid-input. Maintains underlying std::istream and std::streambuf to support +subsequent use of standard std::istream operations to process any input +characters following those used in parsing the JSON input. Clears the +std::istream flags; any input errors (e.g., EOF) will be detected by the first +subsequent call for input from the std::istream. +*/ +class input_stream_adapter : public input_adapter_protocol +{ + public: + ~input_stream_adapter() override + { + // clear stream flags; we use underlying streambuf I/O, do not + // maintain ifstream flags + is.clear(); + } + + explicit input_stream_adapter(std::istream& i) + : is(i), sb(*i.rdbuf()) + { + // skip byte order mark + std::char_traits::int_type c; + if ((c = get_character()) == 0xEF) + { + if ((c = get_character()) == 0xBB) + { + if ((c = get_character()) == 0xBF) + { + return; // Ignore BOM + } + else if (c != std::char_traits::eof()) + { + is.unget(); + } + is.putback('\xBB'); + } + else if (c != std::char_traits::eof()) + { + is.unget(); + } + is.putback('\xEF'); + } + else if (c != std::char_traits::eof()) + { + is.unget(); // no byte order mark; process as usual + } + } + + // delete because of pointer members + input_stream_adapter(const input_stream_adapter&) = delete; + input_stream_adapter& operator=(input_stream_adapter&) = delete; + + // std::istream/std::streambuf use std::char_traits::to_int_type, to + // ensure that std::char_traits::eof() and the character 0xFF do not + // end up as the same value, eg. 0xFFFFFFFF. + std::char_traits::int_type get_character() override + { + return sb.sbumpc(); + } + + void unget_character() override + { + sb.sungetc(); // is.unget() avoided for performance + } + + private: + /// the associated input stream + std::istream& is; + std::streambuf& sb; +}; + +/// input adapter for buffer input +class input_buffer_adapter : public input_adapter_protocol +{ + public: + input_buffer_adapter(const char* b, const std::size_t l) + : cursor(b), limit(b + l), start(b) + { + // skip byte order mark + if (l >= 3 and b[0] == '\xEF' and b[1] == '\xBB' and b[2] == '\xBF') + { + cursor += 3; + } + } + + // delete because of pointer members + input_buffer_adapter(const input_buffer_adapter&) = delete; + input_buffer_adapter& operator=(input_buffer_adapter&) = delete; + + std::char_traits::int_type get_character() noexcept override + { + if (JSON_LIKELY(cursor < limit)) + { + return std::char_traits::to_int_type(*(cursor++)); + } + + return std::char_traits::eof(); + } + + void unget_character() noexcept override + { + if (JSON_LIKELY(cursor > start)) + { + --cursor; + } + } + + private: + /// pointer to the current character + const char* cursor; + /// pointer past the last character + const char* limit; + /// pointer to the first character + const char* start; +}; + +class input_adapter +{ + public: + // native support + + /// input adapter for input stream + input_adapter(std::istream& i) + : ia(std::make_shared(i)) {} + + /// input adapter for input stream + input_adapter(std::istream&& i) + : ia(std::make_shared(i)) {} + + /// input adapter for buffer + template::value and + std::is_integral::type>::value and + sizeof(typename std::remove_pointer::type) == 1, + int>::type = 0> + input_adapter(CharT b, std::size_t l) + : ia(std::make_shared(reinterpret_cast(b), l)) {} + + // derived support + + /// input adapter for string literal + template::value and + std::is_integral::type>::value and + sizeof(typename std::remove_pointer::type) == 1, + int>::type = 0> + input_adapter(CharT b) + : input_adapter(reinterpret_cast(b), + std::strlen(reinterpret_cast(b))) {} + + /// input adapter for iterator range with contiguous storage + template::iterator_category, std::random_access_iterator_tag>::value, + int>::type = 0> + input_adapter(IteratorType first, IteratorType last) + { + // assertion to check that the iterator range is indeed contiguous, + // see http://stackoverflow.com/a/35008842/266378 for more discussion + assert(std::accumulate( + first, last, std::pair(true, 0), + [&first](std::pair res, decltype(*first) val) + { + res.first &= (val == *(std::next(std::addressof(*first), res.second++))); + return res; + }).first); + + // assertion to check that each element is 1 byte long + static_assert( + sizeof(typename std::iterator_traits::value_type) == 1, + "each element in the iterator range must have the size of 1 byte"); + + const auto len = static_cast(std::distance(first, last)); + if (JSON_LIKELY(len > 0)) + { + // there is at least one element: use the address of first + ia = std::make_shared(reinterpret_cast(&(*first)), len); + } + else + { + // the address of first cannot be used: use nullptr + ia = std::make_shared(nullptr, len); + } + } + + /// input adapter for array + template + input_adapter(T (&array)[N]) + : input_adapter(std::begin(array), std::end(array)) {} + + /// input adapter for contiguous container + template::value and + std::is_base_of()))>::iterator_category>::value, + int>::type = 0> + input_adapter(const ContiguousContainer& c) + : input_adapter(std::begin(c), std::end(c)) {} + + operator input_adapter_t() + { + return ia; + } + + private: + /// the actual adapter + input_adapter_t ia = nullptr; +}; +} +} + +#endif + +/*** End of inlined file: input_adapters.hpp ***/ + + +/*** Start of inlined file: lexer.hpp ***/ +#ifndef NLOHMANN_JSON_DETAIL_PARSING_LEXER_HPP +#define NLOHMANN_JSON_DETAIL_PARSING_LEXER_HPP + +#include // localeconv +#include // size_t +#include // strtof, strtod, strtold, strtoll, strtoull +#include // initializer_list +#include // hex, uppercase +#include // setw, setfill +#include // stringstream +#include // char_traits, string +#include // vector + + +/*** Start of inlined file: input_adapters.hpp ***/ +#ifndef NLOHMANN_JSON_DETAIL_PARSING_INPUT_ADAPTERS_HPP +#define NLOHMANN_JSON_DETAIL_PARSING_INPUT_ADAPTERS_HPP + +#include // min +#include // array +#include // assert +#include // size_t +#include // strlen +#include // streamsize, streamoff, streampos +#include // istream +#include // begin, end, iterator_traits, random_access_iterator_tag, distance, next +#include // shared_ptr, make_shared, addressof +#include // accumulate +#include // string, char_traits +#include // enable_if, is_base_of, is_pointer, is_integral, remove_pointer +#include // pair, declval + +namespace nlohmann +{ +namespace detail +{ +//////////////////// +// input adapters // +//////////////////// + +/*! +@brief abstract input adapter interface + +Produces a stream of std::char_traits::int_type characters from a +std::istream, a buffer, or some other input type. Accepts the return of exactly +one non-EOF character for future input. The int_type characters returned +consist of all valid char values as positive values (typically unsigned char), +plus an EOF value outside that range, specified by the value of the function +std::char_traits::eof(). This value is typically -1, but could be any +arbitrary value which is not a valid char value. +*/ +struct input_adapter_protocol +{ + /// get a character [0,255] or std::char_traits::eof(). + virtual std::char_traits::int_type get_character() = 0; + /// restore the last non-eof() character to input + virtual void unget_character() = 0; + virtual ~input_adapter_protocol() = default; +}; + +/// a type to simplify interfaces +using input_adapter_t = std::shared_ptr; + +/*! +Input adapter for a (caching) istream. Ignores a UFT Byte Order Mark at +beginning of input. Does not support changing the underlying std::streambuf +in mid-input. Maintains underlying std::istream and std::streambuf to support +subsequent use of standard std::istream operations to process any input +characters following those used in parsing the JSON input. Clears the +std::istream flags; any input errors (e.g., EOF) will be detected by the first +subsequent call for input from the std::istream. +*/ +class input_stream_adapter : public input_adapter_protocol +{ + public: + ~input_stream_adapter() override + { + // clear stream flags; we use underlying streambuf I/O, do not + // maintain ifstream flags + is.clear(); + } + + explicit input_stream_adapter(std::istream& i) + : is(i), sb(*i.rdbuf()) + { + // skip byte order mark + std::char_traits::int_type c; + if ((c = get_character()) == 0xEF) + { + if ((c = get_character()) == 0xBB) + { + if ((c = get_character()) == 0xBF) + { + return; // Ignore BOM + } + else if (c != std::char_traits::eof()) + { + is.unget(); + } + is.putback('\xBB'); + } + else if (c != std::char_traits::eof()) + { + is.unget(); + } + is.putback('\xEF'); + } + else if (c != std::char_traits::eof()) + { + is.unget(); // no byte order mark; process as usual + } + } + + // delete because of pointer members + input_stream_adapter(const input_stream_adapter&) = delete; + input_stream_adapter& operator=(input_stream_adapter&) = delete; + + // std::istream/std::streambuf use std::char_traits::to_int_type, to + // ensure that std::char_traits::eof() and the character 0xFF do not + // end up as the same value, eg. 0xFFFFFFFF. + std::char_traits::int_type get_character() override + { + return sb.sbumpc(); + } + + void unget_character() override + { + sb.sungetc(); // is.unget() avoided for performance + } + + private: + /// the associated input stream + std::istream& is; + std::streambuf& sb; +}; + +/// input adapter for buffer input +class input_buffer_adapter : public input_adapter_protocol +{ + public: + input_buffer_adapter(const char* b, const std::size_t l) + : cursor(b), limit(b + l), start(b) + { + // skip byte order mark + if (l >= 3 and b[0] == '\xEF' and b[1] == '\xBB' and b[2] == '\xBF') + { + cursor += 3; + } + } + + // delete because of pointer members + input_buffer_adapter(const input_buffer_adapter&) = delete; + input_buffer_adapter& operator=(input_buffer_adapter&) = delete; + + std::char_traits::int_type get_character() noexcept override + { + if (JSON_LIKELY(cursor < limit)) + { + return std::char_traits::to_int_type(*(cursor++)); + } + + return std::char_traits::eof(); + } + + void unget_character() noexcept override + { + if (JSON_LIKELY(cursor > start)) + { + --cursor; + } + } + + private: + /// pointer to the current character + const char* cursor; + /// pointer past the last character + const char* limit; + /// pointer to the first character + const char* start; +}; + +class input_adapter +{ + public: + // native support + + /// input adapter for input stream + input_adapter(std::istream& i) + : ia(std::make_shared(i)) {} + + /// input adapter for input stream + input_adapter(std::istream&& i) + : ia(std::make_shared(i)) {} + + /// input adapter for buffer + template::value and + std::is_integral::type>::value and + sizeof(typename std::remove_pointer::type) == 1, + int>::type = 0> + input_adapter(CharT b, std::size_t l) + : ia(std::make_shared(reinterpret_cast(b), l)) {} + + // derived support + + /// input adapter for string literal + template::value and + std::is_integral::type>::value and + sizeof(typename std::remove_pointer::type) == 1, + int>::type = 0> + input_adapter(CharT b) + : input_adapter(reinterpret_cast(b), + std::strlen(reinterpret_cast(b))) {} + + /// input adapter for iterator range with contiguous storage + template::iterator_category, std::random_access_iterator_tag>::value, + int>::type = 0> + input_adapter(IteratorType first, IteratorType last) + { + // assertion to check that the iterator range is indeed contiguous, + // see http://stackoverflow.com/a/35008842/266378 for more discussion + assert(std::accumulate( + first, last, std::pair(true, 0), + [&first](std::pair res, decltype(*first) val) + { + res.first &= (val == *(std::next(std::addressof(*first), res.second++))); + return res; + }).first); + + // assertion to check that each element is 1 byte long + static_assert( + sizeof(typename std::iterator_traits::value_type) == 1, + "each element in the iterator range must have the size of 1 byte"); + + const auto len = static_cast(std::distance(first, last)); + if (JSON_LIKELY(len > 0)) + { + // there is at least one element: use the address of first + ia = std::make_shared(reinterpret_cast(&(*first)), len); + } + else + { + // the address of first cannot be used: use nullptr + ia = std::make_shared(nullptr, len); + } + } + + /// input adapter for array + template + input_adapter(T (&array)[N]) + : input_adapter(std::begin(array), std::end(array)) {} + + /// input adapter for contiguous container + template::value and + std::is_base_of()))>::iterator_category>::value, + int>::type = 0> + input_adapter(const ContiguousContainer& c) + : input_adapter(std::begin(c), std::end(c)) {} + + operator input_adapter_t() + { + return ia; + } + + private: + /// the actual adapter + input_adapter_t ia = nullptr; +}; +} +} + +#endif + +/*** End of inlined file: input_adapters.hpp ***/ + +namespace nlohmann +{ +namespace detail +{ +/////////// +// lexer // +/////////// + +/*! +@brief lexical analysis + +This class organizes the lexical analysis during JSON deserialization. +*/ +template +class lexer +{ + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + + public: + /// token types for the parser + enum class token_type + { + uninitialized, ///< indicating the scanner is uninitialized + literal_true, ///< the `true` literal + literal_false, ///< the `false` literal + literal_null, ///< the `null` literal + value_string, ///< a string -- use get_string() for actual value + value_unsigned, ///< an unsigned integer -- use get_number_unsigned() for actual value + value_integer, ///< a signed integer -- use get_number_integer() for actual value + value_float, ///< an floating point number -- use get_number_float() for actual value + begin_array, ///< the character for array begin `[` + begin_object, ///< the character for object begin `{` + end_array, ///< the character for array end `]` + end_object, ///< the character for object end `}` + name_separator, ///< the name separator `:` + value_separator, ///< the value separator `,` + parse_error, ///< indicating a parse error + end_of_input, ///< indicating the end of the input buffer + literal_or_value ///< a literal or the begin of a value (only for diagnostics) + }; + + /// return name of values of type token_type (only used for errors) + static const char* token_type_name(const token_type t) noexcept + { + switch (t) + { + case token_type::uninitialized: + return ""; + case token_type::literal_true: + return "true literal"; + case token_type::literal_false: + return "false literal"; + case token_type::literal_null: + return "null literal"; + case token_type::value_string: + return "string literal"; + case lexer::token_type::value_unsigned: + case lexer::token_type::value_integer: + case lexer::token_type::value_float: + return "number literal"; + case token_type::begin_array: + return "'['"; + case token_type::begin_object: + return "'{'"; + case token_type::end_array: + return "']'"; + case token_type::end_object: + return "'}'"; + case token_type::name_separator: + return "':'"; + case token_type::value_separator: + return "','"; + case token_type::parse_error: + return ""; + case token_type::end_of_input: + return "end of input"; + case token_type::literal_or_value: + return "'[', '{', or a literal"; + default: // catch non-enum values + return "unknown token"; // LCOV_EXCL_LINE + } + } + + explicit lexer(detail::input_adapter_t adapter) + : ia(std::move(adapter)), decimal_point_char(get_decimal_point()) {} + + // delete because of pointer members + lexer(const lexer&) = delete; + lexer& operator=(lexer&) = delete; + + private: + ///////////////////// + // locales + ///////////////////// + + /// return the locale-dependent decimal point + static char get_decimal_point() noexcept + { + const auto loc = localeconv(); + assert(loc != nullptr); + return (loc->decimal_point == nullptr) ? '.' : *(loc->decimal_point); + } + + ///////////////////// + // scan functions + ///////////////////// + + /*! + @brief get codepoint from 4 hex characters following `\u` + + For input "\u c1 c2 c3 c4" the codepoint is: + (c1 * 0x1000) + (c2 * 0x0100) + (c3 * 0x0010) + c4 + = (c1 << 12) + (c2 << 8) + (c3 << 4) + (c4 << 0) + + Furthermore, the possible characters '0'..'9', 'A'..'F', and 'a'..'f' + must be converted to the integers 0x0..0x9, 0xA..0xF, 0xA..0xF, resp. The + conversion is done by subtracting the offset (0x30, 0x37, and 0x57) + between the ASCII value of the character and the desired integer value. + + @return codepoint (0x0000..0xFFFF) or -1 in case of an error (e.g. EOF or + non-hex character) + */ + int get_codepoint() + { + // this function only makes sense after reading `\u` + assert(current == 'u'); + int codepoint = 0; + + const auto factors = { 12, 8, 4, 0 }; + for (const auto factor : factors) + { + get(); + + if (current >= '0' and current <= '9') + { + codepoint += ((current - 0x30) << factor); + } + else if (current >= 'A' and current <= 'F') + { + codepoint += ((current - 0x37) << factor); + } + else if (current >= 'a' and current <= 'f') + { + codepoint += ((current - 0x57) << factor); + } + else + { + return -1; + } + } + + assert(0x0000 <= codepoint and codepoint <= 0xFFFF); + return codepoint; + } + + /*! + @brief check if the next byte(s) are inside a given range + + Adds the current byte and, for each passed range, reads a new byte and + checks if it is inside the range. If a violation was detected, set up an + error message and return false. Otherwise, return true. + + @param[in] ranges list of integers; interpreted as list of pairs of + inclusive lower and upper bound, respectively + + @pre The passed list @a ranges must have 2, 4, or 6 elements; that is, + 1, 2, or 3 pairs. This precondition is enforced by an assertion. + + @return true if and only if no range violation was detected + */ + bool next_byte_in_range(std::initializer_list ranges) + { + assert(ranges.size() == 2 or ranges.size() == 4 or ranges.size() == 6); + add(current); + + for (auto range = ranges.begin(); range != ranges.end(); ++range) + { + get(); + if (JSON_LIKELY(*range <= current and current <= *(++range))) + { + add(current); + } + else + { + error_message = "invalid string: ill-formed UTF-8 byte"; + return false; + } + } + + return true; + } + + /*! + @brief scan a string literal + + This function scans a string according to Sect. 7 of RFC 7159. While + scanning, bytes are escaped and copied into buffer yytext. Then the function + returns successfully, yytext is *not* null-terminated (as it may contain \0 + bytes), and yytext.size() is the number of bytes in the string. + + @return token_type::value_string if string could be successfully scanned, + token_type::parse_error otherwise + + @note In case of errors, variable error_message contains a textual + description. + */ + token_type scan_string() + { + // reset yytext (ignore opening quote) + reset(); + + // we entered the function by reading an open quote + assert(current == '\"'); + + while (true) + { + // get next character + switch (get()) + { + // end of file while parsing string + case std::char_traits::eof(): + { + error_message = "invalid string: missing closing quote"; + return token_type::parse_error; + } + + // closing quote + case '\"': + { + return token_type::value_string; + } + + // escapes + case '\\': + { + switch (get()) + { + // quotation mark + case '\"': + add('\"'); + break; + // reverse solidus + case '\\': + add('\\'); + break; + // solidus + case '/': + add('/'); + break; + // backspace + case 'b': + add('\b'); + break; + // form feed + case 'f': + add('\f'); + break; + // line feed + case 'n': + add('\n'); + break; + // carriage return + case 'r': + add('\r'); + break; + // tab + case 't': + add('\t'); + break; + + // unicode escapes + case 'u': + { + const int codepoint1 = get_codepoint(); + int codepoint = codepoint1; // start with codepoint1 + + if (JSON_UNLIKELY(codepoint1 == -1)) + { + error_message = "invalid string: '\\u' must be followed by 4 hex digits"; + return token_type::parse_error; + } + + // check if code point is a high surrogate + if (0xD800 <= codepoint1 and codepoint1 <= 0xDBFF) + { + // expect next \uxxxx entry + if (JSON_LIKELY(get() == '\\' and get() == 'u')) + { + const int codepoint2 = get_codepoint(); + + if (JSON_UNLIKELY(codepoint2 == -1)) + { + error_message = "invalid string: '\\u' must be followed by 4 hex digits"; + return token_type::parse_error; + } + + // check if codepoint2 is a low surrogate + if (JSON_LIKELY(0xDC00 <= codepoint2 and codepoint2 <= 0xDFFF)) + { + // overwrite codepoint + codepoint = + // high surrogate occupies the most significant 22 bits + (codepoint1 << 10) + // low surrogate occupies the least significant 15 bits + + codepoint2 + // there is still the 0xD800, 0xDC00 and 0x10000 noise + // in the result so we have to subtract with: + // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00 + - 0x35FDC00; + } + else + { + error_message = "invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF"; + return token_type::parse_error; + } + } + else + { + error_message = "invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF"; + return token_type::parse_error; + } + } + else + { + if (JSON_UNLIKELY(0xDC00 <= codepoint1 and codepoint1 <= 0xDFFF)) + { + error_message = "invalid string: surrogate U+DC00..U+DFFF must follow U+D800..U+DBFF"; + return token_type::parse_error; + } + } + + // result of the above calculation yields a proper codepoint + assert(0x00 <= codepoint and codepoint <= 0x10FFFF); + + // translate codepoint into bytes + if (codepoint < 0x80) + { + // 1-byte characters: 0xxxxxxx (ASCII) + add(codepoint); + } + else if (codepoint <= 0x7FF) + { + // 2-byte characters: 110xxxxx 10xxxxxx + add(0xC0 | (codepoint >> 6)); + add(0x80 | (codepoint & 0x3F)); + } + else if (codepoint <= 0xFFFF) + { + // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx + add(0xE0 | (codepoint >> 12)); + add(0x80 | ((codepoint >> 6) & 0x3F)); + add(0x80 | (codepoint & 0x3F)); + } + else + { + // 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + add(0xF0 | (codepoint >> 18)); + add(0x80 | ((codepoint >> 12) & 0x3F)); + add(0x80 | ((codepoint >> 6) & 0x3F)); + add(0x80 | (codepoint & 0x3F)); + } + + break; + } + + // other characters after escape + default: + error_message = "invalid string: forbidden character after backslash"; + return token_type::parse_error; + } + + break; + } + + // invalid control characters + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + case 0x09: + case 0x0A: + case 0x0B: + case 0x0C: + case 0x0D: + case 0x0E: + case 0x0F: + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + case 0x1A: + case 0x1B: + case 0x1C: + case 0x1D: + case 0x1E: + case 0x1F: + { + error_message = "invalid string: control character must be escaped"; + return token_type::parse_error; + } + + // U+0020..U+007F (except U+0022 (quote) and U+005C (backspace)) + case 0x20: + case 0x21: + case 0x23: + case 0x24: + case 0x25: + case 0x26: + case 0x27: + case 0x28: + case 0x29: + case 0x2A: + case 0x2B: + case 0x2C: + case 0x2D: + case 0x2E: + case 0x2F: + case 0x30: + case 0x31: + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: + case 0x38: + case 0x39: + case 0x3A: + case 0x3B: + case 0x3C: + case 0x3D: + case 0x3E: + case 0x3F: + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + case 0x48: + case 0x49: + case 0x4A: + case 0x4B: + case 0x4C: + case 0x4D: + case 0x4E: + case 0x4F: + case 0x50: + case 0x51: + case 0x52: + case 0x53: + case 0x54: + case 0x55: + case 0x56: + case 0x57: + case 0x58: + case 0x59: + case 0x5A: + case 0x5B: + case 0x5D: + case 0x5E: + case 0x5F: + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: + case 0x68: + case 0x69: + case 0x6A: + case 0x6B: + case 0x6C: + case 0x6D: + case 0x6E: + case 0x6F: + case 0x70: + case 0x71: + case 0x72: + case 0x73: + case 0x74: + case 0x75: + case 0x76: + case 0x77: + case 0x78: + case 0x79: + case 0x7A: + case 0x7B: + case 0x7C: + case 0x7D: + case 0x7E: + case 0x7F: + { + add(current); + break; + } + + // U+0080..U+07FF: bytes C2..DF 80..BF + case 0xC2: + case 0xC3: + case 0xC4: + case 0xC5: + case 0xC6: + case 0xC7: + case 0xC8: + case 0xC9: + case 0xCA: + case 0xCB: + case 0xCC: + case 0xCD: + case 0xCE: + case 0xCF: + case 0xD0: + case 0xD1: + case 0xD2: + case 0xD3: + case 0xD4: + case 0xD5: + case 0xD6: + case 0xD7: + case 0xD8: + case 0xD9: + case 0xDA: + case 0xDB: + case 0xDC: + case 0xDD: + case 0xDE: + case 0xDF: + { + if (JSON_UNLIKELY(not next_byte_in_range({0x80, 0xBF}))) + { + return token_type::parse_error; + } + break; + } + + // U+0800..U+0FFF: bytes E0 A0..BF 80..BF + case 0xE0: + { + if (JSON_UNLIKELY(not (next_byte_in_range({0xA0, 0xBF, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // U+1000..U+CFFF: bytes E1..EC 80..BF 80..BF + // U+E000..U+FFFF: bytes EE..EF 80..BF 80..BF + case 0xE1: + case 0xE2: + case 0xE3: + case 0xE4: + case 0xE5: + case 0xE6: + case 0xE7: + case 0xE8: + case 0xE9: + case 0xEA: + case 0xEB: + case 0xEC: + case 0xEE: + case 0xEF: + { + if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0xBF, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // U+D000..U+D7FF: bytes ED 80..9F 80..BF + case 0xED: + { + if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0x9F, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // U+10000..U+3FFFF F0 90..BF 80..BF 80..BF + case 0xF0: + { + if (JSON_UNLIKELY(not (next_byte_in_range({0x90, 0xBF, 0x80, 0xBF, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // U+40000..U+FFFFF F1..F3 80..BF 80..BF 80..BF + case 0xF1: + case 0xF2: + case 0xF3: + { + if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0xBF, 0x80, 0xBF, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // U+100000..U+10FFFF F4 80..8F 80..BF 80..BF + case 0xF4: + { + if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0x8F, 0x80, 0xBF, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // remaining bytes (80..C1 and F5..FF) are ill-formed + default: + { + error_message = "invalid string: ill-formed UTF-8 byte"; + return token_type::parse_error; + } + } + } + } + + static void strtof(float& f, const char* str, char** endptr) noexcept + { + f = std::strtof(str, endptr); + } + + static void strtof(double& f, const char* str, char** endptr) noexcept + { + f = std::strtod(str, endptr); + } + + static void strtof(long double& f, const char* str, char** endptr) noexcept + { + f = std::strtold(str, endptr); + } + + /*! + @brief scan a number literal + + This function scans a string according to Sect. 6 of RFC 7159. + + The function is realized with a deterministic finite state machine derived + from the grammar described in RFC 7159. Starting in state "init", the + input is read and used to determined the next state. Only state "done" + accepts the number. State "error" is a trap state to model errors. In the + table below, "anything" means any character but the ones listed before. + + state | 0 | 1-9 | e E | + | - | . | anything + ---------|----------|----------|----------|---------|---------|----------|----------- + init | zero | any1 | [error] | [error] | minus | [error] | [error] + minus | zero | any1 | [error] | [error] | [error] | [error] | [error] + zero | done | done | exponent | done | done | decimal1 | done + any1 | any1 | any1 | exponent | done | done | decimal1 | done + decimal1 | decimal2 | [error] | [error] | [error] | [error] | [error] | [error] + decimal2 | decimal2 | decimal2 | exponent | done | done | done | done + exponent | any2 | any2 | [error] | sign | sign | [error] | [error] + sign | any2 | any2 | [error] | [error] | [error] | [error] | [error] + any2 | any2 | any2 | done | done | done | done | done + + The state machine is realized with one label per state (prefixed with + "scan_number_") and `goto` statements between them. The state machine + contains cycles, but any cycle can be left when EOF is read. Therefore, + the function is guaranteed to terminate. + + During scanning, the read bytes are stored in yytext. This string is + then converted to a signed integer, an unsigned integer, or a + floating-point number. + + @return token_type::value_unsigned, token_type::value_integer, or + token_type::value_float if number could be successfully scanned, + token_type::parse_error otherwise + + @note The scanner is independent of the current locale. Internally, the + locale's decimal point is used instead of `.` to work with the + locale-dependent converters. + */ + token_type scan_number() + { + // reset yytext to store the number's bytes + reset(); + + // the type of the parsed number; initially set to unsigned; will be + // changed if minus sign, decimal point or exponent is read + token_type number_type = token_type::value_unsigned; + + // state (init): we just found out we need to scan a number + switch (current) + { + case '-': + { + add(current); + goto scan_number_minus; + } + + case '0': + { + add(current); + goto scan_number_zero; + } + + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any1; + } + + default: + { + // all other characters are rejected outside scan_number() + assert(false); // LCOV_EXCL_LINE + } + } + +scan_number_minus: + // state: we just parsed a leading minus sign + number_type = token_type::value_integer; + switch (get()) + { + case '0': + { + add(current); + goto scan_number_zero; + } + + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any1; + } + + default: + { + error_message = "invalid number; expected digit after '-'"; + return token_type::parse_error; + } + } + +scan_number_zero: + // state: we just parse a zero (maybe with a leading minus sign) + switch (get()) + { + case '.': + { + add(decimal_point_char); + goto scan_number_decimal1; + } + + case 'e': + case 'E': + { + add(current); + goto scan_number_exponent; + } + + default: + goto scan_number_done; + } + +scan_number_any1: + // state: we just parsed a number 0-9 (maybe with a leading minus sign) + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any1; + } + + case '.': + { + add(decimal_point_char); + goto scan_number_decimal1; + } + + case 'e': + case 'E': + { + add(current); + goto scan_number_exponent; + } + + default: + goto scan_number_done; + } + +scan_number_decimal1: + // state: we just parsed a decimal point + number_type = token_type::value_float; + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_decimal2; + } + + default: + { + error_message = "invalid number; expected digit after '.'"; + return token_type::parse_error; + } + } + +scan_number_decimal2: + // we just parsed at least one number after a decimal point + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_decimal2; + } + + case 'e': + case 'E': + { + add(current); + goto scan_number_exponent; + } + + default: + goto scan_number_done; + } + +scan_number_exponent: + // we just parsed an exponent + number_type = token_type::value_float; + switch (get()) + { + case '+': + case '-': + { + add(current); + goto scan_number_sign; + } + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any2; + } + + default: + { + error_message = + "invalid number; expected '+', '-', or digit after exponent"; + return token_type::parse_error; + } + } + +scan_number_sign: + // we just parsed an exponent sign + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any2; + } + + default: + { + error_message = "invalid number; expected digit after exponent sign"; + return token_type::parse_error; + } + } + +scan_number_any2: + // we just parsed a number after the exponent or exponent sign + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any2; + } + + default: + goto scan_number_done; + } + +scan_number_done: + // unget the character after the number (we only read it to know that + // we are done scanning a number) + unget(); + + char* endptr = nullptr; + errno = 0; + + // try to parse integers first and fall back to floats + if (number_type == token_type::value_unsigned) + { + const auto x = std::strtoull(yytext.data(), &endptr, 10); + + // we checked the number format before + assert(endptr == yytext.data() + yytext.size()); + + if (errno == 0) + { + value_unsigned = static_cast(x); + if (value_unsigned == x) + { + return token_type::value_unsigned; + } + } + } + else if (number_type == token_type::value_integer) + { + const auto x = std::strtoll(yytext.data(), &endptr, 10); + + // we checked the number format before + assert(endptr == yytext.data() + yytext.size()); + + if (errno == 0) + { + value_integer = static_cast(x); + if (value_integer == x) + { + return token_type::value_integer; + } + } + } + + // this code is reached if we parse a floating-point number or if an + // integer conversion above failed + strtof(value_float, yytext.data(), &endptr); + + // we checked the number format before + assert(endptr == yytext.data() + yytext.size()); + + return token_type::value_float; + } + + /*! + @param[in] literal_text the literal text to expect + @param[in] length the length of the passed literal text + @param[in] return_type the token type to return on success + */ + token_type scan_literal(const char* literal_text, const std::size_t length, + token_type return_type) + { + assert(current == literal_text[0]); + for (std::size_t i = 1; i < length; ++i) + { + if (JSON_UNLIKELY(get() != literal_text[i])) + { + error_message = "invalid literal"; + return token_type::parse_error; + } + } + return return_type; + } + + ///////////////////// + // input management + ///////////////////// + + /// reset yytext; current character is beginning of token + void reset() noexcept + { + yytext.clear(); + token_string.clear(); + token_string.push_back(std::char_traits::to_char_type(current)); + } + + /* + @brief get next character from the input + + This function provides the interface to the used input adapter. It does + not throw in case the input reached EOF, but returns a + `std::char_traits::eof()` in that case. Stores the scanned characters + for use in error messages. + + @return character read from the input + */ + std::char_traits::int_type get() + { + ++chars_read; + current = ia->get_character(); + if (JSON_LIKELY(current != std::char_traits::eof())) + { + token_string.push_back(std::char_traits::to_char_type(current)); + } + return current; + } + + /// unget current character (return it again on next get) + void unget() + { + --chars_read; + if (JSON_LIKELY(current != std::char_traits::eof())) + { + ia->unget_character(); + assert(token_string.size() != 0); + token_string.pop_back(); + } + } + + /// add a character to yytext + void add(int c) + { + yytext.push_back(std::char_traits::to_char_type(c)); + } + + public: + ///////////////////// + // value getters + ///////////////////// + + /// return integer value + constexpr number_integer_t get_number_integer() const noexcept + { + return value_integer; + } + + /// return unsigned integer value + constexpr number_unsigned_t get_number_unsigned() const noexcept + { + return value_unsigned; + } + + /// return floating-point value + constexpr number_float_t get_number_float() const noexcept + { + return value_float; + } + + /// return current string value (implicitly resets the token; useful only once) + std::string move_string() + { + return std::move(yytext); + } + + ///////////////////// + // diagnostics + ///////////////////// + + /// return position of last read token + constexpr std::size_t get_position() const noexcept + { + return chars_read; + } + + /// return the last read token (for errors only). Will never contain EOF + /// (an arbitrary value that is not a valid char value, often -1), because + /// 255 may legitimately occur. May contain NUL, which should be escaped. + std::string get_token_string() const + { + // escape control characters + std::string result; + for (const auto c : token_string) + { + if ('\x00' <= c and c <= '\x1F') + { + // escape control characters + std::stringstream ss; + ss << "(c) << ">"; + result += ss.str(); + } + else + { + // add character as is + result.push_back(c); + } + } + + return result; + } + + /// return syntax error message + constexpr const char* get_error_message() const noexcept + { + return error_message; + } + + ///////////////////// + // actual scanner + ///////////////////// + + token_type scan() + { + // read next character and ignore whitespace + do + { + get(); + } + while (current == ' ' or current == '\t' or current == '\n' or current == '\r'); + + switch (current) + { + // structural characters + case '[': + return token_type::begin_array; + case ']': + return token_type::end_array; + case '{': + return token_type::begin_object; + case '}': + return token_type::end_object; + case ':': + return token_type::name_separator; + case ',': + return token_type::value_separator; + + // literals + case 't': + return scan_literal("true", 4, token_type::literal_true); + case 'f': + return scan_literal("false", 5, token_type::literal_false); + case 'n': + return scan_literal("null", 4, token_type::literal_null); + + // string + case '\"': + return scan_string(); + + // number + case '-': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + return scan_number(); + + // end of input (the null byte is needed when parsing from + // string literals) + case '\0': + case std::char_traits::eof(): + return token_type::end_of_input; + + // error + default: + error_message = "invalid literal"; + return token_type::parse_error; + } + } + + private: + /// input adapter + detail::input_adapter_t ia = nullptr; + + /// the current character + std::char_traits::int_type current = std::char_traits::eof(); + + /// the number of characters read + std::size_t chars_read = 0; + + /// raw input token string (for error messages) + std::vector token_string {}; + + /// buffer for variable-length tokens (numbers, strings) + std::string yytext {}; + + /// a description of occurred lexer errors + const char* error_message = ""; + + // number values + number_integer_t value_integer = 0; + number_unsigned_t value_unsigned = 0; + number_float_t value_float = 0; + + /// the decimal point + const char decimal_point_char = '.'; +}; +} +} + +#endif + +/*** End of inlined file: lexer.hpp ***/ + + +/*** Start of inlined file: parser.hpp ***/ +#ifndef NLOHMANN_JSON_DETAIL_PARSING_PARSER_HPP +#define NLOHMANN_JSON_DETAIL_PARSING_PARSER_HPP + +#include // assert +#include // isfinite +#include // uint8_t +#include // function +#include // string +#include // move + + +/*** Start of inlined file: lexer.hpp ***/ +#ifndef NLOHMANN_JSON_DETAIL_PARSING_LEXER_HPP +#define NLOHMANN_JSON_DETAIL_PARSING_LEXER_HPP + +#include // localeconv +#include // size_t +#include // strtof, strtod, strtold, strtoll, strtoull +#include // initializer_list +#include // hex, uppercase +#include // setw, setfill +#include // stringstream +#include // char_traits, string +#include // vector + +namespace nlohmann +{ +namespace detail +{ +/////////// +// lexer // +/////////// + +/*! +@brief lexical analysis + +This class organizes the lexical analysis during JSON deserialization. +*/ +template +class lexer +{ + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + + public: + /// token types for the parser + enum class token_type + { + uninitialized, ///< indicating the scanner is uninitialized + literal_true, ///< the `true` literal + literal_false, ///< the `false` literal + literal_null, ///< the `null` literal + value_string, ///< a string -- use get_string() for actual value + value_unsigned, ///< an unsigned integer -- use get_number_unsigned() for actual value + value_integer, ///< a signed integer -- use get_number_integer() for actual value + value_float, ///< an floating point number -- use get_number_float() for actual value + begin_array, ///< the character for array begin `[` + begin_object, ///< the character for object begin `{` + end_array, ///< the character for array end `]` + end_object, ///< the character for object end `}` + name_separator, ///< the name separator `:` + value_separator, ///< the value separator `,` + parse_error, ///< indicating a parse error + end_of_input, ///< indicating the end of the input buffer + literal_or_value ///< a literal or the begin of a value (only for diagnostics) + }; + + /// return name of values of type token_type (only used for errors) + static const char* token_type_name(const token_type t) noexcept + { + switch (t) + { + case token_type::uninitialized: + return ""; + case token_type::literal_true: + return "true literal"; + case token_type::literal_false: + return "false literal"; + case token_type::literal_null: + return "null literal"; + case token_type::value_string: + return "string literal"; + case lexer::token_type::value_unsigned: + case lexer::token_type::value_integer: + case lexer::token_type::value_float: + return "number literal"; + case token_type::begin_array: + return "'['"; + case token_type::begin_object: + return "'{'"; + case token_type::end_array: + return "']'"; + case token_type::end_object: + return "'}'"; + case token_type::name_separator: + return "':'"; + case token_type::value_separator: + return "','"; + case token_type::parse_error: + return ""; + case token_type::end_of_input: + return "end of input"; + case token_type::literal_or_value: + return "'[', '{', or a literal"; + default: // catch non-enum values + return "unknown token"; // LCOV_EXCL_LINE + } + } + + explicit lexer(detail::input_adapter_t adapter) + : ia(std::move(adapter)), decimal_point_char(get_decimal_point()) {} + + // delete because of pointer members + lexer(const lexer&) = delete; + lexer& operator=(lexer&) = delete; + + private: + ///////////////////// + // locales + ///////////////////// + + /// return the locale-dependent decimal point + static char get_decimal_point() noexcept + { + const auto loc = localeconv(); + assert(loc != nullptr); + return (loc->decimal_point == nullptr) ? '.' : *(loc->decimal_point); + } + + ///////////////////// + // scan functions + ///////////////////// + + /*! + @brief get codepoint from 4 hex characters following `\u` + + For input "\u c1 c2 c3 c4" the codepoint is: + (c1 * 0x1000) + (c2 * 0x0100) + (c3 * 0x0010) + c4 + = (c1 << 12) + (c2 << 8) + (c3 << 4) + (c4 << 0) + + Furthermore, the possible characters '0'..'9', 'A'..'F', and 'a'..'f' + must be converted to the integers 0x0..0x9, 0xA..0xF, 0xA..0xF, resp. The + conversion is done by subtracting the offset (0x30, 0x37, and 0x57) + between the ASCII value of the character and the desired integer value. + + @return codepoint (0x0000..0xFFFF) or -1 in case of an error (e.g. EOF or + non-hex character) + */ + int get_codepoint() + { + // this function only makes sense after reading `\u` + assert(current == 'u'); + int codepoint = 0; + + const auto factors = { 12, 8, 4, 0 }; + for (const auto factor : factors) + { + get(); + + if (current >= '0' and current <= '9') + { + codepoint += ((current - 0x30) << factor); + } + else if (current >= 'A' and current <= 'F') + { + codepoint += ((current - 0x37) << factor); + } + else if (current >= 'a' and current <= 'f') + { + codepoint += ((current - 0x57) << factor); + } + else + { + return -1; + } + } + + assert(0x0000 <= codepoint and codepoint <= 0xFFFF); + return codepoint; + } + + /*! + @brief check if the next byte(s) are inside a given range + + Adds the current byte and, for each passed range, reads a new byte and + checks if it is inside the range. If a violation was detected, set up an + error message and return false. Otherwise, return true. + + @param[in] ranges list of integers; interpreted as list of pairs of + inclusive lower and upper bound, respectively + + @pre The passed list @a ranges must have 2, 4, or 6 elements; that is, + 1, 2, or 3 pairs. This precondition is enforced by an assertion. + + @return true if and only if no range violation was detected + */ + bool next_byte_in_range(std::initializer_list ranges) + { + assert(ranges.size() == 2 or ranges.size() == 4 or ranges.size() == 6); + add(current); + + for (auto range = ranges.begin(); range != ranges.end(); ++range) + { + get(); + if (JSON_LIKELY(*range <= current and current <= *(++range))) + { + add(current); + } + else + { + error_message = "invalid string: ill-formed UTF-8 byte"; + return false; + } + } + + return true; + } + + /*! + @brief scan a string literal + + This function scans a string according to Sect. 7 of RFC 7159. While + scanning, bytes are escaped and copied into buffer yytext. Then the function + returns successfully, yytext is *not* null-terminated (as it may contain \0 + bytes), and yytext.size() is the number of bytes in the string. + + @return token_type::value_string if string could be successfully scanned, + token_type::parse_error otherwise + + @note In case of errors, variable error_message contains a textual + description. + */ + token_type scan_string() + { + // reset yytext (ignore opening quote) + reset(); + + // we entered the function by reading an open quote + assert(current == '\"'); + + while (true) + { + // get next character + switch (get()) + { + // end of file while parsing string + case std::char_traits::eof(): + { + error_message = "invalid string: missing closing quote"; + return token_type::parse_error; + } + + // closing quote + case '\"': + { + return token_type::value_string; + } + + // escapes + case '\\': + { + switch (get()) + { + // quotation mark + case '\"': + add('\"'); + break; + // reverse solidus + case '\\': + add('\\'); + break; + // solidus + case '/': + add('/'); + break; + // backspace + case 'b': + add('\b'); + break; + // form feed + case 'f': + add('\f'); + break; + // line feed + case 'n': + add('\n'); + break; + // carriage return + case 'r': + add('\r'); + break; + // tab + case 't': + add('\t'); + break; + + // unicode escapes + case 'u': + { + const int codepoint1 = get_codepoint(); + int codepoint = codepoint1; // start with codepoint1 + + if (JSON_UNLIKELY(codepoint1 == -1)) + { + error_message = "invalid string: '\\u' must be followed by 4 hex digits"; + return token_type::parse_error; + } + + // check if code point is a high surrogate + if (0xD800 <= codepoint1 and codepoint1 <= 0xDBFF) + { + // expect next \uxxxx entry + if (JSON_LIKELY(get() == '\\' and get() == 'u')) + { + const int codepoint2 = get_codepoint(); + + if (JSON_UNLIKELY(codepoint2 == -1)) + { + error_message = "invalid string: '\\u' must be followed by 4 hex digits"; + return token_type::parse_error; + } + + // check if codepoint2 is a low surrogate + if (JSON_LIKELY(0xDC00 <= codepoint2 and codepoint2 <= 0xDFFF)) + { + // overwrite codepoint + codepoint = + // high surrogate occupies the most significant 22 bits + (codepoint1 << 10) + // low surrogate occupies the least significant 15 bits + + codepoint2 + // there is still the 0xD800, 0xDC00 and 0x10000 noise + // in the result so we have to subtract with: + // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00 + - 0x35FDC00; + } + else + { + error_message = "invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF"; + return token_type::parse_error; + } + } + else + { + error_message = "invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF"; + return token_type::parse_error; + } + } + else + { + if (JSON_UNLIKELY(0xDC00 <= codepoint1 and codepoint1 <= 0xDFFF)) + { + error_message = "invalid string: surrogate U+DC00..U+DFFF must follow U+D800..U+DBFF"; + return token_type::parse_error; + } + } + + // result of the above calculation yields a proper codepoint + assert(0x00 <= codepoint and codepoint <= 0x10FFFF); + + // translate codepoint into bytes + if (codepoint < 0x80) + { + // 1-byte characters: 0xxxxxxx (ASCII) + add(codepoint); + } + else if (codepoint <= 0x7FF) + { + // 2-byte characters: 110xxxxx 10xxxxxx + add(0xC0 | (codepoint >> 6)); + add(0x80 | (codepoint & 0x3F)); + } + else if (codepoint <= 0xFFFF) + { + // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx + add(0xE0 | (codepoint >> 12)); + add(0x80 | ((codepoint >> 6) & 0x3F)); + add(0x80 | (codepoint & 0x3F)); + } + else + { + // 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + add(0xF0 | (codepoint >> 18)); + add(0x80 | ((codepoint >> 12) & 0x3F)); + add(0x80 | ((codepoint >> 6) & 0x3F)); + add(0x80 | (codepoint & 0x3F)); + } + + break; + } + + // other characters after escape + default: + error_message = "invalid string: forbidden character after backslash"; + return token_type::parse_error; + } + + break; + } + + // invalid control characters + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + case 0x09: + case 0x0A: + case 0x0B: + case 0x0C: + case 0x0D: + case 0x0E: + case 0x0F: + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + case 0x1A: + case 0x1B: + case 0x1C: + case 0x1D: + case 0x1E: + case 0x1F: + { + error_message = "invalid string: control character must be escaped"; + return token_type::parse_error; + } + + // U+0020..U+007F (except U+0022 (quote) and U+005C (backspace)) + case 0x20: + case 0x21: + case 0x23: + case 0x24: + case 0x25: + case 0x26: + case 0x27: + case 0x28: + case 0x29: + case 0x2A: + case 0x2B: + case 0x2C: + case 0x2D: + case 0x2E: + case 0x2F: + case 0x30: + case 0x31: + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: + case 0x38: + case 0x39: + case 0x3A: + case 0x3B: + case 0x3C: + case 0x3D: + case 0x3E: + case 0x3F: + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + case 0x48: + case 0x49: + case 0x4A: + case 0x4B: + case 0x4C: + case 0x4D: + case 0x4E: + case 0x4F: + case 0x50: + case 0x51: + case 0x52: + case 0x53: + case 0x54: + case 0x55: + case 0x56: + case 0x57: + case 0x58: + case 0x59: + case 0x5A: + case 0x5B: + case 0x5D: + case 0x5E: + case 0x5F: + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: + case 0x68: + case 0x69: + case 0x6A: + case 0x6B: + case 0x6C: + case 0x6D: + case 0x6E: + case 0x6F: + case 0x70: + case 0x71: + case 0x72: + case 0x73: + case 0x74: + case 0x75: + case 0x76: + case 0x77: + case 0x78: + case 0x79: + case 0x7A: + case 0x7B: + case 0x7C: + case 0x7D: + case 0x7E: + case 0x7F: + { + add(current); + break; + } + + // U+0080..U+07FF: bytes C2..DF 80..BF + case 0xC2: + case 0xC3: + case 0xC4: + case 0xC5: + case 0xC6: + case 0xC7: + case 0xC8: + case 0xC9: + case 0xCA: + case 0xCB: + case 0xCC: + case 0xCD: + case 0xCE: + case 0xCF: + case 0xD0: + case 0xD1: + case 0xD2: + case 0xD3: + case 0xD4: + case 0xD5: + case 0xD6: + case 0xD7: + case 0xD8: + case 0xD9: + case 0xDA: + case 0xDB: + case 0xDC: + case 0xDD: + case 0xDE: + case 0xDF: + { + if (JSON_UNLIKELY(not next_byte_in_range({0x80, 0xBF}))) + { + return token_type::parse_error; + } + break; + } + + // U+0800..U+0FFF: bytes E0 A0..BF 80..BF + case 0xE0: + { + if (JSON_UNLIKELY(not (next_byte_in_range({0xA0, 0xBF, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // U+1000..U+CFFF: bytes E1..EC 80..BF 80..BF + // U+E000..U+FFFF: bytes EE..EF 80..BF 80..BF + case 0xE1: + case 0xE2: + case 0xE3: + case 0xE4: + case 0xE5: + case 0xE6: + case 0xE7: + case 0xE8: + case 0xE9: + case 0xEA: + case 0xEB: + case 0xEC: + case 0xEE: + case 0xEF: + { + if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0xBF, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // U+D000..U+D7FF: bytes ED 80..9F 80..BF + case 0xED: + { + if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0x9F, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // U+10000..U+3FFFF F0 90..BF 80..BF 80..BF + case 0xF0: + { + if (JSON_UNLIKELY(not (next_byte_in_range({0x90, 0xBF, 0x80, 0xBF, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // U+40000..U+FFFFF F1..F3 80..BF 80..BF 80..BF + case 0xF1: + case 0xF2: + case 0xF3: + { + if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0xBF, 0x80, 0xBF, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // U+100000..U+10FFFF F4 80..8F 80..BF 80..BF + case 0xF4: + { + if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0x8F, 0x80, 0xBF, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // remaining bytes (80..C1 and F5..FF) are ill-formed + default: + { + error_message = "invalid string: ill-formed UTF-8 byte"; + return token_type::parse_error; + } + } + } + } + + static void strtof(float& f, const char* str, char** endptr) noexcept + { + f = std::strtof(str, endptr); + } + + static void strtof(double& f, const char* str, char** endptr) noexcept + { + f = std::strtod(str, endptr); + } + + static void strtof(long double& f, const char* str, char** endptr) noexcept + { + f = std::strtold(str, endptr); + } + + /*! + @brief scan a number literal + + This function scans a string according to Sect. 6 of RFC 7159. + + The function is realized with a deterministic finite state machine derived + from the grammar described in RFC 7159. Starting in state "init", the + input is read and used to determined the next state. Only state "done" + accepts the number. State "error" is a trap state to model errors. In the + table below, "anything" means any character but the ones listed before. + + state | 0 | 1-9 | e E | + | - | . | anything + ---------|----------|----------|----------|---------|---------|----------|----------- + init | zero | any1 | [error] | [error] | minus | [error] | [error] + minus | zero | any1 | [error] | [error] | [error] | [error] | [error] + zero | done | done | exponent | done | done | decimal1 | done + any1 | any1 | any1 | exponent | done | done | decimal1 | done + decimal1 | decimal2 | [error] | [error] | [error] | [error] | [error] | [error] + decimal2 | decimal2 | decimal2 | exponent | done | done | done | done + exponent | any2 | any2 | [error] | sign | sign | [error] | [error] + sign | any2 | any2 | [error] | [error] | [error] | [error] | [error] + any2 | any2 | any2 | done | done | done | done | done + + The state machine is realized with one label per state (prefixed with + "scan_number_") and `goto` statements between them. The state machine + contains cycles, but any cycle can be left when EOF is read. Therefore, + the function is guaranteed to terminate. + + During scanning, the read bytes are stored in yytext. This string is + then converted to a signed integer, an unsigned integer, or a + floating-point number. + + @return token_type::value_unsigned, token_type::value_integer, or + token_type::value_float if number could be successfully scanned, + token_type::parse_error otherwise + + @note The scanner is independent of the current locale. Internally, the + locale's decimal point is used instead of `.` to work with the + locale-dependent converters. + */ + token_type scan_number() + { + // reset yytext to store the number's bytes + reset(); + + // the type of the parsed number; initially set to unsigned; will be + // changed if minus sign, decimal point or exponent is read + token_type number_type = token_type::value_unsigned; + + // state (init): we just found out we need to scan a number + switch (current) + { + case '-': + { + add(current); + goto scan_number_minus; + } + + case '0': + { + add(current); + goto scan_number_zero; + } + + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any1; + } + + default: + { + // all other characters are rejected outside scan_number() + assert(false); // LCOV_EXCL_LINE + } + } + +scan_number_minus: + // state: we just parsed a leading minus sign + number_type = token_type::value_integer; + switch (get()) + { + case '0': + { + add(current); + goto scan_number_zero; + } + + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any1; + } + + default: + { + error_message = "invalid number; expected digit after '-'"; + return token_type::parse_error; + } + } + +scan_number_zero: + // state: we just parse a zero (maybe with a leading minus sign) + switch (get()) + { + case '.': + { + add(decimal_point_char); + goto scan_number_decimal1; + } + + case 'e': + case 'E': + { + add(current); + goto scan_number_exponent; + } + + default: + goto scan_number_done; + } + +scan_number_any1: + // state: we just parsed a number 0-9 (maybe with a leading minus sign) + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any1; + } + + case '.': + { + add(decimal_point_char); + goto scan_number_decimal1; + } + + case 'e': + case 'E': + { + add(current); + goto scan_number_exponent; + } + + default: + goto scan_number_done; + } + +scan_number_decimal1: + // state: we just parsed a decimal point + number_type = token_type::value_float; + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_decimal2; + } + + default: + { + error_message = "invalid number; expected digit after '.'"; + return token_type::parse_error; + } + } + +scan_number_decimal2: + // we just parsed at least one number after a decimal point + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_decimal2; + } + + case 'e': + case 'E': + { + add(current); + goto scan_number_exponent; + } + + default: + goto scan_number_done; + } + +scan_number_exponent: + // we just parsed an exponent + number_type = token_type::value_float; + switch (get()) + { + case '+': + case '-': + { + add(current); + goto scan_number_sign; + } + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any2; + } + + default: + { + error_message = + "invalid number; expected '+', '-', or digit after exponent"; + return token_type::parse_error; + } + } + +scan_number_sign: + // we just parsed an exponent sign + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any2; + } + + default: + { + error_message = "invalid number; expected digit after exponent sign"; + return token_type::parse_error; + } + } + +scan_number_any2: + // we just parsed a number after the exponent or exponent sign + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any2; + } + + default: + goto scan_number_done; + } + +scan_number_done: + // unget the character after the number (we only read it to know that + // we are done scanning a number) + unget(); + + char* endptr = nullptr; + errno = 0; + + // try to parse integers first and fall back to floats + if (number_type == token_type::value_unsigned) + { + const auto x = std::strtoull(yytext.data(), &endptr, 10); + + // we checked the number format before + assert(endptr == yytext.data() + yytext.size()); + + if (errno == 0) + { + value_unsigned = static_cast(x); + if (value_unsigned == x) + { + return token_type::value_unsigned; + } + } + } + else if (number_type == token_type::value_integer) + { + const auto x = std::strtoll(yytext.data(), &endptr, 10); + + // we checked the number format before + assert(endptr == yytext.data() + yytext.size()); + + if (errno == 0) + { + value_integer = static_cast(x); + if (value_integer == x) + { + return token_type::value_integer; + } + } + } + + // this code is reached if we parse a floating-point number or if an + // integer conversion above failed + strtof(value_float, yytext.data(), &endptr); + + // we checked the number format before + assert(endptr == yytext.data() + yytext.size()); + + return token_type::value_float; + } + + /*! + @param[in] literal_text the literal text to expect + @param[in] length the length of the passed literal text + @param[in] return_type the token type to return on success + */ + token_type scan_literal(const char* literal_text, const std::size_t length, + token_type return_type) + { + assert(current == literal_text[0]); + for (std::size_t i = 1; i < length; ++i) + { + if (JSON_UNLIKELY(get() != literal_text[i])) + { + error_message = "invalid literal"; + return token_type::parse_error; + } + } + return return_type; + } + + ///////////////////// + // input management + ///////////////////// + + /// reset yytext; current character is beginning of token + void reset() noexcept + { + yytext.clear(); + token_string.clear(); + token_string.push_back(std::char_traits::to_char_type(current)); + } + + /* + @brief get next character from the input + + This function provides the interface to the used input adapter. It does + not throw in case the input reached EOF, but returns a + `std::char_traits::eof()` in that case. Stores the scanned characters + for use in error messages. + + @return character read from the input + */ + std::char_traits::int_type get() + { + ++chars_read; + current = ia->get_character(); + if (JSON_LIKELY(current != std::char_traits::eof())) + { + token_string.push_back(std::char_traits::to_char_type(current)); + } + return current; + } + + /// unget current character (return it again on next get) + void unget() + { + --chars_read; + if (JSON_LIKELY(current != std::char_traits::eof())) + { + ia->unget_character(); + assert(token_string.size() != 0); + token_string.pop_back(); + } + } + + /// add a character to yytext + void add(int c) + { + yytext.push_back(std::char_traits::to_char_type(c)); + } + + public: + ///////////////////// + // value getters + ///////////////////// + + /// return integer value + constexpr number_integer_t get_number_integer() const noexcept + { + return value_integer; + } + + /// return unsigned integer value + constexpr number_unsigned_t get_number_unsigned() const noexcept + { + return value_unsigned; + } + + /// return floating-point value + constexpr number_float_t get_number_float() const noexcept + { + return value_float; + } + + /// return current string value (implicitly resets the token; useful only once) + std::string move_string() + { + return std::move(yytext); + } + + ///////////////////// + // diagnostics + ///////////////////// + + /// return position of last read token + constexpr std::size_t get_position() const noexcept + { + return chars_read; + } + + /// return the last read token (for errors only). Will never contain EOF + /// (an arbitrary value that is not a valid char value, often -1), because + /// 255 may legitimately occur. May contain NUL, which should be escaped. + std::string get_token_string() const + { + // escape control characters + std::string result; + for (const auto c : token_string) + { + if ('\x00' <= c and c <= '\x1F') + { + // escape control characters + std::stringstream ss; + ss << "(c) << ">"; + result += ss.str(); + } + else + { + // add character as is + result.push_back(c); + } + } + + return result; + } + + /// return syntax error message + constexpr const char* get_error_message() const noexcept + { + return error_message; + } + + ///////////////////// + // actual scanner + ///////////////////// + + token_type scan() + { + // read next character and ignore whitespace + do + { + get(); + } + while (current == ' ' or current == '\t' or current == '\n' or current == '\r'); + + switch (current) + { + // structural characters + case '[': + return token_type::begin_array; + case ']': + return token_type::end_array; + case '{': + return token_type::begin_object; + case '}': + return token_type::end_object; + case ':': + return token_type::name_separator; + case ',': + return token_type::value_separator; + + // literals + case 't': + return scan_literal("true", 4, token_type::literal_true); + case 'f': + return scan_literal("false", 5, token_type::literal_false); + case 'n': + return scan_literal("null", 4, token_type::literal_null); + + // string + case '\"': + return scan_string(); + + // number + case '-': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + return scan_number(); + + // end of input (the null byte is needed when parsing from + // string literals) + case '\0': + case std::char_traits::eof(): + return token_type::end_of_input; + + // error + default: + error_message = "invalid literal"; + return token_type::parse_error; + } + } + + private: + /// input adapter + detail::input_adapter_t ia = nullptr; + + /// the current character + std::char_traits::int_type current = std::char_traits::eof(); + + /// the number of characters read + std::size_t chars_read = 0; + + /// raw input token string (for error messages) + std::vector token_string {}; + + /// buffer for variable-length tokens (numbers, strings) + std::string yytext {}; + + /// a description of occurred lexer errors + const char* error_message = ""; + + // number values + number_integer_t value_integer = 0; + number_unsigned_t value_unsigned = 0; + number_float_t value_float = 0; + + /// the decimal point + const char decimal_point_char = '.'; +}; +} +} + +#endif + +/*** End of inlined file: lexer.hpp ***/ + +namespace nlohmann +{ +namespace detail +{ +//////////// +// parser // +//////////// + +/*! +@brief syntax analysis + +This class implements a recursive decent parser. +*/ +template +class parser +{ + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + using lexer_t = lexer; + using token_type = typename lexer_t::token_type; + + public: + enum class parse_event_t : uint8_t + { + /// the parser read `{` and started to process a JSON object + object_start, + /// the parser read `}` and finished processing a JSON object + object_end, + /// the parser read `[` and started to process a JSON array + array_start, + /// the parser read `]` and finished processing a JSON array + array_end, + /// the parser read a key of a value in an object + key, + /// the parser finished reading a JSON value + value + }; + + using parser_callback_t = + std::function; + + /// a parser reading from an input adapter + explicit parser(detail::input_adapter_t adapter, + const parser_callback_t cb = nullptr, + const bool allow_exceptions_ = true) + : callback(cb), m_lexer(adapter), allow_exceptions(allow_exceptions_) + {} + + /*! + @brief public parser interface + + @param[in] strict whether to expect the last token to be EOF + @param[in,out] result parsed JSON value + + @throw parse_error.101 in case of an unexpected token + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + */ + void parse(const bool strict, BasicJsonType& result) + { + // read first token + get_token(); + + parse_internal(true, result); + result.assert_invariant(); + + // in strict mode, input must be completely read + if (strict) + { + get_token(); + expect(token_type::end_of_input); + } + + // in case of an error, return discarded value + if (errored) + { + result = value_t::discarded; + return; + } + + // set top-level value to null if it was discarded by the callback + // function + if (result.is_discarded()) + { + result = nullptr; + } + } + + /*! + @brief public accept interface + + @param[in] strict whether to expect the last token to be EOF + @return whether the input is a proper JSON text + */ + bool accept(const bool strict = true) + { + // read first token + get_token(); + + if (not accept_internal()) + { + return false; + } + + // strict => last token must be EOF + return not strict or (get_token() == token_type::end_of_input); + } + + private: + /*! + @brief the actual parser + @throw parse_error.101 in case of an unexpected token + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + */ + void parse_internal(bool keep, BasicJsonType& result) + { + // never parse after a parse error was detected + assert(not errored); + + // start with a discarded value + if (not result.is_discarded()) + { + result.m_value.destroy(result.m_type); + result.m_type = value_t::discarded; + } + + switch (last_token) + { + case token_type::begin_object: + { + if (keep) + { + if (callback) + { + keep = callback(depth++, parse_event_t::object_start, result); + } + + if (not callback or keep) + { + // explicitly set result to object to cope with {} + result.m_type = value_t::object; + result.m_value = value_t::object; + } + } + + // read next token + get_token(); + + // closing } -> we are done + if (last_token == token_type::end_object) + { + if (keep and callback and not callback(--depth, parse_event_t::object_end, result)) + { + result.m_value.destroy(result.m_type); + result.m_type = value_t::discarded; + } + break; + } + + // parse values + std::string key; + BasicJsonType value; + while (true) + { + // store key + if (not expect(token_type::value_string)) + { + return; + } + key = m_lexer.move_string(); + + bool keep_tag = false; + if (keep) + { + if (callback) + { + BasicJsonType k(key); + keep_tag = callback(depth, parse_event_t::key, k); + } + else + { + keep_tag = true; + } + } + + // parse separator (:) + get_token(); + if (not expect(token_type::name_separator)) + { + return; + } + + // parse and add value + get_token(); + value.m_value.destroy(value.m_type); + value.m_type = value_t::discarded; + parse_internal(keep, value); + + if (JSON_UNLIKELY(errored)) + { + return; + } + + if (keep and keep_tag and not value.is_discarded()) + { + result.m_value.object->emplace(std::move(key), std::move(value)); + } + + // comma -> next value + get_token(); + if (last_token == token_type::value_separator) + { + get_token(); + continue; + } + + // closing } + if (not expect(token_type::end_object)) + { + return; + } + break; + } + + if (keep and callback and not callback(--depth, parse_event_t::object_end, result)) + { + result.m_value.destroy(result.m_type); + result.m_type = value_t::discarded; + } + break; + } + + case token_type::begin_array: + { + if (keep) + { + if (callback) + { + keep = callback(depth++, parse_event_t::array_start, result); + } + + if (not callback or keep) + { + // explicitly set result to array to cope with [] + result.m_type = value_t::array; + result.m_value = value_t::array; + } + } + + // read next token + get_token(); + + // closing ] -> we are done + if (last_token == token_type::end_array) + { + if (callback and not callback(--depth, parse_event_t::array_end, result)) + { + result.m_value.destroy(result.m_type); + result.m_type = value_t::discarded; + } + break; + } + + // parse values + BasicJsonType value; + while (true) + { + // parse value + value.m_value.destroy(value.m_type); + value.m_type = value_t::discarded; + parse_internal(keep, value); + + if (JSON_UNLIKELY(errored)) + { + return; + } + + if (keep and not value.is_discarded()) + { + result.m_value.array->push_back(std::move(value)); + } + + // comma -> next value + get_token(); + if (last_token == token_type::value_separator) + { + get_token(); + continue; + } + + // closing ] + if (not expect(token_type::end_array)) + { + return; + } + break; + } + + if (keep and callback and not callback(--depth, parse_event_t::array_end, result)) + { + result.m_value.destroy(result.m_type); + result.m_type = value_t::discarded; + } + break; + } + + case token_type::literal_null: + { + result.m_type = value_t::null; + break; + } + + case token_type::value_string: + { + result.m_type = value_t::string; + result.m_value = m_lexer.move_string(); + break; + } + + case token_type::literal_true: + { + result.m_type = value_t::boolean; + result.m_value = true; + break; + } + + case token_type::literal_false: + { + result.m_type = value_t::boolean; + result.m_value = false; + break; + } + + case token_type::value_unsigned: + { + result.m_type = value_t::number_unsigned; + result.m_value = m_lexer.get_number_unsigned(); + break; + } + + case token_type::value_integer: + { + result.m_type = value_t::number_integer; + result.m_value = m_lexer.get_number_integer(); + break; + } + + case token_type::value_float: + { + result.m_type = value_t::number_float; + result.m_value = m_lexer.get_number_float(); + + // throw in case of infinity or NAN + if (JSON_UNLIKELY(not std::isfinite(result.m_value.number_float))) + { + if (allow_exceptions) + { + JSON_THROW(out_of_range::create(406, "number overflow parsing '" + + m_lexer.get_token_string() + "'")); + } + expect(token_type::uninitialized); + } + break; + } + + case token_type::parse_error: + { + // using "uninitialized" to avoid "expected" message + if (not expect(token_type::uninitialized)) + { + return; + } + break; // LCOV_EXCL_LINE + } + + default: + { + // the last token was unexpected; we expected a value + if (not expect(token_type::literal_or_value)) + { + return; + } + break; // LCOV_EXCL_LINE + } + } + + if (keep and callback and not callback(depth, parse_event_t::value, result)) + { + result.m_type = value_t::discarded; + } + } + + /*! + @brief the actual acceptor + + @invariant 1. The last token is not yet processed. Therefore, the caller + of this function must make sure a token has been read. + 2. When this function returns, the last token is processed. + That is, the last read character was already considered. + + This invariant makes sure that no token needs to be "unput". + */ + bool accept_internal() + { + switch (last_token) + { + case token_type::begin_object: + { + // read next token + get_token(); + + // closing } -> we are done + if (last_token == token_type::end_object) + { + return true; + } + + // parse values + while (true) + { + // parse key + if (last_token != token_type::value_string) + { + return false; + } + + // parse separator (:) + get_token(); + if (last_token != token_type::name_separator) + { + return false; + } + + // parse value + get_token(); + if (not accept_internal()) + { + return false; + } + + // comma -> next value + get_token(); + if (last_token == token_type::value_separator) + { + get_token(); + continue; + } + + // closing } + return (last_token == token_type::end_object); + } + } + + case token_type::begin_array: + { + // read next token + get_token(); + + // closing ] -> we are done + if (last_token == token_type::end_array) + { + return true; + } + + // parse values + while (true) + { + // parse value + if (not accept_internal()) + { + return false; + } + + // comma -> next value + get_token(); + if (last_token == token_type::value_separator) + { + get_token(); + continue; + } + + // closing ] + return (last_token == token_type::end_array); + } + } + + case token_type::value_float: + { + // reject infinity or NAN + return std::isfinite(m_lexer.get_number_float()); + } + + case token_type::literal_false: + case token_type::literal_null: + case token_type::literal_true: + case token_type::value_integer: + case token_type::value_string: + case token_type::value_unsigned: + return true; + + default: // the last token was unexpected + return false; + } + } + + /// get next token from lexer + token_type get_token() + { + return (last_token = m_lexer.scan()); + } + + /*! + @throw parse_error.101 if expected token did not occur + */ + bool expect(token_type t) + { + if (JSON_UNLIKELY(t != last_token)) + { + errored = true; + expected = t; + if (allow_exceptions) + { + throw_exception(); + } + else + { + return false; + } + } + + return true; + } + + [[noreturn]] void throw_exception() const + { + std::string error_msg = "syntax error - "; + if (last_token == token_type::parse_error) + { + error_msg += std::string(m_lexer.get_error_message()) + "; last read: '" + + m_lexer.get_token_string() + "'"; + } + else + { + error_msg += "unexpected " + std::string(lexer_t::token_type_name(last_token)); + } + + if (expected != token_type::uninitialized) + { + error_msg += "; expected " + std::string(lexer_t::token_type_name(expected)); + } + + JSON_THROW(parse_error::create(101, m_lexer.get_position(), error_msg)); + } + + private: + /// current level of recursion + int depth = 0; + /// callback function + const parser_callback_t callback = nullptr; + /// the type of the last read token + token_type last_token = token_type::uninitialized; + /// the lexer + lexer_t m_lexer; + /// whether a syntax error occurred + bool errored = false; + /// possible reason for the syntax error + token_type expected = token_type::uninitialized; + /// whether to throw exceptions in case of errors + const bool allow_exceptions = true; +}; +} +} + +#endif + +/*** End of inlined file: parser.hpp ***/ + + +/*** Start of inlined file: primitive_iterator.hpp ***/ +#ifndef NLOHMANN_JSON_DETAIL_ITERATORS_PRIMITIVE_ITERATOR_HPP +#define NLOHMANN_JSON_DETAIL_ITERATORS_PRIMITIVE_ITERATOR_HPP + +#include // not +#include // ptrdiff_t +#include // numeric_limits +#include // ostream + +namespace nlohmann +{ +namespace detail +{ +/* +@brief an iterator for primitive JSON types + +This class models an iterator for primitive JSON types (boolean, number, +string). It's only purpose is to allow the iterator/const_iterator classes +to "iterate" over primitive values. Internally, the iterator is modeled by +a `difference_type` variable. Value begin_value (`0`) models the begin, +end_value (`1`) models past the end. +*/ +class primitive_iterator_t +{ + public: + using difference_type = std::ptrdiff_t; + + constexpr difference_type get_value() const noexcept + { + return m_it; + } + + /// set iterator to a defined beginning + void set_begin() noexcept + { + m_it = begin_value; + } + + /// set iterator to a defined past the end + void set_end() noexcept + { + m_it = end_value; + } + + /// return whether the iterator can be dereferenced + constexpr bool is_begin() const noexcept + { + return m_it == begin_value; + } + + /// return whether the iterator is at end + constexpr bool is_end() const noexcept + { + return m_it == end_value; + } + + friend constexpr bool operator==(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept + { + return lhs.m_it == rhs.m_it; + } + + friend constexpr bool operator<(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept + { + return lhs.m_it < rhs.m_it; + } + + primitive_iterator_t operator+(difference_type i) + { + auto result = *this; + result += i; + return result; + } + + friend constexpr difference_type operator-(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept + { + return lhs.m_it - rhs.m_it; + } + + friend std::ostream& operator<<(std::ostream& os, primitive_iterator_t it) + { + return os << it.m_it; + } + + primitive_iterator_t& operator++() + { + ++m_it; + return *this; + } + + primitive_iterator_t const operator++(int) + { + auto result = *this; + m_it++; + return result; + } + + primitive_iterator_t& operator--() + { + --m_it; + return *this; + } + + primitive_iterator_t const operator--(int) + { + auto result = *this; + m_it--; + return result; + } + + primitive_iterator_t& operator+=(difference_type n) + { + m_it += n; + return *this; + } + + primitive_iterator_t& operator-=(difference_type n) + { + m_it -= n; + return *this; + } + + private: + static constexpr difference_type begin_value = 0; + static constexpr difference_type end_value = begin_value + 1; + + /// iterator as signed integer type + difference_type m_it = (std::numeric_limits::min)(); +}; +} +} + +#endif + +/*** End of inlined file: primitive_iterator.hpp ***/ + + +/*** Start of inlined file: internal_iterator.hpp ***/ +#ifndef NLOHMANN_JSON_DETAIL_ITERATORS_INTERNAL_ITERATOR_HPP +#define NLOHMANN_JSON_DETAIL_ITERATORS_INTERNAL_ITERATOR_HPP + + +/*** Start of inlined file: primitive_iterator.hpp ***/ +#ifndef NLOHMANN_JSON_DETAIL_ITERATORS_PRIMITIVE_ITERATOR_HPP +#define NLOHMANN_JSON_DETAIL_ITERATORS_PRIMITIVE_ITERATOR_HPP + +#include // not +#include // ptrdiff_t +#include // numeric_limits +#include // ostream + +namespace nlohmann +{ +namespace detail +{ +/* +@brief an iterator for primitive JSON types + +This class models an iterator for primitive JSON types (boolean, number, +string). It's only purpose is to allow the iterator/const_iterator classes +to "iterate" over primitive values. Internally, the iterator is modeled by +a `difference_type` variable. Value begin_value (`0`) models the begin, +end_value (`1`) models past the end. +*/ +class primitive_iterator_t +{ + public: + using difference_type = std::ptrdiff_t; + + constexpr difference_type get_value() const noexcept + { + return m_it; + } + + /// set iterator to a defined beginning + void set_begin() noexcept + { + m_it = begin_value; + } + + /// set iterator to a defined past the end + void set_end() noexcept + { + m_it = end_value; + } + + /// return whether the iterator can be dereferenced + constexpr bool is_begin() const noexcept + { + return m_it == begin_value; + } + + /// return whether the iterator is at end + constexpr bool is_end() const noexcept + { + return m_it == end_value; + } + + friend constexpr bool operator==(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept + { + return lhs.m_it == rhs.m_it; + } + + friend constexpr bool operator<(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept + { + return lhs.m_it < rhs.m_it; + } + + primitive_iterator_t operator+(difference_type i) + { + auto result = *this; + result += i; + return result; + } + + friend constexpr difference_type operator-(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept + { + return lhs.m_it - rhs.m_it; + } + + friend std::ostream& operator<<(std::ostream& os, primitive_iterator_t it) + { + return os << it.m_it; + } + + primitive_iterator_t& operator++() + { + ++m_it; + return *this; + } + + primitive_iterator_t const operator++(int) + { + auto result = *this; + m_it++; + return result; + } + + primitive_iterator_t& operator--() + { + --m_it; + return *this; + } + + primitive_iterator_t const operator--(int) + { + auto result = *this; + m_it--; + return result; + } + + primitive_iterator_t& operator+=(difference_type n) + { + m_it += n; + return *this; + } + + primitive_iterator_t& operator-=(difference_type n) + { + m_it -= n; + return *this; + } + + private: + static constexpr difference_type begin_value = 0; + static constexpr difference_type end_value = begin_value + 1; + + /// iterator as signed integer type + difference_type m_it = (std::numeric_limits::min)(); +}; +} +} + +#endif + +/*** End of inlined file: primitive_iterator.hpp ***/ + +namespace nlohmann +{ +namespace detail +{ +/*! +@brief an iterator value + +@note This structure could easily be a union, but MSVC currently does not allow +unions members with complex constructors, see https://github.com/nlohmann/json/pull/105. +*/ +template struct internal_iterator +{ + /// iterator for JSON objects + typename BasicJsonType::object_t::iterator object_iterator {}; + /// iterator for JSON arrays + typename BasicJsonType::array_t::iterator array_iterator {}; + /// generic iterator for all other types + primitive_iterator_t primitive_iterator {}; +}; +} +} + +#endif + +/*** End of inlined file: internal_iterator.hpp ***/ + + +/*** Start of inlined file: iter_impl.hpp ***/ +#ifndef NLOHMANN_JSON_DETAIL_ITERATORS_ITER_IMPL_HPP +#define NLOHMANN_JSON_DETAIL_ITERATORS_ITER_IMPL_HPP + +#include // not +#include // iterator, random_access_iterator_tag, bidirectional_iterator_tag, advance, next +#include // conditional, is_const, remove_const + + +/*** Start of inlined file: internal_iterator.hpp ***/ +#ifndef NLOHMANN_JSON_DETAIL_ITERATORS_INTERNAL_ITERATOR_HPP +#define NLOHMANN_JSON_DETAIL_ITERATORS_INTERNAL_ITERATOR_HPP + +namespace nlohmann +{ +namespace detail +{ +/*! +@brief an iterator value + +@note This structure could easily be a union, but MSVC currently does not allow +unions members with complex constructors, see https://github.com/nlohmann/json/pull/105. +*/ +template struct internal_iterator +{ + /// iterator for JSON objects + typename BasicJsonType::object_t::iterator object_iterator {}; + /// iterator for JSON arrays + typename BasicJsonType::array_t::iterator array_iterator {}; + /// generic iterator for all other types + primitive_iterator_t primitive_iterator {}; +}; +} +} + +#endif + +/*** End of inlined file: internal_iterator.hpp ***/ + +namespace nlohmann +{ +namespace detail +{ +// forward declare, to be able to friend it later on +template class iteration_proxy; + +/*! +@brief a template for a bidirectional iterator for the @ref basic_json class + +This class implements a both iterators (iterator and const_iterator) for the +@ref basic_json class. + +@note An iterator is called *initialized* when a pointer to a JSON value has + been set (e.g., by a constructor or a copy assignment). If the iterator is + default-constructed, it is *uninitialized* and most methods are undefined. + **The library uses assertions to detect calls on uninitialized iterators.** + +@requirement The class satisfies the following concept requirements: +- +[BidirectionalIterator](http://en.cppreference.com/w/cpp/concept/BidirectionalIterator): + The iterator that can be moved can be moved in both directions (i.e. + incremented and decremented). + +@since version 1.0.0, simplified in version 2.0.9, change to bidirectional + iterators in version 3.0.0 (see https://github.com/nlohmann/json/issues/593) +*/ +template +class iter_impl +{ + /// allow basic_json to access private members + friend iter_impl::value, typename std::remove_const::type, const BasicJsonType>::type>; + friend BasicJsonType; + friend iteration_proxy; + + using object_t = typename BasicJsonType::object_t; + using array_t = typename BasicJsonType::array_t; + // make sure BasicJsonType is basic_json or const basic_json + static_assert(is_basic_json::type>::value, + "iter_impl only accepts (const) basic_json"); + + public: + + /// The std::iterator class template (used as a base class to provide typedefs) is deprecated in C++17. + /// The C++ Standard has never required user-defined iterators to derive from std::iterator. + /// A user-defined iterator should provide publicly accessible typedefs named + /// iterator_category, value_type, difference_type, pointer, and reference. + /// Note that value_type is required to be non-const, even for constant iterators. + using iterator_category = std::bidirectional_iterator_tag; + + /// the type of the values when the iterator is dereferenced + using value_type = typename BasicJsonType::value_type; + /// a type to represent differences between iterators + using difference_type = typename BasicJsonType::difference_type; + /// defines a pointer to the type iterated over (value_type) + using pointer = typename std::conditional::value, + typename BasicJsonType::const_pointer, + typename BasicJsonType::pointer>::type; + /// defines a reference to the type iterated over (value_type) + using reference = + typename std::conditional::value, + typename BasicJsonType::const_reference, + typename BasicJsonType::reference>::type; + + /// default constructor + iter_impl() = default; + + /*! + @brief constructor for a given JSON instance + @param[in] object pointer to a JSON object for this iterator + @pre object != nullptr + @post The iterator is initialized; i.e. `m_object != nullptr`. + */ + explicit iter_impl(pointer object) noexcept : m_object(object) + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + { + m_it.object_iterator = typename object_t::iterator(); + break; + } + + case value_t::array: + { + m_it.array_iterator = typename array_t::iterator(); + break; + } + + default: + { + m_it.primitive_iterator = primitive_iterator_t(); + break; + } + } + } + + /*! + @note The conventional copy constructor and copy assignment are implicitly + defined. Combined with the following converting constructor and + assignment, they support: (1) copy from iterator to iterator, (2) + copy from const iterator to const iterator, and (3) conversion from + iterator to const iterator. However conversion from const iterator + to iterator is not defined. + */ + + /*! + @brief converting constructor + @param[in] other non-const iterator to copy from + @note It is not checked whether @a other is initialized. + */ + iter_impl(const iter_impl::type>& other) noexcept + : m_object(other.m_object), m_it(other.m_it) {} + + /*! + @brief converting assignment + @param[in,out] other non-const iterator to copy from + @return const/non-const iterator + @note It is not checked whether @a other is initialized. + */ + iter_impl& operator=(const iter_impl::type>& other) noexcept + { + m_object = other.m_object; + m_it = other.m_it; + return *this; + } + + private: + /*! + @brief set the iterator to the first value + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + void set_begin() noexcept + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + { + m_it.object_iterator = m_object->m_value.object->begin(); + break; + } + + case value_t::array: + { + m_it.array_iterator = m_object->m_value.array->begin(); + break; + } + + case value_t::null: + { + // set to end so begin()==end() is true: null is empty + m_it.primitive_iterator.set_end(); + break; + } + + default: + { + m_it.primitive_iterator.set_begin(); + break; + } + } + } + + /*! + @brief set the iterator past the last value + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + void set_end() noexcept + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + { + m_it.object_iterator = m_object->m_value.object->end(); + break; + } + + case value_t::array: + { + m_it.array_iterator = m_object->m_value.array->end(); + break; + } + + default: + { + m_it.primitive_iterator.set_end(); + break; + } + } + } + + public: + /*! + @brief return a reference to the value pointed to by the iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + reference operator*() const + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + { + assert(m_it.object_iterator != m_object->m_value.object->end()); + return m_it.object_iterator->second; + } + + case value_t::array: + { + assert(m_it.array_iterator != m_object->m_value.array->end()); + return *m_it.array_iterator; + } + + case value_t::null: + JSON_THROW(invalid_iterator::create(214, "cannot get value")); + + default: + { + if (JSON_LIKELY(m_it.primitive_iterator.is_begin())) + { + return *m_object; + } + + JSON_THROW(invalid_iterator::create(214, "cannot get value")); + } + } + } + + /*! + @brief dereference the iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + pointer operator->() const + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + { + assert(m_it.object_iterator != m_object->m_value.object->end()); + return &(m_it.object_iterator->second); + } + + case value_t::array: + { + assert(m_it.array_iterator != m_object->m_value.array->end()); + return &*m_it.array_iterator; + } + + default: + { + if (JSON_LIKELY(m_it.primitive_iterator.is_begin())) + { + return m_object; + } + + JSON_THROW(invalid_iterator::create(214, "cannot get value")); + } + } + } + + /*! + @brief post-increment (it++) + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl const operator++(int) + { + auto result = *this; + ++(*this); + return result; + } + + /*! + @brief pre-increment (++it) + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl& operator++() + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + { + std::advance(m_it.object_iterator, 1); + break; + } + + case value_t::array: + { + std::advance(m_it.array_iterator, 1); + break; + } + + default: + { + ++m_it.primitive_iterator; + break; + } + } + + return *this; + } + + /*! + @brief post-decrement (it--) + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl const operator--(int) + { + auto result = *this; + --(*this); + return result; + } + + /*! + @brief pre-decrement (--it) + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl& operator--() + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + { + std::advance(m_it.object_iterator, -1); + break; + } + + case value_t::array: + { + std::advance(m_it.array_iterator, -1); + break; + } + + default: + { + --m_it.primitive_iterator; + break; + } + } + + return *this; + } + + /*! + @brief comparison: equal + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + bool operator==(const iter_impl& other) const + { + // if objects are not the same, the comparison is undefined + if (JSON_UNLIKELY(m_object != other.m_object)) + { + JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers")); + } + + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + return (m_it.object_iterator == other.m_it.object_iterator); + + case value_t::array: + return (m_it.array_iterator == other.m_it.array_iterator); + + default: + return (m_it.primitive_iterator == other.m_it.primitive_iterator); + } + } + + /*! + @brief comparison: not equal + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + bool operator!=(const iter_impl& other) const + { + return not operator==(other); + } + + /*! + @brief comparison: smaller + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + bool operator<(const iter_impl& other) const + { + // if objects are not the same, the comparison is undefined + if (JSON_UNLIKELY(m_object != other.m_object)) + { + JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers")); + } + + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + JSON_THROW(invalid_iterator::create(213, "cannot compare order of object iterators")); + + case value_t::array: + return (m_it.array_iterator < other.m_it.array_iterator); + + default: + return (m_it.primitive_iterator < other.m_it.primitive_iterator); + } + } + + /*! + @brief comparison: less than or equal + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + bool operator<=(const iter_impl& other) const + { + return not other.operator < (*this); + } + + /*! + @brief comparison: greater than + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + bool operator>(const iter_impl& other) const + { + return not operator<=(other); + } + + /*! + @brief comparison: greater than or equal + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + bool operator>=(const iter_impl& other) const + { + return not operator<(other); + } + + /*! + @brief add to iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl& operator+=(difference_type i) + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators")); + + case value_t::array: + { + std::advance(m_it.array_iterator, i); + break; + } + + default: + { + m_it.primitive_iterator += i; + break; + } + } + + return *this; + } + + /*! + @brief subtract from iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl& operator-=(difference_type i) + { + return operator+=(-i); + } + + /*! + @brief add to iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl operator+(difference_type i) const + { + auto result = *this; + result += i; + return result; + } + + /*! + @brief addition of distance and iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + friend iter_impl operator+(difference_type i, const iter_impl& it) + { + auto result = it; + result += i; + return result; + } + + /*! + @brief subtract from iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl operator-(difference_type i) const + { + auto result = *this; + result -= i; + return result; + } + + /*! + @brief return difference + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + difference_type operator-(const iter_impl& other) const + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators")); + + case value_t::array: + return m_it.array_iterator - other.m_it.array_iterator; + + default: + return m_it.primitive_iterator - other.m_it.primitive_iterator; + } + } + + /*! + @brief access to successor + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + reference operator[](difference_type n) const + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + JSON_THROW(invalid_iterator::create(208, "cannot use operator[] for object iterators")); + + case value_t::array: + return *std::next(m_it.array_iterator, n); + + case value_t::null: + JSON_THROW(invalid_iterator::create(214, "cannot get value")); + + default: + { + if (JSON_LIKELY(m_it.primitive_iterator.get_value() == -n)) + { + return *m_object; + } + + JSON_THROW(invalid_iterator::create(214, "cannot get value")); + } + } + } + + /*! + @brief return the key of an object iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + typename object_t::key_type key() const + { + assert(m_object != nullptr); + + if (JSON_LIKELY(m_object->is_object())) + { + return m_it.object_iterator->first; + } + + JSON_THROW(invalid_iterator::create(207, "cannot use key() for non-object iterators")); + } + + /*! + @brief return the value of an iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + reference value() const + { + return operator*(); + } + + private: + /// associated JSON instance + pointer m_object = nullptr; + /// the actual iterator of the associated instance + internal_iterator::type> m_it = {}; +}; +} +} + +#endif + +/*** End of inlined file: iter_impl.hpp ***/ + + +/*** Start of inlined file: iteration_proxy.hpp ***/ +#ifndef NLOHMANN_JSON_DETAIL_ITERATORS_ITERATION_PROXY_HPP +#define NLOHMANN_JSON_DETAIL_ITERATORS_ITERATION_PROXY_HPP + +#include // size_t +#include // string, to_string + +namespace nlohmann +{ +namespace detail +{ +/// proxy class for the iterator_wrapper functions +template class iteration_proxy +{ + private: + /// helper class for iteration + class iteration_proxy_internal + { + private: + /// the iterator + IteratorType anchor; + /// an index for arrays (used to create key names) + std::size_t array_index = 0; + + public: + explicit iteration_proxy_internal(IteratorType it) noexcept : anchor(it) {} + + /// dereference operator (needed for range-based for) + iteration_proxy_internal& operator*() + { + return *this; + } + + /// increment operator (needed for range-based for) + iteration_proxy_internal& operator++() + { + ++anchor; + ++array_index; + + return *this; + } + + /// inequality operator (needed for range-based for) + bool operator!=(const iteration_proxy_internal& o) const noexcept + { + return anchor != o.anchor; + } + + /// return key of the iterator + std::string key() const + { + assert(anchor.m_object != nullptr); + + switch (anchor.m_object->type()) + { + // use integer array index as key + case value_t::array: + return std::to_string(array_index); + + // use key from the object + case value_t::object: + return anchor.key(); + + // use an empty key for all primitive types + default: + return ""; + } + } + + /// return value of the iterator + typename IteratorType::reference value() const + { + return anchor.value(); + } + }; + + /// the container to iterate + typename IteratorType::reference container; + + public: + /// construct iteration proxy from a container + explicit iteration_proxy(typename IteratorType::reference cont) + : container(cont) {} + + /// return iterator begin (needed for range-based for) + iteration_proxy_internal begin() noexcept + { + return iteration_proxy_internal(container.begin()); + } + + /// return iterator end (needed for range-based for) + iteration_proxy_internal end() noexcept + { + return iteration_proxy_internal(container.end()); + } +}; +} +} + +#endif + +/*** End of inlined file: iteration_proxy.hpp ***/ + + +/*** Start of inlined file: json_reverse_iterator.hpp ***/ +#ifndef NLOHMANN_JSON_DETAIL_ITERATORS_JSON_REVERSE_ITERATOR_HPP +#define NLOHMANN_JSON_DETAIL_ITERATORS_JSON_REVERSE_ITERATOR_HPP + +#include // ptrdiff_t +#include // reverse_iterator +#include // declval + +namespace nlohmann +{ +namespace detail +{ +////////////////////// +// reverse_iterator // +////////////////////// + +/*! +@brief a template for a reverse iterator class + +@tparam Base the base iterator type to reverse. Valid types are @ref +iterator (to create @ref reverse_iterator) and @ref const_iterator (to +create @ref const_reverse_iterator). + +@requirement The class satisfies the following concept requirements: +- +[BidirectionalIterator](http://en.cppreference.com/w/cpp/concept/BidirectionalIterator): + The iterator that can be moved can be moved in both directions (i.e. + incremented and decremented). +- [OutputIterator](http://en.cppreference.com/w/cpp/concept/OutputIterator): + It is possible to write to the pointed-to element (only if @a Base is + @ref iterator). + +@since version 1.0.0 +*/ +template +class json_reverse_iterator : public std::reverse_iterator +{ + public: + using difference_type = std::ptrdiff_t; + /// shortcut to the reverse iterator adapter + using base_iterator = std::reverse_iterator; + /// the reference type for the pointed-to element + using reference = typename Base::reference; + + /// create reverse iterator from iterator + json_reverse_iterator(const typename base_iterator::iterator_type& it) noexcept + : base_iterator(it) {} + + /// create reverse iterator from base class + json_reverse_iterator(const base_iterator& it) noexcept : base_iterator(it) {} + + /// post-increment (it++) + json_reverse_iterator const operator++(int) + { + return static_cast(base_iterator::operator++(1)); + } + + /// pre-increment (++it) + json_reverse_iterator& operator++() + { + return static_cast(base_iterator::operator++()); + } + + /// post-decrement (it--) + json_reverse_iterator const operator--(int) + { + return static_cast(base_iterator::operator--(1)); + } + + /// pre-decrement (--it) + json_reverse_iterator& operator--() + { + return static_cast(base_iterator::operator--()); + } + + /// add to iterator + json_reverse_iterator& operator+=(difference_type i) + { + return static_cast(base_iterator::operator+=(i)); + } + + /// add to iterator + json_reverse_iterator operator+(difference_type i) const + { + return static_cast(base_iterator::operator+(i)); + } + + /// subtract from iterator + json_reverse_iterator operator-(difference_type i) const + { + return static_cast(base_iterator::operator-(i)); + } + + /// return difference + difference_type operator-(const json_reverse_iterator& other) const + { + return base_iterator(*this) - base_iterator(other); + } + + /// access to successor + reference operator[](difference_type n) const + { + return *(this->operator+(n)); + } + + /// return the key of an object iterator + auto key() const -> decltype(std::declval().key()) + { + auto it = --this->base(); + return it.key(); + } + + /// return the value of an iterator + reference value() const + { + auto it = --this->base(); + return it.operator * (); + } +}; +} +} + +#endif + +/*** End of inlined file: json_reverse_iterator.hpp ***/ + + +/*** Start of inlined file: output_adapters.hpp ***/ +#ifndef NLOHMANN_JSON_DETAIL_PARSING_OUTPUT_ADAPTERS_HPP +#define NLOHMANN_JSON_DETAIL_PARSING_OUTPUT_ADAPTERS_HPP + +#include // copy +#include // size_t +#include // streamsize +#include // back_inserter +#include // shared_ptr, make_shared +#include // basic_ostream +#include // basic_string +#include // vector + +namespace nlohmann +{ +namespace detail +{ +/// abstract output adapter interface +template struct output_adapter_protocol +{ + virtual void write_character(CharType c) = 0; + virtual void write_characters(const CharType* s, std::size_t length) = 0; + virtual ~output_adapter_protocol() = default; +}; + +/// a type to simplify interfaces +template +using output_adapter_t = std::shared_ptr>; + +/// output adapter for byte vectors +template +class output_vector_adapter : public output_adapter_protocol +{ + public: + explicit output_vector_adapter(std::vector& vec) : v(vec) {} + + void write_character(CharType c) override + { + v.push_back(c); + } + + void write_characters(const CharType* s, std::size_t length) override + { + std::copy(s, s + length, std::back_inserter(v)); + } + + private: + std::vector& v; +}; + +/// output adapter for output streams +template +class output_stream_adapter : public output_adapter_protocol +{ + public: + explicit output_stream_adapter(std::basic_ostream& s) : stream(s) {} + + void write_character(CharType c) override + { + stream.put(c); + } + + void write_characters(const CharType* s, std::size_t length) override + { + stream.write(s, static_cast(length)); + } + + private: + std::basic_ostream& stream; +}; + +/// output adapter for basic_string +template +class output_string_adapter : public output_adapter_protocol +{ + public: + explicit output_string_adapter(std::basic_string& s) : str(s) {} + + void write_character(CharType c) override + { + str.push_back(c); + } + + void write_characters(const CharType* s, std::size_t length) override + { + str.append(s, length); + } + + private: + std::basic_string& str; +}; + +template +class output_adapter +{ + public: + output_adapter(std::vector& vec) + : oa(std::make_shared>(vec)) {} + + output_adapter(std::basic_ostream& s) + : oa(std::make_shared>(s)) {} + + output_adapter(std::basic_string& s) + : oa(std::make_shared>(s)) {} + + operator output_adapter_t() + { + return oa; + } + + private: + output_adapter_t oa = nullptr; +}; +} +} + +#endif + +/*** End of inlined file: output_adapters.hpp ***/ + + +/*** Start of inlined file: binary_reader.hpp ***/ +#ifndef NLOHMANN_JSON_DETAIL_PARSING_BINARY_READER_HPP +#define NLOHMANN_JSON_DETAIL_PARSING_BINARY_READER_HPP + +#include // generate_n +#include // array +#include // assert +#include // ldexp +#include // size_t +#include // uint8_t, uint16_t, uint32_t, uint64_t +#include // memcpy +#include // setw, setfill +#include // hex +#include // back_inserter +#include // numeric_limits +#include // stringstream +#include // char_traits, string +#include // make_pair, move + +namespace nlohmann +{ +namespace detail +{ +/////////////////// +// binary reader // +/////////////////// + +/*! +@brief deserialization of CBOR and MessagePack values +*/ +template +class binary_reader +{ + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + + public: + /*! + @brief create a binary reader + + @param[in] adapter input adapter to read from + */ + explicit binary_reader(input_adapter_t adapter) : ia(std::move(adapter)) + { + assert(ia); + } + + /*! + @brief create a JSON value from CBOR input + + @param[in] strict whether to expect the input to be consumed completed + @return JSON value created from CBOR input + + @throw parse_error.110 if input ended unexpectedly or the end of file was + not reached when @a strict was set to true + @throw parse_error.112 if unsupported byte was read + */ + BasicJsonType parse_cbor(const bool strict) + { + const auto res = parse_cbor_internal(); + if (strict) + { + get(); + check_eof(true); + } + return res; + } + + /*! + @brief create a JSON value from MessagePack input + + @param[in] strict whether to expect the input to be consumed completed + @return JSON value created from MessagePack input + + @throw parse_error.110 if input ended unexpectedly or the end of file was + not reached when @a strict was set to true + @throw parse_error.112 if unsupported byte was read + */ + BasicJsonType parse_msgpack(const bool strict) + { + const auto res = parse_msgpack_internal(); + if (strict) + { + get(); + check_eof(true); + } + return res; + } + + /*! + @brief determine system byte order + + @return true if and only if system's byte order is little endian + + @note from http://stackoverflow.com/a/1001328/266378 + */ + static constexpr bool little_endianess(int num = 1) noexcept + { + return (*reinterpret_cast(&num) == 1); + } + + private: + /*! + @param[in] get_char whether a new character should be retrieved from the + input (true, default) or whether the last read + character should be considered instead + */ + BasicJsonType parse_cbor_internal(const bool get_char = true) + { + switch (get_char ? get() : current) + { + // EOF + case std::char_traits::eof(): + JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input")); + + // Integer 0x00..0x17 (0..23) + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + case 0x09: + case 0x0A: + case 0x0B: + case 0x0C: + case 0x0D: + case 0x0E: + case 0x0F: + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + return static_cast(current); + + case 0x18: // Unsigned integer (one-byte uint8_t follows) + return get_number(); + + case 0x19: // Unsigned integer (two-byte uint16_t follows) + return get_number(); + + case 0x1A: // Unsigned integer (four-byte uint32_t follows) + return get_number(); + + case 0x1B: // Unsigned integer (eight-byte uint64_t follows) + return get_number(); + + // Negative integer -1-0x00..-1-0x17 (-1..-24) + case 0x20: + case 0x21: + case 0x22: + case 0x23: + case 0x24: + case 0x25: + case 0x26: + case 0x27: + case 0x28: + case 0x29: + case 0x2A: + case 0x2B: + case 0x2C: + case 0x2D: + case 0x2E: + case 0x2F: + case 0x30: + case 0x31: + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: + return static_cast(0x20 - 1 - current); + + case 0x38: // Negative integer (one-byte uint8_t follows) + { + // must be uint8_t ! + return static_cast(-1) - get_number(); + } + + case 0x39: // Negative integer -1-n (two-byte uint16_t follows) + { + return static_cast(-1) - get_number(); + } + + case 0x3A: // Negative integer -1-n (four-byte uint32_t follows) + { + return static_cast(-1) - get_number(); + } + + case 0x3B: // Negative integer -1-n (eight-byte uint64_t follows) + { + return static_cast(-1) - + static_cast(get_number()); + } + + // UTF-8 string (0x00..0x17 bytes follow) + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: + case 0x68: + case 0x69: + case 0x6A: + case 0x6B: + case 0x6C: + case 0x6D: + case 0x6E: + case 0x6F: + case 0x70: + case 0x71: + case 0x72: + case 0x73: + case 0x74: + case 0x75: + case 0x76: + case 0x77: + case 0x78: // UTF-8 string (one-byte uint8_t for n follows) + case 0x79: // UTF-8 string (two-byte uint16_t for n follow) + case 0x7A: // UTF-8 string (four-byte uint32_t for n follow) + case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow) + case 0x7F: // UTF-8 string (indefinite length) + { + return get_cbor_string(); + } + + // array (0x00..0x17 data items follow) + case 0x80: + case 0x81: + case 0x82: + case 0x83: + case 0x84: + case 0x85: + case 0x86: + case 0x87: + case 0x88: + case 0x89: + case 0x8A: + case 0x8B: + case 0x8C: + case 0x8D: + case 0x8E: + case 0x8F: + case 0x90: + case 0x91: + case 0x92: + case 0x93: + case 0x94: + case 0x95: + case 0x96: + case 0x97: + { + return get_cbor_array(current & 0x1F); + } + + case 0x98: // array (one-byte uint8_t for n follows) + { + return get_cbor_array(get_number()); + } + + case 0x99: // array (two-byte uint16_t for n follow) + { + return get_cbor_array(get_number()); + } + + case 0x9A: // array (four-byte uint32_t for n follow) + { + return get_cbor_array(get_number()); + } + + case 0x9B: // array (eight-byte uint64_t for n follow) + { + return get_cbor_array(get_number()); + } + + case 0x9F: // array (indefinite length) + { + BasicJsonType result = value_t::array; + while (get() != 0xFF) + { + result.push_back(parse_cbor_internal(false)); + } + return result; + } + + // map (0x00..0x17 pairs of data items follow) + case 0xA0: + case 0xA1: + case 0xA2: + case 0xA3: + case 0xA4: + case 0xA5: + case 0xA6: + case 0xA7: + case 0xA8: + case 0xA9: + case 0xAA: + case 0xAB: + case 0xAC: + case 0xAD: + case 0xAE: + case 0xAF: + case 0xB0: + case 0xB1: + case 0xB2: + case 0xB3: + case 0xB4: + case 0xB5: + case 0xB6: + case 0xB7: + { + return get_cbor_object(current & 0x1F); + } + + case 0xB8: // map (one-byte uint8_t for n follows) + { + return get_cbor_object(get_number()); + } + + case 0xB9: // map (two-byte uint16_t for n follow) + { + return get_cbor_object(get_number()); + } + + case 0xBA: // map (four-byte uint32_t for n follow) + { + return get_cbor_object(get_number()); + } + + case 0xBB: // map (eight-byte uint64_t for n follow) + { + return get_cbor_object(get_number()); + } + + case 0xBF: // map (indefinite length) + { + BasicJsonType result = value_t::object; + while (get() != 0xFF) + { + auto key = get_cbor_string(); + result[key] = parse_cbor_internal(); + } + return result; + } + + case 0xF4: // false + { + return false; + } + + case 0xF5: // true + { + return true; + } + + case 0xF6: // null + { + return value_t::null; + } + + case 0xF9: // Half-Precision Float (two-byte IEEE 754) + { + const int byte1 = get(); + check_eof(); + const int byte2 = get(); + check_eof(); + + // code from RFC 7049, Appendix D, Figure 3: + // As half-precision floating-point numbers were only added + // to IEEE 754 in 2008, today's programming platforms often + // still only have limited support for them. It is very + // easy to include at least decoding support for them even + // without such support. An example of a small decoder for + // half-precision floating-point numbers in the C language + // is shown in Fig. 3. + const int half = (byte1 << 8) + byte2; + const int exp = (half >> 10) & 0x1F; + const int mant = half & 0x3FF; + double val; + if (exp == 0) + { + val = std::ldexp(mant, -24); + } + else if (exp != 31) + { + val = std::ldexp(mant + 1024, exp - 25); + } + else + { + val = (mant == 0) ? std::numeric_limits::infinity() + : std::numeric_limits::quiet_NaN(); + } + return (half & 0x8000) != 0 ? -val : val; + } + + case 0xFA: // Single-Precision Float (four-byte IEEE 754) + { + return get_number(); + } + + case 0xFB: // Double-Precision Float (eight-byte IEEE 754) + { + return get_number(); + } + + default: // anything else (0xFF is handled inside the other types) + { + std::stringstream ss; + ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; + JSON_THROW(parse_error::create(112, chars_read, "error reading CBOR; last byte: 0x" + ss.str())); + } + } + } + + BasicJsonType parse_msgpack_internal() + { + switch (get()) + { + // EOF + case std::char_traits::eof(): + JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input")); + + // positive fixint + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + case 0x09: + case 0x0A: + case 0x0B: + case 0x0C: + case 0x0D: + case 0x0E: + case 0x0F: + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + case 0x1A: + case 0x1B: + case 0x1C: + case 0x1D: + case 0x1E: + case 0x1F: + case 0x20: + case 0x21: + case 0x22: + case 0x23: + case 0x24: + case 0x25: + case 0x26: + case 0x27: + case 0x28: + case 0x29: + case 0x2A: + case 0x2B: + case 0x2C: + case 0x2D: + case 0x2E: + case 0x2F: + case 0x30: + case 0x31: + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: + case 0x38: + case 0x39: + case 0x3A: + case 0x3B: + case 0x3C: + case 0x3D: + case 0x3E: + case 0x3F: + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + case 0x48: + case 0x49: + case 0x4A: + case 0x4B: + case 0x4C: + case 0x4D: + case 0x4E: + case 0x4F: + case 0x50: + case 0x51: + case 0x52: + case 0x53: + case 0x54: + case 0x55: + case 0x56: + case 0x57: + case 0x58: + case 0x59: + case 0x5A: + case 0x5B: + case 0x5C: + case 0x5D: + case 0x5E: + case 0x5F: + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: + case 0x68: + case 0x69: + case 0x6A: + case 0x6B: + case 0x6C: + case 0x6D: + case 0x6E: + case 0x6F: + case 0x70: + case 0x71: + case 0x72: + case 0x73: + case 0x74: + case 0x75: + case 0x76: + case 0x77: + case 0x78: + case 0x79: + case 0x7A: + case 0x7B: + case 0x7C: + case 0x7D: + case 0x7E: + case 0x7F: + return static_cast(current); + + // fixmap + case 0x80: + case 0x81: + case 0x82: + case 0x83: + case 0x84: + case 0x85: + case 0x86: + case 0x87: + case 0x88: + case 0x89: + case 0x8A: + case 0x8B: + case 0x8C: + case 0x8D: + case 0x8E: + case 0x8F: + { + return get_msgpack_object(current & 0x0F); + } + + // fixarray + case 0x90: + case 0x91: + case 0x92: + case 0x93: + case 0x94: + case 0x95: + case 0x96: + case 0x97: + case 0x98: + case 0x99: + case 0x9A: + case 0x9B: + case 0x9C: + case 0x9D: + case 0x9E: + case 0x9F: + { + return get_msgpack_array(current & 0x0F); + } + + // fixstr + case 0xA0: + case 0xA1: + case 0xA2: + case 0xA3: + case 0xA4: + case 0xA5: + case 0xA6: + case 0xA7: + case 0xA8: + case 0xA9: + case 0xAA: + case 0xAB: + case 0xAC: + case 0xAD: + case 0xAE: + case 0xAF: + case 0xB0: + case 0xB1: + case 0xB2: + case 0xB3: + case 0xB4: + case 0xB5: + case 0xB6: + case 0xB7: + case 0xB8: + case 0xB9: + case 0xBA: + case 0xBB: + case 0xBC: + case 0xBD: + case 0xBE: + case 0xBF: + return get_msgpack_string(); + + case 0xC0: // nil + return value_t::null; + + case 0xC2: // false + return false; + + case 0xC3: // true + return true; + + case 0xCA: // float 32 + return get_number(); + + case 0xCB: // float 64 + return get_number(); + + case 0xCC: // uint 8 + return get_number(); + + case 0xCD: // uint 16 + return get_number(); + + case 0xCE: // uint 32 + return get_number(); + + case 0xCF: // uint 64 + return get_number(); + + case 0xD0: // int 8 + return get_number(); + + case 0xD1: // int 16 + return get_number(); + + case 0xD2: // int 32 + return get_number(); + + case 0xD3: // int 64 + return get_number(); + + case 0xD9: // str 8 + case 0xDA: // str 16 + case 0xDB: // str 32 + return get_msgpack_string(); + + case 0xDC: // array 16 + { + return get_msgpack_array(get_number()); + } + + case 0xDD: // array 32 + { + return get_msgpack_array(get_number()); + } + + case 0xDE: // map 16 + { + return get_msgpack_object(get_number()); + } + + case 0xDF: // map 32 + { + return get_msgpack_object(get_number()); + } + + // positive fixint + case 0xE0: + case 0xE1: + case 0xE2: + case 0xE3: + case 0xE4: + case 0xE5: + case 0xE6: + case 0xE7: + case 0xE8: + case 0xE9: + case 0xEA: + case 0xEB: + case 0xEC: + case 0xED: + case 0xEE: + case 0xEF: + case 0xF0: + case 0xF1: + case 0xF2: + case 0xF3: + case 0xF4: + case 0xF5: + case 0xF6: + case 0xF7: + case 0xF8: + case 0xF9: + case 0xFA: + case 0xFB: + case 0xFC: + case 0xFD: + case 0xFE: + case 0xFF: + return static_cast(current); + + default: // anything else + { + std::stringstream ss; + ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; + JSON_THROW(parse_error::create(112, chars_read, + "error reading MessagePack; last byte: 0x" + ss.str())); + } + } + } + + /*! + @brief get next character from the input + + This function provides the interface to the used input adapter. It does + not throw in case the input reached EOF, but returns a -'ve valued + `std::char_traits::eof()` in that case. + + @return character read from the input + */ + int get() + { + ++chars_read; + return (current = ia->get_character()); + } + + /* + @brief read a number from the input + + @tparam NumberType the type of the number + + @return number of type @a NumberType + + @note This function needs to respect the system's endianess, because + bytes in CBOR and MessagePack are stored in network order (big + endian) and therefore need reordering on little endian systems. + + @throw parse_error.110 if input has less than `sizeof(NumberType)` bytes + */ + template NumberType get_number() + { + // step 1: read input into array with system's byte order + std::array vec; + for (std::size_t i = 0; i < sizeof(NumberType); ++i) + { + get(); + check_eof(); + + // reverse byte order prior to conversion if necessary + if (is_little_endian) + { + vec[sizeof(NumberType) - i - 1] = static_cast(current); + } + else + { + vec[i] = static_cast(current); // LCOV_EXCL_LINE + } + } + + // step 2: convert array into number of type T and return + NumberType result; + std::memcpy(&result, vec.data(), sizeof(NumberType)); + return result; + } + + /*! + @brief create a string by reading characters from the input + + @param[in] len number of bytes to read + + @note We can not reserve @a len bytes for the result, because @a len + may be too large. Usually, @ref check_eof() detects the end of + the input before we run out of string memory. + + @return string created by reading @a len bytes + + @throw parse_error.110 if input has less than @a len bytes + */ + template + std::string get_string(const NumberType len) + { + std::string result; + std::generate_n(std::back_inserter(result), len, [this]() + { + get(); + check_eof(); + return static_cast(current); + }); + return result; + } + + /*! + @brief reads a CBOR string + + This function first reads starting bytes to determine the expected + string length and then copies this number of bytes into a string. + Additionally, CBOR's strings with indefinite lengths are supported. + + @return string + + @throw parse_error.110 if input ended + @throw parse_error.113 if an unexpected byte is read + */ + std::string get_cbor_string() + { + check_eof(); + + switch (current) + { + // UTF-8 string (0x00..0x17 bytes follow) + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: + case 0x68: + case 0x69: + case 0x6A: + case 0x6B: + case 0x6C: + case 0x6D: + case 0x6E: + case 0x6F: + case 0x70: + case 0x71: + case 0x72: + case 0x73: + case 0x74: + case 0x75: + case 0x76: + case 0x77: + { + return get_string(current & 0x1F); + } + + case 0x78: // UTF-8 string (one-byte uint8_t for n follows) + { + return get_string(get_number()); + } + + case 0x79: // UTF-8 string (two-byte uint16_t for n follow) + { + return get_string(get_number()); + } + + case 0x7A: // UTF-8 string (four-byte uint32_t for n follow) + { + return get_string(get_number()); + } + + case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow) + { + return get_string(get_number()); + } + + case 0x7F: // UTF-8 string (indefinite length) + { + std::string result; + while (get() != 0xFF) + { + check_eof(); + result.push_back(static_cast(current)); + } + return result; + } + + default: + { + std::stringstream ss; + ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; + JSON_THROW(parse_error::create(113, chars_read, "expected a CBOR string; last byte: 0x" + ss.str())); + } + } + } + + template + BasicJsonType get_cbor_array(const NumberType len) + { + BasicJsonType result = value_t::array; + std::generate_n(std::back_inserter(*result.m_value.array), len, [this]() + { + return parse_cbor_internal(); + }); + return result; + } + + template + BasicJsonType get_cbor_object(const NumberType len) + { + BasicJsonType result = value_t::object; + std::generate_n(std::inserter(*result.m_value.object, + result.m_value.object->end()), + len, [this]() + { + get(); + auto key = get_cbor_string(); + auto val = parse_cbor_internal(); + return std::make_pair(std::move(key), std::move(val)); + }); + return result; + } + + /*! + @brief reads a MessagePack string + + This function first reads starting bytes to determine the expected + string length and then copies this number of bytes into a string. + + @return string + + @throw parse_error.110 if input ended + @throw parse_error.113 if an unexpected byte is read + */ + std::string get_msgpack_string() + { + check_eof(); + + switch (current) + { + // fixstr + case 0xA0: + case 0xA1: + case 0xA2: + case 0xA3: + case 0xA4: + case 0xA5: + case 0xA6: + case 0xA7: + case 0xA8: + case 0xA9: + case 0xAA: + case 0xAB: + case 0xAC: + case 0xAD: + case 0xAE: + case 0xAF: + case 0xB0: + case 0xB1: + case 0xB2: + case 0xB3: + case 0xB4: + case 0xB5: + case 0xB6: + case 0xB7: + case 0xB8: + case 0xB9: + case 0xBA: + case 0xBB: + case 0xBC: + case 0xBD: + case 0xBE: + case 0xBF: + { + return get_string(current & 0x1F); + } + + case 0xD9: // str 8 + { + return get_string(get_number()); + } + + case 0xDA: // str 16 + { + return get_string(get_number()); + } + + case 0xDB: // str 32 + { + return get_string(get_number()); + } + + default: + { + std::stringstream ss; + ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; + JSON_THROW(parse_error::create(113, chars_read, + "expected a MessagePack string; last byte: 0x" + ss.str())); + } + } + } + + template + BasicJsonType get_msgpack_array(const NumberType len) + { + BasicJsonType result = value_t::array; + std::generate_n(std::back_inserter(*result.m_value.array), len, [this]() + { + return parse_msgpack_internal(); + }); + return result; + } + + template + BasicJsonType get_msgpack_object(const NumberType len) + { + BasicJsonType result = value_t::object; + std::generate_n(std::inserter(*result.m_value.object, + result.m_value.object->end()), + len, [this]() + { + get(); + auto key = get_msgpack_string(); + auto val = parse_msgpack_internal(); + return std::make_pair(std::move(key), std::move(val)); + }); + return result; + } + + /*! + @brief check if input ended + @throw parse_error.110 if input ended + */ + void check_eof(const bool expect_eof = false) const + { + if (expect_eof) + { + if (JSON_UNLIKELY(current != std::char_traits::eof())) + { + JSON_THROW(parse_error::create(110, chars_read, "expected end of input")); + } + } + else + { + if (JSON_UNLIKELY(current == std::char_traits::eof())) + { + JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input")); + } + } + } + + private: + /// input adapter + input_adapter_t ia = nullptr; + + /// the current character + int current = std::char_traits::eof(); + + /// the number of characters read + std::size_t chars_read = 0; + + /// whether we can assume little endianess + const bool is_little_endian = little_endianess(); +}; +} +} + +#endif + +/*** End of inlined file: binary_reader.hpp ***/ + + +/*** Start of inlined file: binary_writer.hpp ***/ +#ifndef NLOHMANN_JSON_DETAIL_PARSING_BINARY_WRITER_HPP +#define NLOHMANN_JSON_DETAIL_PARSING_BINARY_WRITER_HPP + +#include // reverse +#include // array +#include // uint8_t, uint16_t, uint32_t, uint64_t +#include // memcpy +#include // numeric_limits + + +/*** Start of inlined file: binary_reader.hpp ***/ +#ifndef NLOHMANN_JSON_DETAIL_PARSING_BINARY_READER_HPP +#define NLOHMANN_JSON_DETAIL_PARSING_BINARY_READER_HPP + +#include // generate_n +#include // array +#include // assert +#include // ldexp +#include // size_t +#include // uint8_t, uint16_t, uint32_t, uint64_t +#include // memcpy +#include // setw, setfill +#include // hex +#include // back_inserter +#include // numeric_limits +#include // stringstream +#include // char_traits, string +#include // make_pair, move + +namespace nlohmann +{ +namespace detail +{ +/////////////////// +// binary reader // +/////////////////// + +/*! +@brief deserialization of CBOR and MessagePack values +*/ +template +class binary_reader +{ + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + + public: + /*! + @brief create a binary reader + + @param[in] adapter input adapter to read from + */ + explicit binary_reader(input_adapter_t adapter) : ia(std::move(adapter)) + { + assert(ia); + } + + /*! + @brief create a JSON value from CBOR input + + @param[in] strict whether to expect the input to be consumed completed + @return JSON value created from CBOR input + + @throw parse_error.110 if input ended unexpectedly or the end of file was + not reached when @a strict was set to true + @throw parse_error.112 if unsupported byte was read + */ + BasicJsonType parse_cbor(const bool strict) + { + const auto res = parse_cbor_internal(); + if (strict) + { + get(); + check_eof(true); + } + return res; + } + + /*! + @brief create a JSON value from MessagePack input + + @param[in] strict whether to expect the input to be consumed completed + @return JSON value created from MessagePack input + + @throw parse_error.110 if input ended unexpectedly or the end of file was + not reached when @a strict was set to true + @throw parse_error.112 if unsupported byte was read + */ + BasicJsonType parse_msgpack(const bool strict) + { + const auto res = parse_msgpack_internal(); + if (strict) + { + get(); + check_eof(true); + } + return res; + } + + /*! + @brief determine system byte order + + @return true if and only if system's byte order is little endian + + @note from http://stackoverflow.com/a/1001328/266378 + */ + static constexpr bool little_endianess(int num = 1) noexcept + { + return (*reinterpret_cast(&num) == 1); + } + + private: + /*! + @param[in] get_char whether a new character should be retrieved from the + input (true, default) or whether the last read + character should be considered instead + */ + BasicJsonType parse_cbor_internal(const bool get_char = true) + { + switch (get_char ? get() : current) + { + // EOF + case std::char_traits::eof(): + JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input")); + + // Integer 0x00..0x17 (0..23) + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + case 0x09: + case 0x0A: + case 0x0B: + case 0x0C: + case 0x0D: + case 0x0E: + case 0x0F: + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + return static_cast(current); + + case 0x18: // Unsigned integer (one-byte uint8_t follows) + return get_number(); + + case 0x19: // Unsigned integer (two-byte uint16_t follows) + return get_number(); + + case 0x1A: // Unsigned integer (four-byte uint32_t follows) + return get_number(); + + case 0x1B: // Unsigned integer (eight-byte uint64_t follows) + return get_number(); + + // Negative integer -1-0x00..-1-0x17 (-1..-24) + case 0x20: + case 0x21: + case 0x22: + case 0x23: + case 0x24: + case 0x25: + case 0x26: + case 0x27: + case 0x28: + case 0x29: + case 0x2A: + case 0x2B: + case 0x2C: + case 0x2D: + case 0x2E: + case 0x2F: + case 0x30: + case 0x31: + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: + return static_cast(0x20 - 1 - current); + + case 0x38: // Negative integer (one-byte uint8_t follows) + { + // must be uint8_t ! + return static_cast(-1) - get_number(); + } + + case 0x39: // Negative integer -1-n (two-byte uint16_t follows) + { + return static_cast(-1) - get_number(); + } + + case 0x3A: // Negative integer -1-n (four-byte uint32_t follows) + { + return static_cast(-1) - get_number(); + } + + case 0x3B: // Negative integer -1-n (eight-byte uint64_t follows) + { + return static_cast(-1) - + static_cast(get_number()); + } + + // UTF-8 string (0x00..0x17 bytes follow) + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: + case 0x68: + case 0x69: + case 0x6A: + case 0x6B: + case 0x6C: + case 0x6D: + case 0x6E: + case 0x6F: + case 0x70: + case 0x71: + case 0x72: + case 0x73: + case 0x74: + case 0x75: + case 0x76: + case 0x77: + case 0x78: // UTF-8 string (one-byte uint8_t for n follows) + case 0x79: // UTF-8 string (two-byte uint16_t for n follow) + case 0x7A: // UTF-8 string (four-byte uint32_t for n follow) + case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow) + case 0x7F: // UTF-8 string (indefinite length) + { + return get_cbor_string(); + } + + // array (0x00..0x17 data items follow) + case 0x80: + case 0x81: + case 0x82: + case 0x83: + case 0x84: + case 0x85: + case 0x86: + case 0x87: + case 0x88: + case 0x89: + case 0x8A: + case 0x8B: + case 0x8C: + case 0x8D: + case 0x8E: + case 0x8F: + case 0x90: + case 0x91: + case 0x92: + case 0x93: + case 0x94: + case 0x95: + case 0x96: + case 0x97: + { + return get_cbor_array(current & 0x1F); + } + + case 0x98: // array (one-byte uint8_t for n follows) + { + return get_cbor_array(get_number()); + } + + case 0x99: // array (two-byte uint16_t for n follow) + { + return get_cbor_array(get_number()); + } + + case 0x9A: // array (four-byte uint32_t for n follow) + { + return get_cbor_array(get_number()); + } + + case 0x9B: // array (eight-byte uint64_t for n follow) + { + return get_cbor_array(get_number()); + } + + case 0x9F: // array (indefinite length) + { + BasicJsonType result = value_t::array; + while (get() != 0xFF) + { + result.push_back(parse_cbor_internal(false)); + } + return result; + } + + // map (0x00..0x17 pairs of data items follow) + case 0xA0: + case 0xA1: + case 0xA2: + case 0xA3: + case 0xA4: + case 0xA5: + case 0xA6: + case 0xA7: + case 0xA8: + case 0xA9: + case 0xAA: + case 0xAB: + case 0xAC: + case 0xAD: + case 0xAE: + case 0xAF: + case 0xB0: + case 0xB1: + case 0xB2: + case 0xB3: + case 0xB4: + case 0xB5: + case 0xB6: + case 0xB7: + { + return get_cbor_object(current & 0x1F); + } + + case 0xB8: // map (one-byte uint8_t for n follows) + { + return get_cbor_object(get_number()); + } + + case 0xB9: // map (two-byte uint16_t for n follow) + { + return get_cbor_object(get_number()); + } + + case 0xBA: // map (four-byte uint32_t for n follow) + { + return get_cbor_object(get_number()); + } + + case 0xBB: // map (eight-byte uint64_t for n follow) + { + return get_cbor_object(get_number()); + } + + case 0xBF: // map (indefinite length) + { + BasicJsonType result = value_t::object; + while (get() != 0xFF) + { + auto key = get_cbor_string(); + result[key] = parse_cbor_internal(); + } + return result; + } + + case 0xF4: // false + { + return false; + } + + case 0xF5: // true + { + return true; + } + + case 0xF6: // null + { + return value_t::null; + } + + case 0xF9: // Half-Precision Float (two-byte IEEE 754) + { + const int byte1 = get(); + check_eof(); + const int byte2 = get(); + check_eof(); + + // code from RFC 7049, Appendix D, Figure 3: + // As half-precision floating-point numbers were only added + // to IEEE 754 in 2008, today's programming platforms often + // still only have limited support for them. It is very + // easy to include at least decoding support for them even + // without such support. An example of a small decoder for + // half-precision floating-point numbers in the C language + // is shown in Fig. 3. + const int half = (byte1 << 8) + byte2; + const int exp = (half >> 10) & 0x1F; + const int mant = half & 0x3FF; + double val; + if (exp == 0) + { + val = std::ldexp(mant, -24); + } + else if (exp != 31) + { + val = std::ldexp(mant + 1024, exp - 25); + } + else + { + val = (mant == 0) ? std::numeric_limits::infinity() + : std::numeric_limits::quiet_NaN(); + } + return (half & 0x8000) != 0 ? -val : val; + } + + case 0xFA: // Single-Precision Float (four-byte IEEE 754) + { + return get_number(); + } + + case 0xFB: // Double-Precision Float (eight-byte IEEE 754) + { + return get_number(); + } + + default: // anything else (0xFF is handled inside the other types) + { + std::stringstream ss; + ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; + JSON_THROW(parse_error::create(112, chars_read, "error reading CBOR; last byte: 0x" + ss.str())); + } + } + } + + BasicJsonType parse_msgpack_internal() + { + switch (get()) + { + // EOF + case std::char_traits::eof(): + JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input")); + + // positive fixint + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + case 0x09: + case 0x0A: + case 0x0B: + case 0x0C: + case 0x0D: + case 0x0E: + case 0x0F: + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + case 0x1A: + case 0x1B: + case 0x1C: + case 0x1D: + case 0x1E: + case 0x1F: + case 0x20: + case 0x21: + case 0x22: + case 0x23: + case 0x24: + case 0x25: + case 0x26: + case 0x27: + case 0x28: + case 0x29: + case 0x2A: + case 0x2B: + case 0x2C: + case 0x2D: + case 0x2E: + case 0x2F: + case 0x30: + case 0x31: + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: + case 0x38: + case 0x39: + case 0x3A: + case 0x3B: + case 0x3C: + case 0x3D: + case 0x3E: + case 0x3F: + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + case 0x48: + case 0x49: + case 0x4A: + case 0x4B: + case 0x4C: + case 0x4D: + case 0x4E: + case 0x4F: + case 0x50: + case 0x51: + case 0x52: + case 0x53: + case 0x54: + case 0x55: + case 0x56: + case 0x57: + case 0x58: + case 0x59: + case 0x5A: + case 0x5B: + case 0x5C: + case 0x5D: + case 0x5E: + case 0x5F: + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: + case 0x68: + case 0x69: + case 0x6A: + case 0x6B: + case 0x6C: + case 0x6D: + case 0x6E: + case 0x6F: + case 0x70: + case 0x71: + case 0x72: + case 0x73: + case 0x74: + case 0x75: + case 0x76: + case 0x77: + case 0x78: + case 0x79: + case 0x7A: + case 0x7B: + case 0x7C: + case 0x7D: + case 0x7E: + case 0x7F: + return static_cast(current); + + // fixmap + case 0x80: + case 0x81: + case 0x82: + case 0x83: + case 0x84: + case 0x85: + case 0x86: + case 0x87: + case 0x88: + case 0x89: + case 0x8A: + case 0x8B: + case 0x8C: + case 0x8D: + case 0x8E: + case 0x8F: + { + return get_msgpack_object(current & 0x0F); + } + + // fixarray + case 0x90: + case 0x91: + case 0x92: + case 0x93: + case 0x94: + case 0x95: + case 0x96: + case 0x97: + case 0x98: + case 0x99: + case 0x9A: + case 0x9B: + case 0x9C: + case 0x9D: + case 0x9E: + case 0x9F: + { + return get_msgpack_array(current & 0x0F); + } + + // fixstr + case 0xA0: + case 0xA1: + case 0xA2: + case 0xA3: + case 0xA4: + case 0xA5: + case 0xA6: + case 0xA7: + case 0xA8: + case 0xA9: + case 0xAA: + case 0xAB: + case 0xAC: + case 0xAD: + case 0xAE: + case 0xAF: + case 0xB0: + case 0xB1: + case 0xB2: + case 0xB3: + case 0xB4: + case 0xB5: + case 0xB6: + case 0xB7: + case 0xB8: + case 0xB9: + case 0xBA: + case 0xBB: + case 0xBC: + case 0xBD: + case 0xBE: + case 0xBF: + return get_msgpack_string(); + + case 0xC0: // nil + return value_t::null; + + case 0xC2: // false + return false; + + case 0xC3: // true + return true; + + case 0xCA: // float 32 + return get_number(); + + case 0xCB: // float 64 + return get_number(); + + case 0xCC: // uint 8 + return get_number(); + + case 0xCD: // uint 16 + return get_number(); + + case 0xCE: // uint 32 + return get_number(); + + case 0xCF: // uint 64 + return get_number(); + + case 0xD0: // int 8 + return get_number(); + + case 0xD1: // int 16 + return get_number(); + + case 0xD2: // int 32 + return get_number(); + + case 0xD3: // int 64 + return get_number(); + + case 0xD9: // str 8 + case 0xDA: // str 16 + case 0xDB: // str 32 + return get_msgpack_string(); + + case 0xDC: // array 16 + { + return get_msgpack_array(get_number()); + } + + case 0xDD: // array 32 + { + return get_msgpack_array(get_number()); + } + + case 0xDE: // map 16 + { + return get_msgpack_object(get_number()); + } + + case 0xDF: // map 32 + { + return get_msgpack_object(get_number()); + } + + // positive fixint + case 0xE0: + case 0xE1: + case 0xE2: + case 0xE3: + case 0xE4: + case 0xE5: + case 0xE6: + case 0xE7: + case 0xE8: + case 0xE9: + case 0xEA: + case 0xEB: + case 0xEC: + case 0xED: + case 0xEE: + case 0xEF: + case 0xF0: + case 0xF1: + case 0xF2: + case 0xF3: + case 0xF4: + case 0xF5: + case 0xF6: + case 0xF7: + case 0xF8: + case 0xF9: + case 0xFA: + case 0xFB: + case 0xFC: + case 0xFD: + case 0xFE: + case 0xFF: + return static_cast(current); + + default: // anything else + { + std::stringstream ss; + ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; + JSON_THROW(parse_error::create(112, chars_read, + "error reading MessagePack; last byte: 0x" + ss.str())); + } + } + } + + /*! + @brief get next character from the input + + This function provides the interface to the used input adapter. It does + not throw in case the input reached EOF, but returns a -'ve valued + `std::char_traits::eof()` in that case. + + @return character read from the input + */ + int get() + { + ++chars_read; + return (current = ia->get_character()); + } + + /* + @brief read a number from the input + + @tparam NumberType the type of the number + + @return number of type @a NumberType + + @note This function needs to respect the system's endianess, because + bytes in CBOR and MessagePack are stored in network order (big + endian) and therefore need reordering on little endian systems. + + @throw parse_error.110 if input has less than `sizeof(NumberType)` bytes + */ + template NumberType get_number() + { + // step 1: read input into array with system's byte order + std::array vec; + for (std::size_t i = 0; i < sizeof(NumberType); ++i) + { + get(); + check_eof(); + + // reverse byte order prior to conversion if necessary + if (is_little_endian) + { + vec[sizeof(NumberType) - i - 1] = static_cast(current); + } + else + { + vec[i] = static_cast(current); // LCOV_EXCL_LINE + } + } + + // step 2: convert array into number of type T and return + NumberType result; + std::memcpy(&result, vec.data(), sizeof(NumberType)); + return result; + } + + /*! + @brief create a string by reading characters from the input + + @param[in] len number of bytes to read + + @note We can not reserve @a len bytes for the result, because @a len + may be too large. Usually, @ref check_eof() detects the end of + the input before we run out of string memory. + + @return string created by reading @a len bytes + + @throw parse_error.110 if input has less than @a len bytes + */ + template + std::string get_string(const NumberType len) + { + std::string result; + std::generate_n(std::back_inserter(result), len, [this]() + { + get(); + check_eof(); + return static_cast(current); + }); + return result; + } + + /*! + @brief reads a CBOR string + + This function first reads starting bytes to determine the expected + string length and then copies this number of bytes into a string. + Additionally, CBOR's strings with indefinite lengths are supported. + + @return string + + @throw parse_error.110 if input ended + @throw parse_error.113 if an unexpected byte is read + */ + std::string get_cbor_string() + { + check_eof(); + + switch (current) + { + // UTF-8 string (0x00..0x17 bytes follow) + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: + case 0x68: + case 0x69: + case 0x6A: + case 0x6B: + case 0x6C: + case 0x6D: + case 0x6E: + case 0x6F: + case 0x70: + case 0x71: + case 0x72: + case 0x73: + case 0x74: + case 0x75: + case 0x76: + case 0x77: + { + return get_string(current & 0x1F); + } + + case 0x78: // UTF-8 string (one-byte uint8_t for n follows) + { + return get_string(get_number()); + } + + case 0x79: // UTF-8 string (two-byte uint16_t for n follow) + { + return get_string(get_number()); + } + + case 0x7A: // UTF-8 string (four-byte uint32_t for n follow) + { + return get_string(get_number()); + } + + case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow) + { + return get_string(get_number()); + } + + case 0x7F: // UTF-8 string (indefinite length) + { + std::string result; + while (get() != 0xFF) + { + check_eof(); + result.push_back(static_cast(current)); + } + return result; + } + + default: + { + std::stringstream ss; + ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; + JSON_THROW(parse_error::create(113, chars_read, "expected a CBOR string; last byte: 0x" + ss.str())); + } + } + } + + template + BasicJsonType get_cbor_array(const NumberType len) + { + BasicJsonType result = value_t::array; + std::generate_n(std::back_inserter(*result.m_value.array), len, [this]() + { + return parse_cbor_internal(); + }); + return result; + } + + template + BasicJsonType get_cbor_object(const NumberType len) + { + BasicJsonType result = value_t::object; + std::generate_n(std::inserter(*result.m_value.object, + result.m_value.object->end()), + len, [this]() + { + get(); + auto key = get_cbor_string(); + auto val = parse_cbor_internal(); + return std::make_pair(std::move(key), std::move(val)); + }); + return result; + } + + /*! + @brief reads a MessagePack string + + This function first reads starting bytes to determine the expected + string length and then copies this number of bytes into a string. + + @return string + + @throw parse_error.110 if input ended + @throw parse_error.113 if an unexpected byte is read + */ + std::string get_msgpack_string() + { + check_eof(); + + switch (current) + { + // fixstr + case 0xA0: + case 0xA1: + case 0xA2: + case 0xA3: + case 0xA4: + case 0xA5: + case 0xA6: + case 0xA7: + case 0xA8: + case 0xA9: + case 0xAA: + case 0xAB: + case 0xAC: + case 0xAD: + case 0xAE: + case 0xAF: + case 0xB0: + case 0xB1: + case 0xB2: + case 0xB3: + case 0xB4: + case 0xB5: + case 0xB6: + case 0xB7: + case 0xB8: + case 0xB9: + case 0xBA: + case 0xBB: + case 0xBC: + case 0xBD: + case 0xBE: + case 0xBF: + { + return get_string(current & 0x1F); + } + + case 0xD9: // str 8 + { + return get_string(get_number()); + } + + case 0xDA: // str 16 + { + return get_string(get_number()); + } + + case 0xDB: // str 32 + { + return get_string(get_number()); + } + + default: + { + std::stringstream ss; + ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; + JSON_THROW(parse_error::create(113, chars_read, + "expected a MessagePack string; last byte: 0x" + ss.str())); + } + } + } + + template + BasicJsonType get_msgpack_array(const NumberType len) + { + BasicJsonType result = value_t::array; + std::generate_n(std::back_inserter(*result.m_value.array), len, [this]() + { + return parse_msgpack_internal(); + }); + return result; + } + + template + BasicJsonType get_msgpack_object(const NumberType len) + { + BasicJsonType result = value_t::object; + std::generate_n(std::inserter(*result.m_value.object, + result.m_value.object->end()), + len, [this]() + { + get(); + auto key = get_msgpack_string(); + auto val = parse_msgpack_internal(); + return std::make_pair(std::move(key), std::move(val)); + }); + return result; + } + + /*! + @brief check if input ended + @throw parse_error.110 if input ended + */ + void check_eof(const bool expect_eof = false) const + { + if (expect_eof) + { + if (JSON_UNLIKELY(current != std::char_traits::eof())) + { + JSON_THROW(parse_error::create(110, chars_read, "expected end of input")); + } + } + else + { + if (JSON_UNLIKELY(current == std::char_traits::eof())) + { + JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input")); + } + } + } + + private: + /// input adapter + input_adapter_t ia = nullptr; + + /// the current character + int current = std::char_traits::eof(); + + /// the number of characters read + std::size_t chars_read = 0; + + /// whether we can assume little endianess + const bool is_little_endian = little_endianess(); +}; +} +} + +#endif + +/*** End of inlined file: binary_reader.hpp ***/ + + +/*** Start of inlined file: output_adapters.hpp ***/ +#ifndef NLOHMANN_JSON_DETAIL_PARSING_OUTPUT_ADAPTERS_HPP +#define NLOHMANN_JSON_DETAIL_PARSING_OUTPUT_ADAPTERS_HPP + +#include // copy +#include // size_t +#include // streamsize +#include // back_inserter +#include // shared_ptr, make_shared +#include // basic_ostream +#include // basic_string +#include // vector + +namespace nlohmann +{ +namespace detail +{ +/// abstract output adapter interface +template struct output_adapter_protocol +{ + virtual void write_character(CharType c) = 0; + virtual void write_characters(const CharType* s, std::size_t length) = 0; + virtual ~output_adapter_protocol() = default; +}; + +/// a type to simplify interfaces +template +using output_adapter_t = std::shared_ptr>; + +/// output adapter for byte vectors +template +class output_vector_adapter : public output_adapter_protocol +{ + public: + explicit output_vector_adapter(std::vector& vec) : v(vec) {} + + void write_character(CharType c) override + { + v.push_back(c); + } + + void write_characters(const CharType* s, std::size_t length) override + { + std::copy(s, s + length, std::back_inserter(v)); + } + + private: + std::vector& v; +}; + +/// output adapter for output streams +template +class output_stream_adapter : public output_adapter_protocol +{ + public: + explicit output_stream_adapter(std::basic_ostream& s) : stream(s) {} + + void write_character(CharType c) override + { + stream.put(c); + } + + void write_characters(const CharType* s, std::size_t length) override + { + stream.write(s, static_cast(length)); + } + + private: + std::basic_ostream& stream; +}; + +/// output adapter for basic_string +template +class output_string_adapter : public output_adapter_protocol +{ + public: + explicit output_string_adapter(std::basic_string& s) : str(s) {} + + void write_character(CharType c) override + { + str.push_back(c); + } + + void write_characters(const CharType* s, std::size_t length) override + { + str.append(s, length); + } + + private: + std::basic_string& str; +}; + +template +class output_adapter +{ + public: + output_adapter(std::vector& vec) + : oa(std::make_shared>(vec)) {} + + output_adapter(std::basic_ostream& s) + : oa(std::make_shared>(s)) {} + + output_adapter(std::basic_string& s) + : oa(std::make_shared>(s)) {} + + operator output_adapter_t() + { + return oa; + } + + private: + output_adapter_t oa = nullptr; +}; +} +} + +#endif + +/*** End of inlined file: output_adapters.hpp ***/ + +namespace nlohmann +{ +namespace detail +{ +/////////////////// +// binary writer // +/////////////////// + +/*! +@brief serialization to CBOR and MessagePack values +*/ +template +class binary_writer +{ + public: + /*! + @brief create a binary writer + + @param[in] adapter output adapter to write to + */ + explicit binary_writer(output_adapter_t adapter) : oa(adapter) + { + assert(oa); + } + + /*! + @brief[in] j JSON value to serialize + */ + void write_cbor(const BasicJsonType& j) + { + switch (j.type()) + { + case value_t::null: + { + oa->write_character(static_cast(0xF6)); + break; + } + + case value_t::boolean: + { + oa->write_character(j.m_value.boolean + ? static_cast(0xF5) + : static_cast(0xF4)); + break; + } + + case value_t::number_integer: + { + if (j.m_value.number_integer >= 0) + { + // CBOR does not differentiate between positive signed + // integers and unsigned integers. Therefore, we used the + // code from the value_t::number_unsigned case here. + if (j.m_value.number_integer <= 0x17) + { + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_integer <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0x18)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_integer <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0x19)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_integer <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0x1A)); + write_number(static_cast(j.m_value.number_integer)); + } + else + { + oa->write_character(static_cast(0x1B)); + write_number(static_cast(j.m_value.number_integer)); + } + } + else + { + // The conversions below encode the sign in the first + // byte, and the value is converted to a positive number. + const auto positive_number = -1 - j.m_value.number_integer; + if (j.m_value.number_integer >= -24) + { + write_number(static_cast(0x20 + positive_number)); + } + else if (positive_number <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0x38)); + write_number(static_cast(positive_number)); + } + else if (positive_number <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0x39)); + write_number(static_cast(positive_number)); + } + else if (positive_number <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0x3A)); + write_number(static_cast(positive_number)); + } + else + { + oa->write_character(static_cast(0x3B)); + write_number(static_cast(positive_number)); + } + } + break; + } + + case value_t::number_unsigned: + { + if (j.m_value.number_unsigned <= 0x17) + { + write_number(static_cast(j.m_value.number_unsigned)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0x18)); + write_number(static_cast(j.m_value.number_unsigned)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0x19)); + write_number(static_cast(j.m_value.number_unsigned)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0x1A)); + write_number(static_cast(j.m_value.number_unsigned)); + } + else + { + oa->write_character(static_cast(0x1B)); + write_number(static_cast(j.m_value.number_unsigned)); + } + break; + } + + case value_t::number_float: // Double-Precision Float + { + oa->write_character(static_cast(0xFB)); + write_number(j.m_value.number_float); + break; + } + + case value_t::string: + { + // step 1: write control byte and the string length + const auto N = j.m_value.string->size(); + if (N <= 0x17) + { + write_number(static_cast(0x60 + N)); + } + else if (N <= 0xFF) + { + oa->write_character(static_cast(0x78)); + write_number(static_cast(N)); + } + else if (N <= 0xFFFF) + { + oa->write_character(static_cast(0x79)); + write_number(static_cast(N)); + } + else if (N <= 0xFFFFFFFF) + { + oa->write_character(static_cast(0x7A)); + write_number(static_cast(N)); + } + // LCOV_EXCL_START + else if (N <= 0xFFFFFFFFFFFFFFFF) + { + oa->write_character(static_cast(0x7B)); + write_number(static_cast(N)); + } + // LCOV_EXCL_STOP + + // step 2: write the string + oa->write_characters( + reinterpret_cast(j.m_value.string->c_str()), + j.m_value.string->size()); + break; + } + + case value_t::array: + { + // step 1: write control byte and the array size + const auto N = j.m_value.array->size(); + if (N <= 0x17) + { + write_number(static_cast(0x80 + N)); + } + else if (N <= 0xFF) + { + oa->write_character(static_cast(0x98)); + write_number(static_cast(N)); + } + else if (N <= 0xFFFF) + { + oa->write_character(static_cast(0x99)); + write_number(static_cast(N)); + } + else if (N <= 0xFFFFFFFF) + { + oa->write_character(static_cast(0x9A)); + write_number(static_cast(N)); + } + // LCOV_EXCL_START + else if (N <= 0xFFFFFFFFFFFFFFFF) + { + oa->write_character(static_cast(0x9B)); + write_number(static_cast(N)); + } + // LCOV_EXCL_STOP + + // step 2: write each element + for (const auto& el : *j.m_value.array) + { + write_cbor(el); + } + break; + } + + case value_t::object: + { + // step 1: write control byte and the object size + const auto N = j.m_value.object->size(); + if (N <= 0x17) + { + write_number(static_cast(0xA0 + N)); + } + else if (N <= 0xFF) + { + oa->write_character(static_cast(0xB8)); + write_number(static_cast(N)); + } + else if (N <= 0xFFFF) + { + oa->write_character(static_cast(0xB9)); + write_number(static_cast(N)); + } + else if (N <= 0xFFFFFFFF) + { + oa->write_character(static_cast(0xBA)); + write_number(static_cast(N)); + } + // LCOV_EXCL_START + else if (N <= 0xFFFFFFFFFFFFFFFF) + { + oa->write_character(static_cast(0xBB)); + write_number(static_cast(N)); + } + // LCOV_EXCL_STOP + + // step 2: write each element + for (const auto& el : *j.m_value.object) + { + write_cbor(el.first); + write_cbor(el.second); + } + break; + } + + default: + break; + } + } + + /*! + @brief[in] j JSON value to serialize + */ + void write_msgpack(const BasicJsonType& j) + { + switch (j.type()) + { + case value_t::null: // nil + { + oa->write_character(static_cast(0xC0)); + break; + } + + case value_t::boolean: // true and false + { + oa->write_character(j.m_value.boolean + ? static_cast(0xC3) + : static_cast(0xC2)); + break; + } + + case value_t::number_integer: + { + if (j.m_value.number_integer >= 0) + { + // MessagePack does not differentiate between positive + // signed integers and unsigned integers. Therefore, we used + // the code from the value_t::number_unsigned case here. + if (j.m_value.number_unsigned < 128) + { + // positive fixnum + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 8 + oa->write_character(static_cast(0xCC)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 16 + oa->write_character(static_cast(0xCD)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 32 + oa->write_character(static_cast(0xCE)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 64 + oa->write_character(static_cast(0xCF)); + write_number(static_cast(j.m_value.number_integer)); + } + } + else + { + if (j.m_value.number_integer >= -32) + { + // negative fixnum + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_integer >= (std::numeric_limits::min)() and + j.m_value.number_integer <= (std::numeric_limits::max)()) + { + // int 8 + oa->write_character(static_cast(0xD0)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_integer >= (std::numeric_limits::min)() and + j.m_value.number_integer <= (std::numeric_limits::max)()) + { + // int 16 + oa->write_character(static_cast(0xD1)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_integer >= (std::numeric_limits::min)() and + j.m_value.number_integer <= (std::numeric_limits::max)()) + { + // int 32 + oa->write_character(static_cast(0xD2)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_integer >= (std::numeric_limits::min)() and + j.m_value.number_integer <= (std::numeric_limits::max)()) + { + // int 64 + oa->write_character(static_cast(0xD3)); + write_number(static_cast(j.m_value.number_integer)); + } + } + break; + } + + case value_t::number_unsigned: + { + if (j.m_value.number_unsigned < 128) + { + // positive fixnum + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 8 + oa->write_character(static_cast(0xCC)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 16 + oa->write_character(static_cast(0xCD)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 32 + oa->write_character(static_cast(0xCE)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 64 + oa->write_character(static_cast(0xCF)); + write_number(static_cast(j.m_value.number_integer)); + } + break; + } + + case value_t::number_float: // float 64 + { + oa->write_character(static_cast(0xCB)); + write_number(j.m_value.number_float); + break; + } + + case value_t::string: + { + // step 1: write control byte and the string length + const auto N = j.m_value.string->size(); + if (N <= 31) + { + // fixstr + write_number(static_cast(0xA0 | N)); + } + else if (N <= 255) + { + // str 8 + oa->write_character(static_cast(0xD9)); + write_number(static_cast(N)); + } + else if (N <= 65535) + { + // str 16 + oa->write_character(static_cast(0xDA)); + write_number(static_cast(N)); + } + else if (N <= 4294967295) + { + // str 32 + oa->write_character(static_cast(0xDB)); + write_number(static_cast(N)); + } + + // step 2: write the string + oa->write_characters( + reinterpret_cast(j.m_value.string->c_str()), + j.m_value.string->size()); + break; + } + + case value_t::array: + { + // step 1: write control byte and the array size + const auto N = j.m_value.array->size(); + if (N <= 15) + { + // fixarray + write_number(static_cast(0x90 | N)); + } + else if (N <= 0xFFFF) + { + // array 16 + oa->write_character(static_cast(0xDC)); + write_number(static_cast(N)); + } + else if (N <= 0xFFFFFFFF) + { + // array 32 + oa->write_character(static_cast(0xDD)); + write_number(static_cast(N)); + } + + // step 2: write each element + for (const auto& el : *j.m_value.array) + { + write_msgpack(el); + } + break; + } + + case value_t::object: + { + // step 1: write control byte and the object size + const auto N = j.m_value.object->size(); + if (N <= 15) + { + // fixmap + write_number(static_cast(0x80 | (N & 0xF))); + } + else if (N <= 65535) + { + // map 16 + oa->write_character(static_cast(0xDE)); + write_number(static_cast(N)); + } + else if (N <= 4294967295) + { + // map 32 + oa->write_character(static_cast(0xDF)); + write_number(static_cast(N)); + } + + // step 2: write each element + for (const auto& el : *j.m_value.object) + { + write_msgpack(el.first); + write_msgpack(el.second); + } + break; + } + + default: + break; + } + } + + private: + /* + @brief write a number to output input + + @param[in] n number of type @a NumberType + @tparam NumberType the type of the number + + @note This function needs to respect the system's endianess, because bytes + in CBOR and MessagePack are stored in network order (big endian) and + therefore need reordering on little endian systems. + */ + template void write_number(NumberType n) + { + // step 1: write number to array of length NumberType + std::array vec; + std::memcpy(vec.data(), &n, sizeof(NumberType)); + + // step 2: write array to output (with possible reordering) + if (is_little_endian) + { + // reverse byte order prior to conversion if necessary + std::reverse(vec.begin(), vec.end()); + } + + oa->write_characters(vec.data(), sizeof(NumberType)); + } + + private: + /// whether we can assume little endianess + const bool is_little_endian = binary_reader::little_endianess(); + + /// the output + output_adapter_t oa = nullptr; +}; +} +} + +#endif + +/*** End of inlined file: binary_writer.hpp ***/ + + +/*** Start of inlined file: serializer.hpp ***/ +#ifndef NLOHMANN_JSON_DETAIL_SERIALIZER_HPP +#define NLOHMANN_JSON_DETAIL_SERIALIZER_HPP + +#include // reverse, remove, fill, find, none_of +#include // array +#include // assert +#include // and, or +#include // localeconv, lconv +#include // labs, isfinite, isnan, signbit +#include // size_t, ptrdiff_t +#include // uint8_t +#include // snprintf +#include // next +#include // numeric_limits +#include // string +#include // is_same + +namespace nlohmann +{ +namespace detail +{ +/////////////////// +// serialization // +/////////////////// + +template +class serializer +{ + using string_t = typename BasicJsonType::string_t; + using number_float_t = typename BasicJsonType::number_float_t; + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + public: + /*! + @param[in] s output stream to serialize to + @param[in] ichar indentation character to use + */ + serializer(output_adapter_t s, const char ichar) + : o(std::move(s)), loc(std::localeconv()), + thousands_sep(loc->thousands_sep == nullptr ? '\0' : * (loc->thousands_sep)), + decimal_point(loc->decimal_point == nullptr ? '\0' : * (loc->decimal_point)), + indent_char(ichar), indent_string(512, indent_char) {} + + // delete because of pointer members + serializer(const serializer&) = delete; + serializer& operator=(const serializer&) = delete; + + /*! + @brief internal implementation of the serialization function + + This function is called by the public member function dump and organizes + the serialization internally. The indentation level is propagated as + additional parameter. In case of arrays and objects, the function is + called recursively. + + - strings and object keys are escaped using `escape_string()` + - integer numbers are converted implicitly via `operator<<` + - floating-point numbers are converted to a string using `"%g"` format + + @param[in] val value to serialize + @param[in] pretty_print whether the output shall be pretty-printed + @param[in] indent_step the indent level + @param[in] current_indent the current indent level (only used internally) + */ + void dump(const BasicJsonType& val, const bool pretty_print, + const bool ensure_ascii, + const unsigned int indent_step, + const unsigned int current_indent = 0) + { + switch (val.m_type) + { + case value_t::object: + { + if (val.m_value.object->empty()) + { + o->write_characters("{}", 2); + return; + } + + if (pretty_print) + { + o->write_characters("{\n", 2); + + // variable to hold indentation for recursive calls + const auto new_indent = current_indent + indent_step; + if (JSON_UNLIKELY(indent_string.size() < new_indent)) + { + indent_string.resize(indent_string.size() * 2, ' '); + } + + // first n-1 elements + auto i = val.m_value.object->cbegin(); + for (std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i) + { + o->write_characters(indent_string.c_str(), new_indent); + o->write_character('\"'); + dump_escaped(i->first, ensure_ascii); + o->write_characters("\": ", 3); + dump(i->second, true, ensure_ascii, indent_step, new_indent); + o->write_characters(",\n", 2); + } + + // last element + assert(i != val.m_value.object->cend()); + assert(std::next(i) == val.m_value.object->cend()); + o->write_characters(indent_string.c_str(), new_indent); + o->write_character('\"'); + dump_escaped(i->first, ensure_ascii); + o->write_characters("\": ", 3); + dump(i->second, true, ensure_ascii, indent_step, new_indent); + + o->write_character('\n'); + o->write_characters(indent_string.c_str(), current_indent); + o->write_character('}'); + } + else + { + o->write_character('{'); + + // first n-1 elements + auto i = val.m_value.object->cbegin(); + for (std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i) + { + o->write_character('\"'); + dump_escaped(i->first, ensure_ascii); + o->write_characters("\":", 2); + dump(i->second, false, ensure_ascii, indent_step, current_indent); + o->write_character(','); + } + + // last element + assert(i != val.m_value.object->cend()); + assert(std::next(i) == val.m_value.object->cend()); + o->write_character('\"'); + dump_escaped(i->first, ensure_ascii); + o->write_characters("\":", 2); + dump(i->second, false, ensure_ascii, indent_step, current_indent); + + o->write_character('}'); + } + + return; + } + + case value_t::array: + { + if (val.m_value.array->empty()) + { + o->write_characters("[]", 2); + return; + } + + if (pretty_print) + { + o->write_characters("[\n", 2); + + // variable to hold indentation for recursive calls + const auto new_indent = current_indent + indent_step; + if (JSON_UNLIKELY(indent_string.size() < new_indent)) + { + indent_string.resize(indent_string.size() * 2, ' '); + } + + // first n-1 elements + for (auto i = val.m_value.array->cbegin(); + i != val.m_value.array->cend() - 1; ++i) + { + o->write_characters(indent_string.c_str(), new_indent); + dump(*i, true, ensure_ascii, indent_step, new_indent); + o->write_characters(",\n", 2); + } + + // last element + assert(not val.m_value.array->empty()); + o->write_characters(indent_string.c_str(), new_indent); + dump(val.m_value.array->back(), true, ensure_ascii, indent_step, new_indent); + + o->write_character('\n'); + o->write_characters(indent_string.c_str(), current_indent); + o->write_character(']'); + } + else + { + o->write_character('['); + + // first n-1 elements + for (auto i = val.m_value.array->cbegin(); + i != val.m_value.array->cend() - 1; ++i) + { + dump(*i, false, ensure_ascii, indent_step, current_indent); + o->write_character(','); + } + + // last element + assert(not val.m_value.array->empty()); + dump(val.m_value.array->back(), false, ensure_ascii, indent_step, current_indent); + + o->write_character(']'); + } + + return; + } + + case value_t::string: + { + o->write_character('\"'); + dump_escaped(*val.m_value.string, ensure_ascii); + o->write_character('\"'); + return; + } + + case value_t::boolean: + { + if (val.m_value.boolean) + { + o->write_characters("true", 4); + } + else + { + o->write_characters("false", 5); + } + return; + } + + case value_t::number_integer: + { + dump_integer(val.m_value.number_integer); + return; + } + + case value_t::number_unsigned: + { + dump_integer(val.m_value.number_unsigned); + return; + } + + case value_t::number_float: + { + dump_float(val.m_value.number_float); + return; + } + + case value_t::discarded: + { + o->write_characters("", 11); + return; + } + + case value_t::null: + { + o->write_characters("null", 4); + return; + } + } + } + + private: + /*! + @brief returns the number of expected bytes following in UTF-8 string + + @param[in] u the first byte of a UTF-8 string + @return the number of expected bytes following + */ + static constexpr std::size_t bytes_following(const uint8_t u) + { + return ((u <= 127) ? 0 + : ((192 <= u and u <= 223) ? 1 + : ((224 <= u and u <= 239) ? 2 + : ((240 <= u and u <= 247) ? 3 : std::string::npos)))); + } + + /*! + @brief calculates the extra space to escape a JSON string + + @param[in] s the string to escape + @param[in] ensure_ascii whether to escape non-ASCII characters with + \uXXXX sequences + @return the number of characters required to escape string @a s + + @complexity Linear in the length of string @a s. + */ + static std::size_t extra_space(const string_t& s, + const bool ensure_ascii) noexcept + { + std::size_t res = 0; + + for (std::size_t i = 0; i < s.size(); ++i) + { + switch (s[i]) + { + // control characters that can be escaped with a backslash + case '"': + case '\\': + case '\b': + case '\f': + case '\n': + case '\r': + case '\t': + { + // from c (1 byte) to \x (2 bytes) + res += 1; + break; + } + + // control characters that need \uxxxx escaping + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x0B: + case 0x0E: + case 0x0F: + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + case 0x1A: + case 0x1B: + case 0x1C: + case 0x1D: + case 0x1E: + case 0x1F: + { + // from c (1 byte) to \uxxxx (6 bytes) + res += 5; + break; + } + + default: + { + if (ensure_ascii and (s[i] & 0x80 or s[i] == 0x7F)) + { + const auto bytes = bytes_following(static_cast(s[i])); + // invalid characters will be detected by throw_if_invalid_utf8 + assert (bytes != std::string::npos); + + if (bytes == 3) + { + // codepoints that need 4 bytes (i.e., 3 additional + // bytes) in UTF-8 need a surrogate pair when \u + // escaping is used: from 4 bytes to \uxxxx\uxxxx + // (12 bytes) + res += (12 - bytes - 1); + } + else + { + // from x bytes to \uxxxx (6 bytes) + res += (6 - bytes - 1); + } + + // skip the additional bytes + i += bytes; + } + break; + } + } + } + + return res; + } + + static void escape_codepoint(int codepoint, string_t& result, std::size_t& pos) + { + // expecting a proper codepoint + assert(0x00 <= codepoint and codepoint <= 0x10FFFF); + + // the last written character was the backslash before the 'u' + assert(result[pos] == '\\'); + + // write the 'u' + result[++pos] = 'u'; + + // convert a number 0..15 to its hex representation (0..f) + static const std::array hexify = + { + { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' + } + }; + + if (codepoint < 0x10000) + { + // codepoints U+0000..U+FFFF can be represented as \uxxxx. + result[++pos] = hexify[(codepoint >> 12) & 0x0F]; + result[++pos] = hexify[(codepoint >> 8) & 0x0F]; + result[++pos] = hexify[(codepoint >> 4) & 0x0F]; + result[++pos] = hexify[codepoint & 0x0F]; + } + else + { + // codepoints U+10000..U+10FFFF need a surrogate pair to be + // represented as \uxxxx\uxxxx. + // http://www.unicode.org/faq/utf_bom.html#utf16-4 + codepoint -= 0x10000; + const int high_surrogate = 0xD800 | ((codepoint >> 10) & 0x3FF); + const int low_surrogate = 0xDC00 | (codepoint & 0x3FF); + result[++pos] = hexify[(high_surrogate >> 12) & 0x0F]; + result[++pos] = hexify[(high_surrogate >> 8) & 0x0F]; + result[++pos] = hexify[(high_surrogate >> 4) & 0x0F]; + result[++pos] = hexify[high_surrogate & 0x0F]; + ++pos; // backslash is already in output + result[++pos] = 'u'; + result[++pos] = hexify[(low_surrogate >> 12) & 0x0F]; + result[++pos] = hexify[(low_surrogate >> 8) & 0x0F]; + result[++pos] = hexify[(low_surrogate >> 4) & 0x0F]; + result[++pos] = hexify[low_surrogate & 0x0F]; + } + + ++pos; + } + + /*! + @brief dump escaped string + + Escape a string by replacing certain special characters by a sequence of an + escape character (backslash) and another character and other control + characters by a sequence of "\u" followed by a four-digit hex + representation. The escaped string is written to output stream @a o. + + @param[in] s the string to escape + @param[in] ensure_ascii whether to escape non-ASCII characters with + \uXXXX sequences + + @complexity Linear in the length of string @a s. + */ + void dump_escaped(const string_t& s, const bool ensure_ascii) const + { + throw_if_invalid_utf8(s); + + const auto space = extra_space(s, ensure_ascii); + if (space == 0) + { + o->write_characters(s.c_str(), s.size()); + return; + } + + // create a result string of necessary size + string_t result(s.size() + space, '\\'); + std::size_t pos = 0; + + for (std::size_t i = 0; i < s.size(); ++i) + { + switch (s[i]) + { + case '"': // quotation mark (0x22) + { + result[pos + 1] = '"'; + pos += 2; + break; + } + + case '\\': // reverse solidus (0x5C) + { + // nothing to change + pos += 2; + break; + } + + case '\b': // backspace (0x08) + { + result[pos + 1] = 'b'; + pos += 2; + break; + } + + case '\f': // formfeed (0x0C) + { + result[pos + 1] = 'f'; + pos += 2; + break; + } + + case '\n': // newline (0x0A) + { + result[pos + 1] = 'n'; + pos += 2; + break; + } + + case '\r': // carriage return (0x0D) + { + result[pos + 1] = 'r'; + pos += 2; + break; + } + + case '\t': // horizontal tab (0x09) + { + result[pos + 1] = 't'; + pos += 2; + break; + } + + default: + { + // escape control characters (0x00..0x1F) or, if + // ensure_ascii parameter is used, non-ASCII characters + if ((0x00 <= s[i] and s[i] <= 0x1F) or + (ensure_ascii and (s[i] & 0x80 or s[i] == 0x7F))) + { + const auto bytes = bytes_following(static_cast(s[i])); + // invalid characters will be detected by throw_if_invalid_utf8 + assert (bytes != std::string::npos); + + // check that the additional bytes are present + assert(i + bytes < s.size()); + + // to use \uxxxx escaping, we first need to calculate + // the codepoint from the UTF-8 bytes + int codepoint = 0; + + // bytes is unsigned type: + assert(bytes <= 3); + switch (bytes) + { + case 0: + { + codepoint = s[i] & 0xFF; + break; + } + + case 1: + { + codepoint = ((s[i] & 0x3F) << 6) + + (s[i + 1] & 0x7F); + break; + } + + case 2: + { + codepoint = ((s[i] & 0x1F) << 12) + + ((s[i + 1] & 0x7F) << 6) + + (s[i + 2] & 0x7F); + break; + } + + case 3: + { + codepoint = ((s[i] & 0xF) << 18) + + ((s[i + 1] & 0x7F) << 12) + + ((s[i + 2] & 0x7F) << 6) + + (s[i + 3] & 0x7F); + break; + } + + default: + break; // LCOV_EXCL_LINE + } + + escape_codepoint(codepoint, result, pos); + i += bytes; + } + else + { + // all other characters are added as-is + result[pos++] = s[i]; + } + break; + } + } + } + + assert(pos == result.size()); + o->write_characters(result.c_str(), result.size()); + } + + /*! + @brief dump an integer + + Dump a given integer to output stream @a o. Works internally with + @a number_buffer. + + @param[in] x integer number (signed or unsigned) to dump + @tparam NumberType either @a number_integer_t or @a number_unsigned_t + */ + template::value or + std::is_same::value, + int> = 0> + void dump_integer(NumberType x) + { + // special case for "0" + if (x == 0) + { + o->write_character('0'); + return; + } + + const bool is_negative = (x <= 0) and (x != 0); // see issue #755 + std::size_t i = 0; + + while (x != 0) + { + // spare 1 byte for '\0' + assert(i < number_buffer.size() - 1); + + const auto digit = std::labs(static_cast(x % 10)); + number_buffer[i++] = static_cast('0' + digit); + x /= 10; + } + + if (is_negative) + { + // make sure there is capacity for the '-' + assert(i < number_buffer.size() - 2); + number_buffer[i++] = '-'; + } + + std::reverse(number_buffer.begin(), number_buffer.begin() + i); + o->write_characters(number_buffer.data(), i); + } + + /*! + @brief dump a floating-point number + + Dump a given floating-point number to output stream @a o. Works internally + with @a number_buffer. + + @param[in] x floating-point number to dump + */ + void dump_float(number_float_t x) + { + // NaN / inf + if (not std::isfinite(x) or std::isnan(x)) + { + o->write_characters("null", 4); + return; + } + + // get number of digits for a text -> float -> text round-trip + static constexpr auto d = std::numeric_limits::digits10; + + // the actual conversion + std::ptrdiff_t len = snprintf(number_buffer.data(), number_buffer.size(), "%.*g", d, x); + + // negative value indicates an error + assert(len > 0); + // check if buffer was large enough + assert(static_cast(len) < number_buffer.size()); + + // erase thousands separator + if (thousands_sep != '\0') + { + const auto end = std::remove(number_buffer.begin(), + number_buffer.begin() + len, thousands_sep); + std::fill(end, number_buffer.end(), '\0'); + assert((end - number_buffer.begin()) <= len); + len = (end - number_buffer.begin()); + } + + // convert decimal point to '.' + if (decimal_point != '\0' and decimal_point != '.') + { + const auto dec_pos = std::find(number_buffer.begin(), number_buffer.end(), decimal_point); + if (dec_pos != number_buffer.end()) + { + *dec_pos = '.'; + } + } + + o->write_characters(number_buffer.data(), static_cast(len)); + + // determine if need to append ".0" + const bool value_is_int_like = + std::none_of(number_buffer.begin(), number_buffer.begin() + len + 1, + [](char c) + { + return (c == '.' or c == 'e'); + }); + + if (value_is_int_like) + { + o->write_characters(".0", 2); + } + } + + /*! + @brief check whether a string is UTF-8 encoded + + The function checks each byte of a string whether it is UTF-8 encoded. The + result of the check is stored in the @a state parameter. The function must + be called initially with state 0 (accept). State 1 means the string must + be rejected, because the current byte is not allowed. If the string is + completely processed, but the state is non-zero, the string ended + prematurely; that is, the last byte indicated more bytes should have + followed. + + @param[in,out] state the state of the decoding + @param[in] byte next byte to decode + + @note The function has been edited: a std::array is used and the code + point is not calculated. + + @copyright Copyright (c) 2008-2009 Bjoern Hoehrmann + @sa http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ + */ + static void decode(uint8_t& state, const uint8_t byte) + { + static const std::array utf8d = + { + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00..1F + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20..3F + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 40..5F + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60..7F + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 80..9F + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // A0..BF + 8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // C0..DF + 0xA, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3, 0x3, // E0..EF + 0xB, 0x6, 0x6, 0x6, 0x5, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, // F0..FF + 0x0, 0x1, 0x2, 0x3, 0x5, 0x8, 0x7, 0x1, 0x1, 0x1, 0x4, 0x6, 0x1, 0x1, 0x1, 0x1, // s0..s0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, // s1..s2 + 1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, // s3..s4 + 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, // s5..s6 + 1, 3, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // s7..s8 + } + }; + + const uint8_t type = utf8d[byte]; + state = utf8d[256u + state * 16u + type]; + } + + /*! + @brief throw an exception if a string is not UTF-8 encoded + + @param[in] str UTF-8 string to check + @throw type_error.316 if passed string is not UTF-8 encoded + + @since version 3.0.0 + */ + static void throw_if_invalid_utf8(const std::string& str) + { + // start with state 0 (= accept) + uint8_t state = 0; + + for (size_t i = 0; i < str.size(); ++i) + { + const auto byte = static_cast(str[i]); + decode(state, byte); + if (state == 1) + { + // state 1 means reject + std::stringstream ss; + ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << static_cast(byte); + JSON_THROW(type_error::create(316, "invalid UTF-8 byte at index " + std::to_string(i) + ": 0x" + ss.str())); + } + } + + if (state != 0) + { + // we finish reading, but do not accept: string was incomplete + std::stringstream ss; + ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << static_cast(static_cast(str.back())); + JSON_THROW(type_error::create(316, "incomplete UTF-8 string; last byte: 0x" + ss.str())); + } + } + + private: + /// the output of the serializer + output_adapter_t o = nullptr; + + /// a (hopefully) large enough character buffer + std::array number_buffer{{}}; + + /// the locale + const std::lconv* loc = nullptr; + /// the locale's thousand separator character + const char thousands_sep = '\0'; + /// the locale's decimal point character + const char decimal_point = '\0'; + + /// the indentation character + const char indent_char; + + /// the indentation string + string_t indent_string; +}; +} +} + +#endif + +/*** End of inlined file: serializer.hpp ***/ + + +/*** Start of inlined file: json_ref.hpp ***/ +#ifndef NLOHMANN_JSON_DETAIL_JSON_REF_HPP +#define NLOHMANN_JSON_DETAIL_JSON_REF_HPP + +#include +#include + +namespace nlohmann +{ +namespace detail +{ +template +class json_ref +{ + public: + using value_type = BasicJsonType; + + json_ref(value_type&& value) + : owned_value(std::move(value)), value_ref(&owned_value), is_rvalue(true) + {} + + json_ref(const value_type& value) + : value_ref(const_cast(&value)), is_rvalue(false) + {} + + json_ref(std::initializer_list init) + : owned_value(init), value_ref(&owned_value), is_rvalue(true) + {} + + template + json_ref(Args&& ... args) + : owned_value(std::forward(args)...), value_ref(&owned_value), is_rvalue(true) + {} + + // class should be movable only + json_ref(json_ref&&) = default; + json_ref(const json_ref&) = delete; + json_ref& operator=(const json_ref&) = delete; + + value_type moved_or_copied() const + { + if (is_rvalue) + { + return std::move(*value_ref); + } + return *value_ref; + } + + value_type const& operator*() const + { + return *static_cast(value_ref); + } + + value_type const* operator->() const + { + return static_cast(value_ref); + } + + private: + mutable value_type owned_value = nullptr; + value_type* value_ref = nullptr; + const bool is_rvalue; +}; +} +} + +#endif + +/*** End of inlined file: json_ref.hpp ***/ + + +/*** Start of inlined file: adl_serializer.hpp ***/ +#ifndef NLOHMANN_JSON_ADL_SERIALIZER_HPP +#define NLOHMANN_JSON_ADL_SERIALIZER_HPP + +#include + +namespace nlohmann +{ +template +struct adl_serializer +{ + /*! + @brief convert a JSON value to any value type + + This function is usually called by the `get()` function of the + @ref basic_json class (either explicit or via conversion operators). + + @param[in] j JSON value to read from + @param[in,out] val value to write to + */ + template + static void from_json(BasicJsonType&& j, ValueType& val) noexcept( + noexcept(::nlohmann::from_json(std::forward(j), val))) + { + ::nlohmann::from_json(std::forward(j), val); + } + + /*! + @brief convert any value type to a JSON value + + This function is usually called by the constructors of the @ref basic_json + class. + + @param[in,out] j JSON value to write to + @param[in] val value to read from + */ + template + static void to_json(BasicJsonType& j, ValueType&& val) noexcept( + noexcept(::nlohmann::to_json(j, std::forward(val)))) + { + ::nlohmann::to_json(j, std::forward(val)); + } +}; +} + +#endif + +/*** End of inlined file: adl_serializer.hpp ***/ + +/*! +@brief namespace for Niels Lohmann +@see https://github.com/nlohmann +@since version 1.0.0 +*/ +namespace nlohmann +{ +class json_pointer +{ + /// allow basic_json to access private members + NLOHMANN_BASIC_JSON_TPL_DECLARATION + friend class basic_json; + + public: + /*! + @brief create JSON pointer + + Create a JSON pointer according to the syntax described in + [Section 3 of RFC6901](https://tools.ietf.org/html/rfc6901#section-3). + + @param[in] s string representing the JSON pointer; if omitted, the empty + string is assumed which references the whole JSON value + + @throw parse_error.107 if the given JSON pointer @a s is nonempty and + does not begin with a slash (`/`); see example below + + @throw parse_error.108 if a tilde (`~`) in the given JSON pointer @a s + is not followed by `0` (representing `~`) or `1` (representing `/`); + see example below + + @liveexample{The example shows the construction several valid JSON + pointers as well as the exceptional behavior.,json_pointer} + + @since version 2.0.0 + */ + explicit json_pointer(const std::string& s = "") : reference_tokens(split(s)) {} + + /*! + @brief return a string representation of the JSON pointer + + @invariant For each JSON pointer `ptr`, it holds: + @code {.cpp} + ptr == json_pointer(ptr.to_string()); + @endcode + + @return a string representation of the JSON pointer + + @liveexample{The example shows the result of `to_string`., + json_pointer__to_string} + + @since version 2.0.0 + */ + std::string to_string() const noexcept + { + return std::accumulate(reference_tokens.begin(), reference_tokens.end(), + std::string{}, + [](const std::string & a, const std::string & b) + { + return a + "/" + escape(b); + }); + } + + /// @copydoc to_string() + operator std::string() const + { + return to_string(); + } + + /*! + @param[in] s reference token to be converted into an array index + + @return integer representation of @a s + + @throw out_of_range.404 if string @a s could not be converted to an integer + */ + static int array_index(const std::string& s) + { + size_t processed_chars = 0; + const int res = std::stoi(s, &processed_chars); + + // check if the string was completely read + if (JSON_UNLIKELY(processed_chars != s.size())) + { + JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + s + "'")); + } + + return res; + } + + private: + /*! + @brief remove and return last reference pointer + @throw out_of_range.405 if JSON pointer has no parent + */ + std::string pop_back() + { + if (JSON_UNLIKELY(is_root())) + { + JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent")); + } + + auto last = reference_tokens.back(); + reference_tokens.pop_back(); + return last; + } + + /// return whether pointer points to the root document + bool is_root() const + { + return reference_tokens.empty(); + } + + json_pointer top() const + { + if (JSON_UNLIKELY(is_root())) + { + JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent")); + } + + json_pointer result = *this; + result.reference_tokens = {reference_tokens[0]}; + return result; + } + + /*! + @brief create and return a reference to the pointed to value + + @complexity Linear in the number of reference tokens. + + @throw parse_error.109 if array index is not a number + @throw type_error.313 if value cannot be unflattened + */ + NLOHMANN_BASIC_JSON_TPL_DECLARATION + NLOHMANN_BASIC_JSON_TPL& get_and_create(NLOHMANN_BASIC_JSON_TPL& j) const; + + /*! + @brief return a reference to the pointed to value + + @note This version does not throw if a value is not present, but tries to + create nested values instead. For instance, calling this function + with pointer `"/this/that"` on a null value is equivalent to calling + `operator[]("this").operator[]("that")` on that value, effectively + changing the null value to an object. + + @param[in] ptr a JSON value + + @return reference to the JSON value pointed to by the JSON pointer + + @complexity Linear in the length of the JSON pointer. + + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.404 if the JSON pointer can not be resolved + */ + NLOHMANN_BASIC_JSON_TPL_DECLARATION + NLOHMANN_BASIC_JSON_TPL& get_unchecked(NLOHMANN_BASIC_JSON_TPL* ptr) const; + + /*! + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.402 if the array index '-' is used + @throw out_of_range.404 if the JSON pointer can not be resolved + */ + NLOHMANN_BASIC_JSON_TPL_DECLARATION + NLOHMANN_BASIC_JSON_TPL& get_checked(NLOHMANN_BASIC_JSON_TPL* ptr) const; + + /*! + @brief return a const reference to the pointed to value + + @param[in] ptr a JSON value + + @return const reference to the JSON value pointed to by the JSON + pointer + + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.402 if the array index '-' is used + @throw out_of_range.404 if the JSON pointer can not be resolved + */ + NLOHMANN_BASIC_JSON_TPL_DECLARATION + const NLOHMANN_BASIC_JSON_TPL& get_unchecked(const NLOHMANN_BASIC_JSON_TPL* ptr) const; + + /*! + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.402 if the array index '-' is used + @throw out_of_range.404 if the JSON pointer can not be resolved + */ + NLOHMANN_BASIC_JSON_TPL_DECLARATION + const NLOHMANN_BASIC_JSON_TPL& get_checked(const NLOHMANN_BASIC_JSON_TPL* ptr) const; + + /*! + @brief split the string input to reference tokens + + @note This function is only called by the json_pointer constructor. + All exceptions below are documented there. + + @throw parse_error.107 if the pointer is not empty or begins with '/' + @throw parse_error.108 if character '~' is not followed by '0' or '1' + */ + static std::vector split(const std::string& reference_string) + { + std::vector result; + + // special case: empty reference string -> no reference tokens + if (reference_string.empty()) + { + return result; + } + + // check if nonempty reference string begins with slash + if (JSON_UNLIKELY(reference_string[0] != '/')) + { + JSON_THROW(detail::parse_error::create(107, 1, + "JSON pointer must be empty or begin with '/' - was: '" + + reference_string + "'")); + } + + // extract the reference tokens: + // - slash: position of the last read slash (or end of string) + // - start: position after the previous slash + for ( + // search for the first slash after the first character + std::size_t slash = reference_string.find_first_of('/', 1), + // set the beginning of the first reference token + start = 1; + // we can stop if start == string::npos+1 = 0 + start != 0; + // set the beginning of the next reference token + // (will eventually be 0 if slash == std::string::npos) + start = slash + 1, + // find next slash + slash = reference_string.find_first_of('/', start)) + { + // use the text between the beginning of the reference token + // (start) and the last slash (slash). + auto reference_token = reference_string.substr(start, slash - start); + + // check reference tokens are properly escaped + for (std::size_t pos = reference_token.find_first_of('~'); + pos != std::string::npos; + pos = reference_token.find_first_of('~', pos + 1)) + { + assert(reference_token[pos] == '~'); + + // ~ must be followed by 0 or 1 + if (JSON_UNLIKELY(pos == reference_token.size() - 1 or + (reference_token[pos + 1] != '0' and + reference_token[pos + 1] != '1'))) + { + JSON_THROW(detail::parse_error::create(108, 0, "escape character '~' must be followed with '0' or '1'")); + } + } + + // finally, store the reference token + unescape(reference_token); + result.push_back(reference_token); + } + + return result; + } + + /*! + @brief replace all occurrences of a substring by another string + + @param[in,out] s the string to manipulate; changed so that all + occurrences of @a f are replaced with @a t + @param[in] f the substring to replace with @a t + @param[in] t the string to replace @a f + + @pre The search string @a f must not be empty. **This precondition is + enforced with an assertion.** + + @since version 2.0.0 + */ + static void replace_substring(std::string& s, const std::string& f, + const std::string& t) + { + assert(not f.empty()); + for (auto pos = s.find(f); // find first occurrence of f + pos != std::string::npos; // make sure f was found + s.replace(pos, f.size(), t), // replace with t, and + pos = s.find(f, pos + t.size())) // find next occurrence of f + {} + } + + /// escape "~"" to "~0" and "/" to "~1" + static std::string escape(std::string s) + { + replace_substring(s, "~", "~0"); + replace_substring(s, "/", "~1"); + return s; + } + + /// unescape "~1" to tilde and "~0" to slash (order is important!) + static void unescape(std::string& s) + { + replace_substring(s, "~1", "/"); + replace_substring(s, "~0", "~"); + } + + /*! + @param[in] reference_string the reference string to the current value + @param[in] value the value to consider + @param[in,out] result the result object to insert values to + + @note Empty objects or arrays are flattened to `null`. + */ + NLOHMANN_BASIC_JSON_TPL_DECLARATION + static void flatten(const std::string& reference_string, + const NLOHMANN_BASIC_JSON_TPL& value, + NLOHMANN_BASIC_JSON_TPL& result); + + /*! + @param[in] value flattened JSON + + @return unflattened JSON + + @throw parse_error.109 if array index is not a number + @throw type_error.314 if value is not an object + @throw type_error.315 if object values are not primitive + @throw type_error.313 if value cannot be unflattened + */ + NLOHMANN_BASIC_JSON_TPL_DECLARATION + static NLOHMANN_BASIC_JSON_TPL + unflatten(const NLOHMANN_BASIC_JSON_TPL& value); + + friend bool operator==(json_pointer const& lhs, + json_pointer const& rhs) noexcept; + + friend bool operator!=(json_pointer const& lhs, + json_pointer const& rhs) noexcept; + + /// the reference tokens + std::vector reference_tokens; +}; + +/*! +@brief a class to store JSON values + +@tparam ObjectType type for JSON objects (`std::map` by default; will be used +in @ref object_t) +@tparam ArrayType type for JSON arrays (`std::vector` by default; will be used +in @ref array_t) +@tparam StringType type for JSON strings and object keys (`std::string` by +default; will be used in @ref string_t) +@tparam BooleanType type for JSON booleans (`bool` by default; will be used +in @ref boolean_t) +@tparam NumberIntegerType type for JSON integer numbers (`int64_t` by +default; will be used in @ref number_integer_t) +@tparam NumberUnsignedType type for JSON unsigned integer numbers (@c +`uint64_t` by default; will be used in @ref number_unsigned_t) +@tparam NumberFloatType type for JSON floating-point numbers (`double` by +default; will be used in @ref number_float_t) +@tparam AllocatorType type of the allocator to use (`std::allocator` by +default) +@tparam JSONSerializer the serializer to resolve internal calls to `to_json()` +and `from_json()` (@ref adl_serializer by default) + +@requirement The class satisfies the following concept requirements: +- Basic + - [DefaultConstructible](http://en.cppreference.com/w/cpp/concept/DefaultConstructible): + JSON values can be default constructed. The result will be a JSON null + value. + - [MoveConstructible](http://en.cppreference.com/w/cpp/concept/MoveConstructible): + A JSON value can be constructed from an rvalue argument. + - [CopyConstructible](http://en.cppreference.com/w/cpp/concept/CopyConstructible): + A JSON value can be copy-constructed from an lvalue expression. + - [MoveAssignable](http://en.cppreference.com/w/cpp/concept/MoveAssignable): + A JSON value van be assigned from an rvalue argument. + - [CopyAssignable](http://en.cppreference.com/w/cpp/concept/CopyAssignable): + A JSON value can be copy-assigned from an lvalue expression. + - [Destructible](http://en.cppreference.com/w/cpp/concept/Destructible): + JSON values can be destructed. +- Layout + - [StandardLayoutType](http://en.cppreference.com/w/cpp/concept/StandardLayoutType): + JSON values have + [standard layout](http://en.cppreference.com/w/cpp/language/data_members#Standard_layout): + All non-static data members are private and standard layout types, the + class has no virtual functions or (virtual) base classes. +- Library-wide + - [EqualityComparable](http://en.cppreference.com/w/cpp/concept/EqualityComparable): + JSON values can be compared with `==`, see @ref + operator==(const_reference,const_reference). + - [LessThanComparable](http://en.cppreference.com/w/cpp/concept/LessThanComparable): + JSON values can be compared with `<`, see @ref + operator<(const_reference,const_reference). + - [Swappable](http://en.cppreference.com/w/cpp/concept/Swappable): + Any JSON lvalue or rvalue of can be swapped with any lvalue or rvalue of + other compatible types, using unqualified function call @ref swap(). + - [NullablePointer](http://en.cppreference.com/w/cpp/concept/NullablePointer): + JSON values can be compared against `std::nullptr_t` objects which are used + to model the `null` value. +- Container + - [Container](http://en.cppreference.com/w/cpp/concept/Container): + JSON values can be used like STL containers and provide iterator access. + - [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer); + JSON values can be used like STL containers and provide reverse iterator + access. + +@invariant The member variables @a m_value and @a m_type have the following +relationship: +- If `m_type == value_t::object`, then `m_value.object != nullptr`. +- If `m_type == value_t::array`, then `m_value.array != nullptr`. +- If `m_type == value_t::string`, then `m_value.string != nullptr`. +The invariants are checked by member function assert_invariant(). + +@internal +@note ObjectType trick from http://stackoverflow.com/a/9860911 +@endinternal + +@see [RFC 7159: The JavaScript Object Notation (JSON) Data Interchange +Format](http://rfc7159.net/rfc7159) + +@since version 1.0.0 + +@nosubgrouping +*/ +NLOHMANN_BASIC_JSON_TPL_DECLARATION +class basic_json +{ + private: + template friend struct detail::external_constructor; + friend ::nlohmann::json_pointer; + friend ::nlohmann::detail::parser; + friend ::nlohmann::detail::serializer; + template + friend class ::nlohmann::detail::iter_impl; + template + friend class ::nlohmann::detail::binary_writer; + template + friend class ::nlohmann::detail::binary_reader; + + /// workaround type for MSVC + using basic_json_t = NLOHMANN_BASIC_JSON_TPL; + + // convenience aliases for types residing in namespace detail; + using lexer = ::nlohmann::detail::lexer; + using parser = ::nlohmann::detail::parser; + + using primitive_iterator_t = ::nlohmann::detail::primitive_iterator_t; + template + using internal_iterator = ::nlohmann::detail::internal_iterator; + template + using iter_impl = ::nlohmann::detail::iter_impl; + template + using iteration_proxy = ::nlohmann::detail::iteration_proxy; + template using json_reverse_iterator = ::nlohmann::detail::json_reverse_iterator; + + template + using output_adapter_t = ::nlohmann::detail::output_adapter_t; + + using binary_reader = ::nlohmann::detail::binary_reader; + template using binary_writer = ::nlohmann::detail::binary_writer; + + using serializer = ::nlohmann::detail::serializer; + + public: + using value_t = detail::value_t; + /// @copydoc nlohmann::json_pointer + using json_pointer = ::nlohmann::json_pointer; + template + using json_serializer = JSONSerializer; + /// helper type for initializer lists of basic_json values + using initializer_list_t = std::initializer_list>; + + //////////////// + // exceptions // + //////////////// + + /// @name exceptions + /// Classes to implement user-defined exceptions. + /// @{ + + /// @copydoc detail::exception + using exception = detail::exception; + /// @copydoc detail::parse_error + using parse_error = detail::parse_error; + /// @copydoc detail::invalid_iterator + using invalid_iterator = detail::invalid_iterator; + /// @copydoc detail::type_error + using type_error = detail::type_error; + /// @copydoc detail::out_of_range + using out_of_range = detail::out_of_range; + /// @copydoc detail::other_error + using other_error = detail::other_error; + + /// @} + + ///////////////////// + // container types // + ///////////////////// + + /// @name container types + /// The canonic container types to use @ref basic_json like any other STL + /// container. + /// @{ + + /// the type of elements in a basic_json container + using value_type = basic_json; + + /// the type of an element reference + using reference = value_type&; + /// the type of an element const reference + using const_reference = const value_type&; + + /// a type to represent differences between iterators + using difference_type = std::ptrdiff_t; + /// a type to represent container sizes + using size_type = std::size_t; + + /// the allocator type + using allocator_type = AllocatorType; + + /// the type of an element pointer + using pointer = typename std::allocator_traits::pointer; + /// the type of an element const pointer + using const_pointer = typename std::allocator_traits::const_pointer; + + /// an iterator for a basic_json container + using iterator = iter_impl; + /// a const iterator for a basic_json container + using const_iterator = iter_impl; + /// a reverse iterator for a basic_json container + using reverse_iterator = json_reverse_iterator; + /// a const reverse iterator for a basic_json container + using const_reverse_iterator = json_reverse_iterator; + + /// @} + + /*! + @brief returns the allocator associated with the container + */ + static allocator_type get_allocator() + { + return allocator_type(); + } + + /*! + @brief returns version information on the library + + This function returns a JSON object with information about the library, + including the version number and information on the platform and compiler. + + @return JSON object holding version information + key | description + ----------- | --------------- + `compiler` | Information on the used compiler. It is an object with the following keys: `c++` (the used C++ standard), `family` (the compiler family; possible values are `clang`, `icc`, `gcc`, `ilecpp`, `msvc`, `pgcpp`, `sunpro`, and `unknown`), and `version` (the compiler version). + `copyright` | The copyright line for the library as string. + `name` | The name of the library as string. + `platform` | The used platform as string. Possible values are `win32`, `linux`, `apple`, `unix`, and `unknown`. + `url` | The URL of the project as string. + `version` | The version of the library. It is an object with the following keys: `major`, `minor`, and `patch` as defined by [Semantic Versioning](http://semver.org), and `string` (the version string). + + @liveexample{The following code shows an example output of the `meta()` + function.,meta} + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @complexity Constant. + + @since 2.1.0 + */ + static basic_json meta() + { + basic_json result; + + result["copyright"] = "(C) 2013-2017 Niels Lohmann"; + result["name"] = "JSON for Modern C++"; + result["url"] = "https://github.com/nlohmann/json"; + result["version"] = + { + {"string", "3.0.0"}, {"major", 3}, {"minor", 0}, {"patch", 0} + }; + +#ifdef _WIN32 + result["platform"] = "win32"; +#elif defined __linux__ + result["platform"] = "linux"; +#elif defined __APPLE__ + result["platform"] = "apple"; +#elif defined __unix__ + result["platform"] = "unix"; +#else + result["platform"] = "unknown"; +#endif + +#if defined(__ICC) || defined(__INTEL_COMPILER) + result["compiler"] = {{"family", "icc"}, {"version", __INTEL_COMPILER}}; +#elif defined(__clang__) + result["compiler"] = {{"family", "clang"}, {"version", __clang_version__}}; +#elif defined(__GNUC__) || defined(__GNUG__) + result["compiler"] = {{"family", "gcc"}, {"version", std::to_string(__GNUC__) + "." + std::to_string(__GNUC_MINOR__) + "." + std::to_string(__GNUC_PATCHLEVEL__)}}; +#elif defined(__HP_cc) || defined(__HP_aCC) + result["compiler"] = "hp" +#elif defined(__IBMCPP__) + result["compiler"] = {{"family", "ilecpp"}, {"version", __IBMCPP__}}; +#elif defined(_MSC_VER) + result["compiler"] = {{"family", "msvc"}, {"version", _MSC_VER}}; +#elif defined(__PGI) + result["compiler"] = {{"family", "pgcpp"}, {"version", __PGI}}; +#elif defined(__SUNPRO_CC) + result["compiler"] = {{"family", "sunpro"}, {"version", __SUNPRO_CC}}; +#else + result["compiler"] = {{"family", "unknown"}, {"version", "unknown"}}; +#endif + +#ifdef __cplusplus + result["compiler"]["c++"] = std::to_string(__cplusplus); +#else + result["compiler"]["c++"] = "unknown"; +#endif + return result; + } + + /////////////////////////// + // JSON value data types // + /////////////////////////// + + /// @name JSON value data types + /// The data types to store a JSON value. These types are derived from + /// the template arguments passed to class @ref basic_json. + /// @{ + +#if defined(JSON_HAS_CPP_14) + // Use transparent comparator if possible, combined with perfect forwarding + // on find() and count() calls prevents unnecessary string construction. + using object_comparator_t = std::less<>; +#else + using object_comparator_t = std::less; +#endif + + /*! + @brief a type for an object + + [RFC 7159](http://rfc7159.net/rfc7159) describes JSON objects as follows: + > An object is an unordered collection of zero or more name/value pairs, + > where a name is a string and a value is a string, number, boolean, null, + > object, or array. + + To store objects in C++, a type is defined by the template parameters + described below. + + @tparam ObjectType the container to store objects (e.g., `std::map` or + `std::unordered_map`) + @tparam StringType the type of the keys or names (e.g., `std::string`). + The comparison function `std::less` is used to order elements + inside the container. + @tparam AllocatorType the allocator to use for objects (e.g., + `std::allocator`) + + #### Default type + + With the default values for @a ObjectType (`std::map`), @a StringType + (`std::string`), and @a AllocatorType (`std::allocator`), the default + value for @a object_t is: + + @code {.cpp} + std::map< + std::string, // key_type + basic_json, // value_type + std::less, // key_compare + std::allocator> // allocator_type + > + @endcode + + #### Behavior + + The choice of @a object_t influences the behavior of the JSON class. With + the default type, objects have the following behavior: + + - When all names are unique, objects will be interoperable in the sense + that all software implementations receiving that object will agree on + the name-value mappings. + - When the names within an object are not unique, later stored name/value + pairs overwrite previously stored name/value pairs, leaving the used + names unique. For instance, `{"key": 1}` and `{"key": 2, "key": 1}` will + be treated as equal and both stored as `{"key": 1}`. + - Internally, name/value pairs are stored in lexicographical order of the + names. Objects will also be serialized (see @ref dump) in this order. + For instance, `{"b": 1, "a": 2}` and `{"a": 2, "b": 1}` will be stored + and serialized as `{"a": 2, "b": 1}`. + - When comparing objects, the order of the name/value pairs is irrelevant. + This makes objects interoperable in the sense that they will not be + affected by these differences. For instance, `{"b": 1, "a": 2}` and + `{"a": 2, "b": 1}` will be treated as equal. + + #### Limits + + [RFC 7159](http://rfc7159.net/rfc7159) specifies: + > An implementation may set limits on the maximum depth of nesting. + + In this class, the object's limit of nesting is not explicitly constrained. + However, a maximum depth of nesting may be introduced by the compiler or + runtime environment. A theoretical limit can be queried by calling the + @ref max_size function of a JSON object. + + #### Storage + + Objects are stored as pointers in a @ref basic_json type. That is, for any + access to object values, a pointer of type `object_t*` must be + dereferenced. + + @sa @ref array_t -- type for an array value + + @since version 1.0.0 + + @note The order name/value pairs are added to the object is *not* + preserved by the library. Therefore, iterating an object may return + name/value pairs in a different order than they were originally stored. In + fact, keys will be traversed in alphabetical order as `std::map` with + `std::less` is used by default. Please note this behavior conforms to [RFC + 7159](http://rfc7159.net/rfc7159), because any order implements the + specified "unordered" nature of JSON objects. + */ + using object_t = ObjectType>>; + + /*! + @brief a type for an array + + [RFC 7159](http://rfc7159.net/rfc7159) describes JSON arrays as follows: + > An array is an ordered sequence of zero or more values. + + To store objects in C++, a type is defined by the template parameters + explained below. + + @tparam ArrayType container type to store arrays (e.g., `std::vector` or + `std::list`) + @tparam AllocatorType allocator to use for arrays (e.g., `std::allocator`) + + #### Default type + + With the default values for @a ArrayType (`std::vector`) and @a + AllocatorType (`std::allocator`), the default value for @a array_t is: + + @code {.cpp} + std::vector< + basic_json, // value_type + std::allocator // allocator_type + > + @endcode + + #### Limits + + [RFC 7159](http://rfc7159.net/rfc7159) specifies: + > An implementation may set limits on the maximum depth of nesting. + + In this class, the array's limit of nesting is not explicitly constrained. + However, a maximum depth of nesting may be introduced by the compiler or + runtime environment. A theoretical limit can be queried by calling the + @ref max_size function of a JSON array. + + #### Storage + + Arrays are stored as pointers in a @ref basic_json type. That is, for any + access to array values, a pointer of type `array_t*` must be dereferenced. + + @sa @ref object_t -- type for an object value + + @since version 1.0.0 + */ + using array_t = ArrayType>; + + /*! + @brief a type for a string + + [RFC 7159](http://rfc7159.net/rfc7159) describes JSON strings as follows: + > A string is a sequence of zero or more Unicode characters. + + To store objects in C++, a type is defined by the template parameter + described below. Unicode values are split by the JSON class into + byte-sized characters during deserialization. + + @tparam StringType the container to store strings (e.g., `std::string`). + Note this container is used for keys/names in objects, see @ref object_t. + + #### Default type + + With the default values for @a StringType (`std::string`), the default + value for @a string_t is: + + @code {.cpp} + std::string + @endcode + + #### Encoding + + Strings are stored in UTF-8 encoding. Therefore, functions like + `std::string::size()` or `std::string::length()` return the number of + bytes in the string rather than the number of characters or glyphs. + + #### String comparison + + [RFC 7159](http://rfc7159.net/rfc7159) states: + > Software implementations are typically required to test names of object + > members for equality. Implementations that transform the textual + > representation into sequences of Unicode code units and then perform the + > comparison numerically, code unit by code unit, are interoperable in the + > sense that implementations will agree in all cases on equality or + > inequality of two strings. For example, implementations that compare + > strings with escaped characters unconverted may incorrectly find that + > `"a\\b"` and `"a\u005Cb"` are not equal. + + This implementation is interoperable as it does compare strings code unit + by code unit. + + #### Storage + + String values are stored as pointers in a @ref basic_json type. That is, + for any access to string values, a pointer of type `string_t*` must be + dereferenced. + + @since version 1.0.0 + */ + using string_t = StringType; + + /*! + @brief a type for a boolean + + [RFC 7159](http://rfc7159.net/rfc7159) implicitly describes a boolean as a + type which differentiates the two literals `true` and `false`. + + To store objects in C++, a type is defined by the template parameter @a + BooleanType which chooses the type to use. + + #### Default type + + With the default values for @a BooleanType (`bool`), the default value for + @a boolean_t is: + + @code {.cpp} + bool + @endcode + + #### Storage + + Boolean values are stored directly inside a @ref basic_json type. + + @since version 1.0.0 + */ + using boolean_t = BooleanType; + + /*! + @brief a type for a number (integer) + + [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: + > The representation of numbers is similar to that used in most + > programming languages. A number is represented in base 10 using decimal + > digits. It contains an integer component that may be prefixed with an + > optional minus sign, which may be followed by a fraction part and/or an + > exponent part. Leading zeros are not allowed. (...) Numeric values that + > cannot be represented in the grammar below (such as Infinity and NaN) + > are not permitted. + + This description includes both integer and floating-point numbers. + However, C++ allows more precise storage if it is known whether the number + is a signed integer, an unsigned integer or a floating-point number. + Therefore, three different types, @ref number_integer_t, @ref + number_unsigned_t and @ref number_float_t are used. + + To store integer numbers in C++, a type is defined by the template + parameter @a NumberIntegerType which chooses the type to use. + + #### Default type + + With the default values for @a NumberIntegerType (`int64_t`), the default + value for @a number_integer_t is: + + @code {.cpp} + int64_t + @endcode + + #### Default behavior + + - The restrictions about leading zeros is not enforced in C++. Instead, + leading zeros in integer literals lead to an interpretation as octal + number. Internally, the value will be stored as decimal number. For + instance, the C++ integer literal `010` will be serialized to `8`. + During deserialization, leading zeros yield an error. + - Not-a-number (NaN) values will be serialized to `null`. + + #### Limits + + [RFC 7159](http://rfc7159.net/rfc7159) specifies: + > An implementation may set limits on the range and precision of numbers. + + When the default type is used, the maximal integer number that can be + stored is `9223372036854775807` (INT64_MAX) and the minimal integer number + that can be stored is `-9223372036854775808` (INT64_MIN). Integer numbers + that are out of range will yield over/underflow when used in a + constructor. During deserialization, too large or small integer numbers + will be automatically be stored as @ref number_unsigned_t or @ref + number_float_t. + + [RFC 7159](http://rfc7159.net/rfc7159) further states: + > Note that when such software is used, numbers that are integers and are + > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense + > that implementations will agree exactly on their numeric values. + + As this range is a subrange of the exactly supported range [INT64_MIN, + INT64_MAX], this class's integer type is interoperable. + + #### Storage + + Integer number values are stored directly inside a @ref basic_json type. + + @sa @ref number_float_t -- type for number values (floating-point) + + @sa @ref number_unsigned_t -- type for number values (unsigned integer) + + @since version 1.0.0 + */ + using number_integer_t = NumberIntegerType; + + /*! + @brief a type for a number (unsigned) + + [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: + > The representation of numbers is similar to that used in most + > programming languages. A number is represented in base 10 using decimal + > digits. It contains an integer component that may be prefixed with an + > optional minus sign, which may be followed by a fraction part and/or an + > exponent part. Leading zeros are not allowed. (...) Numeric values that + > cannot be represented in the grammar below (such as Infinity and NaN) + > are not permitted. + + This description includes both integer and floating-point numbers. + However, C++ allows more precise storage if it is known whether the number + is a signed integer, an unsigned integer or a floating-point number. + Therefore, three different types, @ref number_integer_t, @ref + number_unsigned_t and @ref number_float_t are used. + + To store unsigned integer numbers in C++, a type is defined by the + template parameter @a NumberUnsignedType which chooses the type to use. + + #### Default type + + With the default values for @a NumberUnsignedType (`uint64_t`), the + default value for @a number_unsigned_t is: + + @code {.cpp} + uint64_t + @endcode + + #### Default behavior + + - The restrictions about leading zeros is not enforced in C++. Instead, + leading zeros in integer literals lead to an interpretation as octal + number. Internally, the value will be stored as decimal number. For + instance, the C++ integer literal `010` will be serialized to `8`. + During deserialization, leading zeros yield an error. + - Not-a-number (NaN) values will be serialized to `null`. + + #### Limits + + [RFC 7159](http://rfc7159.net/rfc7159) specifies: + > An implementation may set limits on the range and precision of numbers. + + When the default type is used, the maximal integer number that can be + stored is `18446744073709551615` (UINT64_MAX) and the minimal integer + number that can be stored is `0`. Integer numbers that are out of range + will yield over/underflow when used in a constructor. During + deserialization, too large or small integer numbers will be automatically + be stored as @ref number_integer_t or @ref number_float_t. + + [RFC 7159](http://rfc7159.net/rfc7159) further states: + > Note that when such software is used, numbers that are integers and are + > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense + > that implementations will agree exactly on their numeric values. + + As this range is a subrange (when considered in conjunction with the + number_integer_t type) of the exactly supported range [0, UINT64_MAX], + this class's integer type is interoperable. + + #### Storage + + Integer number values are stored directly inside a @ref basic_json type. + + @sa @ref number_float_t -- type for number values (floating-point) + @sa @ref number_integer_t -- type for number values (integer) + + @since version 2.0.0 + */ + using number_unsigned_t = NumberUnsignedType; + + /*! + @brief a type for a number (floating-point) + + [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: + > The representation of numbers is similar to that used in most + > programming languages. A number is represented in base 10 using decimal + > digits. It contains an integer component that may be prefixed with an + > optional minus sign, which may be followed by a fraction part and/or an + > exponent part. Leading zeros are not allowed. (...) Numeric values that + > cannot be represented in the grammar below (such as Infinity and NaN) + > are not permitted. + + This description includes both integer and floating-point numbers. + However, C++ allows more precise storage if it is known whether the number + is a signed integer, an unsigned integer or a floating-point number. + Therefore, three different types, @ref number_integer_t, @ref + number_unsigned_t and @ref number_float_t are used. + + To store floating-point numbers in C++, a type is defined by the template + parameter @a NumberFloatType which chooses the type to use. + + #### Default type + + With the default values for @a NumberFloatType (`double`), the default + value for @a number_float_t is: + + @code {.cpp} + double + @endcode + + #### Default behavior + + - The restrictions about leading zeros is not enforced in C++. Instead, + leading zeros in floating-point literals will be ignored. Internally, + the value will be stored as decimal number. For instance, the C++ + floating-point literal `01.2` will be serialized to `1.2`. During + deserialization, leading zeros yield an error. + - Not-a-number (NaN) values will be serialized to `null`. + + #### Limits + + [RFC 7159](http://rfc7159.net/rfc7159) states: + > This specification allows implementations to set limits on the range and + > precision of numbers accepted. Since software that implements IEEE + > 754-2008 binary64 (double precision) numbers is generally available and + > widely used, good interoperability can be achieved by implementations + > that expect no more precision or range than these provide, in the sense + > that implementations will approximate JSON numbers within the expected + > precision. + + This implementation does exactly follow this approach, as it uses double + precision floating-point numbers. Note values smaller than + `-1.79769313486232e+308` and values greater than `1.79769313486232e+308` + will be stored as NaN internally and be serialized to `null`. + + #### Storage + + Floating-point number values are stored directly inside a @ref basic_json + type. + + @sa @ref number_integer_t -- type for number values (integer) + + @sa @ref number_unsigned_t -- type for number values (unsigned integer) + + @since version 1.0.0 + */ + using number_float_t = NumberFloatType; + + /// @} + + private: + + /// helper for exception-safe object creation + template + static T* create(Args&& ... args) + { + AllocatorType alloc; + using AllocatorTraits = std::allocator_traits>; + + auto deleter = [&](T * object) + { + AllocatorTraits::deallocate(alloc, object, 1); + }; + std::unique_ptr object(AllocatorTraits::allocate(alloc, 1), deleter); + AllocatorTraits::construct(alloc, object.get(), std::forward(args)...); + assert(object != nullptr); + return object.release(); + } + + //////////////////////// + // JSON value storage // + //////////////////////// + + /*! + @brief a JSON value + + The actual storage for a JSON value of the @ref basic_json class. This + union combines the different storage types for the JSON value types + defined in @ref value_t. + + JSON type | value_t type | used type + --------- | --------------- | ------------------------ + object | object | pointer to @ref object_t + array | array | pointer to @ref array_t + string | string | pointer to @ref string_t + boolean | boolean | @ref boolean_t + number | number_integer | @ref number_integer_t + number | number_unsigned | @ref number_unsigned_t + number | number_float | @ref number_float_t + null | null | *no value is stored* + + @note Variable-length types (objects, arrays, and strings) are stored as + pointers. The size of the union should not exceed 64 bits if the default + value types are used. + + @since version 1.0.0 + */ + union json_value + { + /// object (stored with pointer to save storage) + object_t* object; + /// array (stored with pointer to save storage) + array_t* array; + /// string (stored with pointer to save storage) + string_t* string; + /// boolean + boolean_t boolean; + /// number (integer) + number_integer_t number_integer; + /// number (unsigned integer) + number_unsigned_t number_unsigned; + /// number (floating-point) + number_float_t number_float; + + /// default constructor (for null values) + json_value() = default; + /// constructor for booleans + json_value(boolean_t v) noexcept : boolean(v) {} + /// constructor for numbers (integer) + json_value(number_integer_t v) noexcept : number_integer(v) {} + /// constructor for numbers (unsigned) + json_value(number_unsigned_t v) noexcept : number_unsigned(v) {} + /// constructor for numbers (floating-point) + json_value(number_float_t v) noexcept : number_float(v) {} + /// constructor for empty values of a given type + json_value(value_t t) + { + switch (t) + { + case value_t::object: + { + object = create(); + break; + } + + case value_t::array: + { + array = create(); + break; + } + + case value_t::string: + { + string = create(""); + break; + } + + case value_t::boolean: + { + boolean = boolean_t(false); + break; + } + + case value_t::number_integer: + { + number_integer = number_integer_t(0); + break; + } + + case value_t::number_unsigned: + { + number_unsigned = number_unsigned_t(0); + break; + } + + case value_t::number_float: + { + number_float = number_float_t(0.0); + break; + } + + case value_t::null: + { + object = nullptr; // silence warning, see #821 + break; + } + + default: + { + object = nullptr; // silence warning, see #821 + if (JSON_UNLIKELY(t == value_t::null)) + { + JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.0.0")); // LCOV_EXCL_LINE + } + break; + } + } + } + + /// constructor for strings + json_value(const string_t& value) + { + string = create(value); + } + + /// constructor for rvalue strings + json_value(string_t&& value) + { + string = create(std::move(value)); + } + + /// constructor for objects + json_value(const object_t& value) + { + object = create(value); + } + + /// constructor for rvalue objects + json_value(object_t&& value) + { + object = create(std::move(value)); + } + + /// constructor for arrays + json_value(const array_t& value) + { + array = create(value); + } + + /// constructor for rvalue arrays + json_value(array_t&& value) + { + array = create(std::move(value)); + } + + void destroy(value_t t) + { + switch (t) + { + case value_t::object: + { + AllocatorType alloc; + std::allocator_traits::destroy(alloc, object); + std::allocator_traits::deallocate(alloc, object, 1); + break; + } + + case value_t::array: + { + AllocatorType alloc; + std::allocator_traits::destroy(alloc, array); + std::allocator_traits::deallocate(alloc, array, 1); + break; + } + + case value_t::string: + { + AllocatorType alloc; + std::allocator_traits::destroy(alloc, string); + std::allocator_traits::deallocate(alloc, string, 1); + break; + } + + default: + { + break; + } + } + } + }; + + /*! + @brief checks the class invariants + + This function asserts the class invariants. It needs to be called at the + end of every constructor to make sure that created objects respect the + invariant. Furthermore, it has to be called each time the type of a JSON + value is changed, because the invariant expresses a relationship between + @a m_type and @a m_value. + */ + void assert_invariant() const + { + assert(m_type != value_t::object or m_value.object != nullptr); + assert(m_type != value_t::array or m_value.array != nullptr); + assert(m_type != value_t::string or m_value.string != nullptr); + } + + public: + ////////////////////////// + // JSON parser callback // + ////////////////////////// + + /*! + @brief parser event types + + The parser callback distinguishes the following events: + - `object_start`: the parser read `{` and started to process a JSON object + - `key`: the parser read a key of a value in an object + - `object_end`: the parser read `}` and finished processing a JSON object + - `array_start`: the parser read `[` and started to process a JSON array + - `array_end`: the parser read `]` and finished processing a JSON array + - `value`: the parser finished reading a JSON value + + @image html callback_events.png "Example when certain parse events are triggered" + + @sa @ref parser_callback_t for more information and examples + */ + using parse_event_t = typename parser::parse_event_t; + + /*! + @brief per-element parser callback type + + With a parser callback function, the result of parsing a JSON text can be + influenced. When passed to @ref parse, it is called on certain events + (passed as @ref parse_event_t via parameter @a event) with a set recursion + depth @a depth and context JSON value @a parsed. The return value of the + callback function is a boolean indicating whether the element that emitted + the callback shall be kept or not. + + We distinguish six scenarios (determined by the event type) in which the + callback function can be called. The following table describes the values + of the parameters @a depth, @a event, and @a parsed. + + parameter @a event | description | parameter @a depth | parameter @a parsed + ------------------ | ----------- | ------------------ | ------------------- + parse_event_t::object_start | the parser read `{` and started to process a JSON object | depth of the parent of the JSON object | a JSON value with type discarded + parse_event_t::key | the parser read a key of a value in an object | depth of the currently parsed JSON object | a JSON string containing the key + parse_event_t::object_end | the parser read `}` and finished processing a JSON object | depth of the parent of the JSON object | the parsed JSON object + parse_event_t::array_start | the parser read `[` and started to process a JSON array | depth of the parent of the JSON array | a JSON value with type discarded + parse_event_t::array_end | the parser read `]` and finished processing a JSON array | depth of the parent of the JSON array | the parsed JSON array + parse_event_t::value | the parser finished reading a JSON value | depth of the value | the parsed JSON value + + @image html callback_events.png "Example when certain parse events are triggered" + + Discarding a value (i.e., returning `false`) has different effects + depending on the context in which function was called: + + - Discarded values in structured types are skipped. That is, the parser + will behave as if the discarded value was never read. + - In case a value outside a structured type is skipped, it is replaced + with `null`. This case happens if the top-level element is skipped. + + @param[in] depth the depth of the recursion during parsing + + @param[in] event an event of type parse_event_t indicating the context in + the callback function has been called + + @param[in,out] parsed the current intermediate parse result; note that + writing to this value has no effect for parse_event_t::key events + + @return Whether the JSON value which called the function during parsing + should be kept (`true`) or not (`false`). In the latter case, it is either + skipped completely or replaced by an empty discarded object. + + @sa @ref parse for examples + + @since version 1.0.0 + */ + using parser_callback_t = typename parser::parser_callback_t; + + ////////////////// + // constructors // + ////////////////// + + /// @name constructors and destructors + /// Constructors of class @ref basic_json, copy/move constructor, copy + /// assignment, static functions creating objects, and the destructor. + /// @{ + + /*! + @brief create an empty value with a given type + + Create an empty JSON value with a given type. The value will be default + initialized with an empty value which depends on the type: + + Value type | initial value + ----------- | ------------- + null | `null` + boolean | `false` + string | `""` + number | `0` + object | `{}` + array | `[]` + + @param[in] v the type of the value to create + + @complexity Constant. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @liveexample{The following code shows the constructor for different @ref + value_t values,basic_json__value_t} + + @sa @ref clear() -- restores the postcondition of this constructor + + @since version 1.0.0 + */ + basic_json(const value_t v) + : m_type(v), m_value(v) + { + assert_invariant(); + } + + /*! + @brief create a null object + + Create a `null` JSON value. It either takes a null pointer as parameter + (explicitly creating `null`) or no parameter (implicitly creating `null`). + The passed null pointer itself is not read -- it is only used to choose + the right constructor. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this constructor never throws + exceptions. + + @liveexample{The following code shows the constructor with and without a + null pointer parameter.,basic_json__nullptr_t} + + @since version 1.0.0 + */ + basic_json(std::nullptr_t = nullptr) noexcept + : basic_json(value_t::null) + { + assert_invariant(); + } + + /*! + @brief create a JSON value + + This is a "catch all" constructor for all compatible JSON types; that is, + types for which a `to_json()` method exists. The constructor forwards the + parameter @a val to that method (to `json_serializer::to_json` method + with `U = uncvref_t`, to be exact). + + Template type @a CompatibleType includes, but is not limited to, the + following types: + - **arrays**: @ref array_t and all kinds of compatible containers such as + `std::vector`, `std::deque`, `std::list`, `std::forward_list`, + `std::array`, `std::valarray`, `std::set`, `std::unordered_set`, + `std::multiset`, and `std::unordered_multiset` with a `value_type` from + which a @ref basic_json value can be constructed. + - **objects**: @ref object_t and all kinds of compatible associative + containers such as `std::map`, `std::unordered_map`, `std::multimap`, + and `std::unordered_multimap` with a `key_type` compatible to + @ref string_t and a `value_type` from which a @ref basic_json value can + be constructed. + - **strings**: @ref string_t, string literals, and all compatible string + containers can be used. + - **numbers**: @ref number_integer_t, @ref number_unsigned_t, + @ref number_float_t, and all convertible number types such as `int`, + `size_t`, `int64_t`, `float` or `double` can be used. + - **boolean**: @ref boolean_t / `bool` can be used. + + See the examples below. + + @tparam CompatibleType a type such that: + - @a CompatibleType is not derived from `std::istream`, + - @a CompatibleType is not @ref basic_json (to avoid hijacking copy/move + constructors), + - @a CompatibleType is not a @ref basic_json nested type (e.g., + @ref json_pointer, @ref iterator, etc ...) + - @ref @ref json_serializer has a + `to_json(basic_json_t&, CompatibleType&&)` method + + @tparam U = `uncvref_t` + + @param[in] val the value to be forwarded to the respective constructor + + @complexity Usually linear in the size of the passed @a val, also + depending on the implementation of the called `to_json()` + method. + + @exceptionsafety Depends on the called constructor. For types directly + supported by the library (i.e., all types for which no `to_json()` function + was provided), strong guarantee holds: if an exception is thrown, there are + no changes to any JSON value. + + @liveexample{The following code shows the constructor with several + compatible types.,basic_json__CompatibleType} + + @since version 2.1.0 + */ + template, + detail::enable_if_t::value and + not std::is_same::value and + not detail::is_basic_json_nested_type< + basic_json_t, U>::value and + detail::has_to_json::value, + int> = 0> + basic_json(CompatibleType && val) noexcept(noexcept(JSONSerializer::to_json( + std::declval(), std::forward(val)))) + { + JSONSerializer::to_json(*this, std::forward(val)); + assert_invariant(); + } + + /*! + @brief create a container (array or object) from an initializer list + + Creates a JSON value of type array or object from the passed initializer + list @a init. In case @a type_deduction is `true` (default), the type of + the JSON value to be created is deducted from the initializer list @a init + according to the following rules: + + 1. If the list is empty, an empty JSON object value `{}` is created. + 2. If the list consists of pairs whose first element is a string, a JSON + object value is created where the first elements of the pairs are + treated as keys and the second elements are as values. + 3. In all other cases, an array is created. + + The rules aim to create the best fit between a C++ initializer list and + JSON values. The rationale is as follows: + + 1. The empty initializer list is written as `{}` which is exactly an empty + JSON object. + 2. C++ has no way of describing mapped types other than to list a list of + pairs. As JSON requires that keys must be of type string, rule 2 is the + weakest constraint one can pose on initializer lists to interpret them + as an object. + 3. In all other cases, the initializer list could not be interpreted as + JSON object type, so interpreting it as JSON array type is safe. + + With the rules described above, the following JSON values cannot be + expressed by an initializer list: + + - the empty array (`[]`): use @ref array(initializer_list_t) + with an empty initializer list in this case + - arrays whose elements satisfy rule 2: use @ref + array(initializer_list_t) with the same initializer list + in this case + + @note When used without parentheses around an empty initializer list, @ref + basic_json() is called instead of this function, yielding the JSON null + value. + + @param[in] init initializer list with JSON values + + @param[in] type_deduction internal parameter; when set to `true`, the type + of the JSON value is deducted from the initializer list @a init; when set + to `false`, the type provided via @a manual_type is forced. This mode is + used by the functions @ref array(initializer_list_t) and + @ref object(initializer_list_t). + + @param[in] manual_type internal parameter; when @a type_deduction is set + to `false`, the created JSON value will use the provided type (only @ref + value_t::array and @ref value_t::object are valid); when @a type_deduction + is set to `true`, this parameter has no effect + + @throw type_error.301 if @a type_deduction is `false`, @a manual_type is + `value_t::object`, but @a init contains an element which is not a pair + whose first element is a string. In this case, the constructor could not + create an object. If @a type_deduction would have be `true`, an array + would have been created. See @ref object(initializer_list_t) + for an example. + + @complexity Linear in the size of the initializer list @a init. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @liveexample{The example below shows how JSON values are created from + initializer lists.,basic_json__list_init_t} + + @sa @ref array(initializer_list_t) -- create a JSON array + value from an initializer list + @sa @ref object(initializer_list_t) -- create a JSON object + value from an initializer list + + @since version 1.0.0 + */ + basic_json(initializer_list_t init, + bool type_deduction = true, + value_t manual_type = value_t::array) + { + // check if each element is an array with two elements whose first + // element is a string + bool is_an_object = std::all_of(init.begin(), init.end(), + [](const detail::json_ref& element_ref) + { + return (element_ref->is_array() and element_ref->size() == 2 and (*element_ref)[0].is_string()); + }); + + // adjust type if type deduction is not wanted + if (not type_deduction) + { + // if array is wanted, do not create an object though possible + if (manual_type == value_t::array) + { + is_an_object = false; + } + + // if object is wanted but impossible, throw an exception + if (JSON_UNLIKELY(manual_type == value_t::object and not is_an_object)) + { + JSON_THROW(type_error::create(301, "cannot create object from initializer list")); + } + } + + if (is_an_object) + { + // the initializer list is a list of pairs -> create object + m_type = value_t::object; + m_value = value_t::object; + + std::for_each(init.begin(), init.end(), [this](const detail::json_ref& element_ref) + { + auto element = element_ref.moved_or_copied(); + m_value.object->emplace( + std::move(*((*element.m_value.array)[0].m_value.string)), + std::move((*element.m_value.array)[1])); + }); + } + else + { + // the initializer list describes an array -> create array + m_type = value_t::array; + m_value.array = create(init.begin(), init.end()); + } + + assert_invariant(); + } + + /*! + @brief explicitly create an array from an initializer list + + Creates a JSON array value from a given initializer list. That is, given a + list of values `a, b, c`, creates the JSON value `[a, b, c]`. If the + initializer list is empty, the empty array `[]` is created. + + @note This function is only needed to express two edge cases that cannot + be realized with the initializer list constructor (@ref + basic_json(initializer_list_t, bool, value_t)). These cases + are: + 1. creating an array whose elements are all pairs whose first element is a + string -- in this case, the initializer list constructor would create an + object, taking the first elements as keys + 2. creating an empty array -- passing the empty initializer list to the + initializer list constructor yields an empty object + + @param[in] init initializer list with JSON values to create an array from + (optional) + + @return JSON array value + + @complexity Linear in the size of @a init. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @liveexample{The following code shows an example for the `array` + function.,array} + + @sa @ref basic_json(initializer_list_t, bool, value_t) -- + create a JSON value from an initializer list + @sa @ref object(initializer_list_t) -- create a JSON object + value from an initializer list + + @since version 1.0.0 + */ + static basic_json array(initializer_list_t init = {}) + { + return basic_json(init, false, value_t::array); + } + + /*! + @brief explicitly create an object from an initializer list + + Creates a JSON object value from a given initializer list. The initializer + lists elements must be pairs, and their first elements must be strings. If + the initializer list is empty, the empty object `{}` is created. + + @note This function is only added for symmetry reasons. In contrast to the + related function @ref array(initializer_list_t), there are + no cases which can only be expressed by this function. That is, any + initializer list @a init can also be passed to the initializer list + constructor @ref basic_json(initializer_list_t, bool, value_t). + + @param[in] init initializer list to create an object from (optional) + + @return JSON object value + + @throw type_error.301 if @a init is not a list of pairs whose first + elements are strings. In this case, no object can be created. When such a + value is passed to @ref basic_json(initializer_list_t, bool, value_t), + an array would have been created from the passed initializer list @a init. + See example below. + + @complexity Linear in the size of @a init. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @liveexample{The following code shows an example for the `object` + function.,object} + + @sa @ref basic_json(initializer_list_t, bool, value_t) -- + create a JSON value from an initializer list + @sa @ref array(initializer_list_t) -- create a JSON array + value from an initializer list + + @since version 1.0.0 + */ + static basic_json object(initializer_list_t init = {}) + { + return basic_json(init, false, value_t::object); + } + + /*! + @brief construct an array with count copies of given value + + Constructs a JSON array value by creating @a cnt copies of a passed value. + In case @a cnt is `0`, an empty array is created. + + @param[in] cnt the number of JSON copies of @a val to create + @param[in] val the JSON value to copy + + @post `std::distance(begin(),end()) == cnt` holds. + + @complexity Linear in @a cnt. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @liveexample{The following code shows examples for the @ref + basic_json(size_type\, const basic_json&) + constructor.,basic_json__size_type_basic_json} + + @since version 1.0.0 + */ + basic_json(size_type cnt, const basic_json& val) + : m_type(value_t::array) + { + m_value.array = create(cnt, val); + assert_invariant(); + } + + /*! + @brief construct a JSON container given an iterator range + + Constructs the JSON value with the contents of the range `[first, last)`. + The semantics depends on the different types a JSON value can have: + - In case of a null type, invalid_iterator.206 is thrown. + - In case of other primitive types (number, boolean, or string), @a first + must be `begin()` and @a last must be `end()`. In this case, the value is + copied. Otherwise, invalid_iterator.204 is thrown. + - In case of structured types (array, object), the constructor behaves as + similar versions for `std::vector` or `std::map`; that is, a JSON array + or object is constructed from the values in the range. + + @tparam InputIT an input iterator type (@ref iterator or @ref + const_iterator) + + @param[in] first begin of the range to copy from (included) + @param[in] last end of the range to copy from (excluded) + + @pre Iterators @a first and @a last must be initialized. **This + precondition is enforced with an assertion (see warning).** If + assertions are switched off, a violation of this precondition yields + undefined behavior. + + @pre Range `[first, last)` is valid. Usually, this precondition cannot be + checked efficiently. Only certain edge cases are detected; see the + description of the exceptions below. A violation of this precondition + yields undefined behavior. + + @warning A precondition is enforced with a runtime assertion that will + result in calling `std::abort` if this precondition is not met. + Assertions can be disabled by defining `NDEBUG` at compile time. + See http://en.cppreference.com/w/cpp/error/assert for more + information. + + @throw invalid_iterator.201 if iterators @a first and @a last are not + compatible (i.e., do not belong to the same JSON value). In this case, + the range `[first, last)` is undefined. + @throw invalid_iterator.204 if iterators @a first and @a last belong to a + primitive type (number, boolean, or string), but @a first does not point + to the first element any more. In this case, the range `[first, last)` is + undefined. See example code below. + @throw invalid_iterator.206 if iterators @a first and @a last belong to a + null value. In this case, the range `[first, last)` is undefined. + + @complexity Linear in distance between @a first and @a last. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @liveexample{The example below shows several ways to create JSON values by + specifying a subrange with iterators.,basic_json__InputIt_InputIt} + + @since version 1.0.0 + */ + template::value or + std::is_same::value, int>::type = 0> + basic_json(InputIT first, InputIT last) + { + assert(first.m_object != nullptr); + assert(last.m_object != nullptr); + + // make sure iterator fits the current value + if (JSON_UNLIKELY(first.m_object != last.m_object)) + { + JSON_THROW(invalid_iterator::create(201, "iterators are not compatible")); + } + + // copy type from first iterator + m_type = first.m_object->m_type; + + // check if iterator range is complete for primitive values + switch (m_type) + { + case value_t::boolean: + case value_t::number_float: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::string: + { + if (JSON_UNLIKELY(not first.m_it.primitive_iterator.is_begin() + or not last.m_it.primitive_iterator.is_end())) + { + JSON_THROW(invalid_iterator::create(204, "iterators out of range")); + } + break; + } + + default: + break; + } + + switch (m_type) + { + case value_t::number_integer: + { + m_value.number_integer = first.m_object->m_value.number_integer; + break; + } + + case value_t::number_unsigned: + { + m_value.number_unsigned = first.m_object->m_value.number_unsigned; + break; + } + + case value_t::number_float: + { + m_value.number_float = first.m_object->m_value.number_float; + break; + } + + case value_t::boolean: + { + m_value.boolean = first.m_object->m_value.boolean; + break; + } + + case value_t::string: + { + m_value = *first.m_object->m_value.string; + break; + } + + case value_t::object: + { + m_value.object = create(first.m_it.object_iterator, + last.m_it.object_iterator); + break; + } + + case value_t::array: + { + m_value.array = create(first.m_it.array_iterator, + last.m_it.array_iterator); + break; + } + + default: + JSON_THROW(invalid_iterator::create(206, "cannot construct with iterators from " + + std::string(first.m_object->type_name()))); + } + + assert_invariant(); + } + + /////////////////////////////////////// + // other constructors and destructor // + /////////////////////////////////////// + + /// @private + basic_json(const detail::json_ref& ref) + : basic_json(ref.moved_or_copied()) + {} + + /*! + @brief copy constructor + + Creates a copy of a given JSON value. + + @param[in] other the JSON value to copy + + @post `*this == other` + + @complexity Linear in the size of @a other. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is linear. + - As postcondition, it holds: `other == basic_json(other)`. + + @liveexample{The following code shows an example for the copy + constructor.,basic_json__basic_json} + + @since version 1.0.0 + */ + basic_json(const basic_json& other) + : m_type(other.m_type) + { + // check of passed value is valid + other.assert_invariant(); + + switch (m_type) + { + case value_t::object: + { + m_value = *other.m_value.object; + break; + } + + case value_t::array: + { + m_value = *other.m_value.array; + break; + } + + case value_t::string: + { + m_value = *other.m_value.string; + break; + } + + case value_t::boolean: + { + m_value = other.m_value.boolean; + break; + } + + case value_t::number_integer: + { + m_value = other.m_value.number_integer; + break; + } + + case value_t::number_unsigned: + { + m_value = other.m_value.number_unsigned; + break; + } + + case value_t::number_float: + { + m_value = other.m_value.number_float; + break; + } + + default: + break; + } + + assert_invariant(); + } + + /*! + @brief move constructor + + Move constructor. Constructs a JSON value with the contents of the given + value @a other using move semantics. It "steals" the resources from @a + other and leaves it as JSON null value. + + @param[in,out] other value to move to this object + + @post `*this` has the same value as @a other before the call. + @post @a other is a JSON null value. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this constructor never throws + exceptions. + + @requirement This function helps `basic_json` satisfying the + [MoveConstructible](http://en.cppreference.com/w/cpp/concept/MoveConstructible) + requirements. + + @liveexample{The code below shows the move constructor explicitly called + via std::move.,basic_json__moveconstructor} + + @since version 1.0.0 + */ + basic_json(basic_json&& other) noexcept + : m_type(std::move(other.m_type)), + m_value(std::move(other.m_value)) + { + // check that passed value is valid + other.assert_invariant(); + + // invalidate payload + other.m_type = value_t::null; + other.m_value = {}; + + assert_invariant(); + } + + /*! + @brief copy assignment + + Copy assignment operator. Copies a JSON value via the "copy and swap" + strategy: It is expressed in terms of the copy constructor, destructor, + and the `swap()` member function. + + @param[in] other value to copy from + + @complexity Linear. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is linear. + + @liveexample{The code below shows and example for the copy assignment. It + creates a copy of value `a` which is then swapped with `b`. Finally\, the + copy of `a` (which is the null value after the swap) is + destroyed.,basic_json__copyassignment} + + @since version 1.0.0 + */ + reference& operator=(basic_json other) noexcept ( + std::is_nothrow_move_constructible::value and + std::is_nothrow_move_assignable::value and + std::is_nothrow_move_constructible::value and + std::is_nothrow_move_assignable::value + ) + { + // check that passed value is valid + other.assert_invariant(); + + using std::swap; + swap(m_type, other.m_type); + swap(m_value, other.m_value); + + assert_invariant(); + return *this; + } + + /*! + @brief destructor + + Destroys the JSON value and frees all allocated memory. + + @complexity Linear. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is linear. + - All stored elements are destroyed and all memory is freed. + + @since version 1.0.0 + */ + ~basic_json() + { + assert_invariant(); + m_value.destroy(m_type); + } + + /// @} + + public: + /////////////////////// + // object inspection // + /////////////////////// + + /// @name object inspection + /// Functions to inspect the type of a JSON value. + /// @{ + + /*! + @brief serialization + + Serialization function for JSON values. The function tries to mimic + Python's `json.dumps()` function, and currently supports its @a indent + and @a ensure_ascii parameters. + + @param[in] indent If indent is nonnegative, then array elements and object + members will be pretty-printed with that indent level. An indent level of + `0` will only insert newlines. `-1` (the default) selects the most compact + representation. + @param[in] indent_char The character to use for indentation if @a indent is + greater than `0`. The default is ` ` (space). + @param[in] ensure_ascii If @a ensure_ascii is true, all non-ASCII characters + in the output are escaped with `\uXXXX` sequences, and the result consists + of ASCII characters only. + + @return string containing the serialization of the JSON value + + @throw type_error.316 if a string stored inside the JSON value is not + UTF-8 encoded + + @complexity Linear. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @liveexample{The following example shows the effect of different @a indent\, + @a indent_char\, and @a ensure_ascii parameters to the result of the + serialization.,dump} + + @see https://docs.python.org/2/library/json.html#json.dump + + @since version 1.0.0; indentation character @a indent_char, option + @a ensure_ascii and exceptions added in version 3.0.0 + */ + string_t dump(const int indent = -1, const char indent_char = ' ', + const bool ensure_ascii = false) const + { + string_t result; + serializer s(detail::output_adapter(result), indent_char); + + if (indent >= 0) + { + s.dump(*this, true, ensure_ascii, static_cast(indent)); + } + else + { + s.dump(*this, false, ensure_ascii, 0); + } + + return result; + } + + /*! + @brief return the type of the JSON value (explicit) + + Return the type of the JSON value as a value from the @ref value_t + enumeration. + + @return the type of the JSON value + Value type | return value + ------------------------- | ------------------------- + null | value_t::null + boolean | value_t::boolean + string | value_t::string + number (integer) | value_t::number_integer + number (unsigned integer) | value_t::number_unsigned + number (floating-point) | value_t::number_float + object | value_t::object + array | value_t::array + discarded | value_t::discarded + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `type()` for all JSON + types.,type} + + @sa @ref operator value_t() -- return the type of the JSON value (implicit) + @sa @ref type_name() -- return the type as string + + @since version 1.0.0 + */ + constexpr value_t type() const noexcept + { + return m_type; + } + + /*! + @brief return whether type is primitive + + This function returns true if and only if the JSON type is primitive + (string, number, boolean, or null). + + @return `true` if type is primitive (string, number, boolean, or null), + `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_primitive()` for all JSON + types.,is_primitive} + + @sa @ref is_structured() -- returns whether JSON value is structured + @sa @ref is_null() -- returns whether JSON value is `null` + @sa @ref is_string() -- returns whether JSON value is a string + @sa @ref is_boolean() -- returns whether JSON value is a boolean + @sa @ref is_number() -- returns whether JSON value is a number + + @since version 1.0.0 + */ + constexpr bool is_primitive() const noexcept + { + return is_null() or is_string() or is_boolean() or is_number(); + } + + /*! + @brief return whether type is structured + + This function returns true if and only if the JSON type is structured + (array or object). + + @return `true` if type is structured (array or object), `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_structured()` for all JSON + types.,is_structured} + + @sa @ref is_primitive() -- returns whether value is primitive + @sa @ref is_array() -- returns whether value is an array + @sa @ref is_object() -- returns whether value is an object + + @since version 1.0.0 + */ + constexpr bool is_structured() const noexcept + { + return is_array() or is_object(); + } + + /*! + @brief return whether value is null + + This function returns true if and only if the JSON value is null. + + @return `true` if type is null, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_null()` for all JSON + types.,is_null} + + @since version 1.0.0 + */ + constexpr bool is_null() const noexcept + { + return (m_type == value_t::null); + } + + /*! + @brief return whether value is a boolean + + This function returns true if and only if the JSON value is a boolean. + + @return `true` if type is boolean, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_boolean()` for all JSON + types.,is_boolean} + + @since version 1.0.0 + */ + constexpr bool is_boolean() const noexcept + { + return (m_type == value_t::boolean); + } + + /*! + @brief return whether value is a number + + This function returns true if and only if the JSON value is a number. This + includes both integer (signed and unsigned) and floating-point values. + + @return `true` if type is number (regardless whether integer, unsigned + integer or floating-type), `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_number()` for all JSON + types.,is_number} + + @sa @ref is_number_integer() -- check if value is an integer or unsigned + integer number + @sa @ref is_number_unsigned() -- check if value is an unsigned integer + number + @sa @ref is_number_float() -- check if value is a floating-point number + + @since version 1.0.0 + */ + constexpr bool is_number() const noexcept + { + return is_number_integer() or is_number_float(); + } + + /*! + @brief return whether value is an integer number + + This function returns true if and only if the JSON value is a signed or + unsigned integer number. This excludes floating-point values. + + @return `true` if type is an integer or unsigned integer number, `false` + otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_number_integer()` for all + JSON types.,is_number_integer} + + @sa @ref is_number() -- check if value is a number + @sa @ref is_number_unsigned() -- check if value is an unsigned integer + number + @sa @ref is_number_float() -- check if value is a floating-point number + + @since version 1.0.0 + */ + constexpr bool is_number_integer() const noexcept + { + return (m_type == value_t::number_integer or m_type == value_t::number_unsigned); + } + + /*! + @brief return whether value is an unsigned integer number + + This function returns true if and only if the JSON value is an unsigned + integer number. This excludes floating-point and signed integer values. + + @return `true` if type is an unsigned integer number, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_number_unsigned()` for all + JSON types.,is_number_unsigned} + + @sa @ref is_number() -- check if value is a number + @sa @ref is_number_integer() -- check if value is an integer or unsigned + integer number + @sa @ref is_number_float() -- check if value is a floating-point number + + @since version 2.0.0 + */ + constexpr bool is_number_unsigned() const noexcept + { + return (m_type == value_t::number_unsigned); + } + + /*! + @brief return whether value is a floating-point number + + This function returns true if and only if the JSON value is a + floating-point number. This excludes signed and unsigned integer values. + + @return `true` if type is a floating-point number, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_number_float()` for all + JSON types.,is_number_float} + + @sa @ref is_number() -- check if value is number + @sa @ref is_number_integer() -- check if value is an integer number + @sa @ref is_number_unsigned() -- check if value is an unsigned integer + number + + @since version 1.0.0 + */ + constexpr bool is_number_float() const noexcept + { + return (m_type == value_t::number_float); + } + + /*! + @brief return whether value is an object + + This function returns true if and only if the JSON value is an object. + + @return `true` if type is object, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_object()` for all JSON + types.,is_object} + + @since version 1.0.0 + */ + constexpr bool is_object() const noexcept + { + return (m_type == value_t::object); + } + + /*! + @brief return whether value is an array + + This function returns true if and only if the JSON value is an array. + + @return `true` if type is array, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_array()` for all JSON + types.,is_array} + + @since version 1.0.0 + */ + constexpr bool is_array() const noexcept + { + return (m_type == value_t::array); + } + + /*! + @brief return whether value is a string + + This function returns true if and only if the JSON value is a string. + + @return `true` if type is string, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_string()` for all JSON + types.,is_string} + + @since version 1.0.0 + */ + constexpr bool is_string() const noexcept + { + return (m_type == value_t::string); + } + + /*! + @brief return whether value is discarded + + This function returns true if and only if the JSON value was discarded + during parsing with a callback function (see @ref parser_callback_t). + + @note This function will always be `false` for JSON values after parsing. + That is, discarded values can only occur during parsing, but will be + removed when inside a structured value or replaced by null in other cases. + + @return `true` if type is discarded, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_discarded()` for all JSON + types.,is_discarded} + + @since version 1.0.0 + */ + constexpr bool is_discarded() const noexcept + { + return (m_type == value_t::discarded); + } + + /*! + @brief return the type of the JSON value (implicit) + + Implicitly return the type of the JSON value as a value from the @ref + value_t enumeration. + + @return the type of the JSON value + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies the @ref value_t operator for + all JSON types.,operator__value_t} + + @sa @ref type() -- return the type of the JSON value (explicit) + @sa @ref type_name() -- return the type as string + + @since version 1.0.0 + */ + constexpr operator value_t() const noexcept + { + return m_type; + } + + /// @} + + private: + ////////////////// + // value access // + ////////////////// + + /// get a boolean (explicit) + boolean_t get_impl(boolean_t* /*unused*/) const + { + if (JSON_LIKELY(is_boolean())) + { + return m_value.boolean; + } + + JSON_THROW(type_error::create(302, "type must be boolean, but is " + std::string(type_name()))); + } + + /// get a pointer to the value (object) + object_t* get_impl_ptr(object_t* /*unused*/) noexcept + { + return is_object() ? m_value.object : nullptr; + } + + /// get a pointer to the value (object) + constexpr const object_t* get_impl_ptr(const object_t* /*unused*/) const noexcept + { + return is_object() ? m_value.object : nullptr; + } + + /// get a pointer to the value (array) + array_t* get_impl_ptr(array_t* /*unused*/) noexcept + { + return is_array() ? m_value.array : nullptr; + } + + /// get a pointer to the value (array) + constexpr const array_t* get_impl_ptr(const array_t* /*unused*/) const noexcept + { + return is_array() ? m_value.array : nullptr; + } + + /// get a pointer to the value (string) + string_t* get_impl_ptr(string_t* /*unused*/) noexcept + { + return is_string() ? m_value.string : nullptr; + } + + /// get a pointer to the value (string) + constexpr const string_t* get_impl_ptr(const string_t* /*unused*/) const noexcept + { + return is_string() ? m_value.string : nullptr; + } + + /// get a pointer to the value (boolean) + boolean_t* get_impl_ptr(boolean_t* /*unused*/) noexcept + { + return is_boolean() ? &m_value.boolean : nullptr; + } + + /// get a pointer to the value (boolean) + constexpr const boolean_t* get_impl_ptr(const boolean_t* /*unused*/) const noexcept + { + return is_boolean() ? &m_value.boolean : nullptr; + } + + /// get a pointer to the value (integer number) + number_integer_t* get_impl_ptr(number_integer_t* /*unused*/) noexcept + { + return is_number_integer() ? &m_value.number_integer : nullptr; + } + + /// get a pointer to the value (integer number) + constexpr const number_integer_t* get_impl_ptr(const number_integer_t* /*unused*/) const noexcept + { + return is_number_integer() ? &m_value.number_integer : nullptr; + } + + /// get a pointer to the value (unsigned number) + number_unsigned_t* get_impl_ptr(number_unsigned_t* /*unused*/) noexcept + { + return is_number_unsigned() ? &m_value.number_unsigned : nullptr; + } + + /// get a pointer to the value (unsigned number) + constexpr const number_unsigned_t* get_impl_ptr(const number_unsigned_t* /*unused*/) const noexcept + { + return is_number_unsigned() ? &m_value.number_unsigned : nullptr; + } + + /// get a pointer to the value (floating-point number) + number_float_t* get_impl_ptr(number_float_t* /*unused*/) noexcept + { + return is_number_float() ? &m_value.number_float : nullptr; + } + + /// get a pointer to the value (floating-point number) + constexpr const number_float_t* get_impl_ptr(const number_float_t* /*unused*/) const noexcept + { + return is_number_float() ? &m_value.number_float : nullptr; + } + + /*! + @brief helper function to implement get_ref() + + This function helps to implement get_ref() without code duplication for + const and non-const overloads + + @tparam ThisType will be deduced as `basic_json` or `const basic_json` + + @throw type_error.303 if ReferenceType does not match underlying value + type of the current JSON + */ + template + static ReferenceType get_ref_impl(ThisType& obj) + { + // delegate the call to get_ptr<>() + auto ptr = obj.template get_ptr::type>(); + + if (JSON_LIKELY(ptr != nullptr)) + { + return *ptr; + } + + JSON_THROW(type_error::create(303, "incompatible ReferenceType for get_ref, actual type is " + std::string(obj.type_name()))); + } + + public: + /// @name value access + /// Direct access to the stored value of a JSON value. + /// @{ + + /*! + @brief get special-case overload + + This overloads avoids a lot of template boilerplate, it can be seen as the + identity method + + @tparam BasicJsonType == @ref basic_json + + @return a copy of *this + + @complexity Constant. + + @since version 2.1.0 + */ + template::type, basic_json_t>::value, + int> = 0> + basic_json get() const + { + return *this; + } + + /*! + @brief get a value (explicit) + + Explicit type conversion between the JSON value and a compatible value + which is [CopyConstructible](http://en.cppreference.com/w/cpp/concept/CopyConstructible) + and [DefaultConstructible](http://en.cppreference.com/w/cpp/concept/DefaultConstructible). + The value is converted by calling the @ref json_serializer + `from_json()` method. + + The function is equivalent to executing + @code {.cpp} + ValueType ret; + JSONSerializer::from_json(*this, ret); + return ret; + @endcode + + This overloads is chosen if: + - @a ValueType is not @ref basic_json, + - @ref json_serializer has a `from_json()` method of the form + `void from_json(const basic_json&, ValueType&)`, and + - @ref json_serializer does not have a `from_json()` method of + the form `ValueType from_json(const basic_json&)` + + @tparam ValueTypeCV the provided value type + @tparam ValueType the returned value type + + @return copy of the JSON value, converted to @a ValueType + + @throw what @ref json_serializer `from_json()` method throws + + @liveexample{The example below shows several conversions from JSON values + to other types. There a few things to note: (1) Floating-point numbers can + be converted to integers\, (2) A JSON array can be converted to a standard + `std::vector`\, (3) A JSON object can be converted to C++ + associative containers such as `std::unordered_map`.,get__ValueType_const} + + @since version 2.1.0 + */ + template, + detail::enable_if_t < + not std::is_same::value and + detail::has_from_json::value and + not detail::has_non_default_from_json::value, + int> = 0> + ValueType get() const noexcept(noexcept( + JSONSerializer::from_json(std::declval(), std::declval()))) + { + // we cannot static_assert on ValueTypeCV being non-const, because + // there is support for get(), which is why we + // still need the uncvref + static_assert(not std::is_reference::value, + "get() cannot be used with reference types, you might want to use get_ref()"); + static_assert(std::is_default_constructible::value, + "types must be DefaultConstructible when used with get()"); + + ValueType ret; + JSONSerializer::from_json(*this, ret); + return ret; + } + + /*! + @brief get a value (explicit); special case + + Explicit type conversion between the JSON value and a compatible value + which is **not** [CopyConstructible](http://en.cppreference.com/w/cpp/concept/CopyConstructible) + and **not** [DefaultConstructible](http://en.cppreference.com/w/cpp/concept/DefaultConstructible). + The value is converted by calling the @ref json_serializer + `from_json()` method. + + The function is equivalent to executing + @code {.cpp} + return JSONSerializer::from_json(*this); + @endcode + + This overloads is chosen if: + - @a ValueType is not @ref basic_json and + - @ref json_serializer has a `from_json()` method of the form + `ValueType from_json(const basic_json&)` + + @note If @ref json_serializer has both overloads of + `from_json()`, this one is chosen. + + @tparam ValueTypeCV the provided value type + @tparam ValueType the returned value type + + @return copy of the JSON value, converted to @a ValueType + + @throw what @ref json_serializer `from_json()` method throws + + @since version 2.1.0 + */ + template, + detail::enable_if_t::value and + detail::has_non_default_from_json::value, + int> = 0> + ValueType get() const noexcept(noexcept( + JSONSerializer::from_json(std::declval()))) + { + static_assert(not std::is_reference::value, + "get() cannot be used with reference types, you might want to use get_ref()"); + return JSONSerializer::from_json(*this); + } + + /*! + @brief get a pointer value (explicit) + + Explicit pointer access to the internally stored JSON value. No copies are + made. + + @warning The pointer becomes invalid if the underlying JSON object + changes. + + @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref + object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, + @ref number_unsigned_t, or @ref number_float_t. + + @return pointer to the internally stored JSON value if the requested + pointer type @a PointerType fits to the JSON value; `nullptr` otherwise + + @complexity Constant. + + @liveexample{The example below shows how pointers to internal values of a + JSON value can be requested. Note that no type conversions are made and a + `nullptr` is returned if the value and the requested pointer type does not + match.,get__PointerType} + + @sa @ref get_ptr() for explicit pointer-member access + + @since version 1.0.0 + */ + template::value, int>::type = 0> + PointerType get() noexcept + { + // delegate the call to get_ptr + return get_ptr(); + } + + /*! + @brief get a pointer value (explicit) + @copydoc get() + */ + template::value, int>::type = 0> + constexpr const PointerType get() const noexcept + { + // delegate the call to get_ptr + return get_ptr(); + } + + /*! + @brief get a pointer value (implicit) + + Implicit pointer access to the internally stored JSON value. No copies are + made. + + @warning Writing data to the pointee of the result yields an undefined + state. + + @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref + object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, + @ref number_unsigned_t, or @ref number_float_t. Enforced by a static + assertion. + + @return pointer to the internally stored JSON value if the requested + pointer type @a PointerType fits to the JSON value; `nullptr` otherwise + + @complexity Constant. + + @liveexample{The example below shows how pointers to internal values of a + JSON value can be requested. Note that no type conversions are made and a + `nullptr` is returned if the value and the requested pointer type does not + match.,get_ptr} + + @since version 1.0.0 + */ + template::value, int>::type = 0> + PointerType get_ptr() noexcept + { + // get the type of the PointerType (remove pointer and const) + using pointee_t = typename std::remove_const::type>::type>::type; + // make sure the type matches the allowed types + static_assert( + std::is_same::value + or std::is_same::value + or std::is_same::value + or std::is_same::value + or std::is_same::value + or std::is_same::value + or std::is_same::value + , "incompatible pointer type"); + + // delegate the call to get_impl_ptr<>() + return get_impl_ptr(static_cast(nullptr)); + } + + /*! + @brief get a pointer value (implicit) + @copydoc get_ptr() + */ + template::value and + std::is_const::type>::value, int>::type = 0> + constexpr const PointerType get_ptr() const noexcept + { + // get the type of the PointerType (remove pointer and const) + using pointee_t = typename std::remove_const::type>::type>::type; + // make sure the type matches the allowed types + static_assert( + std::is_same::value + or std::is_same::value + or std::is_same::value + or std::is_same::value + or std::is_same::value + or std::is_same::value + or std::is_same::value + , "incompatible pointer type"); + + // delegate the call to get_impl_ptr<>() const + return get_impl_ptr(static_cast(nullptr)); + } + + /*! + @brief get a reference value (implicit) + + Implicit reference access to the internally stored JSON value. No copies + are made. + + @warning Writing data to the referee of the result yields an undefined + state. + + @tparam ReferenceType reference type; must be a reference to @ref array_t, + @ref object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, or + @ref number_float_t. Enforced by static assertion. + + @return reference to the internally stored JSON value if the requested + reference type @a ReferenceType fits to the JSON value; throws + type_error.303 otherwise + + @throw type_error.303 in case passed type @a ReferenceType is incompatible + with the stored JSON value; see example below + + @complexity Constant. + + @liveexample{The example shows several calls to `get_ref()`.,get_ref} + + @since version 1.1.0 + */ + template::value, int>::type = 0> + ReferenceType get_ref() + { + // delegate call to get_ref_impl + return get_ref_impl(*this); + } + + /*! + @brief get a reference value (implicit) + @copydoc get_ref() + */ + template::value and + std::is_const::type>::value, int>::type = 0> + ReferenceType get_ref() const + { + // delegate call to get_ref_impl + return get_ref_impl(*this); + } + + /*! + @brief get a value (implicit) + + Implicit type conversion between the JSON value and a compatible value. + The call is realized by calling @ref get() const. + + @tparam ValueType non-pointer type compatible to the JSON value, for + instance `int` for JSON integer numbers, `bool` for JSON booleans, or + `std::vector` types for JSON arrays. The character type of @ref string_t + as well as an initializer list of this type is excluded to avoid + ambiguities as these types implicitly convert to `std::string`. + + @return copy of the JSON value, converted to type @a ValueType + + @throw type_error.302 in case passed type @a ValueType is incompatible + to the JSON value type (e.g., the JSON value is of type boolean, but a + string is requested); see example below + + @complexity Linear in the size of the JSON value. + + @liveexample{The example below shows several conversions from JSON values + to other types. There a few things to note: (1) Floating-point numbers can + be converted to integers\, (2) A JSON array can be converted to a standard + `std::vector`\, (3) A JSON object can be converted to C++ + associative containers such as `std::unordered_map`.,operator__ValueType} + + @since version 1.0.0 + */ + template < typename ValueType, typename std::enable_if < + not std::is_pointer::value and + not std::is_same>::value and + not std::is_same::value +#ifndef _MSC_VER // fix for issue #167 operator<< ambiguity under VS2015 + and not std::is_same>::value +#endif +#if defined(JSON_HAS_CPP_17) + and not std::is_same::value +#endif + , int >::type = 0 > + operator ValueType() const + { + // delegate the call to get<>() const + return get(); + } + + /// @} + + //////////////////// + // element access // + //////////////////// + + /// @name element access + /// Access to the JSON value. + /// @{ + + /*! + @brief access specified array element with bounds checking + + Returns a reference to the element at specified location @a idx, with + bounds checking. + + @param[in] idx index of the element to access + + @return reference to the element at index @a idx + + @throw type_error.304 if the JSON value is not an array; in this case, + calling `at` with an index makes no sense. See example below. + @throw out_of_range.401 if the index @a idx is out of range of the array; + that is, `idx >= size()`. See example below. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Constant. + + @since version 1.0.0 + + @liveexample{The example below shows how array elements can be read and + written using `at()`. It also demonstrates the different exceptions that + can be thrown.,at__size_type} + */ + reference at(size_type idx) + { + // at only works for arrays + if (JSON_LIKELY(is_array())) + { + JSON_TRY + { + return m_value.array->at(idx); + } + JSON_CATCH (std::out_of_range&) + { + // create better exception explanation + JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range")); + } + } + else + { + JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name()))); + } + } + + /*! + @brief access specified array element with bounds checking + + Returns a const reference to the element at specified location @a idx, + with bounds checking. + + @param[in] idx index of the element to access + + @return const reference to the element at index @a idx + + @throw type_error.304 if the JSON value is not an array; in this case, + calling `at` with an index makes no sense. See example below. + @throw out_of_range.401 if the index @a idx is out of range of the array; + that is, `idx >= size()`. See example below. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Constant. + + @since version 1.0.0 + + @liveexample{The example below shows how array elements can be read using + `at()`. It also demonstrates the different exceptions that can be thrown., + at__size_type_const} + */ + const_reference at(size_type idx) const + { + // at only works for arrays + if (JSON_LIKELY(is_array())) + { + JSON_TRY + { + return m_value.array->at(idx); + } + JSON_CATCH (std::out_of_range&) + { + // create better exception explanation + JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range")); + } + } + else + { + JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name()))); + } + } + + /*! + @brief access specified object element with bounds checking + + Returns a reference to the element at with specified key @a key, with + bounds checking. + + @param[in] key key of the element to access + + @return reference to the element at key @a key + + @throw type_error.304 if the JSON value is not an object; in this case, + calling `at` with a key makes no sense. See example below. + @throw out_of_range.403 if the key @a key is is not stored in the object; + that is, `find(key) == end()`. See example below. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Logarithmic in the size of the container. + + @sa @ref operator[](const typename object_t::key_type&) for unchecked + access by reference + @sa @ref value() for access by value with a default value + + @since version 1.0.0 + + @liveexample{The example below shows how object elements can be read and + written using `at()`. It also demonstrates the different exceptions that + can be thrown.,at__object_t_key_type} + */ + reference at(const typename object_t::key_type& key) + { + // at only works for objects + if (JSON_LIKELY(is_object())) + { + JSON_TRY + { + return m_value.object->at(key); + } + JSON_CATCH (std::out_of_range&) + { + // create better exception explanation + JSON_THROW(out_of_range::create(403, "key '" + key + "' not found")); + } + } + else + { + JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name()))); + } + } + + /*! + @brief access specified object element with bounds checking + + Returns a const reference to the element at with specified key @a key, + with bounds checking. + + @param[in] key key of the element to access + + @return const reference to the element at key @a key + + @throw type_error.304 if the JSON value is not an object; in this case, + calling `at` with a key makes no sense. See example below. + @throw out_of_range.403 if the key @a key is is not stored in the object; + that is, `find(key) == end()`. See example below. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Logarithmic in the size of the container. + + @sa @ref operator[](const typename object_t::key_type&) for unchecked + access by reference + @sa @ref value() for access by value with a default value + + @since version 1.0.0 + + @liveexample{The example below shows how object elements can be read using + `at()`. It also demonstrates the different exceptions that can be thrown., + at__object_t_key_type_const} + */ + const_reference at(const typename object_t::key_type& key) const + { + // at only works for objects + if (JSON_LIKELY(is_object())) + { + JSON_TRY + { + return m_value.object->at(key); + } + JSON_CATCH (std::out_of_range&) + { + // create better exception explanation + JSON_THROW(out_of_range::create(403, "key '" + key + "' not found")); + } + } + else + { + JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name()))); + } + } + + /*! + @brief access specified array element + + Returns a reference to the element at specified location @a idx. + + @note If @a idx is beyond the range of the array (i.e., `idx >= size()`), + then the array is silently filled up with `null` values to make `idx` a + valid reference to the last stored element. + + @param[in] idx index of the element to access + + @return reference to the element at index @a idx + + @throw type_error.305 if the JSON value is not an array or null; in that + cases, using the [] operator with an index makes no sense. + + @complexity Constant if @a idx is in the range of the array. Otherwise + linear in `idx - size()`. + + @liveexample{The example below shows how array elements can be read and + written using `[]` operator. Note the addition of `null` + values.,operatorarray__size_type} + + @since version 1.0.0 + */ + reference operator[](size_type idx) + { + // implicitly convert null value to an empty array + if (is_null()) + { + m_type = value_t::array; + m_value.array = create(); + assert_invariant(); + } + + // operator[] only works for arrays + if (JSON_LIKELY(is_array())) + { + // fill up array with null values if given idx is outside range + if (idx >= m_value.array->size()) + { + m_value.array->insert(m_value.array->end(), + idx - m_value.array->size() + 1, + basic_json()); + } + + return m_value.array->operator[](idx); + } + + JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); + } + + /*! + @brief access specified array element + + Returns a const reference to the element at specified location @a idx. + + @param[in] idx index of the element to access + + @return const reference to the element at index @a idx + + @throw type_error.305 if the JSON value is not an array; in that case, + using the [] operator with an index makes no sense. + + @complexity Constant. + + @liveexample{The example below shows how array elements can be read using + the `[]` operator.,operatorarray__size_type_const} + + @since version 1.0.0 + */ + const_reference operator[](size_type idx) const + { + // const operator[] only works for arrays + if (JSON_LIKELY(is_array())) + { + return m_value.array->operator[](idx); + } + + JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); + } + + /*! + @brief access specified object element + + Returns a reference to the element at with specified key @a key. + + @note If @a key is not found in the object, then it is silently added to + the object and filled with a `null` value to make `key` a valid reference. + In case the value was `null` before, it is converted to an object. + + @param[in] key key of the element to access + + @return reference to the element at key @a key + + @throw type_error.305 if the JSON value is not an object or null; in that + cases, using the [] operator with a key makes no sense. + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read and + written using the `[]` operator.,operatorarray__key_type} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value + + @since version 1.0.0 + */ + reference operator[](const typename object_t::key_type& key) + { + // implicitly convert null value to an empty object + if (is_null()) + { + m_type = value_t::object; + m_value.object = create(); + assert_invariant(); + } + + // operator[] only works for objects + if (JSON_LIKELY(is_object())) + { + return m_value.object->operator[](key); + } + + JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); + } + + /*! + @brief read-only access specified object element + + Returns a const reference to the element at with specified key @a key. No + bounds checking is performed. + + @warning If the element with key @a key does not exist, the behavior is + undefined. + + @param[in] key key of the element to access + + @return const reference to the element at key @a key + + @pre The element with key @a key must exist. **This precondition is + enforced with an assertion.** + + @throw type_error.305 if the JSON value is not an object; in that case, + using the [] operator with a key makes no sense. + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read using + the `[]` operator.,operatorarray__key_type_const} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value + + @since version 1.0.0 + */ + const_reference operator[](const typename object_t::key_type& key) const + { + // const operator[] only works for objects + if (JSON_LIKELY(is_object())) + { + assert(m_value.object->find(key) != m_value.object->end()); + return m_value.object->find(key)->second; + } + + JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); + } + + /*! + @brief access specified object element + + Returns a reference to the element at with specified key @a key. + + @note If @a key is not found in the object, then it is silently added to + the object and filled with a `null` value to make `key` a valid reference. + In case the value was `null` before, it is converted to an object. + + @param[in] key key of the element to access + + @return reference to the element at key @a key + + @throw type_error.305 if the JSON value is not an object or null; in that + cases, using the [] operator with a key makes no sense. + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read and + written using the `[]` operator.,operatorarray__key_type} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value + + @since version 1.1.0 + */ + template + reference operator[](T* key) + { + // implicitly convert null to object + if (is_null()) + { + m_type = value_t::object; + m_value = value_t::object; + assert_invariant(); + } + + // at only works for objects + if (JSON_LIKELY(is_object())) + { + return m_value.object->operator[](key); + } + + JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); + } + + /*! + @brief read-only access specified object element + + Returns a const reference to the element at with specified key @a key. No + bounds checking is performed. + + @warning If the element with key @a key does not exist, the behavior is + undefined. + + @param[in] key key of the element to access + + @return const reference to the element at key @a key + + @pre The element with key @a key must exist. **This precondition is + enforced with an assertion.** + + @throw type_error.305 if the JSON value is not an object; in that case, + using the [] operator with a key makes no sense. + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read using + the `[]` operator.,operatorarray__key_type_const} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value + + @since version 1.1.0 + */ + template + const_reference operator[](T* key) const + { + // at only works for objects + if (JSON_LIKELY(is_object())) + { + assert(m_value.object->find(key) != m_value.object->end()); + return m_value.object->find(key)->second; + } + + JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); + } + + /*! + @brief access specified object element with default value + + Returns either a copy of an object's element at the specified key @a key + or a given default value if no element with key @a key exists. + + The function is basically equivalent to executing + @code {.cpp} + try { + return at(key); + } catch(out_of_range) { + return default_value; + } + @endcode + + @note Unlike @ref at(const typename object_t::key_type&), this function + does not throw if the given key @a key was not found. + + @note Unlike @ref operator[](const typename object_t::key_type& key), this + function does not implicitly add an element to the position defined by @a + key. This function is furthermore also applicable to const objects. + + @param[in] key key of the element to access + @param[in] default_value the value to return if @a key is not found + + @tparam ValueType type compatible to JSON values, for instance `int` for + JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for + JSON arrays. Note the type of the expected value at @a key and the default + value @a default_value must be compatible. + + @return copy of the element at key @a key or @a default_value if @a key + is not found + + @throw type_error.306 if the JSON value is not an object; in that case, + using `value()` with a key makes no sense. + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be queried + with a default value.,basic_json__value} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref operator[](const typename object_t::key_type&) for unchecked + access by reference + + @since version 1.0.0 + */ + template::value, int>::type = 0> + ValueType value(const typename object_t::key_type& key, const ValueType& default_value) const + { + // at only works for objects + if (JSON_LIKELY(is_object())) + { + // if key is found, return value and given default value otherwise + const auto it = find(key); + if (it != end()) + { + return *it; + } + + return default_value; + } + + JSON_THROW(type_error::create(306, "cannot use value() with " + std::string(type_name()))); + } + + /*! + @brief overload for a default value of type const char* + @copydoc basic_json::value(const typename object_t::key_type&, ValueType) const + */ + string_t value(const typename object_t::key_type& key, const char* default_value) const + { + return value(key, string_t(default_value)); + } + + /*! + @brief access specified object element via JSON Pointer with default value + + Returns either a copy of an object's element at the specified key @a key + or a given default value if no element with key @a key exists. + + The function is basically equivalent to executing + @code {.cpp} + try { + return at(ptr); + } catch(out_of_range) { + return default_value; + } + @endcode + + @note Unlike @ref at(const json_pointer&), this function does not throw + if the given key @a key was not found. + + @param[in] ptr a JSON pointer to the element to access + @param[in] default_value the value to return if @a ptr found no value + + @tparam ValueType type compatible to JSON values, for instance `int` for + JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for + JSON arrays. Note the type of the expected value at @a key and the default + value @a default_value must be compatible. + + @return copy of the element at key @a key or @a default_value if @a key + is not found + + @throw type_error.306 if the JSON value is not an objec; in that case, + using `value()` with a key makes no sense. + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be queried + with a default value.,basic_json__value_ptr} + + @sa @ref operator[](const json_pointer&) for unchecked access by reference + + @since version 2.0.2 + */ + template::value, int>::type = 0> + ValueType value(const json_pointer& ptr, const ValueType& default_value) const + { + // at only works for objects + if (JSON_LIKELY(is_object())) + { + // if pointer resolves a value, return it or use default value + JSON_TRY + { + return ptr.get_checked(this); + } + JSON_CATCH (out_of_range&) + { + return default_value; + } + } + + JSON_THROW(type_error::create(306, "cannot use value() with " + std::string(type_name()))); + } + + /*! + @brief overload for a default value of type const char* + @copydoc basic_json::value(const json_pointer&, ValueType) const + */ + string_t value(const json_pointer& ptr, const char* default_value) const + { + return value(ptr, string_t(default_value)); + } + + /*! + @brief access the first element + + Returns a reference to the first element in the container. For a JSON + container `c`, the expression `c.front()` is equivalent to `*c.begin()`. + + @return In case of a structured type (array or object), a reference to the + first element is returned. In case of number, string, or boolean values, a + reference to the value is returned. + + @complexity Constant. + + @pre The JSON value must not be `null` (would throw `std::out_of_range`) + or an empty array or object (undefined behavior, **guarded by + assertions**). + @post The JSON value remains unchanged. + + @throw invalid_iterator.214 when called on `null` value + + @liveexample{The following code shows an example for `front()`.,front} + + @sa @ref back() -- access the last element + + @since version 1.0.0 + */ + reference front() + { + return *begin(); + } + + /*! + @copydoc basic_json::front() + */ + const_reference front() const + { + return *cbegin(); + } + + /*! + @brief access the last element + + Returns a reference to the last element in the container. For a JSON + container `c`, the expression `c.back()` is equivalent to + @code {.cpp} + auto tmp = c.end(); + --tmp; + return *tmp; + @endcode + + @return In case of a structured type (array or object), a reference to the + last element is returned. In case of number, string, or boolean values, a + reference to the value is returned. + + @complexity Constant. + + @pre The JSON value must not be `null` (would throw `std::out_of_range`) + or an empty array or object (undefined behavior, **guarded by + assertions**). + @post The JSON value remains unchanged. + + @throw invalid_iterator.214 when called on a `null` value. See example + below. + + @liveexample{The following code shows an example for `back()`.,back} + + @sa @ref front() -- access the first element + + @since version 1.0.0 + */ + reference back() + { + auto tmp = end(); + --tmp; + return *tmp; + } + + /*! + @copydoc basic_json::back() + */ + const_reference back() const + { + auto tmp = cend(); + --tmp; + return *tmp; + } + + /*! + @brief remove element given an iterator + + Removes the element specified by iterator @a pos. The iterator @a pos must + be valid and dereferenceable. Thus the `end()` iterator (which is valid, + but is not dereferenceable) cannot be used as a value for @a pos. + + If called on a primitive type other than `null`, the resulting JSON value + will be `null`. + + @param[in] pos iterator to the element to remove + @return Iterator following the last removed element. If the iterator @a + pos refers to the last element, the `end()` iterator is returned. + + @tparam IteratorType an @ref iterator or @ref const_iterator + + @post Invalidates iterators and references at or after the point of the + erase, including the `end()` iterator. + + @throw type_error.307 if called on a `null` value; example: `"cannot use + erase() with null"` + @throw invalid_iterator.202 if called on an iterator which does not belong + to the current JSON value; example: `"iterator does not fit current + value"` + @throw invalid_iterator.205 if called on a primitive type with invalid + iterator (i.e., any iterator which is not `begin()`); example: `"iterator + out of range"` + + @complexity The complexity depends on the type: + - objects: amortized constant + - arrays: linear in distance between @a pos and the end of the container + - strings: linear in the length of the string + - other types: constant + + @liveexample{The example shows the result of `erase()` for different JSON + types.,erase__IteratorType} + + @sa @ref erase(IteratorType, IteratorType) -- removes the elements in + the given range + @sa @ref erase(const typename object_t::key_type&) -- removes the element + from an object at the given key + @sa @ref erase(const size_type) -- removes the element from an array at + the given index + + @since version 1.0.0 + */ + template::value or + std::is_same::value, int>::type + = 0> + IteratorType erase(IteratorType pos) + { + // make sure iterator fits the current value + if (JSON_UNLIKELY(this != pos.m_object)) + { + JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value")); + } + + IteratorType result = end(); + + switch (m_type) + { + case value_t::boolean: + case value_t::number_float: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::string: + { + if (JSON_UNLIKELY(not pos.m_it.primitive_iterator.is_begin())) + { + JSON_THROW(invalid_iterator::create(205, "iterator out of range")); + } + + if (is_string()) + { + AllocatorType alloc; + std::allocator_traits::destroy(alloc, m_value.string); + std::allocator_traits::deallocate(alloc, m_value.string, 1); + m_value.string = nullptr; + } + + m_type = value_t::null; + assert_invariant(); + break; + } + + case value_t::object: + { + result.m_it.object_iterator = m_value.object->erase(pos.m_it.object_iterator); + break; + } + + case value_t::array: + { + result.m_it.array_iterator = m_value.array->erase(pos.m_it.array_iterator); + break; + } + + default: + JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name()))); + } + + return result; + } + + /*! + @brief remove elements given an iterator range + + Removes the element specified by the range `[first; last)`. The iterator + @a first does not need to be dereferenceable if `first == last`: erasing + an empty range is a no-op. + + If called on a primitive type other than `null`, the resulting JSON value + will be `null`. + + @param[in] first iterator to the beginning of the range to remove + @param[in] last iterator past the end of the range to remove + @return Iterator following the last removed element. If the iterator @a + second refers to the last element, the `end()` iterator is returned. + + @tparam IteratorType an @ref iterator or @ref const_iterator + + @post Invalidates iterators and references at or after the point of the + erase, including the `end()` iterator. + + @throw type_error.307 if called on a `null` value; example: `"cannot use + erase() with null"` + @throw invalid_iterator.203 if called on iterators which does not belong + to the current JSON value; example: `"iterators do not fit current value"` + @throw invalid_iterator.204 if called on a primitive type with invalid + iterators (i.e., if `first != begin()` and `last != end()`); example: + `"iterators out of range"` + + @complexity The complexity depends on the type: + - objects: `log(size()) + std::distance(first, last)` + - arrays: linear in the distance between @a first and @a last, plus linear + in the distance between @a last and end of the container + - strings: linear in the length of the string + - other types: constant + + @liveexample{The example shows the result of `erase()` for different JSON + types.,erase__IteratorType_IteratorType} + + @sa @ref erase(IteratorType) -- removes the element at a given position + @sa @ref erase(const typename object_t::key_type&) -- removes the element + from an object at the given key + @sa @ref erase(const size_type) -- removes the element from an array at + the given index + + @since version 1.0.0 + */ + template::value or + std::is_same::value, int>::type + = 0> + IteratorType erase(IteratorType first, IteratorType last) + { + // make sure iterator fits the current value + if (JSON_UNLIKELY(this != first.m_object or this != last.m_object)) + { + JSON_THROW(invalid_iterator::create(203, "iterators do not fit current value")); + } + + IteratorType result = end(); + + switch (m_type) + { + case value_t::boolean: + case value_t::number_float: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::string: + { + if (JSON_LIKELY(not first.m_it.primitive_iterator.is_begin() + or not last.m_it.primitive_iterator.is_end())) + { + JSON_THROW(invalid_iterator::create(204, "iterators out of range")); + } + + if (is_string()) + { + AllocatorType alloc; + std::allocator_traits::destroy(alloc, m_value.string); + std::allocator_traits::deallocate(alloc, m_value.string, 1); + m_value.string = nullptr; + } + + m_type = value_t::null; + assert_invariant(); + break; + } + + case value_t::object: + { + result.m_it.object_iterator = m_value.object->erase(first.m_it.object_iterator, + last.m_it.object_iterator); + break; + } + + case value_t::array: + { + result.m_it.array_iterator = m_value.array->erase(first.m_it.array_iterator, + last.m_it.array_iterator); + break; + } + + default: + JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name()))); + } + + return result; + } + + /*! + @brief remove element from a JSON object given a key + + Removes elements from a JSON object with the key value @a key. + + @param[in] key value of the elements to remove + + @return Number of elements removed. If @a ObjectType is the default + `std::map` type, the return value will always be `0` (@a key was not + found) or `1` (@a key was found). + + @post References and iterators to the erased elements are invalidated. + Other references and iterators are not affected. + + @throw type_error.307 when called on a type other than JSON object; + example: `"cannot use erase() with null"` + + @complexity `log(size()) + count(key)` + + @liveexample{The example shows the effect of `erase()`.,erase__key_type} + + @sa @ref erase(IteratorType) -- removes the element at a given position + @sa @ref erase(IteratorType, IteratorType) -- removes the elements in + the given range + @sa @ref erase(const size_type) -- removes the element from an array at + the given index + + @since version 1.0.0 + */ + size_type erase(const typename object_t::key_type& key) + { + // this erase only works for objects + if (JSON_LIKELY(is_object())) + { + return m_value.object->erase(key); + } + + JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name()))); + } + + /*! + @brief remove element from a JSON array given an index + + Removes element from a JSON array at the index @a idx. + + @param[in] idx index of the element to remove + + @throw type_error.307 when called on a type other than JSON object; + example: `"cannot use erase() with null"` + @throw out_of_range.401 when `idx >= size()`; example: `"array index 17 + is out of range"` + + @complexity Linear in distance between @a idx and the end of the container. + + @liveexample{The example shows the effect of `erase()`.,erase__size_type} + + @sa @ref erase(IteratorType) -- removes the element at a given position + @sa @ref erase(IteratorType, IteratorType) -- removes the elements in + the given range + @sa @ref erase(const typename object_t::key_type&) -- removes the element + from an object at the given key + + @since version 1.0.0 + */ + void erase(const size_type idx) + { + // this erase only works for arrays + if (JSON_LIKELY(is_array())) + { + if (JSON_UNLIKELY(idx >= size())) + { + JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range")); + } + + m_value.array->erase(m_value.array->begin() + static_cast(idx)); + } + else + { + JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name()))); + } + } + + /// @} + + //////////// + // lookup // + //////////// + + /// @name lookup + /// @{ + + /*! + @brief find an element in a JSON object + + Finds an element in a JSON object with key equivalent to @a key. If the + element is not found or the JSON value is not an object, end() is + returned. + + @note This method always returns @ref end() when executed on a JSON type + that is not an object. + + @param[in] key key value of the element to search for. + + @return Iterator to an element with key equivalent to @a key. If no such + element is found or the JSON value is not an object, past-the-end (see + @ref end()) iterator is returned. + + @complexity Logarithmic in the size of the JSON object. + + @liveexample{The example shows how `find()` is used.,find__key_type} + + @since version 1.0.0 + */ + template + iterator find(KeyT&& key) + { + auto result = end(); + + if (is_object()) + { + result.m_it.object_iterator = m_value.object->find(std::forward(key)); + } + + return result; + } + + /*! + @brief find an element in a JSON object + @copydoc find(KeyT&&) + */ + template + const_iterator find(KeyT&& key) const + { + auto result = cend(); + + if (is_object()) + { + result.m_it.object_iterator = m_value.object->find(std::forward(key)); + } + + return result; + } + + /*! + @brief returns the number of occurrences of a key in a JSON object + + Returns the number of elements with key @a key. If ObjectType is the + default `std::map` type, the return value will always be `0` (@a key was + not found) or `1` (@a key was found). + + @note This method always returns `0` when executed on a JSON type that is + not an object. + + @param[in] key key value of the element to count + + @return Number of elements with key @a key. If the JSON value is not an + object, the return value will be `0`. + + @complexity Logarithmic in the size of the JSON object. + + @liveexample{The example shows how `count()` is used.,count} + + @since version 1.0.0 + */ + template + size_type count(KeyT&& key) const + { + // return 0 for all nonobject types + return is_object() ? m_value.object->count(std::forward(key)) : 0; + } + + /// @} + + /////////////// + // iterators // + /////////////// + + /// @name iterators + /// @{ + + /*! + @brief returns an iterator to the first element + + Returns an iterator to the first element. + + @image html range-begin-end.svg "Illustration from cppreference.com" + + @return iterator to the first element + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + + @liveexample{The following code shows an example for `begin()`.,begin} + + @sa @ref cbegin() -- returns a const iterator to the beginning + @sa @ref end() -- returns an iterator to the end + @sa @ref cend() -- returns a const iterator to the end + + @since version 1.0.0 + */ + iterator begin() noexcept + { + iterator result(this); + result.set_begin(); + return result; + } + + /*! + @copydoc basic_json::cbegin() + */ + const_iterator begin() const noexcept + { + return cbegin(); + } + + /*! + @brief returns a const iterator to the first element + + Returns a const iterator to the first element. + + @image html range-begin-end.svg "Illustration from cppreference.com" + + @return const iterator to the first element + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + - Has the semantics of `const_cast(*this).begin()`. + + @liveexample{The following code shows an example for `cbegin()`.,cbegin} + + @sa @ref begin() -- returns an iterator to the beginning + @sa @ref end() -- returns an iterator to the end + @sa @ref cend() -- returns a const iterator to the end + + @since version 1.0.0 + */ + const_iterator cbegin() const noexcept + { + const_iterator result(this); + result.set_begin(); + return result; + } + + /*! + @brief returns an iterator to one past the last element + + Returns an iterator to one past the last element. + + @image html range-begin-end.svg "Illustration from cppreference.com" + + @return iterator one past the last element + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + + @liveexample{The following code shows an example for `end()`.,end} + + @sa @ref cend() -- returns a const iterator to the end + @sa @ref begin() -- returns an iterator to the beginning + @sa @ref cbegin() -- returns a const iterator to the beginning + + @since version 1.0.0 + */ + iterator end() noexcept + { + iterator result(this); + result.set_end(); + return result; + } + + /*! + @copydoc basic_json::cend() + */ + const_iterator end() const noexcept + { + return cend(); + } + + /*! + @brief returns a const iterator to one past the last element + + Returns a const iterator to one past the last element. + + @image html range-begin-end.svg "Illustration from cppreference.com" + + @return const iterator one past the last element + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + - Has the semantics of `const_cast(*this).end()`. + + @liveexample{The following code shows an example for `cend()`.,cend} + + @sa @ref end() -- returns an iterator to the end + @sa @ref begin() -- returns an iterator to the beginning + @sa @ref cbegin() -- returns a const iterator to the beginning + + @since version 1.0.0 + */ + const_iterator cend() const noexcept + { + const_iterator result(this); + result.set_end(); + return result; + } + + /*! + @brief returns an iterator to the reverse-beginning + + Returns an iterator to the reverse-beginning; that is, the last element. + + @image html range-rbegin-rend.svg "Illustration from cppreference.com" + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) + requirements: + - The complexity is constant. + - Has the semantics of `reverse_iterator(end())`. + + @liveexample{The following code shows an example for `rbegin()`.,rbegin} + + @sa @ref crbegin() -- returns a const reverse iterator to the beginning + @sa @ref rend() -- returns a reverse iterator to the end + @sa @ref crend() -- returns a const reverse iterator to the end + + @since version 1.0.0 + */ + reverse_iterator rbegin() noexcept + { + return reverse_iterator(end()); + } + + /*! + @copydoc basic_json::crbegin() + */ + const_reverse_iterator rbegin() const noexcept + { + return crbegin(); + } + + /*! + @brief returns an iterator to the reverse-end + + Returns an iterator to the reverse-end; that is, one before the first + element. + + @image html range-rbegin-rend.svg "Illustration from cppreference.com" + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) + requirements: + - The complexity is constant. + - Has the semantics of `reverse_iterator(begin())`. + + @liveexample{The following code shows an example for `rend()`.,rend} + + @sa @ref crend() -- returns a const reverse iterator to the end + @sa @ref rbegin() -- returns a reverse iterator to the beginning + @sa @ref crbegin() -- returns a const reverse iterator to the beginning + + @since version 1.0.0 + */ + reverse_iterator rend() noexcept + { + return reverse_iterator(begin()); + } + + /*! + @copydoc basic_json::crend() + */ + const_reverse_iterator rend() const noexcept + { + return crend(); + } + + /*! + @brief returns a const reverse iterator to the last element + + Returns a const iterator to the reverse-beginning; that is, the last + element. + + @image html range-rbegin-rend.svg "Illustration from cppreference.com" + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) + requirements: + - The complexity is constant. + - Has the semantics of `const_cast(*this).rbegin()`. + + @liveexample{The following code shows an example for `crbegin()`.,crbegin} + + @sa @ref rbegin() -- returns a reverse iterator to the beginning + @sa @ref rend() -- returns a reverse iterator to the end + @sa @ref crend() -- returns a const reverse iterator to the end + + @since version 1.0.0 + */ + const_reverse_iterator crbegin() const noexcept + { + return const_reverse_iterator(cend()); + } + + /*! + @brief returns a const reverse iterator to one before the first + + Returns a const reverse iterator to the reverse-end; that is, one before + the first element. + + @image html range-rbegin-rend.svg "Illustration from cppreference.com" + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) + requirements: + - The complexity is constant. + - Has the semantics of `const_cast(*this).rend()`. + + @liveexample{The following code shows an example for `crend()`.,crend} + + @sa @ref rend() -- returns a reverse iterator to the end + @sa @ref rbegin() -- returns a reverse iterator to the beginning + @sa @ref crbegin() -- returns a const reverse iterator to the beginning + + @since version 1.0.0 + */ + const_reverse_iterator crend() const noexcept + { + return const_reverse_iterator(cbegin()); + } + + public: + /*! + @brief wrapper to access iterator member functions in range-based for + + This function allows to access @ref iterator::key() and @ref + iterator::value() during range-based for loops. In these loops, a + reference to the JSON values is returned, so there is no access to the + underlying iterator. + + For loop without iterator_wrapper: + + @code{cpp} + for (auto it = j_object.begin(); it != j_object.end(); ++it) + { + std::cout << "key: " << it.key() << ", value:" << it.value() << '\n'; + } + @endcode + + Range-based for loop without iterator proxy: + + @code{cpp} + for (auto it : j_object) + { + // "it" is of type json::reference and has no key() member + std::cout << "value: " << it << '\n'; + } + @endcode + + Range-based for loop with iterator proxy: + + @code{cpp} + for (auto it : json::iterator_wrapper(j_object)) + { + std::cout << "key: " << it.key() << ", value:" << it.value() << '\n'; + } + @endcode + + @note When iterating over an array, `key()` will return the index of the + element as string (see example). + + @param[in] ref reference to a JSON value + @return iteration proxy object wrapping @a ref with an interface to use in + range-based for loops + + @liveexample{The following code shows how the wrapper is used,iterator_wrapper} + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Constant. + + @note The name of this function is not yet final and may change in the + future. + */ + static iteration_proxy iterator_wrapper(reference ref) + { + return iteration_proxy(ref); + } + + /*! + @copydoc iterator_wrapper(reference) + */ + static iteration_proxy iterator_wrapper(const_reference ref) + { + return iteration_proxy(ref); + } + + /// @} + + ////////////// + // capacity // + ////////////// + + /// @name capacity + /// @{ + + /*! + @brief checks whether the container is empty. + + Checks if a JSON value has no elements (i.e. whether its @ref size is `0`). + + @return The return value depends on the different types and is + defined as follows: + Value type | return value + ----------- | ------------- + null | `true` + boolean | `false` + string | `false` + number | `false` + object | result of function `object_t::empty()` + array | result of function `array_t::empty()` + + @liveexample{The following code uses `empty()` to check if a JSON + object contains any elements.,empty} + + @complexity Constant, as long as @ref array_t and @ref object_t satisfy + the Container concept; that is, their `empty()` functions have constant + complexity. + + @iterators No changes. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @note This function does not return whether a string stored as JSON value + is empty - it returns whether the JSON container itself is empty which is + false in the case of a string. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + - Has the semantics of `begin() == end()`. + + @sa @ref size() -- returns the number of elements + + @since version 1.0.0 + */ + bool empty() const noexcept + { + switch (m_type) + { + case value_t::null: + { + // null values are empty + return true; + } + + case value_t::array: + { + // delegate call to array_t::empty() + return m_value.array->empty(); + } + + case value_t::object: + { + // delegate call to object_t::empty() + return m_value.object->empty(); + } + + default: + { + // all other types are nonempty + return false; + } + } + } + + /*! + @brief returns the number of elements + + Returns the number of elements in a JSON value. + + @return The return value depends on the different types and is + defined as follows: + Value type | return value + ----------- | ------------- + null | `0` + boolean | `1` + string | `1` + number | `1` + object | result of function object_t::size() + array | result of function array_t::size() + + @liveexample{The following code calls `size()` on the different value + types.,size} + + @complexity Constant, as long as @ref array_t and @ref object_t satisfy + the Container concept; that is, their size() functions have constant + complexity. + + @iterators No changes. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @note This function does not return the length of a string stored as JSON + value - it returns the number of elements in the JSON value which is 1 in + the case of a string. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + - Has the semantics of `std::distance(begin(), end())`. + + @sa @ref empty() -- checks whether the container is empty + @sa @ref max_size() -- returns the maximal number of elements + + @since version 1.0.0 + */ + size_type size() const noexcept + { + switch (m_type) + { + case value_t::null: + { + // null values are empty + return 0; + } + + case value_t::array: + { + // delegate call to array_t::size() + return m_value.array->size(); + } + + case value_t::object: + { + // delegate call to object_t::size() + return m_value.object->size(); + } + + default: + { + // all other types have size 1 + return 1; + } + } + } + + /*! + @brief returns the maximum possible number of elements + + Returns the maximum number of elements a JSON value is able to hold due to + system or library implementation limitations, i.e. `std::distance(begin(), + end())` for the JSON value. + + @return The return value depends on the different types and is + defined as follows: + Value type | return value + ----------- | ------------- + null | `0` (same as `size()`) + boolean | `1` (same as `size()`) + string | `1` (same as `size()`) + number | `1` (same as `size()`) + object | result of function `object_t::max_size()` + array | result of function `array_t::max_size()` + + @liveexample{The following code calls `max_size()` on the different value + types. Note the output is implementation specific.,max_size} + + @complexity Constant, as long as @ref array_t and @ref object_t satisfy + the Container concept; that is, their `max_size()` functions have constant + complexity. + + @iterators No changes. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + - Has the semantics of returning `b.size()` where `b` is the largest + possible JSON value. + + @sa @ref size() -- returns the number of elements + + @since version 1.0.0 + */ + size_type max_size() const noexcept + { + switch (m_type) + { + case value_t::array: + { + // delegate call to array_t::max_size() + return m_value.array->max_size(); + } + + case value_t::object: + { + // delegate call to object_t::max_size() + return m_value.object->max_size(); + } + + default: + { + // all other types have max_size() == size() + return size(); + } + } + } + + /// @} + + /////////////// + // modifiers // + /////////////// + + /// @name modifiers + /// @{ + + /*! + @brief clears the contents + + Clears the content of a JSON value and resets it to the default value as + if @ref basic_json(value_t) would have been called with the current value + type from @ref type(): + + Value type | initial value + ----------- | ------------- + null | `null` + boolean | `false` + string | `""` + number | `0` + object | `{}` + array | `[]` + + @post Has the same effect as calling + @code {.cpp} + *this = basic_json(type()); + @endcode + + @liveexample{The example below shows the effect of `clear()` to different + JSON types.,clear} + + @complexity Linear in the size of the JSON value. + + @iterators All iterators, pointers and references related to this container + are invalidated. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @sa @ref basic_json(value_t) -- constructor that creates an object with the + same value than calling `clear()` + + @since version 1.0.0 + */ + void clear() noexcept + { + switch (m_type) + { + case value_t::number_integer: + { + m_value.number_integer = 0; + break; + } + + case value_t::number_unsigned: + { + m_value.number_unsigned = 0; + break; + } + + case value_t::number_float: + { + m_value.number_float = 0.0; + break; + } + + case value_t::boolean: + { + m_value.boolean = false; + break; + } + + case value_t::string: + { + m_value.string->clear(); + break; + } + + case value_t::array: + { + m_value.array->clear(); + break; + } + + case value_t::object: + { + m_value.object->clear(); + break; + } + + default: + break; + } + } + + /*! + @brief add an object to an array + + Appends the given element @a val to the end of the JSON value. If the + function is called on a JSON null value, an empty array is created before + appending @a val. + + @param[in] val the value to add to the JSON array + + @throw type_error.308 when called on a type other than JSON array or + null; example: `"cannot use push_back() with number"` + + @complexity Amortized constant. + + @liveexample{The example shows how `push_back()` and `+=` can be used to + add elements to a JSON array. Note how the `null` value was silently + converted to a JSON array.,push_back} + + @since version 1.0.0 + */ + void push_back(basic_json&& val) + { + // push_back only works for null objects or arrays + if (JSON_UNLIKELY(not(is_null() or is_array()))) + { + JSON_THROW(type_error::create(308, "cannot use push_back() with " + std::string(type_name()))); + } + + // transform null object into an array + if (is_null()) + { + m_type = value_t::array; + m_value = value_t::array; + assert_invariant(); + } + + // add element to array (move semantics) + m_value.array->push_back(std::move(val)); + // invalidate object + val.m_type = value_t::null; + } + + /*! + @brief add an object to an array + @copydoc push_back(basic_json&&) + */ + reference operator+=(basic_json&& val) + { + push_back(std::move(val)); + return *this; + } + + /*! + @brief add an object to an array + @copydoc push_back(basic_json&&) + */ + void push_back(const basic_json& val) + { + // push_back only works for null objects or arrays + if (JSON_UNLIKELY(not(is_null() or is_array()))) + { + JSON_THROW(type_error::create(308, "cannot use push_back() with " + std::string(type_name()))); + } + + // transform null object into an array + if (is_null()) + { + m_type = value_t::array; + m_value = value_t::array; + assert_invariant(); + } + + // add element to array + m_value.array->push_back(val); + } + + /*! + @brief add an object to an array + @copydoc push_back(basic_json&&) + */ + reference operator+=(const basic_json& val) + { + push_back(val); + return *this; + } + + /*! + @brief add an object to an object + + Inserts the given element @a val to the JSON object. If the function is + called on a JSON null value, an empty object is created before inserting + @a val. + + @param[in] val the value to add to the JSON object + + @throw type_error.308 when called on a type other than JSON object or + null; example: `"cannot use push_back() with number"` + + @complexity Logarithmic in the size of the container, O(log(`size()`)). + + @liveexample{The example shows how `push_back()` and `+=` can be used to + add elements to a JSON object. Note how the `null` value was silently + converted to a JSON object.,push_back__object_t__value} + + @since version 1.0.0 + */ + void push_back(const typename object_t::value_type& val) + { + // push_back only works for null objects or objects + if (JSON_UNLIKELY(not(is_null() or is_object()))) + { + JSON_THROW(type_error::create(308, "cannot use push_back() with " + std::string(type_name()))); + } + + // transform null object into an object + if (is_null()) + { + m_type = value_t::object; + m_value = value_t::object; + assert_invariant(); + } + + // add element to array + m_value.object->insert(val); + } + + /*! + @brief add an object to an object + @copydoc push_back(const typename object_t::value_type&) + */ + reference operator+=(const typename object_t::value_type& val) + { + push_back(val); + return *this; + } + + /*! + @brief add an object to an object + + This function allows to use `push_back` with an initializer list. In case + + 1. the current value is an object, + 2. the initializer list @a init contains only two elements, and + 3. the first element of @a init is a string, + + @a init is converted into an object element and added using + @ref push_back(const typename object_t::value_type&). Otherwise, @a init + is converted to a JSON value and added using @ref push_back(basic_json&&). + + @param[in] init an initializer list + + @complexity Linear in the size of the initializer list @a init. + + @note This function is required to resolve an ambiguous overload error, + because pairs like `{"key", "value"}` can be both interpreted as + `object_t::value_type` or `std::initializer_list`, see + https://github.com/nlohmann/json/issues/235 for more information. + + @liveexample{The example shows how initializer lists are treated as + objects when possible.,push_back__initializer_list} + */ + void push_back(initializer_list_t init) + { + if (is_object() and init.size() == 2 and (*init.begin())->is_string()) + { + basic_json&& key = init.begin()->moved_or_copied(); + push_back(typename object_t::value_type( + std::move(key.get_ref()), (init.begin() + 1)->moved_or_copied())); + } + else + { + push_back(basic_json(init)); + } + } + + /*! + @brief add an object to an object + @copydoc push_back(initializer_list_t) + */ + reference operator+=(initializer_list_t init) + { + push_back(init); + return *this; + } + + /*! + @brief add an object to an array + + Creates a JSON value from the passed parameters @a args to the end of the + JSON value. If the function is called on a JSON null value, an empty array + is created before appending the value created from @a args. + + @param[in] args arguments to forward to a constructor of @ref basic_json + @tparam Args compatible types to create a @ref basic_json object + + @throw type_error.311 when called on a type other than JSON array or + null; example: `"cannot use emplace_back() with number"` + + @complexity Amortized constant. + + @liveexample{The example shows how `push_back()` can be used to add + elements to a JSON array. Note how the `null` value was silently converted + to a JSON array.,emplace_back} + + @since version 2.0.8 + */ + template + void emplace_back(Args&& ... args) + { + // emplace_back only works for null objects or arrays + if (JSON_UNLIKELY(not(is_null() or is_array()))) + { + JSON_THROW(type_error::create(311, "cannot use emplace_back() with " + std::string(type_name()))); + } + + // transform null object into an array + if (is_null()) + { + m_type = value_t::array; + m_value = value_t::array; + assert_invariant(); + } + + // add element to array (perfect forwarding) + m_value.array->emplace_back(std::forward(args)...); + } + + /*! + @brief add an object to an object if key does not exist + + Inserts a new element into a JSON object constructed in-place with the + given @a args if there is no element with the key in the container. If the + function is called on a JSON null value, an empty object is created before + appending the value created from @a args. + + @param[in] args arguments to forward to a constructor of @ref basic_json + @tparam Args compatible types to create a @ref basic_json object + + @return a pair consisting of an iterator to the inserted element, or the + already-existing element if no insertion happened, and a bool + denoting whether the insertion took place. + + @throw type_error.311 when called on a type other than JSON object or + null; example: `"cannot use emplace() with number"` + + @complexity Logarithmic in the size of the container, O(log(`size()`)). + + @liveexample{The example shows how `emplace()` can be used to add elements + to a JSON object. Note how the `null` value was silently converted to a + JSON object. Further note how no value is added if there was already one + value stored with the same key.,emplace} + + @since version 2.0.8 + */ + template + std::pair emplace(Args&& ... args) + { + // emplace only works for null objects or arrays + if (JSON_UNLIKELY(not(is_null() or is_object()))) + { + JSON_THROW(type_error::create(311, "cannot use emplace() with " + std::string(type_name()))); + } + + // transform null object into an object + if (is_null()) + { + m_type = value_t::object; + m_value = value_t::object; + assert_invariant(); + } + + // add element to array (perfect forwarding) + auto res = m_value.object->emplace(std::forward(args)...); + // create result iterator and set iterator to the result of emplace + auto it = begin(); + it.m_it.object_iterator = res.first; + + // return pair of iterator and boolean + return {it, res.second}; + } + + /*! + @brief inserts element + + Inserts element @a val before iterator @a pos. + + @param[in] pos iterator before which the content will be inserted; may be + the end() iterator + @param[in] val element to insert + @return iterator pointing to the inserted @a val. + + @throw type_error.309 if called on JSON values other than arrays; + example: `"cannot use insert() with string"` + @throw invalid_iterator.202 if @a pos is not an iterator of *this; + example: `"iterator does not fit current value"` + + @complexity Constant plus linear in the distance between @a pos and end of + the container. + + @liveexample{The example shows how `insert()` is used.,insert} + + @since version 1.0.0 + */ + iterator insert(const_iterator pos, const basic_json& val) + { + // insert only works for arrays + if (JSON_LIKELY(is_array())) + { + // check if iterator pos fits to this JSON value + if (JSON_UNLIKELY(pos.m_object != this)) + { + JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value")); + } + + // insert to array and return iterator + iterator result(this); + result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, val); + return result; + } + + JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); + } + + /*! + @brief inserts element + @copydoc insert(const_iterator, const basic_json&) + */ + iterator insert(const_iterator pos, basic_json&& val) + { + return insert(pos, val); + } + + /*! + @brief inserts elements + + Inserts @a cnt copies of @a val before iterator @a pos. + + @param[in] pos iterator before which the content will be inserted; may be + the end() iterator + @param[in] cnt number of copies of @a val to insert + @param[in] val element to insert + @return iterator pointing to the first element inserted, or @a pos if + `cnt==0` + + @throw type_error.309 if called on JSON values other than arrays; example: + `"cannot use insert() with string"` + @throw invalid_iterator.202 if @a pos is not an iterator of *this; + example: `"iterator does not fit current value"` + + @complexity Linear in @a cnt plus linear in the distance between @a pos + and end of the container. + + @liveexample{The example shows how `insert()` is used.,insert__count} + + @since version 1.0.0 + */ + iterator insert(const_iterator pos, size_type cnt, const basic_json& val) + { + // insert only works for arrays + if (JSON_LIKELY(is_array())) + { + // check if iterator pos fits to this JSON value + if (JSON_UNLIKELY(pos.m_object != this)) + { + JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value")); + } + + // insert to array and return iterator + iterator result(this); + result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val); + return result; + } + + JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); + } + + /*! + @brief inserts elements + + Inserts elements from range `[first, last)` before iterator @a pos. + + @param[in] pos iterator before which the content will be inserted; may be + the end() iterator + @param[in] first begin of the range of elements to insert + @param[in] last end of the range of elements to insert + + @throw type_error.309 if called on JSON values other than arrays; example: + `"cannot use insert() with string"` + @throw invalid_iterator.202 if @a pos is not an iterator of *this; + example: `"iterator does not fit current value"` + @throw invalid_iterator.210 if @a first and @a last do not belong to the + same JSON value; example: `"iterators do not fit"` + @throw invalid_iterator.211 if @a first or @a last are iterators into + container for which insert is called; example: `"passed iterators may not + belong to container"` + + @return iterator pointing to the first element inserted, or @a pos if + `first==last` + + @complexity Linear in `std::distance(first, last)` plus linear in the + distance between @a pos and end of the container. + + @liveexample{The example shows how `insert()` is used.,insert__range} + + @since version 1.0.0 + */ + iterator insert(const_iterator pos, const_iterator first, const_iterator last) + { + // insert only works for arrays + if (JSON_UNLIKELY(not is_array())) + { + JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); + } + + // check if iterator pos fits to this JSON value + if (JSON_UNLIKELY(pos.m_object != this)) + { + JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value")); + } + + // check if range iterators belong to the same JSON object + if (JSON_UNLIKELY(first.m_object != last.m_object)) + { + JSON_THROW(invalid_iterator::create(210, "iterators do not fit")); + } + + if (JSON_UNLIKELY(first.m_object == this)) + { + JSON_THROW(invalid_iterator::create(211, "passed iterators may not belong to container")); + } + + // insert to array and return iterator + iterator result(this); + result.m_it.array_iterator = m_value.array->insert( + pos.m_it.array_iterator, + first.m_it.array_iterator, + last.m_it.array_iterator); + return result; + } + + /*! + @brief inserts elements + + Inserts elements from initializer list @a ilist before iterator @a pos. + + @param[in] pos iterator before which the content will be inserted; may be + the end() iterator + @param[in] ilist initializer list to insert the values from + + @throw type_error.309 if called on JSON values other than arrays; example: + `"cannot use insert() with string"` + @throw invalid_iterator.202 if @a pos is not an iterator of *this; + example: `"iterator does not fit current value"` + + @return iterator pointing to the first element inserted, or @a pos if + `ilist` is empty + + @complexity Linear in `ilist.size()` plus linear in the distance between + @a pos and end of the container. + + @liveexample{The example shows how `insert()` is used.,insert__ilist} + + @since version 1.0.0 + */ + iterator insert(const_iterator pos, initializer_list_t ilist) + { + // insert only works for arrays + if (JSON_UNLIKELY(not is_array())) + { + JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); + } + + // check if iterator pos fits to this JSON value + if (JSON_UNLIKELY(pos.m_object != this)) + { + JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value")); + } + + // insert to array and return iterator + iterator result(this); + result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, ilist.begin(), ilist.end()); + return result; + } + + /*! + @brief inserts elements + + Inserts elements from range `[first, last)`. + + @param[in] first begin of the range of elements to insert + @param[in] last end of the range of elements to insert + + @throw type_error.309 if called on JSON values other than objects; example: + `"cannot use insert() with string"` + @throw invalid_iterator.202 if iterator @a first or @a last does does not + point to an object; example: `"iterators first and last must point to + objects"` + @throw invalid_iterator.210 if @a first and @a last do not belong to the + same JSON value; example: `"iterators do not fit"` + + @complexity Logarithmic: `O(N*log(size() + N))`, where `N` is the number + of elements to insert. + + @liveexample{The example shows how `insert()` is used.,insert__range_object} + + @since version 3.0.0 + */ + void insert(const_iterator first, const_iterator last) + { + // insert only works for objects + if (JSON_UNLIKELY(not is_object())) + { + JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); + } + + // check if range iterators belong to the same JSON object + if (JSON_UNLIKELY(first.m_object != last.m_object)) + { + JSON_THROW(invalid_iterator::create(210, "iterators do not fit")); + } + + // passed iterators must belong to objects + if (JSON_UNLIKELY(not first.m_object->is_object())) + { + JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects")); + } + + m_value.object->insert(first.m_it.object_iterator, last.m_it.object_iterator); + } + + /*! + @brief updates a JSON object from another object, overwriting existing keys + + Inserts all values from JSON object @a j and overwrites existing keys. + + @param[in] j JSON object to read values from + + @throw type_error.312 if called on JSON values other than objects; example: + `"cannot use update() with string"` + + @complexity O(N*log(size() + N)), where N is the number of elements to + insert. + + @liveexample{The example shows how `update()` is used.,update} + + @sa https://docs.python.org/3.6/library/stdtypes.html#dict.update + + @since version 3.0.0 + */ + void update(const_reference j) + { + // implicitly convert null value to an empty object + if (is_null()) + { + m_type = value_t::object; + m_value.object = create(); + assert_invariant(); + } + + if (JSON_UNLIKELY(not is_object())) + { + JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(type_name()))); + } + if (JSON_UNLIKELY(not j.is_object())) + { + JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(j.type_name()))); + } + + for (auto it = j.cbegin(); it != j.cend(); ++it) + { + m_value.object->operator[](it.key()) = it.value(); + } + } + + /*! + @brief updates a JSON object from another object, overwriting existing keys + + Inserts all values from from range `[first, last)` and overwrites existing + keys. + + @param[in] first begin of the range of elements to insert + @param[in] last end of the range of elements to insert + + @throw type_error.312 if called on JSON values other than objects; example: + `"cannot use update() with string"` + @throw invalid_iterator.202 if iterator @a first or @a last does does not + point to an object; example: `"iterators first and last must point to + objects"` + @throw invalid_iterator.210 if @a first and @a last do not belong to the + same JSON value; example: `"iterators do not fit"` + + @complexity O(N*log(size() + N)), where N is the number of elements to + insert. + + @liveexample{The example shows how `update()` is used__range.,update} + + @sa https://docs.python.org/3.6/library/stdtypes.html#dict.update + + @since version 3.0.0 + */ + void update(const_iterator first, const_iterator last) + { + // implicitly convert null value to an empty object + if (is_null()) + { + m_type = value_t::object; + m_value.object = create(); + assert_invariant(); + } + + if (JSON_UNLIKELY(not is_object())) + { + JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(type_name()))); + } + + // check if range iterators belong to the same JSON object + if (JSON_UNLIKELY(first.m_object != last.m_object)) + { + JSON_THROW(invalid_iterator::create(210, "iterators do not fit")); + } + + // passed iterators must belong to objects + if (JSON_UNLIKELY(not first.m_object->is_object() + or not first.m_object->is_object())) + { + JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects")); + } + + for (auto it = first; it != last; ++it) + { + m_value.object->operator[](it.key()) = it.value(); + } + } + + /*! + @brief exchanges the values + + Exchanges the contents of the JSON value with those of @a other. Does not + invoke any move, copy, or swap operations on individual elements. All + iterators and references remain valid. The past-the-end iterator is + invalidated. + + @param[in,out] other JSON value to exchange the contents with + + @complexity Constant. + + @liveexample{The example below shows how JSON values can be swapped with + `swap()`.,swap__reference} + + @since version 1.0.0 + */ + void swap(reference other) noexcept ( + std::is_nothrow_move_constructible::value and + std::is_nothrow_move_assignable::value and + std::is_nothrow_move_constructible::value and + std::is_nothrow_move_assignable::value + ) + { + std::swap(m_type, other.m_type); + std::swap(m_value, other.m_value); + assert_invariant(); + } + + /*! + @brief exchanges the values + + Exchanges the contents of a JSON array with those of @a other. Does not + invoke any move, copy, or swap operations on individual elements. All + iterators and references remain valid. The past-the-end iterator is + invalidated. + + @param[in,out] other array to exchange the contents with + + @throw type_error.310 when JSON value is not an array; example: `"cannot + use swap() with string"` + + @complexity Constant. + + @liveexample{The example below shows how arrays can be swapped with + `swap()`.,swap__array_t} + + @since version 1.0.0 + */ + void swap(array_t& other) + { + // swap only works for arrays + if (JSON_LIKELY(is_array())) + { + std::swap(*(m_value.array), other); + } + else + { + JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name()))); + } + } + + /*! + @brief exchanges the values + + Exchanges the contents of a JSON object with those of @a other. Does not + invoke any move, copy, or swap operations on individual elements. All + iterators and references remain valid. The past-the-end iterator is + invalidated. + + @param[in,out] other object to exchange the contents with + + @throw type_error.310 when JSON value is not an object; example: + `"cannot use swap() with string"` + + @complexity Constant. + + @liveexample{The example below shows how objects can be swapped with + `swap()`.,swap__object_t} + + @since version 1.0.0 + */ + void swap(object_t& other) + { + // swap only works for objects + if (JSON_LIKELY(is_object())) + { + std::swap(*(m_value.object), other); + } + else + { + JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name()))); + } + } + + /*! + @brief exchanges the values + + Exchanges the contents of a JSON string with those of @a other. Does not + invoke any move, copy, or swap operations on individual elements. All + iterators and references remain valid. The past-the-end iterator is + invalidated. + + @param[in,out] other string to exchange the contents with + + @throw type_error.310 when JSON value is not a string; example: `"cannot + use swap() with boolean"` + + @complexity Constant. + + @liveexample{The example below shows how strings can be swapped with + `swap()`.,swap__string_t} + + @since version 1.0.0 + */ + void swap(string_t& other) + { + // swap only works for strings + if (JSON_LIKELY(is_string())) + { + std::swap(*(m_value.string), other); + } + else + { + JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name()))); + } + } + + /// @} + + public: + ////////////////////////////////////////// + // lexicographical comparison operators // + ////////////////////////////////////////// + + /// @name lexicographical comparison operators + /// @{ + + /*! + @brief comparison: equal + + Compares two JSON values for equality according to the following rules: + - Two JSON values are equal if (1) they are from the same type and (2) + their stored values are the same according to their respective + `operator==`. + - Integer and floating-point numbers are automatically converted before + comparison. Note than two NaN values are always treated as unequal. + - Two JSON null values are equal. + + @note Floating-point inside JSON values numbers are compared with + `json::number_float_t::operator==` which is `double::operator==` by + default. To compare floating-point while respecting an epsilon, an alternative + [comparison function](https://github.com/mariokonrad/marnav/blob/master/src/marnav/math/floatingpoint.hpp#L34-#L39) + could be used, for instance + @code {.cpp} + template::value, T>::type> + inline bool is_same(T a, T b, T epsilon = std::numeric_limits::epsilon()) noexcept + { + return std::abs(a - b) <= epsilon; + } + @endcode + + @note NaN values never compare equal to themselves or to other NaN values. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether the values @a lhs and @a rhs are equal + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @complexity Linear. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__equal} + + @since version 1.0.0 + */ + friend bool operator==(const_reference lhs, const_reference rhs) noexcept + { + const auto lhs_type = lhs.type(); + const auto rhs_type = rhs.type(); + + if (lhs_type == rhs_type) + { + switch (lhs_type) + { + case value_t::array: + return (*lhs.m_value.array == *rhs.m_value.array); + + case value_t::object: + return (*lhs.m_value.object == *rhs.m_value.object); + + case value_t::null: + return true; + + case value_t::string: + return (*lhs.m_value.string == *rhs.m_value.string); + + case value_t::boolean: + return (lhs.m_value.boolean == rhs.m_value.boolean); + + case value_t::number_integer: + return (lhs.m_value.number_integer == rhs.m_value.number_integer); + + case value_t::number_unsigned: + return (lhs.m_value.number_unsigned == rhs.m_value.number_unsigned); + + case value_t::number_float: + return (lhs.m_value.number_float == rhs.m_value.number_float); + + default: + return false; + } + } + else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float) + { + return (static_cast(lhs.m_value.number_integer) == rhs.m_value.number_float); + } + else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer) + { + return (lhs.m_value.number_float == static_cast(rhs.m_value.number_integer)); + } + else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float) + { + return (static_cast(lhs.m_value.number_unsigned) == rhs.m_value.number_float); + } + else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned) + { + return (lhs.m_value.number_float == static_cast(rhs.m_value.number_unsigned)); + } + else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer) + { + return (static_cast(lhs.m_value.number_unsigned) == rhs.m_value.number_integer); + } + else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned) + { + return (lhs.m_value.number_integer == static_cast(rhs.m_value.number_unsigned)); + } + + return false; + } + + /*! + @brief comparison: equal + @copydoc operator==(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator==(const_reference lhs, const ScalarType rhs) noexcept + { + return (lhs == basic_json(rhs)); + } + + /*! + @brief comparison: equal + @copydoc operator==(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator==(const ScalarType lhs, const_reference rhs) noexcept + { + return (basic_json(lhs) == rhs); + } + + /*! + @brief comparison: not equal + + Compares two JSON values for inequality by calculating `not (lhs == rhs)`. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether the values @a lhs and @a rhs are not equal + + @complexity Linear. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__notequal} + + @since version 1.0.0 + */ + friend bool operator!=(const_reference lhs, const_reference rhs) noexcept + { + return not (lhs == rhs); + } + + /*! + @brief comparison: not equal + @copydoc operator!=(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator!=(const_reference lhs, const ScalarType rhs) noexcept + { + return (lhs != basic_json(rhs)); + } + + /*! + @brief comparison: not equal + @copydoc operator!=(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator!=(const ScalarType lhs, const_reference rhs) noexcept + { + return (basic_json(lhs) != rhs); + } + + /*! + @brief comparison: less than + + Compares whether one JSON value @a lhs is less than another JSON value @a + rhs according to the following rules: + - If @a lhs and @a rhs have the same type, the values are compared using + the default `<` operator. + - Integer and floating-point numbers are automatically converted before + comparison + - In case @a lhs and @a rhs have different types, the values are ignored + and the order of the types is considered, see + @ref operator<(const value_t, const value_t). + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether @a lhs is less than @a rhs + + @complexity Linear. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__less} + + @since version 1.0.0 + */ + friend bool operator<(const_reference lhs, const_reference rhs) noexcept + { + const auto lhs_type = lhs.type(); + const auto rhs_type = rhs.type(); + + if (lhs_type == rhs_type) + { + switch (lhs_type) + { + case value_t::array: + return (*lhs.m_value.array) < (*rhs.m_value.array); + + case value_t::object: + return *lhs.m_value.object < *rhs.m_value.object; + + case value_t::null: + return false; + + case value_t::string: + return *lhs.m_value.string < *rhs.m_value.string; + + case value_t::boolean: + return lhs.m_value.boolean < rhs.m_value.boolean; + + case value_t::number_integer: + return lhs.m_value.number_integer < rhs.m_value.number_integer; + + case value_t::number_unsigned: + return lhs.m_value.number_unsigned < rhs.m_value.number_unsigned; + + case value_t::number_float: + return lhs.m_value.number_float < rhs.m_value.number_float; + + default: + return false; + } + } + else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float) + { + return static_cast(lhs.m_value.number_integer) < rhs.m_value.number_float; + } + else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer) + { + return lhs.m_value.number_float < static_cast(rhs.m_value.number_integer); + } + else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float) + { + return static_cast(lhs.m_value.number_unsigned) < rhs.m_value.number_float; + } + else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned) + { + return lhs.m_value.number_float < static_cast(rhs.m_value.number_unsigned); + } + else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned) + { + return lhs.m_value.number_integer < static_cast(rhs.m_value.number_unsigned); + } + else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer) + { + return static_cast(lhs.m_value.number_unsigned) < rhs.m_value.number_integer; + } + + // We only reach this line if we cannot compare values. In that case, + // we compare types. Note we have to call the operator explicitly, + // because MSVC has problems otherwise. + return operator<(lhs_type, rhs_type); + } + + /*! + @brief comparison: less than + @copydoc operator<(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator<(const_reference lhs, const ScalarType rhs) noexcept + { + return (lhs < basic_json(rhs)); + } + + /*! + @brief comparison: less than + @copydoc operator<(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator<(const ScalarType lhs, const_reference rhs) noexcept + { + return (basic_json(lhs) < rhs); + } + + /*! + @brief comparison: less than or equal + + Compares whether one JSON value @a lhs is less than or equal to another + JSON value by calculating `not (rhs < lhs)`. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether @a lhs is less than or equal to @a rhs + + @complexity Linear. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__greater} + + @since version 1.0.0 + */ + friend bool operator<=(const_reference lhs, const_reference rhs) noexcept + { + return not (rhs < lhs); + } + + /*! + @brief comparison: less than or equal + @copydoc operator<=(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator<=(const_reference lhs, const ScalarType rhs) noexcept + { + return (lhs <= basic_json(rhs)); + } + + /*! + @brief comparison: less than or equal + @copydoc operator<=(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator<=(const ScalarType lhs, const_reference rhs) noexcept + { + return (basic_json(lhs) <= rhs); + } + + /*! + @brief comparison: greater than + + Compares whether one JSON value @a lhs is greater than another + JSON value by calculating `not (lhs <= rhs)`. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether @a lhs is greater than to @a rhs + + @complexity Linear. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__lessequal} + + @since version 1.0.0 + */ + friend bool operator>(const_reference lhs, const_reference rhs) noexcept + { + return not (lhs <= rhs); + } + + /*! + @brief comparison: greater than + @copydoc operator>(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator>(const_reference lhs, const ScalarType rhs) noexcept + { + return (lhs > basic_json(rhs)); + } + + /*! + @brief comparison: greater than + @copydoc operator>(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator>(const ScalarType lhs, const_reference rhs) noexcept + { + return (basic_json(lhs) > rhs); + } + + /*! + @brief comparison: greater than or equal + + Compares whether one JSON value @a lhs is greater than or equal to another + JSON value by calculating `not (lhs < rhs)`. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether @a lhs is greater than or equal to @a rhs + + @complexity Linear. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__greaterequal} + + @since version 1.0.0 + */ + friend bool operator>=(const_reference lhs, const_reference rhs) noexcept + { + return not (lhs < rhs); + } + + /*! + @brief comparison: greater than or equal + @copydoc operator>=(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator>=(const_reference lhs, const ScalarType rhs) noexcept + { + return (lhs >= basic_json(rhs)); + } + + /*! + @brief comparison: greater than or equal + @copydoc operator>=(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator>=(const ScalarType lhs, const_reference rhs) noexcept + { + return (basic_json(lhs) >= rhs); + } + + /// @} + + /////////////////// + // serialization // + /////////////////// + + /// @name serialization + /// @{ + + /*! + @brief serialize to stream + + Serialize the given JSON value @a j to the output stream @a o. The JSON + value will be serialized using the @ref dump member function. + + - The indentation of the output can be controlled with the member variable + `width` of the output stream @a o. For instance, using the manipulator + `std::setw(4)` on @a o sets the indentation level to `4` and the + serialization result is the same as calling `dump(4)`. + + - The indentation character can be controlled with the member variable + `fill` of the output stream @a o. For instance, the manipulator + `std::setfill('\\t')` sets indentation to use a tab character rather than + the default space character. + + @param[in,out] o stream to serialize to + @param[in] j JSON value to serialize + + @return the stream @a o + + @throw type_error.316 if a string stored inside the JSON value is not + UTF-8 encoded + + @complexity Linear. + + @liveexample{The example below shows the serialization with different + parameters to `width` to adjust the indentation level.,operator_serialize} + + @since version 1.0.0; indentation character added in version 3.0.0 + */ + friend std::ostream& operator<<(std::ostream& o, const basic_json& j) + { + // read width member and use it as indentation parameter if nonzero + const bool pretty_print = (o.width() > 0); + const auto indentation = (pretty_print ? o.width() : 0); + + // reset width to 0 for subsequent calls to this stream + o.width(0); + + // do the actual serialization + serializer s(detail::output_adapter(o), o.fill()); + s.dump(j, pretty_print, false, static_cast(indentation)); + return o; + } + + /*! + @brief serialize to stream + @deprecated This stream operator is deprecated and will be removed in a + future version of the library. Please use + @ref operator<<(std::ostream&, const basic_json&) + instead; that is, replace calls like `j >> o;` with `o << j;`. + @since version 1.0.0; deprecated since version 3.0.0 + */ + JSON_DEPRECATED + friend std::ostream& operator>>(const basic_json& j, std::ostream& o) + { + return o << j; + } + + /// @} + + ///////////////////// + // deserialization // + ///////////////////// + + /// @name deserialization + /// @{ + + /*! + @brief deserialize from a compatible input + + This function reads from a compatible input. Examples are: + - an array of 1-byte values + - strings with character/literal type with size of 1 byte + - input streams + - container with contiguous storage of 1-byte values. Compatible container + types include `std::vector`, `std::string`, `std::array`, + `std::valarray`, and `std::initializer_list`. Furthermore, C-style + arrays can be used with `std::begin()`/`std::end()`. User-defined + containers can be used as long as they implement random-access iterators + and a contiguous storage. + + @pre Each element of the container has a size of 1 byte. Violating this + precondition yields undefined behavior. **This precondition is enforced + with a static assertion.** + + @pre The container storage is contiguous. Violating this precondition + yields undefined behavior. **This precondition is enforced with an + assertion.** + @pre Each element of the container has a size of 1 byte. Violating this + precondition yields undefined behavior. **This precondition is enforced + with a static assertion.** + + @warning There is no way to enforce all preconditions at compile-time. If + the function is called with a noncompliant container and with + assertions switched off, the behavior is undefined and will most + likely yield segmentation violation. + + @param[in] i input to read from + @param[in] cb a parser callback function of type @ref parser_callback_t + which is used to control the deserialization by filtering unwanted values + (optional) + + @return result of the deserialization + + @throw parse_error.101 if a parse error occurs; example: `""unexpected end + of input; expected string literal""` + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + + @complexity Linear in the length of the input. The parser is a predictive + LL(1) parser. The complexity can be higher if the parser callback function + @a cb has a super-linear complexity. + + @note A UTF-8 byte order mark is silently ignored. + + @liveexample{The example below demonstrates the `parse()` function reading + from an array.,parse__array__parser_callback_t} + + @liveexample{The example below demonstrates the `parse()` function with + and without callback function.,parse__string__parser_callback_t} + + @liveexample{The example below demonstrates the `parse()` function with + and without callback function.,parse__istream__parser_callback_t} + + @liveexample{The example below demonstrates the `parse()` function reading + from a contiguous container.,parse__contiguouscontainer__parser_callback_t} + + @since version 2.0.3 (contiguous containers) + */ + static basic_json parse(detail::input_adapter i, + const parser_callback_t cb = nullptr, + const bool allow_exceptions = true) + { + basic_json result; + parser(i, cb, allow_exceptions).parse(true, result); + return result; + } + + /*! + @copydoc basic_json parse(detail::input_adapter, const parser_callback_t) + */ + static basic_json parse(detail::input_adapter& i, + const parser_callback_t cb = nullptr, + const bool allow_exceptions = true) + { + basic_json result; + parser(i, cb, allow_exceptions).parse(true, result); + return result; + } + + static bool accept(detail::input_adapter i) + { + return parser(i).accept(true); + } + + static bool accept(detail::input_adapter& i) + { + return parser(i).accept(true); + } + + /*! + @brief deserialize from an iterator range with contiguous storage + + This function reads from an iterator range of a container with contiguous + storage of 1-byte values. Compatible container types include + `std::vector`, `std::string`, `std::array`, `std::valarray`, and + `std::initializer_list`. Furthermore, C-style arrays can be used with + `std::begin()`/`std::end()`. User-defined containers can be used as long + as they implement random-access iterators and a contiguous storage. + + @pre The iterator range is contiguous. Violating this precondition yields + undefined behavior. **This precondition is enforced with an assertion.** + @pre Each element in the range has a size of 1 byte. Violating this + precondition yields undefined behavior. **This precondition is enforced + with a static assertion.** + + @warning There is no way to enforce all preconditions at compile-time. If + the function is called with noncompliant iterators and with + assertions switched off, the behavior is undefined and will most + likely yield segmentation violation. + + @tparam IteratorType iterator of container with contiguous storage + @param[in] first begin of the range to parse (included) + @param[in] last end of the range to parse (excluded) + @param[in] cb a parser callback function of type @ref parser_callback_t + which is used to control the deserialization by filtering unwanted values + (optional) + @param[in] allow_exceptions whether to throw exceptions in case of a + parse error (optional, true by default) + + @return result of the deserialization + + @throw parse_error.101 in case of an unexpected token + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + + @complexity Linear in the length of the input. The parser is a predictive + LL(1) parser. The complexity can be higher if the parser callback function + @a cb has a super-linear complexity. + + @note A UTF-8 byte order mark is silently ignored. + + @liveexample{The example below demonstrates the `parse()` function reading + from an iterator range.,parse__iteratortype__parser_callback_t} + + @since version 2.0.3 + */ + template::iterator_category>::value, int>::type = 0> + static basic_json parse(IteratorType first, IteratorType last, + const parser_callback_t cb = nullptr, + const bool allow_exceptions = true) + { + basic_json result; + parser(detail::input_adapter(first, last), cb, allow_exceptions).parse(true, result); + return result; + } + + template::iterator_category>::value, int>::type = 0> + static bool accept(IteratorType first, IteratorType last) + { + return parser(detail::input_adapter(first, last)).accept(true); + } + + /*! + @brief deserialize from stream + @deprecated This stream operator is deprecated and will be removed in a + future version of the library. Please use + @ref operator>>(std::istream&, basic_json&) + instead; that is, replace calls like `j << i;` with `i >> j;`. + @since version 1.0.0; deprecated since version 3.0.0 + */ + JSON_DEPRECATED + friend std::istream& operator<<(basic_json& j, std::istream& i) + { + return operator>>(i, j); + } + + /*! + @brief deserialize from stream + + Deserializes an input stream to a JSON value. + + @param[in,out] i input stream to read a serialized JSON value from + @param[in,out] j JSON value to write the deserialized input to + + @throw parse_error.101 in case of an unexpected token + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + + @complexity Linear in the length of the input. The parser is a predictive + LL(1) parser. + + @note A UTF-8 byte order mark is silently ignored. + + @liveexample{The example below shows how a JSON value is constructed by + reading a serialization from a stream.,operator_deserialize} + + @sa parse(std::istream&, const parser_callback_t) for a variant with a + parser callback function to filter values while parsing + + @since version 1.0.0 + */ + friend std::istream& operator>>(std::istream& i, basic_json& j) + { + parser(detail::input_adapter(i)).parse(false, j); + return i; + } + + /// @} + + /////////////////////////// + // convenience functions // + /////////////////////////// + + /*! + @brief return the type as string + + Returns the type name as string to be used in error messages - usually to + indicate that a function was called on a wrong JSON type. + + @return a string representation of a the @a m_type member: + Value type | return value + ----------- | ------------- + null | `"null"` + boolean | `"boolean"` + string | `"string"` + number | `"number"` (for all number types) + object | `"object"` + array | `"array"` + discarded | `"discarded"` + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @complexity Constant. + + @liveexample{The following code exemplifies `type_name()` for all JSON + types.,type_name} + + @sa @ref type() -- return the type of the JSON value + @sa @ref operator value_t() -- return the type of the JSON value (implicit) + + @since version 1.0.0, public since 2.1.0, `const char*` and `noexcept` + since 3.0.0 + */ + const char* type_name() const noexcept + { + { + switch (m_type) + { + case value_t::null: + return "null"; + case value_t::object: + return "object"; + case value_t::array: + return "array"; + case value_t::string: + return "string"; + case value_t::boolean: + return "boolean"; + case value_t::discarded: + return "discarded"; + default: + return "number"; + } + } + } + + private: + ////////////////////// + // member variables // + ////////////////////// + + /// the type of the current element + value_t m_type = value_t::null; + + /// the value of the current element + json_value m_value = {}; + + ////////////////////////////////////////// + // binary serialization/deserialization // + ////////////////////////////////////////// + + /// @name binary serialization/deserialization support + /// @{ + + public: + /*! + @brief create a CBOR serialization of a given JSON value + + Serializes a given JSON value @a j to a byte vector using the CBOR (Concise + Binary Object Representation) serialization format. CBOR is a binary + serialization format which aims to be more compact than JSON itself, yet + more efficient to parse. + + The library uses the following mapping from JSON values types to + CBOR types according to the CBOR specification (RFC 7049): + + JSON value type | value/range | CBOR type | first byte + --------------- | ------------------------------------------ | ---------------------------------- | --------------- + null | `null` | Null | 0xF6 + boolean | `true` | True | 0xF5 + boolean | `false` | False | 0xF4 + number_integer | -9223372036854775808..-2147483649 | Negative integer (8 bytes follow) | 0x3B + number_integer | -2147483648..-32769 | Negative integer (4 bytes follow) | 0x3A + number_integer | -32768..-129 | Negative integer (2 bytes follow) | 0x39 + number_integer | -128..-25 | Negative integer (1 byte follow) | 0x38 + number_integer | -24..-1 | Negative integer | 0x20..0x37 + number_integer | 0..23 | Integer | 0x00..0x17 + number_integer | 24..255 | Unsigned integer (1 byte follow) | 0x18 + number_integer | 256..65535 | Unsigned integer (2 bytes follow) | 0x19 + number_integer | 65536..4294967295 | Unsigned integer (4 bytes follow) | 0x1A + number_integer | 4294967296..18446744073709551615 | Unsigned integer (8 bytes follow) | 0x1B + number_unsigned | 0..23 | Integer | 0x00..0x17 + number_unsigned | 24..255 | Unsigned integer (1 byte follow) | 0x18 + number_unsigned | 256..65535 | Unsigned integer (2 bytes follow) | 0x19 + number_unsigned | 65536..4294967295 | Unsigned integer (4 bytes follow) | 0x1A + number_unsigned | 4294967296..18446744073709551615 | Unsigned integer (8 bytes follow) | 0x1B + number_float | *any value* | Double-Precision Float | 0xFB + string | *length*: 0..23 | UTF-8 string | 0x60..0x77 + string | *length*: 23..255 | UTF-8 string (1 byte follow) | 0x78 + string | *length*: 256..65535 | UTF-8 string (2 bytes follow) | 0x79 + string | *length*: 65536..4294967295 | UTF-8 string (4 bytes follow) | 0x7A + string | *length*: 4294967296..18446744073709551615 | UTF-8 string (8 bytes follow) | 0x7B + array | *size*: 0..23 | array | 0x80..0x97 + array | *size*: 23..255 | array (1 byte follow) | 0x98 + array | *size*: 256..65535 | array (2 bytes follow) | 0x99 + array | *size*: 65536..4294967295 | array (4 bytes follow) | 0x9A + array | *size*: 4294967296..18446744073709551615 | array (8 bytes follow) | 0x9B + object | *size*: 0..23 | map | 0xA0..0xB7 + object | *size*: 23..255 | map (1 byte follow) | 0xB8 + object | *size*: 256..65535 | map (2 bytes follow) | 0xB9 + object | *size*: 65536..4294967295 | map (4 bytes follow) | 0xBA + object | *size*: 4294967296..18446744073709551615 | map (8 bytes follow) | 0xBB + + @note The mapping is **complete** in the sense that any JSON value type + can be converted to a CBOR value. + + @note If NaN or Infinity are stored inside a JSON number, they are + serialized properly. This behavior differs from the @ref dump() + function which serializes NaN or Infinity to `null`. + + @note The following CBOR types are not used in the conversion: + - byte strings (0x40..0x5F) + - UTF-8 strings terminated by "break" (0x7F) + - arrays terminated by "break" (0x9F) + - maps terminated by "break" (0xBF) + - date/time (0xC0..0xC1) + - bignum (0xC2..0xC3) + - decimal fraction (0xC4) + - bigfloat (0xC5) + - tagged items (0xC6..0xD4, 0xD8..0xDB) + - expected conversions (0xD5..0xD7) + - simple values (0xE0..0xF3, 0xF8) + - undefined (0xF7) + - half and single-precision floats (0xF9-0xFA) + - break (0xFF) + + @param[in] j JSON value to serialize + @return MessagePack serialization as byte vector + + @complexity Linear in the size of the JSON value @a j. + + @liveexample{The example shows the serialization of a JSON value to a byte + vector in CBOR format.,to_cbor} + + @sa http://cbor.io + @sa @ref from_cbor(const std::vector&, const size_t) for the + analogous deserialization + @sa @ref to_msgpack(const basic_json&) for the related MessagePack format + + @since version 2.0.9 + */ + static std::vector to_cbor(const basic_json& j) + { + std::vector result; + to_cbor(j, result); + return result; + } + + static void to_cbor(const basic_json& j, detail::output_adapter o) + { + binary_writer(o).write_cbor(j); + } + + static void to_cbor(const basic_json& j, detail::output_adapter o) + { + binary_writer(o).write_cbor(j); + } + + /*! + @brief create a MessagePack serialization of a given JSON value + + Serializes a given JSON value @a j to a byte vector using the MessagePack + serialization format. MessagePack is a binary serialization format which + aims to be more compact than JSON itself, yet more efficient to parse. + + The library uses the following mapping from JSON values types to + MessagePack types according to the MessagePack specification: + + JSON value type | value/range | MessagePack type | first byte + --------------- | --------------------------------- | ---------------- | ---------- + null | `null` | nil | 0xC0 + boolean | `true` | true | 0xC3 + boolean | `false` | false | 0xC2 + number_integer | -9223372036854775808..-2147483649 | int64 | 0xD3 + number_integer | -2147483648..-32769 | int32 | 0xD2 + number_integer | -32768..-129 | int16 | 0xD1 + number_integer | -128..-33 | int8 | 0xD0 + number_integer | -32..-1 | negative fixint | 0xE0..0xFF + number_integer | 0..127 | positive fixint | 0x00..0x7F + number_integer | 128..255 | uint 8 | 0xCC + number_integer | 256..65535 | uint 16 | 0xCD + number_integer | 65536..4294967295 | uint 32 | 0xCE + number_integer | 4294967296..18446744073709551615 | uint 64 | 0xCF + number_unsigned | 0..127 | positive fixint | 0x00..0x7F + number_unsigned | 128..255 | uint 8 | 0xCC + number_unsigned | 256..65535 | uint 16 | 0xCD + number_unsigned | 65536..4294967295 | uint 32 | 0xCE + number_unsigned | 4294967296..18446744073709551615 | uint 64 | 0xCF + number_float | *any value* | float 64 | 0xCB + string | *length*: 0..31 | fixstr | 0xA0..0xBF + string | *length*: 32..255 | str 8 | 0xD9 + string | *length*: 256..65535 | str 16 | 0xDA + string | *length*: 65536..4294967295 | str 32 | 0xDB + array | *size*: 0..15 | fixarray | 0x90..0x9F + array | *size*: 16..65535 | array 16 | 0xDC + array | *size*: 65536..4294967295 | array 32 | 0xDD + object | *size*: 0..15 | fix map | 0x80..0x8F + object | *size*: 16..65535 | map 16 | 0xDE + object | *size*: 65536..4294967295 | map 32 | 0xDF + + @note The mapping is **complete** in the sense that any JSON value type + can be converted to a MessagePack value. + + @note The following values can **not** be converted to a MessagePack value: + - strings with more than 4294967295 bytes + - arrays with more than 4294967295 elements + - objects with more than 4294967295 elements + + @note The following MessagePack types are not used in the conversion: + - bin 8 - bin 32 (0xC4..0xC6) + - ext 8 - ext 32 (0xC7..0xC9) + - float 32 (0xCA) + - fixext 1 - fixext 16 (0xD4..0xD8) + + @note Any MessagePack output created @ref to_msgpack can be successfully + parsed by @ref from_msgpack. + + @note If NaN or Infinity are stored inside a JSON number, they are + serialized properly. This behavior differs from the @ref dump() + function which serializes NaN or Infinity to `null`. + + @param[in] j JSON value to serialize + @return MessagePack serialization as byte vector + + @complexity Linear in the size of the JSON value @a j. + + @liveexample{The example shows the serialization of a JSON value to a byte + vector in MessagePack format.,to_msgpack} + + @sa http://msgpack.org + @sa @ref from_msgpack(const std::vector&, const size_t) for the + analogous deserialization + @sa @ref to_cbor(const basic_json& for the related CBOR format + + @since version 2.0.9 + */ + static std::vector to_msgpack(const basic_json& j) + { + std::vector result; + to_msgpack(j, result); + return result; + } + + static void to_msgpack(const basic_json& j, detail::output_adapter o) + { + binary_writer(o).write_msgpack(j); + } + + static void to_msgpack(const basic_json& j, detail::output_adapter o) + { + binary_writer(o).write_msgpack(j); + } + + /*! + @brief create a JSON value from an input in CBOR format + + Deserializes a given input @a i to a JSON value using the CBOR (Concise + Binary Object Representation) serialization format. + + The library maps CBOR types to JSON value types as follows: + + CBOR type | JSON value type | first byte + ---------------------- | --------------- | ---------- + Integer | number_unsigned | 0x00..0x17 + Unsigned integer | number_unsigned | 0x18 + Unsigned integer | number_unsigned | 0x19 + Unsigned integer | number_unsigned | 0x1A + Unsigned integer | number_unsigned | 0x1B + Negative integer | number_integer | 0x20..0x37 + Negative integer | number_integer | 0x38 + Negative integer | number_integer | 0x39 + Negative integer | number_integer | 0x3A + Negative integer | number_integer | 0x3B + Negative integer | number_integer | 0x40..0x57 + UTF-8 string | string | 0x60..0x77 + UTF-8 string | string | 0x78 + UTF-8 string | string | 0x79 + UTF-8 string | string | 0x7A + UTF-8 string | string | 0x7B + UTF-8 string | string | 0x7F + array | array | 0x80..0x97 + array | array | 0x98 + array | array | 0x99 + array | array | 0x9A + array | array | 0x9B + array | array | 0x9F + map | object | 0xA0..0xB7 + map | object | 0xB8 + map | object | 0xB9 + map | object | 0xBA + map | object | 0xBB + map | object | 0xBF + False | `false` | 0xF4 + True | `true` | 0xF5 + Nill | `null` | 0xF6 + Half-Precision Float | number_float | 0xF9 + Single-Precision Float | number_float | 0xFA + Double-Precision Float | number_float | 0xFB + + @warning The mapping is **incomplete** in the sense that not all CBOR + types can be converted to a JSON value. The following CBOR types + are not supported and will yield parse errors (parse_error.112): + - byte strings (0x40..0x5F) + - date/time (0xC0..0xC1) + - bignum (0xC2..0xC3) + - decimal fraction (0xC4) + - bigfloat (0xC5) + - tagged items (0xC6..0xD4, 0xD8..0xDB) + - expected conversions (0xD5..0xD7) + - simple values (0xE0..0xF3, 0xF8) + - undefined (0xF7) + + @warning CBOR allows map keys of any type, whereas JSON only allows + strings as keys in object values. Therefore, CBOR maps with keys + other than UTF-8 strings are rejected (parse_error.113). + + @note Any CBOR output created @ref to_cbor can be successfully parsed by + @ref from_cbor. + + @param[in] i an input in CBOR format convertible to an input adapter + @param[in] strict whether to expect the input to be consumed until EOF + (true by default) + @return deserialized JSON value + + @throw parse_error.110 if the given input ends prematurely or the end of + file was not reached when @a strict was set to true + @throw parse_error.112 if unsupported features from CBOR were + used in the given input @a v or if the input is not valid CBOR + @throw parse_error.113 if a string was expected as map key, but not found + + @complexity Linear in the size of the input @a i. + + @liveexample{The example shows the deserialization of a byte vector in CBOR + format to a JSON value.,from_cbor} + + @sa http://cbor.io + @sa @ref to_cbor(const basic_json&) for the analogous serialization + @sa @ref from_msgpack(detail::input_adapter, const bool) for the + related MessagePack format + + @since version 2.0.9; parameter @a start_index since 2.1.1; changed to + consume input adapters, removed start_index parameter, and added + @a strict parameter since 3.0.0 + */ + static basic_json from_cbor(detail::input_adapter i, + const bool strict = true) + { + return binary_reader(i).parse_cbor(strict); + } + + /*! + @copydoc from_cbor(detail::input_adapter, const bool) + */ + template::value, int> = 0> + static basic_json from_cbor(A1 && a1, A2 && a2, const bool strict = true) + { + return binary_reader(detail::input_adapter(std::forward(a1), std::forward(a2))).parse_cbor(strict); + } + + /*! + @brief create a JSON value from an input in MessagePack format + + Deserializes a given input @a i to a JSON value using the MessagePack + serialization format. + + The library maps MessagePack types to JSON value types as follows: + + MessagePack type | JSON value type | first byte + ---------------- | --------------- | ---------- + positive fixint | number_unsigned | 0x00..0x7F + fixmap | object | 0x80..0x8F + fixarray | array | 0x90..0x9F + fixstr | string | 0xA0..0xBF + nil | `null` | 0xC0 + false | `false` | 0xC2 + true | `true` | 0xC3 + float 32 | number_float | 0xCA + float 64 | number_float | 0xCB + uint 8 | number_unsigned | 0xCC + uint 16 | number_unsigned | 0xCD + uint 32 | number_unsigned | 0xCE + uint 64 | number_unsigned | 0xCF + int 8 | number_integer | 0xD0 + int 16 | number_integer | 0xD1 + int 32 | number_integer | 0xD2 + int 64 | number_integer | 0xD3 + str 8 | string | 0xD9 + str 16 | string | 0xDA + str 32 | string | 0xDB + array 16 | array | 0xDC + array 32 | array | 0xDD + map 16 | object | 0xDE + map 32 | object | 0xDF + negative fixint | number_integer | 0xE0-0xFF + + @warning The mapping is **incomplete** in the sense that not all + MessagePack types can be converted to a JSON value. The following + MessagePack types are not supported and will yield parse errors: + - bin 8 - bin 32 (0xC4..0xC6) + - ext 8 - ext 32 (0xC7..0xC9) + - fixext 1 - fixext 16 (0xD4..0xD8) + + @note Any MessagePack output created @ref to_msgpack can be successfully + parsed by @ref from_msgpack. + + @param[in] i an input in MessagePack format convertible to an input + adapter + @param[in] strict whether to expect the input to be consumed until EOF + (true by default) + + @throw parse_error.110 if the given input ends prematurely or the end of + file was not reached when @a strict was set to true + @throw parse_error.112 if unsupported features from MessagePack were + used in the given input @a i or if the input is not valid MessagePack + @throw parse_error.113 if a string was expected as map key, but not found + + @complexity Linear in the size of the input @a i. + + @liveexample{The example shows the deserialization of a byte vector in + MessagePack format to a JSON value.,from_msgpack} + + @sa http://msgpack.org + @sa @ref to_msgpack(const basic_json&) for the analogous serialization + @sa @ref from_cbor(detail::input_adapter, const bool) for the related CBOR + format + + @since version 2.0.9; parameter @a start_index since 2.1.1; changed to + consume input adapters, removed start_index parameter, and added + @a strict parameter since 3.0.0 + */ + static basic_json from_msgpack(detail::input_adapter i, + const bool strict = true) + { + return binary_reader(i).parse_msgpack(strict); + } + + /*! + @copydoc from_msgpack(detail::input_adapter, const bool) + */ + template::value, int> = 0> + static basic_json from_msgpack(A1 && a1, A2 && a2, const bool strict = true) + { + return binary_reader(detail::input_adapter(std::forward(a1), std::forward(a2))).parse_msgpack(strict); + } + + /// @} + + ////////////////////////// + // JSON Pointer support // + ////////////////////////// + + /// @name JSON Pointer functions + /// @{ + + /*! + @brief access specified element via JSON Pointer + + Uses a JSON pointer to retrieve a reference to the respective JSON value. + No bound checking is performed. Similar to @ref operator[](const typename + object_t::key_type&), `null` values are created in arrays and objects if + necessary. + + In particular: + - If the JSON pointer points to an object key that does not exist, it + is created an filled with a `null` value before a reference to it + is returned. + - If the JSON pointer points to an array index that does not exist, it + is created an filled with a `null` value before a reference to it + is returned. All indices between the current maximum and the given + index are also filled with `null`. + - The special value `-` is treated as a synonym for the index past the + end. + + @param[in] ptr a JSON pointer + + @return reference to the element pointed to by @a ptr + + @complexity Constant. + + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.404 if the JSON pointer can not be resolved + + @liveexample{The behavior is shown in the example.,operatorjson_pointer} + + @since version 2.0.0 + */ + reference operator[](const json_pointer& ptr) + { + return ptr.get_unchecked(this); + } + + /*! + @brief access specified element via JSON Pointer + + Uses a JSON pointer to retrieve a reference to the respective JSON value. + No bound checking is performed. The function does not change the JSON + value; no `null` values are created. In particular, the the special value + `-` yields an exception. + + @param[in] ptr JSON pointer to the desired element + + @return const reference to the element pointed to by @a ptr + + @complexity Constant. + + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.402 if the array index '-' is used + @throw out_of_range.404 if the JSON pointer can not be resolved + + @liveexample{The behavior is shown in the example.,operatorjson_pointer_const} + + @since version 2.0.0 + */ + const_reference operator[](const json_pointer& ptr) const + { + return ptr.get_unchecked(this); + } + + /*! + @brief access specified element via JSON Pointer + + Returns a reference to the element at with specified JSON pointer @a ptr, + with bounds checking. + + @param[in] ptr JSON pointer to the desired element + + @return reference to the element pointed to by @a ptr + + @throw parse_error.106 if an array index in the passed JSON pointer @a ptr + begins with '0'. See example below. + + @throw parse_error.109 if an array index in the passed JSON pointer @a ptr + is not a number. See example below. + + @throw out_of_range.401 if an array index in the passed JSON pointer @a ptr + is out of range. See example below. + + @throw out_of_range.402 if the array index '-' is used in the passed JSON + pointer @a ptr. As `at` provides checked access (and no elements are + implicitly inserted), the index '-' is always invalid. See example below. + + @throw out_of_range.403 if the JSON pointer describes a key of an object + which cannot be found. See example below. + + @throw out_of_range.404 if the JSON pointer @a ptr can not be resolved. + See example below. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Constant. + + @since version 2.0.0 + + @liveexample{The behavior is shown in the example.,at_json_pointer} + */ + reference at(const json_pointer& ptr) + { + return ptr.get_checked(this); + } + + /*! + @brief access specified element via JSON Pointer + + Returns a const reference to the element at with specified JSON pointer @a + ptr, with bounds checking. + + @param[in] ptr JSON pointer to the desired element + + @return reference to the element pointed to by @a ptr + + @throw parse_error.106 if an array index in the passed JSON pointer @a ptr + begins with '0'. See example below. + + @throw parse_error.109 if an array index in the passed JSON pointer @a ptr + is not a number. See example below. + + @throw out_of_range.401 if an array index in the passed JSON pointer @a ptr + is out of range. See example below. + + @throw out_of_range.402 if the array index '-' is used in the passed JSON + pointer @a ptr. As `at` provides checked access (and no elements are + implicitly inserted), the index '-' is always invalid. See example below. + + @throw out_of_range.403 if the JSON pointer describes a key of an object + which cannot be found. See example below. + + @throw out_of_range.404 if the JSON pointer @a ptr can not be resolved. + See example below. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Constant. + + @since version 2.0.0 + + @liveexample{The behavior is shown in the example.,at_json_pointer_const} + */ + const_reference at(const json_pointer& ptr) const + { + return ptr.get_checked(this); + } + + /*! + @brief return flattened JSON value + + The function creates a JSON object whose keys are JSON pointers (see [RFC + 6901](https://tools.ietf.org/html/rfc6901)) and whose values are all + primitive. The original JSON value can be restored using the @ref + unflatten() function. + + @return an object that maps JSON pointers to primitive values + + @note Empty objects and arrays are flattened to `null` and will not be + reconstructed correctly by the @ref unflatten() function. + + @complexity Linear in the size the JSON value. + + @liveexample{The following code shows how a JSON object is flattened to an + object whose keys consist of JSON pointers.,flatten} + + @sa @ref unflatten() for the reverse function + + @since version 2.0.0 + */ + basic_json flatten() const + { + basic_json result(value_t::object); + json_pointer::flatten("", *this, result); + return result; + } + + /*! + @brief unflatten a previously flattened JSON value + + The function restores the arbitrary nesting of a JSON value that has been + flattened before using the @ref flatten() function. The JSON value must + meet certain constraints: + 1. The value must be an object. + 2. The keys must be JSON pointers (see + [RFC 6901](https://tools.ietf.org/html/rfc6901)) + 3. The mapped values must be primitive JSON types. + + @return the original JSON from a flattened version + + @note Empty objects and arrays are flattened by @ref flatten() to `null` + values and can not unflattened to their original type. Apart from + this example, for a JSON value `j`, the following is always true: + `j == j.flatten().unflatten()`. + + @complexity Linear in the size the JSON value. + + @throw type_error.314 if value is not an object + @throw type_error.315 if object values are not primitive + + @liveexample{The following code shows how a flattened JSON object is + unflattened into the original nested JSON object.,unflatten} + + @sa @ref flatten() for the reverse function + + @since version 2.0.0 + */ + basic_json unflatten() const + { + return json_pointer::unflatten(*this); + } + + /// @} + + ////////////////////////// + // JSON Patch functions // + ////////////////////////// + + /// @name JSON Patch functions + /// @{ + + /*! + @brief applies a JSON patch + + [JSON Patch](http://jsonpatch.com) defines a JSON document structure for + expressing a sequence of operations to apply to a JSON) document. With + this function, a JSON Patch is applied to the current JSON value by + executing all operations from the patch. + + @param[in] json_patch JSON patch document + @return patched document + + @note The application of a patch is atomic: Either all operations succeed + and the patched document is returned or an exception is thrown. In + any case, the original value is not changed: the patch is applied + to a copy of the value. + + @throw parse_error.104 if the JSON patch does not consist of an array of + objects + + @throw parse_error.105 if the JSON patch is malformed (e.g., mandatory + attributes are missing); example: `"operation add must have member path"` + + @throw out_of_range.401 if an array index is out of range. + + @throw out_of_range.403 if a JSON pointer inside the patch could not be + resolved successfully in the current JSON value; example: `"key baz not + found"` + + @throw out_of_range.405 if JSON pointer has no parent ("add", "remove", + "move") + + @throw other_error.501 if "test" operation was unsuccessful + + @complexity Linear in the size of the JSON value and the length of the + JSON patch. As usually only a fraction of the JSON value is affected by + the patch, the complexity can usually be neglected. + + @liveexample{The following code shows how a JSON patch is applied to a + value.,patch} + + @sa @ref diff -- create a JSON patch by comparing two JSON values + + @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902) + @sa [RFC 6901 (JSON Pointer)](https://tools.ietf.org/html/rfc6901) + + @since version 2.0.0 + */ + basic_json patch(const basic_json& json_patch) const + { + // make a working copy to apply the patch to + basic_json result = *this; + + // the valid JSON Patch operations + enum class patch_operations {add, remove, replace, move, copy, test, invalid}; + + const auto get_op = [](const std::string & op) + { + if (op == "add") + { + return patch_operations::add; + } + if (op == "remove") + { + return patch_operations::remove; + } + if (op == "replace") + { + return patch_operations::replace; + } + if (op == "move") + { + return patch_operations::move; + } + if (op == "copy") + { + return patch_operations::copy; + } + if (op == "test") + { + return patch_operations::test; + } + + return patch_operations::invalid; + }; + + // wrapper for "add" operation; add value at ptr + const auto operation_add = [&result](json_pointer & ptr, basic_json val) + { + // adding to the root of the target document means replacing it + if (ptr.is_root()) + { + result = val; + } + else + { + // make sure the top element of the pointer exists + json_pointer top_pointer = ptr.top(); + if (top_pointer != ptr) + { + result.at(top_pointer); + } + + // get reference to parent of JSON pointer ptr + const auto last_path = ptr.pop_back(); + basic_json& parent = result[ptr]; + + switch (parent.m_type) + { + case value_t::null: + case value_t::object: + { + // use operator[] to add value + parent[last_path] = val; + break; + } + + case value_t::array: + { + if (last_path == "-") + { + // special case: append to back + parent.push_back(val); + } + else + { + const auto idx = json_pointer::array_index(last_path); + if (JSON_UNLIKELY(static_cast(idx) > parent.size())) + { + // avoid undefined behavior + JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range")); + } + else + { + // default case: insert add offset + parent.insert(parent.begin() + static_cast(idx), val); + } + } + break; + } + + default: + { + // if there exists a parent it cannot be primitive + assert(false); // LCOV_EXCL_LINE + } + } + } + }; + + // wrapper for "remove" operation; remove value at ptr + const auto operation_remove = [&result](json_pointer & ptr) + { + // get reference to parent of JSON pointer ptr + const auto last_path = ptr.pop_back(); + basic_json& parent = result.at(ptr); + + // remove child + if (parent.is_object()) + { + // perform range check + auto it = parent.find(last_path); + if (JSON_LIKELY(it != parent.end())) + { + parent.erase(it); + } + else + { + JSON_THROW(out_of_range::create(403, "key '" + last_path + "' not found")); + } + } + else if (parent.is_array()) + { + // note erase performs range check + parent.erase(static_cast(json_pointer::array_index(last_path))); + } + }; + + // type check: top level value must be an array + if (JSON_UNLIKELY(not json_patch.is_array())) + { + JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects")); + } + + // iterate and apply the operations + for (const auto& val : json_patch) + { + // wrapper to get a value for an operation + const auto get_value = [&val](const std::string & op, + const std::string & member, + bool string_type) -> basic_json& + { + // find value + auto it = val.m_value.object->find(member); + + // context-sensitive error message + const auto error_msg = (op == "op") ? "operation" : "operation '" + op + "'"; + + // check if desired value is present + if (JSON_UNLIKELY(it == val.m_value.object->end())) + { + JSON_THROW(parse_error::create(105, 0, error_msg + " must have member '" + member + "'")); + } + + // check if result is of type string + if (JSON_UNLIKELY(string_type and not it->second.is_string())) + { + JSON_THROW(parse_error::create(105, 0, error_msg + " must have string member '" + member + "'")); + } + + // no error: return value + return it->second; + }; + + // type check: every element of the array must be an object + if (JSON_UNLIKELY(not val.is_object())) + { + JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects")); + } + + // collect mandatory members + const std::string op = get_value("op", "op", true); + const std::string path = get_value(op, "path", true); + json_pointer ptr(path); + + switch (get_op(op)) + { + case patch_operations::add: + { + operation_add(ptr, get_value("add", "value", false)); + break; + } + + case patch_operations::remove: + { + operation_remove(ptr); + break; + } + + case patch_operations::replace: + { + // the "path" location must exist - use at() + result.at(ptr) = get_value("replace", "value", false); + break; + } + + case patch_operations::move: + { + const std::string from_path = get_value("move", "from", true); + json_pointer from_ptr(from_path); + + // the "from" location must exist - use at() + basic_json v = result.at(from_ptr); + + // The move operation is functionally identical to a + // "remove" operation on the "from" location, followed + // immediately by an "add" operation at the target + // location with the value that was just removed. + operation_remove(from_ptr); + operation_add(ptr, v); + break; + } + + case patch_operations::copy: + { + const std::string from_path = get_value("copy", "from", true); + const json_pointer from_ptr(from_path); + + // the "from" location must exist - use at() + basic_json v = result.at(from_ptr); + + // The copy is functionally identical to an "add" + // operation at the target location using the value + // specified in the "from" member. + operation_add(ptr, v); + break; + } + + case patch_operations::test: + { + bool success = false; + 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)); + } + JSON_CATCH (out_of_range&) + { + // ignore out of range errors: success remains false + } + + // throw an exception if test fails + if (JSON_UNLIKELY(not success)) + { + JSON_THROW(other_error::create(501, "unsuccessful: " + val.dump())); + } + + break; + } + + case patch_operations::invalid: + { + // op must be "add", "remove", "replace", "move", "copy", or + // "test" + JSON_THROW(parse_error::create(105, 0, "operation value '" + op + "' is invalid")); + } + } + } + + return result; + } + + /*! + @brief creates a diff as a JSON patch + + Creates a [JSON Patch](http://jsonpatch.com) so that value @a source can + be changed into the value @a target by calling @ref patch function. + + @invariant For two JSON values @a source and @a target, the following code + yields always `true`: + @code {.cpp} + source.patch(diff(source, target)) == target; + @endcode + + @note Currently, only `remove`, `add`, and `replace` operations are + generated. + + @param[in] source JSON value to compare from + @param[in] target JSON value to compare against + @param[in] path helper value to create JSON pointers + + @return a JSON patch to convert the @a source to @a target + + @complexity Linear in the lengths of @a source and @a target. + + @liveexample{The following code shows how a JSON patch is created as a + diff for two JSON values.,diff} + + @sa @ref patch -- apply a JSON patch + + @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902) + + @since version 2.0.0 + */ + static basic_json diff(const basic_json& source, const basic_json& target, + const std::string& path = "") + { + // the patch + basic_json result(value_t::array); + + // if the values are the same, return empty patch + if (source == target) + { + return result; + } + + if (source.type() != target.type()) + { + // different types: replace value + result.push_back( + { + {"op", "replace"}, {"path", path}, {"value", target} + }); + } + else + { + switch (source.type()) + { + case value_t::array: + { + // first pass: traverse common elements + std::size_t i = 0; + while (i < source.size() and i < target.size()) + { + // recursive call to compare array values at index i + auto temp_diff = diff(source[i], target[i], path + "/" + std::to_string(i)); + result.insert(result.end(), temp_diff.begin(), temp_diff.end()); + ++i; + } + + // i now reached the end of at least one array + // in a second pass, traverse the remaining elements + + // remove my remaining elements + const auto end_index = static_cast(result.size()); + while (i < source.size()) + { + // add operations in reverse order to avoid invalid + // indices + result.insert(result.begin() + end_index, object( + { + {"op", "remove"}, + {"path", path + "/" + std::to_string(i)} + })); + ++i; + } + + // add other remaining elements + while (i < target.size()) + { + result.push_back( + { + {"op", "add"}, + {"path", path + "/" + std::to_string(i)}, + {"value", target[i]} + }); + ++i; + } + + break; + } + + case value_t::object: + { + // first pass: traverse this object's elements + for (auto it = source.cbegin(); it != source.cend(); ++it) + { + // escape the key name to be used in a JSON patch + const auto key = json_pointer::escape(it.key()); + + if (target.find(it.key()) != target.end()) + { + // recursive call to compare object values at key it + auto temp_diff = diff(it.value(), target[it.key()], path + "/" + key); + result.insert(result.end(), temp_diff.begin(), temp_diff.end()); + } + else + { + // found a key that is not in o -> remove it + result.push_back(object( + { + {"op", "remove"}, {"path", path + "/" + key} + })); + } + } + + // second pass: traverse other object's elements + for (auto it = target.cbegin(); it != target.cend(); ++it) + { + if (source.find(it.key()) == source.end()) + { + // found a key that is not in this -> add it + const auto key = json_pointer::escape(it.key()); + result.push_back( + { + {"op", "add"}, {"path", path + "/" + key}, + {"value", it.value()} + }); + } + } + + break; + } + + default: + { + // both primitive type: replace value + result.push_back( + { + {"op", "replace"}, {"path", path}, {"value", target} + }); + break; + } + } + } + + return result; + } + + /// @} +}; + +////////////////// +// json_pointer // +////////////////// + +NLOHMANN_BASIC_JSON_TPL_DECLARATION +NLOHMANN_BASIC_JSON_TPL& +json_pointer::get_and_create(NLOHMANN_BASIC_JSON_TPL& j) const +{ + using size_type = typename NLOHMANN_BASIC_JSON_TPL::size_type; + auto result = &j; + + // in case no reference tokens exist, return a reference to the JSON value + // j which will be overwritten by a primitive value + for (const auto& reference_token : reference_tokens) + { + switch (result->m_type) + { + case detail::value_t::null: + { + if (reference_token == "0") + { + // start a new array if reference token is 0 + result = &result->operator[](0); + } + else + { + // start a new object otherwise + result = &result->operator[](reference_token); + } + break; + } + + case detail::value_t::object: + { + // create an entry in the object + result = &result->operator[](reference_token); + break; + } + + case detail::value_t::array: + { + // create an entry in the array + JSON_TRY + { + result = &result->operator[](static_cast(array_index(reference_token))); + } + JSON_CATCH(std::invalid_argument&) + { + JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number")); + } + break; + } + + /* + The following code is only reached if there exists a reference + token _and_ the current value is primitive. In this case, we have + an error situation, because primitive values may only occur as + single value; that is, with an empty list of reference tokens. + */ + default: + JSON_THROW(detail::type_error::create(313, "invalid value to unflatten")); + } + } + + return *result; +} + +NLOHMANN_BASIC_JSON_TPL_DECLARATION +NLOHMANN_BASIC_JSON_TPL& +json_pointer::get_unchecked(NLOHMANN_BASIC_JSON_TPL* ptr) const +{ + using size_type = typename NLOHMANN_BASIC_JSON_TPL::size_type; + for (const auto& reference_token : reference_tokens) + { + // convert null values to arrays or objects before continuing + if (ptr->m_type == detail::value_t::null) + { + // check if reference token is a number + const bool nums = + std::all_of(reference_token.begin(), reference_token.end(), + [](const char x) + { + return (x >= '0' and x <= '9'); + }); + + // change value to array for numbers or "-" or to object otherwise + *ptr = (nums or reference_token == "-") + ? detail::value_t::array + : detail::value_t::object; + } + + switch (ptr->m_type) + { + case detail::value_t::object: + { + // use unchecked object access + ptr = &ptr->operator[](reference_token); + break; + } + + case detail::value_t::array: + { + // error condition (cf. RFC 6901, Sect. 4) + if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0')) + { + JSON_THROW(detail::parse_error::create(106, 0, + "array index '" + reference_token + + "' must not begin with '0'")); + } + + if (reference_token == "-") + { + // explicitly treat "-" as index beyond the end + ptr = &ptr->operator[](ptr->m_value.array->size()); + } + else + { + // convert array index to number; unchecked access + JSON_TRY + { + ptr = &ptr->operator[]( + static_cast(array_index(reference_token))); + } + JSON_CATCH(std::invalid_argument&) + { + JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number")); + } + } + break; + } + + default: + JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'")); + } + } + + return *ptr; +} + +NLOHMANN_BASIC_JSON_TPL_DECLARATION +NLOHMANN_BASIC_JSON_TPL& +json_pointer::get_checked(NLOHMANN_BASIC_JSON_TPL* ptr) const +{ + using size_type = typename NLOHMANN_BASIC_JSON_TPL::size_type; + for (const auto& reference_token : reference_tokens) + { + switch (ptr->m_type) + { + case detail::value_t::object: + { + // note: at performs range check + ptr = &ptr->at(reference_token); + break; + } + + case detail::value_t::array: + { + if (JSON_UNLIKELY(reference_token == "-")) + { + // "-" always fails the range check + JSON_THROW(detail::out_of_range::create(402, + "array index '-' (" + std::to_string(ptr->m_value.array->size()) + + ") is out of range")); + } + + // error condition (cf. RFC 6901, Sect. 4) + if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0')) + { + JSON_THROW(detail::parse_error::create(106, 0, + "array index '" + reference_token + + "' must not begin with '0'")); + } + + // note: at performs range check + JSON_TRY + { + ptr = &ptr->at(static_cast(array_index(reference_token))); + } + JSON_CATCH(std::invalid_argument&) + { + JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number")); + } + break; + } + + default: + JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'")); + } + } + + return *ptr; +} + +NLOHMANN_BASIC_JSON_TPL_DECLARATION +const NLOHMANN_BASIC_JSON_TPL& +json_pointer::get_unchecked(const NLOHMANN_BASIC_JSON_TPL* ptr) const +{ + using size_type = typename NLOHMANN_BASIC_JSON_TPL::size_type; + for (const auto& reference_token : reference_tokens) + { + switch (ptr->m_type) + { + case detail::value_t::object: + { + // use unchecked object access + ptr = &ptr->operator[](reference_token); + break; + } + + case detail::value_t::array: + { + if (JSON_UNLIKELY(reference_token == "-")) + { + // "-" cannot be used for const access + JSON_THROW(detail::out_of_range::create(402, + "array index '-' (" + std::to_string(ptr->m_value.array->size()) + + ") is out of range")); + } + + // error condition (cf. RFC 6901, Sect. 4) + if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0')) + { + JSON_THROW(detail::parse_error::create(106, 0, + "array index '" + reference_token + + "' must not begin with '0'")); + } + + // use unchecked array access + JSON_TRY + { + ptr = &ptr->operator[]( + static_cast(array_index(reference_token))); + } + JSON_CATCH(std::invalid_argument&) + { + JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number")); + } + break; + } + + default: + JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'")); + } + } + + return *ptr; +} + +NLOHMANN_BASIC_JSON_TPL_DECLARATION +const NLOHMANN_BASIC_JSON_TPL& +json_pointer::get_checked(const NLOHMANN_BASIC_JSON_TPL* ptr) const +{ + using size_type = typename NLOHMANN_BASIC_JSON_TPL::size_type; + for (const auto& reference_token : reference_tokens) + { + switch (ptr->m_type) + { + case detail::value_t::object: + { + // note: at performs range check + ptr = &ptr->at(reference_token); + break; + } + + case detail::value_t::array: + { + if (JSON_UNLIKELY(reference_token == "-")) + { + // "-" always fails the range check + JSON_THROW(detail::out_of_range::create(402, + "array index '-' (" + std::to_string(ptr->m_value.array->size()) + + ") is out of range")); + } + + // error condition (cf. RFC 6901, Sect. 4) + if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0')) + { + JSON_THROW(detail::parse_error::create(106, 0, + "array index '" + reference_token + + "' must not begin with '0'")); + } + + // note: at performs range check + JSON_TRY + { + ptr = &ptr->at(static_cast(array_index(reference_token))); + } + JSON_CATCH(std::invalid_argument&) + { + JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number")); + } + break; + } + + default: + JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'")); + } + } + + return *ptr; +} + +NLOHMANN_BASIC_JSON_TPL_DECLARATION +void json_pointer::flatten(const std::string& reference_string, + const NLOHMANN_BASIC_JSON_TPL& value, + NLOHMANN_BASIC_JSON_TPL& result) +{ + switch (value.m_type) + { + case detail::value_t::array: + { + if (value.m_value.array->empty()) + { + // flatten empty array as null + result[reference_string] = nullptr; + } + else + { + // iterate array and use index as reference string + for (std::size_t i = 0; i < value.m_value.array->size(); ++i) + { + flatten(reference_string + "/" + std::to_string(i), + value.m_value.array->operator[](i), result); + } + } + break; + } + + case detail::value_t::object: + { + if (value.m_value.object->empty()) + { + // flatten empty object as null + result[reference_string] = nullptr; + } + else + { + // iterate object and use keys as reference string + for (const auto& element : *value.m_value.object) + { + flatten(reference_string + "/" + escape(element.first), element.second, result); + } + } + break; + } + + default: + { + // add primitive value with its reference string + result[reference_string] = value; + break; + } + } +} + +NLOHMANN_BASIC_JSON_TPL_DECLARATION +NLOHMANN_BASIC_JSON_TPL +json_pointer::unflatten(const NLOHMANN_BASIC_JSON_TPL& value) +{ + if (JSON_UNLIKELY(not value.is_object())) + { + JSON_THROW(detail::type_error::create(314, "only objects can be unflattened")); + } + + NLOHMANN_BASIC_JSON_TPL result; + + // iterate the JSON object values + for (const auto& element : *value.m_value.object) + { + if (JSON_UNLIKELY(not element.second.is_primitive())) + { + JSON_THROW(detail::type_error::create(315, "values in object must be primitive")); + } + + // assign value to reference pointed to by JSON pointer; Note that if + // the JSON pointer is "" (i.e., points to the whole value), function + // get_and_create returns a reference to result itself. An assignment + // will then create a primitive value. + json_pointer(element.first).get_and_create(result) = element.second; + } + + return result; +} + +inline bool operator==(json_pointer const& lhs, json_pointer const& rhs) noexcept +{ + return (lhs.reference_tokens == rhs.reference_tokens); +} + +inline bool operator!=(json_pointer const& lhs, json_pointer const& rhs) noexcept +{ + return not (lhs == rhs); +} +} // namespace nlohmann + +/////////////////////// +// nonmember support // +/////////////////////// + +// specialization of std::swap, and std::hash +namespace std +{ +/*! +@brief exchanges the values of two JSON objects + +@since version 1.0.0 +*/ +template<> +inline void swap(nlohmann::json& j1, + nlohmann::json& j2) noexcept( + is_nothrow_move_constructible::value and + is_nothrow_move_assignable::value + ) +{ + j1.swap(j2); +} + +/// hash value for JSON objects +template<> +struct hash +{ + /*! + @brief return a hash value for a JSON object + + @since version 1.0.0 + */ + std::size_t operator()(const nlohmann::json& j) const + { + // a naive hashing via the string representation + const auto& h = hash(); + return h(j.dump()); + } +}; + +/// specialization for std::less +/// @note: do not remove the space after '<', +/// see https://github.com/nlohmann/json/pull/679 +template<> +struct less< ::nlohmann::detail::value_t> +{ + /*! + @brief compare two value_t enum values + @since version 3.0.0 + */ + bool operator()(nlohmann::detail::value_t lhs, + nlohmann::detail::value_t rhs) const noexcept + { + return nlohmann::detail::operator<(lhs, rhs); + } +}; + +} // namespace std + +/*! +@brief user-defined string literal for JSON values + +This operator implements a user-defined string literal for JSON objects. It +can be used by adding `"_json"` to a string literal and returns a JSON object +if no parse error occurred. + +@param[in] s a string representation of a JSON object +@param[in] n the length of string @a s +@return a JSON object + +@since version 1.0.0 +*/ +inline nlohmann::json operator "" _json(const char* s, std::size_t n) +{ + return nlohmann::json::parse(s, s + n); +} + +/*! +@brief user-defined string literal for JSON pointer + +This operator implements a user-defined string literal for JSON Pointers. It +can be used by adding `"_json_pointer"` to a string literal and returns a JSON pointer +object if no parse error occurred. + +@param[in] s a string representation of a JSON Pointer +@param[in] n the length of string @a s +@return a JSON pointer object + +@since version 2.0.0 +*/ +inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std::size_t n) +{ + return nlohmann::json::json_pointer(std::string(s, n)); +} + + +/*** Start of inlined file: macro_unscope.hpp ***/ +#ifndef NLOHMANN_JSON_DETAIL_MACRO_UNSCOPE_HPP +#define NLOHMANN_JSON_DETAIL_MACRO_UNSCOPE_HPP + +// restore GCC/clang diagnostic settings +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #pragma GCC diagnostic pop +#endif +#if defined(__clang__) + #pragma GCC diagnostic pop +#endif + +// clean up +#undef JSON_CATCH +#undef JSON_THROW +#undef JSON_TRY +#undef JSON_LIKELY +#undef JSON_UNLIKELY +#undef JSON_DEPRECATED +#undef JSON_HAS_CPP_14 +#undef JSON_HAS_CPP_17 +#undef NLOHMANN_BASIC_JSON_TPL_DECLARATION +#undef NLOHMANN_BASIC_JSON_TPL +#undef NLOHMANN_JSON_HAS_HELPER + +#endif + +/*** End of inlined file: macro_unscope.hpp ***/ + +#endif + diff --git a/test/Makefile b/test/Makefile index a170acb9..bd8b73f0 100644 --- a/test/Makefile +++ b/test/Makefile @@ -77,7 +77,7 @@ test-%: src/unit-%.o src/unit.o ../src/json.hpp thirdparty/catch/catch.hpp TEST_PATTERN ?= "*" TEST_PREFIX = "" -check: $(TESTCASES) +check: $(OBJECTS) $(TESTCASES) @cd .. ; for testcase in $(TESTCASES); do echo "Executing $$testcase..."; $(TEST_PREFIX)test/$$testcase $(TEST_PATTERN) || exit 1; done From 0a2920e0fdae64586867dc64666e32e960d9bce0 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Tue, 9 Jan 2018 18:30:02 +0100 Subject: [PATCH 54/59] :recycle: reorganized code --- CMakeLists.txt | 30 +- Makefile | 45 +- {src => develop}/adl_serializer.hpp | 0 .../detail/conversions/from_json.hpp | 0 .../detail/conversions/to_json.hpp | 0 {src => develop}/detail/exceptions.hpp | 0 .../detail/iterators/internal_iterator.hpp | 0 .../detail/iterators/iter_impl.hpp | 0 .../detail/iterators/iteration_proxy.hpp | 0 .../iterators/json_reverse_iterator.hpp | 0 .../detail/iterators/primitive_iterator.hpp | 0 {src => develop}/detail/json_ref.hpp | 0 {src => develop}/detail/macro_scope.hpp | 0 {src => develop}/detail/macro_unscope.hpp | 0 {src => develop}/detail/meta.hpp | 0 .../detail/parsing/binary_reader.hpp | 0 .../detail/parsing/binary_writer.hpp | 0 .../detail/parsing/input_adapters.hpp | 0 {src => develop}/detail/parsing/lexer.hpp | 0 .../detail/parsing/output_adapters.hpp | 0 {src => develop}/detail/parsing/parser.hpp | 0 {src => develop}/detail/serializer.hpp | 0 {src => develop}/detail/value_t.hpp | 0 develop/json.hpp | 8024 +++++++ {src => develop}/json_fwd.hpp | 0 single_header/json.hpp | 19067 ---------------- src/json.hpp | 11173 ++++++++- 27 files changed, 19205 insertions(+), 19134 deletions(-) rename {src => develop}/adl_serializer.hpp (100%) rename {src => develop}/detail/conversions/from_json.hpp (100%) rename {src => develop}/detail/conversions/to_json.hpp (100%) rename {src => develop}/detail/exceptions.hpp (100%) rename {src => develop}/detail/iterators/internal_iterator.hpp (100%) rename {src => develop}/detail/iterators/iter_impl.hpp (100%) rename {src => develop}/detail/iterators/iteration_proxy.hpp (100%) rename {src => develop}/detail/iterators/json_reverse_iterator.hpp (100%) rename {src => develop}/detail/iterators/primitive_iterator.hpp (100%) rename {src => develop}/detail/json_ref.hpp (100%) rename {src => develop}/detail/macro_scope.hpp (100%) rename {src => develop}/detail/macro_unscope.hpp (100%) rename {src => develop}/detail/meta.hpp (100%) rename {src => develop}/detail/parsing/binary_reader.hpp (100%) rename {src => develop}/detail/parsing/binary_writer.hpp (100%) rename {src => develop}/detail/parsing/input_adapters.hpp (100%) rename {src => develop}/detail/parsing/lexer.hpp (100%) rename {src => develop}/detail/parsing/output_adapters.hpp (100%) rename {src => develop}/detail/parsing/parser.hpp (100%) rename {src => develop}/detail/serializer.hpp (100%) rename {src => develop}/detail/value_t.hpp (100%) create mode 100644 develop/json.hpp rename {src => develop}/json_fwd.hpp (100%) delete mode 100644 single_header/json.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 9cbe3501..cd513a97 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -68,18 +68,26 @@ if(BUILD_TESTING AND JSON_BuildTests) add_subdirectory(test) endif() -ExternalProject_Add(amalgamate - GIT_REPOSITORY "https://github.com/theodelrieu/Amalgamate" - CMAKE_ARGS "-DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR}" -) +## +## AMALGAMATION +## create a single header file +## +option(JSON_Amalgamate "Build and use amalgamation" OFF) -# There is no way to tell amalgamate to force-write the output file even if it already exists... -add_custom_target(single_header ALL rm -f "${CMAKE_SOURCE_DIR}/single_header/json.hpp" - COMMENT "Amalgamating json.hpp..." - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/${NLOHMANN_JSON_SOURCE_DIR} - DEPENDS amalgamate - COMMAND "${CMAKE_BINARY_DIR}/bin/amalgamate" -w '*.hpp' -i . json.hpp "${CMAKE_SOURCE_DIR}/single_header/json.hpp" -) +if(JSON_Amalgamate) + ExternalProject_Add(amalgamate + GIT_REPOSITORY "https://github.com/theodelrieu/Amalgamate" + CMAKE_ARGS "-DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR}" + ) + + # There is no way to tell amalgamate to force-write the output file even if it already exists... + add_custom_target(single_header ALL rm -f "${CMAKE_SOURCE_DIR}/${NLOHMANN_JSON_SOURCE_DIR}/json.hpp" + COMMENT "Amalgamating json.hpp..." + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/develop + DEPENDS amalgamate + COMMAND "${CMAKE_BINARY_DIR}/bin/amalgamate" -w '*.hpp' -i . json.hpp "${CMAKE_SOURCE_DIR}/${NLOHMANN_JSON_SOURCE_DIR}/json.hpp" + ) +endif() ## ## INSTALL diff --git a/Makefile b/Makefile index 8165aa9f..adf2b402 100644 --- a/Makefile +++ b/Makefile @@ -1,29 +1,30 @@ .PHONY: pretty clean ChangeLog.md SRCDIR = ./src +DEVDIR = ./develop SRCS = $(SRCDIR)/json.hpp \ - $(SRCDIR)/json_fwd.hpp \ - $(SRCDIR)/detail/macro_scope.hpp \ - $(SRCDIR)/detail/macro_unscope.hpp \ - $(SRCDIR)/detail/meta.hpp \ - $(SRCDIR)/detail/exceptions.hpp \ - $(SRCDIR)/detail/value_t.hpp \ - $(SRCDIR)/detail/conversions/from_json.hpp \ - $(SRCDIR)/detail/conversions/to_json.hpp \ - $(SRCDIR)/detail/parsing/input_adapters.hpp \ - $(SRCDIR)/detail/parsing/lexer.hpp \ - $(SRCDIR)/detail/parsing/parser.hpp \ - $(SRCDIR)/detail/iterators/primitive_iterator.hpp \ - $(SRCDIR)/detail/iterators/internal_iterator.hpp \ - $(SRCDIR)/detail/iterators/iter_impl.hpp \ - $(SRCDIR)/detail/iterators/iteration_proxy.hpp \ - $(SRCDIR)/detail/iterators/json_reverse_iterator.hpp \ - $(SRCDIR)/detail/parsing/output_adapters.hpp \ - $(SRCDIR)/detail/parsing/binary_reader.hpp \ - $(SRCDIR)/detail/parsing/binary_writer.hpp \ - $(SRCDIR)/detail/serializer.hpp \ - $(SRCDIR)/detail/json_ref.hpp \ - $(SRCDIR)/adl_serializer.hpp + $(DEVDIR)/json_fwd.hpp \ + $(DEVDIR)/detail/macro_scope.hpp \ + $(DEVDIR)/detail/macro_unscope.hpp \ + $(DEVDIR)/detail/meta.hpp \ + $(DEVDIR)/detail/exceptions.hpp \ + $(DEVDIR)/detail/value_t.hpp \ + $(DEVDIR)/detail/conversions/from_json.hpp \ + $(DEVDIR)/detail/conversions/to_json.hpp \ + $(DEVDIR)/detail/parsing/input_adapters.hpp \ + $(DEVDIR)/detail/parsing/lexer.hpp \ + $(DEVDIR)/detail/parsing/parser.hpp \ + $(DEVDIR)/detail/iterators/primitive_iterator.hpp \ + $(DEVDIR)/detail/iterators/internal_iterator.hpp \ + $(DEVDIR)/detail/iterators/iter_impl.hpp \ + $(DEVDIR)/detail/iterators/iteration_proxy.hpp \ + $(DEVDIR)/detail/iterators/json_reverse_iterator.hpp \ + $(DEVDIR)/detail/parsing/output_adapters.hpp \ + $(DEVDIR)/detail/parsing/binary_reader.hpp \ + $(DEVDIR)/detail/parsing/binary_writer.hpp \ + $(DEVDIR)/detail/serializer.hpp \ + $(DEVDIR)/detail/json_ref.hpp \ + $(DEVDIR)/adl_serializer.hpp UNAME = $(shell uname) CXX=clang++ diff --git a/src/adl_serializer.hpp b/develop/adl_serializer.hpp similarity index 100% rename from src/adl_serializer.hpp rename to develop/adl_serializer.hpp diff --git a/src/detail/conversions/from_json.hpp b/develop/detail/conversions/from_json.hpp similarity index 100% rename from src/detail/conversions/from_json.hpp rename to develop/detail/conversions/from_json.hpp diff --git a/src/detail/conversions/to_json.hpp b/develop/detail/conversions/to_json.hpp similarity index 100% rename from src/detail/conversions/to_json.hpp rename to develop/detail/conversions/to_json.hpp diff --git a/src/detail/exceptions.hpp b/develop/detail/exceptions.hpp similarity index 100% rename from src/detail/exceptions.hpp rename to develop/detail/exceptions.hpp diff --git a/src/detail/iterators/internal_iterator.hpp b/develop/detail/iterators/internal_iterator.hpp similarity index 100% rename from src/detail/iterators/internal_iterator.hpp rename to develop/detail/iterators/internal_iterator.hpp diff --git a/src/detail/iterators/iter_impl.hpp b/develop/detail/iterators/iter_impl.hpp similarity index 100% rename from src/detail/iterators/iter_impl.hpp rename to develop/detail/iterators/iter_impl.hpp diff --git a/src/detail/iterators/iteration_proxy.hpp b/develop/detail/iterators/iteration_proxy.hpp similarity index 100% rename from src/detail/iterators/iteration_proxy.hpp rename to develop/detail/iterators/iteration_proxy.hpp diff --git a/src/detail/iterators/json_reverse_iterator.hpp b/develop/detail/iterators/json_reverse_iterator.hpp similarity index 100% rename from src/detail/iterators/json_reverse_iterator.hpp rename to develop/detail/iterators/json_reverse_iterator.hpp diff --git a/src/detail/iterators/primitive_iterator.hpp b/develop/detail/iterators/primitive_iterator.hpp similarity index 100% rename from src/detail/iterators/primitive_iterator.hpp rename to develop/detail/iterators/primitive_iterator.hpp diff --git a/src/detail/json_ref.hpp b/develop/detail/json_ref.hpp similarity index 100% rename from src/detail/json_ref.hpp rename to develop/detail/json_ref.hpp diff --git a/src/detail/macro_scope.hpp b/develop/detail/macro_scope.hpp similarity index 100% rename from src/detail/macro_scope.hpp rename to develop/detail/macro_scope.hpp diff --git a/src/detail/macro_unscope.hpp b/develop/detail/macro_unscope.hpp similarity index 100% rename from src/detail/macro_unscope.hpp rename to develop/detail/macro_unscope.hpp diff --git a/src/detail/meta.hpp b/develop/detail/meta.hpp similarity index 100% rename from src/detail/meta.hpp rename to develop/detail/meta.hpp diff --git a/src/detail/parsing/binary_reader.hpp b/develop/detail/parsing/binary_reader.hpp similarity index 100% rename from src/detail/parsing/binary_reader.hpp rename to develop/detail/parsing/binary_reader.hpp diff --git a/src/detail/parsing/binary_writer.hpp b/develop/detail/parsing/binary_writer.hpp similarity index 100% rename from src/detail/parsing/binary_writer.hpp rename to develop/detail/parsing/binary_writer.hpp diff --git a/src/detail/parsing/input_adapters.hpp b/develop/detail/parsing/input_adapters.hpp similarity index 100% rename from src/detail/parsing/input_adapters.hpp rename to develop/detail/parsing/input_adapters.hpp diff --git a/src/detail/parsing/lexer.hpp b/develop/detail/parsing/lexer.hpp similarity index 100% rename from src/detail/parsing/lexer.hpp rename to develop/detail/parsing/lexer.hpp diff --git a/src/detail/parsing/output_adapters.hpp b/develop/detail/parsing/output_adapters.hpp similarity index 100% rename from src/detail/parsing/output_adapters.hpp rename to develop/detail/parsing/output_adapters.hpp diff --git a/src/detail/parsing/parser.hpp b/develop/detail/parsing/parser.hpp similarity index 100% rename from src/detail/parsing/parser.hpp rename to develop/detail/parsing/parser.hpp diff --git a/src/detail/serializer.hpp b/develop/detail/serializer.hpp similarity index 100% rename from src/detail/serializer.hpp rename to develop/detail/serializer.hpp diff --git a/src/detail/value_t.hpp b/develop/detail/value_t.hpp similarity index 100% rename from src/detail/value_t.hpp rename to develop/detail/value_t.hpp diff --git a/develop/json.hpp b/develop/json.hpp new file mode 100644 index 00000000..f4c139e4 --- /dev/null +++ b/develop/json.hpp @@ -0,0 +1,8024 @@ +/* + __ _____ _____ _____ + __| | __| | | | JSON for Modern C++ +| | |__ | | | | | | version 3.0.1 +|_____|_____|_____|_|___| https://github.com/nlohmann/json + +Licensed under the MIT License . +Copyright (c) 2013-2017 Niels Lohmann . + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#ifndef NLOHMANN_JSON_HPP +#define NLOHMANN_JSON_HPP + +#include // all_of, find, for_each +#include // assert +#include // and, not, or +#include // nullptr_t, ptrdiff_t, size_t +#include // hash, less +#include // initializer_list +#include // istream, ostream +#include // iterator_traits, random_access_iterator_tag +#include // accumulate +#include // string, stoi, to_string +#include // declval, forward, move, pair, swap + +#include "json_fwd.hpp" +#include "detail/macro_scope.hpp" +#include "detail/meta.hpp" +#include "detail/exceptions.hpp" +#include "detail/value_t.hpp" +#include "detail/conversions/from_json.hpp" +#include "detail/conversions/to_json.hpp" +#include "detail/parsing/input_adapters.hpp" +#include "detail/parsing/lexer.hpp" +#include "detail/parsing/parser.hpp" +#include "detail/iterators/primitive_iterator.hpp" +#include "detail/iterators/internal_iterator.hpp" +#include "detail/iterators/iter_impl.hpp" +#include "detail/iterators/iteration_proxy.hpp" +#include "detail/iterators/json_reverse_iterator.hpp" +#include "detail/parsing/output_adapters.hpp" +#include "detail/parsing/binary_reader.hpp" +#include "detail/parsing/binary_writer.hpp" +#include "detail/serializer.hpp" +#include "detail/json_ref.hpp" +#include "adl_serializer.hpp" + +/*! +@brief namespace for Niels Lohmann +@see https://github.com/nlohmann +@since version 1.0.0 +*/ +namespace nlohmann +{ +class json_pointer +{ + /// allow basic_json to access private members + NLOHMANN_BASIC_JSON_TPL_DECLARATION + friend class basic_json; + + public: + /*! + @brief create JSON pointer + + Create a JSON pointer according to the syntax described in + [Section 3 of RFC6901](https://tools.ietf.org/html/rfc6901#section-3). + + @param[in] s string representing the JSON pointer; if omitted, the empty + string is assumed which references the whole JSON value + + @throw parse_error.107 if the given JSON pointer @a s is nonempty and + does not begin with a slash (`/`); see example below + + @throw parse_error.108 if a tilde (`~`) in the given JSON pointer @a s + is not followed by `0` (representing `~`) or `1` (representing `/`); + see example below + + @liveexample{The example shows the construction several valid JSON + pointers as well as the exceptional behavior.,json_pointer} + + @since version 2.0.0 + */ + explicit json_pointer(const std::string& s = "") : reference_tokens(split(s)) {} + + /*! + @brief return a string representation of the JSON pointer + + @invariant For each JSON pointer `ptr`, it holds: + @code {.cpp} + ptr == json_pointer(ptr.to_string()); + @endcode + + @return a string representation of the JSON pointer + + @liveexample{The example shows the result of `to_string`., + json_pointer__to_string} + + @since version 2.0.0 + */ + std::string to_string() const noexcept + { + return std::accumulate(reference_tokens.begin(), reference_tokens.end(), + std::string{}, + [](const std::string & a, const std::string & b) + { + return a + "/" + escape(b); + }); + } + + /// @copydoc to_string() + operator std::string() const + { + return to_string(); + } + + /*! + @param[in] s reference token to be converted into an array index + + @return integer representation of @a s + + @throw out_of_range.404 if string @a s could not be converted to an integer + */ + static int array_index(const std::string& s) + { + size_t processed_chars = 0; + const int res = std::stoi(s, &processed_chars); + + // check if the string was completely read + if (JSON_UNLIKELY(processed_chars != s.size())) + { + JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + s + "'")); + } + + return res; + } + + private: + /*! + @brief remove and return last reference pointer + @throw out_of_range.405 if JSON pointer has no parent + */ + std::string pop_back() + { + if (JSON_UNLIKELY(is_root())) + { + JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent")); + } + + auto last = reference_tokens.back(); + reference_tokens.pop_back(); + return last; + } + + /// return whether pointer points to the root document + bool is_root() const + { + return reference_tokens.empty(); + } + + json_pointer top() const + { + if (JSON_UNLIKELY(is_root())) + { + JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent")); + } + + json_pointer result = *this; + result.reference_tokens = {reference_tokens[0]}; + return result; + } + + /*! + @brief create and return a reference to the pointed to value + + @complexity Linear in the number of reference tokens. + + @throw parse_error.109 if array index is not a number + @throw type_error.313 if value cannot be unflattened + */ + NLOHMANN_BASIC_JSON_TPL_DECLARATION + NLOHMANN_BASIC_JSON_TPL& get_and_create(NLOHMANN_BASIC_JSON_TPL& j) const; + + /*! + @brief return a reference to the pointed to value + + @note This version does not throw if a value is not present, but tries to + create nested values instead. For instance, calling this function + with pointer `"/this/that"` on a null value is equivalent to calling + `operator[]("this").operator[]("that")` on that value, effectively + changing the null value to an object. + + @param[in] ptr a JSON value + + @return reference to the JSON value pointed to by the JSON pointer + + @complexity Linear in the length of the JSON pointer. + + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.404 if the JSON pointer can not be resolved + */ + NLOHMANN_BASIC_JSON_TPL_DECLARATION + NLOHMANN_BASIC_JSON_TPL& get_unchecked(NLOHMANN_BASIC_JSON_TPL* ptr) const; + + /*! + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.402 if the array index '-' is used + @throw out_of_range.404 if the JSON pointer can not be resolved + */ + NLOHMANN_BASIC_JSON_TPL_DECLARATION + NLOHMANN_BASIC_JSON_TPL& get_checked(NLOHMANN_BASIC_JSON_TPL* ptr) const; + + /*! + @brief return a const reference to the pointed to value + + @param[in] ptr a JSON value + + @return const reference to the JSON value pointed to by the JSON + pointer + + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.402 if the array index '-' is used + @throw out_of_range.404 if the JSON pointer can not be resolved + */ + NLOHMANN_BASIC_JSON_TPL_DECLARATION + const NLOHMANN_BASIC_JSON_TPL& get_unchecked(const NLOHMANN_BASIC_JSON_TPL* ptr) const; + + /*! + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.402 if the array index '-' is used + @throw out_of_range.404 if the JSON pointer can not be resolved + */ + NLOHMANN_BASIC_JSON_TPL_DECLARATION + const NLOHMANN_BASIC_JSON_TPL& get_checked(const NLOHMANN_BASIC_JSON_TPL* ptr) const; + + /*! + @brief split the string input to reference tokens + + @note This function is only called by the json_pointer constructor. + All exceptions below are documented there. + + @throw parse_error.107 if the pointer is not empty or begins with '/' + @throw parse_error.108 if character '~' is not followed by '0' or '1' + */ + static std::vector split(const std::string& reference_string) + { + std::vector result; + + // special case: empty reference string -> no reference tokens + if (reference_string.empty()) + { + return result; + } + + // check if nonempty reference string begins with slash + if (JSON_UNLIKELY(reference_string[0] != '/')) + { + JSON_THROW(detail::parse_error::create(107, 1, + "JSON pointer must be empty or begin with '/' - was: '" + + reference_string + "'")); + } + + // extract the reference tokens: + // - slash: position of the last read slash (or end of string) + // - start: position after the previous slash + for ( + // search for the first slash after the first character + std::size_t slash = reference_string.find_first_of('/', 1), + // set the beginning of the first reference token + start = 1; + // we can stop if start == string::npos+1 = 0 + start != 0; + // set the beginning of the next reference token + // (will eventually be 0 if slash == std::string::npos) + start = slash + 1, + // find next slash + slash = reference_string.find_first_of('/', start)) + { + // use the text between the beginning of the reference token + // (start) and the last slash (slash). + auto reference_token = reference_string.substr(start, slash - start); + + // check reference tokens are properly escaped + for (std::size_t pos = reference_token.find_first_of('~'); + pos != std::string::npos; + pos = reference_token.find_first_of('~', pos + 1)) + { + assert(reference_token[pos] == '~'); + + // ~ must be followed by 0 or 1 + if (JSON_UNLIKELY(pos == reference_token.size() - 1 or + (reference_token[pos + 1] != '0' and + reference_token[pos + 1] != '1'))) + { + JSON_THROW(detail::parse_error::create(108, 0, "escape character '~' must be followed with '0' or '1'")); + } + } + + // finally, store the reference token + unescape(reference_token); + result.push_back(reference_token); + } + + return result; + } + + /*! + @brief replace all occurrences of a substring by another string + + @param[in,out] s the string to manipulate; changed so that all + occurrences of @a f are replaced with @a t + @param[in] f the substring to replace with @a t + @param[in] t the string to replace @a f + + @pre The search string @a f must not be empty. **This precondition is + enforced with an assertion.** + + @since version 2.0.0 + */ + static void replace_substring(std::string& s, const std::string& f, + const std::string& t) + { + assert(not f.empty()); + for (auto pos = s.find(f); // find first occurrence of f + pos != std::string::npos; // make sure f was found + s.replace(pos, f.size(), t), // replace with t, and + pos = s.find(f, pos + t.size())) // find next occurrence of f + {} + } + + /// escape "~"" to "~0" and "/" to "~1" + static std::string escape(std::string s) + { + replace_substring(s, "~", "~0"); + replace_substring(s, "/", "~1"); + return s; + } + + /// unescape "~1" to tilde and "~0" to slash (order is important!) + static void unescape(std::string& s) + { + replace_substring(s, "~1", "/"); + replace_substring(s, "~0", "~"); + } + + /*! + @param[in] reference_string the reference string to the current value + @param[in] value the value to consider + @param[in,out] result the result object to insert values to + + @note Empty objects or arrays are flattened to `null`. + */ + NLOHMANN_BASIC_JSON_TPL_DECLARATION + static void flatten(const std::string& reference_string, + const NLOHMANN_BASIC_JSON_TPL& value, + NLOHMANN_BASIC_JSON_TPL& result); + + /*! + @param[in] value flattened JSON + + @return unflattened JSON + + @throw parse_error.109 if array index is not a number + @throw type_error.314 if value is not an object + @throw type_error.315 if object values are not primitive + @throw type_error.313 if value cannot be unflattened + */ + NLOHMANN_BASIC_JSON_TPL_DECLARATION + static NLOHMANN_BASIC_JSON_TPL + unflatten(const NLOHMANN_BASIC_JSON_TPL& value); + + friend bool operator==(json_pointer const& lhs, + json_pointer const& rhs) noexcept; + + friend bool operator!=(json_pointer const& lhs, + json_pointer const& rhs) noexcept; + + /// the reference tokens + std::vector reference_tokens; +}; + +/*! +@brief a class to store JSON values + +@tparam ObjectType type for JSON objects (`std::map` by default; will be used +in @ref object_t) +@tparam ArrayType type for JSON arrays (`std::vector` by default; will be used +in @ref array_t) +@tparam StringType type for JSON strings and object keys (`std::string` by +default; will be used in @ref string_t) +@tparam BooleanType type for JSON booleans (`bool` by default; will be used +in @ref boolean_t) +@tparam NumberIntegerType type for JSON integer numbers (`int64_t` by +default; will be used in @ref number_integer_t) +@tparam NumberUnsignedType type for JSON unsigned integer numbers (@c +`uint64_t` by default; will be used in @ref number_unsigned_t) +@tparam NumberFloatType type for JSON floating-point numbers (`double` by +default; will be used in @ref number_float_t) +@tparam AllocatorType type of the allocator to use (`std::allocator` by +default) +@tparam JSONSerializer the serializer to resolve internal calls to `to_json()` +and `from_json()` (@ref adl_serializer by default) + +@requirement The class satisfies the following concept requirements: +- Basic + - [DefaultConstructible](http://en.cppreference.com/w/cpp/concept/DefaultConstructible): + JSON values can be default constructed. The result will be a JSON null + value. + - [MoveConstructible](http://en.cppreference.com/w/cpp/concept/MoveConstructible): + A JSON value can be constructed from an rvalue argument. + - [CopyConstructible](http://en.cppreference.com/w/cpp/concept/CopyConstructible): + A JSON value can be copy-constructed from an lvalue expression. + - [MoveAssignable](http://en.cppreference.com/w/cpp/concept/MoveAssignable): + A JSON value van be assigned from an rvalue argument. + - [CopyAssignable](http://en.cppreference.com/w/cpp/concept/CopyAssignable): + A JSON value can be copy-assigned from an lvalue expression. + - [Destructible](http://en.cppreference.com/w/cpp/concept/Destructible): + JSON values can be destructed. +- Layout + - [StandardLayoutType](http://en.cppreference.com/w/cpp/concept/StandardLayoutType): + JSON values have + [standard layout](http://en.cppreference.com/w/cpp/language/data_members#Standard_layout): + All non-static data members are private and standard layout types, the + class has no virtual functions or (virtual) base classes. +- Library-wide + - [EqualityComparable](http://en.cppreference.com/w/cpp/concept/EqualityComparable): + JSON values can be compared with `==`, see @ref + operator==(const_reference,const_reference). + - [LessThanComparable](http://en.cppreference.com/w/cpp/concept/LessThanComparable): + JSON values can be compared with `<`, see @ref + operator<(const_reference,const_reference). + - [Swappable](http://en.cppreference.com/w/cpp/concept/Swappable): + Any JSON lvalue or rvalue of can be swapped with any lvalue or rvalue of + other compatible types, using unqualified function call @ref swap(). + - [NullablePointer](http://en.cppreference.com/w/cpp/concept/NullablePointer): + JSON values can be compared against `std::nullptr_t` objects which are used + to model the `null` value. +- Container + - [Container](http://en.cppreference.com/w/cpp/concept/Container): + JSON values can be used like STL containers and provide iterator access. + - [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer); + JSON values can be used like STL containers and provide reverse iterator + access. + +@invariant The member variables @a m_value and @a m_type have the following +relationship: +- If `m_type == value_t::object`, then `m_value.object != nullptr`. +- If `m_type == value_t::array`, then `m_value.array != nullptr`. +- If `m_type == value_t::string`, then `m_value.string != nullptr`. +The invariants are checked by member function assert_invariant(). + +@internal +@note ObjectType trick from http://stackoverflow.com/a/9860911 +@endinternal + +@see [RFC 7159: The JavaScript Object Notation (JSON) Data Interchange +Format](http://rfc7159.net/rfc7159) + +@since version 1.0.0 + +@nosubgrouping +*/ +NLOHMANN_BASIC_JSON_TPL_DECLARATION +class basic_json +{ + private: + template friend struct detail::external_constructor; + friend ::nlohmann::json_pointer; + friend ::nlohmann::detail::parser; + friend ::nlohmann::detail::serializer; + template + friend class ::nlohmann::detail::iter_impl; + template + friend class ::nlohmann::detail::binary_writer; + template + friend class ::nlohmann::detail::binary_reader; + + /// workaround type for MSVC + using basic_json_t = NLOHMANN_BASIC_JSON_TPL; + + // convenience aliases for types residing in namespace detail; + using lexer = ::nlohmann::detail::lexer; + using parser = ::nlohmann::detail::parser; + + using primitive_iterator_t = ::nlohmann::detail::primitive_iterator_t; + template + using internal_iterator = ::nlohmann::detail::internal_iterator; + template + using iter_impl = ::nlohmann::detail::iter_impl; + template + using iteration_proxy = ::nlohmann::detail::iteration_proxy; + template using json_reverse_iterator = ::nlohmann::detail::json_reverse_iterator; + + template + using output_adapter_t = ::nlohmann::detail::output_adapter_t; + + using binary_reader = ::nlohmann::detail::binary_reader; + template using binary_writer = ::nlohmann::detail::binary_writer; + + using serializer = ::nlohmann::detail::serializer; + + public: + using value_t = detail::value_t; + /// @copydoc nlohmann::json_pointer + using json_pointer = ::nlohmann::json_pointer; + template + using json_serializer = JSONSerializer; + /// helper type for initializer lists of basic_json values + using initializer_list_t = std::initializer_list>; + + //////////////// + // exceptions // + //////////////// + + /// @name exceptions + /// Classes to implement user-defined exceptions. + /// @{ + + /// @copydoc detail::exception + using exception = detail::exception; + /// @copydoc detail::parse_error + using parse_error = detail::parse_error; + /// @copydoc detail::invalid_iterator + using invalid_iterator = detail::invalid_iterator; + /// @copydoc detail::type_error + using type_error = detail::type_error; + /// @copydoc detail::out_of_range + using out_of_range = detail::out_of_range; + /// @copydoc detail::other_error + using other_error = detail::other_error; + + /// @} + + + ///////////////////// + // container types // + ///////////////////// + + /// @name container types + /// The canonic container types to use @ref basic_json like any other STL + /// container. + /// @{ + + /// the type of elements in a basic_json container + using value_type = basic_json; + + /// the type of an element reference + using reference = value_type&; + /// the type of an element const reference + using const_reference = const value_type&; + + /// a type to represent differences between iterators + using difference_type = std::ptrdiff_t; + /// a type to represent container sizes + using size_type = std::size_t; + + /// the allocator type + using allocator_type = AllocatorType; + + /// the type of an element pointer + using pointer = typename std::allocator_traits::pointer; + /// the type of an element const pointer + using const_pointer = typename std::allocator_traits::const_pointer; + + /// an iterator for a basic_json container + using iterator = iter_impl; + /// a const iterator for a basic_json container + using const_iterator = iter_impl; + /// a reverse iterator for a basic_json container + using reverse_iterator = json_reverse_iterator; + /// a const reverse iterator for a basic_json container + using const_reverse_iterator = json_reverse_iterator; + + /// @} + + + /*! + @brief returns the allocator associated with the container + */ + static allocator_type get_allocator() + { + return allocator_type(); + } + + /*! + @brief returns version information on the library + + This function returns a JSON object with information about the library, + including the version number and information on the platform and compiler. + + @return JSON object holding version information + key | description + ----------- | --------------- + `compiler` | Information on the used compiler. It is an object with the following keys: `c++` (the used C++ standard), `family` (the compiler family; possible values are `clang`, `icc`, `gcc`, `ilecpp`, `msvc`, `pgcpp`, `sunpro`, and `unknown`), and `version` (the compiler version). + `copyright` | The copyright line for the library as string. + `name` | The name of the library as string. + `platform` | The used platform as string. Possible values are `win32`, `linux`, `apple`, `unix`, and `unknown`. + `url` | The URL of the project as string. + `version` | The version of the library. It is an object with the following keys: `major`, `minor`, and `patch` as defined by [Semantic Versioning](http://semver.org), and `string` (the version string). + + @liveexample{The following code shows an example output of the `meta()` + function.,meta} + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @complexity Constant. + + @since 2.1.0 + */ + static basic_json meta() + { + basic_json result; + + result["copyright"] = "(C) 2013-2017 Niels Lohmann"; + result["name"] = "JSON for Modern C++"; + result["url"] = "https://github.com/nlohmann/json"; + result["version"] = + { + {"string", "3.0.1"}, {"major", 3}, {"minor", 0}, {"patch", 1} + }; + +#ifdef _WIN32 + result["platform"] = "win32"; +#elif defined __linux__ + result["platform"] = "linux"; +#elif defined __APPLE__ + result["platform"] = "apple"; +#elif defined __unix__ + result["platform"] = "unix"; +#else + result["platform"] = "unknown"; +#endif + +#if defined(__ICC) || defined(__INTEL_COMPILER) + result["compiler"] = {{"family", "icc"}, {"version", __INTEL_COMPILER}}; +#elif defined(__clang__) + result["compiler"] = {{"family", "clang"}, {"version", __clang_version__}}; +#elif defined(__GNUC__) || defined(__GNUG__) + result["compiler"] = {{"family", "gcc"}, {"version", std::to_string(__GNUC__) + "." + std::to_string(__GNUC_MINOR__) + "." + std::to_string(__GNUC_PATCHLEVEL__)}}; +#elif defined(__HP_cc) || defined(__HP_aCC) + result["compiler"] = "hp" +#elif defined(__IBMCPP__) + result["compiler"] = {{"family", "ilecpp"}, {"version", __IBMCPP__}}; +#elif defined(_MSC_VER) + result["compiler"] = {{"family", "msvc"}, {"version", _MSC_VER}}; +#elif defined(__PGI) + result["compiler"] = {{"family", "pgcpp"}, {"version", __PGI}}; +#elif defined(__SUNPRO_CC) + result["compiler"] = {{"family", "sunpro"}, {"version", __SUNPRO_CC}}; +#else + result["compiler"] = {{"family", "unknown"}, {"version", "unknown"}}; +#endif + +#ifdef __cplusplus + result["compiler"]["c++"] = std::to_string(__cplusplus); +#else + result["compiler"]["c++"] = "unknown"; +#endif + return result; + } + + + /////////////////////////// + // JSON value data types // + /////////////////////////// + + /// @name JSON value data types + /// The data types to store a JSON value. These types are derived from + /// the template arguments passed to class @ref basic_json. + /// @{ + +#if defined(JSON_HAS_CPP_14) + // Use transparent comparator if possible, combined with perfect forwarding + // on find() and count() calls prevents unnecessary string construction. + using object_comparator_t = std::less<>; +#else + using object_comparator_t = std::less; +#endif + + /*! + @brief a type for an object + + [RFC 7159](http://rfc7159.net/rfc7159) describes JSON objects as follows: + > An object is an unordered collection of zero or more name/value pairs, + > where a name is a string and a value is a string, number, boolean, null, + > object, or array. + + To store objects in C++, a type is defined by the template parameters + described below. + + @tparam ObjectType the container to store objects (e.g., `std::map` or + `std::unordered_map`) + @tparam StringType the type of the keys or names (e.g., `std::string`). + The comparison function `std::less` is used to order elements + inside the container. + @tparam AllocatorType the allocator to use for objects (e.g., + `std::allocator`) + + #### Default type + + With the default values for @a ObjectType (`std::map`), @a StringType + (`std::string`), and @a AllocatorType (`std::allocator`), the default + value for @a object_t is: + + @code {.cpp} + std::map< + std::string, // key_type + basic_json, // value_type + std::less, // key_compare + std::allocator> // allocator_type + > + @endcode + + #### Behavior + + The choice of @a object_t influences the behavior of the JSON class. With + the default type, objects have the following behavior: + + - When all names are unique, objects will be interoperable in the sense + that all software implementations receiving that object will agree on + the name-value mappings. + - When the names within an object are not unique, later stored name/value + pairs overwrite previously stored name/value pairs, leaving the used + names unique. For instance, `{"key": 1}` and `{"key": 2, "key": 1}` will + be treated as equal and both stored as `{"key": 1}`. + - Internally, name/value pairs are stored in lexicographical order of the + names. Objects will also be serialized (see @ref dump) in this order. + For instance, `{"b": 1, "a": 2}` and `{"a": 2, "b": 1}` will be stored + and serialized as `{"a": 2, "b": 1}`. + - When comparing objects, the order of the name/value pairs is irrelevant. + This makes objects interoperable in the sense that they will not be + affected by these differences. For instance, `{"b": 1, "a": 2}` and + `{"a": 2, "b": 1}` will be treated as equal. + + #### Limits + + [RFC 7159](http://rfc7159.net/rfc7159) specifies: + > An implementation may set limits on the maximum depth of nesting. + + In this class, the object's limit of nesting is not explicitly constrained. + However, a maximum depth of nesting may be introduced by the compiler or + runtime environment. A theoretical limit can be queried by calling the + @ref max_size function of a JSON object. + + #### Storage + + Objects are stored as pointers in a @ref basic_json type. That is, for any + access to object values, a pointer of type `object_t*` must be + dereferenced. + + @sa @ref array_t -- type for an array value + + @since version 1.0.0 + + @note The order name/value pairs are added to the object is *not* + preserved by the library. Therefore, iterating an object may return + name/value pairs in a different order than they were originally stored. In + fact, keys will be traversed in alphabetical order as `std::map` with + `std::less` is used by default. Please note this behavior conforms to [RFC + 7159](http://rfc7159.net/rfc7159), because any order implements the + specified "unordered" nature of JSON objects. + */ + using object_t = ObjectType>>; + + /*! + @brief a type for an array + + [RFC 7159](http://rfc7159.net/rfc7159) describes JSON arrays as follows: + > An array is an ordered sequence of zero or more values. + + To store objects in C++, a type is defined by the template parameters + explained below. + + @tparam ArrayType container type to store arrays (e.g., `std::vector` or + `std::list`) + @tparam AllocatorType allocator to use for arrays (e.g., `std::allocator`) + + #### Default type + + With the default values for @a ArrayType (`std::vector`) and @a + AllocatorType (`std::allocator`), the default value for @a array_t is: + + @code {.cpp} + std::vector< + basic_json, // value_type + std::allocator // allocator_type + > + @endcode + + #### Limits + + [RFC 7159](http://rfc7159.net/rfc7159) specifies: + > An implementation may set limits on the maximum depth of nesting. + + In this class, the array's limit of nesting is not explicitly constrained. + However, a maximum depth of nesting may be introduced by the compiler or + runtime environment. A theoretical limit can be queried by calling the + @ref max_size function of a JSON array. + + #### Storage + + Arrays are stored as pointers in a @ref basic_json type. That is, for any + access to array values, a pointer of type `array_t*` must be dereferenced. + + @sa @ref object_t -- type for an object value + + @since version 1.0.0 + */ + using array_t = ArrayType>; + + /*! + @brief a type for a string + + [RFC 7159](http://rfc7159.net/rfc7159) describes JSON strings as follows: + > A string is a sequence of zero or more Unicode characters. + + To store objects in C++, a type is defined by the template parameter + described below. Unicode values are split by the JSON class into + byte-sized characters during deserialization. + + @tparam StringType the container to store strings (e.g., `std::string`). + Note this container is used for keys/names in objects, see @ref object_t. + + #### Default type + + With the default values for @a StringType (`std::string`), the default + value for @a string_t is: + + @code {.cpp} + std::string + @endcode + + #### Encoding + + Strings are stored in UTF-8 encoding. Therefore, functions like + `std::string::size()` or `std::string::length()` return the number of + bytes in the string rather than the number of characters or glyphs. + + #### String comparison + + [RFC 7159](http://rfc7159.net/rfc7159) states: + > Software implementations are typically required to test names of object + > members for equality. Implementations that transform the textual + > representation into sequences of Unicode code units and then perform the + > comparison numerically, code unit by code unit, are interoperable in the + > sense that implementations will agree in all cases on equality or + > inequality of two strings. For example, implementations that compare + > strings with escaped characters unconverted may incorrectly find that + > `"a\\b"` and `"a\u005Cb"` are not equal. + + This implementation is interoperable as it does compare strings code unit + by code unit. + + #### Storage + + String values are stored as pointers in a @ref basic_json type. That is, + for any access to string values, a pointer of type `string_t*` must be + dereferenced. + + @since version 1.0.0 + */ + using string_t = StringType; + + /*! + @brief a type for a boolean + + [RFC 7159](http://rfc7159.net/rfc7159) implicitly describes a boolean as a + type which differentiates the two literals `true` and `false`. + + To store objects in C++, a type is defined by the template parameter @a + BooleanType which chooses the type to use. + + #### Default type + + With the default values for @a BooleanType (`bool`), the default value for + @a boolean_t is: + + @code {.cpp} + bool + @endcode + + #### Storage + + Boolean values are stored directly inside a @ref basic_json type. + + @since version 1.0.0 + */ + using boolean_t = BooleanType; + + /*! + @brief a type for a number (integer) + + [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: + > The representation of numbers is similar to that used in most + > programming languages. A number is represented in base 10 using decimal + > digits. It contains an integer component that may be prefixed with an + > optional minus sign, which may be followed by a fraction part and/or an + > exponent part. Leading zeros are not allowed. (...) Numeric values that + > cannot be represented in the grammar below (such as Infinity and NaN) + > are not permitted. + + This description includes both integer and floating-point numbers. + However, C++ allows more precise storage if it is known whether the number + is a signed integer, an unsigned integer or a floating-point number. + Therefore, three different types, @ref number_integer_t, @ref + number_unsigned_t and @ref number_float_t are used. + + To store integer numbers in C++, a type is defined by the template + parameter @a NumberIntegerType which chooses the type to use. + + #### Default type + + With the default values for @a NumberIntegerType (`int64_t`), the default + value for @a number_integer_t is: + + @code {.cpp} + int64_t + @endcode + + #### Default behavior + + - The restrictions about leading zeros is not enforced in C++. Instead, + leading zeros in integer literals lead to an interpretation as octal + number. Internally, the value will be stored as decimal number. For + instance, the C++ integer literal `010` will be serialized to `8`. + During deserialization, leading zeros yield an error. + - Not-a-number (NaN) values will be serialized to `null`. + + #### Limits + + [RFC 7159](http://rfc7159.net/rfc7159) specifies: + > An implementation may set limits on the range and precision of numbers. + + When the default type is used, the maximal integer number that can be + stored is `9223372036854775807` (INT64_MAX) and the minimal integer number + that can be stored is `-9223372036854775808` (INT64_MIN). Integer numbers + that are out of range will yield over/underflow when used in a + constructor. During deserialization, too large or small integer numbers + will be automatically be stored as @ref number_unsigned_t or @ref + number_float_t. + + [RFC 7159](http://rfc7159.net/rfc7159) further states: + > Note that when such software is used, numbers that are integers and are + > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense + > that implementations will agree exactly on their numeric values. + + As this range is a subrange of the exactly supported range [INT64_MIN, + INT64_MAX], this class's integer type is interoperable. + + #### Storage + + Integer number values are stored directly inside a @ref basic_json type. + + @sa @ref number_float_t -- type for number values (floating-point) + + @sa @ref number_unsigned_t -- type for number values (unsigned integer) + + @since version 1.0.0 + */ + using number_integer_t = NumberIntegerType; + + /*! + @brief a type for a number (unsigned) + + [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: + > The representation of numbers is similar to that used in most + > programming languages. A number is represented in base 10 using decimal + > digits. It contains an integer component that may be prefixed with an + > optional minus sign, which may be followed by a fraction part and/or an + > exponent part. Leading zeros are not allowed. (...) Numeric values that + > cannot be represented in the grammar below (such as Infinity and NaN) + > are not permitted. + + This description includes both integer and floating-point numbers. + However, C++ allows more precise storage if it is known whether the number + is a signed integer, an unsigned integer or a floating-point number. + Therefore, three different types, @ref number_integer_t, @ref + number_unsigned_t and @ref number_float_t are used. + + To store unsigned integer numbers in C++, a type is defined by the + template parameter @a NumberUnsignedType which chooses the type to use. + + #### Default type + + With the default values for @a NumberUnsignedType (`uint64_t`), the + default value for @a number_unsigned_t is: + + @code {.cpp} + uint64_t + @endcode + + #### Default behavior + + - The restrictions about leading zeros is not enforced in C++. Instead, + leading zeros in integer literals lead to an interpretation as octal + number. Internally, the value will be stored as decimal number. For + instance, the C++ integer literal `010` will be serialized to `8`. + During deserialization, leading zeros yield an error. + - Not-a-number (NaN) values will be serialized to `null`. + + #### Limits + + [RFC 7159](http://rfc7159.net/rfc7159) specifies: + > An implementation may set limits on the range and precision of numbers. + + When the default type is used, the maximal integer number that can be + stored is `18446744073709551615` (UINT64_MAX) and the minimal integer + number that can be stored is `0`. Integer numbers that are out of range + will yield over/underflow when used in a constructor. During + deserialization, too large or small integer numbers will be automatically + be stored as @ref number_integer_t or @ref number_float_t. + + [RFC 7159](http://rfc7159.net/rfc7159) further states: + > Note that when such software is used, numbers that are integers and are + > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense + > that implementations will agree exactly on their numeric values. + + As this range is a subrange (when considered in conjunction with the + number_integer_t type) of the exactly supported range [0, UINT64_MAX], + this class's integer type is interoperable. + + #### Storage + + Integer number values are stored directly inside a @ref basic_json type. + + @sa @ref number_float_t -- type for number values (floating-point) + @sa @ref number_integer_t -- type for number values (integer) + + @since version 2.0.0 + */ + using number_unsigned_t = NumberUnsignedType; + + /*! + @brief a type for a number (floating-point) + + [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: + > The representation of numbers is similar to that used in most + > programming languages. A number is represented in base 10 using decimal + > digits. It contains an integer component that may be prefixed with an + > optional minus sign, which may be followed by a fraction part and/or an + > exponent part. Leading zeros are not allowed. (...) Numeric values that + > cannot be represented in the grammar below (such as Infinity and NaN) + > are not permitted. + + This description includes both integer and floating-point numbers. + However, C++ allows more precise storage if it is known whether the number + is a signed integer, an unsigned integer or a floating-point number. + Therefore, three different types, @ref number_integer_t, @ref + number_unsigned_t and @ref number_float_t are used. + + To store floating-point numbers in C++, a type is defined by the template + parameter @a NumberFloatType which chooses the type to use. + + #### Default type + + With the default values for @a NumberFloatType (`double`), the default + value for @a number_float_t is: + + @code {.cpp} + double + @endcode + + #### Default behavior + + - The restrictions about leading zeros is not enforced in C++. Instead, + leading zeros in floating-point literals will be ignored. Internally, + the value will be stored as decimal number. For instance, the C++ + floating-point literal `01.2` will be serialized to `1.2`. During + deserialization, leading zeros yield an error. + - Not-a-number (NaN) values will be serialized to `null`. + + #### Limits + + [RFC 7159](http://rfc7159.net/rfc7159) states: + > This specification allows implementations to set limits on the range and + > precision of numbers accepted. Since software that implements IEEE + > 754-2008 binary64 (double precision) numbers is generally available and + > widely used, good interoperability can be achieved by implementations + > that expect no more precision or range than these provide, in the sense + > that implementations will approximate JSON numbers within the expected + > precision. + + This implementation does exactly follow this approach, as it uses double + precision floating-point numbers. Note values smaller than + `-1.79769313486232e+308` and values greater than `1.79769313486232e+308` + will be stored as NaN internally and be serialized to `null`. + + #### Storage + + Floating-point number values are stored directly inside a @ref basic_json + type. + + @sa @ref number_integer_t -- type for number values (integer) + + @sa @ref number_unsigned_t -- type for number values (unsigned integer) + + @since version 1.0.0 + */ + using number_float_t = NumberFloatType; + + /// @} + + private: + + /// helper for exception-safe object creation + template + static T* create(Args&& ... args) + { + AllocatorType alloc; + using AllocatorTraits = std::allocator_traits>; + + auto deleter = [&](T * object) + { + AllocatorTraits::deallocate(alloc, object, 1); + }; + std::unique_ptr object(AllocatorTraits::allocate(alloc, 1), deleter); + AllocatorTraits::construct(alloc, object.get(), std::forward(args)...); + assert(object != nullptr); + return object.release(); + } + + //////////////////////// + // JSON value storage // + //////////////////////// + + /*! + @brief a JSON value + + The actual storage for a JSON value of the @ref basic_json class. This + union combines the different storage types for the JSON value types + defined in @ref value_t. + + JSON type | value_t type | used type + --------- | --------------- | ------------------------ + object | object | pointer to @ref object_t + array | array | pointer to @ref array_t + string | string | pointer to @ref string_t + boolean | boolean | @ref boolean_t + number | number_integer | @ref number_integer_t + number | number_unsigned | @ref number_unsigned_t + number | number_float | @ref number_float_t + null | null | *no value is stored* + + @note Variable-length types (objects, arrays, and strings) are stored as + pointers. The size of the union should not exceed 64 bits if the default + value types are used. + + @since version 1.0.0 + */ + union json_value + { + /// object (stored with pointer to save storage) + object_t* object; + /// array (stored with pointer to save storage) + array_t* array; + /// string (stored with pointer to save storage) + string_t* string; + /// boolean + boolean_t boolean; + /// number (integer) + number_integer_t number_integer; + /// number (unsigned integer) + number_unsigned_t number_unsigned; + /// number (floating-point) + number_float_t number_float; + + /// default constructor (for null values) + json_value() = default; + /// constructor for booleans + json_value(boolean_t v) noexcept : boolean(v) {} + /// constructor for numbers (integer) + json_value(number_integer_t v) noexcept : number_integer(v) {} + /// constructor for numbers (unsigned) + json_value(number_unsigned_t v) noexcept : number_unsigned(v) {} + /// constructor for numbers (floating-point) + json_value(number_float_t v) noexcept : number_float(v) {} + /// constructor for empty values of a given type + json_value(value_t t) + { + switch (t) + { + case value_t::object: + { + object = create(); + break; + } + + case value_t::array: + { + array = create(); + break; + } + + case value_t::string: + { + string = create(""); + break; + } + + case value_t::boolean: + { + boolean = boolean_t(false); + break; + } + + case value_t::number_integer: + { + number_integer = number_integer_t(0); + break; + } + + case value_t::number_unsigned: + { + number_unsigned = number_unsigned_t(0); + break; + } + + case value_t::number_float: + { + number_float = number_float_t(0.0); + break; + } + + case value_t::null: + { + object = nullptr; // silence warning, see #821 + break; + } + + default: + { + object = nullptr; // silence warning, see #821 + if (JSON_UNLIKELY(t == value_t::null)) + { + JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.0.1")); // LCOV_EXCL_LINE + } + break; + } + } + } + + /// constructor for strings + json_value(const string_t& value) + { + string = create(value); + } + + /// constructor for rvalue strings + json_value(string_t&& value) + { + string = create(std::move(value)); + } + + /// constructor for objects + json_value(const object_t& value) + { + object = create(value); + } + + /// constructor for rvalue objects + json_value(object_t&& value) + { + object = create(std::move(value)); + } + + /// constructor for arrays + json_value(const array_t& value) + { + array = create(value); + } + + /// constructor for rvalue arrays + json_value(array_t&& value) + { + array = create(std::move(value)); + } + + void destroy(value_t t) + { + switch (t) + { + case value_t::object: + { + AllocatorType alloc; + std::allocator_traits::destroy(alloc, object); + std::allocator_traits::deallocate(alloc, object, 1); + break; + } + + case value_t::array: + { + AllocatorType alloc; + std::allocator_traits::destroy(alloc, array); + std::allocator_traits::deallocate(alloc, array, 1); + break; + } + + case value_t::string: + { + AllocatorType alloc; + std::allocator_traits::destroy(alloc, string); + std::allocator_traits::deallocate(alloc, string, 1); + break; + } + + default: + { + break; + } + } + } + }; + + /*! + @brief checks the class invariants + + This function asserts the class invariants. It needs to be called at the + end of every constructor to make sure that created objects respect the + invariant. Furthermore, it has to be called each time the type of a JSON + value is changed, because the invariant expresses a relationship between + @a m_type and @a m_value. + */ + void assert_invariant() const + { + assert(m_type != value_t::object or m_value.object != nullptr); + assert(m_type != value_t::array or m_value.array != nullptr); + assert(m_type != value_t::string or m_value.string != nullptr); + } + + public: + ////////////////////////// + // JSON parser callback // + ////////////////////////// + + /*! + @brief parser event types + + The parser callback distinguishes the following events: + - `object_start`: the parser read `{` and started to process a JSON object + - `key`: the parser read a key of a value in an object + - `object_end`: the parser read `}` and finished processing a JSON object + - `array_start`: the parser read `[` and started to process a JSON array + - `array_end`: the parser read `]` and finished processing a JSON array + - `value`: the parser finished reading a JSON value + + @image html callback_events.png "Example when certain parse events are triggered" + + @sa @ref parser_callback_t for more information and examples + */ + using parse_event_t = typename parser::parse_event_t; + + /*! + @brief per-element parser callback type + + With a parser callback function, the result of parsing a JSON text can be + influenced. When passed to @ref parse, it is called on certain events + (passed as @ref parse_event_t via parameter @a event) with a set recursion + depth @a depth and context JSON value @a parsed. The return value of the + callback function is a boolean indicating whether the element that emitted + the callback shall be kept or not. + + We distinguish six scenarios (determined by the event type) in which the + callback function can be called. The following table describes the values + of the parameters @a depth, @a event, and @a parsed. + + parameter @a event | description | parameter @a depth | parameter @a parsed + ------------------ | ----------- | ------------------ | ------------------- + parse_event_t::object_start | the parser read `{` and started to process a JSON object | depth of the parent of the JSON object | a JSON value with type discarded + parse_event_t::key | the parser read a key of a value in an object | depth of the currently parsed JSON object | a JSON string containing the key + parse_event_t::object_end | the parser read `}` and finished processing a JSON object | depth of the parent of the JSON object | the parsed JSON object + parse_event_t::array_start | the parser read `[` and started to process a JSON array | depth of the parent of the JSON array | a JSON value with type discarded + parse_event_t::array_end | the parser read `]` and finished processing a JSON array | depth of the parent of the JSON array | the parsed JSON array + parse_event_t::value | the parser finished reading a JSON value | depth of the value | the parsed JSON value + + @image html callback_events.png "Example when certain parse events are triggered" + + Discarding a value (i.e., returning `false`) has different effects + depending on the context in which function was called: + + - Discarded values in structured types are skipped. That is, the parser + will behave as if the discarded value was never read. + - In case a value outside a structured type is skipped, it is replaced + with `null`. This case happens if the top-level element is skipped. + + @param[in] depth the depth of the recursion during parsing + + @param[in] event an event of type parse_event_t indicating the context in + the callback function has been called + + @param[in,out] parsed the current intermediate parse result; note that + writing to this value has no effect for parse_event_t::key events + + @return Whether the JSON value which called the function during parsing + should be kept (`true`) or not (`false`). In the latter case, it is either + skipped completely or replaced by an empty discarded object. + + @sa @ref parse for examples + + @since version 1.0.0 + */ + using parser_callback_t = typename parser::parser_callback_t; + + + ////////////////// + // constructors // + ////////////////// + + /// @name constructors and destructors + /// Constructors of class @ref basic_json, copy/move constructor, copy + /// assignment, static functions creating objects, and the destructor. + /// @{ + + /*! + @brief create an empty value with a given type + + Create an empty JSON value with a given type. The value will be default + initialized with an empty value which depends on the type: + + Value type | initial value + ----------- | ------------- + null | `null` + boolean | `false` + string | `""` + number | `0` + object | `{}` + array | `[]` + + @param[in] v the type of the value to create + + @complexity Constant. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @liveexample{The following code shows the constructor for different @ref + value_t values,basic_json__value_t} + + @sa @ref clear() -- restores the postcondition of this constructor + + @since version 1.0.0 + */ + basic_json(const value_t v) + : m_type(v), m_value(v) + { + assert_invariant(); + } + + /*! + @brief create a null object + + Create a `null` JSON value. It either takes a null pointer as parameter + (explicitly creating `null`) or no parameter (implicitly creating `null`). + The passed null pointer itself is not read -- it is only used to choose + the right constructor. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this constructor never throws + exceptions. + + @liveexample{The following code shows the constructor with and without a + null pointer parameter.,basic_json__nullptr_t} + + @since version 1.0.0 + */ + basic_json(std::nullptr_t = nullptr) noexcept + : basic_json(value_t::null) + { + assert_invariant(); + } + + /*! + @brief create a JSON value + + This is a "catch all" constructor for all compatible JSON types; that is, + types for which a `to_json()` method exists. The constructor forwards the + parameter @a val to that method (to `json_serializer::to_json` method + with `U = uncvref_t`, to be exact). + + Template type @a CompatibleType includes, but is not limited to, the + following types: + - **arrays**: @ref array_t and all kinds of compatible containers such as + `std::vector`, `std::deque`, `std::list`, `std::forward_list`, + `std::array`, `std::valarray`, `std::set`, `std::unordered_set`, + `std::multiset`, and `std::unordered_multiset` with a `value_type` from + which a @ref basic_json value can be constructed. + - **objects**: @ref object_t and all kinds of compatible associative + containers such as `std::map`, `std::unordered_map`, `std::multimap`, + and `std::unordered_multimap` with a `key_type` compatible to + @ref string_t and a `value_type` from which a @ref basic_json value can + be constructed. + - **strings**: @ref string_t, string literals, and all compatible string + containers can be used. + - **numbers**: @ref number_integer_t, @ref number_unsigned_t, + @ref number_float_t, and all convertible number types such as `int`, + `size_t`, `int64_t`, `float` or `double` can be used. + - **boolean**: @ref boolean_t / `bool` can be used. + + See the examples below. + + @tparam CompatibleType a type such that: + - @a CompatibleType is not derived from `std::istream`, + - @a CompatibleType is not @ref basic_json (to avoid hijacking copy/move + constructors), + - @a CompatibleType is not a @ref basic_json nested type (e.g., + @ref json_pointer, @ref iterator, etc ...) + - @ref @ref json_serializer has a + `to_json(basic_json_t&, CompatibleType&&)` method + + @tparam U = `uncvref_t` + + @param[in] val the value to be forwarded to the respective constructor + + @complexity Usually linear in the size of the passed @a val, also + depending on the implementation of the called `to_json()` + method. + + @exceptionsafety Depends on the called constructor. For types directly + supported by the library (i.e., all types for which no `to_json()` function + was provided), strong guarantee holds: if an exception is thrown, there are + no changes to any JSON value. + + @liveexample{The following code shows the constructor with several + compatible types.,basic_json__CompatibleType} + + @since version 2.1.0 + */ + template, + detail::enable_if_t::value and + not std::is_same::value and + not detail::is_basic_json_nested_type< + basic_json_t, U>::value and + detail::has_to_json::value, + int> = 0> + basic_json(CompatibleType && val) noexcept(noexcept(JSONSerializer::to_json( + std::declval(), std::forward(val)))) + { + JSONSerializer::to_json(*this, std::forward(val)); + assert_invariant(); + } + + /*! + @brief create a container (array or object) from an initializer list + + Creates a JSON value of type array or object from the passed initializer + list @a init. In case @a type_deduction is `true` (default), the type of + the JSON value to be created is deducted from the initializer list @a init + according to the following rules: + + 1. If the list is empty, an empty JSON object value `{}` is created. + 2. If the list consists of pairs whose first element is a string, a JSON + object value is created where the first elements of the pairs are + treated as keys and the second elements are as values. + 3. In all other cases, an array is created. + + The rules aim to create the best fit between a C++ initializer list and + JSON values. The rationale is as follows: + + 1. The empty initializer list is written as `{}` which is exactly an empty + JSON object. + 2. C++ has no way of describing mapped types other than to list a list of + pairs. As JSON requires that keys must be of type string, rule 2 is the + weakest constraint one can pose on initializer lists to interpret them + as an object. + 3. In all other cases, the initializer list could not be interpreted as + JSON object type, so interpreting it as JSON array type is safe. + + With the rules described above, the following JSON values cannot be + expressed by an initializer list: + + - the empty array (`[]`): use @ref array(initializer_list_t) + with an empty initializer list in this case + - arrays whose elements satisfy rule 2: use @ref + array(initializer_list_t) with the same initializer list + in this case + + @note When used without parentheses around an empty initializer list, @ref + basic_json() is called instead of this function, yielding the JSON null + value. + + @param[in] init initializer list with JSON values + + @param[in] type_deduction internal parameter; when set to `true`, the type + of the JSON value is deducted from the initializer list @a init; when set + to `false`, the type provided via @a manual_type is forced. This mode is + used by the functions @ref array(initializer_list_t) and + @ref object(initializer_list_t). + + @param[in] manual_type internal parameter; when @a type_deduction is set + to `false`, the created JSON value will use the provided type (only @ref + value_t::array and @ref value_t::object are valid); when @a type_deduction + is set to `true`, this parameter has no effect + + @throw type_error.301 if @a type_deduction is `false`, @a manual_type is + `value_t::object`, but @a init contains an element which is not a pair + whose first element is a string. In this case, the constructor could not + create an object. If @a type_deduction would have be `true`, an array + would have been created. See @ref object(initializer_list_t) + for an example. + + @complexity Linear in the size of the initializer list @a init. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @liveexample{The example below shows how JSON values are created from + initializer lists.,basic_json__list_init_t} + + @sa @ref array(initializer_list_t) -- create a JSON array + value from an initializer list + @sa @ref object(initializer_list_t) -- create a JSON object + value from an initializer list + + @since version 1.0.0 + */ + basic_json(initializer_list_t init, + bool type_deduction = true, + value_t manual_type = value_t::array) + { + // check if each element is an array with two elements whose first + // element is a string + bool is_an_object = std::all_of(init.begin(), init.end(), + [](const detail::json_ref& element_ref) + { + return (element_ref->is_array() and element_ref->size() == 2 and (*element_ref)[0].is_string()); + }); + + // adjust type if type deduction is not wanted + if (not type_deduction) + { + // if array is wanted, do not create an object though possible + if (manual_type == value_t::array) + { + is_an_object = false; + } + + // if object is wanted but impossible, throw an exception + if (JSON_UNLIKELY(manual_type == value_t::object and not is_an_object)) + { + JSON_THROW(type_error::create(301, "cannot create object from initializer list")); + } + } + + if (is_an_object) + { + // the initializer list is a list of pairs -> create object + m_type = value_t::object; + m_value = value_t::object; + + std::for_each(init.begin(), init.end(), [this](const detail::json_ref& element_ref) + { + auto element = element_ref.moved_or_copied(); + m_value.object->emplace( + std::move(*((*element.m_value.array)[0].m_value.string)), + std::move((*element.m_value.array)[1])); + }); + } + else + { + // the initializer list describes an array -> create array + m_type = value_t::array; + m_value.array = create(init.begin(), init.end()); + } + + assert_invariant(); + } + + /*! + @brief explicitly create an array from an initializer list + + Creates a JSON array value from a given initializer list. That is, given a + list of values `a, b, c`, creates the JSON value `[a, b, c]`. If the + initializer list is empty, the empty array `[]` is created. + + @note This function is only needed to express two edge cases that cannot + be realized with the initializer list constructor (@ref + basic_json(initializer_list_t, bool, value_t)). These cases + are: + 1. creating an array whose elements are all pairs whose first element is a + string -- in this case, the initializer list constructor would create an + object, taking the first elements as keys + 2. creating an empty array -- passing the empty initializer list to the + initializer list constructor yields an empty object + + @param[in] init initializer list with JSON values to create an array from + (optional) + + @return JSON array value + + @complexity Linear in the size of @a init. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @liveexample{The following code shows an example for the `array` + function.,array} + + @sa @ref basic_json(initializer_list_t, bool, value_t) -- + create a JSON value from an initializer list + @sa @ref object(initializer_list_t) -- create a JSON object + value from an initializer list + + @since version 1.0.0 + */ + static basic_json array(initializer_list_t init = {}) + { + return basic_json(init, false, value_t::array); + } + + /*! + @brief explicitly create an object from an initializer list + + Creates a JSON object value from a given initializer list. The initializer + lists elements must be pairs, and their first elements must be strings. If + the initializer list is empty, the empty object `{}` is created. + + @note This function is only added for symmetry reasons. In contrast to the + related function @ref array(initializer_list_t), there are + no cases which can only be expressed by this function. That is, any + initializer list @a init can also be passed to the initializer list + constructor @ref basic_json(initializer_list_t, bool, value_t). + + @param[in] init initializer list to create an object from (optional) + + @return JSON object value + + @throw type_error.301 if @a init is not a list of pairs whose first + elements are strings. In this case, no object can be created. When such a + value is passed to @ref basic_json(initializer_list_t, bool, value_t), + an array would have been created from the passed initializer list @a init. + See example below. + + @complexity Linear in the size of @a init. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @liveexample{The following code shows an example for the `object` + function.,object} + + @sa @ref basic_json(initializer_list_t, bool, value_t) -- + create a JSON value from an initializer list + @sa @ref array(initializer_list_t) -- create a JSON array + value from an initializer list + + @since version 1.0.0 + */ + static basic_json object(initializer_list_t init = {}) + { + return basic_json(init, false, value_t::object); + } + + /*! + @brief construct an array with count copies of given value + + Constructs a JSON array value by creating @a cnt copies of a passed value. + In case @a cnt is `0`, an empty array is created. + + @param[in] cnt the number of JSON copies of @a val to create + @param[in] val the JSON value to copy + + @post `std::distance(begin(),end()) == cnt` holds. + + @complexity Linear in @a cnt. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @liveexample{The following code shows examples for the @ref + basic_json(size_type\, const basic_json&) + constructor.,basic_json__size_type_basic_json} + + @since version 1.0.0 + */ + basic_json(size_type cnt, const basic_json& val) + : m_type(value_t::array) + { + m_value.array = create(cnt, val); + assert_invariant(); + } + + /*! + @brief construct a JSON container given an iterator range + + Constructs the JSON value with the contents of the range `[first, last)`. + The semantics depends on the different types a JSON value can have: + - In case of a null type, invalid_iterator.206 is thrown. + - In case of other primitive types (number, boolean, or string), @a first + must be `begin()` and @a last must be `end()`. In this case, the value is + copied. Otherwise, invalid_iterator.204 is thrown. + - In case of structured types (array, object), the constructor behaves as + similar versions for `std::vector` or `std::map`; that is, a JSON array + or object is constructed from the values in the range. + + @tparam InputIT an input iterator type (@ref iterator or @ref + const_iterator) + + @param[in] first begin of the range to copy from (included) + @param[in] last end of the range to copy from (excluded) + + @pre Iterators @a first and @a last must be initialized. **This + precondition is enforced with an assertion (see warning).** If + assertions are switched off, a violation of this precondition yields + undefined behavior. + + @pre Range `[first, last)` is valid. Usually, this precondition cannot be + checked efficiently. Only certain edge cases are detected; see the + description of the exceptions below. A violation of this precondition + yields undefined behavior. + + @warning A precondition is enforced with a runtime assertion that will + result in calling `std::abort` if this precondition is not met. + Assertions can be disabled by defining `NDEBUG` at compile time. + See http://en.cppreference.com/w/cpp/error/assert for more + information. + + @throw invalid_iterator.201 if iterators @a first and @a last are not + compatible (i.e., do not belong to the same JSON value). In this case, + the range `[first, last)` is undefined. + @throw invalid_iterator.204 if iterators @a first and @a last belong to a + primitive type (number, boolean, or string), but @a first does not point + to the first element any more. In this case, the range `[first, last)` is + undefined. See example code below. + @throw invalid_iterator.206 if iterators @a first and @a last belong to a + null value. In this case, the range `[first, last)` is undefined. + + @complexity Linear in distance between @a first and @a last. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @liveexample{The example below shows several ways to create JSON values by + specifying a subrange with iterators.,basic_json__InputIt_InputIt} + + @since version 1.0.0 + */ + template::value or + std::is_same::value, int>::type = 0> + basic_json(InputIT first, InputIT last) + { + assert(first.m_object != nullptr); + assert(last.m_object != nullptr); + + // make sure iterator fits the current value + if (JSON_UNLIKELY(first.m_object != last.m_object)) + { + JSON_THROW(invalid_iterator::create(201, "iterators are not compatible")); + } + + // copy type from first iterator + m_type = first.m_object->m_type; + + // check if iterator range is complete for primitive values + switch (m_type) + { + case value_t::boolean: + case value_t::number_float: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::string: + { + if (JSON_UNLIKELY(not first.m_it.primitive_iterator.is_begin() + or not last.m_it.primitive_iterator.is_end())) + { + JSON_THROW(invalid_iterator::create(204, "iterators out of range")); + } + break; + } + + default: + break; + } + + switch (m_type) + { + case value_t::number_integer: + { + m_value.number_integer = first.m_object->m_value.number_integer; + break; + } + + case value_t::number_unsigned: + { + m_value.number_unsigned = first.m_object->m_value.number_unsigned; + break; + } + + case value_t::number_float: + { + m_value.number_float = first.m_object->m_value.number_float; + break; + } + + case value_t::boolean: + { + m_value.boolean = first.m_object->m_value.boolean; + break; + } + + case value_t::string: + { + m_value = *first.m_object->m_value.string; + break; + } + + case value_t::object: + { + m_value.object = create(first.m_it.object_iterator, + last.m_it.object_iterator); + break; + } + + case value_t::array: + { + m_value.array = create(first.m_it.array_iterator, + last.m_it.array_iterator); + break; + } + + default: + JSON_THROW(invalid_iterator::create(206, "cannot construct with iterators from " + + std::string(first.m_object->type_name()))); + } + + assert_invariant(); + } + + + /////////////////////////////////////// + // other constructors and destructor // + /////////////////////////////////////// + + /// @private + basic_json(const detail::json_ref& ref) + : basic_json(ref.moved_or_copied()) + {} + + /*! + @brief copy constructor + + Creates a copy of a given JSON value. + + @param[in] other the JSON value to copy + + @post `*this == other` + + @complexity Linear in the size of @a other. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is linear. + - As postcondition, it holds: `other == basic_json(other)`. + + @liveexample{The following code shows an example for the copy + constructor.,basic_json__basic_json} + + @since version 1.0.0 + */ + basic_json(const basic_json& other) + : m_type(other.m_type) + { + // check of passed value is valid + other.assert_invariant(); + + switch (m_type) + { + case value_t::object: + { + m_value = *other.m_value.object; + break; + } + + case value_t::array: + { + m_value = *other.m_value.array; + break; + } + + case value_t::string: + { + m_value = *other.m_value.string; + break; + } + + case value_t::boolean: + { + m_value = other.m_value.boolean; + break; + } + + case value_t::number_integer: + { + m_value = other.m_value.number_integer; + break; + } + + case value_t::number_unsigned: + { + m_value = other.m_value.number_unsigned; + break; + } + + case value_t::number_float: + { + m_value = other.m_value.number_float; + break; + } + + default: + break; + } + + assert_invariant(); + } + + /*! + @brief move constructor + + Move constructor. Constructs a JSON value with the contents of the given + value @a other using move semantics. It "steals" the resources from @a + other and leaves it as JSON null value. + + @param[in,out] other value to move to this object + + @post `*this` has the same value as @a other before the call. + @post @a other is a JSON null value. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this constructor never throws + exceptions. + + @requirement This function helps `basic_json` satisfying the + [MoveConstructible](http://en.cppreference.com/w/cpp/concept/MoveConstructible) + requirements. + + @liveexample{The code below shows the move constructor explicitly called + via std::move.,basic_json__moveconstructor} + + @since version 1.0.0 + */ + basic_json(basic_json&& other) noexcept + : m_type(std::move(other.m_type)), + m_value(std::move(other.m_value)) + { + // check that passed value is valid + other.assert_invariant(); + + // invalidate payload + other.m_type = value_t::null; + other.m_value = {}; + + assert_invariant(); + } + + /*! + @brief copy assignment + + Copy assignment operator. Copies a JSON value via the "copy and swap" + strategy: It is expressed in terms of the copy constructor, destructor, + and the `swap()` member function. + + @param[in] other value to copy from + + @complexity Linear. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is linear. + + @liveexample{The code below shows and example for the copy assignment. It + creates a copy of value `a` which is then swapped with `b`. Finally\, the + copy of `a` (which is the null value after the swap) is + destroyed.,basic_json__copyassignment} + + @since version 1.0.0 + */ + reference& operator=(basic_json other) noexcept ( + std::is_nothrow_move_constructible::value and + std::is_nothrow_move_assignable::value and + std::is_nothrow_move_constructible::value and + std::is_nothrow_move_assignable::value + ) + { + // check that passed value is valid + other.assert_invariant(); + + using std::swap; + swap(m_type, other.m_type); + swap(m_value, other.m_value); + + assert_invariant(); + return *this; + } + + /*! + @brief destructor + + Destroys the JSON value and frees all allocated memory. + + @complexity Linear. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is linear. + - All stored elements are destroyed and all memory is freed. + + @since version 1.0.0 + */ + ~basic_json() + { + assert_invariant(); + m_value.destroy(m_type); + } + + /// @} + + public: + /////////////////////// + // object inspection // + /////////////////////// + + /// @name object inspection + /// Functions to inspect the type of a JSON value. + /// @{ + + /*! + @brief serialization + + Serialization function for JSON values. The function tries to mimic + Python's `json.dumps()` function, and currently supports its @a indent + and @a ensure_ascii parameters. + + @param[in] indent If indent is nonnegative, then array elements and object + members will be pretty-printed with that indent level. An indent level of + `0` will only insert newlines. `-1` (the default) selects the most compact + representation. + @param[in] indent_char The character to use for indentation if @a indent is + greater than `0`. The default is ` ` (space). + @param[in] ensure_ascii If @a ensure_ascii is true, all non-ASCII characters + in the output are escaped with `\uXXXX` sequences, and the result consists + of ASCII characters only. + + @return string containing the serialization of the JSON value + + @throw type_error.316 if a string stored inside the JSON value is not + UTF-8 encoded + + @complexity Linear. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @liveexample{The following example shows the effect of different @a indent\, + @a indent_char\, and @a ensure_ascii parameters to the result of the + serialization.,dump} + + @see https://docs.python.org/2/library/json.html#json.dump + + @since version 1.0.0; indentation character @a indent_char, option + @a ensure_ascii and exceptions added in version 3.0.0 + */ + string_t dump(const int indent = -1, const char indent_char = ' ', + const bool ensure_ascii = false) const + { + string_t result; + serializer s(detail::output_adapter(result), indent_char); + + if (indent >= 0) + { + s.dump(*this, true, ensure_ascii, static_cast(indent)); + } + else + { + s.dump(*this, false, ensure_ascii, 0); + } + + return result; + } + + /*! + @brief return the type of the JSON value (explicit) + + Return the type of the JSON value as a value from the @ref value_t + enumeration. + + @return the type of the JSON value + Value type | return value + ------------------------- | ------------------------- + null | value_t::null + boolean | value_t::boolean + string | value_t::string + number (integer) | value_t::number_integer + number (unsigned integer) | value_t::number_unsigned + number (floating-point) | value_t::number_float + object | value_t::object + array | value_t::array + discarded | value_t::discarded + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `type()` for all JSON + types.,type} + + @sa @ref operator value_t() -- return the type of the JSON value (implicit) + @sa @ref type_name() -- return the type as string + + @since version 1.0.0 + */ + constexpr value_t type() const noexcept + { + return m_type; + } + + /*! + @brief return whether type is primitive + + This function returns true if and only if the JSON type is primitive + (string, number, boolean, or null). + + @return `true` if type is primitive (string, number, boolean, or null), + `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_primitive()` for all JSON + types.,is_primitive} + + @sa @ref is_structured() -- returns whether JSON value is structured + @sa @ref is_null() -- returns whether JSON value is `null` + @sa @ref is_string() -- returns whether JSON value is a string + @sa @ref is_boolean() -- returns whether JSON value is a boolean + @sa @ref is_number() -- returns whether JSON value is a number + + @since version 1.0.0 + */ + constexpr bool is_primitive() const noexcept + { + return is_null() or is_string() or is_boolean() or is_number(); + } + + /*! + @brief return whether type is structured + + This function returns true if and only if the JSON type is structured + (array or object). + + @return `true` if type is structured (array or object), `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_structured()` for all JSON + types.,is_structured} + + @sa @ref is_primitive() -- returns whether value is primitive + @sa @ref is_array() -- returns whether value is an array + @sa @ref is_object() -- returns whether value is an object + + @since version 1.0.0 + */ + constexpr bool is_structured() const noexcept + { + return is_array() or is_object(); + } + + /*! + @brief return whether value is null + + This function returns true if and only if the JSON value is null. + + @return `true` if type is null, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_null()` for all JSON + types.,is_null} + + @since version 1.0.0 + */ + constexpr bool is_null() const noexcept + { + return (m_type == value_t::null); + } + + /*! + @brief return whether value is a boolean + + This function returns true if and only if the JSON value is a boolean. + + @return `true` if type is boolean, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_boolean()` for all JSON + types.,is_boolean} + + @since version 1.0.0 + */ + constexpr bool is_boolean() const noexcept + { + return (m_type == value_t::boolean); + } + + /*! + @brief return whether value is a number + + This function returns true if and only if the JSON value is a number. This + includes both integer (signed and unsigned) and floating-point values. + + @return `true` if type is number (regardless whether integer, unsigned + integer or floating-type), `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_number()` for all JSON + types.,is_number} + + @sa @ref is_number_integer() -- check if value is an integer or unsigned + integer number + @sa @ref is_number_unsigned() -- check if value is an unsigned integer + number + @sa @ref is_number_float() -- check if value is a floating-point number + + @since version 1.0.0 + */ + constexpr bool is_number() const noexcept + { + return is_number_integer() or is_number_float(); + } + + /*! + @brief return whether value is an integer number + + This function returns true if and only if the JSON value is a signed or + unsigned integer number. This excludes floating-point values. + + @return `true` if type is an integer or unsigned integer number, `false` + otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_number_integer()` for all + JSON types.,is_number_integer} + + @sa @ref is_number() -- check if value is a number + @sa @ref is_number_unsigned() -- check if value is an unsigned integer + number + @sa @ref is_number_float() -- check if value is a floating-point number + + @since version 1.0.0 + */ + constexpr bool is_number_integer() const noexcept + { + return (m_type == value_t::number_integer or m_type == value_t::number_unsigned); + } + + /*! + @brief return whether value is an unsigned integer number + + This function returns true if and only if the JSON value is an unsigned + integer number. This excludes floating-point and signed integer values. + + @return `true` if type is an unsigned integer number, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_number_unsigned()` for all + JSON types.,is_number_unsigned} + + @sa @ref is_number() -- check if value is a number + @sa @ref is_number_integer() -- check if value is an integer or unsigned + integer number + @sa @ref is_number_float() -- check if value is a floating-point number + + @since version 2.0.0 + */ + constexpr bool is_number_unsigned() const noexcept + { + return (m_type == value_t::number_unsigned); + } + + /*! + @brief return whether value is a floating-point number + + This function returns true if and only if the JSON value is a + floating-point number. This excludes signed and unsigned integer values. + + @return `true` if type is a floating-point number, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_number_float()` for all + JSON types.,is_number_float} + + @sa @ref is_number() -- check if value is number + @sa @ref is_number_integer() -- check if value is an integer number + @sa @ref is_number_unsigned() -- check if value is an unsigned integer + number + + @since version 1.0.0 + */ + constexpr bool is_number_float() const noexcept + { + return (m_type == value_t::number_float); + } + + /*! + @brief return whether value is an object + + This function returns true if and only if the JSON value is an object. + + @return `true` if type is object, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_object()` for all JSON + types.,is_object} + + @since version 1.0.0 + */ + constexpr bool is_object() const noexcept + { + return (m_type == value_t::object); + } + + /*! + @brief return whether value is an array + + This function returns true if and only if the JSON value is an array. + + @return `true` if type is array, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_array()` for all JSON + types.,is_array} + + @since version 1.0.0 + */ + constexpr bool is_array() const noexcept + { + return (m_type == value_t::array); + } + + /*! + @brief return whether value is a string + + This function returns true if and only if the JSON value is a string. + + @return `true` if type is string, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_string()` for all JSON + types.,is_string} + + @since version 1.0.0 + */ + constexpr bool is_string() const noexcept + { + return (m_type == value_t::string); + } + + /*! + @brief return whether value is discarded + + This function returns true if and only if the JSON value was discarded + during parsing with a callback function (see @ref parser_callback_t). + + @note This function will always be `false` for JSON values after parsing. + That is, discarded values can only occur during parsing, but will be + removed when inside a structured value or replaced by null in other cases. + + @return `true` if type is discarded, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_discarded()` for all JSON + types.,is_discarded} + + @since version 1.0.0 + */ + constexpr bool is_discarded() const noexcept + { + return (m_type == value_t::discarded); + } + + /*! + @brief return the type of the JSON value (implicit) + + Implicitly return the type of the JSON value as a value from the @ref + value_t enumeration. + + @return the type of the JSON value + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies the @ref value_t operator for + all JSON types.,operator__value_t} + + @sa @ref type() -- return the type of the JSON value (explicit) + @sa @ref type_name() -- return the type as string + + @since version 1.0.0 + */ + constexpr operator value_t() const noexcept + { + return m_type; + } + + /// @} + + private: + ////////////////// + // value access // + ////////////////// + + /// get a boolean (explicit) + boolean_t get_impl(boolean_t* /*unused*/) const + { + if (JSON_LIKELY(is_boolean())) + { + return m_value.boolean; + } + + JSON_THROW(type_error::create(302, "type must be boolean, but is " + std::string(type_name()))); + } + + /// get a pointer to the value (object) + object_t* get_impl_ptr(object_t* /*unused*/) noexcept + { + return is_object() ? m_value.object : nullptr; + } + + /// get a pointer to the value (object) + constexpr const object_t* get_impl_ptr(const object_t* /*unused*/) const noexcept + { + return is_object() ? m_value.object : nullptr; + } + + /// get a pointer to the value (array) + array_t* get_impl_ptr(array_t* /*unused*/) noexcept + { + return is_array() ? m_value.array : nullptr; + } + + /// get a pointer to the value (array) + constexpr const array_t* get_impl_ptr(const array_t* /*unused*/) const noexcept + { + return is_array() ? m_value.array : nullptr; + } + + /// get a pointer to the value (string) + string_t* get_impl_ptr(string_t* /*unused*/) noexcept + { + return is_string() ? m_value.string : nullptr; + } + + /// get a pointer to the value (string) + constexpr const string_t* get_impl_ptr(const string_t* /*unused*/) const noexcept + { + return is_string() ? m_value.string : nullptr; + } + + /// get a pointer to the value (boolean) + boolean_t* get_impl_ptr(boolean_t* /*unused*/) noexcept + { + return is_boolean() ? &m_value.boolean : nullptr; + } + + /// get a pointer to the value (boolean) + constexpr const boolean_t* get_impl_ptr(const boolean_t* /*unused*/) const noexcept + { + return is_boolean() ? &m_value.boolean : nullptr; + } + + /// get a pointer to the value (integer number) + number_integer_t* get_impl_ptr(number_integer_t* /*unused*/) noexcept + { + return is_number_integer() ? &m_value.number_integer : nullptr; + } + + /// get a pointer to the value (integer number) + constexpr const number_integer_t* get_impl_ptr(const number_integer_t* /*unused*/) const noexcept + { + return is_number_integer() ? &m_value.number_integer : nullptr; + } + + /// get a pointer to the value (unsigned number) + number_unsigned_t* get_impl_ptr(number_unsigned_t* /*unused*/) noexcept + { + return is_number_unsigned() ? &m_value.number_unsigned : nullptr; + } + + /// get a pointer to the value (unsigned number) + constexpr const number_unsigned_t* get_impl_ptr(const number_unsigned_t* /*unused*/) const noexcept + { + return is_number_unsigned() ? &m_value.number_unsigned : nullptr; + } + + /// get a pointer to the value (floating-point number) + number_float_t* get_impl_ptr(number_float_t* /*unused*/) noexcept + { + return is_number_float() ? &m_value.number_float : nullptr; + } + + /// get a pointer to the value (floating-point number) + constexpr const number_float_t* get_impl_ptr(const number_float_t* /*unused*/) const noexcept + { + return is_number_float() ? &m_value.number_float : nullptr; + } + + /*! + @brief helper function to implement get_ref() + + This function helps to implement get_ref() without code duplication for + const and non-const overloads + + @tparam ThisType will be deduced as `basic_json` or `const basic_json` + + @throw type_error.303 if ReferenceType does not match underlying value + type of the current JSON + */ + template + static ReferenceType get_ref_impl(ThisType& obj) + { + // delegate the call to get_ptr<>() + auto ptr = obj.template get_ptr::type>(); + + if (JSON_LIKELY(ptr != nullptr)) + { + return *ptr; + } + + JSON_THROW(type_error::create(303, "incompatible ReferenceType for get_ref, actual type is " + std::string(obj.type_name()))); + } + + public: + /// @name value access + /// Direct access to the stored value of a JSON value. + /// @{ + + /*! + @brief get special-case overload + + This overloads avoids a lot of template boilerplate, it can be seen as the + identity method + + @tparam BasicJsonType == @ref basic_json + + @return a copy of *this + + @complexity Constant. + + @since version 2.1.0 + */ + template::type, basic_json_t>::value, + int> = 0> + basic_json get() const + { + return *this; + } + + /*! + @brief get a value (explicit) + + Explicit type conversion between the JSON value and a compatible value + which is [CopyConstructible](http://en.cppreference.com/w/cpp/concept/CopyConstructible) + and [DefaultConstructible](http://en.cppreference.com/w/cpp/concept/DefaultConstructible). + The value is converted by calling the @ref json_serializer + `from_json()` method. + + The function is equivalent to executing + @code {.cpp} + ValueType ret; + JSONSerializer::from_json(*this, ret); + return ret; + @endcode + + This overloads is chosen if: + - @a ValueType is not @ref basic_json, + - @ref json_serializer has a `from_json()` method of the form + `void from_json(const basic_json&, ValueType&)`, and + - @ref json_serializer does not have a `from_json()` method of + the form `ValueType from_json(const basic_json&)` + + @tparam ValueTypeCV the provided value type + @tparam ValueType the returned value type + + @return copy of the JSON value, converted to @a ValueType + + @throw what @ref json_serializer `from_json()` method throws + + @liveexample{The example below shows several conversions from JSON values + to other types. There a few things to note: (1) Floating-point numbers can + be converted to integers\, (2) A JSON array can be converted to a standard + `std::vector`\, (3) A JSON object can be converted to C++ + associative containers such as `std::unordered_map`.,get__ValueType_const} + + @since version 2.1.0 + */ + template, + detail::enable_if_t < + not std::is_same::value and + detail::has_from_json::value and + not detail::has_non_default_from_json::value, + int> = 0> + ValueType get() const noexcept(noexcept( + JSONSerializer::from_json(std::declval(), std::declval()))) + { + // we cannot static_assert on ValueTypeCV being non-const, because + // there is support for get(), which is why we + // still need the uncvref + static_assert(not std::is_reference::value, + "get() cannot be used with reference types, you might want to use get_ref()"); + static_assert(std::is_default_constructible::value, + "types must be DefaultConstructible when used with get()"); + + ValueType ret; + JSONSerializer::from_json(*this, ret); + return ret; + } + + /*! + @brief get a value (explicit); special case + + Explicit type conversion between the JSON value and a compatible value + which is **not** [CopyConstructible](http://en.cppreference.com/w/cpp/concept/CopyConstructible) + and **not** [DefaultConstructible](http://en.cppreference.com/w/cpp/concept/DefaultConstructible). + The value is converted by calling the @ref json_serializer + `from_json()` method. + + The function is equivalent to executing + @code {.cpp} + return JSONSerializer::from_json(*this); + @endcode + + This overloads is chosen if: + - @a ValueType is not @ref basic_json and + - @ref json_serializer has a `from_json()` method of the form + `ValueType from_json(const basic_json&)` + + @note If @ref json_serializer has both overloads of + `from_json()`, this one is chosen. + + @tparam ValueTypeCV the provided value type + @tparam ValueType the returned value type + + @return copy of the JSON value, converted to @a ValueType + + @throw what @ref json_serializer `from_json()` method throws + + @since version 2.1.0 + */ + template, + detail::enable_if_t::value and + detail::has_non_default_from_json::value, + int> = 0> + ValueType get() const noexcept(noexcept( + JSONSerializer::from_json(std::declval()))) + { + static_assert(not std::is_reference::value, + "get() cannot be used with reference types, you might want to use get_ref()"); + return JSONSerializer::from_json(*this); + } + + /*! + @brief get a pointer value (explicit) + + Explicit pointer access to the internally stored JSON value. No copies are + made. + + @warning The pointer becomes invalid if the underlying JSON object + changes. + + @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref + object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, + @ref number_unsigned_t, or @ref number_float_t. + + @return pointer to the internally stored JSON value if the requested + pointer type @a PointerType fits to the JSON value; `nullptr` otherwise + + @complexity Constant. + + @liveexample{The example below shows how pointers to internal values of a + JSON value can be requested. Note that no type conversions are made and a + `nullptr` is returned if the value and the requested pointer type does not + match.,get__PointerType} + + @sa @ref get_ptr() for explicit pointer-member access + + @since version 1.0.0 + */ + template::value, int>::type = 0> + PointerType get() noexcept + { + // delegate the call to get_ptr + return get_ptr(); + } + + /*! + @brief get a pointer value (explicit) + @copydoc get() + */ + template::value, int>::type = 0> + constexpr const PointerType get() const noexcept + { + // delegate the call to get_ptr + return get_ptr(); + } + + /*! + @brief get a pointer value (implicit) + + Implicit pointer access to the internally stored JSON value. No copies are + made. + + @warning Writing data to the pointee of the result yields an undefined + state. + + @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref + object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, + @ref number_unsigned_t, or @ref number_float_t. Enforced by a static + assertion. + + @return pointer to the internally stored JSON value if the requested + pointer type @a PointerType fits to the JSON value; `nullptr` otherwise + + @complexity Constant. + + @liveexample{The example below shows how pointers to internal values of a + JSON value can be requested. Note that no type conversions are made and a + `nullptr` is returned if the value and the requested pointer type does not + match.,get_ptr} + + @since version 1.0.0 + */ + template::value, int>::type = 0> + PointerType get_ptr() noexcept + { + // get the type of the PointerType (remove pointer and const) + using pointee_t = typename std::remove_const::type>::type>::type; + // make sure the type matches the allowed types + static_assert( + std::is_same::value + or std::is_same::value + or std::is_same::value + or std::is_same::value + or std::is_same::value + or std::is_same::value + or std::is_same::value + , "incompatible pointer type"); + + // delegate the call to get_impl_ptr<>() + return get_impl_ptr(static_cast(nullptr)); + } + + /*! + @brief get a pointer value (implicit) + @copydoc get_ptr() + */ + template::value and + std::is_const::type>::value, int>::type = 0> + constexpr const PointerType get_ptr() const noexcept + { + // get the type of the PointerType (remove pointer and const) + using pointee_t = typename std::remove_const::type>::type>::type; + // make sure the type matches the allowed types + static_assert( + std::is_same::value + or std::is_same::value + or std::is_same::value + or std::is_same::value + or std::is_same::value + or std::is_same::value + or std::is_same::value + , "incompatible pointer type"); + + // delegate the call to get_impl_ptr<>() const + return get_impl_ptr(static_cast(nullptr)); + } + + /*! + @brief get a reference value (implicit) + + Implicit reference access to the internally stored JSON value. No copies + are made. + + @warning Writing data to the referee of the result yields an undefined + state. + + @tparam ReferenceType reference type; must be a reference to @ref array_t, + @ref object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, or + @ref number_float_t. Enforced by static assertion. + + @return reference to the internally stored JSON value if the requested + reference type @a ReferenceType fits to the JSON value; throws + type_error.303 otherwise + + @throw type_error.303 in case passed type @a ReferenceType is incompatible + with the stored JSON value; see example below + + @complexity Constant. + + @liveexample{The example shows several calls to `get_ref()`.,get_ref} + + @since version 1.1.0 + */ + template::value, int>::type = 0> + ReferenceType get_ref() + { + // delegate call to get_ref_impl + return get_ref_impl(*this); + } + + /*! + @brief get a reference value (implicit) + @copydoc get_ref() + */ + template::value and + std::is_const::type>::value, int>::type = 0> + ReferenceType get_ref() const + { + // delegate call to get_ref_impl + return get_ref_impl(*this); + } + + /*! + @brief get a value (implicit) + + Implicit type conversion between the JSON value and a compatible value. + The call is realized by calling @ref get() const. + + @tparam ValueType non-pointer type compatible to the JSON value, for + instance `int` for JSON integer numbers, `bool` for JSON booleans, or + `std::vector` types for JSON arrays. The character type of @ref string_t + as well as an initializer list of this type is excluded to avoid + ambiguities as these types implicitly convert to `std::string`. + + @return copy of the JSON value, converted to type @a ValueType + + @throw type_error.302 in case passed type @a ValueType is incompatible + to the JSON value type (e.g., the JSON value is of type boolean, but a + string is requested); see example below + + @complexity Linear in the size of the JSON value. + + @liveexample{The example below shows several conversions from JSON values + to other types. There a few things to note: (1) Floating-point numbers can + be converted to integers\, (2) A JSON array can be converted to a standard + `std::vector`\, (3) A JSON object can be converted to C++ + associative containers such as `std::unordered_map`.,operator__ValueType} + + @since version 1.0.0 + */ + template < typename ValueType, typename std::enable_if < + not std::is_pointer::value and + not std::is_same>::value and + not std::is_same::value +#ifndef _MSC_VER // fix for issue #167 operator<< ambiguity under VS2015 + and not std::is_same>::value +#endif +#if defined(JSON_HAS_CPP_17) + and not std::is_same::value +#endif + , int >::type = 0 > + operator ValueType() const + { + // delegate the call to get<>() const + return get(); + } + + /// @} + + + //////////////////// + // element access // + //////////////////// + + /// @name element access + /// Access to the JSON value. + /// @{ + + /*! + @brief access specified array element with bounds checking + + Returns a reference to the element at specified location @a idx, with + bounds checking. + + @param[in] idx index of the element to access + + @return reference to the element at index @a idx + + @throw type_error.304 if the JSON value is not an array; in this case, + calling `at` with an index makes no sense. See example below. + @throw out_of_range.401 if the index @a idx is out of range of the array; + that is, `idx >= size()`. See example below. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Constant. + + @since version 1.0.0 + + @liveexample{The example below shows how array elements can be read and + written using `at()`. It also demonstrates the different exceptions that + can be thrown.,at__size_type} + */ + reference at(size_type idx) + { + // at only works for arrays + if (JSON_LIKELY(is_array())) + { + JSON_TRY + { + return m_value.array->at(idx); + } + JSON_CATCH (std::out_of_range&) + { + // create better exception explanation + JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range")); + } + } + else + { + JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name()))); + } + } + + /*! + @brief access specified array element with bounds checking + + Returns a const reference to the element at specified location @a idx, + with bounds checking. + + @param[in] idx index of the element to access + + @return const reference to the element at index @a idx + + @throw type_error.304 if the JSON value is not an array; in this case, + calling `at` with an index makes no sense. See example below. + @throw out_of_range.401 if the index @a idx is out of range of the array; + that is, `idx >= size()`. See example below. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Constant. + + @since version 1.0.0 + + @liveexample{The example below shows how array elements can be read using + `at()`. It also demonstrates the different exceptions that can be thrown., + at__size_type_const} + */ + const_reference at(size_type idx) const + { + // at only works for arrays + if (JSON_LIKELY(is_array())) + { + JSON_TRY + { + return m_value.array->at(idx); + } + JSON_CATCH (std::out_of_range&) + { + // create better exception explanation + JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range")); + } + } + else + { + JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name()))); + } + } + + /*! + @brief access specified object element with bounds checking + + Returns a reference to the element at with specified key @a key, with + bounds checking. + + @param[in] key key of the element to access + + @return reference to the element at key @a key + + @throw type_error.304 if the JSON value is not an object; in this case, + calling `at` with a key makes no sense. See example below. + @throw out_of_range.403 if the key @a key is is not stored in the object; + that is, `find(key) == end()`. See example below. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Logarithmic in the size of the container. + + @sa @ref operator[](const typename object_t::key_type&) for unchecked + access by reference + @sa @ref value() for access by value with a default value + + @since version 1.0.0 + + @liveexample{The example below shows how object elements can be read and + written using `at()`. It also demonstrates the different exceptions that + can be thrown.,at__object_t_key_type} + */ + reference at(const typename object_t::key_type& key) + { + // at only works for objects + if (JSON_LIKELY(is_object())) + { + JSON_TRY + { + return m_value.object->at(key); + } + JSON_CATCH (std::out_of_range&) + { + // create better exception explanation + JSON_THROW(out_of_range::create(403, "key '" + key + "' not found")); + } + } + else + { + JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name()))); + } + } + + /*! + @brief access specified object element with bounds checking + + Returns a const reference to the element at with specified key @a key, + with bounds checking. + + @param[in] key key of the element to access + + @return const reference to the element at key @a key + + @throw type_error.304 if the JSON value is not an object; in this case, + calling `at` with a key makes no sense. See example below. + @throw out_of_range.403 if the key @a key is is not stored in the object; + that is, `find(key) == end()`. See example below. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Logarithmic in the size of the container. + + @sa @ref operator[](const typename object_t::key_type&) for unchecked + access by reference + @sa @ref value() for access by value with a default value + + @since version 1.0.0 + + @liveexample{The example below shows how object elements can be read using + `at()`. It also demonstrates the different exceptions that can be thrown., + at__object_t_key_type_const} + */ + const_reference at(const typename object_t::key_type& key) const + { + // at only works for objects + if (JSON_LIKELY(is_object())) + { + JSON_TRY + { + return m_value.object->at(key); + } + JSON_CATCH (std::out_of_range&) + { + // create better exception explanation + JSON_THROW(out_of_range::create(403, "key '" + key + "' not found")); + } + } + else + { + JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name()))); + } + } + + /*! + @brief access specified array element + + Returns a reference to the element at specified location @a idx. + + @note If @a idx is beyond the range of the array (i.e., `idx >= size()`), + then the array is silently filled up with `null` values to make `idx` a + valid reference to the last stored element. + + @param[in] idx index of the element to access + + @return reference to the element at index @a idx + + @throw type_error.305 if the JSON value is not an array or null; in that + cases, using the [] operator with an index makes no sense. + + @complexity Constant if @a idx is in the range of the array. Otherwise + linear in `idx - size()`. + + @liveexample{The example below shows how array elements can be read and + written using `[]` operator. Note the addition of `null` + values.,operatorarray__size_type} + + @since version 1.0.0 + */ + reference operator[](size_type idx) + { + // implicitly convert null value to an empty array + if (is_null()) + { + m_type = value_t::array; + m_value.array = create(); + assert_invariant(); + } + + // operator[] only works for arrays + if (JSON_LIKELY(is_array())) + { + // fill up array with null values if given idx is outside range + if (idx >= m_value.array->size()) + { + m_value.array->insert(m_value.array->end(), + idx - m_value.array->size() + 1, + basic_json()); + } + + return m_value.array->operator[](idx); + } + + JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); + } + + /*! + @brief access specified array element + + Returns a const reference to the element at specified location @a idx. + + @param[in] idx index of the element to access + + @return const reference to the element at index @a idx + + @throw type_error.305 if the JSON value is not an array; in that case, + using the [] operator with an index makes no sense. + + @complexity Constant. + + @liveexample{The example below shows how array elements can be read using + the `[]` operator.,operatorarray__size_type_const} + + @since version 1.0.0 + */ + const_reference operator[](size_type idx) const + { + // const operator[] only works for arrays + if (JSON_LIKELY(is_array())) + { + return m_value.array->operator[](idx); + } + + JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); + } + + /*! + @brief access specified object element + + Returns a reference to the element at with specified key @a key. + + @note If @a key is not found in the object, then it is silently added to + the object and filled with a `null` value to make `key` a valid reference. + In case the value was `null` before, it is converted to an object. + + @param[in] key key of the element to access + + @return reference to the element at key @a key + + @throw type_error.305 if the JSON value is not an object or null; in that + cases, using the [] operator with a key makes no sense. + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read and + written using the `[]` operator.,operatorarray__key_type} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value + + @since version 1.0.0 + */ + reference operator[](const typename object_t::key_type& key) + { + // implicitly convert null value to an empty object + if (is_null()) + { + m_type = value_t::object; + m_value.object = create(); + assert_invariant(); + } + + // operator[] only works for objects + if (JSON_LIKELY(is_object())) + { + return m_value.object->operator[](key); + } + + JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); + } + + /*! + @brief read-only access specified object element + + Returns a const reference to the element at with specified key @a key. No + bounds checking is performed. + + @warning If the element with key @a key does not exist, the behavior is + undefined. + + @param[in] key key of the element to access + + @return const reference to the element at key @a key + + @pre The element with key @a key must exist. **This precondition is + enforced with an assertion.** + + @throw type_error.305 if the JSON value is not an object; in that case, + using the [] operator with a key makes no sense. + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read using + the `[]` operator.,operatorarray__key_type_const} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value + + @since version 1.0.0 + */ + const_reference operator[](const typename object_t::key_type& key) const + { + // const operator[] only works for objects + if (JSON_LIKELY(is_object())) + { + assert(m_value.object->find(key) != m_value.object->end()); + return m_value.object->find(key)->second; + } + + JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); + } + + /*! + @brief access specified object element + + Returns a reference to the element at with specified key @a key. + + @note If @a key is not found in the object, then it is silently added to + the object and filled with a `null` value to make `key` a valid reference. + In case the value was `null` before, it is converted to an object. + + @param[in] key key of the element to access + + @return reference to the element at key @a key + + @throw type_error.305 if the JSON value is not an object or null; in that + cases, using the [] operator with a key makes no sense. + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read and + written using the `[]` operator.,operatorarray__key_type} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value + + @since version 1.1.0 + */ + template + reference operator[](T* key) + { + // implicitly convert null to object + if (is_null()) + { + m_type = value_t::object; + m_value = value_t::object; + assert_invariant(); + } + + // at only works for objects + if (JSON_LIKELY(is_object())) + { + return m_value.object->operator[](key); + } + + JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); + } + + /*! + @brief read-only access specified object element + + Returns a const reference to the element at with specified key @a key. No + bounds checking is performed. + + @warning If the element with key @a key does not exist, the behavior is + undefined. + + @param[in] key key of the element to access + + @return const reference to the element at key @a key + + @pre The element with key @a key must exist. **This precondition is + enforced with an assertion.** + + @throw type_error.305 if the JSON value is not an object; in that case, + using the [] operator with a key makes no sense. + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read using + the `[]` operator.,operatorarray__key_type_const} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value + + @since version 1.1.0 + */ + template + const_reference operator[](T* key) const + { + // at only works for objects + if (JSON_LIKELY(is_object())) + { + assert(m_value.object->find(key) != m_value.object->end()); + return m_value.object->find(key)->second; + } + + JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); + } + + /*! + @brief access specified object element with default value + + Returns either a copy of an object's element at the specified key @a key + or a given default value if no element with key @a key exists. + + The function is basically equivalent to executing + @code {.cpp} + try { + return at(key); + } catch(out_of_range) { + return default_value; + } + @endcode + + @note Unlike @ref at(const typename object_t::key_type&), this function + does not throw if the given key @a key was not found. + + @note Unlike @ref operator[](const typename object_t::key_type& key), this + function does not implicitly add an element to the position defined by @a + key. This function is furthermore also applicable to const objects. + + @param[in] key key of the element to access + @param[in] default_value the value to return if @a key is not found + + @tparam ValueType type compatible to JSON values, for instance `int` for + JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for + JSON arrays. Note the type of the expected value at @a key and the default + value @a default_value must be compatible. + + @return copy of the element at key @a key or @a default_value if @a key + is not found + + @throw type_error.306 if the JSON value is not an object; in that case, + using `value()` with a key makes no sense. + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be queried + with a default value.,basic_json__value} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref operator[](const typename object_t::key_type&) for unchecked + access by reference + + @since version 1.0.0 + */ + template::value, int>::type = 0> + ValueType value(const typename object_t::key_type& key, const ValueType& default_value) const + { + // at only works for objects + if (JSON_LIKELY(is_object())) + { + // if key is found, return value and given default value otherwise + const auto it = find(key); + if (it != end()) + { + return *it; + } + + return default_value; + } + + JSON_THROW(type_error::create(306, "cannot use value() with " + std::string(type_name()))); + } + + /*! + @brief overload for a default value of type const char* + @copydoc basic_json::value(const typename object_t::key_type&, ValueType) const + */ + string_t value(const typename object_t::key_type& key, const char* default_value) const + { + return value(key, string_t(default_value)); + } + + /*! + @brief access specified object element via JSON Pointer with default value + + Returns either a copy of an object's element at the specified key @a key + or a given default value if no element with key @a key exists. + + The function is basically equivalent to executing + @code {.cpp} + try { + return at(ptr); + } catch(out_of_range) { + return default_value; + } + @endcode + + @note Unlike @ref at(const json_pointer&), this function does not throw + if the given key @a key was not found. + + @param[in] ptr a JSON pointer to the element to access + @param[in] default_value the value to return if @a ptr found no value + + @tparam ValueType type compatible to JSON values, for instance `int` for + JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for + JSON arrays. Note the type of the expected value at @a key and the default + value @a default_value must be compatible. + + @return copy of the element at key @a key or @a default_value if @a key + is not found + + @throw type_error.306 if the JSON value is not an objec; in that case, + using `value()` with a key makes no sense. + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be queried + with a default value.,basic_json__value_ptr} + + @sa @ref operator[](const json_pointer&) for unchecked access by reference + + @since version 2.0.2 + */ + template::value, int>::type = 0> + ValueType value(const json_pointer& ptr, const ValueType& default_value) const + { + // at only works for objects + if (JSON_LIKELY(is_object())) + { + // if pointer resolves a value, return it or use default value + JSON_TRY + { + return ptr.get_checked(this); + } + JSON_CATCH (out_of_range&) + { + return default_value; + } + } + + JSON_THROW(type_error::create(306, "cannot use value() with " + std::string(type_name()))); + } + + /*! + @brief overload for a default value of type const char* + @copydoc basic_json::value(const json_pointer&, ValueType) const + */ + string_t value(const json_pointer& ptr, const char* default_value) const + { + return value(ptr, string_t(default_value)); + } + + /*! + @brief access the first element + + Returns a reference to the first element in the container. For a JSON + container `c`, the expression `c.front()` is equivalent to `*c.begin()`. + + @return In case of a structured type (array or object), a reference to the + first element is returned. In case of number, string, or boolean values, a + reference to the value is returned. + + @complexity Constant. + + @pre The JSON value must not be `null` (would throw `std::out_of_range`) + or an empty array or object (undefined behavior, **guarded by + assertions**). + @post The JSON value remains unchanged. + + @throw invalid_iterator.214 when called on `null` value + + @liveexample{The following code shows an example for `front()`.,front} + + @sa @ref back() -- access the last element + + @since version 1.0.0 + */ + reference front() + { + return *begin(); + } + + /*! + @copydoc basic_json::front() + */ + const_reference front() const + { + return *cbegin(); + } + + /*! + @brief access the last element + + Returns a reference to the last element in the container. For a JSON + container `c`, the expression `c.back()` is equivalent to + @code {.cpp} + auto tmp = c.end(); + --tmp; + return *tmp; + @endcode + + @return In case of a structured type (array or object), a reference to the + last element is returned. In case of number, string, or boolean values, a + reference to the value is returned. + + @complexity Constant. + + @pre The JSON value must not be `null` (would throw `std::out_of_range`) + or an empty array or object (undefined behavior, **guarded by + assertions**). + @post The JSON value remains unchanged. + + @throw invalid_iterator.214 when called on a `null` value. See example + below. + + @liveexample{The following code shows an example for `back()`.,back} + + @sa @ref front() -- access the first element + + @since version 1.0.0 + */ + reference back() + { + auto tmp = end(); + --tmp; + return *tmp; + } + + /*! + @copydoc basic_json::back() + */ + const_reference back() const + { + auto tmp = cend(); + --tmp; + return *tmp; + } + + /*! + @brief remove element given an iterator + + Removes the element specified by iterator @a pos. The iterator @a pos must + be valid and dereferenceable. Thus the `end()` iterator (which is valid, + but is not dereferenceable) cannot be used as a value for @a pos. + + If called on a primitive type other than `null`, the resulting JSON value + will be `null`. + + @param[in] pos iterator to the element to remove + @return Iterator following the last removed element. If the iterator @a + pos refers to the last element, the `end()` iterator is returned. + + @tparam IteratorType an @ref iterator or @ref const_iterator + + @post Invalidates iterators and references at or after the point of the + erase, including the `end()` iterator. + + @throw type_error.307 if called on a `null` value; example: `"cannot use + erase() with null"` + @throw invalid_iterator.202 if called on an iterator which does not belong + to the current JSON value; example: `"iterator does not fit current + value"` + @throw invalid_iterator.205 if called on a primitive type with invalid + iterator (i.e., any iterator which is not `begin()`); example: `"iterator + out of range"` + + @complexity The complexity depends on the type: + - objects: amortized constant + - arrays: linear in distance between @a pos and the end of the container + - strings: linear in the length of the string + - other types: constant + + @liveexample{The example shows the result of `erase()` for different JSON + types.,erase__IteratorType} + + @sa @ref erase(IteratorType, IteratorType) -- removes the elements in + the given range + @sa @ref erase(const typename object_t::key_type&) -- removes the element + from an object at the given key + @sa @ref erase(const size_type) -- removes the element from an array at + the given index + + @since version 1.0.0 + */ + template::value or + std::is_same::value, int>::type + = 0> + IteratorType erase(IteratorType pos) + { + // make sure iterator fits the current value + if (JSON_UNLIKELY(this != pos.m_object)) + { + JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value")); + } + + IteratorType result = end(); + + switch (m_type) + { + case value_t::boolean: + case value_t::number_float: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::string: + { + if (JSON_UNLIKELY(not pos.m_it.primitive_iterator.is_begin())) + { + JSON_THROW(invalid_iterator::create(205, "iterator out of range")); + } + + if (is_string()) + { + AllocatorType alloc; + std::allocator_traits::destroy(alloc, m_value.string); + std::allocator_traits::deallocate(alloc, m_value.string, 1); + m_value.string = nullptr; + } + + m_type = value_t::null; + assert_invariant(); + break; + } + + case value_t::object: + { + result.m_it.object_iterator = m_value.object->erase(pos.m_it.object_iterator); + break; + } + + case value_t::array: + { + result.m_it.array_iterator = m_value.array->erase(pos.m_it.array_iterator); + break; + } + + default: + JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name()))); + } + + return result; + } + + /*! + @brief remove elements given an iterator range + + Removes the element specified by the range `[first; last)`. The iterator + @a first does not need to be dereferenceable if `first == last`: erasing + an empty range is a no-op. + + If called on a primitive type other than `null`, the resulting JSON value + will be `null`. + + @param[in] first iterator to the beginning of the range to remove + @param[in] last iterator past the end of the range to remove + @return Iterator following the last removed element. If the iterator @a + second refers to the last element, the `end()` iterator is returned. + + @tparam IteratorType an @ref iterator or @ref const_iterator + + @post Invalidates iterators and references at or after the point of the + erase, including the `end()` iterator. + + @throw type_error.307 if called on a `null` value; example: `"cannot use + erase() with null"` + @throw invalid_iterator.203 if called on iterators which does not belong + to the current JSON value; example: `"iterators do not fit current value"` + @throw invalid_iterator.204 if called on a primitive type with invalid + iterators (i.e., if `first != begin()` and `last != end()`); example: + `"iterators out of range"` + + @complexity The complexity depends on the type: + - objects: `log(size()) + std::distance(first, last)` + - arrays: linear in the distance between @a first and @a last, plus linear + in the distance between @a last and end of the container + - strings: linear in the length of the string + - other types: constant + + @liveexample{The example shows the result of `erase()` for different JSON + types.,erase__IteratorType_IteratorType} + + @sa @ref erase(IteratorType) -- removes the element at a given position + @sa @ref erase(const typename object_t::key_type&) -- removes the element + from an object at the given key + @sa @ref erase(const size_type) -- removes the element from an array at + the given index + + @since version 1.0.0 + */ + template::value or + std::is_same::value, int>::type + = 0> + IteratorType erase(IteratorType first, IteratorType last) + { + // make sure iterator fits the current value + if (JSON_UNLIKELY(this != first.m_object or this != last.m_object)) + { + JSON_THROW(invalid_iterator::create(203, "iterators do not fit current value")); + } + + IteratorType result = end(); + + switch (m_type) + { + case value_t::boolean: + case value_t::number_float: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::string: + { + if (JSON_LIKELY(not first.m_it.primitive_iterator.is_begin() + or not last.m_it.primitive_iterator.is_end())) + { + JSON_THROW(invalid_iterator::create(204, "iterators out of range")); + } + + if (is_string()) + { + AllocatorType alloc; + std::allocator_traits::destroy(alloc, m_value.string); + std::allocator_traits::deallocate(alloc, m_value.string, 1); + m_value.string = nullptr; + } + + m_type = value_t::null; + assert_invariant(); + break; + } + + case value_t::object: + { + result.m_it.object_iterator = m_value.object->erase(first.m_it.object_iterator, + last.m_it.object_iterator); + break; + } + + case value_t::array: + { + result.m_it.array_iterator = m_value.array->erase(first.m_it.array_iterator, + last.m_it.array_iterator); + break; + } + + default: + JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name()))); + } + + return result; + } + + /*! + @brief remove element from a JSON object given a key + + Removes elements from a JSON object with the key value @a key. + + @param[in] key value of the elements to remove + + @return Number of elements removed. If @a ObjectType is the default + `std::map` type, the return value will always be `0` (@a key was not + found) or `1` (@a key was found). + + @post References and iterators to the erased elements are invalidated. + Other references and iterators are not affected. + + @throw type_error.307 when called on a type other than JSON object; + example: `"cannot use erase() with null"` + + @complexity `log(size()) + count(key)` + + @liveexample{The example shows the effect of `erase()`.,erase__key_type} + + @sa @ref erase(IteratorType) -- removes the element at a given position + @sa @ref erase(IteratorType, IteratorType) -- removes the elements in + the given range + @sa @ref erase(const size_type) -- removes the element from an array at + the given index + + @since version 1.0.0 + */ + size_type erase(const typename object_t::key_type& key) + { + // this erase only works for objects + if (JSON_LIKELY(is_object())) + { + return m_value.object->erase(key); + } + + JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name()))); + } + + /*! + @brief remove element from a JSON array given an index + + Removes element from a JSON array at the index @a idx. + + @param[in] idx index of the element to remove + + @throw type_error.307 when called on a type other than JSON object; + example: `"cannot use erase() with null"` + @throw out_of_range.401 when `idx >= size()`; example: `"array index 17 + is out of range"` + + @complexity Linear in distance between @a idx and the end of the container. + + @liveexample{The example shows the effect of `erase()`.,erase__size_type} + + @sa @ref erase(IteratorType) -- removes the element at a given position + @sa @ref erase(IteratorType, IteratorType) -- removes the elements in + the given range + @sa @ref erase(const typename object_t::key_type&) -- removes the element + from an object at the given key + + @since version 1.0.0 + */ + void erase(const size_type idx) + { + // this erase only works for arrays + if (JSON_LIKELY(is_array())) + { + if (JSON_UNLIKELY(idx >= size())) + { + JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range")); + } + + m_value.array->erase(m_value.array->begin() + static_cast(idx)); + } + else + { + JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name()))); + } + } + + /// @} + + + //////////// + // lookup // + //////////// + + /// @name lookup + /// @{ + + /*! + @brief find an element in a JSON object + + Finds an element in a JSON object with key equivalent to @a key. If the + element is not found or the JSON value is not an object, end() is + returned. + + @note This method always returns @ref end() when executed on a JSON type + that is not an object. + + @param[in] key key value of the element to search for. + + @return Iterator to an element with key equivalent to @a key. If no such + element is found or the JSON value is not an object, past-the-end (see + @ref end()) iterator is returned. + + @complexity Logarithmic in the size of the JSON object. + + @liveexample{The example shows how `find()` is used.,find__key_type} + + @since version 1.0.0 + */ + template + iterator find(KeyT&& key) + { + auto result = end(); + + if (is_object()) + { + result.m_it.object_iterator = m_value.object->find(std::forward(key)); + } + + return result; + } + + /*! + @brief find an element in a JSON object + @copydoc find(KeyT&&) + */ + template + const_iterator find(KeyT&& key) const + { + auto result = cend(); + + if (is_object()) + { + result.m_it.object_iterator = m_value.object->find(std::forward(key)); + } + + return result; + } + + /*! + @brief returns the number of occurrences of a key in a JSON object + + Returns the number of elements with key @a key. If ObjectType is the + default `std::map` type, the return value will always be `0` (@a key was + not found) or `1` (@a key was found). + + @note This method always returns `0` when executed on a JSON type that is + not an object. + + @param[in] key key value of the element to count + + @return Number of elements with key @a key. If the JSON value is not an + object, the return value will be `0`. + + @complexity Logarithmic in the size of the JSON object. + + @liveexample{The example shows how `count()` is used.,count} + + @since version 1.0.0 + */ + template + size_type count(KeyT&& key) const + { + // return 0 for all nonobject types + return is_object() ? m_value.object->count(std::forward(key)) : 0; + } + + /// @} + + + /////////////// + // iterators // + /////////////// + + /// @name iterators + /// @{ + + /*! + @brief returns an iterator to the first element + + Returns an iterator to the first element. + + @image html range-begin-end.svg "Illustration from cppreference.com" + + @return iterator to the first element + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + + @liveexample{The following code shows an example for `begin()`.,begin} + + @sa @ref cbegin() -- returns a const iterator to the beginning + @sa @ref end() -- returns an iterator to the end + @sa @ref cend() -- returns a const iterator to the end + + @since version 1.0.0 + */ + iterator begin() noexcept + { + iterator result(this); + result.set_begin(); + return result; + } + + /*! + @copydoc basic_json::cbegin() + */ + const_iterator begin() const noexcept + { + return cbegin(); + } + + /*! + @brief returns a const iterator to the first element + + Returns a const iterator to the first element. + + @image html range-begin-end.svg "Illustration from cppreference.com" + + @return const iterator to the first element + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + - Has the semantics of `const_cast(*this).begin()`. + + @liveexample{The following code shows an example for `cbegin()`.,cbegin} + + @sa @ref begin() -- returns an iterator to the beginning + @sa @ref end() -- returns an iterator to the end + @sa @ref cend() -- returns a const iterator to the end + + @since version 1.0.0 + */ + const_iterator cbegin() const noexcept + { + const_iterator result(this); + result.set_begin(); + return result; + } + + /*! + @brief returns an iterator to one past the last element + + Returns an iterator to one past the last element. + + @image html range-begin-end.svg "Illustration from cppreference.com" + + @return iterator one past the last element + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + + @liveexample{The following code shows an example for `end()`.,end} + + @sa @ref cend() -- returns a const iterator to the end + @sa @ref begin() -- returns an iterator to the beginning + @sa @ref cbegin() -- returns a const iterator to the beginning + + @since version 1.0.0 + */ + iterator end() noexcept + { + iterator result(this); + result.set_end(); + return result; + } + + /*! + @copydoc basic_json::cend() + */ + const_iterator end() const noexcept + { + return cend(); + } + + /*! + @brief returns a const iterator to one past the last element + + Returns a const iterator to one past the last element. + + @image html range-begin-end.svg "Illustration from cppreference.com" + + @return const iterator one past the last element + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + - Has the semantics of `const_cast(*this).end()`. + + @liveexample{The following code shows an example for `cend()`.,cend} + + @sa @ref end() -- returns an iterator to the end + @sa @ref begin() -- returns an iterator to the beginning + @sa @ref cbegin() -- returns a const iterator to the beginning + + @since version 1.0.0 + */ + const_iterator cend() const noexcept + { + const_iterator result(this); + result.set_end(); + return result; + } + + /*! + @brief returns an iterator to the reverse-beginning + + Returns an iterator to the reverse-beginning; that is, the last element. + + @image html range-rbegin-rend.svg "Illustration from cppreference.com" + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) + requirements: + - The complexity is constant. + - Has the semantics of `reverse_iterator(end())`. + + @liveexample{The following code shows an example for `rbegin()`.,rbegin} + + @sa @ref crbegin() -- returns a const reverse iterator to the beginning + @sa @ref rend() -- returns a reverse iterator to the end + @sa @ref crend() -- returns a const reverse iterator to the end + + @since version 1.0.0 + */ + reverse_iterator rbegin() noexcept + { + return reverse_iterator(end()); + } + + /*! + @copydoc basic_json::crbegin() + */ + const_reverse_iterator rbegin() const noexcept + { + return crbegin(); + } + + /*! + @brief returns an iterator to the reverse-end + + Returns an iterator to the reverse-end; that is, one before the first + element. + + @image html range-rbegin-rend.svg "Illustration from cppreference.com" + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) + requirements: + - The complexity is constant. + - Has the semantics of `reverse_iterator(begin())`. + + @liveexample{The following code shows an example for `rend()`.,rend} + + @sa @ref crend() -- returns a const reverse iterator to the end + @sa @ref rbegin() -- returns a reverse iterator to the beginning + @sa @ref crbegin() -- returns a const reverse iterator to the beginning + + @since version 1.0.0 + */ + reverse_iterator rend() noexcept + { + return reverse_iterator(begin()); + } + + /*! + @copydoc basic_json::crend() + */ + const_reverse_iterator rend() const noexcept + { + return crend(); + } + + /*! + @brief returns a const reverse iterator to the last element + + Returns a const iterator to the reverse-beginning; that is, the last + element. + + @image html range-rbegin-rend.svg "Illustration from cppreference.com" + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) + requirements: + - The complexity is constant. + - Has the semantics of `const_cast(*this).rbegin()`. + + @liveexample{The following code shows an example for `crbegin()`.,crbegin} + + @sa @ref rbegin() -- returns a reverse iterator to the beginning + @sa @ref rend() -- returns a reverse iterator to the end + @sa @ref crend() -- returns a const reverse iterator to the end + + @since version 1.0.0 + */ + const_reverse_iterator crbegin() const noexcept + { + return const_reverse_iterator(cend()); + } + + /*! + @brief returns a const reverse iterator to one before the first + + Returns a const reverse iterator to the reverse-end; that is, one before + the first element. + + @image html range-rbegin-rend.svg "Illustration from cppreference.com" + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) + requirements: + - The complexity is constant. + - Has the semantics of `const_cast(*this).rend()`. + + @liveexample{The following code shows an example for `crend()`.,crend} + + @sa @ref rend() -- returns a reverse iterator to the end + @sa @ref rbegin() -- returns a reverse iterator to the beginning + @sa @ref crbegin() -- returns a const reverse iterator to the beginning + + @since version 1.0.0 + */ + const_reverse_iterator crend() const noexcept + { + return const_reverse_iterator(cbegin()); + } + + public: + /*! + @brief wrapper to access iterator member functions in range-based for + + This function allows to access @ref iterator::key() and @ref + iterator::value() during range-based for loops. In these loops, a + reference to the JSON values is returned, so there is no access to the + underlying iterator. + + For loop without iterator_wrapper: + + @code{cpp} + for (auto it = j_object.begin(); it != j_object.end(); ++it) + { + std::cout << "key: " << it.key() << ", value:" << it.value() << '\n'; + } + @endcode + + Range-based for loop without iterator proxy: + + @code{cpp} + for (auto it : j_object) + { + // "it" is of type json::reference and has no key() member + std::cout << "value: " << it << '\n'; + } + @endcode + + Range-based for loop with iterator proxy: + + @code{cpp} + for (auto it : json::iterator_wrapper(j_object)) + { + std::cout << "key: " << it.key() << ", value:" << it.value() << '\n'; + } + @endcode + + @note When iterating over an array, `key()` will return the index of the + element as string (see example). + + @param[in] ref reference to a JSON value + @return iteration proxy object wrapping @a ref with an interface to use in + range-based for loops + + @liveexample{The following code shows how the wrapper is used,iterator_wrapper} + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Constant. + + @note The name of this function is not yet final and may change in the + future. + */ + static iteration_proxy iterator_wrapper(reference ref) + { + return iteration_proxy(ref); + } + + /*! + @copydoc iterator_wrapper(reference) + */ + static iteration_proxy iterator_wrapper(const_reference ref) + { + return iteration_proxy(ref); + } + + /*! + @brief helper to access iterator member functions in range-based for + + This function allows to access @ref iterator::key() and @ref + iterator::value() during range-based for loops. In these loops, a + reference to the JSON values is returned, so there is no access to the + underlying iterator. + + For loop without `items()` function: + + @code{cpp} + for (auto it = j_object.begin(); it != j_object.end(); ++it) + { + std::cout << "key: " << it.key() << ", value:" << it.value() << '\n'; + } + @endcode + + Range-based for loop without `items()` function: + + @code{cpp} + for (auto it : j_object) + { + // "it" is of type json::reference and has no key() member + std::cout << "value: " << it << '\n'; + } + @endcode + + Range-based for loop with `items()` function: + + @code{cpp} + for (auto it : j_object.items()) + { + std::cout << "key: " << it.key() << ", value:" << it.value() << '\n'; + } + @endcode + + @note When iterating over an array, `key()` will return the index of the + element as string (see example). + + @return iteration proxy object wrapping @a ref with an interface to use in + range-based for loops + + @liveexample{The following code shows how the function is used.,items} + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Constant. + */ + iteration_proxy items() + { + return iteration_proxy(*this); + } + + /*! + @copydoc items() + */ + iteration_proxy items() const + { + return iteration_proxy(*this); + } + + /// @} + + + ////////////// + // capacity // + ////////////// + + /// @name capacity + /// @{ + + /*! + @brief checks whether the container is empty. + + Checks if a JSON value has no elements (i.e. whether its @ref size is `0`). + + @return The return value depends on the different types and is + defined as follows: + Value type | return value + ----------- | ------------- + null | `true` + boolean | `false` + string | `false` + number | `false` + object | result of function `object_t::empty()` + array | result of function `array_t::empty()` + + @liveexample{The following code uses `empty()` to check if a JSON + object contains any elements.,empty} + + @complexity Constant, as long as @ref array_t and @ref object_t satisfy + the Container concept; that is, their `empty()` functions have constant + complexity. + + @iterators No changes. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @note This function does not return whether a string stored as JSON value + is empty - it returns whether the JSON container itself is empty which is + false in the case of a string. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + - Has the semantics of `begin() == end()`. + + @sa @ref size() -- returns the number of elements + + @since version 1.0.0 + */ + bool empty() const noexcept + { + switch (m_type) + { + case value_t::null: + { + // null values are empty + return true; + } + + case value_t::array: + { + // delegate call to array_t::empty() + return m_value.array->empty(); + } + + case value_t::object: + { + // delegate call to object_t::empty() + return m_value.object->empty(); + } + + default: + { + // all other types are nonempty + return false; + } + } + } + + /*! + @brief returns the number of elements + + Returns the number of elements in a JSON value. + + @return The return value depends on the different types and is + defined as follows: + Value type | return value + ----------- | ------------- + null | `0` + boolean | `1` + string | `1` + number | `1` + object | result of function object_t::size() + array | result of function array_t::size() + + @liveexample{The following code calls `size()` on the different value + types.,size} + + @complexity Constant, as long as @ref array_t and @ref object_t satisfy + the Container concept; that is, their size() functions have constant + complexity. + + @iterators No changes. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @note This function does not return the length of a string stored as JSON + value - it returns the number of elements in the JSON value which is 1 in + the case of a string. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + - Has the semantics of `std::distance(begin(), end())`. + + @sa @ref empty() -- checks whether the container is empty + @sa @ref max_size() -- returns the maximal number of elements + + @since version 1.0.0 + */ + size_type size() const noexcept + { + switch (m_type) + { + case value_t::null: + { + // null values are empty + return 0; + } + + case value_t::array: + { + // delegate call to array_t::size() + return m_value.array->size(); + } + + case value_t::object: + { + // delegate call to object_t::size() + return m_value.object->size(); + } + + default: + { + // all other types have size 1 + return 1; + } + } + } + + /*! + @brief returns the maximum possible number of elements + + Returns the maximum number of elements a JSON value is able to hold due to + system or library implementation limitations, i.e. `std::distance(begin(), + end())` for the JSON value. + + @return The return value depends on the different types and is + defined as follows: + Value type | return value + ----------- | ------------- + null | `0` (same as `size()`) + boolean | `1` (same as `size()`) + string | `1` (same as `size()`) + number | `1` (same as `size()`) + object | result of function `object_t::max_size()` + array | result of function `array_t::max_size()` + + @liveexample{The following code calls `max_size()` on the different value + types. Note the output is implementation specific.,max_size} + + @complexity Constant, as long as @ref array_t and @ref object_t satisfy + the Container concept; that is, their `max_size()` functions have constant + complexity. + + @iterators No changes. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + - Has the semantics of returning `b.size()` where `b` is the largest + possible JSON value. + + @sa @ref size() -- returns the number of elements + + @since version 1.0.0 + */ + size_type max_size() const noexcept + { + switch (m_type) + { + case value_t::array: + { + // delegate call to array_t::max_size() + return m_value.array->max_size(); + } + + case value_t::object: + { + // delegate call to object_t::max_size() + return m_value.object->max_size(); + } + + default: + { + // all other types have max_size() == size() + return size(); + } + } + } + + /// @} + + + /////////////// + // modifiers // + /////////////// + + /// @name modifiers + /// @{ + + /*! + @brief clears the contents + + Clears the content of a JSON value and resets it to the default value as + if @ref basic_json(value_t) would have been called with the current value + type from @ref type(): + + Value type | initial value + ----------- | ------------- + null | `null` + boolean | `false` + string | `""` + number | `0` + object | `{}` + array | `[]` + + @post Has the same effect as calling + @code {.cpp} + *this = basic_json(type()); + @endcode + + @liveexample{The example below shows the effect of `clear()` to different + JSON types.,clear} + + @complexity Linear in the size of the JSON value. + + @iterators All iterators, pointers and references related to this container + are invalidated. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @sa @ref basic_json(value_t) -- constructor that creates an object with the + same value than calling `clear()` + + @since version 1.0.0 + */ + void clear() noexcept + { + switch (m_type) + { + case value_t::number_integer: + { + m_value.number_integer = 0; + break; + } + + case value_t::number_unsigned: + { + m_value.number_unsigned = 0; + break; + } + + case value_t::number_float: + { + m_value.number_float = 0.0; + break; + } + + case value_t::boolean: + { + m_value.boolean = false; + break; + } + + case value_t::string: + { + m_value.string->clear(); + break; + } + + case value_t::array: + { + m_value.array->clear(); + break; + } + + case value_t::object: + { + m_value.object->clear(); + break; + } + + default: + break; + } + } + + /*! + @brief add an object to an array + + Appends the given element @a val to the end of the JSON value. If the + function is called on a JSON null value, an empty array is created before + appending @a val. + + @param[in] val the value to add to the JSON array + + @throw type_error.308 when called on a type other than JSON array or + null; example: `"cannot use push_back() with number"` + + @complexity Amortized constant. + + @liveexample{The example shows how `push_back()` and `+=` can be used to + add elements to a JSON array. Note how the `null` value was silently + converted to a JSON array.,push_back} + + @since version 1.0.0 + */ + void push_back(basic_json&& val) + { + // push_back only works for null objects or arrays + if (JSON_UNLIKELY(not(is_null() or is_array()))) + { + JSON_THROW(type_error::create(308, "cannot use push_back() with " + std::string(type_name()))); + } + + // transform null object into an array + if (is_null()) + { + m_type = value_t::array; + m_value = value_t::array; + assert_invariant(); + } + + // add element to array (move semantics) + m_value.array->push_back(std::move(val)); + // invalidate object + val.m_type = value_t::null; + } + + /*! + @brief add an object to an array + @copydoc push_back(basic_json&&) + */ + reference operator+=(basic_json&& val) + { + push_back(std::move(val)); + return *this; + } + + /*! + @brief add an object to an array + @copydoc push_back(basic_json&&) + */ + void push_back(const basic_json& val) + { + // push_back only works for null objects or arrays + if (JSON_UNLIKELY(not(is_null() or is_array()))) + { + JSON_THROW(type_error::create(308, "cannot use push_back() with " + std::string(type_name()))); + } + + // transform null object into an array + if (is_null()) + { + m_type = value_t::array; + m_value = value_t::array; + assert_invariant(); + } + + // add element to array + m_value.array->push_back(val); + } + + /*! + @brief add an object to an array + @copydoc push_back(basic_json&&) + */ + reference operator+=(const basic_json& val) + { + push_back(val); + return *this; + } + + /*! + @brief add an object to an object + + Inserts the given element @a val to the JSON object. If the function is + called on a JSON null value, an empty object is created before inserting + @a val. + + @param[in] val the value to add to the JSON object + + @throw type_error.308 when called on a type other than JSON object or + null; example: `"cannot use push_back() with number"` + + @complexity Logarithmic in the size of the container, O(log(`size()`)). + + @liveexample{The example shows how `push_back()` and `+=` can be used to + add elements to a JSON object. Note how the `null` value was silently + converted to a JSON object.,push_back__object_t__value} + + @since version 1.0.0 + */ + void push_back(const typename object_t::value_type& val) + { + // push_back only works for null objects or objects + if (JSON_UNLIKELY(not(is_null() or is_object()))) + { + JSON_THROW(type_error::create(308, "cannot use push_back() with " + std::string(type_name()))); + } + + // transform null object into an object + if (is_null()) + { + m_type = value_t::object; + m_value = value_t::object; + assert_invariant(); + } + + // add element to array + m_value.object->insert(val); + } + + /*! + @brief add an object to an object + @copydoc push_back(const typename object_t::value_type&) + */ + reference operator+=(const typename object_t::value_type& val) + { + push_back(val); + return *this; + } + + /*! + @brief add an object to an object + + This function allows to use `push_back` with an initializer list. In case + + 1. the current value is an object, + 2. the initializer list @a init contains only two elements, and + 3. the first element of @a init is a string, + + @a init is converted into an object element and added using + @ref push_back(const typename object_t::value_type&). Otherwise, @a init + is converted to a JSON value and added using @ref push_back(basic_json&&). + + @param[in] init an initializer list + + @complexity Linear in the size of the initializer list @a init. + + @note This function is required to resolve an ambiguous overload error, + because pairs like `{"key", "value"}` can be both interpreted as + `object_t::value_type` or `std::initializer_list`, see + https://github.com/nlohmann/json/issues/235 for more information. + + @liveexample{The example shows how initializer lists are treated as + objects when possible.,push_back__initializer_list} + */ + void push_back(initializer_list_t init) + { + if (is_object() and init.size() == 2 and (*init.begin())->is_string()) + { + basic_json&& key = init.begin()->moved_or_copied(); + push_back(typename object_t::value_type( + std::move(key.get_ref()), (init.begin() + 1)->moved_or_copied())); + } + else + { + push_back(basic_json(init)); + } + } + + /*! + @brief add an object to an object + @copydoc push_back(initializer_list_t) + */ + reference operator+=(initializer_list_t init) + { + push_back(init); + return *this; + } + + /*! + @brief add an object to an array + + Creates a JSON value from the passed parameters @a args to the end of the + JSON value. If the function is called on a JSON null value, an empty array + is created before appending the value created from @a args. + + @param[in] args arguments to forward to a constructor of @ref basic_json + @tparam Args compatible types to create a @ref basic_json object + + @throw type_error.311 when called on a type other than JSON array or + null; example: `"cannot use emplace_back() with number"` + + @complexity Amortized constant. + + @liveexample{The example shows how `push_back()` can be used to add + elements to a JSON array. Note how the `null` value was silently converted + to a JSON array.,emplace_back} + + @since version 2.0.8 + */ + template + void emplace_back(Args&& ... args) + { + // emplace_back only works for null objects or arrays + if (JSON_UNLIKELY(not(is_null() or is_array()))) + { + JSON_THROW(type_error::create(311, "cannot use emplace_back() with " + std::string(type_name()))); + } + + // transform null object into an array + if (is_null()) + { + m_type = value_t::array; + m_value = value_t::array; + assert_invariant(); + } + + // add element to array (perfect forwarding) + m_value.array->emplace_back(std::forward(args)...); + } + + /*! + @brief add an object to an object if key does not exist + + Inserts a new element into a JSON object constructed in-place with the + given @a args if there is no element with the key in the container. If the + function is called on a JSON null value, an empty object is created before + appending the value created from @a args. + + @param[in] args arguments to forward to a constructor of @ref basic_json + @tparam Args compatible types to create a @ref basic_json object + + @return a pair consisting of an iterator to the inserted element, or the + already-existing element if no insertion happened, and a bool + denoting whether the insertion took place. + + @throw type_error.311 when called on a type other than JSON object or + null; example: `"cannot use emplace() with number"` + + @complexity Logarithmic in the size of the container, O(log(`size()`)). + + @liveexample{The example shows how `emplace()` can be used to add elements + to a JSON object. Note how the `null` value was silently converted to a + JSON object. Further note how no value is added if there was already one + value stored with the same key.,emplace} + + @since version 2.0.8 + */ + template + std::pair emplace(Args&& ... args) + { + // emplace only works for null objects or arrays + if (JSON_UNLIKELY(not(is_null() or is_object()))) + { + JSON_THROW(type_error::create(311, "cannot use emplace() with " + std::string(type_name()))); + } + + // transform null object into an object + if (is_null()) + { + m_type = value_t::object; + m_value = value_t::object; + assert_invariant(); + } + + // add element to array (perfect forwarding) + auto res = m_value.object->emplace(std::forward(args)...); + // create result iterator and set iterator to the result of emplace + auto it = begin(); + it.m_it.object_iterator = res.first; + + // return pair of iterator and boolean + return {it, res.second}; + } + + /*! + @brief inserts element + + Inserts element @a val before iterator @a pos. + + @param[in] pos iterator before which the content will be inserted; may be + the end() iterator + @param[in] val element to insert + @return iterator pointing to the inserted @a val. + + @throw type_error.309 if called on JSON values other than arrays; + example: `"cannot use insert() with string"` + @throw invalid_iterator.202 if @a pos is not an iterator of *this; + example: `"iterator does not fit current value"` + + @complexity Constant plus linear in the distance between @a pos and end of + the container. + + @liveexample{The example shows how `insert()` is used.,insert} + + @since version 1.0.0 + */ + iterator insert(const_iterator pos, const basic_json& val) + { + // insert only works for arrays + if (JSON_LIKELY(is_array())) + { + // check if iterator pos fits to this JSON value + if (JSON_UNLIKELY(pos.m_object != this)) + { + JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value")); + } + + // insert to array and return iterator + iterator result(this); + result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, val); + return result; + } + + JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); + } + + /*! + @brief inserts element + @copydoc insert(const_iterator, const basic_json&) + */ + iterator insert(const_iterator pos, basic_json&& val) + { + return insert(pos, val); + } + + /*! + @brief inserts elements + + Inserts @a cnt copies of @a val before iterator @a pos. + + @param[in] pos iterator before which the content will be inserted; may be + the end() iterator + @param[in] cnt number of copies of @a val to insert + @param[in] val element to insert + @return iterator pointing to the first element inserted, or @a pos if + `cnt==0` + + @throw type_error.309 if called on JSON values other than arrays; example: + `"cannot use insert() with string"` + @throw invalid_iterator.202 if @a pos is not an iterator of *this; + example: `"iterator does not fit current value"` + + @complexity Linear in @a cnt plus linear in the distance between @a pos + and end of the container. + + @liveexample{The example shows how `insert()` is used.,insert__count} + + @since version 1.0.0 + */ + iterator insert(const_iterator pos, size_type cnt, const basic_json& val) + { + // insert only works for arrays + if (JSON_LIKELY(is_array())) + { + // check if iterator pos fits to this JSON value + if (JSON_UNLIKELY(pos.m_object != this)) + { + JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value")); + } + + // insert to array and return iterator + iterator result(this); + result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val); + return result; + } + + JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); + } + + /*! + @brief inserts elements + + Inserts elements from range `[first, last)` before iterator @a pos. + + @param[in] pos iterator before which the content will be inserted; may be + the end() iterator + @param[in] first begin of the range of elements to insert + @param[in] last end of the range of elements to insert + + @throw type_error.309 if called on JSON values other than arrays; example: + `"cannot use insert() with string"` + @throw invalid_iterator.202 if @a pos is not an iterator of *this; + example: `"iterator does not fit current value"` + @throw invalid_iterator.210 if @a first and @a last do not belong to the + same JSON value; example: `"iterators do not fit"` + @throw invalid_iterator.211 if @a first or @a last are iterators into + container for which insert is called; example: `"passed iterators may not + belong to container"` + + @return iterator pointing to the first element inserted, or @a pos if + `first==last` + + @complexity Linear in `std::distance(first, last)` plus linear in the + distance between @a pos and end of the container. + + @liveexample{The example shows how `insert()` is used.,insert__range} + + @since version 1.0.0 + */ + iterator insert(const_iterator pos, const_iterator first, const_iterator last) + { + // insert only works for arrays + if (JSON_UNLIKELY(not is_array())) + { + JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); + } + + // check if iterator pos fits to this JSON value + if (JSON_UNLIKELY(pos.m_object != this)) + { + JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value")); + } + + // check if range iterators belong to the same JSON object + if (JSON_UNLIKELY(first.m_object != last.m_object)) + { + JSON_THROW(invalid_iterator::create(210, "iterators do not fit")); + } + + if (JSON_UNLIKELY(first.m_object == this)) + { + JSON_THROW(invalid_iterator::create(211, "passed iterators may not belong to container")); + } + + // insert to array and return iterator + iterator result(this); + result.m_it.array_iterator = m_value.array->insert( + pos.m_it.array_iterator, + first.m_it.array_iterator, + last.m_it.array_iterator); + return result; + } + + /*! + @brief inserts elements + + Inserts elements from initializer list @a ilist before iterator @a pos. + + @param[in] pos iterator before which the content will be inserted; may be + the end() iterator + @param[in] ilist initializer list to insert the values from + + @throw type_error.309 if called on JSON values other than arrays; example: + `"cannot use insert() with string"` + @throw invalid_iterator.202 if @a pos is not an iterator of *this; + example: `"iterator does not fit current value"` + + @return iterator pointing to the first element inserted, or @a pos if + `ilist` is empty + + @complexity Linear in `ilist.size()` plus linear in the distance between + @a pos and end of the container. + + @liveexample{The example shows how `insert()` is used.,insert__ilist} + + @since version 1.0.0 + */ + iterator insert(const_iterator pos, initializer_list_t ilist) + { + // insert only works for arrays + if (JSON_UNLIKELY(not is_array())) + { + JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); + } + + // check if iterator pos fits to this JSON value + if (JSON_UNLIKELY(pos.m_object != this)) + { + JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value")); + } + + // insert to array and return iterator + iterator result(this); + result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, ilist.begin(), ilist.end()); + return result; + } + + /*! + @brief inserts elements + + Inserts elements from range `[first, last)`. + + @param[in] first begin of the range of elements to insert + @param[in] last end of the range of elements to insert + + @throw type_error.309 if called on JSON values other than objects; example: + `"cannot use insert() with string"` + @throw invalid_iterator.202 if iterator @a first or @a last does does not + point to an object; example: `"iterators first and last must point to + objects"` + @throw invalid_iterator.210 if @a first and @a last do not belong to the + same JSON value; example: `"iterators do not fit"` + + @complexity Logarithmic: `O(N*log(size() + N))`, where `N` is the number + of elements to insert. + + @liveexample{The example shows how `insert()` is used.,insert__range_object} + + @since version 3.0.0 + */ + void insert(const_iterator first, const_iterator last) + { + // insert only works for objects + if (JSON_UNLIKELY(not is_object())) + { + JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); + } + + // check if range iterators belong to the same JSON object + if (JSON_UNLIKELY(first.m_object != last.m_object)) + { + JSON_THROW(invalid_iterator::create(210, "iterators do not fit")); + } + + // passed iterators must belong to objects + if (JSON_UNLIKELY(not first.m_object->is_object())) + { + JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects")); + } + + m_value.object->insert(first.m_it.object_iterator, last.m_it.object_iterator); + } + + /*! + @brief updates a JSON object from another object, overwriting existing keys + + Inserts all values from JSON object @a j and overwrites existing keys. + + @param[in] j JSON object to read values from + + @throw type_error.312 if called on JSON values other than objects; example: + `"cannot use update() with string"` + + @complexity O(N*log(size() + N)), where N is the number of elements to + insert. + + @liveexample{The example shows how `update()` is used.,update} + + @sa https://docs.python.org/3.6/library/stdtypes.html#dict.update + + @since version 3.0.0 + */ + void update(const_reference j) + { + // implicitly convert null value to an empty object + if (is_null()) + { + m_type = value_t::object; + m_value.object = create(); + assert_invariant(); + } + + if (JSON_UNLIKELY(not is_object())) + { + JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(type_name()))); + } + if (JSON_UNLIKELY(not j.is_object())) + { + JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(j.type_name()))); + } + + for (auto it = j.cbegin(); it != j.cend(); ++it) + { + m_value.object->operator[](it.key()) = it.value(); + } + } + + /*! + @brief updates a JSON object from another object, overwriting existing keys + + Inserts all values from from range `[first, last)` and overwrites existing + keys. + + @param[in] first begin of the range of elements to insert + @param[in] last end of the range of elements to insert + + @throw type_error.312 if called on JSON values other than objects; example: + `"cannot use update() with string"` + @throw invalid_iterator.202 if iterator @a first or @a last does does not + point to an object; example: `"iterators first and last must point to + objects"` + @throw invalid_iterator.210 if @a first and @a last do not belong to the + same JSON value; example: `"iterators do not fit"` + + @complexity O(N*log(size() + N)), where N is the number of elements to + insert. + + @liveexample{The example shows how `update()` is used__range.,update} + + @sa https://docs.python.org/3.6/library/stdtypes.html#dict.update + + @since version 3.0.0 + */ + void update(const_iterator first, const_iterator last) + { + // implicitly convert null value to an empty object + if (is_null()) + { + m_type = value_t::object; + m_value.object = create(); + assert_invariant(); + } + + if (JSON_UNLIKELY(not is_object())) + { + JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(type_name()))); + } + + // check if range iterators belong to the same JSON object + if (JSON_UNLIKELY(first.m_object != last.m_object)) + { + JSON_THROW(invalid_iterator::create(210, "iterators do not fit")); + } + + // passed iterators must belong to objects + if (JSON_UNLIKELY(not first.m_object->is_object() + or not first.m_object->is_object())) + { + JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects")); + } + + for (auto it = first; it != last; ++it) + { + m_value.object->operator[](it.key()) = it.value(); + } + } + + /*! + @brief exchanges the values + + Exchanges the contents of the JSON value with those of @a other. Does not + invoke any move, copy, or swap operations on individual elements. All + iterators and references remain valid. The past-the-end iterator is + invalidated. + + @param[in,out] other JSON value to exchange the contents with + + @complexity Constant. + + @liveexample{The example below shows how JSON values can be swapped with + `swap()`.,swap__reference} + + @since version 1.0.0 + */ + void swap(reference other) noexcept ( + std::is_nothrow_move_constructible::value and + std::is_nothrow_move_assignable::value and + std::is_nothrow_move_constructible::value and + std::is_nothrow_move_assignable::value + ) + { + std::swap(m_type, other.m_type); + std::swap(m_value, other.m_value); + assert_invariant(); + } + + /*! + @brief exchanges the values + + Exchanges the contents of a JSON array with those of @a other. Does not + invoke any move, copy, or swap operations on individual elements. All + iterators and references remain valid. The past-the-end iterator is + invalidated. + + @param[in,out] other array to exchange the contents with + + @throw type_error.310 when JSON value is not an array; example: `"cannot + use swap() with string"` + + @complexity Constant. + + @liveexample{The example below shows how arrays can be swapped with + `swap()`.,swap__array_t} + + @since version 1.0.0 + */ + void swap(array_t& other) + { + // swap only works for arrays + if (JSON_LIKELY(is_array())) + { + std::swap(*(m_value.array), other); + } + else + { + JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name()))); + } + } + + /*! + @brief exchanges the values + + Exchanges the contents of a JSON object with those of @a other. Does not + invoke any move, copy, or swap operations on individual elements. All + iterators and references remain valid. The past-the-end iterator is + invalidated. + + @param[in,out] other object to exchange the contents with + + @throw type_error.310 when JSON value is not an object; example: + `"cannot use swap() with string"` + + @complexity Constant. + + @liveexample{The example below shows how objects can be swapped with + `swap()`.,swap__object_t} + + @since version 1.0.0 + */ + void swap(object_t& other) + { + // swap only works for objects + if (JSON_LIKELY(is_object())) + { + std::swap(*(m_value.object), other); + } + else + { + JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name()))); + } + } + + /*! + @brief exchanges the values + + Exchanges the contents of a JSON string with those of @a other. Does not + invoke any move, copy, or swap operations on individual elements. All + iterators and references remain valid. The past-the-end iterator is + invalidated. + + @param[in,out] other string to exchange the contents with + + @throw type_error.310 when JSON value is not a string; example: `"cannot + use swap() with boolean"` + + @complexity Constant. + + @liveexample{The example below shows how strings can be swapped with + `swap()`.,swap__string_t} + + @since version 1.0.0 + */ + void swap(string_t& other) + { + // swap only works for strings + if (JSON_LIKELY(is_string())) + { + std::swap(*(m_value.string), other); + } + else + { + JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name()))); + } + } + + /// @} + + public: + ////////////////////////////////////////// + // lexicographical comparison operators // + ////////////////////////////////////////// + + /// @name lexicographical comparison operators + /// @{ + + /*! + @brief comparison: equal + + Compares two JSON values for equality according to the following rules: + - Two JSON values are equal if (1) they are from the same type and (2) + their stored values are the same according to their respective + `operator==`. + - Integer and floating-point numbers are automatically converted before + comparison. Note than two NaN values are always treated as unequal. + - Two JSON null values are equal. + + @note Floating-point inside JSON values numbers are compared with + `json::number_float_t::operator==` which is `double::operator==` by + default. To compare floating-point while respecting an epsilon, an alternative + [comparison function](https://github.com/mariokonrad/marnav/blob/master/src/marnav/math/floatingpoint.hpp#L34-#L39) + could be used, for instance + @code {.cpp} + template::value, T>::type> + inline bool is_same(T a, T b, T epsilon = std::numeric_limits::epsilon()) noexcept + { + return std::abs(a - b) <= epsilon; + } + @endcode + + @note NaN values never compare equal to themselves or to other NaN values. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether the values @a lhs and @a rhs are equal + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @complexity Linear. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__equal} + + @since version 1.0.0 + */ + friend bool operator==(const_reference lhs, const_reference rhs) noexcept + { + const auto lhs_type = lhs.type(); + const auto rhs_type = rhs.type(); + + if (lhs_type == rhs_type) + { + switch (lhs_type) + { + case value_t::array: + return (*lhs.m_value.array == *rhs.m_value.array); + + case value_t::object: + return (*lhs.m_value.object == *rhs.m_value.object); + + case value_t::null: + return true; + + case value_t::string: + return (*lhs.m_value.string == *rhs.m_value.string); + + case value_t::boolean: + return (lhs.m_value.boolean == rhs.m_value.boolean); + + case value_t::number_integer: + return (lhs.m_value.number_integer == rhs.m_value.number_integer); + + case value_t::number_unsigned: + return (lhs.m_value.number_unsigned == rhs.m_value.number_unsigned); + + case value_t::number_float: + return (lhs.m_value.number_float == rhs.m_value.number_float); + + default: + return false; + } + } + else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float) + { + return (static_cast(lhs.m_value.number_integer) == rhs.m_value.number_float); + } + else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer) + { + return (lhs.m_value.number_float == static_cast(rhs.m_value.number_integer)); + } + else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float) + { + return (static_cast(lhs.m_value.number_unsigned) == rhs.m_value.number_float); + } + else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned) + { + return (lhs.m_value.number_float == static_cast(rhs.m_value.number_unsigned)); + } + else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer) + { + return (static_cast(lhs.m_value.number_unsigned) == rhs.m_value.number_integer); + } + else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned) + { + return (lhs.m_value.number_integer == static_cast(rhs.m_value.number_unsigned)); + } + + return false; + } + + /*! + @brief comparison: equal + @copydoc operator==(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator==(const_reference lhs, const ScalarType rhs) noexcept + { + return (lhs == basic_json(rhs)); + } + + /*! + @brief comparison: equal + @copydoc operator==(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator==(const ScalarType lhs, const_reference rhs) noexcept + { + return (basic_json(lhs) == rhs); + } + + /*! + @brief comparison: not equal + + Compares two JSON values for inequality by calculating `not (lhs == rhs)`. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether the values @a lhs and @a rhs are not equal + + @complexity Linear. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__notequal} + + @since version 1.0.0 + */ + friend bool operator!=(const_reference lhs, const_reference rhs) noexcept + { + return not (lhs == rhs); + } + + /*! + @brief comparison: not equal + @copydoc operator!=(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator!=(const_reference lhs, const ScalarType rhs) noexcept + { + return (lhs != basic_json(rhs)); + } + + /*! + @brief comparison: not equal + @copydoc operator!=(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator!=(const ScalarType lhs, const_reference rhs) noexcept + { + return (basic_json(lhs) != rhs); + } + + /*! + @brief comparison: less than + + Compares whether one JSON value @a lhs is less than another JSON value @a + rhs according to the following rules: + - If @a lhs and @a rhs have the same type, the values are compared using + the default `<` operator. + - Integer and floating-point numbers are automatically converted before + comparison + - In case @a lhs and @a rhs have different types, the values are ignored + and the order of the types is considered, see + @ref operator<(const value_t, const value_t). + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether @a lhs is less than @a rhs + + @complexity Linear. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__less} + + @since version 1.0.0 + */ + friend bool operator<(const_reference lhs, const_reference rhs) noexcept + { + const auto lhs_type = lhs.type(); + const auto rhs_type = rhs.type(); + + if (lhs_type == rhs_type) + { + switch (lhs_type) + { + case value_t::array: + return (*lhs.m_value.array) < (*rhs.m_value.array); + + case value_t::object: + return *lhs.m_value.object < *rhs.m_value.object; + + case value_t::null: + return false; + + case value_t::string: + return *lhs.m_value.string < *rhs.m_value.string; + + case value_t::boolean: + return lhs.m_value.boolean < rhs.m_value.boolean; + + case value_t::number_integer: + return lhs.m_value.number_integer < rhs.m_value.number_integer; + + case value_t::number_unsigned: + return lhs.m_value.number_unsigned < rhs.m_value.number_unsigned; + + case value_t::number_float: + return lhs.m_value.number_float < rhs.m_value.number_float; + + default: + return false; + } + } + else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float) + { + return static_cast(lhs.m_value.number_integer) < rhs.m_value.number_float; + } + else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer) + { + return lhs.m_value.number_float < static_cast(rhs.m_value.number_integer); + } + else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float) + { + return static_cast(lhs.m_value.number_unsigned) < rhs.m_value.number_float; + } + else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned) + { + return lhs.m_value.number_float < static_cast(rhs.m_value.number_unsigned); + } + else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned) + { + return lhs.m_value.number_integer < static_cast(rhs.m_value.number_unsigned); + } + else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer) + { + return static_cast(lhs.m_value.number_unsigned) < rhs.m_value.number_integer; + } + + // We only reach this line if we cannot compare values. In that case, + // we compare types. Note we have to call the operator explicitly, + // because MSVC has problems otherwise. + return operator<(lhs_type, rhs_type); + } + + /*! + @brief comparison: less than + @copydoc operator<(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator<(const_reference lhs, const ScalarType rhs) noexcept + { + return (lhs < basic_json(rhs)); + } + + /*! + @brief comparison: less than + @copydoc operator<(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator<(const ScalarType lhs, const_reference rhs) noexcept + { + return (basic_json(lhs) < rhs); + } + + /*! + @brief comparison: less than or equal + + Compares whether one JSON value @a lhs is less than or equal to another + JSON value by calculating `not (rhs < lhs)`. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether @a lhs is less than or equal to @a rhs + + @complexity Linear. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__greater} + + @since version 1.0.0 + */ + friend bool operator<=(const_reference lhs, const_reference rhs) noexcept + { + return not (rhs < lhs); + } + + /*! + @brief comparison: less than or equal + @copydoc operator<=(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator<=(const_reference lhs, const ScalarType rhs) noexcept + { + return (lhs <= basic_json(rhs)); + } + + /*! + @brief comparison: less than or equal + @copydoc operator<=(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator<=(const ScalarType lhs, const_reference rhs) noexcept + { + return (basic_json(lhs) <= rhs); + } + + /*! + @brief comparison: greater than + + Compares whether one JSON value @a lhs is greater than another + JSON value by calculating `not (lhs <= rhs)`. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether @a lhs is greater than to @a rhs + + @complexity Linear. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__lessequal} + + @since version 1.0.0 + */ + friend bool operator>(const_reference lhs, const_reference rhs) noexcept + { + return not (lhs <= rhs); + } + + /*! + @brief comparison: greater than + @copydoc operator>(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator>(const_reference lhs, const ScalarType rhs) noexcept + { + return (lhs > basic_json(rhs)); + } + + /*! + @brief comparison: greater than + @copydoc operator>(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator>(const ScalarType lhs, const_reference rhs) noexcept + { + return (basic_json(lhs) > rhs); + } + + /*! + @brief comparison: greater than or equal + + Compares whether one JSON value @a lhs is greater than or equal to another + JSON value by calculating `not (lhs < rhs)`. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether @a lhs is greater than or equal to @a rhs + + @complexity Linear. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__greaterequal} + + @since version 1.0.0 + */ + friend bool operator>=(const_reference lhs, const_reference rhs) noexcept + { + return not (lhs < rhs); + } + + /*! + @brief comparison: greater than or equal + @copydoc operator>=(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator>=(const_reference lhs, const ScalarType rhs) noexcept + { + return (lhs >= basic_json(rhs)); + } + + /*! + @brief comparison: greater than or equal + @copydoc operator>=(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator>=(const ScalarType lhs, const_reference rhs) noexcept + { + return (basic_json(lhs) >= rhs); + } + + /// @} + + /////////////////// + // serialization // + /////////////////// + + /// @name serialization + /// @{ + + /*! + @brief serialize to stream + + Serialize the given JSON value @a j to the output stream @a o. The JSON + value will be serialized using the @ref dump member function. + + - The indentation of the output can be controlled with the member variable + `width` of the output stream @a o. For instance, using the manipulator + `std::setw(4)` on @a o sets the indentation level to `4` and the + serialization result is the same as calling `dump(4)`. + + - The indentation character can be controlled with the member variable + `fill` of the output stream @a o. For instance, the manipulator + `std::setfill('\\t')` sets indentation to use a tab character rather than + the default space character. + + @param[in,out] o stream to serialize to + @param[in] j JSON value to serialize + + @return the stream @a o + + @throw type_error.316 if a string stored inside the JSON value is not + UTF-8 encoded + + @complexity Linear. + + @liveexample{The example below shows the serialization with different + parameters to `width` to adjust the indentation level.,operator_serialize} + + @since version 1.0.0; indentation character added in version 3.0.0 + */ + friend std::ostream& operator<<(std::ostream& o, const basic_json& j) + { + // read width member and use it as indentation parameter if nonzero + const bool pretty_print = (o.width() > 0); + const auto indentation = (pretty_print ? o.width() : 0); + + // reset width to 0 for subsequent calls to this stream + o.width(0); + + // do the actual serialization + serializer s(detail::output_adapter(o), o.fill()); + s.dump(j, pretty_print, false, static_cast(indentation)); + return o; + } + + /*! + @brief serialize to stream + @deprecated This stream operator is deprecated and will be removed in a + future version of the library. Please use + @ref operator<<(std::ostream&, const basic_json&) + instead; that is, replace calls like `j >> o;` with `o << j;`. + @since version 1.0.0; deprecated since version 3.0.0 + */ + JSON_DEPRECATED + friend std::ostream& operator>>(const basic_json& j, std::ostream& o) + { + return o << j; + } + + /// @} + + + ///////////////////// + // deserialization // + ///////////////////// + + /// @name deserialization + /// @{ + + /*! + @brief deserialize from a compatible input + + This function reads from a compatible input. Examples are: + - an array of 1-byte values + - strings with character/literal type with size of 1 byte + - input streams + - container with contiguous storage of 1-byte values. Compatible container + types include `std::vector`, `std::string`, `std::array`, + `std::valarray`, and `std::initializer_list`. Furthermore, C-style + arrays can be used with `std::begin()`/`std::end()`. User-defined + containers can be used as long as they implement random-access iterators + and a contiguous storage. + + @pre Each element of the container has a size of 1 byte. Violating this + precondition yields undefined behavior. **This precondition is enforced + with a static assertion.** + + @pre The container storage is contiguous. Violating this precondition + yields undefined behavior. **This precondition is enforced with an + assertion.** + @pre Each element of the container has a size of 1 byte. Violating this + precondition yields undefined behavior. **This precondition is enforced + with a static assertion.** + + @warning There is no way to enforce all preconditions at compile-time. If + the function is called with a noncompliant container and with + assertions switched off, the behavior is undefined and will most + likely yield segmentation violation. + + @param[in] i input to read from + @param[in] cb a parser callback function of type @ref parser_callback_t + which is used to control the deserialization by filtering unwanted values + (optional) + + @return result of the deserialization + + @throw parse_error.101 if a parse error occurs; example: `""unexpected end + of input; expected string literal""` + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + + @complexity Linear in the length of the input. The parser is a predictive + LL(1) parser. The complexity can be higher if the parser callback function + @a cb has a super-linear complexity. + + @note A UTF-8 byte order mark is silently ignored. + + @liveexample{The example below demonstrates the `parse()` function reading + from an array.,parse__array__parser_callback_t} + + @liveexample{The example below demonstrates the `parse()` function with + and without callback function.,parse__string__parser_callback_t} + + @liveexample{The example below demonstrates the `parse()` function with + and without callback function.,parse__istream__parser_callback_t} + + @liveexample{The example below demonstrates the `parse()` function reading + from a contiguous container.,parse__contiguouscontainer__parser_callback_t} + + @since version 2.0.3 (contiguous containers) + */ + static basic_json parse(detail::input_adapter i, + const parser_callback_t cb = nullptr, + const bool allow_exceptions = true) + { + basic_json result; + parser(i, cb, allow_exceptions).parse(true, result); + return result; + } + + /*! + @copydoc basic_json parse(detail::input_adapter, const parser_callback_t) + */ + static basic_json parse(detail::input_adapter& i, + const parser_callback_t cb = nullptr, + const bool allow_exceptions = true) + { + basic_json result; + parser(i, cb, allow_exceptions).parse(true, result); + return result; + } + + static bool accept(detail::input_adapter i) + { + return parser(i).accept(true); + } + + static bool accept(detail::input_adapter& i) + { + return parser(i).accept(true); + } + + /*! + @brief deserialize from an iterator range with contiguous storage + + This function reads from an iterator range of a container with contiguous + storage of 1-byte values. Compatible container types include + `std::vector`, `std::string`, `std::array`, `std::valarray`, and + `std::initializer_list`. Furthermore, C-style arrays can be used with + `std::begin()`/`std::end()`. User-defined containers can be used as long + as they implement random-access iterators and a contiguous storage. + + @pre The iterator range is contiguous. Violating this precondition yields + undefined behavior. **This precondition is enforced with an assertion.** + @pre Each element in the range has a size of 1 byte. Violating this + precondition yields undefined behavior. **This precondition is enforced + with a static assertion.** + + @warning There is no way to enforce all preconditions at compile-time. If + the function is called with noncompliant iterators and with + assertions switched off, the behavior is undefined and will most + likely yield segmentation violation. + + @tparam IteratorType iterator of container with contiguous storage + @param[in] first begin of the range to parse (included) + @param[in] last end of the range to parse (excluded) + @param[in] cb a parser callback function of type @ref parser_callback_t + which is used to control the deserialization by filtering unwanted values + (optional) + @param[in] allow_exceptions whether to throw exceptions in case of a + parse error (optional, true by default) + + @return result of the deserialization + + @throw parse_error.101 in case of an unexpected token + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + + @complexity Linear in the length of the input. The parser is a predictive + LL(1) parser. The complexity can be higher if the parser callback function + @a cb has a super-linear complexity. + + @note A UTF-8 byte order mark is silently ignored. + + @liveexample{The example below demonstrates the `parse()` function reading + from an iterator range.,parse__iteratortype__parser_callback_t} + + @since version 2.0.3 + */ + template::iterator_category>::value, int>::type = 0> + static basic_json parse(IteratorType first, IteratorType last, + const parser_callback_t cb = nullptr, + const bool allow_exceptions = true) + { + basic_json result; + parser(detail::input_adapter(first, last), cb, allow_exceptions).parse(true, result); + return result; + } + + template::iterator_category>::value, int>::type = 0> + static bool accept(IteratorType first, IteratorType last) + { + return parser(detail::input_adapter(first, last)).accept(true); + } + + /*! + @brief deserialize from stream + @deprecated This stream operator is deprecated and will be removed in a + future version of the library. Please use + @ref operator>>(std::istream&, basic_json&) + instead; that is, replace calls like `j << i;` with `i >> j;`. + @since version 1.0.0; deprecated since version 3.0.0 + */ + JSON_DEPRECATED + friend std::istream& operator<<(basic_json& j, std::istream& i) + { + return operator>>(i, j); + } + + /*! + @brief deserialize from stream + + Deserializes an input stream to a JSON value. + + @param[in,out] i input stream to read a serialized JSON value from + @param[in,out] j JSON value to write the deserialized input to + + @throw parse_error.101 in case of an unexpected token + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + + @complexity Linear in the length of the input. The parser is a predictive + LL(1) parser. + + @note A UTF-8 byte order mark is silently ignored. + + @liveexample{The example below shows how a JSON value is constructed by + reading a serialization from a stream.,operator_deserialize} + + @sa parse(std::istream&, const parser_callback_t) for a variant with a + parser callback function to filter values while parsing + + @since version 1.0.0 + */ + friend std::istream& operator>>(std::istream& i, basic_json& j) + { + parser(detail::input_adapter(i)).parse(false, j); + return i; + } + + /// @} + + /////////////////////////// + // convenience functions // + /////////////////////////// + + /*! + @brief return the type as string + + Returns the type name as string to be used in error messages - usually to + indicate that a function was called on a wrong JSON type. + + @return a string representation of a the @a m_type member: + Value type | return value + ----------- | ------------- + null | `"null"` + boolean | `"boolean"` + string | `"string"` + number | `"number"` (for all number types) + object | `"object"` + array | `"array"` + discarded | `"discarded"` + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @complexity Constant. + + @liveexample{The following code exemplifies `type_name()` for all JSON + types.,type_name} + + @sa @ref type() -- return the type of the JSON value + @sa @ref operator value_t() -- return the type of the JSON value (implicit) + + @since version 1.0.0, public since 2.1.0, `const char*` and `noexcept` + since 3.0.0 + */ + const char* type_name() const noexcept + { + { + switch (m_type) + { + case value_t::null: + return "null"; + case value_t::object: + return "object"; + case value_t::array: + return "array"; + case value_t::string: + return "string"; + case value_t::boolean: + return "boolean"; + case value_t::discarded: + return "discarded"; + default: + return "number"; + } + } + } + + + private: + ////////////////////// + // member variables // + ////////////////////// + + /// the type of the current element + value_t m_type = value_t::null; + + /// the value of the current element + json_value m_value = {}; + + ////////////////////////////////////////// + // binary serialization/deserialization // + ////////////////////////////////////////// + + /// @name binary serialization/deserialization support + /// @{ + + public: + /*! + @brief create a CBOR serialization of a given JSON value + + Serializes a given JSON value @a j to a byte vector using the CBOR (Concise + Binary Object Representation) serialization format. CBOR is a binary + serialization format which aims to be more compact than JSON itself, yet + more efficient to parse. + + The library uses the following mapping from JSON values types to + CBOR types according to the CBOR specification (RFC 7049): + + JSON value type | value/range | CBOR type | first byte + --------------- | ------------------------------------------ | ---------------------------------- | --------------- + null | `null` | Null | 0xF6 + boolean | `true` | True | 0xF5 + boolean | `false` | False | 0xF4 + number_integer | -9223372036854775808..-2147483649 | Negative integer (8 bytes follow) | 0x3B + number_integer | -2147483648..-32769 | Negative integer (4 bytes follow) | 0x3A + number_integer | -32768..-129 | Negative integer (2 bytes follow) | 0x39 + number_integer | -128..-25 | Negative integer (1 byte follow) | 0x38 + number_integer | -24..-1 | Negative integer | 0x20..0x37 + number_integer | 0..23 | Integer | 0x00..0x17 + number_integer | 24..255 | Unsigned integer (1 byte follow) | 0x18 + number_integer | 256..65535 | Unsigned integer (2 bytes follow) | 0x19 + number_integer | 65536..4294967295 | Unsigned integer (4 bytes follow) | 0x1A + number_integer | 4294967296..18446744073709551615 | Unsigned integer (8 bytes follow) | 0x1B + number_unsigned | 0..23 | Integer | 0x00..0x17 + number_unsigned | 24..255 | Unsigned integer (1 byte follow) | 0x18 + number_unsigned | 256..65535 | Unsigned integer (2 bytes follow) | 0x19 + number_unsigned | 65536..4294967295 | Unsigned integer (4 bytes follow) | 0x1A + number_unsigned | 4294967296..18446744073709551615 | Unsigned integer (8 bytes follow) | 0x1B + number_float | *any value* | Double-Precision Float | 0xFB + string | *length*: 0..23 | UTF-8 string | 0x60..0x77 + string | *length*: 23..255 | UTF-8 string (1 byte follow) | 0x78 + string | *length*: 256..65535 | UTF-8 string (2 bytes follow) | 0x79 + string | *length*: 65536..4294967295 | UTF-8 string (4 bytes follow) | 0x7A + string | *length*: 4294967296..18446744073709551615 | UTF-8 string (8 bytes follow) | 0x7B + array | *size*: 0..23 | array | 0x80..0x97 + array | *size*: 23..255 | array (1 byte follow) | 0x98 + array | *size*: 256..65535 | array (2 bytes follow) | 0x99 + array | *size*: 65536..4294967295 | array (4 bytes follow) | 0x9A + array | *size*: 4294967296..18446744073709551615 | array (8 bytes follow) | 0x9B + object | *size*: 0..23 | map | 0xA0..0xB7 + object | *size*: 23..255 | map (1 byte follow) | 0xB8 + object | *size*: 256..65535 | map (2 bytes follow) | 0xB9 + object | *size*: 65536..4294967295 | map (4 bytes follow) | 0xBA + object | *size*: 4294967296..18446744073709551615 | map (8 bytes follow) | 0xBB + + @note The mapping is **complete** in the sense that any JSON value type + can be converted to a CBOR value. + + @note If NaN or Infinity are stored inside a JSON number, they are + serialized properly. This behavior differs from the @ref dump() + function which serializes NaN or Infinity to `null`. + + @note The following CBOR types are not used in the conversion: + - byte strings (0x40..0x5F) + - UTF-8 strings terminated by "break" (0x7F) + - arrays terminated by "break" (0x9F) + - maps terminated by "break" (0xBF) + - date/time (0xC0..0xC1) + - bignum (0xC2..0xC3) + - decimal fraction (0xC4) + - bigfloat (0xC5) + - tagged items (0xC6..0xD4, 0xD8..0xDB) + - expected conversions (0xD5..0xD7) + - simple values (0xE0..0xF3, 0xF8) + - undefined (0xF7) + - half and single-precision floats (0xF9-0xFA) + - break (0xFF) + + @param[in] j JSON value to serialize + @return MessagePack serialization as byte vector + + @complexity Linear in the size of the JSON value @a j. + + @liveexample{The example shows the serialization of a JSON value to a byte + vector in CBOR format.,to_cbor} + + @sa http://cbor.io + @sa @ref from_cbor(const std::vector&, const size_t) for the + analogous deserialization + @sa @ref to_msgpack(const basic_json&) for the related MessagePack format + + @since version 2.0.9 + */ + static std::vector to_cbor(const basic_json& j) + { + std::vector result; + to_cbor(j, result); + return result; + } + + static void to_cbor(const basic_json& j, detail::output_adapter o) + { + binary_writer(o).write_cbor(j); + } + + static void to_cbor(const basic_json& j, detail::output_adapter o) + { + binary_writer(o).write_cbor(j); + } + + /*! + @brief create a MessagePack serialization of a given JSON value + + Serializes a given JSON value @a j to a byte vector using the MessagePack + serialization format. MessagePack is a binary serialization format which + aims to be more compact than JSON itself, yet more efficient to parse. + + The library uses the following mapping from JSON values types to + MessagePack types according to the MessagePack specification: + + JSON value type | value/range | MessagePack type | first byte + --------------- | --------------------------------- | ---------------- | ---------- + null | `null` | nil | 0xC0 + boolean | `true` | true | 0xC3 + boolean | `false` | false | 0xC2 + number_integer | -9223372036854775808..-2147483649 | int64 | 0xD3 + number_integer | -2147483648..-32769 | int32 | 0xD2 + number_integer | -32768..-129 | int16 | 0xD1 + number_integer | -128..-33 | int8 | 0xD0 + number_integer | -32..-1 | negative fixint | 0xE0..0xFF + number_integer | 0..127 | positive fixint | 0x00..0x7F + number_integer | 128..255 | uint 8 | 0xCC + number_integer | 256..65535 | uint 16 | 0xCD + number_integer | 65536..4294967295 | uint 32 | 0xCE + number_integer | 4294967296..18446744073709551615 | uint 64 | 0xCF + number_unsigned | 0..127 | positive fixint | 0x00..0x7F + number_unsigned | 128..255 | uint 8 | 0xCC + number_unsigned | 256..65535 | uint 16 | 0xCD + number_unsigned | 65536..4294967295 | uint 32 | 0xCE + number_unsigned | 4294967296..18446744073709551615 | uint 64 | 0xCF + number_float | *any value* | float 64 | 0xCB + string | *length*: 0..31 | fixstr | 0xA0..0xBF + string | *length*: 32..255 | str 8 | 0xD9 + string | *length*: 256..65535 | str 16 | 0xDA + string | *length*: 65536..4294967295 | str 32 | 0xDB + array | *size*: 0..15 | fixarray | 0x90..0x9F + array | *size*: 16..65535 | array 16 | 0xDC + array | *size*: 65536..4294967295 | array 32 | 0xDD + object | *size*: 0..15 | fix map | 0x80..0x8F + object | *size*: 16..65535 | map 16 | 0xDE + object | *size*: 65536..4294967295 | map 32 | 0xDF + + @note The mapping is **complete** in the sense that any JSON value type + can be converted to a MessagePack value. + + @note The following values can **not** be converted to a MessagePack value: + - strings with more than 4294967295 bytes + - arrays with more than 4294967295 elements + - objects with more than 4294967295 elements + + @note The following MessagePack types are not used in the conversion: + - bin 8 - bin 32 (0xC4..0xC6) + - ext 8 - ext 32 (0xC7..0xC9) + - float 32 (0xCA) + - fixext 1 - fixext 16 (0xD4..0xD8) + + @note Any MessagePack output created @ref to_msgpack can be successfully + parsed by @ref from_msgpack. + + @note If NaN or Infinity are stored inside a JSON number, they are + serialized properly. This behavior differs from the @ref dump() + function which serializes NaN or Infinity to `null`. + + @param[in] j JSON value to serialize + @return MessagePack serialization as byte vector + + @complexity Linear in the size of the JSON value @a j. + + @liveexample{The example shows the serialization of a JSON value to a byte + vector in MessagePack format.,to_msgpack} + + @sa http://msgpack.org + @sa @ref from_msgpack(const std::vector&, const size_t) for the + analogous deserialization + @sa @ref to_cbor(const basic_json& for the related CBOR format + + @since version 2.0.9 + */ + static std::vector to_msgpack(const basic_json& j) + { + std::vector result; + to_msgpack(j, result); + return result; + } + + static void to_msgpack(const basic_json& j, detail::output_adapter o) + { + binary_writer(o).write_msgpack(j); + } + + static void to_msgpack(const basic_json& j, detail::output_adapter o) + { + binary_writer(o).write_msgpack(j); + } + + /*! + @brief create a JSON value from an input in CBOR format + + Deserializes a given input @a i to a JSON value using the CBOR (Concise + Binary Object Representation) serialization format. + + The library maps CBOR types to JSON value types as follows: + + CBOR type | JSON value type | first byte + ---------------------- | --------------- | ---------- + Integer | number_unsigned | 0x00..0x17 + Unsigned integer | number_unsigned | 0x18 + Unsigned integer | number_unsigned | 0x19 + Unsigned integer | number_unsigned | 0x1A + Unsigned integer | number_unsigned | 0x1B + Negative integer | number_integer | 0x20..0x37 + Negative integer | number_integer | 0x38 + Negative integer | number_integer | 0x39 + Negative integer | number_integer | 0x3A + Negative integer | number_integer | 0x3B + Negative integer | number_integer | 0x40..0x57 + UTF-8 string | string | 0x60..0x77 + UTF-8 string | string | 0x78 + UTF-8 string | string | 0x79 + UTF-8 string | string | 0x7A + UTF-8 string | string | 0x7B + UTF-8 string | string | 0x7F + array | array | 0x80..0x97 + array | array | 0x98 + array | array | 0x99 + array | array | 0x9A + array | array | 0x9B + array | array | 0x9F + map | object | 0xA0..0xB7 + map | object | 0xB8 + map | object | 0xB9 + map | object | 0xBA + map | object | 0xBB + map | object | 0xBF + False | `false` | 0xF4 + True | `true` | 0xF5 + Nill | `null` | 0xF6 + Half-Precision Float | number_float | 0xF9 + Single-Precision Float | number_float | 0xFA + Double-Precision Float | number_float | 0xFB + + @warning The mapping is **incomplete** in the sense that not all CBOR + types can be converted to a JSON value. The following CBOR types + are not supported and will yield parse errors (parse_error.112): + - byte strings (0x40..0x5F) + - date/time (0xC0..0xC1) + - bignum (0xC2..0xC3) + - decimal fraction (0xC4) + - bigfloat (0xC5) + - tagged items (0xC6..0xD4, 0xD8..0xDB) + - expected conversions (0xD5..0xD7) + - simple values (0xE0..0xF3, 0xF8) + - undefined (0xF7) + + @warning CBOR allows map keys of any type, whereas JSON only allows + strings as keys in object values. Therefore, CBOR maps with keys + other than UTF-8 strings are rejected (parse_error.113). + + @note Any CBOR output created @ref to_cbor can be successfully parsed by + @ref from_cbor. + + @param[in] i an input in CBOR format convertible to an input adapter + @param[in] strict whether to expect the input to be consumed until EOF + (true by default) + @return deserialized JSON value + + @throw parse_error.110 if the given input ends prematurely or the end of + file was not reached when @a strict was set to true + @throw parse_error.112 if unsupported features from CBOR were + used in the given input @a v or if the input is not valid CBOR + @throw parse_error.113 if a string was expected as map key, but not found + + @complexity Linear in the size of the input @a i. + + @liveexample{The example shows the deserialization of a byte vector in CBOR + format to a JSON value.,from_cbor} + + @sa http://cbor.io + @sa @ref to_cbor(const basic_json&) for the analogous serialization + @sa @ref from_msgpack(detail::input_adapter, const bool) for the + related MessagePack format + + @since version 2.0.9; parameter @a start_index since 2.1.1; changed to + consume input adapters, removed start_index parameter, and added + @a strict parameter since 3.0.0 + */ + static basic_json from_cbor(detail::input_adapter i, + const bool strict = true) + { + return binary_reader(i).parse_cbor(strict); + } + + /*! + @copydoc from_cbor(detail::input_adapter, const bool) + */ + template::value, int> = 0> + static basic_json from_cbor(A1 && a1, A2 && a2, const bool strict = true) + { + return binary_reader(detail::input_adapter(std::forward(a1), std::forward(a2))).parse_cbor(strict); + } + + /*! + @brief create a JSON value from an input in MessagePack format + + Deserializes a given input @a i to a JSON value using the MessagePack + serialization format. + + The library maps MessagePack types to JSON value types as follows: + + MessagePack type | JSON value type | first byte + ---------------- | --------------- | ---------- + positive fixint | number_unsigned | 0x00..0x7F + fixmap | object | 0x80..0x8F + fixarray | array | 0x90..0x9F + fixstr | string | 0xA0..0xBF + nil | `null` | 0xC0 + false | `false` | 0xC2 + true | `true` | 0xC3 + float 32 | number_float | 0xCA + float 64 | number_float | 0xCB + uint 8 | number_unsigned | 0xCC + uint 16 | number_unsigned | 0xCD + uint 32 | number_unsigned | 0xCE + uint 64 | number_unsigned | 0xCF + int 8 | number_integer | 0xD0 + int 16 | number_integer | 0xD1 + int 32 | number_integer | 0xD2 + int 64 | number_integer | 0xD3 + str 8 | string | 0xD9 + str 16 | string | 0xDA + str 32 | string | 0xDB + array 16 | array | 0xDC + array 32 | array | 0xDD + map 16 | object | 0xDE + map 32 | object | 0xDF + negative fixint | number_integer | 0xE0-0xFF + + @warning The mapping is **incomplete** in the sense that not all + MessagePack types can be converted to a JSON value. The following + MessagePack types are not supported and will yield parse errors: + - bin 8 - bin 32 (0xC4..0xC6) + - ext 8 - ext 32 (0xC7..0xC9) + - fixext 1 - fixext 16 (0xD4..0xD8) + + @note Any MessagePack output created @ref to_msgpack can be successfully + parsed by @ref from_msgpack. + + @param[in] i an input in MessagePack format convertible to an input + adapter + @param[in] strict whether to expect the input to be consumed until EOF + (true by default) + + @throw parse_error.110 if the given input ends prematurely or the end of + file was not reached when @a strict was set to true + @throw parse_error.112 if unsupported features from MessagePack were + used in the given input @a i or if the input is not valid MessagePack + @throw parse_error.113 if a string was expected as map key, but not found + + @complexity Linear in the size of the input @a i. + + @liveexample{The example shows the deserialization of a byte vector in + MessagePack format to a JSON value.,from_msgpack} + + @sa http://msgpack.org + @sa @ref to_msgpack(const basic_json&) for the analogous serialization + @sa @ref from_cbor(detail::input_adapter, const bool) for the related CBOR + format + + @since version 2.0.9; parameter @a start_index since 2.1.1; changed to + consume input adapters, removed start_index parameter, and added + @a strict parameter since 3.0.0 + */ + static basic_json from_msgpack(detail::input_adapter i, + const bool strict = true) + { + return binary_reader(i).parse_msgpack(strict); + } + + /*! + @copydoc from_msgpack(detail::input_adapter, const bool) + */ + template::value, int> = 0> + static basic_json from_msgpack(A1 && a1, A2 && a2, const bool strict = true) + { + return binary_reader(detail::input_adapter(std::forward(a1), std::forward(a2))).parse_msgpack(strict); + } + + /// @} + + ////////////////////////// + // JSON Pointer support // + ////////////////////////// + + /// @name JSON Pointer functions + /// @{ + + /*! + @brief access specified element via JSON Pointer + + Uses a JSON pointer to retrieve a reference to the respective JSON value. + No bound checking is performed. Similar to @ref operator[](const typename + object_t::key_type&), `null` values are created in arrays and objects if + necessary. + + In particular: + - If the JSON pointer points to an object key that does not exist, it + is created an filled with a `null` value before a reference to it + is returned. + - If the JSON pointer points to an array index that does not exist, it + is created an filled with a `null` value before a reference to it + is returned. All indices between the current maximum and the given + index are also filled with `null`. + - The special value `-` is treated as a synonym for the index past the + end. + + @param[in] ptr a JSON pointer + + @return reference to the element pointed to by @a ptr + + @complexity Constant. + + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.404 if the JSON pointer can not be resolved + + @liveexample{The behavior is shown in the example.,operatorjson_pointer} + + @since version 2.0.0 + */ + reference operator[](const json_pointer& ptr) + { + return ptr.get_unchecked(this); + } + + /*! + @brief access specified element via JSON Pointer + + Uses a JSON pointer to retrieve a reference to the respective JSON value. + No bound checking is performed. The function does not change the JSON + value; no `null` values are created. In particular, the the special value + `-` yields an exception. + + @param[in] ptr JSON pointer to the desired element + + @return const reference to the element pointed to by @a ptr + + @complexity Constant. + + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.402 if the array index '-' is used + @throw out_of_range.404 if the JSON pointer can not be resolved + + @liveexample{The behavior is shown in the example.,operatorjson_pointer_const} + + @since version 2.0.0 + */ + const_reference operator[](const json_pointer& ptr) const + { + return ptr.get_unchecked(this); + } + + /*! + @brief access specified element via JSON Pointer + + Returns a reference to the element at with specified JSON pointer @a ptr, + with bounds checking. + + @param[in] ptr JSON pointer to the desired element + + @return reference to the element pointed to by @a ptr + + @throw parse_error.106 if an array index in the passed JSON pointer @a ptr + begins with '0'. See example below. + + @throw parse_error.109 if an array index in the passed JSON pointer @a ptr + is not a number. See example below. + + @throw out_of_range.401 if an array index in the passed JSON pointer @a ptr + is out of range. See example below. + + @throw out_of_range.402 if the array index '-' is used in the passed JSON + pointer @a ptr. As `at` provides checked access (and no elements are + implicitly inserted), the index '-' is always invalid. See example below. + + @throw out_of_range.403 if the JSON pointer describes a key of an object + which cannot be found. See example below. + + @throw out_of_range.404 if the JSON pointer @a ptr can not be resolved. + See example below. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Constant. + + @since version 2.0.0 + + @liveexample{The behavior is shown in the example.,at_json_pointer} + */ + reference at(const json_pointer& ptr) + { + return ptr.get_checked(this); + } + + /*! + @brief access specified element via JSON Pointer + + Returns a const reference to the element at with specified JSON pointer @a + ptr, with bounds checking. + + @param[in] ptr JSON pointer to the desired element + + @return reference to the element pointed to by @a ptr + + @throw parse_error.106 if an array index in the passed JSON pointer @a ptr + begins with '0'. See example below. + + @throw parse_error.109 if an array index in the passed JSON pointer @a ptr + is not a number. See example below. + + @throw out_of_range.401 if an array index in the passed JSON pointer @a ptr + is out of range. See example below. + + @throw out_of_range.402 if the array index '-' is used in the passed JSON + pointer @a ptr. As `at` provides checked access (and no elements are + implicitly inserted), the index '-' is always invalid. See example below. + + @throw out_of_range.403 if the JSON pointer describes a key of an object + which cannot be found. See example below. + + @throw out_of_range.404 if the JSON pointer @a ptr can not be resolved. + See example below. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Constant. + + @since version 2.0.0 + + @liveexample{The behavior is shown in the example.,at_json_pointer_const} + */ + const_reference at(const json_pointer& ptr) const + { + return ptr.get_checked(this); + } + + /*! + @brief return flattened JSON value + + The function creates a JSON object whose keys are JSON pointers (see [RFC + 6901](https://tools.ietf.org/html/rfc6901)) and whose values are all + primitive. The original JSON value can be restored using the @ref + unflatten() function. + + @return an object that maps JSON pointers to primitive values + + @note Empty objects and arrays are flattened to `null` and will not be + reconstructed correctly by the @ref unflatten() function. + + @complexity Linear in the size the JSON value. + + @liveexample{The following code shows how a JSON object is flattened to an + object whose keys consist of JSON pointers.,flatten} + + @sa @ref unflatten() for the reverse function + + @since version 2.0.0 + */ + basic_json flatten() const + { + basic_json result(value_t::object); + json_pointer::flatten("", *this, result); + return result; + } + + /*! + @brief unflatten a previously flattened JSON value + + The function restores the arbitrary nesting of a JSON value that has been + flattened before using the @ref flatten() function. The JSON value must + meet certain constraints: + 1. The value must be an object. + 2. The keys must be JSON pointers (see + [RFC 6901](https://tools.ietf.org/html/rfc6901)) + 3. The mapped values must be primitive JSON types. + + @return the original JSON from a flattened version + + @note Empty objects and arrays are flattened by @ref flatten() to `null` + values and can not unflattened to their original type. Apart from + this example, for a JSON value `j`, the following is always true: + `j == j.flatten().unflatten()`. + + @complexity Linear in the size the JSON value. + + @throw type_error.314 if value is not an object + @throw type_error.315 if object values are not primitive + + @liveexample{The following code shows how a flattened JSON object is + unflattened into the original nested JSON object.,unflatten} + + @sa @ref flatten() for the reverse function + + @since version 2.0.0 + */ + basic_json unflatten() const + { + return json_pointer::unflatten(*this); + } + + /// @} + + ////////////////////////// + // JSON Patch functions // + ////////////////////////// + + /// @name JSON Patch functions + /// @{ + + /*! + @brief applies a JSON patch + + [JSON Patch](http://jsonpatch.com) defines a JSON document structure for + expressing a sequence of operations to apply to a JSON) document. With + this function, a JSON Patch is applied to the current JSON value by + executing all operations from the patch. + + @param[in] json_patch JSON patch document + @return patched document + + @note The application of a patch is atomic: Either all operations succeed + and the patched document is returned or an exception is thrown. In + any case, the original value is not changed: the patch is applied + to a copy of the value. + + @throw parse_error.104 if the JSON patch does not consist of an array of + objects + + @throw parse_error.105 if the JSON patch is malformed (e.g., mandatory + attributes are missing); example: `"operation add must have member path"` + + @throw out_of_range.401 if an array index is out of range. + + @throw out_of_range.403 if a JSON pointer inside the patch could not be + resolved successfully in the current JSON value; example: `"key baz not + found"` + + @throw out_of_range.405 if JSON pointer has no parent ("add", "remove", + "move") + + @throw other_error.501 if "test" operation was unsuccessful + + @complexity Linear in the size of the JSON value and the length of the + JSON patch. As usually only a fraction of the JSON value is affected by + the patch, the complexity can usually be neglected. + + @liveexample{The following code shows how a JSON patch is applied to a + value.,patch} + + @sa @ref diff -- create a JSON patch by comparing two JSON values + + @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902) + @sa [RFC 6901 (JSON Pointer)](https://tools.ietf.org/html/rfc6901) + + @since version 2.0.0 + */ + basic_json patch(const basic_json& json_patch) const + { + // make a working copy to apply the patch to + basic_json result = *this; + + // the valid JSON Patch operations + enum class patch_operations {add, remove, replace, move, copy, test, invalid}; + + const auto get_op = [](const std::string & op) + { + if (op == "add") + { + return patch_operations::add; + } + if (op == "remove") + { + return patch_operations::remove; + } + if (op == "replace") + { + return patch_operations::replace; + } + if (op == "move") + { + return patch_operations::move; + } + if (op == "copy") + { + return patch_operations::copy; + } + if (op == "test") + { + return patch_operations::test; + } + + return patch_operations::invalid; + }; + + // wrapper for "add" operation; add value at ptr + const auto operation_add = [&result](json_pointer & ptr, basic_json val) + { + // adding to the root of the target document means replacing it + if (ptr.is_root()) + { + result = val; + } + else + { + // make sure the top element of the pointer exists + json_pointer top_pointer = ptr.top(); + if (top_pointer != ptr) + { + result.at(top_pointer); + } + + // get reference to parent of JSON pointer ptr + const auto last_path = ptr.pop_back(); + basic_json& parent = result[ptr]; + + switch (parent.m_type) + { + case value_t::null: + case value_t::object: + { + // use operator[] to add value + parent[last_path] = val; + break; + } + + case value_t::array: + { + if (last_path == "-") + { + // special case: append to back + parent.push_back(val); + } + else + { + const auto idx = json_pointer::array_index(last_path); + if (JSON_UNLIKELY(static_cast(idx) > parent.size())) + { + // avoid undefined behavior + JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range")); + } + else + { + // default case: insert add offset + parent.insert(parent.begin() + static_cast(idx), val); + } + } + break; + } + + default: + { + // if there exists a parent it cannot be primitive + assert(false); // LCOV_EXCL_LINE + } + } + } + }; + + // wrapper for "remove" operation; remove value at ptr + const auto operation_remove = [&result](json_pointer & ptr) + { + // get reference to parent of JSON pointer ptr + const auto last_path = ptr.pop_back(); + basic_json& parent = result.at(ptr); + + // remove child + if (parent.is_object()) + { + // perform range check + auto it = parent.find(last_path); + if (JSON_LIKELY(it != parent.end())) + { + parent.erase(it); + } + else + { + JSON_THROW(out_of_range::create(403, "key '" + last_path + "' not found")); + } + } + else if (parent.is_array()) + { + // note erase performs range check + parent.erase(static_cast(json_pointer::array_index(last_path))); + } + }; + + // type check: top level value must be an array + if (JSON_UNLIKELY(not json_patch.is_array())) + { + JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects")); + } + + // iterate and apply the operations + for (const auto& val : json_patch) + { + // wrapper to get a value for an operation + const auto get_value = [&val](const std::string & op, + const std::string & member, + bool string_type) -> basic_json& + { + // find value + auto it = val.m_value.object->find(member); + + // context-sensitive error message + const auto error_msg = (op == "op") ? "operation" : "operation '" + op + "'"; + + // check if desired value is present + if (JSON_UNLIKELY(it == val.m_value.object->end())) + { + JSON_THROW(parse_error::create(105, 0, error_msg + " must have member '" + member + "'")); + } + + // check if result is of type string + if (JSON_UNLIKELY(string_type and not it->second.is_string())) + { + JSON_THROW(parse_error::create(105, 0, error_msg + " must have string member '" + member + "'")); + } + + // no error: return value + return it->second; + }; + + // type check: every element of the array must be an object + if (JSON_UNLIKELY(not val.is_object())) + { + JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects")); + } + + // collect mandatory members + const std::string op = get_value("op", "op", true); + const std::string path = get_value(op, "path", true); + json_pointer ptr(path); + + switch (get_op(op)) + { + case patch_operations::add: + { + operation_add(ptr, get_value("add", "value", false)); + break; + } + + case patch_operations::remove: + { + operation_remove(ptr); + break; + } + + case patch_operations::replace: + { + // the "path" location must exist - use at() + result.at(ptr) = get_value("replace", "value", false); + break; + } + + case patch_operations::move: + { + const std::string from_path = get_value("move", "from", true); + json_pointer from_ptr(from_path); + + // the "from" location must exist - use at() + basic_json v = result.at(from_ptr); + + // The move operation is functionally identical to a + // "remove" operation on the "from" location, followed + // immediately by an "add" operation at the target + // location with the value that was just removed. + operation_remove(from_ptr); + operation_add(ptr, v); + break; + } + + case patch_operations::copy: + { + const std::string from_path = get_value("copy", "from", true); + const json_pointer from_ptr(from_path); + + // the "from" location must exist - use at() + basic_json v = result.at(from_ptr); + + // The copy is functionally identical to an "add" + // operation at the target location using the value + // specified in the "from" member. + operation_add(ptr, v); + break; + } + + case patch_operations::test: + { + bool success = false; + 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)); + } + JSON_CATCH (out_of_range&) + { + // ignore out of range errors: success remains false + } + + // throw an exception if test fails + if (JSON_UNLIKELY(not success)) + { + JSON_THROW(other_error::create(501, "unsuccessful: " + val.dump())); + } + + break; + } + + case patch_operations::invalid: + { + // op must be "add", "remove", "replace", "move", "copy", or + // "test" + JSON_THROW(parse_error::create(105, 0, "operation value '" + op + "' is invalid")); + } + } + } + + return result; + } + + /*! + @brief creates a diff as a JSON patch + + Creates a [JSON Patch](http://jsonpatch.com) so that value @a source can + be changed into the value @a target by calling @ref patch function. + + @invariant For two JSON values @a source and @a target, the following code + yields always `true`: + @code {.cpp} + source.patch(diff(source, target)) == target; + @endcode + + @note Currently, only `remove`, `add`, and `replace` operations are + generated. + + @param[in] source JSON value to compare from + @param[in] target JSON value to compare against + @param[in] path helper value to create JSON pointers + + @return a JSON patch to convert the @a source to @a target + + @complexity Linear in the lengths of @a source and @a target. + + @liveexample{The following code shows how a JSON patch is created as a + diff for two JSON values.,diff} + + @sa @ref patch -- apply a JSON patch + + @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902) + + @since version 2.0.0 + */ + static basic_json diff(const basic_json& source, const basic_json& target, + const std::string& path = "") + { + // the patch + basic_json result(value_t::array); + + // if the values are the same, return empty patch + if (source == target) + { + return result; + } + + if (source.type() != target.type()) + { + // different types: replace value + result.push_back( + { + {"op", "replace"}, {"path", path}, {"value", target} + }); + } + else + { + switch (source.type()) + { + case value_t::array: + { + // first pass: traverse common elements + std::size_t i = 0; + while (i < source.size() and i < target.size()) + { + // recursive call to compare array values at index i + auto temp_diff = diff(source[i], target[i], path + "/" + std::to_string(i)); + result.insert(result.end(), temp_diff.begin(), temp_diff.end()); + ++i; + } + + // i now reached the end of at least one array + // in a second pass, traverse the remaining elements + + // remove my remaining elements + const auto end_index = static_cast(result.size()); + while (i < source.size()) + { + // add operations in reverse order to avoid invalid + // indices + result.insert(result.begin() + end_index, object( + { + {"op", "remove"}, + {"path", path + "/" + std::to_string(i)} + })); + ++i; + } + + // add other remaining elements + while (i < target.size()) + { + result.push_back( + { + {"op", "add"}, + {"path", path + "/" + std::to_string(i)}, + {"value", target[i]} + }); + ++i; + } + + break; + } + + case value_t::object: + { + // first pass: traverse this object's elements + for (auto it = source.cbegin(); it != source.cend(); ++it) + { + // escape the key name to be used in a JSON patch + const auto key = json_pointer::escape(it.key()); + + if (target.find(it.key()) != target.end()) + { + // recursive call to compare object values at key it + auto temp_diff = diff(it.value(), target[it.key()], path + "/" + key); + result.insert(result.end(), temp_diff.begin(), temp_diff.end()); + } + else + { + // found a key that is not in o -> remove it + result.push_back(object( + { + {"op", "remove"}, {"path", path + "/" + key} + })); + } + } + + // second pass: traverse other object's elements + for (auto it = target.cbegin(); it != target.cend(); ++it) + { + if (source.find(it.key()) == source.end()) + { + // found a key that is not in this -> add it + const auto key = json_pointer::escape(it.key()); + result.push_back( + { + {"op", "add"}, {"path", path + "/" + key}, + {"value", it.value()} + }); + } + } + + break; + } + + default: + { + // both primitive type: replace value + result.push_back( + { + {"op", "replace"}, {"path", path}, {"value", target} + }); + break; + } + } + } + + return result; + } + + /// @} +}; + +////////////////// +// json_pointer // +////////////////// + +NLOHMANN_BASIC_JSON_TPL_DECLARATION +NLOHMANN_BASIC_JSON_TPL& +json_pointer::get_and_create(NLOHMANN_BASIC_JSON_TPL& j) const +{ + using size_type = typename NLOHMANN_BASIC_JSON_TPL::size_type; + auto result = &j; + + // in case no reference tokens exist, return a reference to the JSON value + // j which will be overwritten by a primitive value + for (const auto& reference_token : reference_tokens) + { + switch (result->m_type) + { + case detail::value_t::null: + { + if (reference_token == "0") + { + // start a new array if reference token is 0 + result = &result->operator[](0); + } + else + { + // start a new object otherwise + result = &result->operator[](reference_token); + } + break; + } + + case detail::value_t::object: + { + // create an entry in the object + result = &result->operator[](reference_token); + break; + } + + case detail::value_t::array: + { + // create an entry in the array + JSON_TRY + { + result = &result->operator[](static_cast(array_index(reference_token))); + } + JSON_CATCH(std::invalid_argument&) + { + JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number")); + } + break; + } + + /* + The following code is only reached if there exists a reference + token _and_ the current value is primitive. In this case, we have + an error situation, because primitive values may only occur as + single value; that is, with an empty list of reference tokens. + */ + default: + JSON_THROW(detail::type_error::create(313, "invalid value to unflatten")); + } + } + + return *result; +} + +NLOHMANN_BASIC_JSON_TPL_DECLARATION +NLOHMANN_BASIC_JSON_TPL& +json_pointer::get_unchecked(NLOHMANN_BASIC_JSON_TPL* ptr) const +{ + using size_type = typename NLOHMANN_BASIC_JSON_TPL::size_type; + for (const auto& reference_token : reference_tokens) + { + // convert null values to arrays or objects before continuing + if (ptr->m_type == detail::value_t::null) + { + // check if reference token is a number + const bool nums = + std::all_of(reference_token.begin(), reference_token.end(), + [](const char x) + { + return (x >= '0' and x <= '9'); + }); + + // change value to array for numbers or "-" or to object otherwise + *ptr = (nums or reference_token == "-") + ? detail::value_t::array + : detail::value_t::object; + } + + switch (ptr->m_type) + { + case detail::value_t::object: + { + // use unchecked object access + ptr = &ptr->operator[](reference_token); + break; + } + + case detail::value_t::array: + { + // error condition (cf. RFC 6901, Sect. 4) + if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0')) + { + JSON_THROW(detail::parse_error::create(106, 0, + "array index '" + reference_token + + "' must not begin with '0'")); + } + + if (reference_token == "-") + { + // explicitly treat "-" as index beyond the end + ptr = &ptr->operator[](ptr->m_value.array->size()); + } + else + { + // convert array index to number; unchecked access + JSON_TRY + { + ptr = &ptr->operator[]( + static_cast(array_index(reference_token))); + } + JSON_CATCH(std::invalid_argument&) + { + JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number")); + } + } + break; + } + + default: + JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'")); + } + } + + return *ptr; +} + +NLOHMANN_BASIC_JSON_TPL_DECLARATION +NLOHMANN_BASIC_JSON_TPL& +json_pointer::get_checked(NLOHMANN_BASIC_JSON_TPL* ptr) const +{ + using size_type = typename NLOHMANN_BASIC_JSON_TPL::size_type; + for (const auto& reference_token : reference_tokens) + { + switch (ptr->m_type) + { + case detail::value_t::object: + { + // note: at performs range check + ptr = &ptr->at(reference_token); + break; + } + + case detail::value_t::array: + { + if (JSON_UNLIKELY(reference_token == "-")) + { + // "-" always fails the range check + JSON_THROW(detail::out_of_range::create(402, + "array index '-' (" + std::to_string(ptr->m_value.array->size()) + + ") is out of range")); + } + + // error condition (cf. RFC 6901, Sect. 4) + if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0')) + { + JSON_THROW(detail::parse_error::create(106, 0, + "array index '" + reference_token + + "' must not begin with '0'")); + } + + // note: at performs range check + JSON_TRY + { + ptr = &ptr->at(static_cast(array_index(reference_token))); + } + JSON_CATCH(std::invalid_argument&) + { + JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number")); + } + break; + } + + default: + JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'")); + } + } + + return *ptr; +} + +NLOHMANN_BASIC_JSON_TPL_DECLARATION +const NLOHMANN_BASIC_JSON_TPL& +json_pointer::get_unchecked(const NLOHMANN_BASIC_JSON_TPL* ptr) const +{ + using size_type = typename NLOHMANN_BASIC_JSON_TPL::size_type; + for (const auto& reference_token : reference_tokens) + { + switch (ptr->m_type) + { + case detail::value_t::object: + { + // use unchecked object access + ptr = &ptr->operator[](reference_token); + break; + } + + case detail::value_t::array: + { + if (JSON_UNLIKELY(reference_token == "-")) + { + // "-" cannot be used for const access + JSON_THROW(detail::out_of_range::create(402, + "array index '-' (" + std::to_string(ptr->m_value.array->size()) + + ") is out of range")); + } + + // error condition (cf. RFC 6901, Sect. 4) + if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0')) + { + JSON_THROW(detail::parse_error::create(106, 0, + "array index '" + reference_token + + "' must not begin with '0'")); + } + + // use unchecked array access + JSON_TRY + { + ptr = &ptr->operator[]( + static_cast(array_index(reference_token))); + } + JSON_CATCH(std::invalid_argument&) + { + JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number")); + } + break; + } + + default: + JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'")); + } + } + + return *ptr; +} + +NLOHMANN_BASIC_JSON_TPL_DECLARATION +const NLOHMANN_BASIC_JSON_TPL& +json_pointer::get_checked(const NLOHMANN_BASIC_JSON_TPL* ptr) const +{ + using size_type = typename NLOHMANN_BASIC_JSON_TPL::size_type; + for (const auto& reference_token : reference_tokens) + { + switch (ptr->m_type) + { + case detail::value_t::object: + { + // note: at performs range check + ptr = &ptr->at(reference_token); + break; + } + + case detail::value_t::array: + { + if (JSON_UNLIKELY(reference_token == "-")) + { + // "-" always fails the range check + JSON_THROW(detail::out_of_range::create(402, + "array index '-' (" + std::to_string(ptr->m_value.array->size()) + + ") is out of range")); + } + + // error condition (cf. RFC 6901, Sect. 4) + if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0')) + { + JSON_THROW(detail::parse_error::create(106, 0, + "array index '" + reference_token + + "' must not begin with '0'")); + } + + // note: at performs range check + JSON_TRY + { + ptr = &ptr->at(static_cast(array_index(reference_token))); + } + JSON_CATCH(std::invalid_argument&) + { + JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number")); + } + break; + } + + default: + JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'")); + } + } + + return *ptr; +} + +NLOHMANN_BASIC_JSON_TPL_DECLARATION +void json_pointer::flatten(const std::string& reference_string, + const NLOHMANN_BASIC_JSON_TPL& value, + NLOHMANN_BASIC_JSON_TPL& result) +{ + switch (value.m_type) + { + case detail::value_t::array: + { + if (value.m_value.array->empty()) + { + // flatten empty array as null + result[reference_string] = nullptr; + } + else + { + // iterate array and use index as reference string + for (std::size_t i = 0; i < value.m_value.array->size(); ++i) + { + flatten(reference_string + "/" + std::to_string(i), + value.m_value.array->operator[](i), result); + } + } + break; + } + + case detail::value_t::object: + { + if (value.m_value.object->empty()) + { + // flatten empty object as null + result[reference_string] = nullptr; + } + else + { + // iterate object and use keys as reference string + for (const auto& element : *value.m_value.object) + { + flatten(reference_string + "/" + escape(element.first), element.second, result); + } + } + break; + } + + default: + { + // add primitive value with its reference string + result[reference_string] = value; + break; + } + } +} + +NLOHMANN_BASIC_JSON_TPL_DECLARATION +NLOHMANN_BASIC_JSON_TPL +json_pointer::unflatten(const NLOHMANN_BASIC_JSON_TPL& value) +{ + if (JSON_UNLIKELY(not value.is_object())) + { + JSON_THROW(detail::type_error::create(314, "only objects can be unflattened")); + } + + NLOHMANN_BASIC_JSON_TPL result; + + // iterate the JSON object values + for (const auto& element : *value.m_value.object) + { + if (JSON_UNLIKELY(not element.second.is_primitive())) + { + JSON_THROW(detail::type_error::create(315, "values in object must be primitive")); + } + + // assign value to reference pointed to by JSON pointer; Note that if + // the JSON pointer is "" (i.e., points to the whole value), function + // get_and_create returns a reference to result itself. An assignment + // will then create a primitive value. + json_pointer(element.first).get_and_create(result) = element.second; + } + + return result; +} + +inline bool operator==(json_pointer const& lhs, json_pointer const& rhs) noexcept +{ + return (lhs.reference_tokens == rhs.reference_tokens); +} + +inline bool operator!=(json_pointer const& lhs, json_pointer const& rhs) noexcept +{ + return not (lhs == rhs); +} +} // namespace nlohmann + +/////////////////////// +// nonmember support // +/////////////////////// + +// specialization of std::swap, and std::hash +namespace std +{ +/*! +@brief exchanges the values of two JSON objects + +@since version 1.0.0 +*/ +template<> +inline void swap(nlohmann::json& j1, + nlohmann::json& j2) noexcept( + is_nothrow_move_constructible::value and + is_nothrow_move_assignable::value + ) +{ + j1.swap(j2); +} + +/// hash value for JSON objects +template<> +struct hash +{ + /*! + @brief return a hash value for a JSON object + + @since version 1.0.0 + */ + std::size_t operator()(const nlohmann::json& j) const + { + // a naive hashing via the string representation + const auto& h = hash(); + return h(j.dump()); + } +}; + +/// specialization for std::less +/// @note: do not remove the space after '<', +/// see https://github.com/nlohmann/json/pull/679 +template<> +struct less< ::nlohmann::detail::value_t> +{ + /*! + @brief compare two value_t enum values + @since version 3.0.0 + */ + bool operator()(nlohmann::detail::value_t lhs, + nlohmann::detail::value_t rhs) const noexcept + { + return nlohmann::detail::operator<(lhs, rhs); + } +}; + +} // namespace std + +/*! +@brief user-defined string literal for JSON values + +This operator implements a user-defined string literal for JSON objects. It +can be used by adding `"_json"` to a string literal and returns a JSON object +if no parse error occurred. + +@param[in] s a string representation of a JSON object +@param[in] n the length of string @a s +@return a JSON object + +@since version 1.0.0 +*/ +inline nlohmann::json operator "" _json(const char* s, std::size_t n) +{ + return nlohmann::json::parse(s, s + n); +} + +/*! +@brief user-defined string literal for JSON pointer + +This operator implements a user-defined string literal for JSON Pointers. It +can be used by adding `"_json_pointer"` to a string literal and returns a JSON pointer +object if no parse error occurred. + +@param[in] s a string representation of a JSON Pointer +@param[in] n the length of string @a s +@return a JSON pointer object + +@since version 2.0.0 +*/ +inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std::size_t n) +{ + return nlohmann::json::json_pointer(std::string(s, n)); +} + +#include "detail/macro_unscope.hpp" + +#endif diff --git a/src/json_fwd.hpp b/develop/json_fwd.hpp similarity index 100% rename from src/json_fwd.hpp rename to develop/json_fwd.hpp diff --git a/single_header/json.hpp b/single_header/json.hpp deleted file mode 100644 index e6fe5fc1..00000000 --- a/single_header/json.hpp +++ /dev/null @@ -1,19067 +0,0 @@ -/* - __ _____ _____ _____ - __| | __| | | | JSON for Modern C++ -| | |__ | | | | | | version 3.0.0 -|_____|_____|_____|_|___| https://github.com/nlohmann/json - -Licensed under the MIT License . -Copyright (c) 2013-2017 Niels Lohmann . - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -#ifndef NLOHMANN_JSON_HPP -#define NLOHMANN_JSON_HPP - -#include // all_of, find, for_each -#include // assert -#include // and, not, or -#include // nullptr_t, ptrdiff_t, size_t -#include // hash, less -#include // initializer_list -#include // istream, ostream -#include // iterator_traits, random_access_iterator_tag -#include // accumulate -#include // string, stoi, to_string -#include // declval, forward, move, pair, swap - - -/*** Start of inlined file: json_fwd.hpp ***/ -#ifndef NLOHMANN_JSON_FWD_HPP -#define NLOHMANN_JSON_FWD_HPP - -#include // int64_t, uint64_t -#include // map -#include // allocator -#include // string -#include // vector - -/*! -@brief namespace for Niels Lohmann -@see https://github.com/nlohmann -@since version 1.0.0 -*/ -namespace nlohmann -{ -/*! -@brief default JSONSerializer template argument - -This serializer ignores the template arguments and uses ADL -([argument-dependent lookup](http://en.cppreference.com/w/cpp/language/adl)) -for serialization. -*/ -template -struct adl_serializer; - -template class ObjectType = - std::map, - template class ArrayType = std::vector, - class StringType = std::string, class BooleanType = bool, - class NumberIntegerType = std::int64_t, - class NumberUnsignedType = std::uint64_t, - class NumberFloatType = double, - template class AllocatorType = std::allocator, - template class JSONSerializer = - adl_serializer> -class basic_json; - -/*! -@brief JSON Pointer - -A JSON pointer defines a string syntax for identifying a specific value -within a JSON document. It can be used with functions `at` and -`operator[]`. Furthermore, JSON pointers are the base for JSON patches. - -@sa [RFC 6901](https://tools.ietf.org/html/rfc6901) - -@since version 2.0.0 -*/ -class json_pointer; - -/*! -@brief default JSON class - -This type is the default specialization of the @ref basic_json class which -uses the standard template types. - -@since version 1.0.0 -*/ -using json = basic_json<>; -} - -#endif - -/*** End of inlined file: json_fwd.hpp ***/ - - -/*** Start of inlined file: macro_scope.hpp ***/ -#ifndef NLOHMANN_JSON_MACRO_SCOPE_HPP -#define NLOHMANN_JSON_MACRO_SCOPE_HPP - -#include // not - -// This file contains all internal macro definitions -// You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them - -// exclude unsupported compilers -#if defined(__clang__) - #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400 - #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" - #endif -#elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER)) - #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40900 - #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" - #endif -#endif - -// disable float-equal warnings on GCC/clang -#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wfloat-equal" -#endif - -// disable documentation warnings on clang -#if defined(__clang__) - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wdocumentation" -#endif - -// allow for portable deprecation warnings -#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) - #define JSON_DEPRECATED __attribute__((deprecated)) -#elif defined(_MSC_VER) - #define JSON_DEPRECATED __declspec(deprecated) -#else - #define JSON_DEPRECATED -#endif - -// allow to disable exceptions -#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && not defined(JSON_NOEXCEPTION) - #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 - -// manual branch prediction -#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) - #define JSON_LIKELY(x) __builtin_expect(!!(x), 1) - #define JSON_UNLIKELY(x) __builtin_expect(!!(x), 0) -#else - #define JSON_LIKELY(x) x - #define JSON_UNLIKELY(x) x -#endif - -// C++ language standard detection -#if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 - #define JSON_HAS_CPP_17 - #define JSON_HAS_CPP_14 -#elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) - #define JSON_HAS_CPP_14 -#endif - -// Ugly macros to avoid uglier copy-paste when specializing basic_json. They -// may be removed in the future once the class is split. - -#define NLOHMANN_BASIC_JSON_TPL_DECLARATION \ - template class ObjectType, \ - template class ArrayType, \ - class StringType, class BooleanType, class NumberIntegerType, \ - class NumberUnsignedType, class NumberFloatType, \ - template class AllocatorType, \ - template class JSONSerializer> - -#define NLOHMANN_BASIC_JSON_TPL \ - basic_json - -/*! -@brief Helper to determine whether there's a key_type for T. - -This helper is used to tell associative containers apart from other containers -such as sequence containers. For instance, `std::map` passes the test as it -contains a `mapped_type`, whereas `std::vector` fails the test. - -@sa http://stackoverflow.com/a/7728728/266378 -@since version 1.0.0, overworked in version 2.0.6 -*/ -#define NLOHMANN_JSON_HAS_HELPER(type) \ - template struct has_##type { \ - private: \ - template \ - static int detect(U &&); \ - static void detect(...); \ - public: \ - static constexpr bool value = \ - std::is_integral()))>::value; \ - } - -#endif - -/*** End of inlined file: macro_scope.hpp ***/ - - -/*** Start of inlined file: meta.hpp ***/ -#ifndef NLOHMANN_JSON_DETAIL_META_HPP -#define NLOHMANN_JSON_DETAIL_META_HPP - -#include // not -#include // size_t -#include // numeric_limits -#include // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type -#include // declval - - -/*** Start of inlined file: json_fwd.hpp ***/ -#ifndef NLOHMANN_JSON_FWD_HPP -#define NLOHMANN_JSON_FWD_HPP - -#include // int64_t, uint64_t -#include // map -#include // allocator -#include // string -#include // vector - -/*! -@brief namespace for Niels Lohmann -@see https://github.com/nlohmann -@since version 1.0.0 -*/ -namespace nlohmann -{ -/*! -@brief default JSONSerializer template argument - -This serializer ignores the template arguments and uses ADL -([argument-dependent lookup](http://en.cppreference.com/w/cpp/language/adl)) -for serialization. -*/ -template -struct adl_serializer; - -template class ObjectType = - std::map, - template class ArrayType = std::vector, - class StringType = std::string, class BooleanType = bool, - class NumberIntegerType = std::int64_t, - class NumberUnsignedType = std::uint64_t, - class NumberFloatType = double, - template class AllocatorType = std::allocator, - template class JSONSerializer = - adl_serializer> -class basic_json; - -/*! -@brief JSON Pointer - -A JSON pointer defines a string syntax for identifying a specific value -within a JSON document. It can be used with functions `at` and -`operator[]`. Furthermore, JSON pointers are the base for JSON patches. - -@sa [RFC 6901](https://tools.ietf.org/html/rfc6901) - -@since version 2.0.0 -*/ -class json_pointer; - -/*! -@brief default JSON class - -This type is the default specialization of the @ref basic_json class which -uses the standard template types. - -@since version 1.0.0 -*/ -using json = basic_json<>; -} - -#endif - -/*** End of inlined file: json_fwd.hpp ***/ - - -/*** Start of inlined file: macro_scope.hpp ***/ -#ifndef NLOHMANN_JSON_MACRO_SCOPE_HPP -#define NLOHMANN_JSON_MACRO_SCOPE_HPP - -#include // not - -// This file contains all internal macro definitions -// You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them - -// exclude unsupported compilers -#if defined(__clang__) - #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400 - #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" - #endif -#elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER)) - #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40900 - #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" - #endif -#endif - -// disable float-equal warnings on GCC/clang -#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wfloat-equal" -#endif - -// disable documentation warnings on clang -#if defined(__clang__) - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wdocumentation" -#endif - -// allow for portable deprecation warnings -#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) - #define JSON_DEPRECATED __attribute__((deprecated)) -#elif defined(_MSC_VER) - #define JSON_DEPRECATED __declspec(deprecated) -#else - #define JSON_DEPRECATED -#endif - -// allow to disable exceptions -#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && not defined(JSON_NOEXCEPTION) - #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 - -// manual branch prediction -#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) - #define JSON_LIKELY(x) __builtin_expect(!!(x), 1) - #define JSON_UNLIKELY(x) __builtin_expect(!!(x), 0) -#else - #define JSON_LIKELY(x) x - #define JSON_UNLIKELY(x) x -#endif - -// C++ language standard detection -#if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 - #define JSON_HAS_CPP_17 - #define JSON_HAS_CPP_14 -#elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) - #define JSON_HAS_CPP_14 -#endif - -// Ugly macros to avoid uglier copy-paste when specializing basic_json. They -// may be removed in the future once the class is split. - -#define NLOHMANN_BASIC_JSON_TPL_DECLARATION \ - template class ObjectType, \ - template class ArrayType, \ - class StringType, class BooleanType, class NumberIntegerType, \ - class NumberUnsignedType, class NumberFloatType, \ - template class AllocatorType, \ - template class JSONSerializer> - -#define NLOHMANN_BASIC_JSON_TPL \ - basic_json - -/*! -@brief Helper to determine whether there's a key_type for T. - -This helper is used to tell associative containers apart from other containers -such as sequence containers. For instance, `std::map` passes the test as it -contains a `mapped_type`, whereas `std::vector` fails the test. - -@sa http://stackoverflow.com/a/7728728/266378 -@since version 1.0.0, overworked in version 2.0.6 -*/ -#define NLOHMANN_JSON_HAS_HELPER(type) \ - template struct has_##type { \ - private: \ - template \ - static int detect(U &&); \ - static void detect(...); \ - public: \ - static constexpr bool value = \ - std::is_integral()))>::value; \ - } - -#endif - -/*** End of inlined file: macro_scope.hpp ***/ - -namespace nlohmann -{ -/*! -@brief detail namespace with internal helper functions - -This namespace collects functions that should not be exposed, -implementations of some @ref basic_json methods, and meta-programming helpers. - -@since version 2.1.0 -*/ -namespace detail -{ -///////////// -// helpers // -///////////// - -template struct is_basic_json : std::false_type {}; - -NLOHMANN_BASIC_JSON_TPL_DECLARATION -struct is_basic_json : std::true_type {}; - -// alias templates to reduce boilerplate -template -using enable_if_t = typename std::enable_if::type; - -template -using uncvref_t = typename std::remove_cv::type>::type; - -// implementation of C++14 index_sequence and affiliates -// source: https://stackoverflow.com/a/32223343 -template -struct index_sequence -{ - using type = index_sequence; - using value_type = std::size_t; - static constexpr std::size_t size() noexcept - { - return sizeof...(Ints); - } -}; - -template -struct merge_and_renumber; - -template -struct merge_and_renumber, index_sequence> - : index_sequence < I1..., (sizeof...(I1) + I2)... > {}; - -template -struct make_index_sequence - : merge_and_renumber < typename make_index_sequence < N / 2 >::type, - typename make_index_sequence < N - N / 2 >::type > {}; - -template<> struct make_index_sequence<0> : index_sequence<> {}; -template<> struct make_index_sequence<1> : index_sequence<0> {}; - -template -using index_sequence_for = make_index_sequence; - -/* -Implementation of two C++17 constructs: conjunction, negation. This is needed -to avoid evaluating all the traits in a condition - -For example: not std::is_same::value and has_value_type::value -will not compile when T = void (on MSVC at least). Whereas -conjunction>, has_value_type>::value will -stop evaluating if negation<...>::value == false - -Please note that those constructs must be used with caution, since symbols can -become very long quickly (which can slow down compilation and cause MSVC -internal compiler errors). Only use it when you have to (see example ahead). -*/ -template struct conjunction : std::true_type {}; -template struct conjunction : B1 {}; -template -struct conjunction : std::conditional, B1>::type {}; - -template struct negation : std::integral_constant {}; - -// dispatch utility (taken from ranges-v3) -template struct priority_tag : priority_tag < N - 1 > {}; -template<> struct priority_tag<0> {}; - -//////////////////////// -// has_/is_ functions // -//////////////////////// - -NLOHMANN_JSON_HAS_HELPER(mapped_type); -NLOHMANN_JSON_HAS_HELPER(key_type); -NLOHMANN_JSON_HAS_HELPER(value_type); -NLOHMANN_JSON_HAS_HELPER(iterator); - -template -struct is_compatible_object_type_impl : std::false_type {}; - -template -struct is_compatible_object_type_impl -{ - static constexpr auto value = - std::is_constructible::value and - std::is_constructible::value; -}; - -template -struct is_compatible_object_type -{ - static auto constexpr value = is_compatible_object_type_impl < - conjunction>, - has_mapped_type, - has_key_type>::value, - typename BasicJsonType::object_t, CompatibleObjectType >::value; -}; - -template -struct is_basic_json_nested_type -{ - static auto constexpr value = std::is_same::value or - std::is_same::value or - std::is_same::value or - std::is_same::value; -}; - -template -struct is_compatible_array_type -{ - static auto constexpr value = - conjunction>, - negation>, - negation>, - negation>, - has_value_type, - has_iterator>::value; -}; - -template -struct is_compatible_integer_type_impl : std::false_type {}; - -template -struct is_compatible_integer_type_impl -{ - // is there an assert somewhere on overflows? - using RealLimits = std::numeric_limits; - using CompatibleLimits = std::numeric_limits; - - static constexpr auto value = - std::is_constructible::value and - CompatibleLimits::is_integer and - RealLimits::is_signed == CompatibleLimits::is_signed; -}; - -template -struct is_compatible_integer_type -{ - static constexpr auto value = - is_compatible_integer_type_impl < - std::is_integral::value and - not std::is_same::value, - RealIntegerType, CompatibleNumberIntegerType > ::value; -}; - -// trait checking if JSONSerializer::from_json(json const&, udt&) exists -template -struct has_from_json -{ - private: - // also check the return type of from_json - template::from_json( - std::declval(), std::declval()))>::value>> - static int detect(U&&); - static void detect(...); - - public: - static constexpr bool value = std::is_integral>()))>::value; -}; - -// This trait checks if JSONSerializer::from_json(json const&) exists -// this overload is used for non-default-constructible user-defined-types -template -struct has_non_default_from_json -{ - private: - template < - typename U, - typename = enable_if_t::from_json(std::declval()))>::value >> - static int detect(U&&); - static void detect(...); - - public: - static constexpr bool value = std::is_integral>()))>::value; -}; - -// This trait checks if BasicJsonType::json_serializer::to_json exists -template -struct has_to_json -{ - private: - template::to_json( - std::declval(), std::declval()))> - static int detect(U&&); - static void detect(...); - - public: - static constexpr bool value = std::is_integral>()))>::value; -}; - -// taken from ranges-v3 -template -struct static_const -{ - static constexpr T value{}; -}; - -template -constexpr T static_const::value; -} -} - -#endif - -/*** End of inlined file: meta.hpp ***/ - - -/*** Start of inlined file: exceptions.hpp ***/ -#ifndef NLOHMANN_JSON_DETAIL_EXCEPTIONS_HPP -#define NLOHMANN_JSON_DETAIL_EXCEPTIONS_HPP - -#include // exception -#include // runtime_error -#include // to_string - -namespace nlohmann -{ -namespace detail -{ -//////////////// -// exceptions // -//////////////// - -/*! -@brief general exception of the @ref basic_json class - -This class is an extension of `std::exception` objects with a member @a id for -exception ids. It is used as the base class for all exceptions thrown by the -@ref basic_json class. This class can hence be used as "wildcard" to catch -exceptions. - -Subclasses: -- @ref parse_error for exceptions indicating a parse error -- @ref invalid_iterator for exceptions indicating errors with iterators -- @ref type_error for exceptions indicating executing a member function with - a wrong type -- @ref out_of_range for exceptions indicating access out of the defined range -- @ref other_error for exceptions indicating other library errors - -@internal -@note To have nothrow-copy-constructible exceptions, we internally use - `std::runtime_error` which can cope with arbitrary-length error messages. - Intermediate strings are built with static functions and then passed to - the actual constructor. -@endinternal - -@liveexample{The following code shows how arbitrary library exceptions can be -caught.,exception} - -@since version 3.0.0 -*/ -class exception : public std::exception -{ - public: - /// returns the explanatory string - const char* what() const noexcept override - { - return m.what(); - } - - /// the id of the exception - const int id; - - protected: - exception(int id_, const char* what_arg) : id(id_), m(what_arg) {} - - static std::string name(const std::string& ename, int id_) - { - return "[json.exception." + ename + "." + std::to_string(id_) + "] "; - } - - private: - /// an exception object as storage for error messages - std::runtime_error m; -}; - -/*! -@brief exception indicating a parse error - -This exception is thrown by the library when a parse error occurs. Parse errors -can occur during the deserialization of JSON text, CBOR, MessagePack, as well -as when using JSON Patch. - -Member @a byte holds the byte index of the last read character in the input -file. - -Exceptions have ids 1xx. - -name / id | example message | description ------------------------------- | --------------- | ------------------------- -json.exception.parse_error.101 | parse error at 2: unexpected end of input; expected string literal | This error indicates a syntax error while deserializing a JSON text. The error message describes that an unexpected token (character) was encountered, and the member @a byte indicates the error position. -json.exception.parse_error.102 | parse error at 14: missing or wrong low surrogate | JSON uses the `\uxxxx` format to describe Unicode characters. Code points above above 0xFFFF are split into two `\uxxxx` entries ("surrogate pairs"). This error indicates that the surrogate pair is incomplete or contains an invalid code point. -json.exception.parse_error.103 | parse error: code points above 0x10FFFF are invalid | Unicode supports code points up to 0x10FFFF. Code points above 0x10FFFF are invalid. -json.exception.parse_error.104 | parse error: JSON patch must be an array of objects | [RFC 6902](https://tools.ietf.org/html/rfc6902) requires a JSON Patch document to be a JSON document that represents an array of objects. -json.exception.parse_error.105 | parse error: operation must have string member 'op' | An operation of a JSON Patch document must contain exactly one "op" member, whose value indicates the operation to perform. Its value must be one of "add", "remove", "replace", "move", "copy", or "test"; other values are errors. -json.exception.parse_error.106 | parse error: array index '01' must not begin with '0' | An array index in a JSON Pointer ([RFC 6901](https://tools.ietf.org/html/rfc6901)) may be `0` or any number without a leading `0`. -json.exception.parse_error.107 | parse error: JSON pointer must be empty or begin with '/' - was: 'foo' | A JSON Pointer must be a Unicode string containing a sequence of zero or more reference tokens, each prefixed by a `/` character. -json.exception.parse_error.108 | parse error: escape character '~' must be followed with '0' or '1' | In a JSON Pointer, only `~0` and `~1` are valid escape sequences. -json.exception.parse_error.109 | parse error: array index 'one' is not a number | A JSON Pointer array index must be a number. -json.exception.parse_error.110 | parse error at 1: cannot read 2 bytes from vector | When parsing CBOR or MessagePack, the byte vector ends before the complete value has been read. -json.exception.parse_error.112 | parse error at 1: error reading CBOR; last byte: 0xF8 | Not all types of CBOR or MessagePack are supported. This exception occurs if an unsupported byte was read. -json.exception.parse_error.113 | parse error at 2: expected a CBOR string; last byte: 0x98 | While parsing a map key, a value that is not a string has been read. - -@note For an input with n bytes, 1 is the index of the first character and n+1 - is the index of the terminating null byte or the end of file. This also - holds true when reading a byte vector (CBOR or MessagePack). - -@liveexample{The following code shows how a `parse_error` exception can be -caught.,parse_error} - -@sa @ref exception for the base class of the library exceptions -@sa @ref invalid_iterator for exceptions indicating errors with iterators -@sa @ref type_error for exceptions indicating executing a member function with - a wrong type -@sa @ref out_of_range for exceptions indicating access out of the defined range -@sa @ref other_error for exceptions indicating other library errors - -@since version 3.0.0 -*/ -class parse_error : public exception -{ - public: - /*! - @brief create a parse error exception - @param[in] id_ the id of the exception - @param[in] byte_ the byte index where the error occurred (or 0 if the - position cannot be determined) - @param[in] what_arg the explanatory string - @return parse_error object - */ - static parse_error create(int id_, std::size_t byte_, const std::string& what_arg) - { - std::string w = exception::name("parse_error", id_) + "parse error" + - (byte_ != 0 ? (" at " + std::to_string(byte_)) : "") + - ": " + what_arg; - return parse_error(id_, byte_, w.c_str()); - } - - /*! - @brief byte index of the parse error - - The byte index of the last read character in the input file. - - @note For an input with n bytes, 1 is the index of the first character and - n+1 is the index of the terminating null byte or the end of file. - This also holds true when reading a byte vector (CBOR or MessagePack). - */ - const std::size_t byte; - - private: - parse_error(int id_, std::size_t byte_, const char* what_arg) - : exception(id_, what_arg), byte(byte_) {} -}; - -/*! -@brief exception indicating errors with iterators - -This exception is thrown if iterators passed to a library function do not match -the expected semantics. - -Exceptions have ids 2xx. - -name / id | example message | description ------------------------------------ | --------------- | ------------------------- -json.exception.invalid_iterator.201 | iterators are not compatible | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. -json.exception.invalid_iterator.202 | iterator does not fit current value | In an erase or insert function, the passed iterator @a pos does not belong to the JSON value for which the function was called. It hence does not define a valid position for the deletion/insertion. -json.exception.invalid_iterator.203 | iterators do not fit current value | Either iterator passed to function @ref erase(IteratorType first, IteratorType last) does not belong to the JSON value from which values shall be erased. It hence does not define a valid range to delete values from. -json.exception.invalid_iterator.204 | iterators out of range | When an iterator range for a primitive type (number, boolean, or string) is passed to a constructor or an erase function, this range has to be exactly (@ref begin(), @ref end()), because this is the only way the single stored value is expressed. All other ranges are invalid. -json.exception.invalid_iterator.205 | iterator out of range | When an iterator for a primitive type (number, boolean, or string) is passed to an erase function, the iterator has to be the @ref begin() iterator, because it is the only way to address the stored value. All other iterators are invalid. -json.exception.invalid_iterator.206 | cannot construct with iterators from null | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) belong to a JSON null value and hence to not define a valid range. -json.exception.invalid_iterator.207 | cannot use key() for non-object iterators | The key() member function can only be used on iterators belonging to a JSON object, because other types do not have a concept of a key. -json.exception.invalid_iterator.208 | cannot use operator[] for object iterators | The operator[] to specify a concrete offset cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. -json.exception.invalid_iterator.209 | cannot use offsets with object iterators | The offset operators (+, -, +=, -=) cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. -json.exception.invalid_iterator.210 | iterators do not fit | The iterator range passed to the insert function are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. -json.exception.invalid_iterator.211 | passed iterators may not belong to container | The iterator range passed to the insert function must not be a subrange of the container to insert to. -json.exception.invalid_iterator.212 | cannot compare iterators of different containers | When two iterators are compared, they must belong to the same container. -json.exception.invalid_iterator.213 | cannot compare order of object iterators | The order of object iterators cannot be compared, because JSON objects are unordered. -json.exception.invalid_iterator.214 | cannot get value | Cannot get value for iterator: Either the iterator belongs to a null value or it is an iterator to a primitive type (number, boolean, or string), but the iterator is different to @ref begin(). - -@liveexample{The following code shows how an `invalid_iterator` exception can be -caught.,invalid_iterator} - -@sa @ref exception for the base class of the library exceptions -@sa @ref parse_error for exceptions indicating a parse error -@sa @ref type_error for exceptions indicating executing a member function with - a wrong type -@sa @ref out_of_range for exceptions indicating access out of the defined range -@sa @ref other_error for exceptions indicating other library errors - -@since version 3.0.0 -*/ -class invalid_iterator : public exception -{ - public: - static invalid_iterator create(int id_, const std::string& what_arg) - { - std::string w = exception::name("invalid_iterator", id_) + what_arg; - return invalid_iterator(id_, w.c_str()); - } - - private: - invalid_iterator(int id_, const char* what_arg) - : exception(id_, what_arg) {} -}; - -/*! -@brief exception indicating executing a member function with a wrong type - -This exception is thrown in case of a type error; that is, a library function is -executed on a JSON value whose type does not match the expected semantics. - -Exceptions have ids 3xx. - -name / id | example message | description ------------------------------ | --------------- | ------------------------- -json.exception.type_error.301 | cannot create object from initializer list | To create an object from an initializer list, the initializer list must consist only of a list of pairs whose first element is a string. When this constraint is violated, an array is created instead. -json.exception.type_error.302 | type must be object, but is array | During implicit or explicit value conversion, the JSON type must be compatible to the target type. For instance, a JSON string can only be converted into string types, but not into numbers or boolean types. -json.exception.type_error.303 | incompatible ReferenceType for get_ref, actual type is object | To retrieve a reference to a value stored in a @ref basic_json object with @ref get_ref, the type of the reference must match the value type. For instance, for a JSON array, the @a ReferenceType must be @ref array_t&. -json.exception.type_error.304 | cannot use at() with string | The @ref at() member functions can only be executed for certain JSON types. -json.exception.type_error.305 | cannot use operator[] with string | The @ref operator[] member functions can only be executed for certain JSON types. -json.exception.type_error.306 | cannot use value() with string | The @ref value() member functions can only be executed for certain JSON types. -json.exception.type_error.307 | cannot use erase() with string | The @ref erase() member functions can only be executed for certain JSON types. -json.exception.type_error.308 | cannot use push_back() with string | The @ref push_back() and @ref operator+= member functions can only be executed for certain JSON types. -json.exception.type_error.309 | cannot use insert() with | The @ref insert() member functions can only be executed for certain JSON types. -json.exception.type_error.310 | cannot use swap() with number | The @ref swap() member functions can only be executed for certain JSON types. -json.exception.type_error.311 | cannot use emplace_back() with string | The @ref emplace_back() member function can only be executed for certain JSON types. -json.exception.type_error.312 | cannot use update() with string | The @ref update() member functions can only be executed for certain JSON types. -json.exception.type_error.313 | invalid value to unflatten | The @ref unflatten function converts an object whose keys are JSON Pointers back into an arbitrary nested JSON value. The JSON Pointers must not overlap, because then the resulting value would not be well defined. -json.exception.type_error.314 | only objects can be unflattened | The @ref unflatten function only works for an object whose keys are JSON Pointers. -json.exception.type_error.315 | values in object must be primitive | The @ref unflatten function only works for an object whose keys are JSON Pointers and whose values are primitive. -json.exception.type_error.316 | invalid UTF-8 byte at index 10: 0x7E | The @ref dump function only works with UTF-8 encoded strings; that is, if you assign a `std::string` to a JSON value, make sure it is UTF-8 encoded. | - -@liveexample{The following code shows how a `type_error` exception can be -caught.,type_error} - -@sa @ref exception for the base class of the library exceptions -@sa @ref parse_error for exceptions indicating a parse error -@sa @ref invalid_iterator for exceptions indicating errors with iterators -@sa @ref out_of_range for exceptions indicating access out of the defined range -@sa @ref other_error for exceptions indicating other library errors - -@since version 3.0.0 -*/ -class type_error : public exception -{ - public: - static type_error create(int id_, const std::string& what_arg) - { - std::string w = exception::name("type_error", id_) + what_arg; - return type_error(id_, w.c_str()); - } - - private: - type_error(int id_, const char* what_arg) : exception(id_, what_arg) {} -}; - -/*! -@brief exception indicating access out of the defined range - -This exception is thrown in case a library function is called on an input -parameter that exceeds the expected range, for instance in case of array -indices or nonexisting object keys. - -Exceptions have ids 4xx. - -name / id | example message | description -------------------------------- | --------------- | ------------------------- -json.exception.out_of_range.401 | array index 3 is out of range | The provided array index @a i is larger than @a size-1. -json.exception.out_of_range.402 | array index '-' (3) is out of range | The special array index `-` in a JSON Pointer never describes a valid element of the array, but the index past the end. That is, it can only be used to add elements at this position, but not to read it. -json.exception.out_of_range.403 | key 'foo' not found | The provided key was not found in the JSON object. -json.exception.out_of_range.404 | unresolved reference token 'foo' | A reference token in a JSON Pointer could not be resolved. -json.exception.out_of_range.405 | JSON pointer has no parent | The JSON Patch operations 'remove' and 'add' can not be applied to the root element of the JSON value. -json.exception.out_of_range.406 | number overflow parsing '10E1000' | A parsed number could not be stored as without changing it to NaN or INF. - -@liveexample{The following code shows how an `out_of_range` exception can be -caught.,out_of_range} - -@sa @ref exception for the base class of the library exceptions -@sa @ref parse_error for exceptions indicating a parse error -@sa @ref invalid_iterator for exceptions indicating errors with iterators -@sa @ref type_error for exceptions indicating executing a member function with - a wrong type -@sa @ref other_error for exceptions indicating other library errors - -@since version 3.0.0 -*/ -class out_of_range : public exception -{ - public: - static out_of_range create(int id_, const std::string& what_arg) - { - std::string w = exception::name("out_of_range", id_) + what_arg; - return out_of_range(id_, w.c_str()); - } - - private: - out_of_range(int id_, const char* what_arg) : exception(id_, what_arg) {} -}; - -/*! -@brief exception indicating other library errors - -This exception is thrown in case of errors that cannot be classified with the -other exception types. - -Exceptions have ids 5xx. - -name / id | example message | description ------------------------------- | --------------- | ------------------------- -json.exception.other_error.501 | unsuccessful: {"op":"test","path":"/baz", "value":"bar"} | A JSON Patch operation 'test' failed. The unsuccessful operation is also printed. - -@sa @ref exception for the base class of the library exceptions -@sa @ref parse_error for exceptions indicating a parse error -@sa @ref invalid_iterator for exceptions indicating errors with iterators -@sa @ref type_error for exceptions indicating executing a member function with - a wrong type -@sa @ref out_of_range for exceptions indicating access out of the defined range - -@liveexample{The following code shows how an `other_error` exception can be -caught.,other_error} - -@since version 3.0.0 -*/ -class other_error : public exception -{ - public: - static other_error create(int id_, const std::string& what_arg) - { - std::string w = exception::name("other_error", id_) + what_arg; - return other_error(id_, w.c_str()); - } - - private: - other_error(int id_, const char* what_arg) : exception(id_, what_arg) {} -}; -} -} - -#endif - -/*** End of inlined file: exceptions.hpp ***/ - - -/*** Start of inlined file: value_t.hpp ***/ -#ifndef NLOHMANN_JSON_DETAIL_VALUE_T_HPP -#define NLOHMANN_JSON_DETAIL_VALUE_T_HPP - -#include // array -#include // and -#include // size_t -#include // uint8_t - -namespace nlohmann -{ -namespace detail -{ -/////////////////////////// -// JSON type enumeration // -/////////////////////////// - -/*! -@brief the JSON type enumeration - -This enumeration collects the different JSON types. It is internally used to -distinguish the stored values, and the functions @ref basic_json::is_null(), -@ref basic_json::is_object(), @ref basic_json::is_array(), -@ref basic_json::is_string(), @ref basic_json::is_boolean(), -@ref basic_json::is_number() (with @ref basic_json::is_number_integer(), -@ref basic_json::is_number_unsigned(), and @ref basic_json::is_number_float()), -@ref basic_json::is_discarded(), @ref basic_json::is_primitive(), and -@ref basic_json::is_structured() rely on it. - -@note There are three enumeration entries (number_integer, number_unsigned, and -number_float), because the library distinguishes these three types for numbers: -@ref basic_json::number_unsigned_t is used for unsigned integers, -@ref basic_json::number_integer_t is used for signed integers, and -@ref basic_json::number_float_t is used for floating-point numbers or to -approximate integers which do not fit in the limits of their respective type. - -@sa @ref basic_json::basic_json(const value_t value_type) -- create a JSON -value with the default value for a given type - -@since version 1.0.0 -*/ -enum class value_t : std::uint8_t -{ - null, ///< null value - object, ///< object (unordered set of name/value pairs) - array, ///< array (ordered collection of values) - string, ///< string value - boolean, ///< boolean value - number_integer, ///< number value (signed integer) - number_unsigned, ///< number value (unsigned integer) - number_float, ///< number value (floating-point) - discarded ///< discarded by the the parser callback function -}; - -/*! -@brief comparison operator for JSON types - -Returns an ordering that is similar to Python: -- order: null < boolean < number < object < array < string -- furthermore, each type is not smaller than itself -- discarded values are not comparable - -@since version 1.0.0 -*/ -inline bool operator<(const value_t lhs, const value_t rhs) noexcept -{ - static constexpr std::array order = {{ - 0 /* null */, 3 /* object */, 4 /* array */, 5 /* string */, - 1 /* boolean */, 2 /* integer */, 2 /* unsigned */, 2 /* float */ - } - }; - - const auto l_index = static_cast(lhs); - const auto r_index = static_cast(rhs); - return l_index < order.size() and r_index < order.size() and order[l_index] < order[r_index]; -} -} -} - -#endif - -/*** End of inlined file: value_t.hpp ***/ - - -/*** Start of inlined file: from_json.hpp ***/ -#ifndef NLOHMANN_JSON_DETAIL_CONVERSIONS_FROM_JSON_HPP -#define NLOHMANN_JSON_DETAIL_CONVERSIONS_FROM_JSON_HPP - -#include // transform -#include // array -#include // and, not -#include // forward_list -#include // inserter, front_inserter, end -#include // string -#include // tuple, make_tuple -#include // is_arithmetic, is_same, is_enum, underlying_type, is_convertible -#include // pair, declval -#include // valarray - - -/*** Start of inlined file: exceptions.hpp ***/ -#ifndef NLOHMANN_JSON_DETAIL_EXCEPTIONS_HPP -#define NLOHMANN_JSON_DETAIL_EXCEPTIONS_HPP - -#include // exception -#include // runtime_error -#include // to_string - -namespace nlohmann -{ -namespace detail -{ -//////////////// -// exceptions // -//////////////// - -/*! -@brief general exception of the @ref basic_json class - -This class is an extension of `std::exception` objects with a member @a id for -exception ids. It is used as the base class for all exceptions thrown by the -@ref basic_json class. This class can hence be used as "wildcard" to catch -exceptions. - -Subclasses: -- @ref parse_error for exceptions indicating a parse error -- @ref invalid_iterator for exceptions indicating errors with iterators -- @ref type_error for exceptions indicating executing a member function with - a wrong type -- @ref out_of_range for exceptions indicating access out of the defined range -- @ref other_error for exceptions indicating other library errors - -@internal -@note To have nothrow-copy-constructible exceptions, we internally use - `std::runtime_error` which can cope with arbitrary-length error messages. - Intermediate strings are built with static functions and then passed to - the actual constructor. -@endinternal - -@liveexample{The following code shows how arbitrary library exceptions can be -caught.,exception} - -@since version 3.0.0 -*/ -class exception : public std::exception -{ - public: - /// returns the explanatory string - const char* what() const noexcept override - { - return m.what(); - } - - /// the id of the exception - const int id; - - protected: - exception(int id_, const char* what_arg) : id(id_), m(what_arg) {} - - static std::string name(const std::string& ename, int id_) - { - return "[json.exception." + ename + "." + std::to_string(id_) + "] "; - } - - private: - /// an exception object as storage for error messages - std::runtime_error m; -}; - -/*! -@brief exception indicating a parse error - -This exception is thrown by the library when a parse error occurs. Parse errors -can occur during the deserialization of JSON text, CBOR, MessagePack, as well -as when using JSON Patch. - -Member @a byte holds the byte index of the last read character in the input -file. - -Exceptions have ids 1xx. - -name / id | example message | description ------------------------------- | --------------- | ------------------------- -json.exception.parse_error.101 | parse error at 2: unexpected end of input; expected string literal | This error indicates a syntax error while deserializing a JSON text. The error message describes that an unexpected token (character) was encountered, and the member @a byte indicates the error position. -json.exception.parse_error.102 | parse error at 14: missing or wrong low surrogate | JSON uses the `\uxxxx` format to describe Unicode characters. Code points above above 0xFFFF are split into two `\uxxxx` entries ("surrogate pairs"). This error indicates that the surrogate pair is incomplete or contains an invalid code point. -json.exception.parse_error.103 | parse error: code points above 0x10FFFF are invalid | Unicode supports code points up to 0x10FFFF. Code points above 0x10FFFF are invalid. -json.exception.parse_error.104 | parse error: JSON patch must be an array of objects | [RFC 6902](https://tools.ietf.org/html/rfc6902) requires a JSON Patch document to be a JSON document that represents an array of objects. -json.exception.parse_error.105 | parse error: operation must have string member 'op' | An operation of a JSON Patch document must contain exactly one "op" member, whose value indicates the operation to perform. Its value must be one of "add", "remove", "replace", "move", "copy", or "test"; other values are errors. -json.exception.parse_error.106 | parse error: array index '01' must not begin with '0' | An array index in a JSON Pointer ([RFC 6901](https://tools.ietf.org/html/rfc6901)) may be `0` or any number without a leading `0`. -json.exception.parse_error.107 | parse error: JSON pointer must be empty or begin with '/' - was: 'foo' | A JSON Pointer must be a Unicode string containing a sequence of zero or more reference tokens, each prefixed by a `/` character. -json.exception.parse_error.108 | parse error: escape character '~' must be followed with '0' or '1' | In a JSON Pointer, only `~0` and `~1` are valid escape sequences. -json.exception.parse_error.109 | parse error: array index 'one' is not a number | A JSON Pointer array index must be a number. -json.exception.parse_error.110 | parse error at 1: cannot read 2 bytes from vector | When parsing CBOR or MessagePack, the byte vector ends before the complete value has been read. -json.exception.parse_error.112 | parse error at 1: error reading CBOR; last byte: 0xF8 | Not all types of CBOR or MessagePack are supported. This exception occurs if an unsupported byte was read. -json.exception.parse_error.113 | parse error at 2: expected a CBOR string; last byte: 0x98 | While parsing a map key, a value that is not a string has been read. - -@note For an input with n bytes, 1 is the index of the first character and n+1 - is the index of the terminating null byte or the end of file. This also - holds true when reading a byte vector (CBOR or MessagePack). - -@liveexample{The following code shows how a `parse_error` exception can be -caught.,parse_error} - -@sa @ref exception for the base class of the library exceptions -@sa @ref invalid_iterator for exceptions indicating errors with iterators -@sa @ref type_error for exceptions indicating executing a member function with - a wrong type -@sa @ref out_of_range for exceptions indicating access out of the defined range -@sa @ref other_error for exceptions indicating other library errors - -@since version 3.0.0 -*/ -class parse_error : public exception -{ - public: - /*! - @brief create a parse error exception - @param[in] id_ the id of the exception - @param[in] byte_ the byte index where the error occurred (or 0 if the - position cannot be determined) - @param[in] what_arg the explanatory string - @return parse_error object - */ - static parse_error create(int id_, std::size_t byte_, const std::string& what_arg) - { - std::string w = exception::name("parse_error", id_) + "parse error" + - (byte_ != 0 ? (" at " + std::to_string(byte_)) : "") + - ": " + what_arg; - return parse_error(id_, byte_, w.c_str()); - } - - /*! - @brief byte index of the parse error - - The byte index of the last read character in the input file. - - @note For an input with n bytes, 1 is the index of the first character and - n+1 is the index of the terminating null byte or the end of file. - This also holds true when reading a byte vector (CBOR or MessagePack). - */ - const std::size_t byte; - - private: - parse_error(int id_, std::size_t byte_, const char* what_arg) - : exception(id_, what_arg), byte(byte_) {} -}; - -/*! -@brief exception indicating errors with iterators - -This exception is thrown if iterators passed to a library function do not match -the expected semantics. - -Exceptions have ids 2xx. - -name / id | example message | description ------------------------------------ | --------------- | ------------------------- -json.exception.invalid_iterator.201 | iterators are not compatible | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. -json.exception.invalid_iterator.202 | iterator does not fit current value | In an erase or insert function, the passed iterator @a pos does not belong to the JSON value for which the function was called. It hence does not define a valid position for the deletion/insertion. -json.exception.invalid_iterator.203 | iterators do not fit current value | Either iterator passed to function @ref erase(IteratorType first, IteratorType last) does not belong to the JSON value from which values shall be erased. It hence does not define a valid range to delete values from. -json.exception.invalid_iterator.204 | iterators out of range | When an iterator range for a primitive type (number, boolean, or string) is passed to a constructor or an erase function, this range has to be exactly (@ref begin(), @ref end()), because this is the only way the single stored value is expressed. All other ranges are invalid. -json.exception.invalid_iterator.205 | iterator out of range | When an iterator for a primitive type (number, boolean, or string) is passed to an erase function, the iterator has to be the @ref begin() iterator, because it is the only way to address the stored value. All other iterators are invalid. -json.exception.invalid_iterator.206 | cannot construct with iterators from null | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) belong to a JSON null value and hence to not define a valid range. -json.exception.invalid_iterator.207 | cannot use key() for non-object iterators | The key() member function can only be used on iterators belonging to a JSON object, because other types do not have a concept of a key. -json.exception.invalid_iterator.208 | cannot use operator[] for object iterators | The operator[] to specify a concrete offset cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. -json.exception.invalid_iterator.209 | cannot use offsets with object iterators | The offset operators (+, -, +=, -=) cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. -json.exception.invalid_iterator.210 | iterators do not fit | The iterator range passed to the insert function are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. -json.exception.invalid_iterator.211 | passed iterators may not belong to container | The iterator range passed to the insert function must not be a subrange of the container to insert to. -json.exception.invalid_iterator.212 | cannot compare iterators of different containers | When two iterators are compared, they must belong to the same container. -json.exception.invalid_iterator.213 | cannot compare order of object iterators | The order of object iterators cannot be compared, because JSON objects are unordered. -json.exception.invalid_iterator.214 | cannot get value | Cannot get value for iterator: Either the iterator belongs to a null value or it is an iterator to a primitive type (number, boolean, or string), but the iterator is different to @ref begin(). - -@liveexample{The following code shows how an `invalid_iterator` exception can be -caught.,invalid_iterator} - -@sa @ref exception for the base class of the library exceptions -@sa @ref parse_error for exceptions indicating a parse error -@sa @ref type_error for exceptions indicating executing a member function with - a wrong type -@sa @ref out_of_range for exceptions indicating access out of the defined range -@sa @ref other_error for exceptions indicating other library errors - -@since version 3.0.0 -*/ -class invalid_iterator : public exception -{ - public: - static invalid_iterator create(int id_, const std::string& what_arg) - { - std::string w = exception::name("invalid_iterator", id_) + what_arg; - return invalid_iterator(id_, w.c_str()); - } - - private: - invalid_iterator(int id_, const char* what_arg) - : exception(id_, what_arg) {} -}; - -/*! -@brief exception indicating executing a member function with a wrong type - -This exception is thrown in case of a type error; that is, a library function is -executed on a JSON value whose type does not match the expected semantics. - -Exceptions have ids 3xx. - -name / id | example message | description ------------------------------ | --------------- | ------------------------- -json.exception.type_error.301 | cannot create object from initializer list | To create an object from an initializer list, the initializer list must consist only of a list of pairs whose first element is a string. When this constraint is violated, an array is created instead. -json.exception.type_error.302 | type must be object, but is array | During implicit or explicit value conversion, the JSON type must be compatible to the target type. For instance, a JSON string can only be converted into string types, but not into numbers or boolean types. -json.exception.type_error.303 | incompatible ReferenceType for get_ref, actual type is object | To retrieve a reference to a value stored in a @ref basic_json object with @ref get_ref, the type of the reference must match the value type. For instance, for a JSON array, the @a ReferenceType must be @ref array_t&. -json.exception.type_error.304 | cannot use at() with string | The @ref at() member functions can only be executed for certain JSON types. -json.exception.type_error.305 | cannot use operator[] with string | The @ref operator[] member functions can only be executed for certain JSON types. -json.exception.type_error.306 | cannot use value() with string | The @ref value() member functions can only be executed for certain JSON types. -json.exception.type_error.307 | cannot use erase() with string | The @ref erase() member functions can only be executed for certain JSON types. -json.exception.type_error.308 | cannot use push_back() with string | The @ref push_back() and @ref operator+= member functions can only be executed for certain JSON types. -json.exception.type_error.309 | cannot use insert() with | The @ref insert() member functions can only be executed for certain JSON types. -json.exception.type_error.310 | cannot use swap() with number | The @ref swap() member functions can only be executed for certain JSON types. -json.exception.type_error.311 | cannot use emplace_back() with string | The @ref emplace_back() member function can only be executed for certain JSON types. -json.exception.type_error.312 | cannot use update() with string | The @ref update() member functions can only be executed for certain JSON types. -json.exception.type_error.313 | invalid value to unflatten | The @ref unflatten function converts an object whose keys are JSON Pointers back into an arbitrary nested JSON value. The JSON Pointers must not overlap, because then the resulting value would not be well defined. -json.exception.type_error.314 | only objects can be unflattened | The @ref unflatten function only works for an object whose keys are JSON Pointers. -json.exception.type_error.315 | values in object must be primitive | The @ref unflatten function only works for an object whose keys are JSON Pointers and whose values are primitive. -json.exception.type_error.316 | invalid UTF-8 byte at index 10: 0x7E | The @ref dump function only works with UTF-8 encoded strings; that is, if you assign a `std::string` to a JSON value, make sure it is UTF-8 encoded. | - -@liveexample{The following code shows how a `type_error` exception can be -caught.,type_error} - -@sa @ref exception for the base class of the library exceptions -@sa @ref parse_error for exceptions indicating a parse error -@sa @ref invalid_iterator for exceptions indicating errors with iterators -@sa @ref out_of_range for exceptions indicating access out of the defined range -@sa @ref other_error for exceptions indicating other library errors - -@since version 3.0.0 -*/ -class type_error : public exception -{ - public: - static type_error create(int id_, const std::string& what_arg) - { - std::string w = exception::name("type_error", id_) + what_arg; - return type_error(id_, w.c_str()); - } - - private: - type_error(int id_, const char* what_arg) : exception(id_, what_arg) {} -}; - -/*! -@brief exception indicating access out of the defined range - -This exception is thrown in case a library function is called on an input -parameter that exceeds the expected range, for instance in case of array -indices or nonexisting object keys. - -Exceptions have ids 4xx. - -name / id | example message | description -------------------------------- | --------------- | ------------------------- -json.exception.out_of_range.401 | array index 3 is out of range | The provided array index @a i is larger than @a size-1. -json.exception.out_of_range.402 | array index '-' (3) is out of range | The special array index `-` in a JSON Pointer never describes a valid element of the array, but the index past the end. That is, it can only be used to add elements at this position, but not to read it. -json.exception.out_of_range.403 | key 'foo' not found | The provided key was not found in the JSON object. -json.exception.out_of_range.404 | unresolved reference token 'foo' | A reference token in a JSON Pointer could not be resolved. -json.exception.out_of_range.405 | JSON pointer has no parent | The JSON Patch operations 'remove' and 'add' can not be applied to the root element of the JSON value. -json.exception.out_of_range.406 | number overflow parsing '10E1000' | A parsed number could not be stored as without changing it to NaN or INF. - -@liveexample{The following code shows how an `out_of_range` exception can be -caught.,out_of_range} - -@sa @ref exception for the base class of the library exceptions -@sa @ref parse_error for exceptions indicating a parse error -@sa @ref invalid_iterator for exceptions indicating errors with iterators -@sa @ref type_error for exceptions indicating executing a member function with - a wrong type -@sa @ref other_error for exceptions indicating other library errors - -@since version 3.0.0 -*/ -class out_of_range : public exception -{ - public: - static out_of_range create(int id_, const std::string& what_arg) - { - std::string w = exception::name("out_of_range", id_) + what_arg; - return out_of_range(id_, w.c_str()); - } - - private: - out_of_range(int id_, const char* what_arg) : exception(id_, what_arg) {} -}; - -/*! -@brief exception indicating other library errors - -This exception is thrown in case of errors that cannot be classified with the -other exception types. - -Exceptions have ids 5xx. - -name / id | example message | description ------------------------------- | --------------- | ------------------------- -json.exception.other_error.501 | unsuccessful: {"op":"test","path":"/baz", "value":"bar"} | A JSON Patch operation 'test' failed. The unsuccessful operation is also printed. - -@sa @ref exception for the base class of the library exceptions -@sa @ref parse_error for exceptions indicating a parse error -@sa @ref invalid_iterator for exceptions indicating errors with iterators -@sa @ref type_error for exceptions indicating executing a member function with - a wrong type -@sa @ref out_of_range for exceptions indicating access out of the defined range - -@liveexample{The following code shows how an `other_error` exception can be -caught.,other_error} - -@since version 3.0.0 -*/ -class other_error : public exception -{ - public: - static other_error create(int id_, const std::string& what_arg) - { - std::string w = exception::name("other_error", id_) + what_arg; - return other_error(id_, w.c_str()); - } - - private: - other_error(int id_, const char* what_arg) : exception(id_, what_arg) {} -}; -} -} - -#endif - -/*** End of inlined file: exceptions.hpp ***/ - - -/*** Start of inlined file: meta.hpp ***/ -#ifndef NLOHMANN_JSON_DETAIL_META_HPP -#define NLOHMANN_JSON_DETAIL_META_HPP - -#include // not -#include // size_t -#include // numeric_limits -#include // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type -#include // declval - -namespace nlohmann -{ -/*! -@brief detail namespace with internal helper functions - -This namespace collects functions that should not be exposed, -implementations of some @ref basic_json methods, and meta-programming helpers. - -@since version 2.1.0 -*/ -namespace detail -{ -///////////// -// helpers // -///////////// - -template struct is_basic_json : std::false_type {}; - -NLOHMANN_BASIC_JSON_TPL_DECLARATION -struct is_basic_json : std::true_type {}; - -// alias templates to reduce boilerplate -template -using enable_if_t = typename std::enable_if::type; - -template -using uncvref_t = typename std::remove_cv::type>::type; - -// implementation of C++14 index_sequence and affiliates -// source: https://stackoverflow.com/a/32223343 -template -struct index_sequence -{ - using type = index_sequence; - using value_type = std::size_t; - static constexpr std::size_t size() noexcept - { - return sizeof...(Ints); - } -}; - -template -struct merge_and_renumber; - -template -struct merge_and_renumber, index_sequence> - : index_sequence < I1..., (sizeof...(I1) + I2)... > {}; - -template -struct make_index_sequence - : merge_and_renumber < typename make_index_sequence < N / 2 >::type, - typename make_index_sequence < N - N / 2 >::type > {}; - -template<> struct make_index_sequence<0> : index_sequence<> {}; -template<> struct make_index_sequence<1> : index_sequence<0> {}; - -template -using index_sequence_for = make_index_sequence; - -/* -Implementation of two C++17 constructs: conjunction, negation. This is needed -to avoid evaluating all the traits in a condition - -For example: not std::is_same::value and has_value_type::value -will not compile when T = void (on MSVC at least). Whereas -conjunction>, has_value_type>::value will -stop evaluating if negation<...>::value == false - -Please note that those constructs must be used with caution, since symbols can -become very long quickly (which can slow down compilation and cause MSVC -internal compiler errors). Only use it when you have to (see example ahead). -*/ -template struct conjunction : std::true_type {}; -template struct conjunction : B1 {}; -template -struct conjunction : std::conditional, B1>::type {}; - -template struct negation : std::integral_constant {}; - -// dispatch utility (taken from ranges-v3) -template struct priority_tag : priority_tag < N - 1 > {}; -template<> struct priority_tag<0> {}; - -//////////////////////// -// has_/is_ functions // -//////////////////////// - -NLOHMANN_JSON_HAS_HELPER(mapped_type); -NLOHMANN_JSON_HAS_HELPER(key_type); -NLOHMANN_JSON_HAS_HELPER(value_type); -NLOHMANN_JSON_HAS_HELPER(iterator); - -template -struct is_compatible_object_type_impl : std::false_type {}; - -template -struct is_compatible_object_type_impl -{ - static constexpr auto value = - std::is_constructible::value and - std::is_constructible::value; -}; - -template -struct is_compatible_object_type -{ - static auto constexpr value = is_compatible_object_type_impl < - conjunction>, - has_mapped_type, - has_key_type>::value, - typename BasicJsonType::object_t, CompatibleObjectType >::value; -}; - -template -struct is_basic_json_nested_type -{ - static auto constexpr value = std::is_same::value or - std::is_same::value or - std::is_same::value or - std::is_same::value; -}; - -template -struct is_compatible_array_type -{ - static auto constexpr value = - conjunction>, - negation>, - negation>, - negation>, - has_value_type, - has_iterator>::value; -}; - -template -struct is_compatible_integer_type_impl : std::false_type {}; - -template -struct is_compatible_integer_type_impl -{ - // is there an assert somewhere on overflows? - using RealLimits = std::numeric_limits; - using CompatibleLimits = std::numeric_limits; - - static constexpr auto value = - std::is_constructible::value and - CompatibleLimits::is_integer and - RealLimits::is_signed == CompatibleLimits::is_signed; -}; - -template -struct is_compatible_integer_type -{ - static constexpr auto value = - is_compatible_integer_type_impl < - std::is_integral::value and - not std::is_same::value, - RealIntegerType, CompatibleNumberIntegerType > ::value; -}; - -// trait checking if JSONSerializer::from_json(json const&, udt&) exists -template -struct has_from_json -{ - private: - // also check the return type of from_json - template::from_json( - std::declval(), std::declval()))>::value>> - static int detect(U&&); - static void detect(...); - - public: - static constexpr bool value = std::is_integral>()))>::value; -}; - -// This trait checks if JSONSerializer::from_json(json const&) exists -// this overload is used for non-default-constructible user-defined-types -template -struct has_non_default_from_json -{ - private: - template < - typename U, - typename = enable_if_t::from_json(std::declval()))>::value >> - static int detect(U&&); - static void detect(...); - - public: - static constexpr bool value = std::is_integral>()))>::value; -}; - -// This trait checks if BasicJsonType::json_serializer::to_json exists -template -struct has_to_json -{ - private: - template::to_json( - std::declval(), std::declval()))> - static int detect(U&&); - static void detect(...); - - public: - static constexpr bool value = std::is_integral>()))>::value; -}; - -// taken from ranges-v3 -template -struct static_const -{ - static constexpr T value{}; -}; - -template -constexpr T static_const::value; -} -} - -#endif - -/*** End of inlined file: meta.hpp ***/ - - -/*** Start of inlined file: value_t.hpp ***/ -#ifndef NLOHMANN_JSON_DETAIL_VALUE_T_HPP -#define NLOHMANN_JSON_DETAIL_VALUE_T_HPP - -#include // array -#include // and -#include // size_t -#include // uint8_t - -namespace nlohmann -{ -namespace detail -{ -/////////////////////////// -// JSON type enumeration // -/////////////////////////// - -/*! -@brief the JSON type enumeration - -This enumeration collects the different JSON types. It is internally used to -distinguish the stored values, and the functions @ref basic_json::is_null(), -@ref basic_json::is_object(), @ref basic_json::is_array(), -@ref basic_json::is_string(), @ref basic_json::is_boolean(), -@ref basic_json::is_number() (with @ref basic_json::is_number_integer(), -@ref basic_json::is_number_unsigned(), and @ref basic_json::is_number_float()), -@ref basic_json::is_discarded(), @ref basic_json::is_primitive(), and -@ref basic_json::is_structured() rely on it. - -@note There are three enumeration entries (number_integer, number_unsigned, and -number_float), because the library distinguishes these three types for numbers: -@ref basic_json::number_unsigned_t is used for unsigned integers, -@ref basic_json::number_integer_t is used for signed integers, and -@ref basic_json::number_float_t is used for floating-point numbers or to -approximate integers which do not fit in the limits of their respective type. - -@sa @ref basic_json::basic_json(const value_t value_type) -- create a JSON -value with the default value for a given type - -@since version 1.0.0 -*/ -enum class value_t : std::uint8_t -{ - null, ///< null value - object, ///< object (unordered set of name/value pairs) - array, ///< array (ordered collection of values) - string, ///< string value - boolean, ///< boolean value - number_integer, ///< number value (signed integer) - number_unsigned, ///< number value (unsigned integer) - number_float, ///< number value (floating-point) - discarded ///< discarded by the the parser callback function -}; - -/*! -@brief comparison operator for JSON types - -Returns an ordering that is similar to Python: -- order: null < boolean < number < object < array < string -- furthermore, each type is not smaller than itself -- discarded values are not comparable - -@since version 1.0.0 -*/ -inline bool operator<(const value_t lhs, const value_t rhs) noexcept -{ - static constexpr std::array order = {{ - 0 /* null */, 3 /* object */, 4 /* array */, 5 /* string */, - 1 /* boolean */, 2 /* integer */, 2 /* unsigned */, 2 /* float */ - } - }; - - const auto l_index = static_cast(lhs); - const auto r_index = static_cast(rhs); - return l_index < order.size() and r_index < order.size() and order[l_index] < order[r_index]; -} -} -} - -#endif - -/*** End of inlined file: value_t.hpp ***/ - -namespace nlohmann -{ -namespace detail -{ -// overloads for basic_json template parameters -template::value and - not std::is_same::value, - int> = 0> -void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val) -{ - switch (static_cast(j)) - { - case value_t::number_unsigned: - { - val = static_cast(*j.template get_ptr()); - break; - } - case value_t::number_integer: - { - val = static_cast(*j.template get_ptr()); - break; - } - case value_t::number_float: - { - val = static_cast(*j.template get_ptr()); - break; - } - - default: - JSON_THROW(type_error::create(302, "type must be number, but is " + std::string(j.type_name()))); - } -} - -template -void from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b) -{ - if (JSON_UNLIKELY(not j.is_boolean())) - { - JSON_THROW(type_error::create(302, "type must be boolean, but is " + std::string(j.type_name()))); - } - b = *j.template get_ptr(); -} - -template -void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s) -{ - if (JSON_UNLIKELY(not j.is_string())) - { - JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name()))); - } - s = *j.template get_ptr(); -} - -template -void from_json(const BasicJsonType& j, typename BasicJsonType::number_float_t& val) -{ - get_arithmetic_value(j, val); -} - -template -void from_json(const BasicJsonType& j, typename BasicJsonType::number_unsigned_t& val) -{ - get_arithmetic_value(j, val); -} - -template -void from_json(const BasicJsonType& j, typename BasicJsonType::number_integer_t& val) -{ - get_arithmetic_value(j, val); -} - -template::value, int> = 0> -void from_json(const BasicJsonType& j, EnumType& e) -{ - typename std::underlying_type::type val; - get_arithmetic_value(j, val); - e = static_cast(val); -} - -template -void from_json(const BasicJsonType& j, typename BasicJsonType::array_t& arr) -{ - if (JSON_UNLIKELY(not j.is_array())) - { - JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); - } - arr = *j.template get_ptr(); -} - -// forward_list doesn't have an insert method -template::value, int> = 0> -void from_json(const BasicJsonType& j, std::forward_list& l) -{ - if (JSON_UNLIKELY(not j.is_array())) - { - JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); - } - std::transform(j.rbegin(), j.rend(), - std::front_inserter(l), [](const BasicJsonType & i) - { - return i.template get(); - }); -} - -// valarray doesn't have an insert method -template::value, int> = 0> -void from_json(const BasicJsonType& j, std::valarray& l) -{ - if (JSON_UNLIKELY(not j.is_array())) - { - JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); - } - l.resize(j.size()); - std::copy(j.m_value.array->begin(), j.m_value.array->end(), std::begin(l)); -} - -template -void from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, priority_tag<0> /*unused*/) -{ - using std::end; - - std::transform(j.begin(), j.end(), - std::inserter(arr, end(arr)), [](const BasicJsonType & i) - { - // get() returns *this, this won't call a from_json - // method when value_type is BasicJsonType - return i.template get(); - }); -} - -template -auto from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, priority_tag<1> /*unused*/) --> decltype( - arr.reserve(std::declval()), - void()) -{ - using std::end; - - arr.reserve(j.size()); - std::transform(j.begin(), j.end(), - std::inserter(arr, end(arr)), [](const BasicJsonType & i) - { - // get() returns *this, this won't call a from_json - // method when value_type is BasicJsonType - return i.template get(); - }); -} - -template -void from_json_array_impl(const BasicJsonType& j, std::array& arr, priority_tag<2> /*unused*/) -{ - for (std::size_t i = 0; i < N; ++i) - { - arr[i] = j.at(i).template get(); - } -} - -template::value and - std::is_convertible::value and - not std::is_same::value, int> = 0> -void from_json(const BasicJsonType& j, CompatibleArrayType& arr) -{ - if (JSON_UNLIKELY(not j.is_array())) - { - JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); - } - - from_json_array_impl(j, arr, priority_tag<2> {}); -} - -template::value, int> = 0> -void from_json(const BasicJsonType& j, CompatibleObjectType& obj) -{ - if (JSON_UNLIKELY(not j.is_object())) - { - JSON_THROW(type_error::create(302, "type must be object, but is " + std::string(j.type_name()))); - } - - auto inner_object = j.template get_ptr(); - using value_type = typename CompatibleObjectType::value_type; - std::transform( - inner_object->begin(), inner_object->end(), - std::inserter(obj, obj.begin()), - [](typename BasicJsonType::object_t::value_type const & p) - { - return value_type(p.first, p.second.template get()); - }); -} - -// overload for arithmetic types, not chosen for basic_json template arguments -// (BooleanType, etc..); note: Is it really necessary to provide explicit -// overloads for boolean_t etc. in case of a custom BooleanType which is not -// an arithmetic type? -template::value and - not std::is_same::value and - not std::is_same::value and - not std::is_same::value and - not std::is_same::value, - int> = 0> -void from_json(const BasicJsonType& j, ArithmeticType& val) -{ - switch (static_cast(j)) - { - case value_t::number_unsigned: - { - val = static_cast(*j.template get_ptr()); - break; - } - case value_t::number_integer: - { - val = static_cast(*j.template get_ptr()); - break; - } - case value_t::number_float: - { - val = static_cast(*j.template get_ptr()); - break; - } - case value_t::boolean: - { - val = static_cast(*j.template get_ptr()); - break; - } - - default: - JSON_THROW(type_error::create(302, "type must be number, but is " + std::string(j.type_name()))); - } -} - -template -void from_json(const BasicJsonType& j, std::pair& p) -{ - p = {j.at(0).template get(), j.at(1).template get()}; -} - -template -void from_json_tuple_impl(const BasicJsonType& j, Tuple& t, index_sequence) -{ - t = std::make_tuple(j.at(Idx).template get::type>()...); -} - -template -void from_json(const BasicJsonType& j, std::tuple& t) -{ - from_json_tuple_impl(j, t, index_sequence_for {}); -} - -struct from_json_fn -{ - private: - template - auto call(const BasicJsonType& j, T& val, priority_tag<1> /*unused*/) const - noexcept(noexcept(from_json(j, val))) - -> decltype(from_json(j, val), void()) - { - return from_json(j, val); - } - - template - void call(const BasicJsonType& /*unused*/, T& /*unused*/, priority_tag<0> /*unused*/) const noexcept - { - static_assert(sizeof(BasicJsonType) == 0, - "could not find from_json() method in T's namespace"); -#ifdef _MSC_VER - // MSVC does not show a stacktrace for the above assert - using decayed = uncvref_t; - static_assert(sizeof(typename decayed::force_msvc_stacktrace) == 0, - "forcing MSVC stacktrace to show which T we're talking about."); -#endif - } - - public: - template - void operator()(const BasicJsonType& j, T& val) const - noexcept(noexcept(std::declval().call(j, val, priority_tag<1> {}))) - { - return call(j, val, priority_tag<1> {}); - } -}; -} - -/// namespace to hold default `from_json` function -/// to see why this is required: -/// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html -namespace -{ -constexpr const auto& from_json = detail::static_const::value; -} -} - -#endif - -/*** End of inlined file: from_json.hpp ***/ - - -/*** Start of inlined file: to_json.hpp ***/ -#ifndef NLOHMANN_JSON_DETAIL_CONVERSIONS_TO_JSON_HPP -#define NLOHMANN_JSON_DETAIL_CONVERSIONS_TO_JSON_HPP - -#include // or, and, not -#include // begin, end -#include // tuple, get -#include // is_same, is_constructible, is_floating_point, is_enum, underlying_type -#include // move, forward, declval, pair -#include // valarray -#include // vector - -namespace nlohmann -{ -namespace detail -{ -////////////////// -// constructors // -////////////////// - -template struct external_constructor; - -template<> -struct external_constructor -{ - template - static void construct(BasicJsonType& j, typename BasicJsonType::boolean_t b) noexcept - { - j.m_type = value_t::boolean; - j.m_value = b; - j.assert_invariant(); - } -}; - -template<> -struct external_constructor -{ - template - static void construct(BasicJsonType& j, const typename BasicJsonType::string_t& s) - { - j.m_type = value_t::string; - j.m_value = s; - j.assert_invariant(); - } - - template - static void construct(BasicJsonType& j, typename BasicJsonType::string_t&& s) - { - j.m_type = value_t::string; - j.m_value = std::move(s); - j.assert_invariant(); - } -}; - -template<> -struct external_constructor -{ - template - static void construct(BasicJsonType& j, typename BasicJsonType::number_float_t val) noexcept - { - j.m_type = value_t::number_float; - j.m_value = val; - j.assert_invariant(); - } -}; - -template<> -struct external_constructor -{ - template - static void construct(BasicJsonType& j, typename BasicJsonType::number_unsigned_t val) noexcept - { - j.m_type = value_t::number_unsigned; - j.m_value = val; - j.assert_invariant(); - } -}; - -template<> -struct external_constructor -{ - template - static void construct(BasicJsonType& j, typename BasicJsonType::number_integer_t val) noexcept - { - j.m_type = value_t::number_integer; - j.m_value = val; - j.assert_invariant(); - } -}; - -template<> -struct external_constructor -{ - template - static void construct(BasicJsonType& j, const typename BasicJsonType::array_t& arr) - { - j.m_type = value_t::array; - j.m_value = arr; - j.assert_invariant(); - } - - template - static void construct(BasicJsonType& j, typename BasicJsonType::array_t&& arr) - { - j.m_type = value_t::array; - j.m_value = std::move(arr); - j.assert_invariant(); - } - - template::value, - int> = 0> - static void construct(BasicJsonType& j, const CompatibleArrayType& arr) - { - using std::begin; - using std::end; - j.m_type = value_t::array; - j.m_value.array = j.template create(begin(arr), end(arr)); - j.assert_invariant(); - } - - template - static void construct(BasicJsonType& j, const std::vector& arr) - { - j.m_type = value_t::array; - j.m_value = value_t::array; - j.m_value.array->reserve(arr.size()); - for (const bool x : arr) - { - j.m_value.array->push_back(x); - } - j.assert_invariant(); - } - - template::value, int> = 0> - static void construct(BasicJsonType& j, const std::valarray& arr) - { - j.m_type = value_t::array; - j.m_value = value_t::array; - j.m_value.array->resize(arr.size()); - std::copy(std::begin(arr), std::end(arr), j.m_value.array->begin()); - j.assert_invariant(); - } -}; - -template<> -struct external_constructor -{ - template - static void construct(BasicJsonType& j, const typename BasicJsonType::object_t& obj) - { - j.m_type = value_t::object; - j.m_value = obj; - j.assert_invariant(); - } - - template - static void construct(BasicJsonType& j, typename BasicJsonType::object_t&& obj) - { - j.m_type = value_t::object; - j.m_value = std::move(obj); - j.assert_invariant(); - } - - template::value, int> = 0> - static void construct(BasicJsonType& j, const CompatibleObjectType& obj) - { - using std::begin; - using std::end; - - j.m_type = value_t::object; - j.m_value.object = j.template create(begin(obj), end(obj)); - j.assert_invariant(); - } -}; - -///////////// -// to_json // -///////////// - -template::value, int> = 0> -void to_json(BasicJsonType& j, T b) noexcept -{ - external_constructor::construct(j, b); -} - -template::value, int> = 0> -void to_json(BasicJsonType& j, const CompatibleString& s) -{ - external_constructor::construct(j, s); -} - -template -void to_json(BasicJsonType& j, typename BasicJsonType::string_t&& s) -{ - external_constructor::construct(j, std::move(s)); -} - -template::value, int> = 0> -void to_json(BasicJsonType& j, FloatType val) noexcept -{ - external_constructor::construct(j, static_cast(val)); -} - -template::value, int> = 0> -void to_json(BasicJsonType& j, CompatibleNumberUnsignedType val) noexcept -{ - external_constructor::construct(j, static_cast(val)); -} - -template::value, int> = 0> -void to_json(BasicJsonType& j, CompatibleNumberIntegerType val) noexcept -{ - external_constructor::construct(j, static_cast(val)); -} - -template::value, int> = 0> -void to_json(BasicJsonType& j, EnumType e) noexcept -{ - using underlying_type = typename std::underlying_type::type; - external_constructor::construct(j, static_cast(e)); -} - -template -void to_json(BasicJsonType& j, const std::vector& e) -{ - external_constructor::construct(j, e); -} - -template::value or - std::is_same::value, - int> = 0> -void to_json(BasicJsonType& j, const CompatibleArrayType& arr) -{ - external_constructor::construct(j, arr); -} - -template::value, int> = 0> -void to_json(BasicJsonType& j, std::valarray arr) -{ - external_constructor::construct(j, std::move(arr)); -} - -template -void to_json(BasicJsonType& j, typename BasicJsonType::array_t&& arr) -{ - external_constructor::construct(j, std::move(arr)); -} - -template::value, int> = 0> -void to_json(BasicJsonType& j, const CompatibleObjectType& obj) -{ - external_constructor::construct(j, obj); -} - -template -void to_json(BasicJsonType& j, typename BasicJsonType::object_t&& obj) -{ - external_constructor::construct(j, std::move(obj)); -} - -template::value, int> = 0> -void to_json(BasicJsonType& j, T (&arr)[N]) -{ - external_constructor::construct(j, arr); -} - -template -void to_json(BasicJsonType& j, const std::pair& p) -{ - j = {p.first, p.second}; -} - -template -void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence) -{ - j = {std::get(t)...}; -} - -template -void to_json(BasicJsonType& j, const std::tuple& t) -{ - to_json_tuple_impl(j, t, index_sequence_for {}); -} - -struct to_json_fn -{ - private: - template - auto call(BasicJsonType& j, T&& val, priority_tag<1> /*unused*/) const noexcept(noexcept(to_json(j, std::forward(val)))) - -> decltype(to_json(j, std::forward(val)), void()) - { - return to_json(j, std::forward(val)); - } - - template - void call(BasicJsonType& /*unused*/, T&& /*unused*/, priority_tag<0> /*unused*/) const noexcept - { - static_assert(sizeof(BasicJsonType) == 0, - "could not find to_json() method in T's namespace"); - -#ifdef _MSC_VER - // MSVC does not show a stacktrace for the above assert - using decayed = uncvref_t; - static_assert(sizeof(typename decayed::force_msvc_stacktrace) == 0, - "forcing MSVC stacktrace to show which T we're talking about."); -#endif - } - - public: - template - void operator()(BasicJsonType& j, T&& val) const - noexcept(noexcept(std::declval().call(j, std::forward(val), priority_tag<1> {}))) - { - return call(j, std::forward(val), priority_tag<1> {}); - } -}; -} - -/// namespace to hold default `to_json` function -namespace -{ -constexpr const auto& to_json = detail::static_const::value; -} -} - -#endif - -/*** End of inlined file: to_json.hpp ***/ - - -/*** Start of inlined file: input_adapters.hpp ***/ -#ifndef NLOHMANN_JSON_DETAIL_PARSING_INPUT_ADAPTERS_HPP -#define NLOHMANN_JSON_DETAIL_PARSING_INPUT_ADAPTERS_HPP - -#include // min -#include // array -#include // assert -#include // size_t -#include // strlen -#include // streamsize, streamoff, streampos -#include // istream -#include // begin, end, iterator_traits, random_access_iterator_tag, distance, next -#include // shared_ptr, make_shared, addressof -#include // accumulate -#include // string, char_traits -#include // enable_if, is_base_of, is_pointer, is_integral, remove_pointer -#include // pair, declval - -namespace nlohmann -{ -namespace detail -{ -//////////////////// -// input adapters // -//////////////////// - -/*! -@brief abstract input adapter interface - -Produces a stream of std::char_traits::int_type characters from a -std::istream, a buffer, or some other input type. Accepts the return of exactly -one non-EOF character for future input. The int_type characters returned -consist of all valid char values as positive values (typically unsigned char), -plus an EOF value outside that range, specified by the value of the function -std::char_traits::eof(). This value is typically -1, but could be any -arbitrary value which is not a valid char value. -*/ -struct input_adapter_protocol -{ - /// get a character [0,255] or std::char_traits::eof(). - virtual std::char_traits::int_type get_character() = 0; - /// restore the last non-eof() character to input - virtual void unget_character() = 0; - virtual ~input_adapter_protocol() = default; -}; - -/// a type to simplify interfaces -using input_adapter_t = std::shared_ptr; - -/*! -Input adapter for a (caching) istream. Ignores a UFT Byte Order Mark at -beginning of input. Does not support changing the underlying std::streambuf -in mid-input. Maintains underlying std::istream and std::streambuf to support -subsequent use of standard std::istream operations to process any input -characters following those used in parsing the JSON input. Clears the -std::istream flags; any input errors (e.g., EOF) will be detected by the first -subsequent call for input from the std::istream. -*/ -class input_stream_adapter : public input_adapter_protocol -{ - public: - ~input_stream_adapter() override - { - // clear stream flags; we use underlying streambuf I/O, do not - // maintain ifstream flags - is.clear(); - } - - explicit input_stream_adapter(std::istream& i) - : is(i), sb(*i.rdbuf()) - { - // skip byte order mark - std::char_traits::int_type c; - if ((c = get_character()) == 0xEF) - { - if ((c = get_character()) == 0xBB) - { - if ((c = get_character()) == 0xBF) - { - return; // Ignore BOM - } - else if (c != std::char_traits::eof()) - { - is.unget(); - } - is.putback('\xBB'); - } - else if (c != std::char_traits::eof()) - { - is.unget(); - } - is.putback('\xEF'); - } - else if (c != std::char_traits::eof()) - { - is.unget(); // no byte order mark; process as usual - } - } - - // delete because of pointer members - input_stream_adapter(const input_stream_adapter&) = delete; - input_stream_adapter& operator=(input_stream_adapter&) = delete; - - // std::istream/std::streambuf use std::char_traits::to_int_type, to - // ensure that std::char_traits::eof() and the character 0xFF do not - // end up as the same value, eg. 0xFFFFFFFF. - std::char_traits::int_type get_character() override - { - return sb.sbumpc(); - } - - void unget_character() override - { - sb.sungetc(); // is.unget() avoided for performance - } - - private: - /// the associated input stream - std::istream& is; - std::streambuf& sb; -}; - -/// input adapter for buffer input -class input_buffer_adapter : public input_adapter_protocol -{ - public: - input_buffer_adapter(const char* b, const std::size_t l) - : cursor(b), limit(b + l), start(b) - { - // skip byte order mark - if (l >= 3 and b[0] == '\xEF' and b[1] == '\xBB' and b[2] == '\xBF') - { - cursor += 3; - } - } - - // delete because of pointer members - input_buffer_adapter(const input_buffer_adapter&) = delete; - input_buffer_adapter& operator=(input_buffer_adapter&) = delete; - - std::char_traits::int_type get_character() noexcept override - { - if (JSON_LIKELY(cursor < limit)) - { - return std::char_traits::to_int_type(*(cursor++)); - } - - return std::char_traits::eof(); - } - - void unget_character() noexcept override - { - if (JSON_LIKELY(cursor > start)) - { - --cursor; - } - } - - private: - /// pointer to the current character - const char* cursor; - /// pointer past the last character - const char* limit; - /// pointer to the first character - const char* start; -}; - -class input_adapter -{ - public: - // native support - - /// input adapter for input stream - input_adapter(std::istream& i) - : ia(std::make_shared(i)) {} - - /// input adapter for input stream - input_adapter(std::istream&& i) - : ia(std::make_shared(i)) {} - - /// input adapter for buffer - template::value and - std::is_integral::type>::value and - sizeof(typename std::remove_pointer::type) == 1, - int>::type = 0> - input_adapter(CharT b, std::size_t l) - : ia(std::make_shared(reinterpret_cast(b), l)) {} - - // derived support - - /// input adapter for string literal - template::value and - std::is_integral::type>::value and - sizeof(typename std::remove_pointer::type) == 1, - int>::type = 0> - input_adapter(CharT b) - : input_adapter(reinterpret_cast(b), - std::strlen(reinterpret_cast(b))) {} - - /// input adapter for iterator range with contiguous storage - template::iterator_category, std::random_access_iterator_tag>::value, - int>::type = 0> - input_adapter(IteratorType first, IteratorType last) - { - // assertion to check that the iterator range is indeed contiguous, - // see http://stackoverflow.com/a/35008842/266378 for more discussion - assert(std::accumulate( - first, last, std::pair(true, 0), - [&first](std::pair res, decltype(*first) val) - { - res.first &= (val == *(std::next(std::addressof(*first), res.second++))); - return res; - }).first); - - // assertion to check that each element is 1 byte long - static_assert( - sizeof(typename std::iterator_traits::value_type) == 1, - "each element in the iterator range must have the size of 1 byte"); - - const auto len = static_cast(std::distance(first, last)); - if (JSON_LIKELY(len > 0)) - { - // there is at least one element: use the address of first - ia = std::make_shared(reinterpret_cast(&(*first)), len); - } - else - { - // the address of first cannot be used: use nullptr - ia = std::make_shared(nullptr, len); - } - } - - /// input adapter for array - template - input_adapter(T (&array)[N]) - : input_adapter(std::begin(array), std::end(array)) {} - - /// input adapter for contiguous container - template::value and - std::is_base_of()))>::iterator_category>::value, - int>::type = 0> - input_adapter(const ContiguousContainer& c) - : input_adapter(std::begin(c), std::end(c)) {} - - operator input_adapter_t() - { - return ia; - } - - private: - /// the actual adapter - input_adapter_t ia = nullptr; -}; -} -} - -#endif - -/*** End of inlined file: input_adapters.hpp ***/ - - -/*** Start of inlined file: lexer.hpp ***/ -#ifndef NLOHMANN_JSON_DETAIL_PARSING_LEXER_HPP -#define NLOHMANN_JSON_DETAIL_PARSING_LEXER_HPP - -#include // localeconv -#include // size_t -#include // strtof, strtod, strtold, strtoll, strtoull -#include // initializer_list -#include // hex, uppercase -#include // setw, setfill -#include // stringstream -#include // char_traits, string -#include // vector - - -/*** Start of inlined file: input_adapters.hpp ***/ -#ifndef NLOHMANN_JSON_DETAIL_PARSING_INPUT_ADAPTERS_HPP -#define NLOHMANN_JSON_DETAIL_PARSING_INPUT_ADAPTERS_HPP - -#include // min -#include // array -#include // assert -#include // size_t -#include // strlen -#include // streamsize, streamoff, streampos -#include // istream -#include // begin, end, iterator_traits, random_access_iterator_tag, distance, next -#include // shared_ptr, make_shared, addressof -#include // accumulate -#include // string, char_traits -#include // enable_if, is_base_of, is_pointer, is_integral, remove_pointer -#include // pair, declval - -namespace nlohmann -{ -namespace detail -{ -//////////////////// -// input adapters // -//////////////////// - -/*! -@brief abstract input adapter interface - -Produces a stream of std::char_traits::int_type characters from a -std::istream, a buffer, or some other input type. Accepts the return of exactly -one non-EOF character for future input. The int_type characters returned -consist of all valid char values as positive values (typically unsigned char), -plus an EOF value outside that range, specified by the value of the function -std::char_traits::eof(). This value is typically -1, but could be any -arbitrary value which is not a valid char value. -*/ -struct input_adapter_protocol -{ - /// get a character [0,255] or std::char_traits::eof(). - virtual std::char_traits::int_type get_character() = 0; - /// restore the last non-eof() character to input - virtual void unget_character() = 0; - virtual ~input_adapter_protocol() = default; -}; - -/// a type to simplify interfaces -using input_adapter_t = std::shared_ptr; - -/*! -Input adapter for a (caching) istream. Ignores a UFT Byte Order Mark at -beginning of input. Does not support changing the underlying std::streambuf -in mid-input. Maintains underlying std::istream and std::streambuf to support -subsequent use of standard std::istream operations to process any input -characters following those used in parsing the JSON input. Clears the -std::istream flags; any input errors (e.g., EOF) will be detected by the first -subsequent call for input from the std::istream. -*/ -class input_stream_adapter : public input_adapter_protocol -{ - public: - ~input_stream_adapter() override - { - // clear stream flags; we use underlying streambuf I/O, do not - // maintain ifstream flags - is.clear(); - } - - explicit input_stream_adapter(std::istream& i) - : is(i), sb(*i.rdbuf()) - { - // skip byte order mark - std::char_traits::int_type c; - if ((c = get_character()) == 0xEF) - { - if ((c = get_character()) == 0xBB) - { - if ((c = get_character()) == 0xBF) - { - return; // Ignore BOM - } - else if (c != std::char_traits::eof()) - { - is.unget(); - } - is.putback('\xBB'); - } - else if (c != std::char_traits::eof()) - { - is.unget(); - } - is.putback('\xEF'); - } - else if (c != std::char_traits::eof()) - { - is.unget(); // no byte order mark; process as usual - } - } - - // delete because of pointer members - input_stream_adapter(const input_stream_adapter&) = delete; - input_stream_adapter& operator=(input_stream_adapter&) = delete; - - // std::istream/std::streambuf use std::char_traits::to_int_type, to - // ensure that std::char_traits::eof() and the character 0xFF do not - // end up as the same value, eg. 0xFFFFFFFF. - std::char_traits::int_type get_character() override - { - return sb.sbumpc(); - } - - void unget_character() override - { - sb.sungetc(); // is.unget() avoided for performance - } - - private: - /// the associated input stream - std::istream& is; - std::streambuf& sb; -}; - -/// input adapter for buffer input -class input_buffer_adapter : public input_adapter_protocol -{ - public: - input_buffer_adapter(const char* b, const std::size_t l) - : cursor(b), limit(b + l), start(b) - { - // skip byte order mark - if (l >= 3 and b[0] == '\xEF' and b[1] == '\xBB' and b[2] == '\xBF') - { - cursor += 3; - } - } - - // delete because of pointer members - input_buffer_adapter(const input_buffer_adapter&) = delete; - input_buffer_adapter& operator=(input_buffer_adapter&) = delete; - - std::char_traits::int_type get_character() noexcept override - { - if (JSON_LIKELY(cursor < limit)) - { - return std::char_traits::to_int_type(*(cursor++)); - } - - return std::char_traits::eof(); - } - - void unget_character() noexcept override - { - if (JSON_LIKELY(cursor > start)) - { - --cursor; - } - } - - private: - /// pointer to the current character - const char* cursor; - /// pointer past the last character - const char* limit; - /// pointer to the first character - const char* start; -}; - -class input_adapter -{ - public: - // native support - - /// input adapter for input stream - input_adapter(std::istream& i) - : ia(std::make_shared(i)) {} - - /// input adapter for input stream - input_adapter(std::istream&& i) - : ia(std::make_shared(i)) {} - - /// input adapter for buffer - template::value and - std::is_integral::type>::value and - sizeof(typename std::remove_pointer::type) == 1, - int>::type = 0> - input_adapter(CharT b, std::size_t l) - : ia(std::make_shared(reinterpret_cast(b), l)) {} - - // derived support - - /// input adapter for string literal - template::value and - std::is_integral::type>::value and - sizeof(typename std::remove_pointer::type) == 1, - int>::type = 0> - input_adapter(CharT b) - : input_adapter(reinterpret_cast(b), - std::strlen(reinterpret_cast(b))) {} - - /// input adapter for iterator range with contiguous storage - template::iterator_category, std::random_access_iterator_tag>::value, - int>::type = 0> - input_adapter(IteratorType first, IteratorType last) - { - // assertion to check that the iterator range is indeed contiguous, - // see http://stackoverflow.com/a/35008842/266378 for more discussion - assert(std::accumulate( - first, last, std::pair(true, 0), - [&first](std::pair res, decltype(*first) val) - { - res.first &= (val == *(std::next(std::addressof(*first), res.second++))); - return res; - }).first); - - // assertion to check that each element is 1 byte long - static_assert( - sizeof(typename std::iterator_traits::value_type) == 1, - "each element in the iterator range must have the size of 1 byte"); - - const auto len = static_cast(std::distance(first, last)); - if (JSON_LIKELY(len > 0)) - { - // there is at least one element: use the address of first - ia = std::make_shared(reinterpret_cast(&(*first)), len); - } - else - { - // the address of first cannot be used: use nullptr - ia = std::make_shared(nullptr, len); - } - } - - /// input adapter for array - template - input_adapter(T (&array)[N]) - : input_adapter(std::begin(array), std::end(array)) {} - - /// input adapter for contiguous container - template::value and - std::is_base_of()))>::iterator_category>::value, - int>::type = 0> - input_adapter(const ContiguousContainer& c) - : input_adapter(std::begin(c), std::end(c)) {} - - operator input_adapter_t() - { - return ia; - } - - private: - /// the actual adapter - input_adapter_t ia = nullptr; -}; -} -} - -#endif - -/*** End of inlined file: input_adapters.hpp ***/ - -namespace nlohmann -{ -namespace detail -{ -/////////// -// lexer // -/////////// - -/*! -@brief lexical analysis - -This class organizes the lexical analysis during JSON deserialization. -*/ -template -class lexer -{ - using number_integer_t = typename BasicJsonType::number_integer_t; - using number_unsigned_t = typename BasicJsonType::number_unsigned_t; - using number_float_t = typename BasicJsonType::number_float_t; - - public: - /// token types for the parser - enum class token_type - { - uninitialized, ///< indicating the scanner is uninitialized - literal_true, ///< the `true` literal - literal_false, ///< the `false` literal - literal_null, ///< the `null` literal - value_string, ///< a string -- use get_string() for actual value - value_unsigned, ///< an unsigned integer -- use get_number_unsigned() for actual value - value_integer, ///< a signed integer -- use get_number_integer() for actual value - value_float, ///< an floating point number -- use get_number_float() for actual value - begin_array, ///< the character for array begin `[` - begin_object, ///< the character for object begin `{` - end_array, ///< the character for array end `]` - end_object, ///< the character for object end `}` - name_separator, ///< the name separator `:` - value_separator, ///< the value separator `,` - parse_error, ///< indicating a parse error - end_of_input, ///< indicating the end of the input buffer - literal_or_value ///< a literal or the begin of a value (only for diagnostics) - }; - - /// return name of values of type token_type (only used for errors) - static const char* token_type_name(const token_type t) noexcept - { - switch (t) - { - case token_type::uninitialized: - return ""; - case token_type::literal_true: - return "true literal"; - case token_type::literal_false: - return "false literal"; - case token_type::literal_null: - return "null literal"; - case token_type::value_string: - return "string literal"; - case lexer::token_type::value_unsigned: - case lexer::token_type::value_integer: - case lexer::token_type::value_float: - return "number literal"; - case token_type::begin_array: - return "'['"; - case token_type::begin_object: - return "'{'"; - case token_type::end_array: - return "']'"; - case token_type::end_object: - return "'}'"; - case token_type::name_separator: - return "':'"; - case token_type::value_separator: - return "','"; - case token_type::parse_error: - return ""; - case token_type::end_of_input: - return "end of input"; - case token_type::literal_or_value: - return "'[', '{', or a literal"; - default: // catch non-enum values - return "unknown token"; // LCOV_EXCL_LINE - } - } - - explicit lexer(detail::input_adapter_t adapter) - : ia(std::move(adapter)), decimal_point_char(get_decimal_point()) {} - - // delete because of pointer members - lexer(const lexer&) = delete; - lexer& operator=(lexer&) = delete; - - private: - ///////////////////// - // locales - ///////////////////// - - /// return the locale-dependent decimal point - static char get_decimal_point() noexcept - { - const auto loc = localeconv(); - assert(loc != nullptr); - return (loc->decimal_point == nullptr) ? '.' : *(loc->decimal_point); - } - - ///////////////////// - // scan functions - ///////////////////// - - /*! - @brief get codepoint from 4 hex characters following `\u` - - For input "\u c1 c2 c3 c4" the codepoint is: - (c1 * 0x1000) + (c2 * 0x0100) + (c3 * 0x0010) + c4 - = (c1 << 12) + (c2 << 8) + (c3 << 4) + (c4 << 0) - - Furthermore, the possible characters '0'..'9', 'A'..'F', and 'a'..'f' - must be converted to the integers 0x0..0x9, 0xA..0xF, 0xA..0xF, resp. The - conversion is done by subtracting the offset (0x30, 0x37, and 0x57) - between the ASCII value of the character and the desired integer value. - - @return codepoint (0x0000..0xFFFF) or -1 in case of an error (e.g. EOF or - non-hex character) - */ - int get_codepoint() - { - // this function only makes sense after reading `\u` - assert(current == 'u'); - int codepoint = 0; - - const auto factors = { 12, 8, 4, 0 }; - for (const auto factor : factors) - { - get(); - - if (current >= '0' and current <= '9') - { - codepoint += ((current - 0x30) << factor); - } - else if (current >= 'A' and current <= 'F') - { - codepoint += ((current - 0x37) << factor); - } - else if (current >= 'a' and current <= 'f') - { - codepoint += ((current - 0x57) << factor); - } - else - { - return -1; - } - } - - assert(0x0000 <= codepoint and codepoint <= 0xFFFF); - return codepoint; - } - - /*! - @brief check if the next byte(s) are inside a given range - - Adds the current byte and, for each passed range, reads a new byte and - checks if it is inside the range. If a violation was detected, set up an - error message and return false. Otherwise, return true. - - @param[in] ranges list of integers; interpreted as list of pairs of - inclusive lower and upper bound, respectively - - @pre The passed list @a ranges must have 2, 4, or 6 elements; that is, - 1, 2, or 3 pairs. This precondition is enforced by an assertion. - - @return true if and only if no range violation was detected - */ - bool next_byte_in_range(std::initializer_list ranges) - { - assert(ranges.size() == 2 or ranges.size() == 4 or ranges.size() == 6); - add(current); - - for (auto range = ranges.begin(); range != ranges.end(); ++range) - { - get(); - if (JSON_LIKELY(*range <= current and current <= *(++range))) - { - add(current); - } - else - { - error_message = "invalid string: ill-formed UTF-8 byte"; - return false; - } - } - - return true; - } - - /*! - @brief scan a string literal - - This function scans a string according to Sect. 7 of RFC 7159. While - scanning, bytes are escaped and copied into buffer yytext. Then the function - returns successfully, yytext is *not* null-terminated (as it may contain \0 - bytes), and yytext.size() is the number of bytes in the string. - - @return token_type::value_string if string could be successfully scanned, - token_type::parse_error otherwise - - @note In case of errors, variable error_message contains a textual - description. - */ - token_type scan_string() - { - // reset yytext (ignore opening quote) - reset(); - - // we entered the function by reading an open quote - assert(current == '\"'); - - while (true) - { - // get next character - switch (get()) - { - // end of file while parsing string - case std::char_traits::eof(): - { - error_message = "invalid string: missing closing quote"; - return token_type::parse_error; - } - - // closing quote - case '\"': - { - return token_type::value_string; - } - - // escapes - case '\\': - { - switch (get()) - { - // quotation mark - case '\"': - add('\"'); - break; - // reverse solidus - case '\\': - add('\\'); - break; - // solidus - case '/': - add('/'); - break; - // backspace - case 'b': - add('\b'); - break; - // form feed - case 'f': - add('\f'); - break; - // line feed - case 'n': - add('\n'); - break; - // carriage return - case 'r': - add('\r'); - break; - // tab - case 't': - add('\t'); - break; - - // unicode escapes - case 'u': - { - const int codepoint1 = get_codepoint(); - int codepoint = codepoint1; // start with codepoint1 - - if (JSON_UNLIKELY(codepoint1 == -1)) - { - error_message = "invalid string: '\\u' must be followed by 4 hex digits"; - return token_type::parse_error; - } - - // check if code point is a high surrogate - if (0xD800 <= codepoint1 and codepoint1 <= 0xDBFF) - { - // expect next \uxxxx entry - if (JSON_LIKELY(get() == '\\' and get() == 'u')) - { - const int codepoint2 = get_codepoint(); - - if (JSON_UNLIKELY(codepoint2 == -1)) - { - error_message = "invalid string: '\\u' must be followed by 4 hex digits"; - return token_type::parse_error; - } - - // check if codepoint2 is a low surrogate - if (JSON_LIKELY(0xDC00 <= codepoint2 and codepoint2 <= 0xDFFF)) - { - // overwrite codepoint - codepoint = - // high surrogate occupies the most significant 22 bits - (codepoint1 << 10) - // low surrogate occupies the least significant 15 bits - + codepoint2 - // there is still the 0xD800, 0xDC00 and 0x10000 noise - // in the result so we have to subtract with: - // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00 - - 0x35FDC00; - } - else - { - error_message = "invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF"; - return token_type::parse_error; - } - } - else - { - error_message = "invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF"; - return token_type::parse_error; - } - } - else - { - if (JSON_UNLIKELY(0xDC00 <= codepoint1 and codepoint1 <= 0xDFFF)) - { - error_message = "invalid string: surrogate U+DC00..U+DFFF must follow U+D800..U+DBFF"; - return token_type::parse_error; - } - } - - // result of the above calculation yields a proper codepoint - assert(0x00 <= codepoint and codepoint <= 0x10FFFF); - - // translate codepoint into bytes - if (codepoint < 0x80) - { - // 1-byte characters: 0xxxxxxx (ASCII) - add(codepoint); - } - else if (codepoint <= 0x7FF) - { - // 2-byte characters: 110xxxxx 10xxxxxx - add(0xC0 | (codepoint >> 6)); - add(0x80 | (codepoint & 0x3F)); - } - else if (codepoint <= 0xFFFF) - { - // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx - add(0xE0 | (codepoint >> 12)); - add(0x80 | ((codepoint >> 6) & 0x3F)); - add(0x80 | (codepoint & 0x3F)); - } - else - { - // 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - add(0xF0 | (codepoint >> 18)); - add(0x80 | ((codepoint >> 12) & 0x3F)); - add(0x80 | ((codepoint >> 6) & 0x3F)); - add(0x80 | (codepoint & 0x3F)); - } - - break; - } - - // other characters after escape - default: - error_message = "invalid string: forbidden character after backslash"; - return token_type::parse_error; - } - - break; - } - - // invalid control characters - case 0x00: - case 0x01: - case 0x02: - case 0x03: - case 0x04: - case 0x05: - case 0x06: - case 0x07: - case 0x08: - case 0x09: - case 0x0A: - case 0x0B: - case 0x0C: - case 0x0D: - case 0x0E: - case 0x0F: - case 0x10: - case 0x11: - case 0x12: - case 0x13: - case 0x14: - case 0x15: - case 0x16: - case 0x17: - case 0x18: - case 0x19: - case 0x1A: - case 0x1B: - case 0x1C: - case 0x1D: - case 0x1E: - case 0x1F: - { - error_message = "invalid string: control character must be escaped"; - return token_type::parse_error; - } - - // U+0020..U+007F (except U+0022 (quote) and U+005C (backspace)) - case 0x20: - case 0x21: - case 0x23: - case 0x24: - case 0x25: - case 0x26: - case 0x27: - case 0x28: - case 0x29: - case 0x2A: - case 0x2B: - case 0x2C: - case 0x2D: - case 0x2E: - case 0x2F: - case 0x30: - case 0x31: - case 0x32: - case 0x33: - case 0x34: - case 0x35: - case 0x36: - case 0x37: - case 0x38: - case 0x39: - case 0x3A: - case 0x3B: - case 0x3C: - case 0x3D: - case 0x3E: - case 0x3F: - case 0x40: - case 0x41: - case 0x42: - case 0x43: - case 0x44: - case 0x45: - case 0x46: - case 0x47: - case 0x48: - case 0x49: - case 0x4A: - case 0x4B: - case 0x4C: - case 0x4D: - case 0x4E: - case 0x4F: - case 0x50: - case 0x51: - case 0x52: - case 0x53: - case 0x54: - case 0x55: - case 0x56: - case 0x57: - case 0x58: - case 0x59: - case 0x5A: - case 0x5B: - case 0x5D: - case 0x5E: - case 0x5F: - case 0x60: - case 0x61: - case 0x62: - case 0x63: - case 0x64: - case 0x65: - case 0x66: - case 0x67: - case 0x68: - case 0x69: - case 0x6A: - case 0x6B: - case 0x6C: - case 0x6D: - case 0x6E: - case 0x6F: - case 0x70: - case 0x71: - case 0x72: - case 0x73: - case 0x74: - case 0x75: - case 0x76: - case 0x77: - case 0x78: - case 0x79: - case 0x7A: - case 0x7B: - case 0x7C: - case 0x7D: - case 0x7E: - case 0x7F: - { - add(current); - break; - } - - // U+0080..U+07FF: bytes C2..DF 80..BF - case 0xC2: - case 0xC3: - case 0xC4: - case 0xC5: - case 0xC6: - case 0xC7: - case 0xC8: - case 0xC9: - case 0xCA: - case 0xCB: - case 0xCC: - case 0xCD: - case 0xCE: - case 0xCF: - case 0xD0: - case 0xD1: - case 0xD2: - case 0xD3: - case 0xD4: - case 0xD5: - case 0xD6: - case 0xD7: - case 0xD8: - case 0xD9: - case 0xDA: - case 0xDB: - case 0xDC: - case 0xDD: - case 0xDE: - case 0xDF: - { - if (JSON_UNLIKELY(not next_byte_in_range({0x80, 0xBF}))) - { - return token_type::parse_error; - } - break; - } - - // U+0800..U+0FFF: bytes E0 A0..BF 80..BF - case 0xE0: - { - if (JSON_UNLIKELY(not (next_byte_in_range({0xA0, 0xBF, 0x80, 0xBF})))) - { - return token_type::parse_error; - } - break; - } - - // U+1000..U+CFFF: bytes E1..EC 80..BF 80..BF - // U+E000..U+FFFF: bytes EE..EF 80..BF 80..BF - case 0xE1: - case 0xE2: - case 0xE3: - case 0xE4: - case 0xE5: - case 0xE6: - case 0xE7: - case 0xE8: - case 0xE9: - case 0xEA: - case 0xEB: - case 0xEC: - case 0xEE: - case 0xEF: - { - if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0xBF, 0x80, 0xBF})))) - { - return token_type::parse_error; - } - break; - } - - // U+D000..U+D7FF: bytes ED 80..9F 80..BF - case 0xED: - { - if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0x9F, 0x80, 0xBF})))) - { - return token_type::parse_error; - } - break; - } - - // U+10000..U+3FFFF F0 90..BF 80..BF 80..BF - case 0xF0: - { - if (JSON_UNLIKELY(not (next_byte_in_range({0x90, 0xBF, 0x80, 0xBF, 0x80, 0xBF})))) - { - return token_type::parse_error; - } - break; - } - - // U+40000..U+FFFFF F1..F3 80..BF 80..BF 80..BF - case 0xF1: - case 0xF2: - case 0xF3: - { - if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0xBF, 0x80, 0xBF, 0x80, 0xBF})))) - { - return token_type::parse_error; - } - break; - } - - // U+100000..U+10FFFF F4 80..8F 80..BF 80..BF - case 0xF4: - { - if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0x8F, 0x80, 0xBF, 0x80, 0xBF})))) - { - return token_type::parse_error; - } - break; - } - - // remaining bytes (80..C1 and F5..FF) are ill-formed - default: - { - error_message = "invalid string: ill-formed UTF-8 byte"; - return token_type::parse_error; - } - } - } - } - - static void strtof(float& f, const char* str, char** endptr) noexcept - { - f = std::strtof(str, endptr); - } - - static void strtof(double& f, const char* str, char** endptr) noexcept - { - f = std::strtod(str, endptr); - } - - static void strtof(long double& f, const char* str, char** endptr) noexcept - { - f = std::strtold(str, endptr); - } - - /*! - @brief scan a number literal - - This function scans a string according to Sect. 6 of RFC 7159. - - The function is realized with a deterministic finite state machine derived - from the grammar described in RFC 7159. Starting in state "init", the - input is read and used to determined the next state. Only state "done" - accepts the number. State "error" is a trap state to model errors. In the - table below, "anything" means any character but the ones listed before. - - state | 0 | 1-9 | e E | + | - | . | anything - ---------|----------|----------|----------|---------|---------|----------|----------- - init | zero | any1 | [error] | [error] | minus | [error] | [error] - minus | zero | any1 | [error] | [error] | [error] | [error] | [error] - zero | done | done | exponent | done | done | decimal1 | done - any1 | any1 | any1 | exponent | done | done | decimal1 | done - decimal1 | decimal2 | [error] | [error] | [error] | [error] | [error] | [error] - decimal2 | decimal2 | decimal2 | exponent | done | done | done | done - exponent | any2 | any2 | [error] | sign | sign | [error] | [error] - sign | any2 | any2 | [error] | [error] | [error] | [error] | [error] - any2 | any2 | any2 | done | done | done | done | done - - The state machine is realized with one label per state (prefixed with - "scan_number_") and `goto` statements between them. The state machine - contains cycles, but any cycle can be left when EOF is read. Therefore, - the function is guaranteed to terminate. - - During scanning, the read bytes are stored in yytext. This string is - then converted to a signed integer, an unsigned integer, or a - floating-point number. - - @return token_type::value_unsigned, token_type::value_integer, or - token_type::value_float if number could be successfully scanned, - token_type::parse_error otherwise - - @note The scanner is independent of the current locale. Internally, the - locale's decimal point is used instead of `.` to work with the - locale-dependent converters. - */ - token_type scan_number() - { - // reset yytext to store the number's bytes - reset(); - - // the type of the parsed number; initially set to unsigned; will be - // changed if minus sign, decimal point or exponent is read - token_type number_type = token_type::value_unsigned; - - // state (init): we just found out we need to scan a number - switch (current) - { - case '-': - { - add(current); - goto scan_number_minus; - } - - case '0': - { - add(current); - goto scan_number_zero; - } - - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_any1; - } - - default: - { - // all other characters are rejected outside scan_number() - assert(false); // LCOV_EXCL_LINE - } - } - -scan_number_minus: - // state: we just parsed a leading minus sign - number_type = token_type::value_integer; - switch (get()) - { - case '0': - { - add(current); - goto scan_number_zero; - } - - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_any1; - } - - default: - { - error_message = "invalid number; expected digit after '-'"; - return token_type::parse_error; - } - } - -scan_number_zero: - // state: we just parse a zero (maybe with a leading minus sign) - switch (get()) - { - case '.': - { - add(decimal_point_char); - goto scan_number_decimal1; - } - - case 'e': - case 'E': - { - add(current); - goto scan_number_exponent; - } - - default: - goto scan_number_done; - } - -scan_number_any1: - // state: we just parsed a number 0-9 (maybe with a leading minus sign) - switch (get()) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_any1; - } - - case '.': - { - add(decimal_point_char); - goto scan_number_decimal1; - } - - case 'e': - case 'E': - { - add(current); - goto scan_number_exponent; - } - - default: - goto scan_number_done; - } - -scan_number_decimal1: - // state: we just parsed a decimal point - number_type = token_type::value_float; - switch (get()) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_decimal2; - } - - default: - { - error_message = "invalid number; expected digit after '.'"; - return token_type::parse_error; - } - } - -scan_number_decimal2: - // we just parsed at least one number after a decimal point - switch (get()) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_decimal2; - } - - case 'e': - case 'E': - { - add(current); - goto scan_number_exponent; - } - - default: - goto scan_number_done; - } - -scan_number_exponent: - // we just parsed an exponent - number_type = token_type::value_float; - switch (get()) - { - case '+': - case '-': - { - add(current); - goto scan_number_sign; - } - - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_any2; - } - - default: - { - error_message = - "invalid number; expected '+', '-', or digit after exponent"; - return token_type::parse_error; - } - } - -scan_number_sign: - // we just parsed an exponent sign - switch (get()) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_any2; - } - - default: - { - error_message = "invalid number; expected digit after exponent sign"; - return token_type::parse_error; - } - } - -scan_number_any2: - // we just parsed a number after the exponent or exponent sign - switch (get()) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_any2; - } - - default: - goto scan_number_done; - } - -scan_number_done: - // unget the character after the number (we only read it to know that - // we are done scanning a number) - unget(); - - char* endptr = nullptr; - errno = 0; - - // try to parse integers first and fall back to floats - if (number_type == token_type::value_unsigned) - { - const auto x = std::strtoull(yytext.data(), &endptr, 10); - - // we checked the number format before - assert(endptr == yytext.data() + yytext.size()); - - if (errno == 0) - { - value_unsigned = static_cast(x); - if (value_unsigned == x) - { - return token_type::value_unsigned; - } - } - } - else if (number_type == token_type::value_integer) - { - const auto x = std::strtoll(yytext.data(), &endptr, 10); - - // we checked the number format before - assert(endptr == yytext.data() + yytext.size()); - - if (errno == 0) - { - value_integer = static_cast(x); - if (value_integer == x) - { - return token_type::value_integer; - } - } - } - - // this code is reached if we parse a floating-point number or if an - // integer conversion above failed - strtof(value_float, yytext.data(), &endptr); - - // we checked the number format before - assert(endptr == yytext.data() + yytext.size()); - - return token_type::value_float; - } - - /*! - @param[in] literal_text the literal text to expect - @param[in] length the length of the passed literal text - @param[in] return_type the token type to return on success - */ - token_type scan_literal(const char* literal_text, const std::size_t length, - token_type return_type) - { - assert(current == literal_text[0]); - for (std::size_t i = 1; i < length; ++i) - { - if (JSON_UNLIKELY(get() != literal_text[i])) - { - error_message = "invalid literal"; - return token_type::parse_error; - } - } - return return_type; - } - - ///////////////////// - // input management - ///////////////////// - - /// reset yytext; current character is beginning of token - void reset() noexcept - { - yytext.clear(); - token_string.clear(); - token_string.push_back(std::char_traits::to_char_type(current)); - } - - /* - @brief get next character from the input - - This function provides the interface to the used input adapter. It does - not throw in case the input reached EOF, but returns a - `std::char_traits::eof()` in that case. Stores the scanned characters - for use in error messages. - - @return character read from the input - */ - std::char_traits::int_type get() - { - ++chars_read; - current = ia->get_character(); - if (JSON_LIKELY(current != std::char_traits::eof())) - { - token_string.push_back(std::char_traits::to_char_type(current)); - } - return current; - } - - /// unget current character (return it again on next get) - void unget() - { - --chars_read; - if (JSON_LIKELY(current != std::char_traits::eof())) - { - ia->unget_character(); - assert(token_string.size() != 0); - token_string.pop_back(); - } - } - - /// add a character to yytext - void add(int c) - { - yytext.push_back(std::char_traits::to_char_type(c)); - } - - public: - ///////////////////// - // value getters - ///////////////////// - - /// return integer value - constexpr number_integer_t get_number_integer() const noexcept - { - return value_integer; - } - - /// return unsigned integer value - constexpr number_unsigned_t get_number_unsigned() const noexcept - { - return value_unsigned; - } - - /// return floating-point value - constexpr number_float_t get_number_float() const noexcept - { - return value_float; - } - - /// return current string value (implicitly resets the token; useful only once) - std::string move_string() - { - return std::move(yytext); - } - - ///////////////////// - // diagnostics - ///////////////////// - - /// return position of last read token - constexpr std::size_t get_position() const noexcept - { - return chars_read; - } - - /// return the last read token (for errors only). Will never contain EOF - /// (an arbitrary value that is not a valid char value, often -1), because - /// 255 may legitimately occur. May contain NUL, which should be escaped. - std::string get_token_string() const - { - // escape control characters - std::string result; - for (const auto c : token_string) - { - if ('\x00' <= c and c <= '\x1F') - { - // escape control characters - std::stringstream ss; - ss << "(c) << ">"; - result += ss.str(); - } - else - { - // add character as is - result.push_back(c); - } - } - - return result; - } - - /// return syntax error message - constexpr const char* get_error_message() const noexcept - { - return error_message; - } - - ///////////////////// - // actual scanner - ///////////////////// - - token_type scan() - { - // read next character and ignore whitespace - do - { - get(); - } - while (current == ' ' or current == '\t' or current == '\n' or current == '\r'); - - switch (current) - { - // structural characters - case '[': - return token_type::begin_array; - case ']': - return token_type::end_array; - case '{': - return token_type::begin_object; - case '}': - return token_type::end_object; - case ':': - return token_type::name_separator; - case ',': - return token_type::value_separator; - - // literals - case 't': - return scan_literal("true", 4, token_type::literal_true); - case 'f': - return scan_literal("false", 5, token_type::literal_false); - case 'n': - return scan_literal("null", 4, token_type::literal_null); - - // string - case '\"': - return scan_string(); - - // number - case '-': - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - return scan_number(); - - // end of input (the null byte is needed when parsing from - // string literals) - case '\0': - case std::char_traits::eof(): - return token_type::end_of_input; - - // error - default: - error_message = "invalid literal"; - return token_type::parse_error; - } - } - - private: - /// input adapter - detail::input_adapter_t ia = nullptr; - - /// the current character - std::char_traits::int_type current = std::char_traits::eof(); - - /// the number of characters read - std::size_t chars_read = 0; - - /// raw input token string (for error messages) - std::vector token_string {}; - - /// buffer for variable-length tokens (numbers, strings) - std::string yytext {}; - - /// a description of occurred lexer errors - const char* error_message = ""; - - // number values - number_integer_t value_integer = 0; - number_unsigned_t value_unsigned = 0; - number_float_t value_float = 0; - - /// the decimal point - const char decimal_point_char = '.'; -}; -} -} - -#endif - -/*** End of inlined file: lexer.hpp ***/ - - -/*** Start of inlined file: parser.hpp ***/ -#ifndef NLOHMANN_JSON_DETAIL_PARSING_PARSER_HPP -#define NLOHMANN_JSON_DETAIL_PARSING_PARSER_HPP - -#include // assert -#include // isfinite -#include // uint8_t -#include // function -#include // string -#include // move - - -/*** Start of inlined file: lexer.hpp ***/ -#ifndef NLOHMANN_JSON_DETAIL_PARSING_LEXER_HPP -#define NLOHMANN_JSON_DETAIL_PARSING_LEXER_HPP - -#include // localeconv -#include // size_t -#include // strtof, strtod, strtold, strtoll, strtoull -#include // initializer_list -#include // hex, uppercase -#include // setw, setfill -#include // stringstream -#include // char_traits, string -#include // vector - -namespace nlohmann -{ -namespace detail -{ -/////////// -// lexer // -/////////// - -/*! -@brief lexical analysis - -This class organizes the lexical analysis during JSON deserialization. -*/ -template -class lexer -{ - using number_integer_t = typename BasicJsonType::number_integer_t; - using number_unsigned_t = typename BasicJsonType::number_unsigned_t; - using number_float_t = typename BasicJsonType::number_float_t; - - public: - /// token types for the parser - enum class token_type - { - uninitialized, ///< indicating the scanner is uninitialized - literal_true, ///< the `true` literal - literal_false, ///< the `false` literal - literal_null, ///< the `null` literal - value_string, ///< a string -- use get_string() for actual value - value_unsigned, ///< an unsigned integer -- use get_number_unsigned() for actual value - value_integer, ///< a signed integer -- use get_number_integer() for actual value - value_float, ///< an floating point number -- use get_number_float() for actual value - begin_array, ///< the character for array begin `[` - begin_object, ///< the character for object begin `{` - end_array, ///< the character for array end `]` - end_object, ///< the character for object end `}` - name_separator, ///< the name separator `:` - value_separator, ///< the value separator `,` - parse_error, ///< indicating a parse error - end_of_input, ///< indicating the end of the input buffer - literal_or_value ///< a literal or the begin of a value (only for diagnostics) - }; - - /// return name of values of type token_type (only used for errors) - static const char* token_type_name(const token_type t) noexcept - { - switch (t) - { - case token_type::uninitialized: - return ""; - case token_type::literal_true: - return "true literal"; - case token_type::literal_false: - return "false literal"; - case token_type::literal_null: - return "null literal"; - case token_type::value_string: - return "string literal"; - case lexer::token_type::value_unsigned: - case lexer::token_type::value_integer: - case lexer::token_type::value_float: - return "number literal"; - case token_type::begin_array: - return "'['"; - case token_type::begin_object: - return "'{'"; - case token_type::end_array: - return "']'"; - case token_type::end_object: - return "'}'"; - case token_type::name_separator: - return "':'"; - case token_type::value_separator: - return "','"; - case token_type::parse_error: - return ""; - case token_type::end_of_input: - return "end of input"; - case token_type::literal_or_value: - return "'[', '{', or a literal"; - default: // catch non-enum values - return "unknown token"; // LCOV_EXCL_LINE - } - } - - explicit lexer(detail::input_adapter_t adapter) - : ia(std::move(adapter)), decimal_point_char(get_decimal_point()) {} - - // delete because of pointer members - lexer(const lexer&) = delete; - lexer& operator=(lexer&) = delete; - - private: - ///////////////////// - // locales - ///////////////////// - - /// return the locale-dependent decimal point - static char get_decimal_point() noexcept - { - const auto loc = localeconv(); - assert(loc != nullptr); - return (loc->decimal_point == nullptr) ? '.' : *(loc->decimal_point); - } - - ///////////////////// - // scan functions - ///////////////////// - - /*! - @brief get codepoint from 4 hex characters following `\u` - - For input "\u c1 c2 c3 c4" the codepoint is: - (c1 * 0x1000) + (c2 * 0x0100) + (c3 * 0x0010) + c4 - = (c1 << 12) + (c2 << 8) + (c3 << 4) + (c4 << 0) - - Furthermore, the possible characters '0'..'9', 'A'..'F', and 'a'..'f' - must be converted to the integers 0x0..0x9, 0xA..0xF, 0xA..0xF, resp. The - conversion is done by subtracting the offset (0x30, 0x37, and 0x57) - between the ASCII value of the character and the desired integer value. - - @return codepoint (0x0000..0xFFFF) or -1 in case of an error (e.g. EOF or - non-hex character) - */ - int get_codepoint() - { - // this function only makes sense after reading `\u` - assert(current == 'u'); - int codepoint = 0; - - const auto factors = { 12, 8, 4, 0 }; - for (const auto factor : factors) - { - get(); - - if (current >= '0' and current <= '9') - { - codepoint += ((current - 0x30) << factor); - } - else if (current >= 'A' and current <= 'F') - { - codepoint += ((current - 0x37) << factor); - } - else if (current >= 'a' and current <= 'f') - { - codepoint += ((current - 0x57) << factor); - } - else - { - return -1; - } - } - - assert(0x0000 <= codepoint and codepoint <= 0xFFFF); - return codepoint; - } - - /*! - @brief check if the next byte(s) are inside a given range - - Adds the current byte and, for each passed range, reads a new byte and - checks if it is inside the range. If a violation was detected, set up an - error message and return false. Otherwise, return true. - - @param[in] ranges list of integers; interpreted as list of pairs of - inclusive lower and upper bound, respectively - - @pre The passed list @a ranges must have 2, 4, or 6 elements; that is, - 1, 2, or 3 pairs. This precondition is enforced by an assertion. - - @return true if and only if no range violation was detected - */ - bool next_byte_in_range(std::initializer_list ranges) - { - assert(ranges.size() == 2 or ranges.size() == 4 or ranges.size() == 6); - add(current); - - for (auto range = ranges.begin(); range != ranges.end(); ++range) - { - get(); - if (JSON_LIKELY(*range <= current and current <= *(++range))) - { - add(current); - } - else - { - error_message = "invalid string: ill-formed UTF-8 byte"; - return false; - } - } - - return true; - } - - /*! - @brief scan a string literal - - This function scans a string according to Sect. 7 of RFC 7159. While - scanning, bytes are escaped and copied into buffer yytext. Then the function - returns successfully, yytext is *not* null-terminated (as it may contain \0 - bytes), and yytext.size() is the number of bytes in the string. - - @return token_type::value_string if string could be successfully scanned, - token_type::parse_error otherwise - - @note In case of errors, variable error_message contains a textual - description. - */ - token_type scan_string() - { - // reset yytext (ignore opening quote) - reset(); - - // we entered the function by reading an open quote - assert(current == '\"'); - - while (true) - { - // get next character - switch (get()) - { - // end of file while parsing string - case std::char_traits::eof(): - { - error_message = "invalid string: missing closing quote"; - return token_type::parse_error; - } - - // closing quote - case '\"': - { - return token_type::value_string; - } - - // escapes - case '\\': - { - switch (get()) - { - // quotation mark - case '\"': - add('\"'); - break; - // reverse solidus - case '\\': - add('\\'); - break; - // solidus - case '/': - add('/'); - break; - // backspace - case 'b': - add('\b'); - break; - // form feed - case 'f': - add('\f'); - break; - // line feed - case 'n': - add('\n'); - break; - // carriage return - case 'r': - add('\r'); - break; - // tab - case 't': - add('\t'); - break; - - // unicode escapes - case 'u': - { - const int codepoint1 = get_codepoint(); - int codepoint = codepoint1; // start with codepoint1 - - if (JSON_UNLIKELY(codepoint1 == -1)) - { - error_message = "invalid string: '\\u' must be followed by 4 hex digits"; - return token_type::parse_error; - } - - // check if code point is a high surrogate - if (0xD800 <= codepoint1 and codepoint1 <= 0xDBFF) - { - // expect next \uxxxx entry - if (JSON_LIKELY(get() == '\\' and get() == 'u')) - { - const int codepoint2 = get_codepoint(); - - if (JSON_UNLIKELY(codepoint2 == -1)) - { - error_message = "invalid string: '\\u' must be followed by 4 hex digits"; - return token_type::parse_error; - } - - // check if codepoint2 is a low surrogate - if (JSON_LIKELY(0xDC00 <= codepoint2 and codepoint2 <= 0xDFFF)) - { - // overwrite codepoint - codepoint = - // high surrogate occupies the most significant 22 bits - (codepoint1 << 10) - // low surrogate occupies the least significant 15 bits - + codepoint2 - // there is still the 0xD800, 0xDC00 and 0x10000 noise - // in the result so we have to subtract with: - // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00 - - 0x35FDC00; - } - else - { - error_message = "invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF"; - return token_type::parse_error; - } - } - else - { - error_message = "invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF"; - return token_type::parse_error; - } - } - else - { - if (JSON_UNLIKELY(0xDC00 <= codepoint1 and codepoint1 <= 0xDFFF)) - { - error_message = "invalid string: surrogate U+DC00..U+DFFF must follow U+D800..U+DBFF"; - return token_type::parse_error; - } - } - - // result of the above calculation yields a proper codepoint - assert(0x00 <= codepoint and codepoint <= 0x10FFFF); - - // translate codepoint into bytes - if (codepoint < 0x80) - { - // 1-byte characters: 0xxxxxxx (ASCII) - add(codepoint); - } - else if (codepoint <= 0x7FF) - { - // 2-byte characters: 110xxxxx 10xxxxxx - add(0xC0 | (codepoint >> 6)); - add(0x80 | (codepoint & 0x3F)); - } - else if (codepoint <= 0xFFFF) - { - // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx - add(0xE0 | (codepoint >> 12)); - add(0x80 | ((codepoint >> 6) & 0x3F)); - add(0x80 | (codepoint & 0x3F)); - } - else - { - // 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - add(0xF0 | (codepoint >> 18)); - add(0x80 | ((codepoint >> 12) & 0x3F)); - add(0x80 | ((codepoint >> 6) & 0x3F)); - add(0x80 | (codepoint & 0x3F)); - } - - break; - } - - // other characters after escape - default: - error_message = "invalid string: forbidden character after backslash"; - return token_type::parse_error; - } - - break; - } - - // invalid control characters - case 0x00: - case 0x01: - case 0x02: - case 0x03: - case 0x04: - case 0x05: - case 0x06: - case 0x07: - case 0x08: - case 0x09: - case 0x0A: - case 0x0B: - case 0x0C: - case 0x0D: - case 0x0E: - case 0x0F: - case 0x10: - case 0x11: - case 0x12: - case 0x13: - case 0x14: - case 0x15: - case 0x16: - case 0x17: - case 0x18: - case 0x19: - case 0x1A: - case 0x1B: - case 0x1C: - case 0x1D: - case 0x1E: - case 0x1F: - { - error_message = "invalid string: control character must be escaped"; - return token_type::parse_error; - } - - // U+0020..U+007F (except U+0022 (quote) and U+005C (backspace)) - case 0x20: - case 0x21: - case 0x23: - case 0x24: - case 0x25: - case 0x26: - case 0x27: - case 0x28: - case 0x29: - case 0x2A: - case 0x2B: - case 0x2C: - case 0x2D: - case 0x2E: - case 0x2F: - case 0x30: - case 0x31: - case 0x32: - case 0x33: - case 0x34: - case 0x35: - case 0x36: - case 0x37: - case 0x38: - case 0x39: - case 0x3A: - case 0x3B: - case 0x3C: - case 0x3D: - case 0x3E: - case 0x3F: - case 0x40: - case 0x41: - case 0x42: - case 0x43: - case 0x44: - case 0x45: - case 0x46: - case 0x47: - case 0x48: - case 0x49: - case 0x4A: - case 0x4B: - case 0x4C: - case 0x4D: - case 0x4E: - case 0x4F: - case 0x50: - case 0x51: - case 0x52: - case 0x53: - case 0x54: - case 0x55: - case 0x56: - case 0x57: - case 0x58: - case 0x59: - case 0x5A: - case 0x5B: - case 0x5D: - case 0x5E: - case 0x5F: - case 0x60: - case 0x61: - case 0x62: - case 0x63: - case 0x64: - case 0x65: - case 0x66: - case 0x67: - case 0x68: - case 0x69: - case 0x6A: - case 0x6B: - case 0x6C: - case 0x6D: - case 0x6E: - case 0x6F: - case 0x70: - case 0x71: - case 0x72: - case 0x73: - case 0x74: - case 0x75: - case 0x76: - case 0x77: - case 0x78: - case 0x79: - case 0x7A: - case 0x7B: - case 0x7C: - case 0x7D: - case 0x7E: - case 0x7F: - { - add(current); - break; - } - - // U+0080..U+07FF: bytes C2..DF 80..BF - case 0xC2: - case 0xC3: - case 0xC4: - case 0xC5: - case 0xC6: - case 0xC7: - case 0xC8: - case 0xC9: - case 0xCA: - case 0xCB: - case 0xCC: - case 0xCD: - case 0xCE: - case 0xCF: - case 0xD0: - case 0xD1: - case 0xD2: - case 0xD3: - case 0xD4: - case 0xD5: - case 0xD6: - case 0xD7: - case 0xD8: - case 0xD9: - case 0xDA: - case 0xDB: - case 0xDC: - case 0xDD: - case 0xDE: - case 0xDF: - { - if (JSON_UNLIKELY(not next_byte_in_range({0x80, 0xBF}))) - { - return token_type::parse_error; - } - break; - } - - // U+0800..U+0FFF: bytes E0 A0..BF 80..BF - case 0xE0: - { - if (JSON_UNLIKELY(not (next_byte_in_range({0xA0, 0xBF, 0x80, 0xBF})))) - { - return token_type::parse_error; - } - break; - } - - // U+1000..U+CFFF: bytes E1..EC 80..BF 80..BF - // U+E000..U+FFFF: bytes EE..EF 80..BF 80..BF - case 0xE1: - case 0xE2: - case 0xE3: - case 0xE4: - case 0xE5: - case 0xE6: - case 0xE7: - case 0xE8: - case 0xE9: - case 0xEA: - case 0xEB: - case 0xEC: - case 0xEE: - case 0xEF: - { - if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0xBF, 0x80, 0xBF})))) - { - return token_type::parse_error; - } - break; - } - - // U+D000..U+D7FF: bytes ED 80..9F 80..BF - case 0xED: - { - if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0x9F, 0x80, 0xBF})))) - { - return token_type::parse_error; - } - break; - } - - // U+10000..U+3FFFF F0 90..BF 80..BF 80..BF - case 0xF0: - { - if (JSON_UNLIKELY(not (next_byte_in_range({0x90, 0xBF, 0x80, 0xBF, 0x80, 0xBF})))) - { - return token_type::parse_error; - } - break; - } - - // U+40000..U+FFFFF F1..F3 80..BF 80..BF 80..BF - case 0xF1: - case 0xF2: - case 0xF3: - { - if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0xBF, 0x80, 0xBF, 0x80, 0xBF})))) - { - return token_type::parse_error; - } - break; - } - - // U+100000..U+10FFFF F4 80..8F 80..BF 80..BF - case 0xF4: - { - if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0x8F, 0x80, 0xBF, 0x80, 0xBF})))) - { - return token_type::parse_error; - } - break; - } - - // remaining bytes (80..C1 and F5..FF) are ill-formed - default: - { - error_message = "invalid string: ill-formed UTF-8 byte"; - return token_type::parse_error; - } - } - } - } - - static void strtof(float& f, const char* str, char** endptr) noexcept - { - f = std::strtof(str, endptr); - } - - static void strtof(double& f, const char* str, char** endptr) noexcept - { - f = std::strtod(str, endptr); - } - - static void strtof(long double& f, const char* str, char** endptr) noexcept - { - f = std::strtold(str, endptr); - } - - /*! - @brief scan a number literal - - This function scans a string according to Sect. 6 of RFC 7159. - - The function is realized with a deterministic finite state machine derived - from the grammar described in RFC 7159. Starting in state "init", the - input is read and used to determined the next state. Only state "done" - accepts the number. State "error" is a trap state to model errors. In the - table below, "anything" means any character but the ones listed before. - - state | 0 | 1-9 | e E | + | - | . | anything - ---------|----------|----------|----------|---------|---------|----------|----------- - init | zero | any1 | [error] | [error] | minus | [error] | [error] - minus | zero | any1 | [error] | [error] | [error] | [error] | [error] - zero | done | done | exponent | done | done | decimal1 | done - any1 | any1 | any1 | exponent | done | done | decimal1 | done - decimal1 | decimal2 | [error] | [error] | [error] | [error] | [error] | [error] - decimal2 | decimal2 | decimal2 | exponent | done | done | done | done - exponent | any2 | any2 | [error] | sign | sign | [error] | [error] - sign | any2 | any2 | [error] | [error] | [error] | [error] | [error] - any2 | any2 | any2 | done | done | done | done | done - - The state machine is realized with one label per state (prefixed with - "scan_number_") and `goto` statements between them. The state machine - contains cycles, but any cycle can be left when EOF is read. Therefore, - the function is guaranteed to terminate. - - During scanning, the read bytes are stored in yytext. This string is - then converted to a signed integer, an unsigned integer, or a - floating-point number. - - @return token_type::value_unsigned, token_type::value_integer, or - token_type::value_float if number could be successfully scanned, - token_type::parse_error otherwise - - @note The scanner is independent of the current locale. Internally, the - locale's decimal point is used instead of `.` to work with the - locale-dependent converters. - */ - token_type scan_number() - { - // reset yytext to store the number's bytes - reset(); - - // the type of the parsed number; initially set to unsigned; will be - // changed if minus sign, decimal point or exponent is read - token_type number_type = token_type::value_unsigned; - - // state (init): we just found out we need to scan a number - switch (current) - { - case '-': - { - add(current); - goto scan_number_minus; - } - - case '0': - { - add(current); - goto scan_number_zero; - } - - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_any1; - } - - default: - { - // all other characters are rejected outside scan_number() - assert(false); // LCOV_EXCL_LINE - } - } - -scan_number_minus: - // state: we just parsed a leading minus sign - number_type = token_type::value_integer; - switch (get()) - { - case '0': - { - add(current); - goto scan_number_zero; - } - - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_any1; - } - - default: - { - error_message = "invalid number; expected digit after '-'"; - return token_type::parse_error; - } - } - -scan_number_zero: - // state: we just parse a zero (maybe with a leading minus sign) - switch (get()) - { - case '.': - { - add(decimal_point_char); - goto scan_number_decimal1; - } - - case 'e': - case 'E': - { - add(current); - goto scan_number_exponent; - } - - default: - goto scan_number_done; - } - -scan_number_any1: - // state: we just parsed a number 0-9 (maybe with a leading minus sign) - switch (get()) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_any1; - } - - case '.': - { - add(decimal_point_char); - goto scan_number_decimal1; - } - - case 'e': - case 'E': - { - add(current); - goto scan_number_exponent; - } - - default: - goto scan_number_done; - } - -scan_number_decimal1: - // state: we just parsed a decimal point - number_type = token_type::value_float; - switch (get()) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_decimal2; - } - - default: - { - error_message = "invalid number; expected digit after '.'"; - return token_type::parse_error; - } - } - -scan_number_decimal2: - // we just parsed at least one number after a decimal point - switch (get()) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_decimal2; - } - - case 'e': - case 'E': - { - add(current); - goto scan_number_exponent; - } - - default: - goto scan_number_done; - } - -scan_number_exponent: - // we just parsed an exponent - number_type = token_type::value_float; - switch (get()) - { - case '+': - case '-': - { - add(current); - goto scan_number_sign; - } - - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_any2; - } - - default: - { - error_message = - "invalid number; expected '+', '-', or digit after exponent"; - return token_type::parse_error; - } - } - -scan_number_sign: - // we just parsed an exponent sign - switch (get()) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_any2; - } - - default: - { - error_message = "invalid number; expected digit after exponent sign"; - return token_type::parse_error; - } - } - -scan_number_any2: - // we just parsed a number after the exponent or exponent sign - switch (get()) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_any2; - } - - default: - goto scan_number_done; - } - -scan_number_done: - // unget the character after the number (we only read it to know that - // we are done scanning a number) - unget(); - - char* endptr = nullptr; - errno = 0; - - // try to parse integers first and fall back to floats - if (number_type == token_type::value_unsigned) - { - const auto x = std::strtoull(yytext.data(), &endptr, 10); - - // we checked the number format before - assert(endptr == yytext.data() + yytext.size()); - - if (errno == 0) - { - value_unsigned = static_cast(x); - if (value_unsigned == x) - { - return token_type::value_unsigned; - } - } - } - else if (number_type == token_type::value_integer) - { - const auto x = std::strtoll(yytext.data(), &endptr, 10); - - // we checked the number format before - assert(endptr == yytext.data() + yytext.size()); - - if (errno == 0) - { - value_integer = static_cast(x); - if (value_integer == x) - { - return token_type::value_integer; - } - } - } - - // this code is reached if we parse a floating-point number or if an - // integer conversion above failed - strtof(value_float, yytext.data(), &endptr); - - // we checked the number format before - assert(endptr == yytext.data() + yytext.size()); - - return token_type::value_float; - } - - /*! - @param[in] literal_text the literal text to expect - @param[in] length the length of the passed literal text - @param[in] return_type the token type to return on success - */ - token_type scan_literal(const char* literal_text, const std::size_t length, - token_type return_type) - { - assert(current == literal_text[0]); - for (std::size_t i = 1; i < length; ++i) - { - if (JSON_UNLIKELY(get() != literal_text[i])) - { - error_message = "invalid literal"; - return token_type::parse_error; - } - } - return return_type; - } - - ///////////////////// - // input management - ///////////////////// - - /// reset yytext; current character is beginning of token - void reset() noexcept - { - yytext.clear(); - token_string.clear(); - token_string.push_back(std::char_traits::to_char_type(current)); - } - - /* - @brief get next character from the input - - This function provides the interface to the used input adapter. It does - not throw in case the input reached EOF, but returns a - `std::char_traits::eof()` in that case. Stores the scanned characters - for use in error messages. - - @return character read from the input - */ - std::char_traits::int_type get() - { - ++chars_read; - current = ia->get_character(); - if (JSON_LIKELY(current != std::char_traits::eof())) - { - token_string.push_back(std::char_traits::to_char_type(current)); - } - return current; - } - - /// unget current character (return it again on next get) - void unget() - { - --chars_read; - if (JSON_LIKELY(current != std::char_traits::eof())) - { - ia->unget_character(); - assert(token_string.size() != 0); - token_string.pop_back(); - } - } - - /// add a character to yytext - void add(int c) - { - yytext.push_back(std::char_traits::to_char_type(c)); - } - - public: - ///////////////////// - // value getters - ///////////////////// - - /// return integer value - constexpr number_integer_t get_number_integer() const noexcept - { - return value_integer; - } - - /// return unsigned integer value - constexpr number_unsigned_t get_number_unsigned() const noexcept - { - return value_unsigned; - } - - /// return floating-point value - constexpr number_float_t get_number_float() const noexcept - { - return value_float; - } - - /// return current string value (implicitly resets the token; useful only once) - std::string move_string() - { - return std::move(yytext); - } - - ///////////////////// - // diagnostics - ///////////////////// - - /// return position of last read token - constexpr std::size_t get_position() const noexcept - { - return chars_read; - } - - /// return the last read token (for errors only). Will never contain EOF - /// (an arbitrary value that is not a valid char value, often -1), because - /// 255 may legitimately occur. May contain NUL, which should be escaped. - std::string get_token_string() const - { - // escape control characters - std::string result; - for (const auto c : token_string) - { - if ('\x00' <= c and c <= '\x1F') - { - // escape control characters - std::stringstream ss; - ss << "(c) << ">"; - result += ss.str(); - } - else - { - // add character as is - result.push_back(c); - } - } - - return result; - } - - /// return syntax error message - constexpr const char* get_error_message() const noexcept - { - return error_message; - } - - ///////////////////// - // actual scanner - ///////////////////// - - token_type scan() - { - // read next character and ignore whitespace - do - { - get(); - } - while (current == ' ' or current == '\t' or current == '\n' or current == '\r'); - - switch (current) - { - // structural characters - case '[': - return token_type::begin_array; - case ']': - return token_type::end_array; - case '{': - return token_type::begin_object; - case '}': - return token_type::end_object; - case ':': - return token_type::name_separator; - case ',': - return token_type::value_separator; - - // literals - case 't': - return scan_literal("true", 4, token_type::literal_true); - case 'f': - return scan_literal("false", 5, token_type::literal_false); - case 'n': - return scan_literal("null", 4, token_type::literal_null); - - // string - case '\"': - return scan_string(); - - // number - case '-': - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - return scan_number(); - - // end of input (the null byte is needed when parsing from - // string literals) - case '\0': - case std::char_traits::eof(): - return token_type::end_of_input; - - // error - default: - error_message = "invalid literal"; - return token_type::parse_error; - } - } - - private: - /// input adapter - detail::input_adapter_t ia = nullptr; - - /// the current character - std::char_traits::int_type current = std::char_traits::eof(); - - /// the number of characters read - std::size_t chars_read = 0; - - /// raw input token string (for error messages) - std::vector token_string {}; - - /// buffer for variable-length tokens (numbers, strings) - std::string yytext {}; - - /// a description of occurred lexer errors - const char* error_message = ""; - - // number values - number_integer_t value_integer = 0; - number_unsigned_t value_unsigned = 0; - number_float_t value_float = 0; - - /// the decimal point - const char decimal_point_char = '.'; -}; -} -} - -#endif - -/*** End of inlined file: lexer.hpp ***/ - -namespace nlohmann -{ -namespace detail -{ -//////////// -// parser // -//////////// - -/*! -@brief syntax analysis - -This class implements a recursive decent parser. -*/ -template -class parser -{ - using number_integer_t = typename BasicJsonType::number_integer_t; - using number_unsigned_t = typename BasicJsonType::number_unsigned_t; - using number_float_t = typename BasicJsonType::number_float_t; - using lexer_t = lexer; - using token_type = typename lexer_t::token_type; - - public: - enum class parse_event_t : uint8_t - { - /// the parser read `{` and started to process a JSON object - object_start, - /// the parser read `}` and finished processing a JSON object - object_end, - /// the parser read `[` and started to process a JSON array - array_start, - /// the parser read `]` and finished processing a JSON array - array_end, - /// the parser read a key of a value in an object - key, - /// the parser finished reading a JSON value - value - }; - - using parser_callback_t = - std::function; - - /// a parser reading from an input adapter - explicit parser(detail::input_adapter_t adapter, - const parser_callback_t cb = nullptr, - const bool allow_exceptions_ = true) - : callback(cb), m_lexer(adapter), allow_exceptions(allow_exceptions_) - {} - - /*! - @brief public parser interface - - @param[in] strict whether to expect the last token to be EOF - @param[in,out] result parsed JSON value - - @throw parse_error.101 in case of an unexpected token - @throw parse_error.102 if to_unicode fails or surrogate error - @throw parse_error.103 if to_unicode fails - */ - void parse(const bool strict, BasicJsonType& result) - { - // read first token - get_token(); - - parse_internal(true, result); - result.assert_invariant(); - - // in strict mode, input must be completely read - if (strict) - { - get_token(); - expect(token_type::end_of_input); - } - - // in case of an error, return discarded value - if (errored) - { - result = value_t::discarded; - return; - } - - // set top-level value to null if it was discarded by the callback - // function - if (result.is_discarded()) - { - result = nullptr; - } - } - - /*! - @brief public accept interface - - @param[in] strict whether to expect the last token to be EOF - @return whether the input is a proper JSON text - */ - bool accept(const bool strict = true) - { - // read first token - get_token(); - - if (not accept_internal()) - { - return false; - } - - // strict => last token must be EOF - return not strict or (get_token() == token_type::end_of_input); - } - - private: - /*! - @brief the actual parser - @throw parse_error.101 in case of an unexpected token - @throw parse_error.102 if to_unicode fails or surrogate error - @throw parse_error.103 if to_unicode fails - */ - void parse_internal(bool keep, BasicJsonType& result) - { - // never parse after a parse error was detected - assert(not errored); - - // start with a discarded value - if (not result.is_discarded()) - { - result.m_value.destroy(result.m_type); - result.m_type = value_t::discarded; - } - - switch (last_token) - { - case token_type::begin_object: - { - if (keep) - { - if (callback) - { - keep = callback(depth++, parse_event_t::object_start, result); - } - - if (not callback or keep) - { - // explicitly set result to object to cope with {} - result.m_type = value_t::object; - result.m_value = value_t::object; - } - } - - // read next token - get_token(); - - // closing } -> we are done - if (last_token == token_type::end_object) - { - if (keep and callback and not callback(--depth, parse_event_t::object_end, result)) - { - result.m_value.destroy(result.m_type); - result.m_type = value_t::discarded; - } - break; - } - - // parse values - std::string key; - BasicJsonType value; - while (true) - { - // store key - if (not expect(token_type::value_string)) - { - return; - } - key = m_lexer.move_string(); - - bool keep_tag = false; - if (keep) - { - if (callback) - { - BasicJsonType k(key); - keep_tag = callback(depth, parse_event_t::key, k); - } - else - { - keep_tag = true; - } - } - - // parse separator (:) - get_token(); - if (not expect(token_type::name_separator)) - { - return; - } - - // parse and add value - get_token(); - value.m_value.destroy(value.m_type); - value.m_type = value_t::discarded; - parse_internal(keep, value); - - if (JSON_UNLIKELY(errored)) - { - return; - } - - if (keep and keep_tag and not value.is_discarded()) - { - result.m_value.object->emplace(std::move(key), std::move(value)); - } - - // comma -> next value - get_token(); - if (last_token == token_type::value_separator) - { - get_token(); - continue; - } - - // closing } - if (not expect(token_type::end_object)) - { - return; - } - break; - } - - if (keep and callback and not callback(--depth, parse_event_t::object_end, result)) - { - result.m_value.destroy(result.m_type); - result.m_type = value_t::discarded; - } - break; - } - - case token_type::begin_array: - { - if (keep) - { - if (callback) - { - keep = callback(depth++, parse_event_t::array_start, result); - } - - if (not callback or keep) - { - // explicitly set result to array to cope with [] - result.m_type = value_t::array; - result.m_value = value_t::array; - } - } - - // read next token - get_token(); - - // closing ] -> we are done - if (last_token == token_type::end_array) - { - if (callback and not callback(--depth, parse_event_t::array_end, result)) - { - result.m_value.destroy(result.m_type); - result.m_type = value_t::discarded; - } - break; - } - - // parse values - BasicJsonType value; - while (true) - { - // parse value - value.m_value.destroy(value.m_type); - value.m_type = value_t::discarded; - parse_internal(keep, value); - - if (JSON_UNLIKELY(errored)) - { - return; - } - - if (keep and not value.is_discarded()) - { - result.m_value.array->push_back(std::move(value)); - } - - // comma -> next value - get_token(); - if (last_token == token_type::value_separator) - { - get_token(); - continue; - } - - // closing ] - if (not expect(token_type::end_array)) - { - return; - } - break; - } - - if (keep and callback and not callback(--depth, parse_event_t::array_end, result)) - { - result.m_value.destroy(result.m_type); - result.m_type = value_t::discarded; - } - break; - } - - case token_type::literal_null: - { - result.m_type = value_t::null; - break; - } - - case token_type::value_string: - { - result.m_type = value_t::string; - result.m_value = m_lexer.move_string(); - break; - } - - case token_type::literal_true: - { - result.m_type = value_t::boolean; - result.m_value = true; - break; - } - - case token_type::literal_false: - { - result.m_type = value_t::boolean; - result.m_value = false; - break; - } - - case token_type::value_unsigned: - { - result.m_type = value_t::number_unsigned; - result.m_value = m_lexer.get_number_unsigned(); - break; - } - - case token_type::value_integer: - { - result.m_type = value_t::number_integer; - result.m_value = m_lexer.get_number_integer(); - break; - } - - case token_type::value_float: - { - result.m_type = value_t::number_float; - result.m_value = m_lexer.get_number_float(); - - // throw in case of infinity or NAN - if (JSON_UNLIKELY(not std::isfinite(result.m_value.number_float))) - { - if (allow_exceptions) - { - JSON_THROW(out_of_range::create(406, "number overflow parsing '" + - m_lexer.get_token_string() + "'")); - } - expect(token_type::uninitialized); - } - break; - } - - case token_type::parse_error: - { - // using "uninitialized" to avoid "expected" message - if (not expect(token_type::uninitialized)) - { - return; - } - break; // LCOV_EXCL_LINE - } - - default: - { - // the last token was unexpected; we expected a value - if (not expect(token_type::literal_or_value)) - { - return; - } - break; // LCOV_EXCL_LINE - } - } - - if (keep and callback and not callback(depth, parse_event_t::value, result)) - { - result.m_type = value_t::discarded; - } - } - - /*! - @brief the actual acceptor - - @invariant 1. The last token is not yet processed. Therefore, the caller - of this function must make sure a token has been read. - 2. When this function returns, the last token is processed. - That is, the last read character was already considered. - - This invariant makes sure that no token needs to be "unput". - */ - bool accept_internal() - { - switch (last_token) - { - case token_type::begin_object: - { - // read next token - get_token(); - - // closing } -> we are done - if (last_token == token_type::end_object) - { - return true; - } - - // parse values - while (true) - { - // parse key - if (last_token != token_type::value_string) - { - return false; - } - - // parse separator (:) - get_token(); - if (last_token != token_type::name_separator) - { - return false; - } - - // parse value - get_token(); - if (not accept_internal()) - { - return false; - } - - // comma -> next value - get_token(); - if (last_token == token_type::value_separator) - { - get_token(); - continue; - } - - // closing } - return (last_token == token_type::end_object); - } - } - - case token_type::begin_array: - { - // read next token - get_token(); - - // closing ] -> we are done - if (last_token == token_type::end_array) - { - return true; - } - - // parse values - while (true) - { - // parse value - if (not accept_internal()) - { - return false; - } - - // comma -> next value - get_token(); - if (last_token == token_type::value_separator) - { - get_token(); - continue; - } - - // closing ] - return (last_token == token_type::end_array); - } - } - - case token_type::value_float: - { - // reject infinity or NAN - return std::isfinite(m_lexer.get_number_float()); - } - - case token_type::literal_false: - case token_type::literal_null: - case token_type::literal_true: - case token_type::value_integer: - case token_type::value_string: - case token_type::value_unsigned: - return true; - - default: // the last token was unexpected - return false; - } - } - - /// get next token from lexer - token_type get_token() - { - return (last_token = m_lexer.scan()); - } - - /*! - @throw parse_error.101 if expected token did not occur - */ - bool expect(token_type t) - { - if (JSON_UNLIKELY(t != last_token)) - { - errored = true; - expected = t; - if (allow_exceptions) - { - throw_exception(); - } - else - { - return false; - } - } - - return true; - } - - [[noreturn]] void throw_exception() const - { - std::string error_msg = "syntax error - "; - if (last_token == token_type::parse_error) - { - error_msg += std::string(m_lexer.get_error_message()) + "; last read: '" + - m_lexer.get_token_string() + "'"; - } - else - { - error_msg += "unexpected " + std::string(lexer_t::token_type_name(last_token)); - } - - if (expected != token_type::uninitialized) - { - error_msg += "; expected " + std::string(lexer_t::token_type_name(expected)); - } - - JSON_THROW(parse_error::create(101, m_lexer.get_position(), error_msg)); - } - - private: - /// current level of recursion - int depth = 0; - /// callback function - const parser_callback_t callback = nullptr; - /// the type of the last read token - token_type last_token = token_type::uninitialized; - /// the lexer - lexer_t m_lexer; - /// whether a syntax error occurred - bool errored = false; - /// possible reason for the syntax error - token_type expected = token_type::uninitialized; - /// whether to throw exceptions in case of errors - const bool allow_exceptions = true; -}; -} -} - -#endif - -/*** End of inlined file: parser.hpp ***/ - - -/*** Start of inlined file: primitive_iterator.hpp ***/ -#ifndef NLOHMANN_JSON_DETAIL_ITERATORS_PRIMITIVE_ITERATOR_HPP -#define NLOHMANN_JSON_DETAIL_ITERATORS_PRIMITIVE_ITERATOR_HPP - -#include // not -#include // ptrdiff_t -#include // numeric_limits -#include // ostream - -namespace nlohmann -{ -namespace detail -{ -/* -@brief an iterator for primitive JSON types - -This class models an iterator for primitive JSON types (boolean, number, -string). It's only purpose is to allow the iterator/const_iterator classes -to "iterate" over primitive values. Internally, the iterator is modeled by -a `difference_type` variable. Value begin_value (`0`) models the begin, -end_value (`1`) models past the end. -*/ -class primitive_iterator_t -{ - public: - using difference_type = std::ptrdiff_t; - - constexpr difference_type get_value() const noexcept - { - return m_it; - } - - /// set iterator to a defined beginning - void set_begin() noexcept - { - m_it = begin_value; - } - - /// set iterator to a defined past the end - void set_end() noexcept - { - m_it = end_value; - } - - /// return whether the iterator can be dereferenced - constexpr bool is_begin() const noexcept - { - return m_it == begin_value; - } - - /// return whether the iterator is at end - constexpr bool is_end() const noexcept - { - return m_it == end_value; - } - - friend constexpr bool operator==(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept - { - return lhs.m_it == rhs.m_it; - } - - friend constexpr bool operator<(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept - { - return lhs.m_it < rhs.m_it; - } - - primitive_iterator_t operator+(difference_type i) - { - auto result = *this; - result += i; - return result; - } - - friend constexpr difference_type operator-(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept - { - return lhs.m_it - rhs.m_it; - } - - friend std::ostream& operator<<(std::ostream& os, primitive_iterator_t it) - { - return os << it.m_it; - } - - primitive_iterator_t& operator++() - { - ++m_it; - return *this; - } - - primitive_iterator_t const operator++(int) - { - auto result = *this; - m_it++; - return result; - } - - primitive_iterator_t& operator--() - { - --m_it; - return *this; - } - - primitive_iterator_t const operator--(int) - { - auto result = *this; - m_it--; - return result; - } - - primitive_iterator_t& operator+=(difference_type n) - { - m_it += n; - return *this; - } - - primitive_iterator_t& operator-=(difference_type n) - { - m_it -= n; - return *this; - } - - private: - static constexpr difference_type begin_value = 0; - static constexpr difference_type end_value = begin_value + 1; - - /// iterator as signed integer type - difference_type m_it = (std::numeric_limits::min)(); -}; -} -} - -#endif - -/*** End of inlined file: primitive_iterator.hpp ***/ - - -/*** Start of inlined file: internal_iterator.hpp ***/ -#ifndef NLOHMANN_JSON_DETAIL_ITERATORS_INTERNAL_ITERATOR_HPP -#define NLOHMANN_JSON_DETAIL_ITERATORS_INTERNAL_ITERATOR_HPP - - -/*** Start of inlined file: primitive_iterator.hpp ***/ -#ifndef NLOHMANN_JSON_DETAIL_ITERATORS_PRIMITIVE_ITERATOR_HPP -#define NLOHMANN_JSON_DETAIL_ITERATORS_PRIMITIVE_ITERATOR_HPP - -#include // not -#include // ptrdiff_t -#include // numeric_limits -#include // ostream - -namespace nlohmann -{ -namespace detail -{ -/* -@brief an iterator for primitive JSON types - -This class models an iterator for primitive JSON types (boolean, number, -string). It's only purpose is to allow the iterator/const_iterator classes -to "iterate" over primitive values. Internally, the iterator is modeled by -a `difference_type` variable. Value begin_value (`0`) models the begin, -end_value (`1`) models past the end. -*/ -class primitive_iterator_t -{ - public: - using difference_type = std::ptrdiff_t; - - constexpr difference_type get_value() const noexcept - { - return m_it; - } - - /// set iterator to a defined beginning - void set_begin() noexcept - { - m_it = begin_value; - } - - /// set iterator to a defined past the end - void set_end() noexcept - { - m_it = end_value; - } - - /// return whether the iterator can be dereferenced - constexpr bool is_begin() const noexcept - { - return m_it == begin_value; - } - - /// return whether the iterator is at end - constexpr bool is_end() const noexcept - { - return m_it == end_value; - } - - friend constexpr bool operator==(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept - { - return lhs.m_it == rhs.m_it; - } - - friend constexpr bool operator<(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept - { - return lhs.m_it < rhs.m_it; - } - - primitive_iterator_t operator+(difference_type i) - { - auto result = *this; - result += i; - return result; - } - - friend constexpr difference_type operator-(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept - { - return lhs.m_it - rhs.m_it; - } - - friend std::ostream& operator<<(std::ostream& os, primitive_iterator_t it) - { - return os << it.m_it; - } - - primitive_iterator_t& operator++() - { - ++m_it; - return *this; - } - - primitive_iterator_t const operator++(int) - { - auto result = *this; - m_it++; - return result; - } - - primitive_iterator_t& operator--() - { - --m_it; - return *this; - } - - primitive_iterator_t const operator--(int) - { - auto result = *this; - m_it--; - return result; - } - - primitive_iterator_t& operator+=(difference_type n) - { - m_it += n; - return *this; - } - - primitive_iterator_t& operator-=(difference_type n) - { - m_it -= n; - return *this; - } - - private: - static constexpr difference_type begin_value = 0; - static constexpr difference_type end_value = begin_value + 1; - - /// iterator as signed integer type - difference_type m_it = (std::numeric_limits::min)(); -}; -} -} - -#endif - -/*** End of inlined file: primitive_iterator.hpp ***/ - -namespace nlohmann -{ -namespace detail -{ -/*! -@brief an iterator value - -@note This structure could easily be a union, but MSVC currently does not allow -unions members with complex constructors, see https://github.com/nlohmann/json/pull/105. -*/ -template struct internal_iterator -{ - /// iterator for JSON objects - typename BasicJsonType::object_t::iterator object_iterator {}; - /// iterator for JSON arrays - typename BasicJsonType::array_t::iterator array_iterator {}; - /// generic iterator for all other types - primitive_iterator_t primitive_iterator {}; -}; -} -} - -#endif - -/*** End of inlined file: internal_iterator.hpp ***/ - - -/*** Start of inlined file: iter_impl.hpp ***/ -#ifndef NLOHMANN_JSON_DETAIL_ITERATORS_ITER_IMPL_HPP -#define NLOHMANN_JSON_DETAIL_ITERATORS_ITER_IMPL_HPP - -#include // not -#include // iterator, random_access_iterator_tag, bidirectional_iterator_tag, advance, next -#include // conditional, is_const, remove_const - - -/*** Start of inlined file: internal_iterator.hpp ***/ -#ifndef NLOHMANN_JSON_DETAIL_ITERATORS_INTERNAL_ITERATOR_HPP -#define NLOHMANN_JSON_DETAIL_ITERATORS_INTERNAL_ITERATOR_HPP - -namespace nlohmann -{ -namespace detail -{ -/*! -@brief an iterator value - -@note This structure could easily be a union, but MSVC currently does not allow -unions members with complex constructors, see https://github.com/nlohmann/json/pull/105. -*/ -template struct internal_iterator -{ - /// iterator for JSON objects - typename BasicJsonType::object_t::iterator object_iterator {}; - /// iterator for JSON arrays - typename BasicJsonType::array_t::iterator array_iterator {}; - /// generic iterator for all other types - primitive_iterator_t primitive_iterator {}; -}; -} -} - -#endif - -/*** End of inlined file: internal_iterator.hpp ***/ - -namespace nlohmann -{ -namespace detail -{ -// forward declare, to be able to friend it later on -template class iteration_proxy; - -/*! -@brief a template for a bidirectional iterator for the @ref basic_json class - -This class implements a both iterators (iterator and const_iterator) for the -@ref basic_json class. - -@note An iterator is called *initialized* when a pointer to a JSON value has - been set (e.g., by a constructor or a copy assignment). If the iterator is - default-constructed, it is *uninitialized* and most methods are undefined. - **The library uses assertions to detect calls on uninitialized iterators.** - -@requirement The class satisfies the following concept requirements: -- -[BidirectionalIterator](http://en.cppreference.com/w/cpp/concept/BidirectionalIterator): - The iterator that can be moved can be moved in both directions (i.e. - incremented and decremented). - -@since version 1.0.0, simplified in version 2.0.9, change to bidirectional - iterators in version 3.0.0 (see https://github.com/nlohmann/json/issues/593) -*/ -template -class iter_impl -{ - /// allow basic_json to access private members - friend iter_impl::value, typename std::remove_const::type, const BasicJsonType>::type>; - friend BasicJsonType; - friend iteration_proxy; - - using object_t = typename BasicJsonType::object_t; - using array_t = typename BasicJsonType::array_t; - // make sure BasicJsonType is basic_json or const basic_json - static_assert(is_basic_json::type>::value, - "iter_impl only accepts (const) basic_json"); - - public: - - /// The std::iterator class template (used as a base class to provide typedefs) is deprecated in C++17. - /// The C++ Standard has never required user-defined iterators to derive from std::iterator. - /// A user-defined iterator should provide publicly accessible typedefs named - /// iterator_category, value_type, difference_type, pointer, and reference. - /// Note that value_type is required to be non-const, even for constant iterators. - using iterator_category = std::bidirectional_iterator_tag; - - /// the type of the values when the iterator is dereferenced - using value_type = typename BasicJsonType::value_type; - /// a type to represent differences between iterators - using difference_type = typename BasicJsonType::difference_type; - /// defines a pointer to the type iterated over (value_type) - using pointer = typename std::conditional::value, - typename BasicJsonType::const_pointer, - typename BasicJsonType::pointer>::type; - /// defines a reference to the type iterated over (value_type) - using reference = - typename std::conditional::value, - typename BasicJsonType::const_reference, - typename BasicJsonType::reference>::type; - - /// default constructor - iter_impl() = default; - - /*! - @brief constructor for a given JSON instance - @param[in] object pointer to a JSON object for this iterator - @pre object != nullptr - @post The iterator is initialized; i.e. `m_object != nullptr`. - */ - explicit iter_impl(pointer object) noexcept : m_object(object) - { - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case value_t::object: - { - m_it.object_iterator = typename object_t::iterator(); - break; - } - - case value_t::array: - { - m_it.array_iterator = typename array_t::iterator(); - break; - } - - default: - { - m_it.primitive_iterator = primitive_iterator_t(); - break; - } - } - } - - /*! - @note The conventional copy constructor and copy assignment are implicitly - defined. Combined with the following converting constructor and - assignment, they support: (1) copy from iterator to iterator, (2) - copy from const iterator to const iterator, and (3) conversion from - iterator to const iterator. However conversion from const iterator - to iterator is not defined. - */ - - /*! - @brief converting constructor - @param[in] other non-const iterator to copy from - @note It is not checked whether @a other is initialized. - */ - iter_impl(const iter_impl::type>& other) noexcept - : m_object(other.m_object), m_it(other.m_it) {} - - /*! - @brief converting assignment - @param[in,out] other non-const iterator to copy from - @return const/non-const iterator - @note It is not checked whether @a other is initialized. - */ - iter_impl& operator=(const iter_impl::type>& other) noexcept - { - m_object = other.m_object; - m_it = other.m_it; - return *this; - } - - private: - /*! - @brief set the iterator to the first value - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - void set_begin() noexcept - { - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case value_t::object: - { - m_it.object_iterator = m_object->m_value.object->begin(); - break; - } - - case value_t::array: - { - m_it.array_iterator = m_object->m_value.array->begin(); - break; - } - - case value_t::null: - { - // set to end so begin()==end() is true: null is empty - m_it.primitive_iterator.set_end(); - break; - } - - default: - { - m_it.primitive_iterator.set_begin(); - break; - } - } - } - - /*! - @brief set the iterator past the last value - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - void set_end() noexcept - { - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case value_t::object: - { - m_it.object_iterator = m_object->m_value.object->end(); - break; - } - - case value_t::array: - { - m_it.array_iterator = m_object->m_value.array->end(); - break; - } - - default: - { - m_it.primitive_iterator.set_end(); - break; - } - } - } - - public: - /*! - @brief return a reference to the value pointed to by the iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - reference operator*() const - { - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case value_t::object: - { - assert(m_it.object_iterator != m_object->m_value.object->end()); - return m_it.object_iterator->second; - } - - case value_t::array: - { - assert(m_it.array_iterator != m_object->m_value.array->end()); - return *m_it.array_iterator; - } - - case value_t::null: - JSON_THROW(invalid_iterator::create(214, "cannot get value")); - - default: - { - if (JSON_LIKELY(m_it.primitive_iterator.is_begin())) - { - return *m_object; - } - - JSON_THROW(invalid_iterator::create(214, "cannot get value")); - } - } - } - - /*! - @brief dereference the iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - pointer operator->() const - { - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case value_t::object: - { - assert(m_it.object_iterator != m_object->m_value.object->end()); - return &(m_it.object_iterator->second); - } - - case value_t::array: - { - assert(m_it.array_iterator != m_object->m_value.array->end()); - return &*m_it.array_iterator; - } - - default: - { - if (JSON_LIKELY(m_it.primitive_iterator.is_begin())) - { - return m_object; - } - - JSON_THROW(invalid_iterator::create(214, "cannot get value")); - } - } - } - - /*! - @brief post-increment (it++) - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - iter_impl const operator++(int) - { - auto result = *this; - ++(*this); - return result; - } - - /*! - @brief pre-increment (++it) - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - iter_impl& operator++() - { - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case value_t::object: - { - std::advance(m_it.object_iterator, 1); - break; - } - - case value_t::array: - { - std::advance(m_it.array_iterator, 1); - break; - } - - default: - { - ++m_it.primitive_iterator; - break; - } - } - - return *this; - } - - /*! - @brief post-decrement (it--) - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - iter_impl const operator--(int) - { - auto result = *this; - --(*this); - return result; - } - - /*! - @brief pre-decrement (--it) - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - iter_impl& operator--() - { - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case value_t::object: - { - std::advance(m_it.object_iterator, -1); - break; - } - - case value_t::array: - { - std::advance(m_it.array_iterator, -1); - break; - } - - default: - { - --m_it.primitive_iterator; - break; - } - } - - return *this; - } - - /*! - @brief comparison: equal - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - bool operator==(const iter_impl& other) const - { - // if objects are not the same, the comparison is undefined - if (JSON_UNLIKELY(m_object != other.m_object)) - { - JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers")); - } - - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case value_t::object: - return (m_it.object_iterator == other.m_it.object_iterator); - - case value_t::array: - return (m_it.array_iterator == other.m_it.array_iterator); - - default: - return (m_it.primitive_iterator == other.m_it.primitive_iterator); - } - } - - /*! - @brief comparison: not equal - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - bool operator!=(const iter_impl& other) const - { - return not operator==(other); - } - - /*! - @brief comparison: smaller - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - bool operator<(const iter_impl& other) const - { - // if objects are not the same, the comparison is undefined - if (JSON_UNLIKELY(m_object != other.m_object)) - { - JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers")); - } - - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case value_t::object: - JSON_THROW(invalid_iterator::create(213, "cannot compare order of object iterators")); - - case value_t::array: - return (m_it.array_iterator < other.m_it.array_iterator); - - default: - return (m_it.primitive_iterator < other.m_it.primitive_iterator); - } - } - - /*! - @brief comparison: less than or equal - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - bool operator<=(const iter_impl& other) const - { - return not other.operator < (*this); - } - - /*! - @brief comparison: greater than - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - bool operator>(const iter_impl& other) const - { - return not operator<=(other); - } - - /*! - @brief comparison: greater than or equal - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - bool operator>=(const iter_impl& other) const - { - return not operator<(other); - } - - /*! - @brief add to iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - iter_impl& operator+=(difference_type i) - { - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case value_t::object: - JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators")); - - case value_t::array: - { - std::advance(m_it.array_iterator, i); - break; - } - - default: - { - m_it.primitive_iterator += i; - break; - } - } - - return *this; - } - - /*! - @brief subtract from iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - iter_impl& operator-=(difference_type i) - { - return operator+=(-i); - } - - /*! - @brief add to iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - iter_impl operator+(difference_type i) const - { - auto result = *this; - result += i; - return result; - } - - /*! - @brief addition of distance and iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - friend iter_impl operator+(difference_type i, const iter_impl& it) - { - auto result = it; - result += i; - return result; - } - - /*! - @brief subtract from iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - iter_impl operator-(difference_type i) const - { - auto result = *this; - result -= i; - return result; - } - - /*! - @brief return difference - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - difference_type operator-(const iter_impl& other) const - { - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case value_t::object: - JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators")); - - case value_t::array: - return m_it.array_iterator - other.m_it.array_iterator; - - default: - return m_it.primitive_iterator - other.m_it.primitive_iterator; - } - } - - /*! - @brief access to successor - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - reference operator[](difference_type n) const - { - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case value_t::object: - JSON_THROW(invalid_iterator::create(208, "cannot use operator[] for object iterators")); - - case value_t::array: - return *std::next(m_it.array_iterator, n); - - case value_t::null: - JSON_THROW(invalid_iterator::create(214, "cannot get value")); - - default: - { - if (JSON_LIKELY(m_it.primitive_iterator.get_value() == -n)) - { - return *m_object; - } - - JSON_THROW(invalid_iterator::create(214, "cannot get value")); - } - } - } - - /*! - @brief return the key of an object iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - typename object_t::key_type key() const - { - assert(m_object != nullptr); - - if (JSON_LIKELY(m_object->is_object())) - { - return m_it.object_iterator->first; - } - - JSON_THROW(invalid_iterator::create(207, "cannot use key() for non-object iterators")); - } - - /*! - @brief return the value of an iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - reference value() const - { - return operator*(); - } - - private: - /// associated JSON instance - pointer m_object = nullptr; - /// the actual iterator of the associated instance - internal_iterator::type> m_it = {}; -}; -} -} - -#endif - -/*** End of inlined file: iter_impl.hpp ***/ - - -/*** Start of inlined file: iteration_proxy.hpp ***/ -#ifndef NLOHMANN_JSON_DETAIL_ITERATORS_ITERATION_PROXY_HPP -#define NLOHMANN_JSON_DETAIL_ITERATORS_ITERATION_PROXY_HPP - -#include // size_t -#include // string, to_string - -namespace nlohmann -{ -namespace detail -{ -/// proxy class for the iterator_wrapper functions -template class iteration_proxy -{ - private: - /// helper class for iteration - class iteration_proxy_internal - { - private: - /// the iterator - IteratorType anchor; - /// an index for arrays (used to create key names) - std::size_t array_index = 0; - - public: - explicit iteration_proxy_internal(IteratorType it) noexcept : anchor(it) {} - - /// dereference operator (needed for range-based for) - iteration_proxy_internal& operator*() - { - return *this; - } - - /// increment operator (needed for range-based for) - iteration_proxy_internal& operator++() - { - ++anchor; - ++array_index; - - return *this; - } - - /// inequality operator (needed for range-based for) - bool operator!=(const iteration_proxy_internal& o) const noexcept - { - return anchor != o.anchor; - } - - /// return key of the iterator - std::string key() const - { - assert(anchor.m_object != nullptr); - - switch (anchor.m_object->type()) - { - // use integer array index as key - case value_t::array: - return std::to_string(array_index); - - // use key from the object - case value_t::object: - return anchor.key(); - - // use an empty key for all primitive types - default: - return ""; - } - } - - /// return value of the iterator - typename IteratorType::reference value() const - { - return anchor.value(); - } - }; - - /// the container to iterate - typename IteratorType::reference container; - - public: - /// construct iteration proxy from a container - explicit iteration_proxy(typename IteratorType::reference cont) - : container(cont) {} - - /// return iterator begin (needed for range-based for) - iteration_proxy_internal begin() noexcept - { - return iteration_proxy_internal(container.begin()); - } - - /// return iterator end (needed for range-based for) - iteration_proxy_internal end() noexcept - { - return iteration_proxy_internal(container.end()); - } -}; -} -} - -#endif - -/*** End of inlined file: iteration_proxy.hpp ***/ - - -/*** Start of inlined file: json_reverse_iterator.hpp ***/ -#ifndef NLOHMANN_JSON_DETAIL_ITERATORS_JSON_REVERSE_ITERATOR_HPP -#define NLOHMANN_JSON_DETAIL_ITERATORS_JSON_REVERSE_ITERATOR_HPP - -#include // ptrdiff_t -#include // reverse_iterator -#include // declval - -namespace nlohmann -{ -namespace detail -{ -////////////////////// -// reverse_iterator // -////////////////////// - -/*! -@brief a template for a reverse iterator class - -@tparam Base the base iterator type to reverse. Valid types are @ref -iterator (to create @ref reverse_iterator) and @ref const_iterator (to -create @ref const_reverse_iterator). - -@requirement The class satisfies the following concept requirements: -- -[BidirectionalIterator](http://en.cppreference.com/w/cpp/concept/BidirectionalIterator): - The iterator that can be moved can be moved in both directions (i.e. - incremented and decremented). -- [OutputIterator](http://en.cppreference.com/w/cpp/concept/OutputIterator): - It is possible to write to the pointed-to element (only if @a Base is - @ref iterator). - -@since version 1.0.0 -*/ -template -class json_reverse_iterator : public std::reverse_iterator -{ - public: - using difference_type = std::ptrdiff_t; - /// shortcut to the reverse iterator adapter - using base_iterator = std::reverse_iterator; - /// the reference type for the pointed-to element - using reference = typename Base::reference; - - /// create reverse iterator from iterator - json_reverse_iterator(const typename base_iterator::iterator_type& it) noexcept - : base_iterator(it) {} - - /// create reverse iterator from base class - json_reverse_iterator(const base_iterator& it) noexcept : base_iterator(it) {} - - /// post-increment (it++) - json_reverse_iterator const operator++(int) - { - return static_cast(base_iterator::operator++(1)); - } - - /// pre-increment (++it) - json_reverse_iterator& operator++() - { - return static_cast(base_iterator::operator++()); - } - - /// post-decrement (it--) - json_reverse_iterator const operator--(int) - { - return static_cast(base_iterator::operator--(1)); - } - - /// pre-decrement (--it) - json_reverse_iterator& operator--() - { - return static_cast(base_iterator::operator--()); - } - - /// add to iterator - json_reverse_iterator& operator+=(difference_type i) - { - return static_cast(base_iterator::operator+=(i)); - } - - /// add to iterator - json_reverse_iterator operator+(difference_type i) const - { - return static_cast(base_iterator::operator+(i)); - } - - /// subtract from iterator - json_reverse_iterator operator-(difference_type i) const - { - return static_cast(base_iterator::operator-(i)); - } - - /// return difference - difference_type operator-(const json_reverse_iterator& other) const - { - return base_iterator(*this) - base_iterator(other); - } - - /// access to successor - reference operator[](difference_type n) const - { - return *(this->operator+(n)); - } - - /// return the key of an object iterator - auto key() const -> decltype(std::declval().key()) - { - auto it = --this->base(); - return it.key(); - } - - /// return the value of an iterator - reference value() const - { - auto it = --this->base(); - return it.operator * (); - } -}; -} -} - -#endif - -/*** End of inlined file: json_reverse_iterator.hpp ***/ - - -/*** Start of inlined file: output_adapters.hpp ***/ -#ifndef NLOHMANN_JSON_DETAIL_PARSING_OUTPUT_ADAPTERS_HPP -#define NLOHMANN_JSON_DETAIL_PARSING_OUTPUT_ADAPTERS_HPP - -#include // copy -#include // size_t -#include // streamsize -#include // back_inserter -#include // shared_ptr, make_shared -#include // basic_ostream -#include // basic_string -#include // vector - -namespace nlohmann -{ -namespace detail -{ -/// abstract output adapter interface -template struct output_adapter_protocol -{ - virtual void write_character(CharType c) = 0; - virtual void write_characters(const CharType* s, std::size_t length) = 0; - virtual ~output_adapter_protocol() = default; -}; - -/// a type to simplify interfaces -template -using output_adapter_t = std::shared_ptr>; - -/// output adapter for byte vectors -template -class output_vector_adapter : public output_adapter_protocol -{ - public: - explicit output_vector_adapter(std::vector& vec) : v(vec) {} - - void write_character(CharType c) override - { - v.push_back(c); - } - - void write_characters(const CharType* s, std::size_t length) override - { - std::copy(s, s + length, std::back_inserter(v)); - } - - private: - std::vector& v; -}; - -/// output adapter for output streams -template -class output_stream_adapter : public output_adapter_protocol -{ - public: - explicit output_stream_adapter(std::basic_ostream& s) : stream(s) {} - - void write_character(CharType c) override - { - stream.put(c); - } - - void write_characters(const CharType* s, std::size_t length) override - { - stream.write(s, static_cast(length)); - } - - private: - std::basic_ostream& stream; -}; - -/// output adapter for basic_string -template -class output_string_adapter : public output_adapter_protocol -{ - public: - explicit output_string_adapter(std::basic_string& s) : str(s) {} - - void write_character(CharType c) override - { - str.push_back(c); - } - - void write_characters(const CharType* s, std::size_t length) override - { - str.append(s, length); - } - - private: - std::basic_string& str; -}; - -template -class output_adapter -{ - public: - output_adapter(std::vector& vec) - : oa(std::make_shared>(vec)) {} - - output_adapter(std::basic_ostream& s) - : oa(std::make_shared>(s)) {} - - output_adapter(std::basic_string& s) - : oa(std::make_shared>(s)) {} - - operator output_adapter_t() - { - return oa; - } - - private: - output_adapter_t oa = nullptr; -}; -} -} - -#endif - -/*** End of inlined file: output_adapters.hpp ***/ - - -/*** Start of inlined file: binary_reader.hpp ***/ -#ifndef NLOHMANN_JSON_DETAIL_PARSING_BINARY_READER_HPP -#define NLOHMANN_JSON_DETAIL_PARSING_BINARY_READER_HPP - -#include // generate_n -#include // array -#include // assert -#include // ldexp -#include // size_t -#include // uint8_t, uint16_t, uint32_t, uint64_t -#include // memcpy -#include // setw, setfill -#include // hex -#include // back_inserter -#include // numeric_limits -#include // stringstream -#include // char_traits, string -#include // make_pair, move - -namespace nlohmann -{ -namespace detail -{ -/////////////////// -// binary reader // -/////////////////// - -/*! -@brief deserialization of CBOR and MessagePack values -*/ -template -class binary_reader -{ - using number_integer_t = typename BasicJsonType::number_integer_t; - using number_unsigned_t = typename BasicJsonType::number_unsigned_t; - - public: - /*! - @brief create a binary reader - - @param[in] adapter input adapter to read from - */ - explicit binary_reader(input_adapter_t adapter) : ia(std::move(adapter)) - { - assert(ia); - } - - /*! - @brief create a JSON value from CBOR input - - @param[in] strict whether to expect the input to be consumed completed - @return JSON value created from CBOR input - - @throw parse_error.110 if input ended unexpectedly or the end of file was - not reached when @a strict was set to true - @throw parse_error.112 if unsupported byte was read - */ - BasicJsonType parse_cbor(const bool strict) - { - const auto res = parse_cbor_internal(); - if (strict) - { - get(); - check_eof(true); - } - return res; - } - - /*! - @brief create a JSON value from MessagePack input - - @param[in] strict whether to expect the input to be consumed completed - @return JSON value created from MessagePack input - - @throw parse_error.110 if input ended unexpectedly or the end of file was - not reached when @a strict was set to true - @throw parse_error.112 if unsupported byte was read - */ - BasicJsonType parse_msgpack(const bool strict) - { - const auto res = parse_msgpack_internal(); - if (strict) - { - get(); - check_eof(true); - } - return res; - } - - /*! - @brief determine system byte order - - @return true if and only if system's byte order is little endian - - @note from http://stackoverflow.com/a/1001328/266378 - */ - static constexpr bool little_endianess(int num = 1) noexcept - { - return (*reinterpret_cast(&num) == 1); - } - - private: - /*! - @param[in] get_char whether a new character should be retrieved from the - input (true, default) or whether the last read - character should be considered instead - */ - BasicJsonType parse_cbor_internal(const bool get_char = true) - { - switch (get_char ? get() : current) - { - // EOF - case std::char_traits::eof(): - JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input")); - - // Integer 0x00..0x17 (0..23) - case 0x00: - case 0x01: - case 0x02: - case 0x03: - case 0x04: - case 0x05: - case 0x06: - case 0x07: - case 0x08: - case 0x09: - case 0x0A: - case 0x0B: - case 0x0C: - case 0x0D: - case 0x0E: - case 0x0F: - case 0x10: - case 0x11: - case 0x12: - case 0x13: - case 0x14: - case 0x15: - case 0x16: - case 0x17: - return static_cast(current); - - case 0x18: // Unsigned integer (one-byte uint8_t follows) - return get_number(); - - case 0x19: // Unsigned integer (two-byte uint16_t follows) - return get_number(); - - case 0x1A: // Unsigned integer (four-byte uint32_t follows) - return get_number(); - - case 0x1B: // Unsigned integer (eight-byte uint64_t follows) - return get_number(); - - // Negative integer -1-0x00..-1-0x17 (-1..-24) - case 0x20: - case 0x21: - case 0x22: - case 0x23: - case 0x24: - case 0x25: - case 0x26: - case 0x27: - case 0x28: - case 0x29: - case 0x2A: - case 0x2B: - case 0x2C: - case 0x2D: - case 0x2E: - case 0x2F: - case 0x30: - case 0x31: - case 0x32: - case 0x33: - case 0x34: - case 0x35: - case 0x36: - case 0x37: - return static_cast(0x20 - 1 - current); - - case 0x38: // Negative integer (one-byte uint8_t follows) - { - // must be uint8_t ! - return static_cast(-1) - get_number(); - } - - case 0x39: // Negative integer -1-n (two-byte uint16_t follows) - { - return static_cast(-1) - get_number(); - } - - case 0x3A: // Negative integer -1-n (four-byte uint32_t follows) - { - return static_cast(-1) - get_number(); - } - - case 0x3B: // Negative integer -1-n (eight-byte uint64_t follows) - { - return static_cast(-1) - - static_cast(get_number()); - } - - // UTF-8 string (0x00..0x17 bytes follow) - case 0x60: - case 0x61: - case 0x62: - case 0x63: - case 0x64: - case 0x65: - case 0x66: - case 0x67: - case 0x68: - case 0x69: - case 0x6A: - case 0x6B: - case 0x6C: - case 0x6D: - case 0x6E: - case 0x6F: - case 0x70: - case 0x71: - case 0x72: - case 0x73: - case 0x74: - case 0x75: - case 0x76: - case 0x77: - case 0x78: // UTF-8 string (one-byte uint8_t for n follows) - case 0x79: // UTF-8 string (two-byte uint16_t for n follow) - case 0x7A: // UTF-8 string (four-byte uint32_t for n follow) - case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow) - case 0x7F: // UTF-8 string (indefinite length) - { - return get_cbor_string(); - } - - // array (0x00..0x17 data items follow) - case 0x80: - case 0x81: - case 0x82: - case 0x83: - case 0x84: - case 0x85: - case 0x86: - case 0x87: - case 0x88: - case 0x89: - case 0x8A: - case 0x8B: - case 0x8C: - case 0x8D: - case 0x8E: - case 0x8F: - case 0x90: - case 0x91: - case 0x92: - case 0x93: - case 0x94: - case 0x95: - case 0x96: - case 0x97: - { - return get_cbor_array(current & 0x1F); - } - - case 0x98: // array (one-byte uint8_t for n follows) - { - return get_cbor_array(get_number()); - } - - case 0x99: // array (two-byte uint16_t for n follow) - { - return get_cbor_array(get_number()); - } - - case 0x9A: // array (four-byte uint32_t for n follow) - { - return get_cbor_array(get_number()); - } - - case 0x9B: // array (eight-byte uint64_t for n follow) - { - return get_cbor_array(get_number()); - } - - case 0x9F: // array (indefinite length) - { - BasicJsonType result = value_t::array; - while (get() != 0xFF) - { - result.push_back(parse_cbor_internal(false)); - } - return result; - } - - // map (0x00..0x17 pairs of data items follow) - case 0xA0: - case 0xA1: - case 0xA2: - case 0xA3: - case 0xA4: - case 0xA5: - case 0xA6: - case 0xA7: - case 0xA8: - case 0xA9: - case 0xAA: - case 0xAB: - case 0xAC: - case 0xAD: - case 0xAE: - case 0xAF: - case 0xB0: - case 0xB1: - case 0xB2: - case 0xB3: - case 0xB4: - case 0xB5: - case 0xB6: - case 0xB7: - { - return get_cbor_object(current & 0x1F); - } - - case 0xB8: // map (one-byte uint8_t for n follows) - { - return get_cbor_object(get_number()); - } - - case 0xB9: // map (two-byte uint16_t for n follow) - { - return get_cbor_object(get_number()); - } - - case 0xBA: // map (four-byte uint32_t for n follow) - { - return get_cbor_object(get_number()); - } - - case 0xBB: // map (eight-byte uint64_t for n follow) - { - return get_cbor_object(get_number()); - } - - case 0xBF: // map (indefinite length) - { - BasicJsonType result = value_t::object; - while (get() != 0xFF) - { - auto key = get_cbor_string(); - result[key] = parse_cbor_internal(); - } - return result; - } - - case 0xF4: // false - { - return false; - } - - case 0xF5: // true - { - return true; - } - - case 0xF6: // null - { - return value_t::null; - } - - case 0xF9: // Half-Precision Float (two-byte IEEE 754) - { - const int byte1 = get(); - check_eof(); - const int byte2 = get(); - check_eof(); - - // code from RFC 7049, Appendix D, Figure 3: - // As half-precision floating-point numbers were only added - // to IEEE 754 in 2008, today's programming platforms often - // still only have limited support for them. It is very - // easy to include at least decoding support for them even - // without such support. An example of a small decoder for - // half-precision floating-point numbers in the C language - // is shown in Fig. 3. - const int half = (byte1 << 8) + byte2; - const int exp = (half >> 10) & 0x1F; - const int mant = half & 0x3FF; - double val; - if (exp == 0) - { - val = std::ldexp(mant, -24); - } - else if (exp != 31) - { - val = std::ldexp(mant + 1024, exp - 25); - } - else - { - val = (mant == 0) ? std::numeric_limits::infinity() - : std::numeric_limits::quiet_NaN(); - } - return (half & 0x8000) != 0 ? -val : val; - } - - case 0xFA: // Single-Precision Float (four-byte IEEE 754) - { - return get_number(); - } - - case 0xFB: // Double-Precision Float (eight-byte IEEE 754) - { - return get_number(); - } - - default: // anything else (0xFF is handled inside the other types) - { - std::stringstream ss; - ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; - JSON_THROW(parse_error::create(112, chars_read, "error reading CBOR; last byte: 0x" + ss.str())); - } - } - } - - BasicJsonType parse_msgpack_internal() - { - switch (get()) - { - // EOF - case std::char_traits::eof(): - JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input")); - - // positive fixint - case 0x00: - case 0x01: - case 0x02: - case 0x03: - case 0x04: - case 0x05: - case 0x06: - case 0x07: - case 0x08: - case 0x09: - case 0x0A: - case 0x0B: - case 0x0C: - case 0x0D: - case 0x0E: - case 0x0F: - case 0x10: - case 0x11: - case 0x12: - case 0x13: - case 0x14: - case 0x15: - case 0x16: - case 0x17: - case 0x18: - case 0x19: - case 0x1A: - case 0x1B: - case 0x1C: - case 0x1D: - case 0x1E: - case 0x1F: - case 0x20: - case 0x21: - case 0x22: - case 0x23: - case 0x24: - case 0x25: - case 0x26: - case 0x27: - case 0x28: - case 0x29: - case 0x2A: - case 0x2B: - case 0x2C: - case 0x2D: - case 0x2E: - case 0x2F: - case 0x30: - case 0x31: - case 0x32: - case 0x33: - case 0x34: - case 0x35: - case 0x36: - case 0x37: - case 0x38: - case 0x39: - case 0x3A: - case 0x3B: - case 0x3C: - case 0x3D: - case 0x3E: - case 0x3F: - case 0x40: - case 0x41: - case 0x42: - case 0x43: - case 0x44: - case 0x45: - case 0x46: - case 0x47: - case 0x48: - case 0x49: - case 0x4A: - case 0x4B: - case 0x4C: - case 0x4D: - case 0x4E: - case 0x4F: - case 0x50: - case 0x51: - case 0x52: - case 0x53: - case 0x54: - case 0x55: - case 0x56: - case 0x57: - case 0x58: - case 0x59: - case 0x5A: - case 0x5B: - case 0x5C: - case 0x5D: - case 0x5E: - case 0x5F: - case 0x60: - case 0x61: - case 0x62: - case 0x63: - case 0x64: - case 0x65: - case 0x66: - case 0x67: - case 0x68: - case 0x69: - case 0x6A: - case 0x6B: - case 0x6C: - case 0x6D: - case 0x6E: - case 0x6F: - case 0x70: - case 0x71: - case 0x72: - case 0x73: - case 0x74: - case 0x75: - case 0x76: - case 0x77: - case 0x78: - case 0x79: - case 0x7A: - case 0x7B: - case 0x7C: - case 0x7D: - case 0x7E: - case 0x7F: - return static_cast(current); - - // fixmap - case 0x80: - case 0x81: - case 0x82: - case 0x83: - case 0x84: - case 0x85: - case 0x86: - case 0x87: - case 0x88: - case 0x89: - case 0x8A: - case 0x8B: - case 0x8C: - case 0x8D: - case 0x8E: - case 0x8F: - { - return get_msgpack_object(current & 0x0F); - } - - // fixarray - case 0x90: - case 0x91: - case 0x92: - case 0x93: - case 0x94: - case 0x95: - case 0x96: - case 0x97: - case 0x98: - case 0x99: - case 0x9A: - case 0x9B: - case 0x9C: - case 0x9D: - case 0x9E: - case 0x9F: - { - return get_msgpack_array(current & 0x0F); - } - - // fixstr - case 0xA0: - case 0xA1: - case 0xA2: - case 0xA3: - case 0xA4: - case 0xA5: - case 0xA6: - case 0xA7: - case 0xA8: - case 0xA9: - case 0xAA: - case 0xAB: - case 0xAC: - case 0xAD: - case 0xAE: - case 0xAF: - case 0xB0: - case 0xB1: - case 0xB2: - case 0xB3: - case 0xB4: - case 0xB5: - case 0xB6: - case 0xB7: - case 0xB8: - case 0xB9: - case 0xBA: - case 0xBB: - case 0xBC: - case 0xBD: - case 0xBE: - case 0xBF: - return get_msgpack_string(); - - case 0xC0: // nil - return value_t::null; - - case 0xC2: // false - return false; - - case 0xC3: // true - return true; - - case 0xCA: // float 32 - return get_number(); - - case 0xCB: // float 64 - return get_number(); - - case 0xCC: // uint 8 - return get_number(); - - case 0xCD: // uint 16 - return get_number(); - - case 0xCE: // uint 32 - return get_number(); - - case 0xCF: // uint 64 - return get_number(); - - case 0xD0: // int 8 - return get_number(); - - case 0xD1: // int 16 - return get_number(); - - case 0xD2: // int 32 - return get_number(); - - case 0xD3: // int 64 - return get_number(); - - case 0xD9: // str 8 - case 0xDA: // str 16 - case 0xDB: // str 32 - return get_msgpack_string(); - - case 0xDC: // array 16 - { - return get_msgpack_array(get_number()); - } - - case 0xDD: // array 32 - { - return get_msgpack_array(get_number()); - } - - case 0xDE: // map 16 - { - return get_msgpack_object(get_number()); - } - - case 0xDF: // map 32 - { - return get_msgpack_object(get_number()); - } - - // positive fixint - case 0xE0: - case 0xE1: - case 0xE2: - case 0xE3: - case 0xE4: - case 0xE5: - case 0xE6: - case 0xE7: - case 0xE8: - case 0xE9: - case 0xEA: - case 0xEB: - case 0xEC: - case 0xED: - case 0xEE: - case 0xEF: - case 0xF0: - case 0xF1: - case 0xF2: - case 0xF3: - case 0xF4: - case 0xF5: - case 0xF6: - case 0xF7: - case 0xF8: - case 0xF9: - case 0xFA: - case 0xFB: - case 0xFC: - case 0xFD: - case 0xFE: - case 0xFF: - return static_cast(current); - - default: // anything else - { - std::stringstream ss; - ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; - JSON_THROW(parse_error::create(112, chars_read, - "error reading MessagePack; last byte: 0x" + ss.str())); - } - } - } - - /*! - @brief get next character from the input - - This function provides the interface to the used input adapter. It does - not throw in case the input reached EOF, but returns a -'ve valued - `std::char_traits::eof()` in that case. - - @return character read from the input - */ - int get() - { - ++chars_read; - return (current = ia->get_character()); - } - - /* - @brief read a number from the input - - @tparam NumberType the type of the number - - @return number of type @a NumberType - - @note This function needs to respect the system's endianess, because - bytes in CBOR and MessagePack are stored in network order (big - endian) and therefore need reordering on little endian systems. - - @throw parse_error.110 if input has less than `sizeof(NumberType)` bytes - */ - template NumberType get_number() - { - // step 1: read input into array with system's byte order - std::array vec; - for (std::size_t i = 0; i < sizeof(NumberType); ++i) - { - get(); - check_eof(); - - // reverse byte order prior to conversion if necessary - if (is_little_endian) - { - vec[sizeof(NumberType) - i - 1] = static_cast(current); - } - else - { - vec[i] = static_cast(current); // LCOV_EXCL_LINE - } - } - - // step 2: convert array into number of type T and return - NumberType result; - std::memcpy(&result, vec.data(), sizeof(NumberType)); - return result; - } - - /*! - @brief create a string by reading characters from the input - - @param[in] len number of bytes to read - - @note We can not reserve @a len bytes for the result, because @a len - may be too large. Usually, @ref check_eof() detects the end of - the input before we run out of string memory. - - @return string created by reading @a len bytes - - @throw parse_error.110 if input has less than @a len bytes - */ - template - std::string get_string(const NumberType len) - { - std::string result; - std::generate_n(std::back_inserter(result), len, [this]() - { - get(); - check_eof(); - return static_cast(current); - }); - return result; - } - - /*! - @brief reads a CBOR string - - This function first reads starting bytes to determine the expected - string length and then copies this number of bytes into a string. - Additionally, CBOR's strings with indefinite lengths are supported. - - @return string - - @throw parse_error.110 if input ended - @throw parse_error.113 if an unexpected byte is read - */ - std::string get_cbor_string() - { - check_eof(); - - switch (current) - { - // UTF-8 string (0x00..0x17 bytes follow) - case 0x60: - case 0x61: - case 0x62: - case 0x63: - case 0x64: - case 0x65: - case 0x66: - case 0x67: - case 0x68: - case 0x69: - case 0x6A: - case 0x6B: - case 0x6C: - case 0x6D: - case 0x6E: - case 0x6F: - case 0x70: - case 0x71: - case 0x72: - case 0x73: - case 0x74: - case 0x75: - case 0x76: - case 0x77: - { - return get_string(current & 0x1F); - } - - case 0x78: // UTF-8 string (one-byte uint8_t for n follows) - { - return get_string(get_number()); - } - - case 0x79: // UTF-8 string (two-byte uint16_t for n follow) - { - return get_string(get_number()); - } - - case 0x7A: // UTF-8 string (four-byte uint32_t for n follow) - { - return get_string(get_number()); - } - - case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow) - { - return get_string(get_number()); - } - - case 0x7F: // UTF-8 string (indefinite length) - { - std::string result; - while (get() != 0xFF) - { - check_eof(); - result.push_back(static_cast(current)); - } - return result; - } - - default: - { - std::stringstream ss; - ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; - JSON_THROW(parse_error::create(113, chars_read, "expected a CBOR string; last byte: 0x" + ss.str())); - } - } - } - - template - BasicJsonType get_cbor_array(const NumberType len) - { - BasicJsonType result = value_t::array; - std::generate_n(std::back_inserter(*result.m_value.array), len, [this]() - { - return parse_cbor_internal(); - }); - return result; - } - - template - BasicJsonType get_cbor_object(const NumberType len) - { - BasicJsonType result = value_t::object; - std::generate_n(std::inserter(*result.m_value.object, - result.m_value.object->end()), - len, [this]() - { - get(); - auto key = get_cbor_string(); - auto val = parse_cbor_internal(); - return std::make_pair(std::move(key), std::move(val)); - }); - return result; - } - - /*! - @brief reads a MessagePack string - - This function first reads starting bytes to determine the expected - string length and then copies this number of bytes into a string. - - @return string - - @throw parse_error.110 if input ended - @throw parse_error.113 if an unexpected byte is read - */ - std::string get_msgpack_string() - { - check_eof(); - - switch (current) - { - // fixstr - case 0xA0: - case 0xA1: - case 0xA2: - case 0xA3: - case 0xA4: - case 0xA5: - case 0xA6: - case 0xA7: - case 0xA8: - case 0xA9: - case 0xAA: - case 0xAB: - case 0xAC: - case 0xAD: - case 0xAE: - case 0xAF: - case 0xB0: - case 0xB1: - case 0xB2: - case 0xB3: - case 0xB4: - case 0xB5: - case 0xB6: - case 0xB7: - case 0xB8: - case 0xB9: - case 0xBA: - case 0xBB: - case 0xBC: - case 0xBD: - case 0xBE: - case 0xBF: - { - return get_string(current & 0x1F); - } - - case 0xD9: // str 8 - { - return get_string(get_number()); - } - - case 0xDA: // str 16 - { - return get_string(get_number()); - } - - case 0xDB: // str 32 - { - return get_string(get_number()); - } - - default: - { - std::stringstream ss; - ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; - JSON_THROW(parse_error::create(113, chars_read, - "expected a MessagePack string; last byte: 0x" + ss.str())); - } - } - } - - template - BasicJsonType get_msgpack_array(const NumberType len) - { - BasicJsonType result = value_t::array; - std::generate_n(std::back_inserter(*result.m_value.array), len, [this]() - { - return parse_msgpack_internal(); - }); - return result; - } - - template - BasicJsonType get_msgpack_object(const NumberType len) - { - BasicJsonType result = value_t::object; - std::generate_n(std::inserter(*result.m_value.object, - result.m_value.object->end()), - len, [this]() - { - get(); - auto key = get_msgpack_string(); - auto val = parse_msgpack_internal(); - return std::make_pair(std::move(key), std::move(val)); - }); - return result; - } - - /*! - @brief check if input ended - @throw parse_error.110 if input ended - */ - void check_eof(const bool expect_eof = false) const - { - if (expect_eof) - { - if (JSON_UNLIKELY(current != std::char_traits::eof())) - { - JSON_THROW(parse_error::create(110, chars_read, "expected end of input")); - } - } - else - { - if (JSON_UNLIKELY(current == std::char_traits::eof())) - { - JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input")); - } - } - } - - private: - /// input adapter - input_adapter_t ia = nullptr; - - /// the current character - int current = std::char_traits::eof(); - - /// the number of characters read - std::size_t chars_read = 0; - - /// whether we can assume little endianess - const bool is_little_endian = little_endianess(); -}; -} -} - -#endif - -/*** End of inlined file: binary_reader.hpp ***/ - - -/*** Start of inlined file: binary_writer.hpp ***/ -#ifndef NLOHMANN_JSON_DETAIL_PARSING_BINARY_WRITER_HPP -#define NLOHMANN_JSON_DETAIL_PARSING_BINARY_WRITER_HPP - -#include // reverse -#include // array -#include // uint8_t, uint16_t, uint32_t, uint64_t -#include // memcpy -#include // numeric_limits - - -/*** Start of inlined file: binary_reader.hpp ***/ -#ifndef NLOHMANN_JSON_DETAIL_PARSING_BINARY_READER_HPP -#define NLOHMANN_JSON_DETAIL_PARSING_BINARY_READER_HPP - -#include // generate_n -#include // array -#include // assert -#include // ldexp -#include // size_t -#include // uint8_t, uint16_t, uint32_t, uint64_t -#include // memcpy -#include // setw, setfill -#include // hex -#include // back_inserter -#include // numeric_limits -#include // stringstream -#include // char_traits, string -#include // make_pair, move - -namespace nlohmann -{ -namespace detail -{ -/////////////////// -// binary reader // -/////////////////// - -/*! -@brief deserialization of CBOR and MessagePack values -*/ -template -class binary_reader -{ - using number_integer_t = typename BasicJsonType::number_integer_t; - using number_unsigned_t = typename BasicJsonType::number_unsigned_t; - - public: - /*! - @brief create a binary reader - - @param[in] adapter input adapter to read from - */ - explicit binary_reader(input_adapter_t adapter) : ia(std::move(adapter)) - { - assert(ia); - } - - /*! - @brief create a JSON value from CBOR input - - @param[in] strict whether to expect the input to be consumed completed - @return JSON value created from CBOR input - - @throw parse_error.110 if input ended unexpectedly or the end of file was - not reached when @a strict was set to true - @throw parse_error.112 if unsupported byte was read - */ - BasicJsonType parse_cbor(const bool strict) - { - const auto res = parse_cbor_internal(); - if (strict) - { - get(); - check_eof(true); - } - return res; - } - - /*! - @brief create a JSON value from MessagePack input - - @param[in] strict whether to expect the input to be consumed completed - @return JSON value created from MessagePack input - - @throw parse_error.110 if input ended unexpectedly or the end of file was - not reached when @a strict was set to true - @throw parse_error.112 if unsupported byte was read - */ - BasicJsonType parse_msgpack(const bool strict) - { - const auto res = parse_msgpack_internal(); - if (strict) - { - get(); - check_eof(true); - } - return res; - } - - /*! - @brief determine system byte order - - @return true if and only if system's byte order is little endian - - @note from http://stackoverflow.com/a/1001328/266378 - */ - static constexpr bool little_endianess(int num = 1) noexcept - { - return (*reinterpret_cast(&num) == 1); - } - - private: - /*! - @param[in] get_char whether a new character should be retrieved from the - input (true, default) or whether the last read - character should be considered instead - */ - BasicJsonType parse_cbor_internal(const bool get_char = true) - { - switch (get_char ? get() : current) - { - // EOF - case std::char_traits::eof(): - JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input")); - - // Integer 0x00..0x17 (0..23) - case 0x00: - case 0x01: - case 0x02: - case 0x03: - case 0x04: - case 0x05: - case 0x06: - case 0x07: - case 0x08: - case 0x09: - case 0x0A: - case 0x0B: - case 0x0C: - case 0x0D: - case 0x0E: - case 0x0F: - case 0x10: - case 0x11: - case 0x12: - case 0x13: - case 0x14: - case 0x15: - case 0x16: - case 0x17: - return static_cast(current); - - case 0x18: // Unsigned integer (one-byte uint8_t follows) - return get_number(); - - case 0x19: // Unsigned integer (two-byte uint16_t follows) - return get_number(); - - case 0x1A: // Unsigned integer (four-byte uint32_t follows) - return get_number(); - - case 0x1B: // Unsigned integer (eight-byte uint64_t follows) - return get_number(); - - // Negative integer -1-0x00..-1-0x17 (-1..-24) - case 0x20: - case 0x21: - case 0x22: - case 0x23: - case 0x24: - case 0x25: - case 0x26: - case 0x27: - case 0x28: - case 0x29: - case 0x2A: - case 0x2B: - case 0x2C: - case 0x2D: - case 0x2E: - case 0x2F: - case 0x30: - case 0x31: - case 0x32: - case 0x33: - case 0x34: - case 0x35: - case 0x36: - case 0x37: - return static_cast(0x20 - 1 - current); - - case 0x38: // Negative integer (one-byte uint8_t follows) - { - // must be uint8_t ! - return static_cast(-1) - get_number(); - } - - case 0x39: // Negative integer -1-n (two-byte uint16_t follows) - { - return static_cast(-1) - get_number(); - } - - case 0x3A: // Negative integer -1-n (four-byte uint32_t follows) - { - return static_cast(-1) - get_number(); - } - - case 0x3B: // Negative integer -1-n (eight-byte uint64_t follows) - { - return static_cast(-1) - - static_cast(get_number()); - } - - // UTF-8 string (0x00..0x17 bytes follow) - case 0x60: - case 0x61: - case 0x62: - case 0x63: - case 0x64: - case 0x65: - case 0x66: - case 0x67: - case 0x68: - case 0x69: - case 0x6A: - case 0x6B: - case 0x6C: - case 0x6D: - case 0x6E: - case 0x6F: - case 0x70: - case 0x71: - case 0x72: - case 0x73: - case 0x74: - case 0x75: - case 0x76: - case 0x77: - case 0x78: // UTF-8 string (one-byte uint8_t for n follows) - case 0x79: // UTF-8 string (two-byte uint16_t for n follow) - case 0x7A: // UTF-8 string (four-byte uint32_t for n follow) - case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow) - case 0x7F: // UTF-8 string (indefinite length) - { - return get_cbor_string(); - } - - // array (0x00..0x17 data items follow) - case 0x80: - case 0x81: - case 0x82: - case 0x83: - case 0x84: - case 0x85: - case 0x86: - case 0x87: - case 0x88: - case 0x89: - case 0x8A: - case 0x8B: - case 0x8C: - case 0x8D: - case 0x8E: - case 0x8F: - case 0x90: - case 0x91: - case 0x92: - case 0x93: - case 0x94: - case 0x95: - case 0x96: - case 0x97: - { - return get_cbor_array(current & 0x1F); - } - - case 0x98: // array (one-byte uint8_t for n follows) - { - return get_cbor_array(get_number()); - } - - case 0x99: // array (two-byte uint16_t for n follow) - { - return get_cbor_array(get_number()); - } - - case 0x9A: // array (four-byte uint32_t for n follow) - { - return get_cbor_array(get_number()); - } - - case 0x9B: // array (eight-byte uint64_t for n follow) - { - return get_cbor_array(get_number()); - } - - case 0x9F: // array (indefinite length) - { - BasicJsonType result = value_t::array; - while (get() != 0xFF) - { - result.push_back(parse_cbor_internal(false)); - } - return result; - } - - // map (0x00..0x17 pairs of data items follow) - case 0xA0: - case 0xA1: - case 0xA2: - case 0xA3: - case 0xA4: - case 0xA5: - case 0xA6: - case 0xA7: - case 0xA8: - case 0xA9: - case 0xAA: - case 0xAB: - case 0xAC: - case 0xAD: - case 0xAE: - case 0xAF: - case 0xB0: - case 0xB1: - case 0xB2: - case 0xB3: - case 0xB4: - case 0xB5: - case 0xB6: - case 0xB7: - { - return get_cbor_object(current & 0x1F); - } - - case 0xB8: // map (one-byte uint8_t for n follows) - { - return get_cbor_object(get_number()); - } - - case 0xB9: // map (two-byte uint16_t for n follow) - { - return get_cbor_object(get_number()); - } - - case 0xBA: // map (four-byte uint32_t for n follow) - { - return get_cbor_object(get_number()); - } - - case 0xBB: // map (eight-byte uint64_t for n follow) - { - return get_cbor_object(get_number()); - } - - case 0xBF: // map (indefinite length) - { - BasicJsonType result = value_t::object; - while (get() != 0xFF) - { - auto key = get_cbor_string(); - result[key] = parse_cbor_internal(); - } - return result; - } - - case 0xF4: // false - { - return false; - } - - case 0xF5: // true - { - return true; - } - - case 0xF6: // null - { - return value_t::null; - } - - case 0xF9: // Half-Precision Float (two-byte IEEE 754) - { - const int byte1 = get(); - check_eof(); - const int byte2 = get(); - check_eof(); - - // code from RFC 7049, Appendix D, Figure 3: - // As half-precision floating-point numbers were only added - // to IEEE 754 in 2008, today's programming platforms often - // still only have limited support for them. It is very - // easy to include at least decoding support for them even - // without such support. An example of a small decoder for - // half-precision floating-point numbers in the C language - // is shown in Fig. 3. - const int half = (byte1 << 8) + byte2; - const int exp = (half >> 10) & 0x1F; - const int mant = half & 0x3FF; - double val; - if (exp == 0) - { - val = std::ldexp(mant, -24); - } - else if (exp != 31) - { - val = std::ldexp(mant + 1024, exp - 25); - } - else - { - val = (mant == 0) ? std::numeric_limits::infinity() - : std::numeric_limits::quiet_NaN(); - } - return (half & 0x8000) != 0 ? -val : val; - } - - case 0xFA: // Single-Precision Float (four-byte IEEE 754) - { - return get_number(); - } - - case 0xFB: // Double-Precision Float (eight-byte IEEE 754) - { - return get_number(); - } - - default: // anything else (0xFF is handled inside the other types) - { - std::stringstream ss; - ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; - JSON_THROW(parse_error::create(112, chars_read, "error reading CBOR; last byte: 0x" + ss.str())); - } - } - } - - BasicJsonType parse_msgpack_internal() - { - switch (get()) - { - // EOF - case std::char_traits::eof(): - JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input")); - - // positive fixint - case 0x00: - case 0x01: - case 0x02: - case 0x03: - case 0x04: - case 0x05: - case 0x06: - case 0x07: - case 0x08: - case 0x09: - case 0x0A: - case 0x0B: - case 0x0C: - case 0x0D: - case 0x0E: - case 0x0F: - case 0x10: - case 0x11: - case 0x12: - case 0x13: - case 0x14: - case 0x15: - case 0x16: - case 0x17: - case 0x18: - case 0x19: - case 0x1A: - case 0x1B: - case 0x1C: - case 0x1D: - case 0x1E: - case 0x1F: - case 0x20: - case 0x21: - case 0x22: - case 0x23: - case 0x24: - case 0x25: - case 0x26: - case 0x27: - case 0x28: - case 0x29: - case 0x2A: - case 0x2B: - case 0x2C: - case 0x2D: - case 0x2E: - case 0x2F: - case 0x30: - case 0x31: - case 0x32: - case 0x33: - case 0x34: - case 0x35: - case 0x36: - case 0x37: - case 0x38: - case 0x39: - case 0x3A: - case 0x3B: - case 0x3C: - case 0x3D: - case 0x3E: - case 0x3F: - case 0x40: - case 0x41: - case 0x42: - case 0x43: - case 0x44: - case 0x45: - case 0x46: - case 0x47: - case 0x48: - case 0x49: - case 0x4A: - case 0x4B: - case 0x4C: - case 0x4D: - case 0x4E: - case 0x4F: - case 0x50: - case 0x51: - case 0x52: - case 0x53: - case 0x54: - case 0x55: - case 0x56: - case 0x57: - case 0x58: - case 0x59: - case 0x5A: - case 0x5B: - case 0x5C: - case 0x5D: - case 0x5E: - case 0x5F: - case 0x60: - case 0x61: - case 0x62: - case 0x63: - case 0x64: - case 0x65: - case 0x66: - case 0x67: - case 0x68: - case 0x69: - case 0x6A: - case 0x6B: - case 0x6C: - case 0x6D: - case 0x6E: - case 0x6F: - case 0x70: - case 0x71: - case 0x72: - case 0x73: - case 0x74: - case 0x75: - case 0x76: - case 0x77: - case 0x78: - case 0x79: - case 0x7A: - case 0x7B: - case 0x7C: - case 0x7D: - case 0x7E: - case 0x7F: - return static_cast(current); - - // fixmap - case 0x80: - case 0x81: - case 0x82: - case 0x83: - case 0x84: - case 0x85: - case 0x86: - case 0x87: - case 0x88: - case 0x89: - case 0x8A: - case 0x8B: - case 0x8C: - case 0x8D: - case 0x8E: - case 0x8F: - { - return get_msgpack_object(current & 0x0F); - } - - // fixarray - case 0x90: - case 0x91: - case 0x92: - case 0x93: - case 0x94: - case 0x95: - case 0x96: - case 0x97: - case 0x98: - case 0x99: - case 0x9A: - case 0x9B: - case 0x9C: - case 0x9D: - case 0x9E: - case 0x9F: - { - return get_msgpack_array(current & 0x0F); - } - - // fixstr - case 0xA0: - case 0xA1: - case 0xA2: - case 0xA3: - case 0xA4: - case 0xA5: - case 0xA6: - case 0xA7: - case 0xA8: - case 0xA9: - case 0xAA: - case 0xAB: - case 0xAC: - case 0xAD: - case 0xAE: - case 0xAF: - case 0xB0: - case 0xB1: - case 0xB2: - case 0xB3: - case 0xB4: - case 0xB5: - case 0xB6: - case 0xB7: - case 0xB8: - case 0xB9: - case 0xBA: - case 0xBB: - case 0xBC: - case 0xBD: - case 0xBE: - case 0xBF: - return get_msgpack_string(); - - case 0xC0: // nil - return value_t::null; - - case 0xC2: // false - return false; - - case 0xC3: // true - return true; - - case 0xCA: // float 32 - return get_number(); - - case 0xCB: // float 64 - return get_number(); - - case 0xCC: // uint 8 - return get_number(); - - case 0xCD: // uint 16 - return get_number(); - - case 0xCE: // uint 32 - return get_number(); - - case 0xCF: // uint 64 - return get_number(); - - case 0xD0: // int 8 - return get_number(); - - case 0xD1: // int 16 - return get_number(); - - case 0xD2: // int 32 - return get_number(); - - case 0xD3: // int 64 - return get_number(); - - case 0xD9: // str 8 - case 0xDA: // str 16 - case 0xDB: // str 32 - return get_msgpack_string(); - - case 0xDC: // array 16 - { - return get_msgpack_array(get_number()); - } - - case 0xDD: // array 32 - { - return get_msgpack_array(get_number()); - } - - case 0xDE: // map 16 - { - return get_msgpack_object(get_number()); - } - - case 0xDF: // map 32 - { - return get_msgpack_object(get_number()); - } - - // positive fixint - case 0xE0: - case 0xE1: - case 0xE2: - case 0xE3: - case 0xE4: - case 0xE5: - case 0xE6: - case 0xE7: - case 0xE8: - case 0xE9: - case 0xEA: - case 0xEB: - case 0xEC: - case 0xED: - case 0xEE: - case 0xEF: - case 0xF0: - case 0xF1: - case 0xF2: - case 0xF3: - case 0xF4: - case 0xF5: - case 0xF6: - case 0xF7: - case 0xF8: - case 0xF9: - case 0xFA: - case 0xFB: - case 0xFC: - case 0xFD: - case 0xFE: - case 0xFF: - return static_cast(current); - - default: // anything else - { - std::stringstream ss; - ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; - JSON_THROW(parse_error::create(112, chars_read, - "error reading MessagePack; last byte: 0x" + ss.str())); - } - } - } - - /*! - @brief get next character from the input - - This function provides the interface to the used input adapter. It does - not throw in case the input reached EOF, but returns a -'ve valued - `std::char_traits::eof()` in that case. - - @return character read from the input - */ - int get() - { - ++chars_read; - return (current = ia->get_character()); - } - - /* - @brief read a number from the input - - @tparam NumberType the type of the number - - @return number of type @a NumberType - - @note This function needs to respect the system's endianess, because - bytes in CBOR and MessagePack are stored in network order (big - endian) and therefore need reordering on little endian systems. - - @throw parse_error.110 if input has less than `sizeof(NumberType)` bytes - */ - template NumberType get_number() - { - // step 1: read input into array with system's byte order - std::array vec; - for (std::size_t i = 0; i < sizeof(NumberType); ++i) - { - get(); - check_eof(); - - // reverse byte order prior to conversion if necessary - if (is_little_endian) - { - vec[sizeof(NumberType) - i - 1] = static_cast(current); - } - else - { - vec[i] = static_cast(current); // LCOV_EXCL_LINE - } - } - - // step 2: convert array into number of type T and return - NumberType result; - std::memcpy(&result, vec.data(), sizeof(NumberType)); - return result; - } - - /*! - @brief create a string by reading characters from the input - - @param[in] len number of bytes to read - - @note We can not reserve @a len bytes for the result, because @a len - may be too large. Usually, @ref check_eof() detects the end of - the input before we run out of string memory. - - @return string created by reading @a len bytes - - @throw parse_error.110 if input has less than @a len bytes - */ - template - std::string get_string(const NumberType len) - { - std::string result; - std::generate_n(std::back_inserter(result), len, [this]() - { - get(); - check_eof(); - return static_cast(current); - }); - return result; - } - - /*! - @brief reads a CBOR string - - This function first reads starting bytes to determine the expected - string length and then copies this number of bytes into a string. - Additionally, CBOR's strings with indefinite lengths are supported. - - @return string - - @throw parse_error.110 if input ended - @throw parse_error.113 if an unexpected byte is read - */ - std::string get_cbor_string() - { - check_eof(); - - switch (current) - { - // UTF-8 string (0x00..0x17 bytes follow) - case 0x60: - case 0x61: - case 0x62: - case 0x63: - case 0x64: - case 0x65: - case 0x66: - case 0x67: - case 0x68: - case 0x69: - case 0x6A: - case 0x6B: - case 0x6C: - case 0x6D: - case 0x6E: - case 0x6F: - case 0x70: - case 0x71: - case 0x72: - case 0x73: - case 0x74: - case 0x75: - case 0x76: - case 0x77: - { - return get_string(current & 0x1F); - } - - case 0x78: // UTF-8 string (one-byte uint8_t for n follows) - { - return get_string(get_number()); - } - - case 0x79: // UTF-8 string (two-byte uint16_t for n follow) - { - return get_string(get_number()); - } - - case 0x7A: // UTF-8 string (four-byte uint32_t for n follow) - { - return get_string(get_number()); - } - - case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow) - { - return get_string(get_number()); - } - - case 0x7F: // UTF-8 string (indefinite length) - { - std::string result; - while (get() != 0xFF) - { - check_eof(); - result.push_back(static_cast(current)); - } - return result; - } - - default: - { - std::stringstream ss; - ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; - JSON_THROW(parse_error::create(113, chars_read, "expected a CBOR string; last byte: 0x" + ss.str())); - } - } - } - - template - BasicJsonType get_cbor_array(const NumberType len) - { - BasicJsonType result = value_t::array; - std::generate_n(std::back_inserter(*result.m_value.array), len, [this]() - { - return parse_cbor_internal(); - }); - return result; - } - - template - BasicJsonType get_cbor_object(const NumberType len) - { - BasicJsonType result = value_t::object; - std::generate_n(std::inserter(*result.m_value.object, - result.m_value.object->end()), - len, [this]() - { - get(); - auto key = get_cbor_string(); - auto val = parse_cbor_internal(); - return std::make_pair(std::move(key), std::move(val)); - }); - return result; - } - - /*! - @brief reads a MessagePack string - - This function first reads starting bytes to determine the expected - string length and then copies this number of bytes into a string. - - @return string - - @throw parse_error.110 if input ended - @throw parse_error.113 if an unexpected byte is read - */ - std::string get_msgpack_string() - { - check_eof(); - - switch (current) - { - // fixstr - case 0xA0: - case 0xA1: - case 0xA2: - case 0xA3: - case 0xA4: - case 0xA5: - case 0xA6: - case 0xA7: - case 0xA8: - case 0xA9: - case 0xAA: - case 0xAB: - case 0xAC: - case 0xAD: - case 0xAE: - case 0xAF: - case 0xB0: - case 0xB1: - case 0xB2: - case 0xB3: - case 0xB4: - case 0xB5: - case 0xB6: - case 0xB7: - case 0xB8: - case 0xB9: - case 0xBA: - case 0xBB: - case 0xBC: - case 0xBD: - case 0xBE: - case 0xBF: - { - return get_string(current & 0x1F); - } - - case 0xD9: // str 8 - { - return get_string(get_number()); - } - - case 0xDA: // str 16 - { - return get_string(get_number()); - } - - case 0xDB: // str 32 - { - return get_string(get_number()); - } - - default: - { - std::stringstream ss; - ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; - JSON_THROW(parse_error::create(113, chars_read, - "expected a MessagePack string; last byte: 0x" + ss.str())); - } - } - } - - template - BasicJsonType get_msgpack_array(const NumberType len) - { - BasicJsonType result = value_t::array; - std::generate_n(std::back_inserter(*result.m_value.array), len, [this]() - { - return parse_msgpack_internal(); - }); - return result; - } - - template - BasicJsonType get_msgpack_object(const NumberType len) - { - BasicJsonType result = value_t::object; - std::generate_n(std::inserter(*result.m_value.object, - result.m_value.object->end()), - len, [this]() - { - get(); - auto key = get_msgpack_string(); - auto val = parse_msgpack_internal(); - return std::make_pair(std::move(key), std::move(val)); - }); - return result; - } - - /*! - @brief check if input ended - @throw parse_error.110 if input ended - */ - void check_eof(const bool expect_eof = false) const - { - if (expect_eof) - { - if (JSON_UNLIKELY(current != std::char_traits::eof())) - { - JSON_THROW(parse_error::create(110, chars_read, "expected end of input")); - } - } - else - { - if (JSON_UNLIKELY(current == std::char_traits::eof())) - { - JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input")); - } - } - } - - private: - /// input adapter - input_adapter_t ia = nullptr; - - /// the current character - int current = std::char_traits::eof(); - - /// the number of characters read - std::size_t chars_read = 0; - - /// whether we can assume little endianess - const bool is_little_endian = little_endianess(); -}; -} -} - -#endif - -/*** End of inlined file: binary_reader.hpp ***/ - - -/*** Start of inlined file: output_adapters.hpp ***/ -#ifndef NLOHMANN_JSON_DETAIL_PARSING_OUTPUT_ADAPTERS_HPP -#define NLOHMANN_JSON_DETAIL_PARSING_OUTPUT_ADAPTERS_HPP - -#include // copy -#include // size_t -#include // streamsize -#include // back_inserter -#include // shared_ptr, make_shared -#include // basic_ostream -#include // basic_string -#include // vector - -namespace nlohmann -{ -namespace detail -{ -/// abstract output adapter interface -template struct output_adapter_protocol -{ - virtual void write_character(CharType c) = 0; - virtual void write_characters(const CharType* s, std::size_t length) = 0; - virtual ~output_adapter_protocol() = default; -}; - -/// a type to simplify interfaces -template -using output_adapter_t = std::shared_ptr>; - -/// output adapter for byte vectors -template -class output_vector_adapter : public output_adapter_protocol -{ - public: - explicit output_vector_adapter(std::vector& vec) : v(vec) {} - - void write_character(CharType c) override - { - v.push_back(c); - } - - void write_characters(const CharType* s, std::size_t length) override - { - std::copy(s, s + length, std::back_inserter(v)); - } - - private: - std::vector& v; -}; - -/// output adapter for output streams -template -class output_stream_adapter : public output_adapter_protocol -{ - public: - explicit output_stream_adapter(std::basic_ostream& s) : stream(s) {} - - void write_character(CharType c) override - { - stream.put(c); - } - - void write_characters(const CharType* s, std::size_t length) override - { - stream.write(s, static_cast(length)); - } - - private: - std::basic_ostream& stream; -}; - -/// output adapter for basic_string -template -class output_string_adapter : public output_adapter_protocol -{ - public: - explicit output_string_adapter(std::basic_string& s) : str(s) {} - - void write_character(CharType c) override - { - str.push_back(c); - } - - void write_characters(const CharType* s, std::size_t length) override - { - str.append(s, length); - } - - private: - std::basic_string& str; -}; - -template -class output_adapter -{ - public: - output_adapter(std::vector& vec) - : oa(std::make_shared>(vec)) {} - - output_adapter(std::basic_ostream& s) - : oa(std::make_shared>(s)) {} - - output_adapter(std::basic_string& s) - : oa(std::make_shared>(s)) {} - - operator output_adapter_t() - { - return oa; - } - - private: - output_adapter_t oa = nullptr; -}; -} -} - -#endif - -/*** End of inlined file: output_adapters.hpp ***/ - -namespace nlohmann -{ -namespace detail -{ -/////////////////// -// binary writer // -/////////////////// - -/*! -@brief serialization to CBOR and MessagePack values -*/ -template -class binary_writer -{ - public: - /*! - @brief create a binary writer - - @param[in] adapter output adapter to write to - */ - explicit binary_writer(output_adapter_t adapter) : oa(adapter) - { - assert(oa); - } - - /*! - @brief[in] j JSON value to serialize - */ - void write_cbor(const BasicJsonType& j) - { - switch (j.type()) - { - case value_t::null: - { - oa->write_character(static_cast(0xF6)); - break; - } - - case value_t::boolean: - { - oa->write_character(j.m_value.boolean - ? static_cast(0xF5) - : static_cast(0xF4)); - break; - } - - case value_t::number_integer: - { - if (j.m_value.number_integer >= 0) - { - // CBOR does not differentiate between positive signed - // integers and unsigned integers. Therefore, we used the - // code from the value_t::number_unsigned case here. - if (j.m_value.number_integer <= 0x17) - { - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_integer <= (std::numeric_limits::max)()) - { - oa->write_character(static_cast(0x18)); - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_integer <= (std::numeric_limits::max)()) - { - oa->write_character(static_cast(0x19)); - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_integer <= (std::numeric_limits::max)()) - { - oa->write_character(static_cast(0x1A)); - write_number(static_cast(j.m_value.number_integer)); - } - else - { - oa->write_character(static_cast(0x1B)); - write_number(static_cast(j.m_value.number_integer)); - } - } - else - { - // The conversions below encode the sign in the first - // byte, and the value is converted to a positive number. - const auto positive_number = -1 - j.m_value.number_integer; - if (j.m_value.number_integer >= -24) - { - write_number(static_cast(0x20 + positive_number)); - } - else if (positive_number <= (std::numeric_limits::max)()) - { - oa->write_character(static_cast(0x38)); - write_number(static_cast(positive_number)); - } - else if (positive_number <= (std::numeric_limits::max)()) - { - oa->write_character(static_cast(0x39)); - write_number(static_cast(positive_number)); - } - else if (positive_number <= (std::numeric_limits::max)()) - { - oa->write_character(static_cast(0x3A)); - write_number(static_cast(positive_number)); - } - else - { - oa->write_character(static_cast(0x3B)); - write_number(static_cast(positive_number)); - } - } - break; - } - - case value_t::number_unsigned: - { - if (j.m_value.number_unsigned <= 0x17) - { - write_number(static_cast(j.m_value.number_unsigned)); - } - else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) - { - oa->write_character(static_cast(0x18)); - write_number(static_cast(j.m_value.number_unsigned)); - } - else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) - { - oa->write_character(static_cast(0x19)); - write_number(static_cast(j.m_value.number_unsigned)); - } - else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) - { - oa->write_character(static_cast(0x1A)); - write_number(static_cast(j.m_value.number_unsigned)); - } - else - { - oa->write_character(static_cast(0x1B)); - write_number(static_cast(j.m_value.number_unsigned)); - } - break; - } - - case value_t::number_float: // Double-Precision Float - { - oa->write_character(static_cast(0xFB)); - write_number(j.m_value.number_float); - break; - } - - case value_t::string: - { - // step 1: write control byte and the string length - const auto N = j.m_value.string->size(); - if (N <= 0x17) - { - write_number(static_cast(0x60 + N)); - } - else if (N <= 0xFF) - { - oa->write_character(static_cast(0x78)); - write_number(static_cast(N)); - } - else if (N <= 0xFFFF) - { - oa->write_character(static_cast(0x79)); - write_number(static_cast(N)); - } - else if (N <= 0xFFFFFFFF) - { - oa->write_character(static_cast(0x7A)); - write_number(static_cast(N)); - } - // LCOV_EXCL_START - else if (N <= 0xFFFFFFFFFFFFFFFF) - { - oa->write_character(static_cast(0x7B)); - write_number(static_cast(N)); - } - // LCOV_EXCL_STOP - - // step 2: write the string - oa->write_characters( - reinterpret_cast(j.m_value.string->c_str()), - j.m_value.string->size()); - break; - } - - case value_t::array: - { - // step 1: write control byte and the array size - const auto N = j.m_value.array->size(); - if (N <= 0x17) - { - write_number(static_cast(0x80 + N)); - } - else if (N <= 0xFF) - { - oa->write_character(static_cast(0x98)); - write_number(static_cast(N)); - } - else if (N <= 0xFFFF) - { - oa->write_character(static_cast(0x99)); - write_number(static_cast(N)); - } - else if (N <= 0xFFFFFFFF) - { - oa->write_character(static_cast(0x9A)); - write_number(static_cast(N)); - } - // LCOV_EXCL_START - else if (N <= 0xFFFFFFFFFFFFFFFF) - { - oa->write_character(static_cast(0x9B)); - write_number(static_cast(N)); - } - // LCOV_EXCL_STOP - - // step 2: write each element - for (const auto& el : *j.m_value.array) - { - write_cbor(el); - } - break; - } - - case value_t::object: - { - // step 1: write control byte and the object size - const auto N = j.m_value.object->size(); - if (N <= 0x17) - { - write_number(static_cast(0xA0 + N)); - } - else if (N <= 0xFF) - { - oa->write_character(static_cast(0xB8)); - write_number(static_cast(N)); - } - else if (N <= 0xFFFF) - { - oa->write_character(static_cast(0xB9)); - write_number(static_cast(N)); - } - else if (N <= 0xFFFFFFFF) - { - oa->write_character(static_cast(0xBA)); - write_number(static_cast(N)); - } - // LCOV_EXCL_START - else if (N <= 0xFFFFFFFFFFFFFFFF) - { - oa->write_character(static_cast(0xBB)); - write_number(static_cast(N)); - } - // LCOV_EXCL_STOP - - // step 2: write each element - for (const auto& el : *j.m_value.object) - { - write_cbor(el.first); - write_cbor(el.second); - } - break; - } - - default: - break; - } - } - - /*! - @brief[in] j JSON value to serialize - */ - void write_msgpack(const BasicJsonType& j) - { - switch (j.type()) - { - case value_t::null: // nil - { - oa->write_character(static_cast(0xC0)); - break; - } - - case value_t::boolean: // true and false - { - oa->write_character(j.m_value.boolean - ? static_cast(0xC3) - : static_cast(0xC2)); - break; - } - - case value_t::number_integer: - { - if (j.m_value.number_integer >= 0) - { - // MessagePack does not differentiate between positive - // signed integers and unsigned integers. Therefore, we used - // the code from the value_t::number_unsigned case here. - if (j.m_value.number_unsigned < 128) - { - // positive fixnum - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) - { - // uint 8 - oa->write_character(static_cast(0xCC)); - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) - { - // uint 16 - oa->write_character(static_cast(0xCD)); - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) - { - // uint 32 - oa->write_character(static_cast(0xCE)); - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) - { - // uint 64 - oa->write_character(static_cast(0xCF)); - write_number(static_cast(j.m_value.number_integer)); - } - } - else - { - if (j.m_value.number_integer >= -32) - { - // negative fixnum - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_integer >= (std::numeric_limits::min)() and - j.m_value.number_integer <= (std::numeric_limits::max)()) - { - // int 8 - oa->write_character(static_cast(0xD0)); - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_integer >= (std::numeric_limits::min)() and - j.m_value.number_integer <= (std::numeric_limits::max)()) - { - // int 16 - oa->write_character(static_cast(0xD1)); - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_integer >= (std::numeric_limits::min)() and - j.m_value.number_integer <= (std::numeric_limits::max)()) - { - // int 32 - oa->write_character(static_cast(0xD2)); - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_integer >= (std::numeric_limits::min)() and - j.m_value.number_integer <= (std::numeric_limits::max)()) - { - // int 64 - oa->write_character(static_cast(0xD3)); - write_number(static_cast(j.m_value.number_integer)); - } - } - break; - } - - case value_t::number_unsigned: - { - if (j.m_value.number_unsigned < 128) - { - // positive fixnum - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) - { - // uint 8 - oa->write_character(static_cast(0xCC)); - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) - { - // uint 16 - oa->write_character(static_cast(0xCD)); - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) - { - // uint 32 - oa->write_character(static_cast(0xCE)); - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) - { - // uint 64 - oa->write_character(static_cast(0xCF)); - write_number(static_cast(j.m_value.number_integer)); - } - break; - } - - case value_t::number_float: // float 64 - { - oa->write_character(static_cast(0xCB)); - write_number(j.m_value.number_float); - break; - } - - case value_t::string: - { - // step 1: write control byte and the string length - const auto N = j.m_value.string->size(); - if (N <= 31) - { - // fixstr - write_number(static_cast(0xA0 | N)); - } - else if (N <= 255) - { - // str 8 - oa->write_character(static_cast(0xD9)); - write_number(static_cast(N)); - } - else if (N <= 65535) - { - // str 16 - oa->write_character(static_cast(0xDA)); - write_number(static_cast(N)); - } - else if (N <= 4294967295) - { - // str 32 - oa->write_character(static_cast(0xDB)); - write_number(static_cast(N)); - } - - // step 2: write the string - oa->write_characters( - reinterpret_cast(j.m_value.string->c_str()), - j.m_value.string->size()); - break; - } - - case value_t::array: - { - // step 1: write control byte and the array size - const auto N = j.m_value.array->size(); - if (N <= 15) - { - // fixarray - write_number(static_cast(0x90 | N)); - } - else if (N <= 0xFFFF) - { - // array 16 - oa->write_character(static_cast(0xDC)); - write_number(static_cast(N)); - } - else if (N <= 0xFFFFFFFF) - { - // array 32 - oa->write_character(static_cast(0xDD)); - write_number(static_cast(N)); - } - - // step 2: write each element - for (const auto& el : *j.m_value.array) - { - write_msgpack(el); - } - break; - } - - case value_t::object: - { - // step 1: write control byte and the object size - const auto N = j.m_value.object->size(); - if (N <= 15) - { - // fixmap - write_number(static_cast(0x80 | (N & 0xF))); - } - else if (N <= 65535) - { - // map 16 - oa->write_character(static_cast(0xDE)); - write_number(static_cast(N)); - } - else if (N <= 4294967295) - { - // map 32 - oa->write_character(static_cast(0xDF)); - write_number(static_cast(N)); - } - - // step 2: write each element - for (const auto& el : *j.m_value.object) - { - write_msgpack(el.first); - write_msgpack(el.second); - } - break; - } - - default: - break; - } - } - - private: - /* - @brief write a number to output input - - @param[in] n number of type @a NumberType - @tparam NumberType the type of the number - - @note This function needs to respect the system's endianess, because bytes - in CBOR and MessagePack are stored in network order (big endian) and - therefore need reordering on little endian systems. - */ - template void write_number(NumberType n) - { - // step 1: write number to array of length NumberType - std::array vec; - std::memcpy(vec.data(), &n, sizeof(NumberType)); - - // step 2: write array to output (with possible reordering) - if (is_little_endian) - { - // reverse byte order prior to conversion if necessary - std::reverse(vec.begin(), vec.end()); - } - - oa->write_characters(vec.data(), sizeof(NumberType)); - } - - private: - /// whether we can assume little endianess - const bool is_little_endian = binary_reader::little_endianess(); - - /// the output - output_adapter_t oa = nullptr; -}; -} -} - -#endif - -/*** End of inlined file: binary_writer.hpp ***/ - - -/*** Start of inlined file: serializer.hpp ***/ -#ifndef NLOHMANN_JSON_DETAIL_SERIALIZER_HPP -#define NLOHMANN_JSON_DETAIL_SERIALIZER_HPP - -#include // reverse, remove, fill, find, none_of -#include // array -#include // assert -#include // and, or -#include // localeconv, lconv -#include // labs, isfinite, isnan, signbit -#include // size_t, ptrdiff_t -#include // uint8_t -#include // snprintf -#include // next -#include // numeric_limits -#include // string -#include // is_same - -namespace nlohmann -{ -namespace detail -{ -/////////////////// -// serialization // -/////////////////// - -template -class serializer -{ - using string_t = typename BasicJsonType::string_t; - using number_float_t = typename BasicJsonType::number_float_t; - using number_integer_t = typename BasicJsonType::number_integer_t; - using number_unsigned_t = typename BasicJsonType::number_unsigned_t; - public: - /*! - @param[in] s output stream to serialize to - @param[in] ichar indentation character to use - */ - serializer(output_adapter_t s, const char ichar) - : o(std::move(s)), loc(std::localeconv()), - thousands_sep(loc->thousands_sep == nullptr ? '\0' : * (loc->thousands_sep)), - decimal_point(loc->decimal_point == nullptr ? '\0' : * (loc->decimal_point)), - indent_char(ichar), indent_string(512, indent_char) {} - - // delete because of pointer members - serializer(const serializer&) = delete; - serializer& operator=(const serializer&) = delete; - - /*! - @brief internal implementation of the serialization function - - This function is called by the public member function dump and organizes - the serialization internally. The indentation level is propagated as - additional parameter. In case of arrays and objects, the function is - called recursively. - - - strings and object keys are escaped using `escape_string()` - - integer numbers are converted implicitly via `operator<<` - - floating-point numbers are converted to a string using `"%g"` format - - @param[in] val value to serialize - @param[in] pretty_print whether the output shall be pretty-printed - @param[in] indent_step the indent level - @param[in] current_indent the current indent level (only used internally) - */ - void dump(const BasicJsonType& val, const bool pretty_print, - const bool ensure_ascii, - const unsigned int indent_step, - const unsigned int current_indent = 0) - { - switch (val.m_type) - { - case value_t::object: - { - if (val.m_value.object->empty()) - { - o->write_characters("{}", 2); - return; - } - - if (pretty_print) - { - o->write_characters("{\n", 2); - - // variable to hold indentation for recursive calls - const auto new_indent = current_indent + indent_step; - if (JSON_UNLIKELY(indent_string.size() < new_indent)) - { - indent_string.resize(indent_string.size() * 2, ' '); - } - - // first n-1 elements - auto i = val.m_value.object->cbegin(); - for (std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i) - { - o->write_characters(indent_string.c_str(), new_indent); - o->write_character('\"'); - dump_escaped(i->first, ensure_ascii); - o->write_characters("\": ", 3); - dump(i->second, true, ensure_ascii, indent_step, new_indent); - o->write_characters(",\n", 2); - } - - // last element - assert(i != val.m_value.object->cend()); - assert(std::next(i) == val.m_value.object->cend()); - o->write_characters(indent_string.c_str(), new_indent); - o->write_character('\"'); - dump_escaped(i->first, ensure_ascii); - o->write_characters("\": ", 3); - dump(i->second, true, ensure_ascii, indent_step, new_indent); - - o->write_character('\n'); - o->write_characters(indent_string.c_str(), current_indent); - o->write_character('}'); - } - else - { - o->write_character('{'); - - // first n-1 elements - auto i = val.m_value.object->cbegin(); - for (std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i) - { - o->write_character('\"'); - dump_escaped(i->first, ensure_ascii); - o->write_characters("\":", 2); - dump(i->second, false, ensure_ascii, indent_step, current_indent); - o->write_character(','); - } - - // last element - assert(i != val.m_value.object->cend()); - assert(std::next(i) == val.m_value.object->cend()); - o->write_character('\"'); - dump_escaped(i->first, ensure_ascii); - o->write_characters("\":", 2); - dump(i->second, false, ensure_ascii, indent_step, current_indent); - - o->write_character('}'); - } - - return; - } - - case value_t::array: - { - if (val.m_value.array->empty()) - { - o->write_characters("[]", 2); - return; - } - - if (pretty_print) - { - o->write_characters("[\n", 2); - - // variable to hold indentation for recursive calls - const auto new_indent = current_indent + indent_step; - if (JSON_UNLIKELY(indent_string.size() < new_indent)) - { - indent_string.resize(indent_string.size() * 2, ' '); - } - - // first n-1 elements - for (auto i = val.m_value.array->cbegin(); - i != val.m_value.array->cend() - 1; ++i) - { - o->write_characters(indent_string.c_str(), new_indent); - dump(*i, true, ensure_ascii, indent_step, new_indent); - o->write_characters(",\n", 2); - } - - // last element - assert(not val.m_value.array->empty()); - o->write_characters(indent_string.c_str(), new_indent); - dump(val.m_value.array->back(), true, ensure_ascii, indent_step, new_indent); - - o->write_character('\n'); - o->write_characters(indent_string.c_str(), current_indent); - o->write_character(']'); - } - else - { - o->write_character('['); - - // first n-1 elements - for (auto i = val.m_value.array->cbegin(); - i != val.m_value.array->cend() - 1; ++i) - { - dump(*i, false, ensure_ascii, indent_step, current_indent); - o->write_character(','); - } - - // last element - assert(not val.m_value.array->empty()); - dump(val.m_value.array->back(), false, ensure_ascii, indent_step, current_indent); - - o->write_character(']'); - } - - return; - } - - case value_t::string: - { - o->write_character('\"'); - dump_escaped(*val.m_value.string, ensure_ascii); - o->write_character('\"'); - return; - } - - case value_t::boolean: - { - if (val.m_value.boolean) - { - o->write_characters("true", 4); - } - else - { - o->write_characters("false", 5); - } - return; - } - - case value_t::number_integer: - { - dump_integer(val.m_value.number_integer); - return; - } - - case value_t::number_unsigned: - { - dump_integer(val.m_value.number_unsigned); - return; - } - - case value_t::number_float: - { - dump_float(val.m_value.number_float); - return; - } - - case value_t::discarded: - { - o->write_characters("", 11); - return; - } - - case value_t::null: - { - o->write_characters("null", 4); - return; - } - } - } - - private: - /*! - @brief returns the number of expected bytes following in UTF-8 string - - @param[in] u the first byte of a UTF-8 string - @return the number of expected bytes following - */ - static constexpr std::size_t bytes_following(const uint8_t u) - { - return ((u <= 127) ? 0 - : ((192 <= u and u <= 223) ? 1 - : ((224 <= u and u <= 239) ? 2 - : ((240 <= u and u <= 247) ? 3 : std::string::npos)))); - } - - /*! - @brief calculates the extra space to escape a JSON string - - @param[in] s the string to escape - @param[in] ensure_ascii whether to escape non-ASCII characters with - \uXXXX sequences - @return the number of characters required to escape string @a s - - @complexity Linear in the length of string @a s. - */ - static std::size_t extra_space(const string_t& s, - const bool ensure_ascii) noexcept - { - std::size_t res = 0; - - for (std::size_t i = 0; i < s.size(); ++i) - { - switch (s[i]) - { - // control characters that can be escaped with a backslash - case '"': - case '\\': - case '\b': - case '\f': - case '\n': - case '\r': - case '\t': - { - // from c (1 byte) to \x (2 bytes) - res += 1; - break; - } - - // control characters that need \uxxxx escaping - case 0x00: - case 0x01: - case 0x02: - case 0x03: - case 0x04: - case 0x05: - case 0x06: - case 0x07: - case 0x0B: - case 0x0E: - case 0x0F: - case 0x10: - case 0x11: - case 0x12: - case 0x13: - case 0x14: - case 0x15: - case 0x16: - case 0x17: - case 0x18: - case 0x19: - case 0x1A: - case 0x1B: - case 0x1C: - case 0x1D: - case 0x1E: - case 0x1F: - { - // from c (1 byte) to \uxxxx (6 bytes) - res += 5; - break; - } - - default: - { - if (ensure_ascii and (s[i] & 0x80 or s[i] == 0x7F)) - { - const auto bytes = bytes_following(static_cast(s[i])); - // invalid characters will be detected by throw_if_invalid_utf8 - assert (bytes != std::string::npos); - - if (bytes == 3) - { - // codepoints that need 4 bytes (i.e., 3 additional - // bytes) in UTF-8 need a surrogate pair when \u - // escaping is used: from 4 bytes to \uxxxx\uxxxx - // (12 bytes) - res += (12 - bytes - 1); - } - else - { - // from x bytes to \uxxxx (6 bytes) - res += (6 - bytes - 1); - } - - // skip the additional bytes - i += bytes; - } - break; - } - } - } - - return res; - } - - static void escape_codepoint(int codepoint, string_t& result, std::size_t& pos) - { - // expecting a proper codepoint - assert(0x00 <= codepoint and codepoint <= 0x10FFFF); - - // the last written character was the backslash before the 'u' - assert(result[pos] == '\\'); - - // write the 'u' - result[++pos] = 'u'; - - // convert a number 0..15 to its hex representation (0..f) - static const std::array hexify = - { - { - '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' - } - }; - - if (codepoint < 0x10000) - { - // codepoints U+0000..U+FFFF can be represented as \uxxxx. - result[++pos] = hexify[(codepoint >> 12) & 0x0F]; - result[++pos] = hexify[(codepoint >> 8) & 0x0F]; - result[++pos] = hexify[(codepoint >> 4) & 0x0F]; - result[++pos] = hexify[codepoint & 0x0F]; - } - else - { - // codepoints U+10000..U+10FFFF need a surrogate pair to be - // represented as \uxxxx\uxxxx. - // http://www.unicode.org/faq/utf_bom.html#utf16-4 - codepoint -= 0x10000; - const int high_surrogate = 0xD800 | ((codepoint >> 10) & 0x3FF); - const int low_surrogate = 0xDC00 | (codepoint & 0x3FF); - result[++pos] = hexify[(high_surrogate >> 12) & 0x0F]; - result[++pos] = hexify[(high_surrogate >> 8) & 0x0F]; - result[++pos] = hexify[(high_surrogate >> 4) & 0x0F]; - result[++pos] = hexify[high_surrogate & 0x0F]; - ++pos; // backslash is already in output - result[++pos] = 'u'; - result[++pos] = hexify[(low_surrogate >> 12) & 0x0F]; - result[++pos] = hexify[(low_surrogate >> 8) & 0x0F]; - result[++pos] = hexify[(low_surrogate >> 4) & 0x0F]; - result[++pos] = hexify[low_surrogate & 0x0F]; - } - - ++pos; - } - - /*! - @brief dump escaped string - - Escape a string by replacing certain special characters by a sequence of an - escape character (backslash) and another character and other control - characters by a sequence of "\u" followed by a four-digit hex - representation. The escaped string is written to output stream @a o. - - @param[in] s the string to escape - @param[in] ensure_ascii whether to escape non-ASCII characters with - \uXXXX sequences - - @complexity Linear in the length of string @a s. - */ - void dump_escaped(const string_t& s, const bool ensure_ascii) const - { - throw_if_invalid_utf8(s); - - const auto space = extra_space(s, ensure_ascii); - if (space == 0) - { - o->write_characters(s.c_str(), s.size()); - return; - } - - // create a result string of necessary size - string_t result(s.size() + space, '\\'); - std::size_t pos = 0; - - for (std::size_t i = 0; i < s.size(); ++i) - { - switch (s[i]) - { - case '"': // quotation mark (0x22) - { - result[pos + 1] = '"'; - pos += 2; - break; - } - - case '\\': // reverse solidus (0x5C) - { - // nothing to change - pos += 2; - break; - } - - case '\b': // backspace (0x08) - { - result[pos + 1] = 'b'; - pos += 2; - break; - } - - case '\f': // formfeed (0x0C) - { - result[pos + 1] = 'f'; - pos += 2; - break; - } - - case '\n': // newline (0x0A) - { - result[pos + 1] = 'n'; - pos += 2; - break; - } - - case '\r': // carriage return (0x0D) - { - result[pos + 1] = 'r'; - pos += 2; - break; - } - - case '\t': // horizontal tab (0x09) - { - result[pos + 1] = 't'; - pos += 2; - break; - } - - default: - { - // escape control characters (0x00..0x1F) or, if - // ensure_ascii parameter is used, non-ASCII characters - if ((0x00 <= s[i] and s[i] <= 0x1F) or - (ensure_ascii and (s[i] & 0x80 or s[i] == 0x7F))) - { - const auto bytes = bytes_following(static_cast(s[i])); - // invalid characters will be detected by throw_if_invalid_utf8 - assert (bytes != std::string::npos); - - // check that the additional bytes are present - assert(i + bytes < s.size()); - - // to use \uxxxx escaping, we first need to calculate - // the codepoint from the UTF-8 bytes - int codepoint = 0; - - // bytes is unsigned type: - assert(bytes <= 3); - switch (bytes) - { - case 0: - { - codepoint = s[i] & 0xFF; - break; - } - - case 1: - { - codepoint = ((s[i] & 0x3F) << 6) - + (s[i + 1] & 0x7F); - break; - } - - case 2: - { - codepoint = ((s[i] & 0x1F) << 12) - + ((s[i + 1] & 0x7F) << 6) - + (s[i + 2] & 0x7F); - break; - } - - case 3: - { - codepoint = ((s[i] & 0xF) << 18) - + ((s[i + 1] & 0x7F) << 12) - + ((s[i + 2] & 0x7F) << 6) - + (s[i + 3] & 0x7F); - break; - } - - default: - break; // LCOV_EXCL_LINE - } - - escape_codepoint(codepoint, result, pos); - i += bytes; - } - else - { - // all other characters are added as-is - result[pos++] = s[i]; - } - break; - } - } - } - - assert(pos == result.size()); - o->write_characters(result.c_str(), result.size()); - } - - /*! - @brief dump an integer - - Dump a given integer to output stream @a o. Works internally with - @a number_buffer. - - @param[in] x integer number (signed or unsigned) to dump - @tparam NumberType either @a number_integer_t or @a number_unsigned_t - */ - template::value or - std::is_same::value, - int> = 0> - void dump_integer(NumberType x) - { - // special case for "0" - if (x == 0) - { - o->write_character('0'); - return; - } - - const bool is_negative = (x <= 0) and (x != 0); // see issue #755 - std::size_t i = 0; - - while (x != 0) - { - // spare 1 byte for '\0' - assert(i < number_buffer.size() - 1); - - const auto digit = std::labs(static_cast(x % 10)); - number_buffer[i++] = static_cast('0' + digit); - x /= 10; - } - - if (is_negative) - { - // make sure there is capacity for the '-' - assert(i < number_buffer.size() - 2); - number_buffer[i++] = '-'; - } - - std::reverse(number_buffer.begin(), number_buffer.begin() + i); - o->write_characters(number_buffer.data(), i); - } - - /*! - @brief dump a floating-point number - - Dump a given floating-point number to output stream @a o. Works internally - with @a number_buffer. - - @param[in] x floating-point number to dump - */ - void dump_float(number_float_t x) - { - // NaN / inf - if (not std::isfinite(x) or std::isnan(x)) - { - o->write_characters("null", 4); - return; - } - - // get number of digits for a text -> float -> text round-trip - static constexpr auto d = std::numeric_limits::digits10; - - // the actual conversion - std::ptrdiff_t len = snprintf(number_buffer.data(), number_buffer.size(), "%.*g", d, x); - - // negative value indicates an error - assert(len > 0); - // check if buffer was large enough - assert(static_cast(len) < number_buffer.size()); - - // erase thousands separator - if (thousands_sep != '\0') - { - const auto end = std::remove(number_buffer.begin(), - number_buffer.begin() + len, thousands_sep); - std::fill(end, number_buffer.end(), '\0'); - assert((end - number_buffer.begin()) <= len); - len = (end - number_buffer.begin()); - } - - // convert decimal point to '.' - if (decimal_point != '\0' and decimal_point != '.') - { - const auto dec_pos = std::find(number_buffer.begin(), number_buffer.end(), decimal_point); - if (dec_pos != number_buffer.end()) - { - *dec_pos = '.'; - } - } - - o->write_characters(number_buffer.data(), static_cast(len)); - - // determine if need to append ".0" - const bool value_is_int_like = - std::none_of(number_buffer.begin(), number_buffer.begin() + len + 1, - [](char c) - { - return (c == '.' or c == 'e'); - }); - - if (value_is_int_like) - { - o->write_characters(".0", 2); - } - } - - /*! - @brief check whether a string is UTF-8 encoded - - The function checks each byte of a string whether it is UTF-8 encoded. The - result of the check is stored in the @a state parameter. The function must - be called initially with state 0 (accept). State 1 means the string must - be rejected, because the current byte is not allowed. If the string is - completely processed, but the state is non-zero, the string ended - prematurely; that is, the last byte indicated more bytes should have - followed. - - @param[in,out] state the state of the decoding - @param[in] byte next byte to decode - - @note The function has been edited: a std::array is used and the code - point is not calculated. - - @copyright Copyright (c) 2008-2009 Bjoern Hoehrmann - @sa http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ - */ - static void decode(uint8_t& state, const uint8_t byte) - { - static const std::array utf8d = - { - { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00..1F - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20..3F - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 40..5F - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60..7F - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 80..9F - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // A0..BF - 8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // C0..DF - 0xA, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3, 0x3, // E0..EF - 0xB, 0x6, 0x6, 0x6, 0x5, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, // F0..FF - 0x0, 0x1, 0x2, 0x3, 0x5, 0x8, 0x7, 0x1, 0x1, 0x1, 0x4, 0x6, 0x1, 0x1, 0x1, 0x1, // s0..s0 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, // s1..s2 - 1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, // s3..s4 - 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, // s5..s6 - 1, 3, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // s7..s8 - } - }; - - const uint8_t type = utf8d[byte]; - state = utf8d[256u + state * 16u + type]; - } - - /*! - @brief throw an exception if a string is not UTF-8 encoded - - @param[in] str UTF-8 string to check - @throw type_error.316 if passed string is not UTF-8 encoded - - @since version 3.0.0 - */ - static void throw_if_invalid_utf8(const std::string& str) - { - // start with state 0 (= accept) - uint8_t state = 0; - - for (size_t i = 0; i < str.size(); ++i) - { - const auto byte = static_cast(str[i]); - decode(state, byte); - if (state == 1) - { - // state 1 means reject - std::stringstream ss; - ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << static_cast(byte); - JSON_THROW(type_error::create(316, "invalid UTF-8 byte at index " + std::to_string(i) + ": 0x" + ss.str())); - } - } - - if (state != 0) - { - // we finish reading, but do not accept: string was incomplete - std::stringstream ss; - ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << static_cast(static_cast(str.back())); - JSON_THROW(type_error::create(316, "incomplete UTF-8 string; last byte: 0x" + ss.str())); - } - } - - private: - /// the output of the serializer - output_adapter_t o = nullptr; - - /// a (hopefully) large enough character buffer - std::array number_buffer{{}}; - - /// the locale - const std::lconv* loc = nullptr; - /// the locale's thousand separator character - const char thousands_sep = '\0'; - /// the locale's decimal point character - const char decimal_point = '\0'; - - /// the indentation character - const char indent_char; - - /// the indentation string - string_t indent_string; -}; -} -} - -#endif - -/*** End of inlined file: serializer.hpp ***/ - - -/*** Start of inlined file: json_ref.hpp ***/ -#ifndef NLOHMANN_JSON_DETAIL_JSON_REF_HPP -#define NLOHMANN_JSON_DETAIL_JSON_REF_HPP - -#include -#include - -namespace nlohmann -{ -namespace detail -{ -template -class json_ref -{ - public: - using value_type = BasicJsonType; - - json_ref(value_type&& value) - : owned_value(std::move(value)), value_ref(&owned_value), is_rvalue(true) - {} - - json_ref(const value_type& value) - : value_ref(const_cast(&value)), is_rvalue(false) - {} - - json_ref(std::initializer_list init) - : owned_value(init), value_ref(&owned_value), is_rvalue(true) - {} - - template - json_ref(Args&& ... args) - : owned_value(std::forward(args)...), value_ref(&owned_value), is_rvalue(true) - {} - - // class should be movable only - json_ref(json_ref&&) = default; - json_ref(const json_ref&) = delete; - json_ref& operator=(const json_ref&) = delete; - - value_type moved_or_copied() const - { - if (is_rvalue) - { - return std::move(*value_ref); - } - return *value_ref; - } - - value_type const& operator*() const - { - return *static_cast(value_ref); - } - - value_type const* operator->() const - { - return static_cast(value_ref); - } - - private: - mutable value_type owned_value = nullptr; - value_type* value_ref = nullptr; - const bool is_rvalue; -}; -} -} - -#endif - -/*** End of inlined file: json_ref.hpp ***/ - - -/*** Start of inlined file: adl_serializer.hpp ***/ -#ifndef NLOHMANN_JSON_ADL_SERIALIZER_HPP -#define NLOHMANN_JSON_ADL_SERIALIZER_HPP - -#include - -namespace nlohmann -{ -template -struct adl_serializer -{ - /*! - @brief convert a JSON value to any value type - - This function is usually called by the `get()` function of the - @ref basic_json class (either explicit or via conversion operators). - - @param[in] j JSON value to read from - @param[in,out] val value to write to - */ - template - static void from_json(BasicJsonType&& j, ValueType& val) noexcept( - noexcept(::nlohmann::from_json(std::forward(j), val))) - { - ::nlohmann::from_json(std::forward(j), val); - } - - /*! - @brief convert any value type to a JSON value - - This function is usually called by the constructors of the @ref basic_json - class. - - @param[in,out] j JSON value to write to - @param[in] val value to read from - */ - template - static void to_json(BasicJsonType& j, ValueType&& val) noexcept( - noexcept(::nlohmann::to_json(j, std::forward(val)))) - { - ::nlohmann::to_json(j, std::forward(val)); - } -}; -} - -#endif - -/*** End of inlined file: adl_serializer.hpp ***/ - -/*! -@brief namespace for Niels Lohmann -@see https://github.com/nlohmann -@since version 1.0.0 -*/ -namespace nlohmann -{ -class json_pointer -{ - /// allow basic_json to access private members - NLOHMANN_BASIC_JSON_TPL_DECLARATION - friend class basic_json; - - public: - /*! - @brief create JSON pointer - - Create a JSON pointer according to the syntax described in - [Section 3 of RFC6901](https://tools.ietf.org/html/rfc6901#section-3). - - @param[in] s string representing the JSON pointer; if omitted, the empty - string is assumed which references the whole JSON value - - @throw parse_error.107 if the given JSON pointer @a s is nonempty and - does not begin with a slash (`/`); see example below - - @throw parse_error.108 if a tilde (`~`) in the given JSON pointer @a s - is not followed by `0` (representing `~`) or `1` (representing `/`); - see example below - - @liveexample{The example shows the construction several valid JSON - pointers as well as the exceptional behavior.,json_pointer} - - @since version 2.0.0 - */ - explicit json_pointer(const std::string& s = "") : reference_tokens(split(s)) {} - - /*! - @brief return a string representation of the JSON pointer - - @invariant For each JSON pointer `ptr`, it holds: - @code {.cpp} - ptr == json_pointer(ptr.to_string()); - @endcode - - @return a string representation of the JSON pointer - - @liveexample{The example shows the result of `to_string`., - json_pointer__to_string} - - @since version 2.0.0 - */ - std::string to_string() const noexcept - { - return std::accumulate(reference_tokens.begin(), reference_tokens.end(), - std::string{}, - [](const std::string & a, const std::string & b) - { - return a + "/" + escape(b); - }); - } - - /// @copydoc to_string() - operator std::string() const - { - return to_string(); - } - - /*! - @param[in] s reference token to be converted into an array index - - @return integer representation of @a s - - @throw out_of_range.404 if string @a s could not be converted to an integer - */ - static int array_index(const std::string& s) - { - size_t processed_chars = 0; - const int res = std::stoi(s, &processed_chars); - - // check if the string was completely read - if (JSON_UNLIKELY(processed_chars != s.size())) - { - JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + s + "'")); - } - - return res; - } - - private: - /*! - @brief remove and return last reference pointer - @throw out_of_range.405 if JSON pointer has no parent - */ - std::string pop_back() - { - if (JSON_UNLIKELY(is_root())) - { - JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent")); - } - - auto last = reference_tokens.back(); - reference_tokens.pop_back(); - return last; - } - - /// return whether pointer points to the root document - bool is_root() const - { - return reference_tokens.empty(); - } - - json_pointer top() const - { - if (JSON_UNLIKELY(is_root())) - { - JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent")); - } - - json_pointer result = *this; - result.reference_tokens = {reference_tokens[0]}; - return result; - } - - /*! - @brief create and return a reference to the pointed to value - - @complexity Linear in the number of reference tokens. - - @throw parse_error.109 if array index is not a number - @throw type_error.313 if value cannot be unflattened - */ - NLOHMANN_BASIC_JSON_TPL_DECLARATION - NLOHMANN_BASIC_JSON_TPL& get_and_create(NLOHMANN_BASIC_JSON_TPL& j) const; - - /*! - @brief return a reference to the pointed to value - - @note This version does not throw if a value is not present, but tries to - create nested values instead. For instance, calling this function - with pointer `"/this/that"` on a null value is equivalent to calling - `operator[]("this").operator[]("that")` on that value, effectively - changing the null value to an object. - - @param[in] ptr a JSON value - - @return reference to the JSON value pointed to by the JSON pointer - - @complexity Linear in the length of the JSON pointer. - - @throw parse_error.106 if an array index begins with '0' - @throw parse_error.109 if an array index was not a number - @throw out_of_range.404 if the JSON pointer can not be resolved - */ - NLOHMANN_BASIC_JSON_TPL_DECLARATION - NLOHMANN_BASIC_JSON_TPL& get_unchecked(NLOHMANN_BASIC_JSON_TPL* ptr) const; - - /*! - @throw parse_error.106 if an array index begins with '0' - @throw parse_error.109 if an array index was not a number - @throw out_of_range.402 if the array index '-' is used - @throw out_of_range.404 if the JSON pointer can not be resolved - */ - NLOHMANN_BASIC_JSON_TPL_DECLARATION - NLOHMANN_BASIC_JSON_TPL& get_checked(NLOHMANN_BASIC_JSON_TPL* ptr) const; - - /*! - @brief return a const reference to the pointed to value - - @param[in] ptr a JSON value - - @return const reference to the JSON value pointed to by the JSON - pointer - - @throw parse_error.106 if an array index begins with '0' - @throw parse_error.109 if an array index was not a number - @throw out_of_range.402 if the array index '-' is used - @throw out_of_range.404 if the JSON pointer can not be resolved - */ - NLOHMANN_BASIC_JSON_TPL_DECLARATION - const NLOHMANN_BASIC_JSON_TPL& get_unchecked(const NLOHMANN_BASIC_JSON_TPL* ptr) const; - - /*! - @throw parse_error.106 if an array index begins with '0' - @throw parse_error.109 if an array index was not a number - @throw out_of_range.402 if the array index '-' is used - @throw out_of_range.404 if the JSON pointer can not be resolved - */ - NLOHMANN_BASIC_JSON_TPL_DECLARATION - const NLOHMANN_BASIC_JSON_TPL& get_checked(const NLOHMANN_BASIC_JSON_TPL* ptr) const; - - /*! - @brief split the string input to reference tokens - - @note This function is only called by the json_pointer constructor. - All exceptions below are documented there. - - @throw parse_error.107 if the pointer is not empty or begins with '/' - @throw parse_error.108 if character '~' is not followed by '0' or '1' - */ - static std::vector split(const std::string& reference_string) - { - std::vector result; - - // special case: empty reference string -> no reference tokens - if (reference_string.empty()) - { - return result; - } - - // check if nonempty reference string begins with slash - if (JSON_UNLIKELY(reference_string[0] != '/')) - { - JSON_THROW(detail::parse_error::create(107, 1, - "JSON pointer must be empty or begin with '/' - was: '" + - reference_string + "'")); - } - - // extract the reference tokens: - // - slash: position of the last read slash (or end of string) - // - start: position after the previous slash - for ( - // search for the first slash after the first character - std::size_t slash = reference_string.find_first_of('/', 1), - // set the beginning of the first reference token - start = 1; - // we can stop if start == string::npos+1 = 0 - start != 0; - // set the beginning of the next reference token - // (will eventually be 0 if slash == std::string::npos) - start = slash + 1, - // find next slash - slash = reference_string.find_first_of('/', start)) - { - // use the text between the beginning of the reference token - // (start) and the last slash (slash). - auto reference_token = reference_string.substr(start, slash - start); - - // check reference tokens are properly escaped - for (std::size_t pos = reference_token.find_first_of('~'); - pos != std::string::npos; - pos = reference_token.find_first_of('~', pos + 1)) - { - assert(reference_token[pos] == '~'); - - // ~ must be followed by 0 or 1 - if (JSON_UNLIKELY(pos == reference_token.size() - 1 or - (reference_token[pos + 1] != '0' and - reference_token[pos + 1] != '1'))) - { - JSON_THROW(detail::parse_error::create(108, 0, "escape character '~' must be followed with '0' or '1'")); - } - } - - // finally, store the reference token - unescape(reference_token); - result.push_back(reference_token); - } - - return result; - } - - /*! - @brief replace all occurrences of a substring by another string - - @param[in,out] s the string to manipulate; changed so that all - occurrences of @a f are replaced with @a t - @param[in] f the substring to replace with @a t - @param[in] t the string to replace @a f - - @pre The search string @a f must not be empty. **This precondition is - enforced with an assertion.** - - @since version 2.0.0 - */ - static void replace_substring(std::string& s, const std::string& f, - const std::string& t) - { - assert(not f.empty()); - for (auto pos = s.find(f); // find first occurrence of f - pos != std::string::npos; // make sure f was found - s.replace(pos, f.size(), t), // replace with t, and - pos = s.find(f, pos + t.size())) // find next occurrence of f - {} - } - - /// escape "~"" to "~0" and "/" to "~1" - static std::string escape(std::string s) - { - replace_substring(s, "~", "~0"); - replace_substring(s, "/", "~1"); - return s; - } - - /// unescape "~1" to tilde and "~0" to slash (order is important!) - static void unescape(std::string& s) - { - replace_substring(s, "~1", "/"); - replace_substring(s, "~0", "~"); - } - - /*! - @param[in] reference_string the reference string to the current value - @param[in] value the value to consider - @param[in,out] result the result object to insert values to - - @note Empty objects or arrays are flattened to `null`. - */ - NLOHMANN_BASIC_JSON_TPL_DECLARATION - static void flatten(const std::string& reference_string, - const NLOHMANN_BASIC_JSON_TPL& value, - NLOHMANN_BASIC_JSON_TPL& result); - - /*! - @param[in] value flattened JSON - - @return unflattened JSON - - @throw parse_error.109 if array index is not a number - @throw type_error.314 if value is not an object - @throw type_error.315 if object values are not primitive - @throw type_error.313 if value cannot be unflattened - */ - NLOHMANN_BASIC_JSON_TPL_DECLARATION - static NLOHMANN_BASIC_JSON_TPL - unflatten(const NLOHMANN_BASIC_JSON_TPL& value); - - friend bool operator==(json_pointer const& lhs, - json_pointer const& rhs) noexcept; - - friend bool operator!=(json_pointer const& lhs, - json_pointer const& rhs) noexcept; - - /// the reference tokens - std::vector reference_tokens; -}; - -/*! -@brief a class to store JSON values - -@tparam ObjectType type for JSON objects (`std::map` by default; will be used -in @ref object_t) -@tparam ArrayType type for JSON arrays (`std::vector` by default; will be used -in @ref array_t) -@tparam StringType type for JSON strings and object keys (`std::string` by -default; will be used in @ref string_t) -@tparam BooleanType type for JSON booleans (`bool` by default; will be used -in @ref boolean_t) -@tparam NumberIntegerType type for JSON integer numbers (`int64_t` by -default; will be used in @ref number_integer_t) -@tparam NumberUnsignedType type for JSON unsigned integer numbers (@c -`uint64_t` by default; will be used in @ref number_unsigned_t) -@tparam NumberFloatType type for JSON floating-point numbers (`double` by -default; will be used in @ref number_float_t) -@tparam AllocatorType type of the allocator to use (`std::allocator` by -default) -@tparam JSONSerializer the serializer to resolve internal calls to `to_json()` -and `from_json()` (@ref adl_serializer by default) - -@requirement The class satisfies the following concept requirements: -- Basic - - [DefaultConstructible](http://en.cppreference.com/w/cpp/concept/DefaultConstructible): - JSON values can be default constructed. The result will be a JSON null - value. - - [MoveConstructible](http://en.cppreference.com/w/cpp/concept/MoveConstructible): - A JSON value can be constructed from an rvalue argument. - - [CopyConstructible](http://en.cppreference.com/w/cpp/concept/CopyConstructible): - A JSON value can be copy-constructed from an lvalue expression. - - [MoveAssignable](http://en.cppreference.com/w/cpp/concept/MoveAssignable): - A JSON value van be assigned from an rvalue argument. - - [CopyAssignable](http://en.cppreference.com/w/cpp/concept/CopyAssignable): - A JSON value can be copy-assigned from an lvalue expression. - - [Destructible](http://en.cppreference.com/w/cpp/concept/Destructible): - JSON values can be destructed. -- Layout - - [StandardLayoutType](http://en.cppreference.com/w/cpp/concept/StandardLayoutType): - JSON values have - [standard layout](http://en.cppreference.com/w/cpp/language/data_members#Standard_layout): - All non-static data members are private and standard layout types, the - class has no virtual functions or (virtual) base classes. -- Library-wide - - [EqualityComparable](http://en.cppreference.com/w/cpp/concept/EqualityComparable): - JSON values can be compared with `==`, see @ref - operator==(const_reference,const_reference). - - [LessThanComparable](http://en.cppreference.com/w/cpp/concept/LessThanComparable): - JSON values can be compared with `<`, see @ref - operator<(const_reference,const_reference). - - [Swappable](http://en.cppreference.com/w/cpp/concept/Swappable): - Any JSON lvalue or rvalue of can be swapped with any lvalue or rvalue of - other compatible types, using unqualified function call @ref swap(). - - [NullablePointer](http://en.cppreference.com/w/cpp/concept/NullablePointer): - JSON values can be compared against `std::nullptr_t` objects which are used - to model the `null` value. -- Container - - [Container](http://en.cppreference.com/w/cpp/concept/Container): - JSON values can be used like STL containers and provide iterator access. - - [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer); - JSON values can be used like STL containers and provide reverse iterator - access. - -@invariant The member variables @a m_value and @a m_type have the following -relationship: -- If `m_type == value_t::object`, then `m_value.object != nullptr`. -- If `m_type == value_t::array`, then `m_value.array != nullptr`. -- If `m_type == value_t::string`, then `m_value.string != nullptr`. -The invariants are checked by member function assert_invariant(). - -@internal -@note ObjectType trick from http://stackoverflow.com/a/9860911 -@endinternal - -@see [RFC 7159: The JavaScript Object Notation (JSON) Data Interchange -Format](http://rfc7159.net/rfc7159) - -@since version 1.0.0 - -@nosubgrouping -*/ -NLOHMANN_BASIC_JSON_TPL_DECLARATION -class basic_json -{ - private: - template friend struct detail::external_constructor; - friend ::nlohmann::json_pointer; - friend ::nlohmann::detail::parser; - friend ::nlohmann::detail::serializer; - template - friend class ::nlohmann::detail::iter_impl; - template - friend class ::nlohmann::detail::binary_writer; - template - friend class ::nlohmann::detail::binary_reader; - - /// workaround type for MSVC - using basic_json_t = NLOHMANN_BASIC_JSON_TPL; - - // convenience aliases for types residing in namespace detail; - using lexer = ::nlohmann::detail::lexer; - using parser = ::nlohmann::detail::parser; - - using primitive_iterator_t = ::nlohmann::detail::primitive_iterator_t; - template - using internal_iterator = ::nlohmann::detail::internal_iterator; - template - using iter_impl = ::nlohmann::detail::iter_impl; - template - using iteration_proxy = ::nlohmann::detail::iteration_proxy; - template using json_reverse_iterator = ::nlohmann::detail::json_reverse_iterator; - - template - using output_adapter_t = ::nlohmann::detail::output_adapter_t; - - using binary_reader = ::nlohmann::detail::binary_reader; - template using binary_writer = ::nlohmann::detail::binary_writer; - - using serializer = ::nlohmann::detail::serializer; - - public: - using value_t = detail::value_t; - /// @copydoc nlohmann::json_pointer - using json_pointer = ::nlohmann::json_pointer; - template - using json_serializer = JSONSerializer; - /// helper type for initializer lists of basic_json values - using initializer_list_t = std::initializer_list>; - - //////////////// - // exceptions // - //////////////// - - /// @name exceptions - /// Classes to implement user-defined exceptions. - /// @{ - - /// @copydoc detail::exception - using exception = detail::exception; - /// @copydoc detail::parse_error - using parse_error = detail::parse_error; - /// @copydoc detail::invalid_iterator - using invalid_iterator = detail::invalid_iterator; - /// @copydoc detail::type_error - using type_error = detail::type_error; - /// @copydoc detail::out_of_range - using out_of_range = detail::out_of_range; - /// @copydoc detail::other_error - using other_error = detail::other_error; - - /// @} - - ///////////////////// - // container types // - ///////////////////// - - /// @name container types - /// The canonic container types to use @ref basic_json like any other STL - /// container. - /// @{ - - /// the type of elements in a basic_json container - using value_type = basic_json; - - /// the type of an element reference - using reference = value_type&; - /// the type of an element const reference - using const_reference = const value_type&; - - /// a type to represent differences between iterators - using difference_type = std::ptrdiff_t; - /// a type to represent container sizes - using size_type = std::size_t; - - /// the allocator type - using allocator_type = AllocatorType; - - /// the type of an element pointer - using pointer = typename std::allocator_traits::pointer; - /// the type of an element const pointer - using const_pointer = typename std::allocator_traits::const_pointer; - - /// an iterator for a basic_json container - using iterator = iter_impl; - /// a const iterator for a basic_json container - using const_iterator = iter_impl; - /// a reverse iterator for a basic_json container - using reverse_iterator = json_reverse_iterator; - /// a const reverse iterator for a basic_json container - using const_reverse_iterator = json_reverse_iterator; - - /// @} - - /*! - @brief returns the allocator associated with the container - */ - static allocator_type get_allocator() - { - return allocator_type(); - } - - /*! - @brief returns version information on the library - - This function returns a JSON object with information about the library, - including the version number and information on the platform and compiler. - - @return JSON object holding version information - key | description - ----------- | --------------- - `compiler` | Information on the used compiler. It is an object with the following keys: `c++` (the used C++ standard), `family` (the compiler family; possible values are `clang`, `icc`, `gcc`, `ilecpp`, `msvc`, `pgcpp`, `sunpro`, and `unknown`), and `version` (the compiler version). - `copyright` | The copyright line for the library as string. - `name` | The name of the library as string. - `platform` | The used platform as string. Possible values are `win32`, `linux`, `apple`, `unix`, and `unknown`. - `url` | The URL of the project as string. - `version` | The version of the library. It is an object with the following keys: `major`, `minor`, and `patch` as defined by [Semantic Versioning](http://semver.org), and `string` (the version string). - - @liveexample{The following code shows an example output of the `meta()` - function.,meta} - - @exceptionsafety Strong guarantee: if an exception is thrown, there are no - changes to any JSON value. - - @complexity Constant. - - @since 2.1.0 - */ - static basic_json meta() - { - basic_json result; - - result["copyright"] = "(C) 2013-2017 Niels Lohmann"; - result["name"] = "JSON for Modern C++"; - result["url"] = "https://github.com/nlohmann/json"; - result["version"] = - { - {"string", "3.0.0"}, {"major", 3}, {"minor", 0}, {"patch", 0} - }; - -#ifdef _WIN32 - result["platform"] = "win32"; -#elif defined __linux__ - result["platform"] = "linux"; -#elif defined __APPLE__ - result["platform"] = "apple"; -#elif defined __unix__ - result["platform"] = "unix"; -#else - result["platform"] = "unknown"; -#endif - -#if defined(__ICC) || defined(__INTEL_COMPILER) - result["compiler"] = {{"family", "icc"}, {"version", __INTEL_COMPILER}}; -#elif defined(__clang__) - result["compiler"] = {{"family", "clang"}, {"version", __clang_version__}}; -#elif defined(__GNUC__) || defined(__GNUG__) - result["compiler"] = {{"family", "gcc"}, {"version", std::to_string(__GNUC__) + "." + std::to_string(__GNUC_MINOR__) + "." + std::to_string(__GNUC_PATCHLEVEL__)}}; -#elif defined(__HP_cc) || defined(__HP_aCC) - result["compiler"] = "hp" -#elif defined(__IBMCPP__) - result["compiler"] = {{"family", "ilecpp"}, {"version", __IBMCPP__}}; -#elif defined(_MSC_VER) - result["compiler"] = {{"family", "msvc"}, {"version", _MSC_VER}}; -#elif defined(__PGI) - result["compiler"] = {{"family", "pgcpp"}, {"version", __PGI}}; -#elif defined(__SUNPRO_CC) - result["compiler"] = {{"family", "sunpro"}, {"version", __SUNPRO_CC}}; -#else - result["compiler"] = {{"family", "unknown"}, {"version", "unknown"}}; -#endif - -#ifdef __cplusplus - result["compiler"]["c++"] = std::to_string(__cplusplus); -#else - result["compiler"]["c++"] = "unknown"; -#endif - return result; - } - - /////////////////////////// - // JSON value data types // - /////////////////////////// - - /// @name JSON value data types - /// The data types to store a JSON value. These types are derived from - /// the template arguments passed to class @ref basic_json. - /// @{ - -#if defined(JSON_HAS_CPP_14) - // Use transparent comparator if possible, combined with perfect forwarding - // on find() and count() calls prevents unnecessary string construction. - using object_comparator_t = std::less<>; -#else - using object_comparator_t = std::less; -#endif - - /*! - @brief a type for an object - - [RFC 7159](http://rfc7159.net/rfc7159) describes JSON objects as follows: - > An object is an unordered collection of zero or more name/value pairs, - > where a name is a string and a value is a string, number, boolean, null, - > object, or array. - - To store objects in C++, a type is defined by the template parameters - described below. - - @tparam ObjectType the container to store objects (e.g., `std::map` or - `std::unordered_map`) - @tparam StringType the type of the keys or names (e.g., `std::string`). - The comparison function `std::less` is used to order elements - inside the container. - @tparam AllocatorType the allocator to use for objects (e.g., - `std::allocator`) - - #### Default type - - With the default values for @a ObjectType (`std::map`), @a StringType - (`std::string`), and @a AllocatorType (`std::allocator`), the default - value for @a object_t is: - - @code {.cpp} - std::map< - std::string, // key_type - basic_json, // value_type - std::less, // key_compare - std::allocator> // allocator_type - > - @endcode - - #### Behavior - - The choice of @a object_t influences the behavior of the JSON class. With - the default type, objects have the following behavior: - - - When all names are unique, objects will be interoperable in the sense - that all software implementations receiving that object will agree on - the name-value mappings. - - When the names within an object are not unique, later stored name/value - pairs overwrite previously stored name/value pairs, leaving the used - names unique. For instance, `{"key": 1}` and `{"key": 2, "key": 1}` will - be treated as equal and both stored as `{"key": 1}`. - - Internally, name/value pairs are stored in lexicographical order of the - names. Objects will also be serialized (see @ref dump) in this order. - For instance, `{"b": 1, "a": 2}` and `{"a": 2, "b": 1}` will be stored - and serialized as `{"a": 2, "b": 1}`. - - When comparing objects, the order of the name/value pairs is irrelevant. - This makes objects interoperable in the sense that they will not be - affected by these differences. For instance, `{"b": 1, "a": 2}` and - `{"a": 2, "b": 1}` will be treated as equal. - - #### Limits - - [RFC 7159](http://rfc7159.net/rfc7159) specifies: - > An implementation may set limits on the maximum depth of nesting. - - In this class, the object's limit of nesting is not explicitly constrained. - However, a maximum depth of nesting may be introduced by the compiler or - runtime environment. A theoretical limit can be queried by calling the - @ref max_size function of a JSON object. - - #### Storage - - Objects are stored as pointers in a @ref basic_json type. That is, for any - access to object values, a pointer of type `object_t*` must be - dereferenced. - - @sa @ref array_t -- type for an array value - - @since version 1.0.0 - - @note The order name/value pairs are added to the object is *not* - preserved by the library. Therefore, iterating an object may return - name/value pairs in a different order than they were originally stored. In - fact, keys will be traversed in alphabetical order as `std::map` with - `std::less` is used by default. Please note this behavior conforms to [RFC - 7159](http://rfc7159.net/rfc7159), because any order implements the - specified "unordered" nature of JSON objects. - */ - using object_t = ObjectType>>; - - /*! - @brief a type for an array - - [RFC 7159](http://rfc7159.net/rfc7159) describes JSON arrays as follows: - > An array is an ordered sequence of zero or more values. - - To store objects in C++, a type is defined by the template parameters - explained below. - - @tparam ArrayType container type to store arrays (e.g., `std::vector` or - `std::list`) - @tparam AllocatorType allocator to use for arrays (e.g., `std::allocator`) - - #### Default type - - With the default values for @a ArrayType (`std::vector`) and @a - AllocatorType (`std::allocator`), the default value for @a array_t is: - - @code {.cpp} - std::vector< - basic_json, // value_type - std::allocator // allocator_type - > - @endcode - - #### Limits - - [RFC 7159](http://rfc7159.net/rfc7159) specifies: - > An implementation may set limits on the maximum depth of nesting. - - In this class, the array's limit of nesting is not explicitly constrained. - However, a maximum depth of nesting may be introduced by the compiler or - runtime environment. A theoretical limit can be queried by calling the - @ref max_size function of a JSON array. - - #### Storage - - Arrays are stored as pointers in a @ref basic_json type. That is, for any - access to array values, a pointer of type `array_t*` must be dereferenced. - - @sa @ref object_t -- type for an object value - - @since version 1.0.0 - */ - using array_t = ArrayType>; - - /*! - @brief a type for a string - - [RFC 7159](http://rfc7159.net/rfc7159) describes JSON strings as follows: - > A string is a sequence of zero or more Unicode characters. - - To store objects in C++, a type is defined by the template parameter - described below. Unicode values are split by the JSON class into - byte-sized characters during deserialization. - - @tparam StringType the container to store strings (e.g., `std::string`). - Note this container is used for keys/names in objects, see @ref object_t. - - #### Default type - - With the default values for @a StringType (`std::string`), the default - value for @a string_t is: - - @code {.cpp} - std::string - @endcode - - #### Encoding - - Strings are stored in UTF-8 encoding. Therefore, functions like - `std::string::size()` or `std::string::length()` return the number of - bytes in the string rather than the number of characters or glyphs. - - #### String comparison - - [RFC 7159](http://rfc7159.net/rfc7159) states: - > Software implementations are typically required to test names of object - > members for equality. Implementations that transform the textual - > representation into sequences of Unicode code units and then perform the - > comparison numerically, code unit by code unit, are interoperable in the - > sense that implementations will agree in all cases on equality or - > inequality of two strings. For example, implementations that compare - > strings with escaped characters unconverted may incorrectly find that - > `"a\\b"` and `"a\u005Cb"` are not equal. - - This implementation is interoperable as it does compare strings code unit - by code unit. - - #### Storage - - String values are stored as pointers in a @ref basic_json type. That is, - for any access to string values, a pointer of type `string_t*` must be - dereferenced. - - @since version 1.0.0 - */ - using string_t = StringType; - - /*! - @brief a type for a boolean - - [RFC 7159](http://rfc7159.net/rfc7159) implicitly describes a boolean as a - type which differentiates the two literals `true` and `false`. - - To store objects in C++, a type is defined by the template parameter @a - BooleanType which chooses the type to use. - - #### Default type - - With the default values for @a BooleanType (`bool`), the default value for - @a boolean_t is: - - @code {.cpp} - bool - @endcode - - #### Storage - - Boolean values are stored directly inside a @ref basic_json type. - - @since version 1.0.0 - */ - using boolean_t = BooleanType; - - /*! - @brief a type for a number (integer) - - [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: - > The representation of numbers is similar to that used in most - > programming languages. A number is represented in base 10 using decimal - > digits. It contains an integer component that may be prefixed with an - > optional minus sign, which may be followed by a fraction part and/or an - > exponent part. Leading zeros are not allowed. (...) Numeric values that - > cannot be represented in the grammar below (such as Infinity and NaN) - > are not permitted. - - This description includes both integer and floating-point numbers. - However, C++ allows more precise storage if it is known whether the number - is a signed integer, an unsigned integer or a floating-point number. - Therefore, three different types, @ref number_integer_t, @ref - number_unsigned_t and @ref number_float_t are used. - - To store integer numbers in C++, a type is defined by the template - parameter @a NumberIntegerType which chooses the type to use. - - #### Default type - - With the default values for @a NumberIntegerType (`int64_t`), the default - value for @a number_integer_t is: - - @code {.cpp} - int64_t - @endcode - - #### Default behavior - - - The restrictions about leading zeros is not enforced in C++. Instead, - leading zeros in integer literals lead to an interpretation as octal - number. Internally, the value will be stored as decimal number. For - instance, the C++ integer literal `010` will be serialized to `8`. - During deserialization, leading zeros yield an error. - - Not-a-number (NaN) values will be serialized to `null`. - - #### Limits - - [RFC 7159](http://rfc7159.net/rfc7159) specifies: - > An implementation may set limits on the range and precision of numbers. - - When the default type is used, the maximal integer number that can be - stored is `9223372036854775807` (INT64_MAX) and the minimal integer number - that can be stored is `-9223372036854775808` (INT64_MIN). Integer numbers - that are out of range will yield over/underflow when used in a - constructor. During deserialization, too large or small integer numbers - will be automatically be stored as @ref number_unsigned_t or @ref - number_float_t. - - [RFC 7159](http://rfc7159.net/rfc7159) further states: - > Note that when such software is used, numbers that are integers and are - > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense - > that implementations will agree exactly on their numeric values. - - As this range is a subrange of the exactly supported range [INT64_MIN, - INT64_MAX], this class's integer type is interoperable. - - #### Storage - - Integer number values are stored directly inside a @ref basic_json type. - - @sa @ref number_float_t -- type for number values (floating-point) - - @sa @ref number_unsigned_t -- type for number values (unsigned integer) - - @since version 1.0.0 - */ - using number_integer_t = NumberIntegerType; - - /*! - @brief a type for a number (unsigned) - - [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: - > The representation of numbers is similar to that used in most - > programming languages. A number is represented in base 10 using decimal - > digits. It contains an integer component that may be prefixed with an - > optional minus sign, which may be followed by a fraction part and/or an - > exponent part. Leading zeros are not allowed. (...) Numeric values that - > cannot be represented in the grammar below (such as Infinity and NaN) - > are not permitted. - - This description includes both integer and floating-point numbers. - However, C++ allows more precise storage if it is known whether the number - is a signed integer, an unsigned integer or a floating-point number. - Therefore, three different types, @ref number_integer_t, @ref - number_unsigned_t and @ref number_float_t are used. - - To store unsigned integer numbers in C++, a type is defined by the - template parameter @a NumberUnsignedType which chooses the type to use. - - #### Default type - - With the default values for @a NumberUnsignedType (`uint64_t`), the - default value for @a number_unsigned_t is: - - @code {.cpp} - uint64_t - @endcode - - #### Default behavior - - - The restrictions about leading zeros is not enforced in C++. Instead, - leading zeros in integer literals lead to an interpretation as octal - number. Internally, the value will be stored as decimal number. For - instance, the C++ integer literal `010` will be serialized to `8`. - During deserialization, leading zeros yield an error. - - Not-a-number (NaN) values will be serialized to `null`. - - #### Limits - - [RFC 7159](http://rfc7159.net/rfc7159) specifies: - > An implementation may set limits on the range and precision of numbers. - - When the default type is used, the maximal integer number that can be - stored is `18446744073709551615` (UINT64_MAX) and the minimal integer - number that can be stored is `0`. Integer numbers that are out of range - will yield over/underflow when used in a constructor. During - deserialization, too large or small integer numbers will be automatically - be stored as @ref number_integer_t or @ref number_float_t. - - [RFC 7159](http://rfc7159.net/rfc7159) further states: - > Note that when such software is used, numbers that are integers and are - > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense - > that implementations will agree exactly on their numeric values. - - As this range is a subrange (when considered in conjunction with the - number_integer_t type) of the exactly supported range [0, UINT64_MAX], - this class's integer type is interoperable. - - #### Storage - - Integer number values are stored directly inside a @ref basic_json type. - - @sa @ref number_float_t -- type for number values (floating-point) - @sa @ref number_integer_t -- type for number values (integer) - - @since version 2.0.0 - */ - using number_unsigned_t = NumberUnsignedType; - - /*! - @brief a type for a number (floating-point) - - [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: - > The representation of numbers is similar to that used in most - > programming languages. A number is represented in base 10 using decimal - > digits. It contains an integer component that may be prefixed with an - > optional minus sign, which may be followed by a fraction part and/or an - > exponent part. Leading zeros are not allowed. (...) Numeric values that - > cannot be represented in the grammar below (such as Infinity and NaN) - > are not permitted. - - This description includes both integer and floating-point numbers. - However, C++ allows more precise storage if it is known whether the number - is a signed integer, an unsigned integer or a floating-point number. - Therefore, three different types, @ref number_integer_t, @ref - number_unsigned_t and @ref number_float_t are used. - - To store floating-point numbers in C++, a type is defined by the template - parameter @a NumberFloatType which chooses the type to use. - - #### Default type - - With the default values for @a NumberFloatType (`double`), the default - value for @a number_float_t is: - - @code {.cpp} - double - @endcode - - #### Default behavior - - - The restrictions about leading zeros is not enforced in C++. Instead, - leading zeros in floating-point literals will be ignored. Internally, - the value will be stored as decimal number. For instance, the C++ - floating-point literal `01.2` will be serialized to `1.2`. During - deserialization, leading zeros yield an error. - - Not-a-number (NaN) values will be serialized to `null`. - - #### Limits - - [RFC 7159](http://rfc7159.net/rfc7159) states: - > This specification allows implementations to set limits on the range and - > precision of numbers accepted. Since software that implements IEEE - > 754-2008 binary64 (double precision) numbers is generally available and - > widely used, good interoperability can be achieved by implementations - > that expect no more precision or range than these provide, in the sense - > that implementations will approximate JSON numbers within the expected - > precision. - - This implementation does exactly follow this approach, as it uses double - precision floating-point numbers. Note values smaller than - `-1.79769313486232e+308` and values greater than `1.79769313486232e+308` - will be stored as NaN internally and be serialized to `null`. - - #### Storage - - Floating-point number values are stored directly inside a @ref basic_json - type. - - @sa @ref number_integer_t -- type for number values (integer) - - @sa @ref number_unsigned_t -- type for number values (unsigned integer) - - @since version 1.0.0 - */ - using number_float_t = NumberFloatType; - - /// @} - - private: - - /// helper for exception-safe object creation - template - static T* create(Args&& ... args) - { - AllocatorType alloc; - using AllocatorTraits = std::allocator_traits>; - - auto deleter = [&](T * object) - { - AllocatorTraits::deallocate(alloc, object, 1); - }; - std::unique_ptr object(AllocatorTraits::allocate(alloc, 1), deleter); - AllocatorTraits::construct(alloc, object.get(), std::forward(args)...); - assert(object != nullptr); - return object.release(); - } - - //////////////////////// - // JSON value storage // - //////////////////////// - - /*! - @brief a JSON value - - The actual storage for a JSON value of the @ref basic_json class. This - union combines the different storage types for the JSON value types - defined in @ref value_t. - - JSON type | value_t type | used type - --------- | --------------- | ------------------------ - object | object | pointer to @ref object_t - array | array | pointer to @ref array_t - string | string | pointer to @ref string_t - boolean | boolean | @ref boolean_t - number | number_integer | @ref number_integer_t - number | number_unsigned | @ref number_unsigned_t - number | number_float | @ref number_float_t - null | null | *no value is stored* - - @note Variable-length types (objects, arrays, and strings) are stored as - pointers. The size of the union should not exceed 64 bits if the default - value types are used. - - @since version 1.0.0 - */ - union json_value - { - /// object (stored with pointer to save storage) - object_t* object; - /// array (stored with pointer to save storage) - array_t* array; - /// string (stored with pointer to save storage) - string_t* string; - /// boolean - boolean_t boolean; - /// number (integer) - number_integer_t number_integer; - /// number (unsigned integer) - number_unsigned_t number_unsigned; - /// number (floating-point) - number_float_t number_float; - - /// default constructor (for null values) - json_value() = default; - /// constructor for booleans - json_value(boolean_t v) noexcept : boolean(v) {} - /// constructor for numbers (integer) - json_value(number_integer_t v) noexcept : number_integer(v) {} - /// constructor for numbers (unsigned) - json_value(number_unsigned_t v) noexcept : number_unsigned(v) {} - /// constructor for numbers (floating-point) - json_value(number_float_t v) noexcept : number_float(v) {} - /// constructor for empty values of a given type - json_value(value_t t) - { - switch (t) - { - case value_t::object: - { - object = create(); - break; - } - - case value_t::array: - { - array = create(); - break; - } - - case value_t::string: - { - string = create(""); - break; - } - - case value_t::boolean: - { - boolean = boolean_t(false); - break; - } - - case value_t::number_integer: - { - number_integer = number_integer_t(0); - break; - } - - case value_t::number_unsigned: - { - number_unsigned = number_unsigned_t(0); - break; - } - - case value_t::number_float: - { - number_float = number_float_t(0.0); - break; - } - - case value_t::null: - { - object = nullptr; // silence warning, see #821 - break; - } - - default: - { - object = nullptr; // silence warning, see #821 - if (JSON_UNLIKELY(t == value_t::null)) - { - JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.0.0")); // LCOV_EXCL_LINE - } - break; - } - } - } - - /// constructor for strings - json_value(const string_t& value) - { - string = create(value); - } - - /// constructor for rvalue strings - json_value(string_t&& value) - { - string = create(std::move(value)); - } - - /// constructor for objects - json_value(const object_t& value) - { - object = create(value); - } - - /// constructor for rvalue objects - json_value(object_t&& value) - { - object = create(std::move(value)); - } - - /// constructor for arrays - json_value(const array_t& value) - { - array = create(value); - } - - /// constructor for rvalue arrays - json_value(array_t&& value) - { - array = create(std::move(value)); - } - - void destroy(value_t t) - { - switch (t) - { - case value_t::object: - { - AllocatorType alloc; - std::allocator_traits::destroy(alloc, object); - std::allocator_traits::deallocate(alloc, object, 1); - break; - } - - case value_t::array: - { - AllocatorType alloc; - std::allocator_traits::destroy(alloc, array); - std::allocator_traits::deallocate(alloc, array, 1); - break; - } - - case value_t::string: - { - AllocatorType alloc; - std::allocator_traits::destroy(alloc, string); - std::allocator_traits::deallocate(alloc, string, 1); - break; - } - - default: - { - break; - } - } - } - }; - - /*! - @brief checks the class invariants - - This function asserts the class invariants. It needs to be called at the - end of every constructor to make sure that created objects respect the - invariant. Furthermore, it has to be called each time the type of a JSON - value is changed, because the invariant expresses a relationship between - @a m_type and @a m_value. - */ - void assert_invariant() const - { - assert(m_type != value_t::object or m_value.object != nullptr); - assert(m_type != value_t::array or m_value.array != nullptr); - assert(m_type != value_t::string or m_value.string != nullptr); - } - - public: - ////////////////////////// - // JSON parser callback // - ////////////////////////// - - /*! - @brief parser event types - - The parser callback distinguishes the following events: - - `object_start`: the parser read `{` and started to process a JSON object - - `key`: the parser read a key of a value in an object - - `object_end`: the parser read `}` and finished processing a JSON object - - `array_start`: the parser read `[` and started to process a JSON array - - `array_end`: the parser read `]` and finished processing a JSON array - - `value`: the parser finished reading a JSON value - - @image html callback_events.png "Example when certain parse events are triggered" - - @sa @ref parser_callback_t for more information and examples - */ - using parse_event_t = typename parser::parse_event_t; - - /*! - @brief per-element parser callback type - - With a parser callback function, the result of parsing a JSON text can be - influenced. When passed to @ref parse, it is called on certain events - (passed as @ref parse_event_t via parameter @a event) with a set recursion - depth @a depth and context JSON value @a parsed. The return value of the - callback function is a boolean indicating whether the element that emitted - the callback shall be kept or not. - - We distinguish six scenarios (determined by the event type) in which the - callback function can be called. The following table describes the values - of the parameters @a depth, @a event, and @a parsed. - - parameter @a event | description | parameter @a depth | parameter @a parsed - ------------------ | ----------- | ------------------ | ------------------- - parse_event_t::object_start | the parser read `{` and started to process a JSON object | depth of the parent of the JSON object | a JSON value with type discarded - parse_event_t::key | the parser read a key of a value in an object | depth of the currently parsed JSON object | a JSON string containing the key - parse_event_t::object_end | the parser read `}` and finished processing a JSON object | depth of the parent of the JSON object | the parsed JSON object - parse_event_t::array_start | the parser read `[` and started to process a JSON array | depth of the parent of the JSON array | a JSON value with type discarded - parse_event_t::array_end | the parser read `]` and finished processing a JSON array | depth of the parent of the JSON array | the parsed JSON array - parse_event_t::value | the parser finished reading a JSON value | depth of the value | the parsed JSON value - - @image html callback_events.png "Example when certain parse events are triggered" - - Discarding a value (i.e., returning `false`) has different effects - depending on the context in which function was called: - - - Discarded values in structured types are skipped. That is, the parser - will behave as if the discarded value was never read. - - In case a value outside a structured type is skipped, it is replaced - with `null`. This case happens if the top-level element is skipped. - - @param[in] depth the depth of the recursion during parsing - - @param[in] event an event of type parse_event_t indicating the context in - the callback function has been called - - @param[in,out] parsed the current intermediate parse result; note that - writing to this value has no effect for parse_event_t::key events - - @return Whether the JSON value which called the function during parsing - should be kept (`true`) or not (`false`). In the latter case, it is either - skipped completely or replaced by an empty discarded object. - - @sa @ref parse for examples - - @since version 1.0.0 - */ - using parser_callback_t = typename parser::parser_callback_t; - - ////////////////// - // constructors // - ////////////////// - - /// @name constructors and destructors - /// Constructors of class @ref basic_json, copy/move constructor, copy - /// assignment, static functions creating objects, and the destructor. - /// @{ - - /*! - @brief create an empty value with a given type - - Create an empty JSON value with a given type. The value will be default - initialized with an empty value which depends on the type: - - Value type | initial value - ----------- | ------------- - null | `null` - boolean | `false` - string | `""` - number | `0` - object | `{}` - array | `[]` - - @param[in] v the type of the value to create - - @complexity Constant. - - @exceptionsafety Strong guarantee: if an exception is thrown, there are no - changes to any JSON value. - - @liveexample{The following code shows the constructor for different @ref - value_t values,basic_json__value_t} - - @sa @ref clear() -- restores the postcondition of this constructor - - @since version 1.0.0 - */ - basic_json(const value_t v) - : m_type(v), m_value(v) - { - assert_invariant(); - } - - /*! - @brief create a null object - - Create a `null` JSON value. It either takes a null pointer as parameter - (explicitly creating `null`) or no parameter (implicitly creating `null`). - The passed null pointer itself is not read -- it is only used to choose - the right constructor. - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this constructor never throws - exceptions. - - @liveexample{The following code shows the constructor with and without a - null pointer parameter.,basic_json__nullptr_t} - - @since version 1.0.0 - */ - basic_json(std::nullptr_t = nullptr) noexcept - : basic_json(value_t::null) - { - assert_invariant(); - } - - /*! - @brief create a JSON value - - This is a "catch all" constructor for all compatible JSON types; that is, - types for which a `to_json()` method exists. The constructor forwards the - parameter @a val to that method (to `json_serializer::to_json` method - with `U = uncvref_t`, to be exact). - - Template type @a CompatibleType includes, but is not limited to, the - following types: - - **arrays**: @ref array_t and all kinds of compatible containers such as - `std::vector`, `std::deque`, `std::list`, `std::forward_list`, - `std::array`, `std::valarray`, `std::set`, `std::unordered_set`, - `std::multiset`, and `std::unordered_multiset` with a `value_type` from - which a @ref basic_json value can be constructed. - - **objects**: @ref object_t and all kinds of compatible associative - containers such as `std::map`, `std::unordered_map`, `std::multimap`, - and `std::unordered_multimap` with a `key_type` compatible to - @ref string_t and a `value_type` from which a @ref basic_json value can - be constructed. - - **strings**: @ref string_t, string literals, and all compatible string - containers can be used. - - **numbers**: @ref number_integer_t, @ref number_unsigned_t, - @ref number_float_t, and all convertible number types such as `int`, - `size_t`, `int64_t`, `float` or `double` can be used. - - **boolean**: @ref boolean_t / `bool` can be used. - - See the examples below. - - @tparam CompatibleType a type such that: - - @a CompatibleType is not derived from `std::istream`, - - @a CompatibleType is not @ref basic_json (to avoid hijacking copy/move - constructors), - - @a CompatibleType is not a @ref basic_json nested type (e.g., - @ref json_pointer, @ref iterator, etc ...) - - @ref @ref json_serializer has a - `to_json(basic_json_t&, CompatibleType&&)` method - - @tparam U = `uncvref_t` - - @param[in] val the value to be forwarded to the respective constructor - - @complexity Usually linear in the size of the passed @a val, also - depending on the implementation of the called `to_json()` - method. - - @exceptionsafety Depends on the called constructor. For types directly - supported by the library (i.e., all types for which no `to_json()` function - was provided), strong guarantee holds: if an exception is thrown, there are - no changes to any JSON value. - - @liveexample{The following code shows the constructor with several - compatible types.,basic_json__CompatibleType} - - @since version 2.1.0 - */ - template, - detail::enable_if_t::value and - not std::is_same::value and - not detail::is_basic_json_nested_type< - basic_json_t, U>::value and - detail::has_to_json::value, - int> = 0> - basic_json(CompatibleType && val) noexcept(noexcept(JSONSerializer::to_json( - std::declval(), std::forward(val)))) - { - JSONSerializer::to_json(*this, std::forward(val)); - assert_invariant(); - } - - /*! - @brief create a container (array or object) from an initializer list - - Creates a JSON value of type array or object from the passed initializer - list @a init. In case @a type_deduction is `true` (default), the type of - the JSON value to be created is deducted from the initializer list @a init - according to the following rules: - - 1. If the list is empty, an empty JSON object value `{}` is created. - 2. If the list consists of pairs whose first element is a string, a JSON - object value is created where the first elements of the pairs are - treated as keys and the second elements are as values. - 3. In all other cases, an array is created. - - The rules aim to create the best fit between a C++ initializer list and - JSON values. The rationale is as follows: - - 1. The empty initializer list is written as `{}` which is exactly an empty - JSON object. - 2. C++ has no way of describing mapped types other than to list a list of - pairs. As JSON requires that keys must be of type string, rule 2 is the - weakest constraint one can pose on initializer lists to interpret them - as an object. - 3. In all other cases, the initializer list could not be interpreted as - JSON object type, so interpreting it as JSON array type is safe. - - With the rules described above, the following JSON values cannot be - expressed by an initializer list: - - - the empty array (`[]`): use @ref array(initializer_list_t) - with an empty initializer list in this case - - arrays whose elements satisfy rule 2: use @ref - array(initializer_list_t) with the same initializer list - in this case - - @note When used without parentheses around an empty initializer list, @ref - basic_json() is called instead of this function, yielding the JSON null - value. - - @param[in] init initializer list with JSON values - - @param[in] type_deduction internal parameter; when set to `true`, the type - of the JSON value is deducted from the initializer list @a init; when set - to `false`, the type provided via @a manual_type is forced. This mode is - used by the functions @ref array(initializer_list_t) and - @ref object(initializer_list_t). - - @param[in] manual_type internal parameter; when @a type_deduction is set - to `false`, the created JSON value will use the provided type (only @ref - value_t::array and @ref value_t::object are valid); when @a type_deduction - is set to `true`, this parameter has no effect - - @throw type_error.301 if @a type_deduction is `false`, @a manual_type is - `value_t::object`, but @a init contains an element which is not a pair - whose first element is a string. In this case, the constructor could not - create an object. If @a type_deduction would have be `true`, an array - would have been created. See @ref object(initializer_list_t) - for an example. - - @complexity Linear in the size of the initializer list @a init. - - @exceptionsafety Strong guarantee: if an exception is thrown, there are no - changes to any JSON value. - - @liveexample{The example below shows how JSON values are created from - initializer lists.,basic_json__list_init_t} - - @sa @ref array(initializer_list_t) -- create a JSON array - value from an initializer list - @sa @ref object(initializer_list_t) -- create a JSON object - value from an initializer list - - @since version 1.0.0 - */ - basic_json(initializer_list_t init, - bool type_deduction = true, - value_t manual_type = value_t::array) - { - // check if each element is an array with two elements whose first - // element is a string - bool is_an_object = std::all_of(init.begin(), init.end(), - [](const detail::json_ref& element_ref) - { - return (element_ref->is_array() and element_ref->size() == 2 and (*element_ref)[0].is_string()); - }); - - // adjust type if type deduction is not wanted - if (not type_deduction) - { - // if array is wanted, do not create an object though possible - if (manual_type == value_t::array) - { - is_an_object = false; - } - - // if object is wanted but impossible, throw an exception - if (JSON_UNLIKELY(manual_type == value_t::object and not is_an_object)) - { - JSON_THROW(type_error::create(301, "cannot create object from initializer list")); - } - } - - if (is_an_object) - { - // the initializer list is a list of pairs -> create object - m_type = value_t::object; - m_value = value_t::object; - - std::for_each(init.begin(), init.end(), [this](const detail::json_ref& element_ref) - { - auto element = element_ref.moved_or_copied(); - m_value.object->emplace( - std::move(*((*element.m_value.array)[0].m_value.string)), - std::move((*element.m_value.array)[1])); - }); - } - else - { - // the initializer list describes an array -> create array - m_type = value_t::array; - m_value.array = create(init.begin(), init.end()); - } - - assert_invariant(); - } - - /*! - @brief explicitly create an array from an initializer list - - Creates a JSON array value from a given initializer list. That is, given a - list of values `a, b, c`, creates the JSON value `[a, b, c]`. If the - initializer list is empty, the empty array `[]` is created. - - @note This function is only needed to express two edge cases that cannot - be realized with the initializer list constructor (@ref - basic_json(initializer_list_t, bool, value_t)). These cases - are: - 1. creating an array whose elements are all pairs whose first element is a - string -- in this case, the initializer list constructor would create an - object, taking the first elements as keys - 2. creating an empty array -- passing the empty initializer list to the - initializer list constructor yields an empty object - - @param[in] init initializer list with JSON values to create an array from - (optional) - - @return JSON array value - - @complexity Linear in the size of @a init. - - @exceptionsafety Strong guarantee: if an exception is thrown, there are no - changes to any JSON value. - - @liveexample{The following code shows an example for the `array` - function.,array} - - @sa @ref basic_json(initializer_list_t, bool, value_t) -- - create a JSON value from an initializer list - @sa @ref object(initializer_list_t) -- create a JSON object - value from an initializer list - - @since version 1.0.0 - */ - static basic_json array(initializer_list_t init = {}) - { - return basic_json(init, false, value_t::array); - } - - /*! - @brief explicitly create an object from an initializer list - - Creates a JSON object value from a given initializer list. The initializer - lists elements must be pairs, and their first elements must be strings. If - the initializer list is empty, the empty object `{}` is created. - - @note This function is only added for symmetry reasons. In contrast to the - related function @ref array(initializer_list_t), there are - no cases which can only be expressed by this function. That is, any - initializer list @a init can also be passed to the initializer list - constructor @ref basic_json(initializer_list_t, bool, value_t). - - @param[in] init initializer list to create an object from (optional) - - @return JSON object value - - @throw type_error.301 if @a init is not a list of pairs whose first - elements are strings. In this case, no object can be created. When such a - value is passed to @ref basic_json(initializer_list_t, bool, value_t), - an array would have been created from the passed initializer list @a init. - See example below. - - @complexity Linear in the size of @a init. - - @exceptionsafety Strong guarantee: if an exception is thrown, there are no - changes to any JSON value. - - @liveexample{The following code shows an example for the `object` - function.,object} - - @sa @ref basic_json(initializer_list_t, bool, value_t) -- - create a JSON value from an initializer list - @sa @ref array(initializer_list_t) -- create a JSON array - value from an initializer list - - @since version 1.0.0 - */ - static basic_json object(initializer_list_t init = {}) - { - return basic_json(init, false, value_t::object); - } - - /*! - @brief construct an array with count copies of given value - - Constructs a JSON array value by creating @a cnt copies of a passed value. - In case @a cnt is `0`, an empty array is created. - - @param[in] cnt the number of JSON copies of @a val to create - @param[in] val the JSON value to copy - - @post `std::distance(begin(),end()) == cnt` holds. - - @complexity Linear in @a cnt. - - @exceptionsafety Strong guarantee: if an exception is thrown, there are no - changes to any JSON value. - - @liveexample{The following code shows examples for the @ref - basic_json(size_type\, const basic_json&) - constructor.,basic_json__size_type_basic_json} - - @since version 1.0.0 - */ - basic_json(size_type cnt, const basic_json& val) - : m_type(value_t::array) - { - m_value.array = create(cnt, val); - assert_invariant(); - } - - /*! - @brief construct a JSON container given an iterator range - - Constructs the JSON value with the contents of the range `[first, last)`. - The semantics depends on the different types a JSON value can have: - - In case of a null type, invalid_iterator.206 is thrown. - - In case of other primitive types (number, boolean, or string), @a first - must be `begin()` and @a last must be `end()`. In this case, the value is - copied. Otherwise, invalid_iterator.204 is thrown. - - In case of structured types (array, object), the constructor behaves as - similar versions for `std::vector` or `std::map`; that is, a JSON array - or object is constructed from the values in the range. - - @tparam InputIT an input iterator type (@ref iterator or @ref - const_iterator) - - @param[in] first begin of the range to copy from (included) - @param[in] last end of the range to copy from (excluded) - - @pre Iterators @a first and @a last must be initialized. **This - precondition is enforced with an assertion (see warning).** If - assertions are switched off, a violation of this precondition yields - undefined behavior. - - @pre Range `[first, last)` is valid. Usually, this precondition cannot be - checked efficiently. Only certain edge cases are detected; see the - description of the exceptions below. A violation of this precondition - yields undefined behavior. - - @warning A precondition is enforced with a runtime assertion that will - result in calling `std::abort` if this precondition is not met. - Assertions can be disabled by defining `NDEBUG` at compile time. - See http://en.cppreference.com/w/cpp/error/assert for more - information. - - @throw invalid_iterator.201 if iterators @a first and @a last are not - compatible (i.e., do not belong to the same JSON value). In this case, - the range `[first, last)` is undefined. - @throw invalid_iterator.204 if iterators @a first and @a last belong to a - primitive type (number, boolean, or string), but @a first does not point - to the first element any more. In this case, the range `[first, last)` is - undefined. See example code below. - @throw invalid_iterator.206 if iterators @a first and @a last belong to a - null value. In this case, the range `[first, last)` is undefined. - - @complexity Linear in distance between @a first and @a last. - - @exceptionsafety Strong guarantee: if an exception is thrown, there are no - changes to any JSON value. - - @liveexample{The example below shows several ways to create JSON values by - specifying a subrange with iterators.,basic_json__InputIt_InputIt} - - @since version 1.0.0 - */ - template::value or - std::is_same::value, int>::type = 0> - basic_json(InputIT first, InputIT last) - { - assert(first.m_object != nullptr); - assert(last.m_object != nullptr); - - // make sure iterator fits the current value - if (JSON_UNLIKELY(first.m_object != last.m_object)) - { - JSON_THROW(invalid_iterator::create(201, "iterators are not compatible")); - } - - // copy type from first iterator - m_type = first.m_object->m_type; - - // check if iterator range is complete for primitive values - switch (m_type) - { - case value_t::boolean: - case value_t::number_float: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::string: - { - if (JSON_UNLIKELY(not first.m_it.primitive_iterator.is_begin() - or not last.m_it.primitive_iterator.is_end())) - { - JSON_THROW(invalid_iterator::create(204, "iterators out of range")); - } - break; - } - - default: - break; - } - - switch (m_type) - { - case value_t::number_integer: - { - m_value.number_integer = first.m_object->m_value.number_integer; - break; - } - - case value_t::number_unsigned: - { - m_value.number_unsigned = first.m_object->m_value.number_unsigned; - break; - } - - case value_t::number_float: - { - m_value.number_float = first.m_object->m_value.number_float; - break; - } - - case value_t::boolean: - { - m_value.boolean = first.m_object->m_value.boolean; - break; - } - - case value_t::string: - { - m_value = *first.m_object->m_value.string; - break; - } - - case value_t::object: - { - m_value.object = create(first.m_it.object_iterator, - last.m_it.object_iterator); - break; - } - - case value_t::array: - { - m_value.array = create(first.m_it.array_iterator, - last.m_it.array_iterator); - break; - } - - default: - JSON_THROW(invalid_iterator::create(206, "cannot construct with iterators from " + - std::string(first.m_object->type_name()))); - } - - assert_invariant(); - } - - /////////////////////////////////////// - // other constructors and destructor // - /////////////////////////////////////// - - /// @private - basic_json(const detail::json_ref& ref) - : basic_json(ref.moved_or_copied()) - {} - - /*! - @brief copy constructor - - Creates a copy of a given JSON value. - - @param[in] other the JSON value to copy - - @post `*this == other` - - @complexity Linear in the size of @a other. - - @exceptionsafety Strong guarantee: if an exception is thrown, there are no - changes to any JSON value. - - @requirement This function helps `basic_json` satisfying the - [Container](http://en.cppreference.com/w/cpp/concept/Container) - requirements: - - The complexity is linear. - - As postcondition, it holds: `other == basic_json(other)`. - - @liveexample{The following code shows an example for the copy - constructor.,basic_json__basic_json} - - @since version 1.0.0 - */ - basic_json(const basic_json& other) - : m_type(other.m_type) - { - // check of passed value is valid - other.assert_invariant(); - - switch (m_type) - { - case value_t::object: - { - m_value = *other.m_value.object; - break; - } - - case value_t::array: - { - m_value = *other.m_value.array; - break; - } - - case value_t::string: - { - m_value = *other.m_value.string; - break; - } - - case value_t::boolean: - { - m_value = other.m_value.boolean; - break; - } - - case value_t::number_integer: - { - m_value = other.m_value.number_integer; - break; - } - - case value_t::number_unsigned: - { - m_value = other.m_value.number_unsigned; - break; - } - - case value_t::number_float: - { - m_value = other.m_value.number_float; - break; - } - - default: - break; - } - - assert_invariant(); - } - - /*! - @brief move constructor - - Move constructor. Constructs a JSON value with the contents of the given - value @a other using move semantics. It "steals" the resources from @a - other and leaves it as JSON null value. - - @param[in,out] other value to move to this object - - @post `*this` has the same value as @a other before the call. - @post @a other is a JSON null value. - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this constructor never throws - exceptions. - - @requirement This function helps `basic_json` satisfying the - [MoveConstructible](http://en.cppreference.com/w/cpp/concept/MoveConstructible) - requirements. - - @liveexample{The code below shows the move constructor explicitly called - via std::move.,basic_json__moveconstructor} - - @since version 1.0.0 - */ - basic_json(basic_json&& other) noexcept - : m_type(std::move(other.m_type)), - m_value(std::move(other.m_value)) - { - // check that passed value is valid - other.assert_invariant(); - - // invalidate payload - other.m_type = value_t::null; - other.m_value = {}; - - assert_invariant(); - } - - /*! - @brief copy assignment - - Copy assignment operator. Copies a JSON value via the "copy and swap" - strategy: It is expressed in terms of the copy constructor, destructor, - and the `swap()` member function. - - @param[in] other value to copy from - - @complexity Linear. - - @requirement This function helps `basic_json` satisfying the - [Container](http://en.cppreference.com/w/cpp/concept/Container) - requirements: - - The complexity is linear. - - @liveexample{The code below shows and example for the copy assignment. It - creates a copy of value `a` which is then swapped with `b`. Finally\, the - copy of `a` (which is the null value after the swap) is - destroyed.,basic_json__copyassignment} - - @since version 1.0.0 - */ - reference& operator=(basic_json other) noexcept ( - std::is_nothrow_move_constructible::value and - std::is_nothrow_move_assignable::value and - std::is_nothrow_move_constructible::value and - std::is_nothrow_move_assignable::value - ) - { - // check that passed value is valid - other.assert_invariant(); - - using std::swap; - swap(m_type, other.m_type); - swap(m_value, other.m_value); - - assert_invariant(); - return *this; - } - - /*! - @brief destructor - - Destroys the JSON value and frees all allocated memory. - - @complexity Linear. - - @requirement This function helps `basic_json` satisfying the - [Container](http://en.cppreference.com/w/cpp/concept/Container) - requirements: - - The complexity is linear. - - All stored elements are destroyed and all memory is freed. - - @since version 1.0.0 - */ - ~basic_json() - { - assert_invariant(); - m_value.destroy(m_type); - } - - /// @} - - public: - /////////////////////// - // object inspection // - /////////////////////// - - /// @name object inspection - /// Functions to inspect the type of a JSON value. - /// @{ - - /*! - @brief serialization - - Serialization function for JSON values. The function tries to mimic - Python's `json.dumps()` function, and currently supports its @a indent - and @a ensure_ascii parameters. - - @param[in] indent If indent is nonnegative, then array elements and object - members will be pretty-printed with that indent level. An indent level of - `0` will only insert newlines. `-1` (the default) selects the most compact - representation. - @param[in] indent_char The character to use for indentation if @a indent is - greater than `0`. The default is ` ` (space). - @param[in] ensure_ascii If @a ensure_ascii is true, all non-ASCII characters - in the output are escaped with `\uXXXX` sequences, and the result consists - of ASCII characters only. - - @return string containing the serialization of the JSON value - - @throw type_error.316 if a string stored inside the JSON value is not - UTF-8 encoded - - @complexity Linear. - - @exceptionsafety Strong guarantee: if an exception is thrown, there are no - changes in the JSON value. - - @liveexample{The following example shows the effect of different @a indent\, - @a indent_char\, and @a ensure_ascii parameters to the result of the - serialization.,dump} - - @see https://docs.python.org/2/library/json.html#json.dump - - @since version 1.0.0; indentation character @a indent_char, option - @a ensure_ascii and exceptions added in version 3.0.0 - */ - string_t dump(const int indent = -1, const char indent_char = ' ', - const bool ensure_ascii = false) const - { - string_t result; - serializer s(detail::output_adapter(result), indent_char); - - if (indent >= 0) - { - s.dump(*this, true, ensure_ascii, static_cast(indent)); - } - else - { - s.dump(*this, false, ensure_ascii, 0); - } - - return result; - } - - /*! - @brief return the type of the JSON value (explicit) - - Return the type of the JSON value as a value from the @ref value_t - enumeration. - - @return the type of the JSON value - Value type | return value - ------------------------- | ------------------------- - null | value_t::null - boolean | value_t::boolean - string | value_t::string - number (integer) | value_t::number_integer - number (unsigned integer) | value_t::number_unsigned - number (floating-point) | value_t::number_float - object | value_t::object - array | value_t::array - discarded | value_t::discarded - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @liveexample{The following code exemplifies `type()` for all JSON - types.,type} - - @sa @ref operator value_t() -- return the type of the JSON value (implicit) - @sa @ref type_name() -- return the type as string - - @since version 1.0.0 - */ - constexpr value_t type() const noexcept - { - return m_type; - } - - /*! - @brief return whether type is primitive - - This function returns true if and only if the JSON type is primitive - (string, number, boolean, or null). - - @return `true` if type is primitive (string, number, boolean, or null), - `false` otherwise. - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @liveexample{The following code exemplifies `is_primitive()` for all JSON - types.,is_primitive} - - @sa @ref is_structured() -- returns whether JSON value is structured - @sa @ref is_null() -- returns whether JSON value is `null` - @sa @ref is_string() -- returns whether JSON value is a string - @sa @ref is_boolean() -- returns whether JSON value is a boolean - @sa @ref is_number() -- returns whether JSON value is a number - - @since version 1.0.0 - */ - constexpr bool is_primitive() const noexcept - { - return is_null() or is_string() or is_boolean() or is_number(); - } - - /*! - @brief return whether type is structured - - This function returns true if and only if the JSON type is structured - (array or object). - - @return `true` if type is structured (array or object), `false` otherwise. - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @liveexample{The following code exemplifies `is_structured()` for all JSON - types.,is_structured} - - @sa @ref is_primitive() -- returns whether value is primitive - @sa @ref is_array() -- returns whether value is an array - @sa @ref is_object() -- returns whether value is an object - - @since version 1.0.0 - */ - constexpr bool is_structured() const noexcept - { - return is_array() or is_object(); - } - - /*! - @brief return whether value is null - - This function returns true if and only if the JSON value is null. - - @return `true` if type is null, `false` otherwise. - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @liveexample{The following code exemplifies `is_null()` for all JSON - types.,is_null} - - @since version 1.0.0 - */ - constexpr bool is_null() const noexcept - { - return (m_type == value_t::null); - } - - /*! - @brief return whether value is a boolean - - This function returns true if and only if the JSON value is a boolean. - - @return `true` if type is boolean, `false` otherwise. - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @liveexample{The following code exemplifies `is_boolean()` for all JSON - types.,is_boolean} - - @since version 1.0.0 - */ - constexpr bool is_boolean() const noexcept - { - return (m_type == value_t::boolean); - } - - /*! - @brief return whether value is a number - - This function returns true if and only if the JSON value is a number. This - includes both integer (signed and unsigned) and floating-point values. - - @return `true` if type is number (regardless whether integer, unsigned - integer or floating-type), `false` otherwise. - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @liveexample{The following code exemplifies `is_number()` for all JSON - types.,is_number} - - @sa @ref is_number_integer() -- check if value is an integer or unsigned - integer number - @sa @ref is_number_unsigned() -- check if value is an unsigned integer - number - @sa @ref is_number_float() -- check if value is a floating-point number - - @since version 1.0.0 - */ - constexpr bool is_number() const noexcept - { - return is_number_integer() or is_number_float(); - } - - /*! - @brief return whether value is an integer number - - This function returns true if and only if the JSON value is a signed or - unsigned integer number. This excludes floating-point values. - - @return `true` if type is an integer or unsigned integer number, `false` - otherwise. - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @liveexample{The following code exemplifies `is_number_integer()` for all - JSON types.,is_number_integer} - - @sa @ref is_number() -- check if value is a number - @sa @ref is_number_unsigned() -- check if value is an unsigned integer - number - @sa @ref is_number_float() -- check if value is a floating-point number - - @since version 1.0.0 - */ - constexpr bool is_number_integer() const noexcept - { - return (m_type == value_t::number_integer or m_type == value_t::number_unsigned); - } - - /*! - @brief return whether value is an unsigned integer number - - This function returns true if and only if the JSON value is an unsigned - integer number. This excludes floating-point and signed integer values. - - @return `true` if type is an unsigned integer number, `false` otherwise. - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @liveexample{The following code exemplifies `is_number_unsigned()` for all - JSON types.,is_number_unsigned} - - @sa @ref is_number() -- check if value is a number - @sa @ref is_number_integer() -- check if value is an integer or unsigned - integer number - @sa @ref is_number_float() -- check if value is a floating-point number - - @since version 2.0.0 - */ - constexpr bool is_number_unsigned() const noexcept - { - return (m_type == value_t::number_unsigned); - } - - /*! - @brief return whether value is a floating-point number - - This function returns true if and only if the JSON value is a - floating-point number. This excludes signed and unsigned integer values. - - @return `true` if type is a floating-point number, `false` otherwise. - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @liveexample{The following code exemplifies `is_number_float()` for all - JSON types.,is_number_float} - - @sa @ref is_number() -- check if value is number - @sa @ref is_number_integer() -- check if value is an integer number - @sa @ref is_number_unsigned() -- check if value is an unsigned integer - number - - @since version 1.0.0 - */ - constexpr bool is_number_float() const noexcept - { - return (m_type == value_t::number_float); - } - - /*! - @brief return whether value is an object - - This function returns true if and only if the JSON value is an object. - - @return `true` if type is object, `false` otherwise. - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @liveexample{The following code exemplifies `is_object()` for all JSON - types.,is_object} - - @since version 1.0.0 - */ - constexpr bool is_object() const noexcept - { - return (m_type == value_t::object); - } - - /*! - @brief return whether value is an array - - This function returns true if and only if the JSON value is an array. - - @return `true` if type is array, `false` otherwise. - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @liveexample{The following code exemplifies `is_array()` for all JSON - types.,is_array} - - @since version 1.0.0 - */ - constexpr bool is_array() const noexcept - { - return (m_type == value_t::array); - } - - /*! - @brief return whether value is a string - - This function returns true if and only if the JSON value is a string. - - @return `true` if type is string, `false` otherwise. - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @liveexample{The following code exemplifies `is_string()` for all JSON - types.,is_string} - - @since version 1.0.0 - */ - constexpr bool is_string() const noexcept - { - return (m_type == value_t::string); - } - - /*! - @brief return whether value is discarded - - This function returns true if and only if the JSON value was discarded - during parsing with a callback function (see @ref parser_callback_t). - - @note This function will always be `false` for JSON values after parsing. - That is, discarded values can only occur during parsing, but will be - removed when inside a structured value or replaced by null in other cases. - - @return `true` if type is discarded, `false` otherwise. - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @liveexample{The following code exemplifies `is_discarded()` for all JSON - types.,is_discarded} - - @since version 1.0.0 - */ - constexpr bool is_discarded() const noexcept - { - return (m_type == value_t::discarded); - } - - /*! - @brief return the type of the JSON value (implicit) - - Implicitly return the type of the JSON value as a value from the @ref - value_t enumeration. - - @return the type of the JSON value - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @liveexample{The following code exemplifies the @ref value_t operator for - all JSON types.,operator__value_t} - - @sa @ref type() -- return the type of the JSON value (explicit) - @sa @ref type_name() -- return the type as string - - @since version 1.0.0 - */ - constexpr operator value_t() const noexcept - { - return m_type; - } - - /// @} - - private: - ////////////////// - // value access // - ////////////////// - - /// get a boolean (explicit) - boolean_t get_impl(boolean_t* /*unused*/) const - { - if (JSON_LIKELY(is_boolean())) - { - return m_value.boolean; - } - - JSON_THROW(type_error::create(302, "type must be boolean, but is " + std::string(type_name()))); - } - - /// get a pointer to the value (object) - object_t* get_impl_ptr(object_t* /*unused*/) noexcept - { - return is_object() ? m_value.object : nullptr; - } - - /// get a pointer to the value (object) - constexpr const object_t* get_impl_ptr(const object_t* /*unused*/) const noexcept - { - return is_object() ? m_value.object : nullptr; - } - - /// get a pointer to the value (array) - array_t* get_impl_ptr(array_t* /*unused*/) noexcept - { - return is_array() ? m_value.array : nullptr; - } - - /// get a pointer to the value (array) - constexpr const array_t* get_impl_ptr(const array_t* /*unused*/) const noexcept - { - return is_array() ? m_value.array : nullptr; - } - - /// get a pointer to the value (string) - string_t* get_impl_ptr(string_t* /*unused*/) noexcept - { - return is_string() ? m_value.string : nullptr; - } - - /// get a pointer to the value (string) - constexpr const string_t* get_impl_ptr(const string_t* /*unused*/) const noexcept - { - return is_string() ? m_value.string : nullptr; - } - - /// get a pointer to the value (boolean) - boolean_t* get_impl_ptr(boolean_t* /*unused*/) noexcept - { - return is_boolean() ? &m_value.boolean : nullptr; - } - - /// get a pointer to the value (boolean) - constexpr const boolean_t* get_impl_ptr(const boolean_t* /*unused*/) const noexcept - { - return is_boolean() ? &m_value.boolean : nullptr; - } - - /// get a pointer to the value (integer number) - number_integer_t* get_impl_ptr(number_integer_t* /*unused*/) noexcept - { - return is_number_integer() ? &m_value.number_integer : nullptr; - } - - /// get a pointer to the value (integer number) - constexpr const number_integer_t* get_impl_ptr(const number_integer_t* /*unused*/) const noexcept - { - return is_number_integer() ? &m_value.number_integer : nullptr; - } - - /// get a pointer to the value (unsigned number) - number_unsigned_t* get_impl_ptr(number_unsigned_t* /*unused*/) noexcept - { - return is_number_unsigned() ? &m_value.number_unsigned : nullptr; - } - - /// get a pointer to the value (unsigned number) - constexpr const number_unsigned_t* get_impl_ptr(const number_unsigned_t* /*unused*/) const noexcept - { - return is_number_unsigned() ? &m_value.number_unsigned : nullptr; - } - - /// get a pointer to the value (floating-point number) - number_float_t* get_impl_ptr(number_float_t* /*unused*/) noexcept - { - return is_number_float() ? &m_value.number_float : nullptr; - } - - /// get a pointer to the value (floating-point number) - constexpr const number_float_t* get_impl_ptr(const number_float_t* /*unused*/) const noexcept - { - return is_number_float() ? &m_value.number_float : nullptr; - } - - /*! - @brief helper function to implement get_ref() - - This function helps to implement get_ref() without code duplication for - const and non-const overloads - - @tparam ThisType will be deduced as `basic_json` or `const basic_json` - - @throw type_error.303 if ReferenceType does not match underlying value - type of the current JSON - */ - template - static ReferenceType get_ref_impl(ThisType& obj) - { - // delegate the call to get_ptr<>() - auto ptr = obj.template get_ptr::type>(); - - if (JSON_LIKELY(ptr != nullptr)) - { - return *ptr; - } - - JSON_THROW(type_error::create(303, "incompatible ReferenceType for get_ref, actual type is " + std::string(obj.type_name()))); - } - - public: - /// @name value access - /// Direct access to the stored value of a JSON value. - /// @{ - - /*! - @brief get special-case overload - - This overloads avoids a lot of template boilerplate, it can be seen as the - identity method - - @tparam BasicJsonType == @ref basic_json - - @return a copy of *this - - @complexity Constant. - - @since version 2.1.0 - */ - template::type, basic_json_t>::value, - int> = 0> - basic_json get() const - { - return *this; - } - - /*! - @brief get a value (explicit) - - Explicit type conversion between the JSON value and a compatible value - which is [CopyConstructible](http://en.cppreference.com/w/cpp/concept/CopyConstructible) - and [DefaultConstructible](http://en.cppreference.com/w/cpp/concept/DefaultConstructible). - The value is converted by calling the @ref json_serializer - `from_json()` method. - - The function is equivalent to executing - @code {.cpp} - ValueType ret; - JSONSerializer::from_json(*this, ret); - return ret; - @endcode - - This overloads is chosen if: - - @a ValueType is not @ref basic_json, - - @ref json_serializer has a `from_json()` method of the form - `void from_json(const basic_json&, ValueType&)`, and - - @ref json_serializer does not have a `from_json()` method of - the form `ValueType from_json(const basic_json&)` - - @tparam ValueTypeCV the provided value type - @tparam ValueType the returned value type - - @return copy of the JSON value, converted to @a ValueType - - @throw what @ref json_serializer `from_json()` method throws - - @liveexample{The example below shows several conversions from JSON values - to other types. There a few things to note: (1) Floating-point numbers can - be converted to integers\, (2) A JSON array can be converted to a standard - `std::vector`\, (3) A JSON object can be converted to C++ - associative containers such as `std::unordered_map`.,get__ValueType_const} - - @since version 2.1.0 - */ - template, - detail::enable_if_t < - not std::is_same::value and - detail::has_from_json::value and - not detail::has_non_default_from_json::value, - int> = 0> - ValueType get() const noexcept(noexcept( - JSONSerializer::from_json(std::declval(), std::declval()))) - { - // we cannot static_assert on ValueTypeCV being non-const, because - // there is support for get(), which is why we - // still need the uncvref - static_assert(not std::is_reference::value, - "get() cannot be used with reference types, you might want to use get_ref()"); - static_assert(std::is_default_constructible::value, - "types must be DefaultConstructible when used with get()"); - - ValueType ret; - JSONSerializer::from_json(*this, ret); - return ret; - } - - /*! - @brief get a value (explicit); special case - - Explicit type conversion between the JSON value and a compatible value - which is **not** [CopyConstructible](http://en.cppreference.com/w/cpp/concept/CopyConstructible) - and **not** [DefaultConstructible](http://en.cppreference.com/w/cpp/concept/DefaultConstructible). - The value is converted by calling the @ref json_serializer - `from_json()` method. - - The function is equivalent to executing - @code {.cpp} - return JSONSerializer::from_json(*this); - @endcode - - This overloads is chosen if: - - @a ValueType is not @ref basic_json and - - @ref json_serializer has a `from_json()` method of the form - `ValueType from_json(const basic_json&)` - - @note If @ref json_serializer has both overloads of - `from_json()`, this one is chosen. - - @tparam ValueTypeCV the provided value type - @tparam ValueType the returned value type - - @return copy of the JSON value, converted to @a ValueType - - @throw what @ref json_serializer `from_json()` method throws - - @since version 2.1.0 - */ - template, - detail::enable_if_t::value and - detail::has_non_default_from_json::value, - int> = 0> - ValueType get() const noexcept(noexcept( - JSONSerializer::from_json(std::declval()))) - { - static_assert(not std::is_reference::value, - "get() cannot be used with reference types, you might want to use get_ref()"); - return JSONSerializer::from_json(*this); - } - - /*! - @brief get a pointer value (explicit) - - Explicit pointer access to the internally stored JSON value. No copies are - made. - - @warning The pointer becomes invalid if the underlying JSON object - changes. - - @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref - object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, - @ref number_unsigned_t, or @ref number_float_t. - - @return pointer to the internally stored JSON value if the requested - pointer type @a PointerType fits to the JSON value; `nullptr` otherwise - - @complexity Constant. - - @liveexample{The example below shows how pointers to internal values of a - JSON value can be requested. Note that no type conversions are made and a - `nullptr` is returned if the value and the requested pointer type does not - match.,get__PointerType} - - @sa @ref get_ptr() for explicit pointer-member access - - @since version 1.0.0 - */ - template::value, int>::type = 0> - PointerType get() noexcept - { - // delegate the call to get_ptr - return get_ptr(); - } - - /*! - @brief get a pointer value (explicit) - @copydoc get() - */ - template::value, int>::type = 0> - constexpr const PointerType get() const noexcept - { - // delegate the call to get_ptr - return get_ptr(); - } - - /*! - @brief get a pointer value (implicit) - - Implicit pointer access to the internally stored JSON value. No copies are - made. - - @warning Writing data to the pointee of the result yields an undefined - state. - - @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref - object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, - @ref number_unsigned_t, or @ref number_float_t. Enforced by a static - assertion. - - @return pointer to the internally stored JSON value if the requested - pointer type @a PointerType fits to the JSON value; `nullptr` otherwise - - @complexity Constant. - - @liveexample{The example below shows how pointers to internal values of a - JSON value can be requested. Note that no type conversions are made and a - `nullptr` is returned if the value and the requested pointer type does not - match.,get_ptr} - - @since version 1.0.0 - */ - template::value, int>::type = 0> - PointerType get_ptr() noexcept - { - // get the type of the PointerType (remove pointer and const) - using pointee_t = typename std::remove_const::type>::type>::type; - // make sure the type matches the allowed types - static_assert( - std::is_same::value - or std::is_same::value - or std::is_same::value - or std::is_same::value - or std::is_same::value - or std::is_same::value - or std::is_same::value - , "incompatible pointer type"); - - // delegate the call to get_impl_ptr<>() - return get_impl_ptr(static_cast(nullptr)); - } - - /*! - @brief get a pointer value (implicit) - @copydoc get_ptr() - */ - template::value and - std::is_const::type>::value, int>::type = 0> - constexpr const PointerType get_ptr() const noexcept - { - // get the type of the PointerType (remove pointer and const) - using pointee_t = typename std::remove_const::type>::type>::type; - // make sure the type matches the allowed types - static_assert( - std::is_same::value - or std::is_same::value - or std::is_same::value - or std::is_same::value - or std::is_same::value - or std::is_same::value - or std::is_same::value - , "incompatible pointer type"); - - // delegate the call to get_impl_ptr<>() const - return get_impl_ptr(static_cast(nullptr)); - } - - /*! - @brief get a reference value (implicit) - - Implicit reference access to the internally stored JSON value. No copies - are made. - - @warning Writing data to the referee of the result yields an undefined - state. - - @tparam ReferenceType reference type; must be a reference to @ref array_t, - @ref object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, or - @ref number_float_t. Enforced by static assertion. - - @return reference to the internally stored JSON value if the requested - reference type @a ReferenceType fits to the JSON value; throws - type_error.303 otherwise - - @throw type_error.303 in case passed type @a ReferenceType is incompatible - with the stored JSON value; see example below - - @complexity Constant. - - @liveexample{The example shows several calls to `get_ref()`.,get_ref} - - @since version 1.1.0 - */ - template::value, int>::type = 0> - ReferenceType get_ref() - { - // delegate call to get_ref_impl - return get_ref_impl(*this); - } - - /*! - @brief get a reference value (implicit) - @copydoc get_ref() - */ - template::value and - std::is_const::type>::value, int>::type = 0> - ReferenceType get_ref() const - { - // delegate call to get_ref_impl - return get_ref_impl(*this); - } - - /*! - @brief get a value (implicit) - - Implicit type conversion between the JSON value and a compatible value. - The call is realized by calling @ref get() const. - - @tparam ValueType non-pointer type compatible to the JSON value, for - instance `int` for JSON integer numbers, `bool` for JSON booleans, or - `std::vector` types for JSON arrays. The character type of @ref string_t - as well as an initializer list of this type is excluded to avoid - ambiguities as these types implicitly convert to `std::string`. - - @return copy of the JSON value, converted to type @a ValueType - - @throw type_error.302 in case passed type @a ValueType is incompatible - to the JSON value type (e.g., the JSON value is of type boolean, but a - string is requested); see example below - - @complexity Linear in the size of the JSON value. - - @liveexample{The example below shows several conversions from JSON values - to other types. There a few things to note: (1) Floating-point numbers can - be converted to integers\, (2) A JSON array can be converted to a standard - `std::vector`\, (3) A JSON object can be converted to C++ - associative containers such as `std::unordered_map`.,operator__ValueType} - - @since version 1.0.0 - */ - template < typename ValueType, typename std::enable_if < - not std::is_pointer::value and - not std::is_same>::value and - not std::is_same::value -#ifndef _MSC_VER // fix for issue #167 operator<< ambiguity under VS2015 - and not std::is_same>::value -#endif -#if defined(JSON_HAS_CPP_17) - and not std::is_same::value -#endif - , int >::type = 0 > - operator ValueType() const - { - // delegate the call to get<>() const - return get(); - } - - /// @} - - //////////////////// - // element access // - //////////////////// - - /// @name element access - /// Access to the JSON value. - /// @{ - - /*! - @brief access specified array element with bounds checking - - Returns a reference to the element at specified location @a idx, with - bounds checking. - - @param[in] idx index of the element to access - - @return reference to the element at index @a idx - - @throw type_error.304 if the JSON value is not an array; in this case, - calling `at` with an index makes no sense. See example below. - @throw out_of_range.401 if the index @a idx is out of range of the array; - that is, `idx >= size()`. See example below. - - @exceptionsafety Strong guarantee: if an exception is thrown, there are no - changes in the JSON value. - - @complexity Constant. - - @since version 1.0.0 - - @liveexample{The example below shows how array elements can be read and - written using `at()`. It also demonstrates the different exceptions that - can be thrown.,at__size_type} - */ - reference at(size_type idx) - { - // at only works for arrays - if (JSON_LIKELY(is_array())) - { - JSON_TRY - { - return m_value.array->at(idx); - } - JSON_CATCH (std::out_of_range&) - { - // create better exception explanation - JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range")); - } - } - else - { - JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name()))); - } - } - - /*! - @brief access specified array element with bounds checking - - Returns a const reference to the element at specified location @a idx, - with bounds checking. - - @param[in] idx index of the element to access - - @return const reference to the element at index @a idx - - @throw type_error.304 if the JSON value is not an array; in this case, - calling `at` with an index makes no sense. See example below. - @throw out_of_range.401 if the index @a idx is out of range of the array; - that is, `idx >= size()`. See example below. - - @exceptionsafety Strong guarantee: if an exception is thrown, there are no - changes in the JSON value. - - @complexity Constant. - - @since version 1.0.0 - - @liveexample{The example below shows how array elements can be read using - `at()`. It also demonstrates the different exceptions that can be thrown., - at__size_type_const} - */ - const_reference at(size_type idx) const - { - // at only works for arrays - if (JSON_LIKELY(is_array())) - { - JSON_TRY - { - return m_value.array->at(idx); - } - JSON_CATCH (std::out_of_range&) - { - // create better exception explanation - JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range")); - } - } - else - { - JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name()))); - } - } - - /*! - @brief access specified object element with bounds checking - - Returns a reference to the element at with specified key @a key, with - bounds checking. - - @param[in] key key of the element to access - - @return reference to the element at key @a key - - @throw type_error.304 if the JSON value is not an object; in this case, - calling `at` with a key makes no sense. See example below. - @throw out_of_range.403 if the key @a key is is not stored in the object; - that is, `find(key) == end()`. See example below. - - @exceptionsafety Strong guarantee: if an exception is thrown, there are no - changes in the JSON value. - - @complexity Logarithmic in the size of the container. - - @sa @ref operator[](const typename object_t::key_type&) for unchecked - access by reference - @sa @ref value() for access by value with a default value - - @since version 1.0.0 - - @liveexample{The example below shows how object elements can be read and - written using `at()`. It also demonstrates the different exceptions that - can be thrown.,at__object_t_key_type} - */ - reference at(const typename object_t::key_type& key) - { - // at only works for objects - if (JSON_LIKELY(is_object())) - { - JSON_TRY - { - return m_value.object->at(key); - } - JSON_CATCH (std::out_of_range&) - { - // create better exception explanation - JSON_THROW(out_of_range::create(403, "key '" + key + "' not found")); - } - } - else - { - JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name()))); - } - } - - /*! - @brief access specified object element with bounds checking - - Returns a const reference to the element at with specified key @a key, - with bounds checking. - - @param[in] key key of the element to access - - @return const reference to the element at key @a key - - @throw type_error.304 if the JSON value is not an object; in this case, - calling `at` with a key makes no sense. See example below. - @throw out_of_range.403 if the key @a key is is not stored in the object; - that is, `find(key) == end()`. See example below. - - @exceptionsafety Strong guarantee: if an exception is thrown, there are no - changes in the JSON value. - - @complexity Logarithmic in the size of the container. - - @sa @ref operator[](const typename object_t::key_type&) for unchecked - access by reference - @sa @ref value() for access by value with a default value - - @since version 1.0.0 - - @liveexample{The example below shows how object elements can be read using - `at()`. It also demonstrates the different exceptions that can be thrown., - at__object_t_key_type_const} - */ - const_reference at(const typename object_t::key_type& key) const - { - // at only works for objects - if (JSON_LIKELY(is_object())) - { - JSON_TRY - { - return m_value.object->at(key); - } - JSON_CATCH (std::out_of_range&) - { - // create better exception explanation - JSON_THROW(out_of_range::create(403, "key '" + key + "' not found")); - } - } - else - { - JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name()))); - } - } - - /*! - @brief access specified array element - - Returns a reference to the element at specified location @a idx. - - @note If @a idx is beyond the range of the array (i.e., `idx >= size()`), - then the array is silently filled up with `null` values to make `idx` a - valid reference to the last stored element. - - @param[in] idx index of the element to access - - @return reference to the element at index @a idx - - @throw type_error.305 if the JSON value is not an array or null; in that - cases, using the [] operator with an index makes no sense. - - @complexity Constant if @a idx is in the range of the array. Otherwise - linear in `idx - size()`. - - @liveexample{The example below shows how array elements can be read and - written using `[]` operator. Note the addition of `null` - values.,operatorarray__size_type} - - @since version 1.0.0 - */ - reference operator[](size_type idx) - { - // implicitly convert null value to an empty array - if (is_null()) - { - m_type = value_t::array; - m_value.array = create(); - assert_invariant(); - } - - // operator[] only works for arrays - if (JSON_LIKELY(is_array())) - { - // fill up array with null values if given idx is outside range - if (idx >= m_value.array->size()) - { - m_value.array->insert(m_value.array->end(), - idx - m_value.array->size() + 1, - basic_json()); - } - - return m_value.array->operator[](idx); - } - - JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); - } - - /*! - @brief access specified array element - - Returns a const reference to the element at specified location @a idx. - - @param[in] idx index of the element to access - - @return const reference to the element at index @a idx - - @throw type_error.305 if the JSON value is not an array; in that case, - using the [] operator with an index makes no sense. - - @complexity Constant. - - @liveexample{The example below shows how array elements can be read using - the `[]` operator.,operatorarray__size_type_const} - - @since version 1.0.0 - */ - const_reference operator[](size_type idx) const - { - // const operator[] only works for arrays - if (JSON_LIKELY(is_array())) - { - return m_value.array->operator[](idx); - } - - JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); - } - - /*! - @brief access specified object element - - Returns a reference to the element at with specified key @a key. - - @note If @a key is not found in the object, then it is silently added to - the object and filled with a `null` value to make `key` a valid reference. - In case the value was `null` before, it is converted to an object. - - @param[in] key key of the element to access - - @return reference to the element at key @a key - - @throw type_error.305 if the JSON value is not an object or null; in that - cases, using the [] operator with a key makes no sense. - - @complexity Logarithmic in the size of the container. - - @liveexample{The example below shows how object elements can be read and - written using the `[]` operator.,operatorarray__key_type} - - @sa @ref at(const typename object_t::key_type&) for access by reference - with range checking - @sa @ref value() for access by value with a default value - - @since version 1.0.0 - */ - reference operator[](const typename object_t::key_type& key) - { - // implicitly convert null value to an empty object - if (is_null()) - { - m_type = value_t::object; - m_value.object = create(); - assert_invariant(); - } - - // operator[] only works for objects - if (JSON_LIKELY(is_object())) - { - return m_value.object->operator[](key); - } - - JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); - } - - /*! - @brief read-only access specified object element - - Returns a const reference to the element at with specified key @a key. No - bounds checking is performed. - - @warning If the element with key @a key does not exist, the behavior is - undefined. - - @param[in] key key of the element to access - - @return const reference to the element at key @a key - - @pre The element with key @a key must exist. **This precondition is - enforced with an assertion.** - - @throw type_error.305 if the JSON value is not an object; in that case, - using the [] operator with a key makes no sense. - - @complexity Logarithmic in the size of the container. - - @liveexample{The example below shows how object elements can be read using - the `[]` operator.,operatorarray__key_type_const} - - @sa @ref at(const typename object_t::key_type&) for access by reference - with range checking - @sa @ref value() for access by value with a default value - - @since version 1.0.0 - */ - const_reference operator[](const typename object_t::key_type& key) const - { - // const operator[] only works for objects - if (JSON_LIKELY(is_object())) - { - assert(m_value.object->find(key) != m_value.object->end()); - return m_value.object->find(key)->second; - } - - JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); - } - - /*! - @brief access specified object element - - Returns a reference to the element at with specified key @a key. - - @note If @a key is not found in the object, then it is silently added to - the object and filled with a `null` value to make `key` a valid reference. - In case the value was `null` before, it is converted to an object. - - @param[in] key key of the element to access - - @return reference to the element at key @a key - - @throw type_error.305 if the JSON value is not an object or null; in that - cases, using the [] operator with a key makes no sense. - - @complexity Logarithmic in the size of the container. - - @liveexample{The example below shows how object elements can be read and - written using the `[]` operator.,operatorarray__key_type} - - @sa @ref at(const typename object_t::key_type&) for access by reference - with range checking - @sa @ref value() for access by value with a default value - - @since version 1.1.0 - */ - template - reference operator[](T* key) - { - // implicitly convert null to object - if (is_null()) - { - m_type = value_t::object; - m_value = value_t::object; - assert_invariant(); - } - - // at only works for objects - if (JSON_LIKELY(is_object())) - { - return m_value.object->operator[](key); - } - - JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); - } - - /*! - @brief read-only access specified object element - - Returns a const reference to the element at with specified key @a key. No - bounds checking is performed. - - @warning If the element with key @a key does not exist, the behavior is - undefined. - - @param[in] key key of the element to access - - @return const reference to the element at key @a key - - @pre The element with key @a key must exist. **This precondition is - enforced with an assertion.** - - @throw type_error.305 if the JSON value is not an object; in that case, - using the [] operator with a key makes no sense. - - @complexity Logarithmic in the size of the container. - - @liveexample{The example below shows how object elements can be read using - the `[]` operator.,operatorarray__key_type_const} - - @sa @ref at(const typename object_t::key_type&) for access by reference - with range checking - @sa @ref value() for access by value with a default value - - @since version 1.1.0 - */ - template - const_reference operator[](T* key) const - { - // at only works for objects - if (JSON_LIKELY(is_object())) - { - assert(m_value.object->find(key) != m_value.object->end()); - return m_value.object->find(key)->second; - } - - JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); - } - - /*! - @brief access specified object element with default value - - Returns either a copy of an object's element at the specified key @a key - or a given default value if no element with key @a key exists. - - The function is basically equivalent to executing - @code {.cpp} - try { - return at(key); - } catch(out_of_range) { - return default_value; - } - @endcode - - @note Unlike @ref at(const typename object_t::key_type&), this function - does not throw if the given key @a key was not found. - - @note Unlike @ref operator[](const typename object_t::key_type& key), this - function does not implicitly add an element to the position defined by @a - key. This function is furthermore also applicable to const objects. - - @param[in] key key of the element to access - @param[in] default_value the value to return if @a key is not found - - @tparam ValueType type compatible to JSON values, for instance `int` for - JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for - JSON arrays. Note the type of the expected value at @a key and the default - value @a default_value must be compatible. - - @return copy of the element at key @a key or @a default_value if @a key - is not found - - @throw type_error.306 if the JSON value is not an object; in that case, - using `value()` with a key makes no sense. - - @complexity Logarithmic in the size of the container. - - @liveexample{The example below shows how object elements can be queried - with a default value.,basic_json__value} - - @sa @ref at(const typename object_t::key_type&) for access by reference - with range checking - @sa @ref operator[](const typename object_t::key_type&) for unchecked - access by reference - - @since version 1.0.0 - */ - template::value, int>::type = 0> - ValueType value(const typename object_t::key_type& key, const ValueType& default_value) const - { - // at only works for objects - if (JSON_LIKELY(is_object())) - { - // if key is found, return value and given default value otherwise - const auto it = find(key); - if (it != end()) - { - return *it; - } - - return default_value; - } - - JSON_THROW(type_error::create(306, "cannot use value() with " + std::string(type_name()))); - } - - /*! - @brief overload for a default value of type const char* - @copydoc basic_json::value(const typename object_t::key_type&, ValueType) const - */ - string_t value(const typename object_t::key_type& key, const char* default_value) const - { - return value(key, string_t(default_value)); - } - - /*! - @brief access specified object element via JSON Pointer with default value - - Returns either a copy of an object's element at the specified key @a key - or a given default value if no element with key @a key exists. - - The function is basically equivalent to executing - @code {.cpp} - try { - return at(ptr); - } catch(out_of_range) { - return default_value; - } - @endcode - - @note Unlike @ref at(const json_pointer&), this function does not throw - if the given key @a key was not found. - - @param[in] ptr a JSON pointer to the element to access - @param[in] default_value the value to return if @a ptr found no value - - @tparam ValueType type compatible to JSON values, for instance `int` for - JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for - JSON arrays. Note the type of the expected value at @a key and the default - value @a default_value must be compatible. - - @return copy of the element at key @a key or @a default_value if @a key - is not found - - @throw type_error.306 if the JSON value is not an objec; in that case, - using `value()` with a key makes no sense. - - @complexity Logarithmic in the size of the container. - - @liveexample{The example below shows how object elements can be queried - with a default value.,basic_json__value_ptr} - - @sa @ref operator[](const json_pointer&) for unchecked access by reference - - @since version 2.0.2 - */ - template::value, int>::type = 0> - ValueType value(const json_pointer& ptr, const ValueType& default_value) const - { - // at only works for objects - if (JSON_LIKELY(is_object())) - { - // if pointer resolves a value, return it or use default value - JSON_TRY - { - return ptr.get_checked(this); - } - JSON_CATCH (out_of_range&) - { - return default_value; - } - } - - JSON_THROW(type_error::create(306, "cannot use value() with " + std::string(type_name()))); - } - - /*! - @brief overload for a default value of type const char* - @copydoc basic_json::value(const json_pointer&, ValueType) const - */ - string_t value(const json_pointer& ptr, const char* default_value) const - { - return value(ptr, string_t(default_value)); - } - - /*! - @brief access the first element - - Returns a reference to the first element in the container. For a JSON - container `c`, the expression `c.front()` is equivalent to `*c.begin()`. - - @return In case of a structured type (array or object), a reference to the - first element is returned. In case of number, string, or boolean values, a - reference to the value is returned. - - @complexity Constant. - - @pre The JSON value must not be `null` (would throw `std::out_of_range`) - or an empty array or object (undefined behavior, **guarded by - assertions**). - @post The JSON value remains unchanged. - - @throw invalid_iterator.214 when called on `null` value - - @liveexample{The following code shows an example for `front()`.,front} - - @sa @ref back() -- access the last element - - @since version 1.0.0 - */ - reference front() - { - return *begin(); - } - - /*! - @copydoc basic_json::front() - */ - const_reference front() const - { - return *cbegin(); - } - - /*! - @brief access the last element - - Returns a reference to the last element in the container. For a JSON - container `c`, the expression `c.back()` is equivalent to - @code {.cpp} - auto tmp = c.end(); - --tmp; - return *tmp; - @endcode - - @return In case of a structured type (array or object), a reference to the - last element is returned. In case of number, string, or boolean values, a - reference to the value is returned. - - @complexity Constant. - - @pre The JSON value must not be `null` (would throw `std::out_of_range`) - or an empty array or object (undefined behavior, **guarded by - assertions**). - @post The JSON value remains unchanged. - - @throw invalid_iterator.214 when called on a `null` value. See example - below. - - @liveexample{The following code shows an example for `back()`.,back} - - @sa @ref front() -- access the first element - - @since version 1.0.0 - */ - reference back() - { - auto tmp = end(); - --tmp; - return *tmp; - } - - /*! - @copydoc basic_json::back() - */ - const_reference back() const - { - auto tmp = cend(); - --tmp; - return *tmp; - } - - /*! - @brief remove element given an iterator - - Removes the element specified by iterator @a pos. The iterator @a pos must - be valid and dereferenceable. Thus the `end()` iterator (which is valid, - but is not dereferenceable) cannot be used as a value for @a pos. - - If called on a primitive type other than `null`, the resulting JSON value - will be `null`. - - @param[in] pos iterator to the element to remove - @return Iterator following the last removed element. If the iterator @a - pos refers to the last element, the `end()` iterator is returned. - - @tparam IteratorType an @ref iterator or @ref const_iterator - - @post Invalidates iterators and references at or after the point of the - erase, including the `end()` iterator. - - @throw type_error.307 if called on a `null` value; example: `"cannot use - erase() with null"` - @throw invalid_iterator.202 if called on an iterator which does not belong - to the current JSON value; example: `"iterator does not fit current - value"` - @throw invalid_iterator.205 if called on a primitive type with invalid - iterator (i.e., any iterator which is not `begin()`); example: `"iterator - out of range"` - - @complexity The complexity depends on the type: - - objects: amortized constant - - arrays: linear in distance between @a pos and the end of the container - - strings: linear in the length of the string - - other types: constant - - @liveexample{The example shows the result of `erase()` for different JSON - types.,erase__IteratorType} - - @sa @ref erase(IteratorType, IteratorType) -- removes the elements in - the given range - @sa @ref erase(const typename object_t::key_type&) -- removes the element - from an object at the given key - @sa @ref erase(const size_type) -- removes the element from an array at - the given index - - @since version 1.0.0 - */ - template::value or - std::is_same::value, int>::type - = 0> - IteratorType erase(IteratorType pos) - { - // make sure iterator fits the current value - if (JSON_UNLIKELY(this != pos.m_object)) - { - JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value")); - } - - IteratorType result = end(); - - switch (m_type) - { - case value_t::boolean: - case value_t::number_float: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::string: - { - if (JSON_UNLIKELY(not pos.m_it.primitive_iterator.is_begin())) - { - JSON_THROW(invalid_iterator::create(205, "iterator out of range")); - } - - if (is_string()) - { - AllocatorType alloc; - std::allocator_traits::destroy(alloc, m_value.string); - std::allocator_traits::deallocate(alloc, m_value.string, 1); - m_value.string = nullptr; - } - - m_type = value_t::null; - assert_invariant(); - break; - } - - case value_t::object: - { - result.m_it.object_iterator = m_value.object->erase(pos.m_it.object_iterator); - break; - } - - case value_t::array: - { - result.m_it.array_iterator = m_value.array->erase(pos.m_it.array_iterator); - break; - } - - default: - JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name()))); - } - - return result; - } - - /*! - @brief remove elements given an iterator range - - Removes the element specified by the range `[first; last)`. The iterator - @a first does not need to be dereferenceable if `first == last`: erasing - an empty range is a no-op. - - If called on a primitive type other than `null`, the resulting JSON value - will be `null`. - - @param[in] first iterator to the beginning of the range to remove - @param[in] last iterator past the end of the range to remove - @return Iterator following the last removed element. If the iterator @a - second refers to the last element, the `end()` iterator is returned. - - @tparam IteratorType an @ref iterator or @ref const_iterator - - @post Invalidates iterators and references at or after the point of the - erase, including the `end()` iterator. - - @throw type_error.307 if called on a `null` value; example: `"cannot use - erase() with null"` - @throw invalid_iterator.203 if called on iterators which does not belong - to the current JSON value; example: `"iterators do not fit current value"` - @throw invalid_iterator.204 if called on a primitive type with invalid - iterators (i.e., if `first != begin()` and `last != end()`); example: - `"iterators out of range"` - - @complexity The complexity depends on the type: - - objects: `log(size()) + std::distance(first, last)` - - arrays: linear in the distance between @a first and @a last, plus linear - in the distance between @a last and end of the container - - strings: linear in the length of the string - - other types: constant - - @liveexample{The example shows the result of `erase()` for different JSON - types.,erase__IteratorType_IteratorType} - - @sa @ref erase(IteratorType) -- removes the element at a given position - @sa @ref erase(const typename object_t::key_type&) -- removes the element - from an object at the given key - @sa @ref erase(const size_type) -- removes the element from an array at - the given index - - @since version 1.0.0 - */ - template::value or - std::is_same::value, int>::type - = 0> - IteratorType erase(IteratorType first, IteratorType last) - { - // make sure iterator fits the current value - if (JSON_UNLIKELY(this != first.m_object or this != last.m_object)) - { - JSON_THROW(invalid_iterator::create(203, "iterators do not fit current value")); - } - - IteratorType result = end(); - - switch (m_type) - { - case value_t::boolean: - case value_t::number_float: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::string: - { - if (JSON_LIKELY(not first.m_it.primitive_iterator.is_begin() - or not last.m_it.primitive_iterator.is_end())) - { - JSON_THROW(invalid_iterator::create(204, "iterators out of range")); - } - - if (is_string()) - { - AllocatorType alloc; - std::allocator_traits::destroy(alloc, m_value.string); - std::allocator_traits::deallocate(alloc, m_value.string, 1); - m_value.string = nullptr; - } - - m_type = value_t::null; - assert_invariant(); - break; - } - - case value_t::object: - { - result.m_it.object_iterator = m_value.object->erase(first.m_it.object_iterator, - last.m_it.object_iterator); - break; - } - - case value_t::array: - { - result.m_it.array_iterator = m_value.array->erase(first.m_it.array_iterator, - last.m_it.array_iterator); - break; - } - - default: - JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name()))); - } - - return result; - } - - /*! - @brief remove element from a JSON object given a key - - Removes elements from a JSON object with the key value @a key. - - @param[in] key value of the elements to remove - - @return Number of elements removed. If @a ObjectType is the default - `std::map` type, the return value will always be `0` (@a key was not - found) or `1` (@a key was found). - - @post References and iterators to the erased elements are invalidated. - Other references and iterators are not affected. - - @throw type_error.307 when called on a type other than JSON object; - example: `"cannot use erase() with null"` - - @complexity `log(size()) + count(key)` - - @liveexample{The example shows the effect of `erase()`.,erase__key_type} - - @sa @ref erase(IteratorType) -- removes the element at a given position - @sa @ref erase(IteratorType, IteratorType) -- removes the elements in - the given range - @sa @ref erase(const size_type) -- removes the element from an array at - the given index - - @since version 1.0.0 - */ - size_type erase(const typename object_t::key_type& key) - { - // this erase only works for objects - if (JSON_LIKELY(is_object())) - { - return m_value.object->erase(key); - } - - JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name()))); - } - - /*! - @brief remove element from a JSON array given an index - - Removes element from a JSON array at the index @a idx. - - @param[in] idx index of the element to remove - - @throw type_error.307 when called on a type other than JSON object; - example: `"cannot use erase() with null"` - @throw out_of_range.401 when `idx >= size()`; example: `"array index 17 - is out of range"` - - @complexity Linear in distance between @a idx and the end of the container. - - @liveexample{The example shows the effect of `erase()`.,erase__size_type} - - @sa @ref erase(IteratorType) -- removes the element at a given position - @sa @ref erase(IteratorType, IteratorType) -- removes the elements in - the given range - @sa @ref erase(const typename object_t::key_type&) -- removes the element - from an object at the given key - - @since version 1.0.0 - */ - void erase(const size_type idx) - { - // this erase only works for arrays - if (JSON_LIKELY(is_array())) - { - if (JSON_UNLIKELY(idx >= size())) - { - JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range")); - } - - m_value.array->erase(m_value.array->begin() + static_cast(idx)); - } - else - { - JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name()))); - } - } - - /// @} - - //////////// - // lookup // - //////////// - - /// @name lookup - /// @{ - - /*! - @brief find an element in a JSON object - - Finds an element in a JSON object with key equivalent to @a key. If the - element is not found or the JSON value is not an object, end() is - returned. - - @note This method always returns @ref end() when executed on a JSON type - that is not an object. - - @param[in] key key value of the element to search for. - - @return Iterator to an element with key equivalent to @a key. If no such - element is found or the JSON value is not an object, past-the-end (see - @ref end()) iterator is returned. - - @complexity Logarithmic in the size of the JSON object. - - @liveexample{The example shows how `find()` is used.,find__key_type} - - @since version 1.0.0 - */ - template - iterator find(KeyT&& key) - { - auto result = end(); - - if (is_object()) - { - result.m_it.object_iterator = m_value.object->find(std::forward(key)); - } - - return result; - } - - /*! - @brief find an element in a JSON object - @copydoc find(KeyT&&) - */ - template - const_iterator find(KeyT&& key) const - { - auto result = cend(); - - if (is_object()) - { - result.m_it.object_iterator = m_value.object->find(std::forward(key)); - } - - return result; - } - - /*! - @brief returns the number of occurrences of a key in a JSON object - - Returns the number of elements with key @a key. If ObjectType is the - default `std::map` type, the return value will always be `0` (@a key was - not found) or `1` (@a key was found). - - @note This method always returns `0` when executed on a JSON type that is - not an object. - - @param[in] key key value of the element to count - - @return Number of elements with key @a key. If the JSON value is not an - object, the return value will be `0`. - - @complexity Logarithmic in the size of the JSON object. - - @liveexample{The example shows how `count()` is used.,count} - - @since version 1.0.0 - */ - template - size_type count(KeyT&& key) const - { - // return 0 for all nonobject types - return is_object() ? m_value.object->count(std::forward(key)) : 0; - } - - /// @} - - /////////////// - // iterators // - /////////////// - - /// @name iterators - /// @{ - - /*! - @brief returns an iterator to the first element - - Returns an iterator to the first element. - - @image html range-begin-end.svg "Illustration from cppreference.com" - - @return iterator to the first element - - @complexity Constant. - - @requirement This function helps `basic_json` satisfying the - [Container](http://en.cppreference.com/w/cpp/concept/Container) - requirements: - - The complexity is constant. - - @liveexample{The following code shows an example for `begin()`.,begin} - - @sa @ref cbegin() -- returns a const iterator to the beginning - @sa @ref end() -- returns an iterator to the end - @sa @ref cend() -- returns a const iterator to the end - - @since version 1.0.0 - */ - iterator begin() noexcept - { - iterator result(this); - result.set_begin(); - return result; - } - - /*! - @copydoc basic_json::cbegin() - */ - const_iterator begin() const noexcept - { - return cbegin(); - } - - /*! - @brief returns a const iterator to the first element - - Returns a const iterator to the first element. - - @image html range-begin-end.svg "Illustration from cppreference.com" - - @return const iterator to the first element - - @complexity Constant. - - @requirement This function helps `basic_json` satisfying the - [Container](http://en.cppreference.com/w/cpp/concept/Container) - requirements: - - The complexity is constant. - - Has the semantics of `const_cast(*this).begin()`. - - @liveexample{The following code shows an example for `cbegin()`.,cbegin} - - @sa @ref begin() -- returns an iterator to the beginning - @sa @ref end() -- returns an iterator to the end - @sa @ref cend() -- returns a const iterator to the end - - @since version 1.0.0 - */ - const_iterator cbegin() const noexcept - { - const_iterator result(this); - result.set_begin(); - return result; - } - - /*! - @brief returns an iterator to one past the last element - - Returns an iterator to one past the last element. - - @image html range-begin-end.svg "Illustration from cppreference.com" - - @return iterator one past the last element - - @complexity Constant. - - @requirement This function helps `basic_json` satisfying the - [Container](http://en.cppreference.com/w/cpp/concept/Container) - requirements: - - The complexity is constant. - - @liveexample{The following code shows an example for `end()`.,end} - - @sa @ref cend() -- returns a const iterator to the end - @sa @ref begin() -- returns an iterator to the beginning - @sa @ref cbegin() -- returns a const iterator to the beginning - - @since version 1.0.0 - */ - iterator end() noexcept - { - iterator result(this); - result.set_end(); - return result; - } - - /*! - @copydoc basic_json::cend() - */ - const_iterator end() const noexcept - { - return cend(); - } - - /*! - @brief returns a const iterator to one past the last element - - Returns a const iterator to one past the last element. - - @image html range-begin-end.svg "Illustration from cppreference.com" - - @return const iterator one past the last element - - @complexity Constant. - - @requirement This function helps `basic_json` satisfying the - [Container](http://en.cppreference.com/w/cpp/concept/Container) - requirements: - - The complexity is constant. - - Has the semantics of `const_cast(*this).end()`. - - @liveexample{The following code shows an example for `cend()`.,cend} - - @sa @ref end() -- returns an iterator to the end - @sa @ref begin() -- returns an iterator to the beginning - @sa @ref cbegin() -- returns a const iterator to the beginning - - @since version 1.0.0 - */ - const_iterator cend() const noexcept - { - const_iterator result(this); - result.set_end(); - return result; - } - - /*! - @brief returns an iterator to the reverse-beginning - - Returns an iterator to the reverse-beginning; that is, the last element. - - @image html range-rbegin-rend.svg "Illustration from cppreference.com" - - @complexity Constant. - - @requirement This function helps `basic_json` satisfying the - [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) - requirements: - - The complexity is constant. - - Has the semantics of `reverse_iterator(end())`. - - @liveexample{The following code shows an example for `rbegin()`.,rbegin} - - @sa @ref crbegin() -- returns a const reverse iterator to the beginning - @sa @ref rend() -- returns a reverse iterator to the end - @sa @ref crend() -- returns a const reverse iterator to the end - - @since version 1.0.0 - */ - reverse_iterator rbegin() noexcept - { - return reverse_iterator(end()); - } - - /*! - @copydoc basic_json::crbegin() - */ - const_reverse_iterator rbegin() const noexcept - { - return crbegin(); - } - - /*! - @brief returns an iterator to the reverse-end - - Returns an iterator to the reverse-end; that is, one before the first - element. - - @image html range-rbegin-rend.svg "Illustration from cppreference.com" - - @complexity Constant. - - @requirement This function helps `basic_json` satisfying the - [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) - requirements: - - The complexity is constant. - - Has the semantics of `reverse_iterator(begin())`. - - @liveexample{The following code shows an example for `rend()`.,rend} - - @sa @ref crend() -- returns a const reverse iterator to the end - @sa @ref rbegin() -- returns a reverse iterator to the beginning - @sa @ref crbegin() -- returns a const reverse iterator to the beginning - - @since version 1.0.0 - */ - reverse_iterator rend() noexcept - { - return reverse_iterator(begin()); - } - - /*! - @copydoc basic_json::crend() - */ - const_reverse_iterator rend() const noexcept - { - return crend(); - } - - /*! - @brief returns a const reverse iterator to the last element - - Returns a const iterator to the reverse-beginning; that is, the last - element. - - @image html range-rbegin-rend.svg "Illustration from cppreference.com" - - @complexity Constant. - - @requirement This function helps `basic_json` satisfying the - [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) - requirements: - - The complexity is constant. - - Has the semantics of `const_cast(*this).rbegin()`. - - @liveexample{The following code shows an example for `crbegin()`.,crbegin} - - @sa @ref rbegin() -- returns a reverse iterator to the beginning - @sa @ref rend() -- returns a reverse iterator to the end - @sa @ref crend() -- returns a const reverse iterator to the end - - @since version 1.0.0 - */ - const_reverse_iterator crbegin() const noexcept - { - return const_reverse_iterator(cend()); - } - - /*! - @brief returns a const reverse iterator to one before the first - - Returns a const reverse iterator to the reverse-end; that is, one before - the first element. - - @image html range-rbegin-rend.svg "Illustration from cppreference.com" - - @complexity Constant. - - @requirement This function helps `basic_json` satisfying the - [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) - requirements: - - The complexity is constant. - - Has the semantics of `const_cast(*this).rend()`. - - @liveexample{The following code shows an example for `crend()`.,crend} - - @sa @ref rend() -- returns a reverse iterator to the end - @sa @ref rbegin() -- returns a reverse iterator to the beginning - @sa @ref crbegin() -- returns a const reverse iterator to the beginning - - @since version 1.0.0 - */ - const_reverse_iterator crend() const noexcept - { - return const_reverse_iterator(cbegin()); - } - - public: - /*! - @brief wrapper to access iterator member functions in range-based for - - This function allows to access @ref iterator::key() and @ref - iterator::value() during range-based for loops. In these loops, a - reference to the JSON values is returned, so there is no access to the - underlying iterator. - - For loop without iterator_wrapper: - - @code{cpp} - for (auto it = j_object.begin(); it != j_object.end(); ++it) - { - std::cout << "key: " << it.key() << ", value:" << it.value() << '\n'; - } - @endcode - - Range-based for loop without iterator proxy: - - @code{cpp} - for (auto it : j_object) - { - // "it" is of type json::reference and has no key() member - std::cout << "value: " << it << '\n'; - } - @endcode - - Range-based for loop with iterator proxy: - - @code{cpp} - for (auto it : json::iterator_wrapper(j_object)) - { - std::cout << "key: " << it.key() << ", value:" << it.value() << '\n'; - } - @endcode - - @note When iterating over an array, `key()` will return the index of the - element as string (see example). - - @param[in] ref reference to a JSON value - @return iteration proxy object wrapping @a ref with an interface to use in - range-based for loops - - @liveexample{The following code shows how the wrapper is used,iterator_wrapper} - - @exceptionsafety Strong guarantee: if an exception is thrown, there are no - changes in the JSON value. - - @complexity Constant. - - @note The name of this function is not yet final and may change in the - future. - */ - static iteration_proxy iterator_wrapper(reference ref) - { - return iteration_proxy(ref); - } - - /*! - @copydoc iterator_wrapper(reference) - */ - static iteration_proxy iterator_wrapper(const_reference ref) - { - return iteration_proxy(ref); - } - - /// @} - - ////////////// - // capacity // - ////////////// - - /// @name capacity - /// @{ - - /*! - @brief checks whether the container is empty. - - Checks if a JSON value has no elements (i.e. whether its @ref size is `0`). - - @return The return value depends on the different types and is - defined as follows: - Value type | return value - ----------- | ------------- - null | `true` - boolean | `false` - string | `false` - number | `false` - object | result of function `object_t::empty()` - array | result of function `array_t::empty()` - - @liveexample{The following code uses `empty()` to check if a JSON - object contains any elements.,empty} - - @complexity Constant, as long as @ref array_t and @ref object_t satisfy - the Container concept; that is, their `empty()` functions have constant - complexity. - - @iterators No changes. - - @exceptionsafety No-throw guarantee: this function never throws exceptions. - - @note This function does not return whether a string stored as JSON value - is empty - it returns whether the JSON container itself is empty which is - false in the case of a string. - - @requirement This function helps `basic_json` satisfying the - [Container](http://en.cppreference.com/w/cpp/concept/Container) - requirements: - - The complexity is constant. - - Has the semantics of `begin() == end()`. - - @sa @ref size() -- returns the number of elements - - @since version 1.0.0 - */ - bool empty() const noexcept - { - switch (m_type) - { - case value_t::null: - { - // null values are empty - return true; - } - - case value_t::array: - { - // delegate call to array_t::empty() - return m_value.array->empty(); - } - - case value_t::object: - { - // delegate call to object_t::empty() - return m_value.object->empty(); - } - - default: - { - // all other types are nonempty - return false; - } - } - } - - /*! - @brief returns the number of elements - - Returns the number of elements in a JSON value. - - @return The return value depends on the different types and is - defined as follows: - Value type | return value - ----------- | ------------- - null | `0` - boolean | `1` - string | `1` - number | `1` - object | result of function object_t::size() - array | result of function array_t::size() - - @liveexample{The following code calls `size()` on the different value - types.,size} - - @complexity Constant, as long as @ref array_t and @ref object_t satisfy - the Container concept; that is, their size() functions have constant - complexity. - - @iterators No changes. - - @exceptionsafety No-throw guarantee: this function never throws exceptions. - - @note This function does not return the length of a string stored as JSON - value - it returns the number of elements in the JSON value which is 1 in - the case of a string. - - @requirement This function helps `basic_json` satisfying the - [Container](http://en.cppreference.com/w/cpp/concept/Container) - requirements: - - The complexity is constant. - - Has the semantics of `std::distance(begin(), end())`. - - @sa @ref empty() -- checks whether the container is empty - @sa @ref max_size() -- returns the maximal number of elements - - @since version 1.0.0 - */ - size_type size() const noexcept - { - switch (m_type) - { - case value_t::null: - { - // null values are empty - return 0; - } - - case value_t::array: - { - // delegate call to array_t::size() - return m_value.array->size(); - } - - case value_t::object: - { - // delegate call to object_t::size() - return m_value.object->size(); - } - - default: - { - // all other types have size 1 - return 1; - } - } - } - - /*! - @brief returns the maximum possible number of elements - - Returns the maximum number of elements a JSON value is able to hold due to - system or library implementation limitations, i.e. `std::distance(begin(), - end())` for the JSON value. - - @return The return value depends on the different types and is - defined as follows: - Value type | return value - ----------- | ------------- - null | `0` (same as `size()`) - boolean | `1` (same as `size()`) - string | `1` (same as `size()`) - number | `1` (same as `size()`) - object | result of function `object_t::max_size()` - array | result of function `array_t::max_size()` - - @liveexample{The following code calls `max_size()` on the different value - types. Note the output is implementation specific.,max_size} - - @complexity Constant, as long as @ref array_t and @ref object_t satisfy - the Container concept; that is, their `max_size()` functions have constant - complexity. - - @iterators No changes. - - @exceptionsafety No-throw guarantee: this function never throws exceptions. - - @requirement This function helps `basic_json` satisfying the - [Container](http://en.cppreference.com/w/cpp/concept/Container) - requirements: - - The complexity is constant. - - Has the semantics of returning `b.size()` where `b` is the largest - possible JSON value. - - @sa @ref size() -- returns the number of elements - - @since version 1.0.0 - */ - size_type max_size() const noexcept - { - switch (m_type) - { - case value_t::array: - { - // delegate call to array_t::max_size() - return m_value.array->max_size(); - } - - case value_t::object: - { - // delegate call to object_t::max_size() - return m_value.object->max_size(); - } - - default: - { - // all other types have max_size() == size() - return size(); - } - } - } - - /// @} - - /////////////// - // modifiers // - /////////////// - - /// @name modifiers - /// @{ - - /*! - @brief clears the contents - - Clears the content of a JSON value and resets it to the default value as - if @ref basic_json(value_t) would have been called with the current value - type from @ref type(): - - Value type | initial value - ----------- | ------------- - null | `null` - boolean | `false` - string | `""` - number | `0` - object | `{}` - array | `[]` - - @post Has the same effect as calling - @code {.cpp} - *this = basic_json(type()); - @endcode - - @liveexample{The example below shows the effect of `clear()` to different - JSON types.,clear} - - @complexity Linear in the size of the JSON value. - - @iterators All iterators, pointers and references related to this container - are invalidated. - - @exceptionsafety No-throw guarantee: this function never throws exceptions. - - @sa @ref basic_json(value_t) -- constructor that creates an object with the - same value than calling `clear()` - - @since version 1.0.0 - */ - void clear() noexcept - { - switch (m_type) - { - case value_t::number_integer: - { - m_value.number_integer = 0; - break; - } - - case value_t::number_unsigned: - { - m_value.number_unsigned = 0; - break; - } - - case value_t::number_float: - { - m_value.number_float = 0.0; - break; - } - - case value_t::boolean: - { - m_value.boolean = false; - break; - } - - case value_t::string: - { - m_value.string->clear(); - break; - } - - case value_t::array: - { - m_value.array->clear(); - break; - } - - case value_t::object: - { - m_value.object->clear(); - break; - } - - default: - break; - } - } - - /*! - @brief add an object to an array - - Appends the given element @a val to the end of the JSON value. If the - function is called on a JSON null value, an empty array is created before - appending @a val. - - @param[in] val the value to add to the JSON array - - @throw type_error.308 when called on a type other than JSON array or - null; example: `"cannot use push_back() with number"` - - @complexity Amortized constant. - - @liveexample{The example shows how `push_back()` and `+=` can be used to - add elements to a JSON array. Note how the `null` value was silently - converted to a JSON array.,push_back} - - @since version 1.0.0 - */ - void push_back(basic_json&& val) - { - // push_back only works for null objects or arrays - if (JSON_UNLIKELY(not(is_null() or is_array()))) - { - JSON_THROW(type_error::create(308, "cannot use push_back() with " + std::string(type_name()))); - } - - // transform null object into an array - if (is_null()) - { - m_type = value_t::array; - m_value = value_t::array; - assert_invariant(); - } - - // add element to array (move semantics) - m_value.array->push_back(std::move(val)); - // invalidate object - val.m_type = value_t::null; - } - - /*! - @brief add an object to an array - @copydoc push_back(basic_json&&) - */ - reference operator+=(basic_json&& val) - { - push_back(std::move(val)); - return *this; - } - - /*! - @brief add an object to an array - @copydoc push_back(basic_json&&) - */ - void push_back(const basic_json& val) - { - // push_back only works for null objects or arrays - if (JSON_UNLIKELY(not(is_null() or is_array()))) - { - JSON_THROW(type_error::create(308, "cannot use push_back() with " + std::string(type_name()))); - } - - // transform null object into an array - if (is_null()) - { - m_type = value_t::array; - m_value = value_t::array; - assert_invariant(); - } - - // add element to array - m_value.array->push_back(val); - } - - /*! - @brief add an object to an array - @copydoc push_back(basic_json&&) - */ - reference operator+=(const basic_json& val) - { - push_back(val); - return *this; - } - - /*! - @brief add an object to an object - - Inserts the given element @a val to the JSON object. If the function is - called on a JSON null value, an empty object is created before inserting - @a val. - - @param[in] val the value to add to the JSON object - - @throw type_error.308 when called on a type other than JSON object or - null; example: `"cannot use push_back() with number"` - - @complexity Logarithmic in the size of the container, O(log(`size()`)). - - @liveexample{The example shows how `push_back()` and `+=` can be used to - add elements to a JSON object. Note how the `null` value was silently - converted to a JSON object.,push_back__object_t__value} - - @since version 1.0.0 - */ - void push_back(const typename object_t::value_type& val) - { - // push_back only works for null objects or objects - if (JSON_UNLIKELY(not(is_null() or is_object()))) - { - JSON_THROW(type_error::create(308, "cannot use push_back() with " + std::string(type_name()))); - } - - // transform null object into an object - if (is_null()) - { - m_type = value_t::object; - m_value = value_t::object; - assert_invariant(); - } - - // add element to array - m_value.object->insert(val); - } - - /*! - @brief add an object to an object - @copydoc push_back(const typename object_t::value_type&) - */ - reference operator+=(const typename object_t::value_type& val) - { - push_back(val); - return *this; - } - - /*! - @brief add an object to an object - - This function allows to use `push_back` with an initializer list. In case - - 1. the current value is an object, - 2. the initializer list @a init contains only two elements, and - 3. the first element of @a init is a string, - - @a init is converted into an object element and added using - @ref push_back(const typename object_t::value_type&). Otherwise, @a init - is converted to a JSON value and added using @ref push_back(basic_json&&). - - @param[in] init an initializer list - - @complexity Linear in the size of the initializer list @a init. - - @note This function is required to resolve an ambiguous overload error, - because pairs like `{"key", "value"}` can be both interpreted as - `object_t::value_type` or `std::initializer_list`, see - https://github.com/nlohmann/json/issues/235 for more information. - - @liveexample{The example shows how initializer lists are treated as - objects when possible.,push_back__initializer_list} - */ - void push_back(initializer_list_t init) - { - if (is_object() and init.size() == 2 and (*init.begin())->is_string()) - { - basic_json&& key = init.begin()->moved_or_copied(); - push_back(typename object_t::value_type( - std::move(key.get_ref()), (init.begin() + 1)->moved_or_copied())); - } - else - { - push_back(basic_json(init)); - } - } - - /*! - @brief add an object to an object - @copydoc push_back(initializer_list_t) - */ - reference operator+=(initializer_list_t init) - { - push_back(init); - return *this; - } - - /*! - @brief add an object to an array - - Creates a JSON value from the passed parameters @a args to the end of the - JSON value. If the function is called on a JSON null value, an empty array - is created before appending the value created from @a args. - - @param[in] args arguments to forward to a constructor of @ref basic_json - @tparam Args compatible types to create a @ref basic_json object - - @throw type_error.311 when called on a type other than JSON array or - null; example: `"cannot use emplace_back() with number"` - - @complexity Amortized constant. - - @liveexample{The example shows how `push_back()` can be used to add - elements to a JSON array. Note how the `null` value was silently converted - to a JSON array.,emplace_back} - - @since version 2.0.8 - */ - template - void emplace_back(Args&& ... args) - { - // emplace_back only works for null objects or arrays - if (JSON_UNLIKELY(not(is_null() or is_array()))) - { - JSON_THROW(type_error::create(311, "cannot use emplace_back() with " + std::string(type_name()))); - } - - // transform null object into an array - if (is_null()) - { - m_type = value_t::array; - m_value = value_t::array; - assert_invariant(); - } - - // add element to array (perfect forwarding) - m_value.array->emplace_back(std::forward(args)...); - } - - /*! - @brief add an object to an object if key does not exist - - Inserts a new element into a JSON object constructed in-place with the - given @a args if there is no element with the key in the container. If the - function is called on a JSON null value, an empty object is created before - appending the value created from @a args. - - @param[in] args arguments to forward to a constructor of @ref basic_json - @tparam Args compatible types to create a @ref basic_json object - - @return a pair consisting of an iterator to the inserted element, or the - already-existing element if no insertion happened, and a bool - denoting whether the insertion took place. - - @throw type_error.311 when called on a type other than JSON object or - null; example: `"cannot use emplace() with number"` - - @complexity Logarithmic in the size of the container, O(log(`size()`)). - - @liveexample{The example shows how `emplace()` can be used to add elements - to a JSON object. Note how the `null` value was silently converted to a - JSON object. Further note how no value is added if there was already one - value stored with the same key.,emplace} - - @since version 2.0.8 - */ - template - std::pair emplace(Args&& ... args) - { - // emplace only works for null objects or arrays - if (JSON_UNLIKELY(not(is_null() or is_object()))) - { - JSON_THROW(type_error::create(311, "cannot use emplace() with " + std::string(type_name()))); - } - - // transform null object into an object - if (is_null()) - { - m_type = value_t::object; - m_value = value_t::object; - assert_invariant(); - } - - // add element to array (perfect forwarding) - auto res = m_value.object->emplace(std::forward(args)...); - // create result iterator and set iterator to the result of emplace - auto it = begin(); - it.m_it.object_iterator = res.first; - - // return pair of iterator and boolean - return {it, res.second}; - } - - /*! - @brief inserts element - - Inserts element @a val before iterator @a pos. - - @param[in] pos iterator before which the content will be inserted; may be - the end() iterator - @param[in] val element to insert - @return iterator pointing to the inserted @a val. - - @throw type_error.309 if called on JSON values other than arrays; - example: `"cannot use insert() with string"` - @throw invalid_iterator.202 if @a pos is not an iterator of *this; - example: `"iterator does not fit current value"` - - @complexity Constant plus linear in the distance between @a pos and end of - the container. - - @liveexample{The example shows how `insert()` is used.,insert} - - @since version 1.0.0 - */ - iterator insert(const_iterator pos, const basic_json& val) - { - // insert only works for arrays - if (JSON_LIKELY(is_array())) - { - // check if iterator pos fits to this JSON value - if (JSON_UNLIKELY(pos.m_object != this)) - { - JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value")); - } - - // insert to array and return iterator - iterator result(this); - result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, val); - return result; - } - - JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); - } - - /*! - @brief inserts element - @copydoc insert(const_iterator, const basic_json&) - */ - iterator insert(const_iterator pos, basic_json&& val) - { - return insert(pos, val); - } - - /*! - @brief inserts elements - - Inserts @a cnt copies of @a val before iterator @a pos. - - @param[in] pos iterator before which the content will be inserted; may be - the end() iterator - @param[in] cnt number of copies of @a val to insert - @param[in] val element to insert - @return iterator pointing to the first element inserted, or @a pos if - `cnt==0` - - @throw type_error.309 if called on JSON values other than arrays; example: - `"cannot use insert() with string"` - @throw invalid_iterator.202 if @a pos is not an iterator of *this; - example: `"iterator does not fit current value"` - - @complexity Linear in @a cnt plus linear in the distance between @a pos - and end of the container. - - @liveexample{The example shows how `insert()` is used.,insert__count} - - @since version 1.0.0 - */ - iterator insert(const_iterator pos, size_type cnt, const basic_json& val) - { - // insert only works for arrays - if (JSON_LIKELY(is_array())) - { - // check if iterator pos fits to this JSON value - if (JSON_UNLIKELY(pos.m_object != this)) - { - JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value")); - } - - // insert to array and return iterator - iterator result(this); - result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val); - return result; - } - - JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); - } - - /*! - @brief inserts elements - - Inserts elements from range `[first, last)` before iterator @a pos. - - @param[in] pos iterator before which the content will be inserted; may be - the end() iterator - @param[in] first begin of the range of elements to insert - @param[in] last end of the range of elements to insert - - @throw type_error.309 if called on JSON values other than arrays; example: - `"cannot use insert() with string"` - @throw invalid_iterator.202 if @a pos is not an iterator of *this; - example: `"iterator does not fit current value"` - @throw invalid_iterator.210 if @a first and @a last do not belong to the - same JSON value; example: `"iterators do not fit"` - @throw invalid_iterator.211 if @a first or @a last are iterators into - container for which insert is called; example: `"passed iterators may not - belong to container"` - - @return iterator pointing to the first element inserted, or @a pos if - `first==last` - - @complexity Linear in `std::distance(first, last)` plus linear in the - distance between @a pos and end of the container. - - @liveexample{The example shows how `insert()` is used.,insert__range} - - @since version 1.0.0 - */ - iterator insert(const_iterator pos, const_iterator first, const_iterator last) - { - // insert only works for arrays - if (JSON_UNLIKELY(not is_array())) - { - JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); - } - - // check if iterator pos fits to this JSON value - if (JSON_UNLIKELY(pos.m_object != this)) - { - JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value")); - } - - // check if range iterators belong to the same JSON object - if (JSON_UNLIKELY(first.m_object != last.m_object)) - { - JSON_THROW(invalid_iterator::create(210, "iterators do not fit")); - } - - if (JSON_UNLIKELY(first.m_object == this)) - { - JSON_THROW(invalid_iterator::create(211, "passed iterators may not belong to container")); - } - - // insert to array and return iterator - iterator result(this); - result.m_it.array_iterator = m_value.array->insert( - pos.m_it.array_iterator, - first.m_it.array_iterator, - last.m_it.array_iterator); - return result; - } - - /*! - @brief inserts elements - - Inserts elements from initializer list @a ilist before iterator @a pos. - - @param[in] pos iterator before which the content will be inserted; may be - the end() iterator - @param[in] ilist initializer list to insert the values from - - @throw type_error.309 if called on JSON values other than arrays; example: - `"cannot use insert() with string"` - @throw invalid_iterator.202 if @a pos is not an iterator of *this; - example: `"iterator does not fit current value"` - - @return iterator pointing to the first element inserted, or @a pos if - `ilist` is empty - - @complexity Linear in `ilist.size()` plus linear in the distance between - @a pos and end of the container. - - @liveexample{The example shows how `insert()` is used.,insert__ilist} - - @since version 1.0.0 - */ - iterator insert(const_iterator pos, initializer_list_t ilist) - { - // insert only works for arrays - if (JSON_UNLIKELY(not is_array())) - { - JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); - } - - // check if iterator pos fits to this JSON value - if (JSON_UNLIKELY(pos.m_object != this)) - { - JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value")); - } - - // insert to array and return iterator - iterator result(this); - result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, ilist.begin(), ilist.end()); - return result; - } - - /*! - @brief inserts elements - - Inserts elements from range `[first, last)`. - - @param[in] first begin of the range of elements to insert - @param[in] last end of the range of elements to insert - - @throw type_error.309 if called on JSON values other than objects; example: - `"cannot use insert() with string"` - @throw invalid_iterator.202 if iterator @a first or @a last does does not - point to an object; example: `"iterators first and last must point to - objects"` - @throw invalid_iterator.210 if @a first and @a last do not belong to the - same JSON value; example: `"iterators do not fit"` - - @complexity Logarithmic: `O(N*log(size() + N))`, where `N` is the number - of elements to insert. - - @liveexample{The example shows how `insert()` is used.,insert__range_object} - - @since version 3.0.0 - */ - void insert(const_iterator first, const_iterator last) - { - // insert only works for objects - if (JSON_UNLIKELY(not is_object())) - { - JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); - } - - // check if range iterators belong to the same JSON object - if (JSON_UNLIKELY(first.m_object != last.m_object)) - { - JSON_THROW(invalid_iterator::create(210, "iterators do not fit")); - } - - // passed iterators must belong to objects - if (JSON_UNLIKELY(not first.m_object->is_object())) - { - JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects")); - } - - m_value.object->insert(first.m_it.object_iterator, last.m_it.object_iterator); - } - - /*! - @brief updates a JSON object from another object, overwriting existing keys - - Inserts all values from JSON object @a j and overwrites existing keys. - - @param[in] j JSON object to read values from - - @throw type_error.312 if called on JSON values other than objects; example: - `"cannot use update() with string"` - - @complexity O(N*log(size() + N)), where N is the number of elements to - insert. - - @liveexample{The example shows how `update()` is used.,update} - - @sa https://docs.python.org/3.6/library/stdtypes.html#dict.update - - @since version 3.0.0 - */ - void update(const_reference j) - { - // implicitly convert null value to an empty object - if (is_null()) - { - m_type = value_t::object; - m_value.object = create(); - assert_invariant(); - } - - if (JSON_UNLIKELY(not is_object())) - { - JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(type_name()))); - } - if (JSON_UNLIKELY(not j.is_object())) - { - JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(j.type_name()))); - } - - for (auto it = j.cbegin(); it != j.cend(); ++it) - { - m_value.object->operator[](it.key()) = it.value(); - } - } - - /*! - @brief updates a JSON object from another object, overwriting existing keys - - Inserts all values from from range `[first, last)` and overwrites existing - keys. - - @param[in] first begin of the range of elements to insert - @param[in] last end of the range of elements to insert - - @throw type_error.312 if called on JSON values other than objects; example: - `"cannot use update() with string"` - @throw invalid_iterator.202 if iterator @a first or @a last does does not - point to an object; example: `"iterators first and last must point to - objects"` - @throw invalid_iterator.210 if @a first and @a last do not belong to the - same JSON value; example: `"iterators do not fit"` - - @complexity O(N*log(size() + N)), where N is the number of elements to - insert. - - @liveexample{The example shows how `update()` is used__range.,update} - - @sa https://docs.python.org/3.6/library/stdtypes.html#dict.update - - @since version 3.0.0 - */ - void update(const_iterator first, const_iterator last) - { - // implicitly convert null value to an empty object - if (is_null()) - { - m_type = value_t::object; - m_value.object = create(); - assert_invariant(); - } - - if (JSON_UNLIKELY(not is_object())) - { - JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(type_name()))); - } - - // check if range iterators belong to the same JSON object - if (JSON_UNLIKELY(first.m_object != last.m_object)) - { - JSON_THROW(invalid_iterator::create(210, "iterators do not fit")); - } - - // passed iterators must belong to objects - if (JSON_UNLIKELY(not first.m_object->is_object() - or not first.m_object->is_object())) - { - JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects")); - } - - for (auto it = first; it != last; ++it) - { - m_value.object->operator[](it.key()) = it.value(); - } - } - - /*! - @brief exchanges the values - - Exchanges the contents of the JSON value with those of @a other. Does not - invoke any move, copy, or swap operations on individual elements. All - iterators and references remain valid. The past-the-end iterator is - invalidated. - - @param[in,out] other JSON value to exchange the contents with - - @complexity Constant. - - @liveexample{The example below shows how JSON values can be swapped with - `swap()`.,swap__reference} - - @since version 1.0.0 - */ - void swap(reference other) noexcept ( - std::is_nothrow_move_constructible::value and - std::is_nothrow_move_assignable::value and - std::is_nothrow_move_constructible::value and - std::is_nothrow_move_assignable::value - ) - { - std::swap(m_type, other.m_type); - std::swap(m_value, other.m_value); - assert_invariant(); - } - - /*! - @brief exchanges the values - - Exchanges the contents of a JSON array with those of @a other. Does not - invoke any move, copy, or swap operations on individual elements. All - iterators and references remain valid. The past-the-end iterator is - invalidated. - - @param[in,out] other array to exchange the contents with - - @throw type_error.310 when JSON value is not an array; example: `"cannot - use swap() with string"` - - @complexity Constant. - - @liveexample{The example below shows how arrays can be swapped with - `swap()`.,swap__array_t} - - @since version 1.0.0 - */ - void swap(array_t& other) - { - // swap only works for arrays - if (JSON_LIKELY(is_array())) - { - std::swap(*(m_value.array), other); - } - else - { - JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name()))); - } - } - - /*! - @brief exchanges the values - - Exchanges the contents of a JSON object with those of @a other. Does not - invoke any move, copy, or swap operations on individual elements. All - iterators and references remain valid. The past-the-end iterator is - invalidated. - - @param[in,out] other object to exchange the contents with - - @throw type_error.310 when JSON value is not an object; example: - `"cannot use swap() with string"` - - @complexity Constant. - - @liveexample{The example below shows how objects can be swapped with - `swap()`.,swap__object_t} - - @since version 1.0.0 - */ - void swap(object_t& other) - { - // swap only works for objects - if (JSON_LIKELY(is_object())) - { - std::swap(*(m_value.object), other); - } - else - { - JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name()))); - } - } - - /*! - @brief exchanges the values - - Exchanges the contents of a JSON string with those of @a other. Does not - invoke any move, copy, or swap operations on individual elements. All - iterators and references remain valid. The past-the-end iterator is - invalidated. - - @param[in,out] other string to exchange the contents with - - @throw type_error.310 when JSON value is not a string; example: `"cannot - use swap() with boolean"` - - @complexity Constant. - - @liveexample{The example below shows how strings can be swapped with - `swap()`.,swap__string_t} - - @since version 1.0.0 - */ - void swap(string_t& other) - { - // swap only works for strings - if (JSON_LIKELY(is_string())) - { - std::swap(*(m_value.string), other); - } - else - { - JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name()))); - } - } - - /// @} - - public: - ////////////////////////////////////////// - // lexicographical comparison operators // - ////////////////////////////////////////// - - /// @name lexicographical comparison operators - /// @{ - - /*! - @brief comparison: equal - - Compares two JSON values for equality according to the following rules: - - Two JSON values are equal if (1) they are from the same type and (2) - their stored values are the same according to their respective - `operator==`. - - Integer and floating-point numbers are automatically converted before - comparison. Note than two NaN values are always treated as unequal. - - Two JSON null values are equal. - - @note Floating-point inside JSON values numbers are compared with - `json::number_float_t::operator==` which is `double::operator==` by - default. To compare floating-point while respecting an epsilon, an alternative - [comparison function](https://github.com/mariokonrad/marnav/blob/master/src/marnav/math/floatingpoint.hpp#L34-#L39) - could be used, for instance - @code {.cpp} - template::value, T>::type> - inline bool is_same(T a, T b, T epsilon = std::numeric_limits::epsilon()) noexcept - { - return std::abs(a - b) <= epsilon; - } - @endcode - - @note NaN values never compare equal to themselves or to other NaN values. - - @param[in] lhs first JSON value to consider - @param[in] rhs second JSON value to consider - @return whether the values @a lhs and @a rhs are equal - - @exceptionsafety No-throw guarantee: this function never throws exceptions. - - @complexity Linear. - - @liveexample{The example demonstrates comparing several JSON - types.,operator__equal} - - @since version 1.0.0 - */ - friend bool operator==(const_reference lhs, const_reference rhs) noexcept - { - const auto lhs_type = lhs.type(); - const auto rhs_type = rhs.type(); - - if (lhs_type == rhs_type) - { - switch (lhs_type) - { - case value_t::array: - return (*lhs.m_value.array == *rhs.m_value.array); - - case value_t::object: - return (*lhs.m_value.object == *rhs.m_value.object); - - case value_t::null: - return true; - - case value_t::string: - return (*lhs.m_value.string == *rhs.m_value.string); - - case value_t::boolean: - return (lhs.m_value.boolean == rhs.m_value.boolean); - - case value_t::number_integer: - return (lhs.m_value.number_integer == rhs.m_value.number_integer); - - case value_t::number_unsigned: - return (lhs.m_value.number_unsigned == rhs.m_value.number_unsigned); - - case value_t::number_float: - return (lhs.m_value.number_float == rhs.m_value.number_float); - - default: - return false; - } - } - else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float) - { - return (static_cast(lhs.m_value.number_integer) == rhs.m_value.number_float); - } - else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer) - { - return (lhs.m_value.number_float == static_cast(rhs.m_value.number_integer)); - } - else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float) - { - return (static_cast(lhs.m_value.number_unsigned) == rhs.m_value.number_float); - } - else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned) - { - return (lhs.m_value.number_float == static_cast(rhs.m_value.number_unsigned)); - } - else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer) - { - return (static_cast(lhs.m_value.number_unsigned) == rhs.m_value.number_integer); - } - else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned) - { - return (lhs.m_value.number_integer == static_cast(rhs.m_value.number_unsigned)); - } - - return false; - } - - /*! - @brief comparison: equal - @copydoc operator==(const_reference, const_reference) - */ - template::value, int>::type = 0> - friend bool operator==(const_reference lhs, const ScalarType rhs) noexcept - { - return (lhs == basic_json(rhs)); - } - - /*! - @brief comparison: equal - @copydoc operator==(const_reference, const_reference) - */ - template::value, int>::type = 0> - friend bool operator==(const ScalarType lhs, const_reference rhs) noexcept - { - return (basic_json(lhs) == rhs); - } - - /*! - @brief comparison: not equal - - Compares two JSON values for inequality by calculating `not (lhs == rhs)`. - - @param[in] lhs first JSON value to consider - @param[in] rhs second JSON value to consider - @return whether the values @a lhs and @a rhs are not equal - - @complexity Linear. - - @exceptionsafety No-throw guarantee: this function never throws exceptions. - - @liveexample{The example demonstrates comparing several JSON - types.,operator__notequal} - - @since version 1.0.0 - */ - friend bool operator!=(const_reference lhs, const_reference rhs) noexcept - { - return not (lhs == rhs); - } - - /*! - @brief comparison: not equal - @copydoc operator!=(const_reference, const_reference) - */ - template::value, int>::type = 0> - friend bool operator!=(const_reference lhs, const ScalarType rhs) noexcept - { - return (lhs != basic_json(rhs)); - } - - /*! - @brief comparison: not equal - @copydoc operator!=(const_reference, const_reference) - */ - template::value, int>::type = 0> - friend bool operator!=(const ScalarType lhs, const_reference rhs) noexcept - { - return (basic_json(lhs) != rhs); - } - - /*! - @brief comparison: less than - - Compares whether one JSON value @a lhs is less than another JSON value @a - rhs according to the following rules: - - If @a lhs and @a rhs have the same type, the values are compared using - the default `<` operator. - - Integer and floating-point numbers are automatically converted before - comparison - - In case @a lhs and @a rhs have different types, the values are ignored - and the order of the types is considered, see - @ref operator<(const value_t, const value_t). - - @param[in] lhs first JSON value to consider - @param[in] rhs second JSON value to consider - @return whether @a lhs is less than @a rhs - - @complexity Linear. - - @exceptionsafety No-throw guarantee: this function never throws exceptions. - - @liveexample{The example demonstrates comparing several JSON - types.,operator__less} - - @since version 1.0.0 - */ - friend bool operator<(const_reference lhs, const_reference rhs) noexcept - { - const auto lhs_type = lhs.type(); - const auto rhs_type = rhs.type(); - - if (lhs_type == rhs_type) - { - switch (lhs_type) - { - case value_t::array: - return (*lhs.m_value.array) < (*rhs.m_value.array); - - case value_t::object: - return *lhs.m_value.object < *rhs.m_value.object; - - case value_t::null: - return false; - - case value_t::string: - return *lhs.m_value.string < *rhs.m_value.string; - - case value_t::boolean: - return lhs.m_value.boolean < rhs.m_value.boolean; - - case value_t::number_integer: - return lhs.m_value.number_integer < rhs.m_value.number_integer; - - case value_t::number_unsigned: - return lhs.m_value.number_unsigned < rhs.m_value.number_unsigned; - - case value_t::number_float: - return lhs.m_value.number_float < rhs.m_value.number_float; - - default: - return false; - } - } - else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float) - { - return static_cast(lhs.m_value.number_integer) < rhs.m_value.number_float; - } - else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer) - { - return lhs.m_value.number_float < static_cast(rhs.m_value.number_integer); - } - else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float) - { - return static_cast(lhs.m_value.number_unsigned) < rhs.m_value.number_float; - } - else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned) - { - return lhs.m_value.number_float < static_cast(rhs.m_value.number_unsigned); - } - else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned) - { - return lhs.m_value.number_integer < static_cast(rhs.m_value.number_unsigned); - } - else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer) - { - return static_cast(lhs.m_value.number_unsigned) < rhs.m_value.number_integer; - } - - // We only reach this line if we cannot compare values. In that case, - // we compare types. Note we have to call the operator explicitly, - // because MSVC has problems otherwise. - return operator<(lhs_type, rhs_type); - } - - /*! - @brief comparison: less than - @copydoc operator<(const_reference, const_reference) - */ - template::value, int>::type = 0> - friend bool operator<(const_reference lhs, const ScalarType rhs) noexcept - { - return (lhs < basic_json(rhs)); - } - - /*! - @brief comparison: less than - @copydoc operator<(const_reference, const_reference) - */ - template::value, int>::type = 0> - friend bool operator<(const ScalarType lhs, const_reference rhs) noexcept - { - return (basic_json(lhs) < rhs); - } - - /*! - @brief comparison: less than or equal - - Compares whether one JSON value @a lhs is less than or equal to another - JSON value by calculating `not (rhs < lhs)`. - - @param[in] lhs first JSON value to consider - @param[in] rhs second JSON value to consider - @return whether @a lhs is less than or equal to @a rhs - - @complexity Linear. - - @exceptionsafety No-throw guarantee: this function never throws exceptions. - - @liveexample{The example demonstrates comparing several JSON - types.,operator__greater} - - @since version 1.0.0 - */ - friend bool operator<=(const_reference lhs, const_reference rhs) noexcept - { - return not (rhs < lhs); - } - - /*! - @brief comparison: less than or equal - @copydoc operator<=(const_reference, const_reference) - */ - template::value, int>::type = 0> - friend bool operator<=(const_reference lhs, const ScalarType rhs) noexcept - { - return (lhs <= basic_json(rhs)); - } - - /*! - @brief comparison: less than or equal - @copydoc operator<=(const_reference, const_reference) - */ - template::value, int>::type = 0> - friend bool operator<=(const ScalarType lhs, const_reference rhs) noexcept - { - return (basic_json(lhs) <= rhs); - } - - /*! - @brief comparison: greater than - - Compares whether one JSON value @a lhs is greater than another - JSON value by calculating `not (lhs <= rhs)`. - - @param[in] lhs first JSON value to consider - @param[in] rhs second JSON value to consider - @return whether @a lhs is greater than to @a rhs - - @complexity Linear. - - @exceptionsafety No-throw guarantee: this function never throws exceptions. - - @liveexample{The example demonstrates comparing several JSON - types.,operator__lessequal} - - @since version 1.0.0 - */ - friend bool operator>(const_reference lhs, const_reference rhs) noexcept - { - return not (lhs <= rhs); - } - - /*! - @brief comparison: greater than - @copydoc operator>(const_reference, const_reference) - */ - template::value, int>::type = 0> - friend bool operator>(const_reference lhs, const ScalarType rhs) noexcept - { - return (lhs > basic_json(rhs)); - } - - /*! - @brief comparison: greater than - @copydoc operator>(const_reference, const_reference) - */ - template::value, int>::type = 0> - friend bool operator>(const ScalarType lhs, const_reference rhs) noexcept - { - return (basic_json(lhs) > rhs); - } - - /*! - @brief comparison: greater than or equal - - Compares whether one JSON value @a lhs is greater than or equal to another - JSON value by calculating `not (lhs < rhs)`. - - @param[in] lhs first JSON value to consider - @param[in] rhs second JSON value to consider - @return whether @a lhs is greater than or equal to @a rhs - - @complexity Linear. - - @exceptionsafety No-throw guarantee: this function never throws exceptions. - - @liveexample{The example demonstrates comparing several JSON - types.,operator__greaterequal} - - @since version 1.0.0 - */ - friend bool operator>=(const_reference lhs, const_reference rhs) noexcept - { - return not (lhs < rhs); - } - - /*! - @brief comparison: greater than or equal - @copydoc operator>=(const_reference, const_reference) - */ - template::value, int>::type = 0> - friend bool operator>=(const_reference lhs, const ScalarType rhs) noexcept - { - return (lhs >= basic_json(rhs)); - } - - /*! - @brief comparison: greater than or equal - @copydoc operator>=(const_reference, const_reference) - */ - template::value, int>::type = 0> - friend bool operator>=(const ScalarType lhs, const_reference rhs) noexcept - { - return (basic_json(lhs) >= rhs); - } - - /// @} - - /////////////////// - // serialization // - /////////////////// - - /// @name serialization - /// @{ - - /*! - @brief serialize to stream - - Serialize the given JSON value @a j to the output stream @a o. The JSON - value will be serialized using the @ref dump member function. - - - The indentation of the output can be controlled with the member variable - `width` of the output stream @a o. For instance, using the manipulator - `std::setw(4)` on @a o sets the indentation level to `4` and the - serialization result is the same as calling `dump(4)`. - - - The indentation character can be controlled with the member variable - `fill` of the output stream @a o. For instance, the manipulator - `std::setfill('\\t')` sets indentation to use a tab character rather than - the default space character. - - @param[in,out] o stream to serialize to - @param[in] j JSON value to serialize - - @return the stream @a o - - @throw type_error.316 if a string stored inside the JSON value is not - UTF-8 encoded - - @complexity Linear. - - @liveexample{The example below shows the serialization with different - parameters to `width` to adjust the indentation level.,operator_serialize} - - @since version 1.0.0; indentation character added in version 3.0.0 - */ - friend std::ostream& operator<<(std::ostream& o, const basic_json& j) - { - // read width member and use it as indentation parameter if nonzero - const bool pretty_print = (o.width() > 0); - const auto indentation = (pretty_print ? o.width() : 0); - - // reset width to 0 for subsequent calls to this stream - o.width(0); - - // do the actual serialization - serializer s(detail::output_adapter(o), o.fill()); - s.dump(j, pretty_print, false, static_cast(indentation)); - return o; - } - - /*! - @brief serialize to stream - @deprecated This stream operator is deprecated and will be removed in a - future version of the library. Please use - @ref operator<<(std::ostream&, const basic_json&) - instead; that is, replace calls like `j >> o;` with `o << j;`. - @since version 1.0.0; deprecated since version 3.0.0 - */ - JSON_DEPRECATED - friend std::ostream& operator>>(const basic_json& j, std::ostream& o) - { - return o << j; - } - - /// @} - - ///////////////////// - // deserialization // - ///////////////////// - - /// @name deserialization - /// @{ - - /*! - @brief deserialize from a compatible input - - This function reads from a compatible input. Examples are: - - an array of 1-byte values - - strings with character/literal type with size of 1 byte - - input streams - - container with contiguous storage of 1-byte values. Compatible container - types include `std::vector`, `std::string`, `std::array`, - `std::valarray`, and `std::initializer_list`. Furthermore, C-style - arrays can be used with `std::begin()`/`std::end()`. User-defined - containers can be used as long as they implement random-access iterators - and a contiguous storage. - - @pre Each element of the container has a size of 1 byte. Violating this - precondition yields undefined behavior. **This precondition is enforced - with a static assertion.** - - @pre The container storage is contiguous. Violating this precondition - yields undefined behavior. **This precondition is enforced with an - assertion.** - @pre Each element of the container has a size of 1 byte. Violating this - precondition yields undefined behavior. **This precondition is enforced - with a static assertion.** - - @warning There is no way to enforce all preconditions at compile-time. If - the function is called with a noncompliant container and with - assertions switched off, the behavior is undefined and will most - likely yield segmentation violation. - - @param[in] i input to read from - @param[in] cb a parser callback function of type @ref parser_callback_t - which is used to control the deserialization by filtering unwanted values - (optional) - - @return result of the deserialization - - @throw parse_error.101 if a parse error occurs; example: `""unexpected end - of input; expected string literal""` - @throw parse_error.102 if to_unicode fails or surrogate error - @throw parse_error.103 if to_unicode fails - - @complexity Linear in the length of the input. The parser is a predictive - LL(1) parser. The complexity can be higher if the parser callback function - @a cb has a super-linear complexity. - - @note A UTF-8 byte order mark is silently ignored. - - @liveexample{The example below demonstrates the `parse()` function reading - from an array.,parse__array__parser_callback_t} - - @liveexample{The example below demonstrates the `parse()` function with - and without callback function.,parse__string__parser_callback_t} - - @liveexample{The example below demonstrates the `parse()` function with - and without callback function.,parse__istream__parser_callback_t} - - @liveexample{The example below demonstrates the `parse()` function reading - from a contiguous container.,parse__contiguouscontainer__parser_callback_t} - - @since version 2.0.3 (contiguous containers) - */ - static basic_json parse(detail::input_adapter i, - const parser_callback_t cb = nullptr, - const bool allow_exceptions = true) - { - basic_json result; - parser(i, cb, allow_exceptions).parse(true, result); - return result; - } - - /*! - @copydoc basic_json parse(detail::input_adapter, const parser_callback_t) - */ - static basic_json parse(detail::input_adapter& i, - const parser_callback_t cb = nullptr, - const bool allow_exceptions = true) - { - basic_json result; - parser(i, cb, allow_exceptions).parse(true, result); - return result; - } - - static bool accept(detail::input_adapter i) - { - return parser(i).accept(true); - } - - static bool accept(detail::input_adapter& i) - { - return parser(i).accept(true); - } - - /*! - @brief deserialize from an iterator range with contiguous storage - - This function reads from an iterator range of a container with contiguous - storage of 1-byte values. Compatible container types include - `std::vector`, `std::string`, `std::array`, `std::valarray`, and - `std::initializer_list`. Furthermore, C-style arrays can be used with - `std::begin()`/`std::end()`. User-defined containers can be used as long - as they implement random-access iterators and a contiguous storage. - - @pre The iterator range is contiguous. Violating this precondition yields - undefined behavior. **This precondition is enforced with an assertion.** - @pre Each element in the range has a size of 1 byte. Violating this - precondition yields undefined behavior. **This precondition is enforced - with a static assertion.** - - @warning There is no way to enforce all preconditions at compile-time. If - the function is called with noncompliant iterators and with - assertions switched off, the behavior is undefined and will most - likely yield segmentation violation. - - @tparam IteratorType iterator of container with contiguous storage - @param[in] first begin of the range to parse (included) - @param[in] last end of the range to parse (excluded) - @param[in] cb a parser callback function of type @ref parser_callback_t - which is used to control the deserialization by filtering unwanted values - (optional) - @param[in] allow_exceptions whether to throw exceptions in case of a - parse error (optional, true by default) - - @return result of the deserialization - - @throw parse_error.101 in case of an unexpected token - @throw parse_error.102 if to_unicode fails or surrogate error - @throw parse_error.103 if to_unicode fails - - @complexity Linear in the length of the input. The parser is a predictive - LL(1) parser. The complexity can be higher if the parser callback function - @a cb has a super-linear complexity. - - @note A UTF-8 byte order mark is silently ignored. - - @liveexample{The example below demonstrates the `parse()` function reading - from an iterator range.,parse__iteratortype__parser_callback_t} - - @since version 2.0.3 - */ - template::iterator_category>::value, int>::type = 0> - static basic_json parse(IteratorType first, IteratorType last, - const parser_callback_t cb = nullptr, - const bool allow_exceptions = true) - { - basic_json result; - parser(detail::input_adapter(first, last), cb, allow_exceptions).parse(true, result); - return result; - } - - template::iterator_category>::value, int>::type = 0> - static bool accept(IteratorType first, IteratorType last) - { - return parser(detail::input_adapter(first, last)).accept(true); - } - - /*! - @brief deserialize from stream - @deprecated This stream operator is deprecated and will be removed in a - future version of the library. Please use - @ref operator>>(std::istream&, basic_json&) - instead; that is, replace calls like `j << i;` with `i >> j;`. - @since version 1.0.0; deprecated since version 3.0.0 - */ - JSON_DEPRECATED - friend std::istream& operator<<(basic_json& j, std::istream& i) - { - return operator>>(i, j); - } - - /*! - @brief deserialize from stream - - Deserializes an input stream to a JSON value. - - @param[in,out] i input stream to read a serialized JSON value from - @param[in,out] j JSON value to write the deserialized input to - - @throw parse_error.101 in case of an unexpected token - @throw parse_error.102 if to_unicode fails or surrogate error - @throw parse_error.103 if to_unicode fails - - @complexity Linear in the length of the input. The parser is a predictive - LL(1) parser. - - @note A UTF-8 byte order mark is silently ignored. - - @liveexample{The example below shows how a JSON value is constructed by - reading a serialization from a stream.,operator_deserialize} - - @sa parse(std::istream&, const parser_callback_t) for a variant with a - parser callback function to filter values while parsing - - @since version 1.0.0 - */ - friend std::istream& operator>>(std::istream& i, basic_json& j) - { - parser(detail::input_adapter(i)).parse(false, j); - return i; - } - - /// @} - - /////////////////////////// - // convenience functions // - /////////////////////////// - - /*! - @brief return the type as string - - Returns the type name as string to be used in error messages - usually to - indicate that a function was called on a wrong JSON type. - - @return a string representation of a the @a m_type member: - Value type | return value - ----------- | ------------- - null | `"null"` - boolean | `"boolean"` - string | `"string"` - number | `"number"` (for all number types) - object | `"object"` - array | `"array"` - discarded | `"discarded"` - - @exceptionsafety No-throw guarantee: this function never throws exceptions. - - @complexity Constant. - - @liveexample{The following code exemplifies `type_name()` for all JSON - types.,type_name} - - @sa @ref type() -- return the type of the JSON value - @sa @ref operator value_t() -- return the type of the JSON value (implicit) - - @since version 1.0.0, public since 2.1.0, `const char*` and `noexcept` - since 3.0.0 - */ - const char* type_name() const noexcept - { - { - switch (m_type) - { - case value_t::null: - return "null"; - case value_t::object: - return "object"; - case value_t::array: - return "array"; - case value_t::string: - return "string"; - case value_t::boolean: - return "boolean"; - case value_t::discarded: - return "discarded"; - default: - return "number"; - } - } - } - - private: - ////////////////////// - // member variables // - ////////////////////// - - /// the type of the current element - value_t m_type = value_t::null; - - /// the value of the current element - json_value m_value = {}; - - ////////////////////////////////////////// - // binary serialization/deserialization // - ////////////////////////////////////////// - - /// @name binary serialization/deserialization support - /// @{ - - public: - /*! - @brief create a CBOR serialization of a given JSON value - - Serializes a given JSON value @a j to a byte vector using the CBOR (Concise - Binary Object Representation) serialization format. CBOR is a binary - serialization format which aims to be more compact than JSON itself, yet - more efficient to parse. - - The library uses the following mapping from JSON values types to - CBOR types according to the CBOR specification (RFC 7049): - - JSON value type | value/range | CBOR type | first byte - --------------- | ------------------------------------------ | ---------------------------------- | --------------- - null | `null` | Null | 0xF6 - boolean | `true` | True | 0xF5 - boolean | `false` | False | 0xF4 - number_integer | -9223372036854775808..-2147483649 | Negative integer (8 bytes follow) | 0x3B - number_integer | -2147483648..-32769 | Negative integer (4 bytes follow) | 0x3A - number_integer | -32768..-129 | Negative integer (2 bytes follow) | 0x39 - number_integer | -128..-25 | Negative integer (1 byte follow) | 0x38 - number_integer | -24..-1 | Negative integer | 0x20..0x37 - number_integer | 0..23 | Integer | 0x00..0x17 - number_integer | 24..255 | Unsigned integer (1 byte follow) | 0x18 - number_integer | 256..65535 | Unsigned integer (2 bytes follow) | 0x19 - number_integer | 65536..4294967295 | Unsigned integer (4 bytes follow) | 0x1A - number_integer | 4294967296..18446744073709551615 | Unsigned integer (8 bytes follow) | 0x1B - number_unsigned | 0..23 | Integer | 0x00..0x17 - number_unsigned | 24..255 | Unsigned integer (1 byte follow) | 0x18 - number_unsigned | 256..65535 | Unsigned integer (2 bytes follow) | 0x19 - number_unsigned | 65536..4294967295 | Unsigned integer (4 bytes follow) | 0x1A - number_unsigned | 4294967296..18446744073709551615 | Unsigned integer (8 bytes follow) | 0x1B - number_float | *any value* | Double-Precision Float | 0xFB - string | *length*: 0..23 | UTF-8 string | 0x60..0x77 - string | *length*: 23..255 | UTF-8 string (1 byte follow) | 0x78 - string | *length*: 256..65535 | UTF-8 string (2 bytes follow) | 0x79 - string | *length*: 65536..4294967295 | UTF-8 string (4 bytes follow) | 0x7A - string | *length*: 4294967296..18446744073709551615 | UTF-8 string (8 bytes follow) | 0x7B - array | *size*: 0..23 | array | 0x80..0x97 - array | *size*: 23..255 | array (1 byte follow) | 0x98 - array | *size*: 256..65535 | array (2 bytes follow) | 0x99 - array | *size*: 65536..4294967295 | array (4 bytes follow) | 0x9A - array | *size*: 4294967296..18446744073709551615 | array (8 bytes follow) | 0x9B - object | *size*: 0..23 | map | 0xA0..0xB7 - object | *size*: 23..255 | map (1 byte follow) | 0xB8 - object | *size*: 256..65535 | map (2 bytes follow) | 0xB9 - object | *size*: 65536..4294967295 | map (4 bytes follow) | 0xBA - object | *size*: 4294967296..18446744073709551615 | map (8 bytes follow) | 0xBB - - @note The mapping is **complete** in the sense that any JSON value type - can be converted to a CBOR value. - - @note If NaN or Infinity are stored inside a JSON number, they are - serialized properly. This behavior differs from the @ref dump() - function which serializes NaN or Infinity to `null`. - - @note The following CBOR types are not used in the conversion: - - byte strings (0x40..0x5F) - - UTF-8 strings terminated by "break" (0x7F) - - arrays terminated by "break" (0x9F) - - maps terminated by "break" (0xBF) - - date/time (0xC0..0xC1) - - bignum (0xC2..0xC3) - - decimal fraction (0xC4) - - bigfloat (0xC5) - - tagged items (0xC6..0xD4, 0xD8..0xDB) - - expected conversions (0xD5..0xD7) - - simple values (0xE0..0xF3, 0xF8) - - undefined (0xF7) - - half and single-precision floats (0xF9-0xFA) - - break (0xFF) - - @param[in] j JSON value to serialize - @return MessagePack serialization as byte vector - - @complexity Linear in the size of the JSON value @a j. - - @liveexample{The example shows the serialization of a JSON value to a byte - vector in CBOR format.,to_cbor} - - @sa http://cbor.io - @sa @ref from_cbor(const std::vector&, const size_t) for the - analogous deserialization - @sa @ref to_msgpack(const basic_json&) for the related MessagePack format - - @since version 2.0.9 - */ - static std::vector to_cbor(const basic_json& j) - { - std::vector result; - to_cbor(j, result); - return result; - } - - static void to_cbor(const basic_json& j, detail::output_adapter o) - { - binary_writer(o).write_cbor(j); - } - - static void to_cbor(const basic_json& j, detail::output_adapter o) - { - binary_writer(o).write_cbor(j); - } - - /*! - @brief create a MessagePack serialization of a given JSON value - - Serializes a given JSON value @a j to a byte vector using the MessagePack - serialization format. MessagePack is a binary serialization format which - aims to be more compact than JSON itself, yet more efficient to parse. - - The library uses the following mapping from JSON values types to - MessagePack types according to the MessagePack specification: - - JSON value type | value/range | MessagePack type | first byte - --------------- | --------------------------------- | ---------------- | ---------- - null | `null` | nil | 0xC0 - boolean | `true` | true | 0xC3 - boolean | `false` | false | 0xC2 - number_integer | -9223372036854775808..-2147483649 | int64 | 0xD3 - number_integer | -2147483648..-32769 | int32 | 0xD2 - number_integer | -32768..-129 | int16 | 0xD1 - number_integer | -128..-33 | int8 | 0xD0 - number_integer | -32..-1 | negative fixint | 0xE0..0xFF - number_integer | 0..127 | positive fixint | 0x00..0x7F - number_integer | 128..255 | uint 8 | 0xCC - number_integer | 256..65535 | uint 16 | 0xCD - number_integer | 65536..4294967295 | uint 32 | 0xCE - number_integer | 4294967296..18446744073709551615 | uint 64 | 0xCF - number_unsigned | 0..127 | positive fixint | 0x00..0x7F - number_unsigned | 128..255 | uint 8 | 0xCC - number_unsigned | 256..65535 | uint 16 | 0xCD - number_unsigned | 65536..4294967295 | uint 32 | 0xCE - number_unsigned | 4294967296..18446744073709551615 | uint 64 | 0xCF - number_float | *any value* | float 64 | 0xCB - string | *length*: 0..31 | fixstr | 0xA0..0xBF - string | *length*: 32..255 | str 8 | 0xD9 - string | *length*: 256..65535 | str 16 | 0xDA - string | *length*: 65536..4294967295 | str 32 | 0xDB - array | *size*: 0..15 | fixarray | 0x90..0x9F - array | *size*: 16..65535 | array 16 | 0xDC - array | *size*: 65536..4294967295 | array 32 | 0xDD - object | *size*: 0..15 | fix map | 0x80..0x8F - object | *size*: 16..65535 | map 16 | 0xDE - object | *size*: 65536..4294967295 | map 32 | 0xDF - - @note The mapping is **complete** in the sense that any JSON value type - can be converted to a MessagePack value. - - @note The following values can **not** be converted to a MessagePack value: - - strings with more than 4294967295 bytes - - arrays with more than 4294967295 elements - - objects with more than 4294967295 elements - - @note The following MessagePack types are not used in the conversion: - - bin 8 - bin 32 (0xC4..0xC6) - - ext 8 - ext 32 (0xC7..0xC9) - - float 32 (0xCA) - - fixext 1 - fixext 16 (0xD4..0xD8) - - @note Any MessagePack output created @ref to_msgpack can be successfully - parsed by @ref from_msgpack. - - @note If NaN or Infinity are stored inside a JSON number, they are - serialized properly. This behavior differs from the @ref dump() - function which serializes NaN or Infinity to `null`. - - @param[in] j JSON value to serialize - @return MessagePack serialization as byte vector - - @complexity Linear in the size of the JSON value @a j. - - @liveexample{The example shows the serialization of a JSON value to a byte - vector in MessagePack format.,to_msgpack} - - @sa http://msgpack.org - @sa @ref from_msgpack(const std::vector&, const size_t) for the - analogous deserialization - @sa @ref to_cbor(const basic_json& for the related CBOR format - - @since version 2.0.9 - */ - static std::vector to_msgpack(const basic_json& j) - { - std::vector result; - to_msgpack(j, result); - return result; - } - - static void to_msgpack(const basic_json& j, detail::output_adapter o) - { - binary_writer(o).write_msgpack(j); - } - - static void to_msgpack(const basic_json& j, detail::output_adapter o) - { - binary_writer(o).write_msgpack(j); - } - - /*! - @brief create a JSON value from an input in CBOR format - - Deserializes a given input @a i to a JSON value using the CBOR (Concise - Binary Object Representation) serialization format. - - The library maps CBOR types to JSON value types as follows: - - CBOR type | JSON value type | first byte - ---------------------- | --------------- | ---------- - Integer | number_unsigned | 0x00..0x17 - Unsigned integer | number_unsigned | 0x18 - Unsigned integer | number_unsigned | 0x19 - Unsigned integer | number_unsigned | 0x1A - Unsigned integer | number_unsigned | 0x1B - Negative integer | number_integer | 0x20..0x37 - Negative integer | number_integer | 0x38 - Negative integer | number_integer | 0x39 - Negative integer | number_integer | 0x3A - Negative integer | number_integer | 0x3B - Negative integer | number_integer | 0x40..0x57 - UTF-8 string | string | 0x60..0x77 - UTF-8 string | string | 0x78 - UTF-8 string | string | 0x79 - UTF-8 string | string | 0x7A - UTF-8 string | string | 0x7B - UTF-8 string | string | 0x7F - array | array | 0x80..0x97 - array | array | 0x98 - array | array | 0x99 - array | array | 0x9A - array | array | 0x9B - array | array | 0x9F - map | object | 0xA0..0xB7 - map | object | 0xB8 - map | object | 0xB9 - map | object | 0xBA - map | object | 0xBB - map | object | 0xBF - False | `false` | 0xF4 - True | `true` | 0xF5 - Nill | `null` | 0xF6 - Half-Precision Float | number_float | 0xF9 - Single-Precision Float | number_float | 0xFA - Double-Precision Float | number_float | 0xFB - - @warning The mapping is **incomplete** in the sense that not all CBOR - types can be converted to a JSON value. The following CBOR types - are not supported and will yield parse errors (parse_error.112): - - byte strings (0x40..0x5F) - - date/time (0xC0..0xC1) - - bignum (0xC2..0xC3) - - decimal fraction (0xC4) - - bigfloat (0xC5) - - tagged items (0xC6..0xD4, 0xD8..0xDB) - - expected conversions (0xD5..0xD7) - - simple values (0xE0..0xF3, 0xF8) - - undefined (0xF7) - - @warning CBOR allows map keys of any type, whereas JSON only allows - strings as keys in object values. Therefore, CBOR maps with keys - other than UTF-8 strings are rejected (parse_error.113). - - @note Any CBOR output created @ref to_cbor can be successfully parsed by - @ref from_cbor. - - @param[in] i an input in CBOR format convertible to an input adapter - @param[in] strict whether to expect the input to be consumed until EOF - (true by default) - @return deserialized JSON value - - @throw parse_error.110 if the given input ends prematurely or the end of - file was not reached when @a strict was set to true - @throw parse_error.112 if unsupported features from CBOR were - used in the given input @a v or if the input is not valid CBOR - @throw parse_error.113 if a string was expected as map key, but not found - - @complexity Linear in the size of the input @a i. - - @liveexample{The example shows the deserialization of a byte vector in CBOR - format to a JSON value.,from_cbor} - - @sa http://cbor.io - @sa @ref to_cbor(const basic_json&) for the analogous serialization - @sa @ref from_msgpack(detail::input_adapter, const bool) for the - related MessagePack format - - @since version 2.0.9; parameter @a start_index since 2.1.1; changed to - consume input adapters, removed start_index parameter, and added - @a strict parameter since 3.0.0 - */ - static basic_json from_cbor(detail::input_adapter i, - const bool strict = true) - { - return binary_reader(i).parse_cbor(strict); - } - - /*! - @copydoc from_cbor(detail::input_adapter, const bool) - */ - template::value, int> = 0> - static basic_json from_cbor(A1 && a1, A2 && a2, const bool strict = true) - { - return binary_reader(detail::input_adapter(std::forward(a1), std::forward(a2))).parse_cbor(strict); - } - - /*! - @brief create a JSON value from an input in MessagePack format - - Deserializes a given input @a i to a JSON value using the MessagePack - serialization format. - - The library maps MessagePack types to JSON value types as follows: - - MessagePack type | JSON value type | first byte - ---------------- | --------------- | ---------- - positive fixint | number_unsigned | 0x00..0x7F - fixmap | object | 0x80..0x8F - fixarray | array | 0x90..0x9F - fixstr | string | 0xA0..0xBF - nil | `null` | 0xC0 - false | `false` | 0xC2 - true | `true` | 0xC3 - float 32 | number_float | 0xCA - float 64 | number_float | 0xCB - uint 8 | number_unsigned | 0xCC - uint 16 | number_unsigned | 0xCD - uint 32 | number_unsigned | 0xCE - uint 64 | number_unsigned | 0xCF - int 8 | number_integer | 0xD0 - int 16 | number_integer | 0xD1 - int 32 | number_integer | 0xD2 - int 64 | number_integer | 0xD3 - str 8 | string | 0xD9 - str 16 | string | 0xDA - str 32 | string | 0xDB - array 16 | array | 0xDC - array 32 | array | 0xDD - map 16 | object | 0xDE - map 32 | object | 0xDF - negative fixint | number_integer | 0xE0-0xFF - - @warning The mapping is **incomplete** in the sense that not all - MessagePack types can be converted to a JSON value. The following - MessagePack types are not supported and will yield parse errors: - - bin 8 - bin 32 (0xC4..0xC6) - - ext 8 - ext 32 (0xC7..0xC9) - - fixext 1 - fixext 16 (0xD4..0xD8) - - @note Any MessagePack output created @ref to_msgpack can be successfully - parsed by @ref from_msgpack. - - @param[in] i an input in MessagePack format convertible to an input - adapter - @param[in] strict whether to expect the input to be consumed until EOF - (true by default) - - @throw parse_error.110 if the given input ends prematurely or the end of - file was not reached when @a strict was set to true - @throw parse_error.112 if unsupported features from MessagePack were - used in the given input @a i or if the input is not valid MessagePack - @throw parse_error.113 if a string was expected as map key, but not found - - @complexity Linear in the size of the input @a i. - - @liveexample{The example shows the deserialization of a byte vector in - MessagePack format to a JSON value.,from_msgpack} - - @sa http://msgpack.org - @sa @ref to_msgpack(const basic_json&) for the analogous serialization - @sa @ref from_cbor(detail::input_adapter, const bool) for the related CBOR - format - - @since version 2.0.9; parameter @a start_index since 2.1.1; changed to - consume input adapters, removed start_index parameter, and added - @a strict parameter since 3.0.0 - */ - static basic_json from_msgpack(detail::input_adapter i, - const bool strict = true) - { - return binary_reader(i).parse_msgpack(strict); - } - - /*! - @copydoc from_msgpack(detail::input_adapter, const bool) - */ - template::value, int> = 0> - static basic_json from_msgpack(A1 && a1, A2 && a2, const bool strict = true) - { - return binary_reader(detail::input_adapter(std::forward(a1), std::forward(a2))).parse_msgpack(strict); - } - - /// @} - - ////////////////////////// - // JSON Pointer support // - ////////////////////////// - - /// @name JSON Pointer functions - /// @{ - - /*! - @brief access specified element via JSON Pointer - - Uses a JSON pointer to retrieve a reference to the respective JSON value. - No bound checking is performed. Similar to @ref operator[](const typename - object_t::key_type&), `null` values are created in arrays and objects if - necessary. - - In particular: - - If the JSON pointer points to an object key that does not exist, it - is created an filled with a `null` value before a reference to it - is returned. - - If the JSON pointer points to an array index that does not exist, it - is created an filled with a `null` value before a reference to it - is returned. All indices between the current maximum and the given - index are also filled with `null`. - - The special value `-` is treated as a synonym for the index past the - end. - - @param[in] ptr a JSON pointer - - @return reference to the element pointed to by @a ptr - - @complexity Constant. - - @throw parse_error.106 if an array index begins with '0' - @throw parse_error.109 if an array index was not a number - @throw out_of_range.404 if the JSON pointer can not be resolved - - @liveexample{The behavior is shown in the example.,operatorjson_pointer} - - @since version 2.0.0 - */ - reference operator[](const json_pointer& ptr) - { - return ptr.get_unchecked(this); - } - - /*! - @brief access specified element via JSON Pointer - - Uses a JSON pointer to retrieve a reference to the respective JSON value. - No bound checking is performed. The function does not change the JSON - value; no `null` values are created. In particular, the the special value - `-` yields an exception. - - @param[in] ptr JSON pointer to the desired element - - @return const reference to the element pointed to by @a ptr - - @complexity Constant. - - @throw parse_error.106 if an array index begins with '0' - @throw parse_error.109 if an array index was not a number - @throw out_of_range.402 if the array index '-' is used - @throw out_of_range.404 if the JSON pointer can not be resolved - - @liveexample{The behavior is shown in the example.,operatorjson_pointer_const} - - @since version 2.0.0 - */ - const_reference operator[](const json_pointer& ptr) const - { - return ptr.get_unchecked(this); - } - - /*! - @brief access specified element via JSON Pointer - - Returns a reference to the element at with specified JSON pointer @a ptr, - with bounds checking. - - @param[in] ptr JSON pointer to the desired element - - @return reference to the element pointed to by @a ptr - - @throw parse_error.106 if an array index in the passed JSON pointer @a ptr - begins with '0'. See example below. - - @throw parse_error.109 if an array index in the passed JSON pointer @a ptr - is not a number. See example below. - - @throw out_of_range.401 if an array index in the passed JSON pointer @a ptr - is out of range. See example below. - - @throw out_of_range.402 if the array index '-' is used in the passed JSON - pointer @a ptr. As `at` provides checked access (and no elements are - implicitly inserted), the index '-' is always invalid. See example below. - - @throw out_of_range.403 if the JSON pointer describes a key of an object - which cannot be found. See example below. - - @throw out_of_range.404 if the JSON pointer @a ptr can not be resolved. - See example below. - - @exceptionsafety Strong guarantee: if an exception is thrown, there are no - changes in the JSON value. - - @complexity Constant. - - @since version 2.0.0 - - @liveexample{The behavior is shown in the example.,at_json_pointer} - */ - reference at(const json_pointer& ptr) - { - return ptr.get_checked(this); - } - - /*! - @brief access specified element via JSON Pointer - - Returns a const reference to the element at with specified JSON pointer @a - ptr, with bounds checking. - - @param[in] ptr JSON pointer to the desired element - - @return reference to the element pointed to by @a ptr - - @throw parse_error.106 if an array index in the passed JSON pointer @a ptr - begins with '0'. See example below. - - @throw parse_error.109 if an array index in the passed JSON pointer @a ptr - is not a number. See example below. - - @throw out_of_range.401 if an array index in the passed JSON pointer @a ptr - is out of range. See example below. - - @throw out_of_range.402 if the array index '-' is used in the passed JSON - pointer @a ptr. As `at` provides checked access (and no elements are - implicitly inserted), the index '-' is always invalid. See example below. - - @throw out_of_range.403 if the JSON pointer describes a key of an object - which cannot be found. See example below. - - @throw out_of_range.404 if the JSON pointer @a ptr can not be resolved. - See example below. - - @exceptionsafety Strong guarantee: if an exception is thrown, there are no - changes in the JSON value. - - @complexity Constant. - - @since version 2.0.0 - - @liveexample{The behavior is shown in the example.,at_json_pointer_const} - */ - const_reference at(const json_pointer& ptr) const - { - return ptr.get_checked(this); - } - - /*! - @brief return flattened JSON value - - The function creates a JSON object whose keys are JSON pointers (see [RFC - 6901](https://tools.ietf.org/html/rfc6901)) and whose values are all - primitive. The original JSON value can be restored using the @ref - unflatten() function. - - @return an object that maps JSON pointers to primitive values - - @note Empty objects and arrays are flattened to `null` and will not be - reconstructed correctly by the @ref unflatten() function. - - @complexity Linear in the size the JSON value. - - @liveexample{The following code shows how a JSON object is flattened to an - object whose keys consist of JSON pointers.,flatten} - - @sa @ref unflatten() for the reverse function - - @since version 2.0.0 - */ - basic_json flatten() const - { - basic_json result(value_t::object); - json_pointer::flatten("", *this, result); - return result; - } - - /*! - @brief unflatten a previously flattened JSON value - - The function restores the arbitrary nesting of a JSON value that has been - flattened before using the @ref flatten() function. The JSON value must - meet certain constraints: - 1. The value must be an object. - 2. The keys must be JSON pointers (see - [RFC 6901](https://tools.ietf.org/html/rfc6901)) - 3. The mapped values must be primitive JSON types. - - @return the original JSON from a flattened version - - @note Empty objects and arrays are flattened by @ref flatten() to `null` - values and can not unflattened to their original type. Apart from - this example, for a JSON value `j`, the following is always true: - `j == j.flatten().unflatten()`. - - @complexity Linear in the size the JSON value. - - @throw type_error.314 if value is not an object - @throw type_error.315 if object values are not primitive - - @liveexample{The following code shows how a flattened JSON object is - unflattened into the original nested JSON object.,unflatten} - - @sa @ref flatten() for the reverse function - - @since version 2.0.0 - */ - basic_json unflatten() const - { - return json_pointer::unflatten(*this); - } - - /// @} - - ////////////////////////// - // JSON Patch functions // - ////////////////////////// - - /// @name JSON Patch functions - /// @{ - - /*! - @brief applies a JSON patch - - [JSON Patch](http://jsonpatch.com) defines a JSON document structure for - expressing a sequence of operations to apply to a JSON) document. With - this function, a JSON Patch is applied to the current JSON value by - executing all operations from the patch. - - @param[in] json_patch JSON patch document - @return patched document - - @note The application of a patch is atomic: Either all operations succeed - and the patched document is returned or an exception is thrown. In - any case, the original value is not changed: the patch is applied - to a copy of the value. - - @throw parse_error.104 if the JSON patch does not consist of an array of - objects - - @throw parse_error.105 if the JSON patch is malformed (e.g., mandatory - attributes are missing); example: `"operation add must have member path"` - - @throw out_of_range.401 if an array index is out of range. - - @throw out_of_range.403 if a JSON pointer inside the patch could not be - resolved successfully in the current JSON value; example: `"key baz not - found"` - - @throw out_of_range.405 if JSON pointer has no parent ("add", "remove", - "move") - - @throw other_error.501 if "test" operation was unsuccessful - - @complexity Linear in the size of the JSON value and the length of the - JSON patch. As usually only a fraction of the JSON value is affected by - the patch, the complexity can usually be neglected. - - @liveexample{The following code shows how a JSON patch is applied to a - value.,patch} - - @sa @ref diff -- create a JSON patch by comparing two JSON values - - @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902) - @sa [RFC 6901 (JSON Pointer)](https://tools.ietf.org/html/rfc6901) - - @since version 2.0.0 - */ - basic_json patch(const basic_json& json_patch) const - { - // make a working copy to apply the patch to - basic_json result = *this; - - // the valid JSON Patch operations - enum class patch_operations {add, remove, replace, move, copy, test, invalid}; - - const auto get_op = [](const std::string & op) - { - if (op == "add") - { - return patch_operations::add; - } - if (op == "remove") - { - return patch_operations::remove; - } - if (op == "replace") - { - return patch_operations::replace; - } - if (op == "move") - { - return patch_operations::move; - } - if (op == "copy") - { - return patch_operations::copy; - } - if (op == "test") - { - return patch_operations::test; - } - - return patch_operations::invalid; - }; - - // wrapper for "add" operation; add value at ptr - const auto operation_add = [&result](json_pointer & ptr, basic_json val) - { - // adding to the root of the target document means replacing it - if (ptr.is_root()) - { - result = val; - } - else - { - // make sure the top element of the pointer exists - json_pointer top_pointer = ptr.top(); - if (top_pointer != ptr) - { - result.at(top_pointer); - } - - // get reference to parent of JSON pointer ptr - const auto last_path = ptr.pop_back(); - basic_json& parent = result[ptr]; - - switch (parent.m_type) - { - case value_t::null: - case value_t::object: - { - // use operator[] to add value - parent[last_path] = val; - break; - } - - case value_t::array: - { - if (last_path == "-") - { - // special case: append to back - parent.push_back(val); - } - else - { - const auto idx = json_pointer::array_index(last_path); - if (JSON_UNLIKELY(static_cast(idx) > parent.size())) - { - // avoid undefined behavior - JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range")); - } - else - { - // default case: insert add offset - parent.insert(parent.begin() + static_cast(idx), val); - } - } - break; - } - - default: - { - // if there exists a parent it cannot be primitive - assert(false); // LCOV_EXCL_LINE - } - } - } - }; - - // wrapper for "remove" operation; remove value at ptr - const auto operation_remove = [&result](json_pointer & ptr) - { - // get reference to parent of JSON pointer ptr - const auto last_path = ptr.pop_back(); - basic_json& parent = result.at(ptr); - - // remove child - if (parent.is_object()) - { - // perform range check - auto it = parent.find(last_path); - if (JSON_LIKELY(it != parent.end())) - { - parent.erase(it); - } - else - { - JSON_THROW(out_of_range::create(403, "key '" + last_path + "' not found")); - } - } - else if (parent.is_array()) - { - // note erase performs range check - parent.erase(static_cast(json_pointer::array_index(last_path))); - } - }; - - // type check: top level value must be an array - if (JSON_UNLIKELY(not json_patch.is_array())) - { - JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects")); - } - - // iterate and apply the operations - for (const auto& val : json_patch) - { - // wrapper to get a value for an operation - const auto get_value = [&val](const std::string & op, - const std::string & member, - bool string_type) -> basic_json& - { - // find value - auto it = val.m_value.object->find(member); - - // context-sensitive error message - const auto error_msg = (op == "op") ? "operation" : "operation '" + op + "'"; - - // check if desired value is present - if (JSON_UNLIKELY(it == val.m_value.object->end())) - { - JSON_THROW(parse_error::create(105, 0, error_msg + " must have member '" + member + "'")); - } - - // check if result is of type string - if (JSON_UNLIKELY(string_type and not it->second.is_string())) - { - JSON_THROW(parse_error::create(105, 0, error_msg + " must have string member '" + member + "'")); - } - - // no error: return value - return it->second; - }; - - // type check: every element of the array must be an object - if (JSON_UNLIKELY(not val.is_object())) - { - JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects")); - } - - // collect mandatory members - const std::string op = get_value("op", "op", true); - const std::string path = get_value(op, "path", true); - json_pointer ptr(path); - - switch (get_op(op)) - { - case patch_operations::add: - { - operation_add(ptr, get_value("add", "value", false)); - break; - } - - case patch_operations::remove: - { - operation_remove(ptr); - break; - } - - case patch_operations::replace: - { - // the "path" location must exist - use at() - result.at(ptr) = get_value("replace", "value", false); - break; - } - - case patch_operations::move: - { - const std::string from_path = get_value("move", "from", true); - json_pointer from_ptr(from_path); - - // the "from" location must exist - use at() - basic_json v = result.at(from_ptr); - - // The move operation is functionally identical to a - // "remove" operation on the "from" location, followed - // immediately by an "add" operation at the target - // location with the value that was just removed. - operation_remove(from_ptr); - operation_add(ptr, v); - break; - } - - case patch_operations::copy: - { - const std::string from_path = get_value("copy", "from", true); - const json_pointer from_ptr(from_path); - - // the "from" location must exist - use at() - basic_json v = result.at(from_ptr); - - // The copy is functionally identical to an "add" - // operation at the target location using the value - // specified in the "from" member. - operation_add(ptr, v); - break; - } - - case patch_operations::test: - { - bool success = false; - 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)); - } - JSON_CATCH (out_of_range&) - { - // ignore out of range errors: success remains false - } - - // throw an exception if test fails - if (JSON_UNLIKELY(not success)) - { - JSON_THROW(other_error::create(501, "unsuccessful: " + val.dump())); - } - - break; - } - - case patch_operations::invalid: - { - // op must be "add", "remove", "replace", "move", "copy", or - // "test" - JSON_THROW(parse_error::create(105, 0, "operation value '" + op + "' is invalid")); - } - } - } - - return result; - } - - /*! - @brief creates a diff as a JSON patch - - Creates a [JSON Patch](http://jsonpatch.com) so that value @a source can - be changed into the value @a target by calling @ref patch function. - - @invariant For two JSON values @a source and @a target, the following code - yields always `true`: - @code {.cpp} - source.patch(diff(source, target)) == target; - @endcode - - @note Currently, only `remove`, `add`, and `replace` operations are - generated. - - @param[in] source JSON value to compare from - @param[in] target JSON value to compare against - @param[in] path helper value to create JSON pointers - - @return a JSON patch to convert the @a source to @a target - - @complexity Linear in the lengths of @a source and @a target. - - @liveexample{The following code shows how a JSON patch is created as a - diff for two JSON values.,diff} - - @sa @ref patch -- apply a JSON patch - - @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902) - - @since version 2.0.0 - */ - static basic_json diff(const basic_json& source, const basic_json& target, - const std::string& path = "") - { - // the patch - basic_json result(value_t::array); - - // if the values are the same, return empty patch - if (source == target) - { - return result; - } - - if (source.type() != target.type()) - { - // different types: replace value - result.push_back( - { - {"op", "replace"}, {"path", path}, {"value", target} - }); - } - else - { - switch (source.type()) - { - case value_t::array: - { - // first pass: traverse common elements - std::size_t i = 0; - while (i < source.size() and i < target.size()) - { - // recursive call to compare array values at index i - auto temp_diff = diff(source[i], target[i], path + "/" + std::to_string(i)); - result.insert(result.end(), temp_diff.begin(), temp_diff.end()); - ++i; - } - - // i now reached the end of at least one array - // in a second pass, traverse the remaining elements - - // remove my remaining elements - const auto end_index = static_cast(result.size()); - while (i < source.size()) - { - // add operations in reverse order to avoid invalid - // indices - result.insert(result.begin() + end_index, object( - { - {"op", "remove"}, - {"path", path + "/" + std::to_string(i)} - })); - ++i; - } - - // add other remaining elements - while (i < target.size()) - { - result.push_back( - { - {"op", "add"}, - {"path", path + "/" + std::to_string(i)}, - {"value", target[i]} - }); - ++i; - } - - break; - } - - case value_t::object: - { - // first pass: traverse this object's elements - for (auto it = source.cbegin(); it != source.cend(); ++it) - { - // escape the key name to be used in a JSON patch - const auto key = json_pointer::escape(it.key()); - - if (target.find(it.key()) != target.end()) - { - // recursive call to compare object values at key it - auto temp_diff = diff(it.value(), target[it.key()], path + "/" + key); - result.insert(result.end(), temp_diff.begin(), temp_diff.end()); - } - else - { - // found a key that is not in o -> remove it - result.push_back(object( - { - {"op", "remove"}, {"path", path + "/" + key} - })); - } - } - - // second pass: traverse other object's elements - for (auto it = target.cbegin(); it != target.cend(); ++it) - { - if (source.find(it.key()) == source.end()) - { - // found a key that is not in this -> add it - const auto key = json_pointer::escape(it.key()); - result.push_back( - { - {"op", "add"}, {"path", path + "/" + key}, - {"value", it.value()} - }); - } - } - - break; - } - - default: - { - // both primitive type: replace value - result.push_back( - { - {"op", "replace"}, {"path", path}, {"value", target} - }); - break; - } - } - } - - return result; - } - - /// @} -}; - -////////////////// -// json_pointer // -////////////////// - -NLOHMANN_BASIC_JSON_TPL_DECLARATION -NLOHMANN_BASIC_JSON_TPL& -json_pointer::get_and_create(NLOHMANN_BASIC_JSON_TPL& j) const -{ - using size_type = typename NLOHMANN_BASIC_JSON_TPL::size_type; - auto result = &j; - - // in case no reference tokens exist, return a reference to the JSON value - // j which will be overwritten by a primitive value - for (const auto& reference_token : reference_tokens) - { - switch (result->m_type) - { - case detail::value_t::null: - { - if (reference_token == "0") - { - // start a new array if reference token is 0 - result = &result->operator[](0); - } - else - { - // start a new object otherwise - result = &result->operator[](reference_token); - } - break; - } - - case detail::value_t::object: - { - // create an entry in the object - result = &result->operator[](reference_token); - break; - } - - case detail::value_t::array: - { - // create an entry in the array - JSON_TRY - { - result = &result->operator[](static_cast(array_index(reference_token))); - } - JSON_CATCH(std::invalid_argument&) - { - JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number")); - } - break; - } - - /* - The following code is only reached if there exists a reference - token _and_ the current value is primitive. In this case, we have - an error situation, because primitive values may only occur as - single value; that is, with an empty list of reference tokens. - */ - default: - JSON_THROW(detail::type_error::create(313, "invalid value to unflatten")); - } - } - - return *result; -} - -NLOHMANN_BASIC_JSON_TPL_DECLARATION -NLOHMANN_BASIC_JSON_TPL& -json_pointer::get_unchecked(NLOHMANN_BASIC_JSON_TPL* ptr) const -{ - using size_type = typename NLOHMANN_BASIC_JSON_TPL::size_type; - for (const auto& reference_token : reference_tokens) - { - // convert null values to arrays or objects before continuing - if (ptr->m_type == detail::value_t::null) - { - // check if reference token is a number - const bool nums = - std::all_of(reference_token.begin(), reference_token.end(), - [](const char x) - { - return (x >= '0' and x <= '9'); - }); - - // change value to array for numbers or "-" or to object otherwise - *ptr = (nums or reference_token == "-") - ? detail::value_t::array - : detail::value_t::object; - } - - switch (ptr->m_type) - { - case detail::value_t::object: - { - // use unchecked object access - ptr = &ptr->operator[](reference_token); - break; - } - - case detail::value_t::array: - { - // error condition (cf. RFC 6901, Sect. 4) - if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0')) - { - JSON_THROW(detail::parse_error::create(106, 0, - "array index '" + reference_token + - "' must not begin with '0'")); - } - - if (reference_token == "-") - { - // explicitly treat "-" as index beyond the end - ptr = &ptr->operator[](ptr->m_value.array->size()); - } - else - { - // convert array index to number; unchecked access - JSON_TRY - { - ptr = &ptr->operator[]( - static_cast(array_index(reference_token))); - } - JSON_CATCH(std::invalid_argument&) - { - JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number")); - } - } - break; - } - - default: - JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'")); - } - } - - return *ptr; -} - -NLOHMANN_BASIC_JSON_TPL_DECLARATION -NLOHMANN_BASIC_JSON_TPL& -json_pointer::get_checked(NLOHMANN_BASIC_JSON_TPL* ptr) const -{ - using size_type = typename NLOHMANN_BASIC_JSON_TPL::size_type; - for (const auto& reference_token : reference_tokens) - { - switch (ptr->m_type) - { - case detail::value_t::object: - { - // note: at performs range check - ptr = &ptr->at(reference_token); - break; - } - - case detail::value_t::array: - { - if (JSON_UNLIKELY(reference_token == "-")) - { - // "-" always fails the range check - JSON_THROW(detail::out_of_range::create(402, - "array index '-' (" + std::to_string(ptr->m_value.array->size()) + - ") is out of range")); - } - - // error condition (cf. RFC 6901, Sect. 4) - if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0')) - { - JSON_THROW(detail::parse_error::create(106, 0, - "array index '" + reference_token + - "' must not begin with '0'")); - } - - // note: at performs range check - JSON_TRY - { - ptr = &ptr->at(static_cast(array_index(reference_token))); - } - JSON_CATCH(std::invalid_argument&) - { - JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number")); - } - break; - } - - default: - JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'")); - } - } - - return *ptr; -} - -NLOHMANN_BASIC_JSON_TPL_DECLARATION -const NLOHMANN_BASIC_JSON_TPL& -json_pointer::get_unchecked(const NLOHMANN_BASIC_JSON_TPL* ptr) const -{ - using size_type = typename NLOHMANN_BASIC_JSON_TPL::size_type; - for (const auto& reference_token : reference_tokens) - { - switch (ptr->m_type) - { - case detail::value_t::object: - { - // use unchecked object access - ptr = &ptr->operator[](reference_token); - break; - } - - case detail::value_t::array: - { - if (JSON_UNLIKELY(reference_token == "-")) - { - // "-" cannot be used for const access - JSON_THROW(detail::out_of_range::create(402, - "array index '-' (" + std::to_string(ptr->m_value.array->size()) + - ") is out of range")); - } - - // error condition (cf. RFC 6901, Sect. 4) - if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0')) - { - JSON_THROW(detail::parse_error::create(106, 0, - "array index '" + reference_token + - "' must not begin with '0'")); - } - - // use unchecked array access - JSON_TRY - { - ptr = &ptr->operator[]( - static_cast(array_index(reference_token))); - } - JSON_CATCH(std::invalid_argument&) - { - JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number")); - } - break; - } - - default: - JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'")); - } - } - - return *ptr; -} - -NLOHMANN_BASIC_JSON_TPL_DECLARATION -const NLOHMANN_BASIC_JSON_TPL& -json_pointer::get_checked(const NLOHMANN_BASIC_JSON_TPL* ptr) const -{ - using size_type = typename NLOHMANN_BASIC_JSON_TPL::size_type; - for (const auto& reference_token : reference_tokens) - { - switch (ptr->m_type) - { - case detail::value_t::object: - { - // note: at performs range check - ptr = &ptr->at(reference_token); - break; - } - - case detail::value_t::array: - { - if (JSON_UNLIKELY(reference_token == "-")) - { - // "-" always fails the range check - JSON_THROW(detail::out_of_range::create(402, - "array index '-' (" + std::to_string(ptr->m_value.array->size()) + - ") is out of range")); - } - - // error condition (cf. RFC 6901, Sect. 4) - if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0')) - { - JSON_THROW(detail::parse_error::create(106, 0, - "array index '" + reference_token + - "' must not begin with '0'")); - } - - // note: at performs range check - JSON_TRY - { - ptr = &ptr->at(static_cast(array_index(reference_token))); - } - JSON_CATCH(std::invalid_argument&) - { - JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number")); - } - break; - } - - default: - JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'")); - } - } - - return *ptr; -} - -NLOHMANN_BASIC_JSON_TPL_DECLARATION -void json_pointer::flatten(const std::string& reference_string, - const NLOHMANN_BASIC_JSON_TPL& value, - NLOHMANN_BASIC_JSON_TPL& result) -{ - switch (value.m_type) - { - case detail::value_t::array: - { - if (value.m_value.array->empty()) - { - // flatten empty array as null - result[reference_string] = nullptr; - } - else - { - // iterate array and use index as reference string - for (std::size_t i = 0; i < value.m_value.array->size(); ++i) - { - flatten(reference_string + "/" + std::to_string(i), - value.m_value.array->operator[](i), result); - } - } - break; - } - - case detail::value_t::object: - { - if (value.m_value.object->empty()) - { - // flatten empty object as null - result[reference_string] = nullptr; - } - else - { - // iterate object and use keys as reference string - for (const auto& element : *value.m_value.object) - { - flatten(reference_string + "/" + escape(element.first), element.second, result); - } - } - break; - } - - default: - { - // add primitive value with its reference string - result[reference_string] = value; - break; - } - } -} - -NLOHMANN_BASIC_JSON_TPL_DECLARATION -NLOHMANN_BASIC_JSON_TPL -json_pointer::unflatten(const NLOHMANN_BASIC_JSON_TPL& value) -{ - if (JSON_UNLIKELY(not value.is_object())) - { - JSON_THROW(detail::type_error::create(314, "only objects can be unflattened")); - } - - NLOHMANN_BASIC_JSON_TPL result; - - // iterate the JSON object values - for (const auto& element : *value.m_value.object) - { - if (JSON_UNLIKELY(not element.second.is_primitive())) - { - JSON_THROW(detail::type_error::create(315, "values in object must be primitive")); - } - - // assign value to reference pointed to by JSON pointer; Note that if - // the JSON pointer is "" (i.e., points to the whole value), function - // get_and_create returns a reference to result itself. An assignment - // will then create a primitive value. - json_pointer(element.first).get_and_create(result) = element.second; - } - - return result; -} - -inline bool operator==(json_pointer const& lhs, json_pointer const& rhs) noexcept -{ - return (lhs.reference_tokens == rhs.reference_tokens); -} - -inline bool operator!=(json_pointer const& lhs, json_pointer const& rhs) noexcept -{ - return not (lhs == rhs); -} -} // namespace nlohmann - -/////////////////////// -// nonmember support // -/////////////////////// - -// specialization of std::swap, and std::hash -namespace std -{ -/*! -@brief exchanges the values of two JSON objects - -@since version 1.0.0 -*/ -template<> -inline void swap(nlohmann::json& j1, - nlohmann::json& j2) noexcept( - is_nothrow_move_constructible::value and - is_nothrow_move_assignable::value - ) -{ - j1.swap(j2); -} - -/// hash value for JSON objects -template<> -struct hash -{ - /*! - @brief return a hash value for a JSON object - - @since version 1.0.0 - */ - std::size_t operator()(const nlohmann::json& j) const - { - // a naive hashing via the string representation - const auto& h = hash(); - return h(j.dump()); - } -}; - -/// specialization for std::less -/// @note: do not remove the space after '<', -/// see https://github.com/nlohmann/json/pull/679 -template<> -struct less< ::nlohmann::detail::value_t> -{ - /*! - @brief compare two value_t enum values - @since version 3.0.0 - */ - bool operator()(nlohmann::detail::value_t lhs, - nlohmann::detail::value_t rhs) const noexcept - { - return nlohmann::detail::operator<(lhs, rhs); - } -}; - -} // namespace std - -/*! -@brief user-defined string literal for JSON values - -This operator implements a user-defined string literal for JSON objects. It -can be used by adding `"_json"` to a string literal and returns a JSON object -if no parse error occurred. - -@param[in] s a string representation of a JSON object -@param[in] n the length of string @a s -@return a JSON object - -@since version 1.0.0 -*/ -inline nlohmann::json operator "" _json(const char* s, std::size_t n) -{ - return nlohmann::json::parse(s, s + n); -} - -/*! -@brief user-defined string literal for JSON pointer - -This operator implements a user-defined string literal for JSON Pointers. It -can be used by adding `"_json_pointer"` to a string literal and returns a JSON pointer -object if no parse error occurred. - -@param[in] s a string representation of a JSON Pointer -@param[in] n the length of string @a s -@return a JSON pointer object - -@since version 2.0.0 -*/ -inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std::size_t n) -{ - return nlohmann::json::json_pointer(std::string(s, n)); -} - - -/*** Start of inlined file: macro_unscope.hpp ***/ -#ifndef NLOHMANN_JSON_DETAIL_MACRO_UNSCOPE_HPP -#define NLOHMANN_JSON_DETAIL_MACRO_UNSCOPE_HPP - -// restore GCC/clang diagnostic settings -#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) - #pragma GCC diagnostic pop -#endif -#if defined(__clang__) - #pragma GCC diagnostic pop -#endif - -// clean up -#undef JSON_CATCH -#undef JSON_THROW -#undef JSON_TRY -#undef JSON_LIKELY -#undef JSON_UNLIKELY -#undef JSON_DEPRECATED -#undef JSON_HAS_CPP_14 -#undef JSON_HAS_CPP_17 -#undef NLOHMANN_BASIC_JSON_TPL_DECLARATION -#undef NLOHMANN_BASIC_JSON_TPL -#undef NLOHMANN_JSON_HAS_HELPER - -#endif - -/*** End of inlined file: macro_unscope.hpp ***/ - -#endif - diff --git a/src/json.hpp b/src/json.hpp index f4c139e4..00b10675 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -41,27 +41,11115 @@ SOFTWARE. #include // string, stoi, to_string #include // declval, forward, move, pair, swap -#include "json_fwd.hpp" -#include "detail/macro_scope.hpp" -#include "detail/meta.hpp" -#include "detail/exceptions.hpp" -#include "detail/value_t.hpp" -#include "detail/conversions/from_json.hpp" -#include "detail/conversions/to_json.hpp" -#include "detail/parsing/input_adapters.hpp" -#include "detail/parsing/lexer.hpp" -#include "detail/parsing/parser.hpp" -#include "detail/iterators/primitive_iterator.hpp" -#include "detail/iterators/internal_iterator.hpp" -#include "detail/iterators/iter_impl.hpp" -#include "detail/iterators/iteration_proxy.hpp" -#include "detail/iterators/json_reverse_iterator.hpp" -#include "detail/parsing/output_adapters.hpp" -#include "detail/parsing/binary_reader.hpp" -#include "detail/parsing/binary_writer.hpp" -#include "detail/serializer.hpp" -#include "detail/json_ref.hpp" -#include "adl_serializer.hpp" + +/*** Start of inlined file: json_fwd.hpp ***/ +#ifndef NLOHMANN_JSON_FWD_HPP +#define NLOHMANN_JSON_FWD_HPP + +#include // int64_t, uint64_t +#include // map +#include // allocator +#include // string +#include // vector + +/*! +@brief namespace for Niels Lohmann +@see https://github.com/nlohmann +@since version 1.0.0 +*/ +namespace nlohmann +{ +/*! +@brief default JSONSerializer template argument + +This serializer ignores the template arguments and uses ADL +([argument-dependent lookup](http://en.cppreference.com/w/cpp/language/adl)) +for serialization. +*/ +template +struct adl_serializer; + +template class ObjectType = + std::map, + template class ArrayType = std::vector, + class StringType = std::string, class BooleanType = bool, + class NumberIntegerType = std::int64_t, + class NumberUnsignedType = std::uint64_t, + class NumberFloatType = double, + template class AllocatorType = std::allocator, + template class JSONSerializer = + adl_serializer> +class basic_json; + +/*! +@brief JSON Pointer + +A JSON pointer defines a string syntax for identifying a specific value +within a JSON document. It can be used with functions `at` and +`operator[]`. Furthermore, JSON pointers are the base for JSON patches. + +@sa [RFC 6901](https://tools.ietf.org/html/rfc6901) + +@since version 2.0.0 +*/ +class json_pointer; + +/*! +@brief default JSON class + +This type is the default specialization of the @ref basic_json class which +uses the standard template types. + +@since version 1.0.0 +*/ +using json = basic_json<>; +} + +#endif + +/*** End of inlined file: json_fwd.hpp ***/ + + +/*** Start of inlined file: macro_scope.hpp ***/ +#ifndef NLOHMANN_JSON_MACRO_SCOPE_HPP +#define NLOHMANN_JSON_MACRO_SCOPE_HPP + +#include // not + +// This file contains all internal macro definitions +// You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them + +// exclude unsupported compilers +#if defined(__clang__) + #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400 + #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" + #endif +#elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER)) + #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40900 + #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" + #endif +#endif + +// disable float-equal warnings on GCC/clang +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wfloat-equal" +#endif + +// disable documentation warnings on clang +#if defined(__clang__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wdocumentation" +#endif + +// allow for portable deprecation warnings +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #define JSON_DEPRECATED __attribute__((deprecated)) +#elif defined(_MSC_VER) + #define JSON_DEPRECATED __declspec(deprecated) +#else + #define JSON_DEPRECATED +#endif + +// allow to disable exceptions +#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && not defined(JSON_NOEXCEPTION) + #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 + +// manual branch prediction +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #define JSON_LIKELY(x) __builtin_expect(!!(x), 1) + #define JSON_UNLIKELY(x) __builtin_expect(!!(x), 0) +#else + #define JSON_LIKELY(x) x + #define JSON_UNLIKELY(x) x +#endif + +// C++ language standard detection +#if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 + #define JSON_HAS_CPP_17 + #define JSON_HAS_CPP_14 +#elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) + #define JSON_HAS_CPP_14 +#endif + +// Ugly macros to avoid uglier copy-paste when specializing basic_json. They +// may be removed in the future once the class is split. + +#define NLOHMANN_BASIC_JSON_TPL_DECLARATION \ + template class ObjectType, \ + template class ArrayType, \ + class StringType, class BooleanType, class NumberIntegerType, \ + class NumberUnsignedType, class NumberFloatType, \ + template class AllocatorType, \ + template class JSONSerializer> + +#define NLOHMANN_BASIC_JSON_TPL \ + basic_json + +/*! +@brief Helper to determine whether there's a key_type for T. + +This helper is used to tell associative containers apart from other containers +such as sequence containers. For instance, `std::map` passes the test as it +contains a `mapped_type`, whereas `std::vector` fails the test. + +@sa http://stackoverflow.com/a/7728728/266378 +@since version 1.0.0, overworked in version 2.0.6 +*/ +#define NLOHMANN_JSON_HAS_HELPER(type) \ + template struct has_##type { \ + private: \ + template \ + static int detect(U &&); \ + static void detect(...); \ + public: \ + static constexpr bool value = \ + std::is_integral()))>::value; \ + } + +#endif + +/*** End of inlined file: macro_scope.hpp ***/ + + +/*** Start of inlined file: meta.hpp ***/ +#ifndef NLOHMANN_JSON_DETAIL_META_HPP +#define NLOHMANN_JSON_DETAIL_META_HPP + +#include // not +#include // size_t +#include // numeric_limits +#include // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type +#include // declval + + +/*** Start of inlined file: json_fwd.hpp ***/ +#ifndef NLOHMANN_JSON_FWD_HPP +#define NLOHMANN_JSON_FWD_HPP + +#include // int64_t, uint64_t +#include // map +#include // allocator +#include // string +#include // vector + +/*! +@brief namespace for Niels Lohmann +@see https://github.com/nlohmann +@since version 1.0.0 +*/ +namespace nlohmann +{ +/*! +@brief default JSONSerializer template argument + +This serializer ignores the template arguments and uses ADL +([argument-dependent lookup](http://en.cppreference.com/w/cpp/language/adl)) +for serialization. +*/ +template +struct adl_serializer; + +template class ObjectType = + std::map, + template class ArrayType = std::vector, + class StringType = std::string, class BooleanType = bool, + class NumberIntegerType = std::int64_t, + class NumberUnsignedType = std::uint64_t, + class NumberFloatType = double, + template class AllocatorType = std::allocator, + template class JSONSerializer = + adl_serializer> +class basic_json; + +/*! +@brief JSON Pointer + +A JSON pointer defines a string syntax for identifying a specific value +within a JSON document. It can be used with functions `at` and +`operator[]`. Furthermore, JSON pointers are the base for JSON patches. + +@sa [RFC 6901](https://tools.ietf.org/html/rfc6901) + +@since version 2.0.0 +*/ +class json_pointer; + +/*! +@brief default JSON class + +This type is the default specialization of the @ref basic_json class which +uses the standard template types. + +@since version 1.0.0 +*/ +using json = basic_json<>; +} + +#endif + +/*** End of inlined file: json_fwd.hpp ***/ + + +/*** Start of inlined file: macro_scope.hpp ***/ +#ifndef NLOHMANN_JSON_MACRO_SCOPE_HPP +#define NLOHMANN_JSON_MACRO_SCOPE_HPP + +#include // not + +// This file contains all internal macro definitions +// You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them + +// exclude unsupported compilers +#if defined(__clang__) + #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400 + #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" + #endif +#elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER)) + #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40900 + #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" + #endif +#endif + +// disable float-equal warnings on GCC/clang +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wfloat-equal" +#endif + +// disable documentation warnings on clang +#if defined(__clang__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wdocumentation" +#endif + +// allow for portable deprecation warnings +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #define JSON_DEPRECATED __attribute__((deprecated)) +#elif defined(_MSC_VER) + #define JSON_DEPRECATED __declspec(deprecated) +#else + #define JSON_DEPRECATED +#endif + +// allow to disable exceptions +#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && not defined(JSON_NOEXCEPTION) + #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 + +// manual branch prediction +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #define JSON_LIKELY(x) __builtin_expect(!!(x), 1) + #define JSON_UNLIKELY(x) __builtin_expect(!!(x), 0) +#else + #define JSON_LIKELY(x) x + #define JSON_UNLIKELY(x) x +#endif + +// C++ language standard detection +#if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 + #define JSON_HAS_CPP_17 + #define JSON_HAS_CPP_14 +#elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) + #define JSON_HAS_CPP_14 +#endif + +// Ugly macros to avoid uglier copy-paste when specializing basic_json. They +// may be removed in the future once the class is split. + +#define NLOHMANN_BASIC_JSON_TPL_DECLARATION \ + template class ObjectType, \ + template class ArrayType, \ + class StringType, class BooleanType, class NumberIntegerType, \ + class NumberUnsignedType, class NumberFloatType, \ + template class AllocatorType, \ + template class JSONSerializer> + +#define NLOHMANN_BASIC_JSON_TPL \ + basic_json + +/*! +@brief Helper to determine whether there's a key_type for T. + +This helper is used to tell associative containers apart from other containers +such as sequence containers. For instance, `std::map` passes the test as it +contains a `mapped_type`, whereas `std::vector` fails the test. + +@sa http://stackoverflow.com/a/7728728/266378 +@since version 1.0.0, overworked in version 2.0.6 +*/ +#define NLOHMANN_JSON_HAS_HELPER(type) \ + template struct has_##type { \ + private: \ + template \ + static int detect(U &&); \ + static void detect(...); \ + public: \ + static constexpr bool value = \ + std::is_integral()))>::value; \ + } + +#endif + +/*** End of inlined file: macro_scope.hpp ***/ + +namespace nlohmann +{ +/*! +@brief detail namespace with internal helper functions + +This namespace collects functions that should not be exposed, +implementations of some @ref basic_json methods, and meta-programming helpers. + +@since version 2.1.0 +*/ +namespace detail +{ +///////////// +// helpers // +///////////// + +template struct is_basic_json : std::false_type {}; + +NLOHMANN_BASIC_JSON_TPL_DECLARATION +struct is_basic_json : std::true_type {}; + +// alias templates to reduce boilerplate +template +using enable_if_t = typename std::enable_if::type; + +template +using uncvref_t = typename std::remove_cv::type>::type; + +// implementation of C++14 index_sequence and affiliates +// source: https://stackoverflow.com/a/32223343 +template +struct index_sequence +{ + using type = index_sequence; + using value_type = std::size_t; + static constexpr std::size_t size() noexcept + { + return sizeof...(Ints); + } +}; + +template +struct merge_and_renumber; + +template +struct merge_and_renumber, index_sequence> + : index_sequence < I1..., (sizeof...(I1) + I2)... > {}; + +template +struct make_index_sequence + : merge_and_renumber < typename make_index_sequence < N / 2 >::type, + typename make_index_sequence < N - N / 2 >::type > {}; + +template<> struct make_index_sequence<0> : index_sequence<> {}; +template<> struct make_index_sequence<1> : index_sequence<0> {}; + +template +using index_sequence_for = make_index_sequence; + +/* +Implementation of two C++17 constructs: conjunction, negation. This is needed +to avoid evaluating all the traits in a condition + +For example: not std::is_same::value and has_value_type::value +will not compile when T = void (on MSVC at least). Whereas +conjunction>, has_value_type>::value will +stop evaluating if negation<...>::value == false + +Please note that those constructs must be used with caution, since symbols can +become very long quickly (which can slow down compilation and cause MSVC +internal compiler errors). Only use it when you have to (see example ahead). +*/ +template struct conjunction : std::true_type {}; +template struct conjunction : B1 {}; +template +struct conjunction : std::conditional, B1>::type {}; + +template struct negation : std::integral_constant {}; + +// dispatch utility (taken from ranges-v3) +template struct priority_tag : priority_tag < N - 1 > {}; +template<> struct priority_tag<0> {}; + +//////////////////////// +// has_/is_ functions // +//////////////////////// + +NLOHMANN_JSON_HAS_HELPER(mapped_type); +NLOHMANN_JSON_HAS_HELPER(key_type); +NLOHMANN_JSON_HAS_HELPER(value_type); +NLOHMANN_JSON_HAS_HELPER(iterator); + +template +struct is_compatible_object_type_impl : std::false_type {}; + +template +struct is_compatible_object_type_impl +{ + static constexpr auto value = + std::is_constructible::value and + std::is_constructible::value; +}; + +template +struct is_compatible_object_type +{ + static auto constexpr value = is_compatible_object_type_impl < + conjunction>, + has_mapped_type, + has_key_type>::value, + typename BasicJsonType::object_t, CompatibleObjectType >::value; +}; + +template +struct is_basic_json_nested_type +{ + static auto constexpr value = std::is_same::value or + std::is_same::value or + std::is_same::value or + std::is_same::value; +}; + +template +struct is_compatible_array_type +{ + static auto constexpr value = + conjunction>, + negation>, + negation>, + negation>, + has_value_type, + has_iterator>::value; +}; + +template +struct is_compatible_integer_type_impl : std::false_type {}; + +template +struct is_compatible_integer_type_impl +{ + // is there an assert somewhere on overflows? + using RealLimits = std::numeric_limits; + using CompatibleLimits = std::numeric_limits; + + static constexpr auto value = + std::is_constructible::value and + CompatibleLimits::is_integer and + RealLimits::is_signed == CompatibleLimits::is_signed; +}; + +template +struct is_compatible_integer_type +{ + static constexpr auto value = + is_compatible_integer_type_impl < + std::is_integral::value and + not std::is_same::value, + RealIntegerType, CompatibleNumberIntegerType > ::value; +}; + +// trait checking if JSONSerializer::from_json(json const&, udt&) exists +template +struct has_from_json +{ + private: + // also check the return type of from_json + template::from_json( + std::declval(), std::declval()))>::value>> + static int detect(U&&); + static void detect(...); + + public: + static constexpr bool value = std::is_integral>()))>::value; +}; + +// This trait checks if JSONSerializer::from_json(json const&) exists +// this overload is used for non-default-constructible user-defined-types +template +struct has_non_default_from_json +{ + private: + template < + typename U, + typename = enable_if_t::from_json(std::declval()))>::value >> + static int detect(U&&); + static void detect(...); + + public: + static constexpr bool value = std::is_integral>()))>::value; +}; + +// This trait checks if BasicJsonType::json_serializer::to_json exists +template +struct has_to_json +{ + private: + template::to_json( + std::declval(), std::declval()))> + static int detect(U&&); + static void detect(...); + + public: + static constexpr bool value = std::is_integral>()))>::value; +}; + +// taken from ranges-v3 +template +struct static_const +{ + static constexpr T value{}; +}; + +template +constexpr T static_const::value; +} +} + +#endif + +/*** End of inlined file: meta.hpp ***/ + + +/*** Start of inlined file: exceptions.hpp ***/ +#ifndef NLOHMANN_JSON_DETAIL_EXCEPTIONS_HPP +#define NLOHMANN_JSON_DETAIL_EXCEPTIONS_HPP + +#include // exception +#include // runtime_error +#include // to_string + +namespace nlohmann +{ +namespace detail +{ +//////////////// +// exceptions // +//////////////// + +/*! +@brief general exception of the @ref basic_json class + +This class is an extension of `std::exception` objects with a member @a id for +exception ids. It is used as the base class for all exceptions thrown by the +@ref basic_json class. This class can hence be used as "wildcard" to catch +exceptions. + +Subclasses: +- @ref parse_error for exceptions indicating a parse error +- @ref invalid_iterator for exceptions indicating errors with iterators +- @ref type_error for exceptions indicating executing a member function with + a wrong type +- @ref out_of_range for exceptions indicating access out of the defined range +- @ref other_error for exceptions indicating other library errors + +@internal +@note To have nothrow-copy-constructible exceptions, we internally use + `std::runtime_error` which can cope with arbitrary-length error messages. + Intermediate strings are built with static functions and then passed to + the actual constructor. +@endinternal + +@liveexample{The following code shows how arbitrary library exceptions can be +caught.,exception} + +@since version 3.0.0 +*/ +class exception : public std::exception +{ + public: + /// returns the explanatory string + const char* what() const noexcept override + { + return m.what(); + } + + /// the id of the exception + const int id; + + protected: + exception(int id_, const char* what_arg) : id(id_), m(what_arg) {} + + static std::string name(const std::string& ename, int id_) + { + return "[json.exception." + ename + "." + std::to_string(id_) + "] "; + } + + private: + /// an exception object as storage for error messages + std::runtime_error m; +}; + +/*! +@brief exception indicating a parse error + +This exception is thrown by the library when a parse error occurs. Parse errors +can occur during the deserialization of JSON text, CBOR, MessagePack, as well +as when using JSON Patch. + +Member @a byte holds the byte index of the last read character in the input +file. + +Exceptions have ids 1xx. + +name / id | example message | description +------------------------------ | --------------- | ------------------------- +json.exception.parse_error.101 | parse error at 2: unexpected end of input; expected string literal | This error indicates a syntax error while deserializing a JSON text. The error message describes that an unexpected token (character) was encountered, and the member @a byte indicates the error position. +json.exception.parse_error.102 | parse error at 14: missing or wrong low surrogate | JSON uses the `\uxxxx` format to describe Unicode characters. Code points above above 0xFFFF are split into two `\uxxxx` entries ("surrogate pairs"). This error indicates that the surrogate pair is incomplete or contains an invalid code point. +json.exception.parse_error.103 | parse error: code points above 0x10FFFF are invalid | Unicode supports code points up to 0x10FFFF. Code points above 0x10FFFF are invalid. +json.exception.parse_error.104 | parse error: JSON patch must be an array of objects | [RFC 6902](https://tools.ietf.org/html/rfc6902) requires a JSON Patch document to be a JSON document that represents an array of objects. +json.exception.parse_error.105 | parse error: operation must have string member 'op' | An operation of a JSON Patch document must contain exactly one "op" member, whose value indicates the operation to perform. Its value must be one of "add", "remove", "replace", "move", "copy", or "test"; other values are errors. +json.exception.parse_error.106 | parse error: array index '01' must not begin with '0' | An array index in a JSON Pointer ([RFC 6901](https://tools.ietf.org/html/rfc6901)) may be `0` or any number without a leading `0`. +json.exception.parse_error.107 | parse error: JSON pointer must be empty or begin with '/' - was: 'foo' | A JSON Pointer must be a Unicode string containing a sequence of zero or more reference tokens, each prefixed by a `/` character. +json.exception.parse_error.108 | parse error: escape character '~' must be followed with '0' or '1' | In a JSON Pointer, only `~0` and `~1` are valid escape sequences. +json.exception.parse_error.109 | parse error: array index 'one' is not a number | A JSON Pointer array index must be a number. +json.exception.parse_error.110 | parse error at 1: cannot read 2 bytes from vector | When parsing CBOR or MessagePack, the byte vector ends before the complete value has been read. +json.exception.parse_error.112 | parse error at 1: error reading CBOR; last byte: 0xF8 | Not all types of CBOR or MessagePack are supported. This exception occurs if an unsupported byte was read. +json.exception.parse_error.113 | parse error at 2: expected a CBOR string; last byte: 0x98 | While parsing a map key, a value that is not a string has been read. + +@note For an input with n bytes, 1 is the index of the first character and n+1 + is the index of the terminating null byte or the end of file. This also + holds true when reading a byte vector (CBOR or MessagePack). + +@liveexample{The following code shows how a `parse_error` exception can be +caught.,parse_error} + +@sa @ref exception for the base class of the library exceptions +@sa @ref invalid_iterator for exceptions indicating errors with iterators +@sa @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa @ref out_of_range for exceptions indicating access out of the defined range +@sa @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class parse_error : public exception +{ + public: + /*! + @brief create a parse error exception + @param[in] id_ the id of the exception + @param[in] byte_ the byte index where the error occurred (or 0 if the + position cannot be determined) + @param[in] what_arg the explanatory string + @return parse_error object + */ + static parse_error create(int id_, std::size_t byte_, const std::string& what_arg) + { + std::string w = exception::name("parse_error", id_) + "parse error" + + (byte_ != 0 ? (" at " + std::to_string(byte_)) : "") + + ": " + what_arg; + return parse_error(id_, byte_, w.c_str()); + } + + /*! + @brief byte index of the parse error + + The byte index of the last read character in the input file. + + @note For an input with n bytes, 1 is the index of the first character and + n+1 is the index of the terminating null byte or the end of file. + This also holds true when reading a byte vector (CBOR or MessagePack). + */ + const std::size_t byte; + + private: + parse_error(int id_, std::size_t byte_, const char* what_arg) + : exception(id_, what_arg), byte(byte_) {} +}; + +/*! +@brief exception indicating errors with iterators + +This exception is thrown if iterators passed to a library function do not match +the expected semantics. + +Exceptions have ids 2xx. + +name / id | example message | description +----------------------------------- | --------------- | ------------------------- +json.exception.invalid_iterator.201 | iterators are not compatible | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. +json.exception.invalid_iterator.202 | iterator does not fit current value | In an erase or insert function, the passed iterator @a pos does not belong to the JSON value for which the function was called. It hence does not define a valid position for the deletion/insertion. +json.exception.invalid_iterator.203 | iterators do not fit current value | Either iterator passed to function @ref erase(IteratorType first, IteratorType last) does not belong to the JSON value from which values shall be erased. It hence does not define a valid range to delete values from. +json.exception.invalid_iterator.204 | iterators out of range | When an iterator range for a primitive type (number, boolean, or string) is passed to a constructor or an erase function, this range has to be exactly (@ref begin(), @ref end()), because this is the only way the single stored value is expressed. All other ranges are invalid. +json.exception.invalid_iterator.205 | iterator out of range | When an iterator for a primitive type (number, boolean, or string) is passed to an erase function, the iterator has to be the @ref begin() iterator, because it is the only way to address the stored value. All other iterators are invalid. +json.exception.invalid_iterator.206 | cannot construct with iterators from null | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) belong to a JSON null value and hence to not define a valid range. +json.exception.invalid_iterator.207 | cannot use key() for non-object iterators | The key() member function can only be used on iterators belonging to a JSON object, because other types do not have a concept of a key. +json.exception.invalid_iterator.208 | cannot use operator[] for object iterators | The operator[] to specify a concrete offset cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. +json.exception.invalid_iterator.209 | cannot use offsets with object iterators | The offset operators (+, -, +=, -=) cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. +json.exception.invalid_iterator.210 | iterators do not fit | The iterator range passed to the insert function are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. +json.exception.invalid_iterator.211 | passed iterators may not belong to container | The iterator range passed to the insert function must not be a subrange of the container to insert to. +json.exception.invalid_iterator.212 | cannot compare iterators of different containers | When two iterators are compared, they must belong to the same container. +json.exception.invalid_iterator.213 | cannot compare order of object iterators | The order of object iterators cannot be compared, because JSON objects are unordered. +json.exception.invalid_iterator.214 | cannot get value | Cannot get value for iterator: Either the iterator belongs to a null value or it is an iterator to a primitive type (number, boolean, or string), but the iterator is different to @ref begin(). + +@liveexample{The following code shows how an `invalid_iterator` exception can be +caught.,invalid_iterator} + +@sa @ref exception for the base class of the library exceptions +@sa @ref parse_error for exceptions indicating a parse error +@sa @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa @ref out_of_range for exceptions indicating access out of the defined range +@sa @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class invalid_iterator : public exception +{ + public: + static invalid_iterator create(int id_, const std::string& what_arg) + { + std::string w = exception::name("invalid_iterator", id_) + what_arg; + return invalid_iterator(id_, w.c_str()); + } + + private: + invalid_iterator(int id_, const char* what_arg) + : exception(id_, what_arg) {} +}; + +/*! +@brief exception indicating executing a member function with a wrong type + +This exception is thrown in case of a type error; that is, a library function is +executed on a JSON value whose type does not match the expected semantics. + +Exceptions have ids 3xx. + +name / id | example message | description +----------------------------- | --------------- | ------------------------- +json.exception.type_error.301 | cannot create object from initializer list | To create an object from an initializer list, the initializer list must consist only of a list of pairs whose first element is a string. When this constraint is violated, an array is created instead. +json.exception.type_error.302 | type must be object, but is array | During implicit or explicit value conversion, the JSON type must be compatible to the target type. For instance, a JSON string can only be converted into string types, but not into numbers or boolean types. +json.exception.type_error.303 | incompatible ReferenceType for get_ref, actual type is object | To retrieve a reference to a value stored in a @ref basic_json object with @ref get_ref, the type of the reference must match the value type. For instance, for a JSON array, the @a ReferenceType must be @ref array_t&. +json.exception.type_error.304 | cannot use at() with string | The @ref at() member functions can only be executed for certain JSON types. +json.exception.type_error.305 | cannot use operator[] with string | The @ref operator[] member functions can only be executed for certain JSON types. +json.exception.type_error.306 | cannot use value() with string | The @ref value() member functions can only be executed for certain JSON types. +json.exception.type_error.307 | cannot use erase() with string | The @ref erase() member functions can only be executed for certain JSON types. +json.exception.type_error.308 | cannot use push_back() with string | The @ref push_back() and @ref operator+= member functions can only be executed for certain JSON types. +json.exception.type_error.309 | cannot use insert() with | The @ref insert() member functions can only be executed for certain JSON types. +json.exception.type_error.310 | cannot use swap() with number | The @ref swap() member functions can only be executed for certain JSON types. +json.exception.type_error.311 | cannot use emplace_back() with string | The @ref emplace_back() member function can only be executed for certain JSON types. +json.exception.type_error.312 | cannot use update() with string | The @ref update() member functions can only be executed for certain JSON types. +json.exception.type_error.313 | invalid value to unflatten | The @ref unflatten function converts an object whose keys are JSON Pointers back into an arbitrary nested JSON value. The JSON Pointers must not overlap, because then the resulting value would not be well defined. +json.exception.type_error.314 | only objects can be unflattened | The @ref unflatten function only works for an object whose keys are JSON Pointers. +json.exception.type_error.315 | values in object must be primitive | The @ref unflatten function only works for an object whose keys are JSON Pointers and whose values are primitive. +json.exception.type_error.316 | invalid UTF-8 byte at index 10: 0x7E | The @ref dump function only works with UTF-8 encoded strings; that is, if you assign a `std::string` to a JSON value, make sure it is UTF-8 encoded. | + +@liveexample{The following code shows how a `type_error` exception can be +caught.,type_error} + +@sa @ref exception for the base class of the library exceptions +@sa @ref parse_error for exceptions indicating a parse error +@sa @ref invalid_iterator for exceptions indicating errors with iterators +@sa @ref out_of_range for exceptions indicating access out of the defined range +@sa @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class type_error : public exception +{ + public: + static type_error create(int id_, const std::string& what_arg) + { + std::string w = exception::name("type_error", id_) + what_arg; + return type_error(id_, w.c_str()); + } + + private: + type_error(int id_, const char* what_arg) : exception(id_, what_arg) {} +}; + +/*! +@brief exception indicating access out of the defined range + +This exception is thrown in case a library function is called on an input +parameter that exceeds the expected range, for instance in case of array +indices or nonexisting object keys. + +Exceptions have ids 4xx. + +name / id | example message | description +------------------------------- | --------------- | ------------------------- +json.exception.out_of_range.401 | array index 3 is out of range | The provided array index @a i is larger than @a size-1. +json.exception.out_of_range.402 | array index '-' (3) is out of range | The special array index `-` in a JSON Pointer never describes a valid element of the array, but the index past the end. That is, it can only be used to add elements at this position, but not to read it. +json.exception.out_of_range.403 | key 'foo' not found | The provided key was not found in the JSON object. +json.exception.out_of_range.404 | unresolved reference token 'foo' | A reference token in a JSON Pointer could not be resolved. +json.exception.out_of_range.405 | JSON pointer has no parent | The JSON Patch operations 'remove' and 'add' can not be applied to the root element of the JSON value. +json.exception.out_of_range.406 | number overflow parsing '10E1000' | A parsed number could not be stored as without changing it to NaN or INF. + +@liveexample{The following code shows how an `out_of_range` exception can be +caught.,out_of_range} + +@sa @ref exception for the base class of the library exceptions +@sa @ref parse_error for exceptions indicating a parse error +@sa @ref invalid_iterator for exceptions indicating errors with iterators +@sa @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class out_of_range : public exception +{ + public: + static out_of_range create(int id_, const std::string& what_arg) + { + std::string w = exception::name("out_of_range", id_) + what_arg; + return out_of_range(id_, w.c_str()); + } + + private: + out_of_range(int id_, const char* what_arg) : exception(id_, what_arg) {} +}; + +/*! +@brief exception indicating other library errors + +This exception is thrown in case of errors that cannot be classified with the +other exception types. + +Exceptions have ids 5xx. + +name / id | example message | description +------------------------------ | --------------- | ------------------------- +json.exception.other_error.501 | unsuccessful: {"op":"test","path":"/baz", "value":"bar"} | A JSON Patch operation 'test' failed. The unsuccessful operation is also printed. + +@sa @ref exception for the base class of the library exceptions +@sa @ref parse_error for exceptions indicating a parse error +@sa @ref invalid_iterator for exceptions indicating errors with iterators +@sa @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa @ref out_of_range for exceptions indicating access out of the defined range + +@liveexample{The following code shows how an `other_error` exception can be +caught.,other_error} + +@since version 3.0.0 +*/ +class other_error : public exception +{ + public: + static other_error create(int id_, const std::string& what_arg) + { + std::string w = exception::name("other_error", id_) + what_arg; + return other_error(id_, w.c_str()); + } + + private: + other_error(int id_, const char* what_arg) : exception(id_, what_arg) {} +}; +} +} + +#endif + +/*** End of inlined file: exceptions.hpp ***/ + + +/*** Start of inlined file: value_t.hpp ***/ +#ifndef NLOHMANN_JSON_DETAIL_VALUE_T_HPP +#define NLOHMANN_JSON_DETAIL_VALUE_T_HPP + +#include // array +#include // and +#include // size_t +#include // uint8_t + +namespace nlohmann +{ +namespace detail +{ +/////////////////////////// +// JSON type enumeration // +/////////////////////////// + +/*! +@brief the JSON type enumeration + +This enumeration collects the different JSON types. It is internally used to +distinguish the stored values, and the functions @ref basic_json::is_null(), +@ref basic_json::is_object(), @ref basic_json::is_array(), +@ref basic_json::is_string(), @ref basic_json::is_boolean(), +@ref basic_json::is_number() (with @ref basic_json::is_number_integer(), +@ref basic_json::is_number_unsigned(), and @ref basic_json::is_number_float()), +@ref basic_json::is_discarded(), @ref basic_json::is_primitive(), and +@ref basic_json::is_structured() rely on it. + +@note There are three enumeration entries (number_integer, number_unsigned, and +number_float), because the library distinguishes these three types for numbers: +@ref basic_json::number_unsigned_t is used for unsigned integers, +@ref basic_json::number_integer_t is used for signed integers, and +@ref basic_json::number_float_t is used for floating-point numbers or to +approximate integers which do not fit in the limits of their respective type. + +@sa @ref basic_json::basic_json(const value_t value_type) -- create a JSON +value with the default value for a given type + +@since version 1.0.0 +*/ +enum class value_t : std::uint8_t +{ + null, ///< null value + object, ///< object (unordered set of name/value pairs) + array, ///< array (ordered collection of values) + string, ///< string value + boolean, ///< boolean value + number_integer, ///< number value (signed integer) + number_unsigned, ///< number value (unsigned integer) + number_float, ///< number value (floating-point) + discarded ///< discarded by the the parser callback function +}; + +/*! +@brief comparison operator for JSON types + +Returns an ordering that is similar to Python: +- order: null < boolean < number < object < array < string +- furthermore, each type is not smaller than itself +- discarded values are not comparable + +@since version 1.0.0 +*/ +inline bool operator<(const value_t lhs, const value_t rhs) noexcept +{ + static constexpr std::array order = {{ + 0 /* null */, 3 /* object */, 4 /* array */, 5 /* string */, + 1 /* boolean */, 2 /* integer */, 2 /* unsigned */, 2 /* float */ + } + }; + + const auto l_index = static_cast(lhs); + const auto r_index = static_cast(rhs); + return l_index < order.size() and r_index < order.size() and order[l_index] < order[r_index]; +} +} +} + +#endif + +/*** End of inlined file: value_t.hpp ***/ + + +/*** Start of inlined file: from_json.hpp ***/ +#ifndef NLOHMANN_JSON_DETAIL_CONVERSIONS_FROM_JSON_HPP +#define NLOHMANN_JSON_DETAIL_CONVERSIONS_FROM_JSON_HPP + +#include // transform +#include // array +#include // and, not +#include // forward_list +#include // inserter, front_inserter, end +#include // string +#include // tuple, make_tuple +#include // is_arithmetic, is_same, is_enum, underlying_type, is_convertible +#include // pair, declval +#include // valarray + + +/*** Start of inlined file: exceptions.hpp ***/ +#ifndef NLOHMANN_JSON_DETAIL_EXCEPTIONS_HPP +#define NLOHMANN_JSON_DETAIL_EXCEPTIONS_HPP + +#include // exception +#include // runtime_error +#include // to_string + +namespace nlohmann +{ +namespace detail +{ +//////////////// +// exceptions // +//////////////// + +/*! +@brief general exception of the @ref basic_json class + +This class is an extension of `std::exception` objects with a member @a id for +exception ids. It is used as the base class for all exceptions thrown by the +@ref basic_json class. This class can hence be used as "wildcard" to catch +exceptions. + +Subclasses: +- @ref parse_error for exceptions indicating a parse error +- @ref invalid_iterator for exceptions indicating errors with iterators +- @ref type_error for exceptions indicating executing a member function with + a wrong type +- @ref out_of_range for exceptions indicating access out of the defined range +- @ref other_error for exceptions indicating other library errors + +@internal +@note To have nothrow-copy-constructible exceptions, we internally use + `std::runtime_error` which can cope with arbitrary-length error messages. + Intermediate strings are built with static functions and then passed to + the actual constructor. +@endinternal + +@liveexample{The following code shows how arbitrary library exceptions can be +caught.,exception} + +@since version 3.0.0 +*/ +class exception : public std::exception +{ + public: + /// returns the explanatory string + const char* what() const noexcept override + { + return m.what(); + } + + /// the id of the exception + const int id; + + protected: + exception(int id_, const char* what_arg) : id(id_), m(what_arg) {} + + static std::string name(const std::string& ename, int id_) + { + return "[json.exception." + ename + "." + std::to_string(id_) + "] "; + } + + private: + /// an exception object as storage for error messages + std::runtime_error m; +}; + +/*! +@brief exception indicating a parse error + +This exception is thrown by the library when a parse error occurs. Parse errors +can occur during the deserialization of JSON text, CBOR, MessagePack, as well +as when using JSON Patch. + +Member @a byte holds the byte index of the last read character in the input +file. + +Exceptions have ids 1xx. + +name / id | example message | description +------------------------------ | --------------- | ------------------------- +json.exception.parse_error.101 | parse error at 2: unexpected end of input; expected string literal | This error indicates a syntax error while deserializing a JSON text. The error message describes that an unexpected token (character) was encountered, and the member @a byte indicates the error position. +json.exception.parse_error.102 | parse error at 14: missing or wrong low surrogate | JSON uses the `\uxxxx` format to describe Unicode characters. Code points above above 0xFFFF are split into two `\uxxxx` entries ("surrogate pairs"). This error indicates that the surrogate pair is incomplete or contains an invalid code point. +json.exception.parse_error.103 | parse error: code points above 0x10FFFF are invalid | Unicode supports code points up to 0x10FFFF. Code points above 0x10FFFF are invalid. +json.exception.parse_error.104 | parse error: JSON patch must be an array of objects | [RFC 6902](https://tools.ietf.org/html/rfc6902) requires a JSON Patch document to be a JSON document that represents an array of objects. +json.exception.parse_error.105 | parse error: operation must have string member 'op' | An operation of a JSON Patch document must contain exactly one "op" member, whose value indicates the operation to perform. Its value must be one of "add", "remove", "replace", "move", "copy", or "test"; other values are errors. +json.exception.parse_error.106 | parse error: array index '01' must not begin with '0' | An array index in a JSON Pointer ([RFC 6901](https://tools.ietf.org/html/rfc6901)) may be `0` or any number without a leading `0`. +json.exception.parse_error.107 | parse error: JSON pointer must be empty or begin with '/' - was: 'foo' | A JSON Pointer must be a Unicode string containing a sequence of zero or more reference tokens, each prefixed by a `/` character. +json.exception.parse_error.108 | parse error: escape character '~' must be followed with '0' or '1' | In a JSON Pointer, only `~0` and `~1` are valid escape sequences. +json.exception.parse_error.109 | parse error: array index 'one' is not a number | A JSON Pointer array index must be a number. +json.exception.parse_error.110 | parse error at 1: cannot read 2 bytes from vector | When parsing CBOR or MessagePack, the byte vector ends before the complete value has been read. +json.exception.parse_error.112 | parse error at 1: error reading CBOR; last byte: 0xF8 | Not all types of CBOR or MessagePack are supported. This exception occurs if an unsupported byte was read. +json.exception.parse_error.113 | parse error at 2: expected a CBOR string; last byte: 0x98 | While parsing a map key, a value that is not a string has been read. + +@note For an input with n bytes, 1 is the index of the first character and n+1 + is the index of the terminating null byte or the end of file. This also + holds true when reading a byte vector (CBOR or MessagePack). + +@liveexample{The following code shows how a `parse_error` exception can be +caught.,parse_error} + +@sa @ref exception for the base class of the library exceptions +@sa @ref invalid_iterator for exceptions indicating errors with iterators +@sa @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa @ref out_of_range for exceptions indicating access out of the defined range +@sa @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class parse_error : public exception +{ + public: + /*! + @brief create a parse error exception + @param[in] id_ the id of the exception + @param[in] byte_ the byte index where the error occurred (or 0 if the + position cannot be determined) + @param[in] what_arg the explanatory string + @return parse_error object + */ + static parse_error create(int id_, std::size_t byte_, const std::string& what_arg) + { + std::string w = exception::name("parse_error", id_) + "parse error" + + (byte_ != 0 ? (" at " + std::to_string(byte_)) : "") + + ": " + what_arg; + return parse_error(id_, byte_, w.c_str()); + } + + /*! + @brief byte index of the parse error + + The byte index of the last read character in the input file. + + @note For an input with n bytes, 1 is the index of the first character and + n+1 is the index of the terminating null byte or the end of file. + This also holds true when reading a byte vector (CBOR or MessagePack). + */ + const std::size_t byte; + + private: + parse_error(int id_, std::size_t byte_, const char* what_arg) + : exception(id_, what_arg), byte(byte_) {} +}; + +/*! +@brief exception indicating errors with iterators + +This exception is thrown if iterators passed to a library function do not match +the expected semantics. + +Exceptions have ids 2xx. + +name / id | example message | description +----------------------------------- | --------------- | ------------------------- +json.exception.invalid_iterator.201 | iterators are not compatible | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. +json.exception.invalid_iterator.202 | iterator does not fit current value | In an erase or insert function, the passed iterator @a pos does not belong to the JSON value for which the function was called. It hence does not define a valid position for the deletion/insertion. +json.exception.invalid_iterator.203 | iterators do not fit current value | Either iterator passed to function @ref erase(IteratorType first, IteratorType last) does not belong to the JSON value from which values shall be erased. It hence does not define a valid range to delete values from. +json.exception.invalid_iterator.204 | iterators out of range | When an iterator range for a primitive type (number, boolean, or string) is passed to a constructor or an erase function, this range has to be exactly (@ref begin(), @ref end()), because this is the only way the single stored value is expressed. All other ranges are invalid. +json.exception.invalid_iterator.205 | iterator out of range | When an iterator for a primitive type (number, boolean, or string) is passed to an erase function, the iterator has to be the @ref begin() iterator, because it is the only way to address the stored value. All other iterators are invalid. +json.exception.invalid_iterator.206 | cannot construct with iterators from null | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) belong to a JSON null value and hence to not define a valid range. +json.exception.invalid_iterator.207 | cannot use key() for non-object iterators | The key() member function can only be used on iterators belonging to a JSON object, because other types do not have a concept of a key. +json.exception.invalid_iterator.208 | cannot use operator[] for object iterators | The operator[] to specify a concrete offset cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. +json.exception.invalid_iterator.209 | cannot use offsets with object iterators | The offset operators (+, -, +=, -=) cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. +json.exception.invalid_iterator.210 | iterators do not fit | The iterator range passed to the insert function are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. +json.exception.invalid_iterator.211 | passed iterators may not belong to container | The iterator range passed to the insert function must not be a subrange of the container to insert to. +json.exception.invalid_iterator.212 | cannot compare iterators of different containers | When two iterators are compared, they must belong to the same container. +json.exception.invalid_iterator.213 | cannot compare order of object iterators | The order of object iterators cannot be compared, because JSON objects are unordered. +json.exception.invalid_iterator.214 | cannot get value | Cannot get value for iterator: Either the iterator belongs to a null value or it is an iterator to a primitive type (number, boolean, or string), but the iterator is different to @ref begin(). + +@liveexample{The following code shows how an `invalid_iterator` exception can be +caught.,invalid_iterator} + +@sa @ref exception for the base class of the library exceptions +@sa @ref parse_error for exceptions indicating a parse error +@sa @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa @ref out_of_range for exceptions indicating access out of the defined range +@sa @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class invalid_iterator : public exception +{ + public: + static invalid_iterator create(int id_, const std::string& what_arg) + { + std::string w = exception::name("invalid_iterator", id_) + what_arg; + return invalid_iterator(id_, w.c_str()); + } + + private: + invalid_iterator(int id_, const char* what_arg) + : exception(id_, what_arg) {} +}; + +/*! +@brief exception indicating executing a member function with a wrong type + +This exception is thrown in case of a type error; that is, a library function is +executed on a JSON value whose type does not match the expected semantics. + +Exceptions have ids 3xx. + +name / id | example message | description +----------------------------- | --------------- | ------------------------- +json.exception.type_error.301 | cannot create object from initializer list | To create an object from an initializer list, the initializer list must consist only of a list of pairs whose first element is a string. When this constraint is violated, an array is created instead. +json.exception.type_error.302 | type must be object, but is array | During implicit or explicit value conversion, the JSON type must be compatible to the target type. For instance, a JSON string can only be converted into string types, but not into numbers or boolean types. +json.exception.type_error.303 | incompatible ReferenceType for get_ref, actual type is object | To retrieve a reference to a value stored in a @ref basic_json object with @ref get_ref, the type of the reference must match the value type. For instance, for a JSON array, the @a ReferenceType must be @ref array_t&. +json.exception.type_error.304 | cannot use at() with string | The @ref at() member functions can only be executed for certain JSON types. +json.exception.type_error.305 | cannot use operator[] with string | The @ref operator[] member functions can only be executed for certain JSON types. +json.exception.type_error.306 | cannot use value() with string | The @ref value() member functions can only be executed for certain JSON types. +json.exception.type_error.307 | cannot use erase() with string | The @ref erase() member functions can only be executed for certain JSON types. +json.exception.type_error.308 | cannot use push_back() with string | The @ref push_back() and @ref operator+= member functions can only be executed for certain JSON types. +json.exception.type_error.309 | cannot use insert() with | The @ref insert() member functions can only be executed for certain JSON types. +json.exception.type_error.310 | cannot use swap() with number | The @ref swap() member functions can only be executed for certain JSON types. +json.exception.type_error.311 | cannot use emplace_back() with string | The @ref emplace_back() member function can only be executed for certain JSON types. +json.exception.type_error.312 | cannot use update() with string | The @ref update() member functions can only be executed for certain JSON types. +json.exception.type_error.313 | invalid value to unflatten | The @ref unflatten function converts an object whose keys are JSON Pointers back into an arbitrary nested JSON value. The JSON Pointers must not overlap, because then the resulting value would not be well defined. +json.exception.type_error.314 | only objects can be unflattened | The @ref unflatten function only works for an object whose keys are JSON Pointers. +json.exception.type_error.315 | values in object must be primitive | The @ref unflatten function only works for an object whose keys are JSON Pointers and whose values are primitive. +json.exception.type_error.316 | invalid UTF-8 byte at index 10: 0x7E | The @ref dump function only works with UTF-8 encoded strings; that is, if you assign a `std::string` to a JSON value, make sure it is UTF-8 encoded. | + +@liveexample{The following code shows how a `type_error` exception can be +caught.,type_error} + +@sa @ref exception for the base class of the library exceptions +@sa @ref parse_error for exceptions indicating a parse error +@sa @ref invalid_iterator for exceptions indicating errors with iterators +@sa @ref out_of_range for exceptions indicating access out of the defined range +@sa @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class type_error : public exception +{ + public: + static type_error create(int id_, const std::string& what_arg) + { + std::string w = exception::name("type_error", id_) + what_arg; + return type_error(id_, w.c_str()); + } + + private: + type_error(int id_, const char* what_arg) : exception(id_, what_arg) {} +}; + +/*! +@brief exception indicating access out of the defined range + +This exception is thrown in case a library function is called on an input +parameter that exceeds the expected range, for instance in case of array +indices or nonexisting object keys. + +Exceptions have ids 4xx. + +name / id | example message | description +------------------------------- | --------------- | ------------------------- +json.exception.out_of_range.401 | array index 3 is out of range | The provided array index @a i is larger than @a size-1. +json.exception.out_of_range.402 | array index '-' (3) is out of range | The special array index `-` in a JSON Pointer never describes a valid element of the array, but the index past the end. That is, it can only be used to add elements at this position, but not to read it. +json.exception.out_of_range.403 | key 'foo' not found | The provided key was not found in the JSON object. +json.exception.out_of_range.404 | unresolved reference token 'foo' | A reference token in a JSON Pointer could not be resolved. +json.exception.out_of_range.405 | JSON pointer has no parent | The JSON Patch operations 'remove' and 'add' can not be applied to the root element of the JSON value. +json.exception.out_of_range.406 | number overflow parsing '10E1000' | A parsed number could not be stored as without changing it to NaN or INF. + +@liveexample{The following code shows how an `out_of_range` exception can be +caught.,out_of_range} + +@sa @ref exception for the base class of the library exceptions +@sa @ref parse_error for exceptions indicating a parse error +@sa @ref invalid_iterator for exceptions indicating errors with iterators +@sa @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class out_of_range : public exception +{ + public: + static out_of_range create(int id_, const std::string& what_arg) + { + std::string w = exception::name("out_of_range", id_) + what_arg; + return out_of_range(id_, w.c_str()); + } + + private: + out_of_range(int id_, const char* what_arg) : exception(id_, what_arg) {} +}; + +/*! +@brief exception indicating other library errors + +This exception is thrown in case of errors that cannot be classified with the +other exception types. + +Exceptions have ids 5xx. + +name / id | example message | description +------------------------------ | --------------- | ------------------------- +json.exception.other_error.501 | unsuccessful: {"op":"test","path":"/baz", "value":"bar"} | A JSON Patch operation 'test' failed. The unsuccessful operation is also printed. + +@sa @ref exception for the base class of the library exceptions +@sa @ref parse_error for exceptions indicating a parse error +@sa @ref invalid_iterator for exceptions indicating errors with iterators +@sa @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa @ref out_of_range for exceptions indicating access out of the defined range + +@liveexample{The following code shows how an `other_error` exception can be +caught.,other_error} + +@since version 3.0.0 +*/ +class other_error : public exception +{ + public: + static other_error create(int id_, const std::string& what_arg) + { + std::string w = exception::name("other_error", id_) + what_arg; + return other_error(id_, w.c_str()); + } + + private: + other_error(int id_, const char* what_arg) : exception(id_, what_arg) {} +}; +} +} + +#endif + +/*** End of inlined file: exceptions.hpp ***/ + + +/*** Start of inlined file: meta.hpp ***/ +#ifndef NLOHMANN_JSON_DETAIL_META_HPP +#define NLOHMANN_JSON_DETAIL_META_HPP + +#include // not +#include // size_t +#include // numeric_limits +#include // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type +#include // declval + +namespace nlohmann +{ +/*! +@brief detail namespace with internal helper functions + +This namespace collects functions that should not be exposed, +implementations of some @ref basic_json methods, and meta-programming helpers. + +@since version 2.1.0 +*/ +namespace detail +{ +///////////// +// helpers // +///////////// + +template struct is_basic_json : std::false_type {}; + +NLOHMANN_BASIC_JSON_TPL_DECLARATION +struct is_basic_json : std::true_type {}; + +// alias templates to reduce boilerplate +template +using enable_if_t = typename std::enable_if::type; + +template +using uncvref_t = typename std::remove_cv::type>::type; + +// implementation of C++14 index_sequence and affiliates +// source: https://stackoverflow.com/a/32223343 +template +struct index_sequence +{ + using type = index_sequence; + using value_type = std::size_t; + static constexpr std::size_t size() noexcept + { + return sizeof...(Ints); + } +}; + +template +struct merge_and_renumber; + +template +struct merge_and_renumber, index_sequence> + : index_sequence < I1..., (sizeof...(I1) + I2)... > {}; + +template +struct make_index_sequence + : merge_and_renumber < typename make_index_sequence < N / 2 >::type, + typename make_index_sequence < N - N / 2 >::type > {}; + +template<> struct make_index_sequence<0> : index_sequence<> {}; +template<> struct make_index_sequence<1> : index_sequence<0> {}; + +template +using index_sequence_for = make_index_sequence; + +/* +Implementation of two C++17 constructs: conjunction, negation. This is needed +to avoid evaluating all the traits in a condition + +For example: not std::is_same::value and has_value_type::value +will not compile when T = void (on MSVC at least). Whereas +conjunction>, has_value_type>::value will +stop evaluating if negation<...>::value == false + +Please note that those constructs must be used with caution, since symbols can +become very long quickly (which can slow down compilation and cause MSVC +internal compiler errors). Only use it when you have to (see example ahead). +*/ +template struct conjunction : std::true_type {}; +template struct conjunction : B1 {}; +template +struct conjunction : std::conditional, B1>::type {}; + +template struct negation : std::integral_constant {}; + +// dispatch utility (taken from ranges-v3) +template struct priority_tag : priority_tag < N - 1 > {}; +template<> struct priority_tag<0> {}; + +//////////////////////// +// has_/is_ functions // +//////////////////////// + +NLOHMANN_JSON_HAS_HELPER(mapped_type); +NLOHMANN_JSON_HAS_HELPER(key_type); +NLOHMANN_JSON_HAS_HELPER(value_type); +NLOHMANN_JSON_HAS_HELPER(iterator); + +template +struct is_compatible_object_type_impl : std::false_type {}; + +template +struct is_compatible_object_type_impl +{ + static constexpr auto value = + std::is_constructible::value and + std::is_constructible::value; +}; + +template +struct is_compatible_object_type +{ + static auto constexpr value = is_compatible_object_type_impl < + conjunction>, + has_mapped_type, + has_key_type>::value, + typename BasicJsonType::object_t, CompatibleObjectType >::value; +}; + +template +struct is_basic_json_nested_type +{ + static auto constexpr value = std::is_same::value or + std::is_same::value or + std::is_same::value or + std::is_same::value; +}; + +template +struct is_compatible_array_type +{ + static auto constexpr value = + conjunction>, + negation>, + negation>, + negation>, + has_value_type, + has_iterator>::value; +}; + +template +struct is_compatible_integer_type_impl : std::false_type {}; + +template +struct is_compatible_integer_type_impl +{ + // is there an assert somewhere on overflows? + using RealLimits = std::numeric_limits; + using CompatibleLimits = std::numeric_limits; + + static constexpr auto value = + std::is_constructible::value and + CompatibleLimits::is_integer and + RealLimits::is_signed == CompatibleLimits::is_signed; +}; + +template +struct is_compatible_integer_type +{ + static constexpr auto value = + is_compatible_integer_type_impl < + std::is_integral::value and + not std::is_same::value, + RealIntegerType, CompatibleNumberIntegerType > ::value; +}; + +// trait checking if JSONSerializer::from_json(json const&, udt&) exists +template +struct has_from_json +{ + private: + // also check the return type of from_json + template::from_json( + std::declval(), std::declval()))>::value>> + static int detect(U&&); + static void detect(...); + + public: + static constexpr bool value = std::is_integral>()))>::value; +}; + +// This trait checks if JSONSerializer::from_json(json const&) exists +// this overload is used for non-default-constructible user-defined-types +template +struct has_non_default_from_json +{ + private: + template < + typename U, + typename = enable_if_t::from_json(std::declval()))>::value >> + static int detect(U&&); + static void detect(...); + + public: + static constexpr bool value = std::is_integral>()))>::value; +}; + +// This trait checks if BasicJsonType::json_serializer::to_json exists +template +struct has_to_json +{ + private: + template::to_json( + std::declval(), std::declval()))> + static int detect(U&&); + static void detect(...); + + public: + static constexpr bool value = std::is_integral>()))>::value; +}; + +// taken from ranges-v3 +template +struct static_const +{ + static constexpr T value{}; +}; + +template +constexpr T static_const::value; +} +} + +#endif + +/*** End of inlined file: meta.hpp ***/ + + +/*** Start of inlined file: value_t.hpp ***/ +#ifndef NLOHMANN_JSON_DETAIL_VALUE_T_HPP +#define NLOHMANN_JSON_DETAIL_VALUE_T_HPP + +#include // array +#include // and +#include // size_t +#include // uint8_t + +namespace nlohmann +{ +namespace detail +{ +/////////////////////////// +// JSON type enumeration // +/////////////////////////// + +/*! +@brief the JSON type enumeration + +This enumeration collects the different JSON types. It is internally used to +distinguish the stored values, and the functions @ref basic_json::is_null(), +@ref basic_json::is_object(), @ref basic_json::is_array(), +@ref basic_json::is_string(), @ref basic_json::is_boolean(), +@ref basic_json::is_number() (with @ref basic_json::is_number_integer(), +@ref basic_json::is_number_unsigned(), and @ref basic_json::is_number_float()), +@ref basic_json::is_discarded(), @ref basic_json::is_primitive(), and +@ref basic_json::is_structured() rely on it. + +@note There are three enumeration entries (number_integer, number_unsigned, and +number_float), because the library distinguishes these three types for numbers: +@ref basic_json::number_unsigned_t is used for unsigned integers, +@ref basic_json::number_integer_t is used for signed integers, and +@ref basic_json::number_float_t is used for floating-point numbers or to +approximate integers which do not fit in the limits of their respective type. + +@sa @ref basic_json::basic_json(const value_t value_type) -- create a JSON +value with the default value for a given type + +@since version 1.0.0 +*/ +enum class value_t : std::uint8_t +{ + null, ///< null value + object, ///< object (unordered set of name/value pairs) + array, ///< array (ordered collection of values) + string, ///< string value + boolean, ///< boolean value + number_integer, ///< number value (signed integer) + number_unsigned, ///< number value (unsigned integer) + number_float, ///< number value (floating-point) + discarded ///< discarded by the the parser callback function +}; + +/*! +@brief comparison operator for JSON types + +Returns an ordering that is similar to Python: +- order: null < boolean < number < object < array < string +- furthermore, each type is not smaller than itself +- discarded values are not comparable + +@since version 1.0.0 +*/ +inline bool operator<(const value_t lhs, const value_t rhs) noexcept +{ + static constexpr std::array order = {{ + 0 /* null */, 3 /* object */, 4 /* array */, 5 /* string */, + 1 /* boolean */, 2 /* integer */, 2 /* unsigned */, 2 /* float */ + } + }; + + const auto l_index = static_cast(lhs); + const auto r_index = static_cast(rhs); + return l_index < order.size() and r_index < order.size() and order[l_index] < order[r_index]; +} +} +} + +#endif + +/*** End of inlined file: value_t.hpp ***/ + +namespace nlohmann +{ +namespace detail +{ +// overloads for basic_json template parameters +template::value and + not std::is_same::value, + int> = 0> +void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val) +{ + switch (static_cast(j)) + { + case value_t::number_unsigned: + { + val = static_cast(*j.template get_ptr()); + break; + } + case value_t::number_integer: + { + val = static_cast(*j.template get_ptr()); + break; + } + case value_t::number_float: + { + val = static_cast(*j.template get_ptr()); + break; + } + + default: + JSON_THROW(type_error::create(302, "type must be number, but is " + std::string(j.type_name()))); + } +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b) +{ + if (JSON_UNLIKELY(not j.is_boolean())) + { + JSON_THROW(type_error::create(302, "type must be boolean, but is " + std::string(j.type_name()))); + } + b = *j.template get_ptr(); +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s) +{ + if (JSON_UNLIKELY(not j.is_string())) + { + JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name()))); + } + s = *j.template get_ptr(); +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::number_float_t& val) +{ + get_arithmetic_value(j, val); +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::number_unsigned_t& val) +{ + get_arithmetic_value(j, val); +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::number_integer_t& val) +{ + get_arithmetic_value(j, val); +} + +template::value, int> = 0> +void from_json(const BasicJsonType& j, EnumType& e) +{ + typename std::underlying_type::type val; + get_arithmetic_value(j, val); + e = static_cast(val); +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::array_t& arr) +{ + if (JSON_UNLIKELY(not j.is_array())) + { + JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); + } + arr = *j.template get_ptr(); +} + +// forward_list doesn't have an insert method +template::value, int> = 0> +void from_json(const BasicJsonType& j, std::forward_list& l) +{ + if (JSON_UNLIKELY(not j.is_array())) + { + JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); + } + std::transform(j.rbegin(), j.rend(), + std::front_inserter(l), [](const BasicJsonType & i) + { + return i.template get(); + }); +} + +// valarray doesn't have an insert method +template::value, int> = 0> +void from_json(const BasicJsonType& j, std::valarray& l) +{ + if (JSON_UNLIKELY(not j.is_array())) + { + JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); + } + l.resize(j.size()); + std::copy(j.m_value.array->begin(), j.m_value.array->end(), std::begin(l)); +} + +template +void from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, priority_tag<0> /*unused*/) +{ + using std::end; + + std::transform(j.begin(), j.end(), + std::inserter(arr, end(arr)), [](const BasicJsonType & i) + { + // get() returns *this, this won't call a from_json + // method when value_type is BasicJsonType + return i.template get(); + }); +} + +template +auto from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, priority_tag<1> /*unused*/) +-> decltype( + arr.reserve(std::declval()), + void()) +{ + using std::end; + + arr.reserve(j.size()); + std::transform(j.begin(), j.end(), + std::inserter(arr, end(arr)), [](const BasicJsonType & i) + { + // get() returns *this, this won't call a from_json + // method when value_type is BasicJsonType + return i.template get(); + }); +} + +template +void from_json_array_impl(const BasicJsonType& j, std::array& arr, priority_tag<2> /*unused*/) +{ + for (std::size_t i = 0; i < N; ++i) + { + arr[i] = j.at(i).template get(); + } +} + +template::value and + std::is_convertible::value and + not std::is_same::value, int> = 0> +void from_json(const BasicJsonType& j, CompatibleArrayType& arr) +{ + if (JSON_UNLIKELY(not j.is_array())) + { + JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); + } + + from_json_array_impl(j, arr, priority_tag<2> {}); +} + +template::value, int> = 0> +void from_json(const BasicJsonType& j, CompatibleObjectType& obj) +{ + if (JSON_UNLIKELY(not j.is_object())) + { + JSON_THROW(type_error::create(302, "type must be object, but is " + std::string(j.type_name()))); + } + + auto inner_object = j.template get_ptr(); + using value_type = typename CompatibleObjectType::value_type; + std::transform( + inner_object->begin(), inner_object->end(), + std::inserter(obj, obj.begin()), + [](typename BasicJsonType::object_t::value_type const & p) + { + return value_type(p.first, p.second.template get()); + }); +} + +// overload for arithmetic types, not chosen for basic_json template arguments +// (BooleanType, etc..); note: Is it really necessary to provide explicit +// overloads for boolean_t etc. in case of a custom BooleanType which is not +// an arithmetic type? +template::value and + not std::is_same::value and + not std::is_same::value and + not std::is_same::value and + not std::is_same::value, + int> = 0> +void from_json(const BasicJsonType& j, ArithmeticType& val) +{ + switch (static_cast(j)) + { + case value_t::number_unsigned: + { + val = static_cast(*j.template get_ptr()); + break; + } + case value_t::number_integer: + { + val = static_cast(*j.template get_ptr()); + break; + } + case value_t::number_float: + { + val = static_cast(*j.template get_ptr()); + break; + } + case value_t::boolean: + { + val = static_cast(*j.template get_ptr()); + break; + } + + default: + JSON_THROW(type_error::create(302, "type must be number, but is " + std::string(j.type_name()))); + } +} + +template +void from_json(const BasicJsonType& j, std::pair& p) +{ + p = {j.at(0).template get(), j.at(1).template get()}; +} + +template +void from_json_tuple_impl(const BasicJsonType& j, Tuple& t, index_sequence) +{ + t = std::make_tuple(j.at(Idx).template get::type>()...); +} + +template +void from_json(const BasicJsonType& j, std::tuple& t) +{ + from_json_tuple_impl(j, t, index_sequence_for {}); +} + +struct from_json_fn +{ + private: + template + auto call(const BasicJsonType& j, T& val, priority_tag<1> /*unused*/) const + noexcept(noexcept(from_json(j, val))) + -> decltype(from_json(j, val), void()) + { + return from_json(j, val); + } + + template + void call(const BasicJsonType& /*unused*/, T& /*unused*/, priority_tag<0> /*unused*/) const noexcept + { + static_assert(sizeof(BasicJsonType) == 0, + "could not find from_json() method in T's namespace"); +#ifdef _MSC_VER + // MSVC does not show a stacktrace for the above assert + using decayed = uncvref_t; + static_assert(sizeof(typename decayed::force_msvc_stacktrace) == 0, + "forcing MSVC stacktrace to show which T we're talking about."); +#endif + } + + public: + template + void operator()(const BasicJsonType& j, T& val) const + noexcept(noexcept(std::declval().call(j, val, priority_tag<1> {}))) + { + return call(j, val, priority_tag<1> {}); + } +}; +} + +/// namespace to hold default `from_json` function +/// to see why this is required: +/// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html +namespace +{ +constexpr const auto& from_json = detail::static_const::value; +} +} + +#endif + +/*** End of inlined file: from_json.hpp ***/ + + +/*** Start of inlined file: to_json.hpp ***/ +#ifndef NLOHMANN_JSON_DETAIL_CONVERSIONS_TO_JSON_HPP +#define NLOHMANN_JSON_DETAIL_CONVERSIONS_TO_JSON_HPP + +#include // or, and, not +#include // begin, end +#include // tuple, get +#include // is_same, is_constructible, is_floating_point, is_enum, underlying_type +#include // move, forward, declval, pair +#include // valarray +#include // vector + +namespace nlohmann +{ +namespace detail +{ +////////////////// +// constructors // +////////////////// + +template struct external_constructor; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, typename BasicJsonType::boolean_t b) noexcept + { + j.m_type = value_t::boolean; + j.m_value = b; + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, const typename BasicJsonType::string_t& s) + { + j.m_type = value_t::string; + j.m_value = s; + j.assert_invariant(); + } + + template + static void construct(BasicJsonType& j, typename BasicJsonType::string_t&& s) + { + j.m_type = value_t::string; + j.m_value = std::move(s); + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, typename BasicJsonType::number_float_t val) noexcept + { + j.m_type = value_t::number_float; + j.m_value = val; + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, typename BasicJsonType::number_unsigned_t val) noexcept + { + j.m_type = value_t::number_unsigned; + j.m_value = val; + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, typename BasicJsonType::number_integer_t val) noexcept + { + j.m_type = value_t::number_integer; + j.m_value = val; + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, const typename BasicJsonType::array_t& arr) + { + j.m_type = value_t::array; + j.m_value = arr; + j.assert_invariant(); + } + + template + static void construct(BasicJsonType& j, typename BasicJsonType::array_t&& arr) + { + j.m_type = value_t::array; + j.m_value = std::move(arr); + j.assert_invariant(); + } + + template::value, + int> = 0> + static void construct(BasicJsonType& j, const CompatibleArrayType& arr) + { + using std::begin; + using std::end; + j.m_type = value_t::array; + j.m_value.array = j.template create(begin(arr), end(arr)); + j.assert_invariant(); + } + + template + static void construct(BasicJsonType& j, const std::vector& arr) + { + j.m_type = value_t::array; + j.m_value = value_t::array; + j.m_value.array->reserve(arr.size()); + for (const bool x : arr) + { + j.m_value.array->push_back(x); + } + j.assert_invariant(); + } + + template::value, int> = 0> + static void construct(BasicJsonType& j, const std::valarray& arr) + { + j.m_type = value_t::array; + j.m_value = value_t::array; + j.m_value.array->resize(arr.size()); + std::copy(std::begin(arr), std::end(arr), j.m_value.array->begin()); + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, const typename BasicJsonType::object_t& obj) + { + j.m_type = value_t::object; + j.m_value = obj; + j.assert_invariant(); + } + + template + static void construct(BasicJsonType& j, typename BasicJsonType::object_t&& obj) + { + j.m_type = value_t::object; + j.m_value = std::move(obj); + j.assert_invariant(); + } + + template::value, int> = 0> + static void construct(BasicJsonType& j, const CompatibleObjectType& obj) + { + using std::begin; + using std::end; + + j.m_type = value_t::object; + j.m_value.object = j.template create(begin(obj), end(obj)); + j.assert_invariant(); + } +}; + +///////////// +// to_json // +///////////// + +template::value, int> = 0> +void to_json(BasicJsonType& j, T b) noexcept +{ + external_constructor::construct(j, b); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, const CompatibleString& s) +{ + external_constructor::construct(j, s); +} + +template +void to_json(BasicJsonType& j, typename BasicJsonType::string_t&& s) +{ + external_constructor::construct(j, std::move(s)); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, FloatType val) noexcept +{ + external_constructor::construct(j, static_cast(val)); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, CompatibleNumberUnsignedType val) noexcept +{ + external_constructor::construct(j, static_cast(val)); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, CompatibleNumberIntegerType val) noexcept +{ + external_constructor::construct(j, static_cast(val)); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, EnumType e) noexcept +{ + using underlying_type = typename std::underlying_type::type; + external_constructor::construct(j, static_cast(e)); +} + +template +void to_json(BasicJsonType& j, const std::vector& e) +{ + external_constructor::construct(j, e); +} + +template::value or + std::is_same::value, + int> = 0> +void to_json(BasicJsonType& j, const CompatibleArrayType& arr) +{ + external_constructor::construct(j, arr); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, std::valarray arr) +{ + external_constructor::construct(j, std::move(arr)); +} + +template +void to_json(BasicJsonType& j, typename BasicJsonType::array_t&& arr) +{ + external_constructor::construct(j, std::move(arr)); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, const CompatibleObjectType& obj) +{ + external_constructor::construct(j, obj); +} + +template +void to_json(BasicJsonType& j, typename BasicJsonType::object_t&& obj) +{ + external_constructor::construct(j, std::move(obj)); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, T (&arr)[N]) +{ + external_constructor::construct(j, arr); +} + +template +void to_json(BasicJsonType& j, const std::pair& p) +{ + j = {p.first, p.second}; +} + +template +void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence) +{ + j = {std::get(t)...}; +} + +template +void to_json(BasicJsonType& j, const std::tuple& t) +{ + to_json_tuple_impl(j, t, index_sequence_for {}); +} + +struct to_json_fn +{ + private: + template + auto call(BasicJsonType& j, T&& val, priority_tag<1> /*unused*/) const noexcept(noexcept(to_json(j, std::forward(val)))) + -> decltype(to_json(j, std::forward(val)), void()) + { + return to_json(j, std::forward(val)); + } + + template + void call(BasicJsonType& /*unused*/, T&& /*unused*/, priority_tag<0> /*unused*/) const noexcept + { + static_assert(sizeof(BasicJsonType) == 0, + "could not find to_json() method in T's namespace"); + +#ifdef _MSC_VER + // MSVC does not show a stacktrace for the above assert + using decayed = uncvref_t; + static_assert(sizeof(typename decayed::force_msvc_stacktrace) == 0, + "forcing MSVC stacktrace to show which T we're talking about."); +#endif + } + + public: + template + void operator()(BasicJsonType& j, T&& val) const + noexcept(noexcept(std::declval().call(j, std::forward(val), priority_tag<1> {}))) + { + return call(j, std::forward(val), priority_tag<1> {}); + } +}; +} + +/// namespace to hold default `to_json` function +namespace +{ +constexpr const auto& to_json = detail::static_const::value; +} +} + +#endif + +/*** End of inlined file: to_json.hpp ***/ + + +/*** Start of inlined file: input_adapters.hpp ***/ +#ifndef NLOHMANN_JSON_DETAIL_PARSING_INPUT_ADAPTERS_HPP +#define NLOHMANN_JSON_DETAIL_PARSING_INPUT_ADAPTERS_HPP + +#include // min +#include // array +#include // assert +#include // size_t +#include // strlen +#include // streamsize, streamoff, streampos +#include // istream +#include // begin, end, iterator_traits, random_access_iterator_tag, distance, next +#include // shared_ptr, make_shared, addressof +#include // accumulate +#include // string, char_traits +#include // enable_if, is_base_of, is_pointer, is_integral, remove_pointer +#include // pair, declval + +namespace nlohmann +{ +namespace detail +{ +//////////////////// +// input adapters // +//////////////////// + +/*! +@brief abstract input adapter interface + +Produces a stream of std::char_traits::int_type characters from a +std::istream, a buffer, or some other input type. Accepts the return of exactly +one non-EOF character for future input. The int_type characters returned +consist of all valid char values as positive values (typically unsigned char), +plus an EOF value outside that range, specified by the value of the function +std::char_traits::eof(). This value is typically -1, but could be any +arbitrary value which is not a valid char value. +*/ +struct input_adapter_protocol +{ + /// get a character [0,255] or std::char_traits::eof(). + virtual std::char_traits::int_type get_character() = 0; + /// restore the last non-eof() character to input + virtual void unget_character() = 0; + virtual ~input_adapter_protocol() = default; +}; + +/// a type to simplify interfaces +using input_adapter_t = std::shared_ptr; + +/*! +Input adapter for a (caching) istream. Ignores a UFT Byte Order Mark at +beginning of input. Does not support changing the underlying std::streambuf +in mid-input. Maintains underlying std::istream and std::streambuf to support +subsequent use of standard std::istream operations to process any input +characters following those used in parsing the JSON input. Clears the +std::istream flags; any input errors (e.g., EOF) will be detected by the first +subsequent call for input from the std::istream. +*/ +class input_stream_adapter : public input_adapter_protocol +{ + public: + ~input_stream_adapter() override + { + // clear stream flags; we use underlying streambuf I/O, do not + // maintain ifstream flags + is.clear(); + } + + explicit input_stream_adapter(std::istream& i) + : is(i), sb(*i.rdbuf()) + { + // skip byte order mark + std::char_traits::int_type c; + if ((c = get_character()) == 0xEF) + { + if ((c = get_character()) == 0xBB) + { + if ((c = get_character()) == 0xBF) + { + return; // Ignore BOM + } + else if (c != std::char_traits::eof()) + { + is.unget(); + } + is.putback('\xBB'); + } + else if (c != std::char_traits::eof()) + { + is.unget(); + } + is.putback('\xEF'); + } + else if (c != std::char_traits::eof()) + { + is.unget(); // no byte order mark; process as usual + } + } + + // delete because of pointer members + input_stream_adapter(const input_stream_adapter&) = delete; + input_stream_adapter& operator=(input_stream_adapter&) = delete; + + // std::istream/std::streambuf use std::char_traits::to_int_type, to + // ensure that std::char_traits::eof() and the character 0xFF do not + // end up as the same value, eg. 0xFFFFFFFF. + std::char_traits::int_type get_character() override + { + return sb.sbumpc(); + } + + void unget_character() override + { + sb.sungetc(); // is.unget() avoided for performance + } + + private: + /// the associated input stream + std::istream& is; + std::streambuf& sb; +}; + +/// input adapter for buffer input +class input_buffer_adapter : public input_adapter_protocol +{ + public: + input_buffer_adapter(const char* b, const std::size_t l) + : cursor(b), limit(b + l), start(b) + { + // skip byte order mark + if (l >= 3 and b[0] == '\xEF' and b[1] == '\xBB' and b[2] == '\xBF') + { + cursor += 3; + } + } + + // delete because of pointer members + input_buffer_adapter(const input_buffer_adapter&) = delete; + input_buffer_adapter& operator=(input_buffer_adapter&) = delete; + + std::char_traits::int_type get_character() noexcept override + { + if (JSON_LIKELY(cursor < limit)) + { + return std::char_traits::to_int_type(*(cursor++)); + } + + return std::char_traits::eof(); + } + + void unget_character() noexcept override + { + if (JSON_LIKELY(cursor > start)) + { + --cursor; + } + } + + private: + /// pointer to the current character + const char* cursor; + /// pointer past the last character + const char* limit; + /// pointer to the first character + const char* start; +}; + +class input_adapter +{ + public: + // native support + + /// input adapter for input stream + input_adapter(std::istream& i) + : ia(std::make_shared(i)) {} + + /// input adapter for input stream + input_adapter(std::istream&& i) + : ia(std::make_shared(i)) {} + + /// input adapter for buffer + template::value and + std::is_integral::type>::value and + sizeof(typename std::remove_pointer::type) == 1, + int>::type = 0> + input_adapter(CharT b, std::size_t l) + : ia(std::make_shared(reinterpret_cast(b), l)) {} + + // derived support + + /// input adapter for string literal + template::value and + std::is_integral::type>::value and + sizeof(typename std::remove_pointer::type) == 1, + int>::type = 0> + input_adapter(CharT b) + : input_adapter(reinterpret_cast(b), + std::strlen(reinterpret_cast(b))) {} + + /// input adapter for iterator range with contiguous storage + template::iterator_category, std::random_access_iterator_tag>::value, + int>::type = 0> + input_adapter(IteratorType first, IteratorType last) + { + // assertion to check that the iterator range is indeed contiguous, + // see http://stackoverflow.com/a/35008842/266378 for more discussion + assert(std::accumulate( + first, last, std::pair(true, 0), + [&first](std::pair res, decltype(*first) val) + { + res.first &= (val == *(std::next(std::addressof(*first), res.second++))); + return res; + }).first); + + // assertion to check that each element is 1 byte long + static_assert( + sizeof(typename std::iterator_traits::value_type) == 1, + "each element in the iterator range must have the size of 1 byte"); + + const auto len = static_cast(std::distance(first, last)); + if (JSON_LIKELY(len > 0)) + { + // there is at least one element: use the address of first + ia = std::make_shared(reinterpret_cast(&(*first)), len); + } + else + { + // the address of first cannot be used: use nullptr + ia = std::make_shared(nullptr, len); + } + } + + /// input adapter for array + template + input_adapter(T (&array)[N]) + : input_adapter(std::begin(array), std::end(array)) {} + + /// input adapter for contiguous container + template::value and + std::is_base_of()))>::iterator_category>::value, + int>::type = 0> + input_adapter(const ContiguousContainer& c) + : input_adapter(std::begin(c), std::end(c)) {} + + operator input_adapter_t() + { + return ia; + } + + private: + /// the actual adapter + input_adapter_t ia = nullptr; +}; +} +} + +#endif + +/*** End of inlined file: input_adapters.hpp ***/ + + +/*** Start of inlined file: lexer.hpp ***/ +#ifndef NLOHMANN_JSON_DETAIL_PARSING_LEXER_HPP +#define NLOHMANN_JSON_DETAIL_PARSING_LEXER_HPP + +#include // localeconv +#include // size_t +#include // strtof, strtod, strtold, strtoll, strtoull +#include // initializer_list +#include // hex, uppercase +#include // setw, setfill +#include // stringstream +#include // char_traits, string +#include // vector + + +/*** Start of inlined file: input_adapters.hpp ***/ +#ifndef NLOHMANN_JSON_DETAIL_PARSING_INPUT_ADAPTERS_HPP +#define NLOHMANN_JSON_DETAIL_PARSING_INPUT_ADAPTERS_HPP + +#include // min +#include // array +#include // assert +#include // size_t +#include // strlen +#include // streamsize, streamoff, streampos +#include // istream +#include // begin, end, iterator_traits, random_access_iterator_tag, distance, next +#include // shared_ptr, make_shared, addressof +#include // accumulate +#include // string, char_traits +#include // enable_if, is_base_of, is_pointer, is_integral, remove_pointer +#include // pair, declval + +namespace nlohmann +{ +namespace detail +{ +//////////////////// +// input adapters // +//////////////////// + +/*! +@brief abstract input adapter interface + +Produces a stream of std::char_traits::int_type characters from a +std::istream, a buffer, or some other input type. Accepts the return of exactly +one non-EOF character for future input. The int_type characters returned +consist of all valid char values as positive values (typically unsigned char), +plus an EOF value outside that range, specified by the value of the function +std::char_traits::eof(). This value is typically -1, but could be any +arbitrary value which is not a valid char value. +*/ +struct input_adapter_protocol +{ + /// get a character [0,255] or std::char_traits::eof(). + virtual std::char_traits::int_type get_character() = 0; + /// restore the last non-eof() character to input + virtual void unget_character() = 0; + virtual ~input_adapter_protocol() = default; +}; + +/// a type to simplify interfaces +using input_adapter_t = std::shared_ptr; + +/*! +Input adapter for a (caching) istream. Ignores a UFT Byte Order Mark at +beginning of input. Does not support changing the underlying std::streambuf +in mid-input. Maintains underlying std::istream and std::streambuf to support +subsequent use of standard std::istream operations to process any input +characters following those used in parsing the JSON input. Clears the +std::istream flags; any input errors (e.g., EOF) will be detected by the first +subsequent call for input from the std::istream. +*/ +class input_stream_adapter : public input_adapter_protocol +{ + public: + ~input_stream_adapter() override + { + // clear stream flags; we use underlying streambuf I/O, do not + // maintain ifstream flags + is.clear(); + } + + explicit input_stream_adapter(std::istream& i) + : is(i), sb(*i.rdbuf()) + { + // skip byte order mark + std::char_traits::int_type c; + if ((c = get_character()) == 0xEF) + { + if ((c = get_character()) == 0xBB) + { + if ((c = get_character()) == 0xBF) + { + return; // Ignore BOM + } + else if (c != std::char_traits::eof()) + { + is.unget(); + } + is.putback('\xBB'); + } + else if (c != std::char_traits::eof()) + { + is.unget(); + } + is.putback('\xEF'); + } + else if (c != std::char_traits::eof()) + { + is.unget(); // no byte order mark; process as usual + } + } + + // delete because of pointer members + input_stream_adapter(const input_stream_adapter&) = delete; + input_stream_adapter& operator=(input_stream_adapter&) = delete; + + // std::istream/std::streambuf use std::char_traits::to_int_type, to + // ensure that std::char_traits::eof() and the character 0xFF do not + // end up as the same value, eg. 0xFFFFFFFF. + std::char_traits::int_type get_character() override + { + return sb.sbumpc(); + } + + void unget_character() override + { + sb.sungetc(); // is.unget() avoided for performance + } + + private: + /// the associated input stream + std::istream& is; + std::streambuf& sb; +}; + +/// input adapter for buffer input +class input_buffer_adapter : public input_adapter_protocol +{ + public: + input_buffer_adapter(const char* b, const std::size_t l) + : cursor(b), limit(b + l), start(b) + { + // skip byte order mark + if (l >= 3 and b[0] == '\xEF' and b[1] == '\xBB' and b[2] == '\xBF') + { + cursor += 3; + } + } + + // delete because of pointer members + input_buffer_adapter(const input_buffer_adapter&) = delete; + input_buffer_adapter& operator=(input_buffer_adapter&) = delete; + + std::char_traits::int_type get_character() noexcept override + { + if (JSON_LIKELY(cursor < limit)) + { + return std::char_traits::to_int_type(*(cursor++)); + } + + return std::char_traits::eof(); + } + + void unget_character() noexcept override + { + if (JSON_LIKELY(cursor > start)) + { + --cursor; + } + } + + private: + /// pointer to the current character + const char* cursor; + /// pointer past the last character + const char* limit; + /// pointer to the first character + const char* start; +}; + +class input_adapter +{ + public: + // native support + + /// input adapter for input stream + input_adapter(std::istream& i) + : ia(std::make_shared(i)) {} + + /// input adapter for input stream + input_adapter(std::istream&& i) + : ia(std::make_shared(i)) {} + + /// input adapter for buffer + template::value and + std::is_integral::type>::value and + sizeof(typename std::remove_pointer::type) == 1, + int>::type = 0> + input_adapter(CharT b, std::size_t l) + : ia(std::make_shared(reinterpret_cast(b), l)) {} + + // derived support + + /// input adapter for string literal + template::value and + std::is_integral::type>::value and + sizeof(typename std::remove_pointer::type) == 1, + int>::type = 0> + input_adapter(CharT b) + : input_adapter(reinterpret_cast(b), + std::strlen(reinterpret_cast(b))) {} + + /// input adapter for iterator range with contiguous storage + template::iterator_category, std::random_access_iterator_tag>::value, + int>::type = 0> + input_adapter(IteratorType first, IteratorType last) + { + // assertion to check that the iterator range is indeed contiguous, + // see http://stackoverflow.com/a/35008842/266378 for more discussion + assert(std::accumulate( + first, last, std::pair(true, 0), + [&first](std::pair res, decltype(*first) val) + { + res.first &= (val == *(std::next(std::addressof(*first), res.second++))); + return res; + }).first); + + // assertion to check that each element is 1 byte long + static_assert( + sizeof(typename std::iterator_traits::value_type) == 1, + "each element in the iterator range must have the size of 1 byte"); + + const auto len = static_cast(std::distance(first, last)); + if (JSON_LIKELY(len > 0)) + { + // there is at least one element: use the address of first + ia = std::make_shared(reinterpret_cast(&(*first)), len); + } + else + { + // the address of first cannot be used: use nullptr + ia = std::make_shared(nullptr, len); + } + } + + /// input adapter for array + template + input_adapter(T (&array)[N]) + : input_adapter(std::begin(array), std::end(array)) {} + + /// input adapter for contiguous container + template::value and + std::is_base_of()))>::iterator_category>::value, + int>::type = 0> + input_adapter(const ContiguousContainer& c) + : input_adapter(std::begin(c), std::end(c)) {} + + operator input_adapter_t() + { + return ia; + } + + private: + /// the actual adapter + input_adapter_t ia = nullptr; +}; +} +} + +#endif + +/*** End of inlined file: input_adapters.hpp ***/ + +namespace nlohmann +{ +namespace detail +{ +/////////// +// lexer // +/////////// + +/*! +@brief lexical analysis + +This class organizes the lexical analysis during JSON deserialization. +*/ +template +class lexer +{ + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + + public: + /// token types for the parser + enum class token_type + { + uninitialized, ///< indicating the scanner is uninitialized + literal_true, ///< the `true` literal + literal_false, ///< the `false` literal + literal_null, ///< the `null` literal + value_string, ///< a string -- use get_string() for actual value + value_unsigned, ///< an unsigned integer -- use get_number_unsigned() for actual value + value_integer, ///< a signed integer -- use get_number_integer() for actual value + value_float, ///< an floating point number -- use get_number_float() for actual value + begin_array, ///< the character for array begin `[` + begin_object, ///< the character for object begin `{` + end_array, ///< the character for array end `]` + end_object, ///< the character for object end `}` + name_separator, ///< the name separator `:` + value_separator, ///< the value separator `,` + parse_error, ///< indicating a parse error + end_of_input, ///< indicating the end of the input buffer + literal_or_value ///< a literal or the begin of a value (only for diagnostics) + }; + + /// return name of values of type token_type (only used for errors) + static const char* token_type_name(const token_type t) noexcept + { + switch (t) + { + case token_type::uninitialized: + return ""; + case token_type::literal_true: + return "true literal"; + case token_type::literal_false: + return "false literal"; + case token_type::literal_null: + return "null literal"; + case token_type::value_string: + return "string literal"; + case lexer::token_type::value_unsigned: + case lexer::token_type::value_integer: + case lexer::token_type::value_float: + return "number literal"; + case token_type::begin_array: + return "'['"; + case token_type::begin_object: + return "'{'"; + case token_type::end_array: + return "']'"; + case token_type::end_object: + return "'}'"; + case token_type::name_separator: + return "':'"; + case token_type::value_separator: + return "','"; + case token_type::parse_error: + return ""; + case token_type::end_of_input: + return "end of input"; + case token_type::literal_or_value: + return "'[', '{', or a literal"; + default: // catch non-enum values + return "unknown token"; // LCOV_EXCL_LINE + } + } + + explicit lexer(detail::input_adapter_t adapter) + : ia(std::move(adapter)), decimal_point_char(get_decimal_point()) {} + + // delete because of pointer members + lexer(const lexer&) = delete; + lexer& operator=(lexer&) = delete; + + private: + ///////////////////// + // locales + ///////////////////// + + /// return the locale-dependent decimal point + static char get_decimal_point() noexcept + { + const auto loc = localeconv(); + assert(loc != nullptr); + return (loc->decimal_point == nullptr) ? '.' : *(loc->decimal_point); + } + + ///////////////////// + // scan functions + ///////////////////// + + /*! + @brief get codepoint from 4 hex characters following `\u` + + For input "\u c1 c2 c3 c4" the codepoint is: + (c1 * 0x1000) + (c2 * 0x0100) + (c3 * 0x0010) + c4 + = (c1 << 12) + (c2 << 8) + (c3 << 4) + (c4 << 0) + + Furthermore, the possible characters '0'..'9', 'A'..'F', and 'a'..'f' + must be converted to the integers 0x0..0x9, 0xA..0xF, 0xA..0xF, resp. The + conversion is done by subtracting the offset (0x30, 0x37, and 0x57) + between the ASCII value of the character and the desired integer value. + + @return codepoint (0x0000..0xFFFF) or -1 in case of an error (e.g. EOF or + non-hex character) + */ + int get_codepoint() + { + // this function only makes sense after reading `\u` + assert(current == 'u'); + int codepoint = 0; + + const auto factors = { 12, 8, 4, 0 }; + for (const auto factor : factors) + { + get(); + + if (current >= '0' and current <= '9') + { + codepoint += ((current - 0x30) << factor); + } + else if (current >= 'A' and current <= 'F') + { + codepoint += ((current - 0x37) << factor); + } + else if (current >= 'a' and current <= 'f') + { + codepoint += ((current - 0x57) << factor); + } + else + { + return -1; + } + } + + assert(0x0000 <= codepoint and codepoint <= 0xFFFF); + return codepoint; + } + + /*! + @brief check if the next byte(s) are inside a given range + + Adds the current byte and, for each passed range, reads a new byte and + checks if it is inside the range. If a violation was detected, set up an + error message and return false. Otherwise, return true. + + @param[in] ranges list of integers; interpreted as list of pairs of + inclusive lower and upper bound, respectively + + @pre The passed list @a ranges must have 2, 4, or 6 elements; that is, + 1, 2, or 3 pairs. This precondition is enforced by an assertion. + + @return true if and only if no range violation was detected + */ + bool next_byte_in_range(std::initializer_list ranges) + { + assert(ranges.size() == 2 or ranges.size() == 4 or ranges.size() == 6); + add(current); + + for (auto range = ranges.begin(); range != ranges.end(); ++range) + { + get(); + if (JSON_LIKELY(*range <= current and current <= *(++range))) + { + add(current); + } + else + { + error_message = "invalid string: ill-formed UTF-8 byte"; + return false; + } + } + + return true; + } + + /*! + @brief scan a string literal + + This function scans a string according to Sect. 7 of RFC 7159. While + scanning, bytes are escaped and copied into buffer yytext. Then the function + returns successfully, yytext is *not* null-terminated (as it may contain \0 + bytes), and yytext.size() is the number of bytes in the string. + + @return token_type::value_string if string could be successfully scanned, + token_type::parse_error otherwise + + @note In case of errors, variable error_message contains a textual + description. + */ + token_type scan_string() + { + // reset yytext (ignore opening quote) + reset(); + + // we entered the function by reading an open quote + assert(current == '\"'); + + while (true) + { + // get next character + switch (get()) + { + // end of file while parsing string + case std::char_traits::eof(): + { + error_message = "invalid string: missing closing quote"; + return token_type::parse_error; + } + + // closing quote + case '\"': + { + return token_type::value_string; + } + + // escapes + case '\\': + { + switch (get()) + { + // quotation mark + case '\"': + add('\"'); + break; + // reverse solidus + case '\\': + add('\\'); + break; + // solidus + case '/': + add('/'); + break; + // backspace + case 'b': + add('\b'); + break; + // form feed + case 'f': + add('\f'); + break; + // line feed + case 'n': + add('\n'); + break; + // carriage return + case 'r': + add('\r'); + break; + // tab + case 't': + add('\t'); + break; + + // unicode escapes + case 'u': + { + const int codepoint1 = get_codepoint(); + int codepoint = codepoint1; // start with codepoint1 + + if (JSON_UNLIKELY(codepoint1 == -1)) + { + error_message = "invalid string: '\\u' must be followed by 4 hex digits"; + return token_type::parse_error; + } + + // check if code point is a high surrogate + if (0xD800 <= codepoint1 and codepoint1 <= 0xDBFF) + { + // expect next \uxxxx entry + if (JSON_LIKELY(get() == '\\' and get() == 'u')) + { + const int codepoint2 = get_codepoint(); + + if (JSON_UNLIKELY(codepoint2 == -1)) + { + error_message = "invalid string: '\\u' must be followed by 4 hex digits"; + return token_type::parse_error; + } + + // check if codepoint2 is a low surrogate + if (JSON_LIKELY(0xDC00 <= codepoint2 and codepoint2 <= 0xDFFF)) + { + // overwrite codepoint + codepoint = + // high surrogate occupies the most significant 22 bits + (codepoint1 << 10) + // low surrogate occupies the least significant 15 bits + + codepoint2 + // there is still the 0xD800, 0xDC00 and 0x10000 noise + // in the result so we have to subtract with: + // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00 + - 0x35FDC00; + } + else + { + error_message = "invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF"; + return token_type::parse_error; + } + } + else + { + error_message = "invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF"; + return token_type::parse_error; + } + } + else + { + if (JSON_UNLIKELY(0xDC00 <= codepoint1 and codepoint1 <= 0xDFFF)) + { + error_message = "invalid string: surrogate U+DC00..U+DFFF must follow U+D800..U+DBFF"; + return token_type::parse_error; + } + } + + // result of the above calculation yields a proper codepoint + assert(0x00 <= codepoint and codepoint <= 0x10FFFF); + + // translate codepoint into bytes + if (codepoint < 0x80) + { + // 1-byte characters: 0xxxxxxx (ASCII) + add(codepoint); + } + else if (codepoint <= 0x7FF) + { + // 2-byte characters: 110xxxxx 10xxxxxx + add(0xC0 | (codepoint >> 6)); + add(0x80 | (codepoint & 0x3F)); + } + else if (codepoint <= 0xFFFF) + { + // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx + add(0xE0 | (codepoint >> 12)); + add(0x80 | ((codepoint >> 6) & 0x3F)); + add(0x80 | (codepoint & 0x3F)); + } + else + { + // 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + add(0xF0 | (codepoint >> 18)); + add(0x80 | ((codepoint >> 12) & 0x3F)); + add(0x80 | ((codepoint >> 6) & 0x3F)); + add(0x80 | (codepoint & 0x3F)); + } + + break; + } + + // other characters after escape + default: + error_message = "invalid string: forbidden character after backslash"; + return token_type::parse_error; + } + + break; + } + + // invalid control characters + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + case 0x09: + case 0x0A: + case 0x0B: + case 0x0C: + case 0x0D: + case 0x0E: + case 0x0F: + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + case 0x1A: + case 0x1B: + case 0x1C: + case 0x1D: + case 0x1E: + case 0x1F: + { + error_message = "invalid string: control character must be escaped"; + return token_type::parse_error; + } + + // U+0020..U+007F (except U+0022 (quote) and U+005C (backspace)) + case 0x20: + case 0x21: + case 0x23: + case 0x24: + case 0x25: + case 0x26: + case 0x27: + case 0x28: + case 0x29: + case 0x2A: + case 0x2B: + case 0x2C: + case 0x2D: + case 0x2E: + case 0x2F: + case 0x30: + case 0x31: + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: + case 0x38: + case 0x39: + case 0x3A: + case 0x3B: + case 0x3C: + case 0x3D: + case 0x3E: + case 0x3F: + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + case 0x48: + case 0x49: + case 0x4A: + case 0x4B: + case 0x4C: + case 0x4D: + case 0x4E: + case 0x4F: + case 0x50: + case 0x51: + case 0x52: + case 0x53: + case 0x54: + case 0x55: + case 0x56: + case 0x57: + case 0x58: + case 0x59: + case 0x5A: + case 0x5B: + case 0x5D: + case 0x5E: + case 0x5F: + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: + case 0x68: + case 0x69: + case 0x6A: + case 0x6B: + case 0x6C: + case 0x6D: + case 0x6E: + case 0x6F: + case 0x70: + case 0x71: + case 0x72: + case 0x73: + case 0x74: + case 0x75: + case 0x76: + case 0x77: + case 0x78: + case 0x79: + case 0x7A: + case 0x7B: + case 0x7C: + case 0x7D: + case 0x7E: + case 0x7F: + { + add(current); + break; + } + + // U+0080..U+07FF: bytes C2..DF 80..BF + case 0xC2: + case 0xC3: + case 0xC4: + case 0xC5: + case 0xC6: + case 0xC7: + case 0xC8: + case 0xC9: + case 0xCA: + case 0xCB: + case 0xCC: + case 0xCD: + case 0xCE: + case 0xCF: + case 0xD0: + case 0xD1: + case 0xD2: + case 0xD3: + case 0xD4: + case 0xD5: + case 0xD6: + case 0xD7: + case 0xD8: + case 0xD9: + case 0xDA: + case 0xDB: + case 0xDC: + case 0xDD: + case 0xDE: + case 0xDF: + { + if (JSON_UNLIKELY(not next_byte_in_range({0x80, 0xBF}))) + { + return token_type::parse_error; + } + break; + } + + // U+0800..U+0FFF: bytes E0 A0..BF 80..BF + case 0xE0: + { + if (JSON_UNLIKELY(not (next_byte_in_range({0xA0, 0xBF, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // U+1000..U+CFFF: bytes E1..EC 80..BF 80..BF + // U+E000..U+FFFF: bytes EE..EF 80..BF 80..BF + case 0xE1: + case 0xE2: + case 0xE3: + case 0xE4: + case 0xE5: + case 0xE6: + case 0xE7: + case 0xE8: + case 0xE9: + case 0xEA: + case 0xEB: + case 0xEC: + case 0xEE: + case 0xEF: + { + if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0xBF, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // U+D000..U+D7FF: bytes ED 80..9F 80..BF + case 0xED: + { + if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0x9F, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // U+10000..U+3FFFF F0 90..BF 80..BF 80..BF + case 0xF0: + { + if (JSON_UNLIKELY(not (next_byte_in_range({0x90, 0xBF, 0x80, 0xBF, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // U+40000..U+FFFFF F1..F3 80..BF 80..BF 80..BF + case 0xF1: + case 0xF2: + case 0xF3: + { + if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0xBF, 0x80, 0xBF, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // U+100000..U+10FFFF F4 80..8F 80..BF 80..BF + case 0xF4: + { + if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0x8F, 0x80, 0xBF, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // remaining bytes (80..C1 and F5..FF) are ill-formed + default: + { + error_message = "invalid string: ill-formed UTF-8 byte"; + return token_type::parse_error; + } + } + } + } + + static void strtof(float& f, const char* str, char** endptr) noexcept + { + f = std::strtof(str, endptr); + } + + static void strtof(double& f, const char* str, char** endptr) noexcept + { + f = std::strtod(str, endptr); + } + + static void strtof(long double& f, const char* str, char** endptr) noexcept + { + f = std::strtold(str, endptr); + } + + /*! + @brief scan a number literal + + This function scans a string according to Sect. 6 of RFC 7159. + + The function is realized with a deterministic finite state machine derived + from the grammar described in RFC 7159. Starting in state "init", the + input is read and used to determined the next state. Only state "done" + accepts the number. State "error" is a trap state to model errors. In the + table below, "anything" means any character but the ones listed before. + + state | 0 | 1-9 | e E | + | - | . | anything + ---------|----------|----------|----------|---------|---------|----------|----------- + init | zero | any1 | [error] | [error] | minus | [error] | [error] + minus | zero | any1 | [error] | [error] | [error] | [error] | [error] + zero | done | done | exponent | done | done | decimal1 | done + any1 | any1 | any1 | exponent | done | done | decimal1 | done + decimal1 | decimal2 | [error] | [error] | [error] | [error] | [error] | [error] + decimal2 | decimal2 | decimal2 | exponent | done | done | done | done + exponent | any2 | any2 | [error] | sign | sign | [error] | [error] + sign | any2 | any2 | [error] | [error] | [error] | [error] | [error] + any2 | any2 | any2 | done | done | done | done | done + + The state machine is realized with one label per state (prefixed with + "scan_number_") and `goto` statements between them. The state machine + contains cycles, but any cycle can be left when EOF is read. Therefore, + the function is guaranteed to terminate. + + During scanning, the read bytes are stored in yytext. This string is + then converted to a signed integer, an unsigned integer, or a + floating-point number. + + @return token_type::value_unsigned, token_type::value_integer, or + token_type::value_float if number could be successfully scanned, + token_type::parse_error otherwise + + @note The scanner is independent of the current locale. Internally, the + locale's decimal point is used instead of `.` to work with the + locale-dependent converters. + */ + token_type scan_number() + { + // reset yytext to store the number's bytes + reset(); + + // the type of the parsed number; initially set to unsigned; will be + // changed if minus sign, decimal point or exponent is read + token_type number_type = token_type::value_unsigned; + + // state (init): we just found out we need to scan a number + switch (current) + { + case '-': + { + add(current); + goto scan_number_minus; + } + + case '0': + { + add(current); + goto scan_number_zero; + } + + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any1; + } + + default: + { + // all other characters are rejected outside scan_number() + assert(false); // LCOV_EXCL_LINE + } + } + +scan_number_minus: + // state: we just parsed a leading minus sign + number_type = token_type::value_integer; + switch (get()) + { + case '0': + { + add(current); + goto scan_number_zero; + } + + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any1; + } + + default: + { + error_message = "invalid number; expected digit after '-'"; + return token_type::parse_error; + } + } + +scan_number_zero: + // state: we just parse a zero (maybe with a leading minus sign) + switch (get()) + { + case '.': + { + add(decimal_point_char); + goto scan_number_decimal1; + } + + case 'e': + case 'E': + { + add(current); + goto scan_number_exponent; + } + + default: + goto scan_number_done; + } + +scan_number_any1: + // state: we just parsed a number 0-9 (maybe with a leading minus sign) + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any1; + } + + case '.': + { + add(decimal_point_char); + goto scan_number_decimal1; + } + + case 'e': + case 'E': + { + add(current); + goto scan_number_exponent; + } + + default: + goto scan_number_done; + } + +scan_number_decimal1: + // state: we just parsed a decimal point + number_type = token_type::value_float; + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_decimal2; + } + + default: + { + error_message = "invalid number; expected digit after '.'"; + return token_type::parse_error; + } + } + +scan_number_decimal2: + // we just parsed at least one number after a decimal point + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_decimal2; + } + + case 'e': + case 'E': + { + add(current); + goto scan_number_exponent; + } + + default: + goto scan_number_done; + } + +scan_number_exponent: + // we just parsed an exponent + number_type = token_type::value_float; + switch (get()) + { + case '+': + case '-': + { + add(current); + goto scan_number_sign; + } + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any2; + } + + default: + { + error_message = + "invalid number; expected '+', '-', or digit after exponent"; + return token_type::parse_error; + } + } + +scan_number_sign: + // we just parsed an exponent sign + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any2; + } + + default: + { + error_message = "invalid number; expected digit after exponent sign"; + return token_type::parse_error; + } + } + +scan_number_any2: + // we just parsed a number after the exponent or exponent sign + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any2; + } + + default: + goto scan_number_done; + } + +scan_number_done: + // unget the character after the number (we only read it to know that + // we are done scanning a number) + unget(); + + char* endptr = nullptr; + errno = 0; + + // try to parse integers first and fall back to floats + if (number_type == token_type::value_unsigned) + { + const auto x = std::strtoull(yytext.data(), &endptr, 10); + + // we checked the number format before + assert(endptr == yytext.data() + yytext.size()); + + if (errno == 0) + { + value_unsigned = static_cast(x); + if (value_unsigned == x) + { + return token_type::value_unsigned; + } + } + } + else if (number_type == token_type::value_integer) + { + const auto x = std::strtoll(yytext.data(), &endptr, 10); + + // we checked the number format before + assert(endptr == yytext.data() + yytext.size()); + + if (errno == 0) + { + value_integer = static_cast(x); + if (value_integer == x) + { + return token_type::value_integer; + } + } + } + + // this code is reached if we parse a floating-point number or if an + // integer conversion above failed + strtof(value_float, yytext.data(), &endptr); + + // we checked the number format before + assert(endptr == yytext.data() + yytext.size()); + + return token_type::value_float; + } + + /*! + @param[in] literal_text the literal text to expect + @param[in] length the length of the passed literal text + @param[in] return_type the token type to return on success + */ + token_type scan_literal(const char* literal_text, const std::size_t length, + token_type return_type) + { + assert(current == literal_text[0]); + for (std::size_t i = 1; i < length; ++i) + { + if (JSON_UNLIKELY(get() != literal_text[i])) + { + error_message = "invalid literal"; + return token_type::parse_error; + } + } + return return_type; + } + + ///////////////////// + // input management + ///////////////////// + + /// reset yytext; current character is beginning of token + void reset() noexcept + { + yytext.clear(); + token_string.clear(); + token_string.push_back(std::char_traits::to_char_type(current)); + } + + /* + @brief get next character from the input + + This function provides the interface to the used input adapter. It does + not throw in case the input reached EOF, but returns a + `std::char_traits::eof()` in that case. Stores the scanned characters + for use in error messages. + + @return character read from the input + */ + std::char_traits::int_type get() + { + ++chars_read; + current = ia->get_character(); + if (JSON_LIKELY(current != std::char_traits::eof())) + { + token_string.push_back(std::char_traits::to_char_type(current)); + } + return current; + } + + /// unget current character (return it again on next get) + void unget() + { + --chars_read; + if (JSON_LIKELY(current != std::char_traits::eof())) + { + ia->unget_character(); + assert(token_string.size() != 0); + token_string.pop_back(); + } + } + + /// add a character to yytext + void add(int c) + { + yytext.push_back(std::char_traits::to_char_type(c)); + } + + public: + ///////////////////// + // value getters + ///////////////////// + + /// return integer value + constexpr number_integer_t get_number_integer() const noexcept + { + return value_integer; + } + + /// return unsigned integer value + constexpr number_unsigned_t get_number_unsigned() const noexcept + { + return value_unsigned; + } + + /// return floating-point value + constexpr number_float_t get_number_float() const noexcept + { + return value_float; + } + + /// return current string value (implicitly resets the token; useful only once) + std::string move_string() + { + return std::move(yytext); + } + + ///////////////////// + // diagnostics + ///////////////////// + + /// return position of last read token + constexpr std::size_t get_position() const noexcept + { + return chars_read; + } + + /// return the last read token (for errors only). Will never contain EOF + /// (an arbitrary value that is not a valid char value, often -1), because + /// 255 may legitimately occur. May contain NUL, which should be escaped. + std::string get_token_string() const + { + // escape control characters + std::string result; + for (const auto c : token_string) + { + if ('\x00' <= c and c <= '\x1F') + { + // escape control characters + std::stringstream ss; + ss << "(c) << ">"; + result += ss.str(); + } + else + { + // add character as is + result.push_back(c); + } + } + + return result; + } + + /// return syntax error message + constexpr const char* get_error_message() const noexcept + { + return error_message; + } + + ///////////////////// + // actual scanner + ///////////////////// + + token_type scan() + { + // read next character and ignore whitespace + do + { + get(); + } + while (current == ' ' or current == '\t' or current == '\n' or current == '\r'); + + switch (current) + { + // structural characters + case '[': + return token_type::begin_array; + case ']': + return token_type::end_array; + case '{': + return token_type::begin_object; + case '}': + return token_type::end_object; + case ':': + return token_type::name_separator; + case ',': + return token_type::value_separator; + + // literals + case 't': + return scan_literal("true", 4, token_type::literal_true); + case 'f': + return scan_literal("false", 5, token_type::literal_false); + case 'n': + return scan_literal("null", 4, token_type::literal_null); + + // string + case '\"': + return scan_string(); + + // number + case '-': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + return scan_number(); + + // end of input (the null byte is needed when parsing from + // string literals) + case '\0': + case std::char_traits::eof(): + return token_type::end_of_input; + + // error + default: + error_message = "invalid literal"; + return token_type::parse_error; + } + } + + private: + /// input adapter + detail::input_adapter_t ia = nullptr; + + /// the current character + std::char_traits::int_type current = std::char_traits::eof(); + + /// the number of characters read + std::size_t chars_read = 0; + + /// raw input token string (for error messages) + std::vector token_string {}; + + /// buffer for variable-length tokens (numbers, strings) + std::string yytext {}; + + /// a description of occurred lexer errors + const char* error_message = ""; + + // number values + number_integer_t value_integer = 0; + number_unsigned_t value_unsigned = 0; + number_float_t value_float = 0; + + /// the decimal point + const char decimal_point_char = '.'; +}; +} +} + +#endif + +/*** End of inlined file: lexer.hpp ***/ + + +/*** Start of inlined file: parser.hpp ***/ +#ifndef NLOHMANN_JSON_DETAIL_PARSING_PARSER_HPP +#define NLOHMANN_JSON_DETAIL_PARSING_PARSER_HPP + +#include // assert +#include // isfinite +#include // uint8_t +#include // function +#include // string +#include // move + + +/*** Start of inlined file: lexer.hpp ***/ +#ifndef NLOHMANN_JSON_DETAIL_PARSING_LEXER_HPP +#define NLOHMANN_JSON_DETAIL_PARSING_LEXER_HPP + +#include // localeconv +#include // size_t +#include // strtof, strtod, strtold, strtoll, strtoull +#include // initializer_list +#include // hex, uppercase +#include // setw, setfill +#include // stringstream +#include // char_traits, string +#include // vector + +namespace nlohmann +{ +namespace detail +{ +/////////// +// lexer // +/////////// + +/*! +@brief lexical analysis + +This class organizes the lexical analysis during JSON deserialization. +*/ +template +class lexer +{ + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + + public: + /// token types for the parser + enum class token_type + { + uninitialized, ///< indicating the scanner is uninitialized + literal_true, ///< the `true` literal + literal_false, ///< the `false` literal + literal_null, ///< the `null` literal + value_string, ///< a string -- use get_string() for actual value + value_unsigned, ///< an unsigned integer -- use get_number_unsigned() for actual value + value_integer, ///< a signed integer -- use get_number_integer() for actual value + value_float, ///< an floating point number -- use get_number_float() for actual value + begin_array, ///< the character for array begin `[` + begin_object, ///< the character for object begin `{` + end_array, ///< the character for array end `]` + end_object, ///< the character for object end `}` + name_separator, ///< the name separator `:` + value_separator, ///< the value separator `,` + parse_error, ///< indicating a parse error + end_of_input, ///< indicating the end of the input buffer + literal_or_value ///< a literal or the begin of a value (only for diagnostics) + }; + + /// return name of values of type token_type (only used for errors) + static const char* token_type_name(const token_type t) noexcept + { + switch (t) + { + case token_type::uninitialized: + return ""; + case token_type::literal_true: + return "true literal"; + case token_type::literal_false: + return "false literal"; + case token_type::literal_null: + return "null literal"; + case token_type::value_string: + return "string literal"; + case lexer::token_type::value_unsigned: + case lexer::token_type::value_integer: + case lexer::token_type::value_float: + return "number literal"; + case token_type::begin_array: + return "'['"; + case token_type::begin_object: + return "'{'"; + case token_type::end_array: + return "']'"; + case token_type::end_object: + return "'}'"; + case token_type::name_separator: + return "':'"; + case token_type::value_separator: + return "','"; + case token_type::parse_error: + return ""; + case token_type::end_of_input: + return "end of input"; + case token_type::literal_or_value: + return "'[', '{', or a literal"; + default: // catch non-enum values + return "unknown token"; // LCOV_EXCL_LINE + } + } + + explicit lexer(detail::input_adapter_t adapter) + : ia(std::move(adapter)), decimal_point_char(get_decimal_point()) {} + + // delete because of pointer members + lexer(const lexer&) = delete; + lexer& operator=(lexer&) = delete; + + private: + ///////////////////// + // locales + ///////////////////// + + /// return the locale-dependent decimal point + static char get_decimal_point() noexcept + { + const auto loc = localeconv(); + assert(loc != nullptr); + return (loc->decimal_point == nullptr) ? '.' : *(loc->decimal_point); + } + + ///////////////////// + // scan functions + ///////////////////// + + /*! + @brief get codepoint from 4 hex characters following `\u` + + For input "\u c1 c2 c3 c4" the codepoint is: + (c1 * 0x1000) + (c2 * 0x0100) + (c3 * 0x0010) + c4 + = (c1 << 12) + (c2 << 8) + (c3 << 4) + (c4 << 0) + + Furthermore, the possible characters '0'..'9', 'A'..'F', and 'a'..'f' + must be converted to the integers 0x0..0x9, 0xA..0xF, 0xA..0xF, resp. The + conversion is done by subtracting the offset (0x30, 0x37, and 0x57) + between the ASCII value of the character and the desired integer value. + + @return codepoint (0x0000..0xFFFF) or -1 in case of an error (e.g. EOF or + non-hex character) + */ + int get_codepoint() + { + // this function only makes sense after reading `\u` + assert(current == 'u'); + int codepoint = 0; + + const auto factors = { 12, 8, 4, 0 }; + for (const auto factor : factors) + { + get(); + + if (current >= '0' and current <= '9') + { + codepoint += ((current - 0x30) << factor); + } + else if (current >= 'A' and current <= 'F') + { + codepoint += ((current - 0x37) << factor); + } + else if (current >= 'a' and current <= 'f') + { + codepoint += ((current - 0x57) << factor); + } + else + { + return -1; + } + } + + assert(0x0000 <= codepoint and codepoint <= 0xFFFF); + return codepoint; + } + + /*! + @brief check if the next byte(s) are inside a given range + + Adds the current byte and, for each passed range, reads a new byte and + checks if it is inside the range. If a violation was detected, set up an + error message and return false. Otherwise, return true. + + @param[in] ranges list of integers; interpreted as list of pairs of + inclusive lower and upper bound, respectively + + @pre The passed list @a ranges must have 2, 4, or 6 elements; that is, + 1, 2, or 3 pairs. This precondition is enforced by an assertion. + + @return true if and only if no range violation was detected + */ + bool next_byte_in_range(std::initializer_list ranges) + { + assert(ranges.size() == 2 or ranges.size() == 4 or ranges.size() == 6); + add(current); + + for (auto range = ranges.begin(); range != ranges.end(); ++range) + { + get(); + if (JSON_LIKELY(*range <= current and current <= *(++range))) + { + add(current); + } + else + { + error_message = "invalid string: ill-formed UTF-8 byte"; + return false; + } + } + + return true; + } + + /*! + @brief scan a string literal + + This function scans a string according to Sect. 7 of RFC 7159. While + scanning, bytes are escaped and copied into buffer yytext. Then the function + returns successfully, yytext is *not* null-terminated (as it may contain \0 + bytes), and yytext.size() is the number of bytes in the string. + + @return token_type::value_string if string could be successfully scanned, + token_type::parse_error otherwise + + @note In case of errors, variable error_message contains a textual + description. + */ + token_type scan_string() + { + // reset yytext (ignore opening quote) + reset(); + + // we entered the function by reading an open quote + assert(current == '\"'); + + while (true) + { + // get next character + switch (get()) + { + // end of file while parsing string + case std::char_traits::eof(): + { + error_message = "invalid string: missing closing quote"; + return token_type::parse_error; + } + + // closing quote + case '\"': + { + return token_type::value_string; + } + + // escapes + case '\\': + { + switch (get()) + { + // quotation mark + case '\"': + add('\"'); + break; + // reverse solidus + case '\\': + add('\\'); + break; + // solidus + case '/': + add('/'); + break; + // backspace + case 'b': + add('\b'); + break; + // form feed + case 'f': + add('\f'); + break; + // line feed + case 'n': + add('\n'); + break; + // carriage return + case 'r': + add('\r'); + break; + // tab + case 't': + add('\t'); + break; + + // unicode escapes + case 'u': + { + const int codepoint1 = get_codepoint(); + int codepoint = codepoint1; // start with codepoint1 + + if (JSON_UNLIKELY(codepoint1 == -1)) + { + error_message = "invalid string: '\\u' must be followed by 4 hex digits"; + return token_type::parse_error; + } + + // check if code point is a high surrogate + if (0xD800 <= codepoint1 and codepoint1 <= 0xDBFF) + { + // expect next \uxxxx entry + if (JSON_LIKELY(get() == '\\' and get() == 'u')) + { + const int codepoint2 = get_codepoint(); + + if (JSON_UNLIKELY(codepoint2 == -1)) + { + error_message = "invalid string: '\\u' must be followed by 4 hex digits"; + return token_type::parse_error; + } + + // check if codepoint2 is a low surrogate + if (JSON_LIKELY(0xDC00 <= codepoint2 and codepoint2 <= 0xDFFF)) + { + // overwrite codepoint + codepoint = + // high surrogate occupies the most significant 22 bits + (codepoint1 << 10) + // low surrogate occupies the least significant 15 bits + + codepoint2 + // there is still the 0xD800, 0xDC00 and 0x10000 noise + // in the result so we have to subtract with: + // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00 + - 0x35FDC00; + } + else + { + error_message = "invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF"; + return token_type::parse_error; + } + } + else + { + error_message = "invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF"; + return token_type::parse_error; + } + } + else + { + if (JSON_UNLIKELY(0xDC00 <= codepoint1 and codepoint1 <= 0xDFFF)) + { + error_message = "invalid string: surrogate U+DC00..U+DFFF must follow U+D800..U+DBFF"; + return token_type::parse_error; + } + } + + // result of the above calculation yields a proper codepoint + assert(0x00 <= codepoint and codepoint <= 0x10FFFF); + + // translate codepoint into bytes + if (codepoint < 0x80) + { + // 1-byte characters: 0xxxxxxx (ASCII) + add(codepoint); + } + else if (codepoint <= 0x7FF) + { + // 2-byte characters: 110xxxxx 10xxxxxx + add(0xC0 | (codepoint >> 6)); + add(0x80 | (codepoint & 0x3F)); + } + else if (codepoint <= 0xFFFF) + { + // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx + add(0xE0 | (codepoint >> 12)); + add(0x80 | ((codepoint >> 6) & 0x3F)); + add(0x80 | (codepoint & 0x3F)); + } + else + { + // 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + add(0xF0 | (codepoint >> 18)); + add(0x80 | ((codepoint >> 12) & 0x3F)); + add(0x80 | ((codepoint >> 6) & 0x3F)); + add(0x80 | (codepoint & 0x3F)); + } + + break; + } + + // other characters after escape + default: + error_message = "invalid string: forbidden character after backslash"; + return token_type::parse_error; + } + + break; + } + + // invalid control characters + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + case 0x09: + case 0x0A: + case 0x0B: + case 0x0C: + case 0x0D: + case 0x0E: + case 0x0F: + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + case 0x1A: + case 0x1B: + case 0x1C: + case 0x1D: + case 0x1E: + case 0x1F: + { + error_message = "invalid string: control character must be escaped"; + return token_type::parse_error; + } + + // U+0020..U+007F (except U+0022 (quote) and U+005C (backspace)) + case 0x20: + case 0x21: + case 0x23: + case 0x24: + case 0x25: + case 0x26: + case 0x27: + case 0x28: + case 0x29: + case 0x2A: + case 0x2B: + case 0x2C: + case 0x2D: + case 0x2E: + case 0x2F: + case 0x30: + case 0x31: + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: + case 0x38: + case 0x39: + case 0x3A: + case 0x3B: + case 0x3C: + case 0x3D: + case 0x3E: + case 0x3F: + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + case 0x48: + case 0x49: + case 0x4A: + case 0x4B: + case 0x4C: + case 0x4D: + case 0x4E: + case 0x4F: + case 0x50: + case 0x51: + case 0x52: + case 0x53: + case 0x54: + case 0x55: + case 0x56: + case 0x57: + case 0x58: + case 0x59: + case 0x5A: + case 0x5B: + case 0x5D: + case 0x5E: + case 0x5F: + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: + case 0x68: + case 0x69: + case 0x6A: + case 0x6B: + case 0x6C: + case 0x6D: + case 0x6E: + case 0x6F: + case 0x70: + case 0x71: + case 0x72: + case 0x73: + case 0x74: + case 0x75: + case 0x76: + case 0x77: + case 0x78: + case 0x79: + case 0x7A: + case 0x7B: + case 0x7C: + case 0x7D: + case 0x7E: + case 0x7F: + { + add(current); + break; + } + + // U+0080..U+07FF: bytes C2..DF 80..BF + case 0xC2: + case 0xC3: + case 0xC4: + case 0xC5: + case 0xC6: + case 0xC7: + case 0xC8: + case 0xC9: + case 0xCA: + case 0xCB: + case 0xCC: + case 0xCD: + case 0xCE: + case 0xCF: + case 0xD0: + case 0xD1: + case 0xD2: + case 0xD3: + case 0xD4: + case 0xD5: + case 0xD6: + case 0xD7: + case 0xD8: + case 0xD9: + case 0xDA: + case 0xDB: + case 0xDC: + case 0xDD: + case 0xDE: + case 0xDF: + { + if (JSON_UNLIKELY(not next_byte_in_range({0x80, 0xBF}))) + { + return token_type::parse_error; + } + break; + } + + // U+0800..U+0FFF: bytes E0 A0..BF 80..BF + case 0xE0: + { + if (JSON_UNLIKELY(not (next_byte_in_range({0xA0, 0xBF, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // U+1000..U+CFFF: bytes E1..EC 80..BF 80..BF + // U+E000..U+FFFF: bytes EE..EF 80..BF 80..BF + case 0xE1: + case 0xE2: + case 0xE3: + case 0xE4: + case 0xE5: + case 0xE6: + case 0xE7: + case 0xE8: + case 0xE9: + case 0xEA: + case 0xEB: + case 0xEC: + case 0xEE: + case 0xEF: + { + if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0xBF, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // U+D000..U+D7FF: bytes ED 80..9F 80..BF + case 0xED: + { + if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0x9F, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // U+10000..U+3FFFF F0 90..BF 80..BF 80..BF + case 0xF0: + { + if (JSON_UNLIKELY(not (next_byte_in_range({0x90, 0xBF, 0x80, 0xBF, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // U+40000..U+FFFFF F1..F3 80..BF 80..BF 80..BF + case 0xF1: + case 0xF2: + case 0xF3: + { + if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0xBF, 0x80, 0xBF, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // U+100000..U+10FFFF F4 80..8F 80..BF 80..BF + case 0xF4: + { + if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0x8F, 0x80, 0xBF, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // remaining bytes (80..C1 and F5..FF) are ill-formed + default: + { + error_message = "invalid string: ill-formed UTF-8 byte"; + return token_type::parse_error; + } + } + } + } + + static void strtof(float& f, const char* str, char** endptr) noexcept + { + f = std::strtof(str, endptr); + } + + static void strtof(double& f, const char* str, char** endptr) noexcept + { + f = std::strtod(str, endptr); + } + + static void strtof(long double& f, const char* str, char** endptr) noexcept + { + f = std::strtold(str, endptr); + } + + /*! + @brief scan a number literal + + This function scans a string according to Sect. 6 of RFC 7159. + + The function is realized with a deterministic finite state machine derived + from the grammar described in RFC 7159. Starting in state "init", the + input is read and used to determined the next state. Only state "done" + accepts the number. State "error" is a trap state to model errors. In the + table below, "anything" means any character but the ones listed before. + + state | 0 | 1-9 | e E | + | - | . | anything + ---------|----------|----------|----------|---------|---------|----------|----------- + init | zero | any1 | [error] | [error] | minus | [error] | [error] + minus | zero | any1 | [error] | [error] | [error] | [error] | [error] + zero | done | done | exponent | done | done | decimal1 | done + any1 | any1 | any1 | exponent | done | done | decimal1 | done + decimal1 | decimal2 | [error] | [error] | [error] | [error] | [error] | [error] + decimal2 | decimal2 | decimal2 | exponent | done | done | done | done + exponent | any2 | any2 | [error] | sign | sign | [error] | [error] + sign | any2 | any2 | [error] | [error] | [error] | [error] | [error] + any2 | any2 | any2 | done | done | done | done | done + + The state machine is realized with one label per state (prefixed with + "scan_number_") and `goto` statements between them. The state machine + contains cycles, but any cycle can be left when EOF is read. Therefore, + the function is guaranteed to terminate. + + During scanning, the read bytes are stored in yytext. This string is + then converted to a signed integer, an unsigned integer, or a + floating-point number. + + @return token_type::value_unsigned, token_type::value_integer, or + token_type::value_float if number could be successfully scanned, + token_type::parse_error otherwise + + @note The scanner is independent of the current locale. Internally, the + locale's decimal point is used instead of `.` to work with the + locale-dependent converters. + */ + token_type scan_number() + { + // reset yytext to store the number's bytes + reset(); + + // the type of the parsed number; initially set to unsigned; will be + // changed if minus sign, decimal point or exponent is read + token_type number_type = token_type::value_unsigned; + + // state (init): we just found out we need to scan a number + switch (current) + { + case '-': + { + add(current); + goto scan_number_minus; + } + + case '0': + { + add(current); + goto scan_number_zero; + } + + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any1; + } + + default: + { + // all other characters are rejected outside scan_number() + assert(false); // LCOV_EXCL_LINE + } + } + +scan_number_minus: + // state: we just parsed a leading minus sign + number_type = token_type::value_integer; + switch (get()) + { + case '0': + { + add(current); + goto scan_number_zero; + } + + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any1; + } + + default: + { + error_message = "invalid number; expected digit after '-'"; + return token_type::parse_error; + } + } + +scan_number_zero: + // state: we just parse a zero (maybe with a leading minus sign) + switch (get()) + { + case '.': + { + add(decimal_point_char); + goto scan_number_decimal1; + } + + case 'e': + case 'E': + { + add(current); + goto scan_number_exponent; + } + + default: + goto scan_number_done; + } + +scan_number_any1: + // state: we just parsed a number 0-9 (maybe with a leading minus sign) + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any1; + } + + case '.': + { + add(decimal_point_char); + goto scan_number_decimal1; + } + + case 'e': + case 'E': + { + add(current); + goto scan_number_exponent; + } + + default: + goto scan_number_done; + } + +scan_number_decimal1: + // state: we just parsed a decimal point + number_type = token_type::value_float; + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_decimal2; + } + + default: + { + error_message = "invalid number; expected digit after '.'"; + return token_type::parse_error; + } + } + +scan_number_decimal2: + // we just parsed at least one number after a decimal point + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_decimal2; + } + + case 'e': + case 'E': + { + add(current); + goto scan_number_exponent; + } + + default: + goto scan_number_done; + } + +scan_number_exponent: + // we just parsed an exponent + number_type = token_type::value_float; + switch (get()) + { + case '+': + case '-': + { + add(current); + goto scan_number_sign; + } + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any2; + } + + default: + { + error_message = + "invalid number; expected '+', '-', or digit after exponent"; + return token_type::parse_error; + } + } + +scan_number_sign: + // we just parsed an exponent sign + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any2; + } + + default: + { + error_message = "invalid number; expected digit after exponent sign"; + return token_type::parse_error; + } + } + +scan_number_any2: + // we just parsed a number after the exponent or exponent sign + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any2; + } + + default: + goto scan_number_done; + } + +scan_number_done: + // unget the character after the number (we only read it to know that + // we are done scanning a number) + unget(); + + char* endptr = nullptr; + errno = 0; + + // try to parse integers first and fall back to floats + if (number_type == token_type::value_unsigned) + { + const auto x = std::strtoull(yytext.data(), &endptr, 10); + + // we checked the number format before + assert(endptr == yytext.data() + yytext.size()); + + if (errno == 0) + { + value_unsigned = static_cast(x); + if (value_unsigned == x) + { + return token_type::value_unsigned; + } + } + } + else if (number_type == token_type::value_integer) + { + const auto x = std::strtoll(yytext.data(), &endptr, 10); + + // we checked the number format before + assert(endptr == yytext.data() + yytext.size()); + + if (errno == 0) + { + value_integer = static_cast(x); + if (value_integer == x) + { + return token_type::value_integer; + } + } + } + + // this code is reached if we parse a floating-point number or if an + // integer conversion above failed + strtof(value_float, yytext.data(), &endptr); + + // we checked the number format before + assert(endptr == yytext.data() + yytext.size()); + + return token_type::value_float; + } + + /*! + @param[in] literal_text the literal text to expect + @param[in] length the length of the passed literal text + @param[in] return_type the token type to return on success + */ + token_type scan_literal(const char* literal_text, const std::size_t length, + token_type return_type) + { + assert(current == literal_text[0]); + for (std::size_t i = 1; i < length; ++i) + { + if (JSON_UNLIKELY(get() != literal_text[i])) + { + error_message = "invalid literal"; + return token_type::parse_error; + } + } + return return_type; + } + + ///////////////////// + // input management + ///////////////////// + + /// reset yytext; current character is beginning of token + void reset() noexcept + { + yytext.clear(); + token_string.clear(); + token_string.push_back(std::char_traits::to_char_type(current)); + } + + /* + @brief get next character from the input + + This function provides the interface to the used input adapter. It does + not throw in case the input reached EOF, but returns a + `std::char_traits::eof()` in that case. Stores the scanned characters + for use in error messages. + + @return character read from the input + */ + std::char_traits::int_type get() + { + ++chars_read; + current = ia->get_character(); + if (JSON_LIKELY(current != std::char_traits::eof())) + { + token_string.push_back(std::char_traits::to_char_type(current)); + } + return current; + } + + /// unget current character (return it again on next get) + void unget() + { + --chars_read; + if (JSON_LIKELY(current != std::char_traits::eof())) + { + ia->unget_character(); + assert(token_string.size() != 0); + token_string.pop_back(); + } + } + + /// add a character to yytext + void add(int c) + { + yytext.push_back(std::char_traits::to_char_type(c)); + } + + public: + ///////////////////// + // value getters + ///////////////////// + + /// return integer value + constexpr number_integer_t get_number_integer() const noexcept + { + return value_integer; + } + + /// return unsigned integer value + constexpr number_unsigned_t get_number_unsigned() const noexcept + { + return value_unsigned; + } + + /// return floating-point value + constexpr number_float_t get_number_float() const noexcept + { + return value_float; + } + + /// return current string value (implicitly resets the token; useful only once) + std::string move_string() + { + return std::move(yytext); + } + + ///////////////////// + // diagnostics + ///////////////////// + + /// return position of last read token + constexpr std::size_t get_position() const noexcept + { + return chars_read; + } + + /// return the last read token (for errors only). Will never contain EOF + /// (an arbitrary value that is not a valid char value, often -1), because + /// 255 may legitimately occur. May contain NUL, which should be escaped. + std::string get_token_string() const + { + // escape control characters + std::string result; + for (const auto c : token_string) + { + if ('\x00' <= c and c <= '\x1F') + { + // escape control characters + std::stringstream ss; + ss << "(c) << ">"; + result += ss.str(); + } + else + { + // add character as is + result.push_back(c); + } + } + + return result; + } + + /// return syntax error message + constexpr const char* get_error_message() const noexcept + { + return error_message; + } + + ///////////////////// + // actual scanner + ///////////////////// + + token_type scan() + { + // read next character and ignore whitespace + do + { + get(); + } + while (current == ' ' or current == '\t' or current == '\n' or current == '\r'); + + switch (current) + { + // structural characters + case '[': + return token_type::begin_array; + case ']': + return token_type::end_array; + case '{': + return token_type::begin_object; + case '}': + return token_type::end_object; + case ':': + return token_type::name_separator; + case ',': + return token_type::value_separator; + + // literals + case 't': + return scan_literal("true", 4, token_type::literal_true); + case 'f': + return scan_literal("false", 5, token_type::literal_false); + case 'n': + return scan_literal("null", 4, token_type::literal_null); + + // string + case '\"': + return scan_string(); + + // number + case '-': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + return scan_number(); + + // end of input (the null byte is needed when parsing from + // string literals) + case '\0': + case std::char_traits::eof(): + return token_type::end_of_input; + + // error + default: + error_message = "invalid literal"; + return token_type::parse_error; + } + } + + private: + /// input adapter + detail::input_adapter_t ia = nullptr; + + /// the current character + std::char_traits::int_type current = std::char_traits::eof(); + + /// the number of characters read + std::size_t chars_read = 0; + + /// raw input token string (for error messages) + std::vector token_string {}; + + /// buffer for variable-length tokens (numbers, strings) + std::string yytext {}; + + /// a description of occurred lexer errors + const char* error_message = ""; + + // number values + number_integer_t value_integer = 0; + number_unsigned_t value_unsigned = 0; + number_float_t value_float = 0; + + /// the decimal point + const char decimal_point_char = '.'; +}; +} +} + +#endif + +/*** End of inlined file: lexer.hpp ***/ + +namespace nlohmann +{ +namespace detail +{ +//////////// +// parser // +//////////// + +/*! +@brief syntax analysis + +This class implements a recursive decent parser. +*/ +template +class parser +{ + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + using lexer_t = lexer; + using token_type = typename lexer_t::token_type; + + public: + enum class parse_event_t : uint8_t + { + /// the parser read `{` and started to process a JSON object + object_start, + /// the parser read `}` and finished processing a JSON object + object_end, + /// the parser read `[` and started to process a JSON array + array_start, + /// the parser read `]` and finished processing a JSON array + array_end, + /// the parser read a key of a value in an object + key, + /// the parser finished reading a JSON value + value + }; + + using parser_callback_t = + std::function; + + /// a parser reading from an input adapter + explicit parser(detail::input_adapter_t adapter, + const parser_callback_t cb = nullptr, + const bool allow_exceptions_ = true) + : callback(cb), m_lexer(adapter), allow_exceptions(allow_exceptions_) + {} + + /*! + @brief public parser interface + + @param[in] strict whether to expect the last token to be EOF + @param[in,out] result parsed JSON value + + @throw parse_error.101 in case of an unexpected token + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + */ + void parse(const bool strict, BasicJsonType& result) + { + // read first token + get_token(); + + parse_internal(true, result); + result.assert_invariant(); + + // in strict mode, input must be completely read + if (strict) + { + get_token(); + expect(token_type::end_of_input); + } + + // in case of an error, return discarded value + if (errored) + { + result = value_t::discarded; + return; + } + + // set top-level value to null if it was discarded by the callback + // function + if (result.is_discarded()) + { + result = nullptr; + } + } + + /*! + @brief public accept interface + + @param[in] strict whether to expect the last token to be EOF + @return whether the input is a proper JSON text + */ + bool accept(const bool strict = true) + { + // read first token + get_token(); + + if (not accept_internal()) + { + return false; + } + + // strict => last token must be EOF + return not strict or (get_token() == token_type::end_of_input); + } + + private: + /*! + @brief the actual parser + @throw parse_error.101 in case of an unexpected token + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + */ + void parse_internal(bool keep, BasicJsonType& result) + { + // never parse after a parse error was detected + assert(not errored); + + // start with a discarded value + if (not result.is_discarded()) + { + result.m_value.destroy(result.m_type); + result.m_type = value_t::discarded; + } + + switch (last_token) + { + case token_type::begin_object: + { + if (keep) + { + if (callback) + { + keep = callback(depth++, parse_event_t::object_start, result); + } + + if (not callback or keep) + { + // explicitly set result to object to cope with {} + result.m_type = value_t::object; + result.m_value = value_t::object; + } + } + + // read next token + get_token(); + + // closing } -> we are done + if (last_token == token_type::end_object) + { + if (keep and callback and not callback(--depth, parse_event_t::object_end, result)) + { + result.m_value.destroy(result.m_type); + result.m_type = value_t::discarded; + } + break; + } + + // parse values + std::string key; + BasicJsonType value; + while (true) + { + // store key + if (not expect(token_type::value_string)) + { + return; + } + key = m_lexer.move_string(); + + bool keep_tag = false; + if (keep) + { + if (callback) + { + BasicJsonType k(key); + keep_tag = callback(depth, parse_event_t::key, k); + } + else + { + keep_tag = true; + } + } + + // parse separator (:) + get_token(); + if (not expect(token_type::name_separator)) + { + return; + } + + // parse and add value + get_token(); + value.m_value.destroy(value.m_type); + value.m_type = value_t::discarded; + parse_internal(keep, value); + + if (JSON_UNLIKELY(errored)) + { + return; + } + + if (keep and keep_tag and not value.is_discarded()) + { + result.m_value.object->emplace(std::move(key), std::move(value)); + } + + // comma -> next value + get_token(); + if (last_token == token_type::value_separator) + { + get_token(); + continue; + } + + // closing } + if (not expect(token_type::end_object)) + { + return; + } + break; + } + + if (keep and callback and not callback(--depth, parse_event_t::object_end, result)) + { + result.m_value.destroy(result.m_type); + result.m_type = value_t::discarded; + } + break; + } + + case token_type::begin_array: + { + if (keep) + { + if (callback) + { + keep = callback(depth++, parse_event_t::array_start, result); + } + + if (not callback or keep) + { + // explicitly set result to array to cope with [] + result.m_type = value_t::array; + result.m_value = value_t::array; + } + } + + // read next token + get_token(); + + // closing ] -> we are done + if (last_token == token_type::end_array) + { + if (callback and not callback(--depth, parse_event_t::array_end, result)) + { + result.m_value.destroy(result.m_type); + result.m_type = value_t::discarded; + } + break; + } + + // parse values + BasicJsonType value; + while (true) + { + // parse value + value.m_value.destroy(value.m_type); + value.m_type = value_t::discarded; + parse_internal(keep, value); + + if (JSON_UNLIKELY(errored)) + { + return; + } + + if (keep and not value.is_discarded()) + { + result.m_value.array->push_back(std::move(value)); + } + + // comma -> next value + get_token(); + if (last_token == token_type::value_separator) + { + get_token(); + continue; + } + + // closing ] + if (not expect(token_type::end_array)) + { + return; + } + break; + } + + if (keep and callback and not callback(--depth, parse_event_t::array_end, result)) + { + result.m_value.destroy(result.m_type); + result.m_type = value_t::discarded; + } + break; + } + + case token_type::literal_null: + { + result.m_type = value_t::null; + break; + } + + case token_type::value_string: + { + result.m_type = value_t::string; + result.m_value = m_lexer.move_string(); + break; + } + + case token_type::literal_true: + { + result.m_type = value_t::boolean; + result.m_value = true; + break; + } + + case token_type::literal_false: + { + result.m_type = value_t::boolean; + result.m_value = false; + break; + } + + case token_type::value_unsigned: + { + result.m_type = value_t::number_unsigned; + result.m_value = m_lexer.get_number_unsigned(); + break; + } + + case token_type::value_integer: + { + result.m_type = value_t::number_integer; + result.m_value = m_lexer.get_number_integer(); + break; + } + + case token_type::value_float: + { + result.m_type = value_t::number_float; + result.m_value = m_lexer.get_number_float(); + + // throw in case of infinity or NAN + if (JSON_UNLIKELY(not std::isfinite(result.m_value.number_float))) + { + if (allow_exceptions) + { + JSON_THROW(out_of_range::create(406, "number overflow parsing '" + + m_lexer.get_token_string() + "'")); + } + expect(token_type::uninitialized); + } + break; + } + + case token_type::parse_error: + { + // using "uninitialized" to avoid "expected" message + if (not expect(token_type::uninitialized)) + { + return; + } + break; // LCOV_EXCL_LINE + } + + default: + { + // the last token was unexpected; we expected a value + if (not expect(token_type::literal_or_value)) + { + return; + } + break; // LCOV_EXCL_LINE + } + } + + if (keep and callback and not callback(depth, parse_event_t::value, result)) + { + result.m_type = value_t::discarded; + } + } + + /*! + @brief the actual acceptor + + @invariant 1. The last token is not yet processed. Therefore, the caller + of this function must make sure a token has been read. + 2. When this function returns, the last token is processed. + That is, the last read character was already considered. + + This invariant makes sure that no token needs to be "unput". + */ + bool accept_internal() + { + switch (last_token) + { + case token_type::begin_object: + { + // read next token + get_token(); + + // closing } -> we are done + if (last_token == token_type::end_object) + { + return true; + } + + // parse values + while (true) + { + // parse key + if (last_token != token_type::value_string) + { + return false; + } + + // parse separator (:) + get_token(); + if (last_token != token_type::name_separator) + { + return false; + } + + // parse value + get_token(); + if (not accept_internal()) + { + return false; + } + + // comma -> next value + get_token(); + if (last_token == token_type::value_separator) + { + get_token(); + continue; + } + + // closing } + return (last_token == token_type::end_object); + } + } + + case token_type::begin_array: + { + // read next token + get_token(); + + // closing ] -> we are done + if (last_token == token_type::end_array) + { + return true; + } + + // parse values + while (true) + { + // parse value + if (not accept_internal()) + { + return false; + } + + // comma -> next value + get_token(); + if (last_token == token_type::value_separator) + { + get_token(); + continue; + } + + // closing ] + return (last_token == token_type::end_array); + } + } + + case token_type::value_float: + { + // reject infinity or NAN + return std::isfinite(m_lexer.get_number_float()); + } + + case token_type::literal_false: + case token_type::literal_null: + case token_type::literal_true: + case token_type::value_integer: + case token_type::value_string: + case token_type::value_unsigned: + return true; + + default: // the last token was unexpected + return false; + } + } + + /// get next token from lexer + token_type get_token() + { + return (last_token = m_lexer.scan()); + } + + /*! + @throw parse_error.101 if expected token did not occur + */ + bool expect(token_type t) + { + if (JSON_UNLIKELY(t != last_token)) + { + errored = true; + expected = t; + if (allow_exceptions) + { + throw_exception(); + } + else + { + return false; + } + } + + return true; + } + + [[noreturn]] void throw_exception() const + { + std::string error_msg = "syntax error - "; + if (last_token == token_type::parse_error) + { + error_msg += std::string(m_lexer.get_error_message()) + "; last read: '" + + m_lexer.get_token_string() + "'"; + } + else + { + error_msg += "unexpected " + std::string(lexer_t::token_type_name(last_token)); + } + + if (expected != token_type::uninitialized) + { + error_msg += "; expected " + std::string(lexer_t::token_type_name(expected)); + } + + JSON_THROW(parse_error::create(101, m_lexer.get_position(), error_msg)); + } + + private: + /// current level of recursion + int depth = 0; + /// callback function + const parser_callback_t callback = nullptr; + /// the type of the last read token + token_type last_token = token_type::uninitialized; + /// the lexer + lexer_t m_lexer; + /// whether a syntax error occurred + bool errored = false; + /// possible reason for the syntax error + token_type expected = token_type::uninitialized; + /// whether to throw exceptions in case of errors + const bool allow_exceptions = true; +}; +} +} + +#endif + +/*** End of inlined file: parser.hpp ***/ + + +/*** Start of inlined file: primitive_iterator.hpp ***/ +#ifndef NLOHMANN_JSON_DETAIL_ITERATORS_PRIMITIVE_ITERATOR_HPP +#define NLOHMANN_JSON_DETAIL_ITERATORS_PRIMITIVE_ITERATOR_HPP + +#include // not +#include // ptrdiff_t +#include // numeric_limits +#include // ostream + +namespace nlohmann +{ +namespace detail +{ +/* +@brief an iterator for primitive JSON types + +This class models an iterator for primitive JSON types (boolean, number, +string). It's only purpose is to allow the iterator/const_iterator classes +to "iterate" over primitive values. Internally, the iterator is modeled by +a `difference_type` variable. Value begin_value (`0`) models the begin, +end_value (`1`) models past the end. +*/ +class primitive_iterator_t +{ + public: + using difference_type = std::ptrdiff_t; + + constexpr difference_type get_value() const noexcept + { + return m_it; + } + + /// set iterator to a defined beginning + void set_begin() noexcept + { + m_it = begin_value; + } + + /// set iterator to a defined past the end + void set_end() noexcept + { + m_it = end_value; + } + + /// return whether the iterator can be dereferenced + constexpr bool is_begin() const noexcept + { + return m_it == begin_value; + } + + /// return whether the iterator is at end + constexpr bool is_end() const noexcept + { + return m_it == end_value; + } + + friend constexpr bool operator==(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept + { + return lhs.m_it == rhs.m_it; + } + + friend constexpr bool operator<(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept + { + return lhs.m_it < rhs.m_it; + } + + primitive_iterator_t operator+(difference_type i) + { + auto result = *this; + result += i; + return result; + } + + friend constexpr difference_type operator-(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept + { + return lhs.m_it - rhs.m_it; + } + + friend std::ostream& operator<<(std::ostream& os, primitive_iterator_t it) + { + return os << it.m_it; + } + + primitive_iterator_t& operator++() + { + ++m_it; + return *this; + } + + primitive_iterator_t const operator++(int) + { + auto result = *this; + m_it++; + return result; + } + + primitive_iterator_t& operator--() + { + --m_it; + return *this; + } + + primitive_iterator_t const operator--(int) + { + auto result = *this; + m_it--; + return result; + } + + primitive_iterator_t& operator+=(difference_type n) + { + m_it += n; + return *this; + } + + primitive_iterator_t& operator-=(difference_type n) + { + m_it -= n; + return *this; + } + + private: + static constexpr difference_type begin_value = 0; + static constexpr difference_type end_value = begin_value + 1; + + /// iterator as signed integer type + difference_type m_it = (std::numeric_limits::min)(); +}; +} +} + +#endif + +/*** End of inlined file: primitive_iterator.hpp ***/ + + +/*** Start of inlined file: internal_iterator.hpp ***/ +#ifndef NLOHMANN_JSON_DETAIL_ITERATORS_INTERNAL_ITERATOR_HPP +#define NLOHMANN_JSON_DETAIL_ITERATORS_INTERNAL_ITERATOR_HPP + + +/*** Start of inlined file: primitive_iterator.hpp ***/ +#ifndef NLOHMANN_JSON_DETAIL_ITERATORS_PRIMITIVE_ITERATOR_HPP +#define NLOHMANN_JSON_DETAIL_ITERATORS_PRIMITIVE_ITERATOR_HPP + +#include // not +#include // ptrdiff_t +#include // numeric_limits +#include // ostream + +namespace nlohmann +{ +namespace detail +{ +/* +@brief an iterator for primitive JSON types + +This class models an iterator for primitive JSON types (boolean, number, +string). It's only purpose is to allow the iterator/const_iterator classes +to "iterate" over primitive values. Internally, the iterator is modeled by +a `difference_type` variable. Value begin_value (`0`) models the begin, +end_value (`1`) models past the end. +*/ +class primitive_iterator_t +{ + public: + using difference_type = std::ptrdiff_t; + + constexpr difference_type get_value() const noexcept + { + return m_it; + } + + /// set iterator to a defined beginning + void set_begin() noexcept + { + m_it = begin_value; + } + + /// set iterator to a defined past the end + void set_end() noexcept + { + m_it = end_value; + } + + /// return whether the iterator can be dereferenced + constexpr bool is_begin() const noexcept + { + return m_it == begin_value; + } + + /// return whether the iterator is at end + constexpr bool is_end() const noexcept + { + return m_it == end_value; + } + + friend constexpr bool operator==(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept + { + return lhs.m_it == rhs.m_it; + } + + friend constexpr bool operator<(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept + { + return lhs.m_it < rhs.m_it; + } + + primitive_iterator_t operator+(difference_type i) + { + auto result = *this; + result += i; + return result; + } + + friend constexpr difference_type operator-(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept + { + return lhs.m_it - rhs.m_it; + } + + friend std::ostream& operator<<(std::ostream& os, primitive_iterator_t it) + { + return os << it.m_it; + } + + primitive_iterator_t& operator++() + { + ++m_it; + return *this; + } + + primitive_iterator_t const operator++(int) + { + auto result = *this; + m_it++; + return result; + } + + primitive_iterator_t& operator--() + { + --m_it; + return *this; + } + + primitive_iterator_t const operator--(int) + { + auto result = *this; + m_it--; + return result; + } + + primitive_iterator_t& operator+=(difference_type n) + { + m_it += n; + return *this; + } + + primitive_iterator_t& operator-=(difference_type n) + { + m_it -= n; + return *this; + } + + private: + static constexpr difference_type begin_value = 0; + static constexpr difference_type end_value = begin_value + 1; + + /// iterator as signed integer type + difference_type m_it = (std::numeric_limits::min)(); +}; +} +} + +#endif + +/*** End of inlined file: primitive_iterator.hpp ***/ + +namespace nlohmann +{ +namespace detail +{ +/*! +@brief an iterator value + +@note This structure could easily be a union, but MSVC currently does not allow +unions members with complex constructors, see https://github.com/nlohmann/json/pull/105. +*/ +template struct internal_iterator +{ + /// iterator for JSON objects + typename BasicJsonType::object_t::iterator object_iterator {}; + /// iterator for JSON arrays + typename BasicJsonType::array_t::iterator array_iterator {}; + /// generic iterator for all other types + primitive_iterator_t primitive_iterator {}; +}; +} +} + +#endif + +/*** End of inlined file: internal_iterator.hpp ***/ + + +/*** Start of inlined file: iter_impl.hpp ***/ +#ifndef NLOHMANN_JSON_DETAIL_ITERATORS_ITER_IMPL_HPP +#define NLOHMANN_JSON_DETAIL_ITERATORS_ITER_IMPL_HPP + +#include // not +#include // iterator, random_access_iterator_tag, bidirectional_iterator_tag, advance, next +#include // conditional, is_const, remove_const + + +/*** Start of inlined file: internal_iterator.hpp ***/ +#ifndef NLOHMANN_JSON_DETAIL_ITERATORS_INTERNAL_ITERATOR_HPP +#define NLOHMANN_JSON_DETAIL_ITERATORS_INTERNAL_ITERATOR_HPP + +namespace nlohmann +{ +namespace detail +{ +/*! +@brief an iterator value + +@note This structure could easily be a union, but MSVC currently does not allow +unions members with complex constructors, see https://github.com/nlohmann/json/pull/105. +*/ +template struct internal_iterator +{ + /// iterator for JSON objects + typename BasicJsonType::object_t::iterator object_iterator {}; + /// iterator for JSON arrays + typename BasicJsonType::array_t::iterator array_iterator {}; + /// generic iterator for all other types + primitive_iterator_t primitive_iterator {}; +}; +} +} + +#endif + +/*** End of inlined file: internal_iterator.hpp ***/ + +namespace nlohmann +{ +namespace detail +{ +// forward declare, to be able to friend it later on +template class iteration_proxy; + +/*! +@brief a template for a bidirectional iterator for the @ref basic_json class + +This class implements a both iterators (iterator and const_iterator) for the +@ref basic_json class. + +@note An iterator is called *initialized* when a pointer to a JSON value has + been set (e.g., by a constructor or a copy assignment). If the iterator is + default-constructed, it is *uninitialized* and most methods are undefined. + **The library uses assertions to detect calls on uninitialized iterators.** + +@requirement The class satisfies the following concept requirements: +- +[BidirectionalIterator](http://en.cppreference.com/w/cpp/concept/BidirectionalIterator): + The iterator that can be moved can be moved in both directions (i.e. + incremented and decremented). + +@since version 1.0.0, simplified in version 2.0.9, change to bidirectional + iterators in version 3.0.0 (see https://github.com/nlohmann/json/issues/593) +*/ +template +class iter_impl +{ + /// allow basic_json to access private members + friend iter_impl::value, typename std::remove_const::type, const BasicJsonType>::type>; + friend BasicJsonType; + friend iteration_proxy; + + using object_t = typename BasicJsonType::object_t; + using array_t = typename BasicJsonType::array_t; + // make sure BasicJsonType is basic_json or const basic_json + static_assert(is_basic_json::type>::value, + "iter_impl only accepts (const) basic_json"); + + public: + + /// The std::iterator class template (used as a base class to provide typedefs) is deprecated in C++17. + /// The C++ Standard has never required user-defined iterators to derive from std::iterator. + /// A user-defined iterator should provide publicly accessible typedefs named + /// iterator_category, value_type, difference_type, pointer, and reference. + /// Note that value_type is required to be non-const, even for constant iterators. + using iterator_category = std::bidirectional_iterator_tag; + + /// the type of the values when the iterator is dereferenced + using value_type = typename BasicJsonType::value_type; + /// a type to represent differences between iterators + using difference_type = typename BasicJsonType::difference_type; + /// defines a pointer to the type iterated over (value_type) + using pointer = typename std::conditional::value, + typename BasicJsonType::const_pointer, + typename BasicJsonType::pointer>::type; + /// defines a reference to the type iterated over (value_type) + using reference = + typename std::conditional::value, + typename BasicJsonType::const_reference, + typename BasicJsonType::reference>::type; + + /// default constructor + iter_impl() = default; + + /*! + @brief constructor for a given JSON instance + @param[in] object pointer to a JSON object for this iterator + @pre object != nullptr + @post The iterator is initialized; i.e. `m_object != nullptr`. + */ + explicit iter_impl(pointer object) noexcept : m_object(object) + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + { + m_it.object_iterator = typename object_t::iterator(); + break; + } + + case value_t::array: + { + m_it.array_iterator = typename array_t::iterator(); + break; + } + + default: + { + m_it.primitive_iterator = primitive_iterator_t(); + break; + } + } + } + + /*! + @note The conventional copy constructor and copy assignment are implicitly + defined. Combined with the following converting constructor and + assignment, they support: (1) copy from iterator to iterator, (2) + copy from const iterator to const iterator, and (3) conversion from + iterator to const iterator. However conversion from const iterator + to iterator is not defined. + */ + + /*! + @brief converting constructor + @param[in] other non-const iterator to copy from + @note It is not checked whether @a other is initialized. + */ + iter_impl(const iter_impl::type>& other) noexcept + : m_object(other.m_object), m_it(other.m_it) {} + + /*! + @brief converting assignment + @param[in,out] other non-const iterator to copy from + @return const/non-const iterator + @note It is not checked whether @a other is initialized. + */ + iter_impl& operator=(const iter_impl::type>& other) noexcept + { + m_object = other.m_object; + m_it = other.m_it; + return *this; + } + + private: + /*! + @brief set the iterator to the first value + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + void set_begin() noexcept + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + { + m_it.object_iterator = m_object->m_value.object->begin(); + break; + } + + case value_t::array: + { + m_it.array_iterator = m_object->m_value.array->begin(); + break; + } + + case value_t::null: + { + // set to end so begin()==end() is true: null is empty + m_it.primitive_iterator.set_end(); + break; + } + + default: + { + m_it.primitive_iterator.set_begin(); + break; + } + } + } + + /*! + @brief set the iterator past the last value + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + void set_end() noexcept + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + { + m_it.object_iterator = m_object->m_value.object->end(); + break; + } + + case value_t::array: + { + m_it.array_iterator = m_object->m_value.array->end(); + break; + } + + default: + { + m_it.primitive_iterator.set_end(); + break; + } + } + } + + public: + /*! + @brief return a reference to the value pointed to by the iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + reference operator*() const + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + { + assert(m_it.object_iterator != m_object->m_value.object->end()); + return m_it.object_iterator->second; + } + + case value_t::array: + { + assert(m_it.array_iterator != m_object->m_value.array->end()); + return *m_it.array_iterator; + } + + case value_t::null: + JSON_THROW(invalid_iterator::create(214, "cannot get value")); + + default: + { + if (JSON_LIKELY(m_it.primitive_iterator.is_begin())) + { + return *m_object; + } + + JSON_THROW(invalid_iterator::create(214, "cannot get value")); + } + } + } + + /*! + @brief dereference the iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + pointer operator->() const + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + { + assert(m_it.object_iterator != m_object->m_value.object->end()); + return &(m_it.object_iterator->second); + } + + case value_t::array: + { + assert(m_it.array_iterator != m_object->m_value.array->end()); + return &*m_it.array_iterator; + } + + default: + { + if (JSON_LIKELY(m_it.primitive_iterator.is_begin())) + { + return m_object; + } + + JSON_THROW(invalid_iterator::create(214, "cannot get value")); + } + } + } + + /*! + @brief post-increment (it++) + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl const operator++(int) + { + auto result = *this; + ++(*this); + return result; + } + + /*! + @brief pre-increment (++it) + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl& operator++() + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + { + std::advance(m_it.object_iterator, 1); + break; + } + + case value_t::array: + { + std::advance(m_it.array_iterator, 1); + break; + } + + default: + { + ++m_it.primitive_iterator; + break; + } + } + + return *this; + } + + /*! + @brief post-decrement (it--) + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl const operator--(int) + { + auto result = *this; + --(*this); + return result; + } + + /*! + @brief pre-decrement (--it) + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl& operator--() + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + { + std::advance(m_it.object_iterator, -1); + break; + } + + case value_t::array: + { + std::advance(m_it.array_iterator, -1); + break; + } + + default: + { + --m_it.primitive_iterator; + break; + } + } + + return *this; + } + + /*! + @brief comparison: equal + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + bool operator==(const iter_impl& other) const + { + // if objects are not the same, the comparison is undefined + if (JSON_UNLIKELY(m_object != other.m_object)) + { + JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers")); + } + + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + return (m_it.object_iterator == other.m_it.object_iterator); + + case value_t::array: + return (m_it.array_iterator == other.m_it.array_iterator); + + default: + return (m_it.primitive_iterator == other.m_it.primitive_iterator); + } + } + + /*! + @brief comparison: not equal + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + bool operator!=(const iter_impl& other) const + { + return not operator==(other); + } + + /*! + @brief comparison: smaller + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + bool operator<(const iter_impl& other) const + { + // if objects are not the same, the comparison is undefined + if (JSON_UNLIKELY(m_object != other.m_object)) + { + JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers")); + } + + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + JSON_THROW(invalid_iterator::create(213, "cannot compare order of object iterators")); + + case value_t::array: + return (m_it.array_iterator < other.m_it.array_iterator); + + default: + return (m_it.primitive_iterator < other.m_it.primitive_iterator); + } + } + + /*! + @brief comparison: less than or equal + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + bool operator<=(const iter_impl& other) const + { + return not other.operator < (*this); + } + + /*! + @brief comparison: greater than + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + bool operator>(const iter_impl& other) const + { + return not operator<=(other); + } + + /*! + @brief comparison: greater than or equal + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + bool operator>=(const iter_impl& other) const + { + return not operator<(other); + } + + /*! + @brief add to iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl& operator+=(difference_type i) + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators")); + + case value_t::array: + { + std::advance(m_it.array_iterator, i); + break; + } + + default: + { + m_it.primitive_iterator += i; + break; + } + } + + return *this; + } + + /*! + @brief subtract from iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl& operator-=(difference_type i) + { + return operator+=(-i); + } + + /*! + @brief add to iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl operator+(difference_type i) const + { + auto result = *this; + result += i; + return result; + } + + /*! + @brief addition of distance and iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + friend iter_impl operator+(difference_type i, const iter_impl& it) + { + auto result = it; + result += i; + return result; + } + + /*! + @brief subtract from iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl operator-(difference_type i) const + { + auto result = *this; + result -= i; + return result; + } + + /*! + @brief return difference + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + difference_type operator-(const iter_impl& other) const + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators")); + + case value_t::array: + return m_it.array_iterator - other.m_it.array_iterator; + + default: + return m_it.primitive_iterator - other.m_it.primitive_iterator; + } + } + + /*! + @brief access to successor + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + reference operator[](difference_type n) const + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + JSON_THROW(invalid_iterator::create(208, "cannot use operator[] for object iterators")); + + case value_t::array: + return *std::next(m_it.array_iterator, n); + + case value_t::null: + JSON_THROW(invalid_iterator::create(214, "cannot get value")); + + default: + { + if (JSON_LIKELY(m_it.primitive_iterator.get_value() == -n)) + { + return *m_object; + } + + JSON_THROW(invalid_iterator::create(214, "cannot get value")); + } + } + } + + /*! + @brief return the key of an object iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + typename object_t::key_type key() const + { + assert(m_object != nullptr); + + if (JSON_LIKELY(m_object->is_object())) + { + return m_it.object_iterator->first; + } + + JSON_THROW(invalid_iterator::create(207, "cannot use key() for non-object iterators")); + } + + /*! + @brief return the value of an iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + reference value() const + { + return operator*(); + } + + private: + /// associated JSON instance + pointer m_object = nullptr; + /// the actual iterator of the associated instance + internal_iterator::type> m_it = {}; +}; +} +} + +#endif + +/*** End of inlined file: iter_impl.hpp ***/ + + +/*** Start of inlined file: iteration_proxy.hpp ***/ +#ifndef NLOHMANN_JSON_DETAIL_ITERATORS_ITERATION_PROXY_HPP +#define NLOHMANN_JSON_DETAIL_ITERATORS_ITERATION_PROXY_HPP + +#include // size_t +#include // string, to_string + +namespace nlohmann +{ +namespace detail +{ +/// proxy class for the iterator_wrapper functions +template class iteration_proxy +{ + private: + /// helper class for iteration + class iteration_proxy_internal + { + private: + /// the iterator + IteratorType anchor; + /// an index for arrays (used to create key names) + std::size_t array_index = 0; + + public: + explicit iteration_proxy_internal(IteratorType it) noexcept : anchor(it) {} + + /// dereference operator (needed for range-based for) + iteration_proxy_internal& operator*() + { + return *this; + } + + /// increment operator (needed for range-based for) + iteration_proxy_internal& operator++() + { + ++anchor; + ++array_index; + + return *this; + } + + /// inequality operator (needed for range-based for) + bool operator!=(const iteration_proxy_internal& o) const noexcept + { + return anchor != o.anchor; + } + + /// return key of the iterator + std::string key() const + { + assert(anchor.m_object != nullptr); + + switch (anchor.m_object->type()) + { + // use integer array index as key + case value_t::array: + return std::to_string(array_index); + + // use key from the object + case value_t::object: + return anchor.key(); + + // use an empty key for all primitive types + default: + return ""; + } + } + + /// return value of the iterator + typename IteratorType::reference value() const + { + return anchor.value(); + } + }; + + /// the container to iterate + typename IteratorType::reference container; + + public: + /// construct iteration proxy from a container + explicit iteration_proxy(typename IteratorType::reference cont) + : container(cont) {} + + /// return iterator begin (needed for range-based for) + iteration_proxy_internal begin() noexcept + { + return iteration_proxy_internal(container.begin()); + } + + /// return iterator end (needed for range-based for) + iteration_proxy_internal end() noexcept + { + return iteration_proxy_internal(container.end()); + } +}; +} +} + +#endif + +/*** End of inlined file: iteration_proxy.hpp ***/ + + +/*** Start of inlined file: json_reverse_iterator.hpp ***/ +#ifndef NLOHMANN_JSON_DETAIL_ITERATORS_JSON_REVERSE_ITERATOR_HPP +#define NLOHMANN_JSON_DETAIL_ITERATORS_JSON_REVERSE_ITERATOR_HPP + +#include // ptrdiff_t +#include // reverse_iterator +#include // declval + +namespace nlohmann +{ +namespace detail +{ +////////////////////// +// reverse_iterator // +////////////////////// + +/*! +@brief a template for a reverse iterator class + +@tparam Base the base iterator type to reverse. Valid types are @ref +iterator (to create @ref reverse_iterator) and @ref const_iterator (to +create @ref const_reverse_iterator). + +@requirement The class satisfies the following concept requirements: +- +[BidirectionalIterator](http://en.cppreference.com/w/cpp/concept/BidirectionalIterator): + The iterator that can be moved can be moved in both directions (i.e. + incremented and decremented). +- [OutputIterator](http://en.cppreference.com/w/cpp/concept/OutputIterator): + It is possible to write to the pointed-to element (only if @a Base is + @ref iterator). + +@since version 1.0.0 +*/ +template +class json_reverse_iterator : public std::reverse_iterator +{ + public: + using difference_type = std::ptrdiff_t; + /// shortcut to the reverse iterator adapter + using base_iterator = std::reverse_iterator; + /// the reference type for the pointed-to element + using reference = typename Base::reference; + + /// create reverse iterator from iterator + json_reverse_iterator(const typename base_iterator::iterator_type& it) noexcept + : base_iterator(it) {} + + /// create reverse iterator from base class + json_reverse_iterator(const base_iterator& it) noexcept : base_iterator(it) {} + + /// post-increment (it++) + json_reverse_iterator const operator++(int) + { + return static_cast(base_iterator::operator++(1)); + } + + /// pre-increment (++it) + json_reverse_iterator& operator++() + { + return static_cast(base_iterator::operator++()); + } + + /// post-decrement (it--) + json_reverse_iterator const operator--(int) + { + return static_cast(base_iterator::operator--(1)); + } + + /// pre-decrement (--it) + json_reverse_iterator& operator--() + { + return static_cast(base_iterator::operator--()); + } + + /// add to iterator + json_reverse_iterator& operator+=(difference_type i) + { + return static_cast(base_iterator::operator+=(i)); + } + + /// add to iterator + json_reverse_iterator operator+(difference_type i) const + { + return static_cast(base_iterator::operator+(i)); + } + + /// subtract from iterator + json_reverse_iterator operator-(difference_type i) const + { + return static_cast(base_iterator::operator-(i)); + } + + /// return difference + difference_type operator-(const json_reverse_iterator& other) const + { + return base_iterator(*this) - base_iterator(other); + } + + /// access to successor + reference operator[](difference_type n) const + { + return *(this->operator+(n)); + } + + /// return the key of an object iterator + auto key() const -> decltype(std::declval().key()) + { + auto it = --this->base(); + return it.key(); + } + + /// return the value of an iterator + reference value() const + { + auto it = --this->base(); + return it.operator * (); + } +}; +} +} + +#endif + +/*** End of inlined file: json_reverse_iterator.hpp ***/ + + +/*** Start of inlined file: output_adapters.hpp ***/ +#ifndef NLOHMANN_JSON_DETAIL_PARSING_OUTPUT_ADAPTERS_HPP +#define NLOHMANN_JSON_DETAIL_PARSING_OUTPUT_ADAPTERS_HPP + +#include // copy +#include // size_t +#include // streamsize +#include // back_inserter +#include // shared_ptr, make_shared +#include // basic_ostream +#include // basic_string +#include // vector + +namespace nlohmann +{ +namespace detail +{ +/// abstract output adapter interface +template struct output_adapter_protocol +{ + virtual void write_character(CharType c) = 0; + virtual void write_characters(const CharType* s, std::size_t length) = 0; + virtual ~output_adapter_protocol() = default; +}; + +/// a type to simplify interfaces +template +using output_adapter_t = std::shared_ptr>; + +/// output adapter for byte vectors +template +class output_vector_adapter : public output_adapter_protocol +{ + public: + explicit output_vector_adapter(std::vector& vec) : v(vec) {} + + void write_character(CharType c) override + { + v.push_back(c); + } + + void write_characters(const CharType* s, std::size_t length) override + { + std::copy(s, s + length, std::back_inserter(v)); + } + + private: + std::vector& v; +}; + +/// output adapter for output streams +template +class output_stream_adapter : public output_adapter_protocol +{ + public: + explicit output_stream_adapter(std::basic_ostream& s) : stream(s) {} + + void write_character(CharType c) override + { + stream.put(c); + } + + void write_characters(const CharType* s, std::size_t length) override + { + stream.write(s, static_cast(length)); + } + + private: + std::basic_ostream& stream; +}; + +/// output adapter for basic_string +template +class output_string_adapter : public output_adapter_protocol +{ + public: + explicit output_string_adapter(std::basic_string& s) : str(s) {} + + void write_character(CharType c) override + { + str.push_back(c); + } + + void write_characters(const CharType* s, std::size_t length) override + { + str.append(s, length); + } + + private: + std::basic_string& str; +}; + +template +class output_adapter +{ + public: + output_adapter(std::vector& vec) + : oa(std::make_shared>(vec)) {} + + output_adapter(std::basic_ostream& s) + : oa(std::make_shared>(s)) {} + + output_adapter(std::basic_string& s) + : oa(std::make_shared>(s)) {} + + operator output_adapter_t() + { + return oa; + } + + private: + output_adapter_t oa = nullptr; +}; +} +} + +#endif + +/*** End of inlined file: output_adapters.hpp ***/ + + +/*** Start of inlined file: binary_reader.hpp ***/ +#ifndef NLOHMANN_JSON_DETAIL_PARSING_BINARY_READER_HPP +#define NLOHMANN_JSON_DETAIL_PARSING_BINARY_READER_HPP + +#include // generate_n +#include // array +#include // assert +#include // ldexp +#include // size_t +#include // uint8_t, uint16_t, uint32_t, uint64_t +#include // memcpy +#include // setw, setfill +#include // hex +#include // back_inserter +#include // numeric_limits +#include // stringstream +#include // char_traits, string +#include // make_pair, move + +namespace nlohmann +{ +namespace detail +{ +/////////////////// +// binary reader // +/////////////////// + +/*! +@brief deserialization of CBOR and MessagePack values +*/ +template +class binary_reader +{ + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + + public: + /*! + @brief create a binary reader + + @param[in] adapter input adapter to read from + */ + explicit binary_reader(input_adapter_t adapter) : ia(std::move(adapter)) + { + assert(ia); + } + + /*! + @brief create a JSON value from CBOR input + + @param[in] strict whether to expect the input to be consumed completed + @return JSON value created from CBOR input + + @throw parse_error.110 if input ended unexpectedly or the end of file was + not reached when @a strict was set to true + @throw parse_error.112 if unsupported byte was read + */ + BasicJsonType parse_cbor(const bool strict) + { + const auto res = parse_cbor_internal(); + if (strict) + { + get(); + check_eof(true); + } + return res; + } + + /*! + @brief create a JSON value from MessagePack input + + @param[in] strict whether to expect the input to be consumed completed + @return JSON value created from MessagePack input + + @throw parse_error.110 if input ended unexpectedly or the end of file was + not reached when @a strict was set to true + @throw parse_error.112 if unsupported byte was read + */ + BasicJsonType parse_msgpack(const bool strict) + { + const auto res = parse_msgpack_internal(); + if (strict) + { + get(); + check_eof(true); + } + return res; + } + + /*! + @brief determine system byte order + + @return true if and only if system's byte order is little endian + + @note from http://stackoverflow.com/a/1001328/266378 + */ + static constexpr bool little_endianess(int num = 1) noexcept + { + return (*reinterpret_cast(&num) == 1); + } + + private: + /*! + @param[in] get_char whether a new character should be retrieved from the + input (true, default) or whether the last read + character should be considered instead + */ + BasicJsonType parse_cbor_internal(const bool get_char = true) + { + switch (get_char ? get() : current) + { + // EOF + case std::char_traits::eof(): + JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input")); + + // Integer 0x00..0x17 (0..23) + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + case 0x09: + case 0x0A: + case 0x0B: + case 0x0C: + case 0x0D: + case 0x0E: + case 0x0F: + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + return static_cast(current); + + case 0x18: // Unsigned integer (one-byte uint8_t follows) + return get_number(); + + case 0x19: // Unsigned integer (two-byte uint16_t follows) + return get_number(); + + case 0x1A: // Unsigned integer (four-byte uint32_t follows) + return get_number(); + + case 0x1B: // Unsigned integer (eight-byte uint64_t follows) + return get_number(); + + // Negative integer -1-0x00..-1-0x17 (-1..-24) + case 0x20: + case 0x21: + case 0x22: + case 0x23: + case 0x24: + case 0x25: + case 0x26: + case 0x27: + case 0x28: + case 0x29: + case 0x2A: + case 0x2B: + case 0x2C: + case 0x2D: + case 0x2E: + case 0x2F: + case 0x30: + case 0x31: + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: + return static_cast(0x20 - 1 - current); + + case 0x38: // Negative integer (one-byte uint8_t follows) + { + // must be uint8_t ! + return static_cast(-1) - get_number(); + } + + case 0x39: // Negative integer -1-n (two-byte uint16_t follows) + { + return static_cast(-1) - get_number(); + } + + case 0x3A: // Negative integer -1-n (four-byte uint32_t follows) + { + return static_cast(-1) - get_number(); + } + + case 0x3B: // Negative integer -1-n (eight-byte uint64_t follows) + { + return static_cast(-1) - + static_cast(get_number()); + } + + // UTF-8 string (0x00..0x17 bytes follow) + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: + case 0x68: + case 0x69: + case 0x6A: + case 0x6B: + case 0x6C: + case 0x6D: + case 0x6E: + case 0x6F: + case 0x70: + case 0x71: + case 0x72: + case 0x73: + case 0x74: + case 0x75: + case 0x76: + case 0x77: + case 0x78: // UTF-8 string (one-byte uint8_t for n follows) + case 0x79: // UTF-8 string (two-byte uint16_t for n follow) + case 0x7A: // UTF-8 string (four-byte uint32_t for n follow) + case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow) + case 0x7F: // UTF-8 string (indefinite length) + { + return get_cbor_string(); + } + + // array (0x00..0x17 data items follow) + case 0x80: + case 0x81: + case 0x82: + case 0x83: + case 0x84: + case 0x85: + case 0x86: + case 0x87: + case 0x88: + case 0x89: + case 0x8A: + case 0x8B: + case 0x8C: + case 0x8D: + case 0x8E: + case 0x8F: + case 0x90: + case 0x91: + case 0x92: + case 0x93: + case 0x94: + case 0x95: + case 0x96: + case 0x97: + { + return get_cbor_array(current & 0x1F); + } + + case 0x98: // array (one-byte uint8_t for n follows) + { + return get_cbor_array(get_number()); + } + + case 0x99: // array (two-byte uint16_t for n follow) + { + return get_cbor_array(get_number()); + } + + case 0x9A: // array (four-byte uint32_t for n follow) + { + return get_cbor_array(get_number()); + } + + case 0x9B: // array (eight-byte uint64_t for n follow) + { + return get_cbor_array(get_number()); + } + + case 0x9F: // array (indefinite length) + { + BasicJsonType result = value_t::array; + while (get() != 0xFF) + { + result.push_back(parse_cbor_internal(false)); + } + return result; + } + + // map (0x00..0x17 pairs of data items follow) + case 0xA0: + case 0xA1: + case 0xA2: + case 0xA3: + case 0xA4: + case 0xA5: + case 0xA6: + case 0xA7: + case 0xA8: + case 0xA9: + case 0xAA: + case 0xAB: + case 0xAC: + case 0xAD: + case 0xAE: + case 0xAF: + case 0xB0: + case 0xB1: + case 0xB2: + case 0xB3: + case 0xB4: + case 0xB5: + case 0xB6: + case 0xB7: + { + return get_cbor_object(current & 0x1F); + } + + case 0xB8: // map (one-byte uint8_t for n follows) + { + return get_cbor_object(get_number()); + } + + case 0xB9: // map (two-byte uint16_t for n follow) + { + return get_cbor_object(get_number()); + } + + case 0xBA: // map (four-byte uint32_t for n follow) + { + return get_cbor_object(get_number()); + } + + case 0xBB: // map (eight-byte uint64_t for n follow) + { + return get_cbor_object(get_number()); + } + + case 0xBF: // map (indefinite length) + { + BasicJsonType result = value_t::object; + while (get() != 0xFF) + { + auto key = get_cbor_string(); + result[key] = parse_cbor_internal(); + } + return result; + } + + case 0xF4: // false + { + return false; + } + + case 0xF5: // true + { + return true; + } + + case 0xF6: // null + { + return value_t::null; + } + + case 0xF9: // Half-Precision Float (two-byte IEEE 754) + { + const int byte1 = get(); + check_eof(); + const int byte2 = get(); + check_eof(); + + // code from RFC 7049, Appendix D, Figure 3: + // As half-precision floating-point numbers were only added + // to IEEE 754 in 2008, today's programming platforms often + // still only have limited support for them. It is very + // easy to include at least decoding support for them even + // without such support. An example of a small decoder for + // half-precision floating-point numbers in the C language + // is shown in Fig. 3. + const int half = (byte1 << 8) + byte2; + const int exp = (half >> 10) & 0x1F; + const int mant = half & 0x3FF; + double val; + if (exp == 0) + { + val = std::ldexp(mant, -24); + } + else if (exp != 31) + { + val = std::ldexp(mant + 1024, exp - 25); + } + else + { + val = (mant == 0) ? std::numeric_limits::infinity() + : std::numeric_limits::quiet_NaN(); + } + return (half & 0x8000) != 0 ? -val : val; + } + + case 0xFA: // Single-Precision Float (four-byte IEEE 754) + { + return get_number(); + } + + case 0xFB: // Double-Precision Float (eight-byte IEEE 754) + { + return get_number(); + } + + default: // anything else (0xFF is handled inside the other types) + { + std::stringstream ss; + ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; + JSON_THROW(parse_error::create(112, chars_read, "error reading CBOR; last byte: 0x" + ss.str())); + } + } + } + + BasicJsonType parse_msgpack_internal() + { + switch (get()) + { + // EOF + case std::char_traits::eof(): + JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input")); + + // positive fixint + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + case 0x09: + case 0x0A: + case 0x0B: + case 0x0C: + case 0x0D: + case 0x0E: + case 0x0F: + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + case 0x1A: + case 0x1B: + case 0x1C: + case 0x1D: + case 0x1E: + case 0x1F: + case 0x20: + case 0x21: + case 0x22: + case 0x23: + case 0x24: + case 0x25: + case 0x26: + case 0x27: + case 0x28: + case 0x29: + case 0x2A: + case 0x2B: + case 0x2C: + case 0x2D: + case 0x2E: + case 0x2F: + case 0x30: + case 0x31: + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: + case 0x38: + case 0x39: + case 0x3A: + case 0x3B: + case 0x3C: + case 0x3D: + case 0x3E: + case 0x3F: + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + case 0x48: + case 0x49: + case 0x4A: + case 0x4B: + case 0x4C: + case 0x4D: + case 0x4E: + case 0x4F: + case 0x50: + case 0x51: + case 0x52: + case 0x53: + case 0x54: + case 0x55: + case 0x56: + case 0x57: + case 0x58: + case 0x59: + case 0x5A: + case 0x5B: + case 0x5C: + case 0x5D: + case 0x5E: + case 0x5F: + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: + case 0x68: + case 0x69: + case 0x6A: + case 0x6B: + case 0x6C: + case 0x6D: + case 0x6E: + case 0x6F: + case 0x70: + case 0x71: + case 0x72: + case 0x73: + case 0x74: + case 0x75: + case 0x76: + case 0x77: + case 0x78: + case 0x79: + case 0x7A: + case 0x7B: + case 0x7C: + case 0x7D: + case 0x7E: + case 0x7F: + return static_cast(current); + + // fixmap + case 0x80: + case 0x81: + case 0x82: + case 0x83: + case 0x84: + case 0x85: + case 0x86: + case 0x87: + case 0x88: + case 0x89: + case 0x8A: + case 0x8B: + case 0x8C: + case 0x8D: + case 0x8E: + case 0x8F: + { + return get_msgpack_object(current & 0x0F); + } + + // fixarray + case 0x90: + case 0x91: + case 0x92: + case 0x93: + case 0x94: + case 0x95: + case 0x96: + case 0x97: + case 0x98: + case 0x99: + case 0x9A: + case 0x9B: + case 0x9C: + case 0x9D: + case 0x9E: + case 0x9F: + { + return get_msgpack_array(current & 0x0F); + } + + // fixstr + case 0xA0: + case 0xA1: + case 0xA2: + case 0xA3: + case 0xA4: + case 0xA5: + case 0xA6: + case 0xA7: + case 0xA8: + case 0xA9: + case 0xAA: + case 0xAB: + case 0xAC: + case 0xAD: + case 0xAE: + case 0xAF: + case 0xB0: + case 0xB1: + case 0xB2: + case 0xB3: + case 0xB4: + case 0xB5: + case 0xB6: + case 0xB7: + case 0xB8: + case 0xB9: + case 0xBA: + case 0xBB: + case 0xBC: + case 0xBD: + case 0xBE: + case 0xBF: + return get_msgpack_string(); + + case 0xC0: // nil + return value_t::null; + + case 0xC2: // false + return false; + + case 0xC3: // true + return true; + + case 0xCA: // float 32 + return get_number(); + + case 0xCB: // float 64 + return get_number(); + + case 0xCC: // uint 8 + return get_number(); + + case 0xCD: // uint 16 + return get_number(); + + case 0xCE: // uint 32 + return get_number(); + + case 0xCF: // uint 64 + return get_number(); + + case 0xD0: // int 8 + return get_number(); + + case 0xD1: // int 16 + return get_number(); + + case 0xD2: // int 32 + return get_number(); + + case 0xD3: // int 64 + return get_number(); + + case 0xD9: // str 8 + case 0xDA: // str 16 + case 0xDB: // str 32 + return get_msgpack_string(); + + case 0xDC: // array 16 + { + return get_msgpack_array(get_number()); + } + + case 0xDD: // array 32 + { + return get_msgpack_array(get_number()); + } + + case 0xDE: // map 16 + { + return get_msgpack_object(get_number()); + } + + case 0xDF: // map 32 + { + return get_msgpack_object(get_number()); + } + + // positive fixint + case 0xE0: + case 0xE1: + case 0xE2: + case 0xE3: + case 0xE4: + case 0xE5: + case 0xE6: + case 0xE7: + case 0xE8: + case 0xE9: + case 0xEA: + case 0xEB: + case 0xEC: + case 0xED: + case 0xEE: + case 0xEF: + case 0xF0: + case 0xF1: + case 0xF2: + case 0xF3: + case 0xF4: + case 0xF5: + case 0xF6: + case 0xF7: + case 0xF8: + case 0xF9: + case 0xFA: + case 0xFB: + case 0xFC: + case 0xFD: + case 0xFE: + case 0xFF: + return static_cast(current); + + default: // anything else + { + std::stringstream ss; + ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; + JSON_THROW(parse_error::create(112, chars_read, + "error reading MessagePack; last byte: 0x" + ss.str())); + } + } + } + + /*! + @brief get next character from the input + + This function provides the interface to the used input adapter. It does + not throw in case the input reached EOF, but returns a -'ve valued + `std::char_traits::eof()` in that case. + + @return character read from the input + */ + int get() + { + ++chars_read; + return (current = ia->get_character()); + } + + /* + @brief read a number from the input + + @tparam NumberType the type of the number + + @return number of type @a NumberType + + @note This function needs to respect the system's endianess, because + bytes in CBOR and MessagePack are stored in network order (big + endian) and therefore need reordering on little endian systems. + + @throw parse_error.110 if input has less than `sizeof(NumberType)` bytes + */ + template NumberType get_number() + { + // step 1: read input into array with system's byte order + std::array vec; + for (std::size_t i = 0; i < sizeof(NumberType); ++i) + { + get(); + check_eof(); + + // reverse byte order prior to conversion if necessary + if (is_little_endian) + { + vec[sizeof(NumberType) - i - 1] = static_cast(current); + } + else + { + vec[i] = static_cast(current); // LCOV_EXCL_LINE + } + } + + // step 2: convert array into number of type T and return + NumberType result; + std::memcpy(&result, vec.data(), sizeof(NumberType)); + return result; + } + + /*! + @brief create a string by reading characters from the input + + @param[in] len number of bytes to read + + @note We can not reserve @a len bytes for the result, because @a len + may be too large. Usually, @ref check_eof() detects the end of + the input before we run out of string memory. + + @return string created by reading @a len bytes + + @throw parse_error.110 if input has less than @a len bytes + */ + template + std::string get_string(const NumberType len) + { + std::string result; + std::generate_n(std::back_inserter(result), len, [this]() + { + get(); + check_eof(); + return static_cast(current); + }); + return result; + } + + /*! + @brief reads a CBOR string + + This function first reads starting bytes to determine the expected + string length and then copies this number of bytes into a string. + Additionally, CBOR's strings with indefinite lengths are supported. + + @return string + + @throw parse_error.110 if input ended + @throw parse_error.113 if an unexpected byte is read + */ + std::string get_cbor_string() + { + check_eof(); + + switch (current) + { + // UTF-8 string (0x00..0x17 bytes follow) + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: + case 0x68: + case 0x69: + case 0x6A: + case 0x6B: + case 0x6C: + case 0x6D: + case 0x6E: + case 0x6F: + case 0x70: + case 0x71: + case 0x72: + case 0x73: + case 0x74: + case 0x75: + case 0x76: + case 0x77: + { + return get_string(current & 0x1F); + } + + case 0x78: // UTF-8 string (one-byte uint8_t for n follows) + { + return get_string(get_number()); + } + + case 0x79: // UTF-8 string (two-byte uint16_t for n follow) + { + return get_string(get_number()); + } + + case 0x7A: // UTF-8 string (four-byte uint32_t for n follow) + { + return get_string(get_number()); + } + + case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow) + { + return get_string(get_number()); + } + + case 0x7F: // UTF-8 string (indefinite length) + { + std::string result; + while (get() != 0xFF) + { + check_eof(); + result.push_back(static_cast(current)); + } + return result; + } + + default: + { + std::stringstream ss; + ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; + JSON_THROW(parse_error::create(113, chars_read, "expected a CBOR string; last byte: 0x" + ss.str())); + } + } + } + + template + BasicJsonType get_cbor_array(const NumberType len) + { + BasicJsonType result = value_t::array; + std::generate_n(std::back_inserter(*result.m_value.array), len, [this]() + { + return parse_cbor_internal(); + }); + return result; + } + + template + BasicJsonType get_cbor_object(const NumberType len) + { + BasicJsonType result = value_t::object; + std::generate_n(std::inserter(*result.m_value.object, + result.m_value.object->end()), + len, [this]() + { + get(); + auto key = get_cbor_string(); + auto val = parse_cbor_internal(); + return std::make_pair(std::move(key), std::move(val)); + }); + return result; + } + + /*! + @brief reads a MessagePack string + + This function first reads starting bytes to determine the expected + string length and then copies this number of bytes into a string. + + @return string + + @throw parse_error.110 if input ended + @throw parse_error.113 if an unexpected byte is read + */ + std::string get_msgpack_string() + { + check_eof(); + + switch (current) + { + // fixstr + case 0xA0: + case 0xA1: + case 0xA2: + case 0xA3: + case 0xA4: + case 0xA5: + case 0xA6: + case 0xA7: + case 0xA8: + case 0xA9: + case 0xAA: + case 0xAB: + case 0xAC: + case 0xAD: + case 0xAE: + case 0xAF: + case 0xB0: + case 0xB1: + case 0xB2: + case 0xB3: + case 0xB4: + case 0xB5: + case 0xB6: + case 0xB7: + case 0xB8: + case 0xB9: + case 0xBA: + case 0xBB: + case 0xBC: + case 0xBD: + case 0xBE: + case 0xBF: + { + return get_string(current & 0x1F); + } + + case 0xD9: // str 8 + { + return get_string(get_number()); + } + + case 0xDA: // str 16 + { + return get_string(get_number()); + } + + case 0xDB: // str 32 + { + return get_string(get_number()); + } + + default: + { + std::stringstream ss; + ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; + JSON_THROW(parse_error::create(113, chars_read, + "expected a MessagePack string; last byte: 0x" + ss.str())); + } + } + } + + template + BasicJsonType get_msgpack_array(const NumberType len) + { + BasicJsonType result = value_t::array; + std::generate_n(std::back_inserter(*result.m_value.array), len, [this]() + { + return parse_msgpack_internal(); + }); + return result; + } + + template + BasicJsonType get_msgpack_object(const NumberType len) + { + BasicJsonType result = value_t::object; + std::generate_n(std::inserter(*result.m_value.object, + result.m_value.object->end()), + len, [this]() + { + get(); + auto key = get_msgpack_string(); + auto val = parse_msgpack_internal(); + return std::make_pair(std::move(key), std::move(val)); + }); + return result; + } + + /*! + @brief check if input ended + @throw parse_error.110 if input ended + */ + void check_eof(const bool expect_eof = false) const + { + if (expect_eof) + { + if (JSON_UNLIKELY(current != std::char_traits::eof())) + { + JSON_THROW(parse_error::create(110, chars_read, "expected end of input")); + } + } + else + { + if (JSON_UNLIKELY(current == std::char_traits::eof())) + { + JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input")); + } + } + } + + private: + /// input adapter + input_adapter_t ia = nullptr; + + /// the current character + int current = std::char_traits::eof(); + + /// the number of characters read + std::size_t chars_read = 0; + + /// whether we can assume little endianess + const bool is_little_endian = little_endianess(); +}; +} +} + +#endif + +/*** End of inlined file: binary_reader.hpp ***/ + + +/*** Start of inlined file: binary_writer.hpp ***/ +#ifndef NLOHMANN_JSON_DETAIL_PARSING_BINARY_WRITER_HPP +#define NLOHMANN_JSON_DETAIL_PARSING_BINARY_WRITER_HPP + +#include // reverse +#include // array +#include // uint8_t, uint16_t, uint32_t, uint64_t +#include // memcpy +#include // numeric_limits + + +/*** Start of inlined file: binary_reader.hpp ***/ +#ifndef NLOHMANN_JSON_DETAIL_PARSING_BINARY_READER_HPP +#define NLOHMANN_JSON_DETAIL_PARSING_BINARY_READER_HPP + +#include // generate_n +#include // array +#include // assert +#include // ldexp +#include // size_t +#include // uint8_t, uint16_t, uint32_t, uint64_t +#include // memcpy +#include // setw, setfill +#include // hex +#include // back_inserter +#include // numeric_limits +#include // stringstream +#include // char_traits, string +#include // make_pair, move + +namespace nlohmann +{ +namespace detail +{ +/////////////////// +// binary reader // +/////////////////// + +/*! +@brief deserialization of CBOR and MessagePack values +*/ +template +class binary_reader +{ + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + + public: + /*! + @brief create a binary reader + + @param[in] adapter input adapter to read from + */ + explicit binary_reader(input_adapter_t adapter) : ia(std::move(adapter)) + { + assert(ia); + } + + /*! + @brief create a JSON value from CBOR input + + @param[in] strict whether to expect the input to be consumed completed + @return JSON value created from CBOR input + + @throw parse_error.110 if input ended unexpectedly or the end of file was + not reached when @a strict was set to true + @throw parse_error.112 if unsupported byte was read + */ + BasicJsonType parse_cbor(const bool strict) + { + const auto res = parse_cbor_internal(); + if (strict) + { + get(); + check_eof(true); + } + return res; + } + + /*! + @brief create a JSON value from MessagePack input + + @param[in] strict whether to expect the input to be consumed completed + @return JSON value created from MessagePack input + + @throw parse_error.110 if input ended unexpectedly or the end of file was + not reached when @a strict was set to true + @throw parse_error.112 if unsupported byte was read + */ + BasicJsonType parse_msgpack(const bool strict) + { + const auto res = parse_msgpack_internal(); + if (strict) + { + get(); + check_eof(true); + } + return res; + } + + /*! + @brief determine system byte order + + @return true if and only if system's byte order is little endian + + @note from http://stackoverflow.com/a/1001328/266378 + */ + static constexpr bool little_endianess(int num = 1) noexcept + { + return (*reinterpret_cast(&num) == 1); + } + + private: + /*! + @param[in] get_char whether a new character should be retrieved from the + input (true, default) or whether the last read + character should be considered instead + */ + BasicJsonType parse_cbor_internal(const bool get_char = true) + { + switch (get_char ? get() : current) + { + // EOF + case std::char_traits::eof(): + JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input")); + + // Integer 0x00..0x17 (0..23) + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + case 0x09: + case 0x0A: + case 0x0B: + case 0x0C: + case 0x0D: + case 0x0E: + case 0x0F: + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + return static_cast(current); + + case 0x18: // Unsigned integer (one-byte uint8_t follows) + return get_number(); + + case 0x19: // Unsigned integer (two-byte uint16_t follows) + return get_number(); + + case 0x1A: // Unsigned integer (four-byte uint32_t follows) + return get_number(); + + case 0x1B: // Unsigned integer (eight-byte uint64_t follows) + return get_number(); + + // Negative integer -1-0x00..-1-0x17 (-1..-24) + case 0x20: + case 0x21: + case 0x22: + case 0x23: + case 0x24: + case 0x25: + case 0x26: + case 0x27: + case 0x28: + case 0x29: + case 0x2A: + case 0x2B: + case 0x2C: + case 0x2D: + case 0x2E: + case 0x2F: + case 0x30: + case 0x31: + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: + return static_cast(0x20 - 1 - current); + + case 0x38: // Negative integer (one-byte uint8_t follows) + { + // must be uint8_t ! + return static_cast(-1) - get_number(); + } + + case 0x39: // Negative integer -1-n (two-byte uint16_t follows) + { + return static_cast(-1) - get_number(); + } + + case 0x3A: // Negative integer -1-n (four-byte uint32_t follows) + { + return static_cast(-1) - get_number(); + } + + case 0x3B: // Negative integer -1-n (eight-byte uint64_t follows) + { + return static_cast(-1) - + static_cast(get_number()); + } + + // UTF-8 string (0x00..0x17 bytes follow) + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: + case 0x68: + case 0x69: + case 0x6A: + case 0x6B: + case 0x6C: + case 0x6D: + case 0x6E: + case 0x6F: + case 0x70: + case 0x71: + case 0x72: + case 0x73: + case 0x74: + case 0x75: + case 0x76: + case 0x77: + case 0x78: // UTF-8 string (one-byte uint8_t for n follows) + case 0x79: // UTF-8 string (two-byte uint16_t for n follow) + case 0x7A: // UTF-8 string (four-byte uint32_t for n follow) + case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow) + case 0x7F: // UTF-8 string (indefinite length) + { + return get_cbor_string(); + } + + // array (0x00..0x17 data items follow) + case 0x80: + case 0x81: + case 0x82: + case 0x83: + case 0x84: + case 0x85: + case 0x86: + case 0x87: + case 0x88: + case 0x89: + case 0x8A: + case 0x8B: + case 0x8C: + case 0x8D: + case 0x8E: + case 0x8F: + case 0x90: + case 0x91: + case 0x92: + case 0x93: + case 0x94: + case 0x95: + case 0x96: + case 0x97: + { + return get_cbor_array(current & 0x1F); + } + + case 0x98: // array (one-byte uint8_t for n follows) + { + return get_cbor_array(get_number()); + } + + case 0x99: // array (two-byte uint16_t for n follow) + { + return get_cbor_array(get_number()); + } + + case 0x9A: // array (four-byte uint32_t for n follow) + { + return get_cbor_array(get_number()); + } + + case 0x9B: // array (eight-byte uint64_t for n follow) + { + return get_cbor_array(get_number()); + } + + case 0x9F: // array (indefinite length) + { + BasicJsonType result = value_t::array; + while (get() != 0xFF) + { + result.push_back(parse_cbor_internal(false)); + } + return result; + } + + // map (0x00..0x17 pairs of data items follow) + case 0xA0: + case 0xA1: + case 0xA2: + case 0xA3: + case 0xA4: + case 0xA5: + case 0xA6: + case 0xA7: + case 0xA8: + case 0xA9: + case 0xAA: + case 0xAB: + case 0xAC: + case 0xAD: + case 0xAE: + case 0xAF: + case 0xB0: + case 0xB1: + case 0xB2: + case 0xB3: + case 0xB4: + case 0xB5: + case 0xB6: + case 0xB7: + { + return get_cbor_object(current & 0x1F); + } + + case 0xB8: // map (one-byte uint8_t for n follows) + { + return get_cbor_object(get_number()); + } + + case 0xB9: // map (two-byte uint16_t for n follow) + { + return get_cbor_object(get_number()); + } + + case 0xBA: // map (four-byte uint32_t for n follow) + { + return get_cbor_object(get_number()); + } + + case 0xBB: // map (eight-byte uint64_t for n follow) + { + return get_cbor_object(get_number()); + } + + case 0xBF: // map (indefinite length) + { + BasicJsonType result = value_t::object; + while (get() != 0xFF) + { + auto key = get_cbor_string(); + result[key] = parse_cbor_internal(); + } + return result; + } + + case 0xF4: // false + { + return false; + } + + case 0xF5: // true + { + return true; + } + + case 0xF6: // null + { + return value_t::null; + } + + case 0xF9: // Half-Precision Float (two-byte IEEE 754) + { + const int byte1 = get(); + check_eof(); + const int byte2 = get(); + check_eof(); + + // code from RFC 7049, Appendix D, Figure 3: + // As half-precision floating-point numbers were only added + // to IEEE 754 in 2008, today's programming platforms often + // still only have limited support for them. It is very + // easy to include at least decoding support for them even + // without such support. An example of a small decoder for + // half-precision floating-point numbers in the C language + // is shown in Fig. 3. + const int half = (byte1 << 8) + byte2; + const int exp = (half >> 10) & 0x1F; + const int mant = half & 0x3FF; + double val; + if (exp == 0) + { + val = std::ldexp(mant, -24); + } + else if (exp != 31) + { + val = std::ldexp(mant + 1024, exp - 25); + } + else + { + val = (mant == 0) ? std::numeric_limits::infinity() + : std::numeric_limits::quiet_NaN(); + } + return (half & 0x8000) != 0 ? -val : val; + } + + case 0xFA: // Single-Precision Float (four-byte IEEE 754) + { + return get_number(); + } + + case 0xFB: // Double-Precision Float (eight-byte IEEE 754) + { + return get_number(); + } + + default: // anything else (0xFF is handled inside the other types) + { + std::stringstream ss; + ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; + JSON_THROW(parse_error::create(112, chars_read, "error reading CBOR; last byte: 0x" + ss.str())); + } + } + } + + BasicJsonType parse_msgpack_internal() + { + switch (get()) + { + // EOF + case std::char_traits::eof(): + JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input")); + + // positive fixint + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + case 0x09: + case 0x0A: + case 0x0B: + case 0x0C: + case 0x0D: + case 0x0E: + case 0x0F: + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + case 0x1A: + case 0x1B: + case 0x1C: + case 0x1D: + case 0x1E: + case 0x1F: + case 0x20: + case 0x21: + case 0x22: + case 0x23: + case 0x24: + case 0x25: + case 0x26: + case 0x27: + case 0x28: + case 0x29: + case 0x2A: + case 0x2B: + case 0x2C: + case 0x2D: + case 0x2E: + case 0x2F: + case 0x30: + case 0x31: + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: + case 0x38: + case 0x39: + case 0x3A: + case 0x3B: + case 0x3C: + case 0x3D: + case 0x3E: + case 0x3F: + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + case 0x48: + case 0x49: + case 0x4A: + case 0x4B: + case 0x4C: + case 0x4D: + case 0x4E: + case 0x4F: + case 0x50: + case 0x51: + case 0x52: + case 0x53: + case 0x54: + case 0x55: + case 0x56: + case 0x57: + case 0x58: + case 0x59: + case 0x5A: + case 0x5B: + case 0x5C: + case 0x5D: + case 0x5E: + case 0x5F: + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: + case 0x68: + case 0x69: + case 0x6A: + case 0x6B: + case 0x6C: + case 0x6D: + case 0x6E: + case 0x6F: + case 0x70: + case 0x71: + case 0x72: + case 0x73: + case 0x74: + case 0x75: + case 0x76: + case 0x77: + case 0x78: + case 0x79: + case 0x7A: + case 0x7B: + case 0x7C: + case 0x7D: + case 0x7E: + case 0x7F: + return static_cast(current); + + // fixmap + case 0x80: + case 0x81: + case 0x82: + case 0x83: + case 0x84: + case 0x85: + case 0x86: + case 0x87: + case 0x88: + case 0x89: + case 0x8A: + case 0x8B: + case 0x8C: + case 0x8D: + case 0x8E: + case 0x8F: + { + return get_msgpack_object(current & 0x0F); + } + + // fixarray + case 0x90: + case 0x91: + case 0x92: + case 0x93: + case 0x94: + case 0x95: + case 0x96: + case 0x97: + case 0x98: + case 0x99: + case 0x9A: + case 0x9B: + case 0x9C: + case 0x9D: + case 0x9E: + case 0x9F: + { + return get_msgpack_array(current & 0x0F); + } + + // fixstr + case 0xA0: + case 0xA1: + case 0xA2: + case 0xA3: + case 0xA4: + case 0xA5: + case 0xA6: + case 0xA7: + case 0xA8: + case 0xA9: + case 0xAA: + case 0xAB: + case 0xAC: + case 0xAD: + case 0xAE: + case 0xAF: + case 0xB0: + case 0xB1: + case 0xB2: + case 0xB3: + case 0xB4: + case 0xB5: + case 0xB6: + case 0xB7: + case 0xB8: + case 0xB9: + case 0xBA: + case 0xBB: + case 0xBC: + case 0xBD: + case 0xBE: + case 0xBF: + return get_msgpack_string(); + + case 0xC0: // nil + return value_t::null; + + case 0xC2: // false + return false; + + case 0xC3: // true + return true; + + case 0xCA: // float 32 + return get_number(); + + case 0xCB: // float 64 + return get_number(); + + case 0xCC: // uint 8 + return get_number(); + + case 0xCD: // uint 16 + return get_number(); + + case 0xCE: // uint 32 + return get_number(); + + case 0xCF: // uint 64 + return get_number(); + + case 0xD0: // int 8 + return get_number(); + + case 0xD1: // int 16 + return get_number(); + + case 0xD2: // int 32 + return get_number(); + + case 0xD3: // int 64 + return get_number(); + + case 0xD9: // str 8 + case 0xDA: // str 16 + case 0xDB: // str 32 + return get_msgpack_string(); + + case 0xDC: // array 16 + { + return get_msgpack_array(get_number()); + } + + case 0xDD: // array 32 + { + return get_msgpack_array(get_number()); + } + + case 0xDE: // map 16 + { + return get_msgpack_object(get_number()); + } + + case 0xDF: // map 32 + { + return get_msgpack_object(get_number()); + } + + // positive fixint + case 0xE0: + case 0xE1: + case 0xE2: + case 0xE3: + case 0xE4: + case 0xE5: + case 0xE6: + case 0xE7: + case 0xE8: + case 0xE9: + case 0xEA: + case 0xEB: + case 0xEC: + case 0xED: + case 0xEE: + case 0xEF: + case 0xF0: + case 0xF1: + case 0xF2: + case 0xF3: + case 0xF4: + case 0xF5: + case 0xF6: + case 0xF7: + case 0xF8: + case 0xF9: + case 0xFA: + case 0xFB: + case 0xFC: + case 0xFD: + case 0xFE: + case 0xFF: + return static_cast(current); + + default: // anything else + { + std::stringstream ss; + ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; + JSON_THROW(parse_error::create(112, chars_read, + "error reading MessagePack; last byte: 0x" + ss.str())); + } + } + } + + /*! + @brief get next character from the input + + This function provides the interface to the used input adapter. It does + not throw in case the input reached EOF, but returns a -'ve valued + `std::char_traits::eof()` in that case. + + @return character read from the input + */ + int get() + { + ++chars_read; + return (current = ia->get_character()); + } + + /* + @brief read a number from the input + + @tparam NumberType the type of the number + + @return number of type @a NumberType + + @note This function needs to respect the system's endianess, because + bytes in CBOR and MessagePack are stored in network order (big + endian) and therefore need reordering on little endian systems. + + @throw parse_error.110 if input has less than `sizeof(NumberType)` bytes + */ + template NumberType get_number() + { + // step 1: read input into array with system's byte order + std::array vec; + for (std::size_t i = 0; i < sizeof(NumberType); ++i) + { + get(); + check_eof(); + + // reverse byte order prior to conversion if necessary + if (is_little_endian) + { + vec[sizeof(NumberType) - i - 1] = static_cast(current); + } + else + { + vec[i] = static_cast(current); // LCOV_EXCL_LINE + } + } + + // step 2: convert array into number of type T and return + NumberType result; + std::memcpy(&result, vec.data(), sizeof(NumberType)); + return result; + } + + /*! + @brief create a string by reading characters from the input + + @param[in] len number of bytes to read + + @note We can not reserve @a len bytes for the result, because @a len + may be too large. Usually, @ref check_eof() detects the end of + the input before we run out of string memory. + + @return string created by reading @a len bytes + + @throw parse_error.110 if input has less than @a len bytes + */ + template + std::string get_string(const NumberType len) + { + std::string result; + std::generate_n(std::back_inserter(result), len, [this]() + { + get(); + check_eof(); + return static_cast(current); + }); + return result; + } + + /*! + @brief reads a CBOR string + + This function first reads starting bytes to determine the expected + string length and then copies this number of bytes into a string. + Additionally, CBOR's strings with indefinite lengths are supported. + + @return string + + @throw parse_error.110 if input ended + @throw parse_error.113 if an unexpected byte is read + */ + std::string get_cbor_string() + { + check_eof(); + + switch (current) + { + // UTF-8 string (0x00..0x17 bytes follow) + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: + case 0x68: + case 0x69: + case 0x6A: + case 0x6B: + case 0x6C: + case 0x6D: + case 0x6E: + case 0x6F: + case 0x70: + case 0x71: + case 0x72: + case 0x73: + case 0x74: + case 0x75: + case 0x76: + case 0x77: + { + return get_string(current & 0x1F); + } + + case 0x78: // UTF-8 string (one-byte uint8_t for n follows) + { + return get_string(get_number()); + } + + case 0x79: // UTF-8 string (two-byte uint16_t for n follow) + { + return get_string(get_number()); + } + + case 0x7A: // UTF-8 string (four-byte uint32_t for n follow) + { + return get_string(get_number()); + } + + case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow) + { + return get_string(get_number()); + } + + case 0x7F: // UTF-8 string (indefinite length) + { + std::string result; + while (get() != 0xFF) + { + check_eof(); + result.push_back(static_cast(current)); + } + return result; + } + + default: + { + std::stringstream ss; + ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; + JSON_THROW(parse_error::create(113, chars_read, "expected a CBOR string; last byte: 0x" + ss.str())); + } + } + } + + template + BasicJsonType get_cbor_array(const NumberType len) + { + BasicJsonType result = value_t::array; + std::generate_n(std::back_inserter(*result.m_value.array), len, [this]() + { + return parse_cbor_internal(); + }); + return result; + } + + template + BasicJsonType get_cbor_object(const NumberType len) + { + BasicJsonType result = value_t::object; + std::generate_n(std::inserter(*result.m_value.object, + result.m_value.object->end()), + len, [this]() + { + get(); + auto key = get_cbor_string(); + auto val = parse_cbor_internal(); + return std::make_pair(std::move(key), std::move(val)); + }); + return result; + } + + /*! + @brief reads a MessagePack string + + This function first reads starting bytes to determine the expected + string length and then copies this number of bytes into a string. + + @return string + + @throw parse_error.110 if input ended + @throw parse_error.113 if an unexpected byte is read + */ + std::string get_msgpack_string() + { + check_eof(); + + switch (current) + { + // fixstr + case 0xA0: + case 0xA1: + case 0xA2: + case 0xA3: + case 0xA4: + case 0xA5: + case 0xA6: + case 0xA7: + case 0xA8: + case 0xA9: + case 0xAA: + case 0xAB: + case 0xAC: + case 0xAD: + case 0xAE: + case 0xAF: + case 0xB0: + case 0xB1: + case 0xB2: + case 0xB3: + case 0xB4: + case 0xB5: + case 0xB6: + case 0xB7: + case 0xB8: + case 0xB9: + case 0xBA: + case 0xBB: + case 0xBC: + case 0xBD: + case 0xBE: + case 0xBF: + { + return get_string(current & 0x1F); + } + + case 0xD9: // str 8 + { + return get_string(get_number()); + } + + case 0xDA: // str 16 + { + return get_string(get_number()); + } + + case 0xDB: // str 32 + { + return get_string(get_number()); + } + + default: + { + std::stringstream ss; + ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; + JSON_THROW(parse_error::create(113, chars_read, + "expected a MessagePack string; last byte: 0x" + ss.str())); + } + } + } + + template + BasicJsonType get_msgpack_array(const NumberType len) + { + BasicJsonType result = value_t::array; + std::generate_n(std::back_inserter(*result.m_value.array), len, [this]() + { + return parse_msgpack_internal(); + }); + return result; + } + + template + BasicJsonType get_msgpack_object(const NumberType len) + { + BasicJsonType result = value_t::object; + std::generate_n(std::inserter(*result.m_value.object, + result.m_value.object->end()), + len, [this]() + { + get(); + auto key = get_msgpack_string(); + auto val = parse_msgpack_internal(); + return std::make_pair(std::move(key), std::move(val)); + }); + return result; + } + + /*! + @brief check if input ended + @throw parse_error.110 if input ended + */ + void check_eof(const bool expect_eof = false) const + { + if (expect_eof) + { + if (JSON_UNLIKELY(current != std::char_traits::eof())) + { + JSON_THROW(parse_error::create(110, chars_read, "expected end of input")); + } + } + else + { + if (JSON_UNLIKELY(current == std::char_traits::eof())) + { + JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input")); + } + } + } + + private: + /// input adapter + input_adapter_t ia = nullptr; + + /// the current character + int current = std::char_traits::eof(); + + /// the number of characters read + std::size_t chars_read = 0; + + /// whether we can assume little endianess + const bool is_little_endian = little_endianess(); +}; +} +} + +#endif + +/*** End of inlined file: binary_reader.hpp ***/ + + +/*** Start of inlined file: output_adapters.hpp ***/ +#ifndef NLOHMANN_JSON_DETAIL_PARSING_OUTPUT_ADAPTERS_HPP +#define NLOHMANN_JSON_DETAIL_PARSING_OUTPUT_ADAPTERS_HPP + +#include // copy +#include // size_t +#include // streamsize +#include // back_inserter +#include // shared_ptr, make_shared +#include // basic_ostream +#include // basic_string +#include // vector + +namespace nlohmann +{ +namespace detail +{ +/// abstract output adapter interface +template struct output_adapter_protocol +{ + virtual void write_character(CharType c) = 0; + virtual void write_characters(const CharType* s, std::size_t length) = 0; + virtual ~output_adapter_protocol() = default; +}; + +/// a type to simplify interfaces +template +using output_adapter_t = std::shared_ptr>; + +/// output adapter for byte vectors +template +class output_vector_adapter : public output_adapter_protocol +{ + public: + explicit output_vector_adapter(std::vector& vec) : v(vec) {} + + void write_character(CharType c) override + { + v.push_back(c); + } + + void write_characters(const CharType* s, std::size_t length) override + { + std::copy(s, s + length, std::back_inserter(v)); + } + + private: + std::vector& v; +}; + +/// output adapter for output streams +template +class output_stream_adapter : public output_adapter_protocol +{ + public: + explicit output_stream_adapter(std::basic_ostream& s) : stream(s) {} + + void write_character(CharType c) override + { + stream.put(c); + } + + void write_characters(const CharType* s, std::size_t length) override + { + stream.write(s, static_cast(length)); + } + + private: + std::basic_ostream& stream; +}; + +/// output adapter for basic_string +template +class output_string_adapter : public output_adapter_protocol +{ + public: + explicit output_string_adapter(std::basic_string& s) : str(s) {} + + void write_character(CharType c) override + { + str.push_back(c); + } + + void write_characters(const CharType* s, std::size_t length) override + { + str.append(s, length); + } + + private: + std::basic_string& str; +}; + +template +class output_adapter +{ + public: + output_adapter(std::vector& vec) + : oa(std::make_shared>(vec)) {} + + output_adapter(std::basic_ostream& s) + : oa(std::make_shared>(s)) {} + + output_adapter(std::basic_string& s) + : oa(std::make_shared>(s)) {} + + operator output_adapter_t() + { + return oa; + } + + private: + output_adapter_t oa = nullptr; +}; +} +} + +#endif + +/*** End of inlined file: output_adapters.hpp ***/ + +namespace nlohmann +{ +namespace detail +{ +/////////////////// +// binary writer // +/////////////////// + +/*! +@brief serialization to CBOR and MessagePack values +*/ +template +class binary_writer +{ + public: + /*! + @brief create a binary writer + + @param[in] adapter output adapter to write to + */ + explicit binary_writer(output_adapter_t adapter) : oa(adapter) + { + assert(oa); + } + + /*! + @brief[in] j JSON value to serialize + */ + void write_cbor(const BasicJsonType& j) + { + switch (j.type()) + { + case value_t::null: + { + oa->write_character(static_cast(0xF6)); + break; + } + + case value_t::boolean: + { + oa->write_character(j.m_value.boolean + ? static_cast(0xF5) + : static_cast(0xF4)); + break; + } + + case value_t::number_integer: + { + if (j.m_value.number_integer >= 0) + { + // CBOR does not differentiate between positive signed + // integers and unsigned integers. Therefore, we used the + // code from the value_t::number_unsigned case here. + if (j.m_value.number_integer <= 0x17) + { + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_integer <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0x18)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_integer <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0x19)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_integer <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0x1A)); + write_number(static_cast(j.m_value.number_integer)); + } + else + { + oa->write_character(static_cast(0x1B)); + write_number(static_cast(j.m_value.number_integer)); + } + } + else + { + // The conversions below encode the sign in the first + // byte, and the value is converted to a positive number. + const auto positive_number = -1 - j.m_value.number_integer; + if (j.m_value.number_integer >= -24) + { + write_number(static_cast(0x20 + positive_number)); + } + else if (positive_number <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0x38)); + write_number(static_cast(positive_number)); + } + else if (positive_number <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0x39)); + write_number(static_cast(positive_number)); + } + else if (positive_number <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0x3A)); + write_number(static_cast(positive_number)); + } + else + { + oa->write_character(static_cast(0x3B)); + write_number(static_cast(positive_number)); + } + } + break; + } + + case value_t::number_unsigned: + { + if (j.m_value.number_unsigned <= 0x17) + { + write_number(static_cast(j.m_value.number_unsigned)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0x18)); + write_number(static_cast(j.m_value.number_unsigned)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0x19)); + write_number(static_cast(j.m_value.number_unsigned)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0x1A)); + write_number(static_cast(j.m_value.number_unsigned)); + } + else + { + oa->write_character(static_cast(0x1B)); + write_number(static_cast(j.m_value.number_unsigned)); + } + break; + } + + case value_t::number_float: // Double-Precision Float + { + oa->write_character(static_cast(0xFB)); + write_number(j.m_value.number_float); + break; + } + + case value_t::string: + { + // step 1: write control byte and the string length + const auto N = j.m_value.string->size(); + if (N <= 0x17) + { + write_number(static_cast(0x60 + N)); + } + else if (N <= 0xFF) + { + oa->write_character(static_cast(0x78)); + write_number(static_cast(N)); + } + else if (N <= 0xFFFF) + { + oa->write_character(static_cast(0x79)); + write_number(static_cast(N)); + } + else if (N <= 0xFFFFFFFF) + { + oa->write_character(static_cast(0x7A)); + write_number(static_cast(N)); + } + // LCOV_EXCL_START + else if (N <= 0xFFFFFFFFFFFFFFFF) + { + oa->write_character(static_cast(0x7B)); + write_number(static_cast(N)); + } + // LCOV_EXCL_STOP + + // step 2: write the string + oa->write_characters( + reinterpret_cast(j.m_value.string->c_str()), + j.m_value.string->size()); + break; + } + + case value_t::array: + { + // step 1: write control byte and the array size + const auto N = j.m_value.array->size(); + if (N <= 0x17) + { + write_number(static_cast(0x80 + N)); + } + else if (N <= 0xFF) + { + oa->write_character(static_cast(0x98)); + write_number(static_cast(N)); + } + else if (N <= 0xFFFF) + { + oa->write_character(static_cast(0x99)); + write_number(static_cast(N)); + } + else if (N <= 0xFFFFFFFF) + { + oa->write_character(static_cast(0x9A)); + write_number(static_cast(N)); + } + // LCOV_EXCL_START + else if (N <= 0xFFFFFFFFFFFFFFFF) + { + oa->write_character(static_cast(0x9B)); + write_number(static_cast(N)); + } + // LCOV_EXCL_STOP + + // step 2: write each element + for (const auto& el : *j.m_value.array) + { + write_cbor(el); + } + break; + } + + case value_t::object: + { + // step 1: write control byte and the object size + const auto N = j.m_value.object->size(); + if (N <= 0x17) + { + write_number(static_cast(0xA0 + N)); + } + else if (N <= 0xFF) + { + oa->write_character(static_cast(0xB8)); + write_number(static_cast(N)); + } + else if (N <= 0xFFFF) + { + oa->write_character(static_cast(0xB9)); + write_number(static_cast(N)); + } + else if (N <= 0xFFFFFFFF) + { + oa->write_character(static_cast(0xBA)); + write_number(static_cast(N)); + } + // LCOV_EXCL_START + else if (N <= 0xFFFFFFFFFFFFFFFF) + { + oa->write_character(static_cast(0xBB)); + write_number(static_cast(N)); + } + // LCOV_EXCL_STOP + + // step 2: write each element + for (const auto& el : *j.m_value.object) + { + write_cbor(el.first); + write_cbor(el.second); + } + break; + } + + default: + break; + } + } + + /*! + @brief[in] j JSON value to serialize + */ + void write_msgpack(const BasicJsonType& j) + { + switch (j.type()) + { + case value_t::null: // nil + { + oa->write_character(static_cast(0xC0)); + break; + } + + case value_t::boolean: // true and false + { + oa->write_character(j.m_value.boolean + ? static_cast(0xC3) + : static_cast(0xC2)); + break; + } + + case value_t::number_integer: + { + if (j.m_value.number_integer >= 0) + { + // MessagePack does not differentiate between positive + // signed integers and unsigned integers. Therefore, we used + // the code from the value_t::number_unsigned case here. + if (j.m_value.number_unsigned < 128) + { + // positive fixnum + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 8 + oa->write_character(static_cast(0xCC)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 16 + oa->write_character(static_cast(0xCD)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 32 + oa->write_character(static_cast(0xCE)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 64 + oa->write_character(static_cast(0xCF)); + write_number(static_cast(j.m_value.number_integer)); + } + } + else + { + if (j.m_value.number_integer >= -32) + { + // negative fixnum + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_integer >= (std::numeric_limits::min)() and + j.m_value.number_integer <= (std::numeric_limits::max)()) + { + // int 8 + oa->write_character(static_cast(0xD0)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_integer >= (std::numeric_limits::min)() and + j.m_value.number_integer <= (std::numeric_limits::max)()) + { + // int 16 + oa->write_character(static_cast(0xD1)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_integer >= (std::numeric_limits::min)() and + j.m_value.number_integer <= (std::numeric_limits::max)()) + { + // int 32 + oa->write_character(static_cast(0xD2)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_integer >= (std::numeric_limits::min)() and + j.m_value.number_integer <= (std::numeric_limits::max)()) + { + // int 64 + oa->write_character(static_cast(0xD3)); + write_number(static_cast(j.m_value.number_integer)); + } + } + break; + } + + case value_t::number_unsigned: + { + if (j.m_value.number_unsigned < 128) + { + // positive fixnum + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 8 + oa->write_character(static_cast(0xCC)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 16 + oa->write_character(static_cast(0xCD)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 32 + oa->write_character(static_cast(0xCE)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 64 + oa->write_character(static_cast(0xCF)); + write_number(static_cast(j.m_value.number_integer)); + } + break; + } + + case value_t::number_float: // float 64 + { + oa->write_character(static_cast(0xCB)); + write_number(j.m_value.number_float); + break; + } + + case value_t::string: + { + // step 1: write control byte and the string length + const auto N = j.m_value.string->size(); + if (N <= 31) + { + // fixstr + write_number(static_cast(0xA0 | N)); + } + else if (N <= 255) + { + // str 8 + oa->write_character(static_cast(0xD9)); + write_number(static_cast(N)); + } + else if (N <= 65535) + { + // str 16 + oa->write_character(static_cast(0xDA)); + write_number(static_cast(N)); + } + else if (N <= 4294967295) + { + // str 32 + oa->write_character(static_cast(0xDB)); + write_number(static_cast(N)); + } + + // step 2: write the string + oa->write_characters( + reinterpret_cast(j.m_value.string->c_str()), + j.m_value.string->size()); + break; + } + + case value_t::array: + { + // step 1: write control byte and the array size + const auto N = j.m_value.array->size(); + if (N <= 15) + { + // fixarray + write_number(static_cast(0x90 | N)); + } + else if (N <= 0xFFFF) + { + // array 16 + oa->write_character(static_cast(0xDC)); + write_number(static_cast(N)); + } + else if (N <= 0xFFFFFFFF) + { + // array 32 + oa->write_character(static_cast(0xDD)); + write_number(static_cast(N)); + } + + // step 2: write each element + for (const auto& el : *j.m_value.array) + { + write_msgpack(el); + } + break; + } + + case value_t::object: + { + // step 1: write control byte and the object size + const auto N = j.m_value.object->size(); + if (N <= 15) + { + // fixmap + write_number(static_cast(0x80 | (N & 0xF))); + } + else if (N <= 65535) + { + // map 16 + oa->write_character(static_cast(0xDE)); + write_number(static_cast(N)); + } + else if (N <= 4294967295) + { + // map 32 + oa->write_character(static_cast(0xDF)); + write_number(static_cast(N)); + } + + // step 2: write each element + for (const auto& el : *j.m_value.object) + { + write_msgpack(el.first); + write_msgpack(el.second); + } + break; + } + + default: + break; + } + } + + private: + /* + @brief write a number to output input + + @param[in] n number of type @a NumberType + @tparam NumberType the type of the number + + @note This function needs to respect the system's endianess, because bytes + in CBOR and MessagePack are stored in network order (big endian) and + therefore need reordering on little endian systems. + */ + template void write_number(NumberType n) + { + // step 1: write number to array of length NumberType + std::array vec; + std::memcpy(vec.data(), &n, sizeof(NumberType)); + + // step 2: write array to output (with possible reordering) + if (is_little_endian) + { + // reverse byte order prior to conversion if necessary + std::reverse(vec.begin(), vec.end()); + } + + oa->write_characters(vec.data(), sizeof(NumberType)); + } + + private: + /// whether we can assume little endianess + const bool is_little_endian = binary_reader::little_endianess(); + + /// the output + output_adapter_t oa = nullptr; +}; +} +} + +#endif + +/*** End of inlined file: binary_writer.hpp ***/ + + +/*** Start of inlined file: serializer.hpp ***/ +#ifndef NLOHMANN_JSON_DETAIL_SERIALIZER_HPP +#define NLOHMANN_JSON_DETAIL_SERIALIZER_HPP + +#include // reverse, remove, fill, find, none_of +#include // array +#include // assert +#include // and, or +#include // localeconv, lconv +#include // labs, isfinite, isnan, signbit +#include // size_t, ptrdiff_t +#include // uint8_t +#include // snprintf +#include // next +#include // numeric_limits +#include // string +#include // is_same + +namespace nlohmann +{ +namespace detail +{ +/////////////////// +// serialization // +/////////////////// + +template +class serializer +{ + using string_t = typename BasicJsonType::string_t; + using number_float_t = typename BasicJsonType::number_float_t; + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + public: + /*! + @param[in] s output stream to serialize to + @param[in] ichar indentation character to use + */ + serializer(output_adapter_t s, const char ichar) + : o(std::move(s)), loc(std::localeconv()), + thousands_sep(loc->thousands_sep == nullptr ? '\0' : * (loc->thousands_sep)), + decimal_point(loc->decimal_point == nullptr ? '\0' : * (loc->decimal_point)), + indent_char(ichar), indent_string(512, indent_char) {} + + // delete because of pointer members + serializer(const serializer&) = delete; + serializer& operator=(const serializer&) = delete; + + /*! + @brief internal implementation of the serialization function + + This function is called by the public member function dump and organizes + the serialization internally. The indentation level is propagated as + additional parameter. In case of arrays and objects, the function is + called recursively. + + - strings and object keys are escaped using `escape_string()` + - integer numbers are converted implicitly via `operator<<` + - floating-point numbers are converted to a string using `"%g"` format + + @param[in] val value to serialize + @param[in] pretty_print whether the output shall be pretty-printed + @param[in] indent_step the indent level + @param[in] current_indent the current indent level (only used internally) + */ + void dump(const BasicJsonType& val, const bool pretty_print, + const bool ensure_ascii, + const unsigned int indent_step, + const unsigned int current_indent = 0) + { + switch (val.m_type) + { + case value_t::object: + { + if (val.m_value.object->empty()) + { + o->write_characters("{}", 2); + return; + } + + if (pretty_print) + { + o->write_characters("{\n", 2); + + // variable to hold indentation for recursive calls + const auto new_indent = current_indent + indent_step; + if (JSON_UNLIKELY(indent_string.size() < new_indent)) + { + indent_string.resize(indent_string.size() * 2, ' '); + } + + // first n-1 elements + auto i = val.m_value.object->cbegin(); + for (std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i) + { + o->write_characters(indent_string.c_str(), new_indent); + o->write_character('\"'); + dump_escaped(i->first, ensure_ascii); + o->write_characters("\": ", 3); + dump(i->second, true, ensure_ascii, indent_step, new_indent); + o->write_characters(",\n", 2); + } + + // last element + assert(i != val.m_value.object->cend()); + assert(std::next(i) == val.m_value.object->cend()); + o->write_characters(indent_string.c_str(), new_indent); + o->write_character('\"'); + dump_escaped(i->first, ensure_ascii); + o->write_characters("\": ", 3); + dump(i->second, true, ensure_ascii, indent_step, new_indent); + + o->write_character('\n'); + o->write_characters(indent_string.c_str(), current_indent); + o->write_character('}'); + } + else + { + o->write_character('{'); + + // first n-1 elements + auto i = val.m_value.object->cbegin(); + for (std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i) + { + o->write_character('\"'); + dump_escaped(i->first, ensure_ascii); + o->write_characters("\":", 2); + dump(i->second, false, ensure_ascii, indent_step, current_indent); + o->write_character(','); + } + + // last element + assert(i != val.m_value.object->cend()); + assert(std::next(i) == val.m_value.object->cend()); + o->write_character('\"'); + dump_escaped(i->first, ensure_ascii); + o->write_characters("\":", 2); + dump(i->second, false, ensure_ascii, indent_step, current_indent); + + o->write_character('}'); + } + + return; + } + + case value_t::array: + { + if (val.m_value.array->empty()) + { + o->write_characters("[]", 2); + return; + } + + if (pretty_print) + { + o->write_characters("[\n", 2); + + // variable to hold indentation for recursive calls + const auto new_indent = current_indent + indent_step; + if (JSON_UNLIKELY(indent_string.size() < new_indent)) + { + indent_string.resize(indent_string.size() * 2, ' '); + } + + // first n-1 elements + for (auto i = val.m_value.array->cbegin(); + i != val.m_value.array->cend() - 1; ++i) + { + o->write_characters(indent_string.c_str(), new_indent); + dump(*i, true, ensure_ascii, indent_step, new_indent); + o->write_characters(",\n", 2); + } + + // last element + assert(not val.m_value.array->empty()); + o->write_characters(indent_string.c_str(), new_indent); + dump(val.m_value.array->back(), true, ensure_ascii, indent_step, new_indent); + + o->write_character('\n'); + o->write_characters(indent_string.c_str(), current_indent); + o->write_character(']'); + } + else + { + o->write_character('['); + + // first n-1 elements + for (auto i = val.m_value.array->cbegin(); + i != val.m_value.array->cend() - 1; ++i) + { + dump(*i, false, ensure_ascii, indent_step, current_indent); + o->write_character(','); + } + + // last element + assert(not val.m_value.array->empty()); + dump(val.m_value.array->back(), false, ensure_ascii, indent_step, current_indent); + + o->write_character(']'); + } + + return; + } + + case value_t::string: + { + o->write_character('\"'); + dump_escaped(*val.m_value.string, ensure_ascii); + o->write_character('\"'); + return; + } + + case value_t::boolean: + { + if (val.m_value.boolean) + { + o->write_characters("true", 4); + } + else + { + o->write_characters("false", 5); + } + return; + } + + case value_t::number_integer: + { + dump_integer(val.m_value.number_integer); + return; + } + + case value_t::number_unsigned: + { + dump_integer(val.m_value.number_unsigned); + return; + } + + case value_t::number_float: + { + dump_float(val.m_value.number_float); + return; + } + + case value_t::discarded: + { + o->write_characters("", 11); + return; + } + + case value_t::null: + { + o->write_characters("null", 4); + return; + } + } + } + + private: + /*! + @brief returns the number of expected bytes following in UTF-8 string + + @param[in] u the first byte of a UTF-8 string + @return the number of expected bytes following + */ + static constexpr std::size_t bytes_following(const uint8_t u) + { + return ((u <= 127) ? 0 + : ((192 <= u and u <= 223) ? 1 + : ((224 <= u and u <= 239) ? 2 + : ((240 <= u and u <= 247) ? 3 : std::string::npos)))); + } + + /*! + @brief calculates the extra space to escape a JSON string + + @param[in] s the string to escape + @param[in] ensure_ascii whether to escape non-ASCII characters with + \uXXXX sequences + @return the number of characters required to escape string @a s + + @complexity Linear in the length of string @a s. + */ + static std::size_t extra_space(const string_t& s, + const bool ensure_ascii) noexcept + { + std::size_t res = 0; + + for (std::size_t i = 0; i < s.size(); ++i) + { + switch (s[i]) + { + // control characters that can be escaped with a backslash + case '"': + case '\\': + case '\b': + case '\f': + case '\n': + case '\r': + case '\t': + { + // from c (1 byte) to \x (2 bytes) + res += 1; + break; + } + + // control characters that need \uxxxx escaping + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x0B: + case 0x0E: + case 0x0F: + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + case 0x1A: + case 0x1B: + case 0x1C: + case 0x1D: + case 0x1E: + case 0x1F: + { + // from c (1 byte) to \uxxxx (6 bytes) + res += 5; + break; + } + + default: + { + if (ensure_ascii and (s[i] & 0x80 or s[i] == 0x7F)) + { + const auto bytes = bytes_following(static_cast(s[i])); + // invalid characters will be detected by throw_if_invalid_utf8 + assert (bytes != std::string::npos); + + if (bytes == 3) + { + // codepoints that need 4 bytes (i.e., 3 additional + // bytes) in UTF-8 need a surrogate pair when \u + // escaping is used: from 4 bytes to \uxxxx\uxxxx + // (12 bytes) + res += (12 - bytes - 1); + } + else + { + // from x bytes to \uxxxx (6 bytes) + res += (6 - bytes - 1); + } + + // skip the additional bytes + i += bytes; + } + break; + } + } + } + + return res; + } + + static void escape_codepoint(int codepoint, string_t& result, std::size_t& pos) + { + // expecting a proper codepoint + assert(0x00 <= codepoint and codepoint <= 0x10FFFF); + + // the last written character was the backslash before the 'u' + assert(result[pos] == '\\'); + + // write the 'u' + result[++pos] = 'u'; + + // convert a number 0..15 to its hex representation (0..f) + static const std::array hexify = + { + { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' + } + }; + + if (codepoint < 0x10000) + { + // codepoints U+0000..U+FFFF can be represented as \uxxxx. + result[++pos] = hexify[(codepoint >> 12) & 0x0F]; + result[++pos] = hexify[(codepoint >> 8) & 0x0F]; + result[++pos] = hexify[(codepoint >> 4) & 0x0F]; + result[++pos] = hexify[codepoint & 0x0F]; + } + else + { + // codepoints U+10000..U+10FFFF need a surrogate pair to be + // represented as \uxxxx\uxxxx. + // http://www.unicode.org/faq/utf_bom.html#utf16-4 + codepoint -= 0x10000; + const int high_surrogate = 0xD800 | ((codepoint >> 10) & 0x3FF); + const int low_surrogate = 0xDC00 | (codepoint & 0x3FF); + result[++pos] = hexify[(high_surrogate >> 12) & 0x0F]; + result[++pos] = hexify[(high_surrogate >> 8) & 0x0F]; + result[++pos] = hexify[(high_surrogate >> 4) & 0x0F]; + result[++pos] = hexify[high_surrogate & 0x0F]; + ++pos; // backslash is already in output + result[++pos] = 'u'; + result[++pos] = hexify[(low_surrogate >> 12) & 0x0F]; + result[++pos] = hexify[(low_surrogate >> 8) & 0x0F]; + result[++pos] = hexify[(low_surrogate >> 4) & 0x0F]; + result[++pos] = hexify[low_surrogate & 0x0F]; + } + + ++pos; + } + + /*! + @brief dump escaped string + + Escape a string by replacing certain special characters by a sequence of an + escape character (backslash) and another character and other control + characters by a sequence of "\u" followed by a four-digit hex + representation. The escaped string is written to output stream @a o. + + @param[in] s the string to escape + @param[in] ensure_ascii whether to escape non-ASCII characters with + \uXXXX sequences + + @complexity Linear in the length of string @a s. + */ + void dump_escaped(const string_t& s, const bool ensure_ascii) const + { + throw_if_invalid_utf8(s); + + const auto space = extra_space(s, ensure_ascii); + if (space == 0) + { + o->write_characters(s.c_str(), s.size()); + return; + } + + // create a result string of necessary size + string_t result(s.size() + space, '\\'); + std::size_t pos = 0; + + for (std::size_t i = 0; i < s.size(); ++i) + { + switch (s[i]) + { + case '"': // quotation mark (0x22) + { + result[pos + 1] = '"'; + pos += 2; + break; + } + + case '\\': // reverse solidus (0x5C) + { + // nothing to change + pos += 2; + break; + } + + case '\b': // backspace (0x08) + { + result[pos + 1] = 'b'; + pos += 2; + break; + } + + case '\f': // formfeed (0x0C) + { + result[pos + 1] = 'f'; + pos += 2; + break; + } + + case '\n': // newline (0x0A) + { + result[pos + 1] = 'n'; + pos += 2; + break; + } + + case '\r': // carriage return (0x0D) + { + result[pos + 1] = 'r'; + pos += 2; + break; + } + + case '\t': // horizontal tab (0x09) + { + result[pos + 1] = 't'; + pos += 2; + break; + } + + default: + { + // escape control characters (0x00..0x1F) or, if + // ensure_ascii parameter is used, non-ASCII characters + if ((0x00 <= s[i] and s[i] <= 0x1F) or + (ensure_ascii and (s[i] & 0x80 or s[i] == 0x7F))) + { + const auto bytes = bytes_following(static_cast(s[i])); + // invalid characters will be detected by throw_if_invalid_utf8 + assert (bytes != std::string::npos); + + // check that the additional bytes are present + assert(i + bytes < s.size()); + + // to use \uxxxx escaping, we first need to calculate + // the codepoint from the UTF-8 bytes + int codepoint = 0; + + // bytes is unsigned type: + assert(bytes <= 3); + switch (bytes) + { + case 0: + { + codepoint = s[i] & 0xFF; + break; + } + + case 1: + { + codepoint = ((s[i] & 0x3F) << 6) + + (s[i + 1] & 0x7F); + break; + } + + case 2: + { + codepoint = ((s[i] & 0x1F) << 12) + + ((s[i + 1] & 0x7F) << 6) + + (s[i + 2] & 0x7F); + break; + } + + case 3: + { + codepoint = ((s[i] & 0xF) << 18) + + ((s[i + 1] & 0x7F) << 12) + + ((s[i + 2] & 0x7F) << 6) + + (s[i + 3] & 0x7F); + break; + } + + default: + break; // LCOV_EXCL_LINE + } + + escape_codepoint(codepoint, result, pos); + i += bytes; + } + else + { + // all other characters are added as-is + result[pos++] = s[i]; + } + break; + } + } + } + + assert(pos == result.size()); + o->write_characters(result.c_str(), result.size()); + } + + /*! + @brief dump an integer + + Dump a given integer to output stream @a o. Works internally with + @a number_buffer. + + @param[in] x integer number (signed or unsigned) to dump + @tparam NumberType either @a number_integer_t or @a number_unsigned_t + */ + template::value or + std::is_same::value, + int> = 0> + void dump_integer(NumberType x) + { + // special case for "0" + if (x == 0) + { + o->write_character('0'); + return; + } + + const bool is_negative = (x <= 0) and (x != 0); // see issue #755 + std::size_t i = 0; + + while (x != 0) + { + // spare 1 byte for '\0' + assert(i < number_buffer.size() - 1); + + const auto digit = std::labs(static_cast(x % 10)); + number_buffer[i++] = static_cast('0' + digit); + x /= 10; + } + + if (is_negative) + { + // make sure there is capacity for the '-' + assert(i < number_buffer.size() - 2); + number_buffer[i++] = '-'; + } + + std::reverse(number_buffer.begin(), number_buffer.begin() + i); + o->write_characters(number_buffer.data(), i); + } + + /*! + @brief dump a floating-point number + + Dump a given floating-point number to output stream @a o. Works internally + with @a number_buffer. + + @param[in] x floating-point number to dump + */ + void dump_float(number_float_t x) + { + // NaN / inf + if (not std::isfinite(x) or std::isnan(x)) + { + o->write_characters("null", 4); + return; + } + + // get number of digits for a text -> float -> text round-trip + static constexpr auto d = std::numeric_limits::digits10; + + // the actual conversion + std::ptrdiff_t len = snprintf(number_buffer.data(), number_buffer.size(), "%.*g", d, x); + + // negative value indicates an error + assert(len > 0); + // check if buffer was large enough + assert(static_cast(len) < number_buffer.size()); + + // erase thousands separator + if (thousands_sep != '\0') + { + const auto end = std::remove(number_buffer.begin(), + number_buffer.begin() + len, thousands_sep); + std::fill(end, number_buffer.end(), '\0'); + assert((end - number_buffer.begin()) <= len); + len = (end - number_buffer.begin()); + } + + // convert decimal point to '.' + if (decimal_point != '\0' and decimal_point != '.') + { + const auto dec_pos = std::find(number_buffer.begin(), number_buffer.end(), decimal_point); + if (dec_pos != number_buffer.end()) + { + *dec_pos = '.'; + } + } + + o->write_characters(number_buffer.data(), static_cast(len)); + + // determine if need to append ".0" + const bool value_is_int_like = + std::none_of(number_buffer.begin(), number_buffer.begin() + len + 1, + [](char c) + { + return (c == '.' or c == 'e'); + }); + + if (value_is_int_like) + { + o->write_characters(".0", 2); + } + } + + /*! + @brief check whether a string is UTF-8 encoded + + The function checks each byte of a string whether it is UTF-8 encoded. The + result of the check is stored in the @a state parameter. The function must + be called initially with state 0 (accept). State 1 means the string must + be rejected, because the current byte is not allowed. If the string is + completely processed, but the state is non-zero, the string ended + prematurely; that is, the last byte indicated more bytes should have + followed. + + @param[in,out] state the state of the decoding + @param[in] byte next byte to decode + + @note The function has been edited: a std::array is used and the code + point is not calculated. + + @copyright Copyright (c) 2008-2009 Bjoern Hoehrmann + @sa http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ + */ + static void decode(uint8_t& state, const uint8_t byte) + { + static const std::array utf8d = + { + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00..1F + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20..3F + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 40..5F + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60..7F + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 80..9F + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // A0..BF + 8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // C0..DF + 0xA, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3, 0x3, // E0..EF + 0xB, 0x6, 0x6, 0x6, 0x5, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, // F0..FF + 0x0, 0x1, 0x2, 0x3, 0x5, 0x8, 0x7, 0x1, 0x1, 0x1, 0x4, 0x6, 0x1, 0x1, 0x1, 0x1, // s0..s0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, // s1..s2 + 1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, // s3..s4 + 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, // s5..s6 + 1, 3, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // s7..s8 + } + }; + + const uint8_t type = utf8d[byte]; + state = utf8d[256u + state * 16u + type]; + } + + /*! + @brief throw an exception if a string is not UTF-8 encoded + + @param[in] str UTF-8 string to check + @throw type_error.316 if passed string is not UTF-8 encoded + + @since version 3.0.0 + */ + static void throw_if_invalid_utf8(const std::string& str) + { + // start with state 0 (= accept) + uint8_t state = 0; + + for (size_t i = 0; i < str.size(); ++i) + { + const auto byte = static_cast(str[i]); + decode(state, byte); + if (state == 1) + { + // state 1 means reject + std::stringstream ss; + ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << static_cast(byte); + JSON_THROW(type_error::create(316, "invalid UTF-8 byte at index " + std::to_string(i) + ": 0x" + ss.str())); + } + } + + if (state != 0) + { + // we finish reading, but do not accept: string was incomplete + std::stringstream ss; + ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << static_cast(static_cast(str.back())); + JSON_THROW(type_error::create(316, "incomplete UTF-8 string; last byte: 0x" + ss.str())); + } + } + + private: + /// the output of the serializer + output_adapter_t o = nullptr; + + /// a (hopefully) large enough character buffer + std::array number_buffer{{}}; + + /// the locale + const std::lconv* loc = nullptr; + /// the locale's thousand separator character + const char thousands_sep = '\0'; + /// the locale's decimal point character + const char decimal_point = '\0'; + + /// the indentation character + const char indent_char; + + /// the indentation string + string_t indent_string; +}; +} +} + +#endif + +/*** End of inlined file: serializer.hpp ***/ + + +/*** Start of inlined file: json_ref.hpp ***/ +#ifndef NLOHMANN_JSON_DETAIL_JSON_REF_HPP +#define NLOHMANN_JSON_DETAIL_JSON_REF_HPP + +#include +#include + +namespace nlohmann +{ +namespace detail +{ +template +class json_ref +{ + public: + using value_type = BasicJsonType; + + json_ref(value_type&& value) + : owned_value(std::move(value)), value_ref(&owned_value), is_rvalue(true) + {} + + json_ref(const value_type& value) + : value_ref(const_cast(&value)), is_rvalue(false) + {} + + json_ref(std::initializer_list init) + : owned_value(init), value_ref(&owned_value), is_rvalue(true) + {} + + template + json_ref(Args&& ... args) + : owned_value(std::forward(args)...), value_ref(&owned_value), is_rvalue(true) + {} + + // class should be movable only + json_ref(json_ref&&) = default; + json_ref(const json_ref&) = delete; + json_ref& operator=(const json_ref&) = delete; + + value_type moved_or_copied() const + { + if (is_rvalue) + { + return std::move(*value_ref); + } + return *value_ref; + } + + value_type const& operator*() const + { + return *static_cast(value_ref); + } + + value_type const* operator->() const + { + return static_cast(value_ref); + } + + private: + mutable value_type owned_value = nullptr; + value_type* value_ref = nullptr; + const bool is_rvalue; +}; +} +} + +#endif + +/*** End of inlined file: json_ref.hpp ***/ + + +/*** Start of inlined file: adl_serializer.hpp ***/ +#ifndef NLOHMANN_JSON_ADL_SERIALIZER_HPP +#define NLOHMANN_JSON_ADL_SERIALIZER_HPP + +#include + +namespace nlohmann +{ +template +struct adl_serializer +{ + /*! + @brief convert a JSON value to any value type + + This function is usually called by the `get()` function of the + @ref basic_json class (either explicit or via conversion operators). + + @param[in] j JSON value to read from + @param[in,out] val value to write to + */ + template + static void from_json(BasicJsonType&& j, ValueType& val) noexcept( + noexcept(::nlohmann::from_json(std::forward(j), val))) + { + ::nlohmann::from_json(std::forward(j), val); + } + + /*! + @brief convert any value type to a JSON value + + This function is usually called by the constructors of the @ref basic_json + class. + + @param[in,out] j JSON value to write to + @param[in] val value to read from + */ + template + static void to_json(BasicJsonType& j, ValueType&& val) noexcept( + noexcept(::nlohmann::to_json(j, std::forward(val)))) + { + ::nlohmann::to_json(j, std::forward(val)); + } +}; +} + +#endif + +/*** End of inlined file: adl_serializer.hpp ***/ /*! @brief namespace for Niels Lohmann @@ -552,7 +11640,6 @@ class basic_json /// @} - ///////////////////// // container types // ///////////////////// @@ -594,7 +11681,6 @@ class basic_json /// @} - /*! @brief returns the allocator associated with the container */ @@ -681,7 +11767,6 @@ class basic_json return result; } - /////////////////////////// // JSON value data types // /////////////////////////// @@ -1426,7 +12511,6 @@ class basic_json */ using parser_callback_t = typename parser::parser_callback_t; - ////////////////// // constructors // ////////////////// @@ -1952,7 +13036,6 @@ class basic_json assert_invariant(); } - /////////////////////////////////////// // other constructors and destructor // /////////////////////////////////////// @@ -3060,7 +14143,6 @@ class basic_json /// @} - //////////////////// // element access // //////////////////// @@ -4056,7 +15138,6 @@ class basic_json /// @} - //////////// // lookup // //////////// @@ -4146,7 +15227,6 @@ class basic_json /// @} - /////////////// // iterators // /////////////// @@ -4558,7 +15638,6 @@ class basic_json /// @} - ////////////// // capacity // ////////////// @@ -4775,7 +15854,6 @@ class basic_json /// @} - /////////////// // modifiers // /////////////// @@ -6138,7 +17216,6 @@ class basic_json /// @} - ///////////////////// // deserialization // ///////////////////// @@ -6412,7 +17489,6 @@ class basic_json } } - private: ////////////////////// // member variables // @@ -8019,6 +19095,35 @@ inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std return nlohmann::json::json_pointer(std::string(s, n)); } -#include "detail/macro_unscope.hpp" + +/*** Start of inlined file: macro_unscope.hpp ***/ +#ifndef NLOHMANN_JSON_DETAIL_MACRO_UNSCOPE_HPP + #define NLOHMANN_JSON_DETAIL_MACRO_UNSCOPE_HPP + + // restore GCC/clang diagnostic settings + #if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #pragma GCC diagnostic pop + #endif + #if defined(__clang__) + #pragma GCC diagnostic pop + #endif + + // clean up + #undef JSON_CATCH + #undef JSON_THROW + #undef JSON_TRY + #undef JSON_LIKELY + #undef JSON_UNLIKELY + #undef JSON_DEPRECATED + #undef JSON_HAS_CPP_14 + #undef JSON_HAS_CPP_17 + #undef NLOHMANN_BASIC_JSON_TPL_DECLARATION + #undef NLOHMANN_BASIC_JSON_TPL + #undef NLOHMANN_JSON_HAS_HELPER #endif + +/*** End of inlined file: macro_unscope.hpp ***/ + +#endif + From ce53537ba25f249fba0a905aff96a3e718fed922 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Tue, 9 Jan 2018 23:15:06 +0100 Subject: [PATCH 55/59] :heavy_minus_sign: :heavy_plus_sign: replaces amalgamation tool The tool used before created a lot of duplicates inside the generated amalgamation. The new tool is a single Python file which seems to do the same job. --- CMakeLists.txt | 21 - Makefile | 57 +- src/json.hpp | 3918 ++---------------------------------------------- 3 files changed, 123 insertions(+), 3873 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cd513a97..b2acb73f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -68,27 +68,6 @@ if(BUILD_TESTING AND JSON_BuildTests) add_subdirectory(test) endif() -## -## AMALGAMATION -## create a single header file -## -option(JSON_Amalgamate "Build and use amalgamation" OFF) - -if(JSON_Amalgamate) - ExternalProject_Add(amalgamate - GIT_REPOSITORY "https://github.com/theodelrieu/Amalgamate" - CMAKE_ARGS "-DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR}" - ) - - # There is no way to tell amalgamate to force-write the output file even if it already exists... - add_custom_target(single_header ALL rm -f "${CMAKE_SOURCE_DIR}/${NLOHMANN_JSON_SOURCE_DIR}/json.hpp" - COMMENT "Amalgamating json.hpp..." - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/develop - DEPENDS amalgamate - COMMAND "${CMAKE_BINARY_DIR}/bin/amalgamate" -w '*.hpp' -i . json.hpp "${CMAKE_SOURCE_DIR}/${NLOHMANN_JSON_SOURCE_DIR}/json.hpp" - ) -endif() - ## ## INSTALL ## install header files, generate and install cmake config files for find_package() diff --git a/Makefile b/Makefile index adf2b402..0029f849 100644 --- a/Makefile +++ b/Makefile @@ -1,30 +1,28 @@ .PHONY: pretty clean ChangeLog.md -SRCDIR = ./src -DEVDIR = ./develop -SRCS = $(SRCDIR)/json.hpp \ - $(DEVDIR)/json_fwd.hpp \ - $(DEVDIR)/detail/macro_scope.hpp \ - $(DEVDIR)/detail/macro_unscope.hpp \ - $(DEVDIR)/detail/meta.hpp \ - $(DEVDIR)/detail/exceptions.hpp \ - $(DEVDIR)/detail/value_t.hpp \ - $(DEVDIR)/detail/conversions/from_json.hpp \ - $(DEVDIR)/detail/conversions/to_json.hpp \ - $(DEVDIR)/detail/parsing/input_adapters.hpp \ - $(DEVDIR)/detail/parsing/lexer.hpp \ - $(DEVDIR)/detail/parsing/parser.hpp \ - $(DEVDIR)/detail/iterators/primitive_iterator.hpp \ - $(DEVDIR)/detail/iterators/internal_iterator.hpp \ - $(DEVDIR)/detail/iterators/iter_impl.hpp \ - $(DEVDIR)/detail/iterators/iteration_proxy.hpp \ - $(DEVDIR)/detail/iterators/json_reverse_iterator.hpp \ - $(DEVDIR)/detail/parsing/output_adapters.hpp \ - $(DEVDIR)/detail/parsing/binary_reader.hpp \ - $(DEVDIR)/detail/parsing/binary_writer.hpp \ - $(DEVDIR)/detail/serializer.hpp \ - $(DEVDIR)/detail/json_ref.hpp \ - $(DEVDIR)/adl_serializer.hpp +SRCS = develop/json.hpp \ + develop/json_fwd.hpp \ + develop/detail/macro_scope.hpp \ + develop/detail/macro_unscope.hpp \ + develop/detail/meta.hpp \ + develop/detail/exceptions.hpp \ + develop/detail/value_t.hpp \ + develop/detail/conversions/from_json.hpp \ + develop/detail/conversions/to_json.hpp \ + develop/detail/parsing/input_adapters.hpp \ + develop/detail/parsing/lexer.hpp \ + develop/detail/parsing/parser.hpp \ + develop/detail/iterators/primitive_iterator.hpp \ + develop/detail/iterators/internal_iterator.hpp \ + develop/detail/iterators/iter_impl.hpp \ + develop/detail/iterators/iteration_proxy.hpp \ + develop/detail/iterators/json_reverse_iterator.hpp \ + develop/detail/parsing/output_adapters.hpp \ + develop/detail/parsing/binary_reader.hpp \ + develop/detail/parsing/binary_writer.hpp \ + develop/detail/serializer.hpp \ + develop/detail/json_ref.hpp \ + develop/adl_serializer.hpp UNAME = $(shell uname) CXX=clang++ @@ -247,9 +245,16 @@ pretty: --indent-col1-comments --pad-oper --pad-header --align-pointer=type \ --align-reference=type --add-brackets --convert-tabs --close-templates \ --lineend=linux --preserve-date --suffix=none --formatted \ - $(SRCS) test/src/*.cpp \ + $(SRCS) src/json.hpp test/src/*.cpp \ benchmarks/src/benchmarks.cpp doc/examples/*.cpp +# create single header file +amalgamate: src/json.hpp + +src/json.hpp: $(SRCS) + develop/amalgamate/amalgamate.py -c develop/amalgamate/config.json -s develop --verbose=yes + $(MAKE) pretty + ########################################################################## # changelog diff --git a/src/json.hpp b/src/json.hpp index 00b10675..cc43f5b5 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -41,8 +41,7 @@ SOFTWARE. #include // string, stoi, to_string #include // declval, forward, move, pair, swap - -/*** Start of inlined file: json_fwd.hpp ***/ +// #include "json_fwd.hpp" #ifndef NLOHMANN_JSON_FWD_HPP #define NLOHMANN_JSON_FWD_HPP @@ -107,10 +106,7 @@ using json = basic_json<>; #endif -/*** End of inlined file: json_fwd.hpp ***/ - - -/*** Start of inlined file: macro_scope.hpp ***/ +// #include "detail/macro_scope.hpp" #ifndef NLOHMANN_JSON_MACRO_SCOPE_HPP #define NLOHMANN_JSON_MACRO_SCOPE_HPP @@ -218,10 +214,7 @@ contains a `mapped_type`, whereas `std::vector` fails the test. #endif -/*** End of inlined file: macro_scope.hpp ***/ - - -/*** Start of inlined file: meta.hpp ***/ +// #include "detail/meta.hpp" #ifndef NLOHMANN_JSON_DETAIL_META_HPP #define NLOHMANN_JSON_DETAIL_META_HPP @@ -231,184 +224,10 @@ contains a `mapped_type`, whereas `std::vector` fails the test. #include // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type #include // declval +// #include "json_fwd.hpp" -/*** Start of inlined file: json_fwd.hpp ***/ -#ifndef NLOHMANN_JSON_FWD_HPP -#define NLOHMANN_JSON_FWD_HPP +// #include "detail/macro_scope.hpp" -#include // int64_t, uint64_t -#include // map -#include // allocator -#include // string -#include // vector - -/*! -@brief namespace for Niels Lohmann -@see https://github.com/nlohmann -@since version 1.0.0 -*/ -namespace nlohmann -{ -/*! -@brief default JSONSerializer template argument - -This serializer ignores the template arguments and uses ADL -([argument-dependent lookup](http://en.cppreference.com/w/cpp/language/adl)) -for serialization. -*/ -template -struct adl_serializer; - -template class ObjectType = - std::map, - template class ArrayType = std::vector, - class StringType = std::string, class BooleanType = bool, - class NumberIntegerType = std::int64_t, - class NumberUnsignedType = std::uint64_t, - class NumberFloatType = double, - template class AllocatorType = std::allocator, - template class JSONSerializer = - adl_serializer> -class basic_json; - -/*! -@brief JSON Pointer - -A JSON pointer defines a string syntax for identifying a specific value -within a JSON document. It can be used with functions `at` and -`operator[]`. Furthermore, JSON pointers are the base for JSON patches. - -@sa [RFC 6901](https://tools.ietf.org/html/rfc6901) - -@since version 2.0.0 -*/ -class json_pointer; - -/*! -@brief default JSON class - -This type is the default specialization of the @ref basic_json class which -uses the standard template types. - -@since version 1.0.0 -*/ -using json = basic_json<>; -} - -#endif - -/*** End of inlined file: json_fwd.hpp ***/ - - -/*** Start of inlined file: macro_scope.hpp ***/ -#ifndef NLOHMANN_JSON_MACRO_SCOPE_HPP -#define NLOHMANN_JSON_MACRO_SCOPE_HPP - -#include // not - -// This file contains all internal macro definitions -// You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them - -// exclude unsupported compilers -#if defined(__clang__) - #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400 - #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" - #endif -#elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER)) - #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40900 - #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" - #endif -#endif - -// disable float-equal warnings on GCC/clang -#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wfloat-equal" -#endif - -// disable documentation warnings on clang -#if defined(__clang__) - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wdocumentation" -#endif - -// allow for portable deprecation warnings -#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) - #define JSON_DEPRECATED __attribute__((deprecated)) -#elif defined(_MSC_VER) - #define JSON_DEPRECATED __declspec(deprecated) -#else - #define JSON_DEPRECATED -#endif - -// allow to disable exceptions -#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && not defined(JSON_NOEXCEPTION) - #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 - -// manual branch prediction -#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) - #define JSON_LIKELY(x) __builtin_expect(!!(x), 1) - #define JSON_UNLIKELY(x) __builtin_expect(!!(x), 0) -#else - #define JSON_LIKELY(x) x - #define JSON_UNLIKELY(x) x -#endif - -// C++ language standard detection -#if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 - #define JSON_HAS_CPP_17 - #define JSON_HAS_CPP_14 -#elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) - #define JSON_HAS_CPP_14 -#endif - -// Ugly macros to avoid uglier copy-paste when specializing basic_json. They -// may be removed in the future once the class is split. - -#define NLOHMANN_BASIC_JSON_TPL_DECLARATION \ - template class ObjectType, \ - template class ArrayType, \ - class StringType, class BooleanType, class NumberIntegerType, \ - class NumberUnsignedType, class NumberFloatType, \ - template class AllocatorType, \ - template class JSONSerializer> - -#define NLOHMANN_BASIC_JSON_TPL \ - basic_json - -/*! -@brief Helper to determine whether there's a key_type for T. - -This helper is used to tell associative containers apart from other containers -such as sequence containers. For instance, `std::map` passes the test as it -contains a `mapped_type`, whereas `std::vector` fails the test. - -@sa http://stackoverflow.com/a/7728728/266378 -@since version 1.0.0, overworked in version 2.0.6 -*/ -#define NLOHMANN_JSON_HAS_HELPER(type) \ - template struct has_##type { \ - private: \ - template \ - static int detect(U &&); \ - static void detect(...); \ - public: \ - static constexpr bool value = \ - std::is_integral()))>::value; \ - } - -#endif - -/*** End of inlined file: macro_scope.hpp ***/ namespace nlohmann { @@ -572,6 +391,7 @@ struct is_compatible_integer_type RealIntegerType, CompatibleNumberIntegerType > ::value; }; + // trait checking if JSONSerializer::from_json(json const&, udt&) exists template struct has_from_json @@ -635,10 +455,7 @@ constexpr T static_const::value; #endif -/*** End of inlined file: meta.hpp ***/ - - -/*** Start of inlined file: exceptions.hpp ***/ +// #include "detail/exceptions.hpp" #ifndef NLOHMANN_JSON_DETAIL_EXCEPTIONS_HPP #define NLOHMANN_JSON_DETAIL_EXCEPTIONS_HPP @@ -971,10 +788,7 @@ class other_error : public exception #endif -/*** End of inlined file: exceptions.hpp ***/ - - -/*** Start of inlined file: value_t.hpp ***/ +// #include "detail/value_t.hpp" #ifndef NLOHMANN_JSON_DETAIL_VALUE_T_HPP #define NLOHMANN_JSON_DETAIL_VALUE_T_HPP @@ -1055,10 +869,7 @@ inline bool operator<(const value_t lhs, const value_t rhs) noexcept #endif -/*** End of inlined file: value_t.hpp ***/ - - -/*** Start of inlined file: from_json.hpp ***/ +// #include "detail/conversions/from_json.hpp" #ifndef NLOHMANN_JSON_DETAIL_CONVERSIONS_FROM_JSON_HPP #define NLOHMANN_JSON_DETAIL_CONVERSIONS_FROM_JSON_HPP @@ -1073,663 +884,14 @@ inline bool operator<(const value_t lhs, const value_t rhs) noexcept #include // pair, declval #include // valarray +// #include "detail/exceptions.hpp" -/*** Start of inlined file: exceptions.hpp ***/ -#ifndef NLOHMANN_JSON_DETAIL_EXCEPTIONS_HPP -#define NLOHMANN_JSON_DETAIL_EXCEPTIONS_HPP +// #include "detail/macro_scope.hpp" -#include // exception -#include // runtime_error -#include // to_string +// #include "detail/meta.hpp" -namespace nlohmann -{ -namespace detail -{ -//////////////// -// exceptions // -//////////////// +// #include "detail/value_t.hpp" -/*! -@brief general exception of the @ref basic_json class - -This class is an extension of `std::exception` objects with a member @a id for -exception ids. It is used as the base class for all exceptions thrown by the -@ref basic_json class. This class can hence be used as "wildcard" to catch -exceptions. - -Subclasses: -- @ref parse_error for exceptions indicating a parse error -- @ref invalid_iterator for exceptions indicating errors with iterators -- @ref type_error for exceptions indicating executing a member function with - a wrong type -- @ref out_of_range for exceptions indicating access out of the defined range -- @ref other_error for exceptions indicating other library errors - -@internal -@note To have nothrow-copy-constructible exceptions, we internally use - `std::runtime_error` which can cope with arbitrary-length error messages. - Intermediate strings are built with static functions and then passed to - the actual constructor. -@endinternal - -@liveexample{The following code shows how arbitrary library exceptions can be -caught.,exception} - -@since version 3.0.0 -*/ -class exception : public std::exception -{ - public: - /// returns the explanatory string - const char* what() const noexcept override - { - return m.what(); - } - - /// the id of the exception - const int id; - - protected: - exception(int id_, const char* what_arg) : id(id_), m(what_arg) {} - - static std::string name(const std::string& ename, int id_) - { - return "[json.exception." + ename + "." + std::to_string(id_) + "] "; - } - - private: - /// an exception object as storage for error messages - std::runtime_error m; -}; - -/*! -@brief exception indicating a parse error - -This exception is thrown by the library when a parse error occurs. Parse errors -can occur during the deserialization of JSON text, CBOR, MessagePack, as well -as when using JSON Patch. - -Member @a byte holds the byte index of the last read character in the input -file. - -Exceptions have ids 1xx. - -name / id | example message | description ------------------------------- | --------------- | ------------------------- -json.exception.parse_error.101 | parse error at 2: unexpected end of input; expected string literal | This error indicates a syntax error while deserializing a JSON text. The error message describes that an unexpected token (character) was encountered, and the member @a byte indicates the error position. -json.exception.parse_error.102 | parse error at 14: missing or wrong low surrogate | JSON uses the `\uxxxx` format to describe Unicode characters. Code points above above 0xFFFF are split into two `\uxxxx` entries ("surrogate pairs"). This error indicates that the surrogate pair is incomplete or contains an invalid code point. -json.exception.parse_error.103 | parse error: code points above 0x10FFFF are invalid | Unicode supports code points up to 0x10FFFF. Code points above 0x10FFFF are invalid. -json.exception.parse_error.104 | parse error: JSON patch must be an array of objects | [RFC 6902](https://tools.ietf.org/html/rfc6902) requires a JSON Patch document to be a JSON document that represents an array of objects. -json.exception.parse_error.105 | parse error: operation must have string member 'op' | An operation of a JSON Patch document must contain exactly one "op" member, whose value indicates the operation to perform. Its value must be one of "add", "remove", "replace", "move", "copy", or "test"; other values are errors. -json.exception.parse_error.106 | parse error: array index '01' must not begin with '0' | An array index in a JSON Pointer ([RFC 6901](https://tools.ietf.org/html/rfc6901)) may be `0` or any number without a leading `0`. -json.exception.parse_error.107 | parse error: JSON pointer must be empty or begin with '/' - was: 'foo' | A JSON Pointer must be a Unicode string containing a sequence of zero or more reference tokens, each prefixed by a `/` character. -json.exception.parse_error.108 | parse error: escape character '~' must be followed with '0' or '1' | In a JSON Pointer, only `~0` and `~1` are valid escape sequences. -json.exception.parse_error.109 | parse error: array index 'one' is not a number | A JSON Pointer array index must be a number. -json.exception.parse_error.110 | parse error at 1: cannot read 2 bytes from vector | When parsing CBOR or MessagePack, the byte vector ends before the complete value has been read. -json.exception.parse_error.112 | parse error at 1: error reading CBOR; last byte: 0xF8 | Not all types of CBOR or MessagePack are supported. This exception occurs if an unsupported byte was read. -json.exception.parse_error.113 | parse error at 2: expected a CBOR string; last byte: 0x98 | While parsing a map key, a value that is not a string has been read. - -@note For an input with n bytes, 1 is the index of the first character and n+1 - is the index of the terminating null byte or the end of file. This also - holds true when reading a byte vector (CBOR or MessagePack). - -@liveexample{The following code shows how a `parse_error` exception can be -caught.,parse_error} - -@sa @ref exception for the base class of the library exceptions -@sa @ref invalid_iterator for exceptions indicating errors with iterators -@sa @ref type_error for exceptions indicating executing a member function with - a wrong type -@sa @ref out_of_range for exceptions indicating access out of the defined range -@sa @ref other_error for exceptions indicating other library errors - -@since version 3.0.0 -*/ -class parse_error : public exception -{ - public: - /*! - @brief create a parse error exception - @param[in] id_ the id of the exception - @param[in] byte_ the byte index where the error occurred (or 0 if the - position cannot be determined) - @param[in] what_arg the explanatory string - @return parse_error object - */ - static parse_error create(int id_, std::size_t byte_, const std::string& what_arg) - { - std::string w = exception::name("parse_error", id_) + "parse error" + - (byte_ != 0 ? (" at " + std::to_string(byte_)) : "") + - ": " + what_arg; - return parse_error(id_, byte_, w.c_str()); - } - - /*! - @brief byte index of the parse error - - The byte index of the last read character in the input file. - - @note For an input with n bytes, 1 is the index of the first character and - n+1 is the index of the terminating null byte or the end of file. - This also holds true when reading a byte vector (CBOR or MessagePack). - */ - const std::size_t byte; - - private: - parse_error(int id_, std::size_t byte_, const char* what_arg) - : exception(id_, what_arg), byte(byte_) {} -}; - -/*! -@brief exception indicating errors with iterators - -This exception is thrown if iterators passed to a library function do not match -the expected semantics. - -Exceptions have ids 2xx. - -name / id | example message | description ------------------------------------ | --------------- | ------------------------- -json.exception.invalid_iterator.201 | iterators are not compatible | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. -json.exception.invalid_iterator.202 | iterator does not fit current value | In an erase or insert function, the passed iterator @a pos does not belong to the JSON value for which the function was called. It hence does not define a valid position for the deletion/insertion. -json.exception.invalid_iterator.203 | iterators do not fit current value | Either iterator passed to function @ref erase(IteratorType first, IteratorType last) does not belong to the JSON value from which values shall be erased. It hence does not define a valid range to delete values from. -json.exception.invalid_iterator.204 | iterators out of range | When an iterator range for a primitive type (number, boolean, or string) is passed to a constructor or an erase function, this range has to be exactly (@ref begin(), @ref end()), because this is the only way the single stored value is expressed. All other ranges are invalid. -json.exception.invalid_iterator.205 | iterator out of range | When an iterator for a primitive type (number, boolean, or string) is passed to an erase function, the iterator has to be the @ref begin() iterator, because it is the only way to address the stored value. All other iterators are invalid. -json.exception.invalid_iterator.206 | cannot construct with iterators from null | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) belong to a JSON null value and hence to not define a valid range. -json.exception.invalid_iterator.207 | cannot use key() for non-object iterators | The key() member function can only be used on iterators belonging to a JSON object, because other types do not have a concept of a key. -json.exception.invalid_iterator.208 | cannot use operator[] for object iterators | The operator[] to specify a concrete offset cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. -json.exception.invalid_iterator.209 | cannot use offsets with object iterators | The offset operators (+, -, +=, -=) cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. -json.exception.invalid_iterator.210 | iterators do not fit | The iterator range passed to the insert function are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. -json.exception.invalid_iterator.211 | passed iterators may not belong to container | The iterator range passed to the insert function must not be a subrange of the container to insert to. -json.exception.invalid_iterator.212 | cannot compare iterators of different containers | When two iterators are compared, they must belong to the same container. -json.exception.invalid_iterator.213 | cannot compare order of object iterators | The order of object iterators cannot be compared, because JSON objects are unordered. -json.exception.invalid_iterator.214 | cannot get value | Cannot get value for iterator: Either the iterator belongs to a null value or it is an iterator to a primitive type (number, boolean, or string), but the iterator is different to @ref begin(). - -@liveexample{The following code shows how an `invalid_iterator` exception can be -caught.,invalid_iterator} - -@sa @ref exception for the base class of the library exceptions -@sa @ref parse_error for exceptions indicating a parse error -@sa @ref type_error for exceptions indicating executing a member function with - a wrong type -@sa @ref out_of_range for exceptions indicating access out of the defined range -@sa @ref other_error for exceptions indicating other library errors - -@since version 3.0.0 -*/ -class invalid_iterator : public exception -{ - public: - static invalid_iterator create(int id_, const std::string& what_arg) - { - std::string w = exception::name("invalid_iterator", id_) + what_arg; - return invalid_iterator(id_, w.c_str()); - } - - private: - invalid_iterator(int id_, const char* what_arg) - : exception(id_, what_arg) {} -}; - -/*! -@brief exception indicating executing a member function with a wrong type - -This exception is thrown in case of a type error; that is, a library function is -executed on a JSON value whose type does not match the expected semantics. - -Exceptions have ids 3xx. - -name / id | example message | description ------------------------------ | --------------- | ------------------------- -json.exception.type_error.301 | cannot create object from initializer list | To create an object from an initializer list, the initializer list must consist only of a list of pairs whose first element is a string. When this constraint is violated, an array is created instead. -json.exception.type_error.302 | type must be object, but is array | During implicit or explicit value conversion, the JSON type must be compatible to the target type. For instance, a JSON string can only be converted into string types, but not into numbers or boolean types. -json.exception.type_error.303 | incompatible ReferenceType for get_ref, actual type is object | To retrieve a reference to a value stored in a @ref basic_json object with @ref get_ref, the type of the reference must match the value type. For instance, for a JSON array, the @a ReferenceType must be @ref array_t&. -json.exception.type_error.304 | cannot use at() with string | The @ref at() member functions can only be executed for certain JSON types. -json.exception.type_error.305 | cannot use operator[] with string | The @ref operator[] member functions can only be executed for certain JSON types. -json.exception.type_error.306 | cannot use value() with string | The @ref value() member functions can only be executed for certain JSON types. -json.exception.type_error.307 | cannot use erase() with string | The @ref erase() member functions can only be executed for certain JSON types. -json.exception.type_error.308 | cannot use push_back() with string | The @ref push_back() and @ref operator+= member functions can only be executed for certain JSON types. -json.exception.type_error.309 | cannot use insert() with | The @ref insert() member functions can only be executed for certain JSON types. -json.exception.type_error.310 | cannot use swap() with number | The @ref swap() member functions can only be executed for certain JSON types. -json.exception.type_error.311 | cannot use emplace_back() with string | The @ref emplace_back() member function can only be executed for certain JSON types. -json.exception.type_error.312 | cannot use update() with string | The @ref update() member functions can only be executed for certain JSON types. -json.exception.type_error.313 | invalid value to unflatten | The @ref unflatten function converts an object whose keys are JSON Pointers back into an arbitrary nested JSON value. The JSON Pointers must not overlap, because then the resulting value would not be well defined. -json.exception.type_error.314 | only objects can be unflattened | The @ref unflatten function only works for an object whose keys are JSON Pointers. -json.exception.type_error.315 | values in object must be primitive | The @ref unflatten function only works for an object whose keys are JSON Pointers and whose values are primitive. -json.exception.type_error.316 | invalid UTF-8 byte at index 10: 0x7E | The @ref dump function only works with UTF-8 encoded strings; that is, if you assign a `std::string` to a JSON value, make sure it is UTF-8 encoded. | - -@liveexample{The following code shows how a `type_error` exception can be -caught.,type_error} - -@sa @ref exception for the base class of the library exceptions -@sa @ref parse_error for exceptions indicating a parse error -@sa @ref invalid_iterator for exceptions indicating errors with iterators -@sa @ref out_of_range for exceptions indicating access out of the defined range -@sa @ref other_error for exceptions indicating other library errors - -@since version 3.0.0 -*/ -class type_error : public exception -{ - public: - static type_error create(int id_, const std::string& what_arg) - { - std::string w = exception::name("type_error", id_) + what_arg; - return type_error(id_, w.c_str()); - } - - private: - type_error(int id_, const char* what_arg) : exception(id_, what_arg) {} -}; - -/*! -@brief exception indicating access out of the defined range - -This exception is thrown in case a library function is called on an input -parameter that exceeds the expected range, for instance in case of array -indices or nonexisting object keys. - -Exceptions have ids 4xx. - -name / id | example message | description -------------------------------- | --------------- | ------------------------- -json.exception.out_of_range.401 | array index 3 is out of range | The provided array index @a i is larger than @a size-1. -json.exception.out_of_range.402 | array index '-' (3) is out of range | The special array index `-` in a JSON Pointer never describes a valid element of the array, but the index past the end. That is, it can only be used to add elements at this position, but not to read it. -json.exception.out_of_range.403 | key 'foo' not found | The provided key was not found in the JSON object. -json.exception.out_of_range.404 | unresolved reference token 'foo' | A reference token in a JSON Pointer could not be resolved. -json.exception.out_of_range.405 | JSON pointer has no parent | The JSON Patch operations 'remove' and 'add' can not be applied to the root element of the JSON value. -json.exception.out_of_range.406 | number overflow parsing '10E1000' | A parsed number could not be stored as without changing it to NaN or INF. - -@liveexample{The following code shows how an `out_of_range` exception can be -caught.,out_of_range} - -@sa @ref exception for the base class of the library exceptions -@sa @ref parse_error for exceptions indicating a parse error -@sa @ref invalid_iterator for exceptions indicating errors with iterators -@sa @ref type_error for exceptions indicating executing a member function with - a wrong type -@sa @ref other_error for exceptions indicating other library errors - -@since version 3.0.0 -*/ -class out_of_range : public exception -{ - public: - static out_of_range create(int id_, const std::string& what_arg) - { - std::string w = exception::name("out_of_range", id_) + what_arg; - return out_of_range(id_, w.c_str()); - } - - private: - out_of_range(int id_, const char* what_arg) : exception(id_, what_arg) {} -}; - -/*! -@brief exception indicating other library errors - -This exception is thrown in case of errors that cannot be classified with the -other exception types. - -Exceptions have ids 5xx. - -name / id | example message | description ------------------------------- | --------------- | ------------------------- -json.exception.other_error.501 | unsuccessful: {"op":"test","path":"/baz", "value":"bar"} | A JSON Patch operation 'test' failed. The unsuccessful operation is also printed. - -@sa @ref exception for the base class of the library exceptions -@sa @ref parse_error for exceptions indicating a parse error -@sa @ref invalid_iterator for exceptions indicating errors with iterators -@sa @ref type_error for exceptions indicating executing a member function with - a wrong type -@sa @ref out_of_range for exceptions indicating access out of the defined range - -@liveexample{The following code shows how an `other_error` exception can be -caught.,other_error} - -@since version 3.0.0 -*/ -class other_error : public exception -{ - public: - static other_error create(int id_, const std::string& what_arg) - { - std::string w = exception::name("other_error", id_) + what_arg; - return other_error(id_, w.c_str()); - } - - private: - other_error(int id_, const char* what_arg) : exception(id_, what_arg) {} -}; -} -} - -#endif - -/*** End of inlined file: exceptions.hpp ***/ - - -/*** Start of inlined file: meta.hpp ***/ -#ifndef NLOHMANN_JSON_DETAIL_META_HPP -#define NLOHMANN_JSON_DETAIL_META_HPP - -#include // not -#include // size_t -#include // numeric_limits -#include // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type -#include // declval - -namespace nlohmann -{ -/*! -@brief detail namespace with internal helper functions - -This namespace collects functions that should not be exposed, -implementations of some @ref basic_json methods, and meta-programming helpers. - -@since version 2.1.0 -*/ -namespace detail -{ -///////////// -// helpers // -///////////// - -template struct is_basic_json : std::false_type {}; - -NLOHMANN_BASIC_JSON_TPL_DECLARATION -struct is_basic_json : std::true_type {}; - -// alias templates to reduce boilerplate -template -using enable_if_t = typename std::enable_if::type; - -template -using uncvref_t = typename std::remove_cv::type>::type; - -// implementation of C++14 index_sequence and affiliates -// source: https://stackoverflow.com/a/32223343 -template -struct index_sequence -{ - using type = index_sequence; - using value_type = std::size_t; - static constexpr std::size_t size() noexcept - { - return sizeof...(Ints); - } -}; - -template -struct merge_and_renumber; - -template -struct merge_and_renumber, index_sequence> - : index_sequence < I1..., (sizeof...(I1) + I2)... > {}; - -template -struct make_index_sequence - : merge_and_renumber < typename make_index_sequence < N / 2 >::type, - typename make_index_sequence < N - N / 2 >::type > {}; - -template<> struct make_index_sequence<0> : index_sequence<> {}; -template<> struct make_index_sequence<1> : index_sequence<0> {}; - -template -using index_sequence_for = make_index_sequence; - -/* -Implementation of two C++17 constructs: conjunction, negation. This is needed -to avoid evaluating all the traits in a condition - -For example: not std::is_same::value and has_value_type::value -will not compile when T = void (on MSVC at least). Whereas -conjunction>, has_value_type>::value will -stop evaluating if negation<...>::value == false - -Please note that those constructs must be used with caution, since symbols can -become very long quickly (which can slow down compilation and cause MSVC -internal compiler errors). Only use it when you have to (see example ahead). -*/ -template struct conjunction : std::true_type {}; -template struct conjunction : B1 {}; -template -struct conjunction : std::conditional, B1>::type {}; - -template struct negation : std::integral_constant {}; - -// dispatch utility (taken from ranges-v3) -template struct priority_tag : priority_tag < N - 1 > {}; -template<> struct priority_tag<0> {}; - -//////////////////////// -// has_/is_ functions // -//////////////////////// - -NLOHMANN_JSON_HAS_HELPER(mapped_type); -NLOHMANN_JSON_HAS_HELPER(key_type); -NLOHMANN_JSON_HAS_HELPER(value_type); -NLOHMANN_JSON_HAS_HELPER(iterator); - -template -struct is_compatible_object_type_impl : std::false_type {}; - -template -struct is_compatible_object_type_impl -{ - static constexpr auto value = - std::is_constructible::value and - std::is_constructible::value; -}; - -template -struct is_compatible_object_type -{ - static auto constexpr value = is_compatible_object_type_impl < - conjunction>, - has_mapped_type, - has_key_type>::value, - typename BasicJsonType::object_t, CompatibleObjectType >::value; -}; - -template -struct is_basic_json_nested_type -{ - static auto constexpr value = std::is_same::value or - std::is_same::value or - std::is_same::value or - std::is_same::value; -}; - -template -struct is_compatible_array_type -{ - static auto constexpr value = - conjunction>, - negation>, - negation>, - negation>, - has_value_type, - has_iterator>::value; -}; - -template -struct is_compatible_integer_type_impl : std::false_type {}; - -template -struct is_compatible_integer_type_impl -{ - // is there an assert somewhere on overflows? - using RealLimits = std::numeric_limits; - using CompatibleLimits = std::numeric_limits; - - static constexpr auto value = - std::is_constructible::value and - CompatibleLimits::is_integer and - RealLimits::is_signed == CompatibleLimits::is_signed; -}; - -template -struct is_compatible_integer_type -{ - static constexpr auto value = - is_compatible_integer_type_impl < - std::is_integral::value and - not std::is_same::value, - RealIntegerType, CompatibleNumberIntegerType > ::value; -}; - -// trait checking if JSONSerializer::from_json(json const&, udt&) exists -template -struct has_from_json -{ - private: - // also check the return type of from_json - template::from_json( - std::declval(), std::declval()))>::value>> - static int detect(U&&); - static void detect(...); - - public: - static constexpr bool value = std::is_integral>()))>::value; -}; - -// This trait checks if JSONSerializer::from_json(json const&) exists -// this overload is used for non-default-constructible user-defined-types -template -struct has_non_default_from_json -{ - private: - template < - typename U, - typename = enable_if_t::from_json(std::declval()))>::value >> - static int detect(U&&); - static void detect(...); - - public: - static constexpr bool value = std::is_integral>()))>::value; -}; - -// This trait checks if BasicJsonType::json_serializer::to_json exists -template -struct has_to_json -{ - private: - template::to_json( - std::declval(), std::declval()))> - static int detect(U&&); - static void detect(...); - - public: - static constexpr bool value = std::is_integral>()))>::value; -}; - -// taken from ranges-v3 -template -struct static_const -{ - static constexpr T value{}; -}; - -template -constexpr T static_const::value; -} -} - -#endif - -/*** End of inlined file: meta.hpp ***/ - - -/*** Start of inlined file: value_t.hpp ***/ -#ifndef NLOHMANN_JSON_DETAIL_VALUE_T_HPP -#define NLOHMANN_JSON_DETAIL_VALUE_T_HPP - -#include // array -#include // and -#include // size_t -#include // uint8_t - -namespace nlohmann -{ -namespace detail -{ -/////////////////////////// -// JSON type enumeration // -/////////////////////////// - -/*! -@brief the JSON type enumeration - -This enumeration collects the different JSON types. It is internally used to -distinguish the stored values, and the functions @ref basic_json::is_null(), -@ref basic_json::is_object(), @ref basic_json::is_array(), -@ref basic_json::is_string(), @ref basic_json::is_boolean(), -@ref basic_json::is_number() (with @ref basic_json::is_number_integer(), -@ref basic_json::is_number_unsigned(), and @ref basic_json::is_number_float()), -@ref basic_json::is_discarded(), @ref basic_json::is_primitive(), and -@ref basic_json::is_structured() rely on it. - -@note There are three enumeration entries (number_integer, number_unsigned, and -number_float), because the library distinguishes these three types for numbers: -@ref basic_json::number_unsigned_t is used for unsigned integers, -@ref basic_json::number_integer_t is used for signed integers, and -@ref basic_json::number_float_t is used for floating-point numbers or to -approximate integers which do not fit in the limits of their respective type. - -@sa @ref basic_json::basic_json(const value_t value_type) -- create a JSON -value with the default value for a given type - -@since version 1.0.0 -*/ -enum class value_t : std::uint8_t -{ - null, ///< null value - object, ///< object (unordered set of name/value pairs) - array, ///< array (ordered collection of values) - string, ///< string value - boolean, ///< boolean value - number_integer, ///< number value (signed integer) - number_unsigned, ///< number value (unsigned integer) - number_float, ///< number value (floating-point) - discarded ///< discarded by the the parser callback function -}; - -/*! -@brief comparison operator for JSON types - -Returns an ordering that is similar to Python: -- order: null < boolean < number < object < array < string -- furthermore, each type is not smaller than itself -- discarded values are not comparable - -@since version 1.0.0 -*/ -inline bool operator<(const value_t lhs, const value_t rhs) noexcept -{ - static constexpr std::array order = {{ - 0 /* null */, 3 /* object */, 4 /* array */, 5 /* string */, - 1 /* boolean */, 2 /* integer */, 2 /* unsigned */, 2 /* float */ - } - }; - - const auto l_index = static_cast(lhs); - const auto r_index = static_cast(rhs); - return l_index < order.size() and r_index < order.size() and order[l_index] < order[r_index]; -} -} -} - -#endif - -/*** End of inlined file: value_t.hpp ***/ namespace nlohmann { @@ -2031,10 +1193,7 @@ constexpr const auto& from_json = detail::static_const::va #endif -/*** End of inlined file: from_json.hpp ***/ - - -/*** Start of inlined file: to_json.hpp ***/ +// #include "detail/conversions/to_json.hpp" #ifndef NLOHMANN_JSON_DETAIL_CONVERSIONS_TO_JSON_HPP #define NLOHMANN_JSON_DETAIL_CONVERSIONS_TO_JSON_HPP @@ -2046,6 +1205,11 @@ constexpr const auto& from_json = detail::static_const::va #include // valarray #include // vector +// #include "detail/meta.hpp" + +// #include "detail/value_t.hpp" + + namespace nlohmann { namespace detail @@ -2374,10 +1538,7 @@ constexpr const auto& to_json = detail::static_const::value; #endif -/*** End of inlined file: to_json.hpp ***/ - - -/*** Start of inlined file: input_adapters.hpp ***/ +// #include "detail/parsing/input_adapters.hpp" #ifndef NLOHMANN_JSON_DETAIL_PARSING_INPUT_ADAPTERS_HPP #define NLOHMANN_JSON_DETAIL_PARSING_INPUT_ADAPTERS_HPP @@ -2395,6 +1556,9 @@ constexpr const auto& to_json = detail::static_const::value; #include // enable_if, is_base_of, is_pointer, is_integral, remove_pointer #include // pair, declval +// #include "detail/macro_scope.hpp" + + namespace nlohmann { namespace detail @@ -2642,10 +1806,7 @@ class input_adapter #endif -/*** End of inlined file: input_adapters.hpp ***/ - - -/*** Start of inlined file: lexer.hpp ***/ +// #include "detail/parsing/lexer.hpp" #ifndef NLOHMANN_JSON_DETAIL_PARSING_LEXER_HPP #define NLOHMANN_JSON_DETAIL_PARSING_LEXER_HPP @@ -2659,273 +1820,10 @@ class input_adapter #include // char_traits, string #include // vector +// #include "detail/macro_scope.hpp" -/*** Start of inlined file: input_adapters.hpp ***/ -#ifndef NLOHMANN_JSON_DETAIL_PARSING_INPUT_ADAPTERS_HPP -#define NLOHMANN_JSON_DETAIL_PARSING_INPUT_ADAPTERS_HPP +// #include "detail/parsing/input_adapters.hpp" -#include // min -#include // array -#include // assert -#include // size_t -#include // strlen -#include // streamsize, streamoff, streampos -#include // istream -#include // begin, end, iterator_traits, random_access_iterator_tag, distance, next -#include // shared_ptr, make_shared, addressof -#include // accumulate -#include // string, char_traits -#include // enable_if, is_base_of, is_pointer, is_integral, remove_pointer -#include // pair, declval - -namespace nlohmann -{ -namespace detail -{ -//////////////////// -// input adapters // -//////////////////// - -/*! -@brief abstract input adapter interface - -Produces a stream of std::char_traits::int_type characters from a -std::istream, a buffer, or some other input type. Accepts the return of exactly -one non-EOF character for future input. The int_type characters returned -consist of all valid char values as positive values (typically unsigned char), -plus an EOF value outside that range, specified by the value of the function -std::char_traits::eof(). This value is typically -1, but could be any -arbitrary value which is not a valid char value. -*/ -struct input_adapter_protocol -{ - /// get a character [0,255] or std::char_traits::eof(). - virtual std::char_traits::int_type get_character() = 0; - /// restore the last non-eof() character to input - virtual void unget_character() = 0; - virtual ~input_adapter_protocol() = default; -}; - -/// a type to simplify interfaces -using input_adapter_t = std::shared_ptr; - -/*! -Input adapter for a (caching) istream. Ignores a UFT Byte Order Mark at -beginning of input. Does not support changing the underlying std::streambuf -in mid-input. Maintains underlying std::istream and std::streambuf to support -subsequent use of standard std::istream operations to process any input -characters following those used in parsing the JSON input. Clears the -std::istream flags; any input errors (e.g., EOF) will be detected by the first -subsequent call for input from the std::istream. -*/ -class input_stream_adapter : public input_adapter_protocol -{ - public: - ~input_stream_adapter() override - { - // clear stream flags; we use underlying streambuf I/O, do not - // maintain ifstream flags - is.clear(); - } - - explicit input_stream_adapter(std::istream& i) - : is(i), sb(*i.rdbuf()) - { - // skip byte order mark - std::char_traits::int_type c; - if ((c = get_character()) == 0xEF) - { - if ((c = get_character()) == 0xBB) - { - if ((c = get_character()) == 0xBF) - { - return; // Ignore BOM - } - else if (c != std::char_traits::eof()) - { - is.unget(); - } - is.putback('\xBB'); - } - else if (c != std::char_traits::eof()) - { - is.unget(); - } - is.putback('\xEF'); - } - else if (c != std::char_traits::eof()) - { - is.unget(); // no byte order mark; process as usual - } - } - - // delete because of pointer members - input_stream_adapter(const input_stream_adapter&) = delete; - input_stream_adapter& operator=(input_stream_adapter&) = delete; - - // std::istream/std::streambuf use std::char_traits::to_int_type, to - // ensure that std::char_traits::eof() and the character 0xFF do not - // end up as the same value, eg. 0xFFFFFFFF. - std::char_traits::int_type get_character() override - { - return sb.sbumpc(); - } - - void unget_character() override - { - sb.sungetc(); // is.unget() avoided for performance - } - - private: - /// the associated input stream - std::istream& is; - std::streambuf& sb; -}; - -/// input adapter for buffer input -class input_buffer_adapter : public input_adapter_protocol -{ - public: - input_buffer_adapter(const char* b, const std::size_t l) - : cursor(b), limit(b + l), start(b) - { - // skip byte order mark - if (l >= 3 and b[0] == '\xEF' and b[1] == '\xBB' and b[2] == '\xBF') - { - cursor += 3; - } - } - - // delete because of pointer members - input_buffer_adapter(const input_buffer_adapter&) = delete; - input_buffer_adapter& operator=(input_buffer_adapter&) = delete; - - std::char_traits::int_type get_character() noexcept override - { - if (JSON_LIKELY(cursor < limit)) - { - return std::char_traits::to_int_type(*(cursor++)); - } - - return std::char_traits::eof(); - } - - void unget_character() noexcept override - { - if (JSON_LIKELY(cursor > start)) - { - --cursor; - } - } - - private: - /// pointer to the current character - const char* cursor; - /// pointer past the last character - const char* limit; - /// pointer to the first character - const char* start; -}; - -class input_adapter -{ - public: - // native support - - /// input adapter for input stream - input_adapter(std::istream& i) - : ia(std::make_shared(i)) {} - - /// input adapter for input stream - input_adapter(std::istream&& i) - : ia(std::make_shared(i)) {} - - /// input adapter for buffer - template::value and - std::is_integral::type>::value and - sizeof(typename std::remove_pointer::type) == 1, - int>::type = 0> - input_adapter(CharT b, std::size_t l) - : ia(std::make_shared(reinterpret_cast(b), l)) {} - - // derived support - - /// input adapter for string literal - template::value and - std::is_integral::type>::value and - sizeof(typename std::remove_pointer::type) == 1, - int>::type = 0> - input_adapter(CharT b) - : input_adapter(reinterpret_cast(b), - std::strlen(reinterpret_cast(b))) {} - - /// input adapter for iterator range with contiguous storage - template::iterator_category, std::random_access_iterator_tag>::value, - int>::type = 0> - input_adapter(IteratorType first, IteratorType last) - { - // assertion to check that the iterator range is indeed contiguous, - // see http://stackoverflow.com/a/35008842/266378 for more discussion - assert(std::accumulate( - first, last, std::pair(true, 0), - [&first](std::pair res, decltype(*first) val) - { - res.first &= (val == *(std::next(std::addressof(*first), res.second++))); - return res; - }).first); - - // assertion to check that each element is 1 byte long - static_assert( - sizeof(typename std::iterator_traits::value_type) == 1, - "each element in the iterator range must have the size of 1 byte"); - - const auto len = static_cast(std::distance(first, last)); - if (JSON_LIKELY(len > 0)) - { - // there is at least one element: use the address of first - ia = std::make_shared(reinterpret_cast(&(*first)), len); - } - else - { - // the address of first cannot be used: use nullptr - ia = std::make_shared(nullptr, len); - } - } - - /// input adapter for array - template - input_adapter(T (&array)[N]) - : input_adapter(std::begin(array), std::end(array)) {} - - /// input adapter for contiguous container - template::value and - std::is_base_of()))>::iterator_category>::value, - int>::type = 0> - input_adapter(const ContiguousContainer& c) - : input_adapter(std::begin(c), std::end(c)) {} - - operator input_adapter_t() - { - return ia; - } - - private: - /// the actual adapter - input_adapter_t ia = nullptr; -}; -} -} - -#endif - -/*** End of inlined file: input_adapters.hpp ***/ namespace nlohmann { @@ -4191,10 +3089,7 @@ scan_number_done: #endif -/*** End of inlined file: lexer.hpp ***/ - - -/*** Start of inlined file: parser.hpp ***/ +// #include "detail/parsing/parser.hpp" #ifndef NLOHMANN_JSON_DETAIL_PARSING_PARSER_HPP #define NLOHMANN_JSON_DETAIL_PARSING_PARSER_HPP @@ -4205,1286 +3100,16 @@ scan_number_done: #include // string #include // move +// #include "detail/exceptions.hpp" -/*** Start of inlined file: lexer.hpp ***/ -#ifndef NLOHMANN_JSON_DETAIL_PARSING_LEXER_HPP -#define NLOHMANN_JSON_DETAIL_PARSING_LEXER_HPP +// #include "detail/macro_scope.hpp" -#include // localeconv -#include // size_t -#include // strtof, strtod, strtold, strtoll, strtoull -#include // initializer_list -#include // hex, uppercase -#include // setw, setfill -#include // stringstream -#include // char_traits, string -#include // vector +// #include "detail/parsing/input_adapters.hpp" -namespace nlohmann -{ -namespace detail -{ -/////////// -// lexer // -/////////// +// #include "detail/parsing/lexer.hpp" -/*! -@brief lexical analysis +// #include "detail/value_t.hpp" -This class organizes the lexical analysis during JSON deserialization. -*/ -template -class lexer -{ - using number_integer_t = typename BasicJsonType::number_integer_t; - using number_unsigned_t = typename BasicJsonType::number_unsigned_t; - using number_float_t = typename BasicJsonType::number_float_t; - - public: - /// token types for the parser - enum class token_type - { - uninitialized, ///< indicating the scanner is uninitialized - literal_true, ///< the `true` literal - literal_false, ///< the `false` literal - literal_null, ///< the `null` literal - value_string, ///< a string -- use get_string() for actual value - value_unsigned, ///< an unsigned integer -- use get_number_unsigned() for actual value - value_integer, ///< a signed integer -- use get_number_integer() for actual value - value_float, ///< an floating point number -- use get_number_float() for actual value - begin_array, ///< the character for array begin `[` - begin_object, ///< the character for object begin `{` - end_array, ///< the character for array end `]` - end_object, ///< the character for object end `}` - name_separator, ///< the name separator `:` - value_separator, ///< the value separator `,` - parse_error, ///< indicating a parse error - end_of_input, ///< indicating the end of the input buffer - literal_or_value ///< a literal or the begin of a value (only for diagnostics) - }; - - /// return name of values of type token_type (only used for errors) - static const char* token_type_name(const token_type t) noexcept - { - switch (t) - { - case token_type::uninitialized: - return ""; - case token_type::literal_true: - return "true literal"; - case token_type::literal_false: - return "false literal"; - case token_type::literal_null: - return "null literal"; - case token_type::value_string: - return "string literal"; - case lexer::token_type::value_unsigned: - case lexer::token_type::value_integer: - case lexer::token_type::value_float: - return "number literal"; - case token_type::begin_array: - return "'['"; - case token_type::begin_object: - return "'{'"; - case token_type::end_array: - return "']'"; - case token_type::end_object: - return "'}'"; - case token_type::name_separator: - return "':'"; - case token_type::value_separator: - return "','"; - case token_type::parse_error: - return ""; - case token_type::end_of_input: - return "end of input"; - case token_type::literal_or_value: - return "'[', '{', or a literal"; - default: // catch non-enum values - return "unknown token"; // LCOV_EXCL_LINE - } - } - - explicit lexer(detail::input_adapter_t adapter) - : ia(std::move(adapter)), decimal_point_char(get_decimal_point()) {} - - // delete because of pointer members - lexer(const lexer&) = delete; - lexer& operator=(lexer&) = delete; - - private: - ///////////////////// - // locales - ///////////////////// - - /// return the locale-dependent decimal point - static char get_decimal_point() noexcept - { - const auto loc = localeconv(); - assert(loc != nullptr); - return (loc->decimal_point == nullptr) ? '.' : *(loc->decimal_point); - } - - ///////////////////// - // scan functions - ///////////////////// - - /*! - @brief get codepoint from 4 hex characters following `\u` - - For input "\u c1 c2 c3 c4" the codepoint is: - (c1 * 0x1000) + (c2 * 0x0100) + (c3 * 0x0010) + c4 - = (c1 << 12) + (c2 << 8) + (c3 << 4) + (c4 << 0) - - Furthermore, the possible characters '0'..'9', 'A'..'F', and 'a'..'f' - must be converted to the integers 0x0..0x9, 0xA..0xF, 0xA..0xF, resp. The - conversion is done by subtracting the offset (0x30, 0x37, and 0x57) - between the ASCII value of the character and the desired integer value. - - @return codepoint (0x0000..0xFFFF) or -1 in case of an error (e.g. EOF or - non-hex character) - */ - int get_codepoint() - { - // this function only makes sense after reading `\u` - assert(current == 'u'); - int codepoint = 0; - - const auto factors = { 12, 8, 4, 0 }; - for (const auto factor : factors) - { - get(); - - if (current >= '0' and current <= '9') - { - codepoint += ((current - 0x30) << factor); - } - else if (current >= 'A' and current <= 'F') - { - codepoint += ((current - 0x37) << factor); - } - else if (current >= 'a' and current <= 'f') - { - codepoint += ((current - 0x57) << factor); - } - else - { - return -1; - } - } - - assert(0x0000 <= codepoint and codepoint <= 0xFFFF); - return codepoint; - } - - /*! - @brief check if the next byte(s) are inside a given range - - Adds the current byte and, for each passed range, reads a new byte and - checks if it is inside the range. If a violation was detected, set up an - error message and return false. Otherwise, return true. - - @param[in] ranges list of integers; interpreted as list of pairs of - inclusive lower and upper bound, respectively - - @pre The passed list @a ranges must have 2, 4, or 6 elements; that is, - 1, 2, or 3 pairs. This precondition is enforced by an assertion. - - @return true if and only if no range violation was detected - */ - bool next_byte_in_range(std::initializer_list ranges) - { - assert(ranges.size() == 2 or ranges.size() == 4 or ranges.size() == 6); - add(current); - - for (auto range = ranges.begin(); range != ranges.end(); ++range) - { - get(); - if (JSON_LIKELY(*range <= current and current <= *(++range))) - { - add(current); - } - else - { - error_message = "invalid string: ill-formed UTF-8 byte"; - return false; - } - } - - return true; - } - - /*! - @brief scan a string literal - - This function scans a string according to Sect. 7 of RFC 7159. While - scanning, bytes are escaped and copied into buffer yytext. Then the function - returns successfully, yytext is *not* null-terminated (as it may contain \0 - bytes), and yytext.size() is the number of bytes in the string. - - @return token_type::value_string if string could be successfully scanned, - token_type::parse_error otherwise - - @note In case of errors, variable error_message contains a textual - description. - */ - token_type scan_string() - { - // reset yytext (ignore opening quote) - reset(); - - // we entered the function by reading an open quote - assert(current == '\"'); - - while (true) - { - // get next character - switch (get()) - { - // end of file while parsing string - case std::char_traits::eof(): - { - error_message = "invalid string: missing closing quote"; - return token_type::parse_error; - } - - // closing quote - case '\"': - { - return token_type::value_string; - } - - // escapes - case '\\': - { - switch (get()) - { - // quotation mark - case '\"': - add('\"'); - break; - // reverse solidus - case '\\': - add('\\'); - break; - // solidus - case '/': - add('/'); - break; - // backspace - case 'b': - add('\b'); - break; - // form feed - case 'f': - add('\f'); - break; - // line feed - case 'n': - add('\n'); - break; - // carriage return - case 'r': - add('\r'); - break; - // tab - case 't': - add('\t'); - break; - - // unicode escapes - case 'u': - { - const int codepoint1 = get_codepoint(); - int codepoint = codepoint1; // start with codepoint1 - - if (JSON_UNLIKELY(codepoint1 == -1)) - { - error_message = "invalid string: '\\u' must be followed by 4 hex digits"; - return token_type::parse_error; - } - - // check if code point is a high surrogate - if (0xD800 <= codepoint1 and codepoint1 <= 0xDBFF) - { - // expect next \uxxxx entry - if (JSON_LIKELY(get() == '\\' and get() == 'u')) - { - const int codepoint2 = get_codepoint(); - - if (JSON_UNLIKELY(codepoint2 == -1)) - { - error_message = "invalid string: '\\u' must be followed by 4 hex digits"; - return token_type::parse_error; - } - - // check if codepoint2 is a low surrogate - if (JSON_LIKELY(0xDC00 <= codepoint2 and codepoint2 <= 0xDFFF)) - { - // overwrite codepoint - codepoint = - // high surrogate occupies the most significant 22 bits - (codepoint1 << 10) - // low surrogate occupies the least significant 15 bits - + codepoint2 - // there is still the 0xD800, 0xDC00 and 0x10000 noise - // in the result so we have to subtract with: - // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00 - - 0x35FDC00; - } - else - { - error_message = "invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF"; - return token_type::parse_error; - } - } - else - { - error_message = "invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF"; - return token_type::parse_error; - } - } - else - { - if (JSON_UNLIKELY(0xDC00 <= codepoint1 and codepoint1 <= 0xDFFF)) - { - error_message = "invalid string: surrogate U+DC00..U+DFFF must follow U+D800..U+DBFF"; - return token_type::parse_error; - } - } - - // result of the above calculation yields a proper codepoint - assert(0x00 <= codepoint and codepoint <= 0x10FFFF); - - // translate codepoint into bytes - if (codepoint < 0x80) - { - // 1-byte characters: 0xxxxxxx (ASCII) - add(codepoint); - } - else if (codepoint <= 0x7FF) - { - // 2-byte characters: 110xxxxx 10xxxxxx - add(0xC0 | (codepoint >> 6)); - add(0x80 | (codepoint & 0x3F)); - } - else if (codepoint <= 0xFFFF) - { - // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx - add(0xE0 | (codepoint >> 12)); - add(0x80 | ((codepoint >> 6) & 0x3F)); - add(0x80 | (codepoint & 0x3F)); - } - else - { - // 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - add(0xF0 | (codepoint >> 18)); - add(0x80 | ((codepoint >> 12) & 0x3F)); - add(0x80 | ((codepoint >> 6) & 0x3F)); - add(0x80 | (codepoint & 0x3F)); - } - - break; - } - - // other characters after escape - default: - error_message = "invalid string: forbidden character after backslash"; - return token_type::parse_error; - } - - break; - } - - // invalid control characters - case 0x00: - case 0x01: - case 0x02: - case 0x03: - case 0x04: - case 0x05: - case 0x06: - case 0x07: - case 0x08: - case 0x09: - case 0x0A: - case 0x0B: - case 0x0C: - case 0x0D: - case 0x0E: - case 0x0F: - case 0x10: - case 0x11: - case 0x12: - case 0x13: - case 0x14: - case 0x15: - case 0x16: - case 0x17: - case 0x18: - case 0x19: - case 0x1A: - case 0x1B: - case 0x1C: - case 0x1D: - case 0x1E: - case 0x1F: - { - error_message = "invalid string: control character must be escaped"; - return token_type::parse_error; - } - - // U+0020..U+007F (except U+0022 (quote) and U+005C (backspace)) - case 0x20: - case 0x21: - case 0x23: - case 0x24: - case 0x25: - case 0x26: - case 0x27: - case 0x28: - case 0x29: - case 0x2A: - case 0x2B: - case 0x2C: - case 0x2D: - case 0x2E: - case 0x2F: - case 0x30: - case 0x31: - case 0x32: - case 0x33: - case 0x34: - case 0x35: - case 0x36: - case 0x37: - case 0x38: - case 0x39: - case 0x3A: - case 0x3B: - case 0x3C: - case 0x3D: - case 0x3E: - case 0x3F: - case 0x40: - case 0x41: - case 0x42: - case 0x43: - case 0x44: - case 0x45: - case 0x46: - case 0x47: - case 0x48: - case 0x49: - case 0x4A: - case 0x4B: - case 0x4C: - case 0x4D: - case 0x4E: - case 0x4F: - case 0x50: - case 0x51: - case 0x52: - case 0x53: - case 0x54: - case 0x55: - case 0x56: - case 0x57: - case 0x58: - case 0x59: - case 0x5A: - case 0x5B: - case 0x5D: - case 0x5E: - case 0x5F: - case 0x60: - case 0x61: - case 0x62: - case 0x63: - case 0x64: - case 0x65: - case 0x66: - case 0x67: - case 0x68: - case 0x69: - case 0x6A: - case 0x6B: - case 0x6C: - case 0x6D: - case 0x6E: - case 0x6F: - case 0x70: - case 0x71: - case 0x72: - case 0x73: - case 0x74: - case 0x75: - case 0x76: - case 0x77: - case 0x78: - case 0x79: - case 0x7A: - case 0x7B: - case 0x7C: - case 0x7D: - case 0x7E: - case 0x7F: - { - add(current); - break; - } - - // U+0080..U+07FF: bytes C2..DF 80..BF - case 0xC2: - case 0xC3: - case 0xC4: - case 0xC5: - case 0xC6: - case 0xC7: - case 0xC8: - case 0xC9: - case 0xCA: - case 0xCB: - case 0xCC: - case 0xCD: - case 0xCE: - case 0xCF: - case 0xD0: - case 0xD1: - case 0xD2: - case 0xD3: - case 0xD4: - case 0xD5: - case 0xD6: - case 0xD7: - case 0xD8: - case 0xD9: - case 0xDA: - case 0xDB: - case 0xDC: - case 0xDD: - case 0xDE: - case 0xDF: - { - if (JSON_UNLIKELY(not next_byte_in_range({0x80, 0xBF}))) - { - return token_type::parse_error; - } - break; - } - - // U+0800..U+0FFF: bytes E0 A0..BF 80..BF - case 0xE0: - { - if (JSON_UNLIKELY(not (next_byte_in_range({0xA0, 0xBF, 0x80, 0xBF})))) - { - return token_type::parse_error; - } - break; - } - - // U+1000..U+CFFF: bytes E1..EC 80..BF 80..BF - // U+E000..U+FFFF: bytes EE..EF 80..BF 80..BF - case 0xE1: - case 0xE2: - case 0xE3: - case 0xE4: - case 0xE5: - case 0xE6: - case 0xE7: - case 0xE8: - case 0xE9: - case 0xEA: - case 0xEB: - case 0xEC: - case 0xEE: - case 0xEF: - { - if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0xBF, 0x80, 0xBF})))) - { - return token_type::parse_error; - } - break; - } - - // U+D000..U+D7FF: bytes ED 80..9F 80..BF - case 0xED: - { - if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0x9F, 0x80, 0xBF})))) - { - return token_type::parse_error; - } - break; - } - - // U+10000..U+3FFFF F0 90..BF 80..BF 80..BF - case 0xF0: - { - if (JSON_UNLIKELY(not (next_byte_in_range({0x90, 0xBF, 0x80, 0xBF, 0x80, 0xBF})))) - { - return token_type::parse_error; - } - break; - } - - // U+40000..U+FFFFF F1..F3 80..BF 80..BF 80..BF - case 0xF1: - case 0xF2: - case 0xF3: - { - if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0xBF, 0x80, 0xBF, 0x80, 0xBF})))) - { - return token_type::parse_error; - } - break; - } - - // U+100000..U+10FFFF F4 80..8F 80..BF 80..BF - case 0xF4: - { - if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0x8F, 0x80, 0xBF, 0x80, 0xBF})))) - { - return token_type::parse_error; - } - break; - } - - // remaining bytes (80..C1 and F5..FF) are ill-formed - default: - { - error_message = "invalid string: ill-formed UTF-8 byte"; - return token_type::parse_error; - } - } - } - } - - static void strtof(float& f, const char* str, char** endptr) noexcept - { - f = std::strtof(str, endptr); - } - - static void strtof(double& f, const char* str, char** endptr) noexcept - { - f = std::strtod(str, endptr); - } - - static void strtof(long double& f, const char* str, char** endptr) noexcept - { - f = std::strtold(str, endptr); - } - - /*! - @brief scan a number literal - - This function scans a string according to Sect. 6 of RFC 7159. - - The function is realized with a deterministic finite state machine derived - from the grammar described in RFC 7159. Starting in state "init", the - input is read and used to determined the next state. Only state "done" - accepts the number. State "error" is a trap state to model errors. In the - table below, "anything" means any character but the ones listed before. - - state | 0 | 1-9 | e E | + | - | . | anything - ---------|----------|----------|----------|---------|---------|----------|----------- - init | zero | any1 | [error] | [error] | minus | [error] | [error] - minus | zero | any1 | [error] | [error] | [error] | [error] | [error] - zero | done | done | exponent | done | done | decimal1 | done - any1 | any1 | any1 | exponent | done | done | decimal1 | done - decimal1 | decimal2 | [error] | [error] | [error] | [error] | [error] | [error] - decimal2 | decimal2 | decimal2 | exponent | done | done | done | done - exponent | any2 | any2 | [error] | sign | sign | [error] | [error] - sign | any2 | any2 | [error] | [error] | [error] | [error] | [error] - any2 | any2 | any2 | done | done | done | done | done - - The state machine is realized with one label per state (prefixed with - "scan_number_") and `goto` statements between them. The state machine - contains cycles, but any cycle can be left when EOF is read. Therefore, - the function is guaranteed to terminate. - - During scanning, the read bytes are stored in yytext. This string is - then converted to a signed integer, an unsigned integer, or a - floating-point number. - - @return token_type::value_unsigned, token_type::value_integer, or - token_type::value_float if number could be successfully scanned, - token_type::parse_error otherwise - - @note The scanner is independent of the current locale. Internally, the - locale's decimal point is used instead of `.` to work with the - locale-dependent converters. - */ - token_type scan_number() - { - // reset yytext to store the number's bytes - reset(); - - // the type of the parsed number; initially set to unsigned; will be - // changed if minus sign, decimal point or exponent is read - token_type number_type = token_type::value_unsigned; - - // state (init): we just found out we need to scan a number - switch (current) - { - case '-': - { - add(current); - goto scan_number_minus; - } - - case '0': - { - add(current); - goto scan_number_zero; - } - - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_any1; - } - - default: - { - // all other characters are rejected outside scan_number() - assert(false); // LCOV_EXCL_LINE - } - } - -scan_number_minus: - // state: we just parsed a leading minus sign - number_type = token_type::value_integer; - switch (get()) - { - case '0': - { - add(current); - goto scan_number_zero; - } - - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_any1; - } - - default: - { - error_message = "invalid number; expected digit after '-'"; - return token_type::parse_error; - } - } - -scan_number_zero: - // state: we just parse a zero (maybe with a leading minus sign) - switch (get()) - { - case '.': - { - add(decimal_point_char); - goto scan_number_decimal1; - } - - case 'e': - case 'E': - { - add(current); - goto scan_number_exponent; - } - - default: - goto scan_number_done; - } - -scan_number_any1: - // state: we just parsed a number 0-9 (maybe with a leading minus sign) - switch (get()) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_any1; - } - - case '.': - { - add(decimal_point_char); - goto scan_number_decimal1; - } - - case 'e': - case 'E': - { - add(current); - goto scan_number_exponent; - } - - default: - goto scan_number_done; - } - -scan_number_decimal1: - // state: we just parsed a decimal point - number_type = token_type::value_float; - switch (get()) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_decimal2; - } - - default: - { - error_message = "invalid number; expected digit after '.'"; - return token_type::parse_error; - } - } - -scan_number_decimal2: - // we just parsed at least one number after a decimal point - switch (get()) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_decimal2; - } - - case 'e': - case 'E': - { - add(current); - goto scan_number_exponent; - } - - default: - goto scan_number_done; - } - -scan_number_exponent: - // we just parsed an exponent - number_type = token_type::value_float; - switch (get()) - { - case '+': - case '-': - { - add(current); - goto scan_number_sign; - } - - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_any2; - } - - default: - { - error_message = - "invalid number; expected '+', '-', or digit after exponent"; - return token_type::parse_error; - } - } - -scan_number_sign: - // we just parsed an exponent sign - switch (get()) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_any2; - } - - default: - { - error_message = "invalid number; expected digit after exponent sign"; - return token_type::parse_error; - } - } - -scan_number_any2: - // we just parsed a number after the exponent or exponent sign - switch (get()) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_any2; - } - - default: - goto scan_number_done; - } - -scan_number_done: - // unget the character after the number (we only read it to know that - // we are done scanning a number) - unget(); - - char* endptr = nullptr; - errno = 0; - - // try to parse integers first and fall back to floats - if (number_type == token_type::value_unsigned) - { - const auto x = std::strtoull(yytext.data(), &endptr, 10); - - // we checked the number format before - assert(endptr == yytext.data() + yytext.size()); - - if (errno == 0) - { - value_unsigned = static_cast(x); - if (value_unsigned == x) - { - return token_type::value_unsigned; - } - } - } - else if (number_type == token_type::value_integer) - { - const auto x = std::strtoll(yytext.data(), &endptr, 10); - - // we checked the number format before - assert(endptr == yytext.data() + yytext.size()); - - if (errno == 0) - { - value_integer = static_cast(x); - if (value_integer == x) - { - return token_type::value_integer; - } - } - } - - // this code is reached if we parse a floating-point number or if an - // integer conversion above failed - strtof(value_float, yytext.data(), &endptr); - - // we checked the number format before - assert(endptr == yytext.data() + yytext.size()); - - return token_type::value_float; - } - - /*! - @param[in] literal_text the literal text to expect - @param[in] length the length of the passed literal text - @param[in] return_type the token type to return on success - */ - token_type scan_literal(const char* literal_text, const std::size_t length, - token_type return_type) - { - assert(current == literal_text[0]); - for (std::size_t i = 1; i < length; ++i) - { - if (JSON_UNLIKELY(get() != literal_text[i])) - { - error_message = "invalid literal"; - return token_type::parse_error; - } - } - return return_type; - } - - ///////////////////// - // input management - ///////////////////// - - /// reset yytext; current character is beginning of token - void reset() noexcept - { - yytext.clear(); - token_string.clear(); - token_string.push_back(std::char_traits::to_char_type(current)); - } - - /* - @brief get next character from the input - - This function provides the interface to the used input adapter. It does - not throw in case the input reached EOF, but returns a - `std::char_traits::eof()` in that case. Stores the scanned characters - for use in error messages. - - @return character read from the input - */ - std::char_traits::int_type get() - { - ++chars_read; - current = ia->get_character(); - if (JSON_LIKELY(current != std::char_traits::eof())) - { - token_string.push_back(std::char_traits::to_char_type(current)); - } - return current; - } - - /// unget current character (return it again on next get) - void unget() - { - --chars_read; - if (JSON_LIKELY(current != std::char_traits::eof())) - { - ia->unget_character(); - assert(token_string.size() != 0); - token_string.pop_back(); - } - } - - /// add a character to yytext - void add(int c) - { - yytext.push_back(std::char_traits::to_char_type(c)); - } - - public: - ///////////////////// - // value getters - ///////////////////// - - /// return integer value - constexpr number_integer_t get_number_integer() const noexcept - { - return value_integer; - } - - /// return unsigned integer value - constexpr number_unsigned_t get_number_unsigned() const noexcept - { - return value_unsigned; - } - - /// return floating-point value - constexpr number_float_t get_number_float() const noexcept - { - return value_float; - } - - /// return current string value (implicitly resets the token; useful only once) - std::string move_string() - { - return std::move(yytext); - } - - ///////////////////// - // diagnostics - ///////////////////// - - /// return position of last read token - constexpr std::size_t get_position() const noexcept - { - return chars_read; - } - - /// return the last read token (for errors only). Will never contain EOF - /// (an arbitrary value that is not a valid char value, often -1), because - /// 255 may legitimately occur. May contain NUL, which should be escaped. - std::string get_token_string() const - { - // escape control characters - std::string result; - for (const auto c : token_string) - { - if ('\x00' <= c and c <= '\x1F') - { - // escape control characters - std::stringstream ss; - ss << "(c) << ">"; - result += ss.str(); - } - else - { - // add character as is - result.push_back(c); - } - } - - return result; - } - - /// return syntax error message - constexpr const char* get_error_message() const noexcept - { - return error_message; - } - - ///////////////////// - // actual scanner - ///////////////////// - - token_type scan() - { - // read next character and ignore whitespace - do - { - get(); - } - while (current == ' ' or current == '\t' or current == '\n' or current == '\r'); - - switch (current) - { - // structural characters - case '[': - return token_type::begin_array; - case ']': - return token_type::end_array; - case '{': - return token_type::begin_object; - case '}': - return token_type::end_object; - case ':': - return token_type::name_separator; - case ',': - return token_type::value_separator; - - // literals - case 't': - return scan_literal("true", 4, token_type::literal_true); - case 'f': - return scan_literal("false", 5, token_type::literal_false); - case 'n': - return scan_literal("null", 4, token_type::literal_null); - - // string - case '\"': - return scan_string(); - - // number - case '-': - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - return scan_number(); - - // end of input (the null byte is needed when parsing from - // string literals) - case '\0': - case std::char_traits::eof(): - return token_type::end_of_input; - - // error - default: - error_message = "invalid literal"; - return token_type::parse_error; - } - } - - private: - /// input adapter - detail::input_adapter_t ia = nullptr; - - /// the current character - std::char_traits::int_type current = std::char_traits::eof(); - - /// the number of characters read - std::size_t chars_read = 0; - - /// raw input token string (for error messages) - std::vector token_string {}; - - /// buffer for variable-length tokens (numbers, strings) - std::string yytext {}; - - /// a description of occurred lexer errors - const char* error_message = ""; - - // number values - number_integer_t value_integer = 0; - number_unsigned_t value_unsigned = 0; - number_float_t value_float = 0; - - /// the decimal point - const char decimal_point_char = '.'; -}; -} -} - -#endif - -/*** End of inlined file: lexer.hpp ***/ namespace nlohmann { @@ -6063,10 +3688,7 @@ class parser #endif -/*** End of inlined file: parser.hpp ***/ - - -/*** Start of inlined file: primitive_iterator.hpp ***/ +// #include "detail/iterators/primitive_iterator.hpp" #ifndef NLOHMANN_JSON_DETAIL_ITERATORS_PRIMITIVE_ITERATOR_HPP #define NLOHMANN_JSON_DETAIL_ITERATORS_PRIMITIVE_ITERATOR_HPP @@ -6199,148 +3821,12 @@ class primitive_iterator_t #endif -/*** End of inlined file: primitive_iterator.hpp ***/ - - -/*** Start of inlined file: internal_iterator.hpp ***/ +// #include "detail/iterators/internal_iterator.hpp" #ifndef NLOHMANN_JSON_DETAIL_ITERATORS_INTERNAL_ITERATOR_HPP #define NLOHMANN_JSON_DETAIL_ITERATORS_INTERNAL_ITERATOR_HPP +// #include "detail/iterators/primitive_iterator.hpp" -/*** Start of inlined file: primitive_iterator.hpp ***/ -#ifndef NLOHMANN_JSON_DETAIL_ITERATORS_PRIMITIVE_ITERATOR_HPP -#define NLOHMANN_JSON_DETAIL_ITERATORS_PRIMITIVE_ITERATOR_HPP - -#include // not -#include // ptrdiff_t -#include // numeric_limits -#include // ostream - -namespace nlohmann -{ -namespace detail -{ -/* -@brief an iterator for primitive JSON types - -This class models an iterator for primitive JSON types (boolean, number, -string). It's only purpose is to allow the iterator/const_iterator classes -to "iterate" over primitive values. Internally, the iterator is modeled by -a `difference_type` variable. Value begin_value (`0`) models the begin, -end_value (`1`) models past the end. -*/ -class primitive_iterator_t -{ - public: - using difference_type = std::ptrdiff_t; - - constexpr difference_type get_value() const noexcept - { - return m_it; - } - - /// set iterator to a defined beginning - void set_begin() noexcept - { - m_it = begin_value; - } - - /// set iterator to a defined past the end - void set_end() noexcept - { - m_it = end_value; - } - - /// return whether the iterator can be dereferenced - constexpr bool is_begin() const noexcept - { - return m_it == begin_value; - } - - /// return whether the iterator is at end - constexpr bool is_end() const noexcept - { - return m_it == end_value; - } - - friend constexpr bool operator==(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept - { - return lhs.m_it == rhs.m_it; - } - - friend constexpr bool operator<(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept - { - return lhs.m_it < rhs.m_it; - } - - primitive_iterator_t operator+(difference_type i) - { - auto result = *this; - result += i; - return result; - } - - friend constexpr difference_type operator-(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept - { - return lhs.m_it - rhs.m_it; - } - - friend std::ostream& operator<<(std::ostream& os, primitive_iterator_t it) - { - return os << it.m_it; - } - - primitive_iterator_t& operator++() - { - ++m_it; - return *this; - } - - primitive_iterator_t const operator++(int) - { - auto result = *this; - m_it++; - return result; - } - - primitive_iterator_t& operator--() - { - --m_it; - return *this; - } - - primitive_iterator_t const operator--(int) - { - auto result = *this; - m_it--; - return result; - } - - primitive_iterator_t& operator+=(difference_type n) - { - m_it += n; - return *this; - } - - primitive_iterator_t& operator-=(difference_type n) - { - m_it -= n; - return *this; - } - - private: - static constexpr difference_type begin_value = 0; - static constexpr difference_type end_value = begin_value + 1; - - /// iterator as signed integer type - difference_type m_it = (std::numeric_limits::min)(); -}; -} -} - -#endif - -/*** End of inlined file: primitive_iterator.hpp ***/ namespace nlohmann { @@ -6366,10 +3852,7 @@ template struct internal_iterator #endif -/*** End of inlined file: internal_iterator.hpp ***/ - - -/*** Start of inlined file: iter_impl.hpp ***/ +// #include "detail/iterators/iter_impl.hpp" #ifndef NLOHMANN_JSON_DETAIL_ITERATORS_ITER_IMPL_HPP #define NLOHMANN_JSON_DETAIL_ITERATORS_ITER_IMPL_HPP @@ -6377,36 +3860,18 @@ template struct internal_iterator #include // iterator, random_access_iterator_tag, bidirectional_iterator_tag, advance, next #include // conditional, is_const, remove_const +// #include "detail/exceptions.hpp" -/*** Start of inlined file: internal_iterator.hpp ***/ -#ifndef NLOHMANN_JSON_DETAIL_ITERATORS_INTERNAL_ITERATOR_HPP -#define NLOHMANN_JSON_DETAIL_ITERATORS_INTERNAL_ITERATOR_HPP +// #include "detail/iterators/internal_iterator.hpp" -namespace nlohmann -{ -namespace detail -{ -/*! -@brief an iterator value +// #include "detail/iterators/primitive_iterator.hpp" -@note This structure could easily be a union, but MSVC currently does not allow -unions members with complex constructors, see https://github.com/nlohmann/json/pull/105. -*/ -template struct internal_iterator -{ - /// iterator for JSON objects - typename BasicJsonType::object_t::iterator object_iterator {}; - /// iterator for JSON arrays - typename BasicJsonType::array_t::iterator array_iterator {}; - /// generic iterator for all other types - primitive_iterator_t primitive_iterator {}; -}; -} -} +// #include "detail/macro_scope.hpp" -#endif +// #include "detail/meta.hpp" + +// #include "detail/value_t.hpp" -/*** End of inlined file: internal_iterator.hpp ***/ namespace nlohmann { @@ -7012,16 +4477,16 @@ class iter_impl #endif -/*** End of inlined file: iter_impl.hpp ***/ - - -/*** Start of inlined file: iteration_proxy.hpp ***/ +// #include "detail/iterators/iteration_proxy.hpp" #ifndef NLOHMANN_JSON_DETAIL_ITERATORS_ITERATION_PROXY_HPP #define NLOHMANN_JSON_DETAIL_ITERATORS_ITERATION_PROXY_HPP #include // size_t #include // string, to_string +// #include "detail/value_t.hpp" + + namespace nlohmann { namespace detail @@ -7116,10 +4581,7 @@ template class iteration_proxy #endif -/*** End of inlined file: iteration_proxy.hpp ***/ - - -/*** Start of inlined file: json_reverse_iterator.hpp ***/ +// #include "detail/iterators/json_reverse_iterator.hpp" #ifndef NLOHMANN_JSON_DETAIL_ITERATORS_JSON_REVERSE_ITERATOR_HPP #define NLOHMANN_JSON_DETAIL_ITERATORS_JSON_REVERSE_ITERATOR_HPP @@ -7243,10 +4705,7 @@ class json_reverse_iterator : public std::reverse_iterator #endif -/*** End of inlined file: json_reverse_iterator.hpp ***/ - - -/*** Start of inlined file: output_adapters.hpp ***/ +// #include "detail/parsing/output_adapters.hpp" #ifndef NLOHMANN_JSON_DETAIL_PARSING_OUTPUT_ADAPTERS_HPP #define NLOHMANN_JSON_DETAIL_PARSING_OUTPUT_ADAPTERS_HPP @@ -7364,10 +4823,7 @@ class output_adapter #endif -/*** End of inlined file: output_adapters.hpp ***/ - - -/*** Start of inlined file: binary_reader.hpp ***/ +// #include "detail/parsing/binary_reader.hpp" #ifndef NLOHMANN_JSON_DETAIL_PARSING_BINARY_READER_HPP #define NLOHMANN_JSON_DETAIL_PARSING_BINARY_READER_HPP @@ -7386,6 +4842,15 @@ class output_adapter #include // char_traits, string #include // make_pair, move +// #include "detail/exceptions.hpp" + +// #include "detail/macro_scope.hpp" + +// #include "detail/parsing/input_adapters.hpp" + +// #include "detail/value_t.hpp" + + namespace nlohmann { namespace detail @@ -8457,10 +5922,7 @@ class binary_reader #endif -/*** End of inlined file: binary_reader.hpp ***/ - - -/*** Start of inlined file: binary_writer.hpp ***/ +// #include "detail/parsing/binary_writer.hpp" #ifndef NLOHMANN_JSON_DETAIL_PARSING_BINARY_WRITER_HPP #define NLOHMANN_JSON_DETAIL_PARSING_BINARY_WRITER_HPP @@ -8470,1219 +5932,10 @@ class binary_reader #include // memcpy #include // numeric_limits +// #include "detail/parsing/binary_reader.hpp" -/*** Start of inlined file: binary_reader.hpp ***/ -#ifndef NLOHMANN_JSON_DETAIL_PARSING_BINARY_READER_HPP -#define NLOHMANN_JSON_DETAIL_PARSING_BINARY_READER_HPP +// #include "detail/parsing/output_adapters.hpp" -#include // generate_n -#include // array -#include // assert -#include // ldexp -#include // size_t -#include // uint8_t, uint16_t, uint32_t, uint64_t -#include // memcpy -#include // setw, setfill -#include // hex -#include // back_inserter -#include // numeric_limits -#include // stringstream -#include // char_traits, string -#include // make_pair, move - -namespace nlohmann -{ -namespace detail -{ -/////////////////// -// binary reader // -/////////////////// - -/*! -@brief deserialization of CBOR and MessagePack values -*/ -template -class binary_reader -{ - using number_integer_t = typename BasicJsonType::number_integer_t; - using number_unsigned_t = typename BasicJsonType::number_unsigned_t; - - public: - /*! - @brief create a binary reader - - @param[in] adapter input adapter to read from - */ - explicit binary_reader(input_adapter_t adapter) : ia(std::move(adapter)) - { - assert(ia); - } - - /*! - @brief create a JSON value from CBOR input - - @param[in] strict whether to expect the input to be consumed completed - @return JSON value created from CBOR input - - @throw parse_error.110 if input ended unexpectedly or the end of file was - not reached when @a strict was set to true - @throw parse_error.112 if unsupported byte was read - */ - BasicJsonType parse_cbor(const bool strict) - { - const auto res = parse_cbor_internal(); - if (strict) - { - get(); - check_eof(true); - } - return res; - } - - /*! - @brief create a JSON value from MessagePack input - - @param[in] strict whether to expect the input to be consumed completed - @return JSON value created from MessagePack input - - @throw parse_error.110 if input ended unexpectedly or the end of file was - not reached when @a strict was set to true - @throw parse_error.112 if unsupported byte was read - */ - BasicJsonType parse_msgpack(const bool strict) - { - const auto res = parse_msgpack_internal(); - if (strict) - { - get(); - check_eof(true); - } - return res; - } - - /*! - @brief determine system byte order - - @return true if and only if system's byte order is little endian - - @note from http://stackoverflow.com/a/1001328/266378 - */ - static constexpr bool little_endianess(int num = 1) noexcept - { - return (*reinterpret_cast(&num) == 1); - } - - private: - /*! - @param[in] get_char whether a new character should be retrieved from the - input (true, default) or whether the last read - character should be considered instead - */ - BasicJsonType parse_cbor_internal(const bool get_char = true) - { - switch (get_char ? get() : current) - { - // EOF - case std::char_traits::eof(): - JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input")); - - // Integer 0x00..0x17 (0..23) - case 0x00: - case 0x01: - case 0x02: - case 0x03: - case 0x04: - case 0x05: - case 0x06: - case 0x07: - case 0x08: - case 0x09: - case 0x0A: - case 0x0B: - case 0x0C: - case 0x0D: - case 0x0E: - case 0x0F: - case 0x10: - case 0x11: - case 0x12: - case 0x13: - case 0x14: - case 0x15: - case 0x16: - case 0x17: - return static_cast(current); - - case 0x18: // Unsigned integer (one-byte uint8_t follows) - return get_number(); - - case 0x19: // Unsigned integer (two-byte uint16_t follows) - return get_number(); - - case 0x1A: // Unsigned integer (four-byte uint32_t follows) - return get_number(); - - case 0x1B: // Unsigned integer (eight-byte uint64_t follows) - return get_number(); - - // Negative integer -1-0x00..-1-0x17 (-1..-24) - case 0x20: - case 0x21: - case 0x22: - case 0x23: - case 0x24: - case 0x25: - case 0x26: - case 0x27: - case 0x28: - case 0x29: - case 0x2A: - case 0x2B: - case 0x2C: - case 0x2D: - case 0x2E: - case 0x2F: - case 0x30: - case 0x31: - case 0x32: - case 0x33: - case 0x34: - case 0x35: - case 0x36: - case 0x37: - return static_cast(0x20 - 1 - current); - - case 0x38: // Negative integer (one-byte uint8_t follows) - { - // must be uint8_t ! - return static_cast(-1) - get_number(); - } - - case 0x39: // Negative integer -1-n (two-byte uint16_t follows) - { - return static_cast(-1) - get_number(); - } - - case 0x3A: // Negative integer -1-n (four-byte uint32_t follows) - { - return static_cast(-1) - get_number(); - } - - case 0x3B: // Negative integer -1-n (eight-byte uint64_t follows) - { - return static_cast(-1) - - static_cast(get_number()); - } - - // UTF-8 string (0x00..0x17 bytes follow) - case 0x60: - case 0x61: - case 0x62: - case 0x63: - case 0x64: - case 0x65: - case 0x66: - case 0x67: - case 0x68: - case 0x69: - case 0x6A: - case 0x6B: - case 0x6C: - case 0x6D: - case 0x6E: - case 0x6F: - case 0x70: - case 0x71: - case 0x72: - case 0x73: - case 0x74: - case 0x75: - case 0x76: - case 0x77: - case 0x78: // UTF-8 string (one-byte uint8_t for n follows) - case 0x79: // UTF-8 string (two-byte uint16_t for n follow) - case 0x7A: // UTF-8 string (four-byte uint32_t for n follow) - case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow) - case 0x7F: // UTF-8 string (indefinite length) - { - return get_cbor_string(); - } - - // array (0x00..0x17 data items follow) - case 0x80: - case 0x81: - case 0x82: - case 0x83: - case 0x84: - case 0x85: - case 0x86: - case 0x87: - case 0x88: - case 0x89: - case 0x8A: - case 0x8B: - case 0x8C: - case 0x8D: - case 0x8E: - case 0x8F: - case 0x90: - case 0x91: - case 0x92: - case 0x93: - case 0x94: - case 0x95: - case 0x96: - case 0x97: - { - return get_cbor_array(current & 0x1F); - } - - case 0x98: // array (one-byte uint8_t for n follows) - { - return get_cbor_array(get_number()); - } - - case 0x99: // array (two-byte uint16_t for n follow) - { - return get_cbor_array(get_number()); - } - - case 0x9A: // array (four-byte uint32_t for n follow) - { - return get_cbor_array(get_number()); - } - - case 0x9B: // array (eight-byte uint64_t for n follow) - { - return get_cbor_array(get_number()); - } - - case 0x9F: // array (indefinite length) - { - BasicJsonType result = value_t::array; - while (get() != 0xFF) - { - result.push_back(parse_cbor_internal(false)); - } - return result; - } - - // map (0x00..0x17 pairs of data items follow) - case 0xA0: - case 0xA1: - case 0xA2: - case 0xA3: - case 0xA4: - case 0xA5: - case 0xA6: - case 0xA7: - case 0xA8: - case 0xA9: - case 0xAA: - case 0xAB: - case 0xAC: - case 0xAD: - case 0xAE: - case 0xAF: - case 0xB0: - case 0xB1: - case 0xB2: - case 0xB3: - case 0xB4: - case 0xB5: - case 0xB6: - case 0xB7: - { - return get_cbor_object(current & 0x1F); - } - - case 0xB8: // map (one-byte uint8_t for n follows) - { - return get_cbor_object(get_number()); - } - - case 0xB9: // map (two-byte uint16_t for n follow) - { - return get_cbor_object(get_number()); - } - - case 0xBA: // map (four-byte uint32_t for n follow) - { - return get_cbor_object(get_number()); - } - - case 0xBB: // map (eight-byte uint64_t for n follow) - { - return get_cbor_object(get_number()); - } - - case 0xBF: // map (indefinite length) - { - BasicJsonType result = value_t::object; - while (get() != 0xFF) - { - auto key = get_cbor_string(); - result[key] = parse_cbor_internal(); - } - return result; - } - - case 0xF4: // false - { - return false; - } - - case 0xF5: // true - { - return true; - } - - case 0xF6: // null - { - return value_t::null; - } - - case 0xF9: // Half-Precision Float (two-byte IEEE 754) - { - const int byte1 = get(); - check_eof(); - const int byte2 = get(); - check_eof(); - - // code from RFC 7049, Appendix D, Figure 3: - // As half-precision floating-point numbers were only added - // to IEEE 754 in 2008, today's programming platforms often - // still only have limited support for them. It is very - // easy to include at least decoding support for them even - // without such support. An example of a small decoder for - // half-precision floating-point numbers in the C language - // is shown in Fig. 3. - const int half = (byte1 << 8) + byte2; - const int exp = (half >> 10) & 0x1F; - const int mant = half & 0x3FF; - double val; - if (exp == 0) - { - val = std::ldexp(mant, -24); - } - else if (exp != 31) - { - val = std::ldexp(mant + 1024, exp - 25); - } - else - { - val = (mant == 0) ? std::numeric_limits::infinity() - : std::numeric_limits::quiet_NaN(); - } - return (half & 0x8000) != 0 ? -val : val; - } - - case 0xFA: // Single-Precision Float (four-byte IEEE 754) - { - return get_number(); - } - - case 0xFB: // Double-Precision Float (eight-byte IEEE 754) - { - return get_number(); - } - - default: // anything else (0xFF is handled inside the other types) - { - std::stringstream ss; - ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; - JSON_THROW(parse_error::create(112, chars_read, "error reading CBOR; last byte: 0x" + ss.str())); - } - } - } - - BasicJsonType parse_msgpack_internal() - { - switch (get()) - { - // EOF - case std::char_traits::eof(): - JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input")); - - // positive fixint - case 0x00: - case 0x01: - case 0x02: - case 0x03: - case 0x04: - case 0x05: - case 0x06: - case 0x07: - case 0x08: - case 0x09: - case 0x0A: - case 0x0B: - case 0x0C: - case 0x0D: - case 0x0E: - case 0x0F: - case 0x10: - case 0x11: - case 0x12: - case 0x13: - case 0x14: - case 0x15: - case 0x16: - case 0x17: - case 0x18: - case 0x19: - case 0x1A: - case 0x1B: - case 0x1C: - case 0x1D: - case 0x1E: - case 0x1F: - case 0x20: - case 0x21: - case 0x22: - case 0x23: - case 0x24: - case 0x25: - case 0x26: - case 0x27: - case 0x28: - case 0x29: - case 0x2A: - case 0x2B: - case 0x2C: - case 0x2D: - case 0x2E: - case 0x2F: - case 0x30: - case 0x31: - case 0x32: - case 0x33: - case 0x34: - case 0x35: - case 0x36: - case 0x37: - case 0x38: - case 0x39: - case 0x3A: - case 0x3B: - case 0x3C: - case 0x3D: - case 0x3E: - case 0x3F: - case 0x40: - case 0x41: - case 0x42: - case 0x43: - case 0x44: - case 0x45: - case 0x46: - case 0x47: - case 0x48: - case 0x49: - case 0x4A: - case 0x4B: - case 0x4C: - case 0x4D: - case 0x4E: - case 0x4F: - case 0x50: - case 0x51: - case 0x52: - case 0x53: - case 0x54: - case 0x55: - case 0x56: - case 0x57: - case 0x58: - case 0x59: - case 0x5A: - case 0x5B: - case 0x5C: - case 0x5D: - case 0x5E: - case 0x5F: - case 0x60: - case 0x61: - case 0x62: - case 0x63: - case 0x64: - case 0x65: - case 0x66: - case 0x67: - case 0x68: - case 0x69: - case 0x6A: - case 0x6B: - case 0x6C: - case 0x6D: - case 0x6E: - case 0x6F: - case 0x70: - case 0x71: - case 0x72: - case 0x73: - case 0x74: - case 0x75: - case 0x76: - case 0x77: - case 0x78: - case 0x79: - case 0x7A: - case 0x7B: - case 0x7C: - case 0x7D: - case 0x7E: - case 0x7F: - return static_cast(current); - - // fixmap - case 0x80: - case 0x81: - case 0x82: - case 0x83: - case 0x84: - case 0x85: - case 0x86: - case 0x87: - case 0x88: - case 0x89: - case 0x8A: - case 0x8B: - case 0x8C: - case 0x8D: - case 0x8E: - case 0x8F: - { - return get_msgpack_object(current & 0x0F); - } - - // fixarray - case 0x90: - case 0x91: - case 0x92: - case 0x93: - case 0x94: - case 0x95: - case 0x96: - case 0x97: - case 0x98: - case 0x99: - case 0x9A: - case 0x9B: - case 0x9C: - case 0x9D: - case 0x9E: - case 0x9F: - { - return get_msgpack_array(current & 0x0F); - } - - // fixstr - case 0xA0: - case 0xA1: - case 0xA2: - case 0xA3: - case 0xA4: - case 0xA5: - case 0xA6: - case 0xA7: - case 0xA8: - case 0xA9: - case 0xAA: - case 0xAB: - case 0xAC: - case 0xAD: - case 0xAE: - case 0xAF: - case 0xB0: - case 0xB1: - case 0xB2: - case 0xB3: - case 0xB4: - case 0xB5: - case 0xB6: - case 0xB7: - case 0xB8: - case 0xB9: - case 0xBA: - case 0xBB: - case 0xBC: - case 0xBD: - case 0xBE: - case 0xBF: - return get_msgpack_string(); - - case 0xC0: // nil - return value_t::null; - - case 0xC2: // false - return false; - - case 0xC3: // true - return true; - - case 0xCA: // float 32 - return get_number(); - - case 0xCB: // float 64 - return get_number(); - - case 0xCC: // uint 8 - return get_number(); - - case 0xCD: // uint 16 - return get_number(); - - case 0xCE: // uint 32 - return get_number(); - - case 0xCF: // uint 64 - return get_number(); - - case 0xD0: // int 8 - return get_number(); - - case 0xD1: // int 16 - return get_number(); - - case 0xD2: // int 32 - return get_number(); - - case 0xD3: // int 64 - return get_number(); - - case 0xD9: // str 8 - case 0xDA: // str 16 - case 0xDB: // str 32 - return get_msgpack_string(); - - case 0xDC: // array 16 - { - return get_msgpack_array(get_number()); - } - - case 0xDD: // array 32 - { - return get_msgpack_array(get_number()); - } - - case 0xDE: // map 16 - { - return get_msgpack_object(get_number()); - } - - case 0xDF: // map 32 - { - return get_msgpack_object(get_number()); - } - - // positive fixint - case 0xE0: - case 0xE1: - case 0xE2: - case 0xE3: - case 0xE4: - case 0xE5: - case 0xE6: - case 0xE7: - case 0xE8: - case 0xE9: - case 0xEA: - case 0xEB: - case 0xEC: - case 0xED: - case 0xEE: - case 0xEF: - case 0xF0: - case 0xF1: - case 0xF2: - case 0xF3: - case 0xF4: - case 0xF5: - case 0xF6: - case 0xF7: - case 0xF8: - case 0xF9: - case 0xFA: - case 0xFB: - case 0xFC: - case 0xFD: - case 0xFE: - case 0xFF: - return static_cast(current); - - default: // anything else - { - std::stringstream ss; - ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; - JSON_THROW(parse_error::create(112, chars_read, - "error reading MessagePack; last byte: 0x" + ss.str())); - } - } - } - - /*! - @brief get next character from the input - - This function provides the interface to the used input adapter. It does - not throw in case the input reached EOF, but returns a -'ve valued - `std::char_traits::eof()` in that case. - - @return character read from the input - */ - int get() - { - ++chars_read; - return (current = ia->get_character()); - } - - /* - @brief read a number from the input - - @tparam NumberType the type of the number - - @return number of type @a NumberType - - @note This function needs to respect the system's endianess, because - bytes in CBOR and MessagePack are stored in network order (big - endian) and therefore need reordering on little endian systems. - - @throw parse_error.110 if input has less than `sizeof(NumberType)` bytes - */ - template NumberType get_number() - { - // step 1: read input into array with system's byte order - std::array vec; - for (std::size_t i = 0; i < sizeof(NumberType); ++i) - { - get(); - check_eof(); - - // reverse byte order prior to conversion if necessary - if (is_little_endian) - { - vec[sizeof(NumberType) - i - 1] = static_cast(current); - } - else - { - vec[i] = static_cast(current); // LCOV_EXCL_LINE - } - } - - // step 2: convert array into number of type T and return - NumberType result; - std::memcpy(&result, vec.data(), sizeof(NumberType)); - return result; - } - - /*! - @brief create a string by reading characters from the input - - @param[in] len number of bytes to read - - @note We can not reserve @a len bytes for the result, because @a len - may be too large. Usually, @ref check_eof() detects the end of - the input before we run out of string memory. - - @return string created by reading @a len bytes - - @throw parse_error.110 if input has less than @a len bytes - */ - template - std::string get_string(const NumberType len) - { - std::string result; - std::generate_n(std::back_inserter(result), len, [this]() - { - get(); - check_eof(); - return static_cast(current); - }); - return result; - } - - /*! - @brief reads a CBOR string - - This function first reads starting bytes to determine the expected - string length and then copies this number of bytes into a string. - Additionally, CBOR's strings with indefinite lengths are supported. - - @return string - - @throw parse_error.110 if input ended - @throw parse_error.113 if an unexpected byte is read - */ - std::string get_cbor_string() - { - check_eof(); - - switch (current) - { - // UTF-8 string (0x00..0x17 bytes follow) - case 0x60: - case 0x61: - case 0x62: - case 0x63: - case 0x64: - case 0x65: - case 0x66: - case 0x67: - case 0x68: - case 0x69: - case 0x6A: - case 0x6B: - case 0x6C: - case 0x6D: - case 0x6E: - case 0x6F: - case 0x70: - case 0x71: - case 0x72: - case 0x73: - case 0x74: - case 0x75: - case 0x76: - case 0x77: - { - return get_string(current & 0x1F); - } - - case 0x78: // UTF-8 string (one-byte uint8_t for n follows) - { - return get_string(get_number()); - } - - case 0x79: // UTF-8 string (two-byte uint16_t for n follow) - { - return get_string(get_number()); - } - - case 0x7A: // UTF-8 string (four-byte uint32_t for n follow) - { - return get_string(get_number()); - } - - case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow) - { - return get_string(get_number()); - } - - case 0x7F: // UTF-8 string (indefinite length) - { - std::string result; - while (get() != 0xFF) - { - check_eof(); - result.push_back(static_cast(current)); - } - return result; - } - - default: - { - std::stringstream ss; - ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; - JSON_THROW(parse_error::create(113, chars_read, "expected a CBOR string; last byte: 0x" + ss.str())); - } - } - } - - template - BasicJsonType get_cbor_array(const NumberType len) - { - BasicJsonType result = value_t::array; - std::generate_n(std::back_inserter(*result.m_value.array), len, [this]() - { - return parse_cbor_internal(); - }); - return result; - } - - template - BasicJsonType get_cbor_object(const NumberType len) - { - BasicJsonType result = value_t::object; - std::generate_n(std::inserter(*result.m_value.object, - result.m_value.object->end()), - len, [this]() - { - get(); - auto key = get_cbor_string(); - auto val = parse_cbor_internal(); - return std::make_pair(std::move(key), std::move(val)); - }); - return result; - } - - /*! - @brief reads a MessagePack string - - This function first reads starting bytes to determine the expected - string length and then copies this number of bytes into a string. - - @return string - - @throw parse_error.110 if input ended - @throw parse_error.113 if an unexpected byte is read - */ - std::string get_msgpack_string() - { - check_eof(); - - switch (current) - { - // fixstr - case 0xA0: - case 0xA1: - case 0xA2: - case 0xA3: - case 0xA4: - case 0xA5: - case 0xA6: - case 0xA7: - case 0xA8: - case 0xA9: - case 0xAA: - case 0xAB: - case 0xAC: - case 0xAD: - case 0xAE: - case 0xAF: - case 0xB0: - case 0xB1: - case 0xB2: - case 0xB3: - case 0xB4: - case 0xB5: - case 0xB6: - case 0xB7: - case 0xB8: - case 0xB9: - case 0xBA: - case 0xBB: - case 0xBC: - case 0xBD: - case 0xBE: - case 0xBF: - { - return get_string(current & 0x1F); - } - - case 0xD9: // str 8 - { - return get_string(get_number()); - } - - case 0xDA: // str 16 - { - return get_string(get_number()); - } - - case 0xDB: // str 32 - { - return get_string(get_number()); - } - - default: - { - std::stringstream ss; - ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; - JSON_THROW(parse_error::create(113, chars_read, - "expected a MessagePack string; last byte: 0x" + ss.str())); - } - } - } - - template - BasicJsonType get_msgpack_array(const NumberType len) - { - BasicJsonType result = value_t::array; - std::generate_n(std::back_inserter(*result.m_value.array), len, [this]() - { - return parse_msgpack_internal(); - }); - return result; - } - - template - BasicJsonType get_msgpack_object(const NumberType len) - { - BasicJsonType result = value_t::object; - std::generate_n(std::inserter(*result.m_value.object, - result.m_value.object->end()), - len, [this]() - { - get(); - auto key = get_msgpack_string(); - auto val = parse_msgpack_internal(); - return std::make_pair(std::move(key), std::move(val)); - }); - return result; - } - - /*! - @brief check if input ended - @throw parse_error.110 if input ended - */ - void check_eof(const bool expect_eof = false) const - { - if (expect_eof) - { - if (JSON_UNLIKELY(current != std::char_traits::eof())) - { - JSON_THROW(parse_error::create(110, chars_read, "expected end of input")); - } - } - else - { - if (JSON_UNLIKELY(current == std::char_traits::eof())) - { - JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input")); - } - } - } - - private: - /// input adapter - input_adapter_t ia = nullptr; - - /// the current character - int current = std::char_traits::eof(); - - /// the number of characters read - std::size_t chars_read = 0; - - /// whether we can assume little endianess - const bool is_little_endian = little_endianess(); -}; -} -} - -#endif - -/*** End of inlined file: binary_reader.hpp ***/ - - -/*** Start of inlined file: output_adapters.hpp ***/ -#ifndef NLOHMANN_JSON_DETAIL_PARSING_OUTPUT_ADAPTERS_HPP -#define NLOHMANN_JSON_DETAIL_PARSING_OUTPUT_ADAPTERS_HPP - -#include // copy -#include // size_t -#include // streamsize -#include // back_inserter -#include // shared_ptr, make_shared -#include // basic_ostream -#include // basic_string -#include // vector - -namespace nlohmann -{ -namespace detail -{ -/// abstract output adapter interface -template struct output_adapter_protocol -{ - virtual void write_character(CharType c) = 0; - virtual void write_characters(const CharType* s, std::size_t length) = 0; - virtual ~output_adapter_protocol() = default; -}; - -/// a type to simplify interfaces -template -using output_adapter_t = std::shared_ptr>; - -/// output adapter for byte vectors -template -class output_vector_adapter : public output_adapter_protocol -{ - public: - explicit output_vector_adapter(std::vector& vec) : v(vec) {} - - void write_character(CharType c) override - { - v.push_back(c); - } - - void write_characters(const CharType* s, std::size_t length) override - { - std::copy(s, s + length, std::back_inserter(v)); - } - - private: - std::vector& v; -}; - -/// output adapter for output streams -template -class output_stream_adapter : public output_adapter_protocol -{ - public: - explicit output_stream_adapter(std::basic_ostream& s) : stream(s) {} - - void write_character(CharType c) override - { - stream.put(c); - } - - void write_characters(const CharType* s, std::size_t length) override - { - stream.write(s, static_cast(length)); - } - - private: - std::basic_ostream& stream; -}; - -/// output adapter for basic_string -template -class output_string_adapter : public output_adapter_protocol -{ - public: - explicit output_string_adapter(std::basic_string& s) : str(s) {} - - void write_character(CharType c) override - { - str.push_back(c); - } - - void write_characters(const CharType* s, std::size_t length) override - { - str.append(s, length); - } - - private: - std::basic_string& str; -}; - -template -class output_adapter -{ - public: - output_adapter(std::vector& vec) - : oa(std::make_shared>(vec)) {} - - output_adapter(std::basic_ostream& s) - : oa(std::make_shared>(s)) {} - - output_adapter(std::basic_string& s) - : oa(std::make_shared>(s)) {} - - operator output_adapter_t() - { - return oa; - } - - private: - output_adapter_t oa = nullptr; -}; -} -} - -#endif - -/*** End of inlined file: output_adapters.hpp ***/ namespace nlohmann { @@ -10231,10 +6484,7 @@ class binary_writer #endif -/*** End of inlined file: binary_writer.hpp ***/ - - -/*** Start of inlined file: serializer.hpp ***/ +// #include "detail/serializer.hpp" #ifndef NLOHMANN_JSON_DETAIL_SERIALIZER_HPP #define NLOHMANN_JSON_DETAIL_SERIALIZER_HPP @@ -10252,6 +6502,15 @@ class binary_writer #include // string #include // is_same +// #include "detail/macro_scope.hpp" + +// #include "detail/meta.hpp" + +// #include "detail/parsing/output_adapters.hpp" + +// #include "detail/value_t.hpp" + + namespace nlohmann { namespace detail @@ -11028,10 +7287,7 @@ class serializer #endif -/*** End of inlined file: serializer.hpp ***/ - - -/*** Start of inlined file: json_ref.hpp ***/ +// #include "detail/json_ref.hpp" #ifndef NLOHMANN_JSON_DETAIL_JSON_REF_HPP #define NLOHMANN_JSON_DETAIL_JSON_REF_HPP @@ -11099,15 +7355,17 @@ class json_ref #endif -/*** End of inlined file: json_ref.hpp ***/ - - -/*** Start of inlined file: adl_serializer.hpp ***/ +// #include "adl_serializer.hpp" #ifndef NLOHMANN_JSON_ADL_SERIALIZER_HPP #define NLOHMANN_JSON_ADL_SERIALIZER_HPP #include +// #include "detail/conversions/from_json.hpp" + +// #include "detail/conversions/to_json.hpp" + + namespace nlohmann { template @@ -11149,7 +7407,6 @@ struct adl_serializer #endif -/*** End of inlined file: adl_serializer.hpp ***/ /*! @brief namespace for Niels Lohmann @@ -11640,6 +7897,7 @@ class basic_json /// @} + ///////////////////// // container types // ///////////////////// @@ -11681,6 +7939,7 @@ class basic_json /// @} + /*! @brief returns the allocator associated with the container */ @@ -11767,6 +8026,7 @@ class basic_json return result; } + /////////////////////////// // JSON value data types // /////////////////////////// @@ -12511,6 +8771,7 @@ class basic_json */ using parser_callback_t = typename parser::parser_callback_t; + ////////////////// // constructors // ////////////////// @@ -13036,6 +9297,7 @@ class basic_json assert_invariant(); } + /////////////////////////////////////// // other constructors and destructor // /////////////////////////////////////// @@ -14143,6 +10405,7 @@ class basic_json /// @} + //////////////////// // element access // //////////////////// @@ -15138,6 +11401,7 @@ class basic_json /// @} + //////////// // lookup // //////////// @@ -15227,6 +11491,7 @@ class basic_json /// @} + /////////////// // iterators // /////////////// @@ -15638,6 +11903,7 @@ class basic_json /// @} + ////////////// // capacity // ////////////// @@ -15854,6 +12120,7 @@ class basic_json /// @} + /////////////// // modifiers // /////////////// @@ -17216,6 +13483,7 @@ class basic_json /// @} + ///////////////////// // deserialization // ///////////////////// @@ -17489,6 +13757,7 @@ class basic_json } } + private: ////////////////////// // member variables // @@ -19095,8 +15364,7 @@ inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std return nlohmann::json::json_pointer(std::string(s, n)); } - -/*** Start of inlined file: macro_unscope.hpp ***/ +// #include "detail/macro_unscope.hpp" #ifndef NLOHMANN_JSON_DETAIL_MACRO_UNSCOPE_HPP #define NLOHMANN_JSON_DETAIL_MACRO_UNSCOPE_HPP @@ -19123,7 +15391,5 @@ inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std #endif -/*** End of inlined file: macro_unscope.hpp ***/ #endif - From 85173f56279eb55161415fa0eae4276059dee876 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Wed, 10 Jan 2018 10:18:31 +0100 Subject: [PATCH 56/59] :hammer: some clean up --- develop/adl_serializer.hpp | 5 +- develop/detail/conversions/from_json.hpp | 5 +- develop/detail/conversions/to_json.hpp | 5 +- .../detail/iterators/internal_iterator.hpp | 5 +- develop/detail/iterators/iter_impl.hpp | 5 +- develop/detail/iterators/iteration_proxy.hpp | 5 +- .../iterators/json_reverse_iterator.hpp | 5 +- .../detail/iterators/primitive_iterator.hpp | 5 +- develop/detail/json_ref.hpp | 5 +- develop/detail/macro_scope.hpp | 5 +- develop/detail/macro_unscope.hpp | 5 +- develop/detail/meta.hpp | 5 +- develop/detail/parsing/binary_reader.hpp | 5 +- develop/detail/parsing/binary_writer.hpp | 5 +- develop/detail/parsing/input_adapters.hpp | 5 +- develop/detail/parsing/lexer.hpp | 5 +- develop/detail/parsing/output_adapters.hpp | 5 +- develop/detail/parsing/parser.hpp | 5 +- develop/detail/serializer.hpp | 5 +- develop/detail/value_t.hpp | 5 +- src/json.hpp | 136 +++++------------- 21 files changed, 58 insertions(+), 178 deletions(-) diff --git a/develop/adl_serializer.hpp b/develop/adl_serializer.hpp index c2ad371c..cae95637 100644 --- a/develop/adl_serializer.hpp +++ b/develop/adl_serializer.hpp @@ -1,5 +1,4 @@ -#ifndef NLOHMANN_JSON_ADL_SERIALIZER_HPP -#define NLOHMANN_JSON_ADL_SERIALIZER_HPP +#pragma once #include @@ -44,5 +43,3 @@ struct adl_serializer } }; } - -#endif diff --git a/develop/detail/conversions/from_json.hpp b/develop/detail/conversions/from_json.hpp index 55925464..ba89e540 100644 --- a/develop/detail/conversions/from_json.hpp +++ b/develop/detail/conversions/from_json.hpp @@ -1,5 +1,4 @@ -#ifndef NLOHMANN_JSON_DETAIL_CONVERSIONS_FROM_JSON_HPP -#define NLOHMANN_JSON_DETAIL_CONVERSIONS_FROM_JSON_HPP +#pragma once #include // transform #include // array @@ -314,5 +313,3 @@ namespace constexpr const auto& from_json = detail::static_const::value; } } - -#endif diff --git a/develop/detail/conversions/to_json.hpp b/develop/detail/conversions/to_json.hpp index 0153b13d..2df7b0b8 100644 --- a/develop/detail/conversions/to_json.hpp +++ b/develop/detail/conversions/to_json.hpp @@ -1,5 +1,4 @@ -#ifndef NLOHMANN_JSON_DETAIL_CONVERSIONS_TO_JSON_HPP -#define NLOHMANN_JSON_DETAIL_CONVERSIONS_TO_JSON_HPP +#pragma once #include // or, and, not #include // begin, end @@ -337,5 +336,3 @@ namespace constexpr const auto& to_json = detail::static_const::value; } } - -#endif diff --git a/develop/detail/iterators/internal_iterator.hpp b/develop/detail/iterators/internal_iterator.hpp index 25763355..b65b33d3 100644 --- a/develop/detail/iterators/internal_iterator.hpp +++ b/develop/detail/iterators/internal_iterator.hpp @@ -1,5 +1,4 @@ -#ifndef NLOHMANN_JSON_DETAIL_ITERATORS_INTERNAL_ITERATOR_HPP -#define NLOHMANN_JSON_DETAIL_ITERATORS_INTERNAL_ITERATOR_HPP +#pragma once #include "detail/iterators/primitive_iterator.hpp" @@ -24,5 +23,3 @@ template struct internal_iterator }; } } - -#endif diff --git a/develop/detail/iterators/iter_impl.hpp b/develop/detail/iterators/iter_impl.hpp index e11412c6..4d939476 100644 --- a/develop/detail/iterators/iter_impl.hpp +++ b/develop/detail/iterators/iter_impl.hpp @@ -1,5 +1,4 @@ -#ifndef NLOHMANN_JSON_DETAIL_ITERATORS_ITER_IMPL_HPP -#define NLOHMANN_JSON_DETAIL_ITERATORS_ITER_IMPL_HPP +#pragma once #include // not #include // iterator, random_access_iterator_tag, bidirectional_iterator_tag, advance, next @@ -613,5 +612,3 @@ class iter_impl }; } } - -#endif diff --git a/develop/detail/iterators/iteration_proxy.hpp b/develop/detail/iterators/iteration_proxy.hpp index e4ce84e4..296101c8 100644 --- a/develop/detail/iterators/iteration_proxy.hpp +++ b/develop/detail/iterators/iteration_proxy.hpp @@ -1,5 +1,4 @@ -#ifndef NLOHMANN_JSON_DETAIL_ITERATORS_ITERATION_PROXY_HPP -#define NLOHMANN_JSON_DETAIL_ITERATORS_ITERATION_PROXY_HPP +#pragma once #include // size_t #include // string, to_string @@ -97,5 +96,3 @@ template class iteration_proxy }; } } - -#endif diff --git a/develop/detail/iterators/json_reverse_iterator.hpp b/develop/detail/iterators/json_reverse_iterator.hpp index b0f4effe..06448191 100644 --- a/develop/detail/iterators/json_reverse_iterator.hpp +++ b/develop/detail/iterators/json_reverse_iterator.hpp @@ -1,5 +1,4 @@ -#ifndef NLOHMANN_JSON_DETAIL_ITERATORS_JSON_REVERSE_ITERATOR_HPP -#define NLOHMANN_JSON_DETAIL_ITERATORS_JSON_REVERSE_ITERATOR_HPP +#pragma once #include // ptrdiff_t #include // reverse_iterator @@ -118,5 +117,3 @@ class json_reverse_iterator : public std::reverse_iterator }; } } - -#endif diff --git a/develop/detail/iterators/primitive_iterator.hpp b/develop/detail/iterators/primitive_iterator.hpp index c5cd4031..fd2a00cb 100644 --- a/develop/detail/iterators/primitive_iterator.hpp +++ b/develop/detail/iterators/primitive_iterator.hpp @@ -1,5 +1,4 @@ -#ifndef NLOHMANN_JSON_DETAIL_ITERATORS_PRIMITIVE_ITERATOR_HPP -#define NLOHMANN_JSON_DETAIL_ITERATORS_PRIMITIVE_ITERATOR_HPP +#pragma once #include // not #include // ptrdiff_t @@ -127,5 +126,3 @@ class primitive_iterator_t }; } } - -#endif diff --git a/develop/detail/json_ref.hpp b/develop/detail/json_ref.hpp index ec120c02..8285be22 100644 --- a/develop/detail/json_ref.hpp +++ b/develop/detail/json_ref.hpp @@ -1,5 +1,4 @@ -#ifndef NLOHMANN_JSON_DETAIL_JSON_REF_HPP -#define NLOHMANN_JSON_DETAIL_JSON_REF_HPP +#pragma once #include #include @@ -62,5 +61,3 @@ class json_ref }; } } - -#endif diff --git a/develop/detail/macro_scope.hpp b/develop/detail/macro_scope.hpp index f20cc667..f8936025 100644 --- a/develop/detail/macro_scope.hpp +++ b/develop/detail/macro_scope.hpp @@ -1,5 +1,4 @@ -#ifndef NLOHMANN_JSON_MACRO_SCOPE_HPP -#define NLOHMANN_JSON_MACRO_SCOPE_HPP +#pragma once #include // not @@ -102,5 +101,3 @@ contains a `mapped_type`, whereas `std::vector` fails the test. static constexpr bool value = \ std::is_integral()))>::value; \ } - -#endif diff --git a/develop/detail/macro_unscope.hpp b/develop/detail/macro_unscope.hpp index 9b8cf7b9..99a0abdf 100644 --- a/develop/detail/macro_unscope.hpp +++ b/develop/detail/macro_unscope.hpp @@ -1,5 +1,4 @@ -#ifndef NLOHMANN_JSON_DETAIL_MACRO_UNSCOPE_HPP -#define NLOHMANN_JSON_DETAIL_MACRO_UNSCOPE_HPP +#pragma once // restore GCC/clang diagnostic settings #if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) @@ -21,5 +20,3 @@ #undef NLOHMANN_BASIC_JSON_TPL_DECLARATION #undef NLOHMANN_BASIC_JSON_TPL #undef NLOHMANN_JSON_HAS_HELPER - -#endif diff --git a/develop/detail/meta.hpp b/develop/detail/meta.hpp index 35705183..bea42a07 100644 --- a/develop/detail/meta.hpp +++ b/develop/detail/meta.hpp @@ -1,5 +1,4 @@ -#ifndef NLOHMANN_JSON_DETAIL_META_HPP -#define NLOHMANN_JSON_DETAIL_META_HPP +#pragma once #include // not #include // size_t @@ -233,5 +232,3 @@ template constexpr T static_const::value; } } - -#endif diff --git a/develop/detail/parsing/binary_reader.hpp b/develop/detail/parsing/binary_reader.hpp index a1195393..bacf3d46 100644 --- a/develop/detail/parsing/binary_reader.hpp +++ b/develop/detail/parsing/binary_reader.hpp @@ -1,5 +1,4 @@ -#ifndef NLOHMANN_JSON_DETAIL_PARSING_BINARY_READER_HPP -#define NLOHMANN_JSON_DETAIL_PARSING_BINARY_READER_HPP +#pragma once #include // generate_n #include // array @@ -1089,5 +1088,3 @@ class binary_reader }; } } - -#endif diff --git a/develop/detail/parsing/binary_writer.hpp b/develop/detail/parsing/binary_writer.hpp index 59583b9c..68034fc7 100644 --- a/develop/detail/parsing/binary_writer.hpp +++ b/develop/detail/parsing/binary_writer.hpp @@ -1,5 +1,4 @@ -#ifndef NLOHMANN_JSON_DETAIL_PARSING_BINARY_WRITER_HPP -#define NLOHMANN_JSON_DETAIL_PARSING_BINARY_WRITER_HPP +#pragma once #include // reverse #include // array @@ -554,5 +553,3 @@ class binary_writer }; } } - -#endif diff --git a/develop/detail/parsing/input_adapters.hpp b/develop/detail/parsing/input_adapters.hpp index 7d4f2dee..abbf5d29 100644 --- a/develop/detail/parsing/input_adapters.hpp +++ b/develop/detail/parsing/input_adapters.hpp @@ -1,5 +1,4 @@ -#ifndef NLOHMANN_JSON_DETAIL_PARSING_INPUT_ADAPTERS_HPP -#define NLOHMANN_JSON_DETAIL_PARSING_INPUT_ADAPTERS_HPP +#pragma once #include // min #include // array @@ -261,5 +260,3 @@ class input_adapter }; } } - -#endif diff --git a/develop/detail/parsing/lexer.hpp b/develop/detail/parsing/lexer.hpp index f50b0521..de222a6c 100644 --- a/develop/detail/parsing/lexer.hpp +++ b/develop/detail/parsing/lexer.hpp @@ -1,5 +1,4 @@ -#ifndef NLOHMANN_JSON_DETAIL_PARSING_LEXER_HPP -#define NLOHMANN_JSON_DETAIL_PARSING_LEXER_HPP +#pragma once #include // localeconv #include // size_t @@ -1275,5 +1274,3 @@ scan_number_done: }; } } - -#endif diff --git a/develop/detail/parsing/output_adapters.hpp b/develop/detail/parsing/output_adapters.hpp index 71099038..fe9e1b36 100644 --- a/develop/detail/parsing/output_adapters.hpp +++ b/develop/detail/parsing/output_adapters.hpp @@ -1,5 +1,4 @@ -#ifndef NLOHMANN_JSON_DETAIL_PARSING_OUTPUT_ADAPTERS_HPP -#define NLOHMANN_JSON_DETAIL_PARSING_OUTPUT_ADAPTERS_HPP +#pragma once #include // copy #include // size_t @@ -112,5 +111,3 @@ class output_adapter }; } } - -#endif diff --git a/develop/detail/parsing/parser.hpp b/develop/detail/parsing/parser.hpp index 52a9c4fe..b0322204 100644 --- a/develop/detail/parsing/parser.hpp +++ b/develop/detail/parsing/parser.hpp @@ -1,5 +1,4 @@ -#ifndef NLOHMANN_JSON_DETAIL_PARSING_PARSER_HPP -#define NLOHMANN_JSON_DETAIL_PARSING_PARSER_HPP +#pragma once #include // assert #include // isfinite @@ -588,5 +587,3 @@ class parser }; } } - -#endif diff --git a/develop/detail/serializer.hpp b/develop/detail/serializer.hpp index 0d3303d9..b5f2b06a 100644 --- a/develop/detail/serializer.hpp +++ b/develop/detail/serializer.hpp @@ -1,5 +1,4 @@ -#ifndef NLOHMANN_JSON_DETAIL_SERIALIZER_HPP -#define NLOHMANN_JSON_DETAIL_SERIALIZER_HPP +#pragma once #include // reverse, remove, fill, find, none_of #include // array @@ -793,5 +792,3 @@ class serializer }; } } - -#endif diff --git a/develop/detail/value_t.hpp b/develop/detail/value_t.hpp index b96f294b..326367c4 100644 --- a/develop/detail/value_t.hpp +++ b/develop/detail/value_t.hpp @@ -1,5 +1,4 @@ -#ifndef NLOHMANN_JSON_DETAIL_VALUE_T_HPP -#define NLOHMANN_JSON_DETAIL_VALUE_T_HPP +#pragma once #include // array #include // and @@ -75,5 +74,3 @@ inline bool operator<(const value_t lhs, const value_t rhs) noexcept } } } - -#endif diff --git a/src/json.hpp b/src/json.hpp index cc43f5b5..a80cc36a 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -107,8 +107,7 @@ using json = basic_json<>; #endif // #include "detail/macro_scope.hpp" -#ifndef NLOHMANN_JSON_MACRO_SCOPE_HPP -#define NLOHMANN_JSON_MACRO_SCOPE_HPP + #include // not @@ -212,11 +211,8 @@ contains a `mapped_type`, whereas `std::vector` fails the test. std::is_integral()))>::value; \ } -#endif - // #include "detail/meta.hpp" -#ifndef NLOHMANN_JSON_DETAIL_META_HPP -#define NLOHMANN_JSON_DETAIL_META_HPP + #include // not #include // size_t @@ -453,8 +449,6 @@ constexpr T static_const::value; } } -#endif - // #include "detail/exceptions.hpp" #ifndef NLOHMANN_JSON_DETAIL_EXCEPTIONS_HPP #define NLOHMANN_JSON_DETAIL_EXCEPTIONS_HPP @@ -789,8 +783,7 @@ class other_error : public exception #endif // #include "detail/value_t.hpp" -#ifndef NLOHMANN_JSON_DETAIL_VALUE_T_HPP -#define NLOHMANN_JSON_DETAIL_VALUE_T_HPP + #include // array #include // and @@ -867,11 +860,8 @@ inline bool operator<(const value_t lhs, const value_t rhs) noexcept } } -#endif - // #include "detail/conversions/from_json.hpp" -#ifndef NLOHMANN_JSON_DETAIL_CONVERSIONS_FROM_JSON_HPP -#define NLOHMANN_JSON_DETAIL_CONVERSIONS_FROM_JSON_HPP + #include // transform #include // array @@ -1191,11 +1181,8 @@ constexpr const auto& from_json = detail::static_const::va } } -#endif - // #include "detail/conversions/to_json.hpp" -#ifndef NLOHMANN_JSON_DETAIL_CONVERSIONS_TO_JSON_HPP -#define NLOHMANN_JSON_DETAIL_CONVERSIONS_TO_JSON_HPP + #include // or, and, not #include // begin, end @@ -1536,11 +1523,8 @@ constexpr const auto& to_json = detail::static_const::value; } } -#endif - // #include "detail/parsing/input_adapters.hpp" -#ifndef NLOHMANN_JSON_DETAIL_PARSING_INPUT_ADAPTERS_HPP -#define NLOHMANN_JSON_DETAIL_PARSING_INPUT_ADAPTERS_HPP + #include // min #include // array @@ -1804,11 +1788,8 @@ class input_adapter } } -#endif - // #include "detail/parsing/lexer.hpp" -#ifndef NLOHMANN_JSON_DETAIL_PARSING_LEXER_HPP -#define NLOHMANN_JSON_DETAIL_PARSING_LEXER_HPP + #include // localeconv #include // size_t @@ -3087,11 +3068,8 @@ scan_number_done: } } -#endif - // #include "detail/parsing/parser.hpp" -#ifndef NLOHMANN_JSON_DETAIL_PARSING_PARSER_HPP -#define NLOHMANN_JSON_DETAIL_PARSING_PARSER_HPP + #include // assert #include // isfinite @@ -3686,11 +3664,8 @@ class parser } } -#endif - // #include "detail/iterators/primitive_iterator.hpp" -#ifndef NLOHMANN_JSON_DETAIL_ITERATORS_PRIMITIVE_ITERATOR_HPP -#define NLOHMANN_JSON_DETAIL_ITERATORS_PRIMITIVE_ITERATOR_HPP + #include // not #include // ptrdiff_t @@ -3819,11 +3794,8 @@ class primitive_iterator_t } } -#endif - // #include "detail/iterators/internal_iterator.hpp" -#ifndef NLOHMANN_JSON_DETAIL_ITERATORS_INTERNAL_ITERATOR_HPP -#define NLOHMANN_JSON_DETAIL_ITERATORS_INTERNAL_ITERATOR_HPP + // #include "detail/iterators/primitive_iterator.hpp" @@ -3850,11 +3822,8 @@ template struct internal_iterator } } -#endif - // #include "detail/iterators/iter_impl.hpp" -#ifndef NLOHMANN_JSON_DETAIL_ITERATORS_ITER_IMPL_HPP -#define NLOHMANN_JSON_DETAIL_ITERATORS_ITER_IMPL_HPP + #include // not #include // iterator, random_access_iterator_tag, bidirectional_iterator_tag, advance, next @@ -4475,11 +4444,8 @@ class iter_impl } } -#endif - // #include "detail/iterators/iteration_proxy.hpp" -#ifndef NLOHMANN_JSON_DETAIL_ITERATORS_ITERATION_PROXY_HPP -#define NLOHMANN_JSON_DETAIL_ITERATORS_ITERATION_PROXY_HPP + #include // size_t #include // string, to_string @@ -4579,11 +4545,8 @@ template class iteration_proxy } } -#endif - // #include "detail/iterators/json_reverse_iterator.hpp" -#ifndef NLOHMANN_JSON_DETAIL_ITERATORS_JSON_REVERSE_ITERATOR_HPP -#define NLOHMANN_JSON_DETAIL_ITERATORS_JSON_REVERSE_ITERATOR_HPP + #include // ptrdiff_t #include // reverse_iterator @@ -4703,11 +4666,8 @@ class json_reverse_iterator : public std::reverse_iterator } } -#endif - // #include "detail/parsing/output_adapters.hpp" -#ifndef NLOHMANN_JSON_DETAIL_PARSING_OUTPUT_ADAPTERS_HPP -#define NLOHMANN_JSON_DETAIL_PARSING_OUTPUT_ADAPTERS_HPP + #include // copy #include // size_t @@ -4821,11 +4781,8 @@ class output_adapter } } -#endif - // #include "detail/parsing/binary_reader.hpp" -#ifndef NLOHMANN_JSON_DETAIL_PARSING_BINARY_READER_HPP -#define NLOHMANN_JSON_DETAIL_PARSING_BINARY_READER_HPP + #include // generate_n #include // array @@ -5920,11 +5877,8 @@ class binary_reader } } -#endif - // #include "detail/parsing/binary_writer.hpp" -#ifndef NLOHMANN_JSON_DETAIL_PARSING_BINARY_WRITER_HPP -#define NLOHMANN_JSON_DETAIL_PARSING_BINARY_WRITER_HPP + #include // reverse #include // array @@ -6482,11 +6436,8 @@ class binary_writer } } -#endif - // #include "detail/serializer.hpp" -#ifndef NLOHMANN_JSON_DETAIL_SERIALIZER_HPP -#define NLOHMANN_JSON_DETAIL_SERIALIZER_HPP + #include // reverse, remove, fill, find, none_of #include // array @@ -7285,11 +7236,8 @@ class serializer } } -#endif - // #include "detail/json_ref.hpp" -#ifndef NLOHMANN_JSON_DETAIL_JSON_REF_HPP -#define NLOHMANN_JSON_DETAIL_JSON_REF_HPP + #include #include @@ -7353,11 +7301,8 @@ class json_ref } } -#endif - // #include "adl_serializer.hpp" -#ifndef NLOHMANN_JSON_ADL_SERIALIZER_HPP -#define NLOHMANN_JSON_ADL_SERIALIZER_HPP + #include @@ -7405,8 +7350,6 @@ struct adl_serializer }; } -#endif - /*! @brief namespace for Niels Lohmann @@ -15365,31 +15308,28 @@ inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std } // #include "detail/macro_unscope.hpp" -#ifndef NLOHMANN_JSON_DETAIL_MACRO_UNSCOPE_HPP - #define NLOHMANN_JSON_DETAIL_MACRO_UNSCOPE_HPP - // restore GCC/clang diagnostic settings - #if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) - #pragma GCC diagnostic pop - #endif - #if defined(__clang__) - #pragma GCC diagnostic pop - #endif - - // clean up - #undef JSON_CATCH - #undef JSON_THROW - #undef JSON_TRY - #undef JSON_LIKELY - #undef JSON_UNLIKELY - #undef JSON_DEPRECATED - #undef JSON_HAS_CPP_14 - #undef JSON_HAS_CPP_17 - #undef NLOHMANN_BASIC_JSON_TPL_DECLARATION - #undef NLOHMANN_BASIC_JSON_TPL - #undef NLOHMANN_JSON_HAS_HELPER +// restore GCC/clang diagnostic settings +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #pragma GCC diagnostic pop #endif +#if defined(__clang__) + #pragma GCC diagnostic pop +#endif + +// clean up +#undef JSON_CATCH +#undef JSON_THROW +#undef JSON_TRY +#undef JSON_LIKELY +#undef JSON_UNLIKELY +#undef JSON_DEPRECATED +#undef JSON_HAS_CPP_14 +#undef JSON_HAS_CPP_17 +#undef NLOHMANN_BASIC_JSON_TPL_DECLARATION +#undef NLOHMANN_BASIC_JSON_TPL +#undef NLOHMANN_JSON_HAS_HELPER #endif From f4a55f26b0867fab39b6fc7eca13b9ee6fb35702 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sat, 13 Jan 2018 10:59:49 +0100 Subject: [PATCH 57/59] :heavy_plus_sign: added amalgamate Python script --- .gitignore | 2 - develop/amalgamate/LICENSE.md | 27 +++ develop/amalgamate/README.md | 66 +++++++ develop/amalgamate/amalgamate.py | 295 +++++++++++++++++++++++++++++++ develop/amalgamate/config.json | 8 + 5 files changed, 396 insertions(+), 2 deletions(-) create mode 100644 develop/amalgamate/LICENSE.md create mode 100644 develop/amalgamate/README.md create mode 100755 develop/amalgamate/amalgamate.py create mode 100644 develop/amalgamate/config.json diff --git a/.gitignore b/.gitignore index bfd2e6ee..92ea2903 100644 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,4 @@ benchmarks/files/numbers/*.json cmake-build-debug test/test-* -amalgamate -single_include third_party/Amalgamate diff --git a/develop/amalgamate/LICENSE.md b/develop/amalgamate/LICENSE.md new file mode 100644 index 00000000..7fe9cf08 --- /dev/null +++ b/develop/amalgamate/LICENSE.md @@ -0,0 +1,27 @@ +amalgamate.py - Amalgamate C source and header files +Copyright (c) 2012, Erik Edlund + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of Erik Edlund, nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/develop/amalgamate/README.md b/develop/amalgamate/README.md new file mode 100644 index 00000000..975ca0bd --- /dev/null +++ b/develop/amalgamate/README.md @@ -0,0 +1,66 @@ + +# amalgamate.py - Amalgamate C source and header files + +Origin: https://bitbucket.org/erikedlund/amalgamate + +Mirror: https://github.com/edlund/amalgamate + +`amalgamate.py` aims to make it easy to use SQLite-style C source and header +amalgamation in projects. + +For more information, please refer to: http://sqlite.org/amalgamation.html + +## Here be dragons + +`amalgamate.py` is quite dumb, it only knows the bare minimum about C code +required in order to be able to handle trivial include directives. It can +produce weird results for unexpected code. + +Things to be aware of: + +`amalgamate.py` will not handle complex include directives correctly: + + #define HEADER_PATH "path/to/header.h" + #include HEADER_PATH + +In the above example, `path/to/header.h` will not be included in the +amalgamation (HEADER_PATH is never expanded). + +`amalgamate.py` makes the assumption that each source and header file which +is not empty will end in a new-line character, which is not immediately +preceded by a backslash character (see 5.1.1.2p1.2 of ISO C99). + +`amalgamate.py` should be usable with C++ code, but raw string literals from +C++11 will definitely cause problems: + + R"delimiter(Terrible raw \ data " #include )delimiter" + R"delimiter(Terrible raw \ data " escaping)delimiter" + +In the examples above, `amalgamate.py` will stop parsing the raw string literal +when it encounters the first quotation mark, which will produce unexpected +results. + +## Installing amalgamate.py + +Python v.2.7.0 or higher is required. + +`amalgamate.py` can be tested and installed using the following commands: + + ./test.sh && sudo -k cp ./amalgamate.py /usr/local/bin/ + +## Using amalgamate.py + + amalgamate.py [-v] -c path/to/config.json -s path/to/source/dir \ + [-p path/to/prologue.(c|h)] + + * The `-c, --config` option should specify the path to a JSON config file which + lists the source files, include paths and where to write the resulting + amalgamation. Have a look at `test/source.c.json` and `test/include.h.json` + to see two examples. + + * The `-s, --source` option should specify the path to the source directory. + This is useful for supporting separate source and build directories. + + * The `-p, --prologue` option should specify the path to a file which will be + added to the beginning of the amalgamation. It is optional. + diff --git a/develop/amalgamate/amalgamate.py b/develop/amalgamate/amalgamate.py new file mode 100755 index 00000000..b03069fd --- /dev/null +++ b/develop/amalgamate/amalgamate.py @@ -0,0 +1,295 @@ +#!/usr/bin/env python + +# amalgamate.py - Amalgamate C source and header files. +# Copyright (c) 2012, Erik Edlund +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of Erik Edlund, nor the names of its contributors may +# be used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +from __future__ import division +from __future__ import print_function +from __future__ import unicode_literals + +import argparse +import datetime +import json +import os +import re +import sys + +class Amalgamation(object): + + # Prepends self.source_path to file_path if needed. + def actual_path(self, file_path): + if not os.path.isabs(file_path): + file_path = os.path.join(self.source_path, file_path) + return file_path + + # Search included file_path in self.include_paths and + # in source_dir if specified. + def find_included_file(self, file_path, source_dir): + search_dirs = self.include_paths[:] + if source_dir: + search_dirs.insert(0, source_dir) + + for search_dir in search_dirs: + search_path = os.path.join(search_dir, file_path) + if os.path.isfile(self.actual_path(search_path)): + return search_path + return None + + def __init__(self, args): + with open(args.config, 'r') as f: + config = json.loads(f.read()) + for key in config: + setattr(self, key, config[key]) + + self.verbose = args.verbose == "yes" + self.prologue = args.prologue + self.source_path = args.source_path + self.included_files = [] + + # Generate the amalgamation and write it to the target file. + def generate(self): + amalgamation = "" + + if self.prologue: + with open(self.prologue, 'r') as f: + amalgamation += datetime.datetime.now().strftime(f.read()) + + if self.verbose: + print("Config:") + print(" target = {0}".format(self.target)) + print(" working_dir = {0}".format(os.getcwd())) + print(" include_paths = {0}".format(self.include_paths)) + print("Creating amalgamation:") + for file_path in self.sources: + # Do not check the include paths while processing the source + # list, all given source paths must be correct. + actual_path = self.actual_path(file_path) + print(" - processing \"{0}\"".format(file_path)) + t = TranslationUnit(file_path, self, True) + amalgamation += t.content + + with open(self.target, 'w') as f: + f.write(amalgamation) + + print("...done!\n") + if self.verbose: + print("Files processed: {0}".format(self.sources)) + print("Files included: {0}".format(self.included_files)) + print("") + +class TranslationUnit(object): + + # // C++ comment. + cpp_comment_pattern = re.compile(r"//.*?\n") + + # /* C comment. */ + c_comment_pattern = re.compile(r"/\*.*?\*/", re.S) + + # "complex \"stri\\\ng\" value". + string_pattern = re.compile("[^']" r'".*?(?<=[^\\])"', re.S) + + # Handle simple include directives. Support for advanced + # directives where macros and defines needs to expanded is + # not a concern right now. + include_pattern = re.compile( + r'#\s*include\s+(<|")(?P.*?)("|>)', re.S) + + # #pragma once + pragma_once_pattern = re.compile(r'#\s*pragma\s+once', re.S) + + # Search for pattern in self.content, add the match to + # contexts if found and update the index accordingly. + def _search_content(self, index, pattern, contexts): + match = pattern.search(self.content, index) + if match: + contexts.append(match) + return match.end() + return index + 2 + + # Return all the skippable contexts, i.e., comments and strings + def _find_skippable_contexts(self): + # Find contexts in the content in which a found include + # directive should not be processed. + skippable_contexts = [] + + # Walk through the content char by char, and try to grab + # skippable contexts using regular expressions when found. + i = 1 + content_len = len(self.content) + while i < content_len: + j = i - 1 + current = self.content[i] + previous = self.content[j] + + if current == '"': + # String value. + i = self._search_content(j, self.string_pattern, + skippable_contexts) + elif current == '*' and previous == '/': + # C style comment. + i = self._search_content(j, self.c_comment_pattern, + skippable_contexts) + elif current == '/' and previous == '/': + # C++ style comment. + i = self._search_content(j, self.cpp_comment_pattern, + skippable_contexts) + else: + # Skip to the next char. + i += 1 + + return skippable_contexts + + # Returns True if the match is within list of other matches + def _is_within(self, match, matches): + for m in matches: + if match.start() > m.start() and \ + match.end() < m.end(): + return True + return False + + # Removes pragma once from content + def _process_pragma_once(self): + content_len = len(self.content) + if content_len < len("#include "): + return 0 + + # Find contexts in the content in which a found include + # directive should not be processed. + skippable_contexts = self._find_skippable_contexts() + + pragmas = [] + pragma_once_match = self.pragma_once_pattern.search(self.content) + while pragma_once_match: + if not self._is_within(pragma_once_match, skippable_contexts): + pragmas.append(pragma_once_match) + + pragma_once_match = self.pragma_once_pattern.search(self.content, + pragma_once_match.end()) + + # Handle all collected pragma once directives. + prev_end = 0 + tmp_content = '' + for pragma_match in pragmas: + tmp_content += self.content[prev_end:pragma_match.start()] + prev_end = pragma_match.end() + tmp_content += self.content[prev_end:] + self.content = tmp_content + + # Include all trivial #include directives into self.content. + def _process_includes(self): + content_len = len(self.content) + if content_len < len("#include "): + return 0 + + # Find contexts in the content in which a found include + # directive should not be processed. + skippable_contexts = self._find_skippable_contexts() + + # Search for include directives in the content, collect those + # which should be included into the content. + includes = [] + include_match = self.include_pattern.search(self.content) + while include_match: + if not self._is_within(include_match, skippable_contexts): + include_path = include_match.group("path") + search_same_dir = include_match.group(1) == '"' + found_included_path = self.amalgamation.find_included_file( + include_path, self.file_dir if search_same_dir else None) + if found_included_path: + includes.append((include_match, found_included_path)) + + include_match = self.include_pattern.search(self.content, + include_match.end()) + + # Handle all collected include directives. + prev_end = 0 + tmp_content = '' + for include in includes: + include_match, found_included_path = include + tmp_content += self.content[prev_end:include_match.start()] + tmp_content += "// {0}\n".format(include_match.group(0)) + if not found_included_path in self.amalgamation.included_files: + t = TranslationUnit(found_included_path, self.amalgamation, False) + tmp_content += t.content + prev_end = include_match.end() + tmp_content += self.content[prev_end:] + self.content = tmp_content + + return len(includes) + + # Make all content processing + def _process(self): + if not self.is_root: + self._process_pragma_once() + self._process_includes() + + def __init__(self, file_path, amalgamation, is_root): + self.file_path = file_path + self.file_dir = os.path.dirname(file_path) + self.amalgamation = amalgamation + self.is_root = is_root + + self.amalgamation.included_files.append(self.file_path) + + actual_path = self.amalgamation.actual_path(file_path) + if not os.path.isfile(actual_path): + raise IOError("File not found: \"{0}\"".format(file_path)) + with open(actual_path, 'r') as f: + self.content = f.read() + self._process() + +def main(): + description = "Amalgamate C source and header files." + usage = " ".join([ + "amalgamate.py", + "[-v]", + "-c path/to/config.json", + "-s path/to/source/dir", + "[-p path/to/prologue.(c|h)]" + ]) + argsparser = argparse.ArgumentParser( + description=description, usage=usage) + + argsparser.add_argument("-v", "--verbose", dest="verbose", + choices=["yes", "no"], metavar="", help="be verbose") + + argsparser.add_argument("-c", "--config", dest="config", + required=True, metavar="", help="path to a JSON config file") + + argsparser.add_argument("-s", "--source", dest="source_path", + required=True, metavar="", help="source code path") + + argsparser.add_argument("-p", "--prologue", dest="prologue", + required=False, metavar="", help="path to a C prologue file") + + amalgamation = Amalgamation(argsparser.parse_args()) + amalgamation.generate() + +if __name__ == "__main__": + main() + diff --git a/develop/amalgamate/config.json b/develop/amalgamate/config.json new file mode 100644 index 00000000..ce937e65 --- /dev/null +++ b/develop/amalgamate/config.json @@ -0,0 +1,8 @@ +{ + "project": "JSON for Modern C++", + "target": "src/json.hpp", + "sources": [ + "json.hpp" + ], + "include_paths": ["."] +} From a66b2d20c654515e22ce3dffcddb533f0740c75e Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sat, 13 Jan 2018 11:15:23 +0100 Subject: [PATCH 58/59] :rotating_light: removed linter warnings for Python code --- develop/amalgamate/CHANGES.md | 10 + develop/amalgamate/amalgamate.py | 494 ++++++++++++++++--------------- 2 files changed, 259 insertions(+), 245 deletions(-) create mode 100644 develop/amalgamate/CHANGES.md diff --git a/develop/amalgamate/CHANGES.md b/develop/amalgamate/CHANGES.md new file mode 100644 index 00000000..728b9331 --- /dev/null +++ b/develop/amalgamate/CHANGES.md @@ -0,0 +1,10 @@ +The following changes have been made to the code with respect to : + +- Resolved inspection results from PyCharm: + - replaced tabs with spaces + - added encoding annotation + - reindented file to remove trailing whitespaces + - unused import `sys` + - membership check + - made function from `_is_within` + - removed unused variable `actual_path` diff --git a/develop/amalgamate/amalgamate.py b/develop/amalgamate/amalgamate.py index b03069fd..f01b43b7 100755 --- a/develop/amalgamate/amalgamate.py +++ b/develop/amalgamate/amalgamate.py @@ -1,4 +1,5 @@ #!/usr/bin/env python +# coding=utf-8 # amalgamate.py - Amalgamate C source and header files. # Copyright (c) 2012, Erik Edlund @@ -37,259 +38,262 @@ import datetime import json import os import re -import sys + class Amalgamation(object): - - # Prepends self.source_path to file_path if needed. - def actual_path(self, file_path): - if not os.path.isabs(file_path): - file_path = os.path.join(self.source_path, file_path) - return file_path - - # Search included file_path in self.include_paths and - # in source_dir if specified. - def find_included_file(self, file_path, source_dir): - search_dirs = self.include_paths[:] - if source_dir: - search_dirs.insert(0, source_dir) - for search_dir in search_dirs: - search_path = os.path.join(search_dir, file_path) - if os.path.isfile(self.actual_path(search_path)): - return search_path - return None - - def __init__(self, args): - with open(args.config, 'r') as f: - config = json.loads(f.read()) - for key in config: - setattr(self, key, config[key]) - - self.verbose = args.verbose == "yes" - self.prologue = args.prologue - self.source_path = args.source_path - self.included_files = [] - - # Generate the amalgamation and write it to the target file. - def generate(self): - amalgamation = "" - - if self.prologue: - with open(self.prologue, 'r') as f: - amalgamation += datetime.datetime.now().strftime(f.read()) - - if self.verbose: - print("Config:") - print(" target = {0}".format(self.target)) - print(" working_dir = {0}".format(os.getcwd())) - print(" include_paths = {0}".format(self.include_paths)) - print("Creating amalgamation:") - for file_path in self.sources: - # Do not check the include paths while processing the source - # list, all given source paths must be correct. - actual_path = self.actual_path(file_path) - print(" - processing \"{0}\"".format(file_path)) - t = TranslationUnit(file_path, self, True) - amalgamation += t.content - - with open(self.target, 'w') as f: - f.write(amalgamation) - - print("...done!\n") - if self.verbose: - print("Files processed: {0}".format(self.sources)) - print("Files included: {0}".format(self.included_files)) - print("") + # Prepends self.source_path to file_path if needed. + def actual_path(self, file_path): + if not os.path.isabs(file_path): + file_path = os.path.join(self.source_path, file_path) + return file_path + + # Search included file_path in self.include_paths and + # in source_dir if specified. + def find_included_file(self, file_path, source_dir): + search_dirs = self.include_paths[:] + if source_dir: + search_dirs.insert(0, source_dir) + + for search_dir in search_dirs: + search_path = os.path.join(search_dir, file_path) + if os.path.isfile(self.actual_path(search_path)): + return search_path + return None + + def __init__(self, args): + with open(args.config, 'r') as f: + config = json.loads(f.read()) + for key in config: + setattr(self, key, config[key]) + + self.verbose = args.verbose == "yes" + self.prologue = args.prologue + self.source_path = args.source_path + self.included_files = [] + + # Generate the amalgamation and write it to the target file. + def generate(self): + amalgamation = "" + + if self.prologue: + with open(self.prologue, 'r') as f: + amalgamation += datetime.datetime.now().strftime(f.read()) + + if self.verbose: + print("Config:") + print(" target = {0}".format(self.target)) + print(" working_dir = {0}".format(os.getcwd())) + print(" include_paths = {0}".format(self.include_paths)) + print("Creating amalgamation:") + for file_path in self.sources: + # Do not check the include paths while processing the source + # list, all given source paths must be correct. + # actual_path = self.actual_path(file_path) + print(" - processing \"{0}\"".format(file_path)) + t = TranslationUnit(file_path, self, True) + amalgamation += t.content + + with open(self.target, 'w') as f: + f.write(amalgamation) + + print("...done!\n") + if self.verbose: + print("Files processed: {0}".format(self.sources)) + print("Files included: {0}".format(self.included_files)) + print("") + + +def _is_within(match, matches): + for m in matches: + if match.start() > m.start() and \ + match.end() < m.end(): + return True + return False + class TranslationUnit(object): - - # // C++ comment. - cpp_comment_pattern = re.compile(r"//.*?\n") - - # /* C comment. */ - c_comment_pattern = re.compile(r"/\*.*?\*/", re.S) - - # "complex \"stri\\\ng\" value". - string_pattern = re.compile("[^']" r'".*?(?<=[^\\])"', re.S) - - # Handle simple include directives. Support for advanced - # directives where macros and defines needs to expanded is - # not a concern right now. - include_pattern = re.compile( - r'#\s*include\s+(<|")(?P.*?)("|>)', re.S) + # // C++ comment. + cpp_comment_pattern = re.compile(r"//.*?\n") - # #pragma once - pragma_once_pattern = re.compile(r'#\s*pragma\s+once', re.S) - - # Search for pattern in self.content, add the match to - # contexts if found and update the index accordingly. - def _search_content(self, index, pattern, contexts): - match = pattern.search(self.content, index) - if match: - contexts.append(match) - return match.end() - return index + 2 - - # Return all the skippable contexts, i.e., comments and strings - def _find_skippable_contexts(self): - # Find contexts in the content in which a found include - # directive should not be processed. - skippable_contexts = [] - - # Walk through the content char by char, and try to grab - # skippable contexts using regular expressions when found. - i = 1 - content_len = len(self.content) - while i < content_len: - j = i - 1 - current = self.content[i] - previous = self.content[j] - - if current == '"': - # String value. - i = self._search_content(j, self.string_pattern, - skippable_contexts) - elif current == '*' and previous == '/': - # C style comment. - i = self._search_content(j, self.c_comment_pattern, - skippable_contexts) - elif current == '/' and previous == '/': - # C++ style comment. - i = self._search_content(j, self.cpp_comment_pattern, - skippable_contexts) - else: - # Skip to the next char. - i += 1 - - return skippable_contexts - - # Returns True if the match is within list of other matches - def _is_within(self, match, matches): - for m in matches: - if match.start() > m.start() and \ - match.end() < m.end(): - return True - return False - - # Removes pragma once from content - def _process_pragma_once(self): - content_len = len(self.content) - if content_len < len("#include "): - return 0 - - # Find contexts in the content in which a found include - # directive should not be processed. - skippable_contexts = self._find_skippable_contexts() + # /* C comment. */ + c_comment_pattern = re.compile(r"/\*.*?\*/", re.S) + + # "complex \"stri\\\ng\" value". + string_pattern = re.compile("[^']" r'".*?(?<=[^\\])"', re.S) + + # Handle simple include directives. Support for advanced + # directives where macros and defines needs to expanded is + # not a concern right now. + include_pattern = re.compile( + r'#\s*include\s+(<|")(?P.*?)("|>)', re.S) + + # #pragma once + pragma_once_pattern = re.compile(r'#\s*pragma\s+once', re.S) + + # Search for pattern in self.content, add the match to + # contexts if found and update the index accordingly. + def _search_content(self, index, pattern, contexts): + match = pattern.search(self.content, index) + if match: + contexts.append(match) + return match.end() + return index + 2 + + # Return all the skippable contexts, i.e., comments and strings + def _find_skippable_contexts(self): + # Find contexts in the content in which a found include + # directive should not be processed. + skippable_contexts = [] + + # Walk through the content char by char, and try to grab + # skippable contexts using regular expressions when found. + i = 1 + content_len = len(self.content) + while i < content_len: + j = i - 1 + current = self.content[i] + previous = self.content[j] + + if current == '"': + # String value. + i = self._search_content(j, self.string_pattern, + skippable_contexts) + elif current == '*' and previous == '/': + # C style comment. + i = self._search_content(j, self.c_comment_pattern, + skippable_contexts) + elif current == '/' and previous == '/': + # C++ style comment. + i = self._search_content(j, self.cpp_comment_pattern, + skippable_contexts) + else: + # Skip to the next char. + i += 1 + + return skippable_contexts + + # Returns True if the match is within list of other matches + + # Removes pragma once from content + def _process_pragma_once(self): + content_len = len(self.content) + if content_len < len("#include "): + return 0 + + # Find contexts in the content in which a found include + # directive should not be processed. + skippable_contexts = self._find_skippable_contexts() + + pragmas = [] + pragma_once_match = self.pragma_once_pattern.search(self.content) + while pragma_once_match: + if not _is_within(pragma_once_match, skippable_contexts): + pragmas.append(pragma_once_match) + + pragma_once_match = self.pragma_once_pattern.search(self.content, + pragma_once_match.end()) + + # Handle all collected pragma once directives. + prev_end = 0 + tmp_content = '' + for pragma_match in pragmas: + tmp_content += self.content[prev_end:pragma_match.start()] + prev_end = pragma_match.end() + tmp_content += self.content[prev_end:] + self.content = tmp_content + + # Include all trivial #include directives into self.content. + def _process_includes(self): + content_len = len(self.content) + if content_len < len("#include "): + return 0 + + # Find contexts in the content in which a found include + # directive should not be processed. + skippable_contexts = self._find_skippable_contexts() + + # Search for include directives in the content, collect those + # which should be included into the content. + includes = [] + include_match = self.include_pattern.search(self.content) + while include_match: + if not _is_within(include_match, skippable_contexts): + include_path = include_match.group("path") + search_same_dir = include_match.group(1) == '"' + found_included_path = self.amalgamation.find_included_file( + include_path, self.file_dir if search_same_dir else None) + if found_included_path: + includes.append((include_match, found_included_path)) + + include_match = self.include_pattern.search(self.content, + include_match.end()) + + # Handle all collected include directives. + prev_end = 0 + tmp_content = '' + for include in includes: + include_match, found_included_path = include + tmp_content += self.content[prev_end:include_match.start()] + tmp_content += "// {0}\n".format(include_match.group(0)) + if found_included_path not in self.amalgamation.included_files: + t = TranslationUnit(found_included_path, self.amalgamation, False) + tmp_content += t.content + prev_end = include_match.end() + tmp_content += self.content[prev_end:] + self.content = tmp_content + + return len(includes) + + # Make all content processing + def _process(self): + if not self.is_root: + self._process_pragma_once() + self._process_includes() + + def __init__(self, file_path, amalgamation, is_root): + self.file_path = file_path + self.file_dir = os.path.dirname(file_path) + self.amalgamation = amalgamation + self.is_root = is_root + + self.amalgamation.included_files.append(self.file_path) + + actual_path = self.amalgamation.actual_path(file_path) + if not os.path.isfile(actual_path): + raise IOError("File not found: \"{0}\"".format(file_path)) + with open(actual_path, 'r') as f: + self.content = f.read() + self._process() - pragmas = [] - pragma_once_match = self.pragma_once_pattern.search(self.content) - while pragma_once_match: - if not self._is_within(pragma_once_match, skippable_contexts): - pragmas.append(pragma_once_match) - - pragma_once_match = self.pragma_once_pattern.search(self.content, - pragma_once_match.end()) - - # Handle all collected pragma once directives. - prev_end = 0 - tmp_content = '' - for pragma_match in pragmas: - tmp_content += self.content[prev_end:pragma_match.start()] - prev_end = pragma_match.end() - tmp_content += self.content[prev_end:] - self.content = tmp_content - - # Include all trivial #include directives into self.content. - def _process_includes(self): - content_len = len(self.content) - if content_len < len("#include "): - return 0 - - # Find contexts in the content in which a found include - # directive should not be processed. - skippable_contexts = self._find_skippable_contexts() - - # Search for include directives in the content, collect those - # which should be included into the content. - includes = [] - include_match = self.include_pattern.search(self.content) - while include_match: - if not self._is_within(include_match, skippable_contexts): - include_path = include_match.group("path") - search_same_dir = include_match.group(1) == '"' - found_included_path = self.amalgamation.find_included_file( - include_path, self.file_dir if search_same_dir else None) - if found_included_path: - includes.append((include_match, found_included_path)) - - include_match = self.include_pattern.search(self.content, - include_match.end()) - - # Handle all collected include directives. - prev_end = 0 - tmp_content = '' - for include in includes: - include_match, found_included_path = include - tmp_content += self.content[prev_end:include_match.start()] - tmp_content += "// {0}\n".format(include_match.group(0)) - if not found_included_path in self.amalgamation.included_files: - t = TranslationUnit(found_included_path, self.amalgamation, False) - tmp_content += t.content - prev_end = include_match.end() - tmp_content += self.content[prev_end:] - self.content = tmp_content - - return len(includes) - - # Make all content processing - def _process(self): - if not self.is_root: - self._process_pragma_once() - self._process_includes() - - def __init__(self, file_path, amalgamation, is_root): - self.file_path = file_path - self.file_dir = os.path.dirname(file_path) - self.amalgamation = amalgamation - self.is_root = is_root - - self.amalgamation.included_files.append(self.file_path) - - actual_path = self.amalgamation.actual_path(file_path) - if not os.path.isfile(actual_path): - raise IOError("File not found: \"{0}\"".format(file_path)) - with open(actual_path, 'r') as f: - self.content = f.read() - self._process() def main(): - description = "Amalgamate C source and header files." - usage = " ".join([ - "amalgamate.py", - "[-v]", - "-c path/to/config.json", - "-s path/to/source/dir", - "[-p path/to/prologue.(c|h)]" - ]) - argsparser = argparse.ArgumentParser( - description=description, usage=usage) - - argsparser.add_argument("-v", "--verbose", dest="verbose", - choices=["yes", "no"], metavar="", help="be verbose") - - argsparser.add_argument("-c", "--config", dest="config", - required=True, metavar="", help="path to a JSON config file") - - argsparser.add_argument("-s", "--source", dest="source_path", - required=True, metavar="", help="source code path") - - argsparser.add_argument("-p", "--prologue", dest="prologue", - required=False, metavar="", help="path to a C prologue file") - - amalgamation = Amalgamation(argsparser.parse_args()) - amalgamation.generate() + description = "Amalgamate C source and header files." + usage = " ".join([ + "amalgamate.py", + "[-v]", + "-c path/to/config.json", + "-s path/to/source/dir", + "[-p path/to/prologue.(c|h)]" + ]) + argsparser = argparse.ArgumentParser( + description=description, usage=usage) + + argsparser.add_argument("-v", "--verbose", dest="verbose", + choices=["yes", "no"], metavar="", help="be verbose") + + argsparser.add_argument("-c", "--config", dest="config", + required=True, metavar="", help="path to a JSON config file") + + argsparser.add_argument("-s", "--source", dest="source_path", + required=True, metavar="", help="source code path") + + argsparser.add_argument("-p", "--prologue", dest="prologue", + required=False, metavar="", help="path to a C prologue file") + + amalgamation = Amalgamation(argsparser.parse_args()) + amalgamation.generate() + if __name__ == "__main__": - main() - + main() From 420dcf1f25db25d6a7799118a2b481fea83dfae0 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sun, 14 Jan 2018 10:10:23 +0100 Subject: [PATCH 59/59] :construction: added check whether code is amalgamated --- Makefile | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Makefile b/Makefile index 0029f849..eb179156 100644 --- a/Makefile +++ b/Makefile @@ -29,8 +29,10 @@ CXX=clang++ # main target all: + @echo "amalgamate - amalgamate file src/json.hpp from the develop sources" @echo "ChangeLog.md - generate ChangeLog file" @echo "check - compile and execute test suite" + @echo "check-amalagamation - check whether sources have been amalgamated" @echo "check-fast - compile and execute test suite (skip long-running tests)" @echo "clean - remove built files" @echo "coverage - create coverage information with lcov" @@ -255,6 +257,13 @@ src/json.hpp: $(SRCS) develop/amalgamate/amalgamate.py -c develop/amalgamate/config.json -s develop --verbose=yes $(MAKE) pretty +# check if src/json.hpp has been amalgamated from the develop sources +check-amalagamation: + @mv src/json.hpp src/json.hpp~ + @$(MAKE) amalgamate + @diff src/json.hpp src/json.hpp~ || (echo "===================================================================\n Amalgamation required! Please read the contribution guidelines\n in file .github/CONTRIBUTING.md.\n===================================================================" ; mv src/json.hpp~ src/json.hpp ; false) + @mv src/json.hpp~ src/json.hpp + ########################################################################## # changelog
    group @@ -137,18 +139,18 @@ The container functions known from STL have been extended to support the differe `at` @link nlohmann::basic_json::at(const typename object_t::key_type & key) `at` @endlink @link nlohmann::basic_json::at(size_type) `at` @endlinkthrows `std::domain_error`throws `std::domain_error`throws `std::domain_error`throws `std::domain_error`throws @link nlohmann::basic_json::type_error `json::type_error` @endlink (304)throws @link nlohmann::basic_json::type_error `json::type_error` @endlink (304)throws @link nlohmann::basic_json::type_error `json::type_error` @endlink (304)throws @link nlohmann::basic_json::type_error `json::type_error` @endlink (304)
    `operator[]` @link nlohmann::basic_json::operator[](const typename object_t::key_type &key) `operator[]` @endlink @link nlohmann::basic_json::operator[](size_type) `operator[]` @endlinkthrows `std::domain_error`throws `std::domain_error`throws `std::domain_error`throws @link nlohmann::basic_json::type_error `json::type_error` @endlink (305)throws @link nlohmann::basic_json::type_error `json::type_error` @endlink (305)throws @link nlohmann::basic_json::type_error `json::type_error` @endlink (305) @link nlohmann::basic_json::operator[](const typename object_t::key_type & key) `operator[]` @endlink (creates object)
    @link nlohmann::basic_json::operator[](size_type) `operator[]` @endlink (creates array)
    @link nlohmann::basic_json::front `front` @endlink @link nlohmann::basic_json::front `front` @endlink @link nlohmann::basic_json::front `front` @endlinkthrows `std::out_of_range`throws @link nlohmann::basic_json::invalid_iterator `json::invalid_iterator` @endlink (214)
    `back`@link nlohmann::basic_json::back `back` @endlink @link nlohmann::basic_json::back `back` @endlink @link nlohmann::basic_json::back `back` @endlinkthrows `std::out_of_range`throws @link nlohmann::basic_json::invalid_iterator `json::invalid_iterator` @endlink (214)
    capacity@link nlohmann::basic_json::max_size `max_size` @endlink (returns `0`)
    modifiersmodifiers `clear` @link nlohmann::basic_json::clear `clear` @endlink @link nlohmann::basic_json::clear `clear` @endlink
    `insert`throws `std::domain_error`throws @link nlohmann::basic_json::type_error `json::type_error` @endlink (309) @link nlohmann::basic_json::insert `insert` @endlinkthrows `std::domain_error`throws `std::domain_error`throws `std::domain_error`throws `std::domain_error`throws @link nlohmann::basic_json::type_error `json::type_error` @endlink (309)throws @link nlohmann::basic_json::type_error `json::type_error` @endlink (309)throws @link nlohmann::basic_json::type_error `json::type_error` @endlink (309)throws @link nlohmann::basic_json::type_error `json::type_error` @endlink (309)
    `erase`@link nlohmann::basic_json::erase `erase` @endlink (converts to null) @link nlohmann::basic_json::erase `erase` @endlink (converts to null) @link nlohmann::basic_json::erase `erase` @endlink (converts to null)throwsthrows @link nlohmann::basic_json::type_error `json::type_error` @endlink (307)
    `push_back` @link nlohmann::basic_json::push_back(const typename object_t::value_type & val) `push_back` @endlink @link nlohmann::basic_json::push_back(const nlohmann::basic_json &) `push_back` @endlinkthrows `std::domain_error`throws `std::domain_error`throws `std::domain_error`throws @link nlohmann::basic_json::type_error `json::type_error` @endlink (308)throws @link nlohmann::basic_json::type_error `json::type_error` @endlink (308)throws @link nlohmann::basic_json::type_error `json::type_error` @endlink (308) @link nlohmann::basic_json::push_back(const typename object_t::value_type & val) `push_back` @endlink (creates object)
    @link nlohmann::basic_json::push_back(const nlohmann::basic_json &) `push_back` @endlink (creates array)
    `emplace` / `emplace_back` @link nlohmann::basic_json::emplace() `emplace` @endlink @link nlohmann::basic_json::emplace_back() `emplace_back` @endlinkthrows `std::domain_error`throws `std::domain_error`throws `std::domain_error`throws @link nlohmann::basic_json::type_error `json::type_error` @endlink (311)throws @link nlohmann::basic_json::type_error `json::type_error` @endlink (311)throws @link nlohmann::basic_json::type_error `json::type_error` @endlink (311) @link nlohmann::basic_json::emplace() `emplace` @endlink (creates object)
    @link nlohmann::basic_json::emplace_back() `emplace_back` @endlink (creates array)
    `update`@link nlohmann::basic_json::update() `update` @endlinkthrows @link nlohmann::basic_json::type_error `json::type_error` @endlink (312)throws @link nlohmann::basic_json::type_error `json::type_error` @endlink (312)throws @link nlohmann::basic_json::type_error `json::type_error` @endlink (312)throws @link nlohmann::basic_json::type_error `json::type_error` @endlink (312)throws @link nlohmann::basic_json::type_error `json::type_error` @endlink (312)
    `swap` @link nlohmann::basic_json::swap `swap` @endlink

    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