Skip to content

Commit

Permalink
Added == and != operators
Browse files Browse the repository at this point in the history
  • Loading branch information
Vladimir Vashurkin (Alkenso) committed Aug 12, 2019
1 parent b766f68 commit e87a25f
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 10 deletions.
68 changes: 65 additions & 3 deletions include/asenum/asenum.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,11 @@ namespace asenum

template <typename T, typename Enum, typename ConcreteAsEnum, Enum... Types>
class AsMap;

template <typename ConcreteAsEnum, typename... T_Cases>
struct Comparator;
}
/**
@class Associated Enum type.
AsEnum should be specialized with single or multiple 'Case/Case11' types that represent associations.
Expand Down Expand Up @@ -138,6 +141,20 @@ namespace asenum
*/
template <typename T>
details::AsMap<T, Enum, AsEnum<T_Cases...>> 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<void> value);
Expand Down Expand Up @@ -299,7 +316,41 @@ namespace asenum
using type = typename TypeMap<Value, Dummy, Cases...>::type;
static_assert(!std::is_same<type, Dummy>::value, "Type is missing for specified enum value.");
};


template <typename ConcreteAsEnum, typename T_Case>
struct Comparator<ConcreteAsEnum, T_Case>
{
template <typename T>
static bool compare(const ConcreteAsEnum& first, const ConcreteAsEnum& second)
{
return first.template forceAsCase<T_Case::Code>() == second.template forceAsCase<T_Case::Code>();
}

template <>
static bool compare<void>(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<typename T_Case::Type>(first, second);
}
};

template <typename ConcreteAsEnum, typename T_Case, typename... T_Cases>
struct Comparator<ConcreteAsEnum, T_Case, T_Cases...>
{
static bool compare(const ConcreteAsEnum& first, const ConcreteAsEnum& second)
{
return Comparator<ConcreteAsEnum, T_Case>::compare(first, second) || Comparator<ConcreteAsEnum, T_Cases...>::compare(first, second);
}
};
}
}

Expand Down Expand Up @@ -381,6 +432,18 @@ asenum::details::AsMap<T, typename asenum::AsEnum<T_Cases...>::Enum, asenum::AsE
return details::AsMap<T, Enum, AsEnum<T_Cases...>>(*this);
}

template <typename... T_Cases>
bool asenum::AsEnum<T_Cases...>::operator==(const AsEnum& other) const
{
return details::Comparator<AsEnum, T_Cases...>::compare(*this, other);
}

template <typename... T_Cases>
bool asenum::AsEnum<T_Cases...>::operator!=(const AsEnum& other) const
{
return !(*this == other);
}


// AsEnum private

Expand All @@ -404,7 +467,6 @@ typename std::enable_if<!std::is_same<T, void>::value, void>::type asenum::AsEnu
handler(*reinterpret_cast<const T*>(value));
}


// Private details - AsSwitch

template <typename Enum, typename ConcreteAsEnum, Enum... Types>
Expand Down
31 changes: 24 additions & 7 deletions tests/AsEnumTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -203,13 +203,30 @@ TEST(AsEnum, Map_All_Cases)

TEST(AsEnum, ForceAsCase)
{
const TestAsEnum value1 = TestAsEnum::create<TestEnum::StringOpt>("test");
// TestEnum::VoidOpt doesn't have 'forceAsEnum' method because associated type is 'void'.
const TestAsEnum value3 = TestAsEnum::create<TestEnum::Unknown>(-100500);
const TestAsEnum value1 = TestAsEnum::create<TestEnum::StringOpt>("test");
// TestEnum::VoidOpt doesn't have 'forceAsEnum' method because associated type is 'void'.
const TestAsEnum value3 = TestAsEnum::create<TestEnum::Unknown>(-100500);

EXPECT_EQ(value1.forceAsCase<TestEnum::StringOpt>(), "test");
EXPECT_THROW(value1.forceAsCase<TestEnum::Unknown>(), std::invalid_argument);

EXPECT_THROW(value3.forceAsCase<TestEnum::StringOpt>(), std::invalid_argument);
EXPECT_EQ(value3.forceAsCase<TestEnum::Unknown>(), -100500);
}

TEST(AsEnum, Compare)
{
const TestAsEnum value1 = TestAsEnum::create<TestEnum::StringOpt>("test");
const TestAsEnum value2 = TestAsEnum::create<TestEnum::StringOpt>("test");
const TestAsEnum value3 = TestAsEnum::create<TestEnum::StringOpt>("test2");
const TestAsEnum value4 = TestAsEnum::create<TestEnum::VoidOpt>();
const TestAsEnum value5 = TestAsEnum::create<TestEnum::Unknown>(-100500);

EXPECT_EQ(value1.forceAsCase<TestEnum::StringOpt>(), "test");
EXPECT_THROW(value1.forceAsCase<TestEnum::Unknown>(), 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<TestEnum::StringOpt>(), std::invalid_argument);
EXPECT_EQ(value3.forceAsCase<TestEnum::Unknown>(), -100500);
EXPECT_EQ(value4, TestAsEnum::create<TestEnum::VoidOpt>());
}

0 comments on commit e87a25f

Please sign in to comment.