88// option. This file may not be copied, modified, or distributed 
99// except according to those terms. 
1010
11- use  allocator:: { Alloc ,  Layout } ; 
12- use  core:: ptr:: { self ,  Unique } ; 
11+ use  core:: cmp; 
1312use  core:: mem; 
13+ use  core:: ops:: Drop ; 
14+ use  core:: ptr:: { self ,  Unique } ; 
1415use  core:: slice; 
15- use  heap:: Heap ; 
16+ use  heap:: { Alloc ,   Layout ,   Heap } ; 
1617use  super :: boxed:: Box ; 
17- use  core:: ops:: Drop ; 
18- use  core:: cmp; 
1918
2019/// A low-level utility for more ergonomically allocating, reallocating, and deallocating 
2120/// a buffer of memory on the heap without having to worry about all the corner cases 
@@ -222,6 +221,20 @@ impl<T, A: Alloc> RawVec<T, A> {
222221        & mut  self . a 
223222    } 
224223
224+     fn  current_layout ( & self )  -> Option < Layout >  { 
225+         if  self . cap  == 0  { 
226+             None 
227+         }  else  { 
228+             // We have an allocated chunk of memory, so we can bypass runtime 
229+             // checks to get our current layout. 
230+             unsafe  { 
231+                 let  align = mem:: align_of :: < T > ( ) ; 
232+                 let  size = mem:: size_of :: < T > ( )  *  self . cap ; 
233+                 Some ( Layout :: from_size_align_unchecked ( size,  align) ) 
234+             } 
235+         } 
236+     } 
237+ 
225238    /// Doubles the size of the type's backing allocation. This is common enough 
226239/// to want to do that it's easiest to just have a dedicated method. Slightly 
227240/// more efficient logic can be provided for this than the general case. 
@@ -280,27 +293,40 @@ impl<T, A: Alloc> RawVec<T, A> {
280293            // 0, getting to here necessarily means the RawVec is overfull. 
281294            assert ! ( elem_size != 0 ,  "capacity overflow" ) ; 
282295
283-             let  ( new_cap,  ptr_res)  = if  self . cap  == 0  { 
284-                 // skip to 4 because tiny Vec's are dumb; but not if that would cause overflow 
285-                 let  new_cap = if  elem_size > ( !0 )  / 8  {  1  }  else  {  4  } ; 
286-                 let  ptr_res = self . a . alloc_array :: < T > ( new_cap) ; 
287-                 ( new_cap,  ptr_res) 
288-             }  else  { 
289-                 // Since we guarantee that we never allocate more than isize::MAX bytes, 
290-                 // `elem_size * self.cap <= isize::MAX` as a precondition, so this can't overflow 
291-                 let  new_cap = 2  *  self . cap ; 
292-                 let  new_alloc_size = new_cap *  elem_size; 
293-                 alloc_guard ( new_alloc_size) ; 
294-                 let  ptr_res = self . a . realloc_array ( self . ptr ,  self . cap ,  new_cap) ; 
295-                 ( new_cap,  ptr_res) 
296-             } ; 
297- 
298-             // If allocate or reallocate fail, we'll get `null` back 
299-             let  uniq = match  ptr_res { 
300-                 Err ( err)  => self . a . oom ( err) , 
301-                 Ok ( uniq)  => uniq, 
296+             let  ( new_cap,  uniq)  = match  self . current_layout ( )  { 
297+                 Some ( cur)  => { 
298+                     // Since we guarantee that we never allocate more than 
299+                     // isize::MAX bytes, `elem_size * self.cap <= isize::MAX` as 
300+                     // a precondition, so this can't overflow. Additionally the 
301+                     // alignment will never be too large as to "not be 
302+                     // satisfiable", so `Layout::from_size_align` will always 
303+                     // return `Some`. 
304+                     // 
305+                     // tl;dr; we bypass runtime checks due to dynamic assertions 
306+                     // in this module, allowing us to use 
307+                     // `from_size_align_unchecked`. 
308+                     let  new_cap = 2  *  self . cap ; 
309+                     let  new_size = new_cap *  elem_size; 
310+                     let  new_layout = Layout :: from_size_align_unchecked ( new_size,  cur. align ( ) ) ; 
311+                     alloc_guard ( new_size) ; 
312+                     let  ptr_res = self . a . realloc ( self . ptr . as_ptr ( )  as  * mut  u8 , 
313+                                                  cur, 
314+                                                  new_layout) ; 
315+                     match  ptr_res { 
316+                         Ok ( ptr)  => ( new_cap,  Unique :: new_unchecked ( ptr as  * mut  T ) ) , 
317+                         Err ( e)  => self . a . oom ( e) , 
318+                     } 
319+                 } 
320+                 None  => { 
321+                     // skip to 4 because tiny Vec's are dumb; but not if that 
322+                     // would cause overflow 
323+                     let  new_cap = if  elem_size > ( !0 )  / 8  {  1  }  else  {  4  } ; 
324+                     match  self . a . alloc_array :: < T > ( new_cap)  { 
325+                         Ok ( ptr)  => ( new_cap,  ptr) , 
326+                         Err ( e)  => self . a . oom ( e) , 
327+                     } 
328+                 } 
302329            } ; 
303- 
304330            self . ptr  = uniq; 
305331            self . cap  = new_cap; 
306332        } 
@@ -323,21 +349,27 @@ impl<T, A: Alloc> RawVec<T, A> {
323349    pub  fn  double_in_place ( & mut  self )  -> bool  { 
324350        unsafe  { 
325351            let  elem_size = mem:: size_of :: < T > ( ) ; 
352+             let  old_layout = match  self . current_layout ( )  { 
353+                 Some ( layout)  => layout, 
354+                 None  => return  false ,  // nothing to double 
355+             } ; 
326356
327357            // since we set the capacity to usize::MAX when elem_size is 
328358            // 0, getting to here necessarily means the RawVec is overfull. 
329359            assert ! ( elem_size != 0 ,  "capacity overflow" ) ; 
330360
331-             // Since we guarantee that we never allocate more than isize::MAX bytes, 
332-             // `elem_size * self.cap <= isize::MAX` as a precondition, so this can't overflow 
361+             // Since we guarantee that we never allocate more than isize::MAX 
362+             // bytes, `elem_size * self.cap <= isize::MAX` as a precondition, so 
363+             // this can't overflow. 
364+             // 
365+             // Similarly like with `double` above we can go straight to 
366+             // `Layout::from_size_align_unchecked` as we know this won't 
367+             // overflow and the alignment is sufficiently small. 
333368            let  new_cap = 2  *  self . cap ; 
334-             let  new_alloc_size = new_cap *  elem_size; 
335- 
336-             alloc_guard ( new_alloc_size) ; 
337- 
369+             let  new_size = new_cap *  elem_size; 
370+             alloc_guard ( new_size) ; 
338371            let  ptr = self . ptr ( )  as  * mut  _ ; 
339-             let  old_layout = Layout :: new :: < T > ( ) . repeat ( self . cap ) . unwrap ( ) . 0 ; 
340-             let  new_layout = Layout :: new :: < T > ( ) . repeat ( new_cap) . unwrap ( ) . 0 ; 
372+             let  new_layout = Layout :: from_size_align_unchecked ( new_size,  old_layout. align ( ) ) ; 
341373            match  self . a . grow_in_place ( ptr,  old_layout,  new_layout)  { 
342374                Ok ( _)  => { 
343375                    // We can't directly divide `size`. 
@@ -373,8 +405,6 @@ impl<T, A: Alloc> RawVec<T, A> {
373405/// Aborts on OOM 
374406pub  fn  reserve_exact ( & mut  self ,  used_cap :  usize ,  needed_extra_cap :  usize )  { 
375407        unsafe  { 
376-             let  elem_size = mem:: size_of :: < T > ( ) ; 
377- 
378408            // NOTE: we don't early branch on ZSTs here because we want this 
379409            // to actually catch "asking for more than usize::MAX" in that case. 
380410            // If we make it past the first branch then we are guaranteed to 
@@ -388,21 +418,22 @@ impl<T, A: Alloc> RawVec<T, A> {
388418
389419            // Nothing we can really do about these checks :( 
390420            let  new_cap = used_cap. checked_add ( needed_extra_cap) . expect ( "capacity overflow" ) ; 
391-             let  new_alloc_size = new_cap. checked_mul ( elem_size) . expect ( "capacity overflow" ) ; 
392-             alloc_guard ( new_alloc_size) ; 
393- 
394-             let  result = if  self . cap  == 0  { 
395-                 self . a . alloc_array :: < T > ( new_cap) 
396-             }  else  { 
397-                 self . a . realloc_array ( self . ptr ,  self . cap ,  new_cap) 
421+             let  new_layout = match  Layout :: array :: < T > ( new_cap)  { 
422+                 Some ( layout)  => layout, 
423+                 None  => panic ! ( "capacity overflow" ) , 
398424            } ; 
399- 
400-             // If allocate or reallocate fail, we'll get `null` back 
401-             let  uniq = match  result { 
402-                 Err ( err)  => self . a . oom ( err) , 
403-                 Ok ( uniq)  => uniq, 
425+             alloc_guard ( new_layout. size ( ) ) ; 
426+             let  res = match  self . current_layout ( )  { 
427+                 Some ( layout)  => { 
428+                     let  old_ptr = self . ptr . as_ptr ( )  as  * mut  u8 ; 
429+                     self . a . realloc ( old_ptr,  layout,  new_layout) 
430+                 } 
431+                 None  => self . a . alloc ( new_layout) , 
432+             } ; 
433+             let  uniq = match  res { 
434+                 Ok ( ptr)  => Unique :: new_unchecked ( ptr as  * mut  T ) , 
435+                 Err ( e)  => self . a . oom ( e) , 
404436            } ; 
405- 
406437            self . ptr  = uniq; 
407438            self . cap  = new_cap; 
408439        } 
@@ -411,17 +442,14 @@ impl<T, A: Alloc> RawVec<T, A> {
411442    /// Calculates the buffer's new size given that it'll hold `used_cap + 
412443/// needed_extra_cap` elements. This logic is used in amortized reserve methods. 
413444/// Returns `(new_capacity, new_alloc_size)`. 
414- fn  amortized_new_size ( & self ,  used_cap :  usize ,  needed_extra_cap :  usize )  -> ( usize ,  usize )  { 
415-         let  elem_size = mem:: size_of :: < T > ( ) ; 
445+ fn  amortized_new_size ( & self ,  used_cap :  usize ,  needed_extra_cap :  usize )  -> usize  { 
416446        // Nothing we can really do about these checks :( 
417447        let  required_cap = used_cap. checked_add ( needed_extra_cap) 
418448            . expect ( "capacity overflow" ) ; 
419449        // Cannot overflow, because `cap <= isize::MAX`, and type of `cap` is `usize`. 
420450        let  double_cap = self . cap  *  2 ; 
421451        // `double_cap` guarantees exponential growth. 
422-         let  new_cap = cmp:: max ( double_cap,  required_cap) ; 
423-         let  new_alloc_size = new_cap. checked_mul ( elem_size) . expect ( "capacity overflow" ) ; 
424-         ( new_cap,  new_alloc_size) 
452+         cmp:: max ( double_cap,  required_cap) 
425453    } 
426454
427455    /// Ensures that the buffer contains at least enough space to hold 
@@ -489,21 +517,25 @@ impl<T, A: Alloc> RawVec<T, A> {
489517                return ; 
490518            } 
491519
492-             let  ( new_cap,  new_alloc_size)  = self . amortized_new_size ( used_cap,  needed_extra_cap) ; 
493-             // FIXME: may crash and burn on over-reserve 
494-             alloc_guard ( new_alloc_size) ; 
520+             let  new_cap = self . amortized_new_size ( used_cap,  needed_extra_cap) ; 
495521
496-             let  result = if  self . cap  == 0  { 
497-                 self . a . alloc_array :: < T > ( new_cap) 
498-             }  else  { 
499-                 self . a . realloc_array ( self . ptr ,  self . cap ,  new_cap) 
522+             let  new_layout = match  Layout :: array :: < T > ( new_cap)  { 
523+                 Some ( layout)  => layout, 
524+                 None  => panic ! ( "capacity overflow" ) , 
500525            } ; 
501- 
502-             let  uniq = match  result { 
503-                 Err ( err)  => self . a . oom ( err) , 
504-                 Ok ( uniq)  => uniq, 
526+             // FIXME: may crash and burn on over-reserve 
527+             alloc_guard ( new_layout. size ( ) ) ; 
528+             let  res = match  self . current_layout ( )  { 
529+                 Some ( layout)  => { 
530+                     let  old_ptr = self . ptr . as_ptr ( )  as  * mut  u8 ; 
531+                     self . a . realloc ( old_ptr,  layout,  new_layout) 
532+                 } 
533+                 None  => self . a . alloc ( new_layout) , 
534+             } ; 
535+             let  uniq = match  res { 
536+                 Ok ( ptr)  => Unique :: new_unchecked ( ptr as  * mut  T ) , 
537+                 Err ( e)  => self . a . oom ( e) , 
505538            } ; 
506- 
507539            self . ptr  = uniq; 
508540            self . cap  = new_cap; 
509541        } 
@@ -536,21 +568,24 @@ impl<T, A: Alloc> RawVec<T, A> {
536568            // Don't actually need any more capacity. If the current `cap` is 0, we can't 
537569            // reallocate in place. 
538570            // Wrapping in case they give a bad `used_cap` 
539-             if  self . cap ( ) . wrapping_sub ( used_cap)  >= needed_extra_cap || self . cap  == 0  { 
571+             let  old_layout = match  self . current_layout ( )  { 
572+                 Some ( layout)  => layout, 
573+                 None  => return  false , 
574+             } ; 
575+             if  self . cap ( ) . wrapping_sub ( used_cap)  >= needed_extra_cap { 
540576                return  false ; 
541577            } 
542578
543-             let  ( new_cap,  new_alloc_size)  = self . amortized_new_size ( used_cap,  needed_extra_cap) ; 
544-             // FIXME: may crash and burn on over-reserve 
545-             alloc_guard ( new_alloc_size) ; 
579+             let  new_cap = self . amortized_new_size ( used_cap,  needed_extra_cap) ; 
546580
547581            // Here, `cap < used_cap + needed_extra_cap <= new_cap` 
548582            // (regardless of whether `self.cap - used_cap` wrapped). 
549583            // Therefore we can safely call grow_in_place. 
550584
551585            let  ptr = self . ptr ( )  as  * mut  _ ; 
552-             let  old_layout = Layout :: new :: < T > ( ) . repeat ( self . cap ) . unwrap ( ) . 0 ; 
553586            let  new_layout = Layout :: new :: < T > ( ) . repeat ( new_cap) . unwrap ( ) . 0 ; 
587+             // FIXME: may crash and burn on over-reserve 
588+             alloc_guard ( new_layout. size ( ) ) ; 
554589            match  self . a . grow_in_place ( ptr,  old_layout,  new_layout)  { 
555590                Ok ( _)  => { 
556591                    self . cap  = new_cap; 
@@ -599,9 +634,24 @@ impl<T, A: Alloc> RawVec<T, A> {
599634            } 
600635        }  else  if  self . cap  != amount { 
601636            unsafe  { 
602-                 match  self . a . realloc_array ( self . ptr ,  self . cap ,  amount)  { 
637+                 // We know here that our `amount` is greater than zero. This 
638+                 // implies, via the assert above, that capacity is also greater 
639+                 // than zero, which means that we've got a current layout that 
640+                 // "fits" 
641+                 // 
642+                 // We also know that `self.cap` is greater than `amount`, and 
643+                 // consequently we don't need runtime checks for creating either 
644+                 // layout 
645+                 let  old_size = elem_size *  self . cap ; 
646+                 let  new_size = elem_size *  amount; 
647+                 let  align = mem:: align_of :: < T > ( ) ; 
648+                 let  old_layout = Layout :: from_size_align_unchecked ( old_size,  align) ; 
649+                 let  new_layout = Layout :: from_size_align_unchecked ( new_size,  align) ; 
650+                 match  self . a . realloc ( self . ptr . as_ptr ( )  as  * mut  u8 , 
651+                                      old_layout, 
652+                                      new_layout)  { 
653+                     Ok ( p)  => self . ptr  = Unique :: new_unchecked ( p as  * mut  T ) , 
603654                    Err ( err)  => self . a . oom ( err) , 
604-                     Ok ( uniq)  => self . ptr  = uniq, 
605655                } 
606656            } 
607657            self . cap  = amount; 
@@ -631,10 +681,11 @@ impl<T, A: Alloc> RawVec<T, A> {
631681    /// Frees the memory owned by the RawVec *without* trying to Drop its contents. 
632682pub  unsafe  fn  dealloc_buffer ( & mut  self )  { 
633683        let  elem_size = mem:: size_of :: < T > ( ) ; 
634-         if  elem_size != 0  && self . cap  != 0  { 
635-             let  ptr = self . ptr ( )  as  * mut  u8 ; 
636-             let  layout = Layout :: new :: < T > ( ) . repeat ( self . cap ) . unwrap ( ) . 0 ; 
637-             self . a . dealloc ( ptr,  layout) ; 
684+         if  elem_size != 0  { 
685+             if  let  Some ( layout)  = self . current_layout ( )  { 
686+                 let  ptr = self . ptr ( )  as  * mut  u8 ; 
687+                 self . a . dealloc ( ptr,  layout) ; 
688+             } 
638689        } 
639690    } 
640691} 
0 commit comments