mirror of
https://github.com/loro-dev/loro.git
synced 2024-11-28 17:41:49 +00:00
fix: notify
This commit is contained in:
parent
8f005180a4
commit
77eac9eb30
9 changed files with 346 additions and 76 deletions
|
@ -16,3 +16,4 @@ color-backtrace = { version = "0.5" }
|
|||
ctor = "0.1.23"
|
||||
proptest = "1.0.0"
|
||||
smartstring = "1.0.1"
|
||||
rand = "0.8.5"
|
||||
|
|
|
@ -6,9 +6,9 @@ use crate::{
|
|||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
struct WithGlobalIndex<Value, Index: GlobalIndex> {
|
||||
value: Value,
|
||||
index: Index,
|
||||
pub(crate) struct WithGlobalIndex<Value, Index: GlobalIndex> {
|
||||
pub(crate) value: Value,
|
||||
pub(crate) index: Index,
|
||||
}
|
||||
|
||||
impl<Value: Rle, Index: GlobalIndex> HasLength for WithGlobalIndex<Value, Index> {
|
||||
|
@ -47,7 +47,7 @@ impl<Value: Rle, Index: GlobalIndex> HasGlobalIndex for WithGlobalIndex<Value, I
|
|||
|
||||
#[repr(transparent)]
|
||||
pub struct RangeMap<Index: GlobalIndex + 'static, Value: Rle + 'static> {
|
||||
tree:
|
||||
pub(crate) tree:
|
||||
RleTree<WithGlobalIndex<Value, Index>, GlobalTreeTrait<WithGlobalIndex<Value, Index>, 10>>,
|
||||
}
|
||||
|
||||
|
@ -104,10 +104,18 @@ impl<Index: GlobalIndex + 'static, Value: Rle + 'static> RangeMap<Index, Value>
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct WithStartEnd<Index: GlobalIndex, T> {
|
||||
start: Index,
|
||||
end: Index,
|
||||
value: T,
|
||||
pub start: Index,
|
||||
pub end: Index,
|
||||
pub value: T,
|
||||
}
|
||||
|
||||
impl<Index: GlobalIndex, T: Clone> WithStartEnd<Index, T> {
|
||||
#[inline]
|
||||
pub fn new(start: Index, end: Index, value: T) -> Self {
|
||||
Self { start, end, value }
|
||||
}
|
||||
}
|
||||
|
||||
impl<Index: GlobalIndex, T: Clone> Sliceable for WithStartEnd<Index, T> {
|
||||
|
|
|
@ -67,7 +67,7 @@ impl<'a, 'bump, T: Rle, A: RleTreeTrait<T>> Iterator for Iter<'a, 'bump, T, A> {
|
|||
match node.children.get(self.child_index) {
|
||||
Some(node) => {
|
||||
self.child_index += 1;
|
||||
return Some(node);
|
||||
return Some(*node);
|
||||
}
|
||||
None => match node.next() {
|
||||
Some(next) => {
|
||||
|
|
|
@ -135,7 +135,14 @@ impl<'a, T: Rle, A: RleTreeTrait<T>> Node<'a, T, A> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn merge_to_sibling(&mut self, sibling: &mut Node<'a, T, A>, either: Either) {
|
||||
pub(crate) fn merge_to_sibling<F>(
|
||||
&mut self,
|
||||
sibling: &mut Node<'a, T, A>,
|
||||
either: Either,
|
||||
notify: &mut F,
|
||||
) where
|
||||
F: FnMut(&T, *mut LeafNode<'a, T, A>),
|
||||
{
|
||||
if either == Either::Left {
|
||||
match sibling {
|
||||
Node::Internal(sibling) => {
|
||||
|
@ -149,6 +156,7 @@ impl<'a, T: Rle, A: RleTreeTrait<T>> Node<'a, T, A> {
|
|||
Node::Leaf(sibling) => {
|
||||
let self_node = self.as_leaf_mut().unwrap();
|
||||
for child in self_node.children.drain(..) {
|
||||
notify(child, sibling);
|
||||
sibling.children.push(child);
|
||||
}
|
||||
}
|
||||
|
@ -160,7 +168,7 @@ impl<'a, T: Rle, A: RleTreeTrait<T>> Node<'a, T, A> {
|
|||
let ptr = NonNull::new(&mut *sibling).unwrap();
|
||||
sibling.children.splice(
|
||||
0..0,
|
||||
self_node.children.drain(0..).rev().map(|x| {
|
||||
self_node.children.drain(0..).map(|x| {
|
||||
x.set_parent(ptr);
|
||||
x
|
||||
}),
|
||||
|
@ -168,9 +176,14 @@ impl<'a, T: Rle, A: RleTreeTrait<T>> Node<'a, T, A> {
|
|||
}
|
||||
Node::Leaf(sibling) => {
|
||||
let self_node = self.as_leaf_mut().unwrap();
|
||||
sibling
|
||||
.children
|
||||
.splice(0..0, self_node.children.drain(0..).rev());
|
||||
let sibling_ptr = sibling as *mut _;
|
||||
sibling.children.splice(
|
||||
0..0,
|
||||
self_node.children.drain(0..).map(|x| {
|
||||
notify(x, sibling_ptr);
|
||||
x
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -179,7 +192,14 @@ impl<'a, T: Rle, A: RleTreeTrait<T>> Node<'a, T, A> {
|
|||
sibling.update_cache();
|
||||
}
|
||||
|
||||
pub(crate) fn borrow_from_sibling(&mut self, sibling: &mut Node<'a, T, A>, either: Either) {
|
||||
pub(crate) fn borrow_from_sibling<F>(
|
||||
&mut self,
|
||||
sibling: &mut Node<'a, T, A>,
|
||||
either: Either,
|
||||
notify: &mut F,
|
||||
) where
|
||||
F: FnMut(&T, *mut LeafNode<'a, T, A>),
|
||||
{
|
||||
if either == Either::Left {
|
||||
match sibling {
|
||||
Node::Internal(sibling) => {
|
||||
|
@ -193,7 +213,11 @@ impl<'a, T: Rle, A: RleTreeTrait<T>> Node<'a, T, A> {
|
|||
}
|
||||
Node::Leaf(sibling) => {
|
||||
let self_node = self.as_leaf_mut().unwrap();
|
||||
let sibling_drain = sibling.children.drain(A::MIN_CHILDREN_NUM..);
|
||||
let self_ptr = self_node as *mut _;
|
||||
let sibling_drain = sibling.children.drain(A::MIN_CHILDREN_NUM..).map(|x| {
|
||||
notify(x, self_ptr);
|
||||
x
|
||||
});
|
||||
self_node.children.splice(0..0, sibling_drain);
|
||||
}
|
||||
}
|
||||
|
@ -219,9 +243,16 @@ impl<'a, T: Rle, A: RleTreeTrait<T>> Node<'a, T, A> {
|
|||
let self_node = self.as_leaf_mut().unwrap();
|
||||
let end = self_node.children.len();
|
||||
let sibling_len = sibling.children.len();
|
||||
let self_ptr = self_node as *mut _;
|
||||
self_node.children.splice(
|
||||
end..end,
|
||||
sibling.children.drain(0..sibling_len - A::MIN_CHILDREN_NUM),
|
||||
sibling
|
||||
.children
|
||||
.drain(0..sibling_len - A::MIN_CHILDREN_NUM)
|
||||
.map(|x| {
|
||||
notify(x, self_ptr);
|
||||
x
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -320,7 +320,7 @@ impl<'a, T: Rle, A: RleTreeTrait<T>> InternalNode<'a, T, A> {
|
|||
}
|
||||
};
|
||||
|
||||
let removed = self._root_shrink_levels_if_only_1_child();
|
||||
let removed = self._root_shrink_levels_if_one_child();
|
||||
|
||||
// filter the same
|
||||
let mut visited: HashSet<NonNull<_>> = HashSet::default();
|
||||
|
@ -366,10 +366,10 @@ impl<'a, T: Rle, A: RleTreeTrait<T>> InternalNode<'a, T, A> {
|
|||
let sibling: &mut Node<'a, T, A> =
|
||||
unsafe { &mut *((sibling as *const _) as usize as *mut _) };
|
||||
if node.children_num() + sibling.children_num() <= A::MAX_CHILDREN_NUM {
|
||||
node.merge_to_sibling(sibling, either);
|
||||
node.merge_to_sibling(sibling, either, notify);
|
||||
to_delete = true;
|
||||
} else {
|
||||
node.borrow_from_sibling(sibling, either);
|
||||
node.borrow_from_sibling(sibling, either, notify);
|
||||
}
|
||||
} else {
|
||||
if node.parent().unwrap().is_root() {
|
||||
|
@ -394,10 +394,10 @@ impl<'a, T: Rle, A: RleTreeTrait<T>> InternalNode<'a, T, A> {
|
|||
}
|
||||
}
|
||||
|
||||
self._root_shrink_levels_if_only_1_child();
|
||||
self._root_shrink_levels_if_one_child();
|
||||
}
|
||||
|
||||
fn _root_shrink_levels_if_only_1_child(&mut self) -> HashSet<*const InternalNode<'a, T, A>> {
|
||||
fn _root_shrink_levels_if_one_child(&mut self) -> HashSet<*const InternalNode<'a, T, A>> {
|
||||
let mut ans: HashSet<_> = Default::default();
|
||||
while self.children.len() == 1 && self.children[0].as_internal().is_some() {
|
||||
let child = self.children.pop().unwrap();
|
||||
|
|
|
@ -29,19 +29,19 @@ impl<'a, T: Rle, A: RleTreeTrait<T>> LeafNode<'a, T, A> {
|
|||
let ans = self
|
||||
.bump
|
||||
.alloc(Node::Leaf(Self::new(self.bump, self.parent)));
|
||||
let mut inner = ans.as_leaf_mut().unwrap();
|
||||
let ans_ptr = inner as _;
|
||||
let mut ans_inner = ans.as_leaf_mut().unwrap();
|
||||
let ans_ptr = ans_inner as _;
|
||||
for child in self
|
||||
.children
|
||||
.drain(self.children.len() - A::MIN_CHILDREN_NUM..self.children.len())
|
||||
{
|
||||
notify(child, ans_ptr);
|
||||
inner.children.push(child);
|
||||
ans_inner.children.push(child);
|
||||
}
|
||||
|
||||
inner.next = self.next;
|
||||
inner.prev = Some(NonNull::new(self).unwrap());
|
||||
self.next = Some(NonNull::new(&mut *inner).unwrap());
|
||||
ans_inner.next = self.next;
|
||||
ans_inner.prev = Some(NonNull::new(self).unwrap());
|
||||
self.next = Some(NonNull::new(&mut *ans_inner).unwrap());
|
||||
ans
|
||||
}
|
||||
|
||||
|
@ -61,10 +61,12 @@ impl<'a, T: Rle, A: RleTreeTrait<T>> LeafNode<'a, T, A> {
|
|||
where
|
||||
F: FnMut(&T, *mut LeafNode<'_, T, A>),
|
||||
{
|
||||
let self_ptr = self as *mut _;
|
||||
if !self.children.is_empty() {
|
||||
let last = self.children.last_mut().unwrap();
|
||||
if last.is_mergable(&value, &()) {
|
||||
last.merge(&value, &());
|
||||
notify(last, self_ptr);
|
||||
A::update_cache_leaf(self);
|
||||
return Ok(());
|
||||
}
|
||||
|
@ -80,6 +82,7 @@ impl<'a, T: Rle, A: RleTreeTrait<T>> LeafNode<'a, T, A> {
|
|||
}
|
||||
|
||||
self.children.push(self.bump.alloc(value));
|
||||
notify(self.children[self.children.len() - 1], self_ptr);
|
||||
A::update_cache_leaf(self);
|
||||
Ok(())
|
||||
}
|
||||
|
@ -109,6 +112,34 @@ impl<'a, T: Rle, A: RleTreeTrait<T>> LeafNode<'a, T, A> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn is_deleted(&self) -> bool {
|
||||
unsafe {
|
||||
let mut node = self.parent.as_ref();
|
||||
if !node
|
||||
.children
|
||||
.iter()
|
||||
.any(|x| std::ptr::eq(x.as_leaf().unwrap(), self))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
while let Some(parent) = node.parent {
|
||||
let parent = parent.as_ref();
|
||||
if !parent
|
||||
.children()
|
||||
.iter()
|
||||
.any(|x| std::ptr::eq(x.as_internal().unwrap(), node))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
node = parent;
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
pub fn insert<F>(
|
||||
&mut self,
|
||||
raw_index: A::Int,
|
||||
|
@ -141,22 +172,26 @@ impl<'a, T: Rle, A: RleTreeTrait<T>> LeafNode<'a, T, A> {
|
|||
F: FnMut(&T, *mut LeafNode<'_, T, A>),
|
||||
{
|
||||
if self.children.is_empty() {
|
||||
notify(&value, self);
|
||||
self.children.push(self.bump.alloc(value));
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let FindPosResult {
|
||||
child_index: mut index,
|
||||
mut child_index,
|
||||
mut offset,
|
||||
mut pos,
|
||||
..
|
||||
} = A::find_pos_leaf(self, raw_index);
|
||||
let self_ptr = self as *mut _;
|
||||
let prev = {
|
||||
if offset == 0 && index > 0 {
|
||||
Some(&mut self.children[index - 1])
|
||||
} else if offset == self.children[index].len() {
|
||||
index += 1;
|
||||
if (pos == Position::Start || pos == Position::Before) && child_index > 0 {
|
||||
Some(&mut self.children[child_index - 1])
|
||||
} else if pos == Position::After || pos == Position::End {
|
||||
child_index += 1;
|
||||
offset = 0;
|
||||
Some(&mut self.children[index - 1])
|
||||
pos = Position::Start;
|
||||
Some(&mut self.children[child_index - 1])
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
@ -166,39 +201,54 @@ impl<'a, T: Rle, A: RleTreeTrait<T>> LeafNode<'a, T, A> {
|
|||
// clean cut, should no split
|
||||
if prev.is_mergable(&value, &()) {
|
||||
prev.merge(&value, &());
|
||||
notify(prev, self_ptr);
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
let clean_cut = offset == 0 || offset == self.children[index].len();
|
||||
let clean_cut = pos != Position::Middle;
|
||||
if clean_cut {
|
||||
return self._insert_with_split(index, value, notify);
|
||||
return self._insert_with_split(child_index, value, notify);
|
||||
}
|
||||
|
||||
// need to split child
|
||||
let a = self.children[index].slice(0, offset);
|
||||
let b = self.children[index].slice(offset, self.children[index].len());
|
||||
self.children[index] = self.bump.alloc(a);
|
||||
let a = self.children[child_index].slice(0, offset);
|
||||
let b = self.children[child_index].slice(offset, self.children[child_index].len());
|
||||
self.children[child_index] = self.bump.alloc(a);
|
||||
|
||||
if self.children.len() >= A::MAX_CHILDREN_NUM - 1 {
|
||||
let node = self._split(notify);
|
||||
let leaf = node.as_leaf_mut().unwrap();
|
||||
if index < self.children.len() {
|
||||
self.children.insert(index + 1, self.bump.alloc(value));
|
||||
self.children.insert(index + 2, self.bump.alloc(b));
|
||||
leaf.children.insert(0, self.children.pop().unwrap());
|
||||
let next_node = self._split(notify);
|
||||
let next_leaf = next_node.as_leaf_mut().unwrap();
|
||||
if child_index < self.children.len() {
|
||||
notify(&value, self_ptr);
|
||||
notify(&b, self_ptr);
|
||||
self.children
|
||||
.insert(child_index + 1, self.bump.alloc(value));
|
||||
self.children.insert(child_index + 2, self.bump.alloc(b));
|
||||
|
||||
let last_child = self.children.pop().unwrap();
|
||||
notify(last_child, next_leaf);
|
||||
next_leaf.children.insert(0, last_child);
|
||||
} else {
|
||||
leaf.children
|
||||
.insert(index - self.children.len() + 1, self.bump.alloc(value));
|
||||
leaf.children
|
||||
.insert(index - self.children.len() + 2, self.bump.alloc(b));
|
||||
notify(&value, next_leaf);
|
||||
next_leaf.children.insert(
|
||||
child_index - self.children.len() + 1,
|
||||
self.bump.alloc(value),
|
||||
);
|
||||
notify(&b, next_leaf);
|
||||
next_leaf
|
||||
.children
|
||||
.insert(child_index - self.children.len() + 2, self.bump.alloc(b));
|
||||
}
|
||||
|
||||
return Err(node);
|
||||
return Err(next_node);
|
||||
}
|
||||
|
||||
self.children.insert(index + 1, self.bump.alloc(b));
|
||||
self.children.insert(index + 1, self.bump.alloc(value));
|
||||
notify(&b, self);
|
||||
notify(&value, self);
|
||||
self.children.insert(child_index + 1, self.bump.alloc(b));
|
||||
self.children
|
||||
.insert(child_index + 1, self.bump.alloc(value));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -258,8 +308,10 @@ impl<'a, T: Rle, A: RleTreeTrait<T>> LeafNode<'a, T, A> {
|
|||
.alloc(self.children[del_start - 1].slice(0, del_relative_from));
|
||||
}
|
||||
if let Some(del_relative_to) = del_relative_to {
|
||||
let self_ptr = self as *mut _;
|
||||
let end = &mut self.children[del_end];
|
||||
*end = self.bump.alloc(end.slice(del_relative_to, end.len()));
|
||||
notify(end, self_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -287,16 +339,18 @@ impl<'a, T: Rle, A: RleTreeTrait<T>> LeafNode<'a, T, A> {
|
|||
if self.children.len() == A::MAX_CHILDREN_NUM {
|
||||
let ans = self._split(notify);
|
||||
if index <= self.children.len() {
|
||||
notify(&value, self);
|
||||
self.children.insert(index, self.bump.alloc(value));
|
||||
} else {
|
||||
ans.as_leaf_mut()
|
||||
.unwrap()
|
||||
.children
|
||||
let leaf = ans.as_leaf_mut().unwrap();
|
||||
notify(&value, leaf);
|
||||
leaf.children
|
||||
.insert(index - self.children.len(), self.bump.alloc(value));
|
||||
}
|
||||
|
||||
Err(ans)
|
||||
} else {
|
||||
notify(&value, self);
|
||||
self.children.insert(index, self.bump.alloc(value));
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,11 +1,17 @@
|
|||
use proptest::prop_compose;
|
||||
use rand::{rngs::StdRng, SeedableRng};
|
||||
|
||||
use crate::{range_map::RangeMap, rle_tree::tree_trait::CumulateTreeTrait};
|
||||
use crate::{
|
||||
range_map::{RangeMap, WithStartEnd},
|
||||
rle_tree::tree_trait::CumulateTreeTrait,
|
||||
HasLength,
|
||||
};
|
||||
|
||||
use super::super::*;
|
||||
use std::{ops::Range, ptr::NonNull};
|
||||
use std::ptr::NonNull;
|
||||
|
||||
type RangeTreeTrait = CumulateTreeTrait<Range<usize>, 4>;
|
||||
type Value = WithStartEnd<usize, u64>;
|
||||
type ValueTreeTrait = CumulateTreeTrait<Value, 4>;
|
||||
|
||||
#[derive(enum_as_inner::EnumAsInner, Debug)]
|
||||
enum Interaction {
|
||||
|
@ -14,38 +20,100 @@ enum Interaction {
|
|||
}
|
||||
|
||||
impl Interaction {
|
||||
fn apply<F>(&self, tree: &mut RleTree<Range<usize>, RangeTreeTrait>, notify: &mut F)
|
||||
fn apply<F, R>(&self, tree: &mut RleTree<Value, ValueTreeTrait>, rng: &mut R, notify: &mut F)
|
||||
where
|
||||
F: FnMut(&Range<usize>, *mut LeafNode<'_, Range<usize>, RangeTreeTrait>),
|
||||
F: FnMut(&Value, *mut LeafNode<'_, Value, ValueTreeTrait>),
|
||||
R: rand::Rng,
|
||||
{
|
||||
match self {
|
||||
Interaction::Insert { from, len } => {
|
||||
tree.with_tree_mut(|tree| tree.insert_notify(*from, *from..*from + *len, notify))
|
||||
}
|
||||
Interaction::Insert { from, len } => tree.with_tree_mut(|tree| {
|
||||
let mut from = *from;
|
||||
let len = *len;
|
||||
if tree.len() == 0 {
|
||||
from = 0;
|
||||
} else {
|
||||
from %= tree.len();
|
||||
}
|
||||
tree.insert_notify(
|
||||
from,
|
||||
WithStartEnd {
|
||||
start: from,
|
||||
end: from + len,
|
||||
value: rng.next_u64(),
|
||||
},
|
||||
notify,
|
||||
);
|
||||
}),
|
||||
Interaction::Delete { from, len } => tree.with_tree_mut(|tree| {
|
||||
tree.delete_range_notify(Some(*from), Some(*from + *len), notify)
|
||||
let mut from = *from;
|
||||
let mut len = *len;
|
||||
if tree.len() == 0 {
|
||||
from = 0;
|
||||
} else {
|
||||
from %= tree.len();
|
||||
}
|
||||
if from + len > tree.len() {
|
||||
len = tree.len() - from;
|
||||
}
|
||||
tree.delete_range_notify(Some(from), Some(from + len), notify)
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn test(tree: &mut RleTree<Range<usize>, RangeTreeTrait>, interactions: &[Interaction]) {
|
||||
// let mut range_map: RangeMap<usize, NonNull<LeafNode<Range<usize>, RangeTreeTrait>>> =
|
||||
// Default::default();
|
||||
// let mut func = |range: &Range<usize>, node: *mut LeafNode<'_, Range<usize>, RangeTreeTrait>| {
|
||||
// let ptr = unsafe { NonNull::new_unchecked(node as usize as *mut _) };
|
||||
// range_map.set(range.start, ptr);
|
||||
// };
|
||||
// for interaction in interactions.iter() {
|
||||
// interaction.apply(tree, &mut func);
|
||||
// }
|
||||
fn test(interactions: &[Interaction]) {
|
||||
let mut tree: RleTree<Value, ValueTreeTrait> = Default::default();
|
||||
let mut rng = StdRng::seed_from_u64(123);
|
||||
type ValueIndex<'a> = WithStartEnd<u64, NonNull<LeafNode<'a, Value, ValueTreeTrait>>>;
|
||||
let mut range_map: RangeMap<u64, ValueIndex<'_>> = Default::default();
|
||||
for interaction in interactions.iter() {
|
||||
let mut func = |value: &Value, node: *mut LeafNode<'_, Value, ValueTreeTrait>| {
|
||||
let ptr = unsafe { NonNull::new_unchecked(node as usize as *mut _) };
|
||||
range_map.set(
|
||||
value.value,
|
||||
WithStartEnd::new(value.value, value.value + value.len() as u64, ptr),
|
||||
);
|
||||
//println!("bbb {:#?}", value);
|
||||
};
|
||||
interaction.apply(&mut tree, &mut rng, &mut func);
|
||||
//println!("----------------------------------");
|
||||
tree.with_tree(|tree| {
|
||||
for v in tree.iter() {
|
||||
//println!("tree: {:#?}", &v);
|
||||
let out = range_map.get(v.value);
|
||||
// if out.is_none() {
|
||||
// range_map.tree.with_tree(|range_tree| {
|
||||
//println!("range_tree: {:#?}", range_tree);
|
||||
// });
|
||||
// }
|
||||
|
||||
let out = out.unwrap();
|
||||
//println!("vs \nindexMap: {:#?}", &out);
|
||||
assert_eq!(v.value, out.start);
|
||||
}
|
||||
});
|
||||
|
||||
range_map.tree.with_tree(|range_tree| {
|
||||
for x in range_tree.iter() {
|
||||
unsafe {
|
||||
let leaf = x.value.value.as_ref();
|
||||
let value = leaf.children.iter().find(|v| v.value == x.index);
|
||||
if value.is_some() {
|
||||
assert!(!leaf.is_deleted());
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
//println!("========================================================================");
|
||||
}
|
||||
}
|
||||
|
||||
prop_compose! {
|
||||
fn gen_interaction()(
|
||||
_type in 0..1,
|
||||
from in 0..10000,
|
||||
len in 0..10,
|
||||
len in 1..10,
|
||||
) -> Interaction {
|
||||
if _type == 0 {
|
||||
Interaction::Insert {
|
||||
|
@ -60,3 +128,101 @@ prop_compose! {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
use Interaction::*;
|
||||
|
||||
#[test]
|
||||
fn issue_0() {
|
||||
test(&[
|
||||
Interaction::Insert { from: 0, len: 1 },
|
||||
Interaction::Insert { from: 0, len: 2 },
|
||||
]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn issue_1() {
|
||||
test(&[
|
||||
Interaction::Insert { from: 0, len: 3 },
|
||||
Interaction::Insert { from: 1, len: 1 },
|
||||
]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn issue_2() {
|
||||
test(&[
|
||||
Insert { from: 0, len: 5 },
|
||||
Insert { from: 0, len: 6 },
|
||||
Insert { from: 4, len: 3 },
|
||||
])
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn issue_3() {
|
||||
test(&[
|
||||
Insert { from: 0, len: 7 },
|
||||
Insert { from: 0, len: 4 },
|
||||
Insert { from: 0, len: 1 },
|
||||
Insert { from: 4, len: 2 },
|
||||
Insert { from: 0, len: 3 },
|
||||
Insert { from: 120, len: 1 },
|
||||
Insert { from: 1785, len: 1 },
|
||||
Insert { from: 6137, len: 1 },
|
||||
Insert { from: 2970, len: 5 },
|
||||
Insert { from: 2424, len: 5 },
|
||||
Insert { from: 2246, len: 4 },
|
||||
Insert { from: 104, len: 1 },
|
||||
Insert { from: 447, len: 1 },
|
||||
Insert { from: 5394, len: 3 },
|
||||
Insert { from: 113, len: 6 },
|
||||
Insert { from: 6563, len: 7 },
|
||||
Insert { from: 8964, len: 1 },
|
||||
Insert { from: 0, len: 1 },
|
||||
Insert { from: 0, len: 1 },
|
||||
Insert { from: 0, len: 1 },
|
||||
Insert { from: 0, len: 1 },
|
||||
Insert { from: 0, len: 1 },
|
||||
Insert { from: 0, len: 1 },
|
||||
Insert { from: 0, len: 1 },
|
||||
Insert { from: 0, len: 1 },
|
||||
Insert { from: 0, len: 1 },
|
||||
Insert { from: 0, len: 1 },
|
||||
Insert { from: 0, len: 1 },
|
||||
Insert { from: 0, len: 1 },
|
||||
Insert { from: 0, len: 1 },
|
||||
Insert { from: 0, len: 1 },
|
||||
Insert { from: 0, len: 1 },
|
||||
Insert { from: 0, len: 1 },
|
||||
Insert { from: 0, len: 1 },
|
||||
Insert { from: 0, len: 1 },
|
||||
Insert { from: 0, len: 1 },
|
||||
Insert { from: 0, len: 1 },
|
||||
Insert { from: 0, len: 1 },
|
||||
Insert { from: 0, len: 1 },
|
||||
Insert { from: 0, len: 1 },
|
||||
Insert { from: 0, len: 1 },
|
||||
Insert { from: 0, len: 1 },
|
||||
Insert { from: 0, len: 1 },
|
||||
Insert { from: 0, len: 1 },
|
||||
Insert { from: 0, len: 1 },
|
||||
Insert { from: 0, len: 1 },
|
||||
Insert { from: 0, len: 1 },
|
||||
Insert { from: 0, len: 1 },
|
||||
Insert { from: 0, len: 1 },
|
||||
Insert { from: 0, len: 1 },
|
||||
]);
|
||||
}
|
||||
|
||||
#[cfg(not(no_proptest))]
|
||||
mod notify_proptest {
|
||||
use super::*;
|
||||
use proptest::prelude::*;
|
||||
|
||||
proptest! {
|
||||
#[test]
|
||||
fn test_notify(
|
||||
interactions in prop::collection::vec(gen_interaction(), 1..100),
|
||||
) {
|
||||
test(&interactions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -69,6 +69,7 @@ pub trait RleTreeTrait<T: Rle>: Sized + Debug {
|
|||
/// - if `pos == Middle`, we need to split the node
|
||||
/// - We need the third arg to determine whether the child is included or excluded
|
||||
/// - If not found, then `found` should be false and `child_index` should be the index of the insert position
|
||||
/// - If target index is after last child, then `child_index` = children.len().wrapping_sub(1), `offset` = children.last().unwrap().len()
|
||||
fn find_pos_leaf(node: &LeafNode<'_, T, Self>, index: Self::Int) -> FindPosResult<usize>;
|
||||
|
||||
fn len_leaf(node: &LeafNode<'_, T, Self>) -> Self::Int;
|
||||
|
@ -227,6 +228,11 @@ impl<T: Rle + HasGlobalIndex, const MAX_CHILD: usize> RleTreeTrait<T>
|
|||
type LeafCache = Cache<T::Int>;
|
||||
|
||||
fn update_cache_leaf(node: &mut LeafNode<'_, T, Self>) {
|
||||
if node.children.is_empty() {
|
||||
node.cache.end = node.cache.start;
|
||||
return;
|
||||
}
|
||||
|
||||
node.cache.end = node
|
||||
.children()
|
||||
.iter()
|
||||
|
@ -291,7 +297,11 @@ impl<T: Rle + HasGlobalIndex, const MAX_CHILD: usize> RleTreeTrait<T>
|
|||
}
|
||||
}
|
||||
|
||||
FindPosResult::new_not_found(node.children.len().saturating_sub(1), 0, Position::After)
|
||||
FindPosResult::new_not_found(
|
||||
node.children.len().saturating_sub(1),
|
||||
node.children().last().unwrap().len(),
|
||||
Position::After,
|
||||
)
|
||||
}
|
||||
|
||||
fn len_leaf(node: &LeafNode<'_, T, Self>) -> Self::Int {
|
||||
|
|
2
justfile
2
justfile
|
@ -6,7 +6,7 @@ test *FLAGS:
|
|||
|
||||
# test without proptest
|
||||
test-fast *FLAGS:
|
||||
RUSTFLAGS='--cfg no_prop_test' cargo nextest run {{FLAGS}}
|
||||
RUSTFLAGS='--cfg no_proptest' cargo nextest run {{FLAGS}}
|
||||
|
||||
# test with slower proptest
|
||||
test-slow *FLAGS:
|
||||
|
|
Loading…
Reference in a new issue