docs: add three figures to the 3.13.0 post

- short strings: two overlapping 16-byte loads and stores
- eight digits at a time: the three multiplications, lane by lane
- validate on the 19 held-out files, per file, Mac and x86-64

The prose the figures replace is trimmed.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
Niels Lohmann committed 2026-10-30 20:45:09 +01:00
1 parent 5cbec344fe
commit 0c74ad29ba
6 files changed
+3606 -12

No files matched your search

@@ -391,10 +391,14 @@ vst1q_u8(d + n - 16, b); // the two stores overlap too, with the same bytes
<p class="nj-code-caption" markdown>Writing a string of 16 to 32 bytes with two overlapping loads and stores (NEON).</p>
Both loads lie inside the string, together they cover all of it, and all tests happen before the first store. Shorter
strings use the same trick with two overlapping 8-, 4- or 2-byte loads, so no `memcpy` with a length known only at run
time is left. On `twitter.json`,
this cut the instructions of `dump()` by 21 %.
<div class="nj-fig-wrap" markdown>
--8<-- "images/perf_blog_overlap.svg"
</div>
<p class="nj-caption" markdown>The code above on `profile_link_color`, a key of `twitter.json`.</p>
Shorter strings use the same trick with two overlapping 8-, 4- or 2-byte loads, so no `memcpy` with a length known
only at run time is left. On `twitter.json`, this cut the instructions of `dump()` by 21 %.
### Escapes from a table
@@ -476,11 +480,14 @@ std::uint32_t parse_eight_digits(std::uint64_t v) noexcept
<p class="nj-code-caption" markdown>fast_float's conversion of eight ASCII digits to their value, with three multiplications.</p>
The mask turns the characters into digit values. Multiplying by `10·2⁸ + 1` adds ten times each byte to the byte
above it, so after the shift every second byte holds a two-digit number: `"12345678"` becomes 12, 34, 56 and 78. The
second step does the same with pairs of bytes and a factor of 100 (1234 and 5678), the third with 32-bit halves and
10,000. Whether all eight bytes are digits is one more expression: a digit is 0x30 to 0x39, so its high nibble must be
3, and adding 6 must keep it 3. Integers of up to 18 digits and floats of up to 19 then need no overflow check at all.
<div class="nj-fig-wrap" markdown>
--8<-- "images/perf_blog_digits.svg"
</div>
<p class="nj-caption" markdown>`parse_eight_digits()` on `"12345678"`: multiplying by `10·2⁸ + 1` adds ten times each byte to the byte above it, and the shift and the next mask keep every second lane.</p>
Whether all eight bytes are digits is one more expression: a digit is 0x30 to 0x39, so its high nibble must be 3, and
adding 6 must keep it 3. Integers of up to 18 digits and floats of up to 19 then need no overflow check at all.
### Clinger's fast path
@@ -1290,9 +1297,17 @@ The four files are the ones 3.13.0 was tuned on, so we also ran *validate*, *sum
other files of simdjson's [`jsonexamples`](https://github.com/simdjson/simdjson-data/tree/master/jsonexamples). By
geometric mean, `json_document` stays the fastest in *validate*, *minify* and *write* on every compiler, and in *sum*
with Clang and on the Mac; with GCC, simdjson sums in 0.83 to 0.85 of its time. File by file, it is less
clear-cut: on x86-64, `json_document` validates only 4 to 8 of the 19 files fastest (13 on the Mac). simdjson wins 5
to 8 of the others, and Boost.JSON, without number conversion, validates the number-heavy `mesh.pretty`, `numbers`
and `marine_ik` up to 1.5 times as fast. We know two causes, but so far each fix slowed down other files.
clear-cut:
<div class="nj-fig-wrap" markdown>
--8<-- "images/perf_blog_heldout.svg"
</div>
<p class="nj-caption" markdown>*validate* on the 19 files: `json_document`'s fastest fully validating way against the fastest library's, per file; 1.0× means it is the fastest. Less is better. The right column names the fastest library on x86-64 (GCC 16.2).</p>
On x86-64, `json_document` validates only 4 to 8 of the 19 files fastest, against 13 on the Mac. Boost.JSON, without
number conversion, validates the number-heavy `mesh.pretty`, `numbers` and `marine_ik` up to 1.5 times as fast. We
know two causes, but so far each fix slowed down other files.
Every *validate* way also ran the 318 files of [JSONTestSuite](https://github.com/nst/JSONTestSuite). The fully
validating ways pass, with a few exceptions listed in [Appendix E](#e-comparison-with-other-libraries), one of them
@@ -0,0 +1,66 @@
<svg class="nj-fig nj-charts nj-charts--swar" viewBox="0 0 600 430" role="img" aria-labelledby="nj-blog-digits nj-blog-digits-d" xmlns="http://www.w3.org/2000/svg">
<title id="nj-blog-digits">Converting eight A&#8203;SCII digits to their value with three multiplications</title>
<desc id="nj-blog-digits-d">The text 12345678 as one word. Masking gives the digit values 1 to 8, one per byte. Multiplying by 10 times 2 to the 8 plus 1 and shifting gives 12, 34, 56 and 78 in 16-bit lanes; multiplying by 100 times 2 to the 16 plus 1 gives 1234 and 5678 in 32-bit lanes; multiplying by 10000 times 2 to the 32 plus 1 gives 12345678.</desc>
<text class="fg-h" x="40" y="20">eight A&#8203;SCII digits in one 64-bit word (byte 0 is the lowest)</text>
<rect class="fg-cell" x="40" y="30" width="58" height="34" rx="4"/>
<text class="fg-code" x="69" y="53" text-anchor="middle">1</text>
<text class="nj-charts-tick" x="69" y="80">0x31</text>
<rect class="fg-cell" x="104" y="30" width="58" height="34" rx="4"/>
<text class="fg-code" x="133" y="53" text-anchor="middle">2</text>
<text class="nj-charts-tick" x="133" y="80">0x32</text>
<rect class="fg-cell" x="168" y="30" width="58" height="34" rx="4"/>
<text class="fg-code" x="197" y="53" text-anchor="middle">3</text>
<text class="nj-charts-tick" x="197" y="80">0x33</text>
<rect class="fg-cell" x="232" y="30" width="58" height="34" rx="4"/>
<text class="fg-code" x="261" y="53" text-anchor="middle">4</text>
<text class="nj-charts-tick" x="261" y="80">0x34</text>
<rect class="fg-cell" x="296" y="30" width="58" height="34" rx="4"/>
<text class="fg-code" x="325" y="53" text-anchor="middle">5</text>
<text class="nj-charts-tick" x="325" y="80">0x35</text>
<rect class="fg-cell" x="360" y="30" width="58" height="34" rx="4"/>
<text class="fg-code" x="389" y="53" text-anchor="middle">6</text>
<text class="nj-charts-tick" x="389" y="80">0x36</text>
<rect class="fg-cell" x="424" y="30" width="58" height="34" rx="4"/>
<text class="fg-code" x="453" y="53" text-anchor="middle">7</text>
<text class="nj-charts-tick" x="453" y="80">0x37</text>
<rect class="fg-cell" x="488" y="30" width="58" height="34" rx="4"/>
<text class="fg-code" x="517" y="53" text-anchor="middle">8</text>
<text class="nj-charts-tick" x="517" y="80">0x38</text>
<text class="fg-h" x="40" y="112">&amp; 0x0F0F0F0F0F0F0F0F: one digit value per byte</text>
<rect class="fg-cell" x="40" y="122" width="58" height="34" rx="4"/>
<text class="fg-code" x="69" y="145" text-anchor="middle">1</text>
<rect class="fg-cell" x="104" y="122" width="58" height="34" rx="4"/>
<text class="fg-code" x="133" y="145" text-anchor="middle">2</text>
<rect class="fg-cell" x="168" y="122" width="58" height="34" rx="4"/>
<text class="fg-code" x="197" y="145" text-anchor="middle">3</text>
<rect class="fg-cell" x="232" y="122" width="58" height="34" rx="4"/>
<text class="fg-code" x="261" y="145" text-anchor="middle">4</text>
<rect class="fg-cell" x="296" y="122" width="58" height="34" rx="4"/>
<text class="fg-code" x="325" y="145" text-anchor="middle">5</text>
<rect class="fg-cell" x="360" y="122" width="58" height="34" rx="4"/>
<text class="fg-code" x="389" y="145" text-anchor="middle">6</text>
<rect class="fg-cell" x="424" y="122" width="58" height="34" rx="4"/>
<text class="fg-code" x="453" y="145" text-anchor="middle">7</text>
<rect class="fg-cell" x="488" y="122" width="58" height="34" rx="4"/>
<text class="fg-code" x="517" y="145" text-anchor="middle">8</text>
<text class="fg-h" x="40" y="186">× (10 · 2⁸ + 1) &gt;&gt; 8, every second byte kept: two digits per 16 bits</text>
<rect class="fg-cell" x="40" y="196" width="122" height="34" rx="4"/>
<text class="fg-code" x="101" y="219" text-anchor="middle">12</text>
<rect class="fg-cell" x="168" y="196" width="122" height="34" rx="4"/>
<text class="fg-code" x="229" y="219" text-anchor="middle">34</text>
<rect class="fg-cell" x="296" y="196" width="122" height="34" rx="4"/>
<text class="fg-code" x="357" y="219" text-anchor="middle">56</text>
<rect class="fg-cell" x="424" y="196" width="122" height="34" rx="4"/>
<text class="fg-code" x="485" y="219" text-anchor="middle">78</text>
<text class="fg-h" x="40" y="260">× (100 · 2¹⁶ + 1) &gt;&gt; 16, every second lane kept: four digits per 32 bits</text>
<rect class="fg-cell" x="40" y="270" width="250" height="34" rx="4"/>
<text class="fg-code" x="165" y="293" text-anchor="middle">1234</text>
<rect class="fg-cell" x="296" y="270" width="250" height="34" rx="4"/>
<text class="fg-code" x="421" y="293" text-anchor="middle">5678</text>
<text class="fg-h" x="40" y="334">× (10000 · 2³² + 1) &gt;&gt; 32: the value</text>
<rect class="fg-cell" x="40" y="344" width="506" height="34" rx="4"/>
<rect class="nj-charts-c1" fill-opacity=".25" x="40" y="344" width="506" height="34" rx="4"/>
<text class="fg-code" x="293" y="367" text-anchor="middle">12345678</text>
<text class="fg-note fg-note--l" x="40" y="400">Each step combines neighboring lanes, in all lanes of the word at once:</text>
<text class="fg-note fg-note--l" x="40" y="418">three multiplications instead of eight, and no branch.</text>
</svg>

After

Width:  |  Height:  |  Size: 5.0 KiB

@@ -0,0 +1,98 @@
<svg class="nj-fig nj-charts nj-charts--blog" viewBox="0 0 620 482" role="img" aria-labelledby="nj-blog-heldout nj-blog-heldout-d" xmlns="http://www.w3.org/2000/svg">
<title id="nj-blog-heldout">Validating 19 files 3.13.0 was not tuned on: json_document&#x27;s time relative to the fastest library per file</title>
<desc id="nj-blog-heldout-d">Dot plot per file, less is better; 1.0 means json_document is the fastest fully validating library. github_events: Mac 1.00, x86-64 1.00 (nlohmann/json json_document); mesh: Mac 1.00, x86-64 1.00 (nlohmann/json json_document); semanticscholar-corpus: Mac 1.00, x86-64 1.00 (nlohmann/json json_document); twitter_api_compact_response: Mac 1.00, x86-64 1.00 (nlohmann/json json_document); twitter_api_response: Mac 1.00, x86-64 1.00 (nlohmann/json json_document); update-center: Mac 1.00, x86-64 1.00 (nlohmann/json json_document); apache_builds: Mac 1.15, x86-64 1.00 (nlohmann/json json_document); twitter_timeline: Mac 1.04, x86-64 1.02 (yyjson); twitterescaped: Mac 1.10, x86-64 1.08 (simdjson); gsoc-2018: Mac 1.00, x86-64 1.10 (Boost.J&#8203;SON); google_maps_api_compact_response: Mac 1.03, x86-64 1.12 (yyjson); tree-pretty: Mac 1.01, x86-64 1.14 (simdjson); repeat: Mac 1.00, x86-64 1.14 (simdjson); random: Mac 1.00, x86-64 1.17 (simdjson); instruments: Mac 1.00, x86-64 1.18 (simdjson); google_maps_api_response: Mac 1.01, x86-64 1.19 (simdjson); marine_ik: Mac 1.00, x86-64 1.23 (Boost.J&#8203;SON); numbers: Mac 1.00, x86-64 1.32 (Boost.J&#8203;SON); mesh.pretty: Mac 1.00, x86-64 1.49 (Boost.J&#8203;SON).</desc>
<line class="nj-charts-grid" x1="262" y1="50" x2="262" y2="438"/>
<text class="nj-charts-tick" x="262" y="454">1.0&#215;</text>
<line class="nj-charts-grid" x1="302.727" y1="50" x2="302.727" y2="438"/>
<text class="nj-charts-tick" x="302.727" y="454">1.1&#215;</text>
<line class="nj-charts-grid" x1="343.455" y1="50" x2="343.455" y2="438"/>
<text class="nj-charts-tick" x="343.455" y="454">1.2&#215;</text>
<line class="nj-charts-grid" x1="384.182" y1="50" x2="384.182" y2="438"/>
<text class="nj-charts-tick" x="384.182" y="454">1.3&#215;</text>
<line class="nj-charts-grid" x1="424.909" y1="50" x2="424.909" y2="438"/>
<text class="nj-charts-tick" x="424.909" y="454">1.4&#215;</text>
<line class="nj-charts-grid" x1="465.636" y1="50" x2="465.636" y2="438"/>
<text class="nj-charts-tick" x="465.636" y="454">1.5&#215;</text>
<text class="nj-charts-tick" x="374" y="472">json&#95;document&#8217;s time / the fastest library&#8217;s, less is better</text>
<circle class="nj-charts-json-dot" cx="13" cy="14" r="5"/><text class="nj-charts-leg" x="23" y="18.5">Apple M1 Max</text>
<circle class="nj-charts-ojson-dot" cx="134.2" cy="14" r="5"/><text class="nj-charts-leg" x="144.2" y="18.5">x86-64, G&#8203;CC 16.2</text>
<text class="nj-charts-tick nj-charts-tick--l" x="500" y="48">fastest on x86-64</text>
<text class="nj-charts-rowlabel nj-charts-code" x="252" y="68" text-anchor="end">github&#95;events</text>
<circle class="nj-charts-json-dot" cx="262.0" cy="60.5" r="4.5"><title>github&#95;events, Apple M1 Max: 1.00&#215; the time of the fastest (it is the fastest)</title></circle>
<circle class="nj-charts-ojson-dot" cx="262.0" cy="67.5" r="4.5"><title>github&#95;events, x86-64, G&#8203;CC 16.2: 1.00&#215; the time of the fastest (it is the fastest)</title></circle>
<text class="nj-charts-tick nj-charts-tick--l" x="500" y="68">json&#95;document</text>
<text class="nj-charts-rowlabel nj-charts-code" x="252" y="88" text-anchor="end">mesh</text>
<circle class="nj-charts-json-dot" cx="262.0" cy="80.5" r="4.5"><title>mesh, Apple M1 Max: 1.00&#215; the time of the fastest (it is the fastest)</title></circle>
<circle class="nj-charts-ojson-dot" cx="262.0" cy="87.5" r="4.5"><title>mesh, x86-64, G&#8203;CC 16.2: 1.00&#215; the time of the fastest (it is the fastest)</title></circle>
<text class="nj-charts-tick nj-charts-tick--l" x="500" y="88">json&#95;document</text>
<text class="nj-charts-rowlabel nj-charts-code" x="252" y="108" text-anchor="end">semanticscholar-corpus</text>
<circle class="nj-charts-json-dot" cx="262.0" cy="100.5" r="4.5"><title>semanticscholar-corpus, Apple M1 Max: 1.00&#215; the time of the fastest (it is the fastest)</title></circle>
<circle class="nj-charts-ojson-dot" cx="262.0" cy="107.5" r="4.5"><title>semanticscholar-corpus, x86-64, G&#8203;CC 16.2: 1.00&#215; the time of the fastest (it is the fastest)</title></circle>
<text class="nj-charts-tick nj-charts-tick--l" x="500" y="108">json&#95;document</text>
<text class="nj-charts-rowlabel nj-charts-code" x="252" y="128" text-anchor="end">twitter&#95;api&#95;compact&#95;response</text>
<circle class="nj-charts-json-dot" cx="262.0" cy="120.5" r="4.5"><title>twitter&#95;api&#95;compact&#95;response, Apple M1 Max: 1.00&#215; the time of the fastest (it is the fastest)</title></circle>
<circle class="nj-charts-ojson-dot" cx="262.0" cy="127.5" r="4.5"><title>twitter&#95;api&#95;compact&#95;response, x86-64, G&#8203;CC 16.2: 1.00&#215; the time of the fastest (it is the fastest)</title></circle>
<text class="nj-charts-tick nj-charts-tick--l" x="500" y="128">json&#95;document</text>
<text class="nj-charts-rowlabel nj-charts-code" x="252" y="148" text-anchor="end">twitter&#95;api&#95;response</text>
<circle class="nj-charts-json-dot" cx="262.0" cy="140.5" r="4.5"><title>twitter&#95;api&#95;response, Apple M1 Max: 1.00&#215; the time of the fastest (it is the fastest)</title></circle>
<circle class="nj-charts-ojson-dot" cx="262.0" cy="147.5" r="4.5"><title>twitter&#95;api&#95;response, x86-64, G&#8203;CC 16.2: 1.00&#215; the time of the fastest (it is the fastest)</title></circle>
<text class="nj-charts-tick nj-charts-tick--l" x="500" y="148">json&#95;document</text>
<text class="nj-charts-rowlabel nj-charts-code" x="252" y="168" text-anchor="end">update-center</text>
<circle class="nj-charts-json-dot" cx="262.0" cy="160.5" r="4.5"><title>update-center, Apple M1 Max: 1.00&#215; the time of the fastest (it is the fastest)</title></circle>
<circle class="nj-charts-ojson-dot" cx="262.0" cy="167.5" r="4.5"><title>update-center, x86-64, G&#8203;CC 16.2: 1.00&#215; the time of the fastest (it is the fastest)</title></circle>
<text class="nj-charts-tick nj-charts-tick--l" x="500" y="168">json&#95;document</text>
<text class="nj-charts-rowlabel nj-charts-code" x="252" y="188" text-anchor="end">apache&#95;builds</text>
<circle class="nj-charts-json-dot" cx="323.8" cy="180.5" r="4.5"><title>apache&#95;builds, Apple M1 Max: 1.15&#215; the time of simdjson</title></circle>
<circle class="nj-charts-ojson-dot" cx="262.0" cy="187.5" r="4.5"><title>apache&#95;builds, x86-64, G&#8203;CC 16.2: 1.00&#215; the time of the fastest (it is the fastest)</title></circle>
<text class="nj-charts-tick nj-charts-tick--l" x="500" y="188">json&#95;document</text>
<text class="nj-charts-rowlabel nj-charts-code" x="252" y="208" text-anchor="end">twitter&#95;timeline</text>
<circle class="nj-charts-json-dot" cx="277.6" cy="200.5" r="4.5"><title>twitter&#95;timeline, Apple M1 Max: 1.04&#215; the time of yyjson</title></circle>
<circle class="nj-charts-ojson-dot" cx="270.8" cy="207.5" r="4.5"><title>twitter&#95;timeline, x86-64, G&#8203;CC 16.2: 1.02&#215; the time of yyjson</title></circle>
<text class="nj-charts-tick nj-charts-tick--l nj-charts-best" x="500" y="208">yyjson</text>
<text class="nj-charts-rowlabel nj-charts-code" x="252" y="228" text-anchor="end">twitterescaped</text>
<circle class="nj-charts-json-dot" cx="303.1" cy="220.5" r="4.5"><title>twitterescaped, Apple M1 Max: 1.10&#215; the time of yyjson</title></circle>
<circle class="nj-charts-ojson-dot" cx="293.5" cy="227.5" r="4.5"><title>twitterescaped, x86-64, G&#8203;CC 16.2: 1.08&#215; the time of simdjson</title></circle>
<text class="nj-charts-tick nj-charts-tick--l nj-charts-best" x="500" y="228">simdjson</text>
<text class="nj-charts-rowlabel nj-charts-code" x="252" y="248" text-anchor="end">gsoc-2018</text>
<circle class="nj-charts-json-dot" cx="262.0" cy="240.5" r="4.5"><title>gsoc-2018, Apple M1 Max: 1.00&#215; the time of the fastest (it is the fastest)</title></circle>
<circle class="nj-charts-ojson-dot" cx="303.9" cy="247.5" r="4.5"><title>gsoc-2018, x86-64, G&#8203;CC 16.2: 1.10&#215; the time of Boost.J&#8203;SON</title></circle>
<text class="nj-charts-tick nj-charts-tick--l nj-charts-best" x="500" y="248">Boost.J&#8203;SON</text>
<text class="nj-charts-rowlabel nj-charts-code" x="252" y="268" text-anchor="end">google&#95;maps&#95;api&#95;compact&#95;response</text>
<circle class="nj-charts-json-dot" cx="274.9" cy="260.5" r="4.5"><title>google&#95;maps&#95;api&#95;compact&#95;response, Apple M1 Max: 1.03&#215; the time of yyjson</title></circle>
<circle class="nj-charts-ojson-dot" cx="310.6" cy="267.5" r="4.5"><title>google&#95;maps&#95;api&#95;compact&#95;response, x86-64, G&#8203;CC 16.2: 1.12&#215; the time of yyjson</title></circle>
<text class="nj-charts-tick nj-charts-tick--l nj-charts-best" x="500" y="268">yyjson</text>
<text class="nj-charts-rowlabel nj-charts-code" x="252" y="288" text-anchor="end">tree-pretty</text>
<circle class="nj-charts-json-dot" cx="265.6" cy="280.5" r="4.5"><title>tree-pretty, Apple M1 Max: 1.01&#215; the time of simdjson</title></circle>
<circle class="nj-charts-ojson-dot" cx="317.7" cy="287.5" r="4.5"><title>tree-pretty, x86-64, G&#8203;CC 16.2: 1.14&#215; the time of simdjson</title></circle>
<text class="nj-charts-tick nj-charts-tick--l nj-charts-best" x="500" y="288">simdjson</text>
<text class="nj-charts-rowlabel nj-charts-code" x="252" y="308" text-anchor="end">repeat</text>
<circle class="nj-charts-json-dot" cx="262.0" cy="300.5" r="4.5"><title>repeat, Apple M1 Max: 1.00&#215; the time of the fastest (it is the fastest)</title></circle>
<circle class="nj-charts-ojson-dot" cx="319.3" cy="307.5" r="4.5"><title>repeat, x86-64, G&#8203;CC 16.2: 1.14&#215; the time of simdjson</title></circle>
<text class="nj-charts-tick nj-charts-tick--l nj-charts-best" x="500" y="308">simdjson</text>
<text class="nj-charts-rowlabel nj-charts-code" x="252" y="328" text-anchor="end">random</text>
<circle class="nj-charts-json-dot" cx="262.0" cy="320.5" r="4.5"><title>random, Apple M1 Max: 1.00&#215; the time of the fastest (it is the fastest)</title></circle>
<circle class="nj-charts-ojson-dot" cx="333.3" cy="327.5" r="4.5"><title>random, x86-64, G&#8203;CC 16.2: 1.17&#215; the time of simdjson</title></circle>
<text class="nj-charts-tick nj-charts-tick--l nj-charts-best" x="500" y="328">simdjson</text>
<text class="nj-charts-rowlabel nj-charts-code" x="252" y="348" text-anchor="end">instruments</text>
<circle class="nj-charts-json-dot" cx="262.0" cy="340.5" r="4.5"><title>instruments, Apple M1 Max: 1.00&#215; the time of the fastest (it is the fastest)</title></circle>
<circle class="nj-charts-ojson-dot" cx="334.2" cy="347.5" r="4.5"><title>instruments, x86-64, G&#8203;CC 16.2: 1.18&#215; the time of simdjson</title></circle>
<text class="nj-charts-tick nj-charts-tick--l nj-charts-best" x="500" y="348">simdjson</text>
<text class="nj-charts-rowlabel nj-charts-code" x="252" y="368" text-anchor="end">google&#95;maps&#95;api&#95;response</text>
<circle class="nj-charts-json-dot" cx="266.3" cy="360.5" r="4.5"><title>google&#95;maps&#95;api&#95;response, Apple M1 Max: 1.01&#215; the time of simdjson</title></circle>
<circle class="nj-charts-ojson-dot" cx="341.1" cy="367.5" r="4.5"><title>google&#95;maps&#95;api&#95;response, x86-64, G&#8203;CC 16.2: 1.19&#215; the time of simdjson</title></circle>
<text class="nj-charts-tick nj-charts-tick--l nj-charts-best" x="500" y="368">simdjson</text>
<text class="nj-charts-rowlabel nj-charts-code" x="252" y="388" text-anchor="end">marine&#95;ik</text>
<circle class="nj-charts-json-dot" cx="262.0" cy="380.5" r="4.5"><title>marine&#95;ik, Apple M1 Max: 1.00&#215; the time of the fastest (it is the fastest)</title></circle>
<circle class="nj-charts-ojson-dot" cx="356.9" cy="387.5" r="4.5"><title>marine&#95;ik, x86-64, G&#8203;CC 16.2: 1.23&#215; the time of Boost.J&#8203;SON</title></circle>
<text class="nj-charts-tick nj-charts-tick--l nj-charts-best" x="500" y="388">Boost.J&#8203;SON</text>
<text class="nj-charts-rowlabel nj-charts-code" x="252" y="408" text-anchor="end">numbers</text>
<circle class="nj-charts-json-dot" cx="262.0" cy="400.5" r="4.5"><title>numbers, Apple M1 Max: 1.00&#215; the time of the fastest (it is the fastest)</title></circle>
<circle class="nj-charts-ojson-dot" cx="393.4" cy="407.5" r="4.5"><title>numbers, x86-64, G&#8203;CC 16.2: 1.32&#215; the time of Boost.J&#8203;SON</title></circle>
<text class="nj-charts-tick nj-charts-tick--l nj-charts-best" x="500" y="408">Boost.J&#8203;SON</text>
<text class="nj-charts-rowlabel nj-charts-code" x="252" y="428" text-anchor="end">mesh.pretty</text>
<circle class="nj-charts-json-dot" cx="262.0" cy="420.5" r="4.5"><title>mesh.pretty, Apple M1 Max: 1.00&#215; the time of the fastest (it is the fastest)</title></circle>
<circle class="nj-charts-ojson-dot" cx="461.4" cy="427.5" r="4.5"><title>mesh.pretty, x86-64, G&#8203;CC 16.2: 1.49&#215; the time of Boost.J&#8203;SON</title></circle>
<text class="nj-charts-tick nj-charts-tick--l nj-charts-best" x="500" y="428">Boost.J&#8203;SON</text>
<line class="nj-charts-ref" x1="262" y1="50" x2="262" y2="438"/>
<text class="nj-charts-tick" x="262" y="44">fastest</text>
</svg>

After

Width:  |  Height:  |  Size: 13 KiB

@@ -0,0 +1,72 @@
<svg class="nj-fig nj-charts nj-charts--swar" viewBox="0 0 640 294" role="img" aria-labelledby="nj-blog-overlap nj-blog-overlap-d" xmlns="http://www.w3.org/2000/svg">
<title id="nj-blog-overlap">Writing an 18-byte string with two overlapping 16-byte loads and stores</title>
<desc id="nj-blog-overlap-d">The 18 bytes of profile_link_color. Load a covers bytes 0 to 15, load b covers bytes 2 to 17, so bytes 2 to 15 are in both. Neither contains a byte that needs escaping, so a is stored at the destination and b 2 bytes later; the second store writes bytes 2 to 15 again with the same values. This works for any length from 16 to 32 bytes without a loop.</desc>
<text class="fg-h" x="40" y="20">a string of n = 18 bytes: too long for one 16-byte vector, too short for a loop</text>
<rect class="fg-cell" x="40" y="34" width="27" height="36" rx="4"/>
<text class="fg-code" x="53.5" y="58" text-anchor="middle">p</text>
<rect class="fg-cell" x="71" y="34" width="27" height="36" rx="4"/>
<text class="fg-code" x="84.5" y="58" text-anchor="middle">r</text>
<rect class="fg-cell" x="102" y="34" width="27" height="36" rx="4"/>
<rect class="nj-charts-c3" fill-opacity=".3" x="102" y="34" width="27" height="36" rx="4"/>
<text class="fg-code" x="115.5" y="58" text-anchor="middle">o</text>
<rect class="fg-cell" x="133" y="34" width="27" height="36" rx="4"/>
<rect class="nj-charts-c3" fill-opacity=".3" x="133" y="34" width="27" height="36" rx="4"/>
<text class="fg-code" x="146.5" y="58" text-anchor="middle">f</text>
<rect class="fg-cell" x="164" y="34" width="27" height="36" rx="4"/>
<rect class="nj-charts-c3" fill-opacity=".3" x="164" y="34" width="27" height="36" rx="4"/>
<text class="fg-code" x="177.5" y="58" text-anchor="middle">i</text>
<rect class="fg-cell" x="195" y="34" width="27" height="36" rx="4"/>
<rect class="nj-charts-c3" fill-opacity=".3" x="195" y="34" width="27" height="36" rx="4"/>
<text class="fg-code" x="208.5" y="58" text-anchor="middle">l</text>
<rect class="fg-cell" x="226" y="34" width="27" height="36" rx="4"/>
<rect class="nj-charts-c3" fill-opacity=".3" x="226" y="34" width="27" height="36" rx="4"/>
<text class="fg-code" x="239.5" y="58" text-anchor="middle">e</text>
<rect class="fg-cell" x="257" y="34" width="27" height="36" rx="4"/>
<rect class="nj-charts-c3" fill-opacity=".3" x="257" y="34" width="27" height="36" rx="4"/>
<text class="fg-code" x="270.5" y="58" text-anchor="middle">&#95;</text>
<rect class="fg-cell" x="288" y="34" width="27" height="36" rx="4"/>
<rect class="nj-charts-c3" fill-opacity=".3" x="288" y="34" width="27" height="36" rx="4"/>
<text class="fg-code" x="301.5" y="58" text-anchor="middle">l</text>
<rect class="fg-cell" x="319" y="34" width="27" height="36" rx="4"/>
<rect class="nj-charts-c3" fill-opacity=".3" x="319" y="34" width="27" height="36" rx="4"/>
<text class="fg-code" x="332.5" y="58" text-anchor="middle">i</text>
<rect class="fg-cell" x="350" y="34" width="27" height="36" rx="4"/>
<rect class="nj-charts-c3" fill-opacity=".3" x="350" y="34" width="27" height="36" rx="4"/>
<text class="fg-code" x="363.5" y="58" text-anchor="middle">n</text>
<rect class="fg-cell" x="381" y="34" width="27" height="36" rx="4"/>
<rect class="nj-charts-c3" fill-opacity=".3" x="381" y="34" width="27" height="36" rx="4"/>
<text class="fg-code" x="394.5" y="58" text-anchor="middle">k</text>
<rect class="fg-cell" x="412" y="34" width="27" height="36" rx="4"/>
<rect class="nj-charts-c3" fill-opacity=".3" x="412" y="34" width="27" height="36" rx="4"/>
<text class="fg-code" x="425.5" y="58" text-anchor="middle">&#95;</text>
<rect class="fg-cell" x="443" y="34" width="27" height="36" rx="4"/>
<rect class="nj-charts-c3" fill-opacity=".3" x="443" y="34" width="27" height="36" rx="4"/>
<text class="fg-code" x="456.5" y="58" text-anchor="middle">c</text>
<rect class="fg-cell" x="474" y="34" width="27" height="36" rx="4"/>
<rect class="nj-charts-c3" fill-opacity=".3" x="474" y="34" width="27" height="36" rx="4"/>
<text class="fg-code" x="487.5" y="58" text-anchor="middle">o</text>
<rect class="fg-cell" x="505" y="34" width="27" height="36" rx="4"/>
<rect class="nj-charts-c3" fill-opacity=".3" x="505" y="34" width="27" height="36" rx="4"/>
<text class="fg-code" x="518.5" y="58" text-anchor="middle">l</text>
<rect class="fg-cell" x="536" y="34" width="27" height="36" rx="4"/>
<text class="fg-code" x="549.5" y="58" text-anchor="middle">o</text>
<rect class="fg-cell" x="567" y="34" width="27" height="36" rx="4"/>
<text class="fg-code" x="580.5" y="58" text-anchor="middle">r</text>
<text class="nj-charts-tick" x="53.5" y="86">0</text>
<text class="nj-charts-tick" x="115.5" y="86">2</text>
<text class="nj-charts-tick" x="518.5" y="86">15</text>
<text class="nj-charts-tick" x="580.5" y="86">17</text>
<rect class="nj-charts-c1" fill-opacity=".22" x="40" y="100" width="492" height="22" rx="4"/>
<rect class="nj-charts-c1" x="40" y="100" width="4" height="22" rx="2"/>
<rect class="nj-charts-c1" x="528" y="100" width="4" height="22" rx="2"/>
<text class="fg-code" x="286" y="116" text-anchor="middle" style="font-size:14px">a = load 16 bytes at p</text>
<rect class="nj-charts-c2" fill-opacity=".22" x="102" y="130" width="492" height="22" rx="4"/>
<rect class="nj-charts-c2" x="102" y="130" width="4" height="22" rx="2"/>
<rect class="nj-charts-c2" x="590" y="130" width="4" height="22" rx="2"/>
<text class="fg-code" x="348" y="146" text-anchor="middle" style="font-size:14px">b = load 16 bytes at p + n &#8722; 16</text>
<text class="fg-note fg-note--l" x="40" y="182">Both loads lie inside the string, and together they cover all of it; bytes 2 to 15 are in both.</text>
<text class="fg-note fg-note--l" x="40" y="204">Test a and b for a quote, a backslash, a control character or 0x7F: none, so write</text>
<text class="fg-code" x="40" y="234">store a at d, store b at d + n &#8722; 16</text>
<text class="fg-note fg-note--l" x="40" y="262">The second store writes bytes 2 to 15 again, with the same values. For any n from 16 to 32:</text>
<text class="fg-note fg-note--l" x="40" y="280">two loads, one test, two stores, no loop and no branch on the length.</text>
</svg>

After

Width:  |  Height:  |  Size: 6.0 KiB