Skip to content
Merged
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
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ debug = false
strip = true

[features]
default = ["allocator-api2"]
allocator-api = []
allocator-api2 = ["dep:allocator-api2", "allocator-api"]
internals = []
rayon = ["std", "dep:rayon"]
serde = ["dep:serde_core"]
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,21 +46,21 @@ v.sort();

## Feature List

- `allocator-api2` (default enabled, nightly if disabled): uses the `allocator-api2` backend for the allocator API, otherwise it uses unstable alloc traits
- `allocator-api` (nightly): uses the `allocator-api` backend for the allocator API
- `allocator-api2`: uses the `allocator-api2` backend for the allocator API
- `arbitrary`: implements `Arbitrary` for any `SmallVec` storing elements that implement `Arbitrary`
- `borsh`: implements `BorshSerialize`, `BorshDeserialize` and `BorshSchema`
- `bytes`: implements `BufMut` for SmallVec
- `defmt`: implements `defmt::Format` for SmallVec
- `encase`: implements encasing as a runtime-sized array
- `internals`: exports through the public API `TaggedLen` and `RawSmallVec`
- `malloc_size_of`: implements `MallocSizeOf` and `MallocShallowSizeOf`
- `may_dangle` (nightly): enables the eyepatch optimization for dropping
- `rayon`: implements parallel iteration
- `serde`: implements serde's serialization and deserialization
- `specialization` (nightly): enables specialization, improving performance on some cases
- `std`: implements the `std::io::Write` type for `SmallVec<u8, N>`

> [!NOTE]
> - SmallVec without any features enabled does not make use of the standard library.
>
> - The `rayon` feature implicitly requires `std`.
> - The `rayon` feature implicitly requires `std`.
> - The `allocator-api2` feature requires `allocator-api`
51 changes: 51 additions & 0 deletions src/allocator/base.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
use {
super::Allocator,
alloc::alloc::{
alloc,
dealloc,
realloc
},
core::{
alloc::Layout,
ptr::NonNull
}
};

#[derive(Clone)]
pub struct Global;

impl Allocator for Global {
#[inline]
fn allocate(&self, layout: Layout) -> Option<NonNull<[u8]>> {
Some(NonNull::slice_from_raw_parts(
NonNull::new(unsafe { alloc(layout) })?,
layout.size()
))
}

#[inline]
unsafe fn deallocate(&self, pointer: NonNull<u8>, layout: Layout) {
unsafe { dealloc(pointer.as_ptr(), layout) };
}

#[inline]
unsafe fn grow(&self, pointer: NonNull<u8>, old: Layout, new: Layout) -> Option<NonNull<[u8]>> {
Some(NonNull::slice_from_raw_parts(
NonNull::new(unsafe { realloc(pointer.as_ptr(), old, new.size()) })?,
new.size()
))
}

#[inline]
unsafe fn shrink(
&self,
pointer: NonNull<u8>,
old: Layout,
new: Layout
) -> Option<NonNull<[u8]>> {
Some(NonNull::slice_from_raw_parts(
NonNull::new(unsafe { realloc(pointer.as_ptr(), old, new.size()) })?,
new.size()
))
}
}
35 changes: 35 additions & 0 deletions src/allocator/external.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
use {
super::Allocator,
allocator_api2::alloc::Allocator as External,
core::{
alloc::Layout,
ptr::NonNull
}
};

impl<Type: External> Allocator for Type {
#[inline]
fn allocate(&self, layout: Layout) -> Option<NonNull<[u8]>> {
External::allocate(&self, layout).ok()
}

#[inline]
unsafe fn deallocate(&self, pointer: NonNull<u8>, layout: Layout) {
unsafe { External::deallocate(&self, pointer, layout) }
}

#[inline]
unsafe fn grow(&self, pointer: NonNull<u8>, old: Layout, new: Layout) -> Option<NonNull<[u8]>> {
unsafe { External::grow(&self, pointer, old, new).ok() }
}

#[inline]
unsafe fn shrink(
&self,
pointer: NonNull<u8>,
old: Layout,
new: Layout
) -> Option<NonNull<[u8]>> {
unsafe { External::shrink(&self, pointer, old, new).ok() }
}
}
50 changes: 50 additions & 0 deletions src/allocator/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#[cfg(not(feature = "allocator-api"))]
mod base;
#[cfg(feature = "allocator-api2")]
mod external;
#[cfg(all(feature = "allocator-api", not(feature = "allocator-api2")))]
mod native;

use core::{
alloc::Layout,
ptr::NonNull
};

#[cfg(not(feature = "allocator-api"))]
#[rustfmt::skip]
pub use {
alloc::{
boxed::Box,
vec::Vec,
vec
},
base::Global
};
#[cfg(feature = "allocator-api2")]
#[rustfmt::skip]
pub use allocator_api2::{
alloc::Global,
boxed::Box,
vec::Vec,
vec
};
#[cfg(all(feature = "allocator-api", not(feature = "allocator-api2")))]
#[rustfmt::skip]
pub use alloc::{
alloc::Global,
boxed::Box,
vec::Vec,
vec
};

