2 * Copyright 2014 Facebook, Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include <folly/Optional.h>
27 namespace folly { namespace wangle { namespace detail {
29 /** The shared state object for Future and Promise. */
33 FutureObject() = default;
36 FutureObject(FutureObject const&) = delete;
37 FutureObject& operator=(FutureObject const&) = delete;
39 // not movable (see comment in the implementation of Future::then)
40 FutureObject(FutureObject&&) = delete;
41 FutureObject& operator=(FutureObject&&) = delete;
48 void setContinuation(F func) {
50 throw std::logic_error("setContinuation called twice");
53 if (value_.hasValue()) {
54 func(std::move(*value_));
57 continuation_ = std::move(func);
61 void fulfil(Try<T>&& t) {
62 if (value_.hasValue()) {
63 throw std::logic_error("fulfil called twice");
67 continuation_(std::move(t));
70 value_ = std::move(t);
74 void setException(std::exception_ptr const& e) {
78 template <class E> void setException(E const& e) {
79 fulfil(Try<T>(std::make_exception_ptr<E>(e)));
83 return value_.hasValue();
86 typename std::add_lvalue_reference<T>::type value() {
87 return value_->value();
91 folly::Optional<Try<T>> value_;
92 std::function<void(Try<T>&&)> continuation_;
95 template <typename... Ts>
96 struct VariadicContext {
97 VariadicContext() : total(0), count(0) {}
98 Promise<std::tuple<Try<Ts>... > > p;
99 std::tuple<Try<Ts>... > results;
101 std::atomic<size_t> count;
102 typedef Future<std::tuple<Try<Ts>...>> type;
105 template <typename... Ts, typename THead, typename... Fs>
106 typename std::enable_if<sizeof...(Fs) == 0, void>::type
107 whenAllVariadicHelper(VariadicContext<Ts...> *ctx, THead&& head, Fs&&... tail) {
108 head.setContinuation([ctx](Try<typename THead::value_type>&& t) {
109 std::get<sizeof...(Ts) - sizeof...(Fs) - 1>(ctx->results) = std::move(t);
110 if (++ctx->count == ctx->total) {
111 ctx->p.setValue(std::move(ctx->results));
117 template <typename... Ts, typename THead, typename... Fs>
118 typename std::enable_if<sizeof...(Fs) != 0, void>::type
119 whenAllVariadicHelper(VariadicContext<Ts...> *ctx, THead&& head, Fs&&... tail) {
120 head.setContinuation([ctx](Try<typename THead::value_type>&& t) {
121 std::get<sizeof...(Ts) - sizeof...(Fs) - 1>(ctx->results) = std::move(t);
122 if (++ctx->count == ctx->total) {
123 ctx->p.setValue(std::move(ctx->results));
127 // template tail-recursion
128 whenAllVariadicHelper(ctx, std::forward<Fs>(tail)...);
131 template <typename T>
132 struct WhenAllContext {
133 explicit WhenAllContext() : count(0), total(0) {}
134 Promise<std::vector<Try<T> > > p;
135 std::vector<Try<T> > results;
136 std::atomic<size_t> count;
140 template <typename T>
141 struct WhenAnyContext {
142 explicit WhenAnyContext(size_t n) : done(false), ref_count(n) {};
143 Promise<std::pair<size_t, Try<T>>> p;
144 std::atomic<bool> done;
145 std::atomic<size_t> ref_count;
147 if (--ref_count == 0) {