@@ -25,6 +25,16 @@ enum AllocInit {
2525 Zeroed ,
2626}
2727
28+ #[ repr( transparent) ]
29+ #[ cfg_attr( target_pointer_width = "16" , rustc_layout_scalar_valid_range_end( 0x7fff ) ) ]
30+ #[ cfg_attr( target_pointer_width = "32" , rustc_layout_scalar_valid_range_end( 0x7fff_ffff ) ) ]
31+ #[ cfg_attr( target_pointer_width = "64" , rustc_layout_scalar_valid_range_end( 0x7fff_ffff_ffff_ffff ) ) ]
32+ struct Cap ( usize ) ;
33+
34+ impl Cap {
35+ const ZERO : Cap = unsafe { Cap ( 0 ) } ;
36+ }
37+
2838/// A low-level utility for more ergonomically allocating, reallocating, and deallocating
2939/// a buffer of memory on the heap without having to worry about all the corner cases
3040/// involved. This type is excellent for building your own data structures like Vec and VecDeque.
@@ -50,7 +60,7 @@ enum AllocInit {
5060#[ allow( missing_debug_implementations) ]
5161pub ( crate ) struct RawVec < T , A : Allocator = Global > {
5262 ptr : Unique < T > ,
53- cap : usize ,
63+ cap : Cap ,
5464 alloc : A ,
5565}
5666
@@ -119,7 +129,7 @@ impl<T, A: Allocator> RawVec<T, A> {
119129 /// the returned `RawVec`.
120130 pub const fn new_in ( alloc : A ) -> Self {
121131 // `cap: 0` means "unallocated". zero-sized types are ignored.
122- Self { ptr : Unique :: dangling ( ) , cap : 0 , alloc }
132+ Self { ptr : Unique :: dangling ( ) , cap : Cap :: ZERO , alloc }
123133 }
124134
125135 /// Like `with_capacity`, but parameterized over the choice of
@@ -194,7 +204,7 @@ impl<T, A: Allocator> RawVec<T, A> {
194204 // here should change to `ptr.len() / mem::size_of::<T>()`.
195205 Self {
196206 ptr : unsafe { Unique :: new_unchecked ( ptr. cast ( ) . as_ptr ( ) ) } ,
197- cap : capacity,
207+ cap : unsafe { Cap ( capacity) } ,
198208 alloc,
199209 }
200210 }
@@ -207,12 +217,13 @@ impl<T, A: Allocator> RawVec<T, A> {
207217 /// The `ptr` must be allocated (via the given allocator `alloc`), and with the given
208218 /// `capacity`.
209219 /// The `capacity` cannot exceed `isize::MAX` for sized types. (only a concern on 32-bit
210- /// systems). ZST vectors may have a capacity up to `usize::MAX` .
220+ /// systems). For ZSTs capacity is ignored .
211221 /// If the `ptr` and `capacity` come from a `RawVec` created via `alloc`, then this is
212222 /// guaranteed.
213223 #[ inline]
214224 pub unsafe fn from_raw_parts_in ( ptr : * mut T , capacity : usize , alloc : A ) -> Self {
215- Self { ptr : unsafe { Unique :: new_unchecked ( ptr) } , cap : capacity, alloc }
225+ let cap = if T :: IS_ZST { Cap :: ZERO } else { unsafe { Cap ( capacity) } } ;
226+ Self { ptr : unsafe { Unique :: new_unchecked ( ptr) } , cap, alloc }
216227 }
217228
218229 /// Gets a raw pointer to the start of the allocation. Note that this is
@@ -228,7 +239,7 @@ impl<T, A: Allocator> RawVec<T, A> {
228239 /// This will always be `usize::MAX` if `T` is zero-sized.
229240 #[ inline( always) ]
230241 pub fn capacity ( & self ) -> usize {
231- if T :: IS_ZST { usize:: MAX } else { self . cap }
242+ if T :: IS_ZST { usize:: MAX } else { self . cap . 0 }
232243 }
233244
234245 /// Returns a shared reference to the allocator backing this `RawVec`.
@@ -237,7 +248,7 @@ impl<T, A: Allocator> RawVec<T, A> {
237248 }
238249
239250 fn current_memory ( & self ) -> Option < ( NonNull < u8 > , Layout ) > {
240- if T :: IS_ZST || self . cap == 0 {
251+ if T :: IS_ZST || self . cap . 0 == 0 {
241252 None
242253 } else {
243254 // We could use Layout::array here which ensures the absence of isize and usize overflows
@@ -247,7 +258,7 @@ impl<T, A: Allocator> RawVec<T, A> {
247258 let _: ( ) = const { assert ! ( mem:: size_of:: <T >( ) % mem:: align_of:: <T >( ) == 0 ) } ;
248259 unsafe {
249260 let align = mem:: align_of :: < T > ( ) ;
250- let size = mem:: size_of :: < T > ( ) . unchecked_mul ( self . cap ) ;
261+ let size = mem:: size_of :: < T > ( ) . unchecked_mul ( self . cap . 0 ) ;
251262 let layout = Layout :: from_size_align_unchecked ( size, align) ;
252263 Some ( ( self . ptr . cast ( ) . into ( ) , layout) )
253264 }
@@ -375,12 +386,15 @@ impl<T, A: Allocator> RawVec<T, A> {
375386 additional > self . capacity ( ) . wrapping_sub ( len)
376387 }
377388
378- fn set_ptr_and_cap ( & mut self , ptr : NonNull < [ u8 ] > , cap : usize ) {
389+ /// # Safety:
390+ ///
391+ /// `cap` must not exceed `isize::MAX`.
392+ unsafe fn set_ptr_and_cap ( & mut self , ptr : NonNull < [ u8 ] > , cap : usize ) {
379393 // Allocators currently return a `NonNull<[u8]>` whose length matches
380394 // the size requested. If that ever changes, the capacity here should
381395 // change to `ptr.len() / mem::size_of::<T>()`.
382396 self . ptr = unsafe { Unique :: new_unchecked ( ptr. cast ( ) . as_ptr ( ) ) } ;
383- self . cap = cap;
397+ self . cap = unsafe { Cap ( cap) } ;
384398 }
385399
386400 // This method is usually instantiated many times. So we want it to be as
@@ -405,14 +419,15 @@ impl<T, A: Allocator> RawVec<T, A> {
405419
406420 // This guarantees exponential growth. The doubling cannot overflow
407421 // because `cap <= isize::MAX` and the type of `cap` is `usize`.
408- let cap = cmp:: max ( self . cap * 2 , required_cap) ;
422+ let cap = cmp:: max ( self . cap . 0 * 2 , required_cap) ;
409423 let cap = cmp:: max ( Self :: MIN_NON_ZERO_CAP , cap) ;
410424
411425 let new_layout = Layout :: array :: < T > ( cap) ;
412426
413427 // `finish_grow` is non-generic over `T`.
414428 let ptr = finish_grow ( new_layout, self . current_memory ( ) , & mut self . alloc ) ?;
415- self . set_ptr_and_cap ( ptr, cap) ;
429+ // SAFETY: finish_grow would have resulted in a capacity overflow if we tried to allocate more than isize::MAX items
430+ unsafe { self . set_ptr_and_cap ( ptr, cap) } ;
416431 Ok ( ( ) )
417432 }
418433
@@ -431,7 +446,10 @@ impl<T, A: Allocator> RawVec<T, A> {
431446
432447 // `finish_grow` is non-generic over `T`.
433448 let ptr = finish_grow ( new_layout, self . current_memory ( ) , & mut self . alloc ) ?;
434- self . set_ptr_and_cap ( ptr, cap) ;
449+ // SAFETY: finish_grow would have resulted in a capacity overflow if we tried to allocate more than isize::MAX items
450+ unsafe {
451+ self . set_ptr_and_cap ( ptr, cap) ;
452+ }
435453 Ok ( ( ) )
436454 }
437455
@@ -449,7 +467,7 @@ impl<T, A: Allocator> RawVec<T, A> {
449467 if cap == 0 {
450468 unsafe { self . alloc . deallocate ( ptr, layout) } ;
451469 self . ptr = Unique :: dangling ( ) ;
452- self . cap = 0 ;
470+ self . cap = Cap :: ZERO ;
453471 } else {
454472 let ptr = unsafe {
455473 // `Layout::array` cannot overflow here because it would have
@@ -460,7 +478,10 @@ impl<T, A: Allocator> RawVec<T, A> {
460478 . shrink ( ptr, layout, new_layout)
461479 . map_err ( |_| AllocError { layout : new_layout, non_exhaustive : ( ) } ) ?
462480 } ;
463- self . set_ptr_and_cap ( ptr, cap) ;
481+ // SAFETY: if the allocation is valid, then the capacity is too
482+ unsafe {
483+ self . set_ptr_and_cap ( ptr, cap) ;
484+ }
464485 }
465486 Ok ( ( ) )
466487 }
0 commit comments