pub trait Allocator {
fn allocate(&self, layout: Layout) -> Option<NonNull<[u8]>>;
unsafe fn deallocate(&self, pointer: NonNull<u8>, layout: Layout);
unsafe fn grow(&self, pointer: NonNull<u8>, old: Layout, new: Layout) -> Option<NonNull<[u8]>>;
unsafe fn shrink(
&self,
pointer: NonNull<u8>,
old: Layout,
new: Layout
) -> Option<NonNull<[u8]>>;
}
35 changes: 35 additions & 0 deletions src/allocator/native.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
use {
super::Allocator,
alloc::alloc::Allocator as Native,
core::{
alloc::Layout,
ptr::NonNull
}
};

impl<Type: Native> Allocator for Type {
#[inline]
fn allocate(&self, layout: Layout) -> Option<NonNull<[u8]>> {
Native::allocate(&self, layout).ok()
}

#[inline]
unsafe fn deallocate(&self, pointer: NonNull<u8>, layout: Layout) {
unsafe { Native::deallocate(&self, pointer, layout) }
}

#[inline]
unsafe fn grow(&self, pointer: NonNull<u8>, old: Layout, new: Layout) -> Option<NonNull<[u8]>> {
unsafe { Native::grow(&self, pointer, old, new).ok() }
}

#[inline]
unsafe fn shrink(
&self,
pointer: NonNull<u8>,
old: Layout,
new: Layout
) -> Option<NonNull<[u8]>> {
unsafe { Native::shrink(&self, pointer, old, new).ok() }
}
}
4 changes: 2 additions & 2 deletions src/conversions.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use {
crate::{
Allocator,
SmallVec
SmallVec,
Vec
},
alloc::vec::Vec,
core::{
mem::ManuallyDrop,
ptr::copy_nonoverlapping
Expand Down
27 changes: 12 additions & 15 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,14 @@
#![cfg_attr(docsrs, feature(doc_cfg))]
#![cfg_attr(feature = "specialization", allow(incomplete_features))]
#![cfg_attr(feature = "specialization", feature(specialization, trusted_len))]
#![cfg_attr(not(feature = "allocator-api2"), feature(allocator_api))]
#![cfg_attr(
all(feature = "allocator-api", not(feature = "allocator-api2")),
feature(allocator_api)
)]

extern crate alloc;

mod allocator;
#[cfg(feature = "borsh")]
mod borsh;
mod comparisons;
Expand All @@ -34,16 +38,6 @@ mod serde;
mod specialization;
mod taggedlen;

#[cfg(not(feature = "allocator-api2"))]
use alloc::alloc::{
Allocator,
Global
};
#[cfg(feature = "allocator-api2")]
use allocator_api2::alloc::{
Allocator,
Global
};
#[cfg(feature = "bytes")]
use bytes::{
BufMut,
Expand All @@ -59,9 +53,12 @@ pub use errors::SmallVecError;
#[cfg(feature = "std")]
use std::io;
use {
alloc::{
boxed::Box,
vec::Vec
allocator::{
Allocator,
Box,
Global,
Vec,
vec
},
core::{
alloc::Layout,
Expand Down Expand Up @@ -1786,7 +1783,7 @@ impl<T, const N: usize, A: Allocator> Drop for IntoIter<T, N, A> {
pub fn from_elem<T: Clone, const N: usize>(elem: T, n: usize) -> SmallVec<T, N> {
if n > SmallVec::<T, N>::inline_size() {
// Standard Rust vectors are already specialized.
SmallVec::from_vec(alloc::vec![elem; n])
SmallVec::from_vec(vec![elem; n])
} else {
#[cfg(feature = "specialization")]
{
Expand Down
4 changes: 2 additions & 2 deletions src/rawsmallvec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ impl<T, const N: usize> RawSmallVec<T, N> {
// `new_layout` has nonzero size.
let new_ptr = allocator
.allocate(new_layout)
.map_err(|_| SmallVecError::AllocationError(new_layout))?
.ok_or(SmallVecError::AllocationError(new_layout))?
.cast();
unsafe { copy_nonoverlapping(ptr, new_ptr.as_ptr(), len) };
new_ptr
Expand Down Expand Up @@ -159,7 +159,7 @@ impl<T, const N: usize> RawSmallVec<T, N> {
new_layout
)
}
.map_err(|_| SmallVecError::AllocationError(new_layout))?
.ok_or(SmallVecError::AllocationError(new_layout))?
.cast()
};
self.heap = (new_ptr, new_capacity);
Expand Down
14 changes: 11 additions & 3 deletions tests/main.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
#[cfg(feature = "allocator-api2")]
use allocator_api2::{
boxed::Box,
vec::Vec
};
#[cfg(not(feature = "allocator-api2"))]
use std::{
boxed::Box,
vec::Vec
};
use {
core::{
borrow::{
Expand All @@ -14,10 +24,8 @@ use {
smallvec::SmallVec,
std::{
borrow::ToOwned,
boxed::Box,
hash::DefaultHasher,
rc::Rc,
vec::Vec
rc::Rc
}
};

Expand Down
Loading