Commit 09c8a80a authored by Yedidya Feldblum's avatar Yedidya Feldblum Committed by Facebook Github Bot

Split Futures exceptions by Promise vs Future

Summary:
[Folly] Split Futures exceptions by `Promise` vs `Future`.

* Move `Promise` exceptions into the `Promise` header.
* Move `Future` exceptions into the `Future` header.
* Split `NoState` into `PromiseInvalid` and `FutureInvalid`.
* Remove the newly-empty exceptions header.

Reviewed By: andriigrynenko

Differential Revision: D7966499

fbshipit-source-id: 2dc6d2a941493979ebf47b3e70e5cf6a6fbd33cf
parent f5063ec7
...@@ -214,7 +214,6 @@ nobase_follyinclude_HEADERS = \ ...@@ -214,7 +214,6 @@ nobase_follyinclude_HEADERS = \
futures/helpers.h \ futures/helpers.h \
futures/Future.h \ futures/Future.h \
futures/Future-inl.h \ futures/Future-inl.h \
futures/FutureException.h \
futures/FutureSplitter.h \ futures/FutureSplitter.h \
futures/Promise-inl.h \ futures/Promise-inl.h \
futures/Promise.h \ futures/Promise.h \
......
...@@ -235,7 +235,7 @@ void FutureBase<T>::detach() { ...@@ -235,7 +235,7 @@ void FutureBase<T>::detach() {
template <class T> template <class T>
void FutureBase<T>::throwIfInvalid() const { void FutureBase<T>::throwIfInvalid() const {
if (!core_) { if (!core_) {
throw_exception<NoState>(); throw_exception<FutureInvalid>();
} }
} }
...@@ -721,7 +721,7 @@ SemiFuture<T>& SemiFuture<T>::operator=(Future<T>&& other) noexcept { ...@@ -721,7 +721,7 @@ SemiFuture<T>& SemiFuture<T>::operator=(Future<T>&& other) noexcept {
template <class T> template <class T>
Future<T> SemiFuture<T>::via(Executor* executor, int8_t priority) && { Future<T> SemiFuture<T>::via(Executor* executor, int8_t priority) && {
if (!executor) { if (!executor) {
throw_exception<NoExecutor>(); throw_exception<FutureNoExecutor>();
} }
if (auto deferredExecutor = getDeferredExecutor()) { if (auto deferredExecutor = getDeferredExecutor()) {
...@@ -1044,7 +1044,7 @@ template <class T> ...@@ -1044,7 +1044,7 @@ template <class T>
template <class F> template <class F>
Future<T> Future<T>::onTimeout(Duration dur, F&& func, Timekeeper* tk) { Future<T> Future<T>::onTimeout(Duration dur, F&& func, Timekeeper* tk) {
return within(dur, tk).onError( return within(dur, tk).onError(
[funcw = std::forward<F>(func)](TimedOut const&) mutable { [funcw = std::forward<F>(func)](FutureTimeout const&) mutable {
return std::forward<F>(funcw)(); return std::forward<F>(funcw)();
}); });
} }
...@@ -1631,7 +1631,7 @@ Future<T> unorderedReduce(It first, It last, T initial, F func) { ...@@ -1631,7 +1631,7 @@ Future<T> unorderedReduce(It first, It last, T initial, F func) {
template <class T> template <class T>
Future<T> Future<T>::within(Duration dur, Timekeeper* tk) { Future<T> Future<T>::within(Duration dur, Timekeeper* tk) {
return within(dur, TimedOut(), tk); return within(dur, FutureTimeout(), tk);
} }
template <class T> template <class T>
...@@ -1657,7 +1657,7 @@ Future<T> Future<T>::within(Duration dur, E e, Timekeeper* tk) { ...@@ -1657,7 +1657,7 @@ Future<T> Future<T>::within(Duration dur, E e, Timekeeper* tk) {
} }
if (UNLIKELY(!tk)) { if (UNLIKELY(!tk)) {
return makeFuture<T>(NoTimekeeper()); return makeFuture<T>(FutureNoTimekeeper());
} }
auto ctx = std::make_shared<Context>(std::move(e)); auto ctx = std::make_shared<Context>(std::move(e));
...@@ -1685,7 +1685,7 @@ Future<T> Future<T>::within(Duration dur, E e, Timekeeper* tk) { ...@@ -1685,7 +1685,7 @@ Future<T> Future<T>::within(Duration dur, E e, Timekeeper* tk) {
return; return;
} }
// "after" completed first, cancel "this" // "after" completed first, cancel "this"
lockedCtx->thisFuture.raise(TimedOut()); lockedCtx->thisFuture.raise(FutureTimeout());
if (lockedCtx->token.exchange(true) == false) { if (lockedCtx->token.exchange(true) == false) {
if (t.hasException()) { if (t.hasException()) {
lockedCtx->promise.setException(std::move(t.exception())); lockedCtx->promise.setException(std::move(t.exception()));
...@@ -1865,7 +1865,7 @@ Try<T> SemiFuture<T>::getTry(Duration dur) && { ...@@ -1865,7 +1865,7 @@ Try<T> SemiFuture<T>::getTry(Duration dur) && {
this->core_ = nullptr; this->core_ = nullptr;
if (!future.isReady()) { if (!future.isReady()) {
throw_exception<TimedOut>(); throw_exception<FutureTimeout>();
} }
return std::move(std::move(future).getTry()); return std::move(std::move(future).getTry());
} }
...@@ -1927,7 +1927,7 @@ template <class T> ...@@ -1927,7 +1927,7 @@ template <class T>
T Future<T>::get(Duration dur) { T Future<T>::get(Duration dur) {
wait(dur); wait(dur);
if (!this->isReady()) { if (!this->isReady()) {
throw_exception<TimedOut>(); throw_exception<FutureTimeout>();
} }
return std::move(this->value()); return std::move(this->value());
} }
...@@ -1946,7 +1946,7 @@ template <class T> ...@@ -1946,7 +1946,7 @@ template <class T>
T Future<T>::getVia(TimedDrivableExecutor* e, Duration dur) { T Future<T>::getVia(TimedDrivableExecutor* e, Duration dur) {
waitVia(e, dur); waitVia(e, dur);
if (!this->isReady()) { if (!this->isReady()) {
throw_exception<TimedOut>(); throw_exception<FutureTimeout>();
} }
return std::move(value()); return std::move(value());
} }
...@@ -1960,7 +1960,7 @@ template <class T> ...@@ -1960,7 +1960,7 @@ template <class T>
Try<T>& Future<T>::getTryVia(TimedDrivableExecutor* e, Duration dur) { Try<T>& Future<T>::getTryVia(TimedDrivableExecutor* e, Duration dur) {
waitVia(e, dur); waitVia(e, dur);
if (!this->isReady()) { if (!this->isReady()) {
throw_exception<TimedOut>(); throw_exception<FutureTimeout>();
} }
return result(); return result();
} }
...@@ -1994,7 +1994,7 @@ Future<T> Future<T>::filter(F&& predicate) { ...@@ -1994,7 +1994,7 @@ Future<T> Future<T>::filter(F&& predicate) {
return this->then([p = std::forward<F>(predicate)](T val) { return this->then([p = std::forward<F>(predicate)](T val) {
T const& valConstRef = val; T const& valConstRef = val;
if (!p(valConstRef)) { if (!p(valConstRef)) {
throw_exception<PredicateDoesNotObtain>(); throw_exception<FuturePredicateDoesNotObtain>();
} }
return val; return val;
}); });
......
...@@ -47,7 +47,7 @@ Future<Unit> sleep(Duration dur, Timekeeper* tk) { ...@@ -47,7 +47,7 @@ Future<Unit> sleep(Duration dur, Timekeeper* tk) {
} }
if (UNLIKELY(!tk)) { if (UNLIKELY(!tk)) {
return makeFuture<Unit>(NoTimekeeper()); return makeFuture<Unit>(FutureNoTimekeeper());
} }
return tk->after(dur); return tk->after(dur);
......
...@@ -46,6 +46,47 @@ ...@@ -46,6 +46,47 @@
namespace folly { namespace folly {
class FOLLY_EXPORT FutureException : public std::logic_error {
public:
using std::logic_error::logic_error;
};
class FOLLY_EXPORT FutureInvalid : public FutureException {
public:
FutureInvalid() : FutureException("Future invalid") {}
};
class FOLLY_EXPORT FutureNotReady : public FutureException {
public:
FutureNotReady() : FutureException("Future not ready") {}
};
class FOLLY_EXPORT FutureCancellation : public FutureException {
public:
FutureCancellation() : FutureException("Future was cancelled") {}
};
class FOLLY_EXPORT FutureTimeout : public FutureException {
public:
FutureTimeout() : FutureException("Timed out") {}
};
class FOLLY_EXPORT FuturePredicateDoesNotObtain : public FutureException {
public:
FuturePredicateDoesNotObtain()
: FutureException("Predicate does not obtain") {}
};
class FOLLY_EXPORT FutureNoTimekeeper : public FutureException {
public:
FutureNoTimekeeper() : FutureException("No timekeeper available") {}
};
class FOLLY_EXPORT FutureNoExecutor : public FutureException {
public:
FutureNoExecutor() : FutureException("No executor provided to via") {}
};
template <class T> template <class T>
class Future; class Future;
...@@ -101,7 +142,7 @@ class FutureBase { ...@@ -101,7 +142,7 @@ class FutureBase {
/// qualification equivalent to the reference category and const-qualification /// qualification equivalent to the reference category and const-qualification
/// of the receiver. /// of the receiver.
/// ///
/// If moved-from, throws NoState. /// If moved-from, throws FutureInvalid.
/// ///
/// If !isReady(), throws FutureNotReady. /// If !isReady(), throws FutureNotReady.
/// ///
...@@ -170,7 +211,8 @@ class FutureBase { ...@@ -170,7 +211,8 @@ class FutureBase {
using CoreType = futures::detail::Core<T>; using CoreType = futures::detail::Core<T>;
using corePtr = CoreType*; using corePtr = CoreType*;
// Throws NoState if there is no shared state object; else returns it by ref. // Throws FutureInvalid if there is no shared state object; else returns it
// by ref.
// //
// Implementation methods should usually use this instead of `this->core_`. // Implementation methods should usually use this instead of `this->core_`.
// The latter should be used only when you need the possibly-null pointer. // The latter should be used only when you need the possibly-null pointer.
...@@ -184,7 +226,7 @@ class FutureBase { ...@@ -184,7 +226,7 @@ class FutureBase {
template <typename Self> template <typename Self>
static decltype(auto) getCoreImpl(Self& self) { static decltype(auto) getCoreImpl(Self& self) {
if (!self.core_) { if (!self.core_) {
throw_exception<NoState>(); throw_exception<FutureInvalid>();
} }
return *self.core_; return *self.core_;
} }
...@@ -307,7 +349,7 @@ class SemiFuture : private futures::detail::FutureBase<T> { ...@@ -307,7 +349,7 @@ class SemiFuture : private futures::detail::FutureBase<T> {
T get() &&; T get() &&;
/// Block until the future is fulfilled, or until timed out. Returns the /// Block until the future is fulfilled, or until timed out. Returns the
/// value (moved out), or throws the exception (which might be a TimedOut /// value (moved out), or throws the exception (which might be a FutureTimeout
/// exception). /// exception).
T get(Duration dur) &&; T get(Duration dur) &&;
...@@ -316,7 +358,7 @@ class SemiFuture : private futures::detail::FutureBase<T> { ...@@ -316,7 +358,7 @@ class SemiFuture : private futures::detail::FutureBase<T> {
Try<T> getTry() &&; Try<T> getTry() &&;
/// Block until the future is fulfilled, or until timed out. Returns the /// Block until the future is fulfilled, or until timed out. Returns the
/// Try of the value (moved out) or may throw a TimedOut exception. /// Try of the value (moved out) or may throw a FutureTimeout exception.
Try<T> getTry(Duration dur) &&; Try<T> getTry(Duration dur) &&;
/// Block until this Future is complete. Returns a reference to this Future. /// Block until this Future is complete. Returns a reference to this Future.
...@@ -563,7 +605,7 @@ class Future : private futures::detail::FutureBase<T> { ...@@ -563,7 +605,7 @@ class Future : private futures::detail::FutureBase<T> {
T getVia(DrivableExecutor* e); T getVia(DrivableExecutor* e);
/// getVia but will wait only until timed out. Returns the /// getVia but will wait only until timed out. Returns the
/// Try of the value (moved out) or may throw a TimedOut exception. /// Try of the value (moved out) or may throw a FutureTimeout exception.
T getVia(TimedDrivableExecutor* e, Duration dur); T getVia(TimedDrivableExecutor* e, Duration dur);
/// Call e->drive() repeatedly until the future is fulfilled. Examples /// Call e->drive() repeatedly until the future is fulfilled. Examples
...@@ -572,7 +614,7 @@ class Future : private futures::detail::FutureBase<T> { ...@@ -572,7 +614,7 @@ class Future : private futures::detail::FutureBase<T> {
Try<T>& getTryVia(DrivableExecutor* e); Try<T>& getTryVia(DrivableExecutor* e);
/// getTryVia but will wait only until timed out. Returns the /// getTryVia but will wait only until timed out. Returns the
/// Try of the value (moved out) or may throw a TimedOut exception. /// Try of the value (moved out) or may throw a FutureTimeout exception.
Try<T>& getTryVia(TimedDrivableExecutor* e, Duration dur); Try<T>& getTryVia(TimedDrivableExecutor* e, Duration dur);
/// Unwraps the case of a Future<Future<T>> instance, and returns a simple /// Unwraps the case of a Future<Future<T>> instance, and returns a simple
...@@ -737,7 +779,7 @@ class Future : private futures::detail::FutureBase<T> { ...@@ -737,7 +779,7 @@ class Future : private futures::detail::FutureBase<T> {
template <class F> template <class F>
Future<T> onTimeout(Duration, F&& func, Timekeeper* = nullptr); Future<T> onTimeout(Duration, F&& func, Timekeeper* = nullptr);
/// Throw TimedOut if this Future does not complete within the given /// Throw FutureTimeout if this Future does not complete within the given
/// duration from now. The optional Timeekeeper is as with futures::sleep(). /// duration from now. The optional Timeekeeper is as with futures::sleep().
Future<T> within(Duration, Timekeeper* = nullptr); Future<T> within(Duration, Timekeeper* = nullptr);
...@@ -756,7 +798,7 @@ class Future : private futures::detail::FutureBase<T> { ...@@ -756,7 +798,7 @@ class Future : private futures::detail::FutureBase<T> {
T get(); T get();
/// Block until the future is fulfilled, or until timed out. Returns the /// Block until the future is fulfilled, or until timed out. Returns the
/// value (moved out), or throws the exception (which might be a TimedOut /// value (moved out), or throws the exception (which might be a FutureTimeout
/// exception). /// exception).
T get(Duration dur); T get(Duration dur);
...@@ -800,7 +842,7 @@ class Future : private futures::detail::FutureBase<T> { ...@@ -800,7 +842,7 @@ class Future : private futures::detail::FutureBase<T> {
/// predicate behaves like std::function<bool(T const&)> /// predicate behaves like std::function<bool(T const&)>
/// If the predicate does not obtain with the value, the result /// If the predicate does not obtain with the value, the result
/// is a folly::PredicateDoesNotObtain exception /// is a folly::FuturePredicateDoesNotObtain exception
template <class F> template <class F>
Future<T> filter(F&& predicate); Future<T> filter(F&& predicate);
......
/*
* Copyright 2014-present Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <stdexcept>
#include <string>
#include <folly/CPortability.h>
namespace folly {
class FOLLY_EXPORT FutureException : public std::logic_error {
public:
using std::logic_error::logic_error;
};
class FOLLY_EXPORT BrokenPromise : public FutureException {
public:
explicit BrokenPromise(const std::string& type)
: FutureException("Broken promise for type name `" + type + '`') {}
explicit BrokenPromise(const char* type) : BrokenPromise(std::string(type)) {}
};
class FOLLY_EXPORT NoState : public FutureException {
public:
NoState() : FutureException("No state") {}
};
class FOLLY_EXPORT PromiseAlreadySatisfied : public FutureException {
public:
PromiseAlreadySatisfied() : FutureException("Promise already satisfied") {}
};
class FOLLY_EXPORT FutureNotReady : public FutureException {
public:
FutureNotReady() : FutureException("Future not ready") {}
};
class FOLLY_EXPORT FutureAlreadyRetrieved : public FutureException {
public:
FutureAlreadyRetrieved() : FutureException("Future already retrieved") {}
};
class FOLLY_EXPORT FutureCancellation : public FutureException {
public:
FutureCancellation() : FutureException("Future was cancelled") {}
};
class FOLLY_EXPORT TimedOut : public FutureException {
public:
TimedOut() : FutureException("Timed out") {}
};
class FOLLY_EXPORT PredicateDoesNotObtain : public FutureException {
public:
PredicateDoesNotObtain() : FutureException("Predicate does not obtain") {}
};
class FOLLY_EXPORT NoFutureInSplitter : public FutureException {
public:
NoFutureInSplitter() : FutureException("No Future in this FutureSplitter") {}
};
class FOLLY_EXPORT NoTimekeeper : public FutureException {
public:
NoTimekeeper() : FutureException("No timekeeper available") {}
};
class FOLLY_EXPORT NoExecutor : public FutureException {
public:
NoExecutor() : FutureException("No executor provided to via") {}
};
} // namespace folly
...@@ -22,6 +22,12 @@ ...@@ -22,6 +22,12 @@
namespace folly { namespace folly {
class FOLLY_EXPORT FutureSplitterInvalid : public FutureException {
public:
FutureSplitterInvalid()
: FutureException("No Future in this FutureSplitter") {}
};
/* /*
* FutureSplitter provides a `getFuture()' method which can be called multiple * FutureSplitter provides a `getFuture()' method which can be called multiple
* times, returning a new Future each time. These futures are completed when the * times, returning a new Future each time. These futures are completed when the
...@@ -55,7 +61,7 @@ class FutureSplitter { ...@@ -55,7 +61,7 @@ class FutureSplitter {
*/ */
Future<T> getFuture() { Future<T> getFuture() {
if (promise_ == nullptr) { if (promise_ == nullptr) {
throw_exception<NoFutureInSplitter>(); throw_exception<FutureSplitterInvalid>();
} }
return promise_->getSemiFuture().via(e_); return promise_->getSemiFuture().via(e_);
} }
...@@ -65,7 +71,7 @@ class FutureSplitter { ...@@ -65,7 +71,7 @@ class FutureSplitter {
*/ */
SemiFuture<T> getSemiFuture() { SemiFuture<T> getSemiFuture() {
if (promise_ == nullptr) { if (promise_ == nullptr) {
throw_exception<NoFutureInSplitter>(); throw_exception<FutureSplitterInvalid>();
} }
return promise_->getSemiFuture(); return promise_->getSemiFuture();
} }
......
...@@ -20,7 +20,6 @@ ...@@ -20,7 +20,6 @@
#include <thread> #include <thread>
#include <folly/executors/InlineExecutor.h> #include <folly/executors/InlineExecutor.h>
#include <folly/futures/FutureException.h>
#include <folly/futures/detail/Core.h> #include <folly/futures/detail/Core.h>
namespace folly { namespace folly {
......
...@@ -20,11 +20,38 @@ ...@@ -20,11 +20,38 @@
#include <folly/Portability.h> #include <folly/Portability.h>
#include <folly/Try.h> #include <folly/Try.h>
#include <folly/futures/FutureException.h>
#include <folly/lang/Exception.h> #include <folly/lang/Exception.h>
namespace folly { namespace folly {
class FOLLY_EXPORT PromiseException : public std::logic_error {
public:
using std::logic_error::logic_error;
};
class FOLLY_EXPORT PromiseInvalid : public PromiseException {
public:
PromiseInvalid() : PromiseException("Promise invalid") {}
};
class FOLLY_EXPORT PromiseAlreadySatisfied : public PromiseException {
public:
PromiseAlreadySatisfied() : PromiseException("Promise already satisfied") {}
};
class FOLLY_EXPORT FutureAlreadyRetrieved : public PromiseException {
public:
FutureAlreadyRetrieved() : PromiseException("Future already retrieved") {}
};
class FOLLY_EXPORT BrokenPromise : public PromiseException {
public:
explicit BrokenPromise(const std::string& type)
: PromiseException("Broken promise for type name `" + type + '`') {}
explicit BrokenPromise(const char* type) : BrokenPromise(std::string(type)) {}
};
// forward declaration // forward declaration
template <class T> template <class T>
class SemiFuture; class SemiFuture;
...@@ -145,7 +172,8 @@ class Promise { ...@@ -145,7 +172,8 @@ class Promise {
using CoreType = typename Future<T>::CoreType; using CoreType = typename Future<T>::CoreType;
using corePtr = typename Future<T>::corePtr; using corePtr = typename Future<T>::corePtr;
// Throws NoState if there is no shared state object; else returns it by ref. // Throws PromiseInvalid if there is no shared state object; else returns it
// by ref.
// //
// Implementation methods should usually use this instead of `this->core_`. // Implementation methods should usually use this instead of `this->core_`.
// The latter should be used only when you need the possibly-null pointer. // The latter should be used only when you need the possibly-null pointer.
...@@ -159,7 +187,7 @@ class Promise { ...@@ -159,7 +187,7 @@ class Promise {
template <typename CoreT> template <typename CoreT>
static CoreT& getCoreImpl(CoreT* core) { static CoreT& getCoreImpl(CoreT* core) {
if (!core) { if (!core) {
throw_exception<NoState>(); throw_exception<PromiseInvalid>();
} }
return *core; return *core;
} }
......
...@@ -747,12 +747,12 @@ Although inspired by the C++11 std::future interface, it is not a drop-in replac ...@@ -747,12 +747,12 @@ Although inspired by the C++11 std::future interface, it is not a drop-in replac
<h2 id="within">within() <a href="#within" class="headerLink">#</a></h2> <h2 id="within">within() <a href="#within" class="headerLink">#</a></h2>
<p><tt>Future&lt;T&gt;::within()</tt> returns a new Future that will complete with the provided exception (by default, a TimedOut exception) if it does not complete within the specified duration. For example:</p> <p><tt>Future&lt;T&gt;::within()</tt> returns a new Future that will complete with the provided exception (by default, a FutureTimeout exception) if it does not complete within the specified duration. For example:</p>
<div class="remarkup-code-block" data-code-lang="cpp"><pre class="remarkup-code"><span class="k">using</span><span class=""> </span><span class="n">std</span><span class="o">:</span><span class="o">:</span><span class="n">chrono</span><span class="o">:</span><span class="o">:</span><span class="n">milliseconds</span><span class="p">;</span><span class=""> <div class="remarkup-code-block" data-code-lang="cpp"><pre class="remarkup-code"><span class="k">using</span><span class=""> </span><span class="n">std</span><span class="o">:</span><span class="o">:</span><span class="n">chrono</span><span class="o">:</span><span class="o">:</span><span class="n">milliseconds</span><span class="p">;</span><span class="">
</span><span class="n">Future</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span><span class=""> </span><span class="n">foo</span><span class="p">(</span><span class="p">)</span><span class="p">;</span><span class=""> </span><span class="n">Future</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span><span class=""> </span><span class="n">foo</span><span class="p">(</span><span class="p">)</span><span class="p">;</span><span class="">
</span><span class=""> </span><span class="">
</span><span class="c1">// f will complete with a TimedOut exception if the Future returned by foo() </span><span class="c1">// f will complete with a FutureTimeout exception if the Future returned by foo()
</span><span class="c1">// does not complete within 500 ms </span><span class="c1">// does not complete within 500 ms
</span><span class="n">f</span><span class=""> </span><span class="o">=</span><span class=""> </span><span class="n">foo</span><span class="p">(</span><span class="p">)</span><span class="p">.</span><span class="n">within</span><span class="p">(</span><span class="n">milliseconds</span><span class="p">(</span><span class="mi">500</span><span class="p">)</span><span class="p">)</span><span class="p">;</span><span class=""> </span><span class="n">f</span><span class=""> </span><span class="o">=</span><span class=""> </span><span class="n">foo</span><span class="p">(</span><span class="p">)</span><span class="p">.</span><span class="n">within</span><span class="p">(</span><span class="n">milliseconds</span><span class="p">(</span><span class="mi">500</span><span class="p">)</span><span class="p">)</span><span class="p">;</span><span class="">
</span><span class=""> </span><span class="">
...@@ -778,7 +778,7 @@ Although inspired by the C++11 std::future interface, it is not a drop-in replac ...@@ -778,7 +778,7 @@ Although inspired by the C++11 std::future interface, it is not a drop-in replac
<div class="remarkup-code-block" data-code-lang="cpp"><pre class="remarkup-code"><span class="n">foo</span><span class="p">(</span><span class="p">)</span><span class=""> <div class="remarkup-code-block" data-code-lang="cpp"><pre class="remarkup-code"><span class="n">foo</span><span class="p">(</span><span class="p">)</span><span class="">
</span><span class=""> </span><span class="p">.</span><span class="n">within</span><span class="p">(</span><span class="n">milliseconds</span><span class="p">(</span><span class="mi">500</span><span class="p">)</span><span class="p">)</span><span class=""> </span><span class=""> </span><span class="p">.</span><span class="n">within</span><span class="p">(</span><span class="n">milliseconds</span><span class="p">(</span><span class="mi">500</span><span class="p">)</span><span class="p">)</span><span class="">
</span><span class=""> </span><span class="p">.</span><span class="n">onError</span><span class="p">(</span><span class="p">[</span><span class="p">]</span><span class="p">(</span><span class="k">const</span><span class=""> </span><span class="n">TimedOut</span><span class="o">&amp;</span><span class=""> </span><span class="n">e</span><span class="p">)</span><span class=""> </span><span class="p">&#123;</span><span class=""> </span><span class=""> </span><span class="p">.</span><span class="n">onError</span><span class="p">(</span><span class="p">[</span><span class="p">]</span><span class="p">(</span><span class="k">const</span><span class=""> </span><span class="n">FutureTimeout</span><span class="o">&amp;</span><span class=""> </span><span class="n">e</span><span class="p">)</span><span class=""> </span><span class="p">&#123;</span><span class="">
</span><span class=""> </span><span class="c1">// handle timeout </span><span class=""> </span><span class="c1">// handle timeout
</span><span class=""> </span><span class="k">return</span><span class=""> </span><span class="o">-</span><span class="mi">1</span><span class="p">;</span><span class=""> </span><span class=""> </span><span class="k">return</span><span class=""> </span><span class="o">-</span><span class="mi">1</span><span class="p">;</span><span class="">
</span><span class=""> </span><span class="p">&#125;</span><span class="p">)</span><span class=""> </span><span class=""> </span><span class="p">&#125;</span><span class="p">)</span><span class="">
...@@ -790,7 +790,7 @@ Although inspired by the C++11 std::future interface, it is not a drop-in replac ...@@ -790,7 +790,7 @@ Although inspired by the C++11 std::future interface, it is not a drop-in replac
<p><tt>get()</tt> and <tt>wait()</tt>, which are detailed in the <a href="#testing">Testing</a> article, optionally take timeouts:</p> <p><tt>get()</tt> and <tt>wait()</tt>, which are detailed in the <a href="#testing">Testing</a> article, optionally take timeouts:</p>
<div class="remarkup-code-block" data-code-lang="cpp"><pre class="remarkup-code"><span class="n">Future</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span><span class=""> </span><span class="n">foo</span><span class="p">(</span><span class="p">)</span><span class="p">;</span><span class=""> <div class="remarkup-code-block" data-code-lang="cpp"><pre class="remarkup-code"><span class="n">Future</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span><span class=""> </span><span class="n">foo</span><span class="p">(</span><span class="p">)</span><span class="p">;</span><span class="">
</span><span class="c1">// Will throw TimedOut if the Future doesn&#039;t complete within one second of </span><span class="c1">// Will throw FutureTimeout if the Future doesn&#039;t complete within one second of
</span><span class="c1">// the get() call </span><span class="c1">// the get() call
</span><span class="kt">int</span><span class=""> </span><span class="n">result</span><span class=""> </span><span class="o">=</span><span class=""> </span><span class="n">foo</span><span class="p">(</span><span class="p">)</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="n">milliseconds</span><span class="p">(</span><span class="mi">1000</span><span class="p">)</span><span class="p">)</span><span class="p">;</span><span class=""> </span><span class="kt">int</span><span class=""> </span><span class="n">result</span><span class=""> </span><span class="o">=</span><span class=""> </span><span class="n">foo</span><span class="p">(</span><span class="p">)</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="n">milliseconds</span><span class="p">(</span><span class="mi">1000</span><span class="p">)</span><span class="p">)</span><span class="p">;</span><span class="">
</span><span class=""> </span><span class="">
...@@ -887,7 +887,7 @@ Although inspired by the C++11 std::future interface, it is not a drop-in replac ...@@ -887,7 +887,7 @@ Although inspired by the C++11 std::future interface, it is not a drop-in replac
<div class="remarkup-code-block" data-code-lang="cpp"><pre class="remarkup-code"><span class="n">EXPECT_TRUE</span><span class="p">(</span><span class="n">isPrime</span><span class="p">(</span><span class="mi">7</span><span class="p">)</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="p">)</span><span class="p">)</span><span class="p">;</span><span class=""> <div class="remarkup-code-block" data-code-lang="cpp"><pre class="remarkup-code"><span class="n">EXPECT_TRUE</span><span class="p">(</span><span class="n">isPrime</span><span class="p">(</span><span class="mi">7</span><span class="p">)</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="p">)</span><span class="p">)</span><span class="p">;</span><span class="">
</span></pre></div> </span></pre></div>
<p>Keep in mind that some other thread had better complete the Future, because the thread that calls <tt>get()</tt> will block. Also, <tt>get()</tt> optionally takes a timeout after which its throws a TimedOut exception. See the <a href="#timeouts-and-related-features">Timeouts</a> article for more information.</p> <p>Keep in mind that some other thread had better complete the Future, because the thread that calls <tt>get()</tt> will block. Also, <tt>get()</tt> optionally takes a timeout after which its throws a FutureTimeout exception. See the <a href="#timeouts-and-related-features">Timeouts</a> article for more information.</p>
<h3 id="wait">wait() <a href="#wait" class="headerLink">#</a></h3> <h3 id="wait">wait() <a href="#wait" class="headerLink">#</a></h3>
......
...@@ -71,7 +71,7 @@ struct WTCallback : public std::enable_shared_from_this<WTCallback>, ...@@ -71,7 +71,7 @@ struct WTCallback : public std::enable_shared_from_this<WTCallback>,
// Don't need Promise anymore, break the circular reference // Don't need Promise anymore, break the circular reference
auto promise = stealPromise(); auto promise = stealPromise();
if (!promise.isFulfilled()) { if (!promise.isFulfilled()) {
promise.setException(NoTimekeeper{}); promise.setException(FutureNoTimekeeper{});
} }
} }
...@@ -142,7 +142,7 @@ Future<Unit> ThreadWheelTimekeeper::after(Duration dur) { ...@@ -142,7 +142,7 @@ Future<Unit> ThreadWheelTimekeeper::after(Duration dur) {
// I don't see it is introducing any problem yet. // I don't see it is introducing any problem yet.
auto promise = cob->stealPromise(); auto promise = cob->stealPromise();
if (!promise.isFulfilled()) { if (!promise.isFulfilled()) {
promise.setException(NoTimekeeper{}); promise.setException(FutureNoTimekeeper{});
} }
} }
return f; return f;
......
...@@ -24,8 +24,9 @@ TEST(Filter, alwaysTrye) { ...@@ -24,8 +24,9 @@ TEST(Filter, alwaysTrye) {
} }
TEST(Filter, alwaysFalse) { TEST(Filter, alwaysFalse) {
EXPECT_THROW(makeFuture(42).filter([](int){ return false; }).get(), EXPECT_THROW(
folly::PredicateDoesNotObtain); makeFuture(42).filter([](int) { return false; }).get(),
folly::FuturePredicateDoesNotObtain);
} }
TEST(Filter, moveOnlyValue) { TEST(Filter, moveOnlyValue) {
......
...@@ -42,7 +42,7 @@ static eggs_t eggs("eggs"); ...@@ -42,7 +42,7 @@ static eggs_t eggs("eggs");
TEST(Future, makeEmpty) { TEST(Future, makeEmpty) {
auto f = Future<int>::makeEmpty(); auto f = Future<int>::makeEmpty();
EXPECT_THROW(f.isReady(), NoState); EXPECT_THROW(f.isReady(), FutureInvalid);
} }
TEST(Future, futureDefaultCtor) { TEST(Future, futureDefaultCtor) {
...@@ -147,7 +147,8 @@ TEST(Future, ctorPostconditionInvalid) { ...@@ -147,7 +147,8 @@ TEST(Future, ctorPostconditionInvalid) {
} }
TEST(Future, lacksPreconditionValid) { TEST(Future, lacksPreconditionValid) {
// Ops that don't throw NoState if !valid() -- without precondition: valid() // Ops that don't throw FutureInvalid if !valid() --
// without precondition: valid()
#define DOIT(STMT) \ #define DOIT(STMT) \
do { \ do { \
...@@ -179,14 +180,15 @@ TEST(Future, lacksPreconditionValid) { ...@@ -179,14 +180,15 @@ TEST(Future, lacksPreconditionValid) {
} }
TEST(Future, hasPreconditionValid) { TEST(Future, hasPreconditionValid) {
// Ops that require validity; precondition: valid(); throw NoState if !valid() // Ops that require validity; precondition: valid();
// throw FutureInvalid if !valid()
#define DOIT(STMT) \
do { \ #define DOIT(STMT) \
auto f = makeValid(); \ do { \
EXPECT_NO_THROW(STMT); \ auto f = makeValid(); \
copy(std::move(f)); \ EXPECT_NO_THROW(STMT); \
EXPECT_THROW(STMT, NoState); \ copy(std::move(f)); \
EXPECT_THROW(STMT, FutureInvalid); \
} while (false) } while (false)
DOIT(f.isReady()); DOIT(f.isReady());
......
...@@ -108,7 +108,8 @@ TEST(Promise, ctorPostconditionInvalid) { ...@@ -108,7 +108,8 @@ TEST(Promise, ctorPostconditionInvalid) {
} }
TEST(Promise, lacksPreconditionValid) { TEST(Promise, lacksPreconditionValid) {
// Ops that don't throw NoState if !valid() -- without precondition: valid() // Ops that don't throw PromiseInvalid if !valid() --
// without precondition: valid()
#define DOIT(STMT) \ #define DOIT(STMT) \
do { \ do { \
...@@ -141,14 +142,15 @@ TEST(Promise, lacksPreconditionValid) { ...@@ -141,14 +142,15 @@ TEST(Promise, lacksPreconditionValid) {
} }
TEST(Promise, hasPreconditionValid) { TEST(Promise, hasPreconditionValid) {
// Ops that require validity; precondition: valid(); throw NoState if !valid() // Ops that require validity; precondition: valid();
// throw PromiseInvalid if !valid()
#define DOIT(STMT) \
do { \ #define DOIT(STMT) \
auto p = makeValid(); \ do { \
EXPECT_NO_THROW(STMT); \ auto p = makeValid(); \
copy(std::move(p)); \ EXPECT_NO_THROW(STMT); \
EXPECT_THROW(STMT, NoState); \ copy(std::move(p)); \
EXPECT_THROW(STMT, PromiseInvalid); \
} while (false) } while (false)
auto const except = std::logic_error("foo"); auto const except = std::logic_error("foo");
......
...@@ -42,7 +42,7 @@ static eggs_t eggs("eggs"); ...@@ -42,7 +42,7 @@ static eggs_t eggs("eggs");
TEST(SemiFuture, makeEmpty) { TEST(SemiFuture, makeEmpty) {
auto f = SemiFuture<int>::makeEmpty(); auto f = SemiFuture<int>::makeEmpty();
EXPECT_THROW(f.isReady(), NoState); EXPECT_THROW(f.isReady(), FutureInvalid);
} }
TEST(SemiFuture, futureDefaultCtor) { TEST(SemiFuture, futureDefaultCtor) {
...@@ -121,7 +121,8 @@ TEST(SemiFuture, ctorPostconditionInvalid) { ...@@ -121,7 +121,8 @@ TEST(SemiFuture, ctorPostconditionInvalid) {
} }
TEST(SemiFuture, lacksPreconditionValid) { TEST(SemiFuture, lacksPreconditionValid) {
// Ops that don't throw NoState if !valid() -- without precondition: valid() // Ops that don't throw FutureInvalid if !valid() --
// without precondition: valid()
#define DOIT(STMT) \ #define DOIT(STMT) \
do { \ do { \
...@@ -153,14 +154,15 @@ TEST(SemiFuture, lacksPreconditionValid) { ...@@ -153,14 +154,15 @@ TEST(SemiFuture, lacksPreconditionValid) {
} }
TEST(SemiFuture, hasPreconditionValid) { TEST(SemiFuture, hasPreconditionValid) {
// Ops that require validity; precondition: valid(); throw NoState if !valid() // Ops that require validity; precondition: valid();
// throw FutureInvalid if !valid()
#define DOIT(STMT) \
do { \ #define DOIT(STMT) \
auto f = makeValid(); \ do { \
EXPECT_NO_THROW(STMT); \ auto f = makeValid(); \
copy(std::move(f)); \ EXPECT_NO_THROW(STMT); \
EXPECT_THROW(STMT, NoState); \ copy(std::move(f)); \
EXPECT_THROW(STMT, FutureInvalid); \
} while (false) } while (false)
DOIT(f.isReady()); DOIT(f.isReady());
...@@ -340,12 +342,12 @@ TEST(SemiFuture, makeSemiFutureNoThrow) { ...@@ -340,12 +342,12 @@ TEST(SemiFuture, makeSemiFutureNoThrow) {
} }
TEST(SemiFuture, ViaThrowOnNull) { TEST(SemiFuture, ViaThrowOnNull) {
EXPECT_THROW(makeSemiFuture().via(nullptr), NoExecutor); EXPECT_THROW(makeSemiFuture().via(nullptr), FutureNoExecutor);
} }
TEST(SemiFuture, ConstructSemiFutureFromEmptyFuture) { TEST(SemiFuture, ConstructSemiFutureFromEmptyFuture) {
auto f = SemiFuture<int>{Future<int>::makeEmpty()}; auto f = SemiFuture<int>{Future<int>::makeEmpty()};
EXPECT_THROW(f.isReady(), NoState); EXPECT_THROW(f.isReady(), FutureInvalid);
} }
TEST(SemiFuture, ConstructSemiFutureFromFutureDefaultCtor) { TEST(SemiFuture, ConstructSemiFutureFromFutureDefaultCtor) {
...@@ -481,7 +483,8 @@ TEST(SemiFuture, SimpleGetTry) { ...@@ -481,7 +483,8 @@ TEST(SemiFuture, SimpleGetTry) {
TEST(SemiFuture, SimpleTimedGet) { TEST(SemiFuture, SimpleTimedGet) {
Promise<folly::Unit> p; Promise<folly::Unit> p;
auto sf = p.getSemiFuture(); auto sf = p.getSemiFuture();
EXPECT_THROW(std::move(sf).get(std::chrono::milliseconds(100)), TimedOut); EXPECT_THROW(
std::move(sf).get(std::chrono::milliseconds(100)), FutureTimeout);
} }
TEST(SemiFuture, SimpleTimedWait) { TEST(SemiFuture, SimpleTimedWait) {
...@@ -510,13 +513,14 @@ TEST(SemiFuture, SimpleTimedGetViaFromSemiFuture) { ...@@ -510,13 +513,14 @@ TEST(SemiFuture, SimpleTimedGetViaFromSemiFuture) {
auto sf = p.getSemiFuture(); auto sf = p.getSemiFuture();
EXPECT_THROW( EXPECT_THROW(
std::move(sf).via(&e2).getVia(&e2, std::chrono::milliseconds(100)), std::move(sf).via(&e2).getVia(&e2, std::chrono::milliseconds(100)),
TimedOut); FutureTimeout);
} }
TEST(SemiFuture, SimpleTimedGetTry) { TEST(SemiFuture, SimpleTimedGetTry) {
Promise<folly::Unit> p; Promise<folly::Unit> p;
auto sf = p.getSemiFuture(); auto sf = p.getSemiFuture();
EXPECT_THROW(std::move(sf).getTry(std::chrono::milliseconds(100)), TimedOut); EXPECT_THROW(
std::move(sf).getTry(std::chrono::milliseconds(100)), FutureTimeout);
} }
TEST(SemiFuture, SimpleTimedGetTryViaFromSemiFuture) { TEST(SemiFuture, SimpleTimedGetTryViaFromSemiFuture) {
...@@ -525,7 +529,7 @@ TEST(SemiFuture, SimpleTimedGetTryViaFromSemiFuture) { ...@@ -525,7 +529,7 @@ TEST(SemiFuture, SimpleTimedGetTryViaFromSemiFuture) {
auto sf = p.getSemiFuture(); auto sf = p.getSemiFuture();
EXPECT_THROW( EXPECT_THROW(
std::move(sf).via(&e2).getTryVia(&e2, std::chrono::milliseconds(100)), std::move(sf).via(&e2).getTryVia(&e2, std::chrono::milliseconds(100)),
TimedOut); FutureTimeout);
} }
TEST(SemiFuture, SimpleValue) { TEST(SemiFuture, SimpleValue) {
...@@ -615,7 +619,8 @@ TEST(SemiFuture, DeferWithGetTimedGet) { ...@@ -615,7 +619,8 @@ TEST(SemiFuture, DeferWithGetTimedGet) {
Promise<folly::Unit> p; Promise<folly::Unit> p;
auto f = p.getSemiFuture().toUnsafeFuture(); auto f = p.getSemiFuture().toUnsafeFuture();
auto sf = std::move(f).semi().defer([&]() { innerResult = 17; }); auto sf = std::move(f).semi().defer([&]() { innerResult = 17; });
EXPECT_THROW(std::move(sf).get(std::chrono::milliseconds(100)), TimedOut); EXPECT_THROW(
std::move(sf).get(std::chrono::milliseconds(100)), FutureTimeout);
ASSERT_EQ(innerResult, 0); ASSERT_EQ(innerResult, 0);
} }
......
...@@ -71,7 +71,7 @@ TEST(Timekeeper, futureGetBeforeTimeout) { ...@@ -71,7 +71,7 @@ TEST(Timekeeper, futureGetBeforeTimeout) {
TEST(Timekeeper, futureGetTimeout) { TEST(Timekeeper, futureGetTimeout) {
Promise<int> p; Promise<int> p;
EXPECT_THROW(p.getFuture().get(one_ms), folly::TimedOut); EXPECT_THROW(p.getFuture().get(one_ms), folly::FutureTimeout);
} }
TEST(Timekeeper, futureSleep) { TEST(Timekeeper, futureSleep) {
...@@ -85,7 +85,7 @@ TEST(Timekeeper, futureSleepHandlesNullTimekeeperSingleton) { ...@@ -85,7 +85,7 @@ TEST(Timekeeper, futureSleepHandlesNullTimekeeperSingleton) {
SCOPE_EXIT { SCOPE_EXIT {
Singleton<ThreadWheelTimekeeper>::make_mock(); Singleton<ThreadWheelTimekeeper>::make_mock();
}; };
EXPECT_THROW(futures::sleep(one_ms).get(), NoTimekeeper); EXPECT_THROW(futures::sleep(one_ms).get(), FutureNoTimekeeper);
} }
TEST(Timekeeper, futureWithinHandlesNullTimekeeperSingleton) { TEST(Timekeeper, futureWithinHandlesNullTimekeeperSingleton) {
...@@ -95,7 +95,7 @@ TEST(Timekeeper, futureWithinHandlesNullTimekeeperSingleton) { ...@@ -95,7 +95,7 @@ TEST(Timekeeper, futureWithinHandlesNullTimekeeperSingleton) {
}; };
Promise<int> p; Promise<int> p;
auto f = p.getFuture().within(one_ms); auto f = p.getFuture().within(one_ms);
EXPECT_THROW(f.get(), NoTimekeeper); EXPECT_THROW(f.get(), FutureNoTimekeeper);
} }
TEST(Timekeeper, futureDelayed) { TEST(Timekeeper, futureDelayed) {
...@@ -110,17 +110,15 @@ TEST(Timekeeper, futureDelayed) { ...@@ -110,17 +110,15 @@ TEST(Timekeeper, futureDelayed) {
TEST(Timekeeper, futureWithinThrows) { TEST(Timekeeper, futureWithinThrows) {
Promise<int> p; Promise<int> p;
auto f = p.getFuture() auto f =
.within(one_ms) p.getFuture().within(one_ms).onError([](FutureTimeout&) { return -1; });
.onError([](TimedOut&) { return -1; });
EXPECT_EQ(-1, f.get()); EXPECT_EQ(-1, f.get());
} }
TEST(Timekeeper, futureWithinAlreadyComplete) { TEST(Timekeeper, futureWithinAlreadyComplete) {
auto f = makeFuture(42) auto f =
.within(one_ms) makeFuture(42).within(one_ms).onError([&](FutureTimeout&) { return -1; });
.onError([&](TimedOut&){ return -1; });
EXPECT_EQ(42, f.get()); EXPECT_EQ(42, f.get());
} }
...@@ -128,8 +126,8 @@ TEST(Timekeeper, futureWithinAlreadyComplete) { ...@@ -128,8 +126,8 @@ TEST(Timekeeper, futureWithinAlreadyComplete) {
TEST(Timekeeper, futureWithinFinishesInTime) { TEST(Timekeeper, futureWithinFinishesInTime) {
Promise<int> p; Promise<int> p;
auto f = p.getFuture() auto f = p.getFuture()
.within(std::chrono::minutes(1)) .within(std::chrono::minutes(1))
.onError([&](TimedOut&){ return -1; }); .onError([&](FutureTimeout&) { return -1; });
p.setValue(42); p.setValue(42);
EXPECT_EQ(42, f.get()); EXPECT_EQ(42, f.get());
...@@ -236,7 +234,7 @@ TEST(Timekeeper, onTimeoutPropagates) { ...@@ -236,7 +234,7 @@ TEST(Timekeeper, onTimeoutPropagates) {
makeFuture(42).delayed(one_ms) makeFuture(42).delayed(one_ms)
.onTimeout(zero_ms, [&]{ flag = true; }) .onTimeout(zero_ms, [&]{ flag = true; })
.get(), .get(),
TimedOut); FutureTimeout);
EXPECT_TRUE(flag); EXPECT_TRUE(flag);
} }
*/ */
......
...@@ -404,7 +404,7 @@ TEST(Via, SimpleTimedGetVia) { ...@@ -404,7 +404,7 @@ TEST(Via, SimpleTimedGetVia) {
TimedDrivableExecutor e2; TimedDrivableExecutor e2;
Promise<folly::Unit> p; Promise<folly::Unit> p;
auto f = p.getFuture(); auto f = p.getFuture();
EXPECT_THROW(f.getVia(&e2, std::chrono::seconds(1)), TimedOut); EXPECT_THROW(f.getVia(&e2, std::chrono::seconds(1)), FutureTimeout);
} }
TEST(Via, getTryVia) { TEST(Via, getTryVia) {
...@@ -437,7 +437,7 @@ TEST(Via, SimpleTimedGetTryVia) { ...@@ -437,7 +437,7 @@ TEST(Via, SimpleTimedGetTryVia) {
TimedDrivableExecutor e2; TimedDrivableExecutor e2;
Promise<folly::Unit> p; Promise<folly::Unit> p;
auto f = p.getFuture(); auto f = p.getFuture();
EXPECT_THROW(f.getTryVia(&e2, std::chrono::seconds(1)), TimedOut); EXPECT_THROW(f.getTryVia(&e2, std::chrono::seconds(1)), FutureTimeout);
} }
TEST(Via, waitVia) { TEST(Via, waitVia) {
......
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