--- a/crates/jrsonnet-evaluator/src/builtin/mod.rs +++ b/crates/jrsonnet-evaluator/src/builtin/mod.rs @@ -11,6 +11,7 @@ }; use crate::{Either, ObjValue}; use format::{format_arr, format_obj}; +use gcmodule::Cc; use jrsonnet_interner::IStr; use serde::Deserialize; use serde_yaml::DeserializingQuirks; @@ -142,11 +143,11 @@ } #[jrsonnet_macros::builtin] -fn builtin_length(x: Either![IStr, VecVal, ObjValue, FuncVal]) -> Result { +fn builtin_length(x: Either![IStr, ArrValue, ObjValue, FuncVal]) -> Result { use Either4::*; Ok(match x { A(x) => x.chars().count(), - B(x) => x.0.len(), + B(x) => x.len(), C(x) => x .fields_visibility() .into_iter() @@ -167,7 +168,7 @@ for i in 0..sz { out.push(func.evaluate_simple(&[i as f64].as_slice())?) } - Ok(VecVal(out)) + Ok(VecVal(Cc::new(out))) } #[jrsonnet_macros::builtin] @@ -178,7 +179,9 @@ #[jrsonnet_macros::builtin] fn builtin_object_fields_ex(obj: ObjValue, inc_hidden: bool) -> Result { let out = obj.fields_ex(inc_hidden); - Ok(VecVal(out.into_iter().map(Val::Str).collect::>())) + Ok(VecVal(Cc::new( + out.into_iter().map(Val::Str).collect::>(), + ))) } #[jrsonnet_macros::builtin] @@ -432,15 +435,11 @@ } #[jrsonnet_macros::builtin] -fn builtin_range(from: i32, to: i32) -> Result { +fn builtin_range(from: i32, to: i32) -> Result { if to < from { - return Ok(VecVal(Vec::new())); + return Ok(ArrValue::new_eager()); } - let mut out = Vec::with_capacity((1 + to as usize - from as usize).max(0)); - for i in from as usize..=to as usize { - out.push(Val::Num(i as f64)); - } - Ok(VecVal(out)) + Ok(ArrValue::new_range(from, to)) } #[jrsonnet_macros::builtin] --- a/crates/jrsonnet-evaluator/src/typed/conversions.rs +++ b/crates/jrsonnet-evaluator/src/typed/conversions.rs @@ -285,7 +285,7 @@ } /// Specialization, provides faster TryFrom for Val -pub struct VecVal(pub Vec); +pub struct VecVal(pub Cc>); impl Typed for VecVal { const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Arr); @@ -296,7 +296,7 @@ fn try_from(value: Val) -> Result { ::TYPE.check(&value)?; match value { - Val::Arr(a) => Ok(Self(a.evaluated()?.to_vec())), + Val::Arr(a) => Ok(Self(a.evaluated()?)), _ => unreachable!(), } } @@ -305,7 +305,7 @@ type Error = LocError; fn try_from(value: VecVal) -> Result { - Ok(Self::Arr(value.0.into())) + Ok(Self::Arr(ArrValue::Eager(value.0))) } } --- a/crates/jrsonnet-evaluator/src/val.rs +++ b/crates/jrsonnet-evaluator/src/val.rs @@ -178,11 +178,17 @@ Lazy(Cc>), Eager(Cc>), Extended(Box<(Self, Self)>), + Range(i32, i32), + Reversed(Box), } impl ArrValue { pub fn new_eager() -> Self { Self::Eager(Cc::new(Vec::new())) } + pub fn new_range(a: i32, b: i32) -> Self { + assert!(a <= b); + Self::Range(a, b) + } pub fn len(&self) -> usize { match self { @@ -190,6 +196,8 @@ Self::Lazy(l) => l.len(), Self::Eager(e) => e.len(), Self::Extended(v) => v.0.len() + v.1.len(), + Self::Range(a, b) => a.abs_diff(*b) as usize, + Self::Reversed(i) => i.len(), } } @@ -218,6 +226,19 @@ v.1.get(index - a_len) } } + Self::Range(a, _) => { + if index >= self.len() { + return Ok(None); + } + Ok(Some(Val::Num(((*a as isize) + index as isize) as f64))) + } + Self::Reversed(v) => { + let len = v.len(); + if index >= len { + return Ok(None); + } + v.get(len - index - 1) + } } } @@ -236,6 +257,21 @@ v.1.get_lazy(index - a_len) } } + Self::Range(a, _) => { + if index >= self.len() { + return None; + } + Some(LazyVal::new_resolved(Val::Num( + ((*a as isize) + index as isize) as f64, + ))) + } + Self::Reversed(v) => { + let len = v.len(); + if index >= len { + return None; + } + v.get_lazy(len - index - 1) + } } } @@ -263,46 +299,50 @@ } Cc::new(out) } + Self::Range(a, b) => { + let mut out = Vec::with_capacity(self.len()); + for i in *a..*b { + out.push(Val::Num(i as f64)); + } + Cc::new(out) + } + Self::Reversed(r) => { + let mut r = r.evaluated()?; + Cc::update_with(&mut r, |v| v.reverse()); + r + } }) } pub fn iter(&self) -> impl DoubleEndedIterator> + '_ { - (0..self.len()).map(move |idx| match self { + // if let Self::Reversed(v) = self { + // return v.iter().rev(); + // } + let len = self.len(); + (0..len).map(move |idx| match self { Self::Bytes(b) => Ok(Val::Num(b[idx] as f64)), Self::Lazy(l) => l[idx].evaluate(), Self::Eager(e) => Ok(e[idx].clone()), Self::Extended(_) => self.get(idx).map(|e| e.unwrap()), + Self::Range(..) => self.get(idx).map(|e| e.unwrap()), + Self::Reversed(..) => self.get(len - idx - 1).map(|e| e.unwrap()), }) } pub fn iter_lazy(&self) -> impl DoubleEndedIterator + '_ { - (0..self.len()).map(move |idx| match self { + let len = self.len(); + (0..len).map(move |idx| match self { Self::Bytes(b) => LazyVal::new_resolved(Val::Num(b[idx] as f64)), Self::Lazy(l) => l[idx].clone(), Self::Eager(e) => LazyVal::new_resolved(e[idx].clone()), Self::Extended(_) => self.get_lazy(idx).unwrap(), + Self::Range(..) => self.get_lazy(idx).unwrap(), + Self::Reversed(..) => self.get_lazy(len - idx - 1).unwrap(), }) } pub fn reversed(self) -> Self { - match self { - Self::Bytes(b) => { - let mut out = b.to_vec(); - out.reverse(); - Self::Bytes(out.into()) - } - Self::Lazy(vec) => { - let mut out = (&vec as &Vec<_>).clone(); - out.reverse(); - Self::Lazy(Cc::new(out)) - } - Self::Eager(vec) => { - let mut out = (&vec as &Vec<_>).clone(); - out.reverse(); - Self::Eager(Cc::new(out)) - } - Self::Extended(b) => Self::Extended(Box::new((b.1.reversed(), b.0.reversed()))), - } + Self::Reversed(Box::new(self)) } pub fn map(self, mapper: impl Fn(Val) -> Result) -> Result {