This reduces the size of cursor by a usize when the summary does not
require a context making Cursor usages and constructions slightly more
efficient.
This change is a bit annoying though, as Rust has no means of
specializing, so this uses a `ContextlessSummary` trait with a blanket
impl while turning the `Context` into a GAT `Context<'a>`. This means
`Summary` implies are a bit more verbose now while contextless ones are
slimmer. It does come with the downside that the lifetime in the GAT is
always considered invariant, so some lifetime splitting occurred due to
that.
```
push/4096 time: [352.65 µs 360.87 µs 367.80 µs]
thrpt: [10.621 MiB/s 10.825 MiB/s 11.077 MiB/s]
change:
time: [-2.6633% -1.3640% -0.0561%] (p = 0.05 < 0.05)
thrpt: [+0.0561% +1.3828% +2.7361%]
Change within noise threshold.
Found 16 outliers among 100 measurements (16.00%)
7 (7.00%) low severe
3 (3.00%) low mild
2 (2.00%) high mild
4 (4.00%) high severe
push/65536 time: [1.2917 ms 1.2949 ms 1.2979 ms]
thrpt: [48.156 MiB/s 48.267 MiB/s 48.387 MiB/s]
change:
time: [+1.4428% +1.9844% +2.5299%] (p = 0.00 < 0.05)
thrpt: [-2.4675% -1.9458% -1.4223%]
Performance has regressed.
Found 3 outliers among 100 measurements (3.00%)
1 (1.00%) low severe
1 (1.00%) low mild
1 (1.00%) high severe
append/4096 time: [677.87 ns 678.87 ns 679.83 ns]
thrpt: [5.6112 GiB/s 5.6192 GiB/s 5.6274 GiB/s]
change:
time: [-0.8924% -0.5017% -0.1705%] (p = 0.00 < 0.05)
thrpt: [+0.1708% +0.5043% +0.9004%]
Change within noise threshold.
Found 2 outliers among 100 measurements (2.00%)
1 (1.00%) low mild
1 (1.00%) high mild
append/65536 time: [9.3275 µs 9.3406 µs 9.3536 µs]
thrpt: [6.5253 GiB/s 6.5344 GiB/s 6.5435 GiB/s]
change:
time: [+0.5409% +0.7215% +0.9054%] (p = 0.00 < 0.05)
thrpt: [-0.8973% -0.7163% -0.5380%]
Change within noise threshold.
slice/4096 time: [27.673 µs 27.791 µs 27.907 µs]
thrpt: [139.97 MiB/s 140.56 MiB/s 141.16 MiB/s]
change:
time: [-1.1065% -0.6725% -0.2429%] (p = 0.00 < 0.05)
thrpt: [+0.2435% +0.6770% +1.1189%]
Change within noise threshold.
Found 5 outliers among 100 measurements (5.00%)
4 (4.00%) low mild
1 (1.00%) high mild
slice/65536 time: [507.55 µs 517.40 µs 535.60 µs]
thrpt: [116.69 MiB/s 120.80 MiB/s 123.14 MiB/s]
change:
time: [-1.3489% +0.0599% +2.2591%] (p = 0.96 > 0.05)
thrpt: [-2.2092% -0.0598% +1.3674%]
No change in performance detected.
Found 8 outliers among 100 measurements (8.00%)
5 (5.00%) low mild
2 (2.00%) high mild
1 (1.00%) high severe
bytes_in_range/4096 time: [3.3917 µs 3.4108 µs 3.4313 µs]
thrpt: [1.1117 GiB/s 1.1184 GiB/s 1.1247 GiB/s]
change:
time: [-5.3466% -4.7193% -4.1262%] (p = 0.00 < 0.05)
thrpt: [+4.3038% +4.9531% +5.6487%]
Performance has improved.
Found 6 outliers among 100 measurements (6.00%)
1 (1.00%) low mild
5 (5.00%) high mild
bytes_in_range/65536 time: [88.175 µs 88.613 µs 89.111 µs]
thrpt: [701.37 MiB/s 705.31 MiB/s 708.82 MiB/s]
change:
time: [-0.6935% +0.3769% +1.4655%] (p = 0.50 > 0.05)
thrpt: [-1.4443% -0.3755% +0.6984%]
No change in performance detected.
Found 2 outliers among 100 measurements (2.00%)
2 (2.00%) high mild
chars/4096 time: [678.70 ns 680.38 ns 682.08 ns]
thrpt: [5.5927 GiB/s 5.6067 GiB/s 5.6206 GiB/s]
change:
time: [-0.6969% -0.2755% +0.1485%] (p = 0.20 > 0.05)
thrpt: [-0.1483% +0.2763% +0.7018%]
No change in performance detected.
Found 9 outliers among 100 measurements (9.00%)
5 (5.00%) low mild
4 (4.00%) high mild
chars/65536 time: [12.720 µs 12.775 µs 12.830 µs]
thrpt: [4.7573 GiB/s 4.7778 GiB/s 4.7983 GiB/s]
change:
time: [-0.6172% -0.1110% +0.4179%] (p = 0.68 > 0.05)
thrpt: [-0.4162% +0.1112% +0.6211%]
No change in performance detected.
Found 2 outliers among 100 measurements (2.00%)
1 (1.00%) low mild
1 (1.00%) high mild
clip_point/4096 time: [33.240 µs 33.310 µs 33.394 µs]
thrpt: [116.98 MiB/s 117.27 MiB/s 117.52 MiB/s]
change:
time: [-2.8892% -2.6305% -2.3438%] (p = 0.00 < 0.05)
thrpt: [+2.4000% +2.7015% +2.9751%]
Performance has improved.
Found 12 outliers among 100 measurements (12.00%)
1 (1.00%) low mild
4 (4.00%) high mild
7 (7.00%) high severe
clip_point/65536 time: [1.6531 ms 1.6586 ms 1.6640 ms]
thrpt: [37.560 MiB/s 37.683 MiB/s 37.808 MiB/s]
change:
time: [-6.6381% -5.9395% -5.2680%] (p = 0.00 < 0.05)
thrpt: [+5.5610% +6.3146% +7.1100%]
Performance has improved.
Found 7 outliers among 100 measurements (7.00%)
1 (1.00%) low mild
2 (2.00%) high mild
4 (4.00%) high severe
point_to_offset/4096 time: [11.586 µs 11.603 µs 11.621 µs]
thrpt: [336.15 MiB/s 336.67 MiB/s 337.16 MiB/s]
change:
time: [-14.289% -14.111% -13.939%] (p = 0.00 < 0.05)
thrpt: [+16.197% +16.429% +16.672%]
Performance has improved.
Found 12 outliers among 100 measurements (12.00%)
3 (3.00%) low severe
5 (5.00%) low mild
4 (4.00%) high mild
point_to_offset/65536 time: [527.74 µs 532.08 µs 536.51 µs]
thrpt: [116.49 MiB/s 117.46 MiB/s 118.43 MiB/s]
change:
time: [-6.7825% -4.6235% -2.3533%] (p = 0.00 < 0.05)
thrpt: [+2.4100% +4.8477% +7.2760%]
Performance has improved.
Found 8 outliers among 100 measurements (8.00%)
4 (4.00%) high mild
4 (4.00%) high severe
cursor/4096 time: [16.154 µs 16.192 µs 16.232 µs]
thrpt: [240.66 MiB/s 241.24 MiB/s 241.81 MiB/s]
change:
time: [-3.2536% -2.9145% -2.5526%] (p = 0.00 < 0.05)
thrpt: [+2.6194% +3.0019% +3.3630%]
Performance has improved.
Found 5 outliers among 100 measurements (5.00%)
1 (1.00%) low mild
2 (2.00%) high mild
2 (2.00%) high severe
cursor/65536 time: [509.60 µs 511.24 µs 512.93 µs]
thrpt: [121.85 MiB/s 122.25 MiB/s 122.65 MiB/s]
change:
time: [-7.3677% -6.6017% -5.7840%] (p = 0.00 < 0.05)
thrpt: [+6.1391% +7.0683% +7.9537%]
Performance has improved.
Found 6 outliers among 100 measurements (6.00%)
3 (3.00%) high mild
3 (3.00%) high severe
```
Release Notes:
- N/A *or* Added/Fixed/Improved ...
818 lines
24 KiB
Rust
818 lines
24 KiB
Rust
use super::*;
|
|
use arrayvec::ArrayVec;
|
|
use std::{cmp::Ordering, mem, sync::Arc};
|
|
|
|
#[derive(Clone)]
|
|
struct StackEntry<'a, T: Item, D> {
|
|
tree: &'a SumTree<T>,
|
|
index: u32,
|
|
position: D,
|
|
}
|
|
|
|
impl<'a, T: Item, D> StackEntry<'a, T, D> {
|
|
#[inline]
|
|
fn index(&self) -> usize {
|
|
self.index as usize
|
|
}
|
|
}
|
|
|
|
impl<T: Item + fmt::Debug, D: fmt::Debug> fmt::Debug for StackEntry<'_, T, D> {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
f.debug_struct("StackEntry")
|
|
.field("index", &self.index)
|
|
.field("position", &self.position)
|
|
.finish()
|
|
}
|
|
}
|
|
|
|
#[derive(Clone)]
|
|
pub struct Cursor<'a, 'b, T: Item, D> {
|
|
tree: &'a SumTree<T>,
|
|
stack: ArrayVec<StackEntry<'a, T, D>, 16>,
|
|
position: D,
|
|
did_seek: bool,
|
|
at_end: bool,
|
|
cx: <T::Summary as Summary>::Context<'b>,
|
|
}
|
|
|
|
impl<T: Item + fmt::Debug, D: fmt::Debug> fmt::Debug for Cursor<'_, '_, T, D>
|
|
where
|
|
T::Summary: fmt::Debug,
|
|
{
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
f.debug_struct("Cursor")
|
|
.field("tree", &self.tree)
|
|
.field("stack", &self.stack)
|
|
.field("position", &self.position)
|
|
.field("did_seek", &self.did_seek)
|
|
.field("at_end", &self.at_end)
|
|
.finish()
|
|
}
|
|
}
|
|
|
|
pub struct Iter<'a, T: Item> {
|
|
tree: &'a SumTree<T>,
|
|
stack: ArrayVec<StackEntry<'a, T, ()>, 16>,
|
|
}
|
|
|
|
impl<'a, 'b, T, D> Cursor<'a, 'b, T, D>
|
|
where
|
|
T: Item,
|
|
D: Dimension<'a, T::Summary>,
|
|
{
|
|
pub fn new(tree: &'a SumTree<T>, cx: <T::Summary as Summary>::Context<'b>) -> Self {
|
|
Self {
|
|
tree,
|
|
stack: ArrayVec::new(),
|
|
position: D::zero(cx),
|
|
did_seek: false,
|
|
at_end: tree.is_empty(),
|
|
cx,
|
|
}
|
|
}
|
|
|
|
fn reset(&mut self) {
|
|
self.did_seek = false;
|
|
self.at_end = self.tree.is_empty();
|
|
self.stack.truncate(0);
|
|
self.position = D::zero(self.cx);
|
|
}
|
|
|
|
pub fn start(&self) -> &D {
|
|
&self.position
|
|
}
|
|
|
|
#[track_caller]
|
|
pub fn end(&self) -> D {
|
|
if let Some(item_summary) = self.item_summary() {
|
|
let mut end = self.start().clone();
|
|
end.add_summary(item_summary, self.cx);
|
|
end
|
|
} else {
|
|
self.start().clone()
|
|
}
|
|
}
|
|
|
|
/// Item is None, when the list is empty, or this cursor is at the end of the list.
|
|
#[track_caller]
|
|
pub fn item(&self) -> Option<&'a T> {
|
|
self.assert_did_seek();
|
|
if let Some(entry) = self.stack.last() {
|
|
match *entry.tree.0 {
|
|
Node::Leaf { ref items, .. } => {
|
|
if entry.index() == items.len() {
|
|
None
|
|
} else {
|
|
Some(&items[entry.index()])
|
|
}
|
|
}
|
|
_ => unreachable!(),
|
|
}
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
|
|
#[track_caller]
|
|
pub fn item_summary(&self) -> Option<&'a T::Summary> {
|
|
self.assert_did_seek();
|
|
if let Some(entry) = self.stack.last() {
|
|
match *entry.tree.0 {
|
|
Node::Leaf {
|
|
ref item_summaries, ..
|
|
} => {
|
|
if entry.index() == item_summaries.len() {
|
|
None
|
|
} else {
|
|
Some(&item_summaries[entry.index()])
|
|
}
|
|
}
|
|
_ => unreachable!(),
|
|
}
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
|
|
#[track_caller]
|
|
pub fn next_item(&self) -> Option<&'a T> {
|
|
self.assert_did_seek();
|
|
if let Some(entry) = self.stack.last() {
|
|
if entry.index() == entry.tree.0.items().len() - 1 {
|
|
if let Some(next_leaf) = self.next_leaf() {
|
|
Some(next_leaf.0.items().first().unwrap())
|
|
} else {
|
|
None
|
|
}
|
|
} else {
|
|
match *entry.tree.0 {
|
|
Node::Leaf { ref items, .. } => Some(&items[entry.index() + 1]),
|
|
_ => unreachable!(),
|
|
}
|
|
}
|
|
} else if self.at_end {
|
|
None
|
|
} else {
|
|
self.tree.first()
|
|
}
|
|
}
|
|
|
|
#[track_caller]
|
|
fn next_leaf(&self) -> Option<&'a SumTree<T>> {
|
|
for entry in self.stack.iter().rev().skip(1) {
|
|
if entry.index() < entry.tree.0.child_trees().len() - 1 {
|
|
match *entry.tree.0 {
|
|
Node::Internal {
|
|
ref child_trees, ..
|
|
} => return Some(child_trees[entry.index() + 1].leftmost_leaf()),
|
|
Node::Leaf { .. } => unreachable!(),
|
|
};
|
|
}
|
|
}
|
|
None
|
|
}
|
|
|
|
#[track_caller]
|
|
pub fn prev_item(&self) -> Option<&'a T> {
|
|
self.assert_did_seek();
|
|
if let Some(entry) = self.stack.last() {
|
|
if entry.index() == 0 {
|
|
if let Some(prev_leaf) = self.prev_leaf() {
|
|
Some(prev_leaf.0.items().last().unwrap())
|
|
} else {
|
|
None
|
|
}
|
|
} else {
|
|
match *entry.tree.0 {
|
|
Node::Leaf { ref items, .. } => Some(&items[entry.index() - 1]),
|
|
_ => unreachable!(),
|
|
}
|
|
}
|
|
} else if self.at_end {
|
|
self.tree.last()
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
|
|
#[track_caller]
|
|
fn prev_leaf(&self) -> Option<&'a SumTree<T>> {
|
|
for entry in self.stack.iter().rev().skip(1) {
|
|
if entry.index() != 0 {
|
|
match *entry.tree.0 {
|
|
Node::Internal {
|
|
ref child_trees, ..
|
|
} => return Some(child_trees[entry.index() - 1].rightmost_leaf()),
|
|
Node::Leaf { .. } => unreachable!(),
|
|
};
|
|
}
|
|
}
|
|
None
|
|
}
|
|
|
|
#[track_caller]
|
|
pub fn prev(&mut self) {
|
|
self.search_backward(|_| true)
|
|
}
|
|
|
|
#[track_caller]
|
|
pub fn search_backward<F>(&mut self, mut filter_node: F)
|
|
where
|
|
F: FnMut(&T::Summary) -> bool,
|
|
{
|
|
if !self.did_seek {
|
|
self.did_seek = true;
|
|
self.at_end = true;
|
|
}
|
|
|
|
if self.at_end {
|
|
self.position = D::zero(self.cx);
|
|
self.at_end = self.tree.is_empty();
|
|
if !self.tree.is_empty() {
|
|
self.stack.push(StackEntry {
|
|
tree: self.tree,
|
|
index: self.tree.0.child_summaries().len() as u32,
|
|
position: D::from_summary(self.tree.summary(), self.cx),
|
|
});
|
|
}
|
|
}
|
|
|
|
let mut descending = false;
|
|
while !self.stack.is_empty() {
|
|
if let Some(StackEntry { position, .. }) = self.stack.iter().rev().nth(1) {
|
|
self.position = position.clone();
|
|
} else {
|
|
self.position = D::zero(self.cx);
|
|
}
|
|
|
|
let entry = self.stack.last_mut().unwrap();
|
|
if !descending {
|
|
if entry.index() == 0 {
|
|
self.stack.pop();
|
|
continue;
|
|
} else {
|
|
entry.index -= 1;
|
|
}
|
|
}
|
|
|
|
for summary in &entry.tree.0.child_summaries()[..entry.index()] {
|
|
self.position.add_summary(summary, self.cx);
|
|
}
|
|
entry.position = self.position.clone();
|
|
|
|
descending = filter_node(&entry.tree.0.child_summaries()[entry.index()]);
|
|
match entry.tree.0.as_ref() {
|
|
Node::Internal { child_trees, .. } => {
|
|
if descending {
|
|
let tree = &child_trees[entry.index()];
|
|
self.stack.push(StackEntry {
|
|
position: D::zero(self.cx),
|
|
tree,
|
|
index: tree.0.child_summaries().len() as u32 - 1,
|
|
})
|
|
}
|
|
}
|
|
Node::Leaf { .. } => {
|
|
if descending {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[track_caller]
|
|
pub fn next(&mut self) {
|
|
self.search_forward(|_| true)
|
|
}
|
|
|
|
#[track_caller]
|
|
pub fn search_forward<F>(&mut self, mut filter_node: F)
|
|
where
|
|
F: FnMut(&T::Summary) -> bool,
|
|
{
|
|
let mut descend = false;
|
|
|
|
if self.stack.is_empty() {
|
|
if !self.at_end {
|
|
self.stack.push(StackEntry {
|
|
tree: self.tree,
|
|
index: 0,
|
|
position: D::zero(self.cx),
|
|
});
|
|
descend = true;
|
|
}
|
|
self.did_seek = true;
|
|
}
|
|
|
|
while !self.stack.is_empty() {
|
|
let new_subtree = {
|
|
let entry = self.stack.last_mut().unwrap();
|
|
match entry.tree.0.as_ref() {
|
|
Node::Internal {
|
|
child_trees,
|
|
child_summaries,
|
|
..
|
|
} => {
|
|
if !descend {
|
|
entry.index += 1;
|
|
entry.position = self.position.clone();
|
|
}
|
|
|
|
while entry.index() < child_summaries.len() {
|
|
let next_summary = &child_summaries[entry.index()];
|
|
if filter_node(next_summary) {
|
|
break;
|
|
} else {
|
|
entry.index += 1;
|
|
entry.position.add_summary(next_summary, self.cx);
|
|
self.position.add_summary(next_summary, self.cx);
|
|
}
|
|
}
|
|
|
|
child_trees.get(entry.index())
|
|
}
|
|
Node::Leaf { item_summaries, .. } => {
|
|
if !descend {
|
|
let item_summary = &item_summaries[entry.index()];
|
|
entry.index += 1;
|
|
entry.position.add_summary(item_summary, self.cx);
|
|
self.position.add_summary(item_summary, self.cx);
|
|
}
|
|
|
|
loop {
|
|
if let Some(next_item_summary) = item_summaries.get(entry.index()) {
|
|
if filter_node(next_item_summary) {
|
|
return;
|
|
} else {
|
|
entry.index += 1;
|
|
entry.position.add_summary(next_item_summary, self.cx);
|
|
self.position.add_summary(next_item_summary, self.cx);
|
|
}
|
|
} else {
|
|
break None;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
if let Some(subtree) = new_subtree {
|
|
descend = true;
|
|
self.stack.push(StackEntry {
|
|
tree: subtree,
|
|
index: 0,
|
|
position: self.position.clone(),
|
|
});
|
|
} else {
|
|
descend = false;
|
|
self.stack.pop();
|
|
}
|
|
}
|
|
|
|
self.at_end = self.stack.is_empty();
|
|
debug_assert!(self.stack.is_empty() || self.stack.last().unwrap().tree.0.is_leaf());
|
|
}
|
|
|
|
#[track_caller]
|
|
fn assert_did_seek(&self) {
|
|
assert!(
|
|
self.did_seek,
|
|
"Must call `seek`, `next` or `prev` before calling this method"
|
|
);
|
|
}
|
|
}
|
|
|
|
impl<'a, 'b, T, D> Cursor<'a, 'b, T, D>
|
|
where
|
|
T: Item,
|
|
D: Dimension<'a, T::Summary>,
|
|
{
|
|
#[track_caller]
|
|
pub fn seek<Target>(&mut self, pos: &Target, bias: Bias) -> bool
|
|
where
|
|
Target: SeekTarget<'a, T::Summary, D>,
|
|
{
|
|
self.reset();
|
|
self.seek_internal(pos, bias, &mut ())
|
|
}
|
|
|
|
#[track_caller]
|
|
pub fn seek_forward<Target>(&mut self, pos: &Target, bias: Bias) -> bool
|
|
where
|
|
Target: SeekTarget<'a, T::Summary, D>,
|
|
{
|
|
self.seek_internal(pos, bias, &mut ())
|
|
}
|
|
|
|
/// Advances the cursor and returns traversed items as a tree.
|
|
#[track_caller]
|
|
pub fn slice<Target>(&mut self, end: &Target, bias: Bias) -> SumTree<T>
|
|
where
|
|
Target: SeekTarget<'a, T::Summary, D>,
|
|
{
|
|
let mut slice = SliceSeekAggregate {
|
|
tree: SumTree::new(self.cx),
|
|
leaf_items: ArrayVec::new(),
|
|
leaf_item_summaries: ArrayVec::new(),
|
|
leaf_summary: <T::Summary as Summary>::zero(self.cx),
|
|
};
|
|
self.seek_internal(end, bias, &mut slice);
|
|
slice.tree
|
|
}
|
|
|
|
#[track_caller]
|
|
pub fn suffix(&mut self) -> SumTree<T> {
|
|
self.slice(&End::new(), Bias::Right)
|
|
}
|
|
|
|
#[track_caller]
|
|
pub fn summary<Target, Output>(&mut self, end: &Target, bias: Bias) -> Output
|
|
where
|
|
Target: SeekTarget<'a, T::Summary, D>,
|
|
Output: Dimension<'a, T::Summary>,
|
|
{
|
|
let mut summary = SummarySeekAggregate(Output::zero(self.cx));
|
|
self.seek_internal(end, bias, &mut summary);
|
|
summary.0
|
|
}
|
|
|
|
/// Returns whether we found the item you were seeking for
|
|
#[track_caller]
|
|
fn seek_internal(
|
|
&mut self,
|
|
target: &dyn SeekTarget<'a, T::Summary, D>,
|
|
bias: Bias,
|
|
aggregate: &mut dyn SeekAggregate<'a, T>,
|
|
) -> bool {
|
|
assert!(
|
|
target.cmp(&self.position, self.cx) >= Ordering::Equal,
|
|
"cannot seek backward",
|
|
);
|
|
|
|
if !self.did_seek {
|
|
self.did_seek = true;
|
|
self.stack.push(StackEntry {
|
|
tree: self.tree,
|
|
index: 0,
|
|
position: D::zero(self.cx),
|
|
});
|
|
}
|
|
|
|
let mut ascending = false;
|
|
'outer: while let Some(entry) = self.stack.last_mut() {
|
|
match *entry.tree.0 {
|
|
Node::Internal {
|
|
ref child_summaries,
|
|
ref child_trees,
|
|
..
|
|
} => {
|
|
if ascending {
|
|
entry.index += 1;
|
|
entry.position = self.position.clone();
|
|
}
|
|
|
|
for (child_tree, child_summary) in child_trees[entry.index()..]
|
|
.iter()
|
|
.zip(&child_summaries[entry.index()..])
|
|
{
|
|
let mut child_end = self.position.clone();
|
|
child_end.add_summary(child_summary, self.cx);
|
|
|
|
let comparison = target.cmp(&child_end, self.cx);
|
|
if comparison == Ordering::Greater
|
|
|| (comparison == Ordering::Equal && bias == Bias::Right)
|
|
{
|
|
self.position = child_end;
|
|
aggregate.push_tree(child_tree, child_summary, self.cx);
|
|
entry.index += 1;
|
|
entry.position = self.position.clone();
|
|
} else {
|
|
self.stack.push(StackEntry {
|
|
tree: child_tree,
|
|
index: 0,
|
|
position: self.position.clone(),
|
|
});
|
|
ascending = false;
|
|
continue 'outer;
|
|
}
|
|
}
|
|
}
|
|
Node::Leaf {
|
|
ref items,
|
|
ref item_summaries,
|
|
..
|
|
} => {
|
|
aggregate.begin_leaf();
|
|
|
|
for (item, item_summary) in items[entry.index()..]
|
|
.iter()
|
|
.zip(&item_summaries[entry.index()..])
|
|
{
|
|
let mut child_end = self.position.clone();
|
|
child_end.add_summary(item_summary, self.cx);
|
|
|
|
let comparison = target.cmp(&child_end, self.cx);
|
|
if comparison == Ordering::Greater
|
|
|| (comparison == Ordering::Equal && bias == Bias::Right)
|
|
{
|
|
self.position = child_end;
|
|
aggregate.push_item(item, item_summary, self.cx);
|
|
entry.index += 1;
|
|
} else {
|
|
aggregate.end_leaf(self.cx);
|
|
break 'outer;
|
|
}
|
|
}
|
|
|
|
aggregate.end_leaf(self.cx);
|
|
}
|
|
}
|
|
|
|
self.stack.pop();
|
|
ascending = true;
|
|
}
|
|
|
|
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.position.clone();
|
|
if bias == Bias::Left
|
|
&& let Some(summary) = self.item_summary()
|
|
{
|
|
end.add_summary(summary, self.cx);
|
|
}
|
|
|
|
target.cmp(&end, self.cx) == Ordering::Equal
|
|
}
|
|
}
|
|
|
|
impl<'a, T: Item> Iter<'a, T> {
|
|
pub(crate) fn new(tree: &'a SumTree<T>) -> Self {
|
|
Self {
|
|
tree,
|
|
stack: Default::default(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a, T: Item> Iterator for Iter<'a, T> {
|
|
type Item = &'a T;
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
let mut descend = false;
|
|
|
|
if self.stack.is_empty() {
|
|
self.stack.push(StackEntry {
|
|
tree: self.tree,
|
|
index: 0,
|
|
position: (),
|
|
});
|
|
descend = true;
|
|
}
|
|
|
|
while !self.stack.is_empty() {
|
|
let new_subtree = {
|
|
let entry = self.stack.last_mut().unwrap();
|
|
match entry.tree.0.as_ref() {
|
|
Node::Internal { child_trees, .. } => {
|
|
if !descend {
|
|
entry.index += 1;
|
|
}
|
|
child_trees.get(entry.index())
|
|
}
|
|
Node::Leaf { items, .. } => {
|
|
if !descend {
|
|
entry.index += 1;
|
|
}
|
|
|
|
if let Some(next_item) = items.get(entry.index()) {
|
|
return Some(next_item);
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
if let Some(subtree) = new_subtree {
|
|
descend = true;
|
|
self.stack.push(StackEntry {
|
|
tree: subtree,
|
|
index: 0,
|
|
position: (),
|
|
});
|
|
} else {
|
|
descend = false;
|
|
self.stack.pop();
|
|
}
|
|
}
|
|
|
|
None
|
|
}
|
|
}
|
|
|
|
impl<'a, 'b, T: Item, D> Iterator for Cursor<'a, 'b, T, D>
|
|
where
|
|
D: Dimension<'a, T::Summary>,
|
|
{
|
|
type Item = &'a T;
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
if !self.did_seek {
|
|
self.next();
|
|
}
|
|
|
|
if let Some(item) = self.item() {
|
|
self.next();
|
|
Some(item)
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
}
|
|
|
|
pub struct FilterCursor<'a, 'b, F, T: Item, D> {
|
|
cursor: Cursor<'a, 'b, T, D>,
|
|
filter_node: F,
|
|
}
|
|
|
|
impl<'a, 'b, F, T: Item, D> FilterCursor<'a, 'b, F, T, D>
|
|
where
|
|
F: FnMut(&T::Summary) -> bool,
|
|
T: Item,
|
|
D: Dimension<'a, T::Summary>,
|
|
{
|
|
pub fn new(
|
|
tree: &'a SumTree<T>,
|
|
cx: <T::Summary as Summary>::Context<'b>,
|
|
filter_node: F,
|
|
) -> Self {
|
|
let cursor = tree.cursor::<D>(cx);
|
|
Self {
|
|
cursor,
|
|
filter_node,
|
|
}
|
|
}
|
|
|
|
pub fn start(&self) -> &D {
|
|
self.cursor.start()
|
|
}
|
|
|
|
pub fn end(&self) -> D {
|
|
self.cursor.end()
|
|
}
|
|
|
|
pub fn item(&self) -> Option<&'a T> {
|
|
self.cursor.item()
|
|
}
|
|
|
|
pub fn item_summary(&self) -> Option<&'a T::Summary> {
|
|
self.cursor.item_summary()
|
|
}
|
|
|
|
pub fn next(&mut self) {
|
|
self.cursor.search_forward(&mut self.filter_node);
|
|
}
|
|
|
|
pub fn prev(&mut self) {
|
|
self.cursor.search_backward(&mut self.filter_node);
|
|
}
|
|
}
|
|
|
|
impl<'a, 'b, F, T: Item, U> Iterator for FilterCursor<'a, 'b, F, T, U>
|
|
where
|
|
F: FnMut(&T::Summary) -> bool,
|
|
U: Dimension<'a, T::Summary>,
|
|
{
|
|
type Item = &'a T;
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
if !self.cursor.did_seek {
|
|
self.next();
|
|
}
|
|
|
|
if let Some(item) = self.item() {
|
|
self.cursor.search_forward(&mut self.filter_node);
|
|
Some(item)
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
}
|
|
|
|
trait SeekAggregate<'a, T: Item> {
|
|
fn begin_leaf(&mut self);
|
|
fn end_leaf(&mut self, cx: <T::Summary as Summary>::Context<'_>);
|
|
fn push_item(
|
|
&mut self,
|
|
item: &'a T,
|
|
summary: &'a T::Summary,
|
|
cx: <T::Summary as Summary>::Context<'_>,
|
|
);
|
|
fn push_tree(
|
|
&mut self,
|
|
tree: &'a SumTree<T>,
|
|
summary: &'a T::Summary,
|
|
cx: <T::Summary as Summary>::Context<'_>,
|
|
);
|
|
}
|
|
|
|
struct SliceSeekAggregate<T: Item> {
|
|
tree: SumTree<T>,
|
|
leaf_items: ArrayVec<T, { 2 * TREE_BASE }>,
|
|
leaf_item_summaries: ArrayVec<T::Summary, { 2 * TREE_BASE }>,
|
|
leaf_summary: T::Summary,
|
|
}
|
|
|
|
struct SummarySeekAggregate<D>(D);
|
|
|
|
impl<T: Item> SeekAggregate<'_, T> for () {
|
|
fn begin_leaf(&mut self) {}
|
|
fn end_leaf(&mut self, _: <T::Summary as Summary>::Context<'_>) {}
|
|
fn push_item(&mut self, _: &T, _: &T::Summary, _: <T::Summary as Summary>::Context<'_>) {}
|
|
fn push_tree(
|
|
&mut self,
|
|
_: &SumTree<T>,
|
|
_: &T::Summary,
|
|
_: <T::Summary as Summary>::Context<'_>,
|
|
) {
|
|
}
|
|
}
|
|
|
|
impl<T: Item> SeekAggregate<'_, T> for SliceSeekAggregate<T> {
|
|
fn begin_leaf(&mut self) {}
|
|
fn end_leaf(&mut self, cx: <T::Summary as Summary>::Context<'_>) {
|
|
self.tree.append(
|
|
SumTree(Arc::new(Node::Leaf {
|
|
summary: mem::replace(&mut self.leaf_summary, <T::Summary as Summary>::zero(cx)),
|
|
items: mem::take(&mut self.leaf_items),
|
|
item_summaries: mem::take(&mut self.leaf_item_summaries),
|
|
})),
|
|
cx,
|
|
);
|
|
}
|
|
fn push_item(
|
|
&mut self,
|
|
item: &T,
|
|
summary: &T::Summary,
|
|
cx: <T::Summary as Summary>::Context<'_>,
|
|
) {
|
|
self.leaf_items.push(item.clone());
|
|
self.leaf_item_summaries.push(summary.clone());
|
|
Summary::add_summary(&mut self.leaf_summary, summary, cx);
|
|
}
|
|
fn push_tree(
|
|
&mut self,
|
|
tree: &SumTree<T>,
|
|
_: &T::Summary,
|
|
cx: <T::Summary as Summary>::Context<'_>,
|
|
) {
|
|
self.tree.append(tree.clone(), cx);
|
|
}
|
|
}
|
|
|
|
impl<'a, T: Item, D> SeekAggregate<'a, T> for SummarySeekAggregate<D>
|
|
where
|
|
D: Dimension<'a, T::Summary>,
|
|
{
|
|
fn begin_leaf(&mut self) {}
|
|
fn end_leaf(&mut self, _: <T::Summary as Summary>::Context<'_>) {}
|
|
fn push_item(
|
|
&mut self,
|
|
_: &T,
|
|
summary: &'a T::Summary,
|
|
cx: <T::Summary as Summary>::Context<'_>,
|
|
) {
|
|
self.0.add_summary(summary, cx);
|
|
}
|
|
fn push_tree(
|
|
&mut self,
|
|
_: &SumTree<T>,
|
|
summary: &'a T::Summary,
|
|
cx: <T::Summary as Summary>::Context<'_>,
|
|
) {
|
|
self.0.add_summary(summary, 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()
|
|
}
|
|
}
|