Skip to content

Commit

Permalink
perf: move more stdlib functions to native
Browse files Browse the repository at this point in the history
  • Loading branch information
CertainLach committed Aug 13, 2023
1 parent 218d8cc commit 89a6508
Show file tree
Hide file tree
Showing 7 changed files with 146 additions and 63 deletions.
28 changes: 28 additions & 0 deletions crates/jrsonnet-stdlib/src/arrays.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,15 @@ pub fn builtin_filter(func: FuncVal, arr: ArrValue) -> Result<ArrValue> {
arr.filter(|val| bool::from_untyped(func.evaluate_simple(&(val.clone(),), false)?))
}

#[builtin]
pub fn builtin_filter_map(
filter_func: FuncVal,
map_func: FuncVal,
arr: ArrValue,
) -> Result<ArrValue> {
Ok(builtin_filter(filter_func, arr)?.map(map_func))
}

#[builtin]
pub fn builtin_foldl(func: FuncVal, arr: ArrValue, init: Val) -> Result<Val> {
let mut acc = init;
Expand Down Expand Up @@ -274,3 +283,22 @@ pub fn builtin_remove(arr: ArrValue, elem: Val) -> Result<ArrValue> {
}
Ok(arr)
}

#[builtin]
pub fn builtin_flatten_arrays(arrs: Vec<ArrValue>) -> ArrValue {
pub fn flatten_inner(values: &[ArrValue]) -> ArrValue {
if values.len() == 1 {
return values[0].clone();
} else if values.len() == 2 {
return ArrValue::extended(values[0].clone(), values[1].clone());
}
let (a, b) = values.split_at(values.len() / 2);
ArrValue::extended(flatten_inner(a), flatten_inner(b))
}
if arrs.is_empty() {
return ArrValue::empty();
} else if arrs.len() == 1 {
return arrs.into_iter().next().expect("single");
}
flatten_inner(&arrs)
}
25 changes: 15 additions & 10 deletions crates/jrsonnet-stdlib/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ pub fn stdlib_uncached(settings: Rc<RefCell<Settings>>) -> ObjValue {
("avg", builtin_avg::INST),
("removeAt", builtin_remove_at::INST),
("remove", builtin_remove::INST),
("flattenArrays", builtin_flatten_arrays::INST),
("filterMap", builtin_filter_map::INST),
// Math
("abs", builtin_abs::INST),
("sign", builtin_sign::INST),
Expand Down Expand Up @@ -137,17 +139,22 @@ pub fn stdlib_uncached(settings: Rc<RefCell<Settings>>) -> ObjValue {
("base64DecodeBytes", builtin_base64_decode_bytes::INST),
// Objects
("objectFieldsEx", builtin_object_fields_ex::INST),
("objectFields", builtin_object_fields::INST),
("objectFieldsAll", builtin_object_fields_all::INST),
("objectValues", builtin_object_values::INST),
("objectValuesAll", builtin_object_values_all::INST),
("objectKeysValues", builtin_object_keys_values::INST),
("objectKeysValuesAll", builtin_object_keys_values_all::INST),
("objectHasEx", builtin_object_has_ex::INST),
("objectHas", builtin_object_has::INST),
("objectHasAll", builtin_object_has_all::INST),
("objectRemoveKey", builtin_object_remove_key::INST),
// Manifest
("escapeStringJson", builtin_escape_string_json::INST),
("manifestJsonEx", builtin_manifest_json_ex::INST),
("manifestYamlDoc", builtin_manifest_yaml_doc::INST),
("manifestTomlEx", builtin_manifest_toml_ex::INST),
("toString", builtin_to_string::INST),
// Parsing
("parseJson", builtin_parse_json::INST),
("parseYaml", builtin_parse_yaml::INST),
Expand All @@ -167,6 +174,7 @@ pub fn stdlib_uncached(settings: Rc<RefCell<Settings>>) -> ObjValue {
("bigint", builtin_bigint::INST),
("parseOctal", builtin_parse_octal::INST),
("parseHex", builtin_parse_hex::INST),
("stringChars", builtin_string_chars::INST),
// Misc
("length", builtin_length::INST),
("startsWith", builtin_starts_with::INST),
Expand All @@ -175,6 +183,7 @@ pub fn stdlib_uncached(settings: Rc<RefCell<Settings>>) -> ObjValue {
("setMember", builtin_set_member::INST),
("setInter", builtin_set_inter::INST),
("setDiff", builtin_set_diff::INST),
("setUnion", builtin_set_union::INST),
// Compat
("__compare", builtin___compare::INST),
]
Expand Down Expand Up @@ -347,19 +356,15 @@ impl jrsonnet_evaluator::ContextInitializer for ContextInitializer {

let mut std = ObjValueBuilder::new();
std.with_super(self.stdlib_obj.clone());
std.field("thisFile".into())
std.field("thisFile")
.hide()
.value(Val::string(match source.source_path().path() {
Some(p) => self.settings().path_resolver.resolve(p).into(),
None => source.source_path().to_string().into(),
}))
.expect("this object builder is empty");
.value(match source.source_path().path() {
Some(p) => self.settings().path_resolver.resolve(p),
None => source.source_path().to_string(),
});
let stdlib_with_this_file = std.build();

builder.bind(
"std".into(),
Thunk::evaluated(Val::Obj(stdlib_with_this_file)),
);
builder.bind("std", Thunk::evaluated(Val::Obj(stdlib_with_this_file)));
}
fn as_any(&self) -> &dyn std::any::Any {
self
Expand Down
5 changes: 5 additions & 0 deletions crates/jrsonnet-stdlib/src/manifest/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,8 @@ pub fn builtin_manifest_toml_ex(
preserve_order.unwrap_or(false),
))
}

#[builtin]
pub fn builtin_to_string(a: Val) -> Result<IStr> {
a.to_string()
}
43 changes: 38 additions & 5 deletions crates/jrsonnet-stdlib/src/objects.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use jrsonnet_evaluator::{
function::builtin,
val::{ArrValue, StrValue, Val},
val::{ArrValue, Val},
IStr, ObjValue, ObjValueBuilder,
};

Expand All @@ -17,10 +17,33 @@ pub fn builtin_object_fields_ex(
#[cfg(feature = "exp-preserve-order")]
preserve_order,
);
out.into_iter()
.map(StrValue::Flat)
.map(Val::Str)
.collect::<Vec<_>>()
out.into_iter().map(Val::string).collect::<Vec<_>>()
}

#[builtin]
pub fn builtin_object_fields(
o: ObjValue,
#[cfg(feature = "exp-preserve-order")] preserve_order: Option<bool>,
) -> Vec<Val> {
builtin_object_fields_ex(
o,
false,
#[cfg(feature = "exp-preserve-order")]
preserve_order,
)
}

#[builtin]
pub fn builtin_object_fields_all(
o: ObjValue,
#[cfg(feature = "exp-preserve-order")] preserve_order: Option<bool>,
) -> Vec<Val> {
builtin_object_fields_ex(
o,
true,
#[cfg(feature = "exp-preserve-order")]
preserve_order,
)
}

pub fn builtin_object_values_ex(
Expand Down Expand Up @@ -104,6 +127,16 @@ pub fn builtin_object_has_ex(obj: ObjValue, fname: IStr, hidden: bool) -> bool {
obj.has_field_ex(fname, hidden)
}

#[builtin]
pub fn builtin_object_has(o: ObjValue, f: IStr) -> bool {
o.has_field(f)
}

#[builtin]
pub fn builtin_object_has_all(o: ObjValue, f: IStr) -> bool {
o.has_field_include_hidden(f)
}

#[builtin]
pub fn builtin_object_remove_key(
obj: ObjValue,
Expand Down
55 changes: 55 additions & 0 deletions crates/jrsonnet-stdlib/src/sets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ pub fn builtin_set_inter(a: ArrValue, b: ArrValue, keyF: Option<FuncVal>) -> Res
}
Ok(ArrValue::lazy(out))
}

#[builtin]
#[allow(non_snake_case, clippy::redundant_closure)]
pub fn builtin_set_diff(a: ArrValue, b: ArrValue, keyF: Option<FuncVal>) -> Result<ArrValue> {
Expand Down Expand Up @@ -115,3 +116,57 @@ pub fn builtin_set_diff(a: ArrValue, b: ArrValue, keyF: Option<FuncVal>) -> Resu
}
Ok(ArrValue::lazy(out))
}

