fix: vec slice bug

This commit is contained in:
Zixuan Chen 2022-10-22 02:07:26 +08:00
parent a9d57bfc14
commit cf3e3ee361
7 changed files with 112 additions and 159 deletions

View file

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

View file

@ -134,6 +134,22 @@ impl ContentMap {
}
}
assert_eq!(len, ans.len());
ans
}
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)) {
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
}
}

View file

@ -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<std::borrow::Cow<'_, str>> {
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<Cow<'static, str>> {
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,

View file

@ -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<std::borrow::Cow<'_, str>> {
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<Cow<'static, str>> {
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 },
],
)
}

View file

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

View file

@ -103,12 +103,15 @@ impl<T: HasLength> HasLength for &T {
impl<T: HasLength + Sliceable, A: Array<Item = T>> Sliceable for SmallVec<A> {
fn slice(&self, from: usize, to: usize) -> Self {
let mut index = 0;
let mut ans = smallvec::smallvec![];
let mut ans: SmallVec<A> = 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();

View file

@ -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<T>> 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<T>> 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<T>> Debug for LeafNode<'a, T, A> {
debug_struct.finish()
}
}
fn slice<T: HasLength + Sliceable>(
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
}