Index: include/llvm/ADT/Optional.h =================================================================== --- include/llvm/ADT/Optional.h +++ include/llvm/ADT/Optional.h @@ -150,14 +150,39 @@ static const bool value = isPodLike::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 -void operator==(const Optional &X, const Optional &Y); +template +bool operator==(const Optional &X, const Optional &Y) { + if (X.hasValue() && Y.hasValue()) + return *X == *Y; + return X.hasValue() == Y.hasValue(); +} + +template +bool operator!=(const Optional &X, const Optional &Y) { + return !(X == Y); +} + +template +bool operator<(const Optional &X, const Optional &Y) { + if (X.hasValue() && Y.hasValue()) + return *X < *Y; + return X.hasValue() < Y.hasValue(); +} + +template +bool operator<=(const Optional &X, const Optional &Y) { + return !(Y < X); +} + +template +bool operator>(const Optional &X, const Optional &Y) { + return Y < X; +} + +template +bool operator>=(const Optional &X, const Optional &Y) { + return !(X < Y); +} template bool operator==(const Optional &X, NoneType) { @@ -178,50 +203,86 @@ bool operator!=(NoneType, const Optional &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 -void operator!=(const Optional &X, const Optional &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 -void operator<(const Optional &X, const Optional &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 -void operator<=(const Optional &X, const Optional &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 -void operator>=(const Optional &X, const Optional &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 -void operator>(const Optional &X, const Optional &Y); + +template bool operator<(const Optional &X, NoneType) { + return false; +} + +template bool operator<(NoneType, const Optional &X) { + return X.hasValue(); +} + +template bool operator<=(const Optional &X, NoneType) { + return !(None < X); +} + +template bool operator<=(NoneType, const Optional &X) { + return !(X < None); +} + +template bool operator>(const Optional &X, NoneType) { + return None < X; +} + +template bool operator>(NoneType, const Optional &X) { + return X < None; +} + +template bool operator>=(const Optional &X, NoneType) { + return None <= X; +} + +template bool operator>=(NoneType, const Optional &X) { + return X <= None; +} + +template bool operator==(const Optional &X, const T &Y) { + return X.hasValue() && *X == Y; +} + +template bool operator==(const T &X, const Optional &Y) { + return Y == X; +} + +template bool operator!=(const Optional &X, const T &Y) { + return !(X == Y); +} + +template bool operator!=(const T &X, const Optional &Y) { + return !(X == Y); +} + +template bool operator<(const Optional &X, const T &Y) { + return !X.hasValue() || *X < Y; +} + +template bool operator<(const T &X, const Optional &Y) { + return Y.hasValue() && X < *Y; +} + +template bool operator<=(const Optional &X, const T &Y) { + return !(Y < X); +} + +template bool operator<=(const T &X, const Optional &Y) { + return !(Y < X); +} + +template bool operator>(const Optional &X, const T &Y) { + return Y < X; +} + +template bool operator>(const T &X, const Optional &Y) { + return Y < X; +} + +template bool operator>=(const Optional &X, const T &Y) { + return !(X < Y); +} + +template bool operator>=(const T &X, const Optional &Y) { + return !(X < Y); +} } // end llvm namespace Index: unittests/ADT/OptionalTest.cpp =================================================================== --- unittests/ADT/OptionalTest.cpp +++ unittests/ADT/OptionalTest.cpp @@ -377,17 +377,97 @@ #endif // LLVM_HAS_RVALUE_REFERENCE_THIS -TEST_F(OptionalTest, NoneComparison) { - Optional 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); +TEST_F(OptionalTest, Comparisonn) { + Optional Opts[] = {None, 3, 4}; + + // None 3 4 + // None = < < + // 3 > = < + // 4 > > = + int Results[3][3] = { + { 0, -1, -1 }, + { 1, 0, -1 }, + { 1, 1, 0 }, + }; + + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + switch (Results[i][j]) { + case -1: + EXPECT_FALSE(Opts[i] == Opts[j]); + EXPECT_TRUE(Opts[i] != Opts[j]); + EXPECT_TRUE(Opts[i] < Opts[j]); + EXPECT_FALSE(Opts[i] > Opts[j]); + EXPECT_TRUE(Opts[i] <= Opts[j]); + EXPECT_FALSE(Opts[i] >= Opts[j]); + if (Opts[i].hasValue()) { + EXPECT_FALSE(*Opts[i] == Opts[j]); + EXPECT_TRUE(*Opts[i] != Opts[j]); + EXPECT_TRUE(*Opts[i] < Opts[j]); + EXPECT_FALSE(*Opts[i] > Opts[j]); + EXPECT_TRUE(*Opts[i] <= Opts[j]); + EXPECT_FALSE(*Opts[i] >= Opts[j]); + } + if (Opts[j].hasValue()) { + EXPECT_FALSE(Opts[i] == *Opts[j]); + EXPECT_TRUE(Opts[i] != *Opts[j]); + EXPECT_TRUE(Opts[i] < *Opts[j]); + EXPECT_FALSE(Opts[i] > *Opts[j]); + EXPECT_TRUE(Opts[i] <= *Opts[j]); + EXPECT_FALSE(Opts[i] >= *Opts[j]); + } + break; + case 0: + EXPECT_TRUE(Opts[i] == Opts[j]); + EXPECT_FALSE(Opts[i] != Opts[j]); + EXPECT_FALSE(Opts[i] < Opts[j]); + EXPECT_FALSE(Opts[i] > Opts[j]); + EXPECT_TRUE(Opts[i] <= Opts[j]); + EXPECT_TRUE(Opts[i] >= Opts[j]); + if (Opts[i].hasValue()) { + EXPECT_TRUE(*Opts[i] == Opts[j]); + EXPECT_FALSE(*Opts[i] != Opts[j]); + EXPECT_FALSE(*Opts[i] < Opts[j]); + EXPECT_FALSE(*Opts[i] > Opts[j]); + EXPECT_TRUE(*Opts[i] <= Opts[j]); + EXPECT_TRUE(*Opts[i] >= Opts[j]); + } + if (Opts[j].hasValue()) { + EXPECT_TRUE(Opts[i] == *Opts[j]); + EXPECT_FALSE(Opts[i] != *Opts[j]); + EXPECT_FALSE(Opts[i] < *Opts[j]); + EXPECT_FALSE(Opts[i] > *Opts[j]); + EXPECT_TRUE(Opts[i] <= *Opts[j]); + EXPECT_TRUE(Opts[i] >= *Opts[j]); + } + break; + case 1: + EXPECT_FALSE(Opts[i] == Opts[j]); + EXPECT_TRUE(Opts[i] != Opts[j]); + EXPECT_FALSE(Opts[i] < Opts[j]); + EXPECT_TRUE(Opts[i] > Opts[j]); + EXPECT_FALSE(Opts[i] <= Opts[j]); + EXPECT_TRUE(Opts[i] >= Opts[j]); + if (Opts[i].hasValue()) { + EXPECT_FALSE(*Opts[i] == Opts[j]); + EXPECT_TRUE(*Opts[i] != Opts[j]); + EXPECT_FALSE(*Opts[i] < Opts[j]); + EXPECT_TRUE(*Opts[i] > Opts[j]); + EXPECT_FALSE(*Opts[i] <= Opts[j]); + EXPECT_TRUE(*Opts[i] >= Opts[j]); + } + if (Opts[j].hasValue()) { + EXPECT_FALSE(Opts[i] == *Opts[j]); + EXPECT_TRUE(Opts[i] != *Opts[j]); + EXPECT_FALSE(Opts[i] < *Opts[j]); + EXPECT_TRUE(Opts[i] > *Opts[j]); + EXPECT_FALSE(Opts[i] <= *Opts[j]); + EXPECT_TRUE(Opts[i] >= *Opts[j]); + } + break; + } + } + } } } // end anonymous namespace