@@ -34,12 +34,18 @@ use hash32;
34
34
/// assert_eq!(*vec, [7, 1, 2, 3]);
35
35
/// ```
36
36
pub struct Vec < T , const N : usize > {
37
- buffer : [ MaybeUninit < T > ; N ] ,
37
+ // NOTE order is important for optimizations. the `len` first layout lets the compiler optimize
38
+ // `new` to: reserve stack space and zero the first word. With the fields in the reverse order
39
+ // the compiler optimizes `new` to `memclr`-ing the *entire* stack space, including the `buffer`
40
+ // field which should be left uninitialized. Optimizations were last checked with Rust 1.60
38
41
len : usize ,
42
+
43
+ buffer : [ MaybeUninit < T > ; N ] ,
39
44
}
40
45
41
46
impl < T , const N : usize > Vec < T , N > {
42
- const INIT : MaybeUninit < T > = MaybeUninit :: uninit ( ) ;
47
+ const ELEM : MaybeUninit < T > = MaybeUninit :: uninit ( ) ;
48
+ const INIT : [ MaybeUninit < T > ; N ] = [ Self :: ELEM ; N ] ; // important for optimization of `new`
43
49
44
50
/// Constructs a new, empty vector with a fixed capacity of `N`
45
51
///
@@ -60,8 +66,8 @@ impl<T, const N: usize> Vec<T, N> {
60
66
crate :: sealed:: greater_than_eq_0 :: < N > ( ) ;
61
67
62
68
Self {
63
- buffer : [ Self :: INIT ; N ] ,
64
69
len : 0 ,
70
+ buffer : Self :: INIT ,
65
71
}
66
72
}
67
73
@@ -92,7 +98,12 @@ impl<T, const N: usize> Vec<T, N> {
92
98
T : Clone ,
93
99
{
94
100
let mut new = Self :: new ( ) ;
95
- new. extend_from_slice ( self . as_slice ( ) ) . unwrap ( ) ;
101
+ // avoid `extend_from_slice` as that introduces a runtime check / panicking branch
102
+ for elem in self {
103
+ unsafe {
104
+ new. push_unchecked ( elem. clone ( ) ) ;
105
+ }
106
+ }
96
107
new
97
108
}
98
109
0 commit comments