s/valueTry/getTry/
[folly.git] / folly / wangle / detail.h
1 /*
2  * Copyright 2014 Facebook, Inc.
3  *
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
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 #pragma once
18
19 #include <folly/Optional.h>
20 #include <stdexcept>
21 #include <atomic>
22
23 #include "Try.h"
24 #include "Promise.h"
25 #include "Future.h"
26
27 namespace folly { namespace wangle { namespace detail {
28
29 /** The shared state object for Future and Promise. */
30 template<typename T>
31 class FutureObject {
32  public:
33   FutureObject() = default;
34
35   // not copyable
36   FutureObject(FutureObject const&) = delete;
37   FutureObject& operator=(FutureObject const&) = delete;
38
39   // not movable (see comment in the implementation of Future::then)
40   FutureObject(FutureObject&&) = delete;
41   FutureObject& operator=(FutureObject&&) = delete;
42
43   Try<T>& getTry() {
44     return *value_;
45   }
46
47   template <typename F>
48   void setContinuation(F func) {
49     if (continuation_) {
50       throw std::logic_error("setContinuation called twice");
51     }
52
53     if (value_.hasValue()) {
54       func(std::move(*value_));
55       delete this;
56     } else {
57       continuation_ = std::move(func);
58     }
59   }
60
61   void fulfil(Try<T>&& t) {
62     if (value_.hasValue()) {
63       throw std::logic_error("fulfil called twice");
64     }
65
66     if (continuation_) {
67       continuation_(std::move(t));
68       delete this;
69     } else {
70       value_ = std::move(t);
71     }
72   }
73
74   void setException(std::exception_ptr const& e) {
75     fulfil(Try<T>(e));
76   }
77
78   template <class E> void setException(E const& e) {
79     fulfil(Try<T>(std::make_exception_ptr<E>(e)));
80   }
81
82   bool ready() const {
83     return value_.hasValue();
84   }
85
86   typename std::add_lvalue_reference<T>::type value() {
87     return value_->value();
88   }
89
90  private:
91   folly::Optional<Try<T>> value_;
92   std::function<void(Try<T>&&)> continuation_;
93 };
94
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;
100   size_t total;
101   std::atomic<size_t> count;
102   typedef Future<std::tuple<Try<Ts>...>> type;
103 };
104
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));
113       delete ctx;
114     }
115   });
116 }
117
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));
126       delete ctx;
127     }
128   });
129   whenAllVariadicHelper(ctx, tail...); // recursive template tail call
130 }
131
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;
138   size_t total;
139 };
140
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;
147   void decref() {
148     if (--ref_count == 0) {
149       delete this;
150     }
151   }
152 };
153
154 }}} // namespace