Commit d0321df8 authored by Christopher Cifra's avatar Christopher Cifra Committed by Wouter van Oortmerssen

C# support for directly reading and writting to memory other than byte[]. For…

C# support for directly reading and writting to memory other than byte[].  For example, ByteBuffer can be initialized with a custom allocator which uses shared memory / memory mapped files. (#4886)

Public access to the backing buffer uses Span<T> instead of ArraySegment<T>.

Writing to the buffer now supports Span<T> in addition to T[].

To maintain backwards compatibility ENABLE_SPAN_T must be defined.
parent e1f48ad3
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
// There are 2 #defines that have an impact on performance of this ByteBuffer implementation // There are 3 #defines that have an impact on performance / features of this ByteBuffer implementation
// //
// UNSAFE_BYTEBUFFER // UNSAFE_BYTEBUFFER
// This will use unsafe code to manipulate the underlying byte array. This // This will use unsafe code to manipulate the underlying byte array. This
...@@ -24,6 +24,12 @@ ...@@ -24,6 +24,12 @@
// This will disable the bounds check asserts to the byte array. This can // This will disable the bounds check asserts to the byte array. This can
// yield a small performance gain in normal code.. // yield a small performance gain in normal code..
// //
// ENABLE_SPAN_T
// This will enable reading and writing blocks of memory with a Span<T> instead if just
// T[]. You can also enable writing directly to shared memory or other types of memory
// by providing a custom implementation of ByteBufferAllocator.
// ENABLE_SPAN_T also requires UNSAFE_BYTEBUFFER to be defined
//
// Using UNSAFE_BYTEBUFFER and BYTEBUFFER_NO_BOUNDS_CHECK together can yield a // Using UNSAFE_BYTEBUFFER and BYTEBUFFER_NO_BOUNDS_CHECK together can yield a
// performance gain of ~15% for some operations, however doing so is potentially // performance gain of ~15% for some operations, however doing so is potentially
// dangerous. Do so at your own risk! // dangerous. Do so at your own risk!
...@@ -32,19 +38,132 @@ ...@@ -32,19 +38,132 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text; using System.Text;
#if ENABLE_SPAN_T && !UNSAFE_BYTEBUFFER
#error ENABLE_SPAN_T requires UNSAFE_BYTEBUFFER to also be defined
#endif
namespace FlatBuffers namespace FlatBuffers
{ {
public abstract class ByteBufferAllocator : IDisposable
{
#if UNSAFE_BYTEBUFFER
public unsafe byte* Buffer
{
get;
protected set;
}
#else
public byte[] Buffer
{
get;
protected set;
}
#endif
public int Length
{
get;
protected set;
}
public abstract void Dispose();
public abstract void GrowFront(int newSize);
#if !ENABLE_SPAN_T
public abstract byte[] ByteArray { get; }
#endif
}
public class ByteArrayAllocator : ByteBufferAllocator
{
private byte[] _buffer;
public ByteArrayAllocator(byte[] buffer)
{
_buffer = buffer;
InitPointer();
}
public override void GrowFront(int newSize)
{
if ((Length & 0xC0000000) != 0)
throw new Exception(
"ByteBuffer: cannot grow buffer beyond 2 gigabytes.");
if (newSize < Length)
throw new Exception("ByteBuffer: cannot truncate buffer.");
byte[] newBuffer = new byte[newSize];
System.Buffer.BlockCopy(_buffer, 0, newBuffer, newSize - Length, Length);
_buffer = newBuffer;
InitPointer();
}
public override void Dispose()
{
GC.SuppressFinalize(this);
#if UNSAFE_BYTEBUFFER
if (_handle.IsAllocated)
{
_handle.Free();
}
#endif
}
#if !ENABLE_SPAN_T
public override byte[] ByteArray => _buffer;
#endif
#if UNSAFE_BYTEBUFFER
private GCHandle _handle;
~ByteArrayAllocator()
{
if (_handle.IsAllocated)
{
_handle.Free();
}
}
#endif
private void InitPointer()
{
Length = _buffer.Length;
#if UNSAFE_BYTEBUFFER
if (_handle.IsAllocated)
{
_handle.Free();
}
_handle = GCHandle.Alloc(_buffer, GCHandleType.Pinned);
unsafe
{
Buffer = (byte*)_handle.AddrOfPinnedObject().ToPointer();
}
#else
Buffer = _buffer;
#endif
}
}
/// <summary> /// <summary>
/// Class to mimic Java's ByteBuffer which is used heavily in Flatbuffers. /// Class to mimic Java's ByteBuffer which is used heavily in Flatbuffers.
/// </summary> /// </summary>
public class ByteBuffer public class ByteBuffer : IDisposable
{ {
protected byte[] _buffer; private ByteBufferAllocator _buffer;
private int _pos; // Must track start of the buffer. private int _pos; // Must track start of the buffer.
public int Length { get { return _buffer.Length; } } public ByteBuffer(ByteBufferAllocator allocator, int position)
{
_buffer = allocator;
_pos = position;
}
public ByteBuffer(int size) : this(new byte[size]) { } public ByteBuffer(int size) : this(new byte[size]) { }
...@@ -52,15 +171,25 @@ namespace FlatBuffers ...@@ -52,15 +171,25 @@ namespace FlatBuffers
public ByteBuffer(byte[] buffer, int pos) public ByteBuffer(byte[] buffer, int pos)
{ {
_buffer = buffer; _buffer = new ByteArrayAllocator(buffer);
_pos = pos; _pos = pos;
} }
public void Dispose()
{
if (_buffer != null)
{
_buffer.Dispose();
}
}
public int Position { public int Position {
get { return _pos; } get { return _pos; }
set { _pos = value; } set { _pos = value; }
} }
public int Length { get { return _buffer.Length; } }
public void Reset() public void Reset()
{ {
_pos = 0; _pos = 0;
...@@ -77,17 +206,7 @@ namespace FlatBuffers ...@@ -77,17 +206,7 @@ namespace FlatBuffers
// the end of the new buffer. // the end of the new buffer.
public void GrowFront(int newSize) public void GrowFront(int newSize)
{ {
if ((Length & 0xC0000000) != 0) _buffer.GrowFront(newSize);
throw new Exception(
"ByteBuffer: cannot grow buffer beyond 2 gigabytes.");
if (newSize < Length)
throw new Exception("ByteBuffer: cannot truncate buffer.");
byte[] newBuffer = new byte[newSize];
Buffer.BlockCopy(_buffer, 0, newBuffer, newSize - Length,
Length);
_buffer = newBuffer;
} }
public byte[] ToArray(int pos, int len) public byte[] ToArray(int pos, int len)
...@@ -145,16 +264,38 @@ namespace FlatBuffers ...@@ -145,16 +264,38 @@ namespace FlatBuffers
return SizeOf<T>() * x.Length; return SizeOf<T>() * x.Length;
} }
#if ENABLE_SPAN_T
public static int ArraySize<T>(Span<T> x)
{
return SizeOf<T>() * x.Length;
}
#endif
// Get a portion of the buffer casted into an array of type T, given // Get a portion of the buffer casted into an array of type T, given
// the buffer position and length. // the buffer position and length.
#if ENABLE_SPAN_T
public T[] ToArray<T>(int pos, int len) public T[] ToArray<T>(int pos, int len)
where T: struct where T: struct
{
unsafe
{
AssertOffsetAndLength(pos, len);
T[] arr = new T[len];
var typed = MemoryMarshal.Cast<byte, T>(new Span<byte>(_buffer.Buffer + pos, _buffer.Length));
typed.Slice(0, arr.Length).CopyTo(arr);
return arr;
}
}
#else
public T[] ToArray<T>(int pos, int len)
where T : struct
{ {
AssertOffsetAndLength(pos, len); AssertOffsetAndLength(pos, len);
T[] arr = new T[len]; T[] arr = new T[len];
Buffer.BlockCopy(_buffer, pos, arr, 0, ArraySize(arr)); Buffer.BlockCopy(_buffer.ByteArray, pos, arr, 0, ArraySize(arr));
return arr; return arr;
} }
#endif
public byte[] ToSizedArray() public byte[] ToSizedArray()
{ {
...@@ -166,15 +307,25 @@ namespace FlatBuffers ...@@ -166,15 +307,25 @@ namespace FlatBuffers
return ToArray<byte>(0, Length); return ToArray<byte>(0, Length);
} }
#if ENABLE_SPAN_T
public unsafe Span<byte> ToSpan(int pos, int len)
{
return new Span<byte>(_buffer.Buffer, _buffer.Length).Slice(pos, len);
}
#else
public ArraySegment<byte> ToArraySegment(int pos, int len) public ArraySegment<byte> ToArraySegment(int pos, int len)
{ {
return new ArraySegment<byte>(_buffer, pos, len); return new ArraySegment<byte>(_buffer.ByteArray, pos, len);
} }
#endif
#if !ENABLE_SPAN_T
public MemoryStream ToMemoryStream(int pos, int len) public MemoryStream ToMemoryStream(int pos, int len)
{ {
return new MemoryStream(_buffer, pos, len); return new MemoryStream(_buffer.ByteArray, pos, len);
} }
#endif
#if !UNSAFE_BYTEBUFFER #if !UNSAFE_BYTEBUFFER
// Pre-allocated helper arrays for convertion. // Pre-allocated helper arrays for convertion.
...@@ -217,14 +368,14 @@ namespace FlatBuffers ...@@ -217,14 +368,14 @@ namespace FlatBuffers
{ {
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
_buffer[offset + i] = (byte)(data >> i * 8); _buffer.Buffer[offset + i] = (byte)(data >> i * 8);
} }
} }
else else
{ {
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
_buffer[offset + count - 1 - i] = (byte)(data >> i * 8); _buffer.Buffer[offset + count - 1 - i] = (byte)(data >> i * 8);
} }
} }
} }
...@@ -237,14 +388,14 @@ namespace FlatBuffers ...@@ -237,14 +388,14 @@ namespace FlatBuffers
{ {
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
r |= (ulong)_buffer[offset + i] << i * 8; r |= (ulong)_buffer.Buffer[offset + i] << i * 8;
} }
} }
else else
{ {
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
r |= (ulong)_buffer[offset + count - 1 - i] << i * 8; r |= (ulong)_buffer.Buffer[offset + count - 1 - i] << i * 8;
} }
} }
return r; return r;
...@@ -253,30 +404,57 @@ namespace FlatBuffers ...@@ -253,30 +404,57 @@ namespace FlatBuffers
private void AssertOffsetAndLength(int offset, int length) private void AssertOffsetAndLength(int offset, int length)
{ {
#if !BYTEBUFFER_NO_BOUNDS_CHECK #if !BYTEBUFFER_NO_BOUNDS_CHECK
if (offset < 0 || if (offset < 0 ||
offset > _buffer.Length - length) offset > _buffer.Length - length)
throw new ArgumentOutOfRangeException(); throw new ArgumentOutOfRangeException();
#endif #endif
}
#if UNSAFE_BYTEBUFFER
public unsafe void PutSbyte(int offset, sbyte value)
{
AssertOffsetAndLength(offset, sizeof(sbyte));
_buffer.Buffer[offset] = (byte)value;
}
public unsafe void PutByte(int offset, byte value)
{
AssertOffsetAndLength(offset, sizeof(byte));
_buffer.Buffer[offset] = value;
} }
public unsafe void PutByte(int offset, byte value, int count)
{
AssertOffsetAndLength(offset, sizeof(byte) * count);
for (var i = 0; i < count; ++i)
_buffer.Buffer[offset + i] = value;
}
// this method exists in order to conform with Java ByteBuffer standards
public void Put(int offset, byte value)
{
PutByte(offset, value);
}
#else
public void PutSbyte(int offset, sbyte value) public void PutSbyte(int offset, sbyte value)
{ {
AssertOffsetAndLength(offset, sizeof(sbyte)); AssertOffsetAndLength(offset, sizeof(sbyte));
_buffer[offset] = (byte)value; _buffer.Buffer[offset] = (byte)value;
} }
public void PutByte(int offset, byte value) public void PutByte(int offset, byte value)
{ {
AssertOffsetAndLength(offset, sizeof(byte)); AssertOffsetAndLength(offset, sizeof(byte));
_buffer[offset] = value; _buffer.Buffer[offset] = value;
} }
public void PutByte(int offset, byte value, int count) public void PutByte(int offset, byte value, int count)
{ {
AssertOffsetAndLength(offset, sizeof(byte) * count); AssertOffsetAndLength(offset, sizeof(byte) * count);
for (var i = 0; i < count; ++i) for (var i = 0; i < count; ++i)
_buffer[offset + i] = value; _buffer.Buffer[offset + i] = value;
} }
// this method exists in order to conform with Java ByteBuffer standards // this method exists in order to conform with Java ByteBuffer standards
...@@ -284,13 +462,25 @@ namespace FlatBuffers ...@@ -284,13 +462,25 @@ namespace FlatBuffers
{ {
PutByte(offset, value); PutByte(offset, value);
} }
#endif
#if ENABLE_SPAN_T
public unsafe void PutStringUTF8(int offset, string value)
{
AssertOffsetAndLength(offset, value.Length);
fixed (char* s = value)
{
Encoding.UTF8.GetBytes(s, value.Length, _buffer.Buffer + offset, Length - offset);
}
}
#else
public void PutStringUTF8(int offset, string value) public void PutStringUTF8(int offset, string value)
{ {
AssertOffsetAndLength(offset, value.Length); AssertOffsetAndLength(offset, value.Length);
Encoding.UTF8.GetBytes(value, 0, value.Length, Encoding.UTF8.GetBytes(value, 0, value.Length,
_buffer, offset); _buffer.ByteArray, offset);
} }
#endif
#if UNSAFE_BYTEBUFFER #if UNSAFE_BYTEBUFFER
// Unsafe but more efficient versions of Put*. // Unsafe but more efficient versions of Put*.
...@@ -302,13 +492,11 @@ namespace FlatBuffers ...@@ -302,13 +492,11 @@ namespace FlatBuffers
public unsafe void PutUshort(int offset, ushort value) public unsafe void PutUshort(int offset, ushort value)
{ {
AssertOffsetAndLength(offset, sizeof(ushort)); AssertOffsetAndLength(offset, sizeof(ushort));
fixed (byte* ptr = _buffer) byte* ptr = _buffer.Buffer;
{
*(ushort*)(ptr + offset) = BitConverter.IsLittleEndian *(ushort*)(ptr + offset) = BitConverter.IsLittleEndian
? value ? value
: ReverseBytes(value); : ReverseBytes(value);
} }
}
public void PutInt(int offset, int value) public void PutInt(int offset, int value)
{ {
...@@ -318,13 +506,11 @@ namespace FlatBuffers ...@@ -318,13 +506,11 @@ namespace FlatBuffers
public unsafe void PutUint(int offset, uint value) public unsafe void PutUint(int offset, uint value)
{ {
AssertOffsetAndLength(offset, sizeof(uint)); AssertOffsetAndLength(offset, sizeof(uint));
fixed (byte* ptr = _buffer) byte* ptr = _buffer.Buffer;
{
*(uint*)(ptr + offset) = BitConverter.IsLittleEndian *(uint*)(ptr + offset) = BitConverter.IsLittleEndian
? value ? value
: ReverseBytes(value); : ReverseBytes(value);
} }
}
public unsafe void PutLong(int offset, long value) public unsafe void PutLong(int offset, long value)
{ {
...@@ -334,19 +520,16 @@ namespace FlatBuffers ...@@ -334,19 +520,16 @@ namespace FlatBuffers
public unsafe void PutUlong(int offset, ulong value) public unsafe void PutUlong(int offset, ulong value)
{ {
AssertOffsetAndLength(offset, sizeof(ulong)); AssertOffsetAndLength(offset, sizeof(ulong));
fixed (byte* ptr = _buffer) byte* ptr = _buffer.Buffer;
{
*(ulong*)(ptr + offset) = BitConverter.IsLittleEndian *(ulong*)(ptr + offset) = BitConverter.IsLittleEndian
? value ? value
: ReverseBytes(value); : ReverseBytes(value);
} }
}
public unsafe void PutFloat(int offset, float value) public unsafe void PutFloat(int offset, float value)
{ {
AssertOffsetAndLength(offset, sizeof(float)); AssertOffsetAndLength(offset, sizeof(float));
fixed (byte* ptr = _buffer) byte* ptr = _buffer.Buffer;
{
if (BitConverter.IsLittleEndian) if (BitConverter.IsLittleEndian)
{ {
*(float*)(ptr + offset) = value; *(float*)(ptr + offset) = value;
...@@ -356,13 +539,11 @@ namespace FlatBuffers ...@@ -356,13 +539,11 @@ namespace FlatBuffers
*(uint*)(ptr + offset) = ReverseBytes(*(uint*)(&value)); *(uint*)(ptr + offset) = ReverseBytes(*(uint*)(&value));
} }
} }
}
public unsafe void PutDouble(int offset, double value) public unsafe void PutDouble(int offset, double value)
{ {
AssertOffsetAndLength(offset, sizeof(double)); AssertOffsetAndLength(offset, sizeof(double));
fixed (byte* ptr = _buffer) byte* ptr = _buffer.Buffer;
{
if (BitConverter.IsLittleEndian) if (BitConverter.IsLittleEndian)
{ {
*(double*)(ptr + offset) = value; *(double*)(ptr + offset) = value;
...@@ -373,7 +554,6 @@ namespace FlatBuffers ...@@ -373,7 +554,6 @@ namespace FlatBuffers
*(ulong*)(ptr + offset) = ReverseBytes(*(ulong*)(ptr + offset)); *(ulong*)(ptr + offset) = ReverseBytes(*(ulong*)(ptr + offset));
} }
} }
}
#else // !UNSAFE_BYTEBUFFER #else // !UNSAFE_BYTEBUFFER
// Slower versions of Put* for when unsafe code is not allowed. // Slower versions of Put* for when unsafe code is not allowed.
public void PutShort(int offset, short value) public void PutShort(int offset, short value)
...@@ -430,74 +610,43 @@ namespace FlatBuffers ...@@ -430,74 +610,43 @@ namespace FlatBuffers
#endif // UNSAFE_BYTEBUFFER #endif // UNSAFE_BYTEBUFFER
/// <summary> #if UNSAFE_BYTEBUFFER
/// Copies an array of type T into this buffer, ending at the given public unsafe sbyte GetSbyte(int index)
/// offset into this buffer. The starting offset is calculated based on the length
/// of the array and is the value returned.
/// </summary>
/// <typeparam name="T">The type of the input data (must be a struct)</typeparam>
/// <param name="offset">The offset into this buffer where the copy will end</param>
/// <param name="x">The array to copy data from</param>
/// <returns>The 'start' location of this buffer now, after the copy completed</returns>
public int Put<T>(int offset, T[] x)
where T : struct
{
if(x == null)
{
throw new ArgumentNullException("Cannot put a null array");
}
if(x.Length == 0)
{
throw new ArgumentException("Cannot put an empty array");
}
if(!IsSupportedType<T>())
{ {
throw new ArgumentException("Cannot put an array of type " AssertOffsetAndLength(index, sizeof(sbyte));
+ typeof(T) + " into this buffer"); return (sbyte)_buffer.Buffer[index];
} }
if (BitConverter.IsLittleEndian) public unsafe byte Get(int index)
{
int numBytes = ByteBuffer.ArraySize(x);
offset -= numBytes;
AssertOffsetAndLength(offset, numBytes);
// if we are LE, just do a block copy
Buffer.BlockCopy(x, 0, _buffer, offset, numBytes);
}
else
{ {
throw new NotImplementedException("Big Endian Support not implemented yet " + AssertOffsetAndLength(index, sizeof(byte));
"for putting typed arrays"); return _buffer.Buffer[index];
// if we are BE, we have to swap each element by itself
//for(int i = x.Length - 1; i >= 0; i--)
//{
// todo: low priority, but need to genericize the Put<T>() functions
//}
}
return offset;
} }
#else
public sbyte GetSbyte(int index) public sbyte GetSbyte(int index)
{ {
AssertOffsetAndLength(index, sizeof(sbyte)); AssertOffsetAndLength(index, sizeof(sbyte));
return (sbyte)_buffer[index]; return (sbyte)_buffer.Buffer[index];
} }
public byte Get(int index) public byte Get(int index)
{ {
AssertOffsetAndLength(index, sizeof(byte)); AssertOffsetAndLength(index, sizeof(byte));
return _buffer[index]; return _buffer.Buffer[index];
} }
#endif
#if ENABLE_SPAN_T
public unsafe string GetStringUTF8(int startPos, int len)
{
return Encoding.UTF8.GetString(_buffer.Buffer + startPos, len);
}
#else
public string GetStringUTF8(int startPos, int len) public string GetStringUTF8(int startPos, int len)
{ {
return Encoding.UTF8.GetString(_buffer, startPos, len); return Encoding.UTF8.GetString(_buffer.ByteArray, startPos, len);
} }
#endif
#if UNSAFE_BYTEBUFFER #if UNSAFE_BYTEBUFFER
// Unsafe but more efficient versions of Get*. // Unsafe but more efficient versions of Get*.
...@@ -509,7 +658,7 @@ namespace FlatBuffers ...@@ -509,7 +658,7 @@ namespace FlatBuffers
public unsafe ushort GetUshort(int offset) public unsafe ushort GetUshort(int offset)
{ {
AssertOffsetAndLength(offset, sizeof(ushort)); AssertOffsetAndLength(offset, sizeof(ushort));
fixed (byte* ptr = _buffer) byte* ptr = _buffer.Buffer;
{ {
return BitConverter.IsLittleEndian return BitConverter.IsLittleEndian
? *(ushort*)(ptr + offset) ? *(ushort*)(ptr + offset)
...@@ -525,7 +674,7 @@ namespace FlatBuffers ...@@ -525,7 +674,7 @@ namespace FlatBuffers
public unsafe uint GetUint(int offset) public unsafe uint GetUint(int offset)
{ {
AssertOffsetAndLength(offset, sizeof(uint)); AssertOffsetAndLength(offset, sizeof(uint));
fixed (byte* ptr = _buffer) byte* ptr = _buffer.Buffer;
{ {
return BitConverter.IsLittleEndian return BitConverter.IsLittleEndian
? *(uint*)(ptr + offset) ? *(uint*)(ptr + offset)
...@@ -541,7 +690,7 @@ namespace FlatBuffers ...@@ -541,7 +690,7 @@ namespace FlatBuffers
public unsafe ulong GetUlong(int offset) public unsafe ulong GetUlong(int offset)
{ {
AssertOffsetAndLength(offset, sizeof(ulong)); AssertOffsetAndLength(offset, sizeof(ulong));
fixed (byte* ptr = _buffer) byte* ptr = _buffer.Buffer;
{ {
return BitConverter.IsLittleEndian return BitConverter.IsLittleEndian
? *(ulong*)(ptr + offset) ? *(ulong*)(ptr + offset)
...@@ -552,7 +701,7 @@ namespace FlatBuffers ...@@ -552,7 +701,7 @@ namespace FlatBuffers
public unsafe float GetFloat(int offset) public unsafe float GetFloat(int offset)
{ {
AssertOffsetAndLength(offset, sizeof(float)); AssertOffsetAndLength(offset, sizeof(float));
fixed (byte* ptr = _buffer) byte* ptr = _buffer.Buffer;
{ {
if (BitConverter.IsLittleEndian) if (BitConverter.IsLittleEndian)
{ {
...@@ -569,7 +718,7 @@ namespace FlatBuffers ...@@ -569,7 +718,7 @@ namespace FlatBuffers
public unsafe double GetDouble(int offset) public unsafe double GetDouble(int offset)
{ {
AssertOffsetAndLength(offset, sizeof(double)); AssertOffsetAndLength(offset, sizeof(double));
fixed (byte* ptr = _buffer) byte* ptr = _buffer.Buffer;
{ {
if (BitConverter.IsLittleEndian) if (BitConverter.IsLittleEndian)
{ {
...@@ -631,5 +780,98 @@ namespace FlatBuffers ...@@ -631,5 +780,98 @@ namespace FlatBuffers
return doublehelper[0]; return doublehelper[0];
} }
#endif // UNSAFE_BYTEBUFFER #endif // UNSAFE_BYTEBUFFER
/// <summary>
/// Copies an array of type T into this buffer, ending at the given
/// offset into this buffer. The starting offset is calculated based on the length
/// of the array and is the value returned.
/// </summary>
/// <typeparam name="T">The type of the input data (must be a struct)</typeparam>
/// <param name="offset">The offset into this buffer where the copy will end</param>
/// <param name="x">The array to copy data from</param>
/// <returns>The 'start' location of this buffer now, after the copy completed</returns>
public int Put<T>(int offset, T[] x)
where T : struct
{
if (x == null)
{
throw new ArgumentNullException("Cannot put a null array");
}
if (x.Length == 0)
{
throw new ArgumentException("Cannot put an empty array");
}
if (!IsSupportedType<T>())
{
throw new ArgumentException("Cannot put an array of type "
+ typeof(T) + " into this buffer");
}
if (BitConverter.IsLittleEndian)
{
int numBytes = ByteBuffer.ArraySize(x);
offset -= numBytes;
AssertOffsetAndLength(offset, numBytes);
// if we are LE, just do a block copy
#if ENABLE_SPAN_T
unsafe
{
MemoryMarshal.Cast<T, byte>(x).CopyTo(new Span<byte>(_buffer.Buffer, _buffer.Length).Slice(offset, numBytes));
}
#else
Buffer.BlockCopy(x, 0, _buffer.ByteArray, offset, numBytes);
#endif
}
else
{
throw new NotImplementedException("Big Endian Support not implemented yet " +
"for putting typed arrays");
// if we are BE, we have to swap each element by itself
//for(int i = x.Length - 1; i >= 0; i--)
//{
// todo: low priority, but need to genericize the Put<T>() functions
//}
}
return offset;
}
#if ENABLE_SPAN_T
public unsafe int Put<T>(int offset, Span<T> x)
where T : struct
{
if (x.Length == 0)
{
throw new ArgumentException("Cannot put an empty array");
}
if (!IsSupportedType<T>())
{
throw new ArgumentException("Cannot put an array of type "
+ typeof(T) + " into this buffer");
}
if (BitConverter.IsLittleEndian)
{
int numBytes = ByteBuffer.ArraySize(x);
offset -= numBytes;
AssertOffsetAndLength(offset, numBytes);
// if we are LE, just do a block copy
MemoryMarshal.Cast<T, byte>(x).CopyTo(new Span<byte>(_buffer.Buffer, _buffer.Length).Slice(offset, numBytes));
}
else
{
throw new NotImplementedException("Big Endian Support not implemented yet " +
"for putting typed arrays");
// if we are BE, we have to swap each element by itself
//for(int i = x.Length - 1; i >= 0; i--)
//{
// todo: low priority, but need to genericize the Put<T>() functions
//}
}
return offset;
}
#endif
} }
} }
...@@ -62,6 +62,17 @@ namespace FlatBuffers ...@@ -62,6 +62,17 @@ namespace FlatBuffers
_bb = new ByteBuffer(initialSize); _bb = new ByteBuffer(initialSize);
} }
/// <summary>
/// Create a FlatBufferBuilder backed by the pased in ByteBuffer
/// </summary>
/// <param name="buffer">The ByteBuffer to write to</param>
public FlatBufferBuilder(ByteBuffer buffer)
{
_bb = buffer;
_space = buffer.Length;
buffer.Reset();
}
/// <summary> /// <summary>
/// Reset the FlatBufferBuilder by purging all data that it holds. /// Reset the FlatBufferBuilder by purging all data that it holds.
/// </summary> /// </summary>
...@@ -191,6 +202,20 @@ namespace FlatBuffers ...@@ -191,6 +202,20 @@ namespace FlatBuffers
_space = _bb.Put(_space, x); _space = _bb.Put(_space, x);
} }
#if ENABLE_SPAN_T
/// <summary>
/// Puts a span of type T into this builder at the
/// current offset
/// </summary>
/// <typeparam name="T">The type of the input data </typeparam>
/// <param name="x">The span to copy data from</param>
public void Put<T>(Span<T> x)
where T : struct
{
_space = _bb.Put(_space, x);
}
#endif
public void PutDouble(double x) public void PutDouble(double x)
{ {
_bb.PutDouble(_space -= sizeof(double), x); _bb.PutDouble(_space -= sizeof(double), x);
...@@ -288,6 +313,28 @@ namespace FlatBuffers ...@@ -288,6 +313,28 @@ namespace FlatBuffers
Put(x); Put(x);
} }
#if ENABLE_SPAN_T
/// <summary>
/// Add a span of type T to the buffer (aligns the data and grows if necessary).
/// </summary>
/// <typeparam name="T">The type of the input data</typeparam>
/// <param name="x">The span to copy data from</param>
public void Add<T>(Span<T> x)
where T : struct
{
if (!ByteBuffer.IsSupportedType<T>())
{
throw new ArgumentException("Cannot add this Type array to the builder");
}
int size = ByteBuffer.SizeOf<T>();
// Need to prep on size (for data alignment) and then we pass the
// rest of the length (minus 1) as additional bytes
Prep(size, size * (x.Length - 1));
Put(x);
}
#endif
/// <summary> /// <summary>
/// Add a `double` to the buffer (aligns the data and grows if necessary). /// Add a `double` to the buffer (aligns the data and grows if necessary).
/// </summary> /// </summary>
...@@ -511,6 +558,27 @@ namespace FlatBuffers ...@@ -511,6 +558,27 @@ namespace FlatBuffers
return new StringOffset(EndVector().Value); return new StringOffset(EndVector().Value);
} }
#if ENABLE_SPAN_T
/// <summary>
/// Creates a string in the buffer from a Span containing
/// a UTF8 string.
/// </summary>
/// <param name="chars">the UTF8 string to add to the buffer</param>
/// <returns>
/// The offset in the buffer where the encoded string starts.
/// </returns>
public StringOffset CreateUTF8String(Span<byte> chars)
{
NotNested();
AddByte(0);
var utf8StringLen = chars.Length;
StartVector(1, utf8StringLen, 1);
_space = _bb.Put(_space, chars);
return new StringOffset(EndVector().Value);
}
#endif
/// @cond FLATBUFFERS_INTERNAL /// @cond FLATBUFFERS_INTERNAL
// Structs are stored inline, so nothing additional is being added. // Structs are stored inline, so nothing additional is being added.
// `d` is always 0. // `d` is always 0.
......
...@@ -10,4 +10,7 @@ ...@@ -10,4 +10,7 @@
<PackageLicenseUrl>https://github.com/google/flatbuffers/blob/master/LICENSE.txt</PackageLicenseUrl> <PackageLicenseUrl>https://github.com/google/flatbuffers/blob/master/LICENSE.txt</PackageLicenseUrl>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Memory" Version="4.5.1" />
</ItemGroup>
</Project> </Project>
\ No newline at end of file
...@@ -78,6 +78,23 @@ namespace FlatBuffers ...@@ -78,6 +78,23 @@ namespace FlatBuffers
return offset + bb.GetInt(offset) + sizeof(int); // data starts after the length return offset + bb.GetInt(offset) + sizeof(int); // data starts after the length
} }
#if ENABLE_SPAN_T
// Get the data of a vector whoses offset is stored at "offset" in this object as an
// Spant&lt;byte&gt;. If the vector is not present in the ByteBuffer,
// then an empty span will be returned.
public Span<byte> __vector_as_span(int offset)
{
var o = this.__offset(offset);
if (0 == o)
{
return new Span<byte>();
}
var pos = this.__vector(o);
var len = this.__vector_len(o);
return bb.ToSpan(pos, len);
}
#else
// Get the data of a vector whoses offset is stored at "offset" in this object as an // Get the data of a vector whoses offset is stored at "offset" in this object as an
// ArraySegment&lt;byte&gt;. If the vector is not present in the ByteBuffer, // ArraySegment&lt;byte&gt;. If the vector is not present in the ByteBuffer,
// then a null value will be returned. // then a null value will be returned.
...@@ -93,6 +110,7 @@ namespace FlatBuffers ...@@ -93,6 +110,7 @@ namespace FlatBuffers
var len = this.__vector_len(o); var len = this.__vector_len(o);
return bb.ToArraySegment(pos, len); return bb.ToArraySegment(pos, len);
} }
#endif
// Get the data of a vector whoses offset is stored at "offset" in this object as an // Get the data of a vector whoses offset is stored at "offset" in this object as an
// T[]. If the vector is not present in the ByteBuffer, then a null value will be // T[]. If the vector is not present in the ByteBuffer, then a null value will be
......
...@@ -1113,12 +1113,21 @@ class GeneralGenerator : public BaseGenerator { ...@@ -1113,12 +1113,21 @@ class GeneralGenerator : public BaseGenerator {
code += "); }\n"; code += "); }\n";
break; break;
case IDLOptions::kCSharp: case IDLOptions::kCSharp:
code += "#if ENABLE_SPAN_T\n";
code += " public Span<byte> Get";
code += MakeCamel(field.name, lang_.first_camel_upper);
code += "Bytes() { return ";
code += lang_.accessor_prefix + "__vector_as_span(";
code += NumToString(field.value.offset);
code += "); }\n";
code += "#else\n";
code += " public ArraySegment<byte>? Get"; code += " public ArraySegment<byte>? Get";
code += MakeCamel(field.name, lang_.first_camel_upper); code += MakeCamel(field.name, lang_.first_camel_upper);
code += "Bytes() { return "; code += "Bytes() { return ";
code += lang_.accessor_prefix + "__vector_as_arraysegment("; code += lang_.accessor_prefix + "__vector_as_arraysegment(";
code += NumToString(field.value.offset); code += NumToString(field.value.offset);
code += "); }\n"; code += "); }\n";
code += "#endif\n";
// For direct blockcopying the data into a typed array // For direct blockcopying the data into a typed array
code += " public "; code += " public ";
......
...@@ -110,14 +110,19 @@ namespace FlatBuffers.Test ...@@ -110,14 +110,19 @@ namespace FlatBuffers.Test
Monster.FinishMonsterBuffer(fbb, mon); Monster.FinishMonsterBuffer(fbb, mon);
} }
// Dump to output directory so we can inspect later, if needed // Dump to output directory so we can inspect later, if needed
#if ENABLE_SPAN_T
var data = fbb.DataBuffer.ToSizedArray();
string filename = @"Resources/monsterdata_cstest" + (sizePrefix ? "_sp" : "") + ".mon";
File.WriteAllBytes(filename, data);
#else
using (var ms = fbb.DataBuffer.ToMemoryStream(fbb.DataBuffer.Position, fbb.Offset)) using (var ms = fbb.DataBuffer.ToMemoryStream(fbb.DataBuffer.Position, fbb.Offset))
{ {
var data = ms.ToArray(); var data = ms.ToArray();
string filename = @"Resources/monsterdata_cstest" + (sizePrefix ? "_sp" : "") + ".mon"; string filename = @"Resources/monsterdata_cstest" + (sizePrefix ? "_sp" : "") + ".mon";
File.WriteAllBytes(filename, data); File.WriteAllBytes(filename, data);
} }
#endif
// Remove the size prefix if necessary for further testing // Remove the size prefix if necessary for further testing
ByteBuffer dataBuffer = fbb.DataBuffer; ByteBuffer dataBuffer = fbb.DataBuffer;
...@@ -243,6 +248,19 @@ namespace FlatBuffers.Test ...@@ -243,6 +248,19 @@ namespace FlatBuffers.Test
Assert.AreEqual(false, monster.Testbool); Assert.AreEqual(false, monster.Testbool);
#if ENABLE_SPAN_T
var nameBytes = monster.GetNameBytes();
Assert.AreEqual("MyMonster", Encoding.UTF8.GetString(nameBytes.ToArray(), 0, nameBytes.Length));
if (0 == monster.TestarrayofboolsLength)
{
Assert.IsFalse(monster.GetTestarrayofboolsBytes().Length != 0);
}
else
{
Assert.IsTrue(monster.GetTestarrayofboolsBytes().Length == 0);
}
#else
var nameBytes = monster.GetNameBytes().Value; var nameBytes = monster.GetNameBytes().Value;
Assert.AreEqual("MyMonster", Encoding.UTF8.GetString(nameBytes.Array, nameBytes.Offset, nameBytes.Count)); Assert.AreEqual("MyMonster", Encoding.UTF8.GetString(nameBytes.Array, nameBytes.Offset, nameBytes.Count));
...@@ -254,6 +272,7 @@ namespace FlatBuffers.Test ...@@ -254,6 +272,7 @@ namespace FlatBuffers.Test
{ {
Assert.IsTrue(monster.GetTestarrayofboolsBytes().HasValue); Assert.IsTrue(monster.GetTestarrayofboolsBytes().HasValue);
} }
#endif
} }
[FlatBuffersTestMethod] [FlatBuffersTestMethod]
......
...@@ -25,11 +25,19 @@ public struct Monster : IFlatbufferObject ...@@ -25,11 +25,19 @@ public struct Monster : IFlatbufferObject
public short Hp { get { int o = __p.__offset(8); return o != 0 ? __p.bb.GetShort(o + __p.bb_pos) : (short)100; } } public short Hp { get { int o = __p.__offset(8); return o != 0 ? __p.bb.GetShort(o + __p.bb_pos) : (short)100; } }
public bool MutateHp(short hp) { int o = __p.__offset(8); if (o != 0) { __p.bb.PutShort(o + __p.bb_pos, hp); return true; } else { return false; } } public bool MutateHp(short hp) { int o = __p.__offset(8); if (o != 0) { __p.bb.PutShort(o + __p.bb_pos, hp); return true; } else { return false; } }
public string Name { get { int o = __p.__offset(10); return o != 0 ? __p.__string(o + __p.bb_pos) : null; } } public string Name { get { int o = __p.__offset(10); return o != 0 ? __p.__string(o + __p.bb_pos) : null; } }
#if ENABLE_SPAN_T
public Span<byte> GetNameBytes() { return __p.__vector_as_span(10); }
#else
public ArraySegment<byte>? GetNameBytes() { return __p.__vector_as_arraysegment(10); } public ArraySegment<byte>? GetNameBytes() { return __p.__vector_as_arraysegment(10); }
#endif
public byte[] GetNameArray() { return __p.__vector_as_array<byte>(10); } public byte[] GetNameArray() { return __p.__vector_as_array<byte>(10); }
public byte Inventory(int j) { int o = __p.__offset(14); return o != 0 ? __p.bb.Get(__p.__vector(o) + j * 1) : (byte)0; } public byte Inventory(int j) { int o = __p.__offset(14); return o != 0 ? __p.bb.Get(__p.__vector(o) + j * 1) : (byte)0; }
public int InventoryLength { get { int o = __p.__offset(14); return o != 0 ? __p.__vector_len(o) : 0; } } public int InventoryLength { get { int o = __p.__offset(14); return o != 0 ? __p.__vector_len(o) : 0; } }
#if ENABLE_SPAN_T
public Span<byte> GetInventoryBytes() { return __p.__vector_as_span(14); }
#else
public ArraySegment<byte>? GetInventoryBytes() { return __p.__vector_as_arraysegment(14); } public ArraySegment<byte>? GetInventoryBytes() { return __p.__vector_as_arraysegment(14); }
#endif
public byte[] GetInventoryArray() { return __p.__vector_as_array<byte>(14); } public byte[] GetInventoryArray() { return __p.__vector_as_array<byte>(14); }
public bool MutateInventory(int j, byte inventory) { int o = __p.__offset(14); if (o != 0) { __p.bb.Put(__p.__vector(o) + j * 1, inventory); return true; } else { return false; } } public bool MutateInventory(int j, byte inventory) { int o = __p.__offset(14); if (o != 0) { __p.bb.Put(__p.__vector(o) + j * 1, inventory); return true; } else { return false; } }
public Color Color { get { int o = __p.__offset(16); return o != 0 ? (Color)__p.bb.GetSbyte(o + __p.bb_pos) : Color.Blue; } } public Color Color { get { int o = __p.__offset(16); return o != 0 ? (Color)__p.bb.GetSbyte(o + __p.bb_pos) : Color.Blue; } }
...@@ -49,7 +57,11 @@ public struct Monster : IFlatbufferObject ...@@ -49,7 +57,11 @@ public struct Monster : IFlatbufferObject
public Monster? Enemy { get { int o = __p.__offset(28); return o != 0 ? (Monster?)(new Monster()).__assign(__p.__indirect(o + __p.bb_pos), __p.bb) : null; } } public Monster? Enemy { get { int o = __p.__offset(28); return o != 0 ? (Monster?)(new Monster()).__assign(__p.__indirect(o + __p.bb_pos), __p.bb) : null; } }
public byte Testnestedflatbuffer(int j) { int o = __p.__offset(30); return o != 0 ? __p.bb.Get(__p.__vector(o) + j * 1) : (byte)0; } public byte Testnestedflatbuffer(int j) { int o = __p.__offset(30); return o != 0 ? __p.bb.Get(__p.__vector(o) + j * 1) : (byte)0; }
public int TestnestedflatbufferLength { get { int o = __p.__offset(30); return o != 0 ? __p.__vector_len(o) : 0; } } public int TestnestedflatbufferLength { get { int o = __p.__offset(30); return o != 0 ? __p.__vector_len(o) : 0; } }
#if ENABLE_SPAN_T
public Span<byte> GetTestnestedflatbufferBytes() { return __p.__vector_as_span(30); }
#else
public ArraySegment<byte>? GetTestnestedflatbufferBytes() { return __p.__vector_as_arraysegment(30); } public ArraySegment<byte>? GetTestnestedflatbufferBytes() { return __p.__vector_as_arraysegment(30); }
#endif
public byte[] GetTestnestedflatbufferArray() { return __p.__vector_as_array<byte>(30); } public byte[] GetTestnestedflatbufferArray() { return __p.__vector_as_array<byte>(30); }
public Monster? GetTestnestedflatbufferAsMonster() { int o = __p.__offset(30); return o != 0 ? (Monster?)(new Monster()).__assign(__p.__indirect(__p.__vector(o)), __p.bb) : null; } public Monster? GetTestnestedflatbufferAsMonster() { int o = __p.__offset(30); return o != 0 ? (Monster?)(new Monster()).__assign(__p.__indirect(__p.__vector(o)), __p.bb) : null; }
public bool MutateTestnestedflatbuffer(int j, byte testnestedflatbuffer) { int o = __p.__offset(30); if (o != 0) { __p.bb.Put(__p.__vector(o) + j * 1, testnestedflatbuffer); return true; } else { return false; } } public bool MutateTestnestedflatbuffer(int j, byte testnestedflatbuffer) { int o = __p.__offset(30); if (o != 0) { __p.bb.Put(__p.__vector(o) + j * 1, testnestedflatbuffer); return true; } else { return false; } }
...@@ -74,7 +86,11 @@ public struct Monster : IFlatbufferObject ...@@ -74,7 +86,11 @@ public struct Monster : IFlatbufferObject
public bool MutateTesthashu64Fnv1a(ulong testhashu64_fnv1a) { int o = __p.__offset(50); if (o != 0) { __p.bb.PutUlong(o + __p.bb_pos, testhashu64_fnv1a); return true; } else { return false; } } public bool MutateTesthashu64Fnv1a(ulong testhashu64_fnv1a) { int o = __p.__offset(50); if (o != 0) { __p.bb.PutUlong(o + __p.bb_pos, testhashu64_fnv1a); return true; } else { return false; } }
public bool Testarrayofbools(int j) { int o = __p.__offset(52); return o != 0 ? 0!=__p.bb.Get(__p.__vector(o) + j * 1) : false; } public bool Testarrayofbools(int j) { int o = __p.__offset(52); return o != 0 ? 0!=__p.bb.Get(__p.__vector(o) + j * 1) : false; }
public int TestarrayofboolsLength { get { int o = __p.__offset(52); return o != 0 ? __p.__vector_len(o) : 0; } } public int TestarrayofboolsLength { get { int o = __p.__offset(52); return o != 0 ? __p.__vector_len(o) : 0; } }
#if ENABLE_SPAN_T
public Span<byte> GetTestarrayofboolsBytes() { return __p.__vector_as_span(52); }
#else
public ArraySegment<byte>? GetTestarrayofboolsBytes() { return __p.__vector_as_arraysegment(52); } public ArraySegment<byte>? GetTestarrayofboolsBytes() { return __p.__vector_as_arraysegment(52); }
#endif
public bool[] GetTestarrayofboolsArray() { return __p.__vector_as_array<bool>(52); } public bool[] GetTestarrayofboolsArray() { return __p.__vector_as_array<bool>(52); }
public bool MutateTestarrayofbools(int j, bool testarrayofbools) { int o = __p.__offset(52); if (o != 0) { __p.bb.Put(__p.__vector(o) + j * 1, (byte)(testarrayofbools ? 1 : 0)); return true; } else { return false; } } public bool MutateTestarrayofbools(int j, bool testarrayofbools) { int o = __p.__offset(52); if (o != 0) { __p.bb.Put(__p.__vector(o) + j * 1, (byte)(testarrayofbools ? 1 : 0)); return true; } else { return false; } }
public float Testf { get { int o = __p.__offset(54); return o != 0 ? __p.bb.GetFloat(o + __p.bb_pos) : (float)3.14159f; } } public float Testf { get { int o = __p.__offset(54); return o != 0 ? __p.bb.GetFloat(o + __p.bb_pos) : (float)3.14159f; } }
...@@ -89,19 +105,31 @@ public struct Monster : IFlatbufferObject ...@@ -89,19 +105,31 @@ public struct Monster : IFlatbufferObject
public int TestarrayofsortedstructLength { get { int o = __p.__offset(62); return o != 0 ? __p.__vector_len(o) : 0; } } public int TestarrayofsortedstructLength { get { int o = __p.__offset(62); return o != 0 ? __p.__vector_len(o) : 0; } }
public byte Flex(int j) { int o = __p.__offset(64); return o != 0 ? __p.bb.Get(__p.__vector(o) + j * 1) : (byte)0; } public byte Flex(int j) { int o = __p.__offset(64); return o != 0 ? __p.bb.Get(__p.__vector(o) + j * 1) : (byte)0; }
public int FlexLength { get { int o = __p.__offset(64); return o != 0 ? __p.__vector_len(o) : 0; } } public int FlexLength { get { int o = __p.__offset(64); return o != 0 ? __p.__vector_len(o) : 0; } }
#if ENABLE_SPAN_T
public Span<byte> GetFlexBytes() { return __p.__vector_as_span(64); }
#else
public ArraySegment<byte>? GetFlexBytes() { return __p.__vector_as_arraysegment(64); } public ArraySegment<byte>? GetFlexBytes() { return __p.__vector_as_arraysegment(64); }
#endif
public byte[] GetFlexArray() { return __p.__vector_as_array<byte>(64); } public byte[] GetFlexArray() { return __p.__vector_as_array<byte>(64); }
public bool MutateFlex(int j, byte flex) { int o = __p.__offset(64); if (o != 0) { __p.bb.Put(__p.__vector(o) + j * 1, flex); return true; } else { return false; } } public bool MutateFlex(int j, byte flex) { int o = __p.__offset(64); if (o != 0) { __p.bb.Put(__p.__vector(o) + j * 1, flex); return true; } else { return false; } }
public Test? Test5(int j) { int o = __p.__offset(66); return o != 0 ? (Test?)(new Test()).__assign(__p.__vector(o) + j * 4, __p.bb) : null; } public Test? Test5(int j) { int o = __p.__offset(66); return o != 0 ? (Test?)(new Test()).__assign(__p.__vector(o) + j * 4, __p.bb) : null; }
public int Test5Length { get { int o = __p.__offset(66); return o != 0 ? __p.__vector_len(o) : 0; } } public int Test5Length { get { int o = __p.__offset(66); return o != 0 ? __p.__vector_len(o) : 0; } }
public long VectorOfLongs(int j) { int o = __p.__offset(68); return o != 0 ? __p.bb.GetLong(__p.__vector(o) + j * 8) : (long)0; } public long VectorOfLongs(int j) { int o = __p.__offset(68); return o != 0 ? __p.bb.GetLong(__p.__vector(o) + j * 8) : (long)0; }
public int VectorOfLongsLength { get { int o = __p.__offset(68); return o != 0 ? __p.__vector_len(o) : 0; } } public int VectorOfLongsLength { get { int o = __p.__offset(68); return o != 0 ? __p.__vector_len(o) : 0; } }
#if ENABLE_SPAN_T
public Span<byte> GetVectorOfLongsBytes() { return __p.__vector_as_span(68); }
#else
public ArraySegment<byte>? GetVectorOfLongsBytes() { return __p.__vector_as_arraysegment(68); } public ArraySegment<byte>? GetVectorOfLongsBytes() { return __p.__vector_as_arraysegment(68); }
#endif
public long[] GetVectorOfLongsArray() { return __p.__vector_as_array<long>(68); } public long[] GetVectorOfLongsArray() { return __p.__vector_as_array<long>(68); }
public bool MutateVectorOfLongs(int j, long vector_of_longs) { int o = __p.__offset(68); if (o != 0) { __p.bb.PutLong(__p.__vector(o) + j * 8, vector_of_longs); return true; } else { return false; } } public bool MutateVectorOfLongs(int j, long vector_of_longs) { int o = __p.__offset(68); if (o != 0) { __p.bb.PutLong(__p.__vector(o) + j * 8, vector_of_longs); return true; } else { return false; } }
public double VectorOfDoubles(int j) { int o = __p.__offset(70); return o != 0 ? __p.bb.GetDouble(__p.__vector(o) + j * 8) : (double)0; } public double VectorOfDoubles(int j) { int o = __p.__offset(70); return o != 0 ? __p.bb.GetDouble(__p.__vector(o) + j * 8) : (double)0; }
public int VectorOfDoublesLength { get { int o = __p.__offset(70); return o != 0 ? __p.__vector_len(o) : 0; } } public int VectorOfDoublesLength { get { int o = __p.__offset(70); return o != 0 ? __p.__vector_len(o) : 0; } }
#if ENABLE_SPAN_T
public Span<byte> GetVectorOfDoublesBytes() { return __p.__vector_as_span(70); }
#else
public ArraySegment<byte>? GetVectorOfDoublesBytes() { return __p.__vector_as_arraysegment(70); } public ArraySegment<byte>? GetVectorOfDoublesBytes() { return __p.__vector_as_arraysegment(70); }
#endif
public double[] GetVectorOfDoublesArray() { return __p.__vector_as_array<double>(70); } public double[] GetVectorOfDoublesArray() { return __p.__vector_as_array<double>(70); }
public bool MutateVectorOfDoubles(int j, double vector_of_doubles) { int o = __p.__offset(70); if (o != 0) { __p.bb.PutDouble(__p.__vector(o) + j * 8, vector_of_doubles); return true; } else { return false; } } public bool MutateVectorOfDoubles(int j, double vector_of_doubles) { int o = __p.__offset(70); if (o != 0) { __p.bb.PutDouble(__p.__vector(o) + j * 8, vector_of_doubles); return true; } else { return false; } }
public MyGame.InParentNamespace? ParentNamespaceTest { get { int o = __p.__offset(72); return o != 0 ? (MyGame.InParentNamespace?)(new MyGame.InParentNamespace()).__assign(__p.__indirect(o + __p.bb_pos), __p.bb) : null; } } public MyGame.InParentNamespace? ParentNamespaceTest { get { int o = __p.__offset(72); return o != 0 ? (MyGame.InParentNamespace?)(new MyGame.InParentNamespace()).__assign(__p.__indirect(o + __p.bb_pos), __p.bb) : null; } }
...@@ -112,7 +140,11 @@ public struct Monster : IFlatbufferObject ...@@ -112,7 +140,11 @@ public struct Monster : IFlatbufferObject
public bool MutateSingleWeakReference(ulong single_weak_reference) { int o = __p.__offset(76); if (o != 0) { __p.bb.PutUlong(o + __p.bb_pos, single_weak_reference); return true; } else { return false; } } public bool MutateSingleWeakReference(ulong single_weak_reference) { int o = __p.__offset(76); if (o != 0) { __p.bb.PutUlong(o + __p.bb_pos, single_weak_reference); return true; } else { return false; } }
public ulong VectorOfWeakReferences(int j) { int o = __p.__offset(78); return o != 0 ? __p.bb.GetUlong(__p.__vector(o) + j * 8) : (ulong)0; } public ulong VectorOfWeakReferences(int j) { int o = __p.__offset(78); return o != 0 ? __p.bb.GetUlong(__p.__vector(o) + j * 8) : (ulong)0; }
public int VectorOfWeakReferencesLength { get { int o = __p.__offset(78); return o != 0 ? __p.__vector_len(o) : 0; } } public int VectorOfWeakReferencesLength { get { int o = __p.__offset(78); return o != 0 ? __p.__vector_len(o) : 0; } }
#if ENABLE_SPAN_T
public Span<byte> GetVectorOfWeakReferencesBytes() { return __p.__vector_as_span(78); }
#else
public ArraySegment<byte>? GetVectorOfWeakReferencesBytes() { return __p.__vector_as_arraysegment(78); } public ArraySegment<byte>? GetVectorOfWeakReferencesBytes() { return __p.__vector_as_arraysegment(78); }
#endif
public ulong[] GetVectorOfWeakReferencesArray() { return __p.__vector_as_array<ulong>(78); } public ulong[] GetVectorOfWeakReferencesArray() { return __p.__vector_as_array<ulong>(78); }
public bool MutateVectorOfWeakReferences(int j, ulong vector_of_weak_references) { int o = __p.__offset(78); if (o != 0) { __p.bb.PutUlong(__p.__vector(o) + j * 8, vector_of_weak_references); return true; } else { return false; } } public bool MutateVectorOfWeakReferences(int j, ulong vector_of_weak_references) { int o = __p.__offset(78); if (o != 0) { __p.bb.PutUlong(__p.__vector(o) + j * 8, vector_of_weak_references); return true; } else { return false; } }
public Referrable? VectorOfStrongReferrables(int j) { int o = __p.__offset(80); return o != 0 ? (Referrable?)(new Referrable()).__assign(__p.__indirect(__p.__vector(o) + j * 4), __p.bb) : null; } public Referrable? VectorOfStrongReferrables(int j) { int o = __p.__offset(80); return o != 0 ? (Referrable?)(new Referrable()).__assign(__p.__indirect(__p.__vector(o) + j * 4), __p.bb) : null; }
...@@ -122,14 +154,22 @@ public struct Monster : IFlatbufferObject ...@@ -122,14 +154,22 @@ public struct Monster : IFlatbufferObject
public bool MutateCoOwningReference(ulong co_owning_reference) { int o = __p.__offset(82); if (o != 0) { __p.bb.PutUlong(o + __p.bb_pos, co_owning_reference); return true; } else { return false; } } public bool MutateCoOwningReference(ulong co_owning_reference) { int o = __p.__offset(82); if (o != 0) { __p.bb.PutUlong(o + __p.bb_pos, co_owning_reference); return true; } else { return false; } }
public ulong VectorOfCoOwningReferences(int j) { int o = __p.__offset(84); return o != 0 ? __p.bb.GetUlong(__p.__vector(o) + j * 8) : (ulong)0; } public ulong VectorOfCoOwningReferences(int j) { int o = __p.__offset(84); return o != 0 ? __p.bb.GetUlong(__p.__vector(o) + j * 8) : (ulong)0; }
public int VectorOfCoOwningReferencesLength { get { int o = __p.__offset(84); return o != 0 ? __p.__vector_len(o) : 0; } } public int VectorOfCoOwningReferencesLength { get { int o = __p.__offset(84); return o != 0 ? __p.__vector_len(o) : 0; } }
#if ENABLE_SPAN_T
public Span<byte> GetVectorOfCoOwningReferencesBytes() { return __p.__vector_as_span(84); }
#else
public ArraySegment<byte>? GetVectorOfCoOwningReferencesBytes() { return __p.__vector_as_arraysegment(84); } public ArraySegment<byte>? GetVectorOfCoOwningReferencesBytes() { return __p.__vector_as_arraysegment(84); }
#endif
public ulong[] GetVectorOfCoOwningReferencesArray() { return __p.__vector_as_array<ulong>(84); } public ulong[] GetVectorOfCoOwningReferencesArray() { return __p.__vector_as_array<ulong>(84); }
public bool MutateVectorOfCoOwningReferences(int j, ulong vector_of_co_owning_references) { int o = __p.__offset(84); if (o != 0) { __p.bb.PutUlong(__p.__vector(o) + j * 8, vector_of_co_owning_references); return true; } else { return false; } } public bool MutateVectorOfCoOwningReferences(int j, ulong vector_of_co_owning_references) { int o = __p.__offset(84); if (o != 0) { __p.bb.PutUlong(__p.__vector(o) + j * 8, vector_of_co_owning_references); return true; } else { return false; } }
public ulong NonOwningReference { get { int o = __p.__offset(86); return o != 0 ? __p.bb.GetUlong(o + __p.bb_pos) : (ulong)0; } } public ulong NonOwningReference { get { int o = __p.__offset(86); return o != 0 ? __p.bb.GetUlong(o + __p.bb_pos) : (ulong)0; } }
public bool MutateNonOwningReference(ulong non_owning_reference) { int o = __p.__offset(86); if (o != 0) { __p.bb.PutUlong(o + __p.bb_pos, non_owning_reference); return true; } else { return false; } } public bool MutateNonOwningReference(ulong non_owning_reference) { int o = __p.__offset(86); if (o != 0) { __p.bb.PutUlong(o + __p.bb_pos, non_owning_reference); return true; } else { return false; } }
public ulong VectorOfNonOwningReferences(int j) { int o = __p.__offset(88); return o != 0 ? __p.bb.GetUlong(__p.__vector(o) + j * 8) : (ulong)0; } public ulong VectorOfNonOwningReferences(int j) { int o = __p.__offset(88); return o != 0 ? __p.bb.GetUlong(__p.__vector(o) + j * 8) : (ulong)0; }
public int VectorOfNonOwningReferencesLength { get { int o = __p.__offset(88); return o != 0 ? __p.__vector_len(o) : 0; } } public int VectorOfNonOwningReferencesLength { get { int o = __p.__offset(88); return o != 0 ? __p.__vector_len(o) : 0; } }
#if ENABLE_SPAN_T
public Span<byte> GetVectorOfNonOwningReferencesBytes() { return __p.__vector_as_span(88); }
#else
public ArraySegment<byte>? GetVectorOfNonOwningReferencesBytes() { return __p.__vector_as_arraysegment(88); } public ArraySegment<byte>? GetVectorOfNonOwningReferencesBytes() { return __p.__vector_as_arraysegment(88); }
#endif
public ulong[] GetVectorOfNonOwningReferencesArray() { return __p.__vector_as_array<ulong>(88); } public ulong[] GetVectorOfNonOwningReferencesArray() { return __p.__vector_as_array<ulong>(88); }
public bool MutateVectorOfNonOwningReferences(int j, ulong vector_of_non_owning_references) { int o = __p.__offset(88); if (o != 0) { __p.bb.PutUlong(__p.__vector(o) + j * 8, vector_of_non_owning_references); return true; } else { return false; } } public bool MutateVectorOfNonOwningReferences(int j, ulong vector_of_non_owning_references) { int o = __p.__offset(88); if (o != 0) { __p.bb.PutUlong(__p.__vector(o) + j * 8, vector_of_non_owning_references); return true; } else { return false; } }
......
...@@ -18,7 +18,11 @@ public struct Stat : IFlatbufferObject ...@@ -18,7 +18,11 @@ public struct Stat : IFlatbufferObject
public Stat __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; } public Stat __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
public string Id { get { int o = __p.__offset(4); return o != 0 ? __p.__string(o + __p.bb_pos) : null; } } public string Id { get { int o = __p.__offset(4); return o != 0 ? __p.__string(o + __p.bb_pos) : null; } }
#if ENABLE_SPAN_T
public Span<byte> GetIdBytes() { return __p.__vector_as_span(4); }
#else
public ArraySegment<byte>? GetIdBytes() { return __p.__vector_as_arraysegment(4); } public ArraySegment<byte>? GetIdBytes() { return __p.__vector_as_arraysegment(4); }
#endif
public byte[] GetIdArray() { return __p.__vector_as_array<byte>(4); } public byte[] GetIdArray() { return __p.__vector_as_array<byte>(4); }
public long Val { get { int o = __p.__offset(6); return o != 0 ? __p.bb.GetLong(o + __p.bb_pos) : (long)0; } } public long Val { get { int o = __p.__offset(6); return o != 0 ? __p.bb.GetLong(o + __p.bb_pos) : (long)0; } }
public bool MutateVal(long val) { int o = __p.__offset(6); if (o != 0) { __p.bb.PutLong(o + __p.bb_pos, val); return true; } else { return false; } } public bool MutateVal(long val) { int o = __p.__offset(6); if (o != 0) { __p.bb.PutLong(o + __p.bb_pos, val); return true; } else { return false; } }
......
...@@ -39,12 +39,20 @@ public struct TypeAliases : IFlatbufferObject ...@@ -39,12 +39,20 @@ public struct TypeAliases : IFlatbufferObject
public bool MutateF64(double f64) { int o = __p.__offset(22); if (o != 0) { __p.bb.PutDouble(o + __p.bb_pos, f64); return true; } else { return false; } } public bool MutateF64(double f64) { int o = __p.__offset(22); if (o != 0) { __p.bb.PutDouble(o + __p.bb_pos, f64); return true; } else { return false; } }
public sbyte V8(int j) { int o = __p.__offset(24); return o != 0 ? __p.bb.GetSbyte(__p.__vector(o) + j * 1) : (sbyte)0; } public sbyte V8(int j) { int o = __p.__offset(24); return o != 0 ? __p.bb.GetSbyte(__p.__vector(o) + j * 1) : (sbyte)0; }
public int V8Length { get { int o = __p.__offset(24); return o != 0 ? __p.__vector_len(o) : 0; } } public int V8Length { get { int o = __p.__offset(24); return o != 0 ? __p.__vector_len(o) : 0; } }
#if ENABLE_SPAN_T
public Span<byte> GetV8Bytes() { return __p.__vector_as_span(24); }
#else
public ArraySegment<byte>? GetV8Bytes() { return __p.__vector_as_arraysegment(24); } public ArraySegment<byte>? GetV8Bytes() { return __p.__vector_as_arraysegment(24); }
#endif
public sbyte[] GetV8Array() { return __p.__vector_as_array<sbyte>(24); } public sbyte[] GetV8Array() { return __p.__vector_as_array<sbyte>(24); }
public bool MutateV8(int j, sbyte v8) { int o = __p.__offset(24); if (o != 0) { __p.bb.PutSbyte(__p.__vector(o) + j * 1, v8); return true; } else { return false; } } public bool MutateV8(int j, sbyte v8) { int o = __p.__offset(24); if (o != 0) { __p.bb.PutSbyte(__p.__vector(o) + j * 1, v8); return true; } else { return false; } }
public double Vf64(int j) { int o = __p.__offset(26); return o != 0 ? __p.bb.GetDouble(__p.__vector(o) + j * 8) : (double)0; } public double Vf64(int j) { int o = __p.__offset(26); return o != 0 ? __p.bb.GetDouble(__p.__vector(o) + j * 8) : (double)0; }
public int Vf64Length { get { int o = __p.__offset(26); return o != 0 ? __p.__vector_len(o) : 0; } } public int Vf64Length { get { int o = __p.__offset(26); return o != 0 ? __p.__vector_len(o) : 0; } }
#if ENABLE_SPAN_T
public Span<byte> GetVf64Bytes() { return __p.__vector_as_span(26); }
#else
public ArraySegment<byte>? GetVf64Bytes() { return __p.__vector_as_arraysegment(26); } public ArraySegment<byte>? GetVf64Bytes() { return __p.__vector_as_arraysegment(26); }
#endif
public double[] GetVf64Array() { return __p.__vector_as_array<double>(26); } public double[] GetVf64Array() { return __p.__vector_as_array<double>(26); }
public bool MutateVf64(int j, double vf64) { int o = __p.__offset(26); if (o != 0) { __p.bb.PutDouble(__p.__vector(o) + j * 8, vf64); return true; } else { return false; } } public bool MutateVf64(int j, double vf64) { int o = __p.__offset(26); if (o != 0) { __p.bb.PutDouble(__p.__vector(o) + j * 8, vf64); return true; } else { return false; } }
......
...@@ -19,7 +19,12 @@ public struct Movie : IFlatbufferObject ...@@ -19,7 +19,12 @@ public struct Movie : IFlatbufferObject
public TTable? MainCharacter<TTable>() where TTable : struct, IFlatbufferObject { int o = __p.__offset(6); return o != 0 ? (TTable?)__p.__union<TTable>(o) : null; } public TTable? MainCharacter<TTable>() where TTable : struct, IFlatbufferObject { int o = __p.__offset(6); return o != 0 ? (TTable?)__p.__union<TTable>(o) : null; }
public Character CharactersType(int j) { int o = __p.__offset(8); return o != 0 ? (Character)__p.bb.Get(__p.__vector(o) + j * 1) : (Character)0; } public Character CharactersType(int j) { int o = __p.__offset(8); return o != 0 ? (Character)__p.bb.Get(__p.__vector(o) + j * 1) : (Character)0; }
public int CharactersTypeLength { get { int o = __p.__offset(8); return o != 0 ? __p.__vector_len(o) : 0; } } public int CharactersTypeLength { get { int o = __p.__offset(8); return o != 0 ? __p.__vector_len(o) : 0; } }
#if ENABLE_SPAN_T
public Span<byte> GetCharactersTypeBytes() { return __p.__vector_as_span(8); }
#else
public ArraySegment<byte>? GetCharactersTypeBytes() { return __p.__vector_as_arraysegment(8); } public ArraySegment<byte>? GetCharactersTypeBytes() { return __p.__vector_as_arraysegment(8); }
#endif
public Character[] GetCharactersTypeArray() { return __p.__vector_as_array<Character>(8); }
public TTable? Characters<TTable>(int j) where TTable : struct, IFlatbufferObject { int o = __p.__offset(10); return o != 0 ? (TTable?)__p.__union<TTable>(__p.__vector(o) + j * 4) : null; } public TTable? Characters<TTable>(int j) where TTable : struct, IFlatbufferObject { int o = __p.__offset(10); return o != 0 ? (TTable?)__p.__union<TTable>(__p.__vector(o) + j * 4) : null; }
public int CharactersLength { get { int o = __p.__offset(10); return o != 0 ? __p.__vector_len(o) : 0; } } public int CharactersLength { get { int o = __p.__offset(10); return o != 0 ? __p.__vector_len(o) : 0; } }
...@@ -41,9 +46,11 @@ public struct Movie : IFlatbufferObject ...@@ -41,9 +46,11 @@ public struct Movie : IFlatbufferObject
public static void AddMainCharacter(FlatBufferBuilder builder, int mainCharacterOffset) { builder.AddOffset(1, mainCharacterOffset, 0); } public static void AddMainCharacter(FlatBufferBuilder builder, int mainCharacterOffset) { builder.AddOffset(1, mainCharacterOffset, 0); }
public static void AddCharactersType(FlatBufferBuilder builder, VectorOffset charactersTypeOffset) { builder.AddOffset(2, charactersTypeOffset.Value, 0); } public static void AddCharactersType(FlatBufferBuilder builder, VectorOffset charactersTypeOffset) { builder.AddOffset(2, charactersTypeOffset.Value, 0); }
public static VectorOffset CreateCharactersTypeVector(FlatBufferBuilder builder, Character[] data) { builder.StartVector(1, data.Length, 1); for (int i = data.Length - 1; i >= 0; i--) builder.AddByte((byte)data[i]); return builder.EndVector(); } public static VectorOffset CreateCharactersTypeVector(FlatBufferBuilder builder, Character[] data) { builder.StartVector(1, data.Length, 1); for (int i = data.Length - 1; i >= 0; i--) builder.AddByte((byte)data[i]); return builder.EndVector(); }
public static VectorOffset CreateCharactersTypeVectorBlock(FlatBufferBuilder builder, Character[] data) { builder.StartVector(1, data.Length, 1); builder.Add(data); return builder.EndVector(); }
public static void StartCharactersTypeVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(1, numElems, 1); } public static void StartCharactersTypeVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(1, numElems, 1); }
public static void AddCharacters(FlatBufferBuilder builder, VectorOffset charactersOffset) { builder.AddOffset(3, charactersOffset.Value, 0); } public static void AddCharacters(FlatBufferBuilder builder, VectorOffset charactersOffset) { builder.AddOffset(3, charactersOffset.Value, 0); }
public static VectorOffset CreateCharactersVector(FlatBufferBuilder builder, int[] data) { builder.StartVector(4, data.Length, 4); for (int i = data.Length - 1; i >= 0; i--) builder.AddOffset(data[i]); return builder.EndVector(); } public static VectorOffset CreateCharactersVector(FlatBufferBuilder builder, int[] data) { builder.StartVector(4, data.Length, 4); for (int i = data.Length - 1; i >= 0; i--) builder.AddOffset(data[i]); return builder.EndVector(); }
public static VectorOffset CreateCharactersVectorBlock(FlatBufferBuilder builder, int[] data) { builder.StartVector(4, data.Length, 4); builder.Add(data); return builder.EndVector(); }
public static void StartCharactersVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(4, numElems, 4); } public static void StartCharactersVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(4, numElems, 4); }
public static Offset<Movie> EndMovie(FlatBufferBuilder builder) { public static Offset<Movie> EndMovie(FlatBufferBuilder builder) {
int o = builder.EndObject(); int o = builder.EndObject();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment