});
}
-// TODO(6838553)
-#ifndef __clang__
template <class T>
-template <class... Args>
-auto Future<T>::then(Executor* x, Args&&... args)
- -> decltype(this->then(std::forward<Args>(args)...))
+template <class Executor, class Arg, class... Args>
+auto Future<T>::then(Executor* x, Arg&& arg, Args&&... args)
+ -> decltype(this->then(std::forward<Arg>(arg),
+ std::forward<Args>(args)...))
{
auto oldX = getExecutor();
setExecutor(x);
- return this->then(std::forward<Args>(args)...).via(oldX);
+ return this->then(std::forward<Arg>(arg), std::forward<Args>(args)...).
+ via(oldX);
}
-#endif
template <class T>
Future<void> Future<T>::then() {
}
template <class T>
-template <typename Executor>
inline Future<T> Future<T>::via(Executor* executor) && {
throwIfInvalid();
}
template <class T>
-template <typename Executor>
inline Future<T> Future<T>::via(Executor* executor) & {
throwIfInvalid();
}
// via
-template <typename Executor>
-Future<void> via(Executor* executor) {
+inline Future<void> via(Executor* executor) {
return makeFuture().via(executor);
}
Optional<T>
>::type VecT;
- explicit CollectContext(int n) : count(0), threw(false) {
+ explicit CollectContext(int n) : count(0), success_count(0), threw(false) {
results.resize(n);
}
Promise<std::vector<T>> p;
std::vector<VecT> results;
- std::atomic<size_t> count;
+ std::atomic<size_t> count, success_count;
std::atomic_bool threw;
typedef std::vector<T> result_type;
template <>
struct CollectContext<void> {
- explicit CollectContext(int n) : count(0), threw(false) {}
+ explicit CollectContext(int n) : count(0), success_count(0), threw(false) {}
Promise<void> p;
- std::atomic<size_t> count;
+ std::atomic<size_t> count, success_count;
std::atomic_bool threw;
typedef void result_type;
assert(i < n);
auto& f = *first;
f.setCallback_([ctx, i, n](Try<T> t) {
- auto c = ++ctx->count;
if (t.hasException()) {
if (!ctx->threw.exchange(true)) {
}
} else if (!ctx->threw) {
ctx->addResult(i, t);
- if (c == n) {
+ if (++ctx->success_count == n) {
ctx->setValue();
}
}
- if (c == n) {
+ if (++ctx->count == n) {
delete ctx;
}
});
return ctx->p.getFuture();
}
-template <class It, class T, class F, class ItT, class Arg>
-typename std::enable_if<!isFutureResult<F, T, Arg>::value, Future<T>>::type
-reduce(It first, It last, T initial, F func) {
+template <class It, class T, class F>
+Future<T> reduce(It first, It last, T&& initial, F&& func) {
if (first == last) {
return makeFuture(std::move(initial));
}
+ typedef typename std::iterator_traits<It>::value_type::value_type ItT;
+ typedef typename std::conditional<
+ detail::callableWith<F, T&&, Try<ItT>&&>::value, Try<ItT>, ItT>::type Arg;
typedef isTry<Arg> IsTry;
- return collectAll(first, last)
- .then([initial, func](std::vector<Try<ItT>>& vals) mutable {
- for (auto& val : vals) {
- initial = func(std::move(initial),
- // Either return a ItT&& or a Try<ItT>&& depending
- // on the type of the argument of func.
- val.template get<IsTry::value, Arg&&>());
- }
- return initial;
- });
-}
+ folly::MoveWrapper<T> minitial(std::move(initial));
+ auto sfunc = std::make_shared<F>(std::move(func));
-template <class It, class T, class F, class ItT, class Arg>
-typename std::enable_if<isFutureResult<F, T, Arg>::value, Future<T>>::type
-reduce(It first, It last, T initial, F func) {
- if (first == last) {
- return makeFuture(std::move(initial));
- }
-
- typedef isTry<Arg> IsTry;
-
- auto f = first->then([initial, func](Try<ItT>& head) mutable {
- return func(std::move(initial),
+ auto f = first->then([minitial, sfunc](Try<ItT>& head) mutable {
+ return (*sfunc)(std::move(*minitial),
head.template get<IsTry::value, Arg&&>());
});
for (++first; first != last; ++first) {
- f = collectAll(f, *first).then([func](std::tuple<Try<T>, Try<ItT>>& t) {
- return func(std::move(std::get<0>(t).value()),
+ f = collectAll(f, *first).then([sfunc](std::tuple<Try<T>, Try<ItT>>& t) {
+ return (*sfunc)(std::move(std::get<0>(t).value()),
// Either return a ItT&& or a Try<ItT>&& depending
// on the type of the argument of func.
std::get<1>(t).template get<IsTry::value, Arg&&>());
return f;
}
+template <class T>
+template <class I, class F>
+Future<I> Future<T>::reduce(I&& initial, F&& func) {
+ folly::MoveWrapper<I> minitial(std::move(initial));
+ folly::MoveWrapper<F> mfunc(std::move(func));
+ return then([minitial, mfunc](T& vals) mutable {
+ auto ret = std::move(*minitial);
+ for (auto& val : vals) {
+ ret = (*mfunc)(std::move(ret), std::move(val));
+ }
+ return ret;
+ });
+}
+
template <class T>
Future<T> Future<T>::within(Duration dur, Timekeeper* tk) {
return within(dur, TimedOut(), tk);
waitVia(e).value();
}
+namespace detail {
+ template <class T>
+ struct TryEquals {
+ static bool equals(const Try<T>& t1, const Try<T>& t2) {
+ 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>
Future<bool> Future<T>::willEqual(Future<T>& f) {
return collectAll(*this, f).then([](const std::tuple<Try<T>, Try<T>>& t) {
if (std::get<0>(t).hasValue() && std::get<1>(t).hasValue()) {
- return std::get<0>(t).value() == std::get<1>(t).value();
+ return detail::TryEquals<T>::equals(std::get<0>(t), std::get<1>(t));
} else {
return false;
}
}
}
+// Instantiate the most common Future types to save compile time
+extern template class Future<void>;
+extern template class Future<bool>;
+extern template class Future<int>;
+extern template class Future<int64_t>;
+extern template class Future<std::string>;
+extern template class Future<double>;
+
} // namespace folly
// I haven't included a Future<T&> specialization because I don't forsee us