Commit 30af28c6 authored by Yedidya Feldblum's avatar Yedidya Feldblum Committed by Facebook Github Bot

Fix SharedPromise move-ctor, move-assign

Summary: [Folly] Fix `SharedPromise` move-ctor, move-assign. Some fields really should be zero'd.

Reviewed By: davidtgoldblatt

Differential Revision: D13152287

fbshipit-source-id: 1ab2da8016cbd736541a98ff32f32c30f6452209
parent 5f5230ff
...@@ -21,15 +21,15 @@ namespace folly { ...@@ -21,15 +21,15 @@ namespace folly {
template <class T> template <class T>
size_t SharedPromise<T>::size() { size_t SharedPromise<T>::size() {
std::lock_guard<std::mutex> g(mutex_); std::lock_guard<std::mutex> g(mutex_);
return size_; return size_.value;
} }
template <class T> template <class T>
SemiFuture<T> SharedPromise<T>::getSemiFuture() { SemiFuture<T> SharedPromise<T>::getSemiFuture() {
std::lock_guard<std::mutex> g(mutex_); std::lock_guard<std::mutex> g(mutex_);
size_++; size_.value++;
if (hasValue_) { if (hasResult()) {
return makeFuture<T>(Try<T>(try_)); return makeFuture<T>(Try<T>(try_.value));
} else { } else {
promises_.emplace_back(); promises_.emplace_back();
if (interruptHandler_) { if (interruptHandler_) {
...@@ -60,7 +60,7 @@ template <class T> ...@@ -60,7 +60,7 @@ template <class T>
void SharedPromise<T>::setInterruptHandler( void SharedPromise<T>::setInterruptHandler(
std::function<void(exception_wrapper const&)> fn) { std::function<void(exception_wrapper const&)> fn) {
std::lock_guard<std::mutex> g(mutex_); std::lock_guard<std::mutex> g(mutex_);
if (hasValue_) { if (hasResult()) {
return; return;
} }
interruptHandler_ = fn; interruptHandler_ = fn;
...@@ -87,23 +87,22 @@ void SharedPromise<T>::setTry(Try<T>&& t) { ...@@ -87,23 +87,22 @@ void SharedPromise<T>::setTry(Try<T>&& t) {
{ {
std::lock_guard<std::mutex> g(mutex_); std::lock_guard<std::mutex> g(mutex_);
if (hasValue_) { if (hasResult()) {
throw_exception<PromiseAlreadySatisfied>(); throw_exception<PromiseAlreadySatisfied>();
} }
hasValue_ = true; try_.value = std::move(t);
try_ = std::move(t);
promises.swap(promises_); promises.swap(promises_);
} }
for (auto& p : promises) { for (auto& p : promises) {
p.setTry(Try<T>(try_)); p.setTry(Try<T>(try_.value));
} }
} }
template <class T> template <class T>
bool SharedPromise<T>::isFulfilled() { bool SharedPromise<T>::isFulfilled() {
std::lock_guard<std::mutex> g(mutex_); std::lock_guard<std::mutex> g(mutex_);
return hasValue_; return hasResult();
} }
} // namespace folly } // namespace folly
...@@ -109,10 +109,29 @@ class SharedPromise { ...@@ -109,10 +109,29 @@ class SharedPromise {
} }
}; };
template <typename V>
struct Defaulted {
using Noexcept = StrictConjunction<
std::is_nothrow_default_constructible<V>,
std::is_nothrow_move_constructible<V>,
std::is_nothrow_move_assignable<V>>;
V value{V()};
Defaulted() = default;
Defaulted(Defaulted&& that) noexcept(Noexcept::value)
: value(std::exchange(that.value, V())) {}
Defaulted& operator=(Defaulted&& that) noexcept(Noexcept::value) {
value = std::exchange(that.value, V());
return *this;
}
};
bool hasResult() {
return try_.value.hasValue() || try_.value.hasException();
}
Mutex mutex_; Mutex mutex_;
size_t size_{0}; Defaulted<size_t> size_;
bool hasValue_{false}; Defaulted<Try<T>> try_;
Try<T> try_;
std::vector<Promise<T>> promises_; std::vector<Promise<T>> promises_;
std::function<void(exception_wrapper const&)> interruptHandler_; std::function<void(exception_wrapper const&)> interruptHandler_;
}; };
......
...@@ -114,7 +114,9 @@ TEST(SharedPromise, moveMove) { ...@@ -114,7 +114,9 @@ TEST(SharedPromise, moveMove) {
auto f1 = p.getFuture(); auto f1 = p.getFuture();
auto f2 = p.getFuture(); auto f2 = p.getFuture();
auto p2 = std::move(p); auto p2 = std::move(p);
EXPECT_EQ(2, p2.size());
p = std::move(p2); p = std::move(p2);
EXPECT_EQ(0, p2.size());
p.setValue(std::make_shared<int>(1)); p.setValue(std::make_shared<int>(1));
} }
...@@ -133,6 +135,7 @@ TEST(SharedPromise, isFulfilled) { ...@@ -133,6 +135,7 @@ TEST(SharedPromise, isFulfilled) {
EXPECT_TRUE(p2.isFulfilled()); EXPECT_TRUE(p2.isFulfilled());
p = std::move(p2); p = std::move(p2);
EXPECT_TRUE(p.isFulfilled()); EXPECT_TRUE(p.isFulfilled());
EXPECT_FALSE(p2.isFulfilled());
} }
TEST(SharedPromise, interruptHandler) { TEST(SharedPromise, interruptHandler) {
......
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