git.delta.rocks / jrsonnet / refs/commits / 970fbe703e95

difftreelog

perf faster strReplace

Yaroslav Bolyukin2021-01-12parent: #d9acc2c.patch.diff
in: master

2 files changed

modifiedcrates/jrsonnet-evaluator/build.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/build.rs
+++ b/crates/jrsonnet-evaluator/build.rs
@@ -39,7 +39,8 @@
 								name == "escapeStringJson" || name == "equals" ||
 								name == "base64" || name == "foldl" || name == "foldr" ||
 								name == "sortImpl" || name == "format" || name == "range" ||
-								name == "reverse" || name == "slice" || name == "mod"
+								name == "reverse" || name == "slice" || name == "mod" ||
+								name == "strReplace"
 							)
 						})
 						.collect(),
modifiedcrates/jrsonnet-evaluator/src/builtin/mod.rsdiffbeforeafterboth
before · crates/jrsonnet-evaluator/src/builtin/mod.rs
1use crate::{2	equals,3	error::{Error::*, Result},4	evaluate, parse_args, primitive_equals, push, throw,5	typed::CheckType,6	with_state, ArrValue, Context, FuncVal, LazyVal, Val,7};8use format::{format_arr, format_obj};9use jrsonnet_interner::IStr;10use jrsonnet_parser::{ArgsDesc, BinaryOpType, ExprLocation};11use jrsonnet_types::ty;12use std::{collections::HashMap, path::PathBuf, rc::Rc};1314pub mod stdlib;15pub use stdlib::*;1617use self::manifest::{escape_string_json, manifest_json_ex, ManifestJsonOptions, ManifestType};1819pub mod format;20pub mod manifest;21pub mod sort;2223fn std_format(str: IStr, vals: Val) -> Result<Val> {24	push(25		&Some(ExprLocation(Rc::from(PathBuf::from("std.jsonnet")), 0, 0)),26		|| format!("std.format of {}", str),27		|| {28			Ok(match vals {29				Val::Arr(vals) => Val::Str(format_arr(&str, &vals.evaluated()?)?.into()),30				Val::Obj(obj) => Val::Str(format_obj(&str, &obj)?.into()),31				o => Val::Str(format_arr(&str, &[o])?.into()),32			})33		},34	)35}3637type Builtin = fn(context: Context, loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val>;3839type BuiltinsType = HashMap<Box<str>, Builtin>;4041thread_local! {42	static BUILTINS: BuiltinsType = {43		[44			("length".into(), builtin_length as Builtin),45			("type".into(), builtin_type),46			("makeArray".into(), builtin_make_array),47			("codepoint".into(), builtin_codepoint),48			("objectFieldsEx".into(), builtin_object_fields_ex),49			("objectHasEx".into(), builtin_object_has_ex),50			("slice".into(), builtin_slice),51			("primitiveEquals".into(), builtin_primitive_equals),52			("equals".into(), builtin_equals),53			("modulo".into(), builtin_modulo),54			("mod".into(), builtin_mod),55			("floor".into(), builtin_floor),56			("log".into(), builtin_log),57			("pow".into(), builtin_pow),58			("extVar".into(), builtin_ext_var),59			("native".into(), builtin_native),60			("filter".into(), builtin_filter),61			("foldl".into(), builtin_foldl),62			("foldr".into(), builtin_foldr),63			("sortImpl".into(), builtin_sort_impl),64			("format".into(), builtin_format),65			("range".into(), builtin_range),66			("char".into(), builtin_char),67			("encodeUTF8".into(), builtin_encode_utf8),68			("md5".into(), builtin_md5),69			("base64".into(), builtin_base64),70			("trace".into(), builtin_trace),71			("join".into(), builtin_join),72			("escapeStringJson".into(), builtin_escape_string_json),73			("manifestJsonEx".into(), builtin_manifest_json_ex),74			("reverse".into(), builtin_reverse),75			("id".into(), builtin_id),76		].iter().cloned().collect()77	};78}7980fn builtin_length(context: Context, _loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {81	parse_args!(context, "length", args, 1, [82		0, x: ty!((string | object | array));83	], {84		Ok(match x {85			Val::Str(n) => Val::Num(n.chars().count() as f64),86			Val::Arr(a) => Val::Num(a.len() as f64),87			Val::Obj(o) => Val::Num(88				o.fields_visibility()89					.into_iter()90					.filter(|(_k, v)| *v)91					.count() as f64,92			),93			_ => unreachable!(),94		})95	})96}9798fn builtin_type(context: Context, _loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {99	parse_args!(context, "type", args, 1, [100		0, x: ty!(any);101	], {102		Ok(Val::Str(x.value_type().name().into()))103	})104}105106fn builtin_make_array(107	context: Context,108	_loc: &Option<ExprLocation>,109	args: &ArgsDesc,110) -> Result<Val> {111	parse_args!(context, "makeArray", args, 2, [112		0, sz: ty!(BoundedNumber<(Some(0.0)), (None)>) => Val::Num;113		1, func: ty!(function) => Val::Func;114	], {115		let mut out = Vec::with_capacity(sz as usize);116		for i in 0..sz as usize {117			out.push(LazyVal::new_resolved(func.evaluate_values(118				Context::new(),119				&[Val::Num(i as f64)]120			)?))121		}122		Ok(Val::Arr(out.into()))123	})124}125126fn builtin_codepoint(127	context: Context,128	_loc: &Option<ExprLocation>,129	args: &ArgsDesc,130) -> Result<Val> {131	parse_args!(context, "codepoint", args, 1, [132		0, str: ty!(char) => Val::Str;133	], {134		Ok(Val::Num(str.chars().take(1).next().unwrap() as u32 as f64))135	})136}137138fn builtin_object_fields_ex(139	context: Context,140	_loc: &Option<ExprLocation>,141	args: &ArgsDesc,142) -> Result<Val> {143	parse_args!(context, "objectFieldsEx", args, 2, [144		0, obj: ty!(object) => Val::Obj;145		1, inc_hidden: ty!(boolean) => Val::Bool;146	], {147		let mut out = obj.fields_visibility()148			.into_iter()149			.filter(|(_k, v)| *v || inc_hidden)150			.map(|(k, _v)|k)151			.collect::<Vec<_>>();152		out.sort();153		Ok(Val::Arr(out.into_iter().map(Val::Str).collect::<Vec<_>>().into()))154	})155}156157fn builtin_object_has_ex(158	context: Context,159	_loc: &Option<ExprLocation>,160	args: &ArgsDesc,161) -> Result<Val> {162	parse_args!(context, "objectHasEx", args, 3, [163		0, obj: ty!(object) => Val::Obj;164		1, f: ty!(string) => Val::Str;165		2, inc_hidden: ty!(boolean) => Val::Bool;166	], {167		Ok(Val::Bool(168			obj.fields_visibility()169				.into_iter()170				.filter(|(_k, v)| *v || inc_hidden)171				.any(|(k, _v)| *k == *f),172		))173	})174}175176// faster177fn builtin_slice(context: Context, _loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {178	parse_args!(context, "slice", args, 4, [179		0, indexable: ty!((string | array));180		1, index: ty!((number | null));181		2, end: ty!((number | null));182		3, step: ty!((number | null));183	], {184		let index = match index {185			Val::Num(v) => v as usize,186			Val::Null => 0,187			_ => unreachable!(),188		};189		let end = match end {190			Val::Num(v) => v as usize,191			Val::Null => match &indexable {192				Val::Str(s) => s.chars().count(),193				Val::Arr(v) => v.len(),194				_ => unreachable!()195			},196			_ => unreachable!()197		};198		let step = match step {199			Val::Num(v) => v as usize,200			Val::Null => 1,201			_ => unreachable!()202		};203		match &indexable {204			Val::Str(s) => {205				Ok(Val::Str((s.chars().skip(index).take(end-index).step_by(step).collect::<String>()).into()))206			}207			Val::Arr(arr) => {208				Ok(Val::Arr((arr.iter().skip(index).take(end-index).step_by(step).collect::<Result<Vec<Val>>>()?).into()))209			}210			_ => unreachable!()211		}212	})213}214215// faster216fn builtin_primitive_equals(217	context: Context,218	_loc: &Option<ExprLocation>,219	args: &ArgsDesc,220) -> Result<Val> {221	parse_args!(context, "primitiveEquals", args, 2, [222		0, a: ty!(any);223		1, b: ty!(any);224	], {225		Ok(Val::Bool(primitive_equals(&a, &b)?))226	})227}228229// faster230fn builtin_equals(context: Context, _loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {231	parse_args!(context, "equals", args, 2, [232		0, a: ty!(any);233		1, b: ty!(any);234	], {235		Ok(Val::Bool(equals(&a, &b)?))236	})237}238239fn builtin_modulo(context: Context, _loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {240	parse_args!(context, "modulo", args, 2, [241		0, a: ty!(number) => Val::Num;242		1, b: ty!(number) => Val::Num;243	], {244		Ok(Val::Num(a % b))245	})246}247248fn builtin_mod(context: Context, _loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {249	parse_args!(context, "mod", args, 2, [250		0, a: ty!((number | string));251		1, b: ty!(any);252	], {253		match (a, b) {254			(Val::Num(a), Val::Num(b)) => Ok(Val::Num(a % b)),255			(Val::Str(str), vals) => std_format(str, vals),256			(a, b) => throw!(BinaryOperatorDoesNotOperateOnValues(BinaryOpType::Mod, a.value_type(), b.value_type()))257		}258	})259}260261fn builtin_floor(context: Context, _loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {262	parse_args!(context, "floor", args, 1, [263		0, x: ty!(number) => Val::Num;264	], {265		Ok(Val::Num(x.floor()))266	})267}268269fn builtin_log(context: Context, _loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {270	parse_args!(context, "log", args, 1, [271		0, n: ty!(number) => Val::Num;272	], {273		Ok(Val::Num(n.ln()))274	})275}276277fn builtin_pow(context: Context, _loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {278	parse_args!(context, "pow", args, 2, [279		0, x: ty!(number) => Val::Num;280		1, n: ty!(number) => Val::Num;281	], {282		Ok(Val::Num(x.powf(n)))283	})284}285286fn builtin_ext_var(context: Context, _loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {287	parse_args!(context, "extVar", args, 1, [288		0, x: ty!(string) => Val::Str;289	], {290		Ok(with_state(|s| s.settings().ext_vars.get(&x).cloned()).ok_or(UndefinedExternalVariable(x))?)291	})292}293294fn builtin_native(context: Context, _loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {295	parse_args!(context, "native", args, 1, [296		0, x: ty!(string) => Val::Str;297	], {298		Ok(with_state(|s| s.settings().ext_natives.get(&x).cloned()).map(|v| Val::Func(Rc::new(FuncVal::NativeExt(x.clone(), v)))).ok_or(UndefinedExternalFunction(x))?)299	})300}301302fn builtin_filter(context: Context, _loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {303	parse_args!(context, "filter", args, 2, [304		0, func: ty!(function) => Val::Func;305		1, arr: ty!(array) => Val::Arr;306	], {307		let mut out = Vec::new();308		for item in arr.iter() {309			let item = item?;310			if func311						.evaluate_values(context.clone(), &[item.clone()])?312						.try_cast_bool("filter predicate")? {313							out.push(item);314						}315		}316		Ok(Val::Arr(out.into()))317	})318}319320fn builtin_foldl(context: Context, _loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {321	parse_args!(context, "foldl", args, 3, [322		0, func: ty!(function) => Val::Func;323		1, arr: ty!(array) => Val::Arr;324		2, init: ty!(any);325	], {326		let mut acc = init;327		for i in arr.iter() {328			acc = func.evaluate_values(context.clone(), &[acc, i?])?;329		}330		Ok(acc)331	})332}333334fn builtin_foldr(context: Context, _loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {335	parse_args!(context, "foldr", args, 3, [336		0, func: ty!(function) => Val::Func;337		1, arr: ty!(array) => Val::Arr;338		2, init: ty!(any);339	], {340		let mut acc = init;341		for i in arr.iter().rev() {342			acc = func.evaluate_values(context.clone(), &[acc, i?])?;343		}344		Ok(acc)345	})346}347348#[allow(non_snake_case)]349fn builtin_sort_impl(350	context: Context,351	_loc: &Option<ExprLocation>,352	args: &ArgsDesc,353) -> Result<Val> {354	parse_args!(context, "sort", args, 2, [355		0, arr: ty!(array) => Val::Arr;356		1, keyF: ty!(function) => Val::Func;357	], {358		if arr.len() <= 1 {359			return Ok(Val::Arr(arr))360		}361		Ok(Val::Arr(ArrValue::Eager(sort::sort(context, arr.evaluated()?, &keyF)?)))362	})363}364365// faster366fn builtin_format(context: Context, _loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {367	parse_args!(context, "format", args, 2, [368		0, str: ty!(string) => Val::Str;369		1, vals: ty!(any)370	], {371		std_format(str, vals)372	})373}374375fn builtin_range(context: Context, _loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {376	parse_args!(context, "range", args, 2, [377		0, from: ty!(number) => Val::Num;378		1, to: ty!(number) => Val::Num;379	], {380		let mut out = Vec::with_capacity((1+to as usize-from as usize).max(0));381		for i in from as usize..=to as usize {382			out.push(Val::Num(i as f64));383		}384		Ok(Val::Arr(out.into()))385	})386}387388fn builtin_char(context: Context, _loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {389	parse_args!(context, "char", args, 1, [390		0, n: ty!(number) => Val::Num;391	], {392		let mut out = String::new();393		out.push(std::char::from_u32(n as u32).ok_or_else(||394			InvalidUnicodeCodepointGot(n as u32)395		)?);396		Ok(Val::Str(out.into()))397	})398}399400fn builtin_encode_utf8(401	context: Context,402	_loc: &Option<ExprLocation>,403	args: &ArgsDesc,404) -> Result<Val> {405	parse_args!(context, "encodeUTF8", args, 1, [406		0, str: ty!(string) => Val::Str;407	], {408		Ok(Val::Arr((str.bytes().map(|b| Val::Num(b as f64)).collect::<Vec<Val>>()).into()))409	})410}411412fn builtin_md5(context: Context, _loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {413	parse_args!(context, "md5", args, 1, [414		0, str: ty!(string) => Val::Str;415	], {416		Ok(Val::Str(format!("{:x}", md5::compute(&str.as_bytes())).into()))417	})418}419420fn builtin_trace(context: Context, loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {421	parse_args!(context, "trace", args, 2, [422		0, str: ty!(string) => Val::Str;423		1, rest: ty!(any);424	], {425		eprint!("TRACE:");426		if let Some(loc) = loc {427			with_state(|s|{428				let locs = s.map_source_locations(&loc.0, &[loc.1]);429				eprint!(" {}:{}", loc.0.file_name().unwrap().to_str().unwrap(), locs[0].line);430			});431		}432		eprintln!(" {}", str);433		Ok(rest)434	})435}436437fn builtin_base64(context: Context, _loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {438	parse_args!(context, "base64", args, 1, [439		0, input: ty!((string | (Array<number>)));440	], {441		Ok(Val::Str(match input {442			Val::Str(s) => {443				base64::encode(s.bytes().collect::<Vec<_>>()).into()444			},445			Val::Arr(a) => {446				base64::encode(a.iter().map(|v| {447					Ok(v?.clone().unwrap_num()? as u8)448				}).collect::<Result<Vec<_>>>()?).into()449			},450			_ => unreachable!()451		}))452	})453}454455456fn builtin_join(context: Context, _loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {457	parse_args!(context, "join", args, 2, [458		0, sep: ty!((string | array));459		1, arr: ty!(array) => Val::Arr;460	], {461		Ok(match sep {462			Val::Arr(joiner_items) => {463				let mut out = Vec::new();464465				let mut first = true;466				for item in arr.iter() {467					let item = item?.clone();468					if let Val::Arr(items) = item {469						if !first {470							out.reserve(joiner_items.len());471							// TODO: extend472							for item in joiner_items.iter() {473								out.push(item?);474							}475						}476						first = false;477						out.reserve(items.len());478						// TODO: extend479						for item in items.iter() {480							out.push(item?);481						}482					} else {483						throw!(RuntimeError("in std.join all items should be arrays".into()));484					}485				}486487				Val::Arr(out.into())488			},489			Val::Str(sep) => {490				let mut out = String::new();491492				let mut first = true;493				for item in arr.iter() {494					let item = item?.clone();495					if let Val::Str(item) = item {496						if !first {497							out += &sep;498						}499						first = false;500						out += &item;501					} else {502						throw!(RuntimeError("in std.join all items should be strings".into()));503					}504				}505506				Val::Str(out.into())507			},508			_ => unreachable!()509		})510	})511}512513// faster514fn builtin_escape_string_json(515	context: Context,516	_loc: &Option<ExprLocation>,517	args: &ArgsDesc,518) -> Result<Val> {519	parse_args!(context, "escapeStringJson", args, 1, [520		0, str_: ty!(string) => Val::Str;521	], {522		Ok(Val::Str(escape_string_json(&str_).into()))523	})524}525526// faster527fn builtin_manifest_json_ex(528	context: Context,529	_loc: &Option<ExprLocation>,530	args: &ArgsDesc,531) -> Result<Val> {532	parse_args!(context, "manifestJsonEx", args, 2, [533		0, value: ty!(any);534		1, indent: ty!(string) => Val::Str;535	], {536		Ok(Val::Str(manifest_json_ex(&value, &ManifestJsonOptions {537			padding: &indent,538			mtype: ManifestType::Std,539		})?.into()))540	})541}542543// faster544fn builtin_reverse(context: Context, _loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {545	parse_args!(context, "reverse", args, 1, [546		0, value: ty!(array) => Val::Arr;547	], {548		Ok(Val::Arr(value.reversed()))549	})550}551552fn builtin_id(context: Context, _loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {553	parse_args!(context, "id", args, 1, [554		0, v: ty!(any);555	], {556		Ok(v)557	})558}559560#[allow(clippy::cognitive_complexity)]561pub fn call_builtin(562	context: Context,563	loc: &Option<ExprLocation>,564	name: &str,565	args: &ArgsDesc,566) -> Result<Val> {567	if let Some(f) = BUILTINS.with(|builtins| builtins.get(name).map(|f| *f)) {568		return Ok(f(context, loc, args)?);569	}570	throw!(IntrinsicNotFound(name.into()))571}