mirror of
https://github.com/loro-dev/loro.git
synced 2024-11-28 17:41:49 +00:00
fix: reduce unsafe code
This commit is contained in:
parent
328d0517c0
commit
b80a70bb2d
4 changed files with 88 additions and 109 deletions
|
@ -41,7 +41,10 @@ impl ZeroElement for Marker {
|
|||
}
|
||||
|
||||
impl Marker {
|
||||
pub fn as_cursor(&self, id: ID) -> Option<SafeCursor<'static, YSpan, YSpanTreeTrait>> {
|
||||
pub(super) fn as_cursor<'a, 'b>(
|
||||
&'a self,
|
||||
id: ID,
|
||||
) -> Option<SafeCursor<'b, YSpan, YSpanTreeTrait>> {
|
||||
match self {
|
||||
Marker::Insert { ptr, len: _ } => {
|
||||
// SAFETY: tree data is always valid
|
||||
|
@ -50,16 +53,17 @@ impl Marker {
|
|||
let child = &node.children()[position];
|
||||
let start_counter = child.id.counter;
|
||||
let offset = id.counter - start_counter;
|
||||
// SAFETY: we just checked it is valid
|
||||
Some(unsafe {
|
||||
SafeCursor::new(
|
||||
*ptr,
|
||||
// SAFETY: we transform lifetime from SafeCursor<'static> to SafeCursor<'b> to suit the need.
|
||||
// Its safety is guaranteed by the caller, who has access to the underlying tree
|
||||
unsafe {
|
||||
std::mem::transmute(Some(SafeCursor::from_leaf(
|
||||
node,
|
||||
position,
|
||||
offset as usize,
|
||||
Position::from_offset(offset as isize, child.atom_len()),
|
||||
0,
|
||||
)
|
||||
})
|
||||
)))
|
||||
}
|
||||
}
|
||||
Marker::Delete(_) => None,
|
||||
}
|
||||
|
|
|
@ -79,7 +79,7 @@ impl ListCrdt for YataImpl {
|
|||
// dbg!(&container.content);
|
||||
// SAFETY: loosen lifetime requirement here. It's safe because the function
|
||||
// signature can limit the lifetime of the returned iterator
|
||||
unsafe { std::mem::transmute(container.content.iter_mut_in(from, to)) }
|
||||
container.content.iter_mut_in(from, to)
|
||||
}
|
||||
|
||||
fn id(op: &Self::OpUnit) -> Self::OpId {
|
||||
|
|
|
@ -38,6 +38,16 @@ impl<T: Rle + 'static, A: RleTreeTrait<T> + 'static> Default for RleTree<T, A> {
|
|||
}
|
||||
|
||||
impl<T: Rle, A: RleTreeTrait<T>> RleTree<T, A> {
|
||||
fn root(&self) -> &Node<T, A> {
|
||||
// SAFETY: self can be shared ref so the root node must be valid and can be shared ref
|
||||
self.with_node(|node| unsafe { std::mem::transmute::<_, &Node<T, A>>(&**node) })
|
||||
}
|
||||
|
||||
fn root_mut(&mut self) -> &mut Node<T, A> {
|
||||
// SAFETY: self can be exclusively ref so the root node must be valid and can be exclusively ref
|
||||
self.with_node_mut(|node| unsafe { std::mem::transmute::<_, &mut Node<T, A>>(&mut **node) })
|
||||
}
|
||||
|
||||
pub fn insert_at_first<F>(&mut self, value: T, notify: &mut F)
|
||||
where
|
||||
F: FnMut(&T, *mut LeafNode<'_, T, A>),
|
||||
|
@ -84,76 +94,68 @@ impl<T: Rle, A: RleTreeTrait<T>> RleTree<T, A> {
|
|||
/// return a cursor at the given index
|
||||
#[inline]
|
||||
pub fn get(&self, mut index: A::Int) -> Option<SafeCursor<'_, T, A>> {
|
||||
self.with_node(|mut node| {
|
||||
loop {
|
||||
match node {
|
||||
Node::Internal(internal_node) => {
|
||||
let result = A::find_pos_internal(internal_node, index);
|
||||
if !result.found {
|
||||
return None;
|
||||
}
|
||||
|
||||
node = &internal_node.children[result.child_index];
|
||||
index = result.offset;
|
||||
let mut node = self.root();
|
||||
loop {
|
||||
match node {
|
||||
Node::Internal(internal_node) => {
|
||||
let result = A::find_pos_internal(internal_node, index);
|
||||
if !result.found {
|
||||
return None;
|
||||
}
|
||||
Node::Leaf(leaf) => {
|
||||
let result = A::find_pos_leaf(leaf, index);
|
||||
if !result.found {
|
||||
return None;
|
||||
}
|
||||
|
||||
// SAFETY: result is valid
|
||||
return Some(unsafe {
|
||||
std::mem::transmute(SafeCursor::from_leaf(
|
||||
leaf,
|
||||
result.child_index,
|
||||
result.offset,
|
||||
result.pos,
|
||||
0,
|
||||
))
|
||||
});
|
||||
node = internal_node.children[result.child_index];
|
||||
index = result.offset;
|
||||
}
|
||||
Node::Leaf(leaf) => {
|
||||
let result = A::find_pos_leaf(leaf, index);
|
||||
if !result.found {
|
||||
return None;
|
||||
}
|
||||
|
||||
return Some(SafeCursor::from_leaf(
|
||||
leaf,
|
||||
result.child_index,
|
||||
result.offset,
|
||||
result.pos,
|
||||
0,
|
||||
));
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// return the first valid cursor after the given index
|
||||
/// reviewed by @Leeeon233
|
||||
#[inline]
|
||||
fn get_cursor_ge(&self, mut index: A::Int) -> Option<SafeCursor<'_, T, A>> {
|
||||
self.with_node(|mut node| {
|
||||
loop {
|
||||
match node {
|
||||
Node::Internal(internal_node) => {
|
||||
let result = A::find_pos_internal(internal_node, index);
|
||||
if result.child_index >= internal_node.children.len() {
|
||||
return None;
|
||||
}
|
||||
|
||||
node = &internal_node.children[result.child_index];
|
||||
index = result.offset;
|
||||
let mut node = self.root();
|
||||
loop {
|
||||
match node {
|
||||
Node::Internal(internal_node) => {
|
||||
let result = A::find_pos_internal(internal_node, index);
|
||||
if result.child_index >= internal_node.children.len() {
|
||||
return None;
|
||||
}
|
||||
Node::Leaf(leaf) => {
|
||||
let result = A::find_pos_leaf(leaf, index);
|
||||
if result.child_index >= leaf.children.len() {
|
||||
return None;
|
||||
}
|
||||
|
||||
// SAFETY: result is valid
|
||||
return Some(unsafe {
|
||||
std::mem::transmute(SafeCursor::new(
|
||||
leaf.into(),
|
||||
result.child_index,
|
||||
result.offset,
|
||||
result.pos,
|
||||
0,
|
||||
))
|
||||
});
|
||||
node = internal_node.children[result.child_index];
|
||||
index = result.offset;
|
||||
}
|
||||
Node::Leaf(leaf) => {
|
||||
let result = A::find_pos_leaf(leaf, index);
|
||||
if result.child_index >= leaf.children.len() {
|
||||
return None;
|
||||
}
|
||||
|
||||
return Some(SafeCursor::from_leaf(
|
||||
leaf,
|
||||
result.child_index,
|
||||
result.offset,
|
||||
result.pos,
|
||||
0,
|
||||
));
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -165,18 +167,13 @@ impl<T: Rle, A: RleTreeTrait<T>> RleTree<T, A> {
|
|||
|
||||
#[inline]
|
||||
pub fn iter(&self) -> iter::Iter<'_, T, A> {
|
||||
// SAFETY: the cursor and iter cannot outlive self
|
||||
self.with_node(|node| unsafe {
|
||||
iter::Iter::new(std::mem::transmute(node.get_first_leaf()))
|
||||
})
|
||||
iter::Iter::new(self.root().get_first_leaf())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn iter_mut(&mut self) -> iter::IterMut<'_, T, A> {
|
||||
// SAFETY: the cursor and iter cannot outlive self
|
||||
self.with_node_mut(|node| unsafe {
|
||||
iter::IterMut::new(std::mem::transmute(node.get_first_leaf_mut()))
|
||||
})
|
||||
iter::IterMut::new(self.root_mut().get_first_leaf_mut())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -184,27 +181,25 @@ impl<T: Rle, A: RleTreeTrait<T>> RleTree<T, A> {
|
|||
self.len() == A::Int::from_usize(0).unwrap()
|
||||
}
|
||||
|
||||
pub fn iter_mut_in(
|
||||
&mut self,
|
||||
start: Option<SafeCursor<'_, T, A>>,
|
||||
end: Option<SafeCursor<'_, T, A>>,
|
||||
) -> iter::IterMut<'_, T, A> {
|
||||
pub fn iter_mut_in<'a>(
|
||||
&'a mut self,
|
||||
start: Option<SafeCursor<'a, T, A>>,
|
||||
end: Option<SafeCursor<'a, T, A>>,
|
||||
) -> iter::IterMut<'a, T, A> {
|
||||
if start.is_none() && end.is_none() {
|
||||
self.iter_mut()
|
||||
} else {
|
||||
// SAFETY: the cursor cannot outlive self, so we are safe here
|
||||
self.with_node_mut(|node| unsafe {
|
||||
let leaf = node.get_first_leaf().unwrap();
|
||||
// SAFETY: this is safe because we know there are at least one element in the tree
|
||||
let start = start.unwrap_or_else(|| {
|
||||
std::mem::transmute(SafeCursor::from_leaf(leaf, 0, 0, Position::Start, 0))
|
||||
});
|
||||
let start: SafeCursorMut<'_, T, A> = SafeCursorMut::from(start.0);
|
||||
std::mem::transmute::<_, iter::IterMut<'_, T, A>>(iter::IterMut::from_cursor(
|
||||
std::mem::transmute::<_, SafeCursorMut<'_, T, A>>(start),
|
||||
end,
|
||||
))
|
||||
})
|
||||
let leaf = self.root().get_first_leaf().unwrap();
|
||||
// SAFETY: this is safe because we know there are at least one element in the tree
|
||||
let start =
|
||||
start.unwrap_or_else(|| SafeCursor::from_leaf(leaf, 0, 0, Position::Start, 0));
|
||||
|
||||
// SAFETY: we have exclusive ref to the tree, so it's safe to have an exclusive ref to its elements
|
||||
let start: SafeCursorMut<'a, T, A> = unsafe { SafeCursorMut::from(start.0) };
|
||||
iter::IterMut::from_cursor(
|
||||
start,
|
||||
end.map(|x| UnsafeCursor::new(x.0.leaf, x.0.index, x.0.offset, x.0.pos, 0)),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -373,26 +368,6 @@ impl<T: Rle, A: RleTreeTrait<T>> RleTree<T, A> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn update_range<U, F>(
|
||||
&mut self,
|
||||
start: A::Int,
|
||||
end: Option<A::Int>,
|
||||
update_fn: &mut U,
|
||||
notify: &mut F,
|
||||
) where
|
||||
U: FnMut(&mut T),
|
||||
F: FnMut(&T, *mut LeafNode<'_, T, A>),
|
||||
{
|
||||
let mut cursors = Vec::new();
|
||||
for cursor in self.iter_range(start, end) {
|
||||
cursors.push(cursor.0);
|
||||
}
|
||||
|
||||
// SAFETY: it's perfectly safe here because we know what we are doing in the update_at_cursors
|
||||
let mut cursors: Vec<_> = unsafe { std::mem::transmute(cursors) };
|
||||
self.update_at_cursors(&mut cursors, update_fn, notify);
|
||||
}
|
||||
|
||||
pub fn debug_check(&mut self) {
|
||||
self.with_node_mut(|node| {
|
||||
node.as_internal_mut().unwrap().check();
|
||||
|
|
|
@ -55,7 +55,7 @@ impl<'tree, T: Rle, A: RleTreeTrait<T>> IterMut<'tree, T, A> {
|
|||
#[inline]
|
||||
pub fn from_cursor(
|
||||
mut start: SafeCursorMut<'tree, T, A>,
|
||||
end: Option<SafeCursor<'tree, T, A>>,
|
||||
end: Option<UnsafeCursor<'tree, T, A>>,
|
||||
) -> Self {
|
||||
if start.0.pos == Position::After {
|
||||
match start.next_elem_start() {
|
||||
|
@ -77,7 +77,7 @@ impl<'tree, T: Rle, A: RleTreeTrait<T>> IterMut<'tree, T, A> {
|
|||
start.0.pos,
|
||||
0,
|
||||
)),
|
||||
end_cursor: end.map(|x| UnsafeCursor::new(x.0.leaf, x.0.index, x.0.offset, x.0.pos, 0)),
|
||||
end_cursor: end,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue