proxygen
OptionalTest.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2012-present Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <folly/Optional.h>
18 #include <folly/Portability.h>
21 
22 #include <algorithm>
23 #include <initializer_list>
24 #include <iomanip>
25 #include <memory>
26 #include <string>
27 #include <tuple>
28 #include <type_traits>
29 #include <unordered_map>
30 #include <vector>
31 
32 #include <boost/optional.hpp>
33 
34 using std::shared_ptr;
35 using std::unique_ptr;
36 
37 namespace folly {
38 
39 namespace {
40 
41 template <class V>
42 std::ostream& operator<<(std::ostream& os, const Optional<V>& v) {
43  if (v) {
44  os << "Optional(" << v.value() << ')';
45  } else {
46  os << "None";
47  }
48  return os;
49 }
50 
51 struct NoDefault {
52  NoDefault(int, int) {}
53  char a, b, c;
54 };
55 
56 } // namespace
57 
58 static_assert(sizeof(Optional<char>) == 2, "");
59 static_assert(sizeof(Optional<int>) == 8, "");
60 static_assert(sizeof(Optional<NoDefault>) == 4, "");
61 static_assert(sizeof(Optional<char>) == sizeof(boost::optional<char>), "");
62 static_assert(sizeof(Optional<short>) == sizeof(boost::optional<short>), "");
63 static_assert(sizeof(Optional<int>) == sizeof(boost::optional<int>), "");
64 static_assert(sizeof(Optional<double>) == sizeof(boost::optional<double>), "");
65 
68  EXPECT_FALSE(x);
69  x.emplace(4, 5);
70  EXPECT_TRUE(bool(x));
71  x.clear();
72  EXPECT_FALSE(x);
73 }
74 
77  auto& values1 = opt.emplace(3, 4);
78  EXPECT_THAT(values1, testing::ElementsAre(4, 4, 4));
79  auto& values2 = opt.emplace(2, 5);
80  EXPECT_THAT(values2, testing::ElementsAre(5, 5));
81 }
82 
83 TEST(Optional, EmplaceInitializerList) {
85  auto& values1 = opt.emplace({3, 4, 5});
86  EXPECT_THAT(values1, testing::ElementsAre(3, 4, 5));
87  auto& values2 = opt.emplace({4, 5, 6});
88  EXPECT_THAT(values2, testing::ElementsAre(4, 5, 6));
89 }
90 
91 TEST(Optional, Reset) {
92  Optional<int> opt(3);
93  opt.reset();
94  EXPECT_FALSE(opt);
95 }
96 
97 TEST(Optional, String) {
98  Optional<std::string> maybeString;
99  EXPECT_FALSE(maybeString);
100  maybeString = "hello";
101  EXPECT_TRUE(bool(maybeString));
102 }
103 
105  { // default construct
107  EXPECT_FALSE(bool(opt));
108  opt.emplace(4);
109  EXPECT_EQ(*opt, 4);
110  opt.emplace(5);
111  EXPECT_EQ(*opt, 5);
112  opt.clear();
113  EXPECT_FALSE(bool(opt));
114  }
115  { // copy-constructed
116  const int x = 6;
117  Optional<const int> opt(x);
118  EXPECT_EQ(*opt, 6);
119  }
120  { // move-constructed
121  const int x = 7;
123  EXPECT_EQ(*opt, 7);
124  }
125  // no assignment allowed
126 }
127 
128 TEST(Optional, Simple) {
129  Optional<int> opt;
130  EXPECT_FALSE(bool(opt));
131  EXPECT_EQ(42, opt.value_or(42));
132  opt = 4;
133  EXPECT_TRUE(bool(opt));
134  EXPECT_EQ(4, *opt);
135  EXPECT_EQ(4, opt.value_or(42));
136  opt = 5;
137  EXPECT_EQ(5, *opt);
138  opt.clear();
139  EXPECT_FALSE(bool(opt));
140 }
141 
142 namespace {
143 
144 class MoveTester {
145  public:
146  /* implicit */ MoveTester(const char* s) : s_(s) {}
147  MoveTester(const MoveTester&) = default;
148  MoveTester(MoveTester&& other) noexcept {
149  s_ = std::move(other.s_);
150  other.s_ = "";
151  }
152  MoveTester& operator=(const MoveTester&) = default;
153  MoveTester& operator=(MoveTester&& other) noexcept {
154  s_ = std::move(other.s_);
155  other.s_ = "";
156  return *this;
157  }
158 
159  private:
160  friend bool operator==(const MoveTester& o1, const MoveTester& o2);
162 };
163 
164 bool operator==(const MoveTester& o1, const MoveTester& o2) {
165  return o1.s_ == o2.s_;
166 }
167 
168 } // namespace
169 
170 TEST(Optional, value_or_rvalue_arg) {
172  MoveTester dflt = "hello";
173  EXPECT_EQ("hello", opt.value_or(dflt));
174  EXPECT_EQ("hello", dflt);
175  EXPECT_EQ("hello", opt.value_or(std::move(dflt)));
176  EXPECT_EQ("", dflt);
177  EXPECT_EQ("world", opt.value_or("world"));
178 
179  dflt = "hello";
180  // Make sure that the const overload works on const objects
181  const auto& optc = opt;
182  EXPECT_EQ("hello", optc.value_or(dflt));
183  EXPECT_EQ("hello", dflt);
184  EXPECT_EQ("hello", optc.value_or(std::move(dflt)));
185  EXPECT_EQ("", dflt);
186  EXPECT_EQ("world", optc.value_or("world"));
187 
188  dflt = "hello";
189  opt = "meow";
190  EXPECT_EQ("meow", opt.value_or(dflt));
191  EXPECT_EQ("hello", dflt);
192  EXPECT_EQ("meow", opt.value_or(std::move(dflt)));
193  EXPECT_EQ("hello", dflt); // only moved if used
194 }
195 
196 TEST(Optional, value_or_noncopyable) {
198  std::unique_ptr<int> dflt(new int(42));
199  EXPECT_EQ(42, *std::move(opt).value_or(std::move(dflt)));
200 }
201 
202 struct ExpectingDeleter {
203  explicit ExpectingDeleter(int expected_) : expected(expected_) {}
204  int expected;
205  void operator()(const int* ptr) {
206  EXPECT_EQ(*ptr, expected);
207  delete ptr;
208  }
209 };
210 
211 TEST(Optional, value_move) {
213  {new int(42), ExpectingDeleter{1337}})
214  .value();
215  *ptr = 1337;
216 }
217 
218 TEST(Optional, dereference_move) {
220  {new int(42), ExpectingDeleter{1337}});
221  *ptr = 1337;
222 }
223 
224 TEST(Optional, EmptyConstruct) {
225  Optional<int> opt;
226  EXPECT_FALSE(bool(opt));
227  Optional<int> test1(opt);
228  EXPECT_FALSE(bool(test1));
229  Optional<int> test2(std::move(opt));
230  EXPECT_FALSE(bool(test2));
231 }
232 
233 TEST(Optional, InPlaceConstruct) {
234  using A = std::pair<int, double>;
235  Optional<A> opt(in_place, 5, 3.2);
236  EXPECT_TRUE(bool(opt));
237  EXPECT_EQ(5, opt->first);
238 }
239 
240 TEST(Optional, InPlaceNestedConstruct) {
241  using A = std::pair<int, double>;
242  Optional<Optional<A>> opt(in_place, in_place, 5, 3.2);
243  EXPECT_TRUE(bool(opt));
244  EXPECT_TRUE(bool(*opt));
245  EXPECT_EQ(5, (*opt)->first);
246 }
247 
248 TEST(Optional, Unique) {
250 
251  opt.clear();
252  EXPECT_FALSE(bool(opt));
253  // empty->emplaced
254  opt.emplace(new int(5));
255  EXPECT_TRUE(bool(opt));
256  EXPECT_EQ(5, **opt);
257 
258  opt.clear();
259  // empty->moved
260  opt = std::make_unique<int>(6);
261  EXPECT_EQ(6, **opt);
262  // full->moved
263  opt = std::make_unique<int>(7);
264  EXPECT_EQ(7, **opt);
265 
266  // move it out by move construct
267  Optional<unique_ptr<int>> moved(std::move(opt));
268  EXPECT_TRUE(bool(moved));
269  EXPECT_FALSE(bool(opt));
270  EXPECT_EQ(7, **moved);
271 
272  EXPECT_TRUE(bool(moved));
273  opt = std::move(moved); // move it back by move assign
274  EXPECT_FALSE(bool(moved));
275  EXPECT_TRUE(bool(opt));
276  EXPECT_EQ(7, **opt);
277 }
278 
279 TEST(Optional, Shared) {
282  EXPECT_FALSE(bool(opt));
283  // empty->emplaced
284  opt.emplace(new int(5));
285  EXPECT_TRUE(bool(opt));
286  ptr = opt.value();
287  EXPECT_EQ(ptr.get(), opt->get());
288  EXPECT_EQ(2, ptr.use_count());
289  opt.clear();
290  EXPECT_EQ(1, ptr.use_count());
291  // full->copied
292  opt = ptr;
293  EXPECT_EQ(2, ptr.use_count());
294  EXPECT_EQ(ptr.get(), opt->get());
295  opt.clear();
296  EXPECT_EQ(1, ptr.use_count());
297  // full->moved
298  opt = std::move(ptr);
299  EXPECT_EQ(1, opt->use_count());
300  EXPECT_EQ(nullptr, ptr.get());
301  {
302  Optional<shared_ptr<int>> copied(opt);
303  EXPECT_EQ(2, opt->use_count());
304  Optional<shared_ptr<int>> moved(std::move(opt));
305  EXPECT_EQ(2, moved->use_count());
306  moved.emplace(new int(6));
307  EXPECT_EQ(1, moved->use_count());
308  copied = moved;
309  EXPECT_EQ(2, moved->use_count());
310  }
311 }
312 
313 TEST(Optional, Order) {
314  std::vector<Optional<int>> vect{
315  {none},
316  {3},
317  {1},
318  {none},
319  {2},
320  };
321  std::vector<Optional<int>> expected{
322  {none},
323  {none},
324  {1},
325  {2},
326  {3},
327  };
328  std::sort(vect.begin(), vect.end());
329  EXPECT_EQ(vect, expected);
330 }
331 
332 TEST(Optional, Swap) {
335 
336  swap(a, b);
337  EXPECT_FALSE(a.hasValue());
338  EXPECT_FALSE(b.hasValue());
339 
340  a = "hello";
341  EXPECT_TRUE(a.hasValue());
342  EXPECT_FALSE(b.hasValue());
343  EXPECT_EQ("hello", a.value());
344 
345  swap(a, b);
346  EXPECT_FALSE(a.hasValue());
347  EXPECT_TRUE(b.hasValue());
348  EXPECT_EQ("hello", b.value());
349 
350  a = "bye";
351  EXPECT_TRUE(a.hasValue());
352  EXPECT_EQ("bye", a.value());
353 
354  swap(a, b);
355  EXPECT_TRUE(a.hasValue());
356  EXPECT_TRUE(b.hasValue());
357  EXPECT_EQ("hello", a.value());
358  EXPECT_EQ("bye", b.value());
359 }
360 
361 TEST(Optional, Comparisons) {
362  Optional<int> o_;
363  Optional<int> o1(1);
364  Optional<int> o2(2);
365 
366  EXPECT_TRUE(o_ <= (o_));
367  EXPECT_TRUE(o_ == (o_));
368  EXPECT_TRUE(o_ >= (o_));
369 
370  EXPECT_TRUE(o1 < o2);
371  EXPECT_TRUE(o1 <= o2);
372  EXPECT_TRUE(o1 <= (o1));
373  EXPECT_TRUE(o1 == (o1));
374  EXPECT_TRUE(o1 != o2);
375  EXPECT_TRUE(o1 >= (o1));
376  EXPECT_TRUE(o2 >= o1);
377  EXPECT_TRUE(o2 > o1);
378 
379  EXPECT_FALSE(o2 < o1);
380  EXPECT_FALSE(o2 <= o1);
381  EXPECT_FALSE(o2 <= o1);
382  EXPECT_FALSE(o2 == o1);
383  EXPECT_FALSE(o1 != (o1));
384  EXPECT_FALSE(o1 >= o2);
385  EXPECT_FALSE(o1 >= o2);
386  EXPECT_FALSE(o1 > o2);
387 
388  /* folly::Optional explicitly doesn't support comparisons with contained value
389  EXPECT_TRUE(1 < o2);
390  EXPECT_TRUE(1 <= o2);
391  EXPECT_TRUE(1 <= o1);
392  EXPECT_TRUE(1 == o1);
393  EXPECT_TRUE(2 != o1);
394  EXPECT_TRUE(1 >= o1);
395  EXPECT_TRUE(2 >= o1);
396  EXPECT_TRUE(2 > o1);
397 
398  EXPECT_FALSE(o2 < 1);
399  EXPECT_FALSE(o2 <= 1);
400  EXPECT_FALSE(o2 <= 1);
401  EXPECT_FALSE(o2 == 1);
402  EXPECT_FALSE(o2 != 2);
403  EXPECT_FALSE(o1 >= 2);
404  EXPECT_FALSE(o1 >= 2);
405  EXPECT_FALSE(o1 > 2);
406  */
407 
408  // boost::optional does support comparison with contained value, which can
409  // lead to confusion when a bool is contained
410  boost::optional<int> boi(3);
411  EXPECT_TRUE(boi < 5);
412  EXPECT_TRUE(boi <= 4);
413  EXPECT_TRUE(boi == 3);
414  EXPECT_TRUE(boi != 2);
415  EXPECT_TRUE(boi >= 1);
416  EXPECT_TRUE(boi > 0);
417  EXPECT_TRUE(1 < boi);
418  EXPECT_TRUE(2 <= boi);
419  EXPECT_TRUE(3 == boi);
420  EXPECT_TRUE(4 != boi);
421  EXPECT_TRUE(5 >= boi);
422  EXPECT_TRUE(6 > boi);
423 
424  boost::optional<bool> bob(false);
425  EXPECT_TRUE((bool)bob);
426  EXPECT_TRUE(bob == false); // well that was confusing
427  EXPECT_FALSE(bob != false);
428 }
429 
430 TEST(Optional, HeterogeneousComparisons) {
431  using opt8 = Optional<uint8_t>;
432  using opt64 = Optional<uint64_t>;
433 
434  EXPECT_TRUE(opt8(4) == uint64_t(4));
435  EXPECT_FALSE(opt8(8) == uint64_t(4));
436  EXPECT_FALSE(opt8() == uint64_t(4));
437 
438  EXPECT_TRUE(uint64_t(4) == opt8(4));
439  EXPECT_FALSE(uint64_t(4) == opt8(8));
440  EXPECT_FALSE(uint64_t(4) == opt8());
441 
442  EXPECT_FALSE(opt8(4) != uint64_t(4));
443  EXPECT_TRUE(opt8(8) != uint64_t(4));
444  EXPECT_TRUE(opt8() != uint64_t(4));
445 
446  EXPECT_FALSE(uint64_t(4) != opt8(4));
447  EXPECT_TRUE(uint64_t(4) != opt8(8));
448  EXPECT_TRUE(uint64_t(4) != opt8());
449 
450  EXPECT_TRUE(opt8() == opt64());
451  EXPECT_TRUE(opt8(4) == opt64(4));
452  EXPECT_FALSE(opt8(8) == opt64(4));
453  EXPECT_FALSE(opt8() == opt64(4));
454  EXPECT_FALSE(opt8(4) == opt64());
455 
456  EXPECT_FALSE(opt8() != opt64());
457  EXPECT_FALSE(opt8(4) != opt64(4));
458  EXPECT_TRUE(opt8(8) != opt64(4));
459  EXPECT_TRUE(opt8() != opt64(4));
460  EXPECT_TRUE(opt8(4) != opt64());
461 
462  EXPECT_TRUE(opt8() < opt64(4));
463  EXPECT_TRUE(opt8(4) < opt64(8));
464  EXPECT_FALSE(opt8() < opt64());
465  EXPECT_FALSE(opt8(4) < opt64(4));
466  EXPECT_FALSE(opt8(8) < opt64(4));
467  EXPECT_FALSE(opt8(4) < opt64());
468 
469  EXPECT_FALSE(opt8() > opt64(4));
470  EXPECT_FALSE(opt8(4) > opt64(8));
471  EXPECT_FALSE(opt8() > opt64());
472  EXPECT_FALSE(opt8(4) > opt64(4));
473  EXPECT_TRUE(opt8(8) > opt64(4));
474  EXPECT_TRUE(opt8(4) > opt64());
475 
476  EXPECT_TRUE(opt8() <= opt64(4));
477  EXPECT_TRUE(opt8(4) <= opt64(8));
478  EXPECT_TRUE(opt8() <= opt64());
479  EXPECT_TRUE(opt8(4) <= opt64(4));
480  EXPECT_FALSE(opt8(8) <= opt64(4));
481  EXPECT_FALSE(opt8(4) <= opt64());
482 
483  EXPECT_FALSE(opt8() >= opt64(4));
484  EXPECT_FALSE(opt8(4) >= opt64(8));
485  EXPECT_TRUE(opt8() >= opt64());
486  EXPECT_TRUE(opt8(4) >= opt64(4));
487  EXPECT_TRUE(opt8(8) >= opt64(4));
488  EXPECT_TRUE(opt8(4) >= opt64());
489 }
490 
491 TEST(Optional, NoneComparisons) {
492  using opt = Optional<int>;
493  EXPECT_TRUE(opt() == none);
494  EXPECT_TRUE(none == opt());
495  EXPECT_FALSE(opt(1) == none);
496  EXPECT_FALSE(none == opt(1));
497 
498  EXPECT_FALSE(opt() != none);
499  EXPECT_FALSE(none != opt());
500  EXPECT_TRUE(opt(1) != none);
501  EXPECT_TRUE(none != opt(1));
502 
503  EXPECT_FALSE(opt() < none);
504  EXPECT_FALSE(none < opt());
505  EXPECT_FALSE(opt(1) < none);
506  EXPECT_TRUE(none < opt(1));
507 
508  EXPECT_FALSE(opt() > none);
509  EXPECT_FALSE(none > opt());
510  EXPECT_FALSE(none > opt(1));
511  EXPECT_TRUE(opt(1) > none);
512 
513  EXPECT_TRUE(opt() <= none);
514  EXPECT_TRUE(none <= opt());
515  EXPECT_FALSE(opt(1) <= none);
516  EXPECT_TRUE(none <= opt(1));
517 
518  EXPECT_TRUE(opt() >= none);
519  EXPECT_TRUE(none >= opt());
520  EXPECT_TRUE(opt(1) >= none);
521  EXPECT_FALSE(none >= opt(1));
522 }
523 
524 TEST(Optional, Conversions) {
525  Optional<bool> mbool;
526  Optional<short> mshort;
527  Optional<char*> mstr;
528  Optional<int> mint;
529 
530  // These don't compile
531  // bool b = mbool;
532  // short s = mshort;
533  // char* c = mstr;
534  // int x = mint;
535  // char* c(mstr);
536  // short s(mshort);
537  // int x(mint);
538 
539  // intended explicit operator bool, for if (opt).
540  bool b(mbool);
541  EXPECT_FALSE(b);
542 
543  // Truthy tests work and are not ambiguous
544  if (mbool && mshort && mstr && mint) { // only checks not-empty
545  if (*mbool && *mshort && *mstr && *mint) { // only checks value
546  ;
547  }
548  }
549 
550  mbool = false;
551  EXPECT_TRUE(bool(mbool));
552  EXPECT_FALSE(*mbool);
553 
554  mbool = true;
555  EXPECT_TRUE(bool(mbool));
556  EXPECT_TRUE(*mbool);
557 
558  mbool = none;
559  EXPECT_FALSE(bool(mbool));
560 
561  // No conversion allowed; does not compile
562  // EXPECT_TRUE(mbool == false);
563 }
564 
568  x = 1;
570  *get_pointer(x) = 2;
571  EXPECT_TRUE(*x == 2);
572  x = none;
574 }
575 
576 namespace {
577 class ConstructibleWithArgsOnly {
578  public:
579  explicit ConstructibleWithArgsOnly(int, double) {}
580 
581  ConstructibleWithArgsOnly() = delete;
582  ConstructibleWithArgsOnly(const ConstructibleWithArgsOnly&) = delete;
583  ConstructibleWithArgsOnly(ConstructibleWithArgsOnly&&) = delete;
584  ConstructibleWithArgsOnly& operator=(const ConstructibleWithArgsOnly&) =
585  delete;
586  ConstructibleWithArgsOnly& operator=(ConstructibleWithArgsOnly&&) = delete;
587 };
588 
589 class ConstructibleWithInitializerListAndArgsOnly {
590  public:
591  ConstructibleWithInitializerListAndArgsOnly(std::initializer_list<int>, int) {
592  }
593 
594  ConstructibleWithInitializerListAndArgsOnly() = delete;
595  ConstructibleWithInitializerListAndArgsOnly(
596  const ConstructibleWithInitializerListAndArgsOnly&) = delete;
597  ConstructibleWithInitializerListAndArgsOnly(
598  ConstructibleWithInitializerListAndArgsOnly&&) = delete;
599  ConstructibleWithInitializerListAndArgsOnly& operator=(
600  const ConstructibleWithInitializerListAndArgsOnly&) = delete;
601  ConstructibleWithInitializerListAndArgsOnly& operator=(
602  ConstructibleWithInitializerListAndArgsOnly&&) = delete;
603 };
604 } // namespace
605 
606 TEST(Optional, MakeOptional) {
607  // const L-value version
608  const std::string s("abc");
609  auto optStr = folly::make_optional(s);
610  ASSERT_TRUE(optStr.hasValue());
611  EXPECT_EQ(*optStr, "abc");
612  *optStr = "cde";
613  EXPECT_EQ(s, "abc");
614  EXPECT_EQ(*optStr, "cde");
615 
616  // L-value version
617  std::string s2("abc");
618  auto optStr2 = folly::make_optional(s2);
619  ASSERT_TRUE(optStr2.hasValue());
620  EXPECT_EQ(*optStr2, "abc");
621  *optStr2 = "cde";
622  // it's vital to check that s2 wasn't clobbered
623  EXPECT_EQ(s2, "abc");
624 
625  // L-value reference version
626  std::string& s3(s2);
627  auto optStr3 = folly::make_optional(s3);
628  ASSERT_TRUE(optStr3.hasValue());
629  EXPECT_EQ(*optStr3, "abc");
630  *optStr3 = "cde";
631  EXPECT_EQ(s3, "abc");
632 
633  // R-value ref version
634  unique_ptr<int> pInt(new int(3));
635  auto optIntPtr = folly::make_optional(std::move(pInt));
636  EXPECT_TRUE(pInt.get() == nullptr);
637  ASSERT_TRUE(optIntPtr.hasValue());
638  EXPECT_EQ(**optIntPtr, 3);
639 
640  // variadic version
641  {
642  auto&& optional = make_optional<ConstructibleWithArgsOnly>(int{}, double{});
643  std::ignore = optional;
644  }
645  {
646  using Type = ConstructibleWithInitializerListAndArgsOnly;
647  auto&& optional = make_optional<Type>({int{}}, double{});
648  std::ignore = optional;
649  }
650 }
651 
652 TEST(Optional, InitializerListConstruct) {
653  using Type = ConstructibleWithInitializerListAndArgsOnly;
654  auto&& optional = Optional<Type>{in_place, {int{}}, double{}};
655  std::ignore = optional;
656 }
657 
658 TEST(Optional, TestDisambiguationMakeOptionalVariants) {
659  {
660  auto optional = make_optional<int>(1);
661  std::ignore = optional;
662  }
663  {
664  auto optional = make_optional(1);
665  std::ignore = optional;
666  }
667 }
668 
669 TEST(Optional, SelfAssignment) {
670  Optional<int> a = 42;
671  a = static_cast<decltype(a)&>(a); // suppress self-assign warning
672  ASSERT_TRUE(a.hasValue() && a.value() == 42);
673 
674  Optional<int> b = 23333333;
675  b = static_cast<decltype(b)&&>(b); // suppress self-move warning
676  ASSERT_TRUE(b.hasValue() && b.value() == 23333333);
677 }
678 
679 namespace {
680 
681 class ContainsOptional {
682  public:
683  ContainsOptional() {}
684  explicit ContainsOptional(int x) : opt_(x) {}
685  bool hasValue() const {
686  return opt_.hasValue();
687  }
688  int value() const {
689  return opt_.value();
690  }
691 
692  ContainsOptional(const ContainsOptional& other) = default;
693  ContainsOptional& operator=(const ContainsOptional& other) = default;
694  ContainsOptional(ContainsOptional&& other) = default;
695  ContainsOptional& operator=(ContainsOptional&& other) = default;
696 
697  private:
698  Optional<int> opt_;
699 };
700 
701 } // namespace
702 
708 TEST(Optional, AssignmentContained) {
709  {
710  ContainsOptional source(5), target;
711  target = source;
712  EXPECT_TRUE(target.hasValue());
713  EXPECT_EQ(5, target.value());
714  }
715 
716  {
717  ContainsOptional source(5), target;
718  target = std::move(source);
719  EXPECT_TRUE(target.hasValue());
720  EXPECT_EQ(5, target.value());
721  EXPECT_FALSE(source.hasValue());
722  }
723 
724  {
725  ContainsOptional opt_uninit, target(10);
726  target = opt_uninit;
727  EXPECT_FALSE(target.hasValue());
728  }
729 }
730 
731 TEST(Optional, Exceptions) {
734 }
735 
736 TEST(Optional, NoThrowDefaultConstructible) {
737  EXPECT_TRUE(std::is_nothrow_default_constructible<Optional<bool>>::value);
738 }
739 
740 namespace {
741 
742 struct NoDestructor {};
743 
744 struct WithDestructor {
745  ~WithDestructor();
746 };
747 
748 } // namespace
749 
750 TEST(Optional, TriviallyDestructible) {
751  // These could all be static_asserts but EXPECT_* give much nicer output on
752  // failure.
753  EXPECT_TRUE(std::is_trivially_destructible<Optional<NoDestructor>>::value);
754  EXPECT_TRUE(std::is_trivially_destructible<Optional<int>>::value);
755  EXPECT_FALSE(std::is_trivially_destructible<Optional<WithDestructor>>::value);
756 }
757 
759  // Test it's usable in std::unordered map (compile time check)
760  std::unordered_map<Optional<int>, Optional<int>> obj;
761  // Also check the std::hash template can be instantiated by the compiler
762  std::hash<Optional<int>>()(none);
763  std::hash<Optional<int>>()(3);
764 }
765 
766 namespace {
767 
768 struct WithConstMember {
769  /* implicit */ WithConstMember(int val) : x(val) {}
770  const int x;
771 };
772 
773 // Make this opaque to the optimizer by preventing inlining.
774 FOLLY_NOINLINE void replaceWith2(Optional<WithConstMember>& o) {
775  o.emplace(2);
776 }
777 
778 } // namespace
779 
780 TEST(Optional, ConstMember) {
781  // Verify that the compiler doesn't optimize out the second load of
782  // o->x based on the assumption that the field is const.
783  //
784  // Current Optional implementation doesn't defend against that
785  // assumption, thus replacing an optional where the object has const
786  // members is technically UB and would require wrapping each access
787  // to the storage with std::launder, but this prevents useful
788  // optimizations.
789  //
790  // Implementations of std::optional in both libstdc++ and libc++ are
791  // subject to the same UB. It is then reasonable to believe that
792  // major compilers don't rely on the constness assumption.
794  int sum = 0;
795  sum += o->x;
796  replaceWith2(o);
797  sum += o->x;
798  EXPECT_EQ(sum, 3);
799 }
800 
801 TEST(Optional, NoneMatchesNullopt) {
802  auto op = make_optional<int>(10);
803  op = {};
804  EXPECT_FALSE(op.has_value());
805 
806  op = make_optional<int>(20);
807  op = none;
808  EXPECT_FALSE(op.has_value());
809 }
810 
811 } // namespace folly
Definition: InvokeTest.cpp:58
void * ptr
std::atomic< int64_t > sum(0)
auto v
std::unique_ptr< int > A
#define EXPECT_THROW(statement, expected_exception)
Definition: gtest.h:1843
std::string s_
ExpectingDeleter(int expected_)
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
const int x
double val
Definition: String.cpp:273
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
in_place_tag in_place(in_place_tag={})
Definition: Utility.h:235
requires E e noexcept(noexcept(s.error(std::move(e))))
Optional< int > opt_
constexpr Optional< _t< std::decay< T > > > make_optional(T &&v)
Definition: Optional.h:450
void operator()(const int *ptr)
#define FOLLY_NOINLINE
Definition: CPortability.h:142
constexpr auto empty(C const &c) -> decltype(c.empty())
Definition: Access.h:55
NoDefault(int, int)
FOLLY_CPP14_CONSTEXPR bool hasValue() const noexcept
Definition: Optional.h:300
internal::PointeeMatcher< InnerMatcher > Pointee(const InnerMatcher &inner_matcher)
Value & emplace(Args &&...args)
Definition: Optional.h:231
FOLLY_CPP14_CONSTEXPR Value value_or(U &&dflt) const &
Definition: Optional.h:330
#define EXPECT_TRUE(condition)
Definition: gtest.h:1859
const Value * get_pointer(const Expected< Value, Error > &ex) noexcept
Definition: Expected.h:1374
void swap(exception_wrapper &a, exception_wrapper &b) noexcept
#define EXPECT_THAT(value, matcher)
void reset() noexcept
Definition: Optional.h:247
bool operator==(const Unexpected< Error > &lhs, const Unexpected< Error > &rhs)
Definition: Expected.h:758
const char * string
Definition: Conv.cpp:212
static set< string > s
uint64_t value(const typename LockFreeRingBuffer< T, Atom >::Cursor &rbcursor)
FOLLY_CPP14_CONSTEXPR const Value & value() const &
Definition: Optional.h:268
#define EXPECT_FALSE(condition)
Definition: gtest.h:1862
internal::ElementsAreMatcher< ::testing::tuple<> > ElementsAre()
#define ASSERT_TRUE(condition)
Definition: gtest.h:1865
TEST(SequencedExecutor, CPUThreadPoolExecutor)
constexpr None none
Definition: Optional.h:87
void clear() noexcept
Definition: Optional.h:251