#[builtin]
#[allow(non_snake_case, clippy::redundant_closure)]
pub fn builtin_set_union(a: ArrValue, b: ArrValue, keyF: Option<FuncVal>) -> Result<ArrValue> {
let mut a = a.iter_lazy();
let mut b = b.iter_lazy();

let keyF = keyF
.unwrap_or(FuncVal::identity())
.into_native::<((Thunk<Val>,), 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.clone().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 => {
out.push(av.clone().expect("ak != None"));
av = a.next();
ak = av.clone().map(keyF).transpose()?;
}
Ordering::Greater => {
out.push(bv.clone().expect("bk != None"));
bv = b.next();
bk = bv.clone().map(keyF).transpose()?;
}
Ordering::Equal => {
// NOTE: order matters, values in `a` win
out.push(av.clone().expect("ak != None"));
av = a.next();
ak = av.clone().map(keyF).transpose()?;
bv = b.next();
bk = bv.clone().map(keyF).transpose()?;
}
};
}
// a.len() > b.len()
while let Some(_ac) = &ak {
out.push(av.clone().expect("ak != None"));
av = a.next();
ak = av.clone().map(keyF).transpose()?;
}
// b.len() > a.len()
while let Some(_bc) = &bk {
out.push(bv.clone().expect("ak != None"));
bv = b.next();
bk = bv.clone().map(keyF).transpose()?;
}
Ok(ArrValue::lazy(out))
}
48 changes: 0 additions & 48 deletions crates/jrsonnet-stdlib/src/std.jsonnet
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@

