@@ -565,7 +565,7 @@ pub trait SliceConcatExt<T: ?Sized> {
565
565
impl < T : Clone , V : Borrow < [ T ] > > SliceConcatExt < T > for [ V ] {
566
566
type Output = Vec < T > ;
567
567
568
- fn concat ( & self ) -> Vec < T > {
568
+ default fn concat ( & self ) -> Vec < T > {
569
569
let size = self . iter ( ) . fold ( 0 , |acc, v| acc + v. borrow ( ) . len ( ) ) ;
570
570
let mut result = Vec :: with_capacity ( size) ;
571
571
for v in self {
@@ -574,26 +574,135 @@ impl<T: Clone, V: Borrow<[T]>> SliceConcatExt<T> for [V] {
574
574
result
575
575
}
576
576
577
- fn join ( & self , sep : & T ) -> Vec < T > {
578
- let size = self . iter ( ) . fold ( 0 , |acc, v| acc + v. borrow ( ) . len ( ) ) ;
579
- let mut result = Vec :: with_capacity ( size + self . len ( ) ) ;
580
- let mut first = true ;
581
- for v in self {
582
- if first {
583
- first = false
584
- } else {
585
- result. push ( sep. clone ( ) )
577
+ default fn join ( & self , sep : & T ) -> Vec < T > {
578
+ let mut iter = self . iter ( ) ;
579
+ iter. next ( ) . map_or ( vec ! [ ] , |first| {
580
+ let size = self . iter ( ) . fold ( 0 , |acc, v| acc + v. borrow ( ) . len ( ) ) ;
581
+ let mut result = Vec :: with_capacity ( size + self . len ( ) ) ;
582
+ result. extend_from_slice ( first. borrow ( ) ) ;
583
+
584
+ for v in iter {
585
+ result. push ( sep. clone ( ) ) ;
586
+ result. extend_from_slice ( v. borrow ( ) )
586
587
}
587
- result. extend_from_slice ( v. borrow ( ) )
588
- }
589
- result
588
+ result
589
+ } )
590
590
}
591
591
592
592
fn connect ( & self , sep : & T ) -> Vec < T > {
593
593
self . join ( sep)
594
594
}
595
595
}
596
596
597
+ #[ unstable( feature = "slice_concat_ext" ,
598
+ reason = "trait should not have to exist" ,
599
+ issue = "27747" ) ]
600
+ impl < T : Copy , V : Borrow < [ T ] > > SliceConcatExt < T > for [ V ] {
601
+ fn concat ( & self ) -> Vec < T > {
602
+ join_generic_copy ( self , & [ ] )
603
+ }
604
+
605
+ fn join ( & self , sep : & T ) -> Vec < T > {
606
+ join_generic_copy ( self , & [ * sep] )
607
+ }
608
+ }
609
+
610
+ macro_rules! spezialize_for_lengths {
611
+ ( $separator: expr, $target: expr, $iter: expr; $( $num: expr) ,* ) => {
612
+ let mut target = $target;
613
+ let iter = $iter;
614
+ let sep_len = $separator. len( ) ;
615
+ let sep_bytes = $separator;
616
+ match $separator. len( ) {
617
+ $(
618
+ // loops with hardcoded sizes run much faster
619
+ // specialize the cases with small separator lengths
620
+ $num => {
621
+ for s in iter {
622
+ target. get_unchecked_mut( ..$num)
623
+ . copy_from_slice( sep_bytes) ;
624
+
625
+ let s_bytes = s. borrow( ) . as_ref( ) ;
626
+ let offset = s_bytes. len( ) ;
627
+ target = { target} . get_unchecked_mut( $num..) ;
628
+ target. get_unchecked_mut( ..offset)
629
+ . copy_from_slice( s_bytes) ;
630
+ target = { target} . get_unchecked_mut( offset..) ;
631
+ }
632
+ } ,
633
+ ) *
634
+ 0 => {
635
+ // concat, same principle without the separator
636
+ for s in iter {
637
+ let s_bytes = s. borrow( ) . as_ref( ) ;
638
+ let offset = s_bytes. len( ) ;
639
+ target. get_unchecked_mut( ..offset)
640
+ . copy_from_slice( s_bytes) ;
641
+ target = { target} . get_unchecked_mut( offset..) ;
642
+ }
643
+ } ,
644
+ _ => {
645
+ // arbitrary non-zero size fallback
646
+ for s in iter {
647
+ target. get_unchecked_mut( ..sep_len)
648
+ . copy_from_slice( sep_bytes) ;
649
+
650
+ let s_bytes = s. borrow( ) . as_ref( ) ;
651
+ let offset = s_bytes. len( ) ;
652
+ target = { target} . get_unchecked_mut( sep_len..) ;
653
+ target. get_unchecked_mut( ..offset)
654
+ . copy_from_slice( s_bytes) ;
655
+ target = { target} . get_unchecked_mut( offset..) ;
656
+ }
657
+ }
658
+ }
659
+ } ;
660
+ }
661
+
662
+ // Optimized join implementation that works for both Vec<T> and String's inner vec
663
+ // the bounds for String-join are S: Borrow<str> and for Vec-join Borrow<[T]>
664
+ // [T] and str both impl AsRef<[T]> for some T
665
+ // => s.borrow().as_ref() and we always have slices
666
+ pub ( crate ) fn join_generic_copy < B , T , S > ( slice : & [ S ] , sep : & [ T ] ) -> Vec < T >
667
+ where
668
+ T : Copy ,
669
+ B : AsRef < [ T ] > + ?Sized ,
670
+ S : Borrow < B > ,
671
+ {
672
+ let sep_len = sep. len ( ) ;
673
+ let mut iter = slice. iter ( ) ;
674
+ iter. next ( ) . map_or ( vec ! [ ] , |first| {
675
+ // this is wrong without the guarantee that `slice` is non-empty
676
+ // if the `len` calculation overflows, we'll panic
677
+ // we would have run out of memory anyway and the rest of the function requires
678
+ // the entire String pre-allocated for safety
679
+ //
680
+ // this is the exact len of the resulting String
681
+ let len = sep_len. checked_mul ( slice. len ( ) - 1 ) . and_then ( |n| {
682
+ slice. iter ( ) . map ( |s| s. borrow ( ) . as_ref ( ) . len ( ) ) . try_fold ( n, usize:: checked_add)
683
+ } ) . expect ( "attempt to join into collection with len > usize::MAX" ) ;
684
+
685
+ // crucial for safety
686
+ let mut result = Vec :: with_capacity ( len) ;
687
+
688
+ unsafe {
689
+ result. extend_from_slice ( first. borrow ( ) . as_ref ( ) ) ;
690
+
691
+ {
692
+ let pos = result. len ( ) ;
693
+ let target = result. get_unchecked_mut ( pos..len) ;
694
+
695
+ // copy separator and strs over without bounds checks
696
+ // generate loops with hardcoded offsets for small separators
697
+ // massive improvements possible (~ x2)
698
+ spezialize_for_lengths ! ( sep, target, iter; 1 , 2 , 3 , 4 ) ;
699
+ }
700
+ result. set_len ( len) ;
701
+ }
702
+ result
703
+ } )
704
+ }
705
+
597
706
////////////////////////////////////////////////////////////////////////////////
598
707
// Standard trait implementations for slices
599
708
////////////////////////////////////////////////////////////////////////////////
0 commit comments