From 81c2b185efcc729777d86815577cd6ebdd7e15c4 Mon Sep 17 00:00:00 2001
From: Maor Itzkovitch <maor.tt@gmail.com>
Date: Sat, 1 Aug 2015 12:38:47 +0300
Subject: [PATCH] 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 a5b7af77..0c733f34 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 a427c664..a029b040 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>(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 6d1c02f0..4b8bdac5 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 38d7ad39..b0ad134d 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 e1663c19..7c78876a 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 32de138d..4cddc369 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 d4e4094c..0dc72a70 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 732f2d65..090dd199 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 794eea1d..df62cc8a 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); }
 
-- 
GitLab