2017
[folly.git] / folly / futures / Future-pre.h
1 /*
2  * Copyright 2017 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 // included by Future.h, do not include directly.
20
21 namespace folly {
22
23 template <class> class Promise;
24
25 template <typename T>
26 struct isFuture : std::false_type {
27   using Inner = typename Unit::Lift<T>::type;
28 };
29
30 template <typename T>
31 struct isFuture<Future<T>> : std::true_type {
32   typedef T Inner;
33 };
34
35 template <typename T>
36 struct isTry : std::false_type {};
37
38 template <typename T>
39 struct isTry<Try<T>> : std::true_type {};
40
41 namespace detail {
42
43 template <class> class Core;
44 template <class...> struct CollectAllVariadicContext;
45 template <class...> struct CollectVariadicContext;
46 template <class> struct CollectContext;
47
48 template<typename F, typename... Args>
49 using resultOf = decltype(std::declval<F>()(std::declval<Args>()...));
50
51 template <typename...>
52 struct ArgType;
53
54 template <typename Arg, typename... Args>
55 struct ArgType<Arg, Args...> {
56   typedef Arg FirstArg;
57 };
58
59 template <>
60 struct ArgType<> {
61   typedef void FirstArg;
62 };
63
64 template <bool isTry, typename F, typename... Args>
65 struct argResult {
66   using Result = resultOf<F, Args...>;
67 };
68
69 template<typename F, typename... Args>
70 struct callableWith {
71     template<typename T,
72              typename = detail::resultOf<T, Args...>>
73     static constexpr std::true_type
74     check(std::nullptr_t) { return std::true_type{}; }
75
76     template<typename>
77     static constexpr std::false_type
78     check(...) { return std::false_type{}; }
79
80     typedef decltype(check<F>(nullptr)) type;
81     static constexpr bool value = type::value;
82 };
83
84 template<typename T, typename F>
85 struct callableResult {
86   typedef typename std::conditional<
87     callableWith<F>::value,
88     detail::argResult<false, F>,
89     typename std::conditional<
90       callableWith<F, T&&>::value,
91       detail::argResult<false, F, T&&>,
92       typename std::conditional<
93         callableWith<F, T&>::value,
94         detail::argResult<false, F, T&>,
95         typename std::conditional<
96           callableWith<F, Try<T>&&>::value,
97           detail::argResult<true, F, Try<T>&&>,
98           detail::argResult<true, F, Try<T>&>>::type>::type>::type>::type Arg;
99   typedef isFuture<typename Arg::Result> ReturnsFuture;
100   typedef Future<typename ReturnsFuture::Inner> Return;
101 };
102
103 template <typename L>
104 struct Extract : Extract<decltype(&L::operator())> { };
105
106 template <typename Class, typename R, typename... Args>
107 struct Extract<R(Class::*)(Args...) const> {
108   typedef isFuture<R> ReturnsFuture;
109   typedef Future<typename ReturnsFuture::Inner> Return;
110   typedef typename ReturnsFuture::Inner RawReturn;
111   typedef typename ArgType<Args...>::FirstArg FirstArg;
112 };
113
114 template <typename Class, typename R, typename... Args>
115 struct Extract<R(Class::*)(Args...)> {
116   typedef isFuture<R> ReturnsFuture;
117   typedef Future<typename ReturnsFuture::Inner> Return;
118   typedef typename ReturnsFuture::Inner RawReturn;
119   typedef typename ArgType<Args...>::FirstArg FirstArg;
120 };
121
122 // gcc-4.8 refuses to capture a function reference in a lambda. This can be
123 // mitigated by casting them to function pointer types first. The following
124 // helper is used in Future.h to achieve that where necessary.
125 // When compiling with gcc versions 4.9 and up, as well as clang, we do not
126 // need to apply FunctionReferenceToPointer (i.e. T can be used instead of
127 // FunctionReferenceToPointer<T>).
128 // Applying FunctionReferenceToPointer first, the code works on all tested
129 // compiler versions: gcc 4.8 and above, cland 3.5 and above.
130
131 template <typename T>
132 struct FunctionReferenceToPointer {
133   using type = T;
134 };
135
136 template <typename R, typename... Args>
137 struct FunctionReferenceToPointer<R (&)(Args...)> {
138   using type = R (*)(Args...);
139 };
140
141 } // detail
142
143 class Timekeeper;
144
145 } // namespace