From 9af1f59feaabd842dd5802f9c3d0298e33b8a8c4 Mon Sep 17 00:00:00 2001 From: Yaroslav Bolyukin Date: Sat, 08 Apr 2023 18:20:58 +0000 Subject: [PATCH] perf: move std.setInter to native --- --- a/crates/jrsonnet-stdlib/src/lib.rs +++ b/crates/jrsonnet-stdlib/src/lib.rs @@ -42,6 +42,8 @@ pub use misc::*; mod sets; pub use sets::*; +mod compat; +pub use compat::*; pub fn stdlib_uncached(settings: Rc>) -> ObjValue { let mut builder = ObjValueBuilder::new(); @@ -147,6 +149,7 @@ ("endsWith", builtin_ends_with::INST), // Sets ("setMember", builtin_set_member::INST), + ("setInter", builtin_set_inter::INST), ] .iter() .cloned() --- a/crates/jrsonnet-stdlib/src/sets.rs +++ b/crates/jrsonnet-stdlib/src/sets.rs @@ -5,23 +5,27 @@ function::{builtin, FuncVal}, operator::evaluate_compare_op, val::ArrValue, - Val, + Thunk, Val, }; +use jrsonnet_gcmodule::Cc; use jrsonnet_parser::BinaryOpType; #[builtin] #[allow(non_snake_case)] -pub fn builtin_set_member(x: Val, arr: ArrValue, keyF: Option) -> Result { +pub fn builtin_set_member(x: Thunk, arr: ArrValue, keyF: Option) -> Result { let mut low = 0; let mut high = arr.len(); - let keyF = keyF.unwrap_or(FuncVal::Id).into_native::<((Val,), Val)>(); + let keyF = keyF + .unwrap_or(FuncVal::Id) + .into_native::<((Thunk,), Val)>(); let x = keyF(x)?; while low < high { let middle = (high + low) / 2; - match evaluate_compare_op(&arr.get(middle)?.expect("in bounds"), &x, BinaryOpType::Lt)? { + let comp = keyF(arr.get_lazy(middle).expect("in bounds"))?; + match evaluate_compare_op(&comp, &x, BinaryOpType::Lt)? { Ordering::Less => low = middle + 1, Ordering::Equal => return Ok(true), Ordering::Greater => high = middle, @@ -29,3 +33,42 @@ } Ok(false) } + +#[builtin] +#[allow(non_snake_case)] +pub fn builtin_set_inter(a: ArrValue, b: ArrValue, keyF: Option) -> Result { + let mut a = a.iter_lazy(); + let mut b = b.iter_lazy(); + + let keyF = keyF + .unwrap_or(FuncVal::identity()) + .into_native::<((Thunk,), Val)>(); + let keyF = |v| keyF(v); + + let mut av = a.next(); + let mut bv = b.next(); + let mut ak = av.clone().map(keyF).transpose()?; + let mut bk = bv.map(keyF).transpose()?; + + let mut out = Vec::new(); + while let (Some(ac), Some(bc)) = (&ak, &bk) { + match evaluate_compare_op(ac, bc, BinaryOpType::Lt)? { + Ordering::Less => { + av = a.next(); + ak = av.clone().map(keyF).transpose()?; + } + Ordering::Greater => { + bv = b.next(); + bk = bv.map(keyF).transpose()?; + } + Ordering::Equal => { + out.push(av.clone().expect("ak != None => av != None")); + av = a.next(); + ak = av.clone().map(keyF).transpose()?; + bv = b.next(); + bk = bv.map(keyF).transpose()?; + } + }; + } + Ok(ArrValue::lazy(Cc::new(out))) +} --- a/crates/jrsonnet-stdlib/src/std.jsonnet +++ b/crates/jrsonnet-stdlib/src/std.jsonnet @@ -214,19 +214,6 @@ aux(a, b, i, j + 1, acc + [b[j]]) tailstrict; aux(a, b, 0, 0, []), - setInter(a, b, keyF=id):: - local aux(a, b, i, j, acc) = - if i >= std.length(a) || j >= std.length(b) then - acc - else - if keyF(a[i]) == keyF(b[j]) then - aux(a, b, i + 1, j + 1, acc + [a[i]]) tailstrict - else if keyF(a[i]) < keyF(b[j]) then - aux(a, b, i + 1, j, acc) tailstrict - else - aux(a, b, i, j + 1, acc) tailstrict; - aux(a, b, 0, 0, []) tailstrict, - setDiff(a, b, keyF=id):: local aux(a, b, i, j, acc) = if i >= std.length(a) then -- gitstuff