Unsigned types in Java now return bigger size signed types.
authorWouter van Oortmerssen <wvo@google.com>
Thu, 19 Mar 2015 00:52:39 +0000 (17:52 -0700)
committerWouter van Oortmerssen <wvo@google.com>
Tue, 24 Mar 2015 00:01:33 +0000 (17:01 -0700)
(Java doesn't support unsigned types).

ubyte/ushort return as int
uint returns as long
(all with correct masking)

ulong still returns as long, as before.

Tested: on Linux & Windows.
Bug 17521464

Change-Id: Id6bc8f38fc8c1a2f4e6733c6980dc6b6e322b452

src/idl_gen_general.cpp
tests/MyGame/Example/Monster.java
tests/MyGame/Example/Stat.cs
tests/MyGame/Example/Stat.go
tests/MyGame/Example/Stat.java
tests/monster_test.fbs
tests/monster_test_generated.h

index bc6f7b9..69c7313 100644 (file)
@@ -167,6 +167,51 @@ static std::string GenTypeGet(const LanguageParameters &lang,
     : GenTypePointer(lang, type);
 }
 
+// Find the destination type the user wants to receive the value in (e.g.
+// one size higher signed types for unsigned serialized values in Java).
+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_USHORT: return Type(BASE_TYPE_INT);
+    case BASE_TYPE_UINT:   return Type(BASE_TYPE_LONG);
+    case BASE_TYPE_VECTOR:
+      if (vectorelem)
+        return DestinationType(lang, type.VectorType(), vectorelem);
+      // else fall thru:
+    default: return type;
+  }
+}
+
+// Mask to turn serialized value into destination type value.
+static std::string DestinationMask(const LanguageParameters &lang,
+                                   const Type &type, bool vectorelem) {
+  if (lang.language != GeneratorOptions::kJava) return "";
+  switch (type.base_type) {
+    case BASE_TYPE_UCHAR:  return " & 0xFF";
+    case BASE_TYPE_USHORT: return " & 0xFFFF";
+    case BASE_TYPE_UINT:   return " & 0xFFFFFFFFL";
+    case BASE_TYPE_VECTOR:
+      if (vectorelem)
+        return DestinationMask(lang, type.VectorType(), vectorelem);
+      // else fall thru:
+    default: return "";
+  }
+}
+
+// Cast necessary to correctly read serialized unsigned values.
+static std::string DestinationCast(const LanguageParameters &lang,
+                                   const Type &type) {
+  if (lang.language == GeneratorOptions::kJava &&
+      (type.base_type == BASE_TYPE_UINT ||
+       (type.base_type == BASE_TYPE_VECTOR &&
+        type.element == BASE_TYPE_UINT))) return "(long)";
+  return "";
+}
+
+
+
 static std::string GenDefaultValue(const Value &value) {
   return value.type.base_type == BASE_TYPE_BOOL
            ? (value.constant == "0" ? "false" : "true")
@@ -276,7 +321,11 @@ static void GenStructArgs(const LanguageParameters &lang,
       GenStructArgs(lang, *field.value.type.struct_def, code_ptr,
                     (field.value.type.struct_def->name + "_").c_str());
     } else {
-      code += ", " + GenTypeBasic(lang, field.value.type) + " " + nameprefix;
+      code += ", ";
+      code += GenTypeBasic(lang,
+                           DestinationType(lang, field.value.type, false));
+      code += " ";
+      code += nameprefix;
       code += MakeCamel(field.name, lang.first_camel_upper);
     }
   }
@@ -304,8 +353,16 @@ static void GenStructBody(const LanguageParameters &lang,
                     (field.value.type.struct_def->name + "_").c_str());
     } else {
       code += "    builder." + FunctionStart(lang, 'P') + "ut";
-      code += GenMethod(lang, field.value.type) + "(" += nameprefix;
-      code += MakeCamel(field.name, lang.first_camel_upper) + ");\n";
+      code += GenMethod(lang, field.value.type) + "(";
+      auto argname = nameprefix + MakeCamel(field.name, lang.first_camel_upper);
+      std::string type_mask = DestinationMask(lang, field.value.type, false);
+      if (type_mask.length()) {
+        code += "(" + GenTypeBasic(lang, field.value.type) + ")";
+        code += "(" + argname + type_mask + ")";
+      } else {
+        code += argname;
+      }
+      code += ");\n";
     }
   }
 }
@@ -363,7 +420,11 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
     if (field.deprecated) continue;
     GenComment(field.doc_comment, code_ptr, "  ");
     std::string type_name = GenTypeGet(lang, field.value.type);
