Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 4 additions & 44 deletions benches/bench.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
#![feature(test)]
#![allow(deprecated)]

extern crate test;

use smallvec::{smallvec, SmallVec};
use test::Bencher;

use {
smallvec::{smallvec, SmallVec},
test::Bencher,
};
const VEC_SIZE: usize = 16;
const SPILLED_SIZE: usize = 100;

trait Vector<T>: for<'a> From<&'a [T]> + Extend<T> {
fn new() -> Self;
fn push(&mut self, val: T);
Expand All @@ -19,75 +17,58 @@ trait Vector<T>: for<'a> From<&'a [T]> + Extend<T> {
fn from_elems(val: &[T]) -> Self;
fn extend_from_slice(&mut self, other: &[T]);
}

impl<T: Copy> Vector<T> for Vec<T> {
fn new() -> Self {
Self::with_capacity(VEC_SIZE)
}

fn push(&mut self, val: T) {
self.push(val)
}

fn pop(&mut self) -> Option<T> {
self.pop()
}

fn remove(&mut self, p: usize) -> T {
self.remove(p)
}

fn insert(&mut self, n: usize, val: T) {
self.insert(n, val)
}

fn from_elem(val: T, n: usize) -> Self {
vec![val; n]
}

fn from_elems(val: &[T]) -> Self {
val.to_owned()
}

fn extend_from_slice(&mut self, other: &[T]) {
Vec::extend_from_slice(self, other)
}
}

impl<T: Copy> Vector<T> for SmallVec<T, VEC_SIZE> {
fn new() -> Self {
Self::new()
}

fn push(&mut self, val: T) {
self.push(val)
}

fn pop(&mut self) -> Option<T> {
self.pop()
}

fn remove(&mut self, p: usize) -> T {
self.remove(p)
}

fn insert(&mut self, n: usize, val: T) {
self.insert(n, val)
}

fn from_elem(val: T, n: usize) -> Self {
smallvec![val; n]
}

fn from_elems(val: &[T]) -> Self {
SmallVec::from(val)
}

fn extend_from_slice(&mut self, other: &[T]) {
SmallVec::extend_from_slice(self, other)
}
}

macro_rules! make_benches {
($typ:ty { $($b_name:ident => $g_name:ident($($args:expr),*),)* }) => {
$(
Expand All @@ -98,7 +79,6 @@ macro_rules! make_benches {
)*
}
}

make_benches! {
SmallVec<u64, VEC_SIZE> {
bench_push => gen_push(SPILLED_SIZE as _),
Expand All @@ -124,7 +104,6 @@ make_benches! {
bench_pushpop => gen_pushpop(),
}
}

make_benches! {
Vec<u64> {
bench_push_vec => gen_push(SPILLED_SIZE as _),
Expand All @@ -150,13 +129,11 @@ make_benches! {
bench_pushpop_vec => gen_pushpop(),
}
}

fn gen_push<V: Vector<u64>>(n: u64, b: &mut Bencher) {
#[inline(never)]
fn push_noinline<V: Vector<u64>>(vec: &mut V, x: u64) {
vec.push(x);
}

b.iter(|| {
let mut vec = V::new();
for x in 0..n {
Expand All @@ -165,13 +142,11 @@ fn gen_push<V: Vector<u64>>(n: u64, b: &mut Bencher) {
vec
});
}

fn gen_insert_push<V: Vector<u64>>(n: u64, b: &mut Bencher) {
#[inline(never)]
fn insert_push_noinline<V: Vector<u64>>(vec: &mut V, x: u64) {
vec.insert(x as usize, x);
}

b.iter(|| {
let mut vec = V::new();
for x in 0..n {
Expand All @@ -180,13 +155,11 @@ fn gen_insert_push<V: Vector<u64>>(n: u64, b: &mut Bencher) {
vec
});
}

fn gen_insert<V: Vector<u64>>(n: u64, b: &mut Bencher) {
#[inline(never)]
fn insert_noinline<V: Vector<u64>>(vec: &mut V, p: usize, x: u64) {
vec.insert(p, x)
}

b.iter(|| {
let mut vec = V::new();
// Always insert at position 0 so that we are subject to shifts of
Expand All @@ -198,54 +171,46 @@ fn gen_insert<V: Vector<u64>>(n: u64, b: &mut Bencher) {
vec
});
}

fn gen_remove<V: Vector<u64>>(n: usize, b: &mut Bencher) {
#[inline(never)]
fn remove_noinline<V: Vector<u64>>(vec: &mut V, p: usize) -> u64 {
vec.remove(p)
}

b.iter(|| {
let mut vec = V::from_elem(0, n as _);

for _ in 0..n {
remove_noinline(&mut vec, 0);
}
});
}

fn gen_extend<V: Vector<u64>>(n: u64, b: &mut Bencher) {
b.iter(|| {
let mut vec = V::new();
vec.extend(0..n);
vec
});
}

fn gen_extend_filtered<V: Vector<u64>>(n: u64, b: &mut Bencher) {
b.iter(|| {
let mut vec = V::new();
vec.extend((0..n).filter(|i| i % 2 == 0));
vec
});
}

fn gen_from_iter<V: Vector<u64>>(n: u64, b: &mut Bencher) {
let v: Vec<u64> = (0..n).collect();
b.iter(|| {
let vec = V::from(&v);
vec
});
}

fn gen_from_slice<V: Vector<u64>>(n: u64, b: &mut Bencher) {
let v: Vec<u64> = (0..n).collect();
b.iter(|| {
let vec = V::from_elems(&v);
vec
});
}

fn gen_extend_from_slice<V: Vector<u64>>(n: u64, b: &mut Bencher) {
let v: Vec<u64> = (0..n).collect();
b.iter(|| {
Expand All @@ -254,14 +219,12 @@ fn gen_extend_from_slice<V: Vector<u64>>(n: u64, b: &mut Bencher) {
vec
});
}

fn gen_pushpop<V: Vector<u64>>(b: &mut Bencher) {
#[inline(never)]
fn pushpop_noinline<V: Vector<u64>>(vec: &mut V, x: u64) -> Option<u64> {
vec.push(x);
vec.pop()
}

b.iter(|| {
let mut vec = V::new();
for x in 0..SPILLED_SIZE as _ {
Expand All @@ -270,14 +233,12 @@ fn gen_pushpop<V: Vector<u64>>(b: &mut Bencher) {
vec
});
}

fn gen_from_elem<V: Vector<u64>>(n: usize, b: &mut Bencher) {
b.iter(|| {
let vec = V::from_elem(42, n);
vec
});
}

#[bench]
fn bench_macro_from_list(b: &mut Bencher) {
b.iter(|| {
Expand All @@ -289,7 +250,6 @@ fn bench_macro_from_list(b: &mut Bencher) {
vec
});
}

#[bench]
fn bench_macro_from_list_vec(b: &mut Bencher) {
b.iter(|| {
Expand Down
10 changes: 10 additions & 0 deletions rustfmt.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
wrap_comments = true
imports_granularity = "One"
group_imports = "One"
format_code_in_doc_comments = true
match_arm_blocks = false
blank_lines_lower_bound = 0
blank_lines_upper_bound = 0
condense_wildcard_suffixes = true
error_on_unformatted = true
error_on_line_overflow = true
24 changes: 24 additions & 0 deletions src/allocationerror.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
use {
alloc::alloc::Layout,
core::{
error::Error,
fmt::{Display, Formatter, Result as Format},
},
};
/// Error type for APIs with fallible heap allocation
#[derive(Debug)]
pub enum AllocationError {
/// Overflow `usize::MAX` or other error during size computation
CapacityOverflow,
/// The allocator return an error
Failure {
/// The layout that was passed to the allocator
layout: Layout,
},
}
impl Display for AllocationError {
fn fmt(&self, f: &mut Formatter) -> Format {
write!(f, "Allocation error: {:?}", self)
}
}
impl Error for AllocationError {}
60 changes: 60 additions & 0 deletions src/bytes.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
use {
super::SmallVec,
bytes::{buf::UninitSlice, BufMut},
};
unsafe impl<const N: usize> BufMut for SmallVec<u8, N> {
#[inline]
fn remaining_mut(&self) -> usize {
// A vector can never have more than isize::MAX bytes
isize::MAX as usize - self.len()
}
#[inline]
unsafe fn advance_mut(&mut self, cnt: usize) {
let len = self.len();
let remaining = self.capacity() - len;
if remaining < cnt {
panic!("advance out of bounds: the len is {remaining} but advancing by {cnt}");
}
// Addition will not overflow since the sum is at most the capacity.
self.set_len(len + cnt);
}
#[inline]
fn chunk_mut(&mut self) -> &mut UninitSlice {
if self.capacity() == self.len() {
self.reserve(64); // Grow the smallvec
}
let cap = self.capacity();
let len = self.len();
let ptr = self.as_mut_ptr();
// SAFETY: Since `ptr` is valid for `cap` bytes, `ptr.add(len)` must be
// valid for `cap - len` bytes. The subtraction will not underflow since
// `len <= cap`.
unsafe { UninitSlice::from_raw_parts_mut(ptr.add(len), cap - len) }
}
// Specialize these methods so they can skip checking `remaining_mut`
// and `advance_mut`.
#[inline]
fn put<T: bytes::Buf>(&mut self, mut src: T)
where
Self: Sized,
{
// In case the src isn't contiguous, reserve upfront.
self.reserve(src.remaining());
while src.has_remaining() {
let s = src.chunk();
let l = s.len();
self.extend_from_slice(s);
src.advance(l);
}
}
#[inline]
fn put_slice(&mut self, src: &[u8]) {
self.extend_from_slice(src);
}
#[inline]
fn put_bytes(&mut self, val: u8, cnt: usize) {
// If the addition overflows, then the `resize` will fail.
let new_len = self.len().saturating_add(cnt);
self.resize(new_len, val);
}
}
Loading
Loading