diff --git a/Cargo.toml b/Cargo.toml index cbb4531..aa515ca 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -45,6 +45,7 @@ unicode-segmentation = { version = "1.10.0", optional = true } [dev-dependencies] criterion = "0.7" rand = "0.9" +rand_chacha = "0.9" ropey = "1.6" serde_json = "1" serde_test = "1.0.177" diff --git a/src/lib.rs b/src/lib.rs index 952809e..52350ad 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -169,7 +169,7 @@ pub use rope::{Rope, RopeBuilder, RopeSlice}; pub use rope::{ gap_buffer::GapBuffer, gap_slice::GapSlice, - metrics::ChunkSummary, + metrics::StrSummary, }; #[inline] diff --git a/src/rope/gap_buffer.rs b/src/rope/gap_buffer.rs index 44c88c5..7cb4184 100644 --- a/src/rope/gap_buffer.rs +++ b/src/rope/gap_buffer.rs @@ -5,13 +5,14 @@ use alloc::boxed::Box; use alloc::vec::Vec; -use core::ops::{Range, RangeBounds}; +use core::cmp::Ordering; +use core::ops::{Add, AddAssign, Deref, Range, RangeBounds, Sub, SubAssign}; use super::gap_slice::GapSlice; -use super::metrics::{ByteMetric, ChunkSummary}; +use super::metrics::{ByteMetric, StrSummary, ToByteOffset}; use super::utils::{panic_messages as panic, *}; use crate::range_bounds_to_start_end; -use crate::tree::{BalancedLeaf, Leaf, ReplaceableLeaf}; +use crate::tree::{BalancedLeaf, Leaf, Metric, ReplaceableLeaf, Summary}; #[cfg(any(test, feature = "small_chunks"))] const MAX_BYTES: usize = 4; @@ -42,8 +43,14 @@ const MAX_BYTES: usize = 2048; #[derive(Clone)] pub struct GapBuffer { pub(super) bytes: Box<[u8; MAX_BYTES]>, - pub(super) left_summary: ChunkSummary, - pub(super) right_summary: ChunkSummary, + pub(super) left_summary: StrSummary, + pub(super) right_summary: StrSummary, +} + +#[derive(Copy, Clone, Default, Debug, PartialEq)] +pub struct GapBufferSummary { + /// The sum of the [`StrSummary`]s of the left and right chunks. + pub(super) chunks_summary: StrSummary, } impl core::fmt::Debug for GapBuffer { @@ -62,8 +69,8 @@ impl Default for GapBuffer { fn default() -> Self { Self { bytes: Box::new([0u8; MAX_BYTES]), - left_summary: ChunkSummary::default(), - right_summary: ChunkSummary::default(), + left_summary: StrSummary::default(), + right_summary: StrSummary::default(), } } } @@ -128,7 +135,7 @@ impl GapBuffer { &mut self, bytes_to_add: usize, right: &mut Self, - ) -> ChunkSummary { + ) -> StrSummary { debug_assert!(right.len() >= bytes_to_add); debug_assert!(self.len() + bytes_to_add <= MAX_BYTES); @@ -149,7 +156,7 @@ impl GapBuffer { bytes_to_add - right.len_left(), ); - let summary = right.left_summary + ChunkSummary::from(move_left); + let summary = right.left_summary + move_left.summarize(); self.append_two(right.left_chunk(), move_left, summary); @@ -201,8 +208,8 @@ impl GapBuffer { self.left_summary += self.right_summary; self.right_summary = other.left_summary + other.right_summary; - other.left_summary = ChunkSummary::new(); - other.right_summary = ChunkSummary::new(); + other.left_summary = StrSummary::empty(); + other.right_summary = StrSummary::empty(); } /// Appends the given string to `self`, shifting the bytes currently in the @@ -217,20 +224,21 @@ impl GapBuffer { /// # Examples /// /// ``` - /// # use crop::{GapBuffer, ChunkSummary}; + /// # use crop::GapBuffer; + /// # use crop::tree::Leaf; /// /// let mut buffer = GapBuffer::from("ab"); /// assert_eq!(buffer.left_chunk(), "a"); /// assert_eq!(buffer.right_chunk(), "b"); /// - /// buffer.append_str("c", ChunkSummary::from("c")); + /// buffer.append_str("c", "c".summarize()); /// assert_eq!(buffer.left_chunk(), "a"); /// assert_eq!(buffer.right_chunk(), "bc"); /// ``` #[inline] - pub fn append_str(&mut self, str: &str, str_summary: ChunkSummary) { + pub fn append_str(&mut self, str: &str, str_summary: StrSummary) { debug_assert!(str.len() <= self.len_gap()); - debug_assert_eq!(str_summary, ChunkSummary::from(str)); + debug_assert_eq!(str_summary, str.summarize()); let start = MAX_BYTES - self.len_right(); @@ -254,20 +262,18 @@ impl GapBuffer { /// # Examples /// /// ``` - /// # use crop::{GapBuffer, ChunkSummary}; + /// # use crop::GapBuffer; + /// # use crop::tree::Leaf; /// let mut buffer = GapBuffer::from("ab"); /// - /// buffer.append_two("c", "d", ChunkSummary::from("cd")); + /// buffer.append_two("c", "d", "cd".summarize()); /// assert_eq!(buffer.left_chunk(), "a"); /// assert_eq!(buffer.right_chunk(), "bcd"); /// ``` #[inline] - pub fn append_two(&mut self, a: &str, b: &str, a_b_summary: ChunkSummary) { + pub fn append_two(&mut self, a: &str, b: &str, a_b_summary: StrSummary) { debug_assert!(a.len() + b.len() <= self.len_gap()); - debug_assert_eq!( - a_b_summary, - ChunkSummary::from(a) + ChunkSummary::from(b) - ); + debug_assert_eq!(a_b_summary, a.summarize() + b.summarize()); // Shift the right chunk to the left. let start = MAX_BYTES - self.len_right(); @@ -288,7 +294,7 @@ impl GapBuffer { /// is not a character boundary. #[track_caller] #[inline] - fn assert_char_boundary(&self, byte_offset: usize) { + pub(super) fn assert_char_boundary(&self, byte_offset: usize) { debug_assert!(byte_offset <= self.len()); if !self.is_char_boundary(byte_offset) { @@ -306,6 +312,23 @@ impl GapBuffer { } } + /// Returns the byte at the given index. + /// + /// # Panics + /// + /// Panics if the index is out of bounds, i.e. greater than or equal to + /// [`len()`](Self::len()). + #[inline] + pub(super) fn byte(&self, byte_index: usize) -> u8 { + debug_assert!(byte_index < self.len()); + + if byte_index < self.len_left() { + self.left_chunk().as_bytes()[byte_index] + } else { + self.right_chunk().as_bytes()[byte_index - self.len_left()] + } + } + /// The number of bytes `RopeChunk`s must always stay over. pub(super) const fn chunk_min() -> usize { // The buffer can be underfilled by 3 bytes at most, which can happen @@ -313,6 +336,60 @@ impl GapBuffer { Self::min_bytes().saturating_sub(3) } + #[inline] + pub(super) fn convert_len_from_byte(&self, byte_offset: usize) -> M + where + M: Metric, + { + debug_assert!(self.is_char_boundary(byte_offset)); + + #[inline] + fn measure_up_to>( + chunk: &str, + chunk_len: M, + byte_offset: usize, + ) -> M { + debug_assert_eq!(chunk.measure::(), chunk_len); + if byte_offset <= chunk.len() / 2 { + M::measure_leaf(&chunk[..byte_offset]) + } else { + chunk_len - M::measure_leaf(&chunk[byte_offset..]) + } + } + + match byte_offset.cmp(&self.len_left()) { + Ordering::Less => measure_up_to( + self.left_chunk(), + self.left_summary.measure::(), + byte_offset, + ), + Ordering::Equal => self.left_summary.measure::(), + Ordering::Greater => { + self.left_summary.measure::() + + measure_up_to( + self.right_chunk(), + self.right_summary.measure::(), + byte_offset - self.len_left(), + ) + }, + } + } + + #[inline] + pub(super) fn convert_len_to_byte(&self, offset: M) -> usize + where + M: Metric + ToByteOffset, + { + let len_left = self.left_summary.measure::(); + + if offset <= len_left { + offset.to_byte_offset(self.left_chunk()) + } else { + self.len_left() + + (offset - len_left).to_byte_offset(self.right_chunk()) + } + } + /// Creates a new `GapBuffer` from a slice of `&str`s. /// /// # Panics @@ -342,7 +419,7 @@ impl GapBuffer { let mut bytes = Box::new([0u8; MAX_BYTES]); - let mut left_summary = ChunkSummary::new(); + let mut left_summary = StrSummary::empty(); let mut chunks = chunks.iter(); @@ -356,47 +433,47 @@ impl GapBuffer { bytes[range].copy_from_slice(chunk.as_bytes()); - left_summary += ChunkSummary::from(chunk); + left_summary += chunk.summarize(); } else { - let (to_first, to_second) = split_adjusted::( + let (to_left, to_right) = split_adjusted::( chunk, to_left - left_summary.bytes(), ); let range = { let start = left_summary.bytes(); - let end = start + to_first.len(); + let end = start + to_left.len(); start..end }; - bytes[range].copy_from_slice(to_first.as_bytes()); + bytes[range].copy_from_slice(to_left.as_bytes()); - left_summary += ChunkSummary::from(to_first); + left_summary += to_left.summarize(); let mut start = MAX_BYTES - (total_len - left_summary.bytes()); let range = { - let end = start + to_second.len(); + let end = start + to_right.len(); start..end }; - bytes[range].copy_from_slice(to_second.as_bytes()); + bytes[range].copy_from_slice(to_right.as_bytes()); - start += to_second.len(); + start += to_right.len(); - let mut right_summary = ChunkSummary::from(to_second); + let mut right_summary = to_right.summarize(); - for &segment in chunks { + for &chunk in chunks { let range = { - let end = start + segment.len(); + let end = start + chunk.len(); start..end }; - bytes[range].copy_from_slice(segment.as_bytes()); + bytes[range].copy_from_slice(chunk.as_bytes()); - start += segment.len(); + start += chunk.len(); - right_summary += ChunkSummary::from(segment); + right_summary += chunk.summarize(); } return Self { bytes, left_summary, right_summary }; @@ -437,13 +514,13 @@ impl GapBuffer { self.bytes[insert_range].copy_from_slice(s.as_bytes()); - let inserted_summary = ChunkSummary::from(s); + let inserted_summary = s.summarize(); self.left_summary += inserted_summary; } #[inline] - fn is_char_boundary(&self, byte_offset: usize) -> bool { + pub(super) fn is_char_boundary(&self, byte_offset: usize) -> bool { debug_assert!(byte_offset <= self.len()); if byte_offset <= self.len_left() { @@ -500,10 +577,12 @@ impl GapBuffer { self.right_summary.bytes() } + #[inline] pub(super) const fn max_bytes() -> usize { MAX_BYTES } + #[inline] /// The minimum number of bytes this buffer should have to not be /// considered underfilled. pub(super) const fn min_bytes() -> usize { @@ -540,8 +619,8 @@ impl GapBuffer { let offset = byte_offset; #[allow(clippy::comparison_chain)] - // The offset splits the first segment => move all the text after the - // offset to the start of the second segment. + // The offset splits the left chunk => move all the text after the + // offset to the start of the right chunk. // // aa|bb~~~ccc => aa~~~bbccc if offset < self.len_left() { @@ -555,8 +634,8 @@ impl GapBuffer { MAX_BYTES - len_right, ); } - // The offset splits the second segment => move all the text before the - // offset to the end of the first segment. + // The offset splits the right chunk => move all the text before the + // offset to the end of the left chunk. // // aaa~~~bb|cc => aaabb~~~cc else if offset > self.len_left() { @@ -617,7 +696,7 @@ impl GapBuffer { self.len_right() - bytes_to_move, ); - let moved_summary = ChunkSummary::from(move_right); + let moved_summary = move_right.summarize(); right.prepend(move_right, moved_summary); @@ -628,7 +707,7 @@ impl GapBuffer { self.len_left() - (bytes_to_move - self.len_right()), ); - let move_right_summary = ChunkSummary::from(move_right); + let move_right_summary = move_right.summarize(); let moved_summary = move_right_summary + self.right_summary; @@ -644,26 +723,25 @@ impl GapBuffer { /// /// Panics if the resulting buffer would have a length greater than /// `MAX_BYTES`, or if the given summary differs from the string's - /// `ChunkSummary`. + /// `StrSummary`. /// /// # Examples /// /// ``` - /// # use crop::{ChunkSummary, GapBuffer}; + /// # use crop::GapBuffer; + /// # use crop::tree::Leaf; /// let mut buf = GapBuffer::from("at"); /// /// let prepend = "c"; /// - /// let prepended_summary = ChunkSummary::from(prepend); - /// - /// buf.prepend(prepend, prepended_summary); + /// buf.prepend(prepend, prepend.summarize()); /// /// assert_eq!(buf, "cat"); /// ``` #[inline] - pub fn prepend(&mut self, str: &str, str_summary: ChunkSummary) { + pub fn prepend(&mut self, str: &str, str_summary: StrSummary) { debug_assert!(str.len() <= self.len_gap()); - debug_assert_eq!(str_summary, ChunkSummary::from(str)); + debug_assert_eq!(str_summary, str.summarize()); // Shift the left chunk over. let len_left = self.len_left(); @@ -686,17 +764,15 @@ impl GapBuffer { /// # Examples /// /// ``` - /// # use crop::{ChunkSummary, GapBuffer}; + /// # use crop::GapBuffer; + /// # use crop::tree::Leaf; /// let mut buf = GapBuffer::from("!"); /// /// let first = "c"; /// /// let second = "at"; /// - /// let prepended_summary = - /// ChunkSummary::from(first) + ChunkSummary::from(second); - /// - /// buf.prepend_two(first, second, prepended_summary); + /// buf.prepend_two(first, second, "cat".summarize()); /// /// assert_eq!(buf, "cat!"); /// ``` @@ -705,18 +781,14 @@ impl GapBuffer { &mut self, a: &str, b: &str, - prepended_summary: ChunkSummary, + prepended_summary: StrSummary, ) { debug_assert!(a.len() + b.len() <= self.len_gap()); + debug_assert_eq!(prepended_summary, a.summarize() + b.summarize()); - debug_assert_eq!( - prepended_summary, - ChunkSummary::from(a) + ChunkSummary::from(b) - ); - - // Shift the first segment to the right. - let len_first = self.len_left(); - self.bytes.copy_within(..len_first, a.len() + b.len()); + // Shift the left chunk to the right. + let len_left = self.len_left(); + self.bytes.copy_within(..len_left, a.len() + b.len()); // Prepend the first string. self.bytes[..a.len()].copy_from_slice(a.as_bytes()); @@ -738,12 +810,11 @@ impl GapBuffer { /// # Examples /// /// ``` - /// # use crop::{ChunkSummary, GapBuffer}; + /// # use crop::GapBuffer; + /// # use crop::tree::Leaf; /// let mut buffer = GapBuffer::from("a\nbc"); /// - /// let removed_summary = ChunkSummary::from("a\n"); - /// - /// buffer.remove_up_to(2, removed_summary); + /// buffer.remove_up_to(2, "a\n".summarize()); /// /// assert_eq!(buffer, "bc"); /// ``` @@ -751,7 +822,7 @@ impl GapBuffer { pub fn remove_up_to( &mut self, byte_offset: usize, - removed_summary: ChunkSummary, + removed_summary: StrSummary, ) { debug_assert!(byte_offset <= self.len()); debug_assert!(self.is_char_boundary(byte_offset)); @@ -773,7 +844,7 @@ impl GapBuffer { self.left_summary -= removed_summary; } else { self.right_summary -= removed_summary - self.left_summary; - self.left_summary = ChunkSummary::new(); + self.left_summary = StrSummary::empty(); } } @@ -813,7 +884,7 @@ impl GapBuffer { let removed_summary = self.summarize_range(start..end); - let added_summary = ChunkSummary::from(s); + let added_summary = s.summarize(); self.bytes[start..start + s.len()].copy_from_slice(s.as_bytes()); @@ -995,15 +1066,14 @@ impl GapBuffer { /// Returns the summary of the left chunk up to the given byte offset. #[inline] - fn summarize_left_chunk_up_to(&self, byte_offset: usize) -> ChunkSummary { + fn summarize_left_chunk_up_to(&self, byte_offset: usize) -> StrSummary { debug_assert!(byte_offset <= self.len_left()); debug_assert!(self.left_chunk().is_char_boundary(byte_offset)); if byte_offset <= self.len_left() / 2 { - ChunkSummary::from(&self.left_chunk()[..byte_offset]) + self.left_chunk()[..byte_offset].summarize() } else { - self.left_summary - - ChunkSummary::from(&self.left_chunk()[byte_offset..]) + self.left_summary - self.left_chunk()[byte_offset..].summarize() } } @@ -1021,7 +1091,7 @@ impl GapBuffer { /// # use crop::GapBuffer; /// # use crop::tree::Leaf; /// let mut buffer = GapBuffer::from("f\n\r\n"); - /// assert_eq!(buffer.summarize_range(0..buffer.len()), buffer.summarize()); + /// assert_eq!(buffer.summarize_range(0..buffer.len()), *buffer.summarize()); /// /// let s = buffer.summarize_range(0..1); /// assert_eq!(s.bytes(), 1); @@ -1035,7 +1105,7 @@ impl GapBuffer { pub fn summarize_range( &self, Range { start, end }: Range, - ) -> ChunkSummary { + ) -> StrSummary { debug_assert!(start <= end); debug_assert!(end <= self.len()); debug_assert!(self.is_char_boundary(start)); @@ -1046,17 +1116,16 @@ impl GapBuffer { buffer: &GapBuffer, mut start: usize, mut end: usize, - ) -> ChunkSummary { + ) -> StrSummary { // The whole range is inside the left chunk. if end <= buffer.len_left() { - let chunk = &buffer.left_chunk()[start..end]; - ChunkSummary::from(chunk) + buffer.left_chunk()[start..end].summarize() } // The start is on the left chunk and the end is on the right. else if start <= buffer.len_left() { let left_chunk = &buffer.left_chunk()[start..]; - ChunkSummary::from(left_chunk) + left_chunk.summarize() + buffer .summarize_right_chunk_up_to(end - buffer.len_left()) } @@ -1064,8 +1133,7 @@ impl GapBuffer { else { start -= buffer.len_left(); end -= buffer.len_left(); - let chunk = &buffer.right_chunk()[start..end]; - ChunkSummary::from(chunk) + buffer.right_chunk()[start..end].summarize() } } @@ -1087,15 +1155,14 @@ impl GapBuffer { /// Note that the offset is only relative to the right chunk, not to the /// whole gap buffer. #[inline] - fn summarize_right_chunk_up_to(&self, byte_offset: usize) -> ChunkSummary { + fn summarize_right_chunk_up_to(&self, byte_offset: usize) -> StrSummary { debug_assert!(byte_offset <= self.len_right()); debug_assert!(self.right_chunk().is_char_boundary(byte_offset)); if byte_offset <= self.len_right() / 2 { - ChunkSummary::from(&self.right_chunk()[..byte_offset]) + self.right_chunk()[..byte_offset].summarize() } else { - self.right_summary - - ChunkSummary::from(&self.right_chunk()[byte_offset..]) + self.right_summary - self.right_chunk()[byte_offset..].summarize() } } @@ -1110,7 +1177,7 @@ impl GapBuffer { if byte_offset <= self.len_left() { self.left_summary = self.summarize_left_chunk_up_to(byte_offset); - self.right_summary = ChunkSummary::new(); + self.right_summary = StrSummary::empty(); } else { let offset = byte_offset - self.len_left(); @@ -1130,7 +1197,7 @@ impl GapBuffer { } impl Leaf for GapBuffer { - type Summary = ChunkSummary; + type Summary = GapBufferSummary; type BaseMetric = ByteMetric; type Slice<'a> = GapSlice<'a>; @@ -1152,7 +1219,9 @@ impl Leaf for GapBuffer { #[inline] fn summarize(&self) -> Self::Summary { - self.left_summary + self.right_summary + GapBufferSummary { + chunks_summary: self.left_summary + self.right_summary, + } } } @@ -1257,6 +1326,82 @@ impl ReplaceableLeaf for GapBuffer { } } +impl Summary for GapBufferSummary { + type Leaf = GapBuffer; + + #[inline] + fn empty() -> Self { + Self { chunks_summary: StrSummary::empty() } + } +} + +impl Add for GapBufferSummary { + type Output = Self; + + #[inline] + fn add(mut self, other: Self) -> Self::Output { + self += other; + self + } +} + +impl AddAssign for GapBufferSummary { + #[inline] + fn add_assign(&mut self, rhs: Self) { + self.chunks_summary += rhs.chunks_summary; + } +} + +impl Sub for GapBufferSummary { + type Output = Self; + + #[inline] + fn sub(mut self, other: Self) -> Self::Output { + self -= other; + self + } +} + +impl SubAssign for GapBufferSummary { + #[inline] + fn sub_assign(&mut self, rhs: Self) { + self.chunks_summary -= rhs.chunks_summary; + } +} + +impl Deref for GapBufferSummary { + type Target = StrSummary; + + #[inline] + fn deref(&self) -> &Self::Target { + &self.chunks_summary + } +} + +impl> Metric for M { + #[inline(always)] + fn zero() -> Self { + >::zero() + } + + #[inline(always)] + fn measure(summary: &GapBufferSummary) -> Self { + M::measure(&summary.chunks_summary) + } + + #[inline(always)] + fn measure_leaf(gap_buffer: &GapBuffer) -> Self { + M::measure(&gap_buffer.left_summary) + + M::measure(&gap_buffer.right_summary) + } + + #[inline(always)] + fn measure_slice(gap_slice: &GapSlice) -> Self { + M::measure(&gap_slice.left_summary) + + M::measure(&gap_slice.right_summary) + } +} + /// Segments a string into [`GapBuffer`]s with at least /// [`GapBuffer::chunk_min()`] bytes. /// @@ -1432,7 +1577,7 @@ mod tests { buffer.move_gap(2); let offset = 1; - buffer.remove_up_to(offset, ChunkSummary::from(&s[..offset])); + buffer.remove_up_to(offset, s[..offset].summarize()); assert_eq!("bb", buffer); } diff --git a/src/rope/gap_slice.rs b/src/rope/gap_slice.rs index 69baf4c..71a5c97 100644 --- a/src/rope/gap_slice.rs +++ b/src/rope/gap_slice.rs @@ -1,14 +1,14 @@ -use super::gap_buffer::GapBuffer; -use super::metrics::{ChunkSummary, SummaryUpTo, ToByteOffset}; +use super::gap_buffer::{GapBuffer, GapBufferSummary}; +use super::metrics::{StrSummary, SummaryUpTo, ToByteOffset}; use super::utils::{debug_no_quotes, panic_messages as panic}; -use crate::tree::{LeafSlice, Metric}; +use crate::tree::{LeafSlice, Metric, Summary}; /// A slice of a [`GapBuffer`](super::gap_buffer::GapBuffer). #[derive(Copy, Clone, Default)] pub struct GapSlice<'a> { pub(super) bytes: &'a [u8], - pub(super) left_summary: ChunkSummary, - pub(super) right_summary: ChunkSummary, + pub(super) left_summary: StrSummary, + pub(super) right_summary: StrSummary, } impl core::fmt::Debug for GapSlice<'_> { @@ -55,7 +55,7 @@ impl<'a> GapSlice<'a> { } pub(super) fn assert_invariants(&self) { - assert_eq!(self.left_summary, ChunkSummary::from(self.left_chunk())); + assert_eq!(self.left_summary, self.left_chunk().summarize()); if self.len_right() == 0 { assert_eq!(self.len_left(), self.bytes.len()); @@ -84,13 +84,13 @@ impl<'a> GapSlice<'a> { #[inline] fn left_measure(&self) -> M where - M: Metric, + M: Metric, { - M::measure(&self.left_summary) + self.left_summary.measure::() } #[inline] - pub(super) fn truncate_last_char(&mut self) -> ChunkSummary { + pub(super) fn truncate_last_char(&mut self) -> StrSummary { debug_assert!(self.len() > 0); use core::cmp::Ordering; @@ -101,7 +101,7 @@ impl<'a> GapSlice<'a> { .next_back() .expect("this slice isn't empty"); - let removed_summary = ChunkSummary::from(last_char); + let removed_summary = StrSummary::from(last_char); let len_utf8 = removed_summary.bytes(); @@ -123,7 +123,7 @@ impl<'a> GapSlice<'a> { // The right chunk has exactly 1 character, so we can keep just the // left chunk. Ordering::Equal => { - self.right_summary = ChunkSummary::new(); + self.right_summary = StrSummary::empty(); self.bytes = &self.bytes[..self.len_left()]; }, } @@ -134,9 +134,9 @@ impl<'a> GapSlice<'a> { /// Removes the trailing line break (if it has one), returning the summary /// of what was removed. #[inline] - pub(super) fn truncate_trailing_line_break(&mut self) -> ChunkSummary { + pub(super) fn truncate_trailing_line_break(&mut self) -> StrSummary { if !self.has_trailing_newline() { - return ChunkSummary::new(); + return StrSummary::empty(); } let mut removed_summary = self.truncate_last_char(); @@ -170,7 +170,7 @@ impl<'a> GapSlice<'a> { } } - /// The second segment if it's not empty, or the first one otherwise. + /// The right chunk if it's not empty, or the left one otherwise. #[inline] pub(super) fn last_chunk(&self) -> &'a str { if self.len_right() == 0 { @@ -223,7 +223,7 @@ impl<'a> GapSlice<'a> { /// /// # Panics /// - /// Panics if the offset is greater than the M-measure of the slice. + /// Panics if the offset is greater than the M-length of the slice. /// /// # Examples /// @@ -241,7 +241,7 @@ impl<'a> GapSlice<'a> { #[inline] pub fn split_at_offset(&self, mut offset: M) -> (Self, Self) where - M: Metric + ToByteOffset + SummaryUpTo, + M: Metric + ToByteOffset + SummaryUpTo, { debug_assert!(offset <= self.measure::()); @@ -260,7 +260,7 @@ impl<'a> GapSlice<'a> { let left = Self { bytes: bytes_left, left_summary: left_left_summary, - right_summary: ChunkSummary::new(), + right_summary: StrSummary::empty(), }; let right = Self { @@ -294,7 +294,7 @@ impl<'a> GapSlice<'a> { let right = Self { bytes: bytes_right, left_summary: self.right_summary - right_left_summary, - right_summary: ChunkSummary::new(), + right_summary: StrSummary::empty(), }; (left, right) @@ -328,8 +328,10 @@ impl<'a> LeafSlice<'a> for GapSlice<'a> { type Leaf = GapBuffer; #[inline] - fn summarize(&self) -> ChunkSummary { - self.right_summary + self.left_summary + fn summarize(&self) -> GapBufferSummary { + GapBufferSummary { + chunks_summary: self.right_summary + self.left_summary, + } } } diff --git a/src/rope/iterators.rs b/src/rope/iterators.rs index c084898..da22a26 100644 --- a/src/rope/iterators.rs +++ b/src/rope/iterators.rs @@ -44,24 +44,24 @@ impl<'a> Iterator for Chunks<'a> { if let Some(extra) = self.forward_extra_right.take() { Some(extra) } else { - let Some(chunk) = self.leaves.next() else { + let Some(gap_slice) = self.leaves.next() else { return self.backward_extra_left.take(); }; - if chunk.left_chunk().is_empty() { + if gap_slice.left_chunk().is_empty() { #[cfg(feature = "small_chunks")] - if chunk.right_chunk().is_empty() { + if gap_slice.right_chunk().is_empty() { return self.next(); } - debug_assert!(!chunk.right_chunk().is_empty()); + debug_assert!(!gap_slice.right_chunk().is_empty()); - Some(chunk.right_chunk()) + Some(gap_slice.right_chunk()) } else { - if !chunk.right_chunk().is_empty() { - self.forward_extra_right = Some(chunk.right_chunk()); + if !gap_slice.right_chunk().is_empty() { + self.forward_extra_right = Some(gap_slice.right_chunk()); } - Some(chunk.left_chunk()) + Some(gap_slice.left_chunk()) } } } @@ -73,24 +73,24 @@ impl DoubleEndedIterator for Chunks<'_> { if let Some(extra) = self.backward_extra_left.take() { Some(extra) } else { - let Some(chunk) = self.leaves.next_back() else { + let Some(gap_slice) = self.leaves.next_back() else { return self.forward_extra_right.take(); }; - if chunk.right_chunk().is_empty() { + if gap_slice.right_chunk().is_empty() { #[cfg(feature = "small_chunks")] - if chunk.left_chunk().is_empty() { + if gap_slice.left_chunk().is_empty() { return self.next_back(); } - debug_assert!(!chunk.left_chunk().is_empty()); + debug_assert!(!gap_slice.left_chunk().is_empty()); - Some(chunk.left_chunk()) + Some(gap_slice.left_chunk()) } else { - if !chunk.left_chunk().is_empty() { - self.backward_extra_left = Some(chunk.left_chunk()); + if !gap_slice.left_chunk().is_empty() { + self.backward_extra_left = Some(gap_slice.left_chunk()); } - Some(chunk.right_chunk()) + Some(gap_slice.right_chunk()) } } } diff --git a/src/rope/metrics.rs b/src/rope/metrics.rs index 67131d3..c5e68e3 100644 --- a/src/rope/metrics.rs +++ b/src/rope/metrics.rs @@ -1,9 +1,11 @@ use core::ops::{Add, AddAssign, Sub, SubAssign}; -use super::gap_buffer::GapBuffer; +use super::gap_buffer::{GapBuffer, GapBufferSummary}; use super::gap_slice::GapSlice; use crate::tree::{ DoubleEndedUnitMetric, + FromMetric, + Leaf, LeafSlice, Metric, SlicingMetric, @@ -13,38 +15,14 @@ use crate::tree::{ #[derive(Copy, Clone, Default, Debug, PartialEq)] #[doc(hidden)] -pub struct ChunkSummary { +pub struct StrSummary { bytes: usize, line_breaks: usize, #[cfg(feature = "utf16-metric")] utf16_code_units: usize, } -impl From<&str> for ChunkSummary { - #[inline] - fn from(s: &str) -> Self { - Self { - bytes: s.len(), - line_breaks: count::line_breaks(s), - #[cfg(feature = "utf16-metric")] - utf16_code_units: count::utf16_code_units(s), - } - } -} - -impl From for ChunkSummary { - #[inline] - fn from(ch: char) -> Self { - Self { - bytes: ch.len_utf8(), - line_breaks: (ch == '\n') as usize, - #[cfg(feature = "utf16-metric")] - utf16_code_units: ch.len_utf16(), - } - } -} - -impl ChunkSummary { +impl StrSummary { #[inline] pub fn bytes(&self) -> usize { self.bytes @@ -55,12 +33,6 @@ impl ChunkSummary { self.line_breaks } - #[doc(hidden)] - #[inline] - pub fn new() -> Self { - Self::default() - } - #[cfg(feature = "utf16-metric")] #[inline] pub fn utf16_code_units(&self) -> usize { @@ -68,51 +40,38 @@ impl ChunkSummary { } } -impl Summary for ChunkSummary { - type Leaf = GapBuffer; -} - -impl Add for ChunkSummary { - type Output = Self; +impl Summary for StrSummary { + type Leaf = str; #[inline] - fn add(mut self, rhs: Self) -> Self { - self += rhs; - self + fn empty() -> Self { + Self::default() } } -impl Sub for ChunkSummary { - type Output = Self; - +impl From for StrSummary { #[inline] - fn sub(mut self, rhs: Self) -> Self { - self -= rhs; - self + fn from(ch: char) -> Self { + Self { + bytes: ch.len_utf8(), + line_breaks: (ch == '\n') as usize, + #[cfg(feature = "utf16-metric")] + utf16_code_units: ch.len_utf16(), + } } } -impl Add<&Self> for ChunkSummary { +impl Add for StrSummary { type Output = Self; #[inline] - fn add(mut self, rhs: &Self) -> Self { + fn add(mut self, rhs: Self) -> Self { self += rhs; self } } -impl Sub<&Self> for ChunkSummary { - type Output = Self; - - #[inline] - fn sub(mut self, rhs: &Self) -> Self { - self -= rhs; - self - } -} - -impl AddAssign for ChunkSummary { +impl AddAssign for StrSummary { #[inline] fn add_assign(&mut self, rhs: Self) { self.bytes += rhs.bytes; @@ -124,7 +83,17 @@ impl AddAssign for ChunkSummary { } } -impl SubAssign for ChunkSummary { +impl Sub for StrSummary { + type Output = Self; + + #[inline] + fn sub(mut self, rhs: Self) -> Self { + self -= rhs; + self + } +} + +impl SubAssign for StrSummary { #[inline] fn sub_assign(&mut self, rhs: Self) { self.bytes -= rhs.bytes; @@ -136,39 +105,55 @@ impl SubAssign for ChunkSummary { } } -impl AddAssign<&Self> for ChunkSummary { +impl Leaf for str { + type BaseMetric = ByteMetric; + type Slice<'a> = &'a Self; + type Summary = StrSummary; + #[inline] - fn add_assign(&mut self, rhs: &Self) { - *self += *rhs; + fn as_slice(&self) -> Self::Slice<'_> { + self + } + + #[inline] + fn summarize(&self) -> Self::Summary { + StrSummary { + bytes: self.len(), + line_breaks: count::line_breaks(self), + #[cfg(feature = "utf16-metric")] + utf16_code_units: count::utf16_code_units(self), + } } } -impl SubAssign<&Self> for ChunkSummary { +impl<'a> LeafSlice<'a> for &'a str { + type Leaf = str; + #[inline] - fn sub_assign(&mut self, rhs: &Self) { - *self -= *rhs; + fn summarize(&self) -> ::Summary { + (*self).summarize() } } /// Conversion trait from the metric implement this trait to the corresponding /// byte offset. -pub trait ToByteOffset: Metric { +pub trait ToByteOffset: Metric { /// Should return the byte offset of `self` in the given string. fn to_byte_offset(&self, in_str: &str) -> usize; } /// Trait to get the summary of a string up to a given offset. -pub trait SummaryUpTo: Metric { +pub trait SummaryUpTo: Metric { /// Return the summary of the given string up to `offset`, where /// /// * `str_summary` is the string's summary, /// * `byte_offset` is byte offset of `offset`. fn up_to( in_str: &str, - str_summary: ChunkSummary, + str_summary: StrSummary, offset: Self, byte_offset: usize, - ) -> ChunkSummary; + ) -> StrSummary; } #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] @@ -233,13 +218,13 @@ impl SummaryUpTo for ByteMetric { #[inline] fn up_to( in_str: &str, - str_summary: ChunkSummary, + str_summary: StrSummary, offset: Self, byte_offset: usize, - ) -> ChunkSummary { + ) -> StrSummary { debug_assert_eq!(offset.0, byte_offset); - ChunkSummary { + StrSummary { bytes: byte_offset, line_breaks: count::line_breaks_up_to( @@ -258,30 +243,46 @@ impl SummaryUpTo for ByteMetric { } } -impl Metric for ByteMetric { +impl Metric for ByteMetric { #[inline] fn zero() -> Self { Self(0) } #[inline] - fn one() -> Self { - Self(1) + fn measure(summary: &StrSummary) -> Self { + Self(summary.bytes) } #[inline] - fn measure(summary: &ChunkSummary) -> Self { - Self(summary.bytes) + fn measure_leaf(str: &str) -> Self { + Self(str.len()) } #[inline] - fn measure_leaf(gap_buffer: &GapBuffer) -> Self { - Self(gap_buffer.left_summary.bytes + gap_buffer.right_summary.bytes) + fn measure_slice(str: &&str) -> Self { + Self(str.len()) } +} + +impl FromMetric for ByteMetric { + #[inline] + fn measure_up_to( + gap_buffer: &GapBuffer, + line_offset: RawLineMetric, + ) -> Self { + Self(gap_buffer.convert_len_to_byte(line_offset)) + } +} +#[cfg(feature = "utf16-metric")] +impl FromMetric for ByteMetric { #[inline] - fn measure_slice(gap_slice: &GapSlice) -> Self { - Self(gap_slice.left_summary.bytes + gap_slice.right_summary.bytes) + fn measure_up_to( + gap_buffer: &GapBuffer, + utf16_offset: utf16_metric::Utf16Metric, + ) -> Self { + Self(gap_buffer.convert_len_to_byte(utf16_offset)) } } @@ -342,6 +343,17 @@ impl SubAssign for RawLineMetric { } } +impl FromMetric for RawLineMetric { + #[inline] + fn measure_up_to( + gap_buffer: &GapBuffer, + ByteMetric(byte_offset): ByteMetric, + ) -> Self { + gap_buffer.assert_char_boundary(byte_offset); + gap_buffer.convert_len_from_byte::(byte_offset) + } +} + impl ToByteOffset for RawLineMetric { #[inline] fn to_byte_offset(&self, s: &str) -> usize { @@ -354,11 +366,11 @@ impl SummaryUpTo for RawLineMetric { #[inline] fn up_to( in_str: &str, - str_summary: ChunkSummary, + str_summary: StrSummary, Self(line_offset): Self, byte_offset: usize, - ) -> ChunkSummary { - ChunkSummary { + ) -> StrSummary { + StrSummary { bytes: byte_offset, line_breaks: line_offset, @@ -373,36 +385,25 @@ impl SummaryUpTo for RawLineMetric { } } -impl Metric for RawLineMetric { +impl Metric for RawLineMetric { #[inline] fn zero() -> Self { Self(0) } #[inline] - fn one() -> Self { - Self(1) - } - - #[inline] - fn measure(summary: &ChunkSummary) -> Self { + fn measure(summary: &StrSummary) -> Self { Self(summary.line_breaks) } #[inline] - fn measure_leaf(gap_buffer: &GapBuffer) -> Self { - Self( - gap_buffer.left_summary.line_breaks - + gap_buffer.right_summary.line_breaks, - ) + fn measure_leaf(str: &str) -> Self { + Self(count::line_breaks(str)) } #[inline] - fn measure_slice(gap_slice: &GapSlice) -> Self { - Self( - gap_slice.left_summary.line_breaks - + gap_slice.right_summary.line_breaks, - ) + fn measure_slice(str: &&str) -> Self { + Self(count::line_breaks(str)) } } @@ -425,15 +426,20 @@ impl SlicingMetric for RawLineMetric { } impl UnitMetric for RawLineMetric { + #[inline] + fn one() -> Self { + Self(1) + } + #[inline] fn first_unit<'a>( chunk: GapSlice<'a>, - ) -> (GapSlice<'a>, GapSlice<'a>, ChunkSummary) + ) -> (GapSlice<'a>, GapSlice<'a>, ByteMetric) where 'a: 'a, { let (first, rest) = chunk.split_at_offset(RawLineMetric(1)); - (first, rest, first.summarize()) + (first, rest, first.measure()) } } @@ -441,16 +447,16 @@ impl DoubleEndedUnitMetric for RawLineMetric { #[inline] fn last_unit<'a>( slice: GapSlice<'a>, - ) -> (GapSlice<'a>, GapSlice<'a>, ChunkSummary) + ) -> (GapSlice<'a>, GapSlice<'a>, ByteMetric) where 'a: 'a, { - let split_offset = slice.summarize().line_breaks + let split_offset = slice.measure::().0 - (slice.has_trailing_newline() as usize); let (rest, last) = slice.split_at_offset(RawLineMetric(split_offset)); - (rest, last, last.summarize()) + (rest, last, last.measure()) } #[inline] @@ -504,47 +510,47 @@ impl SubAssign for LineMetric { } } -impl Metric for LineMetric { +impl Metric for LineMetric { #[inline] fn zero() -> Self { Self(0) } #[inline] - fn one() -> Self { - Self(1) - } - - #[inline] - fn measure(summary: &ChunkSummary) -> Self { + fn measure(summary: &StrSummary) -> Self { Self(summary.line_breaks) } #[inline] - fn measure_leaf(gap_buffer: &GapBuffer) -> Self { - Self(RawLineMetric::measure_leaf(gap_buffer).0) + fn measure_leaf(str: &str) -> Self { + Self(count::line_breaks(str)) } #[inline] - fn measure_slice(gap_slice: &GapSlice) -> Self { - Self(RawLineMetric::measure_slice(gap_slice).0) + fn measure_slice(str: &&str) -> Self { + Self(count::line_breaks(str)) } } impl UnitMetric for LineMetric { + #[inline] + fn one() -> Self { + Self(1) + } + #[inline] fn first_unit<'a>( chunk: GapSlice<'a>, - ) -> (GapSlice<'a>, GapSlice<'a>, ChunkSummary) + ) -> (GapSlice<'a>, GapSlice<'a>, ByteMetric) where 'a: 'a, { - let (mut first, rest, first_summary) = + let (mut first, rest, first_byte_len) = >::first_unit(chunk); first.truncate_trailing_line_break(); - (first, rest, first_summary) + (first, rest, first_byte_len) } } @@ -552,18 +558,18 @@ impl DoubleEndedUnitMetric for LineMetric { #[inline] fn last_unit<'a>( chunk: GapSlice<'a>, - ) -> (GapSlice<'a>, GapSlice<'a>, ChunkSummary) + ) -> (GapSlice<'a>, GapSlice<'a>, ByteMetric) where 'a: 'a, { - let (rest, mut last, last_summary) = + let (rest, mut last, last_byte_len) = >::last_unit( chunk, ); last.truncate_trailing_line_break(); - (rest, last, last_summary) + (rest, last, last_byte_len) } #[inline] @@ -585,7 +591,7 @@ mod utf16_metric { #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] pub struct Utf16Metric(pub usize); - impl Add for Utf16Metric { + impl Add for Utf16Metric { type Output = Self; #[inline] @@ -594,6 +600,13 @@ mod utf16_metric { } } + impl AddAssign for Utf16Metric { + #[inline] + fn add_assign(&mut self, other: Self) { + self.0 += other.0 + } + } + impl Sub for Utf16Metric { type Output = Self; @@ -603,13 +616,6 @@ mod utf16_metric { } } - impl AddAssign for Utf16Metric { - #[inline] - fn add_assign(&mut self, other: Self) { - self.0 += other.0 - } - } - impl SubAssign for Utf16Metric { #[inline] fn sub_assign(&mut self, other: Self) { @@ -632,11 +638,11 @@ mod utf16_metric { #[inline] fn up_to( in_str: &str, - str_summary: ChunkSummary, + str_summary: StrSummary, Self(utf16_code_unit_offset): Self, byte_offset: usize, - ) -> ChunkSummary { - ChunkSummary { + ) -> StrSummary { + StrSummary { bytes: byte_offset, line_breaks: count::line_breaks_up_to( @@ -650,36 +656,37 @@ mod utf16_metric { } } - impl Metric for Utf16Metric { + impl Metric for Utf16Metric { #[inline] fn zero() -> Self { Self(0) } #[inline] - fn one() -> Self { - Self(1) + fn measure(summary: &StrSummary) -> Self { + Self(summary.utf16_code_units) } #[inline] - fn measure(summary: &ChunkSummary) -> Self { - Self(summary.utf16_code_units) + fn measure_leaf(str: &str) -> Self { + Self(count::utf16_code_units(str)) } #[inline] - fn measure_leaf(gap_buffer: &GapBuffer) -> Self { - Self( - gap_buffer.left_summary.utf16_code_units - + gap_buffer.right_summary.utf16_code_units, - ) + fn measure_slice(str: &&str) -> Self { + Self(count::utf16_code_units(str)) } + } + impl FromMetric for Utf16Metric { + #[track_caller] #[inline] - fn measure_slice(gap_slice: &GapSlice) -> Self { - Self( - gap_slice.left_summary.utf16_code_units - + gap_slice.right_summary.utf16_code_units, - ) + fn measure_up_to( + gap_buffer: &GapBuffer, + ByteMetric(byte_offset): ByteMetric, + ) -> Self { + gap_buffer.assert_char_boundary(byte_offset); + gap_buffer.convert_len_from_byte::(byte_offset) } } diff --git a/src/rope/rope.rs b/src/rope/rope.rs index 6da2669..6bb778e 100644 --- a/src/rope/rope.rs +++ b/src/rope/rope.rs @@ -81,7 +81,7 @@ impl Rope { } let (chunk, ByteMetric(chunk_byte_offset)) = - self.tree.leaf_at_measure(ByteMetric(byte_index + 1)); + self.tree.leaf_at_offset(ByteMetric(byte_index + 1)); chunk.byte(byte_index - chunk_byte_offset) } @@ -133,7 +133,7 @@ impl Rope { } let ByteMetric(byte_offset) = - self.tree.convert_measure(RawLineMetric(line_offset)); + self.tree.convert_len(RawLineMetric(line_offset)); byte_offset } @@ -166,9 +166,8 @@ impl Rope { panic::utf16_offset_out_of_bounds(utf16_offset, self.utf16_len()) } - let ByteMetric(byte_offset) = self - .tree - .convert_measure(super::metrics::Utf16Metric(utf16_offset)); + let ByteMetric(byte_offset) = + self.tree.convert_len(super::metrics::Utf16Metric(utf16_offset)); byte_offset } @@ -375,7 +374,7 @@ impl Rope { } let (chunk, ByteMetric(chunk_byte_offset)) = - self.tree.leaf_at_measure(ByteMetric(byte_offset)); + self.tree.leaf_at_offset(ByteMetric(byte_offset)); chunk.is_char_boundary(byte_offset - chunk_byte_offset) } @@ -460,6 +459,13 @@ impl Rope { panic::line_index_out_of_bounds(line_index, self.line_len()); } + if line_index == self.tree.summary().line_breaks() { + return RopeSlice { + tree_slice: self.tree.slice_from(RawLineMetric(line_index)), + has_trailing_newline: false, + }; + } + let tree_slice = self .tree .slice(RawLineMetric(line_index)..RawLineMetric(line_index + 1)); @@ -534,7 +540,7 @@ impl Rope { } let RawLineMetric(line_offset) = - self.tree.convert_measure(ByteMetric(byte_offset)); + self.tree.convert_len(ByteMetric(byte_offset)); line_offset } @@ -576,6 +582,16 @@ impl Rope { panic::line_offset_out_of_bounds(end, self.line_len()); } + if end == self.tree.summary().line_breaks() + 1 { + let tree_slice = if start == end { + self.tree.slice_from(ByteMetric(self.byte_len())) + } else { + self.tree.slice_from(RawLineMetric(start)) + }; + debug_assert!(!tree_slice.end_slice().has_trailing_newline()); + return RopeSlice { tree_slice, has_trailing_newline: false }; + } + self.tree.slice(RawLineMetric(start)..RawLineMetric(end)).into() } @@ -757,7 +773,7 @@ impl Rope { } let super::metrics::Utf16Metric(utf16_offset) = - self.tree.convert_measure(ByteMetric(byte_offset)); + self.tree.convert_len(ByteMetric(byte_offset)); utf16_offset } diff --git a/src/rope/rope_builder.rs b/src/rope/rope_builder.rs index 54bfa08..cb84ab2 100644 --- a/src/rope/rope_builder.rs +++ b/src/rope/rope_builder.rs @@ -1,9 +1,8 @@ use super::Rope; use super::gap_buffer::GapBuffer; -use super::metrics::ChunkSummary; use super::rope::RopeChunk; use super::utils::split_adjusted; -use crate::tree::TreeBuilder; +use crate::tree::{Leaf, TreeBuilder}; /// An incremental [`Rope`](crate::Rope) builder. #[derive(Clone, Default)] @@ -58,8 +57,7 @@ impl RopeBuilder { &mut self.buffer_len_left, text, ) { - self.buffer.left_summary = - ChunkSummary::from(self.buffer_left_chunk()); + self.buffer.left_summary = self.buffer_left_chunk().summarize(); self.tree_builder.append(core::mem::take(&mut self.buffer)); @@ -103,8 +101,7 @@ impl RopeBuilder { #[inline] pub fn build(mut self) -> Rope { if self.buffer_len_left > 0 { - self.buffer.left_summary = - ChunkSummary::from(self.buffer_left_chunk()); + self.buffer.left_summary = self.buffer_left_chunk().summarize(); self.rope_has_trailing_newline = self.buffer.has_trailing_newline(); diff --git a/src/rope/rope_slice.rs b/src/rope/rope_slice.rs index fc8c7d2..c7c921c 100644 --- a/src/rope/rope_slice.rs +++ b/src/rope/rope_slice.rs @@ -7,7 +7,7 @@ use super::metrics::{ByteMetric, RawLineMetric}; use super::rope::RopeChunk; use super::utils::{panic_messages as panic, *}; use crate::range_bounds_to_start_end; -use crate::tree::TreeSlice; +use crate::tree::{LeafSlice, TreeSlice}; /// An immutable slice of a [`Rope`](crate::Rope). #[derive(Copy, Clone)] @@ -57,7 +57,7 @@ impl<'a> RopeSlice<'a> { } let (chunk, ByteMetric(chunk_byte_offset)) = - self.tree_slice.leaf_at_measure(ByteMetric(byte_index + 1)); + self.tree_slice.leaf_at_offset(ByteMetric(byte_index + 1)); chunk.byte(byte_index - chunk_byte_offset) } @@ -116,7 +116,7 @@ impl<'a> RopeSlice<'a> { } let ByteMetric(byte_offset) = - self.tree_slice.convert_measure(RawLineMetric(line_offset)); + self.tree_slice.convert_len_to_base(RawLineMetric(line_offset)); byte_offset } @@ -152,7 +152,7 @@ impl<'a> RopeSlice<'a> { let ByteMetric(byte_offset) = self .tree_slice - .convert_measure(super::metrics::Utf16Metric(utf16_offset)); + .convert_len_to_base(super::metrics::Utf16Metric(utf16_offset)); byte_offset } @@ -301,7 +301,7 @@ impl<'a> RopeSlice<'a> { } let (chunk, ByteMetric(chunk_byte_offset)) = - self.tree_slice.leaf_at_measure(ByteMetric(byte_offset)); + self.tree_slice.leaf_at_offset(ByteMetric(byte_offset)); chunk.is_char_boundary(byte_offset - chunk_byte_offset) } @@ -385,6 +385,15 @@ impl<'a> RopeSlice<'a> { panic::line_offset_out_of_bounds(line_index, self.line_len()); } + if line_index == self.tree_slice.summary().line_breaks() { + return Self { + tree_slice: self + .tree_slice + .slice_from(RawLineMetric(line_index)), + has_trailing_newline: false, + }; + } + let tree_slice = self .tree_slice .slice(RawLineMetric(line_index)..RawLineMetric(line_index + 1)); @@ -463,7 +472,7 @@ impl<'a> RopeSlice<'a> { } let RawLineMetric(line_offset) = - self.tree_slice.convert_measure(ByteMetric(byte_offset)); + self.tree_slice.convert_len_from_base(ByteMetric(byte_offset)); line_offset } @@ -506,6 +515,16 @@ impl<'a> RopeSlice<'a> { panic::line_offset_out_of_bounds(end, self.line_len()); } + if end == self.tree_slice.summary().line_breaks() + 1 { + let tree_slice = if start == end { + self.tree_slice.slice_from(ByteMetric(self.byte_len())) + } else { + self.tree_slice.slice_from(RawLineMetric(start)) + }; + debug_assert!(!tree_slice.end_slice().has_trailing_newline()); + return Self { tree_slice, has_trailing_newline: false }; + } + self.tree_slice.slice(RawLineMetric(start)..RawLineMetric(end)).into() } @@ -588,15 +607,14 @@ impl<'a> RopeSlice<'a> { let slice = &mut self.tree_slice; // The last slice only contains one byte so we have to re-slice. - if slice.end_summary().bytes() == 1 { + if slice.end_slice.base_len() == ByteMetric(1) { *self = self.byte_slice(..self.byte_len() - 1); } - // The last slice contains more than 2 bytes so we can just mutate - // in place. + // The last slice contains at least 2 bytes, so we can just mutate in + // place. else { - let last = &mut slice.end_slice; - - slice.summary -= last.truncate_last_char(); + slice.summary.chunks_summary -= + slice.end_slice.truncate_last_char(); if slice.leaf_count() == 1 { slice.start_slice = slice.end_slice; @@ -672,7 +690,7 @@ impl<'a> RopeSlice<'a> { } let super::metrics::Utf16Metric(utf16_offset) = - self.tree_slice.convert_measure(ByteMetric(byte_offset)); + self.tree_slice.convert_len_from_base(ByteMetric(byte_offset)); utf16_offset } diff --git a/src/tree/inode.rs b/src/tree/inode.rs index 1cedf71..ce7a06c 100644 --- a/src/tree/inode.rs +++ b/src/tree/inode.rs @@ -281,7 +281,7 @@ impl Inode { // remove the second child. if first.len() + second.len() <= Self::max_children() { first.children.append(&mut second.children); - first.summary += second.summary(); + first.summary += second.summary.clone(); self.children.remove(1); } // Move the minimum number of children from the second child @@ -346,7 +346,7 @@ impl Inode { // then remove the last child. if penultimate.len() + last.len() <= Self::max_children() { penultimate.children.append(&mut last.children); - penultimate.summary += last.summary(); + penultimate.summary += last.summary.clone(); self.children.remove(last_idx); } // Move the minimum number of children from the penultimate @@ -379,7 +379,7 @@ impl Inode { } #[inline] - pub fn base_measure(&self) -> L::BaseMetric { + pub fn base_len(&self) -> L::BaseMetric { self.measure::() } @@ -393,18 +393,18 @@ impl Inode { &self.children } - /// Returns the index of the child at the given measure together - /// with the combined `M`-offset of the other children up to but not - /// including that child. + /// Returns the index of the child at the given offset together with the + /// combined M-length of the other children up to but not including that + /// child. #[inline] - pub(super) fn child_at_measure(&self, measure: M) -> (usize, M) + pub(super) fn child_at_offset(&self, offset: M) -> (usize, M) where M: Metric, { - debug_assert!(measure <= self.measure::()); + debug_assert!(offset <= self.measure::()); let mut idx = 0; - let mut offset = M::zero(); + let mut measured = M::zero(); let children = self.children(); loop { @@ -415,12 +415,12 @@ impl Inode { // goes out of bounds. let child = unsafe { children.get_unchecked(idx) }; - let child_measure = child.measure::(); + let child_len = child.measure::(); - offset += child_measure; + measured += child_len; - if offset >= measure { - return (idx, offset - child_measure); + if offset <= measured { + return (idx, measured - child_len); } idx += 1; @@ -454,13 +454,13 @@ impl Inode { // before the index goes out of bounds. let child = unsafe { children.get_unchecked(idx) }; - let measure = child.measure::(); + let child_len = child.measure::(); - offset += measure; + offset += child_len; if offset >= range.start { if offset >= range.end { - return Some((idx, offset - measure)); + return Some((idx, offset - child_len)); } else { return None; } @@ -491,7 +491,7 @@ impl Inode { debug_assert!(end <= self.len()); for child in &self.children[start..end] { - self.summary -= &child.summary(); + self.summary -= child.summary(); } self.children.drain(start..end) @@ -502,7 +502,7 @@ impl Inode { Self { children: Vec::with_capacity(N), depth: 1, - summary: Default::default(), + summary: L::Summary::empty(), } } @@ -535,7 +535,7 @@ impl Inode { let mut summary = children[0].summary(); for child in &children[1..] { - summary += &child.summary(); + summary += child.summary(); } Self { children, depth, summary } @@ -608,7 +608,7 @@ impl Inode { debug_assert!(!self.is_full()); debug_assert_eq!(child.depth() + 1, self.depth()); - self.summary += &child.summary(); + self.summary += child.summary(); self.children.insert(child_offset, child); } @@ -768,7 +768,7 @@ impl Inode { #[inline] pub fn measure>(&self) -> M { - M::measure(self.summary()) + self.summary().measure() } #[inline] @@ -849,7 +849,7 @@ impl Inode { debug_assert!(!self.is_full()); debug_assert_eq!(child.depth() + 1, self.depth()); - self.summary += &child.summary(); + self.summary += child.summary(); self.children.push(child); } @@ -862,7 +862,7 @@ impl Inode { pub(super) fn remove(&mut self, child_idx: usize) -> Arc> { debug_assert!(child_idx < self.len()); let child = self.children.remove(child_idx); - self.summary -= &child.summary(); + self.summary -= child.summary(); child } @@ -887,9 +887,9 @@ impl Inode { debug_assert_eq!(new_child.depth() + 1, self.depth()); let to_swap = &self.children[child_idx]; - self.summary -= &to_swap.summary(); + self.summary -= to_swap.summary(); - self.summary += &new_child.summary(); + self.summary += new_child.summary(); self.children[child_idx] = new_child; } @@ -929,11 +929,11 @@ impl Inode { { let child = &mut self.children[child_idx]; - self.summary -= &child.summary(); + self.summary -= child.summary(); let ret = fun(child); - self.summary += &child.summary(); + self.summary += child.summary(); ret } diff --git a/src/tree/leaves.rs b/src/tree/leaves.rs index daa6e4b..d2a9d5e 100644 --- a/src/tree/leaves.rs +++ b/src/tree/leaves.rs @@ -50,7 +50,7 @@ impl<'a, const ARITY: usize, L: Leaf> Iterator for Leaves<'a, ARITY, L> { #[inline] fn next(&mut self) -> Option { - if self.measure_yielded() == self.measure_total() { + if self.len_yielded() == self.len_total() { None } else { self.forward.next() @@ -63,7 +63,7 @@ impl DoubleEndedIterator { #[inline] fn next_back(&mut self) -> Option { - if self.measure_yielded() == self.measure_total() { + if self.len_yielded() == self.len_total() { None } else { self.backward.previous() @@ -77,21 +77,18 @@ impl core::iter::FusedIterator } impl Leaves<'_, ARITY, L> { - /// Returns the total base measure of all the leaves in the tree or slice + /// Returns the total base length of all the leaves in the tree or slice /// being iterated over. #[inline] - fn measure_total(&self) -> L::BaseMetric { - debug_assert_eq!( - self.forward.measure_total, - self.backward.measure_total - ); - self.forward.measure_total + fn len_total(&self) -> L::BaseMetric { + debug_assert_eq!(self.forward.len_total, self.backward.len_total); + self.forward.len_total } - /// Returns the base measure of all the leaf slices yielded so far. + /// Returns the base length of all the leaf slices yielded so far. #[inline] - fn measure_yielded(&self) -> L::BaseMetric { - self.forward.measure_yielded + self.backward.measure_yielded + fn len_yielded(&self) -> L::BaseMetric { + self.forward.len_yielded + self.backward.len_yielded } } @@ -124,12 +121,12 @@ struct LeavesForward<'a, const N: usize, L: Leaf> { /// iterating over a `Tree`. base_offset: L::BaseMetric, - /// The total base measure of all the leaves in the tree or slice being + /// The total base length of all the leaves in the tree or slice being /// iterated over. - measure_total: L::BaseMetric, + len_total: L::BaseMetric, - /// The base measure of all the leaf slices yielded so far. - measure_yielded: L::BaseMetric, + /// The base length of all the leaf slices yielded so far. + len_yielded: L::BaseMetric, } impl Clone for LeavesForward<'_, N, L> { @@ -152,8 +149,8 @@ impl<'a, const N: usize, L: Leaf> From<&'a Tree> path: Vec::with_capacity(tree.root().depth().saturating_sub(1)), leaves: &[], next_leaf_idx: 0, - measure_yielded: L::BaseMetric::zero(), - measure_total: tree.base_measure(), + len_yielded: L::BaseMetric::zero(), + len_total: tree.base_len(), } } } @@ -164,15 +161,15 @@ impl<'a, const ARITY: usize, L: Leaf> From<&TreeSlice<'a, ARITY, L>> #[inline] fn from(slice: &TreeSlice<'a, ARITY, L>) -> LeavesForward<'a, ARITY, L> { Self { - base_offset: L::BaseMetric::measure(&slice.offset), + base_offset: slice.offset, first_slice: Some(slice.start_slice), last_slice: Some(slice.end_slice), root: &**slice.root(), path: Vec::with_capacity(slice.root().depth().saturating_sub(1)), leaves: &[], next_leaf_idx: 0, - measure_yielded: L::BaseMetric::zero(), - measure_total: slice.base_measure(), + len_yielded: L::BaseMetric::zero(), + len_total: slice.base_len(), } } } @@ -215,7 +212,7 @@ impl<'a, const N: usize, L: Leaf> LeavesForward<'a, N, L> { #[inline] fn initialize(&mut self) -> (L::Slice<'a>, &'a [Arc>]) { - debug_assert!(self.measure_yielded.is_zero()); + debug_assert!(self.len_yielded.is_zero()); let mut inode = match self.root { Node::Internal(inode) => inode, @@ -241,7 +238,7 @@ impl<'a, const N: usize, L: Leaf> LeavesForward<'a, N, L> { }) .enumerate() { - let this = i.base_measure(); + let this = i.base_len(); if offset + this > self.base_offset { self.path.push((inode, idx)); @@ -263,7 +260,7 @@ impl<'a, const N: usize, L: Leaf> LeavesForward<'a, N, L> { .children() .iter() .take_while(|child| { - offset += child.base_measure(); + offset += child.base_len(); offset <= self.base_offset }) .count(); @@ -282,13 +279,13 @@ impl<'a, const N: usize, L: Leaf> LeavesForward<'a, N, L> { #[inline] fn next(&mut self) -> Option> { - if self.measure_yielded == self.measure_total { + if self.len_yielded == self.len_total { return None; } - if self.measure_yielded.is_zero() { + if self.len_yielded.is_zero() { let (first, rest) = self.initialize(); - self.measure_yielded = first.base_measure(); + self.len_yielded = first.base_len(); self.leaves = rest; return Some(first); } @@ -299,12 +296,12 @@ impl<'a, const N: usize, L: Leaf> LeavesForward<'a, N, L> { let next_leaf = &self.leaves[self.next_leaf_idx].get_leaf(); self.next_leaf_idx += 1; - self.measure_yielded += next_leaf.base_measure(); + self.len_yielded += next_leaf.base_len(); // If we're iterating over a `TreeSlice`, make sure we're not yielding // past its end_slice. - if self.measure_yielded > self.measure_total { - self.measure_yielded = self.measure_total; + if self.len_yielded > self.len_total { + self.len_yielded = self.len_total; self.last_slice.take() } else { Some(next_leaf.as_slice()) @@ -337,17 +334,17 @@ struct LeavesBackward<'a, const N: usize, L: Leaf> { /// we're iterating over a `TreeSlice`. last_slice: Option>, - /// The base measure between the end of [`last_slice`](Self::last_slice) + /// The base length between the end of [`last_slice`](Self::last_slice) /// and the end of the subtree under [`root`](Self::root), or zero if we're /// iterating over a `Tree`. base_offset: L::BaseMetric, - /// The total base measure of all the leaves in the tree or slice being + /// The total base length of all the leaves in the tree or slice being /// iterated over. - measure_total: L::BaseMetric, + len_total: L::BaseMetric, - /// The base measure of all the leaf slices yielded so far. - measure_yielded: L::BaseMetric, + /// The base length of all the leaf slices yielded so far. + len_yielded: L::BaseMetric, } impl Clone for LeavesBackward<'_, N, L> { @@ -370,8 +367,8 @@ impl<'a, const N: usize, L: Leaf> From<&'a Tree> path: Vec::with_capacity(tree.root().depth().saturating_sub(1)), leaves: &[], last_leaf_idx: 0, - measure_yielded: L::BaseMetric::zero(), - measure_total: tree.base_measure(), + len_yielded: L::BaseMetric::zero(), + len_total: tree.base_len(), } } } @@ -381,9 +378,8 @@ impl<'a, const ARITY: usize, L: Leaf> From<&TreeSlice<'a, ARITY, L>> { #[inline] fn from(slice: &TreeSlice<'a, ARITY, L>) -> LeavesBackward<'a, ARITY, L> { - let base_offset = slice.root().base_measure() - - L::BaseMetric::measure(&slice.offset) - - slice.base_measure(); + let base_offset = + slice.root().base_len() - slice.offset - slice.base_len(); Self { base_offset, @@ -393,8 +389,8 @@ impl<'a, const ARITY: usize, L: Leaf> From<&TreeSlice<'a, ARITY, L>> path: Vec::with_capacity(slice.root().depth().saturating_sub(1)), leaves: &[], last_leaf_idx: 0, - measure_yielded: L::BaseMetric::zero(), - measure_total: slice.base_measure(), + len_yielded: L::BaseMetric::zero(), + len_total: slice.base_len(), } } } @@ -437,7 +433,7 @@ impl<'a, const N: usize, L: Leaf> LeavesBackward<'a, N, L> { #[inline] fn initialize(&mut self) -> (&'a [Arc>], L::Slice<'a>) { - debug_assert!(self.measure_yielded.is_zero()); + debug_assert!(self.len_yielded.is_zero()); let mut inode = match self.root { Node::Internal(inode) => inode, @@ -464,7 +460,7 @@ impl<'a, const N: usize, L: Leaf> LeavesBackward<'a, N, L> { .enumerate() .rev() { - let this = i.base_measure(); + let this = i.base_len(); if offset + this > self.base_offset { self.path.push((inode, idx)); @@ -489,7 +485,7 @@ impl<'a, const N: usize, L: Leaf> LeavesBackward<'a, N, L> { .iter() .rev() .take_while(|child| { - offset += child.base_measure(); + offset += child.base_len(); offset <= self.base_offset }) .count(); @@ -508,13 +504,13 @@ impl<'a, const N: usize, L: Leaf> LeavesBackward<'a, N, L> { #[inline] fn previous(&mut self) -> Option> { - if self.measure_yielded == self.measure_total { + if self.len_yielded == self.len_total { return None; } - if self.measure_yielded.is_zero() { + if self.len_yielded.is_zero() { let (rest, last) = self.initialize(); - self.measure_yielded = last.base_measure(); + self.len_yielded = last.base_len(); self.leaves = rest; self.last_leaf_idx = rest.len(); return Some(last); @@ -526,12 +522,12 @@ impl<'a, const N: usize, L: Leaf> LeavesBackward<'a, N, L> { self.last_leaf_idx -= 1; let next_leaf = &self.leaves[self.last_leaf_idx].get_leaf(); - self.measure_yielded += next_leaf.base_measure(); + self.len_yielded += next_leaf.base_len(); // If we're iterating over a `TreeSlice`, make sure we're not yielding // past its start_slice. - if self.measure_yielded > self.measure_total { - self.measure_yielded = self.measure_total; + if self.len_yielded > self.len_total { + self.len_yielded = self.len_total; self.first_slice.take() } else { Some(next_leaf.as_slice()) diff --git a/src/tree/node.rs b/src/tree/node.rs index 2d8722a..6abcccf 100644 --- a/src/tree/node.rs +++ b/src/tree/node.rs @@ -1,4 +1,4 @@ -use super::traits::{BalancedLeaf, Leaf, LeafSlice, Metric, SlicingMetric}; +use super::traits::{BalancedLeaf, FromMetric, Leaf, Metric}; use super::{Arc, Inode}; #[derive(Clone)] @@ -72,16 +72,15 @@ impl Node { } #[inline] - pub(super) fn base_measure(&self) -> L::BaseMetric { + pub(super) fn base_len(&self) -> L::BaseMetric { self.measure::() } - #[track_caller] #[inline] - pub(super) fn convert_measure(&self, up_to: M1) -> M2 + pub(super) fn convert_len(&self, up_to: M1) -> M2 where - M1: SlicingMetric, - M2: Metric, + M1: Metric, + M2: FromMetric, { debug_assert!(up_to <= self.measure::()); @@ -109,8 +108,7 @@ impl Node { }, Node::Leaf(leaf) => { - let slice = M1::slice_up_to(leaf.as_slice(), up_to - m1); - return m2 + slice.measure::(); + return m2 + M2::measure_up_to(leaf, up_to - m1); }, } } @@ -186,12 +184,17 @@ impl Node { } } + /// Returns the leaf at the given offset, together with the leaf's + /// M-offset in the tree. + /// + /// If the offset falls on a leaf boundary, the leaf to its left is + /// returned. #[inline] - pub(super) fn leaf_at_measure(&self, measure: M) -> (L::Slice<'_>, M) + pub(super) fn leaf_at_offset(&self, offset: M) -> (&L, M) where M: Metric, { - debug_assert!(measure <= self.measure::()); + debug_assert!(offset <= self.measure::()); let mut measured = M::zero(); @@ -200,17 +203,15 @@ impl Node { loop { match node { Node::Internal(inode) => { - let (child_idx, offset) = - inode.child_at_measure(measure - measured); + let (child_idx, child_offset) = + inode.child_at_offset(offset - measured); - measured += offset; + measured += child_offset; node = inode.child(child_idx); }, - Node::Leaf(leaf) => { - return (leaf.as_slice(), measured); - }, + Node::Leaf(leaf) => return (leaf, measured), } } } @@ -226,7 +227,7 @@ impl Node { } } - /// Continuously replaces the node its child qs long as it's an internal + /// Continuously replaces the node its child as long as it's an internal /// node with a single child. Note that an inode might become a leaf node /// after calling this. /// diff --git a/src/tree/traits.rs b/src/tree/traits.rs index 07eae20..c13fc6d 100644 --- a/src/tree/traits.rs +++ b/src/tree/traits.rs @@ -1,23 +1,29 @@ use core::fmt::Debug; use core::ops::{Add, AddAssign, RangeBounds, Sub, SubAssign}; -pub trait Summary: - Debug - + Default - + Clone - + Add - + for<'a> Add<&'a Self, Output = Self> - + for<'a> AddAssign<&'a Self> - + Sub - + for<'a> Sub<&'a Self, Output = Self> - + for<'a> SubAssign<&'a Self> - + PartialEq -{ +pub trait Summary: Debug + Clone + AddAssign + SubAssign { /// The leaf type this summary is for. - type Leaf: Leaf; + type Leaf: Leaf + ?Sized; + + fn empty() -> Self; + + #[inline] + fn base_len(&self) -> ::BaseMetric { + self.measure() + } + + #[inline] + fn is_empty(&self) -> bool { + self.base_len().is_zero() + } + + #[inline] + fn measure>(&self) -> M { + M::measure(self) + } } -pub trait Leaf: Debug + Sized { +pub trait Leaf: Debug { type BaseMetric: Metric; type Slice<'a>: LeafSlice<'a, Leaf = Self> @@ -31,13 +37,13 @@ pub trait Leaf: Debug + Sized { fn summarize(&self) -> Self::Summary; #[inline] - fn base_measure(&self) -> Self::BaseMetric { + fn base_len(&self) -> Self::BaseMetric { self.measure::() } #[inline] fn is_empty(&self) -> bool { - self.base_measure().is_zero() + self.base_len().is_zero() } #[inline] @@ -46,22 +52,22 @@ pub trait Leaf: Debug + Sized { } } -pub trait LeafSlice<'a>: Copy +pub trait LeafSlice<'a>: Copy + Debug where Self: 'a, { - type Leaf: Leaf = Self>; + type Leaf: Leaf = Self> + ?Sized; fn summarize(&self) -> ::Summary; #[inline] - fn base_measure(&self) -> ::BaseMetric { + fn base_len(&self) -> ::BaseMetric { self.measure() } #[inline] fn is_empty(&self) -> bool { - self.base_measure().is_zero() + self.base_len().is_zero() } #[inline] @@ -109,10 +115,10 @@ pub trait Metric: Debug + Copy + Ord - + Add - + Sub - + AddAssign - + SubAssign + + Add + + AddAssign + + Sub + + SubAssign { /// The identity element of this metric with respect to addition. /// @@ -120,10 +126,6 @@ pub trait Metric: /// it should hold `m == m + M::zero()`. fn zero() -> Self; - /// The smallest value larger than [`zero`](Self::zero()) this metric can - /// measure. - fn one() -> Self; - /// Returns the measure of the leaf's summary according to this metric. fn measure(summary: &S) -> Self; @@ -143,6 +145,18 @@ pub trait Metric: } } +/// Trait for metrics that can be converted from another metric. +pub trait FromMetric, S: Summary>: Metric { + fn measure_up_to(leaf: &S::Leaf, up_to: M) -> Self; +} + +impl> FromMetric for M { + #[inline] + fn measure_up_to(_: &S::Leaf, up_to: Self) -> Self { + up_to + } +} + /// Metrics that can be used to slice `Tree`s and `TreeSlice`s. pub trait SlicingMetric: Metric { fn slice_up_to<'a>(slice: L::Slice<'a>, up_to: Self) -> L::Slice<'a>; @@ -152,31 +166,35 @@ pub trait SlicingMetric: Metric { /// Allows iterating forward over the units of this metric. pub trait UnitMetric: Metric { + /// The smallest value larger than [`zero`](Metric::zero()) this metric can + /// measure. + fn one() -> Self; + /// Returns a `(first_slice, rest_slice, advance)` tuple, where `advance` - /// is equal to `first_slice`'s summary **plus** the summary of any + /// is equal to `first_slice`'s base length **plus** the length of any /// content between the end of `first_slice` and the start of `rest_slice` /// that's not included in either of them. /// /// It follows that if `slice == first_slice ++ rest_slice` (where `++` /// denotes concatenation), the `advance` should be equal to - /// `first_slice`'s summary. + /// `first_slice`'s base length. fn first_unit<'a>( slice: L::Slice<'a>, - ) -> (L::Slice<'a>, L::Slice<'a>, L::Summary); + ) -> (L::Slice<'a>, L::Slice<'a>, L::BaseMetric); } /// Allows iterating backward over the units of this metric. pub trait DoubleEndedUnitMetric: UnitMetric { /// Returns a `(rest_slice, last_slice, advance)` tuple, where `advance` is - /// equal to `last_slice`'s summary **plus** the summary of any content + /// equal to `last_slice`'s base length **plus** the length of any content /// between the end of `last_slice` and the end of the original `slice`. /// /// It follows that if `slice == rest_slice ++ last_slice` (where `++` /// denotes concatenation) the `advance` should be equal to `last_slice`'s - /// summary. + /// base length. fn last_unit<'a>( slice: L::Slice<'a>, - ) -> (L::Slice<'a>, L::Slice<'a>, L::Summary); + ) -> (L::Slice<'a>, L::Slice<'a>, L::BaseMetric); /// It's possible for a leaf slice to contain some content that extends /// past the end of its last `M`-unit. This is referred to as "the diff --git a/src/tree/tree.rs b/src/tree/tree.rs index 7aa3113..d9e3cf8 100644 --- a/src/tree/tree.rs +++ b/src/tree/tree.rs @@ -32,8 +32,8 @@ impl From> { #[inline] fn from(slice: TreeSlice<'_, ARITY, L>) -> Tree { - let root = if slice.base_measure() == slice.root().base_measure() { - // If the TreeSlice and its root have the same base measure it + let root = if slice.base_len() == slice.root().base_len() { + // If the TreeSlice and its root have the same base length it // means the TreeSlice spanned the whole Tree from which it was // created and we can simply clone the root. Arc::clone(slice.root()) @@ -83,21 +83,21 @@ impl Tree { } #[inline] - pub fn base_measure(&self) -> L::BaseMetric { + pub fn base_len(&self) -> L::BaseMetric { self.measure::() } - /// Returns the `M2`-measure of all the leaves before `up_to` plus the - /// `M2`-measure of the left sub-slice of the leaf at `up_to`. + /// Returns the M2-length of all the leaves before `up_to` plus the + /// M2-length of the left sub-slice of the leaf at `up_to`. #[track_caller] #[inline] - pub fn convert_measure(&self, up_to: M1) -> M2 + pub fn convert_len(&self, up_to: M1) -> M2 where - M1: SlicingMetric, - M2: Metric, + M1: Metric, + M2: FromMetric, { debug_assert!(up_to <= self.measure::()); - self.root.convert_measure(up_to) + self.root.convert_len(up_to) } /// Creates a new `Tree` from a sequence of leaves. @@ -130,16 +130,15 @@ impl Tree { Self { root: Arc::new(Node::Internal(root)) } } - /// Returns the leaf containing the `measure`-th unit of the `M`-metric, - /// plus the `M`-measure of all the leaves before it. + /// Returns the leaf at the offset, plus the M-length of all the leaves + /// before it. #[inline] - pub fn leaf_at_measure(&self, measure: M) -> (L::Slice<'_>, M) + pub fn leaf_at_offset(&self, offset: M) -> (&L, M) where M: Metric, { - debug_assert!(measure <= self.measure::() + M::one()); - - self.root.leaf_at_measure(measure) + debug_assert!(offset <= self.measure::()); + self.root.leaf_at_offset(offset) } /// Returns an iterator over the leaves of this `Tree`. @@ -148,14 +147,14 @@ impl Tree { Leaves::from(self) } - /// Returns the `M`-measure of this `Tree` obtaining by summing up the - /// `M`-measures of all its leaves. + /// Returns the M-length of this `Tree` obtaining by summing up the + /// M-lengths of all its leaves. #[inline] pub fn measure(&self) -> M where M: Metric, { - M::measure(&self.summary()) + self.root.measure::() } /// Replaces a range of the `Tree` with the given replacement. @@ -198,9 +197,24 @@ impl Tree { { debug_assert!(M::zero() <= range.start); debug_assert!(range.start <= range.end); - debug_assert!(range.end <= self.measure::() + M::one()); + debug_assert!(range.end <= self.measure::()); + + TreeSlice::slice_node(&self.root, range.start, range.end) + } + + /// Returns a slice of the `Tree` from the given offset to the end of the + /// tree. + #[track_caller] + #[inline] + pub fn slice_from(&self, start: M) -> TreeSlice<'_, ARITY, L> + where + M: SlicingMetric, + L::BaseMetric: SlicingMetric, + for<'d> L::Slice<'d>: Default, + { + debug_assert!(start <= self.measure::()); - TreeSlice::from_range_in_root(&self.root, range) + TreeSlice::slice_node(&self.root, start, self.base_len()) } #[inline] @@ -274,7 +288,7 @@ mod from_treeslice { /// Returns a `(root, invalid_first, invalid_last)` tuple where: /// /// - `root` is the internal node obtained by removing all the nodes before - /// `slice.before` and after `slice.before + slice.base_measure`, + /// `slice.before` and after `slice.before + slice.base_measure()`, /// /// - `invalid_{first,last}` are the number of invalid nodes contained in /// the subtrees of the first and last child, respectively. @@ -303,10 +317,10 @@ mod from_treeslice { // node. let mut children = slice.root().get_internal().children().iter(); - let start = L::BaseMetric::measure(&slice.offset); + let start = slice.offset; for child in children.by_ref() { - let this = child.base_measure(); + let this = child.base_len(); if offset + this > start { if start == L::BaseMetric::zero() { @@ -329,13 +343,13 @@ mod from_treeslice { } } - let end = start + slice.base_measure(); + let end = start + slice.base_len(); for child in children { - let this = child.base_measure(); + let this = child.base_len(); if offset + this >= end { - if end == slice.root().base_measure() { + if end == slice.root().base_len() { root.push(Arc::clone(child)); } else { let last = cut_end_rec( @@ -376,7 +390,7 @@ mod from_treeslice { let mut children = i.children().iter(); for child in children.by_ref() { - let this = child.base_measure(); + let this = child.base_len(); if offset + this > take_from { let first = cut_start_rec( @@ -440,7 +454,7 @@ mod from_treeslice { let mut offset = L::BaseMetric::zero(); for child in i.children() { - let this = child.base_measure(); + let this = child.base_len(); if offset + this >= take_up_to { let last = cut_end_rec( @@ -715,9 +729,9 @@ mod tree_replace { for (idx, child) in indexes.by_ref().map(|idx| (idx, inode.child(idx))) { - let child_measure = child.measure::(); + let child_len = child.measure::(); - offset += child_measure; + offset += child_len; if offset >= range.start { start_idx = idx; @@ -725,7 +739,7 @@ mod tree_replace { extra_leaves = inode.with_child_mut(start_idx, |child| { replace_nodes_in_start_subtree( Arc::make_mut(child), - range.start + child_measure - offset, + range.start + child_len - offset, replace_with, &mut start_should_rebalance, ) @@ -743,9 +757,9 @@ mod tree_replace { }); for (idx, child) in indexes.map(|idx| (idx, inode.child(idx))) { - let child_measure = child.measure::(); + let child_len = child.measure::(); - offset += child_measure; + offset += child_len; if offset >= range.end { end_idx = idx; @@ -753,7 +767,7 @@ mod tree_replace { inode.with_child_mut(end_idx, |child| { replace_nodes_in_end_subtree( Arc::make_mut(child), - range.end + child_measure - offset, + range.end + child_len - offset, &mut extra_leaves, &mut end_should_rebalance, ) @@ -816,7 +830,7 @@ mod tree_replace { }, }; - let (start_idx, offset) = inode.child_at_measure(replace_from); + let (start_idx, offset) = inode.child_at_offset(replace_from); let extra_leaves = inode.with_child_mut(start_idx, |child| { replace_nodes_in_start_subtree( @@ -896,9 +910,9 @@ mod tree_replace { let mut offset = inode.measure::(); for (idx, child) in inode.children().iter().enumerate().rev() { - let child_measure = child.measure::(); + let child_len = child.measure::(); - offset -= child_measure; + offset -= child_len; if offset < replace_up_to { end_idx = idx; @@ -1548,7 +1562,7 @@ mod tree_replace { #[cfg(test)] mod tests { - use core::ops::{Add, AddAssign, Sub, SubAssign}; + use core::ops::{AddAssign, SubAssign}; use super::*; @@ -1558,55 +1572,15 @@ mod tests { leaves: usize, } - impl Add for UsizeSummary { - type Output = Self; - - #[inline] - fn add(mut self, rhs: Self) -> Self { - self += &rhs; - self - } - } - - impl Add<&Self> for UsizeSummary { - type Output = Self; - - #[inline] - fn add(mut self, rhs: &Self) -> Self { - self += rhs; - self - } - } - - impl AddAssign<&Self> for UsizeSummary { - fn add_assign(&mut self, rhs: &Self) { + impl AddAssign for UsizeSummary { + fn add_assign(&mut self, rhs: Self) { self.count += rhs.count; self.leaves += rhs.leaves; } } - impl Sub for UsizeSummary { - type Output = Self; - - #[inline] - fn sub(mut self, rhs: Self) -> Self { - self -= &rhs; - self - } - } - - impl Sub<&Self> for UsizeSummary { - type Output = Self; - - #[inline] - fn sub(mut self, rhs: &Self) -> Self { - self -= rhs; - self - } - } - - impl SubAssign<&Self> for UsizeSummary { - fn sub_assign(&mut self, rhs: &Self) { + impl SubAssign for UsizeSummary { + fn sub_assign(&mut self, rhs: Self) { self.count -= rhs.count; self.leaves -= rhs.leaves; } @@ -1614,6 +1588,11 @@ mod tests { impl Summary for UsizeSummary { type Leaf = usize; + + #[inline] + fn empty() -> Self { + UsizeSummary { count: 0, leaves: 0 } + } } impl Leaf for usize { @@ -1651,10 +1630,6 @@ mod tests { 0 } - fn one() -> Self { - 1 - } - fn measure(summary: &UsizeSummary) -> Self { summary.leaves } diff --git a/src/tree/tree_slice.rs b/src/tree/tree_slice.rs index 62b861b..60254e0 100644 --- a/src/tree/tree_slice.rs +++ b/src/tree/tree_slice.rs @@ -9,9 +9,9 @@ pub struct TreeSlice<'a, const ARITY: usize, L: Leaf> { /// [`start_slice`](Self::start_slice) and [`end_slice`](Self::end_slice). pub(super) root: &'a Arc>, - /// The summary of the subtree under [`root`](Self::root) up to the start - /// of the [`start_slice`](Self::start_slice). - pub(super) offset: L::Summary, + /// The base length of the subtree under [`root`](Self::root) up to the + /// start of the [`start_slice`](Self::start_slice). + pub(super) offset: L::BaseMetric, /// The total summary of this slice. pub(crate) summary: L::Summary, @@ -34,11 +34,7 @@ pub enum SliceLeafCount { impl Clone for TreeSlice<'_, ARITY, L> { #[inline] fn clone(&self) -> Self { - TreeSlice { - offset: self.offset.clone(), - summary: self.summary.clone(), - ..*self - } + TreeSlice { summary: self.summary.clone(), ..*self } } } @@ -48,124 +44,86 @@ impl Copy for TreeSlice<'_, ARITY, L> where } impl<'a, const ARITY: usize, L: Leaf> TreeSlice<'a, ARITY, L> { - /* - Public methods - */ - - #[doc(hidden)] - pub fn assert_invariants(&self) { - match &**self.root { - Node::Internal(_) => { - assert!(self.leaf_count() > 1); - assert!(!self.start_slice.is_empty()); - assert!(!self.end_slice.is_empty()); - - if self.leaf_count() == 2 { - assert_eq!( - self.summary, - self.start_summary() + &self.end_summary() - ); - } - - // This last part checks that the first and last slices are - // under different children of the root, making the latter the - // deepest node that contains both. - - let (root, remove_offset) = { - let start = L::BaseMetric::measure(&self.offset); - deepest_node_containing_base_range( - self.root, - start, - start + L::BaseMetric::measure(&self.summary), - ) - }; - - // These asserts should be equivalent but we use them all for - // redundancy. - - assert!(Arc::ptr_eq(self.root, root)); - assert_eq!(self.root.depth(), root.depth()); - assert_eq!( - L::BaseMetric::measure(&remove_offset), - L::BaseMetric::zero() - ); - }, - - Node::Leaf(leaf) => { - assert_eq!(self.leaf_count(), 1); - assert!(leaf.base_measure() >= self.base_measure()); - }, - } - } - #[inline] - pub fn base_measure(&self) -> L::BaseMetric { + pub fn base_len(&self) -> L::BaseMetric { self.measure::() } - /// Returns the `M2`-measure of all the leaves before `up_to` plus the - /// `M2`-measure of the left sub-slice of the leaf at `up_to`. + /// Returns the M-length of all the leaves before the given offset, plus + /// the M-length of the left sub-slice of the leaf at the given offset. #[inline] - pub fn convert_measure(&self, up_to: M1) -> M2 + pub fn convert_len_from_base(&self, base_offset: L::BaseMetric) -> M where - M1: SlicingMetric, - M2: Metric, + M: FromMetric, { - debug_assert!(up_to <= self.measure::()); + debug_assert!(base_offset <= self.base_len()); - if up_to == M1::zero() { - M2::zero() + if base_offset.is_zero() { + M::zero() } else { - self.root - .convert_measure::(M1::measure(&self.offset) + up_to) - - M2::measure(&self.offset) + self.root.convert_len::<_, M>(self.offset + base_offset) + - self.measure_offset::() } } + /// Returns the base length of all the leaves before the given offset, + /// plus the base length of the left sub-slice of the leaf at the given + /// offset. #[inline] - pub fn end_slice(&self) -> L::Slice<'a> { - self.end_slice + pub fn convert_len_to_base(&self, offset: M) -> L::BaseMetric + where + M: FromMetric, + L::BaseMetric: FromMetric, + { + debug_assert!(offset <= self.measure::()); + + if offset.is_zero() { + L::BaseMetric::zero() + } else { + let m_offset = self.measure_offset::(); + self.root.convert_len::<_, L::BaseMetric>(m_offset + offset) + - self.offset + } } #[inline] - pub fn end_summary(&self) -> L::Summary { - self.end_slice.summarize() + pub fn end_slice(&self) -> L::Slice<'a> { + self.end_slice } - /// Returns the leaf containing the `measure`-th unit of the `M`-metric, - /// plus the `M`-measure of all the leaves before it. + /// Returns the leaf at the given M-offset, plus the M-length of all the + /// leaves before it. #[inline] - pub fn leaf_at_measure(&self, measure: M) -> (L::Slice<'a>, M) + pub fn leaf_at_offset(&self, offset: M) -> (L::Slice<'a>, M) where - M: Metric, + M: Metric + FromMetric, { - debug_assert!(measure <= self.measure::() + M::one()); + debug_assert!(offset <= self.measure::()); - if M::measure(&self.start_summary()) >= measure { - (self.start_slice, M::zero()) - } else { - let all_minus_last = - M::measure(&self.summary) - M::measure(&self.end_summary()); - - if all_minus_last >= measure { - let (leaf, mut offset) = self - .root - .leaf_at_measure(M::measure(&self.offset) + measure); - offset -= M::measure(&self.offset); - (leaf, offset) - } else { - (self.end_slice, all_minus_last) - } + let len_start_slice = self.start_slice.measure::(); + + if offset <= len_start_slice { + return (self.start_slice, M::zero()); } + + let len_total_minus_end = + self.measure::() - self.end_slice.measure::(); + + if len_total_minus_end < offset { + return (self.end_slice, len_total_minus_end); + } + + let m_offset = self.measure_offset::(); + let (leaf, leaf_offset) = self.root.leaf_at_offset(m_offset + offset); + (leaf.as_slice(), leaf_offset - m_offset) } #[inline] pub fn leaf_count(&self) -> SliceLeafCount { if self.root.is_leaf() { SliceLeafCount::One - } else if self.start_slice.base_measure() - + self.end_slice.base_measure() - == self.base_measure() + } else if self.start_slice.base_len() + self.end_slice.base_len() + == self.base_len() { SliceLeafCount::Two } else { @@ -183,27 +141,79 @@ impl<'a, const ARITY: usize, L: Leaf> TreeSlice<'a, ARITY, L> { where M: Metric, { - M::measure(self.summary()) + self.summary.measure::() } #[inline] - pub(super) fn root(&self) -> &'a Arc> { - self.root + pub fn start_slice(&self) -> L::Slice<'a> { + self.start_slice } #[inline] - pub fn start_slice(&self) -> L::Slice<'a> { - self.start_slice + pub fn summary(&self) -> &L::Summary { + &self.summary } #[inline] - pub fn start_summary(&self) -> L::Summary { - self.start_slice.summarize() + pub(super) fn root(&self) -> &'a Arc> { + self.root } + #[doc(hidden)] + pub fn assert_invariants(&self) { + match &**self.root { + Node::Internal(_) => { + assert!(self.leaf_count() > 1); + assert!(!self.start_slice.is_empty()); + assert!(!self.end_slice.is_empty()); + + if self.leaf_count() == 2 { + assert_eq!( + self.summary.base_len(), + self.start_slice.base_len() + + self.end_slice.base_len() + ); + } + + // This last part checks that the first and last slices are + // under different children of the root, making the latter the + // deepest node that contains both. + + let (root, remove_offset) = { + let start = self.offset; + deepest_node_containing_base_range( + self.root, + start, + start + self.summary.base_len(), + ) + }; + + // These asserts should be equivalent but we use them all for + // redundancy. + + assert!(Arc::ptr_eq(self.root, root)); + assert_eq!(self.root.depth(), root.depth()); + assert!(remove_offset.is_zero()); + }, + + Node::Leaf(leaf) => { + assert_eq!(self.leaf_count(), 1); + assert!(leaf.base_len() >= self.base_len()); + }, + } + } + + /// Returns the `M`-length of the subtree under [`root`](Self::root) up to + /// the start of the [`start_slice`](Self::start_slice). + /// + /// Note that it's never necessary to call this with `L::BaseMetric`, as + /// that's already known to be [`Self::offset`]. #[inline] - pub fn summary(&self) -> &L::Summary { - &self.summary + fn measure_offset(&self) -> M + where + M: FromMetric, + { + self.root.convert_len(self.offset) } } @@ -213,75 +223,40 @@ where { #[track_caller] #[inline] - pub(super) fn from_range_in_root( - root: &'a Arc>, - range: Range, - ) -> Self + pub fn slice(self, range: Range) -> Self where - M: SlicingMetric, - L::BaseMetric: SlicingMetric, + M: SlicingMetric + FromMetric, + L::BaseMetric: SlicingMetric + FromMetric, { debug_assert!(M::zero() <= range.start); debug_assert!(range.start <= range.end); - debug_assert!(range.end <= root.measure::() + M::one()); + debug_assert!(range.end <= self.measure::()); - if range.end <= root.measure::() { - Self::slice_impl(root, range.start, range.end) - } else if range.start <= root.measure::() { - Self::slice_impl(root, range.start, root.base_measure()) - } else { - Self::slice_impl(root, root.base_measure(), root.base_measure()) - } + let start = self.offset + self.convert_len_to_base(range.start); + let end = self.measure_offset::() + range.end; + Self::slice_node(self.root, start, end) } #[track_caller] #[inline] - pub fn slice(self, mut range: Range) -> Self + pub fn slice_from(self, start: M) -> Self where - M: SlicingMetric, - L::BaseMetric: SlicingMetric, + M: SlicingMetric + FromMetric, + L::BaseMetric: SlicingMetric + FromMetric, { - debug_assert!(M::zero() <= range.start); - debug_assert!(range.start <= range.end); - debug_assert!(range.end <= self.measure::() + M::one()); - - match ( - range.start > M::zero(), - range.end < self.measure::() + M::one(), - ) { - (true, true) => { - range.start += M::measure(&self.offset); - range.end += M::measure(&self.offset); - Self::from_range_in_root(self.root, range) - }, - - (true, false) if range.start < self.measure::() + M::one() => { - let start = M::measure(&self.offset) + range.start; - let end = - L::BaseMetric::measure(&self.offset) + self.base_measure(); - Self::slice_impl(self.root, start, end) - }, - - (true, false) => { - let start = - L::BaseMetric::measure(&self.offset) + self.base_measure(); - let end = start; - Self::slice_impl(self.root, start, end) - }, - - (false, true) if range.end > M::zero() => { - let start = L::BaseMetric::measure(&self.offset); - let end = M::measure(&self.offset) + range.end; - Self::slice_impl(self.root, start, end) - }, + debug_assert!(start <= self.measure::()); - (false, true) => { - let start = L::BaseMetric::measure(&self.offset); - Self::slice_impl(self.root, start, start) - }, + let start = self.offset + self.convert_len_to_base(start); + let end = self.offset + self.base_len(); + Self::slice_node(self.root, start, end) + } - (false, false) => self, - } + #[inline] + pub fn units(&self) -> Units<'a, ARITY, L, M> + where + M: Metric, + { + Units::from(self) } /// Returns the `TreeSlice` obtained by slicing `root` between `start` and @@ -296,7 +271,7 @@ where /// condition is not met. #[track_caller] #[inline] - fn slice_impl( + pub(super) fn slice_node( root: &'a Arc>, start: S, end: E, @@ -313,8 +288,8 @@ where let mut slice = Self { root, - offset: L::Summary::default(), - summary: L::Summary::default(), + offset: L::BaseMetric::zero(), + summary: L::Summary::empty(), start_slice: Default::default(), end_slice: Default::default(), }; @@ -326,34 +301,28 @@ where root, start, end, + &mut S::zero(), + &mut E::zero(), &mut recompute_root, &mut false, &mut false, ); if recompute_root { - let start = L::BaseMetric::measure(&slice.offset); + let start = slice.offset; let (root, offset) = deepest_node_containing_base_range( slice.root, start, - start + L::BaseMetric::measure(&slice.summary), + start + slice.summary.base_len(), ); slice.root = root; - slice.offset -= &offset; + slice.offset -= offset; } slice } - - #[inline] - pub fn units(&self) -> Units<'a, ARITY, L, M> - where - M: Metric, - { - Units::from(self) - } } impl PartialEq for SliceLeafCount { @@ -402,30 +371,30 @@ where 'outer: loop { match &**node { Node::Internal(inode) => { - let mut measured = L::Summary::default(); + let mut offset = L::Summary::empty(); for child in inode.children() { let child_summary = child.summary(); - let contains_start_slice = S::measure(&measured) - + S::measure(&child_summary) + let contains_start_slice = offset.measure::() + + child_summary.measure::() >= start; if contains_start_slice { - let contains_end_slice = E::measure(&measured) - + E::measure(&child_summary) + let contains_end_slice = offset.measure::() + + child_summary.measure::() >= end; if contains_end_slice { node = child; - start -= S::measure(&measured); - end -= E::measure(&measured); + start -= offset.measure::(); + end -= offset.measure::(); continue 'outer; } else { return (node, start, end); } } else { - measured += &child_summary; + offset += child_summary; } } @@ -438,53 +407,47 @@ where } /// Same as [`deepest_node_containing_range`] except it only accepts base -/// measures and thus can check whether a node contains `start` using `>` +/// lengths and thus can check whether a node contains `start` using `>` /// instead of `>=` (because the remainder of a slice divided by the BaseMetric /// should always be zero), resulting in a potentially deeper node than the one /// returned by [`deepest_node_containing_range`]. /// -/// Also returns the summary between the input `node` and the returned node. +/// Also returns the base length between the input `node` and the returned node. #[inline] pub(super) fn deepest_node_containing_base_range( mut node: &Arc>, mut start: L::BaseMetric, mut end: L::BaseMetric, -) -> (&Arc>, L::Summary) +) -> (&Arc>, L::BaseMetric) where L: Leaf, { - let mut offset = L::Summary::default(); + let mut offset = L::BaseMetric::zero(); 'outer: loop { match &**node { Node::Internal(inode) => { - let mut measured = L::Summary::default(); + let mut measured = L::BaseMetric::zero(); for child in inode.children() { - let child_summary = child.summary(); + let child_len = child.base_len(); - let contains_start_slice = - L::BaseMetric::measure(&measured) - + L::BaseMetric::measure(&child_summary) - > start; + let contains_start_slice = measured + child_len > start; if contains_start_slice { - let contains_end_slice = - L::BaseMetric::measure(&measured) - + L::BaseMetric::measure(&child_summary) - >= end; + let contains_end_slice = measured + child_len >= end; if contains_end_slice { node = child; - start -= L::BaseMetric::measure(&measured); - end -= L::BaseMetric::measure(&measured); - offset += &measured; + start -= measured; + end -= measured; + offset += measured; continue 'outer; } else { return (node, offset); } } else { - measured += &child_summary; + measured += child_len; } } @@ -516,11 +479,14 @@ where /// the other fields of the slice are valid. #[track_caller] #[inline] +#[allow(clippy::too_many_arguments)] fn build_slice<'a, const N: usize, L, S, E>( slice: &mut TreeSlice<'a, N, L>, node: &'a Arc>, start: S, end: E, + start_offset: &mut S, + end_offset: &mut E, recompute_root: &mut bool, found_start_slice: &mut bool, done: &mut bool, @@ -541,9 +507,7 @@ fn build_slice<'a, const N: usize, L, S, E>( let child_summary = child.summary(); if !*found_start_slice { - if S::measure(&slice.offset) + S::measure(&child_summary) - >= start - { + if *start_offset + child_summary.measure::() >= start { // This child contains the starting slice somewhere in // its subtree. Run this function again with this child // as the node. @@ -552,20 +516,24 @@ fn build_slice<'a, const N: usize, L, S, E>( child, start, end, + start_offset, + end_offset, recompute_root, found_start_slice, done, ); } else { // This child comes before the starting leaf. - slice.offset += &child_summary; + slice.offset += child_summary.base_len(); + *start_offset += child_summary.measure::(); + *end_offset += child_summary.measure::(); } - } else if E::measure(&slice.offset) - + E::measure(&slice.summary) - + E::measure(&child_summary) + } else if *end_offset + + slice.summary.measure::() + + child_summary.measure::() >= end { - // This child contains the ending leaf somewhere in its + // This child contains the ending slice somewhere in its // subtree. Run this function again with this child as the // node. build_slice( @@ -573,14 +541,16 @@ fn build_slice<'a, const N: usize, L, S, E>( child, start, end, + start_offset, + end_offset, recompute_root, found_start_slice, done, ); } else { - // This is a node fully contained between the starting and + // This node is fully contained between the starting and // the ending slices. - slice.summary += &child_summary; + slice.summary += child_summary; } } }, @@ -591,38 +561,38 @@ fn build_slice<'a, const N: usize, L, S, E>( // This leaf must contain either the first slice, the last slice or // both. - let contains_end_slice = E::measure(&slice.offset) - + E::measure(&slice.summary) - + E::measure(&leaf_summary) + let contains_end_slice = *end_offset + + slice.summary.measure::() + + leaf_summary.measure::() >= end; if !*found_start_slice { - debug_assert_eq!(L::Summary::default(), slice.summary); + debug_assert!(slice.summary.is_empty()); debug_assert!({ // If we haven't yet found the first slice this leaf must // contain it. - S::measure(&slice.offset) + S::measure(&leaf_summary) - >= start + *start_offset + leaf_summary.measure::() >= start }); if contains_end_slice { // The end of the range is also contained in this leaf // so the final slice only spans this single leaf. - let start = start - S::measure(&slice.offset); + let start = start - *start_offset; let right_slice = S::slice_from(leaf.as_slice(), start); - let left_summary = - leaf.summarize() - &right_slice.summarize(); + let left_slice_end_measure = + leaf.measure::() - right_slice.measure::(); - let end = end - - E::measure(&slice.offset) - - E::measure(&left_summary); + let left_slice_base_measure = + leaf.base_len() - right_slice.base_len(); + + let end = end - *end_offset - left_slice_end_measure; let start_slice = E::slice_up_to(right_slice, end); - slice.offset += &left_summary; + slice.offset += left_slice_base_measure; slice.summary = start_slice.summarize(); slice.start_slice = start_slice; slice.end_slice = start_slice; @@ -630,40 +600,38 @@ fn build_slice<'a, const N: usize, L, S, E>( *done = true; } else { // This leaf contains the first slice but not the last. - let start_slice = S::slice_from( - leaf.as_slice(), - start - S::measure(&slice.offset), - ); - - let start_summary = start_slice.summarize(); - - let right_summary = leaf.summarize() - &start_summary; + let start_slice = + S::slice_from(leaf.as_slice(), start - *start_offset); if start_slice.is_empty() { - slice.offset += &leaf.summarize(); + slice.offset += leaf.base_len(); + *start_offset += leaf.measure::(); + *end_offset += leaf.measure::(); *recompute_root = true; return; } - slice.offset += &right_summary; - slice.summary += &start_summary; - slice.start_slice = start_slice; + let start_summary = start_slice.summarize(); + slice.offset += leaf.base_len() - start_summary.base_len(); + *end_offset += + leaf.measure::() - start_summary.measure::(); + + slice.summary += start_summary; + slice.start_slice = start_slice; *found_start_slice = true; } } else { debug_assert!(contains_end_slice); - let end = end - - E::measure(&slice.offset) - - E::measure(&slice.summary); + let end = end - *end_offset - slice.summary.measure::(); // This leaf contains the last slice. let end_slice = E::slice_up_to(leaf.as_slice(), end); debug_assert!(!end_slice.is_empty()); - slice.summary += &end_slice.summarize(); + slice.summary += end_slice.summarize(); slice.end_slice = end_slice; *done = true; diff --git a/src/tree/units.rs b/src/tree/units.rs index 9f1861b..69fe594 100644 --- a/src/tree/units.rs +++ b/src/tree/units.rs @@ -5,6 +5,7 @@ use super::traits::{ Leaf, LeafSlice, Metric, + Summary, UnitMetric, }; use super::tree_slice; @@ -21,7 +22,7 @@ use super::{Arc, Node, Tree, TreeSlice}; // other, which could cause them to overlap if alternating between calling // `Units::next()` and `Units::next_back()`. // -// To prevent this we also store the base measure of the unyielded iterating +// To prevent this we also store the base length of the unyielded iterating // range, which is decreased as new `TreeSliece`s are yielded (both forward and // backward). Once that reaches zero this iterator will stop yielding any more // items. @@ -33,7 +34,7 @@ pub struct Units<'a, const ARITY: usize, L: Leaf, M: Metric> { /// Iterates over the `M`-units from back to front. backward: UnitsBackward<'a, ARITY, L, M>, - /// The base measure of all the `TreeSlice`s which are yet to be yielded. + /// The base length of all the `TreeSlice`s which are yet to be yielded. remaining: L::BaseMetric, } @@ -47,7 +48,7 @@ where Self { forward: UnitsForward::from(tree), backward: UnitsBackward::from(tree), - remaining: tree.base_measure(), + remaining: tree.base_len(), } } } @@ -62,7 +63,7 @@ where Self { forward: UnitsForward::from(tree_slice), backward: UnitsBackward::from(tree_slice), - remaining: tree_slice.base_measure(), + remaining: tree_slice.base_len(), } } } @@ -77,18 +78,18 @@ impl<'a, const ARITY: usize, L: Leaf, M: UnitMetric> Iterator /// /// The advance describes how much of the iterating range has been yielded /// by returning this `TreeSlice`, and it's always bigger than or equal to - /// the base measure of the slice. + /// the base length of the slice. /// /// To give an example let's consider the string "foo\nbar\nbaz". /// /// The `RawLineMetric` would first yield "foo\n", then "bar\n", and /// finally "baz". In this case the advance is always equal to the base - /// measure of the slice. + /// length of the slice. /// /// On the other hand, the `LineMetric` would first yield "foo" without /// including the trailing newline, then "bar" and lastly "baz". In the /// first and second calls the advance is 1 byte longer than the byte - /// measure of the slice to account for the newlines, which are not part of + /// length of the slice to account for the newlines, which are not part of /// the returned slices. /// /// The name is taken from [typography][1], where the advance of a glyph is @@ -113,31 +114,24 @@ impl<'a, const ARITY: usize, L: Leaf, M: UnitMetric> Iterator let (tree_slice, advance) = if iter.start_slice.measure::() > M::zero() { iter.next_unit_in_leaf() - } else if iter.units_total > iter.units_yielded { + } else if iter.units_yielded < iter.units_total { iter.next_unit_in_range() } else if iter.base_total > iter.base_yielded { let (remainder, advance) = iter.remainder(); - debug_assert_eq!(M::measure(&advance), M::zero()); - - debug_assert_eq!( - L::BaseMetric::measure(&advance), - iter.base_total - iter.base_yielded - ); + debug_assert_eq!(advance, iter.base_total - iter.base_yielded); iter.base_yielded = iter.base_total; - return Some((remainder, L::BaseMetric::measure(&advance))); + return Some((remainder, advance)); } else { return None; }; - debug_assert_eq!(M::measure(&advance), M::one()); - - iter.base_yielded += L::BaseMetric::measure(&advance); + iter.base_yielded += advance; iter.units_yielded += M::one(); - Some((tree_slice, L::BaseMetric::measure(&advance))) + Some((tree_slice, advance)) } } @@ -157,14 +151,8 @@ impl> if iter.base_remaining > L::BaseMetric::zero() { if let Some((remainder, advance)) = iter.remainder() { - debug_assert_eq!(M::measure(&advance), M::zero()); - - iter.base_remaining -= L::BaseMetric::measure(&advance); - - return Some(( - remainder, - L::BaseMetric::measure(&advance), - )); + iter.base_remaining -= advance; + return Some((remainder, advance)); } } } @@ -181,12 +169,10 @@ impl> return None; }; - debug_assert_eq!(M::measure(&advance), M::one()); - - iter.base_remaining -= L::BaseMetric::measure(&advance); + iter.base_remaining -= advance; iter.units_remaining -= M::one(); - Some((tree_slice, L::BaseMetric::measure(&advance))) + Some((tree_slice, advance)) } } @@ -209,8 +195,8 @@ struct UnitsForward<'a, const N: usize, L: Leaf, M: Metric> { /// The current leaf node. leaf_node: &'a Arc>, - /// How much of `leaf_node`'s summary has already been yielded. - yielded_in_leaf: L::Summary, + /// How much of `leaf_node`'s base length has already been yielded. + yielded_in_leaf: L::BaseMetric, /// The `start_slice` field of the next `TreeSlice` that'll be returned by /// [`next`](Self::next()). @@ -227,16 +213,16 @@ struct UnitsForward<'a, const N: usize, L: Leaf, M: Metric> { /// The start of the yielding range as an offset into the root. base_start: L::BaseMetric, - /// The base measure of all the advances yielded so far. + /// The base length of all the advances yielded so far. base_yielded: L::BaseMetric, - /// The total base measure of the iterating range (doesn't change). + /// The total base length of the iterating range (doesn't change). base_total: L::BaseMetric, /// The `M`-units yielded so far. units_yielded: M, - /// The total `M`-measure of the iterating range (doesn't change). + /// The total `M`-length of the iterating range (doesn't change). units_total: M, } @@ -245,11 +231,7 @@ impl> Clone { #[inline] fn clone(&self) -> Self { - Self { - path: self.path.clone(), - yielded_in_leaf: self.yielded_in_leaf.clone(), - ..*self - } + Self { path: self.path.clone(), ..*self } } } @@ -264,13 +246,13 @@ where is_initialized: false, path: Vec::with_capacity(tree.root().depth()), leaf_node: tree.root(), - yielded_in_leaf: L::Summary::default(), + yielded_in_leaf: L::BaseMetric::zero(), start_slice: L::Slice::default(), first_slice: None, last_slice: None, base_start: L::BaseMetric::zero(), base_yielded: L::BaseMetric::zero(), - base_total: tree.base_measure(), + base_total: tree.base_len(), units_yielded: M::zero(), units_total: tree.measure::(), } @@ -290,13 +272,13 @@ where is_initialized: false, path: Vec::with_capacity(tree_slice.root().depth()), leaf_node: tree_slice.root(), - yielded_in_leaf: L::Summary::default(), + yielded_in_leaf: L::BaseMetric::zero(), start_slice: L::Slice::default(), first_slice: Some(tree_slice.start_slice), last_slice: Some(tree_slice.end_slice), - base_start: L::BaseMetric::measure(&tree_slice.offset), + base_start: tree_slice.offset, base_yielded: L::BaseMetric::zero(), - base_total: tree_slice.base_measure(), + base_total: tree_slice.base_len(), units_yielded: M::zero(), units_total: tree_slice.measure::(), } @@ -323,14 +305,14 @@ impl<'a, const N: usize, L: Leaf, M: UnitMetric> UnitsForward<'a, N, L, M> { match &**node { Node::Internal(inode) => { for (idx, child) in inode.children().iter().enumerate() { - let child_measure = child.base_measure(); + let child_len = child.base_len(); - if offset + child_measure > self.base_start { + if offset + child_len > self.base_start { self.path.push((node, idx)); node = child; continue 'outer; } else { - offset += child_measure; + offset += child_len; } } @@ -343,7 +325,7 @@ impl<'a, const N: usize, L: Leaf, M: UnitMetric> UnitsForward<'a, N, L, M> { match self.first_slice.take() { Some(slice) => { self.yielded_in_leaf = - leaf.summarize() - &slice.summarize(); + leaf.base_len() - slice.base_len(); self.start_slice = slice; }, @@ -393,8 +375,8 @@ impl<'a, const N: usize, L: Leaf, M: UnitMetric> UnitsForward<'a, N, L, M> { Node::Leaf(leaf) => { self.leaf_node = node; - let contains_last_slice = leaf.base_measure() - > self.base_total - self.base_yielded; + let contains_last_slice = + leaf.base_len() > self.base_total - self.base_yielded; return if contains_last_slice { self.last_slice.take().unwrap() @@ -407,18 +389,18 @@ impl<'a, const N: usize, L: Leaf, M: UnitMetric> UnitsForward<'a, N, L, M> { } /// Yields the next unit in the current `self.leaf_node`. This function - /// should only be called when `self.start_slice` has an `M`-measure of at + /// should only be called when `self.start_slice` has an `M`-length of at /// least `M::one()`. #[inline] - fn next_unit_in_leaf(&mut self) -> (TreeSlice<'a, N, L>, L::Summary) { + fn next_unit_in_leaf(&mut self) -> (TreeSlice<'a, N, L>, L::BaseMetric) { debug_assert_ne!(self.start_slice.measure::(), M::zero()); debug_assert!(self.units_total > self.units_yielded); let (slice, rest, advance) = M::first_unit(self.start_slice); - let offset = self.yielded_in_leaf.clone(); + let offset = self.yielded_in_leaf; - self.yielded_in_leaf += &advance; + self.yielded_in_leaf += advance; self.start_slice = rest; ( @@ -434,7 +416,7 @@ impl<'a, const N: usize, L: Leaf, M: UnitMetric> UnitsForward<'a, N, L, M> { } /// Traverses the path to reach the next leaf node with a non-zero - /// `M`-measure. + /// `M`-length. /// /// Returns a `(leaf, root, before, summary)` tuple where: /// @@ -443,10 +425,10 @@ impl<'a, const N: usize, L: Leaf, M: UnitMetric> UnitsForward<'a, N, L, M> { /// - `root` is the deepest internal node containing both the current /// `self.leaf_node` and `leaf` in its subtree; /// - /// - `before` is the total base measure of all the nodes from the first + /// - `before` is the total base length of all the nodes from the first /// leaf in `root`'s subtree to the leaf preceding the current /// `self.leaf_node`. If `self.leaf_node` is the first leaf in `root`'s - /// subtree this measure will be zero; + /// subtree this will be zero; /// /// - `summary` is the total summary of all the nodes between (but not /// including) `self.leaf_node` and `leaf`. If `leaf` is the leaf node @@ -463,11 +445,11 @@ impl<'a, const N: usize, L: Leaf, M: UnitMetric> UnitsForward<'a, N, L, M> { #[inline] fn next_leaf_with_measure( &mut self, - ) -> (&'a L, &'a Arc>, L::Summary, L::Summary) { + ) -> (&'a L, &'a Arc>, L::BaseMetric, L::Summary) { debug_assert!(self.units_total > self.units_yielded); - let mut before = L::Summary::default(); - let mut summary = L::Summary::default(); + let mut before = L::BaseMetric::zero(); + let mut summary = L::Summary::empty(); // Step 1: pop nodes off the path until we find a node with some // `M`-units that we haven't yielded yet. @@ -479,7 +461,7 @@ impl<'a, const N: usize, L: Leaf, M: UnitMetric> UnitsForward<'a, N, L, M> { let inode = node.get_internal(); for child in &inode.children()[..child_idx] { - before += &child.summary(); + before += child.base_len(); } for (idx, child) in @@ -489,7 +471,7 @@ impl<'a, const N: usize, L: Leaf, M: UnitMetric> UnitsForward<'a, N, L, M> { self.path.push((node, child_idx + 1 + idx)); break 'outer; } else { - summary += &child.summary(); + summary += child.summary(); } } } @@ -497,7 +479,7 @@ impl<'a, const N: usize, L: Leaf, M: UnitMetric> UnitsForward<'a, N, L, M> { let &(inode, child_idx) = self.path.last().unwrap(); // Step 2: push nodes on the path until we get to the first leaf node - // with a positive `M`-measure. Once we get there we're done. + // with a positive `M`-length. Once we get there we're done. // Every node in the path is an internal node. let mut node = inode.get_internal().child(child_idx); @@ -511,7 +493,7 @@ impl<'a, const N: usize, L: Leaf, M: UnitMetric> UnitsForward<'a, N, L, M> { node = child; continue 'outer; } else { - summary += &child.summary(); + summary += child.summary(); } } @@ -565,7 +547,7 @@ impl<'a, const N: usize, L: Leaf, M: UnitMetric> UnitsForward<'a, N, L, M> { /// when the `TreeSlice` is not totally contained in `self.leaf_node` and /// it's not the remainder. #[inline] - fn next_unit_in_range(&mut self) -> (TreeSlice<'a, N, L>, L::Summary) { + fn next_unit_in_range(&mut self) -> (TreeSlice<'a, N, L>, L::BaseMetric) { debug_assert_eq!(self.start_slice.measure::(), M::zero()); debug_assert!(self.units_total > self.units_yielded); @@ -573,7 +555,7 @@ impl<'a, const N: usize, L: Leaf, M: UnitMetric> UnitsForward<'a, N, L, M> { // slice empty. If it is we move to the next leaf before continuing. if self.start_slice.is_empty() { let leaf_slice = self.next_leaf(); - self.yielded_in_leaf = L::Summary::default(); + self.yielded_in_leaf = L::BaseMetric::zero(); self.start_slice = leaf_slice; if self.start_slice.measure::() > M::zero() { @@ -588,16 +570,15 @@ impl<'a, const N: usize, L: Leaf, M: UnitMetric> UnitsForward<'a, N, L, M> { self.next_leaf_with_measure(); let is_immediately_after = - L::BaseMetric::measure(&summary) == L::BaseMetric::zero(); + summary.measure::().is_zero(); - offset += &self.yielded_in_leaf; - summary += &start_summary; + offset += self.yielded_in_leaf; + summary += start_summary; let slice = { - let contains_last_slice = self.base_yielded - + L::BaseMetric::measure(&summary) - + leaf.base_measure() - > self.base_total; + let contains_last_slice = + self.base_yielded + summary.base_len() + leaf.base_len() + > self.base_total; if contains_last_slice { self.last_slice.take().unwrap() @@ -608,13 +589,13 @@ impl<'a, const N: usize, L: Leaf, M: UnitMetric> UnitsForward<'a, N, L, M> { let (mut end_slice, rest, mut advance) = M::first_unit(slice); - self.yielded_in_leaf = advance.clone(); + self.yielded_in_leaf = advance; self.start_slice = rest; - advance += &summary; + advance += summary.base_len(); if !end_slice.is_empty() { - summary += &end_slice.summarize(); + summary += end_slice.summarize(); } // This edge case can happen when the first unit of `slice` is empty. // @@ -627,21 +608,21 @@ impl<'a, const N: usize, L: Leaf, M: UnitMetric> UnitsForward<'a, N, L, M> { if is_immediately_after { root = previous_leaf; - offset = root.summary() - &summary; + offset = root.base_len() - summary.base_len(); end_slice = start_slice; } else { - let start = L::BaseMetric::measure(&offset); + let start = offset; let (new_root, remove_offset) = tree_slice::deepest_node_containing_base_range( root, start, - start + L::BaseMetric::measure(&summary), + start + summary.base_len(), ); root = new_root; - offset -= &remove_offset; + offset -= remove_offset; // `previous_leaf` is guaranteed to be a leaf node by // `Self::previous_leaf()`. @@ -656,7 +637,7 @@ impl<'a, const N: usize, L: Leaf, M: UnitMetric> UnitsForward<'a, N, L, M> { /// Very similar to [`next_leaf_with_measure`](1), except it doesn't /// mutate any state and instead of returning the next leaf node with a - /// non-zero `M`-measure it returns the leaf node containing + /// non-zero `M`-length it returns the leaf node containing /// [`last_slice`](2), or the last leaf node in the root if that's not set. /// /// NOTE: it assumes that that leaf node is different from the current @@ -669,7 +650,7 @@ impl<'a, const N: usize, L: Leaf, M: UnitMetric> UnitsForward<'a, N, L, M> { #[inline] fn last_leaf( &self, - ) -> (&'a L, &'a Arc>, L::Summary, L::Summary) { + ) -> (&'a L, &'a Arc>, L::BaseMetric, L::Summary) { // Step 1: find the index of deepest node in the path that fully // contains `range`. @@ -688,20 +669,20 @@ impl<'a, const N: usize, L: Leaf, M: UnitMetric> UnitsForward<'a, N, L, M> { let mut measured = L::BaseMetric::zero(); for child in &inode.children()[..child_idx] { - measured += child.base_measure(); + measured += child.base_len(); } for child in &inode.children()[child_idx..] { - let child_measure = child.base_measure(); + let child_len = child.base_len(); if measured <= range.start - && measured + child_measure >= range.end + && measured + child_len >= range.end { range.start -= measured; range.end -= measured; continue 'outer; } else { - measured += child_measure; + measured += child_len; } } @@ -718,19 +699,19 @@ impl<'a, const N: usize, L: Leaf, M: UnitMetric> UnitsForward<'a, N, L, M> { // Step 2: traverse down the path starting from the node after the // root, increasing `before` and `summary` as you go. - let mut before = L::Summary::default(); - let mut summary = L::Summary::default(); + let mut before = L::BaseMetric::zero(); + let mut summary = L::Summary::empty(); for &(node, child_idx) in &self.path[root_idx + 1..] { // Every node in the path is an internal node. let inode = node.get_internal(); for child in &inode.children()[..child_idx] { - before += &child.summary(); + before += child.base_len(); } for child in &inode.children()[child_idx + 1..] { - summary += &child.summary(); + summary += child.summary(); } } @@ -742,26 +723,25 @@ impl<'a, const N: usize, L: Leaf, M: UnitMetric> UnitsForward<'a, N, L, M> { let mut offset = L::BaseMetric::zero(); for child in &inode.children()[..child_idx] { - let child_summary = child.summary(); - offset += L::BaseMetric::measure(&child_summary); - before += &child_summary; + offset += child.base_len(); + before += child.base_len(); } - offset += inode.child(child_idx).base_measure(); + offset += inode.child(child_idx).base_len(); // This will be the child of the root node that contains the last // slice. let mut node = inode.first(); for child in &inode.children()[child_idx + 1..] { - let child_measure = child.base_measure(); + let child_len = child.base_len(); - if offset + child_measure >= range.end { + if offset + child_len >= range.end { node = child; break; } else { - offset += child_measure; - summary += &child.summary(); + offset += child_len; + summary += child.summary(); } } @@ -769,14 +749,14 @@ impl<'a, const N: usize, L: Leaf, M: UnitMetric> UnitsForward<'a, N, L, M> { match &**node { Node::Internal(inode) => { for child in inode.children() { - let child_measure = child.base_measure(); + let child_len = child.base_len(); - if offset + child_measure >= range.end { + if offset + child_len >= range.end { node = child; continue 'outer; } else { - offset += child_measure; - summary += &child.summary(); + offset += child_len; + summary += child.summary(); } } @@ -799,54 +779,57 @@ impl<'a, const N: usize, L: Leaf, M: UnitMetric> UnitsForward<'a, N, L, M> { /// iterate forward this only gets called when we are sure there's a /// remainder to yield. #[inline] - fn remainder(&mut self) -> (TreeSlice<'a, N, L>, L::Summary) { + fn remainder(&mut self) -> (TreeSlice<'a, N, L>, L::BaseMetric) { debug_assert_eq!(self.units_total, self.units_yielded); debug_assert!(self.base_total > self.base_yielded); if self.start_slice.is_empty() { let next_slice = self.next_leaf(); - self.yielded_in_leaf = L::Summary::default(); + self.yielded_in_leaf = L::BaseMetric::zero(); self.start_slice = next_slice; } // First, check if the leaf node is the root. If it is we're done. - if self.base_total - self.base_yielded - == self.start_slice.base_measure() - { - let summary = self.start_slice.summarize(); - - let advance = summary.clone(); - + if self.base_total - self.base_yielded == self.start_slice.base_len() { return ( TreeSlice { root: self.leaf_node, - offset: self.yielded_in_leaf.clone(), + offset: self.yielded_in_leaf, start_slice: self.start_slice, end_slice: self.start_slice, - summary, + summary: self.start_slice.summarize(), }, - advance, + self.start_slice.base_len(), ); } let start_slice = self.start_slice; - let (last_leaf, root, before, mut summary) = self.last_leaf(); + let (last_leaf, root, mut before, mut summary) = self.last_leaf(); - summary += &start_slice.summarize(); + summary += start_slice.summarize(); let end_slice = match self.last_slice.take() { Some(slice) => slice, None => last_leaf.as_slice(), }; - summary += &end_slice.summarize(); + summary += end_slice.summarize(); - let offset = before + &self.yielded_in_leaf; + before += self.yielded_in_leaf; - let advance = summary.clone(); + let advance = summary.base_len(); - (TreeSlice { root, offset, summary, start_slice, end_slice }, advance) + ( + TreeSlice { + root, + offset: before, + summary, + start_slice, + end_slice, + }, + advance, + ) } } @@ -864,8 +847,8 @@ struct UnitsBackward<'a, const N: usize, L: Leaf, M: Metric> { /// The current leaf node. leaf_node: &'a Arc>, - /// How much of `leaf_node`'s base measure has already been yielded. - yielded_in_leaf: L::Summary, + /// How much of `leaf_node`'s base length has already been yielded. + yielded_in_leaf: L::BaseMetric, /// The `end_slice` of the next `TreeSlice` that'll be returned by /// [`previous`](Self::previous()). @@ -882,7 +865,7 @@ struct UnitsBackward<'a, const N: usize, L: Leaf, M: Metric> { /// The start of the yielding range as an offset into the root. base_start: L::BaseMetric, - /// The base measure of all the advances which are yet to be yielded. + /// The base length of all the advances which are yet to be yielded. base_remaining: L::BaseMetric, /// The `M`-units which are yet to be yielded. @@ -894,11 +877,7 @@ impl> Clone { #[inline] fn clone(&self) -> Self { - Self { - path: self.path.clone(), - yielded_in_leaf: self.yielded_in_leaf.clone(), - ..*self - } + Self { path: self.path.clone(), ..*self } } } @@ -913,12 +892,12 @@ where is_initialized: false, path: Vec::with_capacity(tree.root().depth()), leaf_node: tree.root(), - yielded_in_leaf: L::Summary::default(), + yielded_in_leaf: L::BaseMetric::zero(), end_slice: L::Slice::default(), first_slice: None, last_slice: None, base_start: L::BaseMetric::zero(), - base_remaining: tree.base_measure(), + base_remaining: tree.base_len(), units_remaining: tree.root().measure::(), } } @@ -937,12 +916,12 @@ where is_initialized: false, path: Vec::with_capacity(tree_slice.root().depth()), leaf_node: tree_slice.root(), - yielded_in_leaf: L::Summary::default(), + yielded_in_leaf: L::BaseMetric::zero(), end_slice: L::Slice::default(), first_slice: Some(tree_slice.start_slice), last_slice: Some(tree_slice.end_slice), - base_start: L::BaseMetric::measure(&tree_slice.offset), - base_remaining: tree_slice.base_measure(), + base_start: tree_slice.offset, + base_remaining: tree_slice.base_len(), units_remaining: tree_slice.measure::(), } } @@ -973,14 +952,14 @@ impl<'a, const N: usize, L: Leaf, M: DoubleEndedUnitMetric> match &**node { Node::Internal(inode) => { for (idx, child) in inode.children().iter().enumerate() { - let child_measure = child.base_measure(); + let child_len = child.base_len(); - if offset + child_measure >= last_slice_offset { + if offset + child_len >= last_slice_offset { self.path.push((node, idx)); node = child; continue 'outer; } else { - offset += child_measure; + offset += child_len; } } @@ -993,7 +972,7 @@ impl<'a, const N: usize, L: Leaf, M: DoubleEndedUnitMetric> match self.last_slice.take() { Some(slice) => { self.yielded_in_leaf = - leaf.summarize() - &slice.summarize(); + leaf.base_len() - slice.base_len(); self.end_slice = slice; }, @@ -1045,7 +1024,7 @@ impl<'a, const N: usize, L: Leaf, M: DoubleEndedUnitMetric> /// Very similar to [`previous_leaf_with_measure`](1), except it doesn't /// mutate any state and instead of returning the previous leaf node with a - /// non-zero `M`-measure it returns the leaf node containing + /// non-zero `M`-length it returns the leaf node containing /// [`first_slice`](2), or the first leaf node in the root if that's not /// set. /// @@ -1059,7 +1038,7 @@ impl<'a, const N: usize, L: Leaf, M: DoubleEndedUnitMetric> #[inline] fn first_leaf( &self, - ) -> (&'a L, &'a Arc>, L::Summary, L::Summary) { + ) -> (&'a L, &'a Arc>, L::BaseMetric, L::Summary) { // Step 1: find the index of deepest node in the path that fully // contains `range`. @@ -1078,16 +1057,15 @@ impl<'a, const N: usize, L: Leaf, M: DoubleEndedUnitMetric> let mut offset = L::BaseMetric::zero(); for child in &inode.children()[..=child_idx] { - let child_measure = child.base_measure(); + let child_len = child.base_len(); - if offset <= range.start - && offset + child_measure >= range.end + if offset <= range.start && offset + child_len >= range.end { range.start -= offset; range.end -= offset; continue 'outer; } else { - offset += child_measure; + offset += child_len; } } @@ -1104,19 +1082,19 @@ impl<'a, const N: usize, L: Leaf, M: DoubleEndedUnitMetric> // Step 2: traverse down the path starting from the node after the // root, increasing `after` and `summary` as you go. - let mut after = L::Summary::default(); - let mut summary = L::Summary::default(); + let mut after = L::BaseMetric::zero(); + let mut summary = L::Summary::empty(); for &(node, child_idx) in &self.path[root_idx + 1..] { // Every node in the path is an internal node. let inode = node.get_internal(); for child in &inode.children()[..child_idx] { - summary += &child.summary(); + summary += child.summary(); } for child in &inode.children()[child_idx + 1..] { - after += &child.summary(); + after += child.base_len(); } } @@ -1126,7 +1104,7 @@ impl<'a, const N: usize, L: Leaf, M: DoubleEndedUnitMetric> let inode = root.get_internal(); for child in &inode.children()[child_idx + 1..] { - after += &child.summary(); + after += child.base_len(); } // This will be the child of the root node that contains the first @@ -1138,16 +1116,16 @@ impl<'a, const N: usize, L: Leaf, M: DoubleEndedUnitMetric> let mut children = inode.children()[..child_idx].iter(); while let Some(child) = children.next() { - let child_measure = child.base_measure(); + let child_len = child.base_len(); - if offset + child_measure > range.start { + if offset + child_len > range.start { for child in children { - summary += &child.summary(); + summary += child.summary(); } node = child; break; } else { - offset += child_measure; + offset += child_len; } } @@ -1157,16 +1135,16 @@ impl<'a, const N: usize, L: Leaf, M: DoubleEndedUnitMetric> let mut children = inode.children().iter(); while let Some(child) = children.next() { - let child_measure = child.base_measure(); + let child_len = child.base_len(); - if offset + child_measure > range.start { + if offset + child_len > range.start { for child in children { - summary += &child.summary(); + summary += child.summary(); } node = child; continue 'outer; } else { - offset += child_measure; + offset += child_len; } } @@ -1187,18 +1165,18 @@ impl<'a, const N: usize, L: Leaf, M: DoubleEndedUnitMetric> /// /// - by [`Self::previous()`] when there's one final unit to yield. #[inline] - fn first(&mut self) -> (TreeSlice<'a, N, L>, L::Summary) { + fn first(&mut self) -> (TreeSlice<'a, N, L>, L::BaseMetric) { debug_assert!(self.base_remaining > L::BaseMetric::zero()); let (_, end_slice, mut advance) = M::last_unit(self.end_slice); // First, check if the current leaf node is the root. If it is we're // done. - if self.base_remaining == L::BaseMetric::measure(&advance) { + if self.base_remaining == advance { return ( TreeSlice { root: self.leaf_node, - offset: L::Summary::default(), + offset: L::BaseMetric::zero(), summary: end_slice.summarize(), start_slice: end_slice, end_slice, @@ -1217,10 +1195,10 @@ impl<'a, const N: usize, L: Leaf, M: DoubleEndedUnitMetric> if end_slice.is_empty() { let previous_leaf = self.previous_leaf(); - self.base_remaining -= L::BaseMetric::measure(&advance); + self.base_remaining -= advance; let contains_first_slice = - previous_leaf.base_measure() > self.base_remaining; + previous_leaf.base_len() > self.base_remaining; if contains_first_slice { self.end_slice = self.first_slice.take().unwrap(); @@ -1228,22 +1206,22 @@ impl<'a, const N: usize, L: Leaf, M: DoubleEndedUnitMetric> self.end_slice = previous_leaf.as_slice(); }; - self.yielded_in_leaf = L::Summary::default(); + self.yielded_in_leaf = L::BaseMetric::zero(); let (first, first_advance) = self.first(); - self.base_remaining += L::BaseMetric::measure(&advance); + self.base_remaining += advance; - advance += &first_advance; + advance += first_advance; return (first, advance); }; let (first_leaf, root, after, mut summary) = self.first_leaf(); - advance += &summary; + advance += summary.base_len(); - summary += &end_slice.summarize(); + summary += end_slice.summarize(); let start_slice = match self.first_slice.take() { Some(slice) => slice, @@ -1252,12 +1230,11 @@ impl<'a, const N: usize, L: Leaf, M: DoubleEndedUnitMetric> let start_summary = start_slice.summarize(); - advance += &start_summary; + advance += start_summary.base_len(); - summary += &start_summary; + summary += start_summary; - let offset = - root.summary() - &after - &self.yielded_in_leaf - &advance; + let offset = root.base_len() - after - self.yielded_in_leaf - advance; (TreeSlice { root, offset, start_slice, end_slice, summary }, advance) } @@ -1266,7 +1243,9 @@ impl<'a, const N: usize, L: Leaf, M: DoubleEndedUnitMetric> /// correctly `self.end_slice` cannot have any `M`-remainder and it needs /// to contain at least 2 `M`-units. #[inline] - fn previous_unit_in_leaf(&mut self) -> (TreeSlice<'a, N, L>, L::Summary) { + fn previous_unit_in_leaf( + &mut self, + ) -> (TreeSlice<'a, N, L>, L::BaseMetric) { debug_assert!(self.end_slice.measure::() > M::one()); debug_assert!(self.units_remaining > M::zero()); @@ -1274,13 +1253,13 @@ impl<'a, const N: usize, L: Leaf, M: DoubleEndedUnitMetric> debug_assert!(!rest.is_empty()); - self.yielded_in_leaf += &advance; + self.yielded_in_leaf += advance; self.end_slice = rest; ( TreeSlice { root: self.leaf_node, - offset: rest.summarize(), + offset: rest.base_len(), summary: slice.summarize(), end_slice: slice, start_slice: slice, @@ -1290,7 +1269,7 @@ impl<'a, const N: usize, L: Leaf, M: DoubleEndedUnitMetric> } /// Traverses the path to reach the previous leaf node with a non-zero - /// `M`-measure. + /// `M`-length. /// /// Returns a `(leaf, root, after, summary)` tuple where: /// @@ -1299,10 +1278,10 @@ impl<'a, const N: usize, L: Leaf, M: DoubleEndedUnitMetric> /// - `root` is the deepest internal node containing both `leaf` and the /// current `self.leaf_node` in its subtree; /// - /// - `after` is the total base measure of all the nodes from the last leaf + /// - `after` is the total base length of all the nodes from the last leaf /// in `root`'s subtree to the leaf after the current `self.leaf_node`. - /// If `self.leaf_node` if the last leaf in `root`'s subtree this measure - /// will be zero; + /// If `self.leaf_node` if the last leaf in `root`'s subtree this will be + /// zero; /// /// - `summary` is the total summary of all the nodes between (but not /// including) `leaf` and `self.leaf_node`. If `leaf` is the leaf node @@ -1319,11 +1298,11 @@ impl<'a, const N: usize, L: Leaf, M: DoubleEndedUnitMetric> #[inline] fn previous_leaf_with_measure( &mut self, - ) -> (&'a L, &'a Arc>, L::Summary, L::Summary) { + ) -> (&'a L, &'a Arc>, L::BaseMetric, L::Summary) { debug_assert!(self.units_remaining > M::zero()); - let mut after = L::Summary::default(); - let mut summary = L::Summary::default(); + let mut after = L::BaseMetric::zero(); + let mut summary = L::Summary::empty(); // Step 1: pop nodes off the path until we find a node with some // `M`-units that we haven't yielded yet. @@ -1335,7 +1314,7 @@ impl<'a, const N: usize, L: Leaf, M: DoubleEndedUnitMetric> let inode = node.get_internal(); for child in &inode.children()[child_idx + 1..] { - after += &child.summary(); + after += child.base_len(); } for (idx, child) in @@ -1345,7 +1324,7 @@ impl<'a, const N: usize, L: Leaf, M: DoubleEndedUnitMetric> self.path.push((node, idx)); break 'outer; } else { - summary += &child.summary(); + summary += child.summary(); } } } @@ -1353,7 +1332,7 @@ impl<'a, const N: usize, L: Leaf, M: DoubleEndedUnitMetric> let &(inode, child_idx) = self.path.last().unwrap(); // Step 2: push nodes on the path until we get to the first leaf node - // with a positive `M`-measure. Once we get there we're done. + // with a positive M-length. Once we get there we're done. // Every node in the path is an internal node. let mut node = &inode.get_internal().children()[child_idx]; @@ -1369,7 +1348,7 @@ impl<'a, const N: usize, L: Leaf, M: DoubleEndedUnitMetric> node = child; continue 'outer; } else { - summary += &child.summary(); + summary += child.summary(); } } @@ -1432,7 +1411,9 @@ impl<'a, const N: usize, L: Leaf, M: DoubleEndedUnitMetric> /// /// [1]: UnitsBackward::previous_leaf_with_measure() #[inline] - fn previous_unit_in_range(&mut self) -> (TreeSlice<'a, N, L>, L::Summary) { + fn previous_unit_in_range( + &mut self, + ) -> (TreeSlice<'a, N, L>, L::BaseMetric) { debug_assert!(self.units_remaining > M::zero()); let (_, end_slice, mut advance) = M::last_unit(self.end_slice); @@ -1447,10 +1428,10 @@ impl<'a, const N: usize, L: Leaf, M: DoubleEndedUnitMetric> if end_slice.is_empty() { let previous_leaf = self.previous_leaf(); - self.base_remaining -= L::BaseMetric::measure(&advance); + self.base_remaining -= advance; let contains_first_slice = - previous_leaf.base_measure() > self.base_remaining; + previous_leaf.base_len() > self.base_remaining; if contains_first_slice { self.end_slice = self.first_slice.take().unwrap(); @@ -1458,7 +1439,7 @@ impl<'a, const N: usize, L: Leaf, M: DoubleEndedUnitMetric> self.end_slice = previous_leaf.as_slice(); }; - self.yielded_in_leaf = L::Summary::default(); + self.yielded_in_leaf = L::BaseMetric::zero(); let (slice, slice_advance) = match self.remainder() { Some(remainder) => remainder, @@ -1470,19 +1451,19 @@ impl<'a, const N: usize, L: Leaf, M: DoubleEndedUnitMetric> ( TreeSlice { root: self.leaf_node, - offset: self.leaf_node.summary(), + offset: self.leaf_node.base_len(), start_slice: empty, end_slice: empty, - summary: L::Summary::default(), + summary: L::Summary::empty(), }, - L::Summary::default(), + L::BaseMetric::zero(), ) }, }; - self.base_remaining += L::BaseMetric::measure(&advance); + self.base_remaining += advance; - advance += &slice_advance; + advance += slice_advance; return (slice, advance); } @@ -1490,17 +1471,15 @@ impl<'a, const N: usize, L: Leaf, M: DoubleEndedUnitMetric> let (leaf, mut root, after, mut summary) = self.previous_leaf_with_measure(); - let is_immediately_before = - L::BaseMetric::measure(&summary) == L::BaseMetric::zero(); + let is_immediately_before = summary.base_len().is_zero(); - advance += &summary; + advance += summary.measure::(); - summary += &end_slice.summarize(); + summary += end_slice.summarize(); let slice = { - let contains_first_slice = L::BaseMetric::measure(&advance) - + leaf.base_measure() - > self.base_remaining; + let contains_first_slice = + advance + leaf.base_len() > self.base_remaining; if contains_first_slice { self.first_slice.take().unwrap() @@ -1513,16 +1492,16 @@ impl<'a, const N: usize, L: Leaf, M: DoubleEndedUnitMetric> let start_summary = start_slice.summarize(); - advance += &start_summary; + advance += start_summary.base_len(); let mut offset = - root.summary() - &after - &self.yielded_in_leaf - &advance; + root.base_len() - after - self.yielded_in_leaf - advance; - self.yielded_in_leaf = start_summary.clone(); + self.yielded_in_leaf = start_summary.base_len(); self.end_slice = rest; if !start_slice.is_empty() { - summary += &start_summary; + summary += start_summary; } // This edge case can happen when the remainder of `slice` is empty. // @@ -1534,21 +1513,21 @@ impl<'a, const N: usize, L: Leaf, M: DoubleEndedUnitMetric> if is_immediately_before { root = next_leaf; - offset = L::Summary::default(); + offset = L::BaseMetric::zero(); start_slice = end_slice; } else { - let start = L::BaseMetric::measure(&offset); + let start = offset; let (new_root, remove_offset) = tree_slice::deepest_node_containing_base_range( root, start, - start + L::BaseMetric::measure(&summary), + start + summary.base_len(), ); root = new_root; - offset -= &remove_offset; + offset -= remove_offset; // `next_leaf` is guaranteed to be a leaf node by // `Self::next_leaf()`. @@ -1571,7 +1550,7 @@ impl<'a, const N: usize, L: Leaf, M: DoubleEndedUnitMetric> /// /// This is because there's some text in the `LineMetric(2)..ByteMetric(5)` /// range. Calling this function will yield the `TreeSlice` in that range, - /// but only if its base measure is positive (hence the `Option`). + /// but only if its base length is positive (hence the `Option`). /// /// For example if the string was "a\n\b\n" the range would be /// `LineMetric(2)..ByteMetric(4)`, which doesn't contain any text. In that @@ -1580,7 +1559,7 @@ impl<'a, const N: usize, L: Leaf, M: DoubleEndedUnitMetric> /// It also follows that if `M` is the `BaseMetric` this function will /// always return `None`. #[inline] - fn remainder(&mut self) -> Option<(TreeSlice<'a, N, L>, L::Summary)> { + fn remainder(&mut self) -> Option<(TreeSlice<'a, N, L>, L::BaseMetric)> { debug_assert!(self.base_remaining > L::BaseMetric::zero()); if self.end_slice.measure::() > M::zero() { @@ -1589,18 +1568,18 @@ impl<'a, const N: usize, L: Leaf, M: DoubleEndedUnitMetric> let summary = slice.summarize(); if !slice.is_empty() { - self.yielded_in_leaf += &summary; + self.yielded_in_leaf += summary.base_len(); self.end_slice = rest; Some(( TreeSlice { root: self.leaf_node, - offset: rest.summarize(), + offset: rest.base_len(), start_slice: slice, end_slice: slice, - summary: summary.clone(), + summary, }, - summary, + slice.base_len(), )) } else { None diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 6c35fbb..8be33b8 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -1,10 +1,32 @@ #![allow(dead_code)] +use std::env; + +use rand::SeedableRng; + pub const TINY: &str = include_str!("tiny.txt"); pub const SMALL: &str = include_str!("small.txt"); pub const MEDIUM: &str = include_str!("medium.txt"); pub const LARGE: &str = include_str!("large.txt"); +#[track_caller] +pub fn rng() -> impl rand::Rng { + let seed = seed(); + println!("SEED: {seed:?}"); + rand_chacha::ChaChaRng::seed_from_u64(seed) +} + +#[track_caller] +fn seed() -> u64 { + match env::var("SEED") { + Ok(seed) => seed.parse().expect("couldn't parse $SEED"), + Err(env::VarError::NotPresent) => rand::random(), + Err(env::VarError::NotUnicode(seed)) => { + panic!("$SEED contained invalid unicode: {seed:?}") + }, + } +} + /// A cursed version of a lorem ipsum paragraph taken from [this online /// tool][1] with mixed line breaks (LF and CRLF). /// diff --git a/tests/iterators.rs b/tests/iterators.rs index 03ace0e..c8627a9 100644 --- a/tests/iterators.rs +++ b/tests/iterators.rs @@ -1,5 +1,5 @@ use crop::Rope; -use rand::{Rng, rng}; +use rand::Rng; mod common; @@ -41,7 +41,7 @@ fn iter_bytes_both_ways() { let s = if cfg!(miri) { "Hello, world!" } else { LARGE }; let rope = Rope::from(s); - let i = rng().random_range(0..=s.len()); + let i = common::rng().random_range(0..=s.len()); println!("i: {i}"); @@ -209,7 +209,7 @@ fn iter_chars_both_ways() { let rope = Rope::from(LARGE); let total_chars = LARGE.chars().count(); - let i = rng().random_range(0..=total_chars); + let i = common::rng().random_range(0..=total_chars); println!("i: {i}"); @@ -429,7 +429,7 @@ fn iter_lines_forward_backward() { #[cfg_attr(miri, ignore)] #[test] fn iter_lines_over_random_slices() { - let mut rng = rand::rng(); + let mut rng = common::rng(); for s in [TINY, SMALL, MEDIUM, LARGE] { let rope = Rope::from(s); @@ -541,7 +541,7 @@ fn iter_raw_lines_over_test_vectors() { #[cfg_attr(miri, ignore)] #[test] fn iter_raw_lines_over_random_slices() { - let mut rng = rand::rng(); + let mut rng = common::rng(); for s in [TINY, SMALL, MEDIUM, LARGE] { let rope = Rope::from(s); diff --git a/tests/rope_replace.rs b/tests/rope_replace.rs index 94febd9..209650d 100644 --- a/tests/rope_replace.rs +++ b/tests/rope_replace.rs @@ -122,7 +122,7 @@ fn insert_8() { #[cfg_attr(miri, ignore)] #[test] fn insert_small_random() { - let mut rng = rand::rng(); + let mut rng = common::rng(); let mut rope = Rope::new(); let mut string = String::new(); @@ -159,7 +159,7 @@ fn insert_small_random() { #[cfg_attr(miri, ignore)] #[test] fn insert_random() { - let mut rng = rand::rng(); + let mut rng = common::rng(); for s in [TINY, SMALL, MEDIUM, LARGE] { let mut r = Rope::from(s); @@ -272,7 +272,7 @@ fn delete_9() { #[cfg_attr(miri, ignore)] #[test] fn delete_random() { - let mut rng = rand::rng(); + let mut rng = common::rng(); for s in [TINY, SMALL, MEDIUM, LARGE] { let mut r = Rope::from(s); @@ -324,7 +324,7 @@ fn replace_1() { #[cfg_attr(miri, ignore)] #[test] fn replace_random() { - let mut rng = rand::rng(); + let mut rng = common::rng(); for s in [TINY, SMALL, MEDIUM, LARGE] { let mut r = Rope::from(s); diff --git a/tests/slice_indexing.rs b/tests/slice_indexing.rs index 196f3bc..af00e69 100644 --- a/tests/slice_indexing.rs +++ b/tests/slice_indexing.rs @@ -10,7 +10,7 @@ use common::{CURSED_LIPSUM, LARGE, MEDIUM, SMALL, TINY}; #[cfg_attr(miri, ignore)] #[test] fn byte_random() { - let mut rng = rand::rng(); + let mut rng = common::rng(); for s in [TINY, SMALL, MEDIUM, LARGE] { let r = Rope::from(s); @@ -22,13 +22,13 @@ fn byte_random() { let str_slice = &s[start..end]; let rope_slice = r.byte_slice(start..end); - for (idx, byte) in str_slice.bytes().enumerate() { - if byte != rope_slice.byte(idx) { - println!( - "byte index: {idx}, byte range: {:?}", - start..end + for (idx, str_byte) in str_slice.bytes().enumerate() { + let rope_byte = rope_slice.byte(idx); + if str_byte != rope_byte { + panic!( + "string's byte is {str_byte}, but rope's byte is \ + {rope_byte}", ); - assert_eq!(byte, rope_slice.byte(idx)); } } } @@ -40,7 +40,7 @@ fn byte_random() { #[cfg_attr(miri, ignore)] #[test] fn is_char_boundary_random() { - let mut rng = rand::rng(); + let mut rng = common::rng(); for s in [CURSED_LIPSUM, TINY, SMALL, MEDIUM, LARGE] { let r = Rope::from(s); @@ -76,7 +76,7 @@ fn is_char_boundary_random() { #[cfg_attr(miri, ignore)] #[test] fn line_of_byte_random() { - let mut rng = rand::rng(); + let mut rng = common::rng(); for s in [TINY, SMALL, MEDIUM, LARGE] { let crop = Rope::from(s); @@ -110,7 +110,7 @@ fn line_of_byte_random() { #[cfg_attr(miri, ignore)] #[test] fn byte_of_line_random() { - let mut rng = rand::rng(); + let mut rng = common::rng(); for s in [TINY, SMALL, MEDIUM, LARGE] { let crop = Rope::from(s); diff --git a/tests/slicing.rs b/tests/slicing.rs index 8797dd4..c1a0505 100644 --- a/tests/slicing.rs +++ b/tests/slicing.rs @@ -54,7 +54,7 @@ fn byte_slice_0() { #[cfg_attr(miri, ignore)] #[test] fn byte_slice_random() { - let mut rng = rand::rng(); + let mut rng = common::rng(); for s in [TINY, SMALL, MEDIUM, LARGE] { let r = Rope::from(s); @@ -139,7 +139,7 @@ fn byte_slice_then_line() { #[cfg_attr(miri, ignore)] #[test] fn line_slices_random() { - let mut rng = rand::rng(); + let mut rng = common::rng(); for s in [TINY, SMALL, MEDIUM, LARGE] { let r = Rope::from(s); @@ -189,7 +189,7 @@ fn line_slices_random() { /// content while also satisying its invariants. #[test] fn rope_from_slice() { - let mut rng = rand::rng(); + let mut rng = common::rng(); let slices = if cfg!(miri) { ["Hello world", "ƒoo", "bär", "baz", "🗻∈🌏"]