diff --git a/include/asenum/asenum.h b/include/asenum/asenum.h index 2650360..27f34ea 100644 --- a/include/asenum/asenum.h +++ b/include/asenum/asenum.h @@ -60,8 +60,11 @@ namespace asenum template class AsMap; + + template + struct Comparator; } - + /** @class Associated Enum type. AsEnum should be specialized with single or multiple 'Case/Case11' types that represent associations. @@ -138,6 +141,20 @@ namespace asenum */ template details::AsMap> doMap() const; + + /** + Compares two AsEnum instances. Instance meant to be equal if and only if + 1) Underlying enum cases are equal; + 2) Underlying values are equal. + */ + bool operator==(const AsEnum& other) const; + + /** + Compares two AsEnum instances. Instance meant to be equal if and only if + 1) Underlying enum cases are equal; + 2) Underlying values are equal. + */ + bool operator!=(const AsEnum& other) const; private: AsEnum(const Enum relatedCase, std::shared_ptr value); @@ -299,7 +316,41 @@ namespace asenum using type = typename TypeMap::type; static_assert(!std::is_same::value, "Type is missing for specified enum value."); }; - + + template + struct Comparator + { + template + static bool compare(const ConcreteAsEnum& first, const ConcreteAsEnum& second) + { + return first.template forceAsCase() == second.template forceAsCase(); + } + + template <> + static bool compare(const ConcreteAsEnum&, const ConcreteAsEnum&) + { + return true; + } + + static bool compare(const ConcreteAsEnum& first, const ConcreteAsEnum& second) + { + if (first.enumCase() != T_Case::Code || second.enumCase() != T_Case::Code) + { + return false; + } + + return compare(first, second); + } + }; + + template + struct Comparator + { + static bool compare(const ConcreteAsEnum& first, const ConcreteAsEnum& second) + { + return Comparator::compare(first, second) || Comparator::compare(first, second); + } + }; } } @@ -381,6 +432,18 @@ asenum::details::AsMap::Enum, asenum::AsE return details::AsMap>(*this); } +template +bool asenum::AsEnum::operator==(const AsEnum& other) const +{ + return details::Comparator::compare(*this, other); +} + +template +bool asenum::AsEnum::operator!=(const AsEnum& other) const +{ + return !(*this == other); +} + // AsEnum private @@ -404,7 +467,6 @@ typename std::enable_if::value, void>::type asenum::AsEnu handler(*reinterpret_cast(value)); } - // Private details - AsSwitch template diff --git a/tests/AsEnumTest.cpp b/tests/AsEnumTest.cpp index 20505da..75385f5 100644 --- a/tests/AsEnumTest.cpp +++ b/tests/AsEnumTest.cpp @@ -203,13 +203,30 @@ TEST(AsEnum, Map_All_Cases) TEST(AsEnum, ForceAsCase) { - const TestAsEnum value1 = TestAsEnum::create("test"); - // TestEnum::VoidOpt doesn't have 'forceAsEnum' method because associated type is 'void'. - const TestAsEnum value3 = TestAsEnum::create(-100500); + const TestAsEnum value1 = TestAsEnum::create("test"); + // TestEnum::VoidOpt doesn't have 'forceAsEnum' method because associated type is 'void'. + const TestAsEnum value3 = TestAsEnum::create(-100500); + + EXPECT_EQ(value1.forceAsCase(), "test"); + EXPECT_THROW(value1.forceAsCase(), std::invalid_argument); + + EXPECT_THROW(value3.forceAsCase(), std::invalid_argument); + EXPECT_EQ(value3.forceAsCase(), -100500); +} + +TEST(AsEnum, Compare) +{ + const TestAsEnum value1 = TestAsEnum::create("test"); + const TestAsEnum value2 = TestAsEnum::create("test"); + const TestAsEnum value3 = TestAsEnum::create("test2"); + const TestAsEnum value4 = TestAsEnum::create(); + const TestAsEnum value5 = TestAsEnum::create(-100500); - EXPECT_EQ(value1.forceAsCase(), "test"); - EXPECT_THROW(value1.forceAsCase(), std::invalid_argument); + EXPECT_EQ(value1, value1); + EXPECT_EQ(value1, value2); + EXPECT_NE(value1, value3); + EXPECT_NE(value1, value4); + EXPECT_NE(value1, value5); - EXPECT_THROW(value3.forceAsCase(), std::invalid_argument); - EXPECT_EQ(value3.forceAsCase(), -100500); + EXPECT_EQ(value4, TestAsEnum::create()); }