Replace Default trait bound with a zero function on Summary/Dimension (#17975)

This lets us provide a context when constructing the zero value. We need
it so we can require anchors to be associated with a buffer id, which
we're doing as part of simplifying the multibuffer API.

Release Notes:

- N/A

Co-authored-by: Nathan <nathan@zed.dev>
This commit is contained in:
Antonio Scandurra 2024-09-17 19:43:59 -06:00 committed by GitHub
parent 4d074fc737
commit 2e72fd210a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
28 changed files with 706 additions and 349 deletions

View file

@ -28,21 +28,21 @@ where
T: Item,
D: Dimension<'a, T::Summary>,
{
pub fn new(tree: &'a SumTree<T>) -> Self {
pub fn new(tree: &'a SumTree<T>, cx: &<T::Summary as Summary>::Context) -> Self {
Self {
tree,
stack: ArrayVec::new(),
position: D::default(),
position: D::zero(cx),
did_seek: false,
at_end: tree.is_empty(),
}
}
fn reset(&mut self) {
fn reset(&mut self, cx: &<T::Summary as Summary>::Context) {
self.did_seek = false;
self.at_end = self.tree.is_empty();
self.stack.truncate(0);
self.position = D::default();
self.position = D::zero(cx);
}
pub fn start(&self) -> &D {
@ -192,7 +192,7 @@ where
}
if self.at_end {
self.position = D::default();
self.position = D::zero(cx);
self.at_end = self.tree.is_empty();
if !self.tree.is_empty() {
self.stack.push(StackEntry {
@ -208,7 +208,7 @@ where
if let Some(StackEntry { position, .. }) = self.stack.iter().rev().nth(1) {
self.position = position.clone();
} else {
self.position = D::default();
self.position = D::zero(cx);
}
let entry = self.stack.last_mut().unwrap();
@ -232,7 +232,7 @@ where
if descending {
let tree = &child_trees[entry.index];
self.stack.push(StackEntry {
position: D::default(),
position: D::zero(cx),
tree,
index: tree.0.child_summaries().len() - 1,
})
@ -264,7 +264,7 @@ where
self.stack.push(StackEntry {
tree: self.tree,
index: 0,
position: D::default(),
position: D::zero(cx),
});
descend = true;
}
@ -364,7 +364,7 @@ where
where
Target: SeekTarget<'a, T::Summary, D>,
{
self.reset();
self.reset(cx);
self.seek_internal(pos, bias, &mut (), cx)
}
@ -392,10 +392,10 @@ where
Target: SeekTarget<'a, T::Summary, D>,
{
let mut slice = SliceSeekAggregate {
tree: SumTree::new(),
tree: SumTree::new(cx),
leaf_items: ArrayVec::new(),
leaf_item_summaries: ArrayVec::new(),
leaf_summary: T::Summary::default(),
leaf_summary: <T::Summary as Summary>::zero(cx),
};
self.seek_internal(end, bias, &mut slice, cx);
slice.tree
@ -417,7 +417,7 @@ where
Target: SeekTarget<'a, T::Summary, D>,
Output: Dimension<'a, T::Summary>,
{
let mut summary = SummarySeekAggregate(Output::default());
let mut summary = SummarySeekAggregate(Output::zero(cx));
self.seek_internal(end, bias, &mut summary, cx);
summary.0
}
@ -443,7 +443,7 @@ where
self.stack.push(StackEntry {
tree: self.tree,
index: 0,
position: Default::default(),
position: D::zero(cx),
});
}
@ -633,8 +633,12 @@ where
T: Item,
D: Dimension<'a, T::Summary>,
{
pub fn new(tree: &'a SumTree<T>, filter_node: F) -> Self {
let cursor = tree.cursor::<D>();
pub fn new(
tree: &'a SumTree<T>,
cx: &<T::Summary as Summary>::Context,
filter_node: F,
) -> Self {
let cursor = tree.cursor::<D>(cx);
Self {
cursor,
filter_node,
@ -727,7 +731,7 @@ impl<'a, T: Item> SeekAggregate<'a, T> for SliceSeekAggregate<T> {
fn end_leaf(&mut self, cx: &<T::Summary as Summary>::Context) {
self.tree.append(
SumTree(Arc::new(Node::Leaf {
summary: mem::take(&mut self.leaf_summary),
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),
})),

View file

@ -34,9 +34,11 @@ pub trait KeyedItem: Item {
///
/// Each Summary type can have multiple [`Dimensions`] that it measures,
/// which can be used to navigate the tree
pub trait Summary: Default + Clone + fmt::Debug {
pub trait Summary: Clone + fmt::Debug {
type Context;
fn zero(cx: &Self::Context) -> Self;
fn add_summary(&mut self, summary: &Self, cx: &Self::Context);
}
@ -47,17 +49,23 @@ pub trait Summary: Default + Clone + fmt::Debug {
/// # Example:
/// 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 + fmt::Debug + Default {
fn add_summary(&mut self, _summary: &'a S, _: &S::Context);
pub trait Dimension<'a, S: Summary>: Clone + fmt::Debug {
fn zero(cx: &S::Context) -> Self;
fn add_summary(&mut self, summary: &'a S, cx: &S::Context);
fn from_summary(summary: &'a S, cx: &S::Context) -> Self {
let mut dimension = Self::default();
let mut dimension = Self::zero(cx);
dimension.add_summary(summary, cx);
dimension
}
}
impl<'a, T: Summary> Dimension<'a, T> for T {
fn zero(cx: &T::Context) -> Self {
Summary::zero(cx)
}
fn add_summary(&mut self, summary: &'a T, cx: &T::Context) {
Summary::add_summary(self, summary, cx);
}
@ -74,10 +82,18 @@ impl<'a, S: Summary, D: Dimension<'a, S> + Ord> SeekTarget<'a, S, D> for D {
}
impl<'a, T: Summary> Dimension<'a, T> for () {
fn zero(_: &T::Context) -> Self {
()
}
fn add_summary(&mut self, _: &'a T, _: &T::Context) {}
}
impl<'a, T: Summary, D1: Dimension<'a, T>, D2: Dimension<'a, T>> Dimension<'a, T> for (D1, D2) {
fn zero(cx: &T::Context) -> Self {
(D1::zero(cx), D2::zero(cx))
}
fn add_summary(&mut self, summary: &'a T, cx: &T::Context) {
self.0.add_summary(summary, cx);
self.1.add_summary(summary, cx);
@ -161,16 +177,16 @@ impl Bias {
pub struct SumTree<T: Item>(Arc<Node<T>>);
impl<T: Item> SumTree<T> {
pub fn new() -> Self {
pub fn new(cx: &<T::Summary as Summary>::Context) -> Self {
SumTree(Arc::new(Node::Leaf {
summary: T::Summary::default(),
summary: <T::Summary as Summary>::zero(cx),
items: ArrayVec::new(),
item_summaries: ArrayVec::new(),
}))
}
pub fn from_item(item: T, cx: &<T::Summary as Summary>::Context) -> Self {
let mut tree = Self::new();
let mut tree = Self::new(cx);
tree.push(item, cx);
tree
}
@ -206,7 +222,7 @@ impl<T: Item> SumTree<T> {
let mut current_parent_node = None;
for child_node in nodes.drain(..) {
let parent_node = current_parent_node.get_or_insert_with(|| Node::Internal {
summary: T::Summary::default(),
summary: <T::Summary as Summary>::zero(cx),
height,
child_summaries: ArrayVec::new(),
child_trees: ArrayVec::new(),
@ -234,7 +250,7 @@ impl<T: Item> SumTree<T> {
}
if nodes.is_empty() {
Self::new()
Self::new(cx)
} else {
debug_assert_eq!(nodes.len(), 1);
Self(Arc::new(nodes.pop().unwrap()))
@ -296,7 +312,7 @@ impl<T: Item> SumTree<T> {
}
if nodes.is_empty() {
Self::new()
Self::new(cx)
} else {
debug_assert_eq!(nodes.len(), 1);
nodes.pop().unwrap()
@ -306,7 +322,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::<()>(cx);
cursor.next(cx);
while let Some(item) = cursor.item() {
items.push(item.clone());
@ -319,21 +335,25 @@ impl<T: Item> SumTree<T> {
Iter::new(self)
}
pub fn cursor<'a, S>(&'a self) -> Cursor<T, S>
pub fn cursor<'a, S>(&'a self, cx: &<T::Summary as Summary>::Context) -> Cursor<T, S>
where
S: Dimension<'a, T::Summary>,
{
Cursor::new(self)
Cursor::new(self, cx)
}
/// 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>(&'a self, filter_node: F) -> FilterCursor<F, T, U>
pub fn filter<'a, F, U>(
&'a self,
cx: &<T::Summary as Summary>::Context,
filter_node: F,
) -> FilterCursor<F, T, U>
where
F: FnMut(&T::Summary) -> bool,
U: Dimension<'a, T::Summary>,
{
FilterCursor::new(self, filter_node)
FilterCursor::new(self, cx, filter_node)
}
#[allow(dead_code)]
@ -389,7 +409,7 @@ impl<T: Item> SumTree<T> {
&'a self,
cx: &<T::Summary as Summary>::Context,
) -> D {
let mut extent = D::default();
let mut extent = D::zero(cx);
match self.0.as_ref() {
Node::Internal { summary, .. } | Node::Leaf { summary, .. } => {
extent.add_summary(summary, cx);
@ -636,7 +656,7 @@ impl<T: KeyedItem> SumTree<T> {
) -> Option<T> {
let mut replaced = None;
*self = {
let mut cursor = self.cursor::<T::Key>();
let mut cursor = self.cursor::<T::Key>(cx);
let mut new_tree = cursor.slice(&item.key(), Bias::Left, cx);
if let Some(cursor_item) = cursor.item() {
if cursor_item.key() == item.key() {
@ -654,7 +674,7 @@ impl<T: KeyedItem> SumTree<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>();
let mut cursor = self.cursor::<T::Key>(cx);
let mut new_tree = cursor.slice(key, Bias::Left, cx);
if let Some(item) = cursor.item() {
if item.key() == *key {
@ -681,11 +701,11 @@ impl<T: KeyedItem> SumTree<T> {
edits.sort_unstable_by_key(|item| item.key());
*self = {
let mut cursor = self.cursor::<T::Key>();
let mut new_tree = SumTree::new();
let mut cursor = self.cursor::<T::Key>(cx);
let mut new_tree = SumTree::new(cx);
let mut buffered_items = Vec::new();
cursor.seek(&T::Key::default(), Bias::Left, cx);
cursor.seek(&T::Key::zero(cx), Bias::Left, cx);
for edit in edits {
let new_key = edit.key();
let mut old_item = cursor.item();
@ -724,7 +744,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>(cx);
if cursor.seek(key, Bias::Left, cx) {
cursor.item()
} else {
@ -733,9 +753,13 @@ impl<T: KeyedItem> SumTree<T> {
}
}
impl<T: Item> Default for SumTree<T> {
impl<T, S> Default for SumTree<T>
where
T: Item<Summary = S>,
S: Summary<Context = ()>,
{
fn default() -> Self {
Self::new()
Self::new(&())
}
}
@ -824,7 +848,7 @@ where
T: 'a + Summary,
I: Iterator<Item = &'a T>,
{
let mut sum = T::default();
let mut sum = T::zero(cx);
for value in iter {
sum.add_summary(value, cx);
}
@ -846,10 +870,10 @@ mod tests {
#[test]
fn test_extend_and_push_tree() {
let mut tree1 = SumTree::new();
let mut tree1 = SumTree::default();
tree1.extend(0..20, &());
let mut tree2 = SumTree::new();
let mut tree2 = SumTree::default();
tree2.extend(50..100, &());
tree1.append(tree2, &());
@ -877,7 +901,7 @@ mod tests {
let mut rng = StdRng::seed_from_u64(seed);
let rng = &mut rng;
let mut tree = SumTree::<u8>::new();
let mut tree = SumTree::<u8>::default();
let count = rng.gen_range(0..10);
if rng.gen() {
tree.extend(rng.sample_iter(distributions::Standard).take(count), &());
@ -903,7 +927,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, &());
if rng.gen() {
new_tree.extend(new_items, &());
@ -918,12 +942,13 @@ mod tests {
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(&()));
let mut filter_cursor = tree.filter::<_, Count>(|summary| summary.contains_even);
let mut filter_cursor =
tree.filter::<_, Count>(&(), |summary| summary.contains_even);
let expected_filtered_items = tree
.items(&())
.into_iter()
@ -964,7 +989,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.gen_range(0..=reference_items.len());
cursor.seek(&Count(start_pos), Bias::Right, &());
let mut pos = rng.gen_range(start_pos..=reference_items.len());
@ -1015,7 +1040,7 @@ 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, &());
@ -1030,8 +1055,8 @@ mod tests {
#[test]
fn test_cursor() {
// Empty tree
let tree = SumTree::<u8>::new();
let mut cursor = tree.cursor::<IntegersSummary>();
let tree = SumTree::<u8>::default();
let mut cursor = tree.cursor::<IntegersSummary>(&());
assert_eq!(
cursor.slice(&Count(0), Bias::Right, &()).items(&()),
Vec::<u8>::new()
@ -1052,9 +1077,9 @@ mod tests {
assert_eq!(cursor.start().sum, 0);
// Single-element tree
let mut tree = SumTree::<u8>::new();
let mut tree = SumTree::<u8>::default();
tree.extend(vec![1], &());
let mut cursor = tree.cursor::<IntegersSummary>();
let mut cursor = tree.cursor::<IntegersSummary>(&());
assert_eq!(
cursor.slice(&Count(0), Bias::Right, &()).items(&()),
Vec::<u8>::new()
@ -1076,7 +1101,7 @@ mod tests {
assert_eq!(cursor.next_item(), None);
assert_eq!(cursor.start().sum, 0);
let mut cursor = tree.cursor::<IntegersSummary>();
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));
@ -1096,9 +1121,9 @@ mod tests {
assert_eq!(cursor.start().sum, 1);
// Multiple-element tree
let mut tree = SumTree::new();
let mut tree = SumTree::default();
tree.extend(vec![1, 2, 3, 4, 5, 6], &());
let mut cursor = tree.cursor::<IntegersSummary>();
let mut cursor = tree.cursor::<IntegersSummary>(&());
assert_eq!(cursor.slice(&Count(2), Bias::Right, &()).items(&()), [1, 2]);
assert_eq!(cursor.item(), Some(&3));
@ -1179,7 +1204,7 @@ 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, &())
@ -1227,7 +1252,7 @@ mod tests {
#[test]
fn test_edit() {
let mut tree = SumTree::<u8>::new();
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]);
@ -1305,6 +1330,10 @@ mod tests {
impl Summary for IntegersSummary {
type Context = ();
fn zero(_cx: &()) -> Self {
Default::default()
}
fn add_summary(&mut self, other: &Self, _: &()) {
self.count += other.count;
self.sum += other.sum;
@ -1314,12 +1343,20 @@ mod tests {
}
impl<'a> Dimension<'a, IntegersSummary> for u8 {
fn zero(_cx: &()) -> Self {
Default::default()
}
fn add_summary(&mut self, summary: &IntegersSummary, _: &()) {
*self = summary.max;
}
}
impl<'a> Dimension<'a, IntegersSummary> for Count {
fn zero(_cx: &()) -> Self {
Default::default()
}
fn add_summary(&mut self, summary: &IntegersSummary, _: &()) {
self.0 += summary.count;
}
@ -1332,6 +1369,10 @@ mod tests {
}
impl<'a> Dimension<'a, IntegersSummary> for Sum {
fn zero(_cx: &()) -> Self {
Default::default()
}
fn add_summary(&mut self, summary: &IntegersSummary, _: &()) {
self.0 += summary.sum;
}

View file

@ -53,7 +53,7 @@ impl<K: Clone + Debug + Ord, V: Clone + Debug> 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() {
@ -72,7 +72,7 @@ impl<K: Clone + Debug + Ord, V: Clone + Debug> 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 {
@ -88,7 +88,7 @@ impl<K: Clone + Debug + Ord, V: Clone + Debug> 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(&()), &());
@ -98,7 +98,7 @@ impl<K: Clone + Debug + Ord, V: Clone + Debug> TreeMap<K, V> {
/// 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(&());
@ -106,7 +106,7 @@ impl<K: Clone + Debug + Ord, V: Clone + Debug> TreeMap<K, V> {
}
pub fn iter_from<'a>(&'a self, from: &'a K) -> impl Iterator<Item = (&K, &V)> + '_ {
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, &());
@ -117,7 +117,7 @@ impl<K: Clone + Debug + Ord, V: Clone + Debug> 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;
@ -136,7 +136,7 @@ impl<K: Clone + Debug + Ord, V: Clone + Debug> 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) {
@ -247,6 +247,10 @@ where
{
type Context = ();
fn zero(_cx: &()) -> Self {
Default::default()
}
fn add_summary(&mut self, summary: &Self, _: &()) {
*self = summary.clone()
}
@ -256,6 +260,10 @@ impl<'a, K> Dimension<'a, MapKey<K>> for MapKeyRef<'a, K>
where
K: Clone + Debug + Ord,
{
fn zero(_cx: &()) -> Self {
Default::default()
}
fn add_summary(&mut self, summary: &'a MapKey<K>, _: &()) {
self.0 = summary.0.as_ref();
}