Commit Graph

3135 Commits

Author SHA1 Message Date
Francisco Geiman Thiesen 920573fffd Optimize reflection-based deserialization with hybrid algorithm
- Add threshold-based algorithm selection (N<=8: per-field, N>=9: single-pass)
- Per-field lookup leverages simdjson's SIMD-optimized find_field_unordered
- Single-pass uses bitmask tracking, first-char filter, and early termination
- Add fields_in_order<T> trait for user-defined ordered field optimization

Performance improvement on benchmarks:
- Twitter: +5.3% (4167 -> 4389 MB/s)
- CITM: +14.6% (2600 -> 2994 MB/s)

Threshold=8 is based on crossover analysis: at N=9 fields, per-field lookup
causes ~35% regression due to quadratic scan cost vs single-pass linear cost.
2026-02-19 09:04:05 -08:00
Francisco Geiman Thiesen af2a43610e perf: SIMD string escaping and batch integer formatting optimizations (#2605)
* perf(serialization): SIMD-accelerated string escape position finding

Profiling revealed that string serialization was performing redundant
scanning: first calling fast_needs_escaping() (SIMD scan to check IF
escape needed), then find_next_json_quotable_character() (scalar
byte-by-byte scan to find WHERE).

Profile data from Twitter benchmark showed:
- 54.76% time in atom<std::string> (string serialization)
- 24.85% time in find_next_json_quotable_character (scalar position finding)

This optimization unifies both operations into a single SIMD pass that
directly locates the first quotable character position:

- NEON (ARM64): Uses vceqq_u8/vcltq_u8 for character detection, then
  extracts position via __builtin_ctzll on 64-bit vector lanes
- SSE2 (x86-64): Uses _mm_cmpeq_epi8/_mm_subs_epu8 for detection, then
  _mm_movemask_epi8 + __builtin_ctz for position extraction

The write_string_escaped function now uses the position finder directly,
eliminating the separate fast_needs_escaping check.

Benchmark results (ARM64, Apple Silicon via Docker with p2996 clang):
- Twitter (string-heavy): 4330 -> 5723 MB/s (+32%)
- CITM (numeric-heavy): ~neutral (expected, few strings)

* perf(serialization): batch integer formatting with 4-digit processing

Profiling with perf annotate revealed that the integer-to-string
conversion loop was a significant hotspot in numeric-heavy workloads.
The original implementation processed 2 digits per iteration:

    while (pv >= 100) {
        memcpy(write_pointer - 1, &decimal_table[(pv % 100) * 2], 2);
        write_pointer -= 2;
        pv /= 100;
    }

Profile data from CITM benchmark showed:
- 31.20% time in atom<unsigned long> (integer formatting)
- 39.07% of integer formatting time in the 2-byte store instruction
  (sturh on ARM64)
- CITM integers average 8.8 digits, meaning 4+ store operations per number

This optimization processes 4 digits per iteration, reducing both store
operations and division count by approximately half for large numbers:

    while (pv >= 10000) {
        q = pv / 10000;
        r = pv % 10000;
        r_hi = r / 100;  // High 2 digits
        r_lo = r % 100;  // Low 2 digits
        memcpy(write_pointer - 1, &decimal_table[r_lo * 2], 2);
        memcpy(write_pointer - 3, &decimal_table[r_hi * 2], 2);
        write_pointer -= 4;
        pv = q;
    }

The division by 10000 compiles to an efficient multiply-high instruction
(umulh on ARM64). Applied to both unsigned and signed integer paths.

Benchmark results (ARM64, Apple Silicon via Docker with p2996 clang):
- Twitter: ~neutral (few integers)
- CITM (numeric-heavy): 2912 -> 3086 MB/s (+6%)

* fix(build): add MSVC compatibility for bit manipulation intrinsics

MSVC does not have __builtin_ctz/__builtin_ctzll. Use _BitScanForward
and _BitScanForward64 from <intrin.h> on MSVC instead.

This fixes the build on all Windows configurations (x64, ARM64, Win32).

* refactor: clean up comments to be implementation-focused

Remove references to specific benchmarks and previous implementations
from code comments. Comments now describe what the code does rather
than historical context.
2026-02-16 11:50:27 -05:00
Daniel Lemire e362b18499 saving. 2026-02-09 00:31:31 -05:00
Daniel Lemire 6e60ed8338 updating rust 2026-02-08 23:42:43 -05:00
Daniel Lemire e2ca00c841 reenabling bench_nlohmann_parsing in twitter bench 2026-02-08 22:36:34 -05:00
Daniel Lemire b7124f7c64 inlining get_single_implementation (#2600) 2026-02-06 20:34:00 -05:00
Daniel Lemire e6c6db6493 Update field access section in basics.md
Clarified field access behavior and error handling in documentation.
2026-02-03 14:04:26 -05:00
Daniel Lemire 6fffc99dac Add Ladybird Browser to the list of projects 2026-02-02 21:08:31 -05:00
Daniel Lemire 8c5cc8c443 updating the reflection benchmarks (#2598)
* updating the reflection benchmarks

* removing exception during parsing.

* saving.
2026-02-02 11:28:08 -05:00
Daniel Lemire d8c49a8f25 fix to rust instructions 2026-01-27 20:08:06 -05:00
Daniel Lemire cda98064b8 faster amalgamation script (#2597) 2026-01-27 11:35:58 -05:00
Daniel Lemire e532d61e16 when calling get_string with a mutable string parameter, we want to only use the string buffer (#2595)
as scratch space
2026-01-22 10:23:39 -05:00
Olaf Bernstein db93de2a21 add rvv-vls backend (#2593) 2026-01-21 10:13:50 -05:00
Francisco Geiman Thiesen fc57c09cf0 Add FracturedJson formatting support for DOM serialization (#2580)
* Add FracturedJson formatting support for DOM serialization

Implements FracturedJson formatting as requested in issue #2576.
FracturedJson produces human-readable yet compact JSON output by
intelligently choosing between different layout strategies based on
content complexity, length, and structure similarity.

Key features:
- Four layout modes: inline, compact multiline, table, and expanded
- Structure analysis pass to compute metrics before formatting
- Table formatting for arrays of similar objects with column alignment
- Configurable options for line length, indentation, padding, etc.

New files:
- fractured_json.h: Public API with fractured_json_options struct
- fractured_json-inl.h: Implementation (~1000 lines)
- json_structure_analyzer.h: Structure analysis for layout decisions
- fractured_formatter.h: Formatter class using CRTP pattern

Usage:
  dom::parser parser;
  element doc = parser.parse(json_string);
  std::cout << fractured_json(doc) << std::endl;

  // Or with custom options:
  fractured_json_options opts;
  opts.indent_spaces = 2;
  std::cout << fractured_json(doc, opts) << std::endl;

  // Or format any JSON string (useful with reflection API):
  auto formatted = fractured_json_string(minified_json);

Resolves #2576

* Add comprehensive tests for FracturedJson formatter

Adds 27 test cases covering all aspects of the FracturedJson formatter:

Core functionality tests (13):
- Roundtrip parsing verification
- Inline formatting for simple arrays and objects
- Expanded formatting for complex nested structures
- Compact multiline arrays with configurable items per line
- Table formatting for uniform arrays of objects
- Empty container handling
- All scalar types (string, int, uint, double, bool, null)
- String escaping (quotes, backslashes, control characters)
- Custom indentation options
- Deep nesting (10+ levels)
- Mixed type arrays

Edge case tests (11):
- Unicode strings (Chinese, emoji, Arabic, Russian, accented chars)
- Boundary numbers (INT64_MIN/MAX, UINT64_MAX, DBL_MIN/MAX)
- Nested arrays (arrays of arrays)
- Empty string values
- Keys with special characters (spaces, quotes, colons, etc.)
- Non-uniform arrays (should not trigger table mode)
- Very long strings (500+ chars)
- Large arrays (100 elements)
- Reflection API workflow simulation
- Control characters (tab, newline, CR, null)
- Single element containers

Option tests (3):
- Disable compact multiline mode
- Disable table format mode
- Disable all padding options

* Add FracturedJson integration with builder/reflection API

Extends FracturedJson to work seamlessly with the builder API, enabling
formatted output directly from C++ structs using static reflection.

New functions:
- to_fractured_json_string(obj, opts) - serialize struct to formatted JSON
- to_fractured_json(obj, output, opts) - same with output parameter
- extract_fractured_json<fields...>(obj, opts) - format only specific fields

These functions combine the builder's reflection-based serialization with
FracturedJson formatting in a single convenient call:

  struct User { int id; std::string name; bool active; };
  User user{1, "Alice", true};

  // Minified output (existing):
  auto minified = to_json_string(user);
  // {"id":1,"name":"Alice","active":true}

  // Formatted output (new):
  auto formatted = to_fractured_json_string(user);
  // { "id": 1, "name": "Alice", "active": true }

  // Partial extraction with formatting:
  auto partial = extract_fractured_json<"id", "name">(user);
  // { "id": 1, "name": "Alice" }

New files:
- generic/builder/fractured_json_builder.h - builder integration
- tests/builder/static_reflection_fractured_json_tests.cpp - 7 tests

* Fix INT64_MIN overflow and implement table_similarity_threshold

- Fix undefined behavior when negating INT64_MIN in estimate_number_length()
  and measure_value_length() by returning 20 (the exact length of the
  string representation) directly
- Actually use table_similarity_threshold in check_array_uniformity() by
  calling compute_object_similarity() to compare objects against the first
  object in the array

* Fix -Werror=effc++ member initialization warnings

Initialize all member variables in member initialization lists to
satisfy GCC's -Werror=effc++ flag:
- element_metrics::common_keys - add {} default initializer
- structure_analyzer - add default constructor with member init list
- fractured_formatter - add column_widths_{} to constructor
- fractured_string_builder - add analyzer_{} to constructor

* Add Rule of Five to structure_analyzer class

The class has a pointer member (current_opts_) which triggers
-Werror=effc++ requiring explicit copy/move operations. Delete
copy operations (class shouldn't be copied due to cache) and
default move operations.

* Fix Windows build: wrap std::max to avoid macro conflict

Windows.h defines max/min macros that interfere with std::max/std::min.
Wrapping in parentheses as (std::max)(...) prevents macro expansion.

* Fix GCC 15 false positive -Wfree-nonheap-object warning

GCC 15 on MINGW64 gives a false positive warning in parser_moving_parser()
when the std::vector<std::string> goes out of scope. Suppress this
specific warning with a pragma for GCC builds.

* Fix metrics cache key bug by passing metrics through recursion

The cache was using element addresses as keys, but dom::element objects
are lightweight wrappers that get copied during iteration, causing
different addresses between analysis and formatting phases. This resulted
in cache misses and fallback to empty metrics.

Solution: Store child metrics in the element_metrics struct and pass
them through recursive calls, eliminating the need for address-based
caching entirely.

Changes:
- Add children vector to element_metrics for hierarchical metrics
- Remove metrics_cache_ and related get_metrics/has_metrics methods
- Update all format functions to accept and pass child metrics
- Add public analyze_array/analyze_object overloads for standalone use

* Add ignore patterns for Node.js, Rust, and generated files

Add entries for node_modules, package-lock.json, Rust target
directories, local ablation artifacts, and generated documentation
files.

* Refactor: extract analyze_scalar helper to reduce code duplication

Extract common scalar type handling (STRING, INT64, UINT64, DOUBLE,
BOOL, NULL_VALUE) into a dedicated analyze_scalar method. Each scalar
type shares the same initialization pattern for complexity, child_count,
can_inline, and recommended_layout.

Also simplify boolean formatting in format_scalar to use ternary operator.

* Fix formatting and duplicate error message in amalgamate.py

Reformat cramped is_amalgamator condition to multi-line for readability.
Fix duplicate error message text in _included_filename_root and use
correct variable name (relative_root instead of root).

* Refactor: add count_newlines helper in fractured_json tests

Extract repeated newline counting loop into a reusable static helper
function, used by inline_array_test, inline_object_test, and
expanded_test.

* Revert "Add ignore patterns for Node.js, Rust, and generated files"

This reverts commit 4760ea7cd0.

* various minor changes

---------

Co-authored-by: Daniel Lemire <daniel@lemire.me>
2026-01-20 10:32:24 -05:00
Daniel Lemire 2058b47dfe adding padded string builder (#2592)
* adding padded string builder

* minor rename

* deleting copy constructor

* typo

* [no-ci] tuning documentation.
2026-01-18 20:18:19 -05:00
Daniel Lemire b0486c7fa2 saving. 2026-01-18 11:57:55 -05:00
Daniel Lemire feb1e7feb6 work on the ondemand iterators (#2590)
* work on the ondemand iterators

* guarding two SIMDJSON_ASSUME

* simplify following @jkeiser's comment

* adding safety rails to the iterators

* silencing a warning.

* updating the amalgamation files
2026-01-17 21:15:18 -05:00
Eve Silfanus 2c7fbc1538 Build Performance Optimization (#2588) 2026-01-16 11:42:39 -05:00
Daniel Lemire 8b69401d8a moving the builder files in their own directory (#2578) 2026-01-07 18:08:11 -05:00
Daniel Lemire f504e57e7a Add runtime dispatching for loongarch (#2575)
* loongarch runtime dispatching

* remove CMake config for Loongarch.

* make lasx available

* flipping

* moving...

* fixing minor logic error

* minor fixes

* flipping

* adding hackish header

* better comment and reordering

* adding dispatch
2026-01-02 14:28:23 -05:00
Arthur Chan 135c173053 oss-fuzz: Add unit testing build to oss-fuzz build script (#2574) 2026-01-02 14:28:01 -05:00
Daniel Lemire b4ed3a99a9 fixing typos (#2573) 2025-12-30 17:38:03 -05:00
Daniel Lemire d8e1b36c88 just new small tests. (#2571) 2025-12-23 11:14:09 -05:00
Daniel Lemire c249a1b456 Merge branch 'master' of github.com:simdjson/simdjson 2025-12-22 16:08:30 -05:00
Daniel Lemire 9c4b793c90 adding ref 2025-12-22 16:08:19 -05:00
Daniel Lemire dd92a8414c Add optimization option to pull request template 2025-12-19 23:30:13 -05:00
Dirk Stolle 835bdba123 adjust logo image file names (*_simdjason_* -> *_simdjson_*) (#2569) 2025-12-19 23:21:59 -05:00
Dirk Stolle ad3cd71ca2 fix a few typos (#2568) 2025-12-19 21:56:32 -05:00
Daniel Lemire 860f7e0458 Update logo in README.md 2025-12-17 20:36:08 -05:00
Daniel Lemire 980f2ad3af 4.2.4 v4.2.4 2025-12-17 20:33:11 -05:00
Daniel Lemire 7ad9fe63a6 fixing issue 2549 (#2567)
* fixing issue 2549

* saving.
2025-12-17 20:32:36 -05:00
Daniel Lemire 7987418b1f adding the official simdjson logo files 2025-12-13 12:14:40 -05:00
Daniel Lemire 5e871f6724 improving slightly the documentation. 2025-12-12 19:04:34 -05:00
Daniel Lemire 5d16fd5f31 4.2.3 v4.2.3 2025-12-12 17:51:39 -05:00
Jake S. Del Mastro 4e9ff03af5 Make it possible to provide custom serializers for range types ( (#2550)
If you provide a custom serializer for range types it is currently never used due to the requires clause for string_builder::append with ranges is overly broad
2025-12-12 17:50:52 -05:00
Daniel Lemire aa7489060a Fix typo in bug report template 2025-12-12 15:24:48 -05:00
Daniel Lemire ae32422891 a few additional tests and removing a bad remark in the documentation... 2025-12-03 19:35:18 -05:00
Liqiang TAO 667d0ed3c7 make code branchless (#2546) 2025-11-18 16:57:06 -05:00
Daniel Lemire b1c31b428d update v4.2.2 2025-11-11 14:21:04 -05:00
Daniel Lemire 56ac56ba32 Merge branch 'master' of github.com:simdjson/simdjson 2025-11-11 14:17:08 -05:00
Muhammad Rizal Nurromdhoni 19549c60ec string_builder range-based append fix (#2544)
* Use std::ranges::range_value_t on range

* Add ranges test
2025-11-11 14:15:00 -05:00
Daniel Lemire 16e99f229b Update iterate_many.md for clarity on JSON processing
Clarified the example JSON format and emphasized the need for efficient processing.
2025-11-10 13:49:13 -05:00
Liqiang TAO 21342a4142 Fix some wrong content in doc (#2542) 2025-11-10 11:24:38 -05:00
Daniel Lemire d0e841d3e9 Release Candidate 4.2.2 (#2539)
* adding documentation.

* release candidate
2025-11-06 12:00:21 -05:00
Daniel Lemire a962652ec3 adding documentation. 2025-11-05 11:42:38 -05:00
hiteshmk05 77d73b068a add: windows wstring support for padded_str (#2537)
* add: windows wstring support for padded_str

* add: padded_string::load for wstring windows

* fix: extra space

* change: file path
2025-11-05 11:29:30 -05:00
Daniel Lemire 19ff7a572d adding concept examples to the compile-time JSON. (#2538) 2025-11-04 15:06:40 -05:00
Daniel Lemire 235dbc5369 4.2.1 v4.2.1 2025-11-03 11:04:23 -05:00
Daniel Lemire 2b9c8977af using _json for compile-time JSON strings. (#2536) 2025-11-03 11:03:21 -05:00
Daniel Lemire 3d87bd4abc release 4.2.0 v4.2.0 2025-11-02 16:19:39 -05:00