source: mainline/uspace/lib/cpp/include/__bits/functional/bind.hpp@ 7bbf91e

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 7bbf91e was 7bbf91e, checked in by Dzejrou <dzejrou@…>, 7 years ago

cpp: changed internal to bits to avoid include space pollusion, fixed old std::hel:: bugs in files that weren't touched since

  • Property mode set to 100644
File size: 8.7 KB
Line 
1/*
2 * Copyright (c) 2018 Jaroslav Jindrak
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#ifndef LIBCPP_BITS_FUNCTIONAL_BIND
30#define LIBCPP_BITS_FUNCTIONAL_BIND
31
32#include <__bits/functional/function.hpp>
33#include <__bits/functional/invoke.hpp>
34#include <__bits/functional/reference_wrapper.hpp>
35#include <tuple>
36#include <type_traits>
37#include <utility>
38
39namespace std
40{
41 /**
42 * 20.9.10, bind:
43 */
44
45 namespace aux
46 {
47 template<int N>
48 struct placeholder_t
49 {
50 constexpr placeholder_t() = default;
51 constexpr placeholder_t(const placeholder_t&) = default;
52 constexpr placeholder_t(placeholder_t&&) = default;
53 };
54 }
55
56 template<class T>
57 struct is_placeholder: integral_constant<int, 0>
58 { /* DUMMY BODY */ };
59
60 template<int N> // Note: const because they are all constexpr.
61 struct is_placeholder<const aux::placeholder_t<N>>
62 : integral_constant<int, N>
63 { /* DUMMY BODY */ };
64
65 template<class T>
66 inline constexpr int is_placeholder_v = is_placeholder<T>::value;
67
68 namespace aux
69 {
70 /**
71 * Note: Our internal bind return type has an extra type
72 * template parameter and an extra bool template parameter.
73 * We use this for the special version of bind that has
74 * the return type to have a result_type typedef
75 * (i.e. when the bool is true, the extra type parameter
76 * is typedefed as result_type - see the structure below).
77 * This is just a simplification of the implementation
78 * so that we don't need to have two return types for
79 * the two bind functions, because unlike function or
80 * mem_fn, we know exactly when to make the typedef.
81 */
82
83 template<class, bool = false>
84 struct bind_conditional_result_type
85 { /* DUMMY BODY */ };
86
87 template<class R>
88 struct bind_conditional_result_type<R, true>
89 {
90 using result_type = R;
91 };
92
93 template<class, bool, class, class...>
94 class bind_t;
95
96 /**
97 * Filter class that uses its overloaded operator[]
98 * to filter our placeholders, reference_wrappers and bind
99 * subexpressions and replace them with the correct
100 * arguments (extracts references, calls the subexpressions etc).
101 */
102 template<class... Args>
103 class bind_arg_filter
104 {
105 public:
106 bind_arg_filter(Args&&... args)
107 : args_{forward<Args>(args)...}
108 { /* DUMMY BODY */ }
109
110 template<class T>
111 constexpr decltype(auto) operator[](T&& t)
112 {
113 return forward<T>(t);
114 }
115
116 template<int N>
117 constexpr decltype(auto) operator[](const placeholder_t<N>)
118 { // Since placeholders are constexpr, this is the best match for them.
119 /**
120 * Come on, it's int! Why not use -1 as not placeholder
121 * and start them at 0? -.-
122 */
123 return get<N - 1>(args_);
124 }
125
126 template<class T>
127 constexpr T& operator[](reference_wrapper<T> ref)
128 {
129 return ref.get();
130 }
131
132 template<class R, bool B, class F, class... BindArgs>
133 constexpr decltype(auto) operator[](const bind_t<R, B, F, BindArgs...> b)
134 {
135 return b; // TODO: bind subexpressions
136 }
137
138
139 private:
140 tuple<Args...> args_;
141 };
142
143 template<class R, bool HasResultType, class F, class... Args>
144 class bind_t: public bind_conditional_result_type<R, HasResultType>
145 {
146 public:
147 template<class G, class... BoundArgs>
148 constexpr bind_t(G&& g, BoundArgs&&... args)
149 : func_{forward<F>(g)},
150 bound_args_{forward<Args>(args)...}
151 { /* DUMMY BODY */ }
152
153 constexpr bind_t(const bind_t& other) = default;
154 constexpr bind_t(bind_t&& other) = default;
155
156 template<class... ActualArgs>
157 constexpr decltype(auto) operator()(ActualArgs&&... args)
158 {
159 return invoke_(
160 make_index_sequence<sizeof...(Args)>{},
161 forward<ActualArgs>(args)...
162 );
163 }
164
165 private:
166 function<decay_t<F>> func_;
167 tuple<decay_t<Args>...> bound_args_;
168
169 template<size_t... Is, class... ActualArgs>
170 constexpr decltype(auto) invoke_(
171 index_sequence<Is...>, ActualArgs&&... args
172 )
173 {
174 /**
175 * The expression filter[bound_args_[bind_arg_index<Is>()]]...
176 * here expands bind_arg_index to 0, 1, ... sizeof...(ActualArgs) - 1
177 * and then passes this variadic list of indices to the bound_args_
178 * tuple which extracts the bound args from it.
179 * Our filter will then have its operator[] called on each of them
180 * and filter out the placeholders, reference_wrappers etc and changes
181 * them to the actual arguments.
182 */
183 bind_arg_filter<ActualArgs...> filter{forward<ActualArgs>(args)...};
184
185 return aux::invoke(
186 func_,
187 filter[get<Is>(bound_args_)]...
188 );
189 }
190 };
191 }
192
193 template<class T>
194 struct is_bind_expression: false_type
195 { /* DUMMY BODY */ };
196
197 template<class R, bool B, class F, class... Args>
198 struct is_bind_expression<aux::bind_t<R, B, F, Args...>>
199 : true_type
200 { /* DUMMY BODY */ };
201
202 template<class F, class... Args>
203 aux::bind_t<void, false, F, Args...> bind(F&& f, Args&&... args)
204 {
205 return aux::bind_t<void, false, F, Args...>{forward<F>(f), forward<Args>(args)...};
206 }
207
208 template<class R, class F, class... Args>
209 aux::bind_t<R, true, F, Args...> bind(F&& f, Args&&... args)
210 {
211 return aux::bind_t<R, true, F, Args...>{forward<F>(f), forward<Args>(args)...};
212 }
213
214 namespace placeholders
215 {
216 /**
217 * Note: The number of placeholders is
218 * implementation defined, we've chosen
219 * 8 because it is a nice number
220 * and should be enough for any function
221 * call.
222 * Note: According to the C++14 standard, these
223 * are all extern non-const. We decided to use
224 * the C++17 form of them being inline constexpr
225 * because it is more convenient, makes sense
226 * and would eventually need to be upgraded
227 * anyway.
228 */
229 inline constexpr aux::placeholder_t<1> _1;
230 inline constexpr aux::placeholder_t<2> _2;
231 inline constexpr aux::placeholder_t<3> _3;
232 inline constexpr aux::placeholder_t<4> _4;
233 inline constexpr aux::placeholder_t<5> _5;
234 inline constexpr aux::placeholder_t<6> _6;
235 inline constexpr aux::placeholder_t<7> _7;
236 inline constexpr aux::placeholder_t<8> _8;
237 }
238}
239
240#endif
Note: See TracBrowser for help on using the repository browser.