Fix accidentally quadratic behavior in _modify
We need to be careful to not grab an extra reference when mutating data structures because that means we make extra copies. Doing that every time in `_modify` is really painful, as that function implements `|=` and all modify-assign operators. `jv_setpath()` also grabs additional references, so this is not the only fix needed for the modify-assign operators to not be accidentally quadratic. We have to use `LOADVN` in order to make this fix possible, so we should really byte-code `_modify` rather than jq-code it. However, as a stop-gap to make this fix easier, I'm adding syntax for referring to a `$binding` such that you get `LOADVN` instead of `LOADV`. This syntax is not meant to be used outside jq's internals! Therefore it is not documented. I promise to break it later, so don't use it! TBD, but later: - Optimize `_modify` for the case where `update` outputs more than one value. This is trivial: add a `setpath($p; null)` in the middle of `_modify` before calling `update`. But unfortunately the VM retains a reference to `value_at_path` for path expression checking, and fixing that will require more work.
This commit is contained in:
1 parent
0c3455d329
commit
a9f97e9e61
4 files changed
+1163
-1143
No files matched your search
+19
-1
@@ -11,7 +11,25 @@ def min_by(f): _min_by_impl(map([f]));
|
||||
def add: reduce .[] as $x (null; . + $x);
|
||||
def del(f): delpaths([path(f)]);
|
||||
def _assign(paths; $value): reduce path(paths) as $p (.; setpath($p; $value));
|
||||
def _modify(paths; update): reduce path(paths) as $p (.; label $out | (setpath($p; getpath($p) | update) | ., break $out), delpaths([$p]));
|
||||
def _modify(paths; update):
|
||||
reduce path(paths) as $p (.;
|
||||
. as $dot
|
||||
| null
|
||||
| label $out
|
||||
| ($dot | getpath($p)) as $v
|
||||
| (
|
||||
( $$$$v
|
||||
| update
|
||||
| (., break $out) as $v
|
||||
| $$$$dot
|
||||
| setpath($p; $v)
|
||||
),
|
||||
(
|
||||
$$$$dot
|
||||
| delpaths([$p])
|
||||
)
|
||||
)
|
||||
);
|
||||
def map_values(f): .[] |= f;
|
||||
|
||||
# recurse
|
||||
|
||||
Reference in new issue
Block a user