diff --git a/Cargo.toml b/Cargo.toml index 258897f4..d579ebcc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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"] diff --git a/README.md b/README.md index 46d34836..3b5841f5 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,8 @@ 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 @@ -54,7 +55,6 @@ v.sort(); - `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 @@ -62,5 +62,5 @@ v.sort(); > [!NOTE] > - SmallVec without any features enabled does not make use of the standard library. -> -> - The `rayon` feature implicitly requires `std`. \ No newline at end of file +> - The `rayon` feature implicitly requires `std`. +> - The `allocator-api2` feature requires `allocator-api` \ No newline at end of file diff --git a/src/allocator/base.rs b/src/allocator/base.rs new file mode 100644 index 00000000..76ec54e8 --- /dev/null +++ b/src/allocator/base.rs @@ -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> { + Some(NonNull::slice_from_raw_parts( + NonNull::new(unsafe { alloc(layout) })?, + layout.size() + )) + } + + #[inline] + unsafe fn deallocate(&self, pointer: NonNull, layout: Layout) { + unsafe { dealloc(pointer.as_ptr(), layout) }; + } + + #[inline] + unsafe fn grow(&self, pointer: NonNull, old: Layout, new: Layout) -> Option> { + 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, + old: Layout, + new: Layout + ) -> Option> { + Some(NonNull::slice_from_raw_parts( + NonNull::new(unsafe { realloc(pointer.as_ptr(), old, new.size()) })?, + new.size() + )) + } +} diff --git a/src/allocator/external.rs b/src/allocator/external.rs new file mode 100644 index 00000000..635a8697 --- /dev/null +++ b/src/allocator/external.rs @@ -0,0 +1,35 @@ +use { + super::Allocator, + allocator_api2::alloc::Allocator as External, + core::{ + alloc::Layout, + ptr::NonNull + } +}; + +impl Allocator for Type { + #[inline] + fn allocate(&self, layout: Layout) -> Option> { + External::allocate(&self, layout).ok() + } + + #[inline] + unsafe fn deallocate(&self, pointer: NonNull, layout: Layout) { + unsafe { External::deallocate(&self, pointer, layout) } + } + + #[inline] + unsafe fn grow(&self, pointer: NonNull, old: Layout, new: Layout) -> Option> { + unsafe { External::grow(&self, pointer, old, new).ok() } + } + + #[inline] + unsafe fn shrink( + &self, + pointer: NonNull, + old: Layout, + new: Layout + ) -> Option> { + unsafe { External::shrink(&self, pointer, old, new).ok() } + } +} diff --git a/src/allocator/mod.rs b/src/allocator/mod.rs new file mode 100644 index 00000000..2e212219 --- /dev/null +++ b/src/allocator/mod.rs @@ -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>; + unsafe fn deallocate(&self, pointer: NonNull, layout: Layout); + unsafe fn grow(&self, pointer: NonNull, old: Layout, new: Layout) -> Option>; + unsafe fn shrink( + &self, + pointer: NonNull, + old: Layout, + new: Layout + ) -> Option>; +} diff --git a/src/allocator/native.rs b/src/allocator/native.rs new file mode 100644 index 00000000..77603616 --- /dev/null +++ b/src/allocator/native.rs @@ -0,0 +1,35 @@ +use { + super::Allocator, + alloc::alloc::Allocator as Native, + core::{ + alloc::Layout, + ptr::NonNull + } +}; + +impl Allocator for Type { + #[inline] + fn allocate(&self, layout: Layout) -> Option> { + Native::allocate(&self, layout).ok() + } + + #[inline] + unsafe fn deallocate(&self, pointer: NonNull, layout: Layout) { + unsafe { Native::deallocate(&self, pointer, layout) } + } + + #[inline] + unsafe fn grow(&self, pointer: NonNull, old: Layout, new: Layout) -> Option> { + unsafe { Native::grow(&self, pointer, old, new).ok() } + } + + #[inline] + unsafe fn shrink( + &self, + pointer: NonNull, + old: Layout, + new: Layout + ) -> Option> { + unsafe { Native::shrink(&self, pointer, old, new).ok() } + } +} diff --git a/src/conversions.rs b/src/conversions.rs index 3e5bded8..335c8e9a 100644 --- a/src/conversions.rs +++ b/src/conversions.rs @@ -1,9 +1,9 @@ use { crate::{ Allocator, - SmallVec + SmallVec, + Vec }, - alloc::vec::Vec, core::{ mem::ManuallyDrop, ptr::copy_nonoverlapping diff --git a/src/lib.rs b/src/lib.rs index 5434d44f..56f8731c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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; @@ -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, @@ -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, @@ -1786,7 +1783,7 @@ impl Drop for IntoIter { pub fn from_elem(elem: T, n: usize) -> SmallVec { if n > SmallVec::::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")] { diff --git a/src/rawsmallvec.rs b/src/rawsmallvec.rs index ace0e6ad..f5722b3b 100644 --- a/src/rawsmallvec.rs +++ b/src/rawsmallvec.rs @@ -128,7 +128,7 @@ impl RawSmallVec { // `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 @@ -159,7 +159,7 @@ impl RawSmallVec { new_layout ) } - .map_err(|_| SmallVecError::AllocationError(new_layout))? + .ok_or(SmallVecError::AllocationError(new_layout))? .cast() }; self.heap = (new_ptr, new_capacity); diff --git a/tests/main.rs b/tests/main.rs index 6c11a3e3..2707c0a6 100644 --- a/tests/main.rs +++ b/tests/main.rs @@ -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::{ @@ -14,10 +24,8 @@ use { smallvec::SmallVec, std::{ borrow::ToOwned, - boxed::Box, hash::DefaultHasher, - rc::Rc, - vec::Vec + rc::Rc } };