Optimizations for CPU and MCU environments#989
Open
MarcAntoineCRUE wants to merge 2 commits intoDaveGamble:masterfrom
Open
Optimizations for CPU and MCU environments#989MarcAntoineCRUE wants to merge 2 commits intoDaveGamble:masterfrom
MarcAntoineCRUE wants to merge 2 commits intoDaveGamble:masterfrom
Conversation
…optimize number parsing with stack buffer
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
This PR applies five surgical optimizations to cJSON.c,
Changes
1 —
cJSON_Delete(): recursive → iterative traversalFile: cJSON.c ·
cJSON_Delete()Before: The original implementation used implicit recursion through child nodes. Each nesting level consumed a stack frame.
After: Fully iterative using a pointer-threading technique: the sibling chain is appended to the tail of the child chain before descending, eliminating all recursion.
2 —
parse_number(): stack buffer replaces heap allocationFile: cJSON.c ·
parse_number()Before: Every number encountered during parsing triggered a
malloc()+free()to copy the number string before passing it tostrtod().After: A 64-byte stack buffer is used for all valid JSON numbers (max representation is ~25 chars for
±1.7976931348623157e+308). Heap allocation only occurs as a fallback for pathologically long numeric strings.3 —
parse_number(): fast integer path bypassesstrtod()File: cJSON.c ·
parse_number()Before: All numbers, including simple integers like
42or-7, went throughstrtod()— a heavy function that handles locales, state, NaN/Inf detection, and exponent parsing.After: A fast path detects simple integers (no
., noe/E, ≤9 digits) and computes them directly with a digit loop, bypassingstrtod()entirely. All other numeric forms (floats, exponents, large integers) fall through to the originalstrtod()path unchanged.Safety:
NaNandInfinitynever reachparse_number()—parse_value()rejects them at the dispatch stage (neither starts with-or0–9). Floats and exponents are always forwarded tostrtod().4 —
buffer_skip_whitespace(): explicit comparison replacesisspace()File: cJSON.c ·
buffer_skip_whitespace()Before: Used
isspace()— a libc function that internally performs a locale table lookup and function call overhead on every character.After: Explicit comparison against the four whitespace characters defined by the JSON specification (
' ','\t','\r','\n'). This is both correct per spec and faster.5 —
parse_value(): if-else chain →switchdispatchFile: cJSON.c ·
parse_value()Before: Sequential
if/else ifcomparisons testedstrncmp()against"null","true","false", etc., even for common types like strings and numbers.After: A single
switchon the first byte dispatches directly to the correct handler. The compiler generates a jump table; number handling is reached with zero comparisons on common types.