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