Commit e845ef57 authored by Hans Fugal's avatar Hans Fugal Committed by Sara Golemon

Nuke Future<void> (folly/futures)

Summary: Nuke Future<void> in favor of Future<Unit>, for the `folly/futures` subdirectory.

Reviewed By: @djwatson

Differential Revision: D2201259
parent 489ab051
...@@ -51,7 +51,7 @@ Future<T>::Future(T2&& val) ...@@ -51,7 +51,7 @@ Future<T>::Future(T2&& val)
template <class T> template <class T>
template <typename, typename> template <typename, typename>
Future<T>::Future() Future<T>::Future()
: core_(new detail::Core<T>(Try<T>())) {} : core_(new detail::Core<T>(Try<T>(T()))) {}
template <class T> template <class T>
Future<T>::~Future() { Future<T>::~Future() {
...@@ -226,7 +226,7 @@ auto Future<T>::then(Executor* x, Arg&& arg, Args&&... args) ...@@ -226,7 +226,7 @@ auto Future<T>::then(Executor* x, Arg&& arg, Args&&... args)
} }
template <class T> template <class T>
Future<void> Future<T>::then() { Future<Unit> Future<T>::then() {
return then([] () {}); return then([] () {});
} }
...@@ -432,8 +432,6 @@ inline Future<T> Future<T>::via(Executor* executor, int8_t priority) & { ...@@ -432,8 +432,6 @@ inline Future<T> Future<T>::via(Executor* executor, int8_t priority) & {
template <class Func> template <class Func>
auto via(Executor* x, Func func) auto via(Executor* x, Func func)
-> Future<typename isFuture<decltype(func())>::Inner> -> Future<typename isFuture<decltype(func())>::Inner>
// this would work, if not for Future<void> :-/
// -> decltype(via(x).then(func))
{ {
// TODO make this actually more performant. :-P #7260175 // TODO make this actually more performant. :-P #7260175
return via(x).then(func); return via(x).then(func);
...@@ -468,24 +466,29 @@ Future<typename std::decay<T>::type> makeFuture(T&& t) { ...@@ -468,24 +466,29 @@ Future<typename std::decay<T>::type> makeFuture(T&& t) {
} }
inline // for multiple translation units inline // for multiple translation units
Future<void> makeFuture() { Future<Unit> makeFuture() {
return makeFuture(Try<void>()); return makeFuture(Unit{});
} }
// XXX why is the dual necessary here? Can't we just use perfect forwarding
// and capture func by reference always?
template <class F> template <class F>
auto makeFutureWith( auto makeFutureWith(
F&& func, F&& func,
typename std::enable_if<!std::is_reference<F>::value, bool>::type sdf) typename std::enable_if<!std::is_reference<F>::value, bool>::type sdf)
-> Future<decltype(func())> { -> Future<typename Unit::Lift<decltype(func())>::type> {
return makeFuture(makeTryWith([&func]() { using LiftedResult = typename Unit::Lift<decltype(func())>::type;
return makeFuture<LiftedResult>(makeTryWith([&func]() {
return (func)(); return (func)();
})); }));
} }
template <class F> template <class F>
auto makeFutureWith(F const& func) -> Future<decltype(func())> { auto makeFutureWith(F const& func)
-> Future<typename Unit::Lift<decltype(func())>::type> {
F copy = func; F copy = func;
return makeFuture(makeTryWith(std::move(copy))); using LiftedResult = typename Unit::Lift<decltype(func())>::type;
return makeFuture<LiftedResult>(makeTryWith(std::move(copy)));
} }
template <class T> template <class T>
...@@ -511,7 +514,7 @@ Future<T> makeFuture(Try<T>&& t) { ...@@ -511,7 +514,7 @@ Future<T> makeFuture(Try<T>&& t) {
} }
// via // via
Future<void> via(Executor* executor, int8_t priority) { Future<Unit> via(Executor* executor, int8_t priority) {
return makeFuture().via(executor, priority); return makeFuture().via(executor, priority);
} }
...@@ -603,14 +606,6 @@ struct CollectContext { ...@@ -603,14 +606,6 @@ struct CollectContext {
std::atomic<bool> threw {false}; std::atomic<bool> threw {false};
}; };
// Specialize for void (implementations in Future.cpp)
template <>
CollectContext<void>::~CollectContext();
template <>
void CollectContext<void>::setPartialResult(size_t i, Try<void>& t);
} }
template <class InputIterator> template <class InputIterator>
...@@ -884,7 +879,7 @@ Future<T> Future<T>::within(Duration dur, E e, Timekeeper* tk) { ...@@ -884,7 +879,7 @@ Future<T> Future<T>::within(Duration dur, E e, Timekeeper* tk) {
} }
tk->after(dur) tk->after(dur)
.then([ctx](Try<void> const& t) { .then([ctx](Try<Unit> const& t) {
if (ctx->token.exchange(true) == false) { if (ctx->token.exchange(true) == false) {
if (t.hasException()) { if (t.hasException()) {
ctx->promise.setException(std::move(t.exception())); ctx->promise.setException(std::move(t.exception()));
...@@ -908,7 +903,7 @@ Future<T> Future<T>::within(Duration dur, E e, Timekeeper* tk) { ...@@ -908,7 +903,7 @@ Future<T> Future<T>::within(Duration dur, E e, Timekeeper* tk) {
template <class T> template <class T>
Future<T> Future<T>::delayed(Duration dur, Timekeeper* tk) { Future<T> Future<T>::delayed(Duration dur, Timekeeper* tk) {
return collectAll(*this, futures::sleep(dur, tk)) return collectAll(*this, futures::sleep(dur, tk))
.then([](std::tuple<Try<T>, Try<void>> tup) { .then([](std::tuple<Try<T>, Try<Unit>> tup) {
Try<T>& t = std::get<0>(tup); Try<T>& t = std::get<0>(tup);
return makeFuture<T>(std::move(t)); return makeFuture<T>(std::move(t));
}); });
...@@ -1007,11 +1002,6 @@ T Future<T>::get() { ...@@ -1007,11 +1002,6 @@ T Future<T>::get() {
return std::move(wait().value()); return std::move(wait().value());
} }
template <>
inline void Future<void>::get() {
wait().value();
}
template <class T> template <class T>
T Future<T>::get(Duration dur) { T Future<T>::get(Duration dur) {
wait(dur); wait(dur);
...@@ -1022,26 +1012,11 @@ T Future<T>::get(Duration dur) { ...@@ -1022,26 +1012,11 @@ T Future<T>::get(Duration dur) {
} }
} }
template <>
inline void Future<void>::get(Duration dur) {
wait(dur);
if (isReady()) {
return;
} else {
throw TimedOut();
}
}
template <class T> template <class T>
T Future<T>::getVia(DrivableExecutor* e) { T Future<T>::getVia(DrivableExecutor* e) {
return std::move(waitVia(e).value()); return std::move(waitVia(e).value());
} }
template <>
inline void Future<void>::getVia(DrivableExecutor* e) {
waitVia(e).value();
}
namespace detail { namespace detail {
template <class T> template <class T>
struct TryEquals { struct TryEquals {
...@@ -1049,13 +1024,6 @@ namespace detail { ...@@ -1049,13 +1024,6 @@ namespace detail {
return t1.value() == t2.value(); return t1.value() == t2.value();
} }
}; };
template <>
struct TryEquals<void> {
static bool equals(const Try<void>& t1, const Try<void>& t2) {
return true;
}
};
} }
template <class T> template <class T>
...@@ -1134,7 +1102,7 @@ namespace futures { ...@@ -1134,7 +1102,7 @@ namespace futures {
} }
// Instantiate the most common Future types to save compile time // Instantiate the most common Future types to save compile time
extern template class Future<void>; extern template class Future<Unit>;
extern template class Future<bool>; extern template class Future<bool>;
extern template class Future<int>; extern template class Future<int>;
extern template class Future<int64_t>; extern template class Future<int64_t>;
...@@ -1142,8 +1110,3 @@ extern template class Future<std::string>; ...@@ -1142,8 +1110,3 @@ extern template class Future<std::string>;
extern template class Future<double>; extern template class Future<double>;
} // namespace folly } // namespace folly
// I haven't included a Future<T&> specialization because I don't forsee us
// using it, however it is not difficult to add when needed. Refer to
// Future<void> for guidance. std::future and boost::future code would also be
// instructive.
...@@ -24,7 +24,7 @@ template <class> class Promise; ...@@ -24,7 +24,7 @@ template <class> class Promise;
template <typename T> template <typename T>
struct isFuture : std::false_type { struct isFuture : std::false_type {
typedef T Inner; using Inner = typename Unit::Lift<T>::type;
}; };
template <typename T> template <typename T>
...@@ -63,7 +63,7 @@ struct ArgType<> { ...@@ -63,7 +63,7 @@ struct ArgType<> {
template <bool isTry, typename F, typename... Args> template <bool isTry, typename F, typename... Args>
struct argResult { struct argResult {
typedef resultOf<F, Args...> Result; using Result = resultOf<F, Args...>;
}; };
template<typename F, typename... Args> template<typename F, typename... Args>
...@@ -100,19 +100,6 @@ struct callableResult { ...@@ -100,19 +100,6 @@ struct callableResult {
typedef Future<typename ReturnsFuture::Inner> Return; typedef Future<typename ReturnsFuture::Inner> Return;
}; };
template<typename F>
struct callableResult<void, F> {
typedef typename std::conditional<
callableWith<F>::value,
detail::argResult<false, F>,
typename std::conditional<
callableWith<F, Try<void>&&>::value,
detail::argResult<true, F, Try<void>&&>,
detail::argResult<true, F, Try<void>&>>::type>::type Arg;
typedef isFuture<typename Arg::Result> ReturnsFuture;
typedef Future<typename ReturnsFuture::Inner> Return;
};
template <typename L> template <typename L>
struct Extract : Extract<decltype(&L::operator())> { }; struct Extract : Extract<decltype(&L::operator())> { };
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
namespace folly { namespace folly {
// Instantiate the most common Future types to save compile time // Instantiate the most common Future types to save compile time
template class Future<void>; template class Future<Unit>;
template class Future<bool>; template class Future<bool>;
template class Future<int>; template class Future<int>;
template class Future<int64_t>; template class Future<int64_t>;
...@@ -31,7 +31,7 @@ template class Future<double>; ...@@ -31,7 +31,7 @@ template class Future<double>;
namespace folly { namespace futures { namespace folly { namespace futures {
Future<void> sleep(Duration dur, Timekeeper* tk) { Future<Unit> sleep(Duration dur, Timekeeper* tk) {
if (LIKELY(!tk)) { if (LIKELY(!tk)) {
tk = detail::getTimekeeperSingleton(); tk = detail::getTimekeeperSingleton();
} }
...@@ -39,19 +39,3 @@ Future<void> sleep(Duration dur, Timekeeper* tk) { ...@@ -39,19 +39,3 @@ Future<void> sleep(Duration dur, Timekeeper* tk) {
} }
}} }}
namespace folly { namespace detail {
template <>
CollectContext<void>::~CollectContext() {
if (!threw.exchange(true)) {
p.setValue();
}
}
template <>
void CollectContext<void>::setPartialResult(size_t i, Try<void>& t) {
// Nothing to do for void
}
}}
...@@ -62,7 +62,7 @@ class Future { ...@@ -62,7 +62,7 @@ class Future {
template <class T2 = T, typename = template <class T2 = T, typename =
typename std::enable_if< typename std::enable_if<
folly::is_void_or_unit<T2>::value>::type> std::is_same<Unit, T2>::value>::type>
Future(); Future();
~Future(); ~Future();
...@@ -202,9 +202,9 @@ class Future { ...@@ -202,9 +202,9 @@ class Future {
-> decltype(this->then(std::forward<Arg>(arg), -> decltype(this->then(std::forward<Arg>(arg),
std::forward<Args>(args)...)); std::forward<Args>(args)...));
/// Convenience method for ignoring the value and creating a Future<void>. /// Convenience method for ignoring the value and creating a Future<Unit>.
/// Exceptions still propagate. /// Exceptions still propagate.
Future<void> then(); Future<Unit> then();
/// Set an error callback for this Future. The callback should take a single /// Set an error callback for this Future. The callback should take a single
/// argument of the type that you want to catch, and should return a value of /// argument of the type that you want to catch, and should return a value of
......
...@@ -70,13 +70,6 @@ public: ...@@ -70,13 +70,6 @@ public:
/// handled. /// handled.
void setInterruptHandler(std::function<void(exception_wrapper const&)>); void setInterruptHandler(std::function<void(exception_wrapper const&)>);
/// Fulfill this Promise<void>
template <class B = T>
typename std::enable_if<std::is_void<B>::value, void>::type
setValue() {
setTry(Try<T>());
}
/// Sugar to fulfill this Promise<Unit> /// Sugar to fulfill this Promise<Unit>
template <class B = T> template <class B = T>
typename std::enable_if<std::is_same<Unit, B>::value, void>::type typename std::enable_if<std::is_same<Unit, B>::value, void>::type
......
...@@ -81,13 +81,6 @@ public: ...@@ -81,13 +81,6 @@ public:
/// handled. /// handled.
void setInterruptHandler(std::function<void(exception_wrapper const&)>); void setInterruptHandler(std::function<void(exception_wrapper const&)>);
/// Fulfill this SharedPromise<void>
template <class B = T>
typename std::enable_if<std::is_void<B>::value, void>::type
setValue() {
setTry(Try<T>());
}
/// Sugar to fulfill this SharedPromise<Unit> /// Sugar to fulfill this SharedPromise<Unit>
template <class B = T> template <class B = T>
typename std::enable_if<std::is_same<Unit, B>::value, void>::type typename std::enable_if<std::is_same<Unit, B>::value, void>::type
......
...@@ -17,13 +17,14 @@ ...@@ -17,13 +17,14 @@
#pragma once #pragma once
#include <folly/futures/detail/Types.h> #include <folly/futures/detail/Types.h>
#include <folly/futures/Unit.h>
namespace folly { namespace folly {
template <class> class Future; template <class> class Future;
/// A Timekeeper handles the details of keeping time and fulfilling delay /// A Timekeeper handles the details of keeping time and fulfilling delay
/// promises. The returned Future<void> will either complete after the /// promises. The returned Future<Unit> will either complete after the
/// elapsed time, or in the event of some kind of exceptional error may hold /// elapsed time, or in the event of some kind of exceptional error may hold
/// an exception. These Futures respond to cancellation. If you use a lot of /// an exception. These Futures respond to cancellation. If you use a lot of
/// Delays and many of them ultimately are unneeded (as would be the case for /// Delays and many of them ultimately are unneeded (as would be the case for
...@@ -34,7 +35,7 @@ template <class> class Future; ...@@ -34,7 +35,7 @@ template <class> class Future;
/// use them implicitly behind the scenes by passing a timeout to some Future /// use them implicitly behind the scenes by passing a timeout to some Future
/// operation. /// operation.
/// ///
/// Although we don't formally alias Delay = Future<void>, /// Although we don't formally alias Delay = Future<Unit>,
/// that's an appropriate term for it. People will probably also call these /// that's an appropriate term for it. People will probably also call these
/// Timeouts, and that's ok I guess, but that term is so overloaded I thought /// Timeouts, and that's ok I guess, but that term is so overloaded I thought
/// it made sense to introduce a cleaner term. /// it made sense to introduce a cleaner term.
...@@ -54,7 +55,7 @@ class Timekeeper { ...@@ -54,7 +55,7 @@ class Timekeeper {
/// This future probably completes on the timer thread. You should almost /// This future probably completes on the timer thread. You should almost
/// certainly follow it with a via() call or the accuracy of other timers /// certainly follow it with a via() call or the accuracy of other timers
/// will suffer. /// will suffer.
virtual Future<void> after(Duration) = 0; virtual Future<Unit> after(Duration) = 0;
/// Returns a future that will complete at the requested time. /// Returns a future that will complete at the requested time.
/// ///
...@@ -65,7 +66,7 @@ class Timekeeper { ...@@ -65,7 +66,7 @@ class Timekeeper {
/// the system clock but rather execute that many milliseconds in the future /// the system clock but rather execute that many milliseconds in the future
/// according to the steady clock. /// according to the steady clock.
template <class Clock> template <class Clock>
Future<void> at(std::chrono::time_point<Clock> when); Future<Unit> at(std::chrono::time_point<Clock> when);
}; };
} // namespace folly } // namespace folly
...@@ -77,7 +78,7 @@ class Timekeeper { ...@@ -77,7 +78,7 @@ class Timekeeper {
namespace folly { namespace folly {
template <class Clock> template <class Clock>
Future<void> Timekeeper::at(std::chrono::time_point<Clock> when) { Future<Unit> Timekeeper::at(std::chrono::time_point<Clock> when) {
auto now = Clock::now(); auto now = Clock::now();
if (when <= now) { if (when <= now) {
......
...@@ -31,6 +31,21 @@ Try<T>::Try(Try<T>&& t) noexcept : contains_(t.contains_) { ...@@ -31,6 +31,21 @@ Try<T>::Try(Try<T>&& t) noexcept : contains_(t.contains_) {
} }
} }
template <class T>
template <class T2>
Try<T>::Try(typename std::enable_if<std::is_same<Unit, T2>::value,
Try<void> const&>::type t)
: contains_(Contains::NOTHING) {
if (t.hasValue()) {
contains_ = Contains::VALUE;
new (&value_) T();
} else if (t.hasException()) {
contains_ = Contains::EXCEPTION;
new (&e_) std::unique_ptr<exception_wrapper>(
folly::make_unique<exception_wrapper>(t.exception()));
}
}
template <class T> template <class T>
Try<T>& Try<T>::operator=(Try<T>&& t) noexcept { Try<T>& Try<T>::operator=(Try<T>&& t) noexcept {
if (this == &t) { if (this == &t) {
......
...@@ -35,8 +35,7 @@ namespace folly { ...@@ -35,8 +35,7 @@ namespace folly {
* context. Exceptions are stored as exception_wrappers so that the user can * context. Exceptions are stored as exception_wrappers so that the user can
* minimize rethrows if so desired. * minimize rethrows if so desired.
* *
* There is a specialization, Try<void>, which represents either success * To represent success or a captured exception, use Try<Unit>
* or an exception.
*/ */
template <class T> template <class T>
class Try { class Try {
...@@ -74,6 +73,12 @@ class Try { ...@@ -74,6 +73,12 @@ class Try {
*/ */
explicit Try(T&& v) : contains_(Contains::VALUE), value_(std::move(v)) {} explicit Try(T&& v) : contains_(Contains::VALUE), value_(std::move(v)) {}
/// Implicit conversion from Try<void> to Try<Unit>
template <class T2 = T>
/* implicit */
Try(typename std::enable_if<std::is_same<Unit, T2>::value,
Try<void> const&>::type t);
/* /*
* Construct a Try with an exception_wrapper * Construct a Try with an exception_wrapper
* *
...@@ -364,7 +369,7 @@ typename std::enable_if< ...@@ -364,7 +369,7 @@ typename std::enable_if<
makeTryWith(F&& f); makeTryWith(F&& f);
/* /*
* Specialization of makeTryWith for void * Specialization of makeTryWith for void return
* *
* @param f a function to execute and capture the result of * @param f a function to execute and capture the result of
* *
......
...@@ -22,8 +22,6 @@ namespace folly { ...@@ -22,8 +22,6 @@ namespace folly {
/// metaprogramming. So, instead of e.g. Future<void>, we have Future<Unit>. /// metaprogramming. So, instead of e.g. Future<void>, we have Future<Unit>.
/// You can ignore the actual value, and we port some of the syntactic /// You can ignore the actual value, and we port some of the syntactic
/// niceties like setValue() instead of setValue(Unit{}). /// niceties like setValue() instead of setValue(Unit{}).
// We will soon return Future<Unit> wherever we currently return Future<void>
// #6847876
struct Unit { struct Unit {
/// Lift type T into Unit. This is the definition for all non-void types. /// Lift type T into Unit. This is the definition for all non-void types.
template <class T> struct Lift : public std::false_type { template <class T> struct Lift : public std::false_type {
......
...@@ -32,13 +32,13 @@ namespace { ...@@ -32,13 +32,13 @@ namespace {
return new WTCallback(base); return new WTCallback(base);
} }
Future<void> getFuture() { Future<Unit> getFuture() {
return promise_.getFuture(); return promise_.getFuture();
} }
protected: protected:
EventBase* base_; EventBase* base_;
Promise<void> promise_; Promise<Unit> promise_;
explicit WTCallback(EventBase* base) explicit WTCallback(EventBase* base)
: base_(base) { : base_(base) {
...@@ -81,7 +81,7 @@ ThreadWheelTimekeeper::~ThreadWheelTimekeeper() { ...@@ -81,7 +81,7 @@ ThreadWheelTimekeeper::~ThreadWheelTimekeeper() {
thread_.join(); thread_.join();
} }
Future<void> ThreadWheelTimekeeper::after(Duration dur) { Future<Unit> ThreadWheelTimekeeper::after(Duration dur) {
auto cob = WTCallback::create(&eventBase_); auto cob = WTCallback::create(&eventBase_);
auto f = cob->getFuture(); auto f = cob->getFuture();
eventBase_.runInEventBaseThread([=]{ eventBase_.runInEventBaseThread([=]{
......
...@@ -37,7 +37,7 @@ class ThreadWheelTimekeeper : public Timekeeper { ...@@ -37,7 +37,7 @@ class ThreadWheelTimekeeper : public Timekeeper {
/// This future *does* complete on the timer thread. You should almost /// This future *does* complete on the timer thread. You should almost
/// certainly follow it with a via() call or the accuracy of other timers /// certainly follow it with a via() call or the accuracy of other timers
/// will suffer. /// will suffer.
Future<void> after(Duration) override; Future<Unit> after(Duration) override;
protected: protected:
folly::EventBase eventBase_; folly::EventBase eventBase_;
......
...@@ -37,7 +37,7 @@ namespace futures { ...@@ -37,7 +37,7 @@ namespace futures {
/// The Timekeeper thread will be lazily created the first time it is /// The Timekeeper thread will be lazily created the first time it is
/// needed. If your program never uses any timeouts or other time-based /// needed. If your program never uses any timeouts or other time-based
/// Futures you will pay no Timekeeper thread overhead. /// Futures you will pay no Timekeeper thread overhead.
Future<void> sleep(Duration, Timekeeper* = nullptr); Future<Unit> sleep(Duration, Timekeeper* = nullptr);
/** /**
* Set func as the callback for each input Future and return a vector of * Set func as the callback for each input Future and return a vector of
...@@ -72,21 +72,19 @@ template <class T> ...@@ -72,21 +72,19 @@ template <class T>
Future<typename std::decay<T>::type> makeFuture(T&& t); Future<typename std::decay<T>::type> makeFuture(T&& t);
/** Make a completed void Future. */ /** Make a completed void Future. */
Future<void> makeFuture(); Future<Unit> makeFuture();
/** Make a completed Future by executing a function. If the function throws /** Make a completed Future by executing a function. If the function throws
we capture the exception, otherwise we capture the result. */ we capture the exception, otherwise we capture the result. */
template <class F> template <class F>
auto makeFutureWith( auto makeFutureWith(
F&& func, F&& func,
typename std::enable_if< typename std::enable_if<!std::is_reference<F>::value, bool>::type sdf)
!std::is_reference<F>::value, bool>::type sdf = false) -> Future<typename Unit::Lift<decltype(func())>::type>;
-> Future<decltype(func())>;
template <class F> template <class F>
auto makeFutureWith( auto makeFutureWith(F const& func)
F const& func) -> Future<typename Unit::Lift<decltype(func())>::type>;
-> Future<decltype(func())>;
/// Make a failed Future from an exception_ptr. /// Make a failed Future from an exception_ptr.
/// Because the Future's type cannot be inferred you have to specify it, e.g. /// Because the Future's type cannot be inferred you have to specify it, e.g.
...@@ -120,7 +118,7 @@ Future<T> makeFuture(Try<T>&& t); ...@@ -120,7 +118,7 @@ Future<T> makeFuture(Try<T>&& t);
* *
* @returns a void Future that will call back on the given executor * @returns a void Future that will call back on the given executor
*/ */
inline Future<void> via( inline Future<Unit> via(
Executor* executor, Executor* executor,
int8_t priority = Executor::MID_PRI); int8_t priority = Executor::MID_PRI);
......
...@@ -170,8 +170,8 @@ BENCHMARK_DRAW_LINE(); ...@@ -170,8 +170,8 @@ BENCHMARK_DRAW_LINE();
// The old way. Throw an exception, and rethrow to access it upstream. // The old way. Throw an exception, and rethrow to access it upstream.
void throwAndCatchImpl() { void throwAndCatchImpl() {
makeFuture() makeFuture()
.then([](Try<void>&&){ throw std::runtime_error("oh no"); }) .then([](Try<Unit>&&){ throw std::runtime_error("oh no"); })
.then([](Try<void>&& t) { .then([](Try<Unit>&& t) {
try { try {
t.value(); t.value();
} catch(const std::runtime_error& e) { } catch(const std::runtime_error& e) {
...@@ -190,8 +190,8 @@ void throwAndCatchImpl() { ...@@ -190,8 +190,8 @@ void throwAndCatchImpl() {
// will try to wrap, so no exception_ptrs/rethrows are necessary. // will try to wrap, so no exception_ptrs/rethrows are necessary.
void throwAndCatchWrappedImpl() { void throwAndCatchWrappedImpl() {
makeFuture() makeFuture()
.then([](Try<void>&&){ throw std::runtime_error("oh no"); }) .then([](Try<Unit>&&){ throw std::runtime_error("oh no"); })
.then([](Try<void>&& t) { .then([](Try<Unit>&& t) {
auto caught = t.withException<std::runtime_error>( auto caught = t.withException<std::runtime_error>(
[](const std::runtime_error& e){ [](const std::runtime_error& e){
// ... // ...
...@@ -203,10 +203,10 @@ void throwAndCatchWrappedImpl() { ...@@ -203,10 +203,10 @@ void throwAndCatchWrappedImpl() {
// Better. Wrap an exception, and rethrow to access it upstream. // Better. Wrap an exception, and rethrow to access it upstream.
void throwWrappedAndCatchImpl() { void throwWrappedAndCatchImpl() {
makeFuture() makeFuture()
.then([](Try<void>&&){ .then([](Try<Unit>&&){
return makeFuture<void>(std::runtime_error("oh no")); return makeFuture<Unit>(std::runtime_error("oh no"));
}) })
.then([](Try<void>&& t) { .then([](Try<Unit>&& t) {
try { try {
t.value(); t.value();
} catch(const std::runtime_error& e) { } catch(const std::runtime_error& e) {
...@@ -220,10 +220,10 @@ void throwWrappedAndCatchImpl() { ...@@ -220,10 +220,10 @@ void throwWrappedAndCatchImpl() {
// The new way. Wrap an exception, and access it via the wrapper upstream // The new way. Wrap an exception, and access it via the wrapper upstream
void throwWrappedAndCatchWrappedImpl() { void throwWrappedAndCatchWrappedImpl() {
makeFuture() makeFuture()
.then([](Try<void>&&){ .then([](Try<Unit>&&){
return makeFuture<void>(std::runtime_error("oh no")); return makeFuture<Unit>(std::runtime_error("oh no"));
}) })
.then([](Try<void>&& t){ .then([](Try<Unit>&& t){
auto caught = t.withException<std::runtime_error>( auto caught = t.withException<std::runtime_error>(
[](const std::runtime_error& e){ [](const std::runtime_error& e){
// ... // ...
......
...@@ -87,14 +87,14 @@ TEST(Collect, collectAll) { ...@@ -87,14 +87,14 @@ TEST(Collect, collectAll) {
// check that futures are ready in then() // check that futures are ready in then()
{ {
std::vector<Promise<void>> promises(10); std::vector<Promise<Unit>> promises(10);
std::vector<Future<void>> futures; std::vector<Future<Unit>> futures;
for (auto& p : promises) for (auto& p : promises)
futures.push_back(p.getFuture()); futures.push_back(p.getFuture());
auto allf = collectAll(futures) auto allf = collectAll(futures)
.then([](Try<std::vector<Try<void>>>&& ts) { .then([](Try<std::vector<Try<Unit>>>&& ts) {
for (auto& f : ts.value()) for (auto& f : ts.value())
f.value(); f.value();
}); });
...@@ -166,8 +166,8 @@ TEST(Collect, collect) { ...@@ -166,8 +166,8 @@ TEST(Collect, collect) {
// void futures success case // void futures success case
{ {
std::vector<Promise<void>> promises(10); std::vector<Promise<Unit>> promises(10);
std::vector<Future<void>> futures; std::vector<Future<Unit>> futures;
for (auto& p : promises) for (auto& p : promises)
futures.push_back(p.getFuture()); futures.push_back(p.getFuture());
...@@ -185,8 +185,8 @@ TEST(Collect, collect) { ...@@ -185,8 +185,8 @@ TEST(Collect, collect) {
// void futures failure case // void futures failure case
{ {
std::vector<Promise<void>> promises(10); std::vector<Promise<Unit>> promises(10);
std::vector<Future<void>> futures; std::vector<Future<Unit>> futures;
for (auto& p : promises) for (auto& p : promises)
futures.push_back(p.getFuture()); futures.push_back(p.getFuture());
...@@ -294,8 +294,8 @@ TEST(Collect, collectAny) { ...@@ -294,8 +294,8 @@ TEST(Collect, collectAny) {
// error // error
{ {
std::vector<Promise<void>> promises(10); std::vector<Promise<Unit>> promises(10);
std::vector<Future<void>> futures; std::vector<Future<Unit>> futures;
for (auto& p : promises) for (auto& p : promises)
futures.push_back(p.getFuture()); futures.push_back(p.getFuture());
...@@ -334,12 +334,12 @@ TEST(Collect, collectAny) { ...@@ -334,12 +334,12 @@ TEST(Collect, collectAny) {
TEST(Collect, alreadyCompleted) { TEST(Collect, alreadyCompleted) {
{ {
std::vector<Future<void>> fs; std::vector<Future<Unit>> fs;
for (int i = 0; i < 10; i++) for (int i = 0; i < 10; i++)
fs.push_back(makeFuture()); fs.push_back(makeFuture());
collectAll(fs) collectAll(fs)
.then([&](std::vector<Try<void>> ts) { .then([&](std::vector<Try<Unit>> ts) {
EXPECT_EQ(fs.size(), ts.size()); EXPECT_EQ(fs.size(), ts.size());
}); });
} }
...@@ -484,8 +484,8 @@ TEST(Collect, allParallelWithError) { ...@@ -484,8 +484,8 @@ TEST(Collect, allParallelWithError) {
} }
TEST(Collect, collectN) { TEST(Collect, collectN) {
std::vector<Promise<void>> promises(10); std::vector<Promise<Unit>> promises(10);
std::vector<Future<void>> futures; std::vector<Future<Unit>> futures;
for (auto& p : promises) for (auto& p : promises)
futures.push_back(p.getFuture()); futures.push_back(p.getFuture());
...@@ -493,7 +493,7 @@ TEST(Collect, collectN) { ...@@ -493,7 +493,7 @@ TEST(Collect, collectN) {
bool flag = false; bool flag = false;
size_t n = 3; size_t n = 3;
collectN(futures, n) collectN(futures, n)
.then([&](std::vector<std::pair<size_t, Try<void>>> v) { .then([&](std::vector<std::pair<size_t, Try<Unit>>> v) {
flag = true; flag = true;
EXPECT_EQ(n, v.size()); EXPECT_EQ(n, v.size());
for (auto& tt : v) for (auto& tt : v)
...@@ -510,13 +510,13 @@ TEST(Collect, collectN) { ...@@ -510,13 +510,13 @@ TEST(Collect, collectN) {
/// Ensure that we can compile collectAll/Any with folly::small_vector /// Ensure that we can compile collectAll/Any with folly::small_vector
TEST(Collect, smallVector) { TEST(Collect, smallVector) {
static_assert(!FOLLY_IS_TRIVIALLY_COPYABLE(Future<void>), static_assert(!FOLLY_IS_TRIVIALLY_COPYABLE(Future<Unit>),
"Futures should not be trivially copyable"); "Futures should not be trivially copyable");
static_assert(!FOLLY_IS_TRIVIALLY_COPYABLE(Future<int>), static_assert(!FOLLY_IS_TRIVIALLY_COPYABLE(Future<int>),
"Futures should not be trivially copyable"); "Futures should not be trivially copyable");
{ {
folly::small_vector<Future<void>> futures; folly::small_vector<Future<Unit>> futures;
for (int i = 0; i < 10; i++) for (int i = 0; i < 10; i++)
futures.push_back(makeFuture()); futures.push_back(makeFuture());
...@@ -524,7 +524,7 @@ TEST(Collect, smallVector) { ...@@ -524,7 +524,7 @@ TEST(Collect, smallVector) {
auto anyf = collectAny(futures); auto anyf = collectAny(futures);
} }
{ {
folly::small_vector<Future<void>> futures; folly::small_vector<Future<Unit>> futures;
for (int i = 0; i < 10; i++) for (int i = 0; i < 10; i++)
futures.push_back(makeFuture()); futures.push_back(makeFuture());
......
...@@ -40,7 +40,7 @@ TEST(Context, basic) { ...@@ -40,7 +40,7 @@ TEST(Context, basic) {
std::unique_ptr<TestData>(new TestData(10))); std::unique_ptr<TestData>(new TestData(10)));
// Start a future // Start a future
Promise<void> p; Promise<Unit> p;
auto future = p.getFuture().then([&]{ auto future = p.getFuture().then([&]{
// Check that the context followed the future // Check that the context followed the future
EXPECT_TRUE(RequestContext::get() != nullptr); EXPECT_TRUE(RequestContext::get() != nullptr);
......
...@@ -24,5 +24,5 @@ using namespace folly; ...@@ -24,5 +24,5 @@ using namespace folly;
TEST(Core, size) { TEST(Core, size) {
// If this number goes down, it's fine! // If this number goes down, it's fine!
// If it goes up, please seek professional advice ;-) // If it goes up, please seek professional advice ;-)
EXPECT_EQ(192, sizeof(detail::Core<void>)); EXPECT_EQ(192, sizeof(detail::Core<Unit>));
} }
...@@ -95,7 +95,7 @@ TEST(ManualExecutor, waitForDoesNotDeadlock) { ...@@ -95,7 +95,7 @@ TEST(ManualExecutor, waitForDoesNotDeadlock) {
folly::Baton<> baton; folly::Baton<> baton;
auto f = makeFuture() auto f = makeFuture()
.via(&east) .via(&east)
.then([](Try<void>){ return makeFuture(); }) .then([](Try<Unit>){ return makeFuture(); })
.via(&west); .via(&west);
std::thread t([&]{ std::thread t([&]{
baton.post(); baton.post();
...@@ -162,7 +162,7 @@ TEST(Executor, RunnablePtr) { ...@@ -162,7 +162,7 @@ TEST(Executor, RunnablePtr) {
TEST(Executor, ThrowableThen) { TEST(Executor, ThrowableThen) {
InlineExecutor x; InlineExecutor x;
auto f = Future<void>().via(&x).then([](){ auto f = Future<Unit>().via(&x).then([](){
throw std::runtime_error("Faildog"); throw std::runtime_error("Faildog");
}); });
EXPECT_THROW(f.value(), std::exception); EXPECT_THROW(f.value(), std::exception);
......
...@@ -320,11 +320,11 @@ TEST(Future, thenTry) { ...@@ -320,11 +320,11 @@ TEST(Future, thenTry) {
.then([&](Try<int>&& t) { flag = true; EXPECT_EQ(42, t.value()); }); .then([&](Try<int>&& t) { flag = true; EXPECT_EQ(42, t.value()); });
EXPECT_TRUE(flag); flag = false; EXPECT_TRUE(flag); flag = false;
makeFuture().then([&](Try<void>&& t) { flag = true; t.value(); }); makeFuture().then([&](Try<Unit>&& t) { flag = true; t.value(); });
EXPECT_TRUE(flag); flag = false; EXPECT_TRUE(flag); flag = false;
Promise<void> p; Promise<Unit> p;
auto f = p.getFuture().then([&](Try<void>&& t) { flag = true; }); auto f = p.getFuture().then([&](Try<Unit>&& t) { flag = true; });
EXPECT_FALSE(flag); EXPECT_FALSE(flag);
EXPECT_FALSE(f.isReady()); EXPECT_FALSE(f.isReady());
p.setValue(); p.setValue();
...@@ -353,7 +353,7 @@ TEST(Future, thenValue) { ...@@ -353,7 +353,7 @@ TEST(Future, thenValue) {
auto f = makeFuture<int>(eggs).then([&](int i){}); auto f = makeFuture<int>(eggs).then([&](int i){});
EXPECT_THROW(f.value(), eggs_t); EXPECT_THROW(f.value(), eggs_t);
f = makeFuture<void>(eggs).then([&]{}); f = makeFuture<Unit>(eggs).then([&]{});
EXPECT_THROW(f.value(), eggs_t); EXPECT_THROW(f.value(), eggs_t);
} }
...@@ -366,7 +366,7 @@ TEST(Future, thenValueFuture) { ...@@ -366,7 +366,7 @@ TEST(Future, thenValueFuture) {
makeFuture() makeFuture()
.then([]{ return makeFuture(); }) .then([]{ return makeFuture(); })
.then([&](Try<void>&& t) { flag = true; }); .then([&](Try<Unit>&& t) { flag = true; });
EXPECT_TRUE(flag); flag = false; EXPECT_TRUE(flag); flag = false;
} }
...@@ -505,7 +505,7 @@ TEST(Future, makeFuture) { ...@@ -505,7 +505,7 @@ TEST(Future, makeFuture) {
EXPECT_TYPE(makeFutureWith(failfun), Future<int>); EXPECT_TYPE(makeFutureWith(failfun), Future<int>);
EXPECT_THROW(makeFutureWith(failfun).value(), eggs_t); EXPECT_THROW(makeFutureWith(failfun).value(), eggs_t);
EXPECT_TYPE(makeFuture(), Future<void>); EXPECT_TYPE(makeFuture(), Future<Unit>);
} }
TEST(Future, finish) { TEST(Future, finish) {
...@@ -568,18 +568,18 @@ TEST(Future, unwrap) { ...@@ -568,18 +568,18 @@ TEST(Future, unwrap) {
TEST(Future, throwCaughtInImmediateThen) { TEST(Future, throwCaughtInImmediateThen) {
// Neither of these should throw "Promise already satisfied" // Neither of these should throw "Promise already satisfied"
makeFuture().then( makeFuture().then(
[=](Try<void>&&) -> int { throw std::exception(); }); [=](Try<Unit>&&) -> int { throw std::exception(); });
makeFuture().then( makeFuture().then(
[=](Try<void>&&) -> Future<int> { throw std::exception(); }); [=](Try<Unit>&&) -> Future<int> { throw std::exception(); });
} }
TEST(Future, throwIfFailed) { TEST(Future, throwIfFailed) {
makeFuture<void>(eggs) makeFuture<Unit>(eggs)
.then([=](Try<void>&& t) { .then([=](Try<Unit>&& t) {
EXPECT_THROW(t.throwIfFailed(), eggs_t); EXPECT_THROW(t.throwIfFailed(), eggs_t);
}); });
makeFuture() makeFuture()
.then([=](Try<void>&& t) { .then([=](Try<Unit>&& t) {
EXPECT_NO_THROW(t.throwIfFailed()); EXPECT_NO_THROW(t.throwIfFailed());
}); });
...@@ -600,7 +600,7 @@ TEST(Future, getFutureAfterSetValue) { ...@@ -600,7 +600,7 @@ TEST(Future, getFutureAfterSetValue) {
} }
TEST(Future, getFutureAfterSetException) { TEST(Future, getFutureAfterSetException) {
Promise<void> p; Promise<Unit> p;
p.setWith([]() -> void { throw std::logic_error("foo"); }); p.setWith([]() -> void { throw std::logic_error("foo"); });
EXPECT_THROW(p.getFuture().value(), std::logic_error); EXPECT_THROW(p.getFuture().value(), std::logic_error);
} }
...@@ -655,7 +655,7 @@ TEST(Future, CircularDependencySharedPtrSelfReset) { ...@@ -655,7 +655,7 @@ TEST(Future, CircularDependencySharedPtrSelfReset) {
TEST(Future, Constructor) { TEST(Future, Constructor) {
auto f1 = []() -> Future<int> { return Future<int>(3); }(); auto f1 = []() -> Future<int> { return Future<int>(3); }();
EXPECT_EQ(f1.value(), 3); EXPECT_EQ(f1.value(), 3);
auto f2 = []() -> Future<void> { return Future<void>(); }(); auto f2 = []() -> Future<Unit> { return Future<Unit>(); }();
EXPECT_NO_THROW(f2.value()); EXPECT_NO_THROW(f2.value());
} }
...@@ -664,7 +664,7 @@ TEST(Future, ImplicitConstructor) { ...@@ -664,7 +664,7 @@ TEST(Future, ImplicitConstructor) {
EXPECT_EQ(f1.value(), 3); EXPECT_EQ(f1.value(), 3);
// Unfortunately, the C++ standard does not allow the // Unfortunately, the C++ standard does not allow the
// following implicit conversion to work: // following implicit conversion to work:
//auto f2 = []() -> Future<void> { }(); //auto f2 = []() -> Future<Unit> { }();
} }
TEST(Future, thenDynamic) { TEST(Future, thenDynamic) {
...@@ -734,3 +734,7 @@ TEST(Future, RequestContext) { ...@@ -734,3 +734,7 @@ TEST(Future, RequestContext) {
p1.setValue(3); p1.setValue(3);
p2.setValue(4); p2.setValue(4);
} }
TEST(Future, makeFutureNoThrow) {
makeFuture().value();
}
...@@ -23,7 +23,7 @@ using namespace folly; ...@@ -23,7 +23,7 @@ using namespace folly;
TEST(Interrupt, raise) { TEST(Interrupt, raise) {
std::runtime_error eggs("eggs"); std::runtime_error eggs("eggs");
Promise<void> p; Promise<Unit> p;
p.setInterruptHandler([&](const exception_wrapper& e) { p.setInterruptHandler([&](const exception_wrapper& e) {
EXPECT_THROW(e.throwException(), decltype(eggs)); EXPECT_THROW(e.throwException(), decltype(eggs));
}); });
...@@ -31,7 +31,7 @@ TEST(Interrupt, raise) { ...@@ -31,7 +31,7 @@ TEST(Interrupt, raise) {
} }
TEST(Interrupt, cancel) { TEST(Interrupt, cancel) {
Promise<void> p; Promise<Unit> p;
p.setInterruptHandler([&](const exception_wrapper& e) { p.setInterruptHandler([&](const exception_wrapper& e) {
EXPECT_THROW(e.throwException(), FutureCancellation); EXPECT_THROW(e.throwException(), FutureCancellation);
}); });
...@@ -55,7 +55,7 @@ TEST(Interrupt, interruptThenHandle) { ...@@ -55,7 +55,7 @@ TEST(Interrupt, interruptThenHandle) {
} }
TEST(Interrupt, interruptAfterFulfilNoop) { TEST(Interrupt, interruptAfterFulfilNoop) {
Promise<void> p; Promise<Unit> p;
bool flag = false; bool flag = false;
p.setInterruptHandler([&](const exception_wrapper& e) { flag = true; }); p.setInterruptHandler([&](const exception_wrapper& e) { flag = true; });
p.setValue(); p.setValue();
...@@ -64,7 +64,7 @@ TEST(Interrupt, interruptAfterFulfilNoop) { ...@@ -64,7 +64,7 @@ TEST(Interrupt, interruptAfterFulfilNoop) {
} }
TEST(Interrupt, secondInterruptNoop) { TEST(Interrupt, secondInterruptNoop) {
Promise<void> p; Promise<Unit> p;
int count = 0; int count = 0;
p.setInterruptHandler([&](const exception_wrapper& e) { count++; }); p.setInterruptHandler([&](const exception_wrapper& e) { count++; });
auto f = p.getFuture(); auto f = p.getFuture();
......
...@@ -31,7 +31,7 @@ TEST(Map, basic) { ...@@ -31,7 +31,7 @@ TEST(Map, basic) {
fs.push_back(p3.getFuture()); fs.push_back(p3.getFuture());
int c = 0; int c = 0;
std::vector<Future<void>> fs2 = futures::map(fs, [&](int i){ std::vector<Future<Unit>> fs2 = futures::map(fs, [&](int i){
c += i; c += i;
}); });
......
...@@ -34,7 +34,7 @@ TEST(Poll, notReady) { ...@@ -34,7 +34,7 @@ TEST(Poll, notReady) {
} }
TEST(Poll, exception) { TEST(Poll, exception) {
Promise<void> p; Promise<Unit> p;
auto f = p.getFuture(); auto f = p.getFuture();
p.setWith([] { throw std::runtime_error("Runtime"); }); p.setWith([] { throw std::runtime_error("Runtime"); });
EXPECT_TRUE(f.poll().value().hasException()); EXPECT_TRUE(f.poll().value().hasException());
......
...@@ -70,7 +70,7 @@ TEST(Promise, setValue) { ...@@ -70,7 +70,7 @@ TEST(Promise, setValue) {
unique_ptr<int> ptr = std::move(fmov.value()); unique_ptr<int> ptr = std::move(fmov.value());
EXPECT_EQ(42, *ptr); EXPECT_EQ(42, *ptr);
Promise<void> v; Promise<Unit> v;
auto fv = v.getFuture(); auto fv = v.getFuture();
v.setValue(); v.setValue();
EXPECT_TRUE(fv.isReady()); EXPECT_TRUE(fv.isReady());
...@@ -78,13 +78,13 @@ TEST(Promise, setValue) { ...@@ -78,13 +78,13 @@ TEST(Promise, setValue) {
TEST(Promise, setException) { TEST(Promise, setException) {
{ {
Promise<void> p; Promise<Unit> p;
auto f = p.getFuture(); auto f = p.getFuture();
p.setException(eggs); p.setException(eggs);
EXPECT_THROW(f.value(), eggs_t); EXPECT_THROW(f.value(), eggs_t);
} }
{ {
Promise<void> p; Promise<Unit> p;
auto f = p.getFuture(); auto f = p.getFuture();
try { try {
throw eggs; throw eggs;
......
...@@ -123,7 +123,7 @@ TEST(Timekeeper, futureWithinVoidSpecialization) { ...@@ -123,7 +123,7 @@ TEST(Timekeeper, futureWithinVoidSpecialization) {
} }
TEST(Timekeeper, futureWithinException) { TEST(Timekeeper, futureWithinException) {
Promise<void> p; Promise<Unit> p;
auto f = p.getFuture().within(awhile, std::runtime_error("expected")); auto f = p.getFuture().within(awhile, std::runtime_error("expected"));
EXPECT_THROW(f.get(), std::runtime_error); EXPECT_THROW(f.get(), std::runtime_error);
} }
...@@ -150,7 +150,7 @@ TEST(Timekeeper, onTimeoutVoid) { ...@@ -150,7 +150,7 @@ TEST(Timekeeper, onTimeoutVoid) {
}); });
makeFuture().delayed(one_ms) makeFuture().delayed(one_ms)
.onTimeout(Duration(0), [&]{ .onTimeout(Duration(0), [&]{
return makeFuture<void>(std::runtime_error("expected")); return makeFuture<Unit>(std::runtime_error("expected"));
}); });
// just testing compilation here // just testing compilation here
} }
......
...@@ -36,7 +36,7 @@ TEST(Try, basic) { ...@@ -36,7 +36,7 @@ TEST(Try, basic) {
A a(5); A a(5);
Try<A> t_a(std::move(a)); Try<A> t_a(std::move(a));
Try<void> t_void; Try<Unit> t_void;
EXPECT_EQ(5, t_a.value().x()); EXPECT_EQ(5, t_a.value().x());
} }
......
...@@ -35,7 +35,7 @@ TEST(Unit, operatorNe) { ...@@ -35,7 +35,7 @@ TEST(Unit, operatorNe) {
} }
TEST(Unit, voidOrUnit) { TEST(Unit, voidOrUnit) {
EXPECT_TRUE(is_void_or_unit<void>::value); EXPECT_TRUE(is_void_or_unit<Unit>::value);
EXPECT_TRUE(is_void_or_unit<Unit>::value); EXPECT_TRUE(is_void_or_unit<Unit>::value);
EXPECT_FALSE(is_void_or_unit<int>::value); EXPECT_FALSE(is_void_or_unit<int>::value);
} }
...@@ -53,7 +53,7 @@ TEST(Unit, liftInt) { ...@@ -53,7 +53,7 @@ TEST(Unit, liftInt) {
} }
TEST(Unit, liftVoid) { TEST(Unit, liftVoid) {
using Lifted = Unit::Lift<void>; using Lifted = Unit::Lift<Unit>;
EXPECT_TRUE(Lifted::value); EXPECT_TRUE(Lifted::value);
auto v = std::is_same<Unit, Lifted::type>::value; auto v = std::is_same<Unit, Lifted::type>::value;
EXPECT_TRUE(v); EXPECT_TRUE(v);
...@@ -68,7 +68,7 @@ TEST(Unit, futureToUnit) { ...@@ -68,7 +68,7 @@ TEST(Unit, futureToUnit) {
TEST(Unit, voidFutureToUnit) { TEST(Unit, voidFutureToUnit) {
Future<Unit> fu = makeFuture().unit(); Future<Unit> fu = makeFuture().unit();
fu.value(); fu.value();
EXPECT_TRUE(makeFuture<void>(eggs).unit().hasException()); EXPECT_TRUE(makeFuture<Unit>(eggs).unit().hasException());
} }
TEST(Unit, unitFutureToUnitIdentity) { TEST(Unit, unitFutureToUnitIdentity) {
...@@ -84,3 +84,9 @@ TEST(Unit, toUnitWhileInProgress) { ...@@ -84,3 +84,9 @@ TEST(Unit, toUnitWhileInProgress) {
p.setValue(42); p.setValue(42);
EXPECT_TRUE(fu.isReady()); EXPECT_TRUE(fu.isReady());
} }
TEST(Unit, makeFutureWith) {
int count = 0;
Future<Unit> fu = makeFutureWith([&]{ count++; });
EXPECT_EQ(1, count);
}
...@@ -124,7 +124,7 @@ TEST(Via, thenFunction) { ...@@ -124,7 +124,7 @@ TEST(Via, thenFunction) {
TEST_F(ViaFixture, threadHops) { TEST_F(ViaFixture, threadHops) {
auto westThreadId = std::this_thread::get_id(); auto westThreadId = std::this_thread::get_id();
auto f = via(eastExecutor.get()).then([=](Try<void>&& t) { auto f = via(eastExecutor.get()).then([=](Try<Unit>&& t) {
EXPECT_NE(std::this_thread::get_id(), westThreadId); EXPECT_NE(std::this_thread::get_id(), westThreadId);
return makeFuture<int>(1); return makeFuture<int>(1);
}).via(westExecutor.get() }).via(westExecutor.get()
...@@ -283,7 +283,7 @@ TEST(Via, then2) { ...@@ -283,7 +283,7 @@ TEST(Via, then2) {
} }
TEST(Via, then2Variadic) { TEST(Via, then2Variadic) {
struct Foo { bool a = false; void foo(Try<void>) { a = true; } }; struct Foo { bool a = false; void foo(Try<Unit>) { a = true; } };
Foo f; Foo f;
ManualExecutor x; ManualExecutor x;
makeFuture().then(&x, &Foo::foo, &f); makeFuture().then(&x, &Foo::foo, &f);
...@@ -345,14 +345,14 @@ TEST(Via, callbackRace) { ...@@ -345,14 +345,14 @@ TEST(Via, callbackRace) {
ThreadExecutor x; ThreadExecutor x;
auto fn = [&x]{ auto fn = [&x]{
auto promises = std::make_shared<std::vector<Promise<void>>>(4); auto promises = std::make_shared<std::vector<Promise<Unit>>>(4);
std::vector<Future<void>> futures; std::vector<Future<Unit>> futures;
for (auto& p : *promises) { for (auto& p : *promises) {
futures.emplace_back( futures.emplace_back(
p.getFuture() p.getFuture()
.via(&x) .via(&x)
.then([](Try<void>&&){})); .then([](Try<Unit>&&){}));
} }
x.waitForStartup(); x.waitForStartup();
...@@ -424,16 +424,16 @@ TEST(Via, waitVia) { ...@@ -424,16 +424,16 @@ TEST(Via, waitVia) {
TEST(Via, viaRaces) { TEST(Via, viaRaces) {
ManualExecutor x; ManualExecutor x;
Promise<void> p; Promise<Unit> p;
auto tid = std::this_thread::get_id(); auto tid = std::this_thread::get_id();
bool done = false; bool done = false;
std::thread t1([&] { std::thread t1([&] {
p.getFuture() p.getFuture()
.via(&x) .via(&x)
.then([&](Try<void>&&) { EXPECT_EQ(tid, std::this_thread::get_id()); }) .then([&](Try<Unit>&&) { EXPECT_EQ(tid, std::this_thread::get_id()); })
.then([&](Try<void>&&) { EXPECT_EQ(tid, std::this_thread::get_id()); }) .then([&](Try<Unit>&&) { EXPECT_EQ(tid, std::this_thread::get_id()); })
.then([&](Try<void>&&) { done = true; }); .then([&](Try<Unit>&&) { done = true; });
}); });
std::thread t2([&] { std::thread t2([&] {
...@@ -448,7 +448,7 @@ TEST(Via, viaRaces) { ...@@ -448,7 +448,7 @@ TEST(Via, viaRaces) {
TEST(ViaFunc, liftsVoid) { TEST(ViaFunc, liftsVoid) {
ManualExecutor x; ManualExecutor x;
int count = 0; int count = 0;
Future<void> f = via(&x, [&]{ count++; }); Future<Unit> f = via(&x, [&]{ count++; });
EXPECT_EQ(0, count); EXPECT_EQ(0, count);
x.run(); x.run();
......
...@@ -34,7 +34,7 @@ TEST(Wait, waitImmediate) { ...@@ -34,7 +34,7 @@ TEST(Wait, waitImmediate) {
EXPECT_EQ(v.size(), done_v.size()); EXPECT_EQ(v.size(), done_v.size());
EXPECT_EQ(v, done_v); EXPECT_EQ(v, done_v);
vector<Future<void>> v_f; vector<Future<Unit>> v_f;
v_f.push_back(makeFuture()); v_f.push_back(makeFuture());
v_f.push_back(makeFuture()); v_f.push_back(makeFuture());
auto done_v_f = collectAll(v_f).wait().value(); auto done_v_f = collectAll(v_f).wait().value();
...@@ -169,7 +169,7 @@ TEST(Wait, waitWithDuration) { ...@@ -169,7 +169,7 @@ TEST(Wait, waitWithDuration) {
} }
{ {
Promise<void> p; Promise<Unit> p;
auto start = std::chrono::steady_clock::now(); auto start = std::chrono::steady_clock::now();
auto f = p.getFuture().wait(milliseconds(100)); auto f = p.getFuture().wait(milliseconds(100));
auto elapsed = std::chrono::steady_clock::now() - start; auto elapsed = std::chrono::steady_clock::now() - start;
...@@ -182,7 +182,7 @@ TEST(Wait, waitWithDuration) { ...@@ -182,7 +182,7 @@ TEST(Wait, waitWithDuration) {
{ {
// Try to trigger the race where the resultant Future is not yet complete // Try to trigger the race where the resultant Future is not yet complete
// even if we didn't hit the timeout, and make sure we deal with it properly // even if we didn't hit the timeout, and make sure we deal with it properly
Promise<void> p; Promise<Unit> p;
folly::Baton<> b; folly::Baton<> b;
auto t = std::thread([&]{ auto t = std::thread([&]{
b.post(); b.post();
......
...@@ -57,14 +57,14 @@ TEST(Window, basic) { ...@@ -57,14 +57,14 @@ TEST(Window, basic) {
fn(input, 1, 0); fn(input, 1, 0);
} }
{ {
// int -> Future<void> // int -> Future<Unit>
auto res = reduce( auto res = reduce(
window( window(
std::vector<int>({1, 2, 3}), std::vector<int>({1, 2, 3}),
[](int i) { return makeFuture(); }, [](int i) { return makeFuture(); },
2), 2),
0, 0,
[](int sum, const Try<void>& b) { [](int sum, const Try<Unit>& b) {
EXPECT_TRUE(b.hasValue()); EXPECT_TRUE(b.hasValue());
return sum + 1; return sum + 1;
}).get(); }).get();
......
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