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

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

cpp: abort and report when an unimplemented function is called

  • Property mode set to 100644
File size: 8.9 KB
Line 
1/*
2 * Copyright (c) 2019 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 <cassert>
36#include <tuple>
37#include <type_traits>
38#include <utility>
39
40namespace std
41{
42 /**
43 * 20.9.10, bind:
44 */
45
46 namespace aux
47 {
48 template<int N>
49 struct placeholder_t
50 {
51 constexpr placeholder_t() = default;
52 constexpr placeholder_t(const placeholder_t&) = default;
53 constexpr placeholder_t(placeholder_t&&) = default;
54 };
55 }
56
57 template<class T>
58 struct is_placeholder: integral_constant<int, 0>
59 { /* DUMMY BODY */ };
60
61 template<int N> // Note: const because they are all constexpr.
62 struct is_placeholder<const aux::placeholder_t<N>>
63 : integral_constant<int, N>
64 { /* DUMMY BODY */ };
65
66 template<class T>
67 inline constexpr int is_placeholder_v = is_placeholder<T>::value;
68
69 namespace aux
70 {
71 /**
72 * Note: Our internal bind return type has an extra type
73 * template parameter and an extra bool template parameter.
74 * We use this for the special version of bind that has
75 * the return type to have a result_type typedef
76 * (i.e. when the bool is true, the extra type parameter
77 * is typedefed as result_type - see the structure below).
78 * This is just a simplification of the implementation
79 * so that we don't need to have two return types for
80 * the two bind functions, because unlike function or
81 * mem_fn, we know exactly when to make the typedef.
82 */
83
84 template<class, bool = false>
85 struct bind_conditional_result_type
86 { /* DUMMY BODY */ };
87
88 template<class R>
89 struct bind_conditional_result_type<R, true>
90 {
91 using result_type = R;
92 };
93
94 template<class, bool, class, class...>
95 class bind_t;
96
97 /**
98 * Filter class that uses its overloaded operator[]
99 * to filter our placeholders, reference_wrappers and bind
100 * subexpressions and replace them with the correct
101 * arguments (extracts references, calls the subexpressions etc).
102 */
103 template<class... Args>
104 class bind_arg_filter
105 {
106 public:
107 bind_arg_filter(Args&&... args)
108 : args_{forward<Args>(args)...}
109 { /* DUMMY BODY */ }
110
111 template<class T>
112 constexpr decltype(auto) operator[](T&& t)
113 {
114 return forward<T>(t);
115 }
116
117 template<int N>
118 constexpr decltype(auto) operator[](const placeholder_t<N>)
119 { // Since placeholders are constexpr, this is the best match for them.
120 /**
121 * Come on, it's int! Why not use -1 as not placeholder
122 * and start them at 0? -.-
123 */
124 return get<N - 1>(args_);
125 }
126
127 template<class T>
128 constexpr T& operator[](reference_wrapper<T> ref)
129 {
130 return ref.get();
131 }
132
133 template<class R, bool B, class F, class... BindArgs>
134 constexpr decltype(auto) operator[](const bind_t<R, B, F, BindArgs...> b)
135 {
136 __unimplemented();
137 return b; // TODO: bind subexpressions
138 }
139
140
141 private:
142 tuple<Args...> args_;
143 };
144
145 template<class R, bool HasResultType, class F, class... Args>
146 class bind_t: public bind_conditional_result_type<R, HasResultType>
147 {
148 public:
149 template<class G, class... BoundArgs>
150 constexpr bind_t(G&& g, BoundArgs&&... args)
151 : func_{forward<F>(g)},
152 bound_args_{forward<Args>(args)...}
153 { /* DUMMY BODY */ }
154
155 constexpr bind_t(const bind_t& other) = default;
156 constexpr bind_t(bind_t&& other) = default;
157
158 template<class... ActualArgs>
159 constexpr decltype(auto) operator()(ActualArgs&&... args)
160 {
161 return invoke_(
162 make_index_sequence<sizeof...(Args)>{},
163 forward<ActualArgs>(args)...
164 );
165 }
166
167 private: // TODO: This has problem with member function pointers.
168 function<remove_reference_t<F>> func_;
169 tuple<decay_t<Args>...> bound_args_;
170
171 template<size_t... Is, class... ActualArgs>
172 constexpr decltype(auto) invoke_(
173 index_sequence<Is...>, ActualArgs&&... args
174 )
175 {
176 /**
177 * The expression filter[bound_args_[bind_arg_index<Is>()]]...
178 * here expands bind_arg_index to 0, 1, ... sizeof...(ActualArgs) - 1
179 * and then passes this variadic list of indices to the bound_args_
180 * tuple which extracts the bound args from it.
181 * Our filter will then have its operator[] called on each of them
182 * and filter out the placeholders, reference_wrappers etc and changes
183 * them to the actual arguments.
184 */
185 bind_arg_filter<ActualArgs...> filter{forward<ActualArgs>(args)...};
186
187 return aux::INVOKE(
188 func_,
189 filter[get<Is>(bound_args_)]...
190 );
191 }
192 };
193 }
194
195 template<class T>
196 struct is_bind_expression: false_type
197 { /* DUMMY BODY */ };
198
199 template<class R, bool B, class F, class... Args>
200 struct is_bind_expression<aux::bind_t<R, B, F, Args...>>
201 : true_type
202 { /* DUMMY BODY */ };
203
204 template<class F, class... Args>
205 aux::bind_t<void, false, F, Args...> bind(F&& f, Args&&... args)
206 {
207 return aux::bind_t<void, false, F, Args...>{forward<F>(f), forward<Args>(args)...};
208 }
209
210 template<class R, class F, class... Args>
211 aux::bind_t<R, true, F, Args...> bind(F&& f, Args&&... args)
212 {
213 return aux::bind_t<R, true, F, Args...>{forward<F>(f), forward<Args>(args)...};
214 }
215
216 namespace placeholders
217 {
218 /**
219 * Note: The number of placeholders is
220 * implementation defined, we've chosen
221 * 8 because it is a nice number
222 * and should be enough for any function
223 * call.
224 * Note: According to the C++14 standard, these
225 * are all extern non-const. We decided to use
226 * the C++17 form of them being inline constexpr
227 * because it is more convenient, makes sense
228 * and would eventually need to be upgraded
229 * anyway.
230 */
231 inline constexpr aux::placeholder_t<1> _1;
232 inline constexpr aux::placeholder_t<2> _2;
233 inline constexpr aux::placeholder_t<3> _3;
234 inline constexpr aux::placeholder_t<4> _4;
235 inline constexpr aux::placeholder_t<5> _5;
236 inline constexpr aux::placeholder_t<6> _6;
237 inline constexpr aux::placeholder_t<7> _7;
238 inline constexpr aux::placeholder_t<8> _8;
239 }
240}
241
242#endif
Note: See TracBrowser for help on using the repository browser.