Commit 33791dc7 authored by Thomas's avatar Thomas Committed by Wouter van Oortmerssen

Add compare operator to code generated for c++ (#4940)

* Add operator== for c++ genated code

New "--gen-compare" option for flatc to generate compare operators. The operators are defined based on object based api types.

Inspired by issue #263.

* Improve compare operator for c++.
Thanks for the code review.

- Improve robustness against future schema extensions
- Code style
- Fix --rust generation in generate_code.sh
parent 873a60b0
......@@ -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"
......
......@@ -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
......
......@@ -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"),
......
......@@ -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<const WeaponT *>(lhs.value)) ==
*(reinterpret_cast<const WeaponT *>(rhs.value));
}
default: {
return false;
}
}
}
bool VerifyEquipment(flatbuffers::Verifier &verifier, const void *obj, Equipment type);
bool VerifyEquipmentVector(flatbuffers::Verifier &verifier, const flatbuffers::Vector<flatbuffers::Offset<void>> *values, const flatbuffers::Vector<uint8_t> *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<Vec3> 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() {
......
......@@ -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];
......
......@@ -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<const {{NATIVE_TYPE}} *>(lhs.value)) ==";
code_ += " *(reinterpret_cast<const {{NATIVE_TYPE}} *>(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_ += "";
}
......
......@@ -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
......@@ -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
......@@ -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<const MonsterT *>(lhs.value)) ==
*(reinterpret_cast<const MonsterT *>(rhs.value));
}
case Any_TestSimpleTableWithEnum: {
return *(reinterpret_cast<const TestSimpleTableWithEnumT *>(lhs.value)) ==
*(reinterpret_cast<const TestSimpleTableWithEnumT *>(rhs.value));
}
case Any_MyGame_Example2_Monster: {
return *(reinterpret_cast<const MyGame::Example2::MonsterT *>(lhs.value)) ==
*(reinterpret_cast<const MyGame::Example2::MonsterT *>(rhs.value));
}
default: {
return false;
}
}
}
bool VerifyAny(flatbuffers::Verifier &verifier, const void *obj, Any type);
bool VerifyAnyVector(flatbuffers::Verifier &verifier, const flatbuffers::Vector<flatbuffers::Offset<void>> *values, const flatbuffers::Vector<uint8_t> *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() {
......
......@@ -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");
......
......@@ -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<const AttackerT *>(lhs.value)) ==
*(reinterpret_cast<const AttackerT *>(rhs.value));
}
case Character_Rapunzel: {
return *(reinterpret_cast<const Rapunzel *>(lhs.value)) ==
*(reinterpret_cast<const Rapunzel *>(rhs.value));
}
case Character_Belle: {
return *(reinterpret_cast<const BookReader *>(lhs.value)) ==
*(reinterpret_cast<const BookReader *>(rhs.value));
}
case Character_BookFan: {
return *(reinterpret_cast<const BookReader *>(lhs.value)) ==
*(reinterpret_cast<const BookReader *>(rhs.value));
}
case Character_Other: {
return *(reinterpret_cast<const std::string *>(lhs.value)) ==
*(reinterpret_cast<const std::string *>(rhs.value));
}
case Character_Unused: {
return *(reinterpret_cast<const std::string *>(lhs.value)) ==
*(reinterpret_cast<const std::string *>(rhs.value));
}
default: {
return false;
}
}
}
bool VerifyCharacter(flatbuffers::Verifier &verifier, const void *obj, Character type);
bool VerifyCharacterVector(flatbuffers::Verifier &verifier, const flatbuffers::Vector<flatbuffers::Offset<void>> *values, const flatbuffers::Vector<uint8_t> *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() {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment