git.delta.rocks / jrsonnet / refs/commits / 94b99170eb24

difftreelog

perf add string extension threshold

Yaroslav Bolyukin2022-12-03parent: #54c4db5.patch.diff
in: master

2 files changed

modifiedcrates/jrsonnet-evaluator/src/evaluate/operator.rsdiffbeforeafterboth
24 })24 })
25}25}
26
27/// Arbitrary threshold
2826
29pub fn evaluate_add_op(a: &Val, b: &Val) -> Result<Val> {27pub fn evaluate_add_op(a: &Val, b: &Val) -> Result<Val> {
30 use Val::*;28 use Val::*;
31 Ok(match (a, b) {29 Ok(match (a, b) {
32 (Str(a), Str(b)) if a.is_empty() => Val::Str(b.clone()),
33 (Str(a), Str(b)) if b.is_empty() => Val::Str(a.clone()),
34 (Str(v1), Str(v2)) => Str(StrValue::concat(v1.clone(), v2.clone())),30 (Str(v1), Str(v2)) => Str(StrValue::concat(v1.clone(), v2.clone())),
3531
36 // Can't use generic json serialization way, because it depends on number to string concatenation (std.jsonnet:890)32 // Can't use generic json serialization way, because it depends on number to string concatenation (std.jsonnet:890)
modifiedcrates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/val.rs
+++ b/crates/jrsonnet-evaluator/src/val.rs
@@ -199,34 +199,40 @@
 }
 impl StrValue {
 	pub fn concat(a: StrValue, b: StrValue) -> Self {
+		// TODO: benchmark for an optimal value, currently just a arbitrary choice
+		const STRING_EXTEND_THRESHOLD: usize = 100;
+
 		if a.is_empty() {
 			b
 		} else if b.is_empty() {
 			a
+		} else if a.len() + b.len() < STRING_EXTEND_THRESHOLD {
+			Self::Flat(format!("{a}{b}").into())
 		} else {
 			let len = a.len() + b.len();
 			Self::Tree(Rc::new((a, b, len)))
 		}
 	}
 	pub fn into_flat(self) -> IStr {
+		#[cold]
+		fn write_buf(s: &StrValue, out: &mut String) {
+			match s {
+				StrValue::Flat(f) => out.push_str(f),
+				StrValue::Tree(t) => {
+					write_buf(&t.0, out);
+					write_buf(&t.1, out);
+				}
+			}
+		}
 		match self {
 			StrValue::Flat(f) => f,
 			StrValue::Tree(_) => {
-				let mut buf = String::new();
-				self.into_flat_buf(&mut buf);
+				let mut buf = String::with_capacity(self.len());
+				write_buf(&self, &mut buf);
 				buf.into()
 			}
 		}
 	}
-	fn into_flat_buf(&self, out: &mut String) {
-		match self {
-			StrValue::Flat(f) => out.push_str(f),
-			StrValue::Tree(t) => {
-				t.0.into_flat_buf(out);
-				t.1.into_flat_buf(out);
-			}
-		}
-	}
 	pub fn len(&self) -> usize {
 		match self {
 			StrValue::Flat(v) => v.len(),
@@ -236,7 +242,8 @@
 	pub fn is_empty(&self) -> bool {
 		match self {
 			Self::Flat(v) => v.is_empty(),
-			_ => false,
+			// Can't create non-flat empty string
+			Self::Tree(_) => false,
 		}
 	}
 }