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