Detailed changes
@@ -5,7 +5,7 @@ pub mod movement;
use crate::{
settings::{Settings, StyleId},
- util::post_inc,
+ util::{post_inc, Bias},
workspace,
worktree::FileHandle,
};
@@ -723,9 +723,7 @@ impl Editor {
let mut new_selections = Vec::new();
self.buffer.update(cx, |buffer, cx| {
let edit_ranges = old_selections.iter().map(|(_, range)| range.clone());
- if let Err(error) = buffer.edit(edit_ranges, text.as_str(), Some(cx)) {
- log::error!("error inserting text: {}", error);
- };
+ buffer.edit(edit_ranges, text.as_str(), Some(cx));
let text_len = text.len() as isize;
let mut delta = 0_isize;
new_selections = old_selections
@@ -4139,12 +4137,6 @@ mod tests {
}
}
-#[derive(Copy, Clone)]
-pub enum Bias {
- Left,
- Right,
-}
-
trait RangeExt<T> {
fn sorted(&self) -> Range<T>;
fn to_inclusive(&self) -> RangeInclusive<T>;
@@ -13,12 +13,12 @@ use similar::{ChangeTag, TextDiff};
use tree_sitter::{InputEdit, Parser, QueryCursor};
use crate::{
- editor::Bias,
language::{Language, Tree},
operation_queue::{self, OperationQueue},
settings::{StyleId, ThemeMap},
- sum_tree::{self, FilterCursor, SeekBias, SumTree},
+ sum_tree::{self, FilterCursor, SumTree},
time::{self, ReplicaId},
+ util::Bias,
worktree::FileHandle,
};
use anyhow::{anyhow, Result};
@@ -28,8 +28,7 @@ use std::{
cell::RefCell,
cmp,
hash::BuildHasher,
- iter::{self, Iterator},
- mem,
+ iter::Iterator,
ops::{Deref, DerefMut, Range},
str,
sync::Arc,
@@ -109,7 +108,6 @@ pub struct Buffer {
fragments: SumTree<Fragment>,
visible_text: Rope,
deleted_text: Rope,
- insertion_splits: HashMap<time::Local, SumTree<InsertionSplit>>,
pub version: time::Global,
saved_version: time::Global,
saved_mtime: SystemTime,
@@ -171,7 +169,7 @@ impl History {
}
fn push(&mut self, op: EditOperation) {
- self.ops.insert(op.id, op);
+ self.ops.insert(op.timestamp.local(), op);
}
fn start_transaction(
@@ -328,61 +326,62 @@ struct Diff {
changes: Vec<(ChangeTag, usize)>,
}
-#[derive(Clone, Eq, PartialEq, Debug)]
-pub struct Insertion {
- id: time::Local,
- parent_id: time::Local,
- offset_in_parent: usize,
- lamport_timestamp: time::Lamport,
+#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
+struct InsertionTimestamp {
+ replica_id: ReplicaId,
+ local: time::Seq,
+ lamport: time::Seq,
+}
+
+impl InsertionTimestamp {
+ fn local(&self) -> time::Local {
+ time::Local {
+ replica_id: self.replica_id,
+ value: self.local,
+ }
+ }
+
+ fn lamport(&self) -> time::Lamport {
+ time::Lamport {
+ replica_id: self.replica_id,
+ value: self.lamport,
+ }
+ }
}
#[derive(Eq, PartialEq, Clone, Debug)]
struct Fragment {
- id: FragmentId,
- insertion: Arc<Insertion>,
- range_in_insertion: Range<usize>,
+ timestamp: InsertionTimestamp,
+ len: usize,
+ visible: bool,
deletions: HashSet<time::Local>,
max_undos: time::Global,
- visible: bool,
}
#[derive(Eq, PartialEq, Clone, Debug)]
pub struct FragmentSummary {
text: FragmentTextSummary,
- max_fragment_id: FragmentId,
max_version: time::Global,
+ min_insertion_version: time::Global,
+ max_insertion_version: time::Global,
}
-#[derive(Default, Clone, Debug, PartialEq, Eq)]
+#[derive(Copy, Default, Clone, Debug, PartialEq, Eq)]
struct FragmentTextSummary {
visible: usize,
deleted: usize,
}
impl<'a> sum_tree::Dimension<'a, FragmentSummary> for FragmentTextSummary {
- fn add_summary(&mut self, summary: &'a FragmentSummary) {
+ fn add_summary(&mut self, summary: &'a FragmentSummary, _: &Option<time::Global>) {
self.visible += summary.text.visible;
self.deleted += summary.text.deleted;
}
}
-#[derive(Eq, PartialEq, Clone, Debug)]
-struct InsertionSplit {
- extent: usize,
- fragment_id: FragmentId,
-}
-
-#[derive(Eq, PartialEq, Clone, Debug)]
-struct InsertionSplitSummary {
- extent: usize,
-}
-
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Operation {
- Edit {
- edit: EditOperation,
- lamport_timestamp: time::Lamport,
- },
+ Edit(EditOperation),
Undo {
undo: UndoOperation,
lamport_timestamp: time::Lamport,
@@ -396,12 +395,9 @@ pub enum Operation {
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct EditOperation {
- id: time::Local,
- start_id: time::Local,
- start_offset: usize,
- end_id: time::Local,
- end_offset: usize,
- version_in_range: time::Global,
+ timestamp: InsertionTimestamp,
+ version: time::Global,
+ ranges: Vec<Range<usize>>,
new_text: Option<String>,
}
@@ -474,53 +470,19 @@ impl Buffer {
saved_mtime = UNIX_EPOCH;
}
- let mut visible_text = Rope::new();
- let mut insertion_splits = HashMap::default();
let mut fragments = SumTree::new();
- let base_text = Rope::from(history.base_text.as_ref());
- let base_insertion = Arc::new(Insertion {
- id: time::Local::default(),
- parent_id: time::Local::default(),
- offset_in_parent: 0,
- lamport_timestamp: time::Lamport::default(),
- });
-
- insertion_splits.insert(
- base_insertion.id,
- SumTree::from_item(
- InsertionSplit {
- fragment_id: FragmentId::min_value().clone(),
- extent: 0,
- },
- &(),
- ),
- );
- fragments.push(
- Fragment::new(
- FragmentId::min_value().clone(),
- base_insertion.clone(),
- 0..0,
- ),
- &(),
- );
-
- if base_text.len() > 0 {
- let base_fragment_id =
- FragmentId::between(&FragmentId::min_value(), &FragmentId::max_value());
- let range_in_insertion = 0..base_text.len();
-
- visible_text = base_text.clone();
- insertion_splits.get_mut(&base_insertion.id).unwrap().push(
- InsertionSplit {
- fragment_id: base_fragment_id.clone(),
- extent: range_in_insertion.end,
- },
- &(),
- );
+ let visible_text = Rope::from(history.base_text.as_ref());
+ if visible_text.len() > 0 {
fragments.push(
- Fragment::new(base_fragment_id, base_insertion, range_in_insertion.clone()),
- &(),
+ Fragment {
+ timestamp: Default::default(),
+ len: visible_text.len(),
+ visible: true,
+ deletions: Default::default(),
+ max_undos: Default::default(),
+ },
+ &None,
);
}
@@ -528,7 +490,6 @@ impl Buffer {
visible_text,
deleted_text: Rope::new(),
fragments,
- insertion_splits,
version: time::Global::new(),
saved_version: time::Global::new(),
last_edit: time::Local::default(),
@@ -781,12 +742,11 @@ impl Buffer {
match tag {
ChangeTag::Equal => offset += len,
ChangeTag::Delete => {
- operations.extend_from_slice(&self.edit(Some(range), "", Some(cx)).unwrap())
+ operations.push(self.edit(Some(range), "", Some(cx)).unwrap())
}
ChangeTag::Insert => {
- operations.extend_from_slice(
- &self
- .edit(Some(offset..offset), &diff.new_text[range], Some(cx))
+ operations.push(
+ self.edit(Some(offset..offset), &diff.new_text[range], Some(cx))
.unwrap(),
);
offset += len;
@@ -825,7 +785,7 @@ impl Buffer {
}
pub fn len(&self) -> usize {
- self.fragments.extent::<usize>()
+ self.fragments.extent::<usize>(&None)
}
pub fn line_len(&self, row: u32) -> u32 {
@@ -871,9 +831,10 @@ impl Buffer {
pub fn edits_since<'a>(&'a self, since: time::Global) -> impl 'a + Iterator<Item = Edit> {
let since_2 = since.clone();
- let cursor = self
- .fragments
- .filter(move |summary| summary.max_version.changed_since(&since_2));
+ let cursor = self.fragments.filter(
+ move |summary| summary.max_version.changed_since(&since_2),
+ &None,
+ );
Edits {
deleted_text: &self.deleted_text,
@@ -951,56 +912,60 @@ impl Buffer {
pub fn edit<I, S, T>(
&mut self,
- old_ranges: I,
+ ranges_iter: I,
new_text: T,
cx: Option<&mut ModelContext<Self>>,
- ) -> Result<Vec<Operation>>
+ ) -> Option<Operation>
where
I: IntoIterator<Item = Range<S>>,
S: ToOffset,
T: Into<String>,
{
- self.start_transaction_at(None, Instant::now())?;
-
let new_text = new_text.into();
- let old_ranges = old_ranges
- .into_iter()
- .map(|range| range.start.to_offset(self)..range.end.to_offset(self))
- .collect::<Vec<Range<usize>>>();
-
let new_text = if new_text.len() > 0 {
Some(new_text)
} else {
None
};
-
let has_new_text = new_text.is_some();
- let ops = self.splice_fragments(
- old_ranges
- .into_iter()
- .filter(|old_range| has_new_text || old_range.end > old_range.start),
- new_text.into(),
- );
- for op in &ops {
- if let Operation::Edit { edit, .. } = op {
- self.history.push(edit.clone());
- self.history.push_undo(edit.id);
+ // Skip invalid ranges and coalesce contiguous ones.
+ let mut ranges: Vec<Range<usize>> = Vec::new();
+ for range in ranges_iter {
+ let range = range.start.to_offset(self)..range.end.to_offset(self);
+ if has_new_text || !range.is_empty() {
+ if let Some(prev_range) = ranges.last_mut() {
+ if prev_range.end >= range.start {
+ prev_range.end = cmp::max(prev_range.end, range.end);
+ } else {
+ ranges.push(range);
+ }
+ } else {
+ ranges.push(range);
+ }
}
}
- if let Some(op) = ops.last() {
- if let Operation::Edit { edit, .. } = op {
- self.last_edit = edit.id;
- self.version.observe(edit.id);
- } else {
- unreachable!()
- }
- }
+ if ranges.is_empty() {
+ None
+ } else {
+ self.start_transaction_at(None, Instant::now()).unwrap();
+ let timestamp = InsertionTimestamp {
+ replica_id: self.replica_id,
+ local: self.local_clock.tick().value,
+ lamport: self.lamport_clock.tick().value,
+ };
+ let edit = self.apply_local_edit(&ranges, new_text, timestamp);
+
+ self.history.push(edit.clone());
+ self.history.push_undo(edit.timestamp.local());
+ self.last_edit = edit.timestamp.local();
+ self.version.observe(edit.timestamp.local());
- self.end_transaction_at(None, Instant::now(), cx)?;
+ self.end_transaction_at(None, Instant::now(), cx).unwrap();
- Ok(ops)
+ Some(Operation::Edit(edit))
+ }
}
fn did_edit(&self, was_dirty: bool, cx: &mut ModelContext<Self>) {
@@ -1120,23 +1085,15 @@ impl Buffer {
fn apply_op(&mut self, op: Operation) -> Result<()> {
match op {
- Operation::Edit {
- edit,
- lamport_timestamp,
- ..
- } => {
- if !self.version.observed(edit.id) {
- self.apply_edit(
- edit.start_id,
- edit.start_offset,
- edit.end_id,
- edit.end_offset,
+ Operation::Edit(edit) => {
+ if !self.version.observed(edit.timestamp.local()) {
+ self.apply_remote_edit(
+ &edit.version,
+ &edit.ranges,
edit.new_text.as_deref(),
- &edit.version_in_range,
- edit.id,
- lamport_timestamp,
- )?;
- self.version.observe(edit.id);
+ edit.timestamp,
+ );
+ self.version.observe(edit.timestamp.local());
self.history.push(edit);
}
}
@@ -1167,154 +1124,149 @@ impl Buffer {
Ok(())
}
- fn apply_edit(
+ fn apply_remote_edit(
&mut self,
- start_id: time::Local,
- start_offset: usize,
- end_id: time::Local,
- end_offset: usize,
- mut new_text: Option<&str>,
- version_in_range: &time::Global,
- local_timestamp: time::Local,
- lamport_timestamp: time::Lamport,
- ) -> Result<()> {
- let start_fragment_id = self.resolve_fragment_id(start_id, start_offset)?;
- let end_fragment_id = self.resolve_fragment_id(end_id, end_offset)?;
-
- let mut old_visible_text = Rope::new();
- let mut old_deleted_text = Rope::new();
- let mut old_fragments = SumTree::new();
- mem::swap(&mut old_visible_text, &mut self.visible_text);
- mem::swap(&mut old_deleted_text, &mut self.deleted_text);
- mem::swap(&mut old_fragments, &mut self.fragments);
-
- let mut fragments_cursor = old_fragments.cursor::<FragmentIdRef, FragmentTextSummary>();
+ version: &time::Global,
+ ranges: &[Range<usize>],
+ new_text: Option<&str>,
+ timestamp: InsertionTimestamp,
+ ) {
+ if ranges.is_empty() {
+ return;
+ }
- let mut new_fragments =
- fragments_cursor.slice(&FragmentIdRef::new(&start_fragment_id), SeekBias::Left, &());
+ let cx = Some(version.clone());
let mut new_ropes =
- RopeBuilder::new(old_visible_text.cursor(0), old_deleted_text.cursor(0));
+ RopeBuilder::new(self.visible_text.cursor(0), self.deleted_text.cursor(0));
+ let mut old_fragments = self.fragments.cursor::<VersionedOffset, VersionedOffset>();
+ let mut new_fragments =
+ old_fragments.slice(&VersionedOffset::Offset(ranges[0].start), Bias::Left, &cx);
new_ropes.push_tree(new_fragments.summary().text);
- let start_fragment = fragments_cursor.item().unwrap();
- if start_offset == start_fragment.range_in_insertion.end {
- let fragment = fragments_cursor.item().unwrap().clone();
- new_ropes.push_fragment(&fragment, fragment.visible);
- new_fragments.push(fragment, &());
- fragments_cursor.next();
- }
+ let mut fragment_start = old_fragments.start().offset();
+ for range in ranges {
+ let fragment_end = old_fragments.end(&cx).offset();
+
+ // If the current fragment ends before this range, then jump ahead to the first fragment
+ // that extends past the start of this range, reusing any intervening fragments.
+ if fragment_end < range.start {
+ // If the current fragment has been partially consumed, then consume the rest of it
+ // and advance to the next fragment before slicing.
+ if fragment_start > old_fragments.start().offset() {
+ if fragment_end > fragment_start {
+ let mut suffix = old_fragments.item().unwrap().clone();
+ suffix.len = fragment_end - fragment_start;
+ new_ropes.push_fragment(&suffix, suffix.visible);
+ new_fragments.push(suffix, &None);
+ }
+ old_fragments.next(&cx);
+ }
- while let Some(fragment) = fragments_cursor.item() {
- if new_text.is_none() && fragment.id > end_fragment_id {
- break;
+ let slice =
+ old_fragments.slice(&VersionedOffset::Offset(range.start), Bias::Left, &cx);
+ new_ropes.push_tree(slice.summary().text);
+ new_fragments.push_tree(slice, &None);
+ fragment_start = old_fragments.start().offset();
}
- let mut fragment = fragment.clone();
+ // If we are at the end of a non-concurrent fragment, advance to the next one.
+ let fragment_end = old_fragments.end(&cx).offset();
+ if fragment_end == range.start && fragment_end > fragment_start {
+ let mut fragment = old_fragments.item().unwrap().clone();
+ fragment.len = fragment_end - fragment_start;
+ new_ropes.push_fragment(&fragment, fragment.visible);
+ new_fragments.push(fragment, &None);
+ old_fragments.next(&cx);
+ fragment_start = old_fragments.start().offset();
+ }
- if fragment.id == start_fragment_id || fragment.id == end_fragment_id {
- let split_start = if start_fragment_id == fragment.id {
- start_offset
- } else {
- fragment.range_in_insertion.start
- };
- let split_end = if end_fragment_id == fragment.id {
- end_offset
- } else {
- fragment.range_in_insertion.end
- };
- let (before_range, within_range, after_range) = self.split_fragment(
- fragments_cursor.prev_item().as_ref().unwrap(),
- &fragment,
- split_start..split_end,
- );
- let insertion = if let Some(new_text) = new_text {
- let prev_fragment = fragments_cursor.prev_item();
- Some(self.build_fragment_to_insert(
- before_range.as_ref().or(prev_fragment).unwrap(),
- within_range.as_ref().or(after_range.as_ref()),
- new_text,
- local_timestamp,
- lamport_timestamp,
- ))
+ // Skip over insertions that are concurrent to this edit, but have a lower lamport
+ // timestamp.
+ while let Some(fragment) = old_fragments.item() {
+ if fragment_start == range.start
+ && fragment.timestamp.lamport() > timestamp.lamport()
+ {
+ new_ropes.push_fragment(fragment, fragment.visible);
+ new_fragments.push(fragment.clone(), &None);
+ old_fragments.next(&cx);
+ debug_assert_eq!(fragment_start, range.start);
} else {
- None
- };
- if let Some(fragment) = before_range {
- new_ropes.push_fragment(&fragment, fragment.visible);
- new_fragments.push(fragment, &());
- }
- if let Some(fragment) = insertion {
- new_ropes.push_str(new_text.take().unwrap());
- new_fragments.push(fragment, &());
+ break;
}
- if let Some(mut fragment) = within_range {
- let fragment_was_visible = fragment.visible;
- if fragment.was_visible(&version_in_range, &self.undo_map) {
- fragment.deletions.insert(local_timestamp);
- if fragment.visible {
- fragment.visible = false;
- }
- }
+ }
+ debug_assert!(fragment_start <= range.start);
+
+ // Preserve any portion of the current fragment that precedes this range.
+ if fragment_start < range.start {
+ let mut prefix = old_fragments.item().unwrap().clone();
+ prefix.len = range.start - fragment_start;
+ fragment_start = range.start;
+ new_ropes.push_fragment(&prefix, prefix.visible);
+ new_fragments.push(prefix, &None);
+ }
- new_ropes.push_fragment(&fragment, fragment_was_visible);
- new_fragments.push(fragment, &());
+ // Insert the new text before any existing fragments within the range.
+ if let Some(new_text) = new_text {
+ new_ropes.push_str(new_text);
+ new_fragments.push(
+ Fragment {
+ timestamp,
+ len: new_text.len(),
+ deletions: Default::default(),
+ max_undos: Default::default(),
+ visible: true,
+ },
+ &None,
+ );
+ }
+
+ // Advance through every fragment that intersects this range, marking the intersecting
+ // portions as deleted.
+ while fragment_start < range.end {
+ let fragment = old_fragments.item().unwrap();
+ let fragment_end = old_fragments.end(&cx).offset();
+ let mut intersection = fragment.clone();
+ let intersection_end = cmp::min(range.end, fragment_end);
+ if fragment.was_visible(version, &self.undo_map) {
+ intersection.len = intersection_end - fragment_start;
+ intersection.deletions.insert(timestamp.local());
+ intersection.visible = false;
}
- if let Some(fragment) = after_range {
- new_ropes.push_fragment(&fragment, fragment.visible);
- new_fragments.push(fragment, &());
+ if intersection.len > 0 {
+ new_ropes.push_fragment(&intersection, fragment.visible);
+ new_fragments.push(intersection, &None);
+ fragment_start = intersection_end;
}
- } else {
- if new_text.is_some() && lamport_timestamp > fragment.insertion.lamport_timestamp {
- let new_text = new_text.take().unwrap();
- let fragment = self.build_fragment_to_insert(
- fragments_cursor.prev_item().as_ref().unwrap(),
- Some(&fragment),
- new_text,
- local_timestamp,
- lamport_timestamp,
- );
- new_ropes.push_str(new_text);
- new_fragments.push(fragment, &());
- }
-
- let fragment_was_visible = fragment.visible;
- if fragment.id < end_fragment_id
- && fragment.was_visible(&version_in_range, &self.undo_map)
- {
- fragment.deletions.insert(local_timestamp);
- if fragment.visible {
- fragment.visible = false;
- }
+ if fragment_end <= range.end {
+ old_fragments.next(&cx);
}
-
- new_ropes.push_fragment(&fragment, fragment_was_visible);
- new_fragments.push(fragment, &());
}
-
- fragments_cursor.next();
}
- if let Some(new_text) = new_text {
- let fragment = self.build_fragment_to_insert(
- fragments_cursor.prev_item().as_ref().unwrap(),
- None,
- new_text,
- local_timestamp,
- lamport_timestamp,
- );
- new_ropes.push_str(new_text);
- new_fragments.push(fragment, &());
+ // If the current fragment has been partially consumed, then consume the rest of it
+ // and advance to the next fragment before slicing.
+ if fragment_start > old_fragments.start().offset() {
+ let fragment_end = old_fragments.end(&cx).offset();
+ if fragment_end > fragment_start {
+ let mut suffix = old_fragments.item().unwrap().clone();
+ suffix.len = fragment_end - fragment_start;
+ new_ropes.push_fragment(&suffix, suffix.visible);
+ new_fragments.push(suffix, &None);
+ }
+ old_fragments.next(&cx);
}
+ let suffix = old_fragments.suffix(&cx);
+ new_ropes.push_tree(suffix.summary().text);
+ new_fragments.push_tree(suffix, &None);
let (visible_text, deleted_text) = new_ropes.finish();
- new_fragments.push_tree(fragments_cursor.suffix(&()), &());
+ drop(old_fragments);
self.fragments = new_fragments;
self.visible_text = visible_text;
self.deleted_text = deleted_text;
- self.local_clock.observe(local_timestamp);
- self.lamport_clock.observe(lamport_timestamp);
- Ok(())
+ self.local_clock.observe(timestamp.local());
+ self.lamport_clock.observe(timestamp.lamport());
}
pub fn undo(&mut self, mut cx: Option<&mut ModelContext<Self>>) -> Vec<Operation> {
@@ -1387,85 +1339,60 @@ impl Buffer {
}
fn apply_undo(&mut self, undo: UndoOperation) -> Result<()> {
- let mut new_fragments;
- let mut old_visible_text = Rope::new();
- let mut old_deleted_text = Rope::new();
- mem::swap(&mut old_visible_text, &mut self.visible_text);
- mem::swap(&mut old_deleted_text, &mut self.deleted_text);
- let mut new_ropes =
- RopeBuilder::new(old_visible_text.cursor(0), old_deleted_text.cursor(0));
-
self.undo_map.insert(undo);
let edit = &self.history.ops[&undo.edit_id];
- let start_fragment_id = self.resolve_fragment_id(edit.start_id, edit.start_offset)?;
- let end_fragment_id = self.resolve_fragment_id(edit.end_id, edit.end_offset)?;
+ let version = Some(edit.version.clone());
- let mut fragments_cursor = self.fragments.cursor::<FragmentIdRef, ()>();
+ let mut old_fragments = self.fragments.cursor::<VersionedOffset, VersionedOffset>();
+ old_fragments.seek(&VersionedOffset::Offset(0), Bias::Left, &version);
- if edit.start_id == edit.end_id && edit.start_offset == edit.end_offset {
- let splits = &self.insertion_splits[&undo.edit_id];
- let mut insertion_splits = splits.cursor::<(), ()>().map(|s| &s.fragment_id).peekable();
+ let mut new_fragments = SumTree::new();
+ let mut new_ropes =
+ RopeBuilder::new(self.visible_text.cursor(0), self.deleted_text.cursor(0));
- let first_split_id = insertion_splits.next().unwrap();
- new_fragments =
- fragments_cursor.slice(&FragmentIdRef::new(first_split_id), SeekBias::Left, &());
- new_ropes.push_tree(new_fragments.summary().text);
+ for range in &edit.ranges {
+ let mut end_offset = old_fragments.end(&version).offset();
- loop {
- let mut fragment = fragments_cursor.item().unwrap().clone();
- let was_visible = fragment.visible;
- fragment.visible = fragment.is_visible(&self.undo_map);
- fragment.max_undos.observe(undo.id);
-
- new_ropes.push_fragment(&fragment, was_visible);
- new_fragments.push(fragment.clone(), &());
-
- fragments_cursor.next();
- if let Some(split_id) = insertion_splits.next() {
- let slice =
- fragments_cursor.slice(&FragmentIdRef::new(split_id), SeekBias::Left, &());
- new_ropes.push_tree(slice.summary().text);
- new_fragments.push_tree(slice, &());
- } else {
- break;
- }
+ if end_offset < range.start {
+ let preceding_fragments = old_fragments.slice(
+ &VersionedOffset::Offset(range.start),
+ Bias::Left,
+ &version,
+ );
+ new_ropes.push_tree(preceding_fragments.summary().text);
+ new_fragments.push_tree(preceding_fragments, &None);
}
- } else {
- new_fragments = fragments_cursor.slice(
- &FragmentIdRef::new(&start_fragment_id),
- SeekBias::Left,
- &(),
- );
- new_ropes.push_tree(new_fragments.summary().text);
- while let Some(fragment) = fragments_cursor.item() {
- if fragment.id > end_fragment_id {
- break;
- } else {
+ while end_offset <= range.end {
+ if let Some(fragment) = old_fragments.item() {
let mut fragment = fragment.clone();
let fragment_was_visible = fragment.visible;
- if edit.version_in_range.observed(fragment.insertion.id)
- || fragment.insertion.id == undo.edit_id
+ if fragment.was_visible(&edit.version, &self.undo_map)
+ || fragment.timestamp.local() == edit.timestamp.local()
{
fragment.visible = fragment.is_visible(&self.undo_map);
fragment.max_undos.observe(undo.id);
}
-
new_ropes.push_fragment(&fragment, fragment_was_visible);
- new_fragments.push(fragment, &());
- fragments_cursor.next();
+ new_fragments.push(fragment, &None);
+
+ old_fragments.next(&version);
+ end_offset = old_fragments.end(&version).offset();
+ } else {
+ break;
}
}
}
- new_fragments.push_tree(fragments_cursor.suffix(&()), &());
- let (visible_text, deleted_text) = new_ropes.finish();
- drop(fragments_cursor);
+ let suffix = old_fragments.suffix(&version);
+ new_ropes.push_tree(suffix.summary().text);
+ new_fragments.push_tree(suffix, &None);
+ drop(old_fragments);
+ let (visible_text, deleted_text) = new_ropes.finish();
self.fragments = new_fragments;
self.visible_text = visible_text;
self.deleted_text = deleted_text;
-
Ok(())
}
@@ -1489,25 +1416,17 @@ impl Buffer {
false
} else {
match op {
- Operation::Edit { edit, .. } => {
- self.version.observed(edit.start_id)
- && self.version.observed(edit.end_id)
- && edit.version_in_range <= self.version
- }
+ Operation::Edit(edit) => self.version >= edit.version,
Operation::Undo { undo, .. } => self.version.observed(undo.edit_id),
Operation::UpdateSelections { selections, .. } => {
if let Some(selections) = selections {
selections.iter().all(|selection| {
- let contains_start = match selection.start {
- Anchor::Middle { insertion_id, .. } => {
- self.version.observed(insertion_id)
- }
+ let contains_start = match &selection.start {
+ Anchor::Middle { version, .. } => self.version >= *version,
_ => true,
};
- let contains_end = match selection.end {
- Anchor::Middle { insertion_id, .. } => {
- self.version.observed(insertion_id)
- }
+ let contains_end = match &selection.end {
+ Anchor::Middle { version, .. } => self.version >= *version,
_ => true,
};
contains_start && contains_end
@@ -1520,557 +1439,208 @@ impl Buffer {
}
}
- fn resolve_fragment_id(&self, edit_id: time::Local, offset: usize) -> Result<FragmentId> {
- let split_tree = self
- .insertion_splits
- .get(&edit_id)
- .ok_or_else(|| anyhow!("invalid operation"))?;
- let mut cursor = split_tree.cursor::<usize, ()>();
- cursor.seek(&offset, SeekBias::Left, &());
- Ok(cursor
- .item()
- .ok_or_else(|| anyhow!("invalid operation"))?
- .fragment_id
- .clone())
- }
-
- fn splice_fragments<I>(&mut self, mut old_ranges: I, new_text: Option<String>) -> Vec<Operation>
- where
- I: Iterator<Item = Range<usize>>,
- {
- let mut cur_range = old_ranges.next();
- if cur_range.is_none() {
- return Vec::new();
- }
-
- let mut ops = Vec::with_capacity(old_ranges.size_hint().0);
-
- let mut old_fragments = SumTree::new();
- let mut old_visible_text = Rope::new();
- let mut old_deleted_text = Rope::new();
- mem::swap(&mut old_visible_text, &mut self.visible_text);
- mem::swap(&mut old_deleted_text, &mut self.deleted_text);
- mem::swap(&mut old_fragments, &mut self.fragments);
-
- let mut fragments_cursor = old_fragments.cursor::<usize, usize>();
- let mut new_fragments =
- fragments_cursor.slice(&cur_range.as_ref().unwrap().start, SeekBias::Right, &());
+ fn apply_local_edit(
+ &mut self,
+ ranges: &[Range<usize>],
+ new_text: Option<String>,
+ timestamp: InsertionTimestamp,
+ ) -> EditOperation {
+ let mut edit = EditOperation {
+ timestamp,
+ version: self.version(),
+ ranges: Vec::with_capacity(ranges.len()),
+ new_text: None,
+ };
let mut new_ropes =
- RopeBuilder::new(old_visible_text.cursor(0), old_deleted_text.cursor(0));
+ RopeBuilder::new(self.visible_text.cursor(0), self.deleted_text.cursor(0));
+ let mut old_fragments = self.fragments.cursor::<usize, FragmentTextSummary>();
+ let mut new_fragments = old_fragments.slice(&ranges[0].start, Bias::Right, &None);
new_ropes.push_tree(new_fragments.summary().text);
- let mut start_id = None;
- let mut start_offset = None;
- let mut end_id = None;
- let mut end_offset = None;
- let mut version_in_range = time::Global::new();
-
- let mut local_timestamp = self.local_clock.tick();
- let mut lamport_timestamp = self.lamport_clock.tick();
-
- while cur_range.is_some() && fragments_cursor.item().is_some() {
- let mut fragment = fragments_cursor.item().unwrap().clone();
- let fragment_summary = fragments_cursor.item_summary().unwrap();
- let mut fragment_start = *fragments_cursor.start();
- let mut fragment_end = fragment_start + fragment.visible_len();
- let fragment_was_visible = fragment.visible;
-
- let old_split_tree = self
- .insertion_splits
- .remove(&fragment.insertion.id)
- .unwrap();
- let mut splits_cursor = old_split_tree.cursor::<usize, ()>();
- let mut new_split_tree =
- splits_cursor.slice(&fragment.range_in_insertion.start, SeekBias::Right, &());
-
- // Find all splices that start or end within the current fragment. Then, split the
- // fragment and reassemble it in both trees accounting for the deleted and the newly
- // inserted text.
- while cur_range.as_ref().map_or(false, |r| r.start < fragment_end) {
- let range = cur_range.clone().unwrap();
- if range.start > fragment_start {
- let mut prefix = fragment.clone();
- prefix.range_in_insertion.end =
- prefix.range_in_insertion.start + (range.start - fragment_start);
- prefix.id =
- FragmentId::between(&new_fragments.last().unwrap().id, &fragment.id);
- fragment.range_in_insertion.start = prefix.range_in_insertion.end;
-
- new_ropes.push_fragment(&prefix, prefix.visible);
- new_fragments.push(prefix.clone(), &());
- new_split_tree.push(
- InsertionSplit {
- extent: prefix.range_in_insertion.end - prefix.range_in_insertion.start,
- fragment_id: prefix.id,
- },
- &(),
- );
- fragment_start = range.start;
- }
-
- if range.end == fragment_start {
- end_id = Some(new_fragments.last().unwrap().insertion.id);
- end_offset = Some(new_fragments.last().unwrap().range_in_insertion.end);
- } else if range.end == fragment_end {
- end_id = Some(fragment.insertion.id);
- end_offset = Some(fragment.range_in_insertion.end);
- }
-
- if range.start == fragment_start {
- start_id = Some(new_fragments.last().unwrap().insertion.id);
- start_offset = Some(new_fragments.last().unwrap().range_in_insertion.end);
-
- if let Some(new_text) = new_text.clone() {
- let new_fragment = self.build_fragment_to_insert(
- &new_fragments.last().unwrap(),
- Some(&fragment),
- &new_text,
- local_timestamp,
- lamport_timestamp,
- );
-
- new_ropes.push_str(&new_text);
- new_fragments.push(new_fragment, &());
- }
- }
-
- if range.end < fragment_end {
- if range.end > fragment_start {
- let mut prefix = fragment.clone();
- prefix.range_in_insertion.end =
- prefix.range_in_insertion.start + (range.end - fragment_start);
- prefix.id =
- FragmentId::between(&new_fragments.last().unwrap().id, &fragment.id);
- version_in_range.observe_all(&fragment_summary.max_version);
- if prefix.visible {
- prefix.deletions.insert(local_timestamp);
- prefix.visible = false;
- }
- fragment.range_in_insertion.start = prefix.range_in_insertion.end;
- new_ropes.push_fragment(&prefix, fragment_was_visible);
- new_fragments.push(prefix.clone(), &());
- new_split_tree.push(
- InsertionSplit {
- extent: prefix.range_in_insertion.end
- - prefix.range_in_insertion.start,
- fragment_id: prefix.id,
- },
- &(),
- );
- fragment_start = range.end;
- end_id = Some(fragment.insertion.id);
- end_offset = Some(fragment.range_in_insertion.start);
- }
- } else {
- version_in_range.observe_all(&fragment_summary.max_version);
- if fragment.visible {
- fragment.deletions.insert(local_timestamp);
- fragment.visible = false;
+ let mut fragment_start = old_fragments.start().visible;
+ for range in ranges {
+ let fragment_end = old_fragments.end(&None).visible;
+
+ // If the current fragment ends before this range, then jump ahead to the first fragment
+ // that extends past the start of this range, reusing any intervening fragments.
+ if fragment_end < range.start {
+ // If the current fragment has been partially consumed, then consume the rest of it
+ // and advance to the next fragment before slicing.
+ if fragment_start > old_fragments.start().visible {
+ if fragment_end > fragment_start {
+ let mut suffix = old_fragments.item().unwrap().clone();
+ suffix.len = fragment_end - fragment_start;
+ new_ropes.push_fragment(&suffix, suffix.visible);
+ new_fragments.push(suffix, &None);
}
+ old_fragments.next(&None);
}
- // If the splice ends inside this fragment, we can advance to the next splice and
- // check if it also intersects the current fragment. Otherwise we break out of the
- // loop and find the first fragment that the splice does not contain fully.
- if range.end <= fragment_end {
- ops.push(Operation::Edit {
- edit: EditOperation {
- id: local_timestamp,
- start_id: start_id.unwrap(),
- start_offset: start_offset.unwrap(),
- end_id: end_id.unwrap(),
- end_offset: end_offset.unwrap(),
- version_in_range,
- new_text: new_text.clone(),
- },
- lamport_timestamp,
- });
-
- start_id = None;
- start_offset = None;
- end_id = None;
- end_offset = None;
- version_in_range = time::Global::new();
- cur_range = old_ranges.next();
- if cur_range.is_some() {
- local_timestamp = self.local_clock.tick();
- lamport_timestamp = self.lamport_clock.tick();
- }
- } else {
- break;
- }
+ let slice = old_fragments.slice(&range.start, Bias::Right, &None);
+ new_ropes.push_tree(slice.summary().text);
+ new_fragments.push_tree(slice, &None);
+ fragment_start = old_fragments.start().visible;
}
- new_split_tree.push(
- InsertionSplit {
- extent: fragment.range_in_insertion.end - fragment.range_in_insertion.start,
- fragment_id: fragment.id.clone(),
- },
- &(),
- );
- splits_cursor.next();
- new_split_tree.push_tree(
- splits_cursor.slice(&old_split_tree.extent::<usize>(), SeekBias::Right, &()),
- &(),
- );
- self.insertion_splits
- .insert(fragment.insertion.id, new_split_tree);
- new_ropes.push_fragment(&fragment, fragment_was_visible);
- new_fragments.push(fragment, &());
-
- // Scan forward until we find a fragment that is not fully contained by the current splice.
- fragments_cursor.next();
- if let Some(range) = cur_range.clone() {
- while let Some(fragment) = fragments_cursor.item() {
- let fragment_summary = fragments_cursor.item_summary().unwrap();
- let fragment_was_visible = fragment.visible;
- fragment_start = *fragments_cursor.start();
- fragment_end = fragment_start + fragment.visible_len();
- if range.start < fragment_start && range.end >= fragment_end {
- let mut new_fragment = fragment.clone();
- version_in_range.observe_all(&fragment_summary.max_version);
- if new_fragment.visible {
- new_fragment.deletions.insert(local_timestamp);
- new_fragment.visible = false;
- }
+ let full_range_start = range.start + old_fragments.start().deleted;
- new_ropes.push_fragment(&new_fragment, fragment_was_visible);
- new_fragments.push(new_fragment, &());
- fragments_cursor.next();
-
- if range.end == fragment_end {
- end_id = Some(fragment.insertion.id);
- end_offset = Some(fragment.range_in_insertion.end);
- ops.push(Operation::Edit {
- edit: EditOperation {
- id: local_timestamp,
- start_id: start_id.unwrap(),
- start_offset: start_offset.unwrap(),
- end_id: end_id.unwrap(),
- end_offset: end_offset.unwrap(),
- version_in_range,
- new_text: new_text.clone(),
- },
- lamport_timestamp,
- });
+ // Preserve any portion of the current fragment that precedes this range.
+ if fragment_start < range.start {
+ let mut prefix = old_fragments.item().unwrap().clone();
+ prefix.len = range.start - fragment_start;
+ new_ropes.push_fragment(&prefix, prefix.visible);
+ new_fragments.push(prefix, &None);
+ fragment_start = range.start;
+ }
- start_id = None;
- start_offset = None;
- end_id = None;
- end_offset = None;
- version_in_range = time::Global::new();
+ // Insert the new text before any existing fragments within the range.
+ if let Some(new_text) = new_text.as_deref() {
+ new_ropes.push_str(new_text);
+ new_fragments.push(
+ Fragment {
+ timestamp,
+ len: new_text.len(),
+ deletions: Default::default(),
+ max_undos: Default::default(),
+ visible: true,
+ },
+ &None,
+ );
+ }
- cur_range = old_ranges.next();
- if cur_range.is_some() {
- local_timestamp = self.local_clock.tick();
- lamport_timestamp = self.lamport_clock.tick();
- }
- break;
- }
- } else {
- break;
- }
+ // Advance through every fragment that intersects this range, marking the intersecting
+ // portions as deleted.
+ while fragment_start < range.end {
+ let fragment = old_fragments.item().unwrap();
+ let fragment_end = old_fragments.end(&None).visible;
+ let mut intersection = fragment.clone();
+ let intersection_end = cmp::min(range.end, fragment_end);
+ if fragment.visible {
+ intersection.len = intersection_end - fragment_start;
+ intersection.deletions.insert(timestamp.local());
+ intersection.visible = false;
}
-
- // If the splice we are currently evaluating starts after the end of the fragment
- // that the cursor is parked at, we should seek to the next splice's start range
- // and push all the fragments in between into the new tree.
- if cur_range.as_ref().map_or(false, |r| r.start > fragment_end) {
- let slice = fragments_cursor.slice(
- &cur_range.as_ref().unwrap().start,
- SeekBias::Right,
- &(),
- );
- new_ropes.push_tree(slice.summary().text);
- new_fragments.push_tree(slice, &());
+ if intersection.len > 0 {
+ new_ropes.push_fragment(&intersection, fragment.visible);
+ new_fragments.push(intersection, &None);
+ fragment_start = intersection_end;
+ }
+ if fragment_end <= range.end {
+ old_fragments.next(&None);
}
}
- }
- // Handle range that is at the end of the buffer if it exists. There should never be
- // multiple because ranges must be disjoint.
- if cur_range.is_some() {
- debug_assert_eq!(old_ranges.next(), None);
- let last_fragment = new_fragments.last().unwrap();
- ops.push(Operation::Edit {
- edit: EditOperation {
- id: local_timestamp,
- start_id: last_fragment.insertion.id,
- start_offset: last_fragment.range_in_insertion.end,
- end_id: last_fragment.insertion.id,
- end_offset: last_fragment.range_in_insertion.end,
- version_in_range: time::Global::new(),
- // TODO: avoid cloning the String.
- new_text: new_text.clone(),
- },
- lamport_timestamp,
- });
-
- if let Some(new_text) = new_text {
- let new_fragment = self.build_fragment_to_insert(
- &last_fragment,
- None,
- &new_text,
- local_timestamp,
- lamport_timestamp,
- );
+ let full_range_end = range.end + old_fragments.start().deleted;
+ edit.ranges.push(full_range_start..full_range_end);
+ }
- new_ropes.push_str(&new_text);
- new_fragments.push(new_fragment, &());
+ // If the current fragment has been partially consumed, then consume the rest of it
+ // and advance to the next fragment before slicing.
+ if fragment_start > old_fragments.start().visible {
+ let fragment_end = old_fragments.end(&None).visible;
+ if fragment_end > fragment_start {
+ let mut suffix = old_fragments.item().unwrap().clone();
+ suffix.len = fragment_end - fragment_start;
+ new_ropes.push_fragment(&suffix, suffix.visible);
+ new_fragments.push(suffix, &None);
}
+ old_fragments.next(&None);
}
- new_fragments.push_tree(fragments_cursor.suffix(&()), &());
+ let suffix = old_fragments.suffix(&None);
+ new_ropes.push_tree(suffix.summary().text);
+ new_fragments.push_tree(suffix, &None);
let (visible_text, deleted_text) = new_ropes.finish();
+ drop(old_fragments);
self.fragments = new_fragments;
self.visible_text = visible_text;
self.deleted_text = deleted_text;
- ops
- }
-
- fn split_fragment(
- &mut self,
- prev_fragment: &Fragment,
- fragment: &Fragment,
- range: Range<usize>,
- ) -> (Option<Fragment>, Option<Fragment>, Option<Fragment>) {
- debug_assert!(range.start >= fragment.range_in_insertion.start);
- debug_assert!(range.start <= fragment.range_in_insertion.end);
- debug_assert!(range.end <= fragment.range_in_insertion.end);
- debug_assert!(range.end >= fragment.range_in_insertion.start);
-
- if range.end == fragment.range_in_insertion.start {
- (None, None, Some(fragment.clone()))
- } else if range.start == fragment.range_in_insertion.end {
- (Some(fragment.clone()), None, None)
- } else if range.start == fragment.range_in_insertion.start
- && range.end == fragment.range_in_insertion.end
- {
- (None, Some(fragment.clone()), None)
- } else {
- let mut prefix = fragment.clone();
-
- let after_range = if range.end < fragment.range_in_insertion.end {
- let mut suffix = prefix.clone();
- suffix.range_in_insertion.start = range.end;
- prefix.range_in_insertion.end = range.end;
- prefix.id = FragmentId::between(&prev_fragment.id, &suffix.id);
- Some(suffix)
- } else {
- None
- };
-
- let within_range = if range.start != range.end {
- let mut suffix = prefix.clone();
- suffix.range_in_insertion.start = range.start;
- prefix.range_in_insertion.end = range.start;
- prefix.id = FragmentId::between(&prev_fragment.id, &suffix.id);
- Some(suffix)
- } else {
- None
- };
-
- let before_range = if range.start > fragment.range_in_insertion.start {
- Some(prefix)
- } else {
- None
- };
-
- let old_split_tree = self
- .insertion_splits
- .remove(&fragment.insertion.id)
- .unwrap();
- let mut cursor = old_split_tree.cursor::<usize, ()>();
- let mut new_split_tree =
- cursor.slice(&fragment.range_in_insertion.start, SeekBias::Right, &());
-
- if let Some(ref fragment) = before_range {
- new_split_tree.push(
- InsertionSplit {
- extent: range.start - fragment.range_in_insertion.start,
- fragment_id: fragment.id.clone(),
- },
- &(),
- );
- }
-
- if let Some(ref fragment) = within_range {
- new_split_tree.push(
- InsertionSplit {
- extent: range.end - range.start,
- fragment_id: fragment.id.clone(),
- },
- &(),
- );
- }
-
- if let Some(ref fragment) = after_range {
- new_split_tree.push(
- InsertionSplit {
- extent: fragment.range_in_insertion.end - range.end,
- fragment_id: fragment.id.clone(),
- },
- &(),
- );
- }
-
- cursor.next();
- new_split_tree.push_tree(
- cursor.slice(&old_split_tree.extent::<usize>(), SeekBias::Right, &()),
- &(),
- );
-
- self.insertion_splits
- .insert(fragment.insertion.id, new_split_tree);
-
- (before_range, within_range, after_range)
- }
- }
-
- fn build_fragment_to_insert(
- &mut self,
- prev_fragment: &Fragment,
- next_fragment: Option<&Fragment>,
- text: &str,
- insertion_id: time::Local,
- lamport_timestamp: time::Lamport,
- ) -> Fragment {
- let new_fragment_id = FragmentId::between(
- &prev_fragment.id,
- next_fragment
- .map(|f| &f.id)
- .unwrap_or(&FragmentId::max_value()),
- );
-
- let range_in_insertion = 0..text.len();
- let mut split_tree = SumTree::new();
- split_tree.push(
- InsertionSplit {
- extent: range_in_insertion.len(),
- fragment_id: new_fragment_id.clone(),
- },
- &(),
- );
- self.insertion_splits.insert(insertion_id, split_tree);
-
- Fragment::new(
- new_fragment_id,
- Arc::new(Insertion {
- id: insertion_id,
- parent_id: prev_fragment.insertion.id,
- offset_in_parent: prev_fragment.range_in_insertion.end,
- lamport_timestamp,
- }),
- range_in_insertion,
- )
+ edit.new_text = new_text;
+ edit
}
pub fn anchor_before<T: ToOffset>(&self, position: T) -> Anchor {
- self.anchor_at(position, AnchorBias::Left)
+ self.anchor_at(position, Bias::Left)
}
pub fn anchor_after<T: ToOffset>(&self, position: T) -> Anchor {
- self.anchor_at(position, AnchorBias::Right)
+ self.anchor_at(position, Bias::Right)
}
- pub fn anchor_at<T: ToOffset>(&self, position: T, bias: AnchorBias) -> Anchor {
+ pub fn anchor_at<T: ToOffset>(&self, position: T, bias: Bias) -> Anchor {
let offset = position.to_offset(self);
let max_offset = self.len();
assert!(offset <= max_offset, "offset is out of range");
- let seek_bias;
- match bias {
- AnchorBias::Left => {
- if offset == 0 {
- return Anchor::Start;
- } else {
- seek_bias = SeekBias::Left;
- }
- }
- AnchorBias::Right => {
- if offset == max_offset {
- return Anchor::End;
- } else {
- seek_bias = SeekBias::Right;
- }
+ if offset == 0 && bias == Bias::Left {
+ Anchor::Start
+ } else if offset == max_offset && bias == Bias::Right {
+ Anchor::End
+ } else {
+ let mut cursor = self.fragments.cursor::<usize, FragmentTextSummary>();
+ cursor.seek(&offset, bias, &None);
+ Anchor::Middle {
+ offset: offset + cursor.start().deleted,
+ bias,
+ version: self.version(),
}
- };
-
- let mut cursor = self.fragments.cursor::<usize, usize>();
- cursor.seek(&offset, seek_bias, &());
- let fragment = cursor.item().unwrap();
- let offset_in_fragment = offset - cursor.start();
- let offset_in_insertion = fragment.range_in_insertion.start + offset_in_fragment;
- let anchor = Anchor::Middle {
- insertion_id: fragment.insertion.id,
- offset: offset_in_insertion,
- bias,
- };
- anchor
+ }
}
- fn fragment_id_for_anchor(&self, anchor: &Anchor) -> Result<&FragmentId> {
+ fn summary_for_anchor(&self, anchor: &Anchor) -> TextSummary {
match anchor {
- Anchor::Start => Ok(FragmentId::max_value()),
- Anchor::End => Ok(FragmentId::min_value()),
+ Anchor::Start => TextSummary::default(),
+ Anchor::End => self.text_summary(),
Anchor::Middle {
- insertion_id,
offset,
bias,
- ..
+ version,
} => {
- let seek_bias = match bias {
- AnchorBias::Left => SeekBias::Left,
- AnchorBias::Right => SeekBias::Right,
+ let mut cursor = self
+ .fragments
+ .cursor::<VersionedOffset, (VersionedOffset, usize)>();
+ cursor.seek(
+ &VersionedOffset::Offset(*offset),
+ *bias,
+ &Some(version.clone()),
+ );
+ let fragment = cursor.item().unwrap();
+ let overshoot = if fragment.visible {
+ offset - cursor.start().0.offset()
+ } else {
+ 0
};
- let splits = self
- .insertion_splits
- .get(&insertion_id)
- .ok_or_else(|| anyhow!("split does not exist for insertion id"))?;
- let mut splits_cursor = splits.cursor::<usize, ()>();
- splits_cursor.seek(offset, seek_bias, &());
- splits_cursor
- .item()
- .ok_or_else(|| anyhow!("split offset is out of range"))
- .map(|split| &split.fragment_id)
+ self.text_summary_for_range(0..cursor.start().1 + overshoot)
}
}
}
- fn summary_for_anchor(&self, anchor: &Anchor) -> TextSummary {
+ fn full_offset_for_anchor(&self, anchor: &Anchor) -> usize {
match anchor {
- Anchor::Start => TextSummary::default(),
- Anchor::End => self.text_summary(),
+ Anchor::Start => 0,
+ Anchor::End => {
+ let summary = self.fragments.summary();
+ summary.text.visible + summary.text.deleted
+ }
Anchor::Middle {
- insertion_id,
offset,
bias,
+ version,
} => {
- let seek_bias = match bias {
- AnchorBias::Left => SeekBias::Left,
- AnchorBias::Right => SeekBias::Right,
- };
-
- let splits = self
- .insertion_splits
- .get(&insertion_id)
- .expect("split does not exist for insertion id");
- let mut splits_cursor = splits.cursor::<usize, ()>();
- splits_cursor.seek(offset, seek_bias, &());
- let split = splits_cursor.item().expect("split offset is out of range");
-
- let mut fragments_cursor = self.fragments.cursor::<FragmentIdRef, usize>();
- fragments_cursor.seek(&FragmentIdRef::new(&split.fragment_id), SeekBias::Left, &());
- let fragment = fragments_cursor.item().expect("fragment id does not exist");
-
- let mut ix = *fragments_cursor.start();
- if fragment.visible {
- ix += offset - fragment.range_in_insertion.start;
- }
- self.text_summary_for_range(0..ix)
+ let mut cursor = self
+ .fragments
+ .cursor::<VersionedOffset, (VersionedOffset, FragmentTextSummary)>();
+ cursor.seek(
+ &VersionedOffset::Offset(*offset),
+ *bias,
+ &Some(version.clone()),
+ );
+ let overshoot = offset - cursor.start().0.offset();
+ let summary = cursor.start().1;
+ summary.visible + summary.deleted + overshoot
}
}
}
@@ -1,47 +1,19 @@
use super::Buffer;
-use crate::time;
+use crate::{time, util::Bias};
use anyhow::Result;
-use std::cmp::Ordering;
-use std::ops::Range;
+use std::{cmp::Ordering, ops::Range};
#[derive(Clone, Eq, PartialEq, Debug, Hash)]
pub enum Anchor {
Start,
End,
Middle {
- insertion_id: time::Local,
offset: usize,
- bias: AnchorBias,
+ bias: Bias,
+ version: time::Global,
},
}
-#[derive(Clone, Eq, PartialEq, Debug, Hash)]
-pub enum AnchorBias {
- Left,
- Right,
-}
-
-impl PartialOrd for AnchorBias {
- fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
- Some(self.cmp(other))
- }
-}
-
-impl Ord for AnchorBias {
- fn cmp(&self, other: &Self) -> Ordering {
- use AnchorBias::*;
-
- if self == other {
- return Ordering::Equal;
- }
-
- match (self, other) {
- (Left, _) => Ordering::Less,
- (Right, _) => Ordering::Greater,
- }
- }
-}
-
impl Anchor {
pub fn cmp(&self, other: &Anchor, buffer: &Buffer) -> Result<Ordering> {
if self == other {
@@ -55,18 +27,24 @@ impl Anchor {
Anchor::Middle {
offset: self_offset,
bias: self_bias,
- ..
+ version: self_version,
},
Anchor::Middle {
offset: other_offset,
bias: other_bias,
- ..
+ version: other_version,
},
- ) => buffer
- .fragment_id_for_anchor(self)?
- .cmp(buffer.fragment_id_for_anchor(other)?)
- .then_with(|| self_offset.cmp(other_offset))
- .then_with(|| self_bias.cmp(other_bias)),
+ ) => {
+ let offset_comparison = if self_version == other_version {
+ self_offset.cmp(other_offset)
+ } else {
+ buffer
+ .full_offset_for_anchor(self)
+ .cmp(&buffer.full_offset_for_anchor(other))
+ };
+
+ offset_comparison.then_with(|| self_bias.cmp(&other_bias))
+ }
})
}
@@ -74,8 +52,7 @@ impl Anchor {
match self {
Anchor::Start
| Anchor::Middle {
- bias: AnchorBias::Left,
- ..
+ bias: Bias::Left, ..
} => self.clone(),
_ => buffer.anchor_before(self),
}
@@ -85,8 +62,7 @@ impl Anchor {
match self {
Anchor::End
| Anchor::Middle {
- bias: AnchorBias::Right,
- ..
+ bias: Bias::Right, ..
} => self.clone(),
_ => buffer.anchor_after(self),
}
@@ -1,7 +1,7 @@
use super::Point;
use crate::{
- editor::Bias,
- sum_tree::{self, SeekBias, SumTree},
+ sum_tree::{self, SumTree},
+ util::Bias,
};
use arrayvec::ArrayString;
use smallvec::SmallVec;
@@ -25,13 +25,13 @@ impl Rope {
pub fn append(&mut self, rope: Rope) {
let mut chunks = rope.chunks.cursor::<(), ()>();
- chunks.next();
+ chunks.next(&());
if let Some(chunk) = chunks.item() {
if self.chunks.last().map_or(false, |c| c.0.len() < CHUNK_BASE)
|| chunk.0.len() < CHUNK_BASE
{
self.push(&chunk.0);
- chunks.next();
+ chunks.next(&());
}
}
@@ -99,11 +99,11 @@ impl Rope {
}
pub fn len(&self) -> usize {
- self.chunks.extent()
+ self.chunks.extent(&())
}
pub fn max_point(&self) -> Point {
- self.chunks.extent()
+ self.chunks.extent(&())
}
pub fn cursor(&self, offset: usize) -> Cursor {
@@ -129,7 +129,7 @@ impl Rope {
pub fn to_point(&self, offset: usize) -> Point {
assert!(offset <= self.summary().bytes);
let mut cursor = self.chunks.cursor::<usize, TextSummary>();
- cursor.seek(&offset, SeekBias::Left, &());
+ cursor.seek(&offset, Bias::Left, &());
let overshoot = offset - cursor.start().bytes;
cursor.start().lines
+ cursor
@@ -140,14 +140,14 @@ impl Rope {
pub fn to_offset(&self, point: Point) -> usize {
assert!(point <= self.summary().lines);
let mut cursor = self.chunks.cursor::<Point, TextSummary>();
- cursor.seek(&point, SeekBias::Left, &());
+ cursor.seek(&point, Bias::Left, &());
let overshoot = point - cursor.start().lines;
cursor.start().bytes + cursor.item().map_or(0, |chunk| chunk.to_offset(overshoot))
}
pub fn clip_offset(&self, mut offset: usize, bias: Bias) -> usize {
let mut cursor = self.chunks.cursor::<usize, usize>();
- cursor.seek(&offset, SeekBias::Left, &());
+ cursor.seek(&offset, Bias::Left, &());
if let Some(chunk) = cursor.item() {
let mut ix = offset - cursor.start();
while !chunk.0.is_char_boundary(ix) {
@@ -170,7 +170,7 @@ impl Rope {
pub fn clip_point(&self, point: Point, bias: Bias) -> Point {
let mut cursor = self.chunks.cursor::<Point, Point>();
- cursor.seek(&point, SeekBias::Right, &());
+ cursor.seek(&point, Bias::Right, &());
if let Some(chunk) = cursor.item() {
let overshoot = point - cursor.start();
*cursor.start() + chunk.clip_point(overshoot, bias)
@@ -197,7 +197,7 @@ pub struct Cursor<'a> {
impl<'a> Cursor<'a> {
pub fn new(rope: &'a Rope, offset: usize) -> Self {
let mut chunks = rope.chunks.cursor();
- chunks.seek(&offset, SeekBias::Right, &());
+ chunks.seek(&offset, Bias::Right, &());
Self {
rope,
chunks,
@@ -208,24 +208,29 @@ impl<'a> Cursor<'a> {
pub fn seek_forward(&mut self, end_offset: usize) {
debug_assert!(end_offset >= self.offset);
- self.chunks.seek_forward(&end_offset, SeekBias::Right, &());
+ self.chunks.seek_forward(&end_offset, Bias::Right, &());
self.offset = end_offset;
}
pub fn slice(&mut self, end_offset: usize) -> Rope {
- debug_assert!(end_offset >= self.offset);
+ debug_assert!(
+ end_offset >= self.offset,
+ "cannot slice backwards from {} to {}",
+ self.offset,
+ end_offset
+ );
let mut slice = Rope::new();
if let Some(start_chunk) = self.chunks.item() {
let start_ix = self.offset - self.chunks.start();
- let end_ix = cmp::min(end_offset, self.chunks.end()) - self.chunks.start();
+ let end_ix = cmp::min(end_offset, self.chunks.end(&())) - self.chunks.start();
slice.push(&start_chunk.0[start_ix..end_ix]);
}
- if end_offset > self.chunks.end() {
- self.chunks.next();
+ if end_offset > self.chunks.end(&()) {
+ self.chunks.next(&());
slice.append(Rope {
- chunks: self.chunks.slice(&end_offset, SeekBias::Right, &()),
+ chunks: self.chunks.slice(&end_offset, Bias::Right, &()),
});
if let Some(end_chunk) = self.chunks.item() {
let end_ix = end_offset - self.chunks.start();
@@ -243,13 +248,13 @@ impl<'a> Cursor<'a> {
let mut summary = TextSummary::default();
if let Some(start_chunk) = self.chunks.item() {
let start_ix = self.offset - self.chunks.start();
- let end_ix = cmp::min(end_offset, self.chunks.end()) - self.chunks.start();
+ let end_ix = cmp::min(end_offset, self.chunks.end(&())) - self.chunks.start();
summary = TextSummary::from(&start_chunk.0[start_ix..end_ix]);
}
- if end_offset > self.chunks.end() {
- self.chunks.next();
- summary += &self.chunks.summary(&end_offset, SeekBias::Right, &());
+ if end_offset > self.chunks.end(&()) {
+ self.chunks.next(&());
+ summary += &self.chunks.summary(&end_offset, Bias::Right, &());
if let Some(end_chunk) = self.chunks.item() {
let end_ix = end_offset - self.chunks.start();
summary += TextSummary::from(&end_chunk.0[..end_ix]);
@@ -260,7 +265,7 @@ impl<'a> Cursor<'a> {
}
pub fn suffix(mut self) -> Rope {
- self.slice(self.rope.chunks.extent())
+ self.slice(self.rope.chunks.extent(&()))
}
pub fn offset(&self) -> usize {
@@ -276,7 +281,7 @@ pub struct Chunks<'a> {
impl<'a> Chunks<'a> {
pub fn new(rope: &'a Rope, range: Range<usize>) -> Self {
let mut chunks = rope.chunks.cursor();
- chunks.seek(&range.start, SeekBias::Right, &());
+ chunks.seek(&range.start, Bias::Right, &());
Self { chunks, range }
}
@@ -285,10 +290,10 @@ impl<'a> Chunks<'a> {
}
pub fn seek(&mut self, offset: usize) {
- if offset >= self.chunks.end() {
- self.chunks.seek_forward(&offset, SeekBias::Right, &());
+ if offset >= self.chunks.end(&()) {
+ self.chunks.seek_forward(&offset, Bias::Right, &());
} else {
- self.chunks.seek(&offset, SeekBias::Right, &());
+ self.chunks.seek(&offset, Bias::Right, &());
}
self.range.start = offset;
}
@@ -312,7 +317,7 @@ impl<'a> Iterator for Chunks<'a> {
fn next(&mut self) -> Option<Self::Item> {
let result = self.peek();
if result.is_some() {
- self.chunks.next();
+ self.chunks.next(&());
}
result
}
@@ -478,19 +483,19 @@ impl std::ops::AddAssign<Self> for TextSummary {
}
impl<'a> sum_tree::Dimension<'a, TextSummary> for TextSummary {
- fn add_summary(&mut self, summary: &'a TextSummary) {
+ fn add_summary(&mut self, summary: &'a TextSummary, _: &()) {
*self += summary;
}
}
impl<'a> sum_tree::Dimension<'a, TextSummary> for usize {
- fn add_summary(&mut self, summary: &'a TextSummary) {
+ fn add_summary(&mut self, summary: &'a TextSummary, _: &()) {
*self += summary.bytes;
}
}
impl<'a> sum_tree::Dimension<'a, TextSummary> for Point {
- fn add_summary(&mut self, summary: &'a TextSummary) {
+ fn add_summary(&mut self, summary: &'a TextSummary, _: &()) {
*self += &summary.lines;
}
}
@@ -1,17 +1,19 @@
use super::{
buffer::{AnchorRangeExt, TextSummary},
- Anchor, Bias, Buffer, DisplayPoint, Edit, Point, ToOffset,
+ Anchor, Buffer, DisplayPoint, Edit, Point, ToOffset,
};
use crate::{
editor::buffer,
settings::StyleId,
- sum_tree::{self, Cursor, FilterCursor, SeekBias, SumTree},
+ sum_tree::{self, Cursor, FilterCursor, SumTree},
time,
+ util::Bias,
};
use gpui::{AppContext, ModelHandle};
use parking_lot::{Mutex, MutexGuard};
use std::{
cmp::{self, Ordering},
+ iter,
ops::Range,
};
@@ -80,7 +82,13 @@ impl FoldMap {
where
T: ToOffset,
{
- self.intersecting_folds(range, cx).map(|f| &f.0)
+ let buffer = self.buffer.read(cx);
+ let mut folds = self.intersecting_folds(range, cx);
+ iter::from_fn(move || {
+ let item = folds.item().map(|f| &f.0);
+ folds.next(buffer);
+ item
+ })
}
pub fn fold<T: ToOffset>(
@@ -118,7 +126,7 @@ impl FoldMap {
let mut new_tree = SumTree::new();
let mut cursor = self.folds.cursor::<_, ()>();
for fold in folds {
- new_tree.push_tree(cursor.slice(&fold, SeekBias::Right, buffer), buffer);
+ new_tree.push_tree(cursor.slice(&fold, Bias::Right, buffer), buffer);
new_tree.push(fold, buffer);
}
new_tree.push_tree(cursor.suffix(buffer), buffer);
@@ -149,7 +157,7 @@ impl FoldMap {
..Default::default()
});
fold_ixs_to_delete.push(*folds_cursor.start());
- folds_cursor.next();
+ folds_cursor.next(buffer);
}
}
@@ -166,8 +174,8 @@ impl FoldMap {
let mut cursor = self.folds.cursor::<_, ()>();
let mut folds = SumTree::new();
for fold_ix in fold_ixs_to_delete {
- folds.push_tree(cursor.slice(&fold_ix, SeekBias::Right, buffer), buffer);
- cursor.next();
+ folds.push_tree(cursor.slice(&fold_ix, Bias::Right, buffer), buffer);
+ cursor.next(buffer);
}
folds.push_tree(cursor.suffix(buffer), buffer);
folds
@@ -186,10 +194,13 @@ impl FoldMap {
let buffer = self.buffer.read(cx);
let start = buffer.anchor_before(range.start.to_offset(buffer));
let end = buffer.anchor_after(range.end.to_offset(buffer));
- self.folds.filter::<_, usize>(move |summary| {
- start.cmp(&summary.max_end, buffer).unwrap() == Ordering::Less
- && end.cmp(&summary.min_start, buffer).unwrap() == Ordering::Greater
- })
+ self.folds.filter::<_, usize>(
+ move |summary| {
+ start.cmp(&summary.max_end, buffer).unwrap() == Ordering::Less
+ && end.cmp(&summary.min_start, buffer).unwrap() == Ordering::Greater
+ },
+ buffer,
+ )
}
pub fn intersects_fold<T>(&self, offset: T, cx: &AppContext) -> bool
@@ -200,20 +211,20 @@ impl FoldMap {
let offset = offset.to_offset(buffer);
let transforms = self.sync(cx);
let mut cursor = transforms.cursor::<usize, usize>();
- cursor.seek(&offset, SeekBias::Right, &());
+ cursor.seek(&offset, Bias::Right, &());
cursor.item().map_or(false, |t| t.display_text.is_some())
}
pub fn is_line_folded(&self, display_row: u32, cx: &AppContext) -> bool {
let transforms = self.sync(cx);
let mut cursor = transforms.cursor::<DisplayPoint, DisplayPoint>();
- cursor.seek(&DisplayPoint::new(display_row, 0), SeekBias::Right, &());
+ cursor.seek(&DisplayPoint::new(display_row, 0), Bias::Right, &());
while let Some(transform) = cursor.item() {
if transform.display_text.is_some() {
return true;
}
- if cursor.end().row() == display_row {
- cursor.next()
+ if cursor.end(&()).row() == display_row {
+ cursor.next(&())
} else {
break;
}
@@ -232,7 +243,7 @@ impl FoldMap {
pub fn to_buffer_point(&self, display_point: DisplayPoint, cx: &AppContext) -> Point {
let transforms = self.sync(cx);
let mut cursor = transforms.cursor::<DisplayPoint, TransformSummary>();
- cursor.seek(&display_point, SeekBias::Right, &());
+ cursor.seek(&display_point, Bias::Right, &());
let overshoot = display_point.0 - cursor.start().display.lines;
cursor.start().buffer.lines + overshoot
}
@@ -240,11 +251,11 @@ impl FoldMap {
pub fn to_display_point(&self, point: Point, cx: &AppContext) -> DisplayPoint {
let transforms = self.sync(cx);
let mut cursor = transforms.cursor::<Point, TransformSummary>();
- cursor.seek(&point, SeekBias::Right, &());
+ cursor.seek(&point, Bias::Right, &());
let overshoot = point - cursor.start().buffer.lines;
DisplayPoint(cmp::min(
cursor.start().display.lines + overshoot,
- cursor.end().display.lines,
+ cursor.end(&()).display.lines,
))
}
@@ -265,18 +276,15 @@ impl FoldMap {
let mut new_transforms = SumTree::new();
let mut transforms = self.transforms.lock();
let mut cursor = transforms.cursor::<usize, usize>();
- cursor.seek(&0, SeekBias::Right, &());
+ cursor.seek(&0, Bias::Right, &());
while let Some(mut edit) = edits.next() {
- new_transforms.push_tree(
- cursor.slice(&edit.old_range.start, SeekBias::Left, &()),
- &(),
- );
+ new_transforms.push_tree(cursor.slice(&edit.old_range.start, Bias::Left, &()), &());
edit.new_range.start -= edit.old_range.start - cursor.start();
edit.old_range.start = *cursor.start();
- cursor.seek(&edit.old_range.end, SeekBias::Right, &());
- cursor.next();
+ cursor.seek(&edit.old_range.end, Bias::Right, &());
+ cursor.next(&());
let mut delta = edit.delta();
loop {
@@ -292,8 +300,8 @@ impl FoldMap {
if next_edit.old_range.end >= edit.old_range.end {
edit.old_range.end = next_edit.old_range.end;
- cursor.seek(&edit.old_range.end, SeekBias::Right, &());
- cursor.next();
+ cursor.seek(&edit.old_range.end, Bias::Right, &());
+ cursor.next(&());
}
} else {
break;
@@ -305,10 +313,15 @@ impl FoldMap {
let anchor = buffer.anchor_before(edit.new_range.start);
let mut folds_cursor = self.folds.cursor::<_, ()>();
- folds_cursor.seek(&Fold(anchor..Anchor::End), SeekBias::Left, buffer);
- let mut folds = folds_cursor
- .map(|f| f.0.start.to_offset(buffer)..f.0.end.to_offset(buffer))
- .peekable();
+ folds_cursor.seek(&Fold(anchor..Anchor::End), Bias::Left, buffer);
+ let mut folds = iter::from_fn(move || {
+ let item = folds_cursor
+ .item()
+ .map(|f| f.0.start.to_offset(buffer)..f.0.end.to_offset(buffer));
+ folds_cursor.next(buffer);
+ item
+ })
+ .peekable();
while folds
.peek()
@@ -417,7 +430,7 @@ impl FoldMapSnapshot {
let display_point = Point::new(start_row, 0);
let mut cursor = self.transforms.cursor();
- cursor.seek(&DisplayPoint(display_point), SeekBias::Left, &());
+ cursor.seek(&DisplayPoint(display_point), Bias::Left, &());
BufferRows {
display_point,
@@ -431,7 +444,7 @@ impl FoldMapSnapshot {
pub fn chunks_at(&self, offset: DisplayOffset) -> Chunks {
let mut transform_cursor = self.transforms.cursor::<DisplayOffset, TransformSummary>();
- transform_cursor.seek(&offset, SeekBias::Right, &());
+ transform_cursor.seek(&offset, Bias::Right, &());
let overshoot = offset.0 - transform_cursor.start().display.bytes;
let buffer_offset = transform_cursor.start().buffer.bytes + overshoot;
Chunks {
@@ -444,11 +457,11 @@ impl FoldMapSnapshot {
pub fn highlighted_chunks(&mut self, range: Range<DisplayOffset>) -> HighlightedChunks {
let mut transform_cursor = self.transforms.cursor::<DisplayOffset, TransformSummary>();
- transform_cursor.seek(&range.end, SeekBias::Right, &());
+ transform_cursor.seek(&range.end, Bias::Right, &());
let overshoot = range.end.0 - transform_cursor.start().display.bytes;
let buffer_end = transform_cursor.start().buffer.bytes + overshoot;
- transform_cursor.seek(&range.start, SeekBias::Right, &());
+ transform_cursor.seek(&range.start, Bias::Right, &());
let overshoot = range.start.0 - transform_cursor.start().display.bytes;
let buffer_start = transform_cursor.start().buffer.bytes + overshoot;
@@ -469,7 +482,7 @@ impl FoldMapSnapshot {
pub fn to_display_offset(&self, point: DisplayPoint) -> DisplayOffset {
let mut cursor = self.transforms.cursor::<DisplayPoint, TransformSummary>();
- cursor.seek(&point, SeekBias::Right, &());
+ cursor.seek(&point, Bias::Right, &());
let overshoot = point.0 - cursor.start().display.lines;
let mut offset = cursor.start().display.bytes;
if !overshoot.is_zero() {
@@ -485,7 +498,7 @@ impl FoldMapSnapshot {
pub fn to_buffer_offset(&self, point: DisplayPoint) -> usize {
let mut cursor = self.transforms.cursor::<DisplayPoint, TransformSummary>();
- cursor.seek(&point, SeekBias::Right, &());
+ cursor.seek(&point, Bias::Right, &());
let overshoot = point.0 - cursor.start().display.lines;
self.buffer
.to_offset(cursor.start().buffer.lines + overshoot)
@@ -494,14 +507,14 @@ impl FoldMapSnapshot {
#[cfg(test)]
pub fn clip_offset(&self, offset: DisplayOffset, bias: Bias) -> DisplayOffset {
let mut cursor = self.transforms.cursor::<DisplayOffset, TransformSummary>();
- cursor.seek(&offset, SeekBias::Right, &());
+ cursor.seek(&offset, Bias::Right, &());
if let Some(transform) = cursor.item() {
let transform_start = cursor.start().display.bytes;
if transform.display_text.is_some() {
if offset.0 == transform_start || matches!(bias, Bias::Left) {
DisplayOffset(transform_start)
} else {
- DisplayOffset(cursor.end().display.bytes)
+ DisplayOffset(cursor.end(&()).display.bytes)
}
} else {
let overshoot = offset.0 - transform_start;
@@ -519,14 +532,14 @@ impl FoldMapSnapshot {
pub fn clip_point(&self, point: DisplayPoint, bias: Bias) -> DisplayPoint {
let mut cursor = self.transforms.cursor::<DisplayPoint, TransformSummary>();
- cursor.seek(&point, SeekBias::Right, &());
+ cursor.seek(&point, Bias::Right, &());
if let Some(transform) = cursor.item() {
let transform_start = cursor.start().display.lines;
if transform.display_text.is_some() {
if point.0 == transform_start || matches!(bias, Bias::Left) {
DisplayPoint(transform_start)
} else {
- DisplayPoint(cursor.end().display.lines)
+ DisplayPoint(cursor.end(&()).display.lines)
}
} else {
let overshoot = point.0 - transform_start;
@@ -574,7 +587,7 @@ impl sum_tree::Summary for TransformSummary {
}
impl<'a> sum_tree::Dimension<'a, TransformSummary> for TransformSummary {
- fn add_summary(&mut self, summary: &'a TransformSummary) {
+ fn add_summary(&mut self, summary: &'a TransformSummary, _: &()) {
sum_tree::Summary::add_summary(self, summary, &());
}
}
@@ -649,7 +662,7 @@ impl sum_tree::Summary for FoldSummary {
}
impl<'a> sum_tree::Dimension<'a, FoldSummary> for Fold {
- fn add_summary(&mut self, summary: &'a FoldSummary) {
+ fn add_summary(&mut self, summary: &'a FoldSummary, _: &Buffer) {
self.0.start = summary.start.clone();
self.0.end = summary.end.clone();
}
@@ -662,7 +675,7 @@ impl<'a> sum_tree::SeekDimension<'a, FoldSummary> for Fold {
}
impl<'a> sum_tree::Dimension<'a, FoldSummary> for usize {
- fn add_summary(&mut self, summary: &'a FoldSummary) {
+ fn add_summary(&mut self, summary: &'a FoldSummary, _: &Buffer) {
*self += summary.count;
}
}
@@ -676,8 +689,8 @@ impl<'a> Iterator for BufferRows<'a> {
type Item = u32;
fn next(&mut self) -> Option<Self::Item> {
- while self.display_point > self.cursor.end().display.lines {
- self.cursor.next();
+ while self.display_point > self.cursor.end(&()).display.lines {
+ self.cursor.next(&());
if self.cursor.item().is_none() {
// TODO: Return a bool from next?
break;
@@ -717,10 +730,10 @@ impl<'a> Iterator for Chunks<'a> {
self.buffer_offset += transform.summary.buffer.bytes;
self.buffer_chunks.seek(self.buffer_offset);
- while self.buffer_offset >= self.transform_cursor.end().buffer.bytes
+ while self.buffer_offset >= self.transform_cursor.end(&()).buffer.bytes
&& self.transform_cursor.item().is_some()
{
- self.transform_cursor.next();
+ self.transform_cursor.next(&());
}
return Some(display_text);
@@ -732,10 +745,10 @@ impl<'a> Iterator for Chunks<'a> {
chunk = &chunk[offset_in_chunk..];
// Truncate the chunk so that it ends at the next fold.
- let region_end = self.transform_cursor.end().buffer.bytes - self.buffer_offset;
+ let region_end = self.transform_cursor.end(&()).buffer.bytes - self.buffer_offset;
if chunk.len() >= region_end {
chunk = &chunk[0..region_end];
- self.transform_cursor.next();
+ self.transform_cursor.next(&());
} else {
self.buffer_chunks.next();
}
@@ -772,10 +785,10 @@ impl<'a> Iterator for HighlightedChunks<'a> {
self.buffer_offset += transform.summary.buffer.bytes;
self.buffer_chunks.seek(self.buffer_offset);
- while self.buffer_offset >= self.transform_cursor.end().buffer.bytes
+ while self.buffer_offset >= self.transform_cursor.end(&()).buffer.bytes
&& self.transform_cursor.item().is_some()
{
- self.transform_cursor.next();
+ self.transform_cursor.next(&());
}
return Some((display_text, StyleId::default()));
@@ -796,10 +809,10 @@ impl<'a> Iterator for HighlightedChunks<'a> {
chunk = &chunk[offset_in_chunk..];
// Truncate the chunk so that it ends at the next fold.
- let region_end = self.transform_cursor.end().buffer.bytes - self.buffer_offset;
+ let region_end = self.transform_cursor.end(&()).buffer.bytes - self.buffer_offset;
if chunk.len() >= region_end {
chunk = &chunk[0..region_end];
- self.transform_cursor.next();
+ self.transform_cursor.next(&());
} else {
self.buffer_chunk.take();
}
@@ -813,7 +826,7 @@ impl<'a> Iterator for HighlightedChunks<'a> {
}
impl<'a> sum_tree::Dimension<'a, TransformSummary> for DisplayPoint {
- fn add_summary(&mut self, summary: &'a TransformSummary) {
+ fn add_summary(&mut self, summary: &'a TransformSummary, _: &()) {
self.0 += &summary.display.lines;
}
}
@@ -822,19 +835,19 @@ impl<'a> sum_tree::Dimension<'a, TransformSummary> for DisplayPoint {
pub struct DisplayOffset(usize);
impl<'a> sum_tree::Dimension<'a, TransformSummary> for DisplayOffset {
- fn add_summary(&mut self, summary: &'a TransformSummary) {
+ fn add_summary(&mut self, summary: &'a TransformSummary, _: &()) {
self.0 += &summary.display.bytes;
}
}
impl<'a> sum_tree::Dimension<'a, TransformSummary> for Point {
- fn add_summary(&mut self, summary: &'a TransformSummary) {
+ fn add_summary(&mut self, summary: &'a TransformSummary, _: &()) {
*self += &summary.buffer.lines;
}
}
impl<'a> sum_tree::Dimension<'a, TransformSummary> for usize {
- fn add_summary(&mut self, summary: &'a TransformSummary) {
+ fn add_summary(&mut self, summary: &'a TransformSummary, _: &()) {
*self += &summary.buffer.bytes;
}
}
@@ -1031,7 +1044,7 @@ mod tests {
0..=34 => {
let buffer = buffer.read(cx);
let mut to_fold = Vec::new();
- for _ in 0..rng.gen_range(1..=5) {
+ for _ in 0..rng.gen_range(1..=2) {
let end = buffer.clip_offset(rng.gen_range(0..=buffer.len()), Right);
let start = buffer.clip_offset(rng.gen_range(0..=end), Left);
to_fold.push(start..end);
@@ -1172,7 +1185,7 @@ mod tests {
let start = buffer.clip_offset(rng.gen_range(0..=end), Left);
let expected_folds = map
.folds
- .items()
+ .items(buffer)
.into_iter()
.filter(|fold| {
let start = buffer.anchor_before(start);
@@ -1227,7 +1240,7 @@ mod tests {
fn merged_fold_ranges(&self, cx: &AppContext) -> Vec<Range<usize>> {
let buffer = self.buffer.read(cx);
- let mut folds = self.folds.items();
+ let mut folds = self.folds.items(buffer);
// Ensure sorting doesn't change how folds get merged and displayed.
folds.sort_by(|a, b| a.0.cmp(&b.0, buffer).unwrap());
let mut fold_ranges = folds
@@ -89,7 +89,7 @@ impl<'a> Add<&'a Self> for OperationSummary {
}
impl<'a> Dimension<'a, OperationSummary> for OperationKey {
- fn add_summary(&mut self, summary: &OperationSummary) {
+ fn add_summary(&mut self, summary: &OperationSummary, _: &()) {
assert!(*self <= summary.key);
*self = summary.key;
}
@@ -1,5 +1,6 @@
mod cursor;
+use crate::util::Bias;
use arrayvec::ArrayVec;
pub use cursor::Cursor;
pub use cursor::FilterCursor;
@@ -29,11 +30,23 @@ pub trait Summary: Default + Clone + fmt::Debug {
}
pub trait Dimension<'a, S: Summary>: Clone + fmt::Debug + Default {
- fn add_summary(&mut self, _summary: &'a S);
+ fn add_summary(&mut self, _summary: &'a S, _: &S::Context);
}
impl<'a, T: Summary> Dimension<'a, T> for () {
- fn add_summary(&mut self, _: &'a T) {}
+ fn add_summary(&mut self, _: &'a T, _: &T::Context) {}
+}
+
+impl<'a, S, D1, D2> Dimension<'a, S> for (D1, D2)
+where
+ S: Summary,
+ D1: Dimension<'a, S>,
+ D2: Dimension<'a, S>,
+{
+ fn add_summary(&mut self, summary: &'a S, cx: &S::Context) {
+ self.0.add_summary(summary, cx);
+ self.1.add_summary(summary, cx);
+ }
}
pub trait SeekDimension<'a, T: Summary>: Dimension<'a, T> {
@@ -46,12 +59,6 @@ impl<'a, S: Summary, T: Dimension<'a, S> + Ord> SeekDimension<'a, S> for T {
}
}
-#[derive(Copy, Clone, Eq, PartialEq)]
-pub enum SeekBias {
- Left,
- Right,
-}
-
#[derive(Debug, Clone)]
pub struct SumTree<T: Item>(Arc<Node<T>>);
@@ -71,9 +78,15 @@ impl<T: Item> SumTree<T> {
}
#[allow(unused)]
- pub fn items(&self) -> Vec<T> {
+ pub fn items(&self, cx: &<T::Summary as Summary>::Context) -> Vec<T> {
+ let mut items = Vec::new();
let mut cursor = self.cursor::<(), ()>();
- cursor.cloned().collect()
+ cursor.next(cx);
+ while let Some(item) = cursor.item() {
+ items.push(item.clone());
+ cursor.next(cx);
+ }
+ items
}
pub fn cursor<'a, S, U>(&'a self) -> Cursor<T, S, U>
@@ -84,12 +97,16 @@ impl<T: Item> SumTree<T> {
Cursor::new(self)
}
- pub fn filter<'a, F, U>(&'a self, filter_node: F) -> FilterCursor<F, T, U>
+ pub fn filter<'a, F, U>(
+ &'a self,
+ filter_node: F,
+ cx: &<T::Summary as Summary>::Context,
+ ) -> FilterCursor<F, T, U>
where
F: Fn(&T::Summary) -> bool,
U: Dimension<'a, T::Summary>,
{
- FilterCursor::new(self, filter_node)
+ FilterCursor::new(self, filter_node, cx)
}
#[allow(dead_code)]
@@ -141,11 +158,14 @@ impl<T: Item> SumTree<T> {
}
}
- pub fn extent<'a, D: Dimension<'a, T::Summary>>(&'a self) -> D {
+ pub fn extent<'a, D: Dimension<'a, T::Summary>>(
+ &'a self,
+ cx: &<T::Summary as Summary>::Context,
+ ) -> D {
let mut extent = D::default();
match self.0.as_ref() {
Node::Internal { summary, .. } | Node::Leaf { summary, .. } => {
- extent.add_summary(summary);
+ extent.add_summary(summary, cx);
}
}
extent
@@ -392,7 +412,7 @@ impl<T: KeyedItem> SumTree<T> {
pub fn insert(&mut self, item: T, cx: &<T::Summary as Summary>::Context) {
*self = {
let mut cursor = self.cursor::<T::Key, ()>();
- let mut new_tree = cursor.slice(&item.key(), SeekBias::Left, cx);
+ let mut new_tree = cursor.slice(&item.key(), Bias::Left, cx);
new_tree.push(item, cx);
new_tree.push_tree(cursor.suffix(cx), cx);
new_tree
@@ -416,7 +436,7 @@ impl<T: KeyedItem> SumTree<T> {
let mut new_tree = SumTree::new();
let mut buffered_items = Vec::new();
- cursor.seek(&T::Key::default(), SeekBias::Left, cx);
+ cursor.seek(&T::Key::default(), Bias::Left, cx);
for edit in edits {
let new_key = edit.key();
let mut old_item = cursor.item();
@@ -426,7 +446,7 @@ impl<T: KeyedItem> SumTree<T> {
.map_or(false, |old_item| old_item.key() < new_key)
{
new_tree.extend(buffered_items.drain(..), cx);
- let slice = cursor.slice(&new_key, SeekBias::Left, cx);
+ let slice = cursor.slice(&new_key, Bias::Left, cx);
new_tree.push_tree(slice, cx);
old_item = cursor.item();
}
@@ -434,7 +454,7 @@ impl<T: KeyedItem> SumTree<T> {
if let Some(old_item) = old_item {
if old_item.key() == new_key {
removed.push(old_item.clone());
- cursor.next();
+ cursor.next(cx);
}
}
@@ -456,7 +476,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, ()>();
- if cursor.seek(key, SeekBias::Left, cx) {
+ if cursor.seek(key, Bias::Left, cx) {
cursor.item()
} else {
None
@@ -580,7 +600,10 @@ mod tests {
tree2.extend(50..100, &());
tree1.push_tree(tree2, &());
- assert_eq!(tree1.items(), (0..20).chain(50..100).collect::<Vec<u8>>());
+ assert_eq!(
+ tree1.items(&()),
+ (0..20).chain(50..100).collect::<Vec<u8>>()
+ );
}
#[test]
@@ -596,32 +619,33 @@ mod tests {
tree.extend(rng.sample_iter(distributions::Standard).take(count), &());
for _ in 0..5 {
- let splice_end = rng.gen_range(0..tree.extent::<Count>().0 + 1);
+ let splice_end = rng.gen_range(0..tree.extent::<Count>(&()).0 + 1);
let splice_start = rng.gen_range(0..splice_end + 1);
let count = rng.gen_range(0..3);
- let tree_end = tree.extent::<Count>();
+ let tree_end = tree.extent::<Count>(&());
let new_items = rng
.sample_iter(distributions::Standard)
.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 new_tree = cursor.slice(&Count(splice_start), SeekBias::Right, &());
+ let mut new_tree = cursor.slice(&Count(splice_start), Bias::Right, &());
new_tree.extend(new_items, &());
- cursor.seek(&Count(splice_end), SeekBias::Right, &());
- new_tree.push_tree(cursor.slice(&tree_end, SeekBias::Right, &()), &());
+ cursor.seek(&Count(splice_end), Bias::Right, &());
+ new_tree.push_tree(cursor.slice(&tree_end, Bias::Right, &()), &());
new_tree
};
- assert_eq!(tree.items(), reference_items);
+ assert_eq!(tree.items(&()), reference_items);
- let mut filter_cursor = tree.filter::<_, Count>(|summary| summary.contains_even);
+ let mut filter_cursor =
+ tree.filter::<_, Count>(|summary| summary.contains_even, &());
let mut reference_filter = tree
- .items()
+ .items(&())
.into_iter()
.enumerate()
.filter(|(_, item)| (item & 1) == 0);
@@ -629,14 +653,14 @@ mod tests {
let (reference_index, reference_item) = reference_filter.next().unwrap();
assert_eq!(actual_item, &reference_item);
assert_eq!(filter_cursor.start().0, reference_index);
- filter_cursor.next();
+ filter_cursor.next(&());
}
assert!(reference_filter.next().is_none());
- let mut pos = rng.gen_range(0..tree.extent::<Count>().0 + 1);
+ let mut pos = rng.gen_range(0..tree.extent::<Count>(&()).0 + 1);
let mut before_start = false;
let mut cursor = tree.cursor::<Count, Count>();
- cursor.seek(&Count(pos), SeekBias::Right, &());
+ cursor.seek(&Count(pos), Bias::Right, &());
for i in 0..10 {
assert_eq!(cursor.start().0, pos);
@@ -654,13 +678,13 @@ mod tests {
}
if i < 5 {
- cursor.next();
+ cursor.next(&());
if pos < reference_items.len() {
pos += 1;
before_start = false;
}
} else {
- cursor.prev();
+ cursor.prev(&());
if pos == 0 {
before_start = true;
}
@@ -670,18 +694,10 @@ mod tests {
}
for _ in 0..10 {
- let end = rng.gen_range(0..tree.extent::<Count>().0 + 1);
+ let end = rng.gen_range(0..tree.extent::<Count>(&()).0 + 1);
let start = rng.gen_range(0..end + 1);
- let start_bias = if rng.gen() {
- SeekBias::Left
- } else {
- SeekBias::Right
- };
- let end_bias = if rng.gen() {
- SeekBias::Left
- } else {
- SeekBias::Right
- };
+ 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, ()>();
cursor.seek(&Count(start), start_bias, &());
@@ -701,7 +717,7 @@ mod tests {
let tree = SumTree::<u8>::new();
let mut cursor = tree.cursor::<Count, Sum>();
assert_eq!(
- cursor.slice(&Count(0), SeekBias::Right, &()).items(),
+ cursor.slice(&Count(0), Bias::Right, &()).items(&()),
Vec::<u8>::new()
);
assert_eq!(cursor.item(), None);
@@ -713,34 +729,34 @@ mod tests {
tree.extend(vec![1], &());
let mut cursor = tree.cursor::<Count, Sum>();
assert_eq!(
- cursor.slice(&Count(0), SeekBias::Right, &()).items(),
+ 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.start(), &Sum(0));
- cursor.next();
+ cursor.next(&());
assert_eq!(cursor.item(), None);
assert_eq!(cursor.prev_item(), Some(&1));
assert_eq!(cursor.start(), &Sum(1));
- cursor.prev();
+ cursor.prev(&());
assert_eq!(cursor.item(), Some(&1));
assert_eq!(cursor.prev_item(), None);
assert_eq!(cursor.start(), &Sum(0));
let mut cursor = tree.cursor::<Count, Sum>();
- assert_eq!(cursor.slice(&Count(1), SeekBias::Right, &()).items(), [1]);
+ 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.start(), &Sum(1));
- cursor.seek(&Count(0), SeekBias::Right, &());
+ cursor.seek(&Count(0), Bias::Right, &());
assert_eq!(
cursor
- .slice(&tree.extent::<Count>(), SeekBias::Right, &())
- .items(),
+ .slice(&tree.extent::<Count>(&()), Bias::Right, &())
+ .items(&()),
[1]
);
assert_eq!(cursor.item(), None);
@@ -752,71 +768,68 @@ mod tests {
tree.extend(vec![1, 2, 3, 4, 5, 6], &());
let mut cursor = tree.cursor::<Count, Sum>();
- assert_eq!(
- cursor.slice(&Count(2), SeekBias::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.start(), &Sum(3));
- cursor.next();
+ cursor.next(&());
assert_eq!(cursor.item(), Some(&4));
assert_eq!(cursor.prev_item(), Some(&3));
assert_eq!(cursor.start(), &Sum(6));
- cursor.next();
+ cursor.next(&());
assert_eq!(cursor.item(), Some(&5));
assert_eq!(cursor.prev_item(), Some(&4));
assert_eq!(cursor.start(), &Sum(10));
- cursor.next();
+ cursor.next(&());
assert_eq!(cursor.item(), Some(&6));
assert_eq!(cursor.prev_item(), Some(&5));
assert_eq!(cursor.start(), &Sum(15));
- cursor.next();
- cursor.next();
+ cursor.next(&());
+ cursor.next(&());
assert_eq!(cursor.item(), None);
assert_eq!(cursor.prev_item(), Some(&6));
assert_eq!(cursor.start(), &Sum(21));
- cursor.prev();
+ cursor.prev(&());
assert_eq!(cursor.item(), Some(&6));
assert_eq!(cursor.prev_item(), Some(&5));
assert_eq!(cursor.start(), &Sum(15));
- cursor.prev();
+ cursor.prev(&());
assert_eq!(cursor.item(), Some(&5));
assert_eq!(cursor.prev_item(), Some(&4));
assert_eq!(cursor.start(), &Sum(10));
- cursor.prev();
+ cursor.prev(&());
assert_eq!(cursor.item(), Some(&4));
assert_eq!(cursor.prev_item(), Some(&3));
assert_eq!(cursor.start(), &Sum(6));
- cursor.prev();
+ cursor.prev(&());
assert_eq!(cursor.item(), Some(&3));
assert_eq!(cursor.prev_item(), Some(&2));
assert_eq!(cursor.start(), &Sum(3));
- cursor.prev();
+ cursor.prev(&());
assert_eq!(cursor.item(), Some(&2));
assert_eq!(cursor.prev_item(), Some(&1));
assert_eq!(cursor.start(), &Sum(1));
- cursor.prev();
+ cursor.prev(&());
assert_eq!(cursor.item(), Some(&1));
assert_eq!(cursor.prev_item(), None);
assert_eq!(cursor.start(), &Sum(0));
- cursor.prev();
+ cursor.prev(&());
assert_eq!(cursor.item(), None);
assert_eq!(cursor.prev_item(), None);
assert_eq!(cursor.start(), &Sum(0));
- cursor.next();
+ cursor.next(&());
assert_eq!(cursor.item(), Some(&1));
assert_eq!(cursor.prev_item(), None);
assert_eq!(cursor.start(), &Sum(0));
@@ -824,19 +837,19 @@ mod tests {
let mut cursor = tree.cursor::<Count, Sum>();
assert_eq!(
cursor
- .slice(&tree.extent::<Count>(), SeekBias::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));
assert_eq!(cursor.start(), &Sum(21));
- cursor.seek(&Count(3), SeekBias::Right, &());
+ cursor.seek(&Count(3), Bias::Right, &());
assert_eq!(
cursor
- .slice(&tree.extent::<Count>(), SeekBias::Right, &())
- .items(),
+ .slice(&tree.extent::<Count>(&()), Bias::Right, &())
+ .items(&()),
[4, 5, 6]
);
assert_eq!(cursor.item(), None);
@@ -844,23 +857,23 @@ mod tests {
assert_eq!(cursor.start(), &Sum(21));
// Seeking can bias left or right
- cursor.seek(&Count(1), SeekBias::Left, &());
+ cursor.seek(&Count(1), Bias::Left, &());
assert_eq!(cursor.item(), Some(&1));
- cursor.seek(&Count(1), SeekBias::Right, &());
+ cursor.seek(&Count(1), Bias::Right, &());
assert_eq!(cursor.item(), Some(&2));
// Slicing without resetting starts from where the cursor is parked at.
- cursor.seek(&Count(1), SeekBias::Right, &());
+ cursor.seek(&Count(1), Bias::Right, &());
assert_eq!(
- cursor.slice(&Count(3), SeekBias::Right, &()).items(),
+ cursor.slice(&Count(3), Bias::Right, &()).items(&()),
vec![2, 3]
);
assert_eq!(
- cursor.slice(&Count(6), SeekBias::Left, &()).items(),
+ cursor.slice(&Count(6), Bias::Left, &()).items(&()),
vec![4, 5]
);
assert_eq!(
- cursor.slice(&Count(6), SeekBias::Right, &()).items(),
+ cursor.slice(&Count(6), Bias::Right, &()).items(&()),
vec![6]
);
}
@@ -870,7 +883,7 @@ mod tests {
let mut tree = SumTree::<u8>::new();
let removed = tree.edit(vec![Edit::Insert(1), Edit::Insert(2), Edit::Insert(0)], &());
- assert_eq!(tree.items(), vec![0, 1, 2]);
+ 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));
@@ -878,7 +891,7 @@ mod tests {
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]);
+ 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));
@@ -933,19 +946,19 @@ mod tests {
}
impl<'a> Dimension<'a, IntegersSummary> for u8 {
- fn add_summary(&mut self, summary: &IntegersSummary) {
+ fn add_summary(&mut self, summary: &IntegersSummary, _: &()) {
*self = summary.max;
}
}
impl<'a> Dimension<'a, IntegersSummary> for Count {
- fn add_summary(&mut self, summary: &IntegersSummary) {
+ fn add_summary(&mut self, summary: &IntegersSummary, _: &()) {
self.0 += summary.count.0;
}
}
impl<'a> Dimension<'a, IntegersSummary> for Sum {
- fn add_summary(&mut self, summary: &IntegersSummary) {
+ fn add_summary(&mut self, summary: &IntegersSummary, _: &()) {
self.0 += summary.sum.0;
}
}
@@ -49,10 +49,10 @@ where
&self.sum_dimension
}
- pub fn end(&self) -> U {
+ pub fn end(&self, cx: &<T::Summary as Summary>::Context) -> U {
if let Some(item_summary) = self.item_summary() {
let mut end = self.start().clone();
- end.add_summary(item_summary);
+ end.add_summary(item_summary, cx);
end
} else {
self.start().clone()
@@ -134,13 +134,13 @@ where
}
#[allow(unused)]
- pub fn prev(&mut self) {
+ pub fn prev(&mut self, cx: &<T::Summary as Summary>::Context) {
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.descend_to_last_item(self.tree);
+ self.descend_to_last_item(self.tree, cx);
self.at_end = false;
} else {
while let Some(entry) = self.stack.pop() {
@@ -167,8 +167,8 @@ where
..
} => {
for summary in &child_summaries[0..new_index] {
- self.seek_dimension.add_summary(summary);
- self.sum_dimension.add_summary(summary);
+ self.seek_dimension.add_summary(summary, cx);
+ self.sum_dimension.add_summary(summary, cx);
}
self.stack.push(StackEntry {
tree: entry.tree,
@@ -176,12 +176,12 @@ where
seek_dimension: self.seek_dimension.clone(),
sum_dimension: self.sum_dimension.clone(),
});
- self.descend_to_last_item(&child_trees[new_index]);
+ 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);
- self.sum_dimension.add_summary(item_summary);
+ self.seek_dimension.add_summary(item_summary, cx);
+ self.sum_dimension.add_summary(item_summary, cx);
}
self.stack.push(StackEntry {
tree: entry.tree,
@@ -198,11 +198,11 @@ where
}
}
- pub fn next(&mut self) {
- self.next_internal(|_| true)
+ pub fn next(&mut self, cx: &<T::Summary as Summary>::Context) {
+ self.next_internal(|_| true, cx)
}
- fn next_internal<F>(&mut self, filter_node: F)
+ fn next_internal<F>(&mut self, filter_node: F, cx: &<T::Summary as Summary>::Context)
where
F: Fn(&T::Summary) -> bool,
{
@@ -229,9 +229,8 @@ where
..
} => {
if !descend {
- let summary = &child_summaries[entry.index];
- entry.seek_dimension.add_summary(summary);
- entry.sum_dimension.add_summary(summary);
+ entry.seek_dimension = self.seek_dimension.clone();
+ entry.sum_dimension = self.sum_dimension.clone();
entry.index += 1;
}
@@ -240,8 +239,8 @@ where
if filter_node(next_summary) {
break;
} else {
- self.seek_dimension.add_summary(next_summary);
- self.sum_dimension.add_summary(next_summary);
+ self.seek_dimension.add_summary(next_summary, cx);
+ self.sum_dimension.add_summary(next_summary, cx);
}
entry.index += 1;
}
@@ -251,10 +250,10 @@ where
Node::Leaf { item_summaries, .. } => {
if !descend {
let item_summary = &item_summaries[entry.index];
- self.seek_dimension.add_summary(item_summary);
- entry.seek_dimension.add_summary(item_summary);
- self.sum_dimension.add_summary(item_summary);
- entry.sum_dimension.add_summary(item_summary);
+ 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);
entry.index += 1;
}
@@ -263,10 +262,10 @@ where
if filter_node(next_item_summary) {
return;
} else {
- self.seek_dimension.add_summary(next_item_summary);
- entry.seek_dimension.add_summary(next_item_summary);
- self.sum_dimension.add_summary(next_item_summary);
- entry.sum_dimension.add_summary(next_item_summary);
+ 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);
entry.index += 1;
}
} else {
@@ -295,7 +294,11 @@ where
debug_assert!(self.stack.is_empty() || self.stack.last().unwrap().tree.0.is_leaf());
}
- fn descend_to_last_item(&mut self, mut subtree: &'a SumTree<T>) {
+ fn descend_to_last_item(
+ &mut self,
+ mut subtree: &'a SumTree<T>,
+ cx: &<T::Summary as Summary>::Context,
+ ) {
self.did_seek = true;
loop {
match subtree.0.as_ref() {
@@ -305,8 +308,8 @@ where
..
} => {
for summary in &child_summaries[0..child_summaries.len() - 1] {
- self.seek_dimension.add_summary(summary);
- self.sum_dimension.add_summary(summary);
+ self.seek_dimension.add_summary(summary, cx);
+ self.sum_dimension.add_summary(summary, cx);
}
self.stack.push(StackEntry {
@@ -320,8 +323,8 @@ where
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);
- self.sum_dimension.add_summary(item_summary);
+ self.seek_dimension.add_summary(item_summary, cx);
+ self.sum_dimension.add_summary(item_summary, cx);
}
self.stack.push(StackEntry {
tree: subtree,
@@ -342,28 +345,28 @@ where
S: SeekDimension<'a, T::Summary>,
U: Dimension<'a, T::Summary>,
{
- pub fn seek(&mut self, pos: &S, bias: SeekBias, cx: &<T::Summary as Summary>::Context) -> bool {
+ pub fn seek(&mut self, pos: &S, bias: Bias, cx: &<T::Summary as Summary>::Context) -> bool {
self.reset();
- self.seek_internal::<()>(pos, bias, &mut SeekAggregate::None, cx)
+ self.seek_internal::<()>(Some(pos), bias, &mut SeekAggregate::None, cx)
}
pub fn seek_forward(
&mut self,
pos: &S,
- bias: SeekBias,
+ bias: Bias,
cx: &<T::Summary as Summary>::Context,
) -> bool {
- self.seek_internal::<()>(pos, bias, &mut SeekAggregate::None, cx)
+ self.seek_internal::<()>(Some(pos), bias, &mut SeekAggregate::None, cx)
}
pub fn slice(
&mut self,
end: &S,
- bias: SeekBias,
+ bias: Bias,
cx: &<T::Summary as Summary>::Context,
) -> SumTree<T> {
let mut slice = SeekAggregate::Slice(SumTree::new());
- self.seek_internal::<()>(end, bias, &mut slice, cx);
+ self.seek_internal::<()>(Some(end), bias, &mut slice, cx);
if let SeekAggregate::Slice(slice) = slice {
slice
} else {
@@ -372,9 +375,8 @@ where
}
pub fn suffix(&mut self, cx: &<T::Summary as Summary>::Context) -> SumTree<T> {
- let extent = self.tree.extent::<S>();
let mut slice = SeekAggregate::Slice(SumTree::new());
- self.seek_internal::<()>(&extent, SeekBias::Right, &mut slice, cx);
+ self.seek_internal::<()>(None, Bias::Right, &mut slice, cx);
if let SeekAggregate::Slice(slice) = slice {
slice
} else {
@@ -382,17 +384,12 @@ where
}
}
- pub fn summary<D>(
- &mut self,
- end: &S,
- bias: SeekBias,
- cx: &<T::Summary as Summary>::Context,
- ) -> D
+ pub fn summary<D>(&mut self, end: &S, bias: Bias, cx: &<T::Summary as Summary>::Context) -> D
where
D: Dimension<'a, T::Summary>,
{
let mut summary = SeekAggregate::Summary(D::default());
- self.seek_internal(end, bias, &mut summary, cx);
+ self.seek_internal(Some(end), bias, &mut summary, cx);
if let SeekAggregate::Summary(summary) = summary {
summary
} else {
@@ -402,229 +399,126 @@ where
fn seek_internal<D>(
&mut self,
- target: &S,
- bias: SeekBias,
+ target: Option<&S>,
+ bias: Bias,
aggregate: &mut SeekAggregate<T, D>,
cx: &<T::Summary as Summary>::Context,
) -> bool
where
D: Dimension<'a, T::Summary>,
{
- debug_assert!(target.cmp(&self.seek_dimension, cx) >= Ordering::Equal);
- let mut containing_subtree = None;
+ if let Some(target) = target {
+ debug_assert!(
+ target.cmp(&self.seek_dimension, cx) >= Ordering::Equal,
+ "cannot seek backward from {:?} to {:?}",
+ self.seek_dimension,
+ target
+ );
+ }
- if self.did_seek {
- 'outer: while let Some(entry) = self.stack.last_mut() {
- {
- match *entry.tree.0 {
- Node::Internal {
- ref child_summaries,
- ref child_trees,
- ..
- } => {
- entry.index += 1;
- for (child_tree, child_summary) in child_trees[entry.index..]
- .iter()
- .zip(&child_summaries[entry.index..])
- {
- let mut child_end = self.seek_dimension.clone();
- child_end.add_summary(&child_summary);
-
- let comparison = target.cmp(&child_end, cx);
- if comparison == Ordering::Greater
- || (comparison == Ordering::Equal && bias == SeekBias::Right)
- {
- self.seek_dimension = child_end;
- self.sum_dimension.add_summary(child_summary);
- match aggregate {
- SeekAggregate::None => {}
- SeekAggregate::Slice(slice) => {
- slice.push_tree(child_tree.clone(), cx);
- }
- SeekAggregate::Summary(summary) => {
- summary.add_summary(child_summary);
- }
- }
- entry.index += 1;
- } else {
- containing_subtree = Some(child_tree);
- break 'outer;
- }
- }
- }
- Node::Leaf {
- ref items,
- ref item_summaries,
- ..
- } => {
- let mut slice_items = ArrayVec::<[T; 2 * TREE_BASE]>::new();
- let mut slice_item_summaries =
- ArrayVec::<[T::Summary; 2 * TREE_BASE]>::new();
- let mut slice_items_summary = match aggregate {
- SeekAggregate::Slice(_) => Some(T::Summary::default()),
- _ => None,
- };
-
- for (item, item_summary) in items[entry.index..]
- .iter()
- .zip(&item_summaries[entry.index..])
- {
- let mut child_end = self.seek_dimension.clone();
- child_end.add_summary(item_summary);
-
- let comparison = target.cmp(&child_end, cx);
- if comparison == Ordering::Greater
- || (comparison == Ordering::Equal && bias == SeekBias::Right)
- {
- self.seek_dimension = child_end;
- self.sum_dimension.add_summary(item_summary);
- 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);
- }
- SeekAggregate::Summary(summary) => {
- summary.add_summary(item_summary);
- }
- }
- entry.index += 1;
- } else {
- if let SeekAggregate::Slice(slice) = aggregate {
- slice.push_tree(
- SumTree(Arc::new(Node::Leaf {
- summary: slice_items_summary.unwrap(),
- items: slice_items,
- item_summaries: slice_item_summaries,
- })),
- cx,
- );
- }
- break 'outer;
- }
- }
+ 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(),
+ });
+ }
- if let SeekAggregate::Slice(slice) = aggregate {
- if !slice_items.is_empty() {
- slice.push_tree(
- SumTree(Arc::new(Node::Leaf {
- summary: slice_items_summary.unwrap(),
- items: slice_items,
- item_summaries: slice_item_summaries,
- })),
- 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;
}
- }
- self.stack.pop();
- }
- } else {
- self.did_seek = true;
- containing_subtree = Some(self.tree);
- }
+ for (child_tree, child_summary) in child_trees[entry.index..]
+ .iter()
+ .zip(&child_summaries[entry.index..])
+ {
+ let mut child_end = self.seek_dimension.clone();
+ child_end.add_summary(&child_summary, cx);
- if let Some(mut subtree) = containing_subtree {
- loop {
- let mut next_subtree = None;
- match *subtree.0 {
- Node::Internal {
- ref child_summaries,
- ref child_trees,
- ..
- } => {
- for (index, (child_tree, child_summary)) in
- child_trees.iter().zip(child_summaries).enumerate()
+ let comparison =
+ target.map_or(Ordering::Greater, |t| t.cmp(&child_end, cx));
+ if comparison == Ordering::Greater
+ || (comparison == Ordering::Equal && bias == Bias::Right)
{
- let mut child_end = self.seek_dimension.clone();
- child_end.add_summary(child_summary);
-
- let comparison = target.cmp(&child_end, cx);
- if comparison == Ordering::Greater
- || (comparison == Ordering::Equal && bias == SeekBias::Right)
- {
- self.seek_dimension = child_end;
- self.sum_dimension.add_summary(child_summary);
- match aggregate {
- SeekAggregate::None => {}
- SeekAggregate::Slice(slice) => {
- slice.push_tree(child_trees[index].clone(), cx);
- }
- SeekAggregate::Summary(summary) => {
- summary.add_summary(child_summary);
- }
+ self.seek_dimension = child_end;
+ self.sum_dimension.add_summary(child_summary, cx);
+ match aggregate {
+ SeekAggregate::None => {}
+ SeekAggregate::Slice(slice) => {
+ slice.push_tree(child_tree.clone(), cx);
+ }
+ SeekAggregate::Summary(summary) => {
+ summary.add_summary(child_summary, cx);
}
- } else {
- self.stack.push(StackEntry {
- tree: subtree,
- index,
- seek_dimension: self.seek_dimension.clone(),
- sum_dimension: self.sum_dimension.clone(),
- });
- next_subtree = Some(child_tree);
- break;
}
+ entry.index += 1;
+ entry.seek_dimension = self.seek_dimension.clone();
+ entry.sum_dimension = self.sum_dimension.clone();
+ } else {
+ self.stack.push(StackEntry {
+ tree: child_tree,
+ index: 0,
+ seek_dimension: self.seek_dimension.clone(),
+ sum_dimension: self.sum_dimension.clone(),
+ });
+ ascending = false;
+ continue 'outer;
}
}
- Node::Leaf {
- ref items,
- ref item_summaries,
- ..
- } => {
- let mut slice_items = ArrayVec::<[T; 2 * TREE_BASE]>::new();
- let mut slice_item_summaries =
- ArrayVec::<[T::Summary; 2 * TREE_BASE]>::new();
- let mut slice_items_summary = match aggregate {
- SeekAggregate::Slice(_) => Some(T::Summary::default()),
- _ => None,
- };
-
- for (index, (item, item_summary)) in
- items.iter().zip(item_summaries).enumerate()
+ }
+ Node::Leaf {
+ ref items,
+ ref item_summaries,
+ ..
+ } => {
+ let mut slice_items = ArrayVec::<[T; 2 * TREE_BASE]>::new();
+ let mut slice_item_summaries = ArrayVec::<[T::Summary; 2 * TREE_BASE]>::new();
+ let mut slice_items_summary = match aggregate {
+ SeekAggregate::Slice(_) => Some(T::Summary::default()),
+ _ => None,
+ };
+
+ for (item, item_summary) in items[entry.index..]
+ .iter()
+ .zip(&item_summaries[entry.index..])
+ {
+ let mut child_end = self.seek_dimension.clone();
+ child_end.add_summary(item_summary, cx);
+
+ let comparison =
+ target.map_or(Ordering::Greater, |t| t.cmp(&child_end, cx));
+ if comparison == Ordering::Greater
+ || (comparison == Ordering::Equal && bias == Bias::Right)
{
- let mut child_end = self.seek_dimension.clone();
- child_end.add_summary(item_summary);
-
- let comparison = target.cmp(&child_end, cx);
- if comparison == Ordering::Greater
- || (comparison == Ordering::Equal && bias == SeekBias::Right)
- {
- self.seek_dimension = child_end;
- self.sum_dimension.add_summary(item_summary);
- match aggregate {
- SeekAggregate::None => {}
- SeekAggregate::Slice(_) => {
- slice_items.push(item.clone());
- slice_items_summary
- .as_mut()
- .unwrap()
- .add_summary(item_summary, cx);
- slice_item_summaries.push(item_summary.clone());
- }
- SeekAggregate::Summary(summary) => {
- summary.add_summary(item_summary);
- }
+ self.seek_dimension = child_end;
+ self.sum_dimension.add_summary(item_summary, cx);
+ 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);
+ }
+ SeekAggregate::Summary(summary) => {
+ summary.add_summary(item_summary, cx);
}
- } else {
- self.stack.push(StackEntry {
- tree: subtree,
- index,
- seek_dimension: self.seek_dimension.clone(),
- sum_dimension: self.sum_dimension.clone(),
- });
- break;
}
- }
-
- if let SeekAggregate::Slice(slice) = aggregate {
- if !slice_items.is_empty() {
+ entry.index += 1;
+ } else {
+ if let SeekAggregate::Slice(slice) = aggregate {
slice.push_tree(
SumTree(Arc::new(Node::Leaf {
summary: slice_items_summary.unwrap(),
@@ -634,47 +528,59 @@ where
cx,
);
}
+ break 'outer;
}
}
- };
- if let Some(next_subtree) = next_subtree {
- subtree = next_subtree;
- } else {
- break;
+ if let SeekAggregate::Slice(slice) = aggregate {
+ if !slice_items.is_empty() {
+ slice.push_tree(
+ SumTree(Arc::new(Node::Leaf {
+ summary: slice_items_summary.unwrap(),
+ items: slice_items,
+ item_summaries: slice_item_summaries,
+ })),
+ 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());
- if bias == SeekBias::Left {
- let mut end = self.seek_dimension.clone();
+
+ let mut end = self.seek_dimension.clone();
+ if bias == Bias::Left {
if let Some(summary) = self.item_summary() {
- end.add_summary(summary);
+ end.add_summary(summary, cx);
}
- target.cmp(&end, cx) == Ordering::Equal
- } else {
- target.cmp(&self.seek_dimension, cx) == Ordering::Equal
}
+
+ target.map_or(false, |t| t.cmp(&end, cx) == Ordering::Equal)
}
}
-impl<'a, T, S, U> Iterator for Cursor<'a, T, S, U>
+impl<'a, T, S, Seek, Sum> Iterator for Cursor<'a, T, Seek, Sum>
where
- T: Item,
- S: Dimension<'a, T::Summary>,
- U: Dimension<'a, T::Summary>,
+ T: Item<Summary = S>,
+ S: Summary<Context = ()>,
+ Seek: Dimension<'a, T::Summary>,
+ Sum: Dimension<'a, T::Summary>,
{
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> {
if !self.did_seek {
- self.next();
+ self.next(&());
}
if let Some(item) = self.item() {
- self.next();
+ self.next(&());
Some(item)
} else {
None
@@ -693,9 +599,13 @@ where
T: Item,
U: Dimension<'a, T::Summary>,
{
- pub fn new(tree: &'a SumTree<T>, filter_node: F) -> Self {
+ pub fn new(
+ tree: &'a SumTree<T>,
+ filter_node: F,
+ cx: &<T::Summary as Summary>::Context,
+ ) -> Self {
let mut cursor = tree.cursor::<(), U>();
- cursor.next_internal(&filter_node);
+ cursor.next_internal(&filter_node, cx);
Self {
cursor,
filter_node,
@@ -710,22 +620,23 @@ where
self.cursor.item()
}
- pub fn next(&mut self) {
- self.cursor.next_internal(&self.filter_node);
+ pub fn next(&mut self, cx: &<T::Summary as Summary>::Context) {
+ self.cursor.next_internal(&self.filter_node, cx);
}
}
-impl<'a, F, T, U> Iterator for FilterCursor<'a, F, T, U>
+impl<'a, F, T, S, U> Iterator for FilterCursor<'a, F, T, U>
where
F: Fn(&T::Summary) -> bool,
- T: Item,
+ T: Item<Summary = S>,
+ S: Summary<Context = ()>,
U: Dimension<'a, T::Summary>,
{
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> {
if let Some(item) = self.item() {
- self.cursor.next_internal(&self.filter_node);
+ self.cursor.next_internal(&self.filter_node, &());
Some(item)
} else {
None
@@ -1,20 +1,24 @@
use smallvec::SmallVec;
-use std::cmp::{self, Ordering};
-use std::ops::{Add, AddAssign};
+use std::{
+ cmp::{self, Ordering},
+ fmt,
+ ops::{Add, AddAssign},
+ slice,
+};
pub type ReplicaId = u16;
pub type Seq = u32;
-#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq, Ord, PartialOrd)]
+#[derive(Clone, Copy, Default, Eq, Hash, PartialEq, Ord, PartialOrd)]
pub struct Local {
pub replica_id: ReplicaId,
pub value: Seq,
}
-#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
+#[derive(Clone, Copy, Default, Eq, Hash, PartialEq)]
pub struct Lamport {
- pub value: Seq,
pub replica_id: ReplicaId,
+ pub value: Seq,
}
impl Local {
@@ -54,7 +58,7 @@ impl<'a> AddAssign<&'a Local> for Local {
}
}
-#[derive(Clone, Debug, Default, Eq, PartialEq)]
+#[derive(Clone, Default, Hash, Eq, PartialEq)]
pub struct Global(SmallVec<[Local; 3]>);
impl Global {
@@ -81,12 +85,26 @@ impl Global {
}
}
- pub fn observe_all(&mut self, other: &Self) {
+ pub fn join(&mut self, other: &Self) {
for timestamp in other.0.iter() {
self.observe(*timestamp);
}
}
+ pub fn meet(&mut self, other: &Self) {
+ for timestamp in other.0.iter() {
+ if let Some(entry) = self
+ .0
+ .iter_mut()
+ .find(|t| t.replica_id == timestamp.replica_id)
+ {
+ entry.value = cmp::min(entry.value, timestamp.value);
+ } else {
+ self.0.push(*timestamp);
+ }
+ }
+ }
+
pub fn observed(&self, timestamp: Local) -> bool {
self.get(timestamp.replica_id) >= timestamp.value
}
@@ -94,6 +112,10 @@ impl Global {
pub fn changed_since(&self, other: &Self) -> bool {
self.0.iter().any(|t| t.value > other.get(t.replica_id))
}
+
+ pub fn iter(&self) -> slice::Iter<Local> {
+ self.0.iter()
+ }
}
impl PartialOrd for Global {
@@ -117,6 +139,21 @@ impl PartialOrd for Global {
}
}
+impl Ord for Lamport {
+ fn cmp(&self, other: &Self) -> Ordering {
+ // Use the replica id to break ties between concurrent events.
+ self.value
+ .cmp(&other.value)
+ .then_with(|| self.replica_id.cmp(&other.replica_id))
+ }
+}
+
+impl PartialOrd for Lamport {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
impl Lamport {
pub fn new(replica_id: ReplicaId) -> Self {
Self {
@@ -135,3 +172,28 @@ impl Lamport {
self.value = cmp::max(self.value, timestamp.value) + 1;
}
}
+
+impl fmt::Debug for Local {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "Local {{{}: {}}}", self.replica_id, self.value)
+ }
+}
+
+impl fmt::Debug for Lamport {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "Lamport {{{}: {}}}", self.replica_id, self.value)
+ }
+}
+
+impl fmt::Debug for Global {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "Global {{")?;
+ for (i, element) in self.0.iter().enumerate() {
+ if i > 0 {
+ write!(f, ", ")?;
+ }
+ write!(f, "{}: {}", element.replica_id, element.value)?;
+ }
+ write!(f, "}}")
+ }
+}
@@ -1,6 +1,29 @@
use rand::prelude::*;
use std::cmp::Ordering;
+#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)]
+pub enum Bias {
+ Left,
+ Right,
+}
+
+impl PartialOrd for Bias {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+impl Ord for Bias {
+ fn cmp(&self, other: &Self) -> Ordering {
+ match (self, other) {
+ (Self::Left, Self::Left) => Ordering::Equal,
+ (Self::Left, Self::Right) => Ordering::Less,
+ (Self::Right, Self::Right) => Ordering::Equal,
+ (Self::Right, Self::Left) => Ordering::Greater,
+ }
+ }
+}
+
pub fn post_inc(value: &mut usize) -> usize {
let prev = *value;
*value += 1;
@@ -4,7 +4,8 @@ mod ignore;
use crate::{
editor::{History, Rope},
- sum_tree::{self, Cursor, Edit, SeekBias, SumTree},
+ sum_tree::{self, Cursor, Edit, SumTree},
+ util::Bias,
};
use ::ignore::gitignore::Gitignore;
use anyhow::{Context, Result};
@@ -295,7 +296,7 @@ impl Snapshot {
}
let path = path.as_ref();
let mut cursor = self.entries.cursor::<_, ()>();
- if cursor.seek(&PathSearch::Exact(path), SeekBias::Left, &()) {
+ if cursor.seek(&PathSearch::Exact(path), Bias::Left, &()) {
let entry = cursor.item().unwrap();
if entry.path.as_ref() == path {
return matches!(entry.kind, EntryKind::PendingDir);
@@ -310,7 +311,7 @@ impl Snapshot {
fn entry_for_path(&self, path: impl AsRef<Path>) -> Option<&Entry> {
let mut cursor = self.entries.cursor::<_, ()>();
- if cursor.seek(&PathSearch::Exact(path.as_ref()), SeekBias::Left, &()) {
+ if cursor.seek(&PathSearch::Exact(path.as_ref()), Bias::Left, &()) {
cursor.item()
} else {
None
@@ -367,8 +368,8 @@ impl Snapshot {
fn remove_path(&mut self, path: &Path) {
let new_entries = {
let mut cursor = self.entries.cursor::<_, ()>();
- let mut new_entries = cursor.slice(&PathSearch::Exact(path), SeekBias::Left, &());
- cursor.seek_forward(&PathSearch::Successor(path), SeekBias::Left, &());
+ let mut new_entries = cursor.slice(&PathSearch::Exact(path), Bias::Left, &());
+ cursor.seek_forward(&PathSearch::Successor(path), Bias::Left, &());
new_entries.push_tree(cursor.suffix(&()), &());
new_entries
};
@@ -603,7 +604,7 @@ impl Default for PathKey {
}
impl<'a> sum_tree::Dimension<'a, EntrySummary> for PathKey {
- fn add_summary(&mut self, summary: &'a EntrySummary) {
+ fn add_summary(&mut self, summary: &'a EntrySummary, _: &()) {
self.0 = summary.max_path.clone();
}
}
@@ -643,7 +644,7 @@ impl<'a> Default for PathSearch<'a> {
}
impl<'a: 'b, 'b> sum_tree::Dimension<'a, EntrySummary> for PathSearch<'b> {
- fn add_summary(&mut self, summary: &'a EntrySummary) {
+ fn add_summary(&mut self, summary: &'a EntrySummary, _: &()) {
*self = Self::Exact(summary.max_path.as_ref());
}
}
@@ -652,7 +653,7 @@ impl<'a: 'b, 'b> sum_tree::Dimension<'a, EntrySummary> for PathSearch<'b> {
pub struct FileCount(usize);
impl<'a> sum_tree::Dimension<'a, EntrySummary> for FileCount {
- fn add_summary(&mut self, summary: &'a EntrySummary) {
+ fn add_summary(&mut self, summary: &'a EntrySummary, _: &()) {
self.0 += summary.file_count;
}
}
@@ -661,7 +662,7 @@ impl<'a> sum_tree::Dimension<'a, EntrySummary> for FileCount {
pub struct VisibleFileCount(usize);
impl<'a> sum_tree::Dimension<'a, EntrySummary> for VisibleFileCount {
- fn add_summary(&mut self, summary: &'a EntrySummary) {
+ fn add_summary(&mut self, summary: &'a EntrySummary, _: &()) {
self.0 += summary.visible_file_count;
}
}
@@ -1296,13 +1297,13 @@ pub enum FileIter<'a> {
impl<'a> FileIter<'a> {
fn all(snapshot: &'a Snapshot, start: usize) -> Self {
let mut cursor = snapshot.entries.cursor();
- cursor.seek(&FileCount(start), SeekBias::Right, &());
+ cursor.seek(&FileCount(start), Bias::Right, &());
Self::All(cursor)
}
fn visible(snapshot: &'a Snapshot, start: usize) -> Self {
let mut cursor = snapshot.entries.cursor();
- cursor.seek(&VisibleFileCount(start), SeekBias::Right, &());
+ cursor.seek(&VisibleFileCount(start), Bias::Right, &());
Self::Visible(cursor)
}
@@ -1310,11 +1311,11 @@ impl<'a> FileIter<'a> {
match self {
Self::All(cursor) => {
let ix = *cursor.start();
- cursor.seek_forward(&FileCount(ix.0 + 1), SeekBias::Right, &());
+ cursor.seek_forward(&FileCount(ix.0 + 1), Bias::Right, &());
}
Self::Visible(cursor) => {
let ix = *cursor.start();
- cursor.seek_forward(&VisibleFileCount(ix.0 + 1), SeekBias::Right, &());
+ cursor.seek_forward(&VisibleFileCount(ix.0 + 1), Bias::Right, &());
}
}
}
@@ -1348,7 +1349,7 @@ struct ChildEntriesIter<'a> {
impl<'a> ChildEntriesIter<'a> {
fn new(parent_path: &'a Path, snapshot: &'a Snapshot) -> Self {
let mut cursor = snapshot.entries.cursor();
- cursor.seek(&PathSearch::Exact(parent_path), SeekBias::Right, &());
+ cursor.seek(&PathSearch::Exact(parent_path), Bias::Right, &());
Self {
parent_path,
cursor,
@@ -1363,7 +1364,7 @@ impl<'a> Iterator for ChildEntriesIter<'a> {
if let Some(item) = self.cursor.item() {
if item.path().starts_with(self.parent_path) {
self.cursor
- .seek_forward(&PathSearch::Successor(item.path()), SeekBias::Left, &());
+ .seek_forward(&PathSearch::Successor(item.path()), Bias::Left, &());
Some(item)
} else {
None