diff --git a/src/rope/rope.rs b/src/rope/rope.rs index 26cc4f3..f68621b 100644 --- a/src/rope/rope.rs +++ b/src/rope/rope.rs @@ -436,6 +436,27 @@ impl Rope { is_grapheme_boundary(self.chunks(), self.byte_len(), byte_offset) } + /// Returns true if this rope and `other` point to precisely the same + /// in-memory data. + /// + /// This happens when one of the ropes is a clone of the other and + /// neither have been modified since then. Because clones initially + /// share all the same data, it can be useful to check if they still + /// point to precisely the same memory as a way of determining + /// whether they are both still unmodified. + /// + /// Note: this is distinct from checking for equality: two ropes can + /// have the same *contents* (equal) but be stored in different + /// memory locations (not instances). Importantly, two clones that + /// post-cloning are modified identically will *not* be instances + /// anymore, even though they will have equal contents. + /// + /// Runs in O(1) time. + #[inline] + pub fn is_instance(&self, other: &Self) -> bool { + self.tree.is_instance(&other.tree) + } + /// Returns the line at `line_index`, without its line terminator. /// /// If you want to include the line break consider taking a diff --git a/src/tree/tree.rs b/src/tree/tree.rs index ea42833..20ff68c 100644 --- a/src/tree/tree.rs +++ b/src/tree/tree.rs @@ -134,6 +134,12 @@ impl Tree { Self { root: Arc::new(Node::Internal(root)) } } + /// Returns `true` if the two roots point to the same allocation. + #[inline] + pub fn is_instance(&self, other: &Self) -> bool { + Arc::ptr_eq(&self.root, &other.root) + } + /// Returns the leaf containing the `measure`-th unit of the `M`-metric, /// plus the `M`-measure of all the leaves before it. #[inline] diff --git a/tests/rope_indexing.rs b/tests/rope_indexing.rs index cd9fdef..b5346a8 100644 --- a/tests/rope_indexing.rs +++ b/tests/rope_indexing.rs @@ -35,6 +35,24 @@ fn rope_is_char_boundary() { } } +#[cfg_attr(miri, ignore)] +#[test] +fn rope_is_instance() { + let r = Rope::from("Hello there!"); + let mut c1 = r.clone(); + let c2 = c1.clone(); + + assert!(r.is_instance(&c1)); + assert!(r.is_instance(&c2)); + assert!(c1.is_instance(&c2)); + + c1.insert(0, "Oh! "); + + assert!(!r.is_instance(&c1)); + assert!(r.is_instance(&c2)); + assert!(!c1.is_instance(&c2)); +} + /// ``` /// Root /// ├───┐