improve delta application

legacy
Avril 4 years ago
parent 6239a30e27
commit 68d2fae46a
Signed by: flanchan
GPG Key ID: 284488987C31F630

@ -0,0 +1,164 @@
//! Extensions
use super::*;
pub trait VecExt<T>
{
/// Insert many elements
fn move_insert<Ex, I: IntoIterator<Item = T, IntoIter = Ex>>(&mut self, location: usize, slice: I)
where Ex: ExactSizeIterator<Item = T> + std::panic::UnwindSafe;
/// Insert many elements
fn splice_insert<I: IntoIterator<Item =T>>(&mut self, location: usize, slice: I);
}
impl<T> VecExt<T> for Vec<T>
{
fn move_insert<Ex, I: IntoIterator<Item = T, IntoIter = Ex>>(&mut self, location: usize, slice: I)
where Ex: ExactSizeIterator<Item = T> + 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::<T>() * (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<I: IntoIterator<Item =T>>(&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()));
});
}
}
}

@ -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;

@ -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<char> = $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::<String>()[..], $expects);
}
};
}
#[test]
fn insert_body()
{
let mut message: Vec<char> = "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::<String>()[..], "123456789");
insert!("123456789"; "126789", "345", 2);
}
#[test]
fn insert_end()
{
let mut message: Vec<char> = "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::<String>()[..], "123456789");
insert!("123456789"; "1289", "34567", 2);
}
#[test]
fn insert_end_rev()
{
let mut message: Vec<char> = "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::<String>()[..], "123456789");
insert!("123456789"; "1234569", "78", 6);
}
#[test]
fn insert_begin_rev()
{
let mut message: Vec<char> = "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::<String>()[..], "123456789");
insert!("123456789"; "1456789", "23", 1);
}
#[test]
fn insert_begin()
{
let mut message: Vec<char> = "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::<String>()[..], "123456789");
insert!("123456789"; "789", "123456", 0);
}
#[test]
fn insert_end_f()
{
let mut message: Vec<char> = "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::<String>()[..], "123456789");
insert!("123456789"; "123", "456789", 3);
}
#[test]
fn insert_end_f_rev()
{
let mut message: Vec<char> = "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::<String>()[..], "123456789");
insert!("123456789"; "1234567", "89", 7);
}
#[test]
fn insert_single()
{
insert!("123456789"; "12346789", "5",4);
}
}

@ -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<I: IntoIterator<Item= Delta>>(&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)
}

Loading…
Cancel
Save