Add FoldMap::folds_in_range to randomized test and fix issues it found

This commit is contained in:
Antonio Scandurra 2021-05-06 18:49:41 +02:00
parent 652fc9e4ec
commit 178705f8f9
3 changed files with 120 additions and 143 deletions

View file

@ -3,7 +3,7 @@ use super::{
Anchor, Buffer, DisplayPoint, Edit, Point, TextSummary, ToOffset, Anchor, Buffer, DisplayPoint, Edit, Point, TextSummary, ToOffset,
}; };
use crate::{ use crate::{
sum_tree::{self, Cursor, SeekBias, SumTree}, sum_tree::{self, Cursor, FilterCursor, SeekBias, SumTree},
time, time,
}; };
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
@ -80,15 +80,7 @@ impl FoldMap {
where where
T: ToOffset, T: ToOffset,
{ {
let buffer = self.buffer.read(ctx); Ok(self.intersecting_folds(range, ctx)?.map(|f| &f.0))
let range = buffer.anchor_before(range.start)?..buffer.anchor_before(range.end)?;
Ok(self
.folds
.filter::<_, usize>(move |summary| {
range.start.cmp(&summary.max_end, buffer).unwrap() < Ordering::Equal
&& range.end.cmp(&summary.min_start, buffer).unwrap() >= Ordering::Equal
})
.map(|f| &f.0))
} }
pub fn fold<T: ToOffset>( pub fn fold<T: ToOffset>(
@ -150,25 +142,17 @@ impl FoldMap {
let mut edits = Vec::new(); let mut edits = Vec::new();
let mut fold_ixs_to_delete = Vec::new(); let mut fold_ixs_to_delete = Vec::new();
for range in ranges.into_iter() { for range in ranges.into_iter() {
let start = buffer.anchor_before(range.start.to_offset(buffer)?)?;
let end = buffer.anchor_after(range.end.to_offset(buffer)?)?;
let range = start..end;
// Remove intersecting folds and add their ranges to edits that are passed to apply_edits // Remove intersecting folds and add their ranges to edits that are passed to apply_edits
let mut cursor = self.folds.filter::<_, usize>(|summary| { let mut folds_cursor = self.intersecting_folds(range, ctx)?;
range.start.cmp(&summary.max_end, buffer).unwrap() < Ordering::Equal while let Some(fold) = folds_cursor.item() {
&& range.end.cmp(&summary.min_start, buffer).unwrap() >= Ordering::Equal
});
while let Some(fold) = cursor.item() {
let offset_range = let offset_range =
fold.0.start.to_offset(buffer).unwrap()..fold.0.end.to_offset(buffer).unwrap(); fold.0.start.to_offset(buffer).unwrap()..fold.0.end.to_offset(buffer).unwrap();
edits.push(Edit { edits.push(Edit {
old_range: offset_range.clone(), old_range: offset_range.clone(),
new_range: offset_range, new_range: offset_range,
}); });
fold_ixs_to_delete.push(*cursor.start()); fold_ixs_to_delete.push(*folds_cursor.start());
cursor.next(); folds_cursor.next();
} }
} }
fold_ixs_to_delete.sort_unstable(); fold_ixs_to_delete.sort_unstable();
@ -192,6 +176,23 @@ impl FoldMap {
Ok(()) Ok(())
} }
fn intersecting_folds<'a, T>(
&self,
range: Range<T>,
ctx: &'a AppContext,
) -> Result<FilterCursor<impl 'a + Fn(&FoldSummary) -> bool, Fold, usize>>
where
T: ToOffset,
{
let buffer = self.buffer.read(ctx);
let start = buffer.anchor_before(range.start.to_offset(buffer)?)?;
let end = buffer.anchor_after(range.end.to_offset(buffer)?)?;
Ok(self.folds.filter::<_, usize>(move |summary| {
start.cmp(&summary.max_end, buffer).unwrap() <= Ordering::Equal
&& end.cmp(&summary.min_start, buffer).unwrap() >= Ordering::Equal
}))
}
pub fn is_line_folded(&self, display_row: u32, ctx: &AppContext) -> bool { pub fn is_line_folded(&self, display_row: u32, ctx: &AppContext) -> bool {
let transforms = self.sync(ctx); let transforms = self.sync(ctx);
let mut cursor = transforms.cursor::<DisplayPoint, DisplayPoint>(); let mut cursor = transforms.cursor::<DisplayPoint, DisplayPoint>();
@ -502,7 +503,7 @@ impl Default for FoldSummary {
Self { Self {
start: Anchor::Start, start: Anchor::Start,
end: Anchor::End, end: Anchor::End,
min_start: Anchor::Start, min_start: Anchor::End,
max_end: Anchor::Start, max_end: Anchor::Start,
count: 0, count: 0,
} }
@ -521,12 +522,12 @@ impl sum_tree::Summary for FoldSummary {
self.max_end = other.max_end.clone(); self.max_end = other.max_end.clone();
} }
if cfg!(debug_assertions) { #[cfg(debug_assertions)]
{
let start_comparison = self.start.cmp(&other.start, buffer).unwrap(); let start_comparison = self.start.cmp(&other.start, buffer).unwrap();
let end_comparison = self.end.cmp(&other.end, buffer).unwrap();
assert!(start_comparison <= Ordering::Equal); assert!(start_comparison <= Ordering::Equal);
if start_comparison == Ordering::Equal { if start_comparison == Ordering::Equal {
assert!(end_comparison >= Ordering::Equal); assert!(self.end.cmp(&other.end, buffer).unwrap() >= Ordering::Equal);
} }
} }
self.start = other.start.clone(); self.start = other.start.clone();
@ -821,6 +822,7 @@ mod tests {
fold_ranges, fold_ranges,
vec![ vec![
Point::new(0, 2)..Point::new(2, 2), Point::new(0, 2)..Point::new(2, 2),
Point::new(0, 4)..Point::new(1, 0),
Point::new(1, 2)..Point::new(3, 2) Point::new(1, 2)..Point::new(3, 2)
] ]
); );
@ -848,7 +850,7 @@ mod tests {
}; };
for seed in seed_range { for seed in seed_range {
println!("{:?}", seed); dbg!(seed);
let mut rng = StdRng::seed_from_u64(seed); let mut rng = StdRng::seed_from_u64(seed);
App::test((), |app| { App::test((), |app| {
@ -973,6 +975,30 @@ mod tests {
); );
assert!(map.is_line_folded(display_point.row(), app.as_ref())); assert!(map.is_line_folded(display_point.row(), app.as_ref()));
} }
for _ in 0..5 {
let end = rng.gen_range(0..=buffer.len());
let start = rng.gen_range(0..=end);
let expected_folds = map
.folds
.items()
.into_iter()
.filter(|fold| {
let fold_start = fold.0.start.to_offset(buffer).unwrap();
let fold_end = fold.0.end.to_offset(buffer).unwrap();
start <= fold_end && end >= fold_start
})
.map(|fold| fold.0)
.collect::<Vec<_>>();
assert_eq!(
map.folds_in_range(start..end, app.as_ref())
.unwrap()
.cloned()
.collect::<Vec<_>>(),
expected_folds
);
}
} }
}); });
} }

