libstdc++
funcwrap.h
Go to the documentation of this file.
1// Implementation of std::move_only_function, std::copyable_function
2// and std::function_ref -*- C++ -*-
3
4// Copyright The GNU Toolchain Authors.
5//
6// This file is part of the GNU ISO C++ Library. This library is free
7// software; you can redistribute it and/or modify it under the
8// terms of the GNU General Public License as published by the
9// Free Software Foundation; either version 3, or (at your option)
10// any later version.
11
12// This library is distributed in the hope that it will be useful,
13// but WITHOUT ANY WARRANTY; without even the implied warranty of
14// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15// GNU General Public License for more details.
16
17// Under Section 7 of GPL version 3, you are granted additional
18// permissions described in the GCC Runtime Library Exception, version
19// 3.1, as published by the Free Software Foundation.
20
21// You should have received a copy of the GNU General Public License and
22// a copy of the GCC Runtime Library Exception along with this program;
23// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
24// <http://www.gnu.org/licenses/>.
25
26/** @file include/bits/funcwrap.h
27 * This is an internal header file, included by other library headers.
28 * Do not attempt to use it directly. @headername{functional}
29 */
30
31#ifndef _GLIBCXX_FUNCWRAP_H
32#define _GLIBCXX_FUNCWRAP_H 1
33
34#ifdef _GLIBCXX_SYSHDR
35#pragma GCC system_header
36#endif
37
38#include <bits/version.h>
39
40#if __glibcxx_move_only_function || __glibcxx_copyable_function || __glibcxx_function_ref
41
42#include <bits/invoke.h>
43#include <bits/utility.h>
44
45namespace std _GLIBCXX_VISIBILITY(default)
46{
47_GLIBCXX_BEGIN_NAMESPACE_VERSION
48
49 /// @cond undocumented
50 template<typename _Tp>
51 inline constexpr bool __is_polymorphic_function_v = false;
52
53 namespace __polyfunc
54 {
55 union _Ptrs
56 {
57 const void* _M_obj;
58 void (*_M_func)();
59 };
60
61 template<typename _Tp>
62 [[__gnu__::__always_inline__]]
63 constexpr auto*
64 __cast_to(_Ptrs __ptrs) noexcept
65 {
66 using _Td = remove_reference_t<_Tp>;
67 if constexpr (is_function_v<_Td>)
68 return reinterpret_cast<_Td*>(__ptrs._M_func);
69 else if constexpr (is_const_v<_Td>)
70 return static_cast<_Td*>(__ptrs._M_obj);
71 else
72 return static_cast<_Td*>(const_cast<void*>(__ptrs._M_obj));
73 }
74
75 struct _Storage
76 {
77 void* _M_addr() noexcept { return &_M_bytes[0]; }
78 void const* _M_addr() const noexcept { return &_M_bytes[0]; }
79
80 template<typename _Tp>
81 static consteval bool
82 _S_stored_locally() noexcept
83 {
84 return sizeof(_Tp) <= sizeof(_Storage)
85 && alignof(_Tp) <= alignof(_Storage)
86 && is_nothrow_move_constructible_v<_Tp>;
87 }
88
89 template<typename _Tp, typename... _Args>
90 static consteval bool
91 _S_nothrow_init() noexcept
92 {
93 if constexpr (_S_stored_locally<_Tp>())
94 return is_nothrow_constructible_v<_Tp, _Args...>;
95 return false;
96 }
97
98 template<typename _Tp, typename... _Args>
99 void
100 _M_init(_Args&&... __args) noexcept(_S_nothrow_init<_Tp, _Args...>())
101 {
102 if constexpr (is_function_v<remove_pointer_t<_Tp>>)
103 {
104 static_assert( sizeof...(__args) <= 1 );
105 // __args can have up to one element, returns nullptr if empty.
106 _Tp __func = (nullptr, ..., __args);
107 _M_ptrs._M_func = reinterpret_cast<void(*)()>(__func);
108 }
109 else if constexpr (!_S_stored_locally<_Tp>())
110 _M_ptrs._M_obj = new _Tp(std::forward<_Args>(__args)...);
111 else
112 ::new (_M_addr()) _Tp(std::forward<_Args>(__args)...);
113 }
114
115 // We want to have enough space to store a simple delegate type.
116 struct _Delegate { void (_Storage::*__pfm)(); _Storage* __obj; };
117 union {
118 _Ptrs _M_ptrs;
119 alignas(_Delegate) alignas(void(*)())
120 unsigned char _M_bytes[sizeof(_Delegate)];
121 };
122 };
123
124 template<bool _Noex, typename _Ret, typename... _Args>
125 struct _Base_invoker
126 {
127 using _Signature = _Ret(*)(_Args...) noexcept(_Noex);
128
129 using __storage_func_t = _Ret(*)(const _Storage&, _Args...) noexcept(_Noex);
130 template<typename _Tp>
131 static consteval __storage_func_t
132 _S_storage()
133 { return &_S_call_storage<_Adjust_target<_Tp>>; }
134
135 using __ptrs_func_t = _Ret(*)(_Ptrs, _Args...) noexcept(_Noex);
136 template<typename _Tp>
137 static consteval __ptrs_func_t
138 _S_ptrs()
139 { return &_S_call_ptrs<_Adjust_target<_Tp>>; }
140
141#ifdef __glibcxx_function_ref // C++ >= 26
142 template<auto __fn>
143 static _Ret
144 _S_nttp(_Ptrs, _Args... __args) noexcept(_Noex)
145 { return std::__invoke_r<_Ret>(__fn, std::forward<_Args>(__args)...); }
146
147 template<auto __fn, typename _Tp>
148 static _Ret
149 _S_bind_ptr(_Ptrs __ptrs, _Args... __args) noexcept(_Noex)
150 {
151 auto* __p = __polyfunc::__cast_to<_Tp>(__ptrs);
152 return std::__invoke_r<_Ret>(__fn, __p,
153 std::forward<_Args>(__args)...);
154 }
155
156 template<auto __fn, typename _Ref>
157 static _Ret
158 _S_bind_ref(_Ptrs __ptrs, _Args... __args) noexcept(_Noex)
159 {
160 auto* __p = __polyfunc::__cast_to<_Ref>(__ptrs);
161 return std::__invoke_r<_Ret>(__fn, static_cast<_Ref>(*__p),
162 std::forward<_Args>(__args)...);
163 }
164#endif // __glibcxx_function_ref
165
166 private:
167 template<typename _Tp, typename _Td = remove_cvref_t<_Tp>>
168 using _Adjust_target =
169 __conditional_t<is_pointer_v<_Td> || is_member_pointer_v<_Td>, _Td, _Tp>;
170
171 template<typename _Tp>
172 static _Ret
173 _S_call_storage(const _Storage& __ref, _Args... __args) noexcept(_Noex)
174 {
175 _Ptrs __ptrs;
176 if constexpr (is_function_v<remove_pointer_t<_Tp>>)
177 __ptrs._M_func = __ref._M_ptrs._M_func;
178 else if constexpr (!_Storage::_S_stored_locally<remove_cvref_t<_Tp>>())
179 __ptrs._M_obj = __ref._M_ptrs._M_obj;
180 else
181 __ptrs._M_obj = __ref._M_addr();
182 return _S_call_ptrs<_Tp>(__ptrs, std::forward<_Args>(__args)...);
183 }
184
185 template<typename _Tp>
186 static _Ret
187 _S_call_ptrs(_Ptrs __ptrs, _Args... __args) noexcept(_Noex)
188 {
189 if constexpr (is_function_v<remove_pointer_t<_Tp>>)
190 return std::__invoke_r<_Ret>(reinterpret_cast<_Tp>(__ptrs._M_func),
191 std::forward<_Args>(__args)...);
192 else
193 {
194 auto* __p = __polyfunc::__cast_to<_Tp>(__ptrs);
195 return std::__invoke_r<_Ret>(static_cast<_Tp>(*__p),
196 std::forward<_Args>(__args)...);
197 }
198 }
199 };
200
201 template<typename _Tp>
202 consteval bool
203 __pass_by_value()
204 {
205 // n.b. sizeof(Incomplete&) is ill-formed for incomplete types,
206 // so we check is_reference_v first.
207 if constexpr (is_reference_v<_Tp> || is_scalar_v<_Tp>)
208 return true;
209 else
210 // n.b. we already asserted that types are complete in wrappers,
211 // avoid triggering additional errors from this function.
212 if constexpr (std::__is_complete_or_unbounded(__type_identity<_Tp>()))
213 if constexpr (sizeof(_Tp) <= 2 * sizeof(void*))
214 return is_trivially_move_constructible_v<_Tp>
215 && is_trivially_destructible_v<_Tp>;
216 return false;
217 }
218
219 template<typename _Tp>
220 using __param_t = __conditional_t<__pass_by_value<_Tp>(), _Tp, _Tp&&>;
221
222 template<bool _Noex, typename _Ret, typename... _Args>
223 using _Invoker = _Base_invoker<_Noex, remove_cv_t<_Ret>, __param_t<_Args>...>;
224
225 template<typename _Func>
226 auto&
227 __invoker_of(_Func& __f) noexcept
228 { return __f._M_invoke; }
229
230 template<typename _Func>
231 auto&
232 __base_of(_Func& __f) noexcept
233 { return static_cast<__like_t<_Func&, typename _Func::_Base>>(__f); }
234
235 template<typename _Src, typename _Dst>
236 consteval bool
237 __is_invoker_convertible() noexcept
238 {
239 if constexpr (requires { typename _Src::_Signature; })
240 return is_convertible_v<typename _Src::_Signature,
241 typename _Dst::_Signature>;
242 else
243 return false;
244 }
245
246#if __glibcxx_move_only_function || __glibcxx_copyable_function
247 struct _Manager
248 {
249 enum class _Op
250 {
251 // saves address of entity in *__src to __target._M_ptrs,
252 _Address,
253 // moves entity stored in *__src to __target, __src becomes empty
254 _Move,
255 // copies entity stored in *__src to __target, supported only if
256 // _ProvideCopy is specified.
257 _Copy,
258 // destroys entity stored in __target, __src is ignoring
259 _Destroy,
260 };
261
262 // A function that performs operation __op on the __target and possibly __src.
263 using _Func = void (*)(_Op __op, _Storage& __target, const _Storage* __src);
264
265 // The no-op manager function for objects with no target.
266 static void _S_empty(_Op, _Storage&, const _Storage*) noexcept { }
267
268 template<bool _ProvideCopy, typename _Tp>
269 consteval static auto
270 _S_select()
271 {
272 if constexpr (is_function_v<remove_pointer_t<_Tp>>)
273 return &_S_func;
274 else if constexpr (!_Storage::_S_stored_locally<_Tp>())
275 return &_S_ptr<_ProvideCopy, _Tp>;
276 else if constexpr (is_trivially_copyable_v<_Tp>)
277 return &_S_trivial;
278 else
279 return &_S_local<_ProvideCopy, _Tp>;
280 }
281
282 private:
283 static void
284 _S_func(_Op __op, _Storage& __target, const _Storage* __src) noexcept
285 {
286 switch (__op)
287 {
288 case _Op::_Address:
289 case _Op::_Move:
290 case _Op::_Copy:
291 __target._M_ptrs._M_func = __src->_M_ptrs._M_func;
292 return;
293 case _Op::_Destroy:
294 return;
295 }
296 }
297
298 static void
299 _S_trivial(_Op __op, _Storage& __target, const _Storage* __src) noexcept
300 {
301 switch (__op)
302 {
303 case _Op::_Address:
304 __target._M_ptrs._M_obj = __src->_M_addr();
305 return;
306 case _Op::_Move:
307 case _Op::_Copy:
308 // N.B. Creating _Storage starts lifetime of _M_bytes char array,
309 // that implicitly creates, amongst other, all possible trivially
310 // copyable objects, so we copy any object present in __src._M_bytes.
311 ::new (&__target) _Storage(*__src);
312 return;
313 case _Op::_Destroy:
314 return;
315 }
316 }
317
318 template<bool _Provide_copy, typename _Tp>
319 static void
320 _S_local(_Op __op, _Storage& __target, const _Storage* __src)
321 noexcept(!_Provide_copy)
322 {
323 switch (__op)
324 {
325 case _Op::_Address:
326 __target._M_ptrs._M_obj = __src->_M_addr();
327 return;
328 case _Op::_Move:
329 {
330 _Tp* __obj = static_cast<_Tp*>(const_cast<void*>(__src->_M_addr()));
331 ::new(__target._M_addr()) _Tp(std::move(*__obj));
332 __obj->~_Tp();
333 }
334 return;
335 case _Op::_Destroy:
336 static_cast<_Tp*>(__target._M_addr())->~_Tp();
337 return;
338 case _Op::_Copy:
339 if constexpr (_Provide_copy)
340 {
341 auto* __obj = static_cast<const _Tp*>(__src->_M_addr());
342 ::new (__target._M_addr()) _Tp(*__obj);
343 return;
344 }
345 __builtin_unreachable();
346 }
347 }
348
349 template<bool _Provide_copy, typename _Tp>
350 static void
351 _S_ptr(_Op __op, _Storage& __target, const _Storage* __src)
352 noexcept(!_Provide_copy)
353 {
354 switch (__op)
355 {
356 case _Op::_Address:
357 case _Op::_Move:
358 __target._M_ptrs._M_obj = __src->_M_ptrs._M_obj;
359 return;
360 case _Op::_Destroy:
361 delete static_cast<const _Tp*>(__target._M_ptrs._M_obj);
362 return;
363 case _Op::_Copy:
364 if constexpr (_Provide_copy)
365 {
366 auto* __obj = static_cast<const _Tp*>(__src->_M_ptrs._M_obj);
367 __target._M_ptrs._M_obj = new _Tp(*__obj);
368 return;
369 }
370 __builtin_unreachable();
371 }
372 }
373 };
374
375 class _Mo_base
376 {
377 protected:
378 _Mo_base() noexcept
379 : _M_manage(_Manager::_S_empty)
380 { }
381
382 _Mo_base(_Mo_base&& __x) noexcept
383 { _M_move(__x); }
384
385 template<typename _Tp, typename... _Args>
386 static consteval bool
387 _S_nothrow_init() noexcept
388 { return _Storage::_S_nothrow_init<_Tp, _Args...>(); }
389
390 template<typename _Tp, typename... _Args>
391 void
392 _M_init(_Args&&... __args)
393 noexcept(_S_nothrow_init<_Tp, _Args...>())
394 {
395 _M_storage._M_init<_Tp>(std::forward<_Args>(__args)...);
396 _M_manage = _Manager::_S_select<false, _Tp>();
397 }
398
399 void
400 _M_move(_Mo_base& __x) noexcept
401 {
402 using _Op = _Manager::_Op;
403 _M_manage = std::__exchange(__x._M_manage, _Manager::_S_empty);
404 _M_manage(_Op::_Move, _M_storage, &__x._M_storage);
405 }
406
407 _Mo_base&
408 operator=(_Mo_base&& __x) noexcept
409 {
410 _M_destroy();
411 _M_move(__x);
412 return *this;
413 }
414
415 void
416 _M_reset() noexcept
417 {
418 _M_destroy();
419 _M_manage = _Manager::_S_empty;
420 }
421
422 void _M_destroy() noexcept
423 { _M_manage(_Manager::_Op::_Destroy, _M_storage, nullptr); }
424
425 ~_Mo_base()
426 { _M_destroy(); }
427
428 void
429 swap(_Mo_base& __x) noexcept
430 {
431 using _Op = _Manager::_Op;
432 // Order of operations here is more efficient if __x is empty.
433 _Storage __s;
434 __x._M_manage(_Op::_Move, __s, &__x._M_storage);
435 _M_manage(_Op::_Move, __x._M_storage, &_M_storage);
436 __x._M_manage(_Op::_Move, _M_storage, &__s);
437 std::swap(_M_manage, __x._M_manage);
438 }
439
440 _Manager::_Func _M_manage;
441 _Storage _M_storage;
442 };
443#endif // __glibcxx_copyable_function || __glibcxx_copyable_function
444} // namespace __polyfunc
445 /// @endcond
446
447#ifdef __glibcxx_move_only_function // C++ >= 23 && HOSTED
448 template<typename... _Signature>
449 class move_only_function; // not defined
450
451 /// @cond undocumented
452 template<typename _Tp>
453 constexpr bool __is_polymorphic_function_v<move_only_function<_Tp>> = true;
454
455 namespace __detail::__variant
456 {
457 template<typename> struct _Never_valueless_alt; // see <variant>
458
459 // Provide the strong exception-safety guarantee when emplacing a
460 // move_only_function into a variant.
461 template<typename... _Signature>
462 struct _Never_valueless_alt<std::move_only_function<_Signature...>>
463 : true_type
464 { };
465 } // namespace __detail::__variant
466 /// @endcond
467#endif // __glibcxx_move_only_function
468
469#ifdef __glibcxx_copyable_function // C++ >= 26 && HOSTED
470 /// @cond undocumented
471 namespace __polyfunc
472 {
473 class _Cpy_base : public _Mo_base
474 {
475 protected:
476 _Cpy_base() = default;
477
478 template<typename _Tp, typename... _Args>
479 void
480 _M_init(_Args&&... __args)
481 noexcept(_S_nothrow_init<_Tp, _Args...>())
482 {
483 _M_storage._M_init<_Tp>(std::forward<_Args>(__args)...);
484 _M_manage = _Manager::_S_select<true, _Tp>();
485 }
486
487 void
488 _M_copy(_Cpy_base const& __x)
489 {
490 using _Op = _Manager::_Op;
491 __x._M_manage(_Op::_Copy, _M_storage, &__x._M_storage);
492 _M_manage = __x._M_manage;
493 }
494
495 _Cpy_base(_Cpy_base&&) = default;
496
497 _Cpy_base(_Cpy_base const& __x)
498 { _M_copy(__x); }
499
500 _Cpy_base&
501 operator=(_Cpy_base&&) = default;
502
503 _Cpy_base&
504 // Needs to use copy and swap for exception guarantees.
505 operator=(_Cpy_base const&) = delete;
506 };
507 } // namespace __polyfunc
508 /// @endcond
509
510 template<typename... _Signature>
511 class copyable_function; // not defined
512
513 template<typename _Tp>
514 constexpr bool __is_polymorphic_function_v<copyable_function<_Tp>> = true;
515
516 namespace __detail::__variant
517 {
518 template<typename> struct _Never_valueless_alt; // see <variant>
519
520 // Provide the strong exception-safety guarantee when emplacing a
521 // copyable_function into a variant.
522 template<typename... _Signature>
523 struct _Never_valueless_alt<std::copyable_function<_Signature...>>
524 : true_type
525 { };
526 } // namespace __detail::__variant
527#endif // __glibcxx_copyable_function
528
529#ifdef __glibcxx_function_ref // C++ >= 26
530 /// @cond undocumented
531 namespace __polyfunc
532 {
533 template<typename _Sig>
534 struct __skip_first_arg;
535
536 // Additional partial specializations are defined in bits/funcref_impl.h
537 template<bool _Noex, typename _Ret, typename _Arg, typename... _Args>
538 struct __skip_first_arg<_Ret(*)(_Arg, _Args...) noexcept(_Noex)>
539 { using type = _Ret(_Args...) noexcept(_Noex); };
540
541 template<typename _Fn, typename _Tr>
542 consteval auto
543 __deduce_funcref()
544 {
545 if constexpr (is_member_object_pointer_v<_Fn>)
546 // TODO Consider reporting issue to make this noexcept
547 return static_cast<invoke_result_t<_Fn, _Tr>(*)()>(nullptr);
548 else
549 return static_cast<__skip_first_arg<_Fn>::type*>(nullptr);
550 }
551 } // namespace __polyfunc
552 /// @endcond
553
554 template<typename... _Signature>
555 class function_ref; // not defined
556
557 template<typename _Fn>
558 requires is_function_v<_Fn>
559 function_ref(_Fn*) -> function_ref<_Fn>;
560
561 template<auto __f, class _Fn = remove_pointer_t<decltype(__f)>>
562 requires is_function_v<_Fn>
563 function_ref(nontype_t<__f>) -> function_ref<_Fn>;
564
565 template<auto __f, typename _Tp, class _Fn = decltype(__f)>
566 requires is_member_pointer_v<_Fn> || is_function_v<remove_pointer_t<_Fn>>
567 function_ref(nontype_t<__f>, _Tp&&)
568 -> function_ref<
569 remove_pointer_t<decltype(__polyfunc::__deduce_funcref<_Fn, _Tp&>())>>;
570
571#endif // __glibcxx_function_ref
572
573_GLIBCXX_END_NAMESPACE_VERSION
574} // namespace std
575
576#ifdef __glibcxx_move_only_function // C++ >= 23 && HOSTED
577#include "mofunc_impl.h"
578#define _GLIBCXX_MOF_CV const
579#include "mofunc_impl.h"
580#define _GLIBCXX_MOF_REF &
581#include "mofunc_impl.h"
582#define _GLIBCXX_MOF_REF &&
583#include "mofunc_impl.h"
584#define _GLIBCXX_MOF_CV const
585#define _GLIBCXX_MOF_REF &
586#include "mofunc_impl.h"
587#define _GLIBCXX_MOF_CV const
588#define _GLIBCXX_MOF_REF &&
589#include "mofunc_impl.h"
590#endif // __glibcxx_move_only_function
591
592#ifdef __glibcxx_copyable_function // C++ >= 26 && HOSTED
593#include "cpyfunc_impl.h"
594#define _GLIBCXX_MOF_CV const
595#include "cpyfunc_impl.h"
596#define _GLIBCXX_MOF_REF &
597#include "cpyfunc_impl.h"
598#define _GLIBCXX_MOF_REF &&
599#include "cpyfunc_impl.h"
600#define _GLIBCXX_MOF_CV const
601#define _GLIBCXX_MOF_REF &
602#include "cpyfunc_impl.h"
603#define _GLIBCXX_MOF_CV const
604#define _GLIBCXX_MOF_REF &&
605#include "cpyfunc_impl.h"
606#endif // __glibcxx_copyable_function
607
608#ifdef __glibcxx_function_ref // C++ >= 26
609#include "funcref_impl.h"
610#define _GLIBCXX_MOF_CV const
611#include "funcref_impl.h"
612#endif // __glibcxx_function_ref
613
614#endif // move_only_function || copyable_function || function_ref
615#endif // _GLIBCXX_FUNCWRAP_H
__bool_constant< true > true_type
The type used as a compile-time boolean with true value.
Definition type_traits:116
constexpr _Tp && forward(typename std::remove_reference< _Tp >::type &__t) noexcept
Forward an lvalue.
Definition move.h:72
ISO C++ entities toplevel namespace is std.
constexpr void _Destroy(_ForwardIterator __first, _ForwardIterator __last)