mirror of
https://github.com/nlohmann/json.git
synced 2026-11-14 03:18:20 +00:00
patch() and patch_inplace() keep the values along the previously resolved pointer, so that the next operation resumes from the prefix the two paths have in common. To find the resume point, each cached step was tested from the deepest upwards with a memcmp over its whole prefix. If two paths shared a prefix and the previous path continued for D more tokens, the search compared D prefixes of that length: for two "test" operations whose paths share n tokens and continue for n more, the time was quadratic in n (3.12.0 was linear). With more than 16 cached steps, the length of the common prefix of the two paths is now computed once, and the deepest cached step that ends within it, at a token boundary of the new path, is taken. Steps that are skipped are dropped from the cache, so the search is amortized constant per token. With fewer steps, which is the usual case, they are compared as before, as that is cheaper for short paths. The operations, and which values stay valid after them, are unchanged. Measurements (Apple clang -O2, arm64), patch_inplace() of two "test" operations whose paths share n tokens and continue for n more: n 25k 50k 100k 200k before 42 ms 182 ms 1194 ms 5433 ms after 0 ms 2 ms 4 ms 8 ms 3.12.0 3 ms 5 ms 10 ms 19 ms Patches of ordinary documents (diff() then patch(), and many short operations): within 0.5 % of before in instructions retired (canada, citm_catalog, twitter, mesh, update-center, many short synthetic operations). Signed-off-by: Niels Lohmann <mail@nlohmann.me>