Skip to content

Add YYJSON_WRITE_LOWERCASE_HEX flag for \uXXXX escape case#264

Merged
ibireme merged 1 commit into
ibireme:masterfrom
iliaal:lowercase-hex-escapes
May 11, 2026
Merged

Add YYJSON_WRITE_LOWERCASE_HEX flag for \uXXXX escape case#264
ibireme merged 1 commit into
ibireme:masterfrom
iliaal:lowercase-hex-escapes

Conversation

@iliaal
Copy link
Copy Markdown
Contributor

@iliaal iliaal commented May 10, 2026

Resolves #263.

Both RFC 8259 §7 forms are valid, but several widely-used JSON encoders default to lowercase hex: PHP ext/json, Python json, Node.js JSON.stringify (when it emits \u for control chars), Go encoding/json. yyjson defaults to uppercase. Callers shipping yyjson output to those consumers currently need a post-processing pass for byte-equality.

This flag selects a second pre-computed 512-byte hex table at the top of each writer call; the per-byte hot loop is identical. No performance impact on either path.

Functional test on the patched build:

"Ä" → "Ä" (default)
"Ä" → "Ä" (with YYJSON_WRITE_LOWERCASE_HEX)

Builds clean (CMake Release, gcc 14, no new warnings).

Both RFC 8259 §7 forms are valid, but the rest of the JSON ecosystem
(ext/json, Python json, Node.js JSON.stringify, Go encoding/json,
Ruby json, Jackson, RapidJSON) defaults to lowercase hex. yyjson is
the conspicuous outlier with uppercase. Callers shipping yyjson
output to those consumers currently need a post-processing pass for
byte-equality.

This flag selects a second pre-computed 512-byte hex table at the
top of each writer call; the per-byte hot loop is identical. No
performance impact on either path.

Implementation:
- Add esc_hex_char_table_lower next to the existing uppercase table
- get_hex_table_with_flag() returns the right table based on flag
- write_str() takes hex_table as parameter; threaded through the 5
  write driver functions that call it
- The U+FFFD replacement in the invalid-UTF-8 error path now reads
  its 4 hex bytes from hex_table too (two byte_copy_2 instead of one
  byte_copy_4 from a hardcoded rep v32; same total output, error
  path is not perf-critical)
@codecov
Copy link
Copy Markdown

codecov Bot commented May 11, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.49%. Comparing base (8b4a38d) to head (80a8257).
⚠️ Report is 46 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master     #264      +/-   ##
==========================================
- Coverage   98.50%   98.49%   -0.02%     
==========================================
  Files           2        2              
  Lines        9040     7699    -1341     
==========================================
- Hits         8905     7583    -1322     
+ Misses        135      116      -19     
Flag Coverage Δ
unittests 98.49% <100.00%> (-0.02%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@ibireme
Copy link
Copy Markdown
Owner

ibireme commented May 11, 2026

Thanks! This flag does seem useful, let's merge it first.
I'll also take another look at the performance later, but it seems like the impact should be minimal.

@ibireme ibireme merged commit 95f4c61 into ibireme:master May 11, 2026
45 of 46 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Optional lowercase hex digits in \uXXXX escapes (YYJSON_WRITE_LOWERCASE_HEX)

2 participants