From 8a64afabfd3c3f7f4602efbc6dac3f3cd067dd1d Mon Sep 17 00:00:00 2001 From: Lakedaemon Date: Wed, 13 Apr 2016 23:21:18 +0200 Subject: [PATCH 1/3] Transition 1 (with nice diffs) Go, Cpp and General code generators with class --- CMakeLists.txt | 1 + include/flatbuffers/code_generators.h | 64 +++++++++++++++++++++++++++ src/idl_gen_cpp.cpp | 36 +++++++++------ src/idl_gen_general.cpp | 28 +++++++++--- src/idl_gen_go.cpp | 21 ++++++--- 5 files changed, 126 insertions(+), 24 deletions(-) create mode 100644 include/flatbuffers/code_generators.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 8449ffb61..47a66e6cc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,6 +17,7 @@ if(NOT FLATBUFFERS_BUILD_FLATC AND FLATBUFFERS_BUILD_TESTS) endif() set(FlatBuffers_Library_SRCS + include/flatbuffers/code_generators.h include/flatbuffers/flatbuffers.h include/flatbuffers/hash.h include/flatbuffers/idl.h diff --git a/include/flatbuffers/code_generators.h b/include/flatbuffers/code_generators.h new file mode 100644 index 000000000..666e1aa8c --- /dev/null +++ b/include/flatbuffers/code_generators.h @@ -0,0 +1,64 @@ +/* + * Copyright 2014 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLATBUFFERS_CODE_GENERATORS_H_ +#define FLATBUFFERS_CODE_GENERATORS_H_ + +/** This file defines some classes, that code generators should extend to gain + common functionalities : + + BaseGenerator is the base class for all (binary, textual, strongly typed, + dynamically typed, whatever) generators. + It is really abstract, general and flexible and doesn't do much appart from + holding the parser, a path and a filename being processed. + Still, it brings a common structure (normalization) among generators + + The many advantages of object based generators will come later from : + + A) the CodeWriter class (semi-automatic indentation (python), semi-automatic + (C++) namespace scopes, export to different files (classic, top level + methods), + simpler code to generate string from things (comments (vector of strings), + indentation commands (TAB BAT), newlines (NL), numbers, const char* or + std::string) + + B) the Generator subclass (heritance for supporting different versions of a + language, avoid field name clash, write text/binary to file, types + management, + common computations and sctructures : enum analysis (function, array, map, + ordered list + binarysearch),...) + +*/ +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; + +protected: + virtual ~BaseGenerator(){}; + + const Parser &parser; + const std::string &path; + const std::string &file_name; +}; + +} // namespace flatbuffers + +#endif // FLATBUFFERS_CODE_GENERATORS_H_ diff --git a/src/idl_gen_cpp.cpp b/src/idl_gen_cpp.cpp index e043b0146..7ea09c281 100644 --- a/src/idl_gen_cpp.cpp +++ b/src/idl_gen_cpp.cpp @@ -19,6 +19,7 @@ #include "flatbuffers/flatbuffers.h" #include "flatbuffers/idl.h" #include "flatbuffers/util.h" +#include "flatbuffers/code_generators.h" namespace flatbuffers { namespace cpp { @@ -708,10 +709,20 @@ struct IsAlnum { } }; -// Iterate through all definitions we haven't generate code for (enums, structs, -// and tables) and output them to a single file. -std::string GenerateCPP(const Parser &parser, - const std::string &file_name) { +static std::string GeneratedFileName(const std::string &path, + const std::string &file_name) { + return path + file_name + "_generated.h"; +} + +namespace cpp { +class CppGenerator : public BaseGenerator { +public: + CppGenerator(const Parser &parser_, const std::string &path_, + const std::string &file_name_) + : BaseGenerator(parser_, path_, file_name_){}; + // Iterate through all definitions we haven't generate code for (enums, 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) { @@ -722,7 +733,7 @@ std::string GenerateCPP(const Parser &parser, if (!(*it)->generated) goto generate_code; } // No code to generate, exit: - return std::string(); + return true; generate_code: @@ -885,20 +896,17 @@ std::string GenerateCPP(const Parser &parser, // Close the include guard. code += "\n#endif // " + include_guard + "\n"; - return code; -} + return SaveFile(GeneratedFileName(path, file_name).c_str(), code, false); + } +}; +} // namespace cpp -static std::string GeneratedFileName(const std::string &path, - const std::string &file_name) { - return path + file_name + "_generated.h"; -} bool GenerateCPP(const Parser &parser, const std::string &path, const std::string &file_name) { - auto code = GenerateCPP(parser, file_name); - return !code.length() || - SaveFile(GeneratedFileName(path, file_name).c_str(), code, false); + cpp::CppGenerator *generator = new cpp::CppGenerator(parser, path, file_name); + return generator->generate(); } std::string CPPMakeRule(const Parser &parser, diff --git a/src/idl_gen_general.cpp b/src/idl_gen_general.cpp index e663ddb52..09913c4c3 100644 --- a/src/idl_gen_general.cpp +++ b/src/idl_gen_general.cpp @@ -19,6 +19,7 @@ #include "flatbuffers/flatbuffers.h" #include "flatbuffers/idl.h" #include "flatbuffers/util.h" +#include "flatbuffers/code_generators.h" #include namespace flatbuffers { @@ -1146,11 +1147,18 @@ static bool SaveClass(const LanguageParameters &lang, const Parser &parser, return SaveFile(filename.c_str(), code, false); } -bool GenerateGeneral(const Parser &parser, - const std::string &path, - const std::string & file_name) { - - assert(parser.opts.lang <= IDLOptions::kMAX); +/** it'll be split later in java/csharp... and moved to separate files */ +namespace general { +/** members methods signature will be simpler as they won't have to pass parser, + * filename & path */ +/** more features coming through the JavaGenerator, CSharpGenerator ...*/ +class GeneralGenerator : public BaseGenerator { +public: + GeneralGenerator(const Parser &parser_, const std::string &path_, + const std::string &file_name_) + : BaseGenerator(parser_, path_, file_name_){}; + bool generate() { + assert(parser.opts.lang <= IDLOptions::kMAX); auto lang = language_parameters[parser.opts.lang]; std::string one_file_code; @@ -1184,6 +1192,16 @@ bool GenerateGeneral(const Parser &parser, return SaveClass(lang, parser, file_name, one_file_code,path, true, true); } return true; + } +}; +} // namespace general + +bool GenerateGeneral(const Parser &parser, + const std::string &path, + const std::string & file_name) { + general::GeneralGenerator *generator = + new general::GeneralGenerator(parser, path, file_name); + return generator->generate(); } static std::string ClassFileName(const LanguageParameters &lang, diff --git a/src/idl_gen_go.cpp b/src/idl_gen_go.cpp index 88ce1f2a5..473e0fe60 100644 --- a/src/idl_gen_go.cpp +++ b/src/idl_gen_go.cpp @@ -21,6 +21,7 @@ #include "flatbuffers/flatbuffers.h" #include "flatbuffers/idl.h" #include "flatbuffers/util.h" +#include "flatbuffers/code_generators.h" #ifdef _WIN32 #include @@ -660,11 +661,12 @@ static void GenStructBuilder(const StructDef &struct_def, EndBuilderBody(code_ptr); } -} // namespace go - -bool GenerateGo(const Parser &parser, - const std::string &path, - const std::string & /*file_name*/) { +class GoGenerator : public BaseGenerator { +public: + GoGenerator(const Parser &parser_, const std::string &path_, + const std::string &file_name_) + : BaseGenerator(parser_, path_, file_name_){}; + bool generate() { for (auto it = parser.enums_.vec.begin(); it != parser.enums_.vec.end(); ++it) { std::string enumcode; @@ -682,6 +684,15 @@ bool GenerateGo(const Parser &parser, } return true; + } +}; +} // namespace go + +bool GenerateGo(const Parser &parser, + const std::string &path, + const std::string & file_name) { + go::GoGenerator *generator = new go::GoGenerator(parser, path, file_name); + return generator->generate(); } } // namespace flatbuffers From 38597160f2b79a9620d70c43754248c41a5fdfeb Mon Sep 17 00:00:00 2001 From: Lakedaemon Date: Fri, 15 Apr 2016 13:20:26 +0200 Subject: [PATCH 2/3] Enforcing the google C++ style guide --- include/flatbuffers/code_generators.h | 45 +--- src/idl_gen_cpp.cpp | 321 +++++++++++++------------- src/idl_gen_general.cpp | 78 +++---- src/idl_gen_go.cpp | 41 ++-- 4 files changed, 227 insertions(+), 258 deletions(-) diff --git a/include/flatbuffers/code_generators.h b/include/flatbuffers/code_generators.h index 666e1aa8c..6b27ea780 100644 --- a/include/flatbuffers/code_generators.h +++ b/include/flatbuffers/code_generators.h @@ -17,48 +17,23 @@ #ifndef FLATBUFFERS_CODE_GENERATORS_H_ #define FLATBUFFERS_CODE_GENERATORS_H_ -/** This file defines some classes, that code generators should extend to gain - common functionalities : - - BaseGenerator is the base class for all (binary, textual, strongly typed, - dynamically typed, whatever) generators. - It is really abstract, general and flexible and doesn't do much appart from - holding the parser, a path and a filename being processed. - Still, it brings a common structure (normalization) among generators - - The many advantages of object based generators will come later from : - - A) the CodeWriter class (semi-automatic indentation (python), semi-automatic - (C++) namespace scopes, export to different files (classic, top level - methods), - simpler code to generate string from things (comments (vector of strings), - indentation commands (TAB BAT), newlines (NL), numbers, const char* or - std::string) - - B) the Generator subclass (heritance for supporting different versions of a - language, avoid field name clash, write text/binary to file, types - management, - common computations and sctructures : enum analysis (function, array, map, - ordered list + binarysearch),...) - -*/ 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_){}; + 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; -protected: + protected: virtual ~BaseGenerator(){}; - const Parser &parser; - const std::string &path; - const std::string &file_name; + const Parser &parser_; + const std::string &path_; + const std::string &file_name_; }; -} // namespace flatbuffers +} // namespace flatbuffers -#endif // FLATBUFFERS_CODE_GENERATORS_H_ +#endif // FLATBUFFERS_CODE_GENERATORS_H_ diff --git a/src/idl_gen_cpp.cpp b/src/idl_gen_cpp.cpp index 7ea09c281..c1b6ba566 100644 --- a/src/idl_gen_cpp.cpp +++ b/src/idl_gen_cpp.cpp @@ -716,194 +716,195 @@ static std::string GeneratedFileName(const std::string &path, namespace cpp { class CppGenerator : public BaseGenerator { -public: - CppGenerator(const Parser &parser_, const std::string &path_, - const std::string &file_name_) - : BaseGenerator(parser_, path_, file_name_){}; - // Iterate through all definitions we haven't generate code for (enums, structs, + public: + CppGenerator(const Parser &parser, const std::string &path, + const std::string &file_name) + : BaseGenerator(parser, path, file_name){}; + // Iterate through all definitions we haven't generate code for (enums, + // 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; + // 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; + using namespace cpp; - std::string code; - code = "// automatically generated by the FlatBuffers compiler," - " do not modify\n\n"; + std::string code; + code = + "// automatically generated by the FlatBuffers compiler," + " do not modify\n\n"; - // Generate include guard. - std::string include_guard_ident = file_name; - // Remove any non-alpha-numeric characters that may appear in a filename. - include_guard_ident.erase( - std::remove_if(include_guard_ident.begin(), - include_guard_ident.end(), - IsAlnum()), - include_guard_ident.end()); - std::string include_guard = "FLATBUFFERS_GENERATED_" + include_guard_ident; - include_guard += "_"; - // For further uniqueness, also add the namespace. - auto name_space = parser.namespaces_.back(); - for (auto it = name_space->components.begin(); - it != name_space->components.end(); ++it) { - include_guard += *it + "_"; - } - include_guard += "H_"; - std::transform(include_guard.begin(), include_guard.end(), - include_guard.begin(), ::toupper); - code += "#ifndef " + include_guard + "\n"; - code += "#define " + include_guard + "\n\n"; + // Generate include guard. + std::string include_guard_ident = file_name_; + // Remove any non-alpha-numeric characters that may appear in a filename. + include_guard_ident.erase( + std::remove_if(include_guard_ident.begin(), include_guard_ident.end(), + IsAlnum()), + include_guard_ident.end()); + std::string include_guard = "FLATBUFFERS_GENERATED_" + include_guard_ident; + include_guard += "_"; + // For further uniqueness, also add the namespace. + auto name_space = parser_.namespaces_.back(); + for (auto it = name_space->components.begin(); + it != name_space->components.end(); ++it) { + include_guard += *it + "_"; + } + include_guard += "H_"; + std::transform(include_guard.begin(), include_guard.end(), + include_guard.begin(), ::toupper); + code += "#ifndef " + include_guard + "\n"; + code += "#define " + include_guard + "\n\n"; - code += "#include \"flatbuffers/flatbuffers.h\"\n\n"; + code += "#include \"flatbuffers/flatbuffers.h\"\n\n"; - if (parser.opts.include_dependence_headers) { - int num_includes = 0; - for (auto it = parser.included_files_.begin(); - it != parser.included_files_.end(); ++it) { - auto basename = flatbuffers::StripPath( - flatbuffers::StripExtension(it->first)); - if (basename != file_name) { - code += "#include \"" + basename + "_generated.h\"\n"; - num_includes++; + if (parser_.opts.include_dependence_headers) { + int num_includes = 0; + for (auto it = parser_.included_files_.begin(); + it != parser_.included_files_.end(); ++it) { + auto basename = + flatbuffers::StripPath(flatbuffers::StripExtension(it->first)); + if (basename != file_name_) { + code += "#include \"" + basename + "_generated.h\"\n"; + num_includes++; + } + } + if (num_includes) code += "\n"; + } + + assert(!code_generator_cur_name_space); + + // Generate forward declarations for all structs/tables, since they may + // have circular references. + for (auto it = parser_.structs_.vec.begin(); it != parser_.structs_.vec.end(); + ++it) { + auto &struct_def = **it; + if (!struct_def.generated) { + CheckNameSpace(struct_def, &code); + code += "struct " + struct_def.name + ";\n\n"; } } - if (num_includes) code += "\n"; - } - assert(!code_generator_cur_name_space); - - // Generate forward declarations for all structs/tables, since they may - // have circular references. - for (auto it = parser.structs_.vec.begin(); - it != parser.structs_.vec.end(); ++it) { - auto &struct_def = **it; - if (!struct_def.generated) { - CheckNameSpace(struct_def, &code); - code += "struct " + struct_def.name + ";\n\n"; + // Generate code for all the enum declarations. + for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end(); + ++it) { + auto &enum_def = **it; + if (!enum_def.generated) { + CheckNameSpace(**it, &code); + GenEnum(parser_, **it, &code); + } } - } - // Generate code for all the enum declarations. - for (auto it = parser.enums_.vec.begin(); - it != parser.enums_.vec.end(); ++it) { - auto &enum_def = **it; - if (!enum_def.generated) { - CheckNameSpace(**it, &code); - GenEnum(parser, **it, &code); + // Generate code for all structs, then all tables. + for (auto it = parser_.structs_.vec.begin(); it != parser_.structs_.vec.end(); + ++it) { + auto &struct_def = **it; + if (struct_def.fixed && !struct_def.generated) { + CheckNameSpace(struct_def, &code); + GenStruct(parser_, struct_def, &code); + } } - } - - // Generate code for all structs, then all tables. - for (auto it = parser.structs_.vec.begin(); - it != parser.structs_.vec.end(); ++it) { - auto &struct_def = **it; - if (struct_def.fixed && !struct_def.generated) { - CheckNameSpace(struct_def, &code); - GenStruct(parser, struct_def, &code); + for (auto it = parser_.structs_.vec.begin(); it != parser_.structs_.vec.end(); + ++it) { + auto &struct_def = **it; + if (!struct_def.fixed && !struct_def.generated) { + CheckNameSpace(struct_def, &code); + GenTable(parser_, struct_def, &code); + } } - } - for (auto it = parser.structs_.vec.begin(); - it != parser.structs_.vec.end(); ++it) { - auto &struct_def = **it; - if (!struct_def.fixed && !struct_def.generated) { - CheckNameSpace(struct_def, &code); - GenTable(parser, struct_def, &code); + + // Generate code for union verifiers. + for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end(); + ++it) { + auto &enum_def = **it; + if (enum_def.is_union && !enum_def.generated) { + CheckNameSpace(enum_def, &code); + GenEnumPost(parser_, enum_def, &code); + } } - } - // Generate code for union verifiers. - for (auto it = parser.enums_.vec.begin(); - it != parser.enums_.vec.end(); ++it) { - auto &enum_def = **it; - if (enum_def.is_union && !enum_def.generated) { - CheckNameSpace(enum_def, &code); - GenEnumPost(parser, enum_def, &code); - } - } + // Generate convenient global helper functions: + if (parser_.root_struct_def_) { + CheckNameSpace(*parser_.root_struct_def_, &code); + auto &name = parser_.root_struct_def_->name; + std::string qualified_name = + parser_.namespaces_.back()->GetFullyQualifiedName(name); + std::string cpp_qualified_name = TranslateNameSpace(qualified_name); - // Generate convenient global helper functions: - if (parser.root_struct_def_) { - CheckNameSpace(*parser.root_struct_def_, &code); - auto &name = parser.root_struct_def_->name; - std::string qualified_name = - parser.namespaces_.back()->GetFullyQualifiedName(name); - std::string cpp_qualified_name = TranslateNameSpace(qualified_name); - - // The root datatype accessor: - code += "inline const " + cpp_qualified_name + " *Get"; - code += name; - code += "(const void *buf) { return flatbuffers::GetRoot<"; - code += cpp_qualified_name + ">(buf); }\n\n"; - if (parser.opts.mutable_buffer) { - code += "inline " + name + " *GetMutable"; + // The root datatype accessor: + code += "inline const " + cpp_qualified_name + " *Get"; code += name; - code += "(void *buf) { return flatbuffers::GetMutableRoot<"; - code += name + ">(buf); }\n\n"; + code += "(const void *buf) { return flatbuffers::GetRoot<"; + code += cpp_qualified_name + ">(buf); }\n\n"; + if (parser_.opts.mutable_buffer) { + code += "inline " + name + " *GetMutable"; + code += name; + code += "(void *buf) { return flatbuffers::GetMutableRoot<"; + code += name + ">(buf); }\n\n"; + } + + // The root verifier: + code += "inline bool Verify"; + code += name; + code += + "Buffer(flatbuffers::Verifier &verifier) { " + "return verifier.VerifyBuffer<"; + code += cpp_qualified_name + ">(); }\n\n"; + + if (parser_.file_identifier_.length()) { + // Return the identifier + code += "inline const char *" + name; + code += "Identifier() { return \"" + parser_.file_identifier_; + code += "\"; }\n\n"; + + // Check if a buffer has the identifier. + code += "inline bool " + name; + code += "BufferHasIdentifier(const void *buf) { return flatbuffers::"; + code += "BufferHasIdentifier(buf, "; + code += name + "Identifier()); }\n\n"; + } + + if (parser_.file_extension_.length()) { + // Return the extension + code += "inline const char *" + name; + code += "Extension() { return \"" + parser_.file_extension_; + code += "\"; }\n\n"; + } + + // Finish a buffer with a given root object: + code += "inline void Finish" + name; + code += + "Buffer(flatbuffers::FlatBufferBuilder &fbb, flatbuffers::Offset<"; + code += cpp_qualified_name + "> root) { fbb.Finish(root"; + if (parser_.file_identifier_.length()) + code += ", " + name + "Identifier()"; + code += "); }\n\n"; } - // The root verifier: - code += "inline bool Verify"; - code += name; - code += "Buffer(flatbuffers::Verifier &verifier) { " - "return verifier.VerifyBuffer<"; - code += cpp_qualified_name + ">(); }\n\n"; + assert(code_generator_cur_name_space); + CloseNestedNameSpaces(code_generator_cur_name_space, &code); - if (parser.file_identifier_.length()) { - // Return the identifier - code += "inline const char *" + name; - code += "Identifier() { return \"" + parser.file_identifier_; - code += "\"; }\n\n"; + code_generator_cur_name_space = nullptr; - // Check if a buffer has the identifier. - code += "inline bool " + name; - code += "BufferHasIdentifier(const void *buf) { return flatbuffers::"; - code += "BufferHasIdentifier(buf, "; - code += name + "Identifier()); }\n\n"; - } + // Close the include guard. + code += "\n#endif // " + include_guard + "\n"; - if (parser.file_extension_.length()) { - // Return the extension - code += "inline const char *" + name; - code += "Extension() { return \"" + parser.file_extension_; - code += "\"; }\n\n"; - } - - // Finish a buffer with a given root object: - code += "inline void Finish" + name; - code += "Buffer(flatbuffers::FlatBufferBuilder &fbb, flatbuffers::Offset<"; - code += cpp_qualified_name + "> root) { fbb.Finish(root"; - if (parser.file_identifier_.length()) - code += ", " + name + "Identifier()"; - code += "); }\n\n"; - } - - assert(code_generator_cur_name_space); - CloseNestedNameSpaces(code_generator_cur_name_space, &code); - - code_generator_cur_name_space = nullptr; - - // Close the include guard. - code += "\n#endif // " + include_guard + "\n"; - - return SaveFile(GeneratedFileName(path, file_name).c_str(), code, false); + return SaveFile(GeneratedFileName(path_, file_name_).c_str(), code, false); } }; -} // namespace cpp +} // namespace cpp - -bool GenerateCPP(const Parser &parser, - const std::string &path, +bool GenerateCPP(const Parser &parser, const std::string &path, const std::string &file_name) { cpp::CppGenerator *generator = new cpp::CppGenerator(parser, path, file_name); return generator->generate(); diff --git a/src/idl_gen_general.cpp b/src/idl_gen_general.cpp index 09913c4c3..a763d969b 100644 --- a/src/idl_gen_general.cpp +++ b/src/idl_gen_general.cpp @@ -1147,58 +1147,54 @@ static bool SaveClass(const LanguageParameters &lang, const Parser &parser, return SaveFile(filename.c_str(), code, false); } -/** it'll be split later in java/csharp... and moved to separate files */ namespace general { -/** members methods signature will be simpler as they won't have to pass parser, - * filename & path */ -/** more features coming through the JavaGenerator, CSharpGenerator ...*/ class GeneralGenerator : public BaseGenerator { -public: - GeneralGenerator(const Parser &parser_, const std::string &path_, - const std::string &file_name_) - : BaseGenerator(parser_, path_, file_name_){}; + public: + GeneralGenerator(const Parser &parser, const std::string &path, + const std::string &file_name) + : BaseGenerator(parser, path, file_name){}; bool generate() { - assert(parser.opts.lang <= IDLOptions::kMAX); - auto lang = language_parameters[parser.opts.lang]; - std::string one_file_code; + assert(parser_.opts.lang <= IDLOptions::kMAX); + auto lang = language_parameters[parser_.opts.lang]; + std::string one_file_code; - for (auto it = parser.enums_.vec.begin(); - it != parser.enums_.vec.end(); ++it) { - std::string enumcode; - GenEnum(lang, parser, **it, &enumcode); - if (parser.opts.one_file) { - one_file_code += enumcode; + for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end(); + ++it) { + std::string enumcode; + GenEnum(lang, parser_, **it, &enumcode); + if (parser_.opts.one_file) { + one_file_code += enumcode; + } else { + if (!SaveClass(lang, parser_, (**it).name, enumcode, path_, false, + false)) + return false; + } } - else { - if (!SaveClass(lang, parser, (**it).name, enumcode, path, false, false)) - return false; - } - } - for (auto it = parser.structs_.vec.begin(); - it != parser.structs_.vec.end(); ++it) { - std::string declcode; - GenStruct(lang, parser, **it, &declcode); - if (parser.opts.one_file) { - one_file_code += declcode; + for (auto it = parser_.structs_.vec.begin(); + it != parser_.structs_.vec.end(); ++it) { + std::string declcode; + GenStruct(lang, parser_, **it, &declcode); + if (parser_.opts.one_file) { + one_file_code += declcode; + } else { + if (!SaveClass(lang, parser_, (**it).name, declcode, path_, true, + false)) + return false; + } } - else { - if (!SaveClass(lang, parser, (**it).name, declcode, path, true, false)) - return false; - } - } - if (parser.opts.one_file) { - return SaveClass(lang, parser, file_name, one_file_code,path, true, true); - } - return true; + if (parser_.opts.one_file) { + return SaveClass(lang, parser_, file_name_, one_file_code, path_, true, + true); + } + return true; } }; -} // namespace general +} // namespace general -bool GenerateGeneral(const Parser &parser, - const std::string &path, - const std::string & file_name) { +bool GenerateGeneral(const Parser &parser, const std::string &path, + const std::string &file_name) { general::GeneralGenerator *generator = new general::GeneralGenerator(parser, path, file_name); return generator->generate(); diff --git a/src/idl_gen_go.cpp b/src/idl_gen_go.cpp index 473e0fe60..f674d1f47 100644 --- a/src/idl_gen_go.cpp +++ b/src/idl_gen_go.cpp @@ -662,35 +662,32 @@ static void GenStructBuilder(const StructDef &struct_def, } class GoGenerator : public BaseGenerator { -public: - GoGenerator(const Parser &parser_, const std::string &path_, - const std::string &file_name_) - : BaseGenerator(parser_, path_, file_name_){}; + public: + GoGenerator(const Parser &parser, const std::string &path, + const std::string &file_name) + : BaseGenerator(parser, path, file_name){}; bool generate() { - for (auto it = parser.enums_.vec.begin(); - it != parser.enums_.vec.end(); ++it) { - std::string enumcode; - go::GenEnum(**it, &enumcode); - if (!go::SaveType(parser, **it, enumcode, path, false)) - return false; - } + for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end(); + ++it) { + std::string enumcode; + go::GenEnum(**it, &enumcode); + if (!go::SaveType(parser_, **it, enumcode, path_, 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; - } + 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; + } - return true; + return true; } }; } // namespace go -bool GenerateGo(const Parser &parser, - const std::string &path, - const std::string & file_name) { +bool GenerateGo(const Parser &parser, const std::string &path, + const std::string &file_name) { go::GoGenerator *generator = new go::GoGenerator(parser, path, file_name); return generator->generate(); } From 6765c19d45509fdcffd5ee62cac5cacea32bd397 Mon Sep 17 00:00:00 2001 From: Lakedaemon Date: Tue, 26 Apr 2016 17:08:13 +0200 Subject: [PATCH 3/3] memory leak fix + php/js/python transition to class based generator --- src/idl_gen_cpp.cpp | 4 +- src/idl_gen_general.cpp | 5 +- src/idl_gen_go.cpp | 4 +- src/idl_gen_js.cpp | 113 +++++++++++++++++++++++----------------- src/idl_gen_php.cpp | 65 +++++++++++++++-------- src/idl_gen_python.cpp | 60 ++++++++++++++------- 6 files changed, 153 insertions(+), 98 deletions(-) diff --git a/src/idl_gen_cpp.cpp b/src/idl_gen_cpp.cpp index c1b6ba566..0e5d823f3 100644 --- a/src/idl_gen_cpp.cpp +++ b/src/idl_gen_cpp.cpp @@ -906,8 +906,8 @@ class CppGenerator : public BaseGenerator { bool GenerateCPP(const Parser &parser, const std::string &path, const std::string &file_name) { - cpp::CppGenerator *generator = new cpp::CppGenerator(parser, path, file_name); - return generator->generate(); + cpp::CppGenerator generator(parser, path, file_name); + return generator.generate(); } std::string CPPMakeRule(const Parser &parser, diff --git a/src/idl_gen_general.cpp b/src/idl_gen_general.cpp index a763d969b..e28661e82 100644 --- a/src/idl_gen_general.cpp +++ b/src/idl_gen_general.cpp @@ -1195,9 +1195,8 @@ class GeneralGenerator : public BaseGenerator { bool GenerateGeneral(const Parser &parser, const std::string &path, const std::string &file_name) { - general::GeneralGenerator *generator = - new general::GeneralGenerator(parser, path, file_name); - return generator->generate(); + general::GeneralGenerator generator(parser, path, file_name); + return generator.generate(); } static std::string ClassFileName(const LanguageParameters &lang, diff --git a/src/idl_gen_go.cpp b/src/idl_gen_go.cpp index f674d1f47..bce8f95bc 100644 --- a/src/idl_gen_go.cpp +++ b/src/idl_gen_go.cpp @@ -688,8 +688,8 @@ class GoGenerator : public BaseGenerator { bool GenerateGo(const Parser &parser, const std::string &path, const std::string &file_name) { - go::GoGenerator *generator = new go::GoGenerator(parser, path, file_name); - return generator->generate(); + go::GoGenerator generator(parser, path, file_name); + return generator.generate(); } } // namespace flatbuffers diff --git a/src/idl_gen_js.cpp b/src/idl_gen_js.cpp index f824bc688..de81f2764 100644 --- a/src/idl_gen_js.cpp +++ b/src/idl_gen_js.cpp @@ -19,6 +19,7 @@ #include "flatbuffers/flatbuffers.h" #include "flatbuffers/idl.h" #include "flatbuffers/util.h" +#include "flatbuffers/code_generators.h" namespace flatbuffers { namespace js { @@ -661,60 +662,76 @@ static void GenStruct(const Parser &parser, StructDef &struct_def, } // namespace js -// Iterate through all definitions we haven't generate code for (enums, structs, -// and tables) and output them to a single file. -std::string GenerateJS(const Parser &parser) { - using namespace js; - - // Generate code for all the enum declarations. - std::string enum_code, exports_code; - for (auto it = parser.enums_.vec.begin(); - it != parser.enums_.vec.end(); ++it) { - GenEnum(**it, &enum_code, &exports_code); - } - - // Generate code for all structs, then all tables. - std::string decl_code; - for (auto it = parser.structs_.vec.begin(); - it != parser.structs_.vec.end(); ++it) { - GenStruct(parser, **it, &decl_code, &exports_code); - } - - // Only output file-level code if there were any declarations. - if (enum_code.length() || decl_code.length()) { - std::string code; - code = "// automatically generated by the FlatBuffers compiler," - " do not modify\n\n"; - - // Generate code for all the namespace declarations. - GenNamespaces(parser, &code, &exports_code); - - // Output the main declaration code from above. - code += enum_code; - code += decl_code; - - if (!exports_code.empty() && !parser.opts.skip_js_exports) { - code += "// Exports for Node.js and RequireJS\n"; - code += exports_code; - } - - return code; - } - - return std::string(); -} - static std::string GeneratedFileName(const std::string &path, const std::string &file_name) { return path + file_name + "_generated.js"; } -bool GenerateJS(const Parser &parser, - const std::string &path, - const std::string &file_name) { - auto code = GenerateJS(parser); +namespace js { +// Iterate through all definitions we haven't generate code for (enums, structs, +// and tables) and output them to a single file. +class JsGenerator : public BaseGenerator { + public: + JsGenerator(const Parser &parser, const std::string &path, + const std::string &file_name) + : BaseGenerator(parser, path, file_name){}; + // Iterate through all definitions we haven't generate code for (enums, + // structs, and tables) and output them to a single file. + bool generate() { + 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"; + + // 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; + + 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); + SaveFile(GeneratedFileName(path_, file_name_).c_str(), code, false); + } + + private: + // Generate code for all enums. + void generateEnums(std::string *enum_code_ptr, + std::string *exports_code_ptr) { + for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end(); + ++it) { + auto &enum_def = **it; + GenEnum(enum_def, enum_code_ptr, exports_code_ptr); + } + } + + // Generate code for all structs. + void generateStructs(std::string *decl_code_ptr, + std::string *exports_code_ptr) { + 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); + } + } +}; +} // namespace js + +bool GenerateJS(const Parser &parser, const std::string &path, + const std::string &file_name) { + js::JsGenerator generator(parser, path, file_name); + return generator.generate(); } std::string JSMakeRule(const Parser &parser, diff --git a/src/idl_gen_php.cpp b/src/idl_gen_php.cpp index 5b904a077..b43ea6702 100644 --- a/src/idl_gen_php.cpp +++ b/src/idl_gen_php.cpp @@ -21,6 +21,7 @@ #include "flatbuffers/flatbuffers.h" #include "flatbuffers/idl.h" #include "flatbuffers/util.h" +#include "flatbuffers/code_generators.h" namespace flatbuffers { namespace php { @@ -974,29 +975,47 @@ namespace php { code += Indent + "}\n"; } -} // namespace php + class PhpGenerator : public BaseGenerator { + public: + PhpGenerator(const Parser &parser, const std::string &path, + const std::string &file_name) + : BaseGenerator(parser, path, file_name){}; + bool generate() { + if (!generateEnums()) return false; + if (!generateStructs()) return false; + return true; + } - bool GeneratePhp(const Parser &parser, - const std::string &path, - const std::string & /*file_name*/) { - for (auto it = parser.enums_.vec.begin(); - it != parser.enums_.vec.end(); ++it) { - std::string enumcode; - php::GenEnum(**it, &enumcode); + private: + bool generateEnums() { + for (auto it = parser_.enums_.vec.begin(); + it != parser_.enums_.vec.end(); ++it) { + auto &enum_def = **it; + std::string enumcode; + GenEnum(enum_def, &enumcode); + if (!SaveType(parser_, enum_def, enumcode, path_, false)) + return false; + } + return true; + } - if (!php::SaveType(parser, **it, enumcode, path, false)) - return false; + bool generateStructs() { + for (auto it = parser_.structs_.vec.begin(); + it != parser_.structs_.vec.end(); ++it) { + auto &struct_def = **it; + std::string declcode; + GenStruct(parser_, struct_def, &declcode); + if (!SaveType(parser_, struct_def, declcode, path_, true)) + return false; + } + return true; + } + }; + } // namespace php + + bool GeneratePhp(const Parser &parser, const std::string &path, + const std::string &file_name) { + php::PhpGenerator generator(parser, path, file_name); + return generator.generate(); } - - for (auto it = parser.structs_.vec.begin(); - it != parser.structs_.vec.end(); ++it) { - std::string declcode; - php::GenStruct(parser, **it, &declcode); - - if (!php::SaveType(parser, **it, declcode, path, true)) - return false; - } - - return true; -} -} // namespace flatbuffers + } // namespace flatbuffers diff --git a/src/idl_gen_python.cpp b/src/idl_gen_python.cpp index 7cd09cfcd..ee6d16874 100644 --- a/src/idl_gen_python.cpp +++ b/src/idl_gen_python.cpp @@ -21,6 +21,7 @@ #include "flatbuffers/flatbuffers.h" #include "flatbuffers/idl.h" #include "flatbuffers/util.h" +#include "flatbuffers/code_generators.h" namespace flatbuffers { namespace python { @@ -634,28 +635,47 @@ static void GenStructBuilder(const StructDef &struct_def, EndBuilderBody(code_ptr); } +class PythonGenerator : public BaseGenerator { + public: + PythonGenerator(const Parser &parser, const std::string &path, + const std::string &file_name) + : BaseGenerator(parser, path, file_name){}; + bool generate() { + if (!generateEnums()) return false; + if (!generateStructs()) return false; + return true; + } + + private: + bool generateEnums() { + for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end(); + ++it) { + auto &enum_def = **it; + std::string enumcode; + GenEnum(enum_def, &enumcode); + if (!SaveType(parser_, enum_def, enumcode, path_, false)) return false; + } + return true; + } + + bool generateStructs() { + for (auto it = parser_.structs_.vec.begin(); + it != parser_.structs_.vec.end(); ++it) { + 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; + } + return true; + } +}; + } // namespace python -bool GeneratePython(const Parser &parser, - const std::string &path, - const std::string & /*file_name*/) { - for (auto it = parser.enums_.vec.begin(); - it != parser.enums_.vec.end(); ++it) { - std::string enumcode; - python::GenEnum(**it, &enumcode); - if (!python::SaveType(parser, **it, enumcode, path, false)) - return false; - } - - for (auto it = parser.structs_.vec.begin(); - it != parser.structs_.vec.end(); ++it) { - std::string declcode; - python::GenStruct(**it, &declcode, parser.root_struct_def_); - if (!python::SaveType(parser, **it, declcode, path, true)) - return false; - } - - return true; +bool GeneratePython(const Parser &parser, const std::string &path, + const std::string &file_name) { + python::PythonGenerator generator(parser, path, file_name); + return generator.generate(); } } // namespace flatbuffers