diff --git a/docs/source/Schemas.md b/docs/source/Schemas.md index 322ec4f204644773674204d17199eea6326389bd..c4a942166b042a67f00a3ac45e22a11b33c743cb 100755 --- a/docs/source/Schemas.md +++ b/docs/source/Schemas.md @@ -158,6 +158,10 @@ If you have a need to distinguish between different FlatBuffers in a more open-ended way, for example for use as files, see the file identification feature below. +There is an experimental support only in C++ for a vector of unions +(and types). In the example IDL file above, use [Any] to add a +vector of Any to Monster table. + ### Namespaces These will generate the corresponding namespace in C++ for all helper diff --git a/include/flatbuffers/idl.h b/include/flatbuffers/idl.h index ad90d53589df2f493cce1078321f54b7eeb1c247..aab4b8fa64580844aa5106173ea89fd544694447 100644 --- a/include/flatbuffers/idl.h +++ b/include/flatbuffers/idl.h @@ -356,10 +356,25 @@ struct IDLOptions { bool allow_non_utf8; // Possible options for the more general generator below. - enum Language { kJava, kCSharp, kGo, kMAX }; + enum Language { + kJava = 1 << 0, + kCSharp = 1 << 1, + kGo = 1 << 2, + kCpp = 1 << 3, + kJs = 1 << 4, + kPython = 1 << 5, + kPhp = 1 << 6, + kJson = 1 << 7, + kBinary = 1 << 8, + kMAX + }; Language lang; + // The corresponding language bit will be set if a language is included + // for code generation. + unsigned long lang_to_generate; + IDLOptions() : strict_json(false), skip_js_exports(false), @@ -378,7 +393,8 @@ struct IDLOptions { cpp_object_api_pointer_type("std::unique_ptr"), union_value_namespacing(true), allow_non_utf8(false), - lang(IDLOptions::kJava) {} + lang(IDLOptions::kJava), + lang_to_generate(0) {} }; // This encapsulates where the parser is in the current source file. diff --git a/samples/monster_generated.h b/samples/monster_generated.h index 3c86e87a4a0b508c3ed3985f49bcd717f6b0ec4e..0cf21f7bce9c19a14d687edded56db35f2527538 100644 --- a/samples/monster_generated.h +++ b/samples/monster_generated.h @@ -99,6 +99,7 @@ struct EquipmentUnion { }; bool VerifyEquipment(flatbuffers::Verifier &verifier, const void *obj, Equipment type); +bool VerifyEquipmentVector(flatbuffers::Verifier &verifier, const flatbuffers::Vector<flatbuffers::Offset<void>> *values, const flatbuffers::Vector<uint8_t> *types); MANUALLY_ALIGNED_STRUCT(4) Vec3 FLATBUFFERS_FINAL_CLASS { private: @@ -510,6 +511,17 @@ inline bool VerifyEquipment(flatbuffers::Verifier &verifier, const void *obj, Eq } } +inline bool VerifyEquipmentVector(flatbuffers::Verifier &verifier, const flatbuffers::Vector<flatbuffers::Offset<void>> *values, const flatbuffers::Vector<uint8_t> *types) { + if (values->size() != types->size()) return false; + for (flatbuffers::uoffset_t i = 0; i < values->size(); ++i) { + if (!VerifyEquipment( + verifier, values->Get(i), types->GetEnum<Equipment>(i))) { + return false; + } + } + return true; +} + inline flatbuffers::NativeTable *EquipmentUnion::UnPack(const void *obj, Equipment type, const flatbuffers::resolver_function_t *resolver) { switch (type) { case Equipment_Weapon: { diff --git a/src/flatc.cpp b/src/flatc.cpp index 7fc04012f554b00a823f37864396e158ea450353..f5553e85fea644ed95fcbc74f68bab77017d33a9 100644 --- a/src/flatc.cpp +++ b/src/flatc.cpp @@ -47,17 +47,17 @@ struct Generator { const Generator generators[] = { { flatbuffers::GenerateBinary, "-b", "--binary", "binary", nullptr, - flatbuffers::IDLOptions::kMAX, + flatbuffers::IDLOptions::kBinary, "Generate wire format binaries for any data definitions", flatbuffers::BinaryMakeRule }, { flatbuffers::GenerateTextFile, "-t", "--json", "text", nullptr, - flatbuffers::IDLOptions::kMAX, + flatbuffers::IDLOptions::kJson, "Generate text output for any data definitions", flatbuffers::TextMakeRule }, { flatbuffers::GenerateCPP, "-c", "--cpp", "C++", flatbuffers::GenerateCppGRPC, - flatbuffers::IDLOptions::kMAX, + flatbuffers::IDLOptions::kCpp, "Generate C++ headers for tables/structs", flatbuffers::CPPMakeRule }, { flatbuffers::GenerateGo, "-g", "--go", "Go", @@ -72,7 +72,7 @@ const Generator generators[] = { flatbuffers::GeneralMakeRule }, { flatbuffers::GenerateJS, "-s", "--js", "JavaScript", nullptr, - flatbuffers::IDLOptions::kMAX, + flatbuffers::IDLOptions::kJs, "Generate JavaScript code for tables/structs", flatbuffers::JSMakeRule }, { flatbuffers::GenerateGeneral, "-n", "--csharp", "C#", @@ -82,12 +82,12 @@ const Generator generators[] = { flatbuffers::GeneralMakeRule }, { flatbuffers::GeneratePython, "-p", "--python", "Python", nullptr, - flatbuffers::IDLOptions::kMAX, + flatbuffers::IDLOptions::kPython, "Generate Python files for tables/structs", flatbuffers::GeneralMakeRule }, { flatbuffers::GeneratePhp, nullptr, "--php", "PHP", nullptr, - flatbuffers::IDLOptions::kMAX, + flatbuffers::IDLOptions::kPhp, "Generate PHP files for tables/structs", flatbuffers::GeneralMakeRule }, }; @@ -267,6 +267,7 @@ int main(int argc, const char *argv[]) { arg == generators[i].generator_opt_short)) { generator_enabled[i] = true; any_generator = true; + opts.lang_to_generate |= generators[i].lang; goto found; } } diff --git a/src/idl_gen_cpp.cpp b/src/idl_gen_cpp.cpp index 6696438b547c0ac40dc01061180bb95ef5cf00d2..c8acb1fd4a37e71449fa3dc2b2abb78d54ecd1fb 100644 --- a/src/idl_gen_cpp.cpp +++ b/src/idl_gen_cpp.cpp @@ -454,6 +454,13 @@ class CppGenerator : public BaseGenerator { enum_def.name + " type)"; } + static std::string UnionVectorVerifySignature(const EnumDef &enum_def) { + return "bool Verify" + enum_def.name + "Vector" + + "(flatbuffers::Verifier &verifier, " + + "const flatbuffers::Vector<flatbuffers::Offset<void>> *values, " + + "const flatbuffers::Vector<uint8_t> *types)"; + } + static std::string UnionUnPackSignature(const EnumDef &enum_def, bool inclass) { return (inclass ? "static " : "") + @@ -685,6 +692,7 @@ class CppGenerator : public BaseGenerator { if (enum_def.is_union) { code_ += UnionVerifySignature(enum_def) + ";"; + code_ += UnionVectorVerifySignature(enum_def) + ";"; code_ += ""; } } @@ -721,6 +729,18 @@ class CppGenerator : public BaseGenerator { code_ += "}"; code_ += ""; + code_ += "inline " + UnionVectorVerifySignature(enum_def) + " {"; + code_ += " if (values->size() != types->size()) return false;"; + code_ += " for (flatbuffers::uoffset_t i = 0; i < values->size(); ++i) {"; + code_ += " if (!Verify" + enum_def.name + "("; + code_ += " verifier, values->Get(i), types->GetEnum<" + enum_def.name + ">(i))) { "; + code_ += " return false; "; + code_ += " }"; + code_ += " }"; + code_ += " return true;"; + code_ += "}"; + code_ += ""; + if (parser_.opts.generate_object_based_api) { // Generate union Unpack() and Pack() functions. code_ += "inline " + UnionUnPackSignature(enum_def, false) + " {"; @@ -995,6 +1015,10 @@ class CppGenerator : public BaseGenerator { } break; } + case BASE_TYPE_UNION: { + code_ += "{{PRE}}Verify{{ENUM_NAME}}Vector(verifier, {{NAME}}(), {{NAME}}_type())\\"; + break; + } default: break; } diff --git a/src/idl_gen_general.cpp b/src/idl_gen_general.cpp index 8c3220785f241714dbb7706ff9c039f92a836284..857bf46c871284f64beade33fc03f4d106fbaa3b 100644 --- a/src/idl_gen_general.cpp +++ b/src/idl_gen_general.cpp @@ -70,108 +70,80 @@ struct LanguageParameters { CommentConfig comment_config; }; -LanguageParameters language_parameters[] = { - { - IDLOptions::kJava, - false, - ".java", - "String", - "boolean ", - " {\n", - "class ", - " final ", - "final ", - "final class ", - ";\n", - "()", - "", - " extends ", - "package ", - ";", - "", - "_bb.order(ByteOrder.LITTLE_ENDIAN); ", - "position()", - "offset()", - "", - "", - "", - "import java.nio.*;\nimport java.lang.*;\nimport java.util.*;\n" - "import com.google.flatbuffers.*;\n\n@SuppressWarnings(\"unused\")\n", +const LanguageParameters& GetLangParams(IDLOptions::Language lang) { + static LanguageParameters language_parameters[] = { { - "/**", - " *", - " */", + IDLOptions::kJava, + false, + ".java", + "String", + "boolean ", + " {\n", + "class ", + " final ", + "final ", + "final class ", + ";\n", + "()", + "", + " extends ", + "package ", + ";", + "", + "_bb.order(ByteOrder.LITTLE_ENDIAN); ", + "position()", + "offset()", + "", + "", + "", + "import java.nio.*;\nimport java.lang.*;\nimport java.util.*;\n" + "import com.google.flatbuffers.*;\n\n@SuppressWarnings(\"unused\")\n", + { + "/**", + " *", + " */", + }, }, - }, - { - IDLOptions::kCSharp, - true, - ".cs", - "string", - "bool ", - "\n{\n", - "struct ", - " readonly ", - "", - "enum ", - ",\n", - " { get", - "} ", - " : ", - "namespace ", - "\n{", - "\n}\n", - "", - "Position", - "Offset", - "__p.", - "Table.", - "?", - "using System;\nusing FlatBuffers;\n\n", { - nullptr, - "///", - nullptr, + IDLOptions::kCSharp, + true, + ".cs", + "string", + "bool ", + "\n{\n", + "struct ", + " readonly ", + "", + "enum ", + ",\n", + " { get", + "} ", + " : ", + "namespace ", + "\n{", + "\n}\n", + "", + "Position", + "Offset", + "__p.", + "Table.", + "?", + "using System;\nusing FlatBuffers;\n\n", + { + nullptr, + "///", + nullptr, + }, }, - }, - // TODO: add Go support to the general generator. - // WARNING: this is currently only used for generating make rules for Go. - { - IDLOptions::kGo, - true, - ".go", - "string", - "bool ", - "\n{\n", - "class ", - "const ", - " ", - "class ", - ";\n", - "()", - "", - "", - "package ", - "", - "", - "", - "position()", - "offset()", - "", - "", - "", - "import (\n\tflatbuffers \"github.com/google/flatbuffers/go\"\n)", - { - nullptr, - "///", - nullptr, - }, - } -}; + }; -static_assert(sizeof(language_parameters) / sizeof(LanguageParameters) == - IDLOptions::kMAX, - "Please add extra elements to the arrays above."); + if (lang == IDLOptions::kJava) { + return language_parameters[0]; + } else { + assert(lang == IDLOptions::kCSharp); + return language_parameters[1]; + } +} namespace general { class GeneralGenerator : public BaseGenerator { @@ -179,10 +151,10 @@ class GeneralGenerator : public BaseGenerator { GeneralGenerator(const Parser &parser, const std::string &path, const std::string &file_name) : BaseGenerator(parser, path, file_name, "", "."), - lang_(language_parameters[parser_.opts.lang]), + lang_(GetLangParams(parser_.opts.lang)), cur_name_space_( nullptr ) { - assert(parser_.opts.lang <= IDLOptions::kMAX); - }; + } + GeneralGenerator &operator=(const GeneralGenerator &); bool generate() { std::string one_file_code; @@ -258,9 +230,16 @@ static bool IsEnum(const Type& type) { } std::string GenTypeBasic(const Type &type, bool enableLangOverrides) { - static const char *gtypename[] = { + static const char *java_typename[] = { #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \ - #JTYPE, #NTYPE, #GTYPE, + #JTYPE, + FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) + #undef FLATBUFFERS_TD + }; + + static const char *csharp_typename[] = { + #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \ + #NTYPE, FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) #undef FLATBUFFERS_TD }; @@ -274,7 +253,12 @@ std::string GenTypeBasic(const Type &type, bool enableLangOverrides) { } } - return gtypename[type.base_type * IDLOptions::kMAX + lang_.language]; + if (lang_.language == IDLOptions::kJava) { + return java_typename[type.base_type]; + } else { + assert(lang_.language == IDLOptions::kCSharp); + return csharp_typename[type.base_type]; + } } std::string GenTypeBasic(const Type &type) { @@ -1352,7 +1336,7 @@ void GenStruct(StructDef &struct_def, std::string *code_ptr) { code += (lang_.language != IDLOptions::kJava) ? ";" : ""; code += "\n\n"; } - const LanguageParameters & lang_; + const LanguageParameters& lang_; // This tracks the current namespace used to determine if a type need to be prefixed by its namespace const Namespace *cur_name_space_; }; @@ -1367,7 +1351,7 @@ bool GenerateGeneral(const Parser &parser, const std::string &path, std::string GeneralMakeRule(const Parser &parser, const std::string &path, const std::string &file_name) { assert(parser.opts.lang <= IDLOptions::kMAX); - auto lang = language_parameters[parser.opts.lang]; + const auto &lang = GetLangParams(parser.opts.lang); std::string make_rule; diff --git a/src/idl_parser.cpp b/src/idl_parser.cpp index cb02fc484ed840077f662f9a7a2a1d140117bff9..fa7b98bf5a4e770137c856420d17c369e4fc1223 100644 --- a/src/idl_parser.cpp +++ b/src/idl_parser.cpp @@ -554,12 +554,6 @@ CheckedError Parser::ParseType(Type &type) { return Error( "nested vector types not supported (wrap in table first)."); } - if (subtype.base_type == BASE_TYPE_UNION) { - // We could support this if we stored a struct of 2 elements per - // union element. - return Error( - "vector of union types not supported (wrap in table first)."); - } type = Type(BASE_TYPE_VECTOR, subtype.struct_def, subtype.enum_def); type.element = subtype.base_type; EXPECT(']'); @@ -611,6 +605,19 @@ CheckedError Parser::ParseField(StructDef &struct_def) { // with a special suffix. ECHECK(AddField(struct_def, name + UnionTypeFieldSuffix(), type.enum_def->underlying_type, &typefield)); + } else if (type.base_type == BASE_TYPE_VECTOR && + type.element == BASE_TYPE_UNION) { + // Only cpp supports the union vector feature so far. + if (opts.lang_to_generate != IDLOptions::kCpp) { + return Error("Vectors of unions are not yet supported in all " + "the specified programming languages."); + } + // For vector of union fields, add a second auto-generated vector field to + // hold the types, with a special suffix. + Type union_vector(BASE_TYPE_VECTOR, nullptr, type.enum_def); + union_vector.element = BASE_TYPE_UTYPE; + ECHECK(AddField(struct_def, name + UnionTypeFieldSuffix(), + union_vector, &typefield)); } FieldDef *field; diff --git a/tests/generate_code.sh b/tests/generate_code.sh index bf6f3c8ebf041477447d89e9ad12061d772f0607..0510b01d2b4dee7075d1399220da495b256a49f8 100755 --- a/tests/generate_code.sh +++ b/tests/generate_code.sh @@ -16,7 +16,7 @@ ../flatc --cpp --java --csharp --go --binary --python --js --php --grpc --gen-mutable --gen-object-api --no-includes monster_test.fbs monsterdata_test.json ../flatc --cpp --java --csharp --go --binary --python --js --php --gen-mutable -o namespace_test namespace_test/namespace_test1.fbs namespace_test/namespace_test2.fbs -../flatc --binary --schema monster_test.fbs +../flatc --cpp -o union_vector ./union_vector/union_vector.fbs cd ../samples ../flatc --cpp --gen-mutable --gen-object-api monster.fbs cd ../reflection diff --git a/tests/monster_test_generated.h b/tests/monster_test_generated.h index 3fc7cbeec10bc3253a88a361d5f6de41ad3ce38a..b96f85e8550c01c19430aae82e6155a9bb902bc3 100644 --- a/tests/monster_test_generated.h +++ b/tests/monster_test_generated.h @@ -136,6 +136,7 @@ struct AnyUnion { }; bool VerifyAny(flatbuffers::Verifier &verifier, const void *obj, Any type); +bool VerifyAnyVector(flatbuffers::Verifier &verifier, const flatbuffers::Vector<flatbuffers::Offset<void>> *values, const flatbuffers::Vector<uint8_t> *types); MANUALLY_ALIGNED_STRUCT(2) Test FLATBUFFERS_FINAL_CLASS { private: @@ -1198,6 +1199,17 @@ inline bool VerifyAny(flatbuffers::Verifier &verifier, const void *obj, Any type } } +inline bool VerifyAnyVector(flatbuffers::Verifier &verifier, const flatbuffers::Vector<flatbuffers::Offset<void>> *values, const flatbuffers::Vector<uint8_t> *types) { + if (values->size() != types->size()) return false; + for (flatbuffers::uoffset_t i = 0; i < values->size(); ++i) { + if (!VerifyAny( + verifier, values->Get(i), types->GetEnum<Any>(i))) { + return false; + } + } + return true; +} + inline flatbuffers::NativeTable *AnyUnion::UnPack(const void *obj, Any type, const flatbuffers::resolver_function_t *resolver) { switch (type) { case Any_Monster: { diff --git a/tests/test.cpp b/tests/test.cpp index 01d23e0a642a922582957b8294671287c41d027a..02a8b8265307a4d4fbc571bf82edf8929f57c7e0 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -21,6 +21,7 @@ #include "monster_test_generated.h" #include "namespace_test/namespace_test1_generated.h" #include "namespace_test/namespace_test2_generated.h" +#include "union_vector/union_vector_generated.h" #ifndef FLATBUFFERS_CPP98_STL #include <random> @@ -954,7 +955,6 @@ void ErrorTest() { TestError("@", "illegal"); TestError("table 1", "expecting"); TestError("table X { Y:[[int]]; }", "nested vector"); - TestError("union Z { X } table X { Y:[Z]; }", "vector of union"); TestError("table X { Y:1; }", "illegal type"); TestError("table X { Y:int; Y:int; }", "field already"); TestError("struct X { Y:string; }", "only scalar"); @@ -1276,6 +1276,67 @@ void ParseUnionTest() { "{ e_type: N_A, e: {} }"), true); } +void UnionVectorTest() { + // load FlatBuffer fbs schema. + // TODO: load a JSON file with such a vector when JSON support is ready. + std::string schemafile; + TEST_EQ(flatbuffers::LoadFile( + "tests/union_vector/union_vector.fbs", false, &schemafile), true); + + // parse schema. + flatbuffers::IDLOptions idl_opts; + idl_opts.lang_to_generate |= flatbuffers::IDLOptions::kCpp; + flatbuffers::Parser parser(idl_opts); + const char *include_directories[] = { "tests/union_vector", nullptr }; + TEST_EQ(parser.Parse(schemafile.c_str(), include_directories), true); + + flatbuffers::FlatBufferBuilder fbb; + + // union types. + std::vector<uint8_t> types; + types.push_back(static_cast<uint8_t>(Character_Belle)); + types.push_back(static_cast<uint8_t>(Character_Rapunzel)); + types.push_back(static_cast<uint8_t>(Character_MuLan)); + + // union values. + std::vector<flatbuffers::Offset<void>> characters; + characters.push_back(CreateBelle(fbb, /*books_read=*/7).Union()); + characters.push_back(CreateRapunzel(fbb, /*hair_length=*/6).Union()); + characters.push_back(CreateMuLan(fbb, /*sward_attack_damage=*/5).Union()); + + // create Movie. + const auto movie_offset = + CreateMovie(fbb, fbb.CreateVector(types), fbb.CreateVector(characters)); + FinishMovieBuffer(fbb, movie_offset); + uint8_t *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<Character>(0) == Character_Belle, + true); + TEST_EQ( + movie->characters_type()->GetEnum<Character>(1) == Character_Rapunzel, + true); + TEST_EQ( + movie->characters_type()->GetEnum<Character>(2) == Character_MuLan, + true); + + TEST_EQ(movie->characters()->size(), 3); + const Belle *belle = + reinterpret_cast<const Belle*>(movie->characters()->Get(0)); + TEST_EQ(belle->books_read(), 7); + const Rapunzel *rapunzel = + reinterpret_cast<const Rapunzel*>(movie->characters()->Get(1)); + TEST_EQ(rapunzel->hair_length(), 6); + const MuLan *mu_lan = + reinterpret_cast<const MuLan*>(movie->characters()->Get(2)); + TEST_EQ(mu_lan->sword_attack_damage(), 5); +} + void ConformTest() { flatbuffers::Parser parser; TEST_EQ(parser.Parse("table T { A:int; } enum E:byte { A }"), true); @@ -1330,6 +1391,7 @@ int main(int /*argc*/, const char * /*argv*/[]) { InvalidUTF8Test(); UnknownFieldsTest(); ParseUnionTest(); + UnionVectorTest(); ConformTest(); if (!testing_fails) { diff --git a/tests/union_vector/union_vector.fbs b/tests/union_vector/union_vector.fbs new file mode 100644 index 0000000000000000000000000000000000000000..4957cd862daff035d1fc90d74d21cb3dfcf39a5d --- /dev/null +++ b/tests/union_vector/union_vector.fbs @@ -0,0 +1,24 @@ +table MuLan { + sword_attack_damage: int; +} + +table Rapunzel { + hair_length: int; +} + +table Belle { + books_read: int; +} + +union Character { + MuLan, + Rapunzel, + Belle, +} + +table Movie { + characters: [Character]; +} + +root_type Movie; +file_identifier "MOVI"; diff --git a/tests/union_vector/union_vector_generated.h b/tests/union_vector/union_vector_generated.h new file mode 100644 index 0000000000000000000000000000000000000000..180b3d99a86ba2b488324baccbc706e29f4ade45 --- /dev/null +++ b/tests/union_vector/union_vector_generated.h @@ -0,0 +1,300 @@ +// automatically generated by the FlatBuffers compiler, do not modify + + +#ifndef FLATBUFFERS_GENERATED_UNIONVECTOR_H_ +#define FLATBUFFERS_GENERATED_UNIONVECTOR_H_ + +#include "flatbuffers/flatbuffers.h" + +struct MuLan; + +struct Rapunzel; + +struct Belle; + +struct Movie; + +enum Character { + Character_NONE = 0, + Character_MuLan = 1, + Character_Rapunzel = 2, + Character_Belle = 3, + Character_MIN = Character_NONE, + Character_MAX = Character_Belle +}; + +inline const char **EnumNamesCharacter() { + static const char *names[] = { + "NONE", + "MuLan", + "Rapunzel", + "Belle", + nullptr + }; + return names; +} + +inline const char *EnumNameCharacter(Character e) { + const size_t index = static_cast<int>(e); + return EnumNamesCharacter()[index]; +} + +template<typename T> struct CharacterTraits { + static const Character enum_value = Character_NONE; +}; + +template<> struct CharacterTraits<MuLan> { + static const Character enum_value = Character_MuLan; +}; + +template<> struct CharacterTraits<Rapunzel> { + static const Character enum_value = Character_Rapunzel; +}; + +template<> struct CharacterTraits<Belle> { + static const Character enum_value = Character_Belle; +}; + +bool VerifyCharacter(flatbuffers::Verifier &verifier, const void *obj, Character type); +bool VerifyCharacterVector(flatbuffers::Verifier &verifier, const flatbuffers::Vector<flatbuffers::Offset<void>> *values, const flatbuffers::Vector<uint8_t> *types); + +struct MuLan FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + enum { + VT_SWORD_ATTACK_DAMAGE = 4 + }; + int32_t sword_attack_damage() const { + return GetField<int32_t>(VT_SWORD_ATTACK_DAMAGE, 0); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField<int32_t>(verifier, VT_SWORD_ATTACK_DAMAGE) && + verifier.EndTable(); + } +}; + +struct MuLanBuilder { + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_sword_attack_damage(int32_t sword_attack_damage) { + fbb_.AddElement<int32_t>(MuLan::VT_SWORD_ATTACK_DAMAGE, sword_attack_damage, 0); + } + MuLanBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + MuLanBuilder &operator=(const MuLanBuilder &); + flatbuffers::Offset<MuLan> Finish() { + const auto end = fbb_.EndTable(start_, 1); + auto o = flatbuffers::Offset<MuLan>(end); + return o; + } +}; + +inline flatbuffers::Offset<MuLan> CreateMuLan( + flatbuffers::FlatBufferBuilder &_fbb, + int32_t sword_attack_damage = 0) { + MuLanBuilder 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<int32_t>(VT_HAIR_LENGTH, 0); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField<int32_t>(verifier, VT_HAIR_LENGTH) && + verifier.EndTable(); + } +}; + +struct RapunzelBuilder { + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_hair_length(int32_t hair_length) { + fbb_.AddElement<int32_t>(Rapunzel::VT_HAIR_LENGTH, hair_length, 0); + } + RapunzelBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + RapunzelBuilder &operator=(const RapunzelBuilder &); + flatbuffers::Offset<Rapunzel> Finish() { + const auto end = fbb_.EndTable(start_, 1); + auto o = flatbuffers::Offset<Rapunzel>(end); + return o; + } +}; + +inline flatbuffers::Offset<Rapunzel> 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<int32_t>(VT_BOOKS_READ, 0); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField<int32_t>(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<int32_t>(Belle::VT_BOOKS_READ, books_read, 0); + } + BelleBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + BelleBuilder &operator=(const BelleBuilder &); + flatbuffers::Offset<Belle> Finish() { + const auto end = fbb_.EndTable(start_, 1); + auto o = flatbuffers::Offset<Belle>(end); + return o; + } +}; + +inline flatbuffers::Offset<Belle> 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 { + enum { + VT_CHARACTERS_TYPE = 4, + VT_CHARACTERS = 6 + }; + const flatbuffers::Vector<uint8_t> *characters_type() const { + return GetPointer<const flatbuffers::Vector<uint8_t> *>(VT_CHARACTERS_TYPE); + } + const flatbuffers::Vector<flatbuffers::Offset<void>> *characters() const { + return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<void>> *>(VT_CHARACTERS); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField<flatbuffers::uoffset_t>(verifier, VT_CHARACTERS_TYPE) && + verifier.Verify(characters_type()) && + VerifyField<flatbuffers::uoffset_t>(verifier, VT_CHARACTERS) && + verifier.Verify(characters()) && + VerifyCharacterVector(verifier, characters(), characters_type()) && + verifier.EndTable(); + } +}; + +struct MovieBuilder { + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_characters_type(flatbuffers::Offset<flatbuffers::Vector<uint8_t>> characters_type) { + fbb_.AddOffset(Movie::VT_CHARACTERS_TYPE, characters_type); + } + void add_characters(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<void>>> characters) { + fbb_.AddOffset(Movie::VT_CHARACTERS, characters); + } + MovieBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + MovieBuilder &operator=(const MovieBuilder &); + flatbuffers::Offset<Movie> Finish() { + const auto end = fbb_.EndTable(start_, 2); + auto o = flatbuffers::Offset<Movie>(end); + return o; + } +}; + +inline flatbuffers::Offset<Movie> CreateMovie( + flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset<flatbuffers::Vector<uint8_t>> characters_type = 0, + flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<void>>> characters = 0) { + MovieBuilder builder_(_fbb); + builder_.add_characters(characters); + builder_.add_characters_type(characters_type); + return builder_.Finish(); +} + +inline flatbuffers::Offset<Movie> CreateMovieDirect( + flatbuffers::FlatBufferBuilder &_fbb, + const std::vector<uint8_t> *characters_type = nullptr, + const std::vector<flatbuffers::Offset<void>> *characters = nullptr) { + return CreateMovie( + _fbb, + characters_type ? _fbb.CreateVector<uint8_t>(*characters_type) : 0, + characters ? _fbb.CreateVector<flatbuffers::Offset<void>>(*characters) : 0); +} + +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<const MuLan *>(obj); + return verifier.VerifyTable(ptr); + } + case Character_Rapunzel: { + auto ptr = reinterpret_cast<const Rapunzel *>(obj); + return verifier.VerifyTable(ptr); + } + case Character_Belle: { + auto ptr = reinterpret_cast<const Belle *>(obj); + return verifier.VerifyTable(ptr); + } + default: return false; + } +} + +inline bool VerifyCharacterVector(flatbuffers::Verifier &verifier, const flatbuffers::Vector<flatbuffers::Offset<void>> *values, const flatbuffers::Vector<uint8_t> *types) { + if (values->size() != types->size()) return false; + for (flatbuffers::uoffset_t i = 0; i < values->size(); ++i) { + if (!VerifyCharacter( + verifier, values->Get(i), types->GetEnum<Character>(i))) { + return false; + } + } + return true; +} + +inline const Movie *GetMovie(const void *buf) { + return flatbuffers::GetRoot<Movie>(buf); +} + +inline const char *MovieIdentifier() { + return "MOVI"; +} + +inline bool MovieBufferHasIdentifier(const void *buf) { + return flatbuffers::BufferHasIdentifier( + buf, MovieIdentifier()); +} + +inline bool VerifyMovieBuffer( + flatbuffers::Verifier &verifier) { + return verifier.VerifyBuffer<Movie>(MovieIdentifier()); +} + +inline void FinishMovieBuffer( + flatbuffers::FlatBufferBuilder &fbb, + flatbuffers::Offset<Movie> root) { + fbb.Finish(root, MovieIdentifier()); +} + +#endif // FLATBUFFERS_GENERATED_UNIONVECTOR_H_