From ca5c9e7496c79deb4d1e80258d3293e46397f4d8 Mon Sep 17 00:00:00 2001 From: Wouter van Oortmerssen Date: Wed, 18 Mar 2015 17:52:39 -0700 Subject: [PATCH] Unsigned types in Java now return bigger size signed types. (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 | 95 +++++++++++++++++++++++++++---- tests/MyGame/Example/Monster.java | 12 ++-- tests/MyGame/Example/Stat.cs | 10 +++- tests/MyGame/Example/Stat.go | 11 +++- tests/MyGame/Example/Stat.java | 10 +++- tests/monster_test.fbs | 1 + tests/monster_test_generated.h | 9 ++- 7 files changed, 122 insertions(+), 26 deletions(-) diff --git a/src/idl_gen_general.cpp b/src/idl_gen_general.cpp index bc6f7b937..69c731382 100644 --- a/src/idl_gen_general.cpp +++ b/src/idl_gen_general.cpp @@ -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(); diff --git a/tests/MyGame/Example/Monster.java b/tests/MyGame/Example/Monster.java index 03e6aeb31..610487148 100644 --- a/tests/MyGame/Example/Monster.java +++ b/tests/MyGame/Example/Monster.java @@ -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) { diff --git a/tests/MyGame/Example/Stat.cs b/tests/MyGame/Example/Stat.cs index 8ad3a9e1b..c269a0a56 100644 --- a/tests/MyGame/Example/Stat.cs +++ b/tests/MyGame/Example/Stat.cs @@ -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; diff --git a/tests/MyGame/Example/Stat.go b/tests/MyGame/Example/Stat.go index 4c07f56b0..b2c8e3e18 100644 --- a/tests/MyGame/Example/Stat.go +++ b/tests/MyGame/Example/Stat.go @@ -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() } diff --git a/tests/MyGame/Example/Stat.java b/tests/MyGame/Example/Stat.java index 50939d881..9facdf569 100644 --- a/tests/MyGame/Example/Stat.java +++ b/tests/MyGame/Example/Stat.java @@ -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; diff --git a/tests/monster_test.fbs b/tests/monster_test.fbs index 26106574d..9bd713324 100755 --- a/tests/monster_test.fbs +++ b/tests/monster_test.fbs @@ -24,6 +24,7 @@ struct Vec3 (force_align: 16) { table Stat { id:string; val:long; + count:ushort; } table Monster { diff --git a/tests/monster_test_generated.h b/tests/monster_test_generated.h index 55d8eb4be..8313cea46 100755 --- a/tests/monster_test_generated.h +++ b/tests/monster_test_generated.h @@ -89,11 +89,13 @@ STRUCT_END(Vec3, 32); struct Stat FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { const flatbuffers::String *id() const { return GetPointer(4); } int64_t val() const { return GetField(6, 0); } + uint16_t count() const { return GetField(8, 0); } bool Verify(flatbuffers::Verifier &verifier) const { return VerifyTableStart(verifier) && VerifyField(verifier, 4 /* id */) && verifier.Verify(id()) && VerifyField(verifier, 6 /* val */) && + VerifyField(verifier, 8 /* count */) && verifier.EndTable(); } }; @@ -103,20 +105,23 @@ struct StatBuilder { flatbuffers::uoffset_t start_; void add_id(flatbuffers::Offset id) { fbb_.AddOffset(4, id); } void add_val(int64_t val) { fbb_.AddElement(6, val, 0); } + void add_count(uint16_t count) { fbb_.AddElement(8, count, 0); } StatBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); } StatBuilder &operator=(const StatBuilder &); flatbuffers::Offset Finish() { - auto o = flatbuffers::Offset(fbb_.EndTable(start_, 2)); + auto o = flatbuffers::Offset(fbb_.EndTable(start_, 3)); return o; } }; inline flatbuffers::Offset CreateStat(flatbuffers::FlatBufferBuilder &_fbb, flatbuffers::Offset 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(); }