Skip to content

Commit

Permalink
Omit clones in .[f] |= g.
Browse files Browse the repository at this point in the history
This massively improves the performance of filters such as:

* `reduce range(0; 200000) as $x ({}  ; .[[$x | tostring][]] = $x)`
* `reduce range(0; 200000) as $x ([[]]; .[0] += [$x])`

(We use `[$x | tostring][]` to enable estimation of output elements.)

Before, the complexity of these filters was exponential,
whereas after this change, the complexity is linear.
This is because index-based updates can exploit mutation now.
  • Loading branch information
01mf02 committed Oct 7, 2024
1 parent c83749a commit 0eaa0f0
Showing 1 changed file with 4 additions and 2 deletions.
6 changes: 4 additions & 2 deletions jaq-json/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,8 @@ impl jaq_core::ValT for Val {
};
match o.entry(Rc::clone(i)) {
Occupied(mut e) => {
match f(e.get().clone()).next().transpose()? {
let v = core::mem::replace(e.get_mut(), Self::from(false));
match f(v).next().transpose()? {
Some(y) => e.insert(y),
// this runs in constant time, at the price of
// changing the order of the elements
Expand All @@ -210,7 +211,8 @@ impl jaq_core::ValT for Val {
Err(e) => return opt.fail(self, |_| Exn::from(e)),
};

if let Some(y) = f(a[i].clone()).next().transpose()? {
let x = core::mem::replace(&mut a[i], Self::from(false));
if let Some(y) = f(x).next().transpose()? {
a[i] = y;
} else {
a.remove(i);
Expand Down

0 comments on commit 0eaa0f0

Please sign in to comment.