#include "flatbuffers/flatbuffers.h"
#include "flatbuffers/idl.h"
#include "flatbuffers/util.h"
+ #include "flatbuffers/code_generators.h"
namespace flatbuffers {
- namespace cpp {
- // Ensure that a type is prefixed with its namespace whenever it is used
- // outside of its namespace.
- static std::string WrapInNameSpace(const Parser &parser, const Namespace *ns,
- const std::string &name) {
- if (parser.namespaces_.back() != ns) {
- std::string qualified_name;
- for (auto it = ns->components.begin();
- it != ns->components.end(); ++it) {
- qualified_name += *it + "::";
- }
- return qualified_name + name;
- } else {
- return name;
+ struct IsAlnum {
+ bool operator()(char c) {
+ return !isalnum(c);
}
- }
+ };
- static std::string WrapInNameSpace(const Parser &parser,
- const Definition &def) {
- return WrapInNameSpace(parser, def.defined_namespace, def.name);
+ static std::string GeneratedFileName(const std::string &path,
+ const std::string &file_name) {
+ return path + file_name + "_generated.h";
}
- // Translates a qualified name in flatbuffer text format to the same name in
- // the equivalent C++ namepsace.
- static std::string TranslateNameSpace(const std::string &qualified_name) {
- std::string cpp_qualified_name = qualified_name;
- size_t start_pos = 0;
- while((start_pos = cpp_qualified_name.find(".", start_pos)) !=
- std::string::npos) {
- cpp_qualified_name.replace(start_pos, 1, "::");
+ 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() {
+ if (IsEverythingGenerated()) return true;
+
+ std::string code;
+ code = code + "// " + FlatBuffersGeneratedWarning();
+
+ // 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";
+
+ 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(!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) {
+ SetNameSpace(struct_def.defined_namespace, &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) {
+ SetNameSpace((**it).defined_namespace, &code);
+ GenEnum(**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) {
+ SetNameSpace(struct_def.defined_namespace, &code);
+ GenStruct(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) {
+ SetNameSpace(struct_def.defined_namespace, &code);
+ GenTable(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) {
+ SetNameSpace(enum_def.defined_namespace, &code);
+ GenEnumPost(enum_def, &code);
+ }
+ }
+
+ // Generate convenient global helper functions:
+ if (parser_.root_struct_def_) {
+ SetNameSpace((*parser_.root_struct_def_).defined_namespace, &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";
+ 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";
+ }
+
+ assert(cur_name_space_);
+ SetNameSpace(nullptr, &code);
+
+ // Close the include guard.
+ code += "#endif // " + include_guard + "\n";
+
+ return SaveFile(GeneratedFileName(path_, file_name_).c_str(), code, false);
}
- return cpp_qualified_name;
- }
+ private:
+ // This tracks the current namespace so we can insert namespace declarations.
+ const Namespace *cur_name_space_ = nullptr;
++<<<<<<< HEAD
+// Return a C++ type from the table in idl.h
+static std::string GenTypeBasic(const Parser &parser, const Type &type,
+ bool user_facing_type) {
+ static const char *ctypename[] = {
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
+ #CTYPE,
+ FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+ #undef FLATBUFFERS_TD
+ };
+ if (user_facing_type) {
+ if (type.enum_def) return WrapInNameSpace(parser, *type.enum_def);
+ if (type.base_type == BASE_TYPE_BOOL) return "bool";
+ }
+ return ctypename[type.base_type];
+}
+
+static std::string GenTypeWire(const Parser &parser, const Type &type,
+ const char *postfix, bool user_facing_type);
+
+// Return a C++ pointer type, specialized to the actual struct/table types,
+// and vector element types.
+static std::string GenTypePointer(const Parser &parser, const Type &type) {
+ switch (type.base_type) {
+ case BASE_TYPE_STRING:
+ return "flatbuffers::String";
+ case BASE_TYPE_VECTOR:
+ return "flatbuffers::Vector<" +
+ GenTypeWire(parser, type.VectorType(), "", false) + ">";
+ case BASE_TYPE_STRUCT: {
+ return WrapInNameSpace(parser, *type.struct_def);
+ }
+ case BASE_TYPE_UNION:
++=======
+ const Namespace *CurrentNameSpace() { return cur_name_space_; }
+
+ // Translates a qualified name in flatbuffer text format to the same name in
+ // the equivalent C++ namespace.
+ static std::string TranslateNameSpace(const std::string &qualified_name) {
+ std::string cpp_qualified_name = qualified_name;
+ size_t start_pos = 0;
+ while ((start_pos = cpp_qualified_name.find(".", start_pos)) !=
+ std::string::npos) {
+ cpp_qualified_name.replace(start_pos, 1, "::");
+ }
+ return cpp_qualified_name;
+ }
+
+ // Return a C++ type from the table in idl.h
+ std::string GenTypeBasic(const Type &type, bool user_facing_type) {
+ static const char *ctypename[] = {
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) #CTYPE,
+ FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+ #undef FLATBUFFERS_TD
+ };
+ if (user_facing_type) {
+ if (type.enum_def) return WrapInNameSpace(*type.enum_def);
+ if (type.base_type == BASE_TYPE_BOOL) return "bool";
+ }
+ return ctypename[type.base_type];
+ }
+
+ // Return a C++ pointer type, specialized to the actual struct/table types,
+ // and vector element types.
+ std::string GenTypePointer(const Type &type) {
+ switch (type.base_type) {
+ case BASE_TYPE_STRING:
+ return "flatbuffers::String";
+ case BASE_TYPE_VECTOR:
+ return "flatbuffers::Vector<" +
+ GenTypeWire(type.VectorType(), "", false) + ">";
+ case BASE_TYPE_STRUCT: {
+ return WrapInNameSpace(*type.struct_def);
+ }
+ case BASE_TYPE_UNION:
++>>>>>>> 48f37f9e0a04f2b60046dda7fef20a8b0ebc1a70
// fall through
- default:
- return "void";
+ default:
+ return "void";
+ }
}
- }
++<<<<<<< HEAD
+// Return a C++ type for any type (scalar/pointer) specifically for
+// building a flatbuffer.
+static std::string GenTypeWire(const Parser &parser, const Type &type,
+ const char *postfix, bool user_facing_type) {
+ return IsScalar(type.base_type)
+ ? GenTypeBasic(parser, type, user_facing_type) + postfix
+ : IsStruct(type)
+ ? "const " + GenTypePointer(parser, type) + " *"
+ : "flatbuffers::Offset<" + GenTypePointer(parser, type) + ">" + postfix;
+}
++=======
+ // Return a C++ type for any type (scalar/pointer) specifically for
+ // building a flatbuffer.
+ std::string GenTypeWire(const Type &type,
+ const char *postfix, bool user_facing_type) {
+ return IsScalar(type.base_type)
+ ? GenTypeBasic(type, user_facing_type) + postfix
+ : IsStruct(type)
+ ? "const " + GenTypePointer(type) + " *"
+ : "flatbuffers::Offset<" + GenTypePointer(type) +
+ ">" + postfix;
+ }
++>>>>>>> 48f37f9e0a04f2b60046dda7fef20a8b0ebc1a70
- // Return a C++ type for any type (scalar/pointer) that reflects its
- // serialized size.
- static std::string GenTypeSize(const Parser &parser, const Type &type) {
- return IsScalar(type.base_type)
- ? GenTypeBasic(parser, type, false)
- : IsStruct(type)
- ? GenTypePointer(parser, type)
- : "flatbuffers::uoffset_t";
- }
+ // Return a C++ type for any type (scalar/pointer) that reflects its
+ // serialized size.
+ std::string GenTypeSize(const Type &type) {
+ return IsScalar(type.base_type)
+ ? GenTypeBasic(type, false)
+ : IsStruct(type) ? GenTypePointer(type)
+ : "flatbuffers::uoffset_t";
+ }
++<<<<<<< HEAD
+// Return a C++ type for any type (scalar/pointer) specifically for
+// using a flatbuffer.
+static std::string GenTypeGet(const Parser &parser, const Type &type,
+ const char *afterbasic, const char *beforeptr,
+ const char *afterptr, bool user_facing_type) {
+ return IsScalar(type.base_type)
+ ? GenTypeBasic(parser, type, user_facing_type) + afterbasic
+ : beforeptr + GenTypePointer(parser, type) + afterptr;
+}
++=======
+ // Return a C++ type for any type (scalar/pointer) specifically for
+ // using a flatbuffer.
+ std::string GenTypeGet(const Type &type,
+ const char *afterbasic, const char *beforeptr,
+ const char *afterptr, bool user_facing_type) {
+ return IsScalar(type.base_type)
+ ? GenTypeBasic(type, user_facing_type) + afterbasic
+ : beforeptr + GenTypePointer(type) + afterptr;
+ }
++>>>>>>> 48f37f9e0a04f2b60046dda7fef20a8b0ebc1a70
- static std::string GenEnumDecl(const EnumDef &enum_def,
- const GeneratorOptions &opts) {
- return (opts.scoped_enums ? "enum class " : "enum ") + enum_def.name;
- }
+ static std::string GenEnumDecl(const EnumDef &enum_def,
+ const IDLOptions &opts) {
+ return (opts.scoped_enums ? "enum class " : "enum ") + enum_def.name;
+ }
- static std::string GenEnumVal(const EnumDef &enum_def, const EnumVal &enum_val,
- const GeneratorOptions &opts) {
- return opts.prefixed_enums ? enum_def.name + "_" + enum_val.name
- : enum_val.name;
- }
+ static std::string GenEnumVal(const EnumDef &enum_def,
+ const std::string &enum_val,
+ const IDLOptions &opts) {
+ return opts.prefixed_enums ? enum_def.name + "_" + enum_val : enum_val;
+ }
- static std::string GetEnumVal(const EnumDef &enum_def, const EnumVal &enum_val,
- const GeneratorOptions &opts) {
- if (opts.scoped_enums) {
+ static std::string GetEnumVal(const EnumDef &enum_def,
+ const EnumVal &enum_val,
+ const IDLOptions &opts) {
+ if (opts.scoped_enums) {
return enum_def.name + "::" + enum_val.name;
- } else if (opts.prefixed_enums) {
+ } else if (opts.prefixed_enums) {
return enum_def.name + "_" + enum_val.name;
- } else {
+ } else {
return enum_val.name;
+ }
}
- }
- // Generate an enum declaration and an enum string lookup table.
- static void GenEnum(const Parser &parser, EnumDef &enum_def,
- std::string *code_ptr, std::string *code_ptr_post,
- const GeneratorOptions &opts) {
- if (enum_def.generated) return;
- std::string &code = *code_ptr;
- std::string &code_post = *code_ptr_post;
- GenComment(enum_def.doc_comment, code_ptr, nullptr);
- code += GenEnumDecl(enum_def, opts);
- if (opts.scoped_enums)
- code += " : " + GenTypeBasic(parser, enum_def.underlying_type, false);
- code += " {\n";
- for (auto it = enum_def.vals.vec.begin();
- it != enum_def.vals.vec.end();
- ++it) {
- auto &ev = **it;
- GenComment(ev.doc_comment, code_ptr, nullptr, " ");
- code += " " + GenEnumVal(enum_def, ev, opts) + " = ";
- code += NumToString(ev.value);
- code += (it + 1) != enum_def.vals.vec.end() ? ",\n" : "\n";
- }
- code += "};\n\n";
-
- // Generate a generate string table for enum values.
- // Problem is, if values are very sparse that could generate really big
- // tables. Ideally in that case we generate a map lookup instead, but for
- // the moment we simply don't output a table at all.
- auto range = enum_def.vals.vec.back()->value -
- enum_def.vals.vec.front()->value + 1;
- // Average distance between values above which we consider a table
- // "too sparse". Change at will.
- static const int kMaxSparseness = 5;
- if (range / static_cast<int64_t>(enum_def.vals.vec.size()) < kMaxSparseness) {
- code += "inline const char **EnumNames" + enum_def.name + "() {\n";
- code += " static const char *names[] = { ";
- auto val = enum_def.vals.vec.front()->value;
- for (auto it = enum_def.vals.vec.begin();
- it != enum_def.vals.vec.end();
+ std::string EnumSignature(EnumDef &enum_def) {
+ return "inline bool Verify" + enum_def.name +
+ "(flatbuffers::Verifier &verifier, " + "const void *union_obj, " +
+ enum_def.name + " type)";
+ }
+
+ // Generate an enum declaration and an enum string lookup table.
+ void GenEnum(EnumDef &enum_def, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ GenComment(enum_def.doc_comment, code_ptr, nullptr);
+ code += GenEnumDecl(enum_def, parser_.opts);
+ 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();
++it) {
++<<<<<<< HEAD
+ while (val++ != (*it)->value) code += "\"\", ";
+ code += "\"" + (*it)->name + "\", ";
+ }
+ code += "nullptr };\n return names;\n}\n\n";
+ code += "inline const char *EnumName" + enum_def.name;
+ code += "(" + enum_def.name + " e) { return EnumNames" + enum_def.name;
+ code += "()[static_cast<int>(e)";
+ if (enum_def.vals.vec.front()->value) {
+ code += " - static_cast<int>(";
+ code += GetEnumVal(enum_def, *enum_def.vals.vec.front(), opts) +")";
+ }
+ code += "]; }\n\n";
++=======
+ auto &ev = **it;
+ GenComment(ev.doc_comment, code_ptr, nullptr, " ");
+ code += " " + GenEnumVal(enum_def, ev.name, parser_.opts) + " = ";
+ code += NumToString(ev.value) + ",\n";
+ minv = !minv || minv->value > ev.value ? &ev : minv;
+ maxv = !maxv || maxv->value < ev.value ? &ev : maxv;
+ anyv |= ev.value;
+ }
+ 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"))
+ code += "DEFINE_BITMASK_OPERATORS(" + enum_def.name + ", " +
+ GenTypeBasic(enum_def.underlying_type, false) + ")\n";
+ code += "\n";
+
+ // Generate a generate string table for enum values.
+ // Problem is, if values are very sparse that could generate really big
+ // tables. Ideally in that case we generate a map lookup instead, but for
+ // the moment we simply don't output a table at all.
+ auto range =
+ enum_def.vals.vec.back()->value - enum_def.vals.vec.front()->value + 1;
+ // Average distance between values above which we consider a table
+ // "too sparse". Change at will.
+ static const int kMaxSparseness = 5;
+ if (range / static_cast<int64_t>(enum_def.vals.vec.size()) <
+ kMaxSparseness) {
+ code += "inline const char **EnumNames" + enum_def.name + "() {\n";
+ code += " static const char *names[] = { ";
+ auto val = enum_def.vals.vec.front()->value;
+ for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end();
+ ++it) {
+ while (val++ != (*it)->value) code += "\"\", ";
+ code += "\"" + (*it)->name + "\", ";
+ }
+ code += "nullptr };\n return names;\n}\n\n";
+ code += "inline const char *EnumName" + enum_def.name;
+ code += "(" + enum_def.name + " e) { return EnumNames" + enum_def.name;
+ code += "()[static_cast<int>(e)";
+ if (enum_def.vals.vec.front()->value) {
+ code += " - static_cast<int>(";
+ code +=
+ GetEnumVal(enum_def, *enum_def.vals.vec.front(), parser_.opts) + ")";
+ }
+ code += "]; }\n\n";
+ }
+
+ if (enum_def.is_union) {
+ code += EnumSignature(enum_def) + ";\n\n";
+ }
++>>>>>>> 48f37f9e0a04f2b60046dda7fef20a8b0ebc1a70
}
- if (enum_def.is_union) {
+ void GenEnumPost(EnumDef &enum_def, std::string *code_ptr_post) {
// Generate a verifier function for this union that can be called by the
// table verifier functions. It uses a switch case to select a specific
// verifier function to call, this should be safe even if the union type
}
code_post += " default: return false;\n }\n}\n\n";
}
- }
++<<<<<<< HEAD
+// Generates a value with optionally a cast applied if the field has a
+// different underlying type from its interface type (currently only the
+// case for enums. "from" specify the direction, true meaning from the
+// underlying type to the interface type.
+std::string GenUnderlyingCast(const Parser &parser, const FieldDef &field,
+ bool from, const std::string &val) {
+ return (field.value.type.enum_def && IsScalar(field.value.type.base_type)) ||
+ field.value.type.base_type == BASE_TYPE_BOOL
+ ? "static_cast<" + GenTypeBasic(parser, field.value.type, from) + ">(" +
+ val + ")"
+ : val;
+}
+
+std::string GenFieldOffsetName(const FieldDef &field) {
+ std::string uname = field.name;
+ std::transform(uname.begin(), uname.end(), uname.begin(), ::toupper);
+ return "VT_" + uname;
+}
+
+// Generate an accessor struct, builder structs & function for a table.
+static void GenTable(const Parser &parser, StructDef &struct_def,
+ const GeneratorOptions &opts, std::string *code_ptr) {
+ if (struct_def.generated) return;
+ std::string &code = *code_ptr;
+
+ // Generate an accessor struct, with methods of the form:
+ // type name() const { return GetField<type>(offset, defaultval); }
+ GenComment(struct_def.doc_comment, code_ptr, nullptr);
+ code += "struct " + struct_def.name;
+ code += " FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table";
+ code += " {\n";
+ // Generate field id constants.
+ code += " enum {\n";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end();
+ ++it) {
+ auto &field = **it;
+ if (!field.deprecated) { // Deprecated fields won't be accessible.
+ code += " " + GenFieldOffsetName(field) + " = ";
+ code += NumToString(field.value.offset) + ",\n";
+ }
+ }
+ code += " };\n";
+ // Generate the accessors.
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end();
+ ++it) {
+ auto &field = **it;
+ if (!field.deprecated) { // Deprecated fields won't be accessible.
+ auto is_scalar = IsScalar(field.value.type.base_type);
+ GenComment(field.doc_comment, code_ptr, nullptr, " ");
+ code += " " + GenTypeGet(parser, field.value.type, " ", "const ", " *",
+ true);
+ code += field.name + "() const { return ";
+ // Call a different accessor for pointers, that indirects.
+ auto accessor = is_scalar
+ ? "GetField<"
+ : (IsStruct(field.value.type) ? "GetStruct<" : "GetPointer<");
+ auto offsetstr = GenFieldOffsetName(field);
+ auto call =
+ accessor +
+ GenTypeGet(parser, field.value.type, "", "const ", " *", false) +
+ ">(" + offsetstr;
+ // Default value as second arg for non-pointer types.
+ if (IsScalar(field.value.type.base_type))
+ call += ", " + field.value.constant;
+ call += ")";
+ code += GenUnderlyingCast(parser, field, true, call);
+ code += "; }\n";
+ if (opts.mutable_buffer) {
+ if (is_scalar) {
+ code += " bool mutate_" + field.name + "(";
+ code += GenTypeBasic(parser, field.value.type, true);
+ code += " _" + field.name + ") { return SetField(" + offsetstr + ", ";
+ code += GenUnderlyingCast(parser, field, false, "_" + field.name);
+ code += "); }\n";
+ } else {
+ auto type = GenTypeGet(parser, field.value.type, " ", "", " *", true);
+ code += " " + type + "mutable_" + field.name + "() { return ";
+ code += GenUnderlyingCast(parser, field, true,
+ accessor + type + ">(" + offsetstr + ")");
+ code += "; }\n";
++=======
+ // Generates a value with optionally a cast applied if the field has a
+ // different underlying type from its interface type (currently only the
+ // case for enums. "from" specify the direction, true meaning from the
+ // underlying type to the interface type.
+ std::string GenUnderlyingCast(const FieldDef &field, bool from,
+ const std::string &val) {
+ if (from && field.value.type.base_type == BASE_TYPE_BOOL) {
+ return val + " != 0";
+ } else if ((field.value.type.enum_def &&
+ IsScalar(field.value.type.base_type)) ||
+ field.value.type.base_type == BASE_TYPE_BOOL) {
+ return "static_cast<" + GenTypeBasic(field.value.type, from) + ">(" +
+ val + ")";
+ } else {
+ return val;
+ }
+ }
+
+ std::string GenFieldOffsetName(const FieldDef &field) {
+ std::string uname = field.name;
+ std::transform(uname.begin(), uname.end(), uname.begin(), ::toupper);
+ return "VT_" + uname;
+ }
+
+ void GenFullyQualifiedNameGetter(const std::string &name,
+ std::string &code) {
+ if (parser_.opts.generate_name_strings) {
+ code +=
+ " static FLATBUFFERS_CONSTEXPR const char *GetFullyQualifiedName() "
+ "{\n";
+ code += " return \"" +
+ parser_.namespaces_.back()->GetFullyQualifiedName(name) + "\";\n";
+ code += " }\n";
+ }
+ }
+
+ std::string GenDefaultConstant(const FieldDef &field) {
+ return field.value.type.base_type == BASE_TYPE_FLOAT
+ ? field.value.constant + "f"
+ : field.value.constant;
+ }
+
+ // Generate an accessor struct, builder structs & function for a table.
+ void GenTable(StructDef &struct_def, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ // Generate an accessor struct, with methods of the form:
+ // type name() const { return GetField<type>(offset, defaultval); }
+ GenComment(struct_def.doc_comment, code_ptr, nullptr);
+ code += "struct " + struct_def.name;
+ code += " FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table";
+ code += " {\n";
+ // Generate GetFullyQualifiedName
+ GenFullyQualifiedNameGetter(struct_def.name, code);
+ // Generate field id constants.
+ if (struct_def.fields.vec.size() > 0) {
+ code += " enum {\n";
+ bool is_first_field =
+ true; // track the first field that's not deprecated
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (!field.deprecated) { // Deprecated fields won't be accessible.
+ if (!is_first_field) {
+ // Add trailing comma and newline to previous element. Don't add
+ // trailing comma to
+ // last element since older versions of gcc complain about this.
+ code += ",\n";
+ } else {
+ is_first_field = false;
+ }
+ code += " " + GenFieldOffsetName(field) + " = ";
+ code += NumToString(field.value.offset);
++>>>>>>> 48f37f9e0a04f2b60046dda7fef20a8b0ebc1a70
}
}
- auto nested = field.attributes.Lookup("nested_flatbuffer");
- if (nested) {
- std::string qualified_name =
- parser.namespaces_.back()->GetFullyQualifiedName(nested->constant);
- auto nested_root = parser.structs_.Lookup(qualified_name);
- assert(nested_root); // Guaranteed to exist by parser.
- (void)nested_root;
- std::string cpp_qualified_name = TranslateNameSpace(qualified_name);
-
- code += " const " + cpp_qualified_name + " *" + field.name;
- code += "_nested_root() const { return flatbuffers::GetRoot<";
- code += cpp_qualified_name + ">(" + field.name + "()->Data()); }\n";
- }
- // Generate a comparison function for this field if it is a key.
- if (field.key) {
- code += " bool KeyCompareLessThan(const " + struct_def.name;
- code += " *o) const { return ";
- if (field.value.type.base_type == BASE_TYPE_STRING) code += "*";
- code += field.name + "() < ";
- if (field.value.type.base_type == BASE_TYPE_STRING) code += "*";
- code += "o->" + field.name + "(); }\n";
- code += " int KeyCompareWithValue(";
- if (field.value.type.base_type == BASE_TYPE_STRING) {
- code += "const char *val) const { return strcmp(" + field.name;
- code += "()->c_str(), val); }\n";
- } else {
- if (opts.scoped_enums &&
- field.value.type.enum_def &&
- IsScalar(field.value.type.base_type)) {
- code += GenTypeGet(parser, field.value.type, " ", "const ", " *",
- true);
+ code += "\n };\n";
+ }
+ // Generate the accessors.
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (!field.deprecated) { // Deprecated fields won't be accessible.
+ auto is_scalar = IsScalar(field.value.type.base_type);
+ GenComment(field.doc_comment, code_ptr, nullptr, " ");
+ code += " " +
+ GenTypeGet(field.value.type, " ", "const ", " *", true);
+ code += field.name + "() const { return ";
+ // Call a different accessor for pointers, that indirects.
+ auto accessor =
+ is_scalar
+ ? "GetField<"
+ : (IsStruct(field.value.type) ? "GetStruct<" : "GetPointer<");
+ auto offsetstr = GenFieldOffsetName(field);
+ auto call = accessor + GenTypeGet(field.value.type, "",
+ "const ", " *", false) +
+ ">(" + offsetstr;
+ // Default value as second arg for non-pointer types.
+ if (IsScalar(field.value.type.base_type))
+ call += ", " + GenDefaultConstant(field);
+ call += ")";
+ code += GenUnderlyingCast(field, true, call);
+ code += "; }\n";
+ if (parser_.opts.mutable_buffer) {
+ if (is_scalar) {
+ code += " bool mutate_" + field.name + "(";
+ code += GenTypeBasic(field.value.type, true);
+ code +=
+ " _" + field.name + ") { return SetField(" + offsetstr + ", ";
+ code += GenUnderlyingCast(field, false, "_" + field.name);
+ code += "); }\n";
+ } else {
+ auto type =
+ GenTypeGet(field.value.type, " ", "", " *", true);
+ code += " " + type + "mutable_" + field.name + "() { return ";
+ code += GenUnderlyingCast(field, true,
+ accessor + type + ">(" + offsetstr + ")");
+ code += "; }\n";
+ }
+ }
+ auto nested = field.attributes.Lookup("nested_flatbuffer");
+ if (nested) {
+ std::string qualified_name =
+ parser_.namespaces_.back()->GetFullyQualifiedName(
+ nested->constant);
+ auto nested_root = parser_.structs_.Lookup(qualified_name);
+ assert(nested_root); // Guaranteed to exist by parser.
+ (void)nested_root;
+ std::string cpp_qualified_name = TranslateNameSpace(qualified_name);
+
+ code += " const " + cpp_qualified_name + " *" + field.name;
+ code += "_nested_root() const { return flatbuffers::GetRoot<";
+ code += cpp_qualified_name + ">(" + field.name + "()->Data()); }\n";
+ }
+ // Generate a comparison function for this field if it is a key.
+ if (field.key) {
+ code += " bool KeyCompareLessThan(const " + struct_def.name;
+ code += " *o) const { return ";
+ if (field.value.type.base_type == BASE_TYPE_STRING) code += "*";
+ code += field.name + "() < ";
+ if (field.value.type.base_type == BASE_TYPE_STRING) code += "*";
+ code += "o->" + field.name + "(); }\n";
+ code += " int KeyCompareWithValue(";
+ if (field.value.type.base_type == BASE_TYPE_STRING) {
+ code += "const char *val) const { return strcmp(" + field.name;
+ code += "()->c_str(), val); }\n";
} else {
- code += GenTypeBasic(parser, field.value.type, false);
+ if (parser_.opts.scoped_enums && field.value.type.enum_def &&
+ IsScalar(field.value.type.base_type)) {
+ code += GenTypeGet(field.value.type, " ", "const ", " *", true);
+ } else {
+ code += GenTypeBasic(field.value.type, false);
+ }
+ code += " val) const { return " + field.name + "() < val ? -1 : ";
+ code += field.name + "() > val; }\n";
}
- code += " val) const { return " + field.name + "() < val ? -1 : ";
- code += field.name + "() > val; }\n";
}
}
}
++<<<<<<< HEAD
+ }
+ // Generate a verifier function that can check a buffer from an untrusted
+ // source will never cause reads outside the buffer.
+ code += " bool Verify(flatbuffers::Verifier &verifier) const {\n";
+ code += " return VerifyTableStart(verifier)";
+ std::string prefix = " &&\n ";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end();
+ ++it) {
+ auto &field = **it;
+ if (!field.deprecated) {
+ code += prefix + "VerifyField";
+ if (field.required) code += "Required";
+ code += "<" + GenTypeSize(parser, field.value.type);
+ code += ">(verifier, " + GenFieldOffsetName(field) + ")";
+ switch (field.value.type.base_type) {
+ case BASE_TYPE_UNION:
+ code += prefix + "Verify" + field.value.type.enum_def->name;
+ code += "(verifier, " + field.name + "(), " + field.name + "_type())";
+ break;
+ case BASE_TYPE_STRUCT:
+ if (!field.value.type.struct_def->fixed) {
+ code += prefix + "verifier.VerifyTable(" + field.name;
+ code += "())";
+ }
+ break;
+ case BASE_TYPE_STRING:
+ code += prefix + "verifier.Verify(" + field.name + "())";
+ break;
+ case BASE_TYPE_VECTOR:
+ code += prefix + "verifier.Verify(" + field.name + "())";
+ switch (field.value.type.element) {
+ case BASE_TYPE_STRING: {
+ code += prefix + "verifier.VerifyVectorOfStrings(" + field.name;
++=======
+ // Generate a verifier function that can check a buffer from an untrusted
+ // source will never cause reads outside the buffer.
+ code += " bool Verify(flatbuffers::Verifier &verifier) const {\n";
+ code += " return VerifyTableStart(verifier)";
+ std::string prefix = " &&\n ";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (!field.deprecated) {
+ code += prefix + "VerifyField";
+ if (field.required) code += "Required";
+ code += "<" + GenTypeSize(field.value.type);
+ code += ">(verifier, " + GenFieldOffsetName(field) + ")";
+ switch (field.value.type.base_type) {
+ case BASE_TYPE_UNION:
+ code += prefix + "Verify" + field.value.type.enum_def->name;
+ code += "(verifier, " + field.name + "(), " + field.name +
+ UnionTypeFieldSuffix() + "())";
+ break;
+ case BASE_TYPE_STRUCT:
+ if (!field.value.type.struct_def->fixed) {
+ code += prefix + "verifier.VerifyTable(" + field.name;
++>>>>>>> 48f37f9e0a04f2b60046dda7fef20a8b0ebc1a70
code += "())";
- break;
}
- case BASE_TYPE_STRUCT: {
- if (!field.value.type.struct_def->fixed) {
- code += prefix + "verifier.VerifyVectorOfTables(" + field.name;
+ break;
+ case BASE_TYPE_STRING:
+ code += prefix + "verifier.Verify(" + field.name + "())";
+ break;
+ case BASE_TYPE_VECTOR:
+ code += prefix + "verifier.Verify(" + field.name + "())";
+ switch (field.value.type.element) {
+ case BASE_TYPE_STRING: {
+ code += prefix + "verifier.VerifyVectorOfStrings(" + field.name;
code += "())";
+ break;
+ }
+ case BASE_TYPE_STRUCT: {
+ if (!field.value.type.struct_def->fixed) {
+ code +=
+ prefix + "verifier.VerifyVectorOfTables(" + field.name;
+ code += "())";
+ }
+ break;
}
- break;
+ default:
+ break;
}
- default:
- break;
- }
- break;
- default:
- break;
+ break;
+ default:
+ break;
+ }
}
}
- }
- code += prefix + "verifier.EndTable()";
- code += ";\n }\n";
- code += "};\n\n";
+ code += prefix + "verifier.EndTable()";
+ code += ";\n }\n";
+ code += "};\n\n";
- // Generate a builder struct, with methods of the form:
- // void add_name(type name) { fbb_.AddElement<type>(offset, name, default); }
- code += "struct " + struct_def.name;
- code += "Builder {\n flatbuffers::FlatBufferBuilder &fbb_;\n";
- code += " flatbuffers::uoffset_t start_;\n";
- for (auto it = struct_def.fields.vec.begin();
- it != struct_def.fields.vec.end();
- ++it) {
- auto &field = **it;
- if (!field.deprecated) {
- code += " void add_" + field.name + "(";
- code += GenTypeWire(parser, field.value.type, " ", true) + field.name;
- code += ") { fbb_.Add";
- if (IsScalar(field.value.type.base_type)) {
- code += "Element<" + GenTypeWire(parser, field.value.type, "", false);
- code += ">";
- } else if (IsStruct(field.value.type)) {
- code += "Struct";
- } else {
- code += "Offset";
+ // Generate a builder struct, with methods of the form:
+ // void add_name(type name) { fbb_.AddElement<type>(offset, name, default);
+ // }
+ code += "struct " + struct_def.name;
+ code += "Builder {\n flatbuffers::FlatBufferBuilder &fbb_;\n";
+ code += " flatbuffers::uoffset_t start_;\n";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (!field.deprecated) {
+ code += " void add_" + field.name + "(";
+ code += GenTypeWire(field.value.type, " ", true) + field.name;
+ code += ") { fbb_.Add";
+ if (IsScalar(field.value.type.base_type)) {
+ code += "Element<" + GenTypeWire(field.value.type, "", false);
+ code += ">";
+ } else if (IsStruct(field.value.type)) {
+ code += "Struct";
+ } else {
+ code += "Offset";
+ }
+ code += "(" + struct_def.name + "::" + GenFieldOffsetName(field) + ", ";
+ code += GenUnderlyingCast(field, false, field.name);
+ if (IsScalar(field.value.type.base_type))
+ code += ", " + GenDefaultConstant(field);
+ code += "); }\n";
}
++<<<<<<< HEAD
+ code += "(" + struct_def.name + "::" + GenFieldOffsetName(field) + ", ";
+ code += GenUnderlyingCast(parser, field, false, field.name);
+ if (IsScalar(field.value.type.base_type))
+ code += ", " + field.value.constant;
+ code += "); }\n";
+ }
+ }
+ code += " " + struct_def.name;
+ code += "Builder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) ";
+ code += "{ start_ = fbb_.StartTable(); }\n";
+ code += " " + struct_def.name + "Builder &operator=(const ";
+ code += struct_def.name + "Builder &);\n";
+ code += " flatbuffers::Offset<" + struct_def.name;
+ code += "> Finish() {\n auto o = flatbuffers::Offset<" + struct_def.name;
+ code += ">(fbb_.EndTable(start_, ";
+ code += NumToString(struct_def.fields.vec.size()) + "));\n";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end();
+ ++it) {
+ auto &field = **it;
+ if (!field.deprecated && field.required) {
+ code += " fbb_.Required(o, ";
+ code += struct_def.name + "::" + GenFieldOffsetName(field);
+ code += "); // " + field.name + "\n";
++=======
}
- }
- code += " return o;\n }\n};\n\n";
+ code += " " + struct_def.name;
+ code += "Builder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) ";
+ code += "{ start_ = fbb_.StartTable(); }\n";
+ code += " " + struct_def.name + "Builder &operator=(const ";
+ code += struct_def.name + "Builder &);\n";
+ code += " flatbuffers::Offset<" + struct_def.name;
+ code += "> Finish() {\n auto o = flatbuffers::Offset<" + struct_def.name;
+ code += ">(fbb_.EndTable(start_, ";
+ code += NumToString(struct_def.fields.vec.size()) + "));\n";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (!field.deprecated && field.required) {
+ code += " fbb_.Required(o, ";
+ code += struct_def.name + "::" + GenFieldOffsetName(field);
+ code += "); // " + field.name + "\n";
+ }
++>>>>>>> 48f37f9e0a04f2b60046dda7fef20a8b0ebc1a70
+ }
+ code += " return o;\n }\n};\n\n";
- // Generate a convenient CreateX function that uses the above builder
- // to create a table in one go.
- code += "inline flatbuffers::Offset<" + struct_def.name + "> Create";
- code += struct_def.name;
- code += "(flatbuffers::FlatBufferBuilder &_fbb";
- for (auto it = struct_def.fields.vec.begin();
- it != struct_def.fields.vec.end();
- ++it) {
- auto &field = **it;
- if (!field.deprecated) {
- code += ",\n " + GenTypeWire(parser, field.value.type, " ", true);
- code += field.name + " = ";
- if (field.value.type.enum_def && IsScalar(field.value.type.base_type)) {
- auto ev = field.value.type.enum_def->ReverseLookup(
- static_cast<int>(StringToInt(field.value.constant.c_str())), false);
- if (ev) {
- code += WrapInNameSpace(parser,
- field.value.type.enum_def->defined_namespace,
- GetEnumVal(*field.value.type.enum_def, *ev,
- opts));
+ // Generate a convenient CreateX function that uses the above builder
+ // to create a table in one go.
+ code += "inline flatbuffers::Offset<" + struct_def.name + "> Create";
+ code += struct_def.name;
+ code += "(flatbuffers::FlatBufferBuilder &_fbb";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (!field.deprecated) {
+ code += ",\n " + GenTypeWire(field.value.type, " ", true);
+ code += field.name + " = ";
+ if (field.value.type.enum_def && IsScalar(field.value.type.base_type)) {
+ auto ev = field.value.type.enum_def->ReverseLookup(
+ static_cast<int>(StringToInt(field.value.constant.c_str())),
+ false);
+ if (ev) {
+ code += WrapInNameSpace(
+ field.value.type.enum_def->defined_namespace,
+ GetEnumVal(*field.value.type.enum_def, *ev, parser_.opts));
+ } else {
+ code += GenUnderlyingCast(field, true, field.value.constant);
+ }
+ } else if (field.value.type.base_type == BASE_TYPE_BOOL) {
+ code += field.value.constant == "0" ? "false" : "true";
} else {
- code += GenUnderlyingCast(parser, field, true, field.value.constant);
+ code += GenDefaultConstant(field);
}
++<<<<<<< HEAD
+ } else if (field.value.type.base_type == BASE_TYPE_BOOL) {
+ code += field.value.constant == "0" ? "false" : "true";
+ } else {
+ code += field.value.constant;
++=======
++>>>>>>> 48f37f9e0a04f2b60046dda7fef20a8b0ebc1a70
}
}
- }
- code += ") {\n " + struct_def.name + "Builder builder_(_fbb);\n";
- for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1;
- size;
- size /= 2) {
- for (auto it = struct_def.fields.vec.rbegin();
- it != struct_def.fields.vec.rend();
- ++it) {
- auto &field = **it;
- if (!field.deprecated &&
- (!struct_def.sortbysize ||
- size == SizeOf(field.value.type.base_type))) {
- code += " builder_.add_" + field.name + "(" + field.name + ");\n";
+ code += ") {\n " + struct_def.name + "Builder builder_(_fbb);\n";
+ for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1;
+ size; size /= 2) {
+ for (auto it = struct_def.fields.vec.rbegin();
+ it != struct_def.fields.vec.rend(); ++it) {
+ auto &field = **it;
+ if (!field.deprecated && (!struct_def.sortbysize ||
+ size == SizeOf(field.value.type.base_type))) {
+ code += " builder_.add_" + field.name + "(" + field.name + ");\n";
+ }
}
}
+ code += " return builder_.Finish();\n}\n\n";
}
- code += " return builder_.Finish();\n}\n\n";
- }
++<<<<<<< HEAD
+static void GenPadding(const FieldDef &field,
+ const std::function<void (int bits)> &f) {
+ if (field.padding) {
+ for (int i = 0; i < 4; i++)
+ if (static_cast<int>(field.padding) & (1 << i))
+ f((1 << i) * 8);
+ assert(!(field.padding & ~0xF));
+ }
+}
+
+// Generate an accessor struct with constructor for a flatbuffers struct.
+static void GenStruct(const Parser &parser, StructDef &struct_def,
+ const GeneratorOptions &opts, std::string *code_ptr) {
+ if (struct_def.generated) return;
+ std::string &code = *code_ptr;
+
+ // Generate an accessor struct, with private variables of the form:
+ // type name_;
+ // Generates manual padding and alignment.
+ // Variables are private because they contain little endian data on all
+ // platforms.
+ GenComment(struct_def.doc_comment, code_ptr, nullptr);
+ code += "MANUALLY_ALIGNED_STRUCT(" + NumToString(struct_def.minalign) + ") ";
+ code += struct_def.name + " FLATBUFFERS_FINAL_CLASS {\n private:\n";
+ int padding_id = 0;
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end();
+ ++it) {
+ auto &field = **it;
+ code += " " + GenTypeGet(parser, field.value.type, " ", "", " ", false);
+ code += field.name + "_;\n";
+ GenPadding(field, [&code, &padding_id](int bits) {
+ code += " int" + NumToString(bits) +
+ "_t __padding" + NumToString(padding_id++) + ";\n";
+ });
+ }
+
+ // Generate a constructor that takes all fields as arguments.
+ code += "\n public:\n " + struct_def.name + "(";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end();
+ ++it) {
+ auto &field = **it;
+ if (it != struct_def.fields.vec.begin()) code += ", ";
+ code += GenTypeGet(parser, field.value.type, " ", "const ", " &", true);
+ code += "_" + field.name;
+ }
+ code += ")\n : ";
+ padding_id = 0;
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end();
+ ++it) {
+ auto &field = **it;
+ if (it != struct_def.fields.vec.begin()) code += ", ";
+ code += field.name + "_(";
+ if (IsScalar(field.value.type.base_type)) {
+ code += "flatbuffers::EndianScalar(";
+ code += GenUnderlyingCast(parser, field, false, "_" + field.name);
+ code += "))";
+ } else {
+ code += "_" + field.name + ")";
+ }
+ GenPadding(field, [&code, &padding_id](int bits) {
+ (void)bits;
+ code += ", __padding" + NumToString(padding_id++) + "(0)";
+ });
+ }
+ code += " {";
+ padding_id = 0;
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end();
+ ++it) {
+ auto &field = **it;
+ GenPadding(field, [&code, &padding_id](int bits) {
+ (void)bits;
+ code += " (void)__padding" + NumToString(padding_id++) + ";";
+ });
+ }
+ code += " }\n\n";
+
+ // Generate accessor methods of the form:
+ // type name() const { return flatbuffers::EndianScalar(name_); }
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end();
+ ++it) {
+ auto &field = **it;
+ GenComment(field.doc_comment, code_ptr, nullptr, " ");
+ auto is_scalar = IsScalar(field.value.type.base_type);
+ code += " " + GenTypeGet(parser, field.value.type, " ", "const ", " &",
+ true);
+ code += field.name + "() const { return ";
+ code += GenUnderlyingCast(parser, field, true,
+ is_scalar
+ ? "flatbuffers::EndianScalar(" + field.name + "_)"
+ : field.name + "_");
+ code += "; }\n";
+ if (opts.mutable_buffer) {
+ if (is_scalar) {
+ code += " void mutate_" + field.name + "(";
+ code += GenTypeBasic(parser, field.value.type, true);
+ code += " _" + field.name + ") { flatbuffers::WriteScalar(&";
+ code += field.name + "_, ";
+ code += GenUnderlyingCast(parser, field, false, "_" + field.name);
+ code += "); }\n";
+ } else {
+ code += " ";
+ code += GenTypeGet(parser, field.value.type, "", "", " &", true);
+ code += "mutable_" + field.name + "() { return " + field.name;
+ code += "_; }\n";
+ }
++=======
+ static void GenPadding(const FieldDef &field, std::string &code,
+ int &padding_id,
+ const std::function<void(int bits, std::string &code,
+ int &padding_id)> &f) {
+ if (field.padding) {
+ for (int i = 0; i < 4; i++)
+ if (static_cast<int>(field.padding) & (1 << i))
+ f((1 << i) * 8, code, padding_id);
+ assert(!(field.padding & ~0xF));
++>>>>>>> 48f37f9e0a04f2b60046dda7fef20a8b0ebc1a70
}
}
- code += "};\nSTRUCT_END(" + struct_def.name + ", ";
- code += NumToString(struct_def.bytesize) + ");\n\n";
- }
- void GenerateNestedNameSpaces(Namespace *ns, std::string *code_ptr) {
- for (auto it = ns->components.begin(); it != ns->components.end(); ++it) {
- *code_ptr += "namespace " + *it + " {\n";
+ static void PaddingDefinition(int bits, std::string &code, int &padding_id) {
+ code += " int" + NumToString(bits) + "_t __padding" +
+ NumToString(padding_id++) + ";\n";
}
- }
- void CloseNestedNameSpaces(Namespace *ns, std::string *code_ptr) {
- for (auto it = ns->components.rbegin(); it != ns->components.rend(); ++it) {
- *code_ptr += "} // namespace " + *it + "\n";
+ static void PaddingDeclaration(int bits, std::string &code, int &padding_id) {
+ (void)bits;
+ code += " (void)__padding" + NumToString(padding_id++) + ";";
}
- }
-
- } // namespace cpp
- // 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,
- const GeneratorOptions &opts) {
- using namespace cpp;
-
- // Generate code for all the enum declarations.
- std::string enum_code, enum_code_post;
- for (auto it = parser.enums_.vec.begin();
- it != parser.enums_.vec.end(); ++it) {
- GenEnum(parser, **it, &enum_code, &enum_code_post, opts);
- }
-
- // Generate forward declarations for all structs/tables, since they may
- // have circular references.
- std::string forward_decl_code_same_namespace;
- std::string forward_decl_code_other_namespace;
- Namespace *cur_name_space = nullptr;
- for (auto it = parser.structs_.vec.begin();
- it != parser.structs_.vec.end(); ++it) {
- auto &struct_def = **it;
- auto decl = "struct " + struct_def.name + ";\n";
- if (struct_def.defined_namespace == parser.namespaces_.back()) {
- forward_decl_code_same_namespace += decl;
- } else {
- // Wrap this decl in the correct namespace. Only open a namespace if
- // the adjacent one is different.
- // TODO: this could be done more intelligently, by sorting to
- // namespace path and only opening/closing what is necessary, but that's
- // quite a bit more complexity.
- if (cur_name_space != struct_def.defined_namespace) {
- if (cur_name_space) {
- CloseNestedNameSpaces(cur_name_space,
- &forward_decl_code_other_namespace);
- }
- GenerateNestedNameSpaces(struct_def.defined_namespace,
- &forward_decl_code_other_namespace);
- cur_name_space = struct_def.defined_namespace;
- }
- forward_decl_code_other_namespace += decl;
- }
- }
- if (cur_name_space) {
- CloseNestedNameSpaces(cur_name_space,
- &forward_decl_code_other_namespace);
+ static void PaddingInitializer(int bits, std::string &code, int &padding_id) {
+ (void)bits;
+ code += ", __padding" + NumToString(padding_id++) + "(0)";
}
- // 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) {
- if ((**it).fixed) GenStruct(parser, **it, opts, &decl_code);
- }
- for (auto it = parser.structs_.vec.begin();
- it != parser.structs_.vec.end(); ++it) {
- if (!(**it).fixed) GenTable(parser, **it, opts, &decl_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 an accessor struct with constructor for a flatbuffers struct.
+ void GenStruct(StructDef &struct_def, std::string *code_ptr) {
+ if (struct_def.generated) return;
+ std::string &code = *code_ptr;
- // 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(),
- [](char c) { return !isalnum(c); }),
- 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 + "_";
+ // Generate an accessor struct, with private variables of the form:
+ // type name_;
+ // Generates manual padding and alignment.
+ // Variables are private because they contain little endian data on all
+ // platforms.
+ GenComment(struct_def.doc_comment, code_ptr, nullptr);
+ code +=
+ "MANUALLY_ALIGNED_STRUCT(" + NumToString(struct_def.minalign) + ") ";
+ code += struct_def.name + " FLATBUFFERS_FINAL_CLASS {\n private:\n";
+ int padding_id = 0;
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ code += " " + GenTypeGet(field.value.type, " ", "", " ", false);
+ code += field.name + "_;\n";
+ GenPadding(field, code, padding_id, PaddingDefinition);
}
- 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";
+ // Generate GetFullyQualifiedName
+ code += "\n public:\n";
+ GenFullyQualifiedNameGetter(struct_def.name, code);
- if (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";
+ // Generate a constructor that takes all fields as arguments.
+ code += " " + struct_def.name + "(";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (it != struct_def.fields.vec.begin()) code += ", ";
+ code += GenTypeGet(field.value.type, " ", "const ", " &", true);
+ code += "_" + field.name;
}
-
- code += forward_decl_code_other_namespace;
- code += "\n";
-
- GenerateNestedNameSpaces(name_space, &code);
- code += "\n";
-
- code += forward_decl_code_same_namespace;
- code += "\n";
-
- // Output the main declaration code from above.
- code += enum_code;
- code += decl_code;
- code += enum_code_post;
-
- // Generate convenient global helper functions:
- if (parser.root_struct_def_) {
- 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 (opts.mutable_buffer) {
- code += "inline " + name + " *GetMutable";
- code += name;
- code += "(void *buf) { return flatbuffers::GetMutableRoot<";
- code += name + ">(buf); }\n\n";
+ code += ")\n : ";
+ padding_id = 0;
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (it != struct_def.fields.vec.begin()) code += ", ";
+ code += field.name + "_(";
+ if (IsScalar(field.value.type.base_type)) {
+ code += "flatbuffers::EndianScalar(";
+ code += GenUnderlyingCast(field, false, "_" + field.name);
+ code += "))";
+ } else {
+ code += "_" + field.name + ")";
}
+ GenPadding(field, code, padding_id, PaddingInitializer);
+ }
- // 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";
- }
+ code += " {";
+ padding_id = 0;
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ GenPadding(field, code, padding_id, PaddingDeclaration);
+ }
+ code += " }\n\n";
- if (parser.file_extension_.length()) {
- // Return the extension
- code += "inline const char *" + name;
- code += "Extension() { return \"" + parser.file_extension_;
- code += "\"; }\n\n";
+ // Generate accessor methods of the form:
+ // type name() const { return flatbuffers::EndianScalar(name_); }
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ GenComment(field.doc_comment, code_ptr, nullptr, " ");
+ auto is_scalar = IsScalar(field.value.type.base_type);
+ code += " " +
+ GenTypeGet(field.value.type, " ", "const ", " &", true);
+ code += field.name + "() const { return ";
+ code += GenUnderlyingCast(
+ field, true, is_scalar
+ ? "flatbuffers::EndianScalar(" + field.name + "_)"
+ : field.name + "_");
+ code += "; }\n";
+ if (parser_.opts.mutable_buffer) {
+ if (is_scalar) {
+ code += " void mutate_" + field.name + "(";
+ code += GenTypeBasic(field.value.type, true);
+ code += " _" + field.name + ") { flatbuffers::WriteScalar(&";
+ code += field.name + "_, ";
+ code += GenUnderlyingCast(field, false, "_" + field.name);
+ code += "); }\n";
+ } else {
+ code += " ";
+ code += GenTypeGet(field.value.type, "", "", " &", true);
+ code += "mutable_" + field.name + "() { return " + field.name;
+ code += "_; }\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";
-
}
-
- CloseNestedNameSpaces(name_space, &code);
-
- // Close the include guard.
- code += "\n#endif // " + include_guard + "\n";
-
- return code;
+ code += "};\nSTRUCT_END(" + struct_def.name + ", ";
+ code += NumToString(struct_def.bytesize) + ");\n\n";
}
- return std::string();
- }
-
- static std::string GeneratedFileName(const std::string &path,
- const std::string &file_name) {
- return path + file_name + "_generated.h";
- }
+ // Set up the correct namespace. Only open a namespace if
+ // the existing one is different (closing/opening only what is necessary) :
+ //
+ // the file must start and end with an empty (or null) namespace
+ // so that namespaces are properly opened and closed
+ void SetNameSpace(const Namespace *ns, std::string *code_ptr) {
+ if (cur_name_space_ == ns) return;
+ // compute the size of the longest common namespace prefix.
+ // if cur_name_space is A::B::C::D and ns is A::B::E::F::G,
+ // the common prefix is A::B:: and we have old_size = 4, new_size = 5
+ // and common_prefix_size = 2
+ auto old_size =
+ cur_name_space_ == nullptr ? 0 : cur_name_space_->components.size();
+ auto new_size = ns == nullptr ? 0 : ns->components.size();
+ std::vector<std::string>::size_type common_prefix_size = 0;
+ while (common_prefix_size < old_size && common_prefix_size < new_size &&
+ ns->components[common_prefix_size] ==
+ cur_name_space_->components[common_prefix_size])
+ common_prefix_size++;
+ // close cur_name_space in reverse order to reach the common prefix
+ // in the previous example, D then C are closed
+ for (auto j = old_size; j > common_prefix_size; --j)
+ *code_ptr +=
+ "} // namespace " + cur_name_space_->components[j - 1] + "\n";
+ if (old_size != common_prefix_size) *code_ptr += "\n";
+ // open namespace parts to reach the ns namespace
+ // in the previous example, E, then F, then G are opened
+ for (auto j = common_prefix_size; j != new_size; ++j)
+ *code_ptr += "namespace " + ns->components[j] + " {\n";
+ if (new_size != common_prefix_size) *code_ptr += "\n";
+ cur_name_space_ = ns;
+ }
+ };
+ } // namespace cpp
- bool GenerateCPP(const Parser &parser,
- const std::string &path,
- const std::string &file_name,
- const GeneratorOptions &opts) {
- auto code = GenerateCPP(parser, file_name, opts);
- return !code.length() ||
- SaveFile(GeneratedFileName(path, file_name).c_str(), code, false);
+ bool GenerateCPP(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ cpp::CppGenerator generator(parser, path, file_name);
+ return generator.generate();
}
std::string CPPMakeRule(const Parser &parser,