Skip to content

Commit

Permalink
[ADT] Add relation operators for Optional
Browse files Browse the repository at this point in the history
Summary: Make Optional's behavior the same as the coming std::optional.

Reviewers: dblaikie

Subscribers: llvm-commits

Differential Revision: https://reviews.llvm.org/D23178

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@278397 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
timshen91 committed Aug 11, 2016
1 parent eeb1d4f commit 4c26d96
Show file tree
Hide file tree
Showing 2 changed files with 253 additions and 64 deletions.
167 changes: 114 additions & 53 deletions include/llvm/ADT/Optional.h
Original file line number Diff line number Diff line change
Expand Up @@ -150,18 +150,43 @@ template <typename T> struct isPodLike<Optional<T> > {
static const bool value = isPodLike<T>::value;
};

/// \brief Poison comparison between two \c Optional objects. Clients needs to
/// explicitly compare the underlying values and account for empty \c Optional
/// objects.
///
/// This routine will never be defined. It returns \c void to help diagnose
/// errors at compile time.
template<typename T, typename U>
void operator==(const Optional<T> &X, const Optional<U> &Y);
template <typename T, typename U>
bool operator==(const Optional<T> &X, const Optional<U> &Y) {
if (X && Y)
return *X == *Y;
return X.hasValue() == Y.hasValue();
}

template <typename T, typename U>
bool operator!=(const Optional<T> &X, const Optional<U> &Y) {
return !(X == Y);
}

template <typename T, typename U>
bool operator<(const Optional<T> &X, const Optional<U> &Y) {
if (X && Y)
return *X < *Y;
return X.hasValue() < Y.hasValue();
}

template <typename T, typename U>
bool operator<=(const Optional<T> &X, const Optional<U> &Y) {
return !(Y < X);
}

template <typename T, typename U>
bool operator>(const Optional<T> &X, const Optional<U> &Y) {
return Y < X;
}

template <typename T, typename U>
bool operator>=(const Optional<T> &X, const Optional<U> &Y) {
return !(X < Y);
}

template<typename T>
bool operator==(const Optional<T> &X, NoneType) {
return !X.hasValue();
return !X;
}

template<typename T>
Expand All @@ -178,50 +203,86 @@ template<typename T>
bool operator!=(NoneType, const Optional<T> &X) {
return X != None;
}
/// \brief Poison comparison between two \c Optional objects. Clients needs to
/// explicitly compare the underlying values and account for empty \c Optional
/// objects.
///
/// This routine will never be defined. It returns \c void to help diagnose
/// errors at compile time.
template<typename T, typename U>
void operator!=(const Optional<T> &X, const Optional<U> &Y);

/// \brief Poison comparison between two \c Optional objects. Clients needs to
/// explicitly compare the underlying values and account for empty \c Optional
/// objects.
///
/// This routine will never be defined. It returns \c void to help diagnose
/// errors at compile time.
template<typename T, typename U>
void operator<(const Optional<T> &X, const Optional<U> &Y);

/// \brief Poison comparison between two \c Optional objects. Clients needs to
/// explicitly compare the underlying values and account for empty \c Optional
/// objects.
///
/// This routine will never be defined. It returns \c void to help diagnose
/// errors at compile time.
template<typename T, typename U>
void operator<=(const Optional<T> &X, const Optional<U> &Y);

/// \brief Poison comparison between two \c Optional objects. Clients needs to
/// explicitly compare the underlying values and account for empty \c Optional
/// objects.
///
/// This routine will never be defined. It returns \c void to help diagnose
/// errors at compile time.
template<typename T, typename U>
void operator>=(const Optional<T> &X, const Optional<U> &Y);

/// \brief Poison comparison between two \c Optional objects. Clients needs to
/// explicitly compare the underlying values and account for empty \c Optional
/// objects.
///
/// This routine will never be defined. It returns \c void to help diagnose
/// errors at compile time.
template<typename T, typename U>
void operator>(const Optional<T> &X, const Optional<U> &Y);

template <typename T> bool operator<(const Optional<T> &X, NoneType) {
return false;
}

