Merge branch 'develop' into coverity_scan
This commit is contained in:
commit
ea19be1736
8 changed files with 1231 additions and 1049 deletions
19
ChangeLog.md
19
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)
|
## [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)
|
- 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)
|
- Unit test fails when doing a CMake out-of-tree build [\#241](https://github.com/nlohmann/json/issues/241)
|
||||||
|
|
13
README.md
13
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://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)
|
[![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"]
|
// 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
|
```cpp
|
||||||
std::map<std::string, int> c_map { {"one", 1}, {"two", 2}, {"three", 3} };
|
std::map<std::string, int> c_map { {"one", 1}, {"two", 2}, {"three", 3} };
|
||||||
|
@ -323,7 +323,7 @@ json j_original = R"({
|
||||||
})"_json;
|
})"_json;
|
||||||
|
|
||||||
// access members with a JSON pointer (RFC 6901)
|
// access members with a JSON pointer (RFC 6901)
|
||||||
j_original["/baz/2"_json_pointer];
|
j_original["/baz/1"_json_pointer];
|
||||||
// "two"
|
// "two"
|
||||||
|
|
||||||
// a JSON patch (RFC 6902)
|
// a JSON patch (RFC 6902)
|
||||||
|
@ -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)
|
- GCC 4.9 - 6.0 (and possibly later)
|
||||||
- Clang 3.4 - 3.9 (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.
|
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.
|
- [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.
|
- [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).
|
- [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!
|
Thanks a lot for helping out!
|
||||||
|
|
||||||
|
@ -502,7 +505,7 @@ $ make
|
||||||
$ ./json_unit "*"
|
$ ./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).
|
For more information, have a look at the file [.travis.yml](https://github.com/nlohmann/json/blob/master/.travis.yml).
|
||||||
|
|
21
doc/Makefile
21
doc/Makefile
|
@ -1,4 +1,5 @@
|
||||||
SRCDIR = ../src
|
SRCDIR = ../src
|
||||||
|
SED:=$(shell command -v gsed || which sed)
|
||||||
|
|
||||||
all: doxygen
|
all: doxygen
|
||||||
|
|
||||||
|
@ -52,10 +53,10 @@ clean:
|
||||||
# create Doxygen documentation
|
# create Doxygen documentation
|
||||||
doxygen: create_output create_links
|
doxygen: create_output create_links
|
||||||
doxygen
|
doxygen
|
||||||
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
|
||||||
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
|
||||||
gsed -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
|
||||||
gsed -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
|
upload: clean doxygen check_output
|
||||||
cd html ; ../scripts/git-update-ghpages nlohmann/json
|
cd html ; ../scripts/git-update-ghpages nlohmann/json
|
||||||
|
@ -70,14 +71,14 @@ upload: clean doxygen check_output
|
||||||
# create docset for Dash
|
# create docset for Dash
|
||||||
docset: create_output
|
docset: create_output
|
||||||
cp Doxyfile Doxyfile_docset
|
cp Doxyfile Doxyfile_docset
|
||||||
gsed -i 's/DISABLE_INDEX = NO/DISABLE_INDEX = YES/' Doxyfile_docset
|
$(SED) -i 's/DISABLE_INDEX = NO/DISABLE_INDEX = YES/' Doxyfile_docset
|
||||||
gsed -i 's/SEARCHENGINE = YES/SEARCHENGINE = NO/' Doxyfile_docset
|
$(SED) -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@HTML_EXTRA_STYLESHEET = css/mylayout.css@HTML_EXTRA_STYLESHEET = css/mylayout_docset.css@' Doxyfile_docset
|
||||||
rm -fr html *.docset
|
rm -fr html *.docset
|
||||||
doxygen Doxyfile_docset
|
doxygen Doxyfile_docset
|
||||||
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
|
||||||
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
|
||||||
make -C html
|
make -C html
|
||||||
mv html/*.docset .
|
mv html/*.docset .
|
||||||
gsed -i 's@<string>doxygen</string>@<string>json</string>@' me.nlohmann.json.docset/Contents/Info.plist
|
$(SED) -i 's@<string>doxygen</string>@<string>json</string>@' me.nlohmann.json.docset/Contents/Info.plist
|
||||||
rm -fr Doxyfile_docset html
|
rm -fr Doxyfile_docset html
|
||||||
|
|
|
@ -12,7 +12,6 @@ int main()
|
||||||
auto count_three = j_object.count("three");
|
auto count_three = j_object.count("three");
|
||||||
|
|
||||||
// print values
|
// print values
|
||||||
std::cout << std::boolalpha;
|
|
||||||
std::cout << "number of elements with key \"two\": " << count_two << '\n';
|
std::cout << "number of elements with key \"two\": " << count_two << '\n';
|
||||||
std::cout << "number of elements with key \"three\": " << count_three << '\n';
|
std::cout << "number of elements with key \"three\": " << count_three << '\n';
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
<a target="_blank" href="http://melpon.org/wandbox/permlink/XoXqF9LlWu8jlNgE"><b>online</b></a>
|
<a target="_blank" href="http://melpon.org/wandbox/permlink/yv5TMrq9qREivvHf"><b>online</b></a>
|
254
src/json.hpp
254
src/json.hpp
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
__ _____ _____ _____
|
__ _____ _____ _____
|
||||||
__| | __| | | | JSON for Modern C++
|
__| | __| | | | JSON for Modern C++
|
||||||
| | |__ | | | | | | version 2.0.0
|
| | |__ | | | | | | version 2.0.1
|
||||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||||
|
|
||||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||||
|
@ -36,7 +36,7 @@ SOFTWARE.
|
||||||
#include <ciso646>
|
#include <ciso646>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdio>
|
#include <cstdint>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <initializer_list>
|
#include <initializer_list>
|
||||||
|
@ -46,6 +46,7 @@ SOFTWARE.
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <numeric>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
@ -53,6 +54,19 @@ SOFTWARE.
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
// 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
|
// disable float-equal warnings on GCC/clang
|
||||||
#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
|
#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
|
||||||
#pragma GCC diagnostic push
|
#pragma GCC diagnostic push
|
||||||
|
@ -76,7 +90,13 @@ namespace
|
||||||
{
|
{
|
||||||
/*!
|
/*!
|
||||||
@brief Helper to determine whether there's a key_type for T.
|
@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
|
@sa http://stackoverflow.com/a/7728728/266378
|
||||||
|
@since version 1.0.0
|
||||||
*/
|
*/
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct has_mapped_type
|
struct has_mapped_type
|
||||||
|
@ -90,11 +110,18 @@ struct has_mapped_type
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@brief helper class to create locales with decimal point
|
@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
|
@sa https://github.com/nlohmann/json/issues/51#issuecomment-86869315
|
||||||
|
@since version 2.0.0
|
||||||
*/
|
*/
|
||||||
class DecimalSeparator : public std::numpunct<char>
|
struct DecimalSeparator : std::numpunct<char>
|
||||||
{
|
{
|
||||||
protected:
|
|
||||||
char do_decimal_point() const
|
char do_decimal_point() const
|
||||||
{
|
{
|
||||||
return '.';
|
return '.';
|
||||||
|
@ -188,13 +215,8 @@ class basic_json
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
/// workaround type for MSVC
|
/// workaround type for MSVC
|
||||||
using basic_json_t = basic_json<ObjectType,
|
using basic_json_t = basic_json<ObjectType, ArrayType, StringType,
|
||||||
ArrayType,
|
BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType,
|
||||||
StringType,
|
|
||||||
BooleanType,
|
|
||||||
NumberIntegerType,
|
|
||||||
NumberUnsignedType,
|
|
||||||
NumberFloatType,
|
|
||||||
AllocatorType>;
|
AllocatorType>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -207,6 +229,8 @@ class basic_json
|
||||||
/////////////////////
|
/////////////////////
|
||||||
|
|
||||||
/// @name 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
|
/// the type of elements in a basic_json container
|
||||||
|
@ -256,6 +280,8 @@ class basic_json
|
||||||
///////////////////////////
|
///////////////////////////
|
||||||
|
|
||||||
/// @name 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.
|
||||||
/// @{
|
/// @{
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -923,6 +949,8 @@ class basic_json
|
||||||
//////////////////
|
//////////////////
|
||||||
|
|
||||||
/// @name constructors and destructors
|
/// @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,
|
bool type_deduction = true,
|
||||||
value_t manual_type = value_t::array)
|
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
|
// check if each element is an array with two elements whose first
|
||||||
// element is a string
|
// 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
|
return element.is_array() and element.size() == 2 and element[0].is_string();
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// adjust type if type deduction is not wanted
|
// adjust type if type deduction is not wanted
|
||||||
if (not type_deduction)
|
if (not type_deduction)
|
||||||
|
@ -1595,10 +1614,10 @@ class basic_json
|
||||||
|
|
||||||
assert(m_value.object != nullptr);
|
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]);
|
m_value.object->emplace(*(element[0].m_value.string), element[1]);
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -2069,19 +2088,20 @@ class basic_json
|
||||||
///////////////////////
|
///////////////////////
|
||||||
|
|
||||||
/// @name object inspection
|
/// @name object inspection
|
||||||
|
/// Functions to inspect the type of a JSON value.
|
||||||
/// @{
|
/// @{
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@brief serialization
|
@brief serialization
|
||||||
|
|
||||||
Serialization function for JSON values. The function tries to mimic
|
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.
|
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
|
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
|
`0` will only insert newlines. `-1` (the default) selects the most compact
|
||||||
representation
|
representation.
|
||||||
|
|
||||||
@return string containing the serialization of the JSON value
|
@return string containing the serialization of the JSON value
|
||||||
|
|
||||||
|
@ -2097,6 +2117,8 @@ class basic_json
|
||||||
string_t dump(const int indent = -1) const
|
string_t dump(const int indent = -1) const
|
||||||
{
|
{
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
|
// fix locale problems
|
||||||
|
ss.imbue(std::locale(std::locale(), new DecimalSeparator));
|
||||||
|
|
||||||
if (indent >= 0)
|
if (indent >= 0)
|
||||||
{
|
{
|
||||||
|
@ -2765,6 +2787,7 @@ class basic_json
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/// @name value access
|
/// @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
|
Explicit pointer access to the internally stored JSON value. No copies are
|
||||||
made.
|
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
|
@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,
|
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
|
@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,
|
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
|
@return pointer to the internally stored JSON value if the requested
|
||||||
pointer type @a PointerType fits to the JSON value; `nullptr` otherwise
|
pointer type @a PointerType fits to the JSON value; `nullptr` otherwise
|
||||||
|
@ -2890,6 +2915,21 @@ class basic_json
|
||||||
, int>::type = 0>
|
, int>::type = 0>
|
||||||
PointerType get_ptr() noexcept
|
PointerType get_ptr() noexcept
|
||||||
{
|
{
|
||||||
|
// get the type of the PointerType (remove pointer and const)
|
||||||
|
using pointee_t = typename std::remove_const<typename
|
||||||
|
std::remove_pointer<typename
|
||||||
|
std::remove_const<PointerType>::type>::type>::type;
|
||||||
|
// make sure the type matches the allowed types
|
||||||
|
static_assert(
|
||||||
|
std::is_same<object_t, pointee_t>::value
|
||||||
|
or std::is_same<array_t, pointee_t>::value
|
||||||
|
or std::is_same<string_t, pointee_t>::value
|
||||||
|
or std::is_same<boolean_t, pointee_t>::value
|
||||||
|
or std::is_same<number_integer_t, pointee_t>::value
|
||||||
|
or std::is_same<number_unsigned_t, pointee_t>::value
|
||||||
|
or std::is_same<number_float_t, pointee_t>::value
|
||||||
|
, "incompatible pointer type");
|
||||||
|
|
||||||
// delegate the call to get_impl_ptr<>()
|
// delegate the call to get_impl_ptr<>()
|
||||||
return get_impl_ptr(static_cast<PointerType>(nullptr));
|
return get_impl_ptr(static_cast<PointerType>(nullptr));
|
||||||
}
|
}
|
||||||
|
@ -2905,6 +2945,21 @@ class basic_json
|
||||||
, int>::type = 0>
|
, int>::type = 0>
|
||||||
constexpr const PointerType get_ptr() const noexcept
|
constexpr const PointerType get_ptr() const noexcept
|
||||||
{
|
{
|
||||||
|
// get the type of the PointerType (remove pointer and const)
|
||||||
|
using pointee_t = typename std::remove_const<typename
|
||||||
|
std::remove_pointer<typename
|
||||||
|
std::remove_const<PointerType>::type>::type>::type;
|
||||||
|
// make sure the type matches the allowed types
|
||||||
|
static_assert(
|
||||||
|
std::is_same<object_t, pointee_t>::value
|
||||||
|
or std::is_same<array_t, pointee_t>::value
|
||||||
|
or std::is_same<string_t, pointee_t>::value
|
||||||
|
or std::is_same<boolean_t, pointee_t>::value
|
||||||
|
or std::is_same<number_integer_t, pointee_t>::value
|
||||||
|
or std::is_same<number_unsigned_t, pointee_t>::value
|
||||||
|
or std::is_same<number_float_t, pointee_t>::value
|
||||||
|
, "incompatible pointer type");
|
||||||
|
|
||||||
// delegate the call to get_impl_ptr<>() const
|
// delegate the call to get_impl_ptr<>() const
|
||||||
return get_impl_ptr(static_cast<const PointerType>(nullptr));
|
return get_impl_ptr(static_cast<const PointerType>(nullptr));
|
||||||
}
|
}
|
||||||
|
@ -2920,7 +2975,7 @@ class basic_json
|
||||||
|
|
||||||
@tparam ReferenceType reference type; must be a reference to @ref array_t,
|
@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 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
|
@return reference to the internally stored JSON value if the requested
|
||||||
reference type @a ReferenceType fits to the JSON value; throws
|
reference type @a ReferenceType fits to the JSON value; throws
|
||||||
|
@ -3010,6 +3065,7 @@ class basic_json
|
||||||
////////////////////
|
////////////////////
|
||||||
|
|
||||||
/// @name element access
|
/// @name element access
|
||||||
|
/// Access to the JSON value.
|
||||||
/// @{
|
/// @{
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -3233,11 +3289,13 @@ class basic_json
|
||||||
// operator[] only works for arrays
|
// operator[] only works for arrays
|
||||||
if (is_array())
|
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);
|
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);
|
return m_value.array->operator[](idx);
|
||||||
|
@ -5655,9 +5713,14 @@ class basic_json
|
||||||
|
|
||||||
// reset width to 0 for subsequent calls to this stream
|
// reset width to 0 for subsequent calls to this stream
|
||||||
o.width(0);
|
o.width(0);
|
||||||
|
// fix locale problems
|
||||||
|
auto old_locale = o.imbue(std::locale(std::locale(), new DecimalSeparator));
|
||||||
|
|
||||||
// do the actual serialization
|
// do the actual serialization
|
||||||
j.dump(o, pretty_print, static_cast<unsigned int>(indentation));
|
j.dump(o, pretty_print, static_cast<unsigned int>(indentation));
|
||||||
|
|
||||||
|
// reset locale
|
||||||
|
o.imbue(old_locale);
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5794,7 +5857,7 @@ class basic_json
|
||||||
///////////////////////////
|
///////////////////////////
|
||||||
|
|
||||||
/// return the type as string
|
/// return the type as string
|
||||||
string_t type_name() const noexcept
|
std::string type_name() const
|
||||||
{
|
{
|
||||||
switch (m_type)
|
switch (m_type)
|
||||||
{
|
{
|
||||||
|
@ -5825,9 +5888,8 @@ class basic_json
|
||||||
*/
|
*/
|
||||||
static std::size_t extra_space(const string_t& s) noexcept
|
static std::size_t extra_space(const string_t& s) noexcept
|
||||||
{
|
{
|
||||||
std::size_t result = 0;
|
return std::accumulate(s.begin(), s.end(), size_t{},
|
||||||
|
[](size_t res, typename string_t::value_type c)
|
||||||
for (const auto& c : s)
|
|
||||||
{
|
{
|
||||||
switch (c)
|
switch (c)
|
||||||
{
|
{
|
||||||
|
@ -5840,8 +5902,7 @@ class basic_json
|
||||||
case '\t':
|
case '\t':
|
||||||
{
|
{
|
||||||
// from c (1 byte) to \x (2 bytes)
|
// from c (1 byte) to \x (2 bytes)
|
||||||
result += 1;
|
return res + 1;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -5849,14 +5910,15 @@ class basic_json
|
||||||
if (c >= 0x00 and c <= 0x1f)
|
if (c >= 0x00 and c <= 0x1f)
|
||||||
{
|
{
|
||||||
// from c (1 byte) to \uxxxx (6 bytes)
|
// from c (1 byte) to \uxxxx (6 bytes)
|
||||||
result += 5;
|
return res + 5;
|
||||||
}
|
}
|
||||||
break;
|
else
|
||||||
|
{
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
});
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -5950,16 +6012,15 @@ class basic_json
|
||||||
{
|
{
|
||||||
// convert a number 0..15 to its hex representation
|
// convert a number 0..15 to its hex representation
|
||||||
// (0..f)
|
// (0..f)
|
||||||
const auto hexify = [](const int v) -> char
|
static const char hexify[16] =
|
||||||
{
|
{
|
||||||
return (v < 10)
|
'0', '1', '2', '3', '4', '5', '6', '7',
|
||||||
? ('0' + static_cast<char>(v))
|
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
|
||||||
: ('a' + static_cast<char>((v - 10) & 0x1f));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// print character c as \uxxxx
|
// print character c as \uxxxx
|
||||||
for (const char m :
|
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;
|
result[++pos] = m;
|
||||||
|
@ -6128,11 +6189,8 @@ class basic_json
|
||||||
// string->double->string or string->long
|
// string->double->string or string->long
|
||||||
// double->string; to be safe, we read this value from
|
// double->string; to be safe, we read this value from
|
||||||
// std::numeric_limits<number_float_t>::digits10
|
// std::numeric_limits<number_float_t>::digits10
|
||||||
std::stringstream ss;
|
o << std::setprecision(std::numeric_limits<double>::digits10)
|
||||||
ss.imbue(std::locale(std::locale(), new DecimalSeparator)); // fix locale problems
|
|
||||||
ss << std::setprecision(std::numeric_limits<double>::digits10)
|
|
||||||
<< m_value.number_float;
|
<< m_value.number_float;
|
||||||
o << ss.str();
|
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -6609,13 +6667,13 @@ class basic_json
|
||||||
{
|
{
|
||||||
case basic_json::value_t::object:
|
case basic_json::value_t::object:
|
||||||
{
|
{
|
||||||
++m_it.object_iterator;
|
std::advance(m_it.object_iterator, 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case basic_json::value_t::array:
|
case basic_json::value_t::array:
|
||||||
{
|
{
|
||||||
++m_it.array_iterator;
|
std::advance(m_it.array_iterator, 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6646,13 +6704,13 @@ class basic_json
|
||||||
{
|
{
|
||||||
case basic_json::value_t::object:
|
case basic_json::value_t::object:
|
||||||
{
|
{
|
||||||
--m_it.object_iterator;
|
std::advance(m_it.object_iterator, -1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case basic_json::value_t::array:
|
case basic_json::value_t::array:
|
||||||
{
|
{
|
||||||
--m_it.array_iterator;
|
std::advance(m_it.array_iterator, -1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6764,7 +6822,7 @@ class basic_json
|
||||||
|
|
||||||
case basic_json::value_t::array:
|
case basic_json::value_t::array:
|
||||||
{
|
{
|
||||||
m_it.array_iterator += i;
|
std::advance(m_it.array_iterator, i);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6838,7 +6896,7 @@ class basic_json
|
||||||
|
|
||||||
case basic_json::value_t::array:
|
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:
|
case basic_json::value_t::null:
|
||||||
|
@ -7333,6 +7391,8 @@ class basic_json
|
||||||
@return the class of the next token read from the buffer
|
@return the class of the next token read from the buffer
|
||||||
*/
|
*/
|
||||||
token_type scan() noexcept
|
token_type scan() noexcept
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
{
|
{
|
||||||
// pointer for backtracking information
|
// pointer for backtracking information
|
||||||
m_marker = nullptr;
|
m_marker = nullptr;
|
||||||
|
@ -7502,13 +7562,15 @@ class basic_json
|
||||||
basic_json_parser_2:
|
basic_json_parser_2:
|
||||||
++m_cursor;
|
++m_cursor;
|
||||||
{
|
{
|
||||||
return token_type::end_of_input;
|
last_token_type = token_type::end_of_input;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
basic_json_parser_4:
|
basic_json_parser_4:
|
||||||
++m_cursor;
|
++m_cursor;
|
||||||
basic_json_parser_5:
|
basic_json_parser_5:
|
||||||
{
|
{
|
||||||
return token_type::parse_error;
|
last_token_type = token_type::parse_error;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
basic_json_parser_6:
|
basic_json_parser_6:
|
||||||
++m_cursor;
|
++m_cursor;
|
||||||
|
@ -7522,7 +7584,7 @@ basic_json_parser_6:
|
||||||
goto basic_json_parser_6;
|
goto basic_json_parser_6;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
return scan();
|
continue;
|
||||||
}
|
}
|
||||||
basic_json_parser_9:
|
basic_json_parser_9:
|
||||||
yyaccept = 0;
|
yyaccept = 0;
|
||||||
|
@ -7535,7 +7597,8 @@ basic_json_parser_9:
|
||||||
basic_json_parser_10:
|
basic_json_parser_10:
|
||||||
++m_cursor;
|
++m_cursor;
|
||||||
{
|
{
|
||||||
return token_type::value_separator;
|
last_token_type = token_type::value_separator;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
basic_json_parser_12:
|
basic_json_parser_12:
|
||||||
yych = *++m_cursor;
|
yych = *++m_cursor;
|
||||||
|
@ -7575,7 +7638,8 @@ basic_json_parser_13:
|
||||||
}
|
}
|
||||||
basic_json_parser_14:
|
basic_json_parser_14:
|
||||||
{
|
{
|
||||||
return token_type::value_number;
|
last_token_type = token_type::value_number;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
basic_json_parser_15:
|
basic_json_parser_15:
|
||||||
yyaccept = 1;
|
yyaccept = 1;
|
||||||
|
@ -7612,17 +7676,20 @@ basic_json_parser_15:
|
||||||
basic_json_parser_17:
|
basic_json_parser_17:
|
||||||
++m_cursor;
|
++m_cursor;
|
||||||
{
|
{
|
||||||
return token_type::name_separator;
|
last_token_type = token_type::name_separator;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
basic_json_parser_19:
|
basic_json_parser_19:
|
||||||
++m_cursor;
|
++m_cursor;
|
||||||
{
|
{
|
||||||
return token_type::begin_array;
|
last_token_type = token_type::begin_array;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
basic_json_parser_21:
|
basic_json_parser_21:
|
||||||
++m_cursor;
|
++m_cursor;
|
||||||
{
|
{
|
||||||
return token_type::end_array;
|
last_token_type = token_type::end_array;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
basic_json_parser_23:
|
basic_json_parser_23:
|
||||||
yyaccept = 0;
|
yyaccept = 0;
|
||||||
|
@ -7651,12 +7718,14 @@ basic_json_parser_25:
|
||||||
basic_json_parser_26:
|
basic_json_parser_26:
|
||||||
++m_cursor;
|
++m_cursor;
|
||||||
{
|
{
|
||||||
return token_type::begin_object;
|
last_token_type = token_type::begin_object;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
basic_json_parser_28:
|
basic_json_parser_28:
|
||||||
++m_cursor;
|
++m_cursor;
|
||||||
{
|
{
|
||||||
return token_type::end_object;
|
last_token_type = token_type::end_object;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
basic_json_parser_30:
|
basic_json_parser_30:
|
||||||
yyaccept = 0;
|
yyaccept = 0;
|
||||||
|
@ -7700,7 +7769,8 @@ basic_json_parser_33:
|
||||||
basic_json_parser_34:
|
basic_json_parser_34:
|
||||||
++m_cursor;
|
++m_cursor;
|
||||||
{
|
{
|
||||||
return token_type::value_string;
|
last_token_type = token_type::value_string;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
basic_json_parser_36:
|
basic_json_parser_36:
|
||||||
++m_cursor;
|
++m_cursor;
|
||||||
|
@ -7963,7 +8033,7 @@ basic_json_parser_51:
|
||||||
basic_json_parser_52:
|
basic_json_parser_52:
|
||||||
++m_cursor;
|
++m_cursor;
|
||||||
{
|
{
|
||||||
return scan();
|
continue;
|
||||||
}
|
}
|
||||||
basic_json_parser_54:
|
basic_json_parser_54:
|
||||||
++m_cursor;
|
++m_cursor;
|
||||||
|
@ -8010,12 +8080,14 @@ basic_json_parser_55:
|
||||||
basic_json_parser_56:
|
basic_json_parser_56:
|
||||||
++m_cursor;
|
++m_cursor;
|
||||||
{
|
{
|
||||||
return token_type::literal_null;
|
last_token_type = token_type::literal_null;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
basic_json_parser_58:
|
basic_json_parser_58:
|
||||||
++m_cursor;
|
++m_cursor;
|
||||||
{
|
{
|
||||||
return token_type::literal_true;
|
last_token_type = token_type::literal_true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
basic_json_parser_60:
|
basic_json_parser_60:
|
||||||
++m_cursor;
|
++m_cursor;
|
||||||
|
@ -8055,7 +8127,8 @@ basic_json_parser_60:
|
||||||
basic_json_parser_61:
|
basic_json_parser_61:
|
||||||
++m_cursor;
|
++m_cursor;
|
||||||
{
|
{
|
||||||
return token_type::literal_false;
|
last_token_type = token_type::literal_false;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
basic_json_parser_63:
|
basic_json_parser_63:
|
||||||
++m_cursor;
|
++m_cursor;
|
||||||
|
@ -8096,6 +8169,9 @@ basic_json_parser_63:
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return last_token_type;
|
||||||
|
}
|
||||||
|
|
||||||
/// append data from the stream to the internal buffer
|
/// append data from the stream to the internal buffer
|
||||||
void yyfill() noexcept
|
void yyfill() noexcept
|
||||||
{
|
{
|
||||||
|
@ -8123,7 +8199,7 @@ basic_json_parser_63:
|
||||||
}
|
}
|
||||||
|
|
||||||
/// return string representation of last read token
|
/// return string representation of last read token
|
||||||
string_t get_token() const
|
string_t get_token_string() const
|
||||||
{
|
{
|
||||||
assert(m_start != nullptr);
|
assert(m_start != nullptr);
|
||||||
return string_t(reinterpret_cast<typename string_t::const_pointer>(m_start),
|
return string_t(reinterpret_cast<typename string_t::const_pointer>(m_start),
|
||||||
|
@ -8391,7 +8467,7 @@ basic_json_parser_63:
|
||||||
if (type != value_t::number_float)
|
if (type != value_t::number_float)
|
||||||
{
|
{
|
||||||
// multiply last value by ten and add the new digit
|
// 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
|
// test for overflow
|
||||||
if (temp < value || temp > max)
|
if (temp < value || temp > max)
|
||||||
|
@ -8441,6 +8517,8 @@ basic_json_parser_63:
|
||||||
const lexer_char_t* m_cursor = nullptr;
|
const lexer_char_t* m_cursor = nullptr;
|
||||||
/// pointer to the end of the buffer
|
/// pointer to the end of the buffer
|
||||||
const lexer_char_t* m_limit = nullptr;
|
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
|
// return parser result and replace it with null in case the
|
||||||
// top-level value was discarded by the callback function
|
// 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:
|
private:
|
||||||
|
@ -8684,7 +8762,8 @@ basic_json_parser_63:
|
||||||
if (t != last_token)
|
if (t != last_token)
|
||||||
{
|
{
|
||||||
std::string error_msg = "parse error - unexpected ";
|
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));
|
lexer::token_type_name(last_token));
|
||||||
error_msg += "; expected " + lexer::token_type_name(t);
|
error_msg += "; expected " + lexer::token_type_name(t);
|
||||||
throw std::invalid_argument(error_msg);
|
throw std::invalid_argument(error_msg);
|
||||||
|
@ -8696,7 +8775,8 @@ basic_json_parser_63:
|
||||||
if (t == last_token)
|
if (t == last_token)
|
||||||
{
|
{
|
||||||
std::string error_msg = "parse error - unexpected ";
|
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));
|
lexer::token_type_name(last_token));
|
||||||
throw std::invalid_argument(error_msg);
|
throw std::invalid_argument(error_msg);
|
||||||
}
|
}
|
||||||
|
@ -8774,14 +8854,12 @@ basic_json_parser_63:
|
||||||
*/
|
*/
|
||||||
std::string to_string() const noexcept
|
std::string to_string() const noexcept
|
||||||
{
|
{
|
||||||
std::string result;
|
return std::accumulate(reference_tokens.begin(),
|
||||||
|
reference_tokens.end(), std::string{},
|
||||||
for (const auto& reference_token : reference_tokens)
|
[](const std::string & a, const std::string & b)
|
||||||
{
|
{
|
||||||
result += "/" + escape(reference_token);
|
return a + "/" + escape(b);
|
||||||
}
|
});
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @copydoc to_string()
|
/// @copydoc to_string()
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
__ _____ _____ _____
|
__ _____ _____ _____
|
||||||
__| | __| | | | JSON for Modern C++
|
__| | __| | | | JSON for Modern C++
|
||||||
| | |__ | | | | | | version 2.0.0
|
| | |__ | | | | | | version 2.0.1
|
||||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||||
|
|
||||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||||
|
@ -36,7 +36,7 @@ SOFTWARE.
|
||||||
#include <ciso646>
|
#include <ciso646>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdio>
|
#include <cstdint>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <initializer_list>
|
#include <initializer_list>
|
||||||
|
@ -46,6 +46,7 @@ SOFTWARE.
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <numeric>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
@ -53,6 +54,19 @@ SOFTWARE.
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
// 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
|
// disable float-equal warnings on GCC/clang
|
||||||
#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
|
#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
|
||||||
#pragma GCC diagnostic push
|
#pragma GCC diagnostic push
|
||||||
|
@ -76,7 +90,13 @@ namespace
|
||||||
{
|
{
|
||||||
/*!
|
/*!
|
||||||
@brief Helper to determine whether there's a key_type for T.
|
@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
|
@sa http://stackoverflow.com/a/7728728/266378
|
||||||
|
@since version 1.0.0
|
||||||
*/
|
*/
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct has_mapped_type
|
struct has_mapped_type
|
||||||
|
@ -90,11 +110,18 @@ struct has_mapped_type
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@brief helper class to create locales with decimal point
|
@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
|
@sa https://github.com/nlohmann/json/issues/51#issuecomment-86869315
|
||||||
|
@since version 2.0.0
|
||||||
*/
|
*/
|
||||||
class DecimalSeparator : public std::numpunct<char>
|
struct DecimalSeparator : std::numpunct<char>
|
||||||
{
|
{
|
||||||
protected:
|
|
||||||
char do_decimal_point() const
|
char do_decimal_point() const
|
||||||
{
|
{
|
||||||
return '.';
|
return '.';
|
||||||
|
@ -188,13 +215,8 @@ class basic_json
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
/// workaround type for MSVC
|
/// workaround type for MSVC
|
||||||
using basic_json_t = basic_json<ObjectType,
|
using basic_json_t = basic_json<ObjectType, ArrayType, StringType,
|
||||||
ArrayType,
|
BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType,
|
||||||
StringType,
|
|
||||||
BooleanType,
|
|
||||||
NumberIntegerType,
|
|
||||||
NumberUnsignedType,
|
|
||||||
NumberFloatType,
|
|
||||||
AllocatorType>;
|
AllocatorType>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -207,6 +229,8 @@ class basic_json
|
||||||
/////////////////////
|
/////////////////////
|
||||||
|
|
||||||
/// @name 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
|
/// the type of elements in a basic_json container
|
||||||
|
@ -256,6 +280,8 @@ class basic_json
|
||||||
///////////////////////////
|
///////////////////////////
|
||||||
|
|
||||||
/// @name 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.
|
||||||
/// @{
|
/// @{
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -923,6 +949,8 @@ class basic_json
|
||||||
//////////////////
|
//////////////////
|
||||||
|
|
||||||
/// @name constructors and destructors
|
/// @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,
|
bool type_deduction = true,
|
||||||
value_t manual_type = value_t::array)
|
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
|
// check if each element is an array with two elements whose first
|
||||||
// element is a string
|
// 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
|
return element.is_array() and element.size() == 2 and element[0].is_string();
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// adjust type if type deduction is not wanted
|
// adjust type if type deduction is not wanted
|
||||||
if (not type_deduction)
|
if (not type_deduction)
|
||||||
|
@ -1595,10 +1614,10 @@ class basic_json
|
||||||
|
|
||||||
assert(m_value.object != nullptr);
|
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]);
|
m_value.object->emplace(*(element[0].m_value.string), element[1]);
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -2069,19 +2088,20 @@ class basic_json
|
||||||
///////////////////////
|
///////////////////////
|
||||||
|
|
||||||
/// @name object inspection
|
/// @name object inspection
|
||||||
|
/// Functions to inspect the type of a JSON value.
|
||||||
/// @{
|
/// @{
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@brief serialization
|
@brief serialization
|
||||||
|
|
||||||
Serialization function for JSON values. The function tries to mimic
|
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.
|
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
|
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
|
`0` will only insert newlines. `-1` (the default) selects the most compact
|
||||||
representation
|
representation.
|
||||||
|
|
||||||
@return string containing the serialization of the JSON value
|
@return string containing the serialization of the JSON value
|
||||||
|
|
||||||
|
@ -2097,6 +2117,8 @@ class basic_json
|
||||||
string_t dump(const int indent = -1) const
|
string_t dump(const int indent = -1) const
|
||||||
{
|
{
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
|
// fix locale problems
|
||||||
|
ss.imbue(std::locale(std::locale(), new DecimalSeparator));
|
||||||
|
|
||||||
if (indent >= 0)
|
if (indent >= 0)
|
||||||
{
|
{
|
||||||
|
@ -2765,6 +2787,7 @@ class basic_json
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/// @name value access
|
/// @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
|
Explicit pointer access to the internally stored JSON value. No copies are
|
||||||
made.
|
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
|
@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,
|
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
|
@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,
|
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
|
@return pointer to the internally stored JSON value if the requested
|
||||||
pointer type @a PointerType fits to the JSON value; `nullptr` otherwise
|
pointer type @a PointerType fits to the JSON value; `nullptr` otherwise
|
||||||
|
@ -2890,6 +2915,21 @@ class basic_json
|
||||||
, int>::type = 0>
|
, int>::type = 0>
|
||||||
PointerType get_ptr() noexcept
|
PointerType get_ptr() noexcept
|
||||||
{
|
{
|
||||||
|
// get the type of the PointerType (remove pointer and const)
|
||||||
|
using pointee_t = typename std::remove_const<typename
|
||||||
|
std::remove_pointer<typename
|
||||||
|
std::remove_const<PointerType>::type>::type>::type;
|
||||||
|
// make sure the type matches the allowed types
|
||||||
|
static_assert(
|
||||||
|
std::is_same<object_t, pointee_t>::value
|
||||||
|
or std::is_same<array_t, pointee_t>::value
|
||||||
|
or std::is_same<string_t, pointee_t>::value
|
||||||
|
or std::is_same<boolean_t, pointee_t>::value
|
||||||
|
or std::is_same<number_integer_t, pointee_t>::value
|
||||||
|
or std::is_same<number_unsigned_t, pointee_t>::value
|
||||||
|
or std::is_same<number_float_t, pointee_t>::value
|
||||||
|
, "incompatible pointer type");
|
||||||
|
|
||||||
// delegate the call to get_impl_ptr<>()
|
// delegate the call to get_impl_ptr<>()
|
||||||
return get_impl_ptr(static_cast<PointerType>(nullptr));
|
return get_impl_ptr(static_cast<PointerType>(nullptr));
|
||||||
}
|
}
|
||||||
|
@ -2905,6 +2945,21 @@ class basic_json
|
||||||
, int>::type = 0>
|
, int>::type = 0>
|
||||||
constexpr const PointerType get_ptr() const noexcept
|
constexpr const PointerType get_ptr() const noexcept
|
||||||
{
|
{
|
||||||
|
// get the type of the PointerType (remove pointer and const)
|
||||||
|
using pointee_t = typename std::remove_const<typename
|
||||||
|
std::remove_pointer<typename
|
||||||
|
std::remove_const<PointerType>::type>::type>::type;
|
||||||
|
// make sure the type matches the allowed types
|
||||||
|
static_assert(
|
||||||
|
std::is_same<object_t, pointee_t>::value
|
||||||
|
or std::is_same<array_t, pointee_t>::value
|
||||||
|
or std::is_same<string_t, pointee_t>::value
|
||||||
|
or std::is_same<boolean_t, pointee_t>::value
|
||||||
|
or std::is_same<number_integer_t, pointee_t>::value
|
||||||
|
or std::is_same<number_unsigned_t, pointee_t>::value
|
||||||
|
or std::is_same<number_float_t, pointee_t>::value
|
||||||
|
, "incompatible pointer type");
|
||||||
|
|
||||||
// delegate the call to get_impl_ptr<>() const
|
// delegate the call to get_impl_ptr<>() const
|
||||||
return get_impl_ptr(static_cast<const PointerType>(nullptr));
|
return get_impl_ptr(static_cast<const PointerType>(nullptr));
|
||||||
}
|
}
|
||||||
|
@ -2920,7 +2975,7 @@ class basic_json
|
||||||
|
|
||||||
@tparam ReferenceType reference type; must be a reference to @ref array_t,
|
@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 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
|
@return reference to the internally stored JSON value if the requested
|
||||||
reference type @a ReferenceType fits to the JSON value; throws
|
reference type @a ReferenceType fits to the JSON value; throws
|
||||||
|
@ -3010,6 +3065,7 @@ class basic_json
|
||||||
////////////////////
|
////////////////////
|
||||||
|
|
||||||
/// @name element access
|
/// @name element access
|
||||||
|
/// Access to the JSON value.
|
||||||
/// @{
|
/// @{
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -3233,11 +3289,13 @@ class basic_json
|
||||||
// operator[] only works for arrays
|
// operator[] only works for arrays
|
||||||
if (is_array())
|
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);
|
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);
|
return m_value.array->operator[](idx);
|
||||||
|
@ -5655,9 +5713,14 @@ class basic_json
|
||||||
|
|
||||||
// reset width to 0 for subsequent calls to this stream
|
// reset width to 0 for subsequent calls to this stream
|
||||||
o.width(0);
|
o.width(0);
|
||||||
|
// fix locale problems
|
||||||
|
auto old_locale = o.imbue(std::locale(std::locale(), new DecimalSeparator));
|
||||||
|
|
||||||
// do the actual serialization
|
// do the actual serialization
|
||||||
j.dump(o, pretty_print, static_cast<unsigned int>(indentation));
|
j.dump(o, pretty_print, static_cast<unsigned int>(indentation));
|
||||||
|
|
||||||
|
// reset locale
|
||||||
|
o.imbue(old_locale);
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5794,7 +5857,7 @@ class basic_json
|
||||||
///////////////////////////
|
///////////////////////////
|
||||||
|
|
||||||
/// return the type as string
|
/// return the type as string
|
||||||
string_t type_name() const noexcept
|
std::string type_name() const
|
||||||
{
|
{
|
||||||
switch (m_type)
|
switch (m_type)
|
||||||
{
|
{
|
||||||
|
@ -5825,9 +5888,8 @@ class basic_json
|
||||||
*/
|
*/
|
||||||
static std::size_t extra_space(const string_t& s) noexcept
|
static std::size_t extra_space(const string_t& s) noexcept
|
||||||
{
|
{
|
||||||
std::size_t result = 0;
|
return std::accumulate(s.begin(), s.end(), size_t{},
|
||||||
|
[](size_t res, typename string_t::value_type c)
|
||||||
for (const auto& c : s)
|
|
||||||
{
|
{
|
||||||
switch (c)
|
switch (c)
|
||||||
{
|
{
|
||||||
|
@ -5840,8 +5902,7 @@ class basic_json
|
||||||
case '\t':
|
case '\t':
|
||||||
{
|
{
|
||||||
// from c (1 byte) to \x (2 bytes)
|
// from c (1 byte) to \x (2 bytes)
|
||||||
result += 1;
|
return res + 1;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -5849,14 +5910,15 @@ class basic_json
|
||||||
if (c >= 0x00 and c <= 0x1f)
|
if (c >= 0x00 and c <= 0x1f)
|
||||||
{
|
{
|
||||||
// from c (1 byte) to \uxxxx (6 bytes)
|
// from c (1 byte) to \uxxxx (6 bytes)
|
||||||
result += 5;
|
return res + 5;
|
||||||
}
|
}
|
||||||
break;
|
else
|
||||||
|
{
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
});
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -5950,16 +6012,15 @@ class basic_json
|
||||||
{
|
{
|
||||||
// convert a number 0..15 to its hex representation
|
// convert a number 0..15 to its hex representation
|
||||||
// (0..f)
|
// (0..f)
|
||||||
const auto hexify = [](const int v) -> char
|
static const char hexify[16] =
|
||||||
{
|
{
|
||||||
return (v < 10)
|
'0', '1', '2', '3', '4', '5', '6', '7',
|
||||||
? ('0' + static_cast<char>(v))
|
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
|
||||||
: ('a' + static_cast<char>((v - 10) & 0x1f));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// print character c as \uxxxx
|
// print character c as \uxxxx
|
||||||
for (const char m :
|
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;
|
result[++pos] = m;
|
||||||
|
@ -6128,11 +6189,8 @@ class basic_json
|
||||||
// string->double->string or string->long
|
// string->double->string or string->long
|
||||||
// double->string; to be safe, we read this value from
|
// double->string; to be safe, we read this value from
|
||||||
// std::numeric_limits<number_float_t>::digits10
|
// std::numeric_limits<number_float_t>::digits10
|
||||||
std::stringstream ss;
|
o << std::setprecision(std::numeric_limits<double>::digits10)
|
||||||
ss.imbue(std::locale(std::locale(), new DecimalSeparator)); // fix locale problems
|
|
||||||
ss << std::setprecision(std::numeric_limits<double>::digits10)
|
|
||||||
<< m_value.number_float;
|
<< m_value.number_float;
|
||||||
o << ss.str();
|
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -6609,13 +6667,13 @@ class basic_json
|
||||||
{
|
{
|
||||||
case basic_json::value_t::object:
|
case basic_json::value_t::object:
|
||||||
{
|
{
|
||||||
++m_it.object_iterator;
|
std::advance(m_it.object_iterator, 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case basic_json::value_t::array:
|
case basic_json::value_t::array:
|
||||||
{
|
{
|
||||||
++m_it.array_iterator;
|
std::advance(m_it.array_iterator, 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6646,13 +6704,13 @@ class basic_json
|
||||||
{
|
{
|
||||||
case basic_json::value_t::object:
|
case basic_json::value_t::object:
|
||||||
{
|
{
|
||||||
--m_it.object_iterator;
|
std::advance(m_it.object_iterator, -1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case basic_json::value_t::array:
|
case basic_json::value_t::array:
|
||||||
{
|
{
|
||||||
--m_it.array_iterator;
|
std::advance(m_it.array_iterator, -1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6764,7 +6822,7 @@ class basic_json
|
||||||
|
|
||||||
case basic_json::value_t::array:
|
case basic_json::value_t::array:
|
||||||
{
|
{
|
||||||
m_it.array_iterator += i;
|
std::advance(m_it.array_iterator, i);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6838,7 +6896,7 @@ class basic_json
|
||||||
|
|
||||||
case basic_json::value_t::array:
|
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:
|
case basic_json::value_t::null:
|
||||||
|
@ -7333,6 +7391,8 @@ class basic_json
|
||||||
@return the class of the next token read from the buffer
|
@return the class of the next token read from the buffer
|
||||||
*/
|
*/
|
||||||
token_type scan() noexcept
|
token_type scan() noexcept
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
{
|
{
|
||||||
// pointer for backtracking information
|
// pointer for backtracking information
|
||||||
m_marker = nullptr;
|
m_marker = nullptr;
|
||||||
|
@ -7354,24 +7414,24 @@ class basic_json
|
||||||
|
|
||||||
// ignore whitespace
|
// ignore whitespace
|
||||||
ws = [ \t\n\r]+;
|
ws = [ \t\n\r]+;
|
||||||
ws { return scan(); }
|
ws { continue; }
|
||||||
|
|
||||||
// ignore byte-order-mark
|
// ignore byte-order-mark
|
||||||
bom = "\xEF\xBB\xBF";
|
bom = "\xEF\xBB\xBF";
|
||||||
bom { return scan(); }
|
bom { continue; }
|
||||||
|
|
||||||
// structural characters
|
// structural characters
|
||||||
"[" { return token_type::begin_array; }
|
"[" { last_token_type = token_type::begin_array; break; }
|
||||||
"]" { return token_type::end_array; }
|
"]" { last_token_type = token_type::end_array; break; }
|
||||||
"{" { return token_type::begin_object; }
|
"{" { last_token_type = token_type::begin_object; break; }
|
||||||
"}" { return token_type::end_object; }
|
"}" { last_token_type = token_type::end_object; break; }
|
||||||
"," { return token_type::value_separator; }
|
"," { last_token_type = token_type::value_separator; break; }
|
||||||
":" { return token_type::name_separator; }
|
":" { last_token_type = token_type::name_separator; break; }
|
||||||
|
|
||||||
// literal names
|
// literal names
|
||||||
"null" { return token_type::literal_null; }
|
"null" { last_token_type = token_type::literal_null; break; }
|
||||||
"true" { return token_type::literal_true; }
|
"true" { last_token_type = token_type::literal_true; break; }
|
||||||
"false" { return token_type::literal_false; }
|
"false" { last_token_type = token_type::literal_false; break; }
|
||||||
|
|
||||||
// number
|
// number
|
||||||
decimal_point = [.];
|
decimal_point = [.];
|
||||||
|
@ -7385,7 +7445,7 @@ class basic_json
|
||||||
frac = decimal_point digit+;
|
frac = decimal_point digit+;
|
||||||
int = (zero|digit_1_9 digit*);
|
int = (zero|digit_1_9 digit*);
|
||||||
number = minus? int frac? exp?;
|
number = minus? int frac? exp?;
|
||||||
number { return token_type::value_number; }
|
number { last_token_type = token_type::value_number; break; }
|
||||||
|
|
||||||
// string
|
// string
|
||||||
quotation_mark = ["];
|
quotation_mark = ["];
|
||||||
|
@ -7396,16 +7456,19 @@ class basic_json
|
||||||
escaped = escape (single_escaped | unicode_escaped);
|
escaped = escape (single_escaped | unicode_escaped);
|
||||||
char = unescaped | escaped;
|
char = unescaped | escaped;
|
||||||
string = quotation_mark char* quotation_mark;
|
string = quotation_mark char* quotation_mark;
|
||||||
string { return token_type::value_string; }
|
string { last_token_type = token_type::value_string; break; }
|
||||||
|
|
||||||
// end of file
|
// end of file
|
||||||
'\000' { return token_type::end_of_input; }
|
'\000' { last_token_type = token_type::end_of_input; break; }
|
||||||
|
|
||||||
// anything else is an error
|
// anything else is an error
|
||||||
. { return token_type::parse_error; }
|
. { last_token_type = token_type::parse_error; break; }
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return last_token_type;
|
||||||
|
}
|
||||||
|
|
||||||
/// append data from the stream to the internal buffer
|
/// append data from the stream to the internal buffer
|
||||||
void yyfill() noexcept
|
void yyfill() noexcept
|
||||||
{
|
{
|
||||||
|
@ -7433,7 +7496,7 @@ class basic_json
|
||||||
}
|
}
|
||||||
|
|
||||||
/// return string representation of last read token
|
/// return string representation of last read token
|
||||||
string_t get_token() const
|
string_t get_token_string() const
|
||||||
{
|
{
|
||||||
assert(m_start != nullptr);
|
assert(m_start != nullptr);
|
||||||
return string_t(reinterpret_cast<typename string_t::const_pointer>(m_start),
|
return string_t(reinterpret_cast<typename string_t::const_pointer>(m_start),
|
||||||
|
@ -7701,7 +7764,7 @@ class basic_json
|
||||||
if (type != value_t::number_float)
|
if (type != value_t::number_float)
|
||||||
{
|
{
|
||||||
// multiply last value by ten and add the new digit
|
// 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
|
// test for overflow
|
||||||
if (temp < value || temp > max)
|
if (temp < value || temp > max)
|
||||||
|
@ -7751,6 +7814,8 @@ class basic_json
|
||||||
const lexer_char_t* m_cursor = nullptr;
|
const lexer_char_t* m_cursor = nullptr;
|
||||||
/// pointer to the end of the buffer
|
/// pointer to the end of the buffer
|
||||||
const lexer_char_t* m_limit = nullptr;
|
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
|
// return parser result and replace it with null in case the
|
||||||
// top-level value was discarded by the callback function
|
// 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:
|
private:
|
||||||
|
@ -7994,7 +8059,8 @@ class basic_json
|
||||||
if (t != last_token)
|
if (t != last_token)
|
||||||
{
|
{
|
||||||
std::string error_msg = "parse error - unexpected ";
|
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));
|
lexer::token_type_name(last_token));
|
||||||
error_msg += "; expected " + lexer::token_type_name(t);
|
error_msg += "; expected " + lexer::token_type_name(t);
|
||||||
throw std::invalid_argument(error_msg);
|
throw std::invalid_argument(error_msg);
|
||||||
|
@ -8006,7 +8072,8 @@ class basic_json
|
||||||
if (t == last_token)
|
if (t == last_token)
|
||||||
{
|
{
|
||||||
std::string error_msg = "parse error - unexpected ";
|
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));
|
lexer::token_type_name(last_token));
|
||||||
throw std::invalid_argument(error_msg);
|
throw std::invalid_argument(error_msg);
|
||||||
}
|
}
|
||||||
|
@ -8084,14 +8151,12 @@ class basic_json
|
||||||
*/
|
*/
|
||||||
std::string to_string() const noexcept
|
std::string to_string() const noexcept
|
||||||
{
|
{
|
||||||
std::string result;
|
return std::accumulate(reference_tokens.begin(),
|
||||||
|
reference_tokens.end(), std::string{},
|
||||||
for (const auto& reference_token : reference_tokens)
|
[](const std::string & a, const std::string & b)
|
||||||
{
|
{
|
||||||
result += "/" + escape(reference_token);
|
return a + "/" + escape(b);
|
||||||
}
|
});
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @copydoc to_string()
|
/// @copydoc to_string()
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
__ _____ _____ _____
|
__ _____ _____ _____
|
||||||
__| | __| | | | JSON for Modern C++ (test suite)
|
__| | __| | | | JSON for Modern C++ (test suite)
|
||||||
| | |__ | | | | | | version 2.0.0
|
| | |__ | | | | | | version 2.0.1
|
||||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||||
|
|
||||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||||
|
@ -10308,6 +10308,11 @@ TEST_CASE("parser class")
|
||||||
|
|
||||||
TEST_CASE("README", "[hide]")
|
TEST_CASE("README", "[hide]")
|
||||||
{
|
{
|
||||||
|
{
|
||||||
|
// redirect std::cout for the README file
|
||||||
|
auto old_cout_buffer = std::cout.rdbuf();
|
||||||
|
std::ostringstream new_stream;
|
||||||
|
std::cout.rdbuf(new_stream.rdbuf());
|
||||||
{
|
{
|
||||||
// create an empty structure (null)
|
// create an empty structure (null)
|
||||||
json j;
|
json j;
|
||||||
|
@ -10531,7 +10536,7 @@ TEST_CASE("README", "[hide]")
|
||||||
})"_json;
|
})"_json;
|
||||||
|
|
||||||
// access members with a JSON pointer (RFC 6901)
|
// access members with a JSON pointer (RFC 6901)
|
||||||
j_original["/baz/2"_json_pointer];
|
j_original["/baz/1"_json_pointer];
|
||||||
// "two"
|
// "two"
|
||||||
|
|
||||||
// a JSON patch (RFC 6902)
|
// a JSON patch (RFC 6902)
|
||||||
|
@ -10556,6 +10561,10 @@ TEST_CASE("README", "[hide]")
|
||||||
// { "op":"add","path":"/foo","value":"bar" }
|
// { "op":"add","path":"/foo","value":"bar" }
|
||||||
// ]
|
// ]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// restore old std::cout
|
||||||
|
std::cout.rdbuf(old_cout_buffer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("algorithms")
|
TEST_CASE("algorithms")
|
||||||
|
@ -14079,6 +14088,16 @@ TEST_CASE("regression tests")
|
||||||
CHECK(j1a.dump() == "23.42");
|
CHECK(j1a.dump() == "23.42");
|
||||||
CHECK(j1b.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");
|
CHECK(j2a.dump() == "23.42");
|
||||||
//issue #230
|
//issue #230
|
||||||
//CHECK(j2b.dump() == "23.42");
|
//CHECK(j2b.dump() == "23.42");
|
||||||
|
|
Loading…
Reference in a new issue