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