Files
json/home/blog/how_3_13_0_got_faster/index.html
T
2026-11-09 18:59:22 +00:00

2320 lines
826 KiB
HTML
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!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=description content="JSON for Modern C++ is a header-only C++11 library that makes JSON a first-class data type."><meta name=author content="Niels Lohmann"><link href="https://json.nlohmann.me/home/blog/how_3_13_0_got_faster/" rel="canonical"><link href=../../releases/v1.0.0/ rel=prev><link href=../../design_goals/ rel=next><link rel=icon href=../../../assets/images/favicon.png><meta name=generator content="mkdocs-1.6.1, mkdocs-material-9.8.0"><title>How 3.13.0 got faster - JSON for Modern C++</title><link rel=stylesheet href=../../../assets/stylesheets/main.57a0d79d.min.css><link rel=stylesheet href=../../../assets/stylesheets/palette.fb2fffe2.min.css><link rel=stylesheet href=../../../css/custom.css><link rel=stylesheet href=../../../css/brand.css><link rel=stylesheet href=../../../css/fig-sax.css><link rel=stylesheet href=../../../css/fig-jsonview.css><link rel=stylesheet href=../../../css/fig-exceptions.css><link rel=stylesheet href=../../../css/fig-pointer.css><link rel=stylesheet href=../../../css/fig-charts.css><link rel=stylesheet href=../../../css/fig-integration.css><link rel=stylesheet href=../../../css/fig-macros.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=custom data-md-color-accent=custom> <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=#how-nlohmannjson-3130-got-3-faster 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> <img src=../../../images/wordmark-header.svg alt=logo> </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> How 3.13.0 got faster </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=custom data-md-color-accent=custom 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=custom data-md-color-accent=custom 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 5 9.5 5"/></svg> </label> <div class=md-search data-md-component=search role=dialog> <label class=md-search__overlay for=__search></label> <div class=md-search__inner role=search> <form class=md-search__form name=search> <input type=text class=md-search__input name=query aria-label=Search placeholder=Search autocapitalize=off autocorrect=off autocomplete=off spellcheck=false data-md-component=search-query required> <label class="md-search__icon 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 5 9.5 5"/></svg> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11z"/></svg> </label> <nav class=md-search__options aria-label=Search> <button type=reset class="md-search__icon md-icon" title=Clear aria-label=Clear tabindex=-1> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg> </button> </nav> <div class=md-search__suggest data-md-component=search-suggest></div> </form> <div class=md-search__output> <div class=md-search__scrollwrap tabindex=0 data-md-scrollfix> <div class=md-search-result data-md-component=search-result> <div class=md-search-result__meta> Initializing search </div> <ol class=md-search-result__list role=presentation></ol> </div> </div> </div> </div> </div> <div class=md-header__source> <a href="https://github.com/nlohmann/json" title="Go to repository" class="md-source" data-md-component="source"> <div class="md-source__icon md-icon"> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 512 512"><!-- Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2025 Fonticons, Inc.--><path d="M173.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6m-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3m44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9M252.8 8C114.1 8 8 113.3 8 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C436.2 457.8 504 362.9 504 252 504 113.3 391.5 8 252.8 8M105.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1m-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7m32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1m-11.4-14.7c-1.6 1-1.6 3.6 0 5.9s4.3 3.3 5.6 2.3c1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2"/></svg> </div> <div class=md-source__repository> nlohmann/json </div> </a> </div> </nav> </header> <div class=md-container data-md-component=container> <nav class=md-tabs aria-label=Tabs data-md-component=tabs> <div class=md-grid> <ul class=md-tabs__list> <li class="md-tabs__item md-tabs__item--active"> <a href=../../.. class=md-tabs__link> Home </a> </li> <li class=md-tabs__item> <a href=../../../features/ class=md-tabs__link> Features </a> </li> <li class=md-tabs__item> <a href=../../../integration/ class=md-tabs__link> Integration </a> </li> <li class=md-tabs__item> <a href=../../../api/basic_json/ class=md-tabs__link> API Documentation </a> </li> <li class=md-tabs__item> <a href=../../../community/ class=md-tabs__link> Community </a> </li> </ul> </div> </nav> <main class=md-main data-md-component=main> <div class="md-main__inner md-grid"> <div class="md-sidebar md-sidebar--primary" data-md-component=sidebar data-md-type=navigation> <div class=md-sidebar__scrollwrap> <div class=md-sidebar__inner> <nav class="md-nav md-nav--primary md-nav--lifted" aria-label=Navigation data-md-level=0> <label class=md-nav__title for=__drawer> <a href=../../.. title="JSON for Modern C++" class="md-nav__button md-logo" aria-label="JSON for Modern C++" data-md-component=logo> <img src=../../../images/wordmark-header.svg alt=logo> </a> JSON for Modern C++ </label> <div class=md-nav__source> <a href="https://github.com/nlohmann/json" title="Go to repository" class="md-source" data-md-component="source"> <div class="md-source__icon md-icon"> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 512 512"><!-- Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2025 Fonticons, Inc.--><path d="M173.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6m-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3m44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9M252.8 8C114.1 8 8 113.3 8 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C436.2 457.8 504 362.9 504 252 504 113.3 391.5 8 252.8 8M105.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1m-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7m32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1m-11.4-14.7c-1.6 1-1.6 3.6 0 5.9s4.3 3.3 5.6 2.3c1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2"/></svg> </div> <div class=md-source__repository> nlohmann/json </div> </a> </div> <ul class=md-nav__list data-md-scrollfix> <li class="md-nav__item md-nav__item--active md-nav__item--section md-nav__item--nested"> <input class="md-nav__toggle md-toggle " type=checkbox id=__nav_1 checked> <div class="md-nav__link md-nav__container"> <a href=../../.. class="md-nav__link "> <span class=md-ellipsis> Home </span> </a> <label class="md-nav__link " for=__nav_1 id=__nav_1_label tabindex> <span class="md-nav__icon md-icon"></span> </label> </div> <nav class=md-nav data-md-level=1 aria-labelledby=__nav_1_label aria-expanded=true> <label class=md-nav__title for=__nav_1> <span class="md-nav__icon md-icon"></span> Home </label> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=../../license/ class=md-nav__link> <span class=md-ellipsis> License </span> </a> </li> <li class=md-nav__item> <a href=../../faq/ class=md-nav__link> <span class=md-ellipsis> FAQ </span> </a> </li> <li class=md-nav__item> <a href=../../exceptions/ class=md-nav__link> <span class=md-ellipsis> Exceptions </span> </a> </li> <li class="md-nav__item md-nav__item--nested"> <input class="md-nav__toggle md-toggle " type=checkbox id=__nav_1_5> <div class="md-nav__link md-nav__container"> <a href=../../releases/ class="md-nav__link "> <span class=md-ellipsis> Releases </span> </a> <label class="md-nav__link " for=__nav_1_5 id=__nav_1_5_label tabindex=0> <span class="md-nav__icon md-icon"></span> </label> </div> <nav class=md-nav data-md-level=2 aria-labelledby=__nav_1_5_label aria-expanded=false> <label class=md-nav__title for=__nav_1_5> <span class="md-nav__icon md-icon"></span> Releases </label> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=../../releases/unreleased/ class=md-nav__link> <span class=md-ellipsis> Unreleased </span> </a> </li> <li class=md-nav__item> <a href=../../releases/v3.12.0/ class=md-nav__link> <span class=md-ellipsis> v3.12.0 </span> </a> </li> <li class=md-nav__item> <a href=../../releases/v3.11.3/ class=md-nav__link> <span class=md-ellipsis> v3.11.3 </span> </a> </li> <li class=md-nav__item> <a href=../../releases/v3.11.2/ class=md-nav__link> <span class=md-ellipsis> v3.11.2 </span> </a> </li> <li class=md-nav__item> <a href=../../releases/v3.11.1/ class=md-nav__link> <span class=md-ellipsis> v3.11.1 </span> </a> </li> <li class=md-nav__item> <a href=../../releases/v3.11.0/ class=md-nav__link> <span class=md-ellipsis> v3.11.0 </span> </a> </li> <li class=md-nav__item> <a href=../../releases/v3.10.5/ class=md-nav__link> <span class=md-ellipsis> v3.10.5 </span> </a> </li> <li class=md-nav__item> <a href=../../releases/v3.10.4/ class=md-nav__link> <span class=md-ellipsis> v3.10.4 </span> </a> </li> <li class=md-nav__item> <a href=../../releases/v3.10.3/ class=md-nav__link> <span class=md-ellipsis> v3.10.3 </span> </a> </li> <li class=md-nav__item> <a href=../../releases/v3.10.2/ class=md-nav__link> <span class=md-ellipsis> v3.10.2 </span> </a> </li> <li class=md-nav__item> <a href=../../releases/v3.10.1/ class=md-nav__link> <span class=md-ellipsis> v3.10.1 </span> </a> </li> <li class=md-nav__item> <a href=../../releases/v3.10.0/ class=md-nav__link> <span class=md-ellipsis> v3.10.0 </span> </a> </li> <li class=md-nav__item> <a href=../../releases/v3.9.1/ class=md-nav__link> <span class=md-ellipsis> v3.9.1 </span> </a> </li> <li class=md-nav__item> <a href=../../releases/v3.9.0/ class=md-nav__link> <span class=md-ellipsis> v3.9.0 </span> </a> </li> <li class=md-nav__item> <a href=../../releases/v3.8.0/ class=md-nav__link> <span class=md-ellipsis> v3.8.0 </span> </a> </li> <li class=md-nav__item> <a href=../../releases/v3.7.3/ class=md-nav__link> <span class=md-ellipsis> v3.7.3 </span> </a> </li> <li class=md-nav__item> <a href=../../releases/v3.7.2/ class=md-nav__link> <span class=md-ellipsis> v3.7.2 </span> </a> </li> <li class=md-nav__item> <a href=../../releases/v3.7.1/ class=md-nav__link> <span class=md-ellipsis> v3.7.1 </span> </a> </li> <li class=md-nav__item> <a href=../../releases/v3.7.0/ class=md-nav__link> <span class=md-ellipsis> v3.7.0 </span> </a> </li> <li class=md-nav__item> <a href=../../releases/v3.6.1/ class=md-nav__link> <span class=md-ellipsis> v3.6.1 </span> </a> </li> <li class=md-nav__item> <a href=../../releases/v3.6.0/ class=md-nav__link> <span class=md-ellipsis> v3.6.0 </span> </a> </li> <li class=md-nav__item> <a href=../../releases/v3.5.0/ class=md-nav__link> <span class=md-ellipsis> v3.5.0 </span> </a> </li> <li class=md-nav__item> <a href=../../releases/v3.4.0/ class=md-nav__link> <span class=md-ellipsis> v3.4.0 </span> </a> </li> <li class=md-nav__item> <a href=../../releases/v3.3.0/ class=md-nav__link> <span class=md-ellipsis> v3.3.0 </span> </a> </li> <li class=md-nav__item> <a href=../../releases/v3.2.0/ class=md-nav__link> <span class=md-ellipsis> v3.2.0 </span> </a> </li> <li class=md-nav__item> <a href=../../releases/v3.1.2/ class=md-nav__link> <span class=md-ellipsis> v3.1.2 </span> </a> </li> <li class=md-nav__item> <a href=../../releases/v3.1.1/ class=md-nav__link> <span class=md-ellipsis> v3.1.1 </span> </a> </li> <li class=md-nav__item> <a href=../../releases/v3.1.0/ class=md-nav__link> <span class=md-ellipsis> v3.1.0 </span> </a> </li> <li class=md-nav__item> <a href=../../releases/v3.0.1/ class=md-nav__link> <span class=md-ellipsis> v3.0.1 </span> </a> </li> <li class=md-nav__item> <a href=../../releases/v3.0.0/ class=md-nav__link> <span class=md-ellipsis> v3.0.0 </span> </a> </li> <li class=md-nav__item> <a href=../../releases/v2.1.1/ class=md-nav__link> <span class=md-ellipsis> v2.1.1 </span> </a> </li> <li class=md-nav__item> <a href=../../releases/v2.1.0/ class=md-nav__link> <span class=md-ellipsis> v2.1.0 </span> </a> </li> <li class=md-nav__item> <a href=../../releases/v2.0.10/ class=md-nav__link> <span class=md-ellipsis> v2.0.10 </span> </a> </li> <li class=md-nav__item> <a href=../../releases/v2.0.9/ class=md-nav__link> <span class=md-ellipsis> v2.0.9 </span> </a> </li> <li class=md-nav__item> <a href=../../releases/v2.0.8/ class=md-nav__link> <span class=md-ellipsis> v2.0.8 </span> </a> </li> <li class=md-nav__item> <a href=../../releases/v2.0.7/ class=md-nav__link> <span class=md-ellipsis> v2.0.7 </span> </a> </li> <li class=md-nav__item> <a href=../../releases/v2.0.6/ class=md-nav__link> <span class=md-ellipsis> v2.0.6 </span> </a> </li> <li class=md-nav__item> <a href=../../releases/v2.0.5/ class=md-nav__link> <span class=md-ellipsis> v2.0.5 </span> </a> </li> <li class=md-nav__item> <a href=../../releases/v2.0.4/ class=md-nav__link> <span class=md-ellipsis> v2.0.4 </span> </a> </li> <li class=md-nav__item> <a href=../../releases/v2.0.3/ class=md-nav__link> <span class=md-ellipsis> v2.0.3 </span> </a> </li> <li class=md-nav__item> <a href=../../releases/v2.0.2/ class=md-nav__link> <span class=md-ellipsis> v2.0.2 </span> </a> </li> <li class=md-nav__item> <a href=../../releases/v2.0.1/ class=md-nav__link> <span class=md-ellipsis> v2.0.1 </span> </a> </li> <li class=md-nav__item> <a href=../../releases/v2.0.0/ class=md-nav__link> <span class=md-ellipsis> v2.0.0 </span> </a> </li> <li class=md-nav__item> <a href=../../releases/v1.1.0/ class=md-nav__link> <span class=md-ellipsis> v1.1.0 </span> </a> </li> <li class=md-nav__item> <a href=../../releases/v1.0.0/ class=md-nav__link> <span class=md-ellipsis> v1.0.0 </span> </a> </li> </ul> </nav> </li> <li class="md-nav__item md-nav__item--active md-nav__item--nested"> <input class="md-nav__toggle md-toggle " type=checkbox id=__nav_1_6 checked> <label class=md-nav__link for=__nav_1_6 id=__nav_1_6_label tabindex=0> <span class=md-ellipsis> Blog </span> <span class="md-nav__icon md-icon"></span> </label> <nav class=md-nav data-md-level=2 aria-labelledby=__nav_1_6_label aria-expanded=true> <label class=md-nav__title for=__nav_1_6> <span class="md-nav__icon md-icon"></span> Blog </label> <ul class=md-nav__list data-md-scrollfix> <li class="md-nav__item md-nav__item--active"> <input class="md-nav__toggle md-toggle" type=checkbox id=__toc> <label class="md-nav__link md-nav__link--active" for=__toc> <span class=md-ellipsis> How 3.13.0 got faster </span> <span class="md-nav__icon md-icon"></span> </label> <a href=./ class="md-nav__link md-nav__link--active"> <span class=md-ellipsis> How 3.13.0 got faster </span> </a> <nav class="md-nav md-nav--secondary" aria-label="Table of contents"> <label class=md-nav__title for=__toc> <span class="md-nav__icon md-icon"></span> Table of contents </label> <ul class=md-nav__list data-md-component=toc data-md-scrollfix> <li class=md-nav__item> <a href=#the-short-version class=md-nav__link> <span class=md-ellipsis> The short version </span> </a> </li> <li class=md-nav__item> <a href=#where-the-time-went-a-timeline class=md-nav__link> <span class=md-ellipsis> Where the time went: a timeline </span> </a> </li> <li class=md-nav__item> <a href=#theme-1 class=md-nav__link> <span class=md-ellipsis> 1 Specialize for each input source </span> </a> <nav class=md-nav aria-label="1 Specialize for each input source"> <ul class=md-nav__list> <li class=md-nav__item> <a href=#detecting-the-input-in-c11 class=md-nav__link> <span class=md-ellipsis> Detecting the input in C++11 </span> </a> </li> <li class=md-nav__item> <a href=#contiguous-input class=md-nav__link> <span class=md-ellipsis> Contiguous input </span> </a> </li> <li class=md-nav__item> <a href=#streams class=md-nav__link> <span class=md-ellipsis> Streams </span> </a> </li> <li class=md-nav__item> <a href=#file class=md-nav__link> <span class=md-ellipsis> FILE* </span> </a> </li> </ul> </nav> </li> <li class=md-nav__item> <a href=#theme-2 class=md-nav__link> <span class=md-ellipsis> 2 Work on words, not bytes </span> </a> <nav class=md-nav aria-label="2 Work on words, not bytes"> <ul class=md-nav__list> <li class=md-nav__item> <a href=#eight-bytes-in-a-word class=md-nav__link> <span class=md-ellipsis> Eight bytes in a word </span> </a> </li> <li class=md-nav__item> <a href=#16-bytes-with-sse2-and-neon class=md-nav__link> <span class=md-ellipsis> 16 bytes with SSE2 and NEON </span> </a> </li> <li class=md-nav__item> <a href=#validating-utf-8-16-bytes-at-a-time class=md-nav__link> <span class=md-ellipsis> Validating UTF-8 16 bytes at a time </span> </a> </li> <li class=md-nav__item> <a href=#short-strings class=md-nav__link> <span class=md-ellipsis> Short strings </span> </a> </li> <li class=md-nav__item> <a href=#escapes-from-a-table class=md-nav__link> <span class=md-ellipsis> Escapes from a table </span> </a> </li> </ul> </nav> </li> <li class=md-nav__item> <a href=#theme-3 class=md-nav__link> <span class=md-ellipsis> 3 Own the number conversions </span> </a> <nav class=md-nav aria-label="3 Own the number conversions"> <ul class=md-nav__list> <li class=md-nav__item> <a href=#eight-digits-at-a-time class=md-nav__link> <span class=md-ellipsis> Eight digits at a time </span> </a> </li> <li class=md-nav__item> <a href=#clingers-fast-path class=md-nav__link> <span class=md-ellipsis> Clinger's fast path </span> </a> </li> <li class=md-nav__item> <a href=#eisel-lemire class=md-nav__link> <span class=md-ellipsis> Eisel-Lemire </span> </a> </li> <li class=md-nav__item> <a href=#writing-zmij class=md-nav__link> <span class=md-ellipsis> Writing: Żmij </span> </a> </li> </ul> </nav> </li> <li class=md-nav__item> <a href=#theme-4 class=md-nav__link> <span class=md-ellipsis> 4 Don't do unnecessary work </span> </a> <nav class=md-nav aria-label="4 Don't do unnecessary work"> <ul class=md-nav__list> <li class=md-nav__item> <a href=#the-token-buffer class=md-nav__link> <span class=md-ellipsis> The token buffer </span> </a> </li> <li class=md-nav__item> <a href=#positions-only-on-error class=md-nav__link> <span class=md-ellipsis> Positions only on error </span> </a> </li> <li class=md-nav__item> <a href=#the-text-of-float-tokens class=md-nav__link> <span class=md-ellipsis> The text of float tokens </span> </a> </li> <li class=md-nav__item> <a href=#a-copy-that-should-have-been-a-move class=md-nav__link> <span class=md-ellipsis> A copy that should have been a move </span> </a> </li> <li class=md-nav__item> <a href=#ordered_json-growth class=md-nav__link> <span class=md-ellipsis> ordered_json growth </span> </a> </li> <li class=md-nav__item> <a href=#containers-built-one-element-at-a-time class=md-nav__link> <span class=md-ellipsis> Containers built one element at a time </span> </a> </li> <li class=md-nav__item> <a href=#smaller-ones class=md-nav__link> <span class=md-ellipsis> Smaller ones </span> </a> </li> </ul> </nav> </li> <li class=md-nav__item> <a href=#theme-5 class=md-nav__link> <span class=md-ellipsis> 5 Read the assembly </span> </a> <nav class=md-nav aria-label="5 Read the assembly"> <ul class=md-nav__list> <li class=md-nav__item> <a href=#a-stack-canary-on-every-token class=md-nav__link> <span class=md-ellipsis> A stack canary on every token </span> </a> </li> <li class=md-nav__item> <a href=#exceptions-that-block-inlining class=md-nav__link> <span class=md-ellipsis> Exceptions that block inlining </span> </a> </li> <li class=md-nav__item> <a href=#aliasing class=md-nav__link> <span class=md-ellipsis> Aliasing </span> </a> </li> <li class=md-nav__item> <a href=#loop-shape-beats-branch-count class=md-nav__link> <span class=md-ellipsis> Loop shape beats branch count </span> </a> </li> <li class=md-nav__item> <a href=#inlining-that-disappears class=md-nav__link> <span class=md-ellipsis> Inlining that disappears </span> </a> </li> <li class=md-nav__item> <a href=#branches-the-compiler-chose class=md-nav__link> <span class=md-ellipsis> Branches the compiler chose </span> </a> </li> <li class=md-nav__item> <a href=#code-size-as-a-cost class=md-nav__link> <span class=md-ellipsis> Code size as a cost </span> </a> </li> </ul> </nav> </li> <li class=md-nav__item> <a href=#theme-6 class=md-nav__link> <span class=md-ellipsis> 6 Write through a cursor </span> </a> <nav class=md-nav aria-label="6 Write through a cursor"> <ul class=md-nav__list> <li class=md-nav__item> <a href=#a-buffer-in-the-serializer class=md-nav__link> <span class=md-ellipsis> A buffer in the serializer </span> </a> </li> <li class=md-nav__item> <a href=#no-allocation-per-call class=md-nav__link> <span class=md-ellipsis> No allocation per call </span> </a> </li> <li class=md-nav__item> <a href=#a-concrete-sink-for-the-binary-writers class=md-nav__link> <span class=md-ellipsis> A concrete sink for the binary writers </span> </a> </li> <li class=md-nav__item> <a href=#a-cursor-instead-of-vectorinsert class=md-nav__link> <span class=md-ellipsis> A cursor instead of vector::insert() </span> </a> </li> <li class=md-nav__item> <a href=#integers-without-branches class=md-nav__link> <span class=md-ellipsis> Integers without branches </span> </a> </li> </ul> </nav> </li> <li class=md-nav__item> <a href=#theme-7 class=md-nav__link> <span class=md-ellipsis> 7 Fix the algorithm first </span> </a> <nav class=md-nav aria-label="7 Fix the algorithm first"> <ul class=md-nav__list> <li class=md-nav__item> <a href=#comparing-in-one-pass class=md-nav__link> <span class=md-ellipsis> Comparing in one pass </span> </a> </li> <li class=md-nav__item> <a href=#bounded-recursion class=md-nav__link> <span class=md-ellipsis> Bounded recursion </span> </a> </li> <li class=md-nav__item> <a href=#destroying-without-a-stack class=md-nav__link> <span class=md-ellipsis> Destroying without a stack </span> </a> </li> </ul> </nav> </li> <li class=md-nav__item> <a href=#theme-8 class=md-nav__link> <span class=md-ellipsis> 8 Build a different data structure </span> </a> <nav class=md-nav aria-label="8 Build a different data structure"> <ul class=md-nav__list> <li class=md-nav__item> <a href=#one-flat-index class=md-nav__link> <span class=md-ellipsis> One flat index </span> </a> </li> <li class=md-nav__item> <a href=#it-can-be-edited-too class=md-nav__link> <span class=md-ellipsis> It can be edited, too </span> </a> </li> </ul> </nav> </li> <li class=md-nav__item> <a href=#how-it-compares class=md-nav__link> <span class=md-ellipsis> How it compares </span> </a> <nav class=md-nav aria-label="How it compares"> <ul class=md-nav__list> <li class=md-nav__item> <a href=#six-use-cases class=md-nav__link> <span class=md-ellipsis> Six use cases </span> </a> </li> <li class=md-nav__item> <a href=#where-the-input-comes-from class=md-nav__link> <span class=md-ellipsis> Where the input comes from </span> </a> </li> <li class=md-nav__item> <a href=#checking-less-on-purpose class=md-nav__link> <span class=md-ellipsis> Checking less, on purpose </span> </a> </li> <li class=md-nav__item> <a href=#results-on-the-mac class=md-nav__link> <span class=md-ellipsis> Results on the Mac </span> </a> </li> <li class=md-nav__item> <a href=#reading-into-structs class=md-nav__link> <span class=md-ellipsis> Reading into structs </span> </a> </li> <li class=md-nav__item> <a href=#nlohmannjson-without-json_document class=md-nav__link> <span class=md-ellipsis> nlohmann/json without json_document </span> </a> </li> <li class=md-nav__item> <a href=#results-on-x86-64 class=md-nav__link> <span class=md-ellipsis> Results on x86-64 </span> </a> </li> <li class=md-nav__item> <a href=#files-and-checks-we-didnt-choose class=md-nav__link> <span class=md-ellipsis> Files and checks we didn't choose </span> </a> </li> </ul> </nav> </li> <li class=md-nav__item> <a href=#what-didnt-work class=md-nav__link> <span class=md-ellipsis> What didn't work </span> </a> </li> <li class=md-nav__item> <a href=#the-price class=md-nav__link> <span class=md-ellipsis> The price </span> </a> </li> <li class=md-nav__item> <a href=#summing-up class=md-nav__link> <span class=md-ellipsis> Summing up </span> </a> </li> <li class=md-nav__item> <a href=#thanks class=md-nav__link> <span class=md-ellipsis> Thanks </span> </a> </li> <li class=md-nav__item> <a href=#appendix class=md-nav__link> <span class=md-ellipsis> Appendix </span> </a> <nav class=md-nav aria-label=Appendix> <ul class=md-nav__list> <li class=md-nav__item> <a href=#a-test-files class=md-nav__link> <span class=md-ellipsis> A. Test files </span> </a> </li> <li class=md-nav__item> <a href=#b-3120-against-3130 class=md-nav__link> <span class=md-ellipsis> B. 3.12.0 against 3.13.0 </span> </a> </li> <li class=md-nav__item> <a href=#c-the-timeline class=md-nav__link> <span class=md-ellipsis> C. The timeline </span> </a> </li> <li class=md-nav__item> <a href=#d-algorithmic-fixes class=md-nav__link> <span class=md-ellipsis> D. Algorithmic fixes </span> </a> </li> <li class=md-nav__item> <a href=#e-comparison-with-other-libraries class=md-nav__link> <span class=md-ellipsis> E. Comparison with other libraries </span> </a> </li> <li class=md-nav__item> <a href=#f-behavior-changes class=md-nav__link> <span class=md-ellipsis> F. Behavior changes </span> </a> </li> <li class=md-nav__item> <a href=#g-how-we-measured class=md-nav__link> <span class=md-ellipsis> G. How we measured </span> </a> </li> <li class=md-nav__item> <a href=#h-pull-requests-by-theme class=md-nav__link> <span class=md-ellipsis> H. Pull requests by theme </span> </a> </li> <li class=md-nav__item> <a href=#i-details-of-the-themes class=md-nav__link> <span class=md-ellipsis> I. Details of the themes </span> </a> </li> <li class=md-nav__item> <a href=#j-validation class=md-nav__link> <span class=md-ellipsis> J. Validation </span> </a> </li> </ul> </nav> </li> </ul> </nav> </li> </ul> </nav> </li> <li class=md-nav__item> <a href=../../design_goals/ class=md-nav__link> <span class=md-ellipsis> Design goals </span> </a> </li> <li class=md-nav__item> <a href=../../architecture/ class=md-nav__link> <span class=md-ellipsis> Architecture </span> </a> </li> <li class=md-nav__item> <a href=../../customers/ class=md-nav__link> <span class=md-ellipsis> Customers </span> </a> </li> <li class=md-nav__item> <a href=../../sponsors/ class=md-nav__link> <span class=md-ellipsis> Sponsors </span> </a> </li> <li class=md-nav__item> <a href=../../debugging/ class=md-nav__link> <span class=md-ellipsis> Debugging </span> </a> </li> </ul> </nav> </li> <li class="md-nav__item md-nav__item--nested"> <input class="md-nav__toggle md-toggle " type=checkbox id=__nav_2> <div class="md-nav__link md-nav__container"> <a href=../../../features/ class="md-nav__link "> <span class=md-ellipsis> Features </span> </a> <label class="md-nav__link " for=__nav_2 id=__nav_2_label tabindex=0> <span class="md-nav__icon md-icon"></span> </label> </div> <nav class=md-nav data-md-level=1 aria-labelledby=__nav_2_label aria-expanded=false> <label class=md-nav__title for=__nav_2> <span class="md-nav__icon md-icon"></span> Features </label> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=../../../features/arbitrary_types/ class=md-nav__link> <span class=md-ellipsis> Arbitrary Type Conversions </span> </a> </li> <li class=md-nav__item> <a href=../../../features/type_recipes/ class=md-nav__link> <span class=md-ellipsis> Recipes for Common Types </span> </a> </li> <li class="md-nav__item md-nav__item--nested"> <input class="md-nav__toggle md-toggle " type=checkbox id=__nav_2_4> <div class="md-nav__link md-nav__container"> <a href=../../../features/binary_formats/ class="md-nav__link "> <span class=md-ellipsis> Binary Formats </span> </a> <label class="md-nav__link " for=__nav_2_4 id=__nav_2_4_label tabindex=0> <span class="md-nav__icon md-icon"></span> </label> </div> <nav class=md-nav data-md-level=2 aria-labelledby=__nav_2_4_label aria-expanded=false> <label class=md-nav__title for=__nav_2_4> <span class="md-nav__icon md-icon"></span> Binary Formats </label> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=../../../features/binary_formats/bjdata/ class=md-nav__link> <span class=md-ellipsis> BJData </span> </a> </li> <li class=md-nav__item> <a href=../../../features/binary_formats/bon8/ class=md-nav__link> <span class=md-ellipsis> BON8 </span> </a> </li> <li class=md-nav__item> <a href=../../../features/binary_formats/bson/ class=md-nav__link> <span class=md-ellipsis> BSON </span> </a> </li> <li class=md-nav__item> <a href=../../../features/binary_formats/cbor/ class=md-nav__link> <span class=md-ellipsis> CBOR </span> </a> </li> <li class=md-nav__item> <a href=../../../features/binary_formats/messagepack/ class=md-nav__link> <span class=md-ellipsis> MessagePack </span> </a> </li> <li class=md-nav__item> <a href=../../../features/binary_formats/ubjson/ class=md-nav__link> <span class=md-ellipsis> UBJSON </span> </a> </li> </ul> </nav> </li> <li class=md-nav__item> <a href=../../../features/binary_values/ class=md-nav__link> <span class=md-ellipsis> Binary Values </span> </a> </li> <li class=md-nav__item> <a href=../../../features/comments/ class=md-nav__link> <span class=md-ellipsis> Comments </span> </a> </li> <li class=md-nav__item> <a href=../../../features/conversions/ class=md-nav__link> <span class=md-ellipsis> Converting values </span> </a> </li> <li class=md-nav__item> <a href=../../../features/creating_values/ class=md-nav__link> <span class=md-ellipsis> Creating JSON values </span> </a> </li> <li class="md-nav__item md-nav__item--nested"> <input class="md-nav__toggle md-toggle " type=checkbox id=__nav_2_9> <div class="md-nav__link md-nav__container"> <a href=../../../features/element_access/ class="md-nav__link "> <span class=md-ellipsis> Element Access </span> </a> <label class="md-nav__link " for=__nav_2_9 id=__nav_2_9_label tabindex=0> <span class="md-nav__icon md-icon"></span> </label> </div> <nav class=md-nav data-md-level=2 aria-labelledby=__nav_2_9_label aria-expanded=false> <label class=md-nav__title for=__nav_2_9> <span class="md-nav__icon md-icon"></span> Element Access </label> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=../../../features/element_access/unchecked_access/ class=md-nav__link> <span class=md-ellipsis> Unchecked access: operator[] </span> </a> </li> <li class=md-nav__item> <a href=../../../features/element_access/checked_access/ class=md-nav__link> <span class=md-ellipsis> Checked access: at </span> </a> </li> <li class=md-nav__item> <a href=../../../features/element_access/default_value/ class=md-nav__link> <span class=md-ellipsis> Access with default value: value </span> </a> </li> </ul> </nav> </li> <li class=md-nav__item> <a href=../../../features/files/ class=md-nav__link> <span class=md-ellipsis> Reading and writing files </span> </a> </li> <li class=md-nav__item> <a href=../../../features/iterators/ class=md-nav__link> <span class=md-ellipsis> Iterators </span> </a> </li> <li class=md-nav__item> <a href=../../../features/merge_patch/ class=md-nav__link> <span class=md-ellipsis> JSON Merge Patch </span> </a> </li> <li class=md-nav__item> <a href=../../../features/json_patch/ class=md-nav__link> <span class=md-ellipsis> JSON Patch and Diff </span> </a> </li> <li class=md-nav__item> <a href=../../../features/json_pointer/ class=md-nav__link> <span class=md-ellipsis> JSON Pointer </span> </a> </li> <li class=md-nav__item> <a href=../../../features/modifying_values/ class=md-nav__link> <span class=md-ellipsis> Modifying values </span> </a> </li> <li class=md-nav__item> <a href=../../../features/modules/ class=md-nav__link> <span class=md-ellipsis> Modules </span> </a> </li> <li class=md-nav__item> <a href=../../../features/namespace/ class=md-nav__link> <span class=md-ellipsis> nlohmann Namespace </span> </a> </li> <li class=md-nav__item> <a href=../../../features/no_exceptions/ class=md-nav__link> <span class=md-ellipsis> Working Without Exceptions </span> </a> </li> <li class=md-nav__item> <a href=../../../features/object_order/ class=md-nav__link> <span class=md-ellipsis> Object Order </span> </a> </li> <li class=md-nav__item> <a href=../../../features/performance/ class=md-nav__link> <span class=md-ellipsis> Performance </span> </a> </li> <li class="md-nav__item md-nav__item--nested"> <input class="md-nav__toggle md-toggle " type=checkbox id=__nav_2_21> <div class="md-nav__link md-nav__container"> <a href=../../../features/parsing/ class="md-nav__link "> <span class=md-ellipsis> Parsing </span> </a> <label class="md-nav__link " for=__nav_2_21 id=__nav_2_21_label tabindex=0> <span class="md-nav__icon md-icon"></span> </label> </div> <nav class=md-nav data-md-level=2 aria-labelledby=__nav_2_21_label aria-expanded=false> <label class=md-nav__title for=__nav_2_21> <span class="md-nav__icon md-icon"></span> Parsing </label> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=../../../features/parsing/json_lines/ class=md-nav__link> <span class=md-ellipsis> JSON Lines </span> </a> </li> <li class=md-nav__item> <a href=../../../features/parsing/large_and_partial_input/ class=md-nav__link> <span class=md-ellipsis> Large, Streamed, and Partial Input </span> </a> </li> <li class=md-nav__item> <a href=../../../features/parsing/parse_exceptions/ class=md-nav__link> <span class=md-ellipsis> Parsing and Exceptions </span> </a> </li> <li class=md-nav__item> <a href=../../../features/parsing/parser_callbacks/ class=md-nav__link> <span class=md-ellipsis> Parser Callbacks </span> </a> </li> <li class=md-nav__item> <a href=../../../features/parsing/sax_interface/ class=md-nav__link> <span class=md-ellipsis> SAX Interface </span> </a> </li> <li class=md-nav__item> <a href=../../../features/parsing/untrusted_input/ class=md-nav__link> <span class=md-ellipsis> Parsing Untrusted Input </span> </a> </li> </ul> </nav> </li> <li class=md-nav__item> <a href=../../../features/assertions/ class=md-nav__link> <span class=md-ellipsis> Runtime Assertions </span> </a> </li> <li class=md-nav__item> <a href=../../../features/serialization/ class=md-nav__link> <span class=md-ellipsis> Serialization </span> </a> </li> <li class=md-nav__item> <a href=../../../features/enum_conversion/ class=md-nav__link> <span class=md-ellipsis> Specializing enum conversion </span> </a> </li> <li class=md-nav__item> <a href=../../../features/macros/ class=md-nav__link> <span class=md-ellipsis> Supported Macros </span> </a> </li> <li class=md-nav__item> <a href=../../../features/trailing_commas/ class=md-nav__link> <span class=md-ellipsis> Trailing Commas </span> </a> </li> <li class="md-nav__item md-nav__item--nested"> <input class="md-nav__toggle md-toggle " type=checkbox id=__nav_2_27> <div class="md-nav__link md-nav__container"> <a href=../../../features/types/ class="md-nav__link "> <span class=md-ellipsis> Types </span> </a> <label class="md-nav__link " for=__nav_2_27 id=__nav_2_27_label tabindex=0> <span class="md-nav__icon md-icon"></span> </label> </div> <nav class=md-nav data-md-level=2 aria-labelledby=__nav_2_27_label aria-expanded=false> <label class=md-nav__title for=__nav_2_27> <span class="md-nav__icon md-icon"></span> Types </label> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=../../../features/types/number_handling/ class=md-nav__link> <span class=md-ellipsis> Number Handling </span> </a> </li> <li class=md-nav__item> <a href=../../../features/types/template_parameters/ class=md-nav__link> <span class=md-ellipsis> Template Parameter Requirements </span> </a> </li> </ul> </nav> </li> <li class="md-nav__item md-nav__item--nested"> <input class="md-nav__toggle md-toggle " type=checkbox id=__nav_2_28> <div class="md-nav__link md-nav__container"> <a href=../../../features/json_view/ class="md-nav__link "> <span class=md-ellipsis> Zero-copy views </span> </a> <label class="md-nav__link " for=__nav_2_28 id=__nav_2_28_label tabindex=0> <span class="md-nav__icon md-icon"></span> </label> </div> <nav class=md-nav data-md-level=2 aria-labelledby=__nav_2_28_label aria-expanded=false> <label class=md-nav__title for=__nav_2_28> <span class="md-nav__icon md-icon"></span> Zero-copy views </label> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=../../../features/json_view/lifetime/ class=md-nav__link> <span class=md-ellipsis> Ownership and lifetime </span> </a> </li> <li class=md-nav__item> <a href=../../../features/json_view/differences/ class=md-nav__link> <span class=md-ellipsis> Differences from basic_json </span> </a> </li> <li class=md-nav__item> <a href=../../../features/json_view/reading/ class=md-nav__link> <span class=md-ellipsis> Reading values </span> </a> </li> <li class=md-nav__item> <a href=../../../features/json_view/generic_code/ class=md-nav__link> <span class=md-ellipsis> Writing generic code </span> </a> </li> <li class=md-nav__item> <a href=../../../features/json_view/editing/ class=md-nav__link> <span class=md-ellipsis> Editing a document </span> </a> </li> <li class=md-nav__item> <a href=../../../features/json_view/images/ class=md-nav__link> <span class=md-ellipsis> Images </span> </a> </li> </ul> </nav> </li> </ul> </nav> </li> <li class="md-nav__item md-nav__item--nested"> <input class="md-nav__toggle md-toggle " type=checkbox id=__nav_3> <div class="md-nav__link md-nav__container"> <a href=../../../integration/ class="md-nav__link "> <span class=md-ellipsis> Integration </span> </a> <label class="md-nav__link " for=__nav_3 id=__nav_3_label tabindex=0> <span class="md-nav__icon md-icon"></span> </label> </div> <nav class=md-nav data-md-level=1 aria-labelledby=__nav_3_label aria-expanded=false> <label class=md-nav__title for=__nav_3> <span class="md-nav__icon md-icon"></span> Integration </label> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=../../../integration/migration_guide/ class=md-nav__link> <span class=md-ellipsis> Migration Guide </span> </a> </li> <li class=md-nav__item> <a href=../../../integration/cmake/ class=md-nav__link> <span class=md-ellipsis> CMake </span> </a> </li> <li class=md-nav__item> <a href=../../../integration/package_managers/ class=md-nav__link> <span class=md-ellipsis> Package Managers </span> </a> </li> <li class=md-nav__item> <a href=../../../integration/pkg-config/ class=md-nav__link> <span class=md-ellipsis> Pkg-config </span> </a> </li> <li class=md-nav__item> <a href=../../../integration/compile_times/ class=md-nav__link> <span class=md-ellipsis> Compile times </span> </a> </li> </ul> </nav> </li> <li class="md-nav__item md-nav__item--nested"> <input class="md-nav__toggle md-toggle " type=checkbox id=__nav_4> <label class=md-nav__link for=__nav_4 id=__nav_4_label tabindex=0> <span class=md-ellipsis> API Documentation </span> <span class="md-nav__icon md-icon"></span> </label> <nav class=md-nav data-md-level=1 aria-labelledby=__nav_4_label aria-expanded=false> <label class=md-nav__title for=__nav_4> <span class="md-nav__icon md-icon"></span> API Documentation </label> <ul class=md-nav__list data-md-scrollfix> <li class="md-nav__item md-nav__item--nested"> <input class="md-nav__toggle md-toggle " type=checkbox id=__nav_4_1> <div class="md-nav__link md-nav__container"> <a href=../../../api/basic_json/ class="md-nav__link "> <span class=md-ellipsis> basic_json </span> </a> <label class="md-nav__link " for=__nav_4_1 id=__nav_4_1_label tabindex=0> <span class="md-nav__icon md-icon"></span> </label> </div> <nav class=md-nav data-md-level=2 aria-labelledby=__nav_4_1_label aria-expanded=false> <label class=md-nav__title for=__nav_4_1> <span class="md-nav__icon md-icon"></span> basic_json </label> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=../../../api/basic_json/basic_json/ class=md-nav__link> <span class=md-ellipsis> (Constructor) </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/~basic_json/ class=md-nav__link> <span class=md-ellipsis> (Destructor) </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/accept/ class=md-nav__link> <span class=md-ellipsis> accept </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/array/ class=md-nav__link> <span class=md-ellipsis> array </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/array_t/ class=md-nav__link> <span class=md-ellipsis> array_t </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/as_base_class/ class=md-nav__link> <span class=md-ellipsis> as_base_class </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/at/ class=md-nav__link> <span class=md-ellipsis> at </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/back/ class=md-nav__link> <span class=md-ellipsis> back </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/begin/ class=md-nav__link> <span class=md-ellipsis> begin </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/binary/ class=md-nav__link> <span class=md-ellipsis> binary </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/binary_t/ class=md-nav__link> <span class=md-ellipsis> binary_t </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/bjdata_version_t/ class=md-nav__link> <span class=md-ellipsis> bjdata_version_t </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/boolean_t/ class=md-nav__link> <span class=md-ellipsis> boolean_t </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/cbegin/ class=md-nav__link> <span class=md-ellipsis> cbegin </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/cbor_tag_handler_t/ class=md-nav__link> <span class=md-ellipsis> cbor_tag_handler_t </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/cend/ class=md-nav__link> <span class=md-ellipsis> cend </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/clear/ class=md-nav__link> <span class=md-ellipsis> clear </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/contains/ class=md-nav__link> <span class=md-ellipsis> contains </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/count/ class=md-nav__link> <span class=md-ellipsis> count </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/crbegin/ class=md-nav__link> <span class=md-ellipsis> crbegin </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/crend/ class=md-nav__link> <span class=md-ellipsis> crend </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/default_object_comparator_t/ class=md-nav__link> <span class=md-ellipsis> default_object_comparator_t </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/diff/ class=md-nav__link> <span class=md-ellipsis> diff </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/dump/ class=md-nav__link> <span class=md-ellipsis> dump </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/emplace/ class=md-nav__link> <span class=md-ellipsis> emplace </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/emplace_back/ class=md-nav__link> <span class=md-ellipsis> emplace_back </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/empty/ class=md-nav__link> <span class=md-ellipsis> empty </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/end/ class=md-nav__link> <span class=md-ellipsis> end </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/end_pos/ class=md-nav__link> <span class=md-ellipsis> end_pos </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/erase/ class=md-nav__link> <span class=md-ellipsis> erase </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/error_handler_t/ class=md-nav__link> <span class=md-ellipsis> error_handler_t </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/exception/ class=md-nav__link> <span class=md-ellipsis> exception </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/find/ class=md-nav__link> <span class=md-ellipsis> find </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/flatten/ class=md-nav__link> <span class=md-ellipsis> flatten </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/format_as/ class=md-nav__link> <span class=md-ellipsis> format_as </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/from_bjdata/ class=md-nav__link> <span class=md-ellipsis> from_bjdata </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/from_bon8/ class=md-nav__link> <span class=md-ellipsis> from_bon8 </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/from_bson/ class=md-nav__link> <span class=md-ellipsis> from_bson </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/from_cbor/ class=md-nav__link> <span class=md-ellipsis> from_cbor </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/from_msgpack/ class=md-nav__link> <span class=md-ellipsis> from_msgpack </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/from_ubjson/ class=md-nav__link> <span class=md-ellipsis> from_ubjson </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/front/ class=md-nav__link> <span class=md-ellipsis> front </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/get/ class=md-nav__link> <span class=md-ellipsis> get </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/get_allocator/ class=md-nav__link> <span class=md-ellipsis> get_allocator </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/get_binary/ class=md-nav__link> <span class=md-ellipsis> get_binary </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/get_ptr/ class=md-nav__link> <span class=md-ellipsis> get_ptr </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/get_ref/ class=md-nav__link> <span class=md-ellipsis> get_ref </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/get_to/ class=md-nav__link> <span class=md-ellipsis> get_to </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/std_formatter/ class=md-nav__link> <span class=md-ellipsis> std::formatter&lt;basic_json&gt; </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/std_hash/ class=md-nav__link> <span class=md-ellipsis> std::hash&lt;basic_json&gt; </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/input_format_t/ class=md-nav__link> <span class=md-ellipsis> input_format_t </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/insert/ class=md-nav__link> <span class=md-ellipsis> insert </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/invalid_iterator/ class=md-nav__link> <span class=md-ellipsis> invalid_iterator </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/is_array/ class=md-nav__link> <span class=md-ellipsis> is_array </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/is_binary/ class=md-nav__link> <span class=md-ellipsis> is_binary </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/is_boolean/ class=md-nav__link> <span class=md-ellipsis> is_boolean </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/is_discarded/ class=md-nav__link> <span class=md-ellipsis> is_discarded </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/is_null/ class=md-nav__link> <span class=md-ellipsis> is_null </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/is_number/ class=md-nav__link> <span class=md-ellipsis> is_number </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/is_number_float/ class=md-nav__link> <span class=md-ellipsis> is_number_float </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/is_number_integer/ class=md-nav__link> <span class=md-ellipsis> is_number_integer </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/is_number_unsigned/ class=md-nav__link> <span class=md-ellipsis> is_number_unsigned </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/is_object/ class=md-nav__link> <span class=md-ellipsis> is_object </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/is_primitive/ class=md-nav__link> <span class=md-ellipsis> is_primitive </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/is_string/ class=md-nav__link> <span class=md-ellipsis> is_string </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/is_structured/ class=md-nav__link> <span class=md-ellipsis> is_structured </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/items/ class=md-nav__link> <span class=md-ellipsis> items </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/json_base_class_t/ class=md-nav__link> <span class=md-ellipsis> json_base_class_t </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/json_serializer/ class=md-nav__link> <span class=md-ellipsis> json_serializer </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/max_size/ class=md-nav__link> <span class=md-ellipsis> max_size </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/meta/ class=md-nav__link> <span class=md-ellipsis> meta </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/merge_diff/ class=md-nav__link> <span class=md-ellipsis> merge_diff </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/merge_patch/ class=md-nav__link> <span class=md-ellipsis> merge_patch </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/number_float_t/ class=md-nav__link> <span class=md-ellipsis> number_float_t </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/number_integer_t/ class=md-nav__link> <span class=md-ellipsis> number_integer_t </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/number_unsigned_t/ class=md-nav__link> <span class=md-ellipsis> number_unsigned_t </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/object/ class=md-nav__link> <span class=md-ellipsis> object </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/object_comparator_t/ class=md-nav__link> <span class=md-ellipsis> object_comparator_t </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/object_t/ class=md-nav__link> <span class=md-ellipsis> object_t </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/operator_ValueType/ class=md-nav__link> <span class=md-ellipsis> operator ValueType </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/operator_value_t/ class=md-nav__link> <span class=md-ellipsis> operator value_t </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/operator%5B%5D/ class=md-nav__link> <span class=md-ellipsis> operator[] </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/operator%3D/ class=md-nav__link> <span class=md-ellipsis> operator= </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/operator%2B%3D/ class=md-nav__link> <span class=md-ellipsis> operator+= </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/operator_eq/ class=md-nav__link> <span class=md-ellipsis> operator== </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/operator_ne/ class=md-nav__link> <span class=md-ellipsis> operator!= </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/operator_lt/ class=md-nav__link> <span class=md-ellipsis> operator< </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/operator_gt/ class=md-nav__link> <span class=md-ellipsis> operator> </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/operator_le/ class=md-nav__link> <span class=md-ellipsis> operator<= </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/operator_ge/ class=md-nav__link> <span class=md-ellipsis> operator>= </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/operator_spaceship/ class=md-nav__link> <span class=md-ellipsis> operator<=> </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/out_of_range/ class=md-nav__link> <span class=md-ellipsis> out_of_range </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/other_error/ class=md-nav__link> <span class=md-ellipsis> other_error </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/parse/ class=md-nav__link> <span class=md-ellipsis> parse </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/parse_error/ class=md-nav__link> <span class=md-ellipsis> parse_error </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/parse_event_t/ class=md-nav__link> <span class=md-ellipsis> parse_event_t </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/parser_callback_t/ class=md-nav__link> <span class=md-ellipsis> parser_callback_t </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/patch/ class=md-nav__link> <span class=md-ellipsis> patch </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/patch_inplace/ class=md-nav__link> <span class=md-ellipsis> patch_inplace </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/push_back/ class=md-nav__link> <span class=md-ellipsis> push_back </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/rbegin/ class=md-nav__link> <span class=md-ellipsis> rbegin </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/rend/ class=md-nav__link> <span class=md-ellipsis> rend </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/sax_parse/ class=md-nav__link> <span class=md-ellipsis> sax_parse </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/size/ class=md-nav__link> <span class=md-ellipsis> size </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/start_pos/ class=md-nav__link> <span class=md-ellipsis> start_pos </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/string_t/ class=md-nav__link> <span class=md-ellipsis> string_t </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/swap/ class=md-nav__link> <span class=md-ellipsis> swap </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/std_swap/ class=md-nav__link> <span class=md-ellipsis> std::swap&lt;basic_json&gt; </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/to_bjdata/ class=md-nav__link> <span class=md-ellipsis> to_bjdata </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/to_bon8/ class=md-nav__link> <span class=md-ellipsis> to_bon8 </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/to_bson/ class=md-nav__link> <span class=md-ellipsis> to_bson </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/to_cbor/ class=md-nav__link> <span class=md-ellipsis> to_cbor </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/to_msgpack/ class=md-nav__link> <span class=md-ellipsis> to_msgpack </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/to_string/ class=md-nav__link> <span class=md-ellipsis> to_string </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/to_ubjson/ class=md-nav__link> <span class=md-ellipsis> to_ubjson </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/type/ class=md-nav__link> <span class=md-ellipsis> type </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/type_error/ class=md-nav__link> <span class=md-ellipsis> type_error </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/type_name/ class=md-nav__link> <span class=md-ellipsis> type_name </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/unflatten/ class=md-nav__link> <span class=md-ellipsis> unflatten </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/update/ class=md-nav__link> <span class=md-ellipsis> update </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/value/ class=md-nav__link> <span class=md-ellipsis> value </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/value_t/ class=md-nav__link> <span class=md-ellipsis> value_t </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json/with_t/ class=md-nav__link> <span class=md-ellipsis> with_t </span> </a> </li> </ul> </nav> </li> <li class="md-nav__item md-nav__item--nested"> <input class="md-nav__toggle md-toggle " type=checkbox id=__nav_4_2> <div class="md-nav__link md-nav__container"> <a href=../../../api/basic_json_document/ class="md-nav__link "> <span class=md-ellipsis> basic_json_document </span> </a> <label class="md-nav__link " for=__nav_4_2 id=__nav_4_2_label tabindex=0> <span class="md-nav__icon md-icon"></span> </label> </div> <nav class=md-nav data-md-level=2 aria-labelledby=__nav_4_2_label aria-expanded=false> <label class=md-nav__title for=__nav_4_2> <span class="md-nav__icon md-icon"></span> basic_json_document </label> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=../../../api/basic_json_document/basic_json_document/ class=md-nav__link> <span class=md-ellipsis> (Constructor) </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json_document/accept/ class=md-nav__link> <span class=md-ellipsis> accept </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json_document/erase/ class=md-nav__link> <span class=md-ellipsis> erase </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json_document/insert/ class=md-nav__link> <span class=md-ellipsis> insert </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json_document/is_discarded/ class=md-nav__link> <span class=md-ellipsis> is_discarded </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json_document/load/ class=md-nav__link> <span class=md-ellipsis> load </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json_document/memory_usage/ class=md-nav__link> <span class=md-ellipsis> memory_usage </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json_document/node_count/ class=md-nav__link> <span class=md-ellipsis> node_count </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json_document/owns_source/ class=md-nav__link> <span class=md-ellipsis> owns_source </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json_document/parse/ class=md-nav__link> <span class=md-ellipsis> parse </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json_document/parse_copy/ class=md-nav__link> <span class=md-ellipsis> parse_copy </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json_document/push_back/ class=md-nav__link> <span class=md-ellipsis> push_back </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json_document/read/ class=md-nav__link> <span class=md-ellipsis> read </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json_document/root/ class=md-nav__link> <span class=md-ellipsis> root </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json_document/save/ class=md-nav__link> <span class=md-ellipsis> save </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json_document/set/ class=md-nav__link> <span class=md-ellipsis> set </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json_document/shrink_to_fit/ class=md-nav__link> <span class=md-ellipsis> shrink_to_fit </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json_document/source/ class=md-nav__link> <span class=md-ellipsis> source </span> </a> </li> </ul> </nav> </li> <li class="md-nav__item md-nav__item--nested"> <input class="md-nav__toggle md-toggle " type=checkbox id=__nav_4_3> <div class="md-nav__link md-nav__container"> <a href=../../../api/basic_json_view/ class="md-nav__link "> <span class=md-ellipsis> basic_json_view </span> </a> <label class="md-nav__link " for=__nav_4_3 id=__nav_4_3_label tabindex=0> <span class="md-nav__icon md-icon"></span> </label> </div> <nav class=md-nav data-md-level=2 aria-labelledby=__nav_4_3_label aria-expanded=false> <label class=md-nav__title for=__nav_4_3> <span class="md-nav__icon md-icon"></span> basic_json_view </label> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=../../../api/basic_json_view/basic_json_view/ class=md-nav__link> <span class=md-ellipsis> (Constructor) </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json_view/at/ class=md-nav__link> <span class=md-ellipsis> at </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json_view/back/ class=md-nav__link> <span class=md-ellipsis> back </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json_view/begin/ class=md-nav__link> <span class=md-ellipsis> begin </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json_view/cbegin/ class=md-nav__link> <span class=md-ellipsis> cbegin </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json_view/cend/ class=md-nav__link> <span class=md-ellipsis> cend </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json_view/contains/ class=md-nav__link> <span class=md-ellipsis> contains </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json_view/count/ class=md-nav__link> <span class=md-ellipsis> count </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json_view/dump/ class=md-nav__link> <span class=md-ellipsis> dump </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json_view/empty/ class=md-nav__link> <span class=md-ellipsis> empty </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json_view/end/ class=md-nav__link> <span class=md-ellipsis> end </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json_view/find/ class=md-nav__link> <span class=md-ellipsis> find </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json_view/front/ class=md-nav__link> <span class=md-ellipsis> front </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json_view/get/ class=md-nav__link> <span class=md-ellipsis> get </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json_view/get_string/ class=md-nav__link> <span class=md-ellipsis> get_string </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json_view/get_to/ class=md-nav__link> <span class=md-ellipsis> get_to </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json_view/is_array/ class=md-nav__link> <span class=md-ellipsis> is_array </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json_view/is_binary/ class=md-nav__link> <span class=md-ellipsis> is_binary </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json_view/is_boolean/ class=md-nav__link> <span class=md-ellipsis> is_boolean </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json_view/is_discarded/ class=md-nav__link> <span class=md-ellipsis> is_discarded </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json_view/is_null/ class=md-nav__link> <span class=md-ellipsis> is_null </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json_view/is_number/ class=md-nav__link> <span class=md-ellipsis> is_number </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json_view/is_number_float/ class=md-nav__link> <span class=md-ellipsis> is_number_float </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json_view/is_number_integer/ class=md-nav__link> <span class=md-ellipsis> is_number_integer </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json_view/is_number_unsigned/ class=md-nav__link> <span class=md-ellipsis> is_number_unsigned </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json_view/is_object/ class=md-nav__link> <span class=md-ellipsis> is_object </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json_view/is_primitive/ class=md-nav__link> <span class=md-ellipsis> is_primitive </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json_view/is_string/ class=md-nav__link> <span class=md-ellipsis> is_string </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json_view/is_structured/ class=md-nav__link> <span class=md-ellipsis> is_structured </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json_view/items/ class=md-nav__link> <span class=md-ellipsis> items </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json_view/materialize/ class=md-nav__link> <span class=md-ellipsis> materialize </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json_view/number_format/ class=md-nav__link> <span class=md-ellipsis> number_format </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json_view/number_token/ class=md-nav__link> <span class=md-ellipsis> number_token </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json_view/operator_ltlt/ class=md-nav__link> <span class=md-ellipsis> operator<< </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json_view/operator%5B%5D/ class=md-nav__link> <span class=md-ellipsis> operator[] </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json_view/operator_eq/ class=md-nav__link> <span class=md-ellipsis> operator== </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json_view/operator_ne/ class=md-nav__link> <span class=md-ellipsis> operator!= </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json_view/size/ class=md-nav__link> <span class=md-ellipsis> size </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json_view/source_offset/ class=md-nav__link> <span class=md-ellipsis> source_offset </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json_view/type/ class=md-nav__link> <span class=md-ellipsis> type </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json_view/type_name/ class=md-nav__link> <span class=md-ellipsis> type_name </span> </a> </li> <li class=md-nav__item> <a href=../../../api/basic_json_view/value/ class=md-nav__link> <span class=md-ellipsis> value </span> </a> </li> </ul> </nav> </li> <li class="md-nav__item md-nav__item--nested"> <input class="md-nav__toggle md-toggle " type=checkbox id=__nav_4_4> <div class="md-nav__link md-nav__container"> <a href=../../../api/byte_container_with_subtype/ class="md-nav__link "> <span class=md-ellipsis> byte_container_with_subtype </span> </a> <label class="md-nav__link " for=__nav_4_4 id=__nav_4_4_label tabindex=0> <span class="md-nav__icon md-icon"></span> </label> </div> <nav class=md-nav data-md-level=2 aria-labelledby=__nav_4_4_label aria-expanded=false> <label class=md-nav__title for=__nav_4_4> <span class="md-nav__icon md-icon"></span> byte_container_with_subtype </label> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=../../../api/byte_container_with_subtype/byte_container_with_subtype/ class=md-nav__link> <span class=md-ellipsis> (constructor) </span> </a> </li> <li class=md-nav__item> <a href=../../../api/byte_container_with_subtype/clear_subtype/ class=md-nav__link> <span class=md-ellipsis> clear_subtype </span> </a> </li> <li class=md-nav__item> <a href=../../../api/byte_container_with_subtype/has_subtype/ class=md-nav__link> <span class=md-ellipsis> has_subtype </span> </a> </li> <li class=md-nav__item> <a href=../../../api/byte_container_with_subtype/operator_eq/ class=md-nav__link> <span class=md-ellipsis> operator== </span> </a> </li> <li class=md-nav__item> <a href=../../../api/byte_container_with_subtype/operator_ne/ class=md-nav__link> <span class=md-ellipsis> operator!= </span> </a> </li> <li class=md-nav__item> <a href=../../../api/byte_container_with_subtype/set_subtype/ class=md-nav__link> <span class=md-ellipsis> set_subtype </span> </a> </li> <li class=md-nav__item> <a href=../../../api/byte_container_with_subtype/subtype/ class=md-nav__link> <span class=md-ellipsis> subtype </span> </a> </li> </ul> </nav> </li> <li class="md-nav__item md-nav__item--nested"> <input class="md-nav__toggle md-toggle " type=checkbox id=__nav_4_5> <div class="md-nav__link md-nav__container"> <a href=../../../api/adl_serializer/ class="md-nav__link "> <span class=md-ellipsis> adl_serializer </span> </a> <label class="md-nav__link " for=__nav_4_5 id=__nav_4_5_label tabindex=0> <span class="md-nav__icon md-icon"></span> </label> </div> <nav class=md-nav data-md-level=2 aria-labelledby=__nav_4_5_label aria-expanded=false> <label class=md-nav__title for=__nav_4_5> <span class="md-nav__icon md-icon"></span> adl_serializer </label> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=../../../api/adl_serializer/from_json/ class=md-nav__link> <span class=md-ellipsis> from_json </span> </a> </li> <li class=md-nav__item> <a href=../../../api/adl_serializer/to_json/ class=md-nav__link> <span class=md-ellipsis> to_json </span> </a> </li> </ul> </nav> </li> <li class=md-nav__item> <a href=../../../api/is_json_view/ class=md-nav__link> <span class=md-ellipsis> is_json_view </span> </a> </li> <li class=md-nav__item> <a href=../../../api/json/ class=md-nav__link> <span class=md-ellipsis> json </span> </a> </li> <li class=md-nav__item> <a href=../../../api/json_document/ class=md-nav__link> <span class=md-ellipsis> json_document </span> </a> </li> <li class=md-nav__item> <a href=../../../api/json_editable_document/ class=md-nav__link> <span class=md-ellipsis> json_editable_document </span> </a> </li> <li class=md-nav__item> <a href=../../../api/json_editable_view/ class=md-nav__link> <span class=md-ellipsis> json_editable_view </span> </a> </li> <li class="md-nav__item md-nav__item--nested"> <input class="md-nav__toggle md-toggle " type=checkbox id=__nav_4_11> <div class="md-nav__link md-nav__container"> <a href=../../../api/json_pointer/ class="md-nav__link "> <span class=md-ellipsis> json_pointer </span> </a> <label class="md-nav__link " for=__nav_4_11 id=__nav_4_11_label tabindex=0> <span class="md-nav__icon md-icon"></span> </label> </div> <nav class=md-nav data-md-level=2 aria-labelledby=__nav_4_11_label aria-expanded=false> <label class=md-nav__title for=__nav_4_11> <span class="md-nav__icon md-icon"></span> json_pointer </label> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=../../../api/json_pointer/json_pointer/ class=md-nav__link> <span class=md-ellipsis> (Constructor) </span> </a> </li> <li class=md-nav__item> <a href=../../../api/json_pointer/back/ class=md-nav__link> <span class=md-ellipsis> back </span> </a> </li> <li class=md-nav__item> <a href=../../../api/json_pointer/empty/ class=md-nav__link> <span class=md-ellipsis> empty </span> </a> </li> <li class=md-nav__item> <a href=../../../api/json_pointer/front/ class=md-nav__link> <span class=md-ellipsis> front </span> </a> </li> <li class=md-nav__item> <a href=../../../api/json_pointer/operator_string_t/ class=md-nav__link> <span class=md-ellipsis> operator string_t </span> </a> </li> <li class=md-nav__item> <a href=../../../api/json_pointer/operator_eq/ class=md-nav__link> <span class=md-ellipsis> operator== </span> </a> </li> <li class=md-nav__item> <a href=../../../api/json_pointer/operator_ne/ class=md-nav__link> <span class=md-ellipsis> operator!= </span> </a> </li> <li class=md-nav__item> <a href=../../../api/json_pointer/operator_spaceship/ class=md-nav__link> <span class=md-ellipsis> operator<=> </span> </a> </li> <li class=md-nav__item> <a href=../../../api/json_pointer/operator_slash/ class=md-nav__link> <span class=md-ellipsis> operator/ </span> </a> </li> <li class=md-nav__item> <a href=../../../api/json_pointer/operator_slasheq/ class=md-nav__link> <span class=md-ellipsis> operator/= </span> </a> </li> <li class=md-nav__item> <a href=../../../api/json_pointer/parent_pointer/ class=md-nav__link> <span class=md-ellipsis> parent_pointer </span> </a> </li> <li class=md-nav__item> <a href=../../../api/json_pointer/pop_back/ class=md-nav__link> <span class=md-ellipsis> pop_back </span> </a> </li> <li class=md-nav__item> <a href=../../../api/json_pointer/pop_front/ class=md-nav__link> <span class=md-ellipsis> pop_front </span> </a> </li> <li class=md-nav__item> <a href=../../../api/json_pointer/push_back/ class=md-nav__link> <span class=md-ellipsis> push_back </span> </a> </li> <li class=md-nav__item> <a href=../../../api/json_pointer/push_front/ class=md-nav__link> <span class=md-ellipsis> push_front </span> </a> </li> <li class=md-nav__item> <a href=../../../api/json_pointer/string_t/ class=md-nav__link> <span class=md-ellipsis> string_t </span> </a> </li> <li class=md-nav__item> <a href=../../../api/json_pointer/to_string/ class=md-nav__link> <span class=md-ellipsis> to_string </span> </a> </li> </ul> </nav> </li> <li class="md-nav__item md-nav__item--nested"> <input class="md-nav__toggle md-toggle " type=checkbox id=__nav_4_12> <div class="md-nav__link md-nav__container"> <a href=../../../api/json_sax/ class="md-nav__link "> <span class=md-ellipsis> json_sax </span> </a> <label class="md-nav__link " for=__nav_4_12 id=__nav_4_12_label tabindex=0> <span class="md-nav__icon md-icon"></span> </label> </div> <nav class=md-nav data-md-level=2 aria-labelledby=__nav_4_12_label aria-expanded=false> <label class=md-nav__title for=__nav_4_12> <span class="md-nav__icon md-icon"></span> json_sax </label> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=../../../api/json_sax/binary/ class=md-nav__link> <span class=md-ellipsis> binary </span> </a> </li> <li class=md-nav__item> <a href=../../../api/json_sax/boolean/ class=md-nav__link> <span class=md-ellipsis> boolean </span> </a> </li> <li class=md-nav__item> <a href=../../../api/json_sax/end_array/ class=md-nav__link> <span class=md-ellipsis> end_array </span> </a> </li> <li class=md-nav__item> <a href=../../../api/json_sax/end_object/ class=md-nav__link> <span class=md-ellipsis> end_object </span> </a> </li> <li class=md-nav__item> <a href=../../../api/json_sax/key/ class=md-nav__link> <span class=md-ellipsis> key </span> </a> </li> <li class=md-nav__item> <a href=../../../api/json_sax/null/ class=md-nav__link> <span class=md-ellipsis> null </span> </a> </li> <li class=md-nav__item> <a href=../../../api/json_sax/number_float/ class=md-nav__link> <span class=md-ellipsis> number_float </span> </a> </li> <li class=md-nav__item> <a href=../../../api/json_sax/number_integer/ class=md-nav__link> <span class=md-ellipsis> number_integer </span> </a> </li> <li class=md-nav__item> <a href=../../../api/json_sax/number_unsigned/ class=md-nav__link> <span class=md-ellipsis> number_unsigned </span> </a> </li> <li class=md-nav__item> <a href=../../../api/json_sax/parse_error/ class=md-nav__link> <span class=md-ellipsis> parse_error </span> </a> </li> <li class=md-nav__item> <a href=../../../api/json_sax/start_array/ class=md-nav__link> <span class=md-ellipsis> start_array </span> </a> </li> <li class=md-nav__item> <a href=../../../api/json_sax/start_object/ class=md-nav__link> <span class=md-ellipsis> start_object </span> </a> </li> <li class=md-nav__item> <a href=../../../api/json_sax/string/ class=md-nav__link> <span class=md-ellipsis> string </span> </a> </li> </ul> </nav> </li> <li class=md-nav__item> <a href=../../../api/json_view/ class=md-nav__link> <span class=md-ellipsis> json_view </span> </a> </li> <li class=md-nav__item> <a href=../../../api/operator_ltlt/ class=md-nav__link> <span class=md-ellipsis> operator<<(basic_json), operator<<(json_pointer) </span> </a> </li> <li class=md-nav__item> <a href=../../../api/operator_gtgt/ class=md-nav__link> <span class=md-ellipsis> operator>>(basic_json) </span> </a> </li> <li class=md-nav__item> <a href=../../../api/operator_literal_json/ class=md-nav__link> <span class=md-ellipsis> operator""_json </span> </a> </li> <li class=md-nav__item> <a href=../../../api/operator_literal_json_pointer/ class=md-nav__link> <span class=md-ellipsis> operator""_json_pointer </span> </a> </li> <li class=md-nav__item> <a href=../../../api/ordered_json/ class=md-nav__link> <span class=md-ellipsis> ordered_json </span> </a> </li> <li class=md-nav__item> <a href=../../../api/ordered_json_document/ class=md-nav__link> <span class=md-ellipsis> ordered_json_document </span> </a> </li> <li class=md-nav__item> <a href=../../../api/ordered_json_editable_document/ class=md-nav__link> <span class=md-ellipsis> ordered_json_editable_document </span> </a> </li> <li class=md-nav__item> <a href=../../../api/ordered_json_editable_view/ class=md-nav__link> <span class=md-ellipsis> ordered_json_editable_view </span> </a> </li> <li class=md-nav__item> <a href=../../../api/ordered_json_view/ class=md-nav__link> <span class=md-ellipsis> ordered_json_view </span> </a> </li> <li class=md-nav__item> <a href=../../../api/ordered_map/ class=md-nav__link> <span class=md-ellipsis> ordered_map </span> </a> </li> <li class=md-nav__item> <a href=../../../api/view_mode/ class=md-nav__link> <span class=md-ellipsis> view_mode </span> </a> </li> <li class="md-nav__item md-nav__item--nested"> <input class="md-nav__toggle md-toggle " type=checkbox id=__nav_4_25> <div class="md-nav__link md-nav__container"> <a href=../../../api/macros/ class="md-nav__link "> <span class=md-ellipsis> macros </span> </a> <label class="md-nav__link " for=__nav_4_25 id=__nav_4_25_label tabindex=0> <span class="md-nav__icon md-icon"></span> </label> </div> <nav class=md-nav data-md-level=2 aria-labelledby=__nav_4_25_label aria-expanded=false> <label class=md-nav__title for=__nav_4_25> <span class="md-nav__icon md-icon"></span> macros </label> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=../../../api/macros/json_assert/ class=md-nav__link> <span class=md-ellipsis> JSON_ASSERT </span> </a> </li> <li class=md-nav__item> <a href=../../../api/macros/json_brace_init_copy_semantics/ class=md-nav__link> <span class=md-ellipsis> JSON_BRACE_INIT_COPY_SEMANTICS </span> </a> </li> <li class=md-nav__item> <a href=../../../api/macros/json_throw_user/ class=md-nav__link> <span class=md-ellipsis> JSON_CATCH_USER, JSON_THROW_USER, JSON_TRY_USER </span> </a> </li> <li class=md-nav__item> <a href=../../../api/macros/json_diagnostics/ class=md-nav__link> <span class=md-ellipsis> JSON_DIAGNOSTICS </span> </a> </li> <li class=md-nav__item> <a href=../../../api/macros/json_delete_deprecated_functions/ class=md-nav__link> <span class=md-ellipsis> JSON_DELETE_DEPRECATED_FUNCTIONS </span> </a> </li> <li class=md-nav__item> <a href=../../../api/macros/json_diagnostic_positions/ class=md-nav__link> <span class=md-ellipsis> JSON_DIAGNOSTIC_POSITIONS </span> </a> </li> <li class=md-nav__item> <a href=../../../api/macros/json_disable_enum_serialization/ class=md-nav__link> <span class=md-ellipsis> JSON_DISABLE_ENUM_SERIALIZATION </span> </a> </li> <li class=md-nav__item> <a href=../../../api/macros/json_disable_stream_bulk_scan/ class=md-nav__link> <span class=md-ellipsis> JSON_DISABLE_STREAM_BULK_SCAN </span> </a> </li> <li class=md-nav__item> <a href=../../../api/macros/json_disable_tuple_reference_conversion/ class=md-nav__link> <span class=md-ellipsis> JSON_DISABLE_TUPLE_REFERENCE_CONVERSION </span> </a> </li> <li class=md-nav__item> <a href=../../../api/macros/json_disable_unlocked_file_io/ class=md-nav__link> <span class=md-ellipsis> JSON_DISABLE_UNLOCKED_FILE_IO </span> </a> </li> <li class=md-nav__item> <a href=../../../api/macros/json_has_cpp_11/ class=md-nav__link> <span class=md-ellipsis> JSON_HAS_CPP_11, JSON_HAS_CPP_14, JSON_HAS_CPP_17, JSON_HAS_CPP_20, JSON_HAS_CPP_23, JSON_HAS_CPP_26 </span> </a> </li> <li class=md-nav__item> <a href=../../../api/macros/json_has_filesystem/ class=md-nav__link> <span class=md-ellipsis> JSON_HAS_EXPERIMENTAL_FILESYSTEM, JSON_HAS_FILESYSTEM </span> </a> </li> <li class=md-nav__item> <a href=../../../api/macros/json_has_range_view_conversion/ class=md-nav__link> <span class=md-ellipsis> JSON_HAS_RANGE_VIEW_CONVERSION </span> </a> </li> <li class=md-nav__item> <a href=../../../api/macros/json_has_ranges/ class=md-nav__link> <span class=md-ellipsis> JSON_HAS_RANGES </span> </a> </li> <li class=md-nav__item> <a href=../../../api/macros/json_has_static_rtti/ class=md-nav__link> <span class=md-ellipsis> JSON_HAS_STATIC_RTTI </span> </a> </li> <li class=md-nav__item> <a href=../../../api/macros/json_has_std_format/ class=md-nav__link> <span class=md-ellipsis> JSON_HAS_STD_FORMAT </span> </a> </li> <li class=md-nav__item> <a href=../../../api/macros/json_has_three_way_comparison/ class=md-nav__link> <span class=md-ellipsis> JSON_HAS_THREE_WAY_COMPARISON </span> </a> </li> <li class=md-nav__item> <a href=../../../api/macros/json_no_automatic_udls/ class=md-nav__link> <span class=md-ellipsis> JSON_NO_AUTOMATIC_UDLS </span> </a> </li> <li class=md-nav__item> <a href=../../../api/macros/json_noexception/ class=md-nav__link> <span class=md-ellipsis> JSON_NOEXCEPTION </span> </a> </li> <li class=md-nav__item> <a href=../../../api/macros/json_no_io/ class=md-nav__link> <span class=md-ellipsis> JSON_NO_IO </span> </a> </li> <li class=md-nav__item> <a href=../../../api/macros/json_no_simd/ class=md-nav__link> <span class=md-ellipsis> JSON_NO_SIMD </span> </a> </li> <li class=md-nav__item> <a href=../../../api/macros/json_no_thread_local/ class=md-nav__link> <span class=md-ellipsis> JSON_NO_THREAD_LOCAL </span> </a> </li> <li class=md-nav__item> <a href=../../../api/macros/json_precise_stream_position/ class=md-nav__link> <span class=md-ellipsis> JSON_PRECISE_STREAM_POSITION </span> </a> </li> <li class=md-nav__item> <a href=../../../api/macros/json_skip_library_version_check/ class=md-nav__link> <span class=md-ellipsis> JSON_SKIP_LIBRARY_VERSION_CHECK </span> </a> </li> <li class=md-nav__item> <a href=../../../api/macros/json_skip_unsupported_compiler_check/ class=md-nav__link> <span class=md-ellipsis> JSON_SKIP_UNSUPPORTED_COMPILER_CHECK </span> </a> </li> <li class=md-nav__item> <a href=../../../api/macros/json_strict_binary_utf8/ class=md-nav__link> <span class=md-ellipsis> JSON_STRICT_BINARY_UTF8 </span> </a> </li> <li class=md-nav__item> <a href=../../../api/macros/json_strict_nul_handling/ class=md-nav__link> <span class=md-ellipsis> JSON_STRICT_NUL_HANDLING </span> </a> </li> <li class=md-nav__item> <a href=../../../api/macros/json_use_global_udls/ class=md-nav__link> <span class=md-ellipsis> JSON_USE_GLOBAL_UDLS </span> </a> </li> <li class=md-nav__item> <a href=../../../api/macros/json_use_implicit_conversions/ class=md-nav__link> <span class=md-ellipsis> JSON_USE_IMPLICIT_CONVERSIONS </span> </a> </li> <li class=md-nav__item> <a href=../../../api/macros/json_use_legacy_discarded_value_comparison/ class=md-nav__link> <span class=md-ellipsis> JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON </span> </a> </li> <li class=md-nav__item> <a href=../../../api/macros/json_use_objects_for_enum_keyed_maps/ class=md-nav__link> <span class=md-ellipsis> JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS </span> </a> </li> <li class=md-nav__item> <a href=../../../api/macros/json_use_simdutf/ class=md-nav__link> <span class=md-ellipsis> JSON_USE_SIMDUTF </span> </a> </li> <li class=md-nav__item> <a href=../../../api/macros/nlohmann_define_derived_type/ class=md-nav__link> <span class=md-ellipsis> NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE, NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_DEFAULT, NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_ONLY_SERIALIZE, NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE, NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_DEFAULT, NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE </span> </a> </li> <li class=md-nav__item> <a href=../../../api/macros/nlohmann_define_type_intrusive/ class=md-nav__link> <span class=md-ellipsis> NLOHMANN_DEFINE_TYPE_INTRUSIVE, NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT, NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE </span> </a> </li> <li class=md-nav__item> <a href=../../../api/macros/nlohmann_define_type_non_intrusive/ class=md-nav__link> <span class=md-ellipsis> NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE, NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT, NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE </span> </a> </li> <li class=md-nav__item> <a href=../../../api/macros/nlohmann_define_type_with_names/ class=md-nav__link> <span class=md-ellipsis> NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_NAMES, NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT_WITH_NAMES, NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE_WITH_NAMES, NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_NAMES, NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT_WITH_NAMES, NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE_WITH_NAMES, NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_NAMES, NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_DEFAULT_WITH_NAMES, NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_ONLY_SERIALIZE_WITH_NAMES, NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_NAMES, NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_DEFAULT_WITH_NAMES, NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE_WITH_NAMES </span> </a> </li> <li class=md-nav__item> <a href=../../../api/macros/nlohmann_json_namespace/ class=md-nav__link> <span class=md-ellipsis> NLOHMANN_JSON_NAMESPACE </span> </a> </li> <li class=md-nav__item> <a href=../../../api/macros/nlohmann_json_namespace_begin/ class=md-nav__link> <span class=md-ellipsis> NLOHMANN_JSON_NAMESPACE_BEGIN, NLOHMANN_JSON_NAMESPACE_END </span> </a> </li> <li class=md-nav__item> <a href=../../../api/macros/nlohmann_json_namespace_no_version/ class=md-nav__link> <span class=md-ellipsis> NLOHMANN_JSON_NAMESPACE_NO_VERSION </span> </a> </li> <li class=md-nav__item> <a href=../../../api/macros/nlohmann_json_serialize_enum/ class=md-nav__link> <span class=md-ellipsis> NLOHMANN_JSON_SERIALIZE_ENUM </span> </a> </li> <li class=md-nav__item> <a href=../../../api/macros/nlohmann_json_serialize_enum_strict/ class=md-nav__link> <span class=md-ellipsis> NLOHMANN_JSON_SERIALIZE_ENUM_STRICT </span> </a> </li> <li class=md-nav__item> <a href=../../../api/macros/nlohmann_json_version_major/ class=md-nav__link> <span class=md-ellipsis> NLOHMANN_JSON_VERSION_MAJOR, NLOHMANN_JSON_VERSION_MINOR, NLOHMANN_JSON_VERSION_PATCH </span> </a> </li> </ul> </nav> </li> </ul> </nav> </li> <li class="md-nav__item md-nav__item--nested"> <input class="md-nav__toggle md-toggle " type=checkbox id=__nav_5> <div class="md-nav__link md-nav__container"> <a href=../../../community/ class="md-nav__link "> <span class=md-ellipsis> Community </span> </a> <label class="md-nav__link " for=__nav_5 id=__nav_5_label tabindex=0> <span class="md-nav__icon md-icon"></span> </label> </div> <nav class=md-nav data-md-level=1 aria-labelledby=__nav_5_label aria-expanded=false> <label class=md-nav__title for=__nav_5> <span class="md-nav__icon md-icon"></span> Community </label> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=../../../community/ecosystem/ class=md-nav__link> <span class=md-ellipsis> Ecosystem </span> </a> </li> <li class=md-nav__item> <a href=../../../community/code_of_conduct/ class=md-nav__link> <span class=md-ellipsis> Code of Conduct </span> </a> </li> <li class=md-nav__item> <a href=../../../community/contribution_guidelines/ class=md-nav__link> <span class=md-ellipsis> Contribution Guidelines </span> </a> </li> <li class=md-nav__item> <a href=../../../community/quality_assurance/ class=md-nav__link> <span class=md-ellipsis> Quality assurance </span> </a> </li> <li class=md-nav__item> <a href=../../../community/governance/ class=md-nav__link> <span class=md-ellipsis> Governance </span> </a> </li> <li class=md-nav__item> <a href=../../../community/roadmap/ class=md-nav__link> <span class=md-ellipsis> Roadmap </span> </a> </li> <li class=md-nav__item> <a href=../../../community/security_policy/ class=md-nav__link> <span class=md-ellipsis> Security Policy </span> </a> </li> <li class=md-nav__item> <a href=../../../community/assurance_case/ class=md-nav__link> <span class=md-ellipsis> Assurance case </span> </a> </li> </ul> </nav> </li> </ul> </nav> </div> </div> </div> <div class="md-sidebar md-sidebar--secondary" data-md-component=sidebar data-md-type=toc> <div class=md-sidebar__scrollwrap> <div class=md-sidebar__inner> <nav class="md-nav md-nav--secondary" aria-label="Table of contents"> <label class=md-nav__title for=__toc> <span class="md-nav__icon md-icon"></span> Table of contents </label> <ul class=md-nav__list data-md-component=toc data-md-scrollfix> <li class=md-nav__item> <a href=#the-short-version class=md-nav__link> <span class=md-ellipsis> The short version </span> </a> </li> <li class=md-nav__item> <a href=#where-the-time-went-a-timeline class=md-nav__link> <span class=md-ellipsis> Where the time went: a timeline </span> </a> </li> <li class=md-nav__item> <a href=#theme-1 class=md-nav__link> <span class=md-ellipsis> 1 Specialize for each input source </span> </a> <nav class=md-nav aria-label="1 Specialize for each input source"> <ul class=md-nav__list> <li class=md-nav__item> <a href=#detecting-the-input-in-c11 class=md-nav__link> <span class=md-ellipsis> Detecting the input in C++11 </span> </a> </li> <li class=md-nav__item> <a href=#contiguous-input class=md-nav__link> <span class=md-ellipsis> Contiguous input </span> </a> </li> <li class=md-nav__item> <a href=#streams class=md-nav__link> <span class=md-ellipsis> Streams </span> </a> </li> <li class=md-nav__item> <a href=#file class=md-nav__link> <span class=md-ellipsis> FILE* </span> </a> </li> </ul> </nav> </li> <li class=md-nav__item> <a href=#theme-2 class=md-nav__link> <span class=md-ellipsis> 2 Work on words, not bytes </span> </a> <nav class=md-nav aria-label="2 Work on words, not bytes"> <ul class=md-nav__list> <li class=md-nav__item> <a href=#eight-bytes-in-a-word class=md-nav__link> <span class=md-ellipsis> Eight bytes in a word </span> </a> </li> <li class=md-nav__item> <a href=#16-bytes-with-sse2-and-neon class=md-nav__link> <span class=md-ellipsis> 16 bytes with SSE2 and NEON </span> </a> </li> <li class=md-nav__item> <a href=#validating-utf-8-16-bytes-at-a-time class=md-nav__link> <span class=md-ellipsis> Validating UTF-8 16 bytes at a time </span> </a> </li> <li class=md-nav__item> <a href=#short-strings class=md-nav__link> <span class=md-ellipsis> Short strings </span> </a> </li> <li class=md-nav__item> <a href=#escapes-from-a-table class=md-nav__link> <span class=md-ellipsis> Escapes from a table </span> </a> </li> </ul> </nav> </li> <li class=md-nav__item> <a href=#theme-3 class=md-nav__link> <span class=md-ellipsis> 3 Own the number conversions </span> </a> <nav class=md-nav aria-label="3 Own the number conversions"> <ul class=md-nav__list> <li class=md-nav__item> <a href=#eight-digits-at-a-time class=md-nav__link> <span class=md-ellipsis> Eight digits at a time </span> </a> </li> <li class=md-nav__item> <a href=#clingers-fast-path class=md-nav__link> <span class=md-ellipsis> Clinger's fast path </span> </a> </li> <li class=md-nav__item> <a href=#eisel-lemire class=md-nav__link> <span class=md-ellipsis> Eisel-Lemire </span> </a> </li> <li class=md-nav__item> <a href=#writing-zmij class=md-nav__link> <span class=md-ellipsis> Writing: Żmij </span> </a> </li> </ul> </nav> </li> <li class=md-nav__item> <a href=#theme-4 class=md-nav__link> <span class=md-ellipsis> 4 Don't do unnecessary work </span> </a> <nav class=md-nav aria-label="4 Don't do unnecessary work"> <ul class=md-nav__list> <li class=md-nav__item> <a href=#the-token-buffer class=md-nav__link> <span class=md-ellipsis> The token buffer </span> </a> </li> <li class=md-nav__item> <a href=#positions-only-on-error class=md-nav__link> <span class=md-ellipsis> Positions only on error </span> </a> </li> <li class=md-nav__item> <a href=#the-text-of-float-tokens class=md-nav__link> <span class=md-ellipsis> The text of float tokens </span> </a> </li> <li class=md-nav__item> <a href=#a-copy-that-should-have-been-a-move class=md-nav__link> <span class=md-ellipsis> A copy that should have been a move </span> </a> </li> <li class=md-nav__item> <a href=#ordered_json-growth class=md-nav__link> <span class=md-ellipsis> ordered_json growth </span> </a> </li> <li class=md-nav__item> <a href=#containers-built-one-element-at-a-time class=md-nav__link> <span class=md-ellipsis> Containers built one element at a time </span> </a> </li> <li class=md-nav__item> <a href=#smaller-ones class=md-nav__link> <span class=md-ellipsis> Smaller ones </span> </a> </li> </ul> </nav> </li> <li class=md-nav__item> <a href=#theme-5 class=md-nav__link> <span class=md-ellipsis> 5 Read the assembly </span> </a> <nav class=md-nav aria-label="5 Read the assembly"> <ul class=md-nav__list> <li class=md-nav__item> <a href=#a-stack-canary-on-every-token class=md-nav__link> <span class=md-ellipsis> A stack canary on every token </span> </a> </li> <li class=md-nav__item> <a href=#exceptions-that-block-inlining class=md-nav__link> <span class=md-ellipsis> Exceptions that block inlining </span> </a> </li> <li class=md-nav__item> <a href=#aliasing class=md-nav__link> <span class=md-ellipsis> Aliasing </span> </a> </li> <li class=md-nav__item> <a href=#loop-shape-beats-branch-count class=md-nav__link> <span class=md-ellipsis> Loop shape beats branch count </span> </a> </li> <li class=md-nav__item> <a href=#inlining-that-disappears class=md-nav__link> <span class=md-ellipsis> Inlining that disappears </span> </a> </li> <li class=md-nav__item> <a href=#branches-the-compiler-chose class=md-nav__link> <span class=md-ellipsis> Branches the compiler chose </span> </a> </li> <li class=md-nav__item> <a href=#code-size-as-a-cost class=md-nav__link> <span class=md-ellipsis> Code size as a cost </span> </a> </li> </ul> </nav> </li> <li class=md-nav__item> <a href=#theme-6 class=md-nav__link> <span class=md-ellipsis> 6 Write through a cursor </span> </a> <nav class=md-nav aria-label="6 Write through a cursor"> <ul class=md-nav__list> <li class=md-nav__item> <a href=#a-buffer-in-the-serializer class=md-nav__link> <span class=md-ellipsis> A buffer in the serializer </span> </a> </li> <li class=md-nav__item> <a href=#no-allocation-per-call class=md-nav__link> <span class=md-ellipsis> No allocation per call </span> </a> </li> <li class=md-nav__item> <a href=#a-concrete-sink-for-the-binary-writers class=md-nav__link> <span class=md-ellipsis> A concrete sink for the binary writers </span> </a> </li> <li class=md-nav__item> <a href=#a-cursor-instead-of-vectorinsert class=md-nav__link> <span class=md-ellipsis> A cursor instead of vector::insert() </span> </a> </li> <li class=md-nav__item> <a href=#integers-without-branches class=md-nav__link> <span class=md-ellipsis> Integers without branches </span> </a> </li> </ul> </nav> </li> <li class=md-nav__item> <a href=#theme-7 class=md-nav__link> <span class=md-ellipsis> 7 Fix the algorithm first </span> </a> <nav class=md-nav aria-label="7 Fix the algorithm first"> <ul class=md-nav__list> <li class=md-nav__item> <a href=#comparing-in-one-pass class=md-nav__link> <span class=md-ellipsis> Comparing in one pass </span> </a> </li> <li class=md-nav__item> <a href=#bounded-recursion class=md-nav__link> <span class=md-ellipsis> Bounded recursion </span> </a> </li> <li class=md-nav__item> <a href=#destroying-without-a-stack class=md-nav__link> <span class=md-ellipsis> Destroying without a stack </span> </a> </li> </ul> </nav> </li> <li class=md-nav__item> <a href=#theme-8 class=md-nav__link> <span class=md-ellipsis> 8 Build a different data structure </span> </a> <nav class=md-nav aria-label="8 Build a different data structure"> <ul class=md-nav__list> <li class=md-nav__item> <a href=#one-flat-index class=md-nav__link> <span class=md-ellipsis> One flat index </span> </a> </li> <li class=md-nav__item> <a href=#it-can-be-edited-too class=md-nav__link> <span class=md-ellipsis> It can be edited, too </span> </a> </li> </ul> </nav> </li> <li class=md-nav__item> <a href=#how-it-compares class=md-nav__link> <span class=md-ellipsis> How it compares </span> </a> <nav class=md-nav aria-label="How it compares"> <ul class=md-nav__list> <li class=md-nav__item> <a href=#six-use-cases class=md-nav__link> <span class=md-ellipsis> Six use cases </span> </a> </li> <li class=md-nav__item> <a href=#where-the-input-comes-from class=md-nav__link> <span class=md-ellipsis> Where the input comes from </span> </a> </li> <li class=md-nav__item> <a href=#checking-less-on-purpose class=md-nav__link> <span class=md-ellipsis> Checking less, on purpose </span> </a> </li> <li class=md-nav__item> <a href=#results-on-the-mac class=md-nav__link> <span class=md-ellipsis> Results on the Mac </span> </a> </li> <li class=md-nav__item> <a href=#reading-into-structs class=md-nav__link> <span class=md-ellipsis> Reading into structs </span> </a> </li> <li class=md-nav__item> <a href=#nlohmannjson-without-json_document class=md-nav__link> <span class=md-ellipsis> nlohmann/json without json_document </span> </a> </li> <li class=md-nav__item> <a href=#results-on-x86-64 class=md-nav__link> <span class=md-ellipsis> Results on x86-64 </span> </a> </li> <li class=md-nav__item> <a href=#files-and-checks-we-didnt-choose class=md-nav__link> <span class=md-ellipsis> Files and checks we didn't choose </span> </a> </li> </ul> </nav> </li> <li class=md-nav__item> <a href=#what-didnt-work class=md-nav__link> <span class=md-ellipsis> What didn't work </span> </a> </li> <li class=md-nav__item> <a href=#the-price class=md-nav__link> <span class=md-ellipsis> The price </span> </a> </li> <li class=md-nav__item> <a href=#summing-up class=md-nav__link> <span class=md-ellipsis> Summing up </span> </a> </li> <li class=md-nav__item> <a href=#thanks class=md-nav__link> <span class=md-ellipsis> Thanks </span> </a> </li> <li class=md-nav__item> <a href=#appendix class=md-nav__link> <span class=md-ellipsis> Appendix </span> </a> <nav class=md-nav aria-label=Appendix> <ul class=md-nav__list> <li class=md-nav__item> <a href=#a-test-files class=md-nav__link> <span class=md-ellipsis> A. Test files </span> </a> </li> <li class=md-nav__item> <a href=#b-3120-against-3130 class=md-nav__link> <span class=md-ellipsis> B. 3.12.0 against 3.13.0 </span> </a> </li> <li class=md-nav__item> <a href=#c-the-timeline class=md-nav__link> <span class=md-ellipsis> C. The timeline </span> </a> </li> <li class=md-nav__item> <a href=#d-algorithmic-fixes class=md-nav__link> <span class=md-ellipsis> D. Algorithmic fixes </span> </a> </li> <li class=md-nav__item> <a href=#e-comparison-with-other-libraries class=md-nav__link> <span class=md-ellipsis> E. Comparison with other libraries </span> </a> </li> <li class=md-nav__item> <a href=#f-behavior-changes class=md-nav__link> <span class=md-ellipsis> F. Behavior changes </span> </a> </li> <li class=md-nav__item> <a href=#g-how-we-measured class=md-nav__link> <span class=md-ellipsis> G. How we measured </span> </a> </li> <li class=md-nav__item> <a href=#h-pull-requests-by-theme class=md-nav__link> <span class=md-ellipsis> H. Pull requests by theme </span> </a> </li> <li class=md-nav__item> <a href=#i-details-of-the-themes class=md-nav__link> <span class=md-ellipsis> I. Details of the themes </span> </a> </li> <li class=md-nav__item> <a href=#j-validation class=md-nav__link> <span class=md-ellipsis> J. Validation </span> </a> </li> </ul> </nav> </li> </ul> </nav> </div> </div> </div> <div class=md-content data-md-component=content> <article class="md-content__inner md-typeset"> <a href="https://github.com/nlohmann/json/edit/develop/docs/mkdocs/docs/home/blog/how_3_13_0_got_faster.md" title="Edit this page" class="md-content__button md-icon" rel="edit"> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M10 20H6V4h7v5h5v3.1l2-2V8l-6-6H6c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h4zm10.2-7c.1 0 .3.1.4.2l1.3 1.3c.2.2.2.6 0 .8l-1 1-2.1-2.1 1-1c.1-.1.2-.2.4-.2m0 3.9L14.1 23H12v-2.1l6.1-6.1z"/></svg> </a> <a href="https://github.com/nlohmann/json/raw/develop/docs/mkdocs/docs/home/blog/how_3_13_0_got_faster.md" title="View source of this page" class="md-content__button md-icon"> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M17 18c.56 0 1 .44 1 1s-.44 1-1 1-1-.44-1-1 .44-1 1-1m0-3c-2.73 0-5.06 1.66-6 4 .94 2.34 3.27 4 6 4s5.06-1.66 6-4c-.94-2.34-3.27-4-6-4m0 6.5a2.5 2.5 0 0 1-2.5-2.5 2.5 2.5 0 0 1 2.5-2.5 2.5 2.5 0 0 1 2.5 2.5 2.5 2.5 0 0 1-2.5 2.5M9.27 20H6V4h7v5h5v4.07c.7.08 1.36.25 2 .49V8l-6-6H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h4.5a8.2 8.2 0 0 1-1.23-2"/></svg> </a> <h1 id=how-nlohmannjson-3130-got-3-faster>How nlohmann/json 3.13.0 got 3× faster<a class=headerlink href=#how-nlohmannjson-3130-got-3-faster title="Permanent link">&para;</a></h1> <p class=nj-byline><a href="https://github.com/nlohmann">Niels Lohmann</a> · <time datetime=2026-10-28>October 28, 2026</time></p> <!-- Before publishing: set the date to the release date, and measure every number of this post again with the
v3.13.0 tag (Appendix G describes the setup; tests/benchmarks/json_view/others/README.md has the commands of the
comparison), including the line counts in "The price". The numbers below are from develop baba5db36f with the
open non-draft pull requests #5998, #6001, #6002 and #6017-#6019 merged (local branch local/all-prs-1103 at
5c8ccf2f38), all measured 11-03: suite (rounds 2 and 3; round 1 ran under load), timeline (the commits after
10-27 and 3.13.0; the older points are from 10-27, checked with 12 of them), Appendix D, compile times (5
rounds), the stream gap, the comparison on the Mac and on x86-64, and the suite on the Intel MacBook Pro. The Mac's
Rust times are from 10-29 and the x86-64 conformance run from 10-30. The x86-64 server now runs Ubuntu 26.04, so
"GCC 13" is 13.4 (10-31: 13.3 on Ubuntu 24.04). Merge tests/benchmarks/json_view/others before publishing (the
links 404). --> <p>Since 2016, the <a href="https://github.com/nlohmann/json#readme">README</a> of this library has said this about speed:</p> <blockquote> <p>There are certainly faster <abbr title="JavaScript Object Notation">JSON</abbr> libraries out there. However, if your goal is to speed up your development by adding <abbr title="JavaScript Object Notation">JSON</abbr> support with a single header, then this library is the way to go.</p> </blockquote> <p>That sentence is still true, but the gap is a lot smaller now. Swap the 3.12.0 header for the 3.13.0 one, recompile, and the 182 benchmarks of the library's own suite run 3.0× as fast on an Apple M1 Max (geometric mean; 3.1× on an Intel MacBook Pro from 2016). Not a line of your code changes. Parsing typical documents got 3.1–4.3× as fast, and writing them 3.0–6.7×. The new version also adds <a href=../../../features/json_view/ ><code>json_document</code></a>, a second way to hold a parsed document, which competes with the fastest C++ and Rust <abbr title="JavaScript Object Notation">JSON</abbr> libraries; <a href=#how-it-compares>How it compares</a> has the numbers, including where it loses. The price is compile time: two small example programs take 34–62% longer to compile. A precompiled header or a C++20 module wins back most or all of that in debug builds, and 41–91% of it in optimized builds (<a href=#the-price>The price</a>).</p> <p>This post is about <em>how</em>. Hardly any of the techniques are new: we borrowed them from <a href="https://github.com/simdjson/simdjson">simdjson</a>, <a href="https://github.com/ibireme/yyjson">yyjson</a>, <a href="https://github.com/fastfloat/fast_float">fast_float</a>, <a href="https://github.com/vitaut/zmij">Żmij</a>, <a href="https://github.com/serde-rs/json">serde_json</a>, <a href="https://github.com/stephenberry/glaze">Glaze</a>, <a href="https://sqlite.org">SQLite</a>, <a href="https://github.com/boostorg/json">Boost.<abbr title="JavaScript Object Notation">JSON</abbr></a>, or a textbook, and we name the source at each step. What is worth writing about is the <em>combination</em>, and the conditions it had to work under. It is a header-only C++11 library whose 3.x <abbr title="Application Programming Interface">API</abbr> has been stable for almost nine years, and whose value type is a template over its string, number, object, array, and allocator types. Input comes from strings, streams, <code>FILE*</code>, iterator pairs, wide strings, and user-defined adapters. Output had to stay the same byte for byte, and error messages had to keep pointing at the same byte. The few deliberate changes of output are listed in <a href=#f-behavior-changes>Appendix F</a>.</p> <p>Every number comes from a benchmark we ran for this post or from the pull request that made the change. The <a href=#appendix>appendix</a> describes the test files and the setup, has the full tables behind every chart, and lists the pull requests behind each theme.</p> <p>Fast paths are where bugs hide: they run only for some inputs, so a mistake in one can go unnoticed until the right input comes along. So every fast path was tested against the slow path it replaces, on millions of generated and fuzzed inputs. Both had to return the same value, or fail with the same error message at the same byte. <a href=#j-validation>Appendix J</a> lists the checks.</p> <h2 id=the-short-version>The short version<a class=headerlink href=#the-short-version title="Permanent link">&para;</a></h2> <p>The test files are the three of Milo Yip's <a href="https://github.com/miloyip/nativejson-benchmark">nativejson-benchmark</a> that <abbr title="JavaScript Object Notation">JSON</abbr> libraries have been measured with for a decade, <code>twitter.json</code> (strings, much of it Japanese), <code>citm_catalog.json</code> (many small objects, indented) and <code>canada.json</code> (floating-point numbers), plus the 56 MB <code>jeopardy.json</code>. <a href=#a-test-files>Appendix A</a> says what makes each of them hard.</p> <div class=nj-fig-wrap> <p><svg class="nj-fig nj-charts nj-charts--blog" viewbox="0 0 560 604" role=img aria-labelledby="nj-blog-overview nj-blog-overview-d" xmlns=http://www.w3.org/2000/svg> <title id=nj-blog-overview>Speedup of 3.13.0 over 3.12.0 per workload, Apple M1 Max, Apple clang</title> <desc id=nj-blog-overview-d>Horizontal bars of the speedup, more is better. twitter.json 3.1x; citm_catalog.json 4.2x; canada.json 3.4x; canada.json, indented 6.5x; citm, ordered_json 6.8x; twitter, std::ifstream 2.5x; citm, FILE* 4.7x; citm, accept() 7.1x; dump() twitter 6.7x; dump() canada 3.0x; dump(4) citm 4.7x; to_cbor() twitter 4.6x; twitter, memory 3.4x; twitter, FILE* 6.6x; diff() canada 10x; iterate canada 2.7x; copy + destroy citm 1.13x; == citm 1.06x.</desc> <text class=nj-charts-panel x=8 y=20>Parsing</text> <text class=nj-charts-panel x=8 y=244>Writing</text> <text class=nj-charts-panel x=8 y=372>Reading C&#8203;BOR</text> <text class=nj-charts-panel x=8 y=452>Values</text> <line class=nj-charts-grid x1=220 y1=8 x2=220 y2=560 /> <text class=nj-charts-tick x=220 y=576>1&#215;</text> <line class=nj-charts-grid x1=250 y1=8 x2=250 y2=560 /> <text class=nj-charts-tick x=250 y=576>2&#215;</text> <line class=nj-charts-grid x1=280 y1=8 x2=280 y2=560 /> <text class=nj-charts-tick x=280 y=576>3&#215;</text> <line class=nj-charts-grid x1=310 y1=8 x2=310 y2=560 /> <text class=nj-charts-tick x=310 y=576>4&#215;</text> <line class=nj-charts-grid x1=340 y1=8 x2=340 y2=560 /> <text class=nj-charts-tick x=340 y=576>5&#215;</text> <line class=nj-charts-grid x1=370 y1=8 x2=370 y2=560 /> <text class=nj-charts-tick x=370 y=576>6&#215;</text> <line class=nj-charts-grid x1=400 y1=8 x2=400 y2=560 /> <text class=nj-charts-tick x=400 y=576>7&#215;</text> <line class=nj-charts-grid x1=430 y1=8 x2=430 y2=560 /> <text class=nj-charts-tick x=430 y=576>8&#215;</text> <line class=nj-charts-grid x1=460 y1=8 x2=460 y2=560 /> <text class=nj-charts-tick x=460 y=576>9&#215;</text> <line class=nj-charts-grid x1=490 y1=8 x2=490 y2=560 /> <text class=nj-charts-tick x=490 y=576>10&#215;</text> <line class=nj-charts-grid x1=520 y1=8 x2=520 y2=560 /> <text class=nj-charts-tick x=520 y=576>11&#215;</text> <text class="nj-charts-rowlabel nj-charts-tick--r" x=182 y=42 text-anchor=end>twitter.json</text> <path class=nj-charts-c1 d="M190 30 H280.2 Q284.2 30 284.2 34 V41 Q284.2 45 280.2 45 H190 Z"><title>twitter.json: 3.1&#215;</title></path> <text class=nj-charts-val x=289.2 y=42>3.1&#215;</text> <text class="nj-charts-rowlabel nj-charts-tick--r" x=182 y=66 text-anchor=end>citm_catalog.json</text> <path class=nj-charts-c1 d="M190 54 H313.5 Q317.5 54 317.5 58 V65 Q317.5 69 313.5 69 H190 Z"><title>citm_catalog.json: 4.2&#215;</title></path> <text class=nj-charts-val x=322.5 y=66>4.2&#215;</text> <text class="nj-charts-rowlabel nj-charts-tick--r" x=182 y=90 text-anchor=end>canada.json</text> <path class=nj-charts-c1 d="M190 78 H286.5 Q290.5 78 290.5 82 V89 Q290.5 93 286.5 93 H190 Z"><title>canada.json: 3.4&#215;</title></path> <text class=nj-charts-val x=295.5 y=90>3.4&#215;</text> <text class="nj-charts-rowlabel nj-charts-tick--r" x=182 y=114 text-anchor=end>canada.json, indented</text> <path class=nj-charts-c1 d="M190 102 H381.3 Q385.3 102 385.3 106 V113 Q385.3 117 381.3 117 H190 Z"><title>canada.json, indented: 6.5&#215;</title></path> <text class=nj-charts-val x=390.3 y=114>6.5&#215;</text> <text class="nj-charts-rowlabel nj-charts-tick--r" x=182 y=138 text-anchor=end>citm, ordered_json</text> <path class=nj-charts-c1 d="M190 126 H391.5 Q395.5 126 395.5 130 V137 Q395.5 141 391.5 141 H190 Z"><title>citm, ordered_json: 6.8&#215;</title></path> <text class=nj-charts-val x=400.5 y=138>6.8&#215;</text> <text class="nj-charts-rowlabel nj-charts-tick--r" x=182 y=162 text-anchor=end>twitter, std::ifstream</text> <path class=nj-charts-c1 d="M190 150 H261 Q265 150 265 154 V161 Q265 165 261 165 H190 Z"><title>twitter, std::ifstream: 2.5&#215;</title></path> <text class=nj-charts-val x=270 y=162>2.5&#215;</text> <text class="nj-charts-rowlabel nj-charts-tick--r" x=182 y=186 text-anchor=end>citm, FILE*</text> <path class=nj-charts-c1 d="M190 174 H328.2 Q332.2 174 332.2 178 V185 Q332.2 189 328.2 189 H190 Z"><title>citm, FILE*: 4.7&#215;</title></path> <text class=nj-charts-val x=337.2 y=186>4.7&#215;</text> <text class="nj-charts-rowlabel nj-charts-tick--r" x=182 y=210 text-anchor=end>citm, accept()</text> <path class=nj-charts-c1 d="M190 198 H398.1 Q402.1 198 402.1 202 V209 Q402.1 213 398.1 213 H190 Z"><title>citm, accept(): 7.1&#215;</title></path> <text class=nj-charts-val x=407.1 y=210>7.1&#215;</text> <text class="nj-charts-rowlabel nj-charts-tick--r" x=182 y=266 text-anchor=end>dump() twitter</text> <path class=nj-charts-c1 d="M190 254 H387 Q391 254 391 258 V265 Q391 269 387 269 H190 Z"><title>dump() twitter: 6.7&#215;</title></path> <text class=nj-charts-val x=396 y=266>6.7&#215;</text> <text class="nj-charts-rowlabel nj-charts-tick--r" x=182 y=290 text-anchor=end>dump() canada</text> <path class=nj-charts-c1 d="M190 278 H275.4 Q279.4 278 279.4 282 V289 Q279.4 293 275.4 293 H190 Z"><title>dump() canada: 3.0&#215;</title></path> <text class=nj-charts-val x=284.4 y=290>3.0&#215;</text> <text class="nj-charts-rowlabel nj-charts-tick--r" x=182 y=314 text-anchor=end>dump(4) citm</text> <path class=nj-charts-c1 d="M190 302 H327 Q331 302 331 306 V313 Q331 317 327 317 H190 Z"><title>dump(4) citm: 4.7&#215;</title></path> <text class=nj-charts-val x=336 y=314>4.7&#215;</text> <text class="nj-charts-rowlabel nj-charts-tick--r" x=182 y=338 text-anchor=end>to_cbor() twitter</text> <path class=nj-charts-c1 d="M190 326 H323.7 Q327.7 326 327.7 330 V337 Q327.7 341 323.7 341 H190 Z"><title>to_cbor() twitter: 4.6&#215;</title></path> <text class=nj-charts-val x=332.7 y=338>4.6&#215;</text> <text class="nj-charts-rowlabel nj-charts-tick--r" x=182 y=394 text-anchor=end>twitter, memory</text> <path class=nj-charts-c1 d="M190 382 H287.7 Q291.7 382 291.7 386 V393 Q291.7 397 287.7 397 H190 Z"><title>twitter, memory: 3.4&#215;</title></path> <text class=nj-charts-val x=296.7 y=394>3.4&#215;</text> <text class="nj-charts-rowlabel nj-charts-tick--r" x=182 y=418 text-anchor=end>twitter, FILE*</text> <path class=nj-charts-c1 d="M190 406 H383.7 Q387.7 406 387.7 410 V417 Q387.7 421 383.7 421 H190 Z"><title>twitter, FILE*: 6.6&#215;</title></path> <text class=nj-charts-val x=392.7 y=418>6.6&#215;</text> <text class="nj-charts-rowlabel nj-charts-tick--r" x=182 y=474 text-anchor=end>diff() canada</text> <path class=nj-charts-c1 d="M190 462 H499.8 Q503.8 462 503.8 466 V473 Q503.8 477 499.8 477 H190 Z"><title>diff() canada: 10&#215;</title></path> <text class=nj-charts-val x=508.8 y=474>10&#215;</text> <text class="nj-charts-rowlabel nj-charts-tick--r" x=182 y=498 text-anchor=end>iterate canada</text> <path class=nj-charts-c1 d="M190 486 H267.9 Q271.9 486 271.9 490 V497 Q271.9 501 267.9 501 H190 Z"><title>iterate canada: 2.7&#215;</title></path> <text class=nj-charts-val x=276.9 y=498>2.7&#215;</text> <text class="nj-charts-rowlabel nj-charts-tick--r" x=182 y=522 text-anchor=end>copy + destroy citm</text> <path class=nj-charts-c1 d="M190 510 H219.9 Q223.9 510 223.9 514 V521 Q223.9 525 219.9 525 H190 Z"><title>copy + destroy citm: 1.13&#215;</title></path> <text class=nj-charts-val x=228.9 y=522>1.13&#215;</text> <text class="nj-charts-rowlabel nj-charts-tick--r" x=182 y=546 text-anchor=end>== citm</text> <path class=nj-charts-c1 d="M190 534 H217.8 Q221.8 534 221.8 538 V545 Q221.8 549 217.8 549 H190 Z"><title>== citm: 1.06&#215;</title></path> <text class=nj-charts-val x=226.8 y=546>1.06&#215;</text> <line class=nj-charts-ref x1=220 y1=8 x2=220 y2=560 /> <line class=nj-charts-zero x1=190 y1=8 x2=190 y2=560 /> <text class=nj-charts-tick x=355 y=594>speedup over 3.12.0 (3.12.0 = 1&#215;), more is better</text> </svg></p> </div> <p class=nj-caption>Speedup of 3.13.0 over 3.12.0 for a selection of workloads: the old time divided by the new one, Google Benchmark suite on an Apple M1 Max, median of 8 runs. More is better; the vertical line at 1× is 3.12.0. The times are in <a href=#b-3120-against-3130>Appendix B</a>.</p> <p>The rows above are chosen to show the range. All 182 benchmarks of the suite:</p> <div class=nj-fig-wrap> <p><svg class="nj-fig nj-charts nj-charts--blog" viewbox="0 0 560 250" role=img aria-labelledby="nj-blog-dist nj-blog-dist-d" xmlns=http://www.w3.org/2000/svg> <title id=nj-blog-dist>Speedup of 3.13.0 over 3.12.0 for all 182 benchmarks of the suite</title> <desc id=nj-blog-dist-d>Bars counting the benchmarks per speedup range: below 1x: 1; 1 to 1.5x: 22; 1.5 to 2x: 12; 2 to 3x: 60; 3 to 5x: 58; 5 to 10x: 25; 10x or more: 4. Median 2.9x, geometric mean 3.0x.</desc> <line class=nj-charts-grid x1=52 y1=196 x2=548 y2=196 /> <text class="nj-charts-tick nj-charts-tick--r" x=46 y=200>0</text> <line class=nj-charts-grid x1=52 y1=144.571 x2=548 y2=144.571 /> <text class="nj-charts-tick nj-charts-tick--r" x=46 y=148.571>20</text> <line class=nj-charts-grid x1=52 y1=93.1429 x2=548 y2=93.1429 /> <text class="nj-charts-tick nj-charts-tick--r" x=46 y=97.1429>40</text> <line class=nj-charts-grid x1=52 y1=41.7143 x2=548 y2=41.7143 /> <text class="nj-charts-tick nj-charts-tick--r" x=46 y=45.7143>60</text> <rect class=nj-charts-c2 x=60.0 y=193.4 width=54.9 height=2.6 rx=3><title>below 1&#215;: 1</title></rect> <text class=nj-charts-val x=87.4 y=188.4 text-anchor=middle>1</text> <text class=nj-charts-tick x=87.4 y=212.0>below 1&#215;</text> <rect class=nj-charts-c1 x=130.9 y=139.4 width=54.9 height=56.6 rx=3><title>1 to 1.5&#215;: 22</title></rect> <text class=nj-charts-val x=158.3 y=134.4 text-anchor=middle>22</text> <text class=nj-charts-tick x=158.3 y=212.0>1 to 1.5&#215;</text> <rect class=nj-charts-c1 x=201.7 y=165.1 width=54.9 height=30.9 rx=3><title>1.5 to 2&#215;: 12</title></rect> <text class=nj-charts-val x=229.1 y=160.1 text-anchor=middle>12</text> <text class=nj-charts-tick x=229.1 y=212.0>1.5 to 2&#215;</text> <rect class=nj-charts-c1 x=272.6 y=41.7 width=54.9 height=154.3 rx=3><title>2 to 3&#215;: 60</title></rect> <text class=nj-charts-val x=300.0 y=36.7 text-anchor=middle>60</text> <text class=nj-charts-tick x=300.0 y=212.0>2 to 3&#215;</text> <rect class=nj-charts-c1 x=343.4 y=46.9 width=54.9 height=149.1 rx=3><title>3 to 5&#215;: 58</title></rect> <text class=nj-charts-val x=370.9 y=41.9 text-anchor=middle>58</text> <text class=nj-charts-tick x=370.9 y=212.0>3 to 5&#215;</text> <rect class=nj-charts-c1 x=414.3 y=131.7 width=54.9 height=64.3 rx=3><title>5 to 10&#215;: 25</title></rect> <text class=nj-charts-val x=441.7 y=126.7 text-anchor=middle>25</text> <text class=nj-charts-tick x=441.7 y=212.0>5 to 10&#215;</text> <rect class=nj-charts-c1 x=485.1 y=185.7 width=54.9 height=10.3 rx=3><title>10&#215; or more: 4</title></rect> <text class=nj-charts-val x=512.6 y=180.7 text-anchor=middle>4</text> <text class=nj-charts-tick x=512.6 y=212.0>10&#215; or more</text> <line class=nj-charts-axis x1=52 y1=196 x2=548 y2=196 /> <text class=nj-charts-tick x=300 y=240>speedup over 3.12.0, more is better</text> <text class=nj-charts-tick transform=rotate(-90) x=-106 y=14>number of benchmarks</text> </svg></p> </div> <p class=nj-caption>How many of the suite's 182 benchmarks got how much faster. The one below 1× is copying <code>citm_catalog.json</code> without destroying the copy. Every row is in <a href=#b-3120-against-3130>Appendix B</a>.</p> <p>The median benchmark got 2.9× as fast. On an Intel MacBook Pro (Skylake), the median is 2.9× as well, but parsing floating-point numbers gained more (<code>canada.json</code> 6.1× instead of 3.4×) and writing integers less (<code>dump()</code> 1.4–2.3× instead of 2.2–3.8×); <a href=#b-3120-against-3130>Appendix B</a> has both columns. Copying and comparing values gained the least, and the largest gains come from fixing algorithms rather than tuning them (theme <a class=nj-theme href=#theme-7 title="theme 7">7</a>).</p> <p>Eight themes did most of the work:</p> <div class=nj-theme-list> <ul> <li><a class=nj-theme href=#theme-1 title="theme 1">1</a> <a href=#theme-1>Specialize for each input source</a>: a dedicated reader for each of strings, streams, and <code>FILE*</code>, instead of one character at a time for all of them.</li> <li><a class=nj-theme href=#theme-2 title="theme 2">2</a> <a href=#theme-2>Work on words, not bytes</a>: 8 bytes per step with plain integer arithmetic, 16 with <abbr title="Streaming SIMD Extensions 2">SSE2</abbr> and <abbr title="Arm SIMD instruction set extension">NEON</abbr>.</li> <li><a class=nj-theme href=#theme-3 title="theme 3">3</a> <a href=#theme-3>Own the number conversions</a>: no <code>strtod</code>, no locale.</li> <li><a class=nj-theme href=#theme-4 title="theme 4">4</a> <a href=#theme-4>Don't do unnecessary work</a>: positions, copies, and conversions that only matter on an error or for a rare caller.</li> <li><a class=nj-theme href=#theme-5 title="theme 5">5</a> <a href=#theme-5>Read the assembly</a>: stack canaries, missed inlining, aliasing, and branches the compiler chose.</li> <li><a class=nj-theme href=#theme-6 title="theme 6">6</a> <a href=#theme-6>Write through a cursor</a>: no virtual call per character, no allocation per call, no branch per integer.</li> <li><a class=nj-theme href=#theme-7 title="theme 7">7</a> <a href=#theme-7>Fix the algorithm first</a>: seven operations were quadratic or worse.</li> <li><a class=nj-theme href=#theme-8 title="theme 8">8</a> <a href=#theme-8>Build a different data structure</a> when the tree is the cost.</li> </ul> </div> <h2 id=where-the-time-went-a-timeline>Where the time went: a timeline<a class=headerlink href=#where-the-time-went-a-timeline title="Permanent link">&para;</a></h2> <p>The suite compares two points. To see which change did what, we compiled one small benchmark against the header of each of the 351 commits on <code>develop</code> that changed <code>json.hpp</code> or <code>json_view.hpp</code> from 3.12.0 to November 3, and of 3.13.0, and ran all of them interleaved. Four of the eight workloads we followed:</p> <ul> <li><code>parse()</code> of <code>citm_catalog.json</code>: the lexer's structure and whitespace handling, and building many small objects;</li> <li><code>parse()</code> of <code>canada.json</code>: converting text to floating-point numbers;</li> <li><code>dump()</code> of <code>twitter.json</code>: writing strings;</li> <li><code>from_cbor()</code> of <code>twitter.json</code>: reading a binary format.</li> </ul> <p>Each panel shows the speedup over 3.12.0 after each commit, on a logarithmic scale. The badges above the steps name the theme below that explains them. Moving code around changes a build's speed by a few percent on its own, so only the larger steps mean something.</p> <div class=nj-charts-grid-wrap> <div class=nj-fig-wrap> <p><svg class="nj-fig nj-charts nj-charts--timeline" viewbox="0 0 340 270" role=img aria-labelledby="nj-blog-tl-parse_citm nj-blog-tl-parse_citm-d" xmlns=http://www.w3.org/2000/svg> <title id=nj-blog-tl-parse_citm>parse() citm_catalog.json: speedup over 3.12.0 by commit</title> <desc id=nj-blog-tl-parse_citm-d>parse() citm_catalog.json: speedup over 3.12.0 at each of 353 commits, ending at 3.3x. Labeled steps, by theme: 4, 1, 4, 4, 2, 4.</desc> <text class=nj-charts-panel x=8 y=18>parse() citm_catalog.json</text> <line class=nj-charts-grid x1=44 y1=208 x2=330 y2=208 /> <text class="nj-charts-tick nj-charts-tick--r" x=38 y=212>1&#215;</text> <line class=nj-charts-grid x1=44 y1=160.667 x2=330 y2=160.667 /> <text class="nj-charts-tick nj-charts-tick--r" x=38 y=164.667>2&#215;</text> <line class=nj-charts-grid x1=44 y1=113.333 x2=330 y2=113.333 /> <text class="nj-charts-tick nj-charts-tick--r" x=38 y=117.333>4&#215;</text> <line class=nj-charts-grid x1=44 y1=66 x2=330 y2=66 /> <text class="nj-charts-tick nj-charts-tick--r" x=38 y=70>8&#215;</text> <line class=nj-charts-axis x1=44 y1=208 x2=44 y2=212 /> <text class=nj-charts-tick x=44 y=225>3.12.0</text> <line class=nj-charts-axis x1=117.938 y1=208 x2=117.938 y2=212 /> <text class=nj-charts-tick x=117.938 y=225>Sep 2026</text> <line class=nj-charts-axis x1=198.375 y1=208 x2=198.375 y2=212 /> <text class=nj-charts-tick x=198.375 y=225>Oct</text> <polyline class=nj-charts-json points="44.0,208.0 44.8,208.0 44.8,208.2 45.6,208.2 45.6,207.8 46.4,207.8 46.4,207.5 47.2,207.5 47.2,206.5 48.1,206.5 48.1,208.3 48.9,208.3 48.9,207.3 49.7,207.3 49.7,206.8 50.5,206.8 50.5,207.8 51.3,207.8 51.3,206.8 52.1,206.8 52.1,207.3 52.9,207.3 52.9,207.6 53.8,207.6 53.8,207.8 54.6,207.8 54.6,207.0 55.4,207.0 55.4,207.3 56.2,207.3 56.2,207.2 57.0,207.2 57.0,207.4 57.8,207.4 57.8,207.5 58.6,207.5 58.6,207.4 59.4,207.4 59.4,206.6 60.2,206.6 60.2,207.6 61.1,207.6 61.1,207.6 61.9,207.6 61.9,207.2 62.7,207.2 62.7,207.0 63.5,207.0 63.5,207.6 64.3,207.6 64.3,206.7 65.1,206.7 65.1,207.4 65.9,207.4 65.9,206.8 66.8,206.8 66.8,207.3 67.6,207.3 67.6,207.7 68.4,207.7 68.4,207.9 69.2,207.9 69.2,207.2 70.0,207.2 70.0,206.4 70.8,206.4 70.8,207.6 71.6,207.6 71.6,206.4 72.4,206.4 72.4,208.0 73.2,208.0 73.2,207.4 74.1,207.4 74.1,206.5 74.9,206.5 74.9,207.5 75.7,207.5 75.7,207.2 76.5,207.2 76.5,206.9 77.3,206.9 77.3,207.6 78.1,207.6 78.1,207.6 78.9,207.6 78.9,207.0 79.8,207.0 79.8,206.9 80.6,206.9 80.6,208.0 81.4,208.0 81.4,207.6 82.2,207.6 82.2,206.6 83.0,206.6 83.0,206.8 83.8,206.8 83.8,207.3 84.6,207.3 84.6,206.9 85.4,206.9 85.4,207.6 86.2,207.6 86.2,207.1 87.1,207.1 87.1,207.6 87.9,207.6 87.9,207.9 88.7,207.9 88.7,178.2 89.5,178.2 89.5,177.5 90.3,177.5 90.3,177.7 91.1,177.7 91.1,177.6 91.9,177.6 91.9,177.7 92.8,177.7 92.8,177.1 93.6,177.1 93.6,176.8 94.4,176.8 94.4,177.7 95.2,177.7 95.2,177.6 96.0,177.6 96.0,176.8 96.8,176.8 96.8,177.8 97.6,177.8 97.6,177.0 98.4,177.0 98.4,176.8 99.2,176.8 99.2,178.0 100.1,178.0 100.1,178.1 100.9,178.1 100.9,177.6 101.7,177.6 101.7,177.6 102.5,177.6 102.5,177.4 103.3,177.4 103.3,177.6 104.1,177.6 104.1,177.8 104.9,177.8 104.9,177.5 105.8,177.5 105.8,177.9 106.6,177.9 106.6,177.7 107.4,177.7 107.4,175.9 108.2,175.9 108.2,177.5 109.0,177.5 109.0,177.6 109.8,177.6 109.8,177.6 110.6,177.6 110.6,176.9 111.4,176.9 111.4,177.5 112.2,177.5 112.2,177.4 113.1,177.4 113.1,177.4 113.9,177.4 113.9,176.9 114.7,176.9 114.7,177.9 115.5,177.9 115.5,177.3 116.3,177.3 116.3,176.6 117.1,176.6 117.1,177.4 117.9,177.4 117.9,177.5 118.8,177.5 118.8,177.5 119.6,177.5 119.6,177.4 120.4,177.4 120.4,177.0 121.2,177.0 121.2,177.7 122.0,177.7 122.0,176.2 122.8,176.2 122.8,176.9 123.6,176.9 123.6,177.5 124.4,177.5 124.4,177.8 125.3,177.8 125.3,177.8 126.1,177.8 126.1,177.9 126.9,177.9 126.9,177.3 127.7,177.3 127.7,177.5 128.5,177.5 128.5,177.4 129.3,177.4 129.3,177.1 130.1,177.1 130.1,162.5 130.9,162.5 130.9,162.2 131.8,162.2 131.8,161.8 132.6,161.8 132.6,162.2 133.4,162.2 133.4,161.2 134.2,161.2 134.2,160.7 135.0,160.7 135.0,159.4 135.8,159.4 135.8,160.3 136.6,160.3 136.6,160.4 137.4,160.4 137.4,160.6 138.2,160.6 138.2,159.5 139.1,159.5 139.1,160.4 139.9,160.4 139.9,159.6 140.7,159.6 140.7,160.0 141.5,160.0 141.5,159.9 142.3,159.9 142.3,160.2 143.1,160.2 143.1,159.6 143.9,159.6 143.9,160.8 144.8,160.8 144.8,160.1 145.6,160.1 145.6,159.1 146.4,159.1 146.4,159.7 147.2,159.7 147.2,159.9 148.0,159.9 148.0,160.5 148.8,160.5 148.8,160.2 149.6,160.2 149.6,159.9 150.4,159.9 150.4,160.5 151.2,160.5 151.2,160.5 152.1,160.5 152.1,160.6 152.9,160.6 152.9,159.7 153.7,159.7 153.7,159.5 154.5,159.5 154.5,160.0 155.3,160.0 155.3,160.2 156.1,160.2 156.1,160.0 156.9,160.0 156.9,160.6 157.8,160.6 157.8,159.9 158.6,159.9 158.6,160.2 159.4,160.2 159.4,160.1 160.2,160.1 160.2,160.8 161.0,160.8 161.0,159.2 161.8,159.2 161.8,159.6 162.6,159.6 162.6,159.2 163.4,159.2 163.4,160.0 164.2,160.0 164.2,159.4 165.1,159.4 165.1,159.6 165.9,159.6 165.9,159.5 166.7,159.5 166.7,160.1 167.5,160.1 167.5,159.0 168.3,159.0 168.3,159.4 169.1,159.4 169.1,160.2 169.9,160.2 169.9,161.4 170.8,161.4 170.8,161.7 171.6,161.7 171.6,161.6 172.4,161.6 172.4,160.3 173.2,160.3 173.2,161.1 174.0,161.1 174.0,161.2 174.8,161.2 174.8,161.7 175.6,161.7 175.6,161.2 176.4,161.2 176.4,160.4 177.2,160.4 177.2,161.6 178.1,161.6 178.1,160.6 178.9,160.6 178.9,161.4 179.7,161.4 179.7,161.3 180.5,161.3 180.5,161.3 181.3,161.3 181.3,161.7 182.1,161.7 182.1,161.2 182.9,161.2 182.9,160.1 183.8,160.1 183.8,160.9 184.6,160.9 184.6,161.5 185.4,161.5 185.4,160.6 186.2,160.6 186.2,161.9 187.0,161.9 187.0,161.4 187.8,161.4 187.8,160.1 188.6,160.1 188.6,160.6 189.4,160.6 189.4,162.0 190.2,162.0 190.2,161.5 191.1,161.5 191.1,162.0 191.9,162.0 191.9,161.3 192.7,161.3 192.7,162.3 193.5,162.3 193.5,162.1 194.3,162.1 194.3,160.8 195.1,160.8 195.1,161.5 195.9,161.5 195.9,161.4 196.8,161.4 196.8,162.2 197.6,162.2 197.6,161.4 198.4,161.4 198.4,161.4 199.2,161.4 199.2,161.8 200.0,161.8 200.0,160.7 200.8,160.7 200.8,160.5 201.6,160.5 201.6,160.5 202.4,160.5 202.4,159.3 203.2,159.3 203.2,159.4 204.1,159.4 204.1,160.4 204.9,160.4 204.9,160.1 205.7,160.1 205.7,160.4 206.5,160.4 206.5,160.4 207.3,160.4 207.3,160.8 208.1,160.8 208.1,159.8 208.9,159.8 208.9,159.4 209.8,159.4 209.8,160.5 210.6,160.5 210.6,160.1 211.4,160.1 211.4,160.7 212.2,160.7 212.2,160.6 213.0,160.6 213.0,159.5 213.8,159.5 213.8,161.1 214.6,161.1 214.6,161.3 215.4,161.3 215.4,161.0 216.2,161.0 216.2,160.8 217.1,160.8 217.1,159.6 217.9,159.6 217.9,161.0 218.7,161.0 218.7,160.6 219.5,160.6 219.5,160.6 220.3,160.6 220.3,161.4 221.1,161.4 221.1,159.8 221.9,159.8 221.9,160.2 222.8,160.2 222.8,155.4 223.6,155.4 223.6,156.1 224.4,156.1 224.4,155.2 225.2,155.2 225.2,156.3 226.0,156.3 226.0,156.1 226.8,156.1 226.8,155.8 227.6,155.8 227.6,156.5 228.4,156.5 228.4,155.8 229.2,155.8 229.2,155.9 230.1,155.9 230.1,155.7 230.9,155.7 230.9,155.0 231.7,155.0 231.7,156.1 232.5,156.1 232.5,156.5 233.3,156.5 233.3,156.3 234.1,156.3 234.1,155.6 234.9,155.6 234.9,154.9 235.8,154.9 235.8,155.8 236.6,155.8 236.6,155.5 237.4,155.5 237.4,155.0 238.2,155.0 238.2,155.2 239.0,155.2 239.0,155.4 239.8,155.4 239.8,155.4 240.6,155.4 240.6,155.6 241.4,155.6 241.4,156.0 242.3,156.0 242.3,155.7 243.1,155.7 243.1,147.1 243.9,147.1 243.9,138.2 244.7,138.2 244.7,138.0 245.5,138.0 245.5,137.7 246.3,137.7 246.3,137.6 247.1,137.6 247.1,137.8 247.9,137.8 247.9,137.7 248.8,137.7 248.8,137.2 249.6,137.2 249.6,137.3 250.4,137.3 250.4,137.5 251.2,137.5 251.2,137.1 252.0,137.1 252.0,135.2 252.8,135.2 252.8,135.1 253.6,135.1 253.6,132.3 254.4,132.3 254.4,133.6 255.2,133.6 255.2,133.4 256.1,133.4 256.1,133.9 256.9,133.9 256.9,133.2 257.7,133.2 257.7,132.9 258.5,132.9 258.5,131.7 259.3,131.7 259.3,132.8 260.1,132.8 260.1,133.0 260.9,133.0 260.9,132.8 261.8,132.8 261.8,132.8 262.6,132.8 262.6,132.6 263.4,132.6 263.4,133.3 264.2,133.3 264.2,131.7 265.0,131.7 265.0,132.3 265.8,132.3 265.8,132.7 266.6,132.7 266.6,133.3 267.4,133.3 267.4,131.5 268.2,131.5 268.2,132.3 269.1,132.3 269.1,133.4 269.9,133.4 269.9,132.1 270.7,132.1 270.7,132.8 271.5,132.8 271.5,131.2 272.3,131.2 272.3,130.8 273.1,130.8 273.1,130.8 273.9,130.8 273.9,129.9 274.8,129.9 274.8,130.1 275.6,130.1 275.6,131.1 276.4,131.1 276.4,129.7 277.2,129.7 277.2,129.2 278.0,129.2 278.0,129.7 278.8,129.7 278.8,129.8 279.6,129.8 279.6,128.6 280.4,128.6 280.4,130.0 281.2,130.0 281.2,130.0 282.1,130.0 282.1,129.4 282.9,129.4 282.9,129.3 283.7,129.3 283.7,130.1 284.5,130.1 284.5,129.6 285.3,129.6 285.3,125.7 286.1,125.7 286.1,125.7 286.9,125.7 286.9,125.7 287.8,125.7 287.8,126.1 288.6,126.1 288.6,126.1 289.4,126.1 289.4,125.2 290.2,125.2 290.2,125.8 291.0,125.8 291.0,126.1 291.8,126.1 291.8,125.7 292.6,125.7 292.6,125.7 293.4,125.7 293.4,125.7 294.2,125.7 294.2,124.7 295.1,124.7 295.1,126.1 295.9,126.1 295.9,126.2 296.7,126.2 296.7,125.8 297.5,125.8 297.5,126.2 298.3,126.2 298.3,125.9 299.1,125.9 299.1,125.8 299.9,125.8 299.9,125.8 300.8,125.8 300.8,125.7 301.6,125.7 301.6,126.6 302.4,126.6 302.4,125.5 303.2,125.5 303.2,126.4 304.0,126.4 304.0,126.1 304.8,126.1 304.8,126.7 305.6,126.7 305.6,125.8 306.4,125.8 306.4,125.9 307.2,125.9 307.2,125.5 308.1,125.5 308.1,126.4 308.9,126.4 308.9,126.9 309.7,126.9 309.7,126.0 310.5,126.0 310.5,125.8 311.3,125.8 311.3,126.2 312.1,126.2 312.1,126.3 312.9,126.3 312.9,125.9 313.8,125.9 313.8,125.4 314.6,125.4 314.6,127.1 315.4,127.1 315.4,126.0 316.2,126.0 316.2,126.4 317.0,126.4 317.0,125.6 317.8,125.6 317.8,125.7 318.6,125.7 318.6,125.5 319.4,125.5 319.4,125.5 320.2,125.5 320.2,125.4 321.1,125.4 321.1,126.1 321.9,126.1 321.9,125.4 322.7,125.4 322.7,125.9 323.5,125.9 323.5,125.5 324.3,125.5 324.3,125.9 325.1,125.9 325.1,125.0 325.9,125.0 325.9,124.6 326.8,124.6 326.8,125.0 327.6,125.0 327.6,124.9 328.4,124.9 328.4,125.0 329.2,125.0 329.2,125.1 330.0,125.1 330.0,125.9"/> <circle class=nj-charts-json-dot cx=88.7 cy=178.2 r=3.5><title>#5234: 1.55&#215;</title></circle> <line class=nj-charts-grid x1=88.7 y1=54.0 x2=88.7 y2=173.2 stroke-dasharray="2 2"/> <circle class=nj-theme-dot cx=88.7 cy=46.0 r=7.5 /> <text class=nj-theme-num x=88.7 y=50.0 text-anchor=middle>4</text> <circle class=nj-charts-json-dot cx=130.1 cy=162.5 r=3.5><title>#5283: 1.95&#215;</title></circle> <line class=nj-charts-grid x1=130.1 y1=54.0 x2=130.1 y2=157.5 stroke-dasharray="2 2"/> <circle class=nj-theme-dot cx=130.1 cy=46.0 r=7.5 /> <text class=nj-theme-num x=130.1 y=50.0 text-anchor=middle>1</text> <circle class=nj-charts-json-dot cx=222.8 cy=155.4 r=3.5><title>#5592: 2.2&#215;</title></circle> <line class=nj-charts-grid x1=222.8 y1=54.0 x2=222.8 y2=150.4 stroke-dasharray="2 2"/> <circle class=nj-theme-dot cx=222.8 cy=46.0 r=7.5 /> <text class=nj-theme-num x=222.8 y=50.0 text-anchor=middle>4</text> <circle class=nj-charts-json-dot cx=243.1 cy=147.1 r=3.5><title>#5809: 2.4&#215;</title></circle> <circle class=nj-charts-json-dot cx=243.9 cy=138.2 r=3.5><title>#5810: 2.8&#215;</title></circle> <line class=nj-charts-grid x1=243.9 y1=36.0 x2=243.9 y2=133.2 stroke-dasharray="2 2"/> <circle class=nj-theme-dot cx=234.9 cy=28.0 r=7.5 /> <text class=nj-theme-num x=234.9 y=32.0 text-anchor=middle>4</text> <circle class=nj-theme-dot cx=252.9 cy=28.0 r=7.5 /> <text class=nj-theme-num x=252.9 y=32.0 text-anchor=middle>2</text> <circle class=nj-charts-json-dot cx=285.3 cy=125.7 r=3.5><title>#5882: 3.3&#215;</title></circle> <line class=nj-charts-grid x1=285.3 y1=54.0 x2=285.3 y2=120.7 stroke-dasharray="2 2"/> <circle class=nj-theme-dot cx=285.3 cy=46.0 r=7.5 /> <text class=nj-theme-num x=285.3 y=50.0 text-anchor=middle>4</text> <line class=nj-charts-axis x1=44 y1=208 x2=330 y2=208 /> <text class=nj-charts-note x=8 y=262>speedup over 3.12.0 (log scale), more is better</text> </svg></p> </div> <div class=nj-fig-wrap> <p><svg class="nj-fig nj-charts nj-charts--timeline" viewbox="0 0 340 270" role=img aria-labelledby="nj-blog-tl-parse_canada nj-blog-tl-parse_canada-d" xmlns=http://www.w3.org/2000/svg> <title id=nj-blog-tl-parse_canada>parse() canada.json: speedup over 3.12.0 by commit</title> <desc id=nj-blog-tl-parse_canada-d>parse() canada.json: speedup over 3.12.0 at each of 353 commits, ending at 2.8x. Labeled steps, by theme: 4, 1, 3, 3, 3, 4.</desc> <text class=nj-charts-panel x=8 y=18>parse() canada.json</text> <line class=nj-charts-grid x1=44 y1=208 x2=330 y2=208 /> <text class="nj-charts-tick nj-charts-tick--r" x=38 y=212>1&#215;</text> <line class=nj-charts-grid x1=44 y1=137 x2=330 y2=137 /> <text class="nj-charts-tick nj-charts-tick--r" x=38 y=141>2&#215;</text> <line class=nj-charts-grid x1=44 y1=66 x2=330 y2=66 /> <text class="nj-charts-tick nj-charts-tick--r" x=38 y=70>4&#215;</text> <line class=nj-charts-axis x1=44 y1=208 x2=44 y2=212 /> <text class=nj-charts-tick x=44 y=225>3.12.0</text> <line class=nj-charts-axis x1=117.938 y1=208 x2=117.938 y2=212 /> <text class=nj-charts-tick x=117.938 y=225>Sep 2026</text> <line class=nj-charts-axis x1=198.375 y1=208 x2=198.375 y2=212 /> <text class=nj-charts-tick x=198.375 y=225>Oct</text> <polyline class=nj-charts-json points="44.0,208.0 44.8,208.0 44.8,208.2 45.6,208.2 45.6,208.1 46.4,208.1 46.4,207.7 47.2,207.7 47.2,207.2 48.1,207.2 48.1,208.0 48.9,208.0 48.9,208.2 49.7,208.2 49.7,207.8 50.5,207.8 50.5,208.5 51.3,208.5 51.3,207.3 52.1,207.3 52.1,208.0 52.9,208.0 52.9,209.1 53.8,209.1 53.8,208.5 54.6,208.5 54.6,208.1 55.4,208.1 55.4,207.7 56.2,207.7 56.2,209.8 57.0,209.8 57.0,208.6 57.8,208.6 57.8,208.1 58.6,208.1 58.6,208.1 59.4,208.1 59.4,207.0 60.2,207.0 60.2,207.8 61.1,207.8 61.1,207.6 61.9,207.6 61.9,208.1 62.7,208.1 62.7,208.4 63.5,208.4 63.5,207.8 64.3,207.8 64.3,207.4 65.1,207.4 65.1,208.3 65.9,208.3 65.9,207.3 66.8,207.3 66.8,207.8 67.6,207.8 67.6,207.9 68.4,207.9 68.4,207.9 69.2,207.9 69.2,207.5 70.0,207.5 70.0,207.5 70.8,207.5 70.8,208.1 71.6,208.1 71.6,208.1 72.4,208.1 72.4,207.9 73.2,207.9 73.2,207.8 74.1,207.8 74.1,207.1 74.9,207.1 74.9,207.6 75.7,207.6 75.7,207.8 76.5,207.8 76.5,207.3 77.3,207.3 77.3,207.6 78.1,207.6 78.1,208.6 78.9,208.6 78.9,206.5 79.8,206.5 79.8,208.0 80.6,208.0 80.6,208.7 81.4,208.7 81.4,208.0 82.2,208.0 82.2,207.7 83.0,207.7 83.0,208.4 83.8,208.4 83.8,207.9 84.6,207.9 84.6,207.5 85.4,207.5 85.4,207.9 86.2,207.9 86.2,207.4 87.1,207.4 87.1,207.5 87.9,207.5 87.9,208.5 88.7,208.5 88.7,197.5 89.5,197.5 89.5,197.9 90.3,197.9 90.3,196.9 91.1,196.9 91.1,197.0 91.9,197.0 91.9,197.7 92.8,197.7 92.8,196.0 93.6,196.0 93.6,197.3 94.4,197.3 94.4,198.1 95.2,198.1 95.2,197.4 96.0,197.4 96.0,197.0 96.8,197.0 96.8,197.5 97.6,197.5 97.6,197.3 98.4,197.3 98.4,197.7 99.2,197.7 99.2,197.7 100.1,197.7 100.1,197.6 100.9,197.6 100.9,196.9 101.7,196.9 101.7,197.9 102.5,197.9 102.5,197.9 103.3,197.9 103.3,197.6 104.1,197.6 104.1,197.6 104.9,197.6 104.9,197.6 105.8,197.6 105.8,198.1 106.6,198.1 106.6,198.0 107.4,198.0 107.4,195.3 108.2,195.3 108.2,196.6 109.0,196.6 109.0,197.9 109.8,197.9 109.8,197.0 110.6,197.0 110.6,196.3 111.4,196.3 111.4,196.8 112.2,196.8 112.2,196.6 113.1,196.6 113.1,196.6 113.9,196.6 113.9,197.7 114.7,197.7 114.7,197.5 115.5,197.5 115.5,198.1 116.3,198.1 116.3,195.9 117.1,195.9 117.1,197.5 117.9,197.5 117.9,197.6 118.8,197.6 118.8,196.7 119.6,196.7 119.6,197.0 120.4,197.0 120.4,198.0 121.2,198.0 121.2,197.0 122.0,197.0 122.0,197.2 122.8,197.2 122.8,196.6 123.6,196.6 123.6,197.0 124.4,197.0 124.4,197.2 125.3,197.2 125.3,197.6 126.1,197.6 126.1,197.8 126.9,197.8 126.9,197.2 127.7,197.2 127.7,197.6 128.5,197.6 128.5,197.3 129.3,197.3 129.3,197.0 130.1,197.0 130.1,168.6 130.9,168.6 130.9,169.7 131.8,169.7 131.8,170.1 132.6,170.1 132.6,168.9 133.4,168.9 133.4,168.3 134.2,168.3 134.2,169.9 135.0,169.9 135.0,168.7 135.8,168.7 135.8,168.3 136.6,168.3 136.6,169.7 137.4,169.7 137.4,170.9 138.2,170.9 138.2,168.1 139.1,168.1 139.1,170.2 139.9,170.2 139.9,169.1 140.7,169.1 140.7,170.1 141.5,170.1 141.5,168.5 142.3,168.5 142.3,169.7 143.1,169.7 143.1,170.1 143.9,170.1 143.9,169.8 144.8,169.8 144.8,169.1 145.6,169.1 145.6,167.2 146.4,167.2 146.4,169.7 147.2,169.7 147.2,168.6 148.0,168.6 148.0,170.3 148.8,170.3 148.8,169.7 149.6,169.7 149.6,168.7 150.4,168.7 150.4,169.3 151.2,169.3 151.2,172.3 152.1,172.3 152.1,171.2 152.9,171.2 152.9,169.1 153.7,169.1 153.7,167.8 154.5,167.8 154.5,169.3 155.3,169.3 155.3,169.1 156.1,169.1 156.1,168.5 156.9,168.5 156.9,168.7 157.8,168.7 157.8,168.6 158.6,168.6 158.6,169.0 159.4,169.0 159.4,168.5 160.2,168.5 160.2,170.9 161.0,170.9 161.0,169.9 161.8,169.9 161.8,168.0 162.6,168.0 162.6,168.8 163.4,168.8 163.4,168.5 164.2,168.5 164.2,168.5 165.1,168.5 165.1,169.9 165.9,169.9 165.9,169.1 166.7,169.1 166.7,168.6 167.5,168.6 167.5,168.6 168.3,168.6 168.3,169.4 169.1,169.4 169.1,169.1 169.9,169.1 169.9,170.2 170.8,170.2 170.8,178.0 171.6,178.0 171.6,177.3 172.4,177.3 172.4,167.7 173.2,167.7 173.2,168.5 174.0,168.5 174.0,168.7 174.8,168.7 174.8,168.5 175.6,168.5 175.6,168.8 176.4,168.8 176.4,168.0 177.2,168.0 177.2,168.2 178.1,168.2 178.1,167.7 178.9,167.7 178.9,167.5 179.7,167.5 179.7,168.1 180.5,168.1 180.5,168.3 181.3,168.3 181.3,168.1 182.1,168.1 182.1,168.1 182.9,168.1 182.9,167.5 183.8,167.5 183.8,166.5 184.6,166.5 184.6,169.1 185.4,169.1 185.4,168.6 186.2,168.6 186.2,168.5 187.0,168.5 187.0,168.1 187.8,168.1 187.8,167.3 188.6,167.3 188.6,168.0 189.4,168.0 189.4,168.3 190.2,168.3 190.2,168.6 191.1,168.6 191.1,169.0 191.9,169.0 191.9,166.6 192.7,166.6 192.7,169.4 193.5,169.4 193.5,169.3 194.3,169.3 194.3,167.3 195.1,167.3 195.1,168.5 195.9,168.5 195.9,167.1 196.8,167.1 196.8,169.4 197.6,169.4 197.6,168.9 198.4,168.9 198.4,167.4 199.2,167.4 199.2,168.4 200.0,168.4 200.0,168.5 200.8,168.5 200.8,166.9 201.6,166.9 201.6,168.7 202.4,168.7 202.4,165.7 203.2,165.7 203.2,167.0 204.1,167.0 204.1,166.6 204.9,166.6 204.9,167.4 205.7,167.4 205.7,167.6 206.5,167.6 206.5,167.2 207.3,167.2 207.3,167.4 208.1,167.4 208.1,166.6 208.9,166.6 208.9,166.2 209.8,166.2 209.8,168.4 210.6,168.4 210.6,167.2 211.4,167.2 211.4,166.7 212.2,166.7 212.2,166.5 213.0,166.5 213.0,166.0 213.8,166.0 213.8,167.4 214.6,167.4 214.6,167.3 215.4,167.3 215.4,167.3 216.2,167.3 216.2,168.3 217.1,168.3 217.1,166.4 217.9,166.4 217.9,167.9 218.7,167.9 218.7,166.9 219.5,166.9 219.5,168.0 220.3,168.0 220.3,167.9 221.1,167.9 221.1,167.0 221.9,167.0 221.9,160.5 222.8,160.5 222.8,154.8 223.6,154.8 223.6,155.7 224.4,155.7 224.4,154.9 225.2,154.9 225.2,155.9 226.0,155.9 226.0,156.3 226.8,156.3 226.8,155.9 227.6,155.9 227.6,155.9 228.4,155.9 228.4,156.0 229.2,156.0 229.2,156.2 230.1,156.2 230.1,155.7 230.9,155.7 230.9,154.9 231.7,154.9 231.7,155.2 232.5,155.2 232.5,156.4 233.3,156.4 233.3,155.1 234.1,155.1 234.1,155.0 234.9,155.0 234.9,154.0 235.8,154.0 235.8,155.0 236.6,155.0 236.6,154.8 237.4,154.8 237.4,156.0 238.2,156.0 238.2,155.0 239.0,155.0 239.0,156.4 239.8,156.4 239.8,154.7 240.6,154.7 240.6,154.2 241.4,154.2 241.4,155.6 242.3,155.6 242.3,155.9 243.1,155.9 243.1,153.1 243.9,153.1 243.9,154.8 244.7,154.8 244.7,154.7 245.5,154.7 245.5,139.8 246.3,139.8 246.3,139.2 247.1,139.2 247.1,140.2 247.9,140.2 247.9,139.7 248.8,139.7 248.8,140.5 249.6,140.5 249.6,140.0 250.4,140.0 250.4,139.9 251.2,139.9 251.2,140.2 252.0,140.2 252.0,135.7 252.8,135.7 252.8,136.3 253.6,136.3 253.6,138.4 254.4,138.4 254.4,137.9 255.2,137.9 255.2,138.7 256.1,138.7 256.1,137.2 256.9,137.2 256.9,137.6 257.7,137.6 257.7,137.0 258.5,137.0 258.5,135.6 259.3,135.6 259.3,136.4 260.1,136.4 260.1,137.9 260.9,137.9 260.9,137.5 261.8,137.5 261.8,137.1 262.6,137.1 262.6,135.5 263.4,135.5 263.4,137.0 264.2,137.0 264.2,135.3 265.0,135.3 265.0,137.0 265.8,137.0 265.8,135.6 266.6,135.6 266.6,137.2 267.4,137.2 267.4,135.8 268.2,135.8 268.2,138.0 269.1,138.0 269.1,137.5 269.9,137.5 269.9,139.2 270.7,139.2 270.7,140.1 271.5,140.1 271.5,127.4 272.3,127.4 272.3,121.3 273.1,121.3 273.1,121.7 273.9,121.7 273.9,120.9 274.8,120.9 274.8,122.0 275.6,122.0 275.6,120.2 276.4,120.2 276.4,119.5 277.2,119.5 277.2,121.6 278.0,121.6 278.0,119.3 278.8,119.3 278.8,119.8 279.6,119.8 279.6,120.0 280.4,120.0 280.4,120.9 281.2,120.9 281.2,119.0 282.1,119.0 282.1,119.4 282.9,119.4 282.9,120.3 283.7,120.3 283.7,120.4 284.5,120.4 284.5,119.2 285.3,119.2 285.3,102.2 286.1,102.2 286.1,102.4 286.9,102.4 286.9,102.2 287.8,102.2 287.8,102.4 288.6,102.4 288.6,102.0 289.4,102.0 289.4,101.3 290.2,101.3 290.2,101.9 291.0,101.9 291.0,102.3 291.8,102.3 291.8,102.0 292.6,102.0 292.6,101.9 293.4,101.9 293.4,101.9 294.2,101.9 294.2,100.7 295.1,100.7 295.1,102.8 295.9,102.8 295.9,102.3 296.7,102.3 296.7,102.0 297.5,102.0 297.5,102.2 298.3,102.2 298.3,102.2 299.1,102.2 299.1,102.2 299.9,102.2 299.9,102.9 300.8,102.9 300.8,101.9 301.6,101.9 301.6,106.4 302.4,106.4 302.4,101.8 303.2,101.8 303.2,103.3 304.0,103.3 304.0,103.2 304.8,103.2 304.8,102.5 305.6,102.5 305.6,101.5 306.4,101.5 306.4,102.4 307.2,102.4 307.2,102.0 308.1,102.0 308.1,103.1 308.9,103.1 308.9,103.7 309.7,103.7 309.7,101.9 310.5,101.9 310.5,101.9 311.3,101.9 311.3,102.6 312.1,102.6 312.1,103.7 312.9,103.7 312.9,102.2 313.8,102.2 313.8,100.6 314.6,100.6 314.6,102.6 315.4,102.6 315.4,102.1 316.2,102.1 316.2,101.3 317.0,101.3 317.0,100.6 317.8,100.6 317.8,100.6 318.6,100.6 318.6,100.7 319.4,100.7 319.4,101.1 320.2,101.1 320.2,101.4 321.1,101.4 321.1,101.6 321.9,101.6 321.9,101.4 322.7,101.4 322.7,101.7 323.5,101.7 323.5,103.8 324.3,103.8 324.3,104.2 325.1,104.2 325.1,103.1 325.9,103.1 325.9,102.9 326.8,102.9 326.8,103.4 327.6,103.4 327.6,102.7 328.4,102.7 328.4,102.4 329.2,102.4 329.2,103.0 330.0,103.0 330.0,102.9"/> <circle class=nj-charts-json-dot cx=88.7 cy=197.5 r=3.5><title>#5234: 1.11&#215;</title></circle> <line class=nj-charts-grid x1=88.7 y1=54.0 x2=88.7 y2=192.5 stroke-dasharray="2 2"/> <circle class=nj-theme-dot cx=88.7 cy=46.0 r=7.5 /> <text class=nj-theme-num x=88.7 y=50.0 text-anchor=middle>4</text> <circle class=nj-charts-json-dot cx=130.1 cy=168.6 r=3.5><title>#5283: 1.47&#215;</title></circle> <line class=nj-charts-grid x1=130.1 y1=54.0 x2=130.1 y2=163.6 stroke-dasharray="2 2"/> <circle class=nj-theme-dot cx=130.1 cy=46.0 r=7.5 /> <text class=nj-theme-num x=130.1 y=50.0 text-anchor=middle>1</text> <circle class=nj-charts-json-dot cx=172.4 cy=167.7 r=3.5><title>#5617: 1.48&#215;</title></circle> <line class=nj-charts-grid x1=172.4 y1=54.0 x2=172.4 y2=162.7 stroke-dasharray="2 2"/> <circle class=nj-theme-dot cx=172.4 cy=46.0 r=7.5 /> <text class=nj-theme-num x=172.4 y=50.0 text-anchor=middle>3</text> <circle class=nj-charts-json-dot cx=245.5 cy=139.8 r=3.5><title>#5738: 1.95&#215;</title></circle> <line class=nj-charts-grid x1=245.5 y1=54.0 x2=245.5 y2=134.8 stroke-dasharray="2 2"/> <circle class=nj-theme-dot cx=245.5 cy=46.0 r=7.5 /> <text class=nj-theme-num x=245.5 y=50.0 text-anchor=middle>3</text> <circle class=nj-charts-json-dot cx=271.5 cy=127.4 r=3.5><title>#5851: 2.2&#215;</title></circle> <line class=nj-charts-grid x1=271.5 y1=54.0 x2=271.5 y2=122.4 stroke-dasharray="2 2"/> <circle class=nj-theme-dot cx=271.5 cy=46.0 r=7.5 /> <text class=nj-theme-num x=271.5 y=50.0 text-anchor=middle>3</text> <circle class=nj-charts-json-dot cx=285.3 cy=102.2 r=3.5><title>#5882: 2.8&#215;</title></circle> <line class=nj-charts-grid x1=285.3 y1=36.0 x2=285.3 y2=97.2 stroke-dasharray="2 2"/> <circle class=nj-theme-dot cx=285.3 cy=28.0 r=7.5 /> <text class=nj-theme-num x=285.3 y=32.0 text-anchor=middle>4</text> <line class=nj-charts-axis x1=44 y1=208 x2=330 y2=208 /> <text class=nj-charts-note x=8 y=262>speedup over 3.12.0 (log scale), more is better</text> </svg></p> </div> <div class=nj-fig-wrap> <p><svg class="nj-fig nj-charts nj-charts--timeline" viewbox="0 0 340 270" role=img aria-labelledby="nj-blog-tl-dump_twitter nj-blog-tl-dump_twitter-d" xmlns=http://www.w3.org/2000/svg> <title id=nj-blog-tl-dump_twitter>dump() twitter.json: speedup over 3.12.0 by commit</title> <desc id=nj-blog-tl-dump_twitter-d>dump() twitter.json: speedup over 3.12.0 at each of 353 commits, ending at 6.8x. Labeled steps, by theme: 6, 2, 2, 2.</desc> <text class=nj-charts-panel x=8 y=18>dump() twitter.json</text> <line class=nj-charts-grid x1=44 y1=208 x2=330 y2=208 /> <text class="nj-charts-tick nj-charts-tick--r" x=38 y=212>1&#215;</text> <line class=nj-charts-grid x1=44 y1=172.5 x2=330 y2=172.5 /> <text class="nj-charts-tick nj-charts-tick--r" x=38 y=176.5>2&#215;</text> <line class=nj-charts-grid x1=44 y1=137 x2=330 y2=137 /> <text class="nj-charts-tick nj-charts-tick--r" x=38 y=141>4&#215;</text> <line class=nj-charts-grid x1=44 y1=101.5 x2=330 y2=101.5 /> <text class="nj-charts-tick nj-charts-tick--r" x=38 y=105.5>8&#215;</text> <line class=nj-charts-grid x1=44 y1=66 x2=330 y2=66 /> <text class="nj-charts-tick nj-charts-tick--r" x=38 y=70>16&#215;</text> <line class=nj-charts-axis x1=44 y1=208 x2=44 y2=212 /> <text class=nj-charts-tick x=44 y=225>3.12.0</text> <line class=nj-charts-axis x1=117.938 y1=208 x2=117.938 y2=212 /> <text class=nj-charts-tick x=117.938 y=225>Sep 2026</text> <line class=nj-charts-axis x1=198.375 y1=208 x2=198.375 y2=212 /> <text class=nj-charts-tick x=198.375 y=225>Oct</text> <polyline class=nj-charts-json points="44.0,208.0 44.8,208.0 44.8,208.0 45.6,208.0 45.6,207.2 46.4,207.2 46.4,207.9 47.2,207.9 47.2,206.8 48.1,206.8 48.1,208.0 48.9,208.0 48.9,207.4 49.7,207.4 49.7,207.3 50.5,207.3 50.5,208.0 51.3,208.0 51.3,206.8 52.1,206.8 52.1,207.2 52.9,207.2 52.9,208.0 53.8,208.0 53.8,207.2 54.6,207.2 54.6,207.5 55.4,207.5 55.4,206.8 56.2,206.8 56.2,206.9 57.0,206.9 57.0,207.5 57.8,207.5 57.8,207.3 58.6,207.3 58.6,207.8 59.4,207.8 59.4,206.8 60.2,206.8 60.2,207.8 61.1,207.8 61.1,207.4 61.9,207.4 61.9,208.0 62.7,208.0 62.7,207.4 63.5,207.4 63.5,207.3 64.3,207.3 64.3,206.9 65.1,206.9 65.1,207.3 65.9,207.3 65.9,207.4 66.8,207.4 66.8,207.6 67.6,207.6 67.6,207.5 68.4,207.5 68.4,207.6 69.2,207.6 69.2,207.4 70.0,207.4 70.0,207.2 70.8,207.2 70.8,207.1 71.6,207.1 71.6,207.3 72.4,207.3 72.4,207.7 73.2,207.7 73.2,207.8 74.1,207.8 74.1,206.9 74.9,206.9 74.9,207.6 75.7,207.6 75.7,207.0 76.5,207.0 76.5,207.0 77.3,207.0 77.3,207.3 78.1,207.3 78.1,207.6 78.9,207.6 78.9,206.8 79.8,206.8 79.8,207.7 80.6,207.7 80.6,207.4 81.4,207.4 81.4,207.5 82.2,207.5 82.2,207.1 83.0,207.1 83.0,207.3 83.8,207.3 83.8,207.5 84.6,207.5 84.6,207.3 85.4,207.3 85.4,207.3 86.2,207.3 86.2,206.9 87.1,206.9 87.1,207.4 87.9,207.4 87.9,207.9 88.7,207.9 88.7,207.3 89.5,207.3 89.5,206.8 90.3,206.8 90.3,207.6 91.1,207.6 91.1,207.7 91.9,207.7 91.9,208.6 92.8,208.6 92.8,208.5 93.6,208.5 93.6,208.6 94.4,208.6 94.4,209.2 95.2,209.2 95.2,208.5 96.0,208.5 96.0,208.2 96.8,208.2 96.8,209.3 97.6,209.3 97.6,208.4 98.4,208.4 98.4,208.4 99.2,208.4 99.2,209.0 100.1,209.0 100.1,209.0 100.9,209.0 100.9,208.7 101.7,208.7 101.7,208.9 102.5,208.9 102.5,208.7 103.3,208.7 103.3,209.0 104.1,209.0 104.1,208.8 104.9,208.8 104.9,208.7 105.8,208.7 105.8,209.3 106.6,209.3 106.6,208.6 107.4,208.6 107.4,208.5 108.2,208.5 108.2,208.4 109.0,208.4 109.0,208.0 109.8,208.0 109.8,208.9 110.6,208.9 110.6,208.6 111.4,208.6 111.4,208.9 112.2,208.9 112.2,208.1 113.1,208.1 113.1,208.0 113.9,208.0 113.9,208.6 114.7,208.6 114.7,208.5 115.5,208.5 115.5,209.1 116.3,209.1 116.3,208.0 117.1,208.0 117.1,209.1 117.9,209.1 117.9,208.9 118.8,208.9 118.8,208.5 119.6,208.5 119.6,209.1 120.4,209.1 120.4,209.0 121.2,209.0 121.2,208.8 122.0,208.8 122.0,208.6 122.8,208.6 122.8,208.6 123.6,208.6 123.6,208.2 124.4,208.2 124.4,209.0 125.3,209.0 125.3,209.2 126.1,209.2 126.1,209.1 126.9,209.1 126.9,209.2 127.7,209.2 127.7,209.2 128.5,209.2 128.5,208.5 129.3,208.5 129.3,208.7 130.1,208.7 130.1,209.5 130.9,209.5 130.9,208.4 131.8,208.4 131.8,147.4 132.6,147.4 132.6,148.3 133.4,148.3 133.4,148.4 134.2,148.4 134.2,147.5 135.0,147.5 135.0,147.5 135.8,147.5 135.8,147.7 136.6,147.7 136.6,148.2 137.4,148.2 137.4,148.2 138.2,148.2 138.2,147.3 139.1,147.3 139.1,148.1 139.9,148.1 139.9,147.2 140.7,147.2 140.7,147.5 141.5,147.5 141.5,147.3 142.3,147.3 142.3,148.4 143.1,148.4 143.1,147.4 143.9,147.4 143.9,148.3 144.8,148.3 144.8,148.5 145.6,148.5 145.6,147.7 146.4,147.7 146.4,147.8 147.2,147.8 147.2,148.0 148.0,148.0 148.0,148.5 148.8,148.5 148.8,148.0 149.6,148.0 149.6,148.1 150.4,148.1 150.4,148.2 151.2,148.2 151.2,148.3 152.1,148.3 152.1,149.0 152.9,149.0 152.9,148.7 153.7,148.7 153.7,148.2 154.5,148.2 154.5,148.1 155.3,148.1 155.3,148.9 156.1,148.9 156.1,147.7 156.9,147.7 156.9,149.2 157.8,149.2 157.8,149.1 158.6,149.1 158.6,148.8 159.4,148.8 159.4,148.1 160.2,148.1 160.2,148.7 161.0,148.7 161.0,147.7 161.8,147.7 161.8,147.9 162.6,147.9 162.6,147.7 163.4,147.7 163.4,148.3 164.2,148.3 164.2,148.0 165.1,148.0 165.1,148.2 165.9,148.2 165.9,148.4 166.7,148.4 166.7,148.3 167.5,148.3 167.5,148.1 168.3,148.1 168.3,149.0 169.1,149.0 169.1,147.8 169.9,147.8 169.9,148.8 170.8,148.8 170.8,148.3 171.6,148.3 171.6,148.0 172.4,148.0 172.4,147.8 173.2,147.8 173.2,148.0 174.0,148.0 174.0,147.7 174.8,147.7 174.8,148.2 175.6,148.2 175.6,147.1 176.4,147.1 176.4,147.9 177.2,147.9 177.2,147.9 178.1,147.9 178.1,147.9 178.9,147.9 178.9,147.7 179.7,147.7 179.7,148.0 180.5,148.0 180.5,147.4 181.3,147.4 181.3,147.5 182.1,147.5 182.1,147.5 182.9,147.5 182.9,147.0 183.8,147.0 183.8,147.0 184.6,147.0 184.6,148.2 185.4,148.2 185.4,147.7 186.2,147.7 186.2,148.0 187.0,148.0 187.0,148.2 187.8,148.2 187.8,147.7 188.6,147.7 188.6,147.8 189.4,147.8 189.4,148.2 190.2,148.2 190.2,148.3 191.1,148.3 191.1,148.5 191.9,148.5 191.9,148.1 192.7,148.1 192.7,147.9 193.5,147.9 193.5,148.2 194.3,148.2 194.3,147.5 195.1,147.5 195.1,148.1 195.9,148.1 195.9,147.6 196.8,147.6 196.8,148.4 197.6,148.4 197.6,148.2 198.4,148.2 198.4,148.3 199.2,148.3 199.2,148.7 200.0,148.7 200.0,149.4 200.8,149.4 200.8,148.7 201.6,148.7 201.6,149.5 202.4,149.5 202.4,148.2 203.2,148.2 203.2,148.5 204.1,148.5 204.1,149.1 204.9,149.1 204.9,148.8 205.7,148.8 205.7,149.2 206.5,149.2 206.5,149.3 207.3,149.3 207.3,149.1 208.1,149.1 208.1,148.6 208.9,148.6 208.9,148.9 209.8,148.9 209.8,148.5 210.6,148.5 210.6,148.9 211.4,148.9 211.4,149.0 212.2,149.0 212.2,149.0 213.0,149.0 213.0,148.5 213.8,148.5 213.8,149.1 214.6,149.1 214.6,149.2 215.4,149.2 215.4,148.3 216.2,148.3 216.2,149.4 217.1,149.4 217.1,148.3 217.9,148.3 217.9,149.1 218.7,149.1 218.7,149.0 219.5,149.0 219.5,148.7 220.3,148.7 220.3,149.1 221.1,149.1 221.1,149.0 221.9,149.0 221.9,149.7 222.8,149.7 222.8,148.6 223.6,148.6 223.6,148.4 224.4,148.4 224.4,147.9 225.2,147.9 225.2,148.7 226.0,148.7 226.0,149.0 226.8,149.0 226.8,148.5 227.6,148.5 227.6,149.2 228.4,149.2 228.4,149.0 229.2,149.0 229.2,148.9 230.1,148.9 230.1,148.6 230.9,148.6 230.9,148.6 231.7,148.6 231.7,149.1 232.5,149.1 232.5,149.7 233.3,149.7 233.3,149.4 234.1,149.4 234.1,149.0 234.9,149.0 234.9,149.5 235.8,149.5 235.8,149.5 236.6,149.5 236.6,149.5 237.4,149.5 237.4,149.5 238.2,149.5 238.2,149.1 239.0,149.1 239.0,148.8 239.8,148.8 239.8,149.4 240.6,149.4 240.6,148.5 241.4,148.5 241.4,149.4 242.3,149.4 242.3,149.4 243.1,149.4 243.1,149.2 243.9,149.2 243.9,150.2 244.7,150.2 244.7,149.9 245.5,149.9 245.5,139.0 246.3,139.0 246.3,137.5 247.1,137.5 247.1,137.6 247.9,137.6 247.9,137.9 248.8,137.9 248.8,137.8 249.6,137.8 249.6,138.0 250.4,138.0 250.4,138.0 251.2,138.0 251.2,137.9 252.0,137.9 252.0,137.8 252.8,137.8 252.8,137.6 253.6,137.6 253.6,137.9 254.4,137.9 254.4,137.3 255.2,137.3 255.2,137.8 256.1,137.8 256.1,137.8 256.9,137.8 256.9,138.0 257.7,138.0 257.7,137.0 258.5,137.0 258.5,135.9 259.3,135.9 259.3,136.8 260.1,136.8 260.1,136.8 260.9,136.8 260.9,137.3 261.8,137.3 261.8,137.3 262.6,137.3 262.6,137.5 263.4,137.5 263.4,137.3 264.2,137.3 264.2,136.1 265.0,136.1 265.0,136.9 265.8,136.9 265.8,136.6 266.6,136.6 266.6,136.1 267.4,136.1 267.4,136.2 268.2,136.2 268.2,136.9 269.1,136.9 269.1,136.8 269.9,136.8 269.9,137.1 270.7,137.1 270.7,137.0 271.5,137.0 271.5,136.9 272.3,136.9 272.3,137.2 273.1,137.2 273.1,134.2 273.9,134.2 273.9,135.2 274.8,135.2 274.8,134.0 275.6,134.0 275.6,131.0 276.4,131.0 276.4,129.9 277.2,129.9 277.2,130.2 278.0,130.2 278.0,130.2 278.8,130.2 278.8,130.3 279.6,130.3 279.6,130.8 280.4,130.8 280.4,130.5 281.2,130.5 281.2,109.6 282.1,109.6 282.1,109.5 282.9,109.5 282.9,109.8 283.7,109.8 283.7,109.8 284.5,109.8 284.5,109.3 285.3,109.3 285.3,109.2 286.1,109.2 286.1,109.6 286.9,109.6 286.9,110.0 287.8,110.0 287.8,110.2 288.6,110.2 288.6,110.6 289.4,110.6 289.4,109.6 290.2,109.6 290.2,110.2 291.0,110.2 291.0,109.7 291.8,109.7 291.8,109.5 292.6,109.5 292.6,110.4 293.4,110.4 293.4,110.1 294.2,110.1 294.2,109.6 295.1,109.6 295.1,110.4 295.9,110.4 295.9,110.5 296.7,110.5 296.7,110.2 297.5,110.2 297.5,110.2 298.3,110.2 298.3,110.5 299.1,110.5 299.1,110.4 299.9,110.4 299.9,110.8 300.8,110.8 300.8,110.4 301.6,110.4 301.6,110.1 302.4,110.1 302.4,109.9 303.2,109.9 303.2,110.1 304.0,110.1 304.0,110.8 304.8,110.8 304.8,109.9 305.6,109.9 305.6,110.0 306.4,110.0 306.4,109.3 307.2,109.3 307.2,109.3 308.1,109.3 308.1,111.0 308.9,111.0 308.9,110.3 309.7,110.3 309.7,109.7 310.5,109.7 310.5,109.4 311.3,109.4 311.3,109.7 312.1,109.7 312.1,109.6 312.9,109.6 312.9,109.9 313.8,109.9 313.8,109.4 314.6,109.4 314.6,109.7 315.4,109.7 315.4,109.3 316.2,109.3 316.2,109.4 317.0,109.4 317.0,109.3 317.8,109.3 317.8,109.3 318.6,109.3 318.6,109.2 319.4,109.2 319.4,109.5 320.2,109.5 320.2,109.7 321.1,109.7 321.1,110.2 321.9,110.2 321.9,109.9 322.7,109.9 322.7,110.4 323.5,110.4 323.5,109.7 324.3,109.7 324.3,109.7 325.1,109.7 325.1,109.0 325.9,109.0 325.9,109.1 326.8,109.1 326.8,110.0 327.6,110.0 327.6,109.6 328.4,109.6 328.4,109.4 329.2,109.4 329.2,109.5 330.0,109.5 330.0,109.9"/> <circle class=nj-charts-json-dot cx=131.8 cy=147.4 r=3.5><title>#5285: 3.3&#215;</title></circle> <line class=nj-charts-grid x1=131.8 y1=54.0 x2=131.8 y2=142.4 stroke-dasharray="2 2"/> <circle class=nj-theme-dot cx=131.8 cy=46.0 r=7.5 /> <text class=nj-theme-num x=131.8 y=50.0 text-anchor=middle>6</text> <circle class=nj-charts-json-dot cx=245.5 cy=139.0 r=3.5><title>#5738: 3.8&#215;</title></circle> <line class=nj-charts-grid x1=245.5 y1=54.0 x2=245.5 y2=134.0 stroke-dasharray="2 2"/> <circle class=nj-theme-dot cx=245.5 cy=46.0 r=7.5 /> <text class=nj-theme-num x=245.5 y=50.0 text-anchor=middle>2</text> <circle class=nj-charts-json-dot cx=275.6 cy=131.0 r=3.5><title>#5878: 4.5&#215;</title></circle> <circle class=nj-charts-json-dot cx=281.2 cy=109.6 r=3.5><title>#5883: 6.8&#215;</title></circle> <line class=nj-charts-grid x1=281.2 y1=54.0 x2=281.2 y2=104.6 stroke-dasharray="2 2"/> <circle class=nj-theme-dot cx=281.2 cy=46.0 r=7.5 /> <text class=nj-theme-num x=281.2 y=50.0 text-anchor=middle>2</text> <line class=nj-charts-axis x1=44 y1=208 x2=330 y2=208 /> <text class=nj-charts-note x=8 y=262>speedup over 3.12.0 (log scale), more is better</text> </svg></p> </div> <div class=nj-fig-wrap> <p><svg class="nj-fig nj-charts nj-charts--timeline" viewbox="0 0 340 270" role=img aria-labelledby="nj-blog-tl-from_cbor_twitter nj-blog-tl-from_cbor_twitter-d" xmlns=http://www.w3.org/2000/svg> <title id=nj-blog-tl-from_cbor_twitter>from_cbor() twitter: speedup over 3.12.0 by commit</title> <desc id=nj-blog-tl-from_cbor_twitter-d>from_cbor() twitter: speedup over 3.12.0 at each of 353 commits, ending at 2.6x. Labeled steps, by theme: 1, 4, U, U.</desc> <text class=nj-charts-panel x=8 y=18>from_cbor() twitter</text> <line class=nj-charts-grid x1=44 y1=208 x2=330 y2=208 /> <text class="nj-charts-tick nj-charts-tick--r" x=38 y=212>1&#215;</text> <line class=nj-charts-grid x1=44 y1=137 x2=330 y2=137 /> <text class="nj-charts-tick nj-charts-tick--r" x=38 y=141>2&#215;</text> <line class=nj-charts-grid x1=44 y1=66 x2=330 y2=66 /> <text class="nj-charts-tick nj-charts-tick--r" x=38 y=70>4&#215;</text> <line class=nj-charts-axis x1=44 y1=208 x2=44 y2=212 /> <text class=nj-charts-tick x=44 y=225>3.12.0</text> <line class=nj-charts-axis x1=117.938 y1=208 x2=117.938 y2=212 /> <text class=nj-charts-tick x=117.938 y=225>Sep 2026</text> <line class=nj-charts-axis x1=198.375 y1=208 x2=198.375 y2=212 /> <text class=nj-charts-tick x=198.375 y=225>Oct</text> <polyline class=nj-charts-json points="44.0,208.0 44.8,208.0 44.8,209.1 45.6,209.1 45.6,208.2 46.4,208.2 46.4,208.6 47.2,208.6 47.2,208.0 48.1,208.0 48.1,208.4 48.9,208.4 48.9,208.6 49.7,208.6 49.7,208.3 50.5,208.3 50.5,209.1 51.3,209.1 51.3,207.8 52.1,207.8 52.1,208.5 52.9,208.5 52.9,208.6 53.8,208.6 53.8,208.6 54.6,208.6 54.6,207.7 55.4,207.7 55.4,207.1 56.2,207.1 56.2,207.3 57.0,207.3 57.0,206.9 57.8,206.9 57.8,207.1 58.6,207.1 58.6,207.0 59.4,207.0 59.4,207.1 60.2,207.1 60.2,207.1 61.1,207.1 61.1,207.5 61.9,207.5 61.9,207.5 62.7,207.5 62.7,206.9 63.5,206.9 63.5,207.0 64.3,207.0 64.3,206.2 65.1,206.2 65.1,207.1 65.9,207.1 65.9,208.5 66.8,208.5 66.8,208.0 67.6,208.0 67.6,207.8 68.4,207.8 68.4,208.5 69.2,208.5 69.2,207.8 70.0,207.8 70.0,207.0 70.8,207.0 70.8,208.1 71.6,208.1 71.6,208.2 72.4,208.2 72.4,208.6 73.2,208.6 73.2,208.1 74.1,208.1 74.1,207.2 74.9,207.2 74.9,208.3 75.7,208.3 75.7,207.4 76.5,207.4 76.5,207.9 77.3,207.9 77.3,207.7 78.1,207.7 78.1,208.6 78.9,208.6 78.9,207.3 79.8,207.3 79.8,207.9 80.6,207.9 80.6,208.4 81.4,208.4 81.4,208.5 82.2,208.5 82.2,208.0 83.0,208.0 83.0,207.1 83.8,207.1 83.8,208.1 84.6,208.1 84.6,208.1 85.4,208.1 85.4,207.8 86.2,207.8 86.2,207.9 87.1,207.9 87.1,207.9 87.9,207.9 87.9,208.7 88.7,208.7 88.7,208.1 89.5,208.1 89.5,168.9 90.3,168.9 90.3,170.3 91.1,170.3 91.1,169.9 91.9,169.9 91.9,169.0 92.8,169.0 92.8,169.6 93.6,169.6 93.6,169.1 94.4,169.1 94.4,170.1 95.2,170.1 95.2,168.8 96.0,168.8 96.0,167.9 96.8,167.9 96.8,170.4 97.6,170.4 97.6,169.5 98.4,169.5 98.4,169.7 99.2,169.7 99.2,172.9 100.1,172.9 100.1,170.5 100.9,170.5 100.9,170.4 101.7,170.4 101.7,170.1 102.5,170.1 102.5,170.2 103.3,170.2 103.3,170.7 104.1,170.7 104.1,170.5 104.9,170.5 104.9,170.4 105.8,170.4 105.8,171.1 106.6,171.1 106.6,170.2 107.4,170.2 107.4,168.6 108.2,168.6 108.2,168.9 109.0,168.9 109.0,168.8 109.8,168.8 109.8,170.5 110.6,170.5 110.6,169.2 111.4,169.2 111.4,169.8 112.2,169.8 112.2,168.2 113.1,168.2 113.1,168.3 113.9,168.3 113.9,169.9 114.7,169.9 114.7,170.3 115.5,170.3 115.5,170.5 116.3,170.5 116.3,169.2 117.1,169.2 117.1,170.5 117.9,170.5 117.9,170.1 118.8,170.1 118.8,170.0 119.6,170.0 119.6,170.0 120.4,170.0 120.4,169.7 121.2,169.7 121.2,169.9 122.0,169.9 122.0,169.2 122.8,169.2 122.8,169.6 123.6,169.6 123.6,170.0 124.4,170.0 124.4,170.0 125.3,170.0 125.3,170.5 126.1,170.5 126.1,170.8 126.9,170.8 126.9,170.5 127.7,170.5 127.7,170.8 128.5,170.8 128.5,169.2 129.3,169.2 129.3,128.6 130.1,128.6 130.1,121.0 130.9,121.0 130.9,120.5 131.8,120.5 131.8,120.8 132.6,120.8 132.6,120.9 133.4,120.9 133.4,120.2 134.2,120.2 134.2,116.5 135.0,116.5 135.0,117.5 135.8,117.5 135.8,117.4 136.6,117.4 136.6,118.0 137.4,118.0 137.4,118.3 138.2,118.3 138.2,118.0 139.1,118.0 139.1,120.1 139.9,120.1 139.9,118.9 140.7,118.9 140.7,119.6 141.5,119.6 141.5,119.0 142.3,119.0 142.3,120.9 143.1,120.9 143.1,118.6 143.9,118.6 143.9,121.1 144.8,121.1 144.8,120.1 145.6,120.1 145.6,118.4 146.4,118.4 146.4,119.3 147.2,119.3 147.2,119.0 148.0,119.0 148.0,120.2 148.8,120.2 148.8,119.0 149.6,119.0 149.6,119.4 150.4,119.4 150.4,119.8 151.2,119.8 151.2,120.4 152.1,120.4 152.1,120.6 152.9,120.6 152.9,119.6 153.7,119.6 153.7,118.8 154.5,118.8 154.5,118.4 155.3,118.4 155.3,120.2 156.1,120.2 156.1,119.3 156.9,119.3 156.9,119.9 157.8,119.9 157.8,119.6 158.6,119.6 158.6,119.7 159.4,119.7 159.4,119.2 160.2,119.2 160.2,119.5 161.0,119.5 161.0,118.0 161.8,118.0 161.8,150.3 162.6,150.3 162.6,150.5 163.4,150.5 163.4,150.6 164.2,150.6 164.2,151.3 165.1,151.3 165.1,151.4 165.9,151.4 165.9,150.7 166.7,150.7 166.7,152.1 167.5,152.1 167.5,151.8 168.3,151.8 168.3,152.4 169.1,152.4 169.1,150.6 169.9,150.6 169.9,152.8 170.8,152.8 170.8,154.2 171.6,154.2 171.6,152.8 172.4,152.8 172.4,152.9 173.2,152.9 173.2,153.6 174.0,153.6 174.0,151.7 174.8,151.7 174.8,153.8 175.6,153.8 175.6,151.6 176.4,151.6 176.4,152.6 177.2,152.6 177.2,153.5 178.1,153.5 178.1,151.8 178.9,151.8 178.9,152.7 179.7,152.7 179.7,153.6 180.5,153.6 180.5,152.7 181.3,152.7 181.3,152.5 182.1,152.5 182.1,152.7 182.9,152.7 182.9,151.6 183.8,151.6 183.8,153.2 184.6,153.2 184.6,154.6 185.4,154.6 185.4,152.1 186.2,152.1 186.2,152.9 187.0,152.9 187.0,153.9 187.8,153.9 187.8,153.0 188.6,153.0 188.6,152.6 189.4,152.6 189.4,154.0 190.2,154.0 190.2,154.0 191.1,154.0 191.1,154.3 191.9,154.3 191.9,152.5 192.7,152.5 192.7,154.4 193.5,154.4 193.5,154.2 194.3,154.2 194.3,151.8 195.1,151.8 195.1,154.0 195.9,154.0 195.9,153.0 196.8,153.0 196.8,152.2 197.6,152.2 197.6,153.7 198.4,153.7 198.4,153.8 199.2,153.8 199.2,153.9 200.0,153.9 200.0,155.5 200.8,155.5 200.8,153.4 201.6,153.4 201.6,155.4 202.4,155.4 202.4,152.8 203.2,152.8 203.2,154.0 204.1,154.0 204.1,152.3 204.9,152.3 204.9,153.2 205.7,153.2 205.7,153.5 206.5,153.5 206.5,153.6 207.3,153.6 207.3,154.6 208.1,154.6 208.1,152.7 208.9,152.7 208.9,155.4 209.8,155.4 209.8,152.5 210.6,152.5 210.6,153.3 211.4,153.3 211.4,153.3 212.2,153.3 212.2,154.5 213.0,154.5 213.0,152.6 213.8,152.6 213.8,153.0 214.6,153.0 214.6,154.3 215.4,154.3 215.4,122.0 216.2,122.0 216.2,123.3 217.1,123.3 217.1,121.4 217.9,121.4 217.9,122.4 218.7,122.4 218.7,122.6 219.5,122.6 219.5,122.9 220.3,122.9 220.3,123.5 221.1,123.5 221.1,123.0 221.9,123.0 221.9,123.1 222.8,123.1 222.8,123.2 223.6,123.2 223.6,123.3 224.4,123.3 224.4,122.2 225.2,122.2 225.2,123.7 226.0,123.7 226.0,124.3 226.8,124.3 226.8,123.7 227.6,123.7 227.6,123.8 228.4,123.8 228.4,123.1 229.2,123.1 229.2,123.6 230.1,123.6 230.1,123.9 230.9,123.9 230.9,122.7 231.7,122.7 231.7,123.3 232.5,123.3 232.5,123.8 233.3,123.8 233.3,123.0 234.1,123.0 234.1,123.2 234.9,123.2 234.9,122.2 235.8,122.2 235.8,122.9 236.6,122.9 236.6,122.0 237.4,122.0 237.4,121.4 238.2,121.4 238.2,122.1 239.0,122.1 239.0,122.7 239.8,122.7 239.8,122.3 240.6,122.3 240.6,122.5 241.4,122.5 241.4,123.5 242.3,123.5 242.3,124.3 243.1,124.3 243.1,123.8 243.9,123.8 243.9,123.6 244.7,123.6 244.7,123.5 245.5,123.5 245.5,123.2 246.3,123.2 246.3,123.1 247.1,123.1 247.1,122.8 247.9,122.8 247.9,123.9 248.8,123.9 248.8,124.1 249.6,124.1 249.6,124.3 250.4,124.3 250.4,123.9 251.2,123.9 251.2,123.1 252.0,123.1 252.0,121.3 252.8,121.3 252.8,122.2 253.6,122.2 253.6,114.0 254.4,114.0 254.4,112.4 255.2,112.4 255.2,113.8 256.1,113.8 256.1,113.2 256.9,113.2 256.9,113.7 257.7,113.7 257.7,113.4 258.5,113.4 258.5,111.3 259.3,111.3 259.3,111.3 260.1,111.3 260.1,113.3 260.9,113.3 260.9,113.6 261.8,113.6 261.8,112.9 262.6,112.9 262.6,112.5 263.4,112.5 263.4,112.4 264.2,112.4 264.2,113.3 265.0,113.3 265.0,112.7 265.8,112.7 265.8,112.9 266.6,112.9 266.6,112.1 267.4,112.1 267.4,112.5 268.2,112.5 268.2,113.2 269.1,113.2 269.1,113.3 269.9,113.3 269.9,112.4 270.7,112.4 270.7,113.0 271.5,113.0 271.5,112.9 272.3,112.9 272.3,112.6 273.1,112.6 273.1,113.5 273.9,113.5 273.9,113.3 274.8,113.3 274.8,109.2 275.6,109.2 275.6,109.0 276.4,109.0 276.4,109.1 277.2,109.1 277.2,108.5 278.0,108.5 278.0,107.5 278.8,107.5 278.8,108.0 279.6,108.0 279.6,109.2 280.4,109.2 280.4,109.2 281.2,109.2 281.2,109.1 282.1,109.1 282.1,109.5 282.9,109.5 282.9,109.1 283.7,109.1 283.7,109.2 284.5,109.2 284.5,108.5 285.3,108.5 285.3,109.0 286.1,109.0 286.1,109.2 286.9,109.2 286.9,108.7 287.8,108.7 287.8,108.7 288.6,108.7 288.6,109.2 289.4,109.2 289.4,106.9 290.2,106.9 290.2,108.5 291.0,108.5 291.0,109.2 291.8,109.2 291.8,109.1 292.6,109.1 292.6,109.6 293.4,109.6 293.4,109.0 294.2,109.0 294.2,108.3 295.1,108.3 295.1,109.3 295.9,109.3 295.9,109.7 296.7,109.7 296.7,108.4 297.5,108.4 297.5,109.0 298.3,109.0 298.3,109.4 299.1,109.4 299.1,109.8 299.9,109.8 299.9,108.8 300.8,108.8 300.8,108.8 301.6,108.8 301.6,111.4 302.4,111.4 302.4,109.4 303.2,109.4 303.2,109.6 304.0,109.6 304.0,110.5 304.8,110.5 304.8,109.6 305.6,109.6 305.6,109.5 306.4,109.5 306.4,110.1 307.2,110.1 307.2,109.1 308.1,109.1 308.1,111.2 308.9,111.2 308.9,110.0 309.7,110.0 309.7,109.4 310.5,109.4 310.5,109.8 311.3,109.8 311.3,109.5 312.1,109.5 312.1,110.3 312.9,110.3 312.9,109.5 313.8,109.5 313.8,109.3 314.6,109.3 314.6,111.2 315.4,111.2 315.4,108.6 316.2,108.6 316.2,109.8 317.0,109.8 317.0,108.4 317.8,108.4 317.8,108.2 318.6,108.2 318.6,107.7 319.4,107.7 319.4,108.7 320.2,108.7 320.2,108.6 321.1,108.6 321.1,109.9 321.9,109.9 321.9,108.8 322.7,108.8 322.7,110.2 323.5,110.2 323.5,109.3 324.3,109.3 324.3,109.3 325.1,109.3 325.1,107.7 325.9,107.7 325.9,108.1 326.8,108.1 326.8,110.8 327.6,110.8 327.6,108.2 328.4,108.2 328.4,109.9 329.2,109.9 329.2,109.0 330.0,109.0 330.0,109.3"/> <circle class=nj-charts-json-dot cx=89.5 cy=168.9 r=3.5><title>#5233: 1.47&#215;</title></circle> <line class=nj-charts-grid x1=89.5 y1=54.0 x2=89.5 y2=163.9 stroke-dasharray="2 2"/> <circle class=nj-theme-dot cx=89.5 cy=46.0 r=7.5 /> <text class=nj-theme-num x=89.5 y=50.0 text-anchor=middle>1</text> <circle class=nj-charts-json-dot cx=129.3 cy=128.6 r=3.5><title>#5501: 2.2&#215;</title></circle> <line class=nj-charts-grid x1=129.3 y1=54.0 x2=129.3 y2=123.6 stroke-dasharray="2 2"/> <circle class=nj-theme-dot cx=129.3 cy=46.0 r=7.5 /> <text class=nj-theme-num x=129.3 y=50.0 text-anchor=middle>4</text> <circle class=nj-charts-json-dot cx=161.8 cy=150.3 r=3.5><title>#5185: 1.76&#215;</title></circle> <line class=nj-charts-grid x1=161.8 y1=54.0 x2=161.8 y2=145.3 stroke-dasharray="2 2"/> <circle cx=161.8 cy=46.0 r=7.5 class="nj-theme-dot nj-theme-dot--other"/> <text class=nj-theme-num x=161.8 y=50.0 text-anchor=middle>U</text> <circle class=nj-charts-json-dot cx=215.4 cy=122.0 r=3.5><title>#5746: 2.3&#215;</title></circle> <line class=nj-charts-grid x1=215.4 y1=54.0 x2=215.4 y2=117.0 stroke-dasharray="2 2"/> <circle cx=215.4 cy=46.0 r=7.5 class="nj-theme-dot nj-theme-dot--other"/> <text class=nj-theme-num x=215.4 y=50.0 text-anchor=middle>U</text> <line class=nj-charts-axis x1=44 y1=208 x2=330 y2=208 /> <text class=nj-charts-note x=8 y=262>speedup over 3.12.0 (log scale), more is better</text> </svg></p> </div> </div> <p class=nj-caption>Speedup over 3.12.0 after each of the 351 commits that changed the headers up to November 3, from 3.12.0 (left) to 3.13.0 (right). More is better; each point is the median of 4 runs of one build, taken in random order (with 4 runs, the mean of the two middle ones). The badges are theme numbers; "U" is a <abbr title="Unicode Transformation Format">UTF</abbr>-8 check that came and went. The other four workloads, and every labeled step with its pull request and size, are in <a href=#c-the-timeline>Appendix C</a>.</p> <p>A few things stand out. A percentage for a step is relative to the time just before that step, not to the time of 3.12.0:</p> <ul> <li><strong>There is no single big step.</strong> Parsing <code>citm_catalog.json</code> got faster in about six visible steps. The largest removed a buffer that only error messages read, which alone saved 35% of the time. The next ones added the fast paths for contiguous input, derived positions only on error, and skipped indentation eight bytes at a time; most other changes moved it by a few percent.</li> <li><strong>Writing had a few large steps.</strong> <code>dump()</code> of <code>twitter.json</code> lost 70% of its time in one change (a write buffer and bulk string copies), and <code>dump()</code> of <code>canada.json</code> 65% in another (Żmij).</li> <li><strong>Regressions happen in between.</strong> A <abbr title="Unicode Transformation Format">UTF</abbr>-8 check of every text string in the binary readers, byte by byte, made <code>from_cbor()</code> of <code>twitter.json</code> 37% slower for 66 commits, until the readers were made lenient again by default, as in 3.12.0, with the check as an option. That decision was about the format specifications, which don't require a decoder to check, not about speed. The cost went with it. It never shipped in a release.</li> <li><strong>The input decides how big a step is.</strong> Removing the error-message buffer measured 8% on the benchmark of its pull request; on the indented <code>citm_catalog.json</code> it saved 35%, because every space of the indentation went through that buffer.</li> </ul> <h2 id=theme-1><span class=nj-theme>1</span> Specialize for each input source<a class=headerlink href=#theme-1 title="Permanent link">&para;</a></h2> <p>This is the function the 3.12.0 lexer called for <strong>every</strong> byte of input:</p> <div class=highlight><pre><span></span><code><span class=n>char_int_type</span><span class=w> </span><span class=nf>get</span><span class=p>()</span>
<span class=p>{</span>
<span class=w> </span><span class=o>++</span><span class=n>position</span><span class=p>.</span><span class=n>chars_read_total</span><span class=p>;</span>
<span class=w> </span><span class=o>++</span><span class=n>position</span><span class=p>.</span><span class=n>chars_read_current_line</span><span class=p>;</span>
<span class=w> </span><span class=k>if</span><span class=w> </span><span class=p>(</span><span class=n>next_unget</span><span class=p>)</span>
<span class=w> </span><span class=p>{</span>
<span class=w> </span><span class=c1>// just reset the next_unget variable and work with current</span>
<span class=w> </span><span class=n>next_unget</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=nb>false</span><span class=p>;</span>
<span class=w> </span><span class=p>}</span>
<span class=w> </span><span class=k>else</span>
<span class=w> </span><span class=p>{</span>
<span class=w> </span><span class=n>current</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>ia</span><span class=p>.</span><span class=n>get_character</span><span class=p>();</span>
<span class=w> </span><span class=p>}</span>
<span class=w> </span><span class=k>if</span><span class=w> </span><span class=p>(</span><span class=n>JSON_HEDLEY_LIKELY</span><span class=p>(</span><span class=n>current</span><span class=w> </span><span class=o>!=</span><span class=w> </span><span class=n>char_traits</span><span class=o>&lt;</span><span class=n>char_type</span><span class=o>&gt;::</span><span class=n>eof</span><span class=p>()))</span>
<span class=w> </span><span class=p>{</span>
<span class=w> </span><span class=n>token_string</span><span class=p>.</span><span class=n>push_back</span><span class=p>(</span><span class=n>char_traits</span><span class=o>&lt;</span><span class=n>char_type</span><span class=o>&gt;::</span><span class=n>to_char_type</span><span class=p>(</span><span class=n>current</span><span class=p>));</span>
<span class=w> </span><span class=p>}</span>
<span class=w> </span><span class=k>if</span><span class=w> </span><span class=p>(</span><span class=n>current</span><span class=w> </span><span class=o>==</span><span class=w> </span><span class=sc>'\n'</span><span class=p>)</span>
<span class=w> </span><span class=p>{</span>
<span class=w> </span><span class=o>++</span><span class=n>position</span><span class=p>.</span><span class=n>lines_read</span><span class=p>;</span>
<span class=w> </span><span class=n>position</span><span class=p>.</span><span class=n>chars_read_current_line</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=mi>0</span><span class=p>;</span>
<span class=w> </span><span class=p>}</span>
<span class=w> </span><span class=k>return</span><span class=w> </span><span class=n>current</span><span class=p>;</span>
<span class=p>}</span>
</code></pre></div> <p class=nj-code-caption>The 3.12.0 lexer's <code>get()</code>, called for every byte of input.</p> <p>Two counters in memory, a branch for a pending <code>unget()</code>, a call into the input adapter, a <code>push_back()</code> into a buffer that only an error message reads, and a branch for line breaks. The counters are members of the lexer, so the compiler has to load, add, and store them for every byte. A string or a number then copied each byte a second time into their token buffer. That is a clean design: one interface works for a <code>std::string</code>, an <code>std::istream</code>, a <code>FILE*</code>, a pair of iterators over a <code>std::list&lt;char&gt;</code>, or a user's own adapter. But it makes every input pay for the most limited one.</p> <p>3.13.0 has a dedicated reader for each kind of input and picks it at compile time:</p> <pre class=mermaid><code>flowchart LR
src[/"input"/] --&gt; q{{"what is it?"}}
q --&gt;|"std::string, std::vector,&lt;br&gt;pointers, contiguous ranges"| c["contiguous:&lt;br&gt;scan the whole buffer"]
q --&gt;|"std::istream"| w["window:&lt;br&gt;scan the streambuf's get area"]
q --&gt;|"FILE*"| f["one lock per parse,&lt;br&gt;unlocked reads"]
q --&gt;|"other iterators,&lt;br&gt;user adapters"| b["byte at a time"]</code></pre> <p class=nj-caption>The four kinds of input the lexer distinguishes in 3.13.0. Everything on the fast paths falls back to the byte path on anything unusual, so the result and the error messages stay the same.</p> <h3 id=detecting-the-input-in-c11>Detecting the input in C++11<a class=headerlink href=#detecting-the-input-in-c11 title="Permanent link">&para;</a></h3> <p>An input adapter can declare what it supports as static members (<code>supports_seek</code>, <code>supports_bulk_scan</code>, and a few more). The lexer detects them with the detection idiom, so a user's adapter that declares nothing keeps the byte path:</p> <div class=highlight><pre><span></span><code><span class=k>template</span><span class=o>&lt;</span><span class=k>typename</span><span class=w> </span><span class=nc>A</span><span class=o>&gt;</span><span class=w> </span><span class=k>using</span><span class=w> </span><span class=n>detect_supports_seek</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=k>decltype</span><span class=p>(</span><span class=n>A</span><span class=o>::</span><span class=n>supports_seek</span><span class=p>);</span>
<span class=k>template</span><span class=o>&lt;</span><span class=k>typename</span><span class=w> </span><span class=nc>A</span><span class=o>&gt;</span>
<span class=k>constexpr</span><span class=w> </span><span class=kt>bool</span><span class=w> </span><span class=n>input_adapter_supports_seek</span><span class=p>(</span><span class=n>std</span><span class=o>::</span><span class=n>true_type</span><span class=p>)</span><span class=w> </span><span class=p>{</span><span class=w> </span><span class=k>return</span><span class=w> </span><span class=n>A</span><span class=o>::</span><span class=n>supports_seek</span><span class=p>;</span><span class=w> </span><span class=p>}</span>
<span class=k>template</span><span class=o>&lt;</span><span class=k>typename</span><span class=w> </span><span class=nc>A</span><span class=o>&gt;</span>
<span class=k>constexpr</span><span class=w> </span><span class=kt>bool</span><span class=w> </span><span class=n>input_adapter_supports_seek</span><span class=p>(</span><span class=n>std</span><span class=o>::</span><span class=n>false_type</span><span class=p>)</span><span class=w> </span><span class=p>{</span><span class=w> </span><span class=k>return</span><span class=w> </span><span class=nb>false</span><span class=p>;</span><span class=w> </span><span class=p>}</span>
<span class=k>static</span><span class=w> </span><span class=k>constexpr</span><span class=w> </span><span class=kt>bool</span><span class=w> </span><span class=n>seekable</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>input_adapter_supports_seek</span><span class=o>&lt;</span><span class=n>InputAdapterType</span><span class=o>&gt;</span><span class=p>(</span>
<span class=w> </span><span class=n>is_detected</span><span class=o>&lt;</span><span class=n>detect_supports_seek</span><span class=p>,</span><span class=w> </span><span class=n>InputAdapterType</span><span class=o>&gt;</span><span class=w> </span><span class=p>{});</span>
<span class=k>static</span><span class=w> </span><span class=k>constexpr</span><span class=w> </span><span class=kt>bool</span><span class=w> </span><span class=n>lazy_position</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>seekable</span><span class=p>;</span>
</code></pre></div> <p class=nj-code-caption>Detecting a static member of the input adapter with the detection idiom: an adapter that doesn't declare <code>supports_seek</code> is not seekable.</p> <p>Without <code>if constexpr</code>, the flags select overloads by tag dispatch, <code>f(std::integral_constant&lt;bool, lazy_position&gt;{})</code>, which also keeps <abbr title="Microsoft Visual C++">MSVC</abbr> from warning about constant conditions. <code>get()</code> still looks like the old one, but its position and token bookkeeping are now calls. For an adapter that can seek, their <code>std::true_type</code> overloads are empty and cost nothing, because the position and the text of a token are derived only when an error message needs them (theme <a class=nj-theme href=#theme-4 title="theme 4">4</a>). For a <code>std::string</code>, what remains is the branch on <code>next_unget</code> and the adapter's bounds check and pointer increment.</p> <h3 id=contiguous-input>Contiguous input<a class=headerlink href=#contiguous-input title="Permanent link">&para;</a></h3> <p>Containers with <code>data()</code> and <code>size()</code> over single-byte elements now become a pointer range in every C++ standard, not only with C++20's contiguous iterators. <code>data()</code> and <code>size()</code> alone would be duck typing, so the trait also requires the container's <code>value_type</code> to be the element type behind <code>data()</code>. A type whose <code>size()</code> counts something else keeps the iterator path: slower, but correct. On a pointer range, the strings, the numbers and the indentation after a line break are scanned in bulk (themes <a class=nj-theme href=#theme-2 title="theme 2">2</a> and <a class=nj-theme href=#theme-3 title="theme 3">3</a>). Every fast path defers to the byte path on anything malformed, so error messages and byte positions stay the same, with one deliberate correction (the column after a number at the end of a line). <a href=#j-validation>Appendix J</a> describes how that was checked.</p> <h3 id=streams>Streams<a class=headerlink href=#streams title="Permanent link">&para;</a></h3> <p>An <code>std::istream</code> already has a buffer: the get area of its <code>streambuf</code>, <code>gptr()</code> to <code>egptr()</code>. The lexer now scans that window in bulk and keeps the current token as a pointer into it. Those are protected members of <code>std::streambuf</code>, and reaching them takes neither a cast nor a derived object:</p> <div class=highlight><pre><span></span><code><span class=k>struct</span><span class=w> </span><span class=nc>streambuf_access</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>streambuf</span>
<span class=p>{</span>
<span class=w> </span><span class=k>static</span><span class=w> </span><span class=k>const</span><span class=w> </span><span class=kt>char</span><span class=o>*</span><span class=w> </span><span class=nf>get_ptr</span><span class=p>(</span><span class=n>std</span><span class=o>::</span><span class=n>streambuf</span><span class=o>*</span><span class=w> </span><span class=n>s</span><span class=p>)</span><span class=w> </span><span class=p>{</span><span class=w> </span><span class=k>return</span><span class=w> </span><span class=p>(</span><span class=n>s</span><span class=o>-&gt;*</span><span class=p>(</span><span class=o>&amp;</span><span class=n>streambuf_access</span><span class=o>::</span><span class=n>gptr</span><span class=p>))();</span><span class=w> </span><span class=p>}</span>
<span class=w> </span><span class=k>static</span><span class=w> </span><span class=k>const</span><span class=w> </span><span class=kt>char</span><span class=o>*</span><span class=w> </span><span class=nf>get_end</span><span class=p>(</span><span class=n>std</span><span class=o>::</span><span class=n>streambuf</span><span class=o>*</span><span class=w> </span><span class=n>s</span><span class=p>)</span><span class=w> </span><span class=p>{</span><span class=w> </span><span class=k>return</span><span class=w> </span><span class=p>(</span><span class=n>s</span><span class=o>-&gt;*</span><span class=p>(</span><span class=o>&amp;</span><span class=n>streambuf_access</span><span class=o>::</span><span class=n>egptr</span><span class=p>))();</span><span class=w> </span><span class=p>}</span>
<span class=w> </span><span class=k>static</span><span class=w> </span><span class=kt>void</span><span class=w> </span><span class=nf>bump</span><span class=p>(</span><span class=n>std</span><span class=o>::</span><span class=n>streambuf</span><span class=o>*</span><span class=w> </span><span class=n>s</span><span class=p>,</span><span class=w> </span><span class=kt>int</span><span class=w> </span><span class=n>n</span><span class=p>)</span><span class=w> </span><span class=p>{</span><span class=w> </span><span class=p>(</span><span class=n>s</span><span class=o>-&gt;*</span><span class=p>(</span><span class=o>&amp;</span><span class=n>streambuf_access</span><span class=o>::</span><span class=n>gbump</span><span class=p>))(</span><span class=n>n</span><span class=p>);</span><span class=w> </span><span class=p>}</span>
<span class=p>};</span>
</code></pre></div> <p class=nj-code-caption>Reaching the protected get area of any <code>std::streambuf</code> through pointers to members, without a cast.</p> <p>A derived class may name a protected member of its base in a pointer to member, as long as it qualifies the name with its own class. The resulting pointer has the type <code>char* (std::streambuf::*)() const</code>, and access is checked when the name is used, not when the pointer is called, so it works on any <code>std::streambuf*</code>. The common alternative, <code>static_cast&lt;streambuf_access*&gt;(sb)-&gt;gptr()</code>, is undefined behavior, because the object is not a <code>streambuf_access</code>.</p> <p>Before the stream refills its get area, the adapter appends the part of the current token that is in it to a carry buffer; only an error message ever reads the token text back. Nothing is read ahead: the adapter advances <code>gptr()</code> by exactly what the lexer consumes, so the stream is left where it was before. On an M1 Max, parsing from an <code>std::ifstream</code> took 1.8–2.5× as long as reading the file into a string and parsing that, in the pull request's measurement before the change; now it takes just 9–16% longer.</p> <h3 id=file><code>FILE*</code><a class=headerlink href=#file title="Permanent link">&para;</a></h3> <p><code>std::fgetc</code> locks the <code>FILE</code> on every call. 3.13.0 locks it once per parse (<code>flockfile</code>, then <code>getc_unlocked</code>; <code>_lock_file</code> and <code>_fgetc_nolock</code> with the Microsoft runtime). <code>flockfile</code> is recursive, so the binary readers' <code>fread()</code> and a <abbr title="Simple API for XML">SAX</abbr> handler's own <code>ftell()</code> keep working. Whereas parsing <code>citm_catalog.json</code> from a <code>FILE*</code> got 4.4× as fast on macOS in the pull request's measurement, with glibc it got only 1.1–1.3× as fast, because glibc's per-call locking is already cheap. Two details: MemorySanitizer builds keep <code>fgetc</code>, because glibc's inline <code>getc_unlocked</code> reads a buffer that uninstrumented glibc filled. And a <abbr title="Simple API for XML">SAX</abbr> handler that waits for another thread using the same <code>FILE</code> now deadlocks, as the documentation says. Both paths can be switched off, with <a href=../../../api/macros/json_disable_stream_bulk_scan/ ><code>JSON_DISABLE_STREAM_BULK_SCAN</code></a> and <a href=../../../api/macros/json_disable_unlocked_file_io/ ><code>JSON_DISABLE_UNLOCKED_FILE_IO</code></a>.</p> <h2 id=theme-2><span class=nj-theme>2</span> Work on words, not bytes<a class=headerlink href=#theme-2 title="Permanent link">&para;</a></h2> <p>The core of a <abbr title="JavaScript Object Notation">JSON</abbr> lexer is "copy bytes until something interesting happens". Theme 1 gave it ranges of bytes. This theme reads them a word at a time.</p> <h3 id=eight-bytes-in-a-word>Eight bytes in a word<a class=headerlink href=#eight-bytes-in-a-word title="Permanent link">&para;</a></h3> <p>In a string, the interesting bytes are the closing quote, a backslash, a control character, and anything above 0x7F (<abbr title="Unicode Transformation Format">UTF</abbr>-8). This test checks eight bytes at once with ordinary 64-bit arithmetic:</p> <div class=highlight><pre><span></span><code><span class=c1>// return a word whose high bit is set in every byte of v that needs</span>
<span class=c1>// individual handling; zero if all 8 bytes can be copied as they are</span>
<span class=kr>inline</span><span class=w> </span><span class=n>std</span><span class=o>::</span><span class=kt>uint64_t</span><span class=w> </span><span class=nf>swar_string_special</span><span class=p>(</span><span class=n>std</span><span class=o>::</span><span class=kt>uint64_t</span><span class=w> </span><span class=n>v</span><span class=p>)</span><span class=w> </span><span class=k>noexcept</span>
<span class=p>{</span>
<span class=w> </span><span class=k>constexpr</span><span class=w> </span><span class=n>std</span><span class=o>::</span><span class=kt>uint64_t</span><span class=w> </span><span class=n>ones</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=mh>0x0101010101010101ull</span><span class=p>;</span>
<span class=w> </span><span class=k>constexpr</span><span class=w> </span><span class=n>std</span><span class=o>::</span><span class=kt>uint64_t</span><span class=w> </span><span class=n>high</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=mh>0x8080808080808080ull</span><span class=p>;</span>
<span class=w> </span><span class=k>const</span><span class=w> </span><span class=n>std</span><span class=o>::</span><span class=kt>uint64_t</span><span class=w> </span><span class=n>q</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>v</span><span class=w> </span><span class=o>^</span><span class=w> </span><span class=mh>0x2222222222222222ull</span><span class=p>;</span><span class=w> </span><span class=c1>// '"'</span>
<span class=w> </span><span class=k>const</span><span class=w> </span><span class=n>std</span><span class=o>::</span><span class=kt>uint64_t</span><span class=w> </span><span class=n>b</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>v</span><span class=w> </span><span class=o>^</span><span class=w> </span><span class=mh>0x5C5C5C5C5C5C5C5Cull</span><span class=p>;</span><span class=w> </span><span class=c1>// '\\'</span>
<span class=w> </span><span class=k>const</span><span class=w> </span><span class=n>std</span><span class=o>::</span><span class=kt>uint64_t</span><span class=w> </span><span class=n>has_quote</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=p>(</span><span class=n>q</span><span class=w> </span><span class=o>-</span><span class=w> </span><span class=n>ones</span><span class=p>)</span><span class=w> </span><span class=o>&amp;</span><span class=w> </span><span class=o>~</span><span class=n>q</span><span class=w> </span><span class=o>&amp;</span><span class=w> </span><span class=n>high</span><span class=p>;</span>
<span class=w> </span><span class=k>const</span><span class=w> </span><span class=n>std</span><span class=o>::</span><span class=kt>uint64_t</span><span class=w> </span><span class=n>has_backslash</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=p>(</span><span class=n>b</span><span class=w> </span><span class=o>-</span><span class=w> </span><span class=n>ones</span><span class=p>)</span><span class=w> </span><span class=o>&amp;</span><span class=w> </span><span class=o>~</span><span class=n>b</span><span class=w> </span><span class=o>&amp;</span><span class=w> </span><span class=n>high</span><span class=p>;</span>
<span class=w> </span><span class=k>const</span><span class=w> </span><span class=n>std</span><span class=o>::</span><span class=kt>uint64_t</span><span class=w> </span><span class=n>has_control</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=p>(</span><span class=n>v</span><span class=w> </span><span class=o>-</span><span class=w> </span><span class=mh>0x2020202020202020ull</span><span class=p>)</span><span class=w> </span><span class=o>&amp;</span><span class=w> </span><span class=o>~</span><span class=n>v</span><span class=w> </span><span class=o>&amp;</span><span class=w> </span><span class=n>high</span><span class=p>;</span><span class=w> </span><span class=c1>// &lt; 0x20</span>
<span class=w> </span><span class=k>const</span><span class=w> </span><span class=n>std</span><span class=o>::</span><span class=kt>uint64_t</span><span class=w> </span><span class=n>has_non_ascii</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>v</span><span class=w> </span><span class=o>&amp;</span><span class=w> </span><span class=n>high</span><span class=p>;</span><span class=w> </span><span class=c1>// &gt;= 0x80</span>
<span class=w> </span><span class=k>return</span><span class=w> </span><span class=n>has_quote</span><span class=w> </span><span class=o>|</span><span class=w> </span><span class=n>has_backslash</span><span class=w> </span><span class=o>|</span><span class=w> </span><span class=n>has_control</span><span class=w> </span><span class=o>|</span><span class=w> </span><span class=n>has_non_ascii</span><span class=p>;</span>
<span class=p>}</span>
</code></pre></div> <p class=nj-code-caption>The eight-byte test of the string scanner, in portable C++11.</p> <p><abbr title="Exclusive or">XOR</abbr> with the quote turns every quote byte into zero, and <code>(x - 0x01…01) &amp; ~x &amp; 0x80…80</code> sets the high bit of the bytes that were zero: the "determine if a word has a zero byte" trick from Sean Eron Anderson's <a href="https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord">Bit Twiddling Hacks</a>. The subtraction's borrow runs only upwards, so it can flag a byte <em>after</em> a real hit, but never one before it: the lowest flag is always right, and the number of trailing zero bits divided by eight is the index of the first special byte.</p> <div class=nj-fig-wrap> <p><svg class="nj-fig nj-charts nj-charts--swar" viewbox="0 0 640 312" role=img aria-labelledby="nj-blog-swar nj-blog-swar-d" xmlns=http://www.w3.org/2000/svg> <title id=nj-blog-swar>Finding the end of a run of ordinary string characters eight bytes at a time</title> <desc id=nj-blog-swar-d>The eight bytes w, i, t, t, e, r, quote and comma are loaded as one word. The test sets the high bit only in byte 6, the quote. Counting trailing zero bits gives 55, divided by eight gives 6: bytes 0 to 5 are copied at once, then the quote ends the string.</desc> <text class=fg-h x=40 y=20>eight input bytes, loaded as one 64-bit word (byte 0 is the lowest)</text> <rect class=fg-cell x=40 y=34 width=64 height=40 rx=4 /> <text class=fg-code x=72 y=60 text-anchor=middle>w</text> <text class=nj-charts-tick x=72 y=92>0x77</text> <text class=nj-charts-tick x=72 y=108>byte 0</text> <rect class=fg-cell x=110 y=34 width=64 height=40 rx=4 /> <text class=fg-code x=142 y=60 text-anchor=middle>i</text> <text class=nj-charts-tick x=142 y=92>0x69</text> <text class=nj-charts-tick x=142 y=108>byte 1</text> <rect class=fg-cell x=180 y=34 width=64 height=40 rx=4 /> <text class=fg-code x=212 y=60 text-anchor=middle>t</text> <text class=nj-charts-tick x=212 y=92>0x74</text> <text class=nj-charts-tick x=212 y=108>byte 2</text> <rect class=fg-cell x=250 y=34 width=64 height=40 rx=4 /> <text class=fg-code x=282 y=60 text-anchor=middle>t</text> <text class=nj-charts-tick x=282 y=92>0x74</text> <text class=nj-charts-tick x=282 y=108>byte 3</text> <rect class=fg-cell x=320 y=34 width=64 height=40 rx=4 /> <text class=fg-code x=352 y=60 text-anchor=middle>e</text> <text class=nj-charts-tick x=352 y=92>0x65</text> <text class=nj-charts-tick x=352 y=108>byte 4</text> <rect class=fg-cell x=390 y=34 width=64 height=40 rx=4 /> <text class=fg-code x=422 y=60 text-anchor=middle>r</text> <text class=nj-charts-tick x=422 y=92>0x72</text> <text class=nj-charts-tick x=422 y=108>byte 5</text> <rect class=fg-cell x=460 y=34 width=64 height=40 rx=4 /> <rect class=nj-charts-c2 fill-opacity=.25 x=460 y=34 width=64 height=40 rx=4 /> <text class=fg-code x=492 y=60 text-anchor=middle>&quot;</text> <text class=nj-charts-tick x=492 y=92>0x22</text> <text class=nj-charts-tick x=492 y=108>byte 6</text> <rect class=fg-cell x=530 y=34 width=64 height=40 rx=4 /> <text class=fg-code x=562 y=60 text-anchor=middle>,</text> <text class=nj-charts-tick x=562 y=92>0x2C</text> <text class=nj-charts-tick x=562 y=108>byte 7</text> <text class=fg-h x=40 y=132>swar_string_special(): the high bit of each byte that needs handling</text> <rect class=fg-cell x=40 y=146 width=64 height=34 rx=4 /> <text class=fg-code x=72 y=169 text-anchor=middle>0x00</text> <rect class=fg-cell x=110 y=146 width=64 height=34 rx=4 /> <text class=fg-code x=142 y=169 text-anchor=middle>0x00</text> <rect class=fg-cell x=180 y=146 width=64 height=34 rx=4 /> <text class=fg-code x=212 y=169 text-anchor=middle>0x00</text> <rect class=fg-cell x=250 y=146 width=64 height=34 rx=4 /> <text class=fg-code x=282 y=169 text-anchor=middle>0x00</text> <rect class=fg-cell x=320 y=146 width=64 height=34 rx=4 /> <text class=fg-code x=352 y=169 text-anchor=middle>0x00</text> <rect class=fg-cell x=390 y=146 width=64 height=34 rx=4 /> <text class=fg-code x=422 y=169 text-anchor=middle>0x00</text> <rect class=fg-cell x=460 y=146 width=64 height=34 rx=4 /> <rect class=nj-charts-c2 fill-opacity=.25 x=460 y=146 width=64 height=34 rx=4 /> <text class=fg-code x=492 y=169 text-anchor=middle>0x80</text> <rect class=fg-cell x=530 y=146 width=64 height=34 rx=4 /> <text class=fg-code x=562 y=169 text-anchor=middle>0x00</text> <text class=fg-code x=40 y=216>count_trailing_zeros(0x0080000000000000) = 55</text> <text class=fg-code x=40 y=242>55 / 8 = 6: copy bytes 0 to 5 in one go, then handle the quote</text> <text class="fg-note fg-note--l" x=40 y=272>No branch per byte: a few subtractions, ANDs and ORs per word,</text> <text class="fg-note fg-note--l" x=40 y=290>then one count of trailing zeros.</text> </svg></p> </div> <p class=nj-caption><code>swar_string_special()</code> on the last eight bytes of <code>"twitter",</code>: one word in, one flag out, and the count of trailing zero bits says how many bytes can be copied before the quote.</p> <p>Two details make this portable C++11. The word is loaded with <code>std::memcpy</code>, which compilers turn into one load and which, unlike a <code>reinterpret_cast</code>, doesn't break the aliasing rules. And the load always produces the bytes in little-endian order, so the first byte of the text is the lowest byte of the word everywhere; a big-endian target assembles the word from bytes, which compilers fold into a load and a byte swap. Every loop checks that eight bytes remain before it loads, and finishes the remaining one to seven bytes one at a time, so nothing is read past the input.</p> <p>The same kind of word test now runs in several places:</p> <ul> <li><strong>Strings in the lexer,</strong> including runs of well-formed multi-byte <abbr title="Unicode Transformation Format">UTF</abbr>-8, which are validated one sequence after the other without going back to the byte loop.</li> <li><strong>Numbers,</strong> eight digits per step (theme <a class=nj-theme href=#theme-3 title="theme 3">3</a>).</li> <li><strong>Indentation.</strong> After a newline, <code>word ^ 0x2020…20</code> is zero for eight spaces; the first non-zero byte ends the indentation, and its trailing-zero count says how many spaces of the last word to skip as well. The idea is from <a href="https://github.com/stephenberry/glaze">Glaze</a>'s <code>skip_matching_ws</code>, which compares with the previous line's indentation; comparing with spaces needs no state and works for any indentation width. A version that skipped only whole words validated 5–12% slower and gave nothing on two-space indentation, where the runs are often shorter than a word. With four-space indentation, validating <code>citm_catalog.json</code> got 22–30% faster.</li> <li><strong><a href=../../../api/basic_json/dump/ ><code>dump()</code></a>,</strong> for runs of characters that need no escaping, with and without <a href=../../../api/basic_json/dump/#parameters><code>ensure_ascii</code></a>.</li> <li><strong>The binary formats,</strong> for the zero byte that ends a <abbr title="Binary JSON">BSON</abbr> key, and for the <abbr title="Unicode Transformation Format">UTF</abbr>-8 check of strings with <code>error_handler_t::strict</code>. On the M1, reading <code>canada.json</code> from <abbr title="Binary JSON">BSON</abbr> got 14% faster, and writing <code>twitter.json</code> as <abbr title="Unicode Transformation Format">UTF</abbr>-8-checked <abbr title="Concise Binary Object Representation">CBOR</abbr> 14%.</li> </ul> <h3 id=16-bytes-with-sse2-and-neon>16 bytes with <abbr title="Streaming SIMD Extensions 2">SSE2</abbr> and <abbr title="Arm SIMD instruction set extension">NEON</abbr><a class=headerlink href=#16-bytes-with-sse2-and-neon title="Permanent link">&para;</a></h3> <p>Where a vector unit is part of the baseline instruction set (<abbr title="Streaming SIMD Extensions 2">SSE2</abbr> on x86-64, <abbr title="Arm SIMD instruction set extension">NEON</abbr> on 64-bit Arm), the string paths take 16 bytes per step. Two well-known details are worth repeating. A signed comparison <code>byte &lt; 0x20</code> catches control characters <em>and</em> every byte from 0x80, because those are negative as <code>int8_t</code>, so four classes of bytes take three comparisons. And <abbr title="Arm SIMD instruction set extension">NEON</abbr> has no equivalent of x86's <code>pmovmskb</code>, which turns a vector of comparison results into a bit mask. The usual replacement, by <a href="https://developer.arm.com/community/arm-community-blogs/b/servers-and-cloud-computing-blog/posts/porting-x86-vector-bitmask-optimizations-to-arm-neon">Danila Kutenin</a>, shifts each 16-bit lane right by four and narrows it to eight bits, which leaves four bits per input byte in a 64-bit integer:</p> <div class=highlight><pre><span></span><code><span class=k>while</span><span class=w> </span><span class=p>(</span><span class=n>e</span><span class=w> </span><span class=o>-</span><span class=w> </span><span class=n>p</span><span class=w> </span><span class=o>&gt;=</span><span class=w> </span><span class=mi>16</span><span class=p>)</span>
<span class=p>{</span>
<span class=w> </span><span class=k>const</span><span class=w> </span><span class=n>uint8x16_t</span><span class=w> </span><span class=n>in</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>vld1q_u8</span><span class=p>(</span><span class=n>p</span><span class=p>);</span>
<span class=w> </span><span class=k>const</span><span class=w> </span><span class=n>uint8x16_t</span><span class=w> </span><span class=n>quote_or_backslash</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>vorrq_u8</span><span class=p>(</span><span class=n>vceqq_u8</span><span class=p>(</span><span class=n>in</span><span class=p>,</span><span class=w> </span><span class=n>vdupq_n_u8</span><span class=p>(</span><span class=sc>'"'</span><span class=p>)),</span>
<span class=w> </span><span class=n>vceqq_u8</span><span class=p>(</span><span class=n>in</span><span class=p>,</span><span class=w> </span><span class=n>vdupq_n_u8</span><span class=p>(</span><span class=sc>'\\'</span><span class=p>)));</span>
<span class=w> </span><span class=k>const</span><span class=w> </span><span class=n>uint8x16_t</span><span class=w> </span><span class=n>special</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>vorrq_u8</span><span class=p>(</span><span class=n>quote_or_backslash</span><span class=p>,</span>
<span class=w> </span><span class=n>vcltq_s8</span><span class=p>(</span><span class=n>vreinterpretq_s8_u8</span><span class=p>(</span><span class=n>in</span><span class=p>),</span><span class=w> </span><span class=n>vdupq_n_s8</span><span class=p>(</span><span class=mh>0x20</span><span class=p>)));</span>
<span class=w> </span><span class=c1>// each byte of special is 0x00 or 0xFF; shifting each 16-bit lane right by 4 and</span>
<span class=w> </span><span class=c1>// keeping its low byte leaves 4 bits per input byte</span>
<span class=w> </span><span class=k>const</span><span class=w> </span><span class=n>uint8x8_t</span><span class=w> </span><span class=n>nibbles</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>vshrn_n_u16</span><span class=p>(</span><span class=n>vreinterpretq_u16_u8</span><span class=p>(</span><span class=n>special</span><span class=p>),</span><span class=w> </span><span class=mi>4</span><span class=p>);</span>
<span class=w> </span><span class=k>const</span><span class=w> </span><span class=n>std</span><span class=o>::</span><span class=kt>uint64_t</span><span class=w> </span><span class=n>bits</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>vget_lane_u64</span><span class=p>(</span><span class=n>vreinterpret_u64_u8</span><span class=p>(</span><span class=n>nibbles</span><span class=p>),</span><span class=w> </span><span class=mi>0</span><span class=p>);</span>
<span class=w> </span><span class=k>if</span><span class=w> </span><span class=p>(</span><span class=n>bits</span><span class=w> </span><span class=o>!=</span><span class=w> </span><span class=mi>0</span><span class=p>)</span>
<span class=w> </span><span class=p>{</span>
<span class=w> </span><span class=k>return</span><span class=w> </span><span class=n>p</span><span class=w> </span><span class=o>+</span><span class=w> </span><span class=p>(</span><span class=n>count_trailing_zeros</span><span class=p>(</span><span class=n>bits</span><span class=p>)</span><span class=w> </span><span class=o>&gt;&gt;</span><span class=w> </span><span class=mi>2u</span><span class=p>);</span><span class=w> </span><span class=c1>// four bits per byte</span>
<span class=w> </span><span class=p>}</span>
<span class=w> </span><span class=n>p</span><span class=w> </span><span class=o>+=</span><span class=w> </span><span class=mi>16</span><span class=p>;</span>
<span class=p>}</span>
</code></pre></div> <p class=nj-code-caption>The <abbr title="Arm SIMD instruction set extension">NEON</abbr> string scan: three comparisons for four classes of bytes, and a narrowing shift in place of <code>pmovmskb</code>.</p> <p>On <code>twitter.json</code>, the vector scan made <code>json::parse()</code> 5% faster with Clang and 9% with <abbr title="GNU Compiler Collection">GCC</abbr> on an M1 Max; on long strings, 19–24%. It did not win from the first byte. On the M1, starting with <abbr title="Arm SIMD instruction set extension">NEON</abbr> made short strings 3–4% slower and the rest of the lexer bigger. So ARM runs four 8-byte words first and keeps the vector loop out of line, while x86-64 runs one word first. Inlining the vector code into the lexer cost 5% of validating <code>jeopardy.json</code> on the M1, although no string of that file is long enough to reach it: the scan function, which runs once per token, saved more registers and needed a stack slot.</p> <p><a href=../../../features/json_view/ ><code>json_document</code></a>, the new document type of <code>json_view.hpp</code>, also skips the digits after a decimal point 16 bytes at a time with <abbr title="Streaming SIMD Extensions 2">SSE2</abbr>: a compare and a bit mask instead of a branch per digit, about 33% of the instructions for a 12-digit fraction. Parsing <code>canada.json</code> got 22% faster on x86-64, a file of 10,000 floats 28–32%.</p> <p>One row got slower: with <abbr title="GNU Compiler Collection">GCC</abbr> 16, <code>citm_catalog.json</code> took 8% longer with the same number of instructions, because more of its hot jumps now crossed a 32-byte boundary. The microcode fix for Intel's JCC erratum makes that slow on our server. Assembling with <code>-Wa,-mbranches-within-32B-boundaries</code> shrinks the loss to about 4%, but a header-only library can't choose the assembler flags of the programs that include it, so we left the code as it is, and all numbers in this post are measured without that flag.</p> <h3 id=validating-utf-8-16-bytes-at-a-time>Validating <abbr title="Unicode Transformation Format">UTF</abbr>-8 16 bytes at a time<a class=headerlink href=#validating-utf-8-16-bytes-at-a-time title="Permanent link">&para;</a></h3> <p>Validating <abbr title="Unicode Transformation Format">UTF</abbr>-8 16 bytes at a time uses <a href="https://github.com/simdjson/simdjson">simdjson</a>'s "lookup4" algorithm (<a href="https://arxiv.org/abs/2010.03090">Keiser and Lemire, 2021</a>): three 16-entry tables, indexed by nibbles of a byte and of the byte before it, each give the set of errors that nibble allows, and a pair of bytes is invalid if all three sets share an error. It needs <code>pshufb</code>, which is <abbr title="Supplemental Streaming SIMD Extensions 3">SSSE3</abbr> and not part of baseline x86-64. The function is compiled with <code>__attribute__((target("ssse3")))</code>, out of line, and called only if <code>cpuid</code> says so. The result of that query is cached in a constant-initialized <code>static std::atomic&lt;int&gt;</code>, so that neither a guarded local static nor a global constructor is needed; threads that ask at the same time all store the same answer. On an error, the code backs up to the start of the sequence and lets the byte path produce the error message. <a href=../../../api/macros/json_no_simd/ ><code>JSON_NO_SIMD</code></a> turns all vector code off.</p> <h3 id=short-strings>Short strings<a class=headerlink href=#short-strings title="Permanent link">&para;</a></h3> <p>Short strings are a different problem. Most keys and many values are short: <code>citm_catalog.json</code> averages 8 bytes per string and <code>jeopardy.json</code> 14. For them, setting up a scan costs more than the scan. The first step took the idea of <a href="https://sqlite.org/src/file/src/json.c">SQLite</a>'s <code>jsonAppendString()</code>: check each byte of a string of up to 32 bytes against a 256-entry table of bytes that can be written unchanged, and copy the string in one go if they all pass. 32 bytes was the best threshold on the M1; 16 gained less, and 64 lost again. The second step replaced the table, where <abbr title="Streaming SIMD Extensions 2">SSE2</abbr> or <abbr title="Arm SIMD instruction set extension">NEON</abbr> is available, with overlapping loads, the trick that <code>memcpy</code> implementations such as glibc's use for short copies:</p> <div class=highlight><pre><span></span><code><span class=c1>// 16 &lt;= n &lt;= 32: two loads that overlap in the middle cover the whole string</span>
<span class=k>const</span><span class=w> </span><span class=n>uint8x16_t</span><span class=w> </span><span class=n>a</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>vld1q_u8</span><span class=p>(</span><span class=n>p</span><span class=p>);</span>
<span class=k>const</span><span class=w> </span><span class=n>uint8x16_t</span><span class=w> </span><span class=n>b</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>vld1q_u8</span><span class=p>(</span><span class=n>p</span><span class=w> </span><span class=o>+</span><span class=w> </span><span class=n>n</span><span class=w> </span><span class=o>-</span><span class=w> </span><span class=mi>16</span><span class=p>);</span>
<span class=k>const</span><span class=w> </span><span class=n>uint8x16_t</span><span class=w> </span><span class=n>special</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=cm>/* '"', '\\', &lt; 0x20 or 0x7F, in a or in b */</span><span class=p>;</span>
<span class=k>if</span><span class=w> </span><span class=p>(</span><span class=n>vmaxvq_u8</span><span class=p>(</span><span class=n>special</span><span class=p>)</span><span class=w> </span><span class=o>!=</span><span class=w> </span><span class=mi>0</span><span class=p>)</span>
<span class=p>{</span>
<span class=w> </span><span class=k>return</span><span class=w> </span><span class=nb>false</span><span class=p>;</span><span class=w> </span><span class=c1>// nothing has been written yet; take the general path</span>
<span class=p>}</span>
<span class=n>vst1q_u8</span><span class=p>(</span><span class=n>d</span><span class=p>,</span><span class=w> </span><span class=n>a</span><span class=p>);</span>
<span class=n>vst1q_u8</span><span class=p>(</span><span class=n>d</span><span class=w> </span><span class=o>+</span><span class=w> </span><span class=n>n</span><span class=w> </span><span class=o>-</span><span class=w> </span><span class=mi>16</span><span class=p>,</span><span class=w> </span><span class=n>b</span><span class=p>);</span><span class=w> </span><span class=c1>// the two stores overlap too, with the same bytes</span>
</code></pre></div> <p class=nj-code-caption>Writing a string of 16–32 bytes with two overlapping loads and stores (<abbr title="Arm SIMD instruction set extension">NEON</abbr>).</p> <div class=nj-fig-wrap> <p><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></p> </div> <p class=nj-caption>The code above on <code>profile_link_color</code>, a key of <code>twitter.json</code>.</p> <p>On <code>twitter.json</code>, this cut the instructions of <code>dump()</code> by 21%. Shorter strings use the same trick with two overlapping 8-, 4-, or 2-byte loads, so no <code>memcpy</code> with a length known only at run time is left.</p> <h3 id=escapes-from-a-table>Escapes from a table<a class=headerlink href=#escapes-from-a-table title="Permanent link">&para;</a></h3> <p>When the scanner stops at a quote, a backslash, or a control character, the writer copies its escape sequence from a table of 8-byte rows, padded with zeros, with the length in the last byte:</p> <div class=highlight><pre><span></span><code><span class=p>{{</span><span class=sc>'\\'</span><span class=p>,</span><span class=w> </span><span class=sc>'u'</span><span class=p>,</span><span class=w> </span><span class=sc>'0'</span><span class=p>,</span><span class=w> </span><span class=sc>'0'</span><span class=p>,</span><span class=w> </span><span class=sc>'0'</span><span class=p>,</span><span class=w> </span><span class=sc>'0'</span><span class=p>,</span><span class=w> </span><span class=mi>0</span><span class=p>,</span><span class=w> </span><span class=mi>6</span><span class=p>}},</span><span class=w> </span><span class=c1>// 0x00</span>
<span class=p>{{</span><span class=sc>'\\'</span><span class=p>,</span><span class=w> </span><span class=sc>'n'</span><span class=p>,</span><span class=w> </span><span class=mi>0</span><span class=p>,</span><span class=w> </span><span class=mi>0</span><span class=p>,</span><span class=w> </span><span class=mi>0</span><span class=p>,</span><span class=w> </span><span class=mi>0</span><span class=p>,</span><span class=w> </span><span class=mi>0</span><span class=p>,</span><span class=w> </span><span class=mi>2</span><span class=p>}},</span><span class=w> </span><span class=c1>// 0x0A</span>
<span class=p>{{</span><span class=sc>'\\'</span><span class=p>,</span><span class=w> </span><span class=sc>'"'</span><span class=p>,</span><span class=w> </span><span class=mi>0</span><span class=p>,</span><span class=w> </span><span class=mi>0</span><span class=p>,</span><span class=w> </span><span class=mi>0</span><span class=p>,</span><span class=w> </span><span class=mi>0</span><span class=p>,</span><span class=w> </span><span class=mi>0</span><span class=p>,</span><span class=w> </span><span class=mi>2</span><span class=p>}},</span><span class=w> </span><span class=c1>// 0x22</span>
<span class=n>std</span><span class=o>::</span><span class=n>memcpy</span><span class=p>(</span><span class=n>write_buffer</span><span class=p>.</span><span class=n>data</span><span class=p>()</span><span class=w> </span><span class=o>+</span><span class=w> </span><span class=n>write_buffer_pos</span><span class=p>,</span><span class=w> </span><span class=n>escape</span><span class=p>.</span><span class=n>data</span><span class=p>(),</span><span class=w> </span><span class=mi>8</span><span class=p>);</span><span class=w> </span><span class=c1>// always 8 bytes</span>
<span class=n>write_buffer_pos</span><span class=w> </span><span class=o>+=</span><span class=w> </span><span class=n>escape</span><span class=p>[</span><span class=mi>7</span><span class=p>];</span><span class=w> </span><span class=c1>// keep only the real length</span>
</code></pre></div> <p class=nj-code-caption>Three rows of the escape table, and how a row is written: always 8 bytes, then the real length.</p> <p>One 8-byte store and one add, with no branch on the length; the padding lies behind the write position and is overwritten by the next write. The writer makes sure that 8 bytes are free before it copies. The idea is from <a href="https://github.com/ijl/orjson">orjson</a>'s <code>QUOTE_TAB</code>, which orjson took from <a href="https://github.com/cloudwego/sonic-rs">sonic-rs</a>. Although dumping 100,000 log lines full of <code>\n</code>, <code>\t</code>, and quotes got 23% faster on an M1 Max, most of that came from writing straight into the write buffer instead of an intermediate one. The table alone gained 2–7%.</p> <h2 id=theme-3><span class=nj-theme>3</span> Own the number conversions<a class=headerlink href=#theme-3 title="Permanent link">&para;</a></h2> <p>3.12.0 converted every floating-point number with <code>strtod</code> and every integer with <code>strtoull</code> or <code>strtoll</code>, after copying the token into a buffer. <code>strtod</code> is correct, but general: it consults the locale for the decimal point, sets <code>errno</code>, and handles any length of input. <code>std::from_chars</code> would avoid the locale, but it doesn't exist before C++17, and libc++ has its floating-point overloads without defining <code>__cpp_lib_to_chars</code>, so macOS builds could not detect it.</p> <p><code>canada.json</code>, a GeoJSON file of 111,126 numbers, shows what that costs. 108,528 of its numbers have 16 or 17 significant digits, like <code>-65.613616999999977</code>. The classic shortcut is Clinger's fast path (<a href="https://doi.org/10.1145/93542.93557">Clinger, 1990</a>): write the number as its digits <code>w</code> times a power of ten, convert <code>w</code> to a <code>double</code>, and multiply or divide it by that power of ten. If both are exact as <code>double</code>, that is, <code>w</code> is at most 2⁵³ (9,007,199,254,740,992) and the power at most 10²², the operation rounds only once, and the result is the correctly rounded <code>double</code>. For most of <code>canada.json</code>'s numbers, <code>w</code> doesn't fit into 53 bits.</p> <p>3.13.0 converts <code>float</code> and <code>double</code> numbers itself, without the C library and without the locale:</p> <pre class=mermaid><code>flowchart TB
t["number token"] --&gt; d{{"at most 19&lt;br&gt;significant digits?"}}
d --&gt;|"yes"| c{{"digits and power of ten&lt;br&gt;exact as double?"}}
c --&gt;|"yes"| cl["Clinger's fast path:&lt;br&gt;one multiplication or division"]
c --&gt;|"no"| el["Eisel-Lemire:&lt;br&gt;128-bit integer arithmetic"]
d --&gt;|"no"| el2["Eisel-Lemire on the first 19 digits"]
el2 --&gt; amb{{"w and w+1 round&lt;br&gt;to the same double?"}}
amb --&gt;|"yes"| done(["done"])
amb --&gt;|"no"| big["compare with the exact midpoint&lt;br&gt;(big-integer arithmetic)"]</code></pre> <p class=nj-caption>How 3.13.0 converts a decimal token to a <code>double</code>. Of <code>canada.json</code>'s 111,080 floating-point numbers, 9,742 take Clinger's fast path and 101,338 Eisel-Lemire; none has more than 19 digits.</p> <h3 id=eight-digits-at-a-time>Eight digits at a time<a class=headerlink href=#eight-digits-at-a-time title="Permanent link">&para;</a></h3> <p>On contiguous input and stream windows, the lexer accumulates the value while it validates the token, so the digits are read once. The core is <a href="https://github.com/fastfloat/fast_float">fast_float</a>'s eight-digit conversion: three multiplications instead of eight.</p> <div class=highlight><pre><span></span><code><span class=c1>// v: eight ASCII digits, the first digit in the lowest byte</span>
<span class=n>std</span><span class=o>::</span><span class=kt>uint32_t</span><span class=w> </span><span class=nf>parse_eight_digits</span><span class=p>(</span><span class=n>std</span><span class=o>::</span><span class=kt>uint64_t</span><span class=w> </span><span class=n>v</span><span class=p>)</span><span class=w> </span><span class=k>noexcept</span>
<span class=p>{</span>
<span class=w> </span><span class=n>v</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=p>((</span><span class=n>v</span><span class=w> </span><span class=o>&amp;</span><span class=w> </span><span class=mh>0x0F0F0F0F0F0F0F0Fu</span><span class=p>)</span><span class=w> </span><span class=o>*</span><span class=w> </span><span class=mi>2561u</span><span class=p>)</span><span class=w> </span><span class=o>&gt;&gt;</span><span class=w> </span><span class=mi>8u</span><span class=p>;</span><span class=w> </span><span class=c1>// 2561 = 10 * 2^8 + 1</span>
<span class=w> </span><span class=n>v</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=p>((</span><span class=n>v</span><span class=w> </span><span class=o>&amp;</span><span class=w> </span><span class=mh>0x00FF00FF00FF00FFu</span><span class=p>)</span><span class=w> </span><span class=o>*</span><span class=w> </span><span class=mi>6553601u</span><span class=p>)</span><span class=w> </span><span class=o>&gt;&gt;</span><span class=w> </span><span class=mi>16u</span><span class=p>;</span><span class=w> </span><span class=c1>// 6553601 = 100 * 2^16 + 1</span>
<span class=w> </span><span class=n>v</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=p>((</span><span class=n>v</span><span class=w> </span><span class=o>&amp;</span><span class=w> </span><span class=mh>0x0000FFFF0000FFFFu</span><span class=p>)</span><span class=w> </span><span class=o>*</span><span class=w> </span><span class=mi>42949672960001u</span><span class=p>)</span><span class=w> </span><span class=o>&gt;&gt;</span><span class=w> </span><span class=mi>32u</span><span class=p>;</span><span class=w> </span><span class=c1>// 10000 * 2^32 + 1</span>
<span class=w> </span><span class=k>return</span><span class=w> </span><span class=k>static_cast</span><span class=o>&lt;</span><span class=n>std</span><span class=o>::</span><span class=kt>uint32_t</span><span class=o>&gt;</span><span class=p>(</span><span class=n>v</span><span class=p>);</span>
<span class=p>}</span>
</code></pre></div> <p class=nj-code-caption>fast_float's conversion of eight <abbr title="American Standard Code for Information Interchange">ASCII</abbr> digits to their value, with three multiplications.</p> <div class=nj-fig-wrap> <p><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></p> </div> <p class=nj-caption><code>parse_eight_digits()</code> on <code>"12345678"</code>: multiplying by <code>10·2⁸ + 1</code> adds ten times each byte to the byte above it, and the shift and the next mask keep every second lane.</p> <p>Checking that all eight bytes are digits takes one more expression. A digit is a byte from 0x30 to 0x39. In hexadecimal, its upper half is 3 and its lower half is at most 9. Adding 6 tests the lower half: 0x39 + 6 = 0x3F still has the upper half 3, but 0x3A + 6 = 0x40 carries into it. So a byte is a digit exactly if its upper half is 3 both before and after adding 6, and with masks, that is one comparison for all eight bytes. An integer of up to 18 digits always fits into an <code>int64_t</code>, and 19 digits into a <code>uint64_t</code>, so they need no overflow check.</p> <h3 id=clingers-fast-path>Clinger's fast path<a class=headerlink href=#clingers-fast-path title="Permanent link">&para;</a></h3> <p>Clinger's fast path is guarded by more than the two conditions above:</p> <div class=highlight><pre><span></span><code><span class=cp>#if !defined(FLT_EVAL_METHOD) || FLT_EVAL_METHOD == 0</span>
<span class=k>if</span><span class=w> </span><span class=p>(</span><span class=n>exponent</span><span class=w> </span><span class=o>&gt;=</span><span class=w> </span><span class=mi>-22</span><span class=w> </span><span class=o>&amp;&amp;</span><span class=w> </span><span class=n>exponent</span><span class=w> </span><span class=o>&lt;=</span><span class=w> </span><span class=mi>22</span><span class=w> </span><span class=o>&amp;&amp;</span><span class=w> </span><span class=n>w</span><span class=w> </span><span class=o>&lt;=</span><span class=w> </span><span class=p>(</span><span class=n>std</span><span class=o>::</span><span class=kt>uint64_t</span><span class=p>{</span><span class=mi>1</span><span class=p>}</span><span class=w> </span><span class=o>&lt;&lt;</span><span class=w> </span><span class=mi>53</span><span class=p>))</span>
<span class=p>{</span>
<span class=w> </span><span class=kt>double</span><span class=w> </span><span class=n>value</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=k>static_cast</span><span class=o>&lt;</span><span class=kt>double</span><span class=o>&gt;</span><span class=p>(</span><span class=n>w</span><span class=p>);</span>
<span class=w> </span><span class=n>value</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>exponent</span><span class=w> </span><span class=o>&lt;</span><span class=w> </span><span class=mi>0</span><span class=w> </span><span class=o>?</span><span class=w> </span><span class=n>value</span><span class=w> </span><span class=o>/</span><span class=w> </span><span class=n>exact_power_of_ten</span><span class=p>(</span><span class=o>-</span><span class=n>exponent</span><span class=p>)</span>
<span class=w> </span><span class=o>:</span><span class=w> </span><span class=n>value</span><span class=w> </span><span class=o>*</span><span class=w> </span><span class=n>exact_power_of_ten</span><span class=p>(</span><span class=n>exponent</span><span class=p>);</span>
<span class=w> </span><span class=k>return</span><span class=w> </span><span class=n>negative</span><span class=w> </span><span class=o>?</span><span class=w> </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>value</span><span class=p>;</span>
<span class=p>}</span>
<span class=cp>#endif</span>
</code></pre></div> <p class=nj-code-caption>Clinger's fast path: one correctly rounded multiplication or division, only without x87 extended precision.</p> <p>With x87 arithmetic (<code>FLT_EVAL_METHOD != 0</code>), the intermediate result has extended precision and is rounded twice, so those targets skip the fast path and take the integer-only route below.</p> <h3 id=eisel-lemire>Eisel-Lemire<a class=headerlink href=#eisel-lemire title="Permanent link">&para;</a></h3> <p><a href="https://arxiv.org/abs/2101.11408">Eisel-Lemire</a>, adapted from fast_float's <code>compute_float</code>, handles everything else with integers only: it multiplies the digits with a 128-bit approximation of <code>5^q</code> from a table and takes the mantissa from the top of the product. For up to 19 digits, that always suffices (<a href="https://arxiv.org/abs/2212.06644">Mushtak and Lemire, 2023</a>). Longer numbers, rare in <abbr title="JavaScript Object Notation">JSON</abbr>, are bracketed by their first 19 digits and that plus one; only if the two round differently are all digits compared with the exact midpoint. <a href=#i-details-of-the-themes>Appendix I</a> has the details. Because it is integer arithmetic, the result no longer depends on the C locale. (<abbr title="JavaScript Object Notation">JSON</abbr> always uses <code>.</code>, but <code>strtod</code> expects the locale's decimal separator, so 3.12.0 replaced the <code>.</code> before calling it, which <a href="https://github.com/nlohmann/json/issues/5660">failed for separators longer than one byte</a>.) <a href=#j-validation>Appendix J</a> describes how the conversion was checked against <code>strtod</code>.</p> <h3 id=writing-zmij>Writing: Żmij<a class=headerlink href=#writing-zmij title="Permanent link">&para;</a></h3> <p>For output, 3.12.0 used <a href="https://doi.org/10.1145/1806596.1806623">Grisu2</a>, which is fast but sometimes writes a 17th digit where 16 suffice. 3.13.0 ports <a href="https://github.com/vitaut/zmij">Żmij</a> by Victor Zverovich to C++11. It writes the shortest decimal that reads back as the same <code>double</code>, and the closest one if there are several. Its digit conversion, by Xiang JunBo, is the parser's divide-by-multiplying idea run backwards on all lanes of a word at once (<a href=#i-details-of-the-themes>Appendix I</a> shows it), and with <abbr title="Streaming SIMD Extensions 2">SSE2</abbr> or <abbr title="Arm SIMD instruction set extension">NEON</abbr>, Żmij's vector code (the <abbr title="Arm SIMD instruction set extension">NEON</abbr> version by Dougall Johnson, the SSE version by Tobias Schlüter) converts all 16 digits in one vector register.</p> <p>One stall turned up on the way. To make room for the decimal point, the code first wrote all 16 digits, as two 8-byte stores, and then moved the digits after the point one byte to the right: it loaded them and stored them one byte further. That load came right after the two stores and read part of each. A <abbr title="Central Processing Unit">CPU</abbr> can hand a load the data of one store that hasn't reached the cache yet, but it can't combine two, so the load had to wait until both stores were written. The commit measured that wait as about 25% of the time to write a <code>double</code>. The vector version avoids memory: it keeps the digits in a register, moves the ones after the point up by one byte there, puts <code>'.'</code> into the gap, and stores all 16 bytes once.</p> <p>In the pull request's measurement, <code>dump()</code> of <code>canada.json</code> got about 3× as fast, on an M1 Max as well as on an x86-64 server with <abbr title="GNU Compiler Collection">GCC</abbr> and Clang. The changed output is listed in <a href=#f-behavior-changes>Appendix F</a>: 0.14% of random <code>double</code>s are written differently, all of them with the same or fewer digits, and all of them read back as the same value.</p> <h2 id=theme-4><span class=nj-theme>4</span> Don't do unnecessary work<a class=headerlink href=#theme-4 title="Permanent link">&para;</a></h2> <p>A lot of what the 3.12.0 parser did was correct, cheap per call, and read by nobody in the common case.</p> <h3 id=the-token-buffer>The token buffer<a class=headerlink href=#the-token-buffer title="Permanent link">&para;</a></h3> <p>The old <code>get()</code> of theme <a class=nj-theme href=#theme-1 title="theme 1">1</a> pushed every character into <code>token_string</code>, a buffer that only the "last read" part of an error message uses. For seekable input, the lexer now remembers the offset where the token started and copies the text from the input if an error happens. This is the 35% step of the timeline: in the indented <code>citm_catalog.json</code>, every space of the indentation went through the buffer. For streams, the carry buffer of theme <a class=nj-theme href=#theme-1 title="theme 1">1</a> does the same job; the per-character copy had been about 20% of what was left of a stream parse.</p> <p><a href=../../../api/basic_json/accept/ ><code>accept()</code></a> went one step further: it doesn't copy strings and keys at all. The lexer and the parser take a template parameter that drops values, so <code>accept()</code> gets its own instantiation without the copies. That made validating <code>twitter.json</code> 11–13% faster on x86-64, and 19 files of simdjson's examples 12% by geometric mean.</p> <h3 id=positions-only-on-error>Positions only on error<a class=headerlink href=#positions-only-on-error title="Permanent link">&para;</a></h3> <p>For input that can be seeked, the lexer no longer counts lines and columns. The byte offset is the distance from the start, and lines and columns are recomputed only when an error message needs them:</p> <div class=highlight><pre><span></span><code><span class=n>std</span><span class=o>::</span><span class=kt>size_t</span><span class=w> </span><span class=nf>count_consumed_lines</span><span class=p>(</span><span class=n>std</span><span class=o>::</span><span class=kt>size_t</span><span class=w> </span><span class=n>last_index</span><span class=p>,</span><span class=w> </span><span class=n>std</span><span class=o>::</span><span class=kt>size_t</span><span class=o>&amp;</span><span class=w> </span><span class=n>line_start</span><span class=p>)</span><span class=w> </span><span class=k>const</span>
<span class=p>{</span>
<span class=w> </span><span class=k>const</span><span class=w> </span><span class=k>auto</span><span class=w> </span><span class=n>to</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>next</span><span class=p>(</span><span class=n>begin</span><span class=p>,</span><span class=w> </span><span class=n>last_index</span><span class=p>);</span>
<span class=w> </span><span class=k>using</span><span class=w> </span><span class=n>reverse_it</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>reverse_iterator</span><span class=o>&lt;</span><span class=n>IteratorType</span><span class=o>&gt;</span><span class=p>;</span>
<span class=w> </span><span class=k>const</span><span class=w> </span><span class=k>auto</span><span class=w> </span><span class=n>last_newline</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>find</span><span class=p>(</span><span class=n>reverse_it</span><span class=p>(</span><span class=n>to</span><span class=p>),</span><span class=w> </span><span class=n>reverse_it</span><span class=p>(</span><span class=n>begin</span><span class=p>),</span><span class=w> </span><span class=sc>'\n'</span><span class=p>);</span>
<span class=w> </span><span class=n>line_start</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>distance</span><span class=p>(</span><span class=n>begin</span><span class=p>,</span><span class=w> </span><span class=n>last_newline</span><span class=p>.</span><span class=n>base</span><span class=p>());</span><span class=w> </span><span class=c1>// column: offset - line_start</span>
<span class=w> </span><span class=k>return</span><span class=w> </span><span class=n>std</span><span class=o>::</span><span class=n>count</span><span class=p>(</span><span class=n>begin</span><span class=p>,</span><span class=w> </span><span class=n>last_newline</span><span class=p>.</span><span class=n>base</span><span class=p>(),</span><span class=w> </span><span class=sc>'\n'</span><span class=p>);</span><span class=w> </span><span class=c1>// line: newlines before it</span>
<span class=p>}</span>
</code></pre></div> <p class=nj-code-caption>Line and column of an error, computed from the byte offset only when an error message needs them.</p> <p>That is linear in the input, but only an error pays for it. It is what <a href="https://github.com/serde-rs/json/blob/master/src/read.rs">serde_json's slice reader</a> does (<code>position_of_index()</code> with <code>memrchr</code> and a newline count). A pending <code>unget()</code> is a flag, and the offset subtracts one for it, so <code>unget()</code> does no position work at all. Measuring the two parts of the old <code>get()</code> separately on an M1 showed that the newline branch cost more than the counters: removing only the branch saved 16% of validating an indented <code>twitter.json</code>, removing only the increments 4%. Parsing <code>citm_catalog.json</code> got 12% faster.</p> <h3 id=the-text-of-float-tokens>The text of float tokens<a class=headerlink href=#the-text-of-float-tokens title="Permanent link">&para;</a></h3> <p>The lexer copied every float token into a buffer so that a <abbr title="Simple API for XML">SAX</abbr> handler's <code>number_float(val, s)</code> could see the original text: an out-of-line <code>std::string::append</code> per float, about 10% of parsing <code>canada.json</code>. The handlers behind <a href=../../../api/basic_json/parse/ ><code>parse()</code></a> and <a href=../../../api/basic_json/accept/ ><code>accept()</code></a> never look at it. The parser now recognizes them by their exact type:</p> <div class=highlight><pre><span></span><code><span class=k>template</span><span class=o>&lt;</span><span class=k>typename</span><span class=w> </span><span class=nc>SAX</span><span class=o>&gt;</span><span class=w> </span><span class=k>struct</span><span class=w> </span><span class=nc>sax_ignores_number_text</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>false_type</span><span class=w> </span><span class=p>{};</span>
<span class=k>template</span><span class=o>&lt;</span><span class=k>typename</span><span class=w> </span><span class=nc>B</span><span class=p>,</span><span class=w> </span><span class=k>typename</span><span class=w> </span><span class=nc>IA</span><span class=p>,</span><span class=w> </span><span class=kt>bool</span><span class=w> </span><span class=n>Collect</span><span class=p>,</span><span class=w> </span><span class=k>typename</span><span class=w> </span><span class=nc>L</span><span class=o>&gt;</span>
<span class=k>struct</span><span class=w> </span><span class=nc>sax_ignores_number_text</span><span class=o>&lt;</span><span class=n>json_sax_dom_parser</span><span class=o>&lt;</span><span class=n>B</span><span class=p>,</span><span class=w> </span><span class=n>IA</span><span class=p>,</span><span class=w> </span><span class=n>Collect</span><span class=p>,</span><span class=w> </span><span class=n>L</span><span class=o>&gt;&gt;</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>true_type</span><span class=w> </span><span class=p>{};</span>
<span class=k>template</span><span class=o>&lt;</span><span class=k>typename</span><span class=w> </span><span class=nc>B</span><span class=o>&gt;</span>
<span class=k>struct</span><span class=w> </span><span class=nc>sax_ignores_number_text</span><span class=o>&lt;</span><span class=n>json_sax_acceptor</span><span class=o>&lt;</span><span class=n>B</span><span class=o>&gt;&gt;</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>true_type</span><span class=w> </span><span class=p>{};</span>
<span class=c1>// json_sax_dom_callback_parser likewise</span>
<span class=c1>// at the call site</span>
<span class=n>sax</span><span class=o>-&gt;</span><span class=n>number_float</span><span class=p>(</span><span class=n>res</span><span class=p>,</span><span class=w> </span><span class=n>number_float_text</span><span class=p>(</span><span class=n>sax</span><span class=p>));</span><span class=w> </span><span class=c1>// an empty string for the handlers above</span>
</code></pre></div> <p class=nj-code-caption>Recognizing the library's own <abbr title="Simple API for XML">SAX</abbr> handlers, which never read the text of a float token.</p> <p>A class derived from <code>json_sax_dom_parser</code> does not match the specialization, so it keeps getting the exact text. For every other handler, the lexer only records a pointer to the token and its length, and copies on the first <code>get_string()</code>. That is safe for contiguous input, which has to outlive the parse anyway; in a stream's window, the next refill could overwrite the text, so there the copy is made at once. The first version put the "is there pending text?" check into the <code>get_string()</code> that keys and strings use too, and lost 2–3% on string-heavy input. Keys and strings now call a separate function without the check. Parsing <code>canada.json</code> got 9–11% faster.</p> <h3 id=a-copy-that-should-have-been-a-move>A copy that should have been a move<a class=headerlink href=#a-copy-that-should-have-been-a-move title="Permanent link">&para;</a></h3> <p><a href=../../../api/basic_json/from_cbor/ ><code>from_cbor()</code></a> and the other binary readers ended like this:</p> <div class=highlight><pre><span></span><code><span class=k>return</span><span class=w> </span><span class=n>res</span><span class=w> </span><span class=o>?</span><span class=w> </span><span class=n>result</span><span class=w> </span><span class=o>:</span><span class=w> </span><span class=n>basic_json</span><span class=p>(</span><span class=n>value_t</span><span class=o>::</span><span class=n>discarded</span><span class=p>);</span><span class=w> </span><span class=c1>// 3.12.0</span>
</code></pre></div> <p class=nj-code-caption>The end of the 3.12.0 binary readers: the conditional operator copies <code>result</code>.</p> <p><code>result</code> is a local, but the conditional operator's operand is an lvalue expression, and the implicit move on <code>return</code> applies only to a returned name. So every successfully parsed value was deep-copied once and then destroyed. 3.13.0 assigns <code>discarded</code> to <code>result</code> on failure and returns <code>result</code> by name. Decoding a 2 MB <abbr title="Concise Binary Object Representation">CBOR</abbr> document went from 26.99 ms to 14.65 ms. The copy was also a stack-overflow risk: the copy constructor recursed once per level, for a value the reader had already accepted.</p> <h3 id=ordered_json-growth><code>ordered_json</code> growth<a class=headerlink href=#ordered_json-growth title="Permanent link">&para;</a></h3> <p><a href=../../../api/ordered_json/ ><code>ordered_json</code></a> stores its members in a <code>std::vector&lt;std::pair&lt;const std::string, json&gt;&gt;</code>. Because the key is <code>const</code>, the pair's "move" constructor copies the key and can throw. When <code>std::vector</code> grows, it uses <code>std::move_if_noexcept</code> to keep the strong exception guarantee, so for this element type it copies every element, including the whole subtree behind every value. The library now grows the storage itself, in two phases:</p> <div class=highlight><pre><span></span><code><span class=c1>// phase 1, may throw but only touches tmp:</span>
<span class=c1>// copy the keys, default-construct the values, add the new element</span>
<span class=n>Container</span><span class=w> </span><span class=nf>tmp</span><span class=p>(</span><span class=k>this</span><span class=o>-&gt;</span><span class=n>get_allocator</span><span class=p>());</span>
<span class=n>tmp</span><span class=p>.</span><span class=n>reserve</span><span class=p>((</span><span class=n>std</span><span class=o>::</span><span class=n>max</span><span class=p>)(</span><span class=n>size_type</span><span class=p>{</span><span class=mi>1</span><span class=p>},</span><span class=w> </span><span class=mi>2</span><span class=w> </span><span class=o>*</span><span class=w> </span><span class=k>this</span><span class=o>-&gt;</span><span class=n>size</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=o>&amp;</span><span class=w> </span><span class=n>element</span><span class=w> </span><span class=o>:</span><span class=w> </span><span class=o>*</span><span class=k>this</span><span class=p>)</span>
<span class=w> </span><span class=n>tmp</span><span class=p>.</span><span class=n>emplace_back</span><span class=p>(</span><span class=n>std</span><span class=o>::</span><span class=n>piecewise_construct</span><span class=p>,</span><span class=w> </span><span class=n>std</span><span class=o>::</span><span class=n>forward_as_tuple</span><span class=p>(</span><span class=n>element</span><span class=p>.</span><span class=n>first</span><span class=p>),</span>
<span class=w> </span><span class=n>std</span><span class=o>::</span><span class=n>forward_as_tuple</span><span class=p>());</span>
<span class=n>tmp</span><span class=p>.</span><span class=n>emplace_back</span><span class=p>(</span><span class=n>std</span><span class=o>::</span><span class=n>forward</span><span class=o>&lt;</span><span class=n>Args</span><span class=o>&gt;</span><span class=p>(</span><span class=n>args</span><span class=p>)...);</span>
<span class=c1>// phase 2, cannot throw: move-assign the values, adopt the storage</span>
<span class=k>auto</span><span class=w> </span><span class=n>it</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>tmp</span><span class=p>.</span><span class=n>begin</span><span class=p>();</span>
<span class=k>for</span><span class=w> </span><span class=p>(</span><span class=k>auto</span><span class=o>&amp;</span><span class=w> </span><span class=n>element</span><span class=w> </span><span class=o>:</span><span class=w> </span><span class=o>*</span><span class=k>this</span><span class=p>)</span><span class=w> </span><span class=p>{</span><span class=w> </span><span class=n>it</span><span class=o>-&gt;</span><span class=n>second</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>move</span><span class=p>(</span><span class=n>element</span><span class=p>.</span><span class=n>second</span><span class=p>);</span><span class=w> </span><span class=o>++</span><span class=n>it</span><span class=p>;</span><span class=w> </span><span class=p>}</span>
<span class=n>Container</span><span class=o>::</span><span class=n>swap</span><span class=p>(</span><span class=n>tmp</span><span class=p>);</span>
</code></pre></div> <p class=nj-code-caption>How <code>ordered_map</code> grows its storage in two phases, without copying the values.</p> <p>The new element is constructed before any value is moved, so <code>j.emplace("new", std::move(j["old"]))</code> still works, and the strong guarantee holds without a <code>try</code>, which matters because the library also builds with <code>-fno-exceptions</code>. Parsing <code>twitter.json</code> into <code>ordered_json</code> needs 33% of the allocations and, in the pull request's measurement, about 50% of the time. Unfortunately, compilers with the <abbr title="Edison Design Group, maker of a C++ compiler front end">EDG</abbr> front end (Intel's icpc, NVIDIA's nvc++) consider that pair's move constructor <code>noexcept</code>. There, the vector already "moves", the new path is not taken, and a key copy that throws during growth calls <code>std::terminate</code>.</p> <h3 id=containers-built-one-element-at-a-time>Containers built one element at a time<a class=headerlink href=#containers-built-one-element-at-a-time title="Permanent link">&para;</a></h3> <p>The <abbr title="Document Object Model">DOM</abbr> parser used to <code>push_back</code> every element into its array, and insert every member into its object as soon as it was parsed. Now all open arrays share one stack of elements; when an array of up to 16 elements ends, it is constructed at its exact size from a range of move iterators, one allocation. <code>ordered_json</code> objects collect up to 32 members the same way, with a linear duplicate-key check over that short slice, and larger objects get a side table of hashes for that check from 64 members on. An <code>ordered_json</code> object with very many members went from 43 million instructions to 1.9 million, and <code>ordered_json</code> now parses 1–15% <em>faster</em> than <code>json</code> in our suite, since <code>json</code>'s <code>std::map</code> still allocates a node per member. The binary readers know their sizes up front and use a separate handler without the stack; sharing it had made them 5–12% slower with <abbr title="GNU Compiler Collection">GCC</abbr>.</p> <p>The binary readers also stopped taking every element through their general dispatch. When an array opens, the <abbr title="Concise Binary Object Representation">CBOR</abbr> and MessagePack readers read the numbers, booleans, and nulls that follow in one loop, and the <abbr title="Universal Binary JSON">UBJSON</abbr> and <abbr title="Binary JData">BJData</abbr> readers do the same for arrays with a type marker. Reading an array of a million integers from <abbr title="Concise Binary Object Representation">CBOR</abbr> or MessagePack got 42–47% faster, and <code>canada.json</code> 10%. Arrays of one element skip the loop: in 1,000 arrays nested in each other, each entered it only to find another array, which cost 6–8%. Now the loop costs nested arrays nothing measurable, and costs 100,000 arrays <code>[1,2]</code> at most 1.5%.</p> <h3 id=smaller-ones>Smaller ones<a class=headerlink href=#smaller-ones title="Permanent link">&para;</a></h3> <p>The parser checks for the expected <code>:</code> or <code>,</code> before it falls into the lexer's general token switch (−7% on <code>citm_catalog.json</code>, a contribution by <a href="https://github.com/mvanslobbe">@mvanslobbe</a>), and <a href=../../../api/basic_json/to_cbor/ ><code>to_cbor()</code></a> no longer creates a temporary <code>basic_json</code> for every object key it writes (−55% on <code>twitter.json</code>, by <a href="https://github.com/alexprabhat99">@alexprabhat99</a>).</p> <div class="admonition note"> <p class=admonition-title>The same idea, measured twice</p> <p>The <abbr title="Simple API for XML">SAX</abbr> interface hands the lexer's buffer to the handler as <code>string_t&amp;</code> and allows it to be moved from; the lexer starts each token with an empty buffer anyway. In September, moving string values instead of copying them saved 2–3%. We measured moving keys too, and dropped it. The buffer is sized for the longest token so far, and keys are short while values are long. So moving a key hands a large buffer to a short string, and the next value has to grow a new one: 11.9% slower on 40,000 short strings. In October, with much of the lexer around it rewritten, moving keys was measured again: <code>parse()</code> of <code>twitter.json</code> got 3.3% faster with Clang and 5.0% with <abbr title="GNU Compiler Collection">GCC</abbr>, so keys are moved now too. An idea that lost once is worth measuring again when the code around it changes.</p> </div> <h2 id=theme-5><span class=nj-theme>5</span> Read the assembly<a class=headerlink href=#theme-5 title="Permanent link">&para;</a></h2> <p>A good part of 3.13.0 came from reading what the compiler made of the hot loops, with Clang's <code>-Rpass-missed=inline</code>, profiles, and instruction counts. None of the following shows up in the source as a problem.</p> <h3 id=a-stack-canary-on-every-token>A stack canary on every token<a class=headerlink href=#a-stack-canary-on-every-token title="Permanent link">&para;</a></h3> <p>The function that dispatches on the first byte of a token built the expected text of <code>true</code>, <code>false</code>, and <code>null</code> in local arrays:</p> <div class=highlight><pre><span></span><code><span class=k>case</span><span class=w> </span><span class=sc>'t'</span><span class=p>:</span><span class=w> </span><span class=c1>// 3.12.0</span>
<span class=p>{</span>
<span class=w> </span><span class=n>std</span><span class=o>::</span><span class=n>array</span><span class=o>&lt;</span><span class=n>char_type</span><span class=p>,</span><span class=w> </span><span class=mi>4</span><span class=o>&gt;</span><span class=w> </span><span class=n>true_literal</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=p>{{</span><span class=sc>'t'</span><span class=p>,</span><span class=w> </span><span class=sc>'r'</span><span class=p>,</span><span class=w> </span><span class=sc>'u'</span><span class=p>,</span><span class=w> </span><span class=sc>'e'</span><span class=p>}};</span>
<span class=w> </span><span class=k>return</span><span class=w> </span><span class=n>scan_literal</span><span class=p>(</span><span class=n>true_literal</span><span class=p>.</span><span class=n>data</span><span class=p>(),</span><span class=w> </span><span class=n>true_literal</span><span class=p>.</span><span class=n>size</span><span class=p>(),</span><span class=w> </span><span class=n>token_type</span><span class=o>::</span><span class=n>literal_true</span><span class=p>);</span>
<span class=p>}</span>
</code></pre></div> <p class=nj-code-caption>The 3.12.0 lexer's dispatch for <code>true</code>: a local array, and with it a stack canary.</p> <p>With <code>-fstack-protector-strong</code>, which Ubuntu's <abbr title="GNU Compiler Collection">GCC</abbr> enables by default and many distributions use for their packages, <em>any</em> local array gives a function a stack canary: the prologue loads a secret (on x86-64 Linux from thread-local storage) and stores it next to the locals, and every return compares it. Even worse, that happens on every call, also for the <code>[</code>, <code>,</code> and <code>"</code> tokens that never touch the array. The canary's load alone was 11% of the function's samples. (Plain <code>-fstack-protector</code> only protects character arrays of at least 8 bytes, so it didn't trigger here.) Now the literal is a string literal whose length is a template parameter, compared on contiguous input with one <code>memcmp</code> of constant size, and the dispatch has no canary and no array on the stack:</p> <div class=highlight><pre><span></span><code><span class=k>case</span><span class=w> </span><span class=sc>'t'</span><span class=p>:</span><span class=w> </span><span class=k>return</span><span class=w> </span><span class=n>scan_literal</span><span class=p>(</span><span class=s>"rue"</span><span class=p>,</span><span class=w> </span><span class=n>token_type</span><span class=o>::</span><span class=n>literal_true</span><span class=p>);</span>
<span class=k>template</span><span class=o>&lt;</span><span class=n>std</span><span class=o>::</span><span class=kt>size_t</span><span class=w> </span><span class=n>N</span><span class=o>&gt;</span>
<span class=n>JSON_HEDLEY_NEVER_INLINE</span><span class=w> </span><span class=n>token_type</span><span class=w> </span><span class=n>scan_literal</span><span class=p>(</span><span class=k>const</span><span class=w> </span><span class=kt>char</span><span class=w> </span><span class=p>(</span><span class=o>&amp;</span><span class=n>rest</span><span class=p>)[</span><span class=n>N</span><span class=p>],</span><span class=w> </span><span class=n>token_type</span><span class=w> </span><span class=n>return_type</span><span class=p>);</span>
</code></pre></div> <p class=nj-code-caption>The 3.13.0 dispatch: a string literal whose length is a template parameter.</p> <p><code>scan_literal()</code> is deliberately out of line: inlined, it made Clang's dispatch grow from 233 to 278 instructions, and slower. Together with the next change, validating <code>canada.json</code> got 10.5% faster with <abbr title="GNU Compiler Collection">GCC</abbr> on x86-64. The same change replaced the parser's <code>std::vector&lt;bool&gt;</code> nesting stack, whose <code>push_back</code> <abbr title="GNU Compiler Collection">GCC</abbr> called out of line, with <code>std::vector&lt;std::uint8_t&gt;</code>; a bit vector saves memory that a stack of nesting levels doesn't need.</p> <h3 id=exceptions-that-block-inlining>Exceptions that block inlining<a class=headerlink href=#exceptions-that-block-inlining title="Permanent link">&para;</a></h3> <p>A function that can throw builds the message, allocates the exception, and needs a landing pad for every temporary, even if the throw never happens:</p> <div class=highlight><pre><span></span><code><span class=k>if</span><span class=w> </span><span class=p>(</span><span class=n>JSON_HEDLEY_LIKELY</span><span class=p>(</span><span class=n>ptr</span><span class=w> </span><span class=o>!=</span><span class=w> </span><span class=nb>nullptr</span><span class=p>))</span><span class=w> </span><span class=p>{</span><span class=w> </span><span class=k>return</span><span class=w> </span><span class=o>*</span><span class=n>ptr</span><span class=p>;</span><span class=w> </span><span class=p>}</span><span class=w> </span><span class=c1>// 3.12.0, get_ref()</span>
<span class=n>JSON_THROW</span><span class=p>(</span><span class=n>type_error</span><span class=o>::</span><span class=n>create</span><span class=p>(</span><span class=mi>303</span><span class=p>,</span><span class=w> </span><span class=n>detail</span><span class=o>::</span><span class=n>concat</span><span class=p>(</span>
<span class=w> </span><span class=s>"incompatible ReferenceType for get_ref, actual type is "</span><span class=p>,</span><span class=w> </span><span class=n>obj</span><span class=p>.</span><span class=n>type_name</span><span class=p>()),</span><span class=w> </span><span class=o>&amp;</span><span class=n>obj</span><span class=p>));</span>
</code></pre></div> <p class=nj-code-caption>The throw in 3.12.0's <code>get_ref()</code>: building the message makes the function too big to inline.</p> <p>That made <a href=../../../api/basic_json/get_ref/ ><code>get_ref()</code></a>, <a href=../../../api/basic_json/operator%5B%5D/ ><code>operator[]</code></a>, <a href=../../../api/basic_json/at/ ><code>at()</code></a> and the iterator operators too big to inline, and gave callers large frames (192 bytes for <code>get_ref()</code> with <abbr title="GNU Compiler Collection">GCC</abbr>). 3.13.0 moves construction and <code>throw</code> into helpers marked <code>[[noreturn]]</code> and never inlined, so the hot function keeps a test and a call:</p> <div class=highlight><pre><span></span><code><span class=k>if</span><span class=w> </span><span class=p>(</span><span class=n>JSON_HEDLEY_LIKELY</span><span class=p>(</span><span class=n>ptr</span><span class=w> </span><span class=o>!=</span><span class=w> </span><span class=nb>nullptr</span><span class=p>))</span><span class=w> </span><span class=p>{</span><span class=w> </span><span class=k>return</span><span class=w> </span><span class=o>*</span><span class=n>ptr</span><span class=p>;</span><span class=w> </span><span class=p>}</span>
<span class=n>throw_incompatible_reference_type</span><span class=p>(</span><span class=n>obj</span><span class=p>);</span><span class=w> </span><span class=c1>// JSON_HEDLEY_NO_RETURN JSON_HEDLEY_NEVER_INLINE</span>
</code></pre></div> <p class=nj-code-caption>The same function in 3.13.0: a test and a call of a helper that is never inlined.</p> <p>That fixed 27 throw sites. Iterator arithmetic got 6× as fast with Clang, and <code>std::sort</code> over a <code>json</code> array of 10,000 integers in user code 6–9% faster.</p> <p>The value's own lifecycle had the same problem: the destructor, the copy constructor, and <a href=../../../api/basic_json/operator_eq/ ><code>operator==</code></a> contained the code for every type, so they were too big to inline even for a number. Clang reported about 380 call sites where they were not inlined. Now the destructor and the copy constructor start with an inline test whether the value owns memory, which Clang compiles to one bit test (<code>1 &lt;&lt; type &amp; 0x10E</code>), <code>operator==</code> with one for two scalars of the same type, and the rest is out of line. <code>j == 5</code> went from 3.55 ns to 0.65 ns with Clang. It is not free: a test file of <code>extern "C"</code> wrappers around the library's functions, which we compile to check what gets inlined, grew by 13% at <code>-O2</code>, and with <abbr title="GNU Compiler Collection">GCC</abbr>, <code>operator==</code> on large documents got about 7% slower.</p> <h3 id=aliasing>Aliasing<a class=headerlink href=#aliasing title="Permanent link">&para;</a></h3> <p>C++ allows a <code>char</code> to access any object, so a store through a <code>char</code> pointer may change any object whose address the compiler can't rule out. In a writer that keeps its write position <code>pos</code> in a member, <code>buffer[pos++] = c</code> therefore costs more than it looks: the compiler can't prove that the store of <code>c</code> didn't overwrite <code>pos</code> itself, so it writes <code>pos</code> to memory before every character and loads it again after. A local variable whose address never escapes can't be reached by any store, and stays in a register:</p> <div class=highlight><pre><span></span><code><span class=n>std</span><span class=o>::</span><span class=kt>size_t</span><span class=w> </span><span class=n>pos</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>write_buffer_pos</span><span class=p>;</span><span class=w> </span><span class=c1>// a local: no char store can reach it</span>
<span class=c1>// ... write_buffer[pos++] = digit; ...</span>
<span class=n>write_buffer_pos</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>pos</span><span class=p>;</span><span class=w> </span><span class=c1>// published once at the end</span>
</code></pre></div> <p class=nj-code-caption>Keeping the write position in a local, so that the compiler can keep it in a register.</p> <p>On a 4 MiB binary value, <a href=../../../api/basic_json/dump/ ><code>dump()</code></a> went from 18.0 ms to 7.4 ms with this change alone. <code>json_document</code>'s writer and the binary writers keep their cursors in locals for the same reason, and publish them before any call that could see them.</p> <h3 id=loop-shape-beats-branch-count>Loop shape beats branch count<a class=headerlink href=#loop-shape-beats-branch-count title="Permanent link">&para;</a></h3> <p>A change that removed one branch per whitespace byte made scanning long runs of indentation 1.75–3.2× <em>slower</em> with Clang and <abbr title="GNU Compiler Collection">GCC</abbr>. It had rewritten <code>do { get(); } while (is_whitespace());</code> into <code>get(); while (is_whitespace()) { get_ignoring_pending_unget(); }</code>, and the assembly showed why it lost: neither compiler kept the input's read and end pointers in registers any more, and both reloaded them from memory on every character. Restoring the do-while shape, <code>get(); if (is_whitespace()) { do { ... } while (is_whitespace()); }</code>, fixed it. We don't know why the while loop lost the registers, only that the do-while shape gets them back.</p> <h3 id=inlining-that-disappears>Inlining that disappears<a class=headerlink href=#inlining-that-disappears title="Permanent link">&para;</a></h3> <p>Inlining is a budget per function. Once the string writer had grown, <abbr title="GNU Compiler Collection">GCC</abbr> 13 and 16 stopped inlining two tiny, unchanged helpers into the pretty-printing loop, and indented output got up to 13% slower. They are now forced inline. A change in one place silently made an unrelated loop slower; only a benchmark of indented output noticed.</p> <h3 id=branches-the-compiler-chose>Branches the compiler chose<a class=headerlink href=#branches-the-compiler-chose title="Permanent link">&para;</a></h3> <p><a href=../../../api/json_document/ ><code>json_document</code></a> writes most floats of <code>canada.json</code> by deciding, from where the <code>double</code> lies relative to its source text, which of two or three candidate digit strings to write. The conditions of those selections depend on the digits, so they are as good as random:</p> <div class=highlight><pre><span></span><code><span class=k>const</span><span class=w> </span><span class=kt>bool</span><span class=w> </span><span class=n>up</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>from</span><span class=w> </span><span class=o>&gt;</span><span class=w> </span><span class=mi>37</span><span class=w> </span><span class=o>*</span><span class=w> </span><span class=n>one</span><span class=p>;</span>
<span class=k>const</span><span class=w> </span><span class=kt>bool</span><span class=w> </span><span class=n>shorter</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>biased_distance</span><span class=p>(</span><span class=n>from</span><span class=w> </span><span class=o>-</span><span class=w> </span><span class=p>(</span><span class=n>up</span><span class=w> </span><span class=o>?</span><span class=w> </span><span class=mi>10</span><span class=w> </span><span class=o>*</span><span class=w> </span><span class=n>one</span><span class=w> </span><span class=o>:</span><span class=w> </span><span class=mi>0</span><span class=p>))</span><span class=w> </span><span class=o>&lt;</span><span class=w> </span><span class=n>radius</span><span class=p>;</span>
<span class=k>const</span><span class=w> </span><span class=n>std</span><span class=o>::</span><span class=kt>uint64_t</span><span class=w> </span><span class=n>a</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>w</span><span class=w> </span><span class=o>-</span><span class=w> </span><span class=n>r10</span><span class=w> </span><span class=o>+</span><span class=w> </span><span class=p>(</span><span class=n>up</span><span class=w> </span><span class=o>?</span><span class=w> </span><span class=mi>10u</span><span class=w> </span><span class=o>:</span><span class=w> </span><span class=mi>0u</span><span class=p>);</span>
<span class=k>return</span><span class=w> </span><span class=n>shorter</span><span class=w> </span><span class=o>?</span><span class=w> </span><span class=n>a</span><span class=w> </span><span class=o>:</span><span class=w> </span><span class=n>b</span><span class=p>;</span>
</code></pre></div> <p class=nj-code-caption>Selecting a candidate digit string: <abbr title="GNU Compiler Collection">GCC</abbr> 13 compiled the conditional operators as jumps.</p> <p>Clang compiled the <code>?:</code> as conditional moves; <abbr title="GNU Compiler Collection">GCC</abbr> 13 compiled them as jumps. With nothing to tell it that the conditions are unpredictable, a branch that skips some work looks cheaper than computing both sides. <a href="https://valgrind.org/docs/manual/cl-manual.html">Callgrind</a>'s branch simulation counted 220,000 mispredictions per dump of <code>canada.json</code> with <abbr title="GNU Compiler Collection">GCC</abbr>, against 97,000 with Clang. Written as masks, which have no branch form to reconstruct, the selections stay branch-free with <abbr title="GNU Compiler Collection">GCC</abbr> and Clang:</p> <div class=highlight><pre><span></span><code><span class=c1>// all ones or zero</span>
<span class=n>std</span><span class=o>::</span><span class=kt>uint64_t</span><span class=w> </span><span class=nf>mask_if</span><span class=p>(</span><span class=kt>bool</span><span class=w> </span><span class=n>b</span><span class=p>)</span><span class=w> </span><span class=p>{</span><span class=w> </span><span class=k>return</span><span class=w> </span><span class=n>std</span><span class=o>::</span><span class=kt>uint64_t</span><span class=p>{</span><span class=mi>0</span><span class=p>}</span><span class=w> </span><span class=o>-</span><span class=w> </span><span class=k>static_cast</span><span class=o>&lt;</span><span class=n>std</span><span class=o>::</span><span class=kt>uint64_t</span><span class=o>&gt;</span><span class=p>(</span><span class=n>b</span><span class=p>);</span><span class=w> </span><span class=p>}</span>
<span class=n>std</span><span class=o>::</span><span class=kt>uint64_t</span><span class=w> </span><span class=nf>select_if</span><span class=p>(</span><span class=kt>bool</span><span class=w> </span><span class=n>b</span><span class=p>,</span><span class=w> </span><span class=n>std</span><span class=o>::</span><span class=kt>uint64_t</span><span class=w> </span><span class=n>a</span><span class=p>,</span><span class=w> </span><span class=n>std</span><span class=o>::</span><span class=kt>uint64_t</span><span class=w> </span><span class=n>c</span><span class=p>)</span>
<span class=p>{</span>
<span class=w> </span><span class=k>return</span><span class=w> </span><span class=n>c</span><span class=w> </span><span class=o>^</span><span class=w> </span><span class=p>((</span><span class=n>a</span><span class=w> </span><span class=o>^</span><span class=w> </span><span class=n>c</span><span class=p>)</span><span class=w> </span><span class=o>&amp;</span><span class=w> </span><span class=n>mask_if</span><span class=p>(</span><span class=n>b</span><span class=p>));</span>
<span class=p>}</span>
<span class=k>const</span><span class=w> </span><span class=kt>bool</span><span class=w> </span><span class=n>shorter</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>biased_distance</span><span class=p>(</span><span class=n>from</span><span class=w> </span><span class=o>-</span><span class=w> </span><span class=p>(</span><span class=n>mask_if</span><span class=p>(</span><span class=n>up</span><span class=p>)</span><span class=w> </span><span class=o>&amp;</span><span class=w> </span><span class=p>(</span><span class=mi>10</span><span class=w> </span><span class=o>*</span><span class=w> </span><span class=n>one</span><span class=p>)))</span><span class=w> </span><span class=o>&lt;</span><span class=w> </span><span class=n>radius</span><span class=p>;</span>
<span class=k>const</span><span class=w> </span><span class=n>std</span><span class=o>::</span><span class=kt>uint64_t</span><span class=w> </span><span class=n>a</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>w</span><span class=w> </span><span class=o>-</span><span class=w> </span><span class=n>r10</span><span class=w> </span><span class=o>+</span><span class=w> </span><span class=p>(</span><span class=n>mask_if</span><span class=p>(</span><span class=n>up</span><span class=p>)</span><span class=w> </span><span class=o>&amp;</span><span class=w> </span><span class=mi>10u</span><span class=p>);</span>
<span class=k>return</span><span class=w> </span><span class=n>select_if</span><span class=p>(</span><span class=n>shorter</span><span class=p>,</span><span class=w> </span><span class=n>a</span><span class=p>,</span><span class=w> </span><span class=n>b</span><span class=p>);</span>
</code></pre></div> <p class=nj-code-caption>The same selections written as masks, which stay branch-free with <abbr title="GNU Compiler Collection">GCC</abbr> and Clang.</p> <p>With <abbr title="GNU Compiler Collection">GCC</abbr> on x86-64, the mispredictions went down to 98,000, and the dump of <code>canada.json</code> got about 15% faster with 5% <em>more</em> instructions. With Clang, the time stayed the same. We found this one while writing this post.</p> <h3 id=code-size-as-a-cost>Code size as a cost<a class=headerlink href=#code-size-as-a-cost title="Permanent link">&para;</a></h3> <p><a href=../../../api/basic_json/get/ ><code>get&lt;std::array&lt;int, 1000&gt;&gt;()</code></a> used a pack expansion, <code>{{ j.at(Idx).get&lt;T&gt;()... }}</code>. A pack expansion is unrolled before the optimizer decides anything, so once <code>at()</code> had become small enough to inline, Clang emitted one function of about 28,000 instructions (with 3.12.0, about 8,000): a thousand inlined copies of the bounds and type checks. Its time moved from 657 to 957 ns just by aligning the code differently. A loop needs 49 instructions.</p> <div class="admonition note"> <p class=admonition-title>Instruction counts, not only time</p> <p>On the x86-64 machine we used for checking, moving code by a few bytes changed the time of unrelated benchmarks by up to ±5%. Many decisions were therefore made on instruction counts (callgrind on Linux, <code>/usr/bin/time -l</code> on macOS), checked against timings of builds with all functions and loops aligned to 64 bytes, and timed interleaved in one binary with several code layouts. The target, applied strictly in the later changes, was: at least 3% faster, and no benchmark more than 1% slower. Some changes accepted a small loss elsewhere and say so, such as the 7% on <abbr title="GNU Compiler Collection">GCC</abbr>'s <code>operator==</code> above. The branch example shows the limit of that rule: it is faster with more instructions.</p> </div> <h2 id=theme-6><span class=nj-theme>6</span> Write through a cursor<a class=headerlink href=#theme-6 title="Permanent link">&para;</a></h2> <p>In 3.12.0, every <a href=../../../api/basic_json/dump/ ><code>dump()</code></a> created its output adapter with <code>std::make_shared</code>, built a 512-character indentation string, and the serializer wrote every structural character through a virtual call:</p> <div class=highlight><pre><span></span><code><span class=n>o</span><span class=o>-&gt;</span><span class=n>write_characters</span><span class=p>(</span><span class=s>"{</span><span class=se>\n</span><span class=s>"</span><span class=p>,</span><span class=w> </span><span class=mi>2</span><span class=p>);</span>
<span class=n>o</span><span class=o>-&gt;</span><span class=n>write_characters</span><span class=p>(</span><span class=n>indent_string</span><span class=p>.</span><span class=n>c_str</span><span class=p>(),</span><span class=w> </span><span class=n>new_indent</span><span class=p>);</span>
<span class=n>o</span><span class=o>-&gt;</span><span class=n>write_character</span><span class=p>(</span><span class=sc>'\"'</span><span class=p>);</span>
</code></pre></div> <p class=nj-code-caption>How the 3.12.0 serializer wrote an object's opening brace and the start of a key: three virtual calls.</p> <p>The writing side changed in five steps, one per subsection below:</p> <pre class=mermaid><code>flowchart LR
subgraph before["3.12.0"]
direction LR
d1["dump()"] --&gt; a1["make_shared&lt;br&gt;output adapter"] --&gt; v1["virtual call&lt;br&gt;per write"] --&gt; s1[("std::string")]
end
subgraph after["3.13.0"]
direction LR
d2["dump()"] --&gt; a2["adapter on&lt;br&gt;the stack"] --&gt; b2["1 KiB buffer,&lt;br&gt;bulk append"] --&gt; s2[("std::string")]
end</code></pre> <p class=nj-caption>The text serializer's output path before and after the first two steps.</p> <h3 id=a-buffer-in-the-serializer>A buffer in the serializer<a class=headerlink href=#a-buffer-in-the-serializer title="Permanent link">&para;</a></h3> <p>All writes go into a 1 KiB buffer that is flushed in bulk, so the virtual call happens once per KiB, and neighboring writes can be merged. Runs longer than the buffer are written straight through, so they are not copied twice.</p> <div class=highlight><pre><span></span><code><span class=kt>void</span><span class=w> </span><span class=nf>put_char</span><span class=p>(</span><span class=kt>char</span><span class=w> </span><span class=n>c</span><span class=p>)</span>
<span class=p>{</span>
<span class=w> </span><span class=k>if</span><span class=w> </span><span class=p>(</span><span class=n>JSON_HEDLEY_UNLIKELY</span><span class=p>(</span><span class=n>write_buffer_pos</span><span class=w> </span><span class=o>==</span><span class=w> </span><span class=n>write_buffer</span><span class=p>.</span><span class=n>size</span><span class=p>()))</span><span class=w> </span><span class=p>{</span><span class=w> </span><span class=n>flush</span><span class=p>();</span><span class=w> </span><span class=p>}</span><span class=w> </span><span class=c1>// virtual</span>
<span class=w> </span><span class=n>write_buffer</span><span class=p>[</span><span class=n>write_buffer_pos</span><span class=o>++</span><span class=p>]</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>c</span><span class=p>;</span>
<span class=p>}</span>
</code></pre></div> <p class=nj-code-caption>Writing one character: the virtual call happens only when the buffer is full.</p> <h3 id=no-allocation-per-call>No allocation per call<a class=headerlink href=#no-allocation-per-call title="Permanent link">&para;</a></h3> <p>The adapter lives on the stack, and there is no indentation string any more: <code>dump(4)</code> writes the spaces straight into the buffer. A compact <code>dump()</code> of a small object went from 4 heap allocations to 1 with libstdc++ (3 to 1 with libc++): the returned string, and none if it fits into the string's small buffer.</p> <h3 id=a-concrete-sink-for-the-binary-writers>A concrete sink for the binary writers<a class=headerlink href=#a-concrete-sink-for-the-binary-writers title="Permanent link">&para;</a></h3> <p>The overloads of <a href=../../../api/basic_json/to_cbor/ ><code>to_cbor()</code></a> and friends that return a <code>std::vector</code> use a writer that is a template over the sink type, with no virtual call. Byte order is now swapped with <code>__builtin_bswap*</code> (or <code>_byteswap_*</code> with <abbr title="Microsoft Visual C++">MSVC</abbr>) instead of <code>std::reverse</code> on a byte array: compilers can recognize the reversal as a byte swap in a small function, but in the <abbr title="Concise Binary Object Representation">CBOR</abbr> number path, Clang emitted no <code>bswap</code> at all. Writing into a vector also allows <a href=../../../api/basic_json/to_bson/ ><code>to_bson()</code></a> to make one pass instead of two, because a vector can be written to at any position: <abbr title="Binary JSON">BSON</abbr> puts the size of every document in front of it, so the writer used to walk the value once for the sizes and once to write. It now writes a placeholder and fills in the size when the document is complete, 12–20% faster on the M1. Streams and other output adapters, which can only append, still take two passes.</p> <h3 id=a-cursor-instead-of-vectorinsert>A cursor instead of <code>vector::insert()</code><a class=headerlink href=#a-cursor-instead-of-vectorinsert title="Permanent link">&para;</a></h3> <p>After the previous step, writing an array of integers as <abbr title="Concise Binary Object Representation">CBOR</abbr> was still no faster than in 3.12.0, and slower with <abbr title="GNU Compiler Collection">GCC</abbr>. The profile said why: each number's one to eight bytes were appended with <code>vector::insert()</code>, which both standard libraries implement as an out-of-line insert-anywhere routine; it took 30% of the time, more than encoding the numbers. The sink now keeps a cursor and a limit pointer, reserves space for a whole run of numbers at once, and writes through the cursor:</p> <div class=highlight><pre><span></span><code><span class=n>CharType</span><span class=o>*</span><span class=w> </span><span class=k>const</span><span class=w> </span><span class=n>start</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>oa</span><span class=p>.</span><span class=n>reserve</span><span class=p>(</span><span class=n>max_run</span><span class=w> </span><span class=o>*</span><span class=w> </span><span class=n>integer_encoding_space</span><span class=p>);</span><span class=w> </span><span class=c1>// one check per run</span>
<span class=n>CharType</span><span class=o>*</span><span class=w> </span><span class=n>out</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>start</span><span class=p>;</span>
<span class=k>for</span><span class=w> </span><span class=p>(</span><span class=n>n</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=mi>0</span><span class=p>;</span><span class=w> </span><span class=n>n</span><span class=w> </span><span class=o>&lt;</span><span class=w> </span><span class=n>max_run</span><span class=w> </span><span class=o>&amp;&amp;</span><span class=w> </span><span class=n>it</span><span class=w> </span><span class=o>!=</span><span class=w> </span><span class=n>end</span><span class=w> </span><span class=o>&amp;&amp;</span><span class=w> </span><span class=n>it</span><span class=o>-&gt;</span><span class=n>is_number_integer</span><span class=p>();</span><span class=w> </span><span class=o>++</span><span class=n>n</span><span class=p>,</span><span class=w> </span><span class=o>++</span><span class=n>it</span><span class=p>)</span>
<span class=p>{</span>
<span class=w> </span><span class=n>out</span><span class=w> </span><span class=o>+=</span><span class=w> </span><span class=n>encode_integer</span><span class=p>(</span><span class=n>out</span><span class=p>,</span><span class=w> </span><span class=o>*</span><span class=n>it</span><span class=p>);</span>
<span class=p>}</span>
<span class=n>oa</span><span class=p>.</span><span class=n>commit</span><span class=p>(</span><span class=n>out</span><span class=w> </span><span class=o>-</span><span class=w> </span><span class=n>start</span><span class=p>);</span>
</code></pre></div> <p class=nj-code-caption>Encoding a run of integers through a cursor, with one capacity check for the whole run.</p> <h3 id=integers-without-branches>Integers without branches<a class=headerlink href=#integers-without-branches title="Permanent link">&para;</a></h3> <p>The last step also took the branches out of encoding an integer. After the bounds checks, mispredicted branches accounted for about 40% of the remaining time: the type, the sign, and the 1-, 2-, 4-, or 8-byte size class of each integer in a stream are hard to predict. The encoder reads signed and unsigned integers through one masked path, looks the size class up from the number of leading zero bits, and stores the head as one byte plus one 8-byte word, of which the caller keeps only as many bytes as the class needs:</p> <div class=highlight><pre><span></span><code><span class=c1>// 1, 2, 3 or 4 if x fits 1, 2, 4 or 8 bytes, without a branch</span>
<span class=k>static</span><span class=w> </span><span class=kt>unsigned</span><span class=w> </span><span class=nf>integer_size_class</span><span class=p>(</span><span class=k>const</span><span class=w> </span><span class=n>std</span><span class=o>::</span><span class=kt>uint64_t</span><span class=w> </span><span class=n>x</span><span class=p>)</span><span class=w> </span><span class=k>noexcept</span>
<span class=p>{</span>
<span class=w> </span><span class=k>static</span><span class=w> </span><span class=k>constexpr</span><span class=w> </span><span class=n>std</span><span class=o>::</span><span class=n>array</span><span class=o>&lt;</span><span class=n>std</span><span class=o>::</span><span class=kt>uint8_t</span><span class=p>,</span><span class=w> </span><span class=mi>64</span><span class=o>&gt;</span><span class=w> </span><span class=n>size_class_by_leading_zeros</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=p>{</span><span class=w> </span><span class=cm>/* ... */</span><span class=w> </span><span class=p>};</span>
<span class=w> </span><span class=k>return</span><span class=w> </span><span class=n>size_class_by_leading_zeros</span><span class=p>[</span><span class=n>count_leading_zeros</span><span class=p>(</span><span class=n>x</span><span class=w> </span><span class=o>|</span><span class=w> </span><span class=mi>1u</span><span class=p>)];</span>
<span class=p>}</span>
<span class=n>std</span><span class=o>::</span><span class=kt>size_t</span><span class=w> </span><span class=nf>encode_first_byte_and_tail</span><span class=p>(</span><span class=n>CharType</span><span class=o>*</span><span class=w> </span><span class=n>out</span><span class=p>,</span><span class=w> </span><span class=n>std</span><span class=o>::</span><span class=kt>uint8_t</span><span class=w> </span><span class=n>first_byte</span><span class=p>,</span>
<span class=w> </span><span class=kt>unsigned</span><span class=w> </span><span class=n>size_class</span><span class=p>,</span><span class=w> </span><span class=n>std</span><span class=o>::</span><span class=kt>uint64_t</span><span class=w> </span><span class=n>value</span><span class=p>)</span><span class=w> </span><span class=k>const</span><span class=w> </span><span class=k>noexcept</span>
<span class=p>{</span>
<span class=w> </span><span class=n>out</span><span class=p>[</span><span class=mi>0</span><span class=p>]</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>to_char_type</span><span class=p>(</span><span class=n>first_byte</span><span class=p>);</span>
<span class=w> </span><span class=k>const</span><span class=w> </span><span class=kt>unsigned</span><span class=w> </span><span class=n>unused_bits</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=mi>64u</span><span class=w> </span><span class=o>-</span><span class=w> </span><span class=p>((</span><span class=mi>8u</span><span class=w> </span><span class=o>&lt;&lt;</span><span class=w> </span><span class=n>size_class</span><span class=p>)</span><span class=w> </span><span class=o>&gt;&gt;</span><span class=w> </span><span class=mi>1u</span><span class=p>);</span>
<span class=w> </span><span class=k>const</span><span class=w> </span><span class=n>std</span><span class=o>::</span><span class=kt>uint64_t</span><span class=w> </span><span class=n>tail</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>is_little_endian</span><span class=w> </span><span class=o>?</span><span class=w> </span><span class=n>byteswap</span><span class=p>(</span><span class=n>value</span><span class=p>)</span><span class=w> </span><span class=o>&gt;&gt;</span><span class=w> </span><span class=n>unused_bits</span>
<span class=w> </span><span class=o>:</span><span class=w> </span><span class=n>value</span><span class=w> </span><span class=o>&lt;&lt;</span><span class=w> </span><span class=n>unused_bits</span><span class=p>;</span>
<span class=w> </span><span class=c1>// always 8 bytes; the caller keeps the first 0, 1, 2, 4 or 8</span>
<span class=w> </span><span class=n>std</span><span class=o>::</span><span class=n>memcpy</span><span class=p>(</span><span class=n>out</span><span class=w> </span><span class=o>+</span><span class=w> </span><span class=mi>1</span><span class=p>,</span><span class=w> </span><span class=o>&amp;</span><span class=n>tail</span><span class=p>,</span><span class=w> </span><span class=k>sizeof</span><span class=p>(</span><span class=n>tail</span><span class=p>));</span>
<span class=w> </span><span class=k>return</span><span class=w> </span><span class=p>((</span><span class=n>std</span><span class=o>::</span><span class=kt>size_t</span><span class=p>{</span><span class=mi>1</span><span class=p>}</span><span class=w> </span><span class=o>&lt;&lt;</span><span class=w> </span><span class=n>size_class</span><span class=p>)</span><span class=w> </span><span class=o>&gt;&gt;</span><span class=w> </span><span class=mi>1u</span><span class=p>)</span><span class=w> </span><span class=o>+</span><span class=w> </span><span class=mi>1</span><span class=p>;</span>
<span class=p>}</span>
</code></pre></div> <p class=nj-code-caption>Encoding the head of a <abbr title="Concise Binary Object Representation">CBOR</abbr> integer without a branch: the size class from a table, the tail as one 8-byte store.</p> <p>The table is a table because Clang vectorized the equivalent comparisons into slower code, and the unconditional 8-byte store is why <code>reserve()</code> asks for 9 bytes per integer. Writing an array of small signed integers as <abbr title="Concise Binary Object Representation">CBOR</abbr>, which had not gotten faster before, is now 4.2× as fast as with 3.12.0 with Clang on an M1 Max, and was 2.8× as fast with <abbr title="GNU Compiler Collection">GCC</abbr> 13 on x86-64 when the change was made. One more lesson from these changes: the loop over an array is a separate function that is never inlined. Inlined into the function that writes any value, its register needs made every call of that function save more registers, once per nested value, which cost <code>citm_catalog.json</code> 13%.</p> <h2 id=theme-7><span class=nj-theme>7</span> Fix the algorithm first<a class=headerlink href=#theme-7 title="Permanent link">&para;</a></h2> <p>None of the micro-optimizations above matter much next to an algorithm that is quadratic. Seven operations were quadratic or worse in 3.12.0. They are fixes of cases most programs never hit, not tuning, so they are not part of the 3.0× above (except <code>flatten()</code>, which the suite happens to measure); <a href=#d-algorithmic-fixes>Appendix D</a> has the numbers:</p> <div class=nj-fig-wrap> <p><svg class="nj-fig nj-charts nj-charts--blog" viewbox="0 0 600 380" role=img aria-labelledby="nj-blog-cliffs nj-blog-cliffs-d" xmlns=http://www.w3.org/2000/svg> <title id=nj-blog-cliffs>Operations that grew quadratically or worse: time with 3.12.0 and 3.13.0, log scale</title> <desc id=nj-blog-cliffs-d>Dot plot on a logarithmic time axis, less is better; an arrow leads from each 3.12.0 time to the 3.13.0 time. diff() 64k numbers vs []: 4237 ms to 10.8 ms; diff() 20k objects vs half: 122 ms to 4.13 ms; parse() callback, 32k objects: 1398 ms to 12.1 ms; operator&lt; nested 24 deep: 64.4 ms to 0.002 ms; operator&lt; citm, 10x: 284 ms to 3.94 ms; flatten() citm, ordered_json: 271 ms to 1.45 ms; to_bson() 200 deep, 100x: 20.3 ms to 0.352 ms; push_back() 100k, diagnostics: 1589 ms to 5.32 ms; at(i) 10k, diagnostics: 45.9 ms to 0.088 ms.</desc> <line class=nj-charts-grid x1=250 y1=30 x2=250 y2=336 /> <text class=nj-charts-tick x=250 y=352>1 µs</text> <line class=nj-charts-grid x1=297.857 y1=30 x2=297.857 y2=336 /> <text class=nj-charts-tick x=297.857 y=352>10 µs</text> <line class=nj-charts-grid x1=345.714 y1=30 x2=345.714 y2=336 /> <text class=nj-charts-tick x=345.714 y=352>0.1 ms</text> <line class=nj-charts-grid x1=393.571 y1=30 x2=393.571 y2=336 /> <text class=nj-charts-tick x=393.571 y=352>1 ms</text> <line class=nj-charts-grid x1=441.429 y1=30 x2=441.429 y2=336 /> <text class=nj-charts-tick x=441.429 y=352>10 ms</text> <line class=nj-charts-grid x1=489.286 y1=30 x2=489.286 y2=336 /> <text class=nj-charts-tick x=489.286 y=352>0.1 s</text> <line class=nj-charts-grid x1=537.143 y1=30 x2=537.143 y2=336 /> <text class=nj-charts-tick x=537.143 y=352>1 s</text> <line class=nj-charts-grid x1=585 y1=30 x2=585 y2=336 /> <text class=nj-charts-tick x=585 y=352>10 s</text> <text class=nj-charts-tick x=417.5 y=370>runtime (log scale), less is better</text> <defs><marker id=nj-blog-cliffs-head viewbox="0 0 10 10" refx=9 refy=5 markerwidth=5 markerheight=5 orient=auto><path class=nj-charts-head d="M0 0 L10 5 L0 10 z"/></marker></defs> <circle class=nj-charts-ojson-dot cx=250 cy=14 r=5 /><text class=nj-charts-leg x=260 y=18.5>3.12.0</text> <circle class=nj-charts-json-dot cx=330 cy=14 r=5 /><text class=nj-charts-leg x=340 y=18.5>3.13.0</text> <text class=nj-charts-rowlabel x=240 y=52 text-anchor=end>diff() 64k numbers vs []</text> <line class=nj-charts-axis x1=561.152 y1=48 x2=450.028 y2=48 marker-end=url(#nj-blog-cliffs-head) /> <circle class=nj-charts-ojson-dot cx=567.152 cy=48 r=5><title>diff() 64k numbers vs [], 3.12.0: 4237 ms</title></circle> <circle class=nj-charts-json-dot cx=443.028 cy=48 r=5><title>diff() 64k numbers vs [], 3.13.0: 10.8 ms</title></circle> <text class=nj-charts-factor x=505.09 y=41>392&#215;</text> <text class=nj-charts-rowlabel x=240 y=86 text-anchor=end>diff() 20k objects vs half</text> <line class=nj-charts-axis x1=487.419 y1=82 x2=430.049 y2=82 marker-end=url(#nj-blog-cliffs-head) /> <circle class=nj-charts-ojson-dot cx=493.419 cy=82 r=5><title>diff() 20k objects vs half, 3.12.0: 122 ms</title></circle> <circle class=nj-charts-json-dot cx=423.049 cy=82 r=5><title>diff() 20k objects vs half, 3.13.0: 4.13 ms</title></circle> <text class=nj-charts-factor x=458.234 y=75>30&#215;</text> <text class=nj-charts-rowlabel x=240 y=120 text-anchor=end>parse() callback, 32k objects</text> <line class=nj-charts-axis x1=538.106 y1=116 x2=452.39 y2=116 marker-end=url(#nj-blog-cliffs-head) /> <circle class=nj-charts-ojson-dot cx=544.106 cy=116 r=5><title>parse() callback, 32k objects, 3.12.0: 1398 ms</title></circle> <circle class=nj-charts-json-dot cx=445.39 cy=116 r=5><title>parse() callback, 32k objects, 3.13.0: 12.1 ms</title></circle> <text class=nj-charts-factor x=494.748 y=109>116&#215;</text> <text class=nj-charts-rowlabel x=240 y=154 text-anchor=end>operator&lt; nested 24 deep</text> <line class=nj-charts-axis x1=474.14 y1=150 x2=271.406 y2=150 marker-end=url(#nj-blog-cliffs-head) /> <circle class=nj-charts-ojson-dot cx=480.14 cy=150 r=5><title>operator&lt; nested 24 deep, 3.12.0: 64.4 ms</title></circle> <circle class=nj-charts-json-dot cx=264.406 cy=150 r=5><title>operator&lt; nested 24 deep, 3.13.0: 0.002 ms</title></circle> <text class=nj-charts-factor x=372.273 y=143>32200&#215;</text> <text class=nj-charts-rowlabel x=240 y=188 text-anchor=end>operator&lt; citm, 10x</text> <line class=nj-charts-axis x1=504.98 y1=184 x2=429.07 y2=184 marker-end=url(#nj-blog-cliffs-head) /> <circle class=nj-charts-ojson-dot cx=510.98 cy=184 r=5><title>operator&lt; citm, 10x, 3.12.0: 284 ms</title></circle> <circle class=nj-charts-json-dot cx=422.07 cy=184 r=5><title>operator&lt; citm, 10x, 3.13.0: 3.94 ms</title></circle> <text class=nj-charts-factor x=466.525 y=177>72&#215;</text> <text class=nj-charts-rowlabel x=240 y=222 text-anchor=end>flatten() citm, ordered_json</text> <line class=nj-charts-axis x1=504.006 y1=218 x2=408.294 y2=218 marker-end=url(#nj-blog-cliffs-head) /> <circle class=nj-charts-ojson-dot cx=510.006 cy=218 r=5><title>flatten() citm, ordered_json, 3.12.0: 271 ms</title></circle> <circle class=nj-charts-json-dot cx=401.294 cy=218 r=5><title>flatten() citm, ordered_json, 3.13.0: 1.45 ms</title></circle> <text class=nj-charts-factor x=455.65 y=211>187&#215;</text> <text class=nj-charts-rowlabel x=240 y=256 text-anchor=end>to_bson() 200 deep, 100x</text> <line class=nj-charts-axis x1=450.144 y1=252 x2=378.87 y2=252 marker-end=url(#nj-blog-cliffs-head) /> <circle class=nj-charts-ojson-dot cx=456.144 cy=252 r=5><title>to_bson() 200 deep, 100x, 3.12.0: 20.3 ms</title></circle> <circle class=nj-charts-json-dot cx=371.87 cy=252 r=5><title>to_bson() 200 deep, 100x, 3.13.0: 0.352 ms</title></circle> <text class=nj-charts-factor x=414.007 y=245>58&#215;</text> <text class=nj-charts-rowlabel x=240 y=290 text-anchor=end>push_back() 100k, diagnostics</text> <line class=nj-charts-axis x1=540.768 y1=286 x2=435.311 y2=286 marker-end=url(#nj-blog-cliffs-head) /> <circle class=nj-charts-ojson-dot cx=546.768 cy=286 r=5><title>push_back() 100k, diagnostics, 3.12.0: 1589 ms</title></circle> <circle class=nj-charts-json-dot cx=428.311 cy=286 r=5><title>push_back() 100k, diagnostics, 3.13.0: 5.32 ms</title></circle> <text class=nj-charts-factor x=487.54 y=279>299&#215;</text> <text class=nj-charts-rowlabel x=240 y=324 text-anchor=end>at(i) 10k, diagnostics</text> <line class=nj-charts-axis x1=467.101 y1=320 x2=350.057 y2=320 marker-end=url(#nj-blog-cliffs-head) /> <circle class=nj-charts-ojson-dot cx=473.101 cy=320 r=5><title>at(i) 10k, diagnostics, 3.12.0: 45.9 ms</title></circle> <circle class=nj-charts-json-dot cx=343.057 cy=320 r=5><title>at(i) 10k, diagnostics, 3.13.0: 0.088 ms</title></circle> <text class=nj-charts-factor x=408.079 y=313>522&#215;</text> </svg></p> </div> <p class=nj-caption>Operations that were quadratic or worse in 3.12.0, on a logarithmic scale; each arrow leads from the time with 3.12.0 to the time with 3.13.0. Less is better.</p> <h3 id=comparing-in-one-pass>Comparing in one pass<a class=headerlink href=#comparing-in-one-pass title="Permanent link">&para;</a></h3> <p>The most instructive one is <a href=../../../api/basic_json/operator_lt/ ><code>operator&lt;</code></a>. Before C++20, <code>json</code>'s <code>operator&lt;</code> on two arrays or objects called the <code>operator&lt;</code> of <code>std::vector</code> or <code>std::map</code>, which is <code>std::lexicographical_compare</code>. For every pair of elements it asks <code>a &lt; b</code> and, if that is false, <code>b &lt; a</code>. When the elements are themselves containers, both questions recurse into the whole subtree, and when they are equal, both have to go all the way down. So each level of nesting doubles the work: two equal values nested 20 levels deep took 5.7 ms, 30 levels 3.8 seconds, and 40 levels would take about an hour. That matters to anyone who keeps <code>json</code> values in a <code>std::set</code>, uses them as <code>std::map</code> keys, or sorts them. Since C++20, <code>operator&lt;</code> is derived from <a href=../../../api/basic_json/operator_spaceship/ ><code>operator&lt;=&gt;</code></a>, which asks once and was never affected.</p> <p>3.13.0 compares in one pass over an explicit stack of iterator pairs and gets "less", "equal", "greater" or "unordered" for each pair at once, so the ordering question is asked once per element. We found two subtleties by comparing 68,121 results with the old code, not by reading it. <code>std::lexicographical_compare</code> steps over a pair it cannot order (a <abbr title="Not a Number">NaN</abbr>) and goes on, while the three-way version stops there, so the pass has a flag for which behavior the caller needs. And object keys must be compared with <code>operator==</code> when testing equality, not with the object's comparator: for <code>ordered_json</code>, that comparator is <code>std::equal_to</code>, and using it as "less" reports every equal key as smaller. The single pass has a price: ordering flat arrays of numbers got 27% slower, while flat objects got 34% faster, in the pull request's measurement.</p> <h3 id=bounded-recursion>Bounded recursion<a class=headerlink href=#bounded-recursion title="Permanent link">&para;</a></h3> <p>The other side of this theme is depth. A value nested 100,000 levels deep used to crash <code>dump()</code>, the copy constructor, <code>std::hash</code>, <a href=../../../api/basic_json/flatten/ ><code>flatten()</code></a> and the <abbr title="Binary JSON">BSON</abbr> and <abbr title="Universal Binary JSON">UBJSON</abbr> writers with a stack overflow, and in optimized builds <code>operator==</code>, <a href=../../../api/basic_json/diff/ ><code>diff()</code></a> and the other binary writers at 300,000 levels; servers that copy <abbr title="JavaScript Object Notation">JSON</abbr> from clients hit that. Other libraries limit the depth of what they parse (<a href="https://github.com/boostorg/json">Boost.<abbr title="JavaScript Object Notation">JSON</abbr></a> at 32, <a href="https://github.com/serde-rs/json">serde_json</a> at 128, <a href="https://github.com/simdjson/simdjson">simdjson</a> at 1024) or parse and write iteratively (<a href="https://github.com/ibireme/yyjson">yyjson</a>), and <a href="https://github.com/Tencent/rapidjson">RapidJSON</a> parses recursively unless asked otherwise. We tried making every walk iterative, but that made <code>dump()</code>, copying and merging up to 20% slower on ordinary documents. So 3.13.0 bounds the recursion instead:</p> <div class=highlight><pre><span></span><code><span class=k>constexpr</span><span class=w> </span><span class=n>std</span><span class=o>::</span><span class=kt>size_t</span><span class=w> </span><span class=nf>recursion_depth_limit</span><span class=p>()</span><span class=w> </span><span class=k>noexcept</span><span class=w> </span><span class=p>{</span><span class=w> </span><span class=k>return</span><span class=w> </span><span class=mi>128</span><span class=p>;</span><span class=w> </span><span class=p>}</span>
<span class=k>static</span><span class=w> </span><span class=kt>void</span><span class=w> </span><span class=nf>destroy_bounded</span><span class=p>(</span><span class=n>basic_json</span><span class=o>&amp;</span><span class=w> </span><span class=n>v</span><span class=p>,</span><span class=w> </span><span class=n>std</span><span class=o>::</span><span class=kt>size_t</span><span class=w> </span><span class=n>depth</span><span class=p>)</span><span class=w> </span><span class=k>noexcept</span>
<span class=p>{</span>
<span class=w> </span><span class=k>if</span><span class=w> </span><span class=p>(</span><span class=n>JSON_HEDLEY_UNLIKELY</span><span class=p>(</span><span class=n>depth</span><span class=w> </span><span class=o>&gt;=</span><span class=w> </span><span class=n>detail</span><span class=o>::</span><span class=n>recursion_depth_limit</span><span class=p>()))</span>
<span class=w> </span><span class=p>{</span>
<span class=w> </span><span class=n>destroy_walk</span><span class=p>(</span><span class=n>v</span><span class=p>);</span><span class=w> </span><span class=c1>// deeper than 128 levels: no recursion at all (below)</span>
<span class=w> </span><span class=k>return</span><span class=p>;</span>
<span class=w> </span><span class=p>}</span>
<span class=w> </span><span class=c1>// for each child that is a container: destroy_bounded(child, depth + 1)</span>
<span class=w> </span><span class=n>free_container</span><span class=p>(</span><span class=n>v</span><span class=p>);</span>
<span class=p>}</span>
</code></pre></div> <p class=nj-code-caption>Bounded recursion: recursive down to 128 levels, iterative below.</p> <p>The first 128 levels run the old recursive code, and only below that does an explicit stack, or the walk below, take over. A document nested less deeply pays one comparison per container. Testing for equality walks <code>std::vector</code> and <code>std::map</code> itself and passes the depth as an argument. Copying can't do that cheaply: the containers' copy constructors call ours for every element, and a copy that inserts element by element so that it can pass the depth measured 4–16% slower, because <code>std::map</code>'s own copy clones its tree without comparing a single key. So copying counts the levels in a <code>thread_local</code> counter instead, about ten nanoseconds per copy of a small object. Three more operations use the same counter: converting a value from another <code>basic_json</code> specialization, the ordering comparisons (<code>&lt;</code>, <code>&lt;=&gt;</code> and the operators derived from them), and equality for custom container types, whose own <code>operator==</code> calls ours.</p> <h3 id=destroying-without-a-stack>Destroying without a stack<a class=headerlink href=#destroying-without-a-stack title="Permanent link">&para;</a></h3> <p>The destructor's walk for deep values uses pointer reversal, the idea behind the <a href="https://doi.org/10.1145/363534.363554">Schorr-Waite graph marking algorithm</a>: while it empties a container, the slot of that container's last child holds the link back to the container's parent, so the way back needs no memory (<a href=#i-details-of-the-themes>Appendix I</a> shows the loop). The walk allocates nothing and calls nothing that can throw, which fixed two older bugs: the previous destructor flattened children into a <code>std::vector</code>, which ignored the allocator type and could let <code>std::bad_alloc</code> escape from a <code>noexcept</code> destructor. A test checks with a counting allocator that destroying any value allocates nothing. Against 3.12.0, destroying a parsed document is 1.24–1.55× as fast in our suite, and destroying an array of one million small objects 1.39×.</p> <h2 id=theme-8><span class=nj-theme>8</span> Build a different data structure<a class=headerlink href=#theme-8 title="Permanent link">&para;</a></h2> <p>After all of the above, <a href=../../../api/basic_json/parse/ ><code>json::parse()</code></a> is still bound by what it builds: one heap allocation per string, array and object, and a <code>std::map</code> node per member, all of which have to be freed again. Many programs only parse a document, read some fields and throw it away, or change a few values and write it back. For them, 3.13.0 adds <a href=../../../features/json_view/ ><code>json_document</code></a> and <code>json_view</code> in a new header, <code>&lt;nlohmann/json_view.hpp&gt;</code>. The two figures below show what each parser makes of this 54-byte text:</p> <div class=highlight><pre><span></span><code><span class=p>{</span><span class=nt>"port"</span><span class=p>:</span><span class=w> </span><span class=mi>6379</span><span class=p>,</span><span class=w> </span><span class=nt>"price"</span><span class=p>:</span><span class=w> </span><span class=mf>19.90</span><span class=p>,</span><span class=w> </span><span class=nt>"tags"</span><span class=p>:</span><span class=w> </span><span class=p>[</span><span class=s2>"eu"</span><span class=p>,</span><span class=w> </span><span class=s2>"a\"b"</span><span class=p>]}</span>
</code></pre></div> <p class=nj-code-caption>The example text of the next two figures.</p> <div class=nj-fig-wrap> <p><svg class="nj-fig nj-jsonview " viewbox="0 0 840 222" role=img aria-labelledby="fig-jvlt-title fig-jvlt-title-d" xmlns=http://www.w3.org/2000/svg> <title id=fig-jvlt-title>A J&#8203;SON text parsed by basic_json::parse()</title> <desc id=fig-jvlt-title-d>The text {&quot;port&quot;: 6379, &quot;price&quot;: 19.90, &quot;tags&quot;: [&quot;eu&quot;, &quot;a\&quot;b&quot;]} parsed by basic_json::parse(): the root json value points to a std::map whose three nodes are separate heap allocations; the price is stored as the double 19.9; the tags array is a std::vector of two json values, each pointing to its own std::string.</desc> <defs> <marker id=jvlt-line viewbox="0 0 10 10" refx=9 refy=5 markerwidth=6.5 markerheight=6.5 orient=auto-start-reverse><path class="nj-jsonview-c-line nj-jsonview-head" d="M0 1 L10 5 L0 9 z"/></marker> <marker id=jvlt-str viewbox="0 0 10 10" refx=9 refy=5 markerwidth=6.5 markerheight=6.5 orient=auto-start-reverse><path class="nj-jsonview-c-str nj-jsonview-head" d="M0 1 L10 5 L0 9 z"/></marker> <marker id=jvlt-key viewbox="0 0 10 10" refx=9 refy=5 markerwidth=6.5 markerheight=6.5 orient=auto-start-reverse><path class="nj-jsonview-c-key nj-jsonview-head" d="M0 1 L10 5 L0 9 z"/></marker> <marker id=jvlt-num viewbox="0 0 10 10" refx=9 refy=5 markerwidth=6.5 markerheight=6.5 orient=auto-start-reverse><path class="nj-jsonview-c-num nj-jsonview-head" d="M0 1 L10 5 L0 9 z"/></marker> <marker id=jvlt-dec viewbox="0 0 10 10" refx=9 refy=5 markerwidth=6.5 markerheight=6.5 orient=auto-start-reverse><path class="nj-jsonview-c-dec nj-jsonview-head" d="M0 1 L10 5 L0 9 z"/></marker> <marker id=jvlt-own viewbox="0 0 10 10" refx=9 refy=5 markerwidth=6.5 markerheight=6.5 orient=auto-start-reverse><path class="nj-jsonview-c-own nj-jsonview-head" d="M0 1 L10 5 L0 9 z"/></marker> <marker id=jvlt-struct viewbox="0 0 10 10" refx=9 refy=5 markerwidth=6.5 markerheight=6.5 orient=auto-start-reverse><path class="nj-jsonview-c-struct nj-jsonview-head" d="M0 1 L10 5 L0 9 z"/></marker> <marker id=jvlt-bad viewbox="0 0 10 10" refx=9 refy=5 markerwidth=6.5 markerheight=6.5 orient=auto-start-reverse><path class="nj-jsonview-c-bad nj-jsonview-head" d="M0 1 L10 5 L0 9 z"/></marker> </defs> <text class=nj-jsonview-h x=16 y=26 xml:space=preserve>basic_json::parse(): a tree, every array, object, and string in its own heap allocation</text> <rect class=nj-jsonview-box x=16 y=98 width=60 height=34 rx=5 /> <text class=nj-jsonview-mono x=46 y=120 text-anchor=middle xml:space=preserve>json</text> <path class="nj-jsonview-arr nj-jsonview-c-line" marker-end=url(#jvlt-line) d="M76 115 L106 115"/> <rect class=nj-jsonview-heap x=108 y=98 width=84 height=34 rx=5 /> <text class=nj-jsonview-mono x=150 y=120 text-anchor=middle xml:space=preserve>std::map</text> <path class="nj-jsonview-arr nj-jsonview-c-line" marker-end=url(#jvlt-line) d="M192 115 L226 67"/> <rect class=nj-jsonview-heap x=228 y=50 width=180 height=34 rx=5 /> <text class="nj-jsonview-mono nj-jsonview-c-key" x=240 y=72 xml:space=preserve>&quot;port&quot;</text> <text class="nj-jsonview-mono nj-jsonview-c-num" x=396 y=72 text-anchor=end xml:space=preserve>6379</text> <path class="nj-jsonview-arr nj-jsonview-c-line" marker-end=url(#jvlt-line) d="M192 115 L226 115"/> <rect class=nj-jsonview-heap x=228 y=98 width=180 height=34 rx=5 /> <text class="nj-jsonview-mono nj-jsonview-c-key" x=240 y=120 xml:space=preserve>&quot;price&quot;</text> <text class="nj-jsonview-mono nj-jsonview-c-num" x=396 y=120 text-anchor=end xml:space=preserve>19.9</text> <text class=nj-jsonview-note x=418 y=120 xml:space=preserve>double: 19.90 is gone</text> <path class="nj-jsonview-arr nj-jsonview-c-line" marker-end=url(#jvlt-line) d="M192 115 L226 163"/> <rect class=nj-jsonview-heap x=228 y=146 width=180 height=34 rx=5 /> <text class="nj-jsonview-mono nj-jsonview-c-key" x=240 y=168 xml:space=preserve>&quot;tags&quot;</text> <text class="nj-jsonview-mono nj-jsonview-c-line" x=396 y=168 text-anchor=end xml:space=preserve>•</text> <path class="nj-jsonview-arr nj-jsonview-c-line" marker-end=url(#jvlt-line) d="M408 163 L442 163"/> <rect class=nj-jsonview-heap x=444 y=146 width=104 height=34 rx=5 /> <text class=nj-jsonview-mono x=496 y=168 text-anchor=middle xml:space=preserve>std::vector</text> <path class="nj-jsonview-arr nj-jsonview-c-line" marker-end=url(#jvlt-line) d="M548 163 L576 163"/> <rect class=nj-jsonview-heap x=578 y=146 width=92 height=34 rx=5 /> <path class=nj-jsonview-sep d="M624 146 V180"/> <text class=nj-jsonview-mono x=601 y=168 text-anchor=middle xml:space=preserve>json</text> <text class=nj-jsonview-mono x=647 y=168 text-anchor=middle xml:space=preserve>json</text> <path class="nj-jsonview-arr nj-jsonview-c-line" marker-end=url(#jvlt-line) d="M601 146 C601 130 641 130 706 130"/> <path class="nj-jsonview-arr nj-jsonview-c-line" marker-end=url(#jvlt-line) d="M647 180 C647 196 687 196 706 196"/> <rect class=nj-jsonview-heap x=708 y=113 width=126 height=34 rx=5 /> <text class="nj-jsonview-mono nj-jsonview-sm nj-jsonview-c-str" x=771 y=135 text-anchor=middle xml:space=preserve>std::string eu</text> <rect class=nj-jsonview-heap x=708 y=179 width=126 height=34 rx=5 /> <text class="nj-jsonview-mono nj-jsonview-sm nj-jsonview-c-str" x=771 y=201 text-anchor=middle xml:space=preserve>std::string a&quot;b</text> <rect class=nj-jsonview-heap x=16 y=186 width=18 height=14 rx=3 /> <text class=nj-jsonview-note x=42 y=198 xml:space=preserve>a separate heap allocation</text> </svg></p> </div> <p class=nj-caption>What <code>json::parse()</code> builds: a tree in which every object, array, and string is a separate heap allocation (dashed). The float is converted to the nearest <code>double</code> while parsing, so the original text <code>19.90</code> is gone: the stored value is 19.899999999999998578…, which <code>dump()</code> writes as <code>19.9</code>, the shortest text that reads back as the same <code>double</code>.</p> <div class=nj-fig-wrap> <p><svg class="nj-fig nj-jsonview " viewbox="0 0 840 456" role=img aria-labelledby="fig-jvli-title fig-jvli-title-d" xmlns=http://www.w3.org/2000/svg> <title id=fig-jvli-title>The same J&#8203;SON text parsed by json_document::parse()</title> <desc id=fig-jvli-title-d>The same text parsed by json_document::parse(): it keeps the 54 bytes of source text and builds a flat index of nine 16-byte nodes in document order: object, key port, unsigned integer 6379 (the converted value is in the node), key price, float, key tags, array, string eu, and an escaped string. Keys, the float, and the plain string point back into the source text; the escaped string points into the document&#x27;s buffer of decoded strings. A json_view is two pointers: one to the document and one to a node, here the array.</desc> <defs> <marker id=jvli-line viewbox="0 0 10 10" refx=9 refy=5 markerwidth=6.5 markerheight=6.5 orient=auto-start-reverse><path class="nj-jsonview-c-line nj-jsonview-head" d="M0 1 L10 5 L0 9 z"/></marker> <marker id=jvli-str viewbox="0 0 10 10" refx=9 refy=5 markerwidth=6.5 markerheight=6.5 orient=auto-start-reverse><path class="nj-jsonview-c-str nj-jsonview-head" d="M0 1 L10 5 L0 9 z"/></marker> <marker id=jvli-key viewbox="0 0 10 10" refx=9 refy=5 markerwidth=6.5 markerheight=6.5 orient=auto-start-reverse><path class="nj-jsonview-c-key nj-jsonview-head" d="M0 1 L10 5 L0 9 z"/></marker> <marker id=jvli-num viewbox="0 0 10 10" refx=9 refy=5 markerwidth=6.5 markerheight=6.5 orient=auto-start-reverse><path class="nj-jsonview-c-num nj-jsonview-head" d="M0 1 L10 5 L0 9 z"/></marker> <marker id=jvli-dec viewbox="0 0 10 10" refx=9 refy=5 markerwidth=6.5 markerheight=6.5 orient=auto-start-reverse><path class="nj-jsonview-c-dec nj-jsonview-head" d="M0 1 L10 5 L0 9 z"/></marker> <marker id=jvli-own viewbox="0 0 10 10" refx=9 refy=5 markerwidth=6.5 markerheight=6.5 orient=auto-start-reverse><path class="nj-jsonview-c-own nj-jsonview-head" d="M0 1 L10 5 L0 9 z"/></marker> <marker id=jvli-struct viewbox="0 0 10 10" refx=9 refy=5 markerwidth=6.5 markerheight=6.5 orient=auto-start-reverse><path class="nj-jsonview-c-struct nj-jsonview-head" d="M0 1 L10 5 L0 9 z"/></marker> <marker id=jvli-bad viewbox="0 0 10 10" refx=9 refy=5 markerwidth=6.5 markerheight=6.5 orient=auto-start-reverse><path class="nj-jsonview-c-bad nj-jsonview-head" d="M0 1 L10 5 L0 9 z"/></marker> </defs> <g transform="translate(0 -236)"> <text class=nj-jsonview-h x=16 y=262 xml:space=preserve>json_document::parse(): the source text stays where it is; one flat index of 16-byte nodes</text> <text class=nj-jsonview-note x=16 y=290 xml:space=preserve>source text, 54 bytes (borrowed, or owned by the document)</text> <rect class=nj-jsonview-ribbon x=42 y=300 width=756 height=26 rx=4 /> <rect x=71 y=302 width=54 height=22 rx=3 class="nj-jsonview-span nj-jsonview-c-key"/> <rect x=169 y=302 width=54 height=22 rx=3 class="nj-jsonview-span nj-jsonview-c-num"/> <rect x=267 y=302 width=68 height=22 rx=3 class="nj-jsonview-span nj-jsonview-c-key"/> <rect x=379 y=302 width=68 height=22 rx=3 class="nj-jsonview-span nj-jsonview-c-num"/> <rect x=491 y=302 width=54 height=22 rx=3 class="nj-jsonview-span nj-jsonview-c-key"/> <rect x=617 y=302 width=26 height=22 rx=3 class="nj-jsonview-span nj-jsonview-c-str"/> <rect x=701 y=302 width=54 height=22 rx=3 class="nj-jsonview-span nj-jsonview-c-dec"/> <text class="nj-jsonview-mono nj-jsonview-byte" x=49 y=317.5 text-anchor=middle xml:space=preserve>{</text> <text class="nj-jsonview-mono nj-jsonview-byte" x=63 y=317.5 text-anchor=middle xml:space=preserve>&quot;</text> <text class="nj-jsonview-mono nj-jsonview-byte" x=77 y=317.5 text-anchor=middle xml:space=preserve>p</text> <text class="nj-jsonview-mono nj-jsonview-byte" x=91 y=317.5 text-anchor=middle xml:space=preserve>o</text> <text class="nj-jsonview-mono nj-jsonview-byte" x=105 y=317.5 text-anchor=middle xml:space=preserve>r</text> <text class="nj-jsonview-mono nj-jsonview-byte" x=119 y=317.5 text-anchor=middle xml:space=preserve>t</text> <text class="nj-jsonview-mono nj-jsonview-byte" x=133 y=317.5 text-anchor=middle xml:space=preserve>&quot;</text> <text class="nj-jsonview-mono nj-jsonview-byte" x=147 y=317.5 text-anchor=middle xml:space=preserve>:</text> <text class="nj-jsonview-mono nj-jsonview-byte" x=175 y=317.5 text-anchor=middle xml:space=preserve>6</text> <text class="nj-jsonview-mono nj-jsonview-byte" x=189 y=317.5 text-anchor=middle xml:space=preserve>3</text> <text class="nj-jsonview-mono nj-jsonview-byte" x=203 y=317.5 text-anchor=middle xml:space=preserve>7</text> <text class="nj-jsonview-mono nj-jsonview-byte" x=217 y=317.5 text-anchor=middle xml:space=preserve>9</text> <text class="nj-jsonview-mono nj-jsonview-byte" x=231 y=317.5 text-anchor=middle xml:space=preserve>,</text> <text class="nj-jsonview-mono nj-jsonview-byte" x=259 y=317.5 text-anchor=middle xml:space=preserve>&quot;</text> <text class="nj-jsonview-mono nj-jsonview-byte" x=273 y=317.5 text-anchor=middle xml:space=preserve>p</text> <text class="nj-jsonview-mono nj-jsonview-byte" x=287 y=317.5 text-anchor=middle xml:space=preserve>r</text> <text class="nj-jsonview-mono nj-jsonview-byte" x=301 y=317.5 text-anchor=middle xml:space=preserve>i</text> <text class="nj-jsonview-mono nj-jsonview-byte" x=315 y=317.5 text-anchor=middle xml:space=preserve>c</text> <text class="nj-jsonview-mono nj-jsonview-byte" x=329 y=317.5 text-anchor=middle xml:space=preserve>e</text> <text class="nj-jsonview-mono nj-jsonview-byte" x=343 y=317.5 text-anchor=middle xml:space=preserve>&quot;</text> <text class="nj-jsonview-mono nj-jsonview-byte" x=357 y=317.5 text-anchor=middle xml:space=preserve>:</text> <text class="nj-jsonview-mono nj-jsonview-byte" x=385 y=317.5 text-anchor=middle xml:space=preserve>1</text> <text class="nj-jsonview-mono nj-jsonview-byte" x=399 y=317.5 text-anchor=middle xml:space=preserve>9</text> <text class="nj-jsonview-mono nj-jsonview-byte" x=413 y=317.5 text-anchor=middle xml:space=preserve>.</text> <text class="nj-jsonview-mono nj-jsonview-byte" x=427 y=317.5 text-anchor=middle xml:space=preserve>9</text> <text class="nj-jsonview-mono nj-jsonview-byte" x=441 y=317.5 text-anchor=middle xml:space=preserve>0</text> <text class="nj-jsonview-mono nj-jsonview-byte" x=455 y=317.5 text-anchor=middle xml:space=preserve>,</text> <text class="nj-jsonview-mono nj-jsonview-byte" x=483 y=317.5 text-anchor=middle xml:space=preserve>&quot;</text> <text class="nj-jsonview-mono nj-jsonview-byte" x=497 y=317.5 text-anchor=middle xml:space=preserve>t</text> <text class="nj-jsonview-mono nj-jsonview-byte" x=511 y=317.5 text-anchor=middle xml:space=preserve>a</text> <text class="nj-jsonview-mono nj-jsonview-byte" x=525 y=317.5 text-anchor=middle xml:space=preserve>g</text> <text class="nj-jsonview-mono nj-jsonview-byte" x=539 y=317.5 text-anchor=middle xml:space=preserve>s</text> <text class="nj-jsonview-mono nj-jsonview-byte" x=553 y=317.5 text-anchor=middle xml:space=preserve>&quot;</text> <text class="nj-jsonview-mono nj-jsonview-byte" x=567 y=317.5 text-anchor=middle xml:space=preserve>:</text> <text class="nj-jsonview-mono nj-jsonview-byte" x=595 y=317.5 text-anchor=middle xml:space=preserve>[</text> <text class="nj-jsonview-mono nj-jsonview-byte" x=609 y=317.5 text-anchor=middle xml:space=preserve>&quot;</text> <text class="nj-jsonview-mono nj-jsonview-byte" x=623 y=317.5 text-anchor=middle xml:space=preserve>e</text> <text class="nj-jsonview-mono nj-jsonview-byte" x=637 y=317.5 text-anchor=middle xml:space=preserve>u</text> <text class="nj-jsonview-mono nj-jsonview-byte" x=651 y=317.5 text-anchor=middle xml:space=preserve>&quot;</text> <text class="nj-jsonview-mono nj-jsonview-byte" x=665 y=317.5 text-anchor=middle xml:space=preserve>,</text> <text class="nj-jsonview-mono nj-jsonview-byte" x=693 y=317.5 text-anchor=middle xml:space=preserve>&quot;</text> <text class="nj-jsonview-mono nj-jsonview-byte" x=707 y=317.5 text-anchor=middle xml:space=preserve>a</text> <text class="nj-jsonview-mono nj-jsonview-byte" x=721 y=317.5 text-anchor=middle xml:space=preserve>\</text> <text class="nj-jsonview-mono nj-jsonview-byte" x=735 y=317.5 text-anchor=middle xml:space=preserve>&quot;</text> <text class="nj-jsonview-mono nj-jsonview-byte" x=749 y=317.5 text-anchor=middle xml:space=preserve>b</text> <text class="nj-jsonview-mono nj-jsonview-byte" x=763 y=317.5 text-anchor=middle xml:space=preserve>&quot;</text> <text class="nj-jsonview-mono nj-jsonview-byte" x=777 y=317.5 text-anchor=middle xml:space=preserve>]</text> <text class="nj-jsonview-mono nj-jsonview-byte" x=791 y=317.5 text-anchor=middle xml:space=preserve>}</text> <text class=nj-jsonview-tiny x=49 y=340 text-anchor=middle xml:space=preserve>0</text> <text class=nj-jsonview-tiny x=189 y=340 text-anchor=middle xml:space=preserve>10</text> <text class=nj-jsonview-tiny x=329 y=340 text-anchor=middle xml:space=preserve>20</text> <text class=nj-jsonview-tiny x=469 y=340 text-anchor=middle xml:space=preserve>30</text> <text class=nj-jsonview-tiny x=609 y=340 text-anchor=middle xml:space=preserve>40</text> <text class=nj-jsonview-tiny x=749 y=340 text-anchor=middle xml:space=preserve>50</text> <rect class=nj-jsonview-frame x=16 y=366 width=808 height=254 rx=10 /> <text class="nj-jsonview-note nj-jsonview-strong" x=30 y=602 xml:space=preserve>json_document: owns the node index and the buffer of decoded strings</text> <text class=nj-jsonview-note x=30 y=500 xml:space=preserve>node index: 9 nodes × 16 bytes = 144 bytes, in document order</text> <rect x=36 y=406 width=84 height=68 rx=5 class="nj-jsonview-node nj-jsonview-c-struct"/> <text class=nj-jsonview-tiny x=42 y=420 xml:space=preserve>0</text> <text class="nj-jsonview-kind nj-jsonview-c-struct" x=78 y=434 text-anchor=middle xml:space=preserve>object</text> <text class="nj-jsonview-mono nj-jsonview-xs" x=78 y=451 text-anchor=middle xml:space=preserve>len 3</text> <text class="nj-jsonview-mono nj-jsonview-xs" x=78 y=465 text-anchor=middle xml:space=preserve>next 9</text> <rect x=124 y=406 width=84 height=68 rx=5 class="nj-jsonview-node nj-jsonview-c-key"/> <text class=nj-jsonview-tiny x=130 y=420 xml:space=preserve>1</text> <text class="nj-jsonview-kind nj-jsonview-c-key" x=166 y=434 text-anchor=middle xml:space=preserve>key</text> <text class="nj-jsonview-mono nj-jsonview-xs" x=166 y=451 text-anchor=middle xml:space=preserve>off 2</text> <text class="nj-jsonview-mono nj-jsonview-xs" x=166 y=465 text-anchor=middle xml:space=preserve>len 4</text> <path class="nj-jsonview-arr nj-jsonview-c-key" marker-end=url(#jvli-key) d="M166 406 C166 367 98 367 98 328"/> <rect x=212 y=406 width=84 height=68 rx=5 class="nj-jsonview-node nj-jsonview-c-num"/> <text class=nj-jsonview-tiny x=218 y=420 xml:space=preserve>2</text> <text class="nj-jsonview-kind nj-jsonview-c-num" x=254 y=434 text-anchor=middle xml:space=preserve>uint</text> <text class="nj-jsonview-mono nj-jsonview-xs" x=254 y=451 text-anchor=middle xml:space=preserve>6379</text> <text class="nj-jsonview-mono nj-jsonview-xs" x=254 y=465 text-anchor=middle xml:space=preserve>(converted)</text> <rect x=300 y=406 width=84 height=68 rx=5 class="nj-jsonview-node nj-jsonview-c-key"/> <text class=nj-jsonview-tiny x=306 y=420 xml:space=preserve>3</text> <text class="nj-jsonview-kind nj-jsonview-c-key" x=342 y=434 text-anchor=middle xml:space=preserve>key</text> <text class="nj-jsonview-mono nj-jsonview-xs" x=342 y=451 text-anchor=middle xml:space=preserve>off 16</text> <text class="nj-jsonview-mono nj-jsonview-xs" x=342 y=465 text-anchor=middle xml:space=preserve>len 5</text> <path class="nj-jsonview-arr nj-jsonview-c-key" marker-end=url(#jvli-key) d="M342 406 C342 367 301 367 301 328"/> <rect x=388 y=406 width=84 height=68 rx=5 class="nj-jsonview-node nj-jsonview-c-num"/> <text class=nj-jsonview-tiny x=394 y=420 xml:space=preserve>4</text> <text class="nj-jsonview-kind nj-jsonview-c-num" x=430 y=434 text-anchor=middle xml:space=preserve>float</text> <text class="nj-jsonview-mono nj-jsonview-xs" x=430 y=451 text-anchor=middle xml:space=preserve>off 24</text> <text class="nj-jsonview-mono nj-jsonview-xs" x=430 y=465 text-anchor=middle xml:space=preserve>len 5</text> <path class="nj-jsonview-arr nj-jsonview-c-num" marker-end=url(#jvli-num) d="M430 406 C430 367 413 367 413 328"/> <rect x=476 y=406 width=84 height=68 rx=5 class="nj-jsonview-node nj-jsonview-c-key"/> <text class=nj-jsonview-tiny x=482 y=420 xml:space=preserve>5</text> <text class="nj-jsonview-kind nj-jsonview-c-key" x=518 y=434 text-anchor=middle xml:space=preserve>key</text> <text class="nj-jsonview-mono nj-jsonview-xs" x=518 y=451 text-anchor=middle xml:space=preserve>off 32</text> <text class="nj-jsonview-mono nj-jsonview-xs" x=518 y=465 text-anchor=middle xml:space=preserve>len 4</text> <path class="nj-jsonview-arr nj-jsonview-c-key" marker-end=url(#jvli-key) d="M518 406 C518 367 518 367 518 328"/> <rect x=564 y=406 width=84 height=68 rx=5 class="nj-jsonview-node nj-jsonview-c-struct"/> <text class=nj-jsonview-tiny x=570 y=420 xml:space=preserve>6</text> <text class="nj-jsonview-kind nj-jsonview-c-struct" x=606 y=434 text-anchor=middle xml:space=preserve>array</text> <text class="nj-jsonview-mono nj-jsonview-xs" x=606 y=451 text-anchor=middle xml:space=preserve>len 2</text> <text class="nj-jsonview-mono nj-jsonview-xs" x=606 y=465 text-anchor=middle xml:space=preserve>next 3</text> <rect x=652 y=406 width=84 height=68 rx=5 class="nj-jsonview-node nj-jsonview-c-str"/> <text class=nj-jsonview-tiny x=658 y=420 xml:space=preserve>7</text> <text class="nj-jsonview-kind nj-jsonview-c-str" x=694 y=434 text-anchor=middle xml:space=preserve>string</text> <text class="nj-jsonview-mono nj-jsonview-xs" x=694 y=451 text-anchor=middle xml:space=preserve>off 41</text> <text class="nj-jsonview-mono nj-jsonview-xs" x=694 y=465 text-anchor=middle xml:space=preserve>len 2</text> <path class="nj-jsonview-arr nj-jsonview-c-str" marker-end=url(#jvli-str) d="M694 406 C694 367 630 367 630 328"/> <rect x=740 y=406 width=84 height=68 rx=5 class="nj-jsonview-node nj-jsonview-c-dec"/> <text class=nj-jsonview-tiny x=746 y=420 xml:space=preserve>8</text> <text class="nj-jsonview-kind nj-jsonview-c-dec" x=782 y=434 text-anchor=middle xml:space=preserve>string</text> <text class="nj-jsonview-mono nj-jsonview-xs" x=782 y=451 text-anchor=middle xml:space=preserve>escaped</text> <text class="nj-jsonview-mono nj-jsonview-xs" x=782 y=465 text-anchor=middle xml:space=preserve>len 3</text> <text class=nj-jsonview-note x=773 y=568 text-anchor=middle xml:space=preserve>decoded strings</text> <rect x=740 y=518 width=66 height=30 rx=4 class="nj-jsonview-node nj-jsonview-c-dec"/> <text class=nj-jsonview-mono x=751 y=538 text-anchor=middle xml:space=preserve>a</text> <text class=nj-jsonview-mono x=773 y=538 text-anchor=middle xml:space=preserve>&quot;</text> <text class=nj-jsonview-mono x=795 y=538 text-anchor=middle xml:space=preserve>b</text> <path class="nj-jsonview-arr nj-jsonview-c-dec" marker-end=url(#jvli-dec) d="M782 474 C782 496 773 496 773 518"/> <text class="nj-jsonview-mono nj-jsonview-sm" x=470 y=670 text-anchor=end xml:space=preserve>json_view v = doc.root()[&quot;tags&quot;]</text> <rect x=480 y=648 width=140 height=34 rx=6 class="nj-jsonview-node nj-jsonview-c-struct"/> <path class=nj-jsonview-sep d="M550 648 V682"/> <text class=nj-jsonview-mono x=515 y=670 text-anchor=middle xml:space=preserve>doc*</text> <text class=nj-jsonview-mono x=585 y=670 text-anchor=middle xml:space=preserve>node*</text> <path class="nj-jsonview-arr nj-jsonview-c-struct" marker-end=url(#jvli-struct) d="M515 648 L515 622"/> <path class="nj-jsonview-arr nj-jsonview-c-struct" marker-end=url(#jvli-struct) d="M585 648 C585 561 606 561 606 474"/> <text class=nj-jsonview-note x=30 y=524 xml:space=preserve>integers are converted while parsing and kept in their node;</text> <text class=nj-jsonview-note x=30 y=542 xml:space=preserve>floats and strings point back into the text</text> </g> </svg></p> </div> <p class=nj-caption>What <code>json_document::parse()</code> builds from the same text: one flat index of nine 16-byte nodes in document order, which point back into the source text, plus a buffer for the one string with an escape. A <code>json_view</code> is two pointers, here to the array.</p> <h3 id=one-flat-index>One flat index<a class=headerlink href=#one-flat-index title="Permanent link">&para;</a></h3> <p>The design is not ours either. <a href="https://github.com/simdjson/simdjson/blob/master/doc/tape.md">simdjson's tape</a> and <a href="https://github.com/ibireme/yyjson">yyjson</a>'s immutable document are both flat arrays of fixed-size entries in document order instead of trees of separate allocations, and yyjson's entries are 16 bytes, too. Ours:</p> <div class=highlight><pre><span></span><code><span class=k>struct</span><span class=w> </span><span class=nc>node</span>
<span class=p>{</span>
<span class=w> </span><span class=n>node_kind</span><span class=w> </span><span class=n>kind</span><span class=p>;</span><span class=w> </span><span class=c1>// object = 1, array = 2, string, number, ...</span>
<span class=w> </span><span class=n>std</span><span class=o>::</span><span class=kt>uint8_t</span><span class=w> </span><span class=n>flags</span><span class=p>;</span><span class=w> </span><span class=c1>// escaped, edited, moved, ...</span>
<span class=w> </span><span class=n>std</span><span class=o>::</span><span class=kt>uint16_t</span><span class=w> </span><span class=n>extra</span><span class=p>;</span><span class=w> </span><span class=c1>// numbers: digits before and after the point; big objects: hash index</span>
<span class=w> </span><span class=n>std</span><span class=o>::</span><span class=kt>uint32_t</span><span class=w> </span><span class=n>off</span><span class=p>;</span><span class=w> </span><span class=c1>// where the value starts in the source text (or in the arena)</span>
<span class=w> </span><span class=n>std</span><span class=o>::</span><span class=kt>uint32_t</span><span class=w> </span><span class=n>len</span><span class=p>;</span><span class=w> </span><span class=c1>// strings and float tokens: bytes; containers: number of elements</span>
<span class=w> </span><span class=n>std</span><span class=o>::</span><span class=kt>uint32_t</span><span class=w> </span><span class=n>next</span><span class=p>;</span><span class=w> </span><span class=c1>// containers: number of nodes in the subtree, including this one</span>
<span class=p>};</span>
<span class=k>static_assert</span><span class=p>(</span><span class=k>sizeof</span><span class=p>(</span><span class=n>node</span><span class=p>)</span><span class=w> </span><span class=o>==</span><span class=w> </span><span class=mi>16</span><span class=p>,</span><span class=w> </span><span class=s>"node must stay 16 bytes"</span><span class=p>);</span>
</code></pre></div> <p class=nj-code-caption>A node of <code>json_document</code>'s index: 16 bytes for every value.</p> <ul> <li><strong>Skipping is an addition.</strong> A container stores the size of its subtree, so the value after it is <code>n + (is_container(*n) ? n-&gt;next : 1)</code>, and the members of an object are a key node followed by the value's subtree. There are no pointers in the parsed index (edits add links, below); the parser fills in <code>next</code> when the container closes. <code>is_container()</code> is a single subtraction and comparison, <code>kind - 1u &lt;= 1u</code>, which is why objects and arrays are numbered 1 and 2.</li> <li><strong>Strings stay in the input.</strong> Only strings with escapes are decoded, into an arena. A document makes only a handful of allocations, no matter how many values it has. The price is that the text must outlive the document, unless the document owns it: <a href=../../../api/basic_json_document/parse_copy/ ><code>parse_copy()</code></a> copies the text, and parsing an rvalue <code>std::string</code> moves it into the document. Input that can't be read as one contiguous block of bytes, such as a stream or a <code>FILE*</code>, is read into a buffer that the document owns, too. Offsets are 32 bits, which limits a document to 4 <abbr title="Gibibyte (2^30 bytes)">GiB</abbr>.</li> <li><strong>Integers are converted while their digits are in the cache,</strong> into the last 8 bytes of their node.</li> <li><strong>Floats stay text until you read them.</strong> The node records the number of digits before and after the point, and reading converts with the same Clinger/Eisel-Lemire code as <code>json::parse</code>. We tried converting them during the parse. Although parsing <code>canada.json</code> and reading every number got 4–7% faster, parsing alone got 36–90% slower, so we dropped it. A default <code>dump()</code> writes the shortest form of a float, as <code>json</code> does; <a href=../../../api/basic_json_view/number_format/ ><code>number_format::source</code></a> copies the source text of every number instead.</li> <li><strong><abbr title="Single Instruction, Multiple Data">SIMD</abbr> and tables</strong> as in theme <a class=nj-theme href=#theme-2 title="theme 2">2</a>, and <code>\u</code> escapes are decoded with a table, as in yyjson.</li> <li><strong>A hash index for big objects,</strong> an idea from <a href="https://github.com/boostorg/json">Boost.<abbr title="JavaScript Object Notation">JSON</abbr></a>. An object with 128 or more members gets an open-addressing table after parsing; looking up every key of a 10,000-member object went from 59.8 ms to 0.16 ms. The hash is not seeded, so crafted keys could make building the table quadratic. Probing is therefore capped at 64 slots: a key that would need more drops the table, and that one object falls back to a linear search. Parsing can't become quadratic, and a lookup is never slower than the linear search of a small object.</li> <li><strong>Validating writes no index.</strong> <a href=../../../api/basic_json_document/accept/ ><code>json_document::accept()</code></a> runs a second instantiation of the same builder with a template parameter that turns every store off, so the checks are the same code, but no node is written and no escaped string is decoded. On x86-64 that made it 17–31% faster on <code>twitter.json</code>, <code>citm_catalog.json</code> and <code>canada.json</code>, and the 56 MB <code>jeopardy.json</code> no longer needs 52 MB of fresh memory just to be validated.</li> <li><strong>First duplicate wins.</strong> Lookups return the first of duplicate keys, as yyjson and simdjson do, because returning the last one meant scanning every object to its end and made lookups in small objects 1.6–3.4× slower. <code>json::parse()</code> keeps the last one, so for a text with duplicate keys, the two can disagree; the documentation says so.</li> </ul> <h3 id=it-can-be-edited-too>It can be edited, too<a class=headerlink href=#it-can-be-edited-too title="Permanent link">&para;</a></h3> <p>A read-only index is the easy case, and a fair objection is that <code>json_document</code> is only fast because it can't change. <a href=../../../features/json_view/editing/ ><code>json_editable_document</code></a> has <code>set()</code>, <code>insert()</code>, <code>erase()</code> and <code>push_back()</code>. An edit never writes into the source text and never moves the parsed index:</p> <ul> <li>a new scalar is written over its own node, with new string and number text in an append-only arena;</li> <li>new arrays and objects are allocated in chunks of nodes that never move;</li> <li>a container whose elements change is marked as moved and gets a separate list of its entries: links to the values, which stay where they are. The list doubles when it grows, so <code>push_back()</code> is amortized constant.</li> </ul> <p>Views stay valid across edits, because values never move. Reading an edited container costs one flag test per container and one test per element for a link. The link case is out of line, so that it compiles to a predicted branch rather than a conditional select that would delay the following loads. Whereas a read-only document carries none of this, an editable one that hasn't been edited reads within 2% of it on most rows and within 8% on the worst. And because untouched values keep their source text, <a href=../../../api/basic_json_view/dump/ ><code>dump()</code></a> with <code>number_format::source</code> writes back a patched configuration file with its member order and the spelling of every number (<code>19.90</code>) intact, which <code>json</code> (sorted keys) and <code>ordered_json</code> (<code>19.9</code>) can't.</p> <p>The limits are documented: <code>set()</code> of a new key searches the object's members, so building a large object key by key is quadratic, as with <code>ordered_json</code>, and an object that was edited loses its hash index and is searched linearly. <a href=#how-it-compares>How it compares</a> times the editable document against the mutable trees of other libraries.</p> <h2 id=how-it-compares>How it compares<a class=headerlink href=#how-it-compares title="Permanent link">&para;</a></h2> <p>"Which <abbr title="JavaScript Object Notation">JSON</abbr> library parses fastest?" has no answer, because "parsing" means different things in different libraries. They hold a parsed <abbr title="JavaScript Object Notation">JSON</abbr> text in four different ways:</p> <table> <thead> <tr> <th>approach</th> <th>what you get</th> <th>what it costs</th> <th>libraries we measured</th> </tr> </thead> <tbody> <tr> <td><strong>mutable tree</strong></td> <td>a value per <abbr title="JavaScript Object Notation">JSON</abbr> value, every string and number converted and owned; change anything</td> <td>an allocation per container and often per string, all freed again</td> <td>nlohmann/json <code>json</code>, <a href="https://github.com/boostorg/json">Boost.<abbr title="JavaScript Object Notation">JSON</abbr></a>, <a href="https://github.com/Tencent/rapidjson">RapidJSON</a>, <a href="https://github.com/bytedance/sonic-cpp">sonic-cpp</a>, <a href="https://github.com/stephenberry/glaze">Glaze</a> <code>generic</code>, <a href="https://github.com/ibireme/yyjson">yyjson</a>'s mutable document; <a href="https://github.com/serde-rs/json">serde_json</a>, <a href="https://github.com/cloudwego/sonic-rs">sonic-rs</a>, <a href="https://github.com/simd-lite/simd-json">simd-json</a> values</td> </tr> <tr> <td><strong>flat document</strong></td> <td>one array of small entries in document order; read in any order, many times</td> <td>a few allocations; read-only, or extra bookkeeping to edit</td> <td>nlohmann/json <code>json_document</code> (editable as <code>json_editable_document</code>), yyjson, <a href="https://github.com/simdjson/simdjson">simdjson</a> <abbr title="Document Object Model">DOM</abbr></td> </tr> <tr> <td><strong>forward-only reading</strong></td> <td>each value once, in document order: events (<abbr title="Simple API for XML">SAX</abbr>) or a cursor</td> <td>nothing is built; you can't go back</td> <td>nlohmann/json <a href=../../../api/basic_json/sax_parse/ ><code>sax_parse</code></a>, RapidJSON <code>Reader</code>, Boost.<abbr title="JavaScript Object Notation">JSON</abbr> <code>basic_parser</code>, simdjson On-Demand, Glaze <code>lazy_json</code>; serde visitors in Rust</td> </tr> <tr> <td><strong>into your own types</strong></td> <td>the fields you declared, nothing else</td> <td>a struct per document shape; other fields are skipped</td> <td>Glaze reading into structs, serde with <code>derive</code>, nlohmann/json <code>from_json()</code> from <code>json</code> or from a view</td> </tr> </tbody> </table> <p class=nj-table-caption>The kinds of representation the libraries in this comparison offer. Most libraries offer more than one.</p> <p>So a comparison of parse times across the rows of this table compares different amounts of work. Instead, we compare <strong>use cases</strong>: tasks a program actually has, each of which every library may solve in whatever way it does best. In nlohmann/json, <code>json</code> is the mutable tree and <code>json_document</code> the flat document, so we show the library twice: its best way <em>with</em> <code>json_document</code> and its best way <em>without</em> it.</p> <h3 id=six-use-cases>Six use cases<a class=headerlink href=#six-use-cases title="Permanent link">&para;</a></h3> <p>Each starts from the file's text in a <code>std::string</code> (or a byte slice in Rust) and ends with everything the library built freed again:</p> <ul> <li><strong>validate:</strong> is this text valid <abbr title="JavaScript Object Notation">JSON</abbr>? Nothing is kept, so this measures the parser alone, as in a server that checks a request before it passes it on.</li> <li><strong>sum:</strong> visit every value in document order, convert every number, and add them up. This measures walking a whole document and converting all of its numbers.</li> <li><strong>select:</strong> read a few fields of every record, such as the id, the user name, and the retweet count of every tweet, as a program does that needs only part of a response. A library that reads lazily can skip the rest.</li> <li><strong>edit:</strong> change a value, remove a member, and add a member in every record, then write the result as compact <abbr title="JavaScript Object Notation">JSON</abbr>: the round trip of a program that patches a message or a configuration.</li> <li><strong>minify:</strong> read the text and write it as compact <abbr title="JavaScript Object Notation">JSON</abbr>, without whitespace. This measures reading and writing together, without changes in between.</li> <li><strong>write:</strong> write a document that was parsed beforehand as compact <abbr title="JavaScript Object Notation">JSON</abbr>; only the writing is timed.</li> </ul> <p>Each use case runs on each of the four test files, and each library may solve it in every way it offers: in place, with a <abbr title="Simple API for XML">SAX</abbr> handler, into structs, with a parser that is reused (measured, but not chosen). Before anything is timed, every way's result is checked: the same values, the same string bytes, the same sum of all numbers (to the last bit where they are added in the same order), and an output that reads back as the expected document. The <a href="https://github.com/nlohmann/json/tree/develop/tests/benchmarks/json_view/others">README of the programs</a> lists every way, the fields and edits per file, and the checks.</p> <h3 id=where-the-input-comes-from>Where the input comes from<a class=headerlink href=#where-the-input-comes-from title="Permanent link">&para;</a></h3> <p>Starting from a string in memory is how most <abbr title="JavaScript Object Notation">JSON</abbr> benchmarks work: it measures the library, not the disk or the operating system. It is not neutral in every detail, though:</p> <ul> <li>The string has 64 bytes of spare capacity, so simdjson, which reads up to 64 bytes past the end, can use it without a copy. A program would load the file into such a buffer in the first place.</li> <li>yyjson, RapidJSON, and simd-json can parse in place, which changes the buffer. So every call gets a fresh copy of the string, and the copy counts toward their time: 11–14 µs for <code>twitter.json</code> on the Mac, and 30–46 µs on x86-64, where fresh memory costs page faults. yyjson's normal read makes the same copy internally, which is why both ways take about as long. A server that validates a request and then passes it on needs the copy. A program that reads a file into a buffer it owns can skip it, so we also timed the in-place ways with the copy made before the timer starts. On the Mac, yyjson then comes 2–4% closer and stays second, and on <code>twitter.json</code> it sums and selects 2–3% faster than <code>json_document</code>. On x86-64, it ties <code>json_document</code> in <em>sum</em> with Clang and takes 1.06× and 1.19× its time with <abbr title="GNU Compiler Collection">GCC</abbr> 16 and <abbr title="GNU Compiler Collection">GCC</abbr> 13.</li> <li><code>json_document</code> reads the string in place and keeps pointing into it. A document that owns its text (<a href=../../../api/basic_json_document/parse_copy/ ><code>parse_copy()</code></a>) costs one copy more: 3–5% on the Mac.</li> <li>Reading from files and streams is not part of the comparison.</li> </ul> <pre class=mermaid><code>flowchart TB
f[/"test file"/] --&gt;|"read once, untimed"| s["std::string with 64 spare bytes"]
s --&gt; timed
subgraph timed ["timed, every call"]
direction LR
c["copy&lt;br&gt;(in-place ways)"] --&gt; p["parse"] --&gt; u["use case"] --&gt; d["free&lt;br&gt;everything"]
end</code></pre> <p class=nj-caption>What one timed call of a use case contains. For <em>write</em>, the document is parsed before the timer starts, so only the writing is timed. Every way's result is checked before anything is timed.</p> <h3 id=checking-less-on-purpose>Checking less, on purpose<a class=headerlink href=#checking-less-on-purpose title="Permanent link">&para;</a></h3> <p>Some libraries can skip parts of the validation, and that is often why they are fast. A lazy reader such as simdjson's On-Demand <abbr title="Application Programming Interface">API</abbr> or Glaze's <code>lazy_json</code> only looks at what you ask for; to step over the rest, it matches brackets without looking inside, so reading a few fields of a large record costs little more than finding them. A minifier only needs to find whitespace, not understand the values. Skipping the <abbr title="Unicode Transformation Format">UTF</abbr>-8 check is RapidJSON's default and sonic-cpp's too. Each is a good choice for input that is known to be valid, for example text your own program wrote a moment ago. To tell these ways apart, every way is also fed four broken inputs: the file cut short by one byte, a stray comma, an invalid <abbr title="Unicode Transformation Format">UTF</abbr>-8 byte in a string, and garbage after the value. A way that rejects all four validates fully, and each cell shows the fastest such way. A way that checks or does less appears in the right half of the cell, with a letter that the caption explains.</p> <p>A word on who set the rules: we wrote every library's benchmark code, chose the files and the rules, and tuned 3.13.0 on the same machines and files. No maintainer of the other libraries has reviewed their code. If you know a faster way for any of them, please open an issue, and we will rerun the comparison. To check ourselves, we also ran files and a conformance suite we never tuned on (<a href=#files-and-checks-we-didnt-choose>below</a>).</p> <div class=nj-fig-wrap> <p><svg class="nj-fig nj-charts nj-charts--blog nj-charts--heat" viewbox="0 0 784 510" role=img aria-labelledby="nj-blog-uc-mac nj-blog-uc-mac-d" xmlns=http://www.w3.org/2000/svg> <title id=nj-blog-uc-mac>Use cases: time of each library relative to the fastest, Apple M1 Max</title> <desc id=nj-blog-uc-mac-d>Table of relative times, libraries by use case. nlohmann/json json_document validate: 1.00; nlohmann/json json_document sum: 1.00; nlohmann/json json_document select: 1.00; nlohmann/json json_document edit: 1.00 (0.85 doing less, N); nlohmann/json json_document minify: 1.00 (0.85 doing less, N); nlohmann/json json_document write: 1.00 (0.71 doing less, N); yyjson validate: 1.37; yyjson sum: 1.11; yyjson select: 1.25; yyjson edit: 1.45; yyjson minify: 1.23 (1.16 doing less, N); yyjson write: 1.26; simdjson validate: 1.52; simdjson sum: 1.20; simdjson select: 1.33 (0.75 doing less, P); simdjson edit: n/a; simdjson minify: 1.73 (0.18 doing less, P); simdjson write: 2.41; sonic-rs (Rust) validate: 1.93; sonic-rs (Rust) sum: 1.53; sonic-rs (Rust) select: 1.83; sonic-rs (Rust) edit: 2.08; sonic-rs (Rust) minify: 1.93; sonic-rs (Rust) write: 2.38; sonic-cpp validate: no fully validating way (2.53 doing less, U); sonic-cpp sum: no fully validating way (1.86 doing less, U); sonic-cpp select: no fully validating way (2.31 doing less, U); sonic-cpp edit: no fully validating way (1.68 doing less, U); sonic-cpp minify: no fully validating way (2.03 doing less, U); sonic-cpp write: 1.59; simd-json (Rust) validate: 2.07; simd-json (Rust) sum: 1.62; simd-json (Rust) select: 2.38; simd-json (Rust) edit: 2.84; simd-json (Rust) minify: 3.40; simd-json (Rust) write: 3.10; Glaze validate: 2.04; Glaze sum: 3.85; Glaze select: 1.79 (0.82 doing less, P); Glaze edit: 4.41; Glaze minify: 5.19 (1.03 doing less, P); Glaze write: 2.23; Boost.J&#8203;SON validate: 2.56; Boost.J&#8203;SON sum: 1.99; Boost.J&#8203;SON select: 3.27; Boost.J&#8203;SON edit: 3.21; Boost.J&#8203;SON minify: 3.87; Boost.J&#8203;SON write: 3.75; serde_json (Rust) validate: 2.46 (2.23 doing less, U); serde_json (Rust) sum: 2.59; serde_json (Rust) select: 2.39 (2.24 doing less, U); serde_json (Rust) edit: 4.99; serde_json (Rust) minify: 5.85; serde_json (Rust) write: 2.95; nlohmann/json json validate: 2.71; nlohmann/json json sum: 1.96; nlohmann/json json select: 6.87; nlohmann/json json edit: 3.73; nlohmann/json json minify: 4.89; nlohmann/json json write: 2.10; RapidJSON validate: 4.72 (3.09 doing less, U); RapidJSON sum: 4.15 (2.85 doing less, U); RapidJSON select: 5.91 (3.82 doing less, U); RapidJSON edit: 4.82 (3.77 doing less, U); RapidJSON minify: 4.86 (3.60 doing less, U N); RapidJSON write: 5.88.</desc> <text class=nj-charts-tick x=270 y=34>validate</text> <text class=nj-charts-tick x=362 y=34>sum</text> <text class=nj-charts-tick x=454 y=34>select</text> <text class=nj-charts-tick x=546 y=34>edit</text> <text class=nj-charts-tick x=638 y=34>minify</text> <text class=nj-charts-tick x=730 y=34>write</text> <text class="nj-charts-rowlabel nj-charts-name-json" x=216 y=66 text-anchor=end>nlohmann/json json_document</text> <g class=nj-heat-cell tabindex=0 data-tip="nlohmann/json json_document · validate
1.00× the time of the fastest library (fully validating)
way: accept
twitter.json: 170 µs
citm_catalog.json: 313 µs
canada.json: 886 µs
jeopardy.json: 20,873 µs"> <rect class=nj-heat-0 x=225 y=45 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=270 y=66 text-anchor=middle>1.00</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="nlohmann/json json_document · sum
1.00× the time of the fastest library (fully validating)
way: parse
twitter.json: 224 µs
citm_catalog.json: 485 µs
canada.json: 1,816 µs
jeopardy.json: 28,987 µs"> <rect class=nj-heat-0 x=317 y=45 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=362 y=66 text-anchor=middle>1.00</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="nlohmann/json json_document · select
1.00× the time of the fastest library (fully validating)
way: parse
twitter.json: 184 µs
citm_catalog.json: 363 µs
canada.json: 956 µs
jeopardy.json: 24,991 µs"> <rect class=nj-heat-0 x=409 y=45 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=454 y=66 text-anchor=middle>1.00</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="nlohmann/json json_document · edit
1.00× the time of the fastest library (fully validating)
way: editable
twitter.json: 291 µs
citm_catalog.json: 560 µs
canada.json: 2,765 µs
jeopardy.json: 58,057 µs"> <rect class=nj-heat-0 x=501 y=45 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=523.5 y=66 text-anchor=middle>1.00</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="nlohmann/json json_document · edit, checking less
0.85× the time of the fastest fully validating library
twitter.json: 283 µs · editable (source numbers) (validates fully)
citm_catalog.json: 560 µs · editable (validates fully)
canada.json: 1,484 µs · editable (source numbers) (validates fully)
jeopardy.json: 57,635 µs · editable (source numbers) (validates fully)
copies each number's text instead of formatting it (number_format::source)"> <rect class=nj-heat-0 x=547 y=45 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=568.5 y=60 text-anchor=middle>0.85</text> <text class="nj-charts-cell nj-charts-cell--small" x=568.5 y=73 text-anchor=middle>N</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="nlohmann/json json_document · minify
1.00× the time of the fastest library (fully validating)
way: parse + dump
twitter.json: 259 µs
citm_catalog.json: 493 µs
canada.json: 2,582 µs
jeopardy.json: 37,882 µs"> <rect class=nj-heat-0 x=593 y=45 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=615.5 y=66 text-anchor=middle>1.00</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="nlohmann/json json_document · minify, checking less
0.85× the time of the fastest fully validating library
twitter.json: 252 µs · parse + dump (source numbers) (validates fully)
citm_catalog.json: 493 µs · parse + dump (validates fully)
canada.json: 1,360 µs · parse + dump (source numbers) (validates fully)
jeopardy.json: 37,817 µs · parse + dump (source numbers) (validates fully)
copies each number's text instead of formatting it (number_format::source)"> <rect class=nj-heat-0 x=639 y=45 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=660.5 y=60 text-anchor=middle>0.85</text> <text class="nj-charts-cell nj-charts-cell--small" x=660.5 y=73 text-anchor=middle>N</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="nlohmann/json json_document · write
1.00× the time of the fastest library (fully validating)
way: dump
twitter.json: 74.3 µs
citm_catalog.json: 134 µs
canada.json: 1,621 µs
jeopardy.json: 14,757 µs"> <rect class=nj-heat-0 x=685 y=45 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=707.5 y=66 text-anchor=middle>1.00</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="nlohmann/json json_document · write, checking less
0.71× the time of the fastest fully validating library
twitter.json: 74.3 µs · dump (validates fully)
citm_catalog.json: 134 µs · dump (validates fully)
canada.json: 401 µs · dump (source numbers) (validates fully)
jeopardy.json: 14,757 µs · dump (validates fully)
copies each number's text instead of formatting it (number_format::source)"> <rect class=nj-heat-0 x=731 y=45 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=752.5 y=60 text-anchor=middle>0.71</text> <text class="nj-charts-cell nj-charts-cell--small" x=752.5 y=73 text-anchor=middle>N</text> </g> <text class="nj-charts-rowlabel " x=216 y=102 text-anchor=end>yyjson</text> <g class=nj-heat-cell tabindex=0 data-tip="yyjson · validate
1.37× the time of the fastest library (fully validating)
way: insitu (copy untimed)
twitter.json: 172 µs
citm_catalog.json: 451 µs
canada.json: 1,457 µs
jeopardy.json: 30,240 µs"> <rect class=nj-heat-1 x=225 y=81 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=270 y=102 text-anchor=middle>1.37</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="yyjson · sum
1.11× the time of the fastest library (fully validating)
way: insitu (copy untimed)
twitter.json: 219 µs
citm_catalog.json: 551 µs
canada.json: 1,906 µs
jeopardy.json: 37,512 µs"> <rect class=nj-heat-0 x=317 y=81 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=362 y=102 text-anchor=middle>1.11</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="yyjson · select
1.25× the time of the fastest library (fully validating)
way: insitu (copy untimed)
twitter.json: 178 µs
citm_catalog.json: 456 µs
canada.json: 1,461 µs
jeopardy.json: 32,514 µs"> <rect class=nj-heat-1 x=409 y=81 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=454 y=102 text-anchor=middle>1.25</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="yyjson · edit
1.45× the time of the fastest library (fully validating)
way: insitu (copy untimed) + mut copy
twitter.json: 427 µs
citm_catalog.json: 882 µs
canada.json: 3,642 µs
jeopardy.json: 84,239 µs"> <rect class=nj-heat-1 x=501 y=81 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=546 y=102 text-anchor=middle>1.45</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="yyjson · minify
1.23× the time of the fastest library (fully validating)
way: insitu (copy untimed) + write
twitter.json: 279 µs
citm_catalog.json: 625 µs
canada.json: 3,196 µs
jeopardy.json: 50,821 µs"> <rect class=nj-heat-1 x=593 y=81 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=615.5 y=102 text-anchor=middle>1.23</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="yyjson · minify, checking less
1.16× the time of the fastest fully validating library
twitter.json: 279 µs · insitu (copy untimed) + write (validates fully)
citm_catalog.json: 625 µs · insitu (copy untimed) + write (validates fully)
canada.json: 2,550 µs · read (raw numbers) + write (validates fully)
jeopardy.json: 50,821 µs · insitu (copy untimed) + write (validates fully)
copies each number's text instead of formatting it (YYJSON_READ_NUMBER_AS_RAW)"> <rect class=nj-heat-1 x=639 y=81 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=660.5 y=96 text-anchor=middle>1.16</text> <text class="nj-charts-cell nj-charts-cell--small" x=660.5 y=109 text-anchor=middle>N</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="yyjson · write
1.26× the time of the fastest library (fully validating)
way: write
twitter.json: 103 µs
citm_catalog.json: 169 µs
canada.json: 1,731 µs
jeopardy.json: 20,087 µs"> <rect class=nj-heat-1 x=685 y=81 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=730 y=102 text-anchor=middle>1.26</text> </g> <text class="nj-charts-rowlabel " x=216 y=138 text-anchor=end>simdjson</text> <g class=nj-heat-cell tabindex=0 data-tip="simdjson · validate
1.52× the time of the fastest library (fully validating)
way: D​OM
twitter.json: 212 µs
citm_catalog.json: 452 µs
canada.json: 1,888 µs
jeopardy.json: 28,843 µs"> <rect class=nj-heat-2 x=225 y=117 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=270 y=138 text-anchor=middle>1.52</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="simdjson · sum
1.20× the time of the fastest library (fully validating)
twitter.json: 249 µs · D​OM
citm_catalog.json: 571 µs · On-Demand
canada.json: 2,374 µs · On-Demand
jeopardy.json: 35,111 µs · D​OM"> <rect class=nj-heat-1 x=317 y=117 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=362 y=138 text-anchor=middle>1.20</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="simdjson · select
1.33× the time of the fastest library (fully validating)
way: D​OM
twitter.json: 196 µs
citm_catalog.json: 450 µs
canada.json: 1,886 µs
jeopardy.json: 30,504 µs"> <rect class=nj-heat-1 x=409 y=117 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=431.5 y=138 text-anchor=middle>1.33</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="simdjson · select, checking less
0.75× the time of the fastest fully validating library
twitter.json: 127 µs · On-Demand structs
citm_catalog.json: 354 µs · On-Demand
canada.json: 566 µs · On-Demand (key selectors)
jeopardy.json: 19,562 µs · On-Demand
reads lazily: On-Demand reads only what you ask for and steps over the rest by matching brackets"> <rect class=nj-heat-0 x=455 y=117 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=476.5 y=132 text-anchor=middle>0.75</text> <text class="nj-charts-cell nj-charts-cell--small" x=476.5 y=145 text-anchor=middle>P</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="simdjson · edit
simdjson's documents are read-only: it has no A​PI to change a value and write the result"> <rect class=nj-heat-na x=501 y=117 width=90 height=34 rx=3 /> <text class=nj-charts-tick x=546 y=138>n/a</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="simdjson · minify
1.73× the time of the fastest library (fully validating)
way: D​OM + to_string
twitter.json: 423 µs
citm_catalog.json: 848 µs
canada.json: 5,120 µs
jeopardy.json: 61,059 µs"> <rect class=nj-heat-2 x=593 y=117 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=615.5 y=138 text-anchor=middle>1.73</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="simdjson · minify, checking less
0.18× the time of the fastest fully validating library
way: minify
twitter.json: 62.3 µs
citm_catalog.json: 171 µs
canada.json: 227 µs
jeopardy.json: 5,762 µs
simdjson::minify() only removes whitespace, without parsing the values"> <rect class=nj-heat-0 x=639 y=117 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=660.5 y=132 text-anchor=middle>0.18</text> <text class="nj-charts-cell nj-charts-cell--small" x=660.5 y=145 text-anchor=middle>P</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="simdjson · write
2.41× the time of the fastest library (fully validating)
way: to_string
twitter.json: 199 µs
citm_catalog.json: 385 µs
canada.json: 3,241 µs
jeopardy.json: 32,208 µs"> <rect class=nj-heat-2 x=685 y=117 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=730 y=138 text-anchor=middle>2.41</text> </g> <text class="nj-charts-rowlabel " x=216 y=174 text-anchor=end>sonic-rs (Rust)</text> <g class=nj-heat-cell tabindex=0 data-tip="sonic-rs (Rust) · validate
1.93× the time of the fastest library (fully validating)
way: Value
twitter.json: 326 µs
citm_catalog.json: 681 µs
canada.json: 1,939 µs
jeopardy.json: 31,450 µs"> <rect class=nj-heat-2 x=225 y=153 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=270 y=174 text-anchor=middle>1.93</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="sonic-rs (Rust) · sum
1.53× the time of the fastest library (fully validating)
way: visitor
twitter.json: 364 µs
citm_catalog.json: 778 µs
canada.json: 2,703 µs
jeopardy.json: 41,361 µs"> <rect class=nj-heat-2 x=317 y=153 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=362 y=174 text-anchor=middle>1.53</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="sonic-rs (Rust) · select
1.83× the time of the fastest library (fully validating)
way: Value
twitter.json: 333 µs
citm_catalog.json: 691 µs
canada.json: 1,936 µs
jeopardy.json: 40,660 µs"> <rect class=nj-heat-2 x=409 y=153 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=454 y=174 text-anchor=middle>1.83</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="sonic-rs (Rust) · edit
2.08× the time of the fastest library (fully validating)
way: Value
twitter.json: 634 µs
citm_catalog.json: 1,257 µs
canada.json: 4,396 µs
jeopardy.json: 140,936 µs"> <rect class=nj-heat-2 x=501 y=153 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=546 y=174 text-anchor=middle>2.08</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="sonic-rs (Rust) · minify
1.93× the time of the fastest library (fully validating)
way: Value
twitter.json: 535 µs
citm_catalog.json: 1,134 µs
canada.json: 4,377 µs
jeopardy.json: 64,832 µs"> <rect class=nj-heat-2 x=593 y=153 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=638 y=174 text-anchor=middle>1.93</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="sonic-rs (Rust) · write
2.38× the time of the fastest library (fully validating)
way: Value
twitter.json: 212 µs
citm_catalog.json: 446 µs
canada.json: 2,419 µs
jeopardy.json: 33,366 µs"> <rect class=nj-heat-2 x=685 y=153 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=730 y=174 text-anchor=middle>2.38</text> </g> <text class="nj-charts-rowlabel " x=216 y=210 text-anchor=end>sonic-cpp</text> <g class=nj-heat-cell tabindex=0 data-tip="sonic-cpp · validate, checking less
2.53× the time of the fastest fully validating library
way: Document
twitter.json: 382 µs
citm_catalog.json: 985 µs
canada.json: 2,578 µs
jeopardy.json: 41,617 µs
trusts U​TF-8: sonic-cpp 1.0.2 doesn't check it"> <rect class=nj-heat-3 x=225 y=189 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=270 y=204 text-anchor=middle>2.53</text> <text class="nj-charts-cell nj-charts-cell--small" x=270 y=217 text-anchor=middle>U</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="sonic-cpp · sum, checking less
1.86× the time of the fastest fully validating library
way: Document
twitter.json: 428 µs
citm_catalog.json: 1,087 µs
canada.json: 2,993 µs
jeopardy.json: 48,688 µs
trusts U​TF-8: sonic-cpp 1.0.2 doesn't check it"> <rect class=nj-heat-2 x=317 y=189 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=362 y=204 text-anchor=middle>1.86</text> <text class="nj-charts-cell nj-charts-cell--small" x=362 y=217 text-anchor=middle>U</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="sonic-cpp · select, checking less
2.31× the time of the fastest fully validating library
way: Document
twitter.json: 385 µs
citm_catalog.json: 990 µs
canada.json: 2,586 µs
jeopardy.json: 45,858 µs
trusts U​TF-8: sonic-cpp 1.0.2 doesn't check it"> <rect class=nj-heat-2 x=409 y=189 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=454 y=204 text-anchor=middle>2.31</text> <text class="nj-charts-cell nj-charts-cell--small" x=454 y=217 text-anchor=middle>U</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="sonic-cpp · edit, checking less
1.68× the time of the fastest fully validating library
way: Document
twitter.json: 486 µs
citm_catalog.json: 1,224 µs
canada.json: 5,638 µs
jeopardy.json: 62,688 µs
trusts U​TF-8: sonic-cpp 1.0.2 doesn't check it"> <rect class=nj-heat-2 x=501 y=189 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=546 y=204 text-anchor=middle>1.68</text> <text class="nj-charts-cell nj-charts-cell--small" x=546 y=217 text-anchor=middle>U</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="sonic-cpp · minify, checking less
2.03× the time of the fastest fully validating library
way: Document + Serialize
twitter.json: 500 µs
citm_catalog.json: 1,220 µs
canada.json: 5,676 µs
jeopardy.json: 61,236 µs
trusts U​TF-8: sonic-cpp 1.0.2 doesn't check it"> <rect class=nj-heat-2 x=593 y=189 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=638 y=204 text-anchor=middle>2.03</text> <text class="nj-charts-cell nj-charts-cell--small" x=638 y=217 text-anchor=middle>U</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="sonic-cpp · write
1.59× the time of the fastest library (fully validating)
way: Serialize
twitter.json: 108 µs
citm_catalog.json: 230 µs
canada.json: 3,093 µs
jeopardy.json: 19,651 µs"> <rect class=nj-heat-2 x=685 y=189 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=730 y=210 text-anchor=middle>1.59</text> </g> <text class="nj-charts-rowlabel " x=216 y=246 text-anchor=end>simd-json (Rust)</text> <g class=nj-heat-cell tabindex=0 data-tip="simd-json (Rust) · validate
2.07× the time of the fastest library (fully validating)
way: tape (copy)
twitter.json: 289 µs
citm_catalog.json: 698 µs
canada.json: 2,278 µs
jeopardy.json: 38,874 µs
(copy): parses in place, on a copy of the input that is part of the time"> <rect class=nj-heat-2 x=225 y=225 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=270 y=246 text-anchor=middle>2.07</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="simd-json (Rust) · sum
1.62× the time of the fastest library (fully validating)
way: visitor (copy)
twitter.json: 354 µs
citm_catalog.json: 866 µs
canada.json: 2,717 µs
jeopardy.json: 47,518 µs
(copy): parses in place, on a copy of the input that is part of the time"> <rect class=nj-heat-2 x=317 y=225 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=362 y=246 text-anchor=middle>1.62</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="simd-json (Rust) · select
2.38× the time of the fastest library (fully validating)
way: structs (copy)
twitter.json: 364 µs
citm_catalog.json: 914 µs
canada.json: 2,657 µs
jeopardy.json: 57,697 µs
(copy): parses in place, on a copy of the input that is part of the time"> <rect class=nj-heat-2 x=409 y=225 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=454 y=246 text-anchor=middle>2.38</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="simd-json (Rust) · edit
2.84× the time of the fastest library (fully validating)
way: borrowed (copy)
twitter.json: 948 µs
citm_catalog.json: 2,102 µs
canada.json: 7,654 µs
jeopardy.json: 110,693 µs
(copy): parses in place, on a copy of the input that is part of the time"> <rect class=nj-heat-3 x=501 y=225 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=546 y=246 text-anchor=middle>2.84</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="simd-json (Rust) · minify
3.40× the time of the fastest library (fully validating)
way: borrowed (copy)
twitter.json: 952 µs
citm_catalog.json: 2,111 µs
canada.json: 7,658 µs
jeopardy.json: 108,130 µs
(copy): parses in place, on a copy of the input that is part of the time"> <rect class=nj-heat-3 x=593 y=225 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=638 y=246 text-anchor=middle>3.40</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="simd-json (Rust) · write
3.10× the time of the fastest library (fully validating)
way: borrowed
twitter.json: 355 µs
citm_catalog.json: 478 µs
canada.json: 2,728 µs
jeopardy.json: 47,412 µs"> <rect class=nj-heat-3 x=685 y=225 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=730 y=246 text-anchor=middle>3.10</text> </g> <text class="nj-charts-rowlabel " x=216 y=282 text-anchor=end>Glaze</text> <g class=nj-heat-cell tabindex=0 data-tip="Glaze · validate
2.04× the time of the fastest library (fully validating)
way: validate_json
twitter.json: 331 µs
citm_catalog.json: 862 µs
canada.json: 1,326 µs
jeopardy.json: 45,192 µs"> <rect class=nj-heat-2 x=225 y=261 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=270 y=282 text-anchor=middle>2.04</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="Glaze · sum
3.85× the time of the fastest library (fully validating)
way: generic (double, strict)
twitter.json: 968 µs
citm_catalog.json: 2,049 µs
canada.json: 6,331 µs
jeopardy.json: 99,763 µs"> <rect class=nj-heat-3 x=317 y=261 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=362 y=282 text-anchor=middle>3.85</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="Glaze · select
1.79× the time of the fastest library (fully validating)
way: structs (validate_skipped)
twitter.json: 311 µs
citm_catalog.json: 854 µs
canada.json: 1,316 µs
jeopardy.json: 46,924 µs"> <rect class=nj-heat-2 x=409 y=261 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=431.5 y=282 text-anchor=middle>1.79</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="Glaze · select, checking less
0.82× the time of the fastest fully validating library
way: structs
twitter.json: 241 µs
citm_catalog.json: 255 µs
canada.json: 313 µs
jeopardy.json: 37,578 µs
reads into structs and steps over fields it doesn't know without checking them (validate_skipped checks them too)"> <rect class=nj-heat-0 x=455 y=261 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=476.5 y=276 text-anchor=middle>0.82</text> <text class="nj-charts-cell nj-charts-cell--small" x=476.5 y=289 text-anchor=middle>P</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="Glaze · edit
4.41× the time of the fastest library (fully validating)
way: generic (strict)
twitter.json: 1,539 µs
citm_catalog.json: 3,235 µs
canada.json: 11,083 µs
jeopardy.json: 178,333 µs"> <rect class=nj-heat-3 x=501 y=261 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=546 y=282 text-anchor=middle>4.41</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="Glaze · minify
5.19× the time of the fastest library (fully validating)
way: generic (strict)
twitter.json: 1,505 µs
citm_catalog.json: 3,225 µs
canada.json: 11,092 µs
jeopardy.json: 168,855 µs"> <rect class=nj-heat-4 x=593 y=261 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=615.5 y=282 text-anchor=middle>5.19</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="Glaze · minify, checking less
1.03× the time of the fastest fully validating library
way: minify_json
twitter.json: 281 µs
citm_catalog.json: 729 µs
canada.json: 1,722 µs
jeopardy.json: 39,976 µs
minify_json only removes whitespace, without parsing the values"> <rect class=nj-heat-0 x=639 y=261 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=660.5 y=276 text-anchor=middle>1.03</text> <text class="nj-charts-cell nj-charts-cell--small" x=660.5 y=289 text-anchor=middle>P</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="Glaze · write
2.23× the time of the fastest library (fully validating)
twitter.json: 216 µs · generic
citm_catalog.json: 469 µs · generic
canada.json: 1,720 µs · generic (strict)
jeopardy.json: 33,934 µs · generic"> <rect class=nj-heat-2 x=685 y=261 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=730 y=282 text-anchor=middle>2.23</text> </g> <text class="nj-charts-rowlabel " x=216 y=318 text-anchor=end>Boost.J&#8203;SON</text> <g class=nj-heat-cell tabindex=0 data-tip="Boost.J​SON · validate
2.56× the time of the fastest library (fully validating)
way: S​AX (numbers: none)
twitter.json: 535 µs
citm_catalog.json: 994 µs
canada.json: 1,467 µs
jeopardy.json: 53,939 µs"> <rect class=nj-heat-3 x=225 y=297 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=270 y=318 text-anchor=middle>2.56</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="Boost.J​SON · sum
1.99× the time of the fastest library (fully validating)
way: S​AX
twitter.json: 535 µs
citm_catalog.json: 1,010 µs
canada.json: 3,067 µs
jeopardy.json: 53,704 µs"> <rect class=nj-heat-2 x=317 y=297 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=362 y=318 text-anchor=middle>1.99</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="Boost.J​SON · select
3.27× the time of the fastest library (fully validating)
twitter.json: 617 µs · parse_into structs
citm_catalog.json: 1,205 µs · parse_into structs
canada.json: 3,650 µs · parse
jeopardy.json: 67,255 µs · parse_into structs"> <rect class=nj-heat-3 x=409 y=297 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=454 y=318 text-anchor=middle>3.27</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="Boost.J​SON · edit
3.21× the time of the fastest library (fully validating)
way: parse
twitter.json: 1,368 µs
citm_catalog.json: 1,992 µs
canada.json: 6,573 µs
jeopardy.json: 155,237 µs"> <rect class=nj-heat-3 x=501 y=297 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=546 y=318 text-anchor=middle>3.21</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="Boost.J​SON · minify
3.87× the time of the fastest library (fully validating)
way: parse + serialize
twitter.json: 1,393 µs
citm_catalog.json: 1,986 µs
canada.json: 6,542 µs
jeopardy.json: 154,677 µs"> <rect class=nj-heat-3 x=593 y=297 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=638 y=318 text-anchor=middle>3.87</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="Boost.J​SON · write
3.75× the time of the fastest library (fully validating)
way: serialize
twitter.json: 507 µs
citm_catalog.json: 508 µs
canada.json: 2,923 µs
jeopardy.json: 62,583 µs"> <rect class=nj-heat-3 x=685 y=297 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=730 y=318 text-anchor=middle>3.75</text> </g> <text class="nj-charts-rowlabel " x=216 y=354 text-anchor=end>serde_json (Rust)</text> <g class=nj-heat-cell tabindex=0 data-tip="serde_json (Rust) · validate
2.46× the time of the fastest library (fully validating)
way: from_utf8 + IgnoredAny
twitter.json: 452 µs
citm_catalog.json: 1,103 µs
canada.json: 1,556 µs
jeopardy.json: 46,517 µs"> <rect class=nj-heat-2 x=225 y=333 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=247.5 y=354 text-anchor=middle>2.46</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="serde_json (Rust) · validate, checking less
2.23× the time of the fastest fully validating library
way: IgnoredAny
twitter.json: 354 µs
citm_catalog.json: 1,047 µs
canada.json: 1,451 µs
jeopardy.json: 44,984 µs
trusts U​TF-8 in the strings it skips (from_slice); strings it reads are checked"> <rect class=nj-heat-2 x=271 y=333 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=292.5 y=348 text-anchor=middle>2.23</text> <text class="nj-charts-cell nj-charts-cell--small" x=292.5 y=361 text-anchor=middle>U</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="serde_json (Rust) · sum
2.59× the time of the fastest library (fully validating)
way: visitor
twitter.json: 652 µs
citm_catalog.json: 1,242 µs
canada.json: 4,772 µs
jeopardy.json: 66,568 µs"> <rect class=nj-heat-3 x=317 y=333 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=362 y=354 text-anchor=middle>2.59</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="serde_json (Rust) · select
2.39× the time of the fastest library (fully validating)
way: from_utf8 + structs
twitter.json: 480 µs
citm_catalog.json: 1,125 µs
canada.json: 1,560 µs
jeopardy.json: 62,378 µs"> <rect class=nj-heat-2 x=409 y=333 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=431.5 y=354 text-anchor=middle>2.39</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="serde_json (Rust) · select, checking less
2.24× the time of the fastest fully validating library
twitter.json: 410 µs · structs
citm_catalog.json: 1,084 µs · structs
canada.json: 1,455 µs · structs
jeopardy.json: 62,378 µs · from_utf8 + structs (validates fully)
trusts U​TF-8 in the strings it skips (from_slice); strings it reads are checked"> <rect class=nj-heat-2 x=455 y=333 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=476.5 y=348 text-anchor=middle>2.24</text> <text class="nj-charts-cell nj-charts-cell--small" x=476.5 y=361 text-anchor=middle>U</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="serde_json (Rust) · edit
4.99× the time of the fastest library (fully validating)
way: Value
twitter.json: 2,009 µs
citm_catalog.json: 3,316 µs
canada.json: 9,666 µs
jeopardy.json: 251,931 µs"> <rect class=nj-heat-3 x=501 y=333 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=546 y=354 text-anchor=middle>4.99</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="serde_json (Rust) · minify
5.85× the time of the fastest library (fully validating)
way: Value
twitter.json: 2,004 µs
citm_catalog.json: 3,290 µs
canada.json: 9,792 µs
jeopardy.json: 227,369 µs"> <rect class=nj-heat-4 x=593 y=333 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=638 y=354 text-anchor=middle>5.85</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="serde_json (Rust) · write
2.95× the time of the fastest library (fully validating)
way: Value
twitter.json: 322 µs
citm_catalog.json: 490 µs
canada.json: 2,286 µs
jeopardy.json: 49,967 µs"> <rect class=nj-heat-3 x=685 y=333 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=730 y=354 text-anchor=middle>2.95</text> </g> <text class="nj-charts-rowlabel nj-charts-name-json" x=216 y=390 text-anchor=end>nlohmann/json json</text> <g class=nj-heat-cell tabindex=0 data-tip="nlohmann/json json · validate
2.71× the time of the fastest library (fully validating)
way: accept
twitter.json: 451 µs
citm_catalog.json: 888 µs
canada.json: 2,405 µs
jeopardy.json: 55,286 µs"> <rect class=nj-heat-3 x=225 y=369 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=270 y=390 text-anchor=middle>2.71</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="nlohmann/json json · sum
1.96× the time of the fastest library (fully validating)
way: sax
twitter.json: 465 µs
citm_catalog.json: 925 µs
canada.json: 3,072 µs
jeopardy.json: 64,089 µs"> <rect class=nj-heat-2 x=317 y=369 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=362 y=390 text-anchor=middle>1.96</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="nlohmann/json json · select
6.87× the time of the fastest library (fully validating)
twitter.json: 1,360 µs · structs (from_json)
citm_catalog.json: 2,416 µs · parse
canada.json: 6,047 µs · structs (from_json)
jeopardy.json: 179,533 µs · parse"> <rect class=nj-heat-4 x=409 y=369 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=454 y=390 text-anchor=middle>6.87</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="nlohmann/json json · edit
3.73× the time of the fastest library (fully validating)
twitter.json: 1,273 µs · ordered_json
citm_catalog.json: 2,344 µs · ordered_json
canada.json: 8,334 µs · parse
jeopardy.json: 203,232 µs · ordered_json"> <rect class=nj-heat-3 x=501 y=369 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=546 y=390 text-anchor=middle>3.73</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="nlohmann/json json · minify
4.89× the time of the fastest library (fully validating)
way: parse + dump
twitter.json: 1,600 µs
citm_catalog.json: 2,706 µs
canada.json: 8,389 µs
jeopardy.json: 197,745 µs"> <rect class=nj-heat-3 x=593 y=369 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=638 y=390 text-anchor=middle>4.89</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="nlohmann/json json · write
2.10× the time of the fastest library (fully validating)
way: dump
twitter.json: 223 µs
citm_catalog.json: 287 µs
canada.json: 2,276 µs
jeopardy.json: 31,825 µs"> <rect class=nj-heat-2 x=685 y=369 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=730 y=390 text-anchor=middle>2.10</text> </g> <text class="nj-charts-rowlabel " x=216 y=426 text-anchor=end>RapidJSON</text> <g class=nj-heat-cell tabindex=0 data-tip="RapidJSON · validate
4.72× the time of the fastest library (fully validating)
twitter.json: 1,307 µs · insitu (copy untimed)
citm_catalog.json: 1,397 µs · S​AX (string stream, default precision)
canada.json: 1,982 µs · S​AX (string stream, default precision)
jeopardy.json: 134,679 µs · S​AX (string stream, default precision)"> <rect class=nj-heat-3 x=225 y=405 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=247.5 y=426 text-anchor=middle>4.72</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="RapidJSON · validate, checking less
3.09× the time of the fastest fully validating library
twitter.json: 686 µs · insitu (copy untimed) (no encoding check)
citm_catalog.json: 1,032 µs · S​AX (string stream, default precision) (no encoding check)
canada.json: 1,982 µs · S​AX (string stream, default precision) (validates fully)
jeopardy.json: 63,589 µs · insitu (copy untimed) (no encoding check)
trusts U​TF-8: RapidJSON's default (kParseValidateEncodingFlag checks it)"> <rect class=nj-heat-3 x=271 y=405 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=292.5 y=420 text-anchor=middle>3.09</text> <text class="nj-charts-cell nj-charts-cell--small" x=292.5 y=433 text-anchor=middle>U</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="RapidJSON · sum
4.15× the time of the fastest library (fully validating)
twitter.json: 1,329 µs · S​AX
citm_catalog.json: 1,455 µs · S​AX (string stream)
canada.json: 6,453 µs · S​AX (string stream)
jeopardy.json: 136,103 µs · S​AX (string stream)"> <rect class=nj-heat-3 x=317 y=405 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=339.5 y=426 text-anchor=middle>4.15</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="RapidJSON · sum, checking less
2.85× the time of the fastest fully validating library
twitter.json: 735 µs · S​AX (string stream) (no encoding check)
citm_catalog.json: 1,136 µs · S​AX (string stream) (no encoding check)
canada.json: 6,453 µs · S​AX (string stream) (validates fully)
jeopardy.json: 69,604 µs · insitu (copy untimed) (no encoding check)
trusts U​TF-8: RapidJSON's default (kParseValidateEncodingFlag checks it)"> <rect class=nj-heat-3 x=363 y=405 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=384.5 y=420 text-anchor=middle>2.85</text> <text class="nj-charts-cell nj-charts-cell--small" x=384.5 y=433 text-anchor=middle>U</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="RapidJSON · select
5.91× the time of the fastest library (fully validating)
twitter.json: 1,304 µs · insitu (copy untimed)
citm_catalog.json: 1,554 µs · insitu (copy untimed)
canada.json: 6,776 µs · Document (string stream)
jeopardy.json: 141,509 µs · insitu (copy untimed)"> <rect class=nj-heat-4 x=409 y=405 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=431.5 y=426 text-anchor=middle>5.91</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="RapidJSON · select, checking less
3.82× the time of the fastest fully validating library
twitter.json: 679 µs · insitu (copy untimed) (no encoding check)
citm_catalog.json: 1,126 µs · insitu (copy untimed) (no encoding check)
canada.json: 6,776 µs · Document (string stream) (validates fully)
jeopardy.json: 65,625 µs · insitu (copy untimed) (no encoding check)
trusts U​TF-8: RapidJSON's default (kParseValidateEncodingFlag checks it)"> <rect class=nj-heat-3 x=455 y=405 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=476.5 y=420 text-anchor=middle>3.82</text> <text class="nj-charts-cell nj-charts-cell--small" x=476.5 y=433 text-anchor=middle>U</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="RapidJSON · edit
4.82× the time of the fastest library (fully validating)
twitter.json: 1,922 µs · Document
citm_catalog.json: 2,388 µs · insitu (copy untimed)
canada.json: 13,836 µs · Document (string stream)
jeopardy.json: 221,270 µs · insitu (copy untimed)"> <rect class=nj-heat-3 x=501 y=405 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=523.5 y=426 text-anchor=middle>4.82</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="RapidJSON · edit, checking less
3.77× the time of the fastest fully validating library
way: insitu (copy untimed) (no encoding check)
twitter.json: 1,344 µs
citm_catalog.json: 1,964 µs
canada.json: 13,794 µs
jeopardy.json: 144,741 µs
trusts U​TF-8: RapidJSON's default (kParseValidateEncodingFlag checks it)"> <rect class=nj-heat-3 x=547 y=405 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=568.5 y=420 text-anchor=middle>3.77</text> <text class="nj-charts-cell nj-charts-cell--small" x=568.5 y=433 text-anchor=middle>U</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="RapidJSON · minify
4.86× the time of the fastest library (fully validating)
twitter.json: 1,525 µs · S​AX to Writer
citm_catalog.json: 1,808 µs · S​AX to Writer (string stream)
canada.json: 14,460 µs · Document + Writer
jeopardy.json: 174,558 µs · S​AX to Writer (string stream)"> <rect class=nj-heat-3 x=593 y=405 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=615.5 y=426 text-anchor=middle>4.86</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="RapidJSON · minify, checking less
3.60× the time of the fastest fully validating library
twitter.json: 1,058 µs · S​AX to Writer (string stream) (no encoding check)
citm_catalog.json: 1,485 µs · S​AX to Writer (string stream) (no encoding check)
canada.json: 10,908 µs · S​AX to Writer (raw numbers) (no encoding check)
jeopardy.json: 123,119 µs · S​AX to Writer (string stream) (no encoding check)
trusts U​TF-8: RapidJSON's default (kParseValidateEncodingFlag checks it)
copies each number's text instead of formatting it (kParseNumbersAsStringsFlag)"> <rect class=nj-heat-3 x=639 y=405 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=660.5 y=420 text-anchor=middle>3.60</text> <text class="nj-charts-cell nj-charts-cell--small" x=660.5 y=433 text-anchor=middle>U N</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="RapidJSON · write
5.88× the time of the fastest library (fully validating)
way: Writer
twitter.json: 603 µs
citm_catalog.json: 830 µs
canada.json: 6,995 µs
jeopardy.json: 81,150 µs"> <rect class=nj-heat-4 x=685 y=405 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=730 y=426 text-anchor=middle>5.88</text> </g> <text class="nj-charts-tick nj-charts-tick--l" x=8 y=472>time relative to the fastest fully validating library, less is better</text> <g><rect class=nj-heat-0 x=8 y=482 width=76 height=20 rx=3 /> <text class="nj-charts-cell nj-charts-cell--small" x=46 y=496 text-anchor=middle>below 1.15</text></g> <g><rect class=nj-heat-1 x=88 y=482 width=76 height=20 rx=3 /> <text class="nj-charts-cell nj-charts-cell--small" x=126 y=496 text-anchor=middle>1.15 to 1.5</text></g> <g><rect class=nj-heat-2 x=168 y=482 width=76 height=20 rx=3 /> <text class="nj-charts-cell nj-charts-cell--small" x=206 y=496 text-anchor=middle>1.5 to 2.5</text></g> <g><rect class=nj-heat-3 x=248 y=482 width=76 height=20 rx=3 /> <text class="nj-charts-cell nj-charts-cell--small" x=286 y=496 text-anchor=middle>2.5 to 5</text></g> <g><rect class=nj-heat-4 x=328 y=482 width=76 height=20 rx=3 /> <text class="nj-charts-cell nj-charts-cell--small" x=366 y=496 text-anchor=middle>5 and more</text></g> <rect class=nj-heat-na x=420 y=482 width=40 height=20 rx=3 /> <text class=nj-charts-tick x=440 y=496>n/a</text> <text class="nj-charts-tick nj-charts-tick--l" x=468 y=496>no A&#8203;PI for it</text> </svg></p> </div> <p class=nj-caption>Time per library and use case on an Apple M1 Max: each library's fastest fully validating way, as the geometric mean over <code>twitter.json</code>, <code>citm_catalog.json</code>, <code>canada.json</code> and <code>jeopardy.json</code>, so that every file counts equally, divided by the fastest library's mean, which therefore shows 1.00. Less is better. Where a way that checks or does less is at least 3% faster, it is shown in the right half of the cell: "U" trusts <abbr title="Unicode Transformation Format">UTF</abbr>-8, "P" reads lazily, only removes whitespace or, in one Glaze cell on x86-64, doesn't check what follows the value, and "N" copies number text instead of formatting it. "n/a" means the library has no <abbr title="Application Programming Interface">API</abbr> for the use case. Hover over or tap a cell for the times per file and the way; the tables are in <a href=#e-comparison-with-other-libraries>Appendix E</a>. sonic-cpp's README lists only x86-64 Linux; we show it on the Mac anyway.</p> <h3 id=results-on-the-mac>Results on the Mac<a class=headerlink href=#results-on-the-mac title="Permanent link">&para;</a></h3> <p>On the Apple M1 Max, among the ways that reject all four broken inputs, <code>json_document</code> has the lowest mean on the four files in all six use cases, and yyjson is second in every column. That includes editing, where the editable document is faster than yyjson's mutable document: the speed doesn't depend on being read-only.</p> <p>Some caveats belong next to that:</p> <ul> <li><strong>The lead is not the same on every file.</strong> On <code>twitter.json</code>, yyjson is within 3–7% in <em>validate</em>, <em>sum</em>, and <em>select</em>. Most of the lead comes from <code>citm_catalog.json</code>, the floats of <code>canada.json</code> (next point) and the size of <code>jeopardy.json</code>.</li> <li><strong>Floats are converted only when read.</strong> That helps <code>json_document</code> in <em>validate</em> and <em>select</em> on <code>canada.json</code>, where most others convert 111,080 floats nobody looks at. Libraries that can skip the conversion use that mode there, but only Boost.<abbr title="JavaScript Object Notation">JSON</abbr> gains much: it validates <code>canada.json</code> in 47% of the time. <em>sum</em> reads every number, so it is the fair comparison for floats; there, <code>json_document</code> is still slightly ahead of yyjson.</li> <li><strong>Checking less pays in <em>select</em>.</strong> If the input needn't be checked fully, simdjson's On-Demand <abbr title="Application Programming Interface">API</abbr> and Glaze reading into structs select in 0.75× and 0.82× <code>json_document</code>'s time (Glaze is faster only on <code>citm_catalog.json</code> and <code>canada.json</code>), and in 0.54–0.62× on x86-64: the right halves of the <em>select</em> column.</li> <li><strong>Indentation.</strong> Two of the four files are indented, which theme <a class=nj-theme href=#theme-2 title="theme 2">2</a> helps. On minified copies of <code>twitter.json</code> and <code>citm_catalog.json</code>, yyjson comes closer in <em>sum</em> (1.11 → 1.04) but not in <em>validate</em> (1.28 → 1.27), and <code>json_document</code> stays first.</li> <li><strong>Number text can be copied.</strong> With <a href=../../../api/basic_json_view/number_format/ ><code>number_format::source</code></a>, <code>json_document</code> writes each number by copying its text instead of formatting it, and yyjson and RapidJSON can read numbers as text and write them back unchanged. The output keeps the source's spelling of each number, which is all a minifier needs. It makes writing <code>canada.json</code> with <code>json_document</code> 4.0× as fast and minifying it 1.9× as fast; the "N" halves of <em>edit</em>, <em>minify</em>, and <em>write</em> show it.</li> <li><strong>Small documents.</strong> On a 2.5 KB message, the fastest libraries take about a microsecond on the Mac and 1.2–2 on x86-64. yyjson validates and sums it as fast as <code>json_document</code> on the Mac, and with <abbr title="GNU Compiler Collection">GCC</abbr> 16 on x86-64, simdjson and yyjson sum it slightly faster.</li> </ul> <h3 id=reading-into-structs>Reading into structs<a class=headerlink href=#reading-into-structs title="Permanent link">&para;</a></h3> <p>A view can be converted into your own types with the same <a href=../../../features/arbitrary_types/ ><code>from_json()</code></a> as <code>json</code>, including the ones the <a href=../../../api/macros/nlohmann_define_type_non_intrusive/ ><code>NLOHMANN_DEFINE_TYPE_*</code></a> macros generate. That is as fast as picking the fields by hand from the view; only for the many small records of <code>jeopardy.json</code> does it take 23% longer. On the Mac, Glaze, serde_json, and Boost.<abbr title="JavaScript Object Notation">JSON</abbr>'s <code>parse_into</code>, reading into the same structs and checking everything, take 1.7×, 2.2×, and 3.1× as long (geometric mean over the four files). On a <code>json</code> value, reading into the structs takes about as long as <code>json::parse()</code> alone.</p> <h3 id=nlohmannjson-without-json_document>nlohmann/json without <code>json_document</code><a class=headerlink href=#nlohmannjson-without-json_document title="Permanent link">&para;</a></h3> <p>And nlohmann/json without <code>json_document</code>? <code>json</code> builds a tree of separate allocations, and it shows: for <em>select</em>, <em>edit</em>, and <em>minify</em> it takes several times as long as <code>json_document</code>, like Boost.<abbr title="JavaScript Object Notation">JSON</abbr> and RapidJSON. Where no tree is needed, it is closer: on the Mac, a <abbr title="Simple API for XML">SAX</abbr> handler is on par with Boost.<abbr title="JavaScript Object Notation">JSON</abbr>'s, and <a href=../../../api/basic_json/accept/ ><code>json::accept()</code></a> takes 6% longer than Boost.<abbr title="JavaScript Object Notation">JSON</abbr> without number conversion (on x86-64, Boost.<abbr title="JavaScript Object Notation">JSON</abbr> validates in 0.65–0.69× and sums in 0.75–0.79× the time). <code>dump()</code> writes faster than Boost.<abbr title="JavaScript Object Notation">JSON</abbr>, RapidJSON and serde_json, and about as fast as Glaze.</p> <p>Much of Boost.<abbr title="JavaScript Object Notation">JSON</abbr>'s lead in building a tree comes from its allocator: here it builds the tree in a <code>monotonic_resource</code>, an arena that is freed in one go, which saves it 28–41%. With its default allocator, which allocates every string, array, and object on its own as <code>json</code> does, <code>boost::json::parse()</code> with precise numbers takes as long as <code>json::parse()</code> on <code>twitter.json</code>, 5% longer on <code>citm_catalog.json</code>, and 17% less time on <code>canada.json</code> (on the Mac, freeing the tree included).</p> <h3 id=results-on-x86-64>Results on x86-64<a class=headerlink href=#results-on-x86-64 title="Permanent link">&para;</a></h3> <p>On x86-64, the same programs ran on a virtual server with Ubuntu 26.04 whose <abbr title="Central Processing Unit">CPU</abbr> presents itself as Haswell, pinned to one core. We built them with <code>-march=haswell</code> and three compilers: the newest <abbr title="GNU Compiler Collection">GCC</abbr>, 16.2 (the figure below), <abbr title="GNU Compiler Collection">GCC</abbr> 13.4, and Clang 23 (both in <a href=#e-comparison-with-other-libraries>Appendix E</a>). The compiler matters less than one might think. On the Mac, <abbr title="GNU Compiler Collection">GCC</abbr> 16 and Clang 23 put the same library first in every column as Apple clang, and on x86-64, the three compilers disagree only about <em>sum</em>.</p> <div class=nj-fig-wrap> <p><svg class="nj-fig nj-charts nj-charts--blog nj-charts--heat" viewbox="0 0 784 510" role=img aria-labelledby="nj-blog-uc-x86-gcc nj-blog-uc-x86-gcc-d" xmlns=http://www.w3.org/2000/svg> <title id=nj-blog-uc-x86-gcc>Use cases: time of each library relative to the fastest, x86-64 with G&#8203;CC 16.2</title> <desc id=nj-blog-uc-x86-gcc-d>Table of relative times, libraries by use case. nlohmann/json json_document validate: 1.00; nlohmann/json json_document sum: 1.08; nlohmann/json json_document select: 1.00; nlohmann/json json_document edit: 1.00 (0.79 doing less, N); nlohmann/json json_document minify: 1.00 (0.80 doing less, N); nlohmann/json json_document write: 1.00 (0.64 doing less, N); yyjson validate: 1.94; yyjson sum: 1.14; yyjson select: 1.18; yyjson edit: 1.37; yyjson minify: 1.17 (0.95 doing less, N); yyjson write: 1.11; sonic-cpp validate: no fully validating way (2.32 doing less, U); sonic-cpp sum: no fully validating way (1.24 doing less, U); sonic-cpp select: no fully validating way (1.45 doing less, U); sonic-cpp edit: no fully validating way (1.21 doing less, U); sonic-cpp minify: no fully validating way (1.36 doing less, U); sonic-cpp write: 1.45; simdjson validate: 2.11; simdjson sum: 1.00; simdjson select: 1.27 (0.54 doing less, P); simdjson edit: n/a; simdjson minify: 1.54 (0.17 doing less, P); simdjson write: 2.10; sonic-rs (Rust) validate: 1.93; sonic-rs (Rust) sum: 1.13; sonic-rs (Rust) select: 1.34; sonic-rs (Rust) edit: 1.90; sonic-rs (Rust) minify: 1.71; sonic-rs (Rust) write: 2.04; Boost.J&#8203;SON validate: 1.99; Boost.J&#8203;SON sum: 1.27; Boost.J&#8203;SON select: 2.20; Boost.J&#8203;SON edit: 2.30; Boost.J&#8203;SON minify: 2.65; Boost.J&#8203;SON write: 2.36; simd-json (Rust) validate: 3.62; simd-json (Rust) sum: 1.91; simd-json (Rust) select: 2.56; simd-json (Rust) edit: 2.87; simd-json (Rust) minify: 3.35; simd-json (Rust) write: 2.32; RapidJSON validate: 3.71 (3.41 doing less, U); RapidJSON sum: 2.23 (2.09 doing less, U); RapidJSON select: 2.91 (2.73 doing less, U); RapidJSON edit: 2.41 (2.34 doing less, U); RapidJSON minify: 2.68 (2.42 doing less, U N); RapidJSON write: 2.97; serde_json (Rust) validate: 2.39 (2.14 doing less, U); serde_json (Rust) sum: 2.36; serde_json (Rust) select: 1.71; serde_json (Rust) edit: 4.53; serde_json (Rust) minify: 4.89; serde_json (Rust) write: 2.25; Glaze validate: 2.86; Glaze sum: 4.16; Glaze select: 1.79 (0.58 doing less, P); Glaze edit: 4.47; Glaze minify: 4.81 (0.78 doing less, P); Glaze write: 1.96; nlohmann/json json validate: 2.96; nlohmann/json json sum: 1.70; nlohmann/json json select: 7.12; nlohmann/json json edit: 3.83; nlohmann/json json minify: 4.79; nlohmann/json json write: 1.91.</desc> <text class=nj-charts-tick x=270 y=34>validate</text> <text class=nj-charts-tick x=362 y=34>sum</text> <text class=nj-charts-tick x=454 y=34>select</text> <text class=nj-charts-tick x=546 y=34>edit</text> <text class=nj-charts-tick x=638 y=34>minify</text> <text class=nj-charts-tick x=730 y=34>write</text> <text class="nj-charts-rowlabel nj-charts-name-json" x=216 y=66 text-anchor=end>nlohmann/json json_document</text> <g class=nj-heat-cell tabindex=0 data-tip="nlohmann/json json_document · validate
1.00× the time of the fastest library (fully validating)
way: accept
twitter.json: 258 µs
citm_catalog.json: 513 µs
canada.json: 934 µs
jeopardy.json: 34,514 µs"> <rect class=nj-heat-0 x=225 y=45 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=270 y=66 text-anchor=middle>1.00</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="nlohmann/json json_document · sum
1.08× the time of the fastest library (fully validating)
way: parse
twitter.json: 398 µs
citm_catalog.json: 972 µs
canada.json: 3,501 µs
jeopardy.json: 89,756 µs"> <rect class=nj-heat-0 x=317 y=45 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=362 y=66 text-anchor=middle>1.08</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="nlohmann/json json_document · select
1.00× the time of the fastest library (fully validating)
twitter.json: 333 µs · structs (from_json)
citm_catalog.json: 828 µs · parse
canada.json: 1,368 µs · parse
jeopardy.json: 89,876 µs · parse"> <rect class=nj-heat-0 x=409 y=45 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=454 y=66 text-anchor=middle>1.00</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="nlohmann/json json_document · edit
1.00× the time of the fastest library (fully validating)
way: editable
twitter.json: 536 µs
citm_catalog.json: 1,162 µs
canada.json: 5,567 µs
jeopardy.json: 192,323 µs"> <rect class=nj-heat-0 x=501 y=45 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=523.5 y=66 text-anchor=middle>1.00</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="nlohmann/json json_document · edit, checking less
0.79× the time of the fastest fully validating library
twitter.json: 530 µs · editable (source numbers) (validates fully)
citm_catalog.json: 1,149 µs · editable (source numbers) (validates fully)
canada.json: 2,188 µs · editable (source numbers) (validates fully)
jeopardy.json: 192,323 µs · editable (validates fully)
copies each number's text instead of formatting it (number_format::source)"> <rect class=nj-heat-0 x=547 y=45 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=568.5 y=60 text-anchor=middle>0.79</text> <text class="nj-charts-cell nj-charts-cell--small" x=568.5 y=73 text-anchor=middle>N</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="nlohmann/json json_document · minify
1.00× the time of the fastest library (fully validating)
way: parse + dump
twitter.json: 518 µs
citm_catalog.json: 1,045 µs
canada.json: 5,240 µs
jeopardy.json: 143,737 µs"> <rect class=nj-heat-0 x=593 y=45 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=615.5 y=66 text-anchor=middle>1.00</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="nlohmann/json json_document · minify, checking less
0.80× the time of the fastest fully validating library
twitter.json: 496 µs · parse + dump (source numbers) (validates fully)
citm_catalog.json: 1,045 µs · parse + dump (validates fully)
canada.json: 2,196 µs · parse + dump (source numbers) (validates fully)
jeopardy.json: 143,206 µs · parse + dump (source numbers) (validates fully)
copies each number's text instead of formatting it (number_format::source)"> <rect class=nj-heat-0 x=639 y=45 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=660.5 y=60 text-anchor=middle>0.80</text> <text class="nj-charts-cell nj-charts-cell--small" x=660.5 y=73 text-anchor=middle>N</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="nlohmann/json json_document · write
1.00× the time of the fastest library (fully validating)
way: dump
twitter.json: 156 µs
citm_catalog.json: 251 µs
canada.json: 3,842 µs
jeopardy.json: 67,769 µs"> <rect class=nj-heat-0 x=685 y=45 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=707.5 y=66 text-anchor=middle>1.00</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="nlohmann/json json_document · write, checking less
0.64× the time of the fastest fully validating library
way: dump (source numbers)
twitter.json: 140 µs (validates fully)
citm_catalog.json: 230 µs (validates fully)
canada.json: 823 µs (validates fully)
jeopardy.json: 65,376 µs (validates fully)
copies each number's text instead of formatting it (number_format::source)"> <rect class=nj-heat-0 x=731 y=45 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=752.5 y=60 text-anchor=middle>0.64</text> <text class="nj-charts-cell nj-charts-cell--small" x=752.5 y=73 text-anchor=middle>N</text> </g> <text class="nj-charts-rowlabel " x=216 y=102 text-anchor=end>yyjson</text> <g class=nj-heat-cell tabindex=0 data-tip="yyjson · validate
1.94× the time of the fastest library (fully validating)
twitter.json: 352 µs · insitu (copy untimed)
citm_catalog.json: 837 µs · insitu (copy untimed)
canada.json: 2,199 µs · read (raw numbers)
jeopardy.json: 93,043 µs · insitu (copy untimed)"> <rect class=nj-heat-2 x=225 y=81 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=270 y=102 text-anchor=middle>1.94</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="yyjson · sum
1.14× the time of the fastest library (fully validating)
way: insitu (copy untimed)
twitter.json: 415 µs
citm_catalog.json: 986 µs
canada.json: 3,818 µs
jeopardy.json: 97,586 µs"> <rect class=nj-heat-0 x=317 y=81 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=362 y=102 text-anchor=middle>1.14</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="yyjson · select
1.18× the time of the fastest library (fully validating)
twitter.json: 366 µs · insitu (copy untimed)
citm_catalog.json: 840 µs · insitu (copy untimed)
canada.json: 2,204 µs · read (raw numbers)
jeopardy.json: 96,172 µs · insitu (copy untimed)"> <rect class=nj-heat-1 x=409 y=81 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=454 y=102 text-anchor=middle>1.18</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="yyjson · edit
1.37× the time of the fastest library (fully validating)
way: insitu (copy untimed) + mut copy
twitter.json: 746 µs
citm_catalog.json: 1,526 µs
canada.json: 7,479 µs
jeopardy.json: 275,025 µs"> <rect class=nj-heat-1 x=501 y=81 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=546 y=102 text-anchor=middle>1.37</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="yyjson · minify
1.17× the time of the fastest library (fully validating)
twitter.json: 626 µs · insitu (copy) + write
citm_catalog.json: 1,160 µs · insitu (copy untimed) + write
canada.json: 6,701 µs · insitu (copy untimed) + write
jeopardy.json: 156,605 µs · insitu (copy untimed) + write
(copy): parses in place, on a copy of the input that is part of the time"> <rect class=nj-heat-1 x=593 y=81 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=615.5 y=102 text-anchor=middle>1.17</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="yyjson · minify, checking less
0.95× the time of the fastest fully validating library
twitter.json: 626 µs · insitu (copy) + write (validates fully)
citm_catalog.json: 1,160 µs · insitu (copy untimed) + write (validates fully)
canada.json: 2,901 µs · read (raw numbers) + write (validates fully)
jeopardy.json: 156,605 µs · insitu (copy untimed) + write (validates fully)
copies each number's text instead of formatting it (YYJSON_READ_NUMBER_AS_RAW)
(copy): parses in place, on a copy of the input that is part of the time"> <rect class=nj-heat-0 x=639 y=81 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=660.5 y=96 text-anchor=middle>0.95</text> <text class="nj-charts-cell nj-charts-cell--small" x=660.5 y=109 text-anchor=middle>N</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="yyjson · write
1.11× the time of the fastest library (fully validating)
way: write
twitter.json: 215 µs
citm_catalog.json: 319 µs
canada.json: 3,360 µs
jeopardy.json: 66,669 µs"> <rect class=nj-heat-0 x=685 y=81 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=730 y=102 text-anchor=middle>1.11</text> </g> <text class="nj-charts-rowlabel " x=216 y=138 text-anchor=end>sonic-cpp</text> <g class=nj-heat-cell tabindex=0 data-tip="sonic-cpp · validate, checking less
2.32× the time of the fastest fully validating library
way: Document
twitter.json: 403 µs
citm_catalog.json: 932 µs
canada.json: 3,349 µs
jeopardy.json: 98,511 µs
trusts U​TF-8: sonic-cpp 1.0.2 doesn't check it"> <rect class=nj-heat-2 x=225 y=117 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=270 y=132 text-anchor=middle>2.32</text> <text class="nj-charts-cell nj-charts-cell--small" x=270 y=145 text-anchor=middle>U</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="sonic-cpp · sum, checking less
1.24× the time of the fastest fully validating library
way: Document
twitter.json: 456 µs
citm_catalog.json: 1,115 µs
canada.json: 3,980 µs
jeopardy.json: 105,081 µs
trusts U​TF-8: sonic-cpp 1.0.2 doesn't check it"> <rect class=nj-heat-1 x=317 y=117 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=362 y=132 text-anchor=middle>1.24</text> <text class="nj-charts-cell nj-charts-cell--small" x=362 y=145 text-anchor=middle>U</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="sonic-cpp · select, checking less
1.45× the time of the fastest fully validating library
way: Document
twitter.json: 407 µs
citm_catalog.json: 948 µs
canada.json: 3,464 µs
jeopardy.json: 110,885 µs
trusts U​TF-8: sonic-cpp 1.0.2 doesn't check it"> <rect class=nj-heat-1 x=409 y=117 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=454 y=132 text-anchor=middle>1.45</text> <text class="nj-charts-cell nj-charts-cell--small" x=454 y=145 text-anchor=middle>U</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="sonic-cpp · edit, checking less
1.21× the time of the fastest fully validating library
way: Document
twitter.json: 620 µs
citm_catalog.json: 1,438 µs
canada.json: 8,495 µs
jeopardy.json: 186,078 µs
trusts U​TF-8: sonic-cpp 1.0.2 doesn't check it"> <rect class=nj-heat-1 x=501 y=117 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=546 y=132 text-anchor=middle>1.21</text> <text class="nj-charts-cell nj-charts-cell--small" x=546 y=145 text-anchor=middle>U</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="sonic-cpp · minify, checking less
1.36× the time of the fastest fully validating library
way: Document + Serialize
twitter.json: 675 µs
citm_catalog.json: 1,417 µs
canada.json: 8,958 µs
jeopardy.json: 164,630 µs
trusts U​TF-8: sonic-cpp 1.0.2 doesn't check it"> <rect class=nj-heat-1 x=593 y=117 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=638 y=132 text-anchor=middle>1.36</text> <text class="nj-charts-cell nj-charts-cell--small" x=638 y=145 text-anchor=middle>U</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="sonic-cpp · write
1.45× the time of the fastest library (fully validating)
way: Serialize
twitter.json: 249 µs
citm_catalog.json: 509 µs
canada.json: 5,074 µs
jeopardy.json: 69,916 µs"> <rect class=nj-heat-1 x=685 y=117 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=730 y=138 text-anchor=middle>1.45</text> </g> <text class="nj-charts-rowlabel " x=216 y=174 text-anchor=end>simdjson</text> <g class=nj-heat-cell tabindex=0 data-tip="simdjson · validate
2.11× the time of the fastest library (fully validating)
way: D​OM
twitter.json: 301 µs
citm_catalog.json: 695 µs
canada.json: 3,337 µs
jeopardy.json: 120,982 µs"> <rect class=nj-heat-2 x=225 y=153 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=270 y=174 text-anchor=middle>2.11</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="simdjson · sum
1.00× the time of the fastest library (fully validating)
way: On-Demand
twitter.json: 348 µs
citm_catalog.json: 805 µs
canada.json: 3,452 µs
jeopardy.json: 92,769 µs"> <rect class=nj-heat-0 x=317 y=153 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=362 y=174 text-anchor=middle>1.00</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="simdjson · select
1.27× the time of the fastest library (fully validating)
way: D​OM
twitter.json: 313 µs
citm_catalog.json: 699 µs
canada.json: 3,325 µs
jeopardy.json: 122,556 µs"> <rect class=nj-heat-1 x=409 y=153 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=431.5 y=174 text-anchor=middle>1.27</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="simdjson · select, checking less
0.54× the time of the fastest fully validating library
twitter.json: 180 µs · On-Demand
citm_catalog.json: 496 µs · On-Demand (key selectors)
canada.json: 690 µs · On-Demand (key selectors)
jeopardy.json: 48,272 µs · On-Demand (key selectors)
reads lazily: On-Demand reads only what you ask for and steps over the rest by matching brackets"> <rect class=nj-heat-0 x=455 y=153 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=476.5 y=168 text-anchor=middle>0.54</text> <text class="nj-charts-cell nj-charts-cell--small" x=476.5 y=181 text-anchor=middle>P</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="simdjson · edit
simdjson's documents are read-only: it has no A​PI to change a value and write the result"> <rect class=nj-heat-na x=501 y=153 width=90 height=34 rx=3 /> <text class=nj-charts-tick x=546 y=174>n/a</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="simdjson · minify
1.54× the time of the fastest library (fully validating)
way: D​OM + to_string
twitter.json: 714 µs
citm_catalog.json: 1,318 µs
canada.json: 9,135 µs
jeopardy.json: 269,597 µs"> <rect class=nj-heat-2 x=593 y=153 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=615.5 y=174 text-anchor=middle>1.54</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="simdjson · minify, checking less
0.17× the time of the fastest fully validating library
way: minify
twitter.json: 99.9 µs
citm_catalog.json: 278 µs
canada.json: 312 µs
jeopardy.json: 42,644 µs
simdjson::minify() only removes whitespace, without parsing the values"> <rect class=nj-heat-0 x=639 y=153 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=660.5 y=168 text-anchor=middle>0.17</text> <text class="nj-charts-cell nj-charts-cell--small" x=660.5 y=181 text-anchor=middle>P</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="simdjson · write
2.10× the time of the fastest library (fully validating)
way: to_string
twitter.json: 361 µs
citm_catalog.json: 614 µs
canada.json: 5,609 µs
jeopardy.json: 158,492 µs"> <rect class=nj-heat-2 x=685 y=153 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=730 y=174 text-anchor=middle>2.10</text> </g> <text class="nj-charts-rowlabel " x=216 y=210 text-anchor=end>sonic-rs (Rust)</text> <g class=nj-heat-cell tabindex=0 data-tip="sonic-rs (Rust) · validate
1.93× the time of the fastest library (fully validating)
way: IgnoredAny
twitter.json: 501 µs
citm_catalog.json: 970 µs
canada.json: 2,249 µs
jeopardy.json: 54,369 µs"> <rect class=nj-heat-2 x=225 y=189 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=270 y=210 text-anchor=middle>1.93</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="sonic-rs (Rust) · sum
1.13× the time of the fastest library (fully validating)
way: visitor
twitter.json: 501 µs
citm_catalog.json: 1,123 µs
canada.json: 4,397 µs
jeopardy.json: 59,583 µs"> <rect class=nj-heat-0 x=317 y=189 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=362 y=210 text-anchor=middle>1.13</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="sonic-rs (Rust) · select
1.34× the time of the fastest library (fully validating)
way: structs
twitter.json: 504 µs
citm_catalog.json: 1,033 µs
canada.json: 2,328 µs
jeopardy.json: 90,486 µs"> <rect class=nj-heat-1 x=409 y=189 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=454 y=210 text-anchor=middle>1.34</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="sonic-rs (Rust) · edit
1.90× the time of the fastest library (fully validating)
way: Value
twitter.json: 1,197 µs
citm_catalog.json: 2,389 µs
canada.json: 7,744 µs
jeopardy.json: 390,952 µs"> <rect class=nj-heat-2 x=501 y=189 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=546 y=210 text-anchor=middle>1.90</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="sonic-rs (Rust) · minify
1.71× the time of the fastest library (fully validating)
way: Value
twitter.json: 1,000 µs
citm_catalog.json: 2,097 µs
canada.json: 7,795 µs
jeopardy.json: 215,280 µs"> <rect class=nj-heat-2 x=593 y=189 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=638 y=210 text-anchor=middle>1.71</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="sonic-rs (Rust) · write
2.04× the time of the fastest library (fully validating)
way: Value
twitter.json: 434 µs
citm_catalog.json: 927 µs
canada.json: 3,987 µs
jeopardy.json: 109,176 µs"> <rect class=nj-heat-2 x=685 y=189 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=730 y=210 text-anchor=middle>2.04</text> </g> <text class="nj-charts-rowlabel " x=216 y=246 text-anchor=end>Boost.J&#8203;SON</text> <g class=nj-heat-cell tabindex=0 data-tip="Boost.J​SON · validate
1.99× the time of the fastest library (fully validating)
way: S​AX (numbers: none)
twitter.json: 690 µs
citm_catalog.json: 917 µs
canada.json: 1,676 µs
jeopardy.json: 62,781 µs"> <rect class=nj-heat-2 x=225 y=225 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=270 y=246 text-anchor=middle>1.99</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="Boost.J​SON · sum
1.27× the time of the fastest library (fully validating)
way: S​AX
twitter.json: 699 µs
citm_catalog.json: 957 µs
canada.json: 5,835 µs
jeopardy.json: 59,656 µs"> <rect class=nj-heat-1 x=317 y=225 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=362 y=246 text-anchor=middle>1.27</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="Boost.J​SON · select
2.20× the time of the fastest library (fully validating)
twitter.json: 887 µs · parse_into structs
citm_catalog.json: 1,270 µs · parse_into structs
canada.json: 7,292 µs · parse
jeopardy.json: 95,866 µs · parse_into structs"> <rect class=nj-heat-2 x=409 y=225 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=454 y=246 text-anchor=middle>2.20</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="Boost.J​SON · edit
2.30× the time of the fastest library (fully validating)
way: parse
twitter.json: 1,767 µs
citm_catalog.json: 2,493 µs
canada.json: 12,767 µs
jeopardy.json: 331,310 µs"> <rect class=nj-heat-2 x=501 y=225 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=546 y=246 text-anchor=middle>2.30</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="Boost.J​SON · minify
2.65× the time of the fastest library (fully validating)
way: parse + serialize
twitter.json: 1,974 µs
citm_catalog.json: 2,525 µs
canada.json: 12,748 µs
jeopardy.json: 314,299 µs"> <rect class=nj-heat-3 x=593 y=225 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=638 y=246 text-anchor=middle>2.65</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="Boost.J​SON · write
2.36× the time of the fastest library (fully validating)
way: serialize
twitter.json: 469 µs
citm_catalog.json: 830 µs
canada.json: 5,659 µs
jeopardy.json: 144,174 µs"> <rect class=nj-heat-2 x=685 y=225 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=730 y=246 text-anchor=middle>2.36</text> </g> <text class="nj-charts-rowlabel " x=216 y=282 text-anchor=end>simd-json (Rust)</text> <g class=nj-heat-cell tabindex=0 data-tip="simd-json (Rust) · validate
3.62× the time of the fastest library (fully validating)
way: tape (copy)
twitter.json: 567 µs
citm_catalog.json: 1,430 µs
canada.json: 4,359 µs
jeopardy.json: 207,551 µs
(copy): parses in place, on a copy of the input that is part of the time"> <rect class=nj-heat-3 x=225 y=261 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=270 y=282 text-anchor=middle>3.62</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="simd-json (Rust) · sum
1.91× the time of the fastest library (fully validating)
way: visitor (copy)
twitter.json: 681 µs
citm_catalog.json: 1,650 µs
canada.json: 5,083 µs
jeopardy.json: 210,185 µs
(copy): parses in place, on a copy of the input that is part of the time"> <rect class=nj-heat-2 x=317 y=261 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=362 y=282 text-anchor=middle>1.91</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="simd-json (Rust) · select
2.56× the time of the fastest library (fully validating)
way: structs (copy)
twitter.json: 679 µs
citm_catalog.json: 1,731 µs
canada.json: 5,144 µs
jeopardy.json: 239,164 µs
(copy): parses in place, on a copy of the input that is part of the time"> <rect class=nj-heat-3 x=409 y=261 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=454 y=282 text-anchor=middle>2.56</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="simd-json (Rust) · edit
2.87× the time of the fastest library (fully validating)
twitter.json: 1,862 µs · borrowed (copy)
citm_catalog.json: 4,194 µs · borrowed (copy)
canada.json: 14,896 µs · owned (copy)
jeopardy.json: 391,369 µs · borrowed (copy)
(copy): parses in place, on a copy of the input that is part of the time"> <rect class=nj-heat-3 x=501 y=261 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=546 y=282 text-anchor=middle>2.87</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="simd-json (Rust) · minify
3.35× the time of the fastest library (fully validating)
way: borrowed (copy)
twitter.json: 1,889 µs
citm_catalog.json: 4,196 µs
canada.json: 15,716 µs
jeopardy.json: 414,377 µs
(copy): parses in place, on a copy of the input that is part of the time"> <rect class=nj-heat-3 x=593 y=261 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=638 y=282 text-anchor=middle>3.35</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="simd-json (Rust) · write
2.32× the time of the fastest library (fully validating)
way: borrowed
twitter.json: 582 µs
citm_catalog.json: 800 µs
canada.json: 5,147 µs
jeopardy.json: 122,623 µs"> <rect class=nj-heat-2 x=685 y=261 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=730 y=282 text-anchor=middle>2.32</text> </g> <text class="nj-charts-rowlabel " x=216 y=318 text-anchor=end>RapidJSON</text> <g class=nj-heat-cell tabindex=0 data-tip="RapidJSON · validate
3.71× the time of the fastest library (fully validating)
twitter.json: 1,166 µs · insitu (copy untimed)
citm_catalog.json: 1,553 µs · S​AX (string stream, default precision)
canada.json: 3,875 µs · S​AX (string stream, default precision)
jeopardy.json: 114,704 µs · insitu (copy untimed)"> <rect class=nj-heat-3 x=225 y=297 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=247.5 y=318 text-anchor=middle>3.71</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="RapidJSON · validate, checking less
3.41× the time of the fastest fully validating library
twitter.json: 1,012 µs · insitu (copy untimed) (no encoding check)
citm_catalog.json: 1,434 µs · S​AX (default precision) (no encoding check)
canada.json: 3,875 µs · S​AX (string stream, default precision) (validates fully)
jeopardy.json: 102,635 µs · insitu (copy untimed) (no encoding check)
trusts U​TF-8: RapidJSON's default (kParseValidateEncodingFlag checks it)"> <rect class=nj-heat-3 x=271 y=297 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=292.5 y=312 text-anchor=middle>3.41</text> <text class="nj-charts-cell nj-charts-cell--small" x=292.5 y=325 text-anchor=middle>U</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="RapidJSON · sum
2.23× the time of the fastest library (fully validating)
twitter.json: 1,221 µs · insitu (copy untimed)
citm_catalog.json: 1,717 µs · S​AX (string stream)
canada.json: 9,435 µs · S​AX (string stream)
jeopardy.json: 112,158 µs · insitu (copy untimed)"> <rect class=nj-heat-2 x=317 y=297 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=339.5 y=318 text-anchor=middle>2.23</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="RapidJSON · sum, checking less
2.09× the time of the fastest fully validating library
twitter.json: 1,063 µs · insitu (copy untimed) (no encoding check)
citm_catalog.json: 1,635 µs · S​AX (string stream) (no encoding check)
canada.json: 9,368 µs · S​AX (string stream) (no encoding check)
jeopardy.json: 105,845 µs · insitu (copy untimed) (no encoding check)
trusts U​TF-8: RapidJSON's default (kParseValidateEncodingFlag checks it)"> <rect class=nj-heat-2 x=363 y=297 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=384.5 y=312 text-anchor=middle>2.09</text> <text class="nj-charts-cell nj-charts-cell--small" x=384.5 y=325 text-anchor=middle>U</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="RapidJSON · select
2.91× the time of the fastest library (fully validating)
twitter.json: 1,180 µs · insitu (copy untimed)
citm_catalog.json: 1,693 µs · insitu (copy untimed)
canada.json: 10,390 µs · Document (string stream)
jeopardy.json: 116,394 µs · insitu (copy untimed)"> <rect class=nj-heat-3 x=409 y=297 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=431.5 y=318 text-anchor=middle>2.91</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="RapidJSON · select, checking less
2.73× the time of the fastest fully validating library
twitter.json: 1,022 µs · insitu (copy untimed) (no encoding check)
citm_catalog.json: 1,648 µs · insitu (copy untimed) (no encoding check)
canada.json: 10,390 µs · Document (string stream) (validates fully)
jeopardy.json: 108,290 µs · insitu (copy untimed) (no encoding check)
trusts U​TF-8: RapidJSON's default (kParseValidateEncodingFlag checks it)"> <rect class=nj-heat-3 x=455 y=297 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=476.5 y=312 text-anchor=middle>2.73</text> <text class="nj-charts-cell nj-charts-cell--small" x=476.5 y=325 text-anchor=middle>U</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="RapidJSON · edit
2.41× the time of the fastest library (fully validating)
twitter.json: 1,865 µs · insitu (copy untimed)
citm_catalog.json: 2,616 µs · insitu (copy untimed)
canada.json: 18,812 µs · Document (string stream)
jeopardy.json: 245,724 µs · insitu (copy untimed)"> <rect class=nj-heat-2 x=501 y=297 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=523.5 y=318 text-anchor=middle>2.41</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="RapidJSON · edit, checking less
2.34× the time of the fastest fully validating library
twitter.json: 1,737 µs · insitu (copy untimed) (no encoding check)
citm_catalog.json: 2,595 µs · insitu (copy untimed) (no encoding check)
canada.json: 18,812 µs · Document (string stream) (validates fully)
jeopardy.json: 234,669 µs · insitu (copy untimed) (no encoding check)
trusts U​TF-8: RapidJSON's default (kParseValidateEncodingFlag checks it)"> <rect class=nj-heat-2 x=547 y=297 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=568.5 y=312 text-anchor=middle>2.34</text> <text class="nj-charts-cell nj-charts-cell--small" x=568.5 y=325 text-anchor=middle>U</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="RapidJSON · minify
2.68× the time of the fastest library (fully validating)
way: S​AX to Writer (string stream)
twitter.json: 1,949 µs
citm_catalog.json: 2,382 µs
canada.json: 19,548 µs
jeopardy.json: 231,979 µs"> <rect class=nj-heat-3 x=593 y=297 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=615.5 y=318 text-anchor=middle>2.68</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="RapidJSON · minify, checking less
2.42× the time of the fastest fully validating library
twitter.json: 1,880 µs · S​AX to Writer (string stream) (no encoding check)
citm_catalog.json: 2,314 µs · S​AX to Writer (string stream) (no encoding check)
canada.json: 14,400 µs · S​AX to Writer (raw numbers) (validates fully)
jeopardy.json: 224,249 µs · S​AX to Writer (string stream) (no encoding check)
trusts U​TF-8: RapidJSON's default (kParseValidateEncodingFlag checks it)
copies each number's text instead of formatting it (kParseNumbersAsStringsFlag)"> <rect class=nj-heat-2 x=639 y=297 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=660.5 y=312 text-anchor=middle>2.42</text> <text class="nj-charts-cell nj-charts-cell--small" x=660.5 y=325 text-anchor=middle>U N</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="RapidJSON · write
2.97× the time of the fastest library (fully validating)
way: Writer
twitter.json: 678 µs
citm_catalog.json: 979 µs
canada.json: 9,095 µs
jeopardy.json: 131,408 µs"> <rect class=nj-heat-3 x=685 y=297 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=730 y=318 text-anchor=middle>2.97</text> </g> <text class="nj-charts-rowlabel " x=216 y=354 text-anchor=end>serde_json (Rust)</text> <g class=nj-heat-cell tabindex=0 data-tip="serde_json (Rust) · validate
2.39× the time of the fastest library (fully validating)
way: from_utf8 + IgnoredAny
twitter.json: 624 µs
citm_catalog.json: 1,440 µs
canada.json: 2,406 µs
jeopardy.json: 64,720 µs"> <rect class=nj-heat-2 x=225 y=333 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=247.5 y=354 text-anchor=middle>2.39</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="serde_json (Rust) · validate, checking less
2.14× the time of the fastest fully validating library
way: IgnoredAny
twitter.json: 484 µs
citm_catalog.json: 1,370 µs
canada.json: 2,314 µs
jeopardy.json: 58,247 µs
trusts U​TF-8 in the strings it skips (from_slice); strings it reads are checked"> <rect class=nj-heat-2 x=271 y=333 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=292.5 y=348 text-anchor=middle>2.14</text> <text class="nj-charts-cell nj-charts-cell--small" x=292.5 y=361 text-anchor=middle>U</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="serde_json (Rust) · sum
2.36× the time of the fastest library (fully validating)
way: visitor
twitter.json: 1,311 µs
citm_catalog.json: 2,288 µs
canada.json: 7,127 µs
jeopardy.json: 129,497 µs"> <rect class=nj-heat-2 x=317 y=333 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=362 y=354 text-anchor=middle>2.36</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="serde_json (Rust) · select
1.71× the time of the fastest library (fully validating)
way: from_utf8 + structs
twitter.json: 701 µs
citm_catalog.json: 1,532 µs
canada.json: 2,529 µs
jeopardy.json: 107,316 µs"> <rect class=nj-heat-2 x=409 y=333 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=454 y=354 text-anchor=middle>1.71</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="serde_json (Rust) · edit
4.53× the time of the fastest library (fully validating)
way: Value
twitter.json: 4,042 µs
citm_catalog.json: 6,586 µs
canada.json: 16,631 µs
jeopardy.json: 632,766 µs"> <rect class=nj-heat-3 x=501 y=333 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=546 y=354 text-anchor=middle>4.53</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="serde_json (Rust) · minify
4.89× the time of the fastest library (fully validating)
way: Value
twitter.json: 4,012 µs
citm_catalog.json: 6,583 µs
canada.json: 17,306 µs
jeopardy.json: 509,702 µs"> <rect class=nj-heat-3 x=593 y=333 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=638 y=354 text-anchor=middle>4.89</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="serde_json (Rust) · write
2.25× the time of the fastest library (fully validating)
way: Value
twitter.json: 550 µs
citm_catalog.json: 887 µs
canada.json: 4,005 µs
jeopardy.json: 134,163 µs"> <rect class=nj-heat-2 x=685 y=333 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=730 y=354 text-anchor=middle>2.25</text> </g> <text class="nj-charts-rowlabel " x=216 y=390 text-anchor=end>Glaze</text> <g class=nj-heat-cell tabindex=0 data-tip="Glaze · validate
2.86× the time of the fastest library (fully validating)
way: validate_json
twitter.json: 712 µs
citm_catalog.json: 1,983 µs
canada.json: 2,625 µs
jeopardy.json: 76,759 µs"> <rect class=nj-heat-3 x=225 y=369 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=270 y=390 text-anchor=middle>2.86</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="Glaze · sum
4.16× the time of the fastest library (fully validating)
way: generic (double, strict)
twitter.json: 2,483 µs
citm_catalog.json: 4,413 µs
canada.json: 10,532 µs
jeopardy.json: 231,505 µs"> <rect class=nj-heat-3 x=317 y=369 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=362 y=390 text-anchor=middle>4.16</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="Glaze · select
1.79× the time of the fastest library (fully validating)
way: structs (validate_skipped)
twitter.json: 606 µs
citm_catalog.json: 2,476 µs
canada.json: 2,557 µs
jeopardy.json: 89,957 µs"> <rect class=nj-heat-2 x=409 y=369 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=431.5 y=390 text-anchor=middle>1.79</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="Glaze · select, checking less
0.58× the time of the fastest fully validating library
way: structs
twitter.json: 344 µs
citm_catalog.json: 402 µs
canada.json: 417 µs
jeopardy.json: 67,467 µs
reads into structs and steps over fields it doesn't know without checking them (validate_skipped checks them too)"> <rect class=nj-heat-0 x=455 y=369 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=476.5 y=384 text-anchor=middle>0.58</text> <text class="nj-charts-cell nj-charts-cell--small" x=476.5 y=397 text-anchor=middle>P</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="Glaze · edit
4.47× the time of the fastest library (fully validating)
way: generic (strict)
twitter.json: 3,389 µs
citm_catalog.json: 6,002 µs
canada.json: 21,598 µs
jeopardy.json: 607,767 µs"> <rect class=nj-heat-3 x=501 y=369 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=546 y=390 text-anchor=middle>4.47</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="Glaze · minify
4.81× the time of the fastest library (fully validating)
way: generic (strict)
twitter.json: 3,685 µs
citm_catalog.json: 5,942 µs
canada.json: 22,138 µs
jeopardy.json: 450,322 µs"> <rect class=nj-heat-3 x=593 y=369 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=615.5 y=390 text-anchor=middle>4.81</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="Glaze · minify, checking less
0.78× the time of the fastest fully validating library
way: minify_json
twitter.json: 442 µs
citm_catalog.json: 1,292 µs
canada.json: 2,726 µs
jeopardy.json: 97,377 µs
minify_json only removes whitespace, without parsing the values"> <rect class=nj-heat-0 x=639 y=369 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=660.5 y=384 text-anchor=middle>0.78</text> <text class="nj-charts-cell nj-charts-cell--small" x=660.5 y=397 text-anchor=middle>P</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="Glaze · write
1.96× the time of the fastest library (fully validating)
way: generic
twitter.json: 381 µs
citm_catalog.json: 730 µs
canada.json: 4,071 µs
jeopardy.json: 131,946 µs"> <rect class=nj-heat-2 x=685 y=369 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=730 y=390 text-anchor=middle>1.96</text> </g> <text class="nj-charts-rowlabel nj-charts-name-json" x=216 y=426 text-anchor=end>nlohmann/json json</text> <g class=nj-heat-cell tabindex=0 data-tip="nlohmann/json json · validate
2.96× the time of the fastest library (fully validating)
way: accept
twitter.json: 683 µs
citm_catalog.json: 1,419 µs
canada.json: 4,559 µs
jeopardy.json: 74,331 µs"> <rect class=nj-heat-3 x=225 y=405 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=270 y=426 text-anchor=middle>2.96</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="nlohmann/json json · sum
1.70× the time of the fastest library (fully validating)
way: sax
twitter.json: 814 µs
citm_catalog.json: 1,666 µs
canada.json: 5,690 µs
jeopardy.json: 97,414 µs"> <rect class=nj-heat-2 x=317 y=405 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=362 y=426 text-anchor=middle>1.70</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="nlohmann/json json · select
7.12× the time of the fastest library (fully validating)
twitter.json: 3,360 µs · structs (from_json)
citm_catalog.json: 5,268 µs · structs (from_json)
canada.json: 12,006 µs · structs (from_json)
jeopardy.json: 410,221 µs · parse"> <rect class=nj-heat-4 x=409 y=405 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=454 y=426 text-anchor=middle>7.12</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="nlohmann/json json · edit
3.83× the time of the fastest library (fully validating)
way: ordered_json
twitter.json: 2,832 µs
citm_catalog.json: 4,970 µs
canada.json: 15,806 µs
jeopardy.json: 647,704 µs"> <rect class=nj-heat-3 x=501 y=405 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=546 y=426 text-anchor=middle>3.83</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="nlohmann/json json · minify
4.79× the time of the fastest library (fully validating)
way: parse + dump
twitter.json: 4,196 µs
citm_catalog.json: 5,806 µs
canada.json: 16,626 µs
jeopardy.json: 529,560 µs"> <rect class=nj-heat-3 x=593 y=405 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=638 y=426 text-anchor=middle>4.79</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="nlohmann/json json · write
1.91× the time of the fastest library (fully validating)
way: dump
twitter.json: 444 µs
citm_catalog.json: 640 µs
canada.json: 4,089 µs
jeopardy.json: 117,316 µs"> <rect class=nj-heat-2 x=685 y=405 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=730 y=426 text-anchor=middle>1.91</text> </g> <text class="nj-charts-tick nj-charts-tick--l" x=8 y=472>time relative to the fastest fully validating library, less is better</text> <g><rect class=nj-heat-0 x=8 y=482 width=76 height=20 rx=3 /> <text class="nj-charts-cell nj-charts-cell--small" x=46 y=496 text-anchor=middle>below 1.15</text></g> <g><rect class=nj-heat-1 x=88 y=482 width=76 height=20 rx=3 /> <text class="nj-charts-cell nj-charts-cell--small" x=126 y=496 text-anchor=middle>1.15 to 1.5</text></g> <g><rect class=nj-heat-2 x=168 y=482 width=76 height=20 rx=3 /> <text class="nj-charts-cell nj-charts-cell--small" x=206 y=496 text-anchor=middle>1.5 to 2.5</text></g> <g><rect class=nj-heat-3 x=248 y=482 width=76 height=20 rx=3 /> <text class="nj-charts-cell nj-charts-cell--small" x=286 y=496 text-anchor=middle>2.5 to 5</text></g> <g><rect class=nj-heat-4 x=328 y=482 width=76 height=20 rx=3 /> <text class="nj-charts-cell nj-charts-cell--small" x=366 y=496 text-anchor=middle>5 and more</text></g> <rect class=nj-heat-na x=420 y=482 width=40 height=20 rx=3 /> <text class=nj-charts-tick x=440 y=496>n/a</text> <text class="nj-charts-tick nj-charts-tick--l" x=468 y=496>no A&#8203;PI for it</text> </svg></p> </div> <p class=nj-caption>The same comparison on the x86-64 server with <abbr title="GNU Compiler Collection">GCC</abbr> 16.2, with the same cells and halves as the figure above. Less is better; hover over or tap a cell for the times and the way. The figures for <abbr title="GNU Compiler Collection">GCC</abbr> 13 and Clang 23 are in <a href=#e-comparison-with-other-libraries>Appendix E</a>.</p> <p><code>json_document</code> has the lowest mean in five of the six columns with <abbr title="GNU Compiler Collection">GCC</abbr>, where simdjson is ahead in <em>sum</em>, and in all six with Clang. This machine is noisy, though: between two runs, a library's time relative to <code>json_document</code>'s moved by up to 9–10% (95th percentile; 2.5% on the Mac). So Clang's 7% lead in <em>sum</em> over sonic-rs is no result, and without <code>twitter.json</code>, sonic-rs is first. In <em>validate</em>, the next library takes 1.8–1.9× as long, or 1.6–1.7× if every library may reuse its parser, because validating no longer builds an index (theme <a class=nj-theme href=#theme-8 title="theme 8">8</a>). Behind those means, it loses on single files:</p> <ul> <li><strong>One pass over every value, with <abbr title="GNU Compiler Collection">GCC</abbr>.</strong> simdjson's On-Demand <abbr title="Application Programming Interface">API</abbr> sums all numbers of <code>twitter.json</code>, <code>citm_catalog.json</code>, and <code>canada.json</code> in 0.83–0.99× <code>json_document</code>'s time with <abbr title="GNU Compiler Collection">GCC</abbr> 16 (0.86–0.91× with <abbr title="GNU Compiler Collection">GCC</abbr> 13). With Clang, <code>json_document</code> is ahead there, except on <code>canada.json</code>, where yyjson, which converts the floats during the parse, is faster than converting them on access.</li> <li><strong>Fresh large documents.</strong> For the 56 MB <code>jeopardy.json</code>, a fresh document needs a fresh 52 MB index, and on Linux the page faults of that much new memory are a large part of the time: copying the file into fresh memory alone takes about 50% as long as <code>json_document</code>'s parse. Boost.<abbr title="JavaScript Object Notation">JSON</abbr>'s <abbr title="Simple API for XML">SAX</abbr> parser and sonic-rs, which build nothing, sum it in 0.66–0.72× the time. Reusing the document cuts <code>json_document</code>'s time by 40–43%, to 51–53 ms, less than sonic-rs's 60 ms. Validating needs no index: <code>json_document::accept()</code> takes 35 ms, and no library validates <code>jeopardy.json</code> faster, even reused (the next is simdjson's reused parser at 47–49 ms). On the Mac, a fresh document costs hardly more than a reused one.</li> <li><strong>Writing floats.</strong> yyjson writes <code>canada.json</code> in 0.87–0.97× the time (and Glaze, with <abbr title="GNU Compiler Collection">GCC</abbr> 13, in 0.96×), because <code>json_document</code> first converts most floats from their text. Writing the source text instead (<code>number_format::source</code>, the "N" half) avoids that.</li> <li><strong>simdjson's <abbr title="Document Object Model">DOM</abbr>.</strong> It selects from <code>citm_catalog.json</code> 16% faster with <abbr title="GNU Compiler Collection">GCC</abbr> 16 and 1–4% faster with <abbr title="GNU Compiler Collection">GCC</abbr> 13 and Clang 23, and from <code>twitter.json</code> 1–6% faster. Boost.<abbr title="JavaScript Object Notation">JSON</abbr>, Glaze, sonic-cpp, and yyjson are 1–3% ahead in a few more cells, which is within the noise.</li> </ul> <p>The full tables, with each library's variants, are in <a href=#e-comparison-with-other-libraries>Appendix E</a>.</p> <h3 id=files-and-checks-we-didnt-choose>Files and checks we didn't choose<a class=headerlink href=#files-and-checks-we-didnt-choose title="Permanent link">&para;</a></h3> <p>The four files are the ones 3.13.0 was tuned on, so we also ran <em>validate</em>, <em>sum</em>, <em>minify</em>, and <em>write</em> on the 19 other files of simdjson's <a href="https://github.com/simdjson/simdjson-data/tree/master/jsonexamples"><code>jsonexamples</code></a>. By geometric mean, <code>json_document</code> stays the fastest in <em>validate</em>, <em>minify</em>, and <em>write</em> on every compiler, and in <em>sum</em> with Clang and on the Mac; with <abbr title="GNU Compiler Collection">GCC</abbr>, simdjson sums in 0.86–0.87× its time. File by file, for <em>validate</em>:</p> <div class=nj-fig-wrap> <p><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 other library per file</title> <desc id=nj-blog-heldout-d>Dot plot per file, less is better; below 1.0 json_document is the fastest fully validating library. mesh: Mac 0.68, x86-64 0.44 (serde_json (Rust)); marine_ik: Mac 0.59, x86-64 0.64 (Boost.J&#8203;SON); semanticscholar-corpus: Mac 0.79, x86-64 0.65 (sonic-rs (Rust)); gsoc-2018: Mac 0.60, x86-64 0.66 (Boost.J&#8203;SON); twitter_api_compact_response: Mac 0.91, x86-64 0.70 (simdjson); twitterescaped: Mac 0.93, x86-64 0.76 (simdjson); numbers: Mac 0.67, x86-64 0.77 (Boost.J&#8203;SON); github_events: Mac 0.79, x86-64 0.77 (simdjson); update-center: Mac 0.88, x86-64 0.79 (simdjson); twitter_timeline: Mac 0.97, x86-64 0.80 (yyjson); twitter_api_response: Mac 0.93, x86-64 0.81 (simdjson); google_maps_api_compact_response: Mac 0.86, x86-64 0.81 (yyjson); repeat: Mac 0.65, x86-64 0.82 (simdjson); random: Mac 0.81, x86-64 0.88 (simdjson); apache_builds: Mac 1.08, x86-64 0.90 (simdjson); instruments: Mac 0.90, x86-64 0.92 (simdjson); mesh.pretty: Mac 0.86, x86-64 0.92 (Boost.J&#8203;SON); tree-pretty: Mac 0.93, x86-64 0.96 (simdjson); google_maps_api_response: Mac 0.93, x86-64 0.99 (simdjson).</desc> <line class=nj-charts-grid x1=262 y1=50 x2=262 y2=438 /> <text class=nj-charts-tick x=262 y=454>0.4&#215;</text> <line class=nj-charts-grid x1=291.867 y1=50 x2=291.867 y2=438 /> <text class=nj-charts-tick x=291.867 y=454>0.5&#215;</text> <line class=nj-charts-grid x1=321.733 y1=50 x2=321.733 y2=438 /> <text class=nj-charts-tick x=321.733 y=454>0.6&#215;</text> <line class=nj-charts-grid x1=351.6 y1=50 x2=351.6 y2=438 /> <text class=nj-charts-tick x=351.6 y=454>0.7&#215;</text> <line class=nj-charts-grid x1=381.467 y1=50 x2=381.467 y2=438 /> <text class=nj-charts-tick x=381.467 y=454>0.8&#215;</text> <line class=nj-charts-grid x1=411.333 y1=50 x2=411.333 y2=438 /> <text class=nj-charts-tick x=411.333 y=454>0.9&#215;</text> <line class=nj-charts-grid x1=441.2 y1=50 x2=441.2 y2=438 /> <text class=nj-charts-tick x=441.2 y=454>1.0&#215;</text> <line class=nj-charts-grid x1=471.067 y1=50 x2=471.067 y2=438 /> <text class=nj-charts-tick x=471.067 y=454>1.1&#215;</text> <text class=nj-charts-tick x=374 y=472>json&#95;document&#8217;s time / the fastest other 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>next on x86-64</text> <text class="nj-charts-rowlabel nj-charts-code" x=252 y=68 text-anchor=end>mesh</text> <circle class=nj-charts-json-dot cx=344.8 cy=60.5 r=4.5><title>mesh, Apple M1 Max: 0.68&#215; the time of Glaze</title></circle> <circle class=nj-charts-ojson-dot cx=273.6 cy=67.5 r=4.5><title>mesh, x86-64, G&#8203;CC 16.2: 0.44&#215; the time of serde&#95;json (Rust)</title></circle> <text class="nj-charts-tick nj-charts-tick--l" x=500 y=68>serde&#95;json (Rust)</text> <text class="nj-charts-rowlabel nj-charts-code" x=252 y=88 text-anchor=end>marine&#95;ik</text> <circle class=nj-charts-json-dot cx=319.5 cy=80.5 r=4.5><title>marine&#95;ik, Apple M1 Max: 0.59&#215; the time of Glaze</title></circle> <circle class=nj-charts-ojson-dot cx=334.2 cy=87.5 r=4.5><title>marine&#95;ik, x86-64, G&#8203;CC 16.2: 0.64&#215; the time of Boost.J&#8203;SON</title></circle> <text class="nj-charts-tick nj-charts-tick--l" x=500 y=88>Boost.J&#8203;SON</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=377.9 cy=100.5 r=4.5><title>semanticscholar-corpus, Apple M1 Max: 0.79&#215; the time of sonic-rs (Rust)</title></circle> <circle class=nj-charts-ojson-dot cx=336.0 cy=107.5 r=4.5><title>semanticscholar-corpus, x86-64, G&#8203;CC 16.2: 0.65&#215; the time of sonic-rs (Rust)</title></circle> <text class="nj-charts-tick nj-charts-tick--l" x=500 y=108>sonic-rs (Rust)</text> <text class="nj-charts-rowlabel nj-charts-code" x=252 y=128 text-anchor=end>gsoc-2018</text> <circle class=nj-charts-json-dot cx=322.9 cy=120.5 r=4.5><title>gsoc-2018, Apple M1 Max: 0.60&#215; the time of sonic-rs (Rust)</title></circle> <circle class=nj-charts-ojson-dot cx=338.8 cy=127.5 r=4.5><title>gsoc-2018, x86-64, G&#8203;CC 16.2: 0.66&#215; the time of Boost.J&#8203;SON</title></circle> <text class="nj-charts-tick nj-charts-tick--l" x=500 y=128>Boost.J&#8203;SON</text> <text class="nj-charts-rowlabel nj-charts-code" x=252 y=148 text-anchor=end>twitter&#95;api&#95;compact&#95;response</text> <circle class=nj-charts-json-dot cx=414.0 cy=140.5 r=4.5><title>twitter&#95;api&#95;compact&#95;response, Apple M1 Max: 0.91&#215; the time of yyjson</title></circle> <circle class=nj-charts-ojson-dot cx=352.1 cy=147.5 r=4.5><title>twitter&#95;api&#95;compact&#95;response, x86-64, G&#8203;CC 16.2: 0.70&#215; the time of simdjson</title></circle> <text class="nj-charts-tick nj-charts-tick--l" x=500 y=148>simdjson</text> <text class="nj-charts-rowlabel nj-charts-code" x=252 y=168 text-anchor=end>twitterescaped</text> <circle class=nj-charts-json-dot cx=419.5 cy=160.5 r=4.5><title>twitterescaped, Apple M1 Max: 0.93&#215; the time of yyjson</title></circle> <circle class=nj-charts-ojson-dot cx=370.8 cy=167.5 r=4.5><title>twitterescaped, x86-64, G&#8203;CC 16.2: 0.76&#215; the time of simdjson</title></circle> <text class="nj-charts-tick nj-charts-tick--l" x=500 y=168>simdjson</text> <text class="nj-charts-rowlabel nj-charts-code" x=252 y=188 text-anchor=end>numbers</text> <circle class=nj-charts-json-dot cx=343.3 cy=180.5 r=4.5><title>numbers, Apple M1 Max: 0.67&#215; the time of Boost.J&#8203;SON</title></circle> <circle class=nj-charts-ojson-dot cx=373.1 cy=187.5 r=4.5><title>numbers, x86-64, G&#8203;CC 16.2: 0.77&#215; the time of Boost.J&#8203;SON</title></circle> <text class="nj-charts-tick nj-charts-tick--l" x=500 y=188>Boost.J&#8203;SON</text> <text class="nj-charts-rowlabel nj-charts-code" x=252 y=208 text-anchor=end>github&#95;events</text> <circle class=nj-charts-json-dot cx=379.5 cy=200.5 r=4.5><title>github&#95;events, Apple M1 Max: 0.79&#215; the time of simdjson</title></circle> <circle class=nj-charts-ojson-dot cx=373.4 cy=207.5 r=4.5><title>github&#95;events, x86-64, G&#8203;CC 16.2: 0.77&#215; the time of simdjson</title></circle> <text class="nj-charts-tick nj-charts-tick--l" x=500 y=208>simdjson</text> <text class="nj-charts-rowlabel nj-charts-code" x=252 y=228 text-anchor=end>update-center</text> <circle class=nj-charts-json-dot cx=405.1 cy=220.5 r=4.5><title>update-center, Apple M1 Max: 0.88&#215; the time of sonic-rs (Rust)</title></circle> <circle class=nj-charts-ojson-dot cx=377.7 cy=227.5 r=4.5><title>update-center, x86-64, G&#8203;CC 16.2: 0.79&#215; the time of simdjson</title></circle> <text class="nj-charts-tick nj-charts-tick--l" x=500 y=228>simdjson</text> <text class="nj-charts-rowlabel nj-charts-code" x=252 y=248 text-anchor=end>twitter&#95;timeline</text> <circle class=nj-charts-json-dot cx=431.6 cy=240.5 r=4.5><title>twitter&#95;timeline, Apple M1 Max: 0.97&#215; the time of yyjson</title></circle> <circle class=nj-charts-ojson-dot cx=381.3 cy=247.5 r=4.5><title>twitter&#95;timeline, x86-64, G&#8203;CC 16.2: 0.80&#215; the time of yyjson</title></circle> <text class="nj-charts-tick nj-charts-tick--l" x=500 y=248>yyjson</text> <text class="nj-charts-rowlabel nj-charts-code" x=252 y=268 text-anchor=end>twitter&#95;api&#95;response</text> <circle class=nj-charts-json-dot cx=420.4 cy=260.5 r=4.5><title>twitter&#95;api&#95;response, Apple M1 Max: 0.93&#215; the time of simdjson</title></circle> <circle class=nj-charts-ojson-dot cx=384.1 cy=267.5 r=4.5><title>twitter&#95;api&#95;response, x86-64, G&#8203;CC 16.2: 0.81&#215; the time of simdjson</title></circle> <text class="nj-charts-tick nj-charts-tick--l" x=500 y=268>simdjson</text> <text class="nj-charts-rowlabel nj-charts-code" x=252 y=288 text-anchor=end>google&#95;maps&#95;api&#95;compact&#95;response</text> <circle class=nj-charts-json-dot cx=399.2 cy=280.5 r=4.5><title>google&#95;maps&#95;api&#95;compact&#95;response, Apple M1 Max: 0.86&#215; the time of yyjson</title></circle> <circle class=nj-charts-ojson-dot cx=384.2 cy=287.5 r=4.5><title>google&#95;maps&#95;api&#95;compact&#95;response, x86-64, G&#8203;CC 16.2: 0.81&#215; the time of yyjson</title></circle> <text class="nj-charts-tick nj-charts-tick--l" x=500 y=288>yyjson</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=336.7 cy=300.5 r=4.5><title>repeat, Apple M1 Max: 0.65&#215; the time of simdjson</title></circle> <circle class=nj-charts-ojson-dot cx=388.2 cy=307.5 r=4.5><title>repeat, x86-64, G&#8203;CC 16.2: 0.82&#215; the time of simdjson</title></circle> <text class="nj-charts-tick nj-charts-tick--l" 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=383.7 cy=320.5 r=4.5><title>random, Apple M1 Max: 0.81&#215; the time of simdjson</title></circle> <circle class=nj-charts-ojson-dot cx=404.9 cy=327.5 r=4.5><title>random, x86-64, G&#8203;CC 16.2: 0.88&#215; the time of simdjson</title></circle> <text class="nj-charts-tick nj-charts-tick--l" x=500 y=328>simdjson</text> <text class="nj-charts-rowlabel nj-charts-code" x=252 y=348 text-anchor=end>apache&#95;builds</text> <circle class=nj-charts-json-dot cx=463.6 cy=340.5 r=4.5><title>apache&#95;builds, Apple M1 Max: 1.08&#215; the time of simdjson</title></circle> <circle class=nj-charts-ojson-dot cx=412.4 cy=347.5 r=4.5><title>apache&#95;builds, x86-64, G&#8203;CC 16.2: 0.90&#215; the time of simdjson</title></circle> <text class="nj-charts-tick nj-charts-tick--l" x=500 y=348>simdjson</text> <text class="nj-charts-rowlabel nj-charts-code" x=252 y=368 text-anchor=end>instruments</text> <circle class=nj-charts-json-dot cx=412.5 cy=360.5 r=4.5><title>instruments, Apple M1 Max: 0.90&#215; the time of yyjson</title></circle> <circle class=nj-charts-ojson-dot cx=416.2 cy=367.5 r=4.5><title>instruments, x86-64, G&#8203;CC 16.2: 0.92&#215; the time of simdjson</title></circle> <text class="nj-charts-tick nj-charts-tick--l" x=500 y=368>simdjson</text> <text class="nj-charts-rowlabel nj-charts-code" x=252 y=388 text-anchor=end>mesh.pretty</text> <circle class=nj-charts-json-dot cx=398.9 cy=380.5 r=4.5><title>mesh.pretty, Apple M1 Max: 0.86&#215; the time of Glaze</title></circle> <circle class=nj-charts-ojson-dot cx=418.6 cy=387.5 r=4.5><title>mesh.pretty, x86-64, G&#8203;CC 16.2: 0.92&#215; the time of Boost.J&#8203;SON</title></circle> <text class="nj-charts-tick nj-charts-tick--l" x=500 y=388>Boost.J&#8203;SON</text> <text class="nj-charts-rowlabel nj-charts-code" x=252 y=408 text-anchor=end>tree-pretty</text> <circle class=nj-charts-json-dot cx=420.1 cy=400.5 r=4.5><title>tree-pretty, Apple M1 Max: 0.93&#215; the time of simdjson</title></circle> <circle class=nj-charts-ojson-dot cx=429.3 cy=407.5 r=4.5><title>tree-pretty, x86-64, G&#8203;CC 16.2: 0.96&#215; the time of simdjson</title></circle> <text class="nj-charts-tick nj-charts-tick--l" x=500 y=408>simdjson</text> <text class="nj-charts-rowlabel nj-charts-code" x=252 y=428 text-anchor=end>google&#95;maps&#95;api&#95;response</text> <circle class=nj-charts-json-dot cx=419.0 cy=420.5 r=4.5><title>google&#95;maps&#95;api&#95;response, Apple M1 Max: 0.93&#215; the time of simdjson</title></circle> <circle class=nj-charts-ojson-dot cx=439.0 cy=427.5 r=4.5><title>google&#95;maps&#95;api&#95;response, x86-64, G&#8203;CC 16.2: 0.99&#215; the time of simdjson</title></circle> <text class="nj-charts-tick nj-charts-tick--l" x=500 y=428>simdjson</text> <line class=nj-charts-ref x1=441.2 y1=50 x2=441.2 y2=438 /> <text class=nj-charts-tick x=441.2 y=44>as fast as the next</text> </svg></p> </div> <p class=nj-caption><em>validate</em> on the 19 files: <code>json_document</code>'s fastest fully validating way against the fastest other library's, per file; below 1.0× it is the fastest. Less is better. The right column names the next library on x86-64 (<abbr title="GNU Compiler Collection">GCC</abbr> 16.2).</p> <p><code>json_document</code> validates all 19 files fastest with <abbr title="GNU Compiler Collection">GCC</abbr> 16 and Clang 23, and 18 with <abbr title="GNU Compiler Collection">GCC</abbr> 13 and on the Mac: simdjson validates <code>apache_builds</code> 8% faster on the Mac and <code>google_maps_api_response</code> 2% faster with <abbr title="GNU Compiler Collection">GCC</abbr> 13. Before validating without an index (theme <a class=nj-theme href=#theme-8 title="theme 8">8</a>) and skipping fraction digits 16 bytes at a time (theme <a class=nj-theme href=#theme-2 title="theme 2">2</a>), Boost.<abbr title="JavaScript Object Notation">JSON</abbr> validated the number-heavy files up to 1.5× as fast on x86-64.</p> <p>The four probes are broken inputs that tell full validation from less (<a href=#e-comparison-with-other-libraries>Appendix E</a> lists them). As a further check, every <em>validate</em> way also ran the 318 files of <a href="https://github.com/nst/JSONTestSuite">JSONTestSuite</a>. <a href=#e-comparison-with-other-libraries>Appendix E</a> lists the exceptions, one of them ours. The suite also found that Glaze's generic reader accepts garbage after the value by default, so the figures use its strict option.</p> <p>We did not measure memory use, a <abbr title="Central Processing Unit">CPU</abbr> with AVX-512, <abbr title="Microsoft Visual C++">MSVC</abbr>, writing from structs, or streaming input.</p> <h2 id=what-didnt-work>What didn't work<a class=headerlink href=#what-didnt-work title="Permanent link">&para;</a></h2> <p>The pull requests record the ideas that measured worse, which is as useful as the ones that made it:</p> <table> <thead> <tr> <th>idea</th> <th>result</th> </tr> </thead> <tbody> <tr> <td>make every walk iterative</td> <td>up to 20% slower on ordinary documents</td> </tr> <tr> <td>move the key out of the lexer's reused buffer</td> <td>11.9% slower (later a win, see theme <a class=nj-theme href=#theme-4 title="theme 4">4</a>)</td> </tr> <tr> <td>inline <code>scan_literal()</code></td> <td>Clang's dispatch grew from 233 to 278 instructions and got slower</td> </tr> <tr> <td>short-string table for strings up to 64 bytes</td> <td>lost against 32</td> </tr> <tr> <td>leave the serializer's buffers uninitialized</td> <td>timings moved 18% apart in opposite directions on two similar workloads, so dropped; done later, when instruction counts showed 170 instructions saved per <code>dump()</code></td> </tr> <tr> <td>move the throws of the <abbr title="JavaScript Object Notation">JSON</abbr> Pointer lookups out of line too</td> <td>no measurable gain, dropped; they stay inline</td> </tr> <tr> <td><code>json_document</code>: an "all <abbr title="American Standard Code for Information Interchange">ASCII</abbr>" flag per string</td> <td><code>dump()</code> with <code>ensure_ascii</code> faster, but parsing 1–13% slower</td> </tr> <tr> <td><code>json_document</code>: convert floats while parsing</td> <td><code>canada.json</code> parse 36–90% slower</td> </tr> <tr> <td><code>json_document</code>: note a large object inline in the parse loop</td> <td><code>canada.json</code> 37% slower</td> </tr> <tr> <td><code>json_document</code>: vector-scan every string in <code>set()</code></td> <td>14–16% slower on 16-byte strings</td> </tr> </tbody> </table> <p class=nj-table-caption>Ideas that were measured and dropped. <a href=#h-pull-requests-by-theme>Appendix H</a> links the pull requests that tried them.</p> <h2 id=the-price>The price<a class=headerlink href=#the-price title="Permanent link">&para;</a></h2> <p>None of this is free at compile time. <code>json.hpp</code> grew from 25,526 to 46,630 lines (<code>json_view.hpp</code> is a separate header of 11,898 lines that you only pay for if you include it). To see what that means for a program, we compiled two small ones with both versions:</p> <ul> <li><code>count_numbers</code> reads <code>twitter.json</code> and adds up all of its numbers, like the <em>sum</em> use case in <a href=#six-use-cases>How it compares</a>;</li> <li><code>server_config</code> reads a configuration file into a struct with <code>to_json()</code> and <code>from_json()</code>, changes it, and writes it back with <code>dump(2)</code>.</li> </ul> <p>Each is one translation unit. We timed it with the 3.12.0 and the 3.13.0 header, and then with 3.13.0 as a precompiled header and as a C++20 module, in a debug build (<code>-O0</code>) and an optimized one (<code>-O2</code>):</p> <div class=nj-fig-wrap> <p><svg class="nj-fig nj-charts nj-charts--blog" viewbox="0 0 600 618" role=img aria-labelledby="nj-blog-price nj-blog-price-d" xmlns=http://www.w3.org/2000/svg> <title id=nj-blog-price>Compile time of two programs with 3.13.0, alone, with a precompiled header and as a module, compared with 3.12.0</title> <desc id=nj-blog-price-d>Horizontal bars of the change in compile time against 3.12.0, less is better. Apple clang 21, -O0 (debug), count_numbers, 3.13.0: +38%; Apple clang 21, -O0 (debug), count_numbers, 3.13.0, precompiled header: -28%; Apple clang 21, -O0 (debug), count_numbers, 3.13.0, module: -4%; Apple clang 21, -O0 (debug), server_config, 3.13.0: +34%; Apple clang 21, -O0 (debug), server_config, 3.13.0, precompiled header: -23%; Apple clang 21, -O0 (debug), server_config, 3.13.0, module: +2%; Apple clang 21, -O2, count_numbers, 3.13.0: +49%; Apple clang 21, -O2, count_numbers, 3.13.0, precompiled header: +5%; Apple clang 21, -O2, count_numbers, 3.13.0, module: +21%; Apple clang 21, -O2, server_config, 3.13.0: +45%; Apple clang 21, -O2, server_config, 3.13.0, precompiled header: +10%; Apple clang 21, -O2, server_config, 3.13.0, module: +24%; G&#8203;CC 16, -O0 (debug), count_numbers, 3.13.0: +62%; G&#8203;CC 16, -O0 (debug), count_numbers, 3.13.0, precompiled header: +10%; G&#8203;CC 16, -O0 (debug), count_numbers, 3.13.0, module: +8%; G&#8203;CC 16, -O0 (debug), server_config, 3.13.0: +47%; G&#8203;CC 16, -O0 (debug), server_config, 3.13.0, precompiled header: +14%; G&#8203;CC 16, -O0 (debug), server_config, 3.13.0, module: +15%; G&#8203;CC 16, -O2, count_numbers, 3.13.0: +58%; G&#8203;CC 16, -O2, count_numbers, 3.13.0, precompiled header: +28%; G&#8203;CC 16, -O2, count_numbers, 3.13.0, module: +25%; G&#8203;CC 16, -O2, server_config, 3.13.0: +51%; G&#8203;CC 16, -O2, server_config, 3.13.0, precompiled header: +28%; G&#8203;CC 16, -O2, server_config, 3.13.0, module: +30%.</desc> <rect class=nj-charts-c2 x=8 y=6 width=12 height=12 rx=3 /> <text class=nj-charts-leg x=26 y=16.5>3.13.0</text> <rect class=nj-charts-c1 x=97.2 y=6 width=12 height=12 rx=3 /> <text class=nj-charts-leg x=115.2 y=16.5>3.13.0, precompiled header</text> <rect class=nj-charts-c3 x=350.4 y=6 width=12 height=12 rx=3 /> <text class=nj-charts-leg x=368.4 y=16.5>3.13.0, module</text> <text class=nj-charts-tick x=320.833 y=46>as fast as 3.12.0</text> <text class=nj-charts-panel x=8 y=68>Apple clang 21, -O0 (debug)</text> <line class=nj-charts-grid x1=184.167 y1=74 x2=184.167 y2=170 /> <line class=nj-charts-grid x1=252.5 y1=74 x2=252.5 y2=170 /> <line class=nj-charts-grid x1=389.167 y1=74 x2=389.167 y2=170 /> <line class=nj-charts-grid x1=457.5 y1=74 x2=457.5 y2=170 /> <line class=nj-charts-grid x1=525.833 y1=74 x2=525.833 y2=170 /> <text class="nj-charts-rowlabel nj-charts-code" x=142 y=101 text-anchor=end>count_numbers</text> <path class=nj-charts-c2 d="M320.833 78 H446.667 Q450.667 78 450.667 82 V85 Q450.667 89 446.667 89 H320.833 Z"><title>count_numbers, Apple clang 21, -O0 (debug), 3.13.0: 1,320 ms against 955 ms with 3.12.0 (+38%)</title></path> <text class=nj-charts-val x=455.667 y=87.5>+38%</text> <path class=nj-charts-c1 d="M320.833 92 H229.167 Q225.167 92 225.167 96 V99 Q225.167 103 229.167 103 H320.833 Z"><title>count_numbers, Apple clang 21, -O0 (debug), 3.13.0, precompiled header: 688 ms against 955 ms with 3.12.0 (&#8722;28%)</title></path> <text class=nj-charts-val x=220.167 y=101.5 text-anchor=end>&#8722;28%</text> <path class=nj-charts-c3 d="M320.833 106 H311.167 Q307.167 106 307.167 110 V113 Q307.167 117 311.167 117 H320.833 Z"><title>count_numbers, Apple clang 21, -O0 (debug), 3.13.0, module: 918 ms against 955 ms with 3.12.0 (&#8722;4%)</title></path> <text class=nj-charts-val x=302.167 y=115.5 text-anchor=end>&#8722;4%</text> <text class="nj-charts-rowlabel nj-charts-code" x=142 y=150 text-anchor=end>server_config</text> <path class=nj-charts-c2 d="M320.833 127 H433 Q437 127 437 131 V134 Q437 138 433 138 H320.833 Z"><title>server_config, Apple clang 21, -O0 (debug), 3.13.0: 1,496 ms against 1,113 ms with 3.12.0 (+34%)</title></path> <text class=nj-charts-val x=442 y=136.5>+34%</text> <path class=nj-charts-c1 d="M320.833 141 H246.25 Q242.25 141 242.25 145 V148 Q242.25 152 246.25 152 H320.833 Z"><title>server_config, Apple clang 21, -O0 (debug), 3.13.0, precompiled header: 863 ms against 1,113 ms with 3.12.0 (&#8722;23%)</title></path> <text class=nj-charts-val x=237.25 y=150.5 text-anchor=end>&#8722;23%</text> <path class=nj-charts-c3 d="M320.833 155 H323.667 Q327.667 155 327.667 159 V162 Q327.667 166 323.667 166 H320.833 Z"><title>server_config, Apple clang 21, -O0 (debug), 3.13.0, module: 1,136 ms against 1,113 ms with 3.12.0 (+2%)</title></path> <text class=nj-charts-val x=332.667 y=164.5>+2%</text> <text class=nj-charts-panel x=8 y=198>Apple clang 21, -O2</text> <line class=nj-charts-grid x1=184.167 y1=204 x2=184.167 y2=300 /> <line class=nj-charts-grid x1=252.5 y1=204 x2=252.5 y2=300 /> <line class=nj-charts-grid x1=389.167 y1=204 x2=389.167 y2=300 /> <line class=nj-charts-grid x1=457.5 y1=204 x2=457.5 y2=300 /> <line class=nj-charts-grid x1=525.833 y1=204 x2=525.833 y2=300 /> <text class="nj-charts-rowlabel nj-charts-code" x=142 y=231 text-anchor=end>count_numbers</text> <path class=nj-charts-c2 d="M320.833 208 H484.25 Q488.25 208 488.25 212 V215 Q488.25 219 484.25 219 H320.833 Z"><title>count_numbers, Apple clang 21, -O2, 3.13.0: 2,081 ms against 1,393 ms with 3.12.0 (+49%)</title></path> <text class=nj-charts-val x=493.25 y=217.5>+49%</text> <path class=nj-charts-c1 d="M320.833 222 H333.917 Q337.917 222 337.917 226 V229 Q337.917 233 333.917 233 H320.833 Z"><title>count_numbers, Apple clang 21, -O2, 3.13.0, precompiled header: 1,458 ms against 1,393 ms with 3.12.0 (+5%)</title></path> <text class=nj-charts-val x=342.917 y=231.5>+5%</text> <path class=nj-charts-c3 d="M320.833 236 H388.583 Q392.583 236 392.583 240 V243 Q392.583 247 388.583 247 H320.833 Z"><title>count_numbers, Apple clang 21, -O2, 3.13.0, module: 1,685 ms against 1,393 ms with 3.12.0 (+21%)</title></path> <text class=nj-charts-val x=397.583 y=245.5>+21%</text> <text class="nj-charts-rowlabel nj-charts-code" x=142 y=280 text-anchor=end>server_config</text> <path class=nj-charts-c2 d="M320.833 257 H470.583 Q474.583 257 474.583 261 V264 Q474.583 268 470.583 268 H320.833 Z"><title>server_config, Apple clang 21, -O2, 3.13.0: 2,546 ms against 1,754 ms with 3.12.0 (+45%)</title></path> <text class=nj-charts-val x=479.583 y=266.5>+45%</text> <path class=nj-charts-c1 d="M320.833 271 H351 Q355 271 355 275 V278 Q355 282 351 282 H320.833 Z"><title>server_config, Apple clang 21, -O2, 3.13.0, precompiled header: 1,925 ms against 1,754 ms with 3.12.0 (+10%)</title></path> <text class=nj-charts-val x=360 y=280.5>+10%</text> <path class=nj-charts-c3 d="M320.833 285 H398.833 Q402.833 285 402.833 289 V292 Q402.833 296 398.833 296 H320.833 Z"><title>server_config, Apple clang 21, -O2, 3.13.0, module: 2,169 ms against 1,754 ms with 3.12.0 (+24%)</title></path> <text class=nj-charts-val x=407.833 y=294.5>+24%</text> <text class=nj-charts-panel x=8 y=328>G&#8203;CC 16, -O0 (debug)</text> <line class=nj-charts-grid x1=184.167 y1=334 x2=184.167 y2=430 /> <line class=nj-charts-grid x1=252.5 y1=334 x2=252.5 y2=430 /> <line class=nj-charts-grid x1=389.167 y1=334 x2=389.167 y2=430 /> <line class=nj-charts-grid x1=457.5 y1=334 x2=457.5 y2=430 /> <line class=nj-charts-grid x1=525.833 y1=334 x2=525.833 y2=430 /> <text class="nj-charts-rowlabel nj-charts-code" x=142 y=361 text-anchor=end>count_numbers</text> <path class=nj-charts-c2 d="M320.833 338 H528.667 Q532.667 338 532.667 342 V345 Q532.667 349 528.667 349 H320.833 Z"><title>count_numbers, G&#8203;CC 16, -O0 (debug), 3.13.0: 2,548 ms against 1,569 ms with 3.12.0 (+62%)</title></path> <text class=nj-charts-val x=537.667 y=347.5>+62%</text> <path class=nj-charts-c1 d="M320.833 352 H351 Q355 352 355 356 V359 Q355 363 351 363 H320.833 Z"><title>count_numbers, G&#8203;CC 16, -O0 (debug), 3.13.0, precompiled header: 1,725 ms against 1,569 ms with 3.12.0 (+10%)</title></path> <text class=nj-charts-val x=360 y=361.5>+10%</text> <path class=nj-charts-c3 d="M320.833 366 H344.167 Q348.167 366 348.167 370 V373 Q348.167 377 344.167 377 H320.833 Z"><title>count_numbers, G&#8203;CC 16, -O0 (debug), 3.13.0, module: 1,700 ms against 1,569 ms with 3.12.0 (+8%)</title></path> <text class=nj-charts-val x=353.167 y=375.5>+8%</text> <text class="nj-charts-rowlabel nj-charts-code" x=142 y=410 text-anchor=end>server_config</text> <path class=nj-charts-c2 d="M320.833 387 H477.417 Q481.417 387 481.417 391 V394 Q481.417 398 477.417 398 H320.833 Z"><title>server_config, G&#8203;CC 16, -O0 (debug), 3.13.0: 2,985 ms against 2,025 ms with 3.12.0 (+47%)</title></path> <text class=nj-charts-val x=486.417 y=396.5>+47%</text> <path class=nj-charts-c1 d="M320.833 401 H364.667 Q368.667 401 368.667 405 V408 Q368.667 412 364.667 412 H320.833 Z"><title>server_config, G&#8203;CC 16, -O0 (debug), 3.13.0, precompiled header: 2,302 ms against 2,025 ms with 3.12.0 (+14%)</title></path> <text class=nj-charts-val x=373.667 y=410.5>+14%</text> <path class=nj-charts-c3 d="M320.833 415 H368.083 Q372.083 415 372.083 419 V422 Q372.083 426 368.083 426 H320.833 Z"><title>server_config, G&#8203;CC 16, -O0 (debug), 3.13.0, module: 2,326 ms against 2,025 ms with 3.12.0 (+15%)</title></path> <text class=nj-charts-val x=377.083 y=424.5>+15%</text> <text class=nj-charts-panel x=8 y=458>G&#8203;CC 16, -O2</text> <line class=nj-charts-grid x1=184.167 y1=464 x2=184.167 y2=560 /> <line class=nj-charts-grid x1=252.5 y1=464 x2=252.5 y2=560 /> <line class=nj-charts-grid x1=389.167 y1=464 x2=389.167 y2=560 /> <line class=nj-charts-grid x1=457.5 y1=464 x2=457.5 y2=560 /> <line class=nj-charts-grid x1=525.833 y1=464 x2=525.833 y2=560 /> <text class="nj-charts-rowlabel nj-charts-code" x=142 y=491 text-anchor=end>count_numbers</text> <path class=nj-charts-c2 d="M320.833 468 H515 Q519 468 519 472 V475 Q519 479 515 479 H320.833 Z"><title>count_numbers, G&#8203;CC 16, -O2, 3.13.0: 3,702 ms against 2,336 ms with 3.12.0 (+58%)</title></path> <text class=nj-charts-val x=524 y=477.5>+58%</text> <path class=nj-charts-c1 d="M320.833 482 H412.5 Q416.5 482 416.5 486 V489 Q416.5 493 412.5 493 H320.833 Z"><title>count_numbers, G&#8203;CC 16, -O2, 3.13.0, precompiled header: 2,987 ms against 2,336 ms with 3.12.0 (+28%)</title></path> <text class=nj-charts-val x=421.5 y=491.5>+28%</text> <path class=nj-charts-c3 d="M320.833 496 H402.25 Q406.25 496 406.25 500 V503 Q406.25 507 402.25 507 H320.833 Z"><title>count_numbers, G&#8203;CC 16, -O2, 3.13.0, module: 2,913 ms against 2,336 ms with 3.12.0 (+25%)</title></path> <text class=nj-charts-val x=411.25 y=505.5>+25%</text> <text class="nj-charts-rowlabel nj-charts-code" x=142 y=540 text-anchor=end>server_config</text> <path class=nj-charts-c2 d="M320.833 517 H491.083 Q495.083 517 495.083 521 V524 Q495.083 528 491.083 528 H320.833 Z"><title>server_config, G&#8203;CC 16, -O2, 3.13.0: 4,714 ms against 3,122 ms with 3.12.0 (+51%)</title></path> <text class=nj-charts-val x=500.083 y=526.5>+51%</text> <path class=nj-charts-c1 d="M320.833 531 H412.5 Q416.5 531 416.5 535 V538 Q416.5 542 412.5 542 H320.833 Z"><title>server_config, G&#8203;CC 16, -O2, 3.13.0, precompiled header: 4,006 ms against 3,122 ms with 3.12.0 (+28%)</title></path> <text class=nj-charts-val x=421.5 y=540.5>+28%</text> <path class=nj-charts-c3 d="M320.833 545 H419.333 Q423.333 545 423.333 549 V552 Q423.333 556 419.333 556 H320.833 Z"><title>server_config, G&#8203;CC 16, -O2, 3.13.0, module: 4,055 ms against 3,122 ms with 3.12.0 (+30%)</title></path> <text class=nj-charts-val x=428.333 y=554.5>+30%</text> <line class=nj-charts-ref x1=320.833 y1=52 x2=320.833 y2=574 /> <text class=nj-charts-tick x=184.167 y=590>&#8722;40%</text> <text class=nj-charts-tick x=252.5 y=590>&#8722;20%</text> <text class=nj-charts-tick x=320.833 y=590>0</text> <text class=nj-charts-tick x=389.167 y=590>+20%</text> <text class=nj-charts-tick x=457.5 y=590>+40%</text> <text class=nj-charts-tick x=525.833 y=590>+60%</text> <text class=nj-charts-tick x=355 y=608>compile time compared with 3.12.0, less is better</text> </svg></p> </div> <p class=nj-caption>How much longer or shorter each program takes to compile than with 3.12.0, less is better: Apple clang 21 and <abbr title="GNU Compiler Collection">GCC</abbr> 16.2, <abbr title="Central Processing Unit">CPU</abbr> time of the compiler, median of 5 interleaved runs, C++20, Apple M1 Max. The one-off cost of building the precompiled header or the module is not included. Hover over a bar for the time in milliseconds; <a href=#g-how-we-measured>Appendix G</a> has all times, the programs, and the commands.</p> <p>3.13.0 takes 34–62% longer to compile these programs. A good part of that is reading the header, and a precompiled header or a module does that once instead of in every translation unit:</p> <ul> <li><strong>In debug builds,</strong> which are what you wait for while you edit, a precompiled 3.13.0 compiles faster than 3.12.0 with Apple clang, and within 8–15% of it with <abbr title="GNU Compiler Collection">GCC</abbr>.</li> <li><strong>In optimized builds,</strong> less of the increase goes away, because the optimizer still works through all the code a program instantiates. A precompiled header or a module wins back 41–91% of it.</li> <li><strong>The one-off cost</strong> is 1.0 s (Apple clang) or 2.6 s (<abbr title="GNU Compiler Collection">GCC</abbr>) to build the precompiled header, and 1.6 s or 2.5 s to build the module, once per set of compiler flags. A precompiled header pays for itself after two to four translation units, a module after three to five.</li> <li><strong>Modules have caveats.</strong> Apple clang needs <code>-fcxx-modules</code>, <a href=../../../features/modules/ >module support</a> still depends heavily on the compiler version, and macros don't cross a module boundary: with <code>import nlohmann.json;</code>, the <code>NLOHMANN_DEFINE_TYPE_*</code> macros aren't available, which is why <code>server_config</code> writes <code>to_json()</code> and <code>from_json()</code> by hand.</li> </ul> <p>The <a href=../../../integration/compile_times/ >compile-time page</a> measures these and the other options, such as including <code>&lt;nlohmann/json_fwd.hpp&gt;</code> in headers that only name <code>json</code>, and <a href=../../../api/macros/json_no_automatic_udls/ ><code>JSON_NO_AUTOMATIC_UDLS</code></a>. We did not measure binary size or peak memory.</p> <h2 id=summing-up>Summing up<a class=headerlink href=#summing-up title="Permanent link">&para;</a></h2> <p>Hardly any of the techniques in this post are new. What we think made the difference is their combination, under the conditions of a header-only C++11 library whose <abbr title="Application Programming Interface">API</abbr> and output had to stay the same.</p> <h2 id=thanks>Thanks<a class=headerlink href=#thanks title="Permanent link">&para;</a></h2> <p>Most of what is in this post was invented by other people.</p> <p><strong>Code we adapted.</strong> The library contains code adapted from these four projects. We use it under the <abbr title="Massachusetts Institute of Technology">MIT</abbr> License, and the source files that contain it carry the authors' copyright lines and say what was taken; the <a href="https://github.com/nlohmann/json#license">README</a> lists them too.</p> <ul> <li><a href="https://github.com/fastfloat/fast_float">fast_float</a> (Apache-2.0, <abbr title="Massachusetts Institute of Technology">MIT</abbr>, or <abbr title="Boost Software License">BSL</abbr>-1.0) by Daniel Lemire and contributors: the Eisel-Lemire algorithm, its table of powers of five, its digit comparison for long numbers, and its parsing of eight digits at a time (N. Mushtak and D. Lemire, <a href="https://arxiv.org/abs/2212.06644">"Fast number parsing without fallback"</a>, 2023). W. D. Clinger for the <a href="https://doi.org/10.1145/93542.93557">fast path</a>, M. Eisel for the algorithm.</li> <li><a href="https://github.com/vitaut/zmij">Żmij</a> (<abbr title="Massachusetts Institute of Technology">MIT</abbr>) by Victor Zverovich, with the digit conversion of Xiang JunBo, the <abbr title="Arm SIMD instruction set extension">NEON</abbr> sequence and compressed powers of ten of Dougall Johnson, and the SSE support of Tobias Schlüter: ported to C++11.</li> <li><a href="https://github.com/simdjson/simdjson">simdjson</a> (Apache-2.0 or <abbr title="Massachusetts Institute of Technology">MIT</abbr>) by Daniel Lemire, Geoff Langdale, John Keiser, and contributors: the "lookup4" <abbr title="Unicode Transformation Format">UTF</abbr>-8 check and its tables (J. Keiser and D. Lemire, <a href="https://arxiv.org/abs/2010.03090">"Validating <abbr title="Unicode Transformation Format">UTF</abbr>-8 In Less Than One Instruction Per Byte"</a>, 2021), in <code>json.hpp</code>'s lexer and in <code>json_view.hpp</code>.</li> <li><a href="https://github.com/ibireme/yyjson">yyjson</a> (<abbr title="Massachusetts Institute of Technology">MIT</abbr>) by YaoYuan: table-driven <code>\u</code> decoding and the unrolled checks at fixed offsets in <code>json_view.hpp</code>'s parser.</li> </ul> <p><strong>Ideas we took.</strong> From these we took the idea, not their code, in the order they appear above:</p> <ul> <li><a href="https://github.com/serde-rs/json">serde_json</a> (<abbr title="Massachusetts Institute of Technology">MIT</abbr> or Apache-2.0): deriving positions from the offset only on error.</li> <li>Sean Eron Anderson's <a href="https://graphics.stanford.edu/~seander/bithacks.html">Bit Twiddling Hacks</a> (snippets in the public domain): the zero-byte test behind every word-at-a-time scan.</li> <li><a href="https://github.com/stephenberry/glaze">Glaze</a> (<abbr title="Massachusetts Institute of Technology">MIT</abbr>): skipping indentation in 8-byte steps (<code>skip_matching_ws</code>).</li> <li><a href="https://sqlite.org">SQLite</a> (public domain): writing short strings with a table loop, as its <code>jsonAppendString()</code> does.</li> <li><a href="https://github.com/ijl/orjson">orjson</a> (Apache-2.0 or <abbr title="Massachusetts Institute of Technology">MIT</abbr>; its escape table <abbr title="Mozilla Public License">MPL</abbr>-2.0) and <a href="https://github.com/cloudwego/sonic-rs">sonic-rs</a> (Apache-2.0), from which orjson adapted it: escape sequences as fixed-size table rows (<code>QUOTE_TAB</code>).</li> <li><a href="https://github.com/simdjson/simdjson">simdjson</a>'s tape and <a href="https://github.com/ibireme/yyjson">yyjson</a>'s 16-byte immutable document: a flat index in document order instead of a tree.</li> <li><a href="https://github.com/boostorg/json">Boost.<abbr title="JavaScript Object Notation">JSON</abbr></a> (<abbr title="Boost Software License">BSL</abbr>-1.0): switching to a hash table for large objects.</li> <li><a href="https://github.com/Tencent/rapidjson">RapidJSON</a> (<abbr title="Massachusetts Institute of Technology">MIT</abbr>): recursion as the default, iterative parsing as an option.</li> </ul> <p>I thank the people who sent or shaped pull requests:</p> <ul> <li><a href="https://github.com/gregmarr">@gregmarr</a> reviewed most of them and suggested the sized-sentinel fast path, the peek design for exact stream positions, one <abbr title="Single Instruction, Multiple Data">SIMD</abbr> switch for the whole library, and the vector check of <code>json_view</code>'s strings on edit;</li> <li><a href="https://github.com/veselink1">@veselink1</a> and <a href="https://github.com/michaelsam94">@michaelsam94</a> wrote the allocator and exception-safety fixes for the destructor that 3.13.0 <a href="https://github.com/nlohmann/json/pull/5762">took over</a>; the non-recursive destructor itself goes back to <a href="https://github.com/nlohmann/json/pull/1436">a pull request</a> by <a href="https://github.com/nickaein">@nickaein</a> in 2019;</li> <li><a href="https://github.com/commit-msuyog">@commit-msuyog</a> gave the 128-bit multiplication behind Eisel-Lemire <abbr title="Microsoft Visual C++">MSVC</abbr> intrinsics;</li> <li><a href="https://github.com/ayush-singh-0601">@ayush-singh-0601</a> started the fix for deep values in the binary writers;</li> <li><a href="https://github.com/avionicharshit-byte">@avionicharshit-byte</a> made <code>diff()</code> linear for shrinking arrays;</li> <li><a href="https://github.com/mvanslobbe">@mvanslobbe</a> sped up the parser's separator check;</li> <li><a href="https://github.com/alexprabhat99">@alexprabhat99</a> removed the temporary values behind <abbr title="Concise Binary Object Representation">CBOR</abbr> and MessagePack object keys.</li> </ul> <p><code>twitter.json</code>, <code>citm_catalog.json</code> and <code>canada.json</code> come from Milo Yip's <a href="https://github.com/miloyip/nativejson-benchmark">nativejson-benchmark</a> (<abbr title="Massachusetts Institute of Technology">MIT</abbr>).</p> <h2 id=appendix>Appendix<a class=headerlink href=#appendix title="Permanent link">&para;</a></h2> <h3 id=a-test-files>A. Test files<a class=headerlink href=#a-test-files title="Permanent link">&para;</a></h3> <table> <thead> <tr> <th>file</th> <th style="text-align: right;">size</th> <th>what it is</th> <th>what makes it hard</th> </tr> </thead> <tbody> <tr> <td><code>twitter.json</code></td> <td style="text-align: right;">632 KB</td> <td>100 tweets from Twitter's search <abbr title="Application Programming Interface">API</abbr>, with their users</td> <td>strings: 58% of the bytes are keys and strings, 15% of the bytes are non-<abbr title="American Standard Code for Information Interchange">ASCII</abbr> (almost all of it Japanese text), and 13,345 keys</td> </tr> <tr> <td><code>citm_catalog.json</code></td> <td style="text-align: right;">1.7 MB</td> <td>a concert hall's catalog of events, performances and seat categories, in French</td> <td>structure: 21,388 small objects and arrays, 14,392 integers, keys that average 8 bytes, and 71% whitespace from indentation</td> </tr> <tr> <td><code>canada.json</code></td> <td style="text-align: right;">2.3 MB</td> <td>the outline of Canada in GeoJSON</td> <td>numbers: 111,080 floating-point coordinates, most with 16 or 17 significant digits, in 56,045 arrays, and almost no whitespace</td> </tr> <tr> <td><code>jeopardy.json</code></td> <td style="text-align: right;">56 MB</td> <td>216,930 Jeopardy! questions as one array of objects</td> <td>size: 1.5 million short strings in objects of 7 members; far larger than the <abbr title="Central Processing Unit">CPU</abbr> caches</td> </tr> </tbody> </table> <p class=nj-table-caption>The test files. The first three are from Milo Yip's <a href="https://github.com/miloyip/nativejson-benchmark">nativejson-benchmark</a>. The counts are of the parsed values; the share of whitespace, string, and non-<abbr title="American Standard Code for Information Interchange">ASCII</abbr> bytes is of the file as distributed. Several changes target the indentation of <code>citm_catalog.json</code>: in the timeline benchmark, a minified copy of it parses 1.9× as fast as with 3.12.0, against 3.4× for the file as distributed.</p> <h3 id=b-3120-against-3130>B. 3.12.0 against 3.13.0<a class=headerlink href=#b-3120-against-3130 title="Permanent link">&para;</a></h3> <p>The rows of the first chart:</p> <table> <thead> <tr> <th>workload</th> <th style="text-align: right;">3.12.0</th> <th style="text-align: right;">3.13.0</th> <th style="text-align: right;">speedup</th> <th style="text-align: right;">Intel</th> </tr> </thead> <tbody> <tr> <td><code>json::parse()</code> of <code>twitter.json</code></td> <td style="text-align: right;">3.30 ms</td> <td style="text-align: right;">1.05 ms</td> <td style="text-align: right;">3.1×</td> <td style="text-align: right;">2.6×</td> </tr> <tr> <td><code>json::parse()</code> of <code>citm_catalog.json</code></td> <td style="text-align: right;">7.56 ms</td> <td style="text-align: right;">1.78 ms</td> <td style="text-align: right;">4.3×</td> <td style="text-align: right;">3.5×</td> </tr> <tr> <td><code>json::parse()</code> of <code>canada.json</code></td> <td style="text-align: right;">15.5 ms</td> <td style="text-align: right;">4.63 ms</td> <td style="text-align: right;">3.4×</td> <td style="text-align: right;">6.1×</td> </tr> <tr> <td><code>json::parse()</code> of <code>canada.json</code>, indented by 4 spaces</td> <td style="text-align: right;">35.0 ms</td> <td style="text-align: right;">5.37 ms</td> <td style="text-align: right;">6.5×</td> <td style="text-align: right;">8.0×</td> </tr> <tr> <td><code>ordered_json::parse()</code> of <code>citm_catalog.json</code></td> <td style="text-align: right;">11.5 ms</td> <td style="text-align: right;">1.68 ms</td> <td style="text-align: right;">6.9×</td> <td style="text-align: right;">6.6×</td> </tr> <tr> <td><code>json::parse()</code> of <code>twitter.json</code> from an <code>std::ifstream</code></td> <td style="text-align: right;">3.43 ms</td> <td style="text-align: right;">1.37 ms</td> <td style="text-align: right;">2.5×</td> <td style="text-align: right;">2.3×</td> </tr> <tr> <td><code>json::parse()</code> of <code>citm_catalog.json</code> from a <code>FILE*</code></td> <td style="text-align: right;">36.0 ms</td> <td style="text-align: right;">7.58 ms</td> <td style="text-align: right;">4.7×</td> <td style="text-align: right;">5.7×</td> </tr> <tr> <td><code>json::accept()</code> of <code>citm_catalog.json</code></td> <td style="text-align: right;">6.53 ms</td> <td style="text-align: right;">0.923 ms</td> <td style="text-align: right;">7.1×</td> <td style="text-align: right;">8.4×</td> </tr> <tr> <td><code>dump()</code> of <code>twitter.json</code></td> <td style="text-align: right;">1.44 ms</td> <td style="text-align: right;">0.214 ms</td> <td style="text-align: right;">6.7×</td> <td style="text-align: right;">5.7×</td> </tr> <tr> <td><code>dump()</code> of <code>canada.json</code></td> <td style="text-align: right;">6.95 ms</td> <td style="text-align: right;">2.34 ms</td> <td style="text-align: right;">3.0×</td> <td style="text-align: right;">3.3×</td> </tr> <tr> <td><code>dump(4)</code> of <code>citm_catalog.json</code></td> <td style="text-align: right;">1.99 ms</td> <td style="text-align: right;">0.423 ms</td> <td style="text-align: right;">4.7×</td> <td style="text-align: right;">4.1×</td> </tr> <tr> <td><code>to_cbor()</code> of <code>twitter.json</code></td> <td style="text-align: right;">0.659 ms</td> <td style="text-align: right;">0.143 ms</td> <td style="text-align: right;">4.6×</td> <td style="text-align: right;">6.7×</td> </tr> <tr> <td><code>from_cbor()</code> of <code>twitter.json</code> from memory</td> <td style="text-align: right;">3.23 ms</td> <td style="text-align: right;">0.953 ms</td> <td style="text-align: right;">3.4×</td> <td style="text-align: right;">2.8×</td> </tr> <tr> <td><code>from_cbor()</code> of <code>twitter.json</code> from a <code>FILE*</code></td> <td style="text-align: right;">10.4 ms</td> <td style="text-align: right;">1.57 ms</td> <td style="text-align: right;">6.6×</td> <td style="text-align: right;">6.5×</td> </tr> <tr> <td><code>diff()</code> of <code>canada.json</code> with every eighth scalar changed</td> <td style="text-align: right;">39.8 ms</td> <td style="text-align: right;">3.80 ms</td> <td style="text-align: right;">10.5×</td> <td style="text-align: right;">11.2×</td> </tr> <tr> <td>iterating over every value of <code>canada.json</code></td> <td style="text-align: right;">0.897 ms</td> <td style="text-align: right;">0.328 ms</td> <td style="text-align: right;">2.7×</td> <td style="text-align: right;">2.0×</td> </tr> <tr> <td>copying <code>citm_catalog.json</code> and destroying the copy</td> <td style="text-align: right;">1.70 ms</td> <td style="text-align: right;">1.51 ms</td> <td style="text-align: right;">1.13×</td> <td style="text-align: right;">1.12×</td> </tr> <tr> <td><code>==</code> of <code>citm_catalog.json</code> and a copy</td> <td style="text-align: right;">0.280 ms</td> <td style="text-align: right;">0.263 ms</td> <td style="text-align: right;">1.06×</td> <td style="text-align: right;">0.95×</td> </tr> </tbody> </table> <p class=nj-table-caption>Time per call with 3.12.0 and 3.13.0, Google Benchmark suite on an Apple M1 Max, median of 8 runs; the speedup is the old time divided by the new one. The Intel column is the speedup on the Intel MacBook Pro of <a href=#g-how-we-measured>Appendix G</a>. The parse rows do not include destroying the result (the suite pauses the timer for that).</p> <details class=info> <summary>All 182 benchmarks of the suite</summary> <table> <thead> <tr> <th>benchmark</th> <th style="text-align: right;">3.12.0</th> <th style="text-align: right;">3.13.0</th> <th style="text-align: right;">speedup</th> <th style="text-align: right;">Intel</th> </tr> </thead> <tbody> <tr> <td><code>Accept/canada</code></td> <td style="text-align: right;">12.9 ms</td> <td style="text-align: right;">2.35 ms</td> <td style="text-align: right;">5.51×</td> <td style="text-align: right;">13×</td> </tr> <tr> <td><code>Accept/citm_catalog</code></td> <td style="text-align: right;">6.53 ms</td> <td style="text-align: right;">923 µs</td> <td style="text-align: right;">7.07×</td> <td style="text-align: right;">8.45×</td> </tr> <tr> <td><code>Accept/floats</code></td> <td style="text-align: right;">116 ms</td> <td style="text-align: right;">22.7 ms</td> <td style="text-align: right;">5.10×</td> <td style="text-align: right;">12.2×</td> </tr> <tr> <td><code>Accept/jeopardy</code></td> <td style="text-align: right;">221 ms</td> <td style="text-align: right;">59.3 ms</td> <td style="text-align: right;">3.72×</td> <td style="text-align: right;">6.64×</td> </tr> <tr> <td><code>Accept/signed_ints</code></td> <td style="text-align: right;">117 ms</td> <td style="text-align: right;">28.3 ms</td> <td style="text-align: right;">4.15×</td> <td style="text-align: right;">4.99×</td> </tr> <tr> <td><code>Accept/small_signed_ints</code></td> <td style="text-align: right;">57.5 ms</td> <td style="text-align: right;">18 ms</td> <td style="text-align: right;">3.19×</td> <td style="text-align: right;">3.90×</td> </tr> <tr> <td><code>Accept/twitter</code></td> <td style="text-align: right;">2.51 ms</td> <td style="text-align: right;">484 µs</td> <td style="text-align: right;">5.20×</td> <td style="text-align: right;">6.89×</td> </tr> <tr> <td><code>Accept/unsigned_ints</code></td> <td style="text-align: right;">116 ms</td> <td style="text-align: right;">29.7 ms</td> <td style="text-align: right;">3.91×</td> <td style="text-align: right;">4.95×</td> </tr> <tr> <td><code>BinaryToCbor/1024</code></td> <td style="text-align: right;">298 ns</td> <td style="text-align: right;">107 ns</td> <td style="text-align: right;">2.79×</td> <td style="text-align: right;">3.67×</td> </tr> <tr> <td><code>BinaryToCbor/128</code></td> <td style="text-align: right;">249 ns</td> <td style="text-align: right;">117 ns</td> <td style="text-align: right;">2.13×</td> <td style="text-align: right;">2.27×</td> </tr> <tr> <td><code>BinaryToCbor/16384</code></td> <td style="text-align: right;">952 ns</td> <td style="text-align: right;">414 ns</td> <td style="text-align: right;">2.30×</td> <td style="text-align: right;">3.46×</td> </tr> <tr> <td><code>BinaryToCbor/16</code></td> <td style="text-align: right;">245 ns</td> <td style="text-align: right;">49.6 ns</td> <td style="text-align: right;">4.93×</td> <td style="text-align: right;">6.33×</td> </tr> <tr> <td><code>BinaryToCbor/2048</code></td> <td style="text-align: right;">328 ns</td> <td style="text-align: right;">125 ns</td> <td style="text-align: right;">2.62×</td> <td style="text-align: right;">3.74×</td> </tr> <tr> <td><code>BinaryToCbor/256</code></td> <td style="text-align: right;">265 ns</td> <td style="text-align: right;">90.9 ns</td> <td style="text-align: right;">2.91×</td> <td style="text-align: right;">3.33×</td> </tr> <tr> <td><code>BinaryToCbor/32768</code></td> <td style="text-align: right;">1.54 µs</td> <td style="text-align: right;">803 ns</td> <td style="text-align: right;">1.92×</td> <td style="text-align: right;">2.11×</td> </tr> <tr> <td><code>BinaryToCbor/32</code></td> <td style="text-align: right;">252 ns</td> <td style="text-align: right;">50.4 ns</td> <td style="text-align: right;">4.99×</td> <td style="text-align: right;">6.24×</td> </tr> <tr> <td><code>BinaryToCbor/4096</code></td> <td style="text-align: right;">407 ns</td> <td style="text-align: right;">177 ns</td> <td style="text-align: right;">2.29×</td> <td style="text-align: right;">3.48×</td> </tr> <tr> <td><code>BinaryToCbor/512</code></td> <td style="text-align: right;">290 ns</td> <td style="text-align: right;">102 ns</td> <td style="text-align: right;">2.84×</td> <td style="text-align: right;">3.02×</td> </tr> <tr> <td><code>BinaryToCbor/64</code></td> <td style="text-align: right;">255 ns</td> <td style="text-align: right;">84.6 ns</td> <td style="text-align: right;">3.01×</td> <td style="text-align: right;">3.78×</td> </tr> <tr> <td><code>BinaryToCbor/8192</code></td> <td style="text-align: right;">514 ns</td> <td style="text-align: right;">256 ns</td> <td style="text-align: right;">2.01×</td> <td style="text-align: right;">3.30×</td> </tr> <tr> <td><code>BinaryToCbor/8</code></td> <td style="text-align: right;">248 ns</td> <td style="text-align: right;">49.4 ns</td> <td style="text-align: right;">5.01×</td> <td style="text-align: right;">6.18×</td> </tr> <tr> <td><code>Copy/canada</code></td> <td style="text-align: right;">3.78 ms</td> <td style="text-align: right;">2.93 ms</td> <td style="text-align: right;">1.29×</td> <td style="text-align: right;">1.17×</td> </tr> <tr> <td><code>Copy/citm_catalog</code></td> <td style="text-align: right;">1.7 ms</td> <td style="text-align: right;">1.51 ms</td> <td style="text-align: right;">1.13×</td> <td style="text-align: right;">1.12×</td> </tr> <tr> <td><code>Copy/twitter</code></td> <td style="text-align: right;">840 µs</td> <td style="text-align: right;">767 µs</td> <td style="text-align: right;">1.09×</td> <td style="text-align: right;">1.14×</td> </tr> <tr> <td><code>CopyAssign/canada</code></td> <td style="text-align: right;">3.86 ms</td> <td style="text-align: right;">2.94 ms</td> <td style="text-align: right;">1.31×</td> <td style="text-align: right;">1.19×</td> </tr> <tr> <td><code>CopyAssign/citm_catalog</code></td> <td style="text-align: right;">1.77 ms</td> <td style="text-align: right;">1.59 ms</td> <td style="text-align: right;">1.11×</td> <td style="text-align: right;">1.12×</td> </tr> <tr> <td><code>CopyAssign/twitter</code></td> <td style="text-align: right;">885 µs</td> <td style="text-align: right;">791 µs</td> <td style="text-align: right;">1.12×</td> <td style="text-align: right;">1.07×</td> </tr> <tr> <td><code>CopyOnly/canada</code></td> <td style="text-align: right;">1.6 ms</td> <td style="text-align: right;">1.58 ms</td> <td style="text-align: right;">1.02×</td> <td style="text-align: right;">1.00×</td> </tr> <tr> <td><code>CopyOnly/citm_catalog</code></td> <td style="text-align: right;">786 µs</td> <td style="text-align: right;">817 µs</td> <td style="text-align: right;">0.96×</td> <td style="text-align: right;">0.93×</td> </tr> <tr> <td><code>CopyOnly/twitter</code></td> <td style="text-align: right;">424 µs</td> <td style="text-align: right;">421 µs</td> <td style="text-align: right;">1.01×</td> <td style="text-align: right;">1.02×</td> </tr> <tr> <td><code>CopyRing/canada</code></td> <td style="text-align: right;">3.86 ms</td> <td style="text-align: right;">3 ms</td> <td style="text-align: right;">1.29×</td> <td style="text-align: right;">1.20×</td> </tr> <tr> <td><code>CopyRing/citm_catalog</code></td> <td style="text-align: right;">1.84 ms</td> <td style="text-align: right;">1.61 ms</td> <td style="text-align: right;">1.15×</td> <td style="text-align: right;">1.20×</td> </tr> <tr> <td><code>CopyRing/twitter</code></td> <td style="text-align: right;">952 µs</td> <td style="text-align: right;">818 µs</td> <td style="text-align: right;">1.16×</td> <td style="text-align: right;">1.15×</td> </tr> <tr> <td><code>DestroyOnly/canada</code></td> <td style="text-align: right;">2.22 ms</td> <td style="text-align: right;">1.4 ms</td> <td style="text-align: right;">1.58×</td> <td style="text-align: right;">1.32×</td> </tr> <tr> <td><code>DestroyOnly/citm_catalog</code></td> <td style="text-align: right;">926 µs</td> <td style="text-align: right;">711 µs</td> <td style="text-align: right;">1.30×</td> <td style="text-align: right;">1.20×</td> </tr> <tr> <td><code>DestroyOnly/twitter</code></td> <td style="text-align: right;">416 µs</td> <td style="text-align: right;">336 µs</td> <td style="text-align: right;">1.24×</td> <td style="text-align: right;">1.15×</td> </tr> <tr> <td><code>Diff/canada</code></td> <td style="text-align: right;">39.8 ms</td> <td style="text-align: right;">3.8 ms</td> <td style="text-align: right;">10.5×</td> <td style="text-align: right;">11.2×</td> </tr> <tr> <td><code>Diff/citm_catalog</code></td> <td style="text-align: right;">7.19 ms</td> <td style="text-align: right;">1.12 ms</td> <td style="text-align: right;">6.40×</td> <td style="text-align: right;">7.78×</td> </tr> <tr> <td><code>Diff/twitter</code></td> <td style="text-align: right;">5.11 ms</td> <td style="text-align: right;">661 µs</td> <td style="text-align: right;">7.73×</td> <td style="text-align: right;">8.79×</td> </tr> <tr> <td><code>Dump/canada / -</code></td> <td style="text-align: right;">6.95 ms</td> <td style="text-align: right;">2.34 ms</td> <td style="text-align: right;">2.98×</td> <td style="text-align: right;">3.34×</td> </tr> <tr> <td><code>Dump/canada / 4</code></td> <td style="text-align: right;">9.1 ms</td> <td style="text-align: right;">3.1 ms</td> <td style="text-align: right;">2.93×</td> <td style="text-align: right;">2.82×</td> </tr> <tr> <td><code>Dump/citm_catalog / -</code></td> <td style="text-align: right;">1.42 ms</td> <td style="text-align: right;">296 µs</td> <td style="text-align: right;">4.81×</td> <td style="text-align: right;">3.93×</td> </tr> <tr> <td><code>Dump/citm_catalog / 4</code></td> <td style="text-align: right;">1.99 ms</td> <td style="text-align: right;">423 µs</td> <td style="text-align: right;">4.70×</td> <td style="text-align: right;">4.09×</td> </tr> <tr> <td><code>Dump/floats / -</code></td> <td style="text-align: right;">64.3 ms</td> <td style="text-align: right;">23.8 ms</td> <td style="text-align: right;">2.71×</td> <td style="text-align: right;">2.50×</td> </tr> <tr> <td><code>Dump/floats / 4</code></td> <td style="text-align: right;">72.6 ms</td> <td style="text-align: right;">24.6 ms</td> <td style="text-align: right;">2.95×</td> <td style="text-align: right;">2.71×</td> </tr> <tr> <td><code>Dump/jeopardy / -</code></td> <td style="text-align: right;">207 ms</td> <td style="text-align: right;">31.7 ms</td> <td style="text-align: right;">6.51×</td> <td style="text-align: right;">3.75×</td> </tr> <tr> <td><code>Dump/jeopardy / 4</code></td> <td style="text-align: right;">228 ms</td> <td style="text-align: right;">35.4 ms</td> <td style="text-align: right;">6.45×</td> <td style="text-align: right;">2.61×</td> </tr> <tr> <td><code>Dump/signed_ints / -</code></td> <td style="text-align: right;">24.1 ms</td> <td style="text-align: right;">10.7 ms</td> <td style="text-align: right;">2.24×</td> <td style="text-align: right;">1.44×</td> </tr> <tr> <td><code>Dump/signed_ints / 4</code></td> <td style="text-align: right;">32.5 ms</td> <td style="text-align: right;">11.3 ms</td> <td style="text-align: right;">2.87×</td> <td style="text-align: right;">2.01×</td> </tr> <tr> <td><code>Dump/small_signed_ints / -</code></td> <td style="text-align: right;">18.1 ms</td> <td style="text-align: right;">8.12 ms</td> <td style="text-align: right;">2.23×</td> <td style="text-align: right;">1.81×</td> </tr> <tr> <td><code>Dump/small_signed_ints / 4</code></td> <td style="text-align: right;">25.5 ms</td> <td style="text-align: right;">8.81 ms</td> <td style="text-align: right;">2.90×</td> <td style="text-align: right;">2.21×</td> </tr> <tr> <td><code>Dump/twitter / -</code></td> <td style="text-align: right;">1.44 ms</td> <td style="text-align: right;">214 µs</td> <td style="text-align: right;">6.70×</td> <td style="text-align: right;">5.75×</td> </tr> <tr> <td><code>Dump/twitter / 4</code></td> <td style="text-align: right;">1.63 ms</td> <td style="text-align: right;">253 µs</td> <td style="text-align: right;">6.45×</td> <td style="text-align: right;">5.18×</td> </tr> <tr> <td><code>Dump/unsigned_ints / -</code></td> <td style="text-align: right;">24 ms</td> <td style="text-align: right;">8.12 ms</td> <td style="text-align: right;">2.95×</td> <td style="text-align: right;">1.58×</td> </tr> <tr> <td><code>Dump/unsigned_ints / 4</code></td> <td style="text-align: right;">32.3 ms</td> <td style="text-align: right;">8.59 ms</td> <td style="text-align: right;">3.76×</td> <td style="text-align: right;">2.30×</td> </tr> <tr> <td><code>Equal/canada</code></td> <td style="text-align: right;">474 µs</td> <td style="text-align: right;">349 µs</td> <td style="text-align: right;">1.36×</td> <td style="text-align: right;">1.38×</td> </tr> <tr> <td><code>Equal/citm_catalog</code></td> <td style="text-align: right;">280 µs</td> <td style="text-align: right;">263 µs</td> <td style="text-align: right;">1.06×</td> <td style="text-align: right;">0.95×</td> </tr> <tr> <td><code>Equal/twitter</code></td> <td style="text-align: right;">146 µs</td> <td style="text-align: right;">131 µs</td> <td style="text-align: right;">1.11×</td> <td style="text-align: right;">1.02×</td> </tr> <tr> <td><code>Flatten/canada</code></td> <td style="text-align: right;">29.4 ms</td> <td style="text-align: right;">11.1 ms</td> <td style="text-align: right;">2.65×</td> <td style="text-align: right;">2.68×</td> </tr> <tr> <td><code>Flatten/citm_catalog</code></td> <td style="text-align: right;">6.72 ms</td> <td style="text-align: right;">3.07 ms</td> <td style="text-align: right;">2.19×</td> <td style="text-align: right;">2.45×</td> </tr> <tr> <td><code>Flatten/twitter</code></td> <td style="text-align: right;">3.66 ms</td> <td style="text-align: right;">2.11 ms</td> <td style="text-align: right;">1.74×</td> <td style="text-align: right;">2.19×</td> </tr> <tr> <td><code>FlattenOrdered/citm_catalog</code></td> <td style="text-align: right;">262 ms</td> <td style="text-align: right;">1.43 ms</td> <td style="text-align: right;">184×</td> <td style="text-align: right;">185×</td> </tr> <tr> <td><code>FlattenOrdered/twitter</code></td> <td style="text-align: right;">51.3 ms</td> <td style="text-align: right;">890 µs</td> <td style="text-align: right;">57.6×</td> <td style="text-align: right;">46.1×</td> </tr> <tr> <td><code>FromBinaryBuffer/bjdata / canada</code></td> <td style="text-align: right;">8.82 ms</td> <td style="text-align: right;">4.17 ms</td> <td style="text-align: right;">2.12×</td> <td style="text-align: right;">2.02×</td> </tr> <tr> <td><code>FromBinaryBuffer/bjdata / twitter</code></td> <td style="text-align: right;">3.32 ms</td> <td style="text-align: right;">976 µs</td> <td style="text-align: right;">3.40×</td> <td style="text-align: right;">2.87×</td> </tr> <tr> <td><code>FromBinaryBuffer/bjdata_optimized / canada</code></td> <td style="text-align: right;">9.24 ms</td> <td style="text-align: right;">2.48 ms</td> <td style="text-align: right;">3.73×</td> <td style="text-align: right;">3.51×</td> </tr> <tr> <td><code>FromBinaryBuffer/bjdata_optimized / twitter</code></td> <td style="text-align: right;">3.31 ms</td> <td style="text-align: right;">986 µs</td> <td style="text-align: right;">3.35×</td> <td style="text-align: right;">2.86×</td> </tr> <tr> <td><code>FromBinaryBuffer/bson / canada</code></td> <td style="text-align: right;">10 ms</td> <td style="text-align: right;">4.32 ms</td> <td style="text-align: right;">2.33×</td> <td style="text-align: right;">2.20×</td> </tr> <tr> <td><code>FromBinaryBuffer/bson / citm_catalog</code></td> <td style="text-align: right;">4.08 ms</td> <td style="text-align: right;">1.61 ms</td> <td style="text-align: right;">2.54×</td> <td style="text-align: right;">2.59×</td> </tr> <tr> <td><code>FromBinaryBuffer/bson / twitter</code></td> <td style="text-align: right;">3.26 ms</td> <td style="text-align: right;">937 µs</td> <td style="text-align: right;">3.48×</td> <td style="text-align: right;">3.08×</td> </tr> <tr> <td><code>FromBinaryBuffer/cbor / canada</code></td> <td style="text-align: right;">8.9 ms</td> <td style="text-align: right;">2.12 ms</td> <td style="text-align: right;">4.21×</td> <td style="text-align: right;">3.86×</td> </tr> <tr> <td><code>FromBinaryBuffer/cbor / citm_catalog</code></td> <td style="text-align: right;">3.94 ms</td> <td style="text-align: right;">1.45 ms</td> <td style="text-align: right;">2.71×</td> <td style="text-align: right;">2.81×</td> </tr> <tr> <td><code>FromBinaryBuffer/cbor / floats</code></td> <td style="text-align: right;">30.5 ms</td> <td style="text-align: right;">5.48 ms</td> <td style="text-align: right;">5.56×</td> <td style="text-align: right;">3.64×</td> </tr> <tr> <td><code>FromBinaryBuffer/cbor / jeopardy</code></td> <td style="text-align: right;">373 ms</td> <td style="text-align: right;">115 ms</td> <td style="text-align: right;">3.25×</td> <td style="text-align: right;">3.43×</td> </tr> <tr> <td><code>FromBinaryBuffer/cbor / signed_ints</code></td> <td style="text-align: right;">36.7 ms</td> <td style="text-align: right;">9.89 ms</td> <td style="text-align: right;">3.71×</td> <td style="text-align: right;">2.37×</td> </tr> <tr> <td><code>FromBinaryBuffer/cbor / twitter</code></td> <td style="text-align: right;">3.23 ms</td> <td style="text-align: right;">953 µs</td> <td style="text-align: right;">3.39×</td> <td style="text-align: right;">2.83×</td> </tr> <tr> <td><code>FromBinaryBuffer/msgpack / canada</code></td> <td style="text-align: right;">8.86 ms</td> <td style="text-align: right;">2.12 ms</td> <td style="text-align: right;">4.17×</td> <td style="text-align: right;">3.92×</td> </tr> <tr> <td><code>FromBinaryBuffer/msgpack / citm_catalog</code></td> <td style="text-align: right;">3.85 ms</td> <td style="text-align: right;">1.45 ms</td> <td style="text-align: right;">2.65×</td> <td style="text-align: right;">2.94×</td> </tr> <tr> <td><code>FromBinaryBuffer/msgpack / jeopardy</code></td> <td style="text-align: right;">373 ms</td> <td style="text-align: right;">111 ms</td> <td style="text-align: right;">3.36×</td> <td style="text-align: right;">3.51×</td> </tr> <tr> <td><code>FromBinaryBuffer/msgpack / twitter</code></td> <td style="text-align: right;">3.24 ms</td> <td style="text-align: right;">955 µs</td> <td style="text-align: right;">3.39×</td> <td style="text-align: right;">3.02×</td> </tr> <tr> <td><code>FromBinaryBuffer/ubjson / canada</code></td> <td style="text-align: right;">8.84 ms</td> <td style="text-align: right;">4.2 ms</td> <td style="text-align: right;">2.10×</td> <td style="text-align: right;">2.13×</td> </tr> <tr> <td><code>FromBinaryBuffer/ubjson / citm_catalog</code></td> <td style="text-align: right;">4.07 ms</td> <td style="text-align: right;">1.79 ms</td> <td style="text-align: right;">2.28×</td> <td style="text-align: right;">2.44×</td> </tr> <tr> <td><code>FromBinaryBuffer/ubjson / jeopardy</code></td> <td style="text-align: right;">379 ms</td> <td style="text-align: right;">117 ms</td> <td style="text-align: right;">3.24×</td> <td style="text-align: right;">3.40×</td> </tr> <tr> <td><code>FromBinaryBuffer/ubjson / twitter</code></td> <td style="text-align: right;">3.3 ms</td> <td style="text-align: right;">981 µs</td> <td style="text-align: right;">3.36×</td> <td style="text-align: right;">2.90×</td> </tr> <tr> <td><code>FromBinaryBuffer/ubjson_optimized / canada</code></td> <td style="text-align: right;">8.89 ms</td> <td style="text-align: right;">2.43 ms</td> <td style="text-align: right;">3.66×</td> <td style="text-align: right;">3.67×</td> </tr> <tr> <td><code>FromBinaryBuffer/ubjson_optimized / twitter</code></td> <td style="text-align: right;">3.3 ms</td> <td style="text-align: right;">975 µs</td> <td style="text-align: right;">3.38×</td> <td style="text-align: right;">2.88×</td> </tr> <tr> <td><code>FromBinaryFile/bjdata / twitter</code></td> <td style="text-align: right;">10.9 ms</td> <td style="text-align: right;">1.95 ms</td> <td style="text-align: right;">5.61×</td> <td style="text-align: right;">5.89×</td> </tr> <tr> <td><code>FromBinaryFile/bson / twitter</code></td> <td style="text-align: right;">10.7 ms</td> <td style="text-align: right;">1.85 ms</td> <td style="text-align: right;">5.80×</td> <td style="text-align: right;">6.21×</td> </tr> <tr> <td><code>FromBinaryFile/cbor / canada</code></td> <td style="text-align: right;">14.9 ms</td> <td style="text-align: right;">4.49 ms</td> <td style="text-align: right;">3.32×</td> <td style="text-align: right;">3.68×</td> </tr> <tr> <td><code>FromBinaryFile/cbor / twitter</code></td> <td style="text-align: right;">10.4 ms</td> <td style="text-align: right;">1.57 ms</td> <td style="text-align: right;">6.59×</td> <td style="text-align: right;">6.46×</td> </tr> <tr> <td><code>FromBinaryFile/ubjson / canada</code></td> <td style="text-align: right;">14.3 ms</td> <td style="text-align: right;">6.43 ms</td> <td style="text-align: right;">2.23×</td> <td style="text-align: right;">2.50×</td> </tr> <tr> <td><code>FromBinaryFile/ubjson / twitter</code></td> <td style="text-align: right;">10.9 ms</td> <td style="text-align: right;">1.97 ms</td> <td style="text-align: right;">5.54×</td> <td style="text-align: right;">5.90×</td> </tr> <tr> <td><code>FromBinaryShape/containers / bjdata</code></td> <td style="text-align: right;">14.7 ms</td> <td style="text-align: right;">7.23 ms</td> <td style="text-align: right;">2.03×</td> <td style="text-align: right;">2.05×</td> </tr> <tr> <td><code>FromBinaryShape/containers / bson</code></td> <td style="text-align: right;">17.6 ms</td> <td style="text-align: right;">7.89 ms</td> <td style="text-align: right;">2.23×</td> <td style="text-align: right;">2.20×</td> </tr> <tr> <td><code>FromBinaryShape/containers / cbor</code></td> <td style="text-align: right;">14.6 ms</td> <td style="text-align: right;">4.16 ms</td> <td style="text-align: right;">3.52×</td> <td style="text-align: right;">3.49×</td> </tr> <tr> <td><code>FromBinaryShape/containers / msgpack</code></td> <td style="text-align: right;">14.6 ms</td> <td style="text-align: right;">3.89 ms</td> <td style="text-align: right;">3.75×</td> <td style="text-align: right;">3.52×</td> </tr> <tr> <td><code>FromBinaryShape/containers / ubjson_optimized</code></td> <td style="text-align: right;">15.5 ms</td> <td style="text-align: right;">4.56 ms</td> <td style="text-align: right;">3.40×</td> <td style="text-align: right;">3.34×</td> </tr> <tr> <td><code>FromBinaryShape/containers / ubjson</code></td> <td style="text-align: right;">15 ms</td> <td style="text-align: right;">7.24 ms</td> <td style="text-align: right;">2.07×</td> <td style="text-align: right;">2.03×</td> </tr> <tr> <td><code>FromBinaryShape/nested / bjdata</code></td> <td style="text-align: right;">96.8 µs</td> <td style="text-align: right;">38.3 µs</td> <td style="text-align: right;">2.53×</td> <td style="text-align: right;">2.50×</td> </tr> <tr> <td><code>FromBinaryShape/nested / bson</code></td> <td style="text-align: right;">101 µs</td> <td style="text-align: right;">42.6 µs</td> <td style="text-align: right;">2.38×</td> <td style="text-align: right;">2.42×</td> </tr> <tr> <td><code>FromBinaryShape/nested / cbor</code></td> <td style="text-align: right;">94.9 µs</td> <td style="text-align: right;">35.8 µs</td> <td style="text-align: right;">2.65×</td> <td style="text-align: right;">2.57×</td> </tr> <tr> <td><code>FromBinaryShape/nested / msgpack</code></td> <td style="text-align: right;">92.6 µs</td> <td style="text-align: right;">35.1 µs</td> <td style="text-align: right;">2.64×</td> <td style="text-align: right;">2.60×</td> </tr> <tr> <td><code>FromBinaryShape/nested / ubjson</code></td> <td style="text-align: right;">96.1 µs</td> <td style="text-align: right;">38.3 µs</td> <td style="text-align: right;">2.51×</td> <td style="text-align: right;">2.50×</td> </tr> <tr> <td><code>FromBinaryShape/scalars / bjdata</code></td> <td style="text-align: right;">25.3 ms</td> <td style="text-align: right;">11.6 ms</td> <td style="text-align: right;">2.18×</td> <td style="text-align: right;">2.22×</td> </tr> <tr> <td><code>FromBinaryShape/scalars / cbor</code></td> <td style="text-align: right;">26.2 ms</td> <td style="text-align: right;">5.89 ms</td> <td style="text-align: right;">4.45×</td> <td style="text-align: right;">3.56×</td> </tr> <tr> <td><code>FromBinaryShape/scalars / msgpack</code></td> <td style="text-align: right;">25.1 ms</td> <td style="text-align: right;">5.65 ms</td> <td style="text-align: right;">4.44×</td> <td style="text-align: right;">3.69×</td> </tr> <tr> <td><code>FromBinaryShape/scalars / ubjson</code></td> <td style="text-align: right;">25.3 ms</td> <td style="text-align: right;">11.6 ms</td> <td style="text-align: right;">2.18×</td> <td style="text-align: right;">2.03×</td> </tr> <tr> <td><code>FromCborChunkedString/10000 chunks</code></td> <td style="text-align: right;">91.8 µs</td> <td style="text-align: right;">82.9 µs</td> <td style="text-align: right;">1.11×</td> <td style="text-align: right;">1.09×</td> </tr> <tr> <td><code>FromMsgpack/canada</code></td> <td style="text-align: right;">14.9 ms</td> <td style="text-align: right;">4.56 ms</td> <td style="text-align: right;">3.26×</td> <td style="text-align: right;">3.63×</td> </tr> <tr> <td><code>FromMsgpack/citm_catalog</code></td> <td style="text-align: right;">9.36 ms</td> <td style="text-align: right;">2.26 ms</td> <td style="text-align: right;">4.14×</td> <td style="text-align: right;">4.60×</td> </tr> <tr> <td><code>FromMsgpack/floats</code></td> <td style="text-align: right;">61.3 ms</td> <td style="text-align: right;">28.7 ms</td> <td style="text-align: right;">2.14×</td> <td style="text-align: right;">2.89×</td> </tr> <tr> <td><code>FromMsgpack/jeopardy</code></td> <td style="text-align: right;">1,170 ms</td> <td style="text-align: right;">190 ms</td> <td style="text-align: right;">6.14×</td> <td style="text-align: right;">6.80×</td> </tr> <tr> <td><code>FromMsgpack/signed_ints</code></td> <td style="text-align: right;">63.9 ms</td> <td style="text-align: right;">32.9 ms</td> <td style="text-align: right;">1.94×</td> <td style="text-align: right;">2.44×</td> </tr> <tr> <td><code>FromMsgpack/small_signed_ints</code></td> <td style="text-align: right;">64.5 ms</td> <td style="text-align: right;">34.4 ms</td> <td style="text-align: right;">1.87×</td> <td style="text-align: right;">2.33×</td> </tr> <tr> <td><code>FromMsgpack/twitter</code></td> <td style="text-align: right;">10.3 ms</td> <td style="text-align: right;">1.49 ms</td> <td style="text-align: right;">6.92×</td> <td style="text-align: right;">6.76×</td> </tr> <tr> <td><code>FromMsgpack/unsigned_ints</code></td> <td style="text-align: right;">57.8 ms</td> <td style="text-align: right;">28.3 ms</td> <td style="text-align: right;">2.04×</td> <td style="text-align: right;">2.77×</td> </tr> <tr> <td><code>GetArray&lt;std::array&lt;int, 1000&gt;&gt;</code></td> <td style="text-align: right;">2.27 µs</td> <td style="text-align: right;">654 ns</td> <td style="text-align: right;">3.48×</td> <td style="text-align: right;">5.38×</td> </tr> <tr> <td><code>GetArray&lt;std::deque&lt;int&gt;&gt;</code></td> <td style="text-align: right;">8.29 µs</td> <td style="text-align: right;">1.18 µs</td> <td style="text-align: right;">7.05×</td> <td style="text-align: right;">4.75×</td> </tr> <tr> <td><code>GetArray&lt;std::set&lt;int&gt;&gt;</code></td> <td style="text-align: right;">60 µs</td> <td style="text-align: right;">42.5 µs</td> <td style="text-align: right;">1.41×</td> <td style="text-align: right;">1.30×</td> </tr> <tr> <td><code>GetArray&lt;std::vector&lt;int&gt;&gt;</code></td> <td style="text-align: right;">6.79 µs</td> <td style="text-align: right;">682 ns</td> <td style="text-align: right;">9.95×</td> <td style="text-align: right;">4.10×</td> </tr> <tr> <td><code>GetMap/citm_catalog</code></td> <td style="text-align: right;">3.6 ms</td> <td style="text-align: right;">2.49 ms</td> <td style="text-align: right;">1.45×</td> <td style="text-align: right;">1.48×</td> </tr> <tr> <td><code>GetVectorDouble/floats</code></td> <td style="text-align: right;">6.84 ms</td> <td style="text-align: right;">656 µs</td> <td style="text-align: right;">10.4×</td> <td style="text-align: right;">2.98×</td> </tr> <tr> <td><code>GetVectorInt/signed_ints</code></td> <td style="text-align: right;">8.22 ms</td> <td style="text-align: right;">3.46 ms</td> <td style="text-align: right;">2.37×</td> <td style="text-align: right;">2.02×</td> </tr> <tr> <td><code>Iterate/canada</code></td> <td style="text-align: right;">897 µs</td> <td style="text-align: right;">328 µs</td> <td style="text-align: right;">2.73×</td> <td style="text-align: right;">2.02×</td> </tr> <tr> <td><code>Iterate/citm_catalog</code></td> <td style="text-align: right;">305 µs</td> <td style="text-align: right;">171 µs</td> <td style="text-align: right;">1.78×</td> <td style="text-align: right;">1.53×</td> </tr> <tr> <td><code>Iterate/twitter</code></td> <td style="text-align: right;">90 µs</td> <td style="text-align: right;">62 µs</td> <td style="text-align: right;">1.45×</td> <td style="text-align: right;">1.20×</td> </tr> <tr> <td><code>JsonPointerAt/citm_catalog</code></td> <td style="text-align: right;">1.9 ms</td> <td style="text-align: right;">1.18 ms</td> <td style="text-align: right;">1.61×</td> <td style="text-align: right;">1.47×</td> </tr> <tr> <td><code>JsonPointerAt/twitter</code></td> <td style="text-align: right;">818 µs</td> <td style="text-align: right;">612 µs</td> <td style="text-align: right;">1.34×</td> <td style="text-align: right;">1.14×</td> </tr> <tr> <td><code>JsonPointerContains/citm_catalog</code></td> <td style="text-align: right;">2.82 ms</td> <td style="text-align: right;">1.27 ms</td> <td style="text-align: right;">2.22×</td> <td style="text-align: right;">2.51×</td> </tr> <tr> <td><code>JsonPointerContains/twitter</code></td> <td style="text-align: right;">1.34 ms</td> <td style="text-align: right;">629 µs</td> <td style="text-align: right;">2.12×</td> <td style="text-align: right;">2.16×</td> </tr> <tr> <td><code>JsonPointerParse/citm_catalog</code></td> <td style="text-align: right;">5.81 ms</td> <td style="text-align: right;">2.25 ms</td> <td style="text-align: right;">2.59×</td> <td style="text-align: right;">3.74×</td> </tr> <tr> <td><code>JsonPointerParse/twitter</code></td> <td style="text-align: right;">2.48 ms</td> <td style="text-align: right;">1.02 ms</td> <td style="text-align: right;">2.43×</td> <td style="text-align: right;">3.18×</td> </tr> <tr> <td><code>JsonPointerToString/citm_catalog</code></td> <td style="text-align: right;">6.79 ms</td> <td style="text-align: right;">1.94 ms</td> <td style="text-align: right;">3.50×</td> <td style="text-align: right;">4.61×</td> </tr> <tr> <td><code>JsonPointerToString/twitter</code></td> <td style="text-align: right;">2.23 ms</td> <td style="text-align: right;">834 µs</td> <td style="text-align: right;">2.67×</td> <td style="text-align: right;">2.66×</td> </tr> <tr> <td><code>ParseFILE/canada</code></td> <td style="text-align: right;">54.2 ms</td> <td style="text-align: right;">14.7 ms</td> <td style="text-align: right;">3.69×</td> <td style="text-align: right;">5.46×</td> </tr> <tr> <td><code>ParseFILE/citm_catalog</code></td> <td style="text-align: right;">36 ms</td> <td style="text-align: right;">7.58 ms</td> <td style="text-align: right;">4.74×</td> <td style="text-align: right;">5.73×</td> </tr> <tr> <td><code>ParseFILE/twitter</code></td> <td style="text-align: right;">14.1 ms</td> <td style="text-align: right;">3.45 ms</td> <td style="text-align: right;">4.08×</td> <td style="text-align: right;">4.24×</td> </tr> <tr> <td><code>ParseFile/canada</code></td> <td style="text-align: right;">18.3 ms</td> <td style="text-align: right;">6.47 ms</td> <td style="text-align: right;">2.83×</td> <td style="text-align: right;">4.67×</td> </tr> <tr> <td><code>ParseFile/citm_catalog</code></td> <td style="text-align: right;">8.13 ms</td> <td style="text-align: right;">2.52 ms</td> <td style="text-align: right;">3.22×</td> <td style="text-align: right;">2.98×</td> </tr> <tr> <td><code>ParseFile/floats</code></td> <td style="text-align: right;">131 ms</td> <td style="text-align: right;">48.1 ms</td> <td style="text-align: right;">2.73×</td> <td style="text-align: right;">5.68×</td> </tr> <tr> <td><code>ParseFile/jeopardy</code></td> <td style="text-align: right;">338 ms</td> <td style="text-align: right;">162 ms</td> <td style="text-align: right;">2.09×</td> <td style="text-align: right;">2.23×</td> </tr> <tr> <td><code>ParseFile/signed_ints</code></td> <td style="text-align: right;">129 ms</td> <td style="text-align: right;">46.2 ms</td> <td style="text-align: right;">2.78×</td> <td style="text-align: right;">3.41×</td> </tr> <tr> <td><code>ParseFile/small_signed_ints</code></td> <td style="text-align: right;">64.7 ms</td> <td style="text-align: right;">33.4 ms</td> <td style="text-align: right;">1.94×</td> <td style="text-align: right;">2.57×</td> </tr> <tr> <td><code>ParseFile/twitter</code></td> <td style="text-align: right;">3.43 ms</td> <td style="text-align: right;">1.37 ms</td> <td style="text-align: right;">2.49×</td> <td style="text-align: right;">2.33×</td> </tr> <tr> <td><code>ParseFile/unsigned_ints</code></td> <td style="text-align: right;">124 ms</td> <td style="text-align: right;">47.4 ms</td> <td style="text-align: right;">2.61×</td> <td style="text-align: right;">3.52×</td> </tr> <tr> <td><code>ParseIndented/canada / 4</code></td> <td style="text-align: right;">35 ms</td> <td style="text-align: right;">5.37 ms</td> <td style="text-align: right;">6.51×</td> <td style="text-align: right;">8.02×</td> </tr> <tr> <td><code>ParseIndented/citm_catalog / 4</code></td> <td style="text-align: right;">7.52 ms</td> <td style="text-align: right;">1.81 ms</td> <td style="text-align: right;">4.15×</td> <td style="text-align: right;">3.49×</td> </tr> <tr> <td><code>ParseIndented/jeopardy / 4</code></td> <td style="text-align: right;">345 ms</td> <td style="text-align: right;">133 ms</td> <td style="text-align: right;">2.59×</td> <td style="text-align: right;">2.46×</td> </tr> <tr> <td><code>ParseIndented/twitter / 4</code></td> <td style="text-align: right;">3.72 ms</td> <td style="text-align: right;">1.13 ms</td> <td style="text-align: right;">3.30×</td> <td style="text-align: right;">2.60×</td> </tr> <tr> <td><code>ParseStreamValues/ndjson</code></td> <td style="text-align: right;">7.16 ms</td> <td style="text-align: right;">3.77 ms</td> <td style="text-align: right;">1.90×</td> <td style="text-align: right;">2.06×</td> </tr> <tr> <td><code>ParseStreamValues/numbers</code></td> <td style="text-align: right;">1.93 ms</td> <td style="text-align: right;">383 µs</td> <td style="text-align: right;">5.03×</td> <td style="text-align: right;">6.06×</td> </tr> <tr> <td><code>ParseString/canada</code></td> <td style="text-align: right;">15.5 ms</td> <td style="text-align: right;">4.63 ms</td> <td style="text-align: right;">3.35×</td> <td style="text-align: right;">6.13×</td> </tr> <tr> <td><code>ParseString/citm_catalog</code></td> <td style="text-align: right;">7.56 ms</td> <td style="text-align: right;">1.78 ms</td> <td style="text-align: right;">4.25×</td> <td style="text-align: right;">3.46×</td> </tr> <tr> <td><code>ParseString/floats</code></td> <td style="text-align: right;">122 ms</td> <td style="text-align: right;">28.3 ms</td> <td style="text-align: right;">4.30×</td> <td style="text-align: right;">8.68×</td> </tr> <tr> <td><code>ParseString/jeopardy</code></td> <td style="text-align: right;">317 ms</td> <td style="text-align: right;">131 ms</td> <td style="text-align: right;">2.42×</td> <td style="text-align: right;">2.32×</td> </tr> <tr> <td><code>ParseString/signed_ints</code></td> <td style="text-align: right;">123 ms</td> <td style="text-align: right;">32 ms</td> <td style="text-align: right;">3.84×</td> <td style="text-align: right;">4.29×</td> </tr> <tr> <td><code>ParseString/small_signed_ints</code></td> <td style="text-align: right;">62.7 ms</td> <td style="text-align: right;">25 ms</td> <td style="text-align: right;">2.51×</td> <td style="text-align: right;">3.38×</td> </tr> <tr> <td><code>ParseString/twitter</code></td> <td style="text-align: right;">3.3 ms</td> <td style="text-align: right;">1.05 ms</td> <td style="text-align: right;">3.14×</td> <td style="text-align: right;">2.60×</td> </tr> <tr> <td><code>ParseString/unsigned_ints</code></td> <td style="text-align: right;">121 ms</td> <td style="text-align: right;">32.9 ms</td> <td style="text-align: right;">3.68×</td> <td style="text-align: right;">4.23×</td> </tr> <tr> <td><code>ParseStringOrdered/canada</code></td> <td style="text-align: right;">15.4 ms</td> <td style="text-align: right;">4.53 ms</td> <td style="text-align: right;">3.40×</td> <td style="text-align: right;">6.21×</td> </tr> <tr> <td><code>ParseStringOrdered/citm_catalog</code></td> <td style="text-align: right;">11.5 ms</td> <td style="text-align: right;">1.68 ms</td> <td style="text-align: right;">6.85×</td> <td style="text-align: right;">6.59×</td> </tr> <tr> <td><code>ParseStringOrdered/jeopardy</code></td> <td style="text-align: right;">374 ms</td> <td style="text-align: right;">113 ms</td> <td style="text-align: right;">3.29×</td> <td style="text-align: right;">3.38×</td> </tr> <tr> <td><code>ParseStringOrdered/twitter</code></td> <td style="text-align: right;">4.6 ms</td> <td style="text-align: right;">949 µs</td> <td style="text-align: right;">4.85×</td> <td style="text-align: right;">4.93×</td> </tr> <tr> <td><code>Patch/canada</code></td> <td style="text-align: right;">10.4 ms</td> <td style="text-align: right;">3.48 ms</td> <td style="text-align: right;">2.98×</td> <td style="text-align: right;">2.46×</td> </tr> <tr> <td><code>Patch/citm_catalog</code></td> <td style="text-align: right;">2.75 ms</td> <td style="text-align: right;">1.74 ms</td> <td style="text-align: right;">1.58×</td> <td style="text-align: right;">1.38×</td> </tr> <tr> <td><code>Patch/twitter</code></td> <td style="text-align: right;">1.58 ms</td> <td style="text-align: right;">889 µs</td> <td style="text-align: right;">1.78×</td> <td style="text-align: right;">1.45×</td> </tr> <tr> <td><code>SaxParse/canada</code></td> <td style="text-align: right;">13.1 ms</td> <td style="text-align: right;">3.27 ms</td> <td style="text-align: right;">4.01×</td> <td style="text-align: right;">8.84×</td> </tr> <tr> <td><code>SaxParse/citm_catalog</code></td> <td style="text-align: right;">6.55 ms</td> <td style="text-align: right;">967 µs</td> <td style="text-align: right;">6.77×</td> <td style="text-align: right;">6.85×</td> </tr> <tr> <td><code>SaxParse/twitter</code></td> <td style="text-align: right;">2.53 ms</td> <td style="text-align: right;">483 µs</td> <td style="text-align: right;">5.24×</td> <td style="text-align: right;">5.91×</td> </tr> <tr> <td><code>ToCbor/canada</code></td> <td style="text-align: right;">1.41 ms</td> <td style="text-align: right;">557 µs</td> <td style="text-align: right;">2.54×</td> <td style="text-align: right;">2.27×</td> </tr> <tr> <td><code>ToCbor/citm_catalog</code></td> <td style="text-align: right;">1.05 ms</td> <td style="text-align: right;">259 µs</td> <td style="text-align: right;">4.04×</td> <td style="text-align: right;">5.60×</td> </tr> <tr> <td><code>ToCbor/floats</code></td> <td style="text-align: right;">9.05 ms</td> <td style="text-align: right;">1.9 ms</td> <td style="text-align: right;">4.76×</td> <td style="text-align: right;">1.94×</td> </tr> <tr> <td><code>ToCbor/jeopardy</code></td> <td style="text-align: right;">73.9 ms</td> <td style="text-align: right;">22.1 ms</td> <td style="text-align: right;">3.35×</td> <td style="text-align: right;">2.87×</td> </tr> <tr> <td><code>ToCbor/signed_ints</code></td> <td style="text-align: right;">11.5 ms</td> <td style="text-align: right;">2.83 ms</td> <td style="text-align: right;">4.08×</td> <td style="text-align: right;">1.83×</td> </tr> <tr> <td><code>ToCbor/small_signed_ints</code></td> <td style="text-align: right;">10.4 ms</td> <td style="text-align: right;">2.48 ms</td> <td style="text-align: right;">4.19×</td> <td style="text-align: right;">2.78×</td> </tr> <tr> <td><code>ToCbor/twitter</code></td> <td style="text-align: right;">659 µs</td> <td style="text-align: right;">143 µs</td> <td style="text-align: right;">4.59×</td> <td style="text-align: right;">6.67×</td> </tr> <tr> <td><code>ToCbor/unsigned_ints</code></td> <td style="text-align: right;">8.18 ms</td> <td style="text-align: right;">2.82 ms</td> <td style="text-align: right;">2.90×</td> <td style="text-align: right;">1.48×</td> </tr> <tr> <td><code>ToJsonStrings/copy</code></td> <td style="text-align: right;">6.12 ms</td> <td style="text-align: right;">5.65 ms</td> <td style="text-align: right;">1.08×</td> <td style="text-align: right;">1.05×</td> </tr> <tr> <td><code>ToJsonStrings/move</code></td> <td style="text-align: right;">6.13 ms</td> <td style="text-align: right;">3.13 ms</td> <td style="text-align: right;">1.96×</td> <td style="text-align: right;">1.78×</td> </tr> <tr> <td><code>Unflatten/canada</code></td> <td style="text-align: right;">42.5 ms</td> <td style="text-align: right;">11.1 ms</td> <td style="text-align: right;">3.83×</td> <td style="text-align: right;">4.32×</td> </tr> <tr> <td><code>Unflatten/citm_catalog</code></td> <td style="text-align: right;">10.2 ms</td> <td style="text-align: right;">3.62 ms</td> <td style="text-align: right;">2.81×</td> <td style="text-align: right;">3.32×</td> </tr> <tr> <td><code>Unflatten/twitter</code></td> <td style="text-align: right;">4.75 ms</td> <td style="text-align: right;">2.21 ms</td> <td style="text-align: right;">2.15×</td> <td style="text-align: right;">2.42×</td> </tr> </tbody> </table> </details> <h3 id=c-the-timeline>C. The timeline<a class=headerlink href=#c-the-timeline title="Permanent link">&para;</a></h3> <p>The other four workloads we followed:</p> <ul> <li><code>accept()</code> of <code>twitter.json</code>: the lexer alone, since <code>accept()</code> only validates and builds nothing;</li> <li><code>parse()</code> of <code>twitter.json</code> from an <code>std::ifstream</code>: reading from a stream instead of a string;</li> <li><code>dump()</code> of <code>canada.json</code>: writing floating-point numbers;</li> <li><code>to_cbor()</code> of <code>twitter.json</code>: writing a binary format.</li> </ul> <div class=nj-charts-grid-wrap> <div class=nj-fig-wrap> <p><svg class="nj-fig nj-charts nj-charts--timeline" viewbox="0 0 340 270" role=img aria-labelledby="nj-blog-tl-accept_twitter nj-blog-tl-accept_twitter-d" xmlns=http://www.w3.org/2000/svg> <title id=nj-blog-tl-accept_twitter>accept() twitter.json: speedup over 3.12.0 by commit</title> <desc id=nj-blog-tl-accept_twitter-d>accept() twitter.json: speedup over 3.12.0 at each of 353 commits, ending at 5.1x. Labeled steps, by theme: 4, 1, 4, 4, 2, 2.</desc> <text class=nj-charts-panel x=8 y=18>accept() twitter.json</text> <line class=nj-charts-grid x1=44 y1=208 x2=330 y2=208 /> <text class="nj-charts-tick nj-charts-tick--r" x=38 y=212>1&#215;</text> <line class=nj-charts-grid x1=44 y1=160.667 x2=330 y2=160.667 /> <text class="nj-charts-tick nj-charts-tick--r" x=38 y=164.667>2&#215;</text> <line class=nj-charts-grid x1=44 y1=113.333 x2=330 y2=113.333 /> <text class="nj-charts-tick nj-charts-tick--r" x=38 y=117.333>4&#215;</text> <line class=nj-charts-grid x1=44 y1=66 x2=330 y2=66 /> <text class="nj-charts-tick nj-charts-tick--r" x=38 y=70>8&#215;</text> <line class=nj-charts-axis x1=44 y1=208 x2=44 y2=212 /> <text class=nj-charts-tick x=44 y=225>3.12.0</text> <line class=nj-charts-axis x1=117.938 y1=208 x2=117.938 y2=212 /> <text class=nj-charts-tick x=117.938 y=225>Sep 2026</text> <line class=nj-charts-axis x1=198.375 y1=208 x2=198.375 y2=212 /> <text class=nj-charts-tick x=198.375 y=225>Oct</text> <polyline class=nj-charts-json points="44.0,208.0 44.8,208.0 44.8,208.1 45.6,208.1 45.6,207.8 46.4,207.8 46.4,208.0 47.2,208.0 47.2,207.7 48.1,207.7 48.1,207.9 48.9,207.9 48.9,208.0 49.7,208.0 49.7,208.1 50.5,208.1 50.5,208.4 51.3,208.4 51.3,207.1 52.1,207.1 52.1,207.9 52.9,207.9 52.9,208.2 53.8,208.2 53.8,207.9 54.6,207.9 54.6,207.9 55.4,207.9 55.4,207.7 56.2,207.7 56.2,207.9 57.0,207.9 57.0,207.8 57.8,207.8 57.8,207.7 58.6,207.7 58.6,208.2 59.4,208.2 59.4,207.3 60.2,207.3 60.2,208.0 61.1,208.0 61.1,208.0 61.9,208.0 61.9,207.8 62.7,207.8 62.7,207.9 63.5,207.9 63.5,207.9 64.3,207.9 64.3,207.2 65.1,207.2 65.1,207.8 65.9,207.8 65.9,207.6 66.8,207.6 66.8,207.8 67.6,207.8 67.6,207.9 68.4,207.9 68.4,207.9 69.2,207.9 69.2,207.4 70.0,207.4 70.0,207.7 70.8,207.7 70.8,207.6 71.6,207.6 71.6,207.7 72.4,207.7 72.4,208.1 73.2,208.1 73.2,207.8 74.1,207.8 74.1,207.1 74.9,207.1 74.9,207.9 75.7,207.9 75.7,207.1 76.5,207.1 76.5,207.8 77.3,207.8 77.3,207.3 78.1,207.3 78.1,208.1 78.9,208.1 78.9,207.6 79.8,207.6 79.8,207.6 80.6,207.6 80.6,208.1 81.4,208.1 81.4,208.3 82.2,208.3 82.2,207.8 83.0,207.8 83.0,207.7 83.8,207.7 83.8,207.9 84.6,207.9 84.6,207.8 85.4,207.8 85.4,207.5 86.2,207.5 86.2,207.9 87.1,207.9 87.1,207.8 87.9,207.8 87.9,208.0 88.7,208.0 88.7,194.6 89.5,194.6 89.5,195.3 90.3,195.3 90.3,195.6 91.1,195.6 91.1,195.1 91.9,195.1 91.9,195.6 92.8,195.6 92.8,194.6 93.6,194.6 93.6,194.7 94.4,194.7 94.4,195.3 95.2,195.3 95.2,195.1 96.0,195.1 96.0,195.1 96.8,195.1 96.8,195.6 97.6,195.6 97.6,194.6 98.4,194.6 98.4,195.2 99.2,195.2 99.2,195.3 100.1,195.3 100.1,195.6 100.9,195.6 100.9,195.3 101.7,195.3 101.7,195.4 102.5,195.4 102.5,195.2 103.3,195.2 103.3,195.8 104.1,195.8 104.1,195.1 104.9,195.1 104.9,195.3 105.8,195.3 105.8,196.2 106.6,196.2 106.6,195.7 107.4,195.7 107.4,194.5 108.2,194.5 108.2,194.7 109.0,194.7 109.0,195.1 109.8,195.1 109.8,195.6 110.6,195.6 110.6,195.6 111.4,195.6 111.4,195.5 112.2,195.5 112.2,194.6 113.1,194.6 113.1,194.4 113.9,194.4 113.9,195.1 114.7,195.1 114.7,195.4 115.5,195.4 115.5,195.8 116.3,195.8 116.3,194.6 117.1,194.6 117.1,195.0 117.9,195.0 117.9,195.4 118.8,195.4 118.8,195.1 119.6,195.1 119.6,195.5 120.4,195.5 120.4,193.5 121.2,193.5 121.2,194.9 122.0,194.9 122.0,195.1 122.8,195.1 122.8,194.8 123.6,194.8 123.6,194.6 124.4,194.6 124.4,194.7 125.3,194.7 125.3,195.1 126.1,195.1 126.1,195.0 126.9,195.0 126.9,194.7 127.7,194.7 127.7,195.3 128.5,195.3 128.5,194.6 129.3,194.6 129.3,194.7 130.1,194.7 130.1,143.3 130.9,143.3 130.9,143.0 131.8,143.0 131.8,142.2 132.6,142.2 132.6,141.9 133.4,141.9 133.4,143.0 134.2,143.0 134.2,142.6 135.0,142.6 135.0,142.4 135.8,142.4 135.8,142.9 136.6,142.9 136.6,143.1 137.4,143.1 137.4,143.2 138.2,143.2 138.2,142.1 139.1,142.1 139.1,143.1 139.9,143.1 139.9,142.4 140.7,142.4 140.7,143.0 141.5,143.0 141.5,141.8 142.3,141.8 142.3,143.1 143.1,143.1 143.1,141.9 143.9,141.9 143.9,143.1 144.8,143.1 144.8,142.9 145.6,142.9 145.6,142.0 146.4,142.0 146.4,142.5 147.2,142.5 147.2,142.4 148.0,142.4 148.0,143.5 148.8,143.5 148.8,142.9 149.6,142.9 149.6,142.3 150.4,142.3 150.4,143.1 151.2,143.1 151.2,141.9 152.1,141.9 152.1,142.4 152.9,142.4 152.9,141.9 153.7,141.9 153.7,141.8 154.5,141.8 154.5,141.3 155.3,141.3 155.3,142.9 156.1,142.9 156.1,141.2 156.9,141.2 156.9,142.8 157.8,142.8 157.8,142.6 158.6,142.6 158.6,142.3 159.4,142.3 159.4,142.7 160.2,142.7 160.2,142.0 161.0,142.0 161.0,141.5 161.8,141.5 161.8,141.2 162.6,141.2 162.6,141.4 163.4,141.4 163.4,141.9 164.2,141.9 164.2,141.6 165.1,141.6 165.1,141.8 165.9,141.8 165.9,142.0 166.7,142.0 166.7,142.0 167.5,142.0 167.5,141.5 168.3,141.5 168.3,142.4 169.1,142.4 169.1,141.7 169.9,141.7 169.9,142.4 170.8,142.4 170.8,141.9 171.6,141.9 171.6,141.7 172.4,141.7 172.4,141.1 173.2,141.1 173.2,141.5 174.0,141.5 174.0,141.6 174.8,141.6 174.8,141.7 175.6,141.7 175.6,140.3 176.4,140.3 176.4,140.7 177.2,140.7 177.2,140.6 178.1,140.6 178.1,141.0 178.9,141.0 178.9,141.8 179.7,141.8 179.7,141.6 180.5,141.6 180.5,141.5 181.3,141.5 181.3,141.0 182.1,141.0 182.1,141.1 182.9,141.1 182.9,140.7 183.8,140.7 183.8,140.4 184.6,140.4 184.6,142.1 185.4,142.1 185.4,141.7 186.2,141.7 186.2,141.2 187.0,141.2 187.0,141.5 187.8,141.5 187.8,140.4 188.6,140.4 188.6,141.0 189.4,141.0 189.4,141.5 190.2,141.5 190.2,141.2 191.1,141.2 191.1,142.1 191.9,142.1 191.9,140.4 192.7,140.4 192.7,141.1 193.5,141.1 193.5,141.5 194.3,141.5 194.3,140.9 195.1,140.9 195.1,141.7 195.9,141.7 195.9,140.4 196.8,140.4 196.8,141.9 197.6,141.9 197.6,141.1 198.4,141.1 198.4,141.4 199.2,141.4 199.2,140.6 200.0,140.6 200.0,141.4 200.8,141.4 200.8,140.1 201.6,140.1 201.6,141.2 202.4,141.2 202.4,140.8 203.2,140.8 203.2,141.4 204.1,141.4 204.1,141.5 204.9,141.5 204.9,141.2 205.7,141.2 205.7,142.0 206.5,142.0 206.5,142.6 207.3,142.6 207.3,142.3 208.1,142.3 208.1,140.6 208.9,140.6 208.9,140.8 209.8,140.8 209.8,140.9 210.6,140.9 210.6,141.1 211.4,141.1 211.4,141.6 212.2,141.6 212.2,141.0 213.0,141.0 213.0,141.5 213.8,141.5 213.8,141.4 214.6,141.4 214.6,142.0 215.4,142.0 215.4,140.6 216.2,140.6 216.2,142.1 217.1,142.1 217.1,140.6 217.9,140.6 217.9,142.1 218.7,142.1 218.7,141.5 219.5,141.5 219.5,141.2 220.3,141.2 220.3,141.7 221.1,141.7 221.1,140.6 221.9,140.6 221.9,143.1 222.8,143.1 222.8,135.2 223.6,135.2 223.6,135.7 224.4,135.7 224.4,135.6 225.2,135.6 225.2,136.1 226.0,136.1 226.0,136.1 226.8,136.1 226.8,135.8 227.6,135.8 227.6,135.8 228.4,135.8 228.4,135.9 229.2,135.9 229.2,136.4 230.1,136.4 230.1,135.6 230.9,135.6 230.9,135.2 231.7,135.2 231.7,135.5 232.5,135.5 232.5,136.9 233.3,136.9 233.3,136.5 234.1,136.5 234.1,136.5 234.9,136.5 234.9,135.9 235.8,135.9 235.8,136.0 236.6,136.0 236.6,136.1 237.4,136.1 237.4,136.9 238.2,136.9 238.2,136.2 239.0,136.2 239.0,136.2 239.8,136.2 239.8,136.5 240.6,136.5 240.6,136.4 241.4,136.4 241.4,136.0 242.3,136.0 242.3,136.7 243.1,136.7 243.1,118.7 243.9,118.7 243.9,112.7 244.7,112.7 244.7,112.3 245.5,112.3 245.5,108.7 246.3,108.7 246.3,107.4 247.1,107.4 247.1,107.2 247.9,107.2 247.9,108.5 248.8,108.5 248.8,108.6 249.6,108.6 249.6,108.8 250.4,108.8 250.4,108.9 251.2,108.9 251.2,108.3 252.0,108.3 252.0,108.2 252.8,108.2 252.8,108.5 253.6,108.5 253.6,109.0 254.4,109.0 254.4,107.9 255.2,107.9 255.2,108.6 256.1,108.6 256.1,107.9 256.9,107.9 256.9,108.5 257.7,108.5 257.7,108.5 258.5,108.5 258.5,107.4 259.3,107.4 259.3,108.0 260.1,108.0 260.1,108.8 260.9,108.8 260.9,108.3 261.8,108.3 261.8,107.3 262.6,107.3 262.6,108.0 263.4,108.0 263.4,108.8 264.2,108.8 264.2,107.3 265.0,107.3 265.0,107.8 265.8,107.8 265.8,108.3 266.6,108.3 266.6,108.4 267.4,108.4 267.4,107.3 268.2,107.3 268.2,108.6 269.1,108.6 269.1,108.6 269.9,108.6 269.9,107.8 270.7,107.8 270.7,108.0 271.5,108.0 271.5,107.0 272.3,107.0 272.3,107.3 273.1,107.3 273.1,99.2 273.9,99.2 273.9,97.0 274.8,97.0 274.8,97.1 275.6,97.1 275.6,96.8 276.4,96.8 276.4,96.0 277.2,96.0 277.2,96.5 278.0,96.5 278.0,96.4 278.8,96.4 278.8,96.5 279.6,96.5 279.6,96.9 280.4,96.9 280.4,97.2 281.2,97.2 281.2,97.3 282.1,97.3 282.1,95.7 282.9,95.7 282.9,96.3 283.7,96.3 283.7,96.8 284.5,96.8 284.5,96.6 285.3,96.6 285.3,97.6 286.1,97.6 286.1,97.6 286.9,97.6 286.9,97.4 287.8,97.4 287.8,98.5 288.6,98.5 288.6,98.7 289.4,98.7 289.4,98.0 290.2,98.0 290.2,98.2 291.0,98.2 291.0,98.7 291.8,98.7 291.8,99.0 292.6,99.0 292.6,99.0 293.4,99.0 293.4,98.7 294.2,98.7 294.2,98.1 295.1,98.1 295.1,99.0 295.9,99.0 295.9,99.1 296.7,99.1 296.7,98.6 297.5,98.6 297.5,98.6 298.3,98.6 298.3,98.1 299.1,98.1 299.1,98.7 299.9,98.7 299.9,98.3 300.8,98.3 300.8,97.3 301.6,97.3 301.6,98.0 302.4,98.0 302.4,97.0 303.2,97.0 303.2,97.3 304.0,97.3 304.0,97.8 304.8,97.8 304.8,98.3 305.6,98.3 305.6,97.7 306.4,97.7 306.4,96.9 307.2,96.9 307.2,96.9 308.1,96.9 308.1,97.9 308.9,97.9 308.9,98.3 309.7,98.3 309.7,97.1 310.5,97.1 310.5,97.4 311.3,97.4 311.3,97.2 312.1,97.2 312.1,97.9 312.9,97.9 312.9,97.7 313.8,97.7 313.8,97.6 314.6,97.6 314.6,97.4 315.4,97.4 315.4,96.6 316.2,96.6 316.2,97.4 317.0,97.4 317.0,97.2 317.8,97.2 317.8,96.7 318.6,96.7 318.6,96.3 319.4,96.3 319.4,97.0 320.2,97.0 320.2,96.9 321.1,96.9 321.1,96.8 321.9,96.8 321.9,97.1 322.7,97.1 322.7,98.2 323.5,98.2 323.5,98.0 324.3,98.0 324.3,98.7 325.1,98.7 325.1,97.1 325.9,97.1 325.9,97.4 326.8,97.4 326.8,98.4 327.6,98.4 327.6,97.2 328.4,97.2 328.4,97.5 329.2,97.5 329.2,97.7 330.0,97.7 330.0,97.4"/> <circle class=nj-charts-json-dot cx=88.7 cy=194.6 r=3.5><title>#5234: 1.22&#215;</title></circle> <line class=nj-charts-grid x1=88.7 y1=54.0 x2=88.7 y2=189.6 stroke-dasharray="2 2"/> <circle class=nj-theme-dot cx=88.7 cy=46.0 r=7.5 /> <text class=nj-theme-num x=88.7 y=50.0 text-anchor=middle>4</text> <circle class=nj-charts-json-dot cx=130.1 cy=143.3 r=3.5><title>#5283: 2.6&#215;</title></circle> <line class=nj-charts-grid x1=130.1 y1=54.0 x2=130.1 y2=138.3 stroke-dasharray="2 2"/> <circle class=nj-theme-dot cx=130.1 cy=46.0 r=7.5 /> <text class=nj-theme-num x=130.1 y=50.0 text-anchor=middle>1</text> <circle class=nj-charts-json-dot cx=222.8 cy=135.2 r=3.5><title>#5592: 2.9&#215;</title></circle> <line class=nj-charts-grid x1=222.8 y1=54.0 x2=222.8 y2=130.2 stroke-dasharray="2 2"/> <circle class=nj-theme-dot cx=222.8 cy=46.0 r=7.5 /> <text class=nj-theme-num x=222.8 y=50.0 text-anchor=middle>4</text> <circle class=nj-charts-json-dot cx=243.1 cy=118.7 r=3.5><title>#5809: 3.7&#215;</title></circle> <circle class=nj-charts-json-dot cx=243.9 cy=112.7 r=3.5><title>#5810: 4.0&#215;</title></circle> <line class=nj-charts-grid x1=243.9 y1=36.0 x2=243.9 y2=107.7 stroke-dasharray="2 2"/> <circle class=nj-theme-dot cx=234.9 cy=28.0 r=7.5 /> <text class=nj-theme-num x=234.9 y=32.0 text-anchor=middle>4</text> <circle class=nj-theme-dot cx=252.9 cy=28.0 r=7.5 /> <text class=nj-theme-num x=252.9 y=32.0 text-anchor=middle>2</text> <circle class=nj-charts-json-dot cx=273.1 cy=99.2 r=3.5><title>#5853: 4.9&#215;</title></circle> <line class=nj-charts-grid x1=273.1 y1=54.0 x2=273.1 y2=94.2 stroke-dasharray="2 2"/> <circle class=nj-theme-dot cx=273.1 cy=46.0 r=7.5 /> <text class=nj-theme-num x=273.1 y=50.0 text-anchor=middle>2</text> <line class=nj-charts-axis x1=44 y1=208 x2=330 y2=208 /> <text class=nj-charts-note x=8 y=262>speedup over 3.12.0 (log scale), more is better</text> </svg></p> </div> <div class=nj-fig-wrap> <p><svg class="nj-fig nj-charts nj-charts--timeline" viewbox="0 0 340 270" role=img aria-labelledby="nj-blog-tl-parse_twitter_ifstream nj-blog-tl-parse_twitter_ifstream-d" xmlns=http://www.w3.org/2000/svg> <title id=nj-blog-tl-parse_twitter_ifstream>parse() twitter.json, std::ifstream: speedup over 3.12.0 by commit</title> <desc id=nj-blog-tl-parse_twitter_ifstream-d>parse() twitter.json, std::ifstream: speedup over 3.12.0 at each of 353 commits, ending at 2.2x. Labeled steps, by theme: 1, 1.</desc> <text class=nj-charts-panel x=8 y=18>parse() twitter.json, std::ifstream</text> <line class=nj-charts-grid x1=44 y1=208 x2=330 y2=208 /> <text class="nj-charts-tick nj-charts-tick--r" x=38 y=212>1&#215;</text> <line class=nj-charts-grid x1=44 y1=137 x2=330 y2=137 /> <text class="nj-charts-tick nj-charts-tick--r" x=38 y=141>2&#215;</text> <line class=nj-charts-grid x1=44 y1=66 x2=330 y2=66 /> <text class="nj-charts-tick nj-charts-tick--r" x=38 y=70>4&#215;</text> <line class=nj-charts-axis x1=44 y1=208 x2=44 y2=212 /> <text class=nj-charts-tick x=44 y=225>3.12.0</text> <line class=nj-charts-axis x1=117.938 y1=208 x2=117.938 y2=212 /> <text class=nj-charts-tick x=117.938 y=225>Sep 2026</text> <line class=nj-charts-axis x1=198.375 y1=208 x2=198.375 y2=212 /> <text class=nj-charts-tick x=198.375 y=225>Oct</text> <polyline class=nj-charts-json points="44.0,208.0 44.8,208.0 44.8,209.3 45.6,209.3 45.6,206.6 46.4,206.6 46.4,208.3 47.2,208.3 47.2,205.9 48.1,205.9 48.1,209.3 48.9,209.3 48.9,208.3 49.7,208.3 49.7,207.9 50.5,207.9 50.5,209.4 51.3,209.4 51.3,205.8 52.1,205.8 52.1,206.7 52.9,206.7 52.9,209.2 53.8,209.2 53.8,208.1 54.6,208.1 54.6,206.9 55.4,206.9 55.4,207.5 56.2,207.5 56.2,207.5 57.0,207.5 57.0,207.6 57.8,207.6 57.8,206.9 58.6,206.9 58.6,206.9 59.4,206.9 59.4,208.4 60.2,208.4 60.2,208.6 61.1,208.6 61.1,209.1 61.9,209.1 61.9,207.7 62.7,207.7 62.7,207.0 63.5,207.0 63.5,206.7 64.3,206.7 64.3,206.1 65.1,206.1 65.1,207.5 65.9,207.5 65.9,206.4 66.8,206.4 66.8,206.7 67.6,206.7 67.6,206.8 68.4,206.8 68.4,209.3 69.2,209.3 69.2,206.7 70.0,206.7 70.0,206.8 70.8,206.8 70.8,206.6 71.6,206.6 71.6,206.8 72.4,206.8 72.4,209.2 73.2,209.2 73.2,207.6 74.1,207.6 74.1,205.9 74.9,205.9 74.9,209.1 75.7,209.1 75.7,206.6 76.5,206.6 76.5,207.4 77.3,207.4 77.3,207.0 78.1,207.0 78.1,209.1 78.9,209.1 78.9,205.8 79.8,205.8 79.8,206.9 80.6,206.9 80.6,208.0 81.4,208.0 81.4,208.5 82.2,208.5 82.2,206.6 83.0,206.6 83.0,206.0 83.8,206.0 83.8,207.9 84.6,207.9 84.6,206.6 85.4,206.6 85.4,206.5 86.2,206.5 86.2,206.6 87.1,206.6 87.1,207.2 87.9,207.2 87.9,208.0 88.7,208.0 88.7,208.1 89.5,208.1 89.5,206.7 90.3,206.7 90.3,207.8 91.1,207.8 91.1,206.7 91.9,206.7 91.9,208.1 92.8,208.1 92.8,205.9 93.6,205.9 93.6,206.8 94.4,206.8 94.4,208.0 95.2,208.0 95.2,207.3 96.0,207.3 96.0,206.7 96.8,206.7 96.8,209.3 97.6,209.3 97.6,206.5 98.4,206.5 98.4,207.2 99.2,207.2 99.2,208.2 100.1,208.2 100.1,209.3 100.9,209.3 100.9,207.8 101.7,207.8 101.7,206.9 102.5,206.9 102.5,206.7 103.3,206.7 103.3,209.0 104.1,209.0 104.1,208.0 104.9,208.0 104.9,208.1 105.8,208.1 105.8,209.1 106.6,209.1 106.6,208.1 107.4,208.1 107.4,205.6 108.2,205.6 108.2,207.0 109.0,207.0 109.0,206.7 109.8,206.7 109.8,207.9 110.6,207.9 110.6,206.7 111.4,206.7 111.4,206.9 112.2,206.9 112.2,206.8 113.1,206.8 113.1,206.4 113.9,206.4 113.9,207.1 114.7,207.1 114.7,208.6 115.5,208.6 115.5,208.7 116.3,208.7 116.3,206.6 117.1,206.6 117.1,209.3 117.9,209.3 117.9,208.0 118.8,208.0 118.8,206.7 119.6,206.7 119.6,207.7 120.4,207.7 120.4,206.9 121.2,206.9 121.2,208.8 122.0,208.8 122.0,208.7 122.8,208.7 122.8,207.7 123.6,207.7 123.6,208.8 124.4,208.8 124.4,207.8 125.3,207.8 125.3,210.3 126.1,210.3 126.1,208.9 126.9,208.9 126.9,208.9 127.7,208.9 127.7,209.0 128.5,209.0 128.5,208.0 129.3,208.0 129.3,207.7 130.1,207.7 130.1,208.3 130.9,208.3 130.9,207.0 131.8,207.0 131.8,207.2 132.6,207.2 132.6,207.5 133.4,207.5 133.4,208.0 134.2,208.0 134.2,207.6 135.0,207.6 135.0,207.9 135.8,207.9 135.8,207.6 136.6,207.6 136.6,208.5 137.4,208.5 137.4,209.2 138.2,209.2 138.2,206.3 139.1,206.3 139.1,208.7 139.9,208.7 139.9,207.6 140.7,207.6 140.7,207.4 141.5,207.4 141.5,207.5 142.3,207.5 142.3,209.0 143.1,209.0 143.1,206.9 143.9,206.9 143.9,209.3 144.8,209.3 144.8,209.9 145.6,209.9 145.6,207.0 146.4,207.0 146.4,207.3 147.2,207.3 147.2,208.1 148.0,208.1 148.0,209.8 148.8,209.8 148.8,208.1 149.6,208.1 149.6,208.1 150.4,208.1 150.4,208.5 151.2,208.5 151.2,208.2 152.1,208.2 152.1,210.4 152.9,210.4 152.9,207.7 153.7,207.7 153.7,207.2 154.5,207.2 154.5,206.7 155.3,206.7 155.3,209.9 156.1,209.9 156.1,206.6 156.9,206.6 156.9,209.9 157.8,209.9 157.8,208.8 158.6,208.8 158.6,208.8 159.4,208.8 159.4,209.5 160.2,209.5 160.2,208.9 161.0,208.9 161.0,206.4 161.8,206.4 161.8,207.2 162.6,207.2 162.6,207.0 163.4,207.0 163.4,207.2 164.2,207.2 164.2,206.6 165.1,206.6 165.1,207.2 165.9,207.2 165.9,208.0 166.7,208.0 166.7,207.6 167.5,207.6 167.5,207.9 168.3,207.9 168.3,207.5 169.1,207.5 169.1,205.6 169.9,205.6 169.9,208.0 170.8,208.0 170.8,209.7 171.6,209.7 171.6,207.9 172.4,207.9 172.4,207.6 173.2,207.6 173.2,208.5 174.0,208.5 174.0,207.9 174.8,207.9 174.8,210.4 175.6,210.4 175.6,206.7 176.4,206.7 176.4,207.7 177.2,207.7 177.2,209.2 178.1,209.2 178.1,206.8 178.9,206.8 178.9,209.3 179.7,209.3 179.7,208.0 180.5,208.0 180.5,208.0 181.3,208.0 181.3,207.9 182.1,207.9 182.1,208.2 182.9,208.2 182.9,207.9 183.8,207.9 183.8,207.0 184.6,207.0 184.6,208.8 185.4,208.8 185.4,208.0 186.2,208.0 186.2,208.0 187.0,208.0 187.0,209.2 187.8,209.2 187.8,206.7 188.6,206.7 188.6,206.7 189.4,206.7 189.4,208.5 190.2,208.5 190.2,208.9 191.1,208.9 191.1,210.1 191.9,210.1 191.9,206.4 192.7,206.4 192.7,209.4 193.5,209.4 193.5,210.1 194.3,210.1 194.3,207.6 195.1,207.6 195.1,209.5 195.9,209.5 195.9,208.7 196.8,208.7 196.8,211.1 197.6,211.1 197.6,210.1 198.4,210.1 198.4,211.7 199.2,211.7 199.2,208.8 200.0,208.8 200.0,209.2 200.8,209.2 200.8,207.7 201.6,207.7 201.6,208.1 202.4,208.1 202.4,206.4 203.2,206.4 203.2,206.7 204.1,206.7 204.1,207.3 204.9,207.3 204.9,207.8 205.7,207.8 205.7,208.7 206.5,208.7 206.5,210.1 207.3,210.1 207.3,210.0 208.1,210.0 208.1,206.9 208.9,206.9 208.9,209.0 209.8,209.0 209.8,208.7 210.6,208.7 210.6,209.1 211.4,209.1 211.4,208.6 212.2,208.6 212.2,208.9 213.0,208.9 213.0,207.3 213.8,207.3 213.8,208.9 214.6,208.9 214.6,209.2 215.4,209.2 215.4,207.3 216.2,207.3 216.2,210.5 217.1,210.5 217.1,207.5 217.9,207.5 217.9,207.9 218.7,207.9 218.7,209.4 219.5,209.4 219.5,207.5 220.3,207.5 220.3,209.0 221.1,209.0 221.1,207.7 221.9,207.7 221.9,209.4 222.8,209.4 222.8,207.7 223.6,207.7 223.6,210.1 224.4,210.1 224.4,208.7 225.2,208.7 225.2,208.7 226.0,208.7 226.0,211.1 226.8,211.1 226.8,208.8 227.6,208.8 227.6,210.9 228.4,210.9 228.4,209.5 229.2,209.5 229.2,210.4 230.1,210.4 230.1,210.2 230.9,210.2 230.9,208.8 231.7,208.8 231.7,210.4 232.5,210.4 232.5,211.6 233.3,211.6 233.3,211.5 234.1,211.5 234.1,209.5 234.9,209.5 234.9,209.4 235.8,209.4 235.8,209.2 236.6,209.2 236.6,208.8 237.4,208.8 237.4,210.0 238.2,210.0 238.2,209.1 239.0,209.1 239.0,208.0 239.8,208.0 239.8,209.3 240.6,209.3 240.6,208.1 241.4,208.1 241.4,209.0 242.3,209.0 242.3,211.5 243.1,211.5 243.1,210.6 243.9,210.6 243.9,210.5 244.7,210.5 244.7,210.0 245.5,210.0 245.5,210.2 246.3,210.2 246.3,208.7 247.1,208.7 247.1,209.0 247.9,209.0 247.9,208.9 248.8,208.9 248.8,210.0 249.6,210.0 249.6,211.7 250.4,211.7 250.4,210.1 251.2,210.1 251.2,209.1 252.0,209.1 252.0,208.8 252.8,208.8 252.8,209.1 253.6,209.1 253.6,206.9 254.4,206.9 254.4,205.9 255.2,205.9 255.2,208.6 256.1,208.6 256.1,206.1 256.9,206.1 256.9,207.0 257.7,207.0 257.7,206.5 258.5,206.5 258.5,204.8 259.3,204.8 259.3,206.3 260.1,206.3 260.1,206.7 260.9,206.7 260.9,207.1 261.8,207.1 261.8,206.4 262.6,206.4 262.6,138.8 263.4,138.8 263.4,140.7 264.2,140.7 264.2,140.3 265.0,140.3 265.0,141.1 265.8,141.1 265.8,143.1 266.6,143.1 266.6,140.7 267.4,140.7 267.4,140.2 268.2,140.2 268.2,141.7 269.1,141.7 269.1,143.4 269.9,143.4 269.9,143.0 270.7,143.0 270.7,141.0 271.5,141.0 271.5,140.4 272.3,140.4 272.3,142.0 273.1,142.0 273.1,141.8 273.9,141.8 273.9,138.4 274.8,138.4 274.8,134.8 275.6,134.8 275.6,137.0 276.4,137.0 276.4,133.2 277.2,133.2 277.2,132.9 278.0,132.9 278.0,133.2 278.8,133.2 278.8,132.6 279.6,132.6 279.6,127.0 280.4,127.0 280.4,124.4 281.2,124.4 281.2,126.3 282.1,126.3 282.1,123.9 282.9,123.9 282.9,126.7 283.7,126.7 283.7,128.5 284.5,128.5 284.5,124.5 285.3,124.5 285.3,124.2 286.1,124.2 286.1,124.9 286.9,124.9 286.9,124.8 287.8,124.8 287.8,125.1 288.6,125.1 288.6,127.3 289.4,127.3 289.4,124.2 290.2,124.2 290.2,125.1 291.0,125.1 291.0,127.0 291.8,127.0 291.8,125.2 292.6,125.2 292.6,127.1 293.4,127.1 293.4,125.0 294.2,125.0 294.2,127.1 295.1,127.1 295.1,128.9 295.9,128.9 295.9,129.4 296.7,129.4 296.7,126.9 297.5,126.9 297.5,127.4 298.3,127.4 298.3,127.0 299.1,127.0 299.1,127.4 299.9,127.4 299.9,125.8 300.8,125.8 300.8,125.7 301.6,125.7 301.6,126.6 302.4,126.6 302.4,125.1 303.2,125.1 303.2,127.2 304.0,127.2 304.0,129.2 304.8,129.2 304.8,126.0 305.6,126.0 305.6,126.5 306.4,126.5 306.4,125.5 307.2,125.5 307.2,125.2 308.1,125.2 308.1,127.9 308.9,127.9 308.9,128.3 309.7,128.3 309.7,125.0 310.5,125.0 310.5,125.9 311.3,125.9 311.3,125.5 312.1,125.5 312.1,126.4 312.9,126.4 312.9,125.6 313.8,125.6 313.8,125.0 314.6,125.0 314.6,128.7 315.4,128.7 315.4,124.8 316.2,124.8 316.2,126.1 317.0,126.1 317.0,125.9 317.8,125.9 317.8,125.2 318.6,125.2 318.6,126.3 319.4,126.3 319.4,125.5 320.2,125.5 320.2,125.8 321.1,125.8 321.1,126.0 321.9,126.0 321.9,125.6 322.7,125.6 322.7,128.4 323.5,128.4 323.5,127.3 324.3,127.3 324.3,128.8 325.1,128.8 325.1,123.9 325.9,123.9 325.9,125.4 326.8,125.4 326.8,126.9 327.6,126.9 327.6,125.9 328.4,125.9 328.4,124.8 329.2,124.8 329.2,125.2 330.0,125.2 330.0,126.2"/> <circle class=nj-charts-json-dot cx=262.6 cy=138.8 r=3.5><title>#5828: 1.97&#215;</title></circle> <line class=nj-charts-grid x1=262.6 y1=54.0 x2=262.6 y2=133.8 stroke-dasharray="2 2"/> <circle class=nj-theme-dot cx=262.6 cy=46.0 r=7.5 /> <text class=nj-theme-num x=262.6 y=50.0 text-anchor=middle>1</text> <circle class=nj-charts-json-dot cx=279.6 cy=127.0 r=3.5><title>#5884: 2.2&#215;</title></circle> <line class=nj-charts-grid x1=279.6 y1=36.0 x2=279.6 y2=122.0 stroke-dasharray="2 2"/> <circle class=nj-theme-dot cx=279.6 cy=28.0 r=7.5 /> <text class=nj-theme-num x=279.6 y=32.0 text-anchor=middle>1</text> <line class=nj-charts-axis x1=44 y1=208 x2=330 y2=208 /> <text class=nj-charts-note x=8 y=262>speedup over 3.12.0 (log scale), more is better</text> </svg></p> </div> <div class=nj-fig-wrap> <p><svg class="nj-fig nj-charts nj-charts--timeline" viewbox="0 0 340 270" role=img aria-labelledby="nj-blog-tl-dump_canada nj-blog-tl-dump_canada-d" xmlns=http://www.w3.org/2000/svg> <title id=nj-blog-tl-dump_canada>dump() canada.json: speedup over 3.12.0 by commit</title> <desc id=nj-blog-tl-dump_canada-d>dump() canada.json: speedup over 3.12.0 at each of 353 commits, ending at 3.3x. Labeled steps, by theme: 6, 3.</desc> <text class=nj-charts-panel x=8 y=18>dump() canada.json</text> <line class=nj-charts-grid x1=44 y1=208 x2=330 y2=208 /> <text class="nj-charts-tick nj-charts-tick--r" x=38 y=212>1&#215;</text> <line class=nj-charts-grid x1=44 y1=160.667 x2=330 y2=160.667 /> <text class="nj-charts-tick nj-charts-tick--r" x=38 y=164.667>2&#215;</text> <line class=nj-charts-grid x1=44 y1=113.333 x2=330 y2=113.333 /> <text class="nj-charts-tick nj-charts-tick--r" x=38 y=117.333>4&#215;</text> <line class=nj-charts-grid x1=44 y1=66 x2=330 y2=66 /> <text class="nj-charts-tick nj-charts-tick--r" x=38 y=70>8&#215;</text> <line class=nj-charts-axis x1=44 y1=208 x2=44 y2=212 /> <text class=nj-charts-tick x=44 y=225>3.12.0</text> <line class=nj-charts-axis x1=117.938 y1=208 x2=117.938 y2=212 /> <text class=nj-charts-tick x=117.938 y=225>Sep 2026</text> <line class=nj-charts-axis x1=198.375 y1=208 x2=198.375 y2=212 /> <text class=nj-charts-tick x=198.375 y=225>Oct</text> <polyline class=nj-charts-json points="44.0,208.0 44.8,208.0 44.8,208.0 45.6,208.0 45.6,207.2 46.4,207.2 46.4,207.9 47.2,207.9 47.2,206.7 48.1,206.7 48.1,207.5 48.9,207.5 48.9,207.7 49.7,207.7 49.7,207.3 50.5,207.3 50.5,207.9 51.3,207.9 51.3,206.6 52.1,206.6 52.1,207.5 52.9,207.5 52.9,208.0 53.8,208.0 53.8,207.6 54.6,207.6 54.6,207.2 55.4,207.2 55.4,207.5 56.2,207.5 56.2,206.6 57.0,206.6 57.0,207.1 57.8,207.1 57.8,207.1 58.6,207.1 58.6,207.2 59.4,207.2 59.4,206.6 60.2,206.6 60.2,207.5 61.1,207.5 61.1,207.6 61.9,207.6 61.9,207.7 62.7,207.7 62.7,207.2 63.5,207.2 63.5,206.5 64.3,206.5 64.3,206.8 65.1,206.8 65.1,207.1 65.9,207.1 65.9,207.0 66.8,207.0 66.8,207.1 67.6,207.1 67.6,206.7 68.4,206.7 68.4,208.2 69.2,208.2 69.2,207.5 70.0,207.5 70.0,206.6 70.8,206.6 70.8,206.7 71.6,206.7 71.6,206.3 72.4,206.3 72.4,208.4 73.2,208.4 73.2,207.3 74.1,207.3 74.1,206.8 74.9,206.8 74.9,208.0 75.7,208.0 75.7,207.8 76.5,207.8 76.5,207.1 77.3,207.1 77.3,207.5 78.1,207.5 78.1,207.9 78.9,207.9 78.9,206.3 79.8,206.3 79.8,206.8 80.6,206.8 80.6,207.5 81.4,207.5 81.4,208.1 82.2,208.1 82.2,206.6 83.0,206.6 83.0,207.2 83.8,207.2 83.8,207.2 84.6,207.2 84.6,207.4 85.4,207.4 85.4,207.0 86.2,207.0 86.2,206.7 87.1,206.7 87.1,206.5 87.9,206.5 87.9,207.6 88.7,207.6 88.7,207.4 89.5,207.4 89.5,207.2 90.3,207.2 90.3,207.5 91.1,207.5 91.1,207.6 91.9,207.6 91.9,208.0 92.8,208.0 92.8,208.2 93.6,208.2 93.6,206.7 94.4,206.7 94.4,207.4 95.2,207.4 95.2,206.7 96.0,206.7 96.0,206.6 96.8,206.6 96.8,208.0 97.6,208.0 97.6,208.0 98.4,208.0 98.4,206.3 99.2,206.3 99.2,208.3 100.1,208.3 100.1,207.8 100.9,207.8 100.9,207.4 101.7,207.4 101.7,206.3 102.5,206.3 102.5,208.1 103.3,208.1 103.3,207.5 104.1,207.5 104.1,207.4 104.9,207.4 104.9,207.5 105.8,207.5 105.8,207.7 106.6,207.7 106.6,208.0 107.4,208.0 107.4,207.0 108.2,207.0 108.2,207.5 109.0,207.5 109.0,207.2 109.8,207.2 109.8,207.7 110.6,207.7 110.6,207.3 111.4,207.3 111.4,208.0 112.2,208.0 112.2,206.7 113.1,206.7 113.1,206.6 113.9,206.6 113.9,207.2 114.7,207.2 114.7,208.1 115.5,208.1 115.5,208.1 116.3,208.1 116.3,206.7 117.1,206.7 117.1,207.8 117.9,207.8 117.9,207.6 118.8,207.6 118.8,207.4 119.6,207.4 119.6,207.1 120.4,207.1 120.4,207.5 121.2,207.5 121.2,208.8 122.0,208.8 122.0,209.2 122.8,209.2 122.8,208.4 123.6,208.4 123.6,208.3 124.4,208.3 124.4,208.0 125.3,208.0 125.3,209.0 126.1,209.0 126.1,208.5 126.9,208.5 126.9,209.1 127.7,209.1 127.7,209.2 128.5,209.2 128.5,208.6 129.3,208.6 129.3,207.7 130.1,207.7 130.1,207.7 130.9,207.7 130.9,207.5 131.8,207.5 131.8,202.2 132.6,202.2 132.6,202.3 133.4,202.3 133.4,201.7 134.2,201.7 134.2,202.3 135.0,202.3 135.0,201.9 135.8,201.9 135.8,201.2 136.6,201.2 136.6,202.1 137.4,202.1 137.4,202.6 138.2,202.6 138.2,201.5 139.1,201.5 139.1,202.3 139.9,202.3 139.9,202.3 140.7,202.3 140.7,201.7 141.5,201.7 141.5,201.3 142.3,201.3 142.3,202.5 143.1,202.5 143.1,201.1 143.9,201.1 143.9,202.9 144.8,202.9 144.8,202.2 145.6,202.2 145.6,201.7 146.4,201.7 146.4,201.7 147.2,201.7 147.2,201.6 148.0,201.6 148.0,203.0 148.8,203.0 148.8,202.7 149.6,202.7 149.6,202.4 150.4,202.4 150.4,202.8 151.2,202.8 151.2,202.1 152.1,202.1 152.1,203.1 152.9,203.1 152.9,202.3 153.7,202.3 153.7,202.3 154.5,202.3 154.5,201.8 155.3,201.8 155.3,203.1 156.1,203.1 156.1,201.8 156.9,201.8 156.9,202.6 157.8,202.6 157.8,202.6 158.6,202.6 158.6,202.9 159.4,202.9 159.4,202.3 160.2,202.3 160.2,202.3 161.0,202.3 161.0,201.6 161.8,201.6 161.8,201.5 162.6,201.5 162.6,202.4 163.4,202.4 163.4,201.7 164.2,201.7 164.2,201.2 165.1,201.2 165.1,202.2 165.9,202.2 165.9,201.6 166.7,201.6 166.7,201.6 167.5,201.6 167.5,201.8 168.3,201.8 168.3,202.1 169.1,202.1 169.1,201.7 169.9,201.7 169.9,201.4 170.8,201.4 170.8,202.2 171.6,202.2 171.6,202.7 172.4,202.7 172.4,202.4 173.2,202.4 173.2,201.7 174.0,201.7 174.0,201.7 174.8,201.7 174.8,202.3 175.6,202.3 175.6,201.6 176.4,201.6 176.4,201.7 177.2,201.7 177.2,202.2 178.1,202.2 178.1,202.2 178.9,202.2 178.9,202.4 179.7,202.4 179.7,201.7 180.5,201.7 180.5,202.1 181.3,202.1 181.3,201.6 182.1,201.6 182.1,202.2 182.9,202.2 182.9,201.9 183.8,201.9 183.8,201.9 184.6,201.9 184.6,202.5 185.4,202.5 185.4,201.6 186.2,201.6 186.2,202.1 187.0,202.1 187.0,202.3 187.8,202.3 187.8,201.8 188.6,201.8 188.6,201.5 189.4,201.5 189.4,202.3 190.2,202.3 190.2,202.2 191.1,202.2 191.1,202.9 191.9,202.9 191.9,201.3 192.7,201.3 192.7,202.2 193.5,202.2 193.5,203.6 194.3,203.6 194.3,201.9 195.1,201.9 195.1,202.4 195.9,202.4 195.9,201.7 196.8,201.7 196.8,202.7 197.6,202.7 197.6,202.3 198.4,202.3 198.4,202.5 199.2,202.5 199.2,202.1 200.0,202.1 200.0,203.4 200.8,203.4 200.8,202.1 201.6,202.1 201.6,202.3 202.4,202.3 202.4,201.9 203.2,201.9 203.2,202.3 204.1,202.3 204.1,201.7 204.9,201.7 204.9,202.4 205.7,202.4 205.7,202.3 206.5,202.3 206.5,202.9 207.3,202.9 207.3,202.9 208.1,202.9 208.1,202.2 208.9,202.2 208.9,202.4 209.8,202.4 209.8,202.2 210.6,202.2 210.6,202.7 211.4,202.7 211.4,202.5 212.2,202.5 212.2,202.5 213.0,202.5 213.0,201.5 213.8,201.5 213.8,203.1 214.6,203.1 214.6,203.2 215.4,203.2 215.4,201.5 216.2,201.5 216.2,203.3 217.1,203.3 217.1,202.4 217.9,202.4 217.9,201.8 218.7,201.8 218.7,202.5 219.5,202.5 219.5,201.7 220.3,201.7 220.3,202.1 221.1,202.1 221.1,202.0 221.9,202.0 221.9,202.9 222.8,202.9 222.8,202.1 223.6,202.1 223.6,202.6 224.4,202.6 224.4,202.3 225.2,202.3 225.2,202.4 226.0,202.4 226.0,202.9 226.8,202.9 226.8,201.9 227.6,201.9 227.6,203.4 228.4,203.4 228.4,202.3 229.2,202.3 229.2,202.3 230.1,202.3 230.1,202.7 230.9,202.7 230.9,202.5 231.7,202.5 231.7,202.3 232.5,202.3 232.5,203.8 233.3,203.8 233.3,202.7 234.1,202.7 234.1,202.1 234.9,202.1 234.9,202.0 235.8,202.0 235.8,202.7 236.6,202.7 236.6,201.9 237.4,201.9 237.4,202.0 238.2,202.0 238.2,202.3 239.0,202.3 239.0,202.7 239.8,202.7 239.8,201.6 240.6,201.6 240.6,202.1 241.4,202.1 241.4,202.3 242.3,202.3 242.3,203.0 243.1,203.0 243.1,202.7 243.9,202.7 243.9,202.9 244.7,202.9 244.7,203.1 245.5,203.1 245.5,202.6 246.3,202.6 246.3,130.7 247.1,130.7 247.1,130.0 247.9,130.0 247.9,130.6 248.8,130.6 248.8,130.9 249.6,130.9 249.6,130.9 250.4,130.9 250.4,130.8 251.2,130.8 251.2,130.5 252.0,130.5 252.0,130.8 252.8,130.8 252.8,130.7 253.6,130.7 253.6,130.7 254.4,130.7 254.4,130.3 255.2,130.3 255.2,131.1 256.1,131.1 256.1,131.0 256.9,131.0 256.9,130.7 257.7,130.7 257.7,131.0 258.5,131.0 258.5,130.1 259.3,130.1 259.3,129.5 260.1,129.5 260.1,130.8 260.9,130.8 260.9,131.1 261.8,131.1 261.8,130.2 262.6,130.2 262.6,130.0 263.4,130.0 263.4,129.9 264.2,129.9 264.2,130.1 265.0,130.1 265.0,129.9 265.8,129.9 265.8,129.6 266.6,129.6 266.6,129.9 267.4,129.9 267.4,130.5 268.2,130.5 268.2,130.5 269.1,130.5 269.1,130.7 269.9,130.7 269.9,130.0 270.7,130.0 270.7,130.0 271.5,130.0 271.5,130.3 272.3,130.3 272.3,130.4 273.1,130.4 273.1,131.1 273.9,131.1 273.9,130.5 274.8,130.5 274.8,130.5 275.6,130.5 275.6,131.4 276.4,131.4 276.4,129.8 277.2,129.8 277.2,131.0 278.0,131.0 278.0,130.3 278.8,130.3 278.8,130.5 279.6,130.5 279.6,131.1 280.4,131.1 280.4,130.3 281.2,130.3 281.2,126.5 282.1,126.5 282.1,127.2 282.9,127.2 282.9,127.8 283.7,127.8 283.7,127.4 284.5,127.4 284.5,126.5 285.3,126.5 285.3,127.2 286.1,127.2 286.1,126.4 286.9,126.4 286.9,126.7 287.8,126.7 287.8,126.9 288.6,126.9 288.6,127.0 289.4,127.0 289.4,126.5 290.2,126.5 290.2,126.9 291.0,126.9 291.0,126.8 291.8,126.8 291.8,126.0 292.6,126.0 292.6,127.6 293.4,127.6 293.4,126.7 294.2,126.7 294.2,126.6 295.1,126.6 295.1,127.3 295.9,127.3 295.9,127.3 296.7,127.3 296.7,127.2 297.5,127.2 297.5,127.4 298.3,127.4 298.3,127.5 299.1,127.5 299.1,127.2 299.9,127.2 299.9,127.6 300.8,127.6 300.8,126.6 301.6,126.6 301.6,127.3 302.4,127.3 302.4,127.1 303.2,127.1 303.2,127.8 304.0,127.8 304.0,128.4 304.8,128.4 304.8,127.6 305.6,127.6 305.6,126.7 306.4,126.7 306.4,127.2 307.2,127.2 307.2,127.0 308.1,127.0 308.1,127.7 308.9,127.7 308.9,128.4 309.7,128.4 309.7,126.9 310.5,126.9 310.5,127.1 311.3,127.1 311.3,127.4 312.1,127.4 312.1,127.4 312.9,127.4 312.9,127.0 313.8,127.0 313.8,126.7 314.6,126.7 314.6,127.7 315.4,127.7 315.4,126.9 316.2,126.9 316.2,127.4 317.0,127.4 317.0,127.2 317.8,127.2 317.8,126.9 318.6,126.9 318.6,127.0 319.4,127.0 319.4,127.4 320.2,127.4 320.2,127.3 321.1,127.3 321.1,127.4 321.9,127.4 321.9,127.5 322.7,127.5 322.7,128.1 323.5,128.1 323.5,127.3 324.3,127.3 324.3,127.7 325.1,127.7 325.1,126.9 325.9,126.9 325.9,127.0 326.8,127.0 326.8,128.6 327.6,128.6 327.6,127.0 328.4,127.0 328.4,128.3 329.2,128.3 329.2,127.8 330.0,127.8 330.0,126.7"/> <circle class=nj-charts-json-dot cx=131.8 cy=202.2 r=3.5><title>#5285: 1.09&#215;</title></circle> <line class=nj-charts-grid x1=131.8 y1=54.0 x2=131.8 y2=197.2 stroke-dasharray="2 2"/> <circle class=nj-theme-dot cx=131.8 cy=46.0 r=7.5 /> <text class=nj-theme-num x=131.8 y=50.0 text-anchor=middle>6</text> <circle class=nj-charts-json-dot cx=246.3 cy=130.7 r=3.5><title>#5634: 3.1&#215;</title></circle> <line class=nj-charts-grid x1=246.3 y1=54.0 x2=246.3 y2=125.7 stroke-dasharray="2 2"/> <circle class=nj-theme-dot cx=246.3 cy=46.0 r=7.5 /> <text class=nj-theme-num x=246.3 y=50.0 text-anchor=middle>3</text> <line class=nj-charts-axis x1=44 y1=208 x2=330 y2=208 /> <text class=nj-charts-note x=8 y=262>speedup over 3.12.0 (log scale), more is better</text> </svg></p> </div> <div class=nj-fig-wrap> <p><svg class="nj-fig nj-charts nj-charts--timeline" viewbox="0 0 340 270" role=img aria-labelledby="nj-blog-tl-to_cbor_twitter nj-blog-tl-to_cbor_twitter-d" xmlns=http://www.w3.org/2000/svg> <title id=nj-blog-tl-to_cbor_twitter>to_cbor() twitter: speedup over 3.12.0 by commit</title> <desc id=nj-blog-tl-to_cbor_twitter-d>to_cbor() twitter: speedup over 3.12.0 at each of 353 commits, ending at 5.0x. Labeled steps, by theme: 4, 6, 6.</desc> <text class=nj-charts-panel x=8 y=18>to_cbor() twitter</text> <line class=nj-charts-grid x1=44 y1=208 x2=330 y2=208 /> <text class="nj-charts-tick nj-charts-tick--r" x=38 y=212>1&#215;</text> <line class=nj-charts-grid x1=44 y1=160.667 x2=330 y2=160.667 /> <text class="nj-charts-tick nj-charts-tick--r" x=38 y=164.667>2&#215;</text> <line class=nj-charts-grid x1=44 y1=113.333 x2=330 y2=113.333 /> <text class="nj-charts-tick nj-charts-tick--r" x=38 y=117.333>4&#215;</text> <line class=nj-charts-grid x1=44 y1=66 x2=330 y2=66 /> <text class="nj-charts-tick nj-charts-tick--r" x=38 y=70>8&#215;</text> <line class=nj-charts-axis x1=44 y1=208 x2=44 y2=212 /> <text class=nj-charts-tick x=44 y=225>3.12.0</text> <line class=nj-charts-axis x1=117.938 y1=208 x2=117.938 y2=212 /> <text class=nj-charts-tick x=117.938 y=225>Sep 2026</text> <line class=nj-charts-axis x1=198.375 y1=208 x2=198.375 y2=212 /> <text class=nj-charts-tick x=198.375 y=225>Oct</text> <polyline class=nj-charts-json points="44.0,208.0 44.8,208.0 44.8,208.0 45.6,208.0 45.6,204.9 46.4,204.9 46.4,205.2 47.2,205.2 47.2,204.7 48.1,204.7 48.1,205.2 48.9,205.2 48.9,205.0 49.7,205.0 49.7,204.9 50.5,204.9 50.5,205.0 51.3,205.0 51.3,205.0 52.1,205.0 52.1,205.1 52.9,205.1 52.9,205.4 53.8,205.4 53.8,205.0 54.6,205.0 54.6,205.2 55.4,205.2 55.4,211.6 56.2,211.6 56.2,206.8 57.0,206.8 57.0,204.2 57.8,204.2 57.8,207.6 58.6,207.6 58.6,204.1 59.4,204.1 59.4,203.8 60.2,203.8 60.2,204.2 61.1,204.2 61.1,205.1 61.9,205.1 61.9,204.4 62.7,204.4 62.7,204.3 63.5,204.3 63.5,204.0 64.3,204.0 64.3,202.7 65.1,202.7 65.1,204.2 65.9,204.2 65.9,204.2 66.8,204.2 66.8,204.2 67.6,204.2 67.6,204.4 68.4,204.4 68.4,206.2 69.2,206.2 69.2,204.3 70.0,204.3 70.0,204.1 70.8,204.1 70.8,204.3 71.6,204.3 71.6,204.3 72.4,204.3 72.4,204.3 73.2,204.3 73.2,204.3 74.1,204.3 74.1,204.4 74.9,204.4 74.9,204.8 75.7,204.8 75.7,208.4 76.5,208.4 76.5,203.5 77.3,203.5 77.3,206.2 78.1,206.2 78.1,204.4 78.9,204.4 78.9,203.2 79.8,203.2 79.8,204.1 80.6,204.1 80.6,204.2 81.4,204.2 81.4,203.7 82.2,203.7 82.2,204.2 83.0,204.2 83.0,203.2 83.8,203.2 83.8,204.2 84.6,204.2 84.6,204.4 85.4,204.4 85.4,203.8 86.2,203.8 86.2,204.4 87.1,204.4 87.1,204.7 87.9,204.7 87.9,204.6 88.7,204.6 88.7,208.7 89.5,208.7 89.5,205.2 90.3,205.2 90.3,205.5 91.1,205.5 91.1,205.2 91.9,205.2 91.9,205.3 92.8,205.3 92.8,206.8 93.6,206.8 93.6,204.6 94.4,204.6 94.4,205.5 95.2,205.5 95.2,205.1 96.0,205.1 96.0,204.7 96.8,204.7 96.8,205.7 97.6,205.7 97.6,205.0 98.4,205.0 98.4,204.9 99.2,204.9 99.2,206.5 100.1,206.5 100.1,205.6 100.9,205.6 100.9,205.0 101.7,205.0 101.7,209.2 102.5,209.2 102.5,205.9 103.3,205.9 103.3,206.5 104.1,206.5 104.1,205.5 104.9,205.5 104.9,205.3 105.8,205.3 105.8,205.3 106.6,205.3 106.6,205.1 107.4,205.1 107.4,204.4 108.2,204.4 108.2,204.6 109.0,204.6 109.0,204.8 109.8,204.8 109.8,204.2 110.6,204.2 110.6,203.8 111.4,203.8 111.4,204.4 112.2,204.4 112.2,202.8 113.1,202.8 113.1,203.5 113.9,203.5 113.9,204.0 114.7,204.0 114.7,204.3 115.5,204.3 115.5,202.9 116.3,202.9 116.3,203.3 117.1,203.3 117.1,204.4 117.9,204.4 117.9,204.5 118.8,204.5 118.8,204.1 119.6,204.1 119.6,208.3 120.4,208.3 120.4,203.8 121.2,203.8 121.2,207.0 122.0,207.0 122.0,205.9 122.8,205.9 122.8,205.4 123.6,205.4 123.6,205.3 124.4,205.3 124.4,205.8 125.3,205.8 125.3,205.4 126.1,205.4 126.1,205.6 126.9,205.6 126.9,206.3 127.7,206.3 127.7,205.5 128.5,205.5 128.5,204.8 129.3,204.8 129.3,204.6 130.1,204.6 130.1,206.1 130.9,206.1 130.9,204.6 131.8,204.6 131.8,204.1 132.6,204.1 132.6,204.3 133.4,204.3 133.4,205.6 134.2,205.6 134.2,203.9 135.0,203.9 135.0,204.0 135.8,204.0 135.8,203.9 136.6,203.9 136.6,204.6 137.4,204.6 137.4,204.1 138.2,204.1 138.2,203.9 139.1,203.9 139.1,204.8 139.9,204.8 139.9,203.2 140.7,203.2 140.7,203.3 141.5,203.3 141.5,204.7 142.3,204.7 142.3,208.3 143.1,208.3 143.1,204.3 143.9,204.3 143.9,207.4 144.8,207.4 144.8,204.4 145.6,204.4 145.6,208.2 146.4,208.2 146.4,205.0 147.2,205.0 147.2,204.9 148.0,204.9 148.0,208.8 148.8,208.8 148.8,207.9 149.6,207.9 149.6,206.2 150.4,206.2 150.4,204.2 151.2,204.2 151.2,204.1 152.1,204.1 152.1,204.2 152.9,204.2 152.9,202.2 153.7,202.2 153.7,205.6 154.5,205.6 154.5,203.0 155.3,203.0 155.3,203.4 156.1,203.4 156.1,202.7 156.9,202.7 156.9,203.6 157.8,203.6 157.8,203.3 158.6,203.3 158.6,203.2 159.4,203.2 159.4,204.9 160.2,204.9 160.2,202.9 161.0,202.9 161.0,202.2 161.8,202.2 161.8,202.5 162.6,202.5 162.6,202.9 163.4,202.9 163.4,202.9 164.2,202.9 164.2,202.3 165.1,202.3 165.1,202.9 165.9,202.9 165.9,203.7 166.7,203.7 166.7,204.1 167.5,204.1 167.5,203.9 168.3,203.9 168.3,203.7 169.1,203.7 169.1,203.3 169.9,203.3 169.9,203.8 170.8,203.8 170.8,205.0 171.6,205.0 171.6,208.0 172.4,208.0 172.4,205.1 173.2,205.1 173.2,206.5 174.0,206.5 174.0,205.4 174.8,205.4 174.8,205.4 175.6,205.4 175.6,207.0 176.4,207.0 176.4,204.9 177.2,204.9 177.2,205.4 178.1,205.4 178.1,203.6 178.9,203.6 178.9,205.7 179.7,205.7 179.7,204.5 180.5,204.5 180.5,205.0 181.3,205.0 181.3,205.2 182.1,205.2 182.1,204.9 182.9,204.9 182.9,204.5 183.8,204.5 183.8,204.9 184.6,204.9 184.6,205.3 185.4,205.3 185.4,203.9 186.2,203.9 186.2,204.8 187.0,204.8 187.0,204.8 187.8,204.8 187.8,203.6 188.6,203.6 188.6,203.4 189.4,203.4 189.4,203.8 190.2,203.8 190.2,205.1 191.1,205.1 191.1,205.5 191.9,205.5 191.9,204.0 192.7,204.0 192.7,204.9 193.5,204.9 193.5,205.0 194.3,205.0 194.3,206.4 195.1,206.4 195.1,205.1 195.9,205.1 195.9,204.5 196.8,204.5 196.8,204.8 197.6,204.8 197.6,205.2 198.4,205.2 198.4,205.0 199.2,205.0 199.2,204.6 200.0,204.6 200.0,203.9 200.8,203.9 200.8,203.5 201.6,203.5 201.6,203.6 202.4,203.6 202.4,204.2 203.2,204.2 203.2,205.9 204.1,205.9 204.1,205.2 204.9,205.2 204.9,204.8 205.7,204.8 205.7,207.3 206.5,207.3 206.5,205.2 207.3,205.2 207.3,208.6 208.1,208.6 208.1,204.3 208.9,204.3 208.9,203.9 209.8,203.9 209.8,203.2 210.6,203.2 210.6,203.9 211.4,203.9 211.4,205.9 212.2,205.9 212.2,204.8 213.0,204.8 213.0,204.7 213.8,204.7 213.8,203.6 214.6,203.6 214.6,203.7 215.4,203.7 215.4,208.2 216.2,208.2 216.2,208.4 217.1,208.4 217.1,208.2 217.9,208.2 217.9,208.1 218.7,208.1 218.7,208.5 219.5,208.5 219.5,209.0 220.3,209.0 220.3,208.3 221.1,208.3 221.1,208.6 221.9,208.6 221.9,205.4 222.8,205.4 222.8,205.3 223.6,205.3 223.6,206.0 224.4,206.0 224.4,206.2 225.2,206.2 225.2,205.9 226.0,205.9 226.0,206.3 226.8,206.3 226.8,208.4 227.6,208.4 227.6,209.0 228.4,209.0 228.4,208.9 229.2,208.9 229.2,209.3 230.1,209.3 230.1,210.4 230.9,210.4 230.9,207.9 231.7,207.9 231.7,208.1 232.5,208.1 232.5,208.2 233.3,208.2 233.3,208.8 234.1,208.8 234.1,208.6 234.9,208.6 234.9,153.7 235.8,153.7 235.8,153.8 236.6,153.8 236.6,153.8 237.4,153.8 237.4,153.3 238.2,153.3 238.2,153.6 239.0,153.6 239.0,156.0 239.8,156.0 239.8,156.0 240.6,156.0 240.6,155.9 241.4,155.9 241.4,156.0 242.3,156.0 242.3,156.3 243.1,156.3 243.1,154.1 243.9,154.1 243.9,154.0 244.7,154.0 244.7,153.8 245.5,153.8 245.5,156.1 246.3,156.1 246.3,155.8 247.1,155.8 247.1,154.2 247.9,154.2 247.9,154.1 248.8,154.1 248.8,154.3 249.6,154.3 249.6,154.2 250.4,154.2 250.4,154.2 251.2,154.2 251.2,154.1 252.0,154.1 252.0,153.7 252.8,153.7 252.8,153.9 253.6,153.9 253.6,154.4 254.4,154.4 254.4,156.0 255.2,156.0 255.2,156.5 256.1,156.5 256.1,156.8 256.9,156.8 256.9,156.3 257.7,156.3 257.7,156.1 258.5,156.1 258.5,155.6 259.3,155.6 259.3,156.0 260.1,156.0 260.1,156.4 260.9,156.4 260.9,156.2 261.8,156.2 261.8,155.8 262.6,155.8 262.6,155.1 263.4,155.1 263.4,156.8 264.2,156.8 264.2,155.4 265.0,155.4 265.0,155.9 265.8,155.9 265.8,155.9 266.6,155.9 266.6,155.9 267.4,155.9 267.4,155.3 268.2,155.3 268.2,155.8 269.1,155.8 269.1,156.0 269.9,156.0 269.9,123.4 270.7,123.4 270.7,123.3 271.5,123.3 271.5,123.1 272.3,123.1 272.3,125.9 273.1,125.9 273.1,125.8 273.9,125.8 273.9,125.4 274.8,125.4 274.8,123.0 275.6,123.0 275.6,123.6 276.4,123.6 276.4,123.0 277.2,123.0 277.2,123.0 278.0,123.0 278.0,122.4 278.8,122.4 278.8,123.2 279.6,123.2 279.6,123.4 280.4,123.4 280.4,123.2 281.2,123.2 281.2,123.1 282.1,123.1 282.1,96.9 282.9,96.9 282.9,97.9 283.7,97.9 283.7,98.3 284.5,98.3 284.5,97.5 285.3,97.5 285.3,97.6 286.1,97.6 286.1,97.3 286.9,97.3 286.9,97.6 287.8,97.6 287.8,97.7 288.6,97.7 288.6,97.5 289.4,97.5 289.4,97.2 290.2,97.2 290.2,97.3 291.0,97.3 291.0,97.2 291.8,97.2 291.8,97.4 292.6,97.4 292.6,98.2 293.4,98.2 293.4,97.5 294.2,97.5 294.2,97.3 295.1,97.3 295.1,98.5 295.9,98.5 295.9,98.0 296.7,98.0 296.7,97.7 297.5,97.7 297.5,97.9 298.3,97.9 298.3,97.8 299.1,97.8 299.1,97.6 299.9,97.6 299.9,97.7 300.8,97.7 300.8,97.8 301.6,97.8 301.6,98.4 302.4,98.4 302.4,97.5 303.2,97.5 303.2,98.2 304.0,98.2 304.0,98.2 304.8,98.2 304.8,97.8 305.6,97.8 305.6,97.3 306.4,97.3 306.4,97.8 307.2,97.8 307.2,97.6 308.1,97.6 308.1,97.8 308.9,97.8 308.9,97.9 309.7,97.9 309.7,97.8 310.5,97.8 310.5,97.4 311.3,97.4 311.3,97.2 312.1,97.2 312.1,98.0 312.9,98.0 312.9,98.3 313.8,98.3 313.8,97.9 314.6,97.9 314.6,98.1 315.4,98.1 315.4,97.7 316.2,97.7 316.2,98.0 317.0,98.0 317.0,97.9 317.8,97.9 317.8,97.7 318.6,97.7 318.6,97.6 319.4,97.6 319.4,97.9 320.2,97.9 320.2,98.0 321.1,98.0 321.1,98.0 321.9,98.0 321.9,97.5 322.7,97.5 322.7,97.9 323.5,97.9 323.5,98.6 324.3,98.6 324.3,97.7 325.1,97.7 325.1,97.5 325.9,97.5 325.9,97.5 326.8,97.5 326.8,98.1 327.6,98.1 327.6,98.2 328.4,98.2 328.4,98.3 329.2,98.3 329.2,98.3 330.0,98.3 330.0,97.4"/> <circle class=nj-charts-json-dot cx=234.9 cy=153.7 r=3.5><title>#5328: 2.2&#215;</title></circle> <line class=nj-charts-grid x1=234.9 y1=54.0 x2=234.9 y2=148.7 stroke-dasharray="2 2"/> <circle class=nj-theme-dot cx=234.9 cy=46.0 r=7.5 /> <text class=nj-theme-num x=234.9 y=50.0 text-anchor=middle>4</text> <circle class=nj-charts-json-dot cx=269.9 cy=123.4 r=3.5><title>#5824: 3.5&#215;</title></circle> <line class=nj-charts-grid x1=269.9 y1=54.0 x2=269.9 y2=118.4 stroke-dasharray="2 2"/> <circle class=nj-theme-dot cx=269.9 cy=46.0 r=7.5 /> <text class=nj-theme-num x=269.9 y=50.0 text-anchor=middle>6</text> <circle class=nj-charts-json-dot cx=282.1 cy=96.9 r=3.5><title>#5885: 5.1&#215;</title></circle> <line class=nj-charts-grid x1=282.1 y1=36.0 x2=282.1 y2=91.9 stroke-dasharray="2 2"/> <circle class=nj-theme-dot cx=282.1 cy=28.0 r=7.5 /> <text class=nj-theme-num x=282.1 y=32.0 text-anchor=middle>6</text> <line class=nj-charts-axis x1=44 y1=208 x2=330 y2=208 /> <text class=nj-charts-note x=8 y=262>speedup over 3.12.0 (log scale), more is better</text> </svg></p> </div> </div> <p class=nj-caption>Speedup over 3.12.0 after each commit that changed the headers, for the four workloads not shown in the timeline section. More is better; the badges are theme numbers.</p> <p>The parse panels include destroying the result: the benchmark returns <code>json::parse(text).size()</code>, so the changes to the destructor (<a href="https://github.com/nlohmann/json/pull/5762">#5762</a>, <a href="https://github.com/nlohmann/json/pull/5835">#5835</a>) show up there too, as steps of up to 6% in either direction. When <code>accept()</code> of <code>twitter.json</code> got 2.5% slower over the last 20 commits, we timed the two ends against each other in one binary with six code layouts: they were equal within 0.2%.</p> <table> <thead> <tr> <th>workload</th> <th style="text-align: center;">theme</th> <th>pull request</th> <th>change</th> <th style="text-align: right;">step</th> </tr> </thead> <tbody> <tr> <td><code>parse()</code> <code>citm_catalog.json</code></td> <td style="text-align: center;"><span class=nj-theme>4</span></td> <td><a href="https://github.com/nlohmann/json/pull/5234">#5234</a></td> <td>the token buffer is filled only for error messages</td> <td style="text-align: right;">−35%</td> </tr> <tr> <td></td> <td style="text-align: center;"><span class=nj-theme>1</span></td> <td><a href="https://github.com/nlohmann/json/pull/5283">#5283</a></td> <td>fast paths for contiguous input</td> <td style="text-align: right;">−19%</td> </tr> <tr> <td></td> <td style="text-align: center;"><span class=nj-theme>4</span></td> <td><a href="https://github.com/nlohmann/json/pull/5592">#5592</a></td> <td>check for the expected <code>:</code> or <code>,</code> before the lexer's token switch</td> <td style="text-align: right;">−7%</td> </tr> <tr> <td></td> <td style="text-align: center;"><span class=nj-theme>4</span></td> <td><a href="https://github.com/nlohmann/json/pull/5809">#5809</a></td> <td>positions derived only on error</td> <td style="text-align: right;">−12%</td> </tr> <tr> <td></td> <td style="text-align: center;"><span class=nj-theme>2</span></td> <td><a href="https://github.com/nlohmann/json/pull/5810">#5810</a></td> <td>indentation skipped eight bytes at a time</td> <td style="text-align: right;">−12%</td> </tr> <tr> <td></td> <td style="text-align: center;"><span class=nj-theme>4</span></td> <td><a href="https://github.com/nlohmann/json/pull/5882">#5882</a></td> <td>arrays allocated once, at their final size</td> <td style="text-align: right;">−6%</td> </tr> <tr> <td><code>parse()</code> <code>canada.json</code></td> <td style="text-align: center;"><span class=nj-theme>4</span></td> <td><a href="https://github.com/nlohmann/json/pull/5234">#5234</a></td> <td>the token buffer is filled only for error messages</td> <td style="text-align: right;">−10%</td> </tr> <tr> <td></td> <td style="text-align: center;"><span class=nj-theme>1</span></td> <td><a href="https://github.com/nlohmann/json/pull/5283">#5283</a></td> <td>fast paths for contiguous input</td> <td style="text-align: right;">−24%</td> </tr> <tr> <td></td> <td style="text-align: center;"><span class=nj-theme>3</span></td> <td><a href="https://github.com/nlohmann/json/pull/5617">#5617</a></td> <td>Eisel-Lemire instead of <code>strtod</code></td> <td style="text-align: right;">−9%</td> </tr> <tr> <td></td> <td style="text-align: center;"><span class=nj-theme>3</span></td> <td><a href="https://github.com/nlohmann/json/pull/5738">#5738</a></td> <td>own float parser, string scan, <code>\u</code> table</td> <td style="text-align: right;">−14%</td> </tr> <tr> <td></td> <td style="text-align: center;"><span class=nj-theme>3</span></td> <td><a href="https://github.com/nlohmann/json/pull/5851">#5851</a></td> <td>digits accumulated while validating, eight at a time</td> <td style="text-align: right;">−12%</td> </tr> <tr> <td></td> <td style="text-align: center;"><span class=nj-theme>4</span></td> <td><a href="https://github.com/nlohmann/json/pull/5882">#5882</a></td> <td>arrays allocated once, at their final size</td> <td style="text-align: right;">−15%</td> </tr> <tr> <td><code>accept()</code> <code>twitter.json</code></td> <td style="text-align: center;"><span class=nj-theme>4</span></td> <td><a href="https://github.com/nlohmann/json/pull/5234">#5234</a></td> <td>the token buffer is filled only for error messages</td> <td style="text-align: right;">−18%</td> </tr> <tr> <td></td> <td style="text-align: center;"><span class=nj-theme>1</span></td> <td><a href="https://github.com/nlohmann/json/pull/5283">#5283</a></td> <td>fast paths for contiguous input</td> <td style="text-align: right;">−53%</td> </tr> <tr> <td></td> <td style="text-align: center;"><span class=nj-theme>4</span></td> <td><a href="https://github.com/nlohmann/json/pull/5592">#5592</a></td> <td>check for the expected <code>:</code> or <code>,</code> before the lexer's token switch</td> <td style="text-align: right;">−11%</td> </tr> <tr> <td></td> <td style="text-align: center;"><span class=nj-theme>4</span></td> <td><a href="https://github.com/nlohmann/json/pull/5809">#5809</a></td> <td>positions derived only on error</td> <td style="text-align: right;">−23%</td> </tr> <tr> <td></td> <td style="text-align: center;"><span class=nj-theme>2</span></td> <td><a href="https://github.com/nlohmann/json/pull/5810">#5810</a></td> <td>indentation skipped eight bytes at a time</td> <td style="text-align: right;">−9%</td> </tr> <tr> <td></td> <td style="text-align: center;"><span class=nj-theme>2</span></td> <td><a href="https://github.com/nlohmann/json/pull/5853">#5853</a></td> <td>strings scanned 16 bytes at a time with <abbr title="Streaming SIMD Extensions 2">SSE2</abbr> or <abbr title="Arm SIMD instruction set extension">NEON</abbr></td> <td style="text-align: right;">−11%</td> </tr> <tr> <td><code>parse()</code> <code>twitter.json</code>, <code>std::ifstream</code></td> <td style="text-align: center;"><span class=nj-theme>1</span></td> <td><a href="https://github.com/nlohmann/json/pull/5828">#5828</a></td> <td>scanning the stream's get area in bulk</td> <td style="text-align: right;">−48%</td> </tr> <tr> <td></td> <td style="text-align: center;"><span class=nj-theme>1</span></td> <td><a href="https://github.com/nlohmann/json/pull/5884">#5884</a></td> <td>inline get-area path, binary reads</td> <td style="text-align: right;">−5%</td> </tr> <tr> <td><code>dump()</code> <code>twitter.json</code></td> <td style="text-align: center;"><span class=nj-theme>6</span></td> <td><a href="https://github.com/nlohmann/json/pull/5285">#5285</a></td> <td>a write buffer and bulk copies of strings</td> <td style="text-align: right;">−70%</td> </tr> <tr> <td></td> <td style="text-align: center;"><span class=nj-theme>2</span></td> <td><a href="https://github.com/nlohmann/json/pull/5738">#5738</a></td> <td>own float parser, string scan, <code>\u</code> table</td> <td style="text-align: right;">−19%</td> </tr> <tr> <td></td> <td style="text-align: center;"><span class=nj-theme>2</span></td> <td><a href="https://github.com/nlohmann/json/pull/5878">#5878</a></td> <td>short strings checked with a table</td> <td style="text-align: right;">−6%</td> </tr> <tr> <td></td> <td style="text-align: center;"><span class=nj-theme>2</span></td> <td><a href="https://github.com/nlohmann/json/pull/5883">#5883</a></td> <td>strings of 16–32 bytes as two overlapping vectors</td> <td style="text-align: right;">−34%</td> </tr> <tr> <td><code>dump()</code> <code>canada.json</code></td> <td style="text-align: center;"><span class=nj-theme>6</span></td> <td><a href="https://github.com/nlohmann/json/pull/5285">#5285</a></td> <td>a write buffer and bulk copies of strings</td> <td style="text-align: right;">−8%</td> </tr> <tr> <td></td> <td style="text-align: center;"><span class=nj-theme>3</span></td> <td><a href="https://github.com/nlohmann/json/pull/5634">#5634</a></td> <td>Żmij instead of Grisu2</td> <td style="text-align: right;">−65%</td> </tr> <tr> <td><code>from_cbor()</code> <code>twitter.json</code></td> <td style="text-align: center;"><span class=nj-theme>1</span></td> <td><a href="https://github.com/nlohmann/json/pull/5233">#5233</a></td> <td>binary strings read in bulk</td> <td style="text-align: right;">−32%</td> </tr> <tr> <td></td> <td style="text-align: center;"><span class=nj-theme>4</span></td> <td><a href="https://github.com/nlohmann/json/pull/5501">#5501</a></td> <td>the result moved instead of copied</td> <td style="text-align: right;">−33%</td> </tr> <tr> <td></td> <td style="text-align: center;"><span class="nj-theme nj-theme--other">U</span></td> <td><a href="https://github.com/nlohmann/json/pull/5185">#5185</a>, <a href="https://github.com/nlohmann/json/pull/5531">#5531</a></td> <td><abbr title="Unicode Transformation Format">UTF</abbr>-8 validation of every text string</td> <td style="text-align: right;">+37%</td> </tr> <tr> <td></td> <td style="text-align: center;"><span class="nj-theme nj-theme--other">U</span></td> <td><a href="https://github.com/nlohmann/json/pull/5746">#5746</a></td> <td>the validation made an option (<a href="https://github.com/nlohmann/json/pull/5741">#5741</a>)</td> <td style="text-align: right;">−27%</td> </tr> <tr> <td><code>to_cbor()</code> <code>twitter.json</code></td> <td style="text-align: center;"><span class=nj-theme>4</span></td> <td><a href="https://github.com/nlohmann/json/pull/5328">#5328</a></td> <td>no temporary <code>basic_json</code> per object key (by <a href="https://github.com/alexprabhat99">@alexprabhat99</a>)</td> <td style="text-align: right;">−55%</td> </tr> <tr> <td></td> <td style="text-align: center;"><span class=nj-theme>6</span></td> <td><a href="https://github.com/nlohmann/json/pull/5824">#5824</a></td> <td>a cursor instead of <code>vector::insert()</code></td> <td style="text-align: right;">−38%</td> </tr> <tr> <td></td> <td style="text-align: center;"><span class=nj-theme>6</span></td> <td><a href="https://github.com/nlohmann/json/pull/5885">#5885</a></td> <td>runs of numbers encoded in a loop</td> <td style="text-align: right;">−32%</td> </tr> </tbody> </table> <p class=nj-table-caption>The labeled steps of the timeline: the change in time at the first commit of each pull request, against the commit before it. <a href="https://github.com/nlohmann/json/pull/5592">#5592</a> is by <a href="https://github.com/mvanslobbe">@mvanslobbe</a>.</p> <h3 id=d-algorithmic-fixes>D. Algorithmic fixes<a class=headerlink href=#d-algorithmic-fixes title="Permanent link">&para;</a></h3> <table> <thead> <tr> <th>operation</th> <th style="text-align: right;">3.12.0</th> <th style="text-align: right;">3.13.0</th> <th style="text-align: right;">speedup</th> <th>cause</th> <th>PR</th> </tr> </thead> <tbody> <tr> <td><code>diff()</code> of an array of 64,000 numbers against an empty array</td> <td style="text-align: right;">4,237 ms</td> <td style="text-align: right;">10.8 ms</td> <td style="text-align: right;">394×</td> <td>each <code>remove</code> was inserted at the front of the patch</td> <td><a href="https://github.com/nlohmann/json/pull/5461">#5461</a></td> </tr> <tr> <td><code>diff()</code> of an array of 20,000 objects against every second one of them</td> <td style="text-align: right;">122 ms</td> <td style="text-align: right;">4.13 ms</td> <td style="text-align: right;">29×</td> <td>the same</td> <td><a href="https://github.com/nlohmann/json/pull/5461">#5461</a></td> </tr> <tr> <td><code>parse()</code> with a callback that rejects half of 32,000 objects</td> <td style="text-align: right;">1,398 ms</td> <td style="text-align: right;">12.1 ms</td> <td style="text-align: right;">116×</td> <td>each rejected value was searched for from the start of its parent</td> <td><a href="https://github.com/nlohmann/json/pull/5457">#5457</a></td> </tr> <tr> <td><code>&lt;</code> on two equal values nested 24 levels deep (C++11 to C++17)</td> <td style="text-align: right;">64.4 ms</td> <td style="text-align: right;">0.002 ms</td> <td style="text-align: right;">exponential</td> <td><code>std::vector</code>'s <code>&lt;</code> asks <code>a &lt; b</code> and <code>b &lt; a</code>, and both recurse</td> <td><a href="https://github.com/nlohmann/json/pull/5390">#5390</a></td> </tr> <tr> <td><code>&lt;</code> on <code>citm_catalog.json</code> and a copy, 10× (C++11 to C++17)</td> <td style="text-align: right;">284 ms</td> <td style="text-align: right;">3.94 ms</td> <td style="text-align: right;">72×</td> <td>the same</td> <td><a href="https://github.com/nlohmann/json/pull/5390">#5390</a></td> </tr> <tr> <td><code>flatten()</code> of <code>citm_catalog.json</code> as <code>ordered_json</code></td> <td style="text-align: right;">271 ms</td> <td style="text-align: right;">1.45 ms</td> <td style="text-align: right;">187×</td> <td>every new key was looked up linearly</td> <td><a href="https://github.com/nlohmann/json/pull/5834">#5834</a></td> </tr> <tr> <td><code>to_bson()</code> of a value nested 200 levels deep, 100×</td> <td style="text-align: right;">20.3 ms</td> <td style="text-align: right;">0.352 ms</td> <td style="text-align: right;">58×</td> <td>each document's size was computed by walking everything below it again</td> <td><a href="https://github.com/nlohmann/json/pull/5553">#5553</a>, <a href="https://github.com/nlohmann/json/pull/5979">#5979</a></td> </tr> <tr> <td>100,000 × <code>push_back()</code> on an <code>ordered_json</code> with <a href=../../../api/macros/json_diagnostics/ ><code>JSON_DIAGNOSTICS</code></a></td> <td style="text-align: right;">1,589 ms</td> <td style="text-align: right;">5.32 ms</td> <td style="text-align: right;">299×</td> <td>every insert re-pointed the parent pointers of all elements</td> <td><a href="https://github.com/nlohmann/json/pull/5832">#5832</a></td> </tr> <tr> <td>10,000 × <code>at(i)</code> on an <code>ordered_json</code> array with <code>JSON_DIAGNOSTICS</code></td> <td style="text-align: right;">45.9 ms</td> <td style="text-align: right;">0.088 ms</td> <td style="text-align: right;">522×</td> <td>the same</td> <td><a href="https://github.com/nlohmann/json/pull/5832">#5832</a></td> </tr> </tbody> </table> <p class=nj-table-caption>Operations that were quadratic or worse in 3.12.0, timed with both versions (C++17, <code>-O3</code>, median of 3 interleaved runs).</p> <h3 id=e-comparison-with-other-libraries>E. Comparison with other libraries<a class=headerlink href=#e-comparison-with-other-libraries title="Permanent link">&para;</a></h3> <p><strong>Method.</strong> The programs are in <a href="https://github.com/nlohmann/json/tree/develop/tests/benchmarks/json_view/others"><code>tests/benchmarks/json_view/others</code></a>, whose README lists every variant, the pinned versions and checksums of every library, and the build commands. The libraries: <a href="https://github.com/ibireme/yyjson">yyjson</a> 0.13.0, <a href="https://github.com/simdjson/simdjson">simdjson</a> 5.1.1, <a href="https://github.com/bytedance/sonic-cpp">sonic-cpp</a> 1.0.2, <a href="https://github.com/Tencent/rapidjson">RapidJSON</a> (master, 24b5e7a, as its last release is from 2016), <a href="https://github.com/stephenberry/glaze">Glaze</a> 9.1.0, <a href="https://github.com/boostorg/json">Boost.<abbr title="JavaScript Object Notation">JSON</abbr></a> 1.92, and in Rust <a href="https://github.com/cloudwego/sonic-rs">sonic-rs</a> 0.5.10, <a href="https://github.com/simd-lite/simd-json">simd-json</a> 0.19.0 and <a href="https://github.com/serde-rs/json">serde_json</a> 1.0.154. C++23 with <code>-O3</code>; on the Mac Apple clang 21 (the compiler of the current Xcode), on x86-64 <abbr title="GNU Compiler Collection">GCC</abbr> 16.2, <abbr title="GNU Compiler Collection">GCC</abbr> 13.4 and Clang 23 with <code>-march=haswell</code> on Ubuntu 26.04, pinned to one core; Rust 1.99 with <code>-C target-cpu=haswell</code> on x86-64. The Rust times on the Mac are from October 29; the Rust programs haven't changed since. Every variant runs in every round, in a different order each round (a shuffle with a fixed seed), each timed call after an untimed one; the time is the best of 2 × 30 rounds (2 × 6 for <code>jeopardy.json</code>). Boost.<abbr title="JavaScript Object Notation">JSON</abbr> uses a monotonic resource and precise number parsing, RapidJSON <code>kParseFullPrecisionFlag</code> (except in <em>validate</em>, which reads no number), serde_json <code>float_roundtrip</code>: every number a library converts has to be exact. That rule, like the others here, is our choice. Between the two runs, a library's time relative to <code>json_document</code>'s moved by 0.8% at the median and 2.5% at the 95th percentile on the Mac, and by 2.5–3% and 9–10% on x86-64.</p> <p><strong>Validation levels.</strong> A way validates fully if it rejects all four broken inputs (cut short by one byte, a stray comma, an invalid <abbr title="Unicode Transformation Format">UTF</abbr>-8 byte in a string, garbage after the value); "U" accepts the invalid <abbr title="Unicode Transformation Format">UTF</abbr>-8 byte; "P" accepts one of the other three. The probes separate the ways that check everything from those that check less; JSONTestSuite is the conformance check. sonic-cpp 1.0.2 does not check <abbr title="Unicode Transformation Format">UTF</abbr>-8. RapidJSON does only with <code>kParseValidateEncodingFlag</code>, and serde_json reading into <code>IgnoredAny</code> or structs from bytes doesn't check the strings it skips, unless the input is checked with <code>std::str::from_utf8</code> first; both are shown both ways. simdjson's On-Demand <abbr title="Application Programming Interface">API</abbr>, Glaze's <code>lazy_json</code>, <code>simdjson::minify()</code> and Glaze's <code>minify_json()</code> don't validate what they skip, Glaze's structs only with <code>validate_skipped</code>, and Glaze's generic reader rejects garbage after the value only with <code>validate_trailing_whitespace</code> (its strict variants also set <code>escape_control_characters</code>, without which it writes control characters unescaped).</p> <p><strong>Conformance.</strong> Every <em>validate</em> way ran the 318 files of <a href="https://github.com/nst/JSONTestSuite">JSONTestSuite</a>, on the Mac with the headers of November 3 and on x86-64 with those of October 30 (the Mac's results didn't change). No way rejected a file that must be accepted. Of those that must be rejected, a few got through: <code>123</code> followed by a <abbr title="Null character (U+0000, byte value 0)">NUL</abbr> byte in nlohmann/json and RapidJSON (nlohmann/json treats <abbr title="Null character (U+0000, byte value 0)">NUL</abbr> as the end of the input; <a href=../../../api/macros/json_strict_nul_handling/ ><code>JSON_STRICT_NUL_HANDLING</code></a> changes that for <code>json</code> and <code>json_document</code>), an incomplete <abbr title="Unicode Transformation Format">UTF</abbr>-8 byte-order mark in RapidJSON, an invalid <code>\u</code> escape in sonic-rs's <code>IgnoredAny</code>, and, in 17 files, garbage after the value in Glaze's generic reader without <code>validate_trailing_whitespace</code>. sonic-rs, and RapidJSON's <abbr title="Simple API for XML">SAX</abbr> reader with <abbr title="GNU Compiler Collection">GCC</abbr> 16.2 on x86-64, crash with a stack overflow on 100,000 nested arrays. Neither machine has AVX-512, so simdjson's fastest kernel never ran, and yyjson and simdjson are compiled as separate files without link-time optimization, while the header-only libraries inline into the benchmark. Built with link-time optimization, and simdjson as C++23 like the rest, they moved by less than 3% against <code>json_document</code> on average (Apple clang and <abbr title="GNU Compiler Collection">GCC</abbr> 16).</p> <p><strong>Choices.</strong> A library's time is its fastest fully validating way per file; "(U …)", "(P …)" and "(N …)" give a faster way that checks or does less. A cell of the figures is the geometric mean of a library's four times, divided by the smallest such mean in its column. Variants that keep a parser or document across calls are measured but not chosen, and so are in-place ways with the copy made before the timer starts; with every library reused, the first place in each column stays the same. Variants that leave numbers unconverted while reading are chosen where they pass the checks (yyjson's and RapidJSON's raw numbers, Boost.<abbr title="JavaScript Object Notation">JSON</abbr>'s <code>number_precision::none</code>). Variants that write each number by copying its text instead of formatting it (<code>json_document</code> with <code>number_format::source</code>, yyjson's and RapidJSON's raw numbers) count as doing less, "N": their output keeps the source's spelling of each number. They matter most for <code>canada.json</code>. Glaze's <code>generic</code> with <code>double</code> numbers fails the checks wherever it has to write the 64-bit ids of <code>twitter.json</code>. The struct variants of nlohmann/json, Glaze, simdjson, and serde read into the same types; Boost.<abbr title="JavaScript Object Notation">JSON</abbr>'s <code>parse_into</code> has no type that skips a value, so it holds a little more.</p> <div class=nj-fig-wrap> <p><svg class="nj-fig nj-charts nj-charts--blog nj-charts--heat" viewbox="0 0 784 510" role=img aria-labelledby="nj-blog-uc-x86-clang nj-blog-uc-x86-clang-d" xmlns=http://www.w3.org/2000/svg> <title id=nj-blog-uc-x86-clang>Use cases: time of each library relative to the fastest, x86-64 with Clang 23</title> <desc id=nj-blog-uc-x86-clang-d>Table of relative times, libraries by use case. nlohmann/json json_document validate: 1.00; nlohmann/json json_document sum: 1.00; nlohmann/json json_document select: 1.00; nlohmann/json json_document edit: 1.00 (0.81 doing less, N); nlohmann/json json_document minify: 1.00 (0.83 doing less, N); nlohmann/json json_document write: 1.00 (0.69 doing less, N); yyjson validate: 1.87; yyjson sum: 1.00; yyjson select: 1.23; yyjson edit: 1.43; yyjson minify: 1.16 (1.00 doing less, N); yyjson write: 1.14; sonic-cpp validate: no fully validating way (2.32 doing less, U); sonic-cpp sum: no fully validating way (1.20 doing less, U); sonic-cpp select: no fully validating way (1.53 doing less, U); sonic-cpp edit: no fully validating way (1.24 doing less, U); sonic-cpp minify: no fully validating way (1.38 doing less, U); sonic-cpp write: 1.28; simdjson validate: 2.03; simdjson sum: 1.13; simdjson select: 1.32 (0.57 doing less, P); simdjson edit: n/a; simdjson minify: 1.58 (0.18 doing less, P); simdjson write: 2.00; sonic-rs (Rust) validate: 1.88; sonic-rs (Rust) sum: 1.07; sonic-rs (Rust) select: 1.39; sonic-rs (Rust) edit: 1.90; sonic-rs (Rust) minify: 1.73; sonic-rs (Rust) write: 1.94; Boost.J&#8203;SON validate: 1.79; Boost.J&#8203;SON sum: 1.12; Boost.J&#8203;SON select: 2.24; Boost.J&#8203;SON edit: 2.39; Boost.J&#8203;SON minify: 2.68; Boost.J&#8203;SON write: 2.31; simd-json (Rust) validate: 3.52; simd-json (Rust) sum: 1.80; simd-json (Rust) select: 2.64; simd-json (Rust) edit: 2.88; simd-json (Rust) minify: 3.38; simd-json (Rust) write: 2.21; serde_json (Rust) validate: 2.33 (2.08 doing less, U); serde_json (Rust) sum: 2.22; serde_json (Rust) select: 1.77; serde_json (Rust) edit: 4.54; serde_json (Rust) minify: 4.92; serde_json (Rust) write: 2.15; Glaze validate: 2.23; Glaze sum: 4.03 (3.78 doing less, P); Glaze select: 1.43 (0.62 doing less, P); Glaze edit: 5.53; Glaze minify: 5.77 (0.70 doing less, P); Glaze write: 1.90; nlohmann/json json validate: 2.77; nlohmann/json json sum: 1.44; nlohmann/json json select: 7.56; nlohmann/json json edit: 3.99; nlohmann/json json minify: 4.91; nlohmann/json json write: 1.86; RapidJSON validate: 4.94 (3.76 doing less, U); RapidJSON sum: 2.98 (2.28 doing less, U); RapidJSON select: 4.20 (3.27 doing less, U); RapidJSON edit: 3.06 (2.60 doing less, U); RapidJSON minify: 3.61 (2.65 doing less, U N); RapidJSON write: 2.79.</desc> <text class=nj-charts-tick x=270 y=34>validate</text> <text class=nj-charts-tick x=362 y=34>sum</text> <text class=nj-charts-tick x=454 y=34>select</text> <text class=nj-charts-tick x=546 y=34>edit</text> <text class=nj-charts-tick x=638 y=34>minify</text> <text class=nj-charts-tick x=730 y=34>write</text> <text class="nj-charts-rowlabel nj-charts-name-json" x=216 y=66 text-anchor=end>nlohmann/json json_document</text> <g class=nj-heat-cell tabindex=0 data-tip="nlohmann/json json_document · validate
1.00× the time of the fastest library (fully validating)
way: accept
twitter.json: 255 µs
citm_catalog.json: 512 µs
canada.json: 1,055 µs
jeopardy.json: 34,729 µs"> <rect class=nj-heat-0 x=225 y=45 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=270 y=66 text-anchor=middle>1.00</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="nlohmann/json json_document · sum
1.00× the time of the fastest library (fully validating)
way: parse
twitter.json: 374 µs
citm_catalog.json: 923 µs
canada.json: 3,846 µs
jeopardy.json: 85,286 µs"> <rect class=nj-heat-0 x=317 y=45 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=362 y=66 text-anchor=middle>1.00</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="nlohmann/json json_document · select
1.00× the time of the fastest library (fully validating)
twitter.json: 320 µs · parse
citm_catalog.json: 759 µs · parse
canada.json: 1,390 µs · structs (from_json)
jeopardy.json: 88,083 µs · parse"> <rect class=nj-heat-0 x=409 y=45 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=454 y=66 text-anchor=middle>1.00</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="nlohmann/json json_document · edit
1.00× the time of the fastest library (fully validating)
way: editable
twitter.json: 526 µs
citm_catalog.json: 1,127 µs
canada.json: 5,674 µs
jeopardy.json: 196,370 µs"> <rect class=nj-heat-0 x=501 y=45 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=523.5 y=66 text-anchor=middle>1.00</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="nlohmann/json json_document · edit, checking less
0.81× the time of the fastest fully validating library
twitter.json: 526 µs · editable (validates fully)
citm_catalog.json: 1,127 µs · editable (validates fully)
canada.json: 2,443 µs · editable (source numbers) (validates fully)
jeopardy.json: 196,370 µs · editable (validates fully)
copies each number's text instead of formatting it (number_format::source)"> <rect class=nj-heat-0 x=547 y=45 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=568.5 y=60 text-anchor=middle>0.81</text> <text class="nj-charts-cell nj-charts-cell--small" x=568.5 y=73 text-anchor=middle>N</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="nlohmann/json json_document · minify
1.00× the time of the fastest library (fully validating)
way: parse + dump
twitter.json: 518 µs
citm_catalog.json: 1,040 µs
canada.json: 5,043 µs
jeopardy.json: 146,125 µs"> <rect class=nj-heat-0 x=593 y=45 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=615.5 y=66 text-anchor=middle>1.00</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="nlohmann/json json_document · minify, checking less
0.83× the time of the fastest fully validating library
twitter.json: 518 µs · parse + dump (validates fully)
citm_catalog.json: 1,030 µs · parse + dump (source numbers) (validates fully)
canada.json: 2,456 µs · parse + dump (source numbers) (validates fully)
jeopardy.json: 146,125 µs · parse + dump (validates fully)
copies each number's text instead of formatting it (number_format::source)"> <rect class=nj-heat-0 x=639 y=45 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=660.5 y=60 text-anchor=middle>0.83</text> <text class="nj-charts-cell nj-charts-cell--small" x=660.5 y=73 text-anchor=middle>N</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="nlohmann/json json_document · write
1.00× the time of the fastest library (fully validating)
way: dump
twitter.json: 160 µs
citm_catalog.json: 311 µs
canada.json: 3,714 µs
jeopardy.json: 67,038 µs"> <rect class=nj-heat-0 x=685 y=45 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=707.5 y=66 text-anchor=middle>1.00</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="nlohmann/json json_document · write, checking less
0.69× the time of the fastest fully validating library
way: dump (source numbers)
twitter.json: 154 µs (validates fully)
citm_catalog.json: 279 µs (validates fully)
canada.json: 989 µs (validates fully)
jeopardy.json: 64,301 µs (validates fully)
copies each number's text instead of formatting it (number_format::source)"> <rect class=nj-heat-0 x=731 y=45 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=752.5 y=60 text-anchor=middle>0.69</text> <text class="nj-charts-cell nj-charts-cell--small" x=752.5 y=73 text-anchor=middle>N</text> </g> <text class="nj-charts-rowlabel " x=216 y=102 text-anchor=end>yyjson</text> <g class=nj-heat-cell tabindex=0 data-tip="yyjson · validate
1.87× the time of the fastest library (fully validating)
twitter.json: 334 µs · insitu (copy untimed)
citm_catalog.json: 811 µs · insitu (copy untimed)
canada.json: 2,580 µs · read (raw numbers)
jeopardy.json: 83,153 µs · insitu (copy untimed)"> <rect class=nj-heat-2 x=225 y=81 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=270 y=102 text-anchor=middle>1.87</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="yyjson · sum
1.00× the time of the fastest library (fully validating)
way: insitu (copy untimed)
twitter.json: 399 µs
citm_catalog.json: 946 µs
canada.json: 3,445 µs
jeopardy.json: 88,447 µs"> <rect class=nj-heat-0 x=317 y=81 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=362 y=102 text-anchor=middle>1.00</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="yyjson · select
1.23× the time of the fastest library (fully validating)
twitter.json: 351 µs · insitu (copy untimed)
citm_catalog.json: 788 µs · insitu (copy untimed)
canada.json: 2,632 µs · read (raw numbers)
jeopardy.json: 92,551 µs · insitu (copy untimed)"> <rect class=nj-heat-1 x=409 y=81 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=454 y=102 text-anchor=middle>1.23</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="yyjson · edit
1.43× the time of the fastest library (fully validating)
twitter.json: 918 µs · insitu (copy) + mut copy
citm_catalog.json: 1,548 µs · insitu (copy untimed) + mut copy
canada.json: 7,155 µs · insitu (copy untimed) + mut copy
jeopardy.json: 270,654 µs · insitu (copy untimed) + mut copy
(copy): parses in place, on a copy of the input that is part of the time"> <rect class=nj-heat-1 x=501 y=81 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=546 y=102 text-anchor=middle>1.43</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="yyjson · minify
1.16× the time of the fastest library (fully validating)
way: insitu (copy untimed) + write
twitter.json: 620 µs
citm_catalog.json: 1,189 µs
canada.json: 6,283 µs
jeopardy.json: 154,016 µs"> <rect class=nj-heat-1 x=593 y=81 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=615.5 y=102 text-anchor=middle>1.16</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="yyjson · minify, checking less
1.00× the time of the fastest fully validating library
twitter.json: 620 µs · insitu (copy untimed) + write (validates fully)
citm_catalog.json: 1,189 µs · insitu (copy untimed) + write (validates fully)
canada.json: 3,472 µs · read (raw numbers) + write (validates fully)
jeopardy.json: 154,016 µs · insitu (copy untimed) + write (validates fully)
copies each number's text instead of formatting it (YYJSON_READ_NUMBER_AS_RAW)"> <rect class=nj-heat-0 x=639 y=81 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=660.5 y=96 text-anchor=middle>1.00</text> <text class="nj-charts-cell nj-charts-cell--small" x=660.5 y=109 text-anchor=middle>N</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="yyjson · write
1.14× the time of the fastest library (fully validating)
way: write
twitter.json: 218 µs
citm_catalog.json: 386 µs
canada.json: 3,476 µs
jeopardy.json: 71,247 µs"> <rect class=nj-heat-0 x=685 y=81 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=730 y=102 text-anchor=middle>1.14</text> </g> <text class="nj-charts-rowlabel " x=216 y=138 text-anchor=end>sonic-cpp</text> <g class=nj-heat-cell tabindex=0 data-tip="sonic-cpp · validate, checking less
2.32× the time of the fastest fully validating library
way: Document
twitter.json: 448 µs
citm_catalog.json: 1,032 µs
canada.json: 3,143 µs
jeopardy.json: 94,884 µs
trusts U​TF-8: sonic-cpp 1.0.2 doesn't check it"> <rect class=nj-heat-2 x=225 y=117 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=270 y=132 text-anchor=middle>2.32</text> <text class="nj-charts-cell nj-charts-cell--small" x=270 y=145 text-anchor=middle>U</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="sonic-cpp · sum, checking less
1.20× the time of the fastest fully validating library
way: Document
twitter.json: 502 µs
citm_catalog.json: 1,175 µs
canada.json: 3,754 µs
jeopardy.json: 104,583 µs
trusts U​TF-8: sonic-cpp 1.0.2 doesn't check it"> <rect class=nj-heat-1 x=317 y=117 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=362 y=132 text-anchor=middle>1.20</text> <text class="nj-charts-cell nj-charts-cell--small" x=362 y=145 text-anchor=middle>U</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="sonic-cpp · select, checking less
1.53× the time of the fastest fully validating library
way: Document
twitter.json: 460 µs
citm_catalog.json: 1,011 µs
canada.json: 3,204 µs
jeopardy.json: 108,245 µs
trusts U​TF-8: sonic-cpp 1.0.2 doesn't check it"> <rect class=nj-heat-2 x=409 y=117 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=454 y=132 text-anchor=middle>1.53</text> <text class="nj-charts-cell nj-charts-cell--small" x=454 y=145 text-anchor=middle>U</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="sonic-cpp · edit, checking less
1.24× the time of the fastest fully validating library
way: Document
twitter.json: 711 µs
citm_catalog.json: 1,472 µs
canada.json: 7,996 µs
jeopardy.json: 183,852 µs
trusts U​TF-8: sonic-cpp 1.0.2 doesn't check it"> <rect class=nj-heat-1 x=501 y=117 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=546 y=132 text-anchor=middle>1.24</text> <text class="nj-charts-cell nj-charts-cell--small" x=546 y=145 text-anchor=middle>U</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="sonic-cpp · minify, checking less
1.38× the time of the fastest fully validating library
way: Document + Serialize
twitter.json: 710 µs
citm_catalog.json: 1,485 µs
canada.json: 8,122 µs
jeopardy.json: 166,935 µs
trusts U​TF-8: sonic-cpp 1.0.2 doesn't check it"> <rect class=nj-heat-1 x=593 y=117 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=638 y=132 text-anchor=middle>1.38</text> <text class="nj-charts-cell nj-charts-cell--small" x=638 y=145 text-anchor=middle>U</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="sonic-cpp · write
1.28× the time of the fastest library (fully validating)
way: Serialize
twitter.json: 224 µs
citm_catalog.json: 475 µs
canada.json: 4,850 µs
jeopardy.json: 65,131 µs"> <rect class=nj-heat-1 x=685 y=117 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=730 y=138 text-anchor=middle>1.28</text> </g> <text class="nj-charts-rowlabel " x=216 y=174 text-anchor=end>simdjson</text> <g class=nj-heat-cell tabindex=0 data-tip="simdjson · validate
2.03× the time of the fastest library (fully validating)
way: D​OM
twitter.json: 306 µs
citm_catalog.json: 732 µs
canada.json: 3,206 µs
jeopardy.json: 113,452 µs"> <rect class=nj-heat-2 x=225 y=153 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=270 y=174 text-anchor=middle>2.03</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="simdjson · sum
1.13× the time of the fastest library (fully validating)
twitter.json: 394 µs · D​OM
citm_catalog.json: 977 µs · D​OM
canada.json: 4,117 µs · D​OM
jeopardy.json: 114,602 µs · On-Demand"> <rect class=nj-heat-0 x=317 y=153 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=362 y=174 text-anchor=middle>1.13</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="simdjson · select
1.32× the time of the fastest library (fully validating)
way: D​OM
twitter.json: 316 µs
citm_catalog.json: 731 µs
canada.json: 3,262 µs
jeopardy.json: 120,808 µs"> <rect class=nj-heat-1 x=409 y=153 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=431.5 y=174 text-anchor=middle>1.32</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="simdjson · select, checking less
0.57× the time of the fastest fully validating library
twitter.json: 181 µs · On-Demand structs
citm_catalog.json: 495 µs · On-Demand
canada.json: 702 µs · On-Demand
jeopardy.json: 48,823 µs · On-Demand
reads lazily: On-Demand reads only what you ask for and steps over the rest by matching brackets"> <rect class=nj-heat-0 x=455 y=153 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=476.5 y=168 text-anchor=middle>0.57</text> <text class="nj-charts-cell nj-charts-cell--small" x=476.5 y=181 text-anchor=middle>P</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="simdjson · edit
simdjson's documents are read-only: it has no A​PI to change a value and write the result"> <rect class=nj-heat-na x=501 y=153 width=90 height=34 rx=3 /> <text class=nj-charts-tick x=546 y=174>n/a</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="simdjson · minify
1.58× the time of the fastest library (fully validating)
way: D​OM + to_string
twitter.json: 783 µs
citm_catalog.json: 1,395 µs
canada.json: 8,303 µs
jeopardy.json: 275,007 µs"> <rect class=nj-heat-2 x=593 y=153 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=615.5 y=174 text-anchor=middle>1.58</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="simdjson · minify, checking less
0.18× the time of the fastest fully validating library
way: minify
twitter.json: 105 µs
citm_catalog.json: 269 µs
canada.json: 337 µs
jeopardy.json: 45,087 µs
simdjson::minify() only removes whitespace, without parsing the values"> <rect class=nj-heat-0 x=639 y=153 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=660.5 y=168 text-anchor=middle>0.18</text> <text class="nj-charts-cell nj-charts-cell--small" x=660.5 y=181 text-anchor=middle>P</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="simdjson · write
2.00× the time of the fastest library (fully validating)
way: to_string
twitter.json: 389 µs
citm_catalog.json: 656 µs
canada.json: 4,896 µs
jeopardy.json: 157,616 µs"> <rect class=nj-heat-2 x=685 y=153 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=730 y=174 text-anchor=middle>2.00</text> </g> <text class="nj-charts-rowlabel " x=216 y=210 text-anchor=end>sonic-rs (Rust)</text> <g class=nj-heat-cell tabindex=0 data-tip="sonic-rs (Rust) · validate
1.88× the time of the fastest library (fully validating)
way: IgnoredAny
twitter.json: 501 µs
citm_catalog.json: 970 µs
canada.json: 2,249 µs
jeopardy.json: 54,369 µs"> <rect class=nj-heat-2 x=225 y=189 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=270 y=210 text-anchor=middle>1.88</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="sonic-rs (Rust) · sum
1.07× the time of the fastest library (fully validating)
way: visitor
twitter.json: 501 µs
citm_catalog.json: 1,123 µs
canada.json: 4,397 µs
jeopardy.json: 59,583 µs"> <rect class=nj-heat-0 x=317 y=189 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=362 y=210 text-anchor=middle>1.07</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="sonic-rs (Rust) · select
1.39× the time of the fastest library (fully validating)
way: structs
twitter.json: 504 µs
citm_catalog.json: 1,033 µs
canada.json: 2,328 µs
jeopardy.json: 90,486 µs"> <rect class=nj-heat-1 x=409 y=189 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=454 y=210 text-anchor=middle>1.39</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="sonic-rs (Rust) · edit
1.90× the time of the fastest library (fully validating)
way: Value
twitter.json: 1,197 µs
citm_catalog.json: 2,389 µs
canada.json: 7,744 µs
jeopardy.json: 390,952 µs"> <rect class=nj-heat-2 x=501 y=189 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=546 y=210 text-anchor=middle>1.90</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="sonic-rs (Rust) · minify
1.73× the time of the fastest library (fully validating)
way: Value
twitter.json: 1,000 µs
citm_catalog.json: 2,097 µs
canada.json: 7,795 µs
jeopardy.json: 215,280 µs"> <rect class=nj-heat-2 x=593 y=189 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=638 y=210 text-anchor=middle>1.73</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="sonic-rs (Rust) · write
1.94× the time of the fastest library (fully validating)
way: Value
twitter.json: 434 µs
citm_catalog.json: 927 µs
canada.json: 3,987 µs
jeopardy.json: 109,176 µs"> <rect class=nj-heat-2 x=685 y=189 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=730 y=210 text-anchor=middle>1.94</text> </g> <text class="nj-charts-rowlabel " x=216 y=246 text-anchor=end>Boost.J&#8203;SON</text> <g class=nj-heat-cell tabindex=0 data-tip="Boost.J​SON · validate
1.79× the time of the fastest library (fully validating)
way: S​AX (numbers: none)
twitter.json: 571 µs
citm_catalog.json: 910 µs
canada.json: 1,684 µs
jeopardy.json: 55,498 µs"> <rect class=nj-heat-2 x=225 y=225 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=270 y=246 text-anchor=middle>1.79</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="Boost.J​SON · sum
1.12× the time of the fastest library (fully validating)
way: S​AX
twitter.json: 580 µs
citm_catalog.json: 928 µs
canada.json: 5,809 µs
jeopardy.json: 56,774 µs"> <rect class=nj-heat-0 x=317 y=225 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=362 y=246 text-anchor=middle>1.12</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="Boost.J​SON · select
2.24× the time of the fastest library (fully validating)
twitter.json: 776 µs · parse_into structs
citm_catalog.json: 1,389 µs · parse_into structs
canada.json: 7,121 µs · parse
jeopardy.json: 97,681 µs · parse_into structs"> <rect class=nj-heat-2 x=409 y=225 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=454 y=246 text-anchor=middle>2.24</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="Boost.J​SON · edit
2.39× the time of the fastest library (fully validating)
way: parse
twitter.json: 1,855 µs
citm_catalog.json: 2,596 µs
canada.json: 12,765 µs
jeopardy.json: 350,286 µs"> <rect class=nj-heat-2 x=501 y=225 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=546 y=246 text-anchor=middle>2.39</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="Boost.J​SON · minify
2.68× the time of the fastest library (fully validating)
way: parse + serialize
twitter.json: 1,924 µs
citm_catalog.json: 2,569 µs
canada.json: 12,622 µs
jeopardy.json: 329,090 µs"> <rect class=nj-heat-3 x=593 y=225 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=638 y=246 text-anchor=middle>2.68</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="Boost.J​SON · write
2.31× the time of the fastest library (fully validating)
way: serialize
twitter.json: 478 µs
citm_catalog.json: 916 µs
canada.json: 5,615 µs
jeopardy.json: 141,846 µs"> <rect class=nj-heat-2 x=685 y=225 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=730 y=246 text-anchor=middle>2.31</text> </g> <text class="nj-charts-rowlabel " x=216 y=282 text-anchor=end>simd-json (Rust)</text> <g class=nj-heat-cell tabindex=0 data-tip="simd-json (Rust) · validate
3.52× the time of the fastest library (fully validating)
way: tape (copy)
twitter.json: 567 µs
citm_catalog.json: 1,430 µs
canada.json: 4,359 µs
jeopardy.json: 207,551 µs
(copy): parses in place, on a copy of the input that is part of the time"> <rect class=nj-heat-3 x=225 y=261 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=270 y=282 text-anchor=middle>3.52</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="simd-json (Rust) · sum
1.80× the time of the fastest library (fully validating)
way: visitor (copy)
twitter.json: 681 µs
citm_catalog.json: 1,650 µs
canada.json: 5,083 µs
jeopardy.json: 210,185 µs
(copy): parses in place, on a copy of the input that is part of the time"> <rect class=nj-heat-2 x=317 y=261 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=362 y=282 text-anchor=middle>1.80</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="simd-json (Rust) · select
2.64× the time of the fastest library (fully validating)
way: structs (copy)
twitter.json: 679 µs
citm_catalog.json: 1,731 µs
canada.json: 5,144 µs
jeopardy.json: 239,164 µs
(copy): parses in place, on a copy of the input that is part of the time"> <rect class=nj-heat-3 x=409 y=261 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=454 y=282 text-anchor=middle>2.64</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="simd-json (Rust) · edit
2.88× the time of the fastest library (fully validating)
twitter.json: 1,862 µs · borrowed (copy)
citm_catalog.json: 4,194 µs · borrowed (copy)
canada.json: 14,896 µs · owned (copy)
jeopardy.json: 391,369 µs · borrowed (copy)
(copy): parses in place, on a copy of the input that is part of the time"> <rect class=nj-heat-3 x=501 y=261 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=546 y=282 text-anchor=middle>2.88</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="simd-json (Rust) · minify
3.38× the time of the fastest library (fully validating)
way: borrowed (copy)
twitter.json: 1,889 µs
citm_catalog.json: 4,196 µs
canada.json: 15,716 µs
jeopardy.json: 414,377 µs
(copy): parses in place, on a copy of the input that is part of the time"> <rect class=nj-heat-3 x=593 y=261 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=638 y=282 text-anchor=middle>3.38</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="simd-json (Rust) · write
2.21× the time of the fastest library (fully validating)
way: borrowed
twitter.json: 582 µs
citm_catalog.json: 800 µs
canada.json: 5,147 µs
jeopardy.json: 122,623 µs"> <rect class=nj-heat-2 x=685 y=261 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=730 y=282 text-anchor=middle>2.21</text> </g> <text class="nj-charts-rowlabel " x=216 y=318 text-anchor=end>serde_json (Rust)</text> <g class=nj-heat-cell tabindex=0 data-tip="serde_json (Rust) · validate
2.33× the time of the fastest library (fully validating)
way: from_utf8 + IgnoredAny
twitter.json: 624 µs
citm_catalog.json: 1,440 µs
canada.json: 2,406 µs
jeopardy.json: 64,720 µs"> <rect class=nj-heat-2 x=225 y=297 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=247.5 y=318 text-anchor=middle>2.33</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="serde_json (Rust) · validate, checking less
2.08× the time of the fastest fully validating library
way: IgnoredAny
twitter.json: 484 µs
citm_catalog.json: 1,370 µs
canada.json: 2,314 µs
jeopardy.json: 58,247 µs
trusts U​TF-8 in the strings it skips (from_slice); strings it reads are checked"> <rect class=nj-heat-2 x=271 y=297 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=292.5 y=312 text-anchor=middle>2.08</text> <text class="nj-charts-cell nj-charts-cell--small" x=292.5 y=325 text-anchor=middle>U</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="serde_json (Rust) · sum
2.22× the time of the fastest library (fully validating)
way: visitor
twitter.json: 1,311 µs
citm_catalog.json: 2,288 µs
canada.json: 7,127 µs
jeopardy.json: 129,497 µs"> <rect class=nj-heat-2 x=317 y=297 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=362 y=318 text-anchor=middle>2.22</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="serde_json (Rust) · select
1.77× the time of the fastest library (fully validating)
way: from_utf8 + structs
twitter.json: 701 µs
citm_catalog.json: 1,532 µs
canada.json: 2,529 µs
jeopardy.json: 107,316 µs"> <rect class=nj-heat-2 x=409 y=297 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=454 y=318 text-anchor=middle>1.77</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="serde_json (Rust) · edit
4.54× the time of the fastest library (fully validating)
way: Value
twitter.json: 4,042 µs
citm_catalog.json: 6,586 µs
canada.json: 16,631 µs
jeopardy.json: 632,766 µs"> <rect class=nj-heat-3 x=501 y=297 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=546 y=318 text-anchor=middle>4.54</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="serde_json (Rust) · minify
4.92× the time of the fastest library (fully validating)
way: Value
twitter.json: 4,012 µs
citm_catalog.json: 6,583 µs
canada.json: 17,306 µs
jeopardy.json: 509,702 µs"> <rect class=nj-heat-3 x=593 y=297 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=638 y=318 text-anchor=middle>4.92</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="serde_json (Rust) · write
2.15× the time of the fastest library (fully validating)
way: Value
twitter.json: 550 µs
citm_catalog.json: 887 µs
canada.json: 4,005 µs
jeopardy.json: 134,163 µs"> <rect class=nj-heat-2 x=685 y=297 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=730 y=318 text-anchor=middle>2.15</text> </g> <text class="nj-charts-rowlabel " x=216 y=354 text-anchor=end>Glaze</text> <g class=nj-heat-cell tabindex=0 data-tip="Glaze · validate
2.23× the time of the fastest library (fully validating)
way: validate_json
twitter.json: 588 µs
citm_catalog.json: 1,431 µs
canada.json: 1,867 µs
jeopardy.json: 75,571 µs"> <rect class=nj-heat-2 x=225 y=333 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=270 y=354 text-anchor=middle>2.23</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="Glaze · sum
4.03× the time of the fastest library (fully validating)
way: generic (double, strict)
twitter.json: 2,427 µs
citm_catalog.json: 3,972 µs
canada.json: 12,165 µs
jeopardy.json: 253,385 µs"> <rect class=nj-heat-3 x=317 y=333 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=339.5 y=354 text-anchor=middle>4.03</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="Glaze · sum, checking less
3.78× the time of the fastest fully validating library
twitter.json: 2,427 µs · generic (double, strict) (validates fully)
citm_catalog.json: 3,972 µs · generic (double, strict) (validates fully)
canada.json: 12,165 µs · generic (double, strict) (validates fully)
jeopardy.json: 196,582 µs · lazy_json
reads lazily: lazy_json reads only what you ask for and steps over the rest"> <rect class=nj-heat-3 x=363 y=333 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=384.5 y=348 text-anchor=middle>3.78</text> <text class="nj-charts-cell nj-charts-cell--small" x=384.5 y=361 text-anchor=middle>P</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="Glaze · select
1.43× the time of the fastest library (fully validating)
way: structs (validate_skipped)
twitter.json: 544 µs
citm_catalog.json: 1,368 µs
canada.json: 1,924 µs
jeopardy.json: 85,745 µs"> <rect class=nj-heat-1 x=409 y=333 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=431.5 y=354 text-anchor=middle>1.43</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="Glaze · select, checking less
0.62× the time of the fastest fully validating library
way: structs
twitter.json: 345 µs
citm_catalog.json: 419 µs
canada.json: 444 µs
jeopardy.json: 66,442 µs
reads into structs and steps over fields it doesn't know without checking them (validate_skipped checks them too)"> <rect class=nj-heat-0 x=455 y=333 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=476.5 y=348 text-anchor=middle>0.62</text> <text class="nj-charts-cell nj-charts-cell--small" x=476.5 y=361 text-anchor=middle>P</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="Glaze · edit
5.53× the time of the fastest library (fully validating)
way: generic (strict)
twitter.json: 4,341 µs
citm_catalog.json: 7,322 µs
canada.json: 26,786 µs
jeopardy.json: 725,881 µs"> <rect class=nj-heat-4 x=501 y=333 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=546 y=354 text-anchor=middle>5.53</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="Glaze · minify
5.77× the time of the fastest library (fully validating)
way: generic (strict)
twitter.json: 4,132 µs
citm_catalog.json: 7,465 µs
canada.json: 26,962 µs
jeopardy.json: 528,811 µs"> <rect class=nj-heat-4 x=593 y=333 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=615.5 y=354 text-anchor=middle>5.77</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="Glaze · minify, checking less
0.70× the time of the fastest fully validating library
way: minify_json
twitter.json: 444 µs
citm_catalog.json: 1,059 µs
canada.json: 2,222 µs
jeopardy.json: 91,153 µs
minify_json only removes whitespace, without parsing the values"> <rect class=nj-heat-0 x=639 y=333 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=660.5 y=348 text-anchor=middle>0.70</text> <text class="nj-charts-cell nj-charts-cell--small" x=660.5 y=361 text-anchor=middle>P</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="Glaze · write
1.90× the time of the fastest library (fully validating)
way: generic
twitter.json: 399 µs
citm_catalog.json: 748 µs
canada.json: 4,220 µs
jeopardy.json: 128,020 µs"> <rect class=nj-heat-2 x=685 y=333 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=730 y=354 text-anchor=middle>1.90</text> </g> <text class="nj-charts-rowlabel nj-charts-name-json" x=216 y=390 text-anchor=end>nlohmann/json json</text> <g class=nj-heat-cell tabindex=0 data-tip="nlohmann/json json · validate
2.77× the time of the fastest library (fully validating)
way: accept
twitter.json: 658 µs
citm_catalog.json: 1,390 µs
canada.json: 4,265 µs
jeopardy.json: 71,982 µs"> <rect class=nj-heat-3 x=225 y=369 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=270 y=390 text-anchor=middle>2.77</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="nlohmann/json json · sum
1.44× the time of the fastest library (fully validating)
way: sax
twitter.json: 728 µs
citm_catalog.json: 1,393 µs
canada.json: 5,428 µs
jeopardy.json: 89,481 µs"> <rect class=nj-heat-1 x=317 y=369 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=362 y=390 text-anchor=middle>1.44</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="nlohmann/json json · select
7.56× the time of the fastest library (fully validating)
twitter.json: 3,602 µs · structs (from_json)
citm_catalog.json: 5,124 µs · parse
canada.json: 11,831 µs · parse
jeopardy.json: 444,210 µs · parse"> <rect class=nj-heat-4 x=409 y=369 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=454 y=390 text-anchor=middle>7.56</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="nlohmann/json json · edit
3.99× the time of the fastest library (fully validating)
twitter.json: 3,069 µs · ordered_json
citm_catalog.json: 4,905 µs · ordered_json
canada.json: 16,702 µs · parse
jeopardy.json: 666,261 µs · ordered_json"> <rect class=nj-heat-3 x=501 y=369 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=546 y=390 text-anchor=middle>3.99</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="nlohmann/json json · minify
4.91× the time of the fastest library (fully validating)
way: parse + dump
twitter.json: 4,445 µs
citm_catalog.json: 5,713 µs
canada.json: 16,711 µs
jeopardy.json: 543,033 µs"> <rect class=nj-heat-3 x=593 y=369 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=638 y=390 text-anchor=middle>4.91</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="nlohmann/json json · write
1.86× the time of the fastest library (fully validating)
way: dump
twitter.json: 451 µs
citm_catalog.json: 628 µs
canada.json: 4,506 µs
jeopardy.json: 116,529 µs"> <rect class=nj-heat-2 x=685 y=369 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=730 y=390 text-anchor=middle>1.86</text> </g> <text class="nj-charts-rowlabel " x=216 y=426 text-anchor=end>RapidJSON</text> <g class=nj-heat-cell tabindex=0 data-tip="RapidJSON · validate
4.94× the time of the fastest library (fully validating)
twitter.json: 1,756 µs · insitu (copy untimed)
citm_catalog.json: 1,971 µs · S​AX (default precision)
canada.json: 4,118 µs · S​AX (string stream, default precision)
jeopardy.json: 198,915 µs · insitu (copy untimed)"> <rect class=nj-heat-3 x=225 y=405 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=247.5 y=426 text-anchor=middle>4.94</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="RapidJSON · validate, checking less
3.76× the time of the fastest fully validating library
twitter.json: 1,132 µs · insitu (copy untimed) (no encoding check)
citm_catalog.json: 1,572 µs · S​AX (default precision) (no encoding check)
canada.json: 4,083 µs · S​AX (string stream, default precision) (no encoding check)
jeopardy.json: 131,204 µs · insitu (copy untimed) (no encoding check)
trusts U​TF-8: RapidJSON's default (kParseValidateEncodingFlag checks it)"> <rect class=nj-heat-3 x=271 y=405 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=292.5 y=420 text-anchor=middle>3.76</text> <text class="nj-charts-cell nj-charts-cell--small" x=292.5 y=433 text-anchor=middle>U</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="RapidJSON · sum
2.98× the time of the fastest library (fully validating)
twitter.json: 1,816 µs · insitu (copy untimed)
citm_catalog.json: 2,224 µs · S​AX
canada.json: 10,719 µs · S​AX (string stream)
jeopardy.json: 206,811 µs · insitu (copy untimed)"> <rect class=nj-heat-3 x=317 y=405 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=339.5 y=426 text-anchor=middle>2.98</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="RapidJSON · sum, checking less
2.28× the time of the fastest fully validating library
twitter.json: 1,187 µs · insitu (copy untimed) (no encoding check)
citm_catalog.json: 1,765 µs · S​AX (no encoding check)
canada.json: 10,719 µs · S​AX (string stream) (validates fully)
jeopardy.json: 135,945 µs · S​AX (string stream) (no encoding check)
trusts U​TF-8: RapidJSON's default (kParseValidateEncodingFlag checks it)"> <rect class=nj-heat-2 x=363 y=405 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=384.5 y=420 text-anchor=middle>2.28</text> <text class="nj-charts-cell nj-charts-cell--small" x=384.5 y=433 text-anchor=middle>U</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="RapidJSON · select
4.20× the time of the fastest library (fully validating)
way: insitu (copy untimed)
twitter.json: 1,762 µs
citm_catalog.json: 2,198 µs
canada.json: 11,464 µs
jeopardy.json: 209,290 µs"> <rect class=nj-heat-3 x=409 y=405 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=431.5 y=426 text-anchor=middle>4.20</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="RapidJSON · select, checking less
3.27× the time of the fastest fully validating library
twitter.json: 1,144 µs · insitu (copy untimed) (no encoding check)
citm_catalog.json: 1,817 µs · insitu (copy untimed) (no encoding check)
canada.json: 11,464 µs · insitu (copy untimed) (validates fully)
jeopardy.json: 142,852 µs · insitu (copy untimed) (no encoding check)
trusts U​TF-8: RapidJSON's default (kParseValidateEncodingFlag checks it)"> <rect class=nj-heat-3 x=455 y=405 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=476.5 y=420 text-anchor=middle>3.27</text> <text class="nj-charts-cell nj-charts-cell--small" x=476.5 y=433 text-anchor=middle>U</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="RapidJSON · edit
3.06× the time of the fastest library (fully validating)
twitter.json: 2,635 µs · insitu (copy)
citm_catalog.json: 3,103 µs · insitu (copy untimed)
canada.json: 21,139 µs · insitu (copy untimed)
jeopardy.json: 333,913 µs · insitu (copy untimed)
(copy): parses in place, on a copy of the input that is part of the time"> <rect class=nj-heat-3 x=501 y=405 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=523.5 y=426 text-anchor=middle>3.06</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="RapidJSON · edit, checking less
2.60× the time of the fastest fully validating library
twitter.json: 1,952 µs · insitu (copy untimed) (no encoding check)
citm_catalog.json: 2,728 µs · insitu (copy untimed) (no encoding check)
canada.json: 21,139 µs · insitu (copy untimed) (validates fully)
jeopardy.json: 267,081 µs · insitu (copy untimed) (no encoding check)
trusts U​TF-8: RapidJSON's default (kParseValidateEncodingFlag checks it)"> <rect class=nj-heat-3 x=547 y=405 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=568.5 y=420 text-anchor=middle>2.60</text> <text class="nj-charts-cell nj-charts-cell--small" x=568.5 y=433 text-anchor=middle>U</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="RapidJSON · minify
3.61× the time of the fastest library (fully validating)
twitter.json: 2,808 µs · S​AX to Writer
citm_catalog.json: 2,975 µs · S​AX to Writer
canada.json: 22,589 µs · Document + Writer
jeopardy.json: 358,807 µs · S​AX to Writer (string stream)"> <rect class=nj-heat-3 x=593 y=405 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=615.5 y=426 text-anchor=middle>3.61</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="RapidJSON · minify, checking less
2.65× the time of the fastest fully validating library
twitter.json: 2,022 µs · S​AX to Writer (raw numbers) (no encoding check)
citm_catalog.json: 2,480 µs · S​AX to Writer (no encoding check)
canada.json: 14,986 µs · S​AX to Writer (raw numbers) (validates fully)
jeopardy.json: 261,527 µs · S​AX to Writer (string stream) (no encoding check)
trusts U​TF-8: RapidJSON's default (kParseValidateEncodingFlag checks it)
copies each number's text instead of formatting it (kParseNumbersAsStringsFlag)"> <rect class=nj-heat-3 x=639 y=405 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=660.5 y=420 text-anchor=middle>2.65</text> <text class="nj-charts-cell nj-charts-cell--small" x=660.5 y=433 text-anchor=middle>U N</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="RapidJSON · write
2.79× the time of the fastest library (fully validating)
way: Writer
twitter.json: 627 µs
citm_catalog.json: 1,008 µs
canada.json: 9,596 µs
jeopardy.json: 123,764 µs"> <rect class=nj-heat-3 x=685 y=405 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=730 y=426 text-anchor=middle>2.79</text> </g> <text class="nj-charts-tick nj-charts-tick--l" x=8 y=472>time relative to the fastest fully validating library, less is better</text> <g><rect class=nj-heat-0 x=8 y=482 width=76 height=20 rx=3 /> <text class="nj-charts-cell nj-charts-cell--small" x=46 y=496 text-anchor=middle>below 1.15</text></g> <g><rect class=nj-heat-1 x=88 y=482 width=76 height=20 rx=3 /> <text class="nj-charts-cell nj-charts-cell--small" x=126 y=496 text-anchor=middle>1.15 to 1.5</text></g> <g><rect class=nj-heat-2 x=168 y=482 width=76 height=20 rx=3 /> <text class="nj-charts-cell nj-charts-cell--small" x=206 y=496 text-anchor=middle>1.5 to 2.5</text></g> <g><rect class=nj-heat-3 x=248 y=482 width=76 height=20 rx=3 /> <text class="nj-charts-cell nj-charts-cell--small" x=286 y=496 text-anchor=middle>2.5 to 5</text></g> <g><rect class=nj-heat-4 x=328 y=482 width=76 height=20 rx=3 /> <text class="nj-charts-cell nj-charts-cell--small" x=366 y=496 text-anchor=middle>5 and more</text></g> <rect class=nj-heat-na x=420 y=482 width=40 height=20 rx=3 /> <text class=nj-charts-tick x=440 y=496>n/a</text> <text class="nj-charts-tick nj-charts-tick--l" x=468 y=496>no A&#8203;PI for it</text> </svg></p> </div> <p class=nj-caption>The use cases on the x86-64 server with Clang 23. Less is better; hover over or tap a cell for the times and the way.</p> <div class=nj-fig-wrap> <p><svg class="nj-fig nj-charts nj-charts--blog nj-charts--heat" viewbox="0 0 784 510" role=img aria-labelledby="nj-blog-uc-x86-gcc13 nj-blog-uc-x86-gcc13-d" xmlns=http://www.w3.org/2000/svg> <title id=nj-blog-uc-x86-gcc13>Use cases: time of each library relative to the fastest, x86-64 with G&#8203;CC 13</title> <desc id=nj-blog-uc-x86-gcc13-d>Table of relative times, libraries by use case. nlohmann/json json_document validate: 1.00; nlohmann/json json_document sum: 1.08; nlohmann/json json_document select: 1.00; nlohmann/json json_document edit: 1.00 (0.83 doing less, N); nlohmann/json json_document minify: 1.00 (0.83 doing less, N); nlohmann/json json_document write: 1.00 (0.71 doing less, N); yyjson validate: 1.81; yyjson sum: 1.28; yyjson select: 1.22; yyjson edit: 1.49; yyjson minify: 1.27 (0.97 doing less, N); yyjson write: 1.14; sonic-cpp validate: no fully validating way (2.24 doing less, U); sonic-cpp sum: no fully validating way (1.28 doing less, U); sonic-cpp select: no fully validating way (1.53 doing less, U); sonic-cpp edit: no fully validating way (1.26 doing less, U); sonic-cpp minify: no fully validating way (1.42 doing less, U); sonic-cpp write: 1.50; simdjson validate: 2.01; simdjson sum: 1.00; simdjson select: 1.35 (0.57 doing less, P); simdjson edit: n/a; simdjson minify: 1.58 (0.22 doing less, P); simdjson write: 2.07; sonic-rs (Rust) validate: 1.79; sonic-rs (Rust) sum: 1.11; sonic-rs (Rust) select: 1.37; sonic-rs (Rust) edit: 1.91; sonic-rs (Rust) minify: 1.73; sonic-rs (Rust) write: 2.07; Boost.J&#8203;SON validate: 1.88; Boost.J&#8203;SON sum: 1.33; Boost.J&#8203;SON select: 2.30; Boost.J&#8203;SON edit: 2.55; Boost.J&#8203;SON minify: 2.92; Boost.J&#8203;SON write: 2.56; simd-json (Rust) validate: 3.35; simd-json (Rust) sum: 1.88; simd-json (Rust) select: 2.61; simd-json (Rust) edit: 2.89; simd-json (Rust) minify: 3.39; simd-json (Rust) write: 2.35; serde_json (Rust) validate: 2.22 (1.98 doing less, U); serde_json (Rust) sum: 2.32; serde_json (Rust) select: 1.75; serde_json (Rust) edit: 4.55; serde_json (Rust) minify: 4.94; serde_json (Rust) write: 2.28; Glaze validate: 2.21; Glaze sum: 4.04; Glaze select: 1.44 (0.60 doing less, P); Glaze edit: 4.85; Glaze minify: 5.10 (0.73 doing less, P); Glaze write: 1.84; nlohmann/json json validate: 2.74; nlohmann/json json sum: 1.67; nlohmann/json json select: 7.24; nlohmann/json json edit: 3.81; nlohmann/json json minify: 4.79; nlohmann/json json write: 1.99; RapidJSON validate: 4.50 (3.40 doing less, U); RapidJSON sum: 2.98 (2.29 doing less, U); RapidJSON select: 3.84 (3.06 doing less, U); RapidJSON edit: 2.92 (2.58 doing less, U); RapidJSON minify: 3.64 (2.64 doing less, U N); RapidJSON write: 3.11.</desc> <text class=nj-charts-tick x=270 y=34>validate</text> <text class=nj-charts-tick x=362 y=34>sum</text> <text class=nj-charts-tick x=454 y=34>select</text> <text class=nj-charts-tick x=546 y=34>edit</text> <text class=nj-charts-tick x=638 y=34>minify</text> <text class=nj-charts-tick x=730 y=34>write</text> <text class="nj-charts-rowlabel nj-charts-name-json" x=216 y=66 text-anchor=end>nlohmann/json json_document</text> <g class=nj-heat-cell tabindex=0 data-tip="nlohmann/json json_document · validate
1.00× the time of the fastest library (fully validating)
way: accept
twitter.json: 271 µs
citm_catalog.json: 609 µs
canada.json: 1,011 µs
jeopardy.json: 34,722 µs"> <rect class=nj-heat-0 x=225 y=45 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=270 y=66 text-anchor=middle>1.00</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="nlohmann/json json_document · sum
1.08× the time of the fastest library (fully validating)
way: parse
twitter.json: 392 µs
citm_catalog.json: 946 µs
canada.json: 3,888 µs
jeopardy.json: 89,044 µs"> <rect class=nj-heat-0 x=317 y=45 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=362 y=66 text-anchor=middle>1.08</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="nlohmann/json json_document · select
1.00× the time of the fastest library (fully validating)
way: parse
twitter.json: 332 µs
citm_catalog.json: 765 µs
canada.json: 1,390 µs
jeopardy.json: 88,202 µs"> <rect class=nj-heat-0 x=409 y=45 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=454 y=66 text-anchor=middle>1.00</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="nlohmann/json json_document · edit
1.00× the time of the fastest library (fully validating)
way: editable
twitter.json: 532 µs
citm_catalog.json: 1,116 µs
canada.json: 5,714 µs
jeopardy.json: 192,363 µs"> <rect class=nj-heat-0 x=501 y=45 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=523.5 y=66 text-anchor=middle>1.00</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="nlohmann/json json_document · edit, checking less
0.83× the time of the fastest fully validating library
twitter.json: 532 µs · editable (validates fully)
citm_catalog.json: 1,116 µs · editable (validates fully)
canada.json: 2,702 µs · editable (source numbers) (validates fully)
jeopardy.json: 192,363 µs · editable (validates fully)
copies each number's text instead of formatting it (number_format::source)"> <rect class=nj-heat-0 x=547 y=45 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=568.5 y=60 text-anchor=middle>0.83</text> <text class="nj-charts-cell nj-charts-cell--small" x=568.5 y=73 text-anchor=middle>N</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="nlohmann/json json_document · minify
1.00× the time of the fastest library (fully validating)
twitter.json: 483 µs · parse + dump
citm_catalog.json: 1,014 µs · parse + dump
canada.json: 5,459 µs · parse_copy + dump
jeopardy.json: 146,320 µs · parse + dump"> <rect class=nj-heat-0 x=593 y=45 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=615.5 y=66 text-anchor=middle>1.00</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="nlohmann/json json_document · minify, checking less
0.83× the time of the fastest fully validating library
twitter.json: 483 µs · parse + dump (validates fully)
citm_catalog.json: 1,014 µs · parse + dump (validates fully)
canada.json: 2,620 µs · parse + dump (source numbers) (validates fully)
jeopardy.json: 146,320 µs · parse + dump (validates fully)
copies each number's text instead of formatting it (number_format::source)"> <rect class=nj-heat-0 x=639 y=45 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=660.5 y=60 text-anchor=middle>0.83</text> <text class="nj-charts-cell nj-charts-cell--small" x=660.5 y=73 text-anchor=middle>N</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="nlohmann/json json_document · write
1.00× the time of the fastest library (fully validating)
way: dump
twitter.json: 150 µs
citm_catalog.json: 260 µs
canada.json: 3,861 µs
jeopardy.json: 63,958 µs"> <rect class=nj-heat-0 x=685 y=45 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=707.5 y=66 text-anchor=middle>1.00</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="nlohmann/json json_document · write, checking less
0.71× the time of the fastest fully validating library
twitter.json: 148 µs · dump (source numbers) (validates fully)
citm_catalog.json: 260 µs · dump (validates fully)
canada.json: 998 µs · dump (source numbers) (validates fully)
jeopardy.json: 63,958 µs · dump (validates fully)
copies each number's text instead of formatting it (number_format::source)"> <rect class=nj-heat-0 x=731 y=45 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=752.5 y=60 text-anchor=middle>0.71</text> <text class="nj-charts-cell nj-charts-cell--small" x=752.5 y=73 text-anchor=middle>N</text> </g> <text class="nj-charts-rowlabel " x=216 y=102 text-anchor=end>yyjson</text> <g class=nj-heat-cell tabindex=0 data-tip="yyjson · validate
1.81× the time of the fastest library (fully validating)
twitter.json: 348 µs · insitu (copy untimed)
citm_catalog.json: 878 µs · insitu (copy untimed)
canada.json: 2,256 µs · read (raw numbers)
jeopardy.json: 90,959 µs · insitu (copy untimed)"> <rect class=nj-heat-2 x=225 y=81 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=270 y=102 text-anchor=middle>1.81</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="yyjson · sum
1.28× the time of the fastest library (fully validating)
way: insitu (copy untimed)
twitter.json: 407 µs
citm_catalog.json: 1,045 µs
canada.json: 6,021 µs
jeopardy.json: 99,764 µs"> <rect class=nj-heat-1 x=317 y=81 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=362 y=102 text-anchor=middle>1.28</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="yyjson · select
1.22× the time of the fastest library (fully validating)
twitter.json: 361 µs · insitu (copy untimed)
citm_catalog.json: 880 µs · insitu (copy untimed)
canada.json: 2,236 µs · read (raw numbers)
jeopardy.json: 98,637 µs · insitu (copy untimed)"> <rect class=nj-heat-1 x=409 y=81 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=454 y=102 text-anchor=middle>1.22</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="yyjson · edit
1.49× the time of the fastest library (fully validating)
way: insitu (copy untimed) + mut copy
twitter.json: 761 µs
citm_catalog.json: 1,590 µs
canada.json: 9,860 µs
jeopardy.json: 271,227 µs"> <rect class=nj-heat-1 x=501 y=81 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=546 y=102 text-anchor=middle>1.49</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="yyjson · minify
1.27× the time of the fastest library (fully validating)
twitter.json: 592 µs · insitu (copy untimed) + write
citm_catalog.json: 1,205 µs · insitu (copy untimed) + write
canada.json: 9,008 µs · read + write
jeopardy.json: 158,577 µs · insitu (copy untimed) + write"> <rect class=nj-heat-1 x=593 y=81 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=615.5 y=102 text-anchor=middle>1.27</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="yyjson · minify, checking less
0.97× the time of the fastest fully validating library
twitter.json: 592 µs · insitu (copy untimed) + write (validates fully)
citm_catalog.json: 1,205 µs · insitu (copy untimed) + write (validates fully)
canada.json: 3,106 µs · read (raw numbers) + write (validates fully)
jeopardy.json: 158,577 µs · insitu (copy untimed) + write (validates fully)
copies each number's text instead of formatting it (YYJSON_READ_NUMBER_AS_RAW)"> <rect class=nj-heat-0 x=639 y=81 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=660.5 y=96 text-anchor=middle>0.97</text> <text class="nj-charts-cell nj-charts-cell--small" x=660.5 y=109 text-anchor=middle>N</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="yyjson · write
1.14× the time of the fastest library (fully validating)
way: write
twitter.json: 204 µs
citm_catalog.json: 327 µs
canada.json: 3,748 µs
jeopardy.json: 65,989 µs"> <rect class=nj-heat-0 x=685 y=81 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=730 y=102 text-anchor=middle>1.14</text> </g> <text class="nj-charts-rowlabel " x=216 y=138 text-anchor=end>sonic-cpp</text> <g class=nj-heat-cell tabindex=0 data-tip="sonic-cpp · validate, checking less
2.24× the time of the fastest fully validating library
way: Document
twitter.json: 408 µs
citm_catalog.json: 1,028 µs
canada.json: 3,622 µs
jeopardy.json: 96,080 µs
trusts U​TF-8: sonic-cpp 1.0.2 doesn't check it"> <rect class=nj-heat-2 x=225 y=117 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=270 y=132 text-anchor=middle>2.24</text> <text class="nj-charts-cell nj-charts-cell--small" x=270 y=145 text-anchor=middle>U</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="sonic-cpp · sum, checking less
1.28× the time of the fastest fully validating library
way: Document
twitter.json: 460 µs
citm_catalog.json: 1,210 µs
canada.json: 4,295 µs
jeopardy.json: 107,092 µs
trusts U​TF-8: sonic-cpp 1.0.2 doesn't check it"> <rect class=nj-heat-1 x=317 y=117 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=362 y=132 text-anchor=middle>1.28</text> <text class="nj-charts-cell nj-charts-cell--small" x=362 y=145 text-anchor=middle>U</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="sonic-cpp · select, checking less
1.53× the time of the fastest fully validating library
way: Document
twitter.json: 413 µs
citm_catalog.json: 1,043 µs
canada.json: 3,695 µs
jeopardy.json: 108,297 µs
trusts U​TF-8: sonic-cpp 1.0.2 doesn't check it"> <rect class=nj-heat-2 x=409 y=117 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=454 y=132 text-anchor=middle>1.53</text> <text class="nj-charts-cell nj-charts-cell--small" x=454 y=145 text-anchor=middle>U</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="sonic-cpp · edit, checking less
1.26× the time of the fastest fully validating library
way: Document
twitter.json: 637 µs
citm_catalog.json: 1,559 µs
canada.json: 8,936 µs
jeopardy.json: 186,232 µs
trusts U​TF-8: sonic-cpp 1.0.2 doesn't check it"> <rect class=nj-heat-1 x=501 y=117 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=546 y=132 text-anchor=middle>1.26</text> <text class="nj-charts-cell nj-charts-cell--small" x=546 y=145 text-anchor=middle>U</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="sonic-cpp · minify, checking less
1.42× the time of the fastest fully validating library
way: Document + Serialize
twitter.json: 695 µs
citm_catalog.json: 1,541 µs
canada.json: 8,838 µs
jeopardy.json: 168,901 µs
trusts U​TF-8: sonic-cpp 1.0.2 doesn't check it"> <rect class=nj-heat-1 x=593 y=117 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=638 y=132 text-anchor=middle>1.42</text> <text class="nj-charts-cell nj-charts-cell--small" x=638 y=145 text-anchor=middle>U</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="sonic-cpp · write
1.50× the time of the fastest library (fully validating)
way: Serialize
twitter.json: 256 µs
citm_catalog.json: 541 µs
canada.json: 5,120 µs
jeopardy.json: 69,546 µs"> <rect class=nj-heat-2 x=685 y=117 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=730 y=138 text-anchor=middle>1.50</text> </g> <text class="nj-charts-rowlabel " x=216 y=174 text-anchor=end>simdjson</text> <g class=nj-heat-cell tabindex=0 data-tip="simdjson · validate
2.01× the time of the fastest library (fully validating)
way: D​OM
twitter.json: 311 µs
citm_catalog.json: 780 µs
canada.json: 3,351 µs
jeopardy.json: 116,704 µs"> <rect class=nj-heat-2 x=225 y=153 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=270 y=174 text-anchor=middle>2.01</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="simdjson · sum
1.00× the time of the fastest library (fully validating)
way: On-Demand
twitter.json: 356 µs
citm_catalog.json: 812 µs
canada.json: 3,435 µs
jeopardy.json: 96,250 µs"> <rect class=nj-heat-0 x=317 y=153 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=362 y=174 text-anchor=middle>1.00</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="simdjson · select
1.35× the time of the fastest library (fully validating)
way: D​OM
twitter.json: 324 µs
citm_catalog.json: 756 µs
canada.json: 3,409 µs
jeopardy.json: 123,214 µs"> <rect class=nj-heat-1 x=409 y=153 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=431.5 y=174 text-anchor=middle>1.35</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="simdjson · select, checking less
0.57× the time of the fastest fully validating library
twitter.json: 184 µs · On-Demand (key selectors)
citm_catalog.json: 509 µs · On-Demand
canada.json: 700 µs · On-Demand
jeopardy.json: 48,614 µs · On-Demand
reads lazily: On-Demand reads only what you ask for and steps over the rest by matching brackets"> <rect class=nj-heat-0 x=455 y=153 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=476.5 y=168 text-anchor=middle>0.57</text> <text class="nj-charts-cell nj-charts-cell--small" x=476.5 y=181 text-anchor=middle>P</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="simdjson · edit
simdjson's documents are read-only: it has no A​PI to change a value and write the result"> <rect class=nj-heat-na x=501 y=153 width=90 height=34 rx=3 /> <text class=nj-charts-tick x=546 y=174>n/a</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="simdjson · minify
1.58× the time of the fastest library (fully validating)
way: D​OM + to_string
twitter.json: 742 µs
citm_catalog.json: 1,393 µs
canada.json: 8,808 µs
jeopardy.json: 266,718 µs"> <rect class=nj-heat-2 x=593 y=153 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=615.5 y=174 text-anchor=middle>1.58</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="simdjson · minify, checking less
0.22× the time of the fastest fully validating library
way: minify
twitter.json: 123 µs
citm_catalog.json: 337 µs
canada.json: 433 µs
jeopardy.json: 47,040 µs
simdjson::minify() only removes whitespace, without parsing the values"> <rect class=nj-heat-0 x=639 y=153 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=660.5 y=168 text-anchor=middle>0.22</text> <text class="nj-charts-cell nj-charts-cell--small" x=660.5 y=181 text-anchor=middle>P</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="simdjson · write
2.07× the time of the fastest library (fully validating)
way: to_string
twitter.json: 359 µs
citm_catalog.json: 637 µs
canada.json: 4,999 µs
jeopardy.json: 154,364 µs"> <rect class=nj-heat-2 x=685 y=153 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=730 y=174 text-anchor=middle>2.07</text> </g> <text class="nj-charts-rowlabel " x=216 y=210 text-anchor=end>sonic-rs (Rust)</text> <g class=nj-heat-cell tabindex=0 data-tip="sonic-rs (Rust) · validate
1.79× the time of the fastest library (fully validating)
way: IgnoredAny
twitter.json: 501 µs
citm_catalog.json: 970 µs
canada.json: 2,249 µs
jeopardy.json: 54,369 µs"> <rect class=nj-heat-2 x=225 y=189 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=270 y=210 text-anchor=middle>1.79</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="sonic-rs (Rust) · sum
1.11× the time of the fastest library (fully validating)
way: visitor
twitter.json: 501 µs
citm_catalog.json: 1,123 µs
canada.json: 4,397 µs
jeopardy.json: 59,583 µs"> <rect class=nj-heat-0 x=317 y=189 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=362 y=210 text-anchor=middle>1.11</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="sonic-rs (Rust) · select
1.37× the time of the fastest library (fully validating)
way: structs
twitter.json: 504 µs
citm_catalog.json: 1,033 µs
canada.json: 2,328 µs
jeopardy.json: 90,486 µs"> <rect class=nj-heat-1 x=409 y=189 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=454 y=210 text-anchor=middle>1.37</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="sonic-rs (Rust) · edit
1.91× the time of the fastest library (fully validating)
way: Value
twitter.json: 1,197 µs
citm_catalog.json: 2,389 µs
canada.json: 7,744 µs
jeopardy.json: 390,952 µs"> <rect class=nj-heat-2 x=501 y=189 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=546 y=210 text-anchor=middle>1.91</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="sonic-rs (Rust) · minify
1.73× the time of the fastest library (fully validating)
way: Value
twitter.json: 1,000 µs
citm_catalog.json: 2,097 µs
canada.json: 7,795 µs
jeopardy.json: 215,280 µs"> <rect class=nj-heat-2 x=593 y=189 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=638 y=210 text-anchor=middle>1.73</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="sonic-rs (Rust) · write
2.07× the time of the fastest library (fully validating)
way: Value
twitter.json: 434 µs
citm_catalog.json: 927 µs
canada.json: 3,987 µs
jeopardy.json: 109,176 µs"> <rect class=nj-heat-2 x=685 y=189 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=730 y=210 text-anchor=middle>2.07</text> </g> <text class="nj-charts-rowlabel " x=216 y=246 text-anchor=end>Boost.J&#8203;SON</text> <g class=nj-heat-cell tabindex=0 data-tip="Boost.J​SON · validate
1.88× the time of the fastest library (fully validating)
way: S​AX (numbers: none)
twitter.json: 710 µs
citm_catalog.json: 969 µs
canada.json: 1,718 µs
jeopardy.json: 61,476 µs"> <rect class=nj-heat-2 x=225 y=225 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=270 y=246 text-anchor=middle>1.88</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="Boost.J​SON · sum
1.33× the time of the fastest library (fully validating)
way: S​AX
twitter.json: 734 µs
citm_catalog.json: 1,030 µs
canada.json: 6,103 µs
jeopardy.json: 64,382 µs"> <rect class=nj-heat-1 x=317 y=225 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=362 y=246 text-anchor=middle>1.33</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="Boost.J​SON · select
2.30× the time of the fastest library (fully validating)
twitter.json: 884 µs · parse_into structs
citm_catalog.json: 1,380 µs · parse_into structs
canada.json: 7,217 µs · parse
jeopardy.json: 99,078 µs · parse_into structs"> <rect class=nj-heat-2 x=409 y=225 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=454 y=246 text-anchor=middle>2.30</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="Boost.J​SON · edit
2.55× the time of the fastest library (fully validating)
way: parse
twitter.json: 1,963 µs
citm_catalog.json: 2,936 µs
canada.json: 13,414 µs
jeopardy.json: 356,244 µs"> <rect class=nj-heat-3 x=501 y=225 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=546 y=246 text-anchor=middle>2.55</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="Boost.J​SON · minify
2.92× the time of the fastest library (fully validating)
way: parse + serialize
twitter.json: 2,086 µs
citm_catalog.json: 2,919 µs
canada.json: 13,974 µs
jeopardy.json: 334,468 µs"> <rect class=nj-heat-3 x=593 y=225 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=638 y=246 text-anchor=middle>2.92</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="Boost.J​SON · write
2.56× the time of the fastest library (fully validating)
way: serialize
twitter.json: 480 µs
citm_catalog.json: 1,016 µs
canada.json: 6,154 µs
jeopardy.json: 139,022 µs"> <rect class=nj-heat-3 x=685 y=225 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=730 y=246 text-anchor=middle>2.56</text> </g> <text class="nj-charts-rowlabel " x=216 y=282 text-anchor=end>simd-json (Rust)</text> <g class=nj-heat-cell tabindex=0 data-tip="simd-json (Rust) · validate
3.35× the time of the fastest library (fully validating)
way: tape (copy)
twitter.json: 567 µs
citm_catalog.json: 1,430 µs
canada.json: 4,359 µs
jeopardy.json: 207,551 µs
(copy): parses in place, on a copy of the input that is part of the time"> <rect class=nj-heat-3 x=225 y=261 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=270 y=282 text-anchor=middle>3.35</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="simd-json (Rust) · sum
1.88× the time of the fastest library (fully validating)
way: visitor (copy)
twitter.json: 681 µs
citm_catalog.json: 1,650 µs
canada.json: 5,083 µs
jeopardy.json: 210,185 µs
(copy): parses in place, on a copy of the input that is part of the time"> <rect class=nj-heat-2 x=317 y=261 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=362 y=282 text-anchor=middle>1.88</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="simd-json (Rust) · select
2.61× the time of the fastest library (fully validating)
way: structs (copy)
twitter.json: 679 µs
citm_catalog.json: 1,731 µs
canada.json: 5,144 µs
jeopardy.json: 239,164 µs
(copy): parses in place, on a copy of the input that is part of the time"> <rect class=nj-heat-3 x=409 y=261 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=454 y=282 text-anchor=middle>2.61</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="simd-json (Rust) · edit
2.89× the time of the fastest library (fully validating)
twitter.json: 1,862 µs · borrowed (copy)
citm_catalog.json: 4,194 µs · borrowed (copy)
canada.json: 14,896 µs · owned (copy)
jeopardy.json: 391,369 µs · borrowed (copy)
(copy): parses in place, on a copy of the input that is part of the time"> <rect class=nj-heat-3 x=501 y=261 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=546 y=282 text-anchor=middle>2.89</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="simd-json (Rust) · minify
3.39× the time of the fastest library (fully validating)
way: borrowed (copy)
twitter.json: 1,889 µs
citm_catalog.json: 4,196 µs
canada.json: 15,716 µs
jeopardy.json: 414,377 µs
(copy): parses in place, on a copy of the input that is part of the time"> <rect class=nj-heat-3 x=593 y=261 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=638 y=282 text-anchor=middle>3.39</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="simd-json (Rust) · write
2.35× the time of the fastest library (fully validating)
way: borrowed
twitter.json: 582 µs
citm_catalog.json: 800 µs
canada.json: 5,147 µs
jeopardy.json: 122,623 µs"> <rect class=nj-heat-2 x=685 y=261 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=730 y=282 text-anchor=middle>2.35</text> </g> <text class="nj-charts-rowlabel " x=216 y=318 text-anchor=end>serde_json (Rust)</text> <g class=nj-heat-cell tabindex=0 data-tip="serde_json (Rust) · validate
2.22× the time of the fastest library (fully validating)
way: from_utf8 + IgnoredAny
twitter.json: 624 µs
citm_catalog.json: 1,440 µs
canada.json: 2,406 µs
jeopardy.json: 64,720 µs"> <rect class=nj-heat-2 x=225 y=297 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=247.5 y=318 text-anchor=middle>2.22</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="serde_json (Rust) · validate, checking less
1.98× the time of the fastest fully validating library
way: IgnoredAny
twitter.json: 484 µs
citm_catalog.json: 1,370 µs
canada.json: 2,314 µs
jeopardy.json: 58,247 µs
trusts U​TF-8 in the strings it skips (from_slice); strings it reads are checked"> <rect class=nj-heat-2 x=271 y=297 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=292.5 y=312 text-anchor=middle>1.98</text> <text class="nj-charts-cell nj-charts-cell--small" x=292.5 y=325 text-anchor=middle>U</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="serde_json (Rust) · sum
2.32× the time of the fastest library (fully validating)
way: visitor
twitter.json: 1,311 µs
citm_catalog.json: 2,288 µs
canada.json: 7,127 µs
jeopardy.json: 129,497 µs"> <rect class=nj-heat-2 x=317 y=297 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=362 y=318 text-anchor=middle>2.32</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="serde_json (Rust) · select
1.75× the time of the fastest library (fully validating)
way: from_utf8 + structs
twitter.json: 701 µs
citm_catalog.json: 1,532 µs
canada.json: 2,529 µs
jeopardy.json: 107,316 µs"> <rect class=nj-heat-2 x=409 y=297 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=454 y=318 text-anchor=middle>1.75</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="serde_json (Rust) · edit
4.55× the time of the fastest library (fully validating)
way: Value
twitter.json: 4,042 µs
citm_catalog.json: 6,586 µs
canada.json: 16,631 µs
jeopardy.json: 632,766 µs"> <rect class=nj-heat-3 x=501 y=297 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=546 y=318 text-anchor=middle>4.55</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="serde_json (Rust) · minify
4.94× the time of the fastest library (fully validating)
way: Value
twitter.json: 4,012 µs
citm_catalog.json: 6,583 µs
canada.json: 17,306 µs
jeopardy.json: 509,702 µs"> <rect class=nj-heat-3 x=593 y=297 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=638 y=318 text-anchor=middle>4.94</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="serde_json (Rust) · write
2.28× the time of the fastest library (fully validating)
way: Value
twitter.json: 550 µs
citm_catalog.json: 887 µs
canada.json: 4,005 µs
jeopardy.json: 134,163 µs"> <rect class=nj-heat-2 x=685 y=297 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=730 y=318 text-anchor=middle>2.28</text> </g> <text class="nj-charts-rowlabel " x=216 y=354 text-anchor=end>Glaze</text> <g class=nj-heat-cell tabindex=0 data-tip="Glaze · validate
2.21× the time of the fastest library (fully validating)
way: validate_json
twitter.json: 590 µs
citm_catalog.json: 1,545 µs
canada.json: 1,980 µs
jeopardy.json: 76,009 µs"> <rect class=nj-heat-2 x=225 y=333 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=270 y=354 text-anchor=middle>2.21</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="Glaze · sum
4.04× the time of the fastest library (fully validating)
way: generic (double, strict)
twitter.json: 2,345 µs
citm_catalog.json: 4,080 µs
canada.json: 10,576 µs
jeopardy.json: 250,685 µs"> <rect class=nj-heat-3 x=317 y=333 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=362 y=354 text-anchor=middle>4.04</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="Glaze · select
1.44× the time of the fastest library (fully validating)
way: structs (validate_skipped)
twitter.json: 529 µs
citm_catalog.json: 1,435 µs
canada.json: 1,913 µs
jeopardy.json: 91,253 µs"> <rect class=nj-heat-1 x=409 y=333 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=431.5 y=354 text-anchor=middle>1.44</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="Glaze · select, checking less
0.60× the time of the fastest fully validating library
way: structs
twitter.json: 342 µs
citm_catalog.json: 410 µs
canada.json: 431 µs
jeopardy.json: 66,069 µs
reads into structs and steps over fields it doesn't know without checking them (validate_skipped checks them too)"> <rect class=nj-heat-0 x=455 y=333 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=476.5 y=348 text-anchor=middle>0.60</text> <text class="nj-charts-cell nj-charts-cell--small" x=476.5 y=361 text-anchor=middle>P</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="Glaze · edit
4.85× the time of the fastest library (fully validating)
way: generic (strict)
twitter.json: 3,525 µs
citm_catalog.json: 6,551 µs
canada.json: 23,644 µs
jeopardy.json: 661,941 µs"> <rect class=nj-heat-3 x=501 y=333 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=546 y=354 text-anchor=middle>4.85</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="Glaze · minify
5.10× the time of the fastest library (fully validating)
way: generic (strict)
twitter.json: 3,780 µs
citm_catalog.json: 6,416 µs
canada.json: 23,765 µs
jeopardy.json: 458,311 µs"> <rect class=nj-heat-4 x=593 y=333 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=615.5 y=354 text-anchor=middle>5.10</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="Glaze · minify, checking less
0.73× the time of the fastest fully validating library
way: minify_json
twitter.json: 422 µs
citm_catalog.json: 1,144 µs
canada.json: 2,350 µs
jeopardy.json: 96,405 µs
minify_json only removes whitespace, without parsing the values"> <rect class=nj-heat-0 x=639 y=333 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=660.5 y=348 text-anchor=middle>0.73</text> <text class="nj-charts-cell nj-charts-cell--small" x=660.5 y=361 text-anchor=middle>P</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="Glaze · write
1.84× the time of the fastest library (fully validating)
twitter.json: 360 µs · generic
citm_catalog.json: 660 µs · generic
canada.json: 3,714 µs · generic (strict)
jeopardy.json: 124,598 µs · generic"> <rect class=nj-heat-2 x=685 y=333 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=730 y=354 text-anchor=middle>1.84</text> </g> <text class="nj-charts-rowlabel nj-charts-name-json" x=216 y=390 text-anchor=end>nlohmann/json json</text> <g class=nj-heat-cell tabindex=0 data-tip="nlohmann/json json · validate
2.74× the time of the fastest library (fully validating)
way: accept
twitter.json: 677 µs
citm_catalog.json: 1,433 µs
canada.json: 4,584 µs
jeopardy.json: 73,561 µs"> <rect class=nj-heat-3 x=225 y=369 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=270 y=390 text-anchor=middle>2.74</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="nlohmann/json json · sum
1.67× the time of the fastest library (fully validating)
way: sax
twitter.json: 797 µs
citm_catalog.json: 1,548 µs
canada.json: 6,004 µs
jeopardy.json: 101,516 µs"> <rect class=nj-heat-2 x=317 y=369 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=362 y=390 text-anchor=middle>1.67</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="nlohmann/json json · select
7.24× the time of the fastest library (fully validating)
way: structs (from_json)
twitter.json: 3,325 µs
citm_catalog.json: 5,126 µs
canada.json: 11,908 µs
jeopardy.json: 423,362 µs"> <rect class=nj-heat-4 x=409 y=369 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=454 y=390 text-anchor=middle>7.24</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="nlohmann/json json · edit
3.81× the time of the fastest library (fully validating)
way: ordered_json
twitter.json: 2,912 µs
citm_catalog.json: 4,999 µs
canada.json: 15,603 µs
jeopardy.json: 604,744 µs"> <rect class=nj-heat-3 x=501 y=369 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=546 y=390 text-anchor=middle>3.81</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="nlohmann/json json · minify
4.79× the time of the fastest library (fully validating)
way: parse + dump
twitter.json: 4,143 µs
citm_catalog.json: 5,702 µs
canada.json: 16,463 µs
jeopardy.json: 528,092 µs"> <rect class=nj-heat-3 x=593 y=369 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=638 y=390 text-anchor=middle>4.79</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="nlohmann/json json · write
1.99× the time of the fastest library (fully validating)
way: dump
twitter.json: 471 µs
citm_catalog.json: 644 µs
canada.json: 4,344 µs
jeopardy.json: 114,096 µs"> <rect class=nj-heat-2 x=685 y=369 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=730 y=390 text-anchor=middle>1.99</text> </g> <text class="nj-charts-rowlabel " x=216 y=426 text-anchor=end>RapidJSON</text> <g class=nj-heat-cell tabindex=0 data-tip="RapidJSON · validate
4.50× the time of the fastest library (fully validating)
twitter.json: 1,552 µs · insitu (copy untimed)
citm_catalog.json: 2,210 µs · insitu (copy untimed)
canada.json: 4,104 µs · S​AX (string stream, default precision)
jeopardy.json: 168,747 µs · insitu (copy untimed)"> <rect class=nj-heat-3 x=225 y=405 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=247.5 y=426 text-anchor=middle>4.50</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="RapidJSON · validate, checking less
3.40× the time of the fastest fully validating library
twitter.json: 1,082 µs · insitu (copy untimed) (no encoding check)
citm_catalog.json: 1,570 µs · S​AX (default precision) (no encoding check)
canada.json: 4,104 µs · S​AX (string stream, default precision) (validates fully)
jeopardy.json: 110,856 µs · insitu (copy untimed) (no encoding check)
trusts U​TF-8: RapidJSON's default (kParseValidateEncodingFlag checks it)"> <rect class=nj-heat-3 x=271 y=405 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=292.5 y=420 text-anchor=middle>3.40</text> <text class="nj-charts-cell nj-charts-cell--small" x=292.5 y=433 text-anchor=middle>U</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="RapidJSON · sum
2.98× the time of the fastest library (fully validating)
twitter.json: 1,616 µs · insitu (copy untimed)
citm_catalog.json: 2,290 µs · insitu (copy untimed)
canada.json: 11,183 µs · S​AX (string stream)
jeopardy.json: 181,500 µs · insitu (copy untimed)"> <rect class=nj-heat-3 x=317 y=405 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=339.5 y=426 text-anchor=middle>2.98</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="RapidJSON · sum, checking less
2.29× the time of the fastest fully validating library
twitter.json: 1,130 µs · insitu (copy untimed) (no encoding check)
citm_catalog.json: 1,743 µs · S​AX (no encoding check)
canada.json: 11,109 µs · S​AX (string stream) (no encoding check)
jeopardy.json: 119,706 µs · insitu (copy untimed) (no encoding check)
trusts U​TF-8: RapidJSON's default (kParseValidateEncodingFlag checks it)"> <rect class=nj-heat-2 x=363 y=405 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=384.5 y=420 text-anchor=middle>2.29</text> <text class="nj-charts-cell nj-charts-cell--small" x=384.5 y=433 text-anchor=middle>U</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="RapidJSON · select
3.84× the time of the fastest library (fully validating)
way: insitu (copy untimed)
twitter.json: 1,560 µs
citm_catalog.json: 2,127 µs
canada.json: 11,547 µs
jeopardy.json: 176,066 µs"> <rect class=nj-heat-3 x=409 y=405 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=431.5 y=426 text-anchor=middle>3.84</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="RapidJSON · select, checking less
3.06× the time of the fastest fully validating library
twitter.json: 1,079 µs · insitu (copy untimed) (no encoding check)
citm_catalog.json: 1,817 µs · insitu (copy untimed) (no encoding check)
canada.json: 11,436 µs · Document (string stream) (no encoding check)
jeopardy.json: 122,354 µs · insitu (copy untimed) (no encoding check)
trusts U​TF-8: RapidJSON's default (kParseValidateEncodingFlag checks it)"> <rect class=nj-heat-3 x=455 y=405 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=476.5 y=420 text-anchor=middle>3.06</text> <text class="nj-charts-cell nj-charts-cell--small" x=476.5 y=433 text-anchor=middle>U</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="RapidJSON · edit
2.92× the time of the fastest library (fully validating)
twitter.json: 2,333 µs · insitu (copy untimed)
citm_catalog.json: 3,133 µs · insitu (copy untimed)
canada.json: 20,518 µs · insitu (copy)
jeopardy.json: 315,892 µs · insitu (copy untimed)
(copy): parses in place, on a copy of the input that is part of the time"> <rect class=nj-heat-3 x=501 y=405 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=523.5 y=426 text-anchor=middle>2.92</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="RapidJSON · edit, checking less
2.58× the time of the fastest fully validating library
twitter.json: 1,838 µs · insitu (copy untimed) (no encoding check)
citm_catalog.json: 2,836 µs · insitu (copy untimed) (no encoding check)
canada.json: 20,320 µs · Document (string stream) (no encoding check)
jeopardy.json: 271,888 µs · insitu (copy untimed) (no encoding check)
trusts U​TF-8: RapidJSON's default (kParseValidateEncodingFlag checks it)"> <rect class=nj-heat-3 x=547 y=405 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=568.5 y=420 text-anchor=middle>2.58</text> <text class="nj-charts-cell nj-charts-cell--small" x=568.5 y=433 text-anchor=middle>U</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="RapidJSON · minify
3.64× the time of the fastest library (fully validating)
twitter.json: 3,015 µs · S​AX to Writer
citm_catalog.json: 3,012 µs · S​AX to Writer
canada.json: 21,177 µs · Document + Writer
jeopardy.json: 355,727 µs · S​AX to Writer (string stream)"> <rect class=nj-heat-3 x=593 y=405 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=615.5 y=426 text-anchor=middle>3.64</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="RapidJSON · minify, checking less
2.64× the time of the fastest fully validating library
twitter.json: 1,978 µs · S​AX to Writer (no encoding check)
citm_catalog.json: 2,493 µs · S​AX to Writer (no encoding check)
canada.json: 15,512 µs · S​AX to Writer (raw numbers) (no encoding check)
jeopardy.json: 249,235 µs · S​AX to Writer (string stream) (no encoding check)
trusts U​TF-8: RapidJSON's default (kParseValidateEncodingFlag checks it)
copies each number's text instead of formatting it (kParseNumbersAsStringsFlag)"> <rect class=nj-heat-3 x=639 y=405 width=44 height=34 rx=3 /> <text class=nj-charts-cell x=660.5 y=420 text-anchor=middle>2.64</text> <text class="nj-charts-cell nj-charts-cell--small" x=660.5 y=433 text-anchor=middle>U N</text> </g> <g class=nj-heat-cell tabindex=0 data-tip="RapidJSON · write
3.11× the time of the fastest library (fully validating)
way: Writer
twitter.json: 717 µs
citm_catalog.json: 1,033 µs
canada.json: 9,017 µs
jeopardy.json: 134,260 µs"> <rect class=nj-heat-3 x=685 y=405 width=90 height=34 rx=3 /> <text class=nj-charts-cell x=730 y=426 text-anchor=middle>3.11</text> </g> <text class="nj-charts-tick nj-charts-tick--l" x=8 y=472>time relative to the fastest fully validating library, less is better</text> <g><rect class=nj-heat-0 x=8 y=482 width=76 height=20 rx=3 /> <text class="nj-charts-cell nj-charts-cell--small" x=46 y=496 text-anchor=middle>below 1.15</text></g> <g><rect class=nj-heat-1 x=88 y=482 width=76 height=20 rx=3 /> <text class="nj-charts-cell nj-charts-cell--small" x=126 y=496 text-anchor=middle>1.15 to 1.5</text></g> <g><rect class=nj-heat-2 x=168 y=482 width=76 height=20 rx=3 /> <text class="nj-charts-cell nj-charts-cell--small" x=206 y=496 text-anchor=middle>1.5 to 2.5</text></g> <g><rect class=nj-heat-3 x=248 y=482 width=76 height=20 rx=3 /> <text class="nj-charts-cell nj-charts-cell--small" x=286 y=496 text-anchor=middle>2.5 to 5</text></g> <g><rect class=nj-heat-4 x=328 y=482 width=76 height=20 rx=3 /> <text class="nj-charts-cell nj-charts-cell--small" x=366 y=496 text-anchor=middle>5 and more</text></g> <rect class=nj-heat-na x=420 y=482 width=40 height=20 rx=3 /> <text class=nj-charts-tick x=440 y=496>n/a</text> <text class="nj-charts-tick nj-charts-tick--l" x=468 y=496>no A&#8203;PI for it</text> </svg></p> </div> <p class=nj-caption>The use cases on the x86-64 server with <abbr title="GNU Compiler Collection">GCC</abbr> 13.4. Less is better; hover over or tap a cell for the times and the way.</p> <details class=info> <summary>Times in µs on the Apple M1 Max</summary> <p><strong>validate</strong></p> <table> <thead> <tr> <th>library</th> <th>variant</th> <th style="text-align: right;"><code>twitter.json</code></th> <th style="text-align: right;"><code>citm_catalog.json</code></th> <th style="text-align: right;"><code>canada.json</code></th> <th style="text-align: right;"><code>jeopardy.json</code></th> <th style="text-align: right;">one status (2.5 KB)</th> </tr> </thead> <tbody> <tr> <td><strong>nlohmann/json <code>json_document</code></strong></td> <td>accept</td> <td style="text-align: right;">170</td> <td style="text-align: right;">313</td> <td style="text-align: right;">886</td> <td style="text-align: right;">20,873</td> <td style="text-align: right;">0.9</td> </tr> <tr> <td>yyjson</td> <td>insitu (copy untimed)</td> <td style="text-align: right;">172</td> <td style="text-align: right;">451</td> <td style="text-align: right;">1,457</td> <td style="text-align: right;">30,240</td> <td style="text-align: right;">0.9</td> </tr> <tr> <td>simdjson</td> <td><abbr title="Document Object Model">DOM</abbr></td> <td style="text-align: right;">212</td> <td style="text-align: right;">452</td> <td style="text-align: right;">1,888</td> <td style="text-align: right;">28,843</td> <td style="text-align: right;">1.1</td> </tr> <tr> <td>sonic-rs (Rust)</td> <td>Value</td> <td style="text-align: right;">326</td> <td style="text-align: right;">681</td> <td style="text-align: right;">1,939</td> <td style="text-align: right;">31,450</td> <td style="text-align: right;">1.4</td> </tr> <tr> <td>Glaze</td> <td>validate_json</td> <td style="text-align: right;">331</td> <td style="text-align: right;">862</td> <td style="text-align: right;">1,326</td> <td style="text-align: right;">45,192</td> <td style="text-align: right;">1.4</td> </tr> <tr> <td>simd-json (Rust)</td> <td>tape (copy)</td> <td style="text-align: right;">289</td> <td style="text-align: right;">698</td> <td style="text-align: right;">2,278</td> <td style="text-align: right;">38,874</td> <td style="text-align: right;">1.7</td> </tr> <tr> <td>sonic-cpp</td> <td>Document [U]</td> <td style="text-align: right;">– (U 382)</td> <td style="text-align: right;">– (U 985)</td> <td style="text-align: right;">– (U 2,578)</td> <td style="text-align: right;">– (U 41,617)</td> <td style="text-align: right;">– (U 1.6)</td> </tr> <tr> <td>serde_json (Rust)</td> <td>IgnoredAny [U], from_utf8 + IgnoredAny</td> <td style="text-align: right;">452 (U 354)</td> <td style="text-align: right;">1,103 (U 1,047)</td> <td style="text-align: right;">1,556 (U 1,451)</td> <td style="text-align: right;">46,517 (U 44,984)</td> <td style="text-align: right;">2.0 (U 1.7)</td> </tr> <tr> <td>Boost.<abbr title="JavaScript Object Notation">JSON</abbr></td> <td><abbr title="Simple API for XML">SAX</abbr>, <abbr title="Simple API for XML">SAX</abbr> (numbers: none)</td> <td style="text-align: right;">535</td> <td style="text-align: right;">994</td> <td style="text-align: right;">1,467</td> <td style="text-align: right;">53,939</td> <td style="text-align: right;">2.3</td> </tr> <tr> <td>nlohmann/json <code>json</code></td> <td>accept</td> <td style="text-align: right;">451</td> <td style="text-align: right;">888</td> <td style="text-align: right;">2,405</td> <td style="text-align: right;">55,286</td> <td style="text-align: right;">2.4</td> </tr> <tr> <td>RapidJSON</td> <td><abbr title="Simple API for XML">SAX</abbr> (default precision), <abbr title="Simple API for XML">SAX</abbr> (string stream, default precision), <abbr title="Simple API for XML">SAX</abbr> (string stream, default precision) (no encoding check) [U], insitu (copy untimed), insitu (copy untimed) (no encoding check) [U]</td> <td style="text-align: right;">1,307 (U 686)</td> <td style="text-align: right;">1,397 (U 1,032)</td> <td style="text-align: right;">1,982</td> <td style="text-align: right;">134,679 (U 63,589)</td> <td style="text-align: right;">6.0 (U 2.6)</td> </tr> </tbody> </table> <p><strong>sum</strong></p> <table> <thead> <tr> <th>library</th> <th>variant</th> <th style="text-align: right;"><code>twitter.json</code></th> <th style="text-align: right;"><code>citm_catalog.json</code></th> <th style="text-align: right;"><code>canada.json</code></th> <th style="text-align: right;"><code>jeopardy.json</code></th> <th style="text-align: right;">one status (2.5 KB)</th> </tr> </thead> <tbody> <tr> <td><strong>nlohmann/json <code>json_document</code></strong></td> <td>parse</td> <td style="text-align: right;">224</td> <td style="text-align: right;">485</td> <td style="text-align: right;">1,816</td> <td style="text-align: right;">28,987</td> <td style="text-align: right;">1.2</td> </tr> <tr> <td>yyjson</td> <td>insitu (copy untimed)</td> <td style="text-align: right;">219</td> <td style="text-align: right;">551</td> <td style="text-align: right;">1,906</td> <td style="text-align: right;">37,512</td> <td style="text-align: right;">1.1</td> </tr> <tr> <td>simdjson</td> <td><abbr title="Document Object Model">DOM</abbr>, On-Demand</td> <td style="text-align: right;">249</td> <td style="text-align: right;">571</td> <td style="text-align: right;">2,374</td> <td style="text-align: right;">35,111</td> <td style="text-align: right;">1.3</td> </tr> <tr> <td>sonic-rs (Rust)</td> <td>visitor</td> <td style="text-align: right;">364</td> <td style="text-align: right;">778</td> <td style="text-align: right;">2,703</td> <td style="text-align: right;">41,361</td> <td style="text-align: right;">1.7</td> </tr> <tr> <td>simd-json (Rust)</td> <td>visitor (copy)</td> <td style="text-align: right;">354</td> <td style="text-align: right;">866</td> <td style="text-align: right;">2,717</td> <td style="text-align: right;">47,518</td> <td style="text-align: right;">2.0</td> </tr> <tr> <td>sonic-cpp</td> <td>Document [U]</td> <td style="text-align: right;">– (U 428)</td> <td style="text-align: right;">– (U 1,087)</td> <td style="text-align: right;">– (U 2,993)</td> <td style="text-align: right;">– (U 48,688)</td> <td style="text-align: right;">– (U 1.9)</td> </tr> <tr> <td>nlohmann/json <code>json</code></td> <td>sax</td> <td style="text-align: right;">465</td> <td style="text-align: right;">925</td> <td style="text-align: right;">3,072</td> <td style="text-align: right;">64,089</td> <td style="text-align: right;">2.4</td> </tr> <tr> <td>Boost.<abbr title="JavaScript Object Notation">JSON</abbr></td> <td><abbr title="Simple API for XML">SAX</abbr></td> <td style="text-align: right;">535</td> <td style="text-align: right;">1,010</td> <td style="text-align: right;">3,067</td> <td style="text-align: right;">53,704</td> <td style="text-align: right;">2.3</td> </tr> <tr> <td>serde_json (Rust)</td> <td>visitor</td> <td style="text-align: right;">652</td> <td style="text-align: right;">1,242</td> <td style="text-align: right;">4,772</td> <td style="text-align: right;">66,568</td> <td style="text-align: right;">2.5</td> </tr> <tr> <td>Glaze</td> <td>generic (double) [P], generic (double, strict), lazy_json [P]</td> <td style="text-align: right;">968</td> <td style="text-align: right;">2,049</td> <td style="text-align: right;">6,331</td> <td style="text-align: right;">99,763</td> <td style="text-align: right;">4.9 (P 3.5)</td> </tr> <tr> <td>RapidJSON</td> <td><abbr title="Simple API for XML">SAX</abbr>, <abbr title="Simple API for XML">SAX</abbr> (string stream), <abbr title="Simple API for XML">SAX</abbr> (string stream) (no encoding check) [U], insitu (copy untimed) (no encoding check) [U]</td> <td style="text-align: right;">1,329 (U 735)</td> <td style="text-align: right;">1,455 (U 1,136)</td> <td style="text-align: right;">6,453</td> <td style="text-align: right;">136,103 (U 69,604)</td> <td style="text-align: right;">6.1 (U 2.9)</td> </tr> </tbody> </table> <p><strong>select</strong></p> <table> <thead> <tr> <th>library</th> <th>variant</th> <th style="text-align: right;"><code>twitter.json</code></th> <th style="text-align: right;"><code>citm_catalog.json</code></th> <th style="text-align: right;"><code>canada.json</code></th> <th style="text-align: right;"><code>jeopardy.json</code></th> <th style="text-align: right;">one status (2.5 KB)</th> </tr> </thead> <tbody> <tr> <td><strong>nlohmann/json <code>json_document</code></strong></td> <td>parse</td> <td style="text-align: right;">184</td> <td style="text-align: right;">363</td> <td style="text-align: right;">956</td> <td style="text-align: right;">24,991</td> <td style="text-align: right;">1.0</td> </tr> <tr> <td>yyjson</td> <td>insitu (copy untimed)</td> <td style="text-align: right;">178</td> <td style="text-align: right;">456</td> <td style="text-align: right;">1,461</td> <td style="text-align: right;">32,514</td> <td style="text-align: right;">1.0</td> </tr> <tr> <td>simdjson</td> <td><abbr title="Document Object Model">DOM</abbr>, On-Demand (key selectors) [P], On-Demand [P], On-Demand structs [P]</td> <td style="text-align: right;">196 (P 127)</td> <td style="text-align: right;">450 (P 354)</td> <td style="text-align: right;">1,886 (P 566)</td> <td style="text-align: right;">30,504 (P 19,562)</td> <td style="text-align: right;">1.2 (P 0.8)</td> </tr> <tr> <td>Glaze</td> <td>structs (validate_skipped), structs [P]</td> <td style="text-align: right;">311 (P 241)</td> <td style="text-align: right;">854 (P 255)</td> <td style="text-align: right;">1,316 (P 313)</td> <td style="text-align: right;">46,924 (P 37,578)</td> <td style="text-align: right;">1.4 (P 1.2)</td> </tr> <tr> <td>sonic-rs (Rust)</td> <td>Value</td> <td style="text-align: right;">333</td> <td style="text-align: right;">691</td> <td style="text-align: right;">1,936</td> <td style="text-align: right;">40,660</td> <td style="text-align: right;">1.7</td> </tr> <tr> <td>sonic-cpp</td> <td>Document [U]</td> <td style="text-align: right;">– (U 385)</td> <td style="text-align: right;">– (U 990)</td> <td style="text-align: right;">– (U 2,586)</td> <td style="text-align: right;">– (U 45,858)</td> <td style="text-align: right;">– (U 1.7)</td> </tr> <tr> <td>simd-json (Rust)</td> <td>structs (copy)</td> <td style="text-align: right;">364</td> <td style="text-align: right;">914</td> <td style="text-align: right;">2,657</td> <td style="text-align: right;">57,697</td> <td style="text-align: right;">2.1</td> </tr> <tr> <td>serde_json (Rust)</td> <td>from_utf8 + structs, structs [U]</td> <td style="text-align: right;">480 (U 410)</td> <td style="text-align: right;">1,125 (U 1,084)</td> <td style="text-align: right;">1,560 (U 1,455)</td> <td style="text-align: right;">62,378</td> <td style="text-align: right;">2.3 (U 1.9)</td> </tr> <tr> <td>Boost.<abbr title="JavaScript Object Notation">JSON</abbr></td> <td>parse, parse_into structs</td> <td style="text-align: right;">617</td> <td style="text-align: right;">1,205</td> <td style="text-align: right;">3,650</td> <td style="text-align: right;">67,255</td> <td style="text-align: right;">2.7</td> </tr> <tr> <td>RapidJSON</td> <td>Document (string stream), insitu (copy untimed), insitu (copy untimed) (no encoding check) [U]</td> <td style="text-align: right;">1,304 (U 679)</td> <td style="text-align: right;">1,554 (U 1,126)</td> <td style="text-align: right;">6,776</td> <td style="text-align: right;">141,509 (U 65,625)</td> <td style="text-align: right;">6.5 (U 2.6)</td> </tr> <tr> <td>nlohmann/json <code>json</code></td> <td>parse, structs (from_json)</td> <td style="text-align: right;">1,360</td> <td style="text-align: right;">2,416</td> <td style="text-align: right;">6,047</td> <td style="text-align: right;">179,533</td> <td style="text-align: right;">7.6</td> </tr> </tbody> </table> <p><strong>edit</strong></p> <table> <thead> <tr> <th>library</th> <th>variant</th> <th style="text-align: right;"><code>twitter.json</code></th> <th style="text-align: right;"><code>citm_catalog.json</code></th> <th style="text-align: right;"><code>canada.json</code></th> <th style="text-align: right;"><code>jeopardy.json</code></th> <th style="text-align: right;">one status (2.5 KB)</th> </tr> </thead> <tbody> <tr> <td><strong>nlohmann/json <code>json_document</code></strong></td> <td>editable, editable (source numbers) [N]</td> <td style="text-align: right;">291</td> <td style="text-align: right;">560</td> <td style="text-align: right;">2,765 (N 1,484)</td> <td style="text-align: right;">58,057</td> <td style="text-align: right;">1.9</td> </tr> <tr> <td>yyjson</td> <td>insitu (copy untimed) + mut copy</td> <td style="text-align: right;">427</td> <td style="text-align: right;">882</td> <td style="text-align: right;">3,642</td> <td style="text-align: right;">84,239</td> <td style="text-align: right;">2.4</td> </tr> <tr> <td>sonic-cpp</td> <td>Document [U]</td> <td style="text-align: right;">– (U 486)</td> <td style="text-align: right;">– (U 1,224)</td> <td style="text-align: right;">– (U 5,638)</td> <td style="text-align: right;">– (U 62,688)</td> <td style="text-align: right;">– (U 2.6)</td> </tr> <tr> <td>sonic-rs (Rust)</td> <td>Value</td> <td style="text-align: right;">634</td> <td style="text-align: right;">1,257</td> <td style="text-align: right;">4,396</td> <td style="text-align: right;">140,936</td> <td style="text-align: right;">3.8</td> </tr> <tr> <td>simd-json (Rust)</td> <td>borrowed (copy)</td> <td style="text-align: right;">948</td> <td style="text-align: right;">2,102</td> <td style="text-align: right;">7,654</td> <td style="text-align: right;">110,693</td> <td style="text-align: right;">5.4</td> </tr> <tr> <td>Boost.<abbr title="JavaScript Object Notation">JSON</abbr></td> <td>parse</td> <td style="text-align: right;">1,368</td> <td style="text-align: right;">1,992</td> <td style="text-align: right;">6,573</td> <td style="text-align: right;">155,237</td> <td style="text-align: right;">6.6</td> </tr> <tr> <td>nlohmann/json <code>json</code></td> <td>ordered_json, parse</td> <td style="text-align: right;">1,273</td> <td style="text-align: right;">2,344</td> <td style="text-align: right;">8,334</td> <td style="text-align: right;">203,232</td> <td style="text-align: right;">7.1</td> </tr> <tr> <td>Glaze</td> <td>generic (strict), generic [P]</td> <td style="text-align: right;">1,539</td> <td style="text-align: right;">3,235</td> <td style="text-align: right;">11,083</td> <td style="text-align: right;">178,333</td> <td style="text-align: right;">8.3</td> </tr> <tr> <td>RapidJSON</td> <td>Document, Document (string stream), insitu (copy untimed), insitu (copy untimed) (no encoding check) [U]</td> <td style="text-align: right;">1,922 (U 1,344)</td> <td style="text-align: right;">2,388 (U 1,964)</td> <td style="text-align: right;">13,836</td> <td style="text-align: right;">221,270 (U 144,741)</td> <td style="text-align: right;">10.3 (U 6.5)</td> </tr> <tr> <td>serde_json (Rust)</td> <td>Value</td> <td style="text-align: right;">2,009</td> <td style="text-align: right;">3,316</td> <td style="text-align: right;">9,666</td> <td style="text-align: right;">251,931</td> <td style="text-align: right;">9.6</td> </tr> </tbody> </table> <p><strong>minify</strong></p> <table> <thead> <tr> <th>library</th> <th>variant</th> <th style="text-align: right;"><code>twitter.json</code></th> <th style="text-align: right;"><code>citm_catalog.json</code></th> <th style="text-align: right;"><code>canada.json</code></th> <th style="text-align: right;"><code>jeopardy.json</code></th> <th style="text-align: right;">one status (2.5 KB)</th> </tr> </thead> <tbody> <tr> <td><strong>nlohmann/json <code>json_document</code></strong></td> <td>parse + dump, parse + dump (source numbers) [N]</td> <td style="text-align: right;">259</td> <td style="text-align: right;">493</td> <td style="text-align: right;">2,582 (N 1,360)</td> <td style="text-align: right;">37,882</td> <td style="text-align: right;">1.4</td> </tr> <tr> <td>yyjson</td> <td>insitu (copy untimed) + write, read (raw numbers) + write [N]</td> <td style="text-align: right;">279</td> <td style="text-align: right;">625</td> <td style="text-align: right;">3,196 (N 2,550)</td> <td style="text-align: right;">50,821</td> <td style="text-align: right;">1.6</td> </tr> <tr> <td>simdjson</td> <td><abbr title="Document Object Model">DOM</abbr> + to_string, minify [P]</td> <td style="text-align: right;">423 (P 62.3)</td> <td style="text-align: right;">848 (P 171)</td> <td style="text-align: right;">5,120 (P 227)</td> <td style="text-align: right;">61,059 (P 5,762)</td> <td style="text-align: right;">2.4 (P 0.3)</td> </tr> <tr> <td>sonic-rs (Rust)</td> <td>Value</td> <td style="text-align: right;">535</td> <td style="text-align: right;">1,134</td> <td style="text-align: right;">4,377</td> <td style="text-align: right;">64,832</td> <td style="text-align: right;">3.0</td> </tr> <tr> <td>sonic-cpp</td> <td>Document + Serialize [U]</td> <td style="text-align: right;">– (U 500)</td> <td style="text-align: right;">– (U 1,220)</td> <td style="text-align: right;">– (U 5,676)</td> <td style="text-align: right;">– (U 61,236)</td> <td style="text-align: right;">– (U 2.5)</td> </tr> <tr> <td>simd-json (Rust)</td> <td>borrowed (copy)</td> <td style="text-align: right;">952</td> <td style="text-align: right;">2,111</td> <td style="text-align: right;">7,658</td> <td style="text-align: right;">108,130</td> <td style="text-align: right;">5.5</td> </tr> <tr> <td>Boost.<abbr title="JavaScript Object Notation">JSON</abbr></td> <td>parse + serialize</td> <td style="text-align: right;">1,393</td> <td style="text-align: right;">1,986</td> <td style="text-align: right;">6,542</td> <td style="text-align: right;">154,677</td> <td style="text-align: right;">6.7</td> </tr> <tr> <td>RapidJSON</td> <td>Document + Writer, <abbr title="Simple API for XML">SAX</abbr> to Writer, <abbr title="Simple API for XML">SAX</abbr> to Writer (raw numbers) (no encoding check) [U N], <abbr title="Simple API for XML">SAX</abbr> to Writer (string stream), <abbr title="Simple API for XML">SAX</abbr> to Writer (string stream) (no encoding check) [U]</td> <td style="text-align: right;">1,525 (U 1,058)</td> <td style="text-align: right;">1,808 (U 1,485)</td> <td style="text-align: right;">14,460 (U N 10,908)</td> <td style="text-align: right;">174,558 (U 123,119)</td> <td style="text-align: right;">8.1 (U 5.0)</td> </tr> <tr> <td>nlohmann/json <code>json</code></td> <td>parse + dump</td> <td style="text-align: right;">1,600</td> <td style="text-align: right;">2,706</td> <td style="text-align: right;">8,389</td> <td style="text-align: right;">197,745</td> <td style="text-align: right;">8.8</td> </tr> <tr> <td>Glaze</td> <td>generic (strict), minify_json [P]</td> <td style="text-align: right;">1,505 (P 281)</td> <td style="text-align: right;">3,225 (P 729)</td> <td style="text-align: right;">11,092 (P 1,722)</td> <td style="text-align: right;">168,855 (P 39,976)</td> <td style="text-align: right;">8.1 (P 1.3)</td> </tr> <tr> <td>serde_json (Rust)</td> <td>Value</td> <td style="text-align: right;">2,004</td> <td style="text-align: right;">3,290</td> <td style="text-align: right;">9,792</td> <td style="text-align: right;">227,369</td> <td style="text-align: right;">9.5</td> </tr> </tbody> </table> <p><strong>write</strong></p> <table> <thead> <tr> <th>library</th> <th>variant</th> <th style="text-align: right;"><code>twitter.json</code></th> <th style="text-align: right;"><code>citm_catalog.json</code></th> <th style="text-align: right;"><code>canada.json</code></th> <th style="text-align: right;"><code>jeopardy.json</code></th> <th style="text-align: right;">one status (2.5 KB)</th> </tr> </thead> <tbody> <tr> <td><strong>nlohmann/json <code>json_document</code></strong></td> <td>dump, dump (source numbers) [N]</td> <td style="text-align: right;">74.3</td> <td style="text-align: right;">134</td> <td style="text-align: right;">1,621 (N 401)</td> <td style="text-align: right;">14,757</td> <td style="text-align: right;">0.5</td> </tr> <tr> <td>yyjson</td> <td>write</td> <td style="text-align: right;">103</td> <td style="text-align: right;">169</td> <td style="text-align: right;">1,731</td> <td style="text-align: right;">20,087</td> <td style="text-align: right;">0.7</td> </tr> <tr> <td>sonic-cpp</td> <td>Serialize</td> <td style="text-align: right;">108</td> <td style="text-align: right;">230</td> <td style="text-align: right;">3,093</td> <td style="text-align: right;">19,651</td> <td style="text-align: right;">0.8</td> </tr> <tr> <td>nlohmann/json <code>json</code></td> <td>dump</td> <td style="text-align: right;">223</td> <td style="text-align: right;">287</td> <td style="text-align: right;">2,276</td> <td style="text-align: right;">31,825</td> <td style="text-align: right;">1.2</td> </tr> <tr> <td>simdjson</td> <td>to_string</td> <td style="text-align: right;">199</td> <td style="text-align: right;">385</td> <td style="text-align: right;">3,241</td> <td style="text-align: right;">32,208</td> <td style="text-align: right;">1.3</td> </tr> <tr> <td>Glaze</td> <td>generic, generic (strict)</td> <td style="text-align: right;">216</td> <td style="text-align: right;">469</td> <td style="text-align: right;">1,720</td> <td style="text-align: right;">33,934</td> <td style="text-align: right;">1.3</td> </tr> <tr> <td>sonic-rs (Rust)</td> <td>Value</td> <td style="text-align: right;">212</td> <td style="text-align: right;">446</td> <td style="text-align: right;">2,419</td> <td style="text-align: right;">33,366</td> <td style="text-align: right;">1.5</td> </tr> <tr> <td>serde_json (Rust)</td> <td>Value</td> <td style="text-align: right;">322</td> <td style="text-align: right;">490</td> <td style="text-align: right;">2,286</td> <td style="text-align: right;">49,967</td> <td style="text-align: right;">2.0</td> </tr> <tr> <td>simd-json (Rust)</td> <td>borrowed</td> <td style="text-align: right;">355</td> <td style="text-align: right;">478</td> <td style="text-align: right;">2,728</td> <td style="text-align: right;">47,412</td> <td style="text-align: right;">1.8</td> </tr> <tr> <td>Boost.<abbr title="JavaScript Object Notation">JSON</abbr></td> <td>serialize</td> <td style="text-align: right;">507</td> <td style="text-align: right;">508</td> <td style="text-align: right;">2,923</td> <td style="text-align: right;">62,583</td> <td style="text-align: right;">2.9</td> </tr> <tr> <td>RapidJSON</td> <td>Writer</td> <td style="text-align: right;">603</td> <td style="text-align: right;">830</td> <td style="text-align: right;">6,995</td> <td style="text-align: right;">81,150</td> <td style="text-align: right;">3.9</td> </tr> </tbody> </table> </details> <details class=info> <summary>Times in µs on x86-64 with <abbr title="GNU Compiler Collection">GCC</abbr> 16.2</summary> <p><strong>validate</strong></p> <table> <thead> <tr> <th>library</th> <th>variant</th> <th style="text-align: right;"><code>twitter.json</code></th> <th style="text-align: right;"><code>citm_catalog.json</code></th> <th style="text-align: right;"><code>canada.json</code></th> <th style="text-align: right;"><code>jeopardy.json</code></th> <th style="text-align: right;">one status (2.5 KB)</th> </tr> </thead> <tbody> <tr> <td><strong>nlohmann/json <code>json_document</code></strong></td> <td>accept</td> <td style="text-align: right;">258</td> <td style="text-align: right;">513</td> <td style="text-align: right;">934</td> <td style="text-align: right;">34,514</td> <td style="text-align: right;">1.2</td> </tr> <tr> <td>yyjson</td> <td>insitu (copy untimed), read (raw numbers)</td> <td style="text-align: right;">352</td> <td style="text-align: right;">837</td> <td style="text-align: right;">2,199</td> <td style="text-align: right;">93,043</td> <td style="text-align: right;">1.5</td> </tr> <tr> <td>sonic-rs (Rust)</td> <td>IgnoredAny</td> <td style="text-align: right;">501</td> <td style="text-align: right;">970</td> <td style="text-align: right;">2,249</td> <td style="text-align: right;">54,369</td> <td style="text-align: right;">1.8</td> </tr> <tr> <td>Boost.<abbr title="JavaScript Object Notation">JSON</abbr></td> <td><abbr title="Simple API for XML">SAX</abbr>, <abbr title="Simple API for XML">SAX</abbr> (numbers: none)</td> <td style="text-align: right;">690</td> <td style="text-align: right;">917</td> <td style="text-align: right;">1,676</td> <td style="text-align: right;">62,781</td> <td style="text-align: right;">2.9</td> </tr> <tr> <td>simdjson</td> <td><abbr title="Document Object Model">DOM</abbr></td> <td style="text-align: right;">301</td> <td style="text-align: right;">695</td> <td style="text-align: right;">3,337</td> <td style="text-align: right;">120,982</td> <td style="text-align: right;">1.7</td> </tr> <tr> <td>sonic-cpp</td> <td>Document [U]</td> <td style="text-align: right;">– (U 403)</td> <td style="text-align: right;">– (U 932)</td> <td style="text-align: right;">– (U 3,349)</td> <td style="text-align: right;">– (U 98,511)</td> <td style="text-align: right;">– (U 1.7)</td> </tr> <tr> <td>serde_json (Rust)</td> <td>IgnoredAny [U], from_utf8 + IgnoredAny</td> <td style="text-align: right;">624 (U 484)</td> <td style="text-align: right;">1,440 (U 1,370)</td> <td style="text-align: right;">2,406 (U 2,314)</td> <td style="text-align: right;">64,720 (U 58,247)</td> <td style="text-align: right;">2.4 (U 1.9)</td> </tr> <tr> <td>Glaze</td> <td>validate_json</td> <td style="text-align: right;">712</td> <td style="text-align: right;">1,983</td> <td style="text-align: right;">2,625</td> <td style="text-align: right;">76,759</td> <td style="text-align: right;">2.5</td> </tr> <tr> <td>nlohmann/json <code>json</code></td> <td>accept</td> <td style="text-align: right;">683</td> <td style="text-align: right;">1,419</td> <td style="text-align: right;">4,559</td> <td style="text-align: right;">74,331</td> <td style="text-align: right;">3.1</td> </tr> <tr> <td>simd-json (Rust)</td> <td>tape (copy)</td> <td style="text-align: right;">567</td> <td style="text-align: right;">1,430</td> <td style="text-align: right;">4,359</td> <td style="text-align: right;">207,551</td> <td style="text-align: right;">2.9</td> </tr> <tr> <td>RapidJSON</td> <td><abbr title="Simple API for XML">SAX</abbr> (default precision) (no encoding check) [U], <abbr title="Simple API for XML">SAX</abbr> (string stream, default precision), <abbr title="Simple API for XML">SAX</abbr> (string stream, default precision) (no encoding check) [U], insitu (copy untimed), insitu (copy untimed) (no encoding check) [U]</td> <td style="text-align: right;">1,166 (U 1,012)</td> <td style="text-align: right;">1,553 (U 1,434)</td> <td style="text-align: right;">3,875</td> <td style="text-align: right;">114,704 (U 102,635)</td> <td style="text-align: right;">4.8 (U 3.2)</td> </tr> </tbody> </table> <p><strong>sum</strong></p> <table> <thead> <tr> <th>library</th> <th>variant</th> <th style="text-align: right;"><code>twitter.json</code></th> <th style="text-align: right;"><code>citm_catalog.json</code></th> <th style="text-align: right;"><code>canada.json</code></th> <th style="text-align: right;"><code>jeopardy.json</code></th> <th style="text-align: right;">one status (2.5 KB)</th> </tr> </thead> <tbody> <tr> <td>simdjson</td> <td>On-Demand</td> <td style="text-align: right;">348</td> <td style="text-align: right;">805</td> <td style="text-align: right;">3,452</td> <td style="text-align: right;">92,769</td> <td style="text-align: right;">1.9</td> </tr> <tr> <td><strong>nlohmann/json <code>json_document</code></strong></td> <td>parse</td> <td style="text-align: right;">398</td> <td style="text-align: right;">972</td> <td style="text-align: right;">3,501</td> <td style="text-align: right;">89,756</td> <td style="text-align: right;">2.0</td> </tr> <tr> <td>yyjson</td> <td>insitu (copy untimed)</td> <td style="text-align: right;">415</td> <td style="text-align: right;">986</td> <td style="text-align: right;">3,818</td> <td style="text-align: right;">97,586</td> <td style="text-align: right;">1.9</td> </tr> <tr> <td>sonic-rs (Rust)</td> <td>visitor</td> <td style="text-align: right;">501</td> <td style="text-align: right;">1,123</td> <td style="text-align: right;">4,397</td> <td style="text-align: right;">59,583</td> <td style="text-align: right;">2.5</td> </tr> <tr> <td>sonic-cpp</td> <td>Document [U]</td> <td style="text-align: right;">– (U 456)</td> <td style="text-align: right;">– (U 1,115)</td> <td style="text-align: right;">– (U 3,980)</td> <td style="text-align: right;">– (U 105,081)</td> <td style="text-align: right;">– (U 2.0)</td> </tr> <tr> <td>Boost.<abbr title="JavaScript Object Notation">JSON</abbr></td> <td><abbr title="Simple API for XML">SAX</abbr></td> <td style="text-align: right;">699</td> <td style="text-align: right;">957</td> <td style="text-align: right;">5,835</td> <td style="text-align: right;">59,656</td> <td style="text-align: right;">3.0</td> </tr> <tr> <td>nlohmann/json <code>json</code></td> <td>sax</td> <td style="text-align: right;">814</td> <td style="text-align: right;">1,666</td> <td style="text-align: right;">5,690</td> <td style="text-align: right;">97,414</td> <td style="text-align: right;">4.0</td> </tr> <tr> <td>simd-json (Rust)</td> <td>visitor (copy)</td> <td style="text-align: right;">681</td> <td style="text-align: right;">1,650</td> <td style="text-align: right;">5,083</td> <td style="text-align: right;">210,185</td> <td style="text-align: right;">3.5</td> </tr> <tr> <td>RapidJSON</td> <td><abbr title="Simple API for XML">SAX</abbr> (string stream), <abbr title="Simple API for XML">SAX</abbr> (string stream) (no encoding check) [U], insitu (copy untimed), insitu (copy untimed) (no encoding check) [U]</td> <td style="text-align: right;">1,221 (U 1,063)</td> <td style="text-align: right;">1,717 (U 1,635)</td> <td style="text-align: right;">9,435</td> <td style="text-align: right;">112,158 (U 105,845)</td> <td style="text-align: right;">5.1 (U 3.5)</td> </tr> <tr> <td>serde_json (Rust)</td> <td>visitor</td> <td style="text-align: right;">1,311</td> <td style="text-align: right;">2,288</td> <td style="text-align: right;">7,127</td> <td style="text-align: right;">129,497</td> <td style="text-align: right;">4.6</td> </tr> <tr> <td>Glaze</td> <td>generic (double) [P], generic (double, strict), lazy_json [P]</td> <td style="text-align: right;">2,483</td> <td style="text-align: right;">4,413</td> <td style="text-align: right;">10,532</td> <td style="text-align: right;">231,505</td> <td style="text-align: right;">8.5 (P 6.4)</td> </tr> </tbody> </table> <p><strong>select</strong></p> <table> <thead> <tr> <th>library</th> <th>variant</th> <th style="text-align: right;"><code>twitter.json</code></th> <th style="text-align: right;"><code>citm_catalog.json</code></th> <th style="text-align: right;"><code>canada.json</code></th> <th style="text-align: right;"><code>jeopardy.json</code></th> <th style="text-align: right;">one status (2.5 KB)</th> </tr> </thead> <tbody> <tr> <td><strong>nlohmann/json <code>json_document</code></strong></td> <td>parse, structs (from_json)</td> <td style="text-align: right;">333</td> <td style="text-align: right;">828</td> <td style="text-align: right;">1,368</td> <td style="text-align: right;">89,876</td> <td style="text-align: right;">1.7</td> </tr> <tr> <td>yyjson</td> <td>insitu (copy untimed), read (raw numbers)</td> <td style="text-align: right;">366</td> <td style="text-align: right;">840</td> <td style="text-align: right;">2,204</td> <td style="text-align: right;">96,172</td> <td style="text-align: right;">1.7</td> </tr> <tr> <td>sonic-rs (Rust)</td> <td>structs</td> <td style="text-align: right;">504</td> <td style="text-align: right;">1,033</td> <td style="text-align: right;">2,328</td> <td style="text-align: right;">90,486</td> <td style="text-align: right;">2.0</td> </tr> <tr> <td>simdjson</td> <td><abbr title="Document Object Model">DOM</abbr>, On-Demand (key selectors) [P], On-Demand [P]</td> <td style="text-align: right;">313 (P 180)</td> <td style="text-align: right;">699 (P 496)</td> <td style="text-align: right;">3,325 (P 690)</td> <td style="text-align: right;">122,556 (P 48,272)</td> <td style="text-align: right;">1.9 (P 1.1)</td> </tr> <tr> <td>sonic-cpp</td> <td>Document [U]</td> <td style="text-align: right;">– (U 407)</td> <td style="text-align: right;">– (U 948)</td> <td style="text-align: right;">– (U 3,464)</td> <td style="text-align: right;">– (U 110,885)</td> <td style="text-align: right;">– (U 1.8)</td> </tr> <tr> <td>serde_json (Rust)</td> <td>from_utf8 + structs, structs [U]</td> <td style="text-align: right;">701</td> <td style="text-align: right;">1,532</td> <td style="text-align: right;">2,529 (U 2,402)</td> <td style="text-align: right;">107,316</td> <td style="text-align: right;">3.0</td> </tr> <tr> <td>Glaze</td> <td>structs (validate_skipped), structs [P]</td> <td style="text-align: right;">606 (P 344)</td> <td style="text-align: right;">2,476 (P 402)</td> <td style="text-align: right;">2,557 (P 417)</td> <td style="text-align: right;">89,957 (P 67,467)</td> <td style="text-align: right;">2.1 (P 1.5)</td> </tr> <tr> <td>simd-json (Rust)</td> <td>structs (copy)</td> <td style="text-align: right;">679</td> <td style="text-align: right;">1,731</td> <td style="text-align: right;">5,144</td> <td style="text-align: right;">239,164</td> <td style="text-align: right;">3.5</td> </tr> <tr> <td>Boost.<abbr title="JavaScript Object Notation">JSON</abbr></td> <td>parse, parse_into structs</td> <td style="text-align: right;">887</td> <td style="text-align: right;">1,270</td> <td style="text-align: right;">7,292</td> <td style="text-align: right;">95,866</td> <td style="text-align: right;">3.7</td> </tr> <tr> <td>RapidJSON</td> <td>Document (string stream), insitu (copy untimed), insitu (copy untimed) (no encoding check) [U]</td> <td style="text-align: right;">1,180 (U 1,022)</td> <td style="text-align: right;">1,693</td> <td style="text-align: right;">10,390</td> <td style="text-align: right;">116,394 (U 108,290)</td> <td style="text-align: right;">4.9 (U 3.4)</td> </tr> <tr> <td>nlohmann/json <code>json</code></td> <td>parse, structs (from_json)</td> <td style="text-align: right;">3,360</td> <td style="text-align: right;">5,268</td> <td style="text-align: right;">12,006</td> <td style="text-align: right;">410,221</td> <td style="text-align: right;">17.7</td> </tr> </tbody> </table> <p><strong>edit</strong></p> <table> <thead> <tr> <th>library</th> <th>variant</th> <th style="text-align: right;"><code>twitter.json</code></th> <th style="text-align: right;"><code>citm_catalog.json</code></th> <th style="text-align: right;"><code>canada.json</code></th> <th style="text-align: right;"><code>jeopardy.json</code></th> <th style="text-align: right;">one status (2.5 KB)</th> </tr> </thead> <tbody> <tr> <td><strong>nlohmann/json <code>json_document</code></strong></td> <td>editable, editable (source numbers) [N]</td> <td style="text-align: right;">536</td> <td style="text-align: right;">1,162</td> <td style="text-align: right;">5,567 (N 2,188)</td> <td style="text-align: right;">192,323</td> <td style="text-align: right;">3.0</td> </tr> <tr> <td>sonic-cpp</td> <td>Document [U]</td> <td style="text-align: right;">– (U 620)</td> <td style="text-align: right;">– (U 1,438)</td> <td style="text-align: right;">– (U 8,495)</td> <td style="text-align: right;">– (U 186,078)</td> <td style="text-align: right;">– (U 3.4)</td> </tr> <tr> <td>yyjson</td> <td>insitu (copy untimed) + mut copy</td> <td style="text-align: right;">746</td> <td style="text-align: right;">1,526</td> <td style="text-align: right;">7,479</td> <td style="text-align: right;">275,025</td> <td style="text-align: right;">3.6</td> </tr> <tr> <td>sonic-rs (Rust)</td> <td>Value</td> <td style="text-align: right;">1,197</td> <td style="text-align: right;">2,389</td> <td style="text-align: right;">7,744</td> <td style="text-align: right;">390,952</td> <td style="text-align: right;">6.9</td> </tr> <tr> <td>Boost.<abbr title="JavaScript Object Notation">JSON</abbr></td> <td>parse</td> <td style="text-align: right;">1,767</td> <td style="text-align: right;">2,493</td> <td style="text-align: right;">12,767</td> <td style="text-align: right;">331,310</td> <td style="text-align: right;">8.5</td> </tr> <tr> <td>RapidJSON</td> <td>Document (string stream), insitu (copy untimed), insitu (copy untimed) (no encoding check) [U]</td> <td style="text-align: right;">1,865 (U 1,737)</td> <td style="text-align: right;">2,616</td> <td style="text-align: right;">18,812</td> <td style="text-align: right;">245,724 (U 234,669)</td> <td style="text-align: right;">8.7 (U 7.2)</td> </tr> <tr> <td>simd-json (Rust)</td> <td>borrowed (copy), owned (copy)</td> <td style="text-align: right;">1,862</td> <td style="text-align: right;">4,194</td> <td style="text-align: right;">14,896</td> <td style="text-align: right;">391,369</td> <td style="text-align: right;">9.0</td> </tr> <tr> <td>nlohmann/json <code>json</code></td> <td>ordered_json</td> <td style="text-align: right;">2,832</td> <td style="text-align: right;">4,970</td> <td style="text-align: right;">15,806</td> <td style="text-align: right;">647,704</td> <td style="text-align: right;">13.1</td> </tr> <tr> <td>Glaze</td> <td>generic (strict), generic [P]</td> <td style="text-align: right;">3,389</td> <td style="text-align: right;">6,002</td> <td style="text-align: right;">21,598</td> <td style="text-align: right;">607,767</td> <td style="text-align: right;">14.8</td> </tr> <tr> <td>serde_json (Rust)</td> <td>Value</td> <td style="text-align: right;">4,042</td> <td style="text-align: right;">6,586</td> <td style="text-align: right;">16,631</td> <td style="text-align: right;">632,766</td> <td style="text-align: right;">17.6</td> </tr> </tbody> </table> <p><strong>minify</strong></p> <table> <thead> <tr> <th>library</th> <th>variant</th> <th style="text-align: right;"><code>twitter.json</code></th> <th style="text-align: right;"><code>citm_catalog.json</code></th> <th style="text-align: right;"><code>canada.json</code></th> <th style="text-align: right;"><code>jeopardy.json</code></th> <th style="text-align: right;">one status (2.5 KB)</th> </tr> </thead> <tbody> <tr> <td><strong>nlohmann/json <code>json_document</code></strong></td> <td>parse + dump, parse + dump (source numbers) [N]</td> <td style="text-align: right;">518 (N 496)</td> <td style="text-align: right;">1,045</td> <td style="text-align: right;">5,240 (N 2,196)</td> <td style="text-align: right;">143,737</td> <td style="text-align: right;">2.5 (N 2.4)</td> </tr> <tr> <td>yyjson</td> <td>insitu (copy untimed) + write, insitu (copy) + write, read (raw numbers) + write [N]</td> <td style="text-align: right;">626</td> <td style="text-align: right;">1,160</td> <td style="text-align: right;">6,701 (N 2,901)</td> <td style="text-align: right;">156,605</td> <td style="text-align: right;">2.8</td> </tr> <tr> <td>sonic-cpp</td> <td>Document + Serialize [U]</td> <td style="text-align: right;">– (U 675)</td> <td style="text-align: right;">– (U 1,417)</td> <td style="text-align: right;">– (U 8,958)</td> <td style="text-align: right;">– (U 164,630)</td> <td style="text-align: right;">– (U 3.3)</td> </tr> <tr> <td>simdjson</td> <td><abbr title="Document Object Model">DOM</abbr> + to_string, minify [P]</td> <td style="text-align: right;">714 (P 99.9)</td> <td style="text-align: right;">1,318 (P 278)</td> <td style="text-align: right;">9,135 (P 312)</td> <td style="text-align: right;">269,597 (P 42,644)</td> <td style="text-align: right;">3.7 (P 0.5)</td> </tr> <tr> <td>sonic-rs (Rust)</td> <td>Value</td> <td style="text-align: right;">1,000</td> <td style="text-align: right;">2,097</td> <td style="text-align: right;">7,795</td> <td style="text-align: right;">215,280</td> <td style="text-align: right;">5.4</td> </tr> <tr> <td>Boost.<abbr title="JavaScript Object Notation">JSON</abbr></td> <td>parse + serialize</td> <td style="text-align: right;">1,974</td> <td style="text-align: right;">2,525</td> <td style="text-align: right;">12,748</td> <td style="text-align: right;">314,299</td> <td style="text-align: right;">8.6</td> </tr> <tr> <td>RapidJSON</td> <td><abbr title="Simple API for XML">SAX</abbr> to Writer (raw numbers) [N], <abbr title="Simple API for XML">SAX</abbr> to Writer (string stream), <abbr title="Simple API for XML">SAX</abbr> to Writer (string stream) (no encoding check) [U]</td> <td style="text-align: right;">1,949 (U 1,880)</td> <td style="text-align: right;">2,382</td> <td style="text-align: right;">19,548 (N 14,400)</td> <td style="text-align: right;">231,979 (U 224,249)</td> <td style="text-align: right;">8.2 (U 6.2)</td> </tr> <tr> <td>simd-json (Rust)</td> <td>borrowed (copy)</td> <td style="text-align: right;">1,889</td> <td style="text-align: right;">4,196</td> <td style="text-align: right;">15,716</td> <td style="text-align: right;">414,377</td> <td style="text-align: right;">9.2</td> </tr> <tr> <td>Glaze</td> <td>generic (strict), minify_json [P]</td> <td style="text-align: right;">3,685 (P 442)</td> <td style="text-align: right;">5,942 (P 1,292)</td> <td style="text-align: right;">22,138 (P 2,726)</td> <td style="text-align: right;">450,322 (P 97,377)</td> <td style="text-align: right;">14.0 (P 1.9)</td> </tr> <tr> <td>serde_json (Rust)</td> <td>Value</td> <td style="text-align: right;">4,012</td> <td style="text-align: right;">6,583</td> <td style="text-align: right;">17,306</td> <td style="text-align: right;">509,702</td> <td style="text-align: right;">16.5</td> </tr> <tr> <td>nlohmann/json <code>json</code></td> <td>parse + dump</td> <td style="text-align: right;">4,196</td> <td style="text-align: right;">5,806</td> <td style="text-align: right;">16,626</td> <td style="text-align: right;">529,560</td> <td style="text-align: right;">19.2</td> </tr> </tbody> </table> <p><strong>write</strong></p> <table> <thead> <tr> <th>library</th> <th>variant</th> <th style="text-align: right;"><code>twitter.json</code></th> <th style="text-align: right;"><code>citm_catalog.json</code></th> <th style="text-align: right;"><code>canada.json</code></th> <th style="text-align: right;"><code>jeopardy.json</code></th> <th style="text-align: right;">one status (2.5 KB)</th> </tr> </thead> <tbody> <tr> <td><strong>nlohmann/json <code>json_document</code></strong></td> <td>dump, dump (source numbers) [N]</td> <td style="text-align: right;">156 (N 140)</td> <td style="text-align: right;">251 (N 230)</td> <td style="text-align: right;">3,842 (N 823)</td> <td style="text-align: right;">67,769 (N 65,376)</td> <td style="text-align: right;">0.9 (N 0.8)</td> </tr> <tr> <td>yyjson</td> <td>write</td> <td style="text-align: right;">215</td> <td style="text-align: right;">319</td> <td style="text-align: right;">3,360</td> <td style="text-align: right;">66,669</td> <td style="text-align: right;">1.3</td> </tr> <tr> <td>sonic-cpp</td> <td>Serialize</td> <td style="text-align: right;">249</td> <td style="text-align: right;">509</td> <td style="text-align: right;">5,074</td> <td style="text-align: right;">69,916</td> <td style="text-align: right;">1.6</td> </tr> <tr> <td>nlohmann/json <code>json</code></td> <td>dump</td> <td style="text-align: right;">444</td> <td style="text-align: right;">640</td> <td style="text-align: right;">4,089</td> <td style="text-align: right;">117,316</td> <td style="text-align: right;">1.8</td> </tr> <tr> <td>simdjson</td> <td>to_string</td> <td style="text-align: right;">361</td> <td style="text-align: right;">614</td> <td style="text-align: right;">5,609</td> <td style="text-align: right;">158,492</td> <td style="text-align: right;">1.8</td> </tr> <tr> <td>Glaze</td> <td>generic</td> <td style="text-align: right;">381</td> <td style="text-align: right;">730</td> <td style="text-align: right;">4,071</td> <td style="text-align: right;">131,946</td> <td style="text-align: right;">2.0</td> </tr> <tr> <td>sonic-rs (Rust)</td> <td>Value</td> <td style="text-align: right;">434</td> <td style="text-align: right;">927</td> <td style="text-align: right;">3,987</td> <td style="text-align: right;">109,176</td> <td style="text-align: right;">2.8</td> </tr> <tr> <td>Boost.<abbr title="JavaScript Object Notation">JSON</abbr></td> <td>serialize</td> <td style="text-align: right;">469</td> <td style="text-align: right;">830</td> <td style="text-align: right;">5,659</td> <td style="text-align: right;">144,174</td> <td style="text-align: right;">2.4</td> </tr> <tr> <td>simd-json (Rust)</td> <td>borrowed</td> <td style="text-align: right;">582</td> <td style="text-align: right;">800</td> <td style="text-align: right;">5,147</td> <td style="text-align: right;">122,623</td> <td style="text-align: right;">2.8</td> </tr> <tr> <td>serde_json (Rust)</td> <td>Value</td> <td style="text-align: right;">550</td> <td style="text-align: right;">887</td> <td style="text-align: right;">4,005</td> <td style="text-align: right;">134,163</td> <td style="text-align: right;">3.3</td> </tr> <tr> <td>RapidJSON</td> <td>Writer</td> <td style="text-align: right;">678</td> <td style="text-align: right;">979</td> <td style="text-align: right;">9,095</td> <td style="text-align: right;">131,408</td> <td style="text-align: right;">3.8</td> </tr> </tbody> </table> </details> <details class=info> <summary>Times in µs on x86-64 with <abbr title="GNU Compiler Collection">GCC</abbr> 13.4</summary> <p><strong>validate</strong></p> <table> <thead> <tr> <th>library</th> <th>variant</th> <th style="text-align: right;"><code>twitter.json</code></th> <th style="text-align: right;"><code>citm_catalog.json</code></th> <th style="text-align: right;"><code>canada.json</code></th> <th style="text-align: right;"><code>jeopardy.json</code></th> <th style="text-align: right;">one status (2.5 KB)</th> </tr> </thead> <tbody> <tr> <td><strong>nlohmann/json <code>json_document</code></strong></td> <td>accept</td> <td style="text-align: right;">271</td> <td style="text-align: right;">609</td> <td style="text-align: right;">1,011</td> <td style="text-align: right;">34,722</td> <td style="text-align: right;">1.2</td> </tr> <tr> <td>sonic-rs (Rust)</td> <td>IgnoredAny</td> <td style="text-align: right;">501</td> <td style="text-align: right;">970</td> <td style="text-align: right;">2,249</td> <td style="text-align: right;">54,369</td> <td style="text-align: right;">1.8</td> </tr> <tr> <td>yyjson</td> <td>insitu (copy untimed), read (raw numbers)</td> <td style="text-align: right;">348</td> <td style="text-align: right;">878</td> <td style="text-align: right;">2,256</td> <td style="text-align: right;">90,959</td> <td style="text-align: right;">1.6</td> </tr> <tr> <td>Boost.<abbr title="JavaScript Object Notation">JSON</abbr></td> <td><abbr title="Simple API for XML">SAX</abbr>, <abbr title="Simple API for XML">SAX</abbr> (numbers: none)</td> <td style="text-align: right;">710</td> <td style="text-align: right;">969</td> <td style="text-align: right;">1,718</td> <td style="text-align: right;">61,476</td> <td style="text-align: right;">3.2</td> </tr> <tr> <td>simdjson</td> <td><abbr title="Document Object Model">DOM</abbr></td> <td style="text-align: right;">311</td> <td style="text-align: right;">780</td> <td style="text-align: right;">3,351</td> <td style="text-align: right;">116,704</td> <td style="text-align: right;">1.8</td> </tr> <tr> <td>Glaze</td> <td>validate_json</td> <td style="text-align: right;">590</td> <td style="text-align: right;">1,545</td> <td style="text-align: right;">1,980</td> <td style="text-align: right;">76,009</td> <td style="text-align: right;">2.3</td> </tr> <tr> <td>sonic-cpp</td> <td>Document [U]</td> <td style="text-align: right;">– (U 408)</td> <td style="text-align: right;">– (U 1,028)</td> <td style="text-align: right;">– (U 3,622)</td> <td style="text-align: right;">– (U 96,080)</td> <td style="text-align: right;">– (U 1.6)</td> </tr> <tr> <td>serde_json (Rust)</td> <td>IgnoredAny [U], from_utf8 + IgnoredAny</td> <td style="text-align: right;">624 (U 484)</td> <td style="text-align: right;">1,440 (U 1,370)</td> <td style="text-align: right;">2,406 (U 2,314)</td> <td style="text-align: right;">64,720 (U 58,247)</td> <td style="text-align: right;">2.4 (U 1.9)</td> </tr> <tr> <td>nlohmann/json <code>json</code></td> <td>accept</td> <td style="text-align: right;">677</td> <td style="text-align: right;">1,433</td> <td style="text-align: right;">4,584</td> <td style="text-align: right;">73,561</td> <td style="text-align: right;">3.3</td> </tr> <tr> <td>simd-json (Rust)</td> <td>tape (copy)</td> <td style="text-align: right;">567</td> <td style="text-align: right;">1,430</td> <td style="text-align: right;">4,359</td> <td style="text-align: right;">207,551</td> <td style="text-align: right;">2.9</td> </tr> <tr> <td>RapidJSON</td> <td><abbr title="Simple API for XML">SAX</abbr> (default precision) (no encoding check) [U], <abbr title="Simple API for XML">SAX</abbr> (string stream, default precision), insitu (copy untimed), insitu (copy untimed) (no encoding check) [U], insitu (copy) (no encoding check) [U]</td> <td style="text-align: right;">1,552 (U 1,082)</td> <td style="text-align: right;">2,210 (U 1,570)</td> <td style="text-align: right;">4,104</td> <td style="text-align: right;">168,747 (U 110,856)</td> <td style="text-align: right;">6.9 (U 3.7)</td> </tr> </tbody> </table> <p><strong>sum</strong></p> <table> <thead> <tr> <th>library</th> <th>variant</th> <th style="text-align: right;"><code>twitter.json</code></th> <th style="text-align: right;"><code>citm_catalog.json</code></th> <th style="text-align: right;"><code>canada.json</code></th> <th style="text-align: right;"><code>jeopardy.json</code></th> <th style="text-align: right;">one status (2.5 KB)</th> </tr> </thead> <tbody> <tr> <td>simdjson</td> <td>On-Demand</td> <td style="text-align: right;">356</td> <td style="text-align: right;">812</td> <td style="text-align: right;">3,435</td> <td style="text-align: right;">96,250</td> <td style="text-align: right;">2.0</td> </tr> <tr> <td><strong>nlohmann/json <code>json_document</code></strong></td> <td>parse</td> <td style="text-align: right;">392</td> <td style="text-align: right;">946</td> <td style="text-align: right;">3,888</td> <td style="text-align: right;">89,044</td> <td style="text-align: right;">2.0</td> </tr> <tr> <td>sonic-rs (Rust)</td> <td>visitor</td> <td style="text-align: right;">501</td> <td style="text-align: right;">1,123</td> <td style="text-align: right;">4,397</td> <td style="text-align: right;">59,583</td> <td style="text-align: right;">2.5</td> </tr> <tr> <td>sonic-cpp</td> <td>Document [U]</td> <td style="text-align: right;">– (U 460)</td> <td style="text-align: right;">– (U 1,210)</td> <td style="text-align: right;">– (U 4,295)</td> <td style="text-align: right;">– (U 107,092)</td> <td style="text-align: right;">– (U 1.9)</td> </tr> <tr> <td>yyjson</td> <td>insitu (copy untimed)</td> <td style="text-align: right;">407</td> <td style="text-align: right;">1,045</td> <td style="text-align: right;">6,021</td> <td style="text-align: right;">99,764</td> <td style="text-align: right;">2.0</td> </tr> <tr> <td>Boost.<abbr title="JavaScript Object Notation">JSON</abbr></td> <td><abbr title="Simple API for XML">SAX</abbr></td> <td style="text-align: right;">734</td> <td style="text-align: right;">1,030</td> <td style="text-align: right;">6,103</td> <td style="text-align: right;">64,382</td> <td style="text-align: right;">3.3</td> </tr> <tr> <td>nlohmann/json <code>json</code></td> <td>sax</td> <td style="text-align: right;">797</td> <td style="text-align: right;">1,548</td> <td style="text-align: right;">6,004</td> <td style="text-align: right;">101,516</td> <td style="text-align: right;">4.0</td> </tr> <tr> <td>simd-json (Rust)</td> <td>visitor (copy)</td> <td style="text-align: right;">681</td> <td style="text-align: right;">1,650</td> <td style="text-align: right;">5,083</td> <td style="text-align: right;">210,185</td> <td style="text-align: right;">3.5</td> </tr> <tr> <td>serde_json (Rust)</td> <td>visitor</td> <td style="text-align: right;">1,311</td> <td style="text-align: right;">2,288</td> <td style="text-align: right;">7,127</td> <td style="text-align: right;">129,497</td> <td style="text-align: right;">4.6</td> </tr> <tr> <td>RapidJSON</td> <td><abbr title="Simple API for XML">SAX</abbr> (no encoding check) [U], <abbr title="Simple API for XML">SAX</abbr> (string stream), <abbr title="Simple API for XML">SAX</abbr> (string stream) (no encoding check) [U], insitu (copy untimed), insitu (copy untimed) (no encoding check) [U]</td> <td style="text-align: right;">1,616 (U 1,130)</td> <td style="text-align: right;">2,290 (U 1,743)</td> <td style="text-align: right;">11,183</td> <td style="text-align: right;">181,500 (U 119,706)</td> <td style="text-align: right;">7.5 (U 3.9)</td> </tr> <tr> <td>Glaze</td> <td>generic (double) [P], generic (double, strict), lazy_json [P]</td> <td style="text-align: right;">2,345</td> <td style="text-align: right;">4,080</td> <td style="text-align: right;">10,576</td> <td style="text-align: right;">250,685 (P 231,181)</td> <td style="text-align: right;">9.0 (P 6.4)</td> </tr> </tbody> </table> <p><strong>select</strong></p> <table> <thead> <tr> <th>library</th> <th>variant</th> <th style="text-align: right;"><code>twitter.json</code></th> <th style="text-align: right;"><code>citm_catalog.json</code></th> <th style="text-align: right;"><code>canada.json</code></th> <th style="text-align: right;"><code>jeopardy.json</code></th> <th style="text-align: right;">one status (2.5 KB)</th> </tr> </thead> <tbody> <tr> <td><strong>nlohmann/json <code>json_document</code></strong></td> <td>parse</td> <td style="text-align: right;">332</td> <td style="text-align: right;">765</td> <td style="text-align: right;">1,390</td> <td style="text-align: right;">88,202</td> <td style="text-align: right;">1.6</td> </tr> <tr> <td>yyjson</td> <td>insitu (copy untimed), read (raw numbers)</td> <td style="text-align: right;">361</td> <td style="text-align: right;">880</td> <td style="text-align: right;">2,236</td> <td style="text-align: right;">98,637</td> <td style="text-align: right;">1.7</td> </tr> <tr> <td>sonic-rs (Rust)</td> <td>structs</td> <td style="text-align: right;">504</td> <td style="text-align: right;">1,033</td> <td style="text-align: right;">2,328</td> <td style="text-align: right;">90,486</td> <td style="text-align: right;">2.0</td> </tr> <tr> <td>simdjson</td> <td><abbr title="Document Object Model">DOM</abbr>, On-Demand (key selectors) [P], On-Demand [P]</td> <td style="text-align: right;">324 (P 184)</td> <td style="text-align: right;">756 (P 509)</td> <td style="text-align: right;">3,409 (P 700)</td> <td style="text-align: right;">123,214 (P 48,614)</td> <td style="text-align: right;">2.0 (P 1.2)</td> </tr> <tr> <td>Glaze</td> <td>structs (validate_skipped), structs [P]</td> <td style="text-align: right;">529 (P 342)</td> <td style="text-align: right;">1,435 (P 410)</td> <td style="text-align: right;">1,913 (P 431)</td> <td style="text-align: right;">91,253 (P 66,069)</td> <td style="text-align: right;">2.0 (P 1.5)</td> </tr> <tr> <td>sonic-cpp</td> <td>Document [U]</td> <td style="text-align: right;">– (U 413)</td> <td style="text-align: right;">– (U 1,043)</td> <td style="text-align: right;">– (U 3,695)</td> <td style="text-align: right;">– (U 108,297)</td> <td style="text-align: right;">– (U 1.7)</td> </tr> <tr> <td>serde_json (Rust)</td> <td>from_utf8 + structs, structs [U]</td> <td style="text-align: right;">701</td> <td style="text-align: right;">1,532</td> <td style="text-align: right;">2,529 (U 2,402)</td> <td style="text-align: right;">107,316</td> <td style="text-align: right;">3.0</td> </tr> <tr> <td>simd-json (Rust)</td> <td>structs (copy)</td> <td style="text-align: right;">679</td> <td style="text-align: right;">1,731</td> <td style="text-align: right;">5,144</td> <td style="text-align: right;">239,164</td> <td style="text-align: right;">3.5</td> </tr> <tr> <td>Boost.<abbr title="JavaScript Object Notation">JSON</abbr></td> <td>parse, parse_into structs</td> <td style="text-align: right;">884</td> <td style="text-align: right;">1,380</td> <td style="text-align: right;">7,217</td> <td style="text-align: right;">99,078</td> <td style="text-align: right;">3.9</td> </tr> <tr> <td>RapidJSON</td> <td>Document (string stream) (no encoding check) [U], insitu (copy untimed), insitu (copy untimed) (no encoding check) [U]</td> <td style="text-align: right;">1,560 (U 1,079)</td> <td style="text-align: right;">2,127 (U 1,817)</td> <td style="text-align: right;">11,547</td> <td style="text-align: right;">176,066 (U 122,354)</td> <td style="text-align: right;">7.1 (U 3.7)</td> </tr> <tr> <td>nlohmann/json <code>json</code></td> <td>structs (from_json)</td> <td style="text-align: right;">3,325</td> <td style="text-align: right;">5,126</td> <td style="text-align: right;">11,908</td> <td style="text-align: right;">423,362</td> <td style="text-align: right;">17.0</td> </tr> </tbody> </table> <p><strong>edit</strong></p> <table> <thead> <tr> <th>library</th> <th>variant</th> <th style="text-align: right;"><code>twitter.json</code></th> <th style="text-align: right;"><code>citm_catalog.json</code></th> <th style="text-align: right;"><code>canada.json</code></th> <th style="text-align: right;"><code>jeopardy.json</code></th> <th style="text-align: right;">one status (2.5 KB)</th> </tr> </thead> <tbody> <tr> <td><strong>nlohmann/json <code>json_document</code></strong></td> <td>editable, editable (source numbers) [N]</td> <td style="text-align: right;">532</td> <td style="text-align: right;">1,116</td> <td style="text-align: right;">5,714 (N 2,702)</td> <td style="text-align: right;">192,363</td> <td style="text-align: right;">3.1</td> </tr> <tr> <td>sonic-cpp</td> <td>Document [U]</td> <td style="text-align: right;">– (U 637)</td> <td style="text-align: right;">– (U 1,559)</td> <td style="text-align: right;">– (U 8,936)</td> <td style="text-align: right;">– (U 186,232)</td> <td style="text-align: right;">– (U 3.3)</td> </tr> <tr> <td>yyjson</td> <td>insitu (copy untimed) + mut copy</td> <td style="text-align: right;">761</td> <td style="text-align: right;">1,590</td> <td style="text-align: right;">9,860</td> <td style="text-align: right;">271,227</td> <td style="text-align: right;">3.7</td> </tr> <tr> <td>sonic-rs (Rust)</td> <td>Value</td> <td style="text-align: right;">1,197</td> <td style="text-align: right;">2,389</td> <td style="text-align: right;">7,744</td> <td style="text-align: right;">390,952</td> <td style="text-align: right;">6.9</td> </tr> <tr> <td>Boost.<abbr title="JavaScript Object Notation">JSON</abbr></td> <td>parse</td> <td style="text-align: right;">1,963</td> <td style="text-align: right;">2,936</td> <td style="text-align: right;">13,414</td> <td style="text-align: right;">356,244</td> <td style="text-align: right;">9.1</td> </tr> <tr> <td>simd-json (Rust)</td> <td>borrowed (copy), owned (copy)</td> <td style="text-align: right;">1,862</td> <td style="text-align: right;">4,194</td> <td style="text-align: right;">14,896</td> <td style="text-align: right;">391,369</td> <td style="text-align: right;">9.0</td> </tr> <tr> <td>RapidJSON</td> <td>Document (string stream) (no encoding check) [U], insitu (copy untimed), insitu (copy untimed) (no encoding check) [U], insitu (copy)</td> <td style="text-align: right;">2,333 (U 1,838)</td> <td style="text-align: right;">3,133 (U 2,836)</td> <td style="text-align: right;">20,518</td> <td style="text-align: right;">315,892 (U 271,888)</td> <td style="text-align: right;">11.0 (U 7.7)</td> </tr> <tr> <td>nlohmann/json <code>json</code></td> <td>ordered_json</td> <td style="text-align: right;">2,912</td> <td style="text-align: right;">4,999</td> <td style="text-align: right;">15,603</td> <td style="text-align: right;">604,744</td> <td style="text-align: right;">13.5</td> </tr> <tr> <td>Glaze</td> <td>generic (strict), generic [P]</td> <td style="text-align: right;">3,525</td> <td style="text-align: right;">6,551</td> <td style="text-align: right;">23,644</td> <td style="text-align: right;">661,941 (P 632,543)</td> <td style="text-align: right;">15.6</td> </tr> <tr> <td>serde_json (Rust)</td> <td>Value</td> <td style="text-align: right;">4,042</td> <td style="text-align: right;">6,586</td> <td style="text-align: right;">16,631</td> <td style="text-align: right;">632,766</td> <td style="text-align: right;">17.6</td> </tr> </tbody> </table> <p><strong>minify</strong></p> <table> <thead> <tr> <th>library</th> <th>variant</th> <th style="text-align: right;"><code>twitter.json</code></th> <th style="text-align: right;"><code>citm_catalog.json</code></th> <th style="text-align: right;"><code>canada.json</code></th> <th style="text-align: right;"><code>jeopardy.json</code></th> <th style="text-align: right;">one status (2.5 KB)</th> </tr> </thead> <tbody> <tr> <td><strong>nlohmann/json <code>json_document</code></strong></td> <td>parse + dump, parse + dump (source numbers) [N], parse_copy + dump</td> <td style="text-align: right;">483</td> <td style="text-align: right;">1,014</td> <td style="text-align: right;">5,459 (N 2,620)</td> <td style="text-align: right;">146,320</td> <td style="text-align: right;">2.4</td> </tr> <tr> <td>yyjson</td> <td>insitu (copy untimed) + write, read (raw numbers) + write [N], read + write</td> <td style="text-align: right;">592</td> <td style="text-align: right;">1,205</td> <td style="text-align: right;">9,008 (N 3,106)</td> <td style="text-align: right;">158,577</td> <td style="text-align: right;">2.9</td> </tr> <tr> <td>sonic-cpp</td> <td>Document + Serialize [U]</td> <td style="text-align: right;">– (U 695)</td> <td style="text-align: right;">– (U 1,541)</td> <td style="text-align: right;">– (U 8,838)</td> <td style="text-align: right;">– (U 168,901)</td> <td style="text-align: right;">– (U 3.3)</td> </tr> <tr> <td>simdjson</td> <td><abbr title="Document Object Model">DOM</abbr> + to_string, minify [P]</td> <td style="text-align: right;">742 (P 123)</td> <td style="text-align: right;">1,393 (P 337)</td> <td style="text-align: right;">8,808 (P 433)</td> <td style="text-align: right;">266,718 (P 47,040)</td> <td style="text-align: right;">3.8 (P 0.6)</td> </tr> <tr> <td>sonic-rs (Rust)</td> <td>Value</td> <td style="text-align: right;">1,000</td> <td style="text-align: right;">2,097</td> <td style="text-align: right;">7,795</td> <td style="text-align: right;">215,280</td> <td style="text-align: right;">5.4</td> </tr> <tr> <td>Boost.<abbr title="JavaScript Object Notation">JSON</abbr></td> <td>parse + serialize</td> <td style="text-align: right;">2,086</td> <td style="text-align: right;">2,919</td> <td style="text-align: right;">13,974</td> <td style="text-align: right;">334,468</td> <td style="text-align: right;">9.2</td> </tr> <tr> <td>simd-json (Rust)</td> <td>borrowed (copy)</td> <td style="text-align: right;">1,889</td> <td style="text-align: right;">4,196</td> <td style="text-align: right;">15,716</td> <td style="text-align: right;">414,377</td> <td style="text-align: right;">9.2</td> </tr> <tr> <td>RapidJSON</td> <td>Document + Writer, <abbr title="Simple API for XML">SAX</abbr> to Writer, <abbr title="Simple API for XML">SAX</abbr> to Writer (no encoding check) [U], <abbr title="Simple API for XML">SAX</abbr> to Writer (raw numbers) (no encoding check) [U N], <abbr title="Simple API for XML">SAX</abbr> to Writer (string stream), <abbr title="Simple API for XML">SAX</abbr> to Writer (string stream) (no encoding check) [U]</td> <td style="text-align: right;">3,015 (U 1,978)</td> <td style="text-align: right;">3,012 (U 2,493)</td> <td style="text-align: right;">21,177 (U N 15,512)</td> <td style="text-align: right;">355,727 (U 249,235)</td> <td style="text-align: right;">13.9 (U 7.5)</td> </tr> <tr> <td>Glaze</td> <td>generic (strict), minify_json [P]</td> <td style="text-align: right;">3,780 (P 422)</td> <td style="text-align: right;">6,416 (P 1,144)</td> <td style="text-align: right;">23,765 (P 2,350)</td> <td style="text-align: right;">458,311 (P 96,405)</td> <td style="text-align: right;">14.7 (P 1.9)</td> </tr> <tr> <td>serde_json (Rust)</td> <td>Value</td> <td style="text-align: right;">4,012</td> <td style="text-align: right;">6,583</td> <td style="text-align: right;">17,306</td> <td style="text-align: right;">509,702</td> <td style="text-align: right;">16.5</td> </tr> <tr> <td>nlohmann/json <code>json</code></td> <td>parse + dump</td> <td style="text-align: right;">4,143</td> <td style="text-align: right;">5,702</td> <td style="text-align: right;">16,463</td> <td style="text-align: right;">528,092</td> <td style="text-align: right;">19.5</td> </tr> </tbody> </table> <p><strong>write</strong></p> <table> <thead> <tr> <th>library</th> <th>variant</th> <th style="text-align: right;"><code>twitter.json</code></th> <th style="text-align: right;"><code>citm_catalog.json</code></th> <th style="text-align: right;"><code>canada.json</code></th> <th style="text-align: right;"><code>jeopardy.json</code></th> <th style="text-align: right;">one status (2.5 KB)</th> </tr> </thead> <tbody> <tr> <td><strong>nlohmann/json <code>json_document</code></strong></td> <td>dump, dump (source numbers) [N]</td> <td style="text-align: right;">150</td> <td style="text-align: right;">260</td> <td style="text-align: right;">3,861 (N 998)</td> <td style="text-align: right;">63,958</td> <td style="text-align: right;">0.8</td> </tr> <tr> <td>yyjson</td> <td>write</td> <td style="text-align: right;">204</td> <td style="text-align: right;">327</td> <td style="text-align: right;">3,748</td> <td style="text-align: right;">65,989</td> <td style="text-align: right;">1.2</td> </tr> <tr> <td>sonic-cpp</td> <td>Serialize</td> <td style="text-align: right;">256</td> <td style="text-align: right;">541</td> <td style="text-align: right;">5,120</td> <td style="text-align: right;">69,546</td> <td style="text-align: right;">1.6</td> </tr> <tr> <td>Glaze</td> <td>generic, generic (strict)</td> <td style="text-align: right;">360</td> <td style="text-align: right;">660</td> <td style="text-align: right;">3,714</td> <td style="text-align: right;">124,598</td> <td style="text-align: right;">1.7</td> </tr> <tr> <td>nlohmann/json <code>json</code></td> <td>dump</td> <td style="text-align: right;">471</td> <td style="text-align: right;">644</td> <td style="text-align: right;">4,344</td> <td style="text-align: right;">114,096</td> <td style="text-align: right;">1.9</td> </tr> <tr> <td>simdjson</td> <td>to_string</td> <td style="text-align: right;">359</td> <td style="text-align: right;">637</td> <td style="text-align: right;">4,999</td> <td style="text-align: right;">154,364</td> <td style="text-align: right;">1.9</td> </tr> <tr> <td>sonic-rs (Rust)</td> <td>Value</td> <td style="text-align: right;">434</td> <td style="text-align: right;">927</td> <td style="text-align: right;">3,987</td> <td style="text-align: right;">109,176</td> <td style="text-align: right;">2.8</td> </tr> <tr> <td>simd-json (Rust)</td> <td>borrowed</td> <td style="text-align: right;">582</td> <td style="text-align: right;">800</td> <td style="text-align: right;">5,147</td> <td style="text-align: right;">122,623</td> <td style="text-align: right;">2.8</td> </tr> <tr> <td>Boost.<abbr title="JavaScript Object Notation">JSON</abbr></td> <td>serialize</td> <td style="text-align: right;">480</td> <td style="text-align: right;">1,016</td> <td style="text-align: right;">6,154</td> <td style="text-align: right;">139,022</td> <td style="text-align: right;">2.5</td> </tr> <tr> <td>serde_json (Rust)</td> <td>Value</td> <td style="text-align: right;">550</td> <td style="text-align: right;">887</td> <td style="text-align: right;">4,005</td> <td style="text-align: right;">134,163</td> <td style="text-align: right;">3.3</td> </tr> <tr> <td>RapidJSON</td> <td>Writer</td> <td style="text-align: right;">717</td> <td style="text-align: right;">1,033</td> <td style="text-align: right;">9,017</td> <td style="text-align: right;">134,260</td> <td style="text-align: right;">4.0</td> </tr> </tbody> </table> </details> <details class=info> <summary>Times in µs on x86-64 with Clang 23</summary> <p><strong>validate</strong></p> <table> <thead> <tr> <th>library</th> <th>variant</th> <th style="text-align: right;"><code>twitter.json</code></th> <th style="text-align: right;"><code>citm_catalog.json</code></th> <th style="text-align: right;"><code>canada.json</code></th> <th style="text-align: right;"><code>jeopardy.json</code></th> <th style="text-align: right;">one status (2.5 KB)</th> </tr> </thead> <tbody> <tr> <td><strong>nlohmann/json <code>json_document</code></strong></td> <td>accept</td> <td style="text-align: right;">255</td> <td style="text-align: right;">512</td> <td style="text-align: right;">1,055</td> <td style="text-align: right;">34,729</td> <td style="text-align: right;">1.1</td> </tr> <tr> <td>yyjson</td> <td>insitu (copy untimed), read (raw numbers)</td> <td style="text-align: right;">334</td> <td style="text-align: right;">811</td> <td style="text-align: right;">2,580</td> <td style="text-align: right;">83,153</td> <td style="text-align: right;">1.5</td> </tr> <tr> <td>sonic-rs (Rust)</td> <td>IgnoredAny</td> <td style="text-align: right;">501</td> <td style="text-align: right;">970</td> <td style="text-align: right;">2,249</td> <td style="text-align: right;">54,369</td> <td style="text-align: right;">1.8</td> </tr> <tr> <td>Boost.<abbr title="JavaScript Object Notation">JSON</abbr></td> <td><abbr title="Simple API for XML">SAX</abbr>, <abbr title="Simple API for XML">SAX</abbr> (numbers: none)</td> <td style="text-align: right;">571</td> <td style="text-align: right;">910</td> <td style="text-align: right;">1,684</td> <td style="text-align: right;">55,498</td> <td style="text-align: right;">2.3</td> </tr> <tr> <td>simdjson</td> <td><abbr title="Document Object Model">DOM</abbr></td> <td style="text-align: right;">306</td> <td style="text-align: right;">732</td> <td style="text-align: right;">3,206</td> <td style="text-align: right;">113,452</td> <td style="text-align: right;">1.7</td> </tr> <tr> <td>sonic-cpp</td> <td>Document [U]</td> <td style="text-align: right;">– (U 448)</td> <td style="text-align: right;">– (U 1,032)</td> <td style="text-align: right;">– (U 3,143)</td> <td style="text-align: right;">– (U 94,884)</td> <td style="text-align: right;">– (U 1.8)</td> </tr> <tr> <td>Glaze</td> <td>validate_json</td> <td style="text-align: right;">588</td> <td style="text-align: right;">1,431</td> <td style="text-align: right;">1,867</td> <td style="text-align: right;">75,571</td> <td style="text-align: right;">2.4</td> </tr> <tr> <td>serde_json (Rust)</td> <td>IgnoredAny [U], from_utf8 + IgnoredAny</td> <td style="text-align: right;">624 (U 484)</td> <td style="text-align: right;">1,440 (U 1,370)</td> <td style="text-align: right;">2,406 (U 2,314)</td> <td style="text-align: right;">64,720 (U 58,247)</td> <td style="text-align: right;">2.4 (U 1.9)</td> </tr> <tr> <td>nlohmann/json <code>json</code></td> <td>accept</td> <td style="text-align: right;">658</td> <td style="text-align: right;">1,390</td> <td style="text-align: right;">4,265</td> <td style="text-align: right;">71,982</td> <td style="text-align: right;">3.5</td> </tr> <tr> <td>simd-json (Rust)</td> <td>tape (copy)</td> <td style="text-align: right;">567</td> <td style="text-align: right;">1,430</td> <td style="text-align: right;">4,359</td> <td style="text-align: right;">207,551</td> <td style="text-align: right;">2.9</td> </tr> <tr> <td>RapidJSON</td> <td><abbr title="Simple API for XML">SAX</abbr> (default precision), <abbr title="Simple API for XML">SAX</abbr> (default precision) (no encoding check) [U], <abbr title="Simple API for XML">SAX</abbr> (string stream, default precision), <abbr title="Simple API for XML">SAX</abbr> (string stream, default precision) (no encoding check) [U], insitu (copy untimed), insitu (copy untimed) (no encoding check) [U]</td> <td style="text-align: right;">1,756 (U 1,132)</td> <td style="text-align: right;">1,971 (U 1,572)</td> <td style="text-align: right;">4,118</td> <td style="text-align: right;">198,915 (U 131,204)</td> <td style="text-align: right;">8.2 (U 4.1)</td> </tr> </tbody> </table> <p><strong>sum</strong></p> <table> <thead> <tr> <th>library</th> <th>variant</th> <th style="text-align: right;"><code>twitter.json</code></th> <th style="text-align: right;"><code>citm_catalog.json</code></th> <th style="text-align: right;"><code>canada.json</code></th> <th style="text-align: right;"><code>jeopardy.json</code></th> <th style="text-align: right;">one status (2.5 KB)</th> </tr> </thead> <tbody> <tr> <td><strong>nlohmann/json <code>json_document</code></strong></td> <td>parse</td> <td style="text-align: right;">374</td> <td style="text-align: right;">923</td> <td style="text-align: right;">3,846</td> <td style="text-align: right;">85,286</td> <td style="text-align: right;">1.8</td> </tr> <tr> <td>yyjson</td> <td>insitu (copy untimed)</td> <td style="text-align: right;">399</td> <td style="text-align: right;">946</td> <td style="text-align: right;">3,445</td> <td style="text-align: right;">88,447</td> <td style="text-align: right;">1.9</td> </tr> <tr> <td>simdjson</td> <td><abbr title="Document Object Model">DOM</abbr>, On-Demand</td> <td style="text-align: right;">394</td> <td style="text-align: right;">977</td> <td style="text-align: right;">4,117</td> <td style="text-align: right;">114,602</td> <td style="text-align: right;">2.2</td> </tr> <tr> <td>sonic-rs (Rust)</td> <td>visitor</td> <td style="text-align: right;">501</td> <td style="text-align: right;">1,123</td> <td style="text-align: right;">4,397</td> <td style="text-align: right;">59,583</td> <td style="text-align: right;">2.5</td> </tr> <tr> <td>sonic-cpp</td> <td>Document [U]</td> <td style="text-align: right;">– (U 502)</td> <td style="text-align: right;">– (U 1,175)</td> <td style="text-align: right;">– (U 3,754)</td> <td style="text-align: right;">– (U 104,583)</td> <td style="text-align: right;">– (U 2.1)</td> </tr> <tr> <td>Boost.<abbr title="JavaScript Object Notation">JSON</abbr></td> <td><abbr title="Simple API for XML">SAX</abbr></td> <td style="text-align: right;">580</td> <td style="text-align: right;">928</td> <td style="text-align: right;">5,809</td> <td style="text-align: right;">56,774</td> <td style="text-align: right;">2.4</td> </tr> <tr> <td>nlohmann/json <code>json</code></td> <td>sax</td> <td style="text-align: right;">728</td> <td style="text-align: right;">1,393</td> <td style="text-align: right;">5,428</td> <td style="text-align: right;">89,481</td> <td style="text-align: right;">3.9</td> </tr> <tr> <td>simd-json (Rust)</td> <td>visitor (copy)</td> <td style="text-align: right;">681</td> <td style="text-align: right;">1,650</td> <td style="text-align: right;">5,083</td> <td style="text-align: right;">210,185</td> <td style="text-align: right;">3.5</td> </tr> <tr> <td>serde_json (Rust)</td> <td>visitor</td> <td style="text-align: right;">1,311</td> <td style="text-align: right;">2,288</td> <td style="text-align: right;">7,127</td> <td style="text-align: right;">129,497</td> <td style="text-align: right;">4.6</td> </tr> <tr> <td>RapidJSON</td> <td><abbr title="Simple API for XML">SAX</abbr>, <abbr title="Simple API for XML">SAX</abbr> (no encoding check) [U], <abbr title="Simple API for XML">SAX</abbr> (string stream), <abbr title="Simple API for XML">SAX</abbr> (string stream) (no encoding check) [U], insitu (copy untimed), insitu (copy untimed) (no encoding check) [U]</td> <td style="text-align: right;">1,816 (U 1,187)</td> <td style="text-align: right;">2,224 (U 1,765)</td> <td style="text-align: right;">10,719</td> <td style="text-align: right;">206,811 (U 135,945)</td> <td style="text-align: right;">8.5 (U 4.3)</td> </tr> <tr> <td>Glaze</td> <td>generic (double, strict), lazy_json [P]</td> <td style="text-align: right;">2,427</td> <td style="text-align: right;">3,972</td> <td style="text-align: right;">12,165</td> <td style="text-align: right;">253,385 (P 196,582)</td> <td style="text-align: right;">9.2 (P 5.6)</td> </tr> </tbody> </table> <p><strong>select</strong></p> <table> <thead> <tr> <th>library</th> <th>variant</th> <th style="text-align: right;"><code>twitter.json</code></th> <th style="text-align: right;"><code>citm_catalog.json</code></th> <th style="text-align: right;"><code>canada.json</code></th> <th style="text-align: right;"><code>jeopardy.json</code></th> <th style="text-align: right;">one status (2.5 KB)</th> </tr> </thead> <tbody> <tr> <td><strong>nlohmann/json <code>json_document</code></strong></td> <td>parse, structs (from_json)</td> <td style="text-align: right;">320</td> <td style="text-align: right;">759</td> <td style="text-align: right;">1,390</td> <td style="text-align: right;">88,083</td> <td style="text-align: right;">1.6</td> </tr> <tr> <td>yyjson</td> <td>insitu (copy untimed), read (raw numbers)</td> <td style="text-align: right;">351</td> <td style="text-align: right;">788</td> <td style="text-align: right;">2,632</td> <td style="text-align: right;">92,551</td> <td style="text-align: right;">1.6</td> </tr> <tr> <td>simdjson</td> <td><abbr title="Document Object Model">DOM</abbr>, On-Demand (key selectors) [P], On-Demand [P], On-Demand structs [P]</td> <td style="text-align: right;">316 (P 181)</td> <td style="text-align: right;">731 (P 495)</td> <td style="text-align: right;">3,262 (P 702)</td> <td style="text-align: right;">120,808 (P 48,823)</td> <td style="text-align: right;">1.9 (P 1.1)</td> </tr> <tr> <td>sonic-rs (Rust)</td> <td>structs</td> <td style="text-align: right;">504</td> <td style="text-align: right;">1,033</td> <td style="text-align: right;">2,328</td> <td style="text-align: right;">90,486</td> <td style="text-align: right;">2.0</td> </tr> <tr> <td>Glaze</td> <td>structs (validate_skipped), structs [P]</td> <td style="text-align: right;">544 (P 345)</td> <td style="text-align: right;">1,368 (P 419)</td> <td style="text-align: right;">1,924 (P 444)</td> <td style="text-align: right;">85,745 (P 66,442)</td> <td style="text-align: right;">2.2 (P 1.6)</td> </tr> <tr> <td>sonic-cpp</td> <td>Document [U]</td> <td style="text-align: right;">– (U 460)</td> <td style="text-align: right;">– (U 1,011)</td> <td style="text-align: right;">– (U 3,204)</td> <td style="text-align: right;">– (U 108,245)</td> <td style="text-align: right;">– (U 1.9)</td> </tr> <tr> <td>serde_json (Rust)</td> <td>from_utf8 + structs, structs [U]</td> <td style="text-align: right;">701</td> <td style="text-align: right;">1,532</td> <td style="text-align: right;">2,529 (U 2,402)</td> <td style="text-align: right;">107,316</td> <td style="text-align: right;">3.0</td> </tr> <tr> <td>Boost.<abbr title="JavaScript Object Notation">JSON</abbr></td> <td>parse, parse_into structs</td> <td style="text-align: right;">776</td> <td style="text-align: right;">1,389</td> <td style="text-align: right;">7,121</td> <td style="text-align: right;">97,681</td> <td style="text-align: right;">3.2</td> </tr> <tr> <td>simd-json (Rust)</td> <td>structs (copy)</td> <td style="text-align: right;">679</td> <td style="text-align: right;">1,731</td> <td style="text-align: right;">5,144</td> <td style="text-align: right;">239,164</td> <td style="text-align: right;">3.5</td> </tr> <tr> <td>RapidJSON</td> <td>insitu (copy untimed), insitu (copy untimed) (no encoding check) [U]</td> <td style="text-align: right;">1,762 (U 1,144)</td> <td style="text-align: right;">2,198 (U 1,817)</td> <td style="text-align: right;">11,464</td> <td style="text-align: right;">209,290 (U 142,852)</td> <td style="text-align: right;">8.2 (U 4.1)</td> </tr> <tr> <td>nlohmann/json <code>json</code></td> <td>parse, structs (from_json)</td> <td style="text-align: right;">3,602</td> <td style="text-align: right;">5,124</td> <td style="text-align: right;">11,831</td> <td style="text-align: right;">444,210</td> <td style="text-align: right;">20.2</td> </tr> </tbody> </table> <p><strong>edit</strong></p> <table> <thead> <tr> <th>library</th> <th>variant</th> <th style="text-align: right;"><code>twitter.json</code></th> <th style="text-align: right;"><code>citm_catalog.json</code></th> <th style="text-align: right;"><code>canada.json</code></th> <th style="text-align: right;"><code>jeopardy.json</code></th> <th style="text-align: right;">one status (2.5 KB)</th> </tr> </thead> <tbody> <tr> <td><strong>nlohmann/json <code>json_document</code></strong></td> <td>editable, editable (source numbers) [N]</td> <td style="text-align: right;">526</td> <td style="text-align: right;">1,127</td> <td style="text-align: right;">5,674 (N 2,443)</td> <td style="text-align: right;">196,370</td> <td style="text-align: right;">2.9</td> </tr> <tr> <td>sonic-cpp</td> <td>Document [U]</td> <td style="text-align: right;">– (U 711)</td> <td style="text-align: right;">– (U 1,472)</td> <td style="text-align: right;">– (U 7,996)</td> <td style="text-align: right;">– (U 183,852)</td> <td style="text-align: right;">– (U 3.2)</td> </tr> <tr> <td>yyjson</td> <td>insitu (copy untimed) + mut copy, insitu (copy) + mut copy</td> <td style="text-align: right;">918</td> <td style="text-align: right;">1,548</td> <td style="text-align: right;">7,155</td> <td style="text-align: right;">270,654</td> <td style="text-align: right;">3.9</td> </tr> <tr> <td>sonic-rs (Rust)</td> <td>Value</td> <td style="text-align: right;">1,197</td> <td style="text-align: right;">2,389</td> <td style="text-align: right;">7,744</td> <td style="text-align: right;">390,952</td> <td style="text-align: right;">6.9</td> </tr> <tr> <td>Boost.<abbr title="JavaScript Object Notation">JSON</abbr></td> <td>parse</td> <td style="text-align: right;">1,855</td> <td style="text-align: right;">2,596</td> <td style="text-align: right;">12,765</td> <td style="text-align: right;">350,286</td> <td style="text-align: right;">8.3</td> </tr> <tr> <td>simd-json (Rust)</td> <td>borrowed (copy), owned (copy)</td> <td style="text-align: right;">1,862</td> <td style="text-align: right;">4,194</td> <td style="text-align: right;">14,896</td> <td style="text-align: right;">391,369</td> <td style="text-align: right;">9.0</td> </tr> <tr> <td>RapidJSON</td> <td>insitu (copy untimed), insitu (copy untimed) (no encoding check) [U], insitu (copy)</td> <td style="text-align: right;">2,635 (U 1,952)</td> <td style="text-align: right;">3,103 (U 2,728)</td> <td style="text-align: right;">21,139</td> <td style="text-align: right;">333,913 (U 267,081)</td> <td style="text-align: right;">11.8 (U 7.7)</td> </tr> <tr> <td>nlohmann/json <code>json</code></td> <td>ordered_json, parse</td> <td style="text-align: right;">3,069</td> <td style="text-align: right;">4,905</td> <td style="text-align: right;">16,702</td> <td style="text-align: right;">666,261</td> <td style="text-align: right;">13.1</td> </tr> <tr> <td>serde_json (Rust)</td> <td>Value</td> <td style="text-align: right;">4,042</td> <td style="text-align: right;">6,586</td> <td style="text-align: right;">16,631</td> <td style="text-align: right;">632,766</td> <td style="text-align: right;">17.6</td> </tr> <tr> <td>Glaze</td> <td>generic (strict), generic [P]</td> <td style="text-align: right;">4,341</td> <td style="text-align: right;">7,322</td> <td style="text-align: right;">26,786</td> <td style="text-align: right;">725,881</td> <td style="text-align: right;">18.3 (P 17.7)</td> </tr> </tbody> </table> <p><strong>minify</strong></p> <table> <thead> <tr> <th>library</th> <th>variant</th> <th style="text-align: right;"><code>twitter.json</code></th> <th style="text-align: right;"><code>citm_catalog.json</code></th> <th style="text-align: right;"><code>canada.json</code></th> <th style="text-align: right;"><code>jeopardy.json</code></th> <th style="text-align: right;">one status (2.5 KB)</th> </tr> </thead> <tbody> <tr> <td><strong>nlohmann/json <code>json_document</code></strong></td> <td>parse + dump, parse + dump (source numbers) [N]</td> <td style="text-align: right;">518</td> <td style="text-align: right;">1,040</td> <td style="text-align: right;">5,043 (N 2,456)</td> <td style="text-align: right;">146,125</td> <td style="text-align: right;">2.4</td> </tr> <tr> <td>yyjson</td> <td>insitu (copy untimed) + write, read (raw numbers) + write [N]</td> <td style="text-align: right;">620</td> <td style="text-align: right;">1,189</td> <td style="text-align: right;">6,283 (N 3,472)</td> <td style="text-align: right;">154,016</td> <td style="text-align: right;">3.0</td> </tr> <tr> <td>sonic-cpp</td> <td>Document + Serialize [U]</td> <td style="text-align: right;">– (U 710)</td> <td style="text-align: right;">– (U 1,485)</td> <td style="text-align: right;">– (U 8,122)</td> <td style="text-align: right;">– (U 166,935)</td> <td style="text-align: right;">– (U 3.1)</td> </tr> <tr> <td>simdjson</td> <td><abbr title="Document Object Model">DOM</abbr> + to_string, minify [P]</td> <td style="text-align: right;">783 (P 105)</td> <td style="text-align: right;">1,395 (P 269)</td> <td style="text-align: right;">8,303 (P 337)</td> <td style="text-align: right;">275,007 (P 45,087)</td> <td style="text-align: right;">4.0 (P 0.5)</td> </tr> <tr> <td>sonic-rs (Rust)</td> <td>Value</td> <td style="text-align: right;">1,000</td> <td style="text-align: right;">2,097</td> <td style="text-align: right;">7,795</td> <td style="text-align: right;">215,280</td> <td style="text-align: right;">5.4</td> </tr> <tr> <td>Boost.<abbr title="JavaScript Object Notation">JSON</abbr></td> <td>parse + serialize</td> <td style="text-align: right;">1,924</td> <td style="text-align: right;">2,569</td> <td style="text-align: right;">12,622</td> <td style="text-align: right;">329,090</td> <td style="text-align: right;">8.4</td> </tr> <tr> <td>simd-json (Rust)</td> <td>borrowed (copy)</td> <td style="text-align: right;">1,889</td> <td style="text-align: right;">4,196</td> <td style="text-align: right;">15,716</td> <td style="text-align: right;">414,377</td> <td style="text-align: right;">9.2</td> </tr> <tr> <td>RapidJSON</td> <td>Document + Writer, <abbr title="Simple API for XML">SAX</abbr> to Writer, <abbr title="Simple API for XML">SAX</abbr> to Writer (no encoding check) [U], <abbr title="Simple API for XML">SAX</abbr> to Writer (raw numbers) (no encoding check) [U N], <abbr title="Simple API for XML">SAX</abbr> to Writer (raw numbers) [N], <abbr title="Simple API for XML">SAX</abbr> to Writer (string stream), <abbr title="Simple API for XML">SAX</abbr> to Writer (string stream) (no encoding check) [U]</td> <td style="text-align: right;">2,808 (U N 2,022)</td> <td style="text-align: right;">2,975 (U 2,480)</td> <td style="text-align: right;">22,589 (N 14,986)</td> <td style="text-align: right;">358,807 (U 261,527)</td> <td style="text-align: right;">12.7 (U 7.2)</td> </tr> <tr> <td>serde_json (Rust)</td> <td>Value</td> <td style="text-align: right;">4,012</td> <td style="text-align: right;">6,583</td> <td style="text-align: right;">17,306</td> <td style="text-align: right;">509,702</td> <td style="text-align: right;">16.5</td> </tr> <tr> <td>nlohmann/json <code>json</code></td> <td>parse + dump</td> <td style="text-align: right;">4,445</td> <td style="text-align: right;">5,713</td> <td style="text-align: right;">16,711</td> <td style="text-align: right;">543,033</td> <td style="text-align: right;">21.4</td> </tr> <tr> <td>Glaze</td> <td>generic (strict), minify_json [P]</td> <td style="text-align: right;">4,132 (P 444)</td> <td style="text-align: right;">7,465 (P 1,059)</td> <td style="text-align: right;">26,962 (P 2,222)</td> <td style="text-align: right;">528,811 (P 91,153)</td> <td style="text-align: right;">17.2 (P 1.9)</td> </tr> </tbody> </table> <p><strong>write</strong></p> <table> <thead> <tr> <th>library</th> <th>variant</th> <th style="text-align: right;"><code>twitter.json</code></th> <th style="text-align: right;"><code>citm_catalog.json</code></th> <th style="text-align: right;"><code>canada.json</code></th> <th style="text-align: right;"><code>jeopardy.json</code></th> <th style="text-align: right;">one status (2.5 KB)</th> </tr> </thead> <tbody> <tr> <td><strong>nlohmann/json <code>json_document</code></strong></td> <td>dump, dump (source numbers) [N]</td> <td style="text-align: right;">160 (N 154)</td> <td style="text-align: right;">311 (N 279)</td> <td style="text-align: right;">3,714 (N 989)</td> <td style="text-align: right;">67,038 (N 64,301)</td> <td style="text-align: right;">0.9</td> </tr> <tr> <td>yyjson</td> <td>write</td> <td style="text-align: right;">218</td> <td style="text-align: right;">386</td> <td style="text-align: right;">3,476</td> <td style="text-align: right;">71,247</td> <td style="text-align: right;">1.4</td> </tr> <tr> <td>sonic-cpp</td> <td>Serialize</td> <td style="text-align: right;">224</td> <td style="text-align: right;">475</td> <td style="text-align: right;">4,850</td> <td style="text-align: right;">65,131</td> <td style="text-align: right;">1.3</td> </tr> <tr> <td>nlohmann/json <code>json</code></td> <td>dump</td> <td style="text-align: right;">451</td> <td style="text-align: right;">628</td> <td style="text-align: right;">4,506</td> <td style="text-align: right;">116,529</td> <td style="text-align: right;">2.0</td> </tr> <tr> <td>Glaze</td> <td>generic</td> <td style="text-align: right;">399</td> <td style="text-align: right;">748</td> <td style="text-align: right;">4,220</td> <td style="text-align: right;">128,020</td> <td style="text-align: right;">2.0</td> </tr> <tr> <td>simdjson</td> <td>to_string</td> <td style="text-align: right;">389</td> <td style="text-align: right;">656</td> <td style="text-align: right;">4,896</td> <td style="text-align: right;">157,616</td> <td style="text-align: right;">2.1</td> </tr> <tr> <td>sonic-rs (Rust)</td> <td>Value</td> <td style="text-align: right;">434</td> <td style="text-align: right;">927</td> <td style="text-align: right;">3,987</td> <td style="text-align: right;">109,176</td> <td style="text-align: right;">2.8</td> </tr> <tr> <td>Boost.<abbr title="JavaScript Object Notation">JSON</abbr></td> <td>serialize</td> <td style="text-align: right;">478</td> <td style="text-align: right;">916</td> <td style="text-align: right;">5,615</td> <td style="text-align: right;">141,846</td> <td style="text-align: right;">2.5</td> </tr> <tr> <td>simd-json (Rust)</td> <td>borrowed</td> <td style="text-align: right;">582</td> <td style="text-align: right;">800</td> <td style="text-align: right;">5,147</td> <td style="text-align: right;">122,623</td> <td style="text-align: right;">2.8</td> </tr> <tr> <td>serde_json (Rust)</td> <td>Value</td> <td style="text-align: right;">550</td> <td style="text-align: right;">887</td> <td style="text-align: right;">4,005</td> <td style="text-align: right;">134,163</td> <td style="text-align: right;">3.3</td> </tr> <tr> <td>RapidJSON</td> <td>Writer</td> <td style="text-align: right;">627</td> <td style="text-align: right;">1,008</td> <td style="text-align: right;">9,596</td> <td style="text-align: right;">123,764</td> <td style="text-align: right;">3.7</td> </tr> </tbody> </table> </details> <h3 id=f-behavior-changes>F. Behavior changes<a class=headerlink href=#f-behavior-changes title="Permanent link">&para;</a></h3> <p>Visible changes that came with the speed:</p> <ul> <li><strong>Float output</strong> (<a href="https://github.com/nlohmann/json/pull/5634">#5634</a>). Żmij writes the shortest decimal that reads back as the same <code>double</code>, and the closest one if there are several. Of one million random <code>double</code> bit patterns, 1,425 (0.14%) are now written differently: 810 with fewer digits (<code>5.3165205877497296e+16</code> becomes <code>5.31652058774973e+16</code>), 615 with the same number of digits but the closer ones. They all read back as the same <code>double</code>, and none of one million short decimals changes. In <code>canada.json</code>, 69 of the 111,126 numbers come out differently.</li> <li><strong>Error positions</strong> (<a href="https://github.com/nlohmann/json/pull/5283">#5283</a>). The column reported after a number at the end of a line is now correct; the fast paths otherwise report the same byte, line, and column as the byte path, checked on 481,000 documents.</li> <li><strong><abbr title="Simple API for XML">SAX</abbr> float text</strong> (<a href="https://github.com/nlohmann/json/pull/5852">#5852</a>). The built-in handlers behind <code>parse()</code> and <code>accept()</code> get an empty string as the text of a float token. A user-written <abbr title="Simple API for XML">SAX</abbr> handler still gets the token's text.</li> <li><strong><code>FILE*</code> locking</strong> (<a href="https://github.com/nlohmann/json/pull/5828">#5828</a>). The lock is taken once and held for the whole parse instead of once per byte. The documentation mentions it, and an opt-out macro restores the old behavior.</li> </ul> <h3 id=g-how-we-measured>G. How we measured<a class=headerlink href=#g-how-we-measured title="Permanent link">&para;</a></h3> <p><strong>What is compared.</strong> "3.12.0" is the released single header and "3.13.0" the released one. Both are compiled from the <em>same</em> benchmark source, the Google Benchmark suite in <a href="https://github.com/nlohmann/json/tree/develop/tests/benchmarks"><code>tests/benchmarks</code></a>, with the <abbr title="Binary Object Notation 8">BON8</abbr> benchmarks removed because 3.12.0 has no <abbr title="Binary Object Notation 8">BON8</abbr>.</p> <table> <thead> <tr> <th></th> <th></th> </tr> </thead> <tbody> <tr> <td>machine</td> <td>Apple M1 Max laptop on AC power, macOS 27.0.1</td> </tr> <tr> <td>compiler</td> <td>Apple clang 21, libc++</td> </tr> <tr> <td>flags</td> <td><code>-O3 -flto -DNDEBUG</code>, the compiler's default standard, C++14</td> </tr> <tr> <td>suite</td> <td>3 rounds × 4 repetitions per version, random interleaving, each round of a version started only when the load average was below 4 and repeated when it rose above 5 while running; of 3.12.0 and 3.13.0, the round that was 4.2% and 1.8% slower overall than the other two was dropped; the median of the remaining 8</td> </tr> <tr> <td>noise</td> <td>the coefficient of variation was 3% or less for 172 of the 182 rows with 3.12.0 and 174 with 3.13.0; the largest was 7.3%, not counting one 3.12.0 run of a 1.5 µs benchmark that a disturbance made 1.4× as slow</td> </tr> <tr> <td>inputs</td> <td>the files of <a href=#a-test-files>Appendix A</a>, and number-heavy files</td> </tr> <tr> <td>Intel check</td> <td>the suite again on a MacBook Pro (15-inch, 2016) with an Intel Core i7-6920HQ (Skylake, 4 cores), macOS 12.0.1, Apple clang 13, the same flags with C++11; started below a load of 3, repeated above 4; the first round of each version dropped (3.12.0's was 4.7% slower than the others); the coefficient of variation was 3% or less for 120 rows with 3.12.0 and 161 of 234 with 3.13.0, so single rows are less reliable than on the M1 Max; geometric mean 3.07×, and two rows below 1×: copying <code>citm_catalog.json</code> without destroying the copy (0.93×) and <code>==</code> of it and a copy (0.95×), both in each round</td> </tr> </tbody> </table> <p class=nj-table-caption>Setup of the Google Benchmark comparison of 3.12.0 and 3.13.0.</p> <p><strong>The other measurements.</strong> The timeline is <a href="https://github.com/nlohmann/json/tree/develop/tests/benchmarks/history"><code>tests/benchmarks/history</code></a>: one program, compiled against <code>single_include</code> of 3.12.0, of each of the 351 commits on <code>develop</code> up to November 3 that changed <code>json.hpp</code> or <code>json_view.hpp</code> since, and of 3.13.0 (C++17, <code>-O3</code>, no <abbr title="Link-Time Optimization">LTO</abbr>), 4 rounds in random order, median of the rounds (the mean of the two middle ones). Two commits that don't compile on their own are left out. The commits up to October 27 were run on October 27, the later ones and 3.13.0 on November 3, together with twelve of the earlier commits as a check: per workload, their median moved by 1.5% or less. The algorithmic fixes come from small extra programs (C++17, <code>-O3</code>, median of 3 interleaved runs). The comparison with other libraries is described in <a href=#e-comparison-with-other-libraries>Appendix E</a>.</p> <p><strong>Compile times.</strong> The two programs of <a href=#the-price>The price</a>, each compiled as one translation unit with <code>-std=c++20</code> (modules need it) and <code>-O0</code> or <code>-O2</code>, with Apple clang 21 and Homebrew <abbr title="GNU Compiler Collection">GCC</abbr> 16.2 on the M1 Max. The time is the <abbr title="Central Processing Unit">CPU</abbr> time (user plus system) of the compiler process, the median of 5 rounds in which all 40 compilations ran in a random order. The slowest of the 5 runs was within 13% of the fastest for every program and every build of the precompiled header or the module. Every variant was also linked and run once, with the same output from all of them.</p> <table> <thead> <tr> <th>build</th> <th>program</th> <th style="text-align: right;">3.12.0</th> <th style="text-align: right;">3.13.0</th> <th style="text-align: right;">3.13.0, <abbr title="Precompiled Header">PCH</abbr></th> <th style="text-align: right;">3.13.0, module</th> </tr> </thead> <tbody> <tr> <td>Apple clang <code>-O0</code></td> <td><code>count_numbers</code></td> <td style="text-align: right;">955</td> <td style="text-align: right;">1,320</td> <td style="text-align: right;">689</td> <td style="text-align: right;">918</td> </tr> <tr> <td></td> <td><code>server_config</code></td> <td style="text-align: right;">1,113</td> <td style="text-align: right;">1,496</td> <td style="text-align: right;">863</td> <td style="text-align: right;">1,136</td> </tr> <tr> <td>Apple clang <code>-O2</code></td> <td><code>count_numbers</code></td> <td style="text-align: right;">1,393</td> <td style="text-align: right;">2,081</td> <td style="text-align: right;">1,458</td> <td style="text-align: right;">1,685</td> </tr> <tr> <td></td> <td><code>server_config</code></td> <td style="text-align: right;">1,754</td> <td style="text-align: right;">2,546</td> <td style="text-align: right;">1,925</td> <td style="text-align: right;">2,169</td> </tr> <tr> <td><abbr title="GNU Compiler Collection">GCC</abbr> 16 <code>-O0</code></td> <td><code>count_numbers</code></td> <td style="text-align: right;">1,569</td> <td style="text-align: right;">2,548</td> <td style="text-align: right;">1,725</td> <td style="text-align: right;">1,700</td> </tr> <tr> <td></td> <td><code>server_config</code></td> <td style="text-align: right;">2,025</td> <td style="text-align: right;">2,985</td> <td style="text-align: right;">2,302</td> <td style="text-align: right;">2,326</td> </tr> <tr> <td><abbr title="GNU Compiler Collection">GCC</abbr> 16 <code>-O2</code></td> <td><code>count_numbers</code></td> <td style="text-align: right;">2,336</td> <td style="text-align: right;">3,702</td> <td style="text-align: right;">2,987</td> <td style="text-align: right;">2,913</td> </tr> <tr> <td></td> <td><code>server_config</code></td> <td style="text-align: right;">3,122</td> <td style="text-align: right;">4,714</td> <td style="text-align: right;">4,006</td> <td style="text-align: right;">4,055</td> </tr> </tbody> </table> <p class=nj-table-caption>Compile time in milliseconds of the two programs in <a href=#the-price>The price</a> (<abbr title="Central Processing Unit">CPU</abbr> time of the compiler, median of 5 runs). Building the precompiled header took 973 and 987 ms with Apple clang (<code>-O0</code>, <code>-O2</code>) and 2,565 and 2,589 ms with <abbr title="GNU Compiler Collection">GCC</abbr>; building the module took 1,617 and 1,602 ms or 2,499 and 2,465 ms.</p> <details class=example> <summary>The programs and the build commands</summary> <div class=highlight><pre><span></span><code><span class=c1>// Reads a JSON file and adds up all of its numbers (the "sum" use case of the benchmark).</span>
<span class=cp>#include</span><span class=w> </span><span class=cpf>&lt;cstddef&gt;</span>
<span class=cp>#include</span><span class=w> </span><span class=cpf>&lt;fstream&gt;</span>
<span class=cp>#include</span><span class=w> </span><span class=cpf>&lt;iostream&gt;</span>
<span class=cp>#ifdef USE_MODULE</span>
<span class=k>import</span><span class=w> </span><span class=n>nlohmann</span><span class=p>.</span><span class=n>json</span><span class=p>;</span>
<span class=cp>#else</span>
<span class=cp>#include</span><span class=w> </span><span class=cpf>&lt;nlohmann/json.hpp&gt;</span>
<span class=cp>#endif</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>static</span><span class=w> </span><span class=kt>double</span><span class=w> </span><span class=nf>sum_numbers</span><span class=p>(</span><span class=k>const</span><span class=w> </span><span class=n>json</span><span class=o>&amp;</span><span class=w> </span><span class=n>j</span><span class=p>)</span>
<span class=p>{</span>
<span class=w> </span><span class=k>switch</span><span class=w> </span><span class=p>(</span><span class=n>j</span><span class=p>.</span><span class=n>type</span><span class=p>())</span>
<span class=w> </span><span class=p>{</span>
<span class=w> </span><span class=k>case</span><span class=w> </span><span class=no>json</span><span class=o>::</span><span class=no>value_t</span><span class=o>::</span><span class=no>array</span><span class=p>:</span>
<span class=w> </span><span class=k>case</span><span class=w> </span><span class=no>json</span><span class=o>::</span><span class=no>value_t</span><span class=o>::</span><span class=no>object</span><span class=p>:</span>
<span class=w> </span><span class=p>{</span>
<span class=w> </span><span class=kt>double</span><span class=w> </span><span class=n>sum</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=mi>0</span><span class=p>;</span>
<span class=w> </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=o>&amp;</span><span class=w> </span><span class=n>element</span><span class=w> </span><span class=o>:</span><span class=w> </span><span class=n>j</span><span class=p>)</span>
<span class=w> </span><span class=p>{</span>
<span class=w> </span><span class=n>sum</span><span class=w> </span><span class=o>+=</span><span class=w> </span><span class=n>sum_numbers</span><span class=p>(</span><span class=n>element</span><span class=p>);</span>
<span class=w> </span><span class=p>}</span>
<span class=w> </span><span class=k>return</span><span class=w> </span><span class=n>sum</span><span class=p>;</span>
<span class=w> </span><span class=p>}</span>
<span class=w> </span><span class=k>case</span><span class=w> </span><span class=no>json</span><span class=o>::</span><span class=no>value_t</span><span class=o>::</span><span class=no>number_integer</span><span class=p>:</span>
<span class=w> </span><span class=k>case</span><span class=w> </span><span class=no>json</span><span class=o>::</span><span class=no>value_t</span><span class=o>::</span><span class=no>number_unsigned</span><span class=p>:</span>
<span class=w> </span><span class=k>case</span><span class=w> </span><span class=no>json</span><span class=o>::</span><span class=no>value_t</span><span class=o>::</span><span class=no>number_float</span><span class=p>:</span>
<span class=w> </span><span class=k>return</span><span class=w> </span><span class=n>j</span><span class=p>.</span><span class=n>get</span><span class=o>&lt;</span><span class=kt>double</span><span class=o>&gt;</span><span class=p>();</span>
<span class=w> </span><span class=k>default</span><span class=o>:</span>
<span class=w> </span><span class=k>return</span><span class=w> </span><span class=mi>0</span><span class=p>;</span>
<span class=w> </span><span class=p>}</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=kt>int</span><span class=w> </span><span class=n>argc</span><span class=p>,</span><span class=w> </span><span class=kt>char</span><span class=o>*</span><span class=w> </span><span class=n>argv</span><span class=p>[])</span>
<span class=p>{</span>
<span class=w> </span><span class=k>if</span><span class=w> </span><span class=p>(</span><span class=n>argc</span><span class=w> </span><span class=o>!=</span><span class=w> </span><span class=mi>2</span><span class=p>)</span>
<span class=w> </span><span class=p>{</span>
<span class=w> </span><span class=k>return</span><span class=w> </span><span class=mi>1</span><span class=p>;</span>
<span class=w> </span><span class=p>}</span>
<span class=w> </span><span class=n>std</span><span class=o>::</span><span class=n>ifstream</span><span class=w> </span><span class=n>in</span><span class=p>(</span><span class=n>argv</span><span class=p>[</span><span class=mi>1</span><span class=p>]);</span>
<span class=w> </span><span class=k>const</span><span class=w> </span><span class=n>json</span><span class=w> </span><span class=n>j</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>json</span><span class=o>::</span><span class=n>parse</span><span class=p>(</span><span class=n>in</span><span class=p>);</span>
<span class=w> </span><span class=n>std</span><span class=o>::</span><span class=n>cout</span><span class=w> </span><span class=o>&lt;&lt;</span><span class=w> </span><span class=n>sum_numbers</span><span class=p>(</span><span class=n>j</span><span class=p>)</span><span class=w> </span><span class=o>&lt;&lt;</span><span class=w> </span><span class=sc>'\n'</span><span class=p>;</span>
<span class=p>}</span>
</code></pre></div> <p><p class=nj-code-caption markdown><code>count_numbers.cpp</code>.</p></p> <div class=highlight><pre><span></span><code><span class=c1>// Reads a configuration file into a struct, changes it, and writes it back indented.</span>
<span class=cp>#include</span><span class=w> </span><span class=cpf>&lt;fstream&gt;</span>
<span class=cp>#include</span><span class=w> </span><span class=cpf>&lt;iostream&gt;</span>
<span class=cp>#include</span><span class=w> </span><span class=cpf>&lt;string&gt;</span>
<span class=cp>#include</span><span class=w> </span><span class=cpf>&lt;vector&gt;</span>
<span class=cp>#ifdef USE_MODULE</span>
<span class=k>import</span><span class=w> </span><span class=n>nlohmann</span><span class=p>.</span><span class=n>json</span><span class=p>;</span>
<span class=cp>#else</span>
<span class=cp>#include</span><span class=w> </span><span class=cpf>&lt;nlohmann/json.hpp&gt;</span>
<span class=cp>#endif</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>struct</span><span class=w> </span><span class=nc>server_config</span>
<span class=p>{</span>
<span class=w> </span><span class=n>std</span><span class=o>::</span><span class=n>string</span><span class=w> </span><span class=n>host</span><span class=p>;</span>
<span class=w> </span><span class=kt>int</span><span class=w> </span><span class=n>port</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=mi>0</span><span class=p>;</span>
<span class=w> </span><span class=kt>double</span><span class=w> </span><span class=n>timeout</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=mi>0</span><span class=p>;</span>
<span class=w> </span><span class=n>std</span><span class=o>::</span><span class=n>vector</span><span class=o>&lt;</span><span class=n>std</span><span class=o>::</span><span class=n>string</span><span class=o>&gt;</span><span class=w> </span><span class=n>tags</span><span class=p>;</span>
<span class=p>};</span>
<span class=kt>void</span><span class=w> </span><span class=nf>to_json</span><span class=p>(</span><span class=n>json</span><span class=o>&amp;</span><span class=w> </span><span class=n>j</span><span class=p>,</span><span class=w> </span><span class=k>const</span><span class=w> </span><span class=n>server_config</span><span class=o>&amp;</span><span class=w> </span><span class=n>c</span><span class=p>)</span>
<span class=p>{</span>
<span class=w> </span><span class=n>j</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>json</span><span class=p>{{</span><span class=s>"host"</span><span class=p>,</span><span class=w> </span><span class=n>c</span><span class=p>.</span><span class=n>host</span><span class=p>},</span><span class=w> </span><span class=p>{</span><span class=s>"port"</span><span class=p>,</span><span class=w> </span><span class=n>c</span><span class=p>.</span><span class=n>port</span><span class=p>},</span><span class=w> </span><span class=p>{</span><span class=s>"timeout"</span><span class=p>,</span><span class=w> </span><span class=n>c</span><span class=p>.</span><span class=n>timeout</span><span class=p>},</span><span class=w> </span><span class=p>{</span><span class=s>"tags"</span><span class=p>,</span><span class=w> </span><span class=n>c</span><span class=p>.</span><span class=n>tags</span><span class=p>}};</span>
<span class=p>}</span>
<span class=kt>void</span><span class=w> </span><span class=nf>from_json</span><span class=p>(</span><span class=k>const</span><span class=w> </span><span class=n>json</span><span class=o>&amp;</span><span class=w> </span><span class=n>j</span><span class=p>,</span><span class=w> </span><span class=n>server_config</span><span class=o>&amp;</span><span class=w> </span><span class=n>c</span><span class=p>)</span>
<span class=p>{</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>"host"</span><span class=p>).</span><span class=n>get_to</span><span class=p>(</span><span class=n>c</span><span class=p>.</span><span class=n>host</span><span class=p>);</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>"port"</span><span class=p>).</span><span class=n>get_to</span><span class=p>(</span><span class=n>c</span><span class=p>.</span><span class=n>port</span><span class=p>);</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>"timeout"</span><span class=p>).</span><span class=n>get_to</span><span class=p>(</span><span class=n>c</span><span class=p>.</span><span class=n>timeout</span><span class=p>);</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>"tags"</span><span class=p>).</span><span class=n>get_to</span><span class=p>(</span><span class=n>c</span><span class=p>.</span><span class=n>tags</span><span class=p>);</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=kt>int</span><span class=w> </span><span class=n>argc</span><span class=p>,</span><span class=w> </span><span class=kt>char</span><span class=o>*</span><span class=w> </span><span class=n>argv</span><span class=p>[])</span>
<span class=p>{</span>
<span class=w> </span><span class=k>if</span><span class=w> </span><span class=p>(</span><span class=n>argc</span><span class=w> </span><span class=o>!=</span><span class=w> </span><span class=mi>3</span><span class=p>)</span>
<span class=w> </span><span class=p>{</span>
<span class=w> </span><span class=k>return</span><span class=w> </span><span class=mi>1</span><span class=p>;</span>
<span class=w> </span><span class=p>}</span>
<span class=w> </span><span class=n>std</span><span class=o>::</span><span class=n>ifstream</span><span class=w> </span><span class=n>in</span><span class=p>(</span><span class=n>argv</span><span class=p>[</span><span class=mi>1</span><span class=p>]);</span>
<span class=w> </span><span class=k>auto</span><span class=w> </span><span class=n>config</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>json</span><span class=o>::</span><span class=n>parse</span><span class=p>(</span><span class=n>in</span><span class=p>).</span><span class=n>get</span><span class=o>&lt;</span><span class=n>server_config</span><span class=o>&gt;</span><span class=p>();</span>
<span class=w> </span><span class=n>config</span><span class=p>.</span><span class=n>port</span><span class=w> </span><span class=o>+=</span><span class=w> </span><span class=mi>1</span><span class=p>;</span>
<span class=w> </span><span class=n>config</span><span class=p>.</span><span class=n>tags</span><span class=p>.</span><span class=n>push_back</span><span class=p>(</span><span class=s>"updated"</span><span class=p>);</span>
<span class=w> </span><span class=n>std</span><span class=o>::</span><span class=n>ofstream</span><span class=p>(</span><span class=n>argv</span><span class=p>[</span><span class=mi>2</span><span class=p>])</span><span class=w> </span><span class=o>&lt;&lt;</span><span class=w> </span><span class=n>json</span><span class=p>(</span><span class=n>config</span><span class=p>).</span><span class=n>dump</span><span class=p>(</span><span class=mi>2</span><span class=p>)</span><span class=w> </span><span class=o>&lt;&lt;</span><span class=w> </span><span class=sc>'\n'</span><span class=p>;</span>
<span class=p>}</span>
</code></pre></div> <p><p class=nj-code-caption markdown><code>server_config.cpp</code>.</p></p> <div class=highlight><pre><span></span><code><span class=c1># Apple clang: the precompiled header (pch.hpp contains only #include &lt;nlohmann/json.hpp&gt;) ...</span>
clang++<span class=w> </span>-std<span class=o>=</span>c++20<span class=w> </span>-O2<span class=w> </span>-I<span class=w> </span>single_include<span class=w> </span>-x<span class=w> </span>c++-header<span class=w> </span>pch.hpp<span class=w> </span>-o<span class=w> </span>pch.hpp.pch
clang++<span class=w> </span>-std<span class=o>=</span>c++20<span class=w> </span>-O2<span class=w> </span>-I<span class=w> </span>single_include<span class=w> </span>-include-pch<span class=w> </span>pch.hpp.pch<span class=w> </span>-c<span class=w> </span>count_numbers.cpp
<span class=c1># ... and the module</span>
clang++<span class=w> </span>-std<span class=o>=</span>c++20<span class=w> </span>-O2<span class=w> </span>-fcxx-modules<span class=w> </span>-I<span class=w> </span>single_include<span class=w> </span>-c<span class=w> </span>-x<span class=w> </span>c++-module<span class=w> </span>src/modules/json.cppm<span class=w> </span><span class=se>\</span>
<span class=w> </span>-fmodule-output<span class=o>=</span>nlohmann.json.pcm<span class=w> </span>-o<span class=w> </span>json_mod.o
clang++<span class=w> </span>-std<span class=o>=</span>c++20<span class=w> </span>-O2<span class=w> </span>-fcxx-modules<span class=w> </span>-fmodule-file<span class=o>=</span>nlohmann.json<span class=o>=</span>nlohmann.json.pcm<span class=w> </span>-DUSE_MODULE<span class=w> </span><span class=se>\</span>
<span class=w> </span>-c<span class=w> </span>count_numbers.cpp
<span class=c1># GCC 16 (Homebrew on macOS, add --sysroot=$(xcrun --show-sdk-path))</span>
g++-16<span class=w> </span>-std<span class=o>=</span>c++20<span class=w> </span>-O2<span class=w> </span>-I<span class=w> </span>single_include<span class=w> </span>-x<span class=w> </span>c++-header<span class=w> </span>pch.hpp<span class=w> </span>-o<span class=w> </span>pch.hpp.gch
g++-16<span class=w> </span>-std<span class=o>=</span>c++20<span class=w> </span>-O2<span class=w> </span>-I<span class=w> </span>single_include<span class=w> </span>-include<span class=w> </span>pch.hpp<span class=w> </span>-Winvalid-pch<span class=w> </span>-c<span class=w> </span>count_numbers.cpp
g++-16<span class=w> </span>-std<span class=o>=</span>c++20<span class=w> </span>-O2<span class=w> </span>-fmodules<span class=w> </span>-I<span class=w> </span>single_include<span class=w> </span>-c<span class=w> </span>src/modules/json.cppm<span class=w> </span>-o<span class=w> </span>json_mod.o
g++-16<span class=w> </span>-std<span class=o>=</span>c++20<span class=w> </span>-O2<span class=w> </span>-fmodules<span class=w> </span>-DUSE_MODULE<span class=w> </span>-c<span class=w> </span>count_numbers.cpp
</code></pre></div> <p><p class=nj-code-caption markdown>The commands for one program at <code>-O2</code>; the module variants are linked with <code>json_mod.o</code>.</p></p> </details> <p><strong>What we did not measure.</strong> The timeline and the algorithmic fixes ran on one Apple silicon laptop with Clang, the suite also on an Intel laptop with Clang. The comparison with other libraries also ran on an x86-64 server with <abbr title="GNU Compiler Collection">GCC</abbr> 16.2, <abbr title="GNU Compiler Collection">GCC</abbr> 13, and Clang 23, and on the Mac with <abbr title="GNU Compiler Collection">GCC</abbr> 16.2 and Clang 23 as a check. That server is a virtual machine with 8 cores that present themselves as Haswell; its timings show the penalty of the microcode fix for Intel's JCC erratum, which Haswell doesn't have, so the real <abbr title="Central Processing Unit">CPU</abbr> is probably a later one. It shares its cores with other work, so its differences of a few percent are noise. The theme sections quote x86-64 numbers where a pull request measured them, mostly with <abbr title="GNU Compiler Collection">GCC</abbr> 13 and Clang 18. Expect smaller gains for some workloads on x86-64 with glibc: its <code>FILE*</code> locking is cheaper to begin with, and its allocator behaves differently. We did not measure on Windows, and we did not measure binary size or memory use.</p> <h3 id=h-pull-requests-by-theme>H. Pull requests by theme<a class=headerlink href=#h-pull-requests-by-theme title="Permanent link">&para;</a></h3> <ul> <li><a class=nj-theme href=#theme-1 title="theme 1">1</a> <strong>Specialize for each input source:</strong> contiguous input <a href="https://github.com/nlohmann/json/pull/5283">#5283</a>; streams and <code>FILE*</code> <a href="https://github.com/nlohmann/json/pull/5828">#5828</a>, <a href="https://github.com/nlohmann/json/pull/5884">#5884</a>; binary strings in bulk <a href="https://github.com/nlohmann/json/pull/5233">#5233</a>; sized sentinels <a href="https://github.com/nlohmann/json/pull/5268">#5268</a>.</li> <li><a class=nj-theme href=#theme-2 title="theme 2">2</a> <strong>Work on words, not bytes:</strong> word-at-a-time strings, <abbr title="Unicode Transformation Format">UTF</abbr>-8 runs, and digits <a href="https://github.com/nlohmann/json/pull/5283">#5283</a>, <a href="https://github.com/nlohmann/json/pull/5738">#5738</a>, <a href="https://github.com/nlohmann/json/pull/5851">#5851</a>; indentation <a href="https://github.com/nlohmann/json/pull/5810">#5810</a>; <code>dump()</code> runs <a href="https://github.com/nlohmann/json/pull/5285">#5285</a>; <abbr title="Streaming SIMD Extensions 2">SSE2</abbr> and <abbr title="Arm SIMD instruction set extension">NEON</abbr> <a href="https://github.com/nlohmann/json/pull/5853">#5853</a>, <a href="https://github.com/nlohmann/json/pull/5628">#5628</a>; <code>json_document</code> with <code>ensure_ascii</code> <a href="https://github.com/nlohmann/json/pull/5879">#5879</a>; short strings <a href="https://github.com/nlohmann/json/pull/5878">#5878</a>, <a href="https://github.com/nlohmann/json/pull/5883">#5883</a>; escape table <a href="https://github.com/nlohmann/json/pull/5822">#5822</a>; loop shape <a href="https://github.com/nlohmann/json/pull/5490">#5490</a>; fraction digits <a href="https://github.com/nlohmann/json/pull/5971">#5971</a>; <abbr title="Binary JSON">BSON</abbr> keys <a href="https://github.com/nlohmann/json/pull/5968">#5968</a>; <abbr title="Unicode Transformation Format">UTF</abbr>-8 checks of binary strings <a href="https://github.com/nlohmann/json/pull/5982">#5982</a>; one <abbr title="Single Instruction, Multiple Data">SIMD</abbr> macro set <a href="https://github.com/nlohmann/json/pull/5921">#5921</a>.</li> <li><a class=nj-theme href=#theme-3 title="theme 3">3</a> <strong>Own the number conversions:</strong> Eisel-Lemire <a href="https://github.com/nlohmann/json/pull/5617">#5617</a>; long numbers <a href="https://github.com/nlohmann/json/pull/5738">#5738</a>; one pass over the digits <a href="https://github.com/nlohmann/json/pull/5851">#5851</a>; Żmij <a href="https://github.com/nlohmann/json/pull/5634">#5634</a>; long integers in <code>dump()</code> <a href="https://github.com/nlohmann/json/pull/5964">#5964</a>; <abbr title="Microsoft Visual C++">MSVC</abbr> intrinsics for the 128-bit multiplication <a href="https://github.com/nlohmann/json/pull/5782">#5782</a>.</li> <li><a class=nj-theme href=#theme-4 title="theme 4">4</a> <strong>Don't do unnecessary work:</strong> float token text <a href="https://github.com/nlohmann/json/pull/5852">#5852</a>; token buffer <a href="https://github.com/nlohmann/json/pull/5234">#5234</a>, <a href="https://github.com/nlohmann/json/pull/5828">#5828</a>; positions on error <a href="https://github.com/nlohmann/json/pull/5809">#5809</a>; binary readers' copy <a href="https://github.com/nlohmann/json/pull/5501">#5501</a>; <code>ordered_json</code> growth <a href="https://github.com/nlohmann/json/pull/5609">#5609</a>; arrays at their final size <a href="https://github.com/nlohmann/json/pull/5882">#5882</a>; moving keys <a href="https://github.com/nlohmann/json/pull/5458">#5458</a>, <a href="https://github.com/nlohmann/json/pull/5855">#5855</a>; separator check <a href="https://github.com/nlohmann/json/pull/5592">#5592</a>; <abbr title="Concise Binary Object Representation">CBOR</abbr> keys <a href="https://github.com/nlohmann/json/pull/5328">#5328</a>; <code>accept()</code> without copies <a href="https://github.com/nlohmann/json/pull/5978">#5978</a>; runs of scalars in binary arrays <a href="https://github.com/nlohmann/json/pull/5975">#5975</a>, <a href="https://github.com/nlohmann/json/pull/5980">#5980</a>, <a href="https://github.com/nlohmann/json/pull/5981">#5981</a>, <a href="https://github.com/nlohmann/json/pull/6008">#6008</a>; <abbr title="Binary JData">BJData</abbr> marker list <a href="https://github.com/nlohmann/json/pull/5555">#5555</a>; <code>from_json()</code> into containers <a href="https://github.com/nlohmann/json/pull/5833">#5833</a>.</li> <li><a class=nj-theme href=#theme-5 title="theme 5">5</a> <strong>Read the assembly:</strong> stack canary <a href="https://github.com/nlohmann/json/pull/5854">#5854</a>; exceptions and inlining <a href="https://github.com/nlohmann/json/pull/5838">#5838</a>, <a href="https://github.com/nlohmann/json/pull/5840">#5840</a>, <a href="https://github.com/nlohmann/json/pull/5839">#5839</a>, <a href="https://github.com/nlohmann/json/pull/5836">#5836</a>; aliasing <a href="https://github.com/nlohmann/json/pull/5633">#5633</a>; forced inlining <a href="https://github.com/nlohmann/json/pull/5878">#5878</a>; branch-free selections <a href="https://github.com/nlohmann/json/pull/5908">#5908</a>; code size <a href="https://github.com/nlohmann/json/pull/5902">#5902</a>.</li> <li><a class=nj-theme href=#theme-6 title="theme 6">6</a> <strong>Write through a cursor:</strong> write buffer <a href="https://github.com/nlohmann/json/pull/5285">#5285</a>; adapter on the stack <a href="https://github.com/nlohmann/json/pull/5449">#5449</a>; binary sinks <a href="https://github.com/nlohmann/json/pull/5286">#5286</a>; cursor and runs of numbers <a href="https://github.com/nlohmann/json/pull/5824">#5824</a>, <a href="https://github.com/nlohmann/json/pull/5885">#5885</a>; <code>to_bson()</code> in one pass <a href="https://github.com/nlohmann/json/pull/5979">#5979</a>.</li> <li><a class=nj-theme href=#theme-7 title="theme 7">7</a> <strong>Fix the algorithm first:</strong> <code>diff()</code> <a href="https://github.com/nlohmann/json/pull/5461">#5461</a>; parse callbacks <a href="https://github.com/nlohmann/json/pull/5457">#5457</a>; <code>operator&lt;</code> <a href="https://github.com/nlohmann/json/pull/5390">#5390</a>; <code>flatten()</code> <a href="https://github.com/nlohmann/json/pull/5834">#5834</a>; <code>unflatten()</code> <a href="https://github.com/nlohmann/json/pull/5793">#5793</a>; <abbr title="JavaScript Object Notation">JSON</abbr> Pointer and Patch <a href="https://github.com/nlohmann/json/pull/5861">#5861</a>, <a href="https://github.com/nlohmann/json/pull/5886">#5886</a>; <code>to_bson()</code> <a href="https://github.com/nlohmann/json/pull/5553">#5553</a>; <code>JSON_DIAGNOSTICS</code> <a href="https://github.com/nlohmann/json/pull/5832">#5832</a>; bounded recursion <a href="https://github.com/nlohmann/json/pull/5285">#5285</a>, <a href="https://github.com/nlohmann/json/pull/5389">#5389</a>, <a href="https://github.com/nlohmann/json/pull/5547">#5547</a>; destructor <a href="https://github.com/nlohmann/json/pull/5762">#5762</a>, <a href="https://github.com/nlohmann/json/pull/5835">#5835</a>.</li> <li><a class=nj-theme href=#theme-8 title="theme 8">8</a> <strong>Build a different data structure:</strong> <code>json_document</code> <a href="https://github.com/nlohmann/json/pull/5620">#5620</a>, <a href="https://github.com/nlohmann/json/pull/5627">#5627</a>, <a href="https://github.com/nlohmann/json/pull/5628">#5628</a>, <a href="https://github.com/nlohmann/json/pull/5622">#5622</a>, <a href="https://github.com/nlohmann/json/pull/5908">#5908</a>, <a href="https://github.com/nlohmann/json/pull/5879">#5879</a>; <code>accept()</code> without an index <a href="https://github.com/nlohmann/json/pull/5970">#5970</a>; reading and indexing <a href="https://github.com/nlohmann/json/pull/5888">#5888</a>, <a href="https://github.com/nlohmann/json/pull/5915">#5915</a>, <a href="https://github.com/nlohmann/json/pull/5889">#5889</a>, <a href="https://github.com/nlohmann/json/pull/5890">#5890</a>; editing <a href="https://github.com/nlohmann/json/pull/5630">#5630</a>, <a href="https://github.com/nlohmann/json/pull/5919">#5919</a>, <a href="https://github.com/nlohmann/json/pull/5926">#5926</a>.</li> <li><strong>Validation:</strong> guard pages <a href="https://github.com/nlohmann/json/pull/5826">#5826</a>; differential fuzzing <a href="https://github.com/nlohmann/json/pull/5827">#5827</a>; float checks <a href="https://github.com/nlohmann/json/pull/5617">#5617</a>, <a href="https://github.com/nlohmann/json/pull/5908">#5908</a>; mutation checks <a href="https://github.com/nlohmann/json/pull/5878">#5878</a>.</li> <li><strong>The <abbr title="Unicode Transformation Format">UTF</abbr>-8 check that came and went:</strong> <a href="https://github.com/nlohmann/json/pull/5185">#5185</a>, <a href="https://github.com/nlohmann/json/pull/5531">#5531</a>, <a href="https://github.com/nlohmann/json/pull/5741">#5741</a>, <a href="https://github.com/nlohmann/json/pull/5746">#5746</a>.</li> </ul> <h3 id=i-details-of-the-themes>I. Details of the themes<a class=headerlink href=#i-details-of-the-themes title="Permanent link">&para;</a></h3> <p><strong>Eisel-Lemire (theme <a class=nj-theme href=#theme-3 title="theme 3">3</a>).</strong> <a href="https://github.com/fastfloat/fast_float">fast_float</a>'s <code>compute_float</code>, which 3.13.0 adapts, works with integers only. The value is <code>w · 10^q = w · 5^q · 2^q</code>, so it normalizes <code>w</code> to 64 significant bits, multiplies it with a 128-bit approximation of <code>5^q</code> from a table of 651 entries, and takes the 53 bits of the mantissa plus one rounding bit from the top of the product. The binary exponent comes from a fixed-point <code>log2(10)</code>. If the nine bits below the rounding bit are all ones, the truncated part of the table entry could still carry into the result; then a second multiplication with the next 64 bits of <code>5^q</code> decides, which happens for about one input in 512. Mushtak and Lemire showed in 2023 that for up to 19 digits these 128 bits always suffice, so the algorithm needs no fallback. Exact ties between two <code>double</code>s, the only place where rounding half to even matters, can only occur for small exponents, and are handled there. (Clinger's fast path, by contrast, uses the floating-point unit and assumes the default rounding mode.)</p> <p>Numbers with more than 19 digits are rare in <abbr title="JavaScript Object Notation">JSON</abbr>. For them, Eisel-Lemire runs on the first 19 digits, <code>w</code>, and on <code>w + 1</code>: the true value lies between the two, so if both give the same <code>double</code>, that is the answer. Only if they differ does fast_float's digit comparison build the exact midpoint between the two candidates as a big integer and compare all digits with it.</p> <p><strong>Żmij's digits (theme <a class=nj-theme href=#theme-3 title="theme 3">3</a>).</strong> Żmij's digit conversion, by Xiang JunBo, is the same divide-by-multiplying idea as the parser's, run backwards on all lanes of a word at once:</p> <div class=highlight><pre><span></span><code><span class=c1>// 12345678 -&gt; the bytes 1, 2, 3, 4, 5, 6, 7, 8 (one digit per byte)</span>
<span class=n>std</span><span class=o>::</span><span class=kt>uint64_t</span><span class=w> </span><span class=nf>eight_digit_bytes</span><span class=p>(</span><span class=n>std</span><span class=o>::</span><span class=kt>uint64_t</span><span class=w> </span><span class=n>abcdefgh</span><span class=p>)</span><span class=w> </span><span class=k>noexcept</span>
<span class=p>{</span>
<span class=w> </span><span class=c1>// x / d as (x * (2^k / d + 1)) &gt;&gt; k</span>
<span class=w> </span><span class=k>const</span><span class=w> </span><span class=n>std</span><span class=o>::</span><span class=kt>uint64_t</span><span class=w> </span><span class=n>abcd</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=p>(</span><span class=n>abcdefgh</span><span class=w> </span><span class=o>*</span><span class=w> </span><span class=p>(((</span><span class=mi>1ull</span><span class=w> </span><span class=o>&lt;&lt;</span><span class=w> </span><span class=mi>40</span><span class=p>)</span><span class=w> </span><span class=o>/</span><span class=w> </span><span class=mi>10000</span><span class=p>)</span><span class=w> </span><span class=o>+</span><span class=w> </span><span class=mi>1</span><span class=p>))</span><span class=w> </span><span class=o>&gt;&gt;</span><span class=w> </span><span class=mi>40</span><span class=p>;</span>
<span class=w> </span><span class=k>const</span><span class=w> </span><span class=n>std</span><span class=o>::</span><span class=kt>uint64_t</span><span class=w> </span><span class=n>abcd_efgh</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>abcdefgh</span><span class=w> </span><span class=o>+</span><span class=w> </span><span class=p>((</span><span class=mi>1ull</span><span class=w> </span><span class=o>&lt;&lt;</span><span class=w> </span><span class=mi>32</span><span class=p>)</span><span class=w> </span><span class=o>-</span><span class=w> </span><span class=mi>10000</span><span class=p>)</span><span class=w> </span><span class=o>*</span><span class=w> </span><span class=n>abcd</span><span class=p>;</span>
<span class=w> </span><span class=k>const</span><span class=w> </span><span class=n>std</span><span class=o>::</span><span class=kt>uint64_t</span><span class=w> </span><span class=n>ab_ef</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=p>((</span><span class=n>abcd_efgh</span><span class=w> </span><span class=o>*</span><span class=w> </span><span class=p>(((</span><span class=mi>1ull</span><span class=w> </span><span class=o>&lt;&lt;</span><span class=w> </span><span class=mi>19</span><span class=p>)</span><span class=w> </span><span class=o>/</span><span class=w> </span><span class=mi>100</span><span class=p>)</span><span class=w> </span><span class=o>+</span><span class=w> </span><span class=mi>1</span><span class=p>))</span><span class=w> </span><span class=o>&gt;&gt;</span><span class=w> </span><span class=mi>19</span><span class=p>)</span><span class=w> </span><span class=o>&amp;</span><span class=w> </span><span class=mh>0x7F0000007Full</span><span class=p>;</span>
<span class=w> </span><span class=k>const</span><span class=w> </span><span class=n>std</span><span class=o>::</span><span class=kt>uint64_t</span><span class=w> </span><span class=n>ab_cd_ef_gh</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>abcd_efgh</span><span class=w> </span><span class=o>+</span><span class=w> </span><span class=p>((</span><span class=mi>1ull</span><span class=w> </span><span class=o>&lt;&lt;</span><span class=w> </span><span class=mi>16</span><span class=p>)</span><span class=w> </span><span class=o>-</span><span class=w> </span><span class=mi>100</span><span class=p>)</span><span class=w> </span><span class=o>*</span><span class=w> </span><span class=n>ab_ef</span><span class=p>;</span>
<span class=w> </span><span class=k>const</span><span class=w> </span><span class=n>std</span><span class=o>::</span><span class=kt>uint64_t</span><span class=w> </span><span class=n>a_c_e_g</span><span class=w> </span><span class=o>=</span>
<span class=w> </span><span class=p>((</span><span class=n>ab_cd_ef_gh</span><span class=w> </span><span class=o>*</span><span class=w> </span><span class=p>(((</span><span class=mi>1ull</span><span class=w> </span><span class=o>&lt;&lt;</span><span class=w> </span><span class=mi>10</span><span class=p>)</span><span class=w> </span><span class=o>/</span><span class=w> </span><span class=mi>10</span><span class=p>)</span><span class=w> </span><span class=o>+</span><span class=w> </span><span class=mi>1</span><span class=p>))</span><span class=w> </span><span class=o>&gt;&gt;</span><span class=w> </span><span class=mi>10</span><span class=p>)</span><span class=w> </span><span class=o>&amp;</span><span class=w> </span><span class=mh>0x000F000F000F000Full</span><span class=p>;</span>
<span class=w> </span><span class=k>return</span><span class=w> </span><span class=n>ab_cd_ef_gh</span><span class=w> </span><span class=o>+</span><span class=w> </span><span class=p>((</span><span class=mi>1ull</span><span class=w> </span><span class=o>&lt;&lt;</span><span class=w> </span><span class=mi>8</span><span class=p>)</span><span class=w> </span><span class=o>-</span><span class=w> </span><span class=mi>10</span><span class=p>)</span><span class=w> </span><span class=o>*</span><span class=w> </span><span class=n>a_c_e_g</span><span class=p>;</span>
<span class=p>}</span>
</code></pre></div> <p class=nj-code-caption>Żmij's conversion of an eight-digit number to one digit per byte, in three steps of divide-by-multiplying.</p> <p><code>(x · ⌈2^k / d⌉) &gt;&gt; k</code> is <code>x / d</code> for the range that occurs, and <code>x + (2^w − d) · (x / d)</code> rewrites <code>x</code> as <code>(x / d) · 2^w + x mod d</code>: the quotient moves up into the next lane. Three steps split 8 digits into 4 + 4, 2 + 2 + 2 + 2, and single digits. A zero digit becomes a zero byte, so leading and trailing zeros are counted with a count of leading or trailing zero bits instead of divisions.</p> <p><strong>The destructor's walk (theme <a class=nj-theme href=#theme-7 title="theme 7">7</a>).</strong> While the destructor's walk empties a container, the slot of that container's last child holds the link back to the container's parent:</p> <div class=highlight><pre><span></span><code><span class=c1>// descend into the last child of cur, reversing the link</span>
<span class=n>basic_json</span><span class=o>&amp;</span><span class=w> </span><span class=n>slot</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>last_child</span><span class=p>(</span><span class=n>cur</span><span class=p>);</span>
<span class=n>take</span><span class=p>(</span><span class=n>tmp</span><span class=p>,</span><span class=w> </span><span class=n>slot</span><span class=p>);</span><span class=w> </span><span class=c1>// the child's contents</span>
<span class=n>take</span><span class=p>(</span><span class=n>slot</span><span class=p>,</span><span class=w> </span><span class=n>prev</span><span class=p>);</span><span class=w> </span><span class=c1>// its slot now remembers cur's parent</span>
<span class=n>take</span><span class=p>(</span><span class=n>prev</span><span class=p>,</span><span class=w> </span><span class=n>cur</span><span class=p>);</span><span class=w> </span><span class=c1>// cur becomes the parent</span>
<span class=n>take</span><span class=p>(</span><span class=n>cur</span><span class=p>,</span><span class=w> </span><span class=n>tmp</span><span class=p>);</span><span class=w> </span><span class=c1>// the child becomes cur</span>
<span class=c1>// on the way up: read the parent back out of prev's last slot, pop that slot, free cur</span>
</code></pre></div> <p class=nj-code-caption>One step down in the destructor's walk: the emptied slot remembers the way back.</p> <p><code>take()</code> moves the 16 bytes of type and value and leaves a null behind. The way back needs no memory: the slot that holds the link is the one being emptied, it stays the last child until the walk comes back up, and only then, after the link is taken out, is it removed. A child is removed only when it is a scalar or an empty container, so each removal destroys one level at most.</p> <h3 id=j-validation>J. Validation<a class=headerlink href=#j-validation title="Permanent link">&para;</a></h3> <p>A faster path is only useful if it gives the same result as the slow one, including the same error at the same byte. These are the checks behind the themes:</p> <ul> <li><strong>Error positions</strong> (theme <a class=nj-theme href=#theme-1 title="theme 1">1</a>). The contiguous fast paths defer to the byte path on anything malformed. On 481,000 documents, 298,333 of them with errors, the contiguous and the byte path reported the same exception, message, byte, line and column, except for the one deliberate correction listed in <a href=#f-behavior-changes>Appendix F</a>.</li> <li><strong>Stream windows</strong> (theme <a class=nj-theme href=#theme-1 title="theme 1">1</a>). A test <code>streambuf</code> hands out get areas of 1–4,096 bytes, so that every token crosses a window edge at every offset, and the result is compared with a <code>streambuf</code> without a get area, which takes the old path.</li> <li><strong>Differential fuzzing of the input kinds.</strong> Every fuzz input is also parsed from an <code>std::istringstream</code>, from <code>std::list</code> iterators (the byte path) and from a <code>FILE*</code>, and the value, the exception id, the message, and the byte offset must be identical (<a href="https://github.com/nlohmann/json/pull/5827">#5827</a>).</li> <li><strong>Guard pages.</strong> The input is copied so that its last byte is the last readable byte of a page, and the next page is unmapped. AddressSanitizer misses an over-read into the slack of the same heap allocation, and fuzzers rarely end an input exactly at a page boundary; this test crashes on any over-read by one byte (<a href="https://github.com/nlohmann/json/pull/5826">#5826</a>).</li> <li><strong>Number conversion</strong> (theme <a class=nj-theme href=#theme-3 title="theme 3">3</a>). 6.5 million float tokens were compared with <code>strtod</code>, among them 60,000 exact halfway cases, and 900,000 hard cases from other test suites: all bit-identical. <code>json_document</code>'s batched float output is byte-identical to the general writer for 10⁹ generated tokens.</li> <li><strong>Unchanged output.</strong> For this post, we checked that 3.13.0 writes the same bytes as 3.12.0 in all five binary formats for 39 test files, and the same <abbr title="JavaScript Object Notation">JSON</abbr> text for <code>twitter.json</code> and <code>citm_catalog.json</code>. The changes of float output are listed in <a href=#f-behavior-changes>Appendix F</a>.</li> <li><strong><code>json_document</code> against <code>json</code>.</strong> A fuzzer parses every input with both and requires the same verdict, the same value and the same error message, from a borrowed string and from an exact-size buffer without a closing <abbr title="Null character (U+0000, byte value 0)">NUL</abbr> (<a href="https://github.com/nlohmann/json/blob/develop/tests/src/fuzzer-parse_json_view.cpp"><code>fuzzer-parse_json_view.cpp</code></a>).</li> <li><strong>Comparison</strong> (theme <a class=nj-theme href=#theme-7 title="theme 7">7</a>). The single-pass <code>operator&lt;</code> was compared with the old code on 68,121 pairs of values.</li> <li><strong>Mutation checks.</strong> Break a fast path on purpose (skip one byte too many, mark <code>"</code> as copyable) and make sure the tests notice. Marking the quote as copyable in the short-string table fails 4,551 assertions.</li> <li><strong>The comparison with other libraries.</strong> Before anything is timed, every way's result is checked: the same values, the same string bytes, the same sum of all numbers (to the last bit where they are added in the same order), and an output that reads back as the expected document. The expected values come from nlohmann/json; the Rust programs compute their own with serde_json, and the two agree (<a href=#e-comparison-with-other-libraries>Appendix E</a>).</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=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M21 13.1c-.1 0-.3.1-.4.2l-1 1 2.1 2.1 1-1c.2-.2.2-.6 0-.8l-1.3-1.3c-.1-.1-.2-.2-.4-.2m-1.9 1.8-6.1 6V23h2.1l6.1-6.1zM12.5 7v5.2l4 2.4-1 1L11 13V7zM11 21.9c-5.1-.5-9-4.8-9-9.9C2 6.5 6.5 2 12 2c5.3 0 9.6 4.1 10 9.3-.3-.1-.6-.2-1-.2s-.7.1-1 .2C19.6 7.2 16.2 4 12 4c-4.4 0-8 3.6-8 8 0 4.1 3.1 7.5 7.1 7.9l-.1.2z"/></svg> </span> <span class="git-revision-date-localized-plugin git-revision-date-localized-plugin-date" title="November 9, 2026 10:37:52 UTC">November 9, 2026</span> </span> </aside> </article> </div> <script>var tabs=__md_get("__tabs");if(Array.isArray(tabs))e:for(var set of document.querySelectorAll(".tabbed-set")){var labels=set.querySelector(".tabbed-labels");for(var tab of tabs)for(var label of labels.getElementsByTagName("label"))if(label.innerText.trim()===tab){var input=document.getElementById(label.htmlFor);input.checked=!0;continue e}}</script> <script>var target=document.getElementById(location.hash.slice(1));target&&target.name&&(target.checked=target.name.startsWith("__tabbed_"))</script> </div> <button type=button class="md-top md-icon" data-md-component=top hidden> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M13 20h-2V8l-5.5 5.5-1.42-1.42L12 4.16l7.92 7.92-1.42 1.42L13 8z"/></svg> Back to top </button> </main> <footer class=md-footer> <nav class="md-footer__inner md-grid" aria-label=Footer> <a href=../../releases/v1.0.0/ class="md-footer__link md-footer__link--prev" aria-label="Previous: v1.0.0"> <div class="md-footer__button md-icon"> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11z"/></svg> </div> <div class=md-footer__title> <span class=md-footer__direction> Previous </span> <div class=md-ellipsis> v1.0.0 </div> </div> </a> <a href=../../design_goals/ class="md-footer__link md-footer__link--next" aria-label="Next: Design goals"> <div class=md-footer__title> <span class=md-footer__direction> Next </span> <div class=md-ellipsis> Design goals </div> </div> <div class="md-footer__button md-icon"> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M4 11v2h12l-5.5 5.5 1.42 1.42L19.84 12l-7.92-7.92L10.5 5.5 16 11z"/></svg> </div> </a> </nav> <div class="md-footer-meta md-typeset"> <div class="md-footer-meta__inner md-grid"> <div class=md-copyright> <div class=md-copyright__highlight> Copyright &copy; 2013-2026 Niels Lohmann </div> </div> <div class=md-social> <a href="https://github.com/nlohmann" target="_blank" rel="noopener" title="github.com" class="md-social__link"> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 512 512"><!-- Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2025 Fonticons, Inc.--><path d="M173.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6m-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3m44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9M252.8 8C114.1 8 8 113.3 8 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C436.2 457.8 504 362.9 504 252 504 113.3 391.5 8 252.8 8M105.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1m-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7m32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1m-11.4-14.7c-1.6 1-1.6 3.6 0 5.9s4.3 3.3 5.6 2.3c1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2"/></svg> </a> <a href="https://www.linkedin.com/in/nielslohmann/" target="_blank" rel="noopener" title="www.linkedin.com" class="md-social__link"> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 448 512"><!-- Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2025 Fonticons, Inc.--><path d="M416 32H31.9C14.3 32 0 46.5 0 64.3v383.4C0 465.5 14.3 480 31.9 480H416c17.6 0 32-14.5 32-32.3V64.3c0-17.8-14.4-32.3-32-32.3M135.4 416H69V202.2h66.5V416zM102.2 96a38.5 38.5 0 1 1 0 77 38.5 38.5 0 1 1 0-77m282.1 320h-66.4V312c0-24.8-.5-56.7-34.5-56.7-34.6 0-39.9 27-39.9 54.9V416h-66.4V202.2h63.7v29.2h.9c8.9-16.8 30.6-34.5 62.9-34.5 67.2 0 79.7 44.3 79.7 101.9z"/></svg> </a> <a href="https://www.xing.com/profile/Niels_Lohmann" target="_blank" rel="noopener" title="www.xing.com" class="md-social__link"> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 384 512"><!-- Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2025 Fonticons, Inc.--><path d="M162.7 210c-1.8 3.3-25.2 44.4-70.1 123.5-4.9 8.3-10.8 12.5-17.7 12.5H9.8c-7.7 0-12.1-7.5-8.5-14.4l69-121.3q.3 0 0-.3l-43.9-75.6c-4.3-7.8.3-14.1 8.5-14.1H100c7.3 0 13.3 4.1 18 12.2zM382.6 46.1l-144 253v.3L330.2 466c3.9 7.1.2 14.1-8.5 14.1h-65.2c-7.6 0-13.6-4-18-12.2l-92.4-168.5c3.3-5.8 51.5-90.8 144.8-255.2 4.6-8.1 10.4-12.2 17.5-12.2h65.7c8 0 12.3 6.7 8.5 14.1"/></svg> </a> <a href="https://www.paypal.me/nlohmann" target="_blank" rel="noopener" title="www.paypal.me" class="md-social__link"> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 384 512"><!-- Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2025 Fonticons, Inc.--><path d="M111.9 295.9c-3.5 19.2-17.4 108.7-21.5 134-.3 1.8-1 2.5-3 2.5H12.8c-7.6 0-13.1-6.6-12.1-13.9L59.3 46.6c1.5-9.6 10.1-16.9 20-16.9 152.3 0 165.1-3.7 204 11.4 60.1 23.3 65.6 79.5 44 140.3-21.5 62.6-72.5 89.5-140.1 90.3-43.4.7-69.5-7-75.3 24.2M357.6 152c-1.8-1.3-2.5-1.8-3 1.3-2 11.4-5.1 22.5-8.8 33.6-39.9 113.8-150.5 103.9-204.5 103.9-6.1 0-10.1 3.3-10.9 9.4-22.6 140.4-27.1 169.7-27.1 169.7-1 7.1 3.5 12.9 10.6 12.9h63.5c8.6 0 15.7-6.3 17.4-14.9.7-5.4-1.1 6.1 14.4-91.3 4.6-22 14.3-19.7 29.3-19.7 71 0 126.4-28.8 142.9-112.3 6.5-34.8 4.6-71.4-23.8-92.6"/></svg> </a> </div> </div> </div> </footer> </div> <div class=md-dialog data-md-component=dialog> <div class="md-dialog__inner md-typeset"></div> </div> <script id=__config type=application/json>{"annotate": null, "base": "../../..", "features": ["navigation.instant", "navigation.tracking", "navigation.tabs", "navigation.indexes", "navigation.top", "navigation.footer", "toc.follow", "search.suggest", "search.highlight", "content.code.copy", "content.tabs.link", "content.action.edit", "content.action.view"], "search": "../../../assets/javascripts/workers/search.a7633da7.min.js", "tags": null, "translations": {"clipboard.copied": "Copied to clipboard", "clipboard.copy": "Copy to clipboard", "search.result.more.one": "1 more on this page", "search.result.more.other": "# more on this page", "search.result.none": "No matching documents", "search.result.one": "1 matching document", "search.result.other": "# matching documents", "search.result.placeholder": "Type to start searching", "search.result.term.missing": "Missing", "select.version": "Select version"}, "version": null}</script> <script src=../../../assets/javascripts/bundle.c21346df.min.js></script> <script src=../../../js/mermaid-brand.js></script> <script src=../../../js/external-links.js></script> <script src=../../../js/fig-sax.js></script> <script src=../../../js/fig-jsonview.js></script> <script src=../../../js/fig-exceptions.js></script> <script src=../../../js/fig-pointer.js></script> <script src=../../../js/fig-charts.js></script> <script src=../../../js/fig-integration.js></script> <script src=../../../js/fig-macros.js></script> </body> </html>