testOptional.cxx 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780
  1. #include <iostream>
  2. #include <type_traits>
  3. #include <vector>
  4. #include <cm/optional>
  5. #include <cm/utility>
  6. class EventLogger;
  7. class Event
  8. {
  9. public:
  10. enum EventType
  11. {
  12. DEFAULT_CONSTRUCT,
  13. COPY_CONSTRUCT,
  14. MOVE_CONSTRUCT,
  15. VALUE_CONSTRUCT,
  16. DESTRUCT,
  17. COPY_ASSIGN,
  18. MOVE_ASSIGN,
  19. VALUE_ASSIGN,
  20. REFERENCE,
  21. CONST_REFERENCE,
  22. RVALUE_REFERENCE,
  23. CONST_RVALUE_REFERENCE,
  24. SWAP,
  25. COMPARE_EE_EQ,
  26. COMPARE_EE_NE,
  27. COMPARE_EE_LT,
  28. COMPARE_EE_LE,
  29. COMPARE_EE_GT,
  30. COMPARE_EE_GE,
  31. };
  32. EventType Type;
  33. const EventLogger* Logger1;
  34. const EventLogger* Logger2;
  35. int Value;
  36. bool operator==(const Event& other) const;
  37. bool operator!=(const Event& other) const;
  38. };
  39. bool Event::operator==(const Event& other) const
  40. {
  41. return this->Type == other.Type && this->Logger1 == other.Logger1 &&
  42. this->Logger2 == other.Logger2 && this->Value == other.Value;
  43. }
  44. bool Event::operator!=(const Event& other) const
  45. {
  46. return !(*this == other);
  47. }
  48. static std::vector<Event> events;
  49. class EventLogger
  50. {
  51. public:
  52. EventLogger();
  53. EventLogger(const EventLogger& other);
  54. EventLogger(EventLogger&& other);
  55. EventLogger(int value);
  56. ~EventLogger();
  57. EventLogger& operator=(const EventLogger& other);
  58. EventLogger& operator=(EventLogger&& other);
  59. EventLogger& operator=(int value);
  60. void Reference() &;
  61. void Reference() const&;
  62. void Reference() &&;
  63. void Reference() const&&;
  64. int Value = 0;
  65. };
  66. #define ASSERT_TRUE(x) \
  67. do { \
  68. if (!(x)) { \
  69. std::cout << "ASSERT_TRUE(" #x ") failed on line " << __LINE__ << "\n"; \
  70. return false; \
  71. } \
  72. } while (false)
  73. // Certain builds of GCC generate false -Wmaybe-uninitialized warnings when
  74. // doing a release build with the system version of std::optional. These
  75. // warnings do not manifest when using our own cm::optional implementation.
  76. // Silence these false warnings.
  77. #if defined(__GNUC__) && !defined(__clang__)
  78. # define BEGIN_IGNORE_UNINITIALIZED \
  79. _Pragma("GCC diagnostic push") \
  80. _Pragma("GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
  81. # define END_IGNORE_UNINITIALIZED _Pragma("GCC diagnostic pop")
  82. #else
  83. # define BEGIN_IGNORE_UNINITIALIZED
  84. # define END_IGNORE_UNINITIALIZED
  85. #endif
  86. void swap(EventLogger& e1, EventLogger& e2)
  87. {
  88. BEGIN_IGNORE_UNINITIALIZED
  89. events.push_back({ Event::SWAP, &e1, &e2, e2.Value });
  90. END_IGNORE_UNINITIALIZED
  91. auto tmp = e1.Value;
  92. e1.Value = e2.Value;
  93. e2.Value = tmp;
  94. }
  95. EventLogger::EventLogger()
  96. : Value(0)
  97. {
  98. events.push_back({ Event::DEFAULT_CONSTRUCT, this, nullptr, 0 });
  99. }
  100. EventLogger::EventLogger(const EventLogger& other)
  101. : Value(other.Value)
  102. {
  103. events.push_back({ Event::COPY_CONSTRUCT, this, &other, other.Value });
  104. }
  105. BEGIN_IGNORE_UNINITIALIZED
  106. EventLogger::EventLogger(EventLogger&& other)
  107. : Value(other.Value)
  108. {
  109. events.push_back({ Event::MOVE_CONSTRUCT, this, &other, other.Value });
  110. }
  111. END_IGNORE_UNINITIALIZED
  112. EventLogger::EventLogger(int value)
  113. : Value(value)
  114. {
  115. events.push_back({ Event::VALUE_CONSTRUCT, this, nullptr, value });
  116. }
  117. EventLogger::~EventLogger()
  118. {
  119. BEGIN_IGNORE_UNINITIALIZED
  120. events.push_back({ Event::DESTRUCT, this, nullptr, this->Value });
  121. END_IGNORE_UNINITIALIZED
  122. }
  123. EventLogger& EventLogger::operator=(const EventLogger& other)
  124. {
  125. events.push_back({ Event::COPY_ASSIGN, this, &other, other.Value });
  126. this->Value = other.Value;
  127. return *this;
  128. }
  129. EventLogger& EventLogger::operator=(EventLogger&& other)
  130. {
  131. events.push_back({ Event::MOVE_ASSIGN, this, &other, other.Value });
  132. this->Value = other.Value;
  133. return *this;
  134. }
  135. EventLogger& EventLogger::operator=(int value)
  136. {
  137. events.push_back({ Event::VALUE_ASSIGN, this, nullptr, value });
  138. this->Value = value;
  139. return *this;
  140. }
  141. bool operator==(const EventLogger& lhs, const EventLogger& rhs)
  142. {
  143. events.push_back({ Event::COMPARE_EE_EQ, &lhs, &rhs, lhs.Value });
  144. return lhs.Value == rhs.Value;
  145. }
  146. bool operator!=(const EventLogger& lhs, const EventLogger& rhs)
  147. {
  148. events.push_back({ Event::COMPARE_EE_NE, &lhs, &rhs, lhs.Value });
  149. return lhs.Value != rhs.Value;
  150. }
  151. bool operator<(const EventLogger& lhs, const EventLogger& rhs)
  152. {
  153. events.push_back({ Event::COMPARE_EE_LT, &lhs, &rhs, lhs.Value });
  154. return lhs.Value < rhs.Value;
  155. }
  156. bool operator<=(const EventLogger& lhs, const EventLogger& rhs)
  157. {
  158. events.push_back({ Event::COMPARE_EE_LE, &lhs, &rhs, lhs.Value });
  159. return lhs.Value <= rhs.Value;
  160. }
  161. bool operator>(const EventLogger& lhs, const EventLogger& rhs)
  162. {
  163. events.push_back({ Event::COMPARE_EE_GT, &lhs, &rhs, lhs.Value });
  164. return lhs.Value > rhs.Value;
  165. }
  166. bool operator>=(const EventLogger& lhs, const EventLogger& rhs)
  167. {
  168. events.push_back({ Event::COMPARE_EE_GE, &lhs, &rhs, lhs.Value });
  169. return lhs.Value >= rhs.Value;
  170. }
  171. void EventLogger::Reference() &
  172. {
  173. events.push_back({ Event::REFERENCE, this, nullptr, this->Value });
  174. }
  175. void EventLogger::Reference() const&
  176. {
  177. events.push_back({ Event::CONST_REFERENCE, this, nullptr, this->Value });
  178. }
  179. void EventLogger::Reference() &&
  180. {
  181. events.push_back({ Event::RVALUE_REFERENCE, this, nullptr, this->Value });
  182. }
  183. void EventLogger::Reference() const&&
  184. {
  185. events.push_back(
  186. { Event::CONST_RVALUE_REFERENCE, this, nullptr, this->Value });
  187. }
  188. static bool testDefaultConstruct(std::vector<Event>& expected)
  189. {
  190. const cm::optional<EventLogger> o{};
  191. expected = {};
  192. return true;
  193. }
  194. static bool testNulloptConstruct(std::vector<Event>& expected)
  195. {
  196. const cm::optional<EventLogger> o{ cm::nullopt };
  197. expected = {};
  198. return true;
  199. }
  200. static bool testValueConstruct(std::vector<Event>& expected)
  201. {
  202. const cm::optional<EventLogger> o{ 4 };
  203. expected = {
  204. { Event::VALUE_CONSTRUCT, &*o, nullptr, 4 },
  205. { Event::DESTRUCT, &*o, nullptr, 4 },
  206. };
  207. return true;
  208. }
  209. static bool testInPlaceConstruct(std::vector<Event>& expected)
  210. {
  211. const cm::optional<EventLogger> o1{ cm::in_place, 4 };
  212. const cm::optional<EventLogger> o2{ cm::in_place_t{}, 4 };
  213. expected = {
  214. { Event::VALUE_CONSTRUCT, &*o1, nullptr, 4 },
  215. { Event::VALUE_CONSTRUCT, &*o2, nullptr, 4 },
  216. { Event::DESTRUCT, &*o2, nullptr, 4 },
  217. { Event::DESTRUCT, &*o1, nullptr, 4 },
  218. };
  219. return true;
  220. }
  221. static bool testCopyConstruct(std::vector<Event>& expected)
  222. {
  223. const cm::optional<EventLogger> o1{ 4 };
  224. const cm::optional<EventLogger> o2{ o1 };
  225. const cm::optional<EventLogger> o3{};
  226. const cm::optional<EventLogger> o4{ o3 };
  227. expected = {
  228. { Event::VALUE_CONSTRUCT, &*o1, nullptr, 4 },
  229. { Event::COPY_CONSTRUCT, &*o2, &o1.value(), 4 },
  230. { Event::DESTRUCT, &*o2, nullptr, 4 },
  231. { Event::DESTRUCT, &*o1, nullptr, 4 },
  232. };
  233. return true;
  234. }
  235. static bool testMoveConstruct(std::vector<Event>& expected)
  236. {
  237. cm::optional<EventLogger> o1{ 4 };
  238. const cm::optional<EventLogger> o2{ std::move(o1) };
  239. cm::optional<EventLogger> o3{};
  240. const cm::optional<EventLogger> o4{ std::move(o3) };
  241. expected = {
  242. { Event::VALUE_CONSTRUCT, &*o1, nullptr, 4 },
  243. { Event::MOVE_CONSTRUCT, &*o2, &*o1, 4 },
  244. { Event::DESTRUCT, &*o2, nullptr, 4 },
  245. { Event::DESTRUCT, &*o1, nullptr, 4 },
  246. };
  247. return true;
  248. }
  249. static bool testNulloptAssign(std::vector<Event>& expected)
  250. {
  251. cm::optional<EventLogger> o1{ 4 };
  252. auto const* v1 = &*o1;
  253. o1 = cm::nullopt;
  254. cm::optional<EventLogger> o2{};
  255. o2 = cm::nullopt;
  256. expected = {
  257. { Event::VALUE_CONSTRUCT, v1, nullptr, 4 },
  258. { Event::DESTRUCT, v1, nullptr, 4 },
  259. };
  260. return true;
  261. }
  262. static bool testCopyAssign(std::vector<Event>& expected)
  263. {
  264. cm::optional<EventLogger> o1{};
  265. const cm::optional<EventLogger> o2{ 4 };
  266. auto const* v2 = &*o2;
  267. o1 = o2;
  268. auto const* v1 = &*o1;
  269. const cm::optional<EventLogger> o3{ 5 };
  270. auto const* v3 = &*o3;
  271. o1 = o3;
  272. const cm::optional<EventLogger> o4{};
  273. o1 = o4;
  274. o1 = o4; // Intentionally duplicated to test assigning an empty optional to
  275. // an empty optional
  276. expected = {
  277. { Event::VALUE_CONSTRUCT, v2, nullptr, 4 },
  278. { Event::COPY_CONSTRUCT, v1, v2, 4 },
  279. { Event::VALUE_CONSTRUCT, v3, nullptr, 5 },
  280. { Event::COPY_ASSIGN, v1, v3, 5 },
  281. { Event::DESTRUCT, v1, nullptr, 5 },
  282. { Event::DESTRUCT, v3, nullptr, 5 },
  283. { Event::DESTRUCT, v2, nullptr, 4 },
  284. };
  285. return true;
  286. }
  287. static bool testMoveAssign(std::vector<Event>& expected)
  288. {
  289. cm::optional<EventLogger> o1{};
  290. cm::optional<EventLogger> o2{ 4 };
  291. auto const* v2 = &*o2;
  292. o1 = std::move(o2);
  293. auto const* v1 = &*o1;
  294. cm::optional<EventLogger> o3{ 5 };
  295. auto const* v3 = &*o3;
  296. o1 = std::move(o3);
  297. cm::optional<EventLogger> o4{};
  298. o1 = std::move(o4);
  299. expected = {
  300. { Event::VALUE_CONSTRUCT, v2, nullptr, 4 },
  301. { Event::MOVE_CONSTRUCT, v1, v2, 4 },
  302. { Event::VALUE_CONSTRUCT, v3, nullptr, 5 },
  303. { Event::MOVE_ASSIGN, v1, v3, 5 },
  304. { Event::DESTRUCT, v1, nullptr, 5 },
  305. { Event::DESTRUCT, v3, nullptr, 5 },
  306. { Event::DESTRUCT, v2, nullptr, 4 },
  307. };
  308. return true;
  309. }
  310. static bool testPointer(std::vector<Event>& expected)
  311. {
  312. cm::optional<EventLogger> o1{ 4 };
  313. const cm::optional<EventLogger> o2{ 5 };
  314. o1->Reference();
  315. o2->Reference();
  316. expected = {
  317. { Event::VALUE_CONSTRUCT, &*o1, nullptr, 4 },
  318. { Event::VALUE_CONSTRUCT, &*o2, nullptr, 5 },
  319. { Event::REFERENCE, &*o1, nullptr, 4 },
  320. { Event::CONST_REFERENCE, &*o2, nullptr, 5 },
  321. { Event::DESTRUCT, &*o2, nullptr, 5 },
  322. { Event::DESTRUCT, &*o1, nullptr, 4 },
  323. };
  324. return true;
  325. }
  326. #if !__GNUC__ || __GNUC__ > 4
  327. # define ALLOW_CONST_RVALUE
  328. #endif
  329. static bool testDereference(std::vector<Event>& expected)
  330. {
  331. cm::optional<EventLogger> o1{ 4 };
  332. auto const* v1 = &*o1;
  333. const cm::optional<EventLogger> o2{ 5 };
  334. auto const* v2 = &*o2;
  335. (*o1).Reference();
  336. (*o2).Reference();
  337. (*std::move(o1)).Reference();
  338. #ifdef ALLOW_CONST_RVALUE
  339. (*std::move(o2)).Reference(); // Broken in GCC 4.9.0. Sigh...
  340. #endif
  341. expected = {
  342. { Event::VALUE_CONSTRUCT, v1, nullptr, 4 },
  343. { Event::VALUE_CONSTRUCT, v2, nullptr, 5 },
  344. { Event::REFERENCE, v1, nullptr, 4 },
  345. { Event::CONST_REFERENCE, v2, nullptr, 5 },
  346. { Event::RVALUE_REFERENCE, v1, nullptr, 4 },
  347. #ifdef ALLOW_CONST_RVALUE
  348. { Event::CONST_RVALUE_REFERENCE, v2, nullptr, 5 },
  349. #endif
  350. { Event::DESTRUCT, v2, nullptr, 5 },
  351. { Event::DESTRUCT, v1, nullptr, 4 },
  352. };
  353. return true;
  354. }
  355. static bool testHasValue(std::vector<Event>& expected)
  356. {
  357. const cm::optional<EventLogger> o1{ 4 };
  358. const cm::optional<EventLogger> o2{};
  359. ASSERT_TRUE(o1.has_value());
  360. ASSERT_TRUE(o1);
  361. ASSERT_TRUE(!o2.has_value());
  362. ASSERT_TRUE(!o2);
  363. expected = {
  364. { Event::VALUE_CONSTRUCT, &*o1, nullptr, 4 },
  365. { Event::DESTRUCT, &*o1, nullptr, 4 },
  366. };
  367. return true;
  368. }
  369. static bool testValue(std::vector<Event>& expected)
  370. {
  371. cm::optional<EventLogger> o1{ 4 };
  372. const cm::optional<EventLogger> o2{ 5 };
  373. cm::optional<EventLogger> o3{};
  374. const cm::optional<EventLogger> o4{};
  375. o1.value().Reference();
  376. o2.value().Reference();
  377. bool thrown = false;
  378. try {
  379. (void)o3.value();
  380. } catch (cm::bad_optional_access&) {
  381. thrown = true;
  382. }
  383. ASSERT_TRUE(thrown);
  384. thrown = false;
  385. try {
  386. (void)o4.value();
  387. } catch (cm::bad_optional_access&) {
  388. thrown = true;
  389. }
  390. ASSERT_TRUE(thrown);
  391. expected = {
  392. { Event::VALUE_CONSTRUCT, &*o1, nullptr, 4 },
  393. { Event::VALUE_CONSTRUCT, &*o2, nullptr, 5 },
  394. { Event::REFERENCE, &*o1, nullptr, 4 },
  395. { Event::CONST_REFERENCE, &*o2, nullptr, 5 },
  396. { Event::DESTRUCT, &*o2, nullptr, 5 },
  397. { Event::DESTRUCT, &*o1, nullptr, 4 },
  398. };
  399. return true;
  400. }
  401. static bool testValueOr()
  402. {
  403. const cm::optional<EventLogger> o1{ 4 };
  404. cm::optional<EventLogger> o2{ 5 };
  405. const cm::optional<EventLogger> o3{};
  406. cm::optional<EventLogger> o4{};
  407. EventLogger e1{ 6 };
  408. EventLogger e2{ 7 };
  409. EventLogger e3{ 8 };
  410. EventLogger e4{ 9 };
  411. EventLogger r1 = o1.value_or(e1);
  412. ASSERT_TRUE(r1.Value == 4);
  413. EventLogger r2 = std::move(o2).value_or(e2);
  414. ASSERT_TRUE(r2.Value == 5);
  415. EventLogger r3 = o3.value_or(e3);
  416. ASSERT_TRUE(r3.Value == 8);
  417. EventLogger r4 = std::move(o4).value_or(e4);
  418. ASSERT_TRUE(r4.Value == 9);
  419. return true;
  420. }
  421. static bool testComparison(std::vector<Event>& expected)
  422. {
  423. const cm::optional<EventLogger> o1{ 1 };
  424. const cm::optional<EventLogger> o2{ 2 };
  425. const cm::optional<EventLogger> o3{ 2 };
  426. const cm::optional<EventLogger> o4{};
  427. const cm::optional<EventLogger> o5{};
  428. const EventLogger e1{ 2 };
  429. ASSERT_TRUE(!(o1 == o2) && o1 != o2);
  430. ASSERT_TRUE(o1 < o2 && !(o1 >= o2));
  431. ASSERT_TRUE(!(o1 > o2) && o1 <= o2);
  432. ASSERT_TRUE(o2 == o3 && !(o2 != o3));
  433. ASSERT_TRUE(!(o2 < o3) && o2 >= o3);
  434. ASSERT_TRUE(!(o2 > o3) && o2 <= o3);
  435. ASSERT_TRUE(!(o3 == o4) && o3 != o4);
  436. ASSERT_TRUE(!(o3 < o4) && o3 >= o4);
  437. ASSERT_TRUE(o3 > o4 && !(o3 <= o4));
  438. ASSERT_TRUE(o4 == o5 && !(o4 != o5));
  439. ASSERT_TRUE(!(o4 < o5) && o4 >= o5);
  440. ASSERT_TRUE(!(o4 > o5) && o4 <= o5);
  441. ASSERT_TRUE(!(o1 == cm::nullopt) && o1 != cm::nullopt);
  442. ASSERT_TRUE(!(o1 < cm::nullopt) && o1 >= cm::nullopt);
  443. ASSERT_TRUE(o1 > cm::nullopt && !(o1 <= cm::nullopt));
  444. ASSERT_TRUE(!(cm::nullopt == o1) && cm::nullopt != o1);
  445. ASSERT_TRUE(cm::nullopt < o1 && !(cm::nullopt >= o1));
  446. ASSERT_TRUE(!(cm::nullopt > o1) && cm::nullopt <= o1);
  447. ASSERT_TRUE(o4 == cm::nullopt && !(o4 != cm::nullopt));
  448. ASSERT_TRUE(!(o4 < cm::nullopt) && o4 >= cm::nullopt);
  449. ASSERT_TRUE(!(o4 > cm::nullopt) && o4 <= cm::nullopt);
  450. ASSERT_TRUE(cm::nullopt == o4 && !(cm::nullopt != o4));
  451. ASSERT_TRUE(!(cm::nullopt < o4) && cm::nullopt >= o4);
  452. ASSERT_TRUE(!(cm::nullopt > o4) && cm::nullopt <= o4);
  453. ASSERT_TRUE(!(o1 == e1) && o1 != e1);
  454. ASSERT_TRUE(o1 < e1 && !(o1 >= e1));
  455. ASSERT_TRUE(!(o1 > e1) && o1 <= e1);
  456. ASSERT_TRUE(o2 == e1 && !(o2 != e1));
  457. ASSERT_TRUE(!(o2 < e1) && o2 >= e1);
  458. ASSERT_TRUE(!(o2 > e1) && o2 <= e1);
  459. ASSERT_TRUE(!(o4 == e1) && o4 != e1);
  460. ASSERT_TRUE(o4 < e1 && !(o4 >= e1));
  461. ASSERT_TRUE(!(o4 > e1) && o4 <= e1);
  462. ASSERT_TRUE(!(e1 == o1) && e1 != o1);
  463. ASSERT_TRUE(!(e1 < o1) && e1 >= o1);
  464. ASSERT_TRUE(e1 > o1 && !(e1 <= o1));
  465. ASSERT_TRUE(e1 == o2 && !(e1 != o2));
  466. ASSERT_TRUE(!(e1 < o2) && e1 >= o2);
  467. ASSERT_TRUE(!(e1 > o2) && e1 <= o2);
  468. ASSERT_TRUE(!(e1 == o4) && e1 != o4);
  469. ASSERT_TRUE(!(e1 < o4) && e1 >= o4);
  470. ASSERT_TRUE(e1 > o4 && !(e1 <= o4));
  471. expected = {
  472. { Event::VALUE_CONSTRUCT, &*o1, nullptr, 1 },
  473. { Event::VALUE_CONSTRUCT, &*o2, nullptr, 2 },
  474. { Event::VALUE_CONSTRUCT, &*o3, nullptr, 2 },
  475. { Event::VALUE_CONSTRUCT, &e1, nullptr, 2 },
  476. { Event::COMPARE_EE_EQ, &*o1, &*o2, 1 },
  477. { Event::COMPARE_EE_NE, &*o1, &*o2, 1 },
  478. { Event::COMPARE_EE_LT, &*o1, &*o2, 1 },
  479. { Event::COMPARE_EE_GE, &*o1, &*o2, 1 },
  480. { Event::COMPARE_EE_GT, &*o1, &*o2, 1 },
  481. { Event::COMPARE_EE_LE, &*o1, &*o2, 1 },
  482. { Event::COMPARE_EE_EQ, &*o2, &*o3, 2 },
  483. { Event::COMPARE_EE_NE, &*o2, &*o3, 2 },
  484. { Event::COMPARE_EE_LT, &*o2, &*o3, 2 },
  485. { Event::COMPARE_EE_GE, &*o2, &*o3, 2 },
  486. { Event::COMPARE_EE_GT, &*o2, &*o3, 2 },
  487. { Event::COMPARE_EE_LE, &*o2, &*o3, 2 },
  488. { Event::COMPARE_EE_EQ, &*o1, &e1, 1 },
  489. { Event::COMPARE_EE_NE, &*o1, &e1, 1 },
  490. { Event::COMPARE_EE_LT, &*o1, &e1, 1 },
  491. { Event::COMPARE_EE_GE, &*o1, &e1, 1 },
  492. { Event::COMPARE_EE_GT, &*o1, &e1, 1 },
  493. { Event::COMPARE_EE_LE, &*o1, &e1, 1 },
  494. { Event::COMPARE_EE_EQ, &*o2, &e1, 2 },
  495. { Event::COMPARE_EE_NE, &*o2, &e1, 2 },
  496. { Event::COMPARE_EE_LT, &*o2, &e1, 2 },
  497. { Event::COMPARE_EE_GE, &*o2, &e1, 2 },
  498. { Event::COMPARE_EE_GT, &*o2, &e1, 2 },
  499. { Event::COMPARE_EE_LE, &*o2, &e1, 2 },
  500. { Event::COMPARE_EE_EQ, &e1, &*o1, 2 },
  501. { Event::COMPARE_EE_NE, &e1, &*o1, 2 },
  502. { Event::COMPARE_EE_LT, &e1, &*o1, 2 },
  503. { Event::COMPARE_EE_GE, &e1, &*o1, 2 },
  504. { Event::COMPARE_EE_GT, &e1, &*o1, 2 },
  505. { Event::COMPARE_EE_LE, &e1, &*o1, 2 },
  506. { Event::COMPARE_EE_EQ, &e1, &*o2, 2 },
  507. { Event::COMPARE_EE_NE, &e1, &*o2, 2 },
  508. { Event::COMPARE_EE_LT, &e1, &*o2, 2 },
  509. { Event::COMPARE_EE_GE, &e1, &*o2, 2 },
  510. { Event::COMPARE_EE_GT, &e1, &*o2, 2 },
  511. { Event::COMPARE_EE_LE, &e1, &*o2, 2 },
  512. { Event::DESTRUCT, &e1, nullptr, 2 },
  513. { Event::DESTRUCT, &*o3, nullptr, 2 },
  514. { Event::DESTRUCT, &*o2, nullptr, 2 },
  515. { Event::DESTRUCT, &*o1, nullptr, 1 },
  516. };
  517. return true;
  518. }
  519. static bool testSwap(std::vector<Event>& expected)
  520. {
  521. cm::optional<EventLogger> o1{ 4 };
  522. auto const* v1 = &*o1;
  523. cm::optional<EventLogger> o2{};
  524. o1.swap(o2);
  525. auto const* v2 = &*o2;
  526. ASSERT_TRUE(!o1.has_value());
  527. ASSERT_TRUE(o2.has_value());
  528. ASSERT_TRUE(o2.value().Value == 4);
  529. o1.swap(o2);
  530. ASSERT_TRUE(o1.has_value());
  531. ASSERT_TRUE(o1.value().Value == 4);
  532. ASSERT_TRUE(!o2.has_value());
  533. o2.emplace(5);
  534. o1.swap(o2);
  535. ASSERT_TRUE(o1.has_value());
  536. ASSERT_TRUE(o1.value().Value == 5);
  537. ASSERT_TRUE(o2.has_value());
  538. ASSERT_TRUE(o2.value().Value == 4);
  539. o1.reset();
  540. o2.reset();
  541. o1.swap(o2);
  542. ASSERT_TRUE(!o1.has_value());
  543. ASSERT_TRUE(!o2.has_value());
  544. expected = {
  545. { Event::VALUE_CONSTRUCT, v1, nullptr, 4 },
  546. { Event::MOVE_CONSTRUCT, v2, v1, 4 },
  547. { Event::DESTRUCT, v1, nullptr, 4 },
  548. { Event::MOVE_CONSTRUCT, v1, v2, 4 },
  549. { Event::DESTRUCT, v2, nullptr, 4 },
  550. { Event::VALUE_CONSTRUCT, v2, nullptr, 5 },
  551. { Event::SWAP, v1, v2, 5 },
  552. { Event::DESTRUCT, v1, nullptr, 5 },
  553. { Event::DESTRUCT, v2, nullptr, 4 },
  554. };
  555. return true;
  556. }
  557. static bool testReset(std::vector<Event>& expected)
  558. {
  559. cm::optional<EventLogger> o{ 4 };
  560. auto const* v = &*o;
  561. o.reset();
  562. ASSERT_TRUE(!o.has_value());
  563. o.reset();
  564. expected = {
  565. { Event::VALUE_CONSTRUCT, v, nullptr, 4 },
  566. { Event::DESTRUCT, v, nullptr, 4 },
  567. };
  568. return true;
  569. }
  570. static bool testEmplace(std::vector<Event>& expected)
  571. {
  572. cm::optional<EventLogger> o{ 4 };
  573. o.emplace(5);
  574. o.reset();
  575. o.emplace();
  576. expected = {
  577. { Event::VALUE_CONSTRUCT, &*o, nullptr, 4 },
  578. { Event::DESTRUCT, &*o, nullptr, 4 },
  579. { Event::VALUE_CONSTRUCT, &*o, nullptr, 5 },
  580. { Event::DESTRUCT, &*o, nullptr, 5 },
  581. { Event::DEFAULT_CONSTRUCT, &*o, nullptr, 0 },
  582. { Event::DESTRUCT, &*o, nullptr, 0 },
  583. };
  584. return true;
  585. }
  586. static bool testMakeOptional(std::vector<Event>& expected)
  587. {
  588. EventLogger e{ 4 };
  589. cm::optional<EventLogger> o1 = cm::make_optional<EventLogger>(e);
  590. cm::optional<EventLogger> o2 = cm::make_optional<EventLogger>(5);
  591. expected = {
  592. { Event::VALUE_CONSTRUCT, &e, nullptr, 4 },
  593. { Event::COPY_CONSTRUCT, &*o1, &e, 4 },
  594. { Event::VALUE_CONSTRUCT, &*o2, nullptr, 5 },
  595. { Event::DESTRUCT, &*o2, nullptr, 5 },
  596. { Event::DESTRUCT, &*o1, nullptr, 4 },
  597. { Event::DESTRUCT, &e, nullptr, 4 },
  598. };
  599. return true;
  600. }
  601. static bool testMemoryRange(std::vector<Event>& expected)
  602. {
  603. cm::optional<EventLogger> o{ 4 };
  604. auto* ostart = &o;
  605. auto* oend = ostart + 1;
  606. auto* estart = &o.value();
  607. auto* eend = estart + 1;
  608. ASSERT_TRUE(static_cast<void*>(estart) >= static_cast<void*>(ostart) &&
  609. static_cast<void*>(eend) <= static_cast<void*>(oend));
  610. expected = {
  611. { Event::VALUE_CONSTRUCT, &*o, nullptr, 4 },
  612. { Event::DESTRUCT, &*o, nullptr, 4 },
  613. };
  614. return true;
  615. }
  616. int testOptional(int /*unused*/, char* /*unused*/ [])
  617. {
  618. int retval = 0;
  619. #define DO_EVENT_TEST(name) \
  620. do { \
  621. events.clear(); \
  622. std::vector<Event> expected; \
  623. if (!name(expected)) { \
  624. std::cout << "in " #name << std::endl; \
  625. retval = 1; \
  626. } else if (expected != events) { \
  627. std::cout << #name " did not produce expected events" << std::endl; \
  628. retval = 1; \
  629. } \
  630. } while (0)
  631. #define DO_TEST(name) \
  632. do { \
  633. if (!name()) { \
  634. std::cout << "in " #name << std::endl; \
  635. retval = 1; \
  636. } \
  637. } while (0)
  638. DO_EVENT_TEST(testDefaultConstruct);
  639. DO_EVENT_TEST(testNulloptConstruct);
  640. DO_EVENT_TEST(testValueConstruct);
  641. DO_EVENT_TEST(testInPlaceConstruct);
  642. DO_EVENT_TEST(testCopyConstruct);
  643. DO_EVENT_TEST(testMoveConstruct);
  644. DO_EVENT_TEST(testNulloptAssign);
  645. DO_EVENT_TEST(testCopyAssign);
  646. DO_EVENT_TEST(testMoveAssign);
  647. DO_EVENT_TEST(testPointer);
  648. DO_EVENT_TEST(testDereference);
  649. DO_EVENT_TEST(testHasValue);
  650. DO_EVENT_TEST(testValue);
  651. DO_TEST(testValueOr);
  652. DO_EVENT_TEST(testComparison);
  653. DO_EVENT_TEST(testSwap);
  654. DO_EVENT_TEST(testReset);
  655. DO_EVENT_TEST(testEmplace);
  656. DO_EVENT_TEST(testMakeOptional);
  657. DO_EVENT_TEST(testMemoryRange);
  658. return retval;
  659. }