Skip to content
Snippets Groups Projects
Commit b78bb3ba authored by Stepan Koltsov's avatar Stepan Koltsov Committed by Carl Lerche
Browse files

Handle corner cases of Bytes::split_{off,to} (#87)

Before this commit `Bytes::split_{off,to}` always created a shallow copy if `self` is arc or vec.

However, in certain cases `split_off` or `split_to` is called with `len` or `0` parameter. E. g. if you are reading a frame from buffered stream, it is likely that buffer contains exactly the frame size bytes, so `split_to` will be called with `len` param.

Although, `split_off` and `split_to` functions are `O(1)`, shallow copy have downsides:

* shallow copy on vector does malloc and atomic cmpxchg
* after shallow copy, following operations (e. g. `drop`) on both `bytes` objects require atomics
* memory will be probably released to the system later
* `try_mut` will fail
* [into_vec](https://github.com/carllerche/bytes/issues/86) will copy
parent 6c6c55d8
No related branches found
No related tags found
No related merge requests found
......@@ -549,6 +549,14 @@ impl Bytes {
///
/// Panics if `at > len`
pub fn split_off(&mut self, at: usize) -> Bytes {
if at == self.len() {
return Bytes::new();
}
if at == 0 {
return mem::replace(self, Bytes::new());
}
Bytes {
inner: Inner2 {
inner: self.inner.split_off(at),
......@@ -580,6 +588,14 @@ impl Bytes {
///
/// Panics if `at > len`
pub fn split_to(&mut self, at: usize) -> Bytes {
if at == self.len() {
return mem::replace(self, Bytes::new());
}
if at == 0 {
return Bytes::new();
}
Bytes {
inner: Inner2 {
inner: self.inner.split_to(at),
......
......@@ -134,6 +134,50 @@ fn split_off_uninitialized() {
assert_eq!(other.capacity(), 896);
}
#[test]
fn split_off_to_loop() {
let s = b"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
for i in 0..(s.len() + 1) {
{
let mut bytes = Bytes::from(&s[..]);
let off = bytes.split_off(i);
assert_eq!(i, bytes.len());
let mut sum = Vec::new();
sum.extend(&bytes);
sum.extend(&off);
assert_eq!(&s[..], &sum[..]);
}
{
let mut bytes = BytesMut::from(&s[..]);
let off = bytes.split_off(i);
assert_eq!(i, bytes.len());
let mut sum = Vec::new();
sum.extend(&bytes);
sum.extend(&off);
assert_eq!(&s[..], &sum[..]);
}
{
let mut bytes = Bytes::from(&s[..]);
let off = bytes.split_to(i);
assert_eq!(i, off.len());
let mut sum = Vec::new();
sum.extend(&off);
sum.extend(&bytes);
assert_eq!(&s[..], &sum[..]);
}
{
let mut bytes = BytesMut::from(&s[..]);
let off = bytes.split_to(i);
assert_eq!(i, off.len());
let mut sum = Vec::new();
sum.extend(&off);
sum.extend(&bytes);
assert_eq!(&s[..], &sum[..]);
}
}
}
#[test]
fn split_to_1() {
// Inline
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment