Lazily allocate the Arc

This commit is contained in:
Carl Lerche
2017-01-26 12:56:38 -08:00
parent 93c08064bb
commit a8320da0f8
+90 -85
View File
@@ -1,8 +1,8 @@
use {IntoBuf, ByteBuf, SliceBuf}; use {IntoBuf, ByteBuf, SliceBuf};
use std::{cmp, fmt, mem, ops, slice};
use std::cell::UnsafeCell; use std::cell::UnsafeCell;
use std::sync::Arc; use std::sync::Arc;
use std::{cmp, fmt, ops};
/// A reference counted slice of bytes. /// A reference counted slice of bytes.
/// ///
@@ -20,14 +20,17 @@ pub struct Bytes {
/// A `BytesMut` is a unique handle to a slice of bytes allowing mutation of /// A `BytesMut` is a unique handle to a slice of bytes allowing mutation of
/// the underlying bytes. /// the underlying bytes.
pub struct BytesMut { pub struct BytesMut {
mem: Mem, // Pointer to the start of the memory owned by this BytesMut
pos: usize, ptr: *mut u8,
len: usize,
cap: usize,
}
struct Mem { // Number of bytes that have been initialized
inner: Arc<UnsafeCell<Box<[u8]>>>, len: usize,
// Total number of bytes owned by this BytesMut
cap: usize,
// If this pointer is set, then the the BytesMut is backed by an Arc
arc: UnsafeCell<Option<Arc<Vec<u8>>>>,
} }
/* /*
@@ -61,9 +64,10 @@ impl Bytes {
pub fn slice(&self, start: usize, end: usize) -> Bytes { pub fn slice(&self, start: usize, end: usize) -> Bytes {
let mut ret = self.clone(); let mut ret = self.clone();
ret.inner unsafe {
.set_end(end) ret.inner.set_end(end);
.set_start(start); ret.inner.set_start(start);
}
ret ret
} }
@@ -113,7 +117,7 @@ impl Bytes {
/// This will only succeed if there are no other outstanding references to /// This will only succeed if there are no other outstanding references to
/// the underlying chunk of memory. /// the underlying chunk of memory.
pub fn try_mut(mut self) -> Result<BytesMut, Bytes> { pub fn try_mut(mut self) -> Result<BytesMut, Bytes> {
if self.inner.mem.is_mut_safe() { if self.inner.is_mut_safe() {
Ok(self.inner) Ok(self.inner)
} else { } else {
Err(self) Err(self)
@@ -207,12 +211,7 @@ unsafe impl Sync for Bytes {}
impl BytesMut { impl BytesMut {
/// Create a new `BytesMut` with the specified capacity. /// Create a new `BytesMut` with the specified capacity.
pub fn with_capacity(cap: usize) -> BytesMut { pub fn with_capacity(cap: usize) -> BytesMut {
BytesMut { BytesMut::from(Vec::with_capacity(cap))
mem: Mem::with_capacity(cap),
pos: 0,
len: 0,
cap: cap,
}
} }
/// Creates a new `BytesMut` and copy the given slice into it. /// Creates a new `BytesMut` and copy the given slice into it.
@@ -255,8 +254,10 @@ impl BytesMut {
pub fn split_off(&mut self, at: usize) -> BytesMut { pub fn split_off(&mut self, at: usize) -> BytesMut {
let mut other = self.shallow_clone(); let mut other = self.shallow_clone();
other.set_start(at); unsafe {
self.set_end(at); other.set_start(at);
self.set_end(at);
}
return other return other
} }
@@ -275,8 +276,10 @@ impl BytesMut {
pub fn drain_to(&mut self, at: usize) -> BytesMut { pub fn drain_to(&mut self, at: usize) -> BytesMut {
let mut other = self.shallow_clone(); let mut other = self.shallow_clone();
other.set_end(at); unsafe {
self.set_start(at); other.set_end(at);
self.set_start(at);
}
return other return other
} }
@@ -290,8 +293,7 @@ impl BytesMut {
/// ///
/// This a slice of bytes that have been initialized /// This a slice of bytes that have been initialized
pub fn as_mut(&mut self) -> &mut [u8] { pub fn as_mut(&mut self) -> &mut [u8] {
let end = self.pos + self.len; unsafe { slice::from_raw_parts_mut(self.ptr, self.len) }
&mut self.mem.as_mut()[self.pos..end]
} }
/// Sets the length of the buffer /// Sets the length of the buffer
@@ -313,22 +315,23 @@ impl BytesMut {
/// ///
/// This a slice of all bytes, including uninitialized memory /// This a slice of all bytes, including uninitialized memory
pub unsafe fn as_raw(&mut self) -> &mut [u8] { pub unsafe fn as_raw(&mut self) -> &mut [u8] {
let end = self.pos + self.cap; slice::from_raw_parts_mut(self.ptr, self.cap)
&mut self.mem.as_mut()[self.pos..end]
} }
/// Changes the starting index of this window to the index specified. /// Changes the starting index of this window to the index specified.
/// ///
/// Returns the windows back to chain multiple calls to this method.
///
/// # Panics /// # Panics
/// ///
/// This method will panic if `start` is out of bounds for the underlying /// This method will panic if `start` is out of bounds for the underlying
/// slice. /// slice.
fn set_start(&mut self, start: usize) -> &mut BytesMut { unsafe fn set_start(&mut self, start: usize) {
assert!(start <= self.cap); assert!(start <= self.cap);
self.pos += start; debug_assert!(self.is_shared());
debug_assert!(self.len <= self.cap);
self.ptr = self.ptr.offset(start as isize);
// TODO: This could probably be optimized with some bit fiddling
if self.len >= start { if self.len >= start {
self.len -= start; self.len -= start;
} else { } else {
@@ -336,33 +339,75 @@ impl BytesMut {
} }
self.cap -= start; self.cap -= start;
self
} }
/// Changes the end index of this window to the index specified. /// Changes the end index of this window to the index specified.
/// ///
/// Returns the windows back to chain multiple calls to this method.
///
/// # Panics /// # Panics
/// ///
/// This method will panic if `start` is out of bounds for the underlying /// This method will panic if `start` is out of bounds for the underlying
/// slice. /// slice.
fn set_end(&mut self, end: usize) -> &mut BytesMut { unsafe fn set_end(&mut self, end: usize) {
assert!(end <= self.cap); assert!(end <= self.cap);
debug_assert!(self.is_shared());
self.cap = end; self.cap = end;
self.len = cmp::min(self.len, end); self.len = cmp::min(self.len, end);
self }
/// Checks if it is safe to mutate the memory
fn is_mut_safe(&mut self) -> bool {
unsafe {
(*self.arc.get()).as_mut()
// Check if there is only one outstanding reference to the memory
.map(|a| Arc::get_mut(a).is_some())
// If there is no arc, then this is a unique pointer
.unwrap_or(true)
}
} }
/// Increments the ref count. This should only be done if it is known that /// Increments the ref count. This should only be done if it is known that
/// it can be done safely. As such, this fn is not public, instead other /// it can be done safely. As such, this fn is not public, instead other
/// fns will use this one while maintaining the guarantees. /// fns will use this one while maintaining the guarantees.
fn shallow_clone(&self) -> BytesMut { fn shallow_clone(&self) -> BytesMut {
let arc = unsafe {
match *self.arc.get() {
Some(ref arc) => {
// Already backed by an arc, just clone it
arc.clone()
}
None => {
// Promote this `Bytes` to an arc, and clone it
let v = Vec::from_raw_parts(self.ptr, self.len, self.cap);
let a = Arc::new(v);
*self.arc.get() = Some(a.clone());
a
}
}
};
BytesMut { BytesMut {
mem: self.mem.clone(), arc: UnsafeCell::new(Some(arc)),
.. *self .. *self
} }
} }
fn is_shared(&self) -> bool {
unsafe { (*self.arc.get()).is_some() }
}
}
impl Drop for BytesMut {
fn drop(&mut self) {
if !self.is_shared() {
unsafe {
// Not shared, manually free
let _ = Vec::from_raw_parts(self.ptr, self.len, self.cap);
}
}
}
} }
impl IntoBuf for BytesMut { impl IntoBuf for BytesMut {
@@ -383,8 +428,7 @@ impl<'a> IntoBuf for &'a BytesMut {
impl AsRef<[u8]> for BytesMut { impl AsRef<[u8]> for BytesMut {
fn as_ref(&self) -> &[u8] { fn as_ref(&self) -> &[u8] {
let end = self.pos + self.len; unsafe { slice::from_raw_parts(self.ptr, self.len) }
&self.mem.as_ref()[self.pos..end]
} }
} }
@@ -403,15 +447,18 @@ impl ops::DerefMut for BytesMut {
} }
impl From<Vec<u8>> for BytesMut { impl From<Vec<u8>> for BytesMut {
fn from(src: Vec<u8>) -> BytesMut { fn from(mut src: Vec<u8>) -> BytesMut {
let len = src.len(); let len = src.len();
let cap = src.capacity(); let cap = src.capacity();
let ptr = src.as_mut_ptr();
mem::forget(src);
BytesMut { BytesMut {
mem: Mem::from_vec(src), ptr: ptr,
pos: 0,
len: len, len: len,
cap: cap, cap: cap,
arc: UnsafeCell::new(None),
} }
} }
} }
@@ -439,44 +486,6 @@ impl fmt::Debug for BytesMut {
unsafe impl Send for BytesMut {} unsafe impl Send for BytesMut {}
/*
*
* ===== Mem =====
*
*/
impl Mem {
fn with_capacity(cap: usize) -> Mem {
let mut vec = Vec::with_capacity(cap);
unsafe { vec.set_len(cap); }
Mem { inner: Arc::new(UnsafeCell::new(vec.into_boxed_slice())) }
}
fn from_vec(mut vec: Vec<u8>) -> Mem {
let cap = vec.capacity();
unsafe { vec.set_len(cap); }
Mem { inner: Arc::new(UnsafeCell::new(vec.into_boxed_slice())) }
}
fn as_ref(&self) -> &[u8] {
unsafe { &*self.inner.get() }
}
fn as_mut(&mut self) -> &mut [u8] {
unsafe { &mut *self.inner.get() }
}
fn is_mut_safe(&mut self) -> bool {
Arc::get_mut(&mut self.inner).is_some()
}
fn clone(&self) -> Mem {
Mem { inner: self.inner.clone() }
}
}
/* /*
* *
* ===== PartialEq ===== * ===== PartialEq =====
@@ -563,11 +572,7 @@ impl Clone for BytesMut {
fn clone(&self) -> BytesMut { fn clone(&self) -> BytesMut {
let mut v = Vec::with_capacity(self.len()); let mut v = Vec::with_capacity(self.len());
v.extend_from_slice(&self[..]); v.extend_from_slice(&self[..]);
BytesMut {
mem: Mem { inner : Arc::new(UnsafeCell::new(v.into_boxed_slice())) }, BytesMut::from(v)
pos: self.pos,
len: self.len,
cap: self.cap,
}
} }
} }