deploy: 94fe31eb9b
This commit is contained in:
1 parent
41c601a7d1
commit
d2e264bd84
1400 files changed
+11859
-5440
No files matched your search
@@ -1,7 +1,7 @@
|
||||
<!doctype html><html lang=en class=no-js> <head><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=author content="Niels Lohmann"><link href="https://json.nlohmann.me/features/json_view/" rel="canonical"><link href=../types/template_parameters/ rel=prev><link href=../../integration/ rel=next><link rel=icon href=../../assets/images/favicon.png><meta name=generator content="mkdocs-1.6.1, mkdocs-material-9.7.7"><title>Zero-copy JSON views - JSON for Modern C++</title><link rel=stylesheet href=../../assets/stylesheets/main.ec1eaa64.min.css><link rel=stylesheet href=../../assets/stylesheets/palette.ab4e12ef.min.css><link rel="stylesheet" href="../../assets/external/fonts.googleapis.com/css.61a430c9.css"><style>:root{--md-text-font:"Roboto";--md-code-font:"JetBrains Mono"}</style><link rel=stylesheet href=../../css/custom.css><script>__md_scope=new URL("../..",location),__md_hash=e=>[...e].reduce(((e,_)=>(e<<5)-e+_.charCodeAt(0)),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script></head> <body dir=ltr data-md-color-scheme=default data-md-color-primary=indigo data-md-color-accent=indigo> <input class=md-toggle data-md-toggle=drawer type=checkbox id=__drawer autocomplete=off> <input class=md-toggle data-md-toggle=search type=checkbox id=__search autocomplete=off> <label class=md-overlay for=__drawer></label> <div data-md-component=skip> <a href=#zero-copy-json-views class=md-skip> Skip to content </a> </div> <div data-md-component=announce> </div> <header class=md-header data-md-component=header> <nav class="md-header__inner md-grid" aria-label=Header> <a href=../.. title="JSON for Modern C++" class="md-header__button md-logo" aria-label="JSON for Modern C++" data-md-component=logo> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M12 8a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3 3 3 0 0 0 3 3m0 3.54C9.64 9.35 6.5 8 3 8v11c3.5 0 6.64 1.35 9 3.54 2.36-2.19 5.5-3.54 9-3.54V8c-3.5 0-6.64 1.35-9 3.54"/></svg> </a> <label class="md-header__button md-icon" for=__drawer> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M3 6h18v2H3zm0 5h18v2H3zm0 5h18v2H3z"/></svg> </label> <div class=md-header__title data-md-component=header-title> <div class=md-header__ellipsis> <div class=md-header__topic> <span class=md-ellipsis> JSON for Modern C++ </span> </div> <div class=md-header__topic data-md-component=header-topic> <span class=md-ellipsis> Zero-copy JSON views </span> </div> </div> </div> <form class=md-header__option data-md-component=palette> <input class=md-option data-md-color-media="(prefers-color-scheme: light)" data-md-color-scheme=default data-md-color-primary=indigo data-md-color-accent=indigo aria-label="Switch to dark mode" type=radio name=__palette id=__palette_0> <label class="md-header__button md-icon" title="Switch to dark mode" for=__palette_1 hidden> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M12 8a4 4 0 0 0-4 4 4 4 0 0 0 4 4 4 4 0 0 0 4-4 4 4 0 0 0-4-4m0 10a6 6 0 0 1-6-6 6 6 0 0 1 6-6 6 6 0 0 1 6 6 6 6 0 0 1-6 6m8-9.31V4h-4.69L12 .69 8.69 4H4v4.69L.69 12 4 15.31V20h4.69L12 23.31 15.31 20H20v-4.69L23.31 12z"/></svg> </label> <input class=md-option data-md-color-media="(prefers-color-scheme: dark)" data-md-color-scheme=slate data-md-color-primary=indigo data-md-color-accent=indigo aria-label="Switch to light mode" type=radio name=__palette id=__palette_1> <label class="md-header__button md-icon" title="Switch to light mode" for=__palette_0 hidden> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M12 18c-.89 0-1.74-.2-2.5-.55C11.56 16.5 13 14.42 13 12s-1.44-4.5-3.5-5.45C10.26 6.2 11.11 6 12 6a6 6 0 0 1 6 6 6 6 0 0 1-6 6m8-9.31V4h-4.69L12 .69 8.69 4H4v4.69L.69 12 4 15.31V20h4.69L12 23.31 15.31 20H20v-4.69L23.31 12z"/></svg> </label> </form> <script>var palette=__md_get("__palette");if(palette&&palette.color){if("(prefers-color-scheme)"===palette.color.media){var media=matchMedia("(prefers-color-scheme: light)"),input=document.querySelector(media.matches?"[data-md-color-media='(prefers-color-scheme: light)']":"[data-md-color-media='(prefers-color-scheme: dark)']");palette.color.media=input.getAttribute("data-md-color-media"),palette.color.scheme=input.getAttribute("data-md-color-scheme"),palette.color.primary=input.getAttribute("data-md-color-primary"),palette.color.accent=input.getAttribute("data-md-color-accent")}for(var[key,value]of Object.entries(palette.color))document.body.setAttribute("data-md-color-"+key,value)}</script> <label class="md-header__button md-icon" for=__search> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 Line truncated
|
||||
<!doctype html><html lang=en class=no-js> <head><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=author content="Niels Lohmann"><link href="https://json.nlohmann.me/features/json_view/" rel="canonical"><link href=../types/template_parameters/ rel=prev><link href=../../integration/ rel=next><link rel=icon href=../../assets/images/favicon.png><meta name=generator content="mkdocs-1.6.1, mkdocs-material-9.7.7"><title>Zero-copy JSON views - JSON for Modern C++</title><link rel=stylesheet href=../../assets/stylesheets/main.ec1eaa64.min.css><link rel=stylesheet href=../../assets/stylesheets/palette.ab4e12ef.min.css><link rel="stylesheet" href="../../assets/external/fonts.googleapis.com/css.61a430c9.css"><style>:root{--md-text-font:"Roboto";--md-code-font:"JetBrains Mono"}</style><link rel=stylesheet href=../../css/custom.css><script>__md_scope=new URL("../..",location),__md_hash=e=>[...e].reduce(((e,_)=>(e<<5)-e+_.charCodeAt(0)),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script></head> <body dir=ltr data-md-color-scheme=default data-md-color-primary=indigo data-md-color-accent=indigo> <input class=md-toggle data-md-toggle=drawer type=checkbox id=__drawer autocomplete=off> <input class=md-toggle data-md-toggle=search type=checkbox id=__search autocomplete=off> <label class=md-overlay for=__drawer></label> <div data-md-component=skip> <a href=#zero-copy-json-views class=md-skip> Skip to content </a> </div> <div data-md-component=announce> </div> <header class=md-header data-md-component=header> <nav class="md-header__inner md-grid" aria-label=Header> <a href=../.. title="JSON for Modern C++" class="md-header__button md-logo" aria-label="JSON for Modern C++" data-md-component=logo> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M12 8a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3 3 3 0 0 0 3 3m0 3.54C9.64 9.35 6.5 8 3 8v11c3.5 0 6.64 1.35 9 3.54 2.36-2.19 5.5-3.54 9-3.54V8c-3.5 0-6.64 1.35-9 3.54"/></svg> </a> <label class="md-header__button md-icon" for=__drawer> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M3 6h18v2H3zm0 5h18v2H3zm0 5h18v2H3z"/></svg> </label> <div class=md-header__title data-md-component=header-title> <div class=md-header__ellipsis> <div class=md-header__topic> <span class=md-ellipsis> JSON for Modern C++ </span> </div> <div class=md-header__topic data-md-component=header-topic> <span class=md-ellipsis> Zero-copy JSON views </span> </div> </div> </div> <form class=md-header__option data-md-component=palette> <input class=md-option data-md-color-media="(prefers-color-scheme: light)" data-md-color-scheme=default data-md-color-primary=indigo data-md-color-accent=indigo aria-label="Switch to dark mode" type=radio name=__palette id=__palette_0> <label class="md-header__button md-icon" title="Switch to dark mode" for=__palette_1 hidden> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M12 8a4 4 0 0 0-4 4 4 4 0 0 0 4 4 4 4 0 0 0 4-4 4 4 0 0 0-4-4m0 10a6 6 0 0 1-6-6 6 6 0 0 1 6-6 6 6 0 0 1 6 6 6 6 0 0 1-6 6m8-9.31V4h-4.69L12 .69 8.69 4H4v4.69L.69 12 4 15.31V20h4.69L12 23.31 15.31 20H20v-4.69L23.31 12z"/></svg> </label> <input class=md-option data-md-color-media="(prefers-color-scheme: dark)" data-md-color-scheme=slate data-md-color-primary=indigo data-md-color-accent=indigo aria-label="Switch to light mode" type=radio name=__palette id=__palette_1> <label class="md-header__button md-icon" title="Switch to light mode" for=__palette_0 hidden> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M12 18c-.89 0-1.74-.2-2.5-.55C11.56 16.5 13 14.42 13 12s-1.44-4.5-3.5-5.45C10.26 6.2 11.11 6 12 6a6 6 0 0 1 6 6 6 6 0 0 1-6 6m8-9.31V4h-4.69L12 .69 8.69 4H4v4.69L.69 12 4 15.31V20h4.69L12 23.31 15.31 20H20v-4.69L23.31 12z"/></svg> </label> </form> <script>var palette=__md_get("__palette");if(palette&&palette.color){if("(prefers-color-scheme)"===palette.color.media){var media=matchMedia("(prefers-color-scheme: light)"),input=document.querySelector(media.matches?"[data-md-color-media='(prefers-color-scheme: light)']":"[data-md-color-media='(prefers-color-scheme: dark)']");palette.color.media=input.getAttribute("data-md-color-media"),palette.color.scheme=input.getAttribute("data-md-color-scheme"),palette.color.primary=input.getAttribute("data-md-color-primary"),palette.color.accent=input.getAttribute("data-md-color-accent")}for(var[key,value]of Object.entries(palette.color))document.body.setAttribute("data-md-color-"+key,value)}</script> <label class="md-header__button md-icon" for=__search> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 Line truncated
|
||||
<span class=cp>#include</span><span class=w> </span><span class=cpf><nlohmann/json_view.hpp></span>
|
||||
|
||||
<span class=k>using</span><span class=w> </span><span class=n>json_document</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>nlohmann</span><span class=o>::</span><span class=n>json_document</span><span class=p>;</span>
|
||||
<span class=k>using</span><span class=w> </span><span class=n>nlohmann</span><span class=o>::</span><span class=n>json_document</span><span class=p>;</span>
|
||||
|
||||
<span class=kt>int</span><span class=w> </span><span class=nf>main</span><span class=p>()</span>
|
||||
<span class=p>{</span>
|
||||
@@ -21,7 +21,7 @@
|
||||
<span class=cp>#include</span><span class=w> </span><span class=cpf><utility></span>
|
||||
<span class=cp>#include</span><span class=w> </span><span class=cpf><nlohmann/json_view.hpp></span>
|
||||
|
||||
<span class=k>using</span><span class=w> </span><span class=n>json_document</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>nlohmann</span><span class=o>::</span><span class=n>json_document</span><span class=p>;</span>
|
||||
<span class=k>using</span><span class=w> </span><span class=n>nlohmann</span><span class=o>::</span><span class=n>json_document</span><span class=p>;</span>
|
||||
|
||||
<span class=kt>int</span><span class=w> </span><span class=nf>main</span><span class=p>()</span>
|
||||
<span class=p>{</span>
|
||||
@@ -53,7 +53,7 @@
|
||||
<span class=kc>true</span>
|
||||
<span class=kc>true</span>
|
||||
<span class=kc>true</span>
|
||||
</code></pre></div> </details> <h2 id=what-is-the-same-as-parse>What is the same as <code>parse()</code><a class=headerlink href=#what-is-the-same-as-parse title="Permanent link">¶</a></h2> <ul> <li><strong>Accept/reject.</strong> <a href=../../api/basic_json_document/accept/ ><code>accept()</code></a> and <a href=../../api/basic_json_document/parse/ ><code>parse()</code></a> accept and reject exactly the same inputs as <a href=../../api/basic_json/accept/ ><code>basic_json::accept()</code></a>/<a href=../../api/basic_json/parse/ ><code>basic_json::parse()</code></a>, with the same <code>ignore_comments</code> and <code>ignore_trailing_commas</code> options.</li> <li><strong>Errors.</strong> A failing parse throws the same exception -- the same id, message, and position -- because on failure the library's own parser is run on the same bytes to produce the diagnostic. Valid input never pays for this, and the replay builds no values: it costs about a lexing pass up to the error. <code class=highlight><span class=n>allow_exceptions</span><span class=w> </span><span class=o>==</span><span class=w> </span><span class=nb>false</span></code> skips the replay and gives a <a href=../../api/basic_json_document/is_discarded/ >discarded</a> document instead of throwing, just as it gives a discarded value for <code class=highlight><span class=n>basic_json</span><span class=o>::</span><span class=n>parse</span><span class=p>()</span></code>.</li> <li><strong>Number classification.</strong> An integer literal that does not fit into the 64-bit integer type becomes a floating-point value, exactly as it does for <code class=highlight><span class=n>basic_json</span><span class=o>::</span><span class=n>parse</span><span class=p>()</span></code>.</li> <li><strong>Macros.</strong> <a href=../../api/macros/json_strict_nul_handling/ ><code>JSON_STRICT_NUL_HANDLING</code></a> and <a href=../../api/macros/json_noexception/ ><code>JSON_NOEXCEPTION</code></a>/<a href=../../api/macros/json_throw_user/ ><code>JSON_THROW_USER</code></a> behave the same way they do for <code><nlohmann/json.hpp></code>. These are the macros that change what the parser accepts or how it reports errors. The others either do not apply (<a href=../../api/macros/json_diagnostics/ ><code>JSON_DIAGNOSTICS</code></a> needs parent pointers in <code>basic_json</code> values) or only affect the values <code>materialize()</code> produces, through <code>BasicJsonType</code>.</li> </ul> <h2 id=what-is-different>What is different<a class=headerlink href=#what-is-different title="Permanent link">¶</a></h2> <ul> <li><strong>Only 64-bit integers.</strong> <code>basic_json_document<BasicJsonType></code> requires <code>BasicJsonType::number_integer_t</code> and <code>number_unsigned_t</code> to both be 64 bits wide; this is a compile-time <code class=highlight><span class=k>static_assert</span></code>.</li> <li><strong>A 4 GiB input limit.</strong> An input of 4294967280 bytes (4 GiB minus 16 bytes) or more throws <a href=../../home/exceptions/#jsonexceptionout_of_range416><code>out_of_range.416</code></a>, a limit <code class=highlight><span class=n>basic_json</span><span class=o>::</span><span class=n>parse</span><span class=p>()</span></code> does not have. It keeps an index entry at 16 bytes: offsets and counts are 32 bits wide. The limit is 16 bytes below 2^32, because the parser reads in 16-byte steps, and a position one step past the end must still fit.</li> <li><strong>A stream is always read to its end.</strong> There is no partial/streaming read of an <code class=highlight><span class=n>std</span><span class=o>::</span><span class=n>istream</span></code>: the stream is read to its end into a buffer the document owns, and parsing starts after that.</li> <li><strong>No source positions on <code>materialize()</code>.</strong> Even with <a href=../../api/macros/json_diagnostic_positions/ ><code>JSON_DIAGNOSTIC_POSITIONS</code></a> enabled, <a href=../../api/basic_json_view/materialize/ ><code>materialize()</code></a> does not set them. The index has the start offset of every value, but not the end of arrays, objects, and escaped strings, which the positions also need.</li> <li><strong>Objects iterate in document order.</strong> <a href=../../api/basic_json_view/begin/ ><code>begin()</code></a>/ <a href=../../api/basic_json_view/end/ ><code>end()</code></a> and <a href=../../api/basic_json_view/items/ ><code>items()</code></a> visit an object's members in the order they appear in the source text. <code>basic_json</code>'s default <code>object_t</code> is a <code>std::map</code>, which sorts by key, so iterating a <a href=../../api/basic_json_view/materialize/ ><code>materialize()</code></a>d value can print members in a different order than iterating the view they came from.</li> <li><strong>Chained access is safe.</strong> <a href=../../api/basic_json_view/operator%5B%5D/ ><code>operator[]</code></a> with a missing key, an index out of range, or aLine truncated
|
||||
</code></pre></div> </details> <h2 id=what-is-the-same-as-parse>What is the same as <code>parse()</code><a class=headerlink href=#what-is-the-same-as-parse title="Permanent link">¶</a></h2> <ul> <li><strong>Accept/reject.</strong> <a href=../../api/basic_json_document/accept/ ><code>accept()</code></a> and <a href=../../api/basic_json_document/parse/ ><code>parse()</code></a> accept and reject exactly the same inputs as <a href=../../api/basic_json/accept/ ><code>basic_json::accept()</code></a>/<a href=../../api/basic_json/parse/ ><code>basic_json::parse()</code></a>, with the same <code>ignore_comments</code> and <code>ignore_trailing_commas</code> options.</li> <li><strong>Errors.</strong> A failing parse throws the same exception -- the same id, message, and position -- because on failure the library's own parser is run on the same bytes to produce the diagnostic. Valid input never pays for this, and the replay builds no values: it costs about a lexing pass up to the error. <code class=highlight><span class=n>allow_exceptions</span><span class=w> </span><span class=o>==</span><span class=w> </span><span class=nb>false</span></code> skips the replay and gives a <a href=../../api/basic_json_document/is_discarded/ >discarded</a> document instead of throwing, just as it gives a discarded value for <code class=highlight><span class=n>basic_json</span><span class=o>::</span><span class=n>parse</span><span class=p>()</span></code>.</li> <li><strong>Number classification.</strong> An integer literal that does not fit into the 64-bit integer type becomes a floating-point value, exactly as it does for <code class=highlight><span class=n>basic_json</span><span class=o>::</span><span class=n>parse</span><span class=p>()</span></code>.</li> <li><strong>Macros.</strong> <a href=../../api/macros/json_strict_nul_handling/ ><code>JSON_STRICT_NUL_HANDLING</code></a> and <a href=../../api/macros/json_noexception/ ><code>JSON_NOEXCEPTION</code></a>/<a href=../../api/macros/json_throw_user/ ><code>JSON_THROW_USER</code></a> behave the same way they do for <code><nlohmann/json.hpp></code>. These are the macros that change what the parser accepts or how it reports errors. The others either do not apply (<a href=../../api/macros/json_diagnostics/ ><code>JSON_DIAGNOSTICS</code></a> needs parent pointers in <code>basic_json</code> values) or only affect the values <code>materialize()</code> produces, through <code>BasicJsonType</code>.</li> </ul> <h2 id=what-is-different>What is different<a class=headerlink href=#what-is-different title="Permanent link">¶</a></h2> <ul> <li><strong>Only 64-bit integers.</strong> <code>basic_json_document<BasicJsonType></code> requires <code>BasicJsonType::number_integer_t</code> and <code>number_unsigned_t</code> to both be 64 bits wide; this is a compile-time <code class=highlight><span class=k>static_assert</span></code>.</li> <li><strong>A 4 <abbr title="Gibibyte (2^30 bytes)">GiB</abbr> input limit.</strong> An input of 4294967280 bytes (4 <abbr title="Gibibyte (2^30 bytes)">GiB</abbr> minus 16 bytes) or more throws <a href=../../home/exceptions/#jsonexceptionout_of_range416><code>out_of_range.416</code></a>, a limit <code class=highlight><span class=n>basic_json</span><span class=o>::</span><span class=n>parse</span><span class=p>()</span></code> does not have. It keeps an index entry at 16 bytes: offsets and counts are 32 bits wide. The limit is 16 bytes below 2^32, because the parser reads in 16-byte steps, and a position one step past the end must still fit.</li> <li><strong>A stream is always read to its end.</strong> There is no partial/streaming read of an <code class=highlight><span class=n>std</span><span class=o>::</span><span class=n>istream</span></code>: the stream is read to its end into a buffer the document owns, and parsing starts after that.</li> <li><strong>No source positions on <code>materialize()</code>.</strong> Even with <a href=../../api/macros/json_diagnostic_positions/ ><code>JSON_DIAGNOSTIC_POSITIONS</code></a> enabled, <a href=../../api/basic_json_view/materialize/ ><code>materialize()</code></a> does not set them. The index has the start offset of every value, but not the end of arrays, objects, and escaped strings, which the positions also need.</li> <li><strong>Objects iterate in document order.</strong> <a href=../../api/basic_json_view/begin/ ><code>begin()</code></a>/ <a href=../../api/basic_json_view/end/ ><code>end()</code></a> and <a href=../../api/basic_json_view/items/ ><code>items()</code></a> visit an object's members in the order they appear in the source text. <code>basic_json</code>'s default <code>object_t</code> is a <code>std::map</code>, which sorts by key, so iterating a <a href=../../api/basic_json_view/materialize/ ><code>materialize()</code></a>d value can print members in a different order than iterating the view they came from.</li> <li><strong>Chained access is safe.</strong> <a href=../../api/basic_json_view/operatLine truncated
|
||||
<span class=n>json_view</span><span class=w> </span><span class=n>last</span><span class=p>;</span>
|
||||
<span class=k>for</span><span class=w> </span><span class=p>(</span><span class=k>const</span><span class=w> </span><span class=k>auto</span><span class=w> </span><span class=n>item</span><span class=w> </span><span class=o>:</span><span class=w> </span><span class=n>view</span><span class=p>.</span><span class=n>items</span><span class=p>())</span>
|
||||
<span class=p>{</span>
|
||||
@@ -62,12 +62,32 @@
|
||||
<span class=w> </span><span class=n>last</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>item</span><span class=p>.</span><span class=n>value</span><span class=p>();</span>
|
||||
<span class=w> </span><span class=p>}</span>
|
||||
<span class=p>}</span>
|
||||
</code></pre></div> <p>If you cannot trust the source text to have unique keys, check <a href=../../api/basic_json_view/size/ ><code>size()</code></a> against the number of distinct keys, or reject duplicates when iterating.</p> <h2 id=getting-values-out-without-copying>Getting values out without copying<a class=headerlink href=#getting-values-out-without-copying title="Permanent link">¶</a></h2> <p><a href=../../api/basic_json_view/get/ ><code>get<T>()</code></a> converts many <code>T</code> directly from the flat index, without ever building a <code>basic_json</code> value for the conversion: <code class=highlight><span class=kt>bool</span></code>, arithmetic types, <code class=highlight><span class=n>std</span><span class=o>::</span><span class=n>nullptr_t</span></code>, <code class=highlight><span class=n>std</span><span class=o>::</span><span class=n>string</span></code>/other <code class=highlight><span class=n>std</span><span class=o>::</span><span class=n>basic_string</span></code>s (copied once), <code>basic_json</code>/<code>ordered_json</code> (via <a href=../../api/basic_json_view/materialize/ ><code>materialize()</code></a>), <code>basic_json_view</code> itself, <code class=highlight><span class=n>std</span><span class=o>::</span><span class=n>vector</span><span class=o><</span><span class=n>U</span><span class=o>></span></code>, and <code class=highlight><span class=n>std</span><span class=o>::</span><span class=n>map</span></code>/<code class=highlight><span class=n>std</span><span class=o>::</span><span class=n>unordered_map</span></code> with string-like keys. Every other type -- <code class=highlight><span class=n>std</span><span class=o>::</span><span class=n>list</span></code>, <code class=highlight><span class=n>std</span><span class=o>::</span><span class=n>pair</span></code>, <code class=highlight><span class=n>std</span><span class=o>::</span><span class=n>array</span></code>, enumerations, user types with a <code>from_json()</code> -- goes through <a href=../../api/basic_json_view/materialize/ ><code>materialize()</code></a><code>.get<T>()</code> instead: the subtree is built into a real <code>basic_json</code> value first, exactly as <a href=../../api/basic_json/parse/ ><code>parse()</code></a> would, and converted from there.</p> <p>Two conversions never copy at all:</p> <ul> <li><a href=../../api/basic_json_view/get_string/ ><code>get_string()</code></a> (equivalently, <code class=highlight><span class=n>get</span><span class=o><</span><span class=n>string_view_t</span><span class=o>></span><span class=p>()</span></code>) returns a string as a <code>string_view_t</code> pointing into the document's <a href=../../api/basic_json_document/source/ ><code>source()</code></a> text -- or, for a string that contains escape sequences, into the document's own buffer of decoded strings -- instead of allocating a new <code class=highlight><span class=n>std</span><span class=o>::</span><span class=n>string</span></code>.</li> <li><a href=../../api/basic_json_view/number_token/ ><code>number_token()</code></a> returns a number exactly as it was written in the source, e.g. <code class=highlight><span class=s>"1.50"</span></code>, <code class=highlight><span class=s>"1E2"</span></code>, or an integer with more digits than any number type holds, instead of rounding it into a <code class=highlight><span class=kt>double</span></code>/<code class=highlight><span class=kt>int64_t</span></code> the way <code class=highlight><span class=n>get</span><span class=o><</span><span class=n>T</span><span class=o>></span><span class=p>()</span></code> (and <a href=../../api/basic_json/parse/ ><code>basic_json::parse()</code></a>) would.</li> </ul> <p>Both results are only valid as long as the view -- and, for a string with no escapes, the borrowed source text -- is.</p> <h2 id=writing-a-view-back>Writing a view back<a class=headerlink href=#writing-a-view-back title="Permanent link">¶</a></h2> <p><a href=../../api/basic_json_view/dump/ ><code>dump()</code></a> serializes a view directly from the flat index, without ever building a <code>basic_json</code> value. An object's members are written in document order, not sorted by key, and <em>every</em> occurrence of a repeated key is written, not only the last one -- the same two ways <a href=#what-is-different>iteration</a> already differs from a <a href=../../api/basic_json_view/materialize/ ><code>materialize()</code></a>d value, see <a href=#duplicate-keys>Duplicate keys</a>. <code class=highlight><span class=n>materialize</span><span class=p>().</span><span class=n>dump</span><span class=p>()</span></code> gives a different result in both respects for a <code>json_view</code>.</p> <p>By default, numbers are written the way <a href=../../api/basic_json/dump/ ><code>basic_json::dump()</code></a> would. <a href=../../api/basic_json_view/number_format/ ><code>number_format::source</code></a> instead copies every number exaLine truncated
|
||||
</code></pre></div> <p>If you cannot trust the source text to have unique keys, check <a href=../../api/basic_json_view/size/ ><code>size()</code></a> against the number of distinct keys, or reject duplicates when iterating.</p> <h2 id=getting-values-out-without-copying>Getting values out without copying<a class=headerlink href=#getting-values-out-without-copying title="Permanent link">¶</a></h2> <p><a href=../../api/basic_json_view/get/ ><code>get<T>()</code></a> converts most <code>T</code> directly from the flat index, without ever building a <code>basic_json</code> value for the conversion: <code class=highlight><span class=kt>bool</span></code>, arithmetic types, <code class=highlight><span class=n>std</span><span class=o>::</span><span class=n>nullptr_t</span></code>, <code class=highlight><span class=n>std</span><span class=o>::</span><span class=n>string</span></code>/other <code class=highlight><span class=n>std</span><span class=o>::</span><span class=n>basic_string</span></code>s (copied once), <code>basic_json_view</code> itself, the standard containers and other types the library converts (<code class=highlight><span class=n>std</span><span class=o>::</span><span class=n>vector</span></code>, <code class=highlight><span class=n>std</span><span class=o>::</span><span class=n>map</span></code>, <code class=highlight><span class=n>std</span><span class=o>::</span><span class=n>list</span></code>, <code class=highlight><span class=n>std</span><span class=o>::</span><span class=n>array</span></code>, <code class=highlight><span class=n>std</span><span class=o>::</span><span class=n>pair</span></code>, <code class=highlight><span class=n>std</span><span class=o>::</span><span class=n>tuple</span></code>, <code class=highlight><span class=n>std</span><span class=o>::</span><span class=n>optional</span></code>, ...), and the types of the <code>NLOHMANN_DEFINE_TYPE_*</code> and <code>NLOHMANN_JSON_SERIALIZE_ENUM</code> macros. Types whose <code>from_json()</code> is written for <code>basic_json</code> only go through <a href=../../api/basic_json_view/materialize/ ><code>materialize()</code></a><code>.get<T>()</code> instead: the subtree is built into a real <code>basic_json</code> value first, exactly as <a href=../../api/basic_json/parse/ ><code>parse()</code></a> would, and converted from there. See <a href=#writing-generic-code>Writing generic code</a> for how to write a <code>from_json()</code> that reads views.</p> <p>Two conversions never copy at all:</p> <ul> <li><a href=../../api/basic_json_view/get_string/ ><code>get_string()</code></a> (equivalently, <code class=highlight><span class=n>get</span><span class=o><</span><span class=n>string_view_t</span><span class=o>></span><span class=p>()</span></code>) returns a string as a <code>string_view_t</code> pointing into the document's <a href=../../api/basic_json_document/source/ ><code>source()</code></a> text -- or, for a string that contains escape sequences, into the document's own buffer of decoded strings -- instead of allocating a new <code class=highlight><span class=n>std</span><span class=o>::</span><span class=n>string</span></code>.</li> <li><a href=../../api/basic_json_view/number_token/ ><code>number_token()</code></a> returns a number exactly as it was written in the source, e.g. <code class=highlight><span class=s>"1.50"</span></code>, <code class=highlight><span class=s>"1E2"</span></code>, or an integer with more digits than any number type holds, instead of rounding it into a <code class=highlight><span class=kt>double</span></code>/<code class=highlight><span class=kt>int64_t</span></code> the way <code class=highlight><span class=n>get</span><span class=o><</span><span class=n>T</span><span class=o>></span><span class=p>()</span></code> (and <a href=../../api/basic_json/parse/ ><code>basic_json::parse()</code></a>) would.</li> </ul> <p>Both results are only valid as long as the view -- and, for a string with no escapes, the borrowed source text -- is.</p> <h2 id=writing-generic-code>Writing generic code<a class=headerlink href=#writing-generic-code title="Permanent link">¶</a></h2> <p>A view's type names its <code>BasicJsonType</code> and its <a href=../../api/view_mode/ ><code>view_mode</code></a>: <a href=../../api/json_view/ ><code>json_view</code></a> is <code class=highlight><span class=n>basic_json_view</span><span class=o><</span><span class=n>json</span><span class=p>,</span><span class=w> </span><span class=n>view_mode</span><span class=o>::</span><span class=n>read_only</span><span class=o>></span></code>, and <a href=../../api/json_editable_view/ ><code>json_editable_view</code></a> is <code class=highlight><span class=n>basic_json_view</span><span class=o><</span><span class=n>json</span><span class=p>,</span><span class=w> </span><span class=n>view_mode</span><span class=o>::</span><span class=n>editable</span><span class=o>></span></code>. These are different types. TLine truncated
|
||||
<span class=kt>void</span><span class=w> </span><span class=nf>print_names</span><span class=p>(</span><span class=n>json_editable_view</span><span class=w> </span><span class=n>v</span><span class=p>);</span><span class=w> </span><span class=c1>// also accepts a json_view, but no ordered_json_view</span>
|
||||
</code></pre></div> <p>This is the same pitfall as a <code>to_json</code>/<code>from_json</code> written for <code>json</code> instead of any <code>BasicJsonType</code>, which then does not work for <code>ordered_json</code>. The shortcuts are for declaring documents and views; a function that takes a view names the views it accepts with a template:</p> <div class=highlight><pre><span></span><code><span class=c1>// views of editable documents only</span>
|
||||
<span class=k>template</span><span class=o><</span><span class=k>typename</span><span class=w> </span><span class=nc>BasicJsonType</span><span class=o>></span>
|
||||
<span class=kt>void</span><span class=w> </span><span class=n>f</span><span class=p>(</span><span class=n>basic_json_view</span><span class=o><</span><span class=n>BasicJsonType</span><span class=p>,</span><span class=w> </span><span class=n>view_mode</span><span class=o>::</span><span class=n>editable</span><span class=o>></span><span class=w> </span><span class=n>v</span><span class=p>);</span>
|
||||
|
||||
<span class=c1>// views of read-only documents only</span>
|
||||
<span class=k>template</span><span class=o><</span><span class=k>typename</span><span class=w> </span><span class=nc>BasicJsonType</span><span class=o>></span>
|
||||
<span class=kt>void</span><span class=w> </span><span class=n>f</span><span class=p>(</span><span class=n>basic_json_view</span><span class=o><</span><span class=n>BasicJsonType</span><span class=p>,</span><span class=w> </span><span class=n>view_mode</span><span class=o>::</span><span class=n>read_only</span><span class=o>></span><span class=w> </span><span class=n>v</span><span class=p>);</span>
|
||||
|
||||
<span class=c1>// views of either document type</span>
|
||||
<span class=k>template</span><span class=o><</span><span class=k>typename</span><span class=w> </span><span class=nc>BasicJsonType</span><span class=p>,</span><span class=w> </span><span class=n>view_mode</span><span class=w> </span><span class=n>Mode</span><span class=o>></span>
|
||||
<span class=kt>void</span><span class=w> </span><span class=n>f</span><span class=p>(</span><span class=n>basic_json_view</span><span class=o><</span><span class=n>BasicJsonType</span><span class=p>,</span><span class=w> </span><span class=n>Mode</span><span class=o>></span><span class=w> </span><span class=n>v</span><span class=p>);</span>
|
||||
</code></pre></div> <p>Views are passed by value: they are two pointers, cheap to copy, like a <code class=highlight><span class=n>std</span><span class=o>::</span><span class=n>string_view</span></code>. A <code>const&</code> works as well, but a non-<code>const</code> reference does not bind to the views that <a href=../../api/basic_json_document/root/ ><code>root()</code></a>, <a href=../../api/basic_json_view/operator%5B%5D/ ><code>operator[]</code></a>, and <a href=../../api/basic_json_view/at/ ><code>at()</code></a> return, so <code class=highlight><span class=n>f</span><span class=p>(</span><span class=n>doc</span><span class=p>.</span><span class=n>root</span><span class=p>())</span></code> would not compile.</p> <p>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 <a href=../../api/basic_json_view/basic_json_view/ >converts</a> 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 <a href=../../api/basic_json_view/operator_eq/ ><code>operator==</code></a>.</p> <p><a href=../../api/is_json_view/ ><code>is_json_view<T></code></a> tells views from other types, for constraints that cannot be written as a <code>basic_json_view<...></code> parameter.</p> <h3 id=a-from_json-that-reads-views>A <code>from_json()</code> that reads views<a class=headerlink href=#a-from_json-that-reads-views title="Permanent link">¶</a></h3> <p><a href=../../api/basic_json_view/get/ ><code>get<T>()</code></a> on a view calls <code>T</code>'s <code>from_json()</code> with the view itself if that <code>from_json()</code> accepts views, and with <a href=../../api/basic_json_view/materialize/ ><code>materialize()</code></a> otherwise. The <code>from_json()</code> functions of the <a href=../../api/macros/nlohmann_define_type_intrusive/ ><code>NLOHMANN_DEFINE_TYPE_*</code></a>, <a href=../../api/macros/nlohmann_define_derived_type/ ><code>NLOHMANN_DEFINE_DERIVED_TYPE_*</code></a>, and <a href=../../api/macros/nlohmann_json_serialize_enum/ ><code>NLOHMANN_JSON_SERIALIZE_ENUM</code></a> 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 <code class=highlight><span class=n>materialize</span><span class=p>().</span><span class=n>get</span><span class=o><</span><span class=n>T</span><span class=o>></span><span class=p>()</span></code>.</p> <p>A hand-written <code>from_json()</code> reads views if it is constrained to <code>json</code> values and views:</p> <div class=highlight><pre><span></span><code><span class=k>template</span><span class=w> </span><span class=o><</span><span class=w> </span><span class=k>typename</span><span class=w> </span><span class=nc>J</span><span class=p>,</span><span class=w> </span><span class=k>typename</span><span class=w> </span><span class=nc>std</span><span class=o>::</span><span class=n>enable_if</span><span class=w> </span><span class=o><</span>
|
||||
<span class=w> </span><span class=n>nlohmann</span><span class=o>::</span><span class=n>is_json_view</span><span class=o><</span><span class=n>J</span><span class=o>>::</span><span class=n>value</span><span class=w> </span><span class=o>||</span><span class=w> </span><span class=n>std</span><span class=o>::</span><span class=n>is_same</span><span class=o><</span><span class=n>J</span><span class=p>,</span><span class=w> </span><span class=n>nlohmann</span><span class=o>::</span><span class=n>json</span><span class=o>>::</span><span class=n>value</span><span class=p>,</span><span class=w> </span><span class=kt>int</span><span class=w> </span><span class=o>>::</span><span class=n>type</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=mi>0</span><span class=w> </span><span class=o>></span>
|
||||
<span class=kt>void</span><span class=w> </span><span class=n>from_json</span><span class=p>(</span><span class=k>const</span><span class=w> </span><span class=n>J</span><span class=o>&</span><span class=w> </span><span class=n>j</span><span class=p>,</span><span class=w> </span><span class=n>person</span><span class=o>&</span><span class=w> </span><span class=n>p</span><span class=p>)</span>
|
||||
<span class=p>{</span>
|
||||
<span class=w> </span><span class=n>p</span><span class=p>.</span><span class=n>name</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>j</span><span class=p>.</span><span class=n>at</span><span class=p>(</span><span class=s>"name"</span><span class=p>).</span><span class=k>template</span><span class=w> </span><span class=n>get</span><span class=o><</span><span class=n>std</span><span class=o>::</span><span class=n>string</span><span class=o>></span><span class=p>();</span>
|
||||
<span class=w> </span><span class=n>p</span><span class=p>.</span><span class=n>age</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>j</span><span class=p>.</span><span class=n>at</span><span class=p>(</span><span class=s>"age"</span><span class=p>).</span><span class=k>template</span><span class=w> </span><span class=n>get</span><span class=o><</span><span class=kt>int</span><span class=o>></span><span class=p>();</span>
|
||||
<span class=p>}</span>
|
||||
</code></pre></div> <p>Its body may only use what views and <code>basic_json</code> have in common: the type checks, <code>at()</code>, <code>operator[]</code>, <code>contains()</code>, <code>value()</code>, <code>size()</code>, iteration and <code>items()</code>, and <code>get<T>()</code>/<code>get_to()</code>. An unconstrained <code class=highlight><span class=k>template</span><span class=o><</span><span class=k>typename</span><span class=w> </span><span class=nc>BasicJsonType</span><span class=o>></span><span class=w> </span><span class=kt>void</span><span class=w> </span><span class=n>from_json</span><span class=p>(</span><span class=k>const</span><span class=w> </span><span class=n>BasicJsonType</span><span class=o>&</span><span class=w> </span><span class=n>j</span><span class=p>,</span><span class=w> </span><span class=n>person</span><span class=o>&</span><span class=w> </span><span class=n>p</span><span class=p>)</span></code>, as in <a href=../arbitrary_types/ >arbitrary type conversions</a>, is never called with a view, as it might use <code>basic_json</code> functions a view does not have; such a type is converted through <code>materialize()</code>. A <code>from_json()</code> for <code>json</code> only is converted through <code>materialize()</code> as well.</p> <p>Two things differ when a <code>from_json()</code> reads the view:</p> <ul> <li><strong>Duplicate keys.</strong> Members looked up by name (<code>at()</code>, <code>value()</code>, ... and thus the macros) find the <strong>first</strong> member with a repeated key, see <a href=#duplicate-keys>Duplicate keys</a>; <code class=highlight><span class=n>materialize</span><span class=p>().</span><span class=n>get</span><span class=o><</span><span class=n>T</span><span class=o>></span><span class=p>()</span></code> would see the last one. Containers built from an object, such as <code class=highlight><span class=n>std</span><span class=o>::</span><span class=n>map</span></code>, keep the <strong>last</strong> value either way, as <a href=../../api/basic_json/parse/ ><code>parse()</code></a> does.</li> <li><strong><a href=../../api/macros/json_diagnostics/ ><code>JSON_DIAGNOSTICS</code></a>.</strong> Exceptions thrown by the view carry no path to the value.</li> </ul> <p><code>to_json()</code> is unaffected: it writes <code>basic_json</code> values, never views.</p> <h2 id=writing-a-view-back>Writing a view back<a class=headerlink href=#writing-a-view-back title="Permanent link">¶</a></h2> <p><a href=../../api/basic_json_view/dump/ ><code>dump()</code></a> serializes a view directly from the flat index, without ever building a <code>basic_json</code> value. An object's members are written in document order, not sorted by key, and <em>every</em> occurrence of a repeated key is written, not only the last one -- the same two ways <a href=#what-is-different>iteration</a> already differs from a <a href=../../api/basic_json_view/materialize/ ><code>materialize()</code></a>d value, see <a href=#duplicate-keys>Duplicate keys</a>. <code class=highlight><span class=n>materialize</span><span class=p>().</span><span class=n>dump</span><span class=p>()</span></code> gives a different result in both respects for a <code>json_view</code>.</p> <p>By default, numbers are written the way <a href=../../api/basic_json/dump/ ><code>basic_json::dump()</code></a> would. <a href=../../api/basic_json_view/number_format/ ><code>number_format::source</code></a> instead copies every number exactly as it was written in the source text -- a price like <code class=highlight><span class=mf>19.90</span></code>, a long order or account ID with more digits than any number type holds, or a high-precision coordinate -- something <code>basic_json</code> cannot do at all, since parsing already reduces a number to its parsed <code class=highlight><span class=kt>double</span></code>/<code class=highlight><span class=kt>int64_t</span></code> value.</p> <p><a href=../../api/basic_json_view/operator_ltlt/ ><code>operator<<</code></a> writes a view to a stream the way <code>basic_json</code>'s does, using the stream's <code>width</code>/<code>fill</code> for indentation.</p> <h2 id=editing-a-document>Editing a document<a class=headerlink href=#editing-a-document title="Permanent link">¶</a></h2> <p>Everything above is read-only: a <code>json_document</code>/<code>json_view</code> lets you look at a parsed text without copying it, but not change it. <a href=../../api/basic_json_document/ ><code>basic_json_document<BasicJsonType, view_mode::editable></code></a> -- more conveniently spelled <a href=../../api/json_editable_document/ ><code>json_editable_document</code></a> or <a href=../../api/ordered_json_editable_document/ ><code>ordered_json_editable_document</code></a> -- also lets you <a href=../../api/basic_json_document/set/ ><code>set</code></a> a value, <a href=../../api/basic_json_document/push_back/ ><code>push_back</code></a> onto orLine truncated
|
||||
<span class=cp>#include</span><span class=w> </span><span class=cpf><nlohmann/json_view.hpp></span>
|
||||
|
||||
<span class=k>using</span><span class=w> </span><span class=n>json</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>nlohmann</span><span class=o>::</span><span class=n>json</span><span class=p>;</span>
|
||||
<span class=k>using</span><span class=w> </span><span class=n>json_editable_document</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>nlohmann</span><span class=o>::</span><span class=n>json_editable_document</span><span class=p>;</span>
|
||||
<span class=k>using</span><span class=w> </span><span class=n>json_editable_view</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>nlohmann</span><span class=o>::</span><span class=n>json_editable_view</span><span class=p>;</span>
|
||||
<span class=k>using</span><span class=w> </span><span class=n>nlohmann</span><span class=o>::</span><span class=n>json</span><span class=p>;</span>
|
||||
<span class=k>using</span><span class=w> </span><span class=n>nlohmann</span><span class=o>::</span><span class=n>json_editable_document</span><span class=p>;</span>
|
||||
<span class=k>using</span><span class=w> </span><span class=n>nlohmann</span><span class=o>::</span><span class=n>json_editable_view</span><span class=p>;</span>
|
||||
|
||||
<span class=kt>int</span><span class=w> </span><span class=nf>main</span><span class=p>()</span>
|
||||
<span class=p>{</span>
|
||||
@@ -102,7 +122,7 @@
|
||||
<span class=cp>#include</span><span class=w> </span><span class=cpf><vector></span>
|
||||
<span class=cp>#include</span><span class=w> </span><span class=cpf><nlohmann/json_view.hpp></span>
|
||||
|
||||
<span class=k>using</span><span class=w> </span><span class=n>json_document</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>nlohmann</span><span class=o>::</span><span class=n>json_document</span><span class=p>;</span>
|
||||
<span class=k>using</span><span class=w> </span><span class=n>nlohmann</span><span class=o>::</span><span class=n>json_document</span><span class=p>;</span>
|
||||
|
||||
<span class=kt>int</span><span class=w> </span><span class=nf>main</span><span class=p>()</span>
|
||||
<span class=p>{</span>
|
||||
@@ -129,4 +149,4 @@
|
||||
</code></pre></div> <p>Output:</p> <div class=highlight><pre><span></span><code><span class=mi>316</span>
|
||||
<span class=kc>true</span>
|
||||
<span class=kc>true</span>
|
||||
</code></pre></div> </details> <div class="admonition warning"> <p class=admonition-title>Experimental</p> <p>The image format is versioned but not yet stable, and may change in an incompatible way before it is declared stable. It is little-endian only, and tied to the library build that wrote it -- use it to cache a document or to hand one to another process running the <em>same</em> build, not as a long-term storage format; keep the original <abbr title="JavaScript Object Notation">JSON</abbr> text if a saved document needs to be readable by a future library version.</p> </div> <p>The idea of a document you can read without parsing comes from zero-copy formats such as <a href="https://github.com/google/flatbuffers">FlatBuffers</a> and <a href="https://github.com/yandex/yaff">YaFF</a>; the check <a href=../../api/basic_json_document/load/ ><code>load()</code></a> runs follows the idea of FlatBuffers' Verifier. No code is taken from either.</p> <h2 id=choosing-between-json-ordered_json-the-sax-interface-and-json_view>Choosing between <code>json</code>, <code>ordered_json</code>, the <abbr title="Simple API for XML">SAX</abbr> interface, and <code>json_view</code><a class=headerlink href=#choosing-between-json-ordered_json-the-sax-interface-and-json_view title="Permanent link">¶</a></h2> <table> <thead> <tr> <th></th> <th><a href=../../api/json/ ><code>json</code></a> / <a href=../../api/ordered_json/ ><code>ordered_json</code></a></th> <th><a href=../parsing/sax_interface/ ><abbr title="Simple API for XML">SAX</abbr> interface</a></th> <th><a href=../../api/json_document/ ><code>json_document</code></a> / <a href=../../api/json_view/ ><code>json_view</code></a></th> <th><a href=../../api/json_editable_document/ ><code>json_editable_document</code></a> / <a href=../../api/json_editable_view/ ><code>json_editable_view</code></a></th> </tr> </thead> <tbody> <tr> <td><strong>Ownership</strong></td> <td>owns every value</td> <td>owns nothing; you decide what to keep, in your handler</td> <td>borrows or owns the <em>text</em>; the index is always owned by the document</td> <td>same as <code>json_document</code>; edits go to storage the document owns</td> </tr> <tr> <td><strong>Mutability</strong></td> <td>freely mutable</td> <td>not applicable (a one-shot event stream)</td> <td>read-only</td> <td><a href=../../api/basic_json_document/set/ ><code>set</code></a>/<a href=../../api/basic_json_document/push_back/ ><code>push_back</code></a>/<a href=../../api/basic_json_document/insert/ ><code>insert</code></a>/<a href=../../api/basic_json_document/erase/ ><code>erase</code></a> edit in place; the source text is never rewritten</td> </tr> <tr> <td><strong>What you get</strong></td> <td>a full tree you can read, write, and keep as long as you like</td> <td>a sequence of callbacks; whatever your handler builds from them</td> <td>a flat index plus, on demand, <a href=../../api/basic_json_view/materialize/ ><code>materialize()</code></a>d <code>json</code>/<code>ordered_json</code> values for the parts you actually use</td> <td>the same, plus <a href=../../api/basic_json_view/dump/ ><code>dump()</code></a> of an edited document that keeps the member order and, with <a href=../../api/basic_json_view/number_format/ ><code>number_format::source</code></a>, the spelling of every untouched number</td> </tr> <tr> <td><strong>Typical use</strong></td> <td>general-purpose <abbr title="JavaScript Object Notation">JSON</abbr> handling: config, request/response bodies you build or modify, anything you hold onto</td> <td>validating or projecting a text into your own data structure without ever holding the whole thing as <abbr title="JavaScript Object Notation">JSON</abbr></td> <td>large or high-volume input where you only need part of it, or need it repeatedly, and can keep the source text (or a copy) alive for as long as the document lives</td> <td>a document you read, patch a few fields of, and write back -- a configuration file, for instance -- where the rest of it should come back exactly as it was</td> </tr> <tr> <td><strong>Caching/reload</strong></td> <td>not applicable -- re-parse, or roll your own serialization</td> <td>not applicable</td> <td><a href=../../api/basic_json_document/save/ ><code>save()</code></a>/<a href=../../api/basic_json_document/load/ ><code>load()</code></a>: cache the parsed index as an image and reload it without parsing</td> <td>same, saving the document's current -- possibly edited -- state</td> </tr> </tbody> </table> <h2 id=version-history>Version history<a class=headerlink href=#version-history title="Permanent link">¶</a></h2> <ul> <li>Added in version 3.13.0 <span class=unreleased-version title="Not part of a release yet; the latest release is 3.12.0.">unreleased</span>.</li> </ul> <!-- https://squidfunk.github.io/mkdocs-material/reference/tooltips/#adding-a-glossary --> <aside class=md-source-file> <span class=md-source-file__fact> <span class=md-icon title="Last update"> <svg xmlns=hLine truncated
|
||||
</code></pre></div> </details> <div class="admonition warning"> <p class=admonition-title>Experimental</p> <p>The image format is versioned but not yet stable, and may change in an incompatible way before it is declared stable. It is little-endian only (on big-endian targets, <code>save()</code> and <code>load()</code> do not exist), and tied to the library build that wrote it -- use it to cache a document or to hand one to another process running the <em>same</em> build, not as a long-term storage format; keep the original <abbr title="JavaScript Object Notation">JSON</abbr> text if a saved document needs to be readable by a future library version.</p> </div> <p>The idea of a document you can read without parsing comes from zero-copy formats such as <a href="https://github.com/google/flatbuffers">FlatBuffers</a> and <a href="https://github.com/yandex/yaff">YaFF</a>; the check <a href=../../api/basic_json_document/load/ ><code>load()</code></a> runs follows the idea of FlatBuffers' Verifier. No code is taken from either.</p> <h2 id=choosing-between-json-ordered_json-the-sax-interface-and-json_view>Choosing between <code>json</code>, <code>ordered_json</code>, the <abbr title="Simple API for XML">SAX</abbr> interface, and <code>json_view</code><a class=headerlink href=#choosing-between-json-ordered_json-the-sax-interface-and-json_view title="Permanent link">¶</a></h2> <table> <thead> <tr> <th></th> <th><a href=../../api/json/ ><code>json</code></a> / <a href=../../api/ordered_json/ ><code>ordered_json</code></a></th> <th><a href=../parsing/sax_interface/ ><abbr title="Simple API for XML">SAX</abbr> interface</a></th> <th><a href=../../api/json_document/ ><code>json_document</code></a> / <a href=../../api/json_view/ ><code>json_view</code></a></th> <th><a href=../../api/json_editable_document/ ><code>json_editable_document</code></a> / <a href=../../api/json_editable_view/ ><code>json_editable_view</code></a></th> </tr> </thead> <tbody> <tr> <td><strong>Ownership</strong></td> <td>owns every value</td> <td>owns nothing; you decide what to keep, in your handler</td> <td>borrows or owns the <em>text</em>; the index is always owned by the document</td> <td>same as <code>json_document</code>; edits go to storage the document owns</td> </tr> <tr> <td><strong>Mutability</strong></td> <td>freely mutable</td> <td>not applicable (a one-shot event stream)</td> <td>read-only</td> <td><a href=../../api/basic_json_document/set/ ><code>set</code></a>/<a href=../../api/basic_json_document/push_back/ ><code>push_back</code></a>/<a href=../../api/basic_json_document/insert/ ><code>insert</code></a>/<a href=../../api/basic_json_document/erase/ ><code>erase</code></a> edit in place; the source text is never rewritten</td> </tr> <tr> <td><strong>What you get</strong></td> <td>a full tree you can read, write, and keep as long as you like</td> <td>a sequence of callbacks; whatever your handler builds from them</td> <td>a flat index plus, on demand, <a href=../../api/basic_json_view/materialize/ ><code>materialize()</code></a>d <code>json</code>/<code>ordered_json</code> values for the parts you actually use</td> <td>the same, plus <a href=../../api/basic_json_view/dump/ ><code>dump()</code></a> of an edited document that keeps the member order and, with <a href=../../api/basic_json_view/number_format/ ><code>number_format::source</code></a>, the spelling of every untouched number</td> </tr> <tr> <td><strong>Typical use</strong></td> <td>general-purpose <abbr title="JavaScript Object Notation">JSON</abbr> handling: config, request/response bodies you build or modify, anything you hold onto</td> <td>validating or projecting a text into your own data structure without ever holding the whole thing as <abbr title="JavaScript Object Notation">JSON</abbr></td> <td>large or high-volume input where you only need part of it, or need it repeatedly, and can keep the source text (or a copy) alive for as long as the document lives</td> <td>a document you read, patch a few fields of, and write back -- a configuration file, for instance -- where the rest of it should come back exactly as it was</td> </tr> <tr> <td><strong>Caching/reload</strong></td> <td>not applicable -- re-parse, or roll your own serialization</td> <td>not applicable</td> <td><a href=../../api/basic_json_document/save/ ><code>save()</code></a>/<a href=../../api/basic_json_document/load/ ><code>load()</code></a>: cache the parsed index as an image and reload it without parsing</td> <td>same, saving the document's current -- possibly edited -- state</td> </tr> </tbody> </table> <h2 id=version-history>Version history<a class=headerlink href=#version-history title="Permanent link">¶</a></h2> <ul> <li>Added in version 3.13.0 <span class=unreleased-version title="Not part of a release yet; the latest release is 3.12.0.">unreleased</span>.</li> </ul> <!-- https://squidfunk.github.io/mkdocs-material/reference/tooltips/#adding-a-glossary --> <aside class=md-source-file> <spanLine truncated
|
||||
+68
-10
@@ -22,7 +22,7 @@ Example: parse a document, inspect its root, and materialize it
|
||||
#include <iostream>
|
||||
#include <nlohmann/json_view.hpp>
|
||||
|
||||
using json_document = nlohmann::json_document;
|
||||
using nlohmann::json_document;
|
||||
|
||||
int main()
|
||||
{
|
||||
@@ -73,7 +73,7 @@ Example: borrowed and owned documents, and when views become invalid
|
||||
#include <utility>
|
||||
#include <nlohmann/json_view.hpp>
|
||||
|
||||
using json_document = nlohmann::json_document;
|
||||
using nlohmann::json_document;
|
||||
|
||||
int main()
|
||||
{
|
||||
@@ -141,6 +141,8 @@ If an object in the source text repeats a key, [`operator[]`](https://json.nlohm
|
||||
|
||||
**Why the first?** A lookup can stop as soon as it finds a match. Returning the last member would force every lookup to scan all members of the object, even when the key is found at the very first one: this made lookups in small objects 1.6 to 3.4 times slower. The hash index of the keys of objects with 128 members or more leads to the first member of a key as well. Other zero-copy parsers that index the source text, such as yyjson and simdjson, also return the first member. RFC 8259 only says that names within an object SHOULD be unique and that the behavior of a receiver that sees duplicates is unpredictable, so neither choice is wrong.
|
||||
|
||||
The same holds for [`get<T>()`](https://json.nlohmann.me/api/basic_json_view/get/index.md) of a type whose `from_json()` reads the view, such as the types of the `NLOHMANN_DEFINE_TYPE_*` macros: their members are looked up, so `get<point>()` of `{"x":1,"x":2}` reads `x == 1`, while `materialize().get<point>()` reads `2`.
|
||||
|
||||
**What stays the same as `parse()`?** [`materialize()`](https://json.nlohmann.me/api/basic_json_view/materialize/index.md) and [`get<std::map<...>>()`](https://json.nlohmann.me/api/basic_json_view/get/index.md) replay every member in order, so they keep the *last* value exactly like `basic_json::parse()` (at the position of the first occurrence of the key, for an [`ordered_json`](https://json.nlohmann.me/api/ordered_json/index.md)).
|
||||
|
||||
**How do I get the value `parse()` would give?** Either call `view.materialize()` and look the key up in the result, or iterate the members and keep the last match:
|
||||
@@ -161,7 +163,7 @@ If you cannot trust the source text to have unique keys, check [`size()`](https:
|
||||
|
||||
## Getting values out without copying
|
||||
|
||||
[`get<T>()`](https://json.nlohmann.me/api/basic_json_view/get/index.md) converts many `T` directly from the flat index, without ever building a `basic_json` value for the conversion: `bool`, arithmetic types, `std::nullptr_t`, `std::string`/other `std::basic_string`s (copied once), `basic_json`/`ordered_json` (via [`materialize()`](https://json.nlohmann.me/api/basic_json_view/materialize/index.md)), `basic_json_view` itself, `std::vector<U>`, and `std::map`/`std::unordered_map` with string-like keys. Every other type -- `std::list`, `std::pair`, `std::array`, enumerations, user types with a `from_json()` -- goes through [`materialize()`](https://json.nlohmann.me/api/basic_json_view/materialize/index.md)`.get<T>()` instead: the subtree is built into a real `basic_json` value first, exactly as [`parse()`](https://json.nlohmann.me/api/basic_json/parse/index.md) would, and converted from there.
|
||||
[`get<T>()`](https://json.nlohmann.me/api/basic_json_view/get/index.md) converts most `T` directly from the flat index, without ever building a `basic_json` value for the conversion: `bool`, arithmetic types, `std::nullptr_t`, `std::string`/other `std::basic_string`s (copied once), `basic_json_view` itself, the standard containers and other types the library converts (`std::vector`, `std::map`, `std::list`, `std::array`, `std::pair`, `std::tuple`, `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()`](https://json.nlohmann.me/api/basic_json_view/materialize/index.md)`.get<T>()` instead: the subtree is built into a real `basic_json` value first, exactly as [`parse()`](https://json.nlohmann.me/api/basic_json/parse/index.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:
|
||||
|
||||
@@ -170,6 +172,62 @@ 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`](https://json.nlohmann.me/api/view_mode/index.md): [`json_view`](https://json.nlohmann.me/api/json_view/index.md) is `basic_json_view<json, view_mode::read_only>`, and [`json_editable_view`](https://json.nlohmann.me/api/json_editable_view/index.md) is `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 `std::string_view`. A `const&` works as well, but a non-`const` reference does not bind to the views that [`root()`](https://json.nlohmann.me/api/basic_json_document/root/index.md), [`operator[]`](https://json.nlohmann.me/api/basic_json_view/operator%5B%5D/index.md), and [`at()`](https://json.nlohmann.me/api/basic_json_view/at/index.md) return, so `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](https://json.nlohmann.me/api/basic_json_view/basic_json_view/index.md) 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==`](https://json.nlohmann.me/api/basic_json_view/operator_eq/index.md).
|
||||
|
||||
[`is_json_view<T>`](https://json.nlohmann.me/api/is_json_view/index.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>()`](https://json.nlohmann.me/api/basic_json_view/get/index.md) on a view calls `T`'s `from_json()` with the view itself if that `from_json()` accepts views, and with [`materialize()`](https://json.nlohmann.me/api/basic_json_view/materialize/index.md) otherwise. The `from_json()` functions of the [`NLOHMANN_DEFINE_TYPE_*`](https://json.nlohmann.me/api/macros/nlohmann_define_type_intrusive/index.md), [`NLOHMANN_DEFINE_DERIVED_TYPE_*`](https://json.nlohmann.me/api/macros/nlohmann_define_derived_type/index.md), and [`NLOHMANN_JSON_SERIALIZE_ENUM`](https://json.nlohmann.me/api/macros/nlohmann_json_serialize_enum/index.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 `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 `template<typename BasicJsonType> void from_json(const BasicJsonType& j, person& p)`, as in [arbitrary type conversions](https://json.nlohmann.me/features/arbitrary_types/index.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); `materialize().get<T>()` would see the last one. Containers built from an object, such as `std::map`, keep the **last** value either way, as [`parse()`](https://json.nlohmann.me/api/basic_json/parse/index.md) does.
|
||||
- **[`JSON_DIAGNOSTICS`](https://json.nlohmann.me/api/macros/json_diagnostics/index.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()`](https://json.nlohmann.me/api/basic_json_view/dump/index.md) serializes a view directly from the flat index, without ever building a `basic_json` value. An object's members are written in document order, not sorted by key, and *every* occurrence of a repeated key is written, not only the last one -- the same two ways [iteration](#what-is-different) already differs from a [`materialize()`](https://json.nlohmann.me/api/basic_json_view/materialize/index.md)d value, see [Duplicate keys](#duplicate-keys). `materialize().dump()` gives a different result in both respects for a `json_view`.
|
||||
@@ -180,9 +238,9 @@ By default, numbers are written the way [`basic_json::dump()`](https://json.nloh
|
||||
|
||||
## Editing a document
|
||||
|
||||
Everything above is read-only: a `json_document`/`json_view` lets you look at a parsed text without copying it, but not change it. [`basic_json_document<BasicJsonType, true>`](https://json.nlohmann.me/api/basic_json_document/index.md) -- more conveniently spelled [`json_editable_document`](https://json.nlohmann.me/api/json_editable_document/index.md) or [`ordered_json_editable_document`](https://json.nlohmann.me/api/ordered_json_editable_document/index.md) -- also lets you [`set`](https://json.nlohmann.me/api/basic_json_document/set/index.md) a value, [`push_back`](https://json.nlohmann.me/api/basic_json_document/push_back/index.md) onto or [`insert`](https://json.nlohmann.me/api/basic_json_document/insert/index.md) into an array, and [`erase`](https://json.nlohmann.me/api/basic_json_document/erase/index.md) an object member or an array element, still without ever building a `basic_json` tree for parts you do not touch.
|
||||
Everything above is read-only: a `json_document`/`json_view` lets you look at a parsed text without copying it, but not change it. [`basic_json_document<BasicJsonType, view_mode::editable>`](https://json.nlohmann.me/api/basic_json_document/index.md) -- more conveniently spelled [`json_editable_document`](https://json.nlohmann.me/api/json_editable_document/index.md) or [`ordered_json_editable_document`](https://json.nlohmann.me/api/ordered_json_editable_document/index.md) -- also lets you [`set`](https://json.nlohmann.me/api/basic_json_document/set/index.md) a value, [`push_back`](https://json.nlohmann.me/api/basic_json_document/push_back/index.md) onto or [`insert`](https://json.nlohmann.me/api/basic_json_document/insert/index.md) into an array, and [`erase`](https://json.nlohmann.me/api/basic_json_document/erase/index.md) an object member or an array element, still without ever building a `basic_json` tree for parts you do not touch.
|
||||
|
||||
`Editable` defaults to `false`, so `json_document`/`ordered_json_document` are unaffected -- they carry none of the bookkeeping edits need, and calling `set`/`push_back`/`insert`/`erase` on one is a compile error, not a runtime one.
|
||||
The [mode](https://json.nlohmann.me/api/view_mode/index.md) defaults to `view_mode::read_only`, so `json_document`/`ordered_json_document` are unaffected -- they carry none of the bookkeeping edits need, and calling `set`/`push_back`/`insert`/`erase` on one is a compile error, not a runtime one.
|
||||
|
||||
### Why: editing without reformatting
|
||||
|
||||
@@ -199,9 +257,9 @@ Example: patch a configuration, keeping member order and number spellings
|
||||
#include <iostream>
|
||||
#include <nlohmann/json_view.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
using json_editable_document = nlohmann::json_editable_document;
|
||||
using json_editable_view = nlohmann::json_editable_view;
|
||||
using nlohmann::json;
|
||||
using nlohmann::json_editable_document;
|
||||
using nlohmann::json_editable_view;
|
||||
|
||||
int main()
|
||||
{
|
||||
@@ -258,7 +316,7 @@ Example: cache a parsed configuration as an image
|
||||
#include <vector>
|
||||
#include <nlohmann/json_view.hpp>
|
||||
|
||||
using json_document = nlohmann::json_document;
|
||||
using nlohmann::json_document;
|
||||
|
||||
int main()
|
||||
{
|
||||
@@ -294,7 +352,7 @@ true
|
||||
|
||||
Experimental
|
||||
|
||||
The image format is versioned but not yet stable, and may change in an incompatible way before it is declared stable. It is little-endian only, and tied to the library build that wrote it -- use it to cache a document or to hand one to another process running the *same* build, not as a long-term storage format; keep the original JSON text if a saved document needs to be readable by a future library version.
|
||||
The image format is versioned but not yet stable, and may change in an incompatible way before it is declared stable. It is little-endian only (on big-endian targets, `save()` and `load()` do not exist), and tied to the library build that wrote it -- use it to cache a document or to hand one to another process running the *same* build, not as a long-term storage format; keep the original JSON text if a saved document needs to be readable by a future library version.
|
||||
|
||||
The idea of a document you can read without parsing comes from zero-copy formats such as [FlatBuffers](https://github.com/google/flatbuffers) and [YaFF](https://github.com/yandex/yaff); the check [`load()`](https://json.nlohmann.me/api/basic_json_document/load/index.md) runs follows the idea of FlatBuffers' Verifier. No code is taken from either.
|
||||
|
||||
|
||||
Reference in new issue
Block a user