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
Comment on lines +6 to +7

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think removing all blank lines improves readability; I think it makes it worse. Also note that servo/servo doesn't do this (example)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fair

then probably 0 for lower bound and 1 for upper I guess. 2+ looks weird to me

did it out of inertia, didn't think much about it, I'll fix it tomorrow

code looks weird though now that you're saying it

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