#include #include #include #include #include class EventLogger; class Event { public: enum EventType { DEFAULT_CONSTRUCT, COPY_CONSTRUCT, MOVE_CONSTRUCT, VALUE_CONSTRUCT, DESTRUCT, COPY_ASSIGN, MOVE_ASSIGN, VALUE_ASSIGN, REFERENCE, CONST_REFERENCE, RVALUE_REFERENCE, CONST_RVALUE_REFERENCE, SWAP, COMPARE_EE_EQ, COMPARE_EE_NE, COMPARE_EE_LT, COMPARE_EE_LE, COMPARE_EE_GT, COMPARE_EE_GE, }; EventType Type; const EventLogger* Logger1; const EventLogger* Logger2; int Value; bool operator==(const Event& other) const; bool operator!=(const Event& other) const; }; bool Event::operator==(const Event& other) const { return this->Type == other.Type && this->Logger1 == other.Logger1 && this->Logger2 == other.Logger2 && this->Value == other.Value; } bool Event::operator!=(const Event& other) const { return !(*this == other); } static std::vector events; class EventLogger { public: EventLogger(); EventLogger(const EventLogger& other); EventLogger(EventLogger&& other); EventLogger(int value); ~EventLogger(); EventLogger& operator=(const EventLogger& other); EventLogger& operator=(EventLogger&& other); EventLogger& operator=(int value); void Reference() &; void Reference() const&; void Reference() &&; void Reference() const&&; int Value = 0; }; class NoMoveAssignEventLogger : public EventLogger { public: using EventLogger::EventLogger; NoMoveAssignEventLogger(const NoMoveAssignEventLogger&) = default; NoMoveAssignEventLogger(NoMoveAssignEventLogger&&) = default; NoMoveAssignEventLogger& operator=(const NoMoveAssignEventLogger&) = default; NoMoveAssignEventLogger& operator=(NoMoveAssignEventLogger&&) = delete; }; #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. // Silence these false warnings. #if defined(__GNUC__) && !defined(__clang__) # define BEGIN_IGNORE_UNINITIALIZED \ _Pragma("GCC diagnostic push") \ _Pragma("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") # define END_IGNORE_UNINITIALIZED _Pragma("GCC diagnostic pop") #else # define BEGIN_IGNORE_UNINITIALIZED # define END_IGNORE_UNINITIALIZED #endif void swap(EventLogger& e1, EventLogger& e2) { BEGIN_IGNORE_UNINITIALIZED events.push_back({ Event::SWAP, &e1, &e2, e2.Value }); END_IGNORE_UNINITIALIZED auto tmp = e1.Value; e1.Value = e2.Value; e2.Value = tmp; } EventLogger::EventLogger() : Value(0) { events.push_back({ Event::DEFAULT_CONSTRUCT, this, nullptr, 0 }); } EventLogger::EventLogger(const EventLogger& other) : Value(other.Value) { events.push_back({ Event::COPY_CONSTRUCT, this, &other, other.Value }); } BEGIN_IGNORE_UNINITIALIZED EventLogger::EventLogger(EventLogger&& other) : Value(other.Value) { events.push_back({ Event::MOVE_CONSTRUCT, this, &other, other.Value }); } END_IGNORE_UNINITIALIZED EventLogger::EventLogger(int value) : Value(value) { events.push_back({ Event::VALUE_CONSTRUCT, this, nullptr, value }); } EventLogger::~EventLogger() { BEGIN_IGNORE_UNINITIALIZED events.push_back({ Event::DESTRUCT, this, nullptr, this->Value }); END_IGNORE_UNINITIALIZED } EventLogger& EventLogger::operator=(const EventLogger& other) { events.push_back({ Event::COPY_ASSIGN, this, &other, other.Value }); this->Value = other.Value; return *this; } EventLogger& EventLogger::operator=(EventLogger&& other) { events.push_back({ Event::MOVE_ASSIGN, this, &other, other.Value }); this->Value = other.Value; return *this; } EventLogger& EventLogger::operator=(int value) { events.push_back({ Event::VALUE_ASSIGN, this, nullptr, value }); this->Value = 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 }); } void EventLogger::Reference() const& { events.push_back({ Event::CONST_REFERENCE, this, nullptr, this->Value }); } void EventLogger::Reference() && { events.push_back({ Event::RVALUE_REFERENCE, this, nullptr, this->Value }); } void EventLogger::Reference() const&& { events.push_back( { Event::CONST_RVALUE_REFERENCE, this, nullptr, this->Value }); } static bool testDefaultConstruct(std::vector& expected) { const cm::optional o{}; expected = {}; return true; } static bool testNulloptConstruct(std::vector& expected) { const cm::optional o{ cm::nullopt }; expected = {}; return true; } static bool testValueConstruct(std::vector& expected) { const cm::optional o{ 4 }; expected = { { Event::VALUE_CONSTRUCT, &*o, nullptr, 4 }, { Event::DESTRUCT, &*o, nullptr, 4 }, }; return true; } static bool testInPlaceConstruct(std::vector& expected) { const cm::optional o1{ cm::in_place, 4 }; const cm::optional o2{ cm::in_place_t{}, 4 }; expected = { { Event::VALUE_CONSTRUCT, &*o1, nullptr, 4 }, { Event::VALUE_CONSTRUCT, &*o2, nullptr, 4 }, { Event::DESTRUCT, &*o2, nullptr, 4 }, { Event::DESTRUCT, &*o1, nullptr, 4 }, }; return true; } static bool testCopyConstruct(std::vector& expected) { const cm::optional o1{ 4 }; const cm::optional o2{ o1 }; const cm::optional o3{}; const cm::optional o4{ o3 }; expected = { { Event::VALUE_CONSTRUCT, &*o1, nullptr, 4 }, { Event::COPY_CONSTRUCT, &*o2, &o1.value(), 4 }, { Event::DESTRUCT, &*o2, nullptr, 4 }, { Event::DESTRUCT, &*o1, nullptr, 4 }, }; return true; } static bool testMoveConstruct(std::vector& expected) { cm::optional o1{ 4 }; const cm::optional o2{ std::move(o1) }; cm::optional o3{}; const cm::optional o4{ std::move(o3) }; #ifndef __clang_analyzer__ /* cplusplus.Move */ expected = { { Event::VALUE_CONSTRUCT, &*o1, nullptr, 4 }, { Event::MOVE_CONSTRUCT, &*o2, &*o1, 4 }, { Event::DESTRUCT, &*o2, nullptr, 4 }, { Event::DESTRUCT, &*o1, nullptr, 4 }, }; #endif return true; } static bool testNulloptAssign(std::vector& expected) { cm::optional o1{ 4 }; auto const* v1 = &*o1; o1 = cm::nullopt; cm::optional o2{}; o2 = cm::nullopt; expected = { { Event::VALUE_CONSTRUCT, v1, nullptr, 4 }, { Event::DESTRUCT, v1, nullptr, 4 }, }; return true; } static bool testCopyAssign(std::vector& expected) { cm::optional o1{}; const cm::optional o2{ 4 }; auto const* v2 = &*o2; o1 = o2; auto const* v1 = &*o1; const cm::optional o3{ 5 }; auto const* v3 = &*o3; o1 = o3; const cm::optional o4{}; o1 = o4; o1 = o4; // Intentionally duplicated to test assigning an empty optional to // an empty optional cm::optional o5{ 1 }; auto const* v5 = &*o5; const cm::optional o6{ 2 }; auto const* v6 = &*o6; o5 = std::move(o6); const NoMoveAssignEventLogger e7{ 3 }; o5 = std::move(e7); expected = { { Event::VALUE_CONSTRUCT, v2, nullptr, 4 }, { Event::COPY_CONSTRUCT, v1, v2, 4 }, { Event::VALUE_CONSTRUCT, v3, nullptr, 5 }, { Event::COPY_ASSIGN, v1, v3, 5 }, { Event::DESTRUCT, v1, nullptr, 5 }, { Event::VALUE_CONSTRUCT, v5, nullptr, 1 }, { Event::VALUE_CONSTRUCT, v6, nullptr, 2 }, { Event::COPY_ASSIGN, v5, v6, 2 }, { Event::VALUE_CONSTRUCT, &e7, nullptr, 3 }, { Event::COPY_ASSIGN, v5, &e7, 3 }, { Event::DESTRUCT, &e7, nullptr, 3 }, { Event::DESTRUCT, v6, nullptr, 2 }, { Event::DESTRUCT, v5, nullptr, 3 }, { Event::DESTRUCT, v3, nullptr, 5 }, { Event::DESTRUCT, v2, nullptr, 4 }, }; return true; } static bool testMoveAssign(std::vector& expected) { cm::optional o1{}; cm::optional o2{ 4 }; auto const* v2 = &*o2; o1 = std::move(o2); auto const* v1 = &*o1; cm::optional o3{ 5 }; auto const* v3 = &*o3; o1 = std::move(o3); cm::optional o4{}; o1 = std::move(o4); expected = { { Event::VALUE_CONSTRUCT, v2, nullptr, 4 }, { Event::MOVE_CONSTRUCT, v1, v2, 4 }, { Event::VALUE_CONSTRUCT, v3, nullptr, 5 }, { Event::MOVE_ASSIGN, v1, v3, 5 }, { Event::DESTRUCT, v1, nullptr, 5 }, { Event::DESTRUCT, v3, nullptr, 5 }, { Event::DESTRUCT, v2, nullptr, 4 }, }; return true; } static bool testPointer(std::vector& expected) { cm::optional o1{ 4 }; const cm::optional o2{ 5 }; o1->Reference(); o2->Reference(); expected = { { Event::VALUE_CONSTRUCT, &*o1, nullptr, 4 }, { Event::VALUE_CONSTRUCT, &*o2, nullptr, 5 }, { Event::REFERENCE, &*o1, nullptr, 4 }, { Event::CONST_REFERENCE, &*o2, nullptr, 5 }, { Event::DESTRUCT, &*o2, nullptr, 5 }, { Event::DESTRUCT, &*o1, nullptr, 4 }, }; return true; } #if !__GNUC__ || __GNUC__ > 4 # define ALLOW_CONST_RVALUE #endif static bool testDereference(std::vector& expected) { cm::optional o1{ 4 }; auto const* v1 = &*o1; const cm::optional o2{ 5 }; auto const* v2 = &*o2; (*o1).Reference(); (*o2).Reference(); (*std::move(o1)).Reference(); #ifdef ALLOW_CONST_RVALUE (*std::move(o2)).Reference(); // Broken in GCC 4.9.0. Sigh... #endif expected = { { Event::VALUE_CONSTRUCT, v1, nullptr, 4 }, { Event::VALUE_CONSTRUCT, v2, nullptr, 5 }, { Event::REFERENCE, v1, nullptr, 4 }, { Event::CONST_REFERENCE, v2, nullptr, 5 }, { Event::RVALUE_REFERENCE, v1, nullptr, 4 }, #ifdef ALLOW_CONST_RVALUE { Event::CONST_RVALUE_REFERENCE, v2, nullptr, 5 }, #endif { Event::DESTRUCT, v2, nullptr, 5 }, { Event::DESTRUCT, v1, nullptr, 4 }, }; return true; } static bool testHasValue(std::vector& expected) { const cm::optional o1{ 4 }; const cm::optional o2{}; 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 true; } static bool testValue(std::vector& expected) { cm::optional o1{ 4 }; const cm::optional o2{ 5 }; cm::optional o3{}; const cm::optional o4{}; o1.value().Reference(); o2.value().Reference(); bool thrown = false; try { (void)o3.value(); } catch (cm::bad_optional_access&) { thrown = true; } ASSERT_TRUE(thrown); thrown = false; try { (void)o4.value(); } catch (cm::bad_optional_access&) { thrown = true; } ASSERT_TRUE(thrown); expected = { { Event::VALUE_CONSTRUCT, &*o1, nullptr, 4 }, { Event::VALUE_CONSTRUCT, &*o2, nullptr, 5 }, { Event::REFERENCE, &*o1, nullptr, 4 }, { Event::CONST_REFERENCE, &*o2, nullptr, 5 }, { Event::DESTRUCT, &*o2, nullptr, 5 }, { Event::DESTRUCT, &*o1, nullptr, 4 }, }; return true; } static bool testValueOr() { const cm::optional o1{ 4 }; cm::optional o2{ 5 }; const cm::optional o3{}; cm::optional o4{}; EventLogger e1{ 6 }; EventLogger e2{ 7 }; EventLogger e3{ 8 }; EventLogger e4{ 9 }; EventLogger r1 = o1.value_or(e1); ASSERT_TRUE(r1.Value == 4); EventLogger r2 = std::move(o2).value_or(e2); ASSERT_TRUE(r2.Value == 5); EventLogger r3 = o3.value_or(e3); ASSERT_TRUE(r3.Value == 8); EventLogger r4 = std::move(o4).value_or(e4); ASSERT_TRUE(r4.Value == 9); return true; } static bool testComparison(std::vector& expected) { const cm::optional o1{ 1 }; const cm::optional o2{ 2 }; const cm::optional o3{ 2 }; const cm::optional o4{}; const cm::optional 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& expected) { cm::optional o1{ 4 }; auto const* v1 = &*o1; cm::optional o2{}; o1.swap(o2); auto const* v2 = &*o2; ASSERT_TRUE(!o1.has_value()); ASSERT_TRUE(o2.has_value()); ASSERT_TRUE(o2.value().Value == 4); o1.swap(o2); ASSERT_TRUE(o1.has_value()); ASSERT_TRUE(o1.value().Value == 4); ASSERT_TRUE(!o2.has_value()); o2.emplace(5); o1.swap(o2); 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); ASSERT_TRUE(!o1.has_value()); ASSERT_TRUE(!o2.has_value()); expected = { { Event::VALUE_CONSTRUCT, v1, nullptr, 4 }, { Event::MOVE_CONSTRUCT, v2, v1, 4 }, { Event::DESTRUCT, v1, nullptr, 4 }, { Event::MOVE_CONSTRUCT, v1, v2, 4 }, { Event::DESTRUCT, v2, nullptr, 4 }, { Event::VALUE_CONSTRUCT, v2, nullptr, 5 }, { Event::SWAP, v1, v2, 5 }, { Event::DESTRUCT, v1, nullptr, 5 }, { Event::DESTRUCT, v2, nullptr, 4 }, }; return true; } static bool testReset(std::vector& expected) { cm::optional o{ 4 }; auto const* v = &*o; o.reset(); ASSERT_TRUE(!o.has_value()); o.reset(); expected = { { Event::VALUE_CONSTRUCT, v, nullptr, 4 }, { Event::DESTRUCT, v, nullptr, 4 }, }; return true; } static bool testEmplace(std::vector& expected) { cm::optional o{ 4 }; o.emplace(5); o.reset(); o.emplace(); expected = { { Event::VALUE_CONSTRUCT, &*o, nullptr, 4 }, { Event::DESTRUCT, &*o, nullptr, 4 }, { Event::VALUE_CONSTRUCT, &*o, nullptr, 5 }, { Event::DESTRUCT, &*o, nullptr, 5 }, { Event::DEFAULT_CONSTRUCT, &*o, nullptr, 0 }, { Event::DESTRUCT, &*o, nullptr, 0 }, }; return true; } static bool testMakeOptional(std::vector& expected) { EventLogger e{ 4 }; cm::optional o1 = cm::make_optional(e); cm::optional o2 = cm::make_optional(5); expected = { { Event::VALUE_CONSTRUCT, &e, nullptr, 4 }, { Event::COPY_CONSTRUCT, &*o1, &e, 4 }, { Event::VALUE_CONSTRUCT, &*o2, nullptr, 5 }, { Event::DESTRUCT, &*o2, nullptr, 5 }, { Event::DESTRUCT, &*o1, nullptr, 4 }, { Event::DESTRUCT, &e, nullptr, 4 }, }; return true; } static bool testMemoryRange(std::vector& expected) { cm::optional o{ 4 }; auto* ostart = &o; auto* oend = ostart + 1; auto* estart = &o.value(); auto* eend = estart + 1; ASSERT_TRUE(static_cast(estart) >= static_cast(ostart) && static_cast(eend) <= static_cast(oend)); expected = { { Event::VALUE_CONSTRUCT, &*o, nullptr, 4 }, { Event::DESTRUCT, &*o, nullptr, 4 }, }; return true; } int testOptional(int /*unused*/, char* /*unused*/ []) { int retval = 0; #define DO_EVENT_TEST(name) \ do { \ events.clear(); \ std::vector expected; \ if (!name(expected)) { \ std::cout << "in " #name << std::endl; \ retval = 1; \ } else if (expected != events) { \ std::cout << #name " did not produce expected events" << std::endl; \ retval = 1; \ } \ } while (0) #define DO_TEST(name) \ do { \ if (!name()) { \ std::cout << "in " #name << std::endl; \ retval = 1; \ } \ } while (0) DO_EVENT_TEST(testDefaultConstruct); DO_EVENT_TEST(testNulloptConstruct); DO_EVENT_TEST(testValueConstruct); DO_EVENT_TEST(testInPlaceConstruct); DO_EVENT_TEST(testCopyConstruct); DO_EVENT_TEST(testMoveConstruct); DO_EVENT_TEST(testNulloptAssign); DO_EVENT_TEST(testCopyAssign); DO_EVENT_TEST(testMoveAssign); DO_EVENT_TEST(testPointer); DO_EVENT_TEST(testDereference); 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); DO_EVENT_TEST(testMakeOptional); DO_EVENT_TEST(testMemoryRange); return retval; }