@@ -713,53 +713,66 @@ private static unsafe string JoinInternal(ReadOnlySpan<char> first, ReadOnlySpan
713
713
{
714
714
Debug . Assert ( first . Length > 0 && second . Length > 0 && third . Length > 0 && fourth . Length > 0 , "should have dealt with empty paths" ) ;
715
715
716
- byte firstNeedsSeparator = PathInternal . IsDirectorySeparator ( first [ ^ 1 ] ) || PathInternal . IsDirectorySeparator ( second [ 0 ] ) ? ( byte ) 0 : ( byte ) 1 ;
717
- byte secondNeedsSeparator = PathInternal . IsDirectorySeparator ( second [ ^ 1 ] ) || PathInternal . IsDirectorySeparator ( third [ 0 ] ) ? ( byte ) 0 : ( byte ) 1 ;
718
- byte thirdNeedsSeparator = PathInternal . IsDirectorySeparator ( third [ ^ 1 ] ) || PathInternal . IsDirectorySeparator ( fourth [ 0 ] ) ? ( byte ) 0 : ( byte ) 1 ;
719
-
720
716
#pragma warning disable CS8500 // This takes the address of, gets the size of, or declares a pointer to a managed type
717
+ var state = new JoinInternalState
718
+ {
719
+ ReadOnlySpanPtr1 = ( IntPtr ) ( & first ) ,
720
+ ReadOnlySpanPtr2 = ( IntPtr ) ( & second ) ,
721
+ ReadOnlySpanPtr3 = ( IntPtr ) ( & third ) ,
722
+ ReadOnlySpanPtr4 = ( IntPtr ) ( & fourth ) ,
723
+ NeedSeparator1 = PathInternal . IsDirectorySeparator ( first [ ^ 1 ] ) || PathInternal . IsDirectorySeparator ( second [ 0 ] ) ? ( byte ) 0 : ( byte ) 1 ,
724
+ NeedSeparator2 = PathInternal . IsDirectorySeparator ( second [ ^ 1 ] ) || PathInternal . IsDirectorySeparator ( third [ 0 ] ) ? ( byte ) 0 : ( byte ) 1 ,
725
+ NeedSeparator3 = PathInternal . IsDirectorySeparator ( third [ ^ 1 ] ) || PathInternal . IsDirectorySeparator ( fourth [ 0 ] ) ? ( byte ) 0 : ( byte ) 1 ,
726
+ } ;
727
+
721
728
return string . Create (
722
- first . Length + second . Length + third . Length + fourth . Length + firstNeedsSeparator + secondNeedsSeparator + thirdNeedsSeparator ,
723
- ( FirstRos : ( IntPtr ) ( & first ) , SecondRos : ( IntPtr ) ( & second ) , ThirdRos : ( IntPtr ) ( & third ) , FourthRos : ( IntPtr ) ( & fourth ) , firstNeedsSeparator , secondNeedsSeparator , thirdNeedsSeparator ) ,
729
+ first . Length + second . Length + third . Length + fourth . Length + state . NeedSeparator1 + state . NeedSeparator2 + state . NeedSeparator3 ,
730
+ state ,
724
731
static ( destination , state ) =>
725
732
{
726
- ReadOnlySpan < char > first = * ( ReadOnlySpan < char > * ) state . FirstRos ;
733
+ ReadOnlySpan < char > first = * ( ReadOnlySpan < char > * ) state . ReadOnlySpanPtr1 ;
727
734
first. CopyTo ( destination ) ;
728
735
destination = destination. Slice ( first . Length ) ;
729
736
730
- if ( state . firstNeedsSeparator != 0 )
737
+ if ( state . NeedSeparator1 != 0 )
731
738
{
732
739
destination [ 0 ] = PathInternal . DirectorySeparatorChar ;
733
740
destination = destination . Slice ( 1 ) ;
734
741
}
735
742
736
- ReadOnlySpan < char > second = * ( ReadOnlySpan < char > * ) state . SecondRos ;
743
+ ReadOnlySpan < char > second = * ( ReadOnlySpan < char > * ) state . ReadOnlySpanPtr2 ;
737
744
second. CopyTo ( destination ) ;
738
745
destination = destination. Slice ( second . Length ) ;
739
746
740
- if ( state . secondNeedsSeparator != 0 )
747
+ if ( state . NeedSeparator2 != 0 )
741
748
{
742
749
destination [ 0 ] = PathInternal . DirectorySeparatorChar ;
743
750
destination = destination . Slice ( 1 ) ;
744
751
}
745
752
746
- ReadOnlySpan < char > third = * ( ReadOnlySpan < char > * ) state . ThirdRos ;
753
+ ReadOnlySpan < char > third = * ( ReadOnlySpan < char > * ) state . ReadOnlySpanPtr3 ;
747
754
third. CopyTo ( destination ) ;
748
755
destination = destination. Slice ( third . Length ) ;
749
756
750
- if ( state . thirdNeedsSeparator != 0 )
757
+ if ( state . NeedSeparator3 != 0 )
751
758
{
752
759
destination [ 0 ] = PathInternal . DirectorySeparatorChar ;
753
760
destination = destination . Slice ( 1 ) ;
754
761
}
755
762
756
- ReadOnlySpan < char > fourth = * ( ReadOnlySpan < char > * ) state . FourthRos ;
763
+ ReadOnlySpan < char > fourth = * ( ReadOnlySpan < char > * ) state . ReadOnlySpanPtr4 ;
757
764
Debug. Assert ( fourth . Length == destination . Length ) ;
758
765
fourth. CopyTo ( destination ) ;
759
766
} ) ;
760
767
#pragma warning restore CS8500
761
768
}
762
769
770
+ private struct JoinInternalState // used to avoid rooting ValueTuple`7
771
+ {
772
+ public IntPtr ReadOnlySpanPtr1 , ReadOnlySpanPtr2 , ReadOnlySpanPtr3 , ReadOnlySpanPtr4 ;
773
+ public byte NeedSeparator1 , NeedSeparator2 , NeedSeparator3 ;
774
+ }
775
+
763
776
private static ReadOnlySpan < byte > Base32Char => "abcdefghijklmnopqrstuvwxyz012345"u8 ;
764
777
765
778
internal static unsafe void Populate83FileNameFromRandomBytes ( byte * bytes , int byteCount , Span < char > chars )
0 commit comments