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