Merge branch 'feature/iterator_range_parsing' into develop
This commit is contained in:
commit
776880bc49
18 changed files with 1075 additions and 498 deletions
10
.github/CONTRIBUTING.md
vendored
10
.github/CONTRIBUTING.md
vendored
|
@ -41,16 +41,10 @@ There are currently two files which need to be edited:
|
|||
|
||||
2. [`test/src/unit.cpp`](https://github.com/nlohmann/json/blob/master/test/unit.cpp) - This contains the [Catch](https://github.com/philsquared/Catch) unit tests which currently cover [100 %](https://coveralls.io/github/nlohmann/json) of the library's code.
|
||||
|
||||
If you add or change a feature, please also add a unit test to this file. The unit tests can be compiled with
|
||||
If you add or change a feature, please also add a unit test to this file. The unit tests can be compiled and executed with
|
||||
|
||||
```sh
|
||||
make
|
||||
```
|
||||
|
||||
and can be executed with
|
||||
|
||||
```sh
|
||||
./json_unit
|
||||
make check
|
||||
```
|
||||
|
||||
The test cases are also executed with several different compilers on [Travis](https://travis-ci.org/nlohmann/json) once you open a pull request.
|
||||
|
|
|
@ -492,6 +492,8 @@ I deeply appreciate the help of the following people.
|
|||
- [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.
|
||||
- [Thomas Braun](https://github.com/t-b) fixed a warning in a test case.
|
||||
- [Théo DELRIEU](https://github.com/theodelrieu) patiently and constructively oversaw the long way toward [iterator-range parsing](https://github.com/nlohmann/json/issues/290).
|
||||
|
||||
Thanks a lot for helping out!
|
||||
|
||||
|
@ -510,7 +512,7 @@ To compile and run the tests, you need to execute
|
|||
$ make check
|
||||
|
||||
===============================================================================
|
||||
All tests passed (8905099 assertions in 32 test cases)
|
||||
All tests passed (8905154 assertions in 35 test cases)
|
||||
```
|
||||
|
||||
For more information, have a look at the file [.travis.yml](https://github.com/nlohmann/json/blob/master/.travis.yml).
|
||||
|
|
28
doc/examples/parse__array__parser_callback_t.cpp
Normal file
28
doc/examples/parse__array__parser_callback_t.cpp
Normal file
|
@ -0,0 +1,28 @@
|
|||
#include <json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
int main()
|
||||
{
|
||||
// a JSON text
|
||||
char text[] = R"(
|
||||
{
|
||||
"Image": {
|
||||
"Width": 800,
|
||||
"Height": 600,
|
||||
"Title": "View from 15th Floor",
|
||||
"Thumbnail": {
|
||||
"Url": "http://www.example.com/image/481989943",
|
||||
"Height": 125,
|
||||
"Width": 100
|
||||
},
|
||||
"Animated" : false,
|
||||
"IDs": [116, 943, 234, 38793]
|
||||
}
|
||||
}
|
||||
)";
|
||||
|
||||
// parse and serialize JSON
|
||||
json j_complete = json::parse(text);
|
||||
std::cout << std::setw(4) << j_complete << "\n\n";
|
||||
}
|
1
doc/examples/parse__array__parser_callback_t.link
Normal file
1
doc/examples/parse__array__parser_callback_t.link
Normal file
|
@ -0,0 +1 @@
|
|||
<a target="_blank" href="http://melpon.org/wandbox/permlink/CwZnqGqte14SYJ5s"><b>online</b></a>
|
20
doc/examples/parse__array__parser_callback_t.output
Normal file
20
doc/examples/parse__array__parser_callback_t.output
Normal file
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"Image": {
|
||||
"Animated": false,
|
||||
"Height": 600,
|
||||
"IDs": [
|
||||
116,
|
||||
943,
|
||||
234,
|
||||
38793
|
||||
],
|
||||
"Thumbnail": {
|
||||
"Height": 125,
|
||||
"Url": "http://www.example.com/image/481989943",
|
||||
"Width": 100
|
||||
},
|
||||
"Title": "View from 15th Floor",
|
||||
"Width": 800
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
#include <json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
int main()
|
||||
{
|
||||
// a JSON text given as std::vector
|
||||
std::vector<uint8_t> text = {'[', '1', ',', '2', ',', '3', ']', '\0'};
|
||||
|
||||
// parse and serialize JSON
|
||||
json j_complete = json::parse(text);
|
||||
std::cout << std::setw(4) << j_complete << "\n\n";
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
<a target="_blank" href="http://melpon.org/wandbox/permlink/F8VaVFyys87qQRt5"><b>online</b></a>
|
|
@ -0,0 +1,6 @@
|
|||
[
|
||||
1,
|
||||
2,
|
||||
3
|
||||
]
|
||||
|
13
doc/examples/parse__iteratortype__parser_callback_t.cpp
Normal file
13
doc/examples/parse__iteratortype__parser_callback_t.cpp
Normal file
|
@ -0,0 +1,13 @@
|
|||
#include <json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
int main()
|
||||
{
|
||||
// a JSON text given as std::vector
|
||||
std::vector<uint8_t> text = {'[', '1', ',', '2', ',', '3', ']', '\0'};
|
||||
|
||||
// parse and serialize JSON
|
||||
json j_complete = json::parse(text.begin(), text.end());
|
||||
std::cout << std::setw(4) << j_complete << "\n\n";
|
||||
}
|
1
doc/examples/parse__iteratortype__parser_callback_t.link
Normal file
1
doc/examples/parse__iteratortype__parser_callback_t.link
Normal file
|
@ -0,0 +1 @@
|
|||
<a target="_blank" href="http://melpon.org/wandbox/permlink/ojh4Eeol4G9RgeRV"><b>online</b></a>
|
|
@ -0,0 +1,6 @@
|
|||
[
|
||||
1,
|
||||
2,
|
||||
3
|
||||
]
|
||||
|
|
@ -5,7 +5,7 @@ using json = nlohmann::json;
|
|||
int main()
|
||||
{
|
||||
// a JSON text
|
||||
std::string text = R"(
|
||||
auto text = R"(
|
||||
{
|
||||
"Image": {
|
||||
"Width": 800,
|
||||
|
@ -44,4 +44,4 @@ int main()
|
|||
// parse (with callback) and serialize JSON
|
||||
json j_filtered = json::parse(text, cb);
|
||||
std::cout << std::setw(4) << j_filtered << '\n';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
<a target="_blank" href="http://melpon.org/wandbox/permlink/SrKpkE9ivmvd2OUy"><b>online</b></a>
|
||||
<a target="_blank" href="http://melpon.org/wandbox/permlink/n888UNQlMFduURhE"><b>online</b></a>
|
605
src/json.hpp
605
src/json.hpp
File diff suppressed because it is too large
Load diff
|
@ -37,6 +37,7 @@ SOFTWARE.
|
|||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
#include <initializer_list>
|
||||
#include <iomanip>
|
||||
|
@ -959,7 +960,7 @@ class basic_json
|
|||
|
||||
With a parser callback function, the result of parsing a JSON text can be
|
||||
influenced. When passed to @ref parse(std::istream&, const
|
||||
parser_callback_t) or @ref parse(const string_t&, const parser_callback_t),
|
||||
parser_callback_t) or @ref parse(const char*, const parser_callback_t),
|
||||
it is called on certain events (passed as @ref parse_event_t via parameter
|
||||
@a event) with a set recursion depth @a depth and context JSON value
|
||||
@a parsed. The return value of the callback function is a boolean
|
||||
|
@ -1002,7 +1003,7 @@ class basic_json
|
|||
skipped completely or replaced by an empty discarded object.
|
||||
|
||||
@sa @ref parse(std::istream&, parser_callback_t) or
|
||||
@ref parse(const string_t&, parser_callback_t) for examples
|
||||
@ref parse(const char*, parser_callback_t) for examples
|
||||
|
||||
@since version 1.0.0
|
||||
*/
|
||||
|
@ -1140,11 +1141,9 @@ class basic_json
|
|||
|
||||
@since version 1.0.0
|
||||
*/
|
||||
template <class CompatibleObjectType, typename
|
||||
std::enable_if<
|
||||
std::is_constructible<typename object_t::key_type, typename CompatibleObjectType::key_type>::value and
|
||||
std::is_constructible<basic_json, typename CompatibleObjectType::mapped_type>::value, int>::type
|
||||
= 0>
|
||||
template<class CompatibleObjectType, typename std::enable_if<
|
||||
std::is_constructible<typename object_t::key_type, typename CompatibleObjectType::key_type>::value and
|
||||
std::is_constructible<basic_json, typename CompatibleObjectType::mapped_type>::value, int>::type = 0>
|
||||
basic_json(const CompatibleObjectType& val)
|
||||
: m_type(value_t::object)
|
||||
{
|
||||
|
@ -1205,16 +1204,14 @@ class basic_json
|
|||
|
||||
@since version 1.0.0
|
||||
*/
|
||||
template <class CompatibleArrayType, typename
|
||||
std::enable_if<
|
||||
not std::is_same<CompatibleArrayType, typename basic_json_t::iterator>::value and
|
||||
not std::is_same<CompatibleArrayType, typename basic_json_t::const_iterator>::value and
|
||||
not std::is_same<CompatibleArrayType, typename basic_json_t::reverse_iterator>::value and
|
||||
not std::is_same<CompatibleArrayType, typename basic_json_t::const_reverse_iterator>::value and
|
||||
not std::is_same<CompatibleArrayType, typename array_t::iterator>::value and
|
||||
not std::is_same<CompatibleArrayType, typename array_t::const_iterator>::value and
|
||||
std::is_constructible<basic_json, typename CompatibleArrayType::value_type>::value, int>::type
|
||||
= 0>
|
||||
template<class CompatibleArrayType, typename std::enable_if<
|
||||
not std::is_same<CompatibleArrayType, typename basic_json_t::iterator>::value and
|
||||
not std::is_same<CompatibleArrayType, typename basic_json_t::const_iterator>::value and
|
||||
not std::is_same<CompatibleArrayType, typename basic_json_t::reverse_iterator>::value and
|
||||
not std::is_same<CompatibleArrayType, typename basic_json_t::const_reverse_iterator>::value and
|
||||
not std::is_same<CompatibleArrayType, typename array_t::iterator>::value and
|
||||
not std::is_same<CompatibleArrayType, typename array_t::const_iterator>::value and
|
||||
std::is_constructible<basic_json, typename CompatibleArrayType::value_type>::value, int>::type = 0>
|
||||
basic_json(const CompatibleArrayType& val)
|
||||
: m_type(value_t::array)
|
||||
{
|
||||
|
@ -1300,10 +1297,8 @@ class basic_json
|
|||
|
||||
@since version 1.0.0
|
||||
*/
|
||||
template <class CompatibleStringType, typename
|
||||
std::enable_if<
|
||||
std::is_constructible<string_t, CompatibleStringType>::value, int>::type
|
||||
= 0>
|
||||
template<class CompatibleStringType, typename std::enable_if<
|
||||
std::is_constructible<string_t, CompatibleStringType>::value, int>::type = 0>
|
||||
basic_json(const CompatibleStringType& val)
|
||||
: basic_json(string_t(val))
|
||||
{
|
||||
|
@ -1353,12 +1348,9 @@ class basic_json
|
|||
|
||||
@since version 1.0.0
|
||||
*/
|
||||
template<typename T,
|
||||
typename std::enable_if<
|
||||
not (std::is_same<T, int>::value)
|
||||
and std::is_same<T, number_integer_t>::value
|
||||
, int>::type
|
||||
= 0>
|
||||
template<typename T, typename std::enable_if<
|
||||
not (std::is_same<T, int>::value) and
|
||||
std::is_same<T, number_integer_t>::value, int>::type = 0>
|
||||
basic_json(const number_integer_t val) noexcept
|
||||
: m_type(value_t::number_integer), m_value(val)
|
||||
{
|
||||
|
@ -1422,13 +1414,11 @@ class basic_json
|
|||
|
||||
@since version 1.0.0
|
||||
*/
|
||||
template<typename CompatibleNumberIntegerType, typename
|
||||
std::enable_if<
|
||||
template<typename CompatibleNumberIntegerType, typename std::enable_if<
|
||||
std::is_constructible<number_integer_t, CompatibleNumberIntegerType>::value and
|
||||
std::numeric_limits<CompatibleNumberIntegerType>::is_integer and
|
||||
std::numeric_limits<CompatibleNumberIntegerType>::is_signed,
|
||||
CompatibleNumberIntegerType>::type
|
||||
= 0>
|
||||
CompatibleNumberIntegerType>::type = 0>
|
||||
basic_json(const CompatibleNumberIntegerType val) noexcept
|
||||
: m_type(value_t::number_integer),
|
||||
m_value(static_cast<number_integer_t>(val))
|
||||
|
@ -1453,12 +1443,9 @@ class basic_json
|
|||
|
||||
@since version 2.0.0
|
||||
*/
|
||||
template<typename T,
|
||||
typename std::enable_if<
|
||||
not (std::is_same<T, int>::value)
|
||||
and std::is_same<T, number_unsigned_t>::value
|
||||
, int>::type
|
||||
= 0>
|
||||
template<typename T, typename std::enable_if<
|
||||
not (std::is_same<T, int>::value) and
|
||||
std::is_same<T, number_unsigned_t>::value, int>::type = 0>
|
||||
basic_json(const number_unsigned_t val) noexcept
|
||||
: m_type(value_t::number_unsigned), m_value(val)
|
||||
{
|
||||
|
@ -1485,13 +1472,11 @@ class basic_json
|
|||
|
||||
@since version 2.0.0
|
||||
*/
|
||||
template <typename CompatibleNumberUnsignedType, typename
|
||||
std::enable_if <
|
||||
std::is_constructible<number_unsigned_t, CompatibleNumberUnsignedType>::value and
|
||||
std::numeric_limits<CompatibleNumberUnsignedType>::is_integer and
|
||||
not std::numeric_limits<CompatibleNumberUnsignedType>::is_signed,
|
||||
CompatibleNumberUnsignedType>::type
|
||||
= 0>
|
||||
template<typename CompatibleNumberUnsignedType, typename std::enable_if <
|
||||
std::is_constructible<number_unsigned_t, CompatibleNumberUnsignedType>::value and
|
||||
std::numeric_limits<CompatibleNumberUnsignedType>::is_integer and
|
||||
not std::numeric_limits<CompatibleNumberUnsignedType>::is_signed,
|
||||
CompatibleNumberUnsignedType>::type = 0>
|
||||
basic_json(const CompatibleNumberUnsignedType val) noexcept
|
||||
: m_type(value_t::number_unsigned),
|
||||
m_value(static_cast<number_unsigned_t>(val))
|
||||
|
@ -1567,11 +1552,9 @@ class basic_json
|
|||
|
||||
@since version 1.0.0
|
||||
*/
|
||||
template<typename CompatibleNumberFloatType, typename = typename
|
||||
std::enable_if<
|
||||
template<typename CompatibleNumberFloatType, typename = typename std::enable_if<
|
||||
std::is_constructible<number_float_t, CompatibleNumberFloatType>::value and
|
||||
std::is_floating_point<CompatibleNumberFloatType>::value>::type
|
||||
>
|
||||
std::is_floating_point<CompatibleNumberFloatType>::value>::type>
|
||||
basic_json(const CompatibleNumberFloatType val) noexcept
|
||||
: basic_json(number_float_t(val))
|
||||
{
|
||||
|
@ -1838,12 +1821,9 @@ class basic_json
|
|||
|
||||
@since version 1.0.0
|
||||
*/
|
||||
template <class InputIT, typename
|
||||
std::enable_if<
|
||||
std::is_same<InputIT, typename basic_json_t::iterator>::value or
|
||||
std::is_same<InputIT, typename basic_json_t::const_iterator>::value
|
||||
, int>::type
|
||||
= 0>
|
||||
template<class InputIT, typename std::enable_if<
|
||||
std::is_same<InputIT, typename basic_json_t::iterator>::value or
|
||||
std::is_same<InputIT, typename basic_json_t::const_iterator>::value, int>::type = 0>
|
||||
basic_json(InputIT first, InputIT last)
|
||||
{
|
||||
assert(first.m_object != nullptr);
|
||||
|
@ -2601,11 +2581,9 @@ class basic_json
|
|||
//////////////////
|
||||
|
||||
/// get an object (explicit)
|
||||
template <class T, typename
|
||||
std::enable_if<
|
||||
std::is_convertible<typename object_t::key_type, typename T::key_type>::value and
|
||||
std::is_convertible<basic_json_t, typename T::mapped_type>::value
|
||||
, int>::type = 0>
|
||||
template<class T, typename std::enable_if<
|
||||
std::is_convertible<typename object_t::key_type, typename T::key_type>::value and
|
||||
std::is_convertible<basic_json_t, typename T::mapped_type>::value, int>::type = 0>
|
||||
T get_impl(T*) const
|
||||
{
|
||||
if (is_object())
|
||||
|
@ -2632,14 +2610,12 @@ class basic_json
|
|||
}
|
||||
|
||||
/// get an array (explicit)
|
||||
template <class T, typename
|
||||
std::enable_if<
|
||||
std::is_convertible<basic_json_t, typename T::value_type>::value and
|
||||
not std::is_same<basic_json_t, typename T::value_type>::value and
|
||||
not std::is_arithmetic<T>::value and
|
||||
not std::is_convertible<std::string, T>::value and
|
||||
not has_mapped_type<T>::value
|
||||
, int>::type = 0>
|
||||
template<class T, typename std::enable_if<
|
||||
std::is_convertible<basic_json_t, typename T::value_type>::value and
|
||||
not std::is_same<basic_json_t, typename T::value_type>::value and
|
||||
not std::is_arithmetic<T>::value and
|
||||
not std::is_convertible<std::string, T>::value and
|
||||
not has_mapped_type<T>::value, int>::type = 0>
|
||||
T get_impl(T*) const
|
||||
{
|
||||
if (is_array())
|
||||
|
@ -2659,11 +2635,9 @@ class basic_json
|
|||
}
|
||||
|
||||
/// get an array (explicit)
|
||||
template <class T, typename
|
||||
std::enable_if<
|
||||
std::is_convertible<basic_json_t, T>::value and
|
||||
not std::is_same<basic_json_t, T>::value
|
||||
, int>::type = 0>
|
||||
template<class T, typename std::enable_if<
|
||||
std::is_convertible<basic_json_t, T>::value and
|
||||
not std::is_same<basic_json_t, T>::value, int>::type = 0>
|
||||
std::vector<T> get_impl(std::vector<T>*) const
|
||||
{
|
||||
if (is_array())
|
||||
|
@ -2684,11 +2658,9 @@ class basic_json
|
|||
}
|
||||
|
||||
/// get an array (explicit)
|
||||
template <class T, typename
|
||||
std::enable_if<
|
||||
std::is_same<basic_json, typename T::value_type>::value and
|
||||
not has_mapped_type<T>::value
|
||||
, int>::type = 0>
|
||||
template<class T, typename std::enable_if<
|
||||
std::is_same<basic_json, typename T::value_type>::value and
|
||||
not has_mapped_type<T>::value, int>::type = 0>
|
||||
T get_impl(T*) const
|
||||
{
|
||||
if (is_array())
|
||||
|
@ -2715,10 +2687,8 @@ class basic_json
|
|||
}
|
||||
|
||||
/// get a string (explicit)
|
||||
template <typename T, typename
|
||||
std::enable_if<
|
||||
std::is_convertible<string_t, T>::value
|
||||
, int>::type = 0>
|
||||
template<typename T, typename std::enable_if<
|
||||
std::is_convertible<string_t, T>::value, int>::type = 0>
|
||||
T get_impl(T*) const
|
||||
{
|
||||
if (is_string())
|
||||
|
@ -2732,10 +2702,8 @@ class basic_json
|
|||
}
|
||||
|
||||
/// get a number (explicit)
|
||||
template<typename T, typename
|
||||
std::enable_if<
|
||||
std::is_arithmetic<T>::value
|
||||
, int>::type = 0>
|
||||
template<typename T, typename std::enable_if<
|
||||
std::is_arithmetic<T>::value, int>::type = 0>
|
||||
T get_impl(T*) const
|
||||
{
|
||||
switch (m_type)
|
||||
|
@ -2924,10 +2892,8 @@ class basic_json
|
|||
|
||||
@since version 1.0.0
|
||||
*/
|
||||
template<typename ValueType, typename
|
||||
std::enable_if<
|
||||
not std::is_pointer<ValueType>::value
|
||||
, int>::type = 0>
|
||||
template<typename ValueType, typename std::enable_if<
|
||||
not std::is_pointer<ValueType>::value, int>::type = 0>
|
||||
ValueType get() const
|
||||
{
|
||||
return get_impl(static_cast<ValueType*>(nullptr));
|
||||
|
@ -2960,10 +2926,8 @@ class basic_json
|
|||
|
||||
@since version 1.0.0
|
||||
*/
|
||||
template<typename PointerType, typename
|
||||
std::enable_if<
|
||||
std::is_pointer<PointerType>::value
|
||||
, int>::type = 0>
|
||||
template<typename PointerType, typename std::enable_if<
|
||||
std::is_pointer<PointerType>::value, int>::type = 0>
|
||||
PointerType get() noexcept
|
||||
{
|
||||
// delegate the call to get_ptr
|
||||
|
@ -2974,10 +2938,8 @@ class basic_json
|
|||
@brief get a pointer value (explicit)
|
||||
@copydoc get()
|
||||
*/
|
||||
template<typename PointerType, typename
|
||||
std::enable_if<
|
||||
std::is_pointer<PointerType>::value
|
||||
, int>::type = 0>
|
||||
template<typename PointerType, typename std::enable_if<
|
||||
std::is_pointer<PointerType>::value, int>::type = 0>
|
||||
constexpr const PointerType get() const noexcept
|
||||
{
|
||||
// delegate the call to get_ptr
|
||||
|
@ -3010,10 +2972,8 @@ class basic_json
|
|||
|
||||
@since version 1.0.0
|
||||
*/
|
||||
template<typename PointerType, typename
|
||||
std::enable_if<
|
||||
std::is_pointer<PointerType>::value
|
||||
, int>::type = 0>
|
||||
template<typename PointerType, typename std::enable_if<
|
||||
std::is_pointer<PointerType>::value, int>::type = 0>
|
||||
PointerType get_ptr() noexcept
|
||||
{
|
||||
// get the type of the PointerType (remove pointer and const)
|
||||
|
@ -3039,11 +2999,9 @@ class basic_json
|
|||
@brief get a pointer value (implicit)
|
||||
@copydoc get_ptr()
|
||||
*/
|
||||
template<typename PointerType, typename
|
||||
std::enable_if<
|
||||
std::is_pointer<PointerType>::value
|
||||
and std::is_const<typename std::remove_pointer<PointerType>::type>::value
|
||||
, int>::type = 0>
|
||||
template<typename PointerType, typename std::enable_if<
|
||||
std::is_pointer<PointerType>::value and
|
||||
std::is_const<typename std::remove_pointer<PointerType>::type>::value, int>::type = 0>
|
||||
constexpr const PointerType get_ptr() const noexcept
|
||||
{
|
||||
// get the type of the PointerType (remove pointer and const)
|
||||
|
@ -3091,10 +3049,8 @@ class basic_json
|
|||
|
||||
@since version 1.1.0
|
||||
*/
|
||||
template<typename ReferenceType, typename
|
||||
std::enable_if<
|
||||
std::is_reference<ReferenceType>::value
|
||||
, int>::type = 0>
|
||||
template<typename ReferenceType, typename std::enable_if<
|
||||
std::is_reference<ReferenceType>::value, int>::type = 0>
|
||||
ReferenceType get_ref()
|
||||
{
|
||||
// delegate call to get_ref_impl
|
||||
|
@ -3105,11 +3061,9 @@ class basic_json
|
|||
@brief get a reference value (implicit)
|
||||
@copydoc get_ref()
|
||||
*/
|
||||
template<typename ReferenceType, typename
|
||||
std::enable_if<
|
||||
std::is_reference<ReferenceType>::value
|
||||
and std::is_const<typename std::remove_reference<ReferenceType>::type>::value
|
||||
, int>::type = 0>
|
||||
template<typename ReferenceType, typename std::enable_if<
|
||||
std::is_reference<ReferenceType>::value and
|
||||
std::is_const<typename std::remove_reference<ReferenceType>::type>::value, int>::type = 0>
|
||||
ReferenceType get_ref() const
|
||||
{
|
||||
// delegate call to get_ref_impl
|
||||
|
@ -3144,10 +3098,9 @@ class basic_json
|
|||
|
||||
@since version 1.0.0
|
||||
*/
|
||||
template < typename ValueType, typename
|
||||
std::enable_if <
|
||||
not std::is_pointer<ValueType>::value
|
||||
and not std::is_same<ValueType, typename string_t::value_type>::value
|
||||
template < typename ValueType, typename std::enable_if <
|
||||
not std::is_pointer<ValueType>::value and
|
||||
not std::is_same<ValueType, typename string_t::value_type>::value
|
||||
#ifndef _MSC_VER // Fix for issue #167 operator<< abiguity under VS2015
|
||||
and not std::is_same<ValueType, std::initializer_list<typename string_t::value_type>>::value
|
||||
#endif
|
||||
|
@ -3737,10 +3690,8 @@ class basic_json
|
|||
|
||||
@since version 1.0.0
|
||||
*/
|
||||
template <class ValueType, typename
|
||||
std::enable_if<
|
||||
std::is_convertible<basic_json_t, ValueType>::value
|
||||
, int>::type = 0>
|
||||
template<class ValueType, typename std::enable_if<
|
||||
std::is_convertible<basic_json_t, ValueType>::value, int>::type = 0>
|
||||
ValueType value(const typename object_t::key_type& key, ValueType default_value) const
|
||||
{
|
||||
// at only works for objects
|
||||
|
@ -3813,10 +3764,8 @@ class basic_json
|
|||
|
||||
@since version 2.0.2
|
||||
*/
|
||||
template <class ValueType, typename
|
||||
std::enable_if<
|
||||
std::is_convertible<basic_json_t, ValueType>::value
|
||||
, int>::type = 0>
|
||||
template<class ValueType, typename std::enable_if<
|
||||
std::is_convertible<basic_json_t, ValueType>::value, int>::type = 0>
|
||||
ValueType value(const json_pointer& ptr, ValueType default_value) const
|
||||
{
|
||||
// at only works for objects
|
||||
|
@ -3946,7 +3895,7 @@ class basic_json
|
|||
@return Iterator following the last removed element. If the iterator @a
|
||||
pos refers to the last element, the `end()` iterator is returned.
|
||||
|
||||
@tparam InteratorType an @ref iterator or @ref const_iterator
|
||||
@tparam IteratorType an @ref iterator or @ref const_iterator
|
||||
|
||||
@post Invalidates iterators and references at or after the point of the
|
||||
erase, including the `end()` iterator.
|
||||
|
@ -3968,7 +3917,7 @@ class basic_json
|
|||
@liveexample{The example shows the result of `erase()` for different JSON
|
||||
types.,erase__IteratorType}
|
||||
|
||||
@sa @ref erase(InteratorType, InteratorType) -- removes the elements in
|
||||
@sa @ref erase(IteratorType, IteratorType) -- removes the elements in
|
||||
the given range
|
||||
@sa @ref erase(const typename object_t::key_type&) -- removes the element
|
||||
from an object at the given key
|
||||
|
@ -3977,13 +3926,11 @@ class basic_json
|
|||
|
||||
@since version 1.0.0
|
||||
*/
|
||||
template <class InteratorType, typename
|
||||
std::enable_if<
|
||||
std::is_same<InteratorType, typename basic_json_t::iterator>::value or
|
||||
std::is_same<InteratorType, typename basic_json_t::const_iterator>::value
|
||||
, int>::type
|
||||
= 0>
|
||||
InteratorType erase(InteratorType pos)
|
||||
template<class IteratorType, typename std::enable_if<
|
||||
std::is_same<IteratorType, typename basic_json_t::iterator>::value or
|
||||
std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int>::type
|
||||
= 0>
|
||||
IteratorType erase(IteratorType pos)
|
||||
{
|
||||
// make sure iterator fits the current value
|
||||
if (this != pos.m_object)
|
||||
|
@ -3991,7 +3938,7 @@ class basic_json
|
|||
throw std::domain_error("iterator does not fit current value");
|
||||
}
|
||||
|
||||
InteratorType result = end();
|
||||
IteratorType result = end();
|
||||
|
||||
switch (m_type)
|
||||
{
|
||||
|
@ -4055,7 +4002,7 @@ class basic_json
|
|||
@return Iterator following the last removed element. If the iterator @a
|
||||
second refers to the last element, the `end()` iterator is returned.
|
||||
|
||||
@tparam InteratorType an @ref iterator or @ref const_iterator
|
||||
@tparam IteratorType an @ref iterator or @ref const_iterator
|
||||
|
||||
@post Invalidates iterators and references at or after the point of the
|
||||
erase, including the `end()` iterator.
|
||||
|
@ -4078,7 +4025,7 @@ class basic_json
|
|||
@liveexample{The example shows the result of `erase()` for different JSON
|
||||
types.,erase__IteratorType_IteratorType}
|
||||
|
||||
@sa @ref erase(InteratorType) -- removes the element at a given position
|
||||
@sa @ref erase(IteratorType) -- removes the element at a given position
|
||||
@sa @ref erase(const typename object_t::key_type&) -- removes the element
|
||||
from an object at the given key
|
||||
@sa @ref erase(const size_type) -- removes the element from an array at
|
||||
|
@ -4086,13 +4033,11 @@ class basic_json
|
|||
|
||||
@since version 1.0.0
|
||||
*/
|
||||
template <class InteratorType, typename
|
||||
std::enable_if<
|
||||
std::is_same<InteratorType, typename basic_json_t::iterator>::value or
|
||||
std::is_same<InteratorType, typename basic_json_t::const_iterator>::value
|
||||
, int>::type
|
||||
= 0>
|
||||
InteratorType erase(InteratorType first, InteratorType last)
|
||||
template<class IteratorType, typename std::enable_if<
|
||||
std::is_same<IteratorType, typename basic_json_t::iterator>::value or
|
||||
std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int>::type
|
||||
= 0>
|
||||
IteratorType erase(IteratorType first, IteratorType last)
|
||||
{
|
||||
// make sure iterator fits the current value
|
||||
if (this != first.m_object or this != last.m_object)
|
||||
|
@ -4100,7 +4045,7 @@ class basic_json
|
|||
throw std::domain_error("iterators do not fit current value");
|
||||
}
|
||||
|
||||
InteratorType result = end();
|
||||
IteratorType result = end();
|
||||
|
||||
switch (m_type)
|
||||
{
|
||||
|
@ -4172,8 +4117,8 @@ class basic_json
|
|||
|
||||
@liveexample{The example shows the effect of `erase()`.,erase__key_type}
|
||||
|
||||
@sa @ref erase(InteratorType) -- removes the element at a given position
|
||||
@sa @ref erase(InteratorType, InteratorType) -- removes the elements in
|
||||
@sa @ref erase(IteratorType) -- removes the element at a given position
|
||||
@sa @ref erase(IteratorType, IteratorType) -- removes the elements in
|
||||
the given range
|
||||
@sa @ref erase(const size_type) -- removes the element from an array at
|
||||
the given index
|
||||
|
@ -4209,8 +4154,8 @@ class basic_json
|
|||
|
||||
@liveexample{The example shows the effect of `erase()`.,erase__size_type}
|
||||
|
||||
@sa @ref erase(InteratorType) -- removes the element at a given position
|
||||
@sa @ref erase(InteratorType, InteratorType) -- removes the elements in
|
||||
@sa @ref erase(IteratorType) -- removes the element at a given position
|
||||
@sa @ref erase(IteratorType, IteratorType) -- removes the elements in
|
||||
the given range
|
||||
@sa @ref erase(const typename object_t::key_type&) -- removes the element
|
||||
from an object at the given key
|
||||
|
@ -5918,10 +5863,16 @@ class basic_json
|
|||
/// @{
|
||||
|
||||
/*!
|
||||
@brief deserialize from string
|
||||
@brief deserialize from an array
|
||||
|
||||
@param[in] s string to read a serialized JSON value from
|
||||
@param[in] cb a parser callback function of type @ref parser_callback_t
|
||||
This function reads from an array of 1-byte values.
|
||||
|
||||
@pre Each element of the container has a size of 1 byte. Violating this
|
||||
precondition yields undefined behavior. **This precondition is enforced
|
||||
with a static assertion.**
|
||||
|
||||
@param[in] array array to read from
|
||||
@param[in] cb a parser callback function of type @ref parser_callback_t
|
||||
which is used to control the deserialization by filtering unwanted values
|
||||
(optional)
|
||||
|
||||
|
@ -5933,18 +5884,54 @@ class basic_json
|
|||
|
||||
@note A UTF-8 byte order mark is silently ignored.
|
||||
|
||||
@liveexample{The example below demonstrates the `parse()` function reading
|
||||
from an array.,parse__array__parser_callback_t}
|
||||
|
||||
@since version 2.0.3
|
||||
*/
|
||||
template<class T, std::size_t N>
|
||||
static basic_json parse(T (&array)[N],
|
||||
const parser_callback_t cb = nullptr)
|
||||
{
|
||||
// delegate the call to the iterator-range parse overload
|
||||
return parse(std::begin(array), std::end(array), cb);
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief deserialize from string literal
|
||||
|
||||
@tparam CharT character/literal type with size of 1 byte
|
||||
@param[in] s string literal to read a serialized JSON value from
|
||||
@param[in] cb a parser callback function of type @ref parser_callback_t
|
||||
which is used to control the deserialization by filtering unwanted values
|
||||
(optional)
|
||||
|
||||
@return result of the deserialization
|
||||
|
||||
@complexity Linear in the length of the input. The parser is a predictive
|
||||
LL(1) parser. The complexity can be higher if the parser callback function
|
||||
@a cb has a super-linear complexity.
|
||||
|
||||
@note A UTF-8 byte order mark is silently ignored.
|
||||
@note String containers like `std::string` or @ref string_t can be parsed
|
||||
with @ref parse(const ContiguousContainer&, const parser_callback_t)
|
||||
|
||||
@liveexample{The example below demonstrates the `parse()` function with
|
||||
and without callback function.,parse__string__parser_callback_t}
|
||||
|
||||
@sa @ref parse(std::istream&, const parser_callback_t) for a version that
|
||||
reads from an input stream
|
||||
|
||||
@since version 1.0.0
|
||||
@since version 1.0.0 (originally for @ref string_t)
|
||||
*/
|
||||
static basic_json parse(const string_t& s,
|
||||
template<typename CharPT, typename std::enable_if<
|
||||
std::is_pointer<CharPT>::value and
|
||||
std::is_integral<typename std::remove_pointer<CharPT>::type>::value and
|
||||
sizeof(typename std::remove_pointer<CharPT>::type) == 1, int>::type = 0>
|
||||
static basic_json parse(const CharPT s,
|
||||
const parser_callback_t cb = nullptr)
|
||||
{
|
||||
return parser(s, cb).parse();
|
||||
return parser(reinterpret_cast<const char*>(s), cb).parse();
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -5966,7 +5953,7 @@ class basic_json
|
|||
@liveexample{The example below demonstrates the `parse()` function with
|
||||
and without callback function.,parse__istream__parser_callback_t}
|
||||
|
||||
@sa @ref parse(const string_t&, const parser_callback_t) for a version
|
||||
@sa @ref parse(const char*, const parser_callback_t) for a version
|
||||
that reads from a string
|
||||
|
||||
@since version 1.0.0
|
||||
|
@ -5986,6 +5973,130 @@ class basic_json
|
|||
return parser(i, cb).parse();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief deserialize from an iterator range with contiguous storage
|
||||
|
||||
This function reads from an iterator range of a container with contiguous
|
||||
storage of 1-byte values. Compatible container types include
|
||||
`std::vector`, `std::string`, `std::array`, `std::valarray`, and
|
||||
`std::initializer_list`. Furthermore, C-style arrays can be used with
|
||||
`std::begin()`/`std::end()`. User-defined containers can be used as long
|
||||
as they implement random-access iterators and a contiguous storage.
|
||||
|
||||
@pre The iterator range is contiguous. Violating this precondition yields
|
||||
undefined behavior. **This precondition is enforced with an assertion.**
|
||||
@pre Each element in the range has a size of 1 byte. Violating this
|
||||
precondition yields undefined behavior. **This precondition is enforced
|
||||
with a static assertion.**
|
||||
|
||||
@warning There is no way to enforce all preconditions at compile-time. If
|
||||
the function is called with noncompliant iterators and with
|
||||
assertions switched off, the behavior is undefined and will most
|
||||
likely yield segmentation violation.
|
||||
|
||||
@tparam IteratorType iterator of container with contiguous storage
|
||||
@param[in] first begin of the range to parse (included)
|
||||
@param[in] last end of the range to parse (excluded)
|
||||
@param[in] cb a parser callback function of type @ref parser_callback_t
|
||||
which is used to control the deserialization by filtering unwanted values
|
||||
(optional)
|
||||
|
||||
@return result of the deserialization
|
||||
|
||||
@complexity Linear in the length of the input. The parser is a predictive
|
||||
LL(1) parser. The complexity can be higher if the parser callback function
|
||||
@a cb has a super-linear complexity.
|
||||
|
||||
@note A UTF-8 byte order mark is silently ignored.
|
||||
|
||||
@liveexample{The example below demonstrates the `parse()` function reading
|
||||
from an iterator range.,parse__iteratortype__parser_callback_t}
|
||||
|
||||
@since version 2.0.3
|
||||
*/
|
||||
template<class IteratorType, typename std::enable_if<
|
||||
std::is_base_of<
|
||||
std::random_access_iterator_tag,
|
||||
typename std::iterator_traits<IteratorType>::iterator_category>::value, int>::type = 0>
|
||||
static basic_json parse(IteratorType first, IteratorType last,
|
||||
const parser_callback_t cb = nullptr)
|
||||
{
|
||||
// assertion to check that the iterator range is indeed contiguous,
|
||||
// see http://stackoverflow.com/a/35008842/266378 for more discussion
|
||||
assert(std::accumulate(first, last, std::make_pair<bool, int>(true, 0),
|
||||
[&first](std::pair<bool, int> res, decltype(*first) val)
|
||||
{
|
||||
res.first &= (val == *(std::next(std::addressof(*first), res.second++)));
|
||||
return res;
|
||||
}).first);
|
||||
|
||||
// assertion to check that each element is 1 byte long
|
||||
static_assert(sizeof(typename std::iterator_traits<IteratorType>::value_type) == 1,
|
||||
"each element in the iterator range must have the size of 1 byte");
|
||||
|
||||
// if iterator range is empty, create a parser with an empty string
|
||||
// to generate "unexpected EOF" error message
|
||||
if (std::distance(first, last) <= 0)
|
||||
{
|
||||
return parser("").parse();
|
||||
}
|
||||
|
||||
return parser(first, last, cb).parse();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief deserialize from a container with contiguous storage
|
||||
|
||||
This function reads from a container with contiguous storage of 1-byte
|
||||
values. Compatible container types include `std::vector`, `std::string`,
|
||||
`std::array`, and `std::initializer_list`. User-defined containers can be
|
||||
used as long as they implement random-access iterators and a contiguous
|
||||
storage.
|
||||
|
||||
@pre The container storage is contiguous. Violating this precondition
|
||||
yields undefined behavior. **This precondition is enforced with an
|
||||
assertion.**
|
||||
@pre Each element of the container has a size of 1 byte. Violating this
|
||||
precondition yields undefined behavior. **This precondition is enforced
|
||||
with a static assertion.**
|
||||
|
||||
@warning There is no way to enforce all preconditions at compile-time. If
|
||||
the function is called with a noncompliant container and with
|
||||
assertions switched off, the behavior is undefined and will most
|
||||
likely yield segmentation violation.
|
||||
|
||||
@tparam ContiguousContainer container type with contiguous storage
|
||||
@param[in] c container to read from
|
||||
@param[in] cb a parser callback function of type @ref parser_callback_t
|
||||
which is used to control the deserialization by filtering unwanted values
|
||||
(optional)
|
||||
|
||||
@return result of the deserialization
|
||||
|
||||
@complexity Linear in the length of the input. The parser is a predictive
|
||||
LL(1) parser. The complexity can be higher if the parser callback function
|
||||
@a cb has a super-linear complexity.
|
||||
|
||||
@note A UTF-8 byte order mark is silently ignored.
|
||||
|
||||
@liveexample{The example below demonstrates the `parse()` function reading
|
||||
from a contiguous container.,parse__contiguouscontainer__parser_callback_t}
|
||||
|
||||
@since version 2.0.3
|
||||
*/
|
||||
template<class ContiguousContainer, typename std::enable_if<
|
||||
not std::is_pointer<ContiguousContainer>::value and
|
||||
std::is_base_of<
|
||||
std::random_access_iterator_tag,
|
||||
typename std::iterator_traits<decltype(std::begin(std::declval<ContiguousContainer const>()))>::iterator_category>::value
|
||||
, int>::type = 0>
|
||||
static basic_json parse(const ContiguousContainer& c,
|
||||
const parser_callback_t cb = nullptr)
|
||||
{
|
||||
// delegate the call to the iterator-range parse overload
|
||||
return parse(std::begin(c), std::end(c), cb);
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief deserialize from stream
|
||||
|
||||
|
@ -6039,7 +6150,7 @@ class basic_json
|
|||
Returns the type name as string to be used in error messages - usually to
|
||||
indicate that a function was called on a wrong JSON type.
|
||||
|
||||
@return basically a string representation of a the @ref m_type member
|
||||
@return basically a string representation of a the @a m_type member
|
||||
|
||||
@complexity Constant.
|
||||
|
||||
|
@ -7490,32 +7601,25 @@ class basic_json
|
|||
/// the char type to use in the lexer
|
||||
using lexer_char_t = unsigned char;
|
||||
|
||||
/// constructor with a given buffer
|
||||
explicit lexer(const string_t& s) noexcept
|
||||
: m_stream(nullptr), m_buffer(s)
|
||||
/// a lexer from a buffer with given length
|
||||
lexer(const lexer_char_t* buff, const size_t len) noexcept
|
||||
: m_content(buff)
|
||||
{
|
||||
m_content = reinterpret_cast<const lexer_char_t*>(m_buffer.c_str());
|
||||
assert(m_content != nullptr);
|
||||
m_start = m_cursor = m_content;
|
||||
m_limit = m_content + s.size();
|
||||
m_limit = m_content + len;
|
||||
}
|
||||
|
||||
/// constructor with a given stream
|
||||
explicit lexer(std::istream* s) noexcept
|
||||
: m_stream(s), m_buffer()
|
||||
/// a lexer from an input stream
|
||||
explicit lexer(std::istream& s)
|
||||
: m_stream(&s), m_line_buffer()
|
||||
{
|
||||
assert(m_stream != nullptr);
|
||||
std::getline(*m_stream, m_buffer);
|
||||
m_content = reinterpret_cast<const lexer_char_t*>(m_buffer.c_str());
|
||||
assert(m_content != nullptr);
|
||||
m_start = m_cursor = m_content;
|
||||
m_limit = m_content + m_buffer.size();
|
||||
// fill buffer
|
||||
fill_line_buffer();
|
||||
}
|
||||
|
||||
/// default constructor
|
||||
lexer() = default;
|
||||
|
||||
// switch off unwanted functions
|
||||
// switch off unwanted functions (due to pointer members)
|
||||
lexer() = delete;
|
||||
lexer(const lexer&) = delete;
|
||||
lexer operator=(const lexer&) = delete;
|
||||
|
||||
|
@ -7668,7 +7772,7 @@ class basic_json
|
|||
infinite sequence of whitespace or byte-order-marks. This contradicts
|
||||
the assumption of finite input, q.e.d.
|
||||
*/
|
||||
token_type scan() noexcept
|
||||
token_type scan()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
|
@ -7684,7 +7788,7 @@ class basic_json
|
|||
re2c:define:YYCURSOR = m_cursor;
|
||||
re2c:define:YYLIMIT = m_limit;
|
||||
re2c:define:YYMARKER = m_marker;
|
||||
re2c:define:YYFILL = "yyfill()";
|
||||
re2c:define:YYFILL = "fill_line_buffer()";
|
||||
re2c:yyfill:parameter = 0;
|
||||
re2c:indent:string = " ";
|
||||
re2c:indent:top = 1;
|
||||
|
@ -7747,30 +7851,76 @@ class basic_json
|
|||
return last_token_type;
|
||||
}
|
||||
|
||||
/// append data from the stream to the internal buffer
|
||||
void yyfill() noexcept
|
||||
{
|
||||
if (m_stream == nullptr or not * m_stream)
|
||||
{
|
||||
return;
|
||||
}
|
||||
/*!
|
||||
@brief append data from the stream to the line buffer
|
||||
|
||||
This function is called by the scan() function when the end of the
|
||||
buffer (`m_limit`) is reached and the `m_cursor` pointer cannot be
|
||||
incremented without leaving the limits of the line buffer. Note re2c
|
||||
decides when to call this function.
|
||||
|
||||
If the lexer reads from contiguous storage, there is no trailing null
|
||||
byte. Therefore, this function must make sure to add these padding
|
||||
null bytes.
|
||||
|
||||
If the lexer reads from an input stream, this function reads the next
|
||||
line of the input.
|
||||
|
||||
@pre
|
||||
p p p p p p u u u u u x . . . . . .
|
||||
^ ^ ^ ^
|
||||
m_content m_start | m_limit
|
||||
m_cursor
|
||||
|
||||
@post
|
||||
u u u u u x x x x x x x . . . . . .
|
||||
^ ^ ^
|
||||
| m_cursor m_limit
|
||||
m_start
|
||||
m_content
|
||||
*/
|
||||
void fill_line_buffer()
|
||||
{
|
||||
// number of processed characters (p)
|
||||
const auto offset_start = m_start - m_content;
|
||||
const auto offset_marker = m_marker - m_start;
|
||||
// offset for m_marker wrt. to m_start
|
||||
const auto offset_marker = (m_marker == nullptr) ? 0 : m_marker - m_start;
|
||||
// number of unprocessed characters (u)
|
||||
const auto offset_cursor = m_cursor - m_start;
|
||||
|
||||
m_buffer.erase(0, static_cast<size_t>(offset_start));
|
||||
std::string line;
|
||||
assert(m_stream != nullptr);
|
||||
std::getline(*m_stream, line);
|
||||
m_buffer += "\n" + line; // add line with newline symbol
|
||||
// no stream is used or end of file is reached
|
||||
if (m_stream == nullptr or not * m_stream)
|
||||
{
|
||||
// copy unprocessed characters to line buffer
|
||||
m_line_buffer.clear();
|
||||
for (m_cursor = m_start; m_cursor != m_limit; ++m_cursor)
|
||||
{
|
||||
m_line_buffer.append(1, static_cast<const char>(*m_cursor));
|
||||
}
|
||||
|
||||
m_content = reinterpret_cast<const lexer_char_t*>(m_buffer.c_str());
|
||||
// append 5 characters (size of longest keyword "false") to
|
||||
// make sure that there is sufficient space between m_cursor
|
||||
// and m_limit
|
||||
m_line_buffer.append(5, '\0');
|
||||
}
|
||||
else
|
||||
{
|
||||
// delete processed characters from line buffer
|
||||
m_line_buffer.erase(0, static_cast<size_t>(offset_start));
|
||||
// read next line from input stream
|
||||
std::string line;
|
||||
std::getline(*m_stream, line);
|
||||
// add line with newline symbol to the line buffer
|
||||
m_line_buffer += "\n" + line;
|
||||
}
|
||||
|
||||
// set pointers
|
||||
m_content = reinterpret_cast<const lexer_char_t*>(m_line_buffer.c_str());
|
||||
assert(m_content != nullptr);
|
||||
m_start = m_content;
|
||||
m_marker = m_start + offset_marker;
|
||||
m_cursor = m_start + offset_cursor;
|
||||
m_limit = m_start + m_buffer.size() - 1;
|
||||
m_limit = m_start + m_line_buffer.size();
|
||||
}
|
||||
|
||||
/// return string representation of last read token
|
||||
|
@ -8112,8 +8262,8 @@ class basic_json
|
|||
private:
|
||||
/// optional input stream
|
||||
std::istream* m_stream = nullptr;
|
||||
/// the buffer
|
||||
string_t m_buffer;
|
||||
/// line buffer buffer for m_stream
|
||||
string_t m_line_buffer {};
|
||||
/// the buffer pointer
|
||||
const lexer_char_t* m_content = nullptr;
|
||||
/// pointer to the beginning of the current symbol
|
||||
|
@ -8136,25 +8286,34 @@ class basic_json
|
|||
class parser
|
||||
{
|
||||
public:
|
||||
/// constructor for strings
|
||||
parser(const string_t& s, const parser_callback_t cb = nullptr) noexcept
|
||||
: callback(cb), m_lexer(s)
|
||||
{
|
||||
// read first token
|
||||
get_token();
|
||||
}
|
||||
/// a parser reading from a string literal
|
||||
parser(const char* buff, const parser_callback_t cb = nullptr)
|
||||
: callback(cb),
|
||||
m_lexer(reinterpret_cast<const typename lexer::lexer_char_t*>(buff), strlen(buff))
|
||||
{}
|
||||
|
||||
/// a parser reading from an input stream
|
||||
parser(std::istream& _is, const parser_callback_t cb = nullptr) noexcept
|
||||
: callback(cb), m_lexer(&_is)
|
||||
{
|
||||
// read first token
|
||||
get_token();
|
||||
}
|
||||
parser(std::istream& is, const parser_callback_t cb = nullptr)
|
||||
: callback(cb), m_lexer(is)
|
||||
{}
|
||||
|
||||
/// a parser reading from an iterator range with contiguous storage
|
||||
template<class IteratorType, typename std::enable_if<
|
||||
std::is_same<typename std::iterator_traits<IteratorType>::iterator_category, std::random_access_iterator_tag>::value
|
||||
, int>::type
|
||||
= 0>
|
||||
parser(IteratorType first, IteratorType last, const parser_callback_t cb = nullptr)
|
||||
: callback(cb),
|
||||
m_lexer(reinterpret_cast<const typename lexer::lexer_char_t*>(&(*first)),
|
||||
static_cast<size_t>(std::distance(first, last)))
|
||||
{}
|
||||
|
||||
/// public parser interface
|
||||
basic_json parse()
|
||||
{
|
||||
// read first token
|
||||
get_token();
|
||||
|
||||
basic_json result = parse_internal(true);
|
||||
result.assert_invariant();
|
||||
|
||||
|
@ -8361,7 +8520,7 @@ class basic_json
|
|||
}
|
||||
|
||||
/// get next token from lexer
|
||||
typename lexer::token_type get_token() noexcept
|
||||
typename lexer::token_type get_token()
|
||||
{
|
||||
last_token = m_lexer.scan();
|
||||
return last_token;
|
||||
|
@ -9659,7 +9818,7 @@ namespace std
|
|||
|
||||
@since version 1.0.0
|
||||
*/
|
||||
template <>
|
||||
template<>
|
||||
inline void swap(nlohmann::json& j1,
|
||||
nlohmann::json& j2) noexcept(
|
||||
is_nothrow_move_constructible<nlohmann::json>::value and
|
||||
|
@ -9670,7 +9829,7 @@ inline void swap(nlohmann::json& j1,
|
|||
}
|
||||
|
||||
/// hash value for JSON objects
|
||||
template <>
|
||||
template<>
|
||||
struct hash<nlohmann::json>
|
||||
{
|
||||
/*!
|
||||
|
@ -9701,7 +9860,7 @@ if no parse error occurred.
|
|||
*/
|
||||
inline nlohmann::json operator "" _json(const char* s, std::size_t)
|
||||
{
|
||||
return nlohmann::json::parse(reinterpret_cast<const nlohmann::json::string_t::value_type*>(s));
|
||||
return nlohmann::json::parse(s);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
|
@ -38,43 +38,67 @@ TEST_CASE("lexer class")
|
|||
{
|
||||
SECTION("structural characters")
|
||||
{
|
||||
CHECK(json::lexer("[").scan() == json::lexer::token_type::begin_array);
|
||||
CHECK(json::lexer("]").scan() == json::lexer::token_type::end_array);
|
||||
CHECK(json::lexer("{").scan() == json::lexer::token_type::begin_object);
|
||||
CHECK(json::lexer("}").scan() == json::lexer::token_type::end_object);
|
||||
CHECK(json::lexer(",").scan() == json::lexer::token_type::value_separator);
|
||||
CHECK(json::lexer(":").scan() == json::lexer::token_type::name_separator);
|
||||
CHECK(json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("["),
|
||||
1).scan() == json::lexer::token_type::begin_array);
|
||||
CHECK(json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("]"),
|
||||
1).scan() == json::lexer::token_type::end_array);
|
||||
CHECK(json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("{"),
|
||||
1).scan() == json::lexer::token_type::begin_object);
|
||||
CHECK(json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("}"),
|
||||
1).scan() == json::lexer::token_type::end_object);
|
||||
CHECK(json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>(","),
|
||||
1).scan() == json::lexer::token_type::value_separator);
|
||||
CHECK(json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>(":"),
|
||||
1).scan() == json::lexer::token_type::name_separator);
|
||||
}
|
||||
|
||||
SECTION("literal names")
|
||||
{
|
||||
CHECK(json::lexer("null").scan() == json::lexer::token_type::literal_null);
|
||||
CHECK(json::lexer("true").scan() == json::lexer::token_type::literal_true);
|
||||
CHECK(json::lexer("false").scan() == json::lexer::token_type::literal_false);
|
||||
CHECK(json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("null"),
|
||||
4).scan() == json::lexer::token_type::literal_null);
|
||||
CHECK(json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("true"),
|
||||
4).scan() == json::lexer::token_type::literal_true);
|
||||
CHECK(json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("false"),
|
||||
5).scan() == json::lexer::token_type::literal_false);
|
||||
}
|
||||
|
||||
SECTION("numbers")
|
||||
{
|
||||
CHECK(json::lexer("0").scan() == json::lexer::token_type::value_number);
|
||||
CHECK(json::lexer("1").scan() == json::lexer::token_type::value_number);
|
||||
CHECK(json::lexer("2").scan() == json::lexer::token_type::value_number);
|
||||
CHECK(json::lexer("3").scan() == json::lexer::token_type::value_number);
|
||||
CHECK(json::lexer("4").scan() == json::lexer::token_type::value_number);
|
||||
CHECK(json::lexer("5").scan() == json::lexer::token_type::value_number);
|
||||
CHECK(json::lexer("6").scan() == json::lexer::token_type::value_number);
|
||||
CHECK(json::lexer("7").scan() == json::lexer::token_type::value_number);
|
||||
CHECK(json::lexer("8").scan() == json::lexer::token_type::value_number);
|
||||
CHECK(json::lexer("9").scan() == json::lexer::token_type::value_number);
|
||||
CHECK(json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("0"),
|
||||
1).scan() == json::lexer::token_type::value_number);
|
||||
CHECK(json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("1"),
|
||||
1).scan() == json::lexer::token_type::value_number);
|
||||
CHECK(json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("2"),
|
||||
1).scan() == json::lexer::token_type::value_number);
|
||||
CHECK(json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("3"),
|
||||
1).scan() == json::lexer::token_type::value_number);
|
||||
CHECK(json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("4"),
|
||||
1).scan() == json::lexer::token_type::value_number);
|
||||
CHECK(json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("5"),
|
||||
1).scan() == json::lexer::token_type::value_number);
|
||||
CHECK(json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("6"),
|
||||
1).scan() == json::lexer::token_type::value_number);
|
||||
CHECK(json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("7"),
|
||||
1).scan() == json::lexer::token_type::value_number);
|
||||
CHECK(json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("8"),
|
||||
1).scan() == json::lexer::token_type::value_number);
|
||||
CHECK(json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("9"),
|
||||
1).scan() == json::lexer::token_type::value_number);
|
||||
}
|
||||
|
||||
SECTION("whitespace")
|
||||
{
|
||||
// result is end_of_input, because not token is following
|
||||
CHECK(json::lexer(" ").scan() == json::lexer::token_type::end_of_input);
|
||||
CHECK(json::lexer("\t").scan() == json::lexer::token_type::end_of_input);
|
||||
CHECK(json::lexer("\n").scan() == json::lexer::token_type::end_of_input);
|
||||
CHECK(json::lexer("\r").scan() == json::lexer::token_type::end_of_input);
|
||||
CHECK(json::lexer(" \t\n\r\n\t ").scan() == json::lexer::token_type::end_of_input);
|
||||
CHECK(json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>(" "),
|
||||
1).scan() == json::lexer::token_type::end_of_input);
|
||||
CHECK(json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("\t"),
|
||||
1).scan() == json::lexer::token_type::end_of_input);
|
||||
CHECK(json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("\n"),
|
||||
1).scan() == json::lexer::token_type::end_of_input);
|
||||
CHECK(json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("\r"),
|
||||
1).scan() == json::lexer::token_type::end_of_input);
|
||||
CHECK(json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>(" \t\n\r\n\t "),
|
||||
7).scan() == json::lexer::token_type::end_of_input);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -100,7 +124,11 @@ TEST_CASE("lexer class")
|
|||
{
|
||||
for (int c = 1; c < 128; ++c)
|
||||
{
|
||||
auto s = std::string(1, c);
|
||||
// create string from the ASCII code
|
||||
const auto s = std::string(1, c);
|
||||
// store scan() result
|
||||
const auto res = json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>(s.c_str()),
|
||||
1).scan();
|
||||
|
||||
switch (c)
|
||||
{
|
||||
|
@ -122,7 +150,7 @@ TEST_CASE("lexer class")
|
|||
case ('8'):
|
||||
case ('9'):
|
||||
{
|
||||
CHECK(json::lexer(s.c_str()).scan() != json::lexer::token_type::parse_error);
|
||||
CHECK(res != json::lexer::token_type::parse_error);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -132,14 +160,14 @@ TEST_CASE("lexer class")
|
|||
case ('\n'):
|
||||
case ('\r'):
|
||||
{
|
||||
CHECK(json::lexer(s.c_str()).scan() == json::lexer::token_type::end_of_input);
|
||||
CHECK(res == json::lexer::token_type::end_of_input);
|
||||
break;
|
||||
}
|
||||
|
||||
// anything else is not expected
|
||||
default:
|
||||
{
|
||||
CHECK(json::lexer(s.c_str()).scan() == json::lexer::token_type::parse_error);
|
||||
CHECK(res == json::lexer::token_type::parse_error);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,6 +32,8 @@ SOFTWARE.
|
|||
#include "json.hpp"
|
||||
using nlohmann::json;
|
||||
|
||||
#include <valarray>
|
||||
|
||||
TEST_CASE("parser class")
|
||||
{
|
||||
SECTION("parse")
|
||||
|
@ -487,7 +489,7 @@ TEST_CASE("parser class")
|
|||
case ('r'):
|
||||
case ('t'):
|
||||
{
|
||||
CHECK_NOTHROW(json::parser(s).parse());
|
||||
CHECK_NOTHROW(json::parser(s.c_str()).parse());
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -500,8 +502,8 @@ TEST_CASE("parser class")
|
|||
// any other combination of backslash and character is invalid
|
||||
default:
|
||||
{
|
||||
CHECK_THROWS_AS(json::parser(s).parse(), std::invalid_argument);
|
||||
CHECK_THROWS_WITH(json::parser(s).parse(), "parse error - unexpected '\"'");
|
||||
CHECK_THROWS_AS(json::parser(s.c_str()).parse(), std::invalid_argument);
|
||||
CHECK_THROWS_WITH(json::parser(s.c_str()).parse(), "parse error - unexpected '\"'");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -559,22 +561,22 @@ TEST_CASE("parser class")
|
|||
|
||||
if (valid(c))
|
||||
{
|
||||
CHECK_NOTHROW(json::parser(s1).parse());
|
||||
CHECK_NOTHROW(json::parser(s2).parse());
|
||||
CHECK_NOTHROW(json::parser(s3).parse());
|
||||
CHECK_NOTHROW(json::parser(s4).parse());
|
||||
CHECK_NOTHROW(json::parser(s1.c_str()).parse());
|
||||
CHECK_NOTHROW(json::parser(s2.c_str()).parse());
|
||||
CHECK_NOTHROW(json::parser(s3.c_str()).parse());
|
||||
CHECK_NOTHROW(json::parser(s4.c_str()).parse());
|
||||
}
|
||||
else
|
||||
{
|
||||
CHECK_THROWS_AS(json::parser(s1).parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser(s2).parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser(s3).parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser(s4).parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser(s1.c_str()).parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser(s2.c_str()).parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser(s3.c_str()).parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser(s4.c_str()).parse(), std::invalid_argument);
|
||||
|
||||
CHECK_THROWS_WITH(json::parser(s1).parse(), "parse error - unexpected '\"'");
|
||||
CHECK_THROWS_WITH(json::parser(s2).parse(), "parse error - unexpected '\"'");
|
||||
CHECK_THROWS_WITH(json::parser(s3).parse(), "parse error - unexpected '\"'");
|
||||
CHECK_THROWS_WITH(json::parser(s4).parse(), "parse error - unexpected '\"'");
|
||||
CHECK_THROWS_WITH(json::parser(s1.c_str()).parse(), "parse error - unexpected '\"'");
|
||||
CHECK_THROWS_WITH(json::parser(s2.c_str()).parse(), "parse error - unexpected '\"'");
|
||||
CHECK_THROWS_WITH(json::parser(s3.c_str()).parse(), "parse error - unexpected '\"'");
|
||||
CHECK_THROWS_WITH(json::parser(s4.c_str()).parse(), "parse error - unexpected '\"'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -755,11 +757,47 @@ TEST_CASE("parser class")
|
|||
}
|
||||
}
|
||||
|
||||
SECTION("copy constructor")
|
||||
SECTION("constructing from contiguous containers")
|
||||
{
|
||||
json::string_t* s = new json::string_t("[1,2,3,4]");
|
||||
json::parser p(*s);
|
||||
delete s;
|
||||
CHECK(p.parse() == json({1, 2, 3, 4}));
|
||||
SECTION("from std::vector")
|
||||
{
|
||||
std::vector<uint8_t> v = {'t', 'r', 'u', 'e'};
|
||||
CHECK(json::parser(std::begin(v), std::end(v)).parse() == json(true));
|
||||
}
|
||||
|
||||
SECTION("from std::array")
|
||||
{
|
||||
std::array<uint8_t, 5> v { {'t', 'r', 'u', 'e'} };
|
||||
CHECK(json::parser(std::begin(v), std::end(v)).parse() == json(true));
|
||||
}
|
||||
|
||||
SECTION("from array")
|
||||
{
|
||||
uint8_t v[] = {'t', 'r', 'u', 'e'};
|
||||
CHECK(json::parser(std::begin(v), std::end(v)).parse() == json(true));
|
||||
}
|
||||
|
||||
SECTION("from char literal")
|
||||
{
|
||||
CHECK(json::parser("true").parse() == json(true));
|
||||
}
|
||||
|
||||
SECTION("from std::string")
|
||||
{
|
||||
std::string v = {'t', 'r', 'u', 'e'};
|
||||
CHECK(json::parser(std::begin(v), std::end(v)).parse() == json(true));
|
||||
}
|
||||
|
||||
SECTION("from std::initializer_list")
|
||||
{
|
||||
std::initializer_list<uint8_t> v = {'t', 'r', 'u', 'e'};
|
||||
CHECK(json::parser(std::begin(v), std::end(v)).parse() == json(true));
|
||||
}
|
||||
|
||||
SECTION("from std::valarray")
|
||||
{
|
||||
std::valarray<uint8_t> v = {'t', 'r', 'u', 'e'};
|
||||
CHECK(json::parser(std::begin(v), std::end(v)).parse() == json(true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,6 +31,8 @@ SOFTWARE.
|
|||
#include "json.hpp"
|
||||
using nlohmann::json;
|
||||
|
||||
#include <valarray>
|
||||
|
||||
TEST_CASE("deserialization")
|
||||
{
|
||||
SECTION("successful deserialization")
|
||||
|
@ -43,7 +45,14 @@ TEST_CASE("deserialization")
|
|||
CHECK(j == json({"foo", 1, 2, 3, false, {{"one", 1}}}));
|
||||
}
|
||||
|
||||
SECTION("string")
|
||||
SECTION("string literal")
|
||||
{
|
||||
auto s = "[\"foo\",1,2,3,false,{\"one\":1}]";
|
||||
json j = json::parse(s);
|
||||
CHECK(j == json({"foo", 1, 2, 3, false, {{"one", 1}}}));
|
||||
}
|
||||
|
||||
SECTION("string_t")
|
||||
{
|
||||
json::string_t s = "[\"foo\",1,2,3,false,{\"one\":1}]";
|
||||
json j = json::parse(s);
|
||||
|
@ -74,7 +83,7 @@ TEST_CASE("deserialization")
|
|||
}
|
||||
}
|
||||
|
||||
SECTION("successful deserialization")
|
||||
SECTION("unsuccessful deserialization")
|
||||
{
|
||||
SECTION("stream")
|
||||
{
|
||||
|
@ -116,4 +125,103 @@ TEST_CASE("deserialization")
|
|||
"parse error - unexpected end of input; expected ']'");
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("contiguous containers")
|
||||
{
|
||||
SECTION("directly")
|
||||
{
|
||||
SECTION("from std::vector")
|
||||
{
|
||||
std::vector<uint8_t> v = {'t', 'r', 'u', 'e'};
|
||||
CHECK(json::parse(v) == json(true));
|
||||
}
|
||||
|
||||
SECTION("from std::array")
|
||||
{
|
||||
std::array<uint8_t, 5> v { {'t', 'r', 'u', 'e'} };
|
||||
CHECK(json::parse(v) == json(true));
|
||||
}
|
||||
|
||||
SECTION("from array")
|
||||
{
|
||||
uint8_t v[] = {'t', 'r', 'u', 'e'};
|
||||
CHECK(json::parse(v) == json(true));
|
||||
}
|
||||
|
||||
SECTION("from chars")
|
||||
{
|
||||
uint8_t *v = new uint8_t[5];
|
||||
v[0] = 't';
|
||||
v[1] = 'r';
|
||||
v[2] = 'u';
|
||||
v[3] = 'e';
|
||||
v[4] = '\0';
|
||||
CHECK(json::parse(v) == json(true));
|
||||
delete[] v;
|
||||
}
|
||||
|
||||
SECTION("from std::string")
|
||||
{
|
||||
std::string v = {'t', 'r', 'u', 'e'};
|
||||
CHECK(json::parse(v) == json(true));
|
||||
}
|
||||
|
||||
SECTION("from std::initializer_list")
|
||||
{
|
||||
std::initializer_list<uint8_t> v = {'t', 'r', 'u', 'e'};
|
||||
CHECK(json::parse(v) == json(true));
|
||||
}
|
||||
|
||||
SECTION("empty container")
|
||||
{
|
||||
std::vector<uint8_t> v;
|
||||
CHECK_THROWS_AS(json::parse(v), std::invalid_argument);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("via iterator range")
|
||||
{
|
||||
SECTION("from std::vector")
|
||||
{
|
||||
std::vector<uint8_t> v = {'t', 'r', 'u', 'e'};
|
||||
CHECK(json::parse(std::begin(v), std::end(v)) == json(true));
|
||||
}
|
||||
|
||||
SECTION("from std::array")
|
||||
{
|
||||
std::array<uint8_t, 5> v { {'t', 'r', 'u', 'e'} };
|
||||
CHECK(json::parse(std::begin(v), std::end(v)) == json(true));
|
||||
}
|
||||
|
||||
SECTION("from array")
|
||||
{
|
||||
uint8_t v[] = {'t', 'r', 'u', 'e'};
|
||||
CHECK(json::parse(std::begin(v), std::end(v)) == json(true));
|
||||
}
|
||||
|
||||
SECTION("from std::string")
|
||||
{
|
||||
std::string v = {'t', 'r', 'u', 'e'};
|
||||
CHECK(json::parse(std::begin(v), std::end(v)) == json(true));
|
||||
}
|
||||
|
||||
SECTION("from std::initializer_list")
|
||||
{
|
||||
std::initializer_list<uint8_t> v = {'t', 'r', 'u', 'e'};
|
||||
CHECK(json::parse(std::begin(v), std::end(v)) == json(true));
|
||||
}
|
||||
|
||||
SECTION("from std::valarray")
|
||||
{
|
||||
std::valarray<uint8_t> v = {'t', 'r', 'u', 'e'};
|
||||
CHECK(json::parse(std::begin(v), std::end(v)) == json(true));
|
||||
}
|
||||
|
||||
SECTION("with empty range")
|
||||
{
|
||||
std::vector<uint8_t> v;
|
||||
CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), std::invalid_argument);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue