Allow seeking SumTree cursor by multiple seek types per dimension

Also, remove the cursor's sum_dimension. Replace it with a
blanket implementation of Dimension for two-element tuples
of dimensions.

Co-Authored-By: Nathan Sobo <nathan@zed.dev>
This commit is contained in:
Max Brunsfeld
2021-09-24 18:23:53 -07:00
co-authored by Nathan Sobo
parent 39fbf7d4d1
commit ab31ddfc31
11 changed files with 458 additions and 509 deletions
+31 -34
View File
@@ -128,7 +128,7 @@ impl Element for List {
});
// Render items after the scroll top, including those in the trailing overdraw.
let mut cursor = old_items.cursor::<Count, ()>();
let mut cursor = old_items.cursor::<Count>();
cursor.seek(&Count(scroll_top.item_ix), Bias::Right, &());
for (ix, item) in cursor.by_ref().enumerate() {
if rendered_height - scroll_top.offset_in_item >= size.y() + state.overdraw {
@@ -149,8 +149,7 @@ impl Element for List {
while rendered_height < size.y() {
cursor.prev(&());
if let Some(item) = cursor.item() {
let element =
state.render_item(cursor.seek_start().0, item, item_constraint, cx);
let element = state.render_item(cursor.start().0, item, item_constraint, cx);
rendered_height += element.size().y();
rendered_items.push_front(ListItem::Rendered(element));
} else {
@@ -159,7 +158,7 @@ impl Element for List {
}
scroll_top = ListOffset {
item_ix: cursor.seek_start().0,
item_ix: cursor.start().0,
offset_in_item: rendered_height - size.y(),
};
@@ -170,7 +169,7 @@ impl Element for List {
}
Orientation::Bottom => {
scroll_top = ListOffset {
item_ix: cursor.seek_start().0,
item_ix: cursor.start().0,
offset_in_item: rendered_height - size.y(),
};
state.logical_scroll_top = None;
@@ -183,7 +182,7 @@ impl Element for List {
while leading_overdraw < state.overdraw {
cursor.prev(&());
if let Some(item) = cursor.item() {
let element = state.render_item(cursor.seek_start().0, item, item_constraint, cx);
let element = state.render_item(cursor.start().0, item, item_constraint, cx);
leading_overdraw += element.size().y();
rendered_items.push_front(ListItem::Rendered(element));
} else {
@@ -191,10 +190,9 @@ impl Element for List {
}
}
let new_rendered_range =
cursor.seek_start().0..(cursor.seek_start().0 + rendered_items.len());
let new_rendered_range = cursor.start().0..(cursor.start().0 + rendered_items.len());
let mut cursor = old_items.cursor::<Count, ()>();
let mut cursor = old_items.cursor::<Count>();
if state.rendered_range.start < new_rendered_range.start {
new_items.push_tree(
@@ -202,7 +200,7 @@ impl Element for List {
&(),
);
let remove_to = state.rendered_range.end.min(new_rendered_range.start);
while cursor.seek_start().0 < remove_to {
while cursor.start().0 < remove_to {
new_items.push(cursor.item().unwrap().remove(), &());
cursor.next(&());
}
@@ -221,7 +219,7 @@ impl Element for List {
&(),
);
}
while cursor.seek_start().0 < state.rendered_range.end {
while cursor.start().0 < state.rendered_range.end {
new_items.push(cursor.item().unwrap().remove(), &());
cursor.next(&());
}
@@ -263,7 +261,7 @@ impl Element for List {
let mut state = self.state.0.borrow_mut();
let mut item_origin = bounds.origin() - vec2f(0., scroll_top.offset_in_item);
let mut cursor = state.items.cursor::<Count, ()>();
let mut cursor = state.items.cursor::<Count>();
let mut new_items = cursor.slice(&Count(scroll_top.item_ix), Bias::Right, &());
while let Some(item) = cursor.item() {
if item_origin.y() > bounds.max_y() {
@@ -390,7 +388,7 @@ impl ListState {
new_end + state.rendered_range.end.saturating_sub(old_range.end);
}
let mut old_heights = state.items.cursor::<Count, ()>();
let mut old_heights = state.items.cursor::<Count>();
let mut new_heights = old_heights.slice(&Count(old_range.start), Bias::Right, &());
old_heights.seek_forward(&Count(old_range.end), Bias::Right, &());
@@ -426,12 +424,11 @@ impl StateInner {
}
fn visible_range(&self, height: f32, scroll_top: &ListOffset) -> Range<usize> {
let mut cursor = self.items.cursor::<Count, Height>();
let mut cursor = self.items.cursor::<ListItemSummary>();
cursor.seek(&Count(scroll_top.item_ix), Bias::Right, &());
let start_y = cursor.sum_start().0 + scroll_top.offset_in_item;
let mut cursor = cursor.swap_dimensions();
let start_y = cursor.start().height + scroll_top.offset_in_item;
cursor.seek_forward(&Height(start_y + height), Bias::Left, &());
scroll_top.item_ix..cursor.sum_start().0 + 1
scroll_top.item_ix..cursor.start().count + 1
}
fn visible_elements<'a>(
@@ -440,7 +437,7 @@ impl StateInner {
scroll_top: &ListOffset,
) -> impl Iterator<Item = (ElementRc, Vector2F)> + 'a {
let mut item_origin = bounds.origin() - vec2f(0., scroll_top.offset_in_item);
let mut cursor = self.items.cursor::<Count, ()>();
let mut cursor = self.items.cursor::<Count>();
cursor.seek(&Count(scroll_top.item_ix), Bias::Right, &());
std::iter::from_fn(move || {
while let Some(item) = cursor.item() {
@@ -482,10 +479,10 @@ impl StateInner {
if self.orientation == Orientation::Bottom && new_scroll_top == scroll_max {
self.logical_scroll_top = None;
} else {
let mut cursor = self.items.cursor::<Height, Count>();
let mut cursor = self.items.cursor::<ListItemSummary>();
cursor.seek(&Height(new_scroll_top), Bias::Right, &());
let item_ix = cursor.sum_start().0;
let offset_in_item = new_scroll_top - cursor.seek_start().0;
let item_ix = cursor.start().count;
let offset_in_item = new_scroll_top - cursor.start().height;
self.logical_scroll_top = Some(ListOffset {
item_ix,
offset_in_item,
@@ -502,9 +499,9 @@ impl StateInner {
}
fn scroll_top(&self, logical_scroll_top: &ListOffset) -> f32 {
let mut cursor = self.items.cursor::<Count, Height>();
let mut cursor = self.items.cursor::<ListItemSummary>();
cursor.seek(&Count(logical_scroll_top.item_ix), Bias::Right, &());
cursor.sum_start().0 + logical_scroll_top.offset_in_item
cursor.start().height + logical_scroll_top.offset_in_item
}
}
@@ -556,12 +553,6 @@ impl sum_tree::Summary for ListItemSummary {
}
}
impl<'a> sum_tree::Dimension<'a, ListItemSummary> for ListItemSummary {
fn add_summary(&mut self, summary: &'a ListItemSummary, _: &()) {
sum_tree::Summary::add_summary(self, summary, &());
}
}
impl<'a> sum_tree::Dimension<'a, ListItemSummary> for Count {
fn add_summary(&mut self, summary: &'a ListItemSummary, _: &()) {
self.0 += summary.count;
@@ -586,9 +577,15 @@ impl<'a> sum_tree::Dimension<'a, ListItemSummary> for Height {
}
}
impl<'a> sum_tree::SeekDimension<'a, ListItemSummary> for Height {
fn cmp(&self, other: &Self, _: &()) -> std::cmp::Ordering {
self.0.partial_cmp(&other.0).unwrap()
impl<'a> sum_tree::SeekTarget<'a, ListItemSummary, ListItemSummary> for Count {
fn cmp(&self, other: &ListItemSummary, _: &()) -> std::cmp::Ordering {
self.0.partial_cmp(&other.count).unwrap()
}
}
impl<'a> sum_tree::SeekTarget<'a, ListItemSummary, ListItemSummary> for Height {
fn cmp(&self, other: &ListItemSummary, _: &()) -> std::cmp::Ordering {
self.0.partial_cmp(&other.height).unwrap()
}
}
@@ -760,7 +757,7 @@ mod tests {
log::info!("splice({:?}, {:?})", start_ix..end_ix, new_elements);
state.splice(start_ix..end_ix, new_elements.len());
elements.splice(start_ix..end_ix, new_elements);
for (ix, item) in state.0.borrow().items.cursor::<(), ()>().enumerate() {
for (ix, item) in state.0.borrow().items.cursor::<()>().enumerate() {
if let ListItem::Rendered(element) = item {
let (expected_id, _) = elements[ix];
element.with_metadata(|metadata: Option<&usize>| {
@@ -797,7 +794,7 @@ mod tests {
let mut first_rendered_element_top = None;
let mut last_rendered_element_bottom = None;
assert_eq!(state.items.summary().count, elements.borrow().len());
for (ix, item) in state.items.cursor::<(), ()>().enumerate() {
for (ix, item) in state.items.cursor::<()>().enumerate() {
match item {
ListItem::Unrendered => {
let item_bottom = item_top;
+101 -64
View File
@@ -3,6 +3,7 @@ mod cursor;
use arrayvec::ArrayVec;
pub use cursor::Cursor;
pub use cursor::FilterCursor;
use std::marker::PhantomData;
use std::{cmp::Ordering, fmt, iter::FromIterator, sync::Arc};
#[cfg(test)]
@@ -32,17 +33,58 @@ pub trait Dimension<'a, S: Summary>: Clone + fmt::Debug + Default {
fn add_summary(&mut self, _summary: &'a S, _: &S::Context);
}
impl<'a, T: Summary> Dimension<'a, T> for T {
fn add_summary(&mut self, summary: &'a T, cx: &T::Context) {
Summary::add_summary(self, summary, cx);
}
}
pub trait SeekTarget<'a, S: Summary, D: Dimension<'a, S>>: fmt::Debug {
fn cmp(&self, cursor_location: &D, cx: &S::Context) -> Ordering;
}
impl<'a, S: Summary, D: Dimension<'a, S> + Ord> SeekTarget<'a, S, D> for D {
fn cmp(&self, cursor_location: &Self, _: &S::Context) -> Ordering {
Ord::cmp(self, cursor_location)
}
}
impl<'a, T: Summary> Dimension<'a, T> for () {
fn add_summary(&mut self, _: &'a T, _: &T::Context) {}
}
pub trait SeekDimension<'a, T: Summary>: Dimension<'a, T> {
fn cmp(&self, other: &Self, cx: &T::Context) -> Ordering;
impl<'a, T: Summary, D1: Dimension<'a, T>, D2: Dimension<'a, T>> Dimension<'a, T> for (D1, D2) {
fn add_summary(&mut self, summary: &'a T, cx: &T::Context) {
self.0.add_summary(summary, cx);
self.1.add_summary(summary, cx);
}
}
impl<'a, S: Summary, T: Dimension<'a, S> + Ord> SeekDimension<'a, S> for T {
fn cmp(&self, other: &Self, _ctx: &S::Context) -> Ordering {
Ord::cmp(self, other)
impl<'a, S: Summary, D1: SeekTarget<'a, S, D1> + Dimension<'a, S>, D2: Dimension<'a, S>>
SeekTarget<'a, S, (D1, D2)> for D1
{
fn cmp(&self, cursor_location: &(D1, D2), cx: &S::Context) -> Ordering {
self.cmp(&cursor_location.0, cx)
}
}
struct End<D>(PhantomData<D>);
impl<D> End<D> {
fn new() -> Self {
Self(PhantomData)
}
}
impl<'a, S: Summary, D: Dimension<'a, S>> SeekTarget<'a, S, D> for End<D> {
fn cmp(&self, _: &D, _: &S::Context) -> Ordering {
Ordering::Greater
}
}
impl<D> fmt::Debug for End<D> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("End").finish()
}
}
@@ -99,7 +141,7 @@ impl<T: Item> SumTree<T> {
#[allow(unused)]
pub fn items(&self, cx: &<T::Summary as Summary>::Context) -> Vec<T> {
let mut items = Vec::new();
let mut cursor = self.cursor::<(), ()>();
let mut cursor = self.cursor::<()>();
cursor.next(cx);
while let Some(item) = cursor.item() {
items.push(item.clone());
@@ -108,10 +150,9 @@ impl<T: Item> SumTree<T> {
items
}
pub fn cursor<'a, S, U>(&'a self) -> Cursor<T, S, U>
pub fn cursor<'a, S>(&'a self) -> Cursor<T, S>
where
S: Dimension<'a, T::Summary>,
U: Dimension<'a, T::Summary>,
{
Cursor::new(self)
}
@@ -230,7 +271,7 @@ impl<T: Item> SumTree<T> {
}) = leaf.as_mut()
{
let item_summary = item.summary();
summary.add_summary(&item_summary, cx);
<T::Summary as Summary>::add_summary(summary, &item_summary, cx);
items.push(item);
item_summaries.push(item_summary);
} else {
@@ -281,7 +322,7 @@ impl<T: Item> SumTree<T> {
..
} => {
let other_node = other.0.clone();
summary.add_summary(other_node.summary(), cx);
<T::Summary as Summary>::add_summary(summary, other_node.summary(), cx);
let height_delta = *height - other_node.height();
let mut summaries_to_append = ArrayVec::<T::Summary, { 2 * TREE_BASE }>::new();
@@ -378,7 +419,7 @@ impl<T: Item> SumTree<T> {
item_summaries: right_summaries,
})))
} else {
summary.add_summary(other_node.summary(), cx);
<T::Summary as Summary>::add_summary(summary, other_node.summary(), cx);
items.extend(other_node.items().iter().cloned());
item_summaries.extend(other_node.child_summaries().iter().cloned());
None
@@ -430,7 +471,7 @@ impl<T: KeyedItem> SumTree<T> {
pub fn insert_or_replace(&mut self, item: T, cx: &<T::Summary as Summary>::Context) -> bool {
let mut replaced = false;
*self = {
let mut cursor = self.cursor::<T::Key, ()>();
let mut cursor = self.cursor::<T::Key>();
let mut new_tree = cursor.slice(&item.key(), Bias::Left, cx);
if cursor
.item()
@@ -459,7 +500,7 @@ impl<T: KeyedItem> SumTree<T> {
edits.sort_unstable_by_key(|item| item.key());
*self = {
let mut cursor = self.cursor::<T::Key, ()>();
let mut cursor = self.cursor::<T::Key>();
let mut new_tree = SumTree::new();
let mut buffered_items = Vec::new();
@@ -502,7 +543,7 @@ impl<T: KeyedItem> SumTree<T> {
}
pub fn get(&self, key: &T::Key, cx: &<T::Summary as Summary>::Context) -> Option<&T> {
let mut cursor = self.cursor::<T::Key, ()>();
let mut cursor = self.cursor::<T::Key>();
if cursor.seek(key, Bias::Left, cx) {
cursor.item()
} else {
@@ -617,7 +658,6 @@ mod tests {
use super::*;
use rand::{distributions, prelude::*};
use std::cmp;
use std::ops::Add;
#[test]
fn test_extend_and_push_tree() {
@@ -655,7 +695,7 @@ mod tests {
reference_items.splice(splice_start..splice_end, new_items.clone());
tree = {
let mut cursor = tree.cursor::<Count, ()>();
let mut cursor = tree.cursor::<Count>();
let mut new_tree = cursor.slice(&Count(splice_start), Bias::Right, &());
new_tree.extend(new_items, &());
cursor.seek(&Count(splice_end), Bias::Right, &());
@@ -681,11 +721,11 @@ mod tests {
let mut pos = rng.gen_range(0..tree.extent::<Count>(&()).0 + 1);
let mut before_start = false;
let mut cursor = tree.cursor::<Count, Count>();
let mut cursor = tree.cursor::<Count>();
cursor.seek(&Count(pos), Bias::Right, &());
for i in 0..10 {
assert_eq!(cursor.sum_start().0, pos);
assert_eq!(cursor.start().0, pos);
if pos > 0 {
assert_eq!(cursor.prev_item().unwrap(), &reference_items[pos - 1]);
@@ -721,14 +761,14 @@ mod tests {
let start_bias = if rng.gen() { Bias::Left } else { Bias::Right };
let end_bias = if rng.gen() { Bias::Left } else { Bias::Right };
let mut cursor = tree.cursor::<Count, ()>();
let mut cursor = tree.cursor::<Count>();
cursor.seek(&Count(start), start_bias, &());
let slice = cursor.slice(&Count(end), end_bias, &());
cursor.seek(&Count(start), start_bias, &());
let summary = cursor.summary::<Sum>(&Count(end), end_bias, &());
let summary = cursor.summary::<_, Sum>(&Count(end), end_bias, &());
assert_eq!(summary, slice.summary().sum);
assert_eq!(summary.0, slice.summary().sum);
}
}
@@ -736,42 +776,42 @@ mod tests {
fn test_cursor() {
// Empty tree
let tree = SumTree::<u8>::new();
let mut cursor = tree.cursor::<Count, Sum>();
let mut cursor = tree.cursor::<IntegersSummary>();
assert_eq!(
cursor.slice(&Count(0), Bias::Right, &()).items(&()),
Vec::<u8>::new()
);
assert_eq!(cursor.item(), None);
assert_eq!(cursor.prev_item(), None);
assert_eq!(cursor.sum_start(), &Sum(0));
assert_eq!(cursor.start().sum, 0);
// Single-element tree
let mut tree = SumTree::<u8>::new();
tree.extend(vec![1], &());
let mut cursor = tree.cursor::<Count, Sum>();
let mut cursor = tree.cursor::<IntegersSummary>();
assert_eq!(
cursor.slice(&Count(0), Bias::Right, &()).items(&()),
Vec::<u8>::new()
);
assert_eq!(cursor.item(), Some(&1));
assert_eq!(cursor.prev_item(), None);
assert_eq!(cursor.sum_start(), &Sum(0));
assert_eq!(cursor.start().sum, 0);
cursor.next(&());
assert_eq!(cursor.item(), None);
assert_eq!(cursor.prev_item(), Some(&1));
assert_eq!(cursor.sum_start(), &Sum(1));
assert_eq!(cursor.start().sum, 1);
cursor.prev(&());
assert_eq!(cursor.item(), Some(&1));
assert_eq!(cursor.prev_item(), None);
assert_eq!(cursor.sum_start(), &Sum(0));
assert_eq!(cursor.start().sum, 0);
let mut cursor = tree.cursor::<Count, Sum>();
let mut cursor = tree.cursor::<IntegersSummary>();
assert_eq!(cursor.slice(&Count(1), Bias::Right, &()).items(&()), [1]);
assert_eq!(cursor.item(), None);
assert_eq!(cursor.prev_item(), Some(&1));
assert_eq!(cursor.sum_start(), &Sum(1));
assert_eq!(cursor.start().sum, 1);
cursor.seek(&Count(0), Bias::Right, &());
assert_eq!(
@@ -782,80 +822,80 @@ mod tests {
);
assert_eq!(cursor.item(), None);
assert_eq!(cursor.prev_item(), Some(&1));
assert_eq!(cursor.sum_start(), &Sum(1));
assert_eq!(cursor.start().sum, 1);
// Multiple-element tree
let mut tree = SumTree::new();
tree.extend(vec![1, 2, 3, 4, 5, 6], &());
let mut cursor = tree.cursor::<Count, Sum>();
let mut cursor = tree.cursor::<IntegersSummary>();
assert_eq!(cursor.slice(&Count(2), Bias::Right, &()).items(&()), [1, 2]);
assert_eq!(cursor.item(), Some(&3));
assert_eq!(cursor.prev_item(), Some(&2));
assert_eq!(cursor.sum_start(), &Sum(3));
assert_eq!(cursor.start().sum, 3);
cursor.next(&());
assert_eq!(cursor.item(), Some(&4));
assert_eq!(cursor.prev_item(), Some(&3));
assert_eq!(cursor.sum_start(), &Sum(6));
assert_eq!(cursor.start().sum, 6);
cursor.next(&());
assert_eq!(cursor.item(), Some(&5));
assert_eq!(cursor.prev_item(), Some(&4));
assert_eq!(cursor.sum_start(), &Sum(10));
assert_eq!(cursor.start().sum, 10);
cursor.next(&());
assert_eq!(cursor.item(), Some(&6));
assert_eq!(cursor.prev_item(), Some(&5));
assert_eq!(cursor.sum_start(), &Sum(15));
assert_eq!(cursor.start().sum, 15);
cursor.next(&());
cursor.next(&());
assert_eq!(cursor.item(), None);
assert_eq!(cursor.prev_item(), Some(&6));
assert_eq!(cursor.sum_start(), &Sum(21));
assert_eq!(cursor.start().sum, 21);
cursor.prev(&());
assert_eq!(cursor.item(), Some(&6));
assert_eq!(cursor.prev_item(), Some(&5));
assert_eq!(cursor.sum_start(), &Sum(15));
assert_eq!(cursor.start().sum, 15);
cursor.prev(&());
assert_eq!(cursor.item(), Some(&5));
assert_eq!(cursor.prev_item(), Some(&4));
assert_eq!(cursor.sum_start(), &Sum(10));
assert_eq!(cursor.start().sum, 10);
cursor.prev(&());
assert_eq!(cursor.item(), Some(&4));
assert_eq!(cursor.prev_item(), Some(&3));
assert_eq!(cursor.sum_start(), &Sum(6));
assert_eq!(cursor.start().sum, 6);
cursor.prev(&());
assert_eq!(cursor.item(), Some(&3));
assert_eq!(cursor.prev_item(), Some(&2));
assert_eq!(cursor.sum_start(), &Sum(3));
assert_eq!(cursor.start().sum, 3);
cursor.prev(&());
assert_eq!(cursor.item(), Some(&2));
assert_eq!(cursor.prev_item(), Some(&1));
assert_eq!(cursor.sum_start(), &Sum(1));
assert_eq!(cursor.start().sum, 1);
cursor.prev(&());
assert_eq!(cursor.item(), Some(&1));
assert_eq!(cursor.prev_item(), None);
assert_eq!(cursor.sum_start(), &Sum(0));
assert_eq!(cursor.start().sum, 0);
cursor.prev(&());
assert_eq!(cursor.item(), None);
assert_eq!(cursor.prev_item(), None);
assert_eq!(cursor.sum_start(), &Sum(0));
assert_eq!(cursor.start().sum, 0);
cursor.next(&());
assert_eq!(cursor.item(), Some(&1));
assert_eq!(cursor.prev_item(), None);
assert_eq!(cursor.sum_start(), &Sum(0));
assert_eq!(cursor.start().sum, 0);
let mut cursor = tree.cursor::<Count, Sum>();
let mut cursor = tree.cursor::<IntegersSummary>();
assert_eq!(
cursor
.slice(&tree.extent::<Count>(&()), Bias::Right, &())
@@ -864,7 +904,7 @@ mod tests {
);
assert_eq!(cursor.item(), None);
assert_eq!(cursor.prev_item(), Some(&6));
assert_eq!(cursor.sum_start(), &Sum(21));
assert_eq!(cursor.start().sum, 21);
cursor.seek(&Count(3), Bias::Right, &());
assert_eq!(
@@ -875,7 +915,7 @@ mod tests {
);
assert_eq!(cursor.item(), None);
assert_eq!(cursor.prev_item(), Some(&6));
assert_eq!(cursor.sum_start(), &Sum(21));
assert_eq!(cursor.start().sum, 21);
// Seeking can bias left or right
cursor.seek(&Count(1), Bias::Left, &());
@@ -922,8 +962,8 @@ mod tests {
#[derive(Clone, Default, Debug)]
pub struct IntegersSummary {
count: Count,
sum: Sum,
count: usize,
sum: usize,
contains_even: bool,
max: u8,
}
@@ -939,8 +979,8 @@ mod tests {
fn summary(&self) -> Self::Summary {
IntegersSummary {
count: Count(1),
sum: Sum(*self as usize),
count: 1,
sum: *self as usize,
contains_even: (*self & 1) == 0,
max: *self,
}
@@ -959,8 +999,8 @@ mod tests {
type Context = ();
fn add_summary(&mut self, other: &Self, _: &()) {
self.count.0 += &other.count.0;
self.sum.0 += &other.sum.0;
self.count += other.count;
self.sum += other.sum;
self.contains_even |= other.contains_even;
self.max = cmp::max(self.max, other.max);
}
@@ -974,22 +1014,19 @@ mod tests {
impl<'a> Dimension<'a, IntegersSummary> for Count {
fn add_summary(&mut self, summary: &IntegersSummary, _: &()) {
self.0 += summary.count.0;
self.0 += summary.count;
}
}
impl<'a> SeekTarget<'a, IntegersSummary, IntegersSummary> for Count {
fn cmp(&self, cursor_location: &IntegersSummary, _: &()) -> Ordering {
self.0.cmp(&cursor_location.count)
}
}
impl<'a> Dimension<'a, IntegersSummary> for Sum {
fn add_summary(&mut self, summary: &IntegersSummary, _: &()) {
self.0 += summary.sum.0;
}
}
impl<'a> Add<&'a Self> for Sum {
type Output = Self;
fn add(mut self, other: &Self) -> Self {
self.0 += other.0;
self
self.0 += summary.sum;
}
}
}
+107 -177
View File
@@ -3,51 +3,31 @@ use arrayvec::ArrayVec;
use std::{cmp::Ordering, sync::Arc};
#[derive(Clone)]
struct StackEntry<'a, T: Item, S, U> {
struct StackEntry<'a, T: Item, D> {
tree: &'a SumTree<T>,
index: usize,
seek_dimension: S,
sum_dimension: U,
}
impl<'a, T, S, U> StackEntry<'a, T, S, U>
where
T: Item,
S: SeekDimension<'a, T::Summary>,
U: SeekDimension<'a, T::Summary>,
{
fn swap_dimensions(self) -> StackEntry<'a, T, U, S> {
StackEntry {
tree: self.tree,
index: self.index,
seek_dimension: self.sum_dimension,
sum_dimension: self.seek_dimension,
}
}
position: D,
}
#[derive(Clone)]
pub struct Cursor<'a, T: Item, S, U> {
pub struct Cursor<'a, T: Item, D> {
tree: &'a SumTree<T>,
stack: ArrayVec<StackEntry<'a, T, S, U>, 16>,
seek_dimension: S,
sum_dimension: U,
stack: ArrayVec<StackEntry<'a, T, D>, 16>,
position: D,
did_seek: bool,
at_end: bool,
}
impl<'a, T, S, U> Cursor<'a, T, S, U>
impl<'a, T, D> Cursor<'a, T, D>
where
T: Item,
S: Dimension<'a, T::Summary>,
U: Dimension<'a, T::Summary>,
D: Dimension<'a, T::Summary>,
{
pub fn new(tree: &'a SumTree<T>) -> Self {
Self {
tree,
stack: ArrayVec::new(),
seek_dimension: S::default(),
sum_dimension: U::default(),
position: D::default(),
did_seek: false,
at_end: false,
}
@@ -57,35 +37,20 @@ where
self.did_seek = false;
self.at_end = false;
self.stack.truncate(0);
self.seek_dimension = S::default();
self.sum_dimension = U::default();
self.position = D::default();
}
pub fn seek_start(&self) -> &S {
&self.seek_dimension
pub fn start(&self) -> &D {
&self.position
}
pub fn seek_end(&self, cx: &<T::Summary as Summary>::Context) -> S {
pub fn end(&self, cx: &<T::Summary as Summary>::Context) -> D {
if let Some(item_summary) = self.item_summary() {
let mut end = self.seek_start().clone();
let mut end = self.start().clone();
end.add_summary(item_summary, cx);
end
} else {
self.seek_start().clone()
}
}
pub fn sum_start(&self) -> &U {
&self.sum_dimension
}
pub fn sum_end(&self, cx: &<T::Summary as Summary>::Context) -> U {
if let Some(item_summary) = self.item_summary() {
let mut end = self.sum_start().clone();
end.add_summary(item_summary, cx);
end
} else {
self.sum_start().clone()
self.start().clone()
}
}
@@ -167,8 +132,7 @@ where
assert!(self.did_seek, "Must seek before calling this method");
if self.at_end {
self.seek_dimension = S::default();
self.sum_dimension = U::default();
self.position = D::default();
self.descend_to_last_item(self.tree, cx);
self.at_end = false;
} else {
@@ -176,17 +140,10 @@ where
if entry.index > 0 {
let new_index = entry.index - 1;
if let Some(StackEntry {
seek_dimension,
sum_dimension,
..
}) = self.stack.last()
{
self.seek_dimension = seek_dimension.clone();
self.sum_dimension = sum_dimension.clone();
if let Some(StackEntry { position, .. }) = self.stack.last() {
self.position = position.clone();
} else {
self.seek_dimension = S::default();
self.sum_dimension = U::default();
self.position = D::default();
}
match entry.tree.0.as_ref() {
@@ -196,27 +153,23 @@ where
..
} => {
for summary in &child_summaries[0..new_index] {
self.seek_dimension.add_summary(summary, cx);
self.sum_dimension.add_summary(summary, cx);
self.position.add_summary(summary, cx);
}
self.stack.push(StackEntry {
tree: entry.tree,
index: new_index,
seek_dimension: self.seek_dimension.clone(),
sum_dimension: self.sum_dimension.clone(),
position: self.position.clone(),
});
self.descend_to_last_item(&child_trees[new_index], cx);
}
Node::Leaf { item_summaries, .. } => {
for item_summary in &item_summaries[0..new_index] {
self.seek_dimension.add_summary(item_summary, cx);
self.sum_dimension.add_summary(item_summary, cx);
self.position.add_summary(item_summary, cx);
}
self.stack.push(StackEntry {
tree: entry.tree,
index: new_index,
seek_dimension: self.seek_dimension.clone(),
sum_dimension: self.sum_dimension.clone(),
position: self.position.clone(),
});
}
}
@@ -241,8 +194,7 @@ where
self.stack.push(StackEntry {
tree: self.tree,
index: 0,
seek_dimension: S::default(),
sum_dimension: U::default(),
position: D::default(),
});
descend = true;
self.did_seek = true;
@@ -258,8 +210,7 @@ where
..
} => {
if !descend {
entry.seek_dimension = self.seek_dimension.clone();
entry.sum_dimension = self.sum_dimension.clone();
entry.position = self.position.clone();
entry.index += 1;
}
@@ -268,8 +219,7 @@ where
if filter_node(next_summary) {
break;
} else {
self.seek_dimension.add_summary(next_summary, cx);
self.sum_dimension.add_summary(next_summary, cx);
self.position.add_summary(next_summary, cx);
}
entry.index += 1;
}
@@ -279,10 +229,8 @@ where
Node::Leaf { item_summaries, .. } => {
if !descend {
let item_summary = &item_summaries[entry.index];
self.seek_dimension.add_summary(item_summary, cx);
entry.seek_dimension.add_summary(item_summary, cx);
self.sum_dimension.add_summary(item_summary, cx);
entry.sum_dimension.add_summary(item_summary, cx);
self.position.add_summary(item_summary, cx);
entry.position.add_summary(item_summary, cx);
entry.index += 1;
}
@@ -291,10 +239,8 @@ where
if filter_node(next_item_summary) {
return;
} else {
self.seek_dimension.add_summary(next_item_summary, cx);
entry.seek_dimension.add_summary(next_item_summary, cx);
self.sum_dimension.add_summary(next_item_summary, cx);
entry.sum_dimension.add_summary(next_item_summary, cx);
self.position.add_summary(next_item_summary, cx);
entry.position.add_summary(next_item_summary, cx);
entry.index += 1;
}
} else {
@@ -310,8 +256,7 @@ where
self.stack.push(StackEntry {
tree: subtree,
index: 0,
seek_dimension: self.seek_dimension.clone(),
sum_dimension: self.sum_dimension.clone(),
position: self.position.clone(),
});
} else {
descend = false;
@@ -337,29 +282,25 @@ where
..
} => {
for summary in &child_summaries[0..child_summaries.len() - 1] {
self.seek_dimension.add_summary(summary, cx);
self.sum_dimension.add_summary(summary, cx);
self.position.add_summary(summary, cx);
}
self.stack.push(StackEntry {
tree: subtree,
index: child_trees.len() - 1,
seek_dimension: self.seek_dimension.clone(),
sum_dimension: self.sum_dimension.clone(),
position: self.position.clone(),
});
subtree = child_trees.last().unwrap();
}
Node::Leaf { item_summaries, .. } => {
let last_index = item_summaries.len().saturating_sub(1);
for item_summary in &item_summaries[0..last_index] {
self.seek_dimension.add_summary(item_summary, cx);
self.sum_dimension.add_summary(item_summary, cx);
self.position.add_summary(item_summary, cx);
}
self.stack.push(StackEntry {
tree: subtree,
index: last_index,
seek_dimension: self.seek_dimension.clone(),
sum_dimension: self.sum_dimension.clone(),
position: self.position.clone(),
});
break;
}
@@ -368,34 +309,47 @@ where
}
}
impl<'a, T, S, U> Cursor<'a, T, S, U>
impl<'a, T, D> Cursor<'a, T, D>
where
T: Item,
S: SeekDimension<'a, T::Summary>,
U: Dimension<'a, T::Summary>,
D: Dimension<'a, T::Summary>,
{
pub fn seek(&mut self, pos: &S, bias: Bias, cx: &<T::Summary as Summary>::Context) -> bool {
pub fn seek<Target>(
&mut self,
pos: &Target,
bias: Bias,
cx: &<T::Summary as Summary>::Context,
) -> bool
where
Target: SeekTarget<'a, T::Summary, D>,
{
self.reset();
self.seek_internal::<()>(Some(pos), bias, &mut SeekAggregate::None, cx)
self.seek_internal::<_, ()>(pos, bias, &mut SeekAggregate::None, cx)
}
pub fn seek_forward(
pub fn seek_forward<Target>(
&mut self,
pos: &S,
pos: &Target,
bias: Bias,
cx: &<T::Summary as Summary>::Context,
) -> bool {
self.seek_internal::<()>(Some(pos), bias, &mut SeekAggregate::None, cx)
) -> bool
where
Target: SeekTarget<'a, T::Summary, D>,
{
self.seek_internal::<_, ()>(pos, bias, &mut SeekAggregate::None, cx)
}
pub fn slice(
pub fn slice<Target>(
&mut self,
end: &S,
end: &Target,
bias: Bias,
cx: &<T::Summary as Summary>::Context,
) -> SumTree<T> {
) -> SumTree<T>
where
Target: SeekTarget<'a, T::Summary, D>,
{
let mut slice = SeekAggregate::Slice(SumTree::new());
self.seek_internal::<()>(Some(end), bias, &mut slice, cx);
self.seek_internal::<_, ()>(end, bias, &mut slice, cx);
if let SeekAggregate::Slice(slice) = slice {
slice
} else {
@@ -405,7 +359,7 @@ where
pub fn suffix(&mut self, cx: &<T::Summary as Summary>::Context) -> SumTree<T> {
let mut slice = SeekAggregate::Slice(SumTree::new());
self.seek_internal::<()>(None, Bias::Right, &mut slice, cx);
self.seek_internal::<_, ()>(&End::new(), Bias::Right, &mut slice, cx);
if let SeekAggregate::Slice(slice) = slice {
slice
} else {
@@ -413,12 +367,18 @@ where
}
}
pub fn summary<D>(&mut self, end: &S, bias: Bias, cx: &<T::Summary as Summary>::Context) -> D
pub fn summary<Target, Output>(
&mut self,
end: &Target,
bias: Bias,
cx: &<T::Summary as Summary>::Context,
) -> Output
where
D: Dimension<'a, T::Summary>,
Target: SeekTarget<'a, T::Summary, D>,
Output: Dimension<'a, T::Summary>,
{
let mut summary = SeekAggregate::Summary(D::default());
self.seek_internal(Some(end), bias, &mut summary, cx);
let mut summary = SeekAggregate::Summary(Output::default());
self.seek_internal(end, bias, &mut summary, cx);
if let SeekAggregate::Summary(summary) = summary {
summary
} else {
@@ -426,32 +386,30 @@ where
}
}
fn seek_internal<D>(
fn seek_internal<Target, Output>(
&mut self,
target: Option<&S>,
target: &Target,
bias: Bias,
aggregate: &mut SeekAggregate<T, D>,
aggregate: &mut SeekAggregate<T, Output>,
cx: &<T::Summary as Summary>::Context,
) -> bool
where
D: Dimension<'a, T::Summary>,
Target: SeekTarget<'a, T::Summary, D>,
Output: Dimension<'a, T::Summary>,
{
if let Some(target) = target {
debug_assert!(
target.cmp(&self.seek_dimension, cx) >= Ordering::Equal,
"cannot seek backward from {:?} to {:?}",
self.seek_dimension,
target
);
}
debug_assert!(
target.cmp(&self.position, cx) >= Ordering::Equal,
"cannot seek backward from {:?} to {:?}",
self.position,
target
);
if !self.did_seek {
self.did_seek = true;
self.stack.push(StackEntry {
tree: self.tree,
index: 0,
seek_dimension: Default::default(),
sum_dimension: Default::default(),
position: Default::default(),
});
}
@@ -471,16 +429,14 @@ where
.iter()
.zip(&child_summaries[entry.index..])
{
let mut child_end = self.seek_dimension.clone();
let mut child_end = self.position.clone();
child_end.add_summary(&child_summary, cx);
let comparison =
target.map_or(Ordering::Greater, |t| t.cmp(&child_end, cx));
let comparison = target.cmp(&child_end, cx);
if comparison == Ordering::Greater
|| (comparison == Ordering::Equal && bias == Bias::Right)
{
self.seek_dimension = child_end;
self.sum_dimension.add_summary(child_summary, cx);
self.position = child_end;
match aggregate {
SeekAggregate::None => {}
SeekAggregate::Slice(slice) => {
@@ -491,14 +447,12 @@ where
}
}
entry.index += 1;
entry.seek_dimension = self.seek_dimension.clone();
entry.sum_dimension = self.sum_dimension.clone();
entry.position = self.position.clone();
} else {
self.stack.push(StackEntry {
tree: child_tree,
index: 0,
seek_dimension: self.seek_dimension.clone(),
sum_dimension: self.sum_dimension.clone(),
position: self.position.clone(),
});
ascending = false;
continue 'outer;
@@ -521,25 +475,24 @@ where
.iter()
.zip(&item_summaries[entry.index..])
{
let mut child_end = self.seek_dimension.clone();
let mut child_end = self.position.clone();
child_end.add_summary(item_summary, cx);
let comparison =
target.map_or(Ordering::Greater, |t| t.cmp(&child_end, cx));
let comparison = target.cmp(&child_end, cx);
if comparison == Ordering::Greater
|| (comparison == Ordering::Equal && bias == Bias::Right)
{
self.seek_dimension = child_end;
self.sum_dimension.add_summary(item_summary, cx);
self.position = child_end;
match aggregate {
SeekAggregate::None => {}
SeekAggregate::Slice(_) => {
slice_items.push(item.clone());
slice_item_summaries.push(item_summary.clone());
slice_items_summary
.as_mut()
.unwrap()
.add_summary(item_summary, cx);
<T::Summary as Summary>::add_summary(
slice_items_summary.as_mut().unwrap(),
item_summary,
cx,
);
}
SeekAggregate::Summary(summary) => {
summary.add_summary(item_summary, cx);
@@ -583,23 +536,22 @@ where
self.at_end = self.stack.is_empty();
debug_assert!(self.stack.is_empty() || self.stack.last().unwrap().tree.0.is_leaf());
let mut end = self.seek_dimension.clone();
let mut end = self.position.clone();
if bias == Bias::Left {
if let Some(summary) = self.item_summary() {
end.add_summary(summary, cx);
}
}
target.map_or(false, |t| t.cmp(&end, cx) == Ordering::Equal)
target.cmp(&end, cx) == Ordering::Equal
}
}
impl<'a, T, S, Seek, Sum> Iterator for Cursor<'a, T, Seek, Sum>
impl<'a, T, S, D> Iterator for Cursor<'a, T, D>
where
T: Item<Summary = S>,
S: Summary<Context = ()>,
Seek: Dimension<'a, T::Summary>,
Sum: Dimension<'a, T::Summary>,
D: Dimension<'a, T::Summary>,
{
type Item = &'a T;
@@ -617,45 +569,23 @@ where
}
}
impl<'a, T, S, U> Cursor<'a, T, S, U>
where
T: Item,
S: SeekDimension<'a, T::Summary>,
U: SeekDimension<'a, T::Summary>,
{
pub fn swap_dimensions(self) -> Cursor<'a, T, U, S> {
Cursor {
tree: self.tree,
stack: self
.stack
.into_iter()
.map(StackEntry::swap_dimensions)
.collect(),
seek_dimension: self.sum_dimension,
sum_dimension: self.seek_dimension,
did_seek: self.did_seek,
at_end: self.at_end,
}
}
}
pub struct FilterCursor<'a, F: Fn(&T::Summary) -> bool, T: Item, U> {
cursor: Cursor<'a, T, (), U>,
pub struct FilterCursor<'a, F: Fn(&T::Summary) -> bool, T: Item, D> {
cursor: Cursor<'a, T, D>,
filter_node: F,
}
impl<'a, F, T, U> FilterCursor<'a, F, T, U>
impl<'a, F, T, D> FilterCursor<'a, F, T, D>
where
F: Fn(&T::Summary) -> bool,
T: Item,
U: Dimension<'a, T::Summary>,
D: Dimension<'a, T::Summary>,
{
pub fn new(
tree: &'a SumTree<T>,
filter_node: F,
cx: &<T::Summary as Summary>::Context,
) -> Self {
let mut cursor = tree.cursor::<(), U>();
let mut cursor = tree.cursor::<D>();
cursor.next_internal(&filter_node, cx);
Self {
cursor,
@@ -663,8 +593,8 @@ where
}
}
pub fn start(&self) -> &U {
self.cursor.sum_start()
pub fn start(&self) -> &D {
self.cursor.start()
}
pub fn item(&self) -> Option<&'a T> {