From 1ed1ec21ddb3ec44e0111c2e87827cae87db76ab Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 9 Dec 2021 10:42:44 -0800 Subject: [PATCH] Batch anchor resolution, avoid cloning fragment ids when seeking --- crates/text/src/selection.rs | 13 ++++++- crates/text/src/tests.rs | 4 +-- crates/text/src/text.rs | 68 +++++++++++++++++++++++++++++++----- 3 files changed, 73 insertions(+), 12 deletions(-) diff --git a/crates/text/src/selection.rs b/crates/text/src/selection.rs index ae96e93e51..5142baf7f5 100644 --- a/crates/text/src/selection.rs +++ b/crates/text/src/selection.rs @@ -125,7 +125,18 @@ impl SelectionSet { where D: 'a + TextDimension<'a>, { - self.selections.iter().map(|s| s.resolve(snapshot)) + let anchors = self + .selections + .iter() + .flat_map(|selection| [&selection.start, &selection.end].into_iter()); + let mut positions = snapshot.summaries_for_anchors::(anchors); + self.selections.iter().map(move |selection| Selection { + start: positions.next().unwrap(), + end: positions.next().unwrap(), + goal: selection.goal, + reversed: selection.reversed, + id: selection.id, + }) } pub fn intersecting_selections<'a, D, I>( diff --git a/crates/text/src/tests.rs b/crates/text/src/tests.rs index f7f307049c..5439e71af7 100644 --- a/crates/text/src/tests.rs +++ b/crates/text/src/tests.rs @@ -645,9 +645,9 @@ impl Buffer { assert_eq!(insertion_fragment.fragment_id, fragment.id); } - let mut cursor = self.snapshot.fragments.cursor::(); + let mut cursor = self.snapshot.fragments.cursor::>(); for insertion_fragment in self.snapshot.insertions.cursor::<()>() { - cursor.seek(&insertion_fragment.fragment_id, Bias::Left, &None); + cursor.seek(&Some(&insertion_fragment.fragment_id), Bias::Left, &None); let fragment = cursor.item().unwrap(); assert_eq!(insertion_fragment.fragment_id, fragment.id); assert_eq!(insertion_fragment.split_offset, fragment.insertion_offset); diff --git a/crates/text/src/text.rs b/crates/text/src/text.rs index 3985501659..d8c9c43d5f 100644 --- a/crates/text/src/text.rs +++ b/crates/text/src/text.rs @@ -1672,6 +1672,56 @@ impl Snapshot { result } + pub fn summaries_for_anchors<'a, D, A>(&'a self, anchors: A) -> impl 'a + Iterator + where + D: 'a + TextDimension<'a>, + A: 'a + IntoIterator, + { + let anchors = anchors.into_iter(); + let mut insertion_cursor = self.insertions.cursor::(); + let mut fragment_cursor = self.fragments.cursor::<(Option<&Locator>, usize)>(); + let mut text_cursor = self.visible_text.cursor(0); + let mut position = D::default(); + + anchors.map(move |anchor| { + if *anchor == Anchor::min() { + return D::default(); + } else if *anchor == Anchor::max() { + return D::from_text_summary(&self.visible_text.summary()); + } + + let anchor_key = InsertionFragmentKey { + timestamp: anchor.timestamp, + split_offset: anchor.offset, + }; + insertion_cursor.seek(&anchor_key, anchor.bias, &()); + if let Some(insertion) = insertion_cursor.item() { + let comparison = sum_tree::KeyedItem::key(insertion).cmp(&anchor_key); + if comparison == Ordering::Greater + || (anchor.bias == Bias::Left + && comparison == Ordering::Equal + && anchor.offset > 0) + { + insertion_cursor.prev(&()); + } + } else { + insertion_cursor.prev(&()); + } + let insertion = insertion_cursor.item().expect("invalid insertion"); + debug_assert_eq!(insertion.timestamp, anchor.timestamp, "invalid insertion"); + + fragment_cursor.seek_forward(&Some(&insertion.fragment_id), Bias::Left, &None); + let fragment = fragment_cursor.item().unwrap(); + let mut fragment_offset = fragment_cursor.start().1; + if fragment.visible { + fragment_offset += anchor.offset - insertion.split_offset; + } + + position.add_assign(&text_cursor.summary(fragment_offset)); + position.clone() + }) + } + fn summary_for_anchor<'a, D>(&'a self, anchor: &Anchor) -> D where D: TextDimension<'a>, @@ -1702,8 +1752,8 @@ impl Snapshot { let insertion = insertion_cursor.item().expect("invalid insertion"); debug_assert_eq!(insertion.timestamp, anchor.timestamp, "invalid insertion"); - let mut fragment_cursor = self.fragments.cursor::<(Locator, usize)>(); - fragment_cursor.seek(&insertion.fragment_id, Bias::Left, &None); + let mut fragment_cursor = self.fragments.cursor::<(Option<&Locator>, usize)>(); + fragment_cursor.seek(&Some(&insertion.fragment_id), Bias::Left, &None); let fragment = fragment_cursor.item().unwrap(); let mut fragment_offset = fragment_cursor.start().1; if fragment.visible { @@ -1741,8 +1791,8 @@ impl Snapshot { let insertion = insertion_cursor.item().expect("invalid insertion"); debug_assert_eq!(insertion.timestamp, anchor.timestamp, "invalid insertion"); - let mut fragment_cursor = self.fragments.cursor::<(Locator, FullOffset)>(); - fragment_cursor.seek(&insertion.fragment_id, Bias::Left, &None); + let mut fragment_cursor = self.fragments.cursor::<(Option<&Locator>, FullOffset)>(); + fragment_cursor.seek(&Some(&insertion.fragment_id), Bias::Left, &None); fragment_cursor.start().1 + (anchor.offset - insertion.split_offset) } } @@ -1771,10 +1821,10 @@ impl Snapshot { } else if bias == Bias::Right && offset == self.len() { Anchor::max() } else { - let mut fragment_cursor = self.fragments.cursor::<(usize, Locator)>(); + let mut fragment_cursor = self.fragments.cursor::(); fragment_cursor.seek(&offset, bias, &None); let fragment = fragment_cursor.item().unwrap(); - let overshoot = offset - fragment_cursor.start().0; + let overshoot = offset - *fragment_cursor.start(); Anchor { timestamp: fragment.insertion_timestamp.local(), offset: fragment.insertion_offset + overshoot, @@ -2111,9 +2161,9 @@ impl<'a> sum_tree::Dimension<'a, FragmentSummary> for FullOffset { } } -impl<'a> sum_tree::Dimension<'a, FragmentSummary> for Locator { - fn add_summary(&mut self, summary: &FragmentSummary, _: &Option) { - self.assign(&summary.max_id); +impl<'a> sum_tree::Dimension<'a, FragmentSummary> for Option<&'a Locator> { + fn add_summary(&mut self, summary: &'a FragmentSummary, _: &Option) { + *self = Some(&summary.max_id); } }