View file

@ -199,9 +199,6 @@ where
} }
pub fn next(&mut self) { pub fn next(&mut self) {
if !self.did_seek {
self.descend_to_first_item(self.tree, |_| true)
}
self.next_internal(|_| true) self.next_internal(|_| true)
} }
@ -209,67 +206,88 @@ where
where where
F: Fn(&T::Summary) -> bool, F: Fn(&T::Summary) -> bool,
{ {
assert!(self.did_seek, "Must seek before calling this method"); let mut descend = false;
if self.stack.is_empty() { if !self.did_seek {
if !self.at_end { self.stack.push(StackEntry {
self.descend_to_first_item(self.tree, filter_node); tree: self.tree,
} index: 0,
} else { seek_dimension: S::default(),
while self.stack.len() > 0 { sum_dimension: U::default(),
let new_subtree = { });
let entry = self.stack.last_mut().unwrap(); descend = true;
match entry.tree.0.as_ref() { self.did_seek = true;
Node::Internal { }
child_trees,
child_summaries,
..
} => {
while entry.index < child_summaries.len() {
entry
.seek_dimension
.add_summary(&child_summaries[entry.index]);
entry
.sum_dimension
.add_summary(&child_summaries[entry.index]);
entry.index += 1; while self.stack.len() > 0 {
if let Some(next_summary) = child_summaries.get(entry.index) { let new_subtree = {
if filter_node(next_summary) { let entry = self.stack.last_mut().unwrap();
break; match entry.tree.0.as_ref() {
} else { Node::Internal {
self.seek_dimension.add_summary(next_summary); child_trees,
self.sum_dimension.add_summary(next_summary); child_summaries,
} ..
} } => {
} if !descend {
let summary = &child_summaries[entry.index];
child_trees.get(entry.index) entry.seek_dimension.add_summary(summary);
entry.sum_dimension.add_summary(summary);
entry.index += 1;
} }
Node::Leaf { item_summaries, .. } => loop {
while entry.index < child_summaries.len() {
let next_summary = &child_summaries[entry.index];
if filter_node(next_summary) {
break;
} else {
self.seek_dimension.add_summary(next_summary);
self.sum_dimension.add_summary(next_summary);
}
entry.index += 1;
}
child_trees.get(entry.index)
}
Node::Leaf { item_summaries, .. } => {
if !descend {
let item_summary = &item_summaries[entry.index]; let item_summary = &item_summaries[entry.index];
self.seek_dimension.add_summary(item_summary); self.seek_dimension.add_summary(item_summary);
entry.seek_dimension.add_summary(item_summary); entry.seek_dimension.add_summary(item_summary);
self.sum_dimension.add_summary(item_summary); self.sum_dimension.add_summary(item_summary);
entry.sum_dimension.add_summary(item_summary); entry.sum_dimension.add_summary(item_summary);
entry.index += 1; entry.index += 1;
}
loop {
if let Some(next_item_summary) = item_summaries.get(entry.index) { if let Some(next_item_summary) = item_summaries.get(entry.index) {
if filter_node(next_item_summary) { if filter_node(next_item_summary) {
return; return;
} else {
self.seek_dimension.add_summary(next_item_summary);
entry.seek_dimension.add_summary(next_item_summary);
self.sum_dimension.add_summary(next_item_summary);
entry.sum_dimension.add_summary(next_item_summary);
entry.index += 1;
} }
} else { } else {
break None; break None;
} }
}, }
} }
};
if let Some(subtree) = new_subtree {
self.descend_to_first_item(subtree, filter_node);
break;
} else {
self.stack.pop();
} }
};
if let Some(subtree) = new_subtree {
descend = true;
self.stack.push(StackEntry {
tree: subtree,
index: 0,
seek_dimension: self.seek_dimension.clone(),
sum_dimension: self.sum_dimension.clone(),
});
} else {
descend = false;
self.stack.pop();
} }
} }
@ -277,67 +295,6 @@ where
debug_assert!(self.stack.is_empty() || self.stack.last().unwrap().tree.0.is_leaf()); debug_assert!(self.stack.is_empty() || self.stack.last().unwrap().tree.0.is_leaf());
} }
pub fn descend_to_first_item<F>(&mut self, mut subtree: &'a SumTree<T>, filter_node: F)
where
F: Fn(&T::Summary) -> bool,
{
self.did_seek = true;
loop {
subtree = match *subtree.0 {
Node::Internal {
ref child_trees,
ref child_summaries,
..
} => {
let mut new_index = None;
for (index, summary) in child_summaries.iter().enumerate() {
if filter_node(summary) {
new_index = Some(index);
break;
}
self.seek_dimension.add_summary(summary);
self.sum_dimension.add_summary(summary);
}
if let Some(new_index) = new_index {
self.stack.push(StackEntry {
tree: subtree,
index: new_index,
seek_dimension: self.seek_dimension.clone(),
sum_dimension: self.sum_dimension.clone(),
});
&child_trees[new_index]
} else {
break;
}
}
Node::Leaf {
ref item_summaries, ..
} => {
let mut new_index = None;
for (index, item_summary) in item_summaries.iter().enumerate() {
if filter_node(item_summary) {
new_index = Some(index);
break;
}
self.seek_dimension.add_summary(item_summary);
self.sum_dimension.add_summary(item_summary);
}
if let Some(new_index) = new_index {
self.stack.push(StackEntry {
tree: subtree,
index: new_index,
seek_dimension: self.seek_dimension.clone(),
sum_dimension: self.sum_dimension.clone(),
});
}
break;
}
}
}
}
fn descend_to_last_item(&mut self, mut subtree: &'a SumTree<T>) { fn descend_to_last_item(&mut self, mut subtree: &'a SumTree<T>) {
self.did_seek = true; self.did_seek = true;
loop { loop {
@ -744,7 +701,7 @@ where
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
if !self.did_seek { if !self.did_seek {
self.descend_to_first_item(self.tree, |_| true); self.next();
} }
if let Some(item) = self.item() { if let Some(item) = self.item() {
@ -769,13 +726,7 @@ where
{ {
pub fn new(tree: &'a SumTree<T>, filter_node: F) -> Self { pub fn new(tree: &'a SumTree<T>, filter_node: F) -> Self {
let mut cursor = tree.cursor::<(), U>(); let mut cursor = tree.cursor::<(), U>();
if filter_node(&tree.summary()) { cursor.next_internal(&filter_node);
cursor.descend_to_first_item(tree, &filter_node);
} else {
cursor.did_seek = true;
cursor.at_end = true;
}
Self { Self {
cursor, cursor,
filter_node, filter_node,

View file

@ -73,7 +73,6 @@ impl<T: Item> SumTree<T> {
#[allow(unused)] #[allow(unused)]
pub fn items(&self) -> Vec<T> { pub fn items(&self) -> Vec<T> {
let mut cursor = self.cursor::<(), ()>(); let mut cursor = self.cursor::<(), ()>();
cursor.descend_to_first_item(self, |_| true);
cursor.cloned().collect() cursor.cloned().collect()
} }
@ -566,6 +565,7 @@ mod tests {
for seed in 0..100 { for seed in 0..100 {
use rand::{distributions, prelude::*}; use rand::{distributions, prelude::*};
dbg!(seed);
let rng = &mut StdRng::seed_from_u64(seed); let rng = &mut StdRng::seed_from_u64(seed);
let mut tree = SumTree::<u8>::new(); let mut tree = SumTree::<u8>::new();