difftreelog
perf add string extension threshold
in: master
2 files changed
crates/jrsonnet-evaluator/src/evaluate/operator.rsdiffbeforeafterboth24 })24 })25}25}2627/// Arbitrary threshold282629pub 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())),353136 // 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)crates/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,
}
}
}