@@ -165,6 +165,32 @@ const fn min_non_zero_cap(size: usize) -> usize {
165165 }
166166}
167167
168+ const impl<T , A : [ const ] Allocator + [ const ] Destruct > RawVec < T , A > {
169+ /// Like `with_capacity`, but parameterized over the choice of
170+ /// allocator for the returned `RawVec`.
171+ #[ cfg ( not ( no_global_oom_handling ) ) ]
172+ #[ inline ]
173+ #[ rustc_const_unstable ( feature = "const_heap" , issue = "79597" ) ]
174+ pub( crate ) fn with_capacity_in ( capacity : usize , alloc : A ) -> Self
175+ {
176+ Self {
177+ inner : RawVecInner :: with_capacity_in( capacity, alloc, T :: LAYOUT ) ,
178+ _marker : PhantomData ,
179+ }
180+ }
181+
182+ /// A specialized version of `self.reserve(len, 1)` which requires the
183+ /// caller to ensure `len == self.capacity()`.
184+ #[ cfg( not( no_global_oom_handling) ) ]
185+ #[ inline( never) ]
186+ #[ rustc_const_unstable( feature = "const_heap" , issue = "79597" ) ]
187+ pub( crate ) fn grow_one ( & mut self )
188+ {
189+ // SAFETY: All calls on self.inner pass T::LAYOUT as the elem_layout
190+ unsafe { self . inner. grow_one ( T :: LAYOUT ) }
191+ }
192+ }
193+
168194impl <T , A : Allocator > RawVec < T , A > {
169195 #[ cfg( not( no_global_oom_handling) ) ]
170196 pub( crate ) const MIN_NON_ZERO_CAP : usize = min_non_zero_cap( size_of :: < T > ( ) ) ;
@@ -178,21 +204,6 @@ impl<T, A: Allocator> RawVec<T, A> {
178204 Self { inner : RawVecInner :: new_in( alloc, Alignment :: of:: < T > ( ) ) , _marker : PhantomData }
179205 }
180206
181- /// Like `with_capacity`, but parameterized over the choice of
182- /// allocator for the returned `RawVec`.
183- #[ cfg( not( no_global_oom_handling) ) ]
184- #[ inline]
185- #[ rustc_const_unstable( feature = "const_heap" , issue = "79597" ) ]
186- pub ( crate ) const fn with_capacity_in( capacity : usize , alloc : A ) -> Self
187- where
188- A : [ const ] Allocator + [ const ] Destruct ,
189- {
190- Self {
191- inner : RawVecInner :: with_capacity_in ( capacity , alloc , T :: LAYOUT ) ,
192- _marker : PhantomData ,
193- }
194- }
195-
196207 /// Like `try_with_capacity`, but parameterized over the choice of
197208 /// allocator for the returned `RawVec`.
198209 #[ inline]
@@ -331,19 +342,6 @@ impl<T, A: Allocator> RawVec<T, A> {
331342 unsafe { self . inner. reserve( len, additional, T :: LAYOUT ) }
332343 }
333344
334- /// A specialized version of `self.reserve(len, 1)` which requires the
335- /// caller to ensure `len == self.capacity()`.
336- #[ cfg( not( no_global_oom_handling) ) ]
337- #[ inline( never) ]
338- #[ rustc_const_unstable( feature = "const_heap" , issue = "79597" ) ]
339- pub( crate ) const fn grow_one ( & mut self )
340- where
341- A : [ const ] Allocator ,
342- {
343- // SAFETY: All calls on self.inner pass T::LAYOUT as the elem_layout
344- unsafe { self . inner. grow_one ( T :: LAYOUT ) }
345- }
346-
347345 /// The same as `reserve`, but returns on errors instead of panicking or aborting.
348346 pub ( crate ) fn try_reserve (
349347 & mut self ,
@@ -413,20 +411,11 @@ unsafe impl<#[may_dangle] T, A: Allocator> Drop for RawVec<T, A> {
413411 }
414412}
415413
416- impl <A : Allocator > RawVecInner < A > {
417- #[ inline ]
418- const fn new_in ( alloc : A , align : Alignment ) -> Self {
419- let ptr = Unique :: from_non_null ( NonNull :: without_provenance ( align. as_nonzero ( ) ) ) ;
420- // `cap: 0` means "unallocated". zero-sized types are ignored.
421- Self { ptr, cap : ZERO_CAP , alloc }
422- }
423-
414+ const impl <A : [ const ] Allocator + [ const ] Destruct > RawVecInner < A > {
424415 #[ cfg ( not ( no_global_oom_handling ) ) ]
425416 #[ inline ]
426417 #[ rustc_const_unstable ( feature = "const_heap" , issue = "79597" ) ]
427- const fn with_capacity_in( capacity : usize , alloc : A , elem_layout : Layout ) -> Self
428- where
429- A : [ const ] Allocator + [ const ] Destruct ,
418+ fn with_capacity_in ( capacity : usize , alloc : A , elem_layout : Layout ) -> Self
430419 {
431420 match Self :: try_allocate_in ( capacity , AllocInit :: Uninitialized , alloc , elem_layout ) {
432421 Ok ( this ) => {
@@ -439,34 +428,13 @@ impl<A: Allocator> RawVecInner<A> {
439428 Err ( err) => handle_error ( err) ,
440429 }
441430 }
442-
443- #[ inline]
444- fn try_with_capacity_in (
445- capacity: usize ,
446- alloc: A ,
447- elem_layout: Layout ,
448- ) -> Result <Self , TryReserveError > {
449- Self :: try_allocate_in ( capacity, AllocInit :: Uninitialized , alloc, elem_layout)
450- }
451-
452- #[ cfg ( not ( no_global_oom_handling) ) ]
453- #[ inline]
454- fn with_capacity_zeroed_in( capacity: usize , alloc: A , elem_layout: Layout ) -> Self {
455- match Self :: try_allocate_in ( capacity, AllocInit :: Zeroed , alloc, elem_layout) {
456- Ok ( res) => res,
457- Err ( err) => handle_error ( err) ,
458- }
459- }
460-
461431 #[ rustc_const_unstable ( feature = "const_heap" , issue = "79597" ) ]
462- const fn try_allocate_in(
432+ fn try_allocate_in (
463433 capacity: usize ,
464434 init: AllocInit ,
465435 alloc: A ,
466436 elem_layout: Layout ,
467437 ) -> Result <Self , TryReserveError >
468- where
469- A : [ const ] Allocator + [ const ] Destruct ,
470438 {
471439 // We avoid `unwrap_or_else` here because it bloats the amount of
472440 // LLVM IR generated.
@@ -500,6 +468,125 @@ impl<A: Allocator> RawVecInner<A> {
500468 } )
501469 }
502470
471+ /// # Safety
472+ /// - `elem_layout` must be valid for `self`, i.e. it must be the same `elem_layout` used to
473+ /// initially construct `self`
474+ /// - `elem_layout`'s size must be a multiple of its alignment
475+ #[ cfg ( not ( no_global_oom_handling) ) ]
476+ #[ inline]
477+ #[ rustc_const_unstable ( feature = "const_heap" , issue = "79597" ) ]
478+ unsafe fn grow_one( & mut self , elem_layout: Layout )
479+ {
480+ // SAFETY: Precondition passed to caller
481+ if let Err ( err) = unsafe { self . grow_amortized ( self . cap . as_inner ( ) , 1 , elem_layout) } {
482+ handle_error ( err) ;
483+ }
484+ }
485+
486+
487+ /// # Safety
488+ /// - `elem_layout` must be valid for `self`, i.e. it must be the same `elem_layout` used to
489+ /// initially construct `self`
490+ /// - `elem_layout`'s size must be a multiple of its alignment
491+ /// - The sum of `len` and `additional` must be greater than the current capacity
492+ #[ rustc_const_unstable ( feature = "const_heap" , issue = "79597" ) ]
493+ unsafe fn grow_amortized(
494+ & mut self ,
495+ len: usize,
496+ additional: usize ,
497+ elem_layout: Layout ,
498+ ) -> Result <( ) , TryReserveError >
499+ {
500+ // This is ensured by the calling contexts.
501+ debug_assert ! ( additional > 0 ) ;
502+
503+ if elem_layout. size ( ) == 0 {
504+ // Since we return a capacity of `usize::MAX` when `elem_size` is
505+ // 0, getting to here necessarily means the `RawVec` is overfull.
506+ return Err ( CapacityOverflow . into ( ) ) ;
507+ }
508+
509+ // Nothing we can really do about these checks, sadly.
510+ let required_cap = len. checked_add ( additional) . ok_or ( CapacityOverflow ) ?;
511+
512+ // This guarantees exponential growth. The doubling cannot overflow
513+ // because `cap <= isize::MAX` and the type of `cap` is `usize`.
514+ let cap = cmp:: max ( self . cap . as_inner ( ) * 2 , required_cap) ;
515+ let cap = cmp:: max ( min_non_zero_cap ( elem_layout. size ( ) ) , cap) ;
516+
517+ // SAFETY:
518+ // - cap >= len + additional
519+ // - other preconditions passed to caller
520+ let ptr = unsafe { self . finish_grow ( cap, elem_layout) ? } ;
521+
522+ // SAFETY: `finish_grow` would have failed if `cap > isize::MAX`
523+ unsafe { self . set_ptr_and_cap ( ptr, cap) } ;
524+ Ok ( ( ) )
525+ }
526+
527+ /// # Safety
528+ /// - `elem_layout` must be valid for `self`, i.e. it must be the same `elem_layout` used to
529+ /// initially construct `self`
530+ /// - `elem_layout`'s size must be a multiple of its alignment
531+ /// - `cap` must be greater than the current capacity
532+ // not marked inline(never) since we want optimizers to be able to observe the specifics of this
533+ // function, see tests/codegen-llvm/vec-reserve-extend.rs.
534+ #[ cold]
535+ #[ rustc_const_unstable( feature = "const_heap" , issue = "79597" ) ]
536+ unsafe fn finish_grow (
537+ & self ,
538+ cap : usize ,
539+ elem_layout : Layout ,
540+ ) -> Result < NonNull < [ u8 ] > , TryReserveError >
541+ {
542+ let new_layout = layout_array ( cap, elem_layout) ?;
543+
544+ let memory = if let Some ( ( ptr, old_layout) ) = unsafe { self . current_memory ( elem_layout) } {
545+ // FIXME(const-hack): switch to `debug_assert_eq`
546+ debug_assert ! ( old_layout. align( ) == new_layout. align( ) ) ;
547+ unsafe {
548+ // The allocator checks for alignment equality
549+ hint:: assert_unchecked ( old_layout. align ( ) == new_layout. align ( ) ) ;
550+ self . alloc . grow ( ptr, old_layout, new_layout)
551+ }
552+ } else {
553+ self . alloc . allocate ( new_layout)
554+ } ;
555+
556+ // FIXME(const-hack): switch back to `map_err`
557+ match memory {
558+ Ok ( memory) => Ok ( memory) ,
559+ Err ( _) => Err ( AllocError { layout : new_layout, non_exhaustive : ( ) } . into ( ) ) ,
560+ }
561+ }
562+ }
563+
564+ impl < A : Allocator > RawVecInner < A > {
565+ #[ inline]
566+ const fn new_in ( alloc : A , align : Alignment ) -> Self {
567+ let ptr = Unique :: from_non_null ( NonNull :: without_provenance ( align. as_nonzero ( ) ) ) ;
568+ // `cap: 0` means "unallocated". zero-sized types are ignored.
569+ Self { ptr, cap : ZERO_CAP , alloc }
570+ }
571+
572+ #[ inline]
573+ fn try_with_capacity_in (
574+ capacity : usize ,
575+ alloc : A ,
576+ elem_layout : Layout ,
577+ ) -> Result < Self , TryReserveError > {
578+ Self :: try_allocate_in ( capacity, AllocInit :: Uninitialized , alloc, elem_layout)
579+ }
580+
581+ #[ cfg( not( no_global_oom_handling) ) ]
582+ #[ inline]
583+ fn with_capacity_zeroed_in ( capacity : usize , alloc : A , elem_layout : Layout ) -> Self {
584+ match Self :: try_allocate_in ( capacity, AllocInit :: Zeroed , alloc, elem_layout) {
585+ Ok ( res) => res,
586+ Err ( err) => handle_error ( err) ,
587+ }
588+ }
589+
503590 #[ inline]
504591 unsafe fn from_raw_parts_in ( ptr : * mut u8 , cap : Cap , alloc : A ) -> Self {
505592 Self { ptr : unsafe { Unique :: new_unchecked ( ptr) } , cap, alloc }
@@ -583,23 +670,6 @@ impl<A: Allocator> RawVecInner<A> {
583670 }
584671 }
585672
586- /// # Safety
587- /// - `elem_layout` must be valid for `self`, i.e. it must be the same `elem_layout` used to
588- /// initially construct `self`
589- /// - `elem_layout`'s size must be a multiple of its alignment
590- #[ cfg( not( no_global_oom_handling) ) ]
591- #[ inline]
592- #[ rustc_const_unstable( feature = "const_heap" , issue = "79597" ) ]
593- const unsafe fn grow_one ( & mut self , elem_layout : Layout )
594- where
595- A : [ const ] Allocator ,
596- {
597- // SAFETY: Precondition passed to caller
598- if let Err ( err) = unsafe { self . grow_amortized ( self . cap . as_inner ( ) , 1 , elem_layout) } {
599- handle_error ( err) ;
600- }
601- }
602-
603673 /// # Safety
604674 /// - `elem_layout` must be valid for `self`, i.e. it must be the same `elem_layout` used to
605675 /// initially construct `self`
@@ -686,48 +756,6 @@ impl<A: Allocator> RawVecInner<A> {
686756 self . cap = unsafe { Cap :: new_unchecked ( cap) } ;
687757 }
688758
689- /// # Safety
690- /// - `elem_layout` must be valid for `self`, i.e. it must be the same `elem_layout` used to
691- /// initially construct `self`
692- /// - `elem_layout`'s size must be a multiple of its alignment
693- /// - The sum of `len` and `additional` must be greater than the current capacity
694- #[ rustc_const_unstable( feature = "const_heap" , issue = "79597" ) ]
695- const unsafe fn grow_amortized (
696- & mut self ,
697- len : usize ,
698- additional : usize ,
699- elem_layout : Layout ,
700- ) -> Result < ( ) , TryReserveError >
701- where
702- A : [ const ] Allocator ,
703- {
704- // This is ensured by the calling contexts.
705- debug_assert ! ( additional > 0 ) ;
706-
707- if elem_layout. size ( ) == 0 {
708- // Since we return a capacity of `usize::MAX` when `elem_size` is
709- // 0, getting to here necessarily means the `RawVec` is overfull.
710- return Err ( CapacityOverflow . into ( ) ) ;
711- }
712-
713- // Nothing we can really do about these checks, sadly.
714- let required_cap = len. checked_add ( additional) . ok_or ( CapacityOverflow ) ?;
715-
716- // This guarantees exponential growth. The doubling cannot overflow
717- // because `cap <= isize::MAX` and the type of `cap` is `usize`.
718- let cap = cmp:: max ( self . cap . as_inner ( ) * 2 , required_cap) ;
719- let cap = cmp:: max ( min_non_zero_cap ( elem_layout. size ( ) ) , cap) ;
720-
721- // SAFETY:
722- // - cap >= len + additional
723- // - other preconditions passed to caller
724- let ptr = unsafe { self . finish_grow ( cap, elem_layout) ? } ;
725-
726- // SAFETY: `finish_grow` would have failed if `cap > isize::MAX`
727- unsafe { self . set_ptr_and_cap ( ptr, cap) } ;
728- Ok ( ( ) )
729- }
730-
731759 /// # Safety
732760 /// - `elem_layout` must be valid for `self`, i.e. it must be the same `elem_layout` used to
733761 /// initially construct `self`
@@ -755,44 +783,6 @@ impl<A: Allocator> RawVecInner<A> {
755783 Ok ( ( ) )
756784 }
757785
758- /// # Safety
759- /// - `elem_layout` must be valid for `self`, i.e. it must be the same `elem_layout` used to
760- /// initially construct `self`
761- /// - `elem_layout`'s size must be a multiple of its alignment
762- /// - `cap` must be greater than the current capacity
763- // not marked inline(never) since we want optimizers to be able to observe the specifics of this
764- // function, see tests/codegen-llvm/vec-reserve-extend.rs.
765- #[ cold]
766- #[ rustc_const_unstable( feature = "const_heap" , issue = "79597" ) ]
767- const unsafe fn finish_grow (
768- & self ,
769- cap : usize ,
770- elem_layout : Layout ,
771- ) -> Result < NonNull < [ u8 ] > , TryReserveError >
772- where
773- A : [ const ] Allocator ,
774- {
775- let new_layout = layout_array ( cap, elem_layout) ?;
776-
777- let memory = if let Some ( ( ptr, old_layout) ) = unsafe { self . current_memory ( elem_layout) } {
778- // FIXME(const-hack): switch to `debug_assert_eq`
779- debug_assert ! ( old_layout. align( ) == new_layout. align( ) ) ;
780- unsafe {
781- // The allocator checks for alignment equality
782- hint:: assert_unchecked ( old_layout. align ( ) == new_layout. align ( ) ) ;
783- self . alloc . grow ( ptr, old_layout, new_layout)
784- }
785- } else {
786- self . alloc . allocate ( new_layout)
787- } ;
788-
789- // FIXME(const-hack): switch back to `map_err`
790- match memory {
791- Ok ( memory) => Ok ( memory) ,
792- Err ( _) => Err ( AllocError { layout : new_layout, non_exhaustive : ( ) } . into ( ) ) ,
793- }
794- }
795-
796786 /// # Safety
797787 /// - `elem_layout` must be valid for `self`, i.e. it must be the same `elem_layout` used to
798788 /// initially construct `self`
0 commit comments