mirror of
https://github.com/loro-dev/loro.git
synced 2024-11-28 17:41:49 +00:00
refactor: use list slice
This commit is contained in:
parent
5a95a3c04d
commit
bfd5e090d9
12 changed files with 92 additions and 37 deletions
|
@ -39,4 +39,7 @@ ctor = "0.1.23"
|
|||
doctest = false
|
||||
|
||||
[features]
|
||||
fuzzing = ["crdt-list/fuzzing", "rand", "arbitrary", "tabled"]
|
||||
# whether to use list slice instead of raw str in text container
|
||||
slice = []
|
||||
fuzzing = ["crdt-list/fuzzing", "slice", "rand", "arbitrary", "tabled"]
|
||||
proptest = ["fuzzing"]
|
||||
|
|
|
@ -31,6 +31,7 @@ pub trait Container: Debug + Any + Unpin {
|
|||
|
||||
/// convert an op to export format. for example [ListSlice] should be convert to str before export
|
||||
fn to_export(&self, op: &mut Op);
|
||||
fn to_import(&mut self, op: &mut Op);
|
||||
}
|
||||
|
||||
/// it's really cheap to clone
|
||||
|
|
|
@ -64,6 +64,14 @@ impl Container for ContainerInstance {
|
|||
ContainerInstance::Dyn(x) => x.to_export(op),
|
||||
}
|
||||
}
|
||||
|
||||
fn to_import(&mut self, op: &mut crate::op::Op) {
|
||||
match self {
|
||||
ContainerInstance::Map(x) => x.to_import(op),
|
||||
ContainerInstance::Text(x) => x.to_import(op),
|
||||
ContainerInstance::Dyn(x) => x.to_import(op),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: containers snapshot: we need to resolve each container's parent even
|
||||
|
|
|
@ -156,4 +156,6 @@ impl Container for MapContainer {
|
|||
}
|
||||
|
||||
fn to_export(&self, _op: &mut Op) {}
|
||||
|
||||
fn to_import(&mut self, op: &mut Op) {}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
use rle::{RleTree, Sliceable};
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
|
||||
|
@ -62,7 +61,9 @@ impl TextContainer {
|
|||
|
||||
let id = if let Ok(mut store) = self.log_store.upgrade().unwrap().write() {
|
||||
let id = store.next_id();
|
||||
// let slice = ListSlice::from_range(self.raw_str.alloc(text));
|
||||
#[cfg(feature = "slice")]
|
||||
let slice = ListSlice::from_range(self.raw_str.alloc(text));
|
||||
#[cfg(not(feature = "slice"))]
|
||||
let slice = ListSlice::from_raw(SmString::from(text));
|
||||
self.state.insert(pos, slice.clone());
|
||||
let op = Op::new(
|
||||
|
@ -253,15 +254,33 @@ impl Container for TextContainer {
|
|||
.and_then(|c| c.as_list_mut())
|
||||
.and_then(|x| x.as_insert_mut())
|
||||
{
|
||||
let change = if let ListSlice::Slice(ranges) = slice {
|
||||
if let Some(change) = if let ListSlice::Slice(ranges) = slice {
|
||||
Some(self.raw_str.get_str(ranges))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
if let Some(change) = change {
|
||||
} {
|
||||
*slice = ListSlice::RawStr(change);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn to_import(&mut self, op: &mut Op) {
|
||||
if let Some((slice, _pos)) = op
|
||||
.content
|
||||
.as_normal_mut()
|
||||
.and_then(|c| c.as_list_mut())
|
||||
.and_then(|x| x.as_insert_mut())
|
||||
{
|
||||
if let Some(slice_range) = match slice {
|
||||
ListSlice::RawStr(s) => {
|
||||
let range = self.raw_str.alloc(s);
|
||||
Some(range)
|
||||
}
|
||||
ListSlice::Slice(_) => unreachable!(),
|
||||
ListSlice::Unknown(_) => unreachable!(),
|
||||
} {
|
||||
*slice = ListSlice::Slice(slice_range);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ use crate::{
|
|||
debug_log, LoroCore,
|
||||
};
|
||||
|
||||
#[derive(Arbitrary, EnumAsInner, Clone, PartialEq, Eq, Debug)]
|
||||
#[derive(arbitrary::Arbitrary, EnumAsInner, Clone, PartialEq, Eq, Debug)]
|
||||
pub enum Action {
|
||||
Ins {
|
||||
content: String,
|
||||
|
@ -307,6 +307,17 @@ mod test {
|
|||
use super::Action::*;
|
||||
use super::*;
|
||||
#[test]
|
||||
fn test_10() {
|
||||
test_multi_sites(
|
||||
10,
|
||||
vec![Ins {
|
||||
content: "\0\0".into(),
|
||||
pos: 0,
|
||||
site: 0,
|
||||
}],
|
||||
)
|
||||
}
|
||||
#[test]
|
||||
fn test_9() {
|
||||
test_multi_sites(
|
||||
2,
|
||||
|
|
|
@ -17,7 +17,7 @@ use crate::{
|
|||
change::{Change, ChangeMergeCfg},
|
||||
configure::Configure,
|
||||
container::{manager::ContainerManager, Container, ContainerID},
|
||||
dag::{Dag, DagUtils},
|
||||
dag::Dag,
|
||||
debug_log,
|
||||
id::{ClientID, Counter},
|
||||
span::{HasIdSpan, IdSpan},
|
||||
|
@ -143,6 +143,17 @@ impl LogStore {
|
|||
}
|
||||
}
|
||||
|
||||
fn change_to_imported_format(
|
||||
&self,
|
||||
container_manager: &mut ContainerManager,
|
||||
change: &mut Change,
|
||||
) {
|
||||
for op in change.ops.vec_mut().iter_mut() {
|
||||
let container = container_manager.get_or_create(&op.container, self.to_self.clone());
|
||||
container.to_import(op);
|
||||
}
|
||||
}
|
||||
|
||||
fn change_to_export_format(&self, change: &mut Change) {
|
||||
let container_manager = self.container.read().unwrap();
|
||||
for op in change.ops.vec_mut().iter_mut() {
|
||||
|
@ -251,14 +262,23 @@ impl LogStore {
|
|||
}
|
||||
|
||||
// TODO: find a way to remove this clone? we don't need change in apply method actually
|
||||
let change = self.push_change(change).clone();
|
||||
let mut container_manager = self.container.write().unwrap();
|
||||
#[cfg(feature = "slice")]
|
||||
self.change_to_imported_format(&mut container_manager, &mut change);
|
||||
let v = self
|
||||
.changes
|
||||
.entry(change.id.client_id)
|
||||
.or_insert_with(RleVec::new);
|
||||
v.push(change);
|
||||
let change = v.vec().last().unwrap().clone();
|
||||
|
||||
// Apply ops.
|
||||
// NOTE: applying expects that log_store has store the Change, and updated self vv
|
||||
let mut set = FxHashSet::default();
|
||||
for op in change.ops.iter() {
|
||||
set.insert(&op.container);
|
||||
}
|
||||
|
||||
for container in set {
|
||||
let container = container_manager.get_or_create(container, self.to_self.clone());
|
||||
container.apply(change.id_span(), self);
|
||||
|
@ -277,16 +297,6 @@ impl LogStore {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn push_change(&mut self, change: Change) -> &Change {
|
||||
let v = self
|
||||
.changes
|
||||
.entry(change.id.client_id)
|
||||
.or_insert_with(RleVec::new);
|
||||
v.push(change);
|
||||
v.vec().last().unwrap()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn contains(&self, id: ID) -> bool {
|
||||
self.changes
|
||||
|
|
|
@ -24,16 +24,16 @@ macro_rules! fx_map {
|
|||
#[macro_export]
|
||||
macro_rules! debug_log {
|
||||
() => {
|
||||
if cfg!(test) {
|
||||
// $crate::print!("\n")
|
||||
}
|
||||
// if cfg!(test) {
|
||||
// $crate::print!("\n")
|
||||
// }
|
||||
};
|
||||
($($arg:tt)*) => {{
|
||||
if cfg!(test) {
|
||||
|
||||
// print!("{}:{}\t", file!().purple(), line!().to_string().purple());
|
||||
// println!($($arg)*);
|
||||
}
|
||||
// if cfg!(test) {
|
||||
|
||||
// print!("{}:{}\t", file!().purple(), line!().to_string().purple());
|
||||
// println!($($arg)*);
|
||||
// }
|
||||
}};
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
#![cfg(test)]
|
||||
|
||||
#[cfg(feature = "fuzzing")]
|
||||
#[cfg(feature = "proptest")]
|
||||
pub const PROPTEST_FACTOR_10: usize = 10;
|
||||
#[cfg(not(feature = "fuzzing"))]
|
||||
#[cfg(not(feature = "proptest"))]
|
||||
pub const PROPTEST_FACTOR_10: usize = 1;
|
||||
|
||||
#[cfg(feature = "fuzzing")]
|
||||
#[cfg(feature = "proptest")]
|
||||
pub const PROPTEST_FACTOR_1: usize = 1;
|
||||
#[cfg(not(feature = "fuzzing"))]
|
||||
#[cfg(not(feature = "proptest"))]
|
||||
pub const PROPTEST_FACTOR_1: usize = 0;
|
||||
|
|
|
@ -25,3 +25,4 @@ static_assertions = "1.1.0"
|
|||
|
||||
[features]
|
||||
fuzzing = []
|
||||
proptest = ["fuzzing"]
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
#![cfg(test)]
|
||||
|
||||
#[cfg(feature = "fuzzing")]
|
||||
#[cfg(feature = "proptest")]
|
||||
pub const PROPTEST_FACTOR_10: usize = 10;
|
||||
#[cfg(not(feature = "fuzzing"))]
|
||||
#[cfg(not(feature = "proptest"))]
|
||||
pub const PROPTEST_FACTOR_10: usize = 1;
|
||||
|
||||
#[cfg(feature = "fuzzing")]
|
||||
#[cfg(feature = "proptest")]
|
||||
pub const PROPTEST_FACTOR_1: usize = 1;
|
||||
#[cfg(not(feature = "fuzzing"))]
|
||||
#[cfg(not(feature = "proptest"))]
|
||||
pub const PROPTEST_FACTOR_1: usize = 0;
|
||||
|
|
2
justfile
2
justfile
|
@ -5,7 +5,7 @@ test *FLAGS:
|
|||
RUST_BACKTRACE=full cargo nextest run {{FLAGS}}
|
||||
|
||||
test-all:
|
||||
cargo nextest run &
|
||||
cargo nextest run --features=fuzzing &
|
||||
just quickfuzz
|
||||
|
||||
quickfuzz:
|
||||
|
|
Loading…
Reference in a new issue