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