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 const size_t i = sizeof...(Ts) - sizeof...(Fs) - 1;
110 std::get<i>(ctx->results) = std::move(t);
111 if (++ctx->count == ctx->total) {
112 ctx->p.setValue(std::move(ctx->results));
118 template <typename... Ts, typename THead, typename... Fs>
119 typename std::enable_if<sizeof...(Fs) != 0, void>::type
120 whenAllVariadicHelper(VariadicContext<Ts...> *ctx, THead& head, Fs&... tail) {
121 head.setContinuation([ctx](Try<typename THead::value_type>&& t) {
122 const size_t i = sizeof...(Ts) - sizeof...(Fs) - 1;
123 std::get<i>(ctx->results) = std::move(t);
124 if (++ctx->count == ctx->total) {
125 ctx->p.setValue(std::move(ctx->results));
129 whenAllVariadicHelper(ctx, tail...); // recursive template tail call
132 template <typename T>
133 struct WhenAllContext {
134 explicit WhenAllContext() : count(0), total(0) {}
135 Promise<std::vector<Try<T> > > p;
136 std::vector<Try<T> > results;
137 std::atomic<size_t> count;
141 template <typename T>
142 struct WhenAnyContext {
143 explicit WhenAnyContext(size_t n) : done(false), ref_count(n) {};
144 Promise<std::pair<size_t, Try<T>>> p;
145 std::atomic<bool> done;
146 std::atomic<size_t> ref_count;
148 if (--ref_count == 0) {