mirror of
https://github.com/google/flatbuffers.git
synced 2026-06-05 13:08:58 +00:00
[C#] Improve Span<> utilization (#8588)
There are a couple instances where the ByteBuffer's Span property was accessed in a loop. + Extracted the use of the property outside of the loop to save a few cpu cycles. Access to the allocator's internal buffer isn't exposed as a ReadOnlySpan<byte> from the ByteBuffer or the FlatBufferBuilder. + Added a few convenience functions to access the buffer using a ReadOnlySpan<byte>. There are a few cases where built in Span extensions can be used to run optimized code. + Added the use of Span.Fill() and ReadOnlySpan.SequenceCompareTo to replace existing loops. Co-authored-by: Björn Harrtell <bjornharrtell@users.noreply.github.com> Co-authored-by: Wouter van Oortmerssen <aardappel@gmail.com>
This commit is contained in:
@@ -275,6 +275,11 @@ namespace Google.FlatBuffers
|
||||
}
|
||||
|
||||
#if ENABLE_SPAN_T && UNSAFE_BYTEBUFFER
|
||||
public ReadOnlySpan<byte> ToSizedReadOnlySpan()
|
||||
{
|
||||
return _buffer.ReadOnlySpan.Slice(Position, Length - Position);
|
||||
}
|
||||
|
||||
public ReadOnlyMemory<byte> ToReadOnlyMemory(int pos, int len)
|
||||
{
|
||||
return _buffer.ReadOnlyMemory.Slice(pos, len);
|
||||
@@ -289,6 +294,11 @@ namespace Google.FlatBuffers
|
||||
{
|
||||
return _buffer.Span.Slice(pos, len);
|
||||
}
|
||||
|
||||
public ReadOnlySpan<byte> ToReadOnlySpan(int pos, int len)
|
||||
{
|
||||
return _buffer.ReadOnlySpan.Slice(pos, len);
|
||||
}
|
||||
#else
|
||||
public ArraySegment<byte> ToArraySegment(int pos, int len)
|
||||
{
|
||||
@@ -380,18 +390,19 @@ namespace Google.FlatBuffers
|
||||
#elif ENABLE_SPAN_T
|
||||
protected void WriteLittleEndian(int offset, int count, ulong data)
|
||||
{
|
||||
Span<byte> span = _buffer.Span.Slice(offset, count);
|
||||
if (BitConverter.IsLittleEndian)
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
_buffer.Span[offset + i] = (byte)(data >> i * 8);
|
||||
span[i] = (byte)(data >> i * 8);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
_buffer.Span[offset + count - 1 - i] = (byte)(data >> i * 8);
|
||||
span[count - 1 - i] = (byte)(data >> i * 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -399,19 +410,20 @@ namespace Google.FlatBuffers
|
||||
protected ulong ReadLittleEndian(int offset, int count)
|
||||
{
|
||||
AssertOffsetAndLength(offset, count);
|
||||
ReadOnlySpan<byte> span = _buffer.ReadOnlySpan.Slice(offset, count);
|
||||
ulong r = 0;
|
||||
if (BitConverter.IsLittleEndian)
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
r |= (ulong)_buffer.Span[offset + i] << i * 8;
|
||||
r |= (ulong)span[i] << i * 8;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
r |= (ulong)_buffer.Span[offset + count - 1 - i] << i * 8;
|
||||
r |= (ulong)span[count - 1 - i] << i * 8;
|
||||
}
|
||||
}
|
||||
return r;
|
||||
@@ -445,8 +457,7 @@ namespace Google.FlatBuffers
|
||||
{
|
||||
AssertOffsetAndLength(offset, sizeof(byte) * count);
|
||||
Span<byte> span = _buffer.Span.Slice(offset, count);
|
||||
for (var i = 0; i < span.Length; ++i)
|
||||
span[i] = value;
|
||||
span.Fill(value);
|
||||
}
|
||||
#else
|
||||
public void PutSbyte(int offset, sbyte value)
|
||||
|
||||
@@ -957,6 +957,21 @@ namespace Google.FlatBuffers
|
||||
return _bb.ToSizedArray();
|
||||
}
|
||||
|
||||
#if ENABLE_SPAN_T && UNSAFE_BYTEBUFFER
|
||||
/// <summary>
|
||||
/// A utility function return the ByteBuffer data as a
|
||||
/// `ReadOnlySpan<byte>`.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A `ReadOnlySpan<byte>` that references the internal
|
||||
/// ByteBuffer data.
|
||||
/// </returns>
|
||||
public ReadOnlySpan<byte> SizedReadOnlySpan()
|
||||
{
|
||||
return _bb.ToSizedReadOnlySpan();
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Finalize a buffer, pointing to the given `rootTable`.
|
||||
/// </summary>
|
||||
|
||||
@@ -183,6 +183,12 @@ namespace Google.FlatBuffers
|
||||
var len_2 = bb.GetInt(offset_2);
|
||||
var startPos_1 = offset_1 + sizeof(int);
|
||||
var startPos_2 = offset_2 + sizeof(int);
|
||||
|
||||
#if ENABLE_SPAN_T && UNSAFE_BYTEBUFFER
|
||||
var span_1 = bb.ToReadOnlySpan(startPos_1, len_1);
|
||||
var span_2 = bb.ToReadOnlySpan(startPos_2, len_2);
|
||||
return span_1.SequenceCompareTo(span_2);
|
||||
#else
|
||||
var len = Math.Min(len_1, len_2);
|
||||
for(int i = 0; i < len; i++) {
|
||||
byte b1 = bb.Get(i + startPos_1);
|
||||
@@ -191,6 +197,7 @@ namespace Google.FlatBuffers
|
||||
return b1 - b2;
|
||||
}
|
||||
return len_1 - len_2;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Compare string from the ByteBuffer with the string object
|
||||
@@ -200,6 +207,11 @@ namespace Google.FlatBuffers
|
||||
var len_1 = bb.GetInt(offset_1);
|
||||
var len_2 = key.Length;
|
||||
var startPos_1 = offset_1 + sizeof(int);
|
||||
#if ENABLE_SPAN_T && UNSAFE_BYTEBUFFER
|
||||
ReadOnlySpan<byte> span = bb.ToReadOnlySpan(startPos_1, len_1);
|
||||
ReadOnlySpan<byte> keySpan = key;
|
||||
return span.SequenceCompareTo(keySpan);
|
||||
#else
|
||||
var len = Math.Min(len_1, len_2);
|
||||
for (int i = 0; i < len; i++) {
|
||||
byte b = bb.Get(i + startPos_1);
|
||||
@@ -207,6 +219,7 @@ namespace Google.FlatBuffers
|
||||
return b - key[i];
|
||||
}
|
||||
return len_1 - len_2;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user