diff --git a/Cargo.toml b/Cargo.toml index f88a5eb84813a36e792d75dfa99069392c8c9b58..657cbc6c27f7484f6b74f478eb8672543dff06a6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT" [dev-dependencies] rand = "0.1.2" -# iobuf = "*" +iobuf = "*" [[bench]] diff --git a/bench/bench.rs b/bench/bench.rs new file mode 100644 index 0000000000000000000000000000000000000000..fc561aa1bea045011a0dbc55799f25e0e4b35786 --- /dev/null +++ b/bench/bench.rs @@ -0,0 +1,34 @@ +#![feature(test, core)] + +use bytes::ByteBuf; +use bytes::traits::*; +use iobuf::{RWIobuf}; +use test::Bencher; + +extern crate bytes; +extern crate iobuf; +extern crate test; + +const SIZE:usize = 4_096; + +#[bench] +pub fn bench_byte_buf_fill_4kb(b: &mut Bencher) { + b.iter(|| { + let mut buf = ByteBuf::mut_with_capacity(SIZE); + + for _ in 0..SIZE { + buf.write_slice(&[0]); + } + }); +} + +#[bench] +pub fn bench_rw_iobuf_fill_4kb(b: &mut Bencher) { + b.iter(|| { + let mut buf = RWIobuf::new(SIZE); + + for _ in 0..SIZE { + let _ = buf.fill(&[0]); + } + }); +} diff --git a/src/byte_buf.rs b/src/byte_buf.rs index 14f50062c9437bd9624b049f235324be04c48b40..96a40b98554a35ab949710f235dd6c47460c0b95 100644 --- a/src/byte_buf.rs +++ b/src/byte_buf.rs @@ -1,5 +1,5 @@ -use {alloc, Bytes, SeqByteStr, BufResult, BufError, MAX_CAPACITY}; -use traits::{Buf, MutBuf, ByteStr}; +use {alloc, Bytes, SeqByteStr, MAX_CAPACITY}; +use traits::{Buf, MutBuf, MutBufExt, ByteStr}; use std::{cmp, ptr}; use std::num::UnsignedInt; @@ -9,6 +9,7 @@ use std::num::UnsignedInt; * */ +/// A `Buf` backed by a contiguous region of memory. pub struct ByteBuf { mem: alloc::MemRef, cap: u32, @@ -17,6 +18,7 @@ pub struct ByteBuf { } impl ByteBuf { + /// Create a new `ByteBuf` by copying the contents of the given slice. pub fn from_slice(bytes: &[u8]) -> ByteBuf { let mut buf = ByteBuf::mut_with_capacity(bytes.len()); buf.write(bytes).ok().expect("unexpected failure"); @@ -105,45 +107,46 @@ impl ByteBuf { } } + #[inline] pub fn to_bytes(self) -> Bytes { Bytes::of(self.to_seq_byte_str()) } + #[inline] fn pos(&self) -> usize { self.pos as usize } + #[inline] fn lim(&self) -> usize { self.lim as usize } + #[inline] fn remaining_u32(&self) -> u32 { self.lim - self.pos } - - fn ensure_remaining(&self, cnt: usize) -> BufResult<()> { - if cnt > self.remaining() { - return Err(BufError::Overflow); - } - - Ok(()) - } } impl Buf for ByteBuf { + + #[inline] fn remaining(&self) -> usize { self.remaining_u32() as usize } + #[inline] fn bytes<'a>(&'a self) -> &'a [u8] { &self.mem.bytes()[self.pos()..self.lim()] } + #[inline] fn advance(&mut self, mut cnt: usize) { cnt = cmp::min(cnt, self.remaining()); self.pos += cnt as u32; } + #[inline] fn read_slice(&mut self, dst: &mut [u8]) -> usize { ByteBuf::read_slice(self, dst) } @@ -225,18 +228,28 @@ impl MutByteBuf { self.buf.lim = self.buf.cap; } - pub fn write_slice(&mut self, src: &[u8]) -> BufResult<()> { - try!(self.buf.ensure_remaining(src.len())); + #[inline] + pub fn write_slice(&mut self, src: &[u8]) -> usize { let cnt = src.len() as u32; + let rem = self.buf.remaining_u32(); + if rem < cnt { + self.write_ptr(src.as_ptr(), rem) + } else { + self.write_ptr(src.as_ptr(), cnt) + } + } + + #[inline] + fn write_ptr(&mut self, src: *const u8, len: u32) -> usize { unsafe { ptr::copy_nonoverlapping_memory( self.buf.mem.ptr().offset(self.buf.pos as isize), - src.as_ptr(), src.len()); - } + src, len as usize); - self.buf.pos += cnt; - return Ok(()); + self.buf.pos += len; + len as usize + } } } diff --git a/src/byte_str.rs b/src/byte_str.rs index 2cccebfb48babf5d9076aa54a308d812afe33620..ee420cf6659fe2059544ce0e5076a9f27e78814d 100644 --- a/src/byte_str.rs +++ b/src/byte_str.rs @@ -1,5 +1,5 @@ use {alloc, Bytes, ByteBuf, ROByteBuf}; -use traits::{Buf, MutBuf, ByteStr}; +use traits::{Buf, MutBuf, MutBufExt, ByteStr}; use std::{cmp, ops}; /* diff --git a/src/lib.rs b/src/lib.rs index d8843dc9f7eb86dcee9bd4e7a35e69f9596e102f..5a4eb88739a58b9248a6038a56a04de6c60d9de9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -24,12 +24,12 @@ mod rope; mod slice; pub mod traits { - pub use {Buf, BufExt, MutBuf, ByteStr}; + pub use {Buf, BufExt, MutBuf, MutBufExt, ByteStr}; } const MAX_CAPACITY: usize = u32::MAX as usize; -/// A trait for objects that provide random and sequential access to bytes. +/// A trait for values that provide random and sequential access to bytes. pub trait Buf { /// Returns the number of bytes that can be accessed from the Buf @@ -113,12 +113,6 @@ pub trait MutBuf : Sized { /// length between 0 and `Buf::remaining()`. fn mut_bytes<'a>(&'a mut self) -> &'a mut [u8]; - /// Read bytes from this Buf into the given sink and advance the cursor by - /// the number of bytes read. - fn write<S: Source>(&mut self, src: S) -> Result<usize, S::Error> { - src.fill(self) - } - /// Read bytes from this Buf into the given slice and advance the cursor by /// the number of bytes read. /// @@ -164,6 +158,13 @@ pub trait MutBuf : Sized { } } +pub trait MutBufExt { + + /// Write bytes from the given source into the current `MutBuf` and advance + /// the cursor by the number of bytes written. + fn write<S: Source>(&mut self, src: S) -> Result<usize, S::Error>; +} + /* * * ===== ByteStr ===== @@ -239,13 +240,19 @@ impl<B: Buf> BufExt for B { } } +impl<B: MutBuf> MutBufExt for B { + fn write<S: Source>(&mut self, src: S) -> Result<usize, S::Error> { + src.fill(self) + } +} + /* * * ===== Sink / Source ===== * */ -/// An object that reads bytes from a Buf into itself +/// An value that reads bytes from a Buf into itself pub trait Sink { type Error;