feat: iter update in rle tree

This commit is contained in:
Zixuan Chen 2022-10-11 16:50:22 +08:00
parent ee5c9bb990
commit bc980c5b02
15 changed files with 351 additions and 23 deletions

1
Cargo.lock generated
View file

@ -786,6 +786,7 @@ dependencies = [
name = "rle"
version = "0.1.0"
dependencies = [
"arref",
"bumpalo",
"color-backtrace",
"ctor",

View file

@ -525,6 +525,7 @@ dependencies = [
name = "rle"
version = "0.1.0"
dependencies = [
"arref",
"bumpalo",
"enum-as-inner",
"num",

View file

@ -98,7 +98,9 @@ impl Tracker {
}
TextOpContent::Delete { id, pos, len } => {
let spans = self.content.get_id_spans(*pos, *len);
todo!()
self.update_spans(&spans, StatusChange::Delete);
self.id_to_cursor
.set((*id).into(), cursor_map::Marker::Delete(spans));
}
}
}
@ -109,14 +111,26 @@ impl Tracker {
}
pub fn update_spans(&mut self, spans: &RleVec<IdSpan>, change: StatusChange) {
let mut cursors = Vec::new();
for span in spans.iter() {
let mut span_start = span.min_id();
for marker in self
.id_to_cursor
.get_range(span.min_id().into(), span.max_id().into())
{
todo!()
let cursor = marker.as_cursor(span_start).unwrap().unwrap();
span_start = span_start.inc(cursor.len as Counter);
cursors.push(cursor);
}
}
self.content.update_at_cursors(
cursors,
&mut |v| {
v.status.apply(change);
},
&mut make_notify(&mut self.id_to_cursor),
)
}
}

View file

@ -141,7 +141,7 @@ impl ContentMap {
}
}
pub fn get_id_spans(&mut self, pos: usize, len: usize) -> RleVec<IdSpan> {
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)) {
ans.push(IdSpan::new(

View file

@ -181,7 +181,7 @@ pub mod fuzz {
use rle::RleVec;
use crate::{
container::text::tracker::Tracker,
container::text::tracker::{y_span::StatusChange, Tracker},
id::{ClientID, ID},
span::IdSpan,
};
@ -241,16 +241,30 @@ pub mod fuzz {
type DeleteOp = RleVec<IdSpan>;
fn new_del_op(container: &Self::Container, pos: usize, len: usize) -> Self::DeleteOp {
todo!()
fn new_del_op(
container: &Self::Container,
mut pos: usize,
mut len: usize,
) -> Self::DeleteOp {
if container.content.len() == 0 {
return RleVec::new();
}
pos %= container.content.len();
len = std::cmp::min(len, container.content.len() - pos);
if len == 0 {
return RleVec::new();
}
container.content.get_id_spans(pos, len)
}
fn integrate_delete_op(container: &mut Self::Container, op: Self::DeleteOp) {
todo!()
container.update_spans(&op, StatusChange::Delete);
}
fn can_apply_del_op(container: &Self::Container, op: &Self::DeleteOp) -> bool {
todo!()
op.iter().all(|x| container.vv.includes(x.max_id()))
}
}

View file

@ -3,7 +3,7 @@ use std::{
ops::{Deref, DerefMut},
};
use fxhash::{FxHashMap};
use fxhash::FxHashMap;
use im::hashmap::HashMap as ImHashMap;
use crate::{
@ -140,8 +140,8 @@ impl VersionVector {
}
}
pub fn includes(&mut self, id: ID) -> bool {
if let Some(end) = self.get_mut(&id.client_id) {
pub fn includes(&self, id: ID) -> bool {
if let Some(end) = self.get(&id.client_id) {
if *end > id.counter {
return true;
}

View file

@ -10,6 +10,7 @@ bumpalo = { version = "3.10.0", features = ["collections", "boxed"] }
num = "0.4.0"
enum-as-inner = "0.5.1"
ouroboros = "0.15.2"
arref = "0.1.0"
[dev-dependencies]
color-backtrace = { version = "0.5" }

View file

@ -10,7 +10,7 @@ use smartstring::SmartString;
type SString = SmartString<smartstring::LazyCompact>;
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct CustomString {
str: Rc<RefCell<SString>>,
slice: Range<usize>,

View file

@ -5,7 +5,7 @@ use crate::{
HasLength, Mergable, Rle, RleTree, Sliceable,
};
#[derive(Debug)]
#[derive(Debug, Clone)]
pub(crate) struct WithGlobalIndex<Value, Index: GlobalIndex> {
pub(crate) value: Value,
pub(crate) index: Index,
@ -118,7 +118,7 @@ impl<Index: GlobalIndex + 'static, Value: Rle + 'static> RangeMap<Index, Value>
}
}
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct WithStartEnd<Index: GlobalIndex, T> {
pub start: Index,
pub end: Index,
@ -169,7 +169,7 @@ mod test {
use std::ops::Range;
use super::*;
#[derive(Debug, PartialEq, Eq)]
#[derive(Debug, PartialEq, Eq, Clone)]
struct V {
from: usize,
to: usize,

View file

@ -43,9 +43,9 @@ pub trait HasLength {
fn len(&self) -> usize;
}
pub trait Rle<Cfg = ()>: HasLength + Sliceable + Mergable<Cfg> + Debug {}
pub trait Rle<Cfg = ()>: HasLength + Sliceable + Mergable<Cfg> + Debug + Clone {}
impl<T: HasLength + Sliceable + Mergable<Cfg> + Debug, Cfg> Rle<Cfg> for T {}
impl<T: HasLength + Sliceable + Mergable<Cfg> + Debug + Clone, Cfg> Rle<Cfg> for T {}
impl<T: Integer + NumCast + Copy> Sliceable for Range<T> {
fn slice(&self, start: usize, end: usize) -> Self {

View file

@ -1,3 +1,5 @@
use std::{collections::HashMap, ptr::NonNull};
use self::node::{InternalNode, LeafNode, Node};
use crate::Rle;
pub(self) use bumpalo::collections::vec::Vec as BumpVec;
@ -227,6 +229,93 @@ impl<T: Rle, A: RleTreeTrait<T>> RleTree<T, A> {
}
}
pub fn update_at_cursors<U, F>(
&mut self,
cursors: Vec<UnsafeCursor<T, A>>,
update_fn: &mut U,
notify: &mut F,
) where
U: FnMut(&mut T),
F: FnMut(&T, *mut LeafNode<T, A>),
{
let mut updates_map: HashMap<NonNull<_>, Vec<(usize, Vec<T>)>> = Default::default();
for cursor in cursors {
// SAFETY: we has the exclusive reference to the tree and the cursor is valid
let updates = unsafe {
cursor
.leaf
.as_ref()
.pure_update(cursor.index, cursor.offset, cursor.len, update_fn)
};
if let Some(update) = updates {
updates_map
.entry(cursor.leaf)
.or_default()
.push((cursor.index, update));
}
}
let mut internal_updates_map: HashMap<
NonNull<_>,
Vec<(usize, Vec<&'_ mut Node<'_, T, A>>)>,
> = Default::default();
for (mut leaf, updates) in updates_map {
// SAFETY: we has the exclusive reference to the tree and the cursor is valid
let leaf = unsafe { leaf.as_mut() };
if let Err(new) = leaf.apply_updates(updates, notify) {
internal_updates_map
.entry(leaf.parent)
.or_default()
.push((leaf.get_index_in_parent().unwrap(), new));
} else {
// insert empty value to trigger cache update
internal_updates_map.insert(leaf.parent, Default::default());
}
}
while !internal_updates_map.is_empty() {
let updates_map = std::mem::take(&mut internal_updates_map);
for (mut node, updates) in updates_map {
// SAFETY: we has the exclusive reference to the tree and the cursor is valid
let node = unsafe { node.as_mut() };
if updates.is_empty() {
A::update_cache_internal(node);
continue;
}
if let Err(new) = node.apply_updates(updates) {
internal_updates_map
.entry(node.parent.unwrap())
.or_default()
.push((node.get_index_in_parent().unwrap(), new));
} else {
// insert empty value to trigger cache update
internal_updates_map.insert(node.parent.unwrap(), Default::default());
}
}
}
}
pub fn iter_update<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
self.update_at_cursors(unsafe { std::mem::transmute(cursors) }, update_fn, notify);
}
pub fn debug_check(&mut self) {
self.with_node_mut(|node| {
node.as_internal_mut().unwrap().check();

View file

@ -1,3 +1,5 @@
use std::marker::PhantomData;
use crate::Rle;
use super::{

View file

@ -65,13 +65,14 @@ impl<'a, T: Rle, A: RleTreeTrait<T>> InternalNode<'a, T, A> {
"children.len() = {}",
self.children.len()
);
assert!(
self.children.len() <= A::MAX_CHILDREN_NUM,
"children.len() = {}",
self.children.len()
);
}
assert!(
self.children.len() <= A::MAX_CHILDREN_NUM,
"children.len() = {}",
self.children.len()
);
let self_ptr = self as *const _;
for child in self.children.iter_mut() {
match child {
@ -217,6 +218,69 @@ impl<'a, T: Rle, A: RleTreeTrait<T>> InternalNode<'a, T, A> {
result
}
pub(crate) fn apply_updates(
&mut self,
mut updates: Vec<(usize, Vec<&'a mut Node<'a, T, A>>)>,
) -> Result<(), Vec<&'a mut Node<'a, T, A>>> {
updates.sort_by_key(|x| x.0);
let mut new_children: Vec<&'a mut Node<'a, T, A>> = Vec::new();
let mut self_children = std::mem::replace(&mut self.children, BumpVec::new_in(self.bump));
let mut last_end = 0;
for (index, replace) in updates {
let should_pop = index - last_end < self_children.len();
for child in self_children.drain(0..index - last_end + 1) {
new_children.push(child);
}
if should_pop {
new_children.pop();
}
for element in replace {
new_children.push(element);
}
last_end = index + 1;
}
let result = if new_children.len() <= A::MAX_CHILDREN_NUM {
for child in new_children {
self.children.push(child);
}
A::update_cache_internal(self);
Ok(())
} else {
for child in new_children.drain(0..A::MAX_CHILDREN_NUM) {
self.children.push(child);
}
A::update_cache_internal(self);
let mut ans_vec = Vec::new();
while !new_children.is_empty() {
let mut new_leaf = InternalNode::new(self.bump, self.parent);
for child in new_children.drain(0..A::MAX_CHILDREN_NUM) {
new_leaf.children.push(child);
}
A::update_cache_internal(&mut new_leaf);
ans_vec.push(self.bump.alloc(Node::Internal(new_leaf)));
}
Err(ans_vec)
};
if result.is_err() && self.is_root() {
let mut new = result.unwrap_err();
assert!(new.len() == 1);
let v = new.pop().unwrap();
self._create_level(v);
Ok(())
} else {
result
}
}
/// connect [prev leaf of left] with [next leaf of right]
fn connect_leaf(&mut self, left_index: usize, right_index: usize) {
let prev = self.children[left_index]

View file

@ -117,6 +117,7 @@ impl<'bump, T: Rle, A: RleTreeTrait<T>> LeafNode<'bump, T, A> {
pub(crate) fn check(&self) {
assert!(self.children.len() <= A::MAX_CHILDREN_NUM);
// assert!(self.children.len() >= A::MIN_CHILDREN_NUM);
assert!(!self.is_deleted());
A::check_cache_leaf(self);
if let Some(next) = self.next {
@ -338,6 +339,147 @@ impl<'bump, T: Rle, A: RleTreeTrait<T>> LeafNode<'bump, T, A> {
}
}
/// this is a effect-less operation, it will not modify the data, it returns the needed change at the given index instead
pub(crate) fn pure_update<U>(
&self,
child_index: usize,
offset: usize,
len: usize,
update_fn: &mut U,
) -> Option<Vec<T>>
where
U: FnMut(&mut T),
{
let mut ans = vec![];
if len == 0 {
return None;
}
let child = &self.children[child_index];
if offset == 0 && child.len() == len {
let mut element = child.slice(0, len);
update_fn(&mut element);
ans.push(element);
return Some(ans);
}
if offset != 0 {
ans.push(child.slice(0, offset));
}
let mut target = child.slice(offset, offset + len);
update_fn(&mut target);
if !ans.is_empty() {
if ans[0].is_mergable(&target, &()) {
ans[0].merge(&target, &());
} else {
ans.push(target);
}
}
if offset + len < child.len() {
let right = child.slice(offset + len, child.len());
let mut merged = false;
if let Some(last) = ans.last_mut() {
if last.is_mergable(&right, &()) {
merged = true;
last.merge(&right, &());
}
}
if !merged {
ans.push(right);
}
}
Some(ans)
}
pub(crate) fn apply_updates<F>(
&mut self,
mut updates: Vec<(usize, Vec<T>)>,
notify: &mut F,
) -> Result<(), Vec<&'bump mut Node<'bump, T, A>>>
where
F: FnMut(&T, *mut LeafNode<'_, T, A>),
{
updates.sort_by_key(|x| x.0);
let mut i = 0;
let mut j = 1;
// try merge sibling updates
while i + j < updates.len() {
if updates[i].0 + j == updates[i + j].0 {
let (a, b) = arref::array_mut_ref!(&mut updates, [i, i + j]);
for node in b.1.drain(..) {
a.1.push(node);
}
j += 1;
} else {
i += j;
j = 1;
}
}
let mut new_children: Vec<&mut T> = Vec::new();
let mut self_children = std::mem::replace(&mut self.children, BumpVec::new_in(self.bump));
let mut last_end = 0;
for (index, replace) in updates {
let should_pop = index - last_end < self_children.len();
for child in self_children.drain(0..index - last_end + 1) {
new_children.push(child);
}
if should_pop {
new_children.pop();
}
for element in replace {
let mut merged = false;
if let Some(last) = new_children.last_mut() {
if last.is_mergable(&element, &()) {
last.merge(&element, &());
merged = true;
}
}
if !merged {
new_children.push(self.bump.alloc(element));
}
}
last_end = index + 1;
}
if new_children.len() <= A::MAX_CHILDREN_NUM {
for child in new_children {
notify(child, self);
self.children.push(child);
}
A::update_cache_leaf(self);
Ok(())
} else {
for child in new_children.drain(0..A::MAX_CHILDREN_NUM) {
notify(child, self);
self.children.push(child);
}
A::update_cache_leaf(self);
let mut leaf_vec = Vec::new();
while !new_children.is_empty() {
let mut new_leaf = LeafNode::new(self.bump, self.parent);
for child in new_children.drain(0..A::MAX_CHILDREN_NUM) {
notify(child, &mut new_leaf);
new_leaf.children.push(child);
}
A::update_cache_leaf(&mut new_leaf);
leaf_vec.push(self.bump.alloc(Node::Leaf(new_leaf)));
}
Err(leaf_vec)
}
}
fn with_cache_updated(
&mut self,
result: Result<(), &'bump mut Node<'bump, T, A>>,

View file

@ -5,7 +5,7 @@ use std::{
use crate::{rle_tree::tree_trait::CumulateTreeTrait, HasLength, Mergable, RleTree, Sliceable};
#[derive(Debug)]
#[derive(Debug, Clone)]
struct CustomString(String);
impl Deref for CustomString {
type Target = String;