1 // Copyright (C) 2011 - 2012 Andrzej Krzemienski.
2 //
3 // Use, modification, and distribution is subject to the Boost Software
4 // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
5 // http://www.boost.org/LICENSE_1_0.txt)
6 //
7 // The idea and interface is based on Boost.Optional library
8 // authored by Fernando Luis Cacciola Carballal
9
10 # include "optional.hpp"
11 # include <vector>
12 # include <iostream>
13 # include <functional>
14 # include <complex>
15
16
17
18 struct caller {
callercaller19 template <class T> caller(T fun) { fun(); }
20 };
21 # define CAT2(X, Y) X ## Y
22 # define CAT(X, Y) CAT2(X, Y)
23 # define TEST(NAME) caller CAT(__VAR, __LINE__) = []
24
25 enum State
26 {
27 sDefaultConstructed,
28 sValueCopyConstructed,
29 sValueMoveConstructed,
30 sCopyConstructed,
31 sMoveConstructed,
32 sMoveAssigned,
33 sCopyAssigned,
34 sValueCopyAssigned,
35 sValueMoveAssigned,
36 sMovedFrom,
37 sValueConstructed
38 };
39
40 struct OracleVal
41 {
42 State s;
43 int i;
OracleValOracleVal44 OracleVal(int i = 0) : s(sValueConstructed), i(i) {}
45 };
46
47 struct Oracle
48 {
49 State s;
50 OracleVal val;
51
OracleOracle52 Oracle() : s(sDefaultConstructed) {}
OracleOracle53 Oracle(const OracleVal& v) : s(sValueCopyConstructed), val(v) {}
OracleOracle54 Oracle(OracleVal&& v) : s(sValueMoveConstructed), val(std::move(v)) {v.s = sMovedFrom;}
OracleOracle55 Oracle(const Oracle& o) : s(sCopyConstructed), val(o.val) {}
OracleOracle56 Oracle(Oracle&& o) : s(sMoveConstructed), val(std::move(o.val)) {o.s = sMovedFrom;}
57
operator =Oracle58 Oracle& operator=(const OracleVal& v) { s = sValueCopyConstructed; val = v; return *this; }
operator =Oracle59 Oracle& operator=(OracleVal&& v) { s = sValueMoveConstructed; val = std::move(v); v.s = sMovedFrom; return *this; }
operator =Oracle60 Oracle& operator=(const Oracle& o) { s = sCopyConstructed; val = o.val; return *this; }
operator =Oracle61 Oracle& operator=(Oracle&& o) { s = sMoveConstructed; val = std::move(o.val); o.s = sMovedFrom; return *this; }
62 };
63
64 struct Guard
65 {
66 std::string val;
GuardGuard67 Guard() : val{} {}
GuardGuard68 explicit Guard(std::string s, int = 0) : val(s) {}
69 Guard(const Guard&) = delete;
70 Guard(Guard&&) = delete;
71 void operator=(const Guard&) = delete;
72 void operator=(Guard&&) = delete;
73 };
74
75 struct ExplicitStr
76 {
77 std::string s;
ExplicitStrExplicitStr78 explicit ExplicitStr(const char* chp) : s(chp) {};
79 };
80
81 struct Date
82 {
83 int i;
84 Date() = delete;
DateDate85 Date(int i) : i{i} {};
DateDate86 Date(Date&& d) : i(d.i) { d.i = 0; }
87 Date(const Date&) = delete;
88 Date& operator=(const Date&) = delete;
operator =Date89 Date& operator=(Date&& d) { i = d.i; d.i = 0; return *this;};
90 };
91
operator ==(Oracle const & a,Oracle const & b)92 bool operator==( Oracle const& a, Oracle const& b ) { return a.val.i == b.val.i; }
operator !=(Oracle const & a,Oracle const & b)93 bool operator!=( Oracle const& a, Oracle const& b ) { return a.val.i != b.val.i; }
94
95
96 namespace tr2 = std::experimental;
97
98
TEST(disengaged_ctor)99 TEST(disengaged_ctor)
100 {
101 tr2::optional<int> o1;
102 assert (!o1);
103
104 tr2::optional<int> o2 = tr2::nullopt;
105 assert (!o2);
106
107 tr2::optional<int> o3 = o2;
108 assert (!o3);
109
110 assert (o1 == tr2::nullopt);
111 assert (o1 == tr2::optional<int>{});
112 assert (!o1);
113 assert (bool(o1) == false);
114
115 assert (o2 == tr2::nullopt);
116 assert (o2 == tr2::optional<int>{});
117 assert (!o2);
118 assert (bool(o2) == false);
119
120 assert (o3 == tr2::nullopt);
121 assert (o3 == tr2::optional<int>{});
122 assert (!o3);
123 assert (bool(o3) == false);
124
125 assert (o1 == o2);
126 assert (o2 == o1);
127 assert (o1 == o3);
128 assert (o3 == o1);
129 assert (o2 == o3);
130 assert (o3 == o2);
131 };
132
133
TEST(value_ctor)134 TEST(value_ctor)
135 {
136 OracleVal v;
137 tr2::optional<Oracle> oo1(v);
138 assert (oo1 != tr2::nullopt);
139 assert (oo1 != tr2::optional<Oracle>{});
140 assert (oo1 == tr2::optional<Oracle>{v});
141 assert (!!oo1);
142 assert (bool(oo1));
143 // NA: assert (oo1->s == sValueCopyConstructed);
144 assert (oo1->s == sMoveConstructed);
145 assert (v.s == sValueConstructed);
146
147 tr2::optional<Oracle> oo2(std::move(v));
148 assert (oo2 != tr2::nullopt);
149 assert (oo2 != tr2::optional<Oracle>{});
150 assert (oo2 == oo1);
151 assert (!!oo2);
152 assert (bool(oo2));
153 // NA: assert (oo2->s == sValueMoveConstructed);
154 assert (oo2->s == sMoveConstructed);
155 assert (v.s == sMovedFrom);
156
157 {
158 OracleVal v;
159 tr2::optional<Oracle> oo1{tr2::in_place, v};
160 assert (oo1 != tr2::nullopt);
161 assert (oo1 != tr2::optional<Oracle>{});
162 assert (oo1 == tr2::optional<Oracle>{v});
163 assert (!!oo1);
164 assert (bool(oo1));
165 assert (oo1->s == sValueCopyConstructed);
166 assert (v.s == sValueConstructed);
167
168 tr2::optional<Oracle> oo2{tr2::in_place, std::move(v)};
169 assert (oo2 != tr2::nullopt);
170 assert (oo2 != tr2::optional<Oracle>{});
171 assert (oo2 == oo1);
172 assert (!!oo2);
173 assert (bool(oo2));
174 assert (oo2->s == sValueMoveConstructed);
175 assert (v.s == sMovedFrom);
176 }
177 };
178
179
TEST(assignment)180 TEST(assignment)
181 {
182 tr2::optional<int> oi;
183 oi = tr2::optional<int>{1};
184 assert (*oi == 1);
185
186 oi = tr2::nullopt;
187 assert (!oi);
188
189 oi = 2;
190 assert (*oi == 2);
191
192 oi = {};
193 assert (!oi);
194 };
195
196
197 template <class T>
198 struct MoveAware
199 {
200 T val;
201 bool moved;
MoveAwareMoveAware202 MoveAware(T val) : val(val), moved(false) {}
203 MoveAware(MoveAware const&) = delete;
MoveAwareMoveAware204 MoveAware(MoveAware&& rhs) : val(rhs.val), moved(rhs.moved) {
205 rhs.moved = true;
206 }
207 MoveAware& operator=(MoveAware const&) = delete;
operator =MoveAware208 MoveAware& operator=(MoveAware&& rhs) {
209 val = (rhs.val);
210 moved = (rhs.moved);
211 rhs.moved = true;
212 return *this;
213 }
214 };
215
TEST(moved_from_state)216 TEST(moved_from_state)
217 {
218 // first, test mock:
219 MoveAware<int> i{1}, j{2};
220 assert (i.val == 1);
221 assert (!i.moved);
222 assert (j.val == 2);
223 assert (!j.moved);
224
225 MoveAware<int> k = std::move(i);
226 assert (k.val == 1);
227 assert (!k.moved);
228 assert (i.val == 1);
229 assert (i.moved);
230
231 k = std::move(j);
232 assert (k.val == 2);
233 assert (!k.moved);
234 assert (j.val == 2);
235 assert (j.moved);
236
237 // now, test optional
238 tr2::optional<MoveAware<int>> oi{1}, oj{2};
239 assert (oi);
240 assert (!oi->moved);
241 assert (oj);
242 assert (!oj->moved);
243
244 tr2::optional<MoveAware<int>> ok = std::move(oi);
245 assert (ok);
246 assert (!ok->moved);
247 assert (oi);
248 assert (oi->moved);
249
250 ok = std::move(oj);
251 assert (ok);
252 assert (!ok->moved);
253 assert (oj);
254 assert (oj->moved);
255 };
256
257
TEST(copy_move_ctor_optional_int)258 TEST(copy_move_ctor_optional_int)
259 {
260 tr2::optional<int> oi;
261 tr2::optional<int> oj = oi;
262
263 assert (!oj);
264 assert (oj == oi);
265 assert (oj == tr2::nullopt);
266 assert (!bool(oj));
267
268 oi = 1;
269 tr2::optional<int> ok = oi;
270 assert (!!ok);
271 assert (bool(ok));
272 assert (ok == oi);
273 assert (ok != oj);
274 assert (*ok == 1);
275
276 tr2::optional<int> ol = std::move(oi);
277 assert (!!ol);
278 assert (bool(ol));
279 assert (ol == oi);
280 assert (ol != oj);
281 assert (*ol == 1);
282 };
283
284
TEST(optional_optional)285 TEST(optional_optional)
286 {
287 tr2::optional<tr2::optional<int>> oi1 = tr2::nullopt;
288 assert (oi1 == tr2::nullopt);
289 assert (!oi1);
290
291 {
292 tr2::optional<tr2::optional<int>> oi2 {tr2::in_place};
293 assert (oi2 != tr2::nullopt);
294 assert (bool(oi2));
295 assert (*oi2 == tr2::nullopt);
296 //assert (!(*oi2));
297 //std::cout << typeid(**oi2).name() << std::endl;
298 }
299
300 {
301 tr2::optional<tr2::optional<int>> oi2 {tr2::in_place, tr2::nullopt};
302 assert (oi2 != tr2::nullopt);
303 assert (bool(oi2));
304 assert (*oi2 == tr2::nullopt);
305 assert (!*oi2);
306 }
307
308 {
309 tr2::optional<tr2::optional<int>> oi2 {tr2::optional<int>{}};
310 assert (oi2 != tr2::nullopt);
311 assert (bool(oi2));
312 assert (*oi2 == tr2::nullopt);
313 assert (!*oi2);
314 }
315
316 tr2::optional<int> oi;
317 auto ooi = tr2::make_optional(oi);
318 static_assert( std::is_same<tr2::optional<tr2::optional<int>>, decltype(ooi)>::value, "");
319
320 };
321
TEST(example_guard)322 TEST(example_guard)
323 {
324 using namespace tr2;
325 //FAILS: optional<Guard> ogx(Guard("res1"));
326 //FAILS: optional<Guard> ogx = "res1";
327 //FAILS: optional<Guard> ogx("res1");
328 optional<Guard> oga; // Guard is non-copyable (and non-moveable)
329 optional<Guard> ogb(in_place, "res1"); // initialzes the contained value with "res1"
330 assert (bool(ogb));
331 assert (ogb->val == "res1");
332
333 optional<Guard> ogc(in_place); // default-constructs the contained value
334 assert (bool(ogc));
335 assert (ogc->val == "");
336
337 oga.emplace("res1"); // initialzes the contained value with "res1"
338 assert (bool(oga));
339 assert (oga->val == "res1");
340
341 oga.emplace(); // destroys the contained value and
342 // default-constructs the new one
343 assert (bool(oga));
344 assert (oga->val == "");
345
346 oga = nullopt; // OK: make disengaged the optional Guard
347 assert (!(oga));
348 //FAILS: ogb = {}; // ERROR: Guard is not Moveable
349 };
350
351
process()352 void process(){}
process(int)353 void process(int ){}
processNil()354 void processNil(){}
355
356
TEST(example1)357 TEST(example1)
358 {
359 using namespace tr2;
360 optional<int> oi; // create disengaged object
361 optional<int> oj = nullopt; // alternative syntax
362 oi = oj; // assign disengaged object
363 optional<int> ok = oj; // ok is disengaged
364
365 if (oi) assert(false); // 'if oi is engaged...'
366 if (!oi) assert(true); // 'if oi is disengaged...'
367
368 if (oi != nullopt) assert(false); // 'if oi is engaged...'
369 if (oi == nullopt) assert(true); // 'if oi is disengaged...'
370
371 assert(oi == ok); // two disengaged optionals compare equal
372
373 ///////////////////////////////////////////////////////////////////////////
374 optional<int> ol{1}; // ol is engaged; its contained value is 1
375 ok = 2; // ok becomes engaged; its contained value is 2
376 oj = ol; // oj becomes engaged; its contained value is 1
377
378 assert(oi != ol); // disengaged != engaged
379 assert(ok != ol); // different contained values
380 assert(oj == ol); // same contained value
381 assert(oi < ol); // disengaged < engaged
382 assert(ol < ok); // less by contained value
383
384 /////////////////////////////////////////////////////////////////////////////
385 optional<int> om{1}; // om is engaged; its contained value is 1
386 optional<int> on = om; // on is engaged; its contained value is 1
387 om = 2; // om is engaged; its contained value is 2
388 assert (on != om); // on still contains 3. They are not pointers
389
390 /////////////////////////////////////////////////////////////////////////////
391 int i = *ol; // i obtains the value contained in ol
392 assert (i == 1);
393 *ol = 9; // the object contained in ol becomes 9
394 assert(*ol == 9);
395 assert(ol == make_optional(9));
396
397 ///////////////////////////////////
398 int p = 1;
399 optional<int> op = p;
400 assert(*op == 1);
401 p = 2;
402 assert(*op == 1); // value contained in op is separated from p
403
404 ////////////////////////////////
405 if (ol)
406 process(*ol); // use contained value if present
407 else
408 process(); // proceed without contained value
409
410 if (!om)
411 processNil();
412 else
413 process(*om);
414
415 /////////////////////////////////////////
416 process(ol.value_or(0)); // use 0 if ol is disengaged
417
418 ////////////////////////////////////////////
419 ok = nullopt; // if ok was engaged calls T's dtor
420 oj = {}; // assigns a temporary disengaged optional
421 };
422
423
TEST(example_guard)424 TEST(example_guard)
425 {
426 using std::experimental::optional;
427 const optional<int> c = 4;
428 int i = *c; // i becomes 4
429 assert (i == 4);
430 // FAILS: *c = i; // ERROR: cannot assign to const int&
431 };
432
433
TEST(example_ref)434 TEST(example_ref)
435 {
436 using namespace std::experimental;
437 int i = 1;
438 int j = 2;
439 optional<int&> ora; // disengaged optional reference to int
440 optional<int&> orb = i; // contained reference refers to object i
441
442 *orb = 3; // i becomes 3
443 // FAILS: ora = j; // ERROR: optional refs do not have assignment from T
444 // FAILS: ora = {j}; // ERROR: optional refs do not have copy/move assignment
445 // FAILS: ora = orb; // ERROR: no copy/move assignment
446 ora.emplace(j); // OK: contained reference refers to object j
447 ora.emplace(i); // OK: contained reference now refers to object i
448
449 ora = nullopt; // OK: ora becomes disengaged
450 };
451
452
453 template <typename T>
getValue(tr2::optional<T> newVal=tr2::nullopt,tr2::optional<T &> storeHere=tr2::nullopt)454 T getValue( tr2::optional<T> newVal = tr2::nullopt, tr2::optional<T&> storeHere = tr2::nullopt )
455 {
456 T cached{};
457
458 if (newVal) {
459 cached = *newVal;
460
461 if (storeHere) {
462 *storeHere = *newVal; // LEGAL: assigning T to T
463 }
464 }
465 return cached;
466 }
467
TEST(example_optional_arg)468 TEST(example_optional_arg)
469 {
470 int iii = 0;
471 iii = getValue<int>(iii, iii);
472 iii = getValue<int>(iii);
473 iii = getValue<int>();
474
475 {
476 using namespace std::experimental;
477 optional<Guard> grd1{in_place, "res1", 1}; // guard 1 initialized
478 optional<Guard> grd2;
479
480 grd2.emplace("res2", 2); // guard 2 initialized
481 grd1 = nullopt; // guard 1 released
482
483 } // guard 2 released (in dtor)
484 };
485
486
getStartMidEnd()487 std::tuple<Date, Date, Date> getStartMidEnd() { return std::tuple<Date, Date, Date>{Date{1}, Date{2}, Date{3}}; }
run(Date const &,Date const &,Date const &)488 void run(Date const&, Date const&, Date const&) {}
489
TEST(example_date)490 TEST(example_date)
491 {
492 using namespace std::experimental;
493 optional<Date> start, mid, end; // Date doesn't have default ctor (no good default date)
494
495 std::tie(start, mid, end) = getStartMidEnd();
496 run(*start, *mid, *end);
497 };
498
499
readNextChar()500 std::experimental::optional<char> readNextChar(){ return{}; }
501
run(std::experimental::optional<std::string>)502 void run(std::experimental::optional<std::string>) {}
run(std::complex<double>)503 void run(std::complex<double>) {}
504
505
506 template <class T>
assign_norebind(tr2::optional<T &> & optref,T & obj)507 void assign_norebind(tr2::optional<T&>& optref, T& obj)
508 {
509 if (optref) *optref = obj;
510 else optref.emplace(obj);
511 }
512
unused(T &&)513 template <typename T> void unused(T&&) {}
514
TEST(example_conceptual_model)515 TEST(example_conceptual_model)
516 {
517 using namespace std::experimental;
518
519 optional<int> oi = 0;
520 optional<int> oj = 1;
521 optional<int> ok = nullopt;
522
523 oi = 1;
524 oj = nullopt;
525 ok = 0;
526
527 unused(oi == nullopt);
528 unused(oj == 0);
529 unused(ok == 1);
530 };
531
TEST(example_rationale)532 TEST(example_rationale)
533 {
534 using namespace std::experimental;
535 if (optional<char> ch = readNextChar()) {
536 unused(ch);
537 // ...
538 }
539
540 //////////////////////////////////
541 optional<int> opt1 = nullopt;
542 optional<int> opt2 = {};
543
544 opt1 = nullopt;
545 opt2 = {};
546
547 if (opt1 == nullopt) {}
548 if (!opt2) {}
549 if (opt2 == optional<int>{}) {}
550
551
552
553 ////////////////////////////////
554
555 run(nullopt); // pick the second overload
556 // FAILS: run({}); // ambiguous
557
558 if (opt1 == nullopt) {} // fine
559 // FAILS: if (opt2 == {}) {} // illegal
560
561 ////////////////////////////////
562 assert (optional<unsigned>{} < optional<unsigned>{0});
563 assert (optional<unsigned>{0} < optional<unsigned>{1});
564 assert (!(optional<unsigned>{} < optional<unsigned>{}) );
565 assert (!(optional<unsigned>{1} < optional<unsigned>{1}));
566
567 assert (optional<unsigned>{} != optional<unsigned>{0});
568 assert (optional<unsigned>{0} != optional<unsigned>{1});
569 assert (optional<unsigned>{} == optional<unsigned>{} );
570 assert (optional<unsigned>{0} == optional<unsigned>{0});
571
572 /////////////////////////////////
573 optional<int> o;
574 o = make_optional(1); // copy/move assignment
575 o = 1; // assignment from T
576 o.emplace(1); // emplacement
577
578 ////////////////////////////////////
579 int isas = 0, i = 9;
580 optional<int&> asas = i;
581 assign_norebind(asas, isas);
582
583 /////////////////////////////////////
584 ////tr2::optional<std::vector<int>> ov2 = {2, 3};
585 ////assert (bool(ov2));
586 ////assert ((*ov2)[1] == 3);
587 ////
588 ////////////////////////////////
589 ////std::vector<int> v = {1, 2, 4, 8};
590 ////optional<std::vector<int>> ov = {1, 2, 4, 8};
591
592 ////assert (v == *ov);
593 ////
594 ////ov = {1, 2, 4, 8};
595
596 ////std::allocator<int> a;
597 ////optional<std::vector<int>> ou { in_place, {1, 2, 4, 8}, a };
598
599 ////assert (ou == ov);
600
601 //////////////////////////////
602 // inconvenient syntax:
603 {
604
605 tr2::optional<std::vector<int>> ov2{tr2::in_place, {2, 3}};
606
607 assert (bool(ov2));
608 assert ((*ov2)[1] == 3);
609
610 ////////////////////////////
611
612 std::vector<int> v = {1, 2, 4, 8};
613 optional<std::vector<int>> ov{tr2::in_place, {1, 2, 4, 8}};
614
615 assert (v == *ov);
616
617 ov.emplace({1, 2, 4, 8});
618 /*
619 std::allocator<int> a;
620 optional<std::vector<int>> ou { in_place, {1, 2, 4, 8}, a };
621
622 assert (ou == ov);
623 */
624 }
625
626 /////////////////////////////////
627 {
628 typedef int T;
629 optional<optional<T>> ot {in_place};
630 optional<optional<T>> ou {in_place, nullopt};
631 optional<optional<T>> ov {optional<T>{}};
632
633 optional<int> oi;
634 auto ooi = make_optional(oi);
635 static_assert( std::is_same<optional<optional<int>>, decltype(ooi)>::value, "");
636 }
637 };
638
639
fun(std::string,std::experimental::optional<int> oi=std::experimental::nullopt)640 bool fun(std::string , std::experimental::optional<int> oi = std::experimental::nullopt)
641 {
642 return bool(oi);
643 }
644
TEST(example_converting_ctor)645 TEST(example_converting_ctor)
646 {
647 using namespace std::experimental;
648
649 assert (true == fun("dog", 2));
650 assert (false == fun("dog"));
651 assert (false == fun("dog", nullopt)); // just to be explicit
652 };
653
654
TEST(bad_comparison)655 TEST(bad_comparison)
656 {
657 tr2::optional<int> oi, oj;
658 int i;
659 bool b = (oi == oj);
660 b = (oi >= i);
661 b = (oi == i);
662 unused(b);
663 };
664
665
666 //// NOT APPLICABLE ANYMORE
667 ////TEST(perfect_ctor)
668 ////{
669 //// //tr2::optional<std::string> ois = "OS";
670 //// assert (*ois == "OS");
671 ////
672 //// // FAILS: tr2::optional<ExplicitStr> oes = "OS";
673 //// tr2::optional<ExplicitStr> oes{"OS"};
674 //// assert (oes->s == "OS");
675 ////};
676
TEST(value_or)677 TEST(value_or)
678 {
679 tr2::optional<int> oi = 1;
680 int i = oi.value_or(0);
681 assert (i == 1);
682
683 oi = tr2::nullopt;
684 assert (oi.value_or(3) == 3);
685
686 tr2::optional<std::string> os{"AAA"};
687 assert (os.value_or("BBB") == "AAA");
688 os = {};
689 assert (os.value_or("BBB") == "BBB");
690 };
691
TEST(mixed_order)692 TEST(mixed_order)
693 {
694 using namespace std::experimental;
695
696 optional<int> oN {nullopt};
697 optional<int> o0 {0};
698 optional<int> o1 {1};
699
700 assert ( (oN < 0));
701 assert ( (oN < 1));
702 assert (!(o0 < 0));
703 assert ( (o0 < 1));
704 assert (!(o1 < 0));
705 assert (!(o1 < 1));
706
707 assert (!(oN >= 0));
708 assert (!(oN >= 1));
709 assert ( (o0 >= 0));
710 assert (!(o0 >= 1));
711 assert ( (o1 >= 0));
712 assert ( (o1 >= 1));
713
714 assert (!(oN > 0));
715 assert (!(oN > 1));
716 assert (!(o0 > 0));
717 assert (!(o0 > 1));
718 assert ( (o1 > 0));
719 assert (!(o1 > 1));
720
721 assert ( (oN <= 0));
722 assert ( (oN <= 1));
723 assert ( (o0 <= 0));
724 assert ( (o0 <= 1));
725 assert (!(o1 <= 0));
726 assert ( (o1 <= 1));
727
728 assert ( (0 > oN));
729 assert ( (1 > oN));
730 assert (!(0 > o0));
731 assert ( (1 > o0));
732 assert (!(0 > o1));
733 assert (!(1 > o1));
734
735 assert (!(0 <= oN));
736 assert (!(1 <= oN));
737 assert ( (0 <= o0));
738 assert (!(1 <= o0));
739 assert ( (0 <= o1));
740 assert ( (1 <= o1));
741
742 assert (!(0 < oN));
743 assert (!(1 < oN));
744 assert (!(0 < o0));
745 assert (!(1 < o0));
746 assert ( (0 < o1));
747 assert (!(1 < o1));
748
749 assert ( (0 >= oN));
750 assert ( (1 >= oN));
751 assert ( (0 >= o0));
752 assert ( (1 >= o0));
753 assert (!(0 >= o1));
754 assert ( (1 >= o1));
755 };
756
757 struct BadRelops
758 {
759 int i;
760 };
761
operator <(BadRelops a,BadRelops b)762 constexpr bool operator<(BadRelops a, BadRelops b) { return a.i < b.i; }
operator >(BadRelops a,BadRelops b)763 constexpr bool operator>(BadRelops a, BadRelops b) { return a.i < b.i; } // intentional error!
764
TEST(bad_relops)765 TEST(bad_relops)
766 {
767 using namespace std::experimental;
768 BadRelops a{1}, b{2};
769 assert (a < b);
770 assert (a > b);
771
772 optional<BadRelops> oa = a, ob = b;
773 assert (oa < ob);
774 assert (!(oa > ob));
775
776 assert (oa < b);
777 assert (oa > b);
778
779 optional<BadRelops&> ra = a, rb = b;
780 assert (ra < rb);
781 assert (!(ra > rb));
782
783 assert (ra < b);
784 assert (ra > b);
785 };
786
787
TEST(mixed_equality)788 TEST(mixed_equality)
789 {
790 using namespace std::experimental;
791
792 assert (make_optional(0) == 0);
793 assert (make_optional(1) == 1);
794 assert (make_optional(0) != 1);
795 assert (make_optional(1) != 0);
796
797 optional<int> oN {nullopt};
798 optional<int> o0 {0};
799 optional<int> o1 {1};
800
801 assert (o0 == 0);
802 assert ( 0 == o0);
803 assert (o1 == 1);
804 assert ( 1 == o1);
805 assert (o1 != 0);
806 assert ( 0 != o1);
807 assert (o0 != 1);
808 assert ( 1 != o0);
809
810 assert ( 1 != oN);
811 assert ( 0 != oN);
812 assert (oN != 1);
813 assert (oN != 0);
814 assert (!( 1 == oN));
815 assert (!( 0 == oN));
816 assert (!(oN == 1));
817 assert (!(oN == 0));
818
819 std::string cat{"cat"}, dog{"dog"};
820 optional<std::string> oNil{}, oDog{"dog"}, oCat{"cat"};
821
822 assert (oCat == cat);
823 assert ( cat == oCat);
824 assert (oDog == dog);
825 assert ( dog == oDog);
826 assert (oDog != cat);
827 assert ( cat != oDog);
828 assert (oCat != dog);
829 assert ( dog != oCat);
830
831 assert ( dog != oNil);
832 assert ( cat != oNil);
833 assert (oNil != dog);
834 assert (oNil != cat);
835 assert (!( dog == oNil));
836 assert (!( cat == oNil));
837 assert (!(oNil == dog));
838 assert (!(oNil == cat));
839 };
840
TEST(const_propagation)841 TEST(const_propagation)
842 {
843 using namespace std::experimental;
844
845 optional<int> mmi{0};
846 static_assert(std::is_same<decltype(*mmi), int&>::value, "WTF");
847
848 const optional<int> cmi{0};
849 static_assert(std::is_same<decltype(*cmi), const int&>::value, "WTF");
850
851 optional<const int> mci{0};
852 static_assert(std::is_same<decltype(*mci), const int&>::value, "WTF");
853
854 optional<const int> cci{0};
855 static_assert(std::is_same<decltype(*cci), const int&>::value, "WTF");
856 };
857
858
859 static_assert(std::is_base_of<std::logic_error, std::experimental::bad_optional_access>::value, "");
860
TEST(safe_value)861 TEST(safe_value)
862 {
863 using namespace std::experimental;
864
865 try {
866 optional<int> ovN{}, ov1{1};
867
868 int& r1 = ov1.value();
869 assert (r1 == 1);
870
871 try {
872 ovN.value();
873 assert (false);
874 }
875 catch (bad_optional_access const&) {
876 }
877
878 { // ref variant
879 int i1 = 1;
880 optional<int&> orN{}, or1{i1};
881
882 int& r2 = or1.value();
883 assert (r2 == 1);
884
885 try {
886 orN.value();
887 assert (false);
888 }
889 catch (bad_optional_access const&) {
890 }
891 }
892 }
893 catch(...) {
894 assert (false);
895 }
896 };
897
TEST(optional_ref)898 TEST(optional_ref)
899 {
900 using namespace tr2;
901 // FAILS: optional<int&&> orr;
902 // FAILS: optional<nullopt_t&> on;
903 int i = 8;
904 optional<int&> ori;
905 assert (!ori);
906 ori.emplace(i);
907 assert (bool(ori));
908 assert (*ori == 8);
909 assert (&*ori == &i);
910 *ori = 9;
911 assert (i == 9);
912
913 // FAILS: int& ir = ori.value_or(i);
914 int ii = ori.value_or(i);
915 assert (ii == 9);
916 ii = 7;
917 assert (*ori == 9);
918
919 int j = 22;
920 auto&& oj = make_optional(std::ref(j));
921 *oj = 23;
922 assert (&*oj == &j);
923 assert (j == 23);
924 };
925
TEST(optional_ref_const_propagation)926 TEST(optional_ref_const_propagation)
927 {
928 using namespace std::experimental;
929
930 int i = 9;
931 const optional<int&> mi = i;
932 int& r = *mi;
933 optional<const int&> ci = i;
934 static_assert(std::is_same<decltype(*mi), int&>::value, "WTF");
935 static_assert(std::is_same<decltype(*ci), const int&>::value, "WTF");
936
937 unused(r);
938 };
939
TEST(optional_ref_assign)940 TEST(optional_ref_assign)
941 {
942 using namespace std::experimental;
943
944 int i = 9;
945 optional<int&> ori = i;
946
947 int j = 1;
948 ori = optional<int&>{j};
949 ori = {j};
950 // FAILS: ori = j;
951
952 optional<int&> orx = ori;
953 ori = orx;
954
955 optional<int&> orj = j;
956
957 assert (ori);
958 assert (*ori == 1);
959 assert (ori == orj);
960 assert (i == 9);
961
962 *ori = 2;
963 assert (*ori == 2);
964 assert (ori == 2);
965 assert (2 == ori);
966 assert (ori != 3);
967
968 assert (ori == orj);
969 assert (j == 2);
970 assert (i == 9);
971
972 ori = {};
973 assert (!ori);
974 assert (ori != orj);
975 assert (j == 2);
976 assert (i == 9);
977 };
978
979
TEST(optional_ref_swap)980 TEST(optional_ref_swap)
981 {
982 using namespace std::experimental;
983 int i = 0;
984 int j = 1;
985 optional<int&> oi = i;
986 optional<int&> oj = j;
987
988 assert (&*oi == &i);
989 assert (&*oj == &j);
990
991 swap(oi, oj);
992 assert (&*oi == &j);
993 assert (&*oj == &i);
994 };
995
TEST(optional_initialization)996 TEST(optional_initialization)
997 {
998 using namespace tr2;
999 using std::string;
1000 string s = "STR";
1001
1002 optional<string> os{s};
1003 optional<string> ot = s;
1004 optional<string> ou{"STR"};
1005 optional<string> ov = string{"STR"};
1006
1007 };
1008
1009 #include <unordered_set>
1010
TEST(optional_hashing)1011 TEST(optional_hashing)
1012 {
1013 using namespace tr2;
1014 using std::string;
1015
1016 std::hash<int> hi;
1017 std::hash<optional<int>> hoi;
1018 std::hash<string> hs;
1019 std::hash<optional<string>> hos;
1020
1021 assert (hi(0) == hoi(optional<int>{0}));
1022 assert (hi(1) == hoi(optional<int>{1}));
1023 assert (hi(3198) == hoi(optional<int>{3198}));
1024
1025 assert (hs("") == hos(optional<string>{""}));
1026 assert (hs("0") == hos(optional<string>{"0"}));
1027 assert (hs("Qa1#") == hos(optional<string>{"Qa1#"}));
1028
1029 std::unordered_set<optional<string>> set;
1030 assert(set.find({"Qa1#"}) == set.end());
1031
1032 set.insert({"0"});
1033 assert(set.find({"Qa1#"}) == set.end());
1034
1035 set.insert({"Qa1#"});
1036 assert(set.find({"Qa1#"}) != set.end());
1037 };
1038
1039
1040 // optional_ref_emulation
1041 template <class T>
1042 struct generic
1043 {
1044 typedef T type;
1045 };
1046
1047 template <class U>
1048 struct generic<U&>
1049 {
1050 typedef std::reference_wrapper<U> type;
1051 };
1052
1053 template <class T>
1054 using Generic = typename generic<T>::type;
1055
1056 template <class X>
generic_fun()1057 bool generic_fun()
1058 {
1059 std::experimental::optional<Generic<X>> op;
1060 return bool(op);
1061 }
1062
TEST(optional_ref_emulation)1063 TEST(optional_ref_emulation)
1064 {
1065 using namespace std::experimental;
1066 optional<Generic<int>> oi = 1;
1067 assert (*oi == 1);
1068
1069 int i = 8;
1070 int j = 4;
1071 optional<Generic<int&>> ori {i};
1072 assert (*ori == 8);
1073 assert ((void*)&*ori != (void*)&i); // !DIFFERENT THAN optional<T&>
1074
1075 *ori = j;
1076 assert (*ori == 4);
1077 };
1078
1079
1080 # if OPTIONAL_HAS_THIS_RVALUE_REFS == 1
TEST(moved_on_value_or)1081 TEST(moved_on_value_or)
1082 {
1083 using namespace tr2;
1084 optional<Oracle> oo{in_place};
1085
1086 assert (oo);
1087 assert (oo->s == sDefaultConstructed);
1088
1089 Oracle o = std::move(oo).value_or( Oracle{OracleVal{}} );
1090 assert (oo);
1091 assert (oo->s == sMovedFrom);
1092 assert (o.s == sMoveConstructed);
1093
1094 optional<MoveAware<int>> om {in_place, 1};
1095 assert (om);
1096 assert (om->moved == false);
1097
1098 /*MoveAware<int> m =*/ std::move(om).value_or( MoveAware<int>{1} );
1099 assert (om);
1100 assert (om->moved == true);
1101
1102 # if OPTIONAL_HAS_MOVE_ACCESSORS == 1
1103 {
1104 Date d = optional<Date>{in_place, 1}.value();
1105 assert (d.i); // to silence compiler warning
1106
1107 Date d2 = *optional<Date>{in_place, 1};
1108 assert (d2.i); // to silence compiler warning
1109 }
1110 # endif
1111 };
1112 # endif
1113
1114
TEST(optional_ref_hashing)1115 TEST(optional_ref_hashing)
1116 {
1117 using namespace tr2;
1118 using std::string;
1119
1120 std::hash<int> hi;
1121 std::hash<optional<int&>> hoi;
1122 std::hash<string> hs;
1123 std::hash<optional<string&>> hos;
1124
1125 int i0 = 0;
1126 int i1 = 1;
1127 assert (hi(0) == hoi(optional<int&>{i0}));
1128 assert (hi(1) == hoi(optional<int&>{i1}));
1129
1130 string s{""};
1131 string s0{"0"};
1132 string sCAT{"CAT"};
1133 assert (hs("") == hos(optional<string&>{s}));
1134 assert (hs("0") == hos(optional<string&>{s0}));
1135 assert (hs("CAT") == hos(optional<string&>{sCAT}));
1136
1137 std::unordered_set<optional<string&>> set;
1138 assert(set.find({sCAT}) == set.end());
1139
1140 set.insert({s0});
1141 assert(set.find({sCAT}) == set.end());
1142
1143 set.insert({sCAT});
1144 assert(set.find({sCAT}) != set.end());
1145 };
1146
1147 struct Combined
1148 {
1149 int m = 0;
1150 int n = 1;
1151
CombinedCombined1152 constexpr Combined() : m{5}, n{6} {}
CombinedCombined1153 constexpr Combined(int m, int n) : m{m}, n{n} {}
1154 };
1155
1156 struct Nasty
1157 {
1158 int m = 0;
1159 int n = 1;
1160
NastyNasty1161 constexpr Nasty() : m{5}, n{6} {}
NastyNasty1162 constexpr Nasty(int m, int n) : m{m}, n{n} {}
1163
operator &Nasty1164 int operator&() { return n; }
operator &Nasty1165 int operator&() const { return n; }
1166 };
1167
TEST(arrow_operator)1168 TEST(arrow_operator)
1169 {
1170 using namespace std::experimental;
1171
1172 optional<Combined> oc1{in_place, 1, 2};
1173 assert (oc1);
1174 assert (oc1->m == 1);
1175 assert (oc1->n == 2);
1176
1177 optional<Nasty> on{in_place, 1, 2};
1178 assert (on);
1179 assert (on->m == 1);
1180 assert (on->n == 2);
1181 };
1182
TEST(arrow_wit_optional_ref)1183 TEST(arrow_wit_optional_ref)
1184 {
1185 using namespace std::experimental;
1186
1187 Combined c{1, 2};
1188 optional<Combined&> oc = c;
1189 assert (oc);
1190 assert (oc->m == 1);
1191 assert (oc->n == 2);
1192
1193 Nasty n{1, 2};
1194 Nasty m{3, 4};
1195 Nasty p{5, 6};
1196
1197 optional<Nasty&> on{n};
1198 assert (on);
1199 assert (on->m == 1);
1200 assert (on->n == 2);
1201
1202 on = {m};
1203 assert (on);
1204 assert (on->m == 3);
1205 assert (on->n == 4);
1206
1207 on.emplace(p);
1208 assert (on);
1209 assert (on->m == 5);
1210 assert (on->n == 6);
1211
1212 optional<Nasty&> om{in_place, n};
1213 assert (om);
1214 assert (om->m == 1);
1215 assert (om->n == 2);
1216 };
1217
TEST(no_dangling_reference_in_value)1218 TEST(no_dangling_reference_in_value)
1219 {
1220 // this mostly tests compiler warnings
1221 using namespace std::experimental;
1222 optional<int> oi {2};
1223 unused (oi.value());
1224 const optional<int> coi {3};
1225 unused (coi.value());
1226 };
1227
1228 struct CountedObject
1229 {
1230 static int _counter;
1231 bool _throw;
CountedObjectCountedObject1232 CountedObject(bool b) : _throw(b) { ++_counter; }
CountedObjectCountedObject1233 CountedObject(CountedObject const& rhs) : _throw(rhs._throw) { if (_throw) throw int(); }
~CountedObjectCountedObject1234 ~CountedObject() { --_counter; }
1235 };
1236
1237 int CountedObject::_counter = 0;
1238
TEST(exception_safety)1239 TEST(exception_safety)
1240 {
1241 using namespace std::experimental;
1242 try {
1243 optional<CountedObject> oo(in_place, true); // throw
1244 optional<CountedObject> o1(oo);
1245 }
1246 catch(...)
1247 {
1248 //
1249 }
1250 assert(CountedObject::_counter == 0);
1251
1252 try {
1253 optional<CountedObject> oo(in_place, true); // throw
1254 optional<CountedObject> o1(std::move(oo)); // now move
1255 }
1256 catch(...)
1257 {
1258 //
1259 }
1260 assert(CountedObject::_counter == 0);
1261 };
1262
1263 //// constexpr tests
1264
1265 // these 4 classes have different noexcept signatures in move operations
1266 struct NothrowBoth {
NothrowBothNothrowBoth1267 NothrowBoth(NothrowBoth&&) noexcept(true) {};
operator =NothrowBoth1268 void operator=(NothrowBoth&&) noexcept(true) {};
1269 };
1270 struct NothrowCtor {
NothrowCtorNothrowCtor1271 NothrowCtor(NothrowCtor&&) noexcept(true) {};
operator =NothrowCtor1272 void operator=(NothrowCtor&&) noexcept(false) {};
1273 };
1274 struct NothrowAssign {
NothrowAssignNothrowAssign1275 NothrowAssign(NothrowAssign&&) noexcept(false) {};
operator =NothrowAssign1276 void operator=(NothrowAssign&&) noexcept(true) {};
1277 };
1278 struct NothrowNone {
NothrowNoneNothrowNone1279 NothrowNone(NothrowNone&&) noexcept(false) {};
operator =NothrowNone1280 void operator=(NothrowNone&&) noexcept(false) {};
1281 };
1282
test_noexcept()1283 void test_noexcept()
1284 {
1285 {
1286 tr2::optional<NothrowBoth> b1, b2;
1287 static_assert(noexcept(tr2::optional<NothrowBoth>{tr2::constexpr_move(b1)}), "bad noexcept!");
1288 static_assert(noexcept(b1 = tr2::constexpr_move(b2)), "bad noexcept!");
1289 }
1290 {
1291 tr2::optional<NothrowCtor> c1, c2;
1292 static_assert(noexcept(tr2::optional<NothrowCtor>{tr2::constexpr_move(c1)}), "bad noexcept!");
1293 static_assert(!noexcept(c1 = tr2::constexpr_move(c2)), "bad noexcept!");
1294 }
1295 {
1296 tr2::optional<NothrowAssign> a1, a2;
1297 static_assert(!noexcept(tr2::optional<NothrowAssign>{tr2::constexpr_move(a1)}), "bad noexcept!");
1298 static_assert(!noexcept(a1 = tr2::constexpr_move(a2)), "bad noexcept!");
1299 }
1300 {
1301 tr2::optional<NothrowNone> n1, n2;
1302 static_assert(!noexcept(tr2::optional<NothrowNone>{tr2::constexpr_move(n1)}), "bad noexcept!");
1303 static_assert(!noexcept(n1 = tr2::constexpr_move(n2)), "bad noexcept!");
1304 }
1305 }
1306
1307
constexpr_test_disengaged()1308 void constexpr_test_disengaged()
1309 {
1310 constexpr tr2::optional<int> g0{};
1311 constexpr tr2::optional<int> g1{tr2::nullopt};
1312 static_assert( !g0, "initialized!" );
1313 static_assert( !g1, "initialized!" );
1314
1315 static_assert( bool(g1) == bool(g0), "ne!" );
1316
1317 static_assert( g1 == g0, "ne!" );
1318 static_assert( !(g1 != g0), "ne!" );
1319 static_assert( g1 >= g0, "ne!" );
1320 static_assert( !(g1 > g0), "ne!" );
1321 static_assert( g1 <= g0, "ne!" );
1322 static_assert( !(g1 <g0), "ne!" );
1323
1324 static_assert( g1 == tr2::nullopt, "!" );
1325 static_assert( !(g1 != tr2::nullopt), "!" );
1326 static_assert( g1 <= tr2::nullopt, "!" );
1327 static_assert( !(g1 < tr2::nullopt), "!" );
1328 static_assert( g1 >= tr2::nullopt, "!" );
1329 static_assert( !(g1 > tr2::nullopt), "!" );
1330
1331 static_assert( (tr2::nullopt == g0), "!" );
1332 static_assert( !(tr2::nullopt != g0), "!" );
1333 static_assert( (tr2::nullopt >= g0), "!" );
1334 static_assert( !(tr2::nullopt > g0), "!" );
1335 static_assert( (tr2::nullopt <= g0), "!" );
1336 static_assert( !(tr2::nullopt < g0), "!" );
1337
1338 static_assert( (g1 != tr2::optional<int>(1)), "!" );
1339 static_assert( !(g1 == tr2::optional<int>(1)), "!" );
1340 static_assert( (g1 < tr2::optional<int>(1)), "!" );
1341 static_assert( (g1 <= tr2::optional<int>(1)), "!" );
1342 static_assert( !(g1 > tr2::optional<int>(1)), "!" );
1343 static_assert( !(g1 > tr2::optional<int>(1)), "!" );
1344 }
1345
1346
1347 constexpr tr2::optional<int> g0{};
1348 constexpr tr2::optional<int> g2{2};
1349 static_assert( g2, "not initialized!" );
1350 static_assert( *g2 == 2, "not 2!" );
1351 static_assert( g2 == tr2::optional<int>(2), "not 2!" );
1352 static_assert( g2 != g0, "eq!" );
1353
1354 # if OPTIONAL_HAS_MOVE_ACCESSORS == 1
1355 static_assert( *tr2::optional<int>{3} == 3, "WTF!" );
1356 static_assert( tr2::optional<int>{3}.value() == 3, "WTF!" );
1357 static_assert( tr2::optional<int>{3}.value_or(1) == 3, "WTF!" );
1358 static_assert( tr2::optional<int>{}.value_or(4) == 4, "WTF!" );
1359 # endif
1360
1361 constexpr tr2::optional<Combined> gc0{tr2::in_place};
1362 static_assert(gc0->n == 6, "WTF!");
1363
1364 // optional refs
1365 int gi = 0;
1366 constexpr tr2::optional<int&> gori = gi;
1367 constexpr tr2::optional<int&> gorn{};
1368 constexpr int& gri = *gori;
1369 static_assert(gori, "WTF");
1370 static_assert(!gorn, "WTF");
1371 static_assert(gori != tr2::nullopt, "WTF");
1372 static_assert(gorn == tr2::nullopt, "WTF");
1373 static_assert(&gri == &*gori, "WTF");
1374
1375 constexpr int gci = 1;
1376 constexpr tr2::optional<int const&> gorci = gci;
1377 constexpr tr2::optional<int const&> gorcn{};
1378
1379 static_assert(gorcn < gorci, "WTF");
1380 static_assert(gorcn <= gorci, "WTF");
1381 static_assert(gorci == gorci, "WTF");
1382 static_assert(*gorci == 1, "WTF");
1383 static_assert(gorci == gci, "WTF");
1384
1385 namespace constexpr_optional_ref_and_arrow
1386 {
1387 using namespace std::experimental;
1388 constexpr Combined c{1, 2};
1389 constexpr optional<Combined const&> oc = c;
1390 static_assert(oc, "WTF!");
1391 static_assert(oc->m == 1, "WTF!");
1392 static_assert(oc->n == 2, "WTF!");
1393 }
1394
1395 #if OPTIONAL_HAS_CONSTEXPR_INIT_LIST
1396
1397 namespace InitList
1398 {
1399 using namespace std::experimental;
1400
1401 struct ConstInitLister
1402 {
1403 template <typename T>
ConstInitListerInitList::ConstInitLister1404 constexpr ConstInitLister(std::initializer_list<T> il) : len (il.size()) {}
1405 size_t len;
1406 };
1407
1408 constexpr ConstInitLister CIL {2, 3, 4};
1409 static_assert(CIL.len == 3, "WTF!");
1410
1411 constexpr optional<ConstInitLister> oil {in_place, {4, 5, 6, 7}};
1412 static_assert(oil, "WTF!");
1413 static_assert(oil->len == 4, "WTF!");
1414 }
1415
1416 #endif // OPTIONAL_HAS_CONSTEXPR_INIT_LIST
1417
1418 // end constexpr tests
1419
1420
1421 #include <string>
1422
1423
1424 struct VEC
1425 {
1426 std::vector<int> v;
1427 template <typename... X>
VECVEC1428 VEC( X&&...x) : v(std::forward<X>(x)...) {}
1429
1430 template <typename U, typename... X>
VECVEC1431 VEC(std::initializer_list<U> il, X&&...x) : v(il, std::forward<X>(x)...) {}
1432 };
1433
1434
1435
main()1436 int main() {
1437 tr2::optional<int> oi = 1;
1438 assert (bool(oi));
1439 oi.operator=({});
1440 assert (!oi);
1441
1442 VEC v = {5, 6};
1443
1444 if (OPTIONAL_HAS_THIS_RVALUE_REFS)
1445 std::cout << "Optional has rvalue references for *this" << std::endl;
1446 else
1447 std::cout << "Optional doesn't have rvalue references for *this" << std::endl;
1448
1449 if (OPTIONAL_HAS_CONSTEXPR_INIT_LIST)
1450 std::cout << "Optional has constexpr initializer_list" << std::endl;
1451 else
1452 std::cout << "Optional doesn't have constexpr initializer_list" << std::endl;
1453
1454 if (OPTIONAL_HAS_MOVE_ACCESSORS)
1455 std::cout << "Optional has constexpr move accessors" << std::endl;
1456 else
1457 std::cout << "Optional doesn't have constexpr move accessors" << std::endl;
1458 }
1459
1460