mirror of
https://github.com/loro-dev/loro.git
synced 2025-02-02 11:06:14 +00:00
feat: cursor mut
This commit is contained in:
parent
f2db2fdcf2
commit
66c50d4a9b
6 changed files with 126 additions and 13 deletions
|
@ -1,5 +1,33 @@
|
||||||
use rle::RleTree;
|
use std::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
use super::y_span::{YSpan, YSpanTreeTrait};
|
use rle::{rle_tree::SafeCursorMut, Rle, RleTree, RleTreeTrait};
|
||||||
|
|
||||||
pub(super) type ContentMap = RleTree<YSpan, YSpanTreeTrait>;
|
use super::y_span::{StatusChange, YSpan, YSpanTreeTrait};
|
||||||
|
|
||||||
|
#[repr(transparent)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(super) struct ContentMap(RleTree<YSpan, YSpanTreeTrait>);
|
||||||
|
|
||||||
|
impl Deref for ContentMap {
|
||||||
|
type Target = RleTree<YSpan, YSpanTreeTrait>;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DerefMut for ContentMap {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
&mut self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn change_status(
|
||||||
|
cursor: &mut SafeCursorMut<'_, '_, YSpan, YSpanTreeTrait>,
|
||||||
|
change: StatusChange,
|
||||||
|
) {
|
||||||
|
let value = cursor.as_mut();
|
||||||
|
if value.status.apply(change) {
|
||||||
|
cursor.update_cache_recursively();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -8,6 +8,29 @@ pub(super) struct Status {
|
||||||
undo_times: usize,
|
undo_times: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Status {
|
||||||
|
#[inline]
|
||||||
|
pub fn is_activated(&self) -> bool {
|
||||||
|
!self.unapplied && self.delete_times == 0 && self.undo_times == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return whether the activation changed
|
||||||
|
#[inline]
|
||||||
|
pub fn apply(&mut self, change: StatusChange) -> bool {
|
||||||
|
let activated = self.is_activated();
|
||||||
|
match change {
|
||||||
|
StatusChange::Apply => self.unapplied = false,
|
||||||
|
StatusChange::PreApply => self.unapplied = true,
|
||||||
|
StatusChange::Redo => self.undo_times -= 1,
|
||||||
|
StatusChange::Undo => self.undo_times += 1,
|
||||||
|
StatusChange::Delete => self.delete_times += 1,
|
||||||
|
StatusChange::UndoDelete => self.delete_times -= 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
self.is_activated() != activated
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub(super) struct YSpan {
|
pub(super) struct YSpan {
|
||||||
pub origin_left: ID,
|
pub origin_left: ID,
|
||||||
|
@ -17,6 +40,16 @@ pub(super) struct YSpan {
|
||||||
pub status: Status,
|
pub status: Status,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub(super) enum StatusChange {
|
||||||
|
Apply,
|
||||||
|
PreApply,
|
||||||
|
Redo,
|
||||||
|
Undo,
|
||||||
|
Delete,
|
||||||
|
UndoDelete,
|
||||||
|
}
|
||||||
|
|
||||||
pub(super) type YSpanTreeTrait = CumulateTreeTrait<YSpan, 10>;
|
pub(super) type YSpanTreeTrait = CumulateTreeTrait<YSpan, 10>;
|
||||||
|
|
||||||
impl Mergable for YSpan {
|
impl Mergable for YSpan {
|
||||||
|
@ -71,7 +104,11 @@ impl InsertContent for YSpan {
|
||||||
|
|
||||||
impl HasLength for YSpan {
|
impl HasLength for YSpan {
|
||||||
fn len(&self) -> usize {
|
fn len(&self) -> usize {
|
||||||
|
if self.status.is_activated() {
|
||||||
self.len
|
self.len
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
use self::{
|
use self::node::{InternalNode, Node};
|
||||||
cursor::SafeCursor,
|
|
||||||
node::{InternalNode, Node},
|
|
||||||
};
|
|
||||||
use crate::Rle;
|
use crate::Rle;
|
||||||
pub(self) use bumpalo::collections::vec::Vec as BumpVec;
|
pub(self) use bumpalo::collections::vec::Vec as BumpVec;
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
|
pub use cursor::{SafeCursor, SafeCursorMut};
|
||||||
use ouroboros::self_referencing;
|
use ouroboros::self_referencing;
|
||||||
use std::marker::{PhantomData, PhantomPinned};
|
use std::marker::{PhantomData, PhantomPinned};
|
||||||
use tree_trait::RleTreeTrait;
|
use tree_trait::RleTreeTrait;
|
||||||
|
@ -61,6 +59,7 @@ impl<'a, T: Rle, A: RleTreeTrait<T>> RleTreeRaw<'a, T, A> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// return a cursor to the tree
|
/// return a cursor to the tree
|
||||||
|
#[inline]
|
||||||
pub fn get<'b>(&'b self, mut index: A::Int) -> SafeCursor<'a, 'b, T, A> {
|
pub fn get<'b>(&'b self, mut index: A::Int) -> SafeCursor<'a, 'b, T, A> {
|
||||||
let mut node = &self.node;
|
let mut node = &self.node;
|
||||||
loop {
|
loop {
|
||||||
|
@ -79,8 +78,9 @@ impl<'a, T: Rle, A: RleTreeTrait<T>> RleTreeRaw<'a, T, A> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_mut<'b>(&'b mut self, index: A::Int) -> SafeCursor<'a, 'b, T, A> {
|
pub fn get_mut<'b>(&'b mut self, index: A::Int) -> SafeCursorMut<'a, 'b, T, A> {
|
||||||
self.get(index)
|
let cursor = self.get(index);
|
||||||
|
SafeCursorMut(cursor.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn iter(&self) -> iter::Iter<'_, 'a, T, A> {
|
pub fn iter(&self) -> iter::Iter<'_, 'a, T, A> {
|
||||||
|
|
|
@ -11,7 +11,11 @@ pub struct UnsafeCursor<'a, Tree, T: Rle, A: RleTreeTrait<T>> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SafeCursor<'a, 'b, T: Rle, A: RleTreeTrait<T>>(
|
pub struct SafeCursor<'a, 'b, T: Rle, A: RleTreeTrait<T>>(
|
||||||
UnsafeCursor<'a, &'b RleTreeRaw<'a, T, A>, T, A>,
|
pub(crate) UnsafeCursor<'a, &'b RleTreeRaw<'a, T, A>, T, A>,
|
||||||
|
);
|
||||||
|
|
||||||
|
pub struct SafeCursorMut<'a, 'b, T: Rle, A: RleTreeTrait<T>>(
|
||||||
|
pub(crate) UnsafeCursor<'a, &'b RleTreeRaw<'a, T, A>, T, A>,
|
||||||
);
|
);
|
||||||
|
|
||||||
impl<'a, Tree, T: Rle, A: RleTreeTrait<T>> UnsafeCursor<'a, Tree, T, A> {
|
impl<'a, Tree, T: Rle, A: RleTreeTrait<T>> UnsafeCursor<'a, Tree, T, A> {
|
||||||
|
@ -61,9 +65,41 @@ impl<'a, 'b, T: Rle, A: RleTreeTrait<T>> SafeCursor<'a, 'b, T, A> {
|
||||||
pub(crate) fn new(leaf: NonNull<LeafNode<'a, T, A>>, index: usize) -> Self {
|
pub(crate) fn new(leaf: NonNull<LeafNode<'a, T, A>>, index: usize) -> Self {
|
||||||
Self(UnsafeCursor::new(leaf, index))
|
Self(UnsafeCursor::new(leaf, index))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b, T: Rle, A: RleTreeTrait<T>> AsRef<T> for SafeCursorMut<'a, 'b, T, A> {
|
||||||
|
#[inline]
|
||||||
|
fn as_ref(&self) -> &T {
|
||||||
|
unsafe { self.0.as_ref() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b, T: Rle, A: RleTreeTrait<T>> SafeCursorMut<'a, 'b, T, A> {
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn new(leaf: NonNull<LeafNode<'a, T, A>>, index: usize) -> Self {
|
||||||
|
Self(UnsafeCursor::new(leaf, index))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b, T: Rle, A: RleTreeTrait<T>> AsMut<T> for SafeCursorMut<'a, 'b, T, A> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn as_mut(&mut self) -> &mut T {
|
fn as_mut(&mut self) -> &mut T {
|
||||||
unsafe { self.0.as_mut() }
|
unsafe { self.0.as_mut() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b, T: Rle, A: RleTreeTrait<T>> SafeCursorMut<'a, 'b, T, A> {
|
||||||
|
#[inline]
|
||||||
|
pub fn update_cache_recursively(&mut self) {
|
||||||
|
let leaf = unsafe { self.0.leaf.as_mut() };
|
||||||
|
A::update_cache_leaf(leaf);
|
||||||
|
let mut node = unsafe { leaf.parent.as_mut() };
|
||||||
|
loop {
|
||||||
|
A::update_cache_internal(node);
|
||||||
|
match node.parent {
|
||||||
|
Some(mut parent) => node = unsafe { parent.as_mut() },
|
||||||
|
None => return,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ use std::{
|
||||||
|
|
||||||
use crate::Rle;
|
use crate::Rle;
|
||||||
|
|
||||||
use super::{tree_trait::RleTreeTrait, BumpVec};
|
use super::{cursor::SafeCursor, tree_trait::RleTreeTrait, BumpVec};
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
use enum_as_inner::EnumAsInner;
|
use enum_as_inner::EnumAsInner;
|
||||||
mod internal_impl;
|
mod internal_impl;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::rle_tree::tree_trait::Position;
|
use crate::rle_tree::{cursor::SafeCursorMut, tree_trait::Position};
|
||||||
use std::fmt::{Debug, Error, Formatter};
|
use std::fmt::{Debug, Error, Formatter};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -37,6 +37,18 @@ impl<'a, T: Rle, A: RleTreeTrait<T>> LeafNode<'a, T, A> {
|
||||||
ans
|
ans
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn get_cursor<'b>(&'b self, pos: A::Int) -> SafeCursor<'a, 'b, T, A> {
|
||||||
|
let index = A::find_pos_leaf(self, pos).0;
|
||||||
|
SafeCursor::new(self.into(), index)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn get_cursor_mut<'b>(&'b mut self, pos: A::Int) -> SafeCursorMut<'a, 'b, T, A> {
|
||||||
|
let index = A::find_pos_leaf(self, pos).0;
|
||||||
|
SafeCursorMut::new(self.into(), index)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn push_child(&mut self, value: T) -> Result<(), &'a mut Node<'a, T, A>> {
|
pub fn push_child(&mut self, value: T) -> Result<(), &'a mut Node<'a, T, A>> {
|
||||||
if !self.children.is_empty() {
|
if !self.children.is_empty() {
|
||||||
let last = self.children.last_mut().unwrap();
|
let last = self.children.last_mut().unwrap();
|
||||||
|
|
Loading…
Reference in a new issue