Skip to content

Release v1.0.1

Latest

Choose a tag to compare

@RealTimeChris RealTimeChris released this 13 Aug 02:41
· 1 commit to main since this release

Jsonifier v1.0.1 Release Notes

πŸ›οΈ Cathedral-Grade Rewrite: Structural Indices, Bool-Propagating Control Flow, and Full UTF-8 Validation

This release touches nearly every layer of the library β€” parsing, serialization, SIMD backends, containers, and error handling all got rebuilt around a few unifying architectural decisions. It's the largest single-release change set in the project's history.


πŸš€ Highlights

Structural indices replace raw pointers throughout. The structural index array (used by the parser, serializer, minifier, and prettifier alike) now stores uint32_t offsets into the source buffer instead of raw 8-byte pointers. This halves the structural index array's memory footprint and improves cache behavior across every major operation β€” parsing, minifying, prettifying, and serializing.

Parsing, validation, minification, and prettification all now return bool. Every core operation propagates failure immediately via [[likely]]/[[unlikely]]-guarded early returns instead of the old pattern of pushing errors to a side-channel and continuing to parse garbage. This is both a correctness improvement (no more wandering through a broken buffer after the first failure) and a performance one (failed parses bail immediately).

Full UTF-8 validation, on by default. A new Lemire/simdjson-derived UTF-8 validator ships with both a bulk validateUtf8() path and a streaming register-based validator that carries state across chunk boundaries β€” built for validating strings incrementally during parsing rather than requiring the whole buffer up front. parse_options::validateUtf8 defaults to true. Backed by an extensive new test suite covering the full Markus Kuhn UTF-8 stress corpus, alignment-sweep fuzzing, and page-boundary overrun checks via mmap/mprotect.

New SVE2 backend for ARM. Jsonifier now has a full SIMD backend for ARM's SVE2 instruction set, covering both low-level primitives and the higher-level structural/whitespace/string stage1 detection layer. ⚠️ This backend is experimental and not yet fully correct β€” a handful of parsing cases still misbehave under SVE2. Treat it as a preview; NEON remains the recommended path on ARM for production use until this shakes out.

AVX-512 gating tightened. AVX-512 codepaths now require F + BW + VBMI2 support to be detected together, rather than just F β€” a real safety fix for hardware that reports partial AVX-512 support.

PCLMULQDQ detection added, plumbed through CMake and the runtime CPU-feature detector as a new instruction-set flag (JSONIFIER_CLMUL).


🧠 Parser

  • Object member dispatch got a tighter known-order fast path: for minified + known-key-order parsing, key matching now fuses comma + quote + key + quote + colon into a single compile-time literal match instead of checking each punctuation character separately.
  • Vector parsing now parses into a reusable thread-local scratch buffer (reusing existing capacity where possible) and only moves the result into the caller's container once the full parse succeeds β€” avoids reallocation churn and ensures partial failures never leave the destination half-written.
  • Tuple parsing unrolled via fold-expression-based functor_runner instead of deep recursive template instantiation β€” better compile times and codegen on larger tuples.
  • The hash-map fallback path's anti-hash-state cache now only updates on a genuinely successful match, fixing a subtle bug where a failed parse could poison the cache for subsequent lookups.
  • New parse_options fields: maxDepth (default 1024, guards against runaway/malicious nesting) and nullTerminated.
  • The old fully-separate parse_partial_impl template hierarchy has been merged into the main parse_impl specializations, cutting a large amount of duplicated logic.

✍️ Serialization

  • New branchless character-escaping via direct table lookup, replacing the old per-character switch statement.
  • Fixed a real big-endian correctness bug in bool serialization ("true"/"false" packed-integer constants are now computed with explicit endian-aware byte ordering instead of a little-endian-only hardcoded value).
  • indent_table was substantially simplified: a single padded memcpy (with memset overflow handling beyond 8 levels of depth) replaces the old per-depth offset-table lookup, removing a template parameter from every serializer specialization that used it.
  • Tuple serialization unrolled via the same functor_runner pattern as parsing.
  • Single-element raw arrays now skip loop setup entirely via if constexpr.

🧬 SIMD / CPU Detection

  • CPU feature detection was rewritten to emit structured, greppable output (HAS_X=0/1, CPU_MASK=, SVE2_VL_BITS=) instead of an 8-bit exit-code bitmask, and the CMake side now supports proper cross-compilation via a JSONIFIER_CPU_INSTRUCTIONS override.
  • opTest semantics were corrected (previously inverted) β€” this was fixed at every call site, including anyBitsSetAnywhere.
  • New cross-backend operations: opSubs, opPermute, opAlignR, opSrLi, opPrev (cross-register byte-boundary carry, critical for the UTF-8 validator), isAscii, orAll.
  • BMI/LZCNT/POPCNT primitives rewritten to branch per compiler and architecture, always falling back to std::countr_zero/countl_zero/popcount as a safety net.
  • Constexpr evaluation budgets were raised substantially across MSVC, Clang, and GCC to accommodate the heavier compile-time table generation elsewhere in the codebase.

πŸ“¦ Containers

  • Fixed a real bug in jsonifier::internal::array::end() β€” it previously returned the same iterator as begin(), meaning naive iteration never terminated correctly.
  • Fixed array::at() to actually throw std::runtime_error on out-of-bounds access β€” it previously constructed the exception and silently discarded it without throwing.
  • array gained compile-time-constant indexing (bounds-checked at compile time), element-wise operator==/!=, and deduction guides.
  • Allocator rewritten around a self-describing allocation header stored ahead of the returned pointer, replacing size-recomputation-based deallocation. Added a Windows large-page fallback path and a non-AVX aligned-malloc path.

πŸ§ͺ Testing

  • Massive expansion of the unit test suite: nearly every test category now runs across all 8 combinations of partial Γ— knownOrder Γ— nullTerminated.
  • New integration of the external JSONTestSuite conformance corpus (150+ cases).
  • New dedicated test files for error construction/reporting, SIMD intrinsics correctness, and UTF-8 validation (including the full Markus Kuhn stress suite, alignment sweeps, and mmap-based page-boundary fault testing).
  • Fixed a bug in the test runner's main.cpp where a thrown test exception would still result in a 0 (success) process exit code.

⚠️ Breaking Changes

  • jsonifier_core's template parameter changed from a boolean (doWeUseInitialBuffer) to a uint64_t initialBufferSize (default 1MB) β€” buffer size is now directly configurable rather than toggled on/off.
  • The standalone compareJson/json_comparator API has been removed. If you were using struct/document comparison, hold off upgrading until we confirm whether/where this lands.
  • parse_status / validate_status / minify_status / prettify_status enums renamed and renumbered (parse_statuses, etc.), with several new members reflecting new failure modes (exceeded_max_depth, illegal_control_character, unexpected_token, and others).
  • Several public headers were renamed from PascalCase to snake_case (Allocator.hpp β†’ allocator.hpp, Config.hpp β†’ config.hpp, Error.hpp β†’ error.hpp, and many more) β€” update any direct includes accordingly.