From 2ca10eeefdc1231a20fb1cb75dc3e8d2c5fa70ba Mon Sep 17 00:00:00 2001 From: Yedidya Feldblum Date: Tue, 24 Oct 2017 22:05:23 -0700 Subject: [PATCH] Flesh out Optional members swap, reset, emplace, has_value Summary: [Folly] Flesh out `Optional` members `swap`, `reset`, `emplace`, `has_value`. * `swap` as a member and deriving `noexcept`-ness to mimic `std::optional::swap`. * `reset` v.s. `clear` to mimic `std::optional::reset`. * `emplace` returning ref and overload taking initializer list to mimic `std::optional::emplace`. * `has_value` v.s. `hasValue` to mimic `std::optional::has_value`. Reviewed By: WillerZ Differential Revision: D6132775 fbshipit-source-id: 34c58367b9dc63289e4b9721c5e79b1c41ba31e4 --- folly/Optional.h | 54 +++++++++++++++++++++++++++---------- folly/test/OptionalTest.cpp | 27 +++++++++++++++++++ 2 files changed, 67 insertions(+), 14 deletions(-) diff --git a/folly/Optional.h b/folly/Optional.h index 31e1f4fd..39abcc1c 100644 --- a/folly/Optional.h +++ b/folly/Optional.h @@ -63,6 +63,7 @@ #include #include +#include #include namespace folly { @@ -203,15 +204,41 @@ class Optional { } template - void emplace(Args&&... args) { + Value& emplace(Args&&... args) { clear(); - storage_.construct(std::forward(args)...); + return storage_.construct(std::forward(args)...); + } + + template + typename std::enable_if< + std::is_constructible&, Args&&...>::value, + Value&>::type + emplace(std::initializer_list ilist, Args&&... args) { + clear(); + return storage_.construct(ilist, std::forward(args)...); } - void clear() { + void reset() noexcept { storage_.clear(); } + void clear() noexcept { + reset(); + } + + void swap(Optional& that) noexcept(IsNothrowSwappable::value) { + if (hasValue() && that.hasValue()) { + using std::swap; + swap(value(), that.value()); + } else if (hasValue()) { + that.emplace(std::move(value())); + reset(); + } else if (that.hasValue()) { + emplace(std::move(that.value())); + that.reset(); + } + } + FOLLY_CPP14_CONSTEXPR const Value& value() const & { require_value(); return *storage_.value_pointer(); @@ -240,12 +267,16 @@ class Optional { } Value* get_pointer() && = delete; - FOLLY_CPP14_CONSTEXPR bool hasValue() const noexcept { + FOLLY_CPP14_CONSTEXPR bool has_value() const noexcept { return storage_.hasValue(); } + FOLLY_CPP14_CONSTEXPR bool hasValue() const noexcept { + return has_value(); + } + FOLLY_CPP14_CONSTEXPR explicit operator bool() const noexcept { - return hasValue(); + return has_value(); } FOLLY_CPP14_CONSTEXPR const Value& operator*() const & { @@ -350,9 +381,10 @@ class Optional { } template - void construct(Args&&... args) { + Value& construct(Args&&... args) { new (raw_pointer()) Value(std::forward(args)...); this->hasValue_ = true; + return *launder(reinterpret_cast(this->value_)); } private: @@ -375,14 +407,8 @@ T* get_pointer(Optional& opt) { } template -void swap(Optional& a, Optional& b) { - if (a.hasValue() && b.hasValue()) { - // both full - using std::swap; - swap(a.value(), b.value()); - } else if (a.hasValue() || b.hasValue()) { - std::swap(a, b); // fall back to default implementation if they're mixed. - } +void swap(Optional& a, Optional& b) noexcept(noexcept(a.swap(b))) { + a.swap(b); } template ::type>> diff --git a/folly/test/OptionalTest.cpp b/folly/test/OptionalTest.cpp index 091dd9a3..a5e12d15 100644 --- a/folly/test/OptionalTest.cpp +++ b/folly/test/OptionalTest.cpp @@ -16,6 +16,7 @@ #include #include +#include #include #include @@ -65,6 +66,28 @@ TEST(Optional, NoDefault) { EXPECT_FALSE(x); } +TEST(Optional, Emplace) { + Optional> opt; + auto& values1 = opt.emplace(3, 4); + EXPECT_THAT(values1, testing::ElementsAre(4, 4, 4)); + auto& values2 = opt.emplace(2, 5); + EXPECT_THAT(values2, testing::ElementsAre(5, 5)); +} + +TEST(Optional, EmplaceInitializerList) { + Optional> opt; + auto& values1 = opt.emplace({3, 4, 5}); + EXPECT_THAT(values1, testing::ElementsAre(3, 4, 5)); + auto& values2 = opt.emplace({4, 5, 6}); + EXPECT_THAT(values2, testing::ElementsAre(4, 5, 6)); +} + +TEST(Optional, Reset) { + Optional opt(3); + opt.reset(); + EXPECT_FALSE(opt); +} + TEST(Optional, String) { Optional maybeString; EXPECT_FALSE(maybeString); @@ -318,6 +341,10 @@ TEST(Optional, Swap) { EXPECT_EQ("bye", a.value()); swap(a, b); + EXPECT_TRUE(a.hasValue()); + EXPECT_TRUE(b.hasValue()); + EXPECT_EQ("hello", a.value()); + EXPECT_EQ("bye", b.value()); } TEST(Optional, Comparisons) { -- 2.34.1