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
199}199}
200impl StrValue {200impl StrValue {
201 pub fn concat(a: StrValue, b: StrValue) -> Self {201 pub fn concat(a: StrValue, b: StrValue) -> Self {
202 // TODO: benchmark for an optimal value, currently just a arbitrary choice
203 const STRING_EXTEND_THRESHOLD: usize = 100;
204
202 if a.is_empty() {205 if a.is_empty() {
203 b206 b
204 } else if b.is_empty() {207 } else if b.is_empty() {
205 a208 a
206 } else {209 } else if a.len() + b.len() < STRING_EXTEND_THRESHOLD {
210 Self::Flat(format!("{a}{b}").into())
211 } else {
207 let len = a.len() + b.len();212 let len = a.len() + b.len();
208 Self::Tree(Rc::new((a, b, len)))213 Self::Tree(Rc::new((a, b, len)))
209 }214 }
210 }215 }
211 pub fn into_flat(self) -> IStr {216 pub fn into_flat(self) -> IStr {
212 match self {217 #[cold]
213 StrValue::Flat(f) => f,
214 StrValue::Tree(_) => {
215 let mut buf = String::new();
216 self.into_flat_buf(&mut buf);
217 buf.into()
218 }
219 }
220 }
221 fn into_flat_buf(&self, out: &mut String) {218 fn write_buf(s: &StrValue, out: &mut String) {
222 match self {219 match s {
223 StrValue::Flat(f) => out.push_str(f),220 StrValue::Flat(f) => out.push_str(f),
224 StrValue::Tree(t) => {221 StrValue::Tree(t) => {
225 t.0.into_flat_buf(out);222 write_buf(&t.0, out);
226 t.1.into_flat_buf(out);223 write_buf(&t.1, out);
227 }224 }
228 }225 }
229 }226 }
227 match self {
228 StrValue::Flat(f) => f,
229 StrValue::Tree(_) => {
230 let mut buf = String::with_capacity(self.len());
231 write_buf(&self, &mut buf);
232 buf.into()
233 }
234 }
235 }
230 pub fn len(&self) -> usize {236 pub fn len(&self) -> usize {
231 match self {237 match self {
232 StrValue::Flat(v) => v.len(),238 StrValue::Flat(v) => v.len(),
236 pub fn is_empty(&self) -> bool {242 pub fn is_empty(&self) -> bool {
237 match self {243 match self {
238 Self::Flat(v) => v.is_empty(),244 Self::Flat(v) => v.is_empty(),
245 // Can't create non-flat empty string
239 _ => false,246 Self::Tree(_) => false,
240 }247 }
241 }248 }
242}249}