Skip to content

Commit

Permalink
Unsigned types in Java now return bigger size signed types.
Browse files Browse the repository at this point in the history
(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
  • Loading branch information
Wouter van Oortmerssen committed Mar 24, 2015
1 parent f7818d8 commit ca5c9e7
Show file tree
Hide file tree
Showing 7 changed files with 122 additions and 26 deletions.
95 changes: 84 additions & 11 deletions src/idl_gen_general.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down Expand Up @@ -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);
}
}
Expand Down Expand Up @@ -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";
}
}
}
Expand Down Expand Up @@ -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) {
Expand All @@ -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:
Expand All @@ -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 {
Expand Down Expand Up @@ -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";
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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();
Expand Down
12 changes: 6 additions & 6 deletions tests/MyGame/Example/Monster.java
Original file line number Diff line number Diff line change
Expand Up @@ -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; }
Expand All @@ -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; }

Expand Down Expand Up @@ -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) {
Expand Down
10 changes: 7 additions & 3 deletions tests/MyGame/Example/Stat.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
11 changes: 10 additions & 1 deletion tests/MyGame/Example/Stat.go
Original file line number Diff line number Diff line change
Expand Up @@ -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() }
10 changes: 7 additions & 3 deletions tests/MyGame/Example/Stat.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions tests/monster_test.fbs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ struct Vec3 (force_align: 16) {
table Stat {
id:string;
val:long;
count:ushort;
}

table Monster {
Expand Down
9 changes: 7 additions & 2 deletions tests/monster_test_generated.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
};
Expand All @@ -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();
}

Expand Down

0 comments on commit ca5c9e7

Please sign in to comment.