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 
48 namespace 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
stl_function.h
std::move
constexpr std::remove_reference< _Tp >::type && move(_Tp &&__t) noexcept
Convert a value to an rvalue.
Definition: move.h:138
utility.h
std::true_type
__bool_constant< true > true_type
The type used as a compile-time boolean with true value.
Definition: type_traits:119
std::_Destroy
constexpr void _Destroy(_ForwardIterator __first, _ForwardIterator __last)
Definition: stl_construct.h:218
invoke.h
std
ISO C++ entities toplevel namespace is std.
funcref_impl.h
mofunc_impl.h
version.h
std::forward
constexpr _Tp && forward(typename std::remove_reference< _Tp >::type &__t) noexcept
Forward an lvalue.
Definition: move.h:72
cpyfunc_impl.h