template <typename T> bool operator<(NoneType, const Optional<T> &X) {
return X.hasValue();
}

template <typename T> bool operator<=(const Optional<T> &X, NoneType) {
return !(None < X);
}

template <typename T> bool operator<=(NoneType, const Optional<T> &X) {
return !(X < None);
}

template <typename T> bool operator>(const Optional<T> &X, NoneType) {
return None < X;
}

template <typename T> bool operator>(NoneType, const Optional<T> &X) {
return X < None;
}

template <typename T> bool operator>=(const Optional<T> &X, NoneType) {
return None <= X;
}

template <typename T> bool operator>=(NoneType, const Optional<T> &X) {
return X <= None;
}

template <typename T> bool operator==(const Optional<T> &X, const T &Y) {
return X && *X == Y;
}

template <typename T> bool operator==(const T &X, const Optional<T> &Y) {
return Y && X == *Y;
}

template <typename T> bool operator!=(const Optional<T> &X, const T &Y) {
return !(X == Y);
}

template <typename T> bool operator!=(const T &X, const Optional<T> &Y) {
return !(X == Y);
}

template <typename T> bool operator<(const Optional<T> &X, const T &Y) {
return !X || *X < Y;
}

template <typename T> bool operator<(const T &X, const Optional<T> &Y) {
return Y && X < *Y;
}

template <typename T> bool operator<=(const Optional<T> &X, const T &Y) {
return !(Y < X);
}

template <typename T> bool operator<=(const T &X, const Optional<T> &Y) {
return !(Y < X);
}

template <typename T> bool operator>(const Optional<T> &X, const T &Y) {
return Y < X;
}

template <typename T> bool operator>(const T &X, const Optional<T> &Y) {
return Y < X;
}

template <typename T> bool operator>=(const Optional<T> &X, const T &Y) {
return !(X < Y);
}

template <typename T> bool operator>=(const T &X, const Optional<T> &Y) {
return !(X < Y);
}

} // end llvm namespace

Expand Down
150 changes: 139 additions & 11 deletions unittests/ADT/OptionalTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include "gtest/gtest.h"
#include "llvm/ADT/Optional.h"

using namespace llvm;

