Fixes #7345 to add the option to minify enums (#7566)

* Added cpp minified enums

* Update generated files

* remove initializer and fix comma

* Fix .gitignore

* Fix comma

* Add tests for cpp minify enums
This commit is contained in:
RishabhDeep Singh
2022-11-11 10:17:28 +05:30
committed by GitHub
parent 83e7a98f69
commit 879622fc57
6 changed files with 225 additions and 187 deletions

2
.gitignore vendored
View File

@@ -149,4 +149,4 @@ flatbuffers.pc
**/html/** **/html/**
**/latex/** **/latex/**
# https://cmake.org/cmake/help/latest/module/FetchContent.html#variable:FETCHCONTENT_BASE_DIR # https://cmake.org/cmake/help/latest/module/FetchContent.html#variable:FETCHCONTENT_BASE_DIR
_deps/ cmake-build-debug/

View File

@@ -587,6 +587,7 @@ struct IDLOptions {
bool strict_json; bool strict_json;
bool output_default_scalars_in_json; bool output_default_scalars_in_json;
int indent_step; int indent_step;
bool cpp_minify_enums;
bool output_enum_identifiers; bool output_enum_identifiers;
bool prefixed_enums; bool prefixed_enums;
bool scoped_enums; bool scoped_enums;
@@ -698,6 +699,7 @@ struct IDLOptions {
strict_json(false), strict_json(false),
output_default_scalars_in_json(false), output_default_scalars_in_json(false),
indent_step(2), indent_step(2),
cpp_minify_enums(false),
output_enum_identifiers(true), output_enum_identifiers(true),
prefixed_enums(true), prefixed_enums(true),
scoped_enums(false), scoped_enums(false),

View File

@@ -454,6 +454,8 @@ int FlatCompiler::Compile(int argc, const char **argv) {
opts.skip_unexpected_fields_in_json = true; opts.skip_unexpected_fields_in_json = true;
} else if (arg == "--no-prefix") { } else if (arg == "--no-prefix") {
opts.prefixed_enums = false; opts.prefixed_enums = false;
} else if (arg == "--cpp-minify-enums") {
opts.cpp_minify_enums = true;
} else if (arg == "--scoped-enums") { } else if (arg == "--scoped-enums") {
opts.prefixed_enums = false; opts.prefixed_enums = false;
opts.scoped_enums = true; opts.scoped_enums = true;

View File

@@ -459,12 +459,10 @@ class CppGenerator : public BaseGenerator {
} }
// Generate code for all the enum declarations. // Generate code for all the enum declarations.
for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end(); for (const auto enum_def : parser_.enums_.vec) {
++it) { if (!enum_def->generated) {
const auto &enum_def = **it; SetNameSpace(enum_def->defined_namespace);
if (!enum_def.generated) { GenEnum(*enum_def);
SetNameSpace(enum_def.defined_namespace);
GenEnum(enum_def);
} }
} }
@@ -1231,17 +1229,21 @@ class CppGenerator : public BaseGenerator {
code_.SetValue("SEP", ","); code_.SetValue("SEP", ",");
auto add_sep = false; auto add_sep = false;
for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) { for (const auto ev : enum_def.Vals()) {
const auto &ev = **it;
if (add_sep) code_ += "{{SEP}}"; if (add_sep) code_ += "{{SEP}}";
GenComment(ev.doc_comment, " "); GenComment(ev->doc_comment, " ");
code_.SetValue("KEY", GenEnumValDecl(enum_def, Name(ev))); code_.SetValue("KEY", GenEnumValDecl(enum_def, Name(*ev)));
code_.SetValue("VALUE", code_.SetValue("VALUE",
NumToStringCpp(enum_def.ToString(ev), NumToStringCpp(enum_def.ToString(*ev),
enum_def.underlying_type.base_type)); enum_def.underlying_type.base_type));
code_ += " {{KEY}} = {{VALUE}}\\"; code_ += " {{KEY}} = {{VALUE}}\\";
add_sep = true; add_sep = true;
} }
if (opts_.cpp_minify_enums) {
code_ += "";
code_ += "};";
return;
}
const EnumVal *minv = enum_def.MinValue(); const EnumVal *minv = enum_def.MinValue();
const EnumVal *maxv = enum_def.MaxValue(); const EnumVal *maxv = enum_def.MaxValue();
@@ -1277,88 +1279,8 @@ class CppGenerator : public BaseGenerator {
"FLATBUFFERS_DEFINE_BITMASK_OPERATORS({{ENUM_NAME}}, {{BASE_TYPE}})"; "FLATBUFFERS_DEFINE_BITMASK_OPERATORS({{ENUM_NAME}}, {{BASE_TYPE}})";
} }
code_ += ""; code_ += "";
GenEnumArray(enum_def);
// Generate an array of all enumeration values GenEnumStringTable(enum_def);
auto num_fields = NumToString(enum_def.size());
code_ += "inline const {{ENUM_NAME}} (&EnumValues{{ENUM_NAME}}())[" +
num_fields + "] {";
code_ += " static const {{ENUM_NAME}} values[] = {";
for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
const auto &ev = **it;
auto value = GetEnumValUse(enum_def, ev);
auto suffix = *it != enum_def.Vals().back() ? "," : "";
code_ += " " + value + suffix;
}
code_ += " };";
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.
auto range = enum_def.Distance();
// Average distance between values above which we consider a table
// "too sparse". Change at will.
static const uint64_t kMaxSparseness = 5;
if (range / static_cast<uint64_t>(enum_def.size()) < kMaxSparseness) {
code_ += "inline const char * const *EnumNames{{ENUM_NAME}}() {";
code_ += " static const char * const names[" +
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 (auto k = enum_def.Distance(val, ev); k > 1; --k) {
code_ += " \"\",";
}
val = ev;
code_ += " \"" + Name(*ev) + "\",";
}
code_ += " nullptr";
code_ += " };";
code_ += " return names;";
code_ += "}";
code_ += "";
code_ += "inline const char *EnumName{{ENUM_NAME}}({{ENUM_NAME}} e) {";
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()) {
auto vals = GetEnumValUse(enum_def, *enum_def.MinValue());
code_ += " - static_cast<size_t>(" + vals + ")\\";
}
code_ += ";";
code_ += " return EnumNames{{ENUM_NAME}}()[index];";
code_ += "}";
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) + "\";";
}
code_ += " default: return \"\";";
code_ += " }";
code_ += "}";
code_ += "";
}
// Generate type traits for unions to map from a type to union enum value. // 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) { if (enum_def.is_union && !enum_def.uses_multiple_type_instances) {
@@ -1380,8 +1302,18 @@ class CppGenerator : public BaseGenerator {
} }
} }
if (opts_.generate_object_based_api && enum_def.is_union) { 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. // 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)); code_.SetValue("NAME", Name(enum_def));
FLATBUFFERS_ASSERT(enum_def.Lookup("NONE")); FLATBUFFERS_ASSERT(enum_def.Lookup("NONE"));
code_.SetValue("NONE", GetEnumValUse(enum_def, *enum_def.Lookup("NONE"))); code_.SetValue("NONE", GetEnumValUse(enum_def, *enum_def.Lookup("NONE")));
@@ -1443,15 +1375,13 @@ class CppGenerator : public BaseGenerator {
code_ += " " + UnionPackSignature(enum_def, true) + ";"; code_ += " " + UnionPackSignature(enum_def, true) + ";";
code_ += ""; code_ += "";
for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); for (const auto ev : enum_def.Vals()) {
++it) { if (ev->IsZero()) { continue; }
const auto &ev = **it;
if (ev.IsZero()) { continue; }
const auto native_type = GetUnionElement(ev, true, opts_); const auto native_type = GetUnionElement(*ev, true, opts_);
code_.SetValue("NATIVE_TYPE", native_type); code_.SetValue("NATIVE_TYPE", native_type);
code_.SetValue("NATIVE_NAME", Name(ev)); code_.SetValue("NATIVE_NAME", Name(*ev));
code_.SetValue("NATIVE_ID", GetEnumValUse(enum_def, ev)); code_.SetValue("NATIVE_ID", GetEnumValUse(enum_def, *ev));
code_ += " {{NATIVE_TYPE}} *As{{NATIVE_NAME}}() {"; code_ += " {{NATIVE_TYPE}} *As{{NATIVE_NAME}}() {";
code_ += " return type == {{NATIVE_ID}} ?"; code_ += " return type == {{NATIVE_ID}} ?";
@@ -1467,6 +1397,10 @@ class CppGenerator : public BaseGenerator {
code_ += "};"; code_ += "};";
code_ += ""; code_ += "";
GenEnumEquals(enum_def);
}
void GenEnumEquals(const EnumDef &enum_def) {
if (opts_.gen_compare) { if (opts_.gen_compare) {
code_ += ""; code_ += "";
code_ += code_ +=
@@ -1512,9 +1446,80 @@ class CppGenerator : public BaseGenerator {
} }
} }
if (enum_def.is_union) { // Generate an array of all enumeration values
code_ += UnionVerifySignature(enum_def) + ";"; void GenEnumArray(const EnumDef &enum_def) {
code_ += UnionVectorVerifySignature(enum_def) + ";"; auto num_fields = NumToString(enum_def.size());
code_ += "inline const {{ENUM_NAME}} (&EnumValues{{ENUM_NAME}}())[" +
num_fields + "] {";
code_ += " static const {{ENUM_NAME}} values[] = {";
for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
const auto &ev = **it;
auto value = GetEnumValUse(enum_def, ev);
auto suffix = *it != enum_def.Vals().back() ? "," : "";
code_ += " " + value + suffix;
}
code_ += " };";
code_ += " return values;";
code_ += "}";
code_ += "";
}
// 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.
static const uint64_t kMaxSparseness = 5;
if (range / static_cast<uint64_t>(enum_def.size()) < kMaxSparseness) {
code_ += "inline const char * const *EnumNames{{ENUM_NAME}}() {";
code_ += " static const char * const names[" +
NumToString(range + 1 + 1) + "] = {";
auto val = enum_def.Vals().front();
for (const auto &ev : enum_def.Vals()) {
for (auto k = enum_def.Distance(val, ev); k > 1; --k) {
code_ += " \"\",";
}
val = ev;
code_ += " \"" + Name(*ev) + "\",";
}
code_ += " nullptr";
code_ += " };";
code_ += " return names;";
code_ += "}";
code_ += "";
code_ += "inline const char *EnumName{{ENUM_NAME}}({{ENUM_NAME}} e) {";
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()) {
auto vals = GetEnumValUse(enum_def, *enum_def.MinValue());
code_ += " - static_cast<size_t>(" + vals + ")\\";
}
code_ += ";";
code_ += " return EnumNames{{ENUM_NAME}}()[index];";
code_ += "}";
code_ += "";
} else {
code_ += "inline const char *EnumName{{ENUM_NAME}}({{ENUM_NAME}} e) {";
code_ += " switch (e) {";
for (const auto &ev : enum_def.Vals()) {
code_ += " case " + GetEnumValUse(enum_def, *ev) + ": return \"" +
Name(*ev) + "\";";
}
code_ += " default: return \"\";";
code_ += " }";
code_ += "}";
code_ += ""; code_ += "";
} }
} }

View File

@@ -0,0 +1,3 @@
enum Color : int {Red = 1, Blue, Orange}
enum Size: int {Small = 10, Large = 100, Medium = 1000}

View File

@@ -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_