Newer
Older
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
///////////////
// from_json //
///////////////
// overloads for basic_json template parameters
template <
typename BasicJsonType, typename ArithmeticType,
enable_if_t<std::is_arithmetic<ArithmeticType>::value and
not std::is_same<ArithmeticType,
typename BasicJsonType::boolean_t>::value,
int> = 0>
void get_arithmetic_value(const BasicJsonType &j, ArithmeticType &val)
{
switch (static_cast<value_t>(j))
{
case value_t::number_unsigned:
{
val = static_cast<ArithmeticType>(
*j.template get_ptr<
const typename BasicJsonType::number_unsigned_t *>());
break;
}
case value_t::number_integer:
{
val = static_cast<ArithmeticType>(
*j.template get_ptr<
const typename BasicJsonType::number_integer_t *>());
break;
}
case value_t::number_float:
{
val = static_cast<ArithmeticType>(
*j.template get_ptr<
const typename BasicJsonType::number_float_t *>());
break;
}
default:
{
JSON_THROW(type_error::create(302, "type must be number, but is " +
j.type_name()));
}
}
}
template <typename BasicJsonType>
void from_json(const BasicJsonType &j, typename BasicJsonType::boolean_t &b)
{
if (not j.is_boolean())
{
JSON_THROW(type_error::create(302, "type must be boolean, but is " +
j.type_name()));
}
b = *j.template get_ptr<const typename BasicJsonType::boolean_t *>();
}
template <typename BasicJsonType>
void from_json(const BasicJsonType &j, typename BasicJsonType::string_t &s)
{
if (not j.is_string())
{
JSON_THROW(type_error::create(302, "type must be string, but is " +
j.type_name()));
}
s = *j.template get_ptr<const typename BasicJsonType::string_t *>();
}
template <typename BasicJsonType>
void from_json(const BasicJsonType &j,
typename BasicJsonType::number_float_t &val)
{
get_arithmetic_value(j, val);
}
template <typename BasicJsonType>
void from_json(const BasicJsonType &j,
typename BasicJsonType::number_unsigned_t &val)
{
get_arithmetic_value(j, val);
}
template <typename BasicJsonType>
void from_json(const BasicJsonType &j,
typename BasicJsonType::number_integer_t &val)
{
get_arithmetic_value(j, val);
}
template <typename BasicJsonType, typename EnumType,
enable_if_t<std::is_enum<EnumType>::value, int> = 0>
void from_json(const BasicJsonType &j, EnumType &e)
{
typename std::underlying_type<EnumType>::type val;
get_arithmetic_value(j, val);
e = static_cast<EnumType>(val);
}
template <typename BasicJsonType>
void from_json(const BasicJsonType &j, typename BasicJsonType::array_t &arr)
{
if (not j.is_array())
{
JSON_THROW(type_error::create(302, "type must be array, but is " +
j.type_name()));
}
arr = *j.template get_ptr<const typename BasicJsonType::array_t *>();
}
// forward_list doesn't have an insert method
template <typename BasicJsonType, typename T, typename Allocator,
enable_if_t<std::is_convertible<BasicJsonType, T>::value, int> = 0>
void from_json(const BasicJsonType &j, std::forward_list<T, Allocator> &l)
{
if (not j.is_array())
{
JSON_THROW(type_error::create(302, "type must be array, but is " +
j.type_name()));
}
for (auto it = j.rbegin(), end = j.rend(); it != end; ++it)
{
l.push_front(it->template get<T>());
}
}
template <typename BasicJsonType, typename CompatibleArrayType>
void from_json_array_impl(const BasicJsonType &j, CompatibleArrayType &arr,
priority_tag<0>)
{
using std::begin;
using std::end;
std::transform(
j.begin(), j.end(), std::inserter(arr, end(arr)),
[](const BasicJsonType &i) {
// get<BasicJsonType>() returns *this, this won't call a from_json
// method when value_type is BasicJsonType
return i.template get<typename CompatibleArrayType::value_type>();
});
}
template <typename BasicJsonType, typename CompatibleArrayType>
auto from_json_array_impl(const BasicJsonType &j, CompatibleArrayType &arr,
priority_tag<1>)
-> decltype(
arr.reserve(std::declval<typename CompatibleArrayType::size_type>()),
void())
{
using std::begin;
using std::end;
arr.reserve(j.size());
std::transform(
j.begin(), j.end(), std::inserter(arr, end(arr)),
[](const BasicJsonType &i) {
// get<BasicJsonType>() returns *this, this won't call a from_json
// method when value_type is BasicJsonType
return i.template get<typename CompatibleArrayType::value_type>();
});
}
template <
typename BasicJsonType, typename CompatibleArrayType,
enable_if_t<
is_compatible_array_type<BasicJsonType, CompatibleArrayType>::value and
std::is_convertible<BasicJsonType, typename CompatibleArrayType::
value_type>::value and
not std::is_same<typename BasicJsonType::array_t,
CompatibleArrayType>::value,
int> = 0>
void from_json(const BasicJsonType &j, CompatibleArrayType &arr)
{
if (not j.is_array())
{
JSON_THROW(type_error::create(302, "type must be array, but is " +
j.type_name()));
}
from_json_array_impl(j, arr, priority_tag<1>{});
}
template <typename BasicJsonType, typename CompatibleObjectType,
enable_if_t<is_compatible_object_type<BasicJsonType,
CompatibleObjectType>::value,
int> = 0>
void from_json(const BasicJsonType &j, CompatibleObjectType &obj)
{
if (not j.is_object())
{
JSON_THROW(type_error::create(302, "type must be object, but is " +
j.type_name()));
}
auto inner_object =
j.template get_ptr<const typename BasicJsonType::object_t *>();
using std::begin;
using std::end;
// we could avoid the assignment, but this might require a for loop, which
// might be less efficient than the container constructor for some
// containers (would it?)
obj = CompatibleObjectType(begin(*inner_object), end(*inner_object));
}
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
// overload for arithmetic types, not chosen for basic_json template arguments
// (BooleanType, etc..); note: Is it really necessary to provide explicit
// overloads for boolean_t etc. in case of a custom BooleanType which is not
// an arithmetic type?
template <
typename BasicJsonType, typename ArithmeticType,
enable_if_t<
std::is_arithmetic<ArithmeticType>::value and
not std::is_same<ArithmeticType, typename BasicJsonType::
number_unsigned_t>::value and
not std::is_same<ArithmeticType, typename BasicJsonType::
number_integer_t>::value and
not std::is_same<ArithmeticType,
typename BasicJsonType::number_float_t>::value and
not std::is_same<ArithmeticType,
typename BasicJsonType::boolean_t>::value,
int> = 0>
void from_json(const BasicJsonType &j, ArithmeticType &val)
{
switch (static_cast<value_t>(j))
{
case value_t::number_unsigned:
{
val = static_cast<ArithmeticType>(
*j.template get_ptr<
const typename BasicJsonType::number_unsigned_t *>());
break;
}
case value_t::number_integer:
{
val = static_cast<ArithmeticType>(
*j.template get_ptr<
const typename BasicJsonType::number_integer_t *>());
break;
}
case value_t::number_float:
{
val = static_cast<ArithmeticType>(
*j.template get_ptr<
const typename BasicJsonType::number_float_t *>());
break;
}
case value_t::boolean:
{
val = static_cast<ArithmeticType>(
*j.template get_ptr<const typename BasicJsonType::boolean_t *>());
break;
}
default:
{
JSON_THROW(type_error::create(302, "type must be number, but is " +
j.type_name()));
}
}
}
struct to_json_fn
{
private:
template <typename BasicJsonType, typename T>
auto call(BasicJsonType &j, T &&val, priority_tag<1>) const
noexcept(noexcept(to_json(j, std::forward<T>(val))))
-> decltype(to_json(j, std::forward<T>(val)), void())
{
return to_json(j, std::forward<T>(val));
}
template <typename BasicJsonType, typename T>
void call(BasicJsonType &, T &&, priority_tag<0>) const noexcept
{
static_assert(sizeof(BasicJsonType) == 0,
"could not find to_json() method in T's namespace");
}
public:
template <typename BasicJsonType, typename T>
void operator()(BasicJsonType &j, T &&val) const
noexcept(noexcept(std::declval<to_json_fn>().call(j,
std::forward<T>(val),
priority_tag<1>{})))
{
return call(j, std::forward<T>(val), priority_tag<1>{});
}
};
struct from_json_fn
{
private:
template <typename BasicJsonType, typename T>
auto call(const BasicJsonType &j, T &val, priority_tag<1>) const
noexcept(noexcept(from_json(j, val)))
-> decltype(from_json(j, val), void())
{
return from_json(j, val);
}
template <typename BasicJsonType, typename T>
void call(const BasicJsonType &, T &, priority_tag<0>) const noexcept
{
static_assert(sizeof(BasicJsonType) == 0,
"could not find from_json() method in T's namespace");
}
public:
template <typename BasicJsonType, typename T>
void operator()(const BasicJsonType &j, T &val) const
noexcept(noexcept(std::declval<from_json_fn>().call(j, val,
priority_tag<1>{})))
{
return call(j, val, priority_tag<1>{});
}
};
// taken from ranges-v3
template <typename T>
struct static_const
{
static constexpr T value{};
};
template <typename T>
constexpr T static_const<T>::value;
} // namespace detail
/// namespace to hold default `to_json` / `from_json` functions
namespace
{
constexpr const auto &to_json = detail::static_const<detail::to_json_fn>::value;
constexpr const auto &from_json =
detail::static_const<detail::from_json_fn>::value;
}
/*!
@brief default JSONSerializer template argument
This serializer ignores the template arguments and uses ADL
([argument-dependent lookup](http://en.cppreference.com/w/cpp/language/adl))
for serialization.
*/
template <typename = void, typename = void>
struct adl_serializer
{
/*!
@brief convert a JSON value to any value type
This function is usually called by the `get()` function of the
@ref basic_json class (either explicit or via conversion operators).
@param[in] j JSON value to read from
@param[in,out] val value to write to
template <typename BasicJsonType, typename ValueType>
static void from_json(BasicJsonType &&j, ValueType &val) noexcept(
noexcept(::nlohmann::from_json(std::forward<BasicJsonType>(j), val)))
{
::nlohmann::from_json(std::forward<BasicJsonType>(j), val);
}
@brief convert any value type to a JSON value
This function is usually called by the constructors of the @ref basic_json
class.
@param[in,out] j JSON value to write to
@param[in] val value to read from
*/
template <typename BasicJsonType, typename ValueType>
static void to_json(BasicJsonType &j, ValueType &&val) noexcept(
noexcept(::nlohmann::to_json(j, std::forward<ValueType>(val))))
{
::nlohmann::to_json(j, std::forward<ValueType>(val));
}
};
/*!
@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)
@tparam JSONSerializer the serializer to resolve internal calls to `to_json()`
and `from_json()` (@ref adl_serializer by default)
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
@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)
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
@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,
template <typename T, typename SFINAE = void> class JSONSerializer =
adl_serializer>
class basic_json
{
private:
template <detail::value_t>
friend struct detail::external_constructor;
/// workaround type for MSVC
using basic_json_t =
basic_json<ObjectType, ArrayType, StringType, BooleanType,
NumberIntegerType, NumberUnsignedType, NumberFloatType,
AllocatorType, JSONSerializer>;
public:
using value_t = detail::value_t;
// forward declarations
template <typename U>
class iter_impl;
template <typename Base>
class json_reverse_iterator;
class json_pointer;
template <typename T, typename SFINAE>
using json_serializer = JSONSerializer<T, SFINAE>;
////////////////
// exceptions //
////////////////
/// @name exceptions
/// Classes to implement user-defined exceptions.
/// @{
/// @copydoc detail::exception
using exception = detail::exception;
/// @copydoc detail::parse_error
using parse_error = detail::parse_error;
/// @copydoc detail::invalid_iterator
using invalid_iterator = detail::invalid_iterator;
/// @copydoc detail::type_error
using type_error = detail::type_error;
/// @copydoc detail::out_of_range
using out_of_range = detail::out_of_range;
/// @copydoc detail::other_error
using other_error = detail::other_error;
/////////////////////
// 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
using iterator = iter_impl<basic_json>;
/// a const iterator for a basic_json container
using const_iterator = iter_impl<const basic_json>;
/// 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(); }
/*!
@brief returns version information on the library
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
This function returns a JSON object with information about the library,
including the version number and information on the platform and compiler.
@return JSON object holding version information
key | description
----------- | ---------------
`compiler` | Information on the used compiler. It is an object with the
following keys: `c++` (the used C++ standard), `family` (the compiler
family; possible values are `clang`, `icc`, `gcc`, `ilecpp`, `msvc`,
`pgcpp`, `sunpro`, and `unknown`), and `version` (the compiler version).
`copyright` | The copyright line for the library as string.
`name` | The name of the library as string.
`platform` | The used platform as string. Possible values are `win32`,
`linux`, `apple`, `unix`, and `unknown`.
`url` | The URL of the project as string.
`version` | The version of the library. It is an object with the following
keys: `major`, `minor`, and `patch` as defined by [Semantic
Versioning](http://semver.org), and `string` (the version string).
@liveexample{The following code shows an example output of the `meta()`
function.,meta}
result["copyright"] = "(C) 2013-2017 Niels Lohmann";
result["name"] = "JSON for Modern C++";
result["url"] = "https://github.com/nlohmann/json";
result["version"] = {
{"string", "2.1.1"}, {"major", 2}, {"minor", 1}, {"patch", 1}};
#ifdef _WIN32
result["platform"] = "win32";
#elif defined __linux__
result["platform"] = "linux";
#elif defined __APPLE__
result["platform"] = "apple";
#elif defined __unix__
result["platform"] = "unix";
#else
result["platform"] = "unknown";
#endif
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
#if defined(__clang__)
result["compiler"] = {{"family", "clang"},
{"version", __clang_version__}};
#elif defined(__ICC) || defined(__INTEL_COMPILER)
result["compiler"] = {{"family", "icc"}, {"version", __INTEL_COMPILER}};
#elif defined(__GNUC__) || defined(__GNUG__)
result["compiler"] = {
{"family", "gcc"},
{"version", std::to_string(__GNUC__) + "." +
std::to_string(__GNUC_MINOR__) + "." +
std::to_string(__GNUC_PATCHLEVEL__)}};
#elif defined(__HP_cc) || defined(__HP_aCC)
result["compiler"] = "hp"
#elif defined(__IBMCPP__)
result["compiler"] = {{"family", "ilecpp"}, {"version", __IBMCPP__}};
#elif defined(_MSC_VER)
result["compiler"] = {{"family", "msvc"}, {"version", _MSC_VER}};
#elif defined(__PGI)
result["compiler"] = {{"family", "pgcpp"}, {"version", __PGI}};
#elif defined(__SUNPRO_CC)
result["compiler"] = {{"family", "sunpro"}, {"version", __SUNPRO_CC}};
#else
result["compiler"] = {{"family", "unknown"}, {"version", "unknown"}};
#endif
#ifdef __cplusplus
result["compiler"]["c++"] = std::to_string(__cplusplus);
#else
result["compiler"]["c++"] = "unknown";
#endif
return result;
}
///////////////////////////
// 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.
/// @{
[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`)
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
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.
[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.
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`)
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
[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.
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>>;
[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.
With the default values for @a StringType (`std::string`), the default
value for @a string_t is:
@code {.cpp}
std::string
@endcode
Strings are stored in UTF-8 encoding. Therefore, functions like
`std::string::size()` or `std::string::length()` return the number of
bytes in the string rather than the number of characters or glyphs.
#### 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
*/
[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.
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
*/
@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.
With the default values for @a NumberIntegerType (`int64_t`), the default
value for @a number_integer_t is:
- 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`.
[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.
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.
With the default values for @a NumberUnsignedType (`uint64_t`), the
default value for @a number_unsigned_t is:
@code {.cpp}
uint64_t
@endcode
- 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`.
[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: