Implement ReerJSONEncoder using yyjson for high-performance JSON encoding#5
Merged
Implement ReerJSONEncoder using yyjson for high-performance JSON encoding#5
Conversation
…ding - Add ReerJSONEncoder with full API parity to Foundation JSONEncoder - Implement JSONEncoderImpl using yyjson mutable document API for JSON tree building - Support all encoding strategies: date, data, key, non-conforming float - Support outputFormatting: prettyPrinted, sortedKeys, withoutEscapingSlashes - Support Int128/UInt128 encoding (Swift 6.0+) - Handle superEncoder, nested containers, redundant key encoding - All 119 encoder tests passing, 531 total tests passing Made-with: Cursor
…tive format - Replace sortMutVal (tree rebuild) with in-place sort via yyjson_mut_obj_clear + re-add - Remove lowercaseUnicodeEscapes post-processing pass (use yyjson native uppercase hex) - Remove addSpaceBeforeColonInPrettyJSON post-processing pass (use yyjson native ": " style) - Update 2 test expectations to match yyjson output format - Eliminates all extra traversals: now only yyjson builds tree + sorts in-place + serializes once Made-with: Cursor
Made-with: Cursor
…Is, nested double fast paths - Replace `as?` type checks with `T.self ==` in generic encode<T> contexts (decoder pattern) - Add wrapGenericEncodable<T> with compile-time type dispatch for all common types - Use yyjson_mut_arr_with_double/sint/uint bulk C APIs for primitive arrays (zero Swift loop) - Add fast paths for [[Double]] and [[[Double]]] (Canada geography killer) - Cover all integer array types: Int8/16/32/64, UInt8/16/32/64, Int, UInt - All 531 tests passing Made-with: Cursor
…bject allocation - Replace sub-encoder creation with _encodeNestedValue() that reuses self via push/pop pattern on codingPath + save/restore of singleValue/array/object - Eliminates ~96.5ns array concat + ~30-50ns class alloc per nested value - Apply same optimization to wrapDateValue, wrapDataValue, wrapStringKeyedDictValue - Twitter: 2.26x → 2.53x, Apache: 1.99x → 2.39x, Random: 1.98x → 2.41x (Foundation=1.00x) - All 119 tests pass
- Remove unnecessary withMemoryRebound in wrapString (Swift auto-bridges UInt8* to Int8* at C boundary) - Cache doc pointer as let field instead of computed property via impl.doc - Cache useDefaultKeys flag at init to skip repeated switch on keyEncodingStrategy - Add _key() fast path that bypasses impl.convertedKey() for default key strategy Random dataset: 2.39x -> 2.53x (+6%), now matches swift-yyjson Twitter: 2.52x -> 2.86x (+13%) Apache: 2.46x -> 2.63x (+7%) All 119 tests passing.
Remove wrapNestedDoubleArray/wrapTripleNestedDoubleArray special cases. These were type-specific optimizations that only benefited the Canada dataset. Multi-dimensional arrays naturally recurse through the encoder and still hit the [Double] bulk fast path at the leaf level. Canada: 10.79x -> 3.56x (still 6.5x faster than swift-yyjson's 0.55x) Other datasets: unaffected
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
ReerJSONEncoderas an API-compatible drop-in replacement for Foundation'sJSONEncoder, powered by yyjson for high-performance JSON encoding.ReerJSONEncoderpublic API (ReerJSONEncoder.swift, 270 lines) and internal encoding implementation (JSONEncoderImpl.swift, 545 lines), with full support for allJSONEncoderoptions (outputFormatting,dateEncodingStrategy,dataEncodingStrategy,keyEncodingStrategy,nonConformingFloatEncodingStrategy,userInfo).T.self ==, bulk yyjson array APIs, reuse encoder inwrapGenericEncodable, in-place sort for sorted keys, and refined container-level optimizations.Differences from Foundation JSONEncoder
\u001f(lowercase)\u001F(uppercase). Both are valid JSON per RFC 8259"key" : value(space before and after colon)"key": value(space after colon only)Changes
Sources/ReerJSON/ReerJSONEncoder.swift— public encoder class with thread-safe option accessorsSources/ReerJSON/JSONEncoderImpl.swift— internal encoder implementation using yyjson C APISources/ReerJSON/Utilities.swift— added shared utility helpersTests/ReerJSONTests/JSONEncoderTests.swift— adapted test suite for ReerJSONEncoderREADME.md— added encoder usage, encoder diff table, marked encoder TODO as doneTest plan
ReerJSONEncodersubstituted forJSONEncoderJSONEncoderMade with Cursor