diff --git a/docs/source/CppUsage.md b/docs/source/CppUsage.md
index 0e226fc75..cff3071bd 100755
--- a/docs/source/CppUsage.md
+++ b/docs/source/CppUsage.md
@@ -411,4 +411,22 @@ manually wrap it in synchronisation primites. There's no automatic way to
accomplish this, by design, as we feel multithreaded construction
of a single buffer will be rare, and synchronisation overhead would be costly.
+## Advanced union features
+
+The C++ implementation currently supports vectors of unions (i.e. you can
+declare a field as `[T]` where `T` is a union type instead of a table type). It
+also supports structs and strings in unions, besides tables.
+
+For an example of these features, see `tests/union_vector`, and
+`UnionVectorTest` in `test.cpp`.
+
+Since these features haven't been ported to other languages yet, if you
+choose to use them, you won't be able to use these buffers in other languages
+(`flatc` will refuse to compile a schema that uses these features).
+
+These features reduce the amount of "table wrapping" that was previously
+needed to use unions.
+
+To use scalars, simply wrap them in a struct.
+
diff --git a/include/flatbuffers/flatbuffers.h b/include/flatbuffers/flatbuffers.h
index 664be4ca4..0a553a0c0 100644
--- a/include/flatbuffers/flatbuffers.h
+++ b/include/flatbuffers/flatbuffers.h
@@ -360,6 +360,8 @@ private:
const uint8_t *data_;
};
+struct String;
+
// This is used as a helper type for accessing vectors.
// Vector::data() assumes the vector elements start after the length field.
template class Vector {
@@ -391,6 +393,18 @@ public:
return static_cast(Get(i));
}
+ // If this a vector of unions, this does the cast for you. There's no check
+ // to make sure this is the right type!
+ template const U *GetAs(uoffset_t i) const {
+ return reinterpret_cast(Get(i));
+ }
+
+ // If this a vector of unions, this does the cast for you. There's no check
+ // to make sure this is actually a string!
+ const String *GetAsString(uoffset_t i) const {
+ return reinterpret_cast(Get(i));
+ }
+
const void *GetStructFromOffset(size_t o) const {
return reinterpret_cast(Data() + o);
}
@@ -1327,6 +1341,13 @@ FLATBUFFERS_FINAL_CLASS
reinterpret_cast(buf));
}
+ /// @brief Write a struct by itself, typically to be part of a union.
+ template Offset CreateStruct(const T &structobj) {
+ Align(AlignOf());
+ buf_.push_small(structobj);
+ return Offset(GetSize());
+ }
+
/// @brief The length of a FlatBuffer file header.
static const size_t kFileIdentifierLength = 4;
diff --git a/include/flatbuffers/idl.h b/include/flatbuffers/idl.h
index 9978d34ec..e81b2fcb9 100644
--- a/include/flatbuffers/idl.h
+++ b/include/flatbuffers/idl.h
@@ -283,18 +283,18 @@ inline size_t InlineAlignment(const Type &type) {
struct EnumVal {
EnumVal(const std::string &_name, int64_t _val)
- : name(_name), value(_val), struct_def(nullptr) {}
+ : name(_name), value(_val) {}
Offset Serialize(FlatBufferBuilder *builder) const;
std::string name;
std::vector doc_comment;
int64_t value;
- StructDef *struct_def; // only set if this is a union
+ Type union_type;
};
struct EnumDef : public Definition {
- EnumDef() : is_union(false) {}
+ EnumDef() : is_union(false), uses_type_aliases(false) {}
EnumVal *ReverseLookup(int enum_idx, bool skip_union_default = true) {
for (auto it = vals.vec.begin() + static_cast(is_union &&
@@ -312,6 +312,7 @@ struct EnumDef : public Definition {
SymbolTable vals;
bool is_union;
+ bool uses_type_aliases;
Type underlying_type;
};
@@ -548,6 +549,7 @@ private:
const std::string &name, const Type &type,
FieldDef **dest);
FLATBUFFERS_CHECKED_ERROR ParseField(StructDef &struct_def);
+ FLATBUFFERS_CHECKED_ERROR ParseString(Value &val);
FLATBUFFERS_CHECKED_ERROR ParseAnyValue(Value &val, FieldDef *field,
size_t parent_fieldn,
const StructDef *parent_struct_def);
diff --git a/include/flatbuffers/reflection_generated.h b/include/flatbuffers/reflection_generated.h
index 8379dcf52..b76814e47 100644
--- a/include/flatbuffers/reflection_generated.h
+++ b/include/flatbuffers/reflection_generated.h
@@ -204,7 +204,8 @@ struct EnumVal FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
enum {
VT_NAME = 4,
VT_VALUE = 6,
- VT_OBJECT = 8
+ VT_OBJECT = 8,
+ VT_UNION_TYPE = 10
};
const flatbuffers::String *name() const {
return GetPointer(VT_NAME);
@@ -228,6 +229,9 @@ struct EnumVal FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
const Object *object() const {
return GetPointer(VT_OBJECT);
}
+ const Type *union_type() const {
+ return GetPointer(VT_UNION_TYPE);
+ }
bool Verify(flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) &&
VerifyFieldRequired(verifier, VT_NAME) &&
@@ -235,6 +239,8 @@ struct EnumVal FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
VerifyField(verifier, VT_VALUE) &&
VerifyField(verifier, VT_OBJECT) &&
verifier.VerifyTable(object()) &&
+ VerifyField(verifier, VT_UNION_TYPE) &&
+ verifier.VerifyTable(union_type()) &&
verifier.EndTable();
}
};
@@ -251,13 +257,16 @@ struct EnumValBuilder {
void add_object(flatbuffers::Offset object) {
fbb_.AddOffset(EnumVal::VT_OBJECT, object);
}
+ void add_union_type(flatbuffers::Offset union_type) {
+ fbb_.AddOffset(EnumVal::VT_UNION_TYPE, union_type);
+ }
EnumValBuilder(flatbuffers::FlatBufferBuilder &_fbb)
: fbb_(_fbb) {
start_ = fbb_.StartTable();
}
EnumValBuilder &operator=(const EnumValBuilder &);
flatbuffers::Offset Finish() {
- const auto end = fbb_.EndTable(start_, 3);
+ const auto end = fbb_.EndTable(start_, 4);
auto o = flatbuffers::Offset(end);
fbb_.Required(o, EnumVal::VT_NAME);
return o;
@@ -268,9 +277,11 @@ inline flatbuffers::Offset CreateEnumVal(
flatbuffers::FlatBufferBuilder &_fbb,
flatbuffers::Offset name = 0,
int64_t value = 0,
- flatbuffers::Offset object = 0) {
+ flatbuffers::Offset object = 0,
+ flatbuffers::Offset union_type = 0) {
EnumValBuilder builder_(_fbb);
builder_.add_value(value);
+ builder_.add_union_type(union_type);
builder_.add_object(object);
builder_.add_name(name);
return builder_.Finish();
@@ -280,12 +291,14 @@ inline flatbuffers::Offset CreateEnumValDirect(
flatbuffers::FlatBufferBuilder &_fbb,
const char *name = nullptr,
int64_t value = 0,
- flatbuffers::Offset object = 0) {
+ flatbuffers::Offset object = 0,
+ flatbuffers::Offset union_type = 0) {
return reflection::CreateEnumVal(
_fbb,
name ? _fbb.CreateString(name) : 0,
value,
- object);
+ object,
+ union_type);
}
struct Enum FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
diff --git a/reflection/reflection.fbs b/reflection/reflection.fbs
index 76ccf85cc..ea41891c3 100644
--- a/reflection/reflection.fbs
+++ b/reflection/reflection.fbs
@@ -42,7 +42,8 @@ table KeyValue {
table EnumVal {
name:string (required);
value:long (key);
- object:Object; // Only if part of a union.
+ object:Object; // Will be deprecated in favor of union_type in the future.
+ union_type:Type;
}
table Enum {
diff --git a/samples/monster_generated.h b/samples/monster_generated.h
index 05633d96e..fdbac0fcc 100644
--- a/samples/monster_generated.h
+++ b/samples/monster_generated.h
@@ -71,35 +71,35 @@ template<> struct EquipmentTraits {
struct EquipmentUnion {
Equipment type;
- flatbuffers::NativeTable *table;
+ void *value;
- EquipmentUnion() : type(Equipment_NONE), table(nullptr) {}
+ EquipmentUnion() : type(Equipment_NONE), value(nullptr) {}
EquipmentUnion(EquipmentUnion&& u) FLATBUFFERS_NOEXCEPT :
- type(Equipment_NONE), table(nullptr)
- { std::swap(type, u.type); std::swap(table, u.table); }
+ type(Equipment_NONE), value(nullptr)
+ { std::swap(type, u.type); std::swap(value, u.value); }
EquipmentUnion(const EquipmentUnion &);
EquipmentUnion &operator=(const EquipmentUnion &);
EquipmentUnion &operator=(EquipmentUnion &&u) FLATBUFFERS_NOEXCEPT
- { std::swap(type, u.type); std::swap(table, u.table); return *this; }
+ { std::swap(type, u.type); std::swap(value, u.value); return *this; }
~EquipmentUnion() { Reset(); }
void Reset();
template
- void Set(T&& value) {
+ void Set(T&& val) {
Reset();
type = EquipmentTraits::enum_value;
if (type != Equipment_NONE) {
- table = new T(std::forward(value));
+ value = new T(std::forward(val));
}
}
- static flatbuffers::NativeTable *UnPack(const void *obj, Equipment type, const flatbuffers::resolver_function_t *resolver);
+ static void *UnPack(const void *obj, Equipment type, const flatbuffers::resolver_function_t *resolver);
flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const flatbuffers::rehasher_function_t *_rehasher = nullptr) const;
WeaponT *AsWeapon() {
return type == Equipment_Weapon ?
- reinterpret_cast(table) : nullptr;
+ reinterpret_cast(value) : nullptr;
}
};
@@ -228,7 +228,7 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
}
template const T *equipped_as() const;
const Weapon *equipped_as_Weapon() const {
- return (equipped_type() == Equipment_Weapon)? static_cast(equipped()) : nullptr;
+ return equipped_type() == Equipment_Weapon ? static_cast(equipped()) : nullptr;
}
void *mutable_equipped() {
return GetPointer(VT_EQUIPPED);
@@ -451,7 +451,7 @@ inline void Monster::UnPackTo(MonsterT *_o, const flatbuffers::resolver_function
{ auto _e = color(); _o->color = _e; };
{ auto _e = weapons(); if (_e) { _o->weapons.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->weapons[_i] = std::unique_ptr(_e->Get(_i)->UnPack(_resolver)); } } };
{ auto _e = equipped_type(); _o->equipped.type = _e; };
- { auto _e = equipped(); if (_e) _o->equipped.table = EquipmentUnion::UnPack(_e, equipped_type(),_resolver); };
+ { auto _e = equipped(); if (_e) _o->equipped.value = EquipmentUnion::UnPack(_e, equipped_type(), _resolver); };
}
inline flatbuffers::Offset Monster::Pack(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT* _o, const flatbuffers::rehasher_function_t *_rehasher) {
@@ -535,7 +535,7 @@ inline bool VerifyEquipmentVector(flatbuffers::Verifier &verifier, const flatbuf
return true;
}
-inline flatbuffers::NativeTable *EquipmentUnion::UnPack(const void *obj, Equipment type, const flatbuffers::resolver_function_t *resolver) {
+inline void *EquipmentUnion::UnPack(const void *obj, Equipment type, const flatbuffers::resolver_function_t *resolver) {
switch (type) {
case Equipment_Weapon: {
auto ptr = reinterpret_cast(obj);
@@ -548,7 +548,7 @@ inline flatbuffers::NativeTable *EquipmentUnion::UnPack(const void *obj, Equipme
inline flatbuffers::Offset EquipmentUnion::Pack(flatbuffers::FlatBufferBuilder &_fbb, const flatbuffers::rehasher_function_t *_rehasher) const {
switch (type) {
case Equipment_Weapon: {
- auto ptr = reinterpret_cast(table);
+ auto ptr = reinterpret_cast(value);
return CreateWeapon(_fbb, ptr, _rehasher).Union();
}
default: return 0;
@@ -558,13 +558,13 @@ inline flatbuffers::Offset EquipmentUnion::Pack(flatbuffers::FlatBufferBui
inline void EquipmentUnion::Reset() {
switch (type) {
case Equipment_Weapon: {
- auto ptr = reinterpret_cast(table);
+ auto ptr = reinterpret_cast(value);
delete ptr;
break;
}
default: break;
}
- table = nullptr;
+ value = nullptr;
type = Equipment_NONE;
}
diff --git a/src/idl_gen_cpp.cpp b/src/idl_gen_cpp.cpp
index 95c5d71ab..b5a6c59ac 100644
--- a/src/idl_gen_cpp.cpp
+++ b/src/idl_gen_cpp.cpp
@@ -109,7 +109,7 @@ class CppGenerator : public BaseGenerator {
SetNameSpace(struct_def.defined_namespace);
code_ += "struct " + struct_def.name + ";";
if (parser_.opts.generate_object_based_api && !struct_def.fixed) {
- code_ += "struct " + NativeName(struct_def.name) + ";";
+ code_ += "struct " + NativeName(struct_def.name, &struct_def) + ";";
}
code_ += "";
}
@@ -239,7 +239,7 @@ class CppGenerator : public BaseGenerator {
if (parser_.opts.generate_object_based_api) {
// A convenient root unpack function.
auto native_name =
- NativeName(WrapInNameSpace(struct_def));
+ NativeName(WrapInNameSpace(struct_def), &struct_def);
code_.SetValue("UNPACK_RETURN",
GenTypeNativePtr(native_name, nullptr, false));
code_.SetValue("UNPACK_TYPE",
@@ -355,7 +355,9 @@ class CppGenerator : public BaseGenerator {
}
// TODO(wvo): make this configurable.
- static std::string NativeName(const std::string &name) { return name + "T"; }
+ static std::string NativeName(const std::string &name, const StructDef *sd) {
+ return sd && !sd->fixed ? name + "T" : name;
+ }
const std::string &PtrType(const FieldDef *field) {
auto attr = field ? field->attributes.Lookup("cpp_ptr_type") : nullptr;
@@ -411,7 +413,8 @@ class CppGenerator : public BaseGenerator {
return GenTypeNativePtr(type_name, &field, false);
}
} else {
- return GenTypeNativePtr(NativeName(type_name), &field, false);
+ return GenTypeNativePtr(NativeName(type_name, type.struct_def),
+ &field, false);
}
}
case BASE_TYPE_UNION: {
@@ -458,6 +461,26 @@ class CppGenerator : public BaseGenerator {
}
}
+ std::string StripUnionType(const std::string &name) {
+ return name.substr(0, name.size() - strlen(UnionTypeFieldSuffix()));
+ }
+
+ std::string GetUnionElement(const EnumVal &ev, bool wrap, bool actual_type,
+ bool native_type = false) {
+ if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
+ auto name = actual_type ? ev.union_type.struct_def->name : ev.name;
+ return wrap
+ ? WrapInNameSpace(ev.union_type.struct_def->defined_namespace, name)
+ : name;
+ } else if (ev.union_type.base_type == BASE_TYPE_STRING) {
+ return actual_type
+ ? (native_type ? "std::string" : "flatbuffers::String")
+ : ev.name;
+ } else {
+ assert(false);
+ }
+ }
+
static std::string UnionVerifySignature(const EnumDef &enum_def) {
return "bool Verify" + enum_def.name +
"(flatbuffers::Verifier &verifier, const void *obj, " +
@@ -474,7 +497,7 @@ class CppGenerator : public BaseGenerator {
static std::string UnionUnPackSignature(const EnumDef &enum_def,
bool inclass) {
return (inclass ? "static " : "") +
- std::string("flatbuffers::NativeTable *") +
+ std::string("void *") +
(inclass ? "" : enum_def.name + "Union::") +
"UnPack(const void *obj, " + enum_def.name +
" type, const flatbuffers::resolver_function_t *resolver)";
@@ -493,7 +516,7 @@ class CppGenerator : public BaseGenerator {
return "flatbuffers::Offset<" + struct_def.name + "> Create" +
struct_def.name +
"(flatbuffers::FlatBufferBuilder &_fbb, const " +
- NativeName(struct_def.name) +
+ NativeName(struct_def.name, &struct_def) +
" *_o, const flatbuffers::rehasher_function_t *_rehasher" +
(predecl ? " = nullptr" : "") + ")";
}
@@ -504,14 +527,14 @@ class CppGenerator : public BaseGenerator {
"flatbuffers::Offset<" + struct_def.name + "> " +
(inclass ? "" : struct_def.name + "::") +
"Pack(flatbuffers::FlatBufferBuilder &_fbb, " +
- "const " + NativeName(struct_def.name) + "* _o, " +
+ "const " + NativeName(struct_def.name, &struct_def) + "* _o, " +
"const flatbuffers::rehasher_function_t *_rehasher" +
(inclass ? " = nullptr" : "") + ")";
}
static std::string TableUnPackSignature(const StructDef &struct_def,
bool inclass) {
- return NativeName(struct_def.name) + " *" +
+ return NativeName(struct_def.name, &struct_def) + " *" +
(inclass ? "" : struct_def.name + "::") +
"UnPack(const flatbuffers::resolver_function_t *_resolver" +
(inclass ? " = nullptr" : "") + ") const";
@@ -520,8 +543,8 @@ class CppGenerator : public BaseGenerator {
static std::string TableUnPackToSignature(const StructDef &struct_def,
bool inclass) {
return "void " + (inclass ? "" : struct_def.name + "::") +
- "UnPackTo(" + NativeName(struct_def.name) + " *" + "_o, " +
- "const flatbuffers::resolver_function_t *_resolver" +
+ "UnPackTo(" + NativeName(struct_def.name, &struct_def) + " *" +
+ "_o, const flatbuffers::resolver_function_t *_resolver" +
(inclass ? " = nullptr" : "") + ") const";
}
@@ -629,7 +652,7 @@ class CppGenerator : public BaseGenerator {
}
// Generate type traits for unions to map from a type to union enum value.
- if (enum_def.is_union) {
+ if (enum_def.is_union && !enum_def.uses_type_aliases) {
for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end();
++it) {
const auto &ev = **it;
@@ -638,7 +661,7 @@ class CppGenerator : public BaseGenerator {
code_ += "template struct {{ENUM_NAME}}Traits {";
}
else {
- auto name = WrapInNameSpace(*ev.struct_def);
+ auto name = GetUnionElement(ev, true, true);
code_ += "template<> struct {{ENUM_NAME}}Traits<" + name + "> {";
}
@@ -657,29 +680,31 @@ class CppGenerator : public BaseGenerator {
code_ += "struct {{NAME}}Union {";
code_ += " {{NAME}} type;";
- code_ += " flatbuffers::NativeTable *table;";
+ code_ += " void *value;";
code_ += "";
- code_ += " {{NAME}}Union() : type({{NONE}}), table(nullptr) {}";
+ code_ += " {{NAME}}Union() : type({{NONE}}), value(nullptr) {}";
code_ += " {{NAME}}Union({{NAME}}Union&& u) FLATBUFFERS_NOEXCEPT :";
- code_ += " type({{NONE}}), table(nullptr)";
- code_ += " { std::swap(type, u.type); std::swap(table, u.table); }";
+ code_ += " type({{NONE}}), value(nullptr)";
+ code_ += " { std::swap(type, u.type); std::swap(value, u.value); }";
code_ += " {{NAME}}Union(const {{NAME}}Union &);";
code_ += " {{NAME}}Union &operator=(const {{NAME}}Union &);";
code_ += " {{NAME}}Union &operator=({{NAME}}Union &&u) FLATBUFFERS_NOEXCEPT";
- code_ += " { std::swap(type, u.type); std::swap(table, u.table); return *this; }";
+ code_ += " { std::swap(type, u.type); std::swap(value, u.value); return *this; }";
code_ += " ~{{NAME}}Union() { Reset(); }";
code_ += "";
code_ += " void Reset();";
code_ += "";
- code_ += " template ";
- code_ += " void Set(T&& value) {";
- code_ += " Reset();";
- code_ += " type = {{NAME}}Traits::enum_value;";
- code_ += " if (type != {{NONE}}) {";
- code_ += " table = new T(std::forward(value));";
- code_ += " }";
- code_ += " }";
- code_ += "";
+ if (!enum_def.uses_type_aliases) {
+ code_ += " template ";
+ code_ += " void Set(T&& val) {";
+ code_ += " Reset();";
+ code_ += " type = {{NAME}}Traits::enum_value;";
+ code_ += " if (type != {{NONE}}) {";
+ code_ += " value = new T(std::forward(val));";
+ code_ += " }";
+ code_ += " }";
+ code_ += "";
+ }
code_ += " " + UnionUnPackSignature(enum_def, true) + ";";
code_ += " " + UnionPackSignature(enum_def, true) + ";";
code_ += "";
@@ -691,14 +716,16 @@ class CppGenerator : public BaseGenerator {
continue;
}
- const auto native_type = NativeName(WrapInNameSpace(*ev.struct_def));
+ const auto native_type =
+ NativeName(GetUnionElement(ev, true, true, true),
+ ev.union_type.struct_def);
code_.SetValue("NATIVE_TYPE", native_type);
code_.SetValue("NATIVE_NAME", ev.name);
code_.SetValue("NATIVE_ID", GetEnumValUse(enum_def, ev));
code_ += " {{NATIVE_TYPE}} *As{{NATIVE_NAME}}() {";
code_ += " return type == {{NATIVE_ID}} ?";
- code_ += " reinterpret_cast<{{NATIVE_TYPE}} *>(table) : nullptr;";
+ code_ += " reinterpret_cast<{{NATIVE_TYPE}} *>(value) : nullptr;";
code_ += " }";
}
code_ += "};";
@@ -728,10 +755,23 @@ class CppGenerator : public BaseGenerator {
code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
if (ev.value) {
- code_.SetValue("TYPE", WrapInNameSpace(*ev.struct_def));
+ code_.SetValue("TYPE", GetUnionElement(ev, true, true));
code_ += " case {{LABEL}}: {";
- code_ += " auto ptr = reinterpret_cast(obj);";
- code_ += " return verifier.VerifyTable(ptr);";
+ auto getptr =
+ " auto ptr = reinterpret_cast(obj);";
+ if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
+ if (ev.union_type.struct_def->fixed) {
+ code_ += " return true;";
+ } else {
+ code_ += getptr;
+ code_ += " return verifier.VerifyTable(ptr);";
+ }
+ } else if (ev.union_type.base_type == BASE_TYPE_STRING) {
+ code_ += getptr;
+ code_ += " return verifier.Verify(ptr);";
+ } else {
+ assert(false);
+ }
code_ += " }";
} else {
code_ += " case {{LABEL}}: {";
@@ -768,10 +808,21 @@ class CppGenerator : public BaseGenerator {
}
code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
- code_.SetValue("TYPE", WrapInNameSpace(*ev.struct_def));
+ code_.SetValue("TYPE", GetUnionElement(ev, true, true));
code_ += " case {{LABEL}}: {";
code_ += " auto ptr = reinterpret_cast(obj);";
- code_ += " return ptr->UnPack(resolver);";
+ if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
+ if (ev.union_type.struct_def->fixed) {
+ code_ += " return new " +
+ WrapInNameSpace(*ev.union_type.struct_def) + "(*ptr);";
+ } else {
+ code_ += " return ptr->UnPack(resolver);";
+ }
+ } else if (ev.union_type.base_type == BASE_TYPE_STRING) {
+ code_ += " return new std::string(ptr->c_str(), ptr->size());";
+ } else {
+ assert(false);
+ }
code_ += " }";
}
code_ += " default: return nullptr;";
@@ -789,11 +840,23 @@ class CppGenerator : public BaseGenerator {
}
code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
- code_.SetValue("TYPE", NativeName(WrapInNameSpace(*ev.struct_def)));
- code_.SetValue("NAME", ev.struct_def->name);
+ code_.SetValue("TYPE", NativeName(GetUnionElement(ev, true, true, true),
+ ev.union_type.struct_def));
+ code_.SetValue("NAME", GetUnionElement(ev, false, true));
code_ += " case {{LABEL}}: {";
- code_ += " auto ptr = reinterpret_cast(table);";
- code_ += " return Create{{NAME}}(_fbb, ptr, _rehasher).Union();";
+ code_ += " auto ptr = reinterpret_cast(value);";
+ if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
+ if (ev.union_type.struct_def->fixed) {
+ code_ += " return _fbb.CreateStruct(*ptr).Union();";
+ } else {
+ code_ +=
+ " return Create{{NAME}}(_fbb, ptr, _rehasher).Union();";
+ }
+ } else if (ev.union_type.base_type == BASE_TYPE_STRING) {
+ code_ += " return _fbb.CreateString(*ptr).Union();";
+ } else {
+ assert(false);
+ }
code_ += " }";
}
code_ += " default: return 0;";
@@ -815,17 +878,18 @@ class CppGenerator : public BaseGenerator {
}
code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
- code_.SetValue("TYPE", NativeName(WrapInNameSpace(*ev.struct_def)));
+ code_.SetValue("TYPE", NativeName(GetUnionElement(ev, true, true, true),
+ ev.union_type.struct_def));
code_ += " case {{LABEL}}: {";
- code_ += " auto ptr = reinterpret_cast<{{TYPE}} *>(table);";
+ code_ += " auto ptr = reinterpret_cast<{{TYPE}} *>(value);";
code_ += " delete ptr;";
code_ += " break;";
code_ += " }";
}
code_ += " default: break;";
code_ += " }";
- code_ += " table = nullptr;";
+ code_ += " value = nullptr;";
code_ += " type = {{NONE}};";
code_ += "}";
code_ += "";
@@ -914,7 +978,9 @@ class CppGenerator : public BaseGenerator {
// Generate a member, including a default value for scalars and raw pointers.
void GenMember(const FieldDef &field) {
if (!field.deprecated && // Deprecated fields won't be accessible.
- field.value.type.base_type != BASE_TYPE_UTYPE) {
+ field.value.type.base_type != BASE_TYPE_UTYPE &&
+ (field.value.type.base_type != BASE_TYPE_VECTOR ||
+ field.value.type.element != BASE_TYPE_UTYPE)) {
auto type = GenTypeNative(field.value.type, false, field);
auto cpp_type = field.attributes.Lookup("cpp_type");
auto full_type = (cpp_type ? cpp_type->constant + " *" : type + " ");
@@ -964,7 +1030,7 @@ class CppGenerator : public BaseGenerator {
initializer_list = "\n : " + initializer_list;
}
- code_.SetValue("NATIVE_NAME", NativeName(struct_def.name));
+ code_.SetValue("NATIVE_NAME", NativeName(struct_def.name, &struct_def));
code_.SetValue("INIT_LIST", initializer_list);
code_ += " {{NATIVE_NAME}}(){{INIT_LIST}} {";
@@ -972,7 +1038,7 @@ class CppGenerator : public BaseGenerator {
}
void GenNativeTable(const StructDef &struct_def) {
- const auto native_name = NativeName(struct_def.name);
+ const auto native_name = NativeName(struct_def.name, &struct_def);
code_.SetValue("STRUCT_NAME", struct_def.name);
code_.SetValue("NATIVE_NAME", native_name);
@@ -1138,24 +1204,23 @@ class CppGenerator : public BaseGenerator {
for (auto u_it = u->vals.vec.begin();
u_it != u->vals.vec.end(); ++u_it) {
- if (!(*u_it)->struct_def) {
+ auto &ev = **u_it;
+ if (ev.union_type.base_type == BASE_TYPE_NONE) {
continue;
}
- auto arg_struct_def = (*u_it)->struct_def;
- auto full_struct_name = WrapInNameSpace(*arg_struct_def);
+ auto full_struct_name = GetUnionElement(ev, true, true);
// @TODO: Mby make this decisions more universal? How?
code_.SetValue("U_GET_TYPE", field.name + UnionTypeFieldSuffix());
code_.SetValue("U_ELEMENT_TYPE", WrapInNameSpace(
- u->defined_namespace, GetEnumValUse(*u, **u_it)));
+ u->defined_namespace, GetEnumValUse(*u, ev)));
code_.SetValue("U_FIELD_TYPE", "const " + full_struct_name + " *");
- code_.SetValue("U_ELEMENT_NAME", full_struct_name);
code_.SetValue("U_FIELD_NAME",
- field.name + "_as_" + (*u_it)->name);
+ field.name + "_as_" + ev.name);
// `const Type *union_name_asType() const` accessor.
code_ += " {{U_FIELD_TYPE}}{{U_FIELD_NAME}}() const {";
- code_ += " return ({{U_GET_TYPE}}() == {{U_ELEMENT_TYPE}})? "
+ code_ += " return {{U_GET_TYPE}}() == {{U_ELEMENT_TYPE}} ? "
"static_cast<{{U_FIELD_TYPE}}>({{FIELD_NAME}}()) "
": nullptr;";
code_ += " }";
@@ -1279,23 +1344,25 @@ class CppGenerator : public BaseGenerator {
}
auto u = field.value.type.enum_def;
+ if (u->uses_type_aliases) continue;
+
code_.SetValue("FIELD_NAME", field.name);
for (auto u_it = u->vals.vec.begin();
u_it != u->vals.vec.end(); ++u_it) {
- if (!(*u_it)->struct_def) {
+ auto &ev = **u_it;
+ if (ev.union_type.base_type == BASE_TYPE_NONE) {
continue;
}
- auto arg_struct_def = (*u_it)->struct_def;
- auto full_struct_name = WrapInNameSpace(*arg_struct_def);
+ auto full_struct_name = GetUnionElement(ev, true, true);
code_.SetValue("U_ELEMENT_TYPE", WrapInNameSpace(
- u->defined_namespace, GetEnumValUse(*u, **u_it)));
+ u->defined_namespace, GetEnumValUse(*u, ev)));
code_.SetValue("U_FIELD_TYPE", "const " + full_struct_name + " *");
code_.SetValue("U_ELEMENT_NAME", full_struct_name);
code_.SetValue("U_FIELD_NAME",
- field.name + "_as_" + (*u_it)->name);
+ field.name + "_as_" + ev.name);
// `template<> const T *union_name_as() const` accessor.
code_ += "template<> "
@@ -1475,6 +1542,14 @@ class CppGenerator : public BaseGenerator {
}
}
+ std::string GenUnionUnpackVal(const FieldDef &afield,
+ const char *vec_elem_access,
+ const char *vec_type_access) {
+ return afield.value.type.enum_def->name + "Union::UnPack(" + "_e" +
+ vec_elem_access + ", " + afield.name + UnionTypeFieldSuffix() +
+ "()" + vec_type_access + ", _resolver)";
+ }
+
std::string GenUnpackVal(const Type &type, const std::string &val,
bool invector, const FieldDef &afield) {
switch (type.base_type) {
@@ -1494,10 +1569,18 @@ class CppGenerator : public BaseGenerator {
return ptype + "(new " + name + "(*" + val + "))";
}
} else {
- const auto ptype = GenTypeNativePtr(NativeName(name), &afield, true);
+ const auto ptype = GenTypeNativePtr(NativeName(name, type.struct_def),
+ &afield, true);
return ptype + "(" + val + "->UnPack(_resolver))";
}
}
+ case BASE_TYPE_UNION: {
+ return GenUnionUnpackVal(afield,
+ invector ? "->Get(_i)" : "",
+ invector ? ("->GetEnum<" +
+ type.enum_def->name +
+ ">(_i)").c_str() : "");
+ }
default: {
return val;
break;
@@ -1523,10 +1606,19 @@ class CppGenerator : public BaseGenerator {
// for (uoffset_t i = 0; i < _e->size(); ++i) {
// _o->field.push_back(_e->Get(_i));
// }
- code += "{ _o->" + field.name + ".resize(_e->size()); ";
+ auto name = field.name;
+ if (field.value.type.element == BASE_TYPE_UTYPE) {
+ name = StripUnionType(field.name);
+ }
+ auto access = field.value.type.element == BASE_TYPE_UTYPE
+ ? ".type"
+ : (field.value.type.element == BASE_TYPE_UNION
+ ? ".value"
+ : "");
+ code += "{ _o->" + name + ".resize(_e->size()); ";
code += "for (flatbuffers::uoffset_t _i = 0;";
code += " _i < _e->size(); _i++) { ";
- code += "_o->" + field.name + "[_i] = ";
+ code += "_o->" + name + "[_i]" + access + " = ";
code += GenUnpackVal(field.value.type.VectorType(),
indexing, true, field);
code += "; } }";
@@ -1540,12 +1632,11 @@ class CppGenerator : public BaseGenerator {
break;
}
case BASE_TYPE_UNION: {
- // Generate code that sets the union table, of the form:
- // _o->field.table = Union::Unpack(_e, field_type(), resolver);
- code += "_o->" + field.name + ".table = ";
- code += field.value.type.enum_def->name + "Union::UnPack(";
- code += "_e, " + field.name + UnionTypeFieldSuffix() + "(),";
- code += "_resolver);";
+ // Generate code that sets the union value, of the form:
+ // _o->field.value = Union::Unpack(_e, field_type(), resolver);
+ code += "_o->" + field.name + ".value = ";
+ code += GenUnionUnpackVal(field, "", "");
+ code += ";";
break;
}
default: {
@@ -1577,8 +1668,7 @@ class CppGenerator : public BaseGenerator {
std::string GenCreateParam(const FieldDef &field) {
std::string value = "_o->";
if (field.value.type.base_type == BASE_TYPE_UTYPE) {
- value += field.name.substr(0, field.name.size() -
- strlen(UnionTypeFieldSuffix()));
+ value += StripUnionType(field.name);
value += ".type";
} else {
value += field.name;
@@ -1635,6 +1725,19 @@ class CppGenerator : public BaseGenerator {
code += "_fbb.CreateVector(" + value + ")";
break;
}
+ case BASE_TYPE_UNION: {
+ code += "_fbb.CreateVector>(" + value +
+ ".size(), [&](size_t i) { return " + value +
+ "[i].Pack(_fbb, _rehasher); })";
+ break;
+ }
+ case BASE_TYPE_UTYPE: {
+ value = StripUnionType(value);
+ code += "_fbb.CreateVector(" + value +
+ ".size(), [&](size_t i) { return static_cast(" + value +
+ "[i].type); })";
+ break;
+ }
default: {
if (field.value.type.enum_def) {
// For enumerations, we need to get access to the array data for
@@ -1693,7 +1796,7 @@ class CppGenerator : public BaseGenerator {
// Generate code for tables that needs to come after the regular definition.
void GenTablePost(const StructDef &struct_def) {
code_.SetValue("STRUCT_NAME", struct_def.name);
- code_.SetValue("NATIVE_NAME", NativeName(struct_def.name));
+ code_.SetValue("NATIVE_NAME", NativeName(struct_def.name, &struct_def));
if (parser_.opts.generate_object_based_api) {
// Generate the X::UnPack() method.
diff --git a/src/idl_gen_js.cpp b/src/idl_gen_js.cpp
index e39387e66..b2839e130 100644
--- a/src/idl_gen_js.cpp
+++ b/src/idl_gen_js.cpp
@@ -71,7 +71,8 @@ namespace js {
class JsGenerator : public BaseGenerator {
public:
typedef std::unordered_set imported_fileset;
- typedef std::unordered_multimap reexport_map;
+ typedef std::unordered_multimap
+ reexport_map;
JsGenerator(const Parser &parser, const std::string &path,
const std::string &file_name)
@@ -104,19 +105,22 @@ class JsGenerator : public BaseGenerator {
code += enum_code;
code += struct_code;
- if (lang_.language == IDLOptions::kJs && !exports_code.empty() && !parser_.opts.skip_js_exports) {
+ if (lang_.language == IDLOptions::kJs && !exports_code.empty() &&
+ !parser_.opts.skip_js_exports) {
code += "// Exports for Node.js and RequireJS\n";
code += exports_code;
}
- return SaveFile(GeneratedFileName(path_, file_name_, lang_).c_str(), code, false);
+ return SaveFile(GeneratedFileName(path_, file_name_, lang_).c_str(), code,
+ false);
}
private:
JsLanguageParameters lang_;
// Generate code for imports
- void generateImportDependencies(std::string *code_ptr, const imported_fileset &imported_files) {
+ void generateImportDependencies(std::string *code_ptr,
+ const imported_fileset &imported_files) {
std::string &code = *code_ptr;
for (auto it = imported_files.begin(); it != imported_files.end(); ++it) {
const auto &file = *it;
@@ -129,11 +133,13 @@ class JsGenerator : public BaseGenerator {
}
}
- // Generate reexports, which might not have been explicitly imported using the "export import" trick
+ // Generate reexports, which might not have been explicitly imported using the
+ // "export import" trick
void generateReexports(std::string *code_ptr,
const reexport_map &reexports,
imported_fileset imported_files) {
- if (!parser_.opts.reexport_ts_modules || lang_.language != IDLOptions::kTs) {
+ if (!parser_.opts.reexport_ts_modules ||
+ lang_.language != IDLOptions::kTs) {
return;
}
@@ -152,7 +158,9 @@ class JsGenerator : public BaseGenerator {
code += "export namespace " + file.second.target_namespace + " { \n";
code += "export import " + file.second.symbol + " = ";
- code += GenFileNamespacePrefix(file.first) + "." + file.second.source_namespace + "." + file.second.symbol + "; }\n";
+ code += GenFileNamespacePrefix(file.first) + "." +
+ file.second.source_namespace + "." + file.second.symbol +
+ "; }\n";
}
}
}
@@ -175,11 +183,13 @@ class JsGenerator : public BaseGenerator {
for (auto it = parser_.structs_.vec.begin();
it != parser_.structs_.vec.end(); ++it) {
auto &struct_def = **it;
- GenStruct(parser_, struct_def, decl_code_ptr, exports_code_ptr, imported_files);
+ GenStruct(parser_, struct_def, decl_code_ptr, exports_code_ptr,
+ imported_files);
}
}
void GenNamespaces(std::string *code_ptr, std::string *exports_ptr) {
- if (lang_.language == IDLOptions::kTs && parser_.opts.skip_flatbuffers_import) {
+ if (lang_.language == IDLOptions::kTs &&
+ parser_.opts.skip_flatbuffers_import) {
return;
}
@@ -282,13 +292,14 @@ void GenEnum(EnumDef &enum_def, std::string *code_ptr,
std::string &exports = *exports_ptr;
GenDocComment(enum_def.doc_comment, code_ptr, "@enum");
if (lang_.language == IDLOptions::kTs) {
- code += "export namespace " + GetNameSpace(enum_def) + "{\n" + "export enum " + enum_def.name + "{\n";
+ code += "export namespace " + GetNameSpace(enum_def) + "{\n" +
+ "export enum " + enum_def.name + "{\n";
} else {
if (enum_def.defined_namespace->components.empty()) {
code += "var ";
if(parser_.opts.use_goog_js_export_format) {
- exports += "goog.exportSymbol('" + enum_def.name + "', " + enum_def.name +
- ");\n";
+ exports += "goog.exportSymbol('" + enum_def.name + "', " +
+ enum_def.name + ");\n";
} else {
exports += "this." + enum_def.name + " = " + enum_def.name + ";\n";
}
@@ -304,12 +315,19 @@ void GenEnum(EnumDef &enum_def, std::string *code_ptr,
}
GenDocComment(ev.doc_comment, code_ptr, "", " ");
}
- code += " " + ev.name + ((lang_.language == IDLOptions::kTs) ? ("= ") : (": ")) + NumToString(ev.value);
+ code += " " + ev.name;
+ code += lang_.language == IDLOptions::kTs ? "= " : ": ";
+ code += NumToString(ev.value);
code += (it + 1) != enum_def.vals.vec.end() ? ",\n" : "\n";
- if (ev.struct_def) {
- ReexportDescription desc = { ev.name, GetNameSpace(*ev.struct_def), GetNameSpace(enum_def) };
- reexports.insert(std::make_pair(ev.struct_def->file, std::move(desc)));
+ if (ev.union_type.struct_def) {
+ ReexportDescription desc = {
+ ev.name,
+ GetNameSpace(*ev.union_type.struct_def),
+ GetNameSpace(enum_def)
+ };
+ reexports.insert(std::make_pair(ev.union_type.struct_def->file,
+ std::move(desc)));
}
}
@@ -366,7 +384,8 @@ std::string GenDefaultValue(const Value &value, const std::string &context) {
if (auto val = value.type.enum_def->ReverseLookup(
atoi(value.constant.c_str()), false)) {
if (lang_.language == IDLOptions::kTs) {
- return GenPrefixedTypeName(WrapInNameSpace(*value.type.enum_def), value.type.enum_def->file) + "." + val->name;
+ return GenPrefixedTypeName(WrapInNameSpace(*value.type.enum_def),
+ value.type.enum_def->file) + "." + val->name;
} else {
return WrapInNameSpace(*value.type.enum_def) + "." + val->name;
}
@@ -448,17 +467,21 @@ static std::string MaybeScale(T value) {
}
static std::string GenFileNamespacePrefix(const std::string &file) {
- return "NS" + std::to_string(static_cast(std::hash()(file)));
+ return "NS" + std::to_string(
+ static_cast(std::hash()(file)));
}
static std::string GenPrefixedImport(const std::string &full_file_name,
const std::string &base_file_name) {
- return "import * as "+ GenFileNamespacePrefix(full_file_name) + " from \"./" + base_file_name + "\";\n";
+ return "import * as "+ GenFileNamespacePrefix(full_file_name) +
+ " from \"./" + base_file_name + "\";\n";
}
// Adds a source-dependent prefix, for of import * statements.
-std::string GenPrefixedTypeName(const std::string &typeName, const std::string &file) {
- const auto basename = flatbuffers::StripPath(flatbuffers::StripExtension(file));
+std::string GenPrefixedTypeName(const std::string &typeName,
+ const std::string &file) {
+ const auto basename =
+ flatbuffers::StripPath(flatbuffers::StripExtension(file));
if (basename == file_name_) {
return typeName;
}
@@ -483,7 +506,8 @@ void GenStructArgs(const StructDef &struct_def,
*annotations += "} " + nameprefix + field.name + "\n";
if (lang_.language == IDLOptions::kTs) {
- *arguments += ", " + nameprefix + field.name + ": " + GenTypeName(field.value.type, true);
+ *arguments += ", " + nameprefix + field.name + ": " +
+ GenTypeName(field.value.type, true);
} else {
*arguments += ", " + nameprefix + field.name;
}
@@ -521,7 +545,8 @@ static void GenStructBody(const StructDef &struct_def,
}
// Generate an accessor struct with constructor for a flatbuffers struct.
-void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_ptr, std::string *exports_ptr,
+void GenStruct(const Parser &parser, StructDef &struct_def,
+ std::string *code_ptr, std::string *exports_ptr,
imported_fileset &imported_files) {
if (struct_def.generated) return;
std::string &code = *code_ptr;
@@ -583,7 +608,8 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
code += " */\n";
if (lang_.language == IDLOptions::kTs) {
- code += "__init(i:number, bb:flatbuffers.ByteBuffer):" + object_name + " {\n";
+ code += "__init(i:number, bb:flatbuffers.ByteBuffer):" + object_name +
+ " {\n";
} else {
code += object_name + ".prototype.__init = function(i, bb) {\n";
}
@@ -602,7 +628,8 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
"@returns {" + object_name + "}");
if (lang_.language == IDLOptions::kTs) {
code += "static getRootAs" + struct_def.name;
- code += "(bb:flatbuffers.ByteBuffer, obj?:" + object_name + "):" + object_name + " {\n";
+ code += "(bb:flatbuffers.ByteBuffer, obj?:" + object_name + "):" +
+ object_name + " {\n";
} else {
code += object_name + ".getRootAs" + struct_def.name;
code += " = function(bb, obj) {\n";
@@ -618,7 +645,8 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
"@param {flatbuffers.ByteBuffer} bb\n"
"@returns {boolean}");
if (lang_.language == IDLOptions::kTs) {
- code += "static bufferHasIdentifier(bb:flatbuffers.ByteBuffer):boolean {\n";
+ code +=
+ "static bufferHasIdentifier(bb:flatbuffers.ByteBuffer):boolean {\n";
} else {
code += object_name + ".bufferHasIdentifier = function(bb) {\n";
}
@@ -647,13 +675,16 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
std::string prefix = MakeCamel(field.name, false) + "(";
if (field.value.type.base_type == BASE_TYPE_STRING) {
code += prefix + "):string\n";
- code += prefix + "optionalEncoding:flatbuffers.Encoding"+"):" + GenTypeName(field.value.type, false)+"\n";
+ code += prefix + "optionalEncoding:flatbuffers.Encoding"+"):" +
+ GenTypeName(field.value.type, false)+"\n";
code += prefix + "optionalEncoding?:any";
} else {
code += prefix;
}
if (field.value.type.enum_def) {
- code += "):" + GenPrefixedTypeName(GenTypeName(field.value.type, false), field.value.type.enum_def->file) + " {\n";
+ code += "):" +
+ GenPrefixedTypeName(GenTypeName(field.value.type, false),
+ field.value.type.enum_def->file) + " {\n";
} else {
code += "):" + GenTypeName(field.value.type, false) + " {\n";
}
@@ -733,12 +764,14 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
std::string prefix = MakeCamel(field.name, false);
prefix += "(index: number";
if (vectortype.base_type == BASE_TYPE_STRUCT) {
- vectortypename = GenPrefixedTypeName(vectortypename, vectortype.struct_def->file);
+ vectortypename = GenPrefixedTypeName(vectortypename,
+ vectortype.struct_def->file);
code += prefix + ", obj?:" + vectortypename;
imported_files.insert(vectortype.struct_def->file);
} else if (vectortype.base_type == BASE_TYPE_STRING) {
code += prefix + "):string\n";
- code += prefix + ",optionalEncoding:flatbuffers.Encoding" + "):" + vectortypename + "\n";
+ code += prefix + ",optionalEncoding:flatbuffers.Encoding" + "):" +
+ vectortypename + "\n";
code += prefix + ",optionalEncoding?:any";
} else {
code += prefix;
@@ -819,31 +852,37 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
// Adds the mutable scalar value to the output
if (IsScalar(field.value.type.base_type) && parser.opts.mutable_buffer) {
- std::string annotations = "@param {" + GenTypeName(field.value.type, true) + "} value\n";
+ std::string annotations =
+ "@param {" + GenTypeName(field.value.type, true) + "} value\n";
GenDocComment(code_ptr, annotations +
"@returns {boolean}");
if (lang_.language == IDLOptions::kTs) {
std::string type;
if (field.value.type.enum_def) {
- type = GenPrefixedTypeName(GenTypeName(field.value.type, true), field.value.type.enum_def->file);
+ type = GenPrefixedTypeName(GenTypeName(field.value.type, true),
+ field.value.type.enum_def->file);
} else {
type = GenTypeName(field.value.type, true);
}
code += "mutate_" + field.name + "(value:" + type + "):boolean {\n";
} else {
- code += object_name + ".prototype.mutate_" + field.name + " = function(value) {\n";
+ code += object_name + ".prototype.mutate_" + field.name +
+ " = function(value) {\n";
}
- code += " var offset = this.bb.__offset(this.bb_pos, " + NumToString(field.value.offset) + ");\n\n";
+ code += " var offset = this.bb.__offset(this.bb_pos, " +
+ NumToString(field.value.offset) + ");\n\n";
code += " if (offset === 0) {\n";
code += " return false;\n";
code += " }\n\n";
// special case for bools, which are treated as uint8
- code += " this.bb.write" + MakeCamel(GenType(field.value.type)) + "(this.bb_pos + offset, ";
- if (field.value.type.base_type == BASE_TYPE_BOOL && lang_.language == IDLOptions::kTs) {
+ code += " this.bb.write" + MakeCamel(GenType(field.value.type)) +
+ "(this.bb_pos + offset, ";
+ if (field.value.type.base_type == BASE_TYPE_BOOL &&
+ lang_.language == IDLOptions::kTs) {
code += "+";
}
@@ -885,7 +924,8 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
if (lang_.language == IDLOptions::kTs) {
code += MakeCamel(field.name, false);
- code += "Array():" + GenType(vectorType) + "Array {\n" + offset_prefix;
+ code += "Array():" + GenType(vectorType) + "Array {\n" +
+ offset_prefix;
} else {
code += object_name + ".prototype." + MakeCamel(field.name, false);
code += "Array = function() {\n" + offset_prefix;
@@ -958,13 +998,15 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
if (lang_.language == IDLOptions::kTs) {
std::string argType;
if (field.value.type.enum_def) {
- argType = GenPrefixedTypeName(GenTypeName(field.value.type, true), field.value.type.enum_def->file);
+ argType = GenPrefixedTypeName(GenTypeName(field.value.type, true),
+ field.value.type.enum_def->file);
} else {
argType = GenTypeName(field.value.type, true);
}
code += "static add" + MakeCamel(field.name);
- code += "(builder:flatbuffers.Builder, " + argname + ":" + argType + ") {\n";
+ code += "(builder:flatbuffers.Builder, " + argname + ":" + argType +
+ ") {\n";
} else {
code += object_name + ".add" + MakeCamel(field.name);
code += " = function(builder, " + argname + ") {\n";
@@ -1005,7 +1047,8 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
if (type == "number[]") {
type += " | Uint8Array";
}
- code += "Vector(builder:flatbuffers.Builder, data:" + type+"):flatbuffers.Offset {\n";
+ code += "Vector(builder:flatbuffers.Builder, data:" + type +
+ "):flatbuffers.Offset {\n";
code += "if(!data){\n return null\n}\n";
} else {
code += object_name + ".create" + MakeCamel(field.name);
diff --git a/src/idl_gen_text.cpp b/src/idl_gen_text.cpp
index 17cd987dd..cff1b322d 100644
--- a/src/idl_gen_text.cpp
+++ b/src/idl_gen_text.cpp
@@ -49,7 +49,7 @@ void OutputIdentifier(const std::string &name, const IDLOptions &opts,
// for a single FlatBuffer value into JSON format.
// The general case for scalars:
template bool Print(T val, Type type, int /*indent*/,
- StructDef * /*union_sd*/,
+ Type */*union_type*/,
const IDLOptions &opts,
std::string *_text) {
std::string &text = *_text;
@@ -169,22 +169,16 @@ static bool EscapeString(const String &s, std::string *_text, const IDLOptions&
// Specialization of Print above for pointer types.
template<> bool Print(const void *val,
Type type, int indent,
- StructDef *union_sd,
+ Type *union_type,
const IDLOptions &opts,
std::string *_text) {
switch (type.base_type) {
case BASE_TYPE_UNION:
// If this assert hits, you have an corrupt buffer, a union type field
// was not present or was out of range.
- assert(union_sd);
- if (!GenStruct(*union_sd,
- reinterpret_cast(val),
- indent,
- opts,
- _text)) {
- return false;
- }
- break;
+ assert(union_type);
+ return Print(val, *union_type, indent, nullptr, opts,
+ _text);
case BASE_TYPE_STRUCT:
if (!GenStruct(*type.struct_def,
reinterpret_cast(val),
@@ -236,7 +230,7 @@ template static bool GenField(const FieldDef &fd,
// Generate text for non-scalar field.
static bool GenFieldOffset(const FieldDef &fd, const Table *table, bool fixed,
- int indent, StructDef *union_sd,
+ int indent, Type *union_type,
const IDLOptions &opts, std::string *_text) {
const void *val = nullptr;
if (fixed) {
@@ -249,7 +243,7 @@ static bool GenFieldOffset(const FieldDef &fd, const Table *table, bool fixed,
? table->GetStruct(fd.value.offset)
: table->GetPointer(fd.value.offset);
}
- return Print(val, fd.value.type, indent, union_sd, opts, _text);
+ return Print(val, fd.value.type, indent, union_type, opts, _text);
}
// Generate text for a struct or table, values separated by commas, indented,
@@ -260,7 +254,7 @@ static bool GenStruct(const StructDef &struct_def, const Table *table,
std::string &text = *_text;
text += "{";
int fieldout = 0;
- StructDef *union_sd = nullptr;
+ Type *union_type = nullptr;
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end();
++it) {
@@ -296,7 +290,7 @@ static bool GenStruct(const StructDef &struct_def, const Table *table,
FLATBUFFERS_GEN_TYPES_POINTER(FLATBUFFERS_TD)
#undef FLATBUFFERS_TD
if (!GenFieldOffset(fd, table, struct_def.fixed, indent + Indent(opts),
- union_sd, opts, _text)) {
+ union_type, opts, _text)) {
return false;
}
break;
@@ -305,7 +299,7 @@ static bool GenStruct(const StructDef &struct_def, const Table *table,
auto enum_val = fd.value.type.enum_def->ReverseLookup(
table->GetField(fd.value.offset, 0));
assert(enum_val);
- union_sd = enum_val->struct_def;
+ union_type = &enum_val->union_type;
}
}
else
diff --git a/src/idl_parser.cpp b/src/idl_parser.cpp
index 0d689da3c..3076f7188 100644
--- a/src/idl_parser.cpp
+++ b/src/idl_parser.cpp
@@ -735,6 +735,13 @@ CheckedError Parser::ParseField(StructDef &struct_def) {
return NoError();
}
+CheckedError Parser::ParseString(Value &val) {
+ auto s = attribute_;
+ EXPECT(kTokenStringConstant);
+ val.constant = NumToString(builder_.CreateString(s).o);
+ return NoError();
+}
+
CheckedError Parser::ParseAnyValue(Value &val, FieldDef *field,
size_t parent_fieldn,
const StructDef *parent_struct_def) {
@@ -784,16 +791,27 @@ CheckedError Parser::ParseAnyValue(Value &val, FieldDef *field,
ECHECK(atot(constant.c_str(), *this, &enum_idx));
auto enum_val = val.type.enum_def->ReverseLookup(enum_idx);
if (!enum_val) return Error("illegal type id for: " + field->name);
- ECHECK(ParseTable(*enum_val->struct_def, &val.constant, nullptr));
+ if (enum_val->union_type.base_type == BASE_TYPE_STRUCT) {
+ ECHECK(ParseTable(*enum_val->union_type.struct_def, &val.constant,
+ nullptr));
+ if (enum_val->union_type.struct_def->fixed) {
+ // All BASE_TYPE_UNION values are offsets, so turn this into one.
+ SerializeStruct(*enum_val->union_type.struct_def, val);
+ builder_.ClearOffsets();
+ val.constant = NumToString(builder_.GetSize());
+ }
+ } else if (enum_val->union_type.base_type == BASE_TYPE_STRING) {
+ ECHECK(ParseString(val));
+ } else {
+ assert(false);
+ }
break;
}
case BASE_TYPE_STRUCT:
ECHECK(ParseTable(*val.type.struct_def, &val.constant, nullptr));
break;
case BASE_TYPE_STRING: {
- auto s = attribute_;
- EXPECT(kTokenStringConstant);
- val.constant = NumToString(builder_.CreateString(s).o);
+ ECHECK(ParseString(val));
break;
}
case BASE_TYPE_VECTOR: {
@@ -1290,7 +1308,16 @@ CheckedError Parser::ParseEnum(bool is_union, EnumDef **dest) {
return Error("enum value already exists: " + value_name);
ev.doc_comment = value_comment;
if (is_union) {
- ev.struct_def = LookupCreateStruct(full_name);
+ if (Is(':')) {
+ NEXT();
+ ECHECK(ParseType(ev.union_type));
+ if (ev.union_type.base_type != BASE_TYPE_STRUCT &&
+ ev.union_type.base_type != BASE_TYPE_STRING)
+ return Error("union value type may only be table/struct/string");
+ enum_def.uses_type_aliases = true;
+ } else {
+ ev.union_type = Type(BASE_TYPE_STRUCT, LookupCreateStruct(full_name));
+ }
}
if (Is('=')) {
NEXT();
@@ -1994,6 +2021,8 @@ CheckedError Parser::DoParse(const char *source, const char **include_paths,
return Error("type referenced but not defined: " + (*it)->name);
}
}
+ // This check has to happen here and not earlier, because only now do we
+ // know for sure what the type of these are.
for (auto it = enums_.vec.begin(); it != enums_.vec.end(); ++it) {
auto &enum_def = **it;
if (enum_def.is_union) {
@@ -2001,8 +2030,11 @@ CheckedError Parser::DoParse(const char *source, const char **include_paths,
val_it != enum_def.vals.vec.end();
++val_it) {
auto &val = **val_it;
- if (val.struct_def && val.struct_def->fixed)
- return Error("only tables can be union elements: " + val.name);
+ if (opts.lang_to_generate != IDLOptions::kCpp &&
+ val.union_type.struct_def && val.union_type.struct_def->fixed)
+ return Error(
+ "only tables can be union elements in the generated language: "
+ + val.name);
}
}
}
@@ -2145,9 +2177,11 @@ Offset EnumVal::Serialize(FlatBufferBuilder *builder) const
return reflection::CreateEnumVal(*builder,
builder->CreateString(name),
value,
- struct_def
- ? struct_def->serialized_location
- : 0);
+ union_type.struct_def
+ ? union_type.struct_def->
+ serialized_location
+ : 0,
+ union_type.Serialize(builder));
}
Offset Type::Serialize(FlatBufferBuilder *builder) const {
diff --git a/tests/generate_code.sh b/tests/generate_code.sh
index 00d87f7c7..b12e78a76 100755
--- a/tests/generate_code.sh
+++ b/tests/generate_code.sh
@@ -16,7 +16,7 @@
../flatc --cpp --java --csharp --go --binary --python --js --ts --php --grpc --gen-mutable --gen-object-api --no-includes monster_test.fbs monsterdata_test.json
../flatc --cpp --java --csharp --go --binary --python --js --ts --php --gen-mutable -o namespace_test namespace_test/namespace_test1.fbs namespace_test/namespace_test2.fbs
-../flatc --cpp -o union_vector ./union_vector/union_vector.fbs
+../flatc --cpp --gen-mutable --gen-object-api -o union_vector ./union_vector/union_vector.fbs
../flatc -b --schema --bfbs-comments monster_test.fbs
cd ../samples
../flatc --cpp --gen-mutable --gen-object-api monster.fbs
diff --git a/tests/monster_test.bfbs b/tests/monster_test.bfbs
index d5a1aadaa..78871d504 100644
Binary files a/tests/monster_test.bfbs and b/tests/monster_test.bfbs differ
diff --git a/tests/monster_test_generated.h b/tests/monster_test_generated.h
index 9fca310b8..08970f942 100644
--- a/tests/monster_test_generated.h
+++ b/tests/monster_test_generated.h
@@ -102,43 +102,43 @@ template<> struct AnyTraits {
struct AnyUnion {
Any type;
- flatbuffers::NativeTable *table;
+ void *value;
- AnyUnion() : type(Any_NONE), table(nullptr) {}
+ AnyUnion() : type(Any_NONE), value(nullptr) {}
AnyUnion(AnyUnion&& u) FLATBUFFERS_NOEXCEPT :
- type(Any_NONE), table(nullptr)
- { std::swap(type, u.type); std::swap(table, u.table); }
+ type(Any_NONE), value(nullptr)
+ { std::swap(type, u.type); std::swap(value, u.value); }
AnyUnion(const AnyUnion &);
AnyUnion &operator=(const AnyUnion &);
AnyUnion &operator=(AnyUnion &&u) FLATBUFFERS_NOEXCEPT
- { std::swap(type, u.type); std::swap(table, u.table); return *this; }
+ { std::swap(type, u.type); std::swap(value, u.value); return *this; }
~AnyUnion() { Reset(); }
void Reset();
template
- void Set(T&& value) {
+ void Set(T&& val) {
Reset();
type = AnyTraits::enum_value;
if (type != Any_NONE) {
- table = new T(std::forward(value));
+ value = new T(std::forward(val));
}
}
- static flatbuffers::NativeTable *UnPack(const void *obj, Any type, const flatbuffers::resolver_function_t *resolver);
+ static void *UnPack(const void *obj, Any type, const flatbuffers::resolver_function_t *resolver);
flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const flatbuffers::rehasher_function_t *_rehasher = nullptr) const;
MonsterT *AsMonster() {
return type == Any_Monster ?
- reinterpret_cast(table) : nullptr;
+ reinterpret_cast(value) : nullptr;
}
TestSimpleTableWithEnumT *AsTestSimpleTableWithEnum() {
return type == Any_TestSimpleTableWithEnum ?
- reinterpret_cast(table) : nullptr;
+ reinterpret_cast(value) : nullptr;
}
MyGame::Example2::MonsterT *AsMyGame_Example2_Monster() {
return type == Any_MyGame_Example2_Monster ?
- reinterpret_cast(table) : nullptr;
+ reinterpret_cast(value) : nullptr;
}
};
@@ -629,13 +629,13 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
}
template const T *test_as() const;
const Monster *test_as_Monster() const {
- return (test_type() == Any_Monster)? static_cast(test()) : nullptr;
+ return test_type() == Any_Monster ? static_cast(test()) : nullptr;
}
const TestSimpleTableWithEnum *test_as_TestSimpleTableWithEnum() const {
- return (test_type() == Any_TestSimpleTableWithEnum)? static_cast(test()) : nullptr;
+ return test_type() == Any_TestSimpleTableWithEnum ? static_cast(test()) : nullptr;
}
const MyGame::Example2::Monster *test_as_MyGame_Example2_Monster() const {
- return (test_type() == Any_MyGame_Example2_Monster)? static_cast(test()) : nullptr;
+ return test_type() == Any_MyGame_Example2_Monster ? static_cast(test()) : nullptr;
}
void *mutable_test() {
return GetPointer(VT_TEST);
@@ -1172,7 +1172,7 @@ inline void Monster::UnPackTo(MonsterT *_o, const flatbuffers::resolver_function
{ auto _e = inventory(); if (_e) { _o->inventory.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->inventory[_i] = _e->Get(_i); } } };
{ auto _e = color(); _o->color = _e; };
{ auto _e = test_type(); _o->test.type = _e; };
- { auto _e = test(); if (_e) _o->test.table = AnyUnion::UnPack(_e, test_type(),_resolver); };
+ { auto _e = test(); if (_e) _o->test.value = AnyUnion::UnPack(_e, test_type(), _resolver); };
{ auto _e = test4(); if (_e) { _o->test4.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->test4[_i] = *_e->Get(_i); } } };
{ auto _e = testarrayofstring(); if (_e) { _o->testarrayofstring.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->testarrayofstring[_i] = _e->Get(_i)->str(); } } };
{ auto _e = testarrayoftables(); if (_e) { _o->testarrayoftables.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->testarrayoftables[_i] = std::unique_ptr(_e->Get(_i)->UnPack(_resolver)); } } };
@@ -1297,7 +1297,7 @@ inline bool VerifyAnyVector(flatbuffers::Verifier &verifier, const flatbuffers::
return true;
}
-inline flatbuffers::NativeTable *AnyUnion::UnPack(const void *obj, Any type, const flatbuffers::resolver_function_t *resolver) {
+inline void *AnyUnion::UnPack(const void *obj, Any type, const flatbuffers::resolver_function_t *resolver) {
switch (type) {
case Any_Monster: {
auto ptr = reinterpret_cast(obj);
@@ -1318,15 +1318,15 @@ inline flatbuffers::NativeTable *AnyUnion::UnPack(const void *obj, Any type, con
inline flatbuffers::Offset AnyUnion::Pack(flatbuffers::FlatBufferBuilder &_fbb, const flatbuffers::rehasher_function_t *_rehasher) const {
switch (type) {
case Any_Monster: {
- auto ptr = reinterpret_cast(table);
+ auto ptr = reinterpret_cast(value);
return CreateMonster(_fbb, ptr, _rehasher).Union();
}
case Any_TestSimpleTableWithEnum: {
- auto ptr = reinterpret_cast(table);
+ auto ptr = reinterpret_cast(value);
return CreateTestSimpleTableWithEnum(_fbb, ptr, _rehasher).Union();
}
case Any_MyGame_Example2_Monster: {
- auto ptr = reinterpret_cast(table);
+ auto ptr = reinterpret_cast(value);
return CreateMonster(_fbb, ptr, _rehasher).Union();
}
default: return 0;
@@ -1336,23 +1336,23 @@ inline flatbuffers::Offset AnyUnion::Pack(flatbuffers::FlatBufferBuilder &
inline void AnyUnion::Reset() {
switch (type) {
case Any_Monster: {
- auto ptr = reinterpret_cast(table);
+ auto ptr = reinterpret_cast(value);
delete ptr;
break;
}
case Any_TestSimpleTableWithEnum: {
- auto ptr = reinterpret_cast(table);
+ auto ptr = reinterpret_cast(value);
delete ptr;
break;
}
case Any_MyGame_Example2_Monster: {
- auto ptr = reinterpret_cast(table);
+ auto ptr = reinterpret_cast(value);
delete ptr;
break;
}
default: break;
}
- table = nullptr;
+ value = nullptr;
type = Any_NONE;
}
diff --git a/tests/test.cpp b/tests/test.cpp
index 262562a60..53b2fe710 100644
--- a/tests/test.cpp
+++ b/tests/test.cpp
@@ -1334,46 +1334,78 @@ void UnionVectorTest() {
// union types.
std::vector types;
types.push_back(static_cast(Character_Belle));
- types.push_back(static_cast(Character_Rapunzel));
types.push_back(static_cast(Character_MuLan));
+ types.push_back(static_cast(Character_BookFan));
+ types.push_back(static_cast(Character_Other));
+ types.push_back(static_cast(Character_Unused));
// union values.
std::vector> characters;
- characters.push_back(CreateBelle(fbb, /*books_read=*/7).Union());
- characters.push_back(CreateRapunzel(fbb, /*hair_length=*/6).Union());
- characters.push_back(CreateMuLan(fbb, /*sword_attack_damage=*/5).Union());
+ characters.push_back(fbb.CreateStruct(BookReader(/*books_read=*/7)).Union());
+ characters.push_back(CreateAttacker(fbb, /*sword_attack_damage=*/5).Union());
+ characters.push_back(fbb.CreateStruct(BookReader(/*books_read=*/2)).Union());
+ characters.push_back(fbb.CreateString("Other").Union());
+ characters.push_back(fbb.CreateString("Unused").Union());
// create Movie.
const auto movie_offset =
- CreateMovie(fbb, fbb.CreateVector(types), fbb.CreateVector(characters));
+ CreateMovie(fbb,
+ Character_Rapunzel,
+ fbb.CreateStruct(Rapunzel(/*hair_length=*/6)).Union(),
+ fbb.CreateVector(types),
+ fbb.CreateVector(characters));
FinishMovieBuffer(fbb, movie_offset);
- uint8_t *buf = fbb.GetBufferPointer();
+ auto buf = fbb.GetBufferPointer();
flatbuffers::Verifier verifier(buf, fbb.GetSize());
TEST_EQ(VerifyMovieBuffer(verifier), true);
- const Movie *movie = GetMovie(buf);
- TEST_EQ(movie->characters_type()->size(), 3);
- TEST_EQ(
- movie->characters_type()->GetEnum(0) == Character_Belle,
- true);
- TEST_EQ(
- movie->characters_type()->GetEnum(1) == Character_Rapunzel,
- true);
- TEST_EQ(
- movie->characters_type()->GetEnum(2) == Character_MuLan,
- true);
+ auto flat_movie = GetMovie(buf);
- TEST_EQ(movie->characters()->size(), 3);
- const Belle *belle =
- reinterpret_cast(movie->characters()->Get(0));
- TEST_EQ(belle->books_read(), 7);
- const Rapunzel *rapunzel =
- reinterpret_cast(movie->characters()->Get(1));
- TEST_EQ(rapunzel->hair_length(), 6);
- const MuLan *mu_lan =
- reinterpret_cast(movie->characters()->Get(2));
- TEST_EQ(mu_lan->sword_attack_damage(), 5);
+ auto TestMovie = [](const Movie *movie) {
+ TEST_EQ(movie->main_character_type() == Character_Rapunzel, true);
+
+ auto cts = movie->characters_type();
+ TEST_EQ(movie->characters_type()->size(), 5);
+ TEST_EQ(cts->GetEnum(0) == Character_Belle, true);
+ TEST_EQ(cts->GetEnum(1) == Character_MuLan, true);
+ TEST_EQ(cts->GetEnum(2) == Character_BookFan, true);
+ TEST_EQ(cts->GetEnum(3) == Character_Other, true);
+ TEST_EQ(cts->GetEnum(4) == Character_Unused, true);
+
+ auto rapunzel = movie->main_character_as_Rapunzel();
+ TEST_EQ(rapunzel->hair_length(), 6);
+
+ auto cs = movie->characters();
+ TEST_EQ(cs->size(), 5);
+ auto belle = cs->GetAs(0);
+ TEST_EQ(belle->books_read(), 7);
+ auto mu_lan = cs->GetAs(1);
+ TEST_EQ(mu_lan->sword_attack_damage(), 5);
+ auto book_fan = cs->GetAs(2);
+ TEST_EQ(book_fan->books_read(), 2);
+ auto other = cs->GetAsString(3);
+ TEST_EQ_STR(other->c_str(), "Other");
+ auto unused = cs->GetAsString(4);
+ TEST_EQ_STR(unused->c_str(), "Unused");
+ };
+
+ TestMovie(flat_movie);
+
+ auto movie_object = flat_movie->UnPack();
+ TEST_EQ(movie_object->main_character.AsRapunzel()->hair_length(), 6);
+ TEST_EQ(movie_object->characters[0].AsBelle()->books_read(), 7);
+ TEST_EQ(movie_object->characters[1].AsMuLan()->sword_attack_damage, 5);
+ TEST_EQ(movie_object->characters[2].AsBookFan()->books_read(), 2);
+ TEST_EQ_STR(movie_object->characters[3].AsOther()->c_str(), "Other");
+ TEST_EQ_STR(movie_object->characters[4].AsUnused()->c_str(), "Unused");
+
+ fbb.Clear();
+ fbb.Finish(Movie::Pack(fbb, movie_object));
+
+ auto repacked_movie = GetMovie(fbb.GetBufferPointer());
+
+ TestMovie(repacked_movie);
}
void ConformTest() {
diff --git a/tests/union_vector/union_vector.fbs b/tests/union_vector/union_vector.fbs
index 4957cd862..495076f52 100644
--- a/tests/union_vector/union_vector.fbs
+++ b/tests/union_vector/union_vector.fbs
@@ -1,22 +1,29 @@
-table MuLan {
+// Demonstrates the ability to have vectors of unions, and also to
+// store structs and strings in unions.
+
+table Attacker {
sword_attack_damage: int;
}
-table Rapunzel {
+struct Rapunzel {
hair_length: int;
}
-table Belle {
+struct BookReader {
books_read: int;
}
union Character {
- MuLan,
- Rapunzel,
- Belle,
+ MuLan: Attacker, // Can have name be different from type.
+ Rapunzel, // Or just both the same, as before.
+ Belle: BookReader,
+ BookFan: BookReader,
+ Other: string,
+ Unused: string
}
table Movie {
+ main_character: Character;
characters: [Character];
}
diff --git a/tests/union_vector/union_vector_generated.h b/tests/union_vector/union_vector_generated.h
index 560860c62..24046bc5d 100644
--- a/tests/union_vector/union_vector_generated.h
+++ b/tests/union_vector/union_vector_generated.h
@@ -6,21 +6,26 @@
#include "flatbuffers/flatbuffers.h"
-struct MuLan;
+struct Attacker;
+struct AttackerT;
struct Rapunzel;
-struct Belle;
+struct BookReader;
struct Movie;
+struct MovieT;
enum Character {
Character_NONE = 0,
Character_MuLan = 1,
Character_Rapunzel = 2,
Character_Belle = 3,
+ Character_BookFan = 4,
+ Character_Other = 5,
+ Character_Unused = 6,
Character_MIN = Character_NONE,
- Character_MAX = Character_Belle
+ Character_MAX = Character_Unused
};
inline const char **EnumNamesCharacter() {
@@ -29,6 +34,9 @@ inline const char **EnumNamesCharacter() {
"MuLan",
"Rapunzel",
"Belle",
+ "BookFan",
+ "Other",
+ "Unused",
nullptr
};
return names;
@@ -39,158 +47,221 @@ inline const char *EnumNameCharacter(Character e) {
return EnumNamesCharacter()[index];
}
-template struct CharacterTraits {
- static const Character enum_value = Character_NONE;
-};
+struct CharacterUnion {
+ Character type;
+ void *value;
-template<> struct CharacterTraits {
- static const Character enum_value = Character_MuLan;
-};
+ CharacterUnion() : type(Character_NONE), value(nullptr) {}
+ CharacterUnion(CharacterUnion&& u) FLATBUFFERS_NOEXCEPT :
+ type(Character_NONE), value(nullptr)
+ { std::swap(type, u.type); std::swap(value, u.value); }
+ CharacterUnion(const CharacterUnion &);
+ CharacterUnion &operator=(const CharacterUnion &);
+ CharacterUnion &operator=(CharacterUnion &&u) FLATBUFFERS_NOEXCEPT
+ { std::swap(type, u.type); std::swap(value, u.value); return *this; }
+ ~CharacterUnion() { Reset(); }
-template<> struct CharacterTraits {
- static const Character enum_value = Character_Rapunzel;
-};
+ void Reset();
-template<> struct CharacterTraits {
- static const Character enum_value = Character_Belle;
+ static void *UnPack(const void *obj, Character type, const flatbuffers::resolver_function_t *resolver);
+ flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const flatbuffers::rehasher_function_t *_rehasher = nullptr) const;
+
+ AttackerT *AsMuLan() {
+ return type == Character_MuLan ?
+ reinterpret_cast(value) : nullptr;
+ }
+ Rapunzel *AsRapunzel() {
+ return type == Character_Rapunzel ?
+ reinterpret_cast(value) : nullptr;
+ }
+ BookReader *AsBelle() {
+ return type == Character_Belle ?
+ reinterpret_cast(value) : nullptr;
+ }
+ BookReader *AsBookFan() {
+ return type == Character_BookFan ?
+ reinterpret_cast(value) : nullptr;
+ }
+ std::string *AsOther() {
+ return type == Character_Other ?
+ reinterpret_cast(value) : nullptr;
+ }
+ std::string *AsUnused() {
+ return type == Character_Unused ?
+ reinterpret_cast(value) : nullptr;
+ }
};
bool VerifyCharacter(flatbuffers::Verifier &verifier, const void *obj, Character type);
bool VerifyCharacterVector(flatbuffers::Verifier &verifier, const flatbuffers::Vector> *values, const flatbuffers::Vector *types);
-struct MuLan FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+MANUALLY_ALIGNED_STRUCT(4) Rapunzel FLATBUFFERS_FINAL_CLASS {
+ private:
+ int32_t hair_length_;
+
+ public:
+ Rapunzel() {
+ memset(this, 0, sizeof(Rapunzel));
+ }
+ Rapunzel(const Rapunzel &_o) {
+ memcpy(this, &_o, sizeof(Rapunzel));
+ }
+ Rapunzel(int32_t _hair_length)
+ : hair_length_(flatbuffers::EndianScalar(_hair_length)) {
+ }
+ int32_t hair_length() const {
+ return flatbuffers::EndianScalar(hair_length_);
+ }
+ void mutate_hair_length(int32_t _hair_length) {
+ flatbuffers::WriteScalar(&hair_length_, _hair_length);
+ }
+};
+STRUCT_END(Rapunzel, 4);
+
+MANUALLY_ALIGNED_STRUCT(4) BookReader FLATBUFFERS_FINAL_CLASS {
+ private:
+ int32_t books_read_;
+
+ public:
+ BookReader() {
+ memset(this, 0, sizeof(BookReader));
+ }
+ BookReader(const BookReader &_o) {
+ memcpy(this, &_o, sizeof(BookReader));
+ }
+ BookReader(int32_t _books_read)
+ : books_read_(flatbuffers::EndianScalar(_books_read)) {
+ }
+ int32_t books_read() const {
+ return flatbuffers::EndianScalar(books_read_);
+ }
+ void mutate_books_read(int32_t _books_read) {
+ flatbuffers::WriteScalar(&books_read_, _books_read);
+ }
+};
+STRUCT_END(BookReader, 4);
+
+struct AttackerT : public flatbuffers::NativeTable {
+ typedef Attacker TableType;
+ int32_t sword_attack_damage;
+ AttackerT()
+ : sword_attack_damage(0) {
+ }
+};
+
+struct Attacker FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+ typedef AttackerT NativeTableType;
enum {
VT_SWORD_ATTACK_DAMAGE = 4
};
int32_t sword_attack_damage() const {
return GetField(VT_SWORD_ATTACK_DAMAGE, 0);
}
+ bool mutate_sword_attack_damage(int32_t _sword_attack_damage) {
+ return SetField(VT_SWORD_ATTACK_DAMAGE, _sword_attack_damage, 0);
+ }
bool Verify(flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) &&
VerifyField(verifier, VT_SWORD_ATTACK_DAMAGE) &&
verifier.EndTable();
}
+ AttackerT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const;
+ void UnPackTo(AttackerT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const;
+ static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const AttackerT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
};
-struct MuLanBuilder {
+struct AttackerBuilder {
flatbuffers::FlatBufferBuilder &fbb_;
flatbuffers::uoffset_t start_;
void add_sword_attack_damage(int32_t sword_attack_damage) {
- fbb_.AddElement(MuLan::VT_SWORD_ATTACK_DAMAGE, sword_attack_damage, 0);
+ fbb_.AddElement(Attacker::VT_SWORD_ATTACK_DAMAGE, sword_attack_damage, 0);
}
- MuLanBuilder(flatbuffers::FlatBufferBuilder &_fbb)
+ AttackerBuilder(flatbuffers::FlatBufferBuilder &_fbb)
: fbb_(_fbb) {
start_ = fbb_.StartTable();
}
- MuLanBuilder &operator=(const MuLanBuilder &);
- flatbuffers::Offset Finish() {
+ AttackerBuilder &operator=(const AttackerBuilder &);
+ flatbuffers::Offset Finish() {
const auto end = fbb_.EndTable(start_, 1);
- auto o = flatbuffers::Offset(end);
+ auto o = flatbuffers::Offset(end);
return o;
}
};
-inline flatbuffers::Offset CreateMuLan(
+inline flatbuffers::Offset CreateAttacker(
flatbuffers::FlatBufferBuilder &_fbb,
int32_t sword_attack_damage = 0) {
- MuLanBuilder builder_(_fbb);
+ AttackerBuilder builder_(_fbb);
builder_.add_sword_attack_damage(sword_attack_damage);
return builder_.Finish();
}
-struct Rapunzel FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
- enum {
- VT_HAIR_LENGTH = 4
- };
- int32_t hair_length() const {
- return GetField(VT_HAIR_LENGTH, 0);
- }
- bool Verify(flatbuffers::Verifier &verifier) const {
- return VerifyTableStart(verifier) &&
- VerifyField(verifier, VT_HAIR_LENGTH) &&
- verifier.EndTable();
+flatbuffers::Offset CreateAttacker(flatbuffers::FlatBufferBuilder &_fbb, const AttackerT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
+
+struct MovieT : public flatbuffers::NativeTable {
+ typedef Movie TableType;
+ CharacterUnion main_character;
+ std::vector characters;
+ MovieT() {
}
};
-struct RapunzelBuilder {
- flatbuffers::FlatBufferBuilder &fbb_;
- flatbuffers::uoffset_t start_;
- void add_hair_length(int32_t hair_length) {
- fbb_.AddElement(Rapunzel::VT_HAIR_LENGTH, hair_length, 0);
- }
- RapunzelBuilder(flatbuffers::FlatBufferBuilder &_fbb)
- : fbb_(_fbb) {
- start_ = fbb_.StartTable();
- }
- RapunzelBuilder &operator=(const RapunzelBuilder &);
- flatbuffers::Offset Finish() {
- const auto end = fbb_.EndTable(start_, 1);
- auto o = flatbuffers::Offset(end);
- return o;
- }
-};
-
-inline flatbuffers::Offset CreateRapunzel(
- flatbuffers::FlatBufferBuilder &_fbb,
- int32_t hair_length = 0) {
- RapunzelBuilder builder_(_fbb);
- builder_.add_hair_length(hair_length);
- return builder_.Finish();
-}
-
-struct Belle FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
- enum {
- VT_BOOKS_READ = 4
- };
- int32_t books_read() const {
- return GetField(VT_BOOKS_READ, 0);
- }
- bool Verify(flatbuffers::Verifier &verifier) const {
- return VerifyTableStart(verifier) &&
- VerifyField(verifier, VT_BOOKS_READ) &&
- verifier.EndTable();
- }
-};
-
-struct BelleBuilder {
- flatbuffers::FlatBufferBuilder &fbb_;
- flatbuffers::uoffset_t start_;
- void add_books_read(int32_t books_read) {
- fbb_.AddElement(Belle::VT_BOOKS_READ, books_read, 0);
- }
- BelleBuilder(flatbuffers::FlatBufferBuilder &_fbb)
- : fbb_(_fbb) {
- start_ = fbb_.StartTable();
- }
- BelleBuilder &operator=(const BelleBuilder &);
- flatbuffers::Offset Finish() {
- const auto end = fbb_.EndTable(start_, 1);
- auto o = flatbuffers::Offset(end);
- return o;
- }
-};
-
-inline flatbuffers::Offset CreateBelle(
- flatbuffers::FlatBufferBuilder &_fbb,
- int32_t books_read = 0) {
- BelleBuilder builder_(_fbb);
- builder_.add_books_read(books_read);
- return builder_.Finish();
-}
-
struct Movie FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+ typedef MovieT NativeTableType;
enum {
- VT_CHARACTERS_TYPE = 4,
- VT_CHARACTERS = 6
+ VT_MAIN_CHARACTER_TYPE = 4,
+ VT_MAIN_CHARACTER = 6,
+ VT_CHARACTERS_TYPE = 8,
+ VT_CHARACTERS = 10
};
+ Character main_character_type() const {
+ return static_cast(GetField(VT_MAIN_CHARACTER_TYPE, 0));
+ }
+ bool mutate_main_character_type(Character _main_character_type) {
+ return SetField(VT_MAIN_CHARACTER_TYPE, static_cast(_main_character_type), 0);
+ }
+ const void *main_character() const {
+ return GetPointer(VT_MAIN_CHARACTER);
+ }
+ template const T *main_character_as() const;
+ const Attacker *main_character_as_MuLan() const {
+ return main_character_type() == Character_MuLan ? static_cast(main_character()) : nullptr;
+ }
+ const Rapunzel *main_character_as_Rapunzel() const {
+ return main_character_type() == Character_Rapunzel ? static_cast(main_character()) : nullptr;
+ }
+ const BookReader *main_character_as_Belle() const {
+ return main_character_type() == Character_Belle ? static_cast(main_character()) : nullptr;
+ }
+ const BookReader *main_character_as_BookFan() const {
+ return main_character_type() == Character_BookFan ? static_cast(main_character()) : nullptr;
+ }
+ const flatbuffers::String *main_character_as_Other() const {
+ return main_character_type() == Character_Other ? static_cast(main_character()) : nullptr;
+ }
+ const flatbuffers::String *main_character_as_Unused() const {
+ return main_character_type() == Character_Unused ? static_cast(main_character()) : nullptr;
+ }
+ void *mutable_main_character() {
+ return GetPointer(VT_MAIN_CHARACTER);
+ }
const flatbuffers::Vector *characters_type() const {
return GetPointer *>(VT_CHARACTERS_TYPE);
}
+ flatbuffers::Vector *mutable_characters_type() {
+ return GetPointer *>(VT_CHARACTERS_TYPE);
+ }
const flatbuffers::Vector> *characters() const {
return GetPointer> *>(VT_CHARACTERS);
}
+ flatbuffers::Vector> *mutable_characters() {
+ return GetPointer> *>(VT_CHARACTERS);
+ }
bool Verify(flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) &&
+ VerifyField(verifier, VT_MAIN_CHARACTER_TYPE) &&
+ VerifyField(verifier, VT_MAIN_CHARACTER) &&
+ VerifyCharacter(verifier, main_character(), main_character_type()) &&
VerifyField(verifier, VT_CHARACTERS_TYPE) &&
verifier.Verify(characters_type()) &&
VerifyField(verifier, VT_CHARACTERS) &&
@@ -198,11 +269,20 @@ struct Movie FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
VerifyCharacterVector(verifier, characters(), characters_type()) &&
verifier.EndTable();
}
+ MovieT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const;
+ void UnPackTo(MovieT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const;
+ static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const MovieT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
};
struct MovieBuilder {
flatbuffers::FlatBufferBuilder &fbb_;
flatbuffers::uoffset_t start_;
+ void add_main_character_type(Character main_character_type) {
+ fbb_.AddElement(Movie::VT_MAIN_CHARACTER_TYPE, static_cast(main_character_type), 0);
+ }
+ void add_main_character(flatbuffers::Offset main_character) {
+ fbb_.AddOffset(Movie::VT_MAIN_CHARACTER, main_character);
+ }
void add_characters_type(flatbuffers::Offset> characters_type) {
fbb_.AddOffset(Movie::VT_CHARACTERS_TYPE, characters_type);
}
@@ -215,7 +295,7 @@ struct MovieBuilder {
}
MovieBuilder &operator=(const MovieBuilder &);
flatbuffers::Offset Finish() {
- const auto end = fbb_.EndTable(start_, 2);
+ const auto end = fbb_.EndTable(start_, 4);
auto o = flatbuffers::Offset(end);
return o;
}
@@ -223,40 +303,118 @@ struct MovieBuilder {
inline flatbuffers::Offset CreateMovie(
flatbuffers::FlatBufferBuilder &_fbb,
+ Character main_character_type = Character_NONE,
+ flatbuffers::Offset main_character = 0,
flatbuffers::Offset> characters_type = 0,
flatbuffers::Offset>> characters = 0) {
MovieBuilder builder_(_fbb);
builder_.add_characters(characters);
builder_.add_characters_type(characters_type);
+ builder_.add_main_character(main_character);
+ builder_.add_main_character_type(main_character_type);
return builder_.Finish();
}
inline flatbuffers::Offset CreateMovieDirect(
flatbuffers::FlatBufferBuilder &_fbb,
+ Character main_character_type = Character_NONE,
+ flatbuffers::Offset main_character = 0,
const std::vector *characters_type = nullptr,
const std::vector> *characters = nullptr) {
return CreateMovie(
_fbb,
+ main_character_type,
+ main_character,
characters_type ? _fbb.CreateVector(*characters_type) : 0,
characters ? _fbb.CreateVector>(*characters) : 0);
}
+flatbuffers::Offset CreateMovie(flatbuffers::FlatBufferBuilder &_fbb, const MovieT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
+
+inline AttackerT *Attacker::UnPack(const flatbuffers::resolver_function_t *_resolver) const {
+ auto _o = new AttackerT();
+ UnPackTo(_o, _resolver);
+ return _o;
+}
+
+inline void Attacker::UnPackTo(AttackerT *_o, const flatbuffers::resolver_function_t *_resolver) const {
+ (void)_o;
+ (void)_resolver;
+ { auto _e = sword_attack_damage(); _o->sword_attack_damage = _e; };
+}
+
+inline flatbuffers::Offset Attacker::Pack(flatbuffers::FlatBufferBuilder &_fbb, const AttackerT* _o, const flatbuffers::rehasher_function_t *_rehasher) {
+ return CreateAttacker(_fbb, _o, _rehasher);
+}
+
+inline flatbuffers::Offset CreateAttacker(flatbuffers::FlatBufferBuilder &_fbb, const AttackerT *_o, const flatbuffers::rehasher_function_t *_rehasher) {
+ (void)_rehasher;
+ (void)_o;
+ auto _sword_attack_damage = _o->sword_attack_damage;
+ return CreateAttacker(
+ _fbb,
+ _sword_attack_damage);
+}
+
+inline MovieT *Movie::UnPack(const flatbuffers::resolver_function_t *_resolver) const {
+ auto _o = new MovieT();
+ UnPackTo(_o, _resolver);
+ return _o;
+}
+
+inline void Movie::UnPackTo(MovieT *_o, const flatbuffers::resolver_function_t *_resolver) const {
+ (void)_o;
+ (void)_resolver;
+ { auto _e = main_character_type(); _o->main_character.type = _e; };
+ { auto _e = main_character(); if (_e) _o->main_character.value = CharacterUnion::UnPack(_e, main_character_type(), _resolver); };
+ { auto _e = characters_type(); if (_e) { _o->characters.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->characters[_i].type = (Character)_e->Get(_i); } } };
+ { auto _e = characters(); if (_e) { _o->characters.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->characters[_i].value = CharacterUnion::UnPack(_e->Get(_i), characters_type()->GetEnum(_i), _resolver); } } };
+}
+
+inline flatbuffers::Offset Movie::Pack(flatbuffers::FlatBufferBuilder &_fbb, const MovieT* _o, const flatbuffers::rehasher_function_t *_rehasher) {
+ return CreateMovie(_fbb, _o, _rehasher);
+}
+
+inline flatbuffers::Offset CreateMovie(flatbuffers::FlatBufferBuilder &_fbb, const MovieT *_o, const flatbuffers::rehasher_function_t *_rehasher) {
+ (void)_rehasher;
+ (void)_o;
+ auto _main_character_type = _o->main_character.type;
+ auto _main_character = _o->main_character.Pack(_fbb);
+ auto _characters_type = _o->characters.size() ? _fbb.CreateVector(_o->characters.size(), [&](size_t i) { return static_cast(_o->characters[i].type); }) : 0;
+ auto _characters = _o->characters.size() ? _fbb.CreateVector>(_o->characters.size(), [&](size_t i) { return _o->characters[i].Pack(_fbb, _rehasher); }) : 0;
+ return CreateMovie(
+ _fbb,
+ _main_character_type,
+ _main_character,
+ _characters_type,
+ _characters);
+}
+
inline bool VerifyCharacter(flatbuffers::Verifier &verifier, const void *obj, Character type) {
switch (type) {
case Character_NONE: {
return true;
}
case Character_MuLan: {
- auto ptr = reinterpret_cast(obj);
+ auto ptr = reinterpret_cast(obj);
return verifier.VerifyTable(ptr);
}
case Character_Rapunzel: {
- auto ptr = reinterpret_cast(obj);
- return verifier.VerifyTable(ptr);
+ return true;
}
case Character_Belle: {
- auto ptr = reinterpret_cast(obj);
- return verifier.VerifyTable(ptr);
+ return true;
+ }
+ case Character_BookFan: {
+ return true;
+ }
+ case Character_Other: {
+ auto ptr = reinterpret_cast(obj);
+ return verifier.Verify(ptr);
+ }
+ case Character_Unused: {
+ auto ptr = reinterpret_cast(obj);
+ return verifier.Verify(ptr);
}
default: return false;
}
@@ -273,10 +431,112 @@ inline bool VerifyCharacterVector(flatbuffers::Verifier &verifier, const flatbuf
return true;
}
+inline void *CharacterUnion::UnPack(const void *obj, Character type, const flatbuffers::resolver_function_t *resolver) {
+ switch (type) {
+ case Character_MuLan: {
+ auto ptr = reinterpret_cast(obj);
+ return ptr->UnPack(resolver);
+ }
+ case Character_Rapunzel: {
+ auto ptr = reinterpret_cast(obj);
+ return new Rapunzel(*ptr);
+ }
+ case Character_Belle: {
+ auto ptr = reinterpret_cast(obj);
+ return new BookReader(*ptr);
+ }
+ case Character_BookFan: {
+ auto ptr = reinterpret_cast(obj);
+ return new BookReader(*ptr);
+ }
+ case Character_Other: {
+ auto ptr = reinterpret_cast(obj);
+ return new std::string(ptr->c_str(), ptr->size());
+ }
+ case Character_Unused: {
+ auto ptr = reinterpret_cast(obj);
+ return new std::string(ptr->c_str(), ptr->size());
+ }
+ default: return nullptr;
+ }
+}
+
+inline flatbuffers::Offset CharacterUnion::Pack(flatbuffers::FlatBufferBuilder &_fbb, const flatbuffers::rehasher_function_t *_rehasher) const {
+ switch (type) {
+ case Character_MuLan: {
+ auto ptr = reinterpret_cast(value);
+ return CreateAttacker(_fbb, ptr, _rehasher).Union();
+ }
+ case Character_Rapunzel: {
+ auto ptr = reinterpret_cast(value);
+ return _fbb.CreateStruct(*ptr).Union();
+ }
+ case Character_Belle: {
+ auto ptr = reinterpret_cast(value);
+ return _fbb.CreateStruct(*ptr).Union();
+ }
+ case Character_BookFan: {
+ auto ptr = reinterpret_cast