Commit 2ca10eee authored by Yedidya Feldblum's avatar Yedidya Feldblum Committed by Facebook Github Bot

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
parent 2f5439e4
......@@ -63,6 +63,7 @@
#include <folly/Launder.h>
#include <folly/Portability.h>
#include <folly/Traits.h>
#include <folly/Utility.h>
namespace folly {
......@@ -203,15 +204,41 @@ class Optional {
}
template <class... Args>
void emplace(Args&&... args) {
Value& emplace(Args&&... args) {
clear();
storage_.construct(std::forward<Args>(args)...);
return storage_.construct(std::forward<Args>(args)...);
}
void clear() {
template <class U, class... Args>
typename std::enable_if<
std::is_constructible<Value, std::initializer_list<U>&, Args&&...>::value,
Value&>::type
emplace(std::initializer_list<U> ilist, Args&&... args) {
clear();
return storage_.construct(ilist, std::forward<Args>(args)...);
}
void reset() noexcept {
storage_.clear();
}
void clear() noexcept {
reset();
}
void swap(Optional& that) noexcept(IsNothrowSwappable<Value>::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 <class... Args>
void construct(Args&&... args) {
Value& construct(Args&&... args) {
new (raw_pointer()) Value(std::forward<Args>(args)...);
this->hasValue_ = true;
return *launder(reinterpret_cast<Value*>(this->value_));
}
private:
......@@ -375,14 +407,8 @@ T* get_pointer(Optional<T>& opt) {
}
template <class T>
void swap(Optional<T>& a, Optional<T>& 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<T>& a, Optional<T>& b) noexcept(noexcept(a.swap(b))) {
a.swap(b);
}
template <class T, class Opt = Optional<typename std::decay<T>::type>>
......
......@@ -16,6 +16,7 @@
#include <folly/Optional.h>
#include <folly/Portability.h>
#include <folly/portability/GMock.h>
#include <folly/portability/GTest.h>
#include <algorithm>
......@@ -65,6 +66,28 @@ TEST(Optional, NoDefault) {
EXPECT_FALSE(x);
}
TEST(Optional, Emplace) {
Optional<std::vector<int>> 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<std::vector<int>> 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<int> opt(3);
opt.reset();
EXPECT_FALSE(opt);
}
TEST(Optional, String) {
Optional<std::string> 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) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment