optional.cc
1 /* Copyright 2017 The TensorFlow Authors. All Rights Reserved.
2 
3 Modifications copyright 2017 Universite catholique de Louvain (UCL), Belgium
4 
5 Licensed under the Apache License, Version 2.0 (the "License");
6 you may not use this file except in compliance with the License.
7 You may obtain a copy of the License at
8 
9  http://www.apache.org/licenses/LICENSE-2.0
10 
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16 ==============================================================================*/
17 
18 #include <lib/optional.h>
19 
20 #include <catch.hpp>
21 
22 #include <string>
23 #include <utility>
24 #include <set>
25 
26 #include <momemta/Logging.h>
27 
28 #include <platform/macros.h>
29 
30 namespace momemta {
31 namespace {
32 
34 using momemta::gtl::nullopt;
36 using momemta::gtl::in_place;
38 using momemta::gtl::make_optional;
39 
40 template <typename T> std::string TypeQuals(T&) { return "&"; }
41 template <typename T> std::string TypeQuals(T&&) { return "&&"; }
42 template <typename T> std::string TypeQuals(const T&) { return "c&"; }
43 template <typename T> std::string TypeQuals(const T&&) { return "c&&"; }
44 
45 struct StructorListener {
46  int construct0 = 0;
47  int construct1 = 0;
48  int construct2 = 0;
49  int listinit = 0;
50  int copy = 0;
51  int move = 0;
52  int copy_assign = 0;
53  int move_assign = 0;
54  int destruct = 0;
55 };
56 
57 struct Listenable {
58  static StructorListener* listener;
59 
60  Listenable() { ++listener->construct0; }
61  Listenable(int /*unused*/) { ++listener->construct1; } // NOLINT
62  Listenable(int /*unused*/, int /*unused*/) { ++listener->construct2; }
63  Listenable(std::initializer_list<int> /*unused*/) { ++listener->listinit; }
64  Listenable(const Listenable& /*unused*/) { ++listener->copy; }
65  Listenable(Listenable&& /*unused*/) { ++listener->move; } // NOLINT
66  Listenable& operator=(const Listenable& /*unused*/) {
67  ++listener->copy_assign;
68  return *this;
69  }
70  Listenable& operator=(Listenable&& /*unused*/) { // NOLINT
71  ++listener->move_assign;
72  return *this;
73  }
74  ~Listenable() { ++listener->destruct; }
75 };
76 
77 StructorListener* Listenable::listener = nullptr;
78 
79 // clang on macos -- even the latest major version at time of writing (8.x) --
80 // does not like much of our constexpr business. clang < 3.0 also has trouble.
81 #if defined(__clang__) && defined(__APPLE__)
82 #define SKIP_CONSTEXPR_TEST_DUE_TO_CLANG_BUG
83 #endif
84 
85 struct ConstexprType {
86  constexpr ConstexprType() : x(0) {}
87  constexpr explicit ConstexprType(int i) : x(i) {}
88 #ifndef SKIP_CONSTEXPR_TEST_DUE_TO_CLANG_BUG
89  constexpr ConstexprType(std::initializer_list<int> il) : x(il.size()) {}
90 #endif
91  constexpr ConstexprType(const char* s ATTRIBUTE_UNUSED) : x(-1) {} // NOLINT
92  int x;
93 };
94 
95 struct Copyable {
96  Copyable() {}
97  Copyable(const Copyable&) {}
98  Copyable& operator=(const Copyable&) { return *this; }
99 };
100 
101 struct MoveableThrow {
102  MoveableThrow() {}
103  MoveableThrow(MoveableThrow&&) {}
104  MoveableThrow& operator=(MoveableThrow&&) { return *this; }
105 };
106 
107 struct MoveableNoThrow {
108  MoveableNoThrow() {}
109  MoveableNoThrow(MoveableNoThrow&&) noexcept {}
110  MoveableNoThrow& operator=(MoveableNoThrow&&) noexcept { return *this; }
111 };
112 
113 struct NonMovable {
114  NonMovable() {}
115  NonMovable(const NonMovable&) = delete;
116  NonMovable& operator=(const NonMovable&) = delete;
117  NonMovable(NonMovable&&) = delete;
118  NonMovable& operator=(NonMovable&&) = delete;
119 };
120 
121 TEST_CASE("optional", "[core/lib]") {
122  SECTION("DefaultConstructor")
123  {
124  optional<int> empty;
125  REQUIRE_FALSE(!!empty);
126  constexpr optional<int> cempty;
127  static_assert(!cempty.has_value(), "");
128  REQUIRE(std::is_nothrow_default_constructible<optional<int>>::value);
129  }
130 
131  SECTION("NullOptConstructor")
132  {
133  optional<int> empty(nullopt);
134  REQUIRE_FALSE(!!empty);
135  // Creating a temporary nullopt_t object instead of using nullopt because
136  // nullopt cannot be constexpr and have external linkage at the same time.
137  constexpr optional<int> cempty{nullopt_t(nullopt_t::init)};
138  static_assert(!cempty.has_value(), "");
139  REQUIRE((std::is_nothrow_constructible<optional<int>, nullopt_t>::value));
140  }
141 
142  SECTION("CopyConstructor")
143  {
144  optional<int> empty, opt42 = 42;
145  optional<int> empty_copy(empty);
146  REQUIRE_FALSE(!!empty_copy);
147  optional<int> opt42_copy(opt42);
148  REQUIRE(!!opt42_copy);
149  REQUIRE(42 == opt42_copy);
150  // test copyablility
151  REQUIRE(std::is_copy_constructible<optional<int>>::value);
152  REQUIRE(std::is_copy_constructible<optional<Copyable>>::value);
153  REQUIRE_FALSE(std::is_copy_constructible<optional<MoveableThrow>>::value);
154  REQUIRE_FALSE(std::is_copy_constructible<optional<MoveableNoThrow>>::value);
155  REQUIRE_FALSE(std::is_copy_constructible<optional<NonMovable>>::value);
156  }
157 
158  SECTION("MoveConstructor")
159  {
160  optional<int> empty, opt42 = 42;
161  optional<int> empty_move(std::move(empty));
162  REQUIRE_FALSE(!!empty_move);
163  optional<int> opt42_move(std::move(opt42));
164  REQUIRE(!!opt42_move);
165  REQUIRE(42 == opt42_move);
166  // test movability
167  REQUIRE(std::is_move_constructible<optional<int>>::value);
168  REQUIRE(std::is_move_constructible<optional<Copyable>>::value);
169  REQUIRE(std::is_move_constructible<optional<MoveableThrow>>::value);
170  REQUIRE(std::is_move_constructible<optional<MoveableNoThrow>>::value);
171  REQUIRE_FALSE(std::is_move_constructible<optional<NonMovable>>::value);
172  // test noexcept
173  REQUIRE(std::is_nothrow_move_constructible<optional<int>>::value);
174  REQUIRE_FALSE(
175  std::is_nothrow_move_constructible<optional<MoveableThrow>>::value);
176  REQUIRE(
177  std::is_nothrow_move_constructible<optional<MoveableNoThrow>>::value);
178  }
179 
180  SECTION("Destructor")
181  {
182  struct Trivial {};
183 
184  struct NonTrivial {
185  ~NonTrivial() {}
186  };
187 
188  REQUIRE(std::is_trivially_destructible<optional<int>>::value);
189  REQUIRE(std::is_trivially_destructible<optional<Trivial>>::value);
190  REQUIRE_FALSE(std::is_trivially_destructible<optional<NonTrivial>>::value);
191  }
192 
193  SECTION("InPlaceConstructor")
194  {
195  constexpr optional<ConstexprType> opt0{in_place_t()};
196  static_assert(opt0, "");
197  static_assert(opt0->x == 0, "");
198  constexpr optional<ConstexprType> opt1{in_place_t(), 1};
199  static_assert(opt1, "");
200  static_assert(opt1->x == 1, "");
201 #ifndef SKIP_CONSTEXPR_TEST_DUE_TO_CLANG_BUG
202  constexpr optional<ConstexprType> opt2{in_place_t(), {1, 2}};
203  static_assert(opt2, "");
204  static_assert(opt2->x == 2, "");
205 #endif
206 
207  // TODO(b/34201852): uncomment these when std::is_constructible<T, Args&&...>
208  // SFINAE is added to optional::optional(in_place_t, Args&&...).
209  // struct I {
210  // I(in_place_t);
211  // };
212 
213  // REQUIRE_FALSE((std::is_constructible<optional<I>, in_place_t>::value));
214  // REQUIRE_FALSE((std::is_constructible<optional<I>, const
215  // in_place_t&>::value));
216  }
217 
218 // template<U=T> optional(U&&);
219  SECTION("ValueConstructor")
220  {
221  constexpr optional<int> opt0(0);
222  static_assert(opt0, "");
223  static_assert(*opt0 == 0, "");
224  REQUIRE((std::is_convertible<int, optional<int>>::value));
225  // Copy initialization ( = "abc") won't work due to optional(optional&&)
226  // is not constexpr. Use list initialization instead. This invokes
227  // optional<ConstexprType>::optional<U>(U&&), with U = const char (&) [4],
228  // which direct-initializes the ConstexprType value held by the optional
229  // via ConstexprType::ConstexprType(const char*).
230  constexpr optional<ConstexprType> opt1 = {"abc"};
231  static_assert(opt1, "");
232  static_assert(-1 == opt1->x, "");
233  REQUIRE(
234  (std::is_convertible<const char *, optional<ConstexprType>>::value));
235  // direct initialization
236  constexpr optional<ConstexprType> opt2{2};
237  static_assert(opt2, "");
238  static_assert(2 == opt2->x, "");
239  REQUIRE_FALSE((std::is_convertible<int, optional<ConstexprType>>::value));
240 
241  // this invokes optional<int>::optional(int&&)
242  // NOTE: this has different behavior than assignment, e.g.
243  // "opt3 = {};" clears the optional rather than setting the value to 0
244  constexpr optional<int> opt3({});
245  static_assert(opt3, "");
246  static_assert(*opt3 == 0, "");
247 
248  // this invokes the move constructor with a default constructed optional
249  // because non-template function is a better match than template function.
250  optional<ConstexprType> opt4({});
251  REQUIRE_FALSE(!!opt4);
252  }
253 
254  struct Implicit {};
255 
256  struct Explicit {};
257 
258  struct Convert {
259  Convert(const Implicit&) // NOLINT(runtime/explicit)
260  : implicit(true), move(false) {}
261  Convert(Implicit&&) // NOLINT(runtime/explicit)
262  : implicit(true), move(true) {}
263  explicit Convert(const Explicit&) : implicit(false), move(false) {}
264  explicit Convert(Explicit&&) : implicit(false), move(true) {}
265 
266  bool implicit;
267  bool move;
268  };
269 
270  struct ConvertFromOptional {
271  ConvertFromOptional(const Implicit&) // NOLINT(runtime/explicit)
272  : implicit(true), move(false), from_optional(false) {}
273  ConvertFromOptional(Implicit&&) // NOLINT(runtime/explicit)
274  : implicit(true), move(true), from_optional(false) {}
275  ConvertFromOptional(const optional<Implicit>&) // NOLINT(runtime/explicit)
276  : implicit(true), move(false), from_optional(true) {}
277  ConvertFromOptional(optional<Implicit>&&) // NOLINT(runtime/explicit)
278  : implicit(true), move(true), from_optional(true) {}
279  explicit ConvertFromOptional(const Explicit&)
280  : implicit(false), move(false), from_optional(false) {}
281  explicit ConvertFromOptional(Explicit&&)
282  : implicit(false), move(true), from_optional(false) {}
283  explicit ConvertFromOptional(const optional<Explicit>&)
284  : implicit(false), move(false), from_optional(true) {}
285  explicit ConvertFromOptional(optional<Explicit>&&)
286  : implicit(false), move(true), from_optional(true) {}
287 
288  bool implicit;
289  bool move;
290  bool from_optional;
291  };
292 
293  SECTION("ConvertingConstructor")
294  {
295  optional<Implicit> i_empty;
296  optional<Implicit> i(in_place);
297  optional<Explicit> e_empty;
298  optional<Explicit> e(in_place);
299  {
300  // implicitly constructing optional<Convert> from optional<Implicit>
301  optional<Convert> empty = i_empty;
302  REQUIRE_FALSE(!!empty);
303  optional<Convert> opt_copy = i;
304  REQUIRE(!!opt_copy);
305  REQUIRE(opt_copy->implicit);
306  REQUIRE_FALSE(opt_copy->move);
307  optional<Convert> opt_move = optional<Implicit>(in_place);
308  REQUIRE(!!opt_move);
309  REQUIRE(opt_move->implicit);
310  REQUIRE(opt_move->move);
311  }
312  {
313  // explicitly constructing optional<Convert> from optional<Explicit>
314  optional<Convert> empty(e_empty);
315  REQUIRE_FALSE(!!empty);
316  optional<Convert> opt_copy(e);
317  REQUIRE(!!opt_copy);
318  REQUIRE_FALSE(opt_copy->implicit);
319  REQUIRE_FALSE(opt_copy->move);
320  REQUIRE_FALSE((std::is_convertible<const optional<Explicit>&,
321  optional<Convert>>::value));
322  optional<Convert> opt_move{optional<Explicit>(in_place)};
323  REQUIRE(!!opt_move);
324  REQUIRE_FALSE(opt_move->implicit);
325  REQUIRE(opt_move->move);
326  REQUIRE_FALSE(
327  (std::is_convertible<optional<Explicit>&&, optional<Convert>>::value));
328  }
329  {
330  // implicitly constructing optional<ConvertFromOptional> from
331  // optional<Implicit> via ConvertFromOptional(optional<Implicit>&&)
332  // check that ConvertFromOptional(Implicit&&) is NOT called
333  static_assert(
334  gtl::internal_optional::is_constructible_convertible_from_optional<
335  ConvertFromOptional, Implicit>::value,
336  "");
337  optional<ConvertFromOptional> opt0 = i_empty;
338  REQUIRE(!!opt0);
339  REQUIRE(opt0->implicit);
340  REQUIRE_FALSE(opt0->move);
341  REQUIRE(opt0->from_optional);
342  optional<ConvertFromOptional> opt1 = optional<Implicit>();
343  REQUIRE(!!opt1);
344  REQUIRE(opt1->implicit);
345  REQUIRE(opt1->move);
346  REQUIRE(opt1->from_optional);
347  }
348  {
349  // implicitly constructing optional<ConvertFromOptional> from
350  // optional<Explicit> via ConvertFromOptional(optional<Explicit>&&)
351  // check that ConvertFromOptional(Explicit&&) is NOT called
352  optional<ConvertFromOptional> opt0(e_empty);
353  REQUIRE(!!opt0);
354  REQUIRE_FALSE(opt0->implicit);
355  REQUIRE_FALSE(opt0->move);
356  REQUIRE(opt0->from_optional);
357  REQUIRE_FALSE((std::is_convertible<const optional<Explicit>&,
358  optional<ConvertFromOptional>>::value));
359  optional<ConvertFromOptional> opt1{optional<Explicit>()};
360  REQUIRE(!!opt1);
361  REQUIRE_FALSE(opt1->implicit);
362  REQUIRE(opt1->move);
363  REQUIRE(opt1->from_optional);
364  REQUIRE_FALSE((std::is_convertible<optional<Explicit>&&,
365  optional<ConvertFromOptional>>::value));
366  }
367  }
368 
369  SECTION("StructorBasic")
370  {
371  StructorListener listener;
372  Listenable::listener = &listener;
373  {
374  optional<Listenable> empty;
375  REQUIRE_FALSE(!!empty);
376  optional<Listenable> opt0(in_place);
377  REQUIRE(!!opt0);
378  optional<Listenable> opt1(in_place, 1);
379  REQUIRE(!!opt1);
380  optional<Listenable> opt2(in_place, 1, 2);
381  REQUIRE(!!opt2);
382  }
383  REQUIRE(1 == listener.construct0);
384  REQUIRE(1 == listener.construct1);
385  REQUIRE(1 == listener.construct2);
386  REQUIRE(3 == listener.destruct);
387  }
388 
389  SECTION("CopyMoveStructor")
390  {
391  StructorListener listener;
392  Listenable::listener = &listener;
393  optional<Listenable> original(in_place);
394  REQUIRE(1 == listener.construct0);
395  REQUIRE(0 == listener.copy);
396  REQUIRE(0 == listener.move);
397  optional<Listenable> copy(original);
398  REQUIRE(1 == listener.construct0);
399  REQUIRE(1 == listener.copy);
400  REQUIRE(0 == listener.move);
401  optional<Listenable> move(std::move(original));
402  REQUIRE(1 == listener.construct0);
403  REQUIRE(1 == listener.copy);
404  REQUIRE(1 == listener.move);
405  }
406 
407  SECTION("ListInit")
408  {
409  StructorListener listener;
410  Listenable::listener = &listener;
411  optional<Listenable> listinit1(in_place, {1});
412  optional<Listenable> listinit2(in_place, {1, 2});
413  REQUIRE(2 == listener.listinit);
414  }
415 
416  SECTION("AssignFromNullopt")
417  {
418  optional<int> opt(1);
419  opt = nullopt;
420  REQUIRE_FALSE(!!opt);
421 
422  StructorListener listener;
423  Listenable::listener = &listener;
424  optional<Listenable> opt1(in_place);
425  opt1 = nullopt;
426  REQUIRE_FALSE(opt1);
427  REQUIRE(1 == listener.construct0);
428  REQUIRE(1 == listener.destruct);
429 
430  REQUIRE((std::is_nothrow_assignable<optional<int>, nullopt_t>::value));
431  REQUIRE(
432  (std::is_nothrow_assignable<optional<Listenable>, nullopt_t>::value));
433  }
434 
435  SECTION("CopyAssignment")
436  {
437  const optional<int> empty, opt1 = 1, opt2 = 2;
438  optional<int> empty_to_opt1, opt1_to_opt2, opt2_to_empty;
439 
440  REQUIRE_FALSE(!!empty_to_opt1);
441  empty_to_opt1 = empty;
442  REQUIRE_FALSE(!!empty_to_opt1);
443  empty_to_opt1 = opt1;
444  REQUIRE(!!empty_to_opt1);
445  REQUIRE(1 == empty_to_opt1.value());
446 
447  REQUIRE_FALSE(!!opt1_to_opt2);
448  opt1_to_opt2 = opt1;
449  REQUIRE(!!opt1_to_opt2);
450  REQUIRE(1 == opt1_to_opt2.value());
451  opt1_to_opt2 = opt2;
452  REQUIRE(!!opt1_to_opt2);
453  REQUIRE(2 == opt1_to_opt2.value());
454 
455  REQUIRE_FALSE(!!opt2_to_empty);
456  opt2_to_empty = opt2;
457  REQUIRE(!!opt2_to_empty);
458  REQUIRE(2 == opt2_to_empty.value());
459  opt2_to_empty = empty;
460  REQUIRE_FALSE(!!opt2_to_empty);
461 
462  REQUIRE(std::is_copy_assignable<optional<Copyable>>::value);
463  REQUIRE_FALSE(std::is_copy_assignable<optional<MoveableThrow>>::value);
464  REQUIRE_FALSE(std::is_copy_assignable<optional<MoveableNoThrow>>::value);
465  REQUIRE_FALSE(std::is_copy_assignable<optional<NonMovable>>::value);
466  }
467 
468  SECTION("MoveAssignment")
469  {
470  StructorListener listener;
471  Listenable::listener = &listener;
472 
473  optional<Listenable> empty1, empty2, set1(in_place), set2(in_place);
474  REQUIRE(2 == listener.construct0);
475  optional<Listenable> empty_to_empty, empty_to_set, set_to_empty(in_place),
476  set_to_set(in_place);
477  REQUIRE(4 == listener.construct0);
478  empty_to_empty = std::move(empty1);
479  empty_to_set = std::move(set1);
480  set_to_empty = std::move(empty2);
481  set_to_set = std::move(set2);
482  REQUIRE(0 == listener.copy);
483  REQUIRE(1 == listener.move);
484  REQUIRE(1 == listener.destruct);
485  REQUIRE(1 == listener.move_assign);
486 
487  REQUIRE(std::is_move_assignable<optional<Copyable>>::value);
488  REQUIRE(std::is_move_assignable<optional<MoveableThrow>>::value);
489  REQUIRE(std::is_move_assignable<optional<MoveableNoThrow>>::value);
490  REQUIRE_FALSE(std::is_move_assignable<optional<NonMovable>>::value);
491 
492  REQUIRE_FALSE(std::is_nothrow_move_assignable<optional<MoveableThrow>>::value);
493  REQUIRE(
494  std::is_nothrow_move_assignable<optional<MoveableNoThrow>>::value);
495  }
496 
497  struct NoConvertToOptional {
498  // disable implicit conversion from const NoConvertToOptional&
499  // to optional<NoConvertToOptional>.
500  NoConvertToOptional(const NoConvertToOptional&) = delete;
501  };
502 
503  struct CopyConvert {
504  CopyConvert(const NoConvertToOptional&);
505  CopyConvert& operator=(const CopyConvert&) = delete;
506  CopyConvert& operator=(const NoConvertToOptional&);
507  };
508 
509  struct CopyConvertFromOptional {
510  CopyConvertFromOptional(const NoConvertToOptional&);
511  CopyConvertFromOptional(const optional<NoConvertToOptional>&);
512  CopyConvertFromOptional& operator=(const CopyConvertFromOptional&) = delete;
513  CopyConvertFromOptional& operator=(const NoConvertToOptional&);
514  CopyConvertFromOptional& operator=(const optional<NoConvertToOptional>&);
515  };
516 
517  struct MoveConvert {
518  MoveConvert(NoConvertToOptional&&);
519  MoveConvert& operator=(const MoveConvert&) = delete;
520  MoveConvert& operator=(NoConvertToOptional&&);
521  };
522 
523  struct MoveConvertFromOptional {
524  MoveConvertFromOptional(NoConvertToOptional&&);
525  MoveConvertFromOptional(optional<NoConvertToOptional>&&);
526  MoveConvertFromOptional& operator=(const MoveConvertFromOptional&) = delete;
527  MoveConvertFromOptional& operator=(NoConvertToOptional&&);
528  MoveConvertFromOptional& operator=(optional<NoConvertToOptional>&&);
529  };
530 
531 // template <class U = T> optional<T>& operator=(U&& v);
532  SECTION("ValueAssignment")
533  {
534  optional<int> opt;
535  REQUIRE_FALSE(!!opt);
536  opt = 42;
537  REQUIRE(!!opt);
538  REQUIRE(42 == opt.value());
539  opt = nullopt;
540  REQUIRE_FALSE(!!opt);
541  opt = 42;
542  REQUIRE(!!opt);
543  REQUIRE(42 == opt.value());
544  opt = 43;
545  REQUIRE(!!opt);
546  REQUIRE(43 == opt.value());
547  opt = {}; // this should clear optional
548  REQUIRE_FALSE(!!opt);
549 
550  opt = {44};
551  REQUIRE(!!opt);
552  REQUIRE(44 == opt.value());
553 
554  // U = const NoConvertToOptional&
555  REQUIRE((std::is_assignable<optional<CopyConvert>&,
556  const NoConvertToOptional&>::value));
557  // U = const optional<NoConvertToOptional>&
558  REQUIRE((std::is_assignable<optional<CopyConvertFromOptional>&,
559  const NoConvertToOptional&>::value));
560  // U = const NoConvertToOptional& triggers SFINAE because
561  // std::is_constructible_v<MoveConvert, const NoConvertToOptional&> is false
562  REQUIRE_FALSE((std::is_assignable<optional<MoveConvert>&,
563  const NoConvertToOptional&>::value));
564  // U = NoConvertToOptional
565  REQUIRE((std::is_assignable<optional<MoveConvert>&,
566  NoConvertToOptional&&>::value));
567  // U = const NoConvertToOptional& triggers SFINAE because
568  // std::is_constructible_v<MoveConvertFromOptional, const
569  // NoConvertToOptional&> is false
570  REQUIRE_FALSE((std::is_assignable<optional<MoveConvertFromOptional>&,
571  const NoConvertToOptional&>::value));
572  // U = NoConvertToOptional
573  REQUIRE((std::is_assignable<optional<MoveConvertFromOptional>&,
574  NoConvertToOptional&&>::value));
575  // U = const optional<NoConvertToOptional>&
576  REQUIRE(
577  (std::is_assignable<optional<CopyConvertFromOptional>&,
578  const optional<NoConvertToOptional>&>::value));
579  // U = optional<NoConvertToOptional>
580  REQUIRE((std::is_assignable<optional<MoveConvertFromOptional>&,
581  optional<NoConvertToOptional>&&>::value));
582  }
583 
584 // template <class U> optional<T>& operator=(const optional<U>& rhs);
585 // template <class U> optional<T>& operator=(optional<U>&& rhs);
586  SECTION("ConvertingAssignment")
587  {
588  optional<int> opt_i;
589  optional<char> opt_c('c');
590  opt_i = opt_c;
591  REQUIRE(!!opt_i);
592  REQUIRE(*opt_c == *opt_i);
593  opt_i = optional<char>();
594  REQUIRE_FALSE(!!opt_i);
595  opt_i = optional<char>('d');
596  REQUIRE(!!opt_i);
597  REQUIRE('d' == *opt_i);
598 
599  optional<std::string> opt_str;
600  optional<const char *> opt_cstr("abc");
601  opt_str = opt_cstr;
602  REQUIRE(!!opt_str);
603  REQUIRE(std::string("abc") == *opt_str);
604  opt_str = optional<const char *>();
605  REQUIRE_FALSE(!!opt_str);
606  opt_str = optional<const char *>("def");
607  REQUIRE(!!opt_str);
608  REQUIRE(std::string("def") == *opt_str);
609 
610  // operator=(const optional<U>&) with U = NoConvertToOptional
611  REQUIRE(
612  (std::is_assignable<optional<CopyConvert>,
613  const optional<NoConvertToOptional>&>::value));
614  // operator=(const optional<U>&) with U = NoConvertToOptional
615  // triggers SFINAE because
616  // std::is_constructible_v<MoveConvert, const NoConvertToOptional&> is false
617  REQUIRE_FALSE(
618  (std::is_assignable<optional<MoveConvert>&,
619  const optional<NoConvertToOptional>&>::value));
620  // operator=(optional<U>&&) with U = NoConvertToOptional
621  REQUIRE((std::is_assignable<optional<MoveConvert>&,
622  optional<NoConvertToOptional>&&>::value));
623  // operator=(const optional<U>&) with U = NoConvertToOptional triggers SFINAE
624  // because std::is_constructible_v<MoveConvertFromOptional,
625  // const NoConvertToOptional&> is false.
626  // operator=(U&&) with U = const optional<NoConverToOptional>& triggers SFINAE
627  // because std::is_constructible<MoveConvertFromOptional,
628  // optional<NoConvertToOptional>&&> is true.
629  REQUIRE_FALSE(
630  (std::is_assignable<optional<MoveConvertFromOptional>&,
631  const optional<NoConvertToOptional>&>::value));
632  }
633 
634  SECTION("ResetAndHasValue")
635  {
636  StructorListener listener;
637  Listenable::listener = &listener;
638  optional<Listenable> opt;
639  REQUIRE_FALSE(!!opt);
640  REQUIRE_FALSE(opt.has_value());
641  opt.emplace();
642  REQUIRE(!!opt);
643  REQUIRE(opt.has_value());
644  opt.reset();
645  REQUIRE_FALSE(!!opt);
646  REQUIRE_FALSE(opt.has_value());
647  REQUIRE(1 == listener.destruct);
648  opt.reset();
649  REQUIRE_FALSE(!!opt);
650  REQUIRE_FALSE(opt.has_value());
651 
652  constexpr optional<int> empty;
653  static_assert(!empty.has_value(), "");
654  constexpr optional<int> nonempty(1);
655  static_assert(nonempty.has_value(), "");
656  }
657 
658  SECTION("Emplace")
659  {
660  StructorListener listener;
661  Listenable::listener = &listener;
662  optional<Listenable> opt;
663  REQUIRE_FALSE(!!opt);
664  opt.emplace(1);
665  REQUIRE(!!opt);
666  opt.emplace(1, 2);
667  REQUIRE(1 == listener.construct1);
668  REQUIRE(1 == listener.construct2);
669  REQUIRE(1 == listener.destruct);
670  }
671 
672  SECTION("ListEmplace")
673  {
674  StructorListener listener;
675  Listenable::listener = &listener;
676  optional<Listenable> opt;
677  REQUIRE_FALSE(!!opt);
678  opt.emplace({1});
679  REQUIRE(!!opt);
680  opt.emplace({1, 2});
681  REQUIRE(2 == listener.listinit);
682  REQUIRE(1 == listener.destruct);
683  }
684 
685  SECTION("Swap")
686  {
687  optional<int> opt_empty, opt1 = 1, opt2 = 2;
688  REQUIRE_FALSE(!!opt_empty);
689  REQUIRE(!!opt1);
690  REQUIRE(1 == opt1.value());
691  REQUIRE(!!opt2);
692  REQUIRE(2 == opt2.value());
693  swap(opt_empty, opt1);
694  REQUIRE_FALSE(!!opt1);
695  REQUIRE(!!opt_empty);
696  REQUIRE(1 == opt_empty.value());
697  REQUIRE(!!opt2);
698  REQUIRE(2 == opt2.value());
699  swap(opt_empty, opt1);
700  REQUIRE_FALSE(!!opt_empty);
701  REQUIRE(!!opt1);
702  REQUIRE(1 == opt1.value());
703  REQUIRE(!!opt2);
704  REQUIRE(2 == opt2.value());
705  swap(opt1, opt2);
706  REQUIRE_FALSE(!!opt_empty);
707  REQUIRE(!!opt1);
708  REQUIRE(2 == opt1.value());
709  REQUIRE(!!opt2);
710  REQUIRE(1 == opt2.value());
711 
712  REQUIRE(noexcept(opt1.swap(opt2)));
713  REQUIRE(noexcept(swap(opt1, opt2)));
714  }
715 
716  SECTION("PointerStuff")
717  {
718  optional<std::string> opt(in_place, "foo");
719  REQUIRE("foo" == *opt);
720  const auto& opt_const = opt;
721  REQUIRE("foo" == *opt_const);
722  REQUIRE(opt->size() == 3);
723  REQUIRE(opt_const->size() == 3);
724 
725  constexpr optional<ConstexprType> opt1(1);
726  static_assert(opt1->x == 1, "");
727  }
728 
729 // gcc has a bug pre 4.9 where it doesn't do correct overload resolution
730 // between rvalue reference qualified member methods. Skip that test to make
731 // the build green again when using the old compiler.
732 #if defined(__GNUC__) && !defined(__clang__)
733 #if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 9)
734 #define SKIP_OVERLOAD_TEST_DUE_TO_GCC_BUG
735 #endif
736 #endif
737 
738  SECTION("Value")
739  {
740  using O = optional<std::string>;
741  using CO = const optional<std::string>;
742  O lvalue(in_place, "lvalue");
743  CO clvalue(in_place, "clvalue");
744  REQUIRE("lvalue" == lvalue.value());
745  REQUIRE("clvalue" == clvalue.value());
746  REQUIRE("xvalue" == O(in_place, "xvalue").value());
747 #ifndef SKIP_OVERLOAD_TEST_DUE_TO_GCC_BUG
748  REQUIRE("cxvalue" == CO(in_place, "cxvalue").value());
749  REQUIRE("&" == TypeQuals(lvalue.value()));
750  REQUIRE("c&" == TypeQuals(clvalue.value()));
751  REQUIRE("&&" == TypeQuals(O(in_place, "xvalue").value()));
752  REQUIRE("c&&" == TypeQuals(CO(in_place, "cxvalue").value()));
753 #endif
754  }
755 
756  SECTION("DerefOperator")
757  {
758  using O = optional<std::string>;
759  using CO = const optional<std::string>;
760  O lvalue(in_place, "lvalue");
761  CO clvalue(in_place, "clvalue");
762  REQUIRE("lvalue" == *lvalue);
763  REQUIRE("clvalue" == *clvalue);
764  REQUIRE("xvalue" == *O(in_place, "xvalue"));
765 #ifndef SKIP_OVERLOAD_TEST_DUE_TO_GCC_BUG
766  REQUIRE("cxvalue" == *CO(in_place, "cxvalue"));
767  REQUIRE("&" == TypeQuals(*lvalue));
768  REQUIRE("c&" == TypeQuals(*clvalue));
769  REQUIRE("&&" == TypeQuals(*O(in_place, "xvalue")));
770  REQUIRE("c&&" == TypeQuals(*CO(in_place, "cxvalue")));
771 #endif
772 
773  constexpr optional<int> opt1(1);
774  static_assert(*opt1 == 1, "");
775 
776 #if !defined(SKIP_CONSTEXPR_TEST_DUE_TO_CLANG_BUG) && \
777  !defined(SKIP_OVERLOAD_TEST_DUE_TO_GCC_BUG)
778  using COI = const optional<int>;
779  static_assert(*COI(2) == 2, "");
780 #endif
781  }
782 
783  SECTION("ValueOr")
784  {
785  optional<double> opt_empty, opt_set = 1.2;
786  REQUIRE(42.0 == opt_empty.value_or(42));
787  REQUIRE(1.2 == opt_set.value_or(42));
788  REQUIRE(42.0 == optional<double>().value_or(42));
789  REQUIRE(1.2 == optional<double>(1.2).value_or(42));
790 
791 #ifndef SKIP_CONSTEXPR_TEST_DUE_TO_CLANG_BUG
792  constexpr optional<double> copt_empty;
793  static_assert(42.0 == copt_empty.value_or(42), "");
794 
795  constexpr optional<double> copt_set = {1.2};
796  static_assert(1.2 == copt_set.value_or(42), "");
797 
798  using COD = const optional<double>;
799  static_assert(42.0 == COD().value_or(42), "");
800  static_assert(1.2 == COD(1.2).value_or(42), "");
801 #endif
802  }
803 
804 // make_optional cannot be constexpr until C++17
805  SECTION("make_optional")
806  {
807  auto opt_int = make_optional(42);
808  REQUIRE((std::is_same<decltype(opt_int), optional<int>>::value));
809  REQUIRE(42 == opt_int);
810 
811  StructorListener listener;
812  Listenable::listener = &listener;
813 
814  optional<Listenable> opt0 = make_optional<Listenable>();
815  REQUIRE(1 == listener.construct0);
816  optional<Listenable> opt1 = make_optional<Listenable>(1);
817  REQUIRE(1 == listener.construct1);
818  optional<Listenable> opt2 = make_optional<Listenable>(1, 2);
819  REQUIRE(1 == listener.construct2);
820  optional<Listenable> opt3 = make_optional<Listenable>({1});
821  optional<Listenable> opt4 = make_optional<Listenable>({1, 2});
822  REQUIRE(2 == listener.listinit);
823  }
824 
825  SECTION("Comparisons")
826  {
827  optional<int> ae, be, a2 = 2, b2 = 2, a4 = 4, b4 = 4;
828 
829 #define optionalTest_Comparisons_EXPECT_LESS(x, y) \
830  REQUIRE_FALSE((x) == (y)); \
831  REQUIRE((x) != (y)); \
832  REQUIRE((x) < (y)); \
833  REQUIRE_FALSE((x) > (y)); \
834  REQUIRE((x) <= (y)); \
835  REQUIRE_FALSE((x) >= (y));
836 
837 #define optionalTest_Comparisons_EXPECT_SAME(x, y) \
838  REQUIRE((x) == (y)); \
839  REQUIRE_FALSE((x) != (y)); \
840  REQUIRE_FALSE((x) < (y)); \
841  REQUIRE_FALSE((x) > (y)); \
842  REQUIRE((x) <= (y)); \
843  REQUIRE((x) >= (y));
844 
845 #define optionalTest_Comparisons_EXPECT_GREATER(x, y) \
846  REQUIRE_FALSE((x) == (y)); \
847  REQUIRE((x) != (y)); \
848  REQUIRE_FALSE((x) < (y)); \
849  REQUIRE((x) > (y)); \
850  REQUIRE_FALSE((x) <= (y)); \
851  REQUIRE((x) >= (y));
852 
853  // LHS: nullopt, ae, a2, 3, a4
854  // RHS: nullopt, be, b2, 3, b4
855 
856  // optionalTest_Comparisons_EXPECT_NOT_TO_WORK(nullopt,nullopt);
857  optionalTest_Comparisons_EXPECT_SAME(nullopt, be);
858  optionalTest_Comparisons_EXPECT_LESS(nullopt, b2);
859  // optionalTest_Comparisons_EXPECT_NOT_TO_WORK(nullopt,3);
860  optionalTest_Comparisons_EXPECT_LESS(nullopt, b4);
861 
862  optionalTest_Comparisons_EXPECT_SAME(ae, nullopt);
863  optionalTest_Comparisons_EXPECT_SAME(ae, be);
864  optionalTest_Comparisons_EXPECT_LESS(ae, b2);
865  optionalTest_Comparisons_EXPECT_LESS(ae, 3);
866  optionalTest_Comparisons_EXPECT_LESS(ae, b4);
867 
868  optionalTest_Comparisons_EXPECT_GREATER(a2, nullopt);
869  optionalTest_Comparisons_EXPECT_GREATER(a2, be);
870  optionalTest_Comparisons_EXPECT_SAME(a2, b2);
871  optionalTest_Comparisons_EXPECT_LESS(a2, 3);
872  optionalTest_Comparisons_EXPECT_LESS(a2, b4);
873 
874  // optionalTest_Comparisons_EXPECT_NOT_TO_WORK(3,nullopt);
875  optionalTest_Comparisons_EXPECT_GREATER(3, be);
876  optionalTest_Comparisons_EXPECT_GREATER(3, b2);
877  optionalTest_Comparisons_EXPECT_SAME(3, 3);
878  optionalTest_Comparisons_EXPECT_LESS(3, b4);
879 
880  optionalTest_Comparisons_EXPECT_GREATER(a4, nullopt);
881  optionalTest_Comparisons_EXPECT_GREATER(a4, be);
882  optionalTest_Comparisons_EXPECT_GREATER(a4, b2);
883  optionalTest_Comparisons_EXPECT_GREATER(a4, 3);
884  optionalTest_Comparisons_EXPECT_SAME(a4, b4);
885  }
886 
887  SECTION("SwapRegression")
888  {
889  StructorListener listener;
890  Listenable::listener = &listener;
891 
892  {
893  optional<Listenable> a;
894  optional<Listenable> b(in_place);
895  a.swap(b);
896  }
897 
898  REQUIRE(1 == listener.construct0);
899  REQUIRE(1 == listener.move);
900  REQUIRE(2 == listener.destruct);
901 
902  {
903  optional<Listenable> a(in_place);
904  optional<Listenable> b;
905  a.swap(b);
906  }
907 
908  REQUIRE(2 == listener.construct0);
909  REQUIRE(2 == listener.move);
910  REQUIRE(4 == listener.destruct);
911  }
912 
913  SECTION("BigStringLeakCheck")
914  {
915  constexpr size_t n = 1 << 16;
916 
917  using OS = optional<std::string>;
918 
919  OS a;
920  OS b = nullopt;
921  OS c = std::string(n, 'c');
922  std::string sd(n, 'd');
923  OS d = sd;
924  OS e(in_place, n, 'e');
925  OS f;
926  f.emplace(n, 'f');
927 
928  OS ca(a);
929  OS cb(b);
930  OS cc(c);
931  OS cd(d);
932  OS ce(e);
933 
934  OS oa;
935  OS ob = nullopt;
936  OS oc = std::string(n, 'c');
937  std::string sod(n, 'd');
938  OS od = sod;
939  OS oe(in_place, n, 'e');
940  OS of;
941  of.emplace(n, 'f');
942 
943  OS ma(std::move(oa));
944  OS mb(std::move(ob));
945  OS mc(std::move(oc));
946  OS md(std::move(od));
947  OS me(std::move(oe));
948  OS mf(std::move(of));
949 
950  OS aa1;
951  OS ab1 = nullopt;
952  OS ac1 = std::string(n, 'c');
953  std::string sad1(n, 'd');
954  OS ad1 = sad1;
955  OS ae1(in_place, n, 'e');
956  OS af1;
957  af1.emplace(n, 'f');
958 
959  OS aa2;
960  OS ab2 = nullopt;
961  OS ac2 = std::string(n, 'c');
962  std::string sad2(n, 'd');
963  OS ad2 = sad2;
964  OS ae2(in_place, n, 'e');
965  OS af2;
966  af2.emplace(n, 'f');
967 
968  aa1 = af2;
969  ab1 = ae2;
970  ac1 = ad2;
971  ad1 = ac2;
972  ae1 = ab2;
973  af1 = aa2;
974 
975  OS aa3;
976  OS ab3 = nullopt;
977  OS ac3 = std::string(n, 'c');
978  std::string sad3(n, 'd');
979  OS ad3 = sad3;
980  OS ae3(in_place, n, 'e');
981  OS af3;
982  af3.emplace(n, 'f');
983 
984  aa3 = nullopt;
985  ab3 = nullopt;
986  ac3 = nullopt;
987  ad3 = nullopt;
988  ae3 = nullopt;
989  af3 = nullopt;
990 
991  OS aa4;
992  OS ab4 = nullopt;
993  OS ac4 = std::string(n, 'c');
994  std::string sad4(n, 'd');
995  OS ad4 = sad4;
996  OS ae4(in_place, n, 'e');
997  OS af4;
998  af4.emplace(n, 'f');
999 
1000  aa4 = OS(in_place, n, 'a');
1001  ab4 = OS(in_place, n, 'b');
1002  ac4 = OS(in_place, n, 'c');
1003  ad4 = OS(in_place, n, 'd');
1004  ae4 = OS(in_place, n, 'e');
1005  af4 = OS(in_place, n, 'f');
1006 
1007  OS aa5;
1008  OS ab5 = nullopt;
1009  OS ac5 = std::string(n, 'c');
1010  std::string sad5(n, 'd');
1011  OS ad5 = sad5;
1012  OS ae5(in_place, n, 'e');
1013  OS af5;
1014  af5.emplace(n, 'f');
1015 
1016  std::string saa5(n, 'a');
1017  std::string sab5(n, 'a');
1018  std::string sac5(n, 'a');
1019  std::string sad52(n, 'a');
1020  std::string sae5(n, 'a');
1021  std::string saf5(n, 'a');
1022 
1023  aa5 = saa5;
1024  ab5 = sab5;
1025  ac5 = sac5;
1026  ad5 = sad52;
1027  ae5 = sae5;
1028  af5 = saf5;
1029 
1030  OS aa6;
1031  OS ab6 = nullopt;
1032  OS ac6 = std::string(n, 'c');
1033  std::string sad6(n, 'd');
1034  OS ad6 = sad6;
1035  OS ae6(in_place, n, 'e');
1036  OS af6;
1037  af6.emplace(n, 'f');
1038 
1039  aa6 = std::string(n, 'a');
1040  ab6 = std::string(n, 'b');
1041  ac6 = std::string(n, 'c');
1042  ad6 = std::string(n, 'd');
1043  ae6 = std::string(n, 'e');
1044  af6 = std::string(n, 'f');
1045 
1046  OS aa7;
1047  OS ab7 = nullopt;
1048  OS ac7 = std::string(n, 'c');
1049  std::string sad7(n, 'd');
1050  OS ad7 = sad7;
1051  OS ae7(in_place, n, 'e');
1052  OS af7;
1053  af7.emplace(n, 'f');
1054 
1055  aa7.emplace(n, 'A');
1056  ab7.emplace(n, 'B');
1057  ac7.emplace(n, 'C');
1058  ad7.emplace(n, 'D');
1059  ae7.emplace(n, 'E');
1060  af7.emplace(n, 'F');
1061  }
1062 
1063  SECTION("MoveAssignRegression")
1064  {
1065  StructorListener listener;
1066  Listenable::listener = &listener;
1067 
1068  {
1069  optional<Listenable> a;
1070  Listenable b;
1071  a = std::move(b);
1072  }
1073 
1074  REQUIRE(1 == listener.construct0);
1075  REQUIRE(1 == listener.move);
1076  REQUIRE(2 == listener.destruct);
1077  }
1078 
1079  SECTION("ValueType")
1080  {
1081  REQUIRE((std::is_same<optional<int>::value_type, int>::value));
1082  REQUIRE((std::is_same<optional<std::string>::value_type, std::string>::value));
1083  REQUIRE_FALSE((std::is_same<optional<int>::value_type, nullopt_t>::value));
1084  }
1085 
1086  SECTION("Hash")
1087  {
1088  std::hash<optional<int>> hash;
1089  std::set<size_t> hashcodes;
1090  hashcodes.insert(hash(nullopt));
1091  for (int i = 0; i < 100; ++i) {
1092  hashcodes.insert(hash(i));
1093  }
1094  REQUIRE(hashcodes.size() > 90);
1095  }
1096 
1097  struct MoveMeNoThrow {
1098  MoveMeNoThrow() : x(0) {}
1099  MoveMeNoThrow(const MoveMeNoThrow& other) : x(other.x) {
1100  LOG(fatal) << "Should not be called.";
1101  }
1102  MoveMeNoThrow(MoveMeNoThrow&& other) noexcept : x(other.x) {}
1103  int x;
1104  };
1105 
1106  struct MoveMeThrow {
1107  MoveMeThrow() : x(0) {}
1108  MoveMeThrow(const MoveMeThrow& other) : x(other.x) {}
1109  MoveMeThrow(MoveMeThrow&& other) : x(other.x) {}
1110  int x;
1111  };
1112 
1113  SECTION("NoExcept")
1114  {
1115  static_assert(
1116  std::is_nothrow_move_constructible<optional<MoveMeNoThrow>>::value, "");
1117  static_assert(
1118  !std::is_nothrow_move_constructible<optional<MoveMeThrow>>::value, "");
1119  std::vector<optional<MoveMeNoThrow>> v;
1120  for (int i = 0; i < 10; ++i)
1121  v.emplace_back();
1122  }
1123 }
1124 
1125 } // namespace
1126 } // namespace momemta
Definition: Graph.h:21