From 023fec627e1a6fdbefa2a0d0a767bd4ccd35d276 Mon Sep 17 00:00:00 2001 From: Martin Ankerl Date: Tue, 3 May 2016 17:20:14 +0200 Subject: [PATCH 01/13] Added helpers to access objects while creating the flatbuffer. GetObject and GetMutableObject are similar to GetRoot and GetMutableRoot, and can be useful when wanting to access data that has just been created. Unfortunately there is a danger in using these methods, as it is possible that the buffer reallocates which will invalidate the pointers. --- include/flatbuffers/flatbuffers.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/include/flatbuffers/flatbuffers.h b/include/flatbuffers/flatbuffers.h index c78583cad..07b7cadec 100644 --- a/include/flatbuffers/flatbuffers.h +++ b/include/flatbuffers/flatbuffers.h @@ -1151,6 +1151,17 @@ template const T *GetRoot(const void *buf) { return GetMutableRoot(const_cast(buf)); } +/// Helpers to get a typed pointer to objects that are currently beeing built. +/// @warning Creating new objects will lead to reallocations and invalidates the pointer! +template T *GetMutableObject(FlatBufferBuilder &fbb, Offset offset) { + return reinterpret_cast(fbb.GetCurrentBufferPointer() + + fbb.GetSize() - offset.o); +} + +template const T *GetObject(FlatBufferBuilder &fbb, Offset offset) { + return GetMutableObject(fbb, offset); +} + // Helper to see if the identifier in a buffer has the expected value. inline bool BufferHasIdentifier(const void *buf, const char *identifier) { return strncmp(reinterpret_cast(buf) + sizeof(uoffset_t), From 6704b19db65727d9afbc74e92733516693df9b18 Mon Sep 17 00:00:00 2001 From: Ben Gertzfield Date: Thu, 28 Apr 2016 12:27:38 -0700 Subject: [PATCH 02/13] Handle \u-escaped surrogate pairs correctly in IDL parser --- src/idl_parser.cpp | 44 ++++++++++++++++++++++++++++++++++++++++++-- tests/test.cpp | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 2 deletions(-) diff --git a/src/idl_parser.cpp b/src/idl_parser.cpp index a606781b5..2bf99eac0 100644 --- a/src/idl_parser.cpp +++ b/src/idl_parser.cpp @@ -236,12 +236,19 @@ CheckedError Parser::Next() { if(!isdigit(static_cast(*cursor_))) return NoError(); return Error("floating point constant can\'t start with \".\""); case '\"': - case '\'': + case '\'': { + int unicode_high_surrogate = -1; + while (*cursor_ != c) { if (*cursor_ < ' ' && *cursor_ >= 0) return Error("illegal character in string constant"); if (*cursor_ == '\\') { cursor_++; + if (unicode_high_surrogate != -1 && + *cursor_ != 'u') { + return Error( + "illegal Unicode sequence (unpaired high surrogate)"); + } switch (*cursor_) { case 'n': attribute_ += '\n'; cursor_++; break; case 't': attribute_ += '\t'; cursor_++; break; @@ -263,18 +270,51 @@ CheckedError Parser::Next() { cursor_++; int64_t val; ECHECK(ParseHexNum(4, &val)); - ToUTF8(static_cast(val), &attribute_); + if (val >= 0xD800 && val <= 0xDBFF) { + if (unicode_high_surrogate != -1) { + return Error( + "illegal Unicode sequence (multiple high surrogates)"); + } else { + unicode_high_surrogate = val; + } + } else if (val >= 0xDC00 && val <= 0xDFFF) { + if (unicode_high_surrogate == -1) { + return Error( + "illegal Unicode sequence (unpaired low surrogate)"); + } else { + int code_point = 0x10000 + + ((unicode_high_surrogate & 0x03FF) << 10) + + (val & 0x03FF); + ToUTF8(code_point, &attribute_); + unicode_high_surrogate = -1; + } + } else { + if (unicode_high_surrogate != -1) { + return Error( + "illegal Unicode sequence (unpaired high surrogate)"); + } + ToUTF8(static_cast(val), &attribute_); + } break; } default: return Error("unknown escape code in string constant"); } } else { // printable chars + UTF-8 bytes + if (unicode_high_surrogate != -1) { + return Error( + "illegal Unicode sequence (unpaired high surrogate)"); + } attribute_ += *cursor_++; } } + if (unicode_high_surrogate != -1) { + return Error( + "illegal Unicode sequence (unpaired high surrogate)"); + } cursor_++; token_ = kTokenStringConstant; return NoError(); + } case '/': if (*cursor_ == '/') { const char *start = ++cursor_; diff --git a/tests/test.cpp b/tests/test.cpp index e636f1f3c..df9cf08b9 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -859,6 +859,44 @@ void UnicodeTest() { "\\u5225\\u30B5\\u30A4\\u30C8\\x01\\x80\"}", true); } +void UnicodeSurrogatesTest() { + flatbuffers::Parser parser; + + TEST_EQ( + parser.Parse( + "table T { F:string (id: 0); }" + "root_type T;" + "{ F:\"\\uD83D\\uDCA9\"}"), true); + auto root = flatbuffers::GetRoot( + parser.builder_.GetBufferPointer()); + auto string = root->GetPointer( + flatbuffers::FieldIndexToOffset(0)); + TEST_EQ(strcmp(string->c_str(), "\xF0\x9F\x92\xA9"), 0); +} + +void UnicodeInvalidSurrogatesTest() { + TestError( + "table T { F:string; }" + "root_type T;" + "{ F:\"\\uD800\"}", "unpaired high surrogate"); + TestError( + "table T { F:string; }" + "root_type T;" + "{ F:\"\\uD800abcd\"}", "unpaired high surrogate"); + TestError( + "table T { F:string; }" + "root_type T;" + "{ F:\"\\uD800\\n\"}", "unpaired high surrogate"); + TestError( + "table T { F:string; }" + "root_type T;" + "{ F:\"\\uD800\\uD800\"}", "multiple high surrogates"); + TestError( + "table T { F:string; }" + "root_type T;" + "{ F:\"\\uDC00\"}", "unpaired low surrogate"); +} + void UnknownFieldsTest() { flatbuffers::IDLOptions opts; opts.skip_unexpected_fields_in_json = true; @@ -907,6 +945,8 @@ int main(int /*argc*/, const char * /*argv*/[]) { EnumStringsTest(); IntegerOutOfRangeTest(); UnicodeTest(); + UnicodeSurrogatesTest(); + UnicodeInvalidSurrogatesTest(); UnknownFieldsTest(); if (!testing_fails) { From b1e8be27a9544b525a94612f9edbe00e306c07c4 Mon Sep 17 00:00:00 2001 From: James Swift Date: Tue, 24 May 2016 17:16:03 +0200 Subject: [PATCH 03/13] MSVC doesn't allow alignment on function params. This prevents the copy and thus avoids this issue https://msdn.microsoft.com/en-us/library/373ak2y1.aspx --- include/flatbuffers/flatbuffers.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/flatbuffers/flatbuffers.h b/include/flatbuffers/flatbuffers.h index 0fa31250f..ef4a693cc 100644 --- a/include/flatbuffers/flatbuffers.h +++ b/include/flatbuffers/flatbuffers.h @@ -333,7 +333,7 @@ public: // Change elements if you have a non-const pointer to this object. // Scalars only. See reflection.h, and the documentation. - void Mutate(uoffset_t i, T val) { + void Mutate(uoffset_t i, const T& val) { assert(i < size()); WriteScalar(data() + i, val); } From 4a8801da34b0edd03277b26b6fd280658c585ca6 Mon Sep 17 00:00:00 2001 From: Lakedaemon Date: Wed, 25 May 2016 15:15:56 +0200 Subject: [PATCH 04/13] shared method that exits early if everything is generated --- include/flatbuffers/code_generators.h | 12 +++++++++++ src/idl_gen_cpp.cpp | 16 +------------- src/idl_gen_js.cpp | 30 +++++++++++++-------------- 3 files changed, 27 insertions(+), 31 deletions(-) diff --git a/include/flatbuffers/code_generators.h b/include/flatbuffers/code_generators.h index 6b27ea780..5770932cc 100644 --- a/include/flatbuffers/code_generators.h +++ b/include/flatbuffers/code_generators.h @@ -29,6 +29,18 @@ class BaseGenerator { protected: virtual ~BaseGenerator(){}; + bool IsEverythingGenerated() { + for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end(); + ++it) { + if (!(*it)->generated) return false; + } + for (auto it = parser_.structs_.vec.begin(); + it != parser_.structs_.vec.end(); ++it) { + if (!(*it)->generated) return false; + } + return true; + } + const Parser &parser_; const std::string &path_; const std::string &file_name_; diff --git a/src/idl_gen_cpp.cpp b/src/idl_gen_cpp.cpp index 0e5d823f3..33024df1c 100644 --- a/src/idl_gen_cpp.cpp +++ b/src/idl_gen_cpp.cpp @@ -724,21 +724,7 @@ class CppGenerator : public BaseGenerator { // structs, // and tables) and output them to a single file. bool generate() { - // Check if we have any code to generate at all, to avoid an empty header. - for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end(); - ++it) { - if (!(*it)->generated) goto generate_code; - } - for (auto it = parser_.structs_.vec.begin(); it != parser_.structs_.vec.end(); - ++it) { - if (!(*it)->generated) goto generate_code; - } - // No code to generate, exit: - return true; - - generate_code: - - using namespace cpp; + if (IsEverythingGenerated()) return true; std::string code; code = diff --git a/src/idl_gen_js.cpp b/src/idl_gen_js.cpp index de81f2764..0265394ed 100644 --- a/src/idl_gen_js.cpp +++ b/src/idl_gen_js.cpp @@ -678,31 +678,29 @@ class JsGenerator : public BaseGenerator { // Iterate through all definitions we haven't generate code for (enums, // structs, and tables) and output them to a single file. bool generate() { + if (IsEverythingGenerated()) return true; + std::string enum_code, struct_code, exports_code, code; generateEnums(&enum_code, &exports_code); generateStructs(&struct_code, &exports_code); - // Only output file-level code if there were any declarations. - if (enum_code.length() || struct_code.length()) { - code += - "// automatically generated by the FlatBuffers compiler, do not " - "modify\n\n"; + code += + "// automatically generated by the FlatBuffers compiler, do not " + "modify\n\n"; - // Generate code for all the namespace declarations. - GenNamespaces(parser_, &code, &exports_code); + // Generate code for all the namespace declarations. + GenNamespaces(parser_, &code, &exports_code); - // Output the main declaration code from above. - code += enum_code; - code += struct_code; + // Output the main declaration code from above. + code += enum_code; + code += struct_code; - if (!exports_code.empty() && !parser_.opts.skip_js_exports) { - code += "// Exports for Node.js and RequireJS\n"; - code += exports_code; - } + if (!exports_code.empty() && !parser_.opts.skip_js_exports) { + code += "// Exports for Node.js and RequireJS\n"; + code += exports_code; } - return !code.length() || - SaveFile(GeneratedFileName(path_, file_name_).c_str(), code, false); + return SaveFile(GeneratedFileName(path_, file_name_).c_str(), code, false); } private: From cd1493b0829b48407887844921ef0e040c0f485a Mon Sep 17 00:00:00 2001 From: lakedaemon Date: Thu, 26 May 2016 15:26:58 +0200 Subject: [PATCH 05/13] sharing the Flatbuffers warning --- include/flatbuffers/code_generators.h | 5 + samples/monster_generated.h | 19 +++- src/idl_gen_cpp.cpp | 4 +- src/idl_gen_general.cpp | 79 +++++++-------- src/idl_gen_go.cpp | 82 ++++++++-------- src/idl_gen_js.cpp | 4 +- src/idl_gen_php.cpp | 98 +++++++++---------- src/idl_gen_python.cpp | 86 ++++++++-------- tests/MyGame/Example/Any.cs | 2 +- tests/MyGame/Example/Any.go | 2 +- tests/MyGame/Example/Any.java | 2 +- tests/MyGame/Example/Any.php | 2 +- tests/MyGame/Example/Any.py | 2 +- tests/MyGame/Example/Color.cs | 2 +- tests/MyGame/Example/Color.go | 2 +- tests/MyGame/Example/Color.java | 2 +- tests/MyGame/Example/Color.php | 2 +- tests/MyGame/Example/Color.py | 2 +- tests/MyGame/Example/Monster.cs | 2 +- tests/MyGame/Example/Monster.go | 2 +- tests/MyGame/Example/Monster.java | 2 +- tests/MyGame/Example/Monster.php | 2 +- tests/MyGame/Example/Monster.py | 2 +- tests/MyGame/Example/Stat.cs | 2 +- tests/MyGame/Example/Stat.go | 2 +- tests/MyGame/Example/Stat.java | 2 +- tests/MyGame/Example/Stat.php | 2 +- tests/MyGame/Example/Stat.py | 2 +- tests/MyGame/Example/Test.cs | 2 +- tests/MyGame/Example/Test.go | 2 +- tests/MyGame/Example/Test.java | 2 +- tests/MyGame/Example/Test.php | 2 +- tests/MyGame/Example/Test.py | 2 +- .../MyGame/Example/TestSimpleTableWithEnum.cs | 2 +- .../MyGame/Example/TestSimpleTableWithEnum.go | 2 +- .../Example/TestSimpleTableWithEnum.java | 2 +- .../Example/TestSimpleTableWithEnum.php | 2 +- .../MyGame/Example/TestSimpleTableWithEnum.py | 2 +- tests/MyGame/Example/Vec3.cs | 2 +- tests/MyGame/Example/Vec3.go | 2 +- tests/MyGame/Example/Vec3.java | 2 +- tests/MyGame/Example/Vec3.php | 2 +- tests/MyGame/Example/Vec3.py | 2 +- .../NamespaceA/NamespaceB/EnumInNestedNS.cs | 2 +- .../NamespaceA/NamespaceB/EnumInNestedNS.go | 2 +- .../NamespaceA/NamespaceB/EnumInNestedNS.java | 2 +- .../NamespaceA/NamespaceB/EnumInNestedNS.php | 2 +- .../NamespaceA/NamespaceB/EnumInNestedNS.py | 2 +- .../NamespaceA/NamespaceB/StructInNestedNS.cs | 2 +- .../NamespaceA/NamespaceB/StructInNestedNS.go | 2 +- .../NamespaceB/StructInNestedNS.java | 2 +- .../NamespaceB/StructInNestedNS.php | 2 +- .../NamespaceA/NamespaceB/StructInNestedNS.py | 2 +- .../NamespaceA/NamespaceB/TableInNestedNS.cs | 2 +- .../NamespaceA/NamespaceB/TableInNestedNS.go | 2 +- .../NamespaceB/TableInNestedNS.java | 2 +- .../NamespaceA/NamespaceB/TableInNestedNS.php | 2 +- .../NamespaceA/NamespaceB/TableInNestedNS.py | 2 +- .../NamespaceA/SecondTableInA.cs | 2 +- .../NamespaceA/SecondTableInA.go | 2 +- .../NamespaceA/SecondTableInA.java | 2 +- .../NamespaceA/SecondTableInA.php | 2 +- .../NamespaceA/SecondTableInA.py | 2 +- tests/namespace_test/NamespaceA/TableInC.cs | 2 +- tests/namespace_test/NamespaceA/TableInC.go | 2 +- tests/namespace_test/NamespaceA/TableInC.java | 2 +- tests/namespace_test/NamespaceA/TableInC.php | 2 +- tests/namespace_test/NamespaceA/TableInC.py | 2 +- .../NamespaceA/TableInFirstNS.cs | 2 +- .../NamespaceA/TableInFirstNS.go | 2 +- .../NamespaceA/TableInFirstNS.java | 2 +- .../NamespaceA/TableInFirstNS.php | 2 +- .../NamespaceA/TableInFirstNS.py | 2 +- 73 files changed, 255 insertions(+), 252 deletions(-) diff --git a/include/flatbuffers/code_generators.h b/include/flatbuffers/code_generators.h index 5770932cc..6c902a454 100644 --- a/include/flatbuffers/code_generators.h +++ b/include/flatbuffers/code_generators.h @@ -29,6 +29,11 @@ class BaseGenerator { protected: virtual ~BaseGenerator(){}; + const char * FlatBuffersGeneratedWarning() { + return "automatically generated by the FlatBuffers compiler," + " do not modify\n\n"; + } + bool IsEverythingGenerated() { for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end(); ++it) { diff --git a/samples/monster_generated.h b/samples/monster_generated.h index cf45bbb91..1a16126a5 100644 --- a/samples/monster_generated.h +++ b/samples/monster_generated.h @@ -5,12 +5,13 @@ #include "flatbuffers/flatbuffers.h" - namespace MyGame { namespace Sample { struct Vec3; + struct Monster; + struct Weapon; enum Color { @@ -55,8 +56,11 @@ MANUALLY_ALIGNED_STRUCT(4) Vec3 FLATBUFFERS_FINAL_CLASS { : x_(flatbuffers::EndianScalar(_x)), y_(flatbuffers::EndianScalar(_y)), z_(flatbuffers::EndianScalar(_z)) { } float x() const { return flatbuffers::EndianScalar(x_); } + void mutate_x(float _x) { flatbuffers::WriteScalar(&x_, _x); } float y() const { return flatbuffers::EndianScalar(y_); } + void mutate_y(float _y) { flatbuffers::WriteScalar(&y_, _y); } float z() const { return flatbuffers::EndianScalar(z_); } + void mutate_z(float _z) { flatbuffers::WriteScalar(&z_, _z); } }; STRUCT_END(Vec3, 12); @@ -73,14 +77,23 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { VT_EQUIPPED = 22 }; const Vec3 *pos() const { return GetStruct(VT_POS); } + Vec3 *mutable_pos() { return GetStruct(VT_POS); } int16_t mana() const { return GetField(VT_MANA, 150); } + bool mutate_mana(int16_t _mana) { return SetField(VT_MANA, _mana); } int16_t hp() const { return GetField(VT_HP, 100); } + bool mutate_hp(int16_t _hp) { return SetField(VT_HP, _hp); } const flatbuffers::String *name() const { return GetPointer(VT_NAME); } + flatbuffers::String *mutable_name() { return GetPointer(VT_NAME); } const flatbuffers::Vector *inventory() const { return GetPointer *>(VT_INVENTORY); } + flatbuffers::Vector *mutable_inventory() { return GetPointer *>(VT_INVENTORY); } Color color() const { return static_cast(GetField(VT_COLOR, 2)); } + bool mutate_color(Color _color) { return SetField(VT_COLOR, static_cast(_color)); } const flatbuffers::Vector> *weapons() const { return GetPointer> *>(VT_WEAPONS); } + flatbuffers::Vector> *mutable_weapons() { return GetPointer> *>(VT_WEAPONS); } Equipment equipped_type() const { return static_cast(GetField(VT_EQUIPPED_TYPE, 0)); } + bool mutate_equipped_type(Equipment _equipped_type) { return SetField(VT_EQUIPPED_TYPE, static_cast(_equipped_type)); } const void *equipped() const { return GetPointer(VT_EQUIPPED); } + void *mutable_equipped() { return GetPointer(VT_EQUIPPED); } bool Verify(flatbuffers::Verifier &verifier) const { return VerifyTableStart(verifier) && VerifyField(verifier, VT_POS) && @@ -150,7 +163,9 @@ struct Weapon FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { VT_DAMAGE = 6 }; const flatbuffers::String *name() const { return GetPointer(VT_NAME); } + flatbuffers::String *mutable_name() { return GetPointer(VT_NAME); } int16_t damage() const { return GetField(VT_DAMAGE, 0); } + bool mutate_damage(int16_t _damage) { return SetField(VT_DAMAGE, _damage); } bool Verify(flatbuffers::Verifier &verifier) const { return VerifyTableStart(verifier) && VerifyField(verifier, VT_NAME) && @@ -192,6 +207,8 @@ inline bool VerifyEquipment(flatbuffers::Verifier &verifier, const void *union_o inline const MyGame::Sample::Monster *GetMonster(const void *buf) { return flatbuffers::GetRoot(buf); } +inline Monster *GetMutableMonster(void *buf) { return flatbuffers::GetMutableRoot(buf); } + inline bool VerifyMonsterBuffer(flatbuffers::Verifier &verifier) { return verifier.VerifyBuffer(); } inline void FinishMonsterBuffer(flatbuffers::FlatBufferBuilder &fbb, flatbuffers::Offset root) { fbb.Finish(root); } diff --git a/src/idl_gen_cpp.cpp b/src/idl_gen_cpp.cpp index 051cd99de..0bec8ca51 100644 --- a/src/idl_gen_cpp.cpp +++ b/src/idl_gen_cpp.cpp @@ -733,9 +733,7 @@ class CppGenerator : public BaseGenerator { if (IsEverythingGenerated()) return true; std::string code; - code = - "// automatically generated by the FlatBuffers compiler," - " do not modify\n\n"; + code = code + "// " + FlatBuffersGeneratedWarning(); // Generate include guard. std::string include_guard_ident = file_name_; diff --git a/src/idl_gen_general.cpp b/src/idl_gen_general.cpp index 4a4e54dc4..71ea19ed1 100644 --- a/src/idl_gen_general.cpp +++ b/src/idl_gen_general.cpp @@ -1115,40 +1115,6 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser, code += "};\n\n"; } -// Save out the generated code for a single class while adding -// declaration boilerplate. -static bool SaveClass(const LanguageParameters &lang, const Parser &parser, - const std::string &defname, const std::string &classcode, - const std::string &path, bool needs_includes, bool onefile) { - if (!classcode.length()) return true; - - std::string namespace_general; - std::string namespace_dir = path; // Either empty or ends in separator. - auto &namespaces = parser.namespaces_.back()->components; - for (auto it = namespaces.begin(); it != namespaces.end(); ++it) { - if (namespace_general.length()) { - namespace_general += "."; - } - namespace_general += *it; - if (!onefile) { - namespace_dir += *it + kPathSeparator; - } - - } - EnsureDirExists(namespace_dir); - - std::string code = "// automatically generated, do not modify\n\n"; - if (!namespace_general.empty()) { - code += lang.namespace_ident + namespace_general + lang.namespace_begin; - code += "\n\n"; - } - if (needs_includes) code += lang.includes; - code += classcode; - if (!namespace_general.empty()) code += lang.namespace_end; - auto filename = namespace_dir + defname + lang.file_extension; - return SaveFile(filename.c_str(), code, false); -} - namespace general { class GeneralGenerator : public BaseGenerator { public: @@ -1167,9 +1133,7 @@ class GeneralGenerator : public BaseGenerator { if (parser_.opts.one_file) { one_file_code += enumcode; } else { - if (!SaveClass(lang, parser_, (**it).name, enumcode, path_, false, - false)) - return false; + if (!SaveType(lang, (**it).name, enumcode, false, false)) return false; } } @@ -1180,18 +1144,49 @@ class GeneralGenerator : public BaseGenerator { if (parser_.opts.one_file) { one_file_code += declcode; } else { - if (!SaveClass(lang, parser_, (**it).name, declcode, path_, true, - false)) - return false; + if (!SaveType(lang, (**it).name, declcode, true, false)) return false; } } if (parser_.opts.one_file) { - return SaveClass(lang, parser_, file_name_, one_file_code, path_, true, - true); + return SaveType(lang, file_name_, one_file_code, true, true); } return true; } + + // Save out the generated code for a single class while adding + // declaration boilerplate. + bool SaveType(const LanguageParameters &lang, const std::string &defname, + const std::string &classcode, bool needs_includes, + bool onefile) { + if (!classcode.length()) return true; + + std::string namespace_general; + std::string namespace_dir = path_; // Either empty or ends in separator. + auto &namespaces = parser_.namespaces_.back()->components; + for (auto it = namespaces.begin(); it != namespaces.end(); ++it) { + if (namespace_general.length()) { + namespace_general += "."; + } + namespace_general += *it; + if (!onefile) { + namespace_dir += *it + kPathSeparator; + } + } + EnsureDirExists(namespace_dir); + + std::string code; + code = code + "// " + FlatBuffersGeneratedWarning(); + if (!namespace_general.empty()) { + code += lang.namespace_ident + namespace_general + lang.namespace_begin; + code += "\n\n"; + } + if (needs_includes) code += lang.includes; + code += classcode; + if (!namespace_general.empty()) code += lang.namespace_end; + auto filename = namespace_dir + defname + lang.file_extension; + return SaveFile(filename.c_str(), code, false); + } }; } // namespace general diff --git a/src/idl_gen_go.cpp b/src/idl_gen_go.cpp index bce8f95bc..be437c7b0 100644 --- a/src/idl_gen_go.cpp +++ b/src/idl_gen_go.cpp @@ -53,20 +53,6 @@ std::string OffsetPrefix(const FieldDef &field) { "))\n\tif o != 0 {\n"; } -// Begin by declaring namespace and imports. -static void BeginFile(const std::string name_space_name, - const bool needs_imports, - std::string *code_ptr) { - std::string &code = *code_ptr; - code += "// automatically generated, do not modify\n\n"; - code += "package " + name_space_name + "\n\n"; - if (needs_imports) { - code += "import (\n"; - code += "\tflatbuffers \"github.com/google/flatbuffers/go\"\n"; - code += ")\n"; - } -} - // Begin a class declaration. static void BeginClass(const StructDef &struct_def, std::string *code_ptr) { std::string &code = *code_ptr; @@ -589,32 +575,6 @@ static std::string GenMethod(const FieldDef &field) { : (IsStruct(field.value.type) ? "Struct" : "UOffsetT"); } - -// Save out the generated code for a Go Table type. -static bool SaveType(const Parser &parser, const Definition &def, - const std::string &classcode, const std::string &path, - bool needs_imports) { - if (!classcode.length()) return true; - - std::string namespace_name; - std::string namespace_dir = path; // Either empty or ends in separator. - auto &namespaces = parser.namespaces_.back()->components; - for (auto it = namespaces.begin(); it != namespaces.end(); ++it) { - if (namespace_name.length()) { - namespace_name += "."; - } - namespace_name = *it; - namespace_dir += *it + kPathSeparator; - } - EnsureDirExists(namespace_dir); - - std::string code = ""; - BeginFile(namespace_name, needs_imports, &code); - code += classcode; - std::string filename = namespace_dir + def.name + ".go"; - return SaveFile(filename.c_str(), code, false); -} - static std::string GenTypeBasic(const Type &type) { static const char *ctypename[] = { #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \ @@ -671,18 +631,56 @@ class GoGenerator : public BaseGenerator { ++it) { std::string enumcode; go::GenEnum(**it, &enumcode); - if (!go::SaveType(parser_, **it, enumcode, path_, false)) return false; + if (!SaveType(**it, enumcode, false)) return false; } for (auto it = parser_.structs_.vec.begin(); it != parser_.structs_.vec.end(); ++it) { std::string declcode; go::GenStruct(**it, &declcode, parser_.root_struct_def_); - if (!go::SaveType(parser_, **it, declcode, path_, true)) return false; + if (!SaveType(**it, declcode, true)) return false; } return true; } + + private: + // Begin by declaring namespace and imports. + void BeginFile(const std::string name_space_name, const bool needs_imports, + std::string *code_ptr) { + std::string &code = *code_ptr; + code = code + "// " + FlatBuffersGeneratedWarning(); + code += "package " + name_space_name + "\n\n"; + if (needs_imports) { + code += "import (\n"; + code += "\tflatbuffers \"github.com/google/flatbuffers/go\"\n"; + code += ")\n"; + } + } + + // Save out the generated code for a Go Table type. + bool SaveType(const Definition &def, const std::string &classcode, + bool needs_imports) { + if (!classcode.length()) return true; + + std::string namespace_name; + std::string namespace_dir = path_; // Either empty or ends in separator. + auto &namespaces = parser_.namespaces_.back()->components; + for (auto it = namespaces.begin(); it != namespaces.end(); ++it) { + if (namespace_name.length()) { + namespace_name += "."; + } + namespace_name = *it; + namespace_dir += *it + kPathSeparator; + } + EnsureDirExists(namespace_dir); + + std::string code = ""; + BeginFile(namespace_name, needs_imports, &code); + code += classcode; + std::string filename = namespace_dir + def.name + ".go"; + return SaveFile(filename.c_str(), code, false); + } }; } // namespace go diff --git a/src/idl_gen_js.cpp b/src/idl_gen_js.cpp index 0265394ed..d724b80f4 100644 --- a/src/idl_gen_js.cpp +++ b/src/idl_gen_js.cpp @@ -684,9 +684,7 @@ class JsGenerator : public BaseGenerator { generateEnums(&enum_code, &exports_code); generateStructs(&struct_code, &exports_code); - code += - "// automatically generated by the FlatBuffers compiler, do not " - "modify\n\n"; + code = code + "// " + FlatBuffersGeneratedWarning(); // Generate code for all the namespace declarations. GenNamespaces(parser_, &code, &exports_code); diff --git a/src/idl_gen_php.cpp b/src/idl_gen_php.cpp index b43ea6702..5fb412434 100644 --- a/src/idl_gen_php.cpp +++ b/src/idl_gen_php.cpp @@ -54,24 +54,6 @@ namespace php { // Hardcode spaces per indentation. const std::string Indent = " "; - // Begin by declaring namespace and imports. - static void BeginFile(const std::string name_space_name, - const bool needs_imports, - std::string *code_ptr) { - std::string &code = *code_ptr; - code += "components; - for (auto it = namespaces.begin(); it != namespaces.end(); ++it) { - if (namespace_name.length()) { - namespace_name += "\\"; - namespace_dir += kPathSeparator; - } - namespace_name += *it; - namespace_dir += *it; - EnsureDirExists(namespace_dir.c_str()); - } - - std::string code = ""; - BeginFile(namespace_name, needs_imports, &code); - code += classcode; - - std::string filename = namespace_dir + kPathSeparator + def.name + ".php"; - return SaveFile(filename.c_str(), code, false); - } - static std::string GenTypeBasic(const Type &type) { static const char *ctypename[] = { #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \ @@ -993,8 +946,7 @@ namespace php { auto &enum_def = **it; std::string enumcode; GenEnum(enum_def, &enumcode); - if (!SaveType(parser_, enum_def, enumcode, path_, false)) - return false; + if (!SaveType(enum_def, enumcode, false)) return false; } return true; } @@ -1005,11 +957,55 @@ namespace php { auto &struct_def = **it; std::string declcode; GenStruct(parser_, struct_def, &declcode); - if (!SaveType(parser_, struct_def, declcode, path_, true)) - return false; + if (!SaveType(struct_def, declcode, true)) return false; } return true; } + + // Begin by declaring namespace and imports. + void BeginFile(const std::string name_space_name, + const bool needs_imports, std::string *code_ptr) { + std::string &code = *code_ptr; + code += "components; + for (auto it = namespaces.begin(); it != namespaces.end(); ++it) { + if (namespace_name.length()) { + namespace_name += "\\"; + namespace_dir += kPathSeparator; + } + namespace_name += *it; + namespace_dir += *it; + EnsureDirExists(namespace_dir.c_str()); + } + + std::string code = ""; + BeginFile(namespace_name, needs_imports, &code); + code += classcode; + + std::string filename = + namespace_dir + kPathSeparator + def.name + ".php"; + return SaveFile(filename.c_str(), code, false); + } }; } // namespace php diff --git a/src/idl_gen_python.cpp b/src/idl_gen_python.cpp index ee6d16874..291aada0e 100644 --- a/src/idl_gen_python.cpp +++ b/src/idl_gen_python.cpp @@ -49,18 +49,6 @@ std::string OffsetPrefix(const FieldDef &field) { "))\n" + Indent + Indent + "if o != 0:\n"; } -// Begin by declaring namespace and imports. -static void BeginFile(const std::string name_space_name, - const bool needs_imports, - std::string *code_ptr) { - std::string &code = *code_ptr; - code += "# automatically generated, do not modify\n\n"; - code += "# namespace: " + name_space_name + "\n\n"; - if (needs_imports) { - code += "import flatbuffers\n\n"; - } -} - // Begin a class declaration. static void BeginClass(const StructDef &struct_def, std::string *code_ptr) { std::string &code = *code_ptr; @@ -558,37 +546,6 @@ static std::string GenMethod(const FieldDef &field) { : (IsStruct(field.value.type) ? "Struct" : "UOffsetTRelative"); } - -// Save out the generated code for a Python Table type. -static bool SaveType(const Parser &parser, const Definition &def, - const std::string &classcode, const std::string &path, - bool needs_imports) { - if (!classcode.length()) return true; - - std::string namespace_name; - std::string namespace_dir = path; - auto &namespaces = parser.namespaces_.back()->components; - for (auto it = namespaces.begin(); it != namespaces.end(); ++it) { - if (namespace_name.length()) { - namespace_name += "."; - namespace_dir += kPathSeparator; - } - namespace_name = *it; - namespace_dir += *it; - EnsureDirExists(namespace_dir.c_str()); - - std::string init_py_filename = namespace_dir + "/__init__.py"; - SaveFile(init_py_filename.c_str(), "", false); - } - - - std::string code = ""; - BeginFile(namespace_name, needs_imports, &code); - code += classcode; - std::string filename = namespace_dir + kPathSeparator + def.name + ".py"; - return SaveFile(filename.c_str(), code, false); -} - static std::string GenTypeBasic(const Type &type) { static const char *ctypename[] = { #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \ @@ -653,7 +610,7 @@ class PythonGenerator : public BaseGenerator { auto &enum_def = **it; std::string enumcode; GenEnum(enum_def, &enumcode); - if (!SaveType(parser_, enum_def, enumcode, path_, false)) return false; + if (!SaveType(enum_def, enumcode, false)) return false; } return true; } @@ -664,10 +621,49 @@ class PythonGenerator : public BaseGenerator { auto &struct_def = **it; std::string declcode; GenStruct(struct_def, &declcode, parser_.root_struct_def_); - if (!SaveType(parser_, struct_def, declcode, path_, true)) return false; + if (!SaveType(struct_def, declcode, true)) return false; } return true; } + + // Begin by declaring namespace and imports. + void BeginFile(const std::string name_space_name, const bool needs_imports, + std::string *code_ptr) { + std::string &code = *code_ptr; + code = code + "# " + FlatBuffersGeneratedWarning(); + code += "# namespace: " + name_space_name + "\n\n"; + if (needs_imports) { + code += "import flatbuffers\n\n"; + } + } + + // Save out the generated code for a Python Table type. + bool SaveType(const Definition &def, const std::string &classcode, + bool needs_imports) { + if (!classcode.length()) return true; + + std::string namespace_name; + std::string namespace_dir = path_; + auto &namespaces = parser_.namespaces_.back()->components; + for (auto it = namespaces.begin(); it != namespaces.end(); ++it) { + if (namespace_name.length()) { + namespace_name += "."; + namespace_dir += kPathSeparator; + } + namespace_name = *it; + namespace_dir += *it; + EnsureDirExists(namespace_dir.c_str()); + + std::string init_py_filename = namespace_dir + "/__init__.py"; + SaveFile(init_py_filename.c_str(), "", false); + } + + std::string code = ""; + BeginFile(namespace_name, needs_imports, &code); + code += classcode; + std::string filename = namespace_dir + kPathSeparator + def.name + ".py"; + return SaveFile(filename.c_str(), code, false); + } }; } // namespace python diff --git a/tests/MyGame/Example/Any.cs b/tests/MyGame/Example/Any.cs index a05a91851..1f018ad89 100644 --- a/tests/MyGame/Example/Any.cs +++ b/tests/MyGame/Example/Any.cs @@ -1,4 +1,4 @@ -// automatically generated, do not modify +// automatically generated by the FlatBuffers compiler, do not modify namespace MyGame.Example { diff --git a/tests/MyGame/Example/Any.go b/tests/MyGame/Example/Any.go index a23de4cbc..0322364c6 100644 --- a/tests/MyGame/Example/Any.go +++ b/tests/MyGame/Example/Any.go @@ -1,4 +1,4 @@ -// automatically generated, do not modify +// automatically generated by the FlatBuffers compiler, do not modify package Example diff --git a/tests/MyGame/Example/Any.java b/tests/MyGame/Example/Any.java index cdc3ec567..27dc1bcb9 100644 --- a/tests/MyGame/Example/Any.java +++ b/tests/MyGame/Example/Any.java @@ -1,4 +1,4 @@ -// automatically generated, do not modify +// automatically generated by the FlatBuffers compiler, do not modify package MyGame.Example; diff --git a/tests/MyGame/Example/Any.php b/tests/MyGame/Example/Any.php index d35bfd639..f04f4ad3f 100644 --- a/tests/MyGame/Example/Any.php +++ b/tests/MyGame/Example/Any.php @@ -1,5 +1,5 @@ Date: Sat, 28 May 2016 08:15:43 +0200 Subject: [PATCH 06/13] sharing namespace_dir and the namespace string methods --- include/flatbuffers/code_generators.h | 46 +++++++++++++--- src/idl_gen_general.cpp | 76 ++++++++------------------- src/idl_gen_go.cpp | 16 +----- src/idl_gen_php.cpp | 18 +------ src/idl_gen_python.cpp | 13 ++--- 5 files changed, 67 insertions(+), 102 deletions(-) diff --git a/include/flatbuffers/code_generators.h b/include/flatbuffers/code_generators.h index 6c902a454..a832334ec 100644 --- a/include/flatbuffers/code_generators.h +++ b/include/flatbuffers/code_generators.h @@ -21,19 +21,35 @@ namespace flatbuffers { class BaseGenerator { public: - BaseGenerator(const Parser &parser, const std::string &path, - const std::string &file_name) - : parser_(parser), path_(path), file_name_(file_name){}; virtual bool generate() = 0; + static const std::string NamespaceDir(const Parser &parser, + const std::string &path) { + EnsureDirExists(path.c_str()); + if (parser.opts.one_file) return path; + std::string namespace_dir = path; // Either empty or ends in separator. + auto &namespaces = parser.namespaces_.back()->components; + for (auto it = namespaces.begin(); it != namespaces.end(); ++it) { + namespace_dir += *it + kPathSeparator; + EnsureDirExists(namespace_dir.c_str()); + } + return namespace_dir; + } + protected: + BaseGenerator(const Parser &parser, const std::string &path, + const std::string &file_name) + : parser_(parser), + path_(path), + file_name_(file_name), + namespace_dir_(BaseGenerator::NamespaceDir(parser, path)){}; virtual ~BaseGenerator(){}; - const char * FlatBuffersGeneratedWarning() { + const char *FlatBuffersGeneratedWarning() { return "automatically generated by the FlatBuffers compiler," - " do not modify\n\n"; - } - + " do not modify\n\n"; + } + bool IsEverythingGenerated() { for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end(); ++it) { @@ -46,9 +62,25 @@ class BaseGenerator { return true; } + std::string FullNamespace(const char *separator) { + std::string namespace_name; + auto &namespaces = parser_.namespaces_.back()->components; + for (auto it = namespaces.begin(); it != namespaces.end(); ++it) { + if (namespace_name.length()) namespace_name += separator; + namespace_name += *it; + } + return namespace_name; + } + + const std::string LastNamespacePart() { + auto &namespaces = parser_.namespaces_.back()->components; + if (namespaces.size()) return *(namespaces.end() - 1); else return std::string(""); + } + const Parser &parser_; const std::string &path_; const std::string &file_name_; + const std::string namespace_dir_; }; } // namespace flatbuffers diff --git a/src/idl_gen_general.cpp b/src/idl_gen_general.cpp index 71ea19ed1..a0b837a20 100644 --- a/src/idl_gen_general.cpp +++ b/src/idl_gen_general.cpp @@ -1133,7 +1133,7 @@ class GeneralGenerator : public BaseGenerator { if (parser_.opts.one_file) { one_file_code += enumcode; } else { - if (!SaveType(lang, (**it).name, enumcode, false, false)) return false; + if (!SaveType(lang, (**it).name, enumcode, false)) return false; } } @@ -1144,12 +1144,12 @@ class GeneralGenerator : public BaseGenerator { if (parser_.opts.one_file) { one_file_code += declcode; } else { - if (!SaveType(lang, (**it).name, declcode, true, false)) return false; + if (!SaveType(lang, (**it).name, declcode, true)) return false; } } if (parser_.opts.one_file) { - return SaveType(lang, file_name_, one_file_code, true, true); + return SaveType(lang, file_name_, one_file_code, true); } return true; } @@ -1157,34 +1157,20 @@ class GeneralGenerator : public BaseGenerator { // Save out the generated code for a single class while adding // declaration boilerplate. bool SaveType(const LanguageParameters &lang, const std::string &defname, - const std::string &classcode, bool needs_includes, - bool onefile) { + const std::string &classcode, bool needs_includes) { if (!classcode.length()) return true; - std::string namespace_general; - std::string namespace_dir = path_; // Either empty or ends in separator. - auto &namespaces = parser_.namespaces_.back()->components; - for (auto it = namespaces.begin(); it != namespaces.end(); ++it) { - if (namespace_general.length()) { - namespace_general += "."; - } - namespace_general += *it; - if (!onefile) { - namespace_dir += *it + kPathSeparator; - } - } - EnsureDirExists(namespace_dir); - std::string code; code = code + "// " + FlatBuffersGeneratedWarning(); - if (!namespace_general.empty()) { - code += lang.namespace_ident + namespace_general + lang.namespace_begin; + std::string namespace_name = FullNamespace("."); + if (!namespace_name.empty()) { + code += lang.namespace_ident + namespace_name + lang.namespace_begin; code += "\n\n"; } if (needs_includes) code += lang.includes; code += classcode; - if (!namespace_general.empty()) code += lang.namespace_end; - auto filename = namespace_dir + defname + lang.file_extension; + if (!namespace_name.empty()) code += lang.namespace_end; + auto filename = namespace_dir_ + defname + lang.file_extension; return SaveFile(filename.c_str(), code, false); } }; @@ -1196,50 +1182,30 @@ bool GenerateGeneral(const Parser &parser, const std::string &path, return generator.generate(); } -static std::string ClassFileName(const LanguageParameters &lang, - const Parser &parser, const Definition &def, - const std::string &path) { - std::string namespace_general; - std::string namespace_dir = path; - auto &namespaces = parser.namespaces_.back()->components; - for (auto it = namespaces.begin(); it != namespaces.end(); ++it) { - if (namespace_general.length()) { - namespace_general += "."; - namespace_dir += kPathSeparator; - } - namespace_general += *it; - namespace_dir += *it; - } - - return namespace_dir + kPathSeparator + def.name + lang.file_extension; -} - -std::string GeneralMakeRule(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]; std::string make_rule; + std::string directory = + BaseGenerator::NamespaceDir(parser, path) + kPathSeparator; - for (auto it = parser.enums_.vec.begin(); - it != parser.enums_.vec.end(); ++it) { - if (make_rule != "") - make_rule += " "; - make_rule += ClassFileName(lang, parser, **it, path); + for (auto it = parser.enums_.vec.begin(); it != parser.enums_.vec.end(); + ++it) { + if (make_rule != "") make_rule += " "; + make_rule += directory + (**it).name + lang.file_extension; } - for (auto it = parser.structs_.vec.begin(); - it != parser.structs_.vec.end(); ++it) { - if (make_rule != "") - make_rule += " "; - make_rule += ClassFileName(lang, parser, **it, path); + for (auto it = parser.structs_.vec.begin(); it != parser.structs_.vec.end(); + ++it) { + if (make_rule != "") make_rule += " "; + make_rule += directory + (**it).name + lang.file_extension; } make_rule += ": "; auto included_files = parser.GetIncludedFilesRecursive(file_name); - for (auto it = included_files.begin(); - it != included_files.end(); ++it) { + for (auto it = included_files.begin(); it != included_files.end(); ++it) { make_rule += " " + *it; } return make_rule; diff --git a/src/idl_gen_go.cpp b/src/idl_gen_go.cpp index be437c7b0..5841e121c 100644 --- a/src/idl_gen_go.cpp +++ b/src/idl_gen_go.cpp @@ -663,22 +663,10 @@ class GoGenerator : public BaseGenerator { bool needs_imports) { if (!classcode.length()) return true; - std::string namespace_name; - std::string namespace_dir = path_; // Either empty or ends in separator. - auto &namespaces = parser_.namespaces_.back()->components; - for (auto it = namespaces.begin(); it != namespaces.end(); ++it) { - if (namespace_name.length()) { - namespace_name += "."; - } - namespace_name = *it; - namespace_dir += *it + kPathSeparator; - } - EnsureDirExists(namespace_dir); - std::string code = ""; - BeginFile(namespace_name, needs_imports, &code); + BeginFile(LastNamespacePart(), needs_imports, &code); code += classcode; - std::string filename = namespace_dir + def.name + ".go"; + std::string filename = namespace_dir_ + def.name + ".go"; return SaveFile(filename.c_str(), code, false); } }; diff --git a/src/idl_gen_php.cpp b/src/idl_gen_php.cpp index 5fb412434..599d5571d 100644 --- a/src/idl_gen_php.cpp +++ b/src/idl_gen_php.cpp @@ -984,26 +984,12 @@ namespace php { bool needs_imports) { if (!classcode.length()) return true; - std::string namespace_name; - std::string namespace_dir = path_; - - auto &namespaces = parser_.namespaces_.back()->components; - for (auto it = namespaces.begin(); it != namespaces.end(); ++it) { - if (namespace_name.length()) { - namespace_name += "\\"; - namespace_dir += kPathSeparator; - } - namespace_name += *it; - namespace_dir += *it; - EnsureDirExists(namespace_dir.c_str()); - } - std::string code = ""; - BeginFile(namespace_name, needs_imports, &code); + BeginFile(FullNamespace("\\"), needs_imports, &code); code += classcode; std::string filename = - namespace_dir + kPathSeparator + def.name + ".php"; + namespace_dir_ + kPathSeparator + def.name + ".php"; return SaveFile(filename.c_str(), code, false); } }; diff --git a/src/idl_gen_python.cpp b/src/idl_gen_python.cpp index 291aada0e..7b8d168c1 100644 --- a/src/idl_gen_python.cpp +++ b/src/idl_gen_python.cpp @@ -642,26 +642,19 @@ class PythonGenerator : public BaseGenerator { bool needs_imports) { if (!classcode.length()) return true; - std::string namespace_name; std::string namespace_dir = path_; auto &namespaces = parser_.namespaces_.back()->components; for (auto it = namespaces.begin(); it != namespaces.end(); ++it) { - if (namespace_name.length()) { - namespace_name += "."; - namespace_dir += kPathSeparator; - } - namespace_name = *it; + if (it != namespaces.begin()) namespace_dir += kPathSeparator; namespace_dir += *it; - EnsureDirExists(namespace_dir.c_str()); - std::string init_py_filename = namespace_dir + "/__init__.py"; SaveFile(init_py_filename.c_str(), "", false); } std::string code = ""; - BeginFile(namespace_name, needs_imports, &code); + BeginFile(LastNamespacePart(), needs_imports, &code); code += classcode; - std::string filename = namespace_dir + kPathSeparator + def.name + ".py"; + std::string filename = namespace_dir_ + kPathSeparator + def.name + ".py"; return SaveFile(filename.c_str(), code, false); } }; From 7dfe8e726bb774727c37b3a83e1f7ee790f52ce8 Mon Sep 17 00:00:00 2001 From: BogDan Vatra Date: Mon, 30 May 2016 14:04:37 +0300 Subject: [PATCH 07/13] Define bit mask operators for scoped enums bitfields Close #3887 --- include/flatbuffers/flatbuffers.h | 29 +++++++++++++++++++++++++++++ src/idl_gen_cpp.cpp | 5 ++++- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/include/flatbuffers/flatbuffers.h b/include/flatbuffers/flatbuffers.h index 0fa31250f..9a8e0bef7 100644 --- a/include/flatbuffers/flatbuffers.h +++ b/include/flatbuffers/flatbuffers.h @@ -1485,6 +1485,35 @@ volatile __attribute__((weak)) const char *flatbuffer_version_string = #endif // !defined(_WIN32) && !defined(__CYGWIN__) +#define DEFINE_BITMASK_OPERATORS(E)\ + inline E operator | (E lhs, E rhs){\ + using T = std::underlying_type::type;\ + return E(T(lhs) | T(rhs));\ + }\ + inline E operator & (E lhs, E rhs){\ + using T = std::underlying_type::type;\ + return E(T(lhs) & T(rhs));\ + }\ + inline E operator ^ (E lhs, E rhs){\ + using T = std::underlying_type::type;\ + return E(T(lhs) ^ T(rhs));\ + }\ + inline E operator ~ (E lhs){\ + using T = std::underlying_type::type;\ + return E(~T(lhs));\ + }\ + inline E operator |= (E &lhs, E rhs){\ + lhs = lhs | rhs;\ + return lhs;\ + }\ + inline E operator &= (E &lhs, E rhs){\ + lhs = lhs & rhs;\ + return lhs;\ + }\ + inline E operator ^= (E &lhs, E rhs){\ + lhs = lhs ^ rhs;\ + return lhs;\ + } /// @endcond } // namespace flatbuffers diff --git a/src/idl_gen_cpp.cpp b/src/idl_gen_cpp.cpp index 051cd99de..f0daca26a 100644 --- a/src/idl_gen_cpp.cpp +++ b/src/idl_gen_cpp.cpp @@ -182,7 +182,10 @@ static void GenEnum(const Parser &parser, EnumDef &enum_def, code += GenEnumVal(enum_def, minv->name, parser.opts) + ",\n"; code += " " + GenEnumVal(enum_def, "MAX", parser.opts) + " = "; code += GenEnumVal(enum_def, maxv->name, parser.opts) + "\n"; - code += "};\n\n"; + code += "};\n"; + if (parser.opts.scoped_enums && enum_def.attributes.Lookup("bit_flags")) + code += "DEFINE_BITMASK_OPERATORS(" + enum_def.name + ")\n"; + code += "\n"; // Generate a generate string table for enum values. // Problem is, if values are very sparse that could generate really big From 0b0cf58f24a007075d17bff42c3a2724eda8ddf2 Mon Sep 17 00:00:00 2001 From: BogDan Vatra Date: Wed, 1 Jun 2016 10:04:55 +0300 Subject: [PATCH 08/13] We already know the underlying_type. We just need to pass it to DEFINE_BITMASK_OPERATORS macro --- include/flatbuffers/flatbuffers.h | 6 +----- src/idl_gen_cpp.cpp | 2 +- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/include/flatbuffers/flatbuffers.h b/include/flatbuffers/flatbuffers.h index 5de3a6611..b6260b6d5 100644 --- a/include/flatbuffers/flatbuffers.h +++ b/include/flatbuffers/flatbuffers.h @@ -1485,21 +1485,17 @@ volatile __attribute__((weak)) const char *flatbuffer_version_string = #endif // !defined(_WIN32) && !defined(__CYGWIN__) -#define DEFINE_BITMASK_OPERATORS(E)\ +#define DEFINE_BITMASK_OPERATORS(E, T)\ inline E operator | (E lhs, E rhs){\ - using T = std::underlying_type::type;\ return E(T(lhs) | T(rhs));\ }\ inline E operator & (E lhs, E rhs){\ - using T = std::underlying_type::type;\ return E(T(lhs) & T(rhs));\ }\ inline E operator ^ (E lhs, E rhs){\ - using T = std::underlying_type::type;\ return E(T(lhs) ^ T(rhs));\ }\ inline E operator ~ (E lhs){\ - using T = std::underlying_type::type;\ return E(~T(lhs));\ }\ inline E operator |= (E &lhs, E rhs){\ diff --git a/src/idl_gen_cpp.cpp b/src/idl_gen_cpp.cpp index f0daca26a..f045fe4a5 100644 --- a/src/idl_gen_cpp.cpp +++ b/src/idl_gen_cpp.cpp @@ -184,7 +184,7 @@ static void GenEnum(const Parser &parser, EnumDef &enum_def, code += GenEnumVal(enum_def, maxv->name, parser.opts) + "\n"; code += "};\n"; if (parser.opts.scoped_enums && enum_def.attributes.Lookup("bit_flags")) - code += "DEFINE_BITMASK_OPERATORS(" + enum_def.name + ")\n"; + code += "DEFINE_BITMASK_OPERATORS(" + enum_def.name + ", " + GenTypeBasic(enum_def.underlying_type, false) + ")\n"; code += "\n"; // Generate a generate string table for enum values. From 038ea7c1d37cccac23ff962d8dcf62f6bce2a67f Mon Sep 17 00:00:00 2001 From: BogDan Vatra Date: Wed, 1 Jun 2016 10:05:27 +0300 Subject: [PATCH 09/13] Add ! operator --- include/flatbuffers/flatbuffers.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/flatbuffers/flatbuffers.h b/include/flatbuffers/flatbuffers.h index b6260b6d5..e487fe4d6 100644 --- a/include/flatbuffers/flatbuffers.h +++ b/include/flatbuffers/flatbuffers.h @@ -1509,6 +1509,10 @@ volatile __attribute__((weak)) const char *flatbuffer_version_string = inline E operator ^= (E &lhs, E rhs){\ lhs = lhs ^ rhs;\ return lhs;\ + }\ + inline bool operator !(E rhs) \ + {\ + return !bool(T(rhs)); \ } /// @endcond } // namespace flatbuffers From cccd7003ed395d7f48ce28cac0cfd79e8e137eab Mon Sep 17 00:00:00 2001 From: BogDan Vatra Date: Wed, 1 Jun 2016 10:03:40 +0300 Subject: [PATCH 10/13] MIN & MAX are useless for bit_flags Instead we need NONE (0) and ANY (all orred values), if the user didn't already defined them --- src/idl_gen_cpp.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/idl_gen_cpp.cpp b/src/idl_gen_cpp.cpp index f045fe4a5..a163ee816 100644 --- a/src/idl_gen_cpp.cpp +++ b/src/idl_gen_cpp.cpp @@ -166,6 +166,7 @@ static void GenEnum(const Parser &parser, EnumDef &enum_def, if (parser.opts.scoped_enums) code += " : " + GenTypeBasic(enum_def.underlying_type, false); code += " {\n"; + int64_t anyv = 0; EnumVal *minv = nullptr, *maxv = nullptr; for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end(); @@ -176,12 +177,20 @@ static void GenEnum(const Parser &parser, EnumDef &enum_def, code += NumToString(ev.value) + ",\n"; minv = !minv || minv->value > ev.value ? &ev : minv; maxv = !maxv || maxv->value < ev.value ? &ev : maxv; + anyv |= ev.value; } assert(minv && maxv); - code += " " + GenEnumVal(enum_def, "MIN", parser.opts) + " = "; - code += GenEnumVal(enum_def, minv->name, parser.opts) + ",\n"; - code += " " + GenEnumVal(enum_def, "MAX", parser.opts) + " = "; - code += GenEnumVal(enum_def, maxv->name, parser.opts) + "\n"; + if (enum_def.attributes.Lookup("bit_flags")) { + if (minv->value != 0) // If the user didn't defined NONE value + code += " " + GenEnumVal(enum_def, "NONE", parser.opts) + " = 0,\n"; + if (maxv->value != anyv) // If the user didn't defined ANY value + code += " " + GenEnumVal(enum_def, "ANY", parser.opts) + " = " + NumToString(anyv) + "\n"; + } else { // MIN & MAX are useless for bit_flags + code += " " + GenEnumVal(enum_def, "MIN", parser.opts) + " = "; + code += GenEnumVal(enum_def, minv->name, parser.opts) + ",\n"; + code += " " + GenEnumVal(enum_def, "MAX", parser.opts) + " = "; + code += GenEnumVal(enum_def, maxv->name, parser.opts) + "\n"; + } code += "};\n"; if (parser.opts.scoped_enums && enum_def.attributes.Lookup("bit_flags")) code += "DEFINE_BITMASK_OPERATORS(" + enum_def.name + ", " + GenTypeBasic(enum_def.underlying_type, false) + ")\n"; From 3e52fecd1ed1c68e62b441c9e227b64351eef1c4 Mon Sep 17 00:00:00 2001 From: BogDan Vatra Date: Wed, 1 Jun 2016 10:23:44 +0300 Subject: [PATCH 11/13] Don't generate MIN & MAX enum values if "--no-prefix" is used. Close #3892 --- src/idl_gen_cpp.cpp | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/idl_gen_cpp.cpp b/src/idl_gen_cpp.cpp index a163ee816..1cb801356 100644 --- a/src/idl_gen_cpp.cpp +++ b/src/idl_gen_cpp.cpp @@ -179,17 +179,19 @@ static void GenEnum(const Parser &parser, EnumDef &enum_def, maxv = !maxv || maxv->value < ev.value ? &ev : maxv; anyv |= ev.value; } - assert(minv && maxv); - if (enum_def.attributes.Lookup("bit_flags")) { - if (minv->value != 0) // If the user didn't defined NONE value - code += " " + GenEnumVal(enum_def, "NONE", parser.opts) + " = 0,\n"; - if (maxv->value != anyv) // If the user didn't defined ANY value - code += " " + GenEnumVal(enum_def, "ANY", parser.opts) + " = " + NumToString(anyv) + "\n"; - } else { // MIN & MAX are useless for bit_flags - code += " " + GenEnumVal(enum_def, "MIN", parser.opts) + " = "; - code += GenEnumVal(enum_def, minv->name, parser.opts) + ",\n"; - code += " " + GenEnumVal(enum_def, "MAX", parser.opts) + " = "; - code += GenEnumVal(enum_def, maxv->name, parser.opts) + "\n"; + if (parser.opts.scoped_enums || parser.opts.prefixed_enums) { + assert(minv && maxv); + if (enum_def.attributes.Lookup("bit_flags")) { + if (minv->value != 0) // If the user didn't defined NONE value + code += " " + GenEnumVal(enum_def, "NONE", parser.opts) + " = 0,\n"; + if (maxv->value != anyv) // If the user didn't defined ANY value + code += " " + GenEnumVal(enum_def, "ANY", parser.opts) + " = " + NumToString(anyv) + "\n"; + } else { // MIN & MAX are useless for bit_flags + code += " " + GenEnumVal(enum_def, "MIN", parser.opts) + " = "; + code += GenEnumVal(enum_def, minv->name, parser.opts) + ",\n"; + code += " " + GenEnumVal(enum_def, "MAX", parser.opts) + " = "; + code += GenEnumVal(enum_def, maxv->name, parser.opts) + "\n"; + } } code += "};\n"; if (parser.opts.scoped_enums && enum_def.attributes.Lookup("bit_flags")) From b3c35750c2a40d09b6fa8982663dd10337d3b5dd Mon Sep 17 00:00:00 2001 From: Martin Ankerl Date: Wed, 1 Jun 2016 13:13:00 +0200 Subject: [PATCH 12/13] renamed functions More descriptive name, show that it's really just a temporary object. --- include/flatbuffers/flatbuffers.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/flatbuffers/flatbuffers.h b/include/flatbuffers/flatbuffers.h index 07b7cadec..e94d0de70 100644 --- a/include/flatbuffers/flatbuffers.h +++ b/include/flatbuffers/flatbuffers.h @@ -1153,13 +1153,13 @@ template const T *GetRoot(const void *buf) { /// Helpers to get a typed pointer to objects that are currently beeing built. /// @warning Creating new objects will lead to reallocations and invalidates the pointer! -template T *GetMutableObject(FlatBufferBuilder &fbb, Offset offset) { +template T *GetMutableTemporaryPointer(FlatBufferBuilder &fbb, Offset offset) { return reinterpret_cast(fbb.GetCurrentBufferPointer() + fbb.GetSize() - offset.o); } -template const T *GetObject(FlatBufferBuilder &fbb, Offset offset) { - return GetMutableObject(fbb, offset); +template const T *GetTemporaryPointer(FlatBufferBuilder &fbb, Offset offset) { + return GetMutableTemporaryPointer(fbb, offset); } // Helper to see if the identifier in a buffer has the expected value. From e92ae5199d52fd59540a800bec7eef46cd778257 Mon Sep 17 00:00:00 2001 From: Wouter van Oortmerssen Date: Thu, 2 Jun 2016 14:55:35 -0700 Subject: [PATCH 13/13] Fixed compile errors on Windows --- include/flatbuffers/code_generators.h | 4 ++++ src/idl_parser.cpp | 10 +++++----- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/include/flatbuffers/code_generators.h b/include/flatbuffers/code_generators.h index a832334ec..95fa0c1ac 100644 --- a/include/flatbuffers/code_generators.h +++ b/include/flatbuffers/code_generators.h @@ -45,6 +45,10 @@ class BaseGenerator { namespace_dir_(BaseGenerator::NamespaceDir(parser, path)){}; virtual ~BaseGenerator(){}; + // No copy/assign. + BaseGenerator &operator=(const BaseGenerator &); + BaseGenerator(const BaseGenerator &); + const char *FlatBuffersGeneratedWarning() { return "automatically generated by the FlatBuffers compiler," " do not modify\n\n"; diff --git a/src/idl_parser.cpp b/src/idl_parser.cpp index 2bf99eac0..f5badab16 100644 --- a/src/idl_parser.cpp +++ b/src/idl_parser.cpp @@ -275,7 +275,7 @@ CheckedError Parser::Next() { return Error( "illegal Unicode sequence (multiple high surrogates)"); } else { - unicode_high_surrogate = val; + unicode_high_surrogate = static_cast(val); } } else if (val >= 0xDC00 && val <= 0xDFFF) { if (unicode_high_surrogate == -1) { @@ -2001,14 +2001,14 @@ flatbuffers::Offset> attrs; - for (auto kv : attributes.dict) { - auto it = parser.known_attributes_.find(kv.first); + for (auto kv = attributes.dict.begin(); kv != attributes.dict.end(); ++kv) { + auto it = parser.known_attributes_.find(kv->first); assert(it != parser.known_attributes_.end()); if (!it->second) { // Custom attribute. attrs.push_back( - reflection::CreateKeyValue(*builder, builder->CreateString(kv.first), + reflection::CreateKeyValue(*builder, builder->CreateString(kv->first), builder->CreateString( - kv.second->constant))); + kv->second->constant))); } } if (attrs.size()) {