diff --git a/.gitignore b/.gitignore index 8c7baf876..1369bce8a 100644 --- a/.gitignore +++ b/.gitignore @@ -149,4 +149,4 @@ flatbuffers.pc **/html/** **/latex/** # https://cmake.org/cmake/help/latest/module/FetchContent.html#variable:FETCHCONTENT_BASE_DIR -_deps/ \ No newline at end of file +cmake-build-debug/ diff --git a/include/flatbuffers/idl.h b/include/flatbuffers/idl.h index 1701236bf..404482812 100644 --- a/include/flatbuffers/idl.h +++ b/include/flatbuffers/idl.h @@ -587,6 +587,7 @@ struct IDLOptions { bool strict_json; bool output_default_scalars_in_json; int indent_step; + bool cpp_minify_enums; bool output_enum_identifiers; bool prefixed_enums; bool scoped_enums; @@ -698,6 +699,7 @@ struct IDLOptions { strict_json(false), output_default_scalars_in_json(false), indent_step(2), + cpp_minify_enums(false), output_enum_identifiers(true), prefixed_enums(true), scoped_enums(false), diff --git a/src/flatc.cpp b/src/flatc.cpp index 40a538fcd..deb45ec88 100644 --- a/src/flatc.cpp +++ b/src/flatc.cpp @@ -454,6 +454,8 @@ int FlatCompiler::Compile(int argc, const char **argv) { opts.skip_unexpected_fields_in_json = true; } else if (arg == "--no-prefix") { opts.prefixed_enums = false; + } else if (arg == "--cpp-minify-enums") { + opts.cpp_minify_enums = true; } else if (arg == "--scoped-enums") { opts.prefixed_enums = false; opts.scoped_enums = true; diff --git a/src/idl_gen_cpp.cpp b/src/idl_gen_cpp.cpp index 6072c0889..5cffc18a3 100644 --- a/src/idl_gen_cpp.cpp +++ b/src/idl_gen_cpp.cpp @@ -459,12 +459,10 @@ class CppGenerator : public BaseGenerator { } // Generate code for all the enum declarations. - for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end(); - ++it) { - const auto &enum_def = **it; - if (!enum_def.generated) { - SetNameSpace(enum_def.defined_namespace); - GenEnum(enum_def); + for (const auto enum_def : parser_.enums_.vec) { + if (!enum_def->generated) { + SetNameSpace(enum_def->defined_namespace); + GenEnum(*enum_def); } } @@ -1231,17 +1229,21 @@ class CppGenerator : public BaseGenerator { code_.SetValue("SEP", ","); auto add_sep = false; - for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) { - const auto &ev = **it; + for (const auto ev : enum_def.Vals()) { if (add_sep) code_ += "{{SEP}}"; - GenComment(ev.doc_comment, " "); - code_.SetValue("KEY", GenEnumValDecl(enum_def, Name(ev))); + GenComment(ev->doc_comment, " "); + code_.SetValue("KEY", GenEnumValDecl(enum_def, Name(*ev))); code_.SetValue("VALUE", - NumToStringCpp(enum_def.ToString(ev), + NumToStringCpp(enum_def.ToString(*ev), enum_def.underlying_type.base_type)); code_ += " {{KEY}} = {{VALUE}}\\"; add_sep = true; } + if (opts_.cpp_minify_enums) { + code_ += ""; + code_ += "};"; + return; + } const EnumVal *minv = enum_def.MinValue(); const EnumVal *maxv = enum_def.MaxValue(); @@ -1277,8 +1279,175 @@ class CppGenerator : public BaseGenerator { "FLATBUFFERS_DEFINE_BITMASK_OPERATORS({{ENUM_NAME}}, {{BASE_TYPE}})"; } code_ += ""; + GenEnumArray(enum_def); + GenEnumStringTable(enum_def); - // Generate an array of all enumeration values + // Generate type traits for unions to map from a type to union enum value. + if (enum_def.is_union && !enum_def.uses_multiple_type_instances) { + for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); + ++it) { + const auto &ev = **it; + + if (it == enum_def.Vals().begin()) { + code_ += "template struct {{ENUM_NAME}}Traits {"; + } else { + auto name = GetUnionElement(ev, false, opts_); + code_ += "template<> struct {{ENUM_NAME}}Traits<" + name + "> {"; + } + + auto value = GetEnumValUse(enum_def, ev); + code_ += " static const {{ENUM_NAME}} enum_value = " + value + ";"; + code_ += "};"; + code_ += ""; + } + } + + GenEnumObjectBasedAPI(enum_def); + + if (enum_def.is_union) { + code_ += UnionVerifySignature(enum_def) + ";"; + code_ += UnionVectorVerifySignature(enum_def) + ";"; + 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; } + code_.SetValue("NAME", Name(enum_def)); + FLATBUFFERS_ASSERT(enum_def.Lookup("NONE")); + code_.SetValue("NONE", GetEnumValUse(enum_def, *enum_def.Lookup("NONE"))); + + if (!enum_def.uses_multiple_type_instances) { + for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); + ++it) { + const auto &ev = **it; + + if (it == enum_def.Vals().begin()) { + code_ += "template struct {{NAME}}UnionTraits {"; + } else { + auto name = GetUnionElement(ev, true, opts_); + code_ += "template<> struct {{NAME}}UnionTraits<" + name + "> {"; + } + + auto value = GetEnumValUse(enum_def, ev); + code_ += " static const {{ENUM_NAME}} enum_value = " + value + ";"; + code_ += "};"; + code_ += ""; + } + } + + code_ += "struct {{NAME}}Union {"; + code_ += " {{NAME}} type;"; + code_ += " void *value;"; + code_ += ""; + code_ += " {{NAME}}Union() : type({{NONE}}), value(nullptr) {}"; + code_ += " {{NAME}}Union({{NAME}}Union&& u) FLATBUFFERS_NOEXCEPT :"; + code_ += " type({{NONE}}), value(nullptr)"; + code_ += " { std::swap(type, u.type); std::swap(value, u.value); }"; + code_ += " {{NAME}}Union(const {{NAME}}Union &);"; + code_ += " {{NAME}}Union &operator=(const {{NAME}}Union &u)"; + code_ += + " { {{NAME}}Union t(u); std::swap(type, t.type); std::swap(value, " + "t.value); return *this; }"; + code_ += + " {{NAME}}Union &operator=({{NAME}}Union &&u) FLATBUFFERS_NOEXCEPT"; + code_ += + " { std::swap(type, u.type); std::swap(value, u.value); return " + "*this; }"; + code_ += " ~{{NAME}}Union() { Reset(); }"; + code_ += ""; + code_ += " void Reset();"; + code_ += ""; + if (!enum_def.uses_multiple_type_instances) { + code_ += " template "; + code_ += " void Set(T&& val) {"; + code_ += " typedef typename std::remove_reference::type RT;"; + code_ += " Reset();"; + code_ += " type = {{NAME}}UnionTraits::enum_value;"; + code_ += " if (type != {{NONE}}) {"; + code_ += " value = new RT(std::forward(val));"; + code_ += " }"; + code_ += " }"; + code_ += ""; + } + code_ += " " + UnionUnPackSignature(enum_def, true) + ";"; + code_ += " " + UnionPackSignature(enum_def, true) + ";"; + code_ += ""; + + for (const auto ev : enum_def.Vals()) { + if (ev->IsZero()) { continue; } + + const auto native_type = GetUnionElement(*ev, true, opts_); + code_.SetValue("NATIVE_TYPE", native_type); + code_.SetValue("NATIVE_NAME", Name(*ev)); + code_.SetValue("NATIVE_ID", GetEnumValUse(enum_def, *ev)); + + code_ += " {{NATIVE_TYPE}} *As{{NATIVE_NAME}}() {"; + code_ += " return type == {{NATIVE_ID}} ?"; + code_ += " reinterpret_cast<{{NATIVE_TYPE}} *>(value) : nullptr;"; + code_ += " }"; + + code_ += " const {{NATIVE_TYPE}} *As{{NATIVE_NAME}}() const {"; + code_ += " return type == {{NATIVE_ID}} ?"; + code_ += + " reinterpret_cast(value) : nullptr;"; + code_ += " }"; + } + code_ += "};"; + code_ += ""; + + GenEnumEquals(enum_def); + } + + void GenEnumEquals(const EnumDef &enum_def) { + if (opts_.gen_compare) { + code_ += ""; + code_ += + "inline bool operator==(const {{NAME}}Union &lhs, const " + "{{NAME}}Union &rhs) {"; + code_ += " if (lhs.type != rhs.type) return false;"; + code_ += " switch (lhs.type) {"; + + for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); + ++it) { + const auto &ev = **it; + code_.SetValue("NATIVE_ID", GetEnumValUse(enum_def, ev)); + if (ev.IsNonZero()) { + const auto native_type = GetUnionElement(ev, true, opts_); + code_.SetValue("NATIVE_TYPE", native_type); + code_ += " case {{NATIVE_ID}}: {"; + code_ += + " return *(reinterpret_cast(lhs.value)) =="; + code_ += + " *(reinterpret_cast(rhs.value));"; + code_ += " }"; + } else { + code_ += " case {{NATIVE_ID}}: {"; + code_ += " return true;"; // "NONE" enum value. + code_ += " }"; + } + } + code_ += " default: {"; + code_ += " return false;"; + code_ += " }"; + code_ += " }"; + code_ += "}"; + + code_ += ""; + code_ += + "inline bool operator!=(const {{NAME}}Union &lhs, const " + "{{NAME}}Union &rhs) {"; + code_ += " return !(lhs == rhs);"; + code_ += "}"; + code_ += ""; + } + } + + // Generate an array of all enumeration values + void GenEnumArray(const EnumDef &enum_def) { auto num_fields = NumToString(enum_def.size()); code_ += "inline const {{ENUM_NAME}} (&EnumValues{{ENUM_NAME}}())[" + num_fields + "] {"; @@ -1293,11 +1462,13 @@ class CppGenerator : public BaseGenerator { code_ += " return values;"; code_ += "}"; code_ += ""; + } - // 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. + // Generate a string table for enum values. + // Problem is, if values are very sparse that could generate huge tables. + // Ideally in that case we generate a map lookup instead, but for the moment + // we simply don't output a table at all. + void GenEnumStringTable(const EnumDef &enum_def) { auto range = enum_def.Distance(); // Average distance between values above which we consider a table // "too sparse". Change at will. @@ -1308,9 +1479,7 @@ class CppGenerator : public BaseGenerator { NumToString(range + 1 + 1) + "] = {"; auto val = enum_def.Vals().front(); - for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); - ++it) { - auto ev = *it; + for (const auto &ev : enum_def.Vals()) { for (auto k = enum_def.Distance(val, ev); k > 1; --k) { code_ += " \"\","; } @@ -1343,180 +1512,16 @@ class CppGenerator : public BaseGenerator { code_ += ""; } else { code_ += "inline const char *EnumName{{ENUM_NAME}}({{ENUM_NAME}} e) {"; - code_ += " switch (e) {"; - - for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); - ++it) { - const auto &ev = **it; - code_ += " case " + GetEnumValUse(enum_def, ev) + ": return \"" + - Name(ev) + "\";"; + for (const auto &ev : enum_def.Vals()) { + code_ += " case " + GetEnumValUse(enum_def, *ev) + ": return \"" + + Name(*ev) + "\";"; } - code_ += " default: return \"\";"; code_ += " }"; - code_ += "}"; code_ += ""; } - - // Generate type traits for unions to map from a type to union enum value. - if (enum_def.is_union && !enum_def.uses_multiple_type_instances) { - for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); - ++it) { - const auto &ev = **it; - - if (it == enum_def.Vals().begin()) { - code_ += "template struct {{ENUM_NAME}}Traits {"; - } else { - auto name = GetUnionElement(ev, false, opts_); - code_ += "template<> struct {{ENUM_NAME}}Traits<" + name + "> {"; - } - - auto value = GetEnumValUse(enum_def, ev); - code_ += " static const {{ENUM_NAME}} enum_value = " + value + ";"; - code_ += "};"; - code_ += ""; - } - } - - if (opts_.generate_object_based_api && enum_def.is_union) { - // Generate a union type and a trait type for it. - code_.SetValue("NAME", Name(enum_def)); - FLATBUFFERS_ASSERT(enum_def.Lookup("NONE")); - code_.SetValue("NONE", GetEnumValUse(enum_def, *enum_def.Lookup("NONE"))); - - if (!enum_def.uses_multiple_type_instances) { - for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); - ++it) { - const auto &ev = **it; - - if (it == enum_def.Vals().begin()) { - code_ += "template struct {{NAME}}UnionTraits {"; - } else { - auto name = GetUnionElement(ev, true, opts_); - code_ += "template<> struct {{NAME}}UnionTraits<" + name + "> {"; - } - - auto value = GetEnumValUse(enum_def, ev); - code_ += " static const {{ENUM_NAME}} enum_value = " + value + ";"; - code_ += "};"; - code_ += ""; - } - } - - code_ += "struct {{NAME}}Union {"; - code_ += " {{NAME}} type;"; - code_ += " void *value;"; - code_ += ""; - code_ += " {{NAME}}Union() : type({{NONE}}), value(nullptr) {}"; - code_ += " {{NAME}}Union({{NAME}}Union&& u) FLATBUFFERS_NOEXCEPT :"; - code_ += " type({{NONE}}), value(nullptr)"; - code_ += " { std::swap(type, u.type); std::swap(value, u.value); }"; - code_ += " {{NAME}}Union(const {{NAME}}Union &);"; - code_ += " {{NAME}}Union &operator=(const {{NAME}}Union &u)"; - code_ += - " { {{NAME}}Union t(u); std::swap(type, t.type); std::swap(value, " - "t.value); return *this; }"; - code_ += - " {{NAME}}Union &operator=({{NAME}}Union &&u) FLATBUFFERS_NOEXCEPT"; - code_ += - " { std::swap(type, u.type); std::swap(value, u.value); return " - "*this; }"; - code_ += " ~{{NAME}}Union() { Reset(); }"; - code_ += ""; - code_ += " void Reset();"; - code_ += ""; - if (!enum_def.uses_multiple_type_instances) { - code_ += " template "; - code_ += " void Set(T&& val) {"; - code_ += " typedef typename std::remove_reference::type RT;"; - code_ += " Reset();"; - code_ += " type = {{NAME}}UnionTraits::enum_value;"; - code_ += " if (type != {{NONE}}) {"; - code_ += " value = new RT(std::forward(val));"; - code_ += " }"; - code_ += " }"; - code_ += ""; - } - code_ += " " + UnionUnPackSignature(enum_def, true) + ";"; - code_ += " " + UnionPackSignature(enum_def, true) + ";"; - code_ += ""; - - for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); - ++it) { - const auto &ev = **it; - if (ev.IsZero()) { continue; } - - const auto native_type = GetUnionElement(ev, true, opts_); - code_.SetValue("NATIVE_TYPE", native_type); - code_.SetValue("NATIVE_NAME", Name(ev)); - code_.SetValue("NATIVE_ID", GetEnumValUse(enum_def, ev)); - - code_ += " {{NATIVE_TYPE}} *As{{NATIVE_NAME}}() {"; - code_ += " return type == {{NATIVE_ID}} ?"; - code_ += " reinterpret_cast<{{NATIVE_TYPE}} *>(value) : nullptr;"; - code_ += " }"; - - code_ += " const {{NATIVE_TYPE}} *As{{NATIVE_NAME}}() const {"; - code_ += " return type == {{NATIVE_ID}} ?"; - code_ += - " reinterpret_cast(value) : nullptr;"; - code_ += " }"; - } - code_ += "};"; - code_ += ""; - - if (opts_.gen_compare) { - code_ += ""; - code_ += - "inline bool operator==(const {{NAME}}Union &lhs, const " - "{{NAME}}Union &rhs) {"; - code_ += " if (lhs.type != rhs.type) return false;"; - code_ += " switch (lhs.type) {"; - - for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); - ++it) { - const auto &ev = **it; - code_.SetValue("NATIVE_ID", GetEnumValUse(enum_def, ev)); - if (ev.IsNonZero()) { - const auto native_type = GetUnionElement(ev, true, opts_); - code_.SetValue("NATIVE_TYPE", native_type); - code_ += " case {{NATIVE_ID}}: {"; - code_ += - " return *(reinterpret_cast(lhs.value)) =="; - code_ += - " *(reinterpret_cast(rhs.value));"; - code_ += " }"; - } else { - code_ += " case {{NATIVE_ID}}: {"; - code_ += " return true;"; // "NONE" enum value. - code_ += " }"; - } - } - code_ += " default: {"; - code_ += " return false;"; - code_ += " }"; - code_ += " }"; - code_ += "}"; - - code_ += ""; - code_ += - "inline bool operator!=(const {{NAME}}Union &lhs, const " - "{{NAME}}Union &rhs) {"; - code_ += " return !(lhs == rhs);"; - code_ += "}"; - code_ += ""; - } - } - - if (enum_def.is_union) { - code_ += UnionVerifySignature(enum_def) + ";"; - code_ += UnionVectorVerifySignature(enum_def) + ";"; - code_ += ""; - } } void GenUnionPost(const EnumDef &enum_def) { diff --git a/tests/minified_enums/enums.fbs b/tests/minified_enums/enums.fbs new file mode 100644 index 000000000..0e0211aa1 --- /dev/null +++ b/tests/minified_enums/enums.fbs @@ -0,0 +1,3 @@ +enum Color : int {Red = 1, Blue, Orange} + +enum Size: int {Small = 10, Large = 100, Medium = 1000} \ No newline at end of file diff --git a/tests/minified_enums/enums_generated.h b/tests/minified_enums/enums_generated.h new file mode 100644 index 000000000..279418668 --- /dev/null +++ b/tests/minified_enums/enums_generated.h @@ -0,0 +1,26 @@ +// automatically generated by the FlatBuffers compiler, do not modify + + +#ifndef FLATBUFFERS_GENERATED_ENUMS_H_ +#define FLATBUFFERS_GENERATED_ENUMS_H_ + +#include "flatbuffers/flatbuffers.h" + +// Ensure the included flatbuffers.h is the same version as when this file was +// generated, otherwise it may not be compatible. +static_assert(FLATBUFFERS_VERSION_MAJOR == 22 && + FLATBUFFERS_VERSION_MINOR == 9 && + FLATBUFFERS_VERSION_REVISION == 29, + "Non-compatible flatbuffers version included"); + +enum Color : int32_t { + Color_Red = 1, + Color_Blue = 2, + Color_Orange = 3 +}; +enum Size : int32_t { + Size_Small = 10, + Size_Large = 100, + Size_Medium = 1000 +}; +#endif // FLATBUFFERS_GENERATED_ENUMS_H_