diff --git a/src/ext.rs b/src/ext.rs new file mode 100644 index 0000000..a529aa6 --- /dev/null +++ b/src/ext.rs @@ -0,0 +1,164 @@ +//! Extensions +use super::*; + +pub trait VecExt +{ + /// Insert many elements + fn move_insert>(&mut self, location: usize, slice: I) + where Ex: ExactSizeIterator + std::panic::UnwindSafe; + + /// Insert many elements + fn splice_insert>(&mut self, location: usize, slice: I); +} + + +impl VecExt for Vec +{ + fn move_insert>(&mut self, location: usize, slice: I) + where Ex: ExactSizeIterator + std::panic::UnwindSafe, + { + #[inline(never)] + #[cold] + fn panic_len(l1: usize, l2: usize) -> ! + { + panic!("Location must be in range 0..{}, got {}", l1,l2) + } + + #[inline(never)] + #[cold] + fn inv_sz() -> ! + { + panic!("ExactSizeIterator returned invalid size"); + } + + if location >= self.len() { + panic_len(self.len(), location); + } + let mut slice = slice.into_iter(); + + let slen = slice.len(); + match slen { + 0 => return, + 1 => { + self.insert(location, slice.next().unwrap()); + return + }, + _ => (), + }; + self.reserve(slice.len()); + + unsafe { + let this = self.as_mut_ptr().add(location); + let len = self.len(); + let rest = std::mem::size_of::() * (location..len).len(); + + libc::memmove(this.add(slen) as *mut libc::c_void, this as *mut libc::c_void, rest); + let mut sent=0; + match std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| { + let mut this = this; + for item in slice { + if sent >= slen { + inv_sz(); + } + + this.write(item); + this = this.add(1); + sent+=1; + } + if sent != slen { + inv_sz(); + } + })) { + Err(e) => { + // memory at (location+sent)..slen is now invalid, move the old one back before allowing unwind to contine + libc::memmove(this.add(sent) as *mut libc::c_void, this.add(slen) as *mut libc::c_void, rest); + std::panic::resume_unwind(e) + }, + _ => (), + } + self.set_len(len + sent); + } + } + fn splice_insert>(&mut self, location: usize, slice: I) + { + let slice = slice.into_iter(); + match slice.size_hint() { + (0, Some(0)) | (0, None) => (), + (_, Some(bound)) | (bound, _) => self.reserve(bound), + }; + // shift everything across, replacing with the new values + let splice: Vec<_> = self.splice(location.., slice).collect(); + // add tail back + self.extend(splice); + } +} + +#[cfg(test)] +mod tests +{ + use super::*; + #[test] + fn vec_move_insert() + { + let mut vec = vec![0,1,2,8,9,10]; + vec.move_insert(3, [3,4,5,6, 7].iter().copied()); + + assert_eq!(&vec[..], + &[0,1,2,3,4,5,6,7,8,9,10] + ); + } + #[test] + fn vec_move_insert_nt() + { + macro_rules! string { + ($str:literal) => (String::from($str)); + } + let mut vec = vec![ + string!("Hello"), + string!("world"), + string!("foo"), + string!("uhh"), + ]; + let vec2 = vec![ + string!("Hello"), + string!("world"), + string!("hi"), + string!("hello"), + string!("foo"), + string!("uhh"), + ]; + + vec.move_insert(2, vec![string!("hi"), string!("hello")]); + + assert_eq!(&vec[..], &vec2[..]); + } + + #[cfg(nightly)] + mod benchmatks + { + use super::super::*; + use test::{ + Bencher, black_box, + }; + #[bench] + fn move_via_splice(b: &mut Bencher) + { + let mut vec = vec![0,10,11,12]; + let span = [0,1,2,3]; + + b.iter(|| { + black_box(vec.splice_insert(2, span.iter().copied())); + }); + } + #[bench] + fn move_via_unsafe(b: &mut Bencher) + { + let mut vec = vec![0,10,11,12]; + let span = [0,1,2,3]; + b.iter(|| { + black_box(vec.move_insert(2, span.iter().copied())); + }); + } + } + +} diff --git a/src/main.rs b/src/main.rs index 4c65412..1899ea7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,11 +3,17 @@ #![allow(dead_code)] +#![cfg_attr(nightly, feature(test))] + +#[cfg(all(nightly, test))] extern crate test; + use async_trait::async_trait; use serde::{ Serialize, Deserialize, }; +mod ext; +use ext::*; mod bytes; mod suspend; diff --git a/src/state/local/delta.rs b/src/state/local/delta.rs index 3b3ab67..6844498 100644 --- a/src/state/local/delta.rs +++ b/src/state/local/delta.rs @@ -1,7 +1,7 @@ //! Deltas and applying them use super::*; -const MAX_SINGLE_DELTA_SIZE: usize = 16; +const MAX_SINGLE_DELTA_SIZE: usize = 14; /// Create a delta span from an input iterator. /// @@ -76,7 +76,9 @@ impl Delta let span = &span[..usize::from(span_len)]; if self.location == inserter.len() { inserter.extend_from_slice(span); - } else { + } else if span.len() == 1 { + inserter.insert(self.location, span[0]); + } else if span.len() > 1 { // reserve the extra space inserter.reserve(span.len()); // shift everything across, replacing with the new values @@ -94,137 +96,68 @@ impl Delta mod tests { use super::*; + + macro_rules! insert { + ($expects:literal; $start:literal, $ins:literal, $where:expr) => { + { + + let mut message: Vec = $start.chars().collect(); + + let delta = { + let (span, span_len) = delta_span($ins.chars()); + Delta { + location: $where, + kind: DeltaKind::Insert{span, span_len}, + } + }; + + println!("from: {:?}", message); + println!("delta: {:?}", delta); + delta.insert(&mut message); + + assert_eq!(&message.into_iter().collect::()[..], $expects); + } + }; + } + #[test] fn insert_body() { - let mut message: Vec = "126789".chars().collect(); - - let delta = { - let (span, span_len) = delta_span("345".chars()); - Delta { - location: 2, - kind: DeltaKind::Insert{span, span_len}, - } - }; - - println!("from: {:?}", message); - println!("delta: {:?}", delta); - delta.insert(&mut message); - - assert_eq!(&message.into_iter().collect::()[..], "123456789"); + insert!("123456789"; "126789", "345", 2); } #[test] fn insert_end() { - let mut message: Vec = "1289".chars().collect(); - - let delta = { - let (span, span_len) = delta_span("34567".chars()); - Delta { - location: 2, - kind: DeltaKind::Insert{span, span_len}, - } - }; - - println!("from: {:?}", message); - println!("delta: {:?}", delta); - delta.insert(&mut message); - - assert_eq!(&message.into_iter().collect::()[..], "123456789"); + insert!("123456789"; "1289", "34567", 2); } #[test] fn insert_end_rev() { - let mut message: Vec = "1234569".chars().collect(); - - let delta = { - let (span, span_len) = delta_span("78".chars()); - Delta { - location: 6, - kind: DeltaKind::Insert{span, span_len}, - } - }; - - println!("from: {:?}", message); - println!("delta: {:?}", delta); - delta.insert(&mut message); - - assert_eq!(&message.into_iter().collect::()[..], "123456789"); + insert!("123456789"; "1234569", "78", 6); } #[test] fn insert_begin_rev() { - let mut message: Vec = "1456789".chars().collect(); - - let delta = { - let (span, span_len) = delta_span("23".chars()); - Delta { - location: 1, - kind: DeltaKind::Insert{span, span_len}, - } - }; - - println!("from: {:?}", message); - println!("delta: {:?}", delta); - delta.insert(&mut message); - - assert_eq!(&message.into_iter().collect::()[..], "123456789"); + insert!("123456789"; "1456789", "23", 1); } #[test] fn insert_begin() { - let mut message: Vec = "789".chars().collect(); - - let delta = { - let (span, span_len) = delta_span("123456".chars()); - Delta { - location: 0, - kind: DeltaKind::Insert{span, span_len}, - } - }; - - println!("from: {:?}", message); - println!("delta: {:?}", delta); - delta.insert(&mut message); - - assert_eq!(&message.into_iter().collect::()[..], "123456789"); + insert!("123456789"; "789", "123456", 0); } #[test] fn insert_end_f() { - let mut message: Vec = "123".chars().collect(); - - let delta = { - let (span, span_len) = delta_span("456789".chars()); - Delta { - location: 3, - kind: DeltaKind::Insert{span, span_len}, - } - }; - - println!("from: {:?}", message); - println!("delta: {:?}", delta); - delta.insert(&mut message); - - assert_eq!(&message.into_iter().collect::()[..], "123456789"); + insert!("123456789"; "123", "456789", 3); } #[test] fn insert_end_f_rev() { - let mut message: Vec = "1234567".chars().collect(); - - let delta = { - let (span, span_len) = delta_span("89".chars()); - Delta { - location: 7, - kind: DeltaKind::Insert{span, span_len}, - } - }; - - println!("from: {:?}", message); - println!("delta: {:?}", delta); - delta.insert(&mut message); - - assert_eq!(&message.into_iter().collect::()[..], "123456789"); + insert!("123456789"; "1234567", "89", 7); + } + #[test] + fn insert_single() + { + insert!("123456789"; "12346789", "5",4); } } diff --git a/src/state/local/work.rs b/src/state/local/work.rs index 58bec6f..66e2c6d 100644 --- a/src/state/local/work.rs +++ b/src/state/local/work.rs @@ -98,15 +98,17 @@ impl Kokoro } /// Apply a delta to this instance. - pub async fn apply(&mut self, delta: Delta) -> Result<(), error::Error> + pub async fn apply>(&mut self, delta: I) -> Result<(), error::Error> { let (mut scape, mut deltas) = tokio::join!{ self.scape.write(), self.deltas.write(), }; - // Only start mutating now that both locks are writable. Is this needed, or can we do the mutation concurrently? - delta.insert(scape.as_mut()); - deltas.push(delta); + for delta in delta.into_iter() { + // Only start mutating now that both locks are writable. Is this needed, or can we do the mutation concurrently? + delta.insert(scape.as_mut()); + deltas.push(delta); + } self.update_body.broadcast(scape.iter().collect()).map_err(|_| error::Error::BroadcastUpdate) }