@@ -83,59 +83,11 @@ struct MonoRawVec<A: Allocator = Global> {
83
83
}
84
84
85
85
#[ inline]
86
- const fn max_size_for_align ( align : usize ) -> usize {
87
- // (power-of-two implies align != 0.)
88
-
89
- // Rounded up size is:
90
- // size_rounded_up = (size + align - 1) & !(align - 1);
91
- //
92
- // We know from above that align != 0. If adding (align - 1)
93
- // does not overflow, then rounding up will be fine.
94
- //
95
- // Conversely, &-masking with !(align - 1) will subtract off
96
- // only low-order-bits. Thus if overflow occurs with the sum,
97
- // the &-mask cannot subtract enough to undo that overflow.
98
- //
99
- // Above implies that checking for summation overflow is both
100
- // necessary and sufficient.
101
- isize:: MAX as usize - ( align - 1 )
102
- }
103
-
104
- #[ inline]
105
- fn layout_array ( cap : usize , size : usize , align : usize ) -> Result < Layout , TryReserveError > {
106
- // We need to check two things about the size:
107
- // - That the total size won't overflow a `usize`, and
108
- // - That the total size still fits in an `isize`.
109
- // By using division we can check them both with a single threshold.
110
- // That'd usually be a bad idea, but thankfully here the element size
111
- // and alignment are constants, so the compiler will fold all of it.
112
- if size != 0 && cap > max_size_for_align ( align) / size {
113
- return Err ( CapacityOverflow . into ( ) ) ;
114
- }
115
-
116
- // SAFETY: We just checked that we won't overflow `usize` when we multiply.
117
- // This is a useless hint inside this function, but after inlining this helps
118
- // deduplicate checks for whether the overall capacity is zero (e.g., in RawVec's
119
- // allocation path) before/after this multiplication.
120
- let array_size = unsafe { size. unchecked_mul ( cap) } ;
121
-
122
- // SAFETY: We just checked above that the `array_size` will not
123
- // exceed `isize::MAX` even when rounded up to the alignment.
124
- // And `Alignment` guarantees it's a power of two.
125
- unsafe { Ok ( Layout :: from_size_align_unchecked ( array_size, align) ) }
86
+ fn layout_array ( cap : usize , elem_layout : Layout ) -> Result < Layout , TryReserveError > {
87
+ elem_layout. repeat ( cap) . map ( |( layout, _pad) | layout) . map_err ( |_| CapacityOverflow . into ( ) )
126
88
}
127
89
128
90
impl < A : Allocator > MonoRawVec < A > {
129
- #[ inline]
130
- fn ptr < T > ( & self ) -> * mut T {
131
- unsafe { core:: mem:: transmute ( self . ptr ) }
132
- }
133
-
134
- #[ inline]
135
- fn non_null < T > ( & self ) -> NonNull < T > {
136
- unsafe { core:: mem:: transmute ( self . ptr ) }
137
- }
138
-
139
91
/// # Safety:
140
92
///
141
93
/// `cap` must not exceed `isize::MAX`.
@@ -149,8 +101,8 @@ impl<A: Allocator> MonoRawVec<A> {
149
101
}
150
102
151
103
#[ inline]
152
- fn current_memory ( & self , size : usize , align : usize ) -> Option < ( NonNull < u8 > , Layout ) > {
153
- if size == 0 || self . cap . 0 == 0 {
104
+ fn current_memory ( & self , elem_layout : Layout ) -> Option < ( NonNull < u8 > , Layout ) > {
105
+ if elem_layout . size ( ) == 0 || self . cap . 0 == 0 {
154
106
return None ;
155
107
}
156
108
@@ -159,21 +111,19 @@ impl<A: Allocator> MonoRawVec<A> {
159
111
// has already been allocated so we know it can't overflow and currently Rust does not
160
112
// support such types. So we can do better by skipping some checks and avoid an unwrap.
161
113
unsafe {
162
- let size = size. unchecked_mul ( self . cap . 0 ) ;
163
- let layout = Layout :: from_size_align_unchecked ( size , align) ;
114
+ let alloc_size = elem_layout . size ( ) . unchecked_mul ( self . cap . 0 ) ;
115
+ let layout = Layout :: from_size_align_unchecked ( alloc_size , elem_layout . align ( ) ) ;
164
116
Some ( ( self . ptr . into ( ) , layout) )
165
117
}
166
118
}
167
119
168
- #[ inline]
169
120
fn grow_amortized (
170
121
& mut self ,
171
122
len : usize ,
172
123
additional : usize ,
173
- size : usize ,
174
- align : usize ,
124
+ elem_layout : Layout ,
175
125
) -> Result < ( ) , TryReserveError > {
176
- if size == 0 {
126
+ if elem_layout . size ( ) == 0 {
177
127
// Since we return a capacity of `usize::MAX` when `elem_size` is
178
128
// 0, getting to here necessarily means the `RawVec` is overfull.
179
129
return Err ( CapacityOverflow . into ( ) ) ;
@@ -185,36 +135,34 @@ impl<A: Allocator> MonoRawVec<A> {
185
135
// This guarantees exponential growth. The doubling cannot overflow
186
136
// because `cap <= isize::MAX` and the type of `cap` is `usize`.
187
137
let cap = cmp:: max ( self . cap . 0 * 2 , required_cap) ;
188
- let cap = cmp:: max ( min_non_zero_cap ( size) , cap) ;
138
+ let cap = cmp:: max ( min_non_zero_cap ( elem_layout . size ( ) ) , cap) ;
189
139
190
- let new_layout = layout_array ( cap, size , align ) ?;
140
+ let new_layout = layout_array ( cap, elem_layout ) ?;
191
141
192
142
// `finish_grow` is non-generic over `T`.
193
- let ptr = finish_grow ( new_layout, self . current_memory ( size , align ) , & mut self . alloc ) ?;
143
+ let ptr = finish_grow ( new_layout, self . current_memory ( elem_layout ) , & mut self . alloc ) ?;
194
144
// SAFETY: finish_grow would have resulted in a capacity overflow if we tried to allocate more than isize::MAX items
195
145
unsafe { self . set_ptr_and_cap ( ptr, cap) } ;
196
146
Ok ( ( ) )
197
147
}
198
148
199
- #[ inline]
200
149
fn grow_exact (
201
150
& mut self ,
202
151
len : usize ,
203
152
additional : usize ,
204
- size : usize ,
205
- align : usize ,
153
+ elem_layout : Layout ,
206
154
) -> Result < ( ) , TryReserveError > {
207
- if size == 0 {
155
+ if elem_layout . size ( ) == 0 {
208
156
// Since we return a capacity of `usize::MAX` when the type size is
209
157
// 0, getting to here necessarily means the `RawVec` is overfull.
210
158
return Err ( CapacityOverflow . into ( ) ) ;
211
159
}
212
160
213
161
let cap = len. checked_add ( additional) . ok_or ( CapacityOverflow ) ?;
214
- let new_layout = layout_array ( cap, size , align ) ?;
162
+ let new_layout = layout_array ( cap, elem_layout ) ?;
215
163
216
164
// `finish_grow` is non-generic over `T`.
217
- let ptr = finish_grow ( new_layout, self . current_memory ( size , align ) , & mut self . alloc ) ?;
165
+ let ptr = finish_grow ( new_layout, self . current_memory ( elem_layout ) , & mut self . alloc ) ?;
218
166
// SAFETY: finish_grow would have resulted in a capacity overflow if we tried to allocate more than isize::MAX items
219
167
unsafe {
220
168
self . set_ptr_and_cap ( ptr, cap) ;
@@ -223,27 +171,27 @@ impl<A: Allocator> MonoRawVec<A> {
223
171
}
224
172
225
173
#[ cfg( not( no_global_oom_handling) ) ]
226
- #[ inline]
227
- fn shrink ( & mut self , cap : usize , size : usize , align : usize ) -> Result < ( ) , TryReserveError > {
228
- if size > 0 {
174
+ fn shrink ( & mut self , cap : usize , elem_layout : Layout ) -> Result < ( ) , TryReserveError > {
175
+ if elem_layout. size ( ) > 0 {
229
176
assert ! ( cap <= self . cap. 0 , "Tried to shrink to a larger capacity" ) ;
230
177
}
231
178
232
179
let ( ptr, layout) =
233
- if let Some ( mem) = self . current_memory ( size , align ) { mem } else { return Ok ( ( ) ) } ;
180
+ if let Some ( mem) = self . current_memory ( elem_layout ) { mem } else { return Ok ( ( ) ) } ;
234
181
235
182
// If shrinking to 0, deallocate the buffer. We don't reach this point
236
183
// for the T::IS_ZST case since current_memory() will have returned
237
184
// None.
238
185
if cap == 0 {
239
186
unsafe { self . alloc . deallocate ( ptr, layout) } ;
240
- self . ptr = unsafe { Unique :: new_unchecked ( ptr:: without_provenance_mut ( align) ) } ;
187
+ self . ptr =
188
+ unsafe { Unique :: new_unchecked ( ptr:: without_provenance_mut ( elem_layout. align ( ) ) ) } ;
241
189
self . cap = Cap :: ZERO ;
242
190
} else {
243
191
let ptr = unsafe {
244
192
// `Layout::array` cannot overflow here because it would have
245
193
// overflowed earlier when capacity was larger.
246
- let new_size = size. unchecked_mul ( cap) ;
194
+ let new_size = elem_layout . size ( ) . unchecked_mul ( cap) ;
247
195
let new_layout = Layout :: from_size_align_unchecked ( new_size, layout. align ( ) ) ;
248
196
self . alloc
249
197
. shrink ( ptr, layout, new_layout)
@@ -264,21 +212,19 @@ impl<A: Allocator> MonoRawVec<A> {
264
212
Self { ptr, cap : Cap :: ZERO , alloc }
265
213
}
266
214
267
- #[ inline]
268
215
fn try_allocate_in (
269
216
capacity : usize ,
270
217
init : AllocInit ,
271
218
alloc : A ,
272
- size : usize ,
273
- align : usize ,
219
+ elem_layout : Layout ,
274
220
) -> Result < Self , TryReserveError > {
275
221
// Don't allocate here because `Drop` will not deallocate when `capacity` is 0.
276
- if size == 0 || capacity == 0 {
277
- Ok ( Self :: new_in ( alloc, align) )
222
+ if elem_layout . size ( ) == 0 || capacity == 0 {
223
+ Ok ( Self :: new_in ( alloc, elem_layout . align ( ) ) )
278
224
} else {
279
225
// We avoid `unwrap_or_else` here because it bloats the amount of
280
226
// LLVM IR generated.
281
- let layout = match layout_array ( capacity, size , align ) {
227
+ let layout = match layout_array ( capacity, elem_layout ) {
282
228
Ok ( layout) => layout,
283
229
Err ( _) => return Err ( CapacityOverflow . into ( ) ) ,
284
230
} ;
@@ -304,10 +250,8 @@ impl<A: Allocator> MonoRawVec<A> {
304
250
}
305
251
}
306
252
307
- #[ inline]
308
- #[ rustc_no_mir_inline]
309
- fn drop_if_needed ( & mut self , size : usize , align : usize ) {
310
- if let Some ( ( ptr, layout) ) = self . current_memory ( size, align) {
253
+ fn drop_if_needed ( & mut self , elem_layout : Layout ) {
254
+ if let Some ( ( ptr, layout) ) = self . current_memory ( elem_layout) {
311
255
unsafe { self . alloc . deallocate ( ptr, layout) }
312
256
}
313
257
}
@@ -449,13 +393,7 @@ impl<T, A: Allocator> RawVec<T, A> {
449
393
init : AllocInit ,
450
394
alloc : A ,
451
395
) -> Result < Self , TryReserveError > {
452
- match MonoRawVec :: try_allocate_in (
453
- capacity,
454
- init,
455
- alloc,
456
- mem:: size_of :: < T > ( ) ,
457
- mem:: align_of :: < T > ( ) ,
458
- ) {
396
+ match MonoRawVec :: try_allocate_in ( capacity, init, alloc, T :: LAYOUT ) {
459
397
Ok ( inner) => Ok ( Self { inner, _phantom : PhantomData } ) ,
460
398
Err ( e) => Err ( e) ,
461
399
}
@@ -499,23 +437,24 @@ impl<T, A: Allocator> RawVec<T, A> {
499
437
/// be careful.
500
438
#[ inline]
501
439
pub fn ptr ( & self ) -> * mut T {
502
- self . inner . ptr ( )
440
+ unsafe { core :: mem :: transmute ( self . inner . ptr ) }
503
441
}
504
442
505
443
#[ inline]
506
444
pub fn non_null ( & self ) -> NonNull < T > {
507
- self . inner . non_null ( )
445
+ unsafe { core :: mem :: transmute ( self . inner . ptr ) }
508
446
}
509
447
510
448
/// Gets the capacity of the allocation.
511
449
///
512
450
/// This will always be `usize::MAX` if `T` is zero-sized.
513
- #[ inline( always ) ]
451
+ #[ inline]
514
452
pub fn capacity ( & self ) -> usize {
515
453
if T :: IS_ZST { usize:: MAX } else { self . inner . cap . 0 }
516
454
}
517
455
518
456
/// Returns a shared reference to the allocator backing this `RawVec`.
457
+ #[ inline]
519
458
pub fn allocator ( & self ) -> & A {
520
459
& self . inner . alloc
521
460
}
@@ -645,6 +584,7 @@ impl<T, A: Allocator> RawVec<T, A> {
645
584
impl < T , A : Allocator > RawVec < T , A > {
646
585
/// Returns if the buffer needs to grow to fulfill the needed extra capacity.
647
586
/// Mainly used to make inlining reserve-calls possible without inlining `grow`.
587
+ #[ inline]
648
588
fn needs_to_grow ( & self , len : usize , additional : usize ) -> bool {
649
589
additional > self . capacity ( ) . wrapping_sub ( len)
650
590
}
@@ -656,27 +596,25 @@ impl<T, A: Allocator> RawVec<T, A> {
656
596
// so that all of the code that depends on `T` is within it, while as much
657
597
// of the code that doesn't depend on `T` as possible is in functions that
658
598
// are non-generic over `T`.
599
+ #[ inline]
659
600
fn grow_amortized ( & mut self , len : usize , additional : usize ) -> Result < ( ) , TryReserveError > {
660
- const { assert ! ( mem:: size_of:: <T >( ) % mem:: align_of:: <T >( ) == 0 ) } ;
661
-
662
601
// This is ensured by the calling contexts.
663
602
debug_assert ! ( additional > 0 ) ;
664
603
665
- self . inner . grow_amortized ( len, additional, mem :: size_of :: < T > ( ) , mem :: align_of :: < T > ( ) )
604
+ self . inner . grow_amortized ( len, additional, T :: LAYOUT )
666
605
}
667
606
668
607
// The constraints on this method are much the same as those on
669
608
// `grow_amortized`, but this method is usually instantiated less often so
670
609
// it's less critical.
610
+ #[ inline]
671
611
fn grow_exact ( & mut self , len : usize , additional : usize ) -> Result < ( ) , TryReserveError > {
672
- const { assert ! ( mem:: size_of:: <T >( ) % mem:: align_of:: <T >( ) == 0 ) } ;
673
- self . inner . grow_exact ( len, additional, mem:: size_of :: < T > ( ) , mem:: align_of :: < T > ( ) )
612
+ self . inner . grow_exact ( len, additional, T :: LAYOUT )
674
613
}
675
614
676
615
#[ cfg( not( no_global_oom_handling) ) ]
677
616
fn shrink ( & mut self , cap : usize ) -> Result < ( ) , TryReserveError > {
678
- const { assert ! ( mem:: size_of:: <T >( ) % mem:: align_of:: <T >( ) == 0 ) } ;
679
- self . inner . shrink ( cap, mem:: size_of :: < T > ( ) , mem:: align_of :: < T > ( ) )
617
+ self . inner . shrink ( cap, T :: LAYOUT )
680
618
}
681
619
}
682
620
@@ -712,8 +650,7 @@ where
712
650
unsafe impl < #[ may_dangle] T , A : Allocator > Drop for RawVec < T , A > {
713
651
/// Frees the memory owned by the `RawVec` *without* trying to drop its contents.
714
652
fn drop ( & mut self ) {
715
- const { assert ! ( mem:: size_of:: <T >( ) % mem:: align_of:: <T >( ) == 0 ) } ;
716
- self . inner . drop_if_needed ( mem:: size_of :: < T > ( ) , mem:: align_of :: < T > ( ) ) ;
653
+ self . inner . drop_if_needed ( T :: LAYOUT ) ;
717
654
}
718
655
}
719
656
0 commit comments