sum_tree: Reduce Cursor size for contextless summary types (#38776)

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 ...
This commit is contained in:
Lukas Wirth
2025-09-24 14:35:38 +02:00
committed by GitHub
parent c5219e8fd2
commit e1b57f00a0
26 changed files with 811 additions and 785 deletions
+78 -55
View File
@@ -5,10 +5,17 @@ use std::{cmp::Ordering, mem, sync::Arc};
#[derive(Clone)]
struct StackEntry<'a, T: Item, D> {
tree: &'a SumTree<T>,
index: usize,
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")
@@ -19,16 +26,16 @@ impl<T: Item + fmt::Debug, D: fmt::Debug> fmt::Debug for StackEntry<'_, T, D> {
}
#[derive(Clone)]
pub struct Cursor<'a, T: Item, D> {
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: &'a <T::Summary as Summary>::Context,
cx: <T::Summary as Summary>::Context<'b>,
}
impl<T: Item + fmt::Debug, D: fmt::Debug> fmt::Debug for Cursor<'_, T, D>
impl<T: Item + fmt::Debug, D: fmt::Debug> fmt::Debug for Cursor<'_, '_, T, D>
where
T::Summary: fmt::Debug,
{
@@ -48,12 +55,12 @@ pub struct Iter<'a, T: Item> {
stack: ArrayVec<StackEntry<'a, T, ()>, 16>,
}
impl<'a, T, D> Cursor<'a, T, D>
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: &'a <T::Summary as Summary>::Context) -> Self {
pub fn new(tree: &'a SumTree<T>, cx: <T::Summary as Summary>::Context<'b>) -> Self {
Self {
tree,
stack: ArrayVec::new(),
@@ -93,10 +100,10 @@ where
if let Some(entry) = self.stack.last() {
match *entry.tree.0 {
Node::Leaf { ref items, .. } => {
if entry.index == items.len() {
if entry.index() == items.len() {
None
} else {
Some(&items[entry.index])
Some(&items[entry.index()])
}
}
_ => unreachable!(),
@@ -114,10 +121,10 @@ where
Node::Leaf {
ref item_summaries, ..
} => {
if entry.index == item_summaries.len() {
if entry.index() == item_summaries.len() {
None
} else {
Some(&item_summaries[entry.index])
Some(&item_summaries[entry.index()])
}
}
_ => unreachable!(),
@@ -131,7 +138,7 @@ where
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 entry.index() == entry.tree.0.items().len() - 1 {
if let Some(next_leaf) = self.next_leaf() {
Some(next_leaf.0.items().first().unwrap())
} else {
@@ -139,7 +146,7 @@ where
}
} else {
match *entry.tree.0 {
Node::Leaf { ref items, .. } => Some(&items[entry.index + 1]),
Node::Leaf { ref items, .. } => Some(&items[entry.index() + 1]),
_ => unreachable!(),
}
}
@@ -153,11 +160,11 @@ where
#[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 {
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()),
} => return Some(child_trees[entry.index() + 1].leftmost_leaf()),
Node::Leaf { .. } => unreachable!(),
};
}
@@ -169,7 +176,7 @@ where
pub fn prev_item(&self) -> Option<&'a T> {
self.assert_did_seek();
if let Some(entry) = self.stack.last() {
if entry.index == 0 {
if entry.index() == 0 {
if let Some(prev_leaf) = self.prev_leaf() {
Some(prev_leaf.0.items().last().unwrap())
} else {
@@ -177,7 +184,7 @@ where
}
} else {
match *entry.tree.0 {
Node::Leaf { ref items, .. } => Some(&items[entry.index - 1]),
Node::Leaf { ref items, .. } => Some(&items[entry.index() - 1]),
_ => unreachable!(),
}
}
@@ -191,11 +198,11 @@ where
#[track_caller]
fn prev_leaf(&self) -> Option<&'a SumTree<T>> {
for entry in self.stack.iter().rev().skip(1) {
if entry.index != 0 {
if entry.index() != 0 {
match *entry.tree.0 {
Node::Internal {
ref child_trees, ..
} => return Some(child_trees[entry.index - 1].rightmost_leaf()),
} => return Some(child_trees[entry.index() - 1].rightmost_leaf()),
Node::Leaf { .. } => unreachable!(),
};
}
@@ -224,7 +231,7 @@ where
if !self.tree.is_empty() {
self.stack.push(StackEntry {
tree: self.tree,
index: self.tree.0.child_summaries().len(),
index: self.tree.0.child_summaries().len() as u32,
position: D::from_summary(self.tree.summary(), self.cx),
});
}
@@ -240,7 +247,7 @@ where
let entry = self.stack.last_mut().unwrap();
if !descending {
if entry.index == 0 {
if entry.index() == 0 {
self.stack.pop();
continue;
} else {
@@ -248,20 +255,20 @@ where
}
}
for summary in &entry.tree.0.child_summaries()[..entry.index] {
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]);
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];
let tree = &child_trees[entry.index()];
self.stack.push(StackEntry {
position: D::zero(self.cx),
tree,
index: tree.0.child_summaries().len() - 1,
index: tree.0.child_summaries().len() as u32 - 1,
})
}
}
@@ -312,8 +319,8 @@ where
entry.position = self.position.clone();
}
while entry.index < child_summaries.len() {
let next_summary = &child_summaries[entry.index];
while entry.index() < child_summaries.len() {
let next_summary = &child_summaries[entry.index()];
if filter_node(next_summary) {
break;
} else {
@@ -323,18 +330,18 @@ where
}
}
child_trees.get(entry.index)
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()];
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 let Some(next_item_summary) = item_summaries.get(entry.index()) {
if filter_node(next_item_summary) {
return;
} else {
@@ -376,7 +383,7 @@ where
}
}
impl<'a, T, D> Cursor<'a, T, D>
impl<'a, 'b, T, D> Cursor<'a, 'b, T, D>
where
T: Item,
D: Dimension<'a, T::Summary>,
@@ -465,9 +472,9 @@ where
entry.position = self.position.clone();
}
for (child_tree, child_summary) in child_trees[entry.index..]
for (child_tree, child_summary) in child_trees[entry.index()..]
.iter()
.zip(&child_summaries[entry.index..])
.zip(&child_summaries[entry.index()..])
{
let mut child_end = self.position.clone();
child_end.add_summary(child_summary, self.cx);
@@ -498,9 +505,9 @@ where
} => {
aggregate.begin_leaf();
for (item, item_summary) in items[entry.index..]
for (item, item_summary) in items[entry.index()..]
.iter()
.zip(&item_summaries[entry.index..])
.zip(&item_summaries[entry.index()..])
{
let mut child_end = self.position.clone();
child_end.add_summary(item_summary, self.cx);
@@ -572,14 +579,14 @@ impl<'a, T: Item> Iterator for Iter<'a, T> {
if !descend {
entry.index += 1;
}
child_trees.get(entry.index)
child_trees.get(entry.index())
}
Node::Leaf { items, .. } => {
if !descend {
entry.index += 1;
}
if let Some(next_item) = items.get(entry.index) {
if let Some(next_item) = items.get(entry.index()) {
return Some(next_item);
} else {
None
@@ -605,7 +612,7 @@ impl<'a, T: Item> Iterator for Iter<'a, T> {
}
}
impl<'a, T: Item, D> Iterator for Cursor<'a, T, D>
impl<'a, 'b, T: Item, D> Iterator for Cursor<'a, 'b, T, D>
where
D: Dimension<'a, T::Summary>,
{
@@ -625,12 +632,12 @@ where
}
}
pub struct FilterCursor<'a, F, T: Item, D> {
cursor: Cursor<'a, T, D>,
pub struct FilterCursor<'a, 'b, F, T: Item, D> {
cursor: Cursor<'a, 'b, T, D>,
filter_node: F,
}
impl<'a, F, T: Item, D> FilterCursor<'a, F, T, D>
impl<'a, 'b, F, T: Item, D> FilterCursor<'a, 'b, F, T, D>
where
F: FnMut(&T::Summary) -> bool,
T: Item,
@@ -638,7 +645,7 @@ where
{
pub fn new(
tree: &'a SumTree<T>,
cx: &'a <T::Summary as Summary>::Context,
cx: <T::Summary as Summary>::Context<'b>,
filter_node: F,
) -> Self {
let cursor = tree.cursor::<D>(cx);
@@ -673,7 +680,7 @@ where
}
}
impl<'a, F, T: Item, U> Iterator for FilterCursor<'a, F, T, U>
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>,
@@ -696,18 +703,18 @@ where
trait SeekAggregate<'a, T: Item> {
fn begin_leaf(&mut self);
fn end_leaf(&mut self, cx: &<T::Summary as Summary>::Context);
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,
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,
cx: <T::Summary as Summary>::Context<'_>,
);
}
@@ -722,14 +729,20 @@ 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) {}
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) {
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)),
@@ -739,7 +752,12 @@ impl<T: Item> SeekAggregate<'_, T> for SliceSeekAggregate<T> {
cx,
);
}
fn push_item(&mut self, item: &T, summary: &T::Summary, cx: &<T::Summary as Summary>::Context) {
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);
@@ -748,7 +766,7 @@ impl<T: Item> SeekAggregate<'_, T> for SliceSeekAggregate<T> {
&mut self,
tree: &SumTree<T>,
_: &T::Summary,
cx: &<T::Summary as Summary>::Context,
cx: <T::Summary as Summary>::Context<'_>,
) {
self.tree.append(tree.clone(), cx);
}
@@ -759,15 +777,20 @@ 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) {
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,
cx: <T::Summary as Summary>::Context<'_>,
) {
self.0.add_summary(summary, cx);
}
@@ -782,7 +805,7 @@ impl<D> End<D> {
}
impl<'a, S: Summary, D: Dimension<'a, S>> SeekTarget<'a, S, D> for End<D> {
fn cmp(&self, _: &D, _: &S::Context) -> Ordering {
fn cmp(&self, _: &D, _: S::Context<'_>) -> Ordering {
Ordering::Greater
}
}
+148 -128
View File
@@ -20,7 +20,7 @@ pub const TREE_BASE: usize = 6;
pub trait Item: Clone {
type Summary: Summary;
fn summary(&self, cx: &<Self::Summary as Summary>::Context) -> Self::Summary;
fn summary(&self, cx: <Self::Summary as Summary>::Context<'_>) -> Self::Summary;
}
/// An [`Item`] whose summary has a specific key that can be used to identify it
@@ -35,23 +35,40 @@ pub trait KeyedItem: Item {
/// Each Summary type can have multiple [`Dimension`]s that it measures,
/// which can be used to navigate the tree
pub trait Summary: Clone {
type Context;
fn zero(cx: &Self::Context) -> Self;
fn add_summary(&mut self, summary: &Self, cx: &Self::Context);
type Context<'a>: Copy;
fn zero<'a>(cx: Self::Context<'a>) -> Self;
fn add_summary<'a>(&mut self, summary: &Self, cx: Self::Context<'a>);
}
/// Catch-all implementation for when you need something that implements [`Summary`] without a specific type.
/// We implement it on a &'static, as that avoids blanket impl collisions with `impl<T: Summary> Dimension for T`
/// (as we also need unit type to be a fill-in dimension)
impl Summary for &'static () {
type Context = ();
pub trait ContextLessSummary: Clone {
fn zero() -> Self;
fn add_summary(&mut self, summary: &Self);
}
fn zero(_: &()) -> Self {
&()
impl<T: ContextLessSummary> Summary for T {
type Context<'a> = ();
fn zero<'a>((): ()) -> Self {
T::zero()
}
fn add_summary(&mut self, _: &Self, _: &()) {}
fn add_summary<'a>(&mut self, summary: &Self, (): ()) {
T::add_summary(self, summary)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct NoSummary;
/// Catch-all implementation for when you need something that implements [`Summary`] without a specific type.
/// We implement it on a `NoSummary` instead of re-using `()`, as that avoids blanket impl collisions with `impl<T: Summary> Dimension for T`
/// (as we also need unit type to be a fill-in dimension)
impl ContextLessSummary for NoSummary {
fn zero() -> Self {
NoSummary
}
fn add_summary(&mut self, _: &Self) {}
}
/// Each [`Summary`] type can have more than one [`Dimension`] type that it measures.
@@ -62,11 +79,11 @@ impl Summary for &'static () {
/// Zed's rope has a `TextSummary` type that summarizes lines, characters, and bytes.
/// Each of these are different dimensions we may want to seek to
pub trait Dimension<'a, S: Summary>: Clone {
fn zero(cx: &S::Context) -> Self;
fn zero(cx: S::Context<'_>) -> Self;
fn add_summary(&mut self, summary: &'a S, cx: &S::Context);
fn add_summary(&mut self, summary: &'a S, cx: S::Context<'_>);
fn from_summary(summary: &'a S, cx: &S::Context) -> Self {
fn from_summary(summary: &'a S, cx: S::Context<'_>) -> Self {
let mut dimension = Self::zero(cx);
dimension.add_summary(summary, cx);
dimension
@@ -74,29 +91,29 @@ pub trait Dimension<'a, S: Summary>: Clone {
}
impl<'a, T: Summary> Dimension<'a, T> for T {
fn zero(cx: &T::Context) -> Self {
fn zero(cx: T::Context<'_>) -> Self {
Summary::zero(cx)
}
fn add_summary(&mut self, summary: &'a T, cx: &T::Context) {
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>> {
fn cmp(&self, cursor_location: &D, cx: &S::Context) -> Ordering;
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 {
fn cmp(&self, cursor_location: &Self, _: S::Context<'_>) -> Ordering {
Ord::cmp(self, cursor_location)
}
}
impl<'a, T: Summary> Dimension<'a, T> for () {
fn zero(_: &T::Context) -> Self {}
fn zero(_: T::Context<'_>) -> Self {}
fn add_summary(&mut self, _: &'a T, _: &T::Context) {}
fn add_summary(&mut self, _: &'a T, _: T::Context<'_>) {}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
@@ -105,11 +122,11 @@ pub struct Dimensions<D1, D2, D3 = ()>(pub D1, pub D2, pub D3);
impl<'a, T: Summary, D1: Dimension<'a, T>, D2: Dimension<'a, T>, D3: Dimension<'a, T>>
Dimension<'a, T> for Dimensions<D1, D2, D3>
{
fn zero(cx: &T::Context) -> Self {
fn zero(cx: T::Context<'_>) -> Self {
Dimensions(D1::zero(cx), D2::zero(cx), D3::zero(cx))
}
fn add_summary(&mut self, summary: &'a T, cx: &T::Context) {
fn add_summary(&mut self, summary: &'a T, cx: T::Context<'_>) {
self.0.add_summary(summary, cx);
self.1.add_summary(summary, cx);
self.2.add_summary(summary, cx);
@@ -123,7 +140,7 @@ where
D2: Dimension<'a, S>,
D3: Dimension<'a, S>,
{
fn cmp(&self, cursor_location: &Dimensions<D1, D2, D3>, cx: &S::Context) -> Ordering {
fn cmp(&self, cursor_location: &Dimensions<D1, D2, D3>, cx: S::Context<'_>) -> Ordering {
self.cmp(&cursor_location.0, cx)
}
}
@@ -187,7 +204,7 @@ where
}
impl<T: Item> SumTree<T> {
pub fn new(cx: &<T::Summary as Summary>::Context) -> Self {
pub fn new(cx: <T::Summary as Summary>::Context<'_>) -> Self {
SumTree(Arc::new(Node::Leaf {
summary: <T::Summary as Summary>::zero(cx),
items: ArrayVec::new(),
@@ -204,7 +221,7 @@ impl<T: Item> SumTree<T> {
}))
}
pub fn from_item(item: T, cx: &<T::Summary as Summary>::Context) -> Self {
pub fn from_item(item: T, cx: <T::Summary as Summary>::Context<'_>) -> Self {
let mut tree = Self::new(cx);
tree.push(item, cx);
tree
@@ -212,7 +229,7 @@ impl<T: Item> SumTree<T> {
pub fn from_iter<I: IntoIterator<Item = T>>(
iter: I,
cx: &<T::Summary as Summary>::Context,
cx: <T::Summary as Summary>::Context<'_>,
) -> Self {
let mut nodes = Vec::new();
@@ -276,13 +293,13 @@ impl<T: Item> SumTree<T> {
}
}
pub fn from_par_iter<I, Iter>(iter: I, cx: &<T::Summary as Summary>::Context) -> Self
pub fn from_par_iter<I, Iter>(iter: I, cx: <T::Summary as Summary>::Context<'_>) -> Self
where
I: IntoParallelIterator<Iter = Iter>,
Iter: IndexedParallelIterator<Item = T>,
T: Send + Sync,
T::Summary: Send + Sync,
<T::Summary as Summary>::Context: Sync,
for<'a> <T::Summary as Summary>::Context<'a>: Sync,
{
let mut nodes = iter
.into_par_iter()
@@ -339,7 +356,7 @@ impl<T: Item> SumTree<T> {
}
#[allow(unused)]
pub fn items(&self, cx: &<T::Summary as Summary>::Context) -> Vec<T> {
pub fn items<'a>(&'a self, cx: <T::Summary as Summary>::Context<'a>) -> Vec<T> {
let mut items = Vec::new();
let mut cursor = self.cursor::<()>(cx);
cursor.next();
@@ -354,7 +371,10 @@ impl<T: Item> SumTree<T> {
Iter::new(self)
}
pub fn cursor<'a, S>(&'a self, cx: &'a <T::Summary as Summary>::Context) -> Cursor<'a, T, S>
pub fn cursor<'a, 'b, S>(
&'a self,
cx: <T::Summary as Summary>::Context<'b>,
) -> Cursor<'a, 'b, T, S>
where
S: Dimension<'a, T::Summary>,
{
@@ -363,11 +383,11 @@ impl<T: Item> SumTree<T> {
/// Note: If the summary type requires a non `()` context, then the filter cursor
/// that is returned cannot be used with Rust's iterators.
pub fn filter<'a, F, U>(
pub fn filter<'a, 'b, F, U>(
&'a self,
cx: &'a <T::Summary as Summary>::Context,
cx: <T::Summary as Summary>::Context<'b>,
filter_node: F,
) -> FilterCursor<'a, F, T, U>
) -> FilterCursor<'a, 'b, F, T, U>
where
F: FnMut(&T::Summary) -> bool,
U: Dimension<'a, T::Summary>,
@@ -384,14 +404,18 @@ impl<T: Item> SumTree<T> {
self.rightmost_leaf().0.items().last()
}
pub fn update_last(&mut self, f: impl FnOnce(&mut T), cx: &<T::Summary as Summary>::Context) {
pub fn update_last(
&mut self,
f: impl FnOnce(&mut T),
cx: <T::Summary as Summary>::Context<'_>,
) {
self.update_last_recursive(f, cx);
}
fn update_last_recursive(
&mut self,
f: impl FnOnce(&mut T),
cx: &<T::Summary as Summary>::Context,
cx: <T::Summary as Summary>::Context<'_>,
) -> Option<T::Summary> {
match Arc::make_mut(&mut self.0) {
Node::Internal {
@@ -426,7 +450,7 @@ impl<T: Item> SumTree<T> {
pub fn extent<'a, D: Dimension<'a, T::Summary>>(
&'a self,
cx: &<T::Summary as Summary>::Context,
cx: <T::Summary as Summary>::Context<'_>,
) -> D {
let mut extent = D::zero(cx);
match self.0.as_ref() {
@@ -451,25 +475,25 @@ impl<T: Item> SumTree<T> {
}
}
pub fn extend<I>(&mut self, iter: I, cx: &<T::Summary as Summary>::Context)
pub fn extend<I>(&mut self, iter: I, cx: <T::Summary as Summary>::Context<'_>)
where
I: IntoIterator<Item = T>,
{
self.append(Self::from_iter(iter, cx), cx);
}
pub fn par_extend<I, Iter>(&mut self, iter: I, cx: &<T::Summary as Summary>::Context)
pub fn par_extend<I, Iter>(&mut self, iter: I, cx: <T::Summary as Summary>::Context<'_>)
where
I: IntoParallelIterator<Iter = Iter>,
Iter: IndexedParallelIterator<Item = T>,
T: Send + Sync,
T::Summary: Send + Sync,
<T::Summary as Summary>::Context: Sync,
for<'a> <T::Summary as Summary>::Context<'a>: Sync,
{
self.append(Self::from_par_iter(iter, cx), cx);
}
pub fn push(&mut self, item: T, cx: &<T::Summary as Summary>::Context) {
pub fn push(&mut self, item: T, cx: <T::Summary as Summary>::Context<'_>) {
let summary = item.summary(cx);
self.append(
SumTree(Arc::new(Node::Leaf {
@@ -481,7 +505,7 @@ impl<T: Item> SumTree<T> {
);
}
pub fn append(&mut self, other: Self, cx: &<T::Summary as Summary>::Context) {
pub fn append(&mut self, other: Self, cx: <T::Summary as Summary>::Context<'_>) {
if self.is_empty() {
*self = other;
} else if !other.0.is_leaf() || !other.0.items().is_empty() {
@@ -498,7 +522,7 @@ impl<T: Item> SumTree<T> {
fn push_tree_recursive(
&mut self,
other: SumTree<T>,
cx: &<T::Summary as Summary>::Context,
cx: <T::Summary as Summary>::Context<'_>,
) -> Option<SumTree<T>> {
match Arc::make_mut(&mut self.0) {
Node::Internal {
@@ -618,7 +642,7 @@ impl<T: Item> SumTree<T> {
fn from_child_trees(
left: SumTree<T>,
right: SumTree<T>,
cx: &<T::Summary as Summary>::Context,
cx: <T::Summary as Summary>::Context<'_>,
) -> Self {
let height = left.0.height() + 1;
let mut child_summaries = ArrayVec::new();
@@ -663,13 +687,13 @@ impl<T: Item + PartialEq> PartialEq for SumTree<T> {
impl<T: Item + Eq> Eq for SumTree<T> {}
impl<T: KeyedItem> SumTree<T> {
pub fn insert_or_replace(
&mut self,
pub fn insert_or_replace<'a, 'b>(
&'a mut self,
item: T,
cx: &<T::Summary as Summary>::Context,
cx: <T::Summary as Summary>::Context<'b>,
) -> Option<T> {
let mut replaced = None;
*self = {
{
let mut cursor = self.cursor::<T::Key>(cx);
let mut new_tree = cursor.slice(&item.key(), Bias::Left);
if let Some(cursor_item) = cursor.item()
@@ -680,12 +704,13 @@ impl<T: KeyedItem> SumTree<T> {
}
new_tree.push(item, cx);
new_tree.append(cursor.suffix(), cx);
new_tree
drop(cursor);
*self = new_tree
};
replaced
}
pub fn remove(&mut self, key: &T::Key, cx: &<T::Summary as Summary>::Context) -> Option<T> {
pub fn remove(&mut self, key: &T::Key, cx: <T::Summary as Summary>::Context<'_>) -> Option<T> {
let mut removed = None;
*self = {
let mut cursor = self.cursor::<T::Key>(cx);
@@ -705,7 +730,7 @@ impl<T: KeyedItem> SumTree<T> {
pub fn edit(
&mut self,
mut edits: Vec<Edit<T>>,
cx: &<T::Summary as Summary>::Context,
cx: <T::Summary as Summary>::Context<'_>,
) -> Vec<T> {
if edits.is_empty() {
return Vec::new();
@@ -760,7 +785,7 @@ impl<T: KeyedItem> SumTree<T> {
pub fn get<'a>(
&'a self,
key: &T::Key,
cx: &'a <T::Summary as Summary>::Context,
cx: <T::Summary as Summary>::Context<'a>,
) -> Option<&'a T> {
let mut cursor = self.cursor::<T::Key>(cx);
if cursor.seek(key, Bias::Left) {
@@ -774,10 +799,10 @@ impl<T: KeyedItem> SumTree<T> {
impl<T, S> Default for SumTree<T>
where
T: Item<Summary = S>,
S: Summary<Context = ()>,
S: for<'a> Summary<Context<'a> = ()>,
{
fn default() -> Self {
Self::new(&())
Self::new(())
}
}
@@ -894,7 +919,7 @@ impl<T: KeyedItem> Edit<T> {
}
}
fn sum<'a, T, I>(iter: I, cx: &T::Context) -> T
fn sum<'a, T, I>(iter: I, cx: T::Context<'_>) -> T
where
T: 'a + Summary,
I: Iterator<Item = &'a T>,
@@ -920,16 +945,13 @@ mod tests {
#[test]
fn test_extend_and_push_tree() {
let mut tree1 = SumTree::default();
tree1.extend(0..20, &());
tree1.extend(0..20, ());
let mut tree2 = SumTree::default();
tree2.extend(50..100, &());
tree2.extend(50..100, ());
tree1.append(tree2, &());
assert_eq!(
tree1.items(&()),
(0..20).chain(50..100).collect::<Vec<u8>>()
);
tree1.append(tree2, ());
assert_eq!(tree1.items(()), (0..20).chain(50..100).collect::<Vec<u8>>());
}
#[test]
@@ -953,53 +975,53 @@ mod tests {
let mut tree = SumTree::<u8>::default();
let count = rng.random_range(0..10);
if rng.random() {
tree.extend(rng.sample_iter(StandardUniform).take(count), &());
tree.extend(rng.sample_iter(StandardUniform).take(count), ());
} else {
let items = rng
.sample_iter(StandardUniform)
.take(count)
.collect::<Vec<_>>();
tree.par_extend(items, &());
tree.par_extend(items, ());
}
for _ in 0..num_operations {
let splice_end = rng.random_range(0..tree.extent::<Count>(&()).0 + 1);
let splice_end = rng.random_range(0..tree.extent::<Count>(()).0 + 1);
let splice_start = rng.random_range(0..splice_end + 1);
let count = rng.random_range(0..10);
let tree_end = tree.extent::<Count>(&());
let tree_end = tree.extent::<Count>(());
let new_items = rng
.sample_iter(StandardUniform)
.take(count)
.collect::<Vec<u8>>();
let mut reference_items = tree.items(&());
let mut reference_items = tree.items(());
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);
if rng.random() {
new_tree.extend(new_items, &());
new_tree.extend(new_items, ());
} else {
new_tree.par_extend(new_items, &());
new_tree.par_extend(new_items, ());
}
cursor.seek(&Count(splice_end), Bias::Right);
new_tree.append(cursor.slice(&tree_end, Bias::Right), &());
new_tree.append(cursor.slice(&tree_end, Bias::Right), ());
new_tree
};
assert_eq!(tree.items(&()), reference_items);
assert_eq!(tree.items(()), reference_items);
assert_eq!(
tree.iter().collect::<Vec<_>>(),
tree.cursor::<()>(&()).collect::<Vec<_>>()
tree.cursor::<()>(()).collect::<Vec<_>>()
);
log::info!("tree items: {:?}", tree.items(&()));
log::info!("tree items: {:?}", tree.items(()));
let mut filter_cursor =
tree.filter::<_, Count>(&(), |summary| summary.contains_even);
tree.filter::<_, Count>((), |summary| summary.contains_even);
let expected_filtered_items = tree
.items(&())
.items(())
.into_iter()
.enumerate()
.filter(|(_, item)| (item & 1) == 0)
@@ -1038,7 +1060,7 @@ mod tests {
assert_eq!(filter_cursor.item(), None);
let mut before_start = false;
let mut cursor = tree.cursor::<Count>(&());
let mut cursor = tree.cursor::<Count>(());
let start_pos = rng.random_range(0..=reference_items.len());
cursor.seek(&Count(start_pos), Bias::Right);
let mut pos = rng.random_range(start_pos..=reference_items.len());
@@ -1084,7 +1106,7 @@ mod tests {
}
for _ in 0..10 {
let end = rng.random_range(0..tree.extent::<Count>(&()).0 + 1);
let end = rng.random_range(0..tree.extent::<Count>(()).0 + 1);
let start = rng.random_range(0..end + 1);
let start_bias = if rng.random() {
Bias::Left
@@ -1097,7 +1119,7 @@ mod tests {
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);
@@ -1113,9 +1135,9 @@ mod tests {
fn test_cursor() {
// Empty tree
let tree = SumTree::<u8>::default();
let mut cursor = tree.cursor::<IntegersSummary>(&());
let mut cursor = tree.cursor::<IntegersSummary>(());
assert_eq!(
cursor.slice(&Count(0), Bias::Right).items(&()),
cursor.slice(&Count(0), Bias::Right).items(()),
Vec::<u8>::new()
);
assert_eq!(cursor.item(), None);
@@ -1135,10 +1157,10 @@ mod tests {
// Single-element tree
let mut tree = SumTree::<u8>::default();
tree.extend(vec![1], &());
let mut cursor = tree.cursor::<IntegersSummary>(&());
tree.extend(vec![1], ());
let mut cursor = tree.cursor::<IntegersSummary>(());
assert_eq!(
cursor.slice(&Count(0), Bias::Right).items(&()),
cursor.slice(&Count(0), Bias::Right).items(()),
Vec::<u8>::new()
);
assert_eq!(cursor.item(), Some(&1));
@@ -1158,8 +1180,8 @@ mod tests {
assert_eq!(cursor.next_item(), None);
assert_eq!(cursor.start().sum, 0);
let mut cursor = tree.cursor::<IntegersSummary>(&());
assert_eq!(cursor.slice(&Count(1), Bias::Right).items(&()), [1]);
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.next_item(), None);
@@ -1168,8 +1190,8 @@ mod tests {
cursor.seek(&Count(0), Bias::Right);
assert_eq!(
cursor
.slice(&tree.extent::<Count>(&()), Bias::Right)
.items(&()),
.slice(&tree.extent::<Count>(()), Bias::Right)
.items(()),
[1]
);
assert_eq!(cursor.item(), None);
@@ -1179,10 +1201,10 @@ mod tests {
// Multiple-element tree
let mut tree = SumTree::default();
tree.extend(vec![1, 2, 3, 4, 5, 6], &());
let mut cursor = tree.cursor::<IntegersSummary>(&());
tree.extend(vec![1, 2, 3, 4, 5, 6], ());
let mut cursor = tree.cursor::<IntegersSummary>(());
assert_eq!(cursor.slice(&Count(2), Bias::Right).items(&()), [1, 2]);
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.next_item(), Some(&4));
@@ -1261,12 +1283,12 @@ mod tests {
assert_eq!(cursor.next_item(), Some(&2));
assert_eq!(cursor.start().sum, 0);
let mut cursor = tree.cursor::<IntegersSummary>(&());
let mut cursor = tree.cursor::<IntegersSummary>(());
assert_eq!(
cursor
.slice(&tree.extent::<Count>(&()), Bias::Right)
.items(&()),
tree.items(&())
.slice(&tree.extent::<Count>(()), Bias::Right)
.items(()),
tree.items(())
);
assert_eq!(cursor.item(), None);
assert_eq!(cursor.prev_item(), Some(&6));
@@ -1276,8 +1298,8 @@ mod tests {
cursor.seek(&Count(3), Bias::Right);
assert_eq!(
cursor
.slice(&tree.extent::<Count>(&()), Bias::Right)
.items(&()),
.slice(&tree.extent::<Count>(()), Bias::Right)
.items(()),
[4, 5, 6]
);
assert_eq!(cursor.item(), None);
@@ -1293,36 +1315,36 @@ mod tests {
// Slicing without resetting starts from where the cursor is parked at.
cursor.seek(&Count(1), Bias::Right);
assert_eq!(cursor.slice(&Count(3), Bias::Right).items(&()), vec![2, 3]);
assert_eq!(cursor.slice(&Count(6), Bias::Left).items(&()), vec![4, 5]);
assert_eq!(cursor.slice(&Count(6), Bias::Right).items(&()), vec![6]);
assert_eq!(cursor.slice(&Count(3), Bias::Right).items(()), vec![2, 3]);
assert_eq!(cursor.slice(&Count(6), Bias::Left).items(()), vec![4, 5]);
assert_eq!(cursor.slice(&Count(6), Bias::Right).items(()), vec![6]);
}
#[test]
fn test_edit() {
let mut tree = SumTree::<u8>::default();
let removed = tree.edit(vec![Edit::Insert(1), Edit::Insert(2), Edit::Insert(0)], &());
assert_eq!(tree.items(&()), vec![0, 1, 2]);
let removed = tree.edit(vec![Edit::Insert(1), Edit::Insert(2), Edit::Insert(0)], ());
assert_eq!(tree.items(()), vec![0, 1, 2]);
assert_eq!(removed, Vec::<u8>::new());
assert_eq!(tree.get(&0, &()), Some(&0));
assert_eq!(tree.get(&1, &()), Some(&1));
assert_eq!(tree.get(&2, &()), Some(&2));
assert_eq!(tree.get(&4, &()), None);
assert_eq!(tree.get(&0, ()), Some(&0));
assert_eq!(tree.get(&1, ()), Some(&1));
assert_eq!(tree.get(&2, ()), Some(&2));
assert_eq!(tree.get(&4, ()), None);
let removed = tree.edit(vec![Edit::Insert(2), Edit::Insert(4), Edit::Remove(0)], &());
assert_eq!(tree.items(&()), vec![1, 2, 4]);
let removed = tree.edit(vec![Edit::Insert(2), Edit::Insert(4), Edit::Remove(0)], ());
assert_eq!(tree.items(()), vec![1, 2, 4]);
assert_eq!(removed, vec![0, 2]);
assert_eq!(tree.get(&0, &()), None);
assert_eq!(tree.get(&1, &()), Some(&1));
assert_eq!(tree.get(&2, &()), Some(&2));
assert_eq!(tree.get(&4, &()), Some(&4));
assert_eq!(tree.get(&0, ()), None);
assert_eq!(tree.get(&1, ()), Some(&1));
assert_eq!(tree.get(&2, ()), Some(&2));
assert_eq!(tree.get(&4, ()), Some(&4));
}
#[test]
fn test_from_iter() {
assert_eq!(
SumTree::from_iter(0..100, &()).items(&()),
SumTree::from_iter(0..100, ()).items(()),
(0..100).collect::<Vec<_>>()
);
@@ -1333,7 +1355,7 @@ mod tests {
ix = (ix + 1) % 2;
if ix == 1 { Some(1) } else { None }
});
assert_eq!(SumTree::from_iter(iterator, &()).items(&()), vec![1]);
assert_eq!(SumTree::from_iter(iterator, ()).items(()), vec![1]);
}
#[derive(Clone, Default, Debug)]
@@ -1353,7 +1375,7 @@ mod tests {
impl Item for u8 {
type Summary = IntegersSummary;
fn summary(&self, _cx: &()) -> Self::Summary {
fn summary(&self, _cx: ()) -> Self::Summary {
IntegersSummary {
count: 1,
sum: *self as usize,
@@ -1371,14 +1393,12 @@ mod tests {
}
}
impl Summary for IntegersSummary {
type Context = ();
fn zero(_cx: &()) -> Self {
impl ContextLessSummary for IntegersSummary {
fn zero() -> Self {
Default::default()
}
fn add_summary(&mut self, other: &Self, _: &()) {
fn add_summary(&mut self, other: &Self) {
self.count += other.count;
self.sum += other.sum;
self.contains_even |= other.contains_even;
@@ -1387,37 +1407,37 @@ mod tests {
}
impl Dimension<'_, IntegersSummary> for u8 {
fn zero(_cx: &()) -> Self {
fn zero(_cx: ()) -> Self {
Default::default()
}
fn add_summary(&mut self, summary: &IntegersSummary, _: &()) {
fn add_summary(&mut self, summary: &IntegersSummary, _: ()) {
*self = summary.max;
}
}
impl Dimension<'_, IntegersSummary> for Count {
fn zero(_cx: &()) -> Self {
fn zero(_cx: ()) -> Self {
Default::default()
}
fn add_summary(&mut self, summary: &IntegersSummary, _: &()) {
fn add_summary(&mut self, summary: &IntegersSummary, _: ()) {
self.0 += summary.count;
}
}
impl SeekTarget<'_, IntegersSummary, IntegersSummary> for Count {
fn cmp(&self, cursor_location: &IntegersSummary, _: &()) -> Ordering {
fn cmp(&self, cursor_location: &IntegersSummary, _: ()) -> Ordering {
self.0.cmp(&cursor_location.count)
}
}
impl Dimension<'_, IntegersSummary> for Sum {
fn zero(_cx: &()) -> Self {
fn zero(_cx: ()) -> Self {
Default::default()
}
fn add_summary(&mut self, summary: &IntegersSummary, _: &()) {
fn add_summary(&mut self, summary: &IntegersSummary, _: ()) {
self.0 += summary.sum;
}
}
+27 -29
View File
@@ -1,6 +1,6 @@
use std::{cmp::Ordering, fmt::Debug};
use crate::{Bias, Dimension, Edit, Item, KeyedItem, SeekTarget, SumTree, Summary};
use crate::{Bias, ContextLessSummary, Dimension, Edit, Item, KeyedItem, SeekTarget, SumTree};
/// A cheaply-cloneable ordered map based on a [SumTree](crate::SumTree).
#[derive(Clone, PartialEq, Eq)]
@@ -44,7 +44,7 @@ impl<K: Clone + Ord, V: Clone> TreeMap<K, V> {
entries
.into_iter()
.map(|(key, value)| MapEntry { key, value }),
&(),
(),
);
Self(tree)
}
@@ -54,7 +54,7 @@ impl<K: Clone + Ord, V: Clone> TreeMap<K, V> {
}
pub fn get(&self, key: &K) -> Option<&V> {
let mut cursor = self.0.cursor::<MapKeyRef<'_, K>>(&());
let mut cursor = self.0.cursor::<MapKeyRef<'_, K>>(());
cursor.seek(&MapKeyRef(Some(key)), Bias::Left);
if let Some(item) = cursor.item() {
if Some(key) == item.key().0.as_ref() {
@@ -68,7 +68,7 @@ impl<K: Clone + Ord, V: Clone> TreeMap<K, V> {
}
pub fn insert(&mut self, key: K, value: V) {
self.0.insert_or_replace(MapEntry { key, value }, &());
self.0.insert_or_replace(MapEntry { key, value }, ());
}
pub fn extend(&mut self, iter: impl IntoIterator<Item = (K, V)>) {
@@ -76,7 +76,7 @@ impl<K: Clone + Ord, V: Clone> TreeMap<K, V> {
.into_iter()
.map(|(key, value)| Edit::Insert(MapEntry { key, value }))
.collect();
self.0.edit(edits, &());
self.0.edit(edits, ());
}
pub fn clear(&mut self) {
@@ -85,14 +85,14 @@ impl<K: Clone + Ord, V: Clone> TreeMap<K, V> {
pub fn remove(&mut self, key: &K) -> Option<V> {
let mut removed = None;
let mut cursor = self.0.cursor::<MapKeyRef<'_, K>>(&());
let mut cursor = self.0.cursor::<MapKeyRef<'_, K>>(());
let key = MapKeyRef(Some(key));
let mut new_tree = cursor.slice(&key, Bias::Left);
if key.cmp(&cursor.end(), &()) == Ordering::Equal {
if key.cmp(&cursor.end(), ()) == Ordering::Equal {
removed = Some(cursor.item().unwrap().value.clone());
cursor.next();
}
new_tree.append(cursor.suffix(), &());
new_tree.append(cursor.suffix(), ());
drop(cursor);
self.0 = new_tree;
removed
@@ -101,17 +101,17 @@ impl<K: Clone + Ord, V: Clone> TreeMap<K, V> {
pub fn remove_range(&mut self, start: &impl MapSeekTarget<K>, end: &impl MapSeekTarget<K>) {
let start = MapSeekTargetAdaptor(start);
let end = MapSeekTargetAdaptor(end);
let mut cursor = self.0.cursor::<MapKeyRef<'_, K>>(&());
let mut cursor = self.0.cursor::<MapKeyRef<'_, K>>(());
let mut new_tree = cursor.slice(&start, Bias::Left);
cursor.seek(&end, Bias::Left);
new_tree.append(cursor.suffix(), &());
new_tree.append(cursor.suffix(), ());
drop(cursor);
self.0 = new_tree;
}
/// Returns the key-value pair with the greatest key less than or equal to the given key.
pub fn closest(&self, key: &K) -> Option<(&K, &V)> {
let mut cursor = self.0.cursor::<MapKeyRef<'_, K>>(&());
let mut cursor = self.0.cursor::<MapKeyRef<'_, K>>(());
let key = MapKeyRef(Some(key));
cursor.seek(&key, Bias::Right);
cursor.prev();
@@ -119,7 +119,7 @@ impl<K: Clone + Ord, V: Clone> TreeMap<K, V> {
}
pub fn iter_from<'a>(&'a self, from: &K) -> impl Iterator<Item = (&'a K, &'a V)> + 'a {
let mut cursor = self.0.cursor::<MapKeyRef<'_, K>>(&());
let mut cursor = self.0.cursor::<MapKeyRef<'_, K>>(());
let from_key = MapKeyRef(Some(from));
cursor.seek(&from_key, Bias::Left);
@@ -130,17 +130,17 @@ impl<K: Clone + Ord, V: Clone> TreeMap<K, V> {
where
F: FnOnce(&mut V) -> T,
{
let mut cursor = self.0.cursor::<MapKeyRef<'_, K>>(&());
let mut cursor = self.0.cursor::<MapKeyRef<'_, K>>(());
let key = MapKeyRef(Some(key));
let mut new_tree = cursor.slice(&key, Bias::Left);
let mut result = None;
if key.cmp(&cursor.end(), &()) == Ordering::Equal {
if key.cmp(&cursor.end(), ()) == Ordering::Equal {
let mut updated = cursor.item().unwrap().clone();
result = Some(f(&mut updated.value));
new_tree.push(updated, &());
new_tree.push(updated, ());
cursor.next();
}
new_tree.append(cursor.suffix(), &());
new_tree.append(cursor.suffix(), ());
drop(cursor);
self.0 = new_tree;
result
@@ -149,11 +149,11 @@ impl<K: Clone + Ord, V: Clone> TreeMap<K, V> {
pub fn retain<F: FnMut(&K, &V) -> bool>(&mut self, mut predicate: F) {
let mut new_map = SumTree::<MapEntry<K, V>>::default();
let mut cursor = self.0.cursor::<MapKeyRef<'_, K>>(&());
let mut cursor = self.0.cursor::<MapKeyRef<'_, K>>(());
cursor.next();
while let Some(item) = cursor.item() {
if predicate(&item.key, &item.value) {
new_map.push(item.clone(), &());
new_map.push(item.clone(), ());
}
cursor.next();
}
@@ -189,7 +189,7 @@ impl<K: Clone + Ord, V: Clone> TreeMap<K, V> {
})
.collect();
self.0.edit(edits, &());
self.0.edit(edits, ());
}
}
@@ -209,7 +209,7 @@ struct MapSeekTargetAdaptor<'a, T>(&'a T);
impl<'a, K: Clone + Ord, T: MapSeekTarget<K>> SeekTarget<'a, MapKey<K>, MapKeyRef<'a, K>>
for MapSeekTargetAdaptor<'_, T>
{
fn cmp(&self, cursor_location: &MapKeyRef<K>, _: &()) -> Ordering {
fn cmp(&self, cursor_location: &MapKeyRef<K>, _: ()) -> Ordering {
if let Some(key) = &cursor_location.0 {
MapSeekTarget::cmp_cursor(self.0, key)
} else {
@@ -245,7 +245,7 @@ where
{
type Summary = MapKey<K>;
fn summary(&self, _cx: &()) -> Self::Summary {
fn summary(&self, _cx: ()) -> Self::Summary {
self.key()
}
}
@@ -262,17 +262,15 @@ where
}
}
impl<K> Summary for MapKey<K>
impl<K> ContextLessSummary for MapKey<K>
where
K: Clone,
{
type Context = ();
fn zero(_cx: &()) -> Self {
fn zero() -> Self {
Default::default()
}
fn add_summary(&mut self, summary: &Self, _: &()) {
fn add_summary(&mut self, summary: &Self) {
*self = summary.clone()
}
}
@@ -281,11 +279,11 @@ impl<'a, K> Dimension<'a, MapKey<K>> for MapKeyRef<'a, K>
where
K: Clone + Ord,
{
fn zero(_cx: &()) -> Self {
fn zero(_cx: ()) -> Self {
Default::default()
}
fn add_summary(&mut self, summary: &'a MapKey<K>, _: &()) {
fn add_summary(&mut self, summary: &'a MapKey<K>, _: ()) {
self.0 = summary.0.as_ref();
}
}
@@ -294,7 +292,7 @@ impl<'a, K> SeekTarget<'a, MapKey<K>, MapKeyRef<'a, K>> for MapKeyRef<'_, K>
where
K: Clone + Ord,
{
fn cmp(&self, cursor_location: &MapKeyRef<K>, _: &()) -> Ordering {
fn cmp(&self, cursor_location: &MapKeyRef<K>, _: ()) -> Ordering {
Ord::cmp(&self.0, &cursor_location.0)
}
}