@@ -25,6 +25,16 @@ enum AllocInit {
25
25
Zeroed ,
26
26
}
27
27
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
+
28
38
/// A low-level utility for more ergonomically allocating, reallocating, and deallocating
29
39
/// a buffer of memory on the heap without having to worry about all the corner cases
30
40
/// involved. This type is excellent for building your own data structures like Vec and VecDeque.
@@ -50,7 +60,7 @@ enum AllocInit {
50
60
#[ allow( missing_debug_implementations) ]
51
61
pub ( crate ) struct RawVec < T , A : Allocator = Global > {
52
62
ptr : Unique < T > ,
53
- cap : usize ,
63
+ cap : Cap ,
54
64
alloc : A ,
55
65
}
56
66
@@ -119,7 +129,7 @@ impl<T, A: Allocator> RawVec<T, A> {
119
129
/// the returned `RawVec`.
120
130
pub const fn new_in ( alloc : A ) -> Self {
121
131
// `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 }
123
133
}
124
134
125
135
/// Like `with_capacity`, but parameterized over the choice of
@@ -194,7 +204,7 @@ impl<T, A: Allocator> RawVec<T, A> {
194
204
// here should change to `ptr.len() / mem::size_of::<T>()`.
195
205
Self {
196
206
ptr : unsafe { Unique :: new_unchecked ( ptr. cast ( ) . as_ptr ( ) ) } ,
197
- cap : capacity,
207
+ cap : unsafe { Cap ( capacity) } ,
198
208
alloc,
199
209
}
200
210
}
@@ -207,12 +217,13 @@ impl<T, A: Allocator> RawVec<T, A> {
207
217
/// The `ptr` must be allocated (via the given allocator `alloc`), and with the given
208
218
/// `capacity`.
209
219
/// 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 .
211
221
/// If the `ptr` and `capacity` come from a `RawVec` created via `alloc`, then this is
212
222
/// guaranteed.
213
223
#[ inline]
214
224
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 }
216
227
}
217
228
218
229
/// 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> {
228
239
/// This will always be `usize::MAX` if `T` is zero-sized.
229
240
#[ inline( always) ]
230
241
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 }
232
243
}
233
244
234
245
/// Returns a shared reference to the allocator backing this `RawVec`.
@@ -237,7 +248,7 @@ impl<T, A: Allocator> RawVec<T, A> {
237
248
}
238
249
239
250
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 {
241
252
None
242
253
} else {
243
254
// 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> {
247
258
let _: ( ) = const { assert ! ( mem:: size_of:: <T >( ) % mem:: align_of:: <T >( ) == 0 ) } ;
248
259
unsafe {
249
260
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 ) ;
251
262
let layout = Layout :: from_size_align_unchecked ( size, align) ;
252
263
Some ( ( self . ptr . cast ( ) . into ( ) , layout) )
253
264
}
@@ -375,12 +386,15 @@ impl<T, A: Allocator> RawVec<T, A> {
375
386
additional > self . capacity ( ) . wrapping_sub ( len)
376
387
}
377
388
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 ) {
379
393
// Allocators currently return a `NonNull<[u8]>` whose length matches
380
394
// the size requested. If that ever changes, the capacity here should
381
395
// change to `ptr.len() / mem::size_of::<T>()`.
382
396
self . ptr = unsafe { Unique :: new_unchecked ( ptr. cast ( ) . as_ptr ( ) ) } ;
383
- self . cap = cap;
397
+ self . cap = unsafe { Cap ( cap) } ;
384
398
}
385
399
386
400
// 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> {
405
419
406
420
// This guarantees exponential growth. The doubling cannot overflow
407
421
// 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) ;
409
423
let cap = cmp:: max ( Self :: MIN_NON_ZERO_CAP , cap) ;
410
424
411
425
let new_layout = Layout :: array :: < T > ( cap) ;
412
426
413
427
// `finish_grow` is non-generic over `T`.
414
428
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) } ;
416
431
Ok ( ( ) )
417
432
}
418
433
@@ -431,7 +446,10 @@ impl<T, A: Allocator> RawVec<T, A> {
431
446
432
447
// `finish_grow` is non-generic over `T`.
433
448
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
+ }
435
453
Ok ( ( ) )
436
454
}
437
455
@@ -449,7 +467,7 @@ impl<T, A: Allocator> RawVec<T, A> {
449
467
if cap == 0 {
450
468
unsafe { self . alloc . deallocate ( ptr, layout) } ;
451
469
self . ptr = Unique :: dangling ( ) ;
452
- self . cap = 0 ;
470
+ self . cap = Cap :: ZERO ;
453
471
} else {
454
472
let ptr = unsafe {
455
473
// `Layout::array` cannot overflow here because it would have
@@ -460,7 +478,10 @@ impl<T, A: Allocator> RawVec<T, A> {
460
478
. shrink ( ptr, layout, new_layout)
461
479
. map_err ( |_| AllocError { layout : new_layout, non_exhaustive : ( ) } ) ?
462
480
} ;
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
+ }
464
485
}
465
486
Ok ( ( ) )
466
487
}
0 commit comments