git.delta.rocks / jrsonnet / refs/commits / 4c21363ed30a

difftreelog

perf implement std.{startsWith, endsWith} in native

Yaroslav Bolyukin2022-08-07parent: #a586993.patch.diff
in: master

2 files changed

modifiedcrates/jrsonnet-stdlib/src/lib.rsdiffbeforeafterboth
--- a/crates/jrsonnet-stdlib/src/lib.rs
+++ b/crates/jrsonnet-stdlib/src/lib.rs
@@ -9,9 +9,9 @@
 	error::{Error::*, Result},
 	function::{builtin::Builtin, ArgLike, CallLocation, FuncVal, TlaArg},
 	gc::TraceBox,
-	tb,
+	tb, throw_runtime,
 	typed::{Any, Either, Either2, Either4, VecVal, M1},
-	val::ArrValue,
+	val::{equals, ArrValue},
 	Context, ContextBuilder, IStr, ObjValue, ObjValueBuilder, State, Thunk, Val,
 };
 use jrsonnet_gcmodule::Cc;
@@ -129,6 +129,8 @@
 		("asciiUpper".into(), builtin_ascii_upper::INST),
 		("asciiLower".into(), builtin_ascii_lower::INST),
 		("findSubstr".into(), builtin_find_substr::INST),
+		("startsWith".into(), builtin_starts_with::INST),
+		("endsWith".into(), builtin_ends_with::INST),
 	]
 	.iter()
 	.cloned()
@@ -446,3 +448,68 @@
 	}
 	Ok(out.into())
 }
+
+#[builtin]
+fn builtin_starts_with(
+	s: State,
+	a: Either![IStr, ArrValue],
+	b: Either![IStr, ArrValue],
+) -> Result<bool> {
+	Ok(match (a, b) {
+		(Either2::A(a), Either2::A(b)) => a.starts_with(b.as_str()),
+		(Either2::B(a), Either2::B(b)) => {
+			if b.len() > a.len() {
+				return Ok(false);
+			} else if b.len() == a.len() {
+				return equals(s, &Val::Arr(a), &Val::Arr(b));
+			} else {
+				for (a, b) in a
+					.slice(None, Some(b.len()), None)
+					.iter(s.clone())
+					.zip(b.iter(s.clone()))
+				{
+					let a = a?;
+					let b = b?;
+					if !equals(s.clone(), &a, &b)? {
+						return Ok(false);
+					}
+				}
+				true
+			}
+		}
+		_ => throw_runtime!("both arguments should be of the same type"),
+	})
+}
+
+#[builtin]
+fn builtin_ends_with(
+	s: State,
+	a: Either![IStr, ArrValue],
+	b: Either![IStr, ArrValue],
+) -> Result<bool> {
+	Ok(match (a, b) {
+		(Either2::A(a), Either2::A(b)) => a.ends_with(b.as_str()),
+		(Either2::B(a), Either2::B(b)) => {
+			if b.len() > a.len() {
+				return Ok(false);
+			} else if b.len() == a.len() {
+				return equals(s, &Val::Arr(a), &Val::Arr(b));
+			} else {
+				let a_len = a.len();
+				for (a, b) in a
+					.slice(Some(a_len - b.len()), None, None)
+					.iter(s.clone())
+					.zip(b.iter(s.clone()))
+				{
+					let a = a?;
+					let b = b?;
+					if !equals(s.clone(), &a, &b)? {
+						return Ok(false);
+					}
+				}
+				true
+			}
+		}
+		_ => throw_runtime!("both arguments should be of the same type"),
+	})
+}
modifiedcrates/jrsonnet-stdlib/src/std.jsonnetdiffbeforeafterboth
44
5 thisFile:: error 'std.thisFile is deprecated, to enable its support in jrsonnet - recompile it with "legacy-this-file" support. This will slow down stdlib caching a bit, though',5 thisFile:: error 'std.thisFile is deprecated, to enable its support in jrsonnet - recompile it with "legacy-this-file" support. This will slow down stdlib caching a bit, though',
66
7 toString(a)::7 toString(a):: '' + a,
8 if std.type(a) == 'string' then a else '' + a,
98
10 startsWith(a, b)::
11 if std.length(a) < std.length(b) then
12 false
13 else
14 std.substr(a, 0, std.length(b)) == b,
15
16 endsWith(a, b)::
17 if std.length(a) < std.length(b) then
18 false
19 else
20 std.substr(a, std.length(a) - std.length(b), std.length(b)) == b,
21
22 lstripChars(str, chars)::9 lstripChars(str, chars)::
23 if std.length(str) > 0 && std.member(chars, str[0]) then10 if std.length(str) > 0 && std.member(chars, str[0]) then
24 std.lstripChars(str[1:], chars)11 std.lstripChars(str[1:], chars)