diff --git a/include/reflection-cpp/reflection.hpp b/include/reflection-cpp/reflection.hpp index 6229d85..fe5cc29 100644 --- a/include/reflection-cpp/reflection.hpp +++ b/include/reflection-cpp/reflection.hpp @@ -811,6 +811,25 @@ std::string Inspect(std::vector const& objects) } return str; } + +template +void CollectDifferences(const Object& lhs, const Object& rhs, Callback&& callback) +{ + template_for<0, CountMembers>([&]() { + if constexpr (std::equality_comparable>) + { + if (GetMemberAt(lhs) != GetMemberAt(rhs)) + { + callback(MemberNameOf, GetMemberAt(lhs), GetMemberAt(rhs)); + } + } + else + { + CollectDifferences(GetMemberAt(lhs), GetMemberAt(rhs), callback); + } + }); +} + } // namespace Reflection template diff --git a/test-reflection-cpp.cpp b/test-reflection-cpp.cpp index d4c98fc..7c32881 100644 --- a/test-reflection-cpp.cpp +++ b/test-reflection-cpp.cpp @@ -102,3 +102,53 @@ TEST_CASE("MemberTypeOf", "[reflection]") static_assert(std::same_as, std::string>); static_assert(std::same_as, Person>); } + +struct Record +{ + int id; + std::string name; + int age; +}; + +TEST_CASE("Compare.simple", "[reflection]") +{ + auto const r1 = Record { .id = 1, .name = "John Doe", .age = 42 }; + auto const r2 = Record { .id = 1, .name = "John Doe", .age = 42 }; + auto const r3 = Record { .id = 2, .name = "Jane Doe", .age = 43 }; + + std::string diff; + auto differenceCallback = [&](std::string_view name, auto const& lhs, auto const& rhs) { + diff += std::format("{}: {} != {}\n", name, lhs, rhs); + }; + + Reflection::CollectDifferences(r1, r2, differenceCallback); + CHECK(diff.empty()); + Reflection::CollectDifferences(r1, r3, differenceCallback); + CHECK(diff == "id: 1 != 2\nname: John Doe != Jane Doe\nage: 42 != 43\n"); +} + +struct Table +{ + Record first; + Record second; +}; + +TEST_CASE("Compare.nested", "[reflection]") +{ + auto const t1 = Table { .first = { .id = 1, .name = "John Doe", .age = 42 }, + .second = { .id = 2, .name = "Jane Doe", .age = 43 } }; + auto const t2 = Table { .first = { .id = 1, .name = "John Doe", .age = 42 }, + .second = { .id = 2, .name = "Jane Doe", .age = 43 } }; + auto const t3 = Table { .first = { .id = 1, .name = "John Doe", .age = 42 }, + .second = { .id = 3, .name = "Jane Doe", .age = 43 } }; + + std::string diff; + auto differenceCallback = [&](std::string_view name, auto const& lhs, auto const& rhs) { + diff += std::format("{}: {} != {}\n", name, lhs, rhs); + }; + + Reflection::CollectDifferences(t1, t2, differenceCallback); + CHECK(diff.empty()); + Reflection::CollectDifferences(t1, t3, differenceCallback); + CHECK(diff == "id: 2 != 3\n"); +}