diff --git a/ChangeLog.md b/ChangeLog.md index ae9e562f9..e3a7cc07f 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -3,7 +3,24 @@ All notable changes to this project will be documented in this file. This projec ## [Unreleased](https://github.com/nlohmann/json/tree/HEAD) -[Full Changelog](https://github.com/nlohmann/json/compare/v1.1.0...HEAD) +[Full Changelog](https://github.com/nlohmann/json/compare/v2.0.1...HEAD) + +- Build error for std::int64 [\#282](https://github.com/nlohmann/json/issues/282) + +- hexify\(\) function emits conversion warning [\#270](https://github.com/nlohmann/json/issues/270) + +- let the makefile choose the correct sed [\#279](https://github.com/nlohmann/json/pull/279) ([murinicanor](https://github.com/murinicanor)) +- Update hexify to use array lookup instead of ternary \(\#270\) [\#275](https://github.com/nlohmann/json/pull/275) ([dtoma](https://github.com/dtoma)) + +## [v2.0.1](https://github.com/nlohmann/json/releases/tag/v2.0.1) (2016-06-28) +[Full Changelog](https://github.com/nlohmann/json/compare/v2.0.0...v2.0.1) + +- dump\(\) performance degradation in v2 [\#272](https://github.com/nlohmann/json/issues/272) + +- fixed a tiny typo [\#271](https://github.com/nlohmann/json/pull/271) ([thelostt](https://github.com/thelostt)) + +## [v2.0.0](https://github.com/nlohmann/json/releases/tag/v2.0.0) (2016-06-23) +[Full Changelog](https://github.com/nlohmann/json/compare/v1.1.0...v2.0.0) - concatenate objects [\#252](https://github.com/nlohmann/json/issues/252) - Unit test fails when doing a CMake out-of-tree build [\#241](https://github.com/nlohmann/json/issues/241) diff --git a/README.md b/README.md index 21ff3c593..24f6d7ab9 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -![JSON for Modern C++](https://raw.githubusercontent.com/nlohmann/json/master/doc/json.gif) +[![JSON for Modern C++](https://raw.githubusercontent.com/nlohmann/json/master/doc/json.gif)](https://github.com/nlohmann/json/releases) [![Build Status](https://travis-ci.org/nlohmann/json.svg?branch=master)](https://travis-ci.org/nlohmann/json) [![Build Status](https://ci.appveyor.com/api/projects/status/1acb366xfyg3qybk?svg=true)](https://ci.appveyor.com/project/nlohmann/json) @@ -291,7 +291,7 @@ json j_umset(c_umset); // both entries for "one" are used // maybe ["one", "two", "one", "four"] ``` -Likewise, any associative key-value containers (`std::map`, `std::multimap`, `std::unordered_map`, `std::unordered_multimap`) whose keys are can construct an `std::string` and whose values can be used to construct JSON types (see examples above) can be used to to create a JSON object. Note that in case of multimaps only one key is used in the JSON object and the value depends on the internal order of the STL container. +Likewise, any associative key-value containers (`std::map`, `std::multimap`, `std::unordered_map`, `std::unordered_multimap`) whose keys can construct an `std::string` and whose values can be used to construct JSON types (see examples above) can be used to to create a JSON object. Note that in case of multimaps only one key is used in the JSON object and the value depends on the internal order of the STL container. ```cpp std::map c_map { {"one", 1}, {"two", 2}, {"three", 3} }; @@ -323,7 +323,7 @@ json j_original = R"({ })"_json; // access members with a JSON pointer (RFC 6901) -j_original["/baz/2"_json_pointer]; +j_original["/baz/1"_json_pointer]; // "two" // a JSON patch (RFC 6902) @@ -344,8 +344,8 @@ json j_result = j_original.patch(j_patch); json::diff(j_result, j_original); // [ // { "op":" replace", "path": "/baz", "value": ["one", "two", "three"] }, -// { "op":"remove","path":"/hello" }, -// { "op":"add","path":"/foo","value":"bar" } +// { "op": "remove","path": "/hello" }, +// { "op": "add", "path": "/foo", "value": "bar" } // ] ``` @@ -390,7 +390,7 @@ Though it's 2016 already, the support for C++11 is still a bit sparse. Currently - GCC 4.9 - 6.0 (and possibly later) - Clang 3.4 - 3.9 (and possibly later) -- Microsoft Visual C++ 2015 / 14.0 (and possibly later) +- Microsoft Visual C++ 2015 / Build Tools 14.0.25123.0 (and possibly later) I would be happy to learn about other compilers/versions. @@ -483,6 +483,9 @@ I deeply appreciate the help of the following people. - [Róbert Márki](https://github.com/robertmrk) added a fix to use move iterators and improved the integration via CMake. - [Chris Kitching](https://github.com/ChrisKitching) cleaned up the CMake files. - [Tom Needham](https://github.com/06needhamt) fixed a subtle bug with MSVC 2015 which was also proposed by [Michael K.](https://github.com/Epidal). +- [Mário Feroldi](https://github.com/thelostt) fixed a small typo. +- [duncanwerner](https://github.com/duncanwerner) found a really embarrassing performance regression in the 2.0.0 release. +- [Damien](https://github.com/dtoma) fixed one of the last conversion warnings. Thanks a lot for helping out! @@ -502,7 +505,7 @@ $ make $ ./json_unit "*" =============================================================================== -All tests passed (5568715 assertions in 32 test cases) +All tests passed (5568718 assertions in 32 test cases) ``` For more information, have a look at the file [.travis.yml](https://github.com/nlohmann/json/blob/master/.travis.yml). diff --git a/doc/Makefile b/doc/Makefile index 5e5459a00..561989237 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -1,4 +1,5 @@ SRCDIR = ../src +SED:=$(shell command -v gsed || which sed) all: doxygen @@ -52,10 +53,10 @@ clean: # create Doxygen documentation doxygen: create_output create_links doxygen - gsed -i 's@< ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberFloatType, AllocatorType >@@g' html/*.html - gsed -i 's@< ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberFloatType, AllocatorType >@@g' html/*.html - gsed -i 's@< ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType >@@g' html/*.html - gsed -i 's@< ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType >@@g' html/*.html + $(SED) -i 's@< ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberFloatType, AllocatorType >@@g' html/*.html + $(SED) -i 's@< ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberFloatType, AllocatorType >@@g' html/*.html + $(SED) -i 's@< ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType >@@g' html/*.html + $(SED) -i 's@< ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType >@@g' html/*.html upload: clean doxygen check_output cd html ; ../scripts/git-update-ghpages nlohmann/json @@ -70,14 +71,14 @@ upload: clean doxygen check_output # create docset for Dash docset: create_output cp Doxyfile Doxyfile_docset - gsed -i 's/DISABLE_INDEX = NO/DISABLE_INDEX = YES/' Doxyfile_docset - gsed -i 's/SEARCHENGINE = YES/SEARCHENGINE = NO/' Doxyfile_docset - gsed -i 's@HTML_EXTRA_STYLESHEET = css/mylayout.css@HTML_EXTRA_STYLESHEET = css/mylayout_docset.css@' Doxyfile_docset + $(SED) -i 's/DISABLE_INDEX = NO/DISABLE_INDEX = YES/' Doxyfile_docset + $(SED) -i 's/SEARCHENGINE = YES/SEARCHENGINE = NO/' Doxyfile_docset + $(SED) -i 's@HTML_EXTRA_STYLESHEET = css/mylayout.css@HTML_EXTRA_STYLESHEET = css/mylayout_docset.css@' Doxyfile_docset rm -fr html *.docset doxygen Doxyfile_docset - gsed -i 's@< ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberFloatType, AllocatorType >@@g' html/*.html - gsed -i 's@< ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberFloatType, AllocatorType >@@g' html/*.html + $(SED) -i 's@< ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberFloatType, AllocatorType >@@g' html/*.html + $(SED) -i 's@< ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberFloatType, AllocatorType >@@g' html/*.html make -C html mv html/*.docset . - gsed -i 's@doxygen@json@' me.nlohmann.json.docset/Contents/Info.plist + $(SED) -i 's@doxygen@json@' me.nlohmann.json.docset/Contents/Info.plist rm -fr Doxyfile_docset html diff --git a/doc/examples/count.cpp b/doc/examples/count.cpp index a805eeb6a..b97f71dab 100644 --- a/doc/examples/count.cpp +++ b/doc/examples/count.cpp @@ -12,7 +12,6 @@ int main() auto count_three = j_object.count("three"); // print values - std::cout << std::boolalpha; std::cout << "number of elements with key \"two\": " << count_two << '\n'; std::cout << "number of elements with key \"three\": " << count_three << '\n'; } diff --git a/doc/examples/count.link b/doc/examples/count.link index 62833ff46..0893d9223 100644 --- a/doc/examples/count.link +++ b/doc/examples/count.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/src/json.hpp b/src/json.hpp index b02a1344d..fa14b0e71 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ -| | |__ | | | | | | version 2.0.0 +| | |__ | | | | | | version 2.0.1 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . @@ -36,7 +36,7 @@ SOFTWARE. #include #include #include -#include +#include #include #include #include @@ -46,6 +46,7 @@ SOFTWARE. #include #include #include +#include #include #include #include @@ -53,6 +54,19 @@ SOFTWARE. #include #include +// exclude unsupported compilers +#if defined(__clang__) + #define CLANG_VERSION (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) + #if CLANG_VERSION < 30400 + #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" + #endif +#elif defined(__GNUC__) + #define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) + #if GCC_VERSION < 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 @@ -76,7 +90,13 @@ namespace { /*! @brief Helper to determine whether there's a key_type for T. + +Thus 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 */ template struct has_mapped_type @@ -90,11 +110,18 @@ struct has_mapped_type /*! @brief helper class to create locales with decimal point + +This struct is used a default locale during the JSON serialization. JSON +requires the decimal point to be `.`, so this function overloads the +`do_decimal_point()` function to return `.`. This function is called by +float-to-string conversions to retrieve the decimal separator between integer +and fractional parts. + @sa https://github.com/nlohmann/json/issues/51#issuecomment-86869315 +@since version 2.0.0 */ -class DecimalSeparator : public std::numpunct +struct DecimalSeparator : std::numpunct { - protected: char do_decimal_point() const { return '.'; @@ -188,13 +215,8 @@ class basic_json { private: /// workaround type for MSVC - using basic_json_t = basic_json; public: @@ -207,6 +229,8 @@ class basic_json ///////////////////// /// @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 @@ -256,6 +280,8 @@ class basic_json /////////////////////////// /// @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. /// @{ /*! @@ -923,6 +949,8 @@ class basic_json ////////////////// /// @name constructors and destructors + /// Constructors of class @ref basic_json, copy/move constructor, copy + /// assignment, static functions creating objects, and the destructor. /// @{ /*! @@ -1554,22 +1582,13 @@ class basic_json bool type_deduction = true, value_t manual_type = value_t::array) { - // the initializer list could describe an object - bool is_an_object = true; - // check if each element is an array with two elements whose first // element is a string - for (const auto& element : init) + bool is_an_object = std::all_of(init.begin(), init.end(), + [](const basic_json & element) { - if (not element.is_array() or element.size() != 2 - or not element[0].is_string()) - { - // we found an element that makes it impossible to use the - // initializer list as object - is_an_object = false; - break; - } - } + return element.is_array() and element.size() == 2 and element[0].is_string(); + }); // adjust type if type deduction is not wanted if (not type_deduction) @@ -1595,10 +1614,10 @@ class basic_json assert(m_value.object != nullptr); - for (auto& element : init) + std::for_each(init.begin(), init.end(), [this](const basic_json & element) { m_value.object->emplace(*(element[0].m_value.string), element[1]); - } + }); } else { @@ -2069,19 +2088,20 @@ class basic_json /////////////////////// /// @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 @p json.dumps() function, and currently supports its @p indent + Python's `json.dumps()` function, and currently supports its @a indent parameter. - @param[in] indent if indent is nonnegative, then array elements and object + @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 + `0` will only insert newlines. `-1` (the default) selects the most compact + representation. @return string containing the serialization of the JSON value @@ -2097,6 +2117,8 @@ class basic_json string_t dump(const int indent = -1) const { std::stringstream ss; + // fix locale problems + ss.imbue(std::locale(std::locale(), new DecimalSeparator)); if (indent >= 0) { @@ -2765,6 +2787,7 @@ class basic_json public: /// @name value access + /// Direct access to the stored value of a JSON value. /// @{ /*! @@ -2815,7 +2838,8 @@ class basic_json Explicit pointer access to the internally stored JSON value. No copies are made. - @warning The pointer becomes invalid if the underlying JSON object changes. + @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, @@ -2870,7 +2894,8 @@ class basic_json @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. + @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 @@ -2890,6 +2915,21 @@ class basic_json , 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)); } @@ -2905,6 +2945,21 @@ class basic_json , 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)); } @@ -2920,7 +2975,7 @@ class basic_json @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. + @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 @@ -3010,6 +3065,7 @@ class basic_json //////////////////// /// @name element access + /// Access to the JSON value. /// @{ /*! @@ -3233,11 +3289,13 @@ class basic_json // operator[] only works for arrays if (is_array()) { - // fill up array with null values until given idx is reached + // fill up array with null values if given idx is outside range assert(m_value.array != nullptr); - for (size_t i = m_value.array->size(); i <= idx; ++i) + if (idx >= m_value.array->size()) { - m_value.array->push_back(basic_json()); + m_value.array->insert(m_value.array->end(), + idx - m_value.array->size() + 1, + basic_json()); } return m_value.array->operator[](idx); @@ -5655,9 +5713,14 @@ class basic_json // reset width to 0 for subsequent calls to this stream o.width(0); + // fix locale problems + auto old_locale = o.imbue(std::locale(std::locale(), new DecimalSeparator)); // do the actual serialization j.dump(o, pretty_print, static_cast(indentation)); + + // reset locale + o.imbue(old_locale); return o; } @@ -5794,7 +5857,7 @@ class basic_json /////////////////////////// /// return the type as string - string_t type_name() const noexcept + std::string type_name() const { switch (m_type) { @@ -5825,9 +5888,8 @@ class basic_json */ static std::size_t extra_space(const string_t& s) noexcept { - std::size_t result = 0; - - for (const auto& c : s) + return std::accumulate(s.begin(), s.end(), size_t{}, + [](size_t res, typename string_t::value_type c) { switch (c) { @@ -5840,8 +5902,7 @@ class basic_json case '\t': { // from c (1 byte) to \x (2 bytes) - result += 1; - break; + return res + 1; } default: @@ -5849,14 +5910,15 @@ class basic_json if (c >= 0x00 and c <= 0x1f) { // from c (1 byte) to \uxxxx (6 bytes) - result += 5; + return res + 5; + } + else + { + return res; } - break; } } - } - - return result; + }); } /*! @@ -5950,16 +6012,15 @@ class basic_json { // convert a number 0..15 to its hex representation // (0..f) - const auto hexify = [](const int v) -> char + static const char hexify[16] = { - return (v < 10) - ? ('0' + static_cast(v)) - : ('a' + static_cast((v - 10) & 0x1f)); + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; // print character c as \uxxxx for (const char m : - { 'u', '0', '0', hexify(c >> 4), hexify(c & 0x0f) + { 'u', '0', '0', hexify[c >> 4], hexify[c & 0x0f] }) { result[++pos] = m; @@ -6128,11 +6189,8 @@ class basic_json // string->double->string or string->long // double->string; to be safe, we read this value from // std::numeric_limits::digits10 - std::stringstream ss; - ss.imbue(std::locale(std::locale(), new DecimalSeparator)); // fix locale problems - ss << std::setprecision(std::numeric_limits::digits10) - << m_value.number_float; - o << ss.str(); + o << std::setprecision(std::numeric_limits::digits10) + << m_value.number_float; } return; } @@ -6609,13 +6667,13 @@ class basic_json { case basic_json::value_t::object: { - ++m_it.object_iterator; + std::advance(m_it.object_iterator, 1); break; } case basic_json::value_t::array: { - ++m_it.array_iterator; + std::advance(m_it.array_iterator, 1); break; } @@ -6646,13 +6704,13 @@ class basic_json { case basic_json::value_t::object: { - --m_it.object_iterator; + std::advance(m_it.object_iterator, -1); break; } case basic_json::value_t::array: { - --m_it.array_iterator; + std::advance(m_it.array_iterator, -1); break; } @@ -6764,7 +6822,7 @@ class basic_json case basic_json::value_t::array: { - m_it.array_iterator += i; + std::advance(m_it.array_iterator, i); break; } @@ -6838,7 +6896,7 @@ class basic_json case basic_json::value_t::array: { - return *(m_it.array_iterator + n); + return *std::next(m_it.array_iterator, n); } case basic_json::value_t::null: @@ -7334,400 +7392,402 @@ class basic_json */ token_type scan() noexcept { - // pointer for backtracking information - m_marker = nullptr; - - // remember the begin of the token - m_start = m_cursor; - assert(m_start != nullptr); - - + while (true) { - lexer_char_t yych; - unsigned int yyaccept = 0; - static const unsigned char yybm[] = + // pointer for backtracking information + m_marker = nullptr; + + // remember the begin of the token + m_start = m_cursor; + assert(m_start != nullptr); + + { - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 32, 32, 0, 0, 32, 0, 0, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 160, 128, 0, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 192, 192, 192, 192, 192, 192, 192, 192, - 192, 192, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 0, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - }; - if ((m_limit - m_cursor) < 5) - { - yyfill(); // LCOV_EXCL_LINE; - } - yych = *m_cursor; - if (yybm[0 + yych] & 32) - { - goto basic_json_parser_6; - } - if (yych <= '\\') - { - if (yych <= '-') + lexer_char_t yych; + unsigned int yyaccept = 0; + static const unsigned char yybm[] = { - if (yych <= '"') + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 32, 32, 0, 0, 32, 0, 0, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 160, 128, 0, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 192, 192, 192, 192, 192, 192, 192, 192, + 192, 192, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 0, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + }; + if ((m_limit - m_cursor) < 5) + { + yyfill(); // LCOV_EXCL_LINE; + } + yych = *m_cursor; + if (yybm[0 + yych] & 32) + { + goto basic_json_parser_6; + } + if (yych <= '\\') + { + if (yych <= '-') { - if (yych <= 0x00) + if (yych <= '"') { - goto basic_json_parser_2; + if (yych <= 0x00) + { + goto basic_json_parser_2; + } + if (yych <= '!') + { + goto basic_json_parser_4; + } + goto basic_json_parser_9; } - if (yych <= '!') + else { - goto basic_json_parser_4; + if (yych <= '+') + { + goto basic_json_parser_4; + } + if (yych <= ',') + { + goto basic_json_parser_10; + } + goto basic_json_parser_12; } - goto basic_json_parser_9; } else { - if (yych <= '+') + if (yych <= '9') { + if (yych <= '/') + { + goto basic_json_parser_4; + } + if (yych <= '0') + { + goto basic_json_parser_13; + } + goto basic_json_parser_15; + } + else + { + if (yych <= ':') + { + goto basic_json_parser_17; + } + if (yych == '[') + { + goto basic_json_parser_19; + } goto basic_json_parser_4; } - if (yych <= ',') - { - goto basic_json_parser_10; - } - goto basic_json_parser_12; } } else { - if (yych <= '9') + if (yych <= 't') { - if (yych <= '/') + if (yych <= 'f') { - goto basic_json_parser_4; + if (yych <= ']') + { + goto basic_json_parser_21; + } + if (yych <= 'e') + { + goto basic_json_parser_4; + } + goto basic_json_parser_23; } - if (yych <= '0') + else { - goto basic_json_parser_13; + if (yych == 'n') + { + goto basic_json_parser_24; + } + if (yych <= 's') + { + goto basic_json_parser_4; + } + goto basic_json_parser_25; } - goto basic_json_parser_15; } else { - if (yych <= ':') - { - goto basic_json_parser_17; - } - if (yych == '[') - { - goto basic_json_parser_19; - } - goto basic_json_parser_4; - } - } - } - else - { - if (yych <= 't') - { - if (yych <= 'f') - { - if (yych <= ']') - { - goto basic_json_parser_21; - } - if (yych <= 'e') + if (yych <= '|') { + if (yych == '{') + { + goto basic_json_parser_26; + } goto basic_json_parser_4; } - goto basic_json_parser_23; - } - else - { - if (yych == 'n') - { - goto basic_json_parser_24; - } - if (yych <= 's') + else { + if (yych <= '}') + { + goto basic_json_parser_28; + } + if (yych == 0xEF) + { + goto basic_json_parser_30; + } goto basic_json_parser_4; } - goto basic_json_parser_25; } } - else - { - if (yych <= '|') - { - if (yych == '{') - { - goto basic_json_parser_26; - } - goto basic_json_parser_4; - } - else - { - if (yych <= '}') - { - goto basic_json_parser_28; - } - if (yych == 0xEF) - { - goto basic_json_parser_30; - } - goto basic_json_parser_4; - } - } - } basic_json_parser_2: - ++m_cursor; - { - return token_type::end_of_input; - } + ++m_cursor; + { + last_token_type = token_type::end_of_input; + break; + } basic_json_parser_4: - ++m_cursor; + ++m_cursor; basic_json_parser_5: - { - return token_type::parse_error; - } + { + last_token_type = token_type::parse_error; + break; + } basic_json_parser_6: - ++m_cursor; - if (m_limit <= m_cursor) - { - yyfill(); // LCOV_EXCL_LINE; - } - yych = *m_cursor; - if (yybm[0 + yych] & 32) - { - goto basic_json_parser_6; - } - { - return scan(); - } + ++m_cursor; + if (m_limit <= m_cursor) + { + yyfill(); // LCOV_EXCL_LINE; + } + yych = *m_cursor; + if (yybm[0 + yych] & 32) + { + goto basic_json_parser_6; + } + { + continue; + } basic_json_parser_9: - yyaccept = 0; - yych = *(m_marker = ++m_cursor); - if (yych <= 0x0F) - { - goto basic_json_parser_5; - } - goto basic_json_parser_32; + yyaccept = 0; + yych = *(m_marker = ++m_cursor); + if (yych <= 0x0F) + { + goto basic_json_parser_5; + } + goto basic_json_parser_32; basic_json_parser_10: - ++m_cursor; - { - return token_type::value_separator; - } + ++m_cursor; + { + last_token_type = token_type::value_separator; + break; + } basic_json_parser_12: - yych = *++m_cursor; - if (yych <= '/') - { - goto basic_json_parser_5; - } - if (yych <= '0') - { - goto basic_json_parser_13; - } - if (yych <= '9') - { - goto basic_json_parser_15; - } - goto basic_json_parser_5; -basic_json_parser_13: - yyaccept = 1; - yych = *(m_marker = ++m_cursor); - if (yych <= 'D') - { - if (yych == '.') - { - goto basic_json_parser_37; - } - } - else - { - if (yych <= 'E') - { - goto basic_json_parser_38; - } - if (yych == 'e') - { - goto basic_json_parser_38; - } - } -basic_json_parser_14: - { - return token_type::value_number; - } -basic_json_parser_15: - yyaccept = 1; - m_marker = ++m_cursor; - if ((m_limit - m_cursor) < 3) - { - yyfill(); // LCOV_EXCL_LINE; - } - yych = *m_cursor; - if (yybm[0 + yych] & 64) - { - goto basic_json_parser_15; - } - if (yych <= 'D') - { - if (yych == '.') - { - goto basic_json_parser_37; - } - goto basic_json_parser_14; - } - else - { - if (yych <= 'E') - { - goto basic_json_parser_38; - } - if (yych == 'e') - { - goto basic_json_parser_38; - } - goto basic_json_parser_14; - } -basic_json_parser_17: - ++m_cursor; - { - return token_type::name_separator; - } -basic_json_parser_19: - ++m_cursor; - { - return token_type::begin_array; - } -basic_json_parser_21: - ++m_cursor; - { - return token_type::end_array; - } -basic_json_parser_23: - yyaccept = 0; - yych = *(m_marker = ++m_cursor); - if (yych == 'a') - { - goto basic_json_parser_39; - } - goto basic_json_parser_5; -basic_json_parser_24: - yyaccept = 0; - yych = *(m_marker = ++m_cursor); - if (yych == 'u') - { - goto basic_json_parser_40; - } - goto basic_json_parser_5; -basic_json_parser_25: - yyaccept = 0; - yych = *(m_marker = ++m_cursor); - if (yych == 'r') - { - goto basic_json_parser_41; - } - goto basic_json_parser_5; -basic_json_parser_26: - ++m_cursor; - { - return token_type::begin_object; - } -basic_json_parser_28: - ++m_cursor; - { - return token_type::end_object; - } -basic_json_parser_30: - yyaccept = 0; - yych = *(m_marker = ++m_cursor); - if (yych == 0xBB) - { - goto basic_json_parser_42; - } - goto basic_json_parser_5; -basic_json_parser_31: - ++m_cursor; - if (m_limit <= m_cursor) - { - yyfill(); // LCOV_EXCL_LINE; - } - yych = *m_cursor; -basic_json_parser_32: - if (yybm[0 + yych] & 128) - { - goto basic_json_parser_31; - } - if (yych <= 0x0F) - { - goto basic_json_parser_33; - } - if (yych <= '"') - { - goto basic_json_parser_34; - } - goto basic_json_parser_36; -basic_json_parser_33: - m_cursor = m_marker; - if (yyaccept == 0) - { - goto basic_json_parser_5; - } - else - { - goto basic_json_parser_14; - } -basic_json_parser_34: - ++m_cursor; - { - return token_type::value_string; - } -basic_json_parser_36: - ++m_cursor; - if (m_limit <= m_cursor) - { - yyfill(); // LCOV_EXCL_LINE; - } - yych = *m_cursor; - if (yych <= 'e') - { + yych = *++m_cursor; if (yych <= '/') { - if (yych == '"') + goto basic_json_parser_5; + } + if (yych <= '0') + { + goto basic_json_parser_13; + } + if (yych <= '9') + { + goto basic_json_parser_15; + } + goto basic_json_parser_5; +basic_json_parser_13: + yyaccept = 1; + yych = *(m_marker = ++m_cursor); + if (yych <= 'D') + { + if (yych == '.') { - goto basic_json_parser_31; + goto basic_json_parser_37; } - if (yych <= '.') - { - goto basic_json_parser_33; - } - goto basic_json_parser_31; } else { - if (yych <= '\\') + if (yych <= 'E') { - if (yych <= '[') + goto basic_json_parser_38; + } + if (yych == 'e') + { + goto basic_json_parser_38; + } + } +basic_json_parser_14: + { + last_token_type = token_type::value_number; + break; + } +basic_json_parser_15: + yyaccept = 1; + m_marker = ++m_cursor; + if ((m_limit - m_cursor) < 3) + { + yyfill(); // LCOV_EXCL_LINE; + } + yych = *m_cursor; + if (yybm[0 + yych] & 64) + { + goto basic_json_parser_15; + } + if (yych <= 'D') + { + if (yych == '.') + { + goto basic_json_parser_37; + } + goto basic_json_parser_14; + } + else + { + if (yych <= 'E') + { + goto basic_json_parser_38; + } + if (yych == 'e') + { + goto basic_json_parser_38; + } + goto basic_json_parser_14; + } +basic_json_parser_17: + ++m_cursor; + { + last_token_type = token_type::name_separator; + break; + } +basic_json_parser_19: + ++m_cursor; + { + last_token_type = token_type::begin_array; + break; + } +basic_json_parser_21: + ++m_cursor; + { + last_token_type = token_type::end_array; + break; + } +basic_json_parser_23: + yyaccept = 0; + yych = *(m_marker = ++m_cursor); + if (yych == 'a') + { + goto basic_json_parser_39; + } + goto basic_json_parser_5; +basic_json_parser_24: + yyaccept = 0; + yych = *(m_marker = ++m_cursor); + if (yych == 'u') + { + goto basic_json_parser_40; + } + goto basic_json_parser_5; +basic_json_parser_25: + yyaccept = 0; + yych = *(m_marker = ++m_cursor); + if (yych == 'r') + { + goto basic_json_parser_41; + } + goto basic_json_parser_5; +basic_json_parser_26: + ++m_cursor; + { + last_token_type = token_type::begin_object; + break; + } +basic_json_parser_28: + ++m_cursor; + { + last_token_type = token_type::end_object; + break; + } +basic_json_parser_30: + yyaccept = 0; + yych = *(m_marker = ++m_cursor); + if (yych == 0xBB) + { + goto basic_json_parser_42; + } + goto basic_json_parser_5; +basic_json_parser_31: + ++m_cursor; + if (m_limit <= m_cursor) + { + yyfill(); // LCOV_EXCL_LINE; + } + yych = *m_cursor; +basic_json_parser_32: + if (yybm[0 + yych] & 128) + { + goto basic_json_parser_31; + } + if (yych <= 0x0F) + { + goto basic_json_parser_33; + } + if (yych <= '"') + { + goto basic_json_parser_34; + } + goto basic_json_parser_36; +basic_json_parser_33: + m_cursor = m_marker; + if (yyaccept == 0) + { + goto basic_json_parser_5; + } + else + { + goto basic_json_parser_14; + } +basic_json_parser_34: + ++m_cursor; + { + last_token_type = token_type::value_string; + break; + } +basic_json_parser_36: + ++m_cursor; + if (m_limit <= m_cursor) + { + yyfill(); // LCOV_EXCL_LINE; + } + yych = *m_cursor; + if (yych <= 'e') + { + if (yych <= '/') + { + if (yych == '"') + { + goto basic_json_parser_31; + } + if (yych <= '.') { goto basic_json_parser_33; } @@ -7735,33 +7795,33 @@ basic_json_parser_36: } else { - if (yych == 'b') + if (yych <= '\\') { + if (yych <= '[') + { + goto basic_json_parser_33; + } goto basic_json_parser_31; } - goto basic_json_parser_33; + else + { + if (yych == 'b') + { + goto basic_json_parser_31; + } + goto basic_json_parser_33; + } } } - } - else - { - if (yych <= 'q') - { - if (yych <= 'f') - { - goto basic_json_parser_31; - } - if (yych == 'n') - { - goto basic_json_parser_31; - } - goto basic_json_parser_33; - } else { - if (yych <= 's') + if (yych <= 'q') { - if (yych <= 'r') + if (yych <= 'f') + { + goto basic_json_parser_31; + } + if (yych == 'n') { goto basic_json_parser_31; } @@ -7769,331 +7829,347 @@ basic_json_parser_36: } else { - if (yych <= 't') + if (yych <= 's') { - goto basic_json_parser_31; + if (yych <= 'r') + { + goto basic_json_parser_31; + } + goto basic_json_parser_33; } - if (yych <= 'u') + else { - goto basic_json_parser_43; + if (yych <= 't') + { + goto basic_json_parser_31; + } + if (yych <= 'u') + { + goto basic_json_parser_43; + } + goto basic_json_parser_33; } - goto basic_json_parser_33; } } - } basic_json_parser_37: - yych = *++m_cursor; - if (yych <= '/') - { + yych = *++m_cursor; + if (yych <= '/') + { + goto basic_json_parser_33; + } + if (yych <= '9') + { + goto basic_json_parser_44; + } goto basic_json_parser_33; - } - if (yych <= '9') - { - goto basic_json_parser_44; - } - goto basic_json_parser_33; basic_json_parser_38: - yych = *++m_cursor; - if (yych <= ',') - { - if (yych == '+') - { - goto basic_json_parser_46; - } - goto basic_json_parser_33; - } - else - { - if (yych <= '-') - { - goto basic_json_parser_46; - } - if (yych <= '/') + yych = *++m_cursor; + if (yych <= ',') { + if (yych == '+') + { + goto basic_json_parser_46; + } goto basic_json_parser_33; } - if (yych <= '9') + else { - goto basic_json_parser_47; + if (yych <= '-') + { + goto basic_json_parser_46; + } + if (yych <= '/') + { + goto basic_json_parser_33; + } + if (yych <= '9') + { + goto basic_json_parser_47; + } + goto basic_json_parser_33; } - goto basic_json_parser_33; - } basic_json_parser_39: - yych = *++m_cursor; - if (yych == 'l') - { - goto basic_json_parser_49; - } - goto basic_json_parser_33; + yych = *++m_cursor; + if (yych == 'l') + { + goto basic_json_parser_49; + } + goto basic_json_parser_33; basic_json_parser_40: - yych = *++m_cursor; - if (yych == 'l') - { - goto basic_json_parser_50; - } - goto basic_json_parser_33; + yych = *++m_cursor; + if (yych == 'l') + { + goto basic_json_parser_50; + } + goto basic_json_parser_33; basic_json_parser_41: - yych = *++m_cursor; - if (yych == 'u') - { - goto basic_json_parser_51; - } - goto basic_json_parser_33; + yych = *++m_cursor; + if (yych == 'u') + { + goto basic_json_parser_51; + } + goto basic_json_parser_33; basic_json_parser_42: - yych = *++m_cursor; - if (yych == 0xBF) - { - goto basic_json_parser_52; - } - goto basic_json_parser_33; + yych = *++m_cursor; + if (yych == 0xBF) + { + goto basic_json_parser_52; + } + goto basic_json_parser_33; basic_json_parser_43: - ++m_cursor; - if (m_limit <= m_cursor) - { - yyfill(); // LCOV_EXCL_LINE; - } - yych = *m_cursor; - if (yych <= '@') - { + ++m_cursor; + if (m_limit <= m_cursor) + { + yyfill(); // LCOV_EXCL_LINE; + } + yych = *m_cursor; + if (yych <= '@') + { + if (yych <= '/') + { + goto basic_json_parser_33; + } + if (yych <= '9') + { + goto basic_json_parser_54; + } + goto basic_json_parser_33; + } + else + { + if (yych <= 'F') + { + goto basic_json_parser_54; + } + if (yych <= '`') + { + goto basic_json_parser_33; + } + if (yych <= 'f') + { + goto basic_json_parser_54; + } + goto basic_json_parser_33; + } +basic_json_parser_44: + yyaccept = 1; + m_marker = ++m_cursor; + if ((m_limit - m_cursor) < 3) + { + yyfill(); // LCOV_EXCL_LINE; + } + yych = *m_cursor; + if (yych <= 'D') + { + if (yych <= '/') + { + goto basic_json_parser_14; + } + if (yych <= '9') + { + goto basic_json_parser_44; + } + goto basic_json_parser_14; + } + else + { + if (yych <= 'E') + { + goto basic_json_parser_38; + } + if (yych == 'e') + { + goto basic_json_parser_38; + } + goto basic_json_parser_14; + } +basic_json_parser_46: + yych = *++m_cursor; if (yych <= '/') { goto basic_json_parser_33; } - if (yych <= '9') - { - goto basic_json_parser_54; - } - goto basic_json_parser_33; - } - else - { - if (yych <= 'F') - { - goto basic_json_parser_54; - } - if (yych <= '`') + if (yych >= ':') { goto basic_json_parser_33; } - if (yych <= 'f') +basic_json_parser_47: + ++m_cursor; + if (m_limit <= m_cursor) { - goto basic_json_parser_54; + yyfill(); // LCOV_EXCL_LINE; } - goto basic_json_parser_33; - } -basic_json_parser_44: - yyaccept = 1; - m_marker = ++m_cursor; - if ((m_limit - m_cursor) < 3) - { - yyfill(); // LCOV_EXCL_LINE; - } - yych = *m_cursor; - if (yych <= 'D') - { + yych = *m_cursor; if (yych <= '/') { goto basic_json_parser_14; } if (yych <= '9') { - goto basic_json_parser_44; + goto basic_json_parser_47; } goto basic_json_parser_14; - } - else - { - if (yych <= 'E') +basic_json_parser_49: + yych = *++m_cursor; + if (yych == 's') { - goto basic_json_parser_38; + goto basic_json_parser_55; } + goto basic_json_parser_33; +basic_json_parser_50: + yych = *++m_cursor; + if (yych == 'l') + { + goto basic_json_parser_56; + } + goto basic_json_parser_33; +basic_json_parser_51: + yych = *++m_cursor; if (yych == 'e') { - goto basic_json_parser_38; + goto basic_json_parser_58; } - goto basic_json_parser_14; - } -basic_json_parser_46: - yych = *++m_cursor; - if (yych <= '/') - { goto basic_json_parser_33; - } - if (yych >= ':') - { - goto basic_json_parser_33; - } -basic_json_parser_47: - ++m_cursor; - if (m_limit <= m_cursor) - { - yyfill(); // LCOV_EXCL_LINE; - } - yych = *m_cursor; - if (yych <= '/') - { - goto basic_json_parser_14; - } - if (yych <= '9') - { - goto basic_json_parser_47; - } - goto basic_json_parser_14; -basic_json_parser_49: - yych = *++m_cursor; - if (yych == 's') - { - goto basic_json_parser_55; - } - goto basic_json_parser_33; -basic_json_parser_50: - yych = *++m_cursor; - if (yych == 'l') - { - goto basic_json_parser_56; - } - goto basic_json_parser_33; -basic_json_parser_51: - yych = *++m_cursor; - if (yych == 'e') - { - goto basic_json_parser_58; - } - goto basic_json_parser_33; basic_json_parser_52: - ++m_cursor; - { - return scan(); - } + ++m_cursor; + { + continue; + } basic_json_parser_54: - ++m_cursor; - if (m_limit <= m_cursor) - { - yyfill(); // LCOV_EXCL_LINE; - } - yych = *m_cursor; - if (yych <= '@') - { - if (yych <= '/') + ++m_cursor; + if (m_limit <= m_cursor) { + yyfill(); // LCOV_EXCL_LINE; + } + yych = *m_cursor; + if (yych <= '@') + { + if (yych <= '/') + { + goto basic_json_parser_33; + } + if (yych <= '9') + { + goto basic_json_parser_60; + } goto basic_json_parser_33; } - if (yych <= '9') - { - goto basic_json_parser_60; - } - goto basic_json_parser_33; - } - else - { - if (yych <= 'F') - { - goto basic_json_parser_60; - } - if (yych <= '`') + else { + if (yych <= 'F') + { + goto basic_json_parser_60; + } + if (yych <= '`') + { + goto basic_json_parser_33; + } + if (yych <= 'f') + { + goto basic_json_parser_60; + } goto basic_json_parser_33; } - if (yych <= 'f') - { - goto basic_json_parser_60; - } - goto basic_json_parser_33; - } basic_json_parser_55: - yych = *++m_cursor; - if (yych == 'e') - { - goto basic_json_parser_61; - } - goto basic_json_parser_33; + yych = *++m_cursor; + if (yych == 'e') + { + goto basic_json_parser_61; + } + goto basic_json_parser_33; basic_json_parser_56: - ++m_cursor; - { - return token_type::literal_null; - } + ++m_cursor; + { + last_token_type = token_type::literal_null; + break; + } basic_json_parser_58: - ++m_cursor; - { - return token_type::literal_true; - } + ++m_cursor; + { + last_token_type = token_type::literal_true; + break; + } basic_json_parser_60: - ++m_cursor; - if (m_limit <= m_cursor) - { - yyfill(); // LCOV_EXCL_LINE; - } - yych = *m_cursor; - if (yych <= '@') - { - if (yych <= '/') + ++m_cursor; + if (m_limit <= m_cursor) { + yyfill(); // LCOV_EXCL_LINE; + } + yych = *m_cursor; + if (yych <= '@') + { + if (yych <= '/') + { + goto basic_json_parser_33; + } + if (yych <= '9') + { + goto basic_json_parser_63; + } goto basic_json_parser_33; } - if (yych <= '9') - { - goto basic_json_parser_63; - } - goto basic_json_parser_33; - } - else - { - if (yych <= 'F') - { - goto basic_json_parser_63; - } - if (yych <= '`') + else { + if (yych <= 'F') + { + goto basic_json_parser_63; + } + if (yych <= '`') + { + goto basic_json_parser_33; + } + if (yych <= 'f') + { + goto basic_json_parser_63; + } goto basic_json_parser_33; } - if (yych <= 'f') - { - goto basic_json_parser_63; - } - goto basic_json_parser_33; - } basic_json_parser_61: - ++m_cursor; - { - return token_type::literal_false; - } + ++m_cursor; + { + last_token_type = token_type::literal_false; + break; + } basic_json_parser_63: - ++m_cursor; - if (m_limit <= m_cursor) - { - yyfill(); // LCOV_EXCL_LINE; - } - yych = *m_cursor; - if (yych <= '@') - { - if (yych <= '/') + ++m_cursor; + if (m_limit <= m_cursor) { + yyfill(); // LCOV_EXCL_LINE; + } + yych = *m_cursor; + if (yych <= '@') + { + if (yych <= '/') + { + goto basic_json_parser_33; + } + if (yych <= '9') + { + goto basic_json_parser_31; + } goto basic_json_parser_33; } - if (yych <= '9') - { - goto basic_json_parser_31; - } - goto basic_json_parser_33; - } - else - { - if (yych <= 'F') - { - goto basic_json_parser_31; - } - if (yych <= '`') + else { + if (yych <= 'F') + { + goto basic_json_parser_31; + } + if (yych <= '`') + { + goto basic_json_parser_33; + } + if (yych <= 'f') + { + goto basic_json_parser_31; + } goto basic_json_parser_33; } - if (yych <= 'f') - { - goto basic_json_parser_31; - } - goto basic_json_parser_33; } + } + return last_token_type; } /// append data from the stream to the internal buffer @@ -8123,7 +8199,7 @@ basic_json_parser_63: } /// return string representation of last read token - string_t get_token() const + string_t get_token_string() const { assert(m_start != nullptr); return string_t(reinterpret_cast(m_start), @@ -8391,7 +8467,7 @@ basic_json_parser_63: if (type != value_t::number_float) { // multiply last value by ten and add the new digit - auto temp = value * 10 + *curptr - 0x30; + auto temp = value * 10 + *curptr - '0'; // test for overflow if (temp < value || temp > max) @@ -8441,6 +8517,8 @@ basic_json_parser_63: const lexer_char_t* m_cursor = nullptr; /// pointer to the end of the buffer const lexer_char_t* m_limit = nullptr; + /// the last token type + token_type last_token_type = token_type::end_of_input; }; /*! @@ -8476,7 +8554,7 @@ basic_json_parser_63: // return parser result and replace it with null in case the // top-level value was discarded by the callback function - return result.is_discarded() ? basic_json() : result; + return result.is_discarded() ? basic_json() : std::move(result); } private: @@ -8684,7 +8762,8 @@ basic_json_parser_63: if (t != last_token) { std::string error_msg = "parse error - unexpected "; - error_msg += (last_token == lexer::token_type::parse_error ? ("'" + m_lexer.get_token() + "'") : + error_msg += (last_token == lexer::token_type::parse_error ? ("'" + m_lexer.get_token_string() + + "'") : lexer::token_type_name(last_token)); error_msg += "; expected " + lexer::token_type_name(t); throw std::invalid_argument(error_msg); @@ -8696,7 +8775,8 @@ basic_json_parser_63: if (t == last_token) { std::string error_msg = "parse error - unexpected "; - error_msg += (last_token == lexer::token_type::parse_error ? ("'" + m_lexer.get_token() + "'") : + error_msg += (last_token == lexer::token_type::parse_error ? ("'" + m_lexer.get_token_string() + + "'") : lexer::token_type_name(last_token)); throw std::invalid_argument(error_msg); } @@ -8774,14 +8854,12 @@ basic_json_parser_63: */ std::string to_string() const noexcept { - std::string result; - - for (const auto& reference_token : reference_tokens) + return std::accumulate(reference_tokens.begin(), + reference_tokens.end(), std::string{}, + [](const std::string & a, const std::string & b) { - result += "/" + escape(reference_token); - } - - return result; + return a + "/" + escape(b); + }); } /// @copydoc to_string() diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index aba10b496..dd1bda1fb 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ -| | |__ | | | | | | version 2.0.0 +| | |__ | | | | | | version 2.0.1 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . @@ -36,7 +36,7 @@ SOFTWARE. #include #include #include -#include +#include #include #include #include @@ -46,6 +46,7 @@ SOFTWARE. #include #include #include +#include #include #include #include @@ -53,6 +54,19 @@ SOFTWARE. #include #include +// exclude unsupported compilers +#if defined(__clang__) + #define CLANG_VERSION (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) + #if CLANG_VERSION < 30400 + #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" + #endif +#elif defined(__GNUC__) + #define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) + #if GCC_VERSION < 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 @@ -76,7 +90,13 @@ namespace { /*! @brief Helper to determine whether there's a key_type for T. + +Thus 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 */ template struct has_mapped_type @@ -90,11 +110,18 @@ struct has_mapped_type /*! @brief helper class to create locales with decimal point + +This struct is used a default locale during the JSON serialization. JSON +requires the decimal point to be `.`, so this function overloads the +`do_decimal_point()` function to return `.`. This function is called by +float-to-string conversions to retrieve the decimal separator between integer +and fractional parts. + @sa https://github.com/nlohmann/json/issues/51#issuecomment-86869315 +@since version 2.0.0 */ -class DecimalSeparator : public std::numpunct +struct DecimalSeparator : std::numpunct { - protected: char do_decimal_point() const { return '.'; @@ -188,13 +215,8 @@ class basic_json { private: /// workaround type for MSVC - using basic_json_t = basic_json; public: @@ -207,6 +229,8 @@ class basic_json ///////////////////// /// @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 @@ -256,6 +280,8 @@ class basic_json /////////////////////////// /// @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. /// @{ /*! @@ -923,6 +949,8 @@ class basic_json ////////////////// /// @name constructors and destructors + /// Constructors of class @ref basic_json, copy/move constructor, copy + /// assignment, static functions creating objects, and the destructor. /// @{ /*! @@ -1554,22 +1582,13 @@ class basic_json bool type_deduction = true, value_t manual_type = value_t::array) { - // the initializer list could describe an object - bool is_an_object = true; - // check if each element is an array with two elements whose first // element is a string - for (const auto& element : init) + bool is_an_object = std::all_of(init.begin(), init.end(), + [](const basic_json & element) { - if (not element.is_array() or element.size() != 2 - or not element[0].is_string()) - { - // we found an element that makes it impossible to use the - // initializer list as object - is_an_object = false; - break; - } - } + return element.is_array() and element.size() == 2 and element[0].is_string(); + }); // adjust type if type deduction is not wanted if (not type_deduction) @@ -1595,10 +1614,10 @@ class basic_json assert(m_value.object != nullptr); - for (auto& element : init) + std::for_each(init.begin(), init.end(), [this](const basic_json & element) { m_value.object->emplace(*(element[0].m_value.string), element[1]); - } + }); } else { @@ -2069,19 +2088,20 @@ class basic_json /////////////////////// /// @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 @p json.dumps() function, and currently supports its @p indent + Python's `json.dumps()` function, and currently supports its @a indent parameter. - @param[in] indent if indent is nonnegative, then array elements and object + @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 + `0` will only insert newlines. `-1` (the default) selects the most compact + representation. @return string containing the serialization of the JSON value @@ -2097,6 +2117,8 @@ class basic_json string_t dump(const int indent = -1) const { std::stringstream ss; + // fix locale problems + ss.imbue(std::locale(std::locale(), new DecimalSeparator)); if (indent >= 0) { @@ -2765,6 +2787,7 @@ class basic_json public: /// @name value access + /// Direct access to the stored value of a JSON value. /// @{ /*! @@ -2815,7 +2838,8 @@ class basic_json Explicit pointer access to the internally stored JSON value. No copies are made. - @warning The pointer becomes invalid if the underlying JSON object changes. + @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, @@ -2870,7 +2894,8 @@ class basic_json @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. + @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 @@ -2890,6 +2915,21 @@ class basic_json , 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)); } @@ -2905,6 +2945,21 @@ class basic_json , 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)); } @@ -2920,7 +2975,7 @@ class basic_json @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. + @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 @@ -3010,6 +3065,7 @@ class basic_json //////////////////// /// @name element access + /// Access to the JSON value. /// @{ /*! @@ -3233,11 +3289,13 @@ class basic_json // operator[] only works for arrays if (is_array()) { - // fill up array with null values until given idx is reached + // fill up array with null values if given idx is outside range assert(m_value.array != nullptr); - for (size_t i = m_value.array->size(); i <= idx; ++i) + if (idx >= m_value.array->size()) { - m_value.array->push_back(basic_json()); + m_value.array->insert(m_value.array->end(), + idx - m_value.array->size() + 1, + basic_json()); } return m_value.array->operator[](idx); @@ -5655,9 +5713,14 @@ class basic_json // reset width to 0 for subsequent calls to this stream o.width(0); + // fix locale problems + auto old_locale = o.imbue(std::locale(std::locale(), new DecimalSeparator)); // do the actual serialization j.dump(o, pretty_print, static_cast(indentation)); + + // reset locale + o.imbue(old_locale); return o; } @@ -5794,7 +5857,7 @@ class basic_json /////////////////////////// /// return the type as string - string_t type_name() const noexcept + std::string type_name() const { switch (m_type) { @@ -5825,9 +5888,8 @@ class basic_json */ static std::size_t extra_space(const string_t& s) noexcept { - std::size_t result = 0; - - for (const auto& c : s) + return std::accumulate(s.begin(), s.end(), size_t{}, + [](size_t res, typename string_t::value_type c) { switch (c) { @@ -5840,8 +5902,7 @@ class basic_json case '\t': { // from c (1 byte) to \x (2 bytes) - result += 1; - break; + return res + 1; } default: @@ -5849,14 +5910,15 @@ class basic_json if (c >= 0x00 and c <= 0x1f) { // from c (1 byte) to \uxxxx (6 bytes) - result += 5; + return res + 5; + } + else + { + return res; } - break; } } - } - - return result; + }); } /*! @@ -5950,16 +6012,15 @@ class basic_json { // convert a number 0..15 to its hex representation // (0..f) - const auto hexify = [](const int v) -> char + static const char hexify[16] = { - return (v < 10) - ? ('0' + static_cast(v)) - : ('a' + static_cast((v - 10) & 0x1f)); + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; // print character c as \uxxxx for (const char m : - { 'u', '0', '0', hexify(c >> 4), hexify(c & 0x0f) + { 'u', '0', '0', hexify[c >> 4], hexify[c & 0x0f] }) { result[++pos] = m; @@ -6128,11 +6189,8 @@ class basic_json // string->double->string or string->long // double->string; to be safe, we read this value from // std::numeric_limits::digits10 - std::stringstream ss; - ss.imbue(std::locale(std::locale(), new DecimalSeparator)); // fix locale problems - ss << std::setprecision(std::numeric_limits::digits10) - << m_value.number_float; - o << ss.str(); + o << std::setprecision(std::numeric_limits::digits10) + << m_value.number_float; } return; } @@ -6609,13 +6667,13 @@ class basic_json { case basic_json::value_t::object: { - ++m_it.object_iterator; + std::advance(m_it.object_iterator, 1); break; } case basic_json::value_t::array: { - ++m_it.array_iterator; + std::advance(m_it.array_iterator, 1); break; } @@ -6646,13 +6704,13 @@ class basic_json { case basic_json::value_t::object: { - --m_it.object_iterator; + std::advance(m_it.object_iterator, -1); break; } case basic_json::value_t::array: { - --m_it.array_iterator; + std::advance(m_it.array_iterator, -1); break; } @@ -6764,7 +6822,7 @@ class basic_json case basic_json::value_t::array: { - m_it.array_iterator += i; + std::advance(m_it.array_iterator, i); break; } @@ -6838,7 +6896,7 @@ class basic_json case basic_json::value_t::array: { - return *(m_it.array_iterator + n); + return *std::next(m_it.array_iterator, n); } case basic_json::value_t::null: @@ -7334,76 +7392,81 @@ class basic_json */ token_type scan() noexcept { - // pointer for backtracking information - m_marker = nullptr; + while (true) + { + // pointer for backtracking information + m_marker = nullptr; - // remember the begin of the token - m_start = m_cursor; - assert(m_start != nullptr); + // remember the begin of the token + m_start = m_cursor; + assert(m_start != nullptr); - /*!re2c - re2c:define:YYCTYPE = lexer_char_t; - re2c:define:YYCURSOR = m_cursor; - re2c:define:YYLIMIT = m_limit; - re2c:define:YYMARKER = m_marker; - re2c:define:YYFILL = "yyfill(); // LCOV_EXCL_LINE"; - re2c:yyfill:parameter = 0; - re2c:indent:string = " "; - re2c:indent:top = 1; - re2c:labelprefix = "basic_json_parser_"; + /*!re2c + re2c:define:YYCTYPE = lexer_char_t; + re2c:define:YYCURSOR = m_cursor; + re2c:define:YYLIMIT = m_limit; + re2c:define:YYMARKER = m_marker; + re2c:define:YYFILL = "yyfill(); // LCOV_EXCL_LINE"; + re2c:yyfill:parameter = 0; + re2c:indent:string = " "; + re2c:indent:top = 1; + re2c:labelprefix = "basic_json_parser_"; - // ignore whitespace - ws = [ \t\n\r]+; - ws { return scan(); } + // ignore whitespace + ws = [ \t\n\r]+; + ws { continue; } - // ignore byte-order-mark - bom = "\xEF\xBB\xBF"; - bom { return scan(); } + // ignore byte-order-mark + bom = "\xEF\xBB\xBF"; + bom { continue; } - // structural characters - "[" { return token_type::begin_array; } - "]" { return token_type::end_array; } - "{" { return token_type::begin_object; } - "}" { return token_type::end_object; } - "," { return token_type::value_separator; } - ":" { return token_type::name_separator; } + // structural characters + "[" { last_token_type = token_type::begin_array; break; } + "]" { last_token_type = token_type::end_array; break; } + "{" { last_token_type = token_type::begin_object; break; } + "}" { last_token_type = token_type::end_object; break; } + "," { last_token_type = token_type::value_separator; break; } + ":" { last_token_type = token_type::name_separator; break; } - // literal names - "null" { return token_type::literal_null; } - "true" { return token_type::literal_true; } - "false" { return token_type::literal_false; } + // literal names + "null" { last_token_type = token_type::literal_null; break; } + "true" { last_token_type = token_type::literal_true; break; } + "false" { last_token_type = token_type::literal_false; break; } - // number - decimal_point = [.]; - digit = [0-9]; - digit_1_9 = [1-9]; - e = [eE]; - minus = [-]; - plus = [+]; - zero = [0]; - exp = e (minus|plus)? digit+; - frac = decimal_point digit+; - int = (zero|digit_1_9 digit*); - number = minus? int frac? exp?; - number { return token_type::value_number; } + // number + decimal_point = [.]; + digit = [0-9]; + digit_1_9 = [1-9]; + e = [eE]; + minus = [-]; + plus = [+]; + zero = [0]; + exp = e (minus|plus)? digit+; + frac = decimal_point digit+; + int = (zero|digit_1_9 digit*); + number = minus? int frac? exp?; + number { last_token_type = token_type::value_number; break; } - // string - quotation_mark = ["]; - escape = [\\]; - unescaped = [^"\\\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F]; - single_escaped = ["\\/bfnrt]; - unicode_escaped = [u][0-9a-fA-F]{4}; - escaped = escape (single_escaped | unicode_escaped); - char = unescaped | escaped; - string = quotation_mark char* quotation_mark; - string { return token_type::value_string; } + // string + quotation_mark = ["]; + escape = [\\]; + unescaped = [^"\\\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F]; + single_escaped = ["\\/bfnrt]; + unicode_escaped = [u][0-9a-fA-F]{4}; + escaped = escape (single_escaped | unicode_escaped); + char = unescaped | escaped; + string = quotation_mark char* quotation_mark; + string { last_token_type = token_type::value_string; break; } - // end of file - '\000' { return token_type::end_of_input; } + // end of file + '\000' { last_token_type = token_type::end_of_input; break; } - // anything else is an error - . { return token_type::parse_error; } - */ + // anything else is an error + . { last_token_type = token_type::parse_error; break; } + */ + } + + return last_token_type; } /// append data from the stream to the internal buffer @@ -7433,7 +7496,7 @@ class basic_json } /// return string representation of last read token - string_t get_token() const + string_t get_token_string() const { assert(m_start != nullptr); return string_t(reinterpret_cast(m_start), @@ -7701,7 +7764,7 @@ class basic_json if (type != value_t::number_float) { // multiply last value by ten and add the new digit - auto temp = value * 10 + *curptr - 0x30; + auto temp = value * 10 + *curptr - '0'; // test for overflow if (temp < value || temp > max) @@ -7751,6 +7814,8 @@ class basic_json const lexer_char_t* m_cursor = nullptr; /// pointer to the end of the buffer const lexer_char_t* m_limit = nullptr; + /// the last token type + token_type last_token_type = token_type::end_of_input; }; /*! @@ -7786,7 +7851,7 @@ class basic_json // return parser result and replace it with null in case the // top-level value was discarded by the callback function - return result.is_discarded() ? basic_json() : result; + return result.is_discarded() ? basic_json() : std::move(result); } private: @@ -7994,7 +8059,8 @@ class basic_json if (t != last_token) { std::string error_msg = "parse error - unexpected "; - error_msg += (last_token == lexer::token_type::parse_error ? ("'" + m_lexer.get_token() + "'") : + error_msg += (last_token == lexer::token_type::parse_error ? ("'" + m_lexer.get_token_string() + + "'") : lexer::token_type_name(last_token)); error_msg += "; expected " + lexer::token_type_name(t); throw std::invalid_argument(error_msg); @@ -8006,7 +8072,8 @@ class basic_json if (t == last_token) { std::string error_msg = "parse error - unexpected "; - error_msg += (last_token == lexer::token_type::parse_error ? ("'" + m_lexer.get_token() + "'") : + error_msg += (last_token == lexer::token_type::parse_error ? ("'" + m_lexer.get_token_string() + + "'") : lexer::token_type_name(last_token)); throw std::invalid_argument(error_msg); } @@ -8084,14 +8151,12 @@ class basic_json */ std::string to_string() const noexcept { - std::string result; - - for (const auto& reference_token : reference_tokens) + return std::accumulate(reference_tokens.begin(), + reference_tokens.end(), std::string{}, + [](const std::string & a, const std::string & b) { - result += "/" + escape(reference_token); - } - - return result; + return a + "/" + escape(b); + }); } /// @copydoc to_string() diff --git a/test/src/unit.cpp b/test/src/unit.cpp index 298a2bb1e..a12f0529a 100644 --- a/test/src/unit.cpp +++ b/test/src/unit.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 2.0.0 +| | |__ | | | | | | version 2.0.1 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . @@ -10309,252 +10309,261 @@ TEST_CASE("parser class") TEST_CASE("README", "[hide]") { { - // create an empty structure (null) - json j; - - // add a number that is stored as double (note the implicit conversion of j to an object) - j["pi"] = 3.141; - - // add a Boolean that is stored as bool - j["happy"] = true; - - // add a string that is stored as std::string - j["name"] = "Niels"; - - // add another null object by passing nullptr - j["nothing"] = nullptr; - - // add an object inside the object - j["answer"]["everything"] = 42; - - // add an array that is stored as std::vector (using an initializer list) - j["list"] = { 1, 0, 2 }; - - // add another object (using an initializer list of pairs) - j["object"] = { {"currency", "USD"}, {"value", 42.99} }; - - // instead, you could also write (which looks very similar to the JSON above) - json j2 = + // redirect std::cout for the README file + auto old_cout_buffer = std::cout.rdbuf(); + std::ostringstream new_stream; + std::cout.rdbuf(new_stream.rdbuf()); { - {"pi", 3.141}, - {"happy", true}, - {"name", "Niels"}, - {"nothing", nullptr}, + // create an empty structure (null) + json j; + + // add a number that is stored as double (note the implicit conversion of j to an object) + j["pi"] = 3.141; + + // add a Boolean that is stored as bool + j["happy"] = true; + + // add a string that is stored as std::string + j["name"] = "Niels"; + + // add another null object by passing nullptr + j["nothing"] = nullptr; + + // add an object inside the object + j["answer"]["everything"] = 42; + + // add an array that is stored as std::vector (using an initializer list) + j["list"] = { 1, 0, 2 }; + + // add another object (using an initializer list of pairs) + j["object"] = { {"currency", "USD"}, {"value", 42.99} }; + + // instead, you could also write (which looks very similar to the JSON above) + json j2 = { - "answer", { - {"everything", 42} + {"pi", 3.141}, + {"happy", true}, + {"name", "Niels"}, + {"nothing", nullptr}, + { + "answer", { + {"everything", 42} + } + }, + {"list", {1, 0, 2}}, + { + "object", { + {"currency", "USD"}, + {"value", 42.99} + } } - }, - {"list", {1, 0, 2}}, - { - "object", { - {"currency", "USD"}, - {"value", 42.99} - } - } - }; - } + }; + } - { - // ways to express the empty array [] - json empty_array_implicit = {{}}; - json empty_array_explicit = json::array(); + { + // ways to express the empty array [] + json empty_array_implicit = {{}}; + json empty_array_explicit = json::array(); - // a way to express the empty object {} - json empty_object_explicit = json::object(); + // a way to express the empty object {} + json empty_object_explicit = json::object(); - // a way to express an _array_ of key/value pairs [["currency", "USD"], ["value", 42.99]] - json array_not_object = { json::array({"currency", "USD"}), json::array({"value", 42.99}) }; - } + // a way to express an _array_ of key/value pairs [["currency", "USD"], ["value", 42.99]] + json array_not_object = { json::array({"currency", "USD"}), json::array({"value", 42.99}) }; + } - { - // create object from string literal - json j = "{ \"happy\": true, \"pi\": 3.141 }"_json; + { + // create object from string literal + json j = "{ \"happy\": true, \"pi\": 3.141 }"_json; - // or even nicer with a raw string literal - auto j2 = R"( + // or even nicer with a raw string literal + auto j2 = R"( { "happy": true, "pi": 3.141 } )"_json; - // or explicitly - auto j3 = json::parse("{ \"happy\": true, \"pi\": 3.141 }"); + // or explicitly + auto j3 = json::parse("{ \"happy\": true, \"pi\": 3.141 }"); - // explicit conversion to string - std::string s = j.dump(); // {\"happy\":true,\"pi\":3.141} + // explicit conversion to string + std::string s = j.dump(); // {\"happy\":true,\"pi\":3.141} - // serialization with pretty printing - // pass in the amount of spaces to indent - std::cout << j.dump(4) << std::endl; - // { - // "happy": true, - // "pi": 3.141 - // } + // serialization with pretty printing + // pass in the amount of spaces to indent + std::cout << j.dump(4) << std::endl; + // { + // "happy": true, + // "pi": 3.141 + // } - std::cout << std::setw(2) << j << std::endl; - } - - { - // create an array using push_back - json j; - j.push_back("foo"); - j.push_back(1); - j.push_back(true); - - // iterate the array - for (json::iterator it = j.begin(); it != j.end(); ++it) - { - std::cout << *it << '\n'; + std::cout << std::setw(2) << j << std::endl; } - // range-based for - for (auto element : j) { - std::cout << element << '\n'; + // create an array using push_back + json j; + j.push_back("foo"); + j.push_back(1); + j.push_back(true); + + // iterate the array + for (json::iterator it = j.begin(); it != j.end(); ++it) + { + std::cout << *it << '\n'; + } + + // range-based for + for (auto element : j) + { + std::cout << element << '\n'; + } + + // getter/setter + const std::string tmp = j[0]; + j[1] = 42; + bool foo = j.at(2); + + // other stuff + j.size(); // 3 entries + j.empty(); // false + j.type(); // json::value_t::array + j.clear(); // the array is empty again + + // comparison + j == "[\"foo\", 1, true]"_json; // true + + // create an object + json o; + o["foo"] = 23; + o["bar"] = false; + o["baz"] = 3.141; + + // find an entry + if (o.find("foo") != o.end()) + { + // there is an entry with key "foo" + } } - // getter/setter - const std::string tmp = j[0]; - j[1] = 42; - bool foo = j.at(2); - - // other stuff - j.size(); // 3 entries - j.empty(); // false - j.type(); // json::value_t::array - j.clear(); // the array is empty again - - // comparison - j == "[\"foo\", 1, true]"_json; // true - - // create an object - json o; - o["foo"] = 23; - o["bar"] = false; - o["baz"] = 3.141; - - // find an entry - if (o.find("foo") != o.end()) { - // there is an entry with key "foo" + std::vector c_vector {1, 2, 3, 4}; + json j_vec(c_vector); + // [1, 2, 3, 4] + + std::deque c_deque {1.2f, 2.3f, 3.4f, 5.6f}; + json j_deque(c_deque); + // [1.2, 2.3, 3.4, 5.6] + + std::list c_list {true, true, false, true}; + json j_list(c_list); + // [true, true, false, true] + + std::forward_list c_flist {12345678909876, 23456789098765, 34567890987654, 45678909876543}; + json j_flist(c_flist); + // [12345678909876, 23456789098765, 34567890987654, 45678909876543] + + std::array c_array {{1, 2, 3, 4}}; + json j_array(c_array); + // [1, 2, 3, 4] + + std::set c_set {"one", "two", "three", "four", "one"}; + json j_set(c_set); // only one entry for "one" is used + // ["four", "one", "three", "two"] + + std::unordered_set c_uset {"one", "two", "three", "four", "one"}; + json j_uset(c_uset); // only one entry for "one" is used + // maybe ["two", "three", "four", "one"] + + std::multiset c_mset {"one", "two", "one", "four"}; + json j_mset(c_mset); // only one entry for "one" is used + // maybe ["one", "two", "four"] + + std::unordered_multiset c_umset {"one", "two", "one", "four"}; + json j_umset(c_umset); // both entries for "one" are used + // maybe ["one", "two", "one", "four"] } - } - { - std::vector c_vector {1, 2, 3, 4}; - json j_vec(c_vector); - // [1, 2, 3, 4] + { + std::map c_map { {"one", 1}, {"two", 2}, {"three", 3} }; + json j_map(c_map); + // {"one": 1, "two": 2, "three": 3} - std::deque c_deque {1.2f, 2.3f, 3.4f, 5.6f}; - json j_deque(c_deque); - // [1.2, 2.3, 3.4, 5.6] + std::unordered_map c_umap { {"one", 1.2f}, {"two", 2.3f}, {"three", 3.4f} }; + json j_umap(c_umap); + // {"one": 1.2, "two": 2.3, "three": 3.4} - std::list c_list {true, true, false, true}; - json j_list(c_list); - // [true, true, false, true] + std::multimap c_mmap { {"one", true}, {"two", true}, {"three", false}, {"three", true} }; + json j_mmap(c_mmap); // only one entry for key "three" is used + // maybe {"one": true, "two": true, "three": true} - std::forward_list c_flist {12345678909876, 23456789098765, 34567890987654, 45678909876543}; - json j_flist(c_flist); - // [12345678909876, 23456789098765, 34567890987654, 45678909876543] + std::unordered_multimap c_ummap { {"one", true}, {"two", true}, {"three", false}, {"three", true} }; + json j_ummap(c_ummap); // only one entry for key "three" is used + // maybe {"one": true, "two": true, "three": true} + } - std::array c_array {{1, 2, 3, 4}}; - json j_array(c_array); - // [1, 2, 3, 4] + { + // strings + std::string s1 = "Hello, world!"; + json js = s1; + std::string s2 = js; - std::set c_set {"one", "two", "three", "four", "one"}; - json j_set(c_set); // only one entry for "one" is used - // ["four", "one", "three", "two"] + // Booleans + bool b1 = true; + json jb = b1; + bool b2 = jb; - std::unordered_set c_uset {"one", "two", "three", "four", "one"}; - json j_uset(c_uset); // only one entry for "one" is used - // maybe ["two", "three", "four", "one"] + // numbers + int i = 42; + json jn = i; + double f = jn; - std::multiset c_mset {"one", "two", "one", "four"}; - json j_mset(c_mset); // only one entry for "one" is used - // maybe ["one", "two", "four"] + // etc. - std::unordered_multiset c_umset {"one", "two", "one", "four"}; - json j_umset(c_umset); // both entries for "one" are used - // maybe ["one", "two", "one", "four"] - } + std::string vs = js.get(); + bool vb = jb.get(); + int vi = jn.get(); - { - std::map c_map { {"one", 1}, {"two", 2}, {"three", 3} }; - json j_map(c_map); - // {"one": 1, "two": 2, "three": 3} + // etc. + } - std::unordered_map c_umap { {"one", 1.2f}, {"two", 2.3f}, {"three", 3.4f} }; - json j_umap(c_umap); - // {"one": 1.2, "two": 2.3, "three": 3.4} - - std::multimap c_mmap { {"one", true}, {"two", true}, {"three", false}, {"three", true} }; - json j_mmap(c_mmap); // only one entry for key "three" is used - // maybe {"one": true, "two": true, "three": true} - - std::unordered_multimap c_ummap { {"one", true}, {"two", true}, {"three", false}, {"three", true} }; - json j_ummap(c_ummap); // only one entry for key "three" is used - // maybe {"one": true, "two": true, "three": true} - } - - { - // strings - std::string s1 = "Hello, world!"; - json js = s1; - std::string s2 = js; - - // Booleans - bool b1 = true; - json jb = b1; - bool b2 = jb; - - // numbers - int i = 42; - json jn = i; - double f = jn; - - // etc. - - std::string vs = js.get(); - bool vb = jb.get(); - int vi = jn.get(); - - // etc. - } - - { - // a JSON value - json j_original = R"({ + { + // a JSON value + json j_original = R"({ "baz": ["one", "two", "three"], "foo": "bar" })"_json; - // access members with a JSON pointer (RFC 6901) - j_original["/baz/2"_json_pointer]; - // "two" + // access members with a JSON pointer (RFC 6901) + j_original["/baz/1"_json_pointer]; + // "two" - // a JSON patch (RFC 6902) - json j_patch = R"([ + // a JSON patch (RFC 6902) + json j_patch = R"([ { "op": "replace", "path": "/baz", "value": "boo" }, { "op": "add", "path": "/hello", "value": ["world"] }, { "op": "remove", "path": "/foo"} ])"_json; - // apply the patch - json j_result = j_original.patch(j_patch); - // { - // "baz": "boo", - // "hello": ["world"] - // } + // apply the patch + json j_result = j_original.patch(j_patch); + // { + // "baz": "boo", + // "hello": ["world"] + // } - // calculate a JSON patch from two JSON values - json::diff(j_result, j_original); - // [ - // { "op":" replace", "path": "/baz", "value": ["one", "two", "three"] }, - // { "op":"remove","path":"/hello" }, - // { "op":"add","path":"/foo","value":"bar" } - // ] + // calculate a JSON patch from two JSON values + json::diff(j_result, j_original); + // [ + // { "op":" replace", "path": "/baz", "value": ["one", "two", "three"] }, + // { "op":"remove","path":"/hello" }, + // { "op":"add","path":"/foo","value":"bar" } + // ] + } + + // restore old std::cout + std::cout.rdbuf(old_cout_buffer); } } @@ -14079,6 +14088,16 @@ TEST_CASE("regression tests") CHECK(j1a.dump() == "23.42"); CHECK(j1b.dump() == "23.42"); + // check if locale is properly reset + std::stringstream ss; + ss.imbue(std::locale(std::locale(), new CommaDecimalSeparator)); + ss << 47.11; + CHECK(ss.str() == "47,11"); + ss << j1a; + CHECK(ss.str() == "47,1123.42"); + ss << 47.11; + CHECK(ss.str() == "47,1123.4247,11"); + CHECK(j2a.dump() == "23.42"); //issue #230 //CHECK(j2b.dump() == "23.42");