@@ -373,38 +373,61 @@ impl CString {
373
373
/// the position of the nul byte.
374
374
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
375
375
pub fn new < T : Into < Vec < u8 > > > ( t : T ) -> Result < CString , NulError > {
376
- trait SpecIntoVec {
377
- fn into_vec ( self ) -> Vec < u8 > ;
376
+ trait SpecNewImpl {
377
+ fn spec_new_impl ( self ) -> Result < CString , NulError > ;
378
378
}
379
- impl < T : Into < Vec < u8 > > > SpecIntoVec for T {
380
- default fn into_vec ( self ) -> Vec < u8 > {
381
- self . into ( )
379
+
380
+ impl < T : Into < Vec < u8 > > > SpecNewImpl for T {
381
+ default fn spec_new_impl ( self ) -> Result < CString , NulError > {
382
+ let bytes: Vec < u8 > = self . into ( ) ;
383
+ match memchr:: memchr ( 0 , & bytes) {
384
+ Some ( i) => Err ( NulError ( i, bytes) ) ,
385
+ None => Ok ( unsafe { CString :: from_vec_unchecked ( bytes) } ) ,
386
+ }
382
387
}
383
388
}
384
- // Specialization for avoiding reallocation.
385
- impl SpecIntoVec for & ' _ [ u8 ] {
386
- fn into_vec ( self ) -> Vec < u8 > {
387
- let mut v = Vec :: with_capacity ( self . len ( ) + 1 ) ;
388
- v. extend ( self ) ;
389
- v
389
+
390
+ // Specialization for avoiding reallocation
391
+ #[ inline( always) ] // Without that it is not inlined into specializations
392
+ fn spec_new_impl_bytes ( bytes : & [ u8 ] ) -> Result < CString , NulError > {
393
+ // We cannot have such large slice that we would overflow here
394
+ // but using `checked_add` allows LLVM to assume that capacity never overflows
395
+ // and generate twice shorter code.
396
+ // `saturating_add` doesn't help for some reason.
397
+ let capacity = bytes. len ( ) . checked_add ( 1 ) . unwrap ( ) ;
398
+
399
+ // Allocate before validation to avoid duplication of allocation code.
400
+ // We still need to allocate and copy memory even if we get an error.
401
+ let mut buffer = Vec :: with_capacity ( capacity) ;
402
+ buffer. extend ( bytes) ;
403
+
404
+ // Check memory of self instead of new buffer.
405
+ // This allows better optimizations if lto enabled.
406
+ match memchr:: memchr ( 0 , bytes) {
407
+ Some ( i) => Err ( NulError ( i, buffer) ) ,
408
+ None => Ok ( unsafe { CString :: from_vec_unchecked ( buffer) } ) ,
390
409
}
391
410
}
392
- impl SpecIntoVec for & ' _ str {
393
- fn into_vec ( self ) -> Vec < u8 > {
394
- let mut v = Vec :: with_capacity ( self . len ( ) + 1 ) ;
395
- v. extend ( self . as_bytes ( ) ) ;
396
- v
411
+
412
+ impl SpecNewImpl for & ' _ [ u8 ] {
413
+ fn spec_new_impl ( self ) -> Result < CString , NulError > {
414
+ spec_new_impl_bytes ( self )
397
415
}
398
416
}
399
417
400
- Self :: _new ( SpecIntoVec :: into_vec ( t) )
401
- }
418
+ impl SpecNewImpl for & ' _ str {
419
+ fn spec_new_impl ( self ) -> Result < CString , NulError > {
420
+ spec_new_impl_bytes ( self . as_bytes ( ) )
421
+ }
422
+ }
402
423
403
- fn _new ( bytes : Vec < u8 > ) -> Result < CString , NulError > {
404
- match memchr :: memchr ( 0 , & bytes ) {
405
- Some ( i ) => Err ( NulError ( i , bytes ) ) ,
406
- None => Ok ( unsafe { CString :: from_vec_unchecked ( bytes ) } ) ,
424
+ impl SpecNewImpl for & ' _ mut [ u8 ] {
425
+ fn spec_new_impl ( self ) -> Result < CString , NulError > {
426
+ spec_new_impl_bytes ( self )
427
+ }
407
428
}
429
+
430
+ t. spec_new_impl ( )
408
431
}
409
432
410
433
/// Creates a C-compatible string by consuming a byte vector,
0 commit comments