-    std::string method_start = "  public " + type_name + " " +
+    std::string type_name_dest =
+      GenTypeGet(lang, DestinationType(lang, field.value.type, true));
+    std::string dest_mask = DestinationMask(lang, field.value.type, true);
+    std::string dest_cast = DestinationCast(lang, field.value.type);
+    std::string method_start = "  public " + type_name_dest + " " +
                                MakeCamel(field.name, lang.first_camel_upper);
     // Generate the accessors that don't do object reuse.
     if (field.value.type.base_type == BASE_TYPE_STRUCT) {
@@ -381,7 +442,7 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
       code += "(new ";
       code += type_name + "(), j); }\n";
     }
-    std::string getter = GenGetter(lang, field.value.type);
+    std::string getter = dest_cast + GenGetter(lang, field.value.type);
     code += method_start + "(";
     // Most field accessors need to retrieve and test the field offset first,
     // this is the prefix code for that:
@@ -390,14 +451,15 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
                          "); return o != 0 ? ";
     std::string default_cast = "";
     if (lang.language == GeneratorOptions::kCSharp)
-      default_cast = "(" + type_name + ")";
+      default_cast = "(" + type_name_dest + ")";
     if (IsScalar(field.value.type.base_type)) {
       if (struct_def.fixed) {
         code += ") { return " + getter;
         code += "(bb_pos + " + NumToString(field.value.offset) + ")";
+        code += dest_mask;
       } else {
         code += offset_prefix + getter;
-        code += "(o + bb_pos) : " + default_cast;
+        code += "(o + bb_pos)" + dest_mask + " : " + default_cast;
         code += GenDefaultValue(field.value);
       }
     } else {
@@ -436,7 +498,7 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
           } else {
             code += index;
           }
-          code += ") : ";
+          code += ")" + dest_mask + " : ";
           code += IsScalar(field.value.type.element)
                   ? default_cast + "0"
                   : "null";
