Merge branch 'develop' into coverity_scan

This commit is contained in:
Niels 2016-07-19 22:49:17 +02:00
commit ea19be1736
8 changed files with 1231 additions and 1049 deletions

View File

@ -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)

View File

@ -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<std::string, int> 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).

View File

@ -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@&lt; ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberFloatType, AllocatorType &gt;@@g' html/*.html
gsed -i 's@&lt;&#160;ObjectType,&#160;ArrayType,&#160;StringType,&#160;BooleanType,&#160;NumberIntegerType,&#160;NumberFloatType,&#160;AllocatorType&#160;&gt;@@g' html/*.html
gsed -i 's@&lt; ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType &gt;@@g' html/*.html
gsed -i 's@< ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType >@@g' html/*.html
$(SED) -i 's@&lt; ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberFloatType, AllocatorType &gt;@@g' html/*.html
$(SED) -i 's@&lt;&#160;ObjectType,&#160;ArrayType,&#160;StringType,&#160;BooleanType,&#160;NumberIntegerType,&#160;NumberFloatType,&#160;AllocatorType&#160;&gt;@@g' html/*.html
$(SED) -i 's@&lt; ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType &gt;@@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@&lt; ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberFloatType, AllocatorType &gt;@@g' html/*.html
gsed -i 's@&lt;&#160;ObjectType,&#160;ArrayType,&#160;StringType,&#160;BooleanType,&#160;NumberIntegerType,&#160;NumberFloatType,&#160;AllocatorType&#160;&gt;@@g' html/*.html
$(SED) -i 's@&lt; ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberFloatType, AllocatorType &gt;@@g' html/*.html
$(SED) -i 's@&lt;&#160;ObjectType,&#160;ArrayType,&#160;StringType,&#160;BooleanType,&#160;NumberIntegerType,&#160;NumberFloatType,&#160;AllocatorType&#160;&gt;@@g' html/*.html
make -C html
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

View File

@ -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';
}

View File

@ -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>

File diff suppressed because it is too large Load Diff

View File

@ -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 <http://opensource.org/licenses/MIT>.
@ -36,7 +36,7 @@ SOFTWARE.
#include <ciso646>
#include <cmath>
#include <cstddef>
#include <cstdio>
#include <cstdint>
#include <cstdlib>
#include <functional>
#include <initializer_list>
@ -46,6 +46,7 @@ SOFTWARE.
#include <limits>
#include <map>
#include <memory>
#include <numeric>
#include <sstream>
#include <stdexcept>
#include <string>
@ -53,6 +54,19 @@ SOFTWARE.
#include <utility>
#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
#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<typename T>
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<char>
struct DecimalSeparator : std::numpunct<char>
{
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<ObjectType,
ArrayType,
StringType,
BooleanType,
NumberIntegerType,
NumberUnsignedType,
NumberFloatType,
using basic_json_t = basic_json<ObjectType, ArrayType, StringType,
BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType,
AllocatorType>;
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<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<>()
return get_impl_ptr(static_cast<PointerType>(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<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
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,
@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<unsigned int>(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<char>(v))
: ('a' + static_cast<char>((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<number_float_t>::digits10
std::stringstream ss;
ss.imbue(std::locale(std::locale(), new DecimalSeparator)); // fix locale problems
ss << std::setprecision(std::numeric_limits<double>::digits10)
<< m_value.number_float;
o << ss.str();
o << std::setprecision(std::numeric_limits<double>::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<typename string_t::const_pointer>(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()

View File

@ -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 <http://opensource.org/licenses/MIT>.
@ -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<int> c_vector {1, 2, 3, 4};
json j_vec(c_vector);
// [1, 2, 3, 4]
std::deque<float> 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<bool> c_list {true, true, false, true};
json j_list(c_list);
// [true, true, false, true]
std::forward_list<int64_t> c_flist {12345678909876, 23456789098765, 34567890987654, 45678909876543};
json j_flist(c_flist);
// [12345678909876, 23456789098765, 34567890987654, 45678909876543]
std::array<unsigned long, 4> c_array {{1, 2, 3, 4}};
json j_array(c_array);
// [1, 2, 3, 4]
std::set<std::string> 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<std::string> 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<std::string> 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<std::string> c_umset {"one", "two", "one", "four"};
json j_umset(c_umset); // both entries for "one" are used
// maybe ["one", "two", "one", "four"]
}
}
{
std::vector<int> c_vector {1, 2, 3, 4};
json j_vec(c_vector);
// [1, 2, 3, 4]
{
std::map<std::string, int> c_map { {"one", 1}, {"two", 2}, {"three", 3} };
json j_map(c_map);
// {"one": 1, "two": 2, "three": 3}
std::deque<float> 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<const char*, float> 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<bool> c_list {true, true, false, true};
json j_list(c_list);
// [true, true, false, true]
std::multimap<std::string, bool> 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<int64_t> c_flist {12345678909876, 23456789098765, 34567890987654, 45678909876543};
json j_flist(c_flist);
// [12345678909876, 23456789098765, 34567890987654, 45678909876543]
std::unordered_multimap<std::string, bool> 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<unsigned long, 4> 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<std::string> 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<std::string> 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<std::string> 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<std::string> 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<std::string>();
bool vb = jb.get<bool>();
int vi = jn.get<int>();
{
std::map<std::string, int> c_map { {"one", 1}, {"two", 2}, {"three", 3} };
json j_map(c_map);
// {"one": 1, "two": 2, "three": 3}
// etc.
}
std::unordered_map<const char*, float> 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<std::string, bool> 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<std::string, bool> 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<std::string>();
bool vb = jb.get<bool>();
int vi = jn.get<int>();
// 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");