Add Get Bytes Method Generator for C#

I updated idl_gen_general.cpp to add support for generating a Get Bytes
method for a vector to the generated C# source code. Given a byte vector
field named Foo, a method named GetFooBytes() will be generated in the
C# source code that will return an ArraySegment<byte> value referencing
the vector data in the underlying ByteBuffer.

I added a method to Table.cs named __vector_as_arraysegment that is used
by the code generated by the change to the C# generator.
__vector_as_arraysegment will take the offset of the vector and will
return the ArraySegment<byte> value corresponding to the bytes that
store the vector data.

I updated FlatBuffersExampleTests.cs to add tests to validate my
implementation of Table.__vector_as_arraysegment. I added tests to
demonstrate that the bytes for the monster's name can be extracted from
the underlying byte array. I also added tests to show that
Table.__vector_as_arraysegment returns a null value if the vector is not
present in the FlatBuffer.

I used the updated flatc.exe program to regenerate the C# source files
for the MyGame example. The new Monster class includes the GetXXXBytes
methods to return the byte arrays containing data for vectors.
This commit is contained in:
Michael Collins 2015-10-04 19:57:39 -07:00
parent fe2f8d32aa
commit e083e466b8
9 changed files with 70 additions and 12 deletions

View File

@ -67,6 +67,21 @@ namespace FlatBuffers
return offset + bb.GetInt(offset) + sizeof(int); // data starts after the length
}
// 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,
// then a null value will be returned.
protected ArraySegment<byte>? __vector_as_arraysegment(int offset) {
var o = this.__offset(offset);
if (0 == o)
{
return null;
}
var pos = this.__vector(o);
var len = this.__vector_len(o);
return new ArraySegment<byte>(this.bb.Data, pos, len);
}
// Initialize any Table-derived type to point to the union at the given offset.
protected TTable __union<TTable>(TTable t, int offset) where TTable : Table
{

View File

@ -145,7 +145,7 @@ LanguageParameters language_parameters[] = {
"",
"Position",
"Offset",
"using FlatBuffers;\n\n",
"using System;\nusing FlatBuffers;\n\n",
{
nullptr,
"///",
@ -823,17 +823,29 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
code += "}\n";
}
// Generate a ByteBuffer accessor for strings & vectors of scalars.
if (((field.value.type.base_type == BASE_TYPE_VECTOR &&
IsScalar(field.value.type.VectorType().base_type)) ||
field.value.type.base_type == BASE_TYPE_STRING) &&
lang.language == IDLOptions::kJava) {
code += " public ByteBuffer ";
code += MakeCamel(field.name, lang.first_camel_upper);
code += "AsByteBuffer() { return __vector_as_bytebuffer(";
code += NumToString(field.value.offset) + ", ";
code += NumToString(field.value.type.base_type == BASE_TYPE_STRING ? 1 :
InlineSize(field.value.type.VectorType()));
code += "); }\n";
if ((field.value.type.base_type == BASE_TYPE_VECTOR &&
IsScalar(field.value.type.VectorType().base_type)) ||
field.value.type.base_type == BASE_TYPE_STRING) {
switch (lang.language) {
case IDLOptions::kJava:
code += " public ByteBuffer ";
code += MakeCamel(field.name, lang.first_camel_upper);
code += "AsByteBuffer() { return __vector_as_bytebuffer(";
code += NumToString(field.value.offset) + ", ";
code += NumToString(field.value.type.base_type == BASE_TYPE_STRING ? 1 :
InlineSize(field.value.type.VectorType()));
code += "); }\n";
break;
case IDLOptions::kCSharp:
code += " public ArraySegment<byte>? Get";
code += MakeCamel(field.name, lang.first_camel_upper);
code += "Bytes() { return __vector_as_arraysegment(";
code += NumToString(field.value.offset);
code += "); }\n";
break;
default:
break;
}
}
// generate mutators for scalar fields or vectors of scalars

View File

@ -107,6 +107,14 @@ namespace FlatBuffers.Test
}
}
public static void IsFalse(bool value)
{
if (value)
{
throw new AssertFailedException(false, value);
}
}
public static void Throws<T>(Action action) where T : Exception
{
var caught = false;

View File

@ -15,6 +15,7 @@
*/
using System.IO;
using System.Text;
using MyGame.Example;
namespace FlatBuffers.Test
@ -184,6 +185,18 @@ namespace FlatBuffers.Test
Assert.AreEqual("test2", monster.GetTestarrayofstring(1));
Assert.AreEqual(false, monster.Testbool);
var nameBytes = monster.GetNameBytes().Value;
Assert.AreEqual("MyMonster", Encoding.UTF8.GetString(nameBytes.Array, nameBytes.Offset, nameBytes.Count));
if (0 == monster.TestarrayofboolsLength)
{
Assert.IsFalse(monster.GetTestarrayofboolsBytes().HasValue);
}
else
{
Assert.IsTrue(monster.GetTestarrayofboolsBytes().HasValue);
}
}
[FlatBuffersTestMethod]

View File

@ -3,6 +3,7 @@
namespace MyGame.Example
{
using System;
using FlatBuffers;
/// an example documentation comment: monster object
@ -19,8 +20,10 @@ public sealed class Monster : Table {
public short Hp { get { int o = __offset(8); return o != 0 ? bb.GetShort(o + bb_pos) : (short)100; } }
public bool MutateHp(short hp) { int o = __offset(8); if (o != 0) { bb.PutShort(o + bb_pos, hp); return true; } else { return false; } }
public string Name { get { int o = __offset(10); return o != 0 ? __string(o + bb_pos) : null; } }
public ArraySegment<byte>? GetNameBytes() { return __vector_as_arraysegment(10); }
public byte GetInventory(int j) { int o = __offset(14); return o != 0 ? bb.Get(__vector(o) + j * 1) : (byte)0; }
public int InventoryLength { get { int o = __offset(14); return o != 0 ? __vector_len(o) : 0; } }
public ArraySegment<byte>? GetInventoryBytes() { return __vector_as_arraysegment(14); }
public bool MutateInventory(int j, byte inventory) { int o = __offset(14); if (o != 0) { bb.Put(__vector(o) + j * 1, inventory); return true; } else { return false; } }
public Color Color { get { int o = __offset(16); return o != 0 ? (Color)bb.GetSbyte(o + bb_pos) : Color.Blue; } }
public bool MutateColor(Color color) { int o = __offset(16); if (o != 0) { bb.PutSbyte(o + bb_pos, (sbyte)color); return true; } else { return false; } }
@ -41,6 +44,7 @@ public sealed class Monster : Table {
public Monster GetEnemy(Monster obj) { int o = __offset(28); return o != 0 ? obj.__init(__indirect(o + bb_pos), bb) : null; }
public byte GetTestnestedflatbuffer(int j) { int o = __offset(30); return o != 0 ? bb.Get(__vector(o) + j * 1) : (byte)0; }
public int TestnestedflatbufferLength { get { int o = __offset(30); return o != 0 ? __vector_len(o) : 0; } }
public ArraySegment<byte>? GetTestnestedflatbufferBytes() { return __vector_as_arraysegment(30); }
public bool MutateTestnestedflatbuffer(int j, byte testnestedflatbuffer) { int o = __offset(30); if (o != 0) { bb.Put(__vector(o) + j * 1, testnestedflatbuffer); return true; } else { return false; } }
public Stat Testempty { get { return GetTestempty(new Stat()); } }
public Stat GetTestempty(Stat obj) { int o = __offset(32); return o != 0 ? obj.__init(__indirect(o + bb_pos), bb) : null; }
@ -64,6 +68,7 @@ public sealed class Monster : Table {
public bool MutateTesthashu64Fnv1a(ulong testhashu64_fnv1a) { int o = __offset(50); if (o != 0) { bb.PutUlong(o + bb_pos, testhashu64_fnv1a); return true; } else { return false; } }
public bool GetTestarrayofbools(int j) { int o = __offset(52); return o != 0 ? 0!=bb.Get(__vector(o) + j * 1) : false; }
public int TestarrayofboolsLength { get { int o = __offset(52); return o != 0 ? __vector_len(o) : 0; } }
public ArraySegment<byte>? GetTestarrayofboolsBytes() { return __vector_as_arraysegment(52); }
public bool MutateTestarrayofbools(int j, bool testarrayofbools) { int o = __offset(52); if (o != 0) { bb.Put(__vector(o) + j * 1, (byte)(testarrayofbools ? 1 : 0)); return true; } else { return false; } }
public static void StartMonster(FlatBufferBuilder builder) { builder.StartObject(25); }

View File

@ -3,6 +3,7 @@
namespace MyGame.Example
{
using System;
using FlatBuffers;
public sealed class Stat : Table {
@ -11,6 +12,7 @@ public sealed class Stat : Table {
public Stat __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }
public string Id { get { int o = __offset(4); return o != 0 ? __string(o + bb_pos) : null; } }
public ArraySegment<byte>? GetIdBytes() { return __vector_as_arraysegment(4); }
public long Val { get { int o = __offset(6); return o != 0 ? bb.GetLong(o + bb_pos) : (long)0; } }
public bool MutateVal(long val) { int o = __offset(6); if (o != 0) { bb.PutLong(o + bb_pos, val); return true; } else { return false; } }
public ushort Count { get { int o = __offset(8); return o != 0 ? bb.GetUshort(o + bb_pos) : (ushort)0; } }

View File

@ -3,6 +3,7 @@
namespace MyGame.Example
{
using System;
using FlatBuffers;
public sealed class Test : Struct {

View File

@ -3,6 +3,7 @@
namespace MyGame.Example
{
using System;
using FlatBuffers;
public sealed class TestSimpleTableWithEnum : Table {

View File

@ -3,6 +3,7 @@
namespace MyGame.Example
{
using System;
using FlatBuffers;
public sealed class Vec3 : Struct {