Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[C++] Add static reflection / stringification for enums (#6499) #8432

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions src/idl_gen_cpp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,12 @@ class CppGenerator : public BaseGenerator {
}
}

if (opts_.g_cpp_std >= cpp::CPP_STD_17) {
// Declare EnumTraits as a template class
code_ += "template<typename T> struct EnumTraits;";
code_ += "";
}

// Generate forward declarations for all equal operators
if (opts_.generate_object_based_api && opts_.gen_compare) {
for (const auto &struct_def : parser_.structs_.vec) {
Expand Down Expand Up @@ -571,6 +577,16 @@ class CppGenerator : public BaseGenerator {
}
}

if (opts_.g_cpp_std >= cpp::CPP_STD_17) {
// Generate traits for enums.
for (const auto &enum_def : parser_.enums_.vec) {
if (!enum_def->generated) {
SetNameSpace(enum_def->defined_namespace);
GenEnumTraits(*enum_def);
}
}
}

// Generate convenient global helper functions:
if (parser_.root_struct_def_) {
auto &struct_def = *parser_.root_struct_def_;
Expand Down Expand Up @@ -1370,6 +1386,29 @@ class CppGenerator : public BaseGenerator {
}
}

void GenEnumTraits(const EnumDef &enum_def) {
code_.SetValue("ENUM_NAME", Name(enum_def));

code_ += "template<>";
code_ += "struct EnumTraits<{{ENUM_NAME}}> {";
if (opts_.mini_reflect != IDLOptions::kNone) {
code_ += " constexpr static auto type_table = {{ENUM_NAME}}TypeTable;";
}
code_ += " constexpr static auto name = EnumName{{ENUM_NAME}};";
code_ += "};";
code_ += "";

code_ += "inline EnumTraits<{{ENUM_NAME}}> EnumValTraits({{ENUM_NAME}}) {";
code_ += " return EnumTraits<{{ENUM_NAME}}>{};";
code_ += "}";
code_ += "";

code_ += "inline const char *GetEnumName({{ENUM_NAME}} e) {";
code_ += " return EnumValTraits(e).name(e);";
code_ += "}";
code_ += "";
}

// Generate a union type and a trait type for it.
void GenEnumObjectBasedAPI(const EnumDef &enum_def) {
if (!(opts_.generate_object_based_api && enum_def.is_union)) { return; }
Expand Down
86 changes: 86 additions & 0 deletions tests/cpp17/generated_cpp17/monster_test_generated.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ struct TypeAliases;
struct TypeAliasesBuilder;
struct TypeAliasesT;

template<typename T> struct EnumTraits;

} // namespace Example

inline const ::flatbuffers::TypeTable *InParentNamespaceTypeTable();
Expand Down Expand Up @@ -4211,6 +4213,90 @@ inline const ::flatbuffers::TypeTable *TypeAliasesTypeTable() {
return &tt;
}

template<>
struct EnumTraits<Color> {
constexpr static auto type_table = ColorTypeTable;
constexpr static auto name = EnumNameColor;
};

inline EnumTraits<Color> EnumValTraits(Color) {
return EnumTraits<Color>{};
}

inline const char *GetEnumName(Color e) {
return EnumValTraits(e).name(e);
}

template<>
struct EnumTraits<Race> {
constexpr static auto type_table = RaceTypeTable;
constexpr static auto name = EnumNameRace;
};

inline EnumTraits<Race> EnumValTraits(Race) {
return EnumTraits<Race>{};
}

inline const char *GetEnumName(Race e) {
return EnumValTraits(e).name(e);
}

template<>
struct EnumTraits<LongEnum> {
constexpr static auto type_table = LongEnumTypeTable;
constexpr static auto name = EnumNameLongEnum;
};

inline EnumTraits<LongEnum> EnumValTraits(LongEnum) {
return EnumTraits<LongEnum>{};
}

inline const char *GetEnumName(LongEnum e) {
return EnumValTraits(e).name(e);
}

template<>
struct EnumTraits<Any> {
constexpr static auto type_table = AnyTypeTable;
constexpr static auto name = EnumNameAny;
};

inline EnumTraits<Any> EnumValTraits(Any) {
return EnumTraits<Any>{};
}

inline const char *GetEnumName(Any e) {
return EnumValTraits(e).name(e);
}

template<>
struct EnumTraits<AnyUniqueAliases> {
constexpr static auto type_table = AnyUniqueAliasesTypeTable;
constexpr static auto name = EnumNameAnyUniqueAliases;
};

inline EnumTraits<AnyUniqueAliases> EnumValTraits(AnyUniqueAliases) {
return EnumTraits<AnyUniqueAliases>{};
}

inline const char *GetEnumName(AnyUniqueAliases e) {
return EnumValTraits(e).name(e);
}

template<>
struct EnumTraits<AnyAmbiguousAliases> {
constexpr static auto type_table = AnyAmbiguousAliasesTypeTable;
constexpr static auto name = EnumNameAnyAmbiguousAliases;
};

inline EnumTraits<AnyAmbiguousAliases> EnumValTraits(AnyAmbiguousAliases) {
return EnumTraits<AnyAmbiguousAliases>{};
}

inline const char *GetEnumName(AnyAmbiguousAliases e) {
return EnumValTraits(e).name(e);
}

inline const MyGame::Example::Monster *GetMonster(const void *buf) {
return ::flatbuffers::GetRoot<MyGame::Example::Monster>(buf);
}
Expand Down
16 changes: 16 additions & 0 deletions tests/cpp17/generated_cpp17/optional_scalars_generated.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ struct ScalarStuff;
struct ScalarStuffBuilder;
struct ScalarStuffT;

template<typename T> struct EnumTraits;

inline const ::flatbuffers::TypeTable *ScalarStuffTypeTable();

enum class OptionalByte : int8_t {
Expand Down Expand Up @@ -928,6 +930,20 @@ inline const ::flatbuffers::TypeTable *ScalarStuffTypeTable() {
return &tt;
}

template<>
struct EnumTraits<OptionalByte> {
constexpr static auto type_table = OptionalByteTypeTable;
constexpr static auto name = EnumNameOptionalByte;
};

inline EnumTraits<OptionalByte> EnumValTraits(OptionalByte) {
return EnumTraits<OptionalByte>{};
}

inline const char *GetEnumName(OptionalByte e) {
return EnumValTraits(e).name(e);
}

inline const optional_scalars::ScalarStuff *GetScalarStuff(const void *buf) {
return ::flatbuffers::GetRoot<optional_scalars::ScalarStuff>(buf);
}
Expand Down
30 changes: 30 additions & 0 deletions tests/cpp17/generated_cpp17/union_vector_generated.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ struct Movie;
struct MovieBuilder;
struct MovieT;

template<typename T> struct EnumTraits;

inline const ::flatbuffers::TypeTable *AttackerTypeTable();

inline const ::flatbuffers::TypeTable *RapunzelTypeTable();
Expand Down Expand Up @@ -1196,6 +1198,34 @@ inline const ::flatbuffers::TypeTable *MovieTypeTable() {
return &tt;
}

template<>
struct EnumTraits<Character> {
constexpr static auto type_table = CharacterTypeTable;
constexpr static auto name = EnumNameCharacter;
};

inline EnumTraits<Character> EnumValTraits(Character) {
return EnumTraits<Character>{};
}

inline const char *GetEnumName(Character e) {
return EnumValTraits(e).name(e);
}

template<>
struct EnumTraits<Gadget> {
constexpr static auto type_table = GadgetTypeTable;
constexpr static auto name = EnumNameGadget;
};

inline EnumTraits<Gadget> EnumValTraits(Gadget) {
return EnumTraits<Gadget>{};
}

inline const char *GetEnumName(Gadget e) {
return EnumValTraits(e).name(e);
}

inline const Movie *GetMovie(const void *buf) {
return ::flatbuffers::GetRoot<Movie>(buf);
}
Expand Down
6 changes: 2 additions & 4 deletions tests/cpp17/stringify_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -150,11 +150,9 @@ std::optional<std::string> StringifyFlatbufferValue(T &&val,
return detail::StringifyArithmeticType(static_cast<int>(val));
}

// Is it an enum? If so, print it like an int, since Flatbuffers doesn't yet
// have type-based reflection for enums, so we can't print the enum's name :(
// Is it an enum? If so, print the enum's name without quotes.
else if constexpr (std::is_enum_v<decayed>) {
return StringifyFlatbufferValue(
static_cast<std::underlying_type_t<decayed>>(val), indent);
return GetEnumName(val);
}

// Is it an int, double, float, uint32_t, etc.?
Expand Down
16 changes: 8 additions & 8 deletions tests/cpp17/test_cpp17.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ void StringifyAnyFlatbuffersTypeTest() {
y = 2.2
z = 3.3
test1 = 6.6
test2 = 2
test2 = Green
test3 = MyGame.Example.Test{
a = 11
b = 90
Expand All @@ -126,8 +126,8 @@ void StringifyAnyFlatbuffersTypeTest() {
6,
7
]
color = 8
test_type = 0
color = Blue
test_type = NONE
testbool = 1
testhashs32_fnv1 = 4
testhashu32_fnv1 = 5
Expand All @@ -143,11 +143,11 @@ void StringifyAnyFlatbuffersTypeTest() {
single_weak_reference = 15
co_owning_reference = 16
non_owning_reference = 17
any_unique_type = 0
any_ambiguous_type = 0
signed_enum = -1
long_enum_non_enum_default = 0
long_enum_normal_default = 2
any_unique_type = NONE
any_ambiguous_type = NONE
signed_enum = None
long_enum_non_enum_default =
long_enum_normal_default = LongOne
nan_default = nan
inf_default = inf
positive_inf_default = inf
Expand Down
Loading