Two further serialization speedups on top of the ensure_ascii=false bulk
copy, both reusing the SWAR primitives in detail/input/string_scan.hpp.
1. Internal write buffer (devirtualization). Every structural character
('{', '"', ',', ...) previously went straight to the output adapter
through a virtual call. Route all writes through put_char/put_chars
into a 1 KiB buffer that flushes in bulk; the public dump() flushes
once the top-level value is done (the recursive worker is split out as
dump_internal). Runs larger than the buffer are written straight
through, so large payloads are not copied twice. This is the dominant
cost for object/array-heavy values.
2. ensure_ascii fast path. dump_escaped previously ran the UTF-8 DFA over
every byte when escaping non-ASCII. Add find_ascii_copyable_run() (a
SWAR scan stopping at '"', '\\', < 0x20, 0x7F, and >= 0x80) so runs of
printable ASCII are bulk-copied, with the byte path handling each
escape/non-ASCII byte exactly as before.
Behavior is unchanged: dump output is byte-for-byte identical to the
previous implementation across ~20k randomized byte strings plus curated
edge cases (all escapes, control chars, 0x7F, valid multibyte,
surrogates, overlong, truncated), for object/array/pretty output, both
ensure_ascii settings, and all three error handlers, in C++11/17/20 at
-O2/-O3. New unit tests cover the buffer flush boundaries, the escape and
0x7F handling, multibyte under both settings, and invalid-UTF-8 handling.
Throughput (g++ -O3, vs the ensure_ascii=false-only baseline):
long ASCII, ensure_ascii=0 4.2x
long ASCII, ensure_ascii=1 4.1x
twitter-like objects 2.7x
dense CJK 1.8x
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XAYM1qhSA2FDaDcGfPW3fG
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
* Fix for printing long doubles bug in dump_float
When you use long double as a floating point type with the current version of this file and try to dump json it prints trash instead of actual number. This if-else fixes the problem. On using long double you just need to add an 'L' modifier before 'g' in format string.
Signed-off-by: Kirill Lokotkov <klokotkov@ya.ru>
* C++11 compatibility
Signed-off-by: Kirill Lokotkov <klokotkov@ya.ru>
* Shorter solution
Signed-off-by: Kirill Lokotkov <klokotkov@ya.ru>
* Applied amalgamate
Signed-off-by: rusloker <klokotkov@ya.ru>
* Add unit tests for `dump()` with `long double` in custom `basic_json`
Signed-off-by: rusloker <klokotkov@ya.ru>
* Fix UB in `snprintf_float` by using `%.*Lg` for `long double`
Signed-off-by: rusloker <klokotkov@ya.ru>
* Use `std::array` for `values` in serialization unit tests to improve type safety
Signed-off-by: rusloker <klokotkov@ya.ru>
* Fix brace initialization for `std::array` in serialization unit tests
Signed-off-by: rusloker <klokotkov@ya.ru>
* Remove comments in `snprintf_float` regarding `%Lg` usage
Signed-off-by: rusloker <klokotkov@ya.ru>
* Skip `long double` infinity dump assertions under Valgrind
Signed-off-by: rusloker <klokotkov@ya.ru>
* Clarify Valgrind bug-tracker reference in `long double` test
Signed-off-by: rusloker <klokotkov@ya.ru>
* Satisfy clang-tidy in `long double` infinity probe
Signed-off-by: rusloker <klokotkov@ya.ru>
---------
Signed-off-by: Kirill Lokotkov <klokotkov@ya.ru>
Signed-off-by: rusloker <klokotkov@ya.ru>