@@ -930,9 +930,28 @@ internal void WriteByte(byte b)
930
930
// set byte in buffer and increment the counter for number of bytes used in the out buffer
931
931
_outBuff [ _outBytesUsed ++ ] = b ;
932
932
}
933
+ internal Task WriteByteSpan ( ReadOnlySpan < byte > span , bool canAccumulate = true , TaskCompletionSource < object > completion = null )
934
+ {
935
+ return WriteBytes ( span , span . Length , 0 , canAccumulate , completion ) ;
936
+ }
933
937
934
938
internal Task WriteByteArray ( byte [ ] b , int len , int offsetBuffer , bool canAccumulate = true , TaskCompletionSource < object > completion = null )
935
939
{
940
+ return WriteBytes ( ReadOnlySpan < byte > . Empty , len , offsetBuffer , canAccumulate , completion , b ) ;
941
+ }
942
+
943
+ //
944
+ // Takes a span or a byte array and writes it to the buffer
945
+ // If you pass in a span and a null array then the span wil be used.
946
+ // If you pass in a non-null array then the array will be used and the span is ignored.
947
+ // if the span cannot be written into the current packet then the remaining contents of the span are copied to a
948
+ // new heap allocated array that will used to callback into the method to continue the write operation.
949
+ private Task WriteBytes ( ReadOnlySpan < byte > b , int len , int offsetBuffer , bool canAccumulate = true , TaskCompletionSource < object > completion = null , byte [ ] array = null )
950
+ {
951
+ if ( array != null )
952
+ {
953
+ b = new ReadOnlySpan < byte > ( array , offsetBuffer , len ) ;
954
+ }
936
955
try
937
956
{
938
957
TdsParser . ReliabilitySection . Assert ( "unreliable call to WriteByteArray" ) ; // you need to setup for a thread abort somewhere before you call this method
@@ -949,7 +968,7 @@ internal Task WriteByteArray(byte[] b, int len, int offsetBuffer, bool canAccumu
949
968
950
969
int offset = offsetBuffer;
951
970
952
- Debug. Assert( b . Length > = len , "Invalid length sent to WriteByteArray ()!" ) ;
971
+ Debug. Assert( b . Length > = len , "Invalid length sent to WriteBytes ()!" ) ;
953
972
954
973
// loop through and write the entire array
955
974
do
@@ -963,12 +982,17 @@ internal Task WriteByteArray(byte[] b, int len, int offsetBuffer, bool canAccumu
963
982
int remainder = _outBuff. Length - _outBytesUsed;
964
983
965
984
// write the remainder
966
- Buffer . BlockCopy( b , offset , _outBuff , _outBytesUsed , remainder ) ;
985
+ Span < byte > copyTo = _outBuff. AsSpan( _outBytesUsed , remainder ) ;
986
+ ReadOnlySpan < byte > copyFrom = b . Slice ( 0 , remainder ) ;
987
+
988
+ Debug . Assert ( copyTo . Length = = copyFrom . Length , $"copyTo.Length:{copyTo.Length} and copyFrom.Length{copyFrom.Length:D} should be the same" ) ;
989
+
990
+ copyFrom . CopyTo ( copyTo ) ;
967
991
968
- // handle counters
969
992
offset += remainder ;
970
993
_outBytesUsed += remainder ;
971
994
len -= remainder ;
995
+ b = b . Slice ( remainder , len ) ;
972
996
973
997
Task packetTask = WritePacket ( TdsEnums . SOFTFLUSH , canAccumulate ) ;
974
998
@@ -981,18 +1005,35 @@ internal Task WriteByteArray(byte[] b, int len, int offsetBuffer, bool canAccumu
981
1005
completion = new TaskCompletionSource < object > ( ) ;
982
1006
task = completion . Task ; // we only care about return from topmost call, so do not access Task property in other cases
983
1007
}
984
- WriteByteArraySetupContinuation ( b , len , completion , offset , packetTask ) ;
1008
+
1009
+ if ( array == null )
1010
+ {
1011
+ byte [ ] tempArray = new byte [ len ] ;
1012
+ Span < byte > copyTempTo = tempArray. AsSpan( ) ;
1013
+
1014
+ Debug . Assert ( copyTempTo . Length = = b . Length , $"copyTempTo.Length:{copyTempTo.Length} and copyTempFrom.Length:{b.Length:D} should be the same" ) ;
1015
+
1016
+ b . CopyTo ( copyTempTo ) ;
1017
+ array = tempArray ;
1018
+ offset = 0 ;
1019
+ }
1020
+
1021
+ WriteBytesSetupContinuation( array , len , completion , offset , packetTask ) ;
985
1022
return task;
986
1023
}
987
-
988
1024
}
989
1025
else
990
1026
{
991
1027
//((stateObj._outBytesUsed + len) <= stateObj._outBuff.Length )
992
1028
// Else the remainder of the string will fit into the buffer, so copy it into the
993
1029
// buffer and then break out of the loop.
994
1030
995
- Buffer . BlockCopy( b, offset , _outBuff , _outBytesUsed , len ) ;
1031
+ Span< byte > copyTo = _outBuff . AsSpan ( _outBytesUsed , len ) ;
1032
+ ReadOnlySpan < byte > copyFrom = b . Slice ( 0 , len ) ;
1033
+
1034
+ Debug. Assert ( copyTo . Length == copyFrom . Length , $ "copyTo.Length:{ copyTo . Length } and copyFrom.Length:{ copyFrom . Length : D} should be the same") ;
1035
+
1036
+ copyFrom. CopyTo ( copyTo ) ;
996
1037
997
1038
// handle out buffer bytes used counter
998
1039
_outBytesUsed += len;
@@ -1021,7 +1062,7 @@ internal Task WriteByteArray(byte[] b, int len, int offsetBuffer, bool canAccumu
1021
1062
}
1022
1063
1023
1064
// This is in its own method to avoid always allocating the lambda in WriteByteArray
1024
- private void WriteByteArraySetupContinuation ( byte [ ] b , int len , TaskCompletionSource < object > completion , int offset , Task packetTask )
1065
+ private void WriteBytesSetupContinuation ( byte [ ] b , int len , TaskCompletionSource < object > completion , int offset , Task packetTask )
1025
1066
{
1026
1067
AsyncHelper. ContinueTask ( packetTask , completion ,
1027
1068
( ) => WriteByteArray ( b , len : len , offsetBuffer : offset , canAccumulate : false , completion : completion ) ,
0 commit comments