Skip to content

Commit 7d5fac7

Browse files
authored
Merge pull request #4394 from RalfJung/smallvec
add SmallVec test
2 parents 19f195d + 3e980d5 commit 7d5fac7

File tree

1 file changed

+99
-0
lines changed

1 file changed

+99
-0
lines changed
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
//! This test represents a core part of `SmallVec`'s `extend_impl`.
2+
//! What makes it interesting as a test is that it relies on Stacked Borrow's "quirk"
3+
//! in a fundamental, hard-to-fix-without-full-trees way.
4+
5+
//@revisions: stack tree
6+
//@[tree]compile-flags: -Zmiri-tree-borrows
7+
8+
use std::marker::PhantomData;
9+
use std::mem::{ManuallyDrop, MaybeUninit};
10+
use std::ptr::NonNull;
11+
12+
#[repr(C)]
13+
pub union RawSmallVec<T, const N: usize> {
14+
inline: ManuallyDrop<MaybeUninit<[T; N]>>,
15+
heap: (NonNull<T>, usize),
16+
}
17+
18+
impl<T, const N: usize> RawSmallVec<T, N> {
19+
const fn new() -> Self {
20+
Self::new_inline(MaybeUninit::uninit())
21+
}
22+
23+
const fn new_inline(inline: MaybeUninit<[T; N]>) -> Self {
24+
Self { inline: ManuallyDrop::new(inline) }
25+
}
26+
27+
const fn as_mut_ptr_inline(&mut self) -> *mut T {
28+
(unsafe { &raw mut self.inline }) as *mut T
29+
}
30+
31+
const unsafe fn as_mut_ptr_heap(&mut self) -> *mut T {
32+
self.heap.0.as_ptr()
33+
}
34+
}
35+
36+
#[repr(transparent)]
37+
#[derive(Clone, Copy)]
38+
struct TaggedLen(usize);
39+
40+
impl TaggedLen {
41+
pub const fn new(len: usize, on_heap: bool, is_zst: bool) -> Self {
42+
if is_zst {
43+
debug_assert!(!on_heap);
44+
TaggedLen(len)
45+
} else {
46+
debug_assert!(len < isize::MAX as usize);
47+
TaggedLen((len << 1) | on_heap as usize)
48+
}
49+
}
50+
51+
pub const fn on_heap(self, is_zst: bool) -> bool {
52+
if is_zst { false } else { (self.0 & 1_usize) == 1 }
53+
}
54+
55+
pub const fn value(self, is_zst: bool) -> usize {
56+
if is_zst { self.0 } else { self.0 >> 1 }
57+
}
58+
}
59+
60+
#[repr(C)]
61+
pub struct SmallVec<T, const N: usize> {
62+
len: TaggedLen,
63+
raw: RawSmallVec<T, N>,
64+
_marker: PhantomData<T>,
65+
}
66+
67+
impl<T, const N: usize> SmallVec<T, N> {
68+
pub const fn new() -> SmallVec<T, N> {
69+
Self {
70+
len: TaggedLen::new(0, false, Self::is_zst()),
71+
raw: RawSmallVec::new(),
72+
_marker: PhantomData,
73+
}
74+
}
75+
76+
const fn is_zst() -> bool {
77+
size_of::<T>() == 0
78+
}
79+
80+
pub const fn as_mut_ptr(&mut self) -> *mut T {
81+
if self.len.on_heap(Self::is_zst()) {
82+
// SAFETY: see above
83+
unsafe { self.raw.as_mut_ptr_heap() }
84+
} else {
85+
self.raw.as_mut_ptr_inline()
86+
}
87+
}
88+
89+
pub const fn len(&self) -> usize {
90+
self.len.value(Self::is_zst())
91+
}
92+
}
93+
94+
fn main() {
95+
let mut v = SmallVec::<i32, 4>::new();
96+
let ptr = v.as_mut_ptr();
97+
let _len = v.len(); // this call incurs a reborrow which just barely does not invalidate `ptr`
98+
unsafe { ptr.write(0) };
99+
}

0 commit comments

Comments
 (0)