summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCole Faust <colecfaust@gmail.com>2024-01-21 21:22:15 -0800
committerEvan Martin <evan.martin@gmail.com>2024-01-25 00:30:16 -0800
commita0e37e96a75f373bd85de0ffda324a8a64f4f6cb (patch)
tree0a1a9d218ef8312629b4e00298eb06cdbcee629d
parentc90437e5024789e90b221589dff73f2997f91532 (diff)
downloadn2-a0e37e96a75f373bd85de0ffda324a8a64f4f6cb.tar.gz
Precalcuate length of evaluated strings
So that we can do one memory allocation for them.
-rw-r--r--src/eval.rs18
1 files changed, 18 insertions, 0 deletions
diff --git a/src/eval.rs b/src/eval.rs
index 5adf6ce..4b711c5 100644
--- a/src/eval.rs
+++ b/src/eval.rs
@@ -47,6 +47,23 @@ impl<T: AsRef<str>> EvalString<T> {
}
}
+ fn calc_evaluated_length(&self, envs: &[&dyn Env]) -> usize {
+ self.0
+ .iter()
+ .map(|part| match part {
+ EvalPart::Literal(s) => s.as_ref().len(),
+ EvalPart::VarRef(v) => {
+ for (i, env) in envs.iter().enumerate() {
+ if let Some(v) = env.get_var(v.as_ref()) {
+ return v.calc_evaluated_length(&envs[i + 1..]);
+ }
+ }
+ 0
+ }
+ })
+ .sum()
+ }
+
/// evalulate turns the EvalString into a regular String, looking up the
/// values of variable references in the provided Envs. It will look up
/// its variables in the earliest Env that has them, and then those lookups
@@ -54,6 +71,7 @@ impl<T: AsRef<str>> EvalString<T> {
/// had the first successful lookup.
pub fn evaluate(&self, envs: &[&dyn Env]) -> String {
let mut result = String::new();
+ result.reserve(self.calc_evaluated_length(envs));
self.evaluate_inner(&mut result, envs);
result
}