Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fc3b716675 | ||
|
|
f268cab0a3 | ||
|
|
93ccdc2738 | ||
|
|
46b6daec9f |
No files matched your search
@@ -19,23 +19,26 @@ For the types below, the conversion works directly on the flat index -- no `Basi
|
||||
document's own buffer of decoded strings (see [`get_string()`](get_string.md))
|
||||
- `BasicJsonType` -- equivalent to [`materialize()`](materialize.md)
|
||||
- `basic_json_view` -- returns `#!cpp *this`
|
||||
- `#!cpp std::vector<U, A>` -- from an array, element by element, each converted with `#!cpp get<U>()`; `#!cpp
|
||||
std::vector<basic_json_view>` keeps a view of every element instead of a value
|
||||
- `#!cpp std::map<K, V, C, A>` and `#!cpp std::unordered_map<K, V, H, E, A>`, if `K` is constructible from a `#!cpp
|
||||
(const char*, std::size_t)` pair -- from an object, member by member, each value converted with `#!cpp get<V>()`; with a repeated
|
||||
key, the *last* value is kept, as [`BasicJsonType::parse()`](../basic_json/parse.md) (and
|
||||
[`materialize()`](materialize.md)) does; `#!cpp std::map<std::string, basic_json_view>` keeps views of the members
|
||||
instead of values
|
||||
- `#!cpp std::vector<U, A>` of the types above -- from an array, element by element, each converted with
|
||||
`#!cpp get<U>()`; `#!cpp std::vector<basic_json_view>` keeps a view of every element instead of a value
|
||||
- `#!cpp std::map<K, basic_json_view, C, A>` and `#!cpp std::unordered_map<K, basic_json_view, H, E, A>`, if `K` is
|
||||
constructible from a `#!cpp (const char*, std::size_t)` pair -- views of the members of an object; with a repeated
|
||||
key, the view of the *last* member is kept, as [`BasicJsonType::parse()`](../basic_json/parse.md) keeps its value
|
||||
|
||||
A default-constructible `T` whose `from_json()` accepts views reads the view directly as well, member by member, without
|
||||
building a `BasicJsonType` value. This covers the types of the
|
||||
A default-constructible `T` whose `from_json()` accepts views reads the view directly as well, without building a
|
||||
`BasicJsonType` value. This covers the library's own conversions of the standard library types -- all other
|
||||
`#!cpp std::vector`s, `#!cpp std::map`/`#!cpp std::unordered_map` (also with other key types), `#!cpp std::list`,
|
||||
`#!cpp std::deque`, `#!cpp std::set`, `#!cpp std::forward_list`, `#!cpp std::valarray`, `#!cpp std::array`, C arrays,
|
||||
`#!cpp std::pair`, `#!cpp std::tuple`, `#!cpp std::optional`, enumerations, `#!cpp std::filesystem::path`, ... --
|
||||
which give the same values as `#!cpp materialize().get<T>()` (from an object, a repeated key keeps the *last* value,
|
||||
as [`BasicJsonType::parse()`](../basic_json/parse.md) does), as well as the types of the
|
||||
[`NLOHMANN_DEFINE_TYPE_*`](../macros/nlohmann_define_type_intrusive.md) and
|
||||
[`NLOHMANN_DEFINE_DERIVED_TYPE_*`](../macros/nlohmann_define_derived_type.md) macros and the enumerations of
|
||||
[`NLOHMANN_JSON_SERIALIZE_ENUM`](../macros/nlohmann_json_serialize_enum.md), and any `from_json()` constrained to
|
||||
accept views, e.g. with [`is_json_view`](../is_json_view.md). A `from_json()` that also accepts types that are no JSON
|
||||
values at all, such as the unconstrained `#!cpp template<typename BasicJsonType> void from_json(const BasicJsonType&,
|
||||
T&)` of [arbitrary type conversions](../../features/arbitrary_types.md), is not called with a view: it may use
|
||||
`BasicJsonType` functions a view does not have. See [json_view](../../features/json_view.md).
|
||||
`BasicJsonType` functions a view does not have. See [Writing generic code](../../features/json_view.md#writing-generic-code).
|
||||
|
||||
!!! warning "Duplicate keys"
|
||||
|
||||
@@ -44,8 +47,8 @@ T&)` of [arbitrary type conversions](../../features/arbitrary_types.md), is not
|
||||
keeps it: for `#!cpp {"x":1,"x":2}`, `#!cpp get<point>()` reads `#!cpp x == 1`. See
|
||||
[Duplicate keys](../../features/json_view.md#duplicate-keys).
|
||||
|
||||
Every other `T` -- `#!cpp std::list`, `#!cpp std::pair`, `#!cpp std::array`, user types whose `from_json()` is
|
||||
written for `BasicJsonType` only, ... -- is converted by `#!cpp materialize().get<T>()`: the subtree is built into a real `BasicJsonType`
|
||||
Every other `T` -- user types whose `from_json()` is written for `BasicJsonType` only, types without a default
|
||||
constructor, `#!cpp std::tuple`s holding references, ... -- is converted by `#!cpp materialize().get<T>()`: the subtree is built into a real `BasicJsonType`
|
||||
value first (as [`BasicJsonType::parse()`](../basic_json/parse.md) would), and converted from there exactly as
|
||||
[`BasicJsonType::get<T>()`](../basic_json/get.md) would convert it.
|
||||
|
||||
@@ -70,10 +73,10 @@ Strong guarantee: there are no changes to the view or the document it refers to.
|
||||
throws for the same JSON type and `T`.
|
||||
- For `#!cpp std::vector<U, A>`: throws `type_error.302` if the value is not an array; otherwise, whatever converting
|
||||
an element to `U` throws.
|
||||
- For `#!cpp std::map`/`#!cpp std::unordered_map`: throws `type_error.302` if the value is not an object; otherwise,
|
||||
whatever converting a member to the mapped type throws.
|
||||
- For a `T` whose `from_json()` reads the view: whatever that `from_json()` throws; for the macros, the same
|
||||
exceptions with the same messages as [`BasicJsonType::get<T>()`](../basic_json/get.md) of the same value.
|
||||
- For `#!cpp std::map`/`#!cpp std::unordered_map` of views: throws `type_error.302` if the value is not an object.
|
||||
- For a `T` whose `from_json()` reads the view: whatever that `from_json()` throws; for the library's conversions and
|
||||
the macros, the same exceptions with the same messages as [`BasicJsonType::get<T>()`](../basic_json/get.md) of the
|
||||
same value.
|
||||
- For every other `T`: whatever [`materialize().get<T>()`](../basic_json/get.md) throws -- typically `type_error.302`,
|
||||
or whatever a user-provided `from_json()` throws.
|
||||
|
||||
|
||||
@@ -9,8 +9,7 @@ Converts the value to `T` and stores it in `v`, in one of three ways:
|
||||
|
||||
- For the types that [`get<T>()`](get.md) converts directly -- arithmetic types, `#!cpp bool`,
|
||||
`#!cpp std::nullptr_t`, [`string_view_t`](index.md#member-types), `#!cpp std::basic_string`, `BasicJsonType`,
|
||||
`basic_json_view`, `#!cpp std::vector`, and `#!cpp std::map`/`#!cpp std::unordered_map` with string keys -- `v` is
|
||||
assigned: `#!cpp v = get<T>()`.
|
||||
`basic_json_view`, vectors of these, and maps of views -- `v` is assigned: `#!cpp v = get<T>()`.
|
||||
- For a type whose `from_json()` accepts views (see [`get<T>()`](get.md)), that `from_json()` is called with the
|
||||
view and the existing `v`, without building a `BasicJsonType` value.
|
||||
- For every other type, the subtree is built into a `BasicJsonType` value and `#!cpp materialize().get_to(v)` is
|
||||
|
||||
@@ -49,6 +49,7 @@ view class.
|
||||
- [basic_json_view](basic_json_view/index.md) - a handle to one value of a document
|
||||
- [get](basic_json_view/get.md) - which conversions read the view directly
|
||||
- [view_mode](view_mode.md) - read-only or editable
|
||||
- [Writing generic code](../features/json_view.md#writing-generic-code) - functions and `from_json()` for views
|
||||
|
||||
## Version history
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ void f(basic_json_view<BasicJsonType, view_mode::editable> v);
|
||||
template<typename BasicJsonType>
|
||||
void f(basic_json_view<BasicJsonType, view_mode::read_only> v);
|
||||
|
||||
// either
|
||||
// views of either document type
|
||||
template<typename BasicJsonType, view_mode Mode>
|
||||
void f(basic_json_view<BasicJsonType, Mode> v);
|
||||
```
|
||||
@@ -74,6 +74,7 @@ nor a [`json_editable_view`](json_editable_view.md). Views of the two modes stil
|
||||
- [basic_json_document](basic_json_document/index.md) - a parsed JSON text
|
||||
- [basic_json_view](basic_json_view/index.md) - a handle to one value of a document
|
||||
- [json_editable_document](json_editable_document.md) - an editable document of `json`
|
||||
- [Writing generic code](../features/json_view.md#writing-generic-code) - functions that accept views
|
||||
|
||||
## Version history
|
||||
|
||||
|
||||
@@ -214,14 +214,15 @@ number of distinct keys, or reject duplicates when iterating.
|
||||
|
||||
## Getting values out without copying
|
||||
|
||||
[`get<T>()`](../api/basic_json_view/get.md) converts many `T` directly from the flat index, without ever building a
|
||||
[`get<T>()`](../api/basic_json_view/get.md) converts most `T` directly from the flat index, without ever building a
|
||||
`basic_json` value for the conversion: `#!cpp bool`, arithmetic types, `#!cpp std::nullptr_t`,
|
||||
`#!cpp std::string`/other `#!cpp std::basic_string`s (copied once), `basic_json`/`ordered_json` (via
|
||||
[`materialize()`](../api/basic_json_view/materialize.md)), `basic_json_view` itself, `#!cpp std::vector<U>`, and
|
||||
`#!cpp std::map`/`#!cpp std::unordered_map` with string-like keys. Every other type -- `#!cpp std::list`,
|
||||
`#!cpp std::pair`, `#!cpp std::array`, enumerations, user types with a `from_json()` -- goes through
|
||||
`#!cpp std::string`/other `#!cpp std::basic_string`s (copied once), `basic_json_view` itself, the standard containers
|
||||
and other types the library converts (`#!cpp std::vector`, `#!cpp std::map`, `#!cpp std::list`, `#!cpp std::array`,
|
||||
`#!cpp std::pair`, `#!cpp std::tuple`, `#!cpp std::optional`, ...), and the types of the `NLOHMANN_DEFINE_TYPE_*` and
|
||||
`NLOHMANN_JSON_SERIALIZE_ENUM` macros. Types whose `from_json()` is written for `basic_json` only go through
|
||||
[`materialize()`](../api/basic_json_view/materialize.md)`.get<T>()` instead: the subtree is built into a real
|
||||
`basic_json` value first, exactly as [`parse()`](../api/basic_json/parse.md) would, and converted from there.
|
||||
`basic_json` value first, exactly as [`parse()`](../api/basic_json/parse.md) would, and converted from there. See
|
||||
[Writing generic code](#writing-generic-code) for how to write a `from_json()` that reads views.
|
||||
|
||||
Two conversions never copy at all:
|
||||
|
||||
@@ -236,6 +237,89 @@ Two conversions never copy at all:
|
||||
|
||||
Both results are only valid as long as the view -- and, for a string with no escapes, the borrowed source text -- is.
|
||||
|
||||
## Writing generic code
|
||||
|
||||
A view's type names its `BasicJsonType` and its [`view_mode`](../api/view_mode.md):
|
||||
[`json_view`](../api/json_view.md) is `#!cpp basic_json_view<json, view_mode::read_only>`, and
|
||||
[`json_editable_view`](../api/json_editable_view.md) is `#!cpp basic_json_view<json, view_mode::editable>`. These are
|
||||
different types, and there is no conversion between them, so a function written for one shortcut accepts no other
|
||||
view:
|
||||
|
||||
```cpp
|
||||
void print_names(json_view v); // accepts neither an ordered_json_view nor a json_editable_view
|
||||
```
|
||||
|
||||
This is the same pitfall as a `to_json`/`from_json` written for `json` instead of any `BasicJsonType`, which then does
|
||||
not work for `ordered_json`. The shortcuts are for declaring documents and views; a function that takes a view names
|
||||
the views it accepts with a template:
|
||||
|
||||
```cpp
|
||||
// views of editable documents only
|
||||
template<typename BasicJsonType>
|
||||
void f(basic_json_view<BasicJsonType, view_mode::editable> v);
|
||||
|
||||
// views of read-only documents only
|
||||
template<typename BasicJsonType>
|
||||
void f(basic_json_view<BasicJsonType, view_mode::read_only> v);
|
||||
|
||||
// views of either document type
|
||||
template<typename BasicJsonType, view_mode Mode>
|
||||
void f(basic_json_view<BasicJsonType, Mode> v);
|
||||
```
|
||||
|
||||
Views are passed by value: they are two pointers, cheap to copy, like a `#!cpp std::string_view`. A `const&` works as
|
||||
well, but a non-`const` reference does not bind to the views that [`root()`](../api/basic_json_document/root.md),
|
||||
[`operator[]`](../api/basic_json_view/operator%5B%5D.md), and [`at()`](../api/basic_json_view/at.md) return, so
|
||||
`#!cpp f(doc.root())` would not compile.
|
||||
|
||||
There is no conversion from an editable view to a read-only one, by design: the mode decides how a view walks the
|
||||
index. A read-only view reads a container in place, while a view of an editable document follows the links that edits
|
||||
leave behind, so a read-only view of an edited document would read stale values. Views of both modes compare with
|
||||
[`operator==`](../api/basic_json_view/operator_eq.md).
|
||||
|
||||
[`is_json_view<T>`](../api/is_json_view.md) tells views from other types, for constraints that cannot be written as a
|
||||
`basic_json_view<...>` parameter.
|
||||
|
||||
### A `from_json()` that reads views
|
||||
|
||||
[`get<T>()`](../api/basic_json_view/get.md) on a view calls `T`'s `from_json()` with the view itself if that
|
||||
`from_json()` accepts views, and with [`materialize()`](../api/basic_json_view/materialize.md) otherwise. The
|
||||
`from_json()` functions of the [`NLOHMANN_DEFINE_TYPE_*`](../api/macros/nlohmann_define_type_intrusive.md),
|
||||
[`NLOHMANN_DEFINE_DERIVED_TYPE_*`](../api/macros/nlohmann_define_derived_type.md), and
|
||||
[`NLOHMANN_JSON_SERIALIZE_ENUM`](../api/macros/nlohmann_json_serialize_enum.md) macros, and those of the library
|
||||
for the standard types, accept views, so these types need nothing else. For decoding the statuses of
|
||||
twitter.json into structs, reading the view is about 5 times faster than `#!cpp materialize().get<T>()`.
|
||||
|
||||
A hand-written `from_json()` reads views if it is constrained to `json` values and views:
|
||||
|
||||
```cpp
|
||||
template < typename J, typename std::enable_if <
|
||||
nlohmann::is_json_view<J>::value || std::is_same<J, nlohmann::json>::value, int >::type = 0 >
|
||||
void from_json(const J& j, person& p)
|
||||
{
|
||||
p.name = j.at("name").template get<std::string>();
|
||||
p.age = j.at("age").template get<int>();
|
||||
}
|
||||
```
|
||||
|
||||
Its body may only use what views and `basic_json` have in common: the type checks, `at()`, `operator[]`, `contains()`,
|
||||
`value()`, `size()`, iteration and `items()`, and `get<T>()`/`get_to()`. An unconstrained
|
||||
`#!cpp template<typename BasicJsonType> void from_json(const BasicJsonType& j, person& p)`, as in
|
||||
[arbitrary type conversions](arbitrary_types.md), is never called with a view, as it might use `basic_json` functions
|
||||
a view does not have; such a type is converted through `materialize()`. A `from_json()` for `json` only is
|
||||
converted through `materialize()` as well.
|
||||
|
||||
Two things differ when a `from_json()` reads the view:
|
||||
|
||||
- **Duplicate keys.** Members looked up by name (`at()`, `value()`, ... and thus the macros) find the **first** member
|
||||
with a repeated key, see [Duplicate keys](#duplicate-keys); `#!cpp materialize().get<T>()` would see the last one.
|
||||
Containers built from an object, such as `#!cpp std::map`, keep the **last** value either way, as
|
||||
[`parse()`](../api/basic_json/parse.md) does.
|
||||
- **[`JSON_DIAGNOSTICS`](../api/macros/json_diagnostics.md).** Exceptions thrown by the view carry no path to the
|
||||
value.
|
||||
|
||||
`to_json()` is unaffected: it writes `basic_json` values, never views.
|
||||
|
||||
## Writing a view back
|
||||
|
||||
[`dump()`](../api/basic_json_view/dump.md) serializes a view directly from the flat index, without ever building a
|
||||
|
||||
@@ -45,6 +45,70 @@ NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||
namespace detail
|
||||
{
|
||||
|
||||
// The from_json() overloads below read basic_json values and the views of
|
||||
// <nlohmann/json_view.hpp> (BasicJsonType is then a view, and
|
||||
// json_type_of_t<BasicJsonType> its basic_json type). The helpers below are
|
||||
// the accesses that differ between the two.
|
||||
|
||||
// the enable_if parameter of the overloads that read basic_json values (written
|
||||
// with negation<> because astyle spaces out a template argument list with '!')
|
||||
template<typename T>
|
||||
using enable_if_not_view_t = enable_if_t<negation<is_json_view<T>>::value, int>;
|
||||
|
||||
// the boolean of j, a boolean
|
||||
template < typename BasicJsonType, enable_if_not_view_t<BasicJsonType> = 0 >
|
||||
typename BasicJsonType::boolean_t boolean_value(const BasicJsonType& j)
|
||||
{
|
||||
return *j.template get_ptr<const typename BasicJsonType::boolean_t*>();
|
||||
}
|
||||
|
||||
template<typename View, enable_if_t<is_json_view<View>::value, int> = 0>
|
||||
bool boolean_value(const View& v)
|
||||
{
|
||||
return v.template get<bool>();
|
||||
}
|
||||
|
||||
// the string of j, a string
|
||||
template < typename BasicJsonType, enable_if_not_view_t<BasicJsonType> = 0 >
|
||||
const typename BasicJsonType::string_t& string_value(const BasicJsonType& j)
|
||||
{
|
||||
return *j.template get_ptr<const typename BasicJsonType::string_t*>();
|
||||
}
|
||||
|
||||
template<typename View, enable_if_t<is_json_view<View>::value, int> = 0>
|
||||
typename View::string_t string_value(const View& v)
|
||||
{
|
||||
const auto s = v.get_string();
|
||||
return typename View::string_t(s.data(), s.size());
|
||||
}
|
||||
|
||||
// the binary value of j, a binary value (never a view: a view of a JSON text
|
||||
// holds no binary values)
|
||||
template < typename BasicJsonType, enable_if_not_view_t<BasicJsonType> = 0 >
|
||||
const typename BasicJsonType::binary_t& binary_value(const BasicJsonType& j)
|
||||
{
|
||||
return *j.template get_ptr<const typename BasicJsonType::binary_t*>();
|
||||
}
|
||||
|
||||
template<typename View, enable_if_t<is_json_view<View>::value, int> = 0>
|
||||
typename View::basic_json_type::binary_t binary_value(const View& /*unused*/)
|
||||
{
|
||||
return {}; // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
// the elements of j, an array, for a range-based for loop
|
||||
template < typename BasicJsonType, enable_if_not_view_t<BasicJsonType> = 0 >
|
||||
const typename BasicJsonType::array_t& array_elements(const BasicJsonType& j)
|
||||
{
|
||||
return *j.template get_ptr<const typename BasicJsonType::array_t*>();
|
||||
}
|
||||
|
||||
template<typename View, enable_if_t<is_json_view<View>::value, int> = 0>
|
||||
View array_elements(const View& v) noexcept
|
||||
{
|
||||
return v; // (a view is two pointers)
|
||||
}
|
||||
|
||||
template<typename BasicJsonType>
|
||||
inline void from_json(const BasicJsonType& j, typename std::nullptr_t& n)
|
||||
{
|
||||
@@ -73,7 +137,7 @@ void from_json(const BasicJsonType& j, std::optional<T>& opt)
|
||||
|
||||
// read a number value of any of the three number types into val;
|
||||
// returns false (leaving val untouched) if j is not a number
|
||||
template<typename BasicJsonType, typename ArithmeticType>
|
||||
template < typename BasicJsonType, typename ArithmeticType, enable_if_not_view_t<BasicJsonType> = 0 >
|
||||
bool get_number_value(const BasicJsonType& j, ArithmeticType& val)
|
||||
{
|
||||
switch (static_cast<value_t>(j))
|
||||
@@ -110,10 +174,22 @@ bool get_number_value(const BasicJsonType& j, ArithmeticType& val)
|
||||
}
|
||||
}
|
||||
|
||||
// a view converts numbers itself (as basic_json does)
|
||||
template<typename View, typename ArithmeticType, enable_if_t<is_json_view<View>::value, int> = 0>
|
||||
bool get_number_value(const View& v, ArithmeticType& val)
|
||||
{
|
||||
if (!v.is_number())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
val = v.template get<ArithmeticType>();
|
||||
return true;
|
||||
}
|
||||
|
||||
// overloads for basic_json template parameters
|
||||
template < typename BasicJsonType, typename ArithmeticType,
|
||||
enable_if_t < std::is_arithmetic<ArithmeticType>::value&&
|
||||
!std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value,
|
||||
!std::is_same<ArithmeticType, typename json_type_of_t<BasicJsonType>::boolean_t>::value,
|
||||
int > = 0 >
|
||||
void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val)
|
||||
{
|
||||
@@ -124,31 +200,31 @@ void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val)
|
||||
}
|
||||
|
||||
template<typename BasicJsonType>
|
||||
inline void from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b)
|
||||
inline void from_json(const BasicJsonType& j, typename json_type_of_t<BasicJsonType>::boolean_t& b)
|
||||
{
|
||||
if (JSON_HEDLEY_UNLIKELY(!j.is_boolean()))
|
||||
{
|
||||
throw_type_must_be("boolean", j);
|
||||
}
|
||||
b = *j.template get_ptr<const typename BasicJsonType::boolean_t*>();
|
||||
b = boolean_value(j);
|
||||
}
|
||||
|
||||
template<typename BasicJsonType>
|
||||
inline void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s)
|
||||
inline void from_json(const BasicJsonType& j, typename json_type_of_t<BasicJsonType>::string_t& s)
|
||||
{
|
||||
if (JSON_HEDLEY_UNLIKELY(!j.is_string()))
|
||||
{
|
||||
throw_type_must_be("string", j);
|
||||
}
|
||||
s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
|
||||
s = string_value(j);
|
||||
}
|
||||
|
||||
template <
|
||||
typename BasicJsonType, typename StringType,
|
||||
enable_if_t <
|
||||
std::is_assignable<StringType&, const typename BasicJsonType::string_t>::value
|
||||
&& is_detected_exact<typename BasicJsonType::string_t::value_type, value_type_t, StringType>::value
|
||||
&& !std::is_same<typename BasicJsonType::string_t, StringType>::value
|
||||
std::is_assignable<StringType&, const typename json_type_of_t<BasicJsonType>::string_t>::value
|
||||
&& is_detected_exact<typename json_type_of_t<BasicJsonType>::string_t::value_type, value_type_t, StringType>::value
|
||||
&& !std::is_same<typename json_type_of_t<BasicJsonType>::string_t, StringType>::value
|
||||
&& !is_json_ref<StringType>::value, int > = 0 >
|
||||
inline void from_json(const BasicJsonType& j, StringType& s)
|
||||
{
|
||||
@@ -157,23 +233,23 @@ inline void from_json(const BasicJsonType& j, StringType& s)
|
||||
throw_type_must_be("string", j);
|
||||
}
|
||||
|
||||
s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
|
||||
s = string_value(j);
|
||||
}
|
||||
|
||||
template<typename BasicJsonType>
|
||||
inline void from_json(const BasicJsonType& j, typename BasicJsonType::number_float_t& val)
|
||||
inline void from_json(const BasicJsonType& j, typename json_type_of_t<BasicJsonType>::number_float_t& val)
|
||||
{
|
||||
get_arithmetic_value(j, val);
|
||||
}
|
||||
|
||||
template<typename BasicJsonType>
|
||||
inline void from_json(const BasicJsonType& j, number_unsigned_overload_t<BasicJsonType>& val)
|
||||
inline void from_json(const BasicJsonType& j, number_unsigned_overload_t<json_type_of_t<BasicJsonType>>& val)
|
||||
{
|
||||
get_arithmetic_value(j, val);
|
||||
}
|
||||
|
||||
template<typename BasicJsonType>
|
||||
inline void from_json(const BasicJsonType& j, typename BasicJsonType::number_integer_t& val)
|
||||
inline void from_json(const BasicJsonType& j, typename json_type_of_t<BasicJsonType>::number_integer_t& val)
|
||||
{
|
||||
get_arithmetic_value(j, val);
|
||||
}
|
||||
@@ -185,8 +261,8 @@ inline void from_json(const BasicJsonType& j, EnumType& e)
|
||||
{
|
||||
using underlying_type = typename std::underlying_type<EnumType>::type;
|
||||
// get_arithmetic_value() does not accept boolean_t; read the number that to_json() wrote instead
|
||||
using value_type = typename std::conditional<std::is_same<underlying_type, typename BasicJsonType::boolean_t>::value,
|
||||
typename BasicJsonType::number_unsigned_t, underlying_type>::type;
|
||||
using value_type = typename std::conditional<std::is_same<underlying_type, typename json_type_of_t<BasicJsonType>::boolean_t>::value,
|
||||
typename json_type_of_t<BasicJsonType>::number_unsigned_t, underlying_type>::type;
|
||||
value_type val;
|
||||
get_arithmetic_value(j, val);
|
||||
e = static_cast<EnumType>(bool_aware_static_cast<underlying_type>(val));
|
||||
@@ -195,7 +271,7 @@ inline void from_json(const BasicJsonType& j, EnumType& e)
|
||||
|
||||
// forward_list doesn't have an insert method
|
||||
template<typename BasicJsonType, typename T, typename Allocator,
|
||||
enable_if_t<is_getable<BasicJsonType, T>::value, int> = 0>
|
||||
enable_if_t<is_getable<json_type_of_t<BasicJsonType>, T>::value, int> = 0>
|
||||
inline void from_json(const BasicJsonType& j, std::forward_list<T, Allocator>& l)
|
||||
{
|
||||
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
|
||||
@@ -203,16 +279,16 @@ inline void from_json(const BasicJsonType& j, std::forward_list<T, Allocator>& l
|
||||
throw_type_must_be("array", j);
|
||||
}
|
||||
l.clear();
|
||||
std::transform(j.rbegin(), j.rend(),
|
||||
std::front_inserter(l), [](const BasicJsonType & i)
|
||||
auto pos = l.before_begin();
|
||||
for (const auto& elem : array_elements(j))
|
||||
{
|
||||
return i.template get<T>();
|
||||
});
|
||||
pos = l.insert_after(pos, elem.template get<T>());
|
||||
}
|
||||
}
|
||||
|
||||
// valarray doesn't have an insert method
|
||||
template<typename BasicJsonType, typename T,
|
||||
enable_if_t<is_getable<BasicJsonType, T>::value, int> = 0>
|
||||
enable_if_t<is_getable<json_type_of_t<BasicJsonType>, T>::value, int> = 0>
|
||||
inline void from_json(const BasicJsonType& j, std::valarray<T>& l)
|
||||
{
|
||||
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
|
||||
@@ -220,11 +296,11 @@ inline void from_json(const BasicJsonType& j, std::valarray<T>& l)
|
||||
throw_type_must_be("array", j);
|
||||
}
|
||||
l.resize(j.size());
|
||||
std::transform(j.begin(), j.end(), std::begin(l),
|
||||
[](const BasicJsonType & elem)
|
||||
std::size_t i = 0;
|
||||
for (const auto& elem : array_elements(j))
|
||||
{
|
||||
return elem.template get<T>();
|
||||
});
|
||||
l[i++] = elem.template get<T>();
|
||||
}
|
||||
}
|
||||
|
||||
// element is not itself a C array: read it directly
|
||||
@@ -252,7 +328,8 @@ auto from_json(const BasicJsonType& j, T (&arr)[N]) // NOLINT(cppcoreguidelines
|
||||
from_json_c_array_element(j, arr);
|
||||
}
|
||||
|
||||
template<typename BasicJsonType>
|
||||
// (for a view, array_t is read element by element below)
|
||||
template < typename BasicJsonType, enable_if_not_view_t<BasicJsonType> = 0 >
|
||||
inline void from_json_array_impl(const BasicJsonType& j, typename BasicJsonType::array_t& arr, priority_tag<3> /*unused*/)
|
||||
{
|
||||
arr = *j.template get_ptr<const typename BasicJsonType::array_t*>();
|
||||
@@ -261,7 +338,7 @@ inline void from_json_array_impl(const BasicJsonType& j, typename BasicJsonType:
|
||||
// fill a std::array from the JSON array j: the size is checked once and the
|
||||
// elements are read in order, so a short array converts the elements it has and
|
||||
// then throws the out_of_range error at() would throw for the first missing one
|
||||
template<typename BasicJsonType, typename T, std::size_t N>
|
||||
template < typename BasicJsonType, typename T, std::size_t N, enable_if_not_view_t<BasicJsonType> = 0 >
|
||||
void from_json_std_array(const BasicJsonType& j, std::array<T, N>& arr)
|
||||
{
|
||||
const auto& inner_array = *j.template get_ptr<const typename BasicJsonType::array_t*>();
|
||||
@@ -276,6 +353,21 @@ void from_json_std_array(const BasicJsonType& j, std::array<T, N>& arr)
|
||||
}
|
||||
}
|
||||
|
||||
// (a view has no random access to the elements: they are read in order)
|
||||
template<typename View, typename T, std::size_t N, enable_if_t<is_json_view<View>::value, int> = 0>
|
||||
void from_json_std_array(const View& v, std::array<T, N>& arr)
|
||||
{
|
||||
std::size_t size = 0;
|
||||
for (auto it = v.begin(); size < N && it != v.end(); ++it)
|
||||
{
|
||||
arr[size++] = (*it).template get<T>();
|
||||
}
|
||||
if (JSON_HEDLEY_UNLIKELY(size < N))
|
||||
{
|
||||
static_cast<void>(v.at(size));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, typename T, std::size_t N>
|
||||
auto from_json_array_impl(const BasicJsonType& j, std::array<T, N>& arr,
|
||||
priority_tag<2> /*unused*/)
|
||||
@@ -324,9 +416,8 @@ auto from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr, p
|
||||
void())
|
||||
{
|
||||
ConstructibleArrayType ret;
|
||||
const auto* inner_array = j.template get_ptr<const typename BasicJsonType::array_t*>();
|
||||
reserve_if_possible(ret, inner_array->size(), priority_tag<1> {});
|
||||
for (const auto& elem : *inner_array)
|
||||
reserve_if_possible(ret, j.size(), priority_tag<1> {});
|
||||
for (const auto& elem : array_elements(j))
|
||||
{
|
||||
// get<BasicJsonType>() returns *this, this won't call a from_json
|
||||
// method when value_type is BasicJsonType
|
||||
@@ -337,11 +428,11 @@ auto from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr, p
|
||||
|
||||
template < typename BasicJsonType, typename ConstructibleArrayType,
|
||||
enable_if_t <
|
||||
is_constructible_array_type<BasicJsonType, ConstructibleArrayType>::value&&
|
||||
!is_constructible_object_type<BasicJsonType, ConstructibleArrayType>::value&&
|
||||
!is_constructible_string_type<BasicJsonType, ConstructibleArrayType>::value&&
|
||||
!std::is_same<ConstructibleArrayType, typename BasicJsonType::binary_t>::value&&
|
||||
!is_compatible_binary_type<BasicJsonType, ConstructibleArrayType>::value&&
|
||||
is_constructible_array_type<json_type_of_t<BasicJsonType>, ConstructibleArrayType>::value&&
|
||||
!is_constructible_object_type<json_type_of_t<BasicJsonType>, ConstructibleArrayType>::value&&
|
||||
!is_constructible_string_type<json_type_of_t<BasicJsonType>, ConstructibleArrayType>::value&&
|
||||
!std::is_same<ConstructibleArrayType, typename json_type_of_t<BasicJsonType>::binary_t>::value&&
|
||||
!is_compatible_binary_type<json_type_of_t<BasicJsonType>, ConstructibleArrayType>::value&&
|
||||
!is_basic_json<ConstructibleArrayType>::value,
|
||||
int > = 0 >
|
||||
auto from_json(const BasicJsonType& j, ConstructibleArrayType& arr)
|
||||
@@ -408,24 +499,24 @@ auto from_json(const BasicJsonType& j, identity_tag<std::array<T, N>> tag)
|
||||
}
|
||||
|
||||
template<typename BasicJsonType>
|
||||
inline void from_json(const BasicJsonType& j, typename BasicJsonType::binary_t& bin)
|
||||
inline void from_json(const BasicJsonType& j, typename json_type_of_t<BasicJsonType>::binary_t& bin)
|
||||
{
|
||||
if (JSON_HEDLEY_UNLIKELY(!j.is_binary()))
|
||||
{
|
||||
throw_type_must_be("binary", j);
|
||||
}
|
||||
|
||||
bin = *j.template get_ptr<const typename BasicJsonType::binary_t*>();
|
||||
bin = binary_value(j);
|
||||
}
|
||||
|
||||
template < typename BasicJsonType, typename CompatibleArrayType,
|
||||
enable_if_t < is_compatible_binary_type<BasicJsonType, CompatibleArrayType>::value,
|
||||
enable_if_t < is_compatible_binary_type<json_type_of_t<BasicJsonType>, CompatibleArrayType>::value,
|
||||
int > = 0 >
|
||||
inline void from_json(const BasicJsonType& j, CompatibleArrayType& bin)
|
||||
{
|
||||
if (j.is_binary())
|
||||
{
|
||||
bin = static_cast<CompatibleArrayType>(*j.template get_ptr<const typename BasicJsonType::binary_t*>());
|
||||
bin = static_cast<CompatibleArrayType>(binary_value(j));
|
||||
}
|
||||
else if (j.is_array())
|
||||
{
|
||||
@@ -454,8 +545,47 @@ void from_json_object_emplace(ConstructibleObjectType& obj, Key&& key, Value&& v
|
||||
obj.emplace(std::forward<Key>(key), std::forward<Value>(value));
|
||||
}
|
||||
|
||||
// a member of a view's object: a later member with the same key replaces an
|
||||
// earlier one, as parse() keeps the last value of a repeated key (containers
|
||||
// without operator[] keep the first)
|
||||
template<typename ConstructibleObjectType, typename Key, typename Value>
|
||||
auto from_json_object_assign(ConstructibleObjectType& obj, Key&& key, Value&& value, priority_tag<1> /*unused*/)
|
||||
-> decltype(obj[std::forward<Key>(key)] = std::forward<Value>(value), void())
|
||||
{
|
||||
obj[std::forward<Key>(key)] = std::forward<Value>(value);
|
||||
}
|
||||
|
||||
template<typename ConstructibleObjectType, typename Key, typename Value>
|
||||
void from_json_object_assign(ConstructibleObjectType& obj, Key&& key, Value&& value, priority_tag<0> /*unused*/)
|
||||
{
|
||||
obj.emplace(std::forward<Key>(key), std::forward<Value>(value));
|
||||
}
|
||||
|
||||
template < typename BasicJsonType, typename ConstructibleObjectType, enable_if_not_view_t<BasicJsonType> = 0 >
|
||||
void from_json_object_impl(const BasicJsonType& j, ConstructibleObjectType& ret)
|
||||
{
|
||||
const auto* inner_object = j.template get_ptr<const typename BasicJsonType::object_t*>();
|
||||
reserve_if_possible(ret, inner_object->size(), priority_tag<1> {});
|
||||
for (const auto& p : *inner_object)
|
||||
{
|
||||
from_json_object_emplace(ret, p.first, p.second.template get<typename ConstructibleObjectType::mapped_type>(), priority_tag<1> {});
|
||||
}
|
||||
}
|
||||
|
||||
template<typename View, typename ConstructibleObjectType, enable_if_t<is_json_view<View>::value, int> = 0>
|
||||
void from_json_object_impl(const View& v, ConstructibleObjectType& ret)
|
||||
{
|
||||
using string_t = typename View::basic_json_type::object_t::key_type;
|
||||
reserve_if_possible(ret, v.size(), priority_tag<1> {});
|
||||
for (const auto item : v.items())
|
||||
{
|
||||
const auto key = item.key();
|
||||
from_json_object_assign(ret, string_t(key.data(), key.size()), item.value().template get<typename ConstructibleObjectType::mapped_type>(), priority_tag<1> {});
|
||||
}
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, typename ConstructibleObjectType,
|
||||
enable_if_t<is_constructible_object_type<BasicJsonType, ConstructibleObjectType>::value, int> = 0>
|
||||
enable_if_t<is_constructible_object_type<json_type_of_t<BasicJsonType>, ConstructibleObjectType>::value, int> = 0>
|
||||
inline void from_json(const BasicJsonType& j, ConstructibleObjectType& obj)
|
||||
{
|
||||
if (JSON_HEDLEY_UNLIKELY(!j.is_object()))
|
||||
@@ -464,12 +594,7 @@ inline void from_json(const BasicJsonType& j, ConstructibleObjectType& obj)
|
||||
}
|
||||
|
||||
ConstructibleObjectType ret;
|
||||
const auto* inner_object = j.template get_ptr<const typename BasicJsonType::object_t*>();
|
||||
reserve_if_possible(ret, inner_object->size(), priority_tag<1> {});
|
||||
for (const auto& p : *inner_object)
|
||||
{
|
||||
from_json_object_emplace(ret, p.first, p.second.template get<typename ConstructibleObjectType::mapped_type>(), priority_tag<1> {});
|
||||
}
|
||||
from_json_object_impl(j, ret);
|
||||
obj = std::move(ret);
|
||||
}
|
||||
|
||||
@@ -478,10 +603,10 @@ inline void from_json(const BasicJsonType& j, ConstructibleObjectType& obj)
|
||||
template < typename BasicJsonType, typename ArithmeticType,
|
||||
enable_if_t <
|
||||
std::is_arithmetic<ArithmeticType>::value&&
|
||||
!std::is_same<ArithmeticType, typename BasicJsonType::number_unsigned_t>::value&&
|
||||
!std::is_same<ArithmeticType, typename BasicJsonType::number_integer_t>::value&&
|
||||
!std::is_same<ArithmeticType, typename BasicJsonType::number_float_t>::value&&
|
||||
!std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value,
|
||||
!std::is_same<ArithmeticType, typename json_type_of_t<BasicJsonType>::number_unsigned_t>::value&&
|
||||
!std::is_same<ArithmeticType, typename json_type_of_t<BasicJsonType>::number_integer_t>::value&&
|
||||
!std::is_same<ArithmeticType, typename json_type_of_t<BasicJsonType>::number_float_t>::value&&
|
||||
!std::is_same<ArithmeticType, typename json_type_of_t<BasicJsonType>::boolean_t>::value,
|
||||
int > = 0 >
|
||||
inline void from_json(const BasicJsonType& j, ArithmeticType& val)
|
||||
{
|
||||
@@ -495,7 +620,7 @@ inline void from_json(const BasicJsonType& j, ArithmeticType& val)
|
||||
{
|
||||
throw_type_must_be("number", j);
|
||||
}
|
||||
val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::boolean_t*>());
|
||||
val = static_cast<ArithmeticType>(boolean_value(j));
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, typename Type>
|
||||
@@ -505,7 +630,7 @@ detail::uncvref_t<Type> from_json_tuple_get_impl(BasicJsonType&& j, detail::iden
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, typename Type,
|
||||
detail::enable_if_t<detail::is_compatible_reference_type<BasicJsonType, Type>::value, int> = 0>
|
||||
detail::enable_if_t<conjunction<is_basic_json<uncvref_t<BasicJsonType>>, is_compatible_reference_type<BasicJsonType, Type>>::value, int> = 0>
|
||||
Type from_json_tuple_get_impl(BasicJsonType && j, detail::identity_tag<Type> /*unused*/, detail::priority_tag<1> /*unused*/)
|
||||
{
|
||||
return std::forward<BasicJsonType>(j).template get_ref<Type>();
|
||||
@@ -549,7 +674,7 @@ inline void from_json_tuple_impl(const BasicJsonType& j, std::pair<A1, A2>& p, p
|
||||
template<typename BasicJsonType, typename... Args>
|
||||
std::tuple<Args...> from_json_tuple_impl(const BasicJsonType& j, identity_tag<std::tuple<Args...>> /*unused*/, priority_tag<2> /*unused*/)
|
||||
{
|
||||
static_assert(conjunction<disjunction<negation<std::is_reference<Args>>, is_compatible_reference_type<const BasicJsonType&, Args>>...>::value,
|
||||
static_assert(conjunction<disjunction<negation<std::is_reference<Args>>, conjunction<is_basic_json<BasicJsonType>, is_compatible_reference_type<const BasicJsonType&, Args>>>...>::value,
|
||||
"Can not return a tuple containing references to types not contained in a Json, try Json::get_to()");
|
||||
return from_json_tuple_impl_base<1, Args...>(j, index_sequence_for<Args...> {});
|
||||
}
|
||||
@@ -595,7 +720,7 @@ void from_json_pair_array_to_map(const BasicJsonType& j, MapType& m)
|
||||
// read a map with enum keys from an object, using the enum's own from_json for
|
||||
// the keys (e.g., from NLOHMANN_JSON_SERIALIZE_ENUM); this is the form written
|
||||
// with JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS
|
||||
template<typename BasicJsonType, typename Map>
|
||||
template < typename BasicJsonType, typename Map, enable_if_not_view_t<BasicJsonType> = 0 >
|
||||
inline bool from_json_enum_keyed_object(const BasicJsonType& j, Map& m, std::true_type /*key is enum*/)
|
||||
{
|
||||
if (!j.is_object())
|
||||
@@ -610,6 +735,24 @@ inline bool from_json_enum_keyed_object(const BasicJsonType& j, Map& m, std::tru
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename View, typename Map, enable_if_t<is_json_view<View>::value, int> = 0>
|
||||
inline bool from_json_enum_keyed_object(const View& v, Map& m, std::true_type /*key is enum*/)
|
||||
{
|
||||
using json_t = typename View::basic_json_type;
|
||||
if (!v.is_object())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
m.clear();
|
||||
for (const auto item : v.items())
|
||||
{
|
||||
const auto key = item.key();
|
||||
from_json_object_assign(m, json_t(typename json_t::string_t(key.data(), key.size())).template get<typename Map::key_type>(),
|
||||
item.value().template get<typename Map::mapped_type>(), priority_tag<1> {});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, typename Map>
|
||||
inline bool from_json_enum_keyed_object(const BasicJsonType& /*j*/, Map& /*m*/, std::false_type /*key is enum*/)
|
||||
{
|
||||
@@ -618,7 +761,7 @@ inline bool from_json_enum_keyed_object(const BasicJsonType& /*j*/, Map& /*m*/,
|
||||
|
||||
template < typename BasicJsonType, typename Key, typename Value, typename Compare, typename Allocator,
|
||||
typename = enable_if_t < !std::is_constructible <
|
||||
typename BasicJsonType::string_t, Key >::value >>
|
||||
typename json_type_of_t<BasicJsonType>::string_t, Key >::value >>
|
||||
void from_json(const BasicJsonType& j, std::map<Key, Value, Compare, Allocator>& m)
|
||||
{
|
||||
// NOLINTNEXTLINE(modernize-type-traits) we use C++11
|
||||
@@ -631,7 +774,7 @@ void from_json(const BasicJsonType& j, std::map<Key, Value, Compare, Allocator>&
|
||||
|
||||
template < typename BasicJsonType, typename Key, typename Value, typename Hash, typename KeyEqual, typename Allocator,
|
||||
typename = enable_if_t < !std::is_constructible <
|
||||
typename BasicJsonType::string_t, Key >::value >>
|
||||
typename json_type_of_t<BasicJsonType>::string_t, Key >::value >>
|
||||
void from_json(const BasicJsonType& j, std::unordered_map<Key, Value, Hash, KeyEqual, Allocator>& m)
|
||||
{
|
||||
// NOLINTNEXTLINE(modernize-type-traits) we use C++11
|
||||
@@ -655,7 +798,7 @@ inline void from_json(const BasicJsonType& j, std_fs::path& p)
|
||||
{
|
||||
throw_type_must_be("string", j);
|
||||
}
|
||||
const auto& s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
|
||||
const auto& s = string_value(j);
|
||||
// Checking for C++20 standard or later can be insufficient in case the
|
||||
// library support for char8_t is either incomplete or was disabled
|
||||
// altogether. Use the __cpp_lib_char8_t feature test instead.
|
||||
@@ -694,10 +837,9 @@ struct fn
|
||||
};
|
||||
} // namespace from_json_adl
|
||||
|
||||
// the sources whose from_json() is only looked up by ADL: views (the library's
|
||||
// overloads are written for basic_json) and the probe
|
||||
// the sources whose from_json() is only looked up by ADL: the probe
|
||||
template<typename T>
|
||||
struct is_adl_only_from_json_source : disjunction<is_json_view<T>, std::is_same<T, from_json_adl::probe>> {};
|
||||
struct is_adl_only_from_json_source : std::is_same<T, from_json_adl::probe> {};
|
||||
|
||||
struct from_json_fn
|
||||
{
|
||||
@@ -748,20 +890,6 @@ void from_json_base(const View& v, T& base)
|
||||
v.get_to(base);
|
||||
}
|
||||
|
||||
// the context of an exception thrown by a from_json() of the macros: the value
|
||||
// itself for basic_json (for JSON_DIAGNOSTICS), none for a view
|
||||
template<typename BasicJsonType, enable_if_t<is_basic_json<BasicJsonType>::value, int> = 0>
|
||||
const BasicJsonType * from_json_context(const BasicJsonType& j) noexcept
|
||||
{
|
||||
return &j;
|
||||
}
|
||||
|
||||
template<typename View, enable_if_t<is_json_view<View>::value, int> = 0>
|
||||
std::nullptr_t from_json_context(const View& /*unused*/) noexcept
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// a value as an exception message shows it (invalid UTF-8 replaced; the
|
||||
// strings of a view are always valid UTF-8)
|
||||
template<typename BasicJsonType, enable_if_t<is_basic_json<BasicJsonType>::value, int> = 0>
|
||||
|
||||
@@ -417,6 +417,20 @@ void templated_json_throw(ExceptionType exception)
|
||||
(void)exception;
|
||||
}
|
||||
|
||||
// the context of an exception about j: j itself for a basic_json value (whose
|
||||
// path JSON_DIAGNOSTICS shows), none for a view of <nlohmann/json_view.hpp>
|
||||
template<typename BasicJsonType, enable_if_t<is_basic_json<BasicJsonType>::value, int> = 0>
|
||||
const BasicJsonType * exception_context(const BasicJsonType& j) noexcept
|
||||
{
|
||||
return &j;
|
||||
}
|
||||
|
||||
template<typename View, enable_if_t<is_json_view<View>::value, int> = 0>
|
||||
std::nullptr_t exception_context(const View& /*unused*/) noexcept
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief throws because @a j does not have the type a conversion expects
|
||||
@param[in] expected the expected type(s), e.g. "array" or "binary or array"
|
||||
@@ -428,7 +442,7 @@ JSON_HEDLEY_NO_RETURN JSON_HEDLEY_NEVER_INLINE void throw_type_must_be(const cha
|
||||
{
|
||||
static_cast<void>(expected); // unused when JSON_NOEXCEPTION is defined
|
||||
static_cast<void>(j);
|
||||
JSON_THROW(type_error::create(exception_id::type_mismatch, concat("type must be ", expected, ", but is ", j.type_name()), &j));
|
||||
JSON_THROW(type_error::create(exception_id::type_mismatch, concat("type must be ", expected, ", but is ", j.type_name()), exception_context(j)));
|
||||
}
|
||||
|
||||
/*!
|
||||
|
||||
@@ -347,7 +347,7 @@
|
||||
return ej_pair.second == j; \
|
||||
}); \
|
||||
if (it != std::end(m)) e = it->first; \
|
||||
else ::nlohmann::detail::templated_json_throw<nlohmann::detail::out_of_range>(nlohmann::detail::out_of_range::create(nlohmann::detail::exception_id::value_out_of_range, nlohmann::detail::concat("enum value out of range for " #ENUM_TYPE ": ", nlohmann::detail::from_json_dump(j)), nlohmann::detail::from_json_context(j))); \
|
||||
else ::nlohmann::detail::templated_json_throw<nlohmann::detail::out_of_range>(nlohmann::detail::out_of_range::create(nlohmann::detail::exception_id::value_out_of_range, nlohmann::detail::concat("enum value out of range for " #ENUM_TYPE ": ", nlohmann::detail::from_json_dump(j)), nlohmann::detail::exception_context(j))); \
|
||||
}
|
||||
|
||||
// Ugly macros to avoid uglier copy-paste when specializing basic_json. They
|
||||
|
||||
@@ -130,14 +130,16 @@ struct is_direct_value : std::integral_constant < bool,
|
||||
template<typename Traits, typename Alloc, typename BasicJsonType, typename View>
|
||||
struct is_direct_value<std::basic_string<char, Traits, Alloc>, BasicJsonType, View> : std::true_type {};
|
||||
|
||||
// (vectors of these, which are faster than through from_json(), and containers
|
||||
// of views; other containers are read by the library's from_json())
|
||||
template<typename U, typename A, typename BasicJsonType, typename View>
|
||||
struct is_direct_value<std::vector<U, A>, BasicJsonType, View> : std::true_type {};
|
||||
struct is_direct_value<std::vector<U, A>, BasicJsonType, View> : is_direct_value<U, BasicJsonType, View> {};
|
||||
|
||||
template<typename K, typename V, typename C, typename A, typename BasicJsonType, typename View>
|
||||
struct is_direct_value<std::map<K, V, C, A>, BasicJsonType, View> : is_string_key<K> {};
|
||||
template<typename K, typename C, typename A, typename BasicJsonType, typename View>
|
||||
struct is_direct_value<std::map<K, View, C, A>, BasicJsonType, View> : is_string_key<K> {};
|
||||
|
||||
template<typename K, typename V, typename H, typename E, typename A, typename BasicJsonType, typename View>
|
||||
struct is_direct_value<std::unordered_map<K, V, H, E, A>, BasicJsonType, View> : is_string_key<K> {};
|
||||
template<typename K, typename H, typename E, typename A, typename BasicJsonType, typename View>
|
||||
struct is_direct_value<std::unordered_map<K, View, H, E, A>, BasicJsonType, View> : is_string_key<K> {};
|
||||
|
||||
} // namespace view
|
||||
} // namespace detail
|
||||
|
||||
@@ -910,22 +910,25 @@ class basic_json_view
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename U, typename A>
|
||||
/// vectors of the types converted directly (faster than the library's
|
||||
/// from_json()) and containers of views (no from_json() reads them: a view
|
||||
/// is no value of BasicJsonType); other containers are read by from_json()
|
||||
template < typename U, typename A, typename std::enable_if < detail::view::is_direct_value<U, BasicJsonType, basic_json_view>::value, int >::type = 0 >
|
||||
std::vector<U, A> get_impl(detail::view::value_tag<std::vector<U, A>> /*unused*/, detail::priority_tag<2> /*unused*/) const
|
||||
{
|
||||
return detail::view::vector_value<basic_json_view, U, A>(*this);
|
||||
}
|
||||
|
||||
template<typename K, typename V, typename C, typename A, typename std::enable_if<detail::view::is_string_key<K>::value, int>::type = 0>
|
||||
std::map<K, V, C, A> get_impl(detail::view::value_tag<std::map<K, V, C, A>> /*unused*/, detail::priority_tag<2> /*unused*/) const
|
||||
template<typename K, typename C, typename A, typename std::enable_if<detail::view::is_string_key<K>::value, int>::type = 0>
|
||||
std::map<K, basic_json_view, C, A> get_impl(detail::view::value_tag<std::map<K, basic_json_view, C, A>> /*unused*/, detail::priority_tag<2> /*unused*/) const
|
||||
{
|
||||
return detail::view::map_value<std::map<K, V, C, A>>(*this);
|
||||
return detail::view::map_value<std::map<K, basic_json_view, C, A>>(*this);
|
||||
}
|
||||
|
||||
template<typename K, typename V, typename H, typename E, typename A, typename std::enable_if<detail::view::is_string_key<K>::value, int>::type = 0>
|
||||
std::unordered_map<K, V, H, E, A> get_impl(detail::view::value_tag<std::unordered_map<K, V, H, E, A>> /*unused*/, detail::priority_tag<2> /*unused*/) const
|
||||
template<typename K, typename H, typename E, typename A, typename std::enable_if<detail::view::is_string_key<K>::value, int>::type = 0>
|
||||
std::unordered_map<K, basic_json_view, H, E, A> get_impl(detail::view::value_tag<std::unordered_map<K, basic_json_view, H, E, A>> /*unused*/, detail::priority_tag<2> /*unused*/) const
|
||||
{
|
||||
return detail::view::map_value<std::unordered_map<K, V, H, E, A>>(*this);
|
||||
return detail::view::map_value<std::unordered_map<K, basic_json_view, H, E, A>>(*this);
|
||||
}
|
||||
|
||||
/// whether the from_json() of T's serializer reads views (see
|
||||
|
||||
Generated
+218
-76
@@ -2720,7 +2720,7 @@ JSON_HEDLEY_DIAGNOSTIC_POP
|
||||
return ej_pair.second == j; \
|
||||
}); \
|
||||
if (it != std::end(m)) e = it->first; \
|
||||
else ::nlohmann::detail::templated_json_throw<nlohmann::detail::out_of_range>(nlohmann::detail::out_of_range::create(nlohmann::detail::exception_id::value_out_of_range, nlohmann::detail::concat("enum value out of range for " #ENUM_TYPE ": ", nlohmann::detail::from_json_dump(j)), nlohmann::detail::from_json_context(j))); \
|
||||
else ::nlohmann::detail::templated_json_throw<nlohmann::detail::out_of_range>(nlohmann::detail::out_of_range::create(nlohmann::detail::exception_id::value_out_of_range, nlohmann::detail::concat("enum value out of range for " #ENUM_TYPE ": ", nlohmann::detail::from_json_dump(j)), nlohmann::detail::exception_context(j))); \
|
||||
}
|
||||
|
||||
// Ugly macros to avoid uglier copy-paste when specializing basic_json. They
|
||||
@@ -5914,6 +5914,20 @@ void templated_json_throw(ExceptionType exception)
|
||||
(void)exception;
|
||||
}
|
||||
|
||||
// the context of an exception about j: j itself for a basic_json value (whose
|
||||
// path JSON_DIAGNOSTICS shows), none for a view of <nlohmann/json_view.hpp>
|
||||
template<typename BasicJsonType, enable_if_t<is_basic_json<BasicJsonType>::value, int> = 0>
|
||||
const BasicJsonType * exception_context(const BasicJsonType& j) noexcept
|
||||
{
|
||||
return &j;
|
||||
}
|
||||
|
||||
template<typename View, enable_if_t<is_json_view<View>::value, int> = 0>
|
||||
std::nullptr_t exception_context(const View& /*unused*/) noexcept
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief throws because @a j does not have the type a conversion expects
|
||||
@param[in] expected the expected type(s), e.g. "array" or "binary or array"
|
||||
@@ -5925,7 +5939,7 @@ JSON_HEDLEY_NO_RETURN JSON_HEDLEY_NEVER_INLINE void throw_type_must_be(const cha
|
||||
{
|
||||
static_cast<void>(expected); // unused when JSON_NOEXCEPTION is defined
|
||||
static_cast<void>(j);
|
||||
JSON_THROW(type_error::create(exception_id::type_mismatch, concat("type must be ", expected, ", but is ", j.type_name()), &j));
|
||||
JSON_THROW(type_error::create(exception_id::type_mismatch, concat("type must be ", expected, ", but is ", j.type_name()), exception_context(j)));
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -6154,6 +6168,70 @@ NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||
namespace detail
|
||||
{
|
||||
|
||||
// The from_json() overloads below read basic_json values and the views of
|
||||
// <nlohmann/json_view.hpp> (BasicJsonType is then a view, and
|
||||
// json_type_of_t<BasicJsonType> its basic_json type). The helpers below are
|
||||
// the accesses that differ between the two.
|
||||
|
||||
// the enable_if parameter of the overloads that read basic_json values (written
|
||||
// with negation<> because astyle spaces out a template argument list with '!')
|
||||
template<typename T>
|
||||
using enable_if_not_view_t = enable_if_t<negation<is_json_view<T>>::value, int>;
|
||||
|
||||
// the boolean of j, a boolean
|
||||
template < typename BasicJsonType, enable_if_not_view_t<BasicJsonType> = 0 >
|
||||
typename BasicJsonType::boolean_t boolean_value(const BasicJsonType& j)
|
||||
{
|
||||
return *j.template get_ptr<const typename BasicJsonType::boolean_t*>();
|
||||
}
|
||||
|
||||
template<typename View, enable_if_t<is_json_view<View>::value, int> = 0>
|
||||
bool boolean_value(const View& v)
|
||||
{
|
||||
return v.template get<bool>();
|
||||
}
|
||||
|
||||
// the string of j, a string
|
||||
template < typename BasicJsonType, enable_if_not_view_t<BasicJsonType> = 0 >
|
||||
const typename BasicJsonType::string_t& string_value(const BasicJsonType& j)
|
||||
{
|
||||
return *j.template get_ptr<const typename BasicJsonType::string_t*>();
|
||||
}
|
||||
|
||||
template<typename View, enable_if_t<is_json_view<View>::value, int> = 0>
|
||||
typename View::string_t string_value(const View& v)
|
||||
{
|
||||
const auto s = v.get_string();
|
||||
return typename View::string_t(s.data(), s.size());
|
||||
}
|
||||
|
||||
// the binary value of j, a binary value (never a view: a view of a JSON text
|
||||
// holds no binary values)
|
||||
template < typename BasicJsonType, enable_if_not_view_t<BasicJsonType> = 0 >
|
||||
const typename BasicJsonType::binary_t& binary_value(const BasicJsonType& j)
|
||||
{
|
||||
return *j.template get_ptr<const typename BasicJsonType::binary_t*>();
|
||||
}
|
||||
|
||||
template<typename View, enable_if_t<is_json_view<View>::value, int> = 0>
|
||||
typename View::basic_json_type::binary_t binary_value(const View& /*unused*/)
|
||||
{
|
||||
return {}; // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
// the elements of j, an array, for a range-based for loop
|
||||
template < typename BasicJsonType, enable_if_not_view_t<BasicJsonType> = 0 >
|
||||
const typename BasicJsonType::array_t& array_elements(const BasicJsonType& j)
|
||||
{
|
||||
return *j.template get_ptr<const typename BasicJsonType::array_t*>();
|
||||
}
|
||||
|
||||
template<typename View, enable_if_t<is_json_view<View>::value, int> = 0>
|
||||
View array_elements(const View& v) noexcept
|
||||
{
|
||||
return v; // (a view is two pointers)
|
||||
}
|
||||
|
||||
template<typename BasicJsonType>
|
||||
inline void from_json(const BasicJsonType& j, typename std::nullptr_t& n)
|
||||
{
|
||||
@@ -6182,7 +6260,7 @@ void from_json(const BasicJsonType& j, std::optional<T>& opt)
|
||||
|
||||
// read a number value of any of the three number types into val;
|
||||
// returns false (leaving val untouched) if j is not a number
|
||||
template<typename BasicJsonType, typename ArithmeticType>
|
||||
template < typename BasicJsonType, typename ArithmeticType, enable_if_not_view_t<BasicJsonType> = 0 >
|
||||
bool get_number_value(const BasicJsonType& j, ArithmeticType& val)
|
||||
{
|
||||
switch (static_cast<value_t>(j))
|
||||
@@ -6219,10 +6297,22 @@ bool get_number_value(const BasicJsonType& j, ArithmeticType& val)
|
||||
}
|
||||
}
|
||||
|
||||
// a view converts numbers itself (as basic_json does)
|
||||
template<typename View, typename ArithmeticType, enable_if_t<is_json_view<View>::value, int> = 0>
|
||||
bool get_number_value(const View& v, ArithmeticType& val)
|
||||
{
|
||||
if (!v.is_number())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
val = v.template get<ArithmeticType>();
|
||||
return true;
|
||||
}
|
||||
|
||||
// overloads for basic_json template parameters
|
||||
template < typename BasicJsonType, typename ArithmeticType,
|
||||
enable_if_t < std::is_arithmetic<ArithmeticType>::value&&
|
||||
!std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value,
|
||||
!std::is_same<ArithmeticType, typename json_type_of_t<BasicJsonType>::boolean_t>::value,
|
||||
int > = 0 >
|
||||
void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val)
|
||||
{
|
||||
@@ -6233,31 +6323,31 @@ void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val)
|
||||
}
|
||||
|
||||
template<typename BasicJsonType>
|
||||
inline void from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b)
|
||||
inline void from_json(const BasicJsonType& j, typename json_type_of_t<BasicJsonType>::boolean_t& b)
|
||||
{
|
||||
if (JSON_HEDLEY_UNLIKELY(!j.is_boolean()))
|
||||
{
|
||||
throw_type_must_be("boolean", j);
|
||||
}
|
||||
b = *j.template get_ptr<const typename BasicJsonType::boolean_t*>();
|
||||
b = boolean_value(j);
|
||||
}
|
||||
|
||||
template<typename BasicJsonType>
|
||||
inline void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s)
|
||||
inline void from_json(const BasicJsonType& j, typename json_type_of_t<BasicJsonType>::string_t& s)
|
||||
{
|
||||
if (JSON_HEDLEY_UNLIKELY(!j.is_string()))
|
||||
{
|
||||
throw_type_must_be("string", j);
|
||||
}
|
||||
s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
|
||||
s = string_value(j);
|
||||
}
|
||||
|
||||
template <
|
||||
typename BasicJsonType, typename StringType,
|
||||
enable_if_t <
|
||||
std::is_assignable<StringType&, const typename BasicJsonType::string_t>::value
|
||||
&& is_detected_exact<typename BasicJsonType::string_t::value_type, value_type_t, StringType>::value
|
||||
&& !std::is_same<typename BasicJsonType::string_t, StringType>::value
|
||||
std::is_assignable<StringType&, const typename json_type_of_t<BasicJsonType>::string_t>::value
|
||||
&& is_detected_exact<typename json_type_of_t<BasicJsonType>::string_t::value_type, value_type_t, StringType>::value
|
||||
&& !std::is_same<typename json_type_of_t<BasicJsonType>::string_t, StringType>::value
|
||||
&& !is_json_ref<StringType>::value, int > = 0 >
|
||||
inline void from_json(const BasicJsonType& j, StringType& s)
|
||||
{
|
||||
@@ -6266,23 +6356,23 @@ inline void from_json(const BasicJsonType& j, StringType& s)
|
||||
throw_type_must_be("string", j);
|
||||
}
|
||||
|
||||
s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
|
||||
s = string_value(j);
|
||||
}
|
||||
|
||||
template<typename BasicJsonType>
|
||||
inline void from_json(const BasicJsonType& j, typename BasicJsonType::number_float_t& val)
|
||||
inline void from_json(const BasicJsonType& j, typename json_type_of_t<BasicJsonType>::number_float_t& val)
|
||||
{
|
||||
get_arithmetic_value(j, val);
|
||||
}
|
||||
|
||||
template<typename BasicJsonType>
|
||||
inline void from_json(const BasicJsonType& j, number_unsigned_overload_t<BasicJsonType>& val)
|
||||
inline void from_json(const BasicJsonType& j, number_unsigned_overload_t<json_type_of_t<BasicJsonType>>& val)
|
||||
{
|
||||
get_arithmetic_value(j, val);
|
||||
}
|
||||
|
||||
template<typename BasicJsonType>
|
||||
inline void from_json(const BasicJsonType& j, typename BasicJsonType::number_integer_t& val)
|
||||
inline void from_json(const BasicJsonType& j, typename json_type_of_t<BasicJsonType>::number_integer_t& val)
|
||||
{
|
||||
get_arithmetic_value(j, val);
|
||||
}
|
||||
@@ -6294,8 +6384,8 @@ inline void from_json(const BasicJsonType& j, EnumType& e)
|
||||
{
|
||||
using underlying_type = typename std::underlying_type<EnumType>::type;
|
||||
// get_arithmetic_value() does not accept boolean_t; read the number that to_json() wrote instead
|
||||
using value_type = typename std::conditional<std::is_same<underlying_type, typename BasicJsonType::boolean_t>::value,
|
||||
typename BasicJsonType::number_unsigned_t, underlying_type>::type;
|
||||
using value_type = typename std::conditional<std::is_same<underlying_type, typename json_type_of_t<BasicJsonType>::boolean_t>::value,
|
||||
typename json_type_of_t<BasicJsonType>::number_unsigned_t, underlying_type>::type;
|
||||
value_type val;
|
||||
get_arithmetic_value(j, val);
|
||||
e = static_cast<EnumType>(bool_aware_static_cast<underlying_type>(val));
|
||||
@@ -6304,7 +6394,7 @@ inline void from_json(const BasicJsonType& j, EnumType& e)
|
||||
|
||||
// forward_list doesn't have an insert method
|
||||
template<typename BasicJsonType, typename T, typename Allocator,
|
||||
enable_if_t<is_getable<BasicJsonType, T>::value, int> = 0>
|
||||
enable_if_t<is_getable<json_type_of_t<BasicJsonType>, T>::value, int> = 0>
|
||||
inline void from_json(const BasicJsonType& j, std::forward_list<T, Allocator>& l)
|
||||
{
|
||||
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
|
||||
@@ -6312,16 +6402,16 @@ inline void from_json(const BasicJsonType& j, std::forward_list<T, Allocator>& l
|
||||
throw_type_must_be("array", j);
|
||||
}
|
||||
l.clear();
|
||||
std::transform(j.rbegin(), j.rend(),
|
||||
std::front_inserter(l), [](const BasicJsonType & i)
|
||||
auto pos = l.before_begin();
|
||||
for (const auto& elem : array_elements(j))
|
||||
{
|
||||
return i.template get<T>();
|
||||
});
|
||||
pos = l.insert_after(pos, elem.template get<T>());
|
||||
}
|
||||
}
|
||||
|
||||
// valarray doesn't have an insert method
|
||||
template<typename BasicJsonType, typename T,
|
||||
enable_if_t<is_getable<BasicJsonType, T>::value, int> = 0>
|
||||
enable_if_t<is_getable<json_type_of_t<BasicJsonType>, T>::value, int> = 0>
|
||||
inline void from_json(const BasicJsonType& j, std::valarray<T>& l)
|
||||
{
|
||||
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
|
||||
@@ -6329,11 +6419,11 @@ inline void from_json(const BasicJsonType& j, std::valarray<T>& l)
|
||||
throw_type_must_be("array", j);
|
||||
}
|
||||
l.resize(j.size());
|
||||
std::transform(j.begin(), j.end(), std::begin(l),
|
||||
[](const BasicJsonType & elem)
|
||||
std::size_t i = 0;
|
||||
for (const auto& elem : array_elements(j))
|
||||
{
|
||||
return elem.template get<T>();
|
||||
});
|
||||
l[i++] = elem.template get<T>();
|
||||
}
|
||||
}
|
||||
|
||||
// element is not itself a C array: read it directly
|
||||
@@ -6361,7 +6451,8 @@ auto from_json(const BasicJsonType& j, T (&arr)[N]) // NOLINT(cppcoreguidelines
|
||||
from_json_c_array_element(j, arr);
|
||||
}
|
||||
|
||||
template<typename BasicJsonType>
|
||||
// (for a view, array_t is read element by element below)
|
||||
template < typename BasicJsonType, enable_if_not_view_t<BasicJsonType> = 0 >
|
||||
inline void from_json_array_impl(const BasicJsonType& j, typename BasicJsonType::array_t& arr, priority_tag<3> /*unused*/)
|
||||
{
|
||||
arr = *j.template get_ptr<const typename BasicJsonType::array_t*>();
|
||||
@@ -6370,7 +6461,7 @@ inline void from_json_array_impl(const BasicJsonType& j, typename BasicJsonType:
|
||||
// fill a std::array from the JSON array j: the size is checked once and the
|
||||
// elements are read in order, so a short array converts the elements it has and
|
||||
// then throws the out_of_range error at() would throw for the first missing one
|
||||
template<typename BasicJsonType, typename T, std::size_t N>
|
||||
template < typename BasicJsonType, typename T, std::size_t N, enable_if_not_view_t<BasicJsonType> = 0 >
|
||||
void from_json_std_array(const BasicJsonType& j, std::array<T, N>& arr)
|
||||
{
|
||||
const auto& inner_array = *j.template get_ptr<const typename BasicJsonType::array_t*>();
|
||||
@@ -6385,6 +6476,21 @@ void from_json_std_array(const BasicJsonType& j, std::array<T, N>& arr)
|
||||
}
|
||||
}
|
||||
|
||||
// (a view has no random access to the elements: they are read in order)
|
||||
template<typename View, typename T, std::size_t N, enable_if_t<is_json_view<View>::value, int> = 0>
|
||||
void from_json_std_array(const View& v, std::array<T, N>& arr)
|
||||
{
|
||||
std::size_t size = 0;
|
||||
for (auto it = v.begin(); size < N && it != v.end(); ++it)
|
||||
{
|
||||
arr[size++] = (*it).template get<T>();
|
||||
}
|
||||
if (JSON_HEDLEY_UNLIKELY(size < N))
|
||||
{
|
||||
static_cast<void>(v.at(size));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, typename T, std::size_t N>
|
||||
auto from_json_array_impl(const BasicJsonType& j, std::array<T, N>& arr,
|
||||
priority_tag<2> /*unused*/)
|
||||
@@ -6433,9 +6539,8 @@ auto from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr, p
|
||||
void())
|
||||
{
|
||||
ConstructibleArrayType ret;
|
||||
const auto* inner_array = j.template get_ptr<const typename BasicJsonType::array_t*>();
|
||||
reserve_if_possible(ret, inner_array->size(), priority_tag<1> {});
|
||||
for (const auto& elem : *inner_array)
|
||||
reserve_if_possible(ret, j.size(), priority_tag<1> {});
|
||||
for (const auto& elem : array_elements(j))
|
||||
{
|
||||
// get<BasicJsonType>() returns *this, this won't call a from_json
|
||||
// method when value_type is BasicJsonType
|
||||
@@ -6446,11 +6551,11 @@ auto from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr, p
|
||||
|
||||
template < typename BasicJsonType, typename ConstructibleArrayType,
|
||||
enable_if_t <
|
||||
is_constructible_array_type<BasicJsonType, ConstructibleArrayType>::value&&
|
||||
!is_constructible_object_type<BasicJsonType, ConstructibleArrayType>::value&&
|
||||
!is_constructible_string_type<BasicJsonType, ConstructibleArrayType>::value&&
|
||||
!std::is_same<ConstructibleArrayType, typename BasicJsonType::binary_t>::value&&
|
||||
!is_compatible_binary_type<BasicJsonType, ConstructibleArrayType>::value&&
|
||||
is_constructible_array_type<json_type_of_t<BasicJsonType>, ConstructibleArrayType>::value&&
|
||||
!is_constructible_object_type<json_type_of_t<BasicJsonType>, ConstructibleArrayType>::value&&
|
||||
!is_constructible_string_type<json_type_of_t<BasicJsonType>, ConstructibleArrayType>::value&&
|
||||
!std::is_same<ConstructibleArrayType, typename json_type_of_t<BasicJsonType>::binary_t>::value&&
|
||||
!is_compatible_binary_type<json_type_of_t<BasicJsonType>, ConstructibleArrayType>::value&&
|
||||
!is_basic_json<ConstructibleArrayType>::value,
|
||||
int > = 0 >
|
||||
auto from_json(const BasicJsonType& j, ConstructibleArrayType& arr)
|
||||
@@ -6517,24 +6622,24 @@ auto from_json(const BasicJsonType& j, identity_tag<std::array<T, N>> tag)
|
||||
}
|
||||
|
||||
template<typename BasicJsonType>
|
||||
inline void from_json(const BasicJsonType& j, typename BasicJsonType::binary_t& bin)
|
||||
inline void from_json(const BasicJsonType& j, typename json_type_of_t<BasicJsonType>::binary_t& bin)
|
||||
{
|
||||
if (JSON_HEDLEY_UNLIKELY(!j.is_binary()))
|
||||
{
|
||||
throw_type_must_be("binary", j);
|
||||
}
|
||||
|
||||
bin = *j.template get_ptr<const typename BasicJsonType::binary_t*>();
|
||||
bin = binary_value(j);
|
||||
}
|
||||
|
||||
template < typename BasicJsonType, typename CompatibleArrayType,
|
||||
enable_if_t < is_compatible_binary_type<BasicJsonType, CompatibleArrayType>::value,
|
||||
enable_if_t < is_compatible_binary_type<json_type_of_t<BasicJsonType>, CompatibleArrayType>::value,
|
||||
int > = 0 >
|
||||
inline void from_json(const BasicJsonType& j, CompatibleArrayType& bin)
|
||||
{
|
||||
if (j.is_binary())
|
||||
{
|
||||
bin = static_cast<CompatibleArrayType>(*j.template get_ptr<const typename BasicJsonType::binary_t*>());
|
||||
bin = static_cast<CompatibleArrayType>(binary_value(j));
|
||||
}
|
||||
else if (j.is_array())
|
||||
{
|
||||
@@ -6563,8 +6668,47 @@ void from_json_object_emplace(ConstructibleObjectType& obj, Key&& key, Value&& v
|
||||
obj.emplace(std::forward<Key>(key), std::forward<Value>(value));
|
||||
}
|
||||
|
||||
// a member of a view's object: a later member with the same key replaces an
|
||||
// earlier one, as parse() keeps the last value of a repeated key (containers
|
||||
// without operator[] keep the first)
|
||||
template<typename ConstructibleObjectType, typename Key, typename Value>
|
||||
auto from_json_object_assign(ConstructibleObjectType& obj, Key&& key, Value&& value, priority_tag<1> /*unused*/)
|
||||
-> decltype(obj[std::forward<Key>(key)] = std::forward<Value>(value), void())
|
||||
{
|
||||
obj[std::forward<Key>(key)] = std::forward<Value>(value);
|
||||
}
|
||||
|
||||
template<typename ConstructibleObjectType, typename Key, typename Value>
|
||||
void from_json_object_assign(ConstructibleObjectType& obj, Key&& key, Value&& value, priority_tag<0> /*unused*/)
|
||||
{
|
||||
obj.emplace(std::forward<Key>(key), std::forward<Value>(value));
|
||||
}
|
||||
|
||||
template < typename BasicJsonType, typename ConstructibleObjectType, enable_if_not_view_t<BasicJsonType> = 0 >
|
||||
void from_json_object_impl(const BasicJsonType& j, ConstructibleObjectType& ret)
|
||||
{
|
||||
const auto* inner_object = j.template get_ptr<const typename BasicJsonType::object_t*>();
|
||||
reserve_if_possible(ret, inner_object->size(), priority_tag<1> {});
|
||||
for (const auto& p : *inner_object)
|
||||
{
|
||||
from_json_object_emplace(ret, p.first, p.second.template get<typename ConstructibleObjectType::mapped_type>(), priority_tag<1> {});
|
||||
}
|
||||
}
|
||||
|
||||
template<typename View, typename ConstructibleObjectType, enable_if_t<is_json_view<View>::value, int> = 0>
|
||||
void from_json_object_impl(const View& v, ConstructibleObjectType& ret)
|
||||
{
|
||||
using string_t = typename View::basic_json_type::object_t::key_type;
|
||||
reserve_if_possible(ret, v.size(), priority_tag<1> {});
|
||||
for (const auto item : v.items())
|
||||
{
|
||||
const auto key = item.key();
|
||||
from_json_object_assign(ret, string_t(key.data(), key.size()), item.value().template get<typename ConstructibleObjectType::mapped_type>(), priority_tag<1> {});
|
||||
}
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, typename ConstructibleObjectType,
|
||||
enable_if_t<is_constructible_object_type<BasicJsonType, ConstructibleObjectType>::value, int> = 0>
|
||||
enable_if_t<is_constructible_object_type<json_type_of_t<BasicJsonType>, ConstructibleObjectType>::value, int> = 0>
|
||||
inline void from_json(const BasicJsonType& j, ConstructibleObjectType& obj)
|
||||
{
|
||||
if (JSON_HEDLEY_UNLIKELY(!j.is_object()))
|
||||
@@ -6573,12 +6717,7 @@ inline void from_json(const BasicJsonType& j, ConstructibleObjectType& obj)
|
||||
}
|
||||
|
||||
ConstructibleObjectType ret;
|
||||
const auto* inner_object = j.template get_ptr<const typename BasicJsonType::object_t*>();
|
||||
reserve_if_possible(ret, inner_object->size(), priority_tag<1> {});
|
||||
for (const auto& p : *inner_object)
|
||||
{
|
||||
from_json_object_emplace(ret, p.first, p.second.template get<typename ConstructibleObjectType::mapped_type>(), priority_tag<1> {});
|
||||
}
|
||||
from_json_object_impl(j, ret);
|
||||
obj = std::move(ret);
|
||||
}
|
||||
|
||||
@@ -6587,10 +6726,10 @@ inline void from_json(const BasicJsonType& j, ConstructibleObjectType& obj)
|
||||
template < typename BasicJsonType, typename ArithmeticType,
|
||||
enable_if_t <
|
||||
std::is_arithmetic<ArithmeticType>::value&&
|
||||
!std::is_same<ArithmeticType, typename BasicJsonType::number_unsigned_t>::value&&
|
||||
!std::is_same<ArithmeticType, typename BasicJsonType::number_integer_t>::value&&
|
||||
!std::is_same<ArithmeticType, typename BasicJsonType::number_float_t>::value&&
|
||||
!std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value,
|
||||
!std::is_same<ArithmeticType, typename json_type_of_t<BasicJsonType>::number_unsigned_t>::value&&
|
||||
!std::is_same<ArithmeticType, typename json_type_of_t<BasicJsonType>::number_integer_t>::value&&
|
||||
!std::is_same<ArithmeticType, typename json_type_of_t<BasicJsonType>::number_float_t>::value&&
|
||||
!std::is_same<ArithmeticType, typename json_type_of_t<BasicJsonType>::boolean_t>::value,
|
||||
int > = 0 >
|
||||
inline void from_json(const BasicJsonType& j, ArithmeticType& val)
|
||||
{
|
||||
@@ -6604,7 +6743,7 @@ inline void from_json(const BasicJsonType& j, ArithmeticType& val)
|
||||
{
|
||||
throw_type_must_be("number", j);
|
||||
}
|
||||
val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::boolean_t*>());
|
||||
val = static_cast<ArithmeticType>(boolean_value(j));
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, typename Type>
|
||||
@@ -6614,7 +6753,7 @@ detail::uncvref_t<Type> from_json_tuple_get_impl(BasicJsonType&& j, detail::iden
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, typename Type,
|
||||
detail::enable_if_t<detail::is_compatible_reference_type<BasicJsonType, Type>::value, int> = 0>
|
||||
detail::enable_if_t<conjunction<is_basic_json<uncvref_t<BasicJsonType>>, is_compatible_reference_type<BasicJsonType, Type>>::value, int> = 0>
|
||||
Type from_json_tuple_get_impl(BasicJsonType && j, detail::identity_tag<Type> /*unused*/, detail::priority_tag<1> /*unused*/)
|
||||
{
|
||||
return std::forward<BasicJsonType>(j).template get_ref<Type>();
|
||||
@@ -6658,7 +6797,7 @@ inline void from_json_tuple_impl(const BasicJsonType& j, std::pair<A1, A2>& p, p
|
||||
template<typename BasicJsonType, typename... Args>
|
||||
std::tuple<Args...> from_json_tuple_impl(const BasicJsonType& j, identity_tag<std::tuple<Args...>> /*unused*/, priority_tag<2> /*unused*/)
|
||||
{
|
||||
static_assert(conjunction<disjunction<negation<std::is_reference<Args>>, is_compatible_reference_type<const BasicJsonType&, Args>>...>::value,
|
||||
static_assert(conjunction<disjunction<negation<std::is_reference<Args>>, conjunction<is_basic_json<BasicJsonType>, is_compatible_reference_type<const BasicJsonType&, Args>>>...>::value,
|
||||
"Can not return a tuple containing references to types not contained in a Json, try Json::get_to()");
|
||||
return from_json_tuple_impl_base<1, Args...>(j, index_sequence_for<Args...> {});
|
||||
}
|
||||
@@ -6704,7 +6843,7 @@ void from_json_pair_array_to_map(const BasicJsonType& j, MapType& m)
|
||||
// read a map with enum keys from an object, using the enum's own from_json for
|
||||
// the keys (e.g., from NLOHMANN_JSON_SERIALIZE_ENUM); this is the form written
|
||||
// with JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS
|
||||
template<typename BasicJsonType, typename Map>
|
||||
template < typename BasicJsonType, typename Map, enable_if_not_view_t<BasicJsonType> = 0 >
|
||||
inline bool from_json_enum_keyed_object(const BasicJsonType& j, Map& m, std::true_type /*key is enum*/)
|
||||
{
|
||||
if (!j.is_object())
|
||||
@@ -6719,6 +6858,24 @@ inline bool from_json_enum_keyed_object(const BasicJsonType& j, Map& m, std::tru
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename View, typename Map, enable_if_t<is_json_view<View>::value, int> = 0>
|
||||
inline bool from_json_enum_keyed_object(const View& v, Map& m, std::true_type /*key is enum*/)
|
||||
{
|
||||
using json_t = typename View::basic_json_type;
|
||||
if (!v.is_object())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
m.clear();
|
||||
for (const auto item : v.items())
|
||||
{
|
||||
const auto key = item.key();
|
||||
from_json_object_assign(m, json_t(typename json_t::string_t(key.data(), key.size())).template get<typename Map::key_type>(),
|
||||
item.value().template get<typename Map::mapped_type>(), priority_tag<1> {});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, typename Map>
|
||||
inline bool from_json_enum_keyed_object(const BasicJsonType& /*j*/, Map& /*m*/, std::false_type /*key is enum*/)
|
||||
{
|
||||
@@ -6727,7 +6884,7 @@ inline bool from_json_enum_keyed_object(const BasicJsonType& /*j*/, Map& /*m*/,
|
||||
|
||||
template < typename BasicJsonType, typename Key, typename Value, typename Compare, typename Allocator,
|
||||
typename = enable_if_t < !std::is_constructible <
|
||||
typename BasicJsonType::string_t, Key >::value >>
|
||||
typename json_type_of_t<BasicJsonType>::string_t, Key >::value >>
|
||||
void from_json(const BasicJsonType& j, std::map<Key, Value, Compare, Allocator>& m)
|
||||
{
|
||||
// NOLINTNEXTLINE(modernize-type-traits) we use C++11
|
||||
@@ -6740,7 +6897,7 @@ void from_json(const BasicJsonType& j, std::map<Key, Value, Compare, Allocator>&
|
||||
|
||||
template < typename BasicJsonType, typename Key, typename Value, typename Hash, typename KeyEqual, typename Allocator,
|
||||
typename = enable_if_t < !std::is_constructible <
|
||||
typename BasicJsonType::string_t, Key >::value >>
|
||||
typename json_type_of_t<BasicJsonType>::string_t, Key >::value >>
|
||||
void from_json(const BasicJsonType& j, std::unordered_map<Key, Value, Hash, KeyEqual, Allocator>& m)
|
||||
{
|
||||
// NOLINTNEXTLINE(modernize-type-traits) we use C++11
|
||||
@@ -6764,7 +6921,7 @@ inline void from_json(const BasicJsonType& j, std_fs::path& p)
|
||||
{
|
||||
throw_type_must_be("string", j);
|
||||
}
|
||||
const auto& s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
|
||||
const auto& s = string_value(j);
|
||||
// Checking for C++20 standard or later can be insufficient in case the
|
||||
// library support for char8_t is either incomplete or was disabled
|
||||
// altogether. Use the __cpp_lib_char8_t feature test instead.
|
||||
@@ -6803,10 +6960,9 @@ struct fn
|
||||
};
|
||||
} // namespace from_json_adl
|
||||
|
||||
// the sources whose from_json() is only looked up by ADL: views (the library's
|
||||
// overloads are written for basic_json) and the probe
|
||||
// the sources whose from_json() is only looked up by ADL: the probe
|
||||
template<typename T>
|
||||
struct is_adl_only_from_json_source : disjunction<is_json_view<T>, std::is_same<T, from_json_adl::probe>> {};
|
||||
struct is_adl_only_from_json_source : std::is_same<T, from_json_adl::probe> {};
|
||||
|
||||
struct from_json_fn
|
||||
{
|
||||
@@ -6857,20 +7013,6 @@ void from_json_base(const View& v, T& base)
|
||||
v.get_to(base);
|
||||
}
|
||||
|
||||
// the context of an exception thrown by a from_json() of the macros: the value
|
||||
// itself for basic_json (for JSON_DIAGNOSTICS), none for a view
|
||||
template<typename BasicJsonType, enable_if_t<is_basic_json<BasicJsonType>::value, int> = 0>
|
||||
const BasicJsonType * from_json_context(const BasicJsonType& j) noexcept
|
||||
{
|
||||
return &j;
|
||||
}
|
||||
|
||||
template<typename View, enable_if_t<is_json_view<View>::value, int> = 0>
|
||||
std::nullptr_t from_json_context(const View& /*unused*/) noexcept
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// a value as an exception message shows it (invalid UTF-8 replaced; the
|
||||
// strings of a view are always valid UTF-8)
|
||||
template<typename BasicJsonType, enable_if_t<is_basic_json<BasicJsonType>::value, int> = 0>
|
||||
|
||||
Generated
+17
-12
@@ -7797,14 +7797,16 @@ struct is_direct_value : std::integral_constant < bool,
|
||||
template<typename Traits, typename Alloc, typename BasicJsonType, typename View>
|
||||
struct is_direct_value<std::basic_string<char, Traits, Alloc>, BasicJsonType, View> : std::true_type {};
|
||||
|
||||
// (vectors of these, which are faster than through from_json(), and containers
|
||||
// of views; other containers are read by the library's from_json())
|
||||
template<typename U, typename A, typename BasicJsonType, typename View>
|
||||
struct is_direct_value<std::vector<U, A>, BasicJsonType, View> : std::true_type {};
|
||||
struct is_direct_value<std::vector<U, A>, BasicJsonType, View> : is_direct_value<U, BasicJsonType, View> {};
|
||||
|
||||
template<typename K, typename V, typename C, typename A, typename BasicJsonType, typename View>
|
||||
struct is_direct_value<std::map<K, V, C, A>, BasicJsonType, View> : is_string_key<K> {};
|
||||
template<typename K, typename C, typename A, typename BasicJsonType, typename View>
|
||||
struct is_direct_value<std::map<K, View, C, A>, BasicJsonType, View> : is_string_key<K> {};
|
||||
|
||||
template<typename K, typename V, typename H, typename E, typename A, typename BasicJsonType, typename View>
|
||||
struct is_direct_value<std::unordered_map<K, V, H, E, A>, BasicJsonType, View> : is_string_key<K> {};
|
||||
template<typename K, typename H, typename E, typename A, typename BasicJsonType, typename View>
|
||||
struct is_direct_value<std::unordered_map<K, View, H, E, A>, BasicJsonType, View> : is_string_key<K> {};
|
||||
|
||||
} // namespace view
|
||||
} // namespace detail
|
||||
@@ -8637,22 +8639,25 @@ class basic_json_view
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename U, typename A>
|
||||
/// vectors of the types converted directly (faster than the library's
|
||||
/// from_json()) and containers of views (no from_json() reads them: a view
|
||||
/// is no value of BasicJsonType); other containers are read by from_json()
|
||||
template < typename U, typename A, typename std::enable_if < detail::view::is_direct_value<U, BasicJsonType, basic_json_view>::value, int >::type = 0 >
|
||||
std::vector<U, A> get_impl(detail::view::value_tag<std::vector<U, A>> /*unused*/, detail::priority_tag<2> /*unused*/) const
|
||||
{
|
||||
return detail::view::vector_value<basic_json_view, U, A>(*this);
|
||||
}
|
||||
|
||||
template<typename K, typename V, typename C, typename A, typename std::enable_if<detail::view::is_string_key<K>::value, int>::type = 0>
|
||||
std::map<K, V, C, A> get_impl(detail::view::value_tag<std::map<K, V, C, A>> /*unused*/, detail::priority_tag<2> /*unused*/) const
|
||||
template<typename K, typename C, typename A, typename std::enable_if<detail::view::is_string_key<K>::value, int>::type = 0>
|
||||
std::map<K, basic_json_view, C, A> get_impl(detail::view::value_tag<std::map<K, basic_json_view, C, A>> /*unused*/, detail::priority_tag<2> /*unused*/) const
|
||||
{
|
||||
return detail::view::map_value<std::map<K, V, C, A>>(*this);
|
||||
return detail::view::map_value<std::map<K, basic_json_view, C, A>>(*this);
|
||||
}
|
||||
|
||||
template<typename K, typename V, typename H, typename E, typename A, typename std::enable_if<detail::view::is_string_key<K>::value, int>::type = 0>
|
||||
std::unordered_map<K, V, H, E, A> get_impl(detail::view::value_tag<std::unordered_map<K, V, H, E, A>> /*unused*/, detail::priority_tag<2> /*unused*/) const
|
||||
template<typename K, typename H, typename E, typename A, typename std::enable_if<detail::view::is_string_key<K>::value, int>::type = 0>
|
||||
std::unordered_map<K, basic_json_view, H, E, A> get_impl(detail::view::value_tag<std::unordered_map<K, basic_json_view, H, E, A>> /*unused*/, detail::priority_tag<2> /*unused*/) const
|
||||
{
|
||||
return detail::view::map_value<std::unordered_map<K, V, H, E, A>>(*this);
|
||||
return detail::view::map_value<std::unordered_map<K, basic_json_view, H, E, A>>(*this);
|
||||
}
|
||||
|
||||
/// whether the from_json() of T's serializer reads views (see
|
||||
|
||||
@@ -52,6 +52,11 @@ struct point
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
NLOHMANN_DEFINE_TYPE_INTRUSIVE(point, x, y)
|
||||
|
||||
friend bool operator==(const point& a, const point& b)
|
||||
{
|
||||
return a.x == b.x && a.y == b.y;
|
||||
}
|
||||
};
|
||||
|
||||
struct shape
|
||||
@@ -184,6 +189,13 @@ namespace
|
||||
{
|
||||
template<typename T, typename View = json_view>
|
||||
struct reads_view : nlohmann::detail::has_view_from_json<nlohmann::adl_serializer<T, void>, View, T> {};
|
||||
|
||||
// whether a member converts to the same T from the view and from the materialized value
|
||||
template<typename T>
|
||||
bool same(const json_view& v, const json& j, const char* key)
|
||||
{
|
||||
return v[key].get<T>() == j[key].get<T>();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("json_view from_json")
|
||||
@@ -215,39 +227,119 @@ TEST_CASE("json_view from_json")
|
||||
static_assert(!nlohmann::is_json_view<int>::value, "is_json_view");
|
||||
}
|
||||
|
||||
SECTION("the library's own conversions are not called with a view (and the probe compiles for them)")
|
||||
SECTION("the library's own conversions read views")
|
||||
{
|
||||
// these go through materialize() (vectors, maps with string keys,
|
||||
// strings, and numbers are converted by the view itself)
|
||||
static_assert(!reads_view<std::list<int>>::value, "std types");
|
||||
static_assert(!reads_view<std::deque<point>>::value, "std types");
|
||||
static_assert(!reads_view<std::set<std::string>>::value, "std types");
|
||||
static_assert(!reads_view<std::unordered_set<int>>::value, "std types");
|
||||
static_assert(!reads_view<std::forward_list<int>>::value, "std types");
|
||||
static_assert(!reads_view<std::valarray<double>>::value, "std types");
|
||||
static_assert(!reads_view<std::array<int, 3>>::value, "std types");
|
||||
static_assert(!reads_view<std::pair<int, std::string>>::value, "std types");
|
||||
static_assert(!reads_view<std::tuple<int, bool, point>>::value, "std types");
|
||||
static_assert(!reads_view<std::map<int, int>>::value, "std types");
|
||||
static_assert(!reads_view<std::unordered_map<int, point>>::value, "std types");
|
||||
static_assert(!reads_view<std::map<color, int>>::value, "std types");
|
||||
static_assert(!reads_view<std::map<std::string, int>>::value, "std types");
|
||||
static_assert(!reads_view<std::vector<point>>::value, "std types");
|
||||
static_assert(!reads_view<std::vector<bool>>::value, "std types");
|
||||
static_assert(!reads_view<std::vector<std::uint8_t>>::value, "std types");
|
||||
static_assert(!reads_view<std::string>::value, "std types");
|
||||
static_assert(!reads_view<int>::value, "std types");
|
||||
static_assert(!reads_view<bool>::value, "std types");
|
||||
static_assert(!reads_view<double>::value, "std types");
|
||||
static_assert(!reads_view<std::nullptr_t>::value, "std types");
|
||||
static_assert(!reads_view<json>::value, "std types");
|
||||
static_assert(!reads_view<json::binary_t>::value, "std types");
|
||||
static_assert(reads_view<std::list<int>>::value, "std types");
|
||||
static_assert(reads_view<std::deque<point>>::value, "std types");
|
||||
static_assert(reads_view<std::set<std::string>>::value, "std types");
|
||||
static_assert(reads_view<std::unordered_set<int>>::value, "std types");
|
||||
static_assert(reads_view<std::forward_list<int>>::value, "std types");
|
||||
static_assert(reads_view<std::valarray<double>>::value, "std types");
|
||||
static_assert(reads_view<std::array<int, 3>>::value, "std types");
|
||||
static_assert(reads_view<std::pair<int, std::string>>::value, "std types");
|
||||
static_assert(reads_view<std::tuple<int, bool, point>>::value, "std types");
|
||||
static_assert(reads_view<std::map<int, int>>::value, "std types");
|
||||
static_assert(reads_view<std::unordered_map<int, point>>::value, "std types");
|
||||
static_assert(reads_view<std::map<color, int>>::value, "std types");
|
||||
static_assert(reads_view<std::map<std::string, int>>::value, "std types");
|
||||
static_assert(reads_view<std::vector<point>>::value, "std types");
|
||||
static_assert(reads_view<std::vector<bool>>::value, "std types");
|
||||
static_assert(reads_view<std::vector<std::uint8_t>>::value, "std types");
|
||||
static_assert(reads_view<std::string>::value, "std types");
|
||||
static_assert(reads_view<int>::value, "std types");
|
||||
static_assert(reads_view<bool>::value, "std types");
|
||||
static_assert(reads_view<double>::value, "std types");
|
||||
static_assert(reads_view<std::nullptr_t>::value, "std types");
|
||||
static_assert(!reads_view<json>::value, "get<BasicJsonType>() is materialize()");
|
||||
static_assert(reads_view<json::binary_t>::value, "std types");
|
||||
#ifdef JSON_HAS_CPP_17
|
||||
static_assert(!reads_view<std::optional<point>>::value, "std types");
|
||||
static_assert(reads_view<std::optional<point>>::value, "std types");
|
||||
#endif
|
||||
CHECK(true);
|
||||
}
|
||||
|
||||
SECTION("std types: the same values as from the materialized value")
|
||||
{
|
||||
const json_document d = json_document::parse(R"({"ints": [3, 1, 2, 1], "strings": ["b", "a", "b"], "pairs": [[1, "x"], [2, "y"]],
|
||||
"points": [{"x": 1, "y": 2}, {"x": 3, "y": 4}], "object": {"b": 1, "a": 2}, "triple": [1, true, {"x": 5, "y": 6}],
|
||||
"colors": {"green": 1, "red": 2}, "bytes": [1, 2, 255], "nested": [[1, 2], [3]], "number": 1.5, "flag": true,
|
||||
"text": "hello", "nothing": null, "mixed": [1, 2.5, -3, 4], "flags": [true, false, true]})");
|
||||
const json j = d.root().materialize();
|
||||
const json_view v = d.root();
|
||||
CHECK(same<std::list<int>>(v, j, "ints"));
|
||||
CHECK(same<std::deque<int>>(v, j, "ints"));
|
||||
CHECK(same<std::set<int>>(v, j, "ints"));
|
||||
CHECK(same<std::multiset<int>>(v, j, "ints"));
|
||||
CHECK(same<std::unordered_set<std::string>>(v, j, "strings"));
|
||||
CHECK(same<std::forward_list<int>>(v, j, "ints"));
|
||||
CHECK(same<std::array<int, 4>>(v, j, "ints"));
|
||||
CHECK(same<std::array<double, 4>>(v, j, "mixed"));
|
||||
CHECK((v["pairs"][0].get<std::pair<int, std::string>>() == j["pairs"][0].get<std::pair<int, std::string>>()));
|
||||
CHECK(same<std::vector<std::pair<int, std::string>>>(v, j, "pairs"));
|
||||
CHECK(same<std::tuple<int, bool, point>>(v, j, "triple"));
|
||||
CHECK(same<std::map<int, std::string>>(v, j, "pairs"));
|
||||
CHECK(same<std::unordered_map<int, std::string>>(v, j, "pairs"));
|
||||
CHECK(same<std::map<std::string, int>>(v, j, "object"));
|
||||
CHECK(same<std::unordered_map<std::string, int>>(v, j, "object"));
|
||||
CHECK(same<std::map<color, int>>(v, j, "colors"));
|
||||
CHECK(same<std::vector<point>>(v, j, "points"));
|
||||
CHECK(same<std::vector<int>>(v, j, "ints"));
|
||||
CHECK(same<std::vector<bool>>(v, j, "flags"));
|
||||
CHECK(same<std::vector<std::uint8_t>>(v, j, "bytes"));
|
||||
CHECK(same<std::vector<std::vector<int>>>(v, j, "nested"));
|
||||
CHECK(same<std::vector<json>>(v, j, "mixed"));
|
||||
CHECK(same<double>(v, j, "number"));
|
||||
CHECK(same<bool>(v, j, "flag"));
|
||||
CHECK(same<std::string>(v, j, "text"));
|
||||
CHECK(same<std::nullptr_t>(v, j, "nothing"));
|
||||
CHECK(same<json>(v, j, "object"));
|
||||
const std::valarray<int> va = v["ints"].get<std::valarray<int>>();
|
||||
CHECK(va.size() == 4);
|
||||
CHECK(va[0] == 3);
|
||||
int c_array[2][2] = {{0, 0}, {0, 0}}; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays): the conversion to C arrays
|
||||
v["nested"][0].get_to(c_array[0]);
|
||||
CHECK(c_array[0][1] == 2);
|
||||
#ifdef JSON_HAS_CPP_17
|
||||
CHECK(v["points"][0].get<std::optional<point>>()->y == 2);
|
||||
CHECK(!v["nothing"].get<std::optional<point>>().has_value());
|
||||
#endif
|
||||
// containers of views keep views of the elements
|
||||
const std::vector<json_view> views = v["points"].get<std::vector<json_view>>();
|
||||
CHECK(views.size() == 2);
|
||||
CHECK(views[1]["x"].get<int>() == 3);
|
||||
CHECK(v["object"].get<std::map<std::string, json_view>>().at("a").get<int>() == 2);
|
||||
}
|
||||
|
||||
SECTION("std types: duplicate keys keep the last value, as from the materialized value")
|
||||
{
|
||||
const json_document d = json_document::parse(R"({"a": 1, "b": 2, "a": 3})");
|
||||
CHECK((d.root().get<std::map<std::string, int>>() == d.root().materialize().get<std::map<std::string, int>>()));
|
||||
CHECK(d.root().get<std::map<std::string, int>>().at("a") == 3);
|
||||
CHECK(d.root().get<std::unordered_map<std::string, int>>().at("a") == 3);
|
||||
}
|
||||
|
||||
#if !defined(JSON_NOEXCEPTION) && !JSON_DIAGNOSTICS
|
||||
SECTION("std types: the same errors as from the materialized value")
|
||||
{
|
||||
const json_document d = json_document::parse(R"([[1, "x"], {"a": 1}, "text", [1], 5, null])");
|
||||
const json j = d.root().materialize();
|
||||
for (std::size_t i = 0; i < 6; ++i)
|
||||
{
|
||||
CAPTURE(i)
|
||||
const json_view v = d.root()[i];
|
||||
CHECK(exception_of_call([&] { static_cast<void>(v.get<std::list<int>>()); }) == exception_of_call([&] { static_cast<void>(j[i].get<std::list<int>>()); }));
|
||||
CHECK(exception_of_call([&] { static_cast<void>(v.get<std::forward_list<int>>()); }) == exception_of_call([&] { static_cast<void>(j[i].get<std::forward_list<int>>()); }));
|
||||
CHECK(exception_of_call([&] { static_cast<void>(v.get<std::array<int, 2>>()); }) == exception_of_call([&] { static_cast<void>(j[i].get<std::array<int, 2>>()); }));
|
||||
CHECK(exception_of_call([&] { static_cast<void>(v.get<std::pair<int, std::string>>()); }) == exception_of_call([&] { static_cast<void>(j[i].get<std::pair<int, std::string>>()); }));
|
||||
CHECK(exception_of_call([&] { static_cast<void>(v.get<std::map<std::string, int>>()); }) == exception_of_call([&] { static_cast<void>(j[i].get<std::map<std::string, int>>()); }));
|
||||
CHECK(exception_of_call([&] { static_cast<void>(v.get<std::map<int, int>>()); }) == exception_of_call([&] { static_cast<void>(j[i].get<std::map<int, int>>()); }));
|
||||
CHECK(exception_of_call([&] { static_cast<void>(v.get<std::vector<std::uint8_t>>()); }) == exception_of_call([&] { static_cast<void>(j[i].get<std::vector<std::uint8_t>>()); }));
|
||||
CHECK(exception_of_call([&] { static_cast<void>(v.get<json::binary_t>()); }) == exception_of_call([&] { static_cast<void>(j[i].get<json::binary_t>()); }));
|
||||
CHECK(exception_of_call([&] { static_cast<void>(v.get<std::valarray<int>>()); }) == exception_of_call([&] { static_cast<void>(j[i].get<std::valarray<int>>()); }));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
SECTION("macro types")
|
||||
{
|
||||
const json_document d = json_document::parse(R"({"name": "s", "points": [{"x": 1, "y": 2}, {"x": 3, "y": 4}],
|
||||
|
||||
Reference in new issue
Block a user