Make summaries a running sum

This commit is contained in:
Piotr Osiewicz 2025-08-08 16:49:30 +02:00
parent 57ea58c83e
commit b43153a99f
3 changed files with 35 additions and 27 deletions

View file

@ -205,13 +205,13 @@ where
#[track_caller] #[track_caller]
pub fn prev(&mut self) { pub fn prev(&mut self) {
self.search_backward(|_| true) self.search_backward(|_| Ordering::Greater)
} }
#[track_caller] #[track_caller]
pub fn search_backward<F>(&mut self, mut filter_node: F) pub fn search_backward<F>(&mut self, mut filter_node: F)
where where
F: FnMut(&T::Summary) -> bool, F: FnMut(&T::Summary) -> Ordering,
{ {
if !self.did_seek { if !self.did_seek {
self.did_seek = true; self.did_seek = true;
@ -253,13 +253,14 @@ where
} }
} }
for summary in &entry.tree.0.child_summaries()[..entry.index] { if entry.index != 0 {
self.position.add_summary(summary, self.cx); self.position
.add_summary(&entry.tree.0.child_summaries()[entry.index - 1], self.cx);
} }
entry.position = self.position.clone(); entry.position = self.position.clone();
descending = filter_node(&entry.tree.0.child_summaries()[entry.index]); descending = filter_node(&entry.tree.0.child_summaries()[entry.index]).is_ge();
match entry.tree.0.as_ref() { match entry.tree.0.as_ref() {
Node::Internal { child_trees, .. } => { Node::Internal { child_trees, .. } => {
if descending { if descending {
@ -282,13 +283,13 @@ where
#[track_caller] #[track_caller]
pub fn next(&mut self) { pub fn next(&mut self) {
self.search_forward(|_| true) self.search_forward(|_| Ordering::Less)
} }
#[track_caller] #[track_caller]
pub fn search_forward<F>(&mut self, mut filter_node: F) pub fn search_forward<F>(&mut self, mut filter_node: F)
where where
F: FnMut(&T::Summary) -> bool, F: FnMut(&T::Summary) -> Ordering,
{ {
let mut descend = false; let mut descend = false;
@ -318,14 +319,17 @@ where
entry.position = self.position.clone(); entry.position = self.position.clone();
} }
while entry.index < child_summaries.len() { if entry.index < child_summaries.len() {
let next_summary = &child_summaries[entry.index]; let index = child_summaries[entry.index..]
if filter_node(next_summary) { .partition_point(|item| filter_node(item).is_lt());
break; entry.index += index;
} else { let position = Some(entry.index)
entry.index += 1; .filter(|index| *index < child_summaries.len())
entry.position.add_summary(next_summary, self.cx); .unwrap_or(child_summaries.len());
self.position.add_summary(next_summary, self.cx);
if let Some(summary) = child_summaries.get(position) {
entry.position.add_summary(summary, self.cx);
self.position.add_summary(summary, self.cx);
} }
} }
@ -340,13 +344,17 @@ where
} }
loop { loop {
if let Some(next_item_summary) = item_summaries.get(entry.index) { if entry.index < item_summaries.len() {
if filter_node(next_item_summary) { let index = item_summaries[entry.index..]
return; .partition_point(|item| filter_node(item).is_lt());
} else { entry.index += index;
entry.index += 1; let position = Some(entry.index)
entry.position.add_summary(next_item_summary, self.cx); .filter(|index| *index < item_summaries.len())
self.position.add_summary(next_item_summary, self.cx); .unwrap_or(item_summaries.len());
if let Some(summary) = item_summaries.get(position) {
entry.position.add_summary(summary, self.cx);
self.position.add_summary(summary, self.cx);
} }
} else { } else {
break None; break None;
@ -638,7 +646,7 @@ pub struct FilterCursor<'a, F, T: Item, D> {
impl<'a, F, T: Item, D> FilterCursor<'a, F, T, D> impl<'a, F, T: Item, D> FilterCursor<'a, F, T, D>
where where
F: FnMut(&T::Summary) -> bool, F: FnMut(&T::Summary) -> Ordering,
T: Item, T: Item,
D: Dimension<'a, T::Summary>, D: Dimension<'a, T::Summary>,
{ {
@ -681,7 +689,7 @@ where
impl<'a, F, T: Item, U> Iterator for FilterCursor<'a, F, T, U> impl<'a, F, T: Item, U> Iterator for FilterCursor<'a, F, T, U>
where where
F: FnMut(&T::Summary) -> bool, F: FnMut(&T::Summary) -> Ordering,
U: Dimension<'a, T::Summary>, U: Dimension<'a, T::Summary>,
{ {
type Item = &'a T; type Item = &'a T;

View file

@ -375,7 +375,7 @@ impl<T: Item> SumTree<T> {
filter_node: F, filter_node: F,
) -> FilterCursor<'a, F, T, U> ) -> FilterCursor<'a, F, T, U>
where where
F: FnMut(&T::Summary) -> bool, F: FnMut(&T::Summary) -> Ordering,
U: Dimension<'a, T::Summary>, U: Dimension<'a, T::Summary>,
{ {
FilterCursor::new(self, cx, filter_node) FilterCursor::new(self, cx, filter_node)
@ -1026,7 +1026,7 @@ mod tests {
log::info!("tree items: {:?}", tree.items(&())); log::info!("tree items: {:?}", tree.items(&()));
let mut filter_cursor = let mut filter_cursor =
tree.filter::<_, Count>(&(), |summary| summary.contains_even); tree.filter::<_, Count>(&(), |summary| summary.contains_even.cmp(&false));
let expected_filtered_items = tree let expected_filtered_items = tree
.items(&()) .items(&())
.into_iter() .into_iter()

View file

@ -412,7 +412,7 @@ mod tests {
.take_while(|(key, _)| key.starts_with("ba")) .take_while(|(key, _)| key.starts_with("ba"))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
assert_eq!(result.len(), 2); assert_eq!(result.len(), 2, "{result:?}");
assert!(result.iter().any(|(k, _)| k == &&"baa")); assert!(result.iter().any(|(k, _)| k == &&"baa"));
assert!(result.iter().any(|(k, _)| k == &&"baaab")); assert!(result.iter().any(|(k, _)| k == &&"baaab"));