fix: notify

This commit is contained in:
Zixuan Chen 2022-09-08 18:24:19 +08:00
parent 8f005180a4
commit 77eac9eb30
9 changed files with 346 additions and 76 deletions

View file

@ -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"

View file

@ -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> {

View file

@ -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) => {

View file

@ -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
}),
);
}
}

View file

@ -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();

View file

@ -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(())
}

View file

@ -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);
}
}
}

View file

@ -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 {

View file

@ -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: