Skip to content

Commit

Permalink
Add blanket impl Allocator for &mut A where A: Allocator
Browse files Browse the repository at this point in the history
  • Loading branch information
dwrensha committed Oct 22, 2020
1 parent fb230d4 commit 8257850
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 16 deletions.
19 changes: 6 additions & 13 deletions benchmark/benchmark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,8 +148,8 @@ fn pass_by_object<S, T>(testcase: T, mut reuse: S, iters: u64) -> ::capnp::Resul
let mut rng = common::FastRand::new();
let (mut allocator_req, mut allocator_res) = reuse.get_allocators();
for _ in 0..iters {
let mut message_req = message::Builder::new(allocator_req);
let mut message_res = message::Builder::new(allocator_res);
let mut message_req = message::Builder::new(&mut allocator_req);
let mut message_res = message::Builder::new(&mut allocator_res);

let expected = testcase.setup_request(
&mut rng,
Expand All @@ -162,9 +162,6 @@ fn pass_by_object<S, T>(testcase: T, mut reuse: S, iters: u64) -> ::capnp::Resul
testcase.check_response(
message_res.get_root_as_reader()?,
expected)?;

allocator_req = message_req.into_allocator();
allocator_res = message_res.into_allocator();
}
Ok(())
}
Expand All @@ -177,8 +174,8 @@ fn pass_by_bytes<C, S, T>(testcase: T, mut reuse: S, compression: C, iters: u64)
let mut rng = common::FastRand::new();
let (mut allocator_req, mut allocator_res) = reuse.get_allocators();
for _ in 0..iters {
let mut message_req = message::Builder::new(allocator_req);
let mut message_res = message::Builder::new(allocator_res);
let mut message_req = message::Builder::new(&mut allocator_req);
let mut message_res = message::Builder::new(&mut allocator_res);

let expected = {
let request = message_req.init_root();
Expand Down Expand Up @@ -214,8 +211,6 @@ fn pass_by_bytes<C, S, T>(testcase: T, mut reuse: S, compression: C, iters: u64)

let response_reader = message_reader.get_root()?;
testcase.check_response(response_reader, expected)?;
allocator_req = message_req.into_allocator();
allocator_res = message_res.into_allocator();
}
Ok(())
}
Expand All @@ -229,7 +224,7 @@ fn server<C, S, T, R, W>(testcase: T, mut reuse: S, compression: C, iters: u64,
let (mut allocator_res, _) = reuse.get_allocators();
for _ in 0..iters {
use std::io::Write;
let mut message_res = message::Builder::new(allocator_res);
let mut message_res = message::Builder::new(&mut allocator_res);

{
let response = message_res.init_root();
Expand All @@ -242,7 +237,6 @@ fn server<C, S, T, R, W>(testcase: T, mut reuse: S, compression: C, iters: u64,

compression.write_message(&mut out_buffered, &mut message_res)?;
out_buffered.flush()?;
allocator_res = message_res.into_allocator();
}
Ok(())
}
Expand All @@ -259,7 +253,7 @@ fn sync_client<C, S, T>(testcase: T, mut reuse: S, compression: C, iters: u64)
let (mut allocator_req, _) = reuse.get_allocators();
for _ in 0..iters {
use std::io::Write;
let mut message_req = message::Builder::new(allocator_req);
let mut message_req = message::Builder::new(&mut allocator_req);

let expected = {
let request = message_req.init_root();
Expand All @@ -273,7 +267,6 @@ fn sync_client<C, S, T>(testcase: T, mut reuse: S, compression: C, iters: u64)
Default::default())?;
let response_reader = message_reader.get_root()?;
testcase.check_response(response_reader, expected)?;
allocator_req = message_req.into_allocator();
}
Ok(())
}
Expand Down
27 changes: 24 additions & 3 deletions capnp/src/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,7 @@ pub unsafe trait Allocator {
fn allocate_segment(&mut self, minimum_size: u32) -> (*mut u8, u32);

/// Indicates that a segment, previously allocated via allocate_segment(), is no longer in use.
/// `word_size` is the length of the segment in words, as returned from `allocate_segment()`.
fn deallocate_segment(&mut self, ptr: *mut u8, word_size: u32, words_used: u32);
}

Expand Down Expand Up @@ -469,6 +470,15 @@ impl Builder<HeapAllocator> {
}

/// An Allocator whose first segment is a backed by a user-provided buffer.
///
/// Recall that an `Allocator` implementation must ensure that allocated segments are
/// initially *zeroed*. `ScratchSpaceHeapAllocator` ensures that is the case by zeroing
/// the entire buffer upon initial construction, and then zeroing any *potentially used*
/// part of the buffer upon `deallocate_segment()`.
///
/// You can reuse a `ScratchSpaceHeapAllocator` by calling `message::Builder::into_allocator()`,
/// or by initally passing it to `message::Builder::new()` as a `&mut ScratchSpaceHeapAllocator`.
/// Such reuse can save significant amounts of zeroing.
pub struct ScratchSpaceHeapAllocator<'a> {
scratch_space: &'a mut [u8],
scratch_space_allocated: bool,
Expand All @@ -478,9 +488,9 @@ pub struct ScratchSpaceHeapAllocator<'a> {
impl <'a> ScratchSpaceHeapAllocator<'a> {
/// Writes zeroes into the entire buffer and constructs a new allocator from it.
///
/// If you want to reuse the same buffer and to minimize the cost of zeroing for each message,
/// you can call `message::Builder::into_allocator()` to recover the allocator from
/// the previous message and then pass it into the new message.
/// If the buffer is large, this operation could be relatively expensive. If you want to reuse
/// the same scratch space in a later message, you should reuse the entire
/// `ScratchSpaceHeapAllocator`, to avoid paying this full cost again.
pub fn new(scratch_space: &'a mut [u8]) -> ScratchSpaceHeapAllocator<'a> {
#[cfg(not(feature = "unaligned"))]
{
Expand Down Expand Up @@ -535,3 +545,14 @@ unsafe impl <'a> Allocator for ScratchSpaceHeapAllocator<'a> {
}
}
}

unsafe impl <'a, A> Allocator for &'a mut A where A: Allocator {
fn allocate_segment(&mut self, minimum_size: u32) -> (*mut u8, u32) {
(*self).allocate_segment(minimum_size)
}

fn deallocate_segment(&mut self, ptr: *mut u8, word_size: u32, words_used: u32) {
(*self).deallocate_segment(ptr, word_size, words_used)
}
}

0 comments on commit 8257850

Please sign in to comment.