difftreelog
perf lazy slice
in: master
5 files changed
crates/jrsonnet-evaluator/src/builtin/mod.rsdiffbeforeafterboth434344pub fn std_slice(44pub fn std_slice(45 indexable: IndexableVal,45 indexable: IndexableVal,46 index: Option<usize>,46 index: Option<BoundedUsize<0, { i32::MAX as usize }>>,47 end: Option<usize>,47 end: Option<BoundedUsize<0, { i32::MAX as usize }>>,48 step: Option<usize>,48 step: Option<BoundedUsize<1, { i32::MAX as usize }>>,49) -> Result<Val> {49) -> Result<Val> {50 let index = index.unwrap_or(0);50 match &indexable {51 let end = end.unwrap_or_else(|| match &indexable {51 IndexableVal::Str(s) => {52 IndexableVal::Str(_) => usize::MAX,53 IndexableVal::Arr(v) => v.len(),54 });52 let index = index.as_deref().copied().unwrap_or(0);53 let end = end.as_deref().copied().unwrap_or(usize::MAX);55 let step = step.unwrap_or(1);54 let step = step.as_deref().copied().unwrap_or(1);56 match &indexable {5556 if index >= end {57 return Ok(Val::Str("".into()));58 }5957 IndexableVal::Str(s) => Ok(Val::Str(60 Ok(Val::Str(58 (s.chars()61 (s.chars()59 .skip(index)62 .skip(index)60 .take(end - index)63 .take(end - index)61 .step_by(step)64 .step_by(step)62 .collect::<String>())65 .collect::<String>())63 .into(),66 .into(),64 )),67 ))68 }65 IndexableVal::Arr(arr) => Ok(Val::Arr(69 IndexableVal::Arr(arr) => {70 let index = index.as_deref().copied().unwrap_or(0);71 let end = end.as_deref().copied().unwrap_or(usize::MAX).min(arr.len());72 let step = step.as_deref().copied().unwrap_or(1);7374 if index >= end {75 return Ok(Val::Arr(ArrValue::new_eager()));76 }7766 (arr.iter()78 Ok(Val::Arr(ArrValue::Slice(Box::new(Slice {67 .skip(index)79 inner: arr.clone(),68 .take(end - index)80 from: index as u32,69 .step_by(step)81 to: end as u32,82 step: step as u32,70 .collect::<Result<Vec<Val>>>()?)83 }))))71 .into(),84 }72 )),85 }73 }74}86}758776type BuiltinsType = HashMap<IStr, &'static dyn StaticBuiltin>;88type BuiltinsType = HashMap<IStr, &'static dyn StaticBuiltin>;221#[jrsonnet_macros::builtin]233#[jrsonnet_macros::builtin]222fn builtin_slice(234fn builtin_slice(223 indexable: IndexableVal,235 indexable: IndexableVal,224 index: Option<usize>,236 index: Option<BoundedUsize<0, { i32::MAX as usize }>>,225 end: Option<usize>,237 end: Option<BoundedUsize<0, { i32::MAX as usize }>>,226 step: Option<usize>,238 step: Option<BoundedUsize<1, { i32::MAX as usize }>>,227) -> Result<Any> {239) -> Result<Any> {228 std_slice(indexable, index, end, step).map(Any)240 std_slice(indexable, index, end, step).map(Any)229}241}crates/jrsonnet-evaluator/src/error.rsdiffbeforeafterboth192 };192 };193}193}194195#[macro_export]196macro_rules! throw_runtime {197 ($($tt:tt)*) => {198 return Err($crate::error::Error::RuntimeError(format!($($tt)*).into()).into())199 };200}194201crates/jrsonnet-evaluator/src/evaluate/mod.rsdiffbeforeafterboth665 }665 }666 Slice(value, desc) => {666 Slice(value, desc) => {667 let indexable = evaluate(context.clone(), value)?;667 let indexable = evaluate(context.clone(), value)?;668 let loc = CallLocation::new(loc);668669669 fn parse_num(670 fn parse_idx<const MIN: usize>(671 loc: CallLocation,670 context: &Context,672 context: &Context,671 expr: Option<&LocExpr>,673 expr: &Option<LocExpr>,672 desc: &'static str,674 desc: &'static str,673 ) -> Result<Option<usize>> {675 ) -> Result<Option<BoundedUsize<MIN, { i32::MAX as usize }>>> {674 Ok(match expr {676 if let Some(value) = expr {675 Some(s) => evaluate(context.clone(), s)?677 Ok(Some(push_frame(676 .try_cast_nullable_num(desc)?678 loc,677 .map(|v| v as usize),679 || format!("slice {}", desc),678 None => None,680 || Ok(evaluate(context.clone(), value)?.try_into()?),681 )?))679 })682 } else {683 Ok(None)684 }680 }685 }681686682 let start = parse_num(&context, desc.start.as_ref(), "start")?;687 let start = parse_idx(loc, &context, &desc.start, "start")?;683 let end = parse_num(&context, desc.end.as_ref(), "end")?;688 let end = parse_idx(loc, &context, &desc.end, "end")?;684 let step = parse_num(&context, desc.step.as_ref(), "step")?;689 let step = parse_idx(loc, &context, &desc.step, "step")?;685690686 std_slice(indexable.into_indexable()?, start, end, step)?691 std_slice(indexable.into_indexable()?, start, end, step)?687 }692 }crates/jrsonnet-evaluator/src/typed/conversions.rsdiffbeforeafterboth1use std::{1use std::{2 convert::{TryFrom, TryInto},2 convert::{TryFrom, TryInto},3 ops::Deref,3 rc::Rc,4 rc::Rc,4};5};5612 error::{Error::*, LocError, Result},13 error::{Error::*, LocError, Result},13 throw,14 throw,14 typed::CheckType,15 typed::CheckType,15 ArrValue, FuncDesc, FuncVal, IndexableVal, ObjValue, ObjValueBuilder, Val,16 val::{ArrValue, FuncDesc, FuncVal, IndexableVal},17 ObjValue, ObjValueBuilder, Val,16};18};1719697170impl_int!(i8 u8 i16 u16 i32 u32);72impl_int!(i8 u8 i16 u16 i32 u32);7374macro_rules! impl_bounded_int {75 ($($name:ident = $ty:ty)*) => {$(76 #[derive(Clone, Copy)]77 pub struct $name<const MIN: $ty, const MAX: $ty>($ty);78 impl<const MIN: $ty, const MAX: $ty> $name<MIN, MAX> {79 pub const fn new(value: $ty) -> Option<$name<MIN, MAX>> {80 if value >= MIN && value <= MAX {81 Some(Self(value))82 } else {83 None84 }85 }86 pub const fn value(self) -> $ty {87 self.088 }89 }90 impl<const MIN: $ty, const MAX: $ty> Deref for $name<MIN, MAX> {91 type Target = $ty;92 fn deref(&self) -> &Self::Target {93 &self.094 }95 }9697 impl<const MIN: $ty, const MAX: $ty> Typed for $name<MIN, MAX> {98 const TYPE: &'static ComplexValType =99 &ComplexValType::BoundedNumber(100 Some(MIN as f64),101 Some(MAX as f64),102 );103 }104 impl<const MIN: $ty, const MAX: $ty> TryFrom<Val> for $name<MIN, MAX> {105 type Error = LocError;106107 fn try_from(value: Val) -> Result<Self> {108 <Self as Typed>::TYPE.check(&value)?;109 match value {110 Val::Num(n) => {111 if n.trunc() != n {112 throw!(RuntimeError(113 format!(114 "cannot convert number with fractional part to {}",115 stringify!($ty)116 )117 .into()118 ))119 }120 Ok(Self(n as $ty))121 }122 _ => unreachable!(),123 }124 }125 }126 impl<const MIN: $ty, const MAX: $ty> TryFrom<$name<MIN, MAX>> for Val {127 type Error = LocError;128129 fn try_from(value: $name<MIN, MAX>) -> Result<Self> {130 Ok(Self::Num(value.0 as f64))131 }132 }133 )*};134}135136impl_bounded_int!(137 BoundedI8 = i8138 BoundedI16 = i16139 BoundedI32 = i32140 BoundedI64 = i64141 BoundedUsize = usize142);7114372impl Typed for f64 {144impl Typed for f64 {73 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Num);145 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Num);crates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth171 String,171 String,172}172}173174#[derive(Debug, Clone, Trace)]175pub struct Slice {176 pub(crate) inner: ArrValue,177 pub(crate) from: u32,178 pub(crate) to: u32,179 pub(crate) step: u32,180}181impl Slice {182 fn from(&self) -> usize {183 self.from as usize184 }185 fn to(&self) -> usize {186 self.to as usize187 }188 fn step(&self) -> usize {189 self.step as usize190 }191 fn len(&self) -> usize {192 // TODO: use div_ceil193 let diff = self.to() - self.from();194 let rem = diff % self.step();195 let div = diff / self.step();196197 if rem != 0 {198 div + 1199 } else {200 div201 }202 }203}173204174#[derive(Debug, Clone, Trace)]205#[derive(Debug, Clone, Trace)]175#[force_tracking]206#[force_tracking]179 Eager(Cc<Vec<Val>>),210 Eager(Cc<Vec<Val>>),180 Extended(Box<(Self, Self)>),211 Extended(Box<(Self, Self)>),181 Range(i32, i32),212 Range(i32, i32),213 Slice(Box<Slice>),182 Reversed(Box<Self>),214 Reversed(Box<Self>),183}215}184impl ArrValue {216impl ArrValue {190 Self::Range(a, b)222 Self::Range(a, b)191 }223 }224225 pub fn slice(self, from: Option<usize>, to: Option<usize>, step: Option<usize>) -> Self {226 let len = self.len();227 let from = from.unwrap_or(0);228 let to = to.unwrap_or(len).min(len);229 let step = step.unwrap_or(1);230 assert!(from < to);231 assert!(step > 0);232233 Self::Slice(Box::new(Slice {234 inner: self,235 from: from as u32,236 to: to as u32,237 step: step as u32,238 }))239 }192240193 pub fn len(&self) -> usize {241 pub fn len(&self) -> usize {194 match self {242 match self {198 Self::Extended(v) => v.0.len() + v.1.len(),246 Self::Extended(v) => v.0.len() + v.1.len(),199 Self::Range(a, b) => a.abs_diff(*b) as usize,247 Self::Range(a, b) => a.abs_diff(*b) as usize,200 Self::Reversed(i) => i.len(),248 Self::Reversed(i) => i.len(),249 Self::Slice(s) => s.len(),201 }250 }202 }251 }203252239 }288 }240 v.get(len - index - 1)289 v.get(len - index - 1)241 }290 }291 Self::Slice(s) => {292 let index = s.from() + index * s.step();293 if index >= s.to() {294 return Ok(None);295 }296 s.inner.get(index as usize)297 }242 }298 }243 }299 }244300272 }328 }273 v.get_lazy(len - index - 1)329 v.get_lazy(len - index - 1)274 }330 }331 Self::Slice(s) => {332 let index = s.from() + index * s.step();333 if index >= s.to() {334 return None;335 }336 s.inner.get_lazy(index as usize)337 }275 }338 }276 }339 }277340311 Cc::update_with(&mut r, |v| v.reverse());374 Cc::update_with(&mut r, |v| v.reverse());312 r375 r313 }376 }377 Self::Slice(v) => {378 let mut out = Vec::with_capacity(v.inner.len());379 for v in v380 .inner381 .iter_lazy()382 .skip(v.from())383 .take(v.to() - v.from())384 .step_by(v.step())385 {386 out.push(v.evaluate()?)387 }388 Cc::new(out)389 }314 })390 })315 }391 }316392317 pub fn iter(&self) -> impl DoubleEndedIterator<Item = Result<Val>> + '_ {393 pub fn iter(&self) -> impl DoubleEndedIterator<Item = Result<Val>> + '_ {318 // if let Self::Reversed(v) = self {319 // return v.iter().rev();320 // }321 let len = self.len();394 (0..self.len()).map(move |idx| match self {322 (0..len).map(move |idx| match self {323 Self::Bytes(b) => Ok(Val::Num(b[idx] as f64)),395 Self::Bytes(b) => Ok(Val::Num(b[idx] as f64)),324 Self::Lazy(l) => l[idx].evaluate(),396 Self::Lazy(l) => l[idx].evaluate(),325 Self::Eager(e) => Ok(e[idx].clone()),397 Self::Eager(e) => Ok(e[idx].clone()),326 Self::Extended(_) => self.get(idx).map(|e| e.unwrap()),398 Self::Extended(_) => self.get(idx).map(|e| e.unwrap()),327 Self::Range(..) => self.get(idx).map(|e| e.unwrap()),399 Self::Range(..) => self.get(idx).map(|e| e.unwrap()),328 Self::Reversed(..) => self.get(len - idx - 1).map(|e| e.unwrap()),400 Self::Reversed(..) => self.get(idx).map(|e| e.unwrap()),401 Self::Slice(..) => self.get(idx).map(|e| e.unwrap()),329 })402 })330 }403 }331404332 pub fn iter_lazy(&self) -> impl DoubleEndedIterator<Item = LazyVal> + '_ {405 pub fn iter_lazy(&self) -> impl DoubleEndedIterator<Item = LazyVal> + '_ {333 let len = self.len();406 (0..self.len()).map(move |idx| match self {334 (0..len).map(move |idx| match self {335 Self::Bytes(b) => LazyVal::new_resolved(Val::Num(b[idx] as f64)),407 Self::Bytes(b) => LazyVal::new_resolved(Val::Num(b[idx] as f64)),336 Self::Lazy(l) => l[idx].clone(),408 Self::Lazy(l) => l[idx].clone(),337 Self::Eager(e) => LazyVal::new_resolved(e[idx].clone()),409 Self::Eager(e) => LazyVal::new_resolved(e[idx].clone()),338 Self::Extended(_) => self.get_lazy(idx).unwrap(),410 Self::Extended(_) => self.get_lazy(idx).unwrap(),339 Self::Range(..) => self.get_lazy(idx).unwrap(),411 Self::Range(..) => self.get_lazy(idx).unwrap(),340 Self::Reversed(..) => self.get_lazy(len - idx - 1).unwrap(),412 Self::Reversed(..) => self.get_lazy(idx).unwrap(),413 Self::Slice(..) => self.get_lazy(idx).unwrap(),341 })414 })342 }415 }343416459 }532 }460 }533 }461534462 pub fn try_cast_nullable_num(self, context: &'static str) -> Result<Option<f64>> {463 Ok(match self {464 Val::Null => None,465 Val::Num(num) => Some(num),466 _ => throw!(TypeMismatch(467 context,468 vec![ValType::Null, ValType::Num],469 self.value_type()470 )),471 })472 }473 pub const fn value_type(&self) -> ValType {535 pub const fn value_type(&self) -> ValType {474 match self {536 match self {475 Self::Str(..) => ValType::Str,537 Self::Str(..) => ValType::Str,