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.
20 #include <folly/Optional.h>
28 namespace folly { namespace wangle { namespace detail {
30 /** The shared state object for Future and Promise. */
34 FutureObject() = default;
37 FutureObject(FutureObject const&) = delete;
38 FutureObject& operator=(FutureObject const&) = delete;
40 // not movable (see comment in the implementation of Future::then)
41 FutureObject(FutureObject&&) noexcept = delete;
42 FutureObject& operator=(FutureObject&&) = delete;
49 void setContinuation(F func) {
51 throw std::logic_error("setContinuation called twice");
54 continuation_ = std::move(func);
56 if (shouldContinue_.test_and_set()) {
57 continuation_(std::move(*value_));
62 void fulfil(Try<T>&& t) {
63 if (value_.hasValue()) {
64 throw std::logic_error("fulfil called twice");
67 value_ = std::move(t);
69 if (shouldContinue_.test_and_set()) {
70 continuation_(std::move(*value_));
75 void setException(std::exception_ptr const& e) {
79 template <class E> void setException(E const& e) {
80 fulfil(Try<T>(std::make_exception_ptr<E>(e)));
84 return value_.hasValue();
87 typename std::add_lvalue_reference<T>::type value() {
89 return value_->value();
91 throw FutureNotReady();
96 std::atomic_flag shouldContinue_ = ATOMIC_FLAG_INIT;
97 folly::Optional<Try<T>> value_;
98 std::function<void(Try<T>&&)> continuation_;
101 template <typename... Ts>
102 struct VariadicContext {
103 VariadicContext() : total(0), count(0) {}
104 Promise<std::tuple<Try<Ts>... > > p;
105 std::tuple<Try<Ts>... > results;
107 std::atomic<size_t> count;
108 typedef Future<std::tuple<Try<Ts>...>> type;
111 template <typename... Ts, typename THead, typename... Fs>
112 typename std::enable_if<sizeof...(Fs) == 0, void>::type
113 whenAllVariadicHelper(VariadicContext<Ts...> *ctx, THead&& head, Fs&&... tail) {
114 head.setContinuation([ctx](Try<typename THead::value_type>&& t) {
115 std::get<sizeof...(Ts) - sizeof...(Fs) - 1>(ctx->results) = std::move(t);
116 if (++ctx->count == ctx->total) {
117 ctx->p.setValue(std::move(ctx->results));
123 template <typename... Ts, typename THead, typename... Fs>
124 typename std::enable_if<sizeof...(Fs) != 0, void>::type
125 whenAllVariadicHelper(VariadicContext<Ts...> *ctx, THead&& head, Fs&&... tail) {
126 head.setContinuation([ctx](Try<typename THead::value_type>&& t) {
127 std::get<sizeof...(Ts) - sizeof...(Fs) - 1>(ctx->results) = std::move(t);
128 if (++ctx->count == ctx->total) {
129 ctx->p.setValue(std::move(ctx->results));
133 // template tail-recursion
134 whenAllVariadicHelper(ctx, std::forward<Fs>(tail)...);
137 template <typename T>
138 struct WhenAllContext {
139 explicit WhenAllContext() : count(0), total(0) {}
140 Promise<std::vector<Try<T> > > p;
141 std::vector<Try<T> > results;
142 std::atomic<size_t> count;
146 template <typename T>
147 struct WhenAnyContext {
148 explicit WhenAnyContext(size_t n) : done(false), ref_count(n) {};
149 Promise<std::pair<size_t, Try<T>>> p;
150 std::atomic<bool> done;
151 std::atomic<size_t> ref_count;
153 if (--ref_count == 0) {