git.delta.rocks / jrsonnet / refs/commits / 4c008687f967

difftreelog

perf lazy slice

Yaroslav Bolyukin2022-04-20parent: #9c0fa01.patch.diff
in: master

5 files changed

modifiedcrates/jrsonnet-evaluator/src/builtin/mod.rsdiffbeforeafterboth
4343
44pub 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 {55
56 if index >= end {
57 return Ok(Val::Str("".into()));
58 }
59
57 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);
73
74 if index >= end {
75 return Ok(Val::Arr(ArrValue::new_eager()));
76 }
77
66 (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}
7587
76type 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}
modifiedcrates/jrsonnet-evaluator/src/error.rsdiffbeforeafterboth
192 };192 };
193}193}
194
195#[macro_export]
196macro_rules! throw_runtime {
197 ($($tt:tt)*) => {
198 return Err($crate::error::Error::RuntimeError(format!($($tt)*).into()).into())
199 };
200}
194201
modifiedcrates/jrsonnet-evaluator/src/evaluate/mod.rsdiffbeforeafterboth
665 }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);
668669
669 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 }
681686
682 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")?;
685690
686 std_slice(indexable.into_indexable()?, start, end, step)?691 std_slice(indexable.into_indexable()?, start, end, step)?
687 }692 }
modifiedcrates/jrsonnet-evaluator/src/typed/conversions.rsdiffbeforeafterboth
1use std::{1use std::{
2 convert::{TryFrom, TryInto},2 convert::{TryFrom, TryInto},
3 ops::Deref,
3 rc::Rc,4 rc::Rc,
4};5};
56
12 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};
1719
6971
70impl_int!(i8 u8 i16 u16 i32 u32);72impl_int!(i8 u8 i16 u16 i32 u32);
73
74macro_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 None
84 }
85 }
86 pub const fn value(self) -> $ty {
87 self.0
88 }
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.0
94 }
95 }
96
97 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;
106
107 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;
128
129 fn try_from(value: $name<MIN, MAX>) -> Result<Self> {
130 Ok(Self::Num(value.0 as f64))
131 }
132 }
133 )*};
134}
135
136impl_bounded_int!(
137 BoundedI8 = i8
138 BoundedI16 = i16
139 BoundedI32 = i32
140 BoundedI64 = i64
141 BoundedUsize = usize
142);
71143
72impl 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);
modifiedcrates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth
171 String,171 String,
172}172}
173
174#[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 usize
184 }
185 fn to(&self) -> usize {
186 self.to as usize
187 }
188 fn step(&self) -> usize {
189 self.step as usize
190 }
191 fn len(&self) -> usize {
192 // TODO: use div_ceil
193 let diff = self.to() - self.from();
194 let rem = diff % self.step();
195 let div = diff / self.step();
196
197 if rem != 0 {
198 div + 1
199 } else {
200 div
201 }
202 }
203}
173204
174#[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 }
224
225 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);
232
233 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 }
192240
193 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 }
203252
239 }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 }
244300
272 }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 }
277340
311 Cc::update_with(&mut r, |v| v.reverse());374 Cc::update_with(&mut r, |v| v.reverse());
312 r375 r
313 }376 }
377 Self::Slice(v) => {
378 let mut out = Vec::with_capacity(v.inner.len());
379 for v in v
380 .inner
381 .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 }
316392
317 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 }
331404
332 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 }
343416
459 }532 }
460 }533 }
461534
462 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,