diff --git a/packages/sycamore/benches/reactivity.rs b/packages/sycamore/benches/reactivity.rs index bbbee21ee..0f7442715 100644 --- a/packages/sycamore/benches/reactivity.rs +++ b/packages/sycamore/benches/reactivity.rs @@ -1,5 +1,6 @@ use criterion::{black_box, criterion_group, criterion_main, Criterion}; use sycamore::prelude::*; +use sycamore::rx::{map_indexed, map_keyed}; pub fn bench(c: &mut Criterion) { c.bench_function("reactivity_signals", |b| { @@ -10,7 +11,7 @@ pub fn bench(c: &mut Criterion) { let value = state.get(); state.set(*value + 1); } - }) + }); }); c.bench_function("reactivity_effects", |b| { @@ -23,7 +24,29 @@ pub fn bench(c: &mut Criterion) { for _i in 0..1000 { state.set(*state.get() + 1); } - }) + }); + }); + + c.bench_function("reactivity map indexed", |b| { + b.iter(|| { + let v = Signal::new((0..100).collect()); + let mut mapped = map_indexed(v.handle(), |x| *x * 2); + mapped(); + + v.set((100..200).collect()); + mapped(); + }); + }); + + c.bench_function("reactivity map keyed", |b| { + b.iter(|| { + let v = Signal::new((0..100).collect()); + let mut mapped = map_keyed(v.handle(), |x| *x * 2); + mapped(); + + v.set((100..200).collect()); + mapped(); + }); }); } diff --git a/packages/sycamore/src/flow.rs b/packages/sycamore/src/flow.rs index 623342391..eeb6c7894 100644 --- a/packages/sycamore/src/flow.rs +++ b/packages/sycamore/src/flow.rs @@ -67,7 +67,7 @@ where let template = Rc::clone(&template); move |x| template(x.clone()) }); - Template::new_lazy(move || Template::new_fragment((*mapped()).clone())) + Template::new_lazy(move || Template::new_fragment(mapped())) } /// Props for [`Indexed`]. @@ -114,5 +114,5 @@ where let template = Rc::clone(&template); move |x| template(x.clone()) }); - Template::new_lazy(move || Template::new_fragment((*mapped()).clone())) + Template::new_lazy(move || Template::new_fragment(mapped())) } diff --git a/packages/sycamore/src/rx/iter.rs b/packages/sycamore/src/rx/iter.rs index c7408b246..4cd3b131f 100644 --- a/packages/sycamore/src/rx/iter.rs +++ b/packages/sycamore/src/rx/iter.rs @@ -10,14 +10,14 @@ use super::*; pub fn map_keyed( list: StateHandle>, map_fn: impl Fn(&T) -> U + 'static, -) -> impl FnMut() -> Rc> +) -> impl FnMut() -> Vec where T: Eq + Clone + Hash, U: Clone + 'static, { // Previous state used for diffing. - let mut items = Vec::new(); - let mapped = Rc::new(RefCell::new(Vec::::new())); + let mut items = Rc::new(Vec::new()); + let mapped = Rc::new(RefCell::new(Vec::new())); let mut scopes: Vec>> = Vec::new(); move || { @@ -140,12 +140,12 @@ where scopes.truncate(new_items.len()); // 4) save a copy of the mapped items for the next update. - items = (*new_items).clone(); + items = Rc::clone(&new_items); debug_assert!([items.len(), mapped.borrow().len(), scopes.len()] .iter() .all(|l| *l == new_items.len())); - Rc::new((*mapped).clone().into_inner()) + mapped.borrow().clone() }) } } @@ -153,13 +153,13 @@ where pub fn map_indexed( list: StateHandle>, map_fn: impl Fn(&T) -> U + 'static, -) -> impl FnMut() -> Rc> +) -> impl FnMut() -> Vec where T: PartialEq + Clone, U: Clone + 'static, { // Previous state used for diffing. - let mut items = Vec::new(); + let mut items = Rc::new(Vec::new()); let mapped = Rc::new(RefCell::new(Vec::new())); let mut scopes = Vec::new(); @@ -169,9 +169,16 @@ where if new_items.is_empty() { // Fast path for removing all items. drop(mem::take(&mut scopes)); - items = Vec::new(); + items = Rc::new(Vec::new()); *mapped.borrow_mut() = Vec::new(); } else { + // Pre-allocate space needed + if new_items.len() > items.len() { + let new_count = new_items.len() - items.len(); + mapped.borrow_mut().reserve(new_count); + scopes.reserve(new_count); + } + for (i, new_item) in new_items.iter().enumerate() { let item = items.get(i); @@ -203,13 +210,13 @@ where scopes.truncate(new_items.len()); // save a copy of the mapped items for the next update. - items = (*new_items).clone(); + items = Rc::clone(&new_items); debug_assert!([items.len(), mapped.borrow().len(), scopes.len()] .iter() .all(|l| *l == new_items.len())); } - Rc::new((*mapped).clone().into_inner()) + mapped.borrow().clone() }) } }