@@ -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,12 @@ 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
+ /// Never used for ZSTs; it's `capacity()`'s responsibility to return usize::MAX in that case.
64
+ ///
65
+ /// # Safety
66
+ ///
67
+ /// `cap` must be in the `0..=isize::MAX` range.
68
+ cap : Cap ,
54
69
alloc : A ,
55
70
}
56
71
@@ -119,7 +134,7 @@ impl<T, A: Allocator> RawVec<T, A> {
119
134
/// the returned `RawVec`.
120
135
pub const fn new_in ( alloc : A ) -> Self {
121
136
// `cap: 0` means "unallocated". zero-sized types are ignored.
122
- Self { ptr : Unique :: dangling ( ) , cap : 0 , alloc }
137
+ Self { ptr : Unique :: dangling ( ) , cap : Cap :: ZERO , alloc }
123
138
}
124
139
125
140
/// Like `with_capacity`, but parameterized over the choice of
@@ -194,7 +209,7 @@ impl<T, A: Allocator> RawVec<T, A> {
194
209
// here should change to `ptr.len() / mem::size_of::<T>()`.
195
210
Self {
196
211
ptr : unsafe { Unique :: new_unchecked ( ptr. cast ( ) . as_ptr ( ) ) } ,
197
- cap : capacity,
212
+ cap : unsafe { Cap ( capacity) } ,
198
213
alloc,
199
214
}
200
215
}
@@ -207,12 +222,13 @@ impl<T, A: Allocator> RawVec<T, A> {
207
222
/// The `ptr` must be allocated (via the given allocator `alloc`), and with the given
208
223
/// `capacity`.
209
224
/// 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` .
225
+ /// systems). For ZSTs capacity is ignored .
211
226
/// If the `ptr` and `capacity` come from a `RawVec` created via `alloc`, then this is
212
227
/// guaranteed.
213
228
#[ inline]
214
229
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 }
230
+ let cap = if T :: IS_ZST { Cap :: ZERO } else { unsafe { Cap ( capacity) } } ;
231
+ Self { ptr : unsafe { Unique :: new_unchecked ( ptr) } , cap, alloc }
216
232
}
217
233
218
234
/// Gets a raw pointer to the start of the allocation. Note that this is
@@ -228,7 +244,7 @@ impl<T, A: Allocator> RawVec<T, A> {
228
244
/// This will always be `usize::MAX` if `T` is zero-sized.
229
245
#[ inline( always) ]
230
246
pub fn capacity ( & self ) -> usize {
231
- if T :: IS_ZST { usize:: MAX } else { self . cap }
247
+ if T :: IS_ZST { usize:: MAX } else { self . cap . 0 }
232
248
}
233
249
234
250
/// Returns a shared reference to the allocator backing this `RawVec`.
@@ -237,7 +253,7 @@ impl<T, A: Allocator> RawVec<T, A> {
237
253
}
238
254
239
255
fn current_memory ( & self ) -> Option < ( NonNull < u8 > , Layout ) > {
240
- if T :: IS_ZST || self . cap == 0 {
256
+ if T :: IS_ZST || self . cap . 0 == 0 {
241
257
None
242
258
} else {
243
259
// We could use Layout::array here which ensures the absence of isize and usize overflows
@@ -247,7 +263,7 @@ impl<T, A: Allocator> RawVec<T, A> {
247
263
let _: ( ) = const { assert ! ( mem:: size_of:: <T >( ) % mem:: align_of:: <T >( ) == 0 ) } ;
248
264
unsafe {
249
265
let align = mem:: align_of :: < T > ( ) ;
250
- let size = mem:: size_of :: < T > ( ) . unchecked_mul ( self . cap ) ;
266
+ let size = mem:: size_of :: < T > ( ) . unchecked_mul ( self . cap . 0 ) ;
251
267
let layout = Layout :: from_size_align_unchecked ( size, align) ;
252
268
Some ( ( self . ptr . cast ( ) . into ( ) , layout) )
253
269
}
@@ -375,12 +391,15 @@ impl<T, A: Allocator> RawVec<T, A> {
375
391
additional > self . capacity ( ) . wrapping_sub ( len)
376
392
}
377
393
378
- fn set_ptr_and_cap ( & mut self , ptr : NonNull < [ u8 ] > , cap : usize ) {
394
+ /// # Safety:
395
+ ///
396
+ /// `cap` must not exceed `isize::MAX`.
397
+ unsafe fn set_ptr_and_cap ( & mut self , ptr : NonNull < [ u8 ] > , cap : usize ) {
379
398
// Allocators currently return a `NonNull<[u8]>` whose length matches
380
399
// the size requested. If that ever changes, the capacity here should
381
400
// change to `ptr.len() / mem::size_of::<T>()`.
382
401
self . ptr = unsafe { Unique :: new_unchecked ( ptr. cast ( ) . as_ptr ( ) ) } ;
383
- self . cap = cap;
402
+ self . cap = unsafe { Cap ( cap) } ;
384
403
}
385
404
386
405
// This method is usually instantiated many times. So we want it to be as
@@ -405,14 +424,15 @@ impl<T, A: Allocator> RawVec<T, A> {
405
424
406
425
// This guarantees exponential growth. The doubling cannot overflow
407
426
// because `cap <= isize::MAX` and the type of `cap` is `usize`.
408
- let cap = cmp:: max ( self . cap * 2 , required_cap) ;
427
+ let cap = cmp:: max ( self . cap . 0 * 2 , required_cap) ;
409
428
let cap = cmp:: max ( Self :: MIN_NON_ZERO_CAP , cap) ;
410
429
411
430
let new_layout = Layout :: array :: < T > ( cap) ;
412
431
413
432
// `finish_grow` is non-generic over `T`.
414
433
let ptr = finish_grow ( new_layout, self . current_memory ( ) , & mut self . alloc ) ?;
415
- self . set_ptr_and_cap ( ptr, cap) ;
434
+ // SAFETY: finish_grow would have resulted in a capacity overflow if we tried to allocate more than isize::MAX items
435
+ unsafe { self . set_ptr_and_cap ( ptr, cap) } ;
416
436
Ok ( ( ) )
417
437
}
418
438
@@ -431,7 +451,10 @@ impl<T, A: Allocator> RawVec<T, A> {
431
451
432
452
// `finish_grow` is non-generic over `T`.
433
453
let ptr = finish_grow ( new_layout, self . current_memory ( ) , & mut self . alloc ) ?;
434
- self . set_ptr_and_cap ( ptr, cap) ;
454
+ // SAFETY: finish_grow would have resulted in a capacity overflow if we tried to allocate more than isize::MAX items
455
+ unsafe {
456
+ self . set_ptr_and_cap ( ptr, cap) ;
457
+ }
435
458
Ok ( ( ) )
436
459
}
437
460
@@ -449,7 +472,7 @@ impl<T, A: Allocator> RawVec<T, A> {
449
472
if cap == 0 {
450
473
unsafe { self . alloc . deallocate ( ptr, layout) } ;
451
474
self . ptr = Unique :: dangling ( ) ;
452
- self . cap = 0 ;
475
+ self . cap = Cap :: ZERO ;
453
476
} else {
454
477
let ptr = unsafe {
455
478
// `Layout::array` cannot overflow here because it would have
@@ -460,7 +483,10 @@ impl<T, A: Allocator> RawVec<T, A> {
460
483
. shrink ( ptr, layout, new_layout)
461
484
. map_err ( |_| AllocError { layout : new_layout, non_exhaustive : ( ) } ) ?
462
485
} ;
463
- self . set_ptr_and_cap ( ptr, cap) ;
486
+ // SAFETY: if the allocation is valid, then the capacity is too
487
+ unsafe {
488
+ self . set_ptr_and_cap ( ptr, cap) ;
489
+ }
464
490
}
465
491
Ok ( ( ) )
466
492
}
0 commit comments