namespace {
Expand Down Expand Up @@ -377,17 +378,144 @@ TEST_F(OptionalTest, MoveGetValueOr) {

#endif // LLVM_HAS_RVALUE_REFERENCE_THIS

TEST_F(OptionalTest, NoneComparison) {
Optional<int> o;
EXPECT_EQ(o, None);
EXPECT_EQ(None, o);
EXPECT_FALSE(o != None);
EXPECT_FALSE(None != o);
o = 3;
EXPECT_FALSE(o == None);
EXPECT_FALSE(None == o);
EXPECT_TRUE(o != None);
EXPECT_TRUE(None != o);
struct EqualTo {
template <typename T, typename U> static bool apply(const T &X, const U &Y) {
return X == Y;
}
};

struct NotEqualTo {
template <typename T, typename U> static bool apply(const T &X, const U &Y) {
return X != Y;
}
};

struct Less {
template <typename T, typename U> static bool apply(const T &X, const U &Y) {
return X < Y;
}
};

struct Greater {
template <typename T, typename U> static bool apply(const T &X, const U &Y) {
return X > Y;
}
};

struct LessEqual {
template <typename T, typename U> static bool apply(const T &X, const U &Y) {
return X <= Y;
}
};

struct GreaterEqual {
template <typename T, typename U> static bool apply(const T &X, const U &Y) {
return X >= Y;
}
};

template <typename OperatorT, typename T>
void CheckRelation(const Optional<T> &Lhs, const Optional<T> &Rhs,
bool Expected) {
EXPECT_EQ(Expected, OperatorT::apply(Lhs, Rhs));

if (Lhs)
EXPECT_EQ(Expected, OperatorT::apply(*Lhs, Rhs));
else
EXPECT_EQ(Expected, OperatorT::apply(None, Rhs));

if (Rhs)
EXPECT_EQ(Expected, OperatorT::apply(Lhs, *Rhs));
else
EXPECT_EQ(Expected, OperatorT::apply(Lhs, None));
}

struct EqualityMock {};
const Optional<EqualityMock> NoneEq, EqualityLhs((EqualityMock())),
EqualityRhs((EqualityMock()));
bool IsEqual;

bool operator==(const EqualityMock &Lhs, const EqualityMock &Rhs) {
EXPECT_EQ(&*EqualityLhs, &Lhs);
EXPECT_EQ(&*EqualityRhs, &Rhs);
return IsEqual;
}

TEST_F(OptionalTest, OperatorEqual) {
CheckRelation<EqualTo>(NoneEq, NoneEq, true);
CheckRelation<EqualTo>(NoneEq, EqualityRhs, false);
CheckRelation<EqualTo>(EqualityLhs, NoneEq, false);

IsEqual = false;
CheckRelation<EqualTo>(EqualityLhs, EqualityRhs, IsEqual);
IsEqual = true;
CheckRelation<EqualTo>(EqualityLhs, EqualityRhs, IsEqual);
}

TEST_F(OptionalTest, OperatorNotEqual) {
CheckRelation<NotEqualTo>(NoneEq, NoneEq, false);
CheckRelation<NotEqualTo>(NoneEq, EqualityRhs, true);
CheckRelation<NotEqualTo>(EqualityLhs, NoneEq, true);

IsEqual = false;
CheckRelation<NotEqualTo>(EqualityLhs, EqualityRhs, !IsEqual);
IsEqual = true;
CheckRelation<NotEqualTo>(EqualityLhs, EqualityRhs, !IsEqual);
}

struct InequalityMock {};
const Optional<InequalityMock> NoneIneq, InequalityLhs((InequalityMock())),
InequalityRhs((InequalityMock()));
bool IsLess;

bool operator<(const InequalityMock &Lhs, const InequalityMock &Rhs) {
EXPECT_EQ(&*InequalityLhs, &Lhs);
EXPECT_EQ(&*InequalityRhs, &Rhs);
return IsLess;
}

TEST_F(OptionalTest, OperatorLess) {
CheckRelation<Less>(NoneIneq, NoneIneq, false);
CheckRelation<Less>(NoneIneq, InequalityRhs, true);
CheckRelation<Less>(InequalityLhs, NoneIneq, false);

IsLess = false;
CheckRelation<Less>(InequalityLhs, InequalityRhs, IsLess);
IsLess = true;
CheckRelation<Less>(InequalityLhs, InequalityRhs, IsLess);
}

TEST_F(OptionalTest, OperatorGreater) {
CheckRelation<Greater>(NoneIneq, NoneIneq, false);
CheckRelation<Greater>(NoneIneq, InequalityRhs, false);
CheckRelation<Greater>(InequalityLhs, NoneIneq, true);

IsLess = false;
CheckRelation<Greater>(InequalityRhs, InequalityLhs, IsLess);
IsLess = true;
CheckRelation<Greater>(InequalityRhs, InequalityLhs, IsLess);
}

TEST_F(OptionalTest, OperatorLessEqual) {
CheckRelation<LessEqual>(NoneIneq, NoneIneq, true);
CheckRelation<LessEqual>(NoneIneq, InequalityRhs, true);
CheckRelation<LessEqual>(InequalityLhs, NoneIneq, false);

IsLess = false;
CheckRelation<LessEqual>(InequalityRhs, InequalityLhs, !IsLess);
IsLess = true;
CheckRelation<LessEqual>(InequalityRhs, InequalityLhs, !IsLess);
}

TEST_F(OptionalTest, OperatorGreaterEqual) {
CheckRelation<GreaterEqual>(NoneIneq, NoneIneq, true);
CheckRelation<GreaterEqual>(NoneIneq, InequalityRhs, false);
CheckRelation<GreaterEqual>(InequalityLhs, NoneIneq, true);

IsLess = false;
CheckRelation<GreaterEqual>(InequalityLhs, InequalityRhs, !IsLess);
IsLess = true;
CheckRelation<GreaterEqual>(InequalityLhs, InequalityRhs, !IsLess);
}

} // end anonymous namespace
Expand Down

0 comments on commit 4c26d96

Please sign in to comment.