mirror of
https://github.com/google/flatbuffers.git
synced 2026-06-30 10:10:01 +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
|
#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)
|
public ReadOnlyMemory<byte> ToReadOnlyMemory(int pos, int len)
|
||||||
{
|
{
|
||||||
return _buffer.ReadOnlyMemory.Slice(pos, len);
|
return _buffer.ReadOnlyMemory.Slice(pos, len);
|
||||||
@@ -289,6 +294,11 @@ namespace Google.FlatBuffers
|
|||||||
{
|
{
|
||||||
return _buffer.Span.Slice(pos, len);
|
return _buffer.Span.Slice(pos, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ReadOnlySpan<byte> ToReadOnlySpan(int pos, int len)
|
||||||
|
{
|
||||||
|
return _buffer.ReadOnlySpan.Slice(pos, len);
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
public ArraySegment<byte> ToArraySegment(int pos, int len)
|
public ArraySegment<byte> ToArraySegment(int pos, int len)
|
||||||
{
|
{
|
||||||
@@ -380,18 +390,19 @@ namespace Google.FlatBuffers
|
|||||||
#elif ENABLE_SPAN_T
|
#elif ENABLE_SPAN_T
|
||||||
protected void WriteLittleEndian(int offset, int count, ulong data)
|
protected void WriteLittleEndian(int offset, int count, ulong data)
|
||||||
{
|
{
|
||||||
|
Span<byte> span = _buffer.Span.Slice(offset, count);
|
||||||
if (BitConverter.IsLittleEndian)
|
if (BitConverter.IsLittleEndian)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
_buffer.Span[offset + i] = (byte)(data >> i * 8);
|
span[i] = (byte)(data >> i * 8);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (int i = 0; i < count; i++)
|
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)
|
protected ulong ReadLittleEndian(int offset, int count)
|
||||||
{
|
{
|
||||||
AssertOffsetAndLength(offset, count);
|
AssertOffsetAndLength(offset, count);
|
||||||
|
ReadOnlySpan<byte> span = _buffer.ReadOnlySpan.Slice(offset, count);
|
||||||
ulong r = 0;
|
ulong r = 0;
|
||||||
if (BitConverter.IsLittleEndian)
|
if (BitConverter.IsLittleEndian)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
r |= (ulong)_buffer.Span[offset + i] << i * 8;
|
r |= (ulong)span[i] << i * 8;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (int i = 0; i < count; i++)
|
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;
|
return r;
|
||||||
@@ -445,8 +457,7 @@ namespace Google.FlatBuffers
|
|||||||
{
|
{
|
||||||
AssertOffsetAndLength(offset, sizeof(byte) * count);
|
AssertOffsetAndLength(offset, sizeof(byte) * count);
|
||||||
Span<byte> span = _buffer.Span.Slice(offset, count);
|
Span<byte> span = _buffer.Span.Slice(offset, count);
|
||||||
for (var i = 0; i < span.Length; ++i)
|
span.Fill(value);
|
||||||
span[i] = value;
|
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
public void PutSbyte(int offset, sbyte value)
|
public void PutSbyte(int offset, sbyte value)
|
||||||
|
|||||||
@@ -957,6 +957,21 @@ namespace Google.FlatBuffers
|
|||||||
return _bb.ToSizedArray();
|
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>
|
/// <summary>
|
||||||
/// Finalize a buffer, pointing to the given `rootTable`.
|
/// Finalize a buffer, pointing to the given `rootTable`.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -183,6 +183,12 @@ namespace Google.FlatBuffers
|
|||||||
var len_2 = bb.GetInt(offset_2);
|
var len_2 = bb.GetInt(offset_2);
|
||||||
var startPos_1 = offset_1 + sizeof(int);
|
var startPos_1 = offset_1 + sizeof(int);
|
||||||
var startPos_2 = offset_2 + 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);
|
var len = Math.Min(len_1, len_2);
|
||||||
for(int i = 0; i < len; i++) {
|
for(int i = 0; i < len; i++) {
|
||||||
byte b1 = bb.Get(i + startPos_1);
|
byte b1 = bb.Get(i + startPos_1);
|
||||||
@@ -191,6 +197,7 @@ namespace Google.FlatBuffers
|
|||||||
return b1 - b2;
|
return b1 - b2;
|
||||||
}
|
}
|
||||||
return len_1 - len_2;
|
return len_1 - len_2;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compare string from the ByteBuffer with the string object
|
// 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_1 = bb.GetInt(offset_1);
|
||||||
var len_2 = key.Length;
|
var len_2 = key.Length;
|
||||||
var startPos_1 = offset_1 + sizeof(int);
|
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);
|
var len = Math.Min(len_1, len_2);
|
||||||
for (int i = 0; i < len; i++) {
|
for (int i = 0; i < len; i++) {
|
||||||
byte b = bb.Get(i + startPos_1);
|
byte b = bb.Get(i + startPos_1);
|
||||||
@@ -207,6 +219,7 @@ namespace Google.FlatBuffers
|
|||||||
return b - key[i];
|
return b - key[i];
|
||||||
}
|
}
|
||||||
return len_1 - len_2;
|
return len_1 - len_2;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user