Permalink
Fetching contributors…
Cannot retrieve contributors at this time
10592 lines (8748 sloc) 347 KB
/*
__ _____ _____ _____
__| | __| | | | JSON for Modern C++
| | |__ | | | | | | version 2.0.3
|_____|_____|_____|_|___| https://github.com/nlohmann/json
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
Copyright (c) 2013-2016 Niels Lohmann <http://nlohmann.me>.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef NLOHMANN_JSON_HPP
#define NLOHMANN_JSON_HPP
#include <algorithm>
#include <array>
#include <cassert>
#include <ciso646>
#include <cmath>
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <functional>
#include <initializer_list>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <limits>
#include <locale>
#include <map>
#include <memory>
#include <numeric>
#include <sstream>
#include <stdexcept>
#include <string>
#include <type_traits>
#include <utility>
#include <vector>
// exclude unsupported compilers
#if defined(__clang__)
#define CLANG_VERSION (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__)
#if CLANG_VERSION < 30400
#error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers"
#endif
#elif defined(__GNUC__)
#define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
#if GCC_VERSION < 40800
#error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers"
#endif
#endif
// disable float-equal warnings on GCC/clang
#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal"
#endif
// allow for portable deprecation warnings
#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
#define JSON_DEPRECATED __attribute__((deprecated))
#elif defined(_MSC_VER)
#define JSON_DEPRECATED __declspec(deprecated)
#else
#define JSON_DEPRECATED
#endif
/*!
@brief namespace for Niels Lohmann
@see https://github.com/nlohmann
@since version 1.0.0
*/
namespace nlohmann
{
/*!
@brief unnamed namespace with internal helper functions
@since version 1.0.0
*/
namespace
{
/*!
@brief Helper to determine whether there's a key_type for T.
Thus helper is used to tell associative containers apart from other containers
such as sequence containers. For instance, `std::map` passes the test as it
contains a `mapped_type`, whereas `std::vector` fails the test.
@sa http://stackoverflow.com/a/7728728/266378
@since version 1.0.0
*/
template<typename T>
struct has_mapped_type
{
private:
template<typename C> static char test(typename C::mapped_type*);
template<typename C> static char (&test(...))[2];
public:
static constexpr bool value = sizeof(test<T>(0)) == 1;
};
/*!
@brief helper class to create locales with decimal point
This struct is used a default locale during the JSON serialization. JSON
requires the decimal point to be `.`, so this function overloads the
`do_decimal_point()` function to return `.`. This function is called by
float-to-string conversions to retrieve the decimal separator between integer
and fractional parts.
@sa https://github.com/nlohmann/json/issues/51#issuecomment-86869315
@since version 2.0.0
*/
struct DecimalSeparator : std::numpunct<char>
{
char do_decimal_point() const
{
return '.';
}
};
}
/*!
@brief a class to store JSON values
@tparam ObjectType type for JSON objects (`std::map` by default; will be used
in @ref object_t)
@tparam ArrayType type for JSON arrays (`std::vector` by default; will be used
in @ref array_t)
@tparam StringType type for JSON strings and object keys (`std::string` by
default; will be used in @ref string_t)
@tparam BooleanType type for JSON booleans (`bool` by default; will be used
in @ref boolean_t)
@tparam NumberIntegerType type for JSON integer numbers (`int64_t` by
default; will be used in @ref number_integer_t)
@tparam NumberUnsignedType type for JSON unsigned integer numbers (@c
`uint64_t` by default; will be used in @ref number_unsigned_t)
@tparam NumberFloatType type for JSON floating-point numbers (`double` by
default; will be used in @ref number_float_t)
@tparam AllocatorType type of the allocator to use (`std::allocator` by
default)
@requirement The class satisfies the following concept requirements:
- Basic
- [DefaultConstructible](http://en.cppreference.com/w/cpp/concept/DefaultConstructible):
JSON values can be default constructed. The result will be a JSON null value.
- [MoveConstructible](http://en.cppreference.com/w/cpp/concept/MoveConstructible):
A JSON value can be constructed from an rvalue argument.
- [CopyConstructible](http://en.cppreference.com/w/cpp/concept/CopyConstructible):
A JSON value can be copy-constructed from an lvalue expression.
- [MoveAssignable](http://en.cppreference.com/w/cpp/concept/MoveAssignable):
A JSON value van be assigned from an rvalue argument.
- [CopyAssignable](http://en.cppreference.com/w/cpp/concept/CopyAssignable):
A JSON value can be copy-assigned from an lvalue expression.
- [Destructible](http://en.cppreference.com/w/cpp/concept/Destructible):
JSON values can be destructed.
- Layout
- [StandardLayoutType](http://en.cppreference.com/w/cpp/concept/StandardLayoutType):
JSON values have
[standard layout](http://en.cppreference.com/w/cpp/language/data_members#Standard_layout):
All non-static data members are private and standard layout types, the class
has no virtual functions or (virtual) base classes.
- Library-wide
- [EqualityComparable](http://en.cppreference.com/w/cpp/concept/EqualityComparable):
JSON values can be compared with `==`, see @ref
operator==(const_reference,const_reference).
- [LessThanComparable](http://en.cppreference.com/w/cpp/concept/LessThanComparable):
JSON values can be compared with `<`, see @ref
operator<(const_reference,const_reference).
- [Swappable](http://en.cppreference.com/w/cpp/concept/Swappable):
Any JSON lvalue or rvalue of can be swapped with any lvalue or rvalue of
other compatible types, using unqualified function call @ref swap().
- [NullablePointer](http://en.cppreference.com/w/cpp/concept/NullablePointer):
JSON values can be compared against `std::nullptr_t` objects which are used
to model the `null` value.
- Container
- [Container](http://en.cppreference.com/w/cpp/concept/Container):
JSON values can be used like STL containers and provide iterator access.
- [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer);
JSON values can be used like STL containers and provide reverse iterator
access.
@invariant The member variables @a m_value and @a m_type have the following
relationship:
- If `m_type == value_t::object`, then `m_value.object != nullptr`.
- If `m_type == value_t::array`, then `m_value.array != nullptr`.
- If `m_type == value_t::string`, then `m_value.string != nullptr`.
The invariants are checked by member function assert_invariant().
@internal
@note ObjectType trick from http://stackoverflow.com/a/9860911
@endinternal
@see [RFC 7159: The JavaScript Object Notation (JSON) Data Interchange
Format](http://rfc7159.net/rfc7159)
@since version 1.0.0
@nosubgrouping
*/
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 = std::int64_t,
class NumberUnsignedType = std::uint64_t,
class NumberFloatType = double,
template<typename U> class AllocatorType = std::allocator
>
class basic_json
{
private:
/// workaround type for MSVC
using basic_json_t = basic_json<ObjectType, ArrayType, StringType,
BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType,
AllocatorType>;
public:
// forward declarations
template<typename Base> class json_reverse_iterator;
class json_pointer;
/////////////////////
// container types //
/////////////////////
/// @name container types
/// The canonic container types to use @ref basic_json like any other STL
/// container.
/// @{
/// the type of elements in a basic_json container
using value_type = basic_json;
/// the type of an element reference
using reference = value_type&;
/// the type of an element const reference
using const_reference = const value_type&;
/// a type to represent differences between iterators
using difference_type = std::ptrdiff_t;
/// a type to represent container sizes
using size_type = std::size_t;
/// the allocator type
using allocator_type = AllocatorType<basic_json>;
/// the type of an element pointer
using pointer = typename std::allocator_traits<allocator_type>::pointer;
/// the type of an element const pointer
using const_pointer = typename std::allocator_traits<allocator_type>::const_pointer;
/// 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
using reverse_iterator = json_reverse_iterator<typename basic_json::iterator>;
/// a const reverse iterator for a basic_json container
using const_reverse_iterator = json_reverse_iterator<typename basic_json::const_iterator>;
/// @}
/*!
@brief returns the allocator associated with the container
*/
static allocator_type get_allocator()
{
return allocator_type();
}
///////////////////////////
// JSON value data types //
///////////////////////////
/// @name JSON value data types
/// The data types to store a JSON value. These types are derived from
/// the template arguments passed to class @ref basic_json.
/// @{
/*!
@brief a type for an object
[RFC 7159](http://rfc7159.net/rfc7159) describes JSON objects as follows:
> An object is an unordered collection of zero or more name/value pairs,
> where a name is a string and a value is a string, number, boolean, null,
> object, or array.
To store objects in C++, a type is defined by the template parameters
described below.
@tparam ObjectType the container to store objects (e.g., `std::map` or
`std::unordered_map`)
@tparam StringType the type of the keys or names (e.g., `std::string`).
The comparison function `std::less<StringType>` is used to order elements
inside the container.
@tparam AllocatorType the allocator to use for objects (e.g.,
`std::allocator`)
#### Default type
With the default values for @a ObjectType (`std::map`), @a StringType
(`std::string`), and @a AllocatorType (`std::allocator`), the default
value for @a object_t is:
@code {.cpp}
std::map<
std::string, // key_type
basic_json, // value_type
std::less<std::string>, // key_compare
std::allocator<std::pair<const std::string, basic_json>> // allocator_type
>
@endcode
#### Behavior
The choice of @a object_t influences the behavior of the JSON class. With
the default type, objects have the following behavior:
- When all names are unique, objects will be interoperable in the sense
that all software implementations receiving that object will agree on
the name-value mappings.
- When the names within an object are not unique, later stored name/value
pairs overwrite previously stored name/value pairs, leaving the used
names unique. For instance, `{"key": 1}` and `{"key": 2, "key": 1}` will
be treated as equal and both stored as `{"key": 1}`.
- Internally, name/value pairs are stored in lexicographical order of the
names. Objects will also be serialized (see @ref dump) in this order.
For instance, `{"b": 1, "a": 2}` and `{"a": 2, "b": 1}` will be stored
and serialized as `{"a": 2, "b": 1}`.
- When comparing objects, the order of the name/value pairs is irrelevant.
This makes objects interoperable in the sense that they will not be
affected by these differences. For instance, `{"b": 1, "a": 2}` and
`{"a": 2, "b": 1}` will be treated as equal.
#### Limits
[RFC 7159](http://rfc7159.net/rfc7159) specifies:
> An implementation may set limits on the maximum depth of nesting.
In this class, the object's limit of nesting is not constraint explicitly.
However, a maximum depth of nesting may be introduced by the compiler or
runtime environment. A theoretical limit can be queried by calling the
@ref max_size function of a JSON object.
#### Storage
Objects are stored as pointers in a @ref basic_json type. That is, for any
access to object values, a pointer of type `object_t*` must be
dereferenced.
@sa @ref array_t -- type for an array value
@since version 1.0.0
@note The order name/value pairs are added to the object is *not*
preserved by the library. Therefore, iterating an object may return
name/value pairs in a different order than they were originally stored. In
fact, keys will be traversed in alphabetical order as `std::map` with
`std::less` is used by default. Please note this behavior conforms to [RFC
7159](http://rfc7159.net/rfc7159), because any order implements the
specified "unordered" nature of JSON objects.
*/
using object_t = ObjectType<StringType,
basic_json,
std::less<StringType>,
AllocatorType<std::pair<const StringType,
basic_json>>>;
/*!
@brief a type for an array
[RFC 7159](http://rfc7159.net/rfc7159) describes JSON arrays as follows:
> An array is an ordered sequence of zero or more values.
To store objects in C++, a type is defined by the template parameters
explained below.
@tparam ArrayType container type to store arrays (e.g., `std::vector` or
`std::list`)
@tparam AllocatorType allocator to use for arrays (e.g., `std::allocator`)
#### Default type
With the default values for @a ArrayType (`std::vector`) and @a
AllocatorType (`std::allocator`), the default value for @a array_t is:
@code {.cpp}
std::vector<
basic_json, // value_type
std::allocator<basic_json> // allocator_type
>
@endcode
#### Limits
[RFC 7159](http://rfc7159.net/rfc7159) specifies:
> An implementation may set limits on the maximum depth of nesting.
In this class, the array's limit of nesting is not constraint explicitly.
However, a maximum depth of nesting may be introduced by the compiler or
runtime environment. A theoretical limit can be queried by calling the
@ref max_size function of a JSON array.
#### Storage
Arrays are stored as pointers in a @ref basic_json type. That is, for any
access to array values, a pointer of type `array_t*` must be dereferenced.
@sa @ref object_t -- type for an object value
@since version 1.0.0
*/
using array_t = ArrayType<basic_json, AllocatorType<basic_json>>;
/*!
@brief a type for a string
[RFC 7159](http://rfc7159.net/rfc7159) describes JSON strings as follows:
> A string is a sequence of zero or more Unicode characters.
To store objects in C++, a type is defined by the template parameter
described below. Unicode values are split by the JSON class into
byte-sized characters during deserialization.
@tparam StringType the container to store strings (e.g., `std::string`).
Note this container is used for keys/names in objects, see @ref object_t.
#### Default type
With the default values for @a StringType (`std::string`), the default
value for @a string_t is:
@code {.cpp}
std::string
@endcode
#### String comparison
[RFC 7159](http://rfc7159.net/rfc7159) states:
> Software implementations are typically required to test names of object
> members for equality. Implementations that transform the textual
> representation into sequences of Unicode code units and then perform the
> comparison numerically, code unit by code unit, are interoperable in the
> sense that implementations will agree in all cases on equality or
> inequality of two strings. For example, implementations that compare
> strings with escaped characters unconverted may incorrectly find that
> `"a\\b"` and `"a\u005Cb"` are not equal.
This implementation is interoperable as it does compare strings code unit
by code unit.
#### Storage
String values are stored as pointers in a @ref basic_json type. That is,
for any access to string values, a pointer of type `string_t*` must be
dereferenced.
@since version 1.0.0
*/
using string_t = StringType;
/*!
@brief a type for a boolean
[RFC 7159](http://rfc7159.net/rfc7159) implicitly describes a boolean as a
type which differentiates the two literals `true` and `false`.
To store objects in C++, a type is defined by the template parameter @a
BooleanType which chooses the type to use.
#### Default type
With the default values for @a BooleanType (`bool`), the default value for
@a boolean_t is:
@code {.cpp}
bool
@endcode
#### Storage
Boolean values are stored directly inside a @ref basic_json type.
@since version 1.0.0
*/
using boolean_t = BooleanType;
/*!
@brief a type for a number (integer)
[RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows:
> The representation of numbers is similar to that used in most
> programming languages. A number is represented in base 10 using decimal
> digits. It contains an integer component that may be prefixed with an
> optional minus sign, which may be followed by a fraction part and/or an
> exponent part. Leading zeros are not allowed. (...) Numeric values that
> cannot be represented in the grammar below (such as Infinity and NaN)
> are not permitted.
This description includes both integer and floating-point numbers.
However, C++ allows more precise storage if it is known whether the number
is a signed integer, an unsigned integer or a floating-point number.
Therefore, three different types, @ref number_integer_t, @ref
number_unsigned_t and @ref number_float_t are used.
To store integer numbers in C++, a type is defined by the template
parameter @a NumberIntegerType which chooses the type to use.
#### Default type
With the default values for @a NumberIntegerType (`int64_t`), the default
value for @a number_integer_t is:
@code {.cpp}
int64_t
@endcode
#### Default behavior
- The restrictions about leading zeros is not enforced in C++. Instead,
leading zeros in integer literals lead to an interpretation as octal
number. Internally, the value will be stored as decimal number. For
instance, the C++ integer literal `010` will be serialized to `8`.
During deserialization, leading zeros yield an error.
- Not-a-number (NaN) values will be serialized to `null`.
#### Limits
[RFC 7159](http://rfc7159.net/rfc7159) specifies:
> An implementation may set limits on the range and precision of numbers.
When the default type is used, the maximal integer number that can be
stored is `9223372036854775807` (INT64_MAX) and the minimal integer number
that can be stored is `-9223372036854775808` (INT64_MIN). Integer numbers
that are out of range will yield over/underflow when used in a
constructor. During deserialization, too large or small integer numbers
will be automatically be stored as @ref number_unsigned_t or @ref
number_float_t.
[RFC 7159](http://rfc7159.net/rfc7159) further states:
> Note that when such software is used, numbers that are integers and are
> in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense
> that implementations will agree exactly on their numeric values.
As this range is a subrange of the exactly supported range [INT64_MIN,
INT64_MAX], this class's integer type is interoperable.
#### Storage
Integer number values are stored directly inside a @ref basic_json type.
@sa @ref number_float_t -- type for number values (floating-point)
@sa @ref number_unsigned_t -- type for number values (unsigned integer)
@since version 1.0.0
*/
using number_integer_t = NumberIntegerType;
/*!
@brief a type for a number (unsigned)
[RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows:
> The representation of numbers is similar to that used in most
> programming languages. A number is represented in base 10 using decimal
> digits. It contains an integer component that may be prefixed with an
> optional minus sign, which may be followed by a fraction part and/or an
> exponent part. Leading zeros are not allowed. (...) Numeric values that
> cannot be represented in the grammar below (such as Infinity and NaN)
> are not permitted.
This description includes both integer and floating-point numbers.
However, C++ allows more precise storage if it is known whether the number
is a signed integer, an unsigned integer or a floating-point number.
Therefore, three different types, @ref number_integer_t, @ref
number_unsigned_t and @ref number_float_t are used.
To store unsigned integer numbers in C++, a type is defined by the
template parameter @a NumberUnsignedType which chooses the type to use.
#### Default type
With the default values for @a NumberUnsignedType (`uint64_t`), the
default value for @a number_unsigned_t is:
@code {.cpp}
uint64_t
@endcode
#### Default behavior
- The restrictions about leading zeros is not enforced in C++. Instead,
leading zeros in integer literals lead to an interpretation as octal
number. Internally, the value will be stored as decimal number. For
instance, the C++ integer literal `010` will be serialized to `8`.
During deserialization, leading zeros yield an error.
- Not-a-number (NaN) values will be serialized to `null`.
#### Limits
[RFC 7159](http://rfc7159.net/rfc7159) specifies:
> An implementation may set limits on the range and precision of numbers.
When the default type is used, the maximal integer number that can be
stored is `18446744073709551615` (UINT64_MAX) and the minimal integer
number that can be stored is `0`. Integer numbers that are out of range
will yield over/underflow when used in a constructor. During
deserialization, too large or small integer numbers will be automatically
be stored as @ref number_integer_t or @ref number_float_t.
[RFC 7159](http://rfc7159.net/rfc7159) further states:
> Note that when such software is used, numbers that are integers and are
> in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense
> that implementations will agree exactly on their numeric values.
As this range is a subrange (when considered in conjunction with the
number_integer_t type) of the exactly supported range [0, UINT64_MAX],
this class's integer type is interoperable.
#### Storage
Integer number values are stored directly inside a @ref basic_json type.
@sa @ref number_float_t -- type for number values (floating-point)
@sa @ref number_integer_t -- type for number values (integer)
@since version 2.0.0
*/
using number_unsigned_t = NumberUnsignedType;
/*!
@brief a type for a number (floating-point)
[RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows:
> The representation of numbers is similar to that used in most
> programming languages. A number is represented in base 10 using decimal
> digits. It contains an integer component that may be prefixed with an
> optional minus sign, which may be followed by a fraction part and/or an
> exponent part. Leading zeros are not allowed. (...) Numeric values that
> cannot be represented in the grammar below (such as Infinity and NaN)
> are not permitted.
This description includes both integer and floating-point numbers.
However, C++ allows more precise storage if it is known whether the number
is a signed integer, an unsigned integer or a floating-point number.
Therefore, three different types, @ref number_integer_t, @ref
number_unsigned_t and @ref number_float_t are used.
To store floating-point numbers in C++, a type is defined by the template
parameter @a NumberFloatType which chooses the type to use.
#### Default type
With the default values for @a NumberFloatType (`double`), the default
value for @a number_float_t is:
@code {.cpp}
double
@endcode
#### Default behavior
- The restrictions about leading zeros is not enforced in C++. Instead,
leading zeros in floating-point literals will be ignored. Internally,
the value will be stored as decimal number. For instance, the C++
floating-point literal `01.2` will be serialized to `1.2`. During
deserialization, leading zeros yield an error.
- Not-a-number (NaN) values will be serialized to `null`.
#### Limits
[RFC 7159](http://rfc7159.net/rfc7159) states:
> This specification allows implementations to set limits on the range and
> precision of numbers accepted. Since software that implements IEEE
> 754-2008 binary64 (double precision) numbers is generally available and
> widely used, good interoperability can be achieved by implementations
> that expect no more precision or range than these provide, in the sense
> that implementations will approximate JSON numbers within the expected
> precision.
This implementation does exactly follow this approach, as it uses double
precision floating-point numbers. Note values smaller than
`-1.79769313486232e+308` and values greater than `1.79769313486232e+308`
will be stored as NaN internally and be serialized to `null`.
#### Storage
Floating-point number values are stored directly inside a @ref basic_json
type.
@sa @ref number_integer_t -- type for number values (integer)
@sa @ref number_unsigned_t -- type for number values (unsigned integer)
@since version 1.0.0
*/
using number_float_t = NumberFloatType;
/// @}
///////////////////////////
// JSON type enumeration //
///////////////////////////
/*!
@brief the JSON type enumeration
This enumeration collects the different JSON types. It is internally used
to distinguish the stored values, and the functions @ref is_null(), @ref
is_object(), @ref is_array(), @ref is_string(), @ref is_boolean(), @ref
is_number() (with @ref is_number_integer(), @ref is_number_unsigned(), and
@ref is_number_float()), @ref is_discarded(), @ref is_primitive(), and
@ref is_structured() rely on it.
@note There are three enumeration entries (number_integer,
number_unsigned, and number_float), because the library distinguishes
these three types for numbers: @ref number_unsigned_t is used for unsigned
integers, @ref number_integer_t is used for signed integers, and @ref
number_float_t is used for floating-point numbers or to approximate
integers which do not fit in the limits of their respective type.
@sa @ref basic_json(const value_t value_type) -- create a JSON value with
the default value for a given type
@since version 1.0.0
*/
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 (signed integer)
number_unsigned, ///< number value (unsigned integer)
number_float, ///< number value (floating-point)
discarded ///< discarded by the the parser callback function
};
private:
/// helper for exception-safe object creation
template<typename T, typename... Args>
static T* create(Args&& ... args)
{
AllocatorType<T> alloc;
auto deleter = [&](T * object)
{
alloc.deallocate(object, 1);
};
std::unique_ptr<T, decltype(deleter)> object(alloc.allocate(1), deleter);
alloc.construct(object.get(), std::forward<Args>(args)...);
assert(object.get() != nullptr);
return object.release();
}
////////////////////////
// JSON value storage //
////////////////////////
/*!
@brief a JSON value
The actual storage for a JSON value of the @ref basic_json class. This
union combines the different storage types for the JSON value types
defined in @ref value_t.
JSON type | value_t type | used type
--------- | --------------- | ------------------------
object | object | pointer to @ref object_t
array | array | pointer to @ref array_t
string | string | pointer to @ref string_t
boolean | boolean | @ref boolean_t
number | number_integer | @ref number_integer_t
number | number_unsigned | @ref number_unsigned_t
number | number_float | @ref number_float_t
null | null | *no value is stored*
@note Variable-length types (objects, arrays, and strings) are stored as
pointers. The size of the union should not exceed 64 bits if the default
value types are used.
@since version 1.0.0
*/
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;
/// boolean
boolean_t boolean;
/// number (integer)
number_integer_t number_integer;
/// number (unsigned integer)
number_unsigned_t number_unsigned;
/// number (floating-point)
number_float_t number_float;
/// default constructor (for null values)
json_value() = default;
/// constructor for booleans
json_value(boolean_t v) noexcept : boolean(v) {}
/// constructor for numbers (integer)
json_value(number_integer_t v) noexcept : number_integer(v) {}
/// constructor for numbers (unsigned)
json_value(number_unsigned_t v) noexcept : number_unsigned(v) {}
/// constructor for numbers (floating-point)
json_value(number_float_t v) noexcept : number_float(v) {}
/// constructor for empty values of a given type
json_value(value_t t)
{
switch (t)
{
case value_t::object:
{
object = create<object_t>();
break;
}
case value_t::array:
{
array = create<array_t>();
break;
}
case value_t::string:
{
string = create<string_t>("");
break;
}
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_unsigned:
{
number_unsigned = number_unsigned_t(0);
break;
}
case value_t::number_float:
{
number_float = number_float_t(0.0);
break;
}
default:
{
break;
}
}
}
/// constructor for strings
json_value(const string_t& value)
{
string = create<string_t>(value);
}
/// constructor for objects
json_value(const object_t& value)
{
object = create<object_t>(value);
}
/// constructor for arrays
json_value(const array_t& value)
{
array = create<array_t>(value);
}
};
/*!
@brief checks the class invariants
This function asserts the class invariants. It needs to be called at the
end of every constructor to make sure that created objects respect the
invariant. Furthermore, it has to be called each time the type of a JSON
value is changed, because the invariant expresses a relationship between
@a m_type and @a m_value.
*/
void assert_invariant() const
{
assert(m_type != value_t::object or m_value.object != nullptr);
assert(m_type != value_t::array or m_value.array != nullptr);
assert(m_type != value_t::string or m_value.string != nullptr);
}
public:
//////////////////////////
// JSON parser callback //
//////////////////////////
/*!
@brief JSON callback events
This enumeration lists the parser events that can trigger calling a
callback function of type @ref parser_callback_t during parsing.
@image html callback_events.png "Example when certain parse events are triggered"
@since version 1.0.0
*/
enum class parse_event_t : uint8_t
{
/// the parser read `{` and started to process a JSON object
object_start,
/// the parser read `}` and finished processing a JSON object
object_end,
/// the parser read `[` and started to process a JSON array
array_start,
/// the parser read `]` and finished processing a JSON array
array_end,
/// the parser read a key of a value in an object
key,
/// the parser finished reading a JSON value
value
};
/*!
@brief per-element parser callback type
With a parser callback function, the result of parsing a JSON text can be
influenced. When passed to @ref parse(std::istream&, const
parser_callback_t) or @ref parse(const char*, const parser_callback_t),
it is called on certain events (passed as @ref parse_event_t via parameter
@a event) with a set recursion depth @a depth and context JSON value
@a parsed. The return value of the callback function is a boolean
indicating whether the element that emitted the callback shall be kept or
not.
We distinguish six scenarios (determined by the event type) in which the
callback function can be called. The following table describes the values
of the parameters @a depth, @a event, and @a parsed.
parameter @a event | description | parameter @a depth | parameter @a parsed
------------------ | ----------- | ------------------ | -------------------
parse_event_t::object_start | the parser read `{` and started to process a JSON object | depth of the parent of the JSON object | a JSON value with type discarded
parse_event_t::key | the parser read a key of a value in an object | depth of the currently parsed JSON object | a JSON string containing the key
parse_event_t::object_end | the parser read `}` and finished processing a JSON object | depth of the parent of the JSON object | the parsed JSON object
parse_event_t::array_start | the parser read `[` and started to process a JSON array | depth of the parent of the JSON array | a JSON value with type discarded
parse_event_t::array_end | the parser read `]` and finished processing a JSON array | depth of the parent of the JSON array | the parsed JSON array
parse_event_t::value | the parser finished reading a JSON value | depth of the value | the parsed JSON value
@image html callback_events.png "Example when certain parse events are triggered"
Discarding a value (i.e., returning `false`) has different effects
depending on the context in which function was called:
- Discarded values in structured types are skipped. That is, the parser
will behave as if the discarded value was never read.
- In case a value outside a structured type is skipped, it is replaced
with `null`. This case happens if the top-level element is skipped.
@param[in] depth the depth of the recursion during parsing
@param[in] event an event of type parse_event_t indicating the context in
the callback function has been called
@param[in,out] parsed the current intermediate parse result; note that
writing to this value has no effect for parse_event_t::key events
@return Whether the JSON value which called the function during parsing
should be kept (`true`) or not (`false`). In the latter case, it is either
skipped completely or replaced by an empty discarded object.
@sa @ref parse(std::istream&, parser_callback_t) or
@ref parse(const char*, parser_callback_t) for examples
@since version 1.0.0
*/
using parser_callback_t = std::function<bool(int depth,
parse_event_t event,
basic_json& parsed)>;
//////////////////
// constructors //
//////////////////
/// @name constructors and destructors
/// Constructors of class @ref basic_json, copy/move constructor, copy
/// assignment, static functions creating objects, and the destructor.
/// @{
/*!
@brief create an empty value with a given type
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
----------- | -------------
null | `null`
boolean | `false`
string | `""`
number | `0`
object | `{}`
array | `[]`
@param[in] value_type the type of the value to create
@complexity Constant.
@throw std::bad_alloc if allocation for object, array, or string value
fails
@liveexample{The following code shows the constructor for different @ref
value_t values,basic_json__value_t}
@sa @ref basic_json(std::nullptr_t) -- create a `null` value
@sa @ref basic_json(boolean_t value) -- create a boolean value
@sa @ref basic_json(const string_t&) -- create a string value
@sa @ref basic_json(const object_t&) -- create a object value
@sa @ref basic_json(const array_t&) -- create a array value
@sa @ref basic_json(const number_float_t) -- create a number
(floating-point) value
@sa @ref basic_json(const number_integer_t) -- create a number (integer)
value
@sa @ref basic_json(const number_unsigned_t) -- create a number (unsigned)
value
@since version 1.0.0
*/
basic_json(const value_t value_type)
: m_type(value_type), m_value(value_type)
{
assert_invariant();
}
/*!
@brief create a null object
Create a `null` JSON value. It either takes a null pointer as parameter
(explicitly creating `null`) or no parameter (implicitly creating `null`).
The passed null pointer itself is not read -- it is only used to choose
the right constructor.
@complexity Constant.
@exceptionsafety No-throw guarantee: this constructor never throws
exceptions.
@liveexample{The following code shows the constructor with and without a
null pointer parameter.,basic_json__nullptr_t}
@since version 1.0.0
*/
basic_json(std::nullptr_t = nullptr) noexcept
: basic_json(value_t::null)
{
assert_invariant();
}
/*!
@brief create an object (explicit)
Create an object JSON value with a given content.
@param[in] val a value for the object
@complexity Linear in the size of the passed @a val.
@throw std::bad_alloc if allocation for object value fails
@liveexample{The following code shows the constructor with an @ref
object_t parameter.,basic_json__object_t}
@sa @ref basic_json(const CompatibleObjectType&) -- create an object value
from a compatible STL container
@since version 1.0.0
*/
basic_json(const object_t& val)
: m_type(value_t::object), m_value(val)
{
assert_invariant();
}
/*!
@brief create an object (implicit)
Create an object JSON value with a given content. This constructor allows
any type @a CompatibleObjectType that can be used to construct values of
type @ref object_t.
@tparam CompatibleObjectType An object type whose `key_type` and
`value_type` is compatible to @ref object_t. Examples include `std::map`,
`std::unordered_map`, `std::multimap`, and `std::unordered_multimap` with
a `key_type` of `std::string`, and a `value_type` from which a @ref
basic_json value can be constructed.
@param[in] val a value for the object
@complexity Linear in the size of the passed @a val.
@throw std::bad_alloc if allocation for object value fails
@liveexample{The following code shows the constructor with several
compatible object type parameters.,basic_json__CompatibleObjectType}
@sa @ref basic_json(const object_t&) -- create an object value
@since version 1.0.0
*/
template<class CompatibleObjectType, typename std::enable_if<
std::is_constructible<typename object_t::key_type, typename CompatibleObjectType::key_type>::value and
std::is_constructible<basic_json, typename CompatibleObjectType::mapped_type>::value, int>::type = 0>
basic_json(const CompatibleObjectType& val)
: m_type(value_t::object)
{
using std::begin;
using std::end;
m_value.object = create<object_t>(begin(val), end(val));
assert_invariant();
}
/*!
@brief create an array (explicit)
Create an array JSON value with a given content.
@param[in] val a value for the array
@complexity Linear in the size of the passed @a val.
@throw std::bad_alloc if allocation for array value fails
@liveexample{The following code shows the constructor with an @ref array_t
parameter.,basic_json__array_t}
@sa @ref basic_json(const CompatibleArrayType&) -- create an array value
from a compatible STL containers
@since version 1.0.0
*/
basic_json(const array_t& val)
: m_type(value_t::array), m_value(val)
{
assert_invariant();
}
/*!
@brief create an array (implicit)
Create an array JSON value with a given content. This constructor allows
any type @a CompatibleArrayType that can be used to construct values of
type @ref array_t.
@tparam CompatibleArrayType An object type whose `value_type` is
compatible to @ref array_t. Examples include `std::vector`, `std::deque`,
`std::list`, `std::forward_list`, `std::array`, `std::set`,
`std::unordered_set`, `std::multiset`, and `unordered_multiset` with a
`value_type` from which a @ref basic_json value can be constructed.
@param[in] val a value for the array
@complexity Linear in the size of the passed @a val.
@throw std::bad_alloc if allocation for array value fails
@liveexample{The following code shows the constructor with several
compatible array type parameters.,basic_json__CompatibleArrayType}
@sa @ref basic_json(const array_t&) -- create an array value
@since version 1.0.0
*/
template<class CompatibleArrayType, typename std::enable_if<
not std::is_same<CompatibleArrayType, typename basic_json_t::iterator>::value and
not std::is_same<CompatibleArrayType, typename basic_json_t::const_iterator>::value and
not std::is_same<CompatibleArrayType, typename basic_json_t::reverse_iterator>::value and
not std::is_same<CompatibleArrayType, typename basic_json_t::const_reverse_iterator>::value and
not std::is_same<CompatibleArrayType, typename array_t::iterator>::value and
not std::is_same<CompatibleArrayType, typename array_t::const_iterator>::value and
std::is_constructible<basic_json, typename CompatibleArrayType::value_type>::value, int>::type = 0>
basic_json(const CompatibleArrayType& val)
: m_type(value_t::array)
{
using std::begin;
using std::end;
m_value.array = create<array_t>(begin(val), end(val));
assert_invariant();
}
/*!
@brief create a string (explicit)
Create an string JSON value with a given content.
@param[in] val a value for the string
@complexity Linear in the size of the passed @a val.
@throw std::bad_alloc if allocation for string value fails
@liveexample{The following code shows the constructor with an @ref
string_t parameter.,basic_json__string_t}
@sa @ref basic_json(const typename string_t::value_type*) -- create a
string value from a character pointer
@sa @ref basic_json(const CompatibleStringType&) -- create a string value
from a compatible string container
@since version 1.0.0
*/
basic_json(const string_t& val)
: m_type(value_t::string), m_value(val)
{
assert_invariant();
}
/*!
@brief create a string (explicit)
Create a string JSON value with a given content.
@param[in] val a literal value for the string
@complexity Linear in the size of the passed @a val.
@throw std::bad_alloc if allocation for string value fails
@liveexample{The following code shows the constructor with string literal
parameter.,basic_json__string_t_value_type}
@sa @ref basic_json(const string_t&) -- create a string value
@sa @ref basic_json(const CompatibleStringType&) -- create a string value
from a compatible string container
@since version 1.0.0
*/
basic_json(const typename string_t::value_type* val)
: basic_json(string_t(val))
{
assert_invariant();
}
/*!
@brief create a string (implicit)
Create a string JSON value with a given content.
@param[in] val a value for the string
@tparam CompatibleStringType an string type which is compatible to @ref
string_t, for instance `std::string`.
@complexity Linear in the size of the passed @a val.
@throw std::bad_alloc if allocation for string value fails
@liveexample{The following code shows the construction of a string value
from a compatible type.,basic_json__CompatibleStringType}
@sa @ref basic_json(const string_t&) -- create a string value
@sa @ref basic_json(const typename string_t::value_type*) -- create a
string value from a character pointer
@since version 1.0.0
*/
template<class CompatibleStringType, typename std::enable_if<
std::is_constructible<string_t, CompatibleStringType>::value, int>::type = 0>
basic_json(const CompatibleStringType& val)
: basic_json(string_t(val))
{
assert_invariant();
}
/*!
@brief create a boolean (explicit)
Creates a JSON boolean type from a given value.
@param[in] val a boolean value to store
@complexity Constant.
@liveexample{The example below demonstrates boolean
values.,basic_json__boolean_t}
@since version 1.0.0
*/
basic_json(boolean_t val) noexcept
: m_type(value_t::boolean), m_value(val)
{
assert_invariant();
}
/*!
@brief create an integer number (explicit)
Create an integer number JSON value with a given content.
@tparam T A helper type to remove this function via SFINAE in case @ref
number_integer_t is the same as `int`. In this case, this constructor
would have the same signature as @ref basic_json(const int value). Note
the helper type @a T is not visible in this constructor's interface.
@param[in] val an integer to create a JSON number from
@complexity Constant.
@liveexample{The example below shows the construction of an integer
number value.,basic_json__number_integer_t}
@sa @ref basic_json(const int) -- create a number value (integer)
@sa @ref basic_json(const CompatibleNumberIntegerType) -- create a number
value (integer) from a compatible number type
@since version 1.0.0
*/
template<typename T, typename std::enable_if<
not (std::is_same<T, int>::value) and
std::is_same<T, number_integer_t>::value, int>::type = 0>
basic_json(const number_integer_t val) noexcept
: m_type(value_t::number_integer), m_value(val)
{
assert_invariant();
}
/*!
@brief create an integer number from an enum type (explicit)
Create an integer number JSON value with a given content.
@param[in] val an integer to create a JSON number from
@note 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 the constructor @ref basic_json(const number_integer_t).
@complexity Constant.
@liveexample{The example below shows the construction of an integer
number value from an anonymous enum.,basic_json__const_int}
@sa @ref basic_json(const number_integer_t) -- create a number value
(integer)
@sa @ref basic_json(const CompatibleNumberIntegerType) -- create a number
value (integer) from a compatible number type
@since version 1.0.0
*/
basic_json(const int val) noexcept
: m_type(value_t::number_integer),
m_value(static_cast<number_integer_t>(val))
{
assert_invariant();
}
/*!
@brief create an integer number (implicit)
Create an integer number JSON value with a given content. This constructor
allows any type @a CompatibleNumberIntegerType that can be used to
construct values of type @ref number_integer_t.
@tparam CompatibleNumberIntegerType An integer type which is compatible to
@ref number_integer_t. Examples include the types `int`, `int32_t`,
`long`, and `short`.
@param[in] val an integer to create a JSON number from
@complexity Constant.
@liveexample{The example below shows the construction of several integer
number values from compatible
types.,basic_json__CompatibleIntegerNumberType}
@sa @ref basic_json(const number_integer_t) -- create a number value
(integer)
@sa @ref basic_json(const int) -- create a number value (integer)
@since version 1.0.0
*/
template<typename CompatibleNumberIntegerType, typename std::enable_if<
std::is_constructible<number_integer_t, CompatibleNumberIntegerType>::value and
std::numeric_limits<CompatibleNumberIntegerType>::is_integer and
std::numeric_limits<CompatibleNumberIntegerType>::is_signed,
CompatibleNumberIntegerType>::type = 0>
basic_json(const CompatibleNumberIntegerType val) noexcept
: m_type(value_t::number_integer),
m_value(static_cast<number_integer_t>(val))
{
assert_invariant();
}
/*!
@brief create an unsigned integer number (explicit)
Create an unsigned integer number JSON value with a given content.
@tparam T helper type to compare number_unsigned_t and unsigned int (not
visible in) the interface.
@param[in] val an integer to create a JSON number from
@complexity Constant.
@sa @ref basic_json(const CompatibleNumberUnsignedType) -- create a number
value (unsigned integer) from a compatible number type
@since version 2.0.0
*/
template<typename T, typename std::enable_if<
not (std::is_same<T, int>::value) and
std::is_same<T, number_unsigned_t>::value, int>::type = 0>
basic_json(const number_unsigned_t val) noexcept
: m_type(value_t::number_unsigned), m_value(val)
{
assert_invariant();
}
/*!
@brief create an unsigned number (implicit)
Create an unsigned number JSON value with a given content. This
constructor allows any type @a CompatibleNumberUnsignedType that can be
used to construct values of type @ref number_unsigned_t.
@tparam CompatibleNumberUnsignedType An integer type which is compatible
to @ref number_unsigned_t. Examples may include the types `unsigned int`,
`uint32_t`, or `unsigned short`.
@param[in] val an unsigned integer to create a JSON number from
@complexity Constant.
@sa @ref basic_json(const number_unsigned_t) -- create a number value
(unsigned)
@since version 2.0.0
*/
template<typename CompatibleNumberUnsignedType, typename std::enable_if <
std::is_constructible<number_unsigned_t, CompatibleNumberUnsignedType>::value and
std::numeric_limits<CompatibleNumberUnsignedType>::is_integer and
not std::numeric_limits<CompatibleNumberUnsignedType>::is_signed,
CompatibleNumberUnsignedType>::type = 0>
basic_json(const CompatibleNumberUnsignedType val) noexcept
: m_type(value_t::number_unsigned),
m_value(static_cast<number_unsigned_t>(val))
{
assert_invariant();
}
/*!
@brief create a floating-point number (explicit)
Create a floating-point number JSON value with a given content.
@param[in] val a floating-point value to create a JSON number from
@note [RFC 7159](http://www.rfc-editor.org/rfc/rfc7159.txt), section 6
disallows NaN values:
> Numeric values that cannot be represented in the grammar below (such as
> Infinity and NaN) are not permitted.
In case the parameter @a val is not a number, a JSON null value is created
instead.
@complexity Constant.
@liveexample{The following example creates several floating-point
values.,basic_json__number_float_t}
@sa @ref basic_json(const CompatibleNumberFloatType) -- create a number
value (floating-point) from a compatible number type
@since version 1.0.0
*/
basic_json(const number_float_t val) noexcept
: m_type(value_t::number_float), m_value(val)
{
// replace infinity and NAN by null
if (not std::isfinite(val))
{
m_type = value_t::null;
m_value = json_value();
}
assert_invariant();
}
/*!
@brief create an floating-point number (implicit)
Create an floating-point number JSON value with a given content. This
constructor allows any type @a CompatibleNumberFloatType that can be used
to construct values of type @ref number_float_t.
@tparam CompatibleNumberFloatType A floating-point type which is
compatible to @ref number_float_t. Examples may include the types `float`
or `double`.
@param[in] val a floating-point to create a JSON number from
@note [RFC 7159](http://www.rfc-editor.org/rfc/rfc7159.txt), section 6
disallows NaN values:
> Numeric values that cannot be represented in the grammar below (such as
> Infinity and NaN) are not permitted.
In case the parameter @a val is not a number, a JSON null value is
created instead.
@complexity Constant.
@liveexample{The example below shows the construction of several
floating-point number values from compatible
types.,basic_json__CompatibleNumberFloatType}
@sa @ref basic_json(const number_float_t) -- create a number value
(floating-point)
@since version 1.0.0
*/
template<typename CompatibleNumberFloatType, typename = typename std::enable_if<
std::is_constructible<number_float_t, CompatibleNumberFloatType>::value and
std::is_floating_point<CompatibleNumberFloatType>::value>::type>
basic_json(const CompatibleNumberFloatType val) noexcept
: basic_json(number_float_t(val))
{
assert_invariant();
}
/*!
@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 rationale 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(std::initializer_list<basic_json>)
with an empty initializer list in this case
- arrays whose elements satisfy rule 2: use @ref
array(std::initializer_list<basic_json>) 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[in] init initializer list with JSON values
@param[in] 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(std::initializer_list<basic_json>) and
@ref object(std::initializer_list<basic_json>).
@param[in] 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; example: `"cannot create object from
initializer list"`
@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}
@sa @ref array(std::initializer_list<basic_json>) -- create a JSON array
value from an initializer list
@sa @ref object(std::initializer_list<basic_json>) -- create a JSON object
value from an initializer list
@since version 1.0.0
*/
basic_json(std::initializer_list<basic_json> init,
bool type_deduction = true,
value_t manual_type = value_t::array)
{
// check if each element is an array with two elements whose first
// element is a string
bool is_an_object = std::all_of(init.begin(), init.end(),
[](const basic_json & element)
{
return element.is_array() and element.size() == 2 and element[0].is_string();
});
// adjust type if type deduction is not wanted
if (not type_deduction)
{
// if array is wanted, do not create an object though possible
if (manual_type == value_t::array)
{
is_an_object = false;
}
// if object is wanted but impossible, throw an exception
if (manual_type == value_t::object and not is_an_object)
{
throw std::domain_error("cannot create object from initializer list");
}
}
if (is_an_object)
{
// the initializer list is a list of pairs -> create object
m_type = value_t::object;
m_value = value_t::object;
std::for_each(init.begin(), init.end(), [this](const basic_json & element)
{
m_value.object->emplace(*(element[0].m_value.string), element[1]);
});
}
else
{
// the initializer list describes an array -> create array
m_type = value_t::array;
m_value.array = create<array_t>(init);
}
assert_invariant();
}
/*!
@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(std::initializer_list<basic_json>, 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[in] 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 `array`
function.,array}
@sa @ref basic_json(std::initializer_list<basic_json>, bool, value_t) --
create a JSON value from an initializer list
@sa @ref object(std::initializer_list<basic_json>) -- create a JSON object
value from an initializer list
@since version 1.0.0
*/
static basic_json array(std::initializer_list<basic_json> init =
std::initializer_list<basic_json>())
{
return basic_json(init, false, value_t::array);
}
/*!
@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 elements 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 array(std::initializer_list<basic_json>), 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(std::initializer_list<basic_json>, bool,
value_t).
@param[in] 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(std::initializer_list<basic_json>, bool, value_t)
@complexity Linear in the size of @a init.
@liveexample{The following code shows an example for the `object`
function.,object}
@sa @ref basic_json(std::initializer_list<basic_json>, bool, value_t) --
create a JSON value from an initializer list
@sa @ref array(std::initializer_list<basic_json>) -- create a JSON array
value from an initializer list
@since version 1.0.0
*/
static basic_json object(std::initializer_list<basic_json> init =
std::initializer_list<basic_json>())
{
return basic_json(init, false, value_t::object);
}
/*!
@brief construct an array with count copies of given value
Constructs a JSON array value by creating @a cnt copies of a passed value.
In case @a cnt is `0`, an empty array is created. As postcondition,
`std::distance(begin(),end()) == cnt` holds.
@param[in] cnt the number of JSON copies of @a val to create
@param[in] val the JSON value to copy
@complexity Linear in @a cnt.
@liveexample{The following code shows examples for the @ref
basic_json(size_type\, const basic_json&)
constructor.,basic_json__size_type_basic_json}
@since version 1.0.0
*/
basic_json(size_type cnt, const basic_json& val)
: m_type(value_t::array)
{
m_value.array = create<array_t>(cnt, val);
assert_invariant();
}
/*!
@brief construct a JSON container given an iterator range
Constructs the JSON value with the contents of the range `[first, last)`.
The semantics depends on the different types a JSON value can have:
- In case of primitive types (number, boolean, or string), @a first must
be `begin()` and @a last must be `end()`. In this case, the value is
copied. Otherwise, std::out_of_range is thrown.
- In case of structured types (array, object), the constructor behaves as
similar versions for `std::vector`.
- In case of a null type, std::domain_error is thrown.
@tparam InputIT an input iterator type (@ref iterator or @ref
const_iterator)
@param[in] first begin of the range to copy from (included)
@param[in] last end of the range to copy from (excluded)
@pre Iterators @a first and @a last must be initialized. **This
precondition is enforced with an assertion.**
@throw std::domain_error if iterators are not compatible; that is, do not
belong to the same JSON value; example: `"iterators are not compatible"`
@throw std::out_of_range if iterators are for a primitive type (number,
boolean, or string) where an out of range error can be detected easily;
example: `"iterators out of range"`
@throw std::bad_alloc if allocation for object, array, or string fails
@throw std::domain_error if called with a null value; example: `"cannot
use construct with iterators from null"`
@complexity Linear in distance between @a first and @a last.
@liveexample{The example below shows several ways to create JSON values by
specifying a subrange with iterators.,basic_json__InputIt_InputIt}
@since version 1.0.0
*/
template<class InputIT, typename std::enable_if<
std::is_same<InputIT, typename basic_json_t::iterator>::value or
std::is_same<InputIT, typename basic_json_t::const_iterator>::value, int>::type = 0>
basic_json(InputIT first, InputIT last)
{
assert(first.m_object != nullptr);
assert(last.m_object != nullptr);
// make sure iterator fits the current value
if (first.m_object != last.m_object)
{
throw std::domain_error("iterators are not compatible");
}
// copy type from first iterator
m_type = first.m_object->m_type;
// check if iterator range is complete for primitive values
switch (m_type)
{
case value_t::boolean:
case value_t::number_float:
case value_t::number_integer:
case value_t::number_unsigned:
case value_t::string:
{
if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end())
{
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_unsigned:
{
m_value.number_unsigned = first.m_object->m_value.number_unsigned;
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:
{
m_value = *first.m_object->m_value.string;
break;
}
case value_t::object:
{
m_value.object = create<object_t>(first.m_it.object_iterator, last.m_it.object_iterator);
break;
}
case value_t::array:
{
m_value.array = create<array_t>(first.m_it.array_iterator, last.m_it.array_iterator);
break;
}
default:
{
throw std::domain_error("cannot use construct with iterators from " + first.m_object->type_name());
}
}
assert_invariant();
}
/*!
@brief construct a JSON value given an input stream
@param[in,out] i stream to read a serialized JSON value from
@param[in] cb a parser callback function of type @ref parser_callback_t
which is used to control the deserialization by filtering unwanted values
(optional)
@complexity Linear in the length of the input. The parser is a predictive
LL(1) parser. The complexity can be higher if the parser callback function
@a cb has a super-linear complexity.
@note A UTF-8 byte order mark is silently ignored.
@deprecated This constructor is deprecated and will be removed in version
3.0.0 to unify the interface of the library. Deserialization will be
done by stream operators or by calling one of the `parse` functions,
e.g. @ref parse(std::istream&, const parser_callback_t). That is, calls
like `json j(i);` for an input stream @a i need to be replaced by
`json j = json::parse(i);`. See the example below.
@liveexample{The example below demonstrates constructing a JSON value from
a `std::stringstream` with and without callback
function.,basic_json__istream}
@since version 2.0.0, deprecated in version 2.0.3, to be removed in
version 3.0.0
*/
JSON_DEPRECATED
explicit basic_json(std::istream& i, const parser_callback_t cb = nullptr)
{
*this = parser(i, cb).parse();
assert_invariant();
}
///////////////////////////////////////
// other constructors and destructor //
///////////////////////////////////////
/*!
@brief copy constructor
Creates a copy of a given JSON value.
@param[in] other the JSON value to copy
@complexity Linear in the size of @a other.
@requirement This function helps `basic_json` satisfying the
[Container](http://en.cppreference.com/w/cpp/concept/Container)
requirements:
- The complexity is linear.
- As postcondition, it holds: `other == basic_json(other)`.
@throw 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}
@since version 1.0.0
*/
basic_json(const basic_json& other)
: m_type(other.m_type)
{
// check of passed value is valid
other.assert_invariant();
switch (m_type)
{
case value_t::object:
{
m_value = *other.m_value.object;
break;
}
case value_t::array:
{
m_value = *other.m_value.array;
break;
}
case value_t::string:
{
m_value = *other.m_value.string;
break;
}
case value_t::boolean:
{
m_value = other.m_value.boolean;
break;
}
case value_t::number_integer:
{
m_value = other.m_value.number_integer;
break;
}
case value_t::number_unsigned:
{
m_value = other.m_value.number_unsigned;
break;
}
case value_t::number_float:
{
m_value = other.m_value.number_float;
break;
}
default:
{
break;
}
}
assert_invariant();
}
/*!
@brief move constructor
Move constructor. Constructs a JSON value with the contents of the given
value @a other using move semantics. It "steals" the resources from @a
other and leaves it as JSON null value.
@param[in,out] other value to move to this object
@post @a other is a JSON null value
@complexity Constant.
@liveexample{The code below shows the move constructor explicitly called
via std::move.,basic_json__moveconstructor}
@since version 1.0.0
*/
basic_json(basic_json&& other) noexcept
: m_type(std::move(other.m_type)),
m_value(std::move(other.m_value))
{
// check that passed value is valid
other.assert_invariant();
// invalidate payload
other.m_type = value_t::null;
other.m_value = {};
assert_invariant();
}
/*!
@brief copy assignment
Copy assignment operator. Copies a JSON value via the "copy and swap"
strategy: It is expressed in terms of the copy constructor, destructor,
and the swap() member function.
@param[in] other value to copy from
@complexity Linear.
@requirement This function helps `basic_json` satisfying the
[Container](http://en.cppreference.com/w/cpp/concept/Container)
requirements:
- The complexity is linear.
@liveexample{The code below shows and example for the copy assignment. It
creates a copy of value `a` which is then swapped with `b`. Finally\, the
copy of `a` (which is the null value after the swap) is
destroyed.,basic_json__copyassignment}
@since version 1.0.0
*/
reference& operator=(basic_json other) noexcept (
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
)
{
// check that passed value is valid
other.assert_invariant();
using std::swap;
swap(m_type, other.m_type);
swap(m_value, other.m_value);
assert_invariant();
return *this;
}
/*!
@brief destructor
Destroys the JSON value and frees all allocated memory.
@complexity Linear.
@requirement This function helps `basic_json` satisfying the
[Container](http://en.cppreference.com/w/cpp/concept/Container)
requirements:
- The complexity is linear.
- All stored elements are destroyed and all memory is freed.
@since version 1.0.0
*/
~basic_json()
{
assert_invariant();
switch (m_type)
{
case value_t::object:
{
AllocatorType<object_t> alloc;
alloc.destroy(m_value.object);
alloc.deallocate(m_value.object, 1);
break;
}
case value_t::array:
{
AllocatorType<array_t> alloc;
alloc.destroy(m_value.array);
alloc.deallocate(m_value.array, 1);
break;
}
case value_t::string:
{
AllocatorType<string_t> alloc;
alloc.destroy(m_value.string);
alloc.deallocate(m_value.string, 1);
break;
}
default:
{
// all other types need no specific destructor
break;
}
}
}
/// @}
public:
///////////////////////
// object inspection //
///////////////////////
/// @name object inspection
/// Functions to inspect the type of a JSON value.
/// @{
/*!
@brief serialization
Serialization function for JSON values. The function tries to mimic
Python's `json.dumps()` function, and currently supports its @a indent
parameter.
@param[in] indent If indent is nonnegative, then array elements and object
members will be pretty-printed with that indent level. An indent level of
`0` will only insert newlines. `-1` (the default) selects the most compact
representation.
@return string containing the serialization of the JSON value
@complexity Linear.
@liveexample{The following example shows the effect of different @a indent
parameters to the result of the serialization.,dump}
@see https://docs.python.org/2/library/json.html#json.dump
@since version 1.0.0
*/
string_t dump(const int indent = -1) const
{
std::stringstream ss;
// fix locale problems
const static std::locale loc(std::locale(), new DecimalSeparator);
ss.imbue(loc);
// 6, 15 or 16 digits of precision allows round-trip IEEE 754
// string->float->string, string->double->string or string->long
// double->string; to be safe, we read this value from
// std::numeric_limits<number_float_t>::digits10
ss.precision(std::numeric_limits<double>::digits10);
if (indent >= 0)
{
dump(ss, true, static_cast<unsigned int>(indent));
}
else
{
dump(ss, false, 0);
}
return ss.str();
}
/*!
@brief return the type of the JSON value (explicit)
Return the type of the JSON value as a value from the @ref value_t
enumeration.
@return the type of the JSON value
@complexity Constant.
@exceptionsafety No-throw guarantee: this member function never throws
exceptions.
@liveexample{The following code exemplifies `type()` for all JSON
types.,type}
@since version 1.0.0
*/
constexpr value_t type() const noexcept
{
return m_type;
}
/*!
@brief return whether type is primitive
This function returns true iff the JSON type is primitive (string, number,
boolean, or null).
@return `true` if type is primitive (string, number, boolean, or null),
`false` otherwise.
@complexity Constant.
@exceptionsafety No-throw guarantee: this member function never throws
exceptions.
@liveexample{The following code exemplifies `is_primitive()` for all JSON
types.,is_primitive}
@sa @ref is_structured() -- returns whether JSON value is structured
@sa @ref is_null() -- returns whether JSON value is `null`
@sa @ref is_string() -- returns whether JSON value is a string
@sa @ref is_boolean() -- returns whether JSON value is a boolean
@sa @ref is_number() -- returns whether JSON value is a number
@since version 1.0.0
*/
constexpr bool is_primitive() const noexcept
{
return is_null() or is_string() or is_boolean() or is_number();
}
/*!
@brief return whether type is structured
This function returns true iff the JSON type is structured (array or
object).
@return `true` if type is structured (array or object), `false` otherwise.
@complexity Constant.
@exceptionsafety No-throw guarantee: this member function never throws
exceptions.
@liveexample{The following code exemplifies `is_structured()` for all JSON
types.,is_structured}
@sa @ref is_primitive() -- returns whether value is primitive
@sa @ref is_array() -- returns whether value is an array
@sa @ref is_object() -- returns whether value is an object
@since version 1.0.0
*/
constexpr bool is_structured() const noexcept
{
return is_array() or is_object();
}
/*!
@brief return whether value is null
This function returns true iff the JSON value is null.
@return `true` if type is null, `false` otherwise.
@complexity Constant.
@exceptionsafety No-throw guarantee: this member function never throws
exceptions.
@liveexample{The following code exemplifies `is_null()` for all JSON
types.,is_null}
@since version 1.0.0
*/
constexpr bool is_null() const noexcept
{
return m_type == value_t::null;
}
/*!
@brief return whether value is a boolean
This function returns true iff the JSON value is a boolean.
@return `true` if type is boolean, `false` otherwise.
@complexity Constant.
@exceptionsafety No-throw guarantee: this member function never throws
exceptions.
@liveexample{The following code exemplifies `is_boolean()` for all JSON
types.,is_boolean}
@since version 1.0.0
*/
constexpr bool is_boolean() const noexcept
{
return m_type == value_t::boolean;
}
/*!
@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 type is number (regardless whether integer, unsigned
integer or floating-type), `false` otherwise.
@complexity Constant.
@exceptionsafety No-throw guarantee: this member function never throws
exceptions.
@liveexample{The following code exemplifies `is_number()` for all JSON
types.,is_number}
@sa @ref is_number_integer() -- check if value is an integer or unsigned
integer number
@sa @ref is_number_unsigned() -- check if value is an unsigned integer
number
@sa @ref is_number_float() -- check if value is a floating-point number
@since version 1.0.0
*/
constexpr bool is_number() const noexcept
{
return is_number_integer() or is_number_float();
}
/*!
@brief return whether value is an integer number
This function returns true iff the JSON value is an integer or unsigned
integer number. This excludes floating-point values.
@return `true` if type is an integer or unsigned integer number, `false`
otherwise.
@complexity Constant.
@exceptionsafety No-throw guarantee: this member function never throws
exceptions.
@liveexample{The following code exemplifies `is_number_integer()` for all
JSON types.,is_number_integer}
@sa @ref is_number() -- check if value is a number
@sa @ref is_number_unsigned() -- check if value is an unsigned integer
number
@sa @ref is_number_float() -- check if value is a floating-point number
@since version 1.0.0
*/
constexpr bool is_number_integer() const noexcept
{
return m_type == value_t::number_integer or m_type == value_t::number_unsigned;
}
/*!
@brief return whether value is an unsigned integer number
This function returns true iff the JSON value is an unsigned integer
number. This excludes floating-point and (signed) integer values.
@return `true` if type is an unsigned integer number, `false` otherwise.
@complexity Constant.
@exceptionsafety No-throw guarantee: this member function never throws
exceptions.
@liveexample{The following code exemplifies `is_number_unsigned()` for all
JSON types.,is_number_unsigned}
@sa @ref is_number() -- check if value is a number
@sa @ref is_number_integer() -- check if value is an integer or unsigned
integer number
@sa @ref is_number_float() -- check if value is a floating-point number
@since version 2.0.0
*/
constexpr bool is_number_unsigned() const noexcept
{
return m_type == value_t::number_unsigned;
}
/*!
@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 and unsigned integer values.
@return `true` if type is a floating-point number, `false` otherwise.
@complexity Constant.
@exceptionsafety No-throw guarantee: this member function never throws
exceptions.
@liveexample{The following code exemplifies `is_number_float()` for all
JSON types.,is_number_float}
@sa @ref is_number() -- check if value is number
@sa @ref is_number_integer() -- check if value is an integer number
@sa @ref is_number_unsigned() -- check if value is an unsigned integer
number
@since version 1.0.0
*/
constexpr bool is_number_float() const noexcept
{
return m_type == value_t::number_float;
}
/*!
@brief return whether value is an object
This function returns true iff the JSON value is an object.
@return `true` if type is object, `false` otherwise.
@complexity Constant.
@exceptionsafety No-throw guarantee: this member function never throws
exceptions.
@liveexample{The following code exemplifies `is_object()` for all JSON
types.,is_object}
@since version 1.0.0
*/
constexpr bool is_object() const noexcept
{
return m_type == value_t::object;
}
/*!
@brief return whether value is an array
This function returns true iff the JSON value is an array.
@return `true` if type is array, `false` otherwise.
@complexity Constant.
@exceptionsafety No-throw guarantee: this member function never throws
exceptions.
@liveexample{The following code exemplifies `is_array()` for all JSON
types.,is_array}
@since version 1.0.0
*/
constexpr bool is_array() const noexcept
{
return m_type == value_t::array;
}
/*!
@brief return whether value is a string
This function returns true iff the JSON value is a string.
@return `true` if type is string, `false` otherwise.
@complexity Constant.
@exceptionsafety No-throw guarantee: this member function never throws
exceptions.
@liveexample{The following code exemplifies `is_string()` for all JSON
types.,is_string}
@since version 1.0.0
*/
constexpr bool is_string() const noexcept
{
return m_type == value_t::string;
}
/*!
@brief return whether value is discarded
This function returns true iff the JSON value was discarded during parsing
with a callback function (see @ref parser_callback_t).
@note This function will always be `false` for JSON values after parsing.
That is, discarded values can only occur during parsing, but will be
removed when inside a structured value or replaced by null in other cases.
@return `true` if type is discarded, `false` otherwise.
@complexity Constant.
@exceptionsafety No-throw guarantee: this member function never throws
exceptions.
@liveexample{The following code exemplifies `is_discarded()` for all JSON
types.,is_discarded}
@since version 1.0.0
*/
constexpr bool is_discarded() const noexcept
{
return m_type == value_t::discarded;
}
/*!
@brief return the type of the JSON value (implicit)
Implicitly return the type of the JSON value as a value from the @ref
value_t enumeration.
@return the type of the JSON value
@complexity Constant.
@exceptionsafety No-throw guarantee: this member function never throws
exceptions.
@liveexample{The following code exemplifies the @ref value_t operator for
all JSON types.,operator__value_t}
@since version 1.0.0
*/
constexpr operator value_t() const noexcept
{
return m_type;
}
/// @}
private:
//////////////////
// value access //
//////////////////
/// get an object (explicit)
template<class T, typename std::enable_if<
std::is_convertible<typename object_t::key_type, typename T::key_type>::value and
std::is_convertible<basic_json_t, typename T::mapped_type>::value, int>::type = 0>
T get_impl(T*) const
{
if (is_object())
{
return T(m_value.object->begin(), m_value.object->end());
}
else
{
throw std::domain_error("type must be object, but is " + type_name());
}
}
/// get an object (explicit)
object_t get_impl(object_t*) const
{
if (is_object())
{
return *(m_value.object);
}
else
{
throw std::domain_error("type must be object, but is " + type_name());
}
}
/// get an array (explicit)
template<class T, typename std::enable_if<
std::is_convertible<basic_json_t, typename T::value_type>::value and
not std::is_same<basic_json_t, typename T::value_type>::value and
not std::is_arithmetic<T>::value and
not std::is_convertible<std::string, T>::value and
not has_mapped_type<T>::value, int>::type = 0>
T get_impl(T*) const
{
if (is_array())
{
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;
}
else
{
throw std::domain_error("type must be array, but is " + type_name());
}
}
/// get an array (explicit)
template<class T, typename std::enable_if<
std::is_convertible<basic_json_t, T>::value and
not std::is_same<basic_json_t, T>::value, int>::type = 0>
std::vector<T> get_impl(std::vector<T>*) const
{
if (is_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;
}
else
{
throw std::domain_error("type must be array, but is " + type_name());
}
}
/// get an array (explicit)
template<class T, typename std::enable_if<
std::is_same<basic_json, typename T::value_type>::value and
not has_mapped_type<T>::value, int>::type = 0>
T get_impl(T*) const
{
if (is_array())
{
return T(m_value.array->begin(), m_value.array->end());
}
else
{
throw std::domain_error("type must be array, but is " + type_name());
}
}
/// get an array (explicit)
array_t get_impl(array_t*) const
{
if (is_array())
{
return *(m_value.array);
}
else
{
throw std::domain_error("type must be array, but is " + type_name());
}
}
/// get a string (explicit)
template<typename T, typename std::enable_if<
std::is_convertible<string_t, T>::value, int>::type = 0>
T get_impl(T*) const
{
if (is_string())
{
return *m_value.string;
}
else
{
throw std::domain_error("type must be string, but is " + type_name());
}
}
/// get a number (explicit)
template<typename T, typename std::enable_if<
std::is_arithmetic<T>::value, int>::type = 0>
T get_impl(T*) const
{
switch (m_type)
{
case value_t::number_integer:
{
return static_cast<T>(m_value.number_integer);
}
case value_t::number_unsigned:
{
return static_cast<T>(m_value.number_unsigned);
}
case value_t::number_float:
{
return static_cast<T>(m_value.number_float);
}
default:
{
throw std::domain_error("type must be number, but is " + type_name());
}
}
}
/// get a boolean (explicit)
constexpr boolean_t get_impl(boolean_t*) const
{
return is_boolean()
? m_value.boolean
: throw std::domain_error("type must be boolean, but is " + type_name());
}
/// get a pointer to the value (object)
object_t* get_impl_ptr(object_t*) noexcept
{
return is_object() ? m_value.object : nullptr;
}
/// get a pointer to the value (object)
constexpr const object_t* get_impl_ptr(const object_t*) const noexcept
{
return is_object() ? m_value.object : nullptr;
}
/// get a pointer to the value (array)
array_t* get_impl_ptr(array_t*) noexcept
{
return is_array() ? m_value.array : nullptr;
}
/// get a pointer to the value (array)
constexpr const array_t* get_impl_ptr(const array_t*) const noexcept
{
return is_array() ? m_value.array : nullptr;
}
/// get a pointer to the value (string)
string_t* get_impl_ptr(string_t*) noexcept
{
return is_string() ? m_value.string : nullptr;
}
/// get a pointer to the value (string)
constexpr const string_t* get_impl_ptr(const string_t*) const noexcept
{
return is_string() ? m_value.string : nullptr;
}
/// get a pointer to the value (boolean)
boolean_t* get_impl_ptr(boolean_t*) noexcept
{
return is_boolean() ? &m_value.boolean : nullptr;
}
/// get a pointer to the value (boolean)
constexpr const boolean_t* get_impl_ptr(const boolean_t*) const noexcept
{
return is_boolean() ? &m_value.boolean : nullptr;
}
/// get a pointer to the value (integer number)
number_integer_t* get_impl_ptr(number_integer_t*) noexcept
{
return is_number_integer() ? &m_value.number_integer : nullptr;
}
/// get a pointer to the value (integer number)
constexpr const number_integer_t* get_impl_ptr(const number_integer_t*) const noexcept
{
return is_number_integer() ? &m_value.number_integer : nullptr;
}
/// get a pointer to the value (unsigned number)
number_unsigned_t* get_impl_ptr(number_unsigned_t*) noexcept
{
return is_number_unsigned() ? &m_value.number_unsigned : nullptr;
}
/// get a pointer to the value (unsigned number)
constexpr const number_unsigned_t* get_impl_ptr(const number_unsigned_t*) const noexcept
{
return is_number_unsigned() ? &m_value.number_unsigned : nullptr;
}
/// get a pointer to the value (floating-point number)
number_float_t* get_impl_ptr(number_float_t*) noexcept
{
return is_number_float() ? &m_value.number_float : nullptr;
}
/// get a pointer to the value (floating-point number)
constexpr const number_float_t* get_impl_ptr(const number_float_t*) const noexcept
{
return is_number_float() ? &m_value.number_float : nullptr;
}
/*!
@brief helper function to implement get_ref()
This funcion helps to implement get_ref() without code duplication for
const and non-const overloads
@tparam ThisType will be deduced as `basic_json` or `const basic_json`
@throw std::domain_error if ReferenceType does not match underlying value
type of the current JSON
*/
template<typename ReferenceType, typename ThisType>
static ReferenceType get_ref_impl(ThisType& obj)
{
// helper type
using PointerType = typename std::add_pointer<ReferenceType>::type;
// delegate the call to get_ptr<>()
auto ptr = obj.template get_ptr<PointerType>();
if (ptr != nullptr)
{
return *ptr;
}
else
{
throw std::domain_error("incompatible ReferenceType for get_ref, actual type is " +
obj.type_name());
}
}
public:
/// @name value access
/// Direct access to the stored value of a JSON value.
/// @{
/*!
@brief get a value (explicit)
Explicit type conversion between the JSON value and a compatible value.
@tparam ValueType non-pointer type compatible to the JSON value, for
instance `int` for JSON integer numbers, `bool` for JSON booleans, or
`std::vector` types for JSON arrays
@return copy of the JSON value, converted to type @a ValueType
@throw std::domain_error in case passed type @a ValueType is incompatible
to JSON; example: `"type must be object, but is null"`
@complexity Linear in the size of the JSON value.
@liveexample{The example below shows several conversions from JSON values
to other types. There a few things to note: (1) Floating-point numbers can
be converted to integers\, (2) A JSON array can be converted to a standard
`std::vector<short>`\, (3) A JSON object can be converted to C++
associative containers such as `std::unordered_map<std::string\,
json>`.,get__ValueType_const}
@internal
The idea of using a casted null pointer to choose the correct
implementation is from <http://stackoverflow.com/a/8315197/266378>.
@endinternal
@sa @ref operator ValueType() const for implicit conversion
@sa @ref get() for pointer-member access
@since version 1.0.0
*/
template<typename ValueType, typename std::enable_if<
not std::is_pointer<ValueType>::value, int>::type = 0>
ValueType get() const
{
return get_impl(static_cast<ValueType*>(nullptr));
}
/*!
@brief get a pointer value (explicit)
Explicit pointer access to the internally stored JSON value. No copies are
made.
@warning The pointer becomes invalid if the underlying JSON object
changes.
@tparam PointerType pointer type; must be a pointer to @ref array_t, @ref
object_t, @ref string_t, @ref boolean_t, @ref number_integer_t,
@ref number_unsigned_t, or @ref number_float_t.
@return pointer to the internally stored JSON value if the requested
pointer type @a PointerType fits to the JSON value; `nullptr` otherwise
@complexity Constant.
@liveexample{The example below shows how pointers to internal values of a
JSON value can be requested. Note that no type conversions are made and a
`nullptr` is returned if the value and the requested pointer type does not
match.,get__PointerType}
@sa @ref get_ptr() for explicit pointer-member access
@since version 1.0.0
*/
template<typename PointerType, typename std::enable_if<
std::is_pointer<PointerType>::value, int>::type = 0>
PointerType get() noexcept
{
// delegate the call to get_ptr
return get_ptr<PointerType>();
}
/*!
@brief get a pointer value (explicit)
@copydoc get()
*/
template<typename PointerType, typename std::enable_if<
std::is_pointer<PointerType>::value, int>::type = 0>
constexpr const PointerType get() const noexcept
{
// delegate the call to get_ptr
return get_ptr<PointerType>();
}
/*!
@brief get a pointer value (implicit)
Implicit pointer access to the internally stored JSON value. No copies are
made.
@warning Writing data to the pointee of the result yields an undefined
state.
@tparam PointerType pointer type; must be a pointer to @ref array_t, @ref
object_t, @ref string_t, @ref boolean_t, @ref number_integer_t,
@ref number_unsigned_t, or @ref number_float_t. Enforced by a static
assertion.
@return pointer to the internally stored JSON value if the requested
pointer type @a PointerType fits to the JSON value; `nullptr` otherwise
@complexity Constant.
@liveexample{The example below shows how pointers to internal values of a
JSON value can be requested. Note that no type conversions are made and a
`nullptr` is returned if the value and the requested pointer type does not
match.,get_ptr}
@since version 1.0.0
*/
template<typename PointerType, typename std::enable_if<
std::is_pointer<PointerType>::value, int>::type = 0>
PointerType get_ptr() noexcept
{
// get the type of the PointerType (remove pointer and const)
using pointee_t = typename std::remove_const<typename
std::remove_pointer<typename
std::remove_const<PointerType>::type>::type>::type;
// make sure the type matches the allowed types
static_assert(
std::is_same<object_t, pointee_t>::value
or std::is_same<array_t, pointee_t>::value
or std::is_same<string_t, pointee_t>::value
or std::is_same<boolean_t, pointee_t>::value
or std::is_same<number_integer_t, pointee_t>::value
or std::is_same<number_unsigned_t, pointee_t>::value
or std::is_same<number_float_t, pointee_t>::value
, "incompatible pointer type");
// delegate the call to get_impl_ptr<>()
return get_impl_ptr(static_cast<PointerType>(nullptr));
}
/*!
@brief get a pointer value (implicit)
@copydoc get_ptr()
*/
template<typename PointerType, typename std::enable_if<
std::is_pointer<PointerType>::value and
std::is_const<typename std::remove_pointer<PointerType>::type>::value, int>::type = 0>
constexpr const PointerType get_ptr() const noexcept
{
// get the type of the PointerType (remove pointer and const)
using pointee_t = typename std::remove_const<typename
std::remove_pointer<typename
std::remove_const<PointerType>::type>::type>::type;
// make sure the type matches the allowed types
static_assert(
std::is_same<object_t, pointee_t>::value
or std::is_same<array_t, pointee_t>::value
or std::is_same<string_t, pointee_t>::value
or std::is_same<boolean_t, pointee_t>::value
or std::is_same<number_integer_t, pointee_t>::value
or std::is_same<number_unsigned_t, pointee_t>::value
or std::is_same<number_float_t, pointee_t>::value
, "incompatible pointer type");
// delegate the call to get_impl_ptr<>() const
return get_impl_ptr(static_cast<const PointerType>(nullptr));
}
/*!
@brief get a reference value (implicit)
Implict reference access to the internally stored JSON value. No copies
are made.
@warning Writing data to the referee of the result yields an undefined
state.
@tparam ReferenceType reference type; must be a reference to @ref array_t,
@ref object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, or
@ref number_float_t. Enforced by static assertion.
@return reference to the internally stored JSON value if the requested
reference type @a ReferenceType fits to the JSON value; throws
std::domain_error otherwise
@throw std::domain_error in case passed type @a ReferenceType is
incompatible with the stored JSON value
@complexity Constant.
@liveexample{The example shows several calls to `get_ref()`.,get_ref}
@since version 1.1.0
*/
template<typename ReferenceType, typename std::enable_if<
std::is_reference<ReferenceType>::value, int>::type = 0>
ReferenceType get_ref()
{
// delegate call to get_ref_impl
return get_ref_impl<ReferenceType>(*this);
}
/*!
@brief get a reference value (implicit)
@copydoc get_ref()
*/
template<typename ReferenceType, typename std::enable_if<
std::is_reference<ReferenceType>::value and
std::is_const<typename std::remove_reference<ReferenceType>::type>::value, int>::type = 0>
ReferenceType get_ref() const
{
// delegate call to get_ref_impl
return get_ref_impl<ReferenceType>(*this);
}
/*!
@brief get a value (implicit)
Implicit type conversion between the JSON value and a compatible value.
The call is realized by calling @ref get() const.
@tparam ValueType non-pointer type compatible to the JSON value, for
instance `int` for JSON integer numbers, `bool` for JSON booleans, or
`std::vector` types for JSON arrays. The character type of @ref string_t
as well as an initializer list of this type is excluded to avoid
ambiguities as these types implicitly convert to `std::string`.
@return copy of the JSON value, converted to type @a ValueType
@throw std::domain_error in case passed type @a ValueType is incompatible
to JSON, thrown by @ref get() const
@complexity Linear in the size of the JSON value.
@liveexample{The example below shows several conversions from JSON values
to other types. There a few things to note: (1) Floating-point numbers can
be converted to integers\, (2) A JSON array can be converted to a standard
`std::vector<short>`\, (3) A JSON object can be converted to C++
associative containers such as `std::unordered_map<std::string\,
json>`.,operator__ValueType}
@since version 1.0.0
*/
template < typename ValueType, typename std::enable_if <
not std::is_pointer<ValueType>::value and
not std::is_same<ValueType, typename string_t::value_type>::value
#ifndef _MSC_VER // Fix for issue #167 operator<< abiguity under VS2015
and not std::is_same<ValueType, std::initializer_list<typename string_t::value_type>>::value
#endif
, int >::type = 0 >
operator ValueType() const
{
// delegate the call to get<>() const
return get<ValueType>();
}
/// @}
////////////////////
// element access //
////////////////////
/// @name element access
/// Access to the JSON value.
/// @{
/*!
@brief access specified array element with bounds checking
Returns a reference to the element at specified location @a idx, with
bounds checking.
@param[in] idx index of the element to access
@return reference to the element at index @a idx
@throw std::domain_error if the JSON value is not an array; example:
`"cannot use at() with string"`
@throw std::out_of_range if the index @a idx is out of range of the array;
that is, `idx >= size()`; example: `"array index 7 is out of range"`
@complexity Constant.
@liveexample{The example below shows how array elements can be read and
written using `at()`.,at__size_type}
@since version 1.0.0
*/
reference at(size_type idx)
{
// at only works for arrays
if (is_array())
{
try
{
return m_value.array->at(idx);
}
catch (std::out_of_range&)
{
// create better exception explanation
throw std::out_of_range("array index " + std::to_string(idx) + " is out of range");
}
}
else
{
throw std::domain_error("cannot use at() with " + type_name());
}
}
/*!
@brief access specified array element with bounds checking
Returns a const reference to the element at specified location @a idx,
with bounds checking.
@param[in] idx index of the element to access
@return const reference to the element at index @a idx
@throw std::domain_error if the JSON value is not an array; example:
`"cannot use at() with string"`
@throw std::out_of_range if the index @a idx is out of range of the array;
that is, `idx >= size()`; example: `"array index 7 is out of range"`
@complexity Constant.
@liveexample{The example below shows how array elements can be read using
`at()`.,at__size_type_const}
@since version 1.0.0
*/
const_reference at(size_type idx) const
{
// at only works for arrays
if (is_array())
{
try
{
return m_value.array->at(idx);
}
catch (std::out_of_range&)
{
// create better exception explanation
throw std::out_of_range("array index " + std::to_string(idx) + " is out of range");
}
}
else
{
throw std::domain_error("cannot use at() with " + type_name());
}
}
/*!
@brief access specified object element with bounds checking
Returns a reference to the element at with specified key @a key, with
bounds checking.
@param[in] key key of the element to access
@return reference to the element at key @a key
@throw std::domain_error if the JSON value is not an object; example:
`"cannot use at() with boolean"`
@throw std::out_of_range if the key @a key is is not stored in the object;
that is, `find(key) == end()`; example: `"key "the fast" not found"`
@complexity Logarithmic in the size of the container.
@liveexample{The example below shows how object elements can be read and
written using `at()`.,at__object_t_key_type}
@sa @ref operator[](const typename object_t::key_type&) for unchecked
access by reference
@sa @ref value() for access by value with a default value
@since version 1.0.0
*/
reference at(const typename object_t::key_type& key)
{
// at only works for objects
if (is_object())
{
try
{
return m_value.object->at(key);
}
catch (std::out_of_range&)
{
// create better exception explanation
throw std::out_of_range("key '" + key + "' not found");
}
}
else
{
throw std::domain_error("cannot use at() with " + type_name());
}
}
/*!
@brief access specified object element with bounds checking
Returns a const reference to the element at with specified key @a key,
with bounds checking.
@param[in] key key of the element to access
@return const reference to the element at key @a key
@throw std::domain_error if the JSON value is not an object; example:
`"cannot use at() with boolean"`
@throw std::out_of_range if the key @a key is is not stored in the object;
that is, `find(key) == end()`; example: `"key "the fast" not found"`
@complexity Logarithmic in the size of the container.
@liveexample{The example below shows how object elements can be read using
`at()`.,at__object_t_key_type_const}
@sa @ref operator[](const typename object_t::key_type&) for unchecked
access by reference
@sa @ref value() for access by value with a default value
@since version 1.0.0
*/
const_reference at(const typename object_t::key_type& key) const
{
// at only works for objects
if (is_object())
{
try
{
return m_value.object->at(key);
}
catch (std::out_of_range&)
{
// create better exception explanation
throw std::out_of_range("key '" + key + "' not found");
}
}
else
{
throw std::domain_error("cannot use at() with " + type_name());
}
}
/*!
@brief access specified array element
Returns a reference to the element at specified location @a idx.
@note If @a idx is beyond the range of the array (i.e., `idx >= size()`),
then the array is silently filled up with `null` values to make `idx` a
valid reference to the last stored element.
@param[in] idx index of the element to access
@return reference to the element at index @a idx
@throw std::domain_error if JSON is not an array or null; example:
`"cannot use operator[] with string"`
@complexity Constant if @a idx is in the range of the array. Otherwise
linear in `idx - size()`.
@liveexample{The example below shows how array elements can be read and
written using `[]` operator. Note the addition of `null`
values.,operatorarray__size_type}
@since version 1.0.0
*/
reference operator[](size_type idx)
{
// implicitly convert null value to an empty array
if (is_null())
{
m_type = value_t::array;
m_value.array = create<array_t>();
assert_invariant();
}
// operator[] only works for arrays
if (is_array())
{
// fill up array with null values if given idx is outside range
if (idx >= m_value.array->size())
{
m_value.array->insert(m_value.array->end(),
idx - m_value.array->size() + 1,
basic_json());
}
return m_value.array->operator[](idx);
}
else
{
throw std::domain_error("cannot use operator[] with " + type_name());
}
}
/*!
@brief access specified array element
Returns a const reference to the element at specified location @a idx.
@param[in] idx index of the element to access
@return const reference to the element at index @a idx
@throw std::domain_error if JSON is not an array; example: `"cannot use
operator[] with null"`
@complexity Constant.
@liveexample{The example below shows how array elements can be read using
the `[]` operator.,operatorarray__size_type_const}
@since version 1.0.0
*/
const_reference operator[](size_type idx) const
{
// const operator[] only works for arrays
if (is_array())
{
return m_value.array->operator[](idx);
}
else
{
throw std::domain_error("cannot use operator[] with " + type_name());
}
}
/*!
@brief access specified object element
Returns a reference to the element at with specified key @a key.
@note If @a key is not found in the object, then it is silently added to
the object and filled with a `null` value to make `key` a valid reference.
In case the value was `null` before, it is converted to an object.
@param[in] key key of the element to access
@return reference to the element at key @a key
@throw std::domain_error if JSON is not an object or null; example:
`"cannot use operator[] with string"`
@complexity Logarithmic in the size of the container.
@liveexample{The example below shows how object elements can be read and
written using the `[]` operator.,operatorarray__key_type}
@sa @ref at(const typename object_t::key_type&) for access by reference
with range checking
@sa @ref value() for access by value with a default value
@since version 1.0.0
*/
reference operator[](const typename object_t::key_type& key)
{
// implicitly convert null value to an empty object
if (is_null())
{
m_type = value_t::object;
m_value.object = create<object_t>();
assert_invariant();
}
// operator[] only works for objects
if (is_object())
{
return m_value.object->operator[](key);
}
else
{
throw std::domain_error("cannot use operator[] with " + type_name());
}
}
/*!
@brief read-only access specified object element
Returns a const reference to the element at with specified key @a key. No
bounds checking is performed.
@warning If the element with key @a key does not exist, the behavior is
undefined.
@param[in] key key of the element to access
@return const reference to the element at key @a key
@pre The element with key @a key must exist. **This precondition is
enforced with an assertion.**
@throw std::domain_error if JSON is not an object; example: `"cannot use
operator[] with null"`
@complexity Logarithmic in the size of the container.
@liveexample{The example below shows how object elements can be read using
the `[]` operator.,operatorarray__key_type_const}
@sa @ref at(const typename object_t::key_type&) for access by reference
with range checking
@sa @ref value() for access by value with a default value
@since version 1.0.0
*/
const_reference operator[](const typename object_t::key_type& key) const
{
// const operator[] only works for objects
if (is_object())
{
assert(m_value.object->find(key) != m_value.object->end());
return m_value.object->find(key)->second;
}
else
{
throw std::domain_error("cannot use operator[] with " + type_name());
}
}
/*!
@brief access specified object element
Returns a reference to the element at with specified key @a key.
@note If @a key is not found in the object, then it is silently added to
the object and filled with a `null` value to make `key` a valid reference.
In case the value was `null` before, it is converted to an object.
@param[in] key key of the element to access
@return reference to the element at key @a key
@throw std::domain_error if JSON is not an object or null; example:
`"cannot use operator[] with string"`
@complexity Logarithmic in the size of the container.
@liveexample{The example below shows how object elements can be read and
written using the `[]` operator.,operatorarray__key_type}
@sa @ref at(const typename object_t::key_type&) for access by reference
with range checking
@sa @ref value() for access by value with a default value
@since version 1.0.0
*/
template<typename T, std::size_t n>
reference operator[](T * (&key)[n])
{
return operator[](static_cast<const T>(key));
}
/*!
@brief read-only access specified object element
Returns a const reference to the element at with specified key @a key. No
bounds checking is performed.
@warning If the element with key @a key does not exist, the behavior is
undefined.
@note This function is required for compatibility reasons with Clang.
@param[in] key key of the element to access
@return const reference to the element at key @a key
@throw std::domain_error if JSON is not an object; example: `"cannot use
operator[] with null"`
@complexity Logarithmic in the size of the container.
@liveexample{The example below shows how object elements can be read using
the `[]` operator.,operatorarray__key_type_const}
@sa @ref at(const typename object_t::key_type&) for access by reference
with range checking
@sa @ref value() for access by value with a default value
@since version 1.0.0
*/
template<typename T, std::size_t n>
const_reference operator[](T * (&key)[n]) const
{
return operator[](static_cast<const T>(key));
}
/*!
@brief access specified object element
Returns a reference to the element at with specified key @a key.
@note If @a key is not found in the object, then it is silently added to
the object and filled with a `null` value to make `key` a valid reference.
In case the value was `null` before, it is converted to an object.
@param[in] key key of the element to access
@return reference to the element at key @a key
@throw std::domain_error if JSON is not an object or null; example:
`"cannot use operator[] with string"`
@complexity Logarithmic in the size of the container.
@liveexample{The example below shows how object elements can be read and
written using the `[]` operator.,operatorarray__key_type}
@sa @ref at(const typename object_t::key_type&) for access by reference
with range checking
@sa @ref value() for access by value with a default value
@since version 1.1.0
*/
template<typename T>
reference operator[](T* key)
{
// implicitly convert null to object
if (is_null())
{
m_type = value_t::object;
m_value = value_t::object;
assert_invariant();
}
// at only works for objects
if (is_object())
{
return m_value.object->operator[](key);
}
else
{
throw std::domain_error("cannot use operator[] with " + type_name());
}
}
/*!
@brief read-only access specified object element
Returns a const reference to the element at with specified key @a key. No
bounds checking is performed.
@warning If the element with key @a key does not exist, the behavior is
undefined.
@param[in] key key of the element to access
@return const reference to the element at key @a key
@pre The element with key @a key must exist. **This precondition is
enforced with an assertion.**
@throw std::domain_error if JSON is not an object; example: `"cannot use
operator[] with null"`
@complexity Logarithmic in the size of the container.
@liveexample{The example below shows how object elements can be read using
the `[]` operator.,operatorarray__key_type_const}
@sa @ref at(const typename object_t::key_type&) for access by reference
with range checking
@sa @ref value() for access by value with a default value
@since version 1.1.0
*/
template<typename T>
const_reference operator[](T* key) const
{
// at only works for objects
if (is_object())
{
assert(m_value.object->find(key) != m_value.object->end());
return m_value.object->find(key)->second;
}
else
{
throw std::domain_error("cannot use operator[] with " + type_name());
}
}
/*!
@brief access specified object element with default value
Returns either a copy of an object's element at the specified key @a key
or a given default value if no element with key @a key exists.
The function is basically equivalent to executing
@code {.cpp}
try {
return at(key);
} catch(std::out_of_range) {
return default_value;
}
@endcode
@note Unlike @ref at(const typename object_t::key_type&), this function
does not throw if the given key @a key was not found.
@note Unlike @ref operator[](const typename object_t::key_type& key), this
function does not implicitly add an element to the position defined by @a
key. This function is furthermore also applicable to const objects.
@param[in] key key of the element to access
@param[in] default_value the value to return if @a key is not found
@tparam ValueType type compatible to JSON values, for instance `int` for
JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for
JSON arrays. Note the type of the expected value at @a key and the default
value @a default_value must be compatible.
@return copy of the element at key @a key or @a default_value if @a key
is not found
@throw std::domain_error if JSON is not an object; example: `"cannot use
value() with null"`
@complexity Logarithmic in the size of the container.
@liveexample{The example below shows how object elements can be queried
with a default value.,basic_json__value}
@sa @ref at(const typename object_t::key_type&) for access by reference
with range checking
@sa @ref operator[](const typename object_t::key_type&) for unchecked
access by reference
@since version 1.0.0
*/
template<class ValueType, typename std::enable_if<
std::is_convertible<basic_json_t, ValueType>::value, int>::type = 0>
ValueType value(const typename object_t::key_type& key, ValueType default_value) const
{
// at only works for objects
if (is_object())
{
// if key is found, return value and given default value otherwise
const auto it = find(key);
if (it != end())
{
return *it;
}
else
{
return default_value;
}
}
else
{
throw std::domain_error("cannot use value() with " + type_name());
}
}
/*!
@brief overload for a default value of type const char*
@copydoc basic_json::value(const typename object_t::key_type&, ValueType) const
*/
string_t value(const typename object_t::key_type& key, const char* default_value) const
{
return value(key, string_t(default_value));
}
/*!
@brief access specified object element via JSON Pointer with default value
Returns either a copy of an object's element at the specified key @a key
or a given default value if no element with key @a key exists.
The function is basically equivalent to executing
@code {.cpp}
try {
return at(ptr);
} catch(std::out_of_range) {
return default_value;
}
@endcode
@note Unlike @ref at(const json_pointer&), this function does not throw
if the given key @a key was not found.
@param[in] ptr a JSON pointer to the element to access
@param[in] default_value the value to return if @a ptr found no value
@tparam ValueType type compatible to JSON values, for instance `int` for
JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for
JSON arrays. Note the type of the expected value at @a key and the default
value @a default_value must be compatible.
@return copy of the element at key @a key or @a default_value if @a key
is not found
@throw std::domain_error if JSON is not an object; example: `"cannot use
value() with null"`
@complexity Logarithmic in the size of the container.
@liveexample{The example below shows how object elements can be queried
with a default value.,basic_json__value_ptr}
@sa @ref operator[](const json_pointer&) for unchecked access by reference
@since version 2.0.2
*/
template<class ValueType, typename std::enable_if<
std::is_convertible<basic_json_t, ValueType>::value, int>::type = 0>
ValueType value(const json_pointer& ptr, ValueType default_value) const
{
// at only works for objects
if (is_object())
{
// if pointer resolves a value, return it or use default value
try
{
return ptr.get_checked(this);
}
catch (std::out_of_range&)
{
return default_value;
}
}
else
{
throw std::domain_error("cannot use value() with " + type_name());
}
}
/*!
@brief overload for a default value of type const char*
@copydoc basic_json::value(const json_pointer&, ValueType) const
*/
string_t value(const json_pointer& ptr, const char* default_value) const
{
return value(ptr, string_t(default_value));
}
/*!
@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 structured type (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.
@pre The JSON value must not be `null` (would throw `std::out_of_range`)
or an empty array or object (undefined behavior, **guarded by
assertions**).
@post The JSON value remains unchanged.
@throw std::out_of_range when called on `null` value
@liveexample{The following code shows an example for `front()`.,front}
@sa @ref back() -- access the last element
@since version 1.0.0
*/
reference front()
{
return *begin();
}
/*!
@copydoc basic_json::front()
*/
const_reference front() const
{
return *cbegin();
}
/*!
@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
@code {.cpp}
auto tmp = c.end();
--tmp;
return *tmp;
@endcode
@return In case of a structured type (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.
@pre The JSON value must not be `null` (would throw `std::out_of_range`)
or an empty array or object (undefined behavior, **guarded by
assertions**).
@post The JSON value remains unchanged.
@throw std::out_of_range when called on `null` value.
@liveexample{The following code shows an example for `back()`.,back}
@sa @ref front() -- access the first element
@since version 1.0.0
*/
reference back()
{
auto tmp = end();
--tmp;
return *tmp;
}
/*!
@copydoc basic_json::back()
*/
const_reference back() const
{
auto tmp = cend();
--tmp;
return *tmp;
}
/*!
@brief remove element given an iterator
Removes the element specified by iterator @a pos. The iterator @a pos must
be valid and dereferenceable. Thus the `end()` iterator (which is valid,
but is not dereferenceable) cannot be used as a value for @a pos.
If called on a primitive type other than `null`, the resulting JSON value
will be `null`.
@param[in] pos iterator to the element to remove
@return Iterator following the last removed element. If the iterator @a
pos refers to the last element, the `end()` iterator is returned.
@tparam IteratorType an @ref iterator or @ref const_iterator
@post Invalidates iterators and references at or after the point of the
erase, including the `end()` iterator.
@throw std::domain_error if called on a `null` value; example: `"cannot
use erase() with null"`
@throw std::domain_error if called on an iterator which does not belong to
the current JSON value; example: `"iterator does not fit current value"`
@throw std::out_of_range if called on a primitive type with invalid
iterator (i.e., any iterator which is not `begin()`); example: `"iterator
out of range"`
@complexity The complexity depends on the type:
- objects: amortized constant
- arrays: linear in distance between pos and the end of the container
- strings: linear in the length of the string
- other types: constant
@liveexample{The example shows the result of `erase()` for different JSON
types.,erase__IteratorType}
@sa @ref erase(IteratorType, IteratorType) -- removes the elements in
the given range
@sa @ref erase(const typename object_t::key_type&) -- removes the element
from an object at the given key
@sa @ref erase(const size_type) -- removes the element from an array at
the given index
@since version 1.0.0
*/
template<class IteratorType, typename std::enable_if<
std::is_same<IteratorType, typename basic_json_t::iterator>::value or
std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int>::type
= 0>
IteratorType erase(IteratorType pos)
{
// make sure iterator fits the current value
if (this != pos.m_object)
{
throw std::domain_error("iterator does not fit current value");
}
IteratorType result = end();
switch (m_type)
{
case value_t::boolean:
case value_t::number_float:
case value_t::number_integer:
case value_t::number_unsigned:
case value_t::string:
{
if (not pos.m_it.primitive_iterator.is_begin())
{
throw std::out_of_range("iterator out of range");
}
if (is_string())
{
AllocatorType<string_t> alloc;
alloc.destroy(m_value.string);
alloc.deallocate(m_value.string, 1);
m_value.string = nullptr;
}
m_type = value_t::null;
assert_invariant();
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:
{
throw std::domain_error("cannot use erase() with " + type_name());
}
}
return result;
}
/*!
@brief remove elements given an iterator range
Removes the element specified by the range `[first; last)`. The iterator
@a first does not need to be dereferenceable if `first == last`: erasing
an empty range is a no-op.
If called on a primitive type other than `null`, the resulting JSON value
will be `null`.
@param[in] first iterator to the beginning of the range to remove
@param[in] last iterator past the end of the range to remove
@return Iterator following the last removed element. If the iterator @a
second refers to the last element, the `end()` iterator is returned.
@tparam IteratorType an @ref iterator or @ref const_iterator
@post Invalidates iterators and references at or after the point of the
erase, including the `end()` iterator.
@throw std::domain_error if called on a `null` value; example: `"cannot
use erase() with null"`
@throw std::domain_error if called on iterators which does not belong to
the current JSON value; example: `"iterators do not fit current value"`
@throw std::out_of_range if called on a primitive type with invalid
iterators (i.e., if `first != begin()` and `last != end()`); example:
`"iterators out of range"`
@complexity The complexity depends on the type:
- objects: `log(size()) + std::distance(first, last)`
- arrays: linear in the distance between @a first and @a last, plus linear
in the distance between @a last and end of the container