Add flatc '--cpp_std' switch (#5656)

* Add flatc '--cpp_std' switch and sandbox for C++17 code generator

- Added 'flac --cpp_std legacy' for compatibility with old compilers (VS2010);
- Added experimental switch 'flac --cpp_std c++17' for future development;
- Added C++17 sandbox test_cpp17.cpp;
- C++ code generator generates enums with explicit underlying type to avoid problems with the forward and backward schema compatibility;
- Adjusted CMakeLists.txt, CI and generate code scripts to support of introduced '--cpp_std';

* Fix --cpp_std values: c++0x, c++11, c++17

* Add 'cpp::CppStandard' enum

* Add testing engine into test_cpp17

* Rebase to upstream/master

* Set default '--cpp-std C++0x'

* Fix code generation (--cpp_std C++11) in CMakeLists.txt

- Fix dependency declaration of grpctest target

* Revert --cpp-std for the tests from explicit C++11 to flatc default value (C++0x)
This commit is contained in:
Vladimir Glavnyy
2019-12-24 03:13:48 +07:00
committed by Wouter van Oortmerssen
parent 3e8f15df90
commit 44bf719883
41 changed files with 4363 additions and 254 deletions

View File

@@ -20,13 +20,16 @@
#include "flatbuffers/code_generators.h"
#include "flatbuffers/flatbuffers.h"
#include "flatbuffers/flatc.h"
#include "flatbuffers/idl.h"
#include "flatbuffers/util.h"
namespace flatbuffers {
// Pedantic warning free version of toupper().
inline char ToUpper(char c) { return static_cast<char>(::toupper(c)); }
inline char ToUpper(char c) {
return static_cast<char>(::toupper(static_cast<unsigned char>(c)));
}
// Make numerical literal with type-suffix.
// This function is only needed for C++! Other languages do not need it.
@@ -51,12 +54,30 @@ static std::string GeneratedFileName(const std::string &path,
}
namespace cpp {
enum CppStandard { CPP_STD_X0 = 0, CPP_STD_11, CPP_STD_17 };
// Extension of IDLOptions for cpp-generator.
struct IDLOptionsCpp : public IDLOptions {
// All fields start with 'g_' prefix to distinguish from the base IDLOptions.
CppStandard g_cpp_std; // Base version of C++ standard.
bool g_only_fixed_enums; // Generate underlaying type for all enums.
// clang-format off
IDLOptionsCpp(const IDLOptions &opts)
: IDLOptions(opts),
g_cpp_std(CPP_STD_11),
g_only_fixed_enums(true)
{}
// clang-format on
};
class CppGenerator : public BaseGenerator {
public:
CppGenerator(const Parser &parser, const std::string &path,
const std::string &file_name)
const std::string &file_name, IDLOptionsCpp opts)
: BaseGenerator(parser, path, file_name, "", "::"),
cur_name_space_(nullptr),
opts_(opts),
float_const_gen_("std::numeric_limits<double>::",
"std::numeric_limits<float>::", "quiet_NaN()",
"infinity()") {
@@ -196,19 +217,18 @@ class CppGenerator : public BaseGenerator {
auto noext = flatbuffers::StripExtension(it->second);
auto basename = flatbuffers::StripPath(noext);
code_ += "#include \"" + parser_.opts.include_prefix +
(parser_.opts.keep_include_path ? noext : basename) +
"_generated.h\"";
code_ += "#include \"" + opts_.include_prefix +
(opts_.keep_include_path ? noext : basename) + "_generated.h\"";
num_includes++;
}
if (num_includes) code_ += "";
}
void GenExtraIncludes() {
for (std::size_t i = 0; i < parser_.opts.cpp_includes.size(); ++i) {
code_ += "#include \"" + parser_.opts.cpp_includes[i] + "\"";
for (std::size_t i = 0; i < opts_.cpp_includes.size(); ++i) {
code_ += "#include \"" + opts_.cpp_includes[i] + "\"";
}
if (!parser_.opts.cpp_includes.empty()) { code_ += ""; }
if (!opts_.cpp_includes.empty()) { code_ += ""; }
}
std::string EscapeKeyword(const std::string &name) const {
@@ -232,9 +252,7 @@ class CppGenerator : public BaseGenerator {
code_ += "#define " + include_guard;
code_ += "";
if (parser_.opts.gen_nullable) {
code_ += "#pragma clang system_header\n\n";
}
if (opts_.gen_nullable) { code_ += "#pragma clang system_header\n\n"; }
code_ += "#include \"flatbuffers/flatbuffers.h\"";
if (parser_.uses_flexbuffers_) {
@@ -242,7 +260,7 @@ class CppGenerator : public BaseGenerator {
}
code_ += "";
if (parser_.opts.include_dependence_headers) { GenIncludeDependencies(); }
if (opts_.include_dependence_headers) { GenIncludeDependencies(); }
GenExtraIncludes();
FLATBUFFERS_ASSERT(!cur_name_space_);
@@ -255,9 +273,8 @@ class CppGenerator : public BaseGenerator {
if (!struct_def.generated) {
SetNameSpace(struct_def.defined_namespace);
code_ += "struct " + Name(struct_def) + ";";
if (parser_.opts.generate_object_based_api) {
auto nativeName =
NativeName(Name(struct_def), &struct_def, parser_.opts);
if (opts_.generate_object_based_api) {
auto nativeName = NativeName(Name(struct_def), &struct_def, opts_);
if (!struct_def.fixed) { code_ += "struct " + nativeName + ";"; }
}
code_ += "";
@@ -265,14 +282,13 @@ class CppGenerator : public BaseGenerator {
}
// Generate forward declarations for all equal operators
if (parser_.opts.generate_object_based_api && parser_.opts.gen_compare) {
if (opts_.generate_object_based_api && opts_.gen_compare) {
for (auto it = parser_.structs_.vec.begin();
it != parser_.structs_.vec.end(); ++it) {
const auto &struct_def = **it;
if (!struct_def.generated) {
SetNameSpace(struct_def.defined_namespace);
auto nativeName =
NativeName(Name(struct_def), &struct_def, parser_.opts);
auto nativeName = NativeName(Name(struct_def), &struct_def, opts_);
code_ += "bool operator==(const " + nativeName + " &lhs, const " +
nativeName + " &rhs);";
code_ += "bool operator!=(const " + nativeName + " &lhs, const " +
@@ -283,7 +299,7 @@ class CppGenerator : public BaseGenerator {
}
// Generate preablmle code for mini reflection.
if (parser_.opts.mini_reflect != IDLOptions::kNone) {
if (opts_.mini_reflect != IDLOptions::kNone) {
// To break cyclic dependencies, first pre-declare all tables/structs.
for (auto it = parser_.structs_.vec.begin();
it != parser_.structs_.vec.end(); ++it) {
@@ -342,7 +358,7 @@ class CppGenerator : public BaseGenerator {
}
// Generate code for mini reflection.
if (parser_.opts.mini_reflect != IDLOptions::kNone) {
if (opts_.mini_reflect != IDLOptions::kNone) {
// Then the unions/enums that may refer to them.
for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
++it) {
@@ -393,7 +409,7 @@ class CppGenerator : public BaseGenerator {
code_ += "}";
code_ += "";
if (parser_.opts.mutable_buffer) {
if (opts_.mutable_buffer) {
code_ += "inline \\";
code_ += "{{STRUCT_NAME}} *GetMutable{{STRUCT_NAME}}(void *buf) {";
code_ += " return flatbuffers::GetMutableRoot<{{STRUCT_NAME}}>(buf);";
@@ -466,10 +482,10 @@ class CppGenerator : public BaseGenerator {
code_ += "}";
code_ += "";
if (parser_.opts.generate_object_based_api) {
if (opts_.generate_object_based_api) {
// A convenient root unpack function.
auto native_name =
NativeName(WrapInNameSpace(struct_def), &struct_def, parser_.opts);
NativeName(WrapInNameSpace(struct_def), &struct_def, opts_);
code_.SetValue("UNPACK_RETURN",
GenTypeNativePtr(native_name, nullptr, false));
code_.SetValue("UNPACK_TYPE",
@@ -511,6 +527,9 @@ class CppGenerator : public BaseGenerator {
// This tracks the current namespace so we can insert namespace declarations.
const Namespace *cur_name_space_;
const IDLOptionsCpp opts_;
const TypedFloatConstantGenerator float_const_gen_;
const Namespace *CurrentNameSpace() const { return cur_name_space_; }
// Translates a qualified name in flatbuffer text format to the same name in
@@ -606,7 +625,7 @@ class CppGenerator : public BaseGenerator {
}
std::string NullableExtension() {
return parser_.opts.gen_nullable ? " _Nullable " : "";
return opts_.gen_nullable ? " _Nullable " : "";
}
static std::string NativeName(const std::string &name, const StructDef *sd,
@@ -617,12 +636,12 @@ class CppGenerator : public BaseGenerator {
const std::string &PtrType(const FieldDef *field) {
auto attr = field ? field->attributes.Lookup("cpp_ptr_type") : nullptr;
return attr ? attr->constant : parser_.opts.cpp_object_api_pointer_type;
return attr ? attr->constant : opts_.cpp_object_api_pointer_type;
}
const std::string NativeString(const FieldDef *field) {
auto attr = field ? field->attributes.Lookup("cpp_str_type") : nullptr;
auto &ret = attr ? attr->constant : parser_.opts.cpp_object_api_string_type;
auto &ret = attr ? attr->constant : opts_.cpp_object_api_string_type;
if (ret.empty()) { return "std::string"; }
return ret;
}
@@ -631,8 +650,7 @@ class CppGenerator : public BaseGenerator {
auto attr = field
? (field->attributes.Lookup("cpp_str_flex_ctor") != nullptr)
: false;
auto ret =
attr ? attr : parser_.opts.cpp_object_api_string_flexible_constructor;
auto ret = attr ? attr : opts_.cpp_object_api_string_flexible_constructor;
return ret && NativeString(field) !=
"std::string"; // Only for custom string types.
}
@@ -643,7 +661,7 @@ class CppGenerator : public BaseGenerator {
if (ptr_type != "naked") {
return (ptr_type != "default_ptr_type"
? ptr_type
: parser_.opts.cpp_object_api_pointer_type) +
: opts_.cpp_object_api_pointer_type) +
"<" + type + ">";
} else if (is_constructor) {
return "";
@@ -687,9 +705,8 @@ class CppGenerator : public BaseGenerator {
return GenTypeNativePtr(type_name, &field, false);
}
} else {
return GenTypeNativePtr(
NativeName(type_name, type.struct_def, parser_.opts), &field,
false);
return GenTypeNativePtr(NativeName(type_name, type.struct_def, opts_),
&field, false);
}
}
case BASE_TYPE_UNION: {
@@ -711,6 +728,12 @@ class CppGenerator : public BaseGenerator {
return GenTypeBasic(type, user_facing_type) + afterbasic;
} else if (IsArray(type)) {
auto element_type = type.VectorType();
// Check if enum arrays are used in C++ without specifying --scoped-enums
if (IsEnum(element_type) && !opts_.g_only_fixed_enums) {
LogCompilerError(
"--scoped-enums must be enabled to use enum arrays in C++");
FLATBUFFERS_ASSERT(true);
}
return beforeptr +
(IsScalar(element_type.base_type)
? GenTypeBasic(element_type, user_facing_type)
@@ -721,23 +744,16 @@ class CppGenerator : public BaseGenerator {
}
}
std::string GenEnumDecl(const EnumDef &enum_def) const {
const IDLOptions &opts = parser_.opts;
return (opts.scoped_enums ? "enum class " : "enum ") + Name(enum_def);
}
std::string GenEnumValDecl(const EnumDef &enum_def,
const std::string &enum_val) const {
const IDLOptions &opts = parser_.opts;
return opts.prefixed_enums ? Name(enum_def) + "_" + enum_val : enum_val;
return opts_.prefixed_enums ? Name(enum_def) + "_" + enum_val : enum_val;
}
std::string GetEnumValUse(const EnumDef &enum_def,
const EnumVal &enum_val) const {
const IDLOptions &opts = parser_.opts;
if (opts.scoped_enums) {
if (opts_.scoped_enums) {
return Name(enum_def) + "::" + Name(enum_val);
} else if (opts.prefixed_enums) {
} else if (opts_.prefixed_enums) {
return Name(enum_def) + "_" + Name(enum_val);
} else {
return Name(enum_val);
@@ -942,7 +958,7 @@ class CppGenerator : public BaseGenerator {
code_ += " static const int64_t values[] = { {{VALUES}} };";
}
auto has_names =
num_fields && parser_.opts.mini_reflect == IDLOptions::kTypesAndNames;
num_fields && opts_.mini_reflect == IDLOptions::kTypesAndNames;
if (has_names) {
code_ += " static const char * const names[] = {";
code_ += " {{NAMES}}";
@@ -969,14 +985,11 @@ class CppGenerator : public BaseGenerator {
code_.SetValue("BASE_TYPE", GenTypeBasic(enum_def.underlying_type, false));
GenComment(enum_def.doc_comment);
code_ += GenEnumDecl(enum_def) + "\\";
// MSVC doesn't support int64/uint64 enum without explicitly declared enum
// type. The value 4611686018427387904ULL is truncated to zero with warning:
// "warning C4309: 'initializing': truncation of constant value".
auto add_type = parser_.opts.scoped_enums;
add_type |= (enum_def.underlying_type.base_type == BASE_TYPE_LONG);
add_type |= (enum_def.underlying_type.base_type == BASE_TYPE_ULONG);
if (add_type) code_ += " : {{BASE_TYPE}}\\";
code_ +=
(opts_.scoped_enums ? "enum class " : "enum ") + Name(enum_def) + "\\";
if (opts_.g_only_fixed_enums) {
code_ += " : {{BASE_TYPE}}\\";
}
code_ += " {";
code_.SetValue("SEP", ",");
@@ -995,7 +1008,7 @@ class CppGenerator : public BaseGenerator {
const EnumVal *minv = enum_def.MinValue();
const EnumVal *maxv = enum_def.MaxValue();
if (parser_.opts.scoped_enums || parser_.opts.prefixed_enums) {
if (opts_.scoped_enums || opts_.prefixed_enums) {
FLATBUFFERS_ASSERT(minv && maxv);
code_.SetValue("SEP", ",\n");
@@ -1022,7 +1035,7 @@ class CppGenerator : public BaseGenerator {
code_ += "";
code_ += "};";
if (parser_.opts.scoped_enums && enum_def.attributes.Lookup("bit_flags")) {
if (opts_.scoped_enums && enum_def.attributes.Lookup("bit_flags")) {
code_ +=
"FLATBUFFERS_DEFINE_BITMASK_OPERATORS({{ENUM_NAME}}, {{BASE_TYPE}})";
}
@@ -1076,9 +1089,10 @@ class CppGenerator : public BaseGenerator {
code_ += "inline const char *EnumName{{ENUM_NAME}}({{ENUM_NAME}} e) {";
code_ += " if (e < " + GetEnumValUse(enum_def, *enum_def.MinValue()) +
" || e > " + GetEnumValUse(enum_def, *enum_def.MaxValue()) +
") return \"\";";
code_ += " if (flatbuffers::IsOutRange(e, " +
GetEnumValUse(enum_def, *enum_def.MinValue()) + ", " +
GetEnumValUse(enum_def, *enum_def.MaxValue()) +
")) return \"\";";
code_ += " const size_t index = static_cast<size_t>(e)\\";
if (enum_def.MinValue()->IsNonZero()) {
@@ -1129,7 +1143,7 @@ class CppGenerator : public BaseGenerator {
}
}
if (parser_.opts.generate_object_based_api && enum_def.is_union) {
if (opts_.generate_object_based_api && enum_def.is_union) {
// Generate a union type
code_.SetValue("NAME", Name(enum_def));
FLATBUFFERS_ASSERT(enum_def.Lookup("NONE"));
@@ -1185,7 +1199,7 @@ class CppGenerator : public BaseGenerator {
const auto native_type =
NativeName(GetUnionElement(ev, true, true, true),
ev.union_type.struct_def, parser_.opts);
ev.union_type.struct_def, opts_);
code_.SetValue("NATIVE_TYPE", native_type);
code_.SetValue("NATIVE_NAME", Name(ev));
code_.SetValue("NATIVE_ID", GetEnumValUse(enum_def, ev));
@@ -1204,7 +1218,7 @@ class CppGenerator : public BaseGenerator {
code_ += "};";
code_ += "";
if (parser_.opts.gen_compare) {
if (opts_.gen_compare) {
code_ += "";
code_ +=
"inline bool operator==(const {{NAME}}Union &lhs, const "
@@ -1219,7 +1233,7 @@ class CppGenerator : public BaseGenerator {
if (ev.IsNonZero()) {
const auto native_type =
NativeName(GetUnionElement(ev, true, true, true),
ev.union_type.struct_def, parser_.opts);
ev.union_type.struct_def, opts_);
code_.SetValue("NATIVE_TYPE", native_type);
code_ += " case {{NATIVE_ID}}: {";
code_ +=
@@ -1318,7 +1332,7 @@ class CppGenerator : public BaseGenerator {
code_ += "}";
code_ += "";
if (parser_.opts.generate_object_based_api) {
if (opts_.generate_object_based_api) {
// Generate union Unpack() and Pack() functions.
code_ += "inline " + UnionUnPackSignature(enum_def, false) + " {";
code_ += " switch (type) {";
@@ -1358,9 +1372,8 @@ class CppGenerator : public BaseGenerator {
if (ev.IsZero()) { continue; }
code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
code_.SetValue("TYPE",
NativeName(GetUnionElement(ev, true, true, true),
ev.union_type.struct_def, parser_.opts));
code_.SetValue("TYPE", NativeName(GetUnionElement(ev, true, true, true),
ev.union_type.struct_def, opts_));
code_.SetValue("NAME", GetUnionElement(ev, false, true));
code_ += " case {{LABEL}}: {";
code_ += " auto ptr = reinterpret_cast<const {{TYPE}} *>(value);";
@@ -1394,9 +1407,8 @@ class CppGenerator : public BaseGenerator {
const auto &ev = **it;
if (ev.IsZero()) { continue; }
code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
code_.SetValue("TYPE",
NativeName(GetUnionElement(ev, true, true, true),
ev.union_type.struct_def, parser_.opts));
code_.SetValue("TYPE", NativeName(GetUnionElement(ev, true, true, true),
ev.union_type.struct_def, opts_));
code_ += " case {{LABEL}}: {";
bool copyable = true;
if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
@@ -1440,9 +1452,8 @@ class CppGenerator : public BaseGenerator {
const auto &ev = **it;
if (ev.IsZero()) { continue; }
code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
code_.SetValue("TYPE",
NativeName(GetUnionElement(ev, true, true, true),
ev.union_type.struct_def, parser_.opts));
code_.SetValue("TYPE", NativeName(GetUnionElement(ev, true, true, true),
ev.union_type.struct_def, opts_));
code_ += " case {{LABEL}}: {";
code_ += " auto ptr = reinterpret_cast<{{TYPE}} *>(value);";
code_ += " delete ptr;";
@@ -1484,7 +1495,7 @@ class CppGenerator : public BaseGenerator {
void GenFullyQualifiedNameGetter(const StructDef &struct_def,
const std::string &name) {
if (!parser_.opts.generate_name_strings) { return; }
if (!opts_.generate_name_strings) { return; }
auto fullname = struct_def.defined_namespace->GetFullyQualifiedName(name);
code_.SetValue("NAME", fullname);
code_.SetValue("CONSTEXPR", "FLATBUFFERS_CONSTEXPR");
@@ -1619,7 +1630,7 @@ class CppGenerator : public BaseGenerator {
}
code_.SetValue("NATIVE_NAME",
NativeName(Name(struct_def), &struct_def, parser_.opts));
NativeName(Name(struct_def), &struct_def, opts_));
code_.SetValue("INIT_LIST", initializer_list);
code_ += " {{NATIVE_NAME}}(){{INIT_LIST}} {";
@@ -1689,8 +1700,7 @@ class CppGenerator : public BaseGenerator {
}
void GenNativeTable(const StructDef &struct_def) {
const auto native_name =
NativeName(Name(struct_def), &struct_def, parser_.opts);
const auto native_name = NativeName(Name(struct_def), &struct_def, opts_);
code_.SetValue("STRUCT_NAME", Name(struct_def));
code_.SetValue("NATIVE_NAME", native_name);
@@ -1705,7 +1715,7 @@ class CppGenerator : public BaseGenerator {
GenOperatorNewDelete(struct_def);
GenDefaultConstructor(struct_def);
code_ += "};";
if (parser_.opts.gen_compare) GenCompareOperator(struct_def);
if (opts_.gen_compare) GenCompareOperator(struct_def);
code_ += "";
}
@@ -1794,7 +1804,7 @@ class CppGenerator : public BaseGenerator {
} else {
FLATBUFFERS_ASSERT(IsScalar(field.value.type.base_type));
auto type = GenTypeBasic(field.value.type, false);
if (parser_.opts.scoped_enums && field.value.type.enum_def &&
if (opts_.scoped_enums && field.value.type.enum_def &&
IsScalar(field.value.type.base_type)) {
type = GenTypeGet(field.value.type, " ", "const ", " *", true);
}
@@ -1810,7 +1820,7 @@ class CppGenerator : public BaseGenerator {
// Generate an accessor struct, builder structs & function for a table.
void GenTable(const StructDef &struct_def) {
if (parser_.opts.generate_object_based_api) { GenNativeTable(struct_def); }
if (opts_.generate_object_based_api) { GenNativeTable(struct_def); }
// Generate an accessor struct, with methods of the form:
// type name() const { return GetField<type>(offset, defaultval); }
@@ -1820,10 +1830,10 @@ class CppGenerator : public BaseGenerator {
code_ +=
"struct {{STRUCT_NAME}} FLATBUFFERS_FINAL_CLASS"
" : private flatbuffers::Table {";
if (parser_.opts.generate_object_based_api) {
if (opts_.generate_object_based_api) {
code_ += " typedef {{NATIVE_NAME}} NativeTableType;";
}
if (parser_.opts.mini_reflect != IDLOptions::kNone) {
if (opts_.mini_reflect != IDLOptions::kNone) {
code_ +=
" static const flatbuffers::TypeTable *MiniReflectTypeTable() {";
code_ += " return {{STRUCT_NAME}}TypeTable();";
@@ -1931,8 +1941,7 @@ class CppGenerator : public BaseGenerator {
}
}
if (parser_.opts.mutable_buffer &&
!(is_scalar && IsUnion(field.value.type))) {
if (opts_.mutable_buffer && !(is_scalar && IsUnion(field.value.type))) {
if (is_scalar) {
const auto type = GenTypeWire(field.value.type, "", false);
code_.SetValue("SET_FN", "SetField<" + type + ">");
@@ -2014,13 +2023,11 @@ class CppGenerator : public BaseGenerator {
code_ += " &&\n verifier.EndTable();";
code_ += " }";
if (parser_.opts.generate_object_based_api) {
if (opts_.generate_object_based_api) {
// Generate the UnPack() pre declaration.
code_ +=
" " + TableUnPackSignature(struct_def, true, parser_.opts) + ";";
code_ +=
" " + TableUnPackToSignature(struct_def, true, parser_.opts) + ";";
code_ += " " + TablePackSignature(struct_def, true, parser_.opts) + ";";
code_ += " " + TableUnPackSignature(struct_def, true, opts_) + ";";
code_ += " " + TableUnPackToSignature(struct_def, true, opts_) + ";";
code_ += " " + TablePackSignature(struct_def, true, opts_) + ";";
}
code_ += "};"; // End of table.
@@ -2065,10 +2072,10 @@ class CppGenerator : public BaseGenerator {
GenBuilders(struct_def);
if (parser_.opts.generate_object_based_api) {
if (opts_.generate_object_based_api) {
// Generate a pre-declaration for a CreateX method that works with an
// unpacked C++ object.
code_ += TableCreateSignature(struct_def, true, parser_.opts) + ";";
code_ += TableCreateSignature(struct_def, true, opts_) + ";";
code_ += "";
}
}
@@ -2292,7 +2299,7 @@ class CppGenerator : public BaseGenerator {
}
} else {
const auto ptype = GenTypeNativePtr(
NativeName(name, type.struct_def, parser_.opts), &afield, true);
NativeName(name, type.struct_def, opts_), &afield, true);
return ptype + "(" + val + "->UnPack(_resolver))";
}
}
@@ -2419,8 +2426,6 @@ class CppGenerator : public BaseGenerator {
}
std::string GenCreateParam(const FieldDef &field) {
const IDLOptions &opts = parser_.opts;
std::string value = "_o->";
if (field.value.type.base_type == BASE_TYPE_UTYPE) {
value += StripUnionType(Name(field));
@@ -2457,7 +2462,7 @@ class CppGenerator : public BaseGenerator {
// depending on set_empty_strings_to_null either set it to 0 or an empty string.
if (!field.required) {
auto empty_value =
opts.set_empty_strings_to_null ? "0" : "_fbb.CreateSharedString(\"\")";
opts_.set_empty_strings_to_null ? "0" : "_fbb.CreateSharedString(\"\")";
code = value + ".empty() ? " + empty_value + " : " + code;
}
break;
@@ -2562,7 +2567,7 @@ class CppGenerator : public BaseGenerator {
// If set_empty_vectors_to_null option is enabled, for optional fields, check to
// see if there actually is any data in _o->field before attempting to
// access it.
if (opts.set_empty_vectors_to_null && !field.required) {
if (opts_.set_empty_vectors_to_null && !field.required) {
code = value + ".size() ? " + code + " : 0";
}
break;
@@ -2604,20 +2609,20 @@ class CppGenerator : public BaseGenerator {
void GenTablePost(const StructDef &struct_def) {
code_.SetValue("STRUCT_NAME", Name(struct_def));
code_.SetValue("NATIVE_NAME",
NativeName(Name(struct_def), &struct_def, parser_.opts));
NativeName(Name(struct_def), &struct_def, opts_));
if (parser_.opts.generate_object_based_api) {
if (opts_.generate_object_based_api) {
// Generate the X::UnPack() method.
code_ += "inline " +
TableUnPackSignature(struct_def, false, parser_.opts) + " {";
code_ +=
"inline " + TableUnPackSignature(struct_def, false, opts_) + " {";
code_ += " auto _o = new {{NATIVE_NAME}}();";
code_ += " UnPackTo(_o, _resolver);";
code_ += " return _o;";
code_ += "}";
code_ += "";
code_ += "inline " +
TableUnPackToSignature(struct_def, false, parser_.opts) + " {";
code_ +=
"inline " + TableUnPackToSignature(struct_def, false, opts_) + " {";
code_ += " (void)_o;";
code_ += " (void)_resolver;";
@@ -2644,15 +2649,14 @@ class CppGenerator : public BaseGenerator {
// Generate the X::Pack member function that simply calls the global
// CreateX function.
code_ += "inline " + TablePackSignature(struct_def, false, parser_.opts) +
" {";
code_ += "inline " + TablePackSignature(struct_def, false, opts_) + " {";
code_ += " return Create{{STRUCT_NAME}}(_fbb, _o, _rehasher);";
code_ += "}";
code_ += "";
// Generate a CreateX method that works with an unpacked C++ object.
code_ += "inline " +
TableCreateSignature(struct_def, false, parser_.opts) + " {";
code_ +=
"inline " + TableCreateSignature(struct_def, false, opts_) + " {";
code_ += " (void)_rehasher;";
code_ += " (void)_o;";
@@ -2660,7 +2664,7 @@ class CppGenerator : public BaseGenerator {
" struct _VectorArgs "
"{ flatbuffers::FlatBufferBuilder *__fbb; "
"const " +
NativeName(Name(struct_def), &struct_def, parser_.opts) +
NativeName(Name(struct_def), &struct_def, opts_) +
"* __o; "
"const flatbuffers::rehasher_function_t *__rehasher; } _va = { "
"&_fbb, _o, _rehasher}; (void)_va;";
@@ -2775,7 +2779,7 @@ class CppGenerator : public BaseGenerator {
code_ += " public:";
// Make TypeTable accessible via the generated struct.
if (parser_.opts.mini_reflect != IDLOptions::kNone) {
if (opts_.mini_reflect != IDLOptions::kNone) {
code_ +=
" static const flatbuffers::TypeTable *MiniReflectTypeTable() {";
code_ += " return {{STRUCT_NAME}}TypeTable();";
@@ -2891,7 +2895,7 @@ class CppGenerator : public BaseGenerator {
}
// Generate a mutable accessor function.
if (parser_.opts.mutable_buffer) {
if (opts_.mutable_buffer) {
auto mut_field_type =
GenTypeGet(field.value.type, " ", "",
IsArray(field.value.type) ? "" : " &", true);
@@ -2932,7 +2936,7 @@ class CppGenerator : public BaseGenerator {
code_.SetValue("STRUCT_BYTE_SIZE", NumToString(struct_def.bytesize));
code_ += "FLATBUFFERS_STRUCT_END({{STRUCT_NAME}}, {{STRUCT_BYTE_SIZE}});";
if (parser_.opts.gen_compare) GenCompareOperator(struct_def, "()");
if (opts_.gen_compare) GenCompareOperator(struct_def, "()");
code_ += "";
}
@@ -2974,15 +2978,39 @@ class CppGenerator : public BaseGenerator {
cur_name_space_ = ns;
}
const TypedFloatConstantGenerator float_const_gen_;
};
} // namespace cpp
bool GenerateCPP(const Parser &parser, const std::string &path,
const std::string &file_name) {
cpp::CppGenerator generator(parser, path, file_name);
cpp::IDLOptionsCpp opts(parser.opts);
// The '--cpp_std' argument could be extended (like ASAN):
// Example: "flatc --cpp_std c++17:option1:option2".
auto cpp_std = !opts.cpp_std.empty() ? opts.cpp_std : "C++0X";
std::transform(cpp_std.begin(), cpp_std.end(), cpp_std.begin(), ToUpper);
if (cpp_std == "C++0X") {
opts.g_cpp_std = cpp::CPP_STD_X0;
opts.g_only_fixed_enums = false;
} else if (cpp_std == "C++11") {
// Use the standard C++11 code generator.
opts.g_cpp_std = cpp::CPP_STD_11;
opts.g_only_fixed_enums = true;
} else if (cpp_std == "C++17") {
opts.g_cpp_std = cpp::CPP_STD_17;
// With c++17 generate strong enums only.
opts.scoped_enums = true;
// By default, prefixed_enums==true, reset it.
opts.prefixed_enums = false;
} else {
LogCompilerError("Unknown value of the '--cpp-std' switch: " +
opts.cpp_std);
return false;
}
// The opts.scoped_enums has priority.
opts.g_only_fixed_enums |= opts.scoped_enums;
cpp::CppGenerator generator(parser, path, file_name, opts);
return generator.generate();
}