From 42df4d4650ada3438366d99ee85520da77cc7956 Mon Sep 17 00:00:00 2001 From: vglavnyy Date: Tue, 26 Mar 2019 21:48:15 +0700 Subject: [PATCH] Fix issues with uint64 enums - hide the implementation of enums from code generators - fix uint64 the issue in the cpp-generator - fix #5108 - fix issues in cpp code-generator - new tests - add monster_enum.fbs for checking of the cpp code generator --- CMakeLists.txt | 1 + include/flatbuffers/code_generators.h | 5 + include/flatbuffers/idl.h | 77 +- include/flatbuffers/reflection_generated.h | 2 +- include/flatbuffers/util.h | 2 + samples/monster_generated.h | 4 +- src/idl_gen_cpp.cpp | 109 +- src/idl_gen_dart.cpp | 10 +- src/idl_gen_fbs.cpp | 2 +- src/idl_gen_general.cpp | 42 +- src/idl_gen_go.cpp | 2 +- src/idl_gen_js_ts.cpp | 4 +- src/idl_gen_lobster.cpp | 2 +- src/idl_gen_lua.cpp | 4 +- src/idl_gen_php.cpp | 3 +- src/idl_gen_python.cpp | 3 +- src/idl_gen_rust.cpp | 40 +- src/idl_parser.cpp | 434 +++-- tests/generate_code.bat | 1 + tests/generate_code.sh | 1 + tests/monster_enum.fbs | 193 +++ tests/monster_enum_generated.h | 1512 +++++++++++++++++ tests/monster_test_generated.h | 8 +- .../namespace_test1_generated.h | 2 +- tests/prototest/test.proto | 7 +- tests/test.cpp | 104 +- tests/union_vector/union_vector_generated.h | 2 +- 27 files changed, 2320 insertions(+), 256 deletions(-) create mode 100644 tests/monster_enum.fbs create mode 100644 tests/monster_enum_generated.h diff --git a/CMakeLists.txt b/CMakeLists.txt index b7acbc7bca8..99e987e1832 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -321,6 +321,7 @@ endfunction() if(FLATBUFFERS_BUILD_TESTS) compile_flatbuffers_schema_to_cpp(tests/monster_test.fbs) + compile_flatbuffers_schema_to_cpp(tests/monster_enum.fbs) include_directories(${CMAKE_CURRENT_BINARY_DIR}/tests) add_executable(flattests ${FlatBuffers_Tests_SRCS}) set_property(TARGET flattests diff --git a/include/flatbuffers/code_generators.h b/include/flatbuffers/code_generators.h index c2ed707aeeb..3128f17a754 100644 --- a/include/flatbuffers/code_generators.h +++ b/include/flatbuffers/code_generators.h @@ -53,6 +53,11 @@ class CodeWriter { value_map_[key] = value; } + std::string GetValue(const std::string &key) const { + const auto it = value_map_.find(key); + return it == value_map_.end() ? "" : it->second; + } + // Appends the given text to the generated code as well as a newline // character. Any text within {{ and }} delimeters is replaced by values // previously stored in the CodeWriter by calling SetValue above. The newline diff --git a/include/flatbuffers/idl.h b/include/flatbuffers/idl.h index 8299fe0cf81..2a0c8b81a73 100644 --- a/include/flatbuffers/idl.h +++ b/include/flatbuffers/idl.h @@ -123,6 +123,13 @@ inline bool IsLong (BaseType t) { return t == BASE_TYPE_LONG || inline bool IsBool (BaseType t) { return t == BASE_TYPE_BOOL; } inline bool IsOneByte(BaseType t) { return t >= BASE_TYPE_UTYPE && t <= BASE_TYPE_UCHAR; } + +inline bool IsUnsigned(BaseType t) { + return (t == BASE_TYPE_UTYPE) || (t == BASE_TYPE_UCHAR) || + (t == BASE_TYPE_USHORT) || (t == BASE_TYPE_UINT) || + (t == BASE_TYPE_ULONG); +} + // clang-format on extern const char *const kTypeNames[]; @@ -327,30 +334,44 @@ inline size_t InlineAlignment(const Type &type) { return IsStruct(type) ? type.struct_def->minalign : SizeOf(type.base_type); } -struct EnumVal { - EnumVal(const std::string &_name, int64_t _val) : name(_name), value(_val) {} - EnumVal() : value(0) {} +struct EnumDef; +struct EnumValBuilder; +struct EnumVal { Offset Serialize(FlatBufferBuilder *builder, const Parser &parser) const; bool Deserialize(const Parser &parser, const reflection::EnumVal *val); bool IsZero() const { return 0 == value; } bool IsNonZero() const { return !IsZero(); } + uint64_t GetAsUInt64() const { return static_cast(value); } + int64_t GetAsInt64() const { return value; } + bool IsZero() const { return 0 == value; } + bool IsNonZero() const { return !IsZero(); } + std::string name; std::vector doc_comment; - int64_t value; Type union_type; + + private: + friend EnumDef; + friend EnumValBuilder; + friend bool operator==(const EnumVal &lhs, const EnumVal &rhs); + + EnumVal(const std::string &_name, int64_t _val) : name(_name), value(_val) {} + EnumVal() : value(0) {} + + int64_t value; }; struct EnumDef : public Definition { EnumDef() : is_union(false), uses_multiple_type_instances(false) {} EnumVal *ReverseLookup(int64_t enum_idx, bool skip_union_default = true) { - for (auto it = Vals().begin() + + for (auto it = Vals().begin() + static_cast(is_union && skip_union_default); it != Vals().end(); ++it) { - if ((*it)->value == enum_idx) { return *it; } + if ((*it)->GetAsInt64() == enum_idx) { return *it; } } return nullptr; } @@ -359,20 +380,60 @@ struct EnumDef : public Definition { bool Deserialize(Parser &parser, const reflection::Enum *values); + template + void ChangeEnumValue(EnumVal* ev, T new_val); + void SortByValue(); + void RemoveDuplicates(); + + std::string AllFlags() const; + const EnumVal *MinValue() const; + const EnumVal *MaxValue() const; + // Returns the number of integer steps from v1 to v2. + uint64_t Distance(const EnumVal *v1, const EnumVal *v2) const; + // Returns the number of integer steps from Min to Max. + uint64_t Distance() const { return Distance(MinValue(), MaxValue()); } + + // In fact, this is uint64/int64 safe ReverseLookup without skip_union_default. + EnumVal *FindByValue(const std::string &constant) const; + + bool IsUInt64() const { + return (BASE_TYPE_ULONG == underlying_type.base_type); + } + + std::string ToString(const EnumVal &ev) const { + return IsUInt64() ? NumToString(ev.GetAsUInt64()) + : NumToString(ev.GetAsInt64()); + } + size_t size() const { return vals.vec.size(); } const std::vector &Vals() const { + FLATBUFFERS_ASSERT(false == vals.vec.empty()); return vals.vec; } - SymbolTable vals; + const EnumVal *Lookup(const std::string &enum_name) const { + return vals.Lookup(enum_name); + } + bool is_union; // Type is a union which uses type aliases where at least one type is // available under two different names. bool uses_multiple_type_instances; Type underlying_type; + +private: + friend EnumValBuilder; + SymbolTable vals; }; +inline bool operator==(const EnumVal& lhs, const EnumVal& rhs) { + return lhs.value == rhs.value; +} +inline bool operator!=(const EnumVal & lhs, const EnumVal & rhs) { + return !(lhs == rhs); +} + inline bool EqualByName(const Type &a, const Type &b) { return a.base_type == b.base_type && a.element == b.element && (a.struct_def == b.struct_def || @@ -705,7 +766,7 @@ class Parser : public ParserState { FLATBUFFERS_CHECKED_ERROR Error(const std::string &msg); - private: +private: void Message(const std::string &msg); void Warning(const std::string &msg); FLATBUFFERS_CHECKED_ERROR ParseHexNum(int nibbles, uint64_t *val); diff --git a/include/flatbuffers/reflection_generated.h b/include/flatbuffers/reflection_generated.h index 869a9f3f223..55ab79cc3b2 100644 --- a/include/flatbuffers/reflection_generated.h +++ b/include/flatbuffers/reflection_generated.h @@ -70,7 +70,7 @@ inline const BaseType (&EnumValuesBaseType())[17] { } inline const char * const *EnumNamesBaseType() { - static const char * const names[] = { + static const char * const names[18] = { "None", "UType", "Bool", diff --git a/include/flatbuffers/util.h b/include/flatbuffers/util.h index 4367bbecfb0..016844830ae 100644 --- a/include/flatbuffers/util.h +++ b/include/flatbuffers/util.h @@ -380,11 +380,13 @@ template<> inline bool StringToNumber(const char *s, double *val) { return StringToFloatImpl(val, s); } +// FLATBUFFERS_ATTRIBUTE(deprecated("use StringToNumber() instead")) inline int64_t StringToInt(const char *s, int base = 10) { int64_t val; return StringToIntegerImpl(&val, s, base) ? val : 0; } +// FLATBUFFERS_ATTRIBUTE(deprecated("use StringToNumber() instead")) inline uint64_t StringToUInt(const char *s, int base = 10) { uint64_t val; return StringToIntegerImpl(&val, s, base) ? val : 0; diff --git a/samples/monster_generated.h b/samples/monster_generated.h index e89ec3a51e9..f14b60972b8 100644 --- a/samples/monster_generated.h +++ b/samples/monster_generated.h @@ -48,7 +48,7 @@ inline const Color (&EnumValuesColor())[3] { } inline const char * const *EnumNamesColor() { - static const char * const names[] = { + static const char * const names[4] = { "Red", "Green", "Blue", @@ -79,7 +79,7 @@ inline const Equipment (&EnumValuesEquipment())[2] { } inline const char * const *EnumNamesEquipment() { - static const char * const names[] = { + static const char * const names[3] = { "NONE", "Weapon", nullptr diff --git a/src/idl_gen_cpp.cpp b/src/idl_gen_cpp.cpp index 17da0693e1a..ef112cd75bb 100644 --- a/src/idl_gen_cpp.cpp +++ b/src/idl_gen_cpp.cpp @@ -28,6 +28,24 @@ namespace flatbuffers { // Pedantic warning free version of toupper(). inline char ToUpper(char c) { return static_cast(::toupper(c)); } +// Make numerical literal with type-suffix. +// This function is only needed for C++! Other languages do not need it. +static inline std::string NumToStringCpp(std::string val, BaseType type) { + // Avoid issues with -2147483648, -9223372036854775808. + // Replace string comparisons by StringToNumber? + switch (type) { + case BASE_TYPE_INT: + return (val != "-2147483648") ? val : ("(-2147483647 - 1)"); + case BASE_TYPE_ULONG: return (val == "0") ? val : (val + "ULL"); + case BASE_TYPE_LONG: + if (val == "-9223372036854775808") + return "(-9223372036854775807LL - 1LL)"; + else + return (val == "0") ? val : (val + "LL"); + default: return val; + } +} + static std::string GeneratedFileName(const std::string &path, const std::string &file_name) { return path + file_name + "_generated.h"; @@ -789,7 +807,7 @@ class CppGenerator : public BaseGenerator { code_.SetValue("NUM_FIELDS", NumToString(num_fields)); std::vector names; std::vector types; - bool consecutive_enum_from_zero = true; + if (struct_def) { for (auto it = struct_def->fields.vec.begin(); it != struct_def->fields.vec.end(); ++it) { @@ -804,9 +822,6 @@ class CppGenerator : public BaseGenerator { names.push_back(Name(ev)); types.push_back(enum_def->is_union ? ev.union_type : Type(enum_def->underlying_type)); - if (static_cast(it - enum_def->Vals().begin()) != ev.value) { - consecutive_enum_from_zero = false; - } } } std::string ts; @@ -851,12 +866,16 @@ class CppGenerator : public BaseGenerator { ns += "\"" + *it + "\""; } std::string vs; + const auto consecutive_enum_from_zero = + enum_def && enum_def->MinValue()->IsZero() && + ((enum_def->size() - 1) == enum_def->Distance()); if (enum_def && !consecutive_enum_from_zero) { for (auto it = enum_def->Vals().begin(); it != enum_def->Vals().end(); ++it) { const auto &ev = **it; if (!vs.empty()) vs += ", "; - vs += NumToString(ev.value); + vs += NumToStringCpp(enum_def->ToString(ev), + enum_def->underlying_type.base_type); } } else if (struct_def && struct_def->fixed) { for (auto it = struct_def->fields.vec.begin(); @@ -883,6 +902,7 @@ class CppGenerator : public BaseGenerator { code_ += " };"; } if (!vs.empty()) { + // Problem with uint64_t values greate than 9223372036854775807ULL. code_ += " static const int64_t values[] = { {{VALUES}} };"; } auto has_names = @@ -907,6 +927,7 @@ class CppGenerator : public BaseGenerator { // Generate an enum declaration, // an enum string lookup table, // and an enum array of values + void GenEnum(const EnumDef &enum_def) { code_.SetValue("ENUM_NAME", Name(enum_def)); code_.SetValue("BASE_TYPE", GenTypeBasic(enum_def.underlying_type, false)); @@ -914,24 +935,31 @@ class CppGenerator : public BaseGenerator { GenComment(enum_def.doc_comment); code_ += GenEnumDecl(enum_def) + "\\"; - if (parser_.opts.scoped_enums) code_ += " : {{BASE_TYPE}}\\"; + // MSVC doesn't support int64/uint64 enum without explicit declared enum type. + // The value 4611686018427387904ULL 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_ += " {"; - int64_t anyv = 0; - const EnumVal *minv = nullptr, *maxv = nullptr; for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) { const auto &ev = **it; - - GenComment(ev.doc_comment, " "); + if(!ev.doc_comment.empty()){ + auto prefix = code_.GetValue("SEP") + " "; + GenComment(ev.doc_comment, prefix.c_str()); + code_.SetValue("SEP", ""); + } code_.SetValue("KEY", GenEnumValDecl(enum_def, Name(ev))); - code_.SetValue("VALUE", NumToString(ev.value)); + code_.SetValue("VALUE", + NumToStringCpp(enum_def.ToString(ev), + enum_def.underlying_type.base_type)); code_ += "{{SEP}} {{KEY}} = {{VALUE}}\\"; code_.SetValue("SEP", ",\n"); - - minv = !minv || minv->value > ev.value ? &ev : minv; - maxv = !maxv || maxv->value < ev.value ? &ev : maxv; - anyv |= ev.value; } + const EnumVal *minv = enum_def.MinValue(); + const EnumVal *maxv = enum_def.MaxValue(); if (parser_.opts.scoped_enums || parser_.opts.prefixed_enums) { FLATBUFFERS_ASSERT(minv && maxv); @@ -943,7 +971,9 @@ class CppGenerator : public BaseGenerator { code_ += "{{SEP}} {{KEY}} = {{VALUE}}\\"; code_.SetValue("KEY", GenEnumValDecl(enum_def, "ANY")); - code_.SetValue("VALUE", NumToString(anyv)); + code_.SetValue("VALUE", + NumToStringCpp(enum_def.AllFlags(), + enum_def.underlying_type.base_type)); code_ += "{{SEP}} {{KEY}} = {{VALUE}}\\"; } else { // MIN & MAX are useless for bit_flags code_.SetValue("KEY", GenEnumValDecl(enum_def, "MIN")); @@ -984,22 +1014,24 @@ class CppGenerator : public BaseGenerator { // 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.vals.vec.back()->value - enum_def.vals.vec.front()->value + 1; + auto range = enum_def.Distance(); // Average distance between values above which we consider a table // "too sparse". Change at will. - static const int kMaxSparseness = 5; - if (range / static_cast(enum_def.vals.vec.size()) < - kMaxSparseness) { + static const uint64_t kMaxSparseness = 5; + if (range / static_cast(enum_def.size()) < kMaxSparseness) { code_ += "inline const char * const *EnumNames{{ENUM_NAME}}() {"; - code_ += " static const char * const names[] = {"; + code_ += " static const char * const names[" + + NumToString(range + 1 + 1) + "] = {"; - auto val = enum_def.Vals().front()->value; + auto val = enum_def.Vals().front(); for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) { - const auto &ev = **it; - while (val++ != ev.value) { code_ += " \"\","; } - code_ += " \"" + Name(ev) + "\","; + auto ev = *it; + for (auto k = enum_def.Distance(val, ev); k > 1; --k) { + code_ += " \"\","; + } + val = ev; + code_ += " \"" + Name(*ev) + "\","; } code_ += " nullptr"; code_ += " };"; @@ -1011,13 +1043,13 @@ class CppGenerator : public BaseGenerator { code_ += "inline const char *EnumName{{ENUM_NAME}}({{ENUM_NAME}} e) {"; code_ += " if (e < " + - GetEnumValUse(enum_def, *enum_def.vals.vec.front()) + - " || e > " + GetEnumValUse(enum_def, *enum_def.vals.vec.back()) + + GetEnumValUse(enum_def, *enum_def.MinValue()) + + " || e > " + GetEnumValUse(enum_def, *enum_def.MaxValue()) + ") return \"\";"; code_ += " const size_t index = static_cast(e)\\"; - if (enum_def.vals.vec.front()->value) { - auto vals = GetEnumValUse(enum_def, *enum_def.vals.vec.front()); + if (enum_def.MinValue()->IsNonZero()) { + auto vals = GetEnumValUse(enum_def, *enum_def.MinValue()); code_ += " - static_cast(" + vals + ")\\"; } code_ += ";"; @@ -1067,8 +1099,8 @@ class CppGenerator : public BaseGenerator { if (parser_.opts.generate_object_based_api && enum_def.is_union) { // Generate a union type code_.SetValue("NAME", Name(enum_def)); - code_.SetValue("NONE", - GetEnumValUse(enum_def, *enum_def.vals.Lookup("NONE"))); + FLATBUFFERS_ASSERT(enum_def.Lookup("NONE")); + code_.SetValue("NONE", GetEnumValUse(enum_def, *enum_def.Lookup("NONE"))); code_ += "struct {{NAME}}Union {"; code_ += " {{NAME}} type;"; @@ -1362,8 +1394,8 @@ class CppGenerator : public BaseGenerator { code_ += ""; // Union Reset() function. - code_.SetValue("NONE", - GetEnumValUse(enum_def, *enum_def.vals.Lookup("NONE"))); + FLATBUFFERS_ASSERT(enum_def.Lookup("NONE")); + code_.SetValue("NONE", GetEnumValUse(enum_def, *enum_def.Lookup("NONE"))); code_ += "inline void {{ENUM_NAME}}Union::Reset() {"; code_ += " switch (type) {"; @@ -1429,18 +1461,19 @@ class CppGenerator : public BaseGenerator { if (IsFloat(field.value.type.base_type)) return float_const_gen_.GenFloatConstant(field); else - return field.value.constant; + return NumToStringCpp(field.value.constant, field.value.type.base_type); } std::string GetDefaultScalarValue(const FieldDef &field, bool is_ctor) { if (field.value.type.enum_def && IsScalar(field.value.type.base_type)) { - auto ev = field.value.type.enum_def->ReverseLookup( - StringToInt(field.value.constant.c_str()), false); + auto ev = field.value.type.enum_def->FindByValue(field.value.constant); if (ev) { return WrapInNameSpace(field.value.type.enum_def->defined_namespace, GetEnumValUse(*field.value.type.enum_def, *ev)); } else { - return GenUnderlyingCast(field, true, field.value.constant); + return GenUnderlyingCast( + field, true, + NumToStringCpp(field.value.constant, field.value.type.base_type)); } } else if (field.value.type.base_type == BASE_TYPE_BOOL) { return field.value.constant == "0" ? "false" : "true"; diff --git a/src/idl_gen_dart.cpp b/src/idl_gen_dart.cpp index 2141eb389ee..c97681b775c 100644 --- a/src/idl_gen_dart.cpp +++ b/src/idl_gen_dart.cpp @@ -242,9 +242,9 @@ class DartGenerator : public BaseGenerator { // holes. if (!is_bit_flags) { code += " static const int minValue = " + - NumToString(enum_def.vals.vec.front()->value) + ";\n"; + enum_def.ToString(*enum_def.MinValue()) + ";\n"; code += " static const int maxValue = " + - NumToString(enum_def.vals.vec.back()->value) + ";\n"; + enum_def.ToString(*enum_def.MaxValue()) + ";\n"; } code += @@ -259,13 +259,13 @@ class DartGenerator : public BaseGenerator { GenDocComment(ev.doc_comment, &code, "", " "); } code += " static const " + name + " " + ev.name + " = "; - code += "const " + name + "._(" + NumToString(ev.value) + ");\n"; + code += "const " + name + "._(" + enum_def.ToString(ev) + ");\n"; } code += " static get values => {"; for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) { auto &ev = **it; - code += NumToString(ev.value) + ": " + ev.name + ","; + code += enum_def.ToString(ev) + ": " + ev.name + ","; } code += "};\n\n"; @@ -507,7 +507,7 @@ class DartGenerator : public BaseGenerator { auto &ev = **en_it; auto enum_name = NamespaceAliasFromUnionType(ev.name); - code += " case " + NumToString(ev.value) + ": return " + + code += " case " + enum_def.ToString(ev) + ": return " + enum_name + ".reader.vTableGet(_bc, _bcOffset, " + NumToString(field.value.offset) + ", null);\n"; } diff --git a/src/idl_gen_fbs.cpp b/src/idl_gen_fbs.cpp index 5a85a955d68..e5f3723cbcd 100644 --- a/src/idl_gen_fbs.cpp +++ b/src/idl_gen_fbs.cpp @@ -102,7 +102,7 @@ std::string GenerateFBS(const Parser &parser, const std::string &file_name) { if (enum_def.is_union) schema += " " + GenType(ev.union_type) + ",\n"; else - schema += " " + ev.name + " = " + NumToString(ev.value) + ",\n"; + schema += " " + ev.name + " = " + enum_def.ToString(ev) + ",\n"; } schema += "}\n\n"; } diff --git a/src/idl_gen_general.cpp b/src/idl_gen_general.cpp index fe793bf3bc8..d4338e3ad55 100644 --- a/src/idl_gen_general.cpp +++ b/src/idl_gen_general.cpp @@ -439,21 +439,12 @@ class GeneralGenerator : public BaseGenerator { } std::string GenEnumDefaultValue(const FieldDef &field) const { - auto& value = field.value; - auto enum_def = value.type.enum_def; - auto vec = enum_def->vals.vec; - auto default_value = StringToInt(value.constant.c_str()); - - auto result = value.constant; - for (auto it = vec.begin(); it != vec.end(); ++it) { - auto enum_val = **it; - if (enum_val.value == default_value) { - result = WrapInNameSpace(*enum_def) + "." + enum_val.name; - break; - } - } - - return result; + auto &value = field.value; + FLATBUFFERS_ASSERT(value.type.enum_def); + auto &enum_def = *value.type.enum_def; + auto enum_val = enum_def.FindByValue(value.constant); + return enum_val ? (WrapInNameSpace(enum_def) + "." + enum_val->name) + : value.constant; } std::string GenDefaultValue(const FieldDef &field, bool enableLangOverrides) const { @@ -552,7 +543,7 @@ class GeneralGenerator : public BaseGenerator { code += GenTypeBasic(enum_def.underlying_type, false); } code += " " + ev.name + " = "; - code += NumToString(ev.value); + code += enum_def.ToString(ev); code += lang_.enum_separator; } @@ -562,21 +553,22 @@ class GeneralGenerator : public BaseGenerator { // 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.vals.vec.back()->value - - enum_def.vals.vec.front()->value + 1; + auto range = enum_def.Distance(); // Average distance between values above which we consider a table // "too sparse". Change at will. - static const int kMaxSparseness = 5; - if (range / static_cast(enum_def.vals.vec.size()) < - kMaxSparseness) { + static const uint64_t kMaxSparseness = 5; + if (range / static_cast(enum_def.size()) < kMaxSparseness) { code += "\n public static"; code += lang_.const_decl; code += lang_.string_type; code += "[] names = { "; - auto val = enum_def.Vals().front()->value; + auto val = enum_def.Vals().front(); for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) { - while (val++ != (*it)->value) code += "\"\", "; + auto ev = *it; + for (auto k = enum_def.Distance(val, ev); k > 1; --k) + code += "\"\", "; + val = ev; code += "\"" + (*it)->name + "\", "; } code += "};\n\n"; @@ -584,8 +576,8 @@ class GeneralGenerator : public BaseGenerator { code += lang_.string_type; code += " " + MakeCamel("name", lang_.first_camel_upper); code += "(int e) { return names[e"; - if (enum_def.vals.vec.front()->value) - code += " - " + enum_def.vals.vec.front()->name; + if (enum_def.MinValue()->IsNonZero()) + code += " - " + enum_def.MinValue()->name; code += "]; }\n"; } } diff --git a/src/idl_gen_go.cpp b/src/idl_gen_go.cpp index 412d1e820de..f6119cb3f8a 100644 --- a/src/idl_gen_go.cpp +++ b/src/idl_gen_go.cpp @@ -162,7 +162,7 @@ class GoGenerator : public BaseGenerator { code += " "; code += GetEnumTypeName(enum_def); code += " = "; - code += NumToString(ev.value) + "\n"; + code += enum_def.ToString(ev) + "\n"; } // End enum code. diff --git a/src/idl_gen_js_ts.cpp b/src/idl_gen_js_ts.cpp index fea46208b5a..3f47ff9ae7d 100644 --- a/src/idl_gen_js_ts.cpp +++ b/src/idl_gen_js_ts.cpp @@ -359,13 +359,13 @@ class JsTsGenerator : public BaseGenerator { // Generate mapping between EnumName: EnumValue(int) if (reverse) { - code += " " + NumToString(ev.value); + code += " " + enum_def.ToString(ev); code += lang_.language == IDLOptions::kTs ? "= " : ": "; code += "'" + ev.name + "'"; } else { code += " " + ev.name; code += lang_.language == IDLOptions::kTs ? "= " : ": "; - code += NumToString(ev.value); + code += enum_def.ToString(ev); } code += (it + 1) != enum_def.Vals().end() ? ",\n" : "\n"; diff --git a/src/idl_gen_lobster.cpp b/src/idl_gen_lobster.cpp index fe23d970db9..b2e8f423668 100644 --- a/src/idl_gen_lobster.cpp +++ b/src/idl_gen_lobster.cpp @@ -263,7 +263,7 @@ class LobsterGenerator : public BaseGenerator { auto &ev = **it; GenComment(ev.doc_comment, code_ptr, nullptr, " "); code += " " + enum_def.name + "_" + NormalizedName(ev) + " = " + - NumToString(ev.value); + enum_def.ToString(ev); if (it + 1 != enum_def.Vals().end()) code += ","; code += "\n"; } diff --git a/src/idl_gen_lua.cpp b/src/idl_gen_lua.cpp index b26f9070daf..deb66c9c53f 100644 --- a/src/idl_gen_lua.cpp +++ b/src/idl_gen_lua.cpp @@ -111,8 +111,8 @@ namespace lua { // A single enum member. void EnumMember(const EnumDef &enum_def, const EnumVal &ev, std::string *code_ptr) { std::string &code = *code_ptr; - code += std::string(Indent) + NormalizedName(ev) + " = " + NumToString(ev.value) + ",\n"; - (void)enum_def; + code += std::string(Indent) + NormalizedName(ev) + " = " + + enum_def.ToString(ev) + ",\n"; } // End enum code. diff --git a/src/idl_gen_php.cpp b/src/idl_gen_php.cpp index a4b9a4694e2..b79a4979bdc 100644 --- a/src/idl_gen_php.cpp +++ b/src/idl_gen_php.cpp @@ -125,8 +125,7 @@ class PhpGenerator : public BaseGenerator { code += Indent + "const "; code += ev.name; code += " = "; - code += NumToString(ev.value) + ";\n"; - (void)enum_def; + code += enum_def.ToString(ev) + ";\n"; } // End enum code. diff --git a/src/idl_gen_python.cpp b/src/idl_gen_python.cpp index f2688e4e133..556869ee953 100644 --- a/src/idl_gen_python.cpp +++ b/src/idl_gen_python.cpp @@ -118,8 +118,7 @@ class PythonGenerator : public BaseGenerator { code += Indent; code += NormalizedName(ev); code += " = "; - code += NumToString(ev.value) + "\n"; - (void)enum_def; + code += enum_def.ToString(ev) + "\n"; } // End enum code. diff --git a/src/idl_gen_rust.cpp b/src/idl_gen_rust.cpp index 23fd34a76fb..81a1f6f3bee 100644 --- a/src/idl_gen_rust.cpp +++ b/src/idl_gen_rust.cpp @@ -589,20 +589,17 @@ class RustGenerator : public BaseGenerator { code_ += "#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]"; code_ += "pub enum " + Name(enum_def) + " {"; - int64_t anyv = 0; - const EnumVal *minv = nullptr, *maxv = nullptr; for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) { const auto &ev = **it; GenComment(ev.doc_comment, " "); code_.SetValue("KEY", Name(ev)); - code_.SetValue("VALUE", NumToString(ev.value)); + code_.SetValue("VALUE", enum_def.ToString(ev)); code_ += " {{KEY}} = {{VALUE}},"; - - minv = !minv || minv->value > ev.value ? &ev : minv; - maxv = !maxv || maxv->value < ev.value ? &ev : maxv; - anyv |= ev.value; } + const EnumVal *minv = enum_def.MinValue(); + const EnumVal *maxv = enum_def.MaxValue(); + FLATBUFFERS_ASSERT(minv && maxv); code_ += ""; code_ += "}"; @@ -611,8 +608,8 @@ class RustGenerator : public BaseGenerator { code_.SetValue("ENUM_NAME", Name(enum_def)); code_.SetValue("ENUM_NAME_SNAKE", MakeSnakeCase(Name(enum_def))); code_.SetValue("ENUM_NAME_CAPS", MakeUpper(MakeSnakeCase(Name(enum_def)))); - code_.SetValue("ENUM_MIN_BASE_VALUE", NumToString(minv->value)); - code_.SetValue("ENUM_MAX_BASE_VALUE", NumToString(maxv->value)); + code_.SetValue("ENUM_MIN_BASE_VALUE", enum_def.ToString(*minv)); + code_.SetValue("ENUM_MAX_BASE_VALUE", enum_def.ToString(*maxv)); // Generate enum constants, and impls for Follow, EndianScalar, and Push. code_ += "const ENUM_MIN_{{ENUM_NAME_CAPS}}: {{BASE_TYPE}} = \\"; @@ -671,24 +668,23 @@ class RustGenerator : public BaseGenerator { // 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.vals.vec.back()->value - enum_def.vals.vec.front()->value + 1; + auto range = enum_def.Distance(); // Average distance between values above which we consider a table // "too sparse". Change at will. - static const int kMaxSparseness = 5; - if (range / static_cast(enum_def.vals.vec.size()) < - kMaxSparseness) { + static const uint64_t kMaxSparseness = 5; + if (range / static_cast(enum_def.size()) < kMaxSparseness) { code_ += "#[allow(non_camel_case_types)]"; code_ += "const ENUM_NAMES_{{ENUM_NAME_CAPS}}:[&'static str; " + - NumToString(range) + "] = ["; + NumToString(range + 1) + "] = ["; - auto val = enum_def.Vals().front()->value; + auto val = enum_def.Vals().front(); for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) { - const auto &ev = **it; - while (val++ != ev.value) { code_ += " \"\","; } - auto suffix = *it != enum_def.vals.vec.back() ? "," : ""; - code_ += " \"" + Name(ev) + "\"" + suffix; + auto ev = *it; + for(auto k=enum_def.Distance(val, ev); k > 1; --k) { code_ += " \"\","; } + val = ev; + auto suffix = *it != enum_def.Vals().back() ? "," : ""; + code_ += " \"" + Name(*ev) + "\"" + suffix; } code_ += "];"; code_ += ""; @@ -697,8 +693,8 @@ class RustGenerator : public BaseGenerator { "&'static str {"; code_ += " let index = e as {{BASE_TYPE}}\\"; - if (enum_def.vals.vec.front()->value) { - auto vals = GetEnumValUse(enum_def, *enum_def.vals.vec.front()); + if (enum_def.MinValue()->IsNonZero()) { + auto vals = GetEnumValUse(enum_def, *enum_def.MinValue()); code_ += " - " + vals + " as {{BASE_TYPE}}\\"; } code_ += ";"; diff --git a/src/idl_parser.cpp b/src/idl_parser.cpp index 70f6cabe7ef..ce7e176b7d8 100644 --- a/src/idl_parser.cpp +++ b/src/idl_parser.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include @@ -674,14 +675,6 @@ CheckedError Parser::ParseField(StructDef &struct_def) { "default values currently only supported for scalars in tables"); ECHECK(ParseSingleValue(&field->name, field->value, true)); } - if (type.enum_def && - !type.enum_def->is_union && - !type.enum_def->attributes.Lookup("bit_flags") && - !type.enum_def->ReverseLookup(StringToInt( - field->value.constant.c_str()))) { - return Error("default value of " + field->value.constant + " for field " + - name + " is not part of enum " + type.enum_def->name); - } // Append .0 if the value has not it (skip hex and scientific floats). // This suffix needed for generated C++ code. if (IsFloat(type.base_type)) { @@ -697,14 +690,29 @@ CheckedError Parser::ParseField(StructDef &struct_def) { field->value.constant += ".0"; } } - - if (type.enum_def && IsScalar(type.base_type) && !struct_def.fixed && - !type.enum_def->attributes.Lookup("bit_flags") && - !type.enum_def->ReverseLookup(StringToInt( - field->value.constant.c_str()))) - Warning("enum " + type.enum_def->name + - " does not have a declaration for this field\'s default of " + - field->value.constant); + if (type.enum_def) { + // The type.base_type can only be scalar, union or vector. + // Table, struct or string can't have enum_def. + // Default value of union and vector in NONE, NULL translated to "0". + FLATBUFFERS_ASSERT(IsInteger(type.base_type) || + (type.base_type == BASE_TYPE_UNION) || + (type.base_type == BASE_TYPE_VECTOR)); + auto check = true; + if (type.base_type == BASE_TYPE_VECTOR) { + // Vector doesn't have initialization list. + FLATBUFFERS_ASSERT(field->value.constant == "0"); + check = false; + } + if (check) { + // All union's enum must have the NONE ("0") value. + auto in_enum = type.enum_def->attributes.Lookup("bit_flags") || + type.enum_def->FindByValue(field->value.constant); + if (false == in_enum) + return Error("default value of " + field->value.constant + + " for field " + name + " is not part of enum " + + type.enum_def->name); + } + } field->doc_comment = dc; ECHECK(ParseMetaData(&field->attributes)); @@ -1336,42 +1344,33 @@ CheckedError Parser::TryTypedValue(const std::string *name, int dtoken, CheckedError Parser::ParseEnumFromString(const Type &type, std::string *result) { + const auto base_type = + type.enum_def ? type.enum_def->underlying_type.base_type : type.base_type; + if (!IsInteger(base_type)) return Error("not a valid value for this field"); int64_t i64 = 0; - // Parse one or more enum identifiers, separated by spaces. - const char *next = attribute_.c_str(); - do { - const char *divider = strchr(next, ' '); - std::string word; - if (divider) { - word = std::string(next, divider); - next = divider + strspn(divider, " "); + for (size_t pos = 0; pos != std::string::npos;) { + const auto delim = attribute_.find_first_of(' ', pos); + const auto last = (std::string::npos == delim); + auto word = attribute_.substr(pos, !last ? delim - pos : std::string::npos); + pos = !last ? delim + 1 : std::string::npos; + const EnumVal *ev = nullptr; + if (type.enum_def) { + ev = type.enum_def->Lookup(word); } else { - word = next; - next += word.length(); - } - if (type.enum_def) { // The field has an enum type - auto enum_val = type.enum_def->vals.Lookup(word); - if (!enum_val) - return Error("unknown enum value: " + word + - ", for enum: " + type.enum_def->name); - i64 |= enum_val->value; - } else { // No enum type, probably integral field. - if (!IsInteger(type.base_type)) - return Error("not a valid value for this field: " + word); - // TODO: could check if its a valid number constant here. - const char *dot = strrchr(word.c_str(), '.'); - if (!dot) + auto dot = word.find_first_of('.'); + if (std::string::npos == dot) return Error("enum values need to be qualified by an enum type"); - std::string enum_def_str(word.c_str(), dot); - std::string enum_val_str(dot + 1, word.c_str() + word.length()); - auto enum_def = LookupEnum(enum_def_str); + auto enum_def_str = word.substr(0, dot); + const auto enum_def = LookupEnum(enum_def_str); if (!enum_def) return Error("unknown enum: " + enum_def_str); - auto enum_val = enum_def->vals.Lookup(enum_val_str); - if (!enum_val) return Error("unknown enum value: " + enum_val_str); - i64 |= enum_val->value; + auto enum_val_str = word.substr(dot + 1); + ev = enum_def->Lookup(enum_val_str); } - } while (*next); - *result = NumToString(i64); + if (!ev) return Error("unknown enum value: " + word); + i64 |= ev->GetAsInt64(); + } + *result = IsUnsigned(base_type) ? NumToString(static_cast(i64)) + : NumToString(i64); return NoError(); } @@ -1616,7 +1615,209 @@ StructDef *Parser::LookupCreateStruct(const std::string &name, return struct_def; } -CheckedError Parser::ParseEnum(bool is_union, EnumDef **dest) { +const EnumVal* EnumDef::MinValue() const { + return vals.vec.empty() ? nullptr : vals.vec.front(); +} +const EnumVal* EnumDef::MaxValue() const { + return vals.vec.empty() ? nullptr : vals.vec.back(); +} + +template static uint64_t EnumDistanceImpl(T e1, T e2) { + if(e1 < e2) std::swap(e1, e2); + // Signed overflow may occur, use unsigned calculation. + // The unsigned overflow is well-defined by C++ standard (modulo 2^n). + return static_cast(e1) - static_cast(e2); +} + +uint64_t EnumDef::Distance(const EnumVal *v1, const EnumVal *v2) const { + return IsUInt64() ? EnumDistanceImpl(v1->GetAsUInt64(), v2->GetAsUInt64()) + : EnumDistanceImpl(v1->GetAsInt64(), v2->GetAsInt64()); +} + +std::string EnumDef::AllFlags() const { + FLATBUFFERS_ASSERT(attributes.Lookup("bit_flags")); + int64_t i64 = 0; + for (auto it = Vals().begin(); it != Vals().end(); ++it) { + i64 |= (*it)->GetAsInt64(); + } + return IsUInt64() ? NumToString(static_cast(i64)) + : NumToString(i64); +} + +EnumVal *EnumDef::FindByValue(const std::string &constant) const { + int64_t i64; + auto done = false; + if (IsUInt64()) { + uint64_t u64; + done = StringToNumber(constant.c_str(), &u64); + i64 = static_cast(u64); + } else { + done = StringToNumber(constant.c_str(), &i64); + } + FLATBUFFERS_ASSERT(done); + if (!done) return nullptr; + for (auto it = Vals().begin(); it != Vals().end(); ++it) { + auto ev = *it; + if (ev->GetAsInt64() == i64) return ev; + } + return nullptr; +} + +void EnumDef::SortByValue() { + auto &v = vals.vec; + if (IsUInt64()) + std::sort(v.begin(), v.end(), [](const EnumVal *e1, const EnumVal *e2) { + return e1->GetAsUInt64() < e2->GetAsUInt64(); + }); + else + std::sort(v.begin(), v.end(), [](const EnumVal *e1, const EnumVal *e2) { + return e1->GetAsInt64() < e2->GetAsInt64(); + }); +} + +void EnumDef::RemoveDuplicates() { + // This method depends form SymbolTable implementation! + // 1) vals.vec - owner (raw pointer) + // 2) vals.dict - access map + auto first = vals.vec.begin(); + auto last = vals.vec.end(); + if (first == last) return; + auto result = first; + while (++first != last) { + if ((*result)->value != (*first)->value) { + *(++result) = *first; + } else { + auto ev = *first; + for (auto it = vals.dict.begin(); it != vals.dict.end(); ++it) { + if (it->second == ev) + it->second = *result; // reassign + } + delete ev; // delete enum value + *first = nullptr; + } + } + vals.vec.erase(++result, last); +} + +template void EnumDef::ChangeEnumValue(EnumVal *ev, T new_value) { + ev->value = static_cast(new_value); +} + +namespace EnumHelper { +template struct EnumValType { typedef int64_t type; }; +template<> struct EnumValType { typedef uint64_t type; }; +} + +struct EnumValBuilder { + EnumVal *CreateEnumerator(const std::string &ev_name) { + FLATBUFFERS_ASSERT(!temp); + auto first = enum_def.vals.vec.empty(); + user_value = first; + temp = new EnumVal(ev_name, first ? 0 : enum_def.vals.vec.back()->value); + return temp; + } + + EnumVal* CreateEnumerator(const std::string& ev_name, int64_t val) { + FLATBUFFERS_ASSERT(!temp); + user_value = true; + temp = new EnumVal(ev_name, val); + return temp; + } + + FLATBUFFERS_CHECKED_ERROR AcceptEnumerator(const std::string &name) { + FLATBUFFERS_ASSERT(temp); + ECHECK(ValidateValue(&temp->value, false == user_value)); + FLATBUFFERS_ASSERT((temp->union_type.enum_def == nullptr) || + (temp->union_type.enum_def == &enum_def)); + //temp->union_type.enum_def = &enum_def; + auto not_unique = enum_def.vals.Add(name, temp); + temp = nullptr; + if (not_unique) return parser.Error("enum value already exists: " + name); + return NoError(); + } + + FLATBUFFERS_CHECKED_ERROR AcceptEnumerator() { + return AcceptEnumerator(temp->name); + } + + FLATBUFFERS_CHECKED_ERROR AssignEnumeratorValue(const std::string& value) + { + user_value = true; + auto ascending = false; + if (enum_def.IsUInt64()) + { + uint64_t u64; + if (!StringToNumber(value.c_str(), &u64)) + return parser.Error(temp->name + " enum value does not fit, \"" + + value + "\""); + ascending = u64 > static_cast(temp->value); + temp->value = static_cast(u64); // well-defined since C++20. + } + else + { + int64_t i64; + if (!StringToNumber(value.c_str(), &i64)) + return parser.Error(temp->name + " enum value does not fit, \"" + + value + "\""); + ascending = i64 > temp->value; + temp->value = i64; + } + if (!ascending && strict_ascending && !enum_def.vals.vec.empty()) + return parser.Error("enum values must be specified in ascending order"); + else + return NoError(); + } + + template + inline FLATBUFFERS_CHECKED_ERROR ValidateImpl(int64_t *ev, int m) { + typedef typename EnumHelper::EnumValType::type T; // int64_t or uint64_t + static_assert(sizeof(T) == sizeof(int64_t), "invalid EnumValType"); + const auto v = static_cast(*ev); + auto up = static_cast((flatbuffers::numeric_limits::max)()); + auto dn = static_cast((flatbuffers::numeric_limits::lowest)()); + if (v < dn || v > (up - m)) { + return parser.Error("enum value does not fit, \"" + NumToString(v) + + (m ? " + 1\"" : "\"") + " out of " + + TypeToIntervalString()); + } + *ev = static_cast(v + m); // well-defined since C++20. + return NoError(); + } + + FLATBUFFERS_CHECKED_ERROR ValidateValue(int64_t *ev, bool next) { + // clang-format off + switch (enum_def.underlying_type.base_type) { + #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, \ + PTYPE, RTYPE) \ + case BASE_TYPE_##ENUM: { \ + if (!IsInteger(BASE_TYPE_##ENUM)) break; \ + return ValidateImpl(ev, next ? 1 : 0); \ + } + FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD); + #undef FLATBUFFERS_TD + default: break; + } + // clang-format on + return parser.Error("fatal: invalid enum underlying type"); + } + + EnumValBuilder(Parser &_parser, EnumDef &_enum_def, bool strict_order = true) + : parser(_parser), + enum_def(_enum_def), + temp(nullptr), + strict_ascending(strict_order), + user_value(false) {} + + ~EnumValBuilder() { delete temp; } + + Parser &parser; + EnumDef &enum_def; + EnumVal* temp; + const bool strict_ascending; + bool user_value; +}; + +CheckedError Parser::ParseEnum(const bool is_union, EnumDef **dest) { std::vector enum_comment = doc_comment_; NEXT(); std::string enum_name = attribute_; @@ -1643,33 +1844,33 @@ CheckedError Parser::ParseEnum(bool is_union, EnumDef **dest) { enum_def->underlying_type.enum_def = enum_def; } ECHECK(ParseMetaData(&enum_def->attributes)); + const auto underlying_type = enum_def->underlying_type.base_type; + // Protobuf allows them to be specified in any order, so sort afterwards. + const auto strict_ascending = (false == opts.proto_mode); + EnumValBuilder evb(*this, *enum_def, strict_ascending); EXPECT('{'); - if (is_union) enum_def->vals.Add("NONE", new EnumVal("NONE", 0)); + // A lot of code expects that an enum is not-empty. + if (is_union || Is('}')) { + evb.CreateEnumerator("NONE"); + ECHECK(evb.AcceptEnumerator()); + } std::set> union_types; - for (;;) { + while(!Is('}')) { if (opts.proto_mode && attribute_ == "option") { ECHECK(ParseProtoOption()); } else { - auto value_name = attribute_; - auto full_name = value_name; - std::vector value_comment = doc_comment_; + auto &ev = *evb.CreateEnumerator(attribute_); + auto full_name = ev.name; + ev.doc_comment = doc_comment_; EXPECT(kTokenIdentifier); if (is_union) { - ECHECK(ParseNamespacing(&full_name, &value_name)); + ECHECK(ParseNamespacing(&full_name, &ev.name)); if (opts.union_value_namespacing) { // Since we can't namespace the actual enum identifiers, turn // namespace parts into part of the identifier. - value_name = full_name; - std::replace(value_name.begin(), value_name.end(), '.', '_'); + ev.name = full_name; + std::replace(ev.name.begin(), ev.name.end(), '.', '_'); } - } - auto prevsize = enum_def->vals.vec.size(); - auto prevvalue = prevsize > 0 ? enum_def->vals.vec.back()->value : 0; - auto &ev = *new EnumVal(value_name, 0); - if (enum_def->vals.Add(value_name, &ev)) - return Error("enum value already exists: " + value_name); - ev.doc_comment = value_comment; - if (is_union) { if (Is(':')) { NEXT(); ECHECK(ParseType(ev.union_type)); @@ -1679,52 +1880,20 @@ CheckedError Parser::ParseEnum(bool is_union, EnumDef **dest) { } else { ev.union_type = Type(BASE_TYPE_STRUCT, LookupCreateStruct(full_name)); } - if (!enum_def->uses_multiple_type_instances) { - auto union_type_key = std::make_pair(ev.union_type.base_type, ev.union_type.struct_def); - if (union_types.count(union_type_key) > 0) { - enum_def->uses_multiple_type_instances = true; - } else { - union_types.insert(union_type_key); - } + if (false == enum_def->uses_multiple_type_instances) { + auto ins = union_types.insert(std::make_pair( + ev.union_type.base_type, ev.union_type.struct_def)); + enum_def->uses_multiple_type_instances = (false == ins.second); } } + if (Is('=')) { NEXT(); - ECHECK(atot(attribute_.c_str(), *this, &ev.value)); + ECHECK(evb.AssignEnumeratorValue(attribute_)); EXPECT(kTokenIntegerConstant); - if (!opts.proto_mode && prevsize && - enum_def->vals.vec[prevsize - 1]->value >= ev.value) - return Error("enum values must be specified in ascending order"); - } else if (prevsize == 0) { - // already set to zero - } else if (prevvalue != flatbuffers::numeric_limits::max()) { - ev.value = prevvalue + 1; - } else { - return Error("enum value overflows"); } - // Check that value fits into the underlying type. - switch (enum_def->underlying_type.base_type) { - // clang-format off - #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, \ - PTYPE, RTYPE) \ - case BASE_TYPE_##ENUM: { \ - int64_t min_value = static_cast( \ - flatbuffers::numeric_limits::lowest()); \ - int64_t max_value = static_cast( \ - flatbuffers::numeric_limits::max()); \ - if (ev.value < min_value || ev.value > max_value) { \ - return Error( \ - "enum value does not fit [" + NumToString(min_value) + \ - "; " + NumToString(max_value) + "]"); \ - } \ - break; \ - } - FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD); - #undef FLATBUFFERS_TD - default: break; - // clang-format on - } + ECHECK(evb.AcceptEnumerator()); if (opts.proto_mode && Is('[')) { NEXT(); @@ -1735,18 +1904,38 @@ CheckedError Parser::ParseEnum(bool is_union, EnumDef **dest) { } if (!Is(opts.proto_mode ? ';' : ',')) break; NEXT(); - if (Is('}')) break; } EXPECT('}'); + + // At this point, the enum can be empty if input is invalid proto-file. + if (!enum_def->size()) + return Error("incomplete enum declaration, values not found"); + if (enum_def->attributes.Lookup("bit_flags")) { - for (auto it = enum_def->vals.vec.begin(); it != enum_def->vals.vec.end(); + const auto base_width = static_cast(8 * SizeOf(underlying_type)); + const auto is_small_signed = (false == IsUnsigned(underlying_type)) && + (SizeOf(underlying_type) < sizeof(int64_t)); + for (auto it = enum_def->Vals().begin(); it != enum_def->Vals().end(); ++it) { - if (static_cast((*it)->value) >= - SizeOf(enum_def->underlying_type.base_type) * 8) + auto ev = *it; + const auto u = ev->GetAsUInt64(); + if (u >= base_width) return Error("bit flag out of range of underlying integral type"); - (*it)->value = 1LL << (*it)->value; + auto flag = static_cast(1ULL << u); + // Problem: the flag can be sign-bit of the enum underlying type. + // Process this to prevent out of range. + if(is_small_signed && u == (base_width-1)) { + flag = -flag; // int8: (1ULL << 7) = 128 => -128. + } + enum_def->ChangeEnumValue(ev, flag); } + // Sorted order may be broken if the sign bit has been set. + enum_def->SortByValue(); } + + if(false == strict_ascending) + enum_def->SortByValue(); // Must be sorted to use MinValue/MaxValue. + if (dest) *dest = enum_def; types_.Add(current_namespace_->GetFullyQualifiedName(enum_def->name), new Type(BASE_TYPE_UNION, nullptr, enum_def)); @@ -1980,10 +2169,6 @@ CheckedError Parser::ParseNamespace() { return NoError(); } -static bool compareEnumVals(const EnumVal *a, const EnumVal *b) { - return a->value < b->value; -} - // Best effort parsing of .proto declarations, with the aim to turn them // in the closest corresponding FlatBuffer equivalent. // We parse everything as identifiers instead of keywords, since we don't @@ -2029,17 +2214,8 @@ CheckedError Parser::ParseProtoDecl() { EnumDef *enum_def; ECHECK(ParseEnum(false, &enum_def)); if (Is(';')) NEXT(); - // Protobuf allows them to be specified in any order, so sort afterwards. - auto &v = enum_def->vals.vec; - std::sort(v.begin(), v.end(), compareEnumVals); - // Temp: remove any duplicates, as .fbs files can't handle them. - for (auto it = v.begin(); it != v.end();) { - if (it != v.begin() && it[0]->value == it[-1]->value) - it = v.erase(it); - else - ++it; - } + enum_def->RemoveDuplicates(); } else if (IsIdent("syntax")) { // Skip these. NEXT(); EXPECT('='); @@ -2209,11 +2385,11 @@ CheckedError Parser::ParseProtoFields(StructDef *struct_def, bool isextend, return Error("oneof '" + name + "' cannot be mapped to a union because member '" + oneof_field.name + "' is not a table type."); - auto enum_val = new EnumVal(oneof_type.struct_def->name, - oneof_union->vals.vec.size()); - enum_val->union_type = oneof_type; - enum_val->doc_comment = oneof_field.doc_comment; - oneof_union->vals.Add(oneof_field.name, enum_val); + EnumValBuilder evb(*this, *oneof_union); + auto ev = evb.CreateEnumerator(oneof_type.struct_def->name); + ev->union_type = oneof_type; + ev->doc_comment = oneof_field.doc_comment; + ECHECK(evb.AcceptEnumerator(oneof_field.name)); } } else { EXPECT(';'); @@ -3195,9 +3371,9 @@ std::string Parser::ConformTo(const Parser &base) { for (auto evit = enum_def.Vals().begin(); evit != enum_def.Vals().end(); ++evit) { auto &enum_val = **evit; - auto enum_val_base = enum_def_base->vals.Lookup(enum_val.name); + auto enum_val_base = enum_def_base->Lookup(enum_val.name); if (enum_val_base) { - if (enum_val.value != enum_val_base->value) + if (enum_val != *enum_val_base) return "values differ for enum: " + enum_val.name; } } diff --git a/tests/generate_code.bat b/tests/generate_code.bat index fd335512cc0..8d1eed36d5c 100644 --- a/tests/generate_code.bat +++ b/tests/generate_code.bat @@ -20,6 +20,7 @@ if "%1"=="-b" set buildtype=%2 ..\%buildtype%\flatc.exe --cpp --java --js --ts --php --gen-mutable --reflect-names --gen-object-api --gen-compare --cpp-ptr-type flatbuffers::unique_ptr -o union_vector ./union_vector/union_vector.fbs || goto FAIL ..\%buildtype%\flatc.exe -b --schema --bfbs-comments --bfbs-builtins -I include_test monster_test.fbs || goto FAIL ..\%buildtype%\flatc.exe --jsonschema --schema -I include_test monster_test.fbs || goto FAIL +..\%buildtype%\flatc.exe --cpp --gen-compare --no-includes monster_enum.fbs || goto FAIL IF NOT "%MONSTER_EXTRA%"=="skip" ( @echo Generate MosterExtra diff --git a/tests/generate_code.sh b/tests/generate_code.sh index 40373a34e0a..3d11cfe5756 100755 --- a/tests/generate_code.sh +++ b/tests/generate_code.sh @@ -20,6 +20,7 @@ set -e ../flatc --cpp --java --csharp --js --ts --php --gen-mutable --reflect-names --gen-object-api --gen-compare --cpp-ptr-type flatbuffers::unique_ptr -o union_vector ./union_vector/union_vector.fbs ../flatc -b --schema --bfbs-comments --bfbs-builtins -I include_test monster_test.fbs ../flatc --jsonschema --schema -I include_test monster_test.fbs +../flatc --cpp --gen-compare --no-includes monster_enum.fbs ../flatc --cpp --java --csharp --python --gen-mutable --reflect-names --gen-object-api --gen-compare --no-includes monster_extra.fbs || goto FAIL cd ../samples ../flatc --cpp --lobster --gen-mutable --reflect-names --gen-object-api --gen-compare --cpp-ptr-type flatbuffers::unique_ptr monster.fbs diff --git a/tests/monster_enum.fbs b/tests/monster_enum.fbs new file mode 100644 index 00000000000..84e036cef3d --- /dev/null +++ b/tests/monster_enum.fbs @@ -0,0 +1,193 @@ +namespace MyGame; + +// Test pack of enums. +// 1. Check the parser +// 2. Check cpp code-generator + +// Valid empty enums +enum ME_I8 : int8 {} +enum ME_U8 : uint8 {} +enum ME_I16 : int16 {} +enum ME_U16 : uint16 {} +enum ME_I32 : int32 {} +enum ME_U32 : uint32 {} +enum ME_I64 : int64 {} +enum ME_U64 : uint64 {} + +// Unsigned enums with bit_flags. + +///DOC: ALL_FLAGS = 13835058055282164099ULL +enum MEFU64_V0 : uint64 (bit_flags) { + /// 1ULL + F00, + /// 2ULL + F01, + /// 128ULL + F07 = 7, + /// 256ULL + F08, + /// 4611686018427387904ULL + F62 = 62, + /// 9223372036854775808ULL + F63 +} + +///DOC: ALL_FLAGS = 0xFFFFFFFFFFFFFFFF +enum MEFU64_V1 : uint64 (bit_flags) { + F00, F01, F02, F03, F04, F05, F06, F07, F08, F09, + F10, F11, F12, F13, F14, F15, F16, F17, F18, F19, + F20, F21, F22, F23, F24, F25, F26, F27, F28, F29, + F30, F31, F32, F33, F34, F35, F36, F37, F38, F39, + F40, F41, F42, F43, F44, F45, F46, F47, F48, F49, + F50, F51, F52, F53, F54, F55, F56, F57, F58, F59, + F60, F61, F62, F63 +} + +///DOC: ALL_FLAGS = -4611686018427387517LL +enum MEFI64_V0 : int64 (bit_flags) { + F00, // 1LL + F01, // 2LL + F07 = 7, // 128LL + F08, // 256LL + F62 = 62, // 4611686018427387904LL + F63 // -9223372036854775808LL +} + +///DOC: ALL_FLAGS = -1LL +enum MEFI64_V1 : int64 (bit_flags) { + F00, F01, F02, F03, F04, F05, F06, F07, F08, F09, + F10, F11, F12, F13, F14, F15, F16, F17, F18, F19, + F20, F21, F22, F23, F24, F25, F26, F27, F28, F29, + F30, F31, F32, F33, F34, F35, F36, F37, F38, F39, + F40, F41, F42, F43, F44, F45, F46, F47, F48, F49, + F50, F51, F52, F53, F54, F55, F56, F57, F58, F59, + F60, F61, F62, F63 +} + +///DOC: ALL_FLAGS = 49539U +enum MEFU16_V0 : uint16 (bit_flags) { + F00, // 1U + F01, // 2U + F07 = 7, // 128U + F08, // 256U + F14 = 14, // 16384U + F15 // 32768U +} + +///DOC: ALL_FLAGS = -15997 +enum MEFI16_V0 : int16 (bit_flags) { + F00, // 1 + F01, // 2 + F07 = 7, // 128 + F08, // 256 + F14 = 14, // 16384 + F15 // -32768 +} + +// Common enums + +enum MECI8_V0 : int8 { + dn = -128, + dn_p1, // -127 + none = -1, + zero = 0, + one, + up = 127 +} + +enum MECU8_V0 : uint8 { + dn, + one, + up = 255 +} + +enum MECI16_V0 : int16 { + dn = -32768, + none = -1, + zero = 0, + one, + up = 32767 +} + +enum MECU16_V0 : uint16 { + dn, + one, + up = 65535 +} + +enum MECI32_V0 : int32 { + dn = -2147483648, + none = -1, + zero = 0, + one, + up = 2147483647 +} + +enum MECU32_V0 : uint32 { + dn, + one, + up = 4294967295 +} + +enum MECI64_V0 : int64 { + dn = -9223372036854775808, + dn_p1, // -9223372036854775807 + none = -1, + zero = 0, + one, + up = 9223372036854775807 +} + +enum MECU64_V0 : uint64 { + dn, + one, + up = 18446744073709551615 +} + +// #5108 +enum MerchantCanChanged : byte { x= 1, y, z, v, s} + +table MonsterEnumTest { + // Test code-generator with scalars (C++ requires LL/ULL suffixes). + int8_min : int8 = -128; + int8_max : int8 = 127; + int16_min : int16 = -32768; + int16_max : int16 = 32767; + int32_min : int32 = -2147483648; + int32_max : int32 = 2147483647; + int64_min : int64 = -9223372036854775808; + int64_max : int64 = 9223372036854775807; + + uint8_max : uint8 = 255; + uint16_max : uint16 = 65535; + uint32_max : uint32 = 4294967295; + uint64_max : uint64 = 18446744073709551615; + // Empty enum allowed by the grammar. + empty_i8 : ME_I8; + empty_u8 : ME_U8; + empty_i16 : ME_I16; + empty_u16 : ME_U16; + empty_i32 : ME_I32; + empty_u32 : ME_U32; + empty_i64 : ME_I64; + empty_u64 : ME_U64; + // 64-bit flags + u64_ef : MEFU64_V0 = "F63 F07 F08"; + i64_ef : MEFI64_V0 = "F63 F07 F08"; + // 64-bit common enums + u64_ec : MECU64_V0 = "dn one up"; // up + i64_ec1 : MECI64_V0 = "dn one"; // dn_p1 + i64_ec2 : MECI64_V0 = "up one"; // up + // 64-bit mixing + u64 : uint64 = "MECU64_V0.one MEFU64_V0.F63"; + i64 : int64 = "MECI64_V0.one MEFI64_V0.F63"; + // 16-bit flags + u16_ef : MEFU16_V0 = "F15 F08"; + i16_ef : MEFI16_V0 = "F15 F08"; + // 8-bit common enums + u8_ec : MECU8_V0 = "dn one up"; // up + i8_ec1 : MECI8_V0 = "dn one"; // dn_p1 + i8_ec2 : MECI8_V0 = "zero one up"; // up + // #5108 + fields_merchant_update:[MerchantCanChanged]; +} diff --git a/tests/monster_enum_generated.h b/tests/monster_enum_generated.h new file mode 100644 index 00000000000..382cc01025e --- /dev/null +++ b/tests/monster_enum_generated.h @@ -0,0 +1,1512 @@ +// automatically generated by the FlatBuffers compiler, do not modify + + +#ifndef FLATBUFFERS_GENERATED_MONSTERENUM_MYGAME_H_ +#define FLATBUFFERS_GENERATED_MONSTERENUM_MYGAME_H_ + +#include "flatbuffers/flatbuffers.h" + +namespace MyGame { + +struct MonsterEnumTest; + +enum ME_I8 { + ME_I8_NONE = 0, + ME_I8_MIN = ME_I8_NONE, + ME_I8_MAX = ME_I8_NONE +}; + +inline const ME_I8 (&EnumValuesME_I8())[1] { + static const ME_I8 values[] = { + ME_I8_NONE + }; + return values; +} + +inline const char * const *EnumNamesME_I8() { + static const char * const names[2] = { + "NONE", + nullptr + }; + return names; +} + +inline const char *EnumNameME_I8(ME_I8 e) { + if (e < ME_I8_NONE || e > ME_I8_NONE) return ""; + const size_t index = static_cast(e); + return EnumNamesME_I8()[index]; +} + +enum ME_U8 { + ME_U8_NONE = 0, + ME_U8_MIN = ME_U8_NONE, + ME_U8_MAX = ME_U8_NONE +}; + +inline const ME_U8 (&EnumValuesME_U8())[1] { + static const ME_U8 values[] = { + ME_U8_NONE + }; + return values; +} + +inline const char * const *EnumNamesME_U8() { + static const char * const names[2] = { + "NONE", + nullptr + }; + return names; +} + +inline const char *EnumNameME_U8(ME_U8 e) { + if (e < ME_U8_NONE || e > ME_U8_NONE) return ""; + const size_t index = static_cast(e); + return EnumNamesME_U8()[index]; +} + +enum ME_I16 { + ME_I16_NONE = 0, + ME_I16_MIN = ME_I16_NONE, + ME_I16_MAX = ME_I16_NONE +}; + +inline const ME_I16 (&EnumValuesME_I16())[1] { + static const ME_I16 values[] = { + ME_I16_NONE + }; + return values; +} + +inline const char * const *EnumNamesME_I16() { + static const char * const names[2] = { + "NONE", + nullptr + }; + return names; +} + +inline const char *EnumNameME_I16(ME_I16 e) { + if (e < ME_I16_NONE || e > ME_I16_NONE) return ""; + const size_t index = static_cast(e); + return EnumNamesME_I16()[index]; +} + +enum ME_U16 { + ME_U16_NONE = 0, + ME_U16_MIN = ME_U16_NONE, + ME_U16_MAX = ME_U16_NONE +}; + +inline const ME_U16 (&EnumValuesME_U16())[1] { + static const ME_U16 values[] = { + ME_U16_NONE + }; + return values; +} + +inline const char * const *EnumNamesME_U16() { + static const char * const names[2] = { + "NONE", + nullptr + }; + return names; +} + +inline const char *EnumNameME_U16(ME_U16 e) { + if (e < ME_U16_NONE || e > ME_U16_NONE) return ""; + const size_t index = static_cast(e); + return EnumNamesME_U16()[index]; +} + +enum ME_I32 { + ME_I32_NONE = 0, + ME_I32_MIN = ME_I32_NONE, + ME_I32_MAX = ME_I32_NONE +}; + +inline const ME_I32 (&EnumValuesME_I32())[1] { + static const ME_I32 values[] = { + ME_I32_NONE + }; + return values; +} + +inline const char * const *EnumNamesME_I32() { + static const char * const names[2] = { + "NONE", + nullptr + }; + return names; +} + +inline const char *EnumNameME_I32(ME_I32 e) { + if (e < ME_I32_NONE || e > ME_I32_NONE) return ""; + const size_t index = static_cast(e); + return EnumNamesME_I32()[index]; +} + +enum ME_U32 { + ME_U32_NONE = 0, + ME_U32_MIN = ME_U32_NONE, + ME_U32_MAX = ME_U32_NONE +}; + +inline const ME_U32 (&EnumValuesME_U32())[1] { + static const ME_U32 values[] = { + ME_U32_NONE + }; + return values; +} + +inline const char * const *EnumNamesME_U32() { + static const char * const names[2] = { + "NONE", + nullptr + }; + return names; +} + +inline const char *EnumNameME_U32(ME_U32 e) { + if (e < ME_U32_NONE || e > ME_U32_NONE) return ""; + const size_t index = static_cast(e); + return EnumNamesME_U32()[index]; +} + +enum ME_I64 : int64_t { + ME_I64_NONE = 0, + ME_I64_MIN = ME_I64_NONE, + ME_I64_MAX = ME_I64_NONE +}; + +inline const ME_I64 (&EnumValuesME_I64())[1] { + static const ME_I64 values[] = { + ME_I64_NONE + }; + return values; +} + +inline const char * const *EnumNamesME_I64() { + static const char * const names[2] = { + "NONE", + nullptr + }; + return names; +} + +inline const char *EnumNameME_I64(ME_I64 e) { + if (e < ME_I64_NONE || e > ME_I64_NONE) return ""; + const size_t index = static_cast(e); + return EnumNamesME_I64()[index]; +} + +enum ME_U64 : uint64_t { + ME_U64_NONE = 0, + ME_U64_MIN = ME_U64_NONE, + ME_U64_MAX = ME_U64_NONE +}; + +inline const ME_U64 (&EnumValuesME_U64())[1] { + static const ME_U64 values[] = { + ME_U64_NONE + }; + return values; +} + +inline const char * const *EnumNamesME_U64() { + static const char * const names[2] = { + "NONE", + nullptr + }; + return names; +} + +inline const char *EnumNameME_U64(ME_U64 e) { + if (e < ME_U64_NONE || e > ME_U64_NONE) return ""; + const size_t index = static_cast(e); + return EnumNamesME_U64()[index]; +} + +///DOC: ALL_FLAGS = 13835058055282164099ULL +enum MEFU64_V0 : uint64_t { + /// 1ULL + MEFU64_V0_F00 = 1ULL, + /// 2ULL + MEFU64_V0_F01 = 2ULL, + /// 128ULL + MEFU64_V0_F07 = 128ULL, + /// 256ULL + MEFU64_V0_F08 = 256ULL, + /// 4611686018427387904ULL + MEFU64_V0_F62 = 4611686018427387904ULL, + /// 9223372036854775808ULL + MEFU64_V0_F63 = 9223372036854775808ULL, + MEFU64_V0_NONE = 0, + MEFU64_V0_ANY = 13835058055282164099ULL +}; + +inline const MEFU64_V0 (&EnumValuesMEFU64_V0())[6] { + static const MEFU64_V0 values[] = { + MEFU64_V0_F00, + MEFU64_V0_F01, + MEFU64_V0_F07, + MEFU64_V0_F08, + MEFU64_V0_F62, + MEFU64_V0_F63 + }; + return values; +} + +inline const char *EnumNameMEFU64_V0(MEFU64_V0 e) { + switch (e) { + case MEFU64_V0_F00: return "F00"; + case MEFU64_V0_F01: return "F01"; + case MEFU64_V0_F07: return "F07"; + case MEFU64_V0_F08: return "F08"; + case MEFU64_V0_F62: return "F62"; + case MEFU64_V0_F63: return "F63"; + default: return ""; + } +} + +///DOC: ALL_FLAGS = 0xFFFFFFFFFFFFFFFF +enum MEFU64_V1 : uint64_t { + MEFU64_V1_F00 = 1ULL, + MEFU64_V1_F01 = 2ULL, + MEFU64_V1_F02 = 4ULL, + MEFU64_V1_F03 = 8ULL, + MEFU64_V1_F04 = 16ULL, + MEFU64_V1_F05 = 32ULL, + MEFU64_V1_F06 = 64ULL, + MEFU64_V1_F07 = 128ULL, + MEFU64_V1_F08 = 256ULL, + MEFU64_V1_F09 = 512ULL, + MEFU64_V1_F10 = 1024ULL, + MEFU64_V1_F11 = 2048ULL, + MEFU64_V1_F12 = 4096ULL, + MEFU64_V1_F13 = 8192ULL, + MEFU64_V1_F14 = 16384ULL, + MEFU64_V1_F15 = 32768ULL, + MEFU64_V1_F16 = 65536ULL, + MEFU64_V1_F17 = 131072ULL, + MEFU64_V1_F18 = 262144ULL, + MEFU64_V1_F19 = 524288ULL, + MEFU64_V1_F20 = 1048576ULL, + MEFU64_V1_F21 = 2097152ULL, + MEFU64_V1_F22 = 4194304ULL, + MEFU64_V1_F23 = 8388608ULL, + MEFU64_V1_F24 = 16777216ULL, + MEFU64_V1_F25 = 33554432ULL, + MEFU64_V1_F26 = 67108864ULL, + MEFU64_V1_F27 = 134217728ULL, + MEFU64_V1_F28 = 268435456ULL, + MEFU64_V1_F29 = 536870912ULL, + MEFU64_V1_F30 = 1073741824ULL, + MEFU64_V1_F31 = 2147483648ULL, + MEFU64_V1_F32 = 4294967296ULL, + MEFU64_V1_F33 = 8589934592ULL, + MEFU64_V1_F34 = 17179869184ULL, + MEFU64_V1_F35 = 34359738368ULL, + MEFU64_V1_F36 = 68719476736ULL, + MEFU64_V1_F37 = 137438953472ULL, + MEFU64_V1_F38 = 274877906944ULL, + MEFU64_V1_F39 = 549755813888ULL, + MEFU64_V1_F40 = 1099511627776ULL, + MEFU64_V1_F41 = 2199023255552ULL, + MEFU64_V1_F42 = 4398046511104ULL, + MEFU64_V1_F43 = 8796093022208ULL, + MEFU64_V1_F44 = 17592186044416ULL, + MEFU64_V1_F45 = 35184372088832ULL, + MEFU64_V1_F46 = 70368744177664ULL, + MEFU64_V1_F47 = 140737488355328ULL, + MEFU64_V1_F48 = 281474976710656ULL, + MEFU64_V1_F49 = 562949953421312ULL, + MEFU64_V1_F50 = 1125899906842624ULL, + MEFU64_V1_F51 = 2251799813685248ULL, + MEFU64_V1_F52 = 4503599627370496ULL, + MEFU64_V1_F53 = 9007199254740992ULL, + MEFU64_V1_F54 = 18014398509481984ULL, + MEFU64_V1_F55 = 36028797018963968ULL, + MEFU64_V1_F56 = 72057594037927936ULL, + MEFU64_V1_F57 = 144115188075855872ULL, + MEFU64_V1_F58 = 288230376151711744ULL, + MEFU64_V1_F59 = 576460752303423488ULL, + MEFU64_V1_F60 = 1152921504606846976ULL, + MEFU64_V1_F61 = 2305843009213693952ULL, + MEFU64_V1_F62 = 4611686018427387904ULL, + MEFU64_V1_F63 = 9223372036854775808ULL, + MEFU64_V1_NONE = 0, + MEFU64_V1_ANY = 18446744073709551615ULL +}; + +inline const MEFU64_V1 (&EnumValuesMEFU64_V1())[64] { + static const MEFU64_V1 values[] = { + MEFU64_V1_F00, + MEFU64_V1_F01, + MEFU64_V1_F02, + MEFU64_V1_F03, + MEFU64_V1_F04, + MEFU64_V1_F05, + MEFU64_V1_F06, + MEFU64_V1_F07, + MEFU64_V1_F08, + MEFU64_V1_F09, + MEFU64_V1_F10, + MEFU64_V1_F11, + MEFU64_V1_F12, + MEFU64_V1_F13, + MEFU64_V1_F14, + MEFU64_V1_F15, + MEFU64_V1_F16, + MEFU64_V1_F17, + MEFU64_V1_F18, + MEFU64_V1_F19, + MEFU64_V1_F20, + MEFU64_V1_F21, + MEFU64_V1_F22, + MEFU64_V1_F23, + MEFU64_V1_F24, + MEFU64_V1_F25, + MEFU64_V1_F26, + MEFU64_V1_F27, + MEFU64_V1_F28, + MEFU64_V1_F29, + MEFU64_V1_F30, + MEFU64_V1_F31, + MEFU64_V1_F32, + MEFU64_V1_F33, + MEFU64_V1_F34, + MEFU64_V1_F35, + MEFU64_V1_F36, + MEFU64_V1_F37, + MEFU64_V1_F38, + MEFU64_V1_F39, + MEFU64_V1_F40, + MEFU64_V1_F41, + MEFU64_V1_F42, + MEFU64_V1_F43, + MEFU64_V1_F44, + MEFU64_V1_F45, + MEFU64_V1_F46, + MEFU64_V1_F47, + MEFU64_V1_F48, + MEFU64_V1_F49, + MEFU64_V1_F50, + MEFU64_V1_F51, + MEFU64_V1_F52, + MEFU64_V1_F53, + MEFU64_V1_F54, + MEFU64_V1_F55, + MEFU64_V1_F56, + MEFU64_V1_F57, + MEFU64_V1_F58, + MEFU64_V1_F59, + MEFU64_V1_F60, + MEFU64_V1_F61, + MEFU64_V1_F62, + MEFU64_V1_F63 + }; + return values; +} + +inline const char *EnumNameMEFU64_V1(MEFU64_V1 e) { + switch (e) { + case MEFU64_V1_F00: return "F00"; + case MEFU64_V1_F01: return "F01"; + case MEFU64_V1_F02: return "F02"; + case MEFU64_V1_F03: return "F03"; + case MEFU64_V1_F04: return "F04"; + case MEFU64_V1_F05: return "F05"; + case MEFU64_V1_F06: return "F06"; + case MEFU64_V1_F07: return "F07"; + case MEFU64_V1_F08: return "F08"; + case MEFU64_V1_F09: return "F09"; + case MEFU64_V1_F10: return "F10"; + case MEFU64_V1_F11: return "F11"; + case MEFU64_V1_F12: return "F12"; + case MEFU64_V1_F13: return "F13"; + case MEFU64_V1_F14: return "F14"; + case MEFU64_V1_F15: return "F15"; + case MEFU64_V1_F16: return "F16"; + case MEFU64_V1_F17: return "F17"; + case MEFU64_V1_F18: return "F18"; + case MEFU64_V1_F19: return "F19"; + case MEFU64_V1_F20: return "F20"; + case MEFU64_V1_F21: return "F21"; + case MEFU64_V1_F22: return "F22"; + case MEFU64_V1_F23: return "F23"; + case MEFU64_V1_F24: return "F24"; + case MEFU64_V1_F25: return "F25"; + case MEFU64_V1_F26: return "F26"; + case MEFU64_V1_F27: return "F27"; + case MEFU64_V1_F28: return "F28"; + case MEFU64_V1_F29: return "F29"; + case MEFU64_V1_F30: return "F30"; + case MEFU64_V1_F31: return "F31"; + case MEFU64_V1_F32: return "F32"; + case MEFU64_V1_F33: return "F33"; + case MEFU64_V1_F34: return "F34"; + case MEFU64_V1_F35: return "F35"; + case MEFU64_V1_F36: return "F36"; + case MEFU64_V1_F37: return "F37"; + case MEFU64_V1_F38: return "F38"; + case MEFU64_V1_F39: return "F39"; + case MEFU64_V1_F40: return "F40"; + case MEFU64_V1_F41: return "F41"; + case MEFU64_V1_F42: return "F42"; + case MEFU64_V1_F43: return "F43"; + case MEFU64_V1_F44: return "F44"; + case MEFU64_V1_F45: return "F45"; + case MEFU64_V1_F46: return "F46"; + case MEFU64_V1_F47: return "F47"; + case MEFU64_V1_F48: return "F48"; + case MEFU64_V1_F49: return "F49"; + case MEFU64_V1_F50: return "F50"; + case MEFU64_V1_F51: return "F51"; + case MEFU64_V1_F52: return "F52"; + case MEFU64_V1_F53: return "F53"; + case MEFU64_V1_F54: return "F54"; + case MEFU64_V1_F55: return "F55"; + case MEFU64_V1_F56: return "F56"; + case MEFU64_V1_F57: return "F57"; + case MEFU64_V1_F58: return "F58"; + case MEFU64_V1_F59: return "F59"; + case MEFU64_V1_F60: return "F60"; + case MEFU64_V1_F61: return "F61"; + case MEFU64_V1_F62: return "F62"; + case MEFU64_V1_F63: return "F63"; + default: return ""; + } +} + +///DOC: ALL_FLAGS = -4611686018427387517LL +enum MEFI64_V0 : int64_t { + MEFI64_V0_F63 = (-9223372036854775807LL - 1LL), + MEFI64_V0_F00 = 1LL, + MEFI64_V0_F01 = 2LL, + MEFI64_V0_F07 = 128LL, + MEFI64_V0_F08 = 256LL, + MEFI64_V0_F62 = 4611686018427387904LL, + MEFI64_V0_NONE = 0, + MEFI64_V0_ANY = -4611686018427387517LL +}; + +inline const MEFI64_V0 (&EnumValuesMEFI64_V0())[6] { + static const MEFI64_V0 values[] = { + MEFI64_V0_F63, + MEFI64_V0_F00, + MEFI64_V0_F01, + MEFI64_V0_F07, + MEFI64_V0_F08, + MEFI64_V0_F62 + }; + return values; +} + +inline const char *EnumNameMEFI64_V0(MEFI64_V0 e) { + switch (e) { + case MEFI64_V0_F63: return "F63"; + case MEFI64_V0_F00: return "F00"; + case MEFI64_V0_F01: return "F01"; + case MEFI64_V0_F07: return "F07"; + case MEFI64_V0_F08: return "F08"; + case MEFI64_V0_F62: return "F62"; + default: return ""; + } +} + +///DOC: ALL_FLAGS = -1LL +enum MEFI64_V1 : int64_t { + MEFI64_V1_F63 = (-9223372036854775807LL - 1LL), + MEFI64_V1_F00 = 1LL, + MEFI64_V1_F01 = 2LL, + MEFI64_V1_F02 = 4LL, + MEFI64_V1_F03 = 8LL, + MEFI64_V1_F04 = 16LL, + MEFI64_V1_F05 = 32LL, + MEFI64_V1_F06 = 64LL, + MEFI64_V1_F07 = 128LL, + MEFI64_V1_F08 = 256LL, + MEFI64_V1_F09 = 512LL, + MEFI64_V1_F10 = 1024LL, + MEFI64_V1_F11 = 2048LL, + MEFI64_V1_F12 = 4096LL, + MEFI64_V1_F13 = 8192LL, + MEFI64_V1_F14 = 16384LL, + MEFI64_V1_F15 = 32768LL, + MEFI64_V1_F16 = 65536LL, + MEFI64_V1_F17 = 131072LL, + MEFI64_V1_F18 = 262144LL, + MEFI64_V1_F19 = 524288LL, + MEFI64_V1_F20 = 1048576LL, + MEFI64_V1_F21 = 2097152LL, + MEFI64_V1_F22 = 4194304LL, + MEFI64_V1_F23 = 8388608LL, + MEFI64_V1_F24 = 16777216LL, + MEFI64_V1_F25 = 33554432LL, + MEFI64_V1_F26 = 67108864LL, + MEFI64_V1_F27 = 134217728LL, + MEFI64_V1_F28 = 268435456LL, + MEFI64_V1_F29 = 536870912LL, + MEFI64_V1_F30 = 1073741824LL, + MEFI64_V1_F31 = 2147483648LL, + MEFI64_V1_F32 = 4294967296LL, + MEFI64_V1_F33 = 8589934592LL, + MEFI64_V1_F34 = 17179869184LL, + MEFI64_V1_F35 = 34359738368LL, + MEFI64_V1_F36 = 68719476736LL, + MEFI64_V1_F37 = 137438953472LL, + MEFI64_V1_F38 = 274877906944LL, + MEFI64_V1_F39 = 549755813888LL, + MEFI64_V1_F40 = 1099511627776LL, + MEFI64_V1_F41 = 2199023255552LL, + MEFI64_V1_F42 = 4398046511104LL, + MEFI64_V1_F43 = 8796093022208LL, + MEFI64_V1_F44 = 17592186044416LL, + MEFI64_V1_F45 = 35184372088832LL, + MEFI64_V1_F46 = 70368744177664LL, + MEFI64_V1_F47 = 140737488355328LL, + MEFI64_V1_F48 = 281474976710656LL, + MEFI64_V1_F49 = 562949953421312LL, + MEFI64_V1_F50 = 1125899906842624LL, + MEFI64_V1_F51 = 2251799813685248LL, + MEFI64_V1_F52 = 4503599627370496LL, + MEFI64_V1_F53 = 9007199254740992LL, + MEFI64_V1_F54 = 18014398509481984LL, + MEFI64_V1_F55 = 36028797018963968LL, + MEFI64_V1_F56 = 72057594037927936LL, + MEFI64_V1_F57 = 144115188075855872LL, + MEFI64_V1_F58 = 288230376151711744LL, + MEFI64_V1_F59 = 576460752303423488LL, + MEFI64_V1_F60 = 1152921504606846976LL, + MEFI64_V1_F61 = 2305843009213693952LL, + MEFI64_V1_F62 = 4611686018427387904LL, + MEFI64_V1_NONE = 0, + MEFI64_V1_ANY = -1LL +}; + +inline const MEFI64_V1 (&EnumValuesMEFI64_V1())[64] { + static const MEFI64_V1 values[] = { + MEFI64_V1_F63, + MEFI64_V1_F00, + MEFI64_V1_F01, + MEFI64_V1_F02, + MEFI64_V1_F03, + MEFI64_V1_F04, + MEFI64_V1_F05, + MEFI64_V1_F06, + MEFI64_V1_F07, + MEFI64_V1_F08, + MEFI64_V1_F09, + MEFI64_V1_F10, + MEFI64_V1_F11, + MEFI64_V1_F12, + MEFI64_V1_F13, + MEFI64_V1_F14, + MEFI64_V1_F15, + MEFI64_V1_F16, + MEFI64_V1_F17, + MEFI64_V1_F18, + MEFI64_V1_F19, + MEFI64_V1_F20, + MEFI64_V1_F21, + MEFI64_V1_F22, + MEFI64_V1_F23, + MEFI64_V1_F24, + MEFI64_V1_F25, + MEFI64_V1_F26, + MEFI64_V1_F27, + MEFI64_V1_F28, + MEFI64_V1_F29, + MEFI64_V1_F30, + MEFI64_V1_F31, + MEFI64_V1_F32, + MEFI64_V1_F33, + MEFI64_V1_F34, + MEFI64_V1_F35, + MEFI64_V1_F36, + MEFI64_V1_F37, + MEFI64_V1_F38, + MEFI64_V1_F39, + MEFI64_V1_F40, + MEFI64_V1_F41, + MEFI64_V1_F42, + MEFI64_V1_F43, + MEFI64_V1_F44, + MEFI64_V1_F45, + MEFI64_V1_F46, + MEFI64_V1_F47, + MEFI64_V1_F48, + MEFI64_V1_F49, + MEFI64_V1_F50, + MEFI64_V1_F51, + MEFI64_V1_F52, + MEFI64_V1_F53, + MEFI64_V1_F54, + MEFI64_V1_F55, + MEFI64_V1_F56, + MEFI64_V1_F57, + MEFI64_V1_F58, + MEFI64_V1_F59, + MEFI64_V1_F60, + MEFI64_V1_F61, + MEFI64_V1_F62 + }; + return values; +} + +inline const char *EnumNameMEFI64_V1(MEFI64_V1 e) { + switch (e) { + case MEFI64_V1_F63: return "F63"; + case MEFI64_V1_F00: return "F00"; + case MEFI64_V1_F01: return "F01"; + case MEFI64_V1_F02: return "F02"; + case MEFI64_V1_F03: return "F03"; + case MEFI64_V1_F04: return "F04"; + case MEFI64_V1_F05: return "F05"; + case MEFI64_V1_F06: return "F06"; + case MEFI64_V1_F07: return "F07"; + case MEFI64_V1_F08: return "F08"; + case MEFI64_V1_F09: return "F09"; + case MEFI64_V1_F10: return "F10"; + case MEFI64_V1_F11: return "F11"; + case MEFI64_V1_F12: return "F12"; + case MEFI64_V1_F13: return "F13"; + case MEFI64_V1_F14: return "F14"; + case MEFI64_V1_F15: return "F15"; + case MEFI64_V1_F16: return "F16"; + case MEFI64_V1_F17: return "F17"; + case MEFI64_V1_F18: return "F18"; + case MEFI64_V1_F19: return "F19"; + case MEFI64_V1_F20: return "F20"; + case MEFI64_V1_F21: return "F21"; + case MEFI64_V1_F22: return "F22"; + case MEFI64_V1_F23: return "F23"; + case MEFI64_V1_F24: return "F24"; + case MEFI64_V1_F25: return "F25"; + case MEFI64_V1_F26: return "F26"; + case MEFI64_V1_F27: return "F27"; + case MEFI64_V1_F28: return "F28"; + case MEFI64_V1_F29: return "F29"; + case MEFI64_V1_F30: return "F30"; + case MEFI64_V1_F31: return "F31"; + case MEFI64_V1_F32: return "F32"; + case MEFI64_V1_F33: return "F33"; + case MEFI64_V1_F34: return "F34"; + case MEFI64_V1_F35: return "F35"; + case MEFI64_V1_F36: return "F36"; + case MEFI64_V1_F37: return "F37"; + case MEFI64_V1_F38: return "F38"; + case MEFI64_V1_F39: return "F39"; + case MEFI64_V1_F40: return "F40"; + case MEFI64_V1_F41: return "F41"; + case MEFI64_V1_F42: return "F42"; + case MEFI64_V1_F43: return "F43"; + case MEFI64_V1_F44: return "F44"; + case MEFI64_V1_F45: return "F45"; + case MEFI64_V1_F46: return "F46"; + case MEFI64_V1_F47: return "F47"; + case MEFI64_V1_F48: return "F48"; + case MEFI64_V1_F49: return "F49"; + case MEFI64_V1_F50: return "F50"; + case MEFI64_V1_F51: return "F51"; + case MEFI64_V1_F52: return "F52"; + case MEFI64_V1_F53: return "F53"; + case MEFI64_V1_F54: return "F54"; + case MEFI64_V1_F55: return "F55"; + case MEFI64_V1_F56: return "F56"; + case MEFI64_V1_F57: return "F57"; + case MEFI64_V1_F58: return "F58"; + case MEFI64_V1_F59: return "F59"; + case MEFI64_V1_F60: return "F60"; + case MEFI64_V1_F61: return "F61"; + case MEFI64_V1_F62: return "F62"; + default: return ""; + } +} + +///DOC: ALL_FLAGS = 49539U +enum MEFU16_V0 { + MEFU16_V0_F00 = 1, + MEFU16_V0_F01 = 2, + MEFU16_V0_F07 = 128, + MEFU16_V0_F08 = 256, + MEFU16_V0_F14 = 16384, + MEFU16_V0_F15 = 32768, + MEFU16_V0_NONE = 0, + MEFU16_V0_ANY = 49539 +}; + +inline const MEFU16_V0 (&EnumValuesMEFU16_V0())[6] { + static const MEFU16_V0 values[] = { + MEFU16_V0_F00, + MEFU16_V0_F01, + MEFU16_V0_F07, + MEFU16_V0_F08, + MEFU16_V0_F14, + MEFU16_V0_F15 + }; + return values; +} + +inline const char *EnumNameMEFU16_V0(MEFU16_V0 e) { + switch (e) { + case MEFU16_V0_F00: return "F00"; + case MEFU16_V0_F01: return "F01"; + case MEFU16_V0_F07: return "F07"; + case MEFU16_V0_F08: return "F08"; + case MEFU16_V0_F14: return "F14"; + case MEFU16_V0_F15: return "F15"; + default: return ""; + } +} + +///DOC: ALL_FLAGS = -15997 +enum MEFI16_V0 { + MEFI16_V0_F15 = -32768, + MEFI16_V0_F00 = 1, + MEFI16_V0_F01 = 2, + MEFI16_V0_F07 = 128, + MEFI16_V0_F08 = 256, + MEFI16_V0_F14 = 16384, + MEFI16_V0_NONE = 0, + MEFI16_V0_ANY = -15997 +}; + +inline const MEFI16_V0 (&EnumValuesMEFI16_V0())[6] { + static const MEFI16_V0 values[] = { + MEFI16_V0_F15, + MEFI16_V0_F00, + MEFI16_V0_F01, + MEFI16_V0_F07, + MEFI16_V0_F08, + MEFI16_V0_F14 + }; + return values; +} + +inline const char *EnumNameMEFI16_V0(MEFI16_V0 e) { + switch (e) { + case MEFI16_V0_F15: return "F15"; + case MEFI16_V0_F00: return "F00"; + case MEFI16_V0_F01: return "F01"; + case MEFI16_V0_F07: return "F07"; + case MEFI16_V0_F08: return "F08"; + case MEFI16_V0_F14: return "F14"; + default: return ""; + } +} + +enum MECI8_V0 { + MECI8_V0_dn = -128, + MECI8_V0_dn_p1 = -127, + MECI8_V0_none = -1, + MECI8_V0_zero = 0, + MECI8_V0_one = 1, + MECI8_V0_up = 127, + MECI8_V0_MIN = MECI8_V0_dn, + MECI8_V0_MAX = MECI8_V0_up +}; + +inline const MECI8_V0 (&EnumValuesMECI8_V0())[6] { + static const MECI8_V0 values[] = { + MECI8_V0_dn, + MECI8_V0_dn_p1, + MECI8_V0_none, + MECI8_V0_zero, + MECI8_V0_one, + MECI8_V0_up + }; + return values; +} + +inline const char *EnumNameMECI8_V0(MECI8_V0 e) { + switch (e) { + case MECI8_V0_dn: return "dn"; + case MECI8_V0_dn_p1: return "dn_p1"; + case MECI8_V0_none: return "none"; + case MECI8_V0_zero: return "zero"; + case MECI8_V0_one: return "one"; + case MECI8_V0_up: return "up"; + default: return ""; + } +} + +enum MECU8_V0 { + MECU8_V0_dn = 0, + MECU8_V0_one = 1, + MECU8_V0_up = 255, + MECU8_V0_MIN = MECU8_V0_dn, + MECU8_V0_MAX = MECU8_V0_up +}; + +inline const MECU8_V0 (&EnumValuesMECU8_V0())[3] { + static const MECU8_V0 values[] = { + MECU8_V0_dn, + MECU8_V0_one, + MECU8_V0_up + }; + return values; +} + +inline const char *EnumNameMECU8_V0(MECU8_V0 e) { + switch (e) { + case MECU8_V0_dn: return "dn"; + case MECU8_V0_one: return "one"; + case MECU8_V0_up: return "up"; + default: return ""; + } +} + +enum MECI16_V0 { + MECI16_V0_dn = -32768, + MECI16_V0_none = -1, + MECI16_V0_zero = 0, + MECI16_V0_one = 1, + MECI16_V0_up = 32767, + MECI16_V0_MIN = MECI16_V0_dn, + MECI16_V0_MAX = MECI16_V0_up +}; + +inline const MECI16_V0 (&EnumValuesMECI16_V0())[5] { + static const MECI16_V0 values[] = { + MECI16_V0_dn, + MECI16_V0_none, + MECI16_V0_zero, + MECI16_V0_one, + MECI16_V0_up + }; + return values; +} + +inline const char *EnumNameMECI16_V0(MECI16_V0 e) { + switch (e) { + case MECI16_V0_dn: return "dn"; + case MECI16_V0_none: return "none"; + case MECI16_V0_zero: return "zero"; + case MECI16_V0_one: return "one"; + case MECI16_V0_up: return "up"; + default: return ""; + } +} + +enum MECU16_V0 { + MECU16_V0_dn = 0, + MECU16_V0_one = 1, + MECU16_V0_up = 65535, + MECU16_V0_MIN = MECU16_V0_dn, + MECU16_V0_MAX = MECU16_V0_up +}; + +inline const MECU16_V0 (&EnumValuesMECU16_V0())[3] { + static const MECU16_V0 values[] = { + MECU16_V0_dn, + MECU16_V0_one, + MECU16_V0_up + }; + return values; +} + +inline const char *EnumNameMECU16_V0(MECU16_V0 e) { + switch (e) { + case MECU16_V0_dn: return "dn"; + case MECU16_V0_one: return "one"; + case MECU16_V0_up: return "up"; + default: return ""; + } +} + +enum MECI32_V0 { + MECI32_V0_dn = (-2147483647 - 1), + MECI32_V0_none = -1, + MECI32_V0_zero = 0, + MECI32_V0_one = 1, + MECI32_V0_up = 2147483647, + MECI32_V0_MIN = MECI32_V0_dn, + MECI32_V0_MAX = MECI32_V0_up +}; + +inline const MECI32_V0 (&EnumValuesMECI32_V0())[5] { + static const MECI32_V0 values[] = { + MECI32_V0_dn, + MECI32_V0_none, + MECI32_V0_zero, + MECI32_V0_one, + MECI32_V0_up + }; + return values; +} + +inline const char *EnumNameMECI32_V0(MECI32_V0 e) { + switch (e) { + case MECI32_V0_dn: return "dn"; + case MECI32_V0_none: return "none"; + case MECI32_V0_zero: return "zero"; + case MECI32_V0_one: return "one"; + case MECI32_V0_up: return "up"; + default: return ""; + } +} + +enum MECU32_V0 { + MECU32_V0_dn = 0, + MECU32_V0_one = 1, + MECU32_V0_up = 4294967295, + MECU32_V0_MIN = MECU32_V0_dn, + MECU32_V0_MAX = MECU32_V0_up +}; + +inline const MECU32_V0 (&EnumValuesMECU32_V0())[3] { + static const MECU32_V0 values[] = { + MECU32_V0_dn, + MECU32_V0_one, + MECU32_V0_up + }; + return values; +} + +inline const char *EnumNameMECU32_V0(MECU32_V0 e) { + switch (e) { + case MECU32_V0_dn: return "dn"; + case MECU32_V0_one: return "one"; + case MECU32_V0_up: return "up"; + default: return ""; + } +} + +enum MECI64_V0 : int64_t { + MECI64_V0_dn = (-9223372036854775807LL - 1LL), + MECI64_V0_dn_p1 = -9223372036854775807LL, + MECI64_V0_none = -1LL, + MECI64_V0_zero = 0, + MECI64_V0_one = 1LL, + MECI64_V0_up = 9223372036854775807LL, + MECI64_V0_MIN = MECI64_V0_dn, + MECI64_V0_MAX = MECI64_V0_up +}; + +inline const MECI64_V0 (&EnumValuesMECI64_V0())[6] { + static const MECI64_V0 values[] = { + MECI64_V0_dn, + MECI64_V0_dn_p1, + MECI64_V0_none, + MECI64_V0_zero, + MECI64_V0_one, + MECI64_V0_up + }; + return values; +} + +inline const char *EnumNameMECI64_V0(MECI64_V0 e) { + switch (e) { + case MECI64_V0_dn: return "dn"; + case MECI64_V0_dn_p1: return "dn_p1"; + case MECI64_V0_none: return "none"; + case MECI64_V0_zero: return "zero"; + case MECI64_V0_one: return "one"; + case MECI64_V0_up: return "up"; + default: return ""; + } +} + +enum MECU64_V0 : uint64_t { + MECU64_V0_dn = 0, + MECU64_V0_one = 1ULL, + MECU64_V0_up = 18446744073709551615ULL, + MECU64_V0_MIN = MECU64_V0_dn, + MECU64_V0_MAX = MECU64_V0_up +}; + +inline const MECU64_V0 (&EnumValuesMECU64_V0())[3] { + static const MECU64_V0 values[] = { + MECU64_V0_dn, + MECU64_V0_one, + MECU64_V0_up + }; + return values; +} + +inline const char *EnumNameMECU64_V0(MECU64_V0 e) { + switch (e) { + case MECU64_V0_dn: return "dn"; + case MECU64_V0_one: return "one"; + case MECU64_V0_up: return "up"; + default: return ""; + } +} + +enum MerchantCanChanged { + MerchantCanChanged_x = 1, + MerchantCanChanged_y = 2, + MerchantCanChanged_z = 3, + MerchantCanChanged_v = 4, + MerchantCanChanged_s = 5, + MerchantCanChanged_MIN = MerchantCanChanged_x, + MerchantCanChanged_MAX = MerchantCanChanged_s +}; + +inline const MerchantCanChanged (&EnumValuesMerchantCanChanged())[5] { + static const MerchantCanChanged values[] = { + MerchantCanChanged_x, + MerchantCanChanged_y, + MerchantCanChanged_z, + MerchantCanChanged_v, + MerchantCanChanged_s + }; + return values; +} + +inline const char * const *EnumNamesMerchantCanChanged() { + static const char * const names[6] = { + "x", + "y", + "z", + "v", + "s", + nullptr + }; + return names; +} + +inline const char *EnumNameMerchantCanChanged(MerchantCanChanged e) { + if (e < MerchantCanChanged_x || e > MerchantCanChanged_s) return ""; + const size_t index = static_cast(e) - static_cast(MerchantCanChanged_x); + return EnumNamesMerchantCanChanged()[index]; +} + +struct MonsterEnumTest FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_INT8_MIN = 4, + VT_INT8_MAX = 6, + VT_INT16_MIN = 8, + VT_INT16_MAX = 10, + VT_INT32_MIN = 12, + VT_INT32_MAX = 14, + VT_INT64_MIN = 16, + VT_INT64_MAX = 18, + VT_UINT8_MAX = 20, + VT_UINT16_MAX = 22, + VT_UINT32_MAX = 24, + VT_UINT64_MAX = 26, + VT_EMPTY_I8 = 28, + VT_EMPTY_U8 = 30, + VT_EMPTY_I16 = 32, + VT_EMPTY_U16 = 34, + VT_EMPTY_I32 = 36, + VT_EMPTY_U32 = 38, + VT_EMPTY_I64 = 40, + VT_EMPTY_U64 = 42, + VT_U64_EF = 44, + VT_I64_EF = 46, + VT_U64_EC = 48, + VT_I64_EC1 = 50, + VT_I64_EC2 = 52, + VT_U64 = 54, + VT_I64 = 56, + VT_U16_EF = 58, + VT_I16_EF = 60, + VT_U8_EC = 62, + VT_I8_EC1 = 64, + VT_I8_EC2 = 66, + VT_FIELDS_MERCHANT_UPDATE = 68 + }; + int8_t int8_min() const { + return GetField(VT_INT8_MIN, -128); + } + int8_t int8_max() const { + return GetField(VT_INT8_MAX, 127); + } + int16_t int16_min() const { + return GetField(VT_INT16_MIN, -32768); + } + int16_t int16_max() const { + return GetField(VT_INT16_MAX, 32767); + } + int32_t int32_min() const { + return GetField(VT_INT32_MIN, (-2147483647 - 1)); + } + int32_t int32_max() const { + return GetField(VT_INT32_MAX, 2147483647); + } + int64_t int64_min() const { + return GetField(VT_INT64_MIN, (-9223372036854775807LL - 1LL)); + } + int64_t int64_max() const { + return GetField(VT_INT64_MAX, 9223372036854775807LL); + } + uint8_t uint8_max() const { + return GetField(VT_UINT8_MAX, 255); + } + uint16_t uint16_max() const { + return GetField(VT_UINT16_MAX, 65535); + } + uint32_t uint32_max() const { + return GetField(VT_UINT32_MAX, 4294967295); + } + uint64_t uint64_max() const { + return GetField(VT_UINT64_MAX, 18446744073709551615ULL); + } + ME_I8 empty_i8() const { + return static_cast(GetField(VT_EMPTY_I8, 0)); + } + ME_U8 empty_u8() const { + return static_cast(GetField(VT_EMPTY_U8, 0)); + } + ME_I16 empty_i16() const { + return static_cast(GetField(VT_EMPTY_I16, 0)); + } + ME_U16 empty_u16() const { + return static_cast(GetField(VT_EMPTY_U16, 0)); + } + ME_I32 empty_i32() const { + return static_cast(GetField(VT_EMPTY_I32, 0)); + } + ME_U32 empty_u32() const { + return static_cast(GetField(VT_EMPTY_U32, 0)); + } + ME_I64 empty_i64() const { + return static_cast(GetField(VT_EMPTY_I64, 0)); + } + ME_U64 empty_u64() const { + return static_cast(GetField(VT_EMPTY_U64, 0)); + } + MEFU64_V0 u64_ef() const { + return static_cast(GetField(VT_U64_EF, 9223372036854776192ULL)); + } + MEFI64_V0 i64_ef() const { + return static_cast(GetField(VT_I64_EF, -9223372036854775424LL)); + } + MECU64_V0 u64_ec() const { + return static_cast(GetField(VT_U64_EC, 18446744073709551615ULL)); + } + MECI64_V0 i64_ec1() const { + return static_cast(GetField(VT_I64_EC1, -9223372036854775807LL)); + } + MECI64_V0 i64_ec2() const { + return static_cast(GetField(VT_I64_EC2, 9223372036854775807LL)); + } + uint64_t u64() const { + return GetField(VT_U64, 9223372036854775809ULL); + } + int64_t i64() const { + return GetField(VT_I64, -9223372036854775807LL); + } + MEFU16_V0 u16_ef() const { + return static_cast(GetField(VT_U16_EF, 33024)); + } + MEFI16_V0 i16_ef() const { + return static_cast(GetField(VT_I16_EF, -32512)); + } + MECU8_V0 u8_ec() const { + return static_cast(GetField(VT_U8_EC, 255)); + } + MECI8_V0 i8_ec1() const { + return static_cast(GetField(VT_I8_EC1, -127)); + } + MECI8_V0 i8_ec2() const { + return static_cast(GetField(VT_I8_EC2, 127)); + } + const flatbuffers::Vector *fields_merchant_update() const { + return GetPointer *>(VT_FIELDS_MERCHANT_UPDATE); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_INT8_MIN) && + VerifyField(verifier, VT_INT8_MAX) && + VerifyField(verifier, VT_INT16_MIN) && + VerifyField(verifier, VT_INT16_MAX) && + VerifyField(verifier, VT_INT32_MIN) && + VerifyField(verifier, VT_INT32_MAX) && + VerifyField(verifier, VT_INT64_MIN) && + VerifyField(verifier, VT_INT64_MAX) && + VerifyField(verifier, VT_UINT8_MAX) && + VerifyField(verifier, VT_UINT16_MAX) && + VerifyField(verifier, VT_UINT32_MAX) && + VerifyField(verifier, VT_UINT64_MAX) && + VerifyField(verifier, VT_EMPTY_I8) && + VerifyField(verifier, VT_EMPTY_U8) && + VerifyField(verifier, VT_EMPTY_I16) && + VerifyField(verifier, VT_EMPTY_U16) && + VerifyField(verifier, VT_EMPTY_I32) && + VerifyField(verifier, VT_EMPTY_U32) && + VerifyField(verifier, VT_EMPTY_I64) && + VerifyField(verifier, VT_EMPTY_U64) && + VerifyField(verifier, VT_U64_EF) && + VerifyField(verifier, VT_I64_EF) && + VerifyField(verifier, VT_U64_EC) && + VerifyField(verifier, VT_I64_EC1) && + VerifyField(verifier, VT_I64_EC2) && + VerifyField(verifier, VT_U64) && + VerifyField(verifier, VT_I64) && + VerifyField(verifier, VT_U16_EF) && + VerifyField(verifier, VT_I16_EF) && + VerifyField(verifier, VT_U8_EC) && + VerifyField(verifier, VT_I8_EC1) && + VerifyField(verifier, VT_I8_EC2) && + VerifyOffset(verifier, VT_FIELDS_MERCHANT_UPDATE) && + verifier.VerifyVector(fields_merchant_update()) && + verifier.EndTable(); + } +}; + +struct MonsterEnumTestBuilder { + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_int8_min(int8_t int8_min) { + fbb_.AddElement(MonsterEnumTest::VT_INT8_MIN, int8_min, -128); + } + void add_int8_max(int8_t int8_max) { + fbb_.AddElement(MonsterEnumTest::VT_INT8_MAX, int8_max, 127); + } + void add_int16_min(int16_t int16_min) { + fbb_.AddElement(MonsterEnumTest::VT_INT16_MIN, int16_min, -32768); + } + void add_int16_max(int16_t int16_max) { + fbb_.AddElement(MonsterEnumTest::VT_INT16_MAX, int16_max, 32767); + } + void add_int32_min(int32_t int32_min) { + fbb_.AddElement(MonsterEnumTest::VT_INT32_MIN, int32_min, (-2147483647 - 1)); + } + void add_int32_max(int32_t int32_max) { + fbb_.AddElement(MonsterEnumTest::VT_INT32_MAX, int32_max, 2147483647); + } + void add_int64_min(int64_t int64_min) { + fbb_.AddElement(MonsterEnumTest::VT_INT64_MIN, int64_min, (-9223372036854775807LL - 1LL)); + } + void add_int64_max(int64_t int64_max) { + fbb_.AddElement(MonsterEnumTest::VT_INT64_MAX, int64_max, 9223372036854775807LL); + } + void add_uint8_max(uint8_t uint8_max) { + fbb_.AddElement(MonsterEnumTest::VT_UINT8_MAX, uint8_max, 255); + } + void add_uint16_max(uint16_t uint16_max) { + fbb_.AddElement(MonsterEnumTest::VT_UINT16_MAX, uint16_max, 65535); + } + void add_uint32_max(uint32_t uint32_max) { + fbb_.AddElement(MonsterEnumTest::VT_UINT32_MAX, uint32_max, 4294967295); + } + void add_uint64_max(uint64_t uint64_max) { + fbb_.AddElement(MonsterEnumTest::VT_UINT64_MAX, uint64_max, 18446744073709551615ULL); + } + void add_empty_i8(ME_I8 empty_i8) { + fbb_.AddElement(MonsterEnumTest::VT_EMPTY_I8, static_cast(empty_i8), 0); + } + void add_empty_u8(ME_U8 empty_u8) { + fbb_.AddElement(MonsterEnumTest::VT_EMPTY_U8, static_cast(empty_u8), 0); + } + void add_empty_i16(ME_I16 empty_i16) { + fbb_.AddElement(MonsterEnumTest::VT_EMPTY_I16, static_cast(empty_i16), 0); + } + void add_empty_u16(ME_U16 empty_u16) { + fbb_.AddElement(MonsterEnumTest::VT_EMPTY_U16, static_cast(empty_u16), 0); + } + void add_empty_i32(ME_I32 empty_i32) { + fbb_.AddElement(MonsterEnumTest::VT_EMPTY_I32, static_cast(empty_i32), 0); + } + void add_empty_u32(ME_U32 empty_u32) { + fbb_.AddElement(MonsterEnumTest::VT_EMPTY_U32, static_cast(empty_u32), 0); + } + void add_empty_i64(ME_I64 empty_i64) { + fbb_.AddElement(MonsterEnumTest::VT_EMPTY_I64, static_cast(empty_i64), 0); + } + void add_empty_u64(ME_U64 empty_u64) { + fbb_.AddElement(MonsterEnumTest::VT_EMPTY_U64, static_cast(empty_u64), 0); + } + void add_u64_ef(MEFU64_V0 u64_ef) { + fbb_.AddElement(MonsterEnumTest::VT_U64_EF, static_cast(u64_ef), 9223372036854776192ULL); + } + void add_i64_ef(MEFI64_V0 i64_ef) { + fbb_.AddElement(MonsterEnumTest::VT_I64_EF, static_cast(i64_ef), -9223372036854775424LL); + } + void add_u64_ec(MECU64_V0 u64_ec) { + fbb_.AddElement(MonsterEnumTest::VT_U64_EC, static_cast(u64_ec), 18446744073709551615ULL); + } + void add_i64_ec1(MECI64_V0 i64_ec1) { + fbb_.AddElement(MonsterEnumTest::VT_I64_EC1, static_cast(i64_ec1), -9223372036854775807LL); + } + void add_i64_ec2(MECI64_V0 i64_ec2) { + fbb_.AddElement(MonsterEnumTest::VT_I64_EC2, static_cast(i64_ec2), 9223372036854775807LL); + } + void add_u64(uint64_t u64) { + fbb_.AddElement(MonsterEnumTest::VT_U64, u64, 9223372036854775809ULL); + } + void add_i64(int64_t i64) { + fbb_.AddElement(MonsterEnumTest::VT_I64, i64, -9223372036854775807LL); + } + void add_u16_ef(MEFU16_V0 u16_ef) { + fbb_.AddElement(MonsterEnumTest::VT_U16_EF, static_cast(u16_ef), 33024); + } + void add_i16_ef(MEFI16_V0 i16_ef) { + fbb_.AddElement(MonsterEnumTest::VT_I16_EF, static_cast(i16_ef), -32512); + } + void add_u8_ec(MECU8_V0 u8_ec) { + fbb_.AddElement(MonsterEnumTest::VT_U8_EC, static_cast(u8_ec), 255); + } + void add_i8_ec1(MECI8_V0 i8_ec1) { + fbb_.AddElement(MonsterEnumTest::VT_I8_EC1, static_cast(i8_ec1), -127); + } + void add_i8_ec2(MECI8_V0 i8_ec2) { + fbb_.AddElement(MonsterEnumTest::VT_I8_EC2, static_cast(i8_ec2), 127); + } + void add_fields_merchant_update(flatbuffers::Offset> fields_merchant_update) { + fbb_.AddOffset(MonsterEnumTest::VT_FIELDS_MERCHANT_UPDATE, fields_merchant_update); + } + explicit MonsterEnumTestBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + MonsterEnumTestBuilder &operator=(const MonsterEnumTestBuilder &); + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateMonsterEnumTest( + flatbuffers::FlatBufferBuilder &_fbb, + int8_t int8_min = -128, + int8_t int8_max = 127, + int16_t int16_min = -32768, + int16_t int16_max = 32767, + int32_t int32_min = (-2147483647 - 1), + int32_t int32_max = 2147483647, + int64_t int64_min = (-9223372036854775807LL - 1LL), + int64_t int64_max = 9223372036854775807LL, + uint8_t uint8_max = 255, + uint16_t uint16_max = 65535, + uint32_t uint32_max = 4294967295, + uint64_t uint64_max = 18446744073709551615ULL, + ME_I8 empty_i8 = ME_I8_NONE, + ME_U8 empty_u8 = ME_U8_NONE, + ME_I16 empty_i16 = ME_I16_NONE, + ME_U16 empty_u16 = ME_U16_NONE, + ME_I32 empty_i32 = ME_I32_NONE, + ME_U32 empty_u32 = ME_U32_NONE, + ME_I64 empty_i64 = ME_I64_NONE, + ME_U64 empty_u64 = ME_U64_NONE, + MEFU64_V0 u64_ef = static_cast(9223372036854776192ULL), + MEFI64_V0 i64_ef = static_cast(-9223372036854775424LL), + MECU64_V0 u64_ec = MECU64_V0_up, + MECI64_V0 i64_ec1 = MECI64_V0_dn_p1, + MECI64_V0 i64_ec2 = MECI64_V0_up, + uint64_t u64 = 9223372036854775809ULL, + int64_t i64 = -9223372036854775807LL, + MEFU16_V0 u16_ef = static_cast(33024), + MEFI16_V0 i16_ef = static_cast(-32512), + MECU8_V0 u8_ec = MECU8_V0_up, + MECI8_V0 i8_ec1 = MECI8_V0_dn_p1, + MECI8_V0 i8_ec2 = MECI8_V0_up, + flatbuffers::Offset> fields_merchant_update = 0) { + MonsterEnumTestBuilder builder_(_fbb); + builder_.add_i64(i64); + builder_.add_u64(u64); + builder_.add_i64_ec2(i64_ec2); + builder_.add_i64_ec1(i64_ec1); + builder_.add_u64_ec(u64_ec); + builder_.add_i64_ef(i64_ef); + builder_.add_u64_ef(u64_ef); + builder_.add_empty_u64(empty_u64); + builder_.add_empty_i64(empty_i64); + builder_.add_uint64_max(uint64_max); + builder_.add_int64_max(int64_max); + builder_.add_int64_min(int64_min); + builder_.add_fields_merchant_update(fields_merchant_update); + builder_.add_empty_u32(empty_u32); + builder_.add_empty_i32(empty_i32); + builder_.add_uint32_max(uint32_max); + builder_.add_int32_max(int32_max); + builder_.add_int32_min(int32_min); + builder_.add_i16_ef(i16_ef); + builder_.add_u16_ef(u16_ef); + builder_.add_empty_u16(empty_u16); + builder_.add_empty_i16(empty_i16); + builder_.add_uint16_max(uint16_max); + builder_.add_int16_max(int16_max); + builder_.add_int16_min(int16_min); + builder_.add_i8_ec2(i8_ec2); + builder_.add_i8_ec1(i8_ec1); + builder_.add_u8_ec(u8_ec); + builder_.add_empty_u8(empty_u8); + builder_.add_empty_i8(empty_i8); + builder_.add_uint8_max(uint8_max); + builder_.add_int8_max(int8_max); + builder_.add_int8_min(int8_min); + return builder_.Finish(); +} + +inline flatbuffers::Offset CreateMonsterEnumTestDirect( + flatbuffers::FlatBufferBuilder &_fbb, + int8_t int8_min = -128, + int8_t int8_max = 127, + int16_t int16_min = -32768, + int16_t int16_max = 32767, + int32_t int32_min = (-2147483647 - 1), + int32_t int32_max = 2147483647, + int64_t int64_min = (-9223372036854775807LL - 1LL), + int64_t int64_max = 9223372036854775807LL, + uint8_t uint8_max = 255, + uint16_t uint16_max = 65535, + uint32_t uint32_max = 4294967295, + uint64_t uint64_max = 18446744073709551615ULL, + ME_I8 empty_i8 = ME_I8_NONE, + ME_U8 empty_u8 = ME_U8_NONE, + ME_I16 empty_i16 = ME_I16_NONE, + ME_U16 empty_u16 = ME_U16_NONE, + ME_I32 empty_i32 = ME_I32_NONE, + ME_U32 empty_u32 = ME_U32_NONE, + ME_I64 empty_i64 = ME_I64_NONE, + ME_U64 empty_u64 = ME_U64_NONE, + MEFU64_V0 u64_ef = static_cast(9223372036854776192ULL), + MEFI64_V0 i64_ef = static_cast(-9223372036854775424LL), + MECU64_V0 u64_ec = MECU64_V0_up, + MECI64_V0 i64_ec1 = MECI64_V0_dn_p1, + MECI64_V0 i64_ec2 = MECI64_V0_up, + uint64_t u64 = 9223372036854775809ULL, + int64_t i64 = -9223372036854775807LL, + MEFU16_V0 u16_ef = static_cast(33024), + MEFI16_V0 i16_ef = static_cast(-32512), + MECU8_V0 u8_ec = MECU8_V0_up, + MECI8_V0 i8_ec1 = MECI8_V0_dn_p1, + MECI8_V0 i8_ec2 = MECI8_V0_up, + const std::vector *fields_merchant_update = nullptr) { + auto fields_merchant_update__ = fields_merchant_update ? _fbb.CreateVector(*fields_merchant_update) : 0; + return MyGame::CreateMonsterEnumTest( + _fbb, + int8_min, + int8_max, + int16_min, + int16_max, + int32_min, + int32_max, + int64_min, + int64_max, + uint8_max, + uint16_max, + uint32_max, + uint64_max, + empty_i8, + empty_u8, + empty_i16, + empty_u16, + empty_i32, + empty_u32, + empty_i64, + empty_u64, + u64_ef, + i64_ef, + u64_ec, + i64_ec1, + i64_ec2, + u64, + i64, + u16_ef, + i16_ef, + u8_ec, + i8_ec1, + i8_ec2, + fields_merchant_update__); +} + +} // namespace MyGame + +#endif // FLATBUFFERS_GENERATED_MONSTERENUM_MYGAME_H_ diff --git a/tests/monster_test_generated.h b/tests/monster_test_generated.h index f98e86b7151..7a3d24517e1 100644 --- a/tests/monster_test_generated.h +++ b/tests/monster_test_generated.h @@ -117,7 +117,7 @@ inline const Color (&EnumValuesColor())[3] { } inline const char * const *EnumNamesColor() { - static const char * const names[] = { + static const char * const names[9] = { "Red", "Green", "", @@ -157,7 +157,7 @@ inline const Any (&EnumValuesAny())[4] { } inline const char * const *EnumNamesAny() { - static const char * const names[] = { + static const char * const names[5] = { "NONE", "Monster", "TestSimpleTableWithEnum", @@ -298,7 +298,7 @@ inline const AnyUniqueAliases (&EnumValuesAnyUniqueAliases())[4] { } inline const char * const *EnumNamesAnyUniqueAliases() { - static const char * const names[] = { + static const char * const names[5] = { "NONE", "M", "T", @@ -439,7 +439,7 @@ inline const AnyAmbiguousAliases (&EnumValuesAnyAmbiguousAliases())[4] { } inline const char * const *EnumNamesAnyAmbiguousAliases() { - static const char * const names[] = { + static const char * const names[5] = { "NONE", "M1", "M2", diff --git a/tests/namespace_test/namespace_test1_generated.h b/tests/namespace_test/namespace_test1_generated.h index 12b344d1382..c0ef32168d2 100644 --- a/tests/namespace_test/namespace_test1_generated.h +++ b/tests/namespace_test/namespace_test1_generated.h @@ -35,7 +35,7 @@ inline const EnumInNestedNS (&EnumValuesEnumInNestedNS())[3] { } inline const char * const *EnumNamesEnumInNestedNS() { - static const char * const names[] = { + static const char * const names[4] = { "A", "B", "C", diff --git a/tests/prototest/test.proto b/tests/prototest/test.proto index cae1f3cfc50..df264a1a0ca 100644 --- a/tests/prototest/test.proto +++ b/tests/prototest/test.proto @@ -7,9 +7,14 @@ package proto.test; /// Enum doc comment. enum ProtoEnum { + option allow_alias = true; FOO = 1; -/// Enum 2nd value doc comment misaligned. + /// Enum 2nd value doc comment misaligned. BAR = 5; + // Aliases + FOO_A1 = 1; + BAR_A1 = 5; + FOO_A2 = 1; } /// 2nd table doc comment with diff --git a/tests/test.cpp b/tests/test.cpp index 81eb91d2cba..e236cbe82b5 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -38,6 +38,11 @@ #include "flatbuffers/flexbuffers.h" +// MSVC2010 has problems with int64/uint64 enums. +#if (!defined(_MSC_VER) || (_MSC_VER >= 1800)) +# include "monster_enum_generated.h" +#endif + using namespace MyGame::Example; void FlatBufferBuilderTest(); @@ -1404,6 +1409,13 @@ void EnumStringsTest() { "root_type T;" "{ F:[ \"E.C\", \"E.A E.B E.C\" ] }"), true); + // signed bit_flags + flatbuffers::Parser parser3; + TEST_EQ( + parser3.Parse("enum E:int16 (bit_flags) { F0, F07=7, F08, F14=14, F15 }" + " table T { F: E = \"F15 F08\"; }" + "root_type T;"), + true); } void EnumNamesTest() { @@ -1436,12 +1448,26 @@ void EnumOutOfRangeTest() { TestError("enum X:int { Y = 2147483648 }", "enum value does not fit"); TestError("enum X:uint { Y = -1 }", "enum value does not fit"); TestError("enum X:uint { Y = 4294967297 }", "enum value does not fit"); - TestError("enum X:long { Y = 9223372036854775808 }", "constant does not fit"); - TestError("enum X:long { Y = 9223372036854775807, Z }", "enum value overflows"); - TestError("enum X:ulong { Y = -1 }", "enum value does not fit"); - // TODO: these are perfectly valid constants that shouldn't fail - TestError("enum X:ulong { Y = 13835058055282163712 }", "constant does not fit"); - TestError("enum X:ulong { Y = 18446744073709551615 }", "constant does not fit"); + TestError("enum X:long { Y = 9223372036854775808 }", "does not fit"); + TestError("enum X:long { Y = 9223372036854775807, Z }", "enum value does not fit"); + TestError("enum X:ulong { Y = -1 }", "does not fit"); +} + +void EnumValueTest() { + TEST_EQ(TestValue("{ Y:0 }", "E", "enum E:int { V }"), 0); + TEST_EQ(TestValue("{ Y:V }", "E", "enum E:int { V }"), 0); + TEST_EQ(TestValue("{ }", "E", "enum E:int { V }"), 0); + + TEST_EQ(TestValue("{ Y:5 }", "E=V", "enum E:int { V=5 }"), 5); + TEST_EQ(TestValue(nullptr, "E=V", "enum E:int { V=5 }"), 5); + TEST_EQ(TestValue("{ Y:5 }", "E", "enum E:int { Z, V=5 }"), 5); + TEST_EQ(TestValue("{ Y:5 }", "E=V", "enum E:int { Z, V=5 }"), 5); + TEST_EQ(TestValue(nullptr, "E", "enum E:int { Z, V=5 }"), 0); + TEST_EQ(TestValue(nullptr, "E=V", "enum E:int { Z, V=5 }"), 5); + TEST_EQ(TestValue(nullptr, "E=V", "enum E:ulong { V = 13835058055282163712 }"), 13835058055282163712ULL); + TEST_EQ(TestValue(nullptr, "E=V", "enum E:ulong { V = 18446744073709551615 }"), 18446744073709551615ULL); + // Assign non-enum value to enum field. Is it right? + TEST_EQ(TestValue("{ Y:7 }", "E", "enum E:int { V = 0 }"), 7); } void EnumValueTest() { @@ -1459,9 +1485,70 @@ void EnumValueTest() { TEST_EQ(TestValue("{ Y:5 }", "E=V", "enum E:int { Z, V=5 }"), 5); // Generate json with defaults and check. TEST_EQ(TestValue(nullptr, "E", "enum E:int { Z, V=5 }"), 0); - TEST_EQ(TestValue(nullptr, "E=V", "enum E:int { Z, V=5 }"), 5); + TEST_EQ(TestValue(nullptr, "E=V", "enum E:int { Z, V=5 }"), 5) } +#ifdef FLATBUFFERS_GENERATED_MONSTERENUM_MYGAME_H_ +void EnumMonsterTest() { + using namespace MyGame; + // Ensure that generated "monster_enum_generated.h" is correct. + flatbuffers::FlatBufferBuilder fbb; + fbb.Finish(CreateMonsterEnumTest(fbb)); + auto p = fbb.GetBufferPointer(); + auto _mt = flatbuffers::GetRoot(p); + TEST_NOTNULL(_mt); + const auto &mt = *_mt; + // Check default values of MonsterEnumTest table. + TEST_EQ(mt.int8_min(), -128); + TEST_EQ(mt.int8_max(), 127); + TEST_EQ(mt.uint8_max(), 255); + TEST_EQ(mt.int16_min(), -32768); + TEST_EQ(mt.int16_max(), 32767); + TEST_EQ(mt.uint16_max(), 65535); + TEST_EQ(mt.int32_min() + 1, -2147483647); + TEST_EQ(mt.int32_max(), 2147483647); + TEST_EQ(mt.uint32_max(), 4294967295); + TEST_EQ(mt.int64_min() + 1LL, -9223372036854775807LL); + TEST_EQ(mt.int64_max(), 9223372036854775807LL); + TEST_EQ(mt.uint64_max(), 18446744073709551615ULL); + // 64-bit flags: "F63 F07 F08" + TEST_EQ(static_cast(mt.u64_ef()), 0x8000000000000180ULL); + TEST_EQ(static_cast(mt.i64_ef()), -0x7FFFFFFFFFFFFE80LL); + // 64-bit common enums + // MECU64_V0 "dn one up" = MECU64_V0.up + TEST_EQ(static_cast(mt.u64_ec()), 0xFFFFFFFFFFFFFFFFULL); + // MECI64_V0 "dn one" = MECI64_V0.dn_p1 + TEST_EQ(static_cast(mt.i64_ec1()), -9223372036854775807LL); + // MECI64_V0 "up one" = MECI64_V0.up + TEST_EQ(static_cast(mt.i64_ec2()), 9223372036854775807LL); + // 64-bit mixing (integer inited by combination of enums) + TEST_EQ(static_cast(mt.u64()), 0x8000000000000001ULL); + TEST_EQ(static_cast(mt.i64()), -0x7FFFFFFFFFFFFFFFLL); + // 16-bit flags: "F15 F08" + TEST_EQ(static_cast(mt.u16_ef()), 0x8100); + TEST_EQ(static_cast(mt.i16_ef()), -0x7F00); + // 8-bit common enums + TEST_EQ(static_cast(mt.u8_ec()), 0xFF); + TEST_EQ(static_cast(mt.i8_ec1()), -0x7F); + TEST_EQ(static_cast(mt.i8_ec2()), 0x7F); + // Check generated enums. + TEST_EQ(static_cast(MEFU64_V0_ANY), 13835058055282164099ULL); + TEST_EQ(static_cast(MEFU64_V1_ANY), 0xFFFFFFFFFFFFFFFFULL); + TEST_EQ(static_cast(MEFI64_V0_ANY), -0x3FFFFFFFFFFFFE7DLL); + TEST_EQ(static_cast(MEFI64_V1_ANY), -1LL); + TEST_EQ(static_cast(MEFU16_V0_ANY), 0xC183); + TEST_EQ(static_cast(MEFI16_V0_ANY), -0x3E7D); + // Common enums + TEST_EQ(static_cast(MECI8_V0_dn_p1), -0x7F); + TEST_EQ(static_cast(MECI8_V0_one), 1); + TEST_EQ(static_cast(MECU8_V0_one), 1); + TEST_EQ(static_cast(MECI8_V0_dn_p1), -0x7F); + TEST_EQ(static_cast(MECI8_V0_one), 1); +} +#else +void EnumMonsterTest() { TEST_OUTPUT_LINE("Warning: skip EnumMonsterTest()") } +#endif + void IntegerOutOfRangeTest() { TestError("table T { F:byte; } root_type T; { F:128 }", "constant does not fit"); @@ -2649,6 +2736,7 @@ int FlatBufferTests() { EnumStringsTest(); EnumNamesTest(); EnumOutOfRangeTest(); + EnumMonsterTest(); IntegerOutOfRangeTest(); IntegerBoundaryTest(); UnicodeTest(); @@ -2682,7 +2770,7 @@ int main(int /*argc*/, const char * /*argv*/ []) { std::string req_locale; if (flatbuffers::ReadEnvironmentVariable("FLATBUFFERS_TEST_LOCALE", - &req_locale)) { + &req_locale)) { TEST_OUTPUT_LINE("The environment variable FLATBUFFERS_TEST_LOCALE=%s", req_locale.c_str()); req_locale = flatbuffers::RemoveStringQuotes(req_locale); diff --git a/tests/union_vector/union_vector_generated.h b/tests/union_vector/union_vector_generated.h index 962c98b916d..80ce38f245a 100644 --- a/tests/union_vector/union_vector_generated.h +++ b/tests/union_vector/union_vector_generated.h @@ -59,7 +59,7 @@ inline const Character (&EnumValuesCharacter())[7] { } inline const char * const *EnumNamesCharacter() { - static const char * const names[] = { + static const char * const names[8] = { "NONE", "MuLan", "Rapunzel",