Files
json/tests/src
Niels Lohmann 06b11f80fd Resume patch operations from the common prefix in constant time per step
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>
2026-11-11 12:42:05 +01:00
..
2026-01-01 20:00:39 +01:00
2026-01-01 20:00:39 +01:00
2026-01-01 20:00:39 +01:00
2026-01-01 20:00:39 +01:00
2026-01-01 20:00:39 +01:00
2026-01-01 20:00:39 +01:00
2026-01-01 20:00:39 +01:00
2026-01-01 20:00:39 +01:00
2026-01-01 20:00:39 +01:00
2026-01-01 20:00:39 +01:00