diff --git a/CMakeLists.txt b/CMakeLists.txt index 122009b61..3d224fe27 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -223,7 +223,7 @@ function(compile_flatbuffers_schema_to_cpp SRC_FBS) add_custom_command( OUTPUT ${GEN_HEADER} COMMAND "${FLATBUFFERS_FLATC_EXECUTABLE}" -c --no-includes --gen-mutable - --gen-object-api -o "${SRC_FBS_DIR}" + --gen-object-api --gen-compare -o "${SRC_FBS_DIR}" --cpp-ptr-type flatbuffers::unique_ptr # Used to test with C++98 STLs --reflect-names -I "${CMAKE_CURRENT_SOURCE_DIR}/tests/include_test" diff --git a/docs/source/Compiler.md b/docs/source/Compiler.md index 586087ad7..18eafd4a9 100644 --- a/docs/source/Compiler.md +++ b/docs/source/Compiler.md @@ -96,6 +96,8 @@ Additional options: at the cost of efficiency (object allocation). Recommended only to be used if other options are insufficient. +- `--gen-compare` : Generate operator== for object-based API types. + - `--gen-onefile` : Generate single output file (useful for C#) - `--gen-all`: Generate not just code for the current schema files, but diff --git a/include/flatbuffers/idl.h b/include/flatbuffers/idl.h index 75e34c52d..8c7b43e72 100644 --- a/include/flatbuffers/idl.h +++ b/include/flatbuffers/idl.h @@ -379,6 +379,7 @@ struct IDLOptions { bool skip_unexpected_fields_in_json; bool generate_name_strings; bool generate_object_based_api; + bool gen_compare; std::string cpp_object_api_pointer_type; std::string cpp_object_api_string_type; bool gen_nullable; @@ -453,6 +454,7 @@ struct IDLOptions { skip_unexpected_fields_in_json(false), generate_name_strings(false), generate_object_based_api(false), + gen_compare(false), cpp_object_api_pointer_type("std::unique_ptr"), gen_nullable(false), object_suffix("T"), diff --git a/samples/monster_generated.h b/samples/monster_generated.h index 5af2e3bcd..5ac4be38d 100644 --- a/samples/monster_generated.h +++ b/samples/monster_generated.h @@ -17,6 +17,10 @@ struct MonsterT; struct Weapon; struct WeaponT; +bool operator==(const Vec3 &lhs, const Vec3 &rhs); +bool operator==(const MonsterT &lhs, const MonsterT &rhs); +bool operator==(const WeaponT &lhs, const WeaponT &rhs); + inline const flatbuffers::TypeTable *Vec3TypeTable(); inline const flatbuffers::TypeTable *MonsterTypeTable(); @@ -133,6 +137,22 @@ struct EquipmentUnion { } }; + +inline bool operator==(const EquipmentUnion &lhs, const EquipmentUnion &rhs) { + if (lhs.type != rhs.type) return false; + switch (lhs.type) { + case Equipment_NONE: { + return true; + } + case Equipment_Weapon: { + return *(reinterpret_cast(lhs.value)) == + *(reinterpret_cast(rhs.value)); + } + default: { + return false; + } + } +} bool VerifyEquipment(flatbuffers::Verifier &verifier, const void *obj, Equipment type); bool VerifyEquipmentVector(flatbuffers::Verifier &verifier, const flatbuffers::Vector> *values, const flatbuffers::Vector *types); @@ -172,6 +192,13 @@ FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(4) Vec3 FLATBUFFERS_FINAL_CLASS { }; FLATBUFFERS_STRUCT_END(Vec3, 12); +inline bool operator==(const Vec3 &lhs, const Vec3 &rhs) { + return + (lhs.x() == rhs.x()) && + (lhs.y() == rhs.y()) && + (lhs.z() == rhs.z()); +} + struct MonsterT : public flatbuffers::NativeTable { typedef Monster TableType; flatbuffers::unique_ptr pos; @@ -189,6 +216,18 @@ struct MonsterT : public flatbuffers::NativeTable { } }; +inline bool operator==(const MonsterT &lhs, const MonsterT &rhs) { + return + (lhs.pos == rhs.pos) && + (lhs.mana == rhs.mana) && + (lhs.hp == rhs.hp) && + (lhs.name == rhs.name) && + (lhs.inventory == rhs.inventory) && + (lhs.color == rhs.color) && + (lhs.weapons == rhs.weapons) && + (lhs.equipped == rhs.equipped); +} + struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { typedef MonsterT NativeTableType; static const flatbuffers::TypeTable *MiniReflectTypeTable() { @@ -391,6 +430,12 @@ struct WeaponT : public flatbuffers::NativeTable { } }; +inline bool operator==(const WeaponT &lhs, const WeaponT &rhs) { + return + (lhs.name == rhs.name) && + (lhs.damage == rhs.damage); +} + struct Weapon FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { typedef WeaponT NativeTableType; static const flatbuffers::TypeTable *MiniReflectTypeTable() { diff --git a/src/flatc.cpp b/src/flatc.cpp index bcd5c3bff..c3a70d1ec 100644 --- a/src/flatc.cpp +++ b/src/flatc.cpp @@ -88,6 +88,7 @@ std::string FlatCompiler::GetUsageString(const char *program_name) const { " --gen-onefile Generate single output file for C# and Go.\n" " --gen-name-strings Generate type name functions for C++.\n" " --gen-object-api Generate an additional object-based API.\n" + " --gen-compare Generate operator== for object-based API types.\n" " --cpp-ptr-type T Set object API pointer type (default std::unique_ptr)\n" " --cpp-str-type T Set object API string type (default std::string)\n" " T::c_str() and T::length() must be supported\n" @@ -222,6 +223,8 @@ int FlatCompiler::Compile(int argc, const char **argv) { opts.generate_name_strings = true; } else if (arg == "--gen-object-api") { opts.generate_object_based_api = true; + } else if (arg == "--gen-compare") { + opts.gen_compare = true; } else if (arg == "--cpp-ptr-type") { if (++argi >= argc) Error("missing type following" + arg, true); opts.cpp_object_api_pointer_type = argv[argi]; diff --git a/src/idl_gen_cpp.cpp b/src/idl_gen_cpp.cpp index b9bfacb02..03778c5ae 100644 --- a/src/idl_gen_cpp.cpp +++ b/src/idl_gen_cpp.cpp @@ -226,14 +226,30 @@ class CppGenerator : public BaseGenerator { if (!struct_def.generated) { SetNameSpace(struct_def.defined_namespace); code_ += "struct " + Name(struct_def) + ";"; - if (parser_.opts.generate_object_based_api && !struct_def.fixed) { - code_ += "struct " + - NativeName(Name(struct_def), &struct_def, parser_.opts) + - ";"; + if (parser_.opts.generate_object_based_api) { + auto nativeName = NativeName(Name(struct_def), &struct_def, parser_.opts); + if (!struct_def.fixed) { + code_ += "struct " + nativeName + ";"; + } } code_ += ""; } } + + // Generate forward declarations for all equal operators + if (parser_.opts.generate_object_based_api && parser_.opts.gen_compare) { + for (auto it = parser_.structs_.vec.begin(); + it != parser_.structs_.vec.end(); ++it) { + const auto &struct_def = **it; + if (!struct_def.generated) { + SetNameSpace(struct_def.defined_namespace); + auto nativeName = NativeName(Name(struct_def), &struct_def, parser_.opts); + code_ += "bool operator==(const " + nativeName + " &lhs, const " + nativeName + " &rhs);"; + } + } + code_ += ""; + } + // Generate preablmle code for mini reflection. if (parser_.opts.mini_reflect != IDLOptions::kNone) { // To break cyclic dependencies, first pre-declare all tables/structs. @@ -1096,6 +1112,38 @@ class CppGenerator : public BaseGenerator { } code_ += "};"; code_ += ""; + + if (parser_.opts.gen_compare) { + code_ += ""; + code_ += "inline bool operator==(const {{NAME}}Union &lhs, const {{NAME}}Union &rhs) {"; + code_ += " if (lhs.type != rhs.type) return false;"; + code_ += " switch (lhs.type) {"; + + for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end(); + ++it) { + const auto &ev = **it; + code_.SetValue("NATIVE_ID", GetEnumValUse(enum_def, ev)); + if (ev.value) { + const auto native_type = + NativeName(GetUnionElement(ev, true, true, true), + ev.union_type.struct_def, parser_.opts); + code_.SetValue("NATIVE_TYPE", native_type); + code_ += " case {{NATIVE_ID}}: {"; + code_ += " return *(reinterpret_cast(lhs.value)) =="; + code_ += " *(reinterpret_cast(rhs.value));"; + code_ += " }"; + } else { + code_ += " case {{NATIVE_ID}}: {"; + code_ += " return true;"; // "NONE" enum value. + code_ += " }"; + } + } + code_ += " default: {"; + code_ += " return false;"; + code_ += " }"; + code_ += " }"; + code_ += "}"; + } } if (enum_def.is_union) { @@ -1456,6 +1504,44 @@ class CppGenerator : public BaseGenerator { code_ += " }"; } + void GenCompareOperator(const StructDef &struct_def, std::string accessSuffix = "") { + std::string compare_op; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + const auto &field = **it; + if (!field.deprecated && // Deprecated fields won't be accessible. + field.value.type.base_type != BASE_TYPE_UTYPE && + (field.value.type.base_type != BASE_TYPE_VECTOR || + field.value.type.element != BASE_TYPE_UTYPE)) { + if (!compare_op.empty()) { + compare_op += " &&\n "; + } + auto accessor = Name(field) + accessSuffix; + compare_op += "(lhs." + accessor + " == rhs." + accessor + ")"; + } + } + + std::string cmp_lhs; + std::string cmp_rhs; + if (compare_op.empty()) { + cmp_lhs = ""; + cmp_rhs = ""; + compare_op = " return true;"; + } else { + cmp_lhs = "lhs"; + cmp_rhs = "rhs"; + compare_op = " return\n " + compare_op + ";"; + } + + code_.SetValue("CMP_OP", compare_op); + code_.SetValue("CMP_LHS", cmp_lhs); + code_.SetValue("CMP_RHS", cmp_rhs); + code_ += ""; + code_ += "inline bool operator==(const {{NATIVE_NAME}} &{{CMP_LHS}}, const {{NATIVE_NAME}} &{{CMP_RHS}}) {"; + code_ += "{{CMP_OP}}"; + code_ += "}"; + } + void GenOperatorNewDelete(const StructDef &struct_def) { if (auto native_custom_alloc = struct_def.attributes.Lookup("native_custom_alloc")) { @@ -1488,6 +1574,7 @@ class CppGenerator : public BaseGenerator { GenOperatorNewDelete(struct_def); GenDefaultConstructor(struct_def); code_ += "};"; + if (parser_.opts.gen_compare) GenCompareOperator(struct_def); code_ += ""; } @@ -2600,6 +2687,7 @@ class CppGenerator : public BaseGenerator { code_.SetValue("STRUCT_BYTE_SIZE", NumToString(struct_def.bytesize)); code_ += "FLATBUFFERS_STRUCT_END({{STRUCT_NAME}}, {{STRUCT_BYTE_SIZE}});"; + if (parser_.opts.gen_compare) GenCompareOperator(struct_def, "()"); code_ += ""; } diff --git a/tests/generate_code.bat b/tests/generate_code.bat index b233c1447..30d18ed77 100644 --- a/tests/generate_code.bat +++ b/tests/generate_code.bat @@ -15,13 +15,13 @@ set buildtype=Release if "%1"=="-b" set buildtype=%2 -..\%buildtype%\flatc.exe --cpp --java --csharp --go --binary --python --lobster --lua --js --rust --ts --php --grpc --gen-mutable --reflect-names --gen-object-api --no-includes --cpp-ptr-type flatbuffers::unique_ptr --no-fb-import -I include_test monster_test.fbs monsterdata_test.json +..\%buildtype%\flatc.exe --cpp --java --csharp --go --binary --python --lobster --lua --js --rust --ts --php --grpc --gen-mutable --reflect-names --gen-object-api --gen-compare --no-includes --cpp-ptr-type flatbuffers::unique_ptr --no-fb-import -I include_test monster_test.fbs monsterdata_test.json ..\%buildtype%\flatc.exe --cpp --java --csharp --go --binary --python --lobster --lua --js --rust --ts --php --gen-mutable --reflect-names --no-fb-import --cpp-ptr-type flatbuffers::unique_ptr -o namespace_test namespace_test/namespace_test1.fbs namespace_test/namespace_test2.fbs -..\%buildtype%\flatc.exe --cpp --js --ts --php --gen-mutable --reflect-names --gen-object-api --cpp-ptr-type flatbuffers::unique_ptr -o union_vector ./union_vector/union_vector.fbs +..\%buildtype%\flatc.exe --cpp --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 ..\%buildtype%\flatc.exe -b --schema --bfbs-comments -I include_test monster_test.fbs ..\%buildtype%\flatc.exe --jsonschema --schema -I include_test monster_test.fbs cd ../samples -..\%buildtype%\flatc.exe --cpp --lobster --gen-mutable --reflect-names --gen-object-api --cpp-ptr-type flatbuffers::unique_ptr monster.fbs +..\%buildtype%\flatc.exe --cpp --lobster --gen-mutable --reflect-names --gen-object-api --gen-compare --cpp-ptr-type flatbuffers::unique_ptr monster.fbs cd ../reflection cd ../tests diff --git a/tests/generate_code.sh b/tests/generate_code.sh index f25366b0e..e50dda28c 100755 --- a/tests/generate_code.sh +++ b/tests/generate_code.sh @@ -14,11 +14,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -../flatc --cpp --java --csharp --dart --go --binary --lobster --lua --python --js --ts --php --rust --grpc --gen-mutable --reflect-names --gen-object-api --no-includes --cpp-ptr-type flatbuffers::unique_ptr --no-fb-import -I include_test monster_test.fbs monsterdata_test.json +../flatc --cpp --java --csharp --dart --go --binary --lobster --lua --python --js --ts --php --rust --grpc --gen-mutable --reflect-names --gen-object-api --gen-compare --no-includes --cpp-ptr-type flatbuffers::unique_ptr --no-fb-import -I include_test monster_test.fbs monsterdata_test.json ../flatc --cpp --java --csharp --dart --go --binary --lobster --lua --python --js --ts --php --rust --gen-mutable --reflect-names --no-fb-import --cpp-ptr-type flatbuffers::unique_ptr -o namespace_test namespace_test/namespace_test1.fbs namespace_test/namespace_test2.fbs -../flatc --cpp --js --ts --php --gen-mutable --reflect-names --gen-object-api --cpp-ptr-type flatbuffers::unique_ptr -o union_vector ./union_vector/union_vector.fbs +../flatc --cpp --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 -I include_test monster_test.fbs ../flatc --jsonschema --schema -I include_test monster_test.fbs cd ../samples -../flatc --cpp --lobster --gen-mutable --reflect-names --gen-object-api --cpp-ptr-type flatbuffers::unique_ptr monster.fbs +../flatc --cpp --lobster --gen-mutable --reflect-names --gen-object-api --gen-compare --cpp-ptr-type flatbuffers::unique_ptr monster.fbs cd ../reflection diff --git a/tests/monster_test_generated.h b/tests/monster_test_generated.h index 3c841b936..0f5e25213 100644 --- a/tests/monster_test_generated.h +++ b/tests/monster_test_generated.h @@ -44,6 +44,25 @@ struct TypeAliasesT; } // namespace Example +bool operator==(const InParentNamespaceT &lhs, const InParentNamespaceT &rhs); +namespace Example2 { + +bool operator==(const MonsterT &lhs, const MonsterT &rhs); +} // namespace Example2 + +namespace Example { + +bool operator==(const Test &lhs, const Test &rhs); +bool operator==(const TestSimpleTableWithEnumT &lhs, const TestSimpleTableWithEnumT &rhs); +bool operator==(const Vec3 &lhs, const Vec3 &rhs); +bool operator==(const Ability &lhs, const Ability &rhs); +bool operator==(const StatT &lhs, const StatT &rhs); +bool operator==(const ReferrableT &lhs, const ReferrableT &rhs); +bool operator==(const MonsterT &lhs, const MonsterT &rhs); +bool operator==(const TypeAliasesT &lhs, const TypeAliasesT &rhs); + +} // namespace Example + inline const flatbuffers::TypeTable *InParentNamespaceTypeTable(); namespace Example2 { @@ -215,6 +234,30 @@ struct AnyUnion { } }; + +inline bool operator==(const AnyUnion &lhs, const AnyUnion &rhs) { + if (lhs.type != rhs.type) return false; + switch (lhs.type) { + case Any_NONE: { + return true; + } + case Any_Monster: { + return *(reinterpret_cast(lhs.value)) == + *(reinterpret_cast(rhs.value)); + } + case Any_TestSimpleTableWithEnum: { + return *(reinterpret_cast(lhs.value)) == + *(reinterpret_cast(rhs.value)); + } + case Any_MyGame_Example2_Monster: { + return *(reinterpret_cast(lhs.value)) == + *(reinterpret_cast(rhs.value)); + } + default: { + return false; + } + } +} bool VerifyAny(flatbuffers::Verifier &verifier, const void *obj, Any type); bool VerifyAnyVector(flatbuffers::Verifier &verifier, const flatbuffers::Vector> *values, const flatbuffers::Vector *types); @@ -249,6 +292,12 @@ FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(2) Test FLATBUFFERS_FINAL_CLASS { }; FLATBUFFERS_STRUCT_END(Test, 4); +inline bool operator==(const Test &lhs, const Test &rhs) { + return + (lhs.a() == rhs.a()) && + (lhs.b() == rhs.b()); +} + FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(16) Vec3 FLATBUFFERS_FINAL_CLASS { private: float x_; @@ -318,6 +367,16 @@ FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(16) Vec3 FLATBUFFERS_FINAL_CLASS { }; FLATBUFFERS_STRUCT_END(Vec3, 32); +inline bool operator==(const Vec3 &lhs, const Vec3 &rhs) { + return + (lhs.x() == rhs.x()) && + (lhs.y() == rhs.y()) && + (lhs.z() == rhs.z()) && + (lhs.test1() == rhs.test1()) && + (lhs.test2() == rhs.test2()) && + (lhs.test3() == rhs.test3()); +} + FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(4) Ability FLATBUFFERS_FINAL_CLASS { private: uint32_t id_; @@ -352,6 +411,12 @@ FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(4) Ability FLATBUFFERS_FINAL_CLASS { }; FLATBUFFERS_STRUCT_END(Ability, 8); +inline bool operator==(const Ability &lhs, const Ability &rhs) { + return + (lhs.id() == rhs.id()) && + (lhs.distance() == rhs.distance()); +} + } // namespace Example struct InParentNamespaceT : public flatbuffers::NativeTable { @@ -360,6 +425,10 @@ struct InParentNamespaceT : public flatbuffers::NativeTable { } }; +inline bool operator==(const InParentNamespaceT &, const InParentNamespaceT &) { + return true; +} + struct InParentNamespace FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { typedef InParentNamespaceT NativeTableType; static const flatbuffers::TypeTable *MiniReflectTypeTable() { @@ -405,6 +474,10 @@ struct MonsterT : public flatbuffers::NativeTable { } }; +inline bool operator==(const MonsterT &, const MonsterT &) { + return true; +} + struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { typedef MonsterT NativeTableType; static const flatbuffers::TypeTable *MiniReflectTypeTable() { @@ -454,6 +527,11 @@ struct TestSimpleTableWithEnumT : public flatbuffers::NativeTable { } }; +inline bool operator==(const TestSimpleTableWithEnumT &lhs, const TestSimpleTableWithEnumT &rhs) { + return + (lhs.color == rhs.color); +} + struct TestSimpleTableWithEnum FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { typedef TestSimpleTableWithEnumT NativeTableType; static const flatbuffers::TypeTable *MiniReflectTypeTable() { @@ -517,6 +595,13 @@ struct StatT : public flatbuffers::NativeTable { } }; +inline bool operator==(const StatT &lhs, const StatT &rhs) { + return + (lhs.id == rhs.id) && + (lhs.val == rhs.val) && + (lhs.count == rhs.count); +} + struct Stat FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { typedef StatT NativeTableType; static const flatbuffers::TypeTable *MiniReflectTypeTable() { @@ -616,6 +701,11 @@ struct ReferrableT : public flatbuffers::NativeTable { } }; +inline bool operator==(const ReferrableT &lhs, const ReferrableT &rhs) { + return + (lhs.id == rhs.id); +} + struct Referrable FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { typedef ReferrableT NativeTableType; static const flatbuffers::TypeTable *MiniReflectTypeTable() { @@ -739,6 +829,51 @@ struct MonsterT : public flatbuffers::NativeTable { } }; +inline bool operator==(const MonsterT &lhs, const MonsterT &rhs) { + return + (lhs.pos == rhs.pos) && + (lhs.mana == rhs.mana) && + (lhs.hp == rhs.hp) && + (lhs.name == rhs.name) && + (lhs.inventory == rhs.inventory) && + (lhs.color == rhs.color) && + (lhs.test == rhs.test) && + (lhs.test4 == rhs.test4) && + (lhs.testarrayofstring == rhs.testarrayofstring) && + (lhs.testarrayoftables == rhs.testarrayoftables) && + (lhs.enemy == rhs.enemy) && + (lhs.testnestedflatbuffer == rhs.testnestedflatbuffer) && + (lhs.testempty == rhs.testempty) && + (lhs.testbool == rhs.testbool) && + (lhs.testhashs32_fnv1 == rhs.testhashs32_fnv1) && + (lhs.testhashu32_fnv1 == rhs.testhashu32_fnv1) && + (lhs.testhashs64_fnv1 == rhs.testhashs64_fnv1) && + (lhs.testhashu64_fnv1 == rhs.testhashu64_fnv1) && + (lhs.testhashs32_fnv1a == rhs.testhashs32_fnv1a) && + (lhs.testhashu32_fnv1a == rhs.testhashu32_fnv1a) && + (lhs.testhashs64_fnv1a == rhs.testhashs64_fnv1a) && + (lhs.testhashu64_fnv1a == rhs.testhashu64_fnv1a) && + (lhs.testarrayofbools == rhs.testarrayofbools) && + (lhs.testf == rhs.testf) && + (lhs.testf2 == rhs.testf2) && + (lhs.testf3 == rhs.testf3) && + (lhs.testarrayofstring2 == rhs.testarrayofstring2) && + (lhs.testarrayofsortedstruct == rhs.testarrayofsortedstruct) && + (lhs.flex == rhs.flex) && + (lhs.test5 == rhs.test5) && + (lhs.vector_of_longs == rhs.vector_of_longs) && + (lhs.vector_of_doubles == rhs.vector_of_doubles) && + (lhs.parent_namespace_test == rhs.parent_namespace_test) && + (lhs.vector_of_referrables == rhs.vector_of_referrables) && + (lhs.single_weak_reference == rhs.single_weak_reference) && + (lhs.vector_of_weak_references == rhs.vector_of_weak_references) && + (lhs.vector_of_strong_referrables == rhs.vector_of_strong_referrables) && + (lhs.co_owning_reference == rhs.co_owning_reference) && + (lhs.vector_of_co_owning_references == rhs.vector_of_co_owning_references) && + (lhs.non_owning_reference == rhs.non_owning_reference) && + (lhs.vector_of_non_owning_references == rhs.vector_of_non_owning_references); +} + /// an example documentation comment: monster object struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { typedef MonsterT NativeTableType; @@ -1507,6 +1642,22 @@ struct TypeAliasesT : public flatbuffers::NativeTable { } }; +inline bool operator==(const TypeAliasesT &lhs, const TypeAliasesT &rhs) { + return + (lhs.i8 == rhs.i8) && + (lhs.u8 == rhs.u8) && + (lhs.i16 == rhs.i16) && + (lhs.u16 == rhs.u16) && + (lhs.i32 == rhs.i32) && + (lhs.u32 == rhs.u32) && + (lhs.i64 == rhs.i64) && + (lhs.u64 == rhs.u64) && + (lhs.f32 == rhs.f32) && + (lhs.f64 == rhs.f64) && + (lhs.v8 == rhs.v8) && + (lhs.vf64 == rhs.vf64); +} + struct TypeAliases FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { typedef TypeAliasesT NativeTableType; static const flatbuffers::TypeTable *MiniReflectTypeTable() { diff --git a/tests/test.cpp b/tests/test.cpp index 27d2a21c3..7b90c568f 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -1978,6 +1978,25 @@ void UninitializedVectorTest() { TEST_EQ(test_1->b(), 40); } +void EqualOperatorTest() { + MonsterT a; + MonsterT b; + TEST_EQ(b == a, true); + + b.mana = 33; + TEST_EQ(b == a, false); + b.mana = 150; + TEST_EQ(b == a, true); + + b.inventory.push_back(3); + TEST_EQ(b == a, false); + b.inventory.clear(); + TEST_EQ(b == a, true); + + b.test.type = Any_Monster; + TEST_EQ(b == a, false); +} + // For testing any binaries, e.g. from fuzzing. void LoadVerifyBinaryTest() { std::string binary; @@ -2062,6 +2081,7 @@ int main(int /*argc*/, const char * /*argv*/ []) { FlexBuffersTest(); UninitializedVectorTest(); + EqualOperatorTest(); if (!testing_fails) { TEST_OUTPUT_LINE("ALL TESTS PASSED"); diff --git a/tests/union_vector/union_vector_generated.h b/tests/union_vector/union_vector_generated.h index 6ed7435d9..c5b2250fd 100644 --- a/tests/union_vector/union_vector_generated.h +++ b/tests/union_vector/union_vector_generated.h @@ -16,6 +16,11 @@ struct BookReader; struct Movie; struct MovieT; +bool operator==(const AttackerT &lhs, const AttackerT &rhs); +bool operator==(const Rapunzel &lhs, const Rapunzel &rhs); +bool operator==(const BookReader &lhs, const BookReader &rhs); +bool operator==(const MovieT &lhs, const MovieT &rhs); + inline const flatbuffers::TypeTable *AttackerTypeTable(); inline const flatbuffers::TypeTable *RapunzelTypeTable(); @@ -138,6 +143,42 @@ struct CharacterUnion { } }; + +inline bool operator==(const CharacterUnion &lhs, const CharacterUnion &rhs) { + if (lhs.type != rhs.type) return false; + switch (lhs.type) { + case Character_NONE: { + return true; + } + case Character_MuLan: { + return *(reinterpret_cast(lhs.value)) == + *(reinterpret_cast(rhs.value)); + } + case Character_Rapunzel: { + return *(reinterpret_cast(lhs.value)) == + *(reinterpret_cast(rhs.value)); + } + case Character_Belle: { + return *(reinterpret_cast(lhs.value)) == + *(reinterpret_cast(rhs.value)); + } + case Character_BookFan: { + return *(reinterpret_cast(lhs.value)) == + *(reinterpret_cast(rhs.value)); + } + case Character_Other: { + return *(reinterpret_cast(lhs.value)) == + *(reinterpret_cast(rhs.value)); + } + case Character_Unused: { + return *(reinterpret_cast(lhs.value)) == + *(reinterpret_cast(rhs.value)); + } + default: { + return false; + } + } +} bool VerifyCharacter(flatbuffers::Verifier &verifier, const void *obj, Character type); bool VerifyCharacterVector(flatbuffers::Verifier &verifier, const flatbuffers::Vector> *values, const flatbuffers::Vector *types); @@ -161,6 +202,11 @@ FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(4) Rapunzel FLATBUFFERS_FINAL_CLASS { }; FLATBUFFERS_STRUCT_END(Rapunzel, 4); +inline bool operator==(const Rapunzel &lhs, const Rapunzel &rhs) { + return + (lhs.hair_length() == rhs.hair_length()); +} + FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(4) BookReader FLATBUFFERS_FINAL_CLASS { private: int32_t books_read_; @@ -181,6 +227,11 @@ FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(4) BookReader FLATBUFFERS_FINAL_CLASS { }; FLATBUFFERS_STRUCT_END(BookReader, 4); +inline bool operator==(const BookReader &lhs, const BookReader &rhs) { + return + (lhs.books_read() == rhs.books_read()); +} + struct AttackerT : public flatbuffers::NativeTable { typedef Attacker TableType; int32_t sword_attack_damage; @@ -189,6 +240,11 @@ struct AttackerT : public flatbuffers::NativeTable { } }; +inline bool operator==(const AttackerT &lhs, const AttackerT &rhs) { + return + (lhs.sword_attack_damage == rhs.sword_attack_damage); +} + struct Attacker FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { typedef AttackerT NativeTableType; static const flatbuffers::TypeTable *MiniReflectTypeTable() { @@ -249,6 +305,12 @@ struct MovieT : public flatbuffers::NativeTable { } }; +inline bool operator==(const MovieT &lhs, const MovieT &rhs) { + return + (lhs.main_character == rhs.main_character) && + (lhs.characters == rhs.characters); +} + struct Movie FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { typedef MovieT NativeTableType; static const flatbuffers::TypeTable *MiniReflectTypeTable() {