mirror of
https://github.com/google/flatbuffers.git
synced 2026-07-02 17:48:17 +00:00
Add overloads for C# ByteBuffer/FlatBufferBuilder to allow adding vector blocks from ArraySegments or IntPtr (#7193)
* Add overloads to Add/Put for ArraySegment and IntPtr In order to allow using code to reduce memory allocations, add overloads to ByteBuffer's and FlatBuffersBuilder's Put/Add methods that take ArraySegment<T> or IntPtr respectively. Also, adaptions to the c# code generator in flatc to emit corresponding CreateVectorBlock() overloads * Add missing files generated with generate_code.py The previous commit changed the C# code generate, but didn't contain the updated generated test files. * Incorporate review findings (1) Adhere to 80 characters limit. (2) In FlatBufferBuilder.Add(IntPtr,int), move zero length check topmost and add sanity check against negative input
This commit is contained in:
@@ -225,6 +225,18 @@ namespace FlatBuffers
|
||||
return SizeOf<T>() * x.Length;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the wire-size (in bytes) of an typed array segment, taking only the
|
||||
/// range specified by <paramref name="x"/> into account.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the array</typeparam>
|
||||
/// <param name="x">The array segment to get the size of</param>
|
||||
/// <returns>The number of bytes the array segment takes on wire</returns>
|
||||
public static int ArraySize<T>(ArraySegment<T> x)
|
||||
{
|
||||
return SizeOf<T>() * x.Count;
|
||||
}
|
||||
|
||||
#if ENABLE_SPAN_T && (UNSAFE_BYTEBUFFER || NETSTANDARD2_1)
|
||||
public static int ArraySize<T>(Span<T> x)
|
||||
{
|
||||
@@ -869,7 +881,30 @@ namespace FlatBuffers
|
||||
throw new ArgumentNullException("Cannot put a null array");
|
||||
}
|
||||
|
||||
if (x.Length == 0)
|
||||
return Put(offset, new ArraySegment<T>(x));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies an array segment of type T into this buffer, ending at the
|
||||
/// given offset into this buffer. The starting offset is calculated
|
||||
/// based on the count of the array segment 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 segment to copy data from</param>
|
||||
/// <returns>The 'start' location of this buffer now, after the copy
|
||||
/// completed</returns>
|
||||
public int Put<T>(int offset, ArraySegment<T> x)
|
||||
where T : struct
|
||||
{
|
||||
if (x.Equals(default(ArraySegment<T>)))
|
||||
{
|
||||
throw new ArgumentNullException("Cannot put a uninitialized array segment");
|
||||
}
|
||||
|
||||
if (x.Count == 0)
|
||||
{
|
||||
throw new ArgumentException("Cannot put an empty array");
|
||||
}
|
||||
@@ -889,7 +924,68 @@ namespace FlatBuffers
|
||||
#if ENABLE_SPAN_T && (UNSAFE_BYTEBUFFER || NETSTANDARD2_1)
|
||||
MemoryMarshal.Cast<T, byte>(x).CopyTo(_buffer.Span.Slice(offset, numBytes));
|
||||
#else
|
||||
Buffer.BlockCopy(x, 0, _buffer.Buffer, offset, numBytes);
|
||||
var srcOffset = ByteBuffer.SizeOf<T>() * x.Offset;
|
||||
Buffer.BlockCopy(x.Array, srcOffset, _buffer.Buffer, 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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies an array segment of type T into this buffer, ending at the
|
||||
/// given offset into this buffer. The starting offset is calculated
|
||||
/// based on the count of the array segment 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="ptr">The pointer to copy data from</param>
|
||||
/// <param name="sizeInBytes">The number of bytes to copy</param>
|
||||
/// <returns>The 'start' location of this buffer now, after the copy
|
||||
/// completed</returns>
|
||||
public int Put<T>(int offset, IntPtr ptr, int sizeInBytes)
|
||||
where T : struct
|
||||
{
|
||||
if (ptr == IntPtr.Zero)
|
||||
{
|
||||
throw new ArgumentNullException("Cannot add a null pointer");
|
||||
}
|
||||
|
||||
if(sizeInBytes <= 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)
|
||||
{
|
||||
offset -= sizeInBytes;
|
||||
AssertOffsetAndLength(offset, sizeInBytes);
|
||||
// if we are LE, just do a block copy
|
||||
#if ENABLE_SPAN_T && UNSAFE_BYTEBUFFER
|
||||
unsafe
|
||||
{
|
||||
var span = new Span<byte>(ptr.ToPointer(), sizeInBytes);
|
||||
span.CopyTo(_buffer.Span.Slice(offset, sizeInBytes));
|
||||
}
|
||||
#else
|
||||
Marshal.Copy(ptr, _buffer.Buffer, offset, sizeInBytes);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
|
||||
Reference in New Issue
Block a user