mirror of
https://github.com/loro-dev/loro.git
synced 2024-11-28 17:41:49 +00:00
fix: simplify get siblings
This commit is contained in:
parent
e136504f3e
commit
6da6cd2915
3 changed files with 313 additions and 269 deletions
|
@ -18,7 +18,7 @@ crev:
|
|||
cargo crev crate check
|
||||
|
||||
fuzz:
|
||||
cargo fuzz run yata -- -max_total_time=300 -max_len=8000 -jobs=2
|
||||
cargo fuzz run yata -- -max_total_time=300 -max_len=1000 -jobs=2
|
||||
|
||||
flame:
|
||||
cargo flamegraph --example test --features=fuzzing --root
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
use rle::{
|
||||
rle_tree::{Position, SafeCursor, SafeCursorMut, UnsafeCursor},
|
||||
rle_tree::{Position, SafeCursor, SafeCursorMut},
|
||||
HasLength, RleTree, RleVec,
|
||||
};
|
||||
|
||||
|
@ -16,28 +16,20 @@ use super::y_span::{StatusChange, YSpan, YSpanTreeTrait};
|
|||
#[derive(Debug, Default)]
|
||||
pub(super) struct ContentMap(RleTree<YSpan, YSpanTreeTrait>);
|
||||
|
||||
struct CursorWithId<'tree> {
|
||||
id: ID,
|
||||
cursor: UnsafeCursor<'tree, YSpan, YSpanTreeTrait>,
|
||||
}
|
||||
|
||||
impl ContentMap {
|
||||
#[inline]
|
||||
pub(super) fn get_yspan_at_pos(&self, id: ID, pos: usize, len: usize) -> YSpan {
|
||||
let (left, right) = self.get_sibling_at_dumb(pos);
|
||||
let (left, right) = self.get_sibling_at(pos);
|
||||
YSpan {
|
||||
origin_left: left.as_ref().map(|x| x.id),
|
||||
origin_right: right.as_ref().map(|x| x.id),
|
||||
origin_left: left,
|
||||
origin_right: right,
|
||||
id,
|
||||
len,
|
||||
status: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_sibling_at_dumb(
|
||||
&self,
|
||||
pos: usize,
|
||||
) -> (Option<CursorWithId<'_>>, Option<CursorWithId<'_>>) {
|
||||
fn get_sibling_at(&self, pos: usize) -> (Option<ID>, Option<ID>) {
|
||||
if let Some(cursor) = self.get(pos) {
|
||||
let mut cursor: SafeCursor<'_, YSpan, YSpanTreeTrait> =
|
||||
// SAFETY: we only change the lifetime of the cursor; the returned lifetime is kinda wrong in this situation
|
||||
|
@ -51,16 +43,7 @@ impl ContentMap {
|
|||
let mut prev_offset_cursor = cursor.unwrap();
|
||||
prev_offset_cursor.offset -= 1;
|
||||
if cursor.as_ref().can_be_origin() {
|
||||
return (
|
||||
Some(CursorWithId {
|
||||
id: id.inc(offset as i32 - 1),
|
||||
cursor: prev_offset_cursor,
|
||||
}),
|
||||
Some(CursorWithId {
|
||||
id: id.inc(offset as i32),
|
||||
cursor: cursor.unwrap(),
|
||||
}),
|
||||
);
|
||||
return (Some(id.inc(offset as i32 - 1)), Some(id.inc(offset as i32)));
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
@ -70,10 +53,7 @@ impl ContentMap {
|
|||
let mut prev_offset_cursor = cursor.unwrap();
|
||||
prev_offset_cursor.offset -= 1;
|
||||
prev_offset_cursor.pos = Position::Middle;
|
||||
Some(CursorWithId {
|
||||
id: cursor.as_ref().last_id(),
|
||||
cursor: prev_offset_cursor,
|
||||
})
|
||||
Some(cursor.as_ref().last_id())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
@ -93,10 +73,7 @@ impl ContentMap {
|
|||
let mut cursor = cursor.unwrap();
|
||||
cursor.offset = offset;
|
||||
cursor.pos = Position::Middle;
|
||||
prev = Some(CursorWithId {
|
||||
id: prev_inner.as_ref().last_id(),
|
||||
cursor,
|
||||
});
|
||||
prev = Some(prev_inner.as_ref().last_id());
|
||||
break;
|
||||
}
|
||||
prev_cursor = prev_inner.prev_elem();
|
||||
|
@ -104,36 +81,18 @@ impl ContentMap {
|
|||
}
|
||||
|
||||
let next = if prev.is_some() {
|
||||
let mut next_cursor = cursor.next_elem_start();
|
||||
let next_cursor = cursor.next_elem_start();
|
||||
let mut ans = None;
|
||||
while let Some(next_inner) = next_cursor {
|
||||
if next_inner.as_ref().status.is_activated() {
|
||||
if let Some(next_inner) = next_cursor {
|
||||
let mut cursor = next_inner.unwrap();
|
||||
cursor.offset = 0;
|
||||
cursor.pos = Position::Start;
|
||||
ans = Some(CursorWithId {
|
||||
id: next_inner.as_ref().id,
|
||||
cursor,
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
next_cursor = next_inner.next_elem_start();
|
||||
ans = Some(next_inner.as_ref().id);
|
||||
}
|
||||
|
||||
ans
|
||||
} else {
|
||||
// if prev is none, next should be the first element in the tree
|
||||
let mut prev = cursor.prev_elem();
|
||||
while let Some(prev_inner) = prev {
|
||||
cursor = prev_inner;
|
||||
prev = prev_inner.prev_elem();
|
||||
}
|
||||
|
||||
Some(CursorWithId {
|
||||
id: cursor.as_ref().id,
|
||||
cursor: cursor.unwrap(),
|
||||
})
|
||||
Some(cursor.as_ref().id)
|
||||
};
|
||||
|
||||
(prev, next)
|
||||
|
@ -142,111 +101,6 @@ impl ContentMap {
|
|||
}
|
||||
}
|
||||
|
||||
/// When we insert a new [YSpan] at given position, we need to calculate its `originLeft` and `originRight`
|
||||
fn get_sibling_at(&self, pos: usize) -> (Option<CursorWithId<'_>>, Option<CursorWithId<'_>>) {
|
||||
if let Some(cursor) = self.get(pos) {
|
||||
let cursor: SafeCursor<'_, YSpan, YSpanTreeTrait> =
|
||||
// SAFETY: we only change the lifetime of the cursor; the returned lifetime is kinda wrong in this situation
|
||||
// because Bumpalo's lifetime is static due to the self-referential structure limitation; Maybe there is a better way?
|
||||
unsafe { std::mem::transmute(cursor) };
|
||||
let (mut prev, mut next) = match cursor.pos() {
|
||||
Position::Start => {
|
||||
if cursor.as_ref().can_be_origin() {
|
||||
let id = cursor.as_ref().id;
|
||||
(
|
||||
None,
|
||||
Some(CursorWithId {
|
||||
id,
|
||||
cursor: cursor.unwrap(),
|
||||
}),
|
||||
)
|
||||
} else {
|
||||
(None, None)
|
||||
}
|
||||
}
|
||||
Position::Middle => {
|
||||
if cursor.as_ref().can_be_origin() {
|
||||
let id = cursor.as_ref().id;
|
||||
let offset = cursor.offset();
|
||||
let mut prev_offset_cursor = cursor.unwrap();
|
||||
prev_offset_cursor.offset -= 1;
|
||||
(
|
||||
Some(CursorWithId {
|
||||
id: id.inc(offset as i32 - 1),
|
||||
cursor: prev_offset_cursor,
|
||||
}),
|
||||
Some(CursorWithId {
|
||||
id: id.inc(offset as i32),
|
||||
cursor: cursor.unwrap(),
|
||||
}),
|
||||
)
|
||||
} else {
|
||||
(None, None)
|
||||
}
|
||||
}
|
||||
Position::End => {
|
||||
if cursor.as_ref().can_be_origin() {
|
||||
let mut prev_offset_cursor = cursor.unwrap();
|
||||
prev_offset_cursor.offset -= 1;
|
||||
prev_offset_cursor.pos = Position::Middle;
|
||||
(
|
||||
Some(CursorWithId {
|
||||
id: cursor.as_ref().last_id(),
|
||||
cursor: prev_offset_cursor,
|
||||
}),
|
||||
None,
|
||||
)
|
||||
} else {
|
||||
(None, None)
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
unreachable!()
|
||||
}
|
||||
};
|
||||
|
||||
if prev.is_none() {
|
||||
let mut prev_cursor = cursor.prev_elem();
|
||||
while let Some(prev_inner) = prev_cursor {
|
||||
if prev_inner.as_ref().status.is_activated() {
|
||||
let cursor = prev_inner;
|
||||
let offset = cursor.as_ref().content_len() - 1;
|
||||
let mut cursor = cursor.unwrap();
|
||||
cursor.offset = offset;
|
||||
cursor.pos = Position::Middle;
|
||||
prev = Some(CursorWithId {
|
||||
id: prev_inner.as_ref().last_id(),
|
||||
cursor,
|
||||
});
|
||||
break;
|
||||
}
|
||||
prev_cursor = prev_inner.prev_elem();
|
||||
}
|
||||
}
|
||||
|
||||
if next.is_none() {
|
||||
let mut next_cursor = cursor.next_elem_start();
|
||||
while let Some(next_inner) = next_cursor {
|
||||
if next_inner.as_ref().status.is_activated() {
|
||||
let mut cursor = next_inner.unwrap();
|
||||
cursor.offset = 0;
|
||||
cursor.pos = Position::Start;
|
||||
next = Some(CursorWithId {
|
||||
id: next_inner.as_ref().id,
|
||||
cursor,
|
||||
});
|
||||
break;
|
||||
}
|
||||
next_cursor = next_inner.next_elem_start();
|
||||
}
|
||||
}
|
||||
|
||||
(prev, next)
|
||||
} else {
|
||||
(None, None)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_id_spans(&self, pos: usize, len: usize) -> RleVec<IdSpan> {
|
||||
let mut ans = RleVec::new();
|
||||
for cursor in self.iter_range(pos, Some(pos + len)) {
|
||||
|
|
|
@ -238,6 +238,8 @@ pub mod fuzz {
|
|||
};
|
||||
|
||||
if aa != bb {
|
||||
dbg!(a.client_id);
|
||||
dbg!(b.client_id);
|
||||
dbg!(aa.vec());
|
||||
dbg!(bb.vec());
|
||||
// dbg!(&a.content);
|
||||
|
@ -306,69 +308,295 @@ pub mod fuzz {
|
|||
5,
|
||||
100,
|
||||
vec![
|
||||
Delete {
|
||||
client_id: 252,
|
||||
pos: 252,
|
||||
len: 252,
|
||||
NewOp {
|
||||
client_id: 177,
|
||||
pos: 41,
|
||||
},
|
||||
Delete {
|
||||
client_id: 39,
|
||||
pos: 252,
|
||||
len: 178,
|
||||
},
|
||||
Delete {
|
||||
client_id: 252,
|
||||
pos: 252,
|
||||
len: 252,
|
||||
},
|
||||
Delete {
|
||||
client_id: 252,
|
||||
pos: 252,
|
||||
len: 252,
|
||||
},
|
||||
Delete {
|
||||
client_id: 145,
|
||||
pos: 145,
|
||||
len: 252,
|
||||
},
|
||||
Delete {
|
||||
client_id: 252,
|
||||
pos: 178,
|
||||
len: 178,
|
||||
},
|
||||
Delete {
|
||||
client_id: 252,
|
||||
pos: 252,
|
||||
len: 178,
|
||||
},
|
||||
Delete {
|
||||
client_id: 252,
|
||||
pos: 252,
|
||||
len: 252,
|
||||
client_id: 255,
|
||||
pos: 255,
|
||||
len: 255,
|
||||
},
|
||||
NewOp {
|
||||
client_id: 145,
|
||||
pos: 252,
|
||||
client_id: 162,
|
||||
pos: 162,
|
||||
},
|
||||
Delete {
|
||||
client_id: 252,
|
||||
pos: 178,
|
||||
len: 252,
|
||||
client_id: 255,
|
||||
pos: 255,
|
||||
len: 229,
|
||||
},
|
||||
Delete {
|
||||
client_id: 150,
|
||||
pos: 227,
|
||||
len: 1,
|
||||
},
|
||||
NewOp {
|
||||
client_id: 255,
|
||||
pos: 255,
|
||||
},
|
||||
Delete {
|
||||
client_id: 255,
|
||||
pos: 255,
|
||||
len: 0,
|
||||
},
|
||||
Sync { from: 0, to: 0 },
|
||||
Sync { from: 0, to: 48 },
|
||||
Sync { from: 0, to: 0 },
|
||||
NewOp {
|
||||
client_id: 150,
|
||||
pos: 150,
|
||||
},
|
||||
Delete {
|
||||
client_id: 63,
|
||||
pos: 229,
|
||||
len: 229,
|
||||
},
|
||||
Delete {
|
||||
client_id: 175,
|
||||
pos: 175,
|
||||
len: 255,
|
||||
},
|
||||
Delete {
|
||||
client_id: 237,
|
||||
pos: 237,
|
||||
len: 237,
|
||||
},
|
||||
Delete {
|
||||
client_id: 237,
|
||||
pos: 237,
|
||||
len: 237,
|
||||
},
|
||||
Delete {
|
||||
client_id: 229,
|
||||
pos: 229,
|
||||
len: 229,
|
||||
},
|
||||
NewOp {
|
||||
client_id: 58,
|
||||
pos: 255,
|
||||
},
|
||||
Delete {
|
||||
client_id: 255,
|
||||
pos: 255,
|
||||
len: 255,
|
||||
},
|
||||
Delete {
|
||||
client_id: 175,
|
||||
pos: 175,
|
||||
len: 175,
|
||||
},
|
||||
Delete {
|
||||
client_id: 175,
|
||||
pos: 175,
|
||||
len: 175,
|
||||
},
|
||||
Delete {
|
||||
client_id: 175,
|
||||
pos: 237,
|
||||
len: 237,
|
||||
},
|
||||
Delete {
|
||||
client_id: 237,
|
||||
pos: 237,
|
||||
len: 237,
|
||||
},
|
||||
Delete {
|
||||
client_id: 237,
|
||||
pos: 237,
|
||||
len: 237,
|
||||
},
|
||||
Delete {
|
||||
client_id: 237,
|
||||
pos: 237,
|
||||
len: 237,
|
||||
},
|
||||
Delete {
|
||||
client_id: 255,
|
||||
pos: 255,
|
||||
len: 255,
|
||||
},
|
||||
Delete {
|
||||
client_id: 255,
|
||||
pos: 255,
|
||||
len: 255,
|
||||
},
|
||||
Delete {
|
||||
client_id: 255,
|
||||
pos: 255,
|
||||
len: 255,
|
||||
},
|
||||
Sync { from: 48, to: 175 },
|
||||
Delete {
|
||||
client_id: 175,
|
||||
pos: 175,
|
||||
len: 175,
|
||||
},
|
||||
Delete {
|
||||
client_id: 175,
|
||||
pos: 175,
|
||||
len: 175,
|
||||
},
|
||||
Delete {
|
||||
client_id: 175,
|
||||
pos: 237,
|
||||
len: 237,
|
||||
},
|
||||
Delete {
|
||||
client_id: 237,
|
||||
pos: 237,
|
||||
len: 237,
|
||||
},
|
||||
Delete {
|
||||
client_id: 175,
|
||||
pos: 175,
|
||||
len: 229,
|
||||
},
|
||||
Delete {
|
||||
client_id: 237,
|
||||
pos: 237,
|
||||
len: 237,
|
||||
},
|
||||
Delete {
|
||||
client_id: 237,
|
||||
pos: 237,
|
||||
len: 229,
|
||||
},
|
||||
Delete {
|
||||
client_id: 229,
|
||||
pos: 114,
|
||||
len: 223,
|
||||
},
|
||||
Delete {
|
||||
client_id: 255,
|
||||
pos: 229,
|
||||
len: 255,
|
||||
},
|
||||
Delete {
|
||||
client_id: 175,
|
||||
pos: 175,
|
||||
len: 175,
|
||||
},
|
||||
Delete {
|
||||
client_id: 175,
|
||||
pos: 175,
|
||||
len: 175,
|
||||
},
|
||||
Delete {
|
||||
client_id: 175,
|
||||
pos: 175,
|
||||
len: 175,
|
||||
},
|
||||
Delete {
|
||||
client_id: 237,
|
||||
pos: 237,
|
||||
len: 237,
|
||||
},
|
||||
Delete {
|
||||
client_id: 237,
|
||||
pos: 237,
|
||||
len: 237,
|
||||
},
|
||||
Delete {
|
||||
client_id: 255,
|
||||
pos: 255,
|
||||
len: 255,
|
||||
},
|
||||
Delete {
|
||||
client_id: 255,
|
||||
pos: 255,
|
||||
len: 255,
|
||||
},
|
||||
Delete {
|
||||
client_id: 196,
|
||||
pos: 150,
|
||||
len: 150,
|
||||
},
|
||||
Sync { from: 162, to: 162 },
|
||||
NewOp {
|
||||
client_id: 162,
|
||||
pos: 162,
|
||||
},
|
||||
NewOp {
|
||||
client_id: 162,
|
||||
pos: 162,
|
||||
},
|
||||
NewOp {
|
||||
client_id: 162,
|
||||
pos: 162,
|
||||
},
|
||||
NewOp {
|
||||
client_id: 162,
|
||||
pos: 162,
|
||||
},
|
||||
Sync { from: 81, to: 162 },
|
||||
Sync { from: 0, to: 0 },
|
||||
Sync { from: 162, to: 162 },
|
||||
Sync { from: 0, to: 0 },
|
||||
Sync { from: 0, to: 0 },
|
||||
Sync { from: 0, to: 162 },
|
||||
NewOp {
|
||||
client_id: 162,
|
||||
pos: 162,
|
||||
},
|
||||
NewOp {
|
||||
client_id: 162,
|
||||
pos: 162,
|
||||
},
|
||||
NewOp {
|
||||
client_id: 233,
|
||||
pos: 162,
|
||||
},
|
||||
NewOp {
|
||||
client_id: 150,
|
||||
pos: 150,
|
||||
},
|
||||
Delete {
|
||||
client_id: 255,
|
||||
pos: 255,
|
||||
len: 255,
|
||||
},
|
||||
Sync { from: 0, to: 0 },
|
||||
Delete {
|
||||
client_id: 252,
|
||||
pos: 178,
|
||||
len: 178,
|
||||
client_id: 175,
|
||||
pos: 255,
|
||||
len: 255,
|
||||
},
|
||||
Delete {
|
||||
client_id: 252,
|
||||
pos: 252,
|
||||
len: 252,
|
||||
client_id: 229,
|
||||
pos: 229,
|
||||
len: 196,
|
||||
},
|
||||
NewOp {
|
||||
client_id: 252,
|
||||
pos: 252,
|
||||
client_id: 162,
|
||||
pos: 162,
|
||||
},
|
||||
NewOp {
|
||||
client_id: 162,
|
||||
pos: 162,
|
||||
},
|
||||
NewOp {
|
||||
client_id: 162,
|
||||
pos: 162,
|
||||
},
|
||||
NewOp {
|
||||
client_id: 162,
|
||||
pos: 1,
|
||||
},
|
||||
NewOp {
|
||||
client_id: 162,
|
||||
pos: 255,
|
||||
},
|
||||
Delete {
|
||||
client_id: 229,
|
||||
pos: 229,
|
||||
len: 229,
|
||||
},
|
||||
Sync { from: 255, to: 255 },
|
||||
Sync { from: 255, to: 162 },
|
||||
NewOp {
|
||||
client_id: 162,
|
||||
pos: 162,
|
||||
},
|
||||
],
|
||||
)
|
||||
|
@ -377,69 +605,31 @@ pub mod fuzz {
|
|||
#[test]
|
||||
fn normalize() {
|
||||
let mut actions = vec![
|
||||
Delete {
|
||||
client_id: 252,
|
||||
pos: 252,
|
||||
len: 252,
|
||||
},
|
||||
Delete {
|
||||
client_id: 39,
|
||||
pos: 252,
|
||||
len: 178,
|
||||
},
|
||||
Delete {
|
||||
client_id: 252,
|
||||
pos: 252,
|
||||
len: 252,
|
||||
},
|
||||
Delete {
|
||||
client_id: 252,
|
||||
pos: 252,
|
||||
len: 252,
|
||||
},
|
||||
Delete {
|
||||
client_id: 145,
|
||||
pos: 145,
|
||||
len: 252,
|
||||
},
|
||||
Delete {
|
||||
client_id: 252,
|
||||
pos: 178,
|
||||
len: 178,
|
||||
},
|
||||
Delete {
|
||||
client_id: 252,
|
||||
pos: 252,
|
||||
len: 178,
|
||||
},
|
||||
Delete {
|
||||
client_id: 252,
|
||||
pos: 252,
|
||||
len: 252,
|
||||
NewOp {
|
||||
client_id: 129,
|
||||
pos: 142,
|
||||
},
|
||||
NewOp {
|
||||
client_id: 145,
|
||||
pos: 252,
|
||||
client_id: 0,
|
||||
pos: 85,
|
||||
},
|
||||
Delete {
|
||||
client_id: 252,
|
||||
pos: 178,
|
||||
len: 252,
|
||||
Sync { from: 85, to: 86 },
|
||||
NewOp {
|
||||
client_id: 129,
|
||||
pos: 129,
|
||||
},
|
||||
Sync { from: 0, to: 0 },
|
||||
Delete {
|
||||
client_id: 252,
|
||||
pos: 178,
|
||||
len: 178,
|
||||
},
|
||||
Delete {
|
||||
client_id: 252,
|
||||
pos: 252,
|
||||
len: 252,
|
||||
Sync { from: 129, to: 129 },
|
||||
NewOp {
|
||||
client_id: 106,
|
||||
pos: 106,
|
||||
},
|
||||
NewOp {
|
||||
client_id: 252,
|
||||
pos: 252,
|
||||
client_id: 1,
|
||||
pos: 0,
|
||||
},
|
||||
NewOp {
|
||||
client_id: 129,
|
||||
pos: 106,
|
||||
},
|
||||
];
|
||||
|
||||
|
|
Loading…
Reference in a new issue