2015-02-12 21:54:42 +00:00
|
|
|
/*!
|
|
|
|
@file
|
|
|
|
@copyright The code is licensed under the MIT License
|
|
|
|
<http://opensource.org/licenses/MIT>,
|
|
|
|
Copyright (c) 2013-2015 Niels Lohmann.
|
|
|
|
@author Niels Lohmann <http://nlohmann.me>
|
|
|
|
@see https://github.com/nlohmann/json
|
|
|
|
*/
|
|
|
|
|
2015-04-26 11:37:01 +00:00
|
|
|
#ifndef NLOHMANN_JSON_HPP
|
|
|
|
#define NLOHMANN_JSON_HPP
|
2015-01-31 19:13:11 +00:00
|
|
|
|
|
|
|
#include <algorithm>
|
2015-04-26 12:55:06 +00:00
|
|
|
#include <array>
|
2015-04-25 21:10:23 +00:00
|
|
|
#include <ciso646>
|
2015-02-15 10:44:49 +00:00
|
|
|
#include <cmath>
|
2015-03-23 19:27:30 +00:00
|
|
|
#include <cstdio>
|
2015-01-31 19:13:11 +00:00
|
|
|
#include <functional>
|
|
|
|
#include <initializer_list>
|
2015-02-16 21:47:30 +00:00
|
|
|
#include <iomanip>
|
2015-01-31 19:13:11 +00:00
|
|
|
#include <iostream>
|
|
|
|
#include <iterator>
|
|
|
|
#include <limits>
|
|
|
|
#include <map>
|
|
|
|
#include <memory>
|
2015-02-16 21:47:30 +00:00
|
|
|
#include <sstream>
|
2015-01-31 19:13:11 +00:00
|
|
|
#include <string>
|
|
|
|
#include <type_traits>
|
|
|
|
#include <utility>
|
|
|
|
#include <vector>
|
|
|
|
|
2015-06-04 06:31:13 +00:00
|
|
|
// enable ssize_t on MinGW
|
|
|
|
#ifdef __GNUC__
|
|
|
|
#ifdef __MINGW32__
|
|
|
|
#include <sys/types.h>
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
2015-06-20 12:25:49 +00:00
|
|
|
// enable ssize_t for MSVC
|
|
|
|
#ifdef _MSC_VER
|
2015-06-20 15:45:52 +00:00
|
|
|
#include <basetsd.h>
|
2015-06-20 12:25:49 +00:00
|
|
|
using ssize_t = SSIZE_T;
|
|
|
|
#endif
|
|
|
|
|
2015-01-31 19:13:11 +00:00
|
|
|
/*!
|
2015-02-22 16:52:27 +00:00
|
|
|
@brief namespace for Niels Lohmann
|
2015-01-31 19:13:11 +00:00
|
|
|
@see https://github.com/nlohmann
|
|
|
|
*/
|
|
|
|
namespace nlohmann
|
|
|
|
{
|
|
|
|
|
2015-04-03 14:34:39 +00:00
|
|
|
|
2015-06-20 22:59:33 +00:00
|
|
|
/// namespace with internal helper functions
|
|
|
|
namespace internals
|
|
|
|
{
|
2015-04-03 14:34:39 +00:00
|
|
|
// Helper to determine whether there's a key_type for T.
|
|
|
|
// http://stackoverflow.com/a/7728728/266378
|
|
|
|
template<typename T>
|
2015-04-08 20:23:40 +00:00
|
|
|
struct has_mapped_type
|
2015-04-03 14:34:39 +00:00
|
|
|
{
|
|
|
|
private:
|
2015-04-08 20:23:40 +00:00
|
|
|
template<typename C> static char test(typename C::mapped_type*);
|
2015-04-03 14:34:39 +00:00
|
|
|
template<typename C> static int test(...);
|
|
|
|
public:
|
|
|
|
enum { value = sizeof(test<T>(0)) == sizeof(char) };
|
|
|
|
};
|
2015-06-20 22:59:33 +00:00
|
|
|
}
|
2015-04-03 14:34:39 +00:00
|
|
|
|
2015-01-31 19:13:11 +00:00
|
|
|
/*!
|
2015-06-20 22:59:33 +00:00
|
|
|
@brief a class to store JSON values
|
2015-01-31 19:13:11 +00:00
|
|
|
|
|
|
|
@tparam ObjectType type for JSON objects
|
|
|
|
(@c std::map by default)
|
|
|
|
@tparam ArrayType type for JSON arrays
|
|
|
|
(@c std::vector by default)
|
|
|
|
@tparam StringType type for JSON strings and object keys
|
|
|
|
(@c std::string by default)
|
|
|
|
@tparam BooleanType type for JSON booleans
|
|
|
|
(@c bool by default)
|
|
|
|
@tparam NumberIntegerType type for JSON integer numbers
|
|
|
|
(@c int64_t by default)
|
2015-02-08 13:38:52 +00:00
|
|
|
@tparam NumberFloatType type for JSON floating-point numbers
|
2015-01-31 19:13:11 +00:00
|
|
|
(@c double by default)
|
2015-04-11 17:26:12 +00:00
|
|
|
@tparam AllocatorType type of the allocator to use
|
2015-02-15 22:13:46 +00:00
|
|
|
(@c std::allocator by default)
|
2015-02-15 13:52:00 +00:00
|
|
|
|
2015-06-21 09:29:32 +00:00
|
|
|
@requirement This class satisfies the Container requirements (see http://en.cppreference.com/w/cpp/concept/Container):
|
|
|
|
- @ref basic_json()
|
|
|
|
- @ref basic_json(const basic_json&)
|
|
|
|
- @ref reference& operator=(basic_json)
|
|
|
|
- @ref ~basic_json()
|
|
|
|
- @ref iterator begin(), @ref const_iterator begin(), @ref const_iterator cbegin()
|
|
|
|
- @ref iterator end(), @ref const_iterator end(), @ref const_iterator cend()
|
|
|
|
- @ref bool operator==(const_reference, const_reference), @ref bool operator!=(const_reference, const_reference)
|
|
|
|
- @ref void swap(reference other)
|
|
|
|
- @ref size_type size(), @ref size_type max_size()
|
|
|
|
- @ref bool empty()
|
|
|
|
|
2015-02-15 22:27:35 +00:00
|
|
|
@note ObjectType trick from http://stackoverflow.com/a/9860911
|
|
|
|
|
2015-02-15 13:52:00 +00:00
|
|
|
@see RFC 7159 <http://rfc7159.net/rfc7159>
|
|
|
|
@see ECMA 404 <http://www.ecma-international.org/publications/standards/Ecma-404.htm>
|
2015-01-31 19:13:11 +00:00
|
|
|
*/
|
|
|
|
template <
|
|
|
|
template<typename U, typename V, typename... Args> class ObjectType = std::map,
|
|
|
|
template<typename U, typename... Args> class ArrayType = std::vector,
|
|
|
|
class StringType = std::string,
|
|
|
|
class BooleanType = bool,
|
|
|
|
class NumberIntegerType = int64_t,
|
2015-02-15 21:49:26 +00:00
|
|
|
class NumberFloatType = double,
|
2015-04-11 17:26:12 +00:00
|
|
|
template<typename U> class AllocatorType = std::allocator
|
2015-01-31 19:13:11 +00:00
|
|
|
>
|
|
|
|
class basic_json
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
/////////////////////
|
|
|
|
// container types //
|
|
|
|
/////////////////////
|
|
|
|
|
2015-06-20 22:59:33 +00:00
|
|
|
/// @name container types
|
|
|
|
/// @{
|
|
|
|
|
2015-06-21 11:04:03 +00:00
|
|
|
using __basic_json =
|
|
|
|
basic_json<ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberFloatType, AllocatorType>;
|
|
|
|
|
2015-04-25 21:10:23 +00:00
|
|
|
/// the type of elements in a basic_json container
|
2015-01-31 19:13:11 +00:00
|
|
|
using value_type = basic_json;
|
2015-02-22 16:52:27 +00:00
|
|
|
|
2015-04-25 21:10:23 +00:00
|
|
|
/// the type of an element reference
|
2015-04-11 17:26:12 +00:00
|
|
|
using reference = value_type&;
|
2015-02-22 16:52:27 +00:00
|
|
|
|
2015-04-25 21:10:23 +00:00
|
|
|
/// the type of an element const reference
|
2015-04-11 17:26:12 +00:00
|
|
|
using const_reference = const value_type&;
|
2015-02-22 16:52:27 +00:00
|
|
|
|
2015-04-25 21:10:23 +00:00
|
|
|
/// a type to represent differences between iterators
|
2015-02-22 16:52:27 +00:00
|
|
|
using difference_type = std::ptrdiff_t;
|
|
|
|
|
2015-04-25 21:10:23 +00:00
|
|
|
/// a type to represent container sizes
|
2015-02-22 16:52:27 +00:00
|
|
|
using size_type = std::size_t;
|
|
|
|
|
|
|
|
/// the allocator type
|
2015-04-11 17:26:12 +00:00
|
|
|
using allocator_type = AllocatorType<basic_json>;
|
2015-02-22 16:52:27 +00:00
|
|
|
|
2015-01-31 19:13:11 +00:00
|
|
|
/// the type of an element pointer
|
2015-04-11 17:26:12 +00:00
|
|
|
using pointer = typename std::allocator_traits<allocator_type>::pointer;
|
2015-01-31 19:13:11 +00:00
|
|
|
/// the type of an element const pointer
|
2015-04-11 17:26:12 +00:00
|
|
|
using const_pointer = typename std::allocator_traits<allocator_type>::const_pointer;
|
2015-02-22 16:52:27 +00:00
|
|
|
|
2015-04-25 21:10:23 +00:00
|
|
|
/// an iterator for a basic_json container
|
|
|
|
class iterator;
|
|
|
|
/// a const iterator for a basic_json container
|
|
|
|
class const_iterator;
|
|
|
|
/// a reverse iterator for a basic_json container
|
|
|
|
class reverse_iterator;
|
|
|
|
/// a const reverse iterator for a basic_json container
|
|
|
|
class const_reverse_iterator;
|
2015-02-15 13:52:00 +00:00
|
|
|
|
2015-06-20 22:59:33 +00:00
|
|
|
/// @}
|
|
|
|
|
|
|
|
|
2015-06-21 09:35:54 +00:00
|
|
|
/*!
|
|
|
|
@brief returns the allocator associated with the container
|
|
|
|
*/
|
2015-06-12 08:08:57 +00:00
|
|
|
static allocator_type get_allocator()
|
2015-02-22 16:52:27 +00:00
|
|
|
{
|
|
|
|
return allocator_type();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-01-31 19:13:11 +00:00
|
|
|
///////////////////////////
|
|
|
|
// JSON value data types //
|
|
|
|
///////////////////////////
|
|
|
|
|
2015-06-20 22:59:33 +00:00
|
|
|
/// @name JSON value data types
|
|
|
|
/// @{
|
|
|
|
|
2015-01-31 19:13:11 +00:00
|
|
|
/// a type for an object
|
2015-06-04 19:02:16 +00:00
|
|
|
using object_t =
|
|
|
|
ObjectType<StringType, basic_json, std::less<StringType>, AllocatorType<std::pair<const StringType, basic_json>>>;
|
2015-01-31 19:13:11 +00:00
|
|
|
/// a type for an array
|
2015-06-04 19:02:16 +00:00
|
|
|
using array_t = ArrayType<basic_json, AllocatorType<basic_json>>;
|
2015-01-31 19:13:11 +00:00
|
|
|
/// a type for a string
|
|
|
|
using string_t = StringType;
|
|
|
|
/// a type for a boolean
|
|
|
|
using boolean_t = BooleanType;
|
|
|
|
/// a type for a number (integer)
|
|
|
|
using number_integer_t = NumberIntegerType;
|
2015-02-08 13:38:52 +00:00
|
|
|
/// a type for a number (floating-point)
|
2015-01-31 19:13:11 +00:00
|
|
|
using number_float_t = NumberFloatType;
|
|
|
|
/// a type for list initialization
|
|
|
|
using list_init_t = std::initializer_list<basic_json>;
|
|
|
|
|
2015-06-20 22:59:33 +00:00
|
|
|
/// @}
|
|
|
|
|
2015-01-31 19:13:11 +00:00
|
|
|
|
2015-05-09 20:49:21 +00:00
|
|
|
/////////////////////////////////
|
|
|
|
// JSON value type enumeration //
|
|
|
|
/////////////////////////////////
|
|
|
|
|
2015-06-20 22:59:33 +00:00
|
|
|
/*!
|
|
|
|
@brief the JSON value type enumeration
|
|
|
|
|
|
|
|
This enumeration collects the different JSON value types. It is used to
|
|
|
|
distinguish the stored values in the union @ref json_value.
|
|
|
|
*/
|
2015-05-09 20:49:21 +00:00
|
|
|
enum class value_t : uint8_t
|
|
|
|
{
|
|
|
|
null, ///< null value
|
|
|
|
object, ///< object (unordered set of name/value pairs)
|
|
|
|
array, ///< array (ordered collection of values)
|
|
|
|
string, ///< string value
|
|
|
|
boolean, ///< boolean value
|
|
|
|
number_integer, ///< number value (integer)
|
|
|
|
number_float, ///< number value (floating-point)
|
|
|
|
discarded ///< (internal) indicates the parser callback chose not to keep the value
|
|
|
|
};
|
|
|
|
|
2015-06-20 22:59:33 +00:00
|
|
|
|
2015-01-31 19:13:11 +00:00
|
|
|
////////////////////////
|
|
|
|
// JSON value storage //
|
|
|
|
////////////////////////
|
|
|
|
|
|
|
|
/// a JSON value
|
|
|
|
union json_value
|
|
|
|
{
|
|
|
|
/// object (stored with pointer to save storage)
|
|
|
|
object_t* object;
|
|
|
|
/// array (stored with pointer to save storage)
|
|
|
|
array_t* array;
|
|
|
|
/// string (stored with pointer to save storage)
|
|
|
|
string_t* string;
|
2015-06-08 14:35:38 +00:00
|
|
|
/// boolean
|
2015-01-31 19:13:11 +00:00
|
|
|
boolean_t boolean;
|
|
|
|
/// number (integer)
|
|
|
|
number_integer_t number_integer;
|
2015-02-08 13:38:52 +00:00
|
|
|
/// number (floating-point)
|
2015-01-31 19:13:11 +00:00
|
|
|
number_float_t number_float;
|
|
|
|
|
|
|
|
/// default constructor (for null values)
|
2015-06-12 08:08:57 +00:00
|
|
|
json_value() noexcept = default;
|
2015-01-31 19:13:11 +00:00
|
|
|
/// constructor for booleans
|
2015-06-12 08:08:57 +00:00
|
|
|
json_value(boolean_t v) noexcept : boolean(v) {}
|
2015-01-31 19:13:11 +00:00
|
|
|
/// constructor for numbers (integer)
|
2015-06-12 08:08:57 +00:00
|
|
|
json_value(number_integer_t v) noexcept : number_integer(v) {}
|
2015-02-08 13:38:52 +00:00
|
|
|
/// constructor for numbers (floating-point)
|
2015-06-12 08:08:57 +00:00
|
|
|
json_value(number_float_t v) noexcept : number_float(v) {}
|
2015-05-09 20:49:21 +00:00
|
|
|
/// constructor for empty values of a given type
|
2015-06-12 08:08:57 +00:00
|
|
|
json_value(value_t t)
|
2015-05-09 20:49:21 +00:00
|
|
|
{
|
|
|
|
switch (t)
|
|
|
|
{
|
|
|
|
case (value_t::null):
|
|
|
|
case (value_t::discarded):
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case (value_t::object):
|
|
|
|
{
|
|
|
|
AllocatorType<object_t> alloc;
|
|
|
|
object = alloc.allocate(1);
|
|
|
|
alloc.construct(object);
|
|
|
|
break;
|
|
|
|
}
|
2015-01-31 19:13:11 +00:00
|
|
|
|
2015-05-09 20:49:21 +00:00
|
|
|
case (value_t::array):
|
|
|
|
{
|
|
|
|
AllocatorType<array_t> alloc;
|
|
|
|
array = alloc.allocate(1);
|
|
|
|
alloc.construct(array);
|
|
|
|
break;
|
|
|
|
}
|
2015-01-31 19:13:11 +00:00
|
|
|
|
2015-05-09 20:49:21 +00:00
|
|
|
case (value_t::string):
|
|
|
|
{
|
|
|
|
AllocatorType<string_t> alloc;
|
|
|
|
string = alloc.allocate(1);
|
|
|
|
alloc.construct(string, "");
|
|
|
|
break;
|
|
|
|
}
|
2015-01-31 19:13:11 +00:00
|
|
|
|
2015-05-09 20:49:21 +00:00
|
|
|
case (value_t::boolean):
|
|
|
|
{
|
|
|
|
boolean = boolean_t(false);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case (value_t::number_integer):
|
|
|
|
{
|
|
|
|
number_integer = number_integer_t(0);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case (value_t::number_float):
|
|
|
|
{
|
|
|
|
number_float = number_float_t(0.0);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-05-10 14:30:33 +00:00
|
|
|
|
|
|
|
/// constructor for strings
|
2015-06-12 08:08:57 +00:00
|
|
|
json_value(const string_t& value)
|
2015-05-10 14:30:33 +00:00
|
|
|
{
|
|
|
|
AllocatorType<string_t> alloc;
|
|
|
|
string = alloc.allocate(1);
|
|
|
|
alloc.construct(string, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// constructor for objects
|
2015-06-12 08:08:57 +00:00
|
|
|
json_value(const object_t& value)
|
2015-05-10 14:30:33 +00:00
|
|
|
{
|
|
|
|
AllocatorType<object_t> alloc;
|
|
|
|
object = alloc.allocate(1);
|
|
|
|
alloc.construct(object, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// constructor for arrays
|
2015-06-12 08:08:57 +00:00
|
|
|
json_value(const array_t& value)
|
2015-05-10 14:30:33 +00:00
|
|
|
{
|
|
|
|
AllocatorType<array_t> alloc;
|
|
|
|
array = alloc.allocate(1);
|
|
|
|
alloc.construct(array, value);
|
|
|
|
}
|
2015-01-31 19:13:11 +00:00
|
|
|
};
|
|
|
|
|
2015-05-03 15:52:13 +00:00
|
|
|
//////////////////////////
|
|
|
|
// JSON parser callback //
|
|
|
|
//////////////////////////
|
|
|
|
|
|
|
|
/// JSON callback event enumeration
|
|
|
|
enum class parse_event_t : uint8_t
|
|
|
|
{
|
|
|
|
object_start, ///< start an object scope (found a '{' token)
|
|
|
|
object_end, ///< end of an object scope (found '}' token)
|
|
|
|
array_start, ///< start of an array scope (found '[' token)
|
|
|
|
array_end, ///< end of an array scope (found ']' token)
|
|
|
|
key, ///< found an object key within an object scope
|
|
|
|
value ///< a value in an appropriate context (i.e., following a tag in an object scope)
|
|
|
|
};
|
|
|
|
|
|
|
|
/// per-element parser callback type
|
|
|
|
using parser_callback_t = std::function<bool(int depth, parse_event_t event,
|
|
|
|
const basic_json& parsed)>;
|
|
|
|
|
2015-02-22 16:52:27 +00:00
|
|
|
/*!
|
|
|
|
@brief comparison operator for JSON value types
|
|
|
|
|
|
|
|
Returns an ordering that is similar to Python:
|
|
|
|
- order: null < boolean < number < object < array < string
|
|
|
|
- furthermore, each type is not smaller than itself
|
|
|
|
*/
|
|
|
|
friend bool operator<(const value_t lhs, const value_t rhs)
|
|
|
|
{
|
2015-06-02 19:27:49 +00:00
|
|
|
static constexpr std::array<uint8_t, 7> order = {{
|
2015-04-26 12:55:06 +00:00
|
|
|
0, // null
|
|
|
|
3, // object
|
|
|
|
4, // array
|
|
|
|
5, // string
|
|
|
|
1, // boolean
|
|
|
|
2, // integer
|
|
|
|
2 // float
|
2015-02-22 16:52:27 +00:00
|
|
|
}
|
2015-04-26 12:55:06 +00:00
|
|
|
};
|
2015-05-03 16:46:26 +00:00
|
|
|
|
|
|
|
// discarded values are not comparable
|
|
|
|
if (lhs == value_t::discarded or rhs == value_t::discarded)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-04-26 12:55:06 +00:00
|
|
|
return order[static_cast<std::size_t>(lhs)] < order[static_cast<std::size_t>(rhs)];
|
2015-02-22 16:52:27 +00:00
|
|
|
}
|
|
|
|
|
2015-01-31 19:13:11 +00:00
|
|
|
|
|
|
|
//////////////////
|
|
|
|
// constructors //
|
|
|
|
//////////////////
|
|
|
|
|
2015-02-24 22:19:19 +00:00
|
|
|
/*!
|
|
|
|
@brief create an empty value with a given type
|
|
|
|
|
2015-06-20 22:59:33 +00:00
|
|
|
Create an empty JSON value with a given type. The value will be default
|
|
|
|
initialized with an empty value which depends on the type:
|
|
|
|
|
|
|
|
Value type | initial value
|
|
|
|
----------- | -------------
|
2015-06-21 07:44:12 +00:00
|
|
|
null | `null`
|
|
|
|
boolean | `false`
|
|
|
|
string | `""`
|
|
|
|
number | `0`
|
|
|
|
object | `{}`
|
|
|
|
array | `[]`
|
2015-06-20 22:59:33 +00:00
|
|
|
|
|
|
|
@param value the type of the value to create
|
|
|
|
|
|
|
|
@complexity Constant.
|
|
|
|
|
|
|
|
@exception std::bad_alloc if allocation for object, array, or string value
|
|
|
|
fails (thrown by the constructors of @ref json_value)
|
|
|
|
|
|
|
|
@liveexample{The following code shows the constructor for different @ref
|
|
|
|
value_t values,basic_json__value_t}
|
2015-02-24 22:19:19 +00:00
|
|
|
*/
|
2015-06-12 08:08:57 +00:00
|
|
|
basic_json(const value_t value)
|
2015-05-09 20:49:21 +00:00
|
|
|
: m_type(value), m_value(value)
|
|
|
|
{}
|
2015-01-31 19:13:11 +00:00
|
|
|
|
2015-02-22 16:52:27 +00:00
|
|
|
/*!
|
|
|
|
@brief create a null object (implicitly)
|
2015-06-20 22:59:33 +00:00
|
|
|
|
|
|
|
Create a `null` JSON value. This is the implicit version of the `null`
|
|
|
|
value constructor as it takes no parameters.
|
|
|
|
|
|
|
|
@complexity Constant.
|
|
|
|
|
|
|
|
@requirement This function satisfies the Container requirements:
|
|
|
|
- The complexity is constant.
|
|
|
|
- As postcondition, it holds: `basic_json().empty() == true`.
|
|
|
|
|
|
|
|
@liveexample{The following code shows the constructor for a `null` JSON
|
|
|
|
value.,basic_json}
|
|
|
|
|
|
|
|
@sa basic_json(std::nullptr_t)
|
2015-02-22 16:52:27 +00:00
|
|
|
@ingroup container
|
|
|
|
*/
|
2015-06-12 08:08:57 +00:00
|
|
|
basic_json() noexcept = default;
|
2015-01-31 19:13:11 +00:00
|
|
|
|
2015-06-20 22:59:33 +00:00
|
|
|
/*!
|
|
|
|
@brief create a null object (explicitly)
|
|
|
|
|
|
|
|
Create a `null` JSON value. This is the explicitly version of the `null`
|
|
|
|
value constructor as it takes a null pointer as parameter. It allows to
|
|
|
|
create `null` values by explicitly assigning a @c nullptr to a JSON value.
|
|
|
|
The passed null pointer itself is not read - it is only used to choose the
|
|
|
|
right constructor.
|
|
|
|
|
|
|
|
@complexity Constant.
|
|
|
|
|
|
|
|
@liveexample{The following code shows the constructor with null pointer
|
|
|
|
parameter.,basic_json__nullptr_t}
|
|
|
|
|
|
|
|
@sa basic_json()
|
|
|
|
*/
|
2015-06-12 08:08:57 +00:00
|
|
|
basic_json(std::nullptr_t) noexcept
|
2015-05-10 14:30:33 +00:00
|
|
|
: basic_json(value_t::null)
|
2015-01-31 19:13:11 +00:00
|
|
|
{}
|
|
|
|
|
2015-06-20 22:59:33 +00:00
|
|
|
/*!
|
|
|
|
@brief create an object (explicit)
|
|
|
|
|
|
|
|
Create an object JSON value with a given content.
|
|
|
|
|
|
|
|
@param value a value for the object
|
|
|
|
|
|
|
|
@complexity Linear in the size of the passed @a value.
|
|
|
|
|
|
|
|
@exception std::bad_alloc if allocation for object value fails (thrown by
|
|
|
|
the constructor of @ref json_value)
|
|
|
|
|
|
|
|
@liveexample{The following code shows the constructor with an @ref object_t
|
|
|
|
parameter.,basic_json__object_t}
|
|
|
|
|
|
|
|
@sa basic_json(const CompatibleObjectType&)
|
|
|
|
*/
|
2015-06-12 08:08:57 +00:00
|
|
|
basic_json(const object_t& value)
|
2015-05-10 14:30:33 +00:00
|
|
|
: m_type(value_t::object), m_value(value)
|
|
|
|
{}
|
2015-01-31 19:13:11 +00:00
|
|
|
|
2015-06-20 22:59:33 +00:00
|
|
|
/*!
|
|
|
|
@brief create an object (implicit)
|
|
|
|
|
|
|
|
Create an object JSON value with a given content. This constructor allows
|
|
|
|
any type that can be used to construct values of type @ref object_t.
|
|
|
|
Examples include the types `std::map` and `std::unordered_map`.
|
|
|
|
|
|
|
|
@tparam CompatibleObjectType an object type whose `key_type` and
|
|
|
|
`value_type` is compatible to @ref object_t
|
|
|
|
|
|
|
|
@param value a value for the object
|
|
|
|
|
|
|
|
@complexity Linear in the size of the passed @a value.
|
|
|
|
|
|
|
|
@exception std::bad_alloc if allocation for object value fails (thrown by
|
|
|
|
the constructor of @ref json_value)
|
|
|
|
|
|
|
|
@liveexample{The following code shows the constructor with several
|
|
|
|
compatible object type parameters.,basic_json__CompatibleObjectType}
|
|
|
|
|
|
|
|
@sa basic_json(const object_t&)
|
|
|
|
*/
|
|
|
|
template <class CompatibleObjectType, typename
|
2015-01-31 19:13:11 +00:00
|
|
|
std::enable_if<
|
2015-06-20 22:59:33 +00:00
|
|
|
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
|
2015-01-31 19:13:11 +00:00
|
|
|
= 0>
|
2015-06-20 22:59:33 +00:00
|
|
|
basic_json(const CompatibleObjectType& value)
|
2015-02-15 22:13:46 +00:00
|
|
|
: m_type(value_t::object)
|
|
|
|
{
|
2015-04-11 17:26:12 +00:00
|
|
|
AllocatorType<object_t> alloc;
|
2015-02-15 22:13:46 +00:00
|
|
|
m_value.object = alloc.allocate(1);
|
2015-03-24 16:39:00 +00:00
|
|
|
using std::begin;
|
|
|
|
using std::end;
|
|
|
|
alloc.construct(m_value.object, begin(value), end(value));
|
2015-02-15 22:13:46 +00:00
|
|
|
}
|
2015-01-31 19:13:11 +00:00
|
|
|
|
2015-06-20 22:59:33 +00:00
|
|
|
/*!
|
|
|
|
@brief create an array (explicit)
|
|
|
|
|
|
|
|
Create an array JSON value with a given content.
|
|
|
|
|
|
|
|
@param value a value for the array
|
|
|
|
|
|
|
|
@complexity Linear in the size of the passed @a value.
|
|
|
|
|
|
|
|
@exception std::bad_alloc if allocation for array value fails (thrown by
|
|
|
|
the constructor of @ref json_value)
|
|
|
|
|
|
|
|
@liveexample{The following code shows the constructor with an @ref array_t
|
|
|
|
parameter.,basic_json__array_t}
|
|
|
|
|
|
|
|
@sa basic_json(const CompatibleArrayType&)
|
|
|
|
*/
|
2015-06-12 08:08:57 +00:00
|
|
|
basic_json(const array_t& value)
|
2015-05-10 14:30:33 +00:00
|
|
|
: m_type(value_t::array), m_value(value)
|
|
|
|
{}
|
2015-01-31 19:13:11 +00:00
|
|
|
|
2015-06-20 22:59:33 +00:00
|
|
|
/*!
|
|
|
|
@brief create an array (implicit)
|
|
|
|
|
|
|
|
Create an array JSON value with a given content. This constructor allows
|
|
|
|
any type that can be used to construct values of type @ref array_t.
|
|
|
|
Examples include the types `std::vector`, `std::list`, and `std::set`.
|
|
|
|
|
|
|
|
@tparam CompatibleArrayType an object type whose `value_type` is compatible
|
|
|
|
to @ref array_t
|
|
|
|
|
|
|
|
@param value a value for the array
|
|
|
|
|
|
|
|
@complexity Linear in the size of the passed @a value.
|
|
|
|
|
|
|
|
@exception std::bad_alloc if allocation for array value fails (thrown by
|
|
|
|
the constructor of @ref json_value)
|
|
|
|
|
|
|
|
@liveexample{The following code shows the constructor with several
|
|
|
|
compatible array type parameters.,basic_json__CompatibleArrayType}
|
|
|
|
|
|
|
|
@sa basic_json(const array_t&)
|
|
|
|
*/
|
|
|
|
template <class CompatibleArrayType, typename
|
2015-01-31 19:13:11 +00:00
|
|
|
std::enable_if<
|
2015-06-21 11:04:03 +00:00
|
|
|
not std::is_same<CompatibleArrayType, typename __basic_json::iterator>::value and
|
|
|
|
not std::is_same<CompatibleArrayType, typename __basic_json::const_iterator>::value and
|
|
|
|
not std::is_same<CompatibleArrayType, typename __basic_json::reverse_iterator>::value and
|
|
|
|
not std::is_same<CompatibleArrayType, typename __basic_json::const_reverse_iterator>::value and
|
2015-06-20 22:59:33 +00:00
|
|
|
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
|
2015-01-31 19:13:11 +00:00
|
|
|
= 0>
|
2015-06-20 22:59:33 +00:00
|
|
|
basic_json(const CompatibleArrayType& value)
|
2015-02-15 22:13:46 +00:00
|
|
|
: m_type(value_t::array)
|
|
|
|
{
|
2015-04-11 17:26:12 +00:00
|
|
|
AllocatorType<array_t> alloc;
|
2015-02-15 22:13:46 +00:00
|
|
|
m_value.array = alloc.allocate(1);
|
2015-03-24 16:39:00 +00:00
|
|
|
using std::begin;
|
|
|
|
using std::end;
|
|
|
|
alloc.construct(m_value.array, begin(value), end(value));
|
2015-02-15 22:13:46 +00:00
|
|
|
}
|
2015-01-31 19:13:11 +00:00
|
|
|
|
|
|
|
/// create a string (explicit)
|
2015-06-12 08:08:57 +00:00
|
|
|
basic_json(const string_t& value)
|
2015-05-10 14:30:33 +00:00
|
|
|
: m_type(value_t::string), m_value(value)
|
|
|
|
{}
|
2015-01-31 19:13:11 +00:00
|
|
|
|
|
|
|
/// create a string (explicit)
|
2015-06-12 08:08:57 +00:00
|
|
|
basic_json(const typename string_t::value_type* value)
|
2015-05-10 14:30:33 +00:00
|
|
|
: basic_json(string_t(value))
|
|
|
|
{}
|
2015-01-31 19:13:11 +00:00
|
|
|
|
|
|
|
/// create a string (implicit)
|
|
|
|
template <class V, typename
|
|
|
|
std::enable_if<
|
|
|
|
std::is_constructible<string_t, V>::value, int>::type
|
|
|
|
= 0>
|
2015-06-12 08:08:57 +00:00
|
|
|
basic_json(const V& value)
|
2015-01-31 19:13:11 +00:00
|
|
|
: basic_json(string_t(value))
|
|
|
|
{}
|
|
|
|
|
|
|
|
/// create a boolean (explicit)
|
2015-06-12 08:08:57 +00:00
|
|
|
basic_json(boolean_t value)
|
2015-01-31 19:13:11 +00:00
|
|
|
: m_type(value_t::boolean), m_value(value)
|
|
|
|
{}
|
|
|
|
|
2015-06-15 17:45:25 +00:00
|
|
|
/*!
|
|
|
|
@brief create an integer number (explicit)
|
|
|
|
|
|
|
|
@tparam T helper type to compare number_integer_t and int
|
|
|
|
@param value an integer to create a JSON number from
|
|
|
|
|
|
|
|
This constructor takes care about explicitly passed values of type
|
|
|
|
number_integer_t. However, this constructor would have the same signature
|
|
|
|
as the existing one for const int values, so we need to switch this one off
|
|
|
|
in case number_integer_t is the same as int.
|
|
|
|
*/
|
|
|
|
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 value)
|
2015-01-31 19:13:11 +00:00
|
|
|
: m_type(value_t::number_integer), m_value(value)
|
|
|
|
{}
|
|
|
|
|
2015-06-15 17:45:25 +00:00
|
|
|
/*!
|
|
|
|
@brief create an int number to support enum type (implicit)
|
|
|
|
|
|
|
|
@param value an integer to create a JSON number from
|
|
|
|
|
|
|
|
This constructor allows to pass enums directly to a constructor. As C++ has
|
|
|
|
no way of specifying the type of an anonymous enum explicitly, we can only
|
|
|
|
rely on the fact that such values implicitly convert to int. As int may
|
|
|
|
already be the same type of number_integer_t, we may need to switch off
|
|
|
|
that constructor, which is done above.
|
|
|
|
*/
|
|
|
|
basic_json(const int value)
|
|
|
|
: m_type(value_t::number_integer),
|
|
|
|
m_value(static_cast<number_integer_t>(value))
|
2015-05-09 13:29:20 +00:00
|
|
|
{}
|
|
|
|
|
2015-01-31 19:13:11 +00:00
|
|
|
/// create an integer number (implicit)
|
|
|
|
template<typename T, typename
|
|
|
|
std::enable_if<
|
|
|
|
std::is_constructible<number_integer_t, T>::value and
|
|
|
|
std::numeric_limits<T>::is_integer, T>::type
|
|
|
|
= 0>
|
2015-06-12 08:08:57 +00:00
|
|
|
basic_json(const T value) noexcept
|
2015-06-15 17:45:25 +00:00
|
|
|
: m_type(value_t::number_integer),
|
|
|
|
m_value(static_cast<number_integer_t>(value))
|
2015-01-31 19:13:11 +00:00
|
|
|
{}
|
|
|
|
|
2015-02-08 13:38:52 +00:00
|
|
|
/// create a floating-point number (explicit)
|
2015-06-15 17:45:25 +00:00
|
|
|
basic_json(const number_float_t value)
|
2015-01-31 19:13:11 +00:00
|
|
|
: m_type(value_t::number_float), m_value(value)
|
2015-05-06 17:52:12 +00:00
|
|
|
{
|
|
|
|
// replace infinity and NAN by null
|
|
|
|
if (not std::isfinite(value))
|
|
|
|
{
|
|
|
|
m_type = value_t::null;
|
|
|
|
m_value = json_value();
|
|
|
|
}
|
|
|
|
}
|
2015-01-31 19:13:11 +00:00
|
|
|
|
2015-02-08 13:38:52 +00:00
|
|
|
/// create a floating-point number (implicit)
|
2015-01-31 19:13:11 +00:00
|
|
|
template<typename T, typename = typename
|
|
|
|
std::enable_if<
|
|
|
|
std::is_constructible<number_float_t, T>::value and
|
|
|
|
std::is_floating_point<T>::value>::type
|
|
|
|
>
|
2015-06-12 08:08:57 +00:00
|
|
|
basic_json(const T value) noexcept
|
2015-05-10 14:30:33 +00:00
|
|
|
: basic_json(number_float_t(value))
|
|
|
|
{}
|
2015-01-31 19:13:11 +00:00
|
|
|
|
2015-06-21 07:44:12 +00:00
|
|
|
/*!
|
|
|
|
@brief create a container (array or object) from an initializer list
|
|
|
|
|
|
|
|
Creates a JSON value of type array or object from the passed initializer
|
|
|
|
list @a init. In case @a type_deduction is `true` (default), the type of
|
|
|
|
the JSON value to be created is deducted from the initializer list @a init
|
|
|
|
according to the following rules:
|
|
|
|
|
|
|
|
1. If the list is empty, an empty JSON object value `{}` is created.
|
|
|
|
2. If the list consists of pairs whose first element is a string, a JSON
|
|
|
|
object value is created where the first elements of the pairs are treated
|
|
|
|
as keys and the second elements are as values.
|
|
|
|
3. In all other cases, an array is created.
|
|
|
|
|
|
|
|
The rules aim to create the best fit between a C++ initializer list and
|
|
|
|
JSON values. The ratioinale is as follows:
|
|
|
|
|
|
|
|
1. The empty initializer list is written as `{}` which is exactly an empty
|
|
|
|
JSON object.
|
|
|
|
2. C++ has now way of describing mapped types other than to list a list of
|
|
|
|
pairs. As JSON requires that keys must be of type string, rule 2 is the
|
|
|
|
weakest constraint one can pose on initializer lists to interpret them as
|
|
|
|
an object.
|
|
|
|
3. In all other cases, the initializer list could not be interpreted as
|
|
|
|
JSON object type, so interpreting it as JSON array type is safe.
|
|
|
|
|
|
|
|
With the rules described above, the following JSON values cannot be expressed by an initializer list:
|
|
|
|
|
|
|
|
- the empty array (`[]`): use @ref array(list_init_t) with an empty
|
|
|
|
initializer list in this case
|
|
|
|
- arrays whose elements satisfy rule 2: use @ref array(list_init_t) with
|
|
|
|
the same initializer list in this case
|
|
|
|
|
|
|
|
@note When used without parentheses around an empty initializer list, @ref
|
|
|
|
basic_json() is called instead of this function, yielding the JSON null
|
|
|
|
value.
|
|
|
|
|
|
|
|
@param init initializer list with JSON values
|
|
|
|
|
|
|
|
@param type_deduction internal parameter; when set to `true`, the type of
|
|
|
|
the JSON value is deducted from the initializer list @a init; when set to
|
|
|
|
`false`, the type provided via @a manual_type is forced. This mode is used
|
|
|
|
by the functions @ref array(list_init_t) and @ref object(list_init_t).
|
|
|
|
|
|
|
|
@param manual_type internal parameter; when @a type_deduction is set to
|
|
|
|
`false`, the created JSON value will use the provided type (only @ref
|
|
|
|
value_t::array and @ref value_t::object are valid); when @a type_deduction
|
|
|
|
is set to `true`, this parameter has no effect
|
|
|
|
|
|
|
|
@throw std::domain_error if @a type_deduction is `false`, @a manual_type is
|
|
|
|
`value_t::object`, but @a init contains an element which is not a pair
|
|
|
|
whose first element is a string
|
|
|
|
|
|
|
|
@complexity Linear in the size of the initializer list @a init.
|
|
|
|
|
|
|
|
@liveexample{The example below shows how JSON values are created from
|
|
|
|
initializer lists,basic_json__list_init_t}
|
|
|
|
|
2015-06-21 11:04:03 +00:00
|
|
|
@sa basic_json array(list_init_t) - create a JSON array value from an
|
|
|
|
initializer list
|
|
|
|
@sa basic_json object(list_init_t) - create a JSON object value from an
|
|
|
|
initializer list
|
2015-06-21 07:44:12 +00:00
|
|
|
*/
|
2015-06-12 08:08:57 +00:00
|
|
|
basic_json(list_init_t init, bool type_deduction = true,
|
2015-06-13 08:29:43 +00:00
|
|
|
value_t manual_type = value_t::array)
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
|
|
|
// the initializer list could describe an object
|
|
|
|
bool is_object = true;
|
|
|
|
|
2015-04-26 19:51:35 +00:00
|
|
|
// check if each element is an array with two elements whose first element
|
|
|
|
// is a string
|
2015-04-24 23:25:42 +00:00
|
|
|
for (const auto& element : init)
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
2015-04-26 19:51:35 +00:00
|
|
|
if (element.m_type != value_t::array or element.size() != 2
|
|
|
|
or element[0].m_type != value_t::string)
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
|
|
|
// we found an element that makes it impossible to use the
|
|
|
|
// initializer list as object
|
|
|
|
is_object = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// adjust type if type deduction is not wanted
|
|
|
|
if (not type_deduction)
|
|
|
|
{
|
|
|
|
// if array is wanted, do not create an object though possible
|
|
|
|
if (manual_type == value_t::array)
|
|
|
|
{
|
|
|
|
is_object = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// if object is wanted but impossible, throw an exception
|
|
|
|
if (manual_type == value_t::object and not is_object)
|
|
|
|
{
|
2015-06-20 12:57:08 +00:00
|
|
|
throw std::domain_error("cannot create object from initializer list");
|
2015-01-31 19:13:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (is_object)
|
|
|
|
{
|
|
|
|
// the initializer list is a list of pairs -> create object
|
|
|
|
m_type = value_t::object;
|
2015-05-10 15:03:50 +00:00
|
|
|
m_value = value_t::object;
|
2015-02-15 22:13:46 +00:00
|
|
|
|
2015-04-24 23:25:42 +00:00
|
|
|
for (auto& element : init)
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
|
|
|
m_value.object->emplace(std::move(*(element[0].m_value.string)), std::move(element[1]));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// the initializer list describes an array -> create array
|
|
|
|
m_type = value_t::array;
|
2015-04-11 17:26:12 +00:00
|
|
|
AllocatorType<array_t> alloc;
|
2015-02-15 22:13:46 +00:00
|
|
|
m_value.array = alloc.allocate(1);
|
2015-04-24 23:25:42 +00:00
|
|
|
alloc.construct(m_value.array, std::move(init));
|
2015-01-31 19:13:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-21 07:44:12 +00:00
|
|
|
/*!
|
|
|
|
@brief explicitly create an array from an initializer list
|
|
|
|
|
|
|
|
Creates a JSON array value from a given initializer list. That is, given a
|
|
|
|
list of values `a, b, c`, creates the JSON value `[a, b, c]`. If the
|
|
|
|
initializer list is empty, the empty array `[]` is created.
|
|
|
|
|
|
|
|
@note This function is only needed to express two edge cases that cannot be
|
|
|
|
realized with the initializer list constructor (@ref
|
|
|
|
basic_json(list_init_t, bool, value_t)). These cases are:
|
|
|
|
1. creating an array whose elements are all pairs whose first element is a
|
|
|
|
string - in this case, the initializer list constructor would create an
|
|
|
|
object, taking the first elements as keys
|
|
|
|
2. creating an empty array - passing the empty initializer list to the
|
|
|
|
initializer list constructor yields an empty object
|
|
|
|
|
|
|
|
@param init initializer list with JSON values to create an array from
|
|
|
|
(optional)
|
|
|
|
|
|
|
|
@return JSON array value
|
|
|
|
|
|
|
|
@complexity Linear in the size of @a init.
|
|
|
|
|
|
|
|
@liveexample{The following code shows an example for the @ref array
|
|
|
|
function.,array}
|
|
|
|
|
2015-06-21 11:04:03 +00:00
|
|
|
@sa basic_json(list_init_t, bool, value_t) - create a JSON value from an
|
|
|
|
initializer list
|
|
|
|
@sa basic_json object(list_init_t) - create a JSON object value from an
|
|
|
|
initializer list
|
2015-06-21 07:44:12 +00:00
|
|
|
*/
|
2015-06-12 08:08:57 +00:00
|
|
|
static basic_json array(list_init_t init = list_init_t())
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
2015-04-24 23:25:42 +00:00
|
|
|
return basic_json(init, false, value_t::array);
|
2015-01-31 19:13:11 +00:00
|
|
|
}
|
|
|
|
|
2015-06-21 07:44:12 +00:00
|
|
|
/*!
|
|
|
|
@brief explicitly create an object from an initializer list
|
|
|
|
|
|
|
|
Creates a JSON object value from a given initializer list. The initializer
|
|
|
|
lists elements must be pairs, and their first elments must be strings. If
|
|
|
|
the initializer list is empty, the empty object `{}` is created.
|
|
|
|
|
|
|
|
@note This function is only added for symmetry reasons. In contrast to the
|
|
|
|
related function @ref basic_json array(list_init_t), there are no cases
|
|
|
|
which can only be expressed by this function. That is, any initializer list
|
|
|
|
@a init can also be passed to the initializer list constructor @ref
|
|
|
|
basic_json(list_init_t, bool, value_t).
|
|
|
|
|
|
|
|
@param init initializer list to create an object from (optional)
|
|
|
|
|
|
|
|
@return JSON object value
|
|
|
|
|
|
|
|
@throw std::domain_error if @a init is not a pair whose first elements are
|
|
|
|
strings; thrown by @ref basic_json(list_init_t, bool, value_t)
|
|
|
|
|
|
|
|
@complexity Linear in the size of @a init.
|
|
|
|
|
|
|
|
@liveexample{The following code shows an example for the @ref object
|
|
|
|
function.,object}
|
|
|
|
|
2015-06-21 11:04:03 +00:00
|
|
|
@sa basic_json(list_init_t, bool, value_t) - create a JSON value from an
|
|
|
|
initializer list
|
|
|
|
@sa basic_json array(list_init_t) - create a JSON array value from an
|
2015-06-21 07:44:12 +00:00
|
|
|
initializer list
|
|
|
|
*/
|
2015-06-12 08:08:57 +00:00
|
|
|
static basic_json object(list_init_t init = list_init_t())
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
2015-04-24 23:25:42 +00:00
|
|
|
return basic_json(init, false, value_t::object);
|
2015-01-31 19:13:11 +00:00
|
|
|
}
|
|
|
|
|
2015-06-21 07:44:12 +00:00
|
|
|
/*!
|
|
|
|
@brief construct an array with count copies of given value
|
|
|
|
|
|
|
|
Constructs a JSON array value by creating @a count copies of a passed
|
|
|
|
value. In case @a count is `0`, an empty array is created. As postcondition,
|
|
|
|
`std::distance(begin(),end()) == count` holds.
|
|
|
|
|
|
|
|
@param count the number of JSON copies of @a value to create
|
|
|
|
@param value the JSON value to copy
|
|
|
|
|
|
|
|
@complexity Linear in @a count.
|
|
|
|
|
|
|
|
@liveexample{The following code shows examples for the @ref
|
|
|
|
basic_json(size_type\, const basic_json&)
|
|
|
|
constructor.,basic_json__size_type_basic_json}
|
|
|
|
*/
|
|
|
|
basic_json(size_type count, const basic_json& value)
|
2015-04-12 10:02:30 +00:00
|
|
|
: m_type(value_t::array)
|
|
|
|
{
|
|
|
|
AllocatorType<array_t> alloc;
|
|
|
|
m_value.array = alloc.allocate(1);
|
2015-06-21 07:44:12 +00:00
|
|
|
alloc.construct(m_value.array, count, value);
|
2015-04-12 10:02:30 +00:00
|
|
|
}
|
2015-02-22 16:52:27 +00:00
|
|
|
|
2015-04-12 11:15:26 +00:00
|
|
|
/// construct a JSON container given an iterator range
|
|
|
|
template <class T, typename
|
|
|
|
std::enable_if<
|
2015-06-21 11:04:03 +00:00
|
|
|
std::is_same<T, typename __basic_json::iterator>::value or
|
|
|
|
std::is_same<T, typename __basic_json::const_iterator>::value
|
2015-04-12 11:15:26 +00:00
|
|
|
, int>::type
|
|
|
|
= 0>
|
2015-06-12 08:08:57 +00:00
|
|
|
basic_json(T first, T last)
|
2015-04-12 11:15:26 +00:00
|
|
|
{
|
|
|
|
// make sure iterator fits the current value
|
|
|
|
if (first.m_object != last.m_object or
|
|
|
|
first.m_object->m_type != last.m_object->m_type)
|
|
|
|
{
|
2015-06-14 17:35:20 +00:00
|
|
|
throw std::domain_error("iterators are not compatible");
|
2015-04-12 11:15:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// set the type
|
|
|
|
m_type = first.m_object->m_type;
|
|
|
|
|
|
|
|
// check if iterator range is complete for non-compound values
|
|
|
|
switch (m_type)
|
|
|
|
{
|
|
|
|
case value_t::number_integer:
|
|
|
|
case value_t::number_float:
|
|
|
|
case value_t::boolean:
|
|
|
|
case value_t::string:
|
|
|
|
{
|
|
|
|
if (first.m_it.generic_iterator != 0 or last.m_it.generic_iterator != 1)
|
|
|
|
{
|
|
|
|
throw std::out_of_range("iterators out of range");
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (m_type)
|
|
|
|
{
|
|
|
|
case value_t::number_integer:
|
|
|
|
{
|
|
|
|
m_value.number_integer = first.m_object->m_value.number_integer;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case value_t::number_float:
|
|
|
|
{
|
|
|
|
m_value.number_float = first.m_object->m_value.number_float;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case value_t::boolean:
|
|
|
|
{
|
|
|
|
m_value.boolean = first.m_object->m_value.boolean;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case value_t::string:
|
|
|
|
{
|
2015-05-10 14:30:33 +00:00
|
|
|
m_value = *first.m_object->m_value.string;
|
2015-04-12 11:15:26 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case value_t::object:
|
|
|
|
{
|
|
|
|
AllocatorType<object_t> alloc;
|
|
|
|
m_value.object = alloc.allocate(1);
|
|
|
|
alloc.construct(m_value.object, first.m_it.object_iterator, last.m_it.object_iterator);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case value_t::array:
|
|
|
|
{
|
|
|
|
AllocatorType<array_t> alloc;
|
|
|
|
m_value.array = alloc.allocate(1);
|
|
|
|
alloc.construct(m_value.array, first.m_it.array_iterator, last.m_it.array_iterator);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
{
|
2015-06-14 17:35:20 +00:00
|
|
|
throw std::domain_error("cannot use construct with iterators from " + first.m_object->type_name());
|
2015-04-12 11:15:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-31 19:13:11 +00:00
|
|
|
///////////////////////////////////////
|
|
|
|
// other constructors and destructor //
|
|
|
|
///////////////////////////////////////
|
|
|
|
|
2015-02-22 16:52:27 +00:00
|
|
|
/*!
|
|
|
|
@brief copy constructor
|
2015-02-24 22:19:19 +00:00
|
|
|
|
2015-06-20 22:59:33 +00:00
|
|
|
Creates a copy of a given JSON value.
|
|
|
|
|
|
|
|
@param other the JSON value to copy
|
|
|
|
|
|
|
|
@complexity Linear in the size of @a other.
|
|
|
|
|
|
|
|
@requirement This function satisfies the Container requirements:
|
|
|
|
- The complexity is linear.
|
|
|
|
- As postcondition, it holds: `other == basic_json(other)`.
|
|
|
|
|
|
|
|
@exception std::bad_alloc if allocation for object, array, or string fails.
|
|
|
|
|
|
|
|
@liveexample{The following code shows an example for the copy
|
|
|
|
constructor.,basic_json__basic_json}
|
2015-02-24 22:19:19 +00:00
|
|
|
|
2015-02-22 16:52:27 +00:00
|
|
|
@ingroup container
|
|
|
|
*/
|
2015-06-12 08:08:57 +00:00
|
|
|
basic_json(const basic_json& other)
|
2015-01-31 19:13:11 +00:00
|
|
|
: m_type(other.m_type)
|
|
|
|
{
|
|
|
|
switch (m_type)
|
|
|
|
{
|
|
|
|
case (value_t::null):
|
2015-05-03 15:52:13 +00:00
|
|
|
case (value_t::discarded):
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
2015-02-24 22:19:19 +00:00
|
|
|
|
2015-01-31 19:13:11 +00:00
|
|
|
case (value_t::object):
|
|
|
|
{
|
2015-05-10 14:30:33 +00:00
|
|
|
m_value = *other.m_value.object;
|
2015-01-31 19:13:11 +00:00
|
|
|
break;
|
|
|
|
}
|
2015-02-24 22:19:19 +00:00
|
|
|
|
2015-01-31 19:13:11 +00:00
|
|
|
case (value_t::array):
|
|
|
|
{
|
2015-05-10 14:30:33 +00:00
|
|
|
m_value = *other.m_value.array;
|
2015-01-31 19:13:11 +00:00
|
|
|
break;
|
|
|
|
}
|
2015-02-24 22:19:19 +00:00
|
|
|
|
2015-01-31 19:13:11 +00:00
|
|
|
case (value_t::string):
|
|
|
|
{
|
2015-05-10 14:30:33 +00:00
|
|
|
m_value = *other.m_value.string;
|
2015-01-31 19:13:11 +00:00
|
|
|
break;
|
|
|
|
}
|
2015-02-24 22:19:19 +00:00
|
|
|
|
2015-01-31 19:13:11 +00:00
|
|
|
case (value_t::boolean):
|
|
|
|
{
|
2015-05-10 14:30:33 +00:00
|
|
|
m_value = other.m_value.boolean;
|
2015-01-31 19:13:11 +00:00
|
|
|
break;
|
|
|
|
}
|
2015-02-24 22:19:19 +00:00
|
|
|
|
2015-01-31 19:13:11 +00:00
|
|
|
case (value_t::number_integer):
|
|
|
|
{
|
2015-05-10 14:30:33 +00:00
|
|
|
m_value = other.m_value.number_integer;
|
2015-01-31 19:13:11 +00:00
|
|
|
break;
|
|
|
|
}
|
2015-02-24 22:19:19 +00:00
|
|
|
|
2015-01-31 19:13:11 +00:00
|
|
|
case (value_t::number_float):
|
|
|
|
{
|
2015-05-10 14:30:33 +00:00
|
|
|
m_value = other.m_value.number_float;
|
2015-01-31 19:13:11 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// move constructor
|
2015-06-12 08:08:57 +00:00
|
|
|
basic_json(basic_json&& other) noexcept
|
2015-01-31 19:13:11 +00:00
|
|
|
: m_type(std::move(other.m_type)),
|
|
|
|
m_value(std::move(other.m_value))
|
|
|
|
{
|
2015-02-08 11:53:10 +00:00
|
|
|
// invalidate payload
|
2015-01-31 19:13:11 +00:00
|
|
|
other.m_type = value_t::null;
|
|
|
|
other.m_value = {};
|
|
|
|
}
|
|
|
|
|
2015-02-22 16:52:27 +00:00
|
|
|
/*!
|
|
|
|
@brief copy assignment
|
2015-06-20 22:59:33 +00:00
|
|
|
|
|
|
|
The copy assignment operator is expressed in terms of the copy constructor,
|
|
|
|
destructor, and the swap() member function.
|
|
|
|
|
|
|
|
@complexity Linear.
|
|
|
|
|
|
|
|
@requirement This function satisfies the Container requirements:
|
|
|
|
- The complexity is linear.
|
|
|
|
|
2015-02-22 16:52:27 +00:00
|
|
|
@ingroup container
|
|
|
|
*/
|
2015-06-12 08:08:57 +00:00
|
|
|
reference& operator=(basic_json other) noexcept (
|
2015-02-13 20:46:33 +00:00
|
|
|
std::is_nothrow_move_constructible<value_t>::value and
|
|
|
|
std::is_nothrow_move_assignable<value_t>::value and
|
|
|
|
std::is_nothrow_move_constructible<json_value>::value and
|
|
|
|
std::is_nothrow_move_assignable<json_value>::value
|
|
|
|
)
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
2015-04-24 23:25:42 +00:00
|
|
|
using std::swap;
|
2015-01-31 19:13:11 +00:00
|
|
|
std::swap(m_type, other.m_type);
|
|
|
|
std::swap(m_value, other.m_value);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2015-02-22 16:52:27 +00:00
|
|
|
/*!
|
|
|
|
@brief destructor
|
2015-06-20 22:59:33 +00:00
|
|
|
|
|
|
|
Destroys the JSON value and frees all memory.
|
|
|
|
|
|
|
|
@complexity Linear.
|
|
|
|
|
|
|
|
@requirement This function satisfies the Container requirements:
|
|
|
|
- The complexity is linear.
|
|
|
|
- All stored elements are destroyed and all memory is freed.
|
|
|
|
|
2015-02-22 16:52:27 +00:00
|
|
|
@ingroup container
|
|
|
|
*/
|
2015-06-12 08:08:57 +00:00
|
|
|
~basic_json() noexcept
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
|
|
|
switch (m_type)
|
|
|
|
{
|
|
|
|
case (value_t::object):
|
|
|
|
{
|
2015-04-11 17:26:12 +00:00
|
|
|
AllocatorType<object_t> alloc;
|
2015-02-15 22:13:46 +00:00
|
|
|
alloc.destroy(m_value.object);
|
|
|
|
alloc.deallocate(m_value.object, 1);
|
2015-01-31 19:13:11 +00:00
|
|
|
m_value.object = nullptr;
|
|
|
|
break;
|
|
|
|
}
|
2015-02-08 11:53:10 +00:00
|
|
|
|
2015-01-31 19:13:11 +00:00
|
|
|
case (value_t::array):
|
|
|
|
{
|
2015-04-11 17:26:12 +00:00
|
|
|
AllocatorType<array_t> alloc;
|
2015-02-15 22:13:46 +00:00
|
|
|
alloc.destroy(m_value.array);
|
|
|
|
alloc.deallocate(m_value.array, 1);
|
2015-01-31 19:13:11 +00:00
|
|
|
m_value.array = nullptr;
|
|
|
|
break;
|
|
|
|
}
|
2015-02-08 11:53:10 +00:00
|
|
|
|
2015-01-31 19:13:11 +00:00
|
|
|
case (value_t::string):
|
|
|
|
{
|
2015-04-11 17:26:12 +00:00
|
|
|
AllocatorType<string_t> alloc;
|
2015-02-15 21:58:35 +00:00
|
|
|
alloc.destroy(m_value.string);
|
2015-02-15 21:49:26 +00:00
|
|
|
alloc.deallocate(m_value.string, 1);
|
2015-01-31 19:13:11 +00:00
|
|
|
m_value.string = nullptr;
|
|
|
|
break;
|
|
|
|
}
|
2015-02-08 11:53:10 +00:00
|
|
|
|
|
|
|
default:
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
2015-02-08 11:53:10 +00:00
|
|
|
// all other types need no specific destructor
|
2015-01-31 19:13:11 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
///////////////////////
|
|
|
|
// object inspection //
|
|
|
|
///////////////////////
|
|
|
|
|
2015-06-20 22:59:33 +00:00
|
|
|
/// @name object inspection
|
|
|
|
/// @{
|
|
|
|
|
2015-01-31 19:13:11 +00:00
|
|
|
/*!
|
2015-02-08 15:08:48 +00:00
|
|
|
@brief serialization
|
|
|
|
|
2015-02-24 22:19:19 +00:00
|
|
|
Serialization function for JSON objects. The function tries to mimick
|
|
|
|
Python's @p json.dumps() function, and currently supports its @p indent
|
|
|
|
parameter.
|
2015-01-31 19:13:11 +00:00
|
|
|
|
2015-06-14 17:35:20 +00:00
|
|
|
@param indent if indent is nonnegative, then array elements and object
|
2015-02-16 21:47:30 +00:00
|
|
|
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
|
2015-01-31 19:13:11 +00:00
|
|
|
|
|
|
|
@see https://docs.python.org/2/library/json.html#json.dump
|
|
|
|
*/
|
2015-06-12 08:08:57 +00:00
|
|
|
string_t dump(const int indent = -1) const noexcept
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
2015-06-03 21:34:10 +00:00
|
|
|
std::stringstream ss;
|
|
|
|
|
2015-01-31 19:13:11 +00:00
|
|
|
if (indent >= 0)
|
|
|
|
{
|
2015-06-03 21:34:10 +00:00
|
|
|
dump(ss, true, static_cast<unsigned int>(indent));
|
2015-01-31 19:13:11 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-06-03 21:34:10 +00:00
|
|
|
dump(ss, false, 0);
|
2015-01-31 19:13:11 +00:00
|
|
|
}
|
2015-06-03 21:34:10 +00:00
|
|
|
|
|
|
|
return ss.str();
|
2015-01-31 19:13:11 +00:00
|
|
|
}
|
|
|
|
|
2015-02-08 14:47:40 +00:00
|
|
|
/// return the type of the object (explicit)
|
2015-06-12 08:08:57 +00:00
|
|
|
value_t type() const noexcept
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
|
|
|
return m_type;
|
|
|
|
}
|
|
|
|
|
2015-06-20 22:59:33 +00:00
|
|
|
/*!
|
|
|
|
@brief return whether value is null
|
|
|
|
|
|
|
|
This function returns true iff the JSON value is null.
|
|
|
|
|
|
|
|
@return `true` if value type is null, `false` otherwise.
|
|
|
|
|
|
|
|
@complexity Constant.
|
|
|
|
|
|
|
|
@liveexample{The following code exemplifies @ref is_null for all JSON
|
|
|
|
value types.,is_null}
|
|
|
|
*/
|
2015-06-12 08:08:57 +00:00
|
|
|
bool is_null() const noexcept
|
2015-02-22 16:52:27 +00:00
|
|
|
{
|
|
|
|
return m_type == value_t::null;
|
|
|
|
}
|
|
|
|
|
2015-06-20 22:59:33 +00:00
|
|
|
/*!
|
|
|
|
@brief return whether value is a boolean
|
|
|
|
|
|
|
|
This function returns true iff the JSON value is a boolean.
|
|
|
|
|
|
|
|
@return `true` if value type is boolean, `false` otherwise.
|
|
|
|
|
|
|
|
@complexity Constant.
|
|
|
|
|
|
|
|
@liveexample{The following code exemplifies @ref is_boolean for all JSON
|
|
|
|
value types.,is_boolean}
|
|
|
|
*/
|
2015-06-12 08:08:57 +00:00
|
|
|
bool is_boolean() const noexcept
|
2015-02-22 16:52:27 +00:00
|
|
|
{
|
|
|
|
return m_type == value_t::boolean;
|
|
|
|
}
|
|
|
|
|
2015-06-20 22:59:33 +00:00
|
|
|
/*!
|
|
|
|
@brief return whether value is a number
|
|
|
|
|
|
|
|
This function returns true iff the JSON value is a number. This includes
|
|
|
|
both integer and floating-point values.
|
|
|
|
|
|
|
|
@return `true` if value type is number, `false` otherwise.
|
|
|
|
|
|
|
|
@complexity Constant.
|
|
|
|
|
|
|
|
@liveexample{The following code exemplifies @ref is_number for all JSON
|
|
|
|
value types.,is_number}
|
|
|
|
*/
|
2015-06-12 08:08:57 +00:00
|
|
|
bool is_number() const noexcept
|
2015-02-22 16:52:27 +00:00
|
|
|
{
|
|
|
|
return (m_type == value_t::number_integer) or (m_type == value_t::number_float);
|
|
|
|
}
|
|
|
|
|
2015-06-20 22:59:33 +00:00
|
|
|
/*!
|
|
|
|
@brief return whether value is an integer number
|
|
|
|
|
|
|
|
This function returns true iff the JSON value is an integer number. This
|
|
|
|
excludes floating-point values.
|
|
|
|
|
|
|
|
@return `true` if value type is an integer number, `false` otherwise.
|
|
|
|
|
|
|
|
@complexity Constant.
|
|
|
|
|
|
|
|
@liveexample{The following code exemplifies @ref is_number_integer for all
|
|
|
|
JSON value types.,is_number_integer}
|
|
|
|
*/
|
2015-06-15 14:37:49 +00:00
|
|
|
bool is_number_integer() const noexcept
|
|
|
|
{
|
|
|
|
return m_type == value_t::number_integer;
|
|
|
|
}
|
|
|
|
|
2015-06-20 22:59:33 +00:00
|
|
|
/*!
|
|
|
|
@brief return whether value is a floating-point number
|
|
|
|
|
|
|
|
This function returns true iff the JSON value is a floating-point number.
|
|
|
|
This excludes integer values.
|
|
|
|
|
|
|
|
@return `true` if value type is a floating-point number, `false` otherwise.
|
|
|
|
|
|
|
|
@complexity Constant.
|
|
|
|
|
|
|
|
@liveexample{The following code exemplifies @ref is_number_float for all
|
|
|
|
JSON value types.,is_number_float}
|
|
|
|
*/
|
2015-06-15 14:37:49 +00:00
|
|
|
bool is_number_float() const noexcept
|
|
|
|
{
|
|
|
|
return m_type == value_t::number_float;
|
|
|
|
}
|
|
|
|
|
2015-06-20 22:59:33 +00:00
|
|
|
/*!
|
|
|
|
@brief return whether value is an object
|
|
|
|
|
|
|
|
This function returns true iff the JSON value is an object.
|
|
|
|
|
|
|
|
@return `true` if value type is object, `false` otherwise.
|
|
|
|
|
|
|
|
@complexity Constant.
|
|
|
|
|
|
|
|
@liveexample{The following code exemplifies @ref is_object for all JSON
|
|
|
|
value types.,is_object}
|
|
|
|
*/
|
2015-06-12 08:08:57 +00:00
|
|
|
bool is_object() const noexcept
|
2015-02-22 16:52:27 +00:00
|
|
|
{
|
|
|
|
return m_type == value_t::object;
|
|
|
|
}
|
|
|
|
|
2015-06-20 22:59:33 +00:00
|
|
|
/*!
|
|
|
|
@brief return whether value is an array
|
|
|
|
|
|
|
|
This function returns true iff the JSON value is an array.
|
|
|
|
|
|
|
|
@return `true` if value type is array, `false` otherwise.
|
|
|
|
|
|
|
|
@complexity Constant.
|
|
|
|
|
|
|
|
@liveexample{The following code exemplifies @ref is_array for all JSON
|
|
|
|
value types.,is_array}
|
|
|
|
*/
|
2015-06-12 08:08:57 +00:00
|
|
|
bool is_array() const noexcept
|
2015-02-22 16:52:27 +00:00
|
|
|
{
|
|
|
|
return m_type == value_t::array;
|
|
|
|
}
|
|
|
|
|
2015-06-20 22:59:33 +00:00
|
|
|
/*!
|
|
|
|
@brief return whether value is a string
|
|
|
|
|
|
|
|
This function returns true iff the JSON value is a string.
|
|
|
|
|
|
|
|
@return `true` if value type is string, `false` otherwise.
|
|
|
|
|
|
|
|
@complexity Constant.
|
|
|
|
|
|
|
|
@liveexample{The following code exemplifies @ref is_string for all JSON
|
|
|
|
value types.,is_string}
|
|
|
|
*/
|
2015-06-12 08:08:57 +00:00
|
|
|
bool is_string() const noexcept
|
2015-02-22 16:52:27 +00:00
|
|
|
{
|
|
|
|
return m_type == value_t::string;
|
|
|
|
}
|
|
|
|
|
2015-05-03 15:52:13 +00:00
|
|
|
// return whether value is discarded
|
2015-06-12 08:08:57 +00:00
|
|
|
bool is_discarded() const noexcept
|
2015-05-03 15:52:13 +00:00
|
|
|
{
|
|
|
|
return m_type == value_t::discarded;
|
|
|
|
}
|
|
|
|
|
2015-04-26 19:51:35 +00:00
|
|
|
/// return the type of the object (implicit)
|
2015-06-12 08:08:57 +00:00
|
|
|
operator value_t() const noexcept
|
2015-04-26 19:51:35 +00:00
|
|
|
{
|
|
|
|
return m_type;
|
|
|
|
}
|
|
|
|
|
2015-06-20 22:59:33 +00:00
|
|
|
/// @}
|
|
|
|
|
2015-04-08 20:23:40 +00:00
|
|
|
private:
|
2015-06-20 22:59:33 +00:00
|
|
|
//////////////////
|
|
|
|
// value access //
|
|
|
|
//////////////////
|
2015-01-31 19:13:11 +00:00
|
|
|
|
2015-02-08 15:08:48 +00:00
|
|
|
/// get an object (explicit)
|
2015-01-31 19:13:11 +00:00
|
|
|
template <class T, typename
|
|
|
|
std::enable_if<
|
2015-04-08 20:23:40 +00:00
|
|
|
std::is_convertible<typename object_t::key_type, typename T::key_type>::value and
|
2015-06-21 11:04:03 +00:00
|
|
|
std::is_convertible<__basic_json, typename T::mapped_type>::value
|
2015-04-08 20:23:40 +00:00
|
|
|
, int>::type = 0>
|
2015-06-12 08:08:57 +00:00
|
|
|
T get_impl(T*) const
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
|
|
|
switch (m_type)
|
|
|
|
{
|
|
|
|
case (value_t::object):
|
2015-04-08 20:23:40 +00:00
|
|
|
{
|
2015-01-31 19:13:11 +00:00
|
|
|
return T(m_value.object->begin(), m_value.object->end());
|
2015-04-08 20:23:40 +00:00
|
|
|
}
|
2015-01-31 19:13:11 +00:00
|
|
|
default:
|
2015-04-08 20:23:40 +00:00
|
|
|
{
|
2015-06-20 12:57:08 +00:00
|
|
|
throw std::domain_error("value type must be object, but is " + type_name());
|
2015-04-08 20:23:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// get an object (explicit)
|
2015-06-12 08:08:57 +00:00
|
|
|
object_t get_impl(object_t*) const
|
2015-04-08 20:23:40 +00:00
|
|
|
{
|
|
|
|
switch (m_type)
|
|
|
|
{
|
|
|
|
case (value_t::object):
|
|
|
|
{
|
|
|
|
return *(m_value.object);
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
{
|
2015-06-20 12:57:08 +00:00
|
|
|
throw std::domain_error("value type must be object, but is " + type_name());
|
2015-04-08 20:23:40 +00:00
|
|
|
}
|
2015-01-31 19:13:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-08 15:08:48 +00:00
|
|
|
/// get an array (explicit)
|
2015-01-31 19:13:11 +00:00
|
|
|
template <class T, typename
|
|
|
|
std::enable_if<
|
2015-06-21 11:04:03 +00:00
|
|
|
std::is_convertible<__basic_json, typename T::value_type>::value and
|
|
|
|
not std::is_same<__basic_json, typename T::value_type>::value and
|
2015-04-08 20:23:40 +00:00
|
|
|
not std::is_arithmetic<T>::value and
|
|
|
|
not std::is_convertible<std::string, T>::value and
|
2015-06-20 22:59:33 +00:00
|
|
|
not internals::has_mapped_type<T>::value
|
2015-04-08 20:23:40 +00:00
|
|
|
, int>::type = 0>
|
2015-06-12 08:08:57 +00:00
|
|
|
T get_impl(T*) const
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
|
|
|
switch (m_type)
|
|
|
|
{
|
|
|
|
case (value_t::array):
|
2015-04-08 20:23:40 +00:00
|
|
|
{
|
|
|
|
T to_vector;
|
|
|
|
std::transform(m_value.array->begin(), m_value.array->end(),
|
|
|
|
std::inserter(to_vector, to_vector.end()), [](basic_json i)
|
|
|
|
{
|
|
|
|
return i.get<typename T::value_type>();
|
|
|
|
});
|
|
|
|
return to_vector;
|
|
|
|
}
|
2015-01-31 19:13:11 +00:00
|
|
|
default:
|
2015-04-08 20:23:40 +00:00
|
|
|
{
|
2015-06-20 12:57:08 +00:00
|
|
|
throw std::domain_error("value type must be array, but is " + type_name());
|
2015-04-08 20:23:40 +00:00
|
|
|
}
|
2015-01-31 19:13:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-08 20:23:40 +00:00
|
|
|
/// get an array (explicit)
|
|
|
|
template <class T, typename
|
2015-01-31 19:13:11 +00:00
|
|
|
std::enable_if<
|
2015-06-21 11:04:03 +00:00
|
|
|
std::is_convertible<__basic_json, T>::value and
|
|
|
|
not std::is_same<__basic_json, T>::value
|
2015-04-08 20:23:40 +00:00
|
|
|
, int>::type = 0>
|
2015-06-12 08:08:57 +00:00
|
|
|
std::vector<T> get_impl(std::vector<T>*) const
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
|
|
|
switch (m_type)
|
|
|
|
{
|
2015-04-08 20:23:40 +00:00
|
|
|
case (value_t::array):
|
|
|
|
{
|
|
|
|
std::vector<T> to_vector;
|
|
|
|
to_vector.reserve(m_value.array->size());
|
|
|
|
std::transform(m_value.array->begin(), m_value.array->end(),
|
|
|
|
std::inserter(to_vector, to_vector.end()), [](basic_json i)
|
|
|
|
{
|
|
|
|
return i.get<T>();
|
|
|
|
});
|
|
|
|
return to_vector;
|
|
|
|
}
|
2015-01-31 19:13:11 +00:00
|
|
|
default:
|
2015-04-08 20:23:40 +00:00
|
|
|
{
|
2015-06-20 12:57:08 +00:00
|
|
|
throw std::domain_error("value type must be array, but is " + type_name());
|
2015-04-08 20:23:40 +00:00
|
|
|
}
|
2015-01-31 19:13:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-08 20:23:40 +00:00
|
|
|
/// get an array (explicit)
|
|
|
|
template <class T, typename
|
|
|
|
std::enable_if<
|
|
|
|
std::is_same<basic_json, typename T::value_type>::value and
|
2015-06-20 22:59:33 +00:00
|
|
|
not internals::has_mapped_type<T>::value
|
2015-04-08 20:23:40 +00:00
|
|
|
, int>::type = 0>
|
2015-06-12 08:08:57 +00:00
|
|
|
T get_impl(T*) const
|
2015-04-08 20:23:40 +00:00
|
|
|
{
|
|
|
|
switch (m_type)
|
|
|
|
{
|
|
|
|
case (value_t::array):
|
|
|
|
{
|
|
|
|
return T(m_value.array->begin(), m_value.array->end());
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
{
|
2015-06-20 12:57:08 +00:00
|
|
|
throw std::domain_error("value type must be array, but is " + type_name());
|
2015-04-08 20:23:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-12 08:08:57 +00:00
|
|
|
array_t get_impl(array_t*) const
|
2015-04-08 20:23:40 +00:00
|
|
|
{
|
|
|
|
switch (m_type)
|
|
|
|
{
|
|
|
|
case (value_t::array):
|
|
|
|
{
|
|
|
|
return *(m_value.array);
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
{
|
2015-06-20 12:57:08 +00:00
|
|
|
throw std::domain_error("value type must be array, but is " + type_name());
|
2015-04-08 20:23:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// get a string (explicit)
|
2015-01-31 19:13:11 +00:00
|
|
|
template <typename T, typename
|
|
|
|
std::enable_if<
|
2015-04-08 20:23:40 +00:00
|
|
|
std::is_convertible<string_t, T>::value
|
|
|
|
, int>::type = 0>
|
2015-06-12 08:08:57 +00:00
|
|
|
T get_impl(T*) const
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
|
|
|
switch (m_type)
|
|
|
|
{
|
2015-04-08 20:23:40 +00:00
|
|
|
case (value_t::string):
|
|
|
|
{
|
|
|
|
return *m_value.string;
|
|
|
|
}
|
2015-01-31 19:13:11 +00:00
|
|
|
default:
|
2015-04-08 20:23:40 +00:00
|
|
|
{
|
2015-06-20 12:57:08 +00:00
|
|
|
throw std::domain_error("value type must be string, but is " + type_name());
|
2015-04-08 20:23:40 +00:00
|
|
|
}
|
2015-01-31 19:13:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-08 15:08:48 +00:00
|
|
|
/// get a number (explicit)
|
2015-01-31 19:13:11 +00:00
|
|
|
template<typename T, typename
|
|
|
|
std::enable_if<
|
2015-04-08 20:23:40 +00:00
|
|
|
std::is_arithmetic<T>::value
|
|
|
|
, int>::type = 0>
|
2015-06-12 08:08:57 +00:00
|
|
|
T get_impl(T*) const
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
|
|
|
switch (m_type)
|
|
|
|
{
|
|
|
|
case (value_t::number_integer):
|
2015-04-08 20:23:40 +00:00
|
|
|
{
|
2015-01-31 19:13:11 +00:00
|
|
|
return static_cast<T>(m_value.number_integer);
|
2015-04-08 20:23:40 +00:00
|
|
|
}
|
2015-01-31 19:13:11 +00:00
|
|
|
case (value_t::number_float):
|
2015-04-08 20:23:40 +00:00
|
|
|
{
|
2015-01-31 19:13:11 +00:00
|
|
|
return static_cast<T>(m_value.number_float);
|
2015-04-08 20:23:40 +00:00
|
|
|
}
|
2015-01-31 19:13:11 +00:00
|
|
|
default:
|
2015-04-08 20:23:40 +00:00
|
|
|
{
|
2015-06-20 12:57:08 +00:00
|
|
|
throw std::domain_error("value type must be number, but is " + type_name());
|
2015-04-08 20:23:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// get a boolean (explicit)
|
2015-06-12 08:08:57 +00:00
|
|
|
boolean_t get_impl(boolean_t*) const
|
2015-04-08 20:23:40 +00:00
|
|
|
{
|
|
|
|
switch (m_type)
|
|
|
|
{
|
|
|
|
case (value_t::boolean):
|
|
|
|
{
|
|
|
|
return m_value.boolean;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
{
|
2015-06-20 12:57:08 +00:00
|
|
|
throw std::domain_error("value type must be boolean, but is " + type_name());
|
2015-04-08 20:23:40 +00:00
|
|
|
}
|
2015-01-31 19:13:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-08 20:23:40 +00:00
|
|
|
public:
|
2015-06-20 22:59:33 +00:00
|
|
|
|
|
|
|
/// @name value access
|
|
|
|
/// @{
|
|
|
|
|
2015-04-08 20:23:40 +00:00
|
|
|
/// get a value (explicit)
|
|
|
|
// <http://stackoverflow.com/a/8315197/266378>
|
|
|
|
template<typename T>
|
2015-06-12 08:08:57 +00:00
|
|
|
T get() const
|
2015-04-08 20:23:40 +00:00
|
|
|
{
|
|
|
|
return get_impl(static_cast<T*>(nullptr));
|
|
|
|
}
|
|
|
|
|
2015-02-08 15:08:48 +00:00
|
|
|
/// get a value (implicit)
|
2015-01-31 19:13:11 +00:00
|
|
|
template<typename T>
|
2015-06-12 08:08:57 +00:00
|
|
|
operator T() const
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
|
|
|
return get<T>();
|
|
|
|
}
|
|
|
|
|
2015-06-20 22:59:33 +00:00
|
|
|
/// @}
|
|
|
|
|
2015-01-31 19:13:11 +00:00
|
|
|
|
|
|
|
////////////////////
|
|
|
|
// element access //
|
|
|
|
////////////////////
|
|
|
|
|
2015-06-20 22:59:33 +00:00
|
|
|
/// @name element access
|
|
|
|
/// @{
|
|
|
|
|
2015-01-31 19:13:11 +00:00
|
|
|
/// access specified element with bounds checking
|
2015-06-12 08:08:57 +00:00
|
|
|
reference at(size_type idx)
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
|
|
|
// at only works for arrays
|
|
|
|
if (m_type != value_t::array)
|
|
|
|
{
|
2015-06-20 12:57:08 +00:00
|
|
|
throw std::domain_error("cannot use at() with " + type_name());
|
2015-01-31 19:13:11 +00:00
|
|
|
}
|
|
|
|
|
2015-04-12 14:19:21 +00:00
|
|
|
return m_value.array->at(idx);
|
2015-01-31 19:13:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// access specified element with bounds checking
|
2015-06-12 08:08:57 +00:00
|
|
|
const_reference at(size_type idx) const
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
|
|
|
// at only works for arrays
|
|
|
|
if (m_type != value_t::array)
|
|
|
|
{
|
2015-06-20 12:57:08 +00:00
|
|
|
throw std::domain_error("cannot use at() with " + type_name());
|
2015-01-31 19:13:11 +00:00
|
|
|
}
|
|
|
|
|
2015-04-12 14:19:21 +00:00
|
|
|
return m_value.array->at(idx);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// access specified element with bounds checking
|
2015-06-12 08:08:57 +00:00
|
|
|
reference at(const typename object_t::key_type& key)
|
2015-04-12 14:19:21 +00:00
|
|
|
{
|
|
|
|
// at only works for objects
|
|
|
|
if (m_type != value_t::object)
|
|
|
|
{
|
2015-06-20 12:57:08 +00:00
|
|
|
throw std::domain_error("cannot use at() with " + type_name());
|
2015-04-12 14:19:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return m_value.object->at(key);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// access specified element with bounds checking
|
2015-06-12 08:08:57 +00:00
|
|
|
const_reference at(const typename object_t::key_type& key) const
|
2015-04-12 14:19:21 +00:00
|
|
|
{
|
|
|
|
// at only works for objects
|
|
|
|
if (m_type != value_t::object)
|
|
|
|
{
|
2015-06-20 12:57:08 +00:00
|
|
|
throw std::domain_error("cannot use at() with " + type_name());
|
2015-04-12 14:19:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return m_value.object->at(key);
|
2015-01-31 19:13:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// access specified element
|
2015-06-12 08:08:57 +00:00
|
|
|
reference operator[](size_type idx)
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
2015-02-21 12:24:07 +00:00
|
|
|
// implicitly convert null to object
|
|
|
|
if (m_type == value_t::null)
|
|
|
|
{
|
|
|
|
m_type = value_t::array;
|
2015-04-11 17:26:12 +00:00
|
|
|
AllocatorType<array_t> alloc;
|
2015-02-21 12:24:07 +00:00
|
|
|
m_value.array = alloc.allocate(1);
|
|
|
|
alloc.construct(m_value.array);
|
|
|
|
}
|
|
|
|
|
|
|
|
// [] only works for arrays
|
2015-01-31 19:13:11 +00:00
|
|
|
if (m_type != value_t::array)
|
|
|
|
{
|
2015-06-20 12:57:08 +00:00
|
|
|
throw std::domain_error("cannot use operator[] with " + type_name());
|
2015-01-31 19:13:11 +00:00
|
|
|
}
|
|
|
|
|
2015-04-12 14:19:21 +00:00
|
|
|
for (size_t i = m_value.array->size(); i <= idx; ++i)
|
2015-02-21 12:24:07 +00:00
|
|
|
{
|
|
|
|
m_value.array->push_back(basic_json());
|
|
|
|
}
|
|
|
|
|
2015-04-12 14:19:21 +00:00
|
|
|
return m_value.array->operator[](idx);
|
2015-01-31 19:13:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// access specified element
|
2015-06-12 08:08:57 +00:00
|
|
|
const_reference operator[](size_type idx) const
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
|
|
|
// at only works for arrays
|
|
|
|
if (m_type != value_t::array)
|
|
|
|
{
|
2015-06-20 12:57:08 +00:00
|
|
|
throw std::domain_error("cannot use operator[] with " + type_name());
|
2015-01-31 19:13:11 +00:00
|
|
|
}
|
|
|
|
|
2015-04-12 14:19:21 +00:00
|
|
|
return m_value.array->operator[](idx);
|
2015-01-31 19:13:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// access specified element
|
2015-06-12 08:08:57 +00:00
|
|
|
reference operator[](const typename object_t::key_type& key)
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
2015-02-18 21:28:56 +00:00
|
|
|
// implicitly convert null to object
|
|
|
|
if (m_type == value_t::null)
|
|
|
|
{
|
|
|
|
m_type = value_t::object;
|
2015-04-11 17:26:12 +00:00
|
|
|
AllocatorType<object_t> alloc;
|
2015-02-18 21:28:56 +00:00
|
|
|
m_value.object = alloc.allocate(1);
|
|
|
|
alloc.construct(m_value.object);
|
|
|
|
}
|
|
|
|
|
2015-02-21 12:24:07 +00:00
|
|
|
// [] only works for objects
|
2015-01-31 19:13:11 +00:00
|
|
|
if (m_type != value_t::object)
|
|
|
|
{
|
2015-06-20 12:57:08 +00:00
|
|
|
throw std::domain_error("cannot use operator[] with " + type_name());
|
2015-01-31 19:13:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return m_value.object->operator[](key);
|
|
|
|
}
|
|
|
|
|
2015-02-15 14:16:11 +00:00
|
|
|
/// access specified element
|
2015-06-12 08:08:57 +00:00
|
|
|
const_reference operator[](const typename object_t::key_type& key) const
|
2015-02-15 14:16:11 +00:00
|
|
|
{
|
|
|
|
// at only works for objects
|
|
|
|
if (m_type != value_t::object)
|
|
|
|
{
|
2015-06-20 12:57:08 +00:00
|
|
|
throw std::domain_error("cannot use operator[] with " + type_name());
|
2015-02-15 14:16:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return m_value.object->operator[](key);
|
|
|
|
}
|
|
|
|
|
2015-01-31 19:13:11 +00:00
|
|
|
/// access specified element (needed for clang)
|
2015-04-11 17:26:12 +00:00
|
|
|
template<typename T, std::size_t n>
|
2015-06-12 08:08:57 +00:00
|
|
|
reference operator[](const T (&key)[n])
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
2015-02-18 21:28:56 +00:00
|
|
|
// implicitly convert null to object
|
|
|
|
if (m_type == value_t::null)
|
|
|
|
{
|
|
|
|
m_type = value_t::object;
|
2015-05-10 15:30:41 +00:00
|
|
|
m_value = value_t::object;
|
2015-02-18 21:28:56 +00:00
|
|
|
}
|
|
|
|
|
2015-01-31 19:13:11 +00:00
|
|
|
// at only works for objects
|
|
|
|
if (m_type != value_t::object)
|
|
|
|
{
|
2015-06-20 12:57:08 +00:00
|
|
|
throw std::domain_error("cannot use operator[] with " + type_name());
|
2015-01-31 19:13:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return m_value.object->operator[](key);
|
|
|
|
}
|
|
|
|
|
2015-02-15 14:16:11 +00:00
|
|
|
/// access specified element (needed for clang)
|
2015-04-11 17:26:12 +00:00
|
|
|
template<typename T, std::size_t n>
|
2015-06-12 08:08:57 +00:00
|
|
|
const_reference operator[](const T (&key)[n]) const
|
2015-02-15 14:16:11 +00:00
|
|
|
{
|
|
|
|
// at only works for objects
|
|
|
|
if (m_type != value_t::object)
|
|
|
|
{
|
2015-06-20 12:57:08 +00:00
|
|
|
throw std::domain_error("cannot use operator[] with " + type_name());
|
2015-02-15 14:16:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return m_value.object->operator[](key);
|
|
|
|
}
|
|
|
|
|
2015-06-21 00:14:01 +00:00
|
|
|
/*!
|
|
|
|
@brief access the first element
|
|
|
|
|
|
|
|
Returns a reference to the first element in the container. For a JSON
|
|
|
|
container `c`, the expression `c.front()` is equivalent to `*c.begin()`.
|
|
|
|
|
|
|
|
@return In case of a compound value (array or object), a reference to the
|
|
|
|
first element is returned. In cast of number, string, or boolean values, a
|
|
|
|
reference to the value is returned.
|
|
|
|
|
|
|
|
@complexity Constant.
|
|
|
|
|
|
|
|
@note Calling `front` on an empty container is undefined.
|
|
|
|
|
|
|
|
@throw std::out_of_range when called on null value.
|
|
|
|
|
|
|
|
@liveexample{The following code shows an example for @ref front.,front}
|
|
|
|
*/
|
2015-06-12 08:08:57 +00:00
|
|
|
reference front()
|
2015-04-12 12:14:00 +00:00
|
|
|
{
|
|
|
|
return *begin();
|
|
|
|
}
|
|
|
|
|
2015-06-21 00:14:01 +00:00
|
|
|
/*!
|
|
|
|
@copydoc basic_json::front()
|
|
|
|
*/
|
2015-06-12 08:08:57 +00:00
|
|
|
const_reference front() const
|
2015-04-12 12:14:00 +00:00
|
|
|
{
|
|
|
|
return *cbegin();
|
|
|
|
}
|
|
|
|
|
2015-06-21 00:14:01 +00:00
|
|
|
/*!
|
|
|
|
@brief access the last element
|
|
|
|
|
|
|
|
Returns a reference to the last element in the container. For a JSON
|
|
|
|
container `c`, the expression `c.back()` is equivalent to `{ auto tmp =
|
|
|
|
c.end(); --tmp; return *tmp; }`.
|
|
|
|
|
|
|
|
@return In case of a compound value (array or object), a reference to the
|
|
|
|
last element is returned. In cast of number, string, or boolean values, a
|
|
|
|
reference to the value is returned.
|
|
|
|
|
|
|
|
@complexity Constant.
|
|
|
|
|
|
|
|
@note Calling `back` on an empty container is undefined.
|
|
|
|
|
|
|
|
@throw std::out_of_range when called on null value.
|
|
|
|
|
|
|
|
@liveexample{The following code shows an example for @ref back.,back}
|
|
|
|
*/
|
2015-06-12 08:08:57 +00:00
|
|
|
reference back()
|
2015-04-12 12:14:00 +00:00
|
|
|
{
|
|
|
|
auto tmp = end();
|
|
|
|
--tmp;
|
|
|
|
return *tmp;
|
|
|
|
}
|
|
|
|
|
2015-06-21 00:14:01 +00:00
|
|
|
/*!
|
|
|
|
@copydoc basic_json::back()
|
|
|
|
*/
|
2015-06-12 08:08:57 +00:00
|
|
|
const_reference back() const
|
2015-04-12 12:14:00 +00:00
|
|
|
{
|
|
|
|
auto tmp = cend();
|
|
|
|
--tmp;
|
|
|
|
return *tmp;
|
|
|
|
}
|
|
|
|
|
2015-04-11 13:30:19 +00:00
|
|
|
/// remove element given an iterator
|
|
|
|
template <class T, typename
|
|
|
|
std::enable_if<
|
2015-06-21 11:04:03 +00:00
|
|
|
std::is_same<T, typename __basic_json::iterator>::value or
|
|
|
|
std::is_same<T, typename __basic_json::const_iterator>::value
|
2015-04-11 13:30:19 +00:00
|
|
|
, int>::type
|
|
|
|
= 0>
|
2015-06-12 08:08:57 +00:00
|
|
|
T erase(T pos)
|
2015-04-11 13:30:19 +00:00
|
|
|
{
|
|
|
|
// make sure iterator fits the current value
|
|
|
|
if (this != pos.m_object or m_type != pos.m_object->m_type)
|
|
|
|
{
|
2015-06-14 17:35:20 +00:00
|
|
|
throw std::domain_error("iterator does not fit current value");
|
2015-04-11 13:30:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
T result = end();
|
|
|
|
|
|
|
|
switch (m_type)
|
|
|
|
{
|
|
|
|
case value_t::number_integer:
|
|
|
|
case value_t::number_float:
|
|
|
|
case value_t::boolean:
|
|
|
|
case value_t::string:
|
|
|
|
{
|
|
|
|
if (pos.m_it.generic_iterator != 0)
|
|
|
|
{
|
|
|
|
throw std::out_of_range("iterator out of range");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_type == value_t::string)
|
|
|
|
{
|
|
|
|
delete m_value.string;
|
|
|
|
m_value.string = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_type = value_t::null;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case value_t::object:
|
|
|
|
{
|
|
|
|
result.m_it.object_iterator = m_value.object->erase(pos.m_it.object_iterator);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case value_t::array:
|
|
|
|
{
|
|
|
|
result.m_it.array_iterator = m_value.array->erase(pos.m_it.array_iterator);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
{
|
2015-06-20 12:57:08 +00:00
|
|
|
throw std::domain_error("cannot use erase() with " + type_name());
|
2015-04-11 13:30:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// remove elements given an iterator range
|
|
|
|
template <class T, typename
|
|
|
|
std::enable_if<
|
2015-04-27 21:09:51 +00:00
|
|
|
std::is_same<T, typename basic_json::iterator>::value or
|
|
|
|
std::is_same<T, typename basic_json::const_iterator>::value
|
2015-04-11 13:30:19 +00:00
|
|
|
, int>::type
|
|
|
|
= 0>
|
2015-06-12 08:08:57 +00:00
|
|
|
T erase(T first, T last)
|
2015-04-11 13:30:19 +00:00
|
|
|
{
|
|
|
|
// make sure iterator fits the current value
|
|
|
|
if (this != first.m_object or this != last.m_object or
|
|
|
|
m_type != first.m_object->m_type or m_type != last.m_object->m_type)
|
|
|
|
{
|
2015-06-14 17:35:20 +00:00
|
|
|
throw std::domain_error("iterators do not fit current value");
|
2015-04-11 13:30:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
T result = end();
|
|
|
|
|
|
|
|
switch (m_type)
|
|
|
|
{
|
|
|
|
case value_t::number_integer:
|
|
|
|
case value_t::number_float:
|
|
|
|
case value_t::boolean:
|
|
|
|
case value_t::string:
|
|
|
|
{
|
|
|
|
if (first.m_it.generic_iterator != 0 or last.m_it.generic_iterator != 1)
|
|
|
|
{
|
|
|
|
throw std::out_of_range("iterators out of range");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_type == value_t::string)
|
|
|
|
{
|
|
|
|
delete m_value.string;
|
|
|
|
m_value.string = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_type = value_t::null;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case value_t::object:
|
|
|
|
{
|
|
|
|
result.m_it.object_iterator = m_value.object->erase(first.m_it.object_iterator,
|
|
|
|
last.m_it.object_iterator);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case value_t::array:
|
|
|
|
{
|
|
|
|
result.m_it.array_iterator = m_value.array->erase(first.m_it.array_iterator,
|
|
|
|
last.m_it.array_iterator);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
{
|
2015-06-14 17:35:20 +00:00
|
|
|
throw std::domain_error("cannot use erase with " + type_name());
|
2015-04-11 13:30:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2015-03-24 15:50:55 +00:00
|
|
|
/// remove element from an object given a key
|
2015-06-12 08:08:57 +00:00
|
|
|
size_type erase(const typename object_t::key_type& key)
|
2015-03-24 15:50:55 +00:00
|
|
|
{
|
2015-04-09 16:55:57 +00:00
|
|
|
// this erase only works for objects
|
2015-03-24 15:50:55 +00:00
|
|
|
if (m_type != value_t::object)
|
|
|
|
{
|
2015-06-20 12:57:08 +00:00
|
|
|
throw std::domain_error("cannot use erase() with " + type_name());
|
2015-03-24 15:50:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return m_value.object->erase(key);
|
|
|
|
}
|
|
|
|
|
2015-04-09 16:55:57 +00:00
|
|
|
/// remove element from an array given an index
|
2015-06-12 08:08:57 +00:00
|
|
|
void erase(const size_type idx)
|
2015-04-09 16:55:57 +00:00
|
|
|
{
|
|
|
|
// this erase only works for arrays
|
|
|
|
if (m_type != value_t::array)
|
|
|
|
{
|
2015-06-20 12:57:08 +00:00
|
|
|
throw std::domain_error("cannot use erase() with " + type_name());
|
2015-04-09 16:55:57 +00:00
|
|
|
}
|
|
|
|
|
2015-04-11 17:26:12 +00:00
|
|
|
if (idx >= size())
|
2015-04-09 16:55:57 +00:00
|
|
|
{
|
|
|
|
throw std::out_of_range("index out of range");
|
|
|
|
}
|
|
|
|
|
2015-04-11 17:26:12 +00:00
|
|
|
m_value.array->erase(m_value.array->begin() + static_cast<difference_type>(idx));
|
2015-04-09 16:55:57 +00:00
|
|
|
}
|
|
|
|
|
2015-02-07 14:57:47 +00:00
|
|
|
/// find an element in an object
|
2015-06-12 08:08:57 +00:00
|
|
|
iterator find(typename object_t::key_type key)
|
2015-02-07 14:57:47 +00:00
|
|
|
{
|
|
|
|
auto result = end();
|
|
|
|
|
|
|
|
if (m_type == value_t::object)
|
|
|
|
{
|
|
|
|
result.m_it.object_iterator = m_value.object->find(key);
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// find an element in an object
|
2015-06-12 08:08:57 +00:00
|
|
|
const_iterator find(typename object_t::key_type key) const
|
2015-02-07 14:57:47 +00:00
|
|
|
{
|
|
|
|
auto result = cend();
|
|
|
|
|
|
|
|
if (m_type == value_t::object)
|
|
|
|
{
|
|
|
|
result.m_it.object_iterator = m_value.object->find(key);
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2015-03-22 18:07:43 +00:00
|
|
|
/// returns the number of occurrences of a key in an object
|
2015-06-12 08:08:57 +00:00
|
|
|
size_type count(typename object_t::key_type key) const
|
2015-03-22 18:07:43 +00:00
|
|
|
{
|
|
|
|
// return 0 for all nonobject types
|
|
|
|
return (m_type == value_t::object) ? m_value.object->count(key) : 0;
|
|
|
|
}
|
|
|
|
|
2015-06-20 22:59:33 +00:00
|
|
|
/// @}
|
|
|
|
|
2015-02-07 14:57:47 +00:00
|
|
|
|
2015-01-31 19:13:11 +00:00
|
|
|
///////////////
|
|
|
|
// iterators //
|
|
|
|
///////////////
|
|
|
|
|
2015-06-20 22:59:33 +00:00
|
|
|
/// @name iterators
|
|
|
|
/// @{
|
|
|
|
|
2015-02-22 16:52:27 +00:00
|
|
|
/*!
|
|
|
|
@brief returns an iterator to the first element
|
2015-06-20 22:59:33 +00:00
|
|
|
|
|
|
|
Returns an iterator to the first element.
|
|
|
|
|
|
|
|
@image html range-begin-end.svg "Illustration from cppreference.com"
|
|
|
|
|
|
|
|
@return iterator to the first element
|
|
|
|
|
|
|
|
@complexity Constant.
|
|
|
|
|
|
|
|
@requirement This function satisfies the Container requirements:
|
|
|
|
- The complexity is constant.
|
|
|
|
|
|
|
|
@liveexample{The following code shows an example for @ref begin.,begin}
|
|
|
|
|
2015-02-22 16:52:27 +00:00
|
|
|
@ingroup container
|
|
|
|
*/
|
2015-06-12 08:08:57 +00:00
|
|
|
iterator begin() noexcept
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
|
|
|
iterator result(this);
|
|
|
|
result.set_begin();
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2015-02-22 16:52:27 +00:00
|
|
|
/*!
|
2015-06-20 22:59:33 +00:00
|
|
|
@copydoc basic_json::cbegin()
|
2015-02-22 16:52:27 +00:00
|
|
|
@ingroup container
|
|
|
|
*/
|
2015-06-12 08:08:57 +00:00
|
|
|
const_iterator begin() const noexcept
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
2015-04-12 15:26:54 +00:00
|
|
|
return cbegin();
|
2015-01-31 19:13:11 +00:00
|
|
|
}
|
|
|
|
|
2015-02-22 16:52:27 +00:00
|
|
|
/*!
|
|
|
|
@brief returns a const iterator to the first element
|
2015-06-20 22:59:33 +00:00
|
|
|
|
|
|
|
Returns a const iterator to the first element.
|
|
|
|
|
|
|
|
@image html range-begin-end.svg "Illustration from cppreference.com"
|
|
|
|
|
|
|
|
@return const iterator to the first element
|
|
|
|
|
|
|
|
@complexity Constant.
|
|
|
|
|
|
|
|
@requirement This function satisfies the Container requirements:
|
|
|
|
- The complexity is constant.
|
|
|
|
- Has the semantics of `const_cast<const basic_json&>(*this).begin()`.
|
|
|
|
|
|
|
|
@liveexample{The following code shows an example for @ref cbegin.,cbegin}
|
|
|
|
|
2015-02-22 16:52:27 +00:00
|
|
|
@ingroup container
|
|
|
|
*/
|
2015-06-12 08:08:57 +00:00
|
|
|
const_iterator cbegin() const noexcept
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
|
|
|
const_iterator result(this);
|
|
|
|
result.set_begin();
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2015-02-22 16:52:27 +00:00
|
|
|
/*!
|
|
|
|
@brief returns an iterator to one past the last element
|
2015-06-20 22:59:33 +00:00
|
|
|
|
|
|
|
Returns an iterator to one past the last element.
|
|
|
|
|
|
|
|
@image html range-begin-end.svg "Illustration from cppreference.com"
|
|
|
|
|
|
|
|
@return iterator one past the last element
|
|
|
|
|
|
|
|
@complexity Constant.
|
|
|
|
|
|
|
|
@requirement This function satisfies the Container requirements:
|
|
|
|
- The complexity is constant.
|
|
|
|
|
|
|
|
@liveexample{The following code shows an example for @ref end.,end}
|
|
|
|
|
2015-02-22 16:52:27 +00:00
|
|
|
@ingroup container
|
|
|
|
*/
|
2015-06-12 08:08:57 +00:00
|
|
|
iterator end() noexcept
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
|
|
|
iterator result(this);
|
|
|
|
result.set_end();
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2015-02-22 16:52:27 +00:00
|
|
|
/*!
|
2015-06-20 22:59:33 +00:00
|
|
|
@copydoc basic_json::cend()
|
2015-02-22 16:52:27 +00:00
|
|
|
@ingroup container
|
|
|
|
*/
|
2015-06-12 08:08:57 +00:00
|
|
|
const_iterator end() const noexcept
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
2015-04-12 15:26:54 +00:00
|
|
|
return cend();
|
2015-01-31 19:13:11 +00:00
|
|
|
}
|
|
|
|
|
2015-02-22 16:52:27 +00:00
|
|
|
/*!
|
|
|
|
@brief returns a const iterator to one past the last element
|
2015-06-20 22:59:33 +00:00
|
|
|
|
|
|
|
Returns a const iterator to one past the last element.
|
|
|
|
|
|
|
|
@image html range-begin-end.svg "Illustration from cppreference.com"
|
|
|
|
|
|
|
|
@return const iterator one past the last element
|
|
|
|
|
|
|
|
@complexity Constant.
|
|
|
|
|
|
|
|
@requirement This function satisfies the Container requirements:
|
|
|
|
- The complexity is constant.
|
|
|
|
- Has the semantics of `const_cast<const basic_json&>(*this).end()`.
|
|
|
|
|
|
|
|
@liveexample{The following code shows an example for @ref cend.,cend}
|
|
|
|
|
2015-02-22 16:52:27 +00:00
|
|
|
@ingroup container
|
|
|
|
*/
|
2015-06-12 08:08:57 +00:00
|
|
|
const_iterator cend() const noexcept
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
|
|
|
const_iterator result(this);
|
|
|
|
result.set_end();
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2015-02-22 16:52:27 +00:00
|
|
|
/*!
|
2015-06-20 22:59:33 +00:00
|
|
|
@brief returns an iterator to the reverse-beginning
|
|
|
|
|
|
|
|
Returns an iterator to the reverse-beginning; that is, the last element.
|
|
|
|
|
|
|
|
@image html range-rbegin-rend.svg "Illustration from cppreference.com"
|
|
|
|
|
|
|
|
@complexity Constant.
|
|
|
|
|
|
|
|
@requirement This function satisfies the ReversibleContainer requirements:
|
|
|
|
- The complexity is constant.
|
|
|
|
- Has the semantics of `reverse_iterator(end())`.
|
|
|
|
|
|
|
|
@liveexample{The following code shows an example for @ref rbegin.,rbegin}
|
|
|
|
|
2015-02-22 16:52:27 +00:00
|
|
|
@ingroup reversiblecontainer
|
|
|
|
*/
|
2015-06-12 08:08:57 +00:00
|
|
|
reverse_iterator rbegin() noexcept
|
2015-02-14 15:47:14 +00:00
|
|
|
{
|
|
|
|
return reverse_iterator(end());
|
|
|
|
}
|
|
|
|
|
2015-02-22 16:52:27 +00:00
|
|
|
/*!
|
2015-06-20 22:59:33 +00:00
|
|
|
@copydoc basic_json::crbegin()
|
2015-02-22 16:52:27 +00:00
|
|
|
@ingroup reversiblecontainer
|
|
|
|
*/
|
2015-06-12 08:08:57 +00:00
|
|
|
const_reverse_iterator rbegin() const noexcept
|
2015-02-15 13:52:00 +00:00
|
|
|
{
|
2015-04-12 15:26:54 +00:00
|
|
|
return crbegin();
|
2015-02-15 13:52:00 +00:00
|
|
|
}
|
|
|
|
|
2015-02-22 16:52:27 +00:00
|
|
|
/*!
|
2015-06-20 22:59:33 +00:00
|
|
|
@brief returns an iterator to the reverse-end
|
|
|
|
|
|
|
|
Returns an iterator to the reverse-end; that is, one before the first
|
|
|
|
element.
|
|
|
|
|
|
|
|
@image html range-rbegin-rend.svg "Illustration from cppreference.com"
|
|
|
|
|
|
|
|
@complexity Constant.
|
|
|
|
|
|
|
|
@requirement This function satisfies the ReversibleContainer requirements:
|
|
|
|
- The complexity is constant.
|
|
|
|
- Has the semantics of `reverse_iterator(begin())`.
|
|
|
|
|
|
|
|
@liveexample{The following code shows an example for @ref rend.,rend}
|
|
|
|
|
2015-02-22 16:52:27 +00:00
|
|
|
@ingroup reversiblecontainer
|
|
|
|
*/
|
2015-06-12 08:08:57 +00:00
|
|
|
reverse_iterator rend() noexcept
|
2015-02-14 15:47:14 +00:00
|
|
|
{
|
|
|
|
return reverse_iterator(begin());
|
|
|
|
}
|
|
|
|
|
2015-02-22 16:52:27 +00:00
|
|
|
/*!
|
2015-06-20 22:59:33 +00:00
|
|
|
@copydoc basic_json::crend()
|
2015-02-22 16:52:27 +00:00
|
|
|
@ingroup reversiblecontainer
|
|
|
|
*/
|
2015-06-12 08:08:57 +00:00
|
|
|
const_reverse_iterator rend() const noexcept
|
2015-02-15 13:52:00 +00:00
|
|
|
{
|
2015-04-12 15:26:54 +00:00
|
|
|
return crend();
|
2015-02-15 13:52:00 +00:00
|
|
|
}
|
|
|
|
|
2015-02-22 16:52:27 +00:00
|
|
|
/*!
|
2015-06-20 22:59:33 +00:00
|
|
|
@brief returns a const reverse iterator to the last element
|
|
|
|
|
|
|
|
Returns a const iterator to the reverse-beginning; that is, the last
|
|
|
|
element.
|
|
|
|
|
|
|
|
@image html range-rbegin-rend.svg "Illustration from cppreference.com"
|
|
|
|
|
|
|
|
@complexity Constant.
|
|
|
|
|
|
|
|
@requirement This function satisfies the ReversibleContainer requirements:
|
|
|
|
- The complexity is constant.
|
|
|
|
- Has the semantics of `const_cast<const basic_json&>(*this).rbegin()`.
|
|
|
|
|
|
|
|
@liveexample{The following code shows an example for @ref crbegin.,crbegin}
|
|
|
|
|
2015-02-22 16:52:27 +00:00
|
|
|
@ingroup reversiblecontainer
|
|
|
|
*/
|
2015-06-12 08:08:57 +00:00
|
|
|
const_reverse_iterator crbegin() const noexcept
|
2015-02-14 15:47:14 +00:00
|
|
|
{
|
|
|
|
return const_reverse_iterator(cend());
|
|
|
|
}
|
|
|
|
|
2015-02-22 16:52:27 +00:00
|
|
|
/*!
|
2015-06-20 22:59:33 +00:00
|
|
|
@brief returns a const reverse iterator to one before the first
|
|
|
|
|
|
|
|
Returns a const reverse iterator to the reverse-end; that is, one before
|
|
|
|
the first element.
|
|
|
|
|
|
|
|
@image html range-rbegin-rend.svg "Illustration from cppreference.com"
|
|
|
|
|
|
|
|
@complexity Constant.
|
|
|
|
|
|
|
|
@requirement This function satisfies the ReversibleContainer requirements:
|
|
|
|
- The complexity is constant.
|
|
|
|
- Has the semantics of `const_cast<const basic_json&>(*this).rend()`.
|
|
|
|
|
|
|
|
@liveexample{The following code shows an example for @ref crend.,crend}
|
|
|
|
|
2015-02-22 16:52:27 +00:00
|
|
|
@ingroup reversiblecontainer
|
|
|
|
*/
|
2015-06-12 08:08:57 +00:00
|
|
|
const_reverse_iterator crend() const noexcept
|
2015-02-14 15:47:14 +00:00
|
|
|
{
|
|
|
|
return const_reverse_iterator(cbegin());
|
|
|
|
}
|
|
|
|
|
2015-06-20 22:59:33 +00:00
|
|
|
/// @}
|
|
|
|
|
2015-01-31 19:13:11 +00:00
|
|
|
|
|
|
|
//////////////
|
|
|
|
// capacity //
|
|
|
|
//////////////
|
|
|
|
|
2015-06-20 22:59:33 +00:00
|
|
|
/// @name capacity
|
|
|
|
/// @{
|
|
|
|
|
2015-02-22 16:52:27 +00:00
|
|
|
/*!
|
|
|
|
@brief checks whether the container is empty
|
2015-06-20 22:59:33 +00:00
|
|
|
|
|
|
|
Checks if a JSON value has no elements.
|
|
|
|
|
|
|
|
@return The return value depends on the different value types and is
|
|
|
|
defined as follows:
|
|
|
|
Value type | return value
|
|
|
|
----------- | -------------
|
|
|
|
null | @c true
|
|
|
|
boolean | @c false
|
|
|
|
string | @c false
|
|
|
|
number | @c false
|
|
|
|
object | result of function object_t::empty()
|
|
|
|
array | result of function array_t::empty()
|
|
|
|
|
|
|
|
@complexity Constant, as long as @ref array_t and @ref object_t satisfy the
|
|
|
|
Container concept; that is, their empty() functions have
|
|
|
|
constant complexity.
|
|
|
|
|
|
|
|
@requirement This function satisfies the Container requirements:
|
|
|
|
- The complexity is constant.
|
|
|
|
- Has the semantics of `begin() == end()`.
|
|
|
|
|
|
|
|
@liveexample{The following code uses @ref empty to check if a @ref json
|
|
|
|
object contains any elements.,empty}
|
|
|
|
|
2015-02-22 16:52:27 +00:00
|
|
|
@ingroup container
|
|
|
|
*/
|
2015-06-12 08:08:57 +00:00
|
|
|
bool empty() const noexcept
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
|
|
|
switch (m_type)
|
|
|
|
{
|
|
|
|
case (value_t::null):
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
2015-02-07 14:57:47 +00:00
|
|
|
|
2015-01-31 19:13:11 +00:00
|
|
|
case (value_t::array):
|
|
|
|
{
|
|
|
|
return m_value.array->empty();
|
|
|
|
}
|
2015-02-07 14:57:47 +00:00
|
|
|
|
2015-01-31 19:13:11 +00:00
|
|
|
case (value_t::object):
|
|
|
|
{
|
|
|
|
return m_value.object->empty();
|
|
|
|
}
|
2015-02-07 14:57:47 +00:00
|
|
|
|
2015-02-08 11:53:10 +00:00
|
|
|
default:
|
|
|
|
{
|
|
|
|
// all other types are nonempty
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2015-01-31 19:13:11 +00:00
|
|
|
}
|
|
|
|
|
2015-02-22 16:52:27 +00:00
|
|
|
/*!
|
|
|
|
@brief returns the number of elements
|
2015-06-20 22:59:33 +00:00
|
|
|
|
|
|
|
Returns the number of elements in a JSON value.
|
|
|
|
|
|
|
|
@return The return value depends on the different value types and is
|
|
|
|
defined as follows:
|
|
|
|
Value type | return value
|
|
|
|
----------- | -------------
|
|
|
|
null | @c 0
|
|
|
|
boolean | @c 1
|
|
|
|
string | @c 1
|
|
|
|
number | @c 1
|
|
|
|
object | result of function object_t::size()
|
|
|
|
array | result of function array_t::size()
|
|
|
|
|
|
|
|
@complexity Constant, as long as @ref array_t and @ref object_t satisfy the
|
|
|
|
Container concept; that is, their size() functions have
|
|
|
|
constant complexity.
|
|
|
|
|
|
|
|
@requirement This function satisfies the Container requirements:
|
|
|
|
- The complexity is constant.
|
|
|
|
- Has the semantics of `std::distance(begin(), end())`.
|
|
|
|
|
|
|
|
@liveexample{The following code calls @ref size on the different value
|
|
|
|
types.,size}
|
|
|
|
|
2015-02-22 16:52:27 +00:00
|
|
|
@ingroup container
|
|
|
|
*/
|
2015-06-12 08:08:57 +00:00
|
|
|
size_type size() const noexcept
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
|
|
|
switch (m_type)
|
|
|
|
{
|
|
|
|
case (value_t::null):
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
2015-02-07 14:57:47 +00:00
|
|
|
|
2015-01-31 19:13:11 +00:00
|
|
|
case (value_t::array):
|
|
|
|
{
|
|
|
|
return m_value.array->size();
|
|
|
|
}
|
2015-02-07 14:57:47 +00:00
|
|
|
|
2015-01-31 19:13:11 +00:00
|
|
|
case (value_t::object):
|
|
|
|
{
|
|
|
|
return m_value.object->size();
|
|
|
|
}
|
2015-02-07 14:57:47 +00:00
|
|
|
|
2015-02-08 11:53:10 +00:00
|
|
|
default:
|
|
|
|
{
|
|
|
|
// all other types have size 1
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
2015-01-31 19:13:11 +00:00
|
|
|
}
|
|
|
|
|
2015-02-22 16:52:27 +00:00
|
|
|
/*!
|
|
|
|
@brief returns the maximum possible number of elements
|
2015-06-21 07:44:12 +00:00
|
|
|
|
|
|
|
Returns the maximum number of elements a JSON value is able to hold due to
|
|
|
|
system or library implementation limitations, i.e. `std::distance(begin(),
|
|
|
|
end())` for the JSON value.
|
|
|
|
|
|
|
|
@return The return value depends on the different value types and is
|
|
|
|
defined as follows:
|
|
|
|
Value type | return value
|
|
|
|
----------- | -------------
|
|
|
|
null | @c 0
|
|
|
|
boolean | @c 1
|
|
|
|
string | @c 1
|
|
|
|
number | @c 1
|
|
|
|
object | result of function object_t::max_size()
|
|
|
|
array | result of function array_t::max_size()
|
|
|
|
|
|
|
|
@complexity Constant, as long as @ref array_t and @ref object_t satisfy the
|
|
|
|
Container concept; that is, their max_size() functions have
|
|
|
|
constant complexity.
|
|
|
|
|
|
|
|
@requirement This function satisfies the Container requirements:
|
|
|
|
- The complexity is constant.
|
|
|
|
- Has the semantics of returning `b.size()` where `b` is the largest
|
|
|
|
possible JSON value.
|
|
|
|
|
|
|
|
@liveexample{The following code calls @ref max_size on the different value
|
|
|
|
types. Note the output is implementation specific.,max_size}
|
|
|
|
|
2015-02-22 16:52:27 +00:00
|
|
|
@ingroup container
|
|
|
|
*/
|
2015-06-12 08:08:57 +00:00
|
|
|
size_type max_size() const noexcept
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
|
|
|
switch (m_type)
|
|
|
|
{
|
|
|
|
case (value_t::null):
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
2015-02-07 14:57:47 +00:00
|
|
|
|
2015-01-31 19:13:11 +00:00
|
|
|
case (value_t::array):
|
|
|
|
{
|
|
|
|
return m_value.array->max_size();
|
|
|
|
}
|
2015-02-07 14:57:47 +00:00
|
|
|
|
2015-01-31 19:13:11 +00:00
|
|
|
case (value_t::object):
|
|
|
|
{
|
|
|
|
return m_value.object->max_size();
|
|
|
|
}
|
2015-02-07 14:57:47 +00:00
|
|
|
|
2015-02-08 11:53:10 +00:00
|
|
|
default:
|
|
|
|
{
|
|
|
|
// all other types have max_size 1
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
2015-01-31 19:13:11 +00:00
|
|
|
}
|
|
|
|
|
2015-06-20 22:59:33 +00:00
|
|
|
/// @}
|
|
|
|
|
2015-01-31 19:13:11 +00:00
|
|
|
|
|
|
|
///////////////
|
|
|
|
// modifiers //
|
|
|
|
///////////////
|
|
|
|
|
2015-06-20 22:59:33 +00:00
|
|
|
/// @name modifiers
|
|
|
|
/// @{
|
|
|
|
|
2015-06-21 07:44:12 +00:00
|
|
|
/*!
|
|
|
|
@brief clears the contents
|
|
|
|
|
|
|
|
Clears the content of a JSON value and resets it to the default value as
|
|
|
|
if @ref basic_json(value_t) would have been called:
|
|
|
|
|
|
|
|
Value type | initial value
|
|
|
|
----------- | -------------
|
|
|
|
null | `null`
|
|
|
|
boolean | `false`
|
|
|
|
string | `""`
|
|
|
|
number | `0`
|
|
|
|
object | `{}`
|
|
|
|
array | `[]`
|
|
|
|
|
|
|
|
@note Floating-point numbers are set to `0.0` which will be serialized to
|
|
|
|
`0`. The vale type remains @ref number_float_t.
|
|
|
|
|
|
|
|
@complexity Linear in the size of the JSON value.
|
|
|
|
|
|
|
|
@liveexample{The example below shows the effect of @ref clear to different
|
|
|
|
JSON value types.,clear}
|
|
|
|
*/
|
2015-06-12 08:08:57 +00:00
|
|
|
void clear() noexcept
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
|
|
|
switch (m_type)
|
|
|
|
{
|
|
|
|
case (value_t::null):
|
2015-05-03 15:52:13 +00:00
|
|
|
case (value_t::discarded):
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
2015-02-07 18:14:23 +00:00
|
|
|
|
2015-01-31 19:13:11 +00:00
|
|
|
case (value_t::number_integer):
|
|
|
|
{
|
2015-02-07 14:57:47 +00:00
|
|
|
m_value.number_integer = 0;
|
2015-01-31 19:13:11 +00:00
|
|
|
break;
|
|
|
|
}
|
2015-02-07 18:14:23 +00:00
|
|
|
|
2015-01-31 19:13:11 +00:00
|
|
|
case (value_t::number_float):
|
|
|
|
{
|
2015-02-07 14:57:47 +00:00
|
|
|
m_value.number_float = 0.0;
|
2015-01-31 19:13:11 +00:00
|
|
|
break;
|
|
|
|
}
|
2015-02-07 18:14:23 +00:00
|
|
|
|
2015-01-31 19:13:11 +00:00
|
|
|
case (value_t::boolean):
|
|
|
|
{
|
2015-02-07 14:57:47 +00:00
|
|
|
m_value.boolean = false;
|
2015-01-31 19:13:11 +00:00
|
|
|
break;
|
|
|
|
}
|
2015-02-07 18:14:23 +00:00
|
|
|
|
2015-01-31 19:13:11 +00:00
|
|
|
case (value_t::string):
|
|
|
|
{
|
|
|
|
m_value.string->clear();
|
|
|
|
break;
|
|
|
|
}
|
2015-02-07 18:14:23 +00:00
|
|
|
|
2015-01-31 19:13:11 +00:00
|
|
|
case (value_t::array):
|
|
|
|
{
|
|
|
|
m_value.array->clear();
|
|
|
|
break;
|
|
|
|
}
|
2015-02-07 18:14:23 +00:00
|
|
|
|
2015-01-31 19:13:11 +00:00
|
|
|
case (value_t::object):
|
|
|
|
{
|
|
|
|
m_value.object->clear();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// add an object to an array
|
2015-06-12 08:08:57 +00:00
|
|
|
void push_back(basic_json&& value)
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
|
|
|
// push_back only works for null objects or arrays
|
|
|
|
if (not(m_type == value_t::null or m_type == value_t::array))
|
|
|
|
{
|
2015-06-20 12:57:08 +00:00
|
|
|
throw std::domain_error("cannot use push_back() with " + type_name());
|
2015-01-31 19:13:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// transform null object into an array
|
|
|
|
if (m_type == value_t::null)
|
|
|
|
{
|
|
|
|
m_type = value_t::array;
|
2015-05-10 15:03:50 +00:00
|
|
|
m_value = value_t::array;
|
2015-01-31 19:13:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// add element to array (move semantics)
|
|
|
|
m_value.array->push_back(std::move(value));
|
|
|
|
// invalidate object
|
|
|
|
value.m_type = value_t::null;
|
|
|
|
}
|
|
|
|
|
2015-02-09 20:10:19 +00:00
|
|
|
/// add an object to an array
|
2015-06-12 08:08:57 +00:00
|
|
|
reference operator+=(basic_json&& value)
|
2015-02-09 20:10:19 +00:00
|
|
|
{
|
|
|
|
push_back(std::move(value));
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2015-01-31 19:13:11 +00:00
|
|
|
/// add an object to an array
|
2015-06-12 08:08:57 +00:00
|
|
|
void push_back(const basic_json& value)
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
|
|
|
// push_back only works for null objects or arrays
|
|
|
|
if (not(m_type == value_t::null or m_type == value_t::array))
|
|
|
|
{
|
2015-06-20 12:57:08 +00:00
|
|
|
throw std::domain_error("cannot use push_back() with " + type_name());
|
2015-01-31 19:13:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// transform null object into an array
|
|
|
|
if (m_type == value_t::null)
|
|
|
|
{
|
|
|
|
m_type = value_t::array;
|
2015-05-10 15:03:50 +00:00
|
|
|
m_value = value_t::array;
|
2015-01-31 19:13:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// add element to array
|
|
|
|
m_value.array->push_back(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// add an object to an array
|
2015-06-12 08:08:57 +00:00
|
|
|
reference operator+=(const basic_json& value)
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
|
|
|
push_back(value);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// add an object to an object
|
2015-06-12 08:08:57 +00:00
|
|
|
void push_back(const typename object_t::value_type& value)
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
|
|
|
// push_back only works for null objects or objects
|
|
|
|
if (not(m_type == value_t::null or m_type == value_t::object))
|
|
|
|
{
|
2015-06-20 12:57:08 +00:00
|
|
|
throw std::domain_error("cannot use push_back() with " + type_name());
|
2015-01-31 19:13:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// transform null object into an object
|
|
|
|
if (m_type == value_t::null)
|
|
|
|
{
|
|
|
|
m_type = value_t::object;
|
2015-05-10 15:03:50 +00:00
|
|
|
m_value = value_t::object;
|
2015-01-31 19:13:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// add element to array
|
|
|
|
m_value.object->insert(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// add an object to an object
|
2015-06-12 08:08:57 +00:00
|
|
|
reference operator+=(const typename object_t::value_type& value)
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
|
|
|
push_back(value);
|
|
|
|
return operator[](value.first);
|
|
|
|
}
|
|
|
|
|
2015-02-22 16:52:27 +00:00
|
|
|
/*!
|
|
|
|
@brief exchanges the values
|
|
|
|
@ingroup container
|
|
|
|
*/
|
2015-06-12 08:08:57 +00:00
|
|
|
void swap(reference other) noexcept (
|
2015-02-13 20:46:33 +00:00
|
|
|
std::is_nothrow_move_constructible<value_t>::value and
|
|
|
|
std::is_nothrow_move_assignable<value_t>::value and
|
|
|
|
std::is_nothrow_move_constructible<json_value>::value and
|
|
|
|
std::is_nothrow_move_assignable<json_value>::value
|
|
|
|
)
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
|
|
|
std::swap(m_type, other.m_type);
|
|
|
|
std::swap(m_value, other.m_value);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// swaps the contents
|
2015-06-12 08:08:57 +00:00
|
|
|
void swap(array_t& other)
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
|
|
|
// swap only works for arrays
|
|
|
|
if (m_type != value_t::array)
|
|
|
|
{
|
2015-06-20 12:57:08 +00:00
|
|
|
throw std::domain_error("cannot use swap() with " + type_name());
|
2015-01-31 19:13:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// swap arrays
|
|
|
|
std::swap(*(m_value.array), other);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// swaps the contents
|
2015-06-12 08:08:57 +00:00
|
|
|
void swap(object_t& other)
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
|
|
|
// swap only works for objects
|
|
|
|
if (m_type != value_t::object)
|
|
|
|
{
|
2015-06-20 12:57:08 +00:00
|
|
|
throw std::domain_error("cannot use swap() with " + type_name());
|
2015-01-31 19:13:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// swap arrays
|
|
|
|
std::swap(*(m_value.object), other);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// swaps the contents
|
2015-06-12 08:08:57 +00:00
|
|
|
void swap(string_t& other)
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
|
|
|
// swap only works for strings
|
|
|
|
if (m_type != value_t::string)
|
|
|
|
{
|
2015-06-20 12:57:08 +00:00
|
|
|
throw std::domain_error("cannot use swap() with " + type_name());
|
2015-01-31 19:13:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// swap arrays
|
|
|
|
std::swap(*(m_value.string), other);
|
|
|
|
}
|
|
|
|
|
2015-06-20 22:59:33 +00:00
|
|
|
/// @}
|
|
|
|
|
2015-01-31 19:13:11 +00:00
|
|
|
|
|
|
|
//////////////////////////////////////////
|
|
|
|
// lexicographical comparison operators //
|
|
|
|
//////////////////////////////////////////
|
|
|
|
|
2015-06-20 22:59:33 +00:00
|
|
|
/// @name lexicographical comparison operators
|
|
|
|
/// @{
|
|
|
|
|
2015-02-22 16:52:27 +00:00
|
|
|
/*!
|
|
|
|
@brief comparison: equal
|
|
|
|
@ingroup container
|
|
|
|
*/
|
2015-02-24 22:19:19 +00:00
|
|
|
friend bool operator==(const_reference lhs, const_reference rhs) noexcept
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
2015-04-26 12:31:31 +00:00
|
|
|
const auto lhs_type = lhs.type();
|
|
|
|
const auto rhs_type = rhs.type();
|
2015-04-26 13:16:07 +00:00
|
|
|
|
2015-04-26 12:31:31 +00:00
|
|
|
if (lhs_type == rhs_type)
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
2015-04-26 12:31:31 +00:00
|
|
|
switch (lhs_type)
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
2015-04-26 12:31:31 +00:00
|
|
|
case (value_t::array):
|
2015-01-31 19:13:11 +00:00
|
|
|
return *lhs.m_value.array == *rhs.m_value.array;
|
2015-04-26 12:31:31 +00:00
|
|
|
case (value_t::object):
|
2015-01-31 19:13:11 +00:00
|
|
|
return *lhs.m_value.object == *rhs.m_value.object;
|
2015-04-26 12:31:31 +00:00
|
|
|
case (value_t::null):
|
2015-01-31 19:13:11 +00:00
|
|
|
return true;
|
2015-04-26 12:31:31 +00:00
|
|
|
case (value_t::string):
|
2015-01-31 19:13:11 +00:00
|
|
|
return *lhs.m_value.string == *rhs.m_value.string;
|
2015-04-26 12:31:31 +00:00
|
|
|
case (value_t::boolean):
|
2015-01-31 19:13:11 +00:00
|
|
|
return lhs.m_value.boolean == rhs.m_value.boolean;
|
2015-04-26 12:31:31 +00:00
|
|
|
case (value_t::number_integer):
|
2015-01-31 19:13:11 +00:00
|
|
|
return lhs.m_value.number_integer == rhs.m_value.number_integer;
|
2015-04-26 12:31:31 +00:00
|
|
|
case (value_t::number_float):
|
2015-03-23 22:03:48 +00:00
|
|
|
return approx(lhs.m_value.number_float, rhs.m_value.number_float);
|
2015-05-03 15:52:13 +00:00
|
|
|
case (value_t::discarded):
|
|
|
|
return false;
|
2015-01-31 19:13:11 +00:00
|
|
|
}
|
|
|
|
}
|
2015-04-26 12:31:31 +00:00
|
|
|
else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float)
|
|
|
|
{
|
2015-04-26 12:39:39 +00:00
|
|
|
return approx(static_cast<number_float_t>(lhs.m_value.number_integer),
|
|
|
|
rhs.m_value.number_float);
|
2015-04-26 12:31:31 +00:00
|
|
|
}
|
|
|
|
else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer)
|
|
|
|
{
|
|
|
|
return approx(lhs.m_value.number_float,
|
|
|
|
static_cast<number_float_t>(rhs.m_value.number_integer));
|
|
|
|
}
|
2015-01-31 19:13:11 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-02-22 16:52:27 +00:00
|
|
|
/*!
|
|
|
|
@brief comparison: not equal
|
|
|
|
@ingroup container
|
|
|
|
*/
|
2015-02-24 22:19:19 +00:00
|
|
|
friend bool operator!=(const_reference lhs, const_reference rhs) noexcept
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
|
|
|
return not (lhs == rhs);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// comparison: less than
|
2015-02-24 22:19:19 +00:00
|
|
|
friend bool operator<(const_reference lhs, const_reference rhs) noexcept
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
2015-04-26 12:19:56 +00:00
|
|
|
const auto lhs_type = lhs.type();
|
|
|
|
const auto rhs_type = rhs.type();
|
2015-04-26 13:16:07 +00:00
|
|
|
|
2015-04-26 12:19:56 +00:00
|
|
|
if (lhs_type == rhs_type)
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
2015-04-26 12:19:56 +00:00
|
|
|
switch (lhs_type)
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
2015-04-26 12:19:56 +00:00
|
|
|
case (value_t::array):
|
2015-01-31 19:13:11 +00:00
|
|
|
return *lhs.m_value.array < *rhs.m_value.array;
|
2015-04-26 12:31:31 +00:00
|
|
|
case (value_t::object):
|
2015-01-31 19:13:11 +00:00
|
|
|
return *lhs.m_value.object < *rhs.m_value.object;
|
2015-04-26 12:19:56 +00:00
|
|
|
case (value_t::null):
|
2015-01-31 19:13:11 +00:00
|
|
|
return false;
|
2015-04-26 12:19:56 +00:00
|
|
|
case (value_t::string):
|
2015-01-31 19:13:11 +00:00
|
|
|
return *lhs.m_value.string < *rhs.m_value.string;
|
2015-04-26 12:19:56 +00:00
|
|
|
case (value_t::boolean):
|
2015-01-31 19:13:11 +00:00
|
|
|
return lhs.m_value.boolean < rhs.m_value.boolean;
|
2015-04-26 12:19:56 +00:00
|
|
|
case (value_t::number_integer):
|
2015-01-31 19:13:11 +00:00
|
|
|
return lhs.m_value.number_integer < rhs.m_value.number_integer;
|
2015-04-26 12:19:56 +00:00
|
|
|
case (value_t::number_float):
|
2015-01-31 19:13:11 +00:00
|
|
|
return lhs.m_value.number_float < rhs.m_value.number_float;
|
2015-05-03 15:52:13 +00:00
|
|
|
case (value_t::discarded):
|
|
|
|
return false;
|
2015-01-31 19:13:11 +00:00
|
|
|
}
|
|
|
|
}
|
2015-04-26 12:19:56 +00:00
|
|
|
else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float)
|
|
|
|
{
|
2015-04-26 12:39:39 +00:00
|
|
|
return static_cast<number_float_t>(lhs.m_value.number_integer) <
|
|
|
|
rhs.m_value.number_float;
|
2015-04-26 12:19:56 +00:00
|
|
|
}
|
|
|
|
else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer)
|
|
|
|
{
|
|
|
|
return lhs.m_value.number_float <
|
|
|
|
static_cast<number_float_t>(rhs.m_value.number_integer);
|
|
|
|
}
|
2015-01-31 19:13:11 +00:00
|
|
|
|
2015-02-22 16:52:27 +00:00
|
|
|
// We only reach this line if we cannot compare values. In that case,
|
|
|
|
// we compare types.
|
2015-04-26 12:19:56 +00:00
|
|
|
return lhs_type < rhs_type;
|
2015-01-31 19:13:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// comparison: less than or equal
|
2015-02-24 22:19:19 +00:00
|
|
|
friend bool operator<=(const_reference lhs, const_reference rhs) noexcept
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
|
|
|
return not (rhs < lhs);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// comparison: greater than
|
2015-02-24 22:19:19 +00:00
|
|
|
friend bool operator>(const_reference lhs, const_reference rhs) noexcept
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
|
|
|
return not (lhs <= rhs);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// comparison: greater than or equal
|
2015-02-24 22:19:19 +00:00
|
|
|
friend bool operator>=(const_reference lhs, const_reference rhs) noexcept
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
|
|
|
return not (lhs < rhs);
|
|
|
|
}
|
|
|
|
|
2015-06-20 22:59:33 +00:00
|
|
|
/// @}
|
|
|
|
|
2015-01-31 19:13:11 +00:00
|
|
|
|
|
|
|
///////////////////
|
|
|
|
// serialization //
|
|
|
|
///////////////////
|
|
|
|
|
2015-06-20 22:59:33 +00:00
|
|
|
/// @name serialization
|
|
|
|
/// @{
|
|
|
|
|
2015-01-31 19:13:11 +00:00
|
|
|
/// serialize to stream
|
|
|
|
friend std::ostream& operator<<(std::ostream& o, const basic_json& j)
|
|
|
|
{
|
2015-02-10 18:50:26 +00:00
|
|
|
// read width member and use it as indentation parameter if nonzero
|
2015-06-14 17:35:20 +00:00
|
|
|
const bool pretty_print = (o.width() > 0);
|
|
|
|
const auto indentation = (pretty_print ? o.width() : 0);
|
2015-02-10 18:50:26 +00:00
|
|
|
|
2015-06-03 21:34:10 +00:00
|
|
|
// reset width to 0 for subsequent calls to this stream
|
|
|
|
o.width(0);
|
|
|
|
|
|
|
|
// do the actual serialization
|
2015-06-14 17:35:20 +00:00
|
|
|
j.dump(o, pretty_print, static_cast<unsigned int>(indentation));
|
2015-01-31 19:13:11 +00:00
|
|
|
return o;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// serialize to stream
|
|
|
|
friend std::ostream& operator>>(const basic_json& j, std::ostream& o)
|
|
|
|
{
|
2015-06-08 09:39:32 +00:00
|
|
|
return o << j;
|
2015-01-31 19:13:11 +00:00
|
|
|
}
|
|
|
|
|
2015-06-20 22:59:33 +00:00
|
|
|
/// @}
|
|
|
|
|
2015-01-31 19:13:11 +00:00
|
|
|
|
2015-02-05 21:45:21 +00:00
|
|
|
/////////////////////
|
|
|
|
// deserialization //
|
|
|
|
/////////////////////
|
|
|
|
|
2015-06-20 22:59:33 +00:00
|
|
|
/// @name deserialization
|
|
|
|
/// @{
|
|
|
|
|
2015-02-05 21:45:21 +00:00
|
|
|
/// deserialize from string
|
2015-05-10 14:09:20 +00:00
|
|
|
static basic_json parse(const string_t& s, parser_callback_t cb = nullptr)
|
2015-02-05 21:45:21 +00:00
|
|
|
{
|
2015-05-03 15:52:13 +00:00
|
|
|
return parser(s, cb).parse();
|
2015-02-05 21:45:21 +00:00
|
|
|
}
|
|
|
|
|
2015-03-01 11:21:47 +00:00
|
|
|
/// deserialize from stream
|
2015-05-10 14:09:20 +00:00
|
|
|
static basic_json parse(std::istream& i, parser_callback_t cb = nullptr)
|
2015-03-01 11:21:47 +00:00
|
|
|
{
|
2015-05-03 15:52:13 +00:00
|
|
|
return parser(i, cb).parse();
|
2015-02-05 21:45:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// deserialize from stream
|
|
|
|
friend std::istream& operator>>(std::istream& i, basic_json& j)
|
|
|
|
{
|
|
|
|
j = parser(i).parse();
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// deserialize from stream
|
|
|
|
friend std::istream& operator<<(basic_json& j, std::istream& i)
|
|
|
|
{
|
|
|
|
j = parser(i).parse();
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
2015-06-20 22:59:33 +00:00
|
|
|
/// @}
|
|
|
|
|
2015-02-05 21:45:21 +00:00
|
|
|
|
2015-01-31 19:13:11 +00:00
|
|
|
private:
|
|
|
|
///////////////////////////
|
|
|
|
// convenience functions //
|
|
|
|
///////////////////////////
|
|
|
|
|
|
|
|
/// return the type as string
|
2015-06-12 08:08:57 +00:00
|
|
|
string_t type_name() const noexcept
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
|
|
|
switch (m_type)
|
|
|
|
{
|
|
|
|
case (value_t::null):
|
|
|
|
{
|
|
|
|
return "null";
|
|
|
|
}
|
2015-02-10 17:51:09 +00:00
|
|
|
|
2015-01-31 19:13:11 +00:00
|
|
|
case (value_t::object):
|
|
|
|
{
|
|
|
|
return "object";
|
|
|
|
}
|
2015-02-10 17:51:09 +00:00
|
|
|
|
2015-01-31 19:13:11 +00:00
|
|
|
case (value_t::array):
|
|
|
|
{
|
|
|
|
return "array";
|
|
|
|
}
|
2015-02-10 17:51:09 +00:00
|
|
|
|
2015-01-31 19:13:11 +00:00
|
|
|
case (value_t::string):
|
|
|
|
{
|
|
|
|
return "string";
|
|
|
|
}
|
2015-02-10 17:51:09 +00:00
|
|
|
|
2015-01-31 19:13:11 +00:00
|
|
|
case (value_t::boolean):
|
|
|
|
{
|
|
|
|
return "boolean";
|
|
|
|
}
|
2015-02-10 17:51:09 +00:00
|
|
|
|
2015-05-03 15:52:13 +00:00
|
|
|
case (value_t::discarded):
|
|
|
|
{
|
|
|
|
return "discarded";
|
|
|
|
}
|
|
|
|
|
2015-02-10 17:51:09 +00:00
|
|
|
default:
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
|
|
|
return "number";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-04 21:49:46 +00:00
|
|
|
/*!
|
2015-02-05 21:45:21 +00:00
|
|
|
@brief escape a string
|
2015-02-07 14:57:47 +00:00
|
|
|
|
2015-02-05 21:45:21 +00:00
|
|
|
Escape a string by replacing certain special characters by a sequence of an
|
|
|
|
escape character (backslash) and another character and other control
|
|
|
|
characters by a sequence of "\u" followed by a four-digit hex
|
|
|
|
representation.
|
|
|
|
|
2015-06-03 21:34:10 +00:00
|
|
|
@param o the stream to write the escaped string to
|
2015-02-05 21:45:21 +00:00
|
|
|
@param s the string to escape
|
2015-02-04 21:49:46 +00:00
|
|
|
*/
|
2015-06-03 21:34:10 +00:00
|
|
|
static void escape_string(std::ostream& o, const string_t& s) noexcept
|
2015-02-04 21:49:46 +00:00
|
|
|
{
|
2015-02-05 21:45:21 +00:00
|
|
|
for (const auto c : s)
|
2015-02-04 21:49:46 +00:00
|
|
|
{
|
|
|
|
switch (c)
|
|
|
|
{
|
2015-02-05 21:45:21 +00:00
|
|
|
// quotation mark (0x22)
|
2015-02-04 21:49:46 +00:00
|
|
|
case '"':
|
|
|
|
{
|
2015-06-03 21:34:10 +00:00
|
|
|
o << "\\\"";
|
2015-02-04 21:49:46 +00:00
|
|
|
break;
|
|
|
|
}
|
2015-02-24 22:19:19 +00:00
|
|
|
|
2015-02-05 21:45:21 +00:00
|
|
|
// reverse solidus (0x5c)
|
2015-02-04 21:49:46 +00:00
|
|
|
case '\\':
|
|
|
|
{
|
2015-06-03 21:34:10 +00:00
|
|
|
o << "\\\\";
|
2015-02-04 21:49:46 +00:00
|
|
|
break;
|
|
|
|
}
|
2015-02-24 22:19:19 +00:00
|
|
|
|
2015-02-05 21:45:21 +00:00
|
|
|
// backspace (0x08)
|
2015-02-04 21:49:46 +00:00
|
|
|
case '\b':
|
|
|
|
{
|
2015-06-03 21:34:10 +00:00
|
|
|
o << "\\b";
|
2015-02-04 21:49:46 +00:00
|
|
|
break;
|
|
|
|
}
|
2015-02-24 22:19:19 +00:00
|
|
|
|
2015-02-05 21:45:21 +00:00
|
|
|
// formfeed (0x0c)
|
2015-02-04 21:49:46 +00:00
|
|
|
case '\f':
|
|
|
|
{
|
2015-06-03 21:34:10 +00:00
|
|
|
o << "\\f";
|
2015-02-04 21:49:46 +00:00
|
|
|
break;
|
|
|
|
}
|
2015-02-24 22:19:19 +00:00
|
|
|
|
2015-02-05 21:45:21 +00:00
|
|
|
// newline (0x0a)
|
2015-02-04 21:49:46 +00:00
|
|
|
case '\n':
|
|
|
|
{
|
2015-06-03 21:34:10 +00:00
|
|
|
o << "\\n";
|
2015-02-04 21:49:46 +00:00
|
|
|
break;
|
|
|
|
}
|
2015-02-24 22:19:19 +00:00
|
|
|
|
2015-02-05 21:45:21 +00:00
|
|
|
// carriage return (0x0d)
|
2015-02-04 21:49:46 +00:00
|
|
|
case '\r':
|
|
|
|
{
|
2015-06-03 21:34:10 +00:00
|
|
|
o << "\\r";
|
2015-02-04 21:49:46 +00:00
|
|
|
break;
|
|
|
|
}
|
2015-02-24 22:19:19 +00:00
|
|
|
|
2015-02-05 21:45:21 +00:00
|
|
|
// horizontal tab (0x09)
|
2015-02-04 21:49:46 +00:00
|
|
|
case '\t':
|
|
|
|
{
|
2015-06-03 21:34:10 +00:00
|
|
|
o << "\\t";
|
2015-02-04 21:49:46 +00:00
|
|
|
break;
|
|
|
|
}
|
2015-02-05 21:45:21 +00:00
|
|
|
|
2015-02-04 21:49:46 +00:00
|
|
|
default:
|
|
|
|
{
|
2015-02-15 17:43:17 +00:00
|
|
|
if (c >= 0 and c <= 0x1f)
|
2015-02-05 21:45:21 +00:00
|
|
|
{
|
|
|
|
// control characters (everything between 0x00 and 0x1f)
|
|
|
|
// -> create four-digit hex representation
|
2015-06-03 21:34:10 +00:00
|
|
|
o << "\\u" << std::hex << std::setw(4) << std::setfill('0') << int(c);
|
2015-02-05 21:45:21 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// all other characters are added as-is
|
2015-06-03 21:34:10 +00:00
|
|
|
o << c;
|
2015-02-05 21:45:21 +00:00
|
|
|
}
|
|
|
|
break;
|
2015-02-04 21:49:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-31 19:13:11 +00:00
|
|
|
/*!
|
2015-02-05 21:45:21 +00:00
|
|
|
@brief internal implementation of the serialization function
|
2015-02-07 14:57:47 +00:00
|
|
|
|
2015-02-05 21:45:21 +00:00
|
|
|
This function is called by the public member function dump and organizes
|
|
|
|
the serializaion internally. The indentation level is propagated as
|
|
|
|
additional parameter. In case of arrays and objects, the function is called
|
|
|
|
recursively. Note that
|
2015-02-07 14:57:47 +00:00
|
|
|
|
2015-02-05 21:45:21 +00:00
|
|
|
- strings and object keys are escaped using escape_string()
|
2015-06-04 06:31:13 +00:00
|
|
|
- integer numbers are converted implictly via operator<<
|
2015-03-23 19:27:30 +00:00
|
|
|
- floating-point numbers are converted to a string using "%g" format
|
2015-01-31 19:13:11 +00:00
|
|
|
|
2015-06-14 17:35:20 +00:00
|
|
|
@param o stream to write to
|
|
|
|
@param pretty_print whether the output shall be pretty-printed
|
|
|
|
@param indent_step the indent level
|
|
|
|
@param current_indent the current indent level (only used internally)
|
2015-01-31 19:13:11 +00:00
|
|
|
*/
|
2015-06-14 17:35:20 +00:00
|
|
|
void dump(std::ostream& o, const bool pretty_print, const unsigned int indent_step,
|
|
|
|
const unsigned int current_indent = 0) const noexcept
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
2015-02-13 20:46:33 +00:00
|
|
|
// variable to hold indentation for recursive calls
|
2015-06-14 17:35:20 +00:00
|
|
|
unsigned int new_indent = current_indent;
|
2015-02-13 20:46:33 +00:00
|
|
|
|
2015-01-31 19:13:11 +00:00
|
|
|
switch (m_type)
|
|
|
|
{
|
|
|
|
case (value_t::object):
|
|
|
|
{
|
|
|
|
if (m_value.object->empty())
|
|
|
|
{
|
2015-06-03 21:34:10 +00:00
|
|
|
o << "{}";
|
|
|
|
return;
|
2015-01-31 19:13:11 +00:00
|
|
|
}
|
|
|
|
|
2015-06-03 21:34:10 +00:00
|
|
|
o << "{";
|
2015-01-31 19:13:11 +00:00
|
|
|
|
|
|
|
// increase indentation
|
2015-06-14 17:35:20 +00:00
|
|
|
if (pretty_print)
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
2015-06-14 17:35:20 +00:00
|
|
|
new_indent += indent_step;
|
2015-06-03 21:34:10 +00:00
|
|
|
o << "\n";
|
2015-01-31 19:13:11 +00:00
|
|
|
}
|
|
|
|
|
2015-02-05 21:45:21 +00:00
|
|
|
for (auto i = m_value.object->cbegin(); i != m_value.object->cend(); ++i)
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
2015-02-05 21:45:21 +00:00
|
|
|
if (i != m_value.object->cbegin())
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
2015-06-14 17:35:20 +00:00
|
|
|
o << (pretty_print ? ",\n" : ",");
|
2015-01-31 19:13:11 +00:00
|
|
|
}
|
2015-06-03 21:34:10 +00:00
|
|
|
o << string_t(new_indent, ' ') << "\"";
|
|
|
|
escape_string(o, i->first);
|
2015-06-14 17:35:20 +00:00
|
|
|
o << "\":" << (pretty_print ? " " : "");
|
|
|
|
i->second.dump(o, pretty_print, indent_step, new_indent);
|
2015-01-31 19:13:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// decrease indentation
|
2015-06-14 17:35:20 +00:00
|
|
|
if (pretty_print)
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
2015-06-14 17:35:20 +00:00
|
|
|
new_indent -= indent_step;
|
2015-06-03 21:34:10 +00:00
|
|
|
o << "\n";
|
2015-01-31 19:13:11 +00:00
|
|
|
}
|
|
|
|
|
2015-06-03 21:34:10 +00:00
|
|
|
o << string_t(new_indent, ' ') + "}";
|
|
|
|
return;
|
2015-01-31 19:13:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
case (value_t::array):
|
|
|
|
{
|
|
|
|
if (m_value.array->empty())
|
|
|
|
{
|
2015-06-03 21:34:10 +00:00
|
|
|
o << "[]";
|
|
|
|
return;
|
2015-01-31 19:13:11 +00:00
|
|
|
}
|
|
|
|
|
2015-06-03 21:34:10 +00:00
|
|
|
o << "[";
|
2015-01-31 19:13:11 +00:00
|
|
|
|
|
|
|
// increase indentation
|
2015-06-14 17:35:20 +00:00
|
|
|
if (pretty_print)
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
2015-06-14 17:35:20 +00:00
|
|
|
new_indent += indent_step;
|
2015-06-03 21:34:10 +00:00
|
|
|
o << "\n";
|
2015-01-31 19:13:11 +00:00
|
|
|
}
|
|
|
|
|
2015-02-05 21:45:21 +00:00
|
|
|
for (auto i = m_value.array->cbegin(); i != m_value.array->cend(); ++i)
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
2015-02-05 21:45:21 +00:00
|
|
|
if (i != m_value.array->cbegin())
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
2015-06-14 17:35:20 +00:00
|
|
|
o << (pretty_print ? ",\n" : ",");
|
2015-01-31 19:13:11 +00:00
|
|
|
}
|
2015-06-03 21:34:10 +00:00
|
|
|
o << string_t(new_indent, ' ');
|
2015-06-14 17:35:20 +00:00
|
|
|
i->dump(o, pretty_print, indent_step, new_indent);
|
2015-01-31 19:13:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// decrease indentation
|
2015-06-14 17:35:20 +00:00
|
|
|
if (pretty_print)
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
2015-06-14 17:35:20 +00:00
|
|
|
new_indent -= indent_step;
|
2015-06-03 21:34:10 +00:00
|
|
|
o << "\n";
|
2015-01-31 19:13:11 +00:00
|
|
|
}
|
|
|
|
|
2015-06-03 21:34:10 +00:00
|
|
|
o << string_t(new_indent, ' ') << "]";
|
|
|
|
return;
|
2015-01-31 19:13:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
case (value_t::string):
|
|
|
|
{
|
2015-06-03 21:34:10 +00:00
|
|
|
o << string_t("\"");
|
|
|
|
escape_string(o, *m_value.string);
|
|
|
|
o << "\"";
|
|
|
|
return;
|
2015-01-31 19:13:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
case (value_t::boolean):
|
|
|
|
{
|
2015-06-03 21:34:10 +00:00
|
|
|
o << (m_value.boolean ? "true" : "false");
|
|
|
|
return;
|
2015-01-31 19:13:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
case (value_t::number_integer):
|
|
|
|
{
|
2015-06-03 21:34:10 +00:00
|
|
|
o << m_value.number_integer;
|
|
|
|
return;
|
2015-01-31 19:13:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
case (value_t::number_float):
|
|
|
|
{
|
2015-03-23 19:27:30 +00:00
|
|
|
// 15 digits of precision allows round-trip IEEE 754
|
2015-06-13 10:42:18 +00:00
|
|
|
// string->double->string; to be safe, we read this value from
|
|
|
|
// std::numeric_limits<number_float_t>::digits10
|
|
|
|
o << std::setprecision(std::numeric_limits<number_float_t>::digits10) << m_value.number_float;
|
2015-06-03 21:34:10 +00:00
|
|
|
return;
|
2015-01-31 19:13:11 +00:00
|
|
|
}
|
2015-02-10 19:28:16 +00:00
|
|
|
|
2015-05-03 15:52:13 +00:00
|
|
|
case (value_t::discarded):
|
|
|
|
{
|
2015-06-03 21:34:10 +00:00
|
|
|
o << "<discarded>";
|
|
|
|
return;
|
2015-05-03 15:52:13 +00:00
|
|
|
}
|
2015-06-03 21:34:10 +00:00
|
|
|
|
2015-02-10 19:28:16 +00:00
|
|
|
default:
|
|
|
|
{
|
2015-06-03 21:34:10 +00:00
|
|
|
o << "null";
|
|
|
|
return;
|
2015-02-10 19:28:16 +00:00
|
|
|
}
|
2015-01-31 19:13:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-23 22:03:48 +00:00
|
|
|
/// "equality" comparison for floating point numbers
|
|
|
|
template<typename T>
|
2015-06-12 08:08:57 +00:00
|
|
|
static bool approx(const T a, const T b)
|
2015-03-23 22:03:48 +00:00
|
|
|
{
|
|
|
|
return not (a > b or a < b);
|
|
|
|
}
|
|
|
|
|
2015-01-31 19:13:11 +00:00
|
|
|
|
|
|
|
private:
|
|
|
|
//////////////////////
|
|
|
|
// member variables //
|
|
|
|
//////////////////////
|
|
|
|
|
|
|
|
/// the type of the current element
|
|
|
|
value_t m_type = value_t::null;
|
|
|
|
|
|
|
|
/// the value of the current element
|
|
|
|
json_value m_value = {};
|
|
|
|
|
2015-02-07 14:57:47 +00:00
|
|
|
|
2015-02-09 17:02:31 +00:00
|
|
|
private:
|
2015-01-31 19:13:11 +00:00
|
|
|
///////////////
|
|
|
|
// iterators //
|
|
|
|
///////////////
|
|
|
|
|
2015-02-09 17:02:31 +00:00
|
|
|
/// an iterator value
|
|
|
|
union internal_iterator
|
|
|
|
{
|
|
|
|
/// iterator for JSON objects
|
2015-05-06 18:18:16 +00:00
|
|
|
typename object_t::iterator object_iterator;
|
2015-02-09 17:02:31 +00:00
|
|
|
/// iterator for JSON arrays
|
2015-05-06 18:18:16 +00:00
|
|
|
typename array_t::iterator array_iterator;
|
2015-06-02 19:24:03 +00:00
|
|
|
/// generic iterator for all other value types
|
2015-02-22 16:52:27 +00:00
|
|
|
difference_type generic_iterator;
|
2015-02-09 17:02:31 +00:00
|
|
|
|
|
|
|
/// default constructor
|
2015-02-22 16:52:27 +00:00
|
|
|
internal_iterator() : generic_iterator(-1) {}
|
2015-02-09 17:02:31 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
public:
|
2015-02-22 16:52:27 +00:00
|
|
|
/// a random access iterator for the basic_json class
|
|
|
|
class iterator : public std::iterator<std::random_access_iterator_tag, basic_json>
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
2015-03-22 18:18:21 +00:00
|
|
|
// allow basic_json class to access m_it
|
|
|
|
friend class basic_json;
|
|
|
|
|
2015-01-31 19:13:11 +00:00
|
|
|
public:
|
|
|
|
/// the type of the values when the iterator is dereferenced
|
2015-06-04 19:02:16 +00:00
|
|
|
using value_type = typename basic_json::value_type;
|
2015-01-31 19:13:11 +00:00
|
|
|
/// a type to represent differences between iterators
|
2015-06-04 19:02:16 +00:00
|
|
|
using difference_type = typename basic_json::difference_type;
|
2015-01-31 19:13:11 +00:00
|
|
|
/// defines a pointer to the type iterated over (value_type)
|
2015-06-04 19:02:16 +00:00
|
|
|
using pointer = typename basic_json::pointer;
|
2015-01-31 19:13:11 +00:00
|
|
|
/// defines a reference to the type iterated over (value_type)
|
2015-06-04 19:02:16 +00:00
|
|
|
using reference = typename basic_json::reference;
|
2015-01-31 19:13:11 +00:00
|
|
|
/// the category of the iterator
|
2015-06-09 11:31:10 +00:00
|
|
|
using iterator_category = std::bidirectional_iterator_tag;
|
2015-01-31 19:13:11 +00:00
|
|
|
|
2015-02-15 14:16:11 +00:00
|
|
|
/// default constructor
|
2015-06-12 08:08:57 +00:00
|
|
|
iterator() = default;
|
2015-02-15 14:16:11 +00:00
|
|
|
|
2015-01-31 19:13:11 +00:00
|
|
|
/// constructor for a given JSON instance
|
2015-06-12 08:08:57 +00:00
|
|
|
iterator(pointer object) noexcept : m_object(object)
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
|
|
|
switch (m_object->m_type)
|
|
|
|
{
|
|
|
|
case (basic_json::value_t::object):
|
|
|
|
{
|
|
|
|
m_it.object_iterator = typename object_t::iterator();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case (basic_json::value_t::array):
|
|
|
|
{
|
|
|
|
m_it.array_iterator = typename array_t::iterator();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
{
|
2015-02-22 16:52:27 +00:00
|
|
|
m_it.generic_iterator = -1;
|
2015-01-31 19:13:11 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-22 16:50:43 +00:00
|
|
|
/// copy constructor
|
2015-06-12 08:08:57 +00:00
|
|
|
iterator(const iterator& other) noexcept
|
2015-03-22 16:50:43 +00:00
|
|
|
: m_object(other.m_object), m_it(other.m_it)
|
|
|
|
{}
|
|
|
|
|
2015-01-31 19:13:11 +00:00
|
|
|
/// copy assignment
|
2015-06-12 08:08:57 +00:00
|
|
|
iterator& operator=(iterator other) noexcept (
|
2015-03-22 16:50:43 +00:00
|
|
|
std::is_nothrow_move_constructible<pointer>::value and
|
|
|
|
std::is_nothrow_move_assignable<pointer>::value and
|
2015-05-06 18:18:16 +00:00
|
|
|
std::is_nothrow_move_constructible<internal_iterator>::value and
|
|
|
|
std::is_nothrow_move_assignable<internal_iterator>::value
|
2015-03-22 16:50:43 +00:00
|
|
|
)
|
|
|
|
{
|
|
|
|
std::swap(m_object, other.m_object);
|
|
|
|
std::swap(m_it, other.m_it);
|
2015-01-31 19:13:11 +00:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2015-03-24 18:08:03 +00:00
|
|
|
private:
|
2015-01-31 19:13:11 +00:00
|
|
|
/// set the iterator to the first value
|
2015-06-12 08:08:57 +00:00
|
|
|
void set_begin() noexcept
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
|
|
|
switch (m_object->m_type)
|
|
|
|
{
|
|
|
|
case (basic_json::value_t::object):
|
|
|
|
{
|
|
|
|
m_it.object_iterator = m_object->m_value.object->begin();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case (basic_json::value_t::array):
|
|
|
|
{
|
|
|
|
m_it.array_iterator = m_object->m_value.array->begin();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case (basic_json::value_t::null):
|
|
|
|
{
|
2015-02-07 14:57:47 +00:00
|
|
|
// set to end so begin()==end() is true: null is empty
|
2015-02-22 16:52:27 +00:00
|
|
|
m_it.generic_iterator = 1;
|
2015-01-31 19:13:11 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
{
|
2015-02-22 16:52:27 +00:00
|
|
|
m_it.generic_iterator = 0;
|
2015-01-31 19:13:11 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// set the iterator past the last value
|
2015-06-12 08:08:57 +00:00
|
|
|
void set_end() noexcept
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
|
|
|
switch (m_object->m_type)
|
|
|
|
{
|
|
|
|
case (basic_json::value_t::object):
|
|
|
|
{
|
|
|
|
m_it.object_iterator = m_object->m_value.object->end();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case (basic_json::value_t::array):
|
|
|
|
{
|
|
|
|
m_it.array_iterator = m_object->m_value.array->end();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
{
|
2015-02-22 16:52:27 +00:00
|
|
|
m_it.generic_iterator = 1;
|
2015-01-31 19:13:11 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-24 18:08:03 +00:00
|
|
|
public:
|
2015-01-31 19:13:11 +00:00
|
|
|
/// return a reference to the value pointed to by the iterator
|
2015-06-12 08:08:57 +00:00
|
|
|
reference operator*()
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
|
|
|
switch (m_object->m_type)
|
|
|
|
{
|
|
|
|
case (basic_json::value_t::object):
|
|
|
|
{
|
|
|
|
return m_it.object_iterator->second;
|
|
|
|
}
|
|
|
|
|
|
|
|
case (basic_json::value_t::array):
|
|
|
|
{
|
|
|
|
return *m_it.array_iterator;
|
|
|
|
}
|
|
|
|
|
|
|
|
case (basic_json::value_t::null):
|
|
|
|
{
|
|
|
|
throw std::out_of_range("cannot get value");
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
{
|
2015-02-22 16:52:27 +00:00
|
|
|
if (m_it.generic_iterator == 0)
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
|
|
|
return *m_object;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
throw std::out_of_range("cannot get value");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// dereference the iterator
|
2015-06-12 08:08:57 +00:00
|
|
|
pointer operator->()
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
|
|
|
switch (m_object->m_type)
|
|
|
|
{
|
|
|
|
case (basic_json::value_t::object):
|
|
|
|
{
|
|
|
|
return &(m_it.object_iterator->second);
|
|
|
|
}
|
|
|
|
|
|
|
|
case (basic_json::value_t::array):
|
|
|
|
{
|
|
|
|
return &*m_it.array_iterator;
|
|
|
|
}
|
|
|
|
|
2015-02-22 16:52:27 +00:00
|
|
|
case (basic_json::value_t::null):
|
|
|
|
{
|
|
|
|
throw std::out_of_range("cannot get value");
|
|
|
|
}
|
|
|
|
|
2015-01-31 19:13:11 +00:00
|
|
|
default:
|
|
|
|
{
|
2015-02-22 16:52:27 +00:00
|
|
|
if (m_it.generic_iterator == 0)
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
|
|
|
return m_object;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
throw std::out_of_range("cannot get value");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// post-increment (it++)
|
2015-06-12 08:08:57 +00:00
|
|
|
iterator operator++(int)
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
2015-02-22 16:52:27 +00:00
|
|
|
auto result = *this;
|
2015-01-31 19:13:11 +00:00
|
|
|
|
|
|
|
switch (m_object->m_type)
|
|
|
|
{
|
|
|
|
case (basic_json::value_t::object):
|
|
|
|
{
|
|
|
|
m_it.object_iterator++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case (basic_json::value_t::array):
|
|
|
|
{
|
|
|
|
m_it.array_iterator++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
{
|
2015-02-22 16:52:27 +00:00
|
|
|
m_it.generic_iterator++;
|
2015-01-31 19:13:11 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// pre-increment (++it)
|
2015-06-12 08:08:57 +00:00
|
|
|
iterator& operator++()
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
|
|
|
switch (m_object->m_type)
|
|
|
|
{
|
|
|
|
case (basic_json::value_t::object):
|
|
|
|
{
|
|
|
|
++m_it.object_iterator;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case (basic_json::value_t::array):
|
|
|
|
{
|
|
|
|
++m_it.array_iterator;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
{
|
2015-02-22 16:52:27 +00:00
|
|
|
++m_it.generic_iterator;
|
2015-01-31 19:13:11 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// post-decrement (it--)
|
2015-06-12 08:08:57 +00:00
|
|
|
iterator operator--(int)
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
2015-02-22 16:52:27 +00:00
|
|
|
auto result = *this;
|
2015-01-31 19:13:11 +00:00
|
|
|
|
|
|
|
switch (m_object->m_type)
|
|
|
|
{
|
|
|
|
case (basic_json::value_t::object):
|
|
|
|
{
|
|
|
|
m_it.object_iterator--;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case (basic_json::value_t::array):
|
|
|
|
{
|
|
|
|
m_it.array_iterator--;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
{
|
2015-02-22 16:52:27 +00:00
|
|
|
m_it.generic_iterator--;
|
2015-01-31 19:13:11 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// pre-decrement (--it)
|
2015-06-12 08:08:57 +00:00
|
|
|
iterator& operator--()
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
|
|
|
switch (m_object->m_type)
|
|
|
|
{
|
|
|
|
case (basic_json::value_t::object):
|
|
|
|
{
|
|
|
|
--m_it.object_iterator;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case (basic_json::value_t::array):
|
|
|
|
{
|
|
|
|
--m_it.array_iterator;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
{
|
2015-02-22 16:52:27 +00:00
|
|
|
--m_it.generic_iterator;
|
2015-01-31 19:13:11 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// comparison: equal
|
2015-06-12 08:08:57 +00:00
|
|
|
bool operator==(const iterator& other) const
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
2015-02-22 16:52:27 +00:00
|
|
|
// if objects are not the same, the comparison is undefined
|
|
|
|
if (m_object != other.m_object)
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
2015-02-22 16:52:27 +00:00
|
|
|
throw std::domain_error("cannot compare iterators of different containers");
|
2015-01-31 19:13:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
switch (m_object->m_type)
|
|
|
|
{
|
|
|
|
case (basic_json::value_t::object):
|
|
|
|
{
|
|
|
|
return (m_it.object_iterator == other.m_it.object_iterator);
|
|
|
|
}
|
|
|
|
|
|
|
|
case (basic_json::value_t::array):
|
|
|
|
{
|
|
|
|
return (m_it.array_iterator == other.m_it.array_iterator);
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
return (m_it.generic_iterator == other.m_it.generic_iterator);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// comparison: not equal
|
2015-06-12 08:08:57 +00:00
|
|
|
bool operator!=(const iterator& other) const
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
|
|
|
return not operator==(other);
|
|
|
|
}
|
|
|
|
|
2015-02-22 16:52:27 +00:00
|
|
|
/// comparison: smaller
|
2015-06-12 08:08:57 +00:00
|
|
|
bool operator<(const iterator& other) const
|
2015-02-22 16:52:27 +00:00
|
|
|
{
|
|
|
|
// if objects are not the same, the comparison is undefined
|
|
|
|
if (m_object != other.m_object)
|
|
|
|
{
|
|
|
|
throw std::domain_error("cannot compare iterators of different containers");
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (m_object->m_type)
|
|
|
|
{
|
|
|
|
case (basic_json::value_t::object):
|
|
|
|
{
|
|
|
|
throw std::domain_error("cannot use operator< for object iterators");
|
|
|
|
}
|
|
|
|
|
|
|
|
case (basic_json::value_t::array):
|
|
|
|
{
|
|
|
|
return (m_it.array_iterator < other.m_it.array_iterator);
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
return (m_it.generic_iterator < other.m_it.generic_iterator);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// comparison: less than or equal
|
2015-06-12 08:08:57 +00:00
|
|
|
bool operator<=(const iterator& other) const
|
2015-02-22 16:52:27 +00:00
|
|
|
{
|
|
|
|
return not other.operator < (*this);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// comparison: greater than
|
2015-06-12 08:08:57 +00:00
|
|
|
bool operator>(const iterator& other) const
|
2015-02-22 16:52:27 +00:00
|
|
|
{
|
|
|
|
return not operator<=(other);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// comparison: greater than or equal
|
2015-06-12 08:08:57 +00:00
|
|
|
bool operator>=(const iterator& other) const
|
2015-02-22 16:52:27 +00:00
|
|
|
{
|
|
|
|
return not operator<(other);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// add to iterator
|
2015-06-12 08:08:57 +00:00
|
|
|
iterator& operator+=(difference_type i)
|
2015-02-22 16:52:27 +00:00
|
|
|
{
|
|
|
|
switch (m_object->m_type)
|
|
|
|
{
|
|
|
|
case (basic_json::value_t::object):
|
|
|
|
{
|
|
|
|
throw std::domain_error("cannot use operator+= for object iterators");
|
|
|
|
}
|
|
|
|
|
|
|
|
case (basic_json::value_t::array):
|
|
|
|
{
|
|
|
|
m_it.array_iterator += i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
m_it.generic_iterator += i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// subtract from iterator
|
2015-06-12 08:08:57 +00:00
|
|
|
iterator& operator-=(difference_type i)
|
2015-02-22 16:52:27 +00:00
|
|
|
{
|
|
|
|
return operator+=(-i);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// add to iterator
|
2015-06-12 08:08:57 +00:00
|
|
|
iterator operator+(difference_type i)
|
2015-02-22 16:52:27 +00:00
|
|
|
{
|
|
|
|
auto result = *this;
|
|
|
|
result += i;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// subtract from iterator
|
2015-06-12 08:08:57 +00:00
|
|
|
iterator operator-(difference_type i)
|
2015-02-22 16:52:27 +00:00
|
|
|
{
|
|
|
|
auto result = *this;
|
|
|
|
result -= i;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// return difference
|
2015-06-12 08:08:57 +00:00
|
|
|
difference_type operator-(const iterator& other) const
|
2015-02-22 16:52:27 +00:00
|
|
|
{
|
|
|
|
switch (m_object->m_type)
|
|
|
|
{
|
|
|
|
case (basic_json::value_t::object):
|
|
|
|
{
|
|
|
|
throw std::domain_error("cannot use operator- for object iterators");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
case (basic_json::value_t::array):
|
|
|
|
{
|
|
|
|
return m_it.array_iterator - other.m_it.array_iterator;
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
return m_it.generic_iterator - other.m_it.generic_iterator;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// access to successor
|
2015-06-12 08:08:57 +00:00
|
|
|
reference operator[](difference_type n)
|
2015-02-22 16:52:27 +00:00
|
|
|
{
|
|
|
|
switch (m_object->m_type)
|
|
|
|
{
|
|
|
|
case (basic_json::value_t::object):
|
|
|
|
{
|
|
|
|
throw std::domain_error("cannot use operator[] for object iterators");
|
|
|
|
}
|
|
|
|
|
|
|
|
case (basic_json::value_t::array):
|
|
|
|
{
|
|
|
|
return *(m_it.array_iterator + n);
|
|
|
|
}
|
|
|
|
|
|
|
|
case (basic_json::value_t::null):
|
|
|
|
{
|
|
|
|
throw std::out_of_range("cannot get value");
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
if (m_it.generic_iterator == -n)
|
|
|
|
{
|
|
|
|
return *m_object;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
throw std::out_of_range("cannot get value");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-26 16:06:33 +00:00
|
|
|
/// return the key of an object iterator
|
2015-06-12 08:08:57 +00:00
|
|
|
typename object_t::key_type key() const
|
2015-03-24 18:08:03 +00:00
|
|
|
{
|
|
|
|
switch (m_object->m_type)
|
|
|
|
{
|
|
|
|
case (basic_json::value_t::object):
|
|
|
|
{
|
|
|
|
return m_it.object_iterator->first;
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
throw std::domain_error("cannot use key() for non-object iterators");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-26 16:06:33 +00:00
|
|
|
/// return the key of an iterator
|
2015-06-12 08:08:57 +00:00
|
|
|
reference value()
|
2015-03-24 18:08:03 +00:00
|
|
|
{
|
|
|
|
return operator*();
|
|
|
|
}
|
|
|
|
|
2015-01-31 19:13:11 +00:00
|
|
|
private:
|
|
|
|
/// associated JSON instance
|
|
|
|
pointer m_object = nullptr;
|
|
|
|
/// the actual iterator of the associated instance
|
2015-06-20 13:47:37 +00:00
|
|
|
internal_iterator m_it = internal_iterator();
|
2015-01-31 19:13:11 +00:00
|
|
|
};
|
|
|
|
|
2015-02-22 16:52:27 +00:00
|
|
|
/// a const random access iterator for the basic_json class
|
|
|
|
class const_iterator : public std::iterator<std::random_access_iterator_tag, const basic_json>
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
2015-03-22 18:18:21 +00:00
|
|
|
// allow basic_json class to access m_it
|
|
|
|
friend class basic_json;
|
|
|
|
|
2015-01-31 19:13:11 +00:00
|
|
|
public:
|
|
|
|
/// the type of the values when the iterator is dereferenced
|
2015-06-04 19:02:16 +00:00
|
|
|
using value_type = typename basic_json::value_type;
|
2015-01-31 19:13:11 +00:00
|
|
|
/// a type to represent differences between iterators
|
2015-06-04 19:02:16 +00:00
|
|
|
using difference_type = typename basic_json::difference_type;
|
2015-01-31 19:13:11 +00:00
|
|
|
/// defines a pointer to the type iterated over (value_type)
|
2015-06-04 19:02:16 +00:00
|
|
|
using pointer = typename basic_json::const_pointer;
|
2015-01-31 19:13:11 +00:00
|
|
|
/// defines a reference to the type iterated over (value_type)
|
2015-06-04 19:02:16 +00:00
|
|
|
using reference = typename basic_json::const_reference;
|
2015-01-31 19:13:11 +00:00
|
|
|
/// the category of the iterator
|
2015-06-09 11:31:10 +00:00
|
|
|
using iterator_category = std::bidirectional_iterator_tag;
|
2015-01-31 19:13:11 +00:00
|
|
|
|
2015-02-15 14:16:11 +00:00
|
|
|
/// default constructor
|
2015-06-12 08:08:57 +00:00
|
|
|
const_iterator() = default;
|
2015-02-15 14:16:11 +00:00
|
|
|
|
2015-01-31 19:13:11 +00:00
|
|
|
/// constructor for a given JSON instance
|
2015-06-12 08:08:57 +00:00
|
|
|
const_iterator(pointer object) noexcept : m_object(object)
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
|
|
|
switch (m_object->m_type)
|
|
|
|
{
|
|
|
|
case (basic_json::value_t::object):
|
|
|
|
{
|
2015-05-06 18:18:16 +00:00
|
|
|
m_it.object_iterator = typename object_t::iterator();
|
2015-01-31 19:13:11 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case (basic_json::value_t::array):
|
|
|
|
{
|
2015-05-06 18:18:16 +00:00
|
|
|
m_it.array_iterator = typename array_t::iterator();
|
2015-01-31 19:13:11 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
{
|
2015-02-22 16:52:27 +00:00
|
|
|
m_it.generic_iterator = -1;
|
2015-01-31 19:13:11 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-07 14:57:47 +00:00
|
|
|
/// copy constructor given a nonconst iterator
|
2015-06-12 08:08:57 +00:00
|
|
|
const_iterator(const iterator& other) noexcept : m_object(other.m_object)
|
2015-02-09 17:02:31 +00:00
|
|
|
{
|
|
|
|
switch (m_object->m_type)
|
|
|
|
{
|
|
|
|
case (basic_json::value_t::object):
|
|
|
|
{
|
|
|
|
m_it.object_iterator = other.m_it.object_iterator;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case (basic_json::value_t::array):
|
|
|
|
{
|
|
|
|
m_it.array_iterator = other.m_it.array_iterator;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
m_it.generic_iterator = other.m_it.generic_iterator;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-01-31 19:13:11 +00:00
|
|
|
|
2015-03-22 16:50:43 +00:00
|
|
|
/// copy constructor
|
2015-06-12 08:08:57 +00:00
|
|
|
const_iterator(const const_iterator& other) noexcept
|
2015-03-22 16:50:43 +00:00
|
|
|
: m_object(other.m_object), m_it(other.m_it)
|
|
|
|
{}
|
|
|
|
|
2015-01-31 19:13:11 +00:00
|
|
|
/// copy assignment
|
2015-06-12 08:08:57 +00:00
|
|
|
const_iterator& operator=(const_iterator other) noexcept(
|
2015-03-22 16:50:43 +00:00
|
|
|
std::is_nothrow_move_constructible<pointer>::value and
|
|
|
|
std::is_nothrow_move_assignable<pointer>::value and
|
2015-05-06 18:18:16 +00:00
|
|
|
std::is_nothrow_move_constructible<internal_iterator>::value and
|
|
|
|
std::is_nothrow_move_assignable<internal_iterator>::value
|
2015-03-22 16:50:43 +00:00
|
|
|
)
|
|
|
|
{
|
|
|
|
std::swap(m_object, other.m_object);
|
|
|
|
std::swap(m_it, other.m_it);
|
2015-01-31 19:13:11 +00:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2015-03-24 18:08:03 +00:00
|
|
|
private:
|
2015-01-31 19:13:11 +00:00
|
|
|
/// set the iterator to the first value
|
2015-06-12 08:08:57 +00:00
|
|
|
void set_begin() noexcept
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
|
|
|
switch (m_object->m_type)
|
|
|
|
{
|
|
|
|
case (basic_json::value_t::object):
|
|
|
|
{
|
2015-05-06 18:18:16 +00:00
|
|
|
m_it.object_iterator = m_object->m_value.object->begin();
|
2015-01-31 19:13:11 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case (basic_json::value_t::array):
|
|
|
|
{
|
2015-05-06 18:18:16 +00:00
|
|
|
m_it.array_iterator = m_object->m_value.array->begin();
|
2015-01-31 19:13:11 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case (basic_json::value_t::null):
|
|
|
|
{
|
2015-02-07 14:57:47 +00:00
|
|
|
// set to end so begin()==end() is true: null is empty
|
2015-02-22 16:52:27 +00:00
|
|
|
m_it.generic_iterator = 1;
|
2015-01-31 19:13:11 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
{
|
2015-02-22 16:52:27 +00:00
|
|
|
m_it.generic_iterator = 0;
|
2015-01-31 19:13:11 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// set the iterator past the last value
|
2015-06-12 08:08:57 +00:00
|
|
|
void set_end() noexcept
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
|
|
|
switch (m_object->m_type)
|
|
|
|
{
|
|
|
|
case (basic_json::value_t::object):
|
|
|
|
{
|
2015-05-06 18:18:16 +00:00
|
|
|
m_it.object_iterator = m_object->m_value.object->end();
|
2015-01-31 19:13:11 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case (basic_json::value_t::array):
|
|
|
|
{
|
2015-05-06 18:18:16 +00:00
|
|
|
m_it.array_iterator = m_object->m_value.array->end();
|
2015-01-31 19:13:11 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
{
|
2015-02-22 16:52:27 +00:00
|
|
|
m_it.generic_iterator = 1;
|
2015-01-31 19:13:11 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-24 18:08:03 +00:00
|
|
|
public:
|
2015-01-31 19:13:11 +00:00
|
|
|
/// return a reference to the value pointed to by the iterator
|
2015-06-12 08:08:57 +00:00
|
|
|
reference operator*() const
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
|
|
|
switch (m_object->m_type)
|
|
|
|
{
|
|
|
|
case (basic_json::value_t::object):
|
|
|
|
{
|
|
|
|
return m_it.object_iterator->second;
|
|
|
|
}
|
|
|
|
|
|
|
|
case (basic_json::value_t::array):
|
|
|
|
{
|
|
|
|
return *m_it.array_iterator;
|
|
|
|
}
|
|
|
|
|
|
|
|
case (basic_json::value_t::null):
|
|
|
|
{
|
|
|
|
throw std::out_of_range("cannot get value");
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
{
|
2015-02-22 16:52:27 +00:00
|
|
|
if (m_it.generic_iterator == 0)
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
|
|
|
return *m_object;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
throw std::out_of_range("cannot get value");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// dereference the iterator
|
2015-06-12 08:08:57 +00:00
|
|
|
pointer operator->() const
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
|
|
|
switch (m_object->m_type)
|
|
|
|
{
|
|
|
|
case (basic_json::value_t::object):
|
|
|
|
{
|
|
|
|
return &(m_it.object_iterator->second);
|
|
|
|
}
|
|
|
|
|
|
|
|
case (basic_json::value_t::array):
|
|
|
|
{
|
|
|
|
return &*m_it.array_iterator;
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
{
|
2015-02-22 16:52:27 +00:00
|
|
|
if (m_it.generic_iterator == 0)
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
|
|
|
return m_object;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
throw std::out_of_range("cannot get value");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// post-increment (it++)
|
2015-06-12 08:08:57 +00:00
|
|
|
const_iterator operator++(int)
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
2015-02-22 16:52:27 +00:00
|
|
|
auto result = *this;
|
2015-06-20 12:29:34 +00:00
|
|
|
++(*this);
|
2015-01-31 19:13:11 +00:00
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// pre-increment (++it)
|
2015-06-12 08:08:57 +00:00
|
|
|
const_iterator& operator++()
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
|
|
|
switch (m_object->m_type)
|
|
|
|
{
|
|
|
|
case (basic_json::value_t::object):
|
|
|
|
{
|
|
|
|
++m_it.object_iterator;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case (basic_json::value_t::array):
|
|
|
|
{
|
|
|
|
++m_it.array_iterator;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
{
|
2015-02-22 16:52:27 +00:00
|
|
|
++m_it.generic_iterator;
|
2015-01-31 19:13:11 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// post-decrement (it--)
|
2015-06-12 08:08:57 +00:00
|
|
|
const_iterator operator--(int)
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
2015-02-22 16:52:27 +00:00
|
|
|
auto result = *this;
|
2015-06-20 12:29:34 +00:00
|
|
|
--(*this);
|
2015-01-31 19:13:11 +00:00
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// pre-decrement (--it)
|
2015-06-12 08:08:57 +00:00
|
|
|
const_iterator& operator--()
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
|
|
|
switch (m_object->m_type)
|
|
|
|
{
|
|
|
|
case (basic_json::value_t::object):
|
|
|
|
{
|
|
|
|
--m_it.object_iterator;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case (basic_json::value_t::array):
|
|
|
|
{
|
|
|
|
--m_it.array_iterator;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
{
|
2015-02-22 16:52:27 +00:00
|
|
|
--m_it.generic_iterator;
|
2015-01-31 19:13:11 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// comparison: equal
|
2015-06-12 08:08:57 +00:00
|
|
|
bool operator==(const const_iterator& other) const
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
2015-02-22 16:52:27 +00:00
|
|
|
// if objects are not the same, the comparison is undefined
|
|
|
|
if (m_object != other.m_object)
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
2015-02-22 16:52:27 +00:00
|
|
|
throw std::domain_error("cannot compare iterators of different containers");
|
2015-01-31 19:13:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
switch (m_object->m_type)
|
|
|
|
{
|
|
|
|
case (basic_json::value_t::object):
|
|
|
|
{
|
|
|
|
return (m_it.object_iterator == other.m_it.object_iterator);
|
|
|
|
}
|
|
|
|
|
|
|
|
case (basic_json::value_t::array):
|
|
|
|
{
|
|
|
|
return (m_it.array_iterator == other.m_it.array_iterator);
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
return (m_it.generic_iterator == other.m_it.generic_iterator);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// comparison: not equal
|
2015-06-12 08:08:57 +00:00
|
|
|
bool operator!=(const const_iterator& other) const
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
|
|
|
return not operator==(other);
|
|
|
|
}
|
|
|
|
|
2015-02-22 16:52:27 +00:00
|
|
|
/// comparison: smaller
|
2015-06-12 08:08:57 +00:00
|
|
|
bool operator<(const const_iterator& other) const
|
2015-02-22 16:52:27 +00:00
|
|
|
{
|
|
|
|
// if objects are not the same, the comparison is undefined
|
|
|
|
if (m_object != other.m_object)
|
|
|
|
{
|
|
|
|
throw std::domain_error("cannot compare iterators of different containers");
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (m_object->m_type)
|
|
|
|
{
|
|
|
|
case (basic_json::value_t::object):
|
|
|
|
{
|
|
|
|
throw std::domain_error("cannot use operator< for object iterators");
|
|
|
|
}
|
|
|
|
|
|
|
|
case (basic_json::value_t::array):
|
|
|
|
{
|
|
|
|
return (m_it.array_iterator < other.m_it.array_iterator);
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
return (m_it.generic_iterator < other.m_it.generic_iterator);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// comparison: less than or equal
|
2015-06-12 08:08:57 +00:00
|
|
|
bool operator<=(const const_iterator& other) const
|
2015-02-22 16:52:27 +00:00
|
|
|
{
|
|
|
|
return not other.operator < (*this);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// comparison: greater than
|
2015-06-12 08:08:57 +00:00
|
|
|
bool operator>(const const_iterator& other) const
|
2015-02-22 16:52:27 +00:00
|
|
|
{
|
|
|
|
return not operator<=(other);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// comparison: greater than or equal
|
2015-06-12 08:08:57 +00:00
|
|
|
bool operator>=(const const_iterator& other) const
|
2015-02-22 16:52:27 +00:00
|
|
|
{
|
|
|
|
return not operator<(other);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// add to iterator
|
2015-06-12 08:08:57 +00:00
|
|
|
const_iterator& operator+=(difference_type i)
|
2015-02-22 16:52:27 +00:00
|
|
|
{
|
|
|
|
switch (m_object->m_type)
|
|
|
|
{
|
|
|
|
case (basic_json::value_t::object):
|
|
|
|
{
|
|
|
|
throw std::domain_error("cannot use operator+= for object iterators");
|
|
|
|
}
|
|
|
|
|
|
|
|
case (basic_json::value_t::array):
|
|
|
|
{
|
|
|
|
m_it.array_iterator += i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
m_it.generic_iterator += i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// subtract from iterator
|
2015-06-12 08:08:57 +00:00
|
|
|
const_iterator& operator-=(difference_type i)
|
2015-02-22 16:52:27 +00:00
|
|
|
{
|
|
|
|
return operator+=(-i);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// add to iterator
|
2015-06-12 08:08:57 +00:00
|
|
|
const_iterator operator+(difference_type i)
|
2015-02-22 16:52:27 +00:00
|
|
|
{
|
|
|
|
auto result = *this;
|
|
|
|
result += i;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// subtract from iterator
|
2015-06-12 08:08:57 +00:00
|
|
|
const_iterator operator-(difference_type i)
|
2015-02-22 16:52:27 +00:00
|
|
|
{
|
|
|
|
auto result = *this;
|
|
|
|
result -= i;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// return difference
|
2015-06-12 08:08:57 +00:00
|
|
|
difference_type operator-(const const_iterator& other) const
|
2015-02-22 16:52:27 +00:00
|
|
|
{
|
|
|
|
switch (m_object->m_type)
|
|
|
|
{
|
|
|
|
case (basic_json::value_t::object):
|
|
|
|
{
|
|
|
|
throw std::domain_error("cannot use operator- for object iterators");
|
|
|
|
}
|
|
|
|
|
|
|
|
case (basic_json::value_t::array):
|
|
|
|
{
|
|
|
|
return m_it.array_iterator - other.m_it.array_iterator;
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
return m_it.generic_iterator - other.m_it.generic_iterator;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// access to successor
|
2015-06-12 08:08:57 +00:00
|
|
|
reference operator[](difference_type n) const
|
2015-02-22 16:52:27 +00:00
|
|
|
{
|
|
|
|
switch (m_object->m_type)
|
|
|
|
{
|
|
|
|
case (basic_json::value_t::object):
|
|
|
|
{
|
|
|
|
throw std::domain_error("cannot use operator[] for object iterators");
|
|
|
|
}
|
|
|
|
|
|
|
|
case (basic_json::value_t::array):
|
|
|
|
{
|
|
|
|
return *(m_it.array_iterator + n);
|
|
|
|
}
|
|
|
|
|
|
|
|
case (basic_json::value_t::null):
|
|
|
|
{
|
|
|
|
throw std::out_of_range("cannot get value");
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
if (m_it.generic_iterator == -n)
|
|
|
|
{
|
|
|
|
return *m_object;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
throw std::out_of_range("cannot get value");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-26 16:06:33 +00:00
|
|
|
/// return the key of an object iterator
|
2015-06-12 08:08:57 +00:00
|
|
|
typename object_t::key_type key() const
|
2015-03-24 18:08:03 +00:00
|
|
|
{
|
|
|
|
switch (m_object->m_type)
|
|
|
|
{
|
|
|
|
case (basic_json::value_t::object):
|
|
|
|
{
|
|
|
|
return m_it.object_iterator->first;
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
throw std::domain_error("cannot use key() for non-object iterators");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-26 16:06:33 +00:00
|
|
|
/// return the value of an iterator
|
2015-06-12 08:08:57 +00:00
|
|
|
reference value() const
|
2015-03-24 18:08:03 +00:00
|
|
|
{
|
|
|
|
return operator*();
|
|
|
|
}
|
|
|
|
|
2015-01-31 19:13:11 +00:00
|
|
|
private:
|
|
|
|
/// associated JSON instance
|
|
|
|
pointer m_object = nullptr;
|
|
|
|
/// the actual iterator of the associated instance
|
2015-06-20 13:47:37 +00:00
|
|
|
internal_iterator m_it = internal_iterator();
|
2015-01-31 19:13:11 +00:00
|
|
|
};
|
2015-02-05 21:45:21 +00:00
|
|
|
|
2015-03-26 16:06:33 +00:00
|
|
|
/// a reverse random access iterator for the basic_json class
|
2015-06-19 06:11:48 +00:00
|
|
|
class reverse_iterator : public std::reverse_iterator<typename basic_json::iterator>
|
2015-03-26 16:06:33 +00:00
|
|
|
{
|
|
|
|
public:
|
2015-06-12 08:08:57 +00:00
|
|
|
reverse_iterator(const typename
|
2015-06-13 08:29:43 +00:00
|
|
|
std::reverse_iterator<typename basic_json::iterator>::iterator_type&
|
|
|
|
it)
|
2015-03-26 16:06:33 +00:00
|
|
|
: std::reverse_iterator<basic_json::iterator>(it) {}
|
|
|
|
|
|
|
|
/// return the key of an object iterator
|
2015-06-12 08:08:57 +00:00
|
|
|
typename object_t::key_type key() const
|
2015-03-26 16:06:33 +00:00
|
|
|
{
|
|
|
|
return this->base().key();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// return the value of an iterator
|
2015-06-12 08:08:57 +00:00
|
|
|
reference value() const
|
2015-03-26 16:06:33 +00:00
|
|
|
{
|
|
|
|
return this->base().operator * ();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/// a const reverse random access iterator for the basic_json class
|
2015-06-19 06:11:48 +00:00
|
|
|
class const_reverse_iterator : public std::reverse_iterator<typename basic_json::const_iterator>
|
2015-03-26 16:06:33 +00:00
|
|
|
{
|
|
|
|
public:
|
2015-06-12 08:08:57 +00:00
|
|
|
const_reverse_iterator(const typename
|
2015-06-13 08:29:43 +00:00
|
|
|
std::reverse_iterator<typename basic_json::const_iterator>::iterator_type& it)
|
2015-03-26 16:06:33 +00:00
|
|
|
: std::reverse_iterator<basic_json::const_iterator>(it) {}
|
|
|
|
|
|
|
|
/// return the key of an object iterator
|
2015-06-12 08:08:57 +00:00
|
|
|
typename object_t::key_type key() const
|
2015-03-26 16:06:33 +00:00
|
|
|
{
|
|
|
|
return this->base().key();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// return the value of an iterator
|
2015-06-12 08:08:57 +00:00
|
|
|
const_reference value() const
|
2015-03-26 16:06:33 +00:00
|
|
|
{
|
|
|
|
return this->base().operator * ();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2015-02-07 14:57:47 +00:00
|
|
|
|
2015-02-05 21:45:21 +00:00
|
|
|
private:
|
2015-02-15 13:52:00 +00:00
|
|
|
//////////////////////
|
|
|
|
// lexer and parser //
|
|
|
|
//////////////////////
|
2015-02-05 21:45:21 +00:00
|
|
|
|
2015-02-15 13:52:00 +00:00
|
|
|
/*!
|
|
|
|
@brief lexical analysis
|
|
|
|
|
|
|
|
This class organizes the lexical analysis during JSON deserialization. The
|
|
|
|
core of it is a scanner generated by re2c <http://re2c.org> that processes
|
|
|
|
a buffer and recognizes tokens according to RFC 7159 and ECMA-404.
|
|
|
|
*/
|
2015-02-11 08:10:28 +00:00
|
|
|
class lexer
|
2015-02-05 21:45:21 +00:00
|
|
|
{
|
2015-02-11 08:10:28 +00:00
|
|
|
public:
|
2015-02-05 21:45:21 +00:00
|
|
|
/// token types for the parser
|
|
|
|
enum class token_type
|
|
|
|
{
|
2015-02-15 13:52:00 +00:00
|
|
|
uninitialized, ///< indicating the scanner is uninitialized
|
|
|
|
literal_true, ///< the "true" literal
|
|
|
|
literal_false, ///< the "false" literal
|
|
|
|
literal_null, ///< the "null" literal
|
|
|
|
value_string, ///< a string - use get_string() for actual value
|
|
|
|
value_number, ///< a number - use get_number() for actual value
|
|
|
|
begin_array, ///< the character for array begin "["
|
|
|
|
begin_object, ///< the character for object begin "{"
|
|
|
|
end_array, ///< the character for array end "]"
|
|
|
|
end_object, ///< the character for object end "}"
|
|
|
|
name_separator, ///< the name separator ":"
|
|
|
|
value_separator, ///< the value separator ","
|
|
|
|
parse_error, ///< indicating a parse error
|
|
|
|
end_of_input ///< indicating the end of the input buffer
|
2015-02-05 21:45:21 +00:00
|
|
|
};
|
|
|
|
|
2015-02-15 12:35:51 +00:00
|
|
|
/// the char type to use in the lexer
|
2015-02-16 23:22:12 +00:00
|
|
|
using lexer_char_t = unsigned char;
|
2015-02-15 12:35:51 +00:00
|
|
|
|
2015-02-15 13:52:00 +00:00
|
|
|
/// constructor with a given buffer
|
2015-06-12 08:08:57 +00:00
|
|
|
lexer(const string_t& s) noexcept
|
2015-03-24 17:05:58 +00:00
|
|
|
: m_stream(nullptr), m_buffer(s)
|
2015-02-11 08:10:28 +00:00
|
|
|
{
|
2015-03-02 20:25:09 +00:00
|
|
|
m_content = reinterpret_cast<const lexer_char_t*>(s.c_str());
|
2015-02-11 08:10:28 +00:00
|
|
|
m_start = m_cursor = m_content;
|
2015-02-15 13:52:00 +00:00
|
|
|
m_limit = m_content + s.size();
|
2015-02-11 08:10:28 +00:00
|
|
|
}
|
2015-06-12 08:08:57 +00:00
|
|
|
lexer(std::istream* s) noexcept
|
2015-06-20 13:47:37 +00:00
|
|
|
: m_stream(s), m_buffer()
|
2015-02-28 01:19:15 +00:00
|
|
|
{
|
2015-03-02 20:25:09 +00:00
|
|
|
getline(*m_stream, m_buffer);
|
|
|
|
m_content = reinterpret_cast<const lexer_char_t*>(m_buffer.c_str());
|
2015-02-11 08:10:28 +00:00
|
|
|
m_start = m_cursor = m_content;
|
2015-02-28 01:19:15 +00:00
|
|
|
m_limit = m_content + m_buffer.size();
|
2015-02-11 08:10:28 +00:00
|
|
|
}
|
|
|
|
|
2015-02-15 13:52:00 +00:00
|
|
|
/// default constructor
|
2015-06-12 08:08:57 +00:00
|
|
|
lexer() = default;
|
2015-02-11 08:10:28 +00:00
|
|
|
|
2015-06-20 13:47:37 +00:00
|
|
|
// switch of unwanted functions
|
|
|
|
lexer(const lexer&) = delete;
|
|
|
|
lexer operator=(const lexer&) = delete;
|
|
|
|
|
2015-02-15 13:52:00 +00:00
|
|
|
/*!
|
|
|
|
@brief create a string from a Unicode code point
|
|
|
|
|
2015-02-22 16:52:27 +00:00
|
|
|
@param codepoint1 the code point (can be high surrogate)
|
|
|
|
@param codepoint2 the code point (can be low surrogate or 0)
|
2015-02-15 13:52:00 +00:00
|
|
|
@return string representation of the code point
|
2015-02-15 15:56:54 +00:00
|
|
|
@exception std::out_of_range if code point is >0x10ffff
|
|
|
|
@exception std::invalid_argument if the low surrogate is invalid
|
2015-02-15 13:52:00 +00:00
|
|
|
|
|
|
|
@see <http://en.wikipedia.org/wiki/UTF-8#Sample_code>
|
|
|
|
*/
|
2015-06-12 08:08:57 +00:00
|
|
|
static string_t to_unicode(const std::size_t codepoint1,
|
2015-06-13 08:29:43 +00:00
|
|
|
const std::size_t codepoint2 = 0)
|
2015-02-15 10:44:49 +00:00
|
|
|
{
|
2015-02-15 12:35:51 +00:00
|
|
|
string_t result;
|
2015-02-15 10:44:49 +00:00
|
|
|
|
2015-02-15 15:56:54 +00:00
|
|
|
// calculate the codepoint from the given code points
|
2015-04-11 17:26:12 +00:00
|
|
|
std::size_t codepoint = codepoint1;
|
2015-06-14 21:17:49 +00:00
|
|
|
|
|
|
|
// check if codepoint1 is a high surrogate
|
2015-02-15 15:56:54 +00:00
|
|
|
if (codepoint1 >= 0xD800 and codepoint1 <= 0xDBFF)
|
|
|
|
{
|
2015-06-14 21:17:49 +00:00
|
|
|
// check if codepoint2 is a low surrogate
|
2015-02-15 15:56:54 +00:00
|
|
|
if (codepoint2 >= 0xDC00 and codepoint2 <= 0xDFFF)
|
|
|
|
{
|
|
|
|
codepoint =
|
|
|
|
// high surrogate occupies the most significant 22 bits
|
|
|
|
(codepoint1 << 10)
|
|
|
|
// low surrogate occupies the least significant 15 bits
|
|
|
|
+ codepoint2
|
|
|
|
// there is still the 0xD800, 0xDC00 and 0x10000 noise
|
|
|
|
// in the result so we have to substract with:
|
|
|
|
// (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00
|
|
|
|
- 0x35FDC00;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
throw std::invalid_argument("missing or wrong low surrogate");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-14 21:17:49 +00:00
|
|
|
if (codepoint < 0x80)
|
2015-02-15 10:44:49 +00:00
|
|
|
{
|
2015-02-24 22:19:19 +00:00
|
|
|
// 1-byte characters: 0xxxxxxx (ASCII)
|
2015-02-15 12:35:51 +00:00
|
|
|
result.append(1, static_cast<typename string_t::value_type>(codepoint));
|
2015-02-15 10:44:49 +00:00
|
|
|
}
|
|
|
|
else if (codepoint <= 0x7ff)
|
|
|
|
{
|
|
|
|
// 2-byte characters: 110xxxxx 10xxxxxx
|
2015-02-15 12:35:51 +00:00
|
|
|
result.append(1, static_cast<typename string_t::value_type>(0xC0 | ((codepoint >> 6) & 0x1F)));
|
|
|
|
result.append(1, static_cast<typename string_t::value_type>(0x80 | (codepoint & 0x3F)));
|
2015-02-15 10:44:49 +00:00
|
|
|
}
|
|
|
|
else if (codepoint <= 0xffff)
|
|
|
|
{
|
|
|
|
// 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx
|
2015-02-15 12:35:51 +00:00
|
|
|
result.append(1, static_cast<typename string_t::value_type>(0xE0 | ((codepoint >> 12) & 0x0F)));
|
|
|
|
result.append(1, static_cast<typename string_t::value_type>(0x80 | ((codepoint >> 6) & 0x3F)));
|
|
|
|
result.append(1, static_cast<typename string_t::value_type>(0x80 | (codepoint & 0x3F)));
|
2015-02-15 10:44:49 +00:00
|
|
|
}
|
|
|
|
else if (codepoint <= 0x10ffff)
|
|
|
|
{
|
|
|
|
// 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
|
2015-02-15 12:35:51 +00:00
|
|
|
result.append(1, static_cast<typename string_t::value_type>(0xF0 | ((codepoint >> 18) & 0x07)));
|
|
|
|
result.append(1, static_cast<typename string_t::value_type>(0x80 | ((codepoint >> 12) & 0x3F)));
|
|
|
|
result.append(1, static_cast<typename string_t::value_type>(0x80 | ((codepoint >> 6) & 0x3F)));
|
|
|
|
result.append(1, static_cast<typename string_t::value_type>(0x80 | (codepoint & 0x3F)));
|
2015-02-15 10:44:49 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-02-15 12:35:51 +00:00
|
|
|
throw std::out_of_range("code points above 0x10FFFF are invalid");
|
2015-02-15 10:44:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2015-02-15 13:52:00 +00:00
|
|
|
/// return name of values of type token_type
|
2015-06-12 08:08:57 +00:00
|
|
|
static std::string token_type_name(token_type t) noexcept
|
2015-02-11 09:16:43 +00:00
|
|
|
{
|
|
|
|
switch (t)
|
|
|
|
{
|
|
|
|
case (token_type::uninitialized):
|
|
|
|
return "<uninitialized>";
|
|
|
|
case (token_type::literal_true):
|
|
|
|
return "true literal";
|
|
|
|
case (token_type::literal_false):
|
|
|
|
return "false literal";
|
|
|
|
case (token_type::literal_null):
|
|
|
|
return "null literal";
|
|
|
|
case (token_type::value_string):
|
|
|
|
return "string literal";
|
|
|
|
case (token_type::value_number):
|
|
|
|
return "number literal";
|
|
|
|
case (token_type::begin_array):
|
|
|
|
return "[";
|
|
|
|
case (token_type::begin_object):
|
|
|
|
return "{";
|
|
|
|
case (token_type::end_array):
|
|
|
|
return "]";
|
|
|
|
case (token_type::end_object):
|
|
|
|
return "}";
|
|
|
|
case (token_type::name_separator):
|
|
|
|
return ":";
|
|
|
|
case (token_type::value_separator):
|
|
|
|
return ",";
|
|
|
|
case (token_type::end_of_input):
|
|
|
|
return "<end of input>";
|
2015-02-11 09:57:17 +00:00
|
|
|
default:
|
|
|
|
return "<parse error>";
|
2015-02-11 09:16:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-11 08:41:23 +00:00
|
|
|
/*!
|
|
|
|
This function implements a scanner for JSON. It is specified using
|
|
|
|
regular expressions that try to follow RFC 7159 and ECMA-404 as close
|
|
|
|
as possible. These regular expressions are then translated into a
|
2015-02-15 13:52:00 +00:00
|
|
|
deterministic finite automaton (DFA) by the tool re2c
|
|
|
|
<http://re2c.org>. As a result, the translated code for this function
|
|
|
|
consists of a large block of code with goto jumps.
|
2015-02-11 08:41:23 +00:00
|
|
|
|
|
|
|
@return the class of the next token read from the buffer
|
|
|
|
*/
|
2015-06-12 08:08:57 +00:00
|
|
|
token_type scan() noexcept
|
2015-02-11 08:10:28 +00:00
|
|
|
{
|
2015-02-11 09:16:43 +00:00
|
|
|
// pointer for backtracking information
|
2015-02-28 01:27:37 +00:00
|
|
|
m_marker = nullptr;
|
2015-02-15 12:35:51 +00:00
|
|
|
|
|
|
|
// remember the begin of the token
|
|
|
|
m_start = m_cursor;
|
|
|
|
|
|
|
|
/*!re2c
|
|
|
|
re2c:define:YYCTYPE = lexer_char_t;
|
|
|
|
re2c:define:YYCURSOR = m_cursor;
|
|
|
|
re2c:define:YYLIMIT = m_limit;
|
|
|
|
re2c:define:YYMARKER = m_marker;
|
2015-05-09 12:54:33 +00:00
|
|
|
re2c:define:YYFILL = "yyfill(); // LCOV_EXCL_LINE";
|
2015-03-01 03:36:57 +00:00
|
|
|
re2c:yyfill:parameter = 0;
|
2015-02-15 12:35:51 +00:00
|
|
|
re2c:indent:string = " ";
|
|
|
|
re2c:indent:top = 1;
|
|
|
|
re2c:labelprefix = "basic_json_parser_";
|
|
|
|
|
|
|
|
// whitespace
|
|
|
|
ws = [ \t\n\r]+;
|
|
|
|
ws { return scan(); }
|
|
|
|
|
|
|
|
// 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; }
|
|
|
|
|
|
|
|
// literal names
|
|
|
|
"null" { return token_type::literal_null; }
|
|
|
|
"true" { return token_type::literal_true; }
|
|
|
|
"false" { return token_type::literal_false; }
|
|
|
|
|
|
|
|
// 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; }
|
|
|
|
|
|
|
|
// string
|
|
|
|
quotation_mark = [\"];
|
|
|
|
escape = [\\];
|
2015-05-09 13:09:52 +00:00
|
|
|
unescaped = [^\"\\\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F];
|
2015-02-15 12:35:51 +00:00
|
|
|
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; }
|
|
|
|
|
|
|
|
// end of file
|
|
|
|
'\000' { return token_type::end_of_input; }
|
|
|
|
|
|
|
|
// anything else is an error
|
|
|
|
. { return token_type::parse_error; }
|
|
|
|
*/
|
2015-02-28 01:19:15 +00:00
|
|
|
|
2015-02-15 12:35:51 +00:00
|
|
|
}
|
|
|
|
|
2015-03-02 20:25:09 +00:00
|
|
|
/// append data from the stream to the internal buffer
|
2015-06-12 08:08:57 +00:00
|
|
|
void yyfill() noexcept
|
2015-03-02 20:25:09 +00:00
|
|
|
{
|
2015-03-24 17:05:58 +00:00
|
|
|
if (not m_stream or not * m_stream)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2015-02-28 01:19:15 +00:00
|
|
|
|
2015-03-24 17:05:58 +00:00
|
|
|
const ssize_t offset_start = m_start - m_content;
|
|
|
|
const ssize_t offset_marker = m_marker - m_start;
|
|
|
|
const ssize_t offset_cursor = m_cursor - m_start;
|
2015-02-28 01:19:15 +00:00
|
|
|
|
2015-03-24 17:05:58 +00:00
|
|
|
m_buffer.erase(0, static_cast<size_t>(offset_start));
|
2015-03-02 20:25:09 +00:00
|
|
|
std::string line;
|
|
|
|
std::getline(*m_stream, line);
|
2015-05-09 11:56:51 +00:00
|
|
|
m_buffer += "\n" + line; // add line with newline symbol
|
2015-02-28 01:19:15 +00:00
|
|
|
|
2015-03-02 20:25:09 +00:00
|
|
|
m_content = reinterpret_cast<const lexer_char_t*>(m_buffer.c_str());
|
|
|
|
m_start = m_content;
|
|
|
|
m_marker = m_start + offset_marker;
|
|
|
|
m_cursor = m_start + offset_cursor;
|
|
|
|
m_limit = m_start + m_buffer.size() - 1;
|
2015-02-15 12:35:51 +00:00
|
|
|
}
|
|
|
|
|
2015-02-15 13:52:00 +00:00
|
|
|
/// return string representation of last read token
|
2015-06-12 08:08:57 +00:00
|
|
|
string_t get_token() const noexcept
|
2015-02-15 12:35:51 +00:00
|
|
|
{
|
2015-02-16 23:22:12 +00:00
|
|
|
return string_t(reinterpret_cast<typename string_t::const_pointer>(m_start),
|
|
|
|
static_cast<size_t>(m_cursor - m_start));
|
2015-02-11 08:10:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
2015-02-15 13:52:00 +00:00
|
|
|
@brief return string value for string tokens
|
|
|
|
|
|
|
|
The function iterates the characters between the opening and closing
|
|
|
|
quotes of the string value. The complete string is the range
|
|
|
|
[m_start,m_cursor). Consequently, we iterate from m_start+1 to
|
|
|
|
m_cursor-1.
|
|
|
|
|
|
|
|
We differentiate two cases:
|
|
|
|
|
|
|
|
1. Escaped characters. In this case, a new character is constructed
|
|
|
|
according to the nature of the escape. Some escapes create new
|
|
|
|
characters (e.g., @c "\\n" is replaced by @c "\n"), some are copied
|
|
|
|
as is (e.g., @c "\\\\"). Furthermore, Unicode escapes of the shape
|
|
|
|
@c "\\uxxxx" need special care. In this case, to_unicode takes care
|
|
|
|
of the construction of the values.
|
|
|
|
2. Unescaped characters are copied as is.
|
2015-02-11 08:10:28 +00:00
|
|
|
|
|
|
|
@return string value of current token without opening and closing quotes
|
2015-02-15 13:52:00 +00:00
|
|
|
@exception std::out_of_range if to_unicode fails
|
2015-02-11 08:10:28 +00:00
|
|
|
*/
|
2015-06-12 08:08:57 +00:00
|
|
|
string_t get_string() const
|
2015-02-11 08:10:28 +00:00
|
|
|
{
|
2015-02-15 12:35:51 +00:00
|
|
|
string_t result;
|
2015-02-15 10:44:49 +00:00
|
|
|
result.reserve(static_cast<size_t>(m_cursor - m_start - 2));
|
|
|
|
|
|
|
|
// iterate the result between the quotes
|
2015-02-16 23:22:12 +00:00
|
|
|
for (const lexer_char_t* i = m_start + 1; i < m_cursor - 1; ++i)
|
2015-02-15 10:44:49 +00:00
|
|
|
{
|
|
|
|
// process escaped characters
|
|
|
|
if (*i == '\\')
|
|
|
|
{
|
|
|
|
// read next character
|
|
|
|
++i;
|
|
|
|
|
|
|
|
switch (*i)
|
|
|
|
{
|
|
|
|
// the default escapes
|
|
|
|
case 't':
|
|
|
|
{
|
|
|
|
result += "\t";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 'b':
|
|
|
|
{
|
|
|
|
result += "\b";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 'f':
|
|
|
|
{
|
|
|
|
result += "\f";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 'n':
|
|
|
|
{
|
|
|
|
result += "\n";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 'r':
|
|
|
|
{
|
|
|
|
result += "\r";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case '\\':
|
|
|
|
{
|
2015-04-24 20:06:57 +00:00
|
|
|
result += "\\";
|
2015-02-15 10:44:49 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case '/':
|
|
|
|
{
|
2015-04-24 20:06:57 +00:00
|
|
|
result += "/";
|
2015-02-15 10:44:49 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case '"':
|
|
|
|
{
|
2015-04-24 20:06:57 +00:00
|
|
|
result += "\"";
|
2015-02-15 10:44:49 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// unicode
|
|
|
|
case 'u':
|
|
|
|
{
|
2015-02-15 15:56:54 +00:00
|
|
|
// get code xxxx from uxxxx
|
2015-02-16 23:22:12 +00:00
|
|
|
auto codepoint = std::strtoul(std::string(reinterpret_cast<typename string_t::const_pointer>(i + 1),
|
|
|
|
4).c_str(), nullptr, 16);
|
2015-02-15 15:56:54 +00:00
|
|
|
|
2015-06-14 21:17:49 +00:00
|
|
|
// check if codepoint is a high surrogate
|
2015-02-15 15:56:54 +00:00
|
|
|
if (codepoint >= 0xD800 and codepoint <= 0xDBFF)
|
|
|
|
{
|
2015-02-15 16:07:19 +00:00
|
|
|
// make sure there is a subsequent unicode
|
2015-02-15 16:40:46 +00:00
|
|
|
if ((i + 6 >= m_limit) or * (i + 5) != '\\' or * (i + 6) != 'u')
|
2015-02-15 16:07:19 +00:00
|
|
|
{
|
|
|
|
throw std::invalid_argument("missing low surrogate");
|
|
|
|
}
|
|
|
|
|
2015-02-15 15:56:54 +00:00
|
|
|
// get code yyyy from uxxxx\uyyyy
|
2015-02-16 23:22:12 +00:00
|
|
|
auto codepoint2 = std::strtoul(std::string(reinterpret_cast<typename string_t::const_pointer>
|
|
|
|
(i + 7), 4).c_str(), nullptr, 16);
|
2015-02-15 15:56:54 +00:00
|
|
|
result += to_unicode(codepoint, codepoint2);
|
|
|
|
// skip the next 11 characters (xxxx\uyyyy)
|
|
|
|
i += 11;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// add unicode character(s)
|
|
|
|
result += to_unicode(codepoint);
|
|
|
|
// skip the next four characters (xxxx)
|
|
|
|
i += 4;
|
|
|
|
}
|
2015-02-15 10:44:49 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// all other characters are just copied to the end of the
|
|
|
|
// string
|
2015-02-16 23:22:12 +00:00
|
|
|
result.append(1, static_cast<typename string_t::value_type>(*i));
|
2015-02-15 10:44:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
2015-02-11 08:10:28 +00:00
|
|
|
}
|
|
|
|
|
2015-02-15 13:52:00 +00:00
|
|
|
/*!
|
|
|
|
@brief return number value for number tokens
|
|
|
|
|
|
|
|
This function translates the last token into a floating point number.
|
|
|
|
The pointer m_begin points to the beginning of the parsed number. We
|
|
|
|
pass this pointer to std::strtod which sets endptr to the first
|
|
|
|
character past the converted number. If this pointer is not the same as
|
|
|
|
m_cursor, then either more or less characters have been used during the
|
|
|
|
comparison. This can happen for inputs like "01" which will be treated
|
|
|
|
like number 0 followed by number 1.
|
|
|
|
|
|
|
|
@return the result of the number conversion or NAN if the conversion
|
|
|
|
read past the current token. The latter case needs to be treated by the
|
|
|
|
caller function.
|
|
|
|
|
|
|
|
@exception std::range_error if passed value is out of range
|
|
|
|
*/
|
2015-06-13 10:42:18 +00:00
|
|
|
long double get_number() const
|
2015-02-11 08:10:28 +00:00
|
|
|
{
|
|
|
|
// conversion
|
2015-02-16 23:22:12 +00:00
|
|
|
typename string_t::value_type* endptr;
|
2015-06-13 10:42:18 +00:00
|
|
|
const auto float_val = std::strtold(reinterpret_cast<typename string_t::const_pointer>(m_start),
|
|
|
|
&endptr);
|
2015-02-11 08:10:28 +00:00
|
|
|
|
2015-02-14 16:34:06 +00:00
|
|
|
// return float_val if the whole number was translated and NAN
|
|
|
|
// otherwise
|
2015-02-16 23:22:12 +00:00
|
|
|
return (reinterpret_cast<lexer_char_t*>(endptr) == m_cursor) ? float_val : NAN;
|
2015-02-11 08:10:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2015-02-28 01:19:15 +00:00
|
|
|
/// optional input stream
|
|
|
|
std::istream* m_stream;
|
2015-02-11 08:41:23 +00:00
|
|
|
/// the buffer
|
2015-02-28 01:19:15 +00:00
|
|
|
string_t m_buffer;
|
|
|
|
/// the buffer pointer
|
2015-02-15 13:52:00 +00:00
|
|
|
const lexer_char_t* m_content = nullptr;
|
2015-02-28 01:19:15 +00:00
|
|
|
/// pointer to the beginning of the current symbol
|
2015-02-15 13:52:00 +00:00
|
|
|
const lexer_char_t* m_start = nullptr;
|
2015-02-28 01:27:37 +00:00
|
|
|
/// pointer for backtracking information
|
|
|
|
const lexer_char_t* m_marker = nullptr;
|
2015-02-11 08:41:23 +00:00
|
|
|
/// pointer to the current symbol
|
2015-02-15 13:52:00 +00:00
|
|
|
const lexer_char_t* m_cursor = nullptr;
|
2015-02-11 08:41:23 +00:00
|
|
|
/// pointer to the end of the buffer
|
2015-02-15 13:52:00 +00:00
|
|
|
const lexer_char_t* m_limit = nullptr;
|
2015-02-11 08:10:28 +00:00
|
|
|
};
|
|
|
|
|
2015-02-22 16:52:27 +00:00
|
|
|
/*!
|
|
|
|
@brief syntax analysis
|
|
|
|
*/
|
2015-02-11 08:10:28 +00:00
|
|
|
class parser
|
|
|
|
{
|
2015-02-05 21:45:21 +00:00
|
|
|
public:
|
|
|
|
/// constructor for strings
|
2015-06-12 08:08:57 +00:00
|
|
|
parser(const string_t& s, parser_callback_t cb = nullptr) : callback(cb), m_lexer(s)
|
2015-02-05 21:45:21 +00:00
|
|
|
{
|
|
|
|
// read first token
|
|
|
|
get_token();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// a parser reading from an input stream
|
2015-06-12 08:08:57 +00:00
|
|
|
parser(std::istream& _is, parser_callback_t cb = nullptr) : callback(cb),
|
2015-05-03 15:52:13 +00:00
|
|
|
m_lexer(&_is)
|
2015-02-05 21:45:21 +00:00
|
|
|
{
|
|
|
|
// read first token
|
|
|
|
get_token();
|
|
|
|
}
|
|
|
|
|
2015-02-11 16:24:14 +00:00
|
|
|
/// public parser interface
|
2015-06-12 08:08:57 +00:00
|
|
|
basic_json parse()
|
2015-02-11 16:24:14 +00:00
|
|
|
{
|
2015-05-03 15:52:13 +00:00
|
|
|
basic_json result = parse_internal(true);
|
2015-02-11 16:24:14 +00:00
|
|
|
|
|
|
|
expect(lexer::token_type::end_of_input);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
/// the actual parser
|
2015-06-12 08:08:57 +00:00
|
|
|
basic_json parse_internal(bool keep)
|
2015-02-05 21:45:21 +00:00
|
|
|
{
|
2015-05-03 15:52:13 +00:00
|
|
|
auto result = basic_json(value_t::discarded);
|
|
|
|
|
2015-02-05 21:45:21 +00:00
|
|
|
switch (last_token)
|
|
|
|
{
|
2015-02-11 08:10:28 +00:00
|
|
|
case (lexer::token_type::begin_object):
|
2015-02-05 21:45:21 +00:00
|
|
|
{
|
2015-05-10 14:09:20 +00:00
|
|
|
if (keep and (not callback or (keep = callback(depth++, parse_event_t::object_start, result))))
|
2015-05-03 15:52:13 +00:00
|
|
|
{
|
|
|
|
// explicitly set result to object to cope with {}
|
2015-05-09 20:49:21 +00:00
|
|
|
result.m_type = value_t::object;
|
|
|
|
result.m_value = json_value(value_t::object);
|
2015-05-03 15:52:13 +00:00
|
|
|
}
|
2015-02-05 21:45:21 +00:00
|
|
|
|
|
|
|
// read next token
|
|
|
|
get_token();
|
|
|
|
|
|
|
|
// closing } -> we are done
|
2015-02-11 08:10:28 +00:00
|
|
|
if (last_token == lexer::token_type::end_object)
|
2015-02-05 21:45:21 +00:00
|
|
|
{
|
2015-02-11 16:24:14 +00:00
|
|
|
get_token();
|
2015-05-10 14:09:20 +00:00
|
|
|
if (keep and callback and not callback(--depth, parse_event_t::object_end, result))
|
2015-05-03 15:52:13 +00:00
|
|
|
{
|
|
|
|
result = basic_json(value_t::discarded);
|
|
|
|
}
|
2015-04-26 19:51:35 +00:00
|
|
|
return result;
|
2015-02-05 21:45:21 +00:00
|
|
|
}
|
|
|
|
|
2015-05-09 11:56:51 +00:00
|
|
|
// no comma is expected here
|
|
|
|
unexpect(lexer::token_type::value_separator);
|
|
|
|
|
2015-02-05 21:45:21 +00:00
|
|
|
// otherwise: parse key-value pairs
|
|
|
|
do
|
|
|
|
{
|
2015-02-11 16:24:14 +00:00
|
|
|
// ugly, but could be fixed with loop reorganization
|
|
|
|
if (last_token == lexer::token_type::value_separator)
|
|
|
|
{
|
|
|
|
get_token();
|
|
|
|
}
|
|
|
|
|
2015-02-05 21:45:21 +00:00
|
|
|
// store key
|
2015-02-11 08:10:28 +00:00
|
|
|
expect(lexer::token_type::value_string);
|
|
|
|
const auto key = m_lexer.get_string();
|
2015-02-05 21:45:21 +00:00
|
|
|
|
2015-05-03 15:52:13 +00:00
|
|
|
bool keep_tag = false;
|
|
|
|
if (keep)
|
|
|
|
{
|
2015-05-10 15:12:36 +00:00
|
|
|
keep_tag = callback ? callback(depth, parse_event_t::key, basic_json(key)) : true;
|
2015-05-03 15:52:13 +00:00
|
|
|
}
|
|
|
|
|
2015-02-05 21:45:21 +00:00
|
|
|
// parse separator (:)
|
|
|
|
get_token();
|
2015-02-11 08:10:28 +00:00
|
|
|
expect(lexer::token_type::name_separator);
|
2015-02-05 21:45:21 +00:00
|
|
|
|
2015-04-26 13:10:04 +00:00
|
|
|
// parse and add value
|
2015-02-05 21:45:21 +00:00
|
|
|
get_token();
|
2015-05-03 15:52:13 +00:00
|
|
|
auto value = parse_internal(keep);
|
|
|
|
if (keep and keep_tag and not value.is_discarded())
|
|
|
|
{
|
2015-05-04 13:08:55 +00:00
|
|
|
result[key] = std::move(value);
|
2015-05-03 15:52:13 +00:00
|
|
|
}
|
2015-02-05 21:45:21 +00:00
|
|
|
}
|
2015-02-11 16:24:14 +00:00
|
|
|
while (last_token == lexer::token_type::value_separator);
|
2015-02-05 21:45:21 +00:00
|
|
|
|
|
|
|
// closing }
|
2015-02-11 08:10:28 +00:00
|
|
|
expect(lexer::token_type::end_object);
|
2015-04-26 19:43:47 +00:00
|
|
|
get_token();
|
2015-05-10 14:09:20 +00:00
|
|
|
if (keep and callback and not callback(--depth, parse_event_t::object_end, result))
|
2015-05-03 15:52:13 +00:00
|
|
|
{
|
|
|
|
result = basic_json(value_t::discarded);
|
|
|
|
}
|
2015-04-26 19:51:35 +00:00
|
|
|
|
|
|
|
return result;
|
2015-02-05 21:45:21 +00:00
|
|
|
}
|
|
|
|
|
2015-02-11 08:10:28 +00:00
|
|
|
case (lexer::token_type::begin_array):
|
2015-02-05 21:45:21 +00:00
|
|
|
{
|
2015-05-10 14:09:20 +00:00
|
|
|
if (keep and (not callback or (keep = callback(depth++, parse_event_t::array_start, result))))
|
2015-05-03 15:52:13 +00:00
|
|
|
{
|
|
|
|
// explicitly set result to object to cope with []
|
2015-05-09 20:49:21 +00:00
|
|
|
result.m_type = value_t::array;
|
|
|
|
result.m_value = json_value(value_t::array);
|
2015-05-03 15:52:13 +00:00
|
|
|
}
|
2015-02-05 21:45:21 +00:00
|
|
|
|
|
|
|
// read next token
|
|
|
|
get_token();
|
|
|
|
|
|
|
|
// closing ] -> we are done
|
2015-02-11 08:10:28 +00:00
|
|
|
if (last_token == lexer::token_type::end_array)
|
2015-02-05 21:45:21 +00:00
|
|
|
{
|
2015-02-11 16:24:14 +00:00
|
|
|
get_token();
|
2015-05-10 14:09:20 +00:00
|
|
|
if (callback and not callback(--depth, parse_event_t::array_end, result))
|
2015-05-03 15:52:13 +00:00
|
|
|
{
|
|
|
|
result = basic_json(value_t::discarded);
|
|
|
|
}
|
2015-04-26 19:51:35 +00:00
|
|
|
return result;
|
2015-02-05 21:45:21 +00:00
|
|
|
}
|
|
|
|
|
2015-05-09 11:56:51 +00:00
|
|
|
// no comma is expected here
|
|
|
|
unexpect(lexer::token_type::value_separator);
|
|
|
|
|
2015-02-05 21:45:21 +00:00
|
|
|
// otherwise: parse values
|
|
|
|
do
|
|
|
|
{
|
2015-02-11 16:24:14 +00:00
|
|
|
// ugly, but could be fixed with loop reorganization
|
|
|
|
if (last_token == lexer::token_type::value_separator)
|
|
|
|
{
|
|
|
|
get_token();
|
|
|
|
}
|
2015-02-05 21:45:21 +00:00
|
|
|
|
2015-05-03 15:52:13 +00:00
|
|
|
// parse value
|
|
|
|
auto value = parse_internal(keep);
|
|
|
|
if (keep and not value.is_discarded())
|
|
|
|
{
|
2015-05-04 13:08:55 +00:00
|
|
|
result.push_back(std::move(value));
|
2015-05-03 15:52:13 +00:00
|
|
|
}
|
2015-02-05 21:45:21 +00:00
|
|
|
}
|
2015-02-11 16:24:14 +00:00
|
|
|
while (last_token == lexer::token_type::value_separator);
|
2015-02-05 21:45:21 +00:00
|
|
|
|
|
|
|
// closing ]
|
2015-02-11 08:10:28 +00:00
|
|
|
expect(lexer::token_type::end_array);
|
2015-04-26 19:43:47 +00:00
|
|
|
get_token();
|
2015-05-10 14:09:20 +00:00
|
|
|
if (keep and callback and not callback(--depth, parse_event_t::array_end, result))
|
2015-05-03 15:52:13 +00:00
|
|
|
{
|
|
|
|
result = basic_json(value_t::discarded);
|
|
|
|
}
|
2015-04-26 19:51:35 +00:00
|
|
|
|
|
|
|
return result;
|
2015-02-05 21:45:21 +00:00
|
|
|
}
|
|
|
|
|
2015-02-11 08:10:28 +00:00
|
|
|
case (lexer::token_type::literal_null):
|
2015-02-05 21:45:21 +00:00
|
|
|
{
|
2015-02-11 16:24:14 +00:00
|
|
|
get_token();
|
2015-05-09 20:49:21 +00:00
|
|
|
result.m_type = value_t::null;
|
2015-05-03 15:52:13 +00:00
|
|
|
break;
|
2015-02-05 21:45:21 +00:00
|
|
|
}
|
|
|
|
|
2015-02-11 08:10:28 +00:00
|
|
|
case (lexer::token_type::value_string):
|
2015-02-05 21:45:21 +00:00
|
|
|
{
|
2015-04-26 19:51:35 +00:00
|
|
|
const auto s = m_lexer.get_string();
|
2015-02-11 16:24:14 +00:00
|
|
|
get_token();
|
2015-05-03 15:52:13 +00:00
|
|
|
result = basic_json(s);
|
|
|
|
break;
|
2015-02-05 21:45:21 +00:00
|
|
|
}
|
|
|
|
|
2015-02-11 08:10:28 +00:00
|
|
|
case (lexer::token_type::literal_true):
|
2015-02-05 21:45:21 +00:00
|
|
|
{
|
2015-02-11 16:24:14 +00:00
|
|
|
get_token();
|
2015-05-09 20:49:21 +00:00
|
|
|
result.m_type = value_t::boolean;
|
|
|
|
result.m_value = true;
|
2015-05-03 15:52:13 +00:00
|
|
|
break;
|
2015-02-05 21:45:21 +00:00
|
|
|
}
|
|
|
|
|
2015-02-11 08:10:28 +00:00
|
|
|
case (lexer::token_type::literal_false):
|
2015-02-05 21:45:21 +00:00
|
|
|
{
|
2015-02-11 16:24:14 +00:00
|
|
|
get_token();
|
2015-05-09 20:49:21 +00:00
|
|
|
result.m_type = value_t::boolean;
|
|
|
|
result.m_value = false;
|
2015-05-03 15:52:13 +00:00
|
|
|
break;
|
2015-02-05 21:45:21 +00:00
|
|
|
}
|
|
|
|
|
2015-02-11 08:10:28 +00:00
|
|
|
case (lexer::token_type::value_number):
|
2015-02-05 21:45:21 +00:00
|
|
|
{
|
2015-02-11 08:10:28 +00:00
|
|
|
auto float_val = m_lexer.get_number();
|
2015-02-05 21:45:21 +00:00
|
|
|
|
2015-02-14 16:34:06 +00:00
|
|
|
// NAN is returned if token could not be translated
|
|
|
|
// completely
|
2015-02-11 08:10:28 +00:00
|
|
|
if (std::isnan(float_val))
|
2015-02-05 21:45:21 +00:00
|
|
|
{
|
|
|
|
throw std::invalid_argument(std::string("parse error - ") +
|
2015-02-14 16:34:06 +00:00
|
|
|
m_lexer.get_token() + " is not a number");
|
2015-02-05 21:45:21 +00:00
|
|
|
}
|
|
|
|
|
2015-04-26 19:51:35 +00:00
|
|
|
get_token();
|
|
|
|
|
2015-02-05 21:45:21 +00:00
|
|
|
// check if conversion loses precision
|
2015-02-11 08:10:28 +00:00
|
|
|
const auto int_val = static_cast<number_integer_t>(float_val);
|
2015-06-13 10:42:18 +00:00
|
|
|
if (approx(float_val, static_cast<long double>(int_val)))
|
2015-02-05 21:45:21 +00:00
|
|
|
{
|
|
|
|
// we basic_json not lose precision -> return int
|
2015-05-09 20:49:21 +00:00
|
|
|
result.m_type = value_t::number_integer;
|
|
|
|
result.m_value = int_val;
|
2015-02-05 21:45:21 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// we would lose precision -> returnfloat
|
2015-05-09 20:49:21 +00:00
|
|
|
result.m_type = value_t::number_float;
|
2015-06-13 10:42:18 +00:00
|
|
|
result.m_value = static_cast<number_float_t>(float_val);
|
2015-02-05 21:45:21 +00:00
|
|
|
}
|
2015-05-03 15:52:13 +00:00
|
|
|
break;
|
2015-02-05 21:45:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
{
|
2015-05-09 11:56:51 +00:00
|
|
|
// the last token was unexpected
|
|
|
|
unexpect(last_token);
|
2015-02-05 21:45:21 +00:00
|
|
|
}
|
|
|
|
}
|
2015-05-03 15:52:13 +00:00
|
|
|
|
2015-05-10 14:09:20 +00:00
|
|
|
if (keep and callback and not callback(depth, parse_event_t::value, result))
|
2015-05-03 15:52:13 +00:00
|
|
|
{
|
|
|
|
result = basic_json(value_t::discarded);
|
|
|
|
}
|
|
|
|
return result;
|
2015-02-05 21:45:21 +00:00
|
|
|
}
|
|
|
|
|
2015-02-11 08:10:28 +00:00
|
|
|
/// get next token from lexer
|
2015-06-12 08:08:57 +00:00
|
|
|
typename lexer::token_type get_token()
|
2015-02-05 21:45:21 +00:00
|
|
|
{
|
2015-02-11 08:10:28 +00:00
|
|
|
last_token = m_lexer.scan();
|
|
|
|
return last_token;
|
2015-02-05 21:45:21 +00:00
|
|
|
}
|
|
|
|
|
2015-06-12 08:08:57 +00:00
|
|
|
void expect(typename lexer::token_type t) const
|
2015-02-05 21:45:21 +00:00
|
|
|
{
|
|
|
|
if (t != last_token)
|
|
|
|
{
|
|
|
|
std::string error_msg = "parse error - unexpected \'";
|
2015-02-14 16:34:06 +00:00
|
|
|
error_msg += m_lexer.get_token();
|
2015-02-11 09:16:43 +00:00
|
|
|
error_msg += "\' (" + lexer::token_type_name(last_token);
|
|
|
|
error_msg += "); expected " + lexer::token_type_name(t);
|
2015-02-05 21:45:21 +00:00
|
|
|
throw std::invalid_argument(error_msg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-12 08:08:57 +00:00
|
|
|
void unexpect(typename lexer::token_type t) const
|
2015-05-09 11:56:51 +00:00
|
|
|
{
|
|
|
|
if (t == last_token)
|
|
|
|
{
|
|
|
|
std::string error_msg = "parse error - unexpected \'";
|
|
|
|
error_msg += m_lexer.get_token();
|
|
|
|
error_msg += "\' (";
|
|
|
|
error_msg += lexer::token_type_name(last_token) + ")";
|
|
|
|
throw std::invalid_argument(error_msg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-08 11:53:10 +00:00
|
|
|
private:
|
2015-05-03 15:52:13 +00:00
|
|
|
/// levels of recursion
|
|
|
|
int depth = 0;
|
|
|
|
/// callback function
|
|
|
|
parser_callback_t callback;
|
2015-02-05 21:45:21 +00:00
|
|
|
/// the type of the last read token
|
2015-02-11 08:10:28 +00:00
|
|
|
typename lexer::token_type last_token = lexer::token_type::uninitialized;
|
2015-02-14 16:34:06 +00:00
|
|
|
/// the lexer
|
2015-02-11 08:10:28 +00:00
|
|
|
lexer m_lexer;
|
2015-02-05 21:45:21 +00:00
|
|
|
};
|
2015-01-31 19:13:11 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/////////////
|
|
|
|
// presets //
|
|
|
|
/////////////
|
|
|
|
|
2015-06-20 22:59:33 +00:00
|
|
|
/*!
|
|
|
|
@brief default JSON class
|
|
|
|
|
|
|
|
This type is the default specialization of the @ref basic_json class which uses
|
|
|
|
the standard template types.
|
|
|
|
*/
|
2015-01-31 19:13:11 +00:00
|
|
|
using json = basic_json<>;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/////////////////////////
|
|
|
|
// nonmember functions //
|
|
|
|
/////////////////////////
|
|
|
|
|
|
|
|
// specialization of std::swap, and std::hash
|
|
|
|
namespace std
|
|
|
|
{
|
2015-02-22 16:52:27 +00:00
|
|
|
/*!
|
|
|
|
@brief exchanges the values of two JSON objects
|
|
|
|
@ingroup container
|
|
|
|
*/
|
2015-01-31 19:13:11 +00:00
|
|
|
template <>
|
|
|
|
inline void swap(nlohmann::json& j1,
|
|
|
|
nlohmann::json& j2) noexcept(
|
|
|
|
is_nothrow_move_constructible<nlohmann::json>::value and
|
|
|
|
is_nothrow_move_assignable<nlohmann::json>::value
|
|
|
|
)
|
|
|
|
{
|
|
|
|
j1.swap(j2);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// hash value for JSON objects
|
|
|
|
template <>
|
|
|
|
struct hash<nlohmann::json>
|
|
|
|
{
|
2015-02-07 14:57:47 +00:00
|
|
|
/// return a hash value for a JSON object
|
2015-06-12 08:08:57 +00:00
|
|
|
std::size_t operator()(const nlohmann::json& j) const
|
2015-01-31 19:13:11 +00:00
|
|
|
{
|
|
|
|
// a naive hashing via the string representation
|
2015-02-16 22:17:28 +00:00
|
|
|
const auto& h = hash<nlohmann::json::string_t>();
|
|
|
|
return h(j.dump());
|
2015-01-31 19:13:11 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2015-02-05 21:45:21 +00:00
|
|
|
/*!
|
|
|
|
This operator implements a user-defined string literal for JSON objects. It can
|
|
|
|
be used by adding \p "_json" to a string literal and returns a JSON object if
|
|
|
|
no parse error occurred.
|
|
|
|
|
|
|
|
@param s a string representation of a JSON object
|
|
|
|
@return a JSON object
|
|
|
|
*/
|
2015-02-07 18:14:23 +00:00
|
|
|
inline nlohmann::json operator "" _json(const char* s, std::size_t)
|
2015-02-05 21:45:21 +00:00
|
|
|
{
|
2015-02-16 22:17:28 +00:00
|
|
|
return nlohmann::json::parse(reinterpret_cast<nlohmann::json::string_t::value_type*>
|
|
|
|
(const_cast<char*>(s)));
|
2015-02-05 21:45:21 +00:00
|
|
|
}
|
|
|
|
|
2015-01-31 19:13:11 +00:00
|
|
|
#endif
|