From 81c2b185efcc729777d86815577cd6ebdd7e15c4 Mon Sep 17 00:00:00 2001 From: Maor Itzkovitch Date: Sat, 1 Aug 2015 12:38:47 +0300 Subject: [PATCH 01/10] support for scalar mutators --- src/idl_gen_general.cpp | 39 +++++++++++++++++++++++++++++-- tests/MyGame/Example/Monster.cs | 13 +++++++++++ tests/MyGame/Example/Monster.java | 13 +++++++++++ tests/MyGame/Example/Stat.cs | 2 ++ tests/MyGame/Example/Stat.java | 2 ++ tests/MyGame/Example/Test.cs | 2 ++ tests/MyGame/Example/Test.java | 2 ++ tests/MyGame/Example/Vec3.cs | 5 ++++ tests/MyGame/Example/Vec3.java | 5 ++++ 9 files changed, 81 insertions(+), 2 deletions(-) diff --git a/src/idl_gen_general.cpp b/src/idl_gen_general.cpp index a5b7af77c..0c733f345 100644 --- a/src/idl_gen_general.cpp +++ b/src/idl_gen_general.cpp @@ -428,6 +428,20 @@ static std::string GenGetter(const LanguageParameters &lang, } } +static std::string GenSetter(const LanguageParameters &lang, + const Type &type) { + switch (type.base_type) { + case BASE_TYPE_STRUCT: return ""; + default: { + std::string setter = "bb." + FunctionStart(lang, 'P') + "ut"; + if (GenTypeBasic(lang, type) != "byte") { + setter += MakeCamel(GenTypeGet(lang, type)); + } + return setter; + } + } +} + // Returns the method name for use with add/put calls. static std::string GenMethod(const LanguageParameters &lang, const Type &type) { return IsScalar(type.base_type) @@ -493,7 +507,8 @@ static void GenStructBody(const LanguageParameters &lang, } static void GenStruct(const LanguageParameters &lang, const Parser &parser, - StructDef &struct_def, std::string *code_ptr) { + StructDef &struct_def, const GeneratorOptions &opts, + std::string *code_ptr) { if (struct_def.generated) return; std::string &code = *code_ptr; @@ -698,6 +713,26 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser, InlineSize(field.value.type.VectorType())); code += "); }\n"; } + + // generate mutators for scalar fields + if (opts.mutable_buffer) { + std::string mutator_prefix = MakeCamel("mutate", lang.first_camel_upper); + if (IsScalar(field.value.type.base_type)) { + code += " public "; + code += struct_def.fixed ? "void " : lang.bool_type; + code += mutator_prefix + MakeCamel(field.name, true) + "("; + code += GenTypeBasic(lang, field.value.type); + code += " " + field.name + ") { "; + if (struct_def.fixed) { + code += GenSetter(lang, field.value.type) + "(bb_pos + "; + code += NumToString(field.value.offset) + "); }\n"; + } else { + code += "int o = __offset(" + NumToString(field.value.offset) + ");"; + code += " if (o != 0) { " + GenSetter(lang, field.value.type); + code += "(o + bb_pos); return true } else { return false } }\n"; + } + } + } } code += "\n"; if (struct_def.fixed) { @@ -914,7 +949,7 @@ bool GenerateGeneral(const Parser &parser, for (auto it = parser.structs_.vec.begin(); it != parser.structs_.vec.end(); ++it) { std::string declcode; - GenStruct(lang, parser, **it, &declcode); + GenStruct(lang, parser, **it, opts, &declcode); if (opts.one_file) { one_file_code += declcode; } diff --git a/tests/MyGame/Example/Monster.cs b/tests/MyGame/Example/Monster.cs index a427c664a..a029b040e 100644 --- a/tests/MyGame/Example/Monster.cs +++ b/tests/MyGame/Example/Monster.cs @@ -14,12 +14,16 @@ public sealed class Monster : Table { public Vec3 Pos { get { return GetPos(new Vec3()); } } public Vec3 GetPos(Vec3 obj) { int o = __offset(4); return o != 0 ? obj.__init(o + bb_pos, bb) : null; } public short Mana { get { int o = __offset(6); return o != 0 ? bb.GetShort(o + bb_pos) : (short)150; } } + public bool MutateMana(short mana) { int o = __offset(6); if (o != 0) { bb.PutShort(o + bb_pos); return true } else { return false } } 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); return true } else { return false } } public string Name { get { int o = __offset(10); return o != 0 ? __string(o + bb_pos) : null; } } 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 Color Color { get { int o = __offset(16); return o != 0 ? (Color)bb.GetSbyte(o + bb_pos) : (Color)8; } } + public bool MutateColor(sbyte color) { int o = __offset(16); if (o != 0) { bb.PutSbyte(o + bb_pos); return true } else { return false } } public Any TestType { get { int o = __offset(18); return o != 0 ? (Any)bb.Get(o + bb_pos) : (Any)0; } } + public bool MutateTestType(byte test_type) { int o = __offset(18); if (o != 0) { bb.Put(o + bb_pos); return true } else { return false } } public TTable GetTest(TTable obj) where TTable : Table { int o = __offset(20); return o != 0 ? __union(obj, o) : null; } public Test GetTest4(int j) { return GetTest4(new Test(), j); } public Test GetTest4(Test obj, int j) { int o = __offset(22); return o != 0 ? obj.__init(__vector(o) + j * 4, bb) : null; } @@ -38,14 +42,23 @@ public sealed class Monster : Table { 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; } public bool Testbool { get { int o = __offset(34); return o != 0 ? 0!=bb.Get(o + bb_pos) : (bool)false; } } + public bool MutateTestbool(bool testbool) { int o = __offset(34); if (o != 0) { bb.PutBool(o + bb_pos); return true } else { return false } } public int Testhashs32Fnv1 { get { int o = __offset(36); return o != 0 ? bb.GetInt(o + bb_pos) : (int)0; } } + public bool MutateTesthashs32Fnv1(int testhashs32_fnv1) { int o = __offset(36); if (o != 0) { bb.PutInt(o + bb_pos); return true } else { return false } } public uint Testhashu32Fnv1 { get { int o = __offset(38); return o != 0 ? bb.GetUint(o + bb_pos) : (uint)0; } } + public bool MutateTesthashu32Fnv1(uint testhashu32_fnv1) { int o = __offset(38); if (o != 0) { bb.PutUint(o + bb_pos); return true } else { return false } } public long Testhashs64Fnv1 { get { int o = __offset(40); return o != 0 ? bb.GetLong(o + bb_pos) : (long)0; } } + public bool MutateTesthashs64Fnv1(long testhashs64_fnv1) { int o = __offset(40); if (o != 0) { bb.PutLong(o + bb_pos); return true } else { return false } } public ulong Testhashu64Fnv1 { get { int o = __offset(42); return o != 0 ? bb.GetUlong(o + bb_pos) : (ulong)0; } } + public bool MutateTesthashu64Fnv1(ulong testhashu64_fnv1) { int o = __offset(42); if (o != 0) { bb.PutUlong(o + bb_pos); return true } else { return false } } public int Testhashs32Fnv1a { get { int o = __offset(44); return o != 0 ? bb.GetInt(o + bb_pos) : (int)0; } } + public bool MutateTesthashs32Fnv1a(int testhashs32_fnv1a) { int o = __offset(44); if (o != 0) { bb.PutInt(o + bb_pos); return true } else { return false } } public uint Testhashu32Fnv1a { get { int o = __offset(46); return o != 0 ? bb.GetUint(o + bb_pos) : (uint)0; } } + public bool MutateTesthashu32Fnv1a(uint testhashu32_fnv1a) { int o = __offset(46); if (o != 0) { bb.PutUint(o + bb_pos); return true } else { return false } } public long Testhashs64Fnv1a { get { int o = __offset(48); return o != 0 ? bb.GetLong(o + bb_pos) : (long)0; } } + public bool MutateTesthashs64Fnv1a(long testhashs64_fnv1a) { int o = __offset(48); if (o != 0) { bb.PutLong(o + bb_pos); return true } else { return false } } public ulong Testhashu64Fnv1a { get { int o = __offset(50); return o != 0 ? bb.GetUlong(o + bb_pos) : (ulong)0; } } + public bool MutateTesthashu64Fnv1a(ulong testhashu64_fnv1a) { int o = __offset(50); if (o != 0) { bb.PutUlong(o + bb_pos); return true } else { return false } } public static void StartMonster(FlatBufferBuilder builder) { builder.StartObject(24); } public static void AddPos(FlatBufferBuilder builder, int posOffset) { builder.AddStruct(0, posOffset, 0); } diff --git a/tests/MyGame/Example/Monster.java b/tests/MyGame/Example/Monster.java index 6d1c02f03..4b8bdac5d 100644 --- a/tests/MyGame/Example/Monster.java +++ b/tests/MyGame/Example/Monster.java @@ -16,14 +16,18 @@ public final class Monster extends Table { public Vec3 pos() { return pos(new Vec3()); } public Vec3 pos(Vec3 obj) { int o = __offset(4); return o != 0 ? obj.__init(o + bb_pos, bb) : null; } public short mana() { int o = __offset(6); return o != 0 ? bb.getShort(o + bb_pos) : 150; } + public boolean mutateMana(short mana) { int o = __offset(6); if (o != 0) { bb.putShort(o + bb_pos); return true } else { return false } } public short hp() { int o = __offset(8); return o != 0 ? bb.getShort(o + bb_pos) : 100; } + public boolean mutateHp(short hp) { int o = __offset(8); if (o != 0) { bb.putShort(o + bb_pos); return true } else { return false } } public String name() { int o = __offset(10); return o != 0 ? __string(o + bb_pos) : null; } public ByteBuffer nameAsByteBuffer() { return __vector_as_bytebuffer(10, 1); } public int inventory(int j) { int o = __offset(14); return o != 0 ? bb.get(__vector(o) + j * 1) & 0xFF : 0; } public int inventoryLength() { int o = __offset(14); return o != 0 ? __vector_len(o) : 0; } public ByteBuffer inventoryAsByteBuffer() { return __vector_as_bytebuffer(14, 1); } public byte color() { int o = __offset(16); return o != 0 ? bb.get(o + bb_pos) : 8; } + public boolean mutateColor(byte color) { int o = __offset(16); if (o != 0) { bb.put(o + bb_pos); return true } else { return false } } public byte testType() { int o = __offset(18); return o != 0 ? bb.get(o + bb_pos) : 0; } + public boolean mutateTestType(byte test_type) { int o = __offset(18); if (o != 0) { bb.put(o + bb_pos); return true } else { return false } } public Table test(Table obj) { int o = __offset(20); return o != 0 ? __union(obj, o) : null; } public Test test4(int j) { return test4(new Test(), j); } public Test test4(Test obj, int j) { int o = __offset(22); return o != 0 ? obj.__init(__vector(o) + j * 4, bb) : null; } @@ -45,14 +49,23 @@ public final class Monster extends Table { public Stat testempty() { return testempty(new Stat()); } public Stat testempty(Stat obj) { int o = __offset(32); return o != 0 ? obj.__init(__indirect(o + bb_pos), bb) : null; } public boolean testbool() { int o = __offset(34); return o != 0 ? 0!=bb.get(o + bb_pos) : false; } + public boolean mutateTestbool(boolean testbool) { int o = __offset(34); if (o != 0) { bb.putBoolean(o + bb_pos); return true } else { return false } } public int testhashs32Fnv1() { int o = __offset(36); return o != 0 ? bb.getInt(o + bb_pos) : 0; } + public boolean mutateTesthashs32Fnv1(int testhashs32_fnv1) { int o = __offset(36); if (o != 0) { bb.putInt(o + bb_pos); return true } else { return false } } public long testhashu32Fnv1() { int o = __offset(38); return o != 0 ? (long)bb.getInt(o + bb_pos) & 0xFFFFFFFFL : 0; } + public boolean mutateTesthashu32Fnv1(int testhashu32_fnv1) { int o = __offset(38); if (o != 0) { bb.putInt(o + bb_pos); return true } else { return false } } public long testhashs64Fnv1() { int o = __offset(40); return o != 0 ? bb.getLong(o + bb_pos) : 0; } + public boolean mutateTesthashs64Fnv1(long testhashs64_fnv1) { int o = __offset(40); if (o != 0) { bb.putLong(o + bb_pos); return true } else { return false } } public long testhashu64Fnv1() { int o = __offset(42); return o != 0 ? bb.getLong(o + bb_pos) : 0; } + public boolean mutateTesthashu64Fnv1(long testhashu64_fnv1) { int o = __offset(42); if (o != 0) { bb.putLong(o + bb_pos); return true } else { return false } } public int testhashs32Fnv1a() { int o = __offset(44); return o != 0 ? bb.getInt(o + bb_pos) : 0; } + public boolean mutateTesthashs32Fnv1a(int testhashs32_fnv1a) { int o = __offset(44); if (o != 0) { bb.putInt(o + bb_pos); return true } else { return false } } public long testhashu32Fnv1a() { int o = __offset(46); return o != 0 ? (long)bb.getInt(o + bb_pos) & 0xFFFFFFFFL : 0; } + public boolean mutateTesthashu32Fnv1a(int testhashu32_fnv1a) { int o = __offset(46); if (o != 0) { bb.putInt(o + bb_pos); return true } else { return false } } public long testhashs64Fnv1a() { int o = __offset(48); return o != 0 ? bb.getLong(o + bb_pos) : 0; } + public boolean mutateTesthashs64Fnv1a(long testhashs64_fnv1a) { int o = __offset(48); if (o != 0) { bb.putLong(o + bb_pos); return true } else { return false } } public long testhashu64Fnv1a() { int o = __offset(50); return o != 0 ? bb.getLong(o + bb_pos) : 0; } + public boolean mutateTesthashu64Fnv1a(long testhashu64_fnv1a) { int o = __offset(50); if (o != 0) { bb.putLong(o + bb_pos); return true } else { return false } } public static void startMonster(FlatBufferBuilder builder) { builder.startObject(24); } public static void addPos(FlatBufferBuilder builder, int posOffset) { builder.addStruct(0, posOffset, 0); } diff --git a/tests/MyGame/Example/Stat.cs b/tests/MyGame/Example/Stat.cs index 38d7ad395..b0ad134d4 100644 --- a/tests/MyGame/Example/Stat.cs +++ b/tests/MyGame/Example/Stat.cs @@ -12,7 +12,9 @@ public sealed class Stat : Table { public string Id { get { int o = __offset(4); return o != 0 ? __string(o + bb_pos) : null; } } 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); return true } else { return false } } public ushort Count { get { int o = __offset(8); return o != 0 ? bb.GetUshort(o + bb_pos) : (ushort)0; } } + public bool MutateCount(ushort count) { int o = __offset(8); if (o != 0) { bb.PutUshort(o + bb_pos); return true } else { return false } } public static int CreateStat(FlatBufferBuilder builder, int id = 0, diff --git a/tests/MyGame/Example/Stat.java b/tests/MyGame/Example/Stat.java index e1663c19c..7c78876a0 100644 --- a/tests/MyGame/Example/Stat.java +++ b/tests/MyGame/Example/Stat.java @@ -15,7 +15,9 @@ public final class Stat extends Table { public String id() { int o = __offset(4); return o != 0 ? __string(o + bb_pos) : null; } public ByteBuffer idAsByteBuffer() { return __vector_as_bytebuffer(4, 1); } public long val() { int o = __offset(6); return o != 0 ? bb.getLong(o + bb_pos) : 0; } + public boolean mutateVal(long val) { int o = __offset(6); if (o != 0) { bb.putLong(o + bb_pos); return true } else { return false } } public int count() { int o = __offset(8); return o != 0 ? bb.getShort(o + bb_pos) & 0xFFFF : 0; } + public boolean mutateCount(short count) { int o = __offset(8); if (o != 0) { bb.putShort(o + bb_pos); return true } else { return false } } public static int createStat(FlatBufferBuilder builder, int id, diff --git a/tests/MyGame/Example/Test.cs b/tests/MyGame/Example/Test.cs index 32de138d7..4cddc369b 100644 --- a/tests/MyGame/Example/Test.cs +++ b/tests/MyGame/Example/Test.cs @@ -9,7 +9,9 @@ public sealed class Test : Struct { public Test __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; } public short A { get { return bb.GetShort(bb_pos + 0); } } + public void MutateA(short a) { bb.PutShort(bb_pos + 0); } public sbyte B { get { return bb.GetSbyte(bb_pos + 2); } } + public void MutateB(sbyte b) { bb.PutSbyte(bb_pos + 2); } public static int CreateTest(FlatBufferBuilder builder, short A, sbyte B) { builder.Prep(2, 4); diff --git a/tests/MyGame/Example/Test.java b/tests/MyGame/Example/Test.java index d4e4094c2..0dc72a705 100644 --- a/tests/MyGame/Example/Test.java +++ b/tests/MyGame/Example/Test.java @@ -11,7 +11,9 @@ public final class Test extends Struct { public Test __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; } public short a() { return bb.getShort(bb_pos + 0); } + public void mutateA(short a) { bb.putShort(bb_pos + 0); } public byte b() { return bb.get(bb_pos + 2); } + public void mutateB(byte b) { bb.put(bb_pos + 2); } public static int createTest(FlatBufferBuilder builder, short a, byte b) { builder.prep(2, 4); diff --git a/tests/MyGame/Example/Vec3.cs b/tests/MyGame/Example/Vec3.cs index 732f2d65f..090dd1995 100644 --- a/tests/MyGame/Example/Vec3.cs +++ b/tests/MyGame/Example/Vec3.cs @@ -9,10 +9,15 @@ public sealed class Vec3 : Struct { public Vec3 __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; } public float X { get { return bb.GetFloat(bb_pos + 0); } } + public void MutateX(float x) { bb.PutFloat(bb_pos + 0); } public float Y { get { return bb.GetFloat(bb_pos + 4); } } + public void MutateY(float y) { bb.PutFloat(bb_pos + 4); } public float Z { get { return bb.GetFloat(bb_pos + 8); } } + public void MutateZ(float z) { bb.PutFloat(bb_pos + 8); } public double Test1 { get { return bb.GetDouble(bb_pos + 16); } } + public void MutateTest1(double test1) { bb.PutDouble(bb_pos + 16); } public Color Test2 { get { return (Color)bb.GetSbyte(bb_pos + 24); } } + public void MutateTest2(sbyte test2) { bb.PutSbyte(bb_pos + 24); } public Test Test3 { get { return GetTest3(new Test()); } } public Test GetTest3(Test obj) { return obj.__init(bb_pos + 26, bb); } diff --git a/tests/MyGame/Example/Vec3.java b/tests/MyGame/Example/Vec3.java index 794eea1d8..df62cc8a4 100644 --- a/tests/MyGame/Example/Vec3.java +++ b/tests/MyGame/Example/Vec3.java @@ -11,10 +11,15 @@ public final class Vec3 extends Struct { public Vec3 __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; } public float x() { return bb.getFloat(bb_pos + 0); } + public void mutateX(float x) { bb.putFloat(bb_pos + 0); } public float y() { return bb.getFloat(bb_pos + 4); } + public void mutateY(float y) { bb.putFloat(bb_pos + 4); } public float z() { return bb.getFloat(bb_pos + 8); } + public void mutateZ(float z) { bb.putFloat(bb_pos + 8); } public double test1() { return bb.getDouble(bb_pos + 16); } + public void mutateTest1(double test1) { bb.putDouble(bb_pos + 16); } public byte test2() { return bb.get(bb_pos + 24); } + public void mutateTest2(byte test2) { bb.put(bb_pos + 24); } public Test test3() { return test3(new Test()); } public Test test3(Test obj) { return obj.__init(bb_pos + 26, bb); } From e24afd838aedabb782b46091d33485360d176608 Mon Sep 17 00:00:00 2001 From: Maor Itzkovitch Date: Sat, 1 Aug 2015 19:07:10 +0300 Subject: [PATCH 02/10] extended scalar mutator support --- .gitignore | 6 ++++++ net/FlatBuffers/ByteBuffer.cs | 6 ++++++ src/idl_gen_general.cpp | 9 ++++++--- tests/JavaTest.java | 25 +++++++++++++++++++++++++ tests/MyGame/Example/Monster.cs | 26 +++++++++++++------------- tests/MyGame/Example/Monster.java | 26 +++++++++++++------------- tests/MyGame/Example/Stat.cs | 4 ++-- tests/MyGame/Example/Stat.java | 4 ++-- tests/MyGame/Example/Test.cs | 4 ++-- tests/MyGame/Example/Test.java | 4 ++-- tests/MyGame/Example/Vec3.cs | 10 +++++----- tests/MyGame/Example/Vec3.java | 10 +++++----- 12 files changed, 87 insertions(+), 47 deletions(-) diff --git a/.gitignore b/.gitignore index 5d7a88540..c8415516a 100755 --- a/.gitignore +++ b/.gitignore @@ -31,10 +31,15 @@ proguard-project.txt linklint_results Makefile flatc +flatc.exe flathash +flathash.exe flattests +flattests.exe flatsamplebinary +flatsamplebinary.exe flatsampletext +flatsampletext.exe snapshot.sh tests/go_gen tests/monsterdata_java_wire.mon @@ -50,3 +55,4 @@ java/.idea java/*.iml java/target **/*.pyc +.idea \ No newline at end of file diff --git a/net/FlatBuffers/ByteBuffer.cs b/net/FlatBuffers/ByteBuffer.cs index aadd0ea5f..1ea040278 100755 --- a/net/FlatBuffers/ByteBuffer.cs +++ b/net/FlatBuffers/ByteBuffer.cs @@ -139,6 +139,12 @@ namespace FlatBuffers _pos = offset; } + // this method exists in order to conform with Java ByteBuffer standards + public void Put(int offset, byte value) + { + PutByte(offset, value); + } + #if UNSAFE_BYTEBUFFER // Unsafe but more efficient versions of Put*. public void PutShort(int offset, short value) diff --git a/src/idl_gen_general.cpp b/src/idl_gen_general.cpp index 0c733f345..9bc1f7093 100644 --- a/src/idl_gen_general.cpp +++ b/src/idl_gen_general.cpp @@ -434,7 +434,8 @@ static std::string GenSetter(const LanguageParameters &lang, case BASE_TYPE_STRUCT: return ""; default: { std::string setter = "bb." + FunctionStart(lang, 'P') + "ut"; - if (GenTypeBasic(lang, type) != "byte") { + if (GenTypeBasic(lang, type) != "byte" && + type.base_type != BASE_TYPE_BOOL) { setter += MakeCamel(GenTypeGet(lang, type)); } return setter; @@ -716,6 +717,8 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser, // generate mutators for scalar fields if (opts.mutable_buffer) { + // boolean parameters have to be explicitly converted to byte representation + std::string setter_parameter = field.value.type.base_type == BASE_TYPE_BOOL ? "(byte)(" + field.name + " ? 1 : 0)" : field.name; std::string mutator_prefix = MakeCamel("mutate", lang.first_camel_upper); if (IsScalar(field.value.type.base_type)) { code += " public "; @@ -725,11 +728,11 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser, code += " " + field.name + ") { "; if (struct_def.fixed) { code += GenSetter(lang, field.value.type) + "(bb_pos + "; - code += NumToString(field.value.offset) + "); }\n"; + code += NumToString(field.value.offset) + ", " + setter_parameter + "); }\n"; } else { code += "int o = __offset(" + NumToString(field.value.offset) + ");"; code += " if (o != 0) { " + GenSetter(lang, field.value.type); - code += "(o + bb_pos); return true } else { return false } }\n"; + code += "(o + bb_pos, " + setter_parameter + "); return true; } else { return false; } }\n"; } } } diff --git a/tests/JavaTest.java b/tests/JavaTest.java index 75fb59820..9e8c77b7c 100755 --- a/tests/JavaTest.java +++ b/tests/JavaTest.java @@ -110,6 +110,31 @@ class JavaTest { TestEnums(); + //Attempt to mutate Monster fields and check whether the buffer has been mutated properly + // revert to original values after testing + Monster monster = Monster.getRootAsMonster(fbb.dataBuffer()); + + // mana is optional and does not exist in the buffer so the mutation should fail + // it should retain its default value + TestEq(monster.mutateMana((short)10), false); + TestEq(monster.mana(), (short)150); + + // testType is an existing field and mutating it should succeed + TestEq(monster.testType(), (byte)Any.Monster); + TestEq(monster.mutateTestType(Any.NONE), true); + TestEq(monster.testType(), (byte)Any.NONE); + TestEq(monster.mutateTestType(Any.Monster), true); + TestEq(monster.testType(), (byte)Any.Monster); + + // get a struct field and edit one of its fields + // + Vec3 pos = monster.pos(); + TestEq(pos.x(), 1.0f); + pos.mutateX(55.0f); + TestEq(pos.x(), 55.0f); + pos.mutateX(1.0f); + TestEq(pos.x(), 1.0f); + System.out.println("FlatBuffers test: completed successfully"); } diff --git a/tests/MyGame/Example/Monster.cs b/tests/MyGame/Example/Monster.cs index a029b040e..593210b34 100644 --- a/tests/MyGame/Example/Monster.cs +++ b/tests/MyGame/Example/Monster.cs @@ -14,16 +14,16 @@ public sealed class Monster : Table { public Vec3 Pos { get { return GetPos(new Vec3()); } } public Vec3 GetPos(Vec3 obj) { int o = __offset(4); return o != 0 ? obj.__init(o + bb_pos, bb) : null; } public short Mana { get { int o = __offset(6); return o != 0 ? bb.GetShort(o + bb_pos) : (short)150; } } - public bool MutateMana(short mana) { int o = __offset(6); if (o != 0) { bb.PutShort(o + bb_pos); return true } else { return false } } + public bool MutateMana(short mana) { int o = __offset(6); if (o != 0) { bb.PutShort(o + bb_pos, mana); return true; } else { return false; } } 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); return true } else { return false } } + 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 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 Color Color { get { int o = __offset(16); return o != 0 ? (Color)bb.GetSbyte(o + bb_pos) : (Color)8; } } - public bool MutateColor(sbyte color) { int o = __offset(16); if (o != 0) { bb.PutSbyte(o + bb_pos); return true } else { return false } } + public bool MutateColor(sbyte color) { int o = __offset(16); if (o != 0) { bb.PutSbyte(o + bb_pos, color); return true; } else { return false; } } public Any TestType { get { int o = __offset(18); return o != 0 ? (Any)bb.Get(o + bb_pos) : (Any)0; } } - public bool MutateTestType(byte test_type) { int o = __offset(18); if (o != 0) { bb.Put(o + bb_pos); return true } else { return false } } + public bool MutateTestType(byte test_type) { int o = __offset(18); if (o != 0) { bb.Put(o + bb_pos, test_type); return true; } else { return false; } } public TTable GetTest(TTable obj) where TTable : Table { int o = __offset(20); return o != 0 ? __union(obj, o) : null; } public Test GetTest4(int j) { return GetTest4(new Test(), j); } public Test GetTest4(Test obj, int j) { int o = __offset(22); return o != 0 ? obj.__init(__vector(o) + j * 4, bb) : null; } @@ -42,23 +42,23 @@ public sealed class Monster : Table { 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; } public bool Testbool { get { int o = __offset(34); return o != 0 ? 0!=bb.Get(o + bb_pos) : (bool)false; } } - public bool MutateTestbool(bool testbool) { int o = __offset(34); if (o != 0) { bb.PutBool(o + bb_pos); return true } else { return false } } + public bool MutateTestbool(bool testbool) { int o = __offset(34); if (o != 0) { bb.Put(o + bb_pos, (byte)(testbool ? 1 : 0)); return true; } else { return false; } } public int Testhashs32Fnv1 { get { int o = __offset(36); return o != 0 ? bb.GetInt(o + bb_pos) : (int)0; } } - public bool MutateTesthashs32Fnv1(int testhashs32_fnv1) { int o = __offset(36); if (o != 0) { bb.PutInt(o + bb_pos); return true } else { return false } } + public bool MutateTesthashs32Fnv1(int testhashs32_fnv1) { int o = __offset(36); if (o != 0) { bb.PutInt(o + bb_pos, testhashs32_fnv1); return true; } else { return false; } } public uint Testhashu32Fnv1 { get { int o = __offset(38); return o != 0 ? bb.GetUint(o + bb_pos) : (uint)0; } } - public bool MutateTesthashu32Fnv1(uint testhashu32_fnv1) { int o = __offset(38); if (o != 0) { bb.PutUint(o + bb_pos); return true } else { return false } } + public bool MutateTesthashu32Fnv1(uint testhashu32_fnv1) { int o = __offset(38); if (o != 0) { bb.PutUint(o + bb_pos, testhashu32_fnv1); return true; } else { return false; } } public long Testhashs64Fnv1 { get { int o = __offset(40); return o != 0 ? bb.GetLong(o + bb_pos) : (long)0; } } - public bool MutateTesthashs64Fnv1(long testhashs64_fnv1) { int o = __offset(40); if (o != 0) { bb.PutLong(o + bb_pos); return true } else { return false } } + public bool MutateTesthashs64Fnv1(long testhashs64_fnv1) { int o = __offset(40); if (o != 0) { bb.PutLong(o + bb_pos, testhashs64_fnv1); return true; } else { return false; } } public ulong Testhashu64Fnv1 { get { int o = __offset(42); return o != 0 ? bb.GetUlong(o + bb_pos) : (ulong)0; } } - public bool MutateTesthashu64Fnv1(ulong testhashu64_fnv1) { int o = __offset(42); if (o != 0) { bb.PutUlong(o + bb_pos); return true } else { return false } } + public bool MutateTesthashu64Fnv1(ulong testhashu64_fnv1) { int o = __offset(42); if (o != 0) { bb.PutUlong(o + bb_pos, testhashu64_fnv1); return true; } else { return false; } } public int Testhashs32Fnv1a { get { int o = __offset(44); return o != 0 ? bb.GetInt(o + bb_pos) : (int)0; } } - public bool MutateTesthashs32Fnv1a(int testhashs32_fnv1a) { int o = __offset(44); if (o != 0) { bb.PutInt(o + bb_pos); return true } else { return false } } + public bool MutateTesthashs32Fnv1a(int testhashs32_fnv1a) { int o = __offset(44); if (o != 0) { bb.PutInt(o + bb_pos, testhashs32_fnv1a); return true; } else { return false; } } public uint Testhashu32Fnv1a { get { int o = __offset(46); return o != 0 ? bb.GetUint(o + bb_pos) : (uint)0; } } - public bool MutateTesthashu32Fnv1a(uint testhashu32_fnv1a) { int o = __offset(46); if (o != 0) { bb.PutUint(o + bb_pos); return true } else { return false } } + public bool MutateTesthashu32Fnv1a(uint testhashu32_fnv1a) { int o = __offset(46); if (o != 0) { bb.PutUint(o + bb_pos, testhashu32_fnv1a); return true; } else { return false; } } public long Testhashs64Fnv1a { get { int o = __offset(48); return o != 0 ? bb.GetLong(o + bb_pos) : (long)0; } } - public bool MutateTesthashs64Fnv1a(long testhashs64_fnv1a) { int o = __offset(48); if (o != 0) { bb.PutLong(o + bb_pos); return true } else { return false } } + public bool MutateTesthashs64Fnv1a(long testhashs64_fnv1a) { int o = __offset(48); if (o != 0) { bb.PutLong(o + bb_pos, testhashs64_fnv1a); return true; } else { return false; } } public ulong Testhashu64Fnv1a { get { int o = __offset(50); return o != 0 ? bb.GetUlong(o + bb_pos) : (ulong)0; } } - public bool MutateTesthashu64Fnv1a(ulong testhashu64_fnv1a) { int o = __offset(50); if (o != 0) { bb.PutUlong(o + bb_pos); return true } else { return false } } + 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 static void StartMonster(FlatBufferBuilder builder) { builder.StartObject(24); } public static void AddPos(FlatBufferBuilder builder, int posOffset) { builder.AddStruct(0, posOffset, 0); } diff --git a/tests/MyGame/Example/Monster.java b/tests/MyGame/Example/Monster.java index 4b8bdac5d..0183a001b 100644 --- a/tests/MyGame/Example/Monster.java +++ b/tests/MyGame/Example/Monster.java @@ -16,18 +16,18 @@ public final class Monster extends Table { public Vec3 pos() { return pos(new Vec3()); } public Vec3 pos(Vec3 obj) { int o = __offset(4); return o != 0 ? obj.__init(o + bb_pos, bb) : null; } public short mana() { int o = __offset(6); return o != 0 ? bb.getShort(o + bb_pos) : 150; } - public boolean mutateMana(short mana) { int o = __offset(6); if (o != 0) { bb.putShort(o + bb_pos); return true } else { return false } } + public boolean mutateMana(short mana) { int o = __offset(6); if (o != 0) { bb.putShort(o + bb_pos, mana); return true; } else { return false; } } public short hp() { int o = __offset(8); return o != 0 ? bb.getShort(o + bb_pos) : 100; } - public boolean mutateHp(short hp) { int o = __offset(8); if (o != 0) { bb.putShort(o + bb_pos); return true } else { return false } } + public boolean mutateHp(short hp) { int o = __offset(8); if (o != 0) { bb.putShort(o + bb_pos, hp); return true; } else { return false; } } public String name() { int o = __offset(10); return o != 0 ? __string(o + bb_pos) : null; } public ByteBuffer nameAsByteBuffer() { return __vector_as_bytebuffer(10, 1); } public int inventory(int j) { int o = __offset(14); return o != 0 ? bb.get(__vector(o) + j * 1) & 0xFF : 0; } public int inventoryLength() { int o = __offset(14); return o != 0 ? __vector_len(o) : 0; } public ByteBuffer inventoryAsByteBuffer() { return __vector_as_bytebuffer(14, 1); } public byte color() { int o = __offset(16); return o != 0 ? bb.get(o + bb_pos) : 8; } - public boolean mutateColor(byte color) { int o = __offset(16); if (o != 0) { bb.put(o + bb_pos); return true } else { return false } } + public boolean mutateColor(byte color) { int o = __offset(16); if (o != 0) { bb.put(o + bb_pos, color); return true; } else { return false; } } public byte testType() { int o = __offset(18); return o != 0 ? bb.get(o + bb_pos) : 0; } - public boolean mutateTestType(byte test_type) { int o = __offset(18); if (o != 0) { bb.put(o + bb_pos); return true } else { return false } } + public boolean mutateTestType(byte test_type) { int o = __offset(18); if (o != 0) { bb.put(o + bb_pos, test_type); return true; } else { return false; } } public Table test(Table obj) { int o = __offset(20); return o != 0 ? __union(obj, o) : null; } public Test test4(int j) { return test4(new Test(), j); } public Test test4(Test obj, int j) { int o = __offset(22); return o != 0 ? obj.__init(__vector(o) + j * 4, bb) : null; } @@ -49,23 +49,23 @@ public final class Monster extends Table { public Stat testempty() { return testempty(new Stat()); } public Stat testempty(Stat obj) { int o = __offset(32); return o != 0 ? obj.__init(__indirect(o + bb_pos), bb) : null; } public boolean testbool() { int o = __offset(34); return o != 0 ? 0!=bb.get(o + bb_pos) : false; } - public boolean mutateTestbool(boolean testbool) { int o = __offset(34); if (o != 0) { bb.putBoolean(o + bb_pos); return true } else { return false } } + public boolean mutateTestbool(boolean testbool) { int o = __offset(34); if (o != 0) { bb.put(o + bb_pos, (byte)(testbool ? 1 : 0)); return true; } else { return false; } } public int testhashs32Fnv1() { int o = __offset(36); return o != 0 ? bb.getInt(o + bb_pos) : 0; } - public boolean mutateTesthashs32Fnv1(int testhashs32_fnv1) { int o = __offset(36); if (o != 0) { bb.putInt(o + bb_pos); return true } else { return false } } + public boolean mutateTesthashs32Fnv1(int testhashs32_fnv1) { int o = __offset(36); if (o != 0) { bb.putInt(o + bb_pos, testhashs32_fnv1); return true; } else { return false; } } public long testhashu32Fnv1() { int o = __offset(38); return o != 0 ? (long)bb.getInt(o + bb_pos) & 0xFFFFFFFFL : 0; } - public boolean mutateTesthashu32Fnv1(int testhashu32_fnv1) { int o = __offset(38); if (o != 0) { bb.putInt(o + bb_pos); return true } else { return false } } + public boolean mutateTesthashu32Fnv1(int testhashu32_fnv1) { int o = __offset(38); if (o != 0) { bb.putInt(o + bb_pos, testhashu32_fnv1); return true; } else { return false; } } public long testhashs64Fnv1() { int o = __offset(40); return o != 0 ? bb.getLong(o + bb_pos) : 0; } - public boolean mutateTesthashs64Fnv1(long testhashs64_fnv1) { int o = __offset(40); if (o != 0) { bb.putLong(o + bb_pos); return true } else { return false } } + public boolean mutateTesthashs64Fnv1(long testhashs64_fnv1) { int o = __offset(40); if (o != 0) { bb.putLong(o + bb_pos, testhashs64_fnv1); return true; } else { return false; } } public long testhashu64Fnv1() { int o = __offset(42); return o != 0 ? bb.getLong(o + bb_pos) : 0; } - public boolean mutateTesthashu64Fnv1(long testhashu64_fnv1) { int o = __offset(42); if (o != 0) { bb.putLong(o + bb_pos); return true } else { return false } } + public boolean mutateTesthashu64Fnv1(long testhashu64_fnv1) { int o = __offset(42); if (o != 0) { bb.putLong(o + bb_pos, testhashu64_fnv1); return true; } else { return false; } } public int testhashs32Fnv1a() { int o = __offset(44); return o != 0 ? bb.getInt(o + bb_pos) : 0; } - public boolean mutateTesthashs32Fnv1a(int testhashs32_fnv1a) { int o = __offset(44); if (o != 0) { bb.putInt(o + bb_pos); return true } else { return false } } + public boolean mutateTesthashs32Fnv1a(int testhashs32_fnv1a) { int o = __offset(44); if (o != 0) { bb.putInt(o + bb_pos, testhashs32_fnv1a); return true; } else { return false; } } public long testhashu32Fnv1a() { int o = __offset(46); return o != 0 ? (long)bb.getInt(o + bb_pos) & 0xFFFFFFFFL : 0; } - public boolean mutateTesthashu32Fnv1a(int testhashu32_fnv1a) { int o = __offset(46); if (o != 0) { bb.putInt(o + bb_pos); return true } else { return false } } + public boolean mutateTesthashu32Fnv1a(int testhashu32_fnv1a) { int o = __offset(46); if (o != 0) { bb.putInt(o + bb_pos, testhashu32_fnv1a); return true; } else { return false; } } public long testhashs64Fnv1a() { int o = __offset(48); return o != 0 ? bb.getLong(o + bb_pos) : 0; } - public boolean mutateTesthashs64Fnv1a(long testhashs64_fnv1a) { int o = __offset(48); if (o != 0) { bb.putLong(o + bb_pos); return true } else { return false } } + public boolean mutateTesthashs64Fnv1a(long testhashs64_fnv1a) { int o = __offset(48); if (o != 0) { bb.putLong(o + bb_pos, testhashs64_fnv1a); return true; } else { return false; } } public long testhashu64Fnv1a() { int o = __offset(50); return o != 0 ? bb.getLong(o + bb_pos) : 0; } - public boolean mutateTesthashu64Fnv1a(long testhashu64_fnv1a) { int o = __offset(50); if (o != 0) { bb.putLong(o + bb_pos); return true } else { return false } } + public boolean mutateTesthashu64Fnv1a(long testhashu64_fnv1a) { int o = __offset(50); if (o != 0) { bb.putLong(o + bb_pos, testhashu64_fnv1a); return true; } else { return false; } } public static void startMonster(FlatBufferBuilder builder) { builder.startObject(24); } public static void addPos(FlatBufferBuilder builder, int posOffset) { builder.addStruct(0, posOffset, 0); } diff --git a/tests/MyGame/Example/Stat.cs b/tests/MyGame/Example/Stat.cs index b0ad134d4..a1f310e39 100644 --- a/tests/MyGame/Example/Stat.cs +++ b/tests/MyGame/Example/Stat.cs @@ -12,9 +12,9 @@ public sealed class Stat : Table { public string Id { get { int o = __offset(4); return o != 0 ? __string(o + bb_pos) : null; } } 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); return true } else { return false } } + 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; } } - public bool MutateCount(ushort count) { int o = __offset(8); if (o != 0) { bb.PutUshort(o + bb_pos); return true } else { return false } } + public bool MutateCount(ushort count) { int o = __offset(8); if (o != 0) { bb.PutUshort(o + bb_pos, count); return true; } else { return false; } } public static int CreateStat(FlatBufferBuilder builder, int id = 0, diff --git a/tests/MyGame/Example/Stat.java b/tests/MyGame/Example/Stat.java index 7c78876a0..23cc42a36 100644 --- a/tests/MyGame/Example/Stat.java +++ b/tests/MyGame/Example/Stat.java @@ -15,9 +15,9 @@ public final class Stat extends Table { public String id() { int o = __offset(4); return o != 0 ? __string(o + bb_pos) : null; } public ByteBuffer idAsByteBuffer() { return __vector_as_bytebuffer(4, 1); } public long val() { int o = __offset(6); return o != 0 ? bb.getLong(o + bb_pos) : 0; } - public boolean mutateVal(long val) { int o = __offset(6); if (o != 0) { bb.putLong(o + bb_pos); return true } else { return false } } + public boolean mutateVal(long val) { int o = __offset(6); if (o != 0) { bb.putLong(o + bb_pos, val); return true; } else { return false; } } public int count() { int o = __offset(8); return o != 0 ? bb.getShort(o + bb_pos) & 0xFFFF : 0; } - public boolean mutateCount(short count) { int o = __offset(8); if (o != 0) { bb.putShort(o + bb_pos); return true } else { return false } } + public boolean mutateCount(short count) { int o = __offset(8); if (o != 0) { bb.putShort(o + bb_pos, count); return true; } else { return false; } } public static int createStat(FlatBufferBuilder builder, int id, diff --git a/tests/MyGame/Example/Test.cs b/tests/MyGame/Example/Test.cs index 4cddc369b..ff81c4595 100644 --- a/tests/MyGame/Example/Test.cs +++ b/tests/MyGame/Example/Test.cs @@ -9,9 +9,9 @@ public sealed class Test : Struct { public Test __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; } public short A { get { return bb.GetShort(bb_pos + 0); } } - public void MutateA(short a) { bb.PutShort(bb_pos + 0); } + public void MutateA(short a) { bb.PutShort(bb_pos + 0, a); } public sbyte B { get { return bb.GetSbyte(bb_pos + 2); } } - public void MutateB(sbyte b) { bb.PutSbyte(bb_pos + 2); } + public void MutateB(sbyte b) { bb.PutSbyte(bb_pos + 2, b); } public static int CreateTest(FlatBufferBuilder builder, short A, sbyte B) { builder.Prep(2, 4); diff --git a/tests/MyGame/Example/Test.java b/tests/MyGame/Example/Test.java index 0dc72a705..c4cd6aa9a 100644 --- a/tests/MyGame/Example/Test.java +++ b/tests/MyGame/Example/Test.java @@ -11,9 +11,9 @@ public final class Test extends Struct { public Test __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; } public short a() { return bb.getShort(bb_pos + 0); } - public void mutateA(short a) { bb.putShort(bb_pos + 0); } + public void mutateA(short a) { bb.putShort(bb_pos + 0, a); } public byte b() { return bb.get(bb_pos + 2); } - public void mutateB(byte b) { bb.put(bb_pos + 2); } + public void mutateB(byte b) { bb.put(bb_pos + 2, b); } public static int createTest(FlatBufferBuilder builder, short a, byte b) { builder.prep(2, 4); diff --git a/tests/MyGame/Example/Vec3.cs b/tests/MyGame/Example/Vec3.cs index 090dd1995..3582c0d06 100644 --- a/tests/MyGame/Example/Vec3.cs +++ b/tests/MyGame/Example/Vec3.cs @@ -9,15 +9,15 @@ public sealed class Vec3 : Struct { public Vec3 __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; } public float X { get { return bb.GetFloat(bb_pos + 0); } } - public void MutateX(float x) { bb.PutFloat(bb_pos + 0); } + public void MutateX(float x) { bb.PutFloat(bb_pos + 0, x); } public float Y { get { return bb.GetFloat(bb_pos + 4); } } - public void MutateY(float y) { bb.PutFloat(bb_pos + 4); } + public void MutateY(float y) { bb.PutFloat(bb_pos + 4, y); } public float Z { get { return bb.GetFloat(bb_pos + 8); } } - public void MutateZ(float z) { bb.PutFloat(bb_pos + 8); } + public void MutateZ(float z) { bb.PutFloat(bb_pos + 8, z); } public double Test1 { get { return bb.GetDouble(bb_pos + 16); } } - public void MutateTest1(double test1) { bb.PutDouble(bb_pos + 16); } + public void MutateTest1(double test1) { bb.PutDouble(bb_pos + 16, test1); } public Color Test2 { get { return (Color)bb.GetSbyte(bb_pos + 24); } } - public void MutateTest2(sbyte test2) { bb.PutSbyte(bb_pos + 24); } + public void MutateTest2(sbyte test2) { bb.PutSbyte(bb_pos + 24, test2); } public Test Test3 { get { return GetTest3(new Test()); } } public Test GetTest3(Test obj) { return obj.__init(bb_pos + 26, bb); } diff --git a/tests/MyGame/Example/Vec3.java b/tests/MyGame/Example/Vec3.java index df62cc8a4..457f57d77 100644 --- a/tests/MyGame/Example/Vec3.java +++ b/tests/MyGame/Example/Vec3.java @@ -11,15 +11,15 @@ public final class Vec3 extends Struct { public Vec3 __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; } public float x() { return bb.getFloat(bb_pos + 0); } - public void mutateX(float x) { bb.putFloat(bb_pos + 0); } + public void mutateX(float x) { bb.putFloat(bb_pos + 0, x); } public float y() { return bb.getFloat(bb_pos + 4); } - public void mutateY(float y) { bb.putFloat(bb_pos + 4); } + public void mutateY(float y) { bb.putFloat(bb_pos + 4, y); } public float z() { return bb.getFloat(bb_pos + 8); } - public void mutateZ(float z) { bb.putFloat(bb_pos + 8); } + public void mutateZ(float z) { bb.putFloat(bb_pos + 8, z); } public double test1() { return bb.getDouble(bb_pos + 16); } - public void mutateTest1(double test1) { bb.putDouble(bb_pos + 16); } + public void mutateTest1(double test1) { bb.putDouble(bb_pos + 16, test1); } public byte test2() { return bb.get(bb_pos + 24); } - public void mutateTest2(byte test2) { bb.put(bb_pos + 24); } + public void mutateTest2(byte test2) { bb.put(bb_pos + 24, test2); } public Test test3() { return test3(new Test()); } public Test test3(Test obj) { return obj.__init(bb_pos + 26, bb); } From f706a42951a9b91df2b681cb0a4df50d2bb2a2b7 Mon Sep 17 00:00:00 2001 From: Maor Itzkovitch Date: Sat, 1 Aug 2015 19:14:12 +0300 Subject: [PATCH 03/10] extend java tests --- tests/JavaTest.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/JavaTest.java b/tests/JavaTest.java index 9e8c77b7c..2344cf0e5 100755 --- a/tests/JavaTest.java +++ b/tests/JavaTest.java @@ -134,7 +134,9 @@ class JavaTest { TestEq(pos.x(), 55.0f); pos.mutateX(1.0f); TestEq(pos.x(), 1.0f); - + + TestBuffer(fbb.dataBuffer().asReadOnlyBuffer()); + System.out.println("FlatBuffers test: completed successfully"); } From 6be146d67ffd31b26751f32c1d3b96726a67c175 Mon Sep 17 00:00:00 2001 From: Maor Itzkovitch Date: Sat, 1 Aug 2015 19:28:22 +0300 Subject: [PATCH 04/10] small refactor to GenSetter method --- src/idl_gen_general.cpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/idl_gen_general.cpp b/src/idl_gen_general.cpp index 9bc1f7093..8749683fc 100644 --- a/src/idl_gen_general.cpp +++ b/src/idl_gen_general.cpp @@ -428,18 +428,19 @@ static std::string GenGetter(const LanguageParameters &lang, } } +// Direct mutation is only allowed for scalar fields. +// Hence a setter method will only be generated for such fields. static std::string GenSetter(const LanguageParameters &lang, const Type &type) { - switch (type.base_type) { - case BASE_TYPE_STRUCT: return ""; - default: { - std::string setter = "bb." + FunctionStart(lang, 'P') + "ut"; - if (GenTypeBasic(lang, type) != "byte" && - type.base_type != BASE_TYPE_BOOL) { - setter += MakeCamel(GenTypeGet(lang, type)); - } - return setter; + if (IsScalar(type.base_type)) { + std::string setter = "bb." + FunctionStart(lang, 'P') + "ut"; + if (GenTypeBasic(lang, type) != "byte" && + type.base_type != BASE_TYPE_BOOL) { + setter += MakeCamel(GenTypeGet(lang, type)); } + return setter; + } else { + return ""; } } From 7196c3684249c12571cd2e16ba8e5564c57484aa Mon Sep 17 00:00:00 2001 From: Maor Itzkovitch Date: Fri, 7 Aug 2015 09:05:08 +0300 Subject: [PATCH 05/10] begin to correct C# bytebuffer behavior --- src/idl_gen_general.cpp | 26 +++++++++++++++++++++++--- tests/JavaTest.java | 22 ++++++++++++++++------ tests/MyGame/Example/Monster.cs | 4 ++-- tests/MyGame/Example/Monster.java | 4 ++-- tests/MyGame/Example/Stat.java | 2 +- tests/MyGame/Example/Vec3.cs | 2 +- 6 files changed, 45 insertions(+), 15 deletions(-) diff --git a/src/idl_gen_general.cpp b/src/idl_gen_general.cpp index 8749683fc..81c0b5b77 100644 --- a/src/idl_gen_general.cpp +++ b/src/idl_gen_general.cpp @@ -330,6 +330,25 @@ static std::string DestinationValue(const LanguageParameters &lang, } } +static std::string SourceCast(const LanguageParameters &lang, + const Type &type) { + switch (lang.language) { + case GeneratorOptions::kJava: + if (type.base_type == BASE_TYPE_UINT) return "(int)"; + else if (type.base_type == BASE_TYPE_USHORT) return "(short)"; + else if (type.base_type == BASE_TYPE_UCHAR) return "(byte)"; + break; + case GeneratorOptions::kCSharp: + if (type.enum_def != nullptr && + type.base_type != BASE_TYPE_UNION) + return "(" + GenTypeGet(lang, type) + ")"; + break; + default: + break; + } + return ""; +} + static std::string GenDefaultValue(const Value &value) { return value.type.base_type == BASE_TYPE_BOOL ? (value.constant == "0" ? "false" : "true") @@ -570,6 +589,7 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser, std::string type_name_dest = GenTypeNameDest(lang, field.value.type); std::string dest_mask = DestinationMask(lang, field.value.type, true); std::string dest_cast = DestinationCast(lang, field.value.type); + std::string src_cast = SourceCast(lang, field.value.type); std::string method_start = " public " + type_name_dest + " " + MakeCamel(field.name, lang.first_camel_upper); // Most field accessors need to retrieve and test the field offset first, @@ -725,15 +745,15 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser, code += " public "; code += struct_def.fixed ? "void " : lang.bool_type; code += mutator_prefix + MakeCamel(field.name, true) + "("; - code += GenTypeBasic(lang, field.value.type); + code += GenTypeNameDest(lang, field.value.type); code += " " + field.name + ") { "; if (struct_def.fixed) { code += GenSetter(lang, field.value.type) + "(bb_pos + "; - code += NumToString(field.value.offset) + ", " + setter_parameter + "); }\n"; + code += NumToString(field.value.offset) + ", " + src_cast + setter_parameter + "); }\n"; } else { code += "int o = __offset(" + NumToString(field.value.offset) + ");"; code += " if (o != 0) { " + GenSetter(lang, field.value.type); - code += "(o + bb_pos, " + setter_parameter + "); return true; } else { return false; } }\n"; + code += "(o + bb_pos, " + src_cast + setter_parameter + "); return true; } else { return false; } }\n"; } } } diff --git a/tests/JavaTest.java b/tests/JavaTest.java index 2344cf0e5..6ac11eaf2 100755 --- a/tests/JavaTest.java +++ b/tests/JavaTest.java @@ -81,6 +81,7 @@ class JavaTest { Monster.addTest4(fbb, test4); Monster.addTestarrayofstring(fbb, testArrayOfString); Monster.addTestbool(fbb, false); + Monster.addTesthashu32Fnv1(fbb, Integer.MAX_VALUE + 1L); int mon = Monster.endMonster(fbb); Monster.finishMonsterBuffer(fbb, mon); @@ -101,12 +102,12 @@ class JavaTest { } // Test it: - TestBuffer(fbb.dataBuffer()); + TestExtendedBuffer(fbb.dataBuffer()); // Make sure it also works with read only ByteBuffers. This is slower, // since creating strings incurs an additional copy // (see Table.__string). - TestBuffer(fbb.dataBuffer().asReadOnlyBuffer()); + TestExtendedBuffer(fbb.dataBuffer().asReadOnlyBuffer()); TestEnums(); @@ -115,7 +116,7 @@ class JavaTest { Monster monster = Monster.getRootAsMonster(fbb.dataBuffer()); // mana is optional and does not exist in the buffer so the mutation should fail - // it should retain its default value + // the mana field should retain its default value TestEq(monster.mutateMana((short)10), false); TestEq(monster.mana(), (short)150); @@ -127,7 +128,6 @@ class JavaTest { TestEq(monster.testType(), (byte)Any.Monster); // get a struct field and edit one of its fields - // Vec3 pos = monster.pos(); TestEq(pos.x(), 1.0f); pos.mutateX(55.0f); @@ -135,7 +135,7 @@ class JavaTest { pos.mutateX(1.0f); TestEq(pos.x(), 1.0f); - TestBuffer(fbb.dataBuffer().asReadOnlyBuffer()); + TestExtendedBuffer(fbb.dataBuffer().asReadOnlyBuffer()); System.out.println("FlatBuffers test: completed successfully"); } @@ -149,7 +149,7 @@ class JavaTest { static void TestBuffer(ByteBuffer bb) { TestEq(Monster.MonsterBufferHasIdentifier(bb), true); - + Monster monster = Monster.getRootAsMonster(bb); TestEq(monster.hp(), (short)80); @@ -198,6 +198,16 @@ class JavaTest { TestEq(monster.testbool(), false); } + // this method checks additional fields not present in the binary buffer read from file + // these new tests are performed on top of the regular tests + static void TestExtendedBuffer(ByteBuffer bb) { + TestBuffer(bb); + + Monster monster = Monster.getRootAsMonster(bb); + + TestEq(monster.testhashu32Fnv1(), Integer.MAX_VALUE + 1L); + } + static void TestEq(T a, T b) { if (!a.equals(b)) { System.out.println("" + a.getClass().getName() + " " + b.getClass().getName()); diff --git a/tests/MyGame/Example/Monster.cs b/tests/MyGame/Example/Monster.cs index 593210b34..e97ae4af6 100644 --- a/tests/MyGame/Example/Monster.cs +++ b/tests/MyGame/Example/Monster.cs @@ -21,9 +21,9 @@ public sealed class Monster : Table { 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 Color Color { get { int o = __offset(16); return o != 0 ? (Color)bb.GetSbyte(o + bb_pos) : (Color)8; } } - public bool MutateColor(sbyte color) { int o = __offset(16); if (o != 0) { bb.PutSbyte(o + bb_pos, color); return true; } else { return false; } } + public bool MutateColor(Color color) { int o = __offset(16); if (o != 0) { bb.PutSbyte(o + bb_pos, (sbyte)color); return true; } else { return false; } } public Any TestType { get { int o = __offset(18); return o != 0 ? (Any)bb.Get(o + bb_pos) : (Any)0; } } - public bool MutateTestType(byte test_type) { int o = __offset(18); if (o != 0) { bb.Put(o + bb_pos, test_type); return true; } else { return false; } } + public bool MutateTestType(Any test_type) { int o = __offset(18); if (o != 0) { bb.Put(o + bb_pos, (byte)test_type); return true; } else { return false; } } public TTable GetTest(TTable obj) where TTable : Table { int o = __offset(20); return o != 0 ? __union(obj, o) : null; } public Test GetTest4(int j) { return GetTest4(new Test(), j); } public Test GetTest4(Test obj, int j) { int o = __offset(22); return o != 0 ? obj.__init(__vector(o) + j * 4, bb) : null; } diff --git a/tests/MyGame/Example/Monster.java b/tests/MyGame/Example/Monster.java index 0183a001b..ad64e786d 100644 --- a/tests/MyGame/Example/Monster.java +++ b/tests/MyGame/Example/Monster.java @@ -53,7 +53,7 @@ public final class Monster extends Table { public int testhashs32Fnv1() { int o = __offset(36); return o != 0 ? bb.getInt(o + bb_pos) : 0; } public boolean mutateTesthashs32Fnv1(int testhashs32_fnv1) { int o = __offset(36); if (o != 0) { bb.putInt(o + bb_pos, testhashs32_fnv1); return true; } else { return false; } } public long testhashu32Fnv1() { int o = __offset(38); return o != 0 ? (long)bb.getInt(o + bb_pos) & 0xFFFFFFFFL : 0; } - public boolean mutateTesthashu32Fnv1(int testhashu32_fnv1) { int o = __offset(38); if (o != 0) { bb.putInt(o + bb_pos, testhashu32_fnv1); return true; } else { return false; } } + public boolean mutateTesthashu32Fnv1(long testhashu32_fnv1) { int o = __offset(38); if (o != 0) { bb.putInt(o + bb_pos, (int)testhashu32_fnv1); return true; } else { return false; } } public long testhashs64Fnv1() { int o = __offset(40); return o != 0 ? bb.getLong(o + bb_pos) : 0; } public boolean mutateTesthashs64Fnv1(long testhashs64_fnv1) { int o = __offset(40); if (o != 0) { bb.putLong(o + bb_pos, testhashs64_fnv1); return true; } else { return false; } } public long testhashu64Fnv1() { int o = __offset(42); return o != 0 ? bb.getLong(o + bb_pos) : 0; } @@ -61,7 +61,7 @@ public final class Monster extends Table { public int testhashs32Fnv1a() { int o = __offset(44); return o != 0 ? bb.getInt(o + bb_pos) : 0; } public boolean mutateTesthashs32Fnv1a(int testhashs32_fnv1a) { int o = __offset(44); if (o != 0) { bb.putInt(o + bb_pos, testhashs32_fnv1a); return true; } else { return false; } } public long testhashu32Fnv1a() { int o = __offset(46); return o != 0 ? (long)bb.getInt(o + bb_pos) & 0xFFFFFFFFL : 0; } - public boolean mutateTesthashu32Fnv1a(int testhashu32_fnv1a) { int o = __offset(46); if (o != 0) { bb.putInt(o + bb_pos, testhashu32_fnv1a); return true; } else { return false; } } + public boolean mutateTesthashu32Fnv1a(long testhashu32_fnv1a) { int o = __offset(46); if (o != 0) { bb.putInt(o + bb_pos, (int)testhashu32_fnv1a); return true; } else { return false; } } public long testhashs64Fnv1a() { int o = __offset(48); return o != 0 ? bb.getLong(o + bb_pos) : 0; } public boolean mutateTesthashs64Fnv1a(long testhashs64_fnv1a) { int o = __offset(48); if (o != 0) { bb.putLong(o + bb_pos, testhashs64_fnv1a); return true; } else { return false; } } public long testhashu64Fnv1a() { int o = __offset(50); return o != 0 ? bb.getLong(o + bb_pos) : 0; } diff --git a/tests/MyGame/Example/Stat.java b/tests/MyGame/Example/Stat.java index 23cc42a36..673729e19 100644 --- a/tests/MyGame/Example/Stat.java +++ b/tests/MyGame/Example/Stat.java @@ -17,7 +17,7 @@ public final class Stat extends Table { public long val() { int o = __offset(6); return o != 0 ? bb.getLong(o + bb_pos) : 0; } public boolean mutateVal(long val) { int o = __offset(6); if (o != 0) { bb.putLong(o + bb_pos, val); return true; } else { return false; } } public int count() { int o = __offset(8); return o != 0 ? bb.getShort(o + bb_pos) & 0xFFFF : 0; } - public boolean mutateCount(short count) { int o = __offset(8); if (o != 0) { bb.putShort(o + bb_pos, count); return true; } else { return false; } } + public boolean mutateCount(int count) { int o = __offset(8); if (o != 0) { bb.putShort(o + bb_pos, (short)count); return true; } else { return false; } } public static int createStat(FlatBufferBuilder builder, int id, diff --git a/tests/MyGame/Example/Vec3.cs b/tests/MyGame/Example/Vec3.cs index 3582c0d06..55c466d42 100644 --- a/tests/MyGame/Example/Vec3.cs +++ b/tests/MyGame/Example/Vec3.cs @@ -17,7 +17,7 @@ public sealed class Vec3 : Struct { public double Test1 { get { return bb.GetDouble(bb_pos + 16); } } public void MutateTest1(double test1) { bb.PutDouble(bb_pos + 16, test1); } public Color Test2 { get { return (Color)bb.GetSbyte(bb_pos + 24); } } - public void MutateTest2(sbyte test2) { bb.PutSbyte(bb_pos + 24, test2); } + public void MutateTest2(Color test2) { bb.PutSbyte(bb_pos + 24, (sbyte)test2); } public Test Test3 { get { return GetTest3(new Test()); } } public Test GetTest3(Test obj) { return obj.__init(bb_pos + 26, bb); } From e4c3bf3d2cec00522fd1a8edd8704413cdc1303b Mon Sep 17 00:00:00 2001 From: Maor Itzkovitch Date: Fri, 7 Aug 2015 10:51:15 +0300 Subject: [PATCH 06/10] fixed C# bytebuffer put methods --- net/FlatBuffers/ByteBuffer.cs | 14 +++++---- net/FlatBuffers/FlatBufferBuilder.cs | 7 +++-- .../FlatBuffersExampleTests.cs | 29 +++++++++++++++++-- 3 files changed, 39 insertions(+), 11 deletions(-) diff --git a/net/FlatBuffers/ByteBuffer.cs b/net/FlatBuffers/ByteBuffer.cs index 1ea040278..fcdf8a1da 100755 --- a/net/FlatBuffers/ByteBuffer.cs +++ b/net/FlatBuffers/ByteBuffer.cs @@ -35,13 +35,18 @@ namespace FlatBuffers public byte[] Data { get { return _buffer; } } - public ByteBuffer(byte[] buffer) + public ByteBuffer(byte[] buffer) : this(buffer, 0) { } + + public ByteBuffer(byte[] buffer, int pos) { _buffer = buffer; - _pos = 0; + _pos = pos; } - public int Position { get { return _pos; } } + public int Position { + get { return _pos; } + set { _pos = value; } + } // Pre-allocated helper arrays for convertion. private float[] floathelper = new[] { 0.0f }; @@ -92,7 +97,6 @@ namespace FlatBuffers _buffer[offset + count - 1 - i] = (byte)(data >> i * 8); } } - _pos = offset; } protected ulong ReadLittleEndian(int offset, int count) @@ -129,14 +133,12 @@ namespace FlatBuffers { AssertOffsetAndLength(offset, sizeof(sbyte)); _buffer[offset] = (byte)value; - _pos = offset; } public void PutByte(int offset, byte value) { AssertOffsetAndLength(offset, sizeof(byte)); _buffer[offset] = value; - _pos = offset; } // this method exists in order to conform with Java ByteBuffer standards diff --git a/net/FlatBuffers/FlatBufferBuilder.cs b/net/FlatBuffers/FlatBufferBuilder.cs index 453b6e5cd..4d43d0dcb 100644 --- a/net/FlatBuffers/FlatBufferBuilder.cs +++ b/net/FlatBuffers/FlatBufferBuilder.cs @@ -75,8 +75,8 @@ namespace FlatBuffers Buffer.BlockCopy(oldBuf, 0, newBuf, newBufSize - oldBufSize, oldBufSize); - - _bb = new ByteBuffer(newBuf); + _bb = new ByteBuffer(newBuf, newBufSize); + System.Diagnostics.Debug.WriteLine(_bb.Position); } // Prepare to write an element of `size` after `additional_bytes` @@ -359,6 +359,7 @@ namespace FlatBuffers { Prep(_minAlign, sizeof(int)); AddOffset(rootTable); + _bb.Position = _space; } public ByteBuffer DataBuffer { get { return _bb; } } @@ -387,7 +388,7 @@ namespace FlatBuffers { AddByte((byte)fileIdentifier[i]); } - AddOffset(rootTable); + Finish(rootTable); } diff --git a/tests/FlatBuffers.Test/FlatBuffersExampleTests.cs b/tests/FlatBuffers.Test/FlatBuffersExampleTests.cs index 2066bc617..ddeda7a66 100644 --- a/tests/FlatBuffers.Test/FlatBuffersExampleTests.cs +++ b/tests/FlatBuffers.Test/FlatBuffersExampleTests.cs @@ -65,7 +65,6 @@ namespace FlatBuffers.Test fbb.AddOffset(test1); var testArrayOfString = fbb.EndVector(); - Monster.StartMonster(fbb); Monster.AddPos(fbb, Vec3.CreateVec3(fbb, 1.0f, 2.0f, 3.0f, 3.0, Color.Green, (short)5, (sbyte)6)); @@ -79,7 +78,7 @@ namespace FlatBuffers.Test Monster.AddTestbool(fbb, false); var mon = Monster.EndMonster(fbb); - fbb.Finish(mon); + Monster.FinishMonsterBuffer(fbb, mon); // Dump to output directory so we can inspect later, if needed using (var ms = new MemoryStream(fbb.DataBuffer.Data, fbb.DataBuffer.Position, fbb.Offset)) @@ -90,6 +89,32 @@ namespace FlatBuffers.Test // Now assert the buffer TestBuffer(fbb.DataBuffer); + + //Attempt to mutate Monster fields and check whether the buffer has been mutated properly + // revert to original values after testing + Monster monster = Monster.GetRootAsMonster(fbb.DataBuffer); + + // mana is optional and does not exist in the buffer so the mutation should fail + // the mana field should retain its default value + Assert.AreEqual(monster.MutateMana((short)10), false); + Assert.AreEqual(monster.Mana, (short)150); + + // testType is an existing field and mutating it should succeed + Assert.AreEqual(monster.TestType, Any.Monster); + Assert.AreEqual(monster.MutateTestType(Any.NONE), true); + Assert.AreEqual(monster.TestType, Any.NONE); + Assert.AreEqual(monster.MutateTestType(Any.Monster), true); + Assert.AreEqual(monster.TestType, Any.Monster); + + // get a struct field and edit one of its fields + Vec3 pos = monster.Pos; + Assert.AreEqual(pos.X, 1.0f); + pos.MutateX(55.0f); + Assert.AreEqual(pos.X, 55.0f); + pos.MutateX(1.0f); + Assert.AreEqual(pos.X, 1.0f); + + TestBuffer(fbb.DataBuffer); } private void TestBuffer(ByteBuffer bb) From 3a74c33ba55adc08386fa0b81fc64d042898cb87 Mon Sep 17 00:00:00 2001 From: Maor Itzkovitch Date: Fri, 7 Aug 2015 10:57:37 +0300 Subject: [PATCH 07/10] removed console print from code --- net/FlatBuffers/FlatBufferBuilder.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/net/FlatBuffers/FlatBufferBuilder.cs b/net/FlatBuffers/FlatBufferBuilder.cs index 4d43d0dcb..8008f5ce7 100644 --- a/net/FlatBuffers/FlatBufferBuilder.cs +++ b/net/FlatBuffers/FlatBufferBuilder.cs @@ -76,7 +76,6 @@ namespace FlatBuffers Buffer.BlockCopy(oldBuf, 0, newBuf, newBufSize - oldBufSize, oldBufSize); _bb = new ByteBuffer(newBuf, newBufSize); - System.Diagnostics.Debug.WriteLine(_bb.Position); } // Prepare to write an element of `size` after `additional_bytes` From 766eaad4e7ac70decae67d0780bea6f3da8e2c18 Mon Sep 17 00:00:00 2001 From: Maor Itzkovitch Date: Fri, 7 Aug 2015 18:12:19 +0300 Subject: [PATCH 08/10] added a successful test run console print --- tests/FlatBuffers.Test/Program.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/FlatBuffers.Test/Program.cs b/tests/FlatBuffers.Test/Program.cs index 6006004a7..91cb6941e 100644 --- a/tests/FlatBuffers.Test/Program.cs +++ b/tests/FlatBuffers.Test/Program.cs @@ -56,6 +56,7 @@ namespace FlatBuffers.Test } + Console.WriteLine("FlatBuffers test: completed successfully"); return 0; } } From 0956719726f444f5e6c3c7e34fc6f7745756e2f8 Mon Sep 17 00:00:00 2001 From: Maor Itzkovitch Date: Fri, 7 Aug 2015 18:35:28 +0300 Subject: [PATCH 09/10] added comments --- src/idl_gen_general.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/idl_gen_general.cpp b/src/idl_gen_general.cpp index 81c0b5b77..faa97059a 100644 --- a/src/idl_gen_general.cpp +++ b/src/idl_gen_general.cpp @@ -330,6 +330,10 @@ static std::string DestinationValue(const LanguageParameters &lang, } } +// Cast statements for mutator method parameters. +// In Java, parameters representing unsigned numbers need to be cast down to their respective type. +// For example, a long holding an unsigned int value would be cast down to int before being put onto the buffer. +// In C#, one cast directly cast an Enum to its underlying type, which is essential before putting it onto the buffer. static std::string SourceCast(const LanguageParameters &lang, const Type &type) { switch (lang.language) { From 7bfed4b29a425b183e2774919ced9e0402fdda10 Mon Sep 17 00:00:00 2001 From: Maor Itzkovitch Date: Sat, 15 Aug 2015 14:48:47 +0300 Subject: [PATCH 10/10] added vector mutators --- docs/source/JavaUsage.md | 45 ++++++++++++ src/idl_gen_general.cpp | 70 ++++++++++++------- .../FlatBuffersExampleTests.cs | 19 +++++ tests/JavaTest.java | 18 +++++ tests/MyGame/Example/Monster.cs | 2 + tests/MyGame/Example/Monster.java | 2 + 6 files changed, 130 insertions(+), 26 deletions(-) diff --git a/docs/source/JavaUsage.md b/docs/source/JavaUsage.md index 6ffb14b71..4819e5b79 100755 --- a/docs/source/JavaUsage.md +++ b/docs/source/JavaUsage.md @@ -177,3 +177,48 @@ There currently is no support for parsing text (Schema's and JSON) directly from Java or C#, though you could use the C++ parser through native call interfaces available to each language. Please see the C++ documentation for more on text parsing. + +### Mutating FlatBuffers + +As you saw above, typically once you have created a FlatBuffer, it is +read-only from that moment on. There are however cases where you have just +received a FlatBuffer, and you'd like to modify something about it before +sending it on to another recipient. With the above functionality, you'd have +to generate an entirely new FlatBuffer, while tracking what you modify in your +own data structures. This is inconvenient. + +For this reason FlatBuffers can also be mutated in-place. While this is great +for making small fixes to an existing buffer, you generally want to create +buffers from scratch whenever possible, since it is much more efficient and +the API is much more general purpose. + +To get non-const accessors, invoke `flatc` with `--gen-mutable`. + +You now can: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.java} + Monster monster = Monster.getRootAsMonster(bb); + monster.mutateHp(10); // Set table field. + monster.pos().mutateZ(4); // Set struct field. + monster.mutateInventory(0, 1); // Set vector element. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +We use the somewhat verbose term `mutate` instead of `set` to indicate that +this is a special use case, not to be confused with the default way of +constructing FlatBuffer data. + +After the above mutations, you can send on the FlatBuffer to a new recipient +without any further work! + +Note that any `mutate` functions on tables return a boolean, which is false +if the field we're trying to set isn't present in the buffer. Fields are not +present if they weren't set, or even if they happen to be equal to the +default value. For example, in the creation code above we set the `mana` field +to `150`, which is the default value, so it was never stored in the buffer. +Trying to call mutateMana() on such data will return false, and the value won't +actually be modified! + +One way to solve this is to call `forceDefaults()` on a +`FlatBufferBuilder` to force all fields you set to actually be written. This +of course increases the size of the buffer somewhat, but this may be +acceptable for a mutable buffer. diff --git a/src/idl_gen_general.cpp b/src/idl_gen_general.cpp index fb55a80cf..86440b153 100644 --- a/src/idl_gen_general.cpp +++ b/src/idl_gen_general.cpp @@ -252,7 +252,7 @@ static Type DestinationType(const LanguageParameters &lang, const Type &type, bool vectorelem) { if (lang.language != GeneratorOptions::kJava) return type; switch (type.base_type) { - case BASE_TYPE_UCHAR: return Type(BASE_TYPE_INT); + case BASE_TYPE_UCHAR: return Type(BASE_TYPE_INT); //intentionally returns int to avoid unnecessary casting in Java case BASE_TYPE_USHORT: return Type(BASE_TYPE_INT); case BASE_TYPE_UINT: return Type(BASE_TYPE_LONG); case BASE_TYPE_VECTOR: @@ -367,21 +367,25 @@ static std::string DestinationValue(const LanguageParameters &lang, // In C#, one cast directly cast an Enum to its underlying type, which is essential before putting it onto the buffer. static std::string SourceCast(const LanguageParameters &lang, const Type &type) { - switch (lang.language) { - case GeneratorOptions::kJava: - if (type.base_type == BASE_TYPE_UINT) return "(int)"; - else if (type.base_type == BASE_TYPE_USHORT) return "(short)"; - else if (type.base_type == BASE_TYPE_UCHAR) return "(byte)"; - break; - case GeneratorOptions::kCSharp: - if (type.enum_def != nullptr && - type.base_type != BASE_TYPE_UNION) - return "(" + GenTypeGet(lang, type) + ")"; - break; - default: - break; + if (type.base_type == BASE_TYPE_VECTOR) { + return SourceCast(lang, type.VectorType()); + } else { + switch (lang.language) { + case GeneratorOptions::kJava: + if (type.base_type == BASE_TYPE_UINT) return "(int)"; + else if (type.base_type == BASE_TYPE_USHORT) return "(short)"; + else if (type.base_type == BASE_TYPE_UCHAR) return "(byte)"; + break; + case GeneratorOptions::kCSharp: + if (type.enum_def != nullptr && + type.base_type != BASE_TYPE_UNION) + return "(" + GenTypeGet(lang, type) + ")"; + break; + default: + break; + } + return ""; } - return ""; } static std::string GenDefaultValue(const LanguageParameters &lang, const Value &value, bool for_buffer) { @@ -640,6 +644,7 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser, std::string src_cast = SourceCast(lang, field.value.type); std::string method_start = " public " + type_name_dest + " " + MakeCamel(field.name, lang.first_camel_upper); + // Most field accessors need to retrieve and test the field offset first, // this is the prefix code for that: auto offset_prefix = " { int o = __offset(" + @@ -784,24 +789,37 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser, code += "); }\n"; } - // generate mutators for scalar fields + // generate mutators for scalar fields or vectors of scalars if (opts.mutable_buffer) { + auto underlying_type = field.value.type.base_type == BASE_TYPE_VECTOR + ? field.value.type.VectorType() + : field.value.type; // boolean parameters have to be explicitly converted to byte representation - std::string setter_parameter = field.value.type.base_type == BASE_TYPE_BOOL ? "(byte)(" + field.name + " ? 1 : 0)" : field.name; - std::string mutator_prefix = MakeCamel("mutate", lang.first_camel_upper); - if (IsScalar(field.value.type.base_type)) { + auto setter_parameter = underlying_type.base_type == BASE_TYPE_BOOL ? "(byte)(" + field.name + " ? 1 : 0)" : field.name; + auto mutator_prefix = MakeCamel("mutate", lang.first_camel_upper); + //a vector mutator also needs the index of the vector element it should mutate + auto mutator_params = (field.value.type.base_type == BASE_TYPE_VECTOR ? "(int j, " : "(") + + GenTypeNameDest(lang, underlying_type) + " " + + field.name + ") { "; + auto setter_index = field.value.type.base_type == BASE_TYPE_VECTOR + ? "__vector(o) + j * " + NumToString(InlineSize(underlying_type)) + : (struct_def.fixed ? "bb_pos + " + NumToString(field.value.offset) : "o + bb_pos"); + + + if (IsScalar(field.value.type.base_type) || + (field.value.type.base_type == BASE_TYPE_VECTOR && + IsScalar(field.value.type.VectorType().base_type))) { code += " public "; code += struct_def.fixed ? "void " : lang.bool_type; - code += mutator_prefix + MakeCamel(field.name, true) + "("; - code += GenTypeNameDest(lang, field.value.type); - code += " " + field.name + ") { "; + code += mutator_prefix + MakeCamel(field.name, true); + code += mutator_params; if (struct_def.fixed) { - code += GenSetter(lang, field.value.type) + "(bb_pos + "; - code += NumToString(field.value.offset) + ", " + src_cast + setter_parameter + "); }\n"; + code += GenSetter(lang, underlying_type) + "(" + setter_index + ", "; + code += src_cast + setter_parameter + "); }\n"; } else { code += "int o = __offset(" + NumToString(field.value.offset) + ");"; - code += " if (o != 0) { " + GenSetter(lang, field.value.type); - code += "(o + bb_pos, " + src_cast + setter_parameter + "); return true; } else { return false; } }\n"; + code += " if (o != 0) { " + GenSetter(lang, underlying_type); + code += "(" + setter_index + ", " + src_cast + setter_parameter + "); return true; } else { return false; } }\n"; } } } diff --git a/tests/FlatBuffers.Test/FlatBuffersExampleTests.cs b/tests/FlatBuffers.Test/FlatBuffersExampleTests.cs index 436180caf..666ac1c6a 100644 --- a/tests/FlatBuffers.Test/FlatBuffersExampleTests.cs +++ b/tests/FlatBuffers.Test/FlatBuffersExampleTests.cs @@ -107,6 +107,25 @@ namespace FlatBuffers.Test Assert.AreEqual(monster.MutateTestType(Any.Monster), true); Assert.AreEqual(monster.TestType, Any.Monster); + //mutate the inventory vector + Assert.AreEqual(monster.MutateInventory(0, 1), true); + Assert.AreEqual(monster.MutateInventory(1, 2), true); + Assert.AreEqual(monster.MutateInventory(2, 3), true); + Assert.AreEqual(monster.MutateInventory(3, 4), true); + Assert.AreEqual(monster.MutateInventory(4, 5), true); + + for (int i = 0; i < monster.InventoryLength; i++) + { + Assert.AreEqual(monster.GetInventory(i), i + 1); + } + + //reverse mutation + Assert.AreEqual(monster.MutateInventory(0, 0), true); + Assert.AreEqual(monster.MutateInventory(1, 1), true); + Assert.AreEqual(monster.MutateInventory(2, 2), true); + Assert.AreEqual(monster.MutateInventory(3, 3), true); + Assert.AreEqual(monster.MutateInventory(4, 4), true); + // get a struct field and edit one of its fields Vec3 pos = monster.Pos; Assert.AreEqual(pos.X, 1.0f); diff --git a/tests/JavaTest.java b/tests/JavaTest.java index 6ac11eaf2..e01701699 100755 --- a/tests/JavaTest.java +++ b/tests/JavaTest.java @@ -127,6 +127,24 @@ class JavaTest { TestEq(monster.mutateTestType(Any.Monster), true); TestEq(monster.testType(), (byte)Any.Monster); + //mutate the inventory vector + TestEq(monster.mutateInventory(0, 1), true); + TestEq(monster.mutateInventory(1, 2), true); + TestEq(monster.mutateInventory(2, 3), true); + TestEq(monster.mutateInventory(3, 4), true); + TestEq(monster.mutateInventory(4, 5), true); + + for (int i = 0; i < monster.inventoryLength(); i++) { + TestEq(monster.inventory(i), i + 1); + } + + //reverse mutation + TestEq(monster.mutateInventory(0, 0), true); + TestEq(monster.mutateInventory(1, 1), true); + TestEq(monster.mutateInventory(2, 2), true); + TestEq(monster.mutateInventory(3, 3), true); + TestEq(monster.mutateInventory(4, 4), true); + // get a struct field and edit one of its fields Vec3 pos = monster.pos(); TestEq(pos.x(), 1.0f); diff --git a/tests/MyGame/Example/Monster.cs b/tests/MyGame/Example/Monster.cs index ef0ef92ec..975e4d085 100644 --- a/tests/MyGame/Example/Monster.cs +++ b/tests/MyGame/Example/Monster.cs @@ -20,6 +20,7 @@ public sealed class Monster : Table { public string Name { get { int o = __offset(10); return o != 0 ? __string(o + bb_pos) : null; } } 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 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)8; } } public bool MutateColor(Color color) { int o = __offset(16); if (o != 0) { bb.PutSbyte(o + bb_pos, (sbyte)color); return true; } else { return false; } } public Any TestType { get { int o = __offset(18); return o != 0 ? (Any)bb.Get(o + bb_pos) : (Any)0; } } @@ -39,6 +40,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 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; } public bool Testbool { get { int o = __offset(34); return o != 0 ? 0!=bb.Get(o + bb_pos) : (bool)false; } } diff --git a/tests/MyGame/Example/Monster.java b/tests/MyGame/Example/Monster.java index ad64e786d..0a5f7dde0 100644 --- a/tests/MyGame/Example/Monster.java +++ b/tests/MyGame/Example/Monster.java @@ -24,6 +24,7 @@ public final class Monster extends Table { public int inventory(int j) { int o = __offset(14); return o != 0 ? bb.get(__vector(o) + j * 1) & 0xFF : 0; } public int inventoryLength() { int o = __offset(14); return o != 0 ? __vector_len(o) : 0; } public ByteBuffer inventoryAsByteBuffer() { return __vector_as_bytebuffer(14, 1); } + public boolean mutateInventory(int j, int inventory) { int o = __offset(14); if (o != 0) { bb.put(__vector(o) + j * 1, (byte)inventory); return true; } else { return false; } } public byte color() { int o = __offset(16); return o != 0 ? bb.get(o + bb_pos) : 8; } public boolean mutateColor(byte color) { int o = __offset(16); if (o != 0) { bb.put(o + bb_pos, color); return true; } else { return false; } } public byte testType() { int o = __offset(18); return o != 0 ? bb.get(o + bb_pos) : 0; } @@ -46,6 +47,7 @@ public final class Monster extends Table { public int testnestedflatbuffer(int j) { int o = __offset(30); return o != 0 ? bb.get(__vector(o) + j * 1) & 0xFF : 0; } public int testnestedflatbufferLength() { int o = __offset(30); return o != 0 ? __vector_len(o) : 0; } public ByteBuffer testnestedflatbufferAsByteBuffer() { return __vector_as_bytebuffer(30, 1); } + public boolean mutateTestnestedflatbuffer(int j, int testnestedflatbuffer) { int o = __offset(30); if (o != 0) { bb.put(__vector(o) + j * 1, (byte)testnestedflatbuffer); return true; } else { return false; } } public Stat testempty() { return testempty(new Stat()); } public Stat testempty(Stat obj) { int o = __offset(32); return o != 0 ? obj.__init(__indirect(o + bb_pos), bb) : null; } public boolean testbool() { int o = __offset(34); return o != 0 ? 0!=bb.get(o + bb_pos) : false; }