thisFile:: error 'std.thisFile is deprecated, to enable its support in jrsonnet - recompile it with "legacy-this-file" support.\nThis will slow down stdlib caching a bit, though',

toString(a):: '' + a,

lstripChars(str, chars)::
if std.length(str) > 0 && std.member(chars, str[0]) then
std.lstripChars(str[1:], chars)
Expand All @@ -22,9 +20,6 @@
stripChars(str, chars)::
std.lstripChars(std.rstripChars(str, chars), chars),

stringChars(str)::
std.makeArray(std.length(str), function(i) str[i]),

splitLimitR(str, c, maxsplits)::
if maxsplits == -1 then
std.splitLimit(str, c, -1)
Expand Down Expand Up @@ -61,16 +56,6 @@
else
error 'Expected string or array, got %s' % std.type(arr),

filterMap(filter_func, map_func, arr)::
if !std.isFunction(filter_func) then
error ('std.filterMap first param must be function, got ' + std.type(filter_func))
else if !std.isFunction(map_func) then
error ('std.filterMap second param must be function, got ' + std.type(map_func))
else if !std.isArray(arr) then
error ('std.filterMap third param must be array, got ' + std.type(arr))
else
std.map(map_func, std.filter(filter_func, arr)),

assertEqual(a, b)::
if a == b then
true
Expand All @@ -82,9 +67,6 @@
else if x > maxVal then maxVal
else x,

flattenArrays(arrs)::
std.foldl(function(a, b) a + b, arrs, []),

manifestIni(ini)::
local body_lines(body) =
std.join([], [
Expand Down Expand Up @@ -196,24 +178,6 @@

aux(value),

setUnion(a, b, keyF=id)::
// NOTE: order matters, values in `a` win
local aux(a, b, i, j, acc) =
if i >= std.length(a) then
acc + b[j:]
else if j >= std.length(b) then
acc + a[i:]
else
local ak = keyF(a[i]);
local bk = keyF(b[j]);
if ak == bk then
aux(a, b, i + 1, j + 1, acc + [a[i]]) tailstrict
else if ak < bk then
aux(a, b, i + 1, j, acc + [a[i]]) tailstrict
else
aux(a, b, i, j + 1, acc + [b[j]]) tailstrict;
aux(a, b, 0, 0, []),

mergePatch(target, patch)::
if std.isObject(patch) then
local target_object =
Expand Down Expand Up @@ -241,18 +205,6 @@
get(o, f, default=null, inc_hidden=true)::
if std.objectHasEx(o, f, inc_hidden) then o[f] else default,

objectFields(o)::
std.objectFieldsEx(o, false),

objectFieldsAll(o)::
std.objectFieldsEx(o, true),

objectHas(o, f)::
std.objectHasEx(o, f, false),

objectHasAll(o, f)::
std.objectHasEx(o, f, true),

resolvePath(f, r)::
local arr = std.split(f, '/');
std.join('/', std.makeArray(std.length(arr) - 1, function(i) arr[i]) + [r]),
Expand Down
5 changes: 5 additions & 0 deletions crates/jrsonnet-stdlib/src/strings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,3 +198,8 @@ mod tests {
assert_eq!(parse_nat::<16>("BbC").unwrap(), 0xBBC as f64);
}
}

#[builtin]
pub fn builtin_string_chars(str: IStr) -> ArrValue {
ArrValue::chars(str.chars())
}

0 comments on commit 89a6508

Please sign in to comment.