@@ -506,7 +568,10 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
            it != struct_def.fields.vec.end(); ++it) {
         auto &field = **it;
         if (field.deprecated) continue;
-        code += ",\n      " + GenTypeBasic(lang, field.value.type) + " ";
+        code += ",\n      ";
+        code += GenTypeBasic(lang,
+                             DestinationType(lang, field.value.type, false));
+        code += " ";
         code += field.name;
         // Java doesn't have defaults, which means this method must always
         // supply all arguments, and thus won't compile when fields are added.
@@ -553,13 +618,21 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
       code += "  public static void " + FunctionStart(lang, 'A') + "dd";
       code += MakeCamel(field.name);
       code += "(FlatBufferBuilder builder, ";
-      code += GenTypeBasic(lang, field.value.type);
+      code += GenTypeBasic(lang,
+                           DestinationType(lang, field.value.type, false));
       auto argname = MakeCamel(field.name, false);
       if (!IsScalar(field.value.type.base_type)) argname += "Offset";
       code += " " + argname + ") { builder." + FunctionStart(lang, 'A') + "dd";
       code += GenMethod(lang, field.value.type) + "(";
       code += NumToString(it - struct_def.fields.vec.begin()) + ", ";
-      code += argname + ", " + GenDefaultValue(field.value);
+      std::string type_mask = DestinationMask(lang, field.value.type, false);
+      if (type_mask.length()) {
+        code += "(" + GenTypeBasic(lang, field.value.type) + ")";
+        code += "(" + argname + type_mask + ")";
+      } else {
+        code += argname;
+      }
+      code += ", " + GenDefaultValue(field.value);
       code += "); }\n";
       if (field.value.type.base_type == BASE_TYPE_VECTOR) {
         auto vector_type = field.value.type.VectorType();
index 03e6aeb..6104871 100644 (file)
@@ -19,7 +19,7 @@ public class Monster extends Table {
   public short hp() { int o = __offset(8); return o != 0 ? bb.getShort(o + bb_pos) : 100; }
   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 byte inventory(int j) { int o = __offset(14); return o != 0 ? bb.get(__vector(o) + j * 1) : 0; }
+  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; }
@@ -37,18 +37,18 @@ public class Monster extends Table {
   public int testarrayoftablesLength() { int o = __offset(26); return o != 0 ? __vector_len(o) : 0; }
   public Monster enemy() { return enemy(new Monster()); }
   public Monster enemy(Monster obj) { int o = __offset(28); return o != 0 ? obj.__init(__indirect(o + bb_pos), bb) : null; }
-  public byte testnestedflatbuffer(int j) { int o = __offset(30); return o != 0 ? bb.get(__vector(o) + j * 1) : 0; }
+  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 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 int testhashs32Fnv1() { int o = __offset(36); return o != 0 ? bb.getInt(o + bb_pos) : 0; }
-  public int testhashu32Fnv1() { int o = __offset(38); return o != 0 ? bb.getInt(o + bb_pos) : 0; }
+  public long testhashu32Fnv1() { int o = __offset(38); return o != 0 ? (long)bb.getInt(o + bb_pos) & 0xFFFFFFFFL : 0; }
   public long testhashs64Fnv1() { int o = __offset(40); return o != 0 ? bb.getLong(o + bb_pos) : 0; }
   public long testhashu64Fnv1() { int o = __offset(42); return o != 0 ? bb.getLong(o + bb_pos) : 0; }
   public int testhashs32Fnv1a() { int o = __offset(44); return o != 0 ? bb.getInt(o + bb_pos) : 0; }
-  public int testhashu32Fnv1a() { int o = __offset(46); return o != 0 ? bb.getInt(o + bb_pos) : 0; }
+  public long testhashu32Fnv1a() { int o = __offset(46); return o != 0 ? (long)bb.getInt(o + bb_pos) & 0xFFFFFFFFL : 0; }
   public long testhashs64Fnv1a() { int o = __offset(48); return o != 0 ? bb.getLong(o + bb_pos) : 0; }
   public long testhashu64Fnv1a() { int o = __offset(50); return o != 0 ? bb.getLong(o + bb_pos) : 0; }
 
@@ -78,11 +78,11 @@ public class Monster extends Table {
   public static void addTestempty(FlatBufferBuilder builder, int testemptyOffset) { builder.addOffset(14, testemptyOffset, 0); }
   public static void addTestbool(FlatBufferBuilder builder, boolean testbool) { builder.addBoolean(15, testbool, false); }
   public static void addTesthashs32Fnv1(FlatBufferBuilder builder, int testhashs32Fnv1) { builder.addInt(16, testhashs32Fnv1, 0); }
-  public static void addTesthashu32Fnv1(FlatBufferBuilder builder, int testhashu32Fnv1) { builder.addInt(17, testhashu32Fnv1, 0); }
+  public static void addTesthashu32Fnv1(FlatBufferBuilder builder, long testhashu32Fnv1) { builder.addInt(17, (int)(testhashu32Fnv1 & 0xFFFFFFFFL), 0); }
   public static void addTesthashs64Fnv1(FlatBufferBuilder builder, long testhashs64Fnv1) { builder.addLong(18, testhashs64Fnv1, 0); }
   public static void addTesthashu64Fnv1(FlatBufferBuilder builder, long testhashu64Fnv1) { builder.addLong(19, testhashu64Fnv1, 0); }
   public static void addTesthashs32Fnv1a(FlatBufferBuilder builder, int testhashs32Fnv1a) { builder.addInt(20, testhashs32Fnv1a, 0); }
-  public static void addTesthashu32Fnv1a(FlatBufferBuilder builder, int testhashu32Fnv1a) { builder.addInt(21, testhashu32Fnv1a, 0); }
+  public static void addTesthashu32Fnv1a(FlatBufferBuilder builder, long testhashu32Fnv1a) { builder.addInt(21, (int)(testhashu32Fnv1a & 0xFFFFFFFFL), 0); }
   public static void addTesthashs64Fnv1a(FlatBufferBuilder builder, long testhashs64Fnv1a) { builder.addLong(22, testhashs64Fnv1a, 0); }
   public static void addTesthashu64Fnv1a(FlatBufferBuilder builder, long testhashu64Fnv1a) { builder.addLong(23, testhashu64Fnv1a, 0); }
   public static int endMonster(FlatBufferBuilder builder) {
index 8ad3a9e..c269a0a 100644 (file)
@@ -12,19 +12,23 @@ public class Stat : Table {
 
   public string Id() { int o = __offset(4); return o != 0 ? __string(o + bb_pos) : null; }
   public long Val() { int o = __offset(6); return o != 0 ? bb.GetLong(o + bb_pos) : (long)0; }
+  public ushort Count() { int o = __offset(8); return o != 0 ? bb.GetUshort(o + bb_pos) : (ushort)0; }
 
   public static int CreateStat(FlatBufferBuilder builder,
       int id = 0,
-      long val = 0) {
-    builder.StartObject(2);
+      long val = 0,
+      ushort count = 0) {
+    builder.StartObject(3);
     Stat.AddVal(builder, val);
     Stat.AddId(builder, id);
+    Stat.AddCount(builder, count);
     return Stat.EndStat(builder);
   }
 
-  public static void StartStat(FlatBufferBuilder builder) { builder.StartObject(2); }
+  public static void StartStat(FlatBufferBuilder builder) { builder.StartObject(3); }
   public static void AddId(FlatBufferBuilder builder, int idOffset) { builder.AddOffset(0, idOffset, 0); }
   public static void AddVal(FlatBufferBuilder builder, long val) { builder.AddLong(1, val, 0); }
+  public static void AddCount(FlatBufferBuilder builder, ushort count) { builder.AddUshort(2, count, 0); }
   public static int EndStat(FlatBufferBuilder builder) {
     int o = builder.EndObject();
     return o;
index 4c07f56..b2c8e3e 100644 (file)
@@ -30,7 +30,16 @@ func (rcv *Stat) Val() int64 {
        return 0
 }
 
-func StatStart(builder *flatbuffers.Builder) { builder.StartObject(2) }
+func (rcv *Stat) Count() uint16 {
+       o := flatbuffers.UOffsetT(rcv._tab.Offset(8))
+       if o != 0 {
+               return rcv._tab.GetUint16(o + rcv._tab.Pos)
+       }
+       return 0
+}
+
+func StatStart(builder *flatbuffers.Builder) { builder.StartObject(3) }
 func StatAddId(builder *flatbuffers.Builder, id flatbuffers.UOffsetT) { builder.PrependUOffsetTSlot(0, flatbuffers.UOffsetT(id), 0) }
 func StatAddVal(builder *flatbuffers.Builder, val int64) { builder.PrependInt64Slot(1, val, 0) }
+func StatAddCount(builder *flatbuffers.Builder, count uint16) { builder.PrependUint16Slot(2, count, 0) }
 func StatEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { return builder.EndObject() }
index 50939d8..9facdf5 100644 (file)
@@ -15,19 +15,23 @@ public 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 int count() { int o = __offset(8); return o != 0 ? bb.getShort(o + bb_pos) & 0xFFFF : 0; }
 
   public static int createStat(FlatBufferBuilder builder,
       int id,
-      long val) {
-    builder.startObject(2);
+      long val,
+      int count) {
+    builder.startObject(3);
     Stat.addVal(builder, val);
     Stat.addId(builder, id);
+    Stat.addCount(builder, count);
     return Stat.endStat(builder);
   }
 
-  public static void startStat(FlatBufferBuilder builder) { builder.startObject(2); }
+  public static void startStat(FlatBufferBuilder builder) { builder.startObject(3); }
   public static void addId(FlatBufferBuilder builder, int idOffset) { builder.addOffset(0, idOffset, 0); }
   public static void addVal(FlatBufferBuilder builder, long val) { builder.addLong(1, val, 0); }
+  public static void addCount(FlatBufferBuilder builder, int count) { builder.addShort(2, (short)(count & 0xFFFF), 0); }
   public static int endStat(FlatBufferBuilder builder) {
     int o = builder.endObject();
     return o;
index 2610657..9bd7133 100755 (executable)
@@ -24,6 +24,7 @@ struct Vec3 (force_align: 16) {
 table Stat {
   id:string;
   val:long;
+  count:ushort;
 }
 
 table Monster {
index 55d8eb4..8313cea 100755 (executable)
@@ -89,11 +89,13 @@ STRUCT_END(Vec3, 32);
 struct Stat FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
   const flatbuffers::String *id() const { return GetPointer<const flatbuffers::String *>(4); }
   int64_t val() const { return GetField<int64_t>(6, 0); }
+  uint16_t count() const { return GetField<uint16_t>(8, 0); }
   bool Verify(flatbuffers::Verifier &verifier) const {
     return VerifyTableStart(verifier) &&
            VerifyField<flatbuffers::uoffset_t>(verifier, 4 /* id */) &&
            verifier.Verify(id()) &&
            VerifyField<int64_t>(verifier, 6 /* val */) &&
+           VerifyField<uint16_t>(verifier, 8 /* count */) &&
            verifier.EndTable();
   }
 };
@@ -103,20 +105,23 @@ struct StatBuilder {
   flatbuffers::uoffset_t start_;
   void add_id(flatbuffers::Offset<flatbuffers::String> id) { fbb_.AddOffset(4, id); }
   void add_val(int64_t val) { fbb_.AddElement<int64_t>(6, val, 0); }
+  void add_count(uint16_t count) { fbb_.AddElement<uint16_t>(8, count, 0); }
   StatBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
   StatBuilder &operator=(const StatBuilder &);
   flatbuffers::Offset<Stat> Finish() {
-    auto o = flatbuffers::Offset<Stat>(fbb_.EndTable(start_, 2));
+    auto o = flatbuffers::Offset<Stat>(fbb_.EndTable(start_, 3));
     return o;
   }
 };
 
 inline flatbuffers::Offset<Stat> CreateStat(flatbuffers::FlatBufferBuilder &_fbb,
    flatbuffers::Offset<flatbuffers::String> id = 0,
-   int64_t val = 0) {
+   int64_t val = 0,
+   uint16_t count = 0) {
   StatBuilder builder_(_fbb);
   builder_.add_val(val);
   builder_.add_id(id);
+  builder_.add_count(count);
   return builder_.Finish();
 }