//
internal void WriteFloat(float v, TdsParserStateObject stateObj)
{
+#if netcoreapp // BitConverter.TryGetBytes is only availble in netcoreapp 2.1> at this time, review support when changing
+ Span<byte> bytes = stackalloc byte[sizeof(float)];
+ BitConverter.TryWriteBytes(bytes, v);
+ stateObj.WriteByteSpan(bytes);
+#else
byte[] bytes = BitConverter.GetBytes(v);
-
- stateObj.WriteByteArray(bytes, bytes.Length, 0);
+ stateObj.WriteByteArray(bytes, bytes.Length, 0);
+#endif
}
//
//
internal void WriteDouble(double v, TdsParserStateObject stateObj)
{
+#if netcoreapp // BitConverter.TryGetBytes is only availble in netcoreapp 2.1> at this time, review support when changing
+ Span<byte> bytes = stackalloc byte[sizeof(double)];
+ BitConverter.TryWriteBytes(bytes, v);
+ stateObj.WriteByteSpan(bytes);
+#else
byte[] bytes = BitConverter.GetBytes(v);
-
stateObj.WriteByteArray(bytes, bytes.Length, 0);
+#endif
}
internal void PrepareResetConnection(bool preserveTransaction)
_outBuff[_outBytesUsed++] = b;
}
- //
- // Takes a byte array and writes it to the buffer.
- //
+
+ internal Task WriteByteSpan(ReadOnlySpan<byte> span, bool canAccumulate = true, TaskCompletionSource<object> completion = null)
+ {
+ return WriteBytes(span, span.Length, 0, canAccumulate, completion);
+ }
+
internal Task WriteByteArray(byte[] b, int len, int offsetBuffer, bool canAccumulate = true, TaskCompletionSource<object> completion = null)
{
+ return WriteBytes(ReadOnlySpan<byte>.Empty, len, offsetBuffer, canAccumulate, completion, b);
+ }
+
+ //
+ // Takes a span or a byte array and writes it to the buffer
+ // If you pass in a span and a null array then the span wil be used.
+ // If you pass in a non-null array then the array will be used and the span is ignored.
+ // if the span cannot be written into the current packet then the remaining contents of the span are copied to a
+ // new heap allocated array that will used to callback into the method to continue the write operation.
+ private Task WriteBytes(ReadOnlySpan<byte> b, int len, int offsetBuffer, bool canAccumulate = true, TaskCompletionSource<object> completion = null, byte[] array = null)
+ {
+ if (array != null)
+ {
+ b = new ReadOnlySpan<byte>(array, offsetBuffer, len);
+ }
try
{
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
int offset = offsetBuffer;
- Debug.Assert(b.Length >= len, "Invalid length sent to WriteByteArray()!");
+ Debug.Assert(b.Length >= len, "Invalid length sent to WriteBytes()!");
// loop through and write the entire array
do
{
if ((_outBytesUsed + len) > _outBuff.Length)
{
- // If the remainder of the string won't fit into the buffer, then we have to put
+ // If the remainder of the data won't fit into the buffer, then we have to put
// whatever we can into the buffer, and flush that so we can then put more into
// the buffer on the next loop of the while.
int remainder = _outBuff.Length - _outBytesUsed;
// write the remainder
- Buffer.BlockCopy(b, offset, _outBuff, _outBytesUsed, remainder);
+ Span<byte> copyTo = _outBuff.AsSpan(_outBytesUsed, remainder);
+ ReadOnlySpan<byte> copyFrom = b.Slice(0, remainder);
+
+ Debug.Assert(copyTo.Length == copyFrom.Length, $"copyTo.Length:{copyTo.Length} and copyFrom.Length{copyFrom.Length:D} should be the same");
+
+ copyFrom.CopyTo(copyTo);
- // handle counters
offset += remainder;
_outBytesUsed += remainder;
len -= remainder;
+ b = b.Slice(remainder, len);
Task packetTask = WritePacket(TdsEnums.SOFTFLUSH, canAccumulate);
completion = new TaskCompletionSource<object>();
task = completion.Task; // we only care about return from topmost call, so do not access Task property in other cases
}
- WriteByteArraySetupContinuation(b, len, completion, offset, packetTask);
+
+ if (array == null)
+ {
+ byte[] tempArray = new byte[len];
+ Span<byte> copyTempTo = tempArray.AsSpan();
+
+ Debug.Assert(copyTempTo.Length == b.Length, $"copyTempTo.Length:{copyTempTo.Length} and copyTempFrom.Length:{b.Length:D} should be the same");
+
+ b.CopyTo(copyTempTo);
+ array = tempArray;
+ offset = 0;
+ }
+
+ WriteBytesSetupContinuation(array, len, completion, offset, packetTask);
return task;
}
}
else
- { //((stateObj._outBytesUsed + len) <= stateObj._outBuff.Length )
+ {
+ //((stateObj._outBytesUsed + len) <= stateObj._outBuff.Length )
// Else the remainder of the string will fit into the buffer, so copy it into the
// buffer and then break out of the loop.
- Buffer.BlockCopy(b, offset, _outBuff, _outBytesUsed, len);
+ Span<byte> copyTo = _outBuff.AsSpan(_outBytesUsed, len);
+ ReadOnlySpan<byte> copyFrom = b.Slice(0, len);
+
+ Debug.Assert(copyTo.Length == copyFrom.Length, $"copyTo.Length:{copyTo.Length} and copyFrom.Length:{copyFrom.Length:D} should be the same");
+
+ copyFrom.CopyTo(copyTo);
// handle out buffer bytes used counter
_outBytesUsed += len;
}
}
- // This is in its own method to avoid always allocating the lambda in WriteByteArray
- private void WriteByteArraySetupContinuation(byte[] b, int len, TaskCompletionSource<object> completion, int offset, Task packetTask)
+ // This is in its own method to avoid always allocating the lambda in WriteBytes
+ private void WriteBytesSetupContinuation(byte[] array, int len, TaskCompletionSource<object> completion, int offset, Task packetTask)
{
AsyncHelper.ContinueTask(packetTask, completion,
- () => WriteByteArray(b, len: len, offsetBuffer: offset, canAccumulate: false, completion: completion),
- connectionToDoom: _parser.Connection);
+ () => WriteBytes(ReadOnlySpan<byte>.Empty, len: len, offsetBuffer: offset, canAccumulate: false, completion: completion, array),
+ connectionToDoom: _parser.Connection
+ );
}
// Dumps contents of buffer to SNI for network write.