* Split the json_view feature page into sub-pages
The single features/json_view.md page grew to ~600 lines covering eight
topics. Split it into features/json_view/ with an overview page and
pages for ownership and lifetime, differences from basic_json, reading
values, generic code, editing, and images.
The new differences page collects what was spread over several sections
("What is the same", "What is different", "Duplicate keys", and notes in
the conversion and serialization sections) under one summary table, and
adds the parts of the basic_json interface a view does not have. The
other pages now link to it instead of restating the rules.
Internal links across the documentation point to the new pages.
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
* Docs: fix stale comments and trim repeated text in json_view pages
- fig-jsonview.js/.css: point the header comments at the new pages
- reading.md: views' strings are valid as long as the document (and a
borrowed source text), as lifetime.md says
- reading.md, generic_code.md: link to differences.md instead of
restating the member-order and repeated-key rules
- differences.md: drop the third mention of ordering comparisons, name
rbegin()/rend() in the iterator row
- exceptions.md: link editable documents to editing.md
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
---------
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
5.0 KiB
Writing generic code
View types
A view's type names its BasicJsonType and its view_mode:
json_view is #!cpp basic_json_view<json, view_mode::read_only>, and
json_editable_view is #!cpp basic_json_view<json, view_mode::editable>. These
are different types. The only conversion between them turns a view of a read-only document into a view of an
editable document of the same BasicJsonType, so a function written for one shortcut accepts few other views:
void print_names(json_view v); // accepts neither an ordered_json_view nor a json_editable_view
void print_names(json_editable_view v); // also accepts a json_view, but no ordered_json_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:
// 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(), operator[], and
at() 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. The other direction is safe: a
read-only document has no edits, so a view of it converts to an
editable view, which reads it like an editable document before its first edit. A template deduces the mode without
conversions, so the template forms above still accept only the modes they name. Views of both modes compare with
operator==.
is_json_view<T> 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>() on a view calls T's from_json() with the view itself if that
from_json() accepts views, and with materialize() otherwise. The
from_json() functions of the NLOHMANN_DEFINE_TYPE_*,
NLOHMANN_DEFINE_DERIVED_TYPE_*, and
NLOHMANN_JSON_SERIALIZE_ENUM 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:
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, 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.
Reading the view and #!cpp materialize().get<T>() give the same result, except for an object with a repeated key;
see Duplicate keys.
to_json() is unaffected: it writes basic_json values, never views.
See also
- Zero-copy JSON views - overview
is_json_view- type trait to detect viewsview_mode- read-only and editable views- Reading values - what
get<T>()converts without materializing
Version history
- Added in version 3.13.0.