From cf3e3ee3616de9c07c4442e396a5c7da478367d3 Mon Sep 17 00:00:00 2001 From: Zixuan Chen Date: Sat, 22 Oct 2022 02:07:26 +0800 Subject: [PATCH] fix: vec slice bug --- .../loro-core/src/container/text/tracker.rs | 8 +- .../src/container/text/tracker/content_map.rs | 16 +++ .../src/container/text/tracker/y_span.rs | 97 +--------------- .../src/container/text/tracker/yata_impl.rs | 107 +++++++++--------- crates/loro-core/src/macros.rs | 4 +- crates/rle/src/rle_trait.rs | 9 +- crates/rle/src/rle_tree/node/leaf_impl.rs | 30 ++++- 7 files changed, 112 insertions(+), 159 deletions(-) diff --git a/crates/loro-core/src/container/text/tracker.rs b/crates/loro-core/src/container/text/tracker.rs index a626f849..8f42f4e7 100644 --- a/crates/loro-core/src/container/text/tracker.rs +++ b/crates/loro-core/src/container/text/tracker.rs @@ -278,9 +278,11 @@ impl Tracker { } } - self.content.update_at_cursors( - &mut cursors, - &mut |v| { + let len = cursors.len(); + self.content.update_at_cursors_with_args( + &cursors, + &vec![(); len], + &mut |v, _| { v.status.apply(change); }, &mut make_notify(&mut self.id_to_cursor), diff --git a/crates/loro-core/src/container/text/tracker/content_map.rs b/crates/loro-core/src/container/text/tracker/content_map.rs index ad085619..309569c0 100644 --- a/crates/loro-core/src/container/text/tracker/content_map.rs +++ b/crates/loro-core/src/container/text/tracker/content_map.rs @@ -134,6 +134,22 @@ impl ContentMap { } } + assert_eq!(len, ans.len()); + ans + } + + pub fn get_id_spans(&self, pos: usize, len: usize) -> RleVec { + let mut ans = RleVec::new(); + for cursor in self.iter_range(pos, Some(pos + len)) { + let id = cursor.as_ref().id; + let cursor = cursor.unwrap(); + ans.push(IdSpan::new( + id.client_id, + id.counter + (cursor.offset as i32), + id.counter + (cursor.offset + cursor.len) as i32, + )); + } + ans } } diff --git a/crates/loro-core/src/container/text/tracker/y_span.rs b/crates/loro-core/src/container/text/tracker/y_span.rs index 8ffa114f..78b81e97 100644 --- a/crates/loro-core/src/container/text/tracker/y_span.rs +++ b/crates/loro-core/src/container/text/tracker/y_span.rs @@ -177,101 +177,8 @@ impl HasLength for YSpan { } } -#[cfg(test)] -mod test { - use std::borrow::Cow; - - use tabled::{Style, Table, Tabled}; - impl Tabled for YSpan { - const LENGTH: usize = 7; - - fn fields(&self) -> Vec> { - vec![ - self.id.to_string().into(), - self.len.to_string().into(), - self.status.future.to_string().into(), - self.status.delete_times.to_string().into(), - self.status.undo_times.to_string().into(), - self.origin_left - .map(|id| id.to_string()) - .unwrap_or_default() - .into(), - self.origin_right - .map(|id| id.to_string()) - .unwrap_or_default() - .into(), - ] - } - - fn headers() -> Vec> { - vec![ - "id".into(), - "len".into(), - "future".into(), - "del".into(), - "undo".into(), - "origin\nleft".into(), - "origin\nright".into(), - ] - } - } - - #[test] - fn test_table() { - let y_spans = vec![ - YSpan { - id: ID::new(1, 0), - len: 1, - status: Status::new(), - origin_left: None, - origin_right: None, - slice: Default::default(), - }, - YSpan { - id: ID::new(1, 1), - len: 1, - status: Status::new(), - origin_left: Some(ID { - client_id: 0, - counter: 2, - }), - origin_right: None, - slice: Default::default(), - }, - YSpan { - id: ID::new(1, 2), - len: 1, - status: Status { - future: true, - delete_times: 5, - undo_times: 3, - }, - origin_left: None, - origin_right: None, - slice: Default::default(), - }, - YSpan { - id: ID::new(1, 3), - len: 1, - status: Status::new(), - origin_left: None, - origin_right: None, - slice: Default::default(), - }, - YSpan { - id: ID::new(1, 4), - len: 1, - status: Status::new(), - origin_left: None, - origin_right: None, - slice: Default::default(), - }, - ]; - let mut t = Table::new(y_spans); - t.with(Style::rounded()); - println!("{}", &t) - } - +#[cfg(any(test, features = "fuzzing"))] +pub mod test { use crate::{ container::{ContainerID, ContainerType}, id::ROOT_ID, diff --git a/crates/loro-core/src/container/text/tracker/yata_impl.rs b/crates/loro-core/src/container/text/tracker/yata_impl.rs index 35608b2f..ee318f70 100644 --- a/crates/loro-core/src/container/text/tracker/yata_impl.rs +++ b/crates/loro-core/src/container/text/tracker/yata_impl.rs @@ -165,20 +165,56 @@ mod test { #[cfg(feature = "fuzzing")] pub mod fuzz { - #![allow(unused_imports)] - use crdt_list::{ - test::{Action, TestFramework}, - yata::Yata, - }; + use std::borrow::Cow; + use tabled::Tabled; + impl Tabled for YSpan { + const LENGTH: usize = 7; + + fn fields(&self) -> Vec> { + vec![ + self.id.to_string().into(), + self.len.to_string().into(), + self.status.future.to_string().into(), + self.status.delete_times.to_string().into(), + self.status.undo_times.to_string().into(), + self.origin_left + .map(|id| id.to_string()) + .unwrap_or_default() + .into(), + self.origin_right + .map(|id| id.to_string()) + .unwrap_or_default() + .into(), + ] + } + + fn headers() -> Vec> { + vec![ + "id".into(), + "len".into(), + "future".into(), + "del".into(), + "undo".into(), + "origin\nleft".into(), + "origin\nright".into(), + ] + } + } + + use crdt_list::test::{Action, TestFramework}; use rle::RleVec; + use tabled::TableIteratorExt; use crate::{ container::text::{ text_content::ListSlice, - tracker::{y_span::StatusChange, Tracker}, + tracker::{ + y_span::{StatusChange, YSpan}, + Tracker, + }, }, id::{ClientID, ID}, - span::{self, IdSpan}, + span::IdSpan, }; use super::YataImpl; @@ -230,8 +266,8 @@ pub mod fuzz { if aa != bb { dbg!(a.client_id); dbg!(b.client_id); - dbg!(aa.vec()); - dbg!(bb.vec()); + println!("{}", aa.vec().table()); + println!("{}", bb.vec().table()); // dbg!(&a.content); // dbg!(&b.content); } @@ -300,52 +336,17 @@ pub mod fuzz { 5, 100, vec![ - NewOp { - client_id: 255, - pos: 11, - }, - NewOp { - client_id: 255, - pos: 252, - }, - NewOp { - client_id: 255, - pos: 64, - }, - NewOp { - client_id: 151, - pos: 151, - }, - NewOp { - client_id: 151, - pos: 151, - }, - NewOp { - client_id: 255, - pos: 252, - }, - NewOp { - client_id: 151, - pos: 158, - }, - NewOp { - client_id: 254, - pos: 121, - }, - NewOp { - client_id: 3, - pos: 255, - }, - NewOp { - client_id: 0, - pos: 144, - }, Delete { - client_id: 255, - pos: 255, - len: 134, + client_id: 2, + pos: 58, + len: 177, + }, + Sync { from: 2, to: 0 }, + Delete { + client_id: 0, + pos: 255, + len: 255, }, - Sync { from: 29, to: 29 }, ], ) } diff --git a/crates/loro-core/src/macros.rs b/crates/loro-core/src/macros.rs index 8fa687a7..d2faba86 100644 --- a/crates/loro-core/src/macros.rs +++ b/crates/loro-core/src/macros.rs @@ -31,8 +31,8 @@ macro_rules! debug_log { ($($arg:tt)*) => {{ if cfg!(test) { use colored::Colorize; - print!("{}:{}\t", file!().purple(), line!().to_string().purple()); - println!($($arg)*); + // print!("{}:{}\t", file!().purple(), line!().to_string().purple()); + // println!($($arg)*); } }}; } diff --git a/crates/rle/src/rle_trait.rs b/crates/rle/src/rle_trait.rs index 8d4e5901..3e07d6e5 100644 --- a/crates/rle/src/rle_trait.rs +++ b/crates/rle/src/rle_trait.rs @@ -103,12 +103,15 @@ impl HasLength for &T { impl> Sliceable for SmallVec { fn slice(&self, from: usize, to: usize) -> Self { let mut index = 0; - let mut ans = smallvec::smallvec![]; + let mut ans: SmallVec = smallvec::smallvec![]; + if to == from { + return ans; + } + for item in self.iter() { if index < to && from < index + item.content_len() { let start = if index < from { from - index } else { 0 }; - let len = (item.content_len() - start).min(to - index); - ans.push(item.slice(start, start + len)); + ans.push(item.slice(start, item.content_len().min(to - index))); } index += item.content_len(); diff --git a/crates/rle/src/rle_tree/node/leaf_impl.rs b/crates/rle/src/rle_tree/node/leaf_impl.rs index be5237c5..42a0f1f5 100644 --- a/crates/rle/src/rle_tree/node/leaf_impl.rs +++ b/crates/rle/src/rle_tree/node/leaf_impl.rs @@ -5,7 +5,7 @@ use crate::{ cursor::SafeCursorMut, tree_trait::{FindPosResult, Position}, }, - Sliceable, + HasLength, Sliceable, }; use std::fmt::{Debug, Error, Formatter}; @@ -427,8 +427,9 @@ impl<'bump, T: Rle, A: RleTreeTrait> LeafNode<'bump, T, A> { return None; } - let mut ans = SmallVec::new(); + let mut ans: SmallVec<[T; 2]> = SmallVec::new(); ans.push(self.children[child_index].clone()); + let ans_len = self.children[child_index].content_len(); for i in 0..offsets.len() { let offset = offsets[i]; let len = lens[i]; @@ -439,12 +440,13 @@ impl<'bump, T: Rle, A: RleTreeTrait> LeafNode<'bump, T, A> { update_fn(span, arg); } - let mut end = ans.slice(offset + len, ans.len()); + let mut end = ans.slice(offset + len, ans_len); ans = ans.slice(0, offset); ans.append(&mut target_spans); ans.append(&mut end); } + debug_assert_eq!(ans_len, ans.iter().map(|x| x.content_len()).sum()); Some(ans) } @@ -789,3 +791,25 @@ impl<'a, T: Rle, A: RleTreeTrait> Debug for LeafNode<'a, T, A> { debug_struct.finish() } } + +fn slice( + vec: &[T], + beginning: usize, + from: usize, + to: usize, +) -> SmallVec<[T; 2]> { + let mut index = beginning; + let mut ans = smallvec::smallvec![]; + dbg!(from, to); + for item in vec.iter() { + if index < to && from < index + item.content_len() { + let start = if index < from { from - index } else { 0 }; + let len = (item.content_len() - start).min(to - index); + ans.push(item.slice(start, start + len)); + } + + index += item.content_len(); + } + + ans +}