Skip to content

Commit 3e2eeca

Browse files
author
sarah el kazdadi
committed
perf: implement specialization based dispatch for improved perf
1 parent c8edfa2 commit 3e2eeca

File tree

1 file changed

+88
-10
lines changed

1 file changed

+88
-10
lines changed

src/lib.rs

Lines changed: 88 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@
4747
//! Tracking issue: [rust-lang/rust#34761](https://github.com/rust-lang/rust/issues/34761)
4848
4949
#![no_std]
50+
#![cfg_attr(docsrs, feature(doc_cfg))]
51+
#![cfg_attr(feature = "specialization", allow(incomplete_features))]
52+
#![cfg_attr(feature = "specialization", feature(specialization))]
53+
#![cfg_attr(feature = "may_dangle", feature(dropck_eyepatch))]
5054

5155
#[doc(hidden)]
5256
pub extern crate alloc;
@@ -73,8 +77,8 @@ use core::ptr::addr_of;
7377
use core::ptr::addr_of_mut;
7478
use core::ptr::copy_nonoverlapping;
7579

76-
#[cfg(feature = "serde")]
7780
use core::marker::PhantomData;
81+
7882
#[cfg(feature = "serde")]
7983
use serde::{
8084
de::{Deserialize, Deserializer, SeqAccess, Visitor},
@@ -279,6 +283,7 @@ impl TaggedLen {
279283
pub struct SmallVec<T, const N: usize> {
280284
len: TaggedLen,
281285
raw: RawSmallVec<T, N>,
286+
_marker: PhantomData<T>,
282287
}
283288

284289
/// An iterator that removes the items from a `SmallVec` and yields them by value.
@@ -361,6 +366,7 @@ pub struct IntoIter<T, const N: usize> {
361366
raw: RawSmallVec<T, N>,
362367
begin: usize,
363368
end: TaggedLen,
369+
_marker: PhantomData<T>,
364370
}
365371

366372
impl<T, const N: usize> IntoIter<T, N> {
@@ -468,13 +474,16 @@ impl<T, const N: usize> SmallVec<T, N> {
468474
Self {
469475
len: TaggedLen::new(0, false, Self::is_zst()),
470476
raw: RawSmallVec::new(),
477+
_marker: PhantomData,
471478
}
472479
}
473480

474481
#[inline]
475482
pub fn with_capacity(capacity: usize) -> Self {
476483
let mut this = Self::new();
477-
this.reserve_exact(capacity);
484+
if capacity > Self::inline_size() {
485+
this.grow(capacity);
486+
}
478487
this
479488
}
480489

@@ -494,6 +503,7 @@ impl<T, const N: usize> SmallVec<T, N> {
494503
Self {
495504
len: TaggedLen::new(len, false, Self::is_zst()),
496505
raw: RawSmallVec::new(),
506+
_marker: PhantomData,
497507
}
498508
} else {
499509
let mut vec = ManuallyDrop::new(vec);
@@ -504,6 +514,7 @@ impl<T, const N: usize> SmallVec<T, N> {
504514
Self {
505515
len: TaggedLen::new(len, true, Self::is_zst()),
506516
raw: RawSmallVec::new_heap(ptr, cap),
517+
_marker: PhantomData,
507518
}
508519
}
509520
}
@@ -513,6 +524,7 @@ impl<T, const N: usize> SmallVec<T, N> {
513524
Self {
514525
len: TaggedLen::new(N, false, Self::is_zst()),
515526
raw: RawSmallVec::new_inline(MaybeUninit::new(buf)),
527+
_marker: PhantomData,
516528
}
517529
}
518530

@@ -522,6 +534,7 @@ impl<T, const N: usize> SmallVec<T, N> {
522534
let mut vec = Self {
523535
len: TaggedLen::new(len, false, Self::is_zst()),
524536
raw: RawSmallVec::new_inline(MaybeUninit::new(buf)),
537+
_marker: PhantomData,
525538
};
526539
// Deallocate the remaining elements so no memory is leaked.
527540
unsafe {
@@ -545,6 +558,7 @@ impl<T, const N: usize> SmallVec<T, N> {
545558
Self {
546559
len: TaggedLen::new(len, false, Self::is_zst()),
547560
raw: RawSmallVec::new_inline(buf),
561+
_marker: PhantomData,
548562
}
549563
}
550564

@@ -684,7 +698,7 @@ impl<T, const N: usize> SmallVec<T, N> {
684698
infallible(self.try_grow(new_capacity));
685699
}
686700

687-
#[inline]
701+
#[cold]
688702
pub fn try_grow(&mut self, new_capacity: usize) -> Result<(), CollectionAllocErr> {
689703
let len = self.len();
690704
assert!(new_capacity >= len);
@@ -1043,6 +1057,7 @@ impl<T, const N: usize> SmallVec<T, N> {
10431057
SmallVec {
10441058
len: TaggedLen::new(length, true, Self::is_zst()),
10451059
raw: RawSmallVec::new_heap(ptr, capacity),
1060+
_marker: PhantomData,
10461061
}
10471062
}
10481063

@@ -1070,14 +1085,23 @@ impl<T: Copy, const N: usize> SmallVec<T, N> {
10701085
#[inline]
10711086
pub fn from_slice(slice: &[T]) -> Self {
10721087
let len = slice.len();
1073-
1074-
let mut this = Self::with_capacity(len);
1075-
let ptr = this.as_mut_ptr();
1076-
unsafe {
1077-
copy_nonoverlapping(slice.as_ptr(), ptr, len);
1078-
this.set_len(len);
1088+
if len <= Self::inline_size() {
1089+
let mut this = Self::new();
1090+
unsafe {
1091+
let ptr = this.raw.as_mut_ptr_inline();
1092+
copy_nonoverlapping(slice.as_ptr(), ptr, len);
1093+
this.set_len(len);
1094+
}
1095+
this
1096+
} else {
1097+
let mut this = Vec::with_capacity(len);
1098+
unsafe {
1099+
let ptr = this.as_mut_ptr();
1100+
copy_nonoverlapping(slice.as_ptr(), ptr, len);
1101+
this.set_len(len);
1102+
}
1103+
Self::from_vec(this)
10791104
}
1080-
this
10811105
}
10821106

10831107
#[inline]
@@ -1250,6 +1274,29 @@ impl Drop for DropDealloc {
12501274
}
12511275
}
12521276

1277+
#[cfg(feature = "may_dangle")]
1278+
unsafe impl<#[may_dangle] T, const N: usize> Drop for SmallVec<T, N> {
1279+
fn drop(&mut self) {
1280+
let on_heap = self.spilled();
1281+
let len = self.len();
1282+
let ptr = self.as_mut_ptr();
1283+
unsafe {
1284+
let _drop_dealloc = if on_heap {
1285+
let capacity = self.capacity();
1286+
Some(DropDealloc {
1287+
ptr: ptr as *mut u8,
1288+
size_bytes: capacity * size_of::<T>(),
1289+
align: align_of::<T>(),
1290+
})
1291+
} else {
1292+
None
1293+
};
1294+
core::ptr::slice_from_raw_parts_mut(ptr, len).drop_in_place();
1295+
}
1296+
}
1297+
}
1298+
1299+
#[cfg(not(feature = "may_dangle"))]
12531300
impl<T, const N: usize> Drop for SmallVec<T, N> {
12541301
fn drop(&mut self) {
12551302
let on_heap = self.spilled();
@@ -1318,6 +1365,36 @@ impl<T, const N: usize> core::iter::FromIterator<T> for SmallVec<T, N> {
13181365
}
13191366
}
13201367

1368+
#[cfg(feature = "specialization")]
1369+
trait SpecFrom {
1370+
type Element;
1371+
fn spec_from(slice: &[Self::Element]) -> Self;
1372+
}
1373+
1374+
#[cfg(feature = "specialization")]
1375+
impl<T: Clone, const N: usize> SpecFrom for SmallVec<T, N> {
1376+
type Element = T;
1377+
1378+
default fn spec_from(slice: &[Self::Element]) -> Self {
1379+
slice.iter().cloned().collect()
1380+
}
1381+
}
1382+
1383+
#[cfg(feature = "specialization")]
1384+
impl<T: Copy, const N: usize> SpecFrom for SmallVec<T, N> {
1385+
fn spec_from(slice: &[Self::Element]) -> Self {
1386+
Self::from_slice(slice)
1387+
}
1388+
}
1389+
1390+
#[cfg(feature = "specialization")]
1391+
impl<'a, T: Clone, const N: usize> From<&'a [T]> for SmallVec<T, N> {
1392+
fn from(slice: &'a [T]) -> Self {
1393+
<Self as SpecFrom>::spec_from(slice)
1394+
}
1395+
}
1396+
1397+
#[cfg(not(feature = "specialization"))]
13211398
impl<'a, T: Clone, const N: usize> From<&'a [T]> for SmallVec<T, N> {
13221399
fn from(slice: &'a [T]) -> Self {
13231400
slice.iter().cloned().collect()
@@ -1408,6 +1485,7 @@ impl<T, const N: usize> IntoIterator for SmallVec<T, N> {
14081485
raw: (&this.raw as *const RawSmallVec<T, N>).read(),
14091486
begin: 0,
14101487
end: this.len,
1488+
_marker: PhantomData,
14111489
}
14121490
}
14131491
}

0 commit comments

Comments
 (0)