1 | /* |
2 | * Copyright 2012-present 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 <functional> |
20 | #include <tuple> |
21 | #include <utility> |
22 | |
23 | #include <folly/Traits.h> |
24 | #include <folly/Utility.h> |
25 | #include <folly/functional/Invoke.h> |
26 | |
27 | namespace folly { |
28 | |
29 | ////////////////////////////////////////////////////////////////////// |
30 | |
31 | /** |
32 | * Helper to generate an index sequence from a tuple like type |
33 | */ |
34 | template <typename Tuple> |
35 | using index_sequence_for_tuple = |
36 | make_index_sequence<std::tuple_size<Tuple>::value>; |
37 | |
38 | namespace detail { |
39 | namespace apply_tuple { |
40 | namespace adl { |
41 | using std::get; |
42 | |
43 | struct ApplyInvoke { |
44 | template <typename T> |
45 | using seq = index_sequence_for_tuple<std::remove_reference_t<T>>; |
46 | |
47 | template <typename F, typename T, std::size_t... I> |
48 | static constexpr auto invoke_(F&& f, T&& t, index_sequence<I...>) noexcept( |
49 | is_nothrow_invocable<F&&, decltype(get<I>(std::declval<T>()))...>::value) |
50 | -> invoke_result_t<F&&, decltype(get<I>(std::declval<T>()))...> { |
51 | return invoke(static_cast<F&&>(f), get<I>(static_cast<T&&>(t))...); |
52 | } |
53 | }; |
54 | |
55 | template < |
56 | typename Tuple, |
57 | std::size_t... Indices, |
58 | typename ReturnTuple = |
59 | std::tuple<decltype(get<Indices>(std::declval<Tuple>()))...>> |
60 | auto forward_tuple(Tuple&& tuple, index_sequence<Indices...>) -> ReturnTuple { |
61 | return ReturnTuple{get<Indices>(std::forward<Tuple>(tuple))...}; |
62 | } |
63 | } // namespace adl |
64 | } // namespace apply_tuple |
65 | } // namespace detail |
66 | |
67 | struct ApplyInvoke : private detail::apply_tuple::adl::ApplyInvoke { |
68 | public: |
69 | template <typename F, typename T> |
70 | constexpr auto operator()(F&& f, T&& t) const noexcept( |
71 | noexcept(invoke_(static_cast<F&&>(f), static_cast<T&&>(t), seq<T>{}))) |
72 | -> decltype(invoke_(static_cast<F&&>(f), static_cast<T&&>(t), seq<T>{})) { |
73 | return invoke_(static_cast<F&&>(f), static_cast<T&&>(t), seq<T>{}); |
74 | } |
75 | }; |
76 | |
77 | ////////////////////////////////////////////////////////////////////// |
78 | |
79 | // libc++ v3.9 has std::apply |
80 | // android ndk r15c libc++ claims to be v3.9 but is missing std::apply |
81 | #if __cpp_lib_apply >= 201603 || \ |
82 | (((__ANDROID__ && _LIBCPP_VERSION > 3900) || \ |
83 | (!__ANDROID__ && _LIBCPP_VERSION > 3800)) && \ |
84 | _LIBCPP_STD_VER > 14) || \ |
85 | (_MSC_VER && _HAS_CXX17) |
86 | |
87 | /* using override */ using std::apply; |
88 | |
89 | #else // __cpp_lib_apply >= 201603 |
90 | |
91 | // mimic: std::apply, C++17 |
92 | template <typename F, typename Tuple> |
93 | constexpr decltype(auto) apply(F&& func, Tuple&& tuple) { |
94 | return ApplyInvoke{}(static_cast<F&&>(func), static_cast<Tuple&&>(tuple)); |
95 | } |
96 | |
97 | #endif // __cpp_lib_apply >= 201603 |
98 | |
99 | /** |
100 | * Get a tuple of references from the passed tuple, forwarding will be applied |
101 | * on the individual types of the tuple based on the value category of the |
102 | * passed tuple |
103 | * |
104 | * For example |
105 | * |
106 | * forward_tuple(std::make_tuple(1, 2)) |
107 | * |
108 | * Returns a std::tuple<int&&, int&&>, |
109 | * |
110 | * auto tuple = std::make_tuple(1, 2); |
111 | * forward_tuple(tuple) |
112 | * |
113 | * Returns a std::tuple<int&, int&> |
114 | */ |
115 | template <typename Tuple> |
116 | auto forward_tuple(Tuple&& tuple) noexcept |
117 | -> decltype(detail::apply_tuple::adl::forward_tuple( |
118 | std::declval<Tuple>(), |
119 | std::declval< |
120 | index_sequence_for_tuple<std::remove_reference_t<Tuple>>>())) { |
121 | return detail::apply_tuple::adl::forward_tuple( |
122 | std::forward<Tuple>(tuple), |
123 | index_sequence_for_tuple<std::remove_reference_t<Tuple>>{}); |
124 | } |
125 | |
126 | /** |
127 | * Mimic the invoke suite of traits for tuple based apply invocation |
128 | */ |
129 | template <typename F, typename Tuple> |
130 | struct apply_result : invoke_result<ApplyInvoke, F, Tuple> {}; |
131 | template <typename F, typename Tuple> |
132 | using apply_result_t = invoke_result_t<ApplyInvoke, F, Tuple>; |
133 | template <typename F, typename Tuple> |
134 | struct is_applicable : is_invocable<ApplyInvoke, F, Tuple> {}; |
135 | template <typename R, typename F, typename Tuple> |
136 | struct is_applicable_r : is_invocable_r<R, ApplyInvoke, F, Tuple> {}; |
137 | template <typename F, typename Tuple> |
138 | struct is_nothrow_applicable : is_nothrow_invocable<ApplyInvoke, F, Tuple> {}; |
139 | template <typename R, typename F, typename Tuple> |
140 | struct is_nothrow_applicable_r |
141 | : is_nothrow_invocable_r<R, ApplyInvoke, F, Tuple> {}; |
142 | |
143 | namespace detail { |
144 | namespace apply_tuple { |
145 | |
146 | template <class F> |
147 | class Uncurry { |
148 | public: |
149 | explicit Uncurry(F&& func) : func_(std::move(func)) {} |
150 | explicit Uncurry(const F& func) : func_(func) {} |
151 | |
152 | template <class Tuple> |
153 | auto operator()(Tuple&& tuple) const |
154 | -> decltype(apply(std::declval<F>(), std::forward<Tuple>(tuple))) { |
155 | return apply(func_, std::forward<Tuple>(tuple)); |
156 | } |
157 | |
158 | private: |
159 | F func_; |
160 | }; |
161 | } // namespace apply_tuple |
162 | } // namespace detail |
163 | |
164 | /** |
165 | * Wraps a function taking N arguments into a function which accepts a tuple of |
166 | * N arguments. Note: This function will also accept an std::pair if N == 2. |
167 | * |
168 | * For example, given the below code: |
169 | * |
170 | * std::vector<std::tuple<int, int, int>> rows = ...; |
171 | * auto test = [](std::tuple<int, int, int>& row) { |
172 | * return std::get<0>(row) * std::get<1>(row) * std::get<2>(row) == 24; |
173 | * }; |
174 | * auto found = std::find_if(rows.begin(), rows.end(), test); |
175 | * |
176 | * |
177 | * 'test' could be rewritten as: |
178 | * |
179 | * auto test = |
180 | * folly::uncurry([](int a, int b, int c) { return a * b * c == 24; }); |
181 | * |
182 | */ |
183 | template <class F> |
184 | auto uncurry(F&& f) |
185 | -> detail::apply_tuple::Uncurry<typename std::decay<F>::type> { |
186 | return detail::apply_tuple::Uncurry<typename std::decay<F>::type>( |
187 | std::forward<F>(f)); |
188 | } |
189 | |
190 | #if __cpp_lib_make_from_tuple || (_MSC_VER >= 1910 && _MSVC_LANG > 201402) |
191 | |
192 | /* using override */ using std::make_from_tuple; |
193 | |
194 | #else |
195 | |
196 | namespace detail { |
197 | namespace apply_tuple { |
198 | template <class T> |
199 | struct Construct { |
200 | template <class... Args> |
201 | constexpr T operator()(Args&&... args) const { |
202 | return T(std::forward<Args>(args)...); |
203 | } |
204 | }; |
205 | } // namespace apply_tuple |
206 | } // namespace detail |
207 | |
208 | // mimic: std::make_from_tuple, C++17 |
209 | template <class T, class Tuple> |
210 | constexpr T make_from_tuple(Tuple&& t) { |
211 | return apply(detail::apply_tuple::Construct<T>(), std::forward<Tuple>(t)); |
212 | } |
213 | |
214 | #endif |
215 | |
216 | ////////////////////////////////////////////////////////////////////// |
217 | } // namespace folly |
218 | |