Enums in C++ are now strongly typed.

Accessors and constructors now take enum types rather than ints.

Bug: 16570507
Change-Id: I4b50fd64ad2e662ea2481bc0ccea784326fb31c0
Tested: on Linux and Windows.
This commit is contained in:
Wouter van Oortmerssen
2014-09-23 11:55:42 -07:00
parent 85c9c83844
commit 7b8053570e
14 changed files with 151 additions and 83 deletions

View File

@@ -23,18 +23,38 @@
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;
}
}
// Return a C++ type from the table in idl.h
static std::string GenTypeBasic(const Type &type) {
static std::string GenTypeBasic(const Parser &parser, const Type &type,
bool real_enum) {
static const char *ctypename[] = {
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE) #CTYPE,
FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
#undef FLATBUFFERS_TD
};
return ctypename[type.base_type];
return real_enum && type.enum_def
? WrapInNameSpace(parser, type.enum_def->defined_namespace,
type.enum_def->name)
: ctypename[type.base_type];
}
static std::string GenTypeWire(const Parser &parser, const Type &type,
const char *postfix);
const char *postfix, bool real_enum);
// Return a C++ pointer type, specialized to the actual struct/table types,
// and vector element types.
@@ -44,19 +64,10 @@ static std::string GenTypePointer(const Parser &parser, const Type &type) {
return "flatbuffers::String";
case BASE_TYPE_VECTOR:
return "flatbuffers::Vector<" +
GenTypeWire(parser, type.VectorType(), "") + ">";
GenTypeWire(parser, type.VectorType(), "", false) + ">";
case BASE_TYPE_STRUCT: {
auto ns = type.struct_def->defined_namespace;
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 + type.struct_def->name;
} else {
return type.struct_def->name;
}
return WrapInNameSpace(parser, type.struct_def->defined_namespace,
type.struct_def->name);
}
case BASE_TYPE_UNION:
// fall through
@@ -68,9 +79,9 @@ static std::string GenTypePointer(const Parser &parser, const Type &type) {
// 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) {
const char *postfix, bool real_enum) {
return IsScalar(type.base_type)
? GenTypeBasic(type) + postfix
? GenTypeBasic(parser, type, real_enum) + postfix
: IsStruct(type)
? "const " + GenTypePointer(parser, type) + " *"
: "flatbuffers::Offset<" + GenTypePointer(parser, type) + ">" + postfix;
@@ -80,7 +91,7 @@ static std::string GenTypeWire(const Parser &parser, const Type &type,
// serialized size.
static std::string GenTypeSize(const Parser &parser, const Type &type) {
return IsScalar(type.base_type)
? GenTypeBasic(type)
? GenTypeBasic(parser, type, false)
: IsStruct(type)
? GenTypePointer(parser, type)
: "flatbuffers::uoffset_t";
@@ -90,9 +101,9 @@ static std::string GenTypeSize(const Parser &parser, const Type &type) {
// using a flatbuffer.
static std::string GenTypeGet(const Parser &parser, const Type &type,
const char *afterbasic, const char *beforeptr,
const char *afterptr) {
const char *afterptr, bool real_enum) {
return IsScalar(type.base_type)
? GenTypeBasic(type) + afterbasic
? GenTypeBasic(parser, type, real_enum) + afterbasic
: beforeptr + GenTypePointer(parser, type) + afterptr;
}
@@ -110,7 +121,7 @@ static void GenEnum(EnumDef &enum_def, std::string *code_ptr,
std::string &code = *code_ptr;
std::string &code_post = *code_ptr_post;
GenComment(enum_def.doc_comment, code_ptr);
code += "enum {\n";
code += "enum " + enum_def.name + " {\n";
for (auto it = enum_def.vals.vec.begin();
it != enum_def.vals.vec.end();
++it) {
@@ -143,7 +154,7 @@ static void GenEnum(EnumDef &enum_def, std::string *code_ptr,
}
code += "nullptr };\n return names;\n}\n\n";
code += "inline const char *EnumName" + enum_def.name;
code += "(int e) { return EnumNames" + enum_def.name + "()[e";
code += "(" + enum_def.name + " e) { return EnumNames" + enum_def.name + "()[e";
if (enum_def.vals.vec.front()->value)
code += " - " + GenEnumVal(enum_def, *enum_def.vals.vec.front(), opts);
code += "]; }\n\n";
@@ -176,6 +187,18 @@ static void GenEnum(EnumDef &enum_def, std::string *code_ptr,
}
}
// 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)
? "static_cast<" + GenTypeBasic(parser, field.value.type, from) + ">(" +
val + ")"
: val;
}
// Generate an accessor struct, builder structs & function for a table.
static void GenTable(const Parser &parser, StructDef &struct_def,
std::string *code_ptr) {
@@ -193,18 +216,21 @@ static void GenTable(const Parser &parser, StructDef &struct_def,
auto &field = **it;
if (!field.deprecated) { // Deprecated fields won't be accessible.
GenComment(field.doc_comment, code_ptr, " ");
code += " " + GenTypeGet(parser, field.value.type, " ", "const ", " *");
code += " " + GenTypeGet(parser, field.value.type, " ", "const ", " *",
true);
code += field.name + "() const { return ";
// Call a different accessor for pointers, that indirects.
code += IsScalar(field.value.type.base_type)
std::string call = IsScalar(field.value.type.base_type)
? "GetField<"
: (IsStruct(field.value.type) ? "GetStruct<" : "GetPointer<");
code += GenTypeGet(parser, field.value.type, "", "const ", " *") + ">(";
code += NumToString(field.value.offset);
call += GenTypeGet(parser, field.value.type, "", "const ", " *", false);
call += ">(" + NumToString(field.value.offset);
// Default value as second arg for non-pointer types.
if (IsScalar(field.value.type.base_type))
code += ", " + field.value.constant;
code += "); }\n";
call += ", " + field.value.constant;
call += ")";
code += GenUnderlyingCast(parser, field, true, call);
code += "; }\n";
auto nested = field.attributes.Lookup("nested_flatbuffer");
if (nested) {
auto nested_root = parser.structs_.Lookup(nested->constant);
@@ -283,15 +309,18 @@ static void GenTable(const Parser &parser, StructDef &struct_def,
auto &field = **it;
if (!field.deprecated) {
code += " void add_" + field.name + "(";
code += GenTypeWire(parser, field.value.type, " ") + 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, "") + ">";
else if (IsStruct(field.value.type))
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
} else {
code += "Offset";
code += "(" + NumToString(field.value.offset) + ", " + field.name;
}
code += "(" + NumToString(field.value.offset) + ", ";
code += GenUnderlyingCast(parser, field, false, field.name);
if (IsScalar(field.value.type.base_type))
code += ", " + field.value.constant;
code += "); }\n";
@@ -327,8 +356,22 @@ static void GenTable(const Parser &parser, StructDef &struct_def,
++it) {
auto &field = **it;
if (!field.deprecated) {
code += ",\n " + GenTypeWire(parser, field.value.type, " ");
code += field.name + " = " + field.value.constant;
code += ",\n " + GenTypeWire(parser, field.value.type, " ", true);
code += field.name + " = ";
if (field.value.type.enum_def && IsScalar(field.value.type.base_type)) {
auto ed = field.value.type.enum_def->ReverseLookup(
StringToInt(field.value.constant.c_str()), false);
if (ed) {
code += WrapInNameSpace(parser,
field.value.type.enum_def->defined_namespace,
field.value.type.enum_def->name + "_" +
ed->name);
} else {
code += GenUnderlyingCast(parser, field, true, field.value.constant);
}
} else {
code += field.value.constant;
}
}
}
code += ") {\n " + struct_def.name + "Builder builder_(_fbb);\n";
@@ -377,7 +420,7 @@ static void GenStruct(const Parser &parser, StructDef &struct_def,
it != struct_def.fields.vec.end();
++it) {
auto &field = **it;
code += " " + GenTypeGet(parser, field.value.type, " ", "", " ");
code += " " + GenTypeGet(parser, field.value.type, " ", "", " ", false);
code += field.name + "_;\n";
GenPadding(field, [&code, &padding_id](int bits) {
code += " int" + NumToString(bits) +
@@ -392,7 +435,7 @@ static void GenStruct(const Parser &parser, StructDef &struct_def,
++it) {
auto &field = **it;
if (it != struct_def.fields.vec.begin()) code += ", ";
code += GenTypeGet(parser, field.value.type, " ", "const ", " &");
code += GenTypeGet(parser, field.value.type, " ", "const ", " &", true);
code += field.name;
}
code += ")\n : ";
@@ -403,10 +446,13 @@ static void GenStruct(const Parser &parser, StructDef &struct_def,
auto &field = **it;
if (it != struct_def.fields.vec.begin()) code += ", ";
code += field.name + "_(";
if (IsScalar(field.value.type.base_type))
code += "flatbuffers::EndianScalar(" + field.name + "))";
else
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)";
@@ -432,12 +478,13 @@ static void GenStruct(const Parser &parser, StructDef &struct_def,
++it) {
auto &field = **it;
GenComment(field.doc_comment, code_ptr, " ");
code += " " + GenTypeGet(parser, field.value.type, " ", "const ", " &");
code += " " + GenTypeGet(parser, field.value.type, " ", "const ", " &",
true);
code += field.name + "() const { return ";
if (IsScalar(field.value.type.base_type))
code += "flatbuffers::EndianScalar(" + field.name + "_)";
else
code += field.name + "_";
code += GenUnderlyingCast(parser, field, true,
IsScalar(field.value.type.base_type)
? "flatbuffers::EndianScalar(" + field.name + "_)"
: field.name + "_");
code += "; }\n";
}
code += "};\nSTRUCT_END(" + struct_def.name + ", ";