diff options
author | Kyle Edwards <kyle.edwards@kitware.com> | 2020-09-08 13:55:10 (GMT) |
---|---|---|
committer | Kitware Robot <kwrobot@kitware.com> | 2020-09-08 13:55:18 (GMT) |
commit | 1d74a64f3839edc6f6c5c651f8d446a7d5875fc0 (patch) | |
tree | b565434960678a20d1245c2defa7cbf26fd9f56f | |
parent | 56134c1708bb227ebded52e66963b58acae7a958 (diff) | |
parent | 7e1304c6e61a25aac6fcf1bee47a719ac39075e5 (diff) | |
download | CMake-1d74a64f3839edc6f6c5c651f8d446a7d5875fc0.zip CMake-1d74a64f3839edc6f6c5c651f8d446a7d5875fc0.tar.gz CMake-1d74a64f3839edc6f6c5c651f8d446a7d5875fc0.tar.bz2 |
Merge topic 'cm-optional-comparison'
7e1304c6e6 cm::optional: Add comparison operators
c854e9eba5 Refactor: Add ASSERT_TRUE() macro to testOptional.cxx
Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !5195
-rw-r--r-- | Tests/CMakeLib/testOptional.cxx | 315 | ||||
-rw-r--r-- | Utilities/std/cm/optional | 204 |
2 files changed, 401 insertions, 118 deletions
diff --git a/Tests/CMakeLib/testOptional.cxx b/Tests/CMakeLib/testOptional.cxx index c6bc9c2..de09c0f 100644 --- a/Tests/CMakeLib/testOptional.cxx +++ b/Tests/CMakeLib/testOptional.cxx @@ -29,6 +29,13 @@ public: CONST_RVALUE_REFERENCE, SWAP, + + COMPARE_EE_EQ, + COMPARE_EE_NE, + COMPARE_EE_LT, + COMPARE_EE_LE, + COMPARE_EE_GT, + COMPARE_EE_GE, }; EventType Type; @@ -75,6 +82,14 @@ public: int Value = 0; }; +#define ASSERT_TRUE(x) \ + do { \ + if (!(x)) { \ + std::cout << "ASSERT_TRUE(" #x ") failed on line " << __LINE__ << "\n"; \ + return false; \ + } \ + } while (false) + // Certain builds of GCC generate false -Wmaybe-uninitialized warnings when // doing a release build with the system version of std::optional. These // warnings do not manifest when using our own cm::optional implementation. @@ -153,6 +168,42 @@ EventLogger& EventLogger::operator=(int value) return *this; } +bool operator==(const EventLogger& lhs, const EventLogger& rhs) +{ + events.push_back({ Event::COMPARE_EE_EQ, &lhs, &rhs, lhs.Value }); + return lhs.Value == rhs.Value; +} + +bool operator!=(const EventLogger& lhs, const EventLogger& rhs) +{ + events.push_back({ Event::COMPARE_EE_NE, &lhs, &rhs, lhs.Value }); + return lhs.Value != rhs.Value; +} + +bool operator<(const EventLogger& lhs, const EventLogger& rhs) +{ + events.push_back({ Event::COMPARE_EE_LT, &lhs, &rhs, lhs.Value }); + return lhs.Value < rhs.Value; +} + +bool operator<=(const EventLogger& lhs, const EventLogger& rhs) +{ + events.push_back({ Event::COMPARE_EE_LE, &lhs, &rhs, lhs.Value }); + return lhs.Value <= rhs.Value; +} + +bool operator>(const EventLogger& lhs, const EventLogger& rhs) +{ + events.push_back({ Event::COMPARE_EE_GT, &lhs, &rhs, lhs.Value }); + return lhs.Value > rhs.Value; +} + +bool operator>=(const EventLogger& lhs, const EventLogger& rhs) +{ + events.push_back({ Event::COMPARE_EE_GE, &lhs, &rhs, lhs.Value }); + return lhs.Value >= rhs.Value; +} + void EventLogger::Reference() & { events.push_back({ Event::REFERENCE, this, nullptr, this->Value }); @@ -368,42 +419,23 @@ static bool testDereference(std::vector<Event>& expected) static bool testHasValue(std::vector<Event>& expected) { - bool retval = true; - const cm::optional<EventLogger> o1{ 4 }; const cm::optional<EventLogger> o2{}; - if (!o1.has_value()) { - std::cout << "o1 should have a value" << std::endl; - retval = false; - } - - if (!o1) { - std::cout << "(bool)o1 should be true" << std::endl; - retval = false; - } - - if (o2.has_value()) { - std::cout << "o2 should not have a value" << std::endl; - retval = false; - } - - if (o2) { - std::cout << "(bool)o2 should be false" << std::endl; - retval = false; - } + ASSERT_TRUE(o1.has_value()); + ASSERT_TRUE(o1); + ASSERT_TRUE(!o2.has_value()); + ASSERT_TRUE(!o2); expected = { { Event::VALUE_CONSTRUCT, &*o1, nullptr, 4 }, { Event::DESTRUCT, &*o1, nullptr, 4 }, }; - return retval; + return true; } static bool testValue(std::vector<Event>& expected) { - bool retval = true; - cm::optional<EventLogger> o1{ 4 }; const cm::optional<EventLogger> o2{ 5 }; cm::optional<EventLogger> o3{}; @@ -418,10 +450,7 @@ static bool testValue(std::vector<Event>& expected) } catch (cm::bad_optional_access&) { thrown = true; } - if (!thrown) { - std::cout << "o3.value() did not throw" << std::endl; - retval = false; - } + ASSERT_TRUE(thrown); thrown = false; try { @@ -429,10 +458,7 @@ static bool testValue(std::vector<Event>& expected) } catch (cm::bad_optional_access&) { thrown = true; } - if (!thrown) { - std::cout << "o4.value() did not throw" << std::endl; - retval = false; - } + ASSERT_TRUE(thrown); expected = { { Event::VALUE_CONSTRUCT, &*o1, nullptr, 4 }, @@ -442,13 +468,11 @@ static bool testValue(std::vector<Event>& expected) { Event::DESTRUCT, &*o2, nullptr, 5 }, { Event::DESTRUCT, &*o1, nullptr, 4 }, }; - return retval; + return true; } static bool testValueOr() { - bool retval = true; - const cm::optional<EventLogger> o1{ 4 }; cm::optional<EventLogger> o2{ 5 }; const cm::optional<EventLogger> o3{}; @@ -460,33 +484,133 @@ static bool testValueOr() EventLogger e4{ 9 }; EventLogger r1 = o1.value_or(e1); - if (r1.Value != 4) { - std::cout << "r1.Value should be 4" << std::endl; - retval = false; - } + ASSERT_TRUE(r1.Value == 4); EventLogger r2 = std::move(o2).value_or(e2); - if (r2.Value != 5) { - std::cout << "r2.Value should be 5" << std::endl; - retval = false; - } + ASSERT_TRUE(r2.Value == 5); EventLogger r3 = o3.value_or(e3); - if (r3.Value != 8) { - std::cout << "r3.Value should be 8" << std::endl; - retval = false; - } + ASSERT_TRUE(r3.Value == 8); EventLogger r4 = std::move(o4).value_or(e4); - if (r4.Value != 9) { - std::cout << "r4.Value should be 9" << std::endl; - retval = false; - } + ASSERT_TRUE(r4.Value == 9); - return retval; + return true; } -static bool testSwap(std::vector<Event>& expected) +static bool testComparison(std::vector<Event>& expected) { - bool retval = true; + const cm::optional<EventLogger> o1{ 1 }; + const cm::optional<EventLogger> o2{ 2 }; + const cm::optional<EventLogger> o3{ 2 }; + const cm::optional<EventLogger> o4{}; + const cm::optional<EventLogger> o5{}; + const EventLogger e1{ 2 }; + + ASSERT_TRUE(!(o1 == o2) && o1 != o2); + ASSERT_TRUE(o1 < o2 && !(o1 >= o2)); + ASSERT_TRUE(!(o1 > o2) && o1 <= o2); + + ASSERT_TRUE(o2 == o3 && !(o2 != o3)); + ASSERT_TRUE(!(o2 < o3) && o2 >= o3); + ASSERT_TRUE(!(o2 > o3) && o2 <= o3); + + ASSERT_TRUE(!(o3 == o4) && o3 != o4); + ASSERT_TRUE(!(o3 < o4) && o3 >= o4); + ASSERT_TRUE(o3 > o4 && !(o3 <= o4)); + + ASSERT_TRUE(o4 == o5 && !(o4 != o5)); + ASSERT_TRUE(!(o4 < o5) && o4 >= o5); + ASSERT_TRUE(!(o4 > o5) && o4 <= o5); + + ASSERT_TRUE(!(o1 == cm::nullopt) && o1 != cm::nullopt); + ASSERT_TRUE(!(o1 < cm::nullopt) && o1 >= cm::nullopt); + ASSERT_TRUE(o1 > cm::nullopt && !(o1 <= cm::nullopt)); + + ASSERT_TRUE(!(cm::nullopt == o1) && cm::nullopt != o1); + ASSERT_TRUE(cm::nullopt < o1 && !(cm::nullopt >= o1)); + ASSERT_TRUE(!(cm::nullopt > o1) && cm::nullopt <= o1); + + ASSERT_TRUE(o4 == cm::nullopt && !(o4 != cm::nullopt)); + ASSERT_TRUE(!(o4 < cm::nullopt) && o4 >= cm::nullopt); + ASSERT_TRUE(!(o4 > cm::nullopt) && o4 <= cm::nullopt); + + ASSERT_TRUE(cm::nullopt == o4 && !(cm::nullopt != o4)); + ASSERT_TRUE(!(cm::nullopt < o4) && cm::nullopt >= o4); + ASSERT_TRUE(!(cm::nullopt > o4) && cm::nullopt <= o4); + + ASSERT_TRUE(!(o1 == e1) && o1 != e1); + ASSERT_TRUE(o1 < e1 && !(o1 >= e1)); + ASSERT_TRUE(!(o1 > e1) && o1 <= e1); + + ASSERT_TRUE(o2 == e1 && !(o2 != e1)); + ASSERT_TRUE(!(o2 < e1) && o2 >= e1); + ASSERT_TRUE(!(o2 > e1) && o2 <= e1); + ASSERT_TRUE(!(o4 == e1) && o4 != e1); + ASSERT_TRUE(o4 < e1 && !(o4 >= e1)); + ASSERT_TRUE(!(o4 > e1) && o4 <= e1); + + ASSERT_TRUE(!(e1 == o1) && e1 != o1); + ASSERT_TRUE(!(e1 < o1) && e1 >= o1); + ASSERT_TRUE(e1 > o1 && !(e1 <= o1)); + + ASSERT_TRUE(e1 == o2 && !(e1 != o2)); + ASSERT_TRUE(!(e1 < o2) && e1 >= o2); + ASSERT_TRUE(!(e1 > o2) && e1 <= o2); + + ASSERT_TRUE(!(e1 == o4) && e1 != o4); + ASSERT_TRUE(!(e1 < o4) && e1 >= o4); + ASSERT_TRUE(e1 > o4 && !(e1 <= o4)); + + expected = { + { Event::VALUE_CONSTRUCT, &*o1, nullptr, 1 }, + { Event::VALUE_CONSTRUCT, &*o2, nullptr, 2 }, + { Event::VALUE_CONSTRUCT, &*o3, nullptr, 2 }, + { Event::VALUE_CONSTRUCT, &e1, nullptr, 2 }, + { Event::COMPARE_EE_EQ, &*o1, &*o2, 1 }, + { Event::COMPARE_EE_NE, &*o1, &*o2, 1 }, + { Event::COMPARE_EE_LT, &*o1, &*o2, 1 }, + { Event::COMPARE_EE_GE, &*o1, &*o2, 1 }, + { Event::COMPARE_EE_GT, &*o1, &*o2, 1 }, + { Event::COMPARE_EE_LE, &*o1, &*o2, 1 }, + { Event::COMPARE_EE_EQ, &*o2, &*o3, 2 }, + { Event::COMPARE_EE_NE, &*o2, &*o3, 2 }, + { Event::COMPARE_EE_LT, &*o2, &*o3, 2 }, + { Event::COMPARE_EE_GE, &*o2, &*o3, 2 }, + { Event::COMPARE_EE_GT, &*o2, &*o3, 2 }, + { Event::COMPARE_EE_LE, &*o2, &*o3, 2 }, + { Event::COMPARE_EE_EQ, &*o1, &e1, 1 }, + { Event::COMPARE_EE_NE, &*o1, &e1, 1 }, + { Event::COMPARE_EE_LT, &*o1, &e1, 1 }, + { Event::COMPARE_EE_GE, &*o1, &e1, 1 }, + { Event::COMPARE_EE_GT, &*o1, &e1, 1 }, + { Event::COMPARE_EE_LE, &*o1, &e1, 1 }, + { Event::COMPARE_EE_EQ, &*o2, &e1, 2 }, + { Event::COMPARE_EE_NE, &*o2, &e1, 2 }, + { Event::COMPARE_EE_LT, &*o2, &e1, 2 }, + { Event::COMPARE_EE_GE, &*o2, &e1, 2 }, + { Event::COMPARE_EE_GT, &*o2, &e1, 2 }, + { Event::COMPARE_EE_LE, &*o2, &e1, 2 }, + { Event::COMPARE_EE_EQ, &e1, &*o1, 2 }, + { Event::COMPARE_EE_NE, &e1, &*o1, 2 }, + { Event::COMPARE_EE_LT, &e1, &*o1, 2 }, + { Event::COMPARE_EE_GE, &e1, &*o1, 2 }, + { Event::COMPARE_EE_GT, &e1, &*o1, 2 }, + { Event::COMPARE_EE_LE, &e1, &*o1, 2 }, + { Event::COMPARE_EE_EQ, &e1, &*o2, 2 }, + { Event::COMPARE_EE_NE, &e1, &*o2, 2 }, + { Event::COMPARE_EE_LT, &e1, &*o2, 2 }, + { Event::COMPARE_EE_GE, &e1, &*o2, 2 }, + { Event::COMPARE_EE_GT, &e1, &*o2, 2 }, + { Event::COMPARE_EE_LE, &e1, &*o2, 2 }, + { Event::DESTRUCT, &e1, nullptr, 2 }, + { Event::DESTRUCT, &*o3, nullptr, 2 }, + { Event::DESTRUCT, &*o2, nullptr, 2 }, + { Event::DESTRUCT, &*o1, nullptr, 1 }, + }; + return true; +} + +static bool testSwap(std::vector<Event>& expected) +{ cm::optional<EventLogger> o1{ 4 }; auto const* v1 = &*o1; cm::optional<EventLogger> o2{}; @@ -494,66 +618,30 @@ static bool testSwap(std::vector<Event>& expected) o1.swap(o2); auto const* v2 = &*o2; - if (o1.has_value()) { - std::cout << "o1 should not have value" << std::endl; - retval = false; - } - if (!o2.has_value()) { - std::cout << "o2 should have value" << std::endl; - retval = false; - } - if (o2.value().Value != 4) { - std::cout << "value of o2 should be 4" << std::endl; - retval = false; - } + ASSERT_TRUE(!o1.has_value()); + ASSERT_TRUE(o2.has_value()); + ASSERT_TRUE(o2.value().Value == 4); o1.swap(o2); - if (!o1.has_value()) { - std::cout << "o1 should have value" << std::endl; - retval = false; - } - if (o1.value().Value != 4) { - std::cout << "value of o1 should be 4" << std::endl; - retval = false; - } - if (o2.has_value()) { - std::cout << "o2 should not have value" << std::endl; - retval = false; - } + ASSERT_TRUE(o1.has_value()); + ASSERT_TRUE(o1.value().Value == 4); + ASSERT_TRUE(!o2.has_value()); o2.emplace(5); o1.swap(o2); - if (!o1.has_value()) { - std::cout << "o1 should have value" << std::endl; - retval = false; - } - if (o1.value().Value != 5) { - std::cout << "value of o1 should be 5" << std::endl; - retval = false; - } - if (!o2.has_value()) { - std::cout << "o2 should not have value" << std::endl; - retval = false; - } - if (o2.value().Value != 4) { - std::cout << "value of o2 should be 4" << std::endl; - retval = false; - } + ASSERT_TRUE(o1.has_value()); + ASSERT_TRUE(o1.value().Value == 5); + ASSERT_TRUE(o2.has_value()); + ASSERT_TRUE(o2.value().Value == 4); o1.reset(); o2.reset(); o1.swap(o2); - if (o1.has_value()) { - std::cout << "o1 should not have value" << std::endl; - retval = false; - } - if (o2.has_value()) { - std::cout << "o2 should not have value" << std::endl; - retval = false; - } + ASSERT_TRUE(!o1.has_value()); + ASSERT_TRUE(!o2.has_value()); expected = { { Event::VALUE_CONSTRUCT, v1, nullptr, 4 }, @@ -566,22 +654,17 @@ static bool testSwap(std::vector<Event>& expected) { Event::DESTRUCT, v1, nullptr, 5 }, { Event::DESTRUCT, v2, nullptr, 4 }, }; - return retval; + return true; } static bool testReset(std::vector<Event>& expected) { - bool retval = true; - cm::optional<EventLogger> o{ 4 }; auto const* v = &*o; o.reset(); - if (o.has_value()) { - std::cout << "o should not have value" << std::endl; - retval = false; - } + ASSERT_TRUE(!o.has_value()); o.reset(); @@ -589,7 +672,7 @@ static bool testReset(std::vector<Event>& expected) { Event::VALUE_CONSTRUCT, v, nullptr, 4 }, { Event::DESTRUCT, v, nullptr, 4 }, }; - return retval; + return true; } static bool testEmplace(std::vector<Event>& expected) @@ -630,8 +713,6 @@ static bool testMakeOptional(std::vector<Event>& expected) static bool testMemoryRange(std::vector<Event>& expected) { - bool retval = true; - cm::optional<EventLogger> o{ 4 }; auto* ostart = &o; @@ -639,17 +720,14 @@ static bool testMemoryRange(std::vector<Event>& expected) auto* estart = &o.value(); auto* eend = estart + 1; - if (static_cast<void*>(estart) < static_cast<void*>(ostart) || - static_cast<void*>(eend) > static_cast<void*>(oend)) { - std::cout << "value is not within memory range of optional" << std::endl; - retval = false; - } + ASSERT_TRUE(static_cast<void*>(estart) >= static_cast<void*>(ostart) && + static_cast<void*>(eend) <= static_cast<void*>(oend)); expected = { { Event::VALUE_CONSTRUCT, &*o, nullptr, 4 }, { Event::DESTRUCT, &*o, nullptr, 4 }, }; - return retval; + return true; } int testOptional(int /*unused*/, char* /*unused*/ []) @@ -691,6 +769,7 @@ int testOptional(int /*unused*/, char* /*unused*/ []) DO_EVENT_TEST(testHasValue); DO_EVENT_TEST(testValue); DO_TEST(testValueOr); + DO_EVENT_TEST(testComparison); DO_EVENT_TEST(testSwap); DO_EVENT_TEST(testReset); DO_EVENT_TEST(testEmplace); diff --git a/Utilities/std/cm/optional b/Utilities/std/cm/optional index e691e8e..9a5d840 100644 --- a/Utilities/std/cm/optional +++ b/Utilities/std/cm/optional @@ -218,6 +218,210 @@ optional<T>& optional<T>::operator=(U&& v) return *this; } +template <typename T, typename U> +bool operator==(const optional<T>& lhs, const optional<U>& rhs) +{ + if (lhs.has_value()) { + return rhs.has_value() && *lhs == *rhs; + } + return !rhs.has_value(); +} + +template <typename T, typename U> +bool operator!=(const optional<T>& lhs, const optional<U>& rhs) +{ + if (lhs.has_value()) { + return !rhs.has_value() || *lhs != *rhs; + } + return rhs.has_value(); +} + +template <typename T, typename U> +bool operator<(const optional<T>& lhs, const optional<U>& rhs) +{ + if (rhs.has_value()) { + return !lhs.has_value() || *lhs < *rhs; + } + return false; +} + +template <typename T, typename U> +bool operator<=(const optional<T>& lhs, const optional<U>& rhs) +{ + if (!lhs.has_value()) { + return true; + } + if (rhs.has_value()) { + return *lhs <= *rhs; + } + return false; +} + +template <typename T, typename U> +bool operator>(const optional<T>& lhs, const optional<U>& rhs) +{ + if (lhs.has_value()) { + return !rhs.has_value() || *lhs > *rhs; + } + return false; +} + +template <typename T, typename U> +bool operator>=(const optional<T>& lhs, const optional<U>& rhs) +{ + if (!rhs.has_value()) { + return true; + } + if (lhs.has_value()) { + return *lhs >= *rhs; + } + return false; +} + +template <typename T> +bool operator==(const optional<T>& opt, nullopt_t) noexcept +{ + return !opt.has_value(); +} + +template <typename T> +bool operator!=(const optional<T>& opt, nullopt_t) noexcept +{ + return opt.has_value(); +} + +template <typename T> +bool operator<(const optional<T>& opt, nullopt_t) noexcept +{ + return false; +} + +template <typename T> +bool operator<=(const optional<T>& opt, nullopt_t) noexcept +{ + return !opt.has_value(); +} + +template <typename T> +bool operator>(const optional<T>& opt, nullopt_t) noexcept +{ + return opt.has_value(); +} + +template <typename T> +bool operator>=(const optional<T>& opt, nullopt_t) noexcept +{ + return true; +} + +template <typename T> +bool operator==(nullopt_t, const optional<T>& opt) noexcept +{ + return !opt.has_value(); +} + +template <typename T> +bool operator!=(nullopt_t, const optional<T>& opt) noexcept +{ + return opt.has_value(); +} + +template <typename T> +bool operator<(nullopt_t, const optional<T>& opt) noexcept +{ + return opt.has_value(); +} + +template <typename T> +bool operator<=(nullopt_t, const optional<T>& opt) noexcept +{ + return true; +} + +template <typename T> +bool operator>(nullopt_t, const optional<T>& opt) noexcept +{ + return false; +} + +template <typename T> +bool operator>=(nullopt_t, const optional<T>& opt) noexcept +{ + return !opt.has_value(); +} + +template <typename T, typename U> +bool operator==(const optional<T>& opt, const U& value) +{ + return opt.has_value() && *opt == value; +} + +template <typename T, typename U> +bool operator!=(const optional<T>& opt, const U& value) +{ + return !opt.has_value() || *opt != value; +} + +template <typename T, typename U> +bool operator<(const optional<T>& opt, const U& value) +{ + return !opt.has_value() || *opt < value; +} + +template <typename T, typename U> +bool operator<=(const optional<T>& opt, const U& value) +{ + return !opt.has_value() || *opt <= value; +} + +template <typename T, typename U> +bool operator>(const optional<T>& opt, const U& value) +{ + return opt.has_value() && *opt > value; +} + +template <typename T, typename U> +bool operator>=(const optional<T>& opt, const U& value) +{ + return opt.has_value() && *opt >= value; +} + +template <typename T, typename U> +bool operator==(const T& value, const optional<U>& opt) +{ + return opt.has_value() && value == *opt; +} + +template <typename T, typename U> +bool operator!=(const T& value, const optional<U>& opt) +{ + return !opt.has_value() || value != *opt; +} + +template <typename T, typename U> +bool operator<(const T& value, const optional<U>& opt) +{ + return opt.has_value() && value < *opt; +} + +template <typename T, typename U> +bool operator<=(const T& value, const optional<U>& opt) +{ + return opt.has_value() && value <= *opt; +} + +template <typename T, typename U> +bool operator>(const T& value, const optional<U>& opt) +{ + return !opt.has_value() || value > *opt; +} + +template <typename T, typename U> +bool operator>=(const T& value, const optional<U>& opt) +{ + return !opt.has_value() || value >= *opt; +} + template <typename T> const T* optional<T>::operator->() const { |