xref: /netbsd-src/external/gpl3/gcc/dist/libstdc++-v3/include/bits/move_only_function.h (revision b1e838363e3c6fc78a55519254d99869742dd33c)
1*b1e83836Smrg // Implementation of std::move_only_function -*- C++ -*-
2*b1e83836Smrg 
3*b1e83836Smrg // Copyright The GNU Toolchain Authors.
4*b1e83836Smrg //
5*b1e83836Smrg // This file is part of the GNU ISO C++ Library.  This library is free
6*b1e83836Smrg // software; you can redistribute it and/or modify it under the
7*b1e83836Smrg // terms of the GNU General Public License as published by the
8*b1e83836Smrg // Free Software Foundation; either version 3, or (at your option)
9*b1e83836Smrg // any later version.
10*b1e83836Smrg 
11*b1e83836Smrg // This library is distributed in the hope that it will be useful,
12*b1e83836Smrg // but WITHOUT ANY WARRANTY; without even the implied warranty of
13*b1e83836Smrg // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14*b1e83836Smrg // GNU General Public License for more details.
15*b1e83836Smrg 
16*b1e83836Smrg // Under Section 7 of GPL version 3, you are granted additional
17*b1e83836Smrg // permissions described in the GCC Runtime Library Exception, version
18*b1e83836Smrg // 3.1, as published by the Free Software Foundation.
19*b1e83836Smrg 
20*b1e83836Smrg // You should have received a copy of the GNU General Public License and
21*b1e83836Smrg // a copy of the GCC Runtime Library Exception along with this program;
22*b1e83836Smrg // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
23*b1e83836Smrg // <http://www.gnu.org/licenses/>.
24*b1e83836Smrg 
25*b1e83836Smrg /** @file include/bits/move_only_function.h
26*b1e83836Smrg  *  This is an internal header file, included by other library headers.
27*b1e83836Smrg  *  Do not attempt to use it directly. @headername{functional}
28*b1e83836Smrg  */
29*b1e83836Smrg 
30*b1e83836Smrg #ifndef _GLIBCXX_MOVE_ONLY_FUNCTION_H
31*b1e83836Smrg #define _GLIBCXX_MOVE_ONLY_FUNCTION_H 1
32*b1e83836Smrg 
33*b1e83836Smrg #pragma GCC system_header
34*b1e83836Smrg 
35*b1e83836Smrg #if __cplusplus > 202002L
36*b1e83836Smrg 
37*b1e83836Smrg #include <bits/invoke.h>
38*b1e83836Smrg #include <bits/utility.h>
39*b1e83836Smrg 
_GLIBCXX_VISIBILITY(default)40*b1e83836Smrg namespace std _GLIBCXX_VISIBILITY(default)
41*b1e83836Smrg {
42*b1e83836Smrg _GLIBCXX_BEGIN_NAMESPACE_VERSION
43*b1e83836Smrg 
44*b1e83836Smrg #define __cpp_lib_move_only_function 202110L
45*b1e83836Smrg 
46*b1e83836Smrg   template<typename... _Signature>
47*b1e83836Smrg     class move_only_function; // not defined
48*b1e83836Smrg 
49*b1e83836Smrg   /// @cond undocumented
50*b1e83836Smrg   class _Mofunc_base
51*b1e83836Smrg   {
52*b1e83836Smrg   protected:
53*b1e83836Smrg     _Mofunc_base() noexcept
54*b1e83836Smrg     : _M_manage(_S_empty)
55*b1e83836Smrg     { }
56*b1e83836Smrg 
57*b1e83836Smrg     _Mofunc_base(_Mofunc_base&& __x) noexcept
58*b1e83836Smrg     {
59*b1e83836Smrg       _M_manage = std::__exchange(__x._M_manage, _S_empty);
60*b1e83836Smrg       _M_manage(_M_storage, &__x._M_storage);
61*b1e83836Smrg     }
62*b1e83836Smrg 
63*b1e83836Smrg     template<typename _Tp, typename... _Args>
64*b1e83836Smrg       static constexpr bool
65*b1e83836Smrg       _S_nothrow_init() noexcept
66*b1e83836Smrg       {
67*b1e83836Smrg 	if constexpr (__stored_locally<_Tp>)
68*b1e83836Smrg 	  return is_nothrow_constructible_v<_Tp, _Args...>;
69*b1e83836Smrg 	return false;
70*b1e83836Smrg       }
71*b1e83836Smrg 
72*b1e83836Smrg     template<typename _Tp, typename... _Args>
73*b1e83836Smrg       void
74*b1e83836Smrg       _M_init(_Args&&... __args) noexcept(_S_nothrow_init<_Tp, _Args...>())
75*b1e83836Smrg       {
76*b1e83836Smrg 	if constexpr (__stored_locally<_Tp>)
77*b1e83836Smrg 	  ::new (_M_storage._M_addr()) _Tp(std::forward<_Args>(__args)...);
78*b1e83836Smrg 	else
79*b1e83836Smrg 	  _M_storage._M_p = new _Tp(std::forward<_Args>(__args)...);
80*b1e83836Smrg 
81*b1e83836Smrg 	_M_manage = &_S_manage<_Tp>;
82*b1e83836Smrg       }
83*b1e83836Smrg 
84*b1e83836Smrg     _Mofunc_base&
85*b1e83836Smrg     operator=(_Mofunc_base&& __x) noexcept
86*b1e83836Smrg     {
87*b1e83836Smrg       _M_manage(_M_storage, nullptr);
88*b1e83836Smrg       _M_manage = std::__exchange(__x._M_manage, _S_empty);
89*b1e83836Smrg       _M_manage(_M_storage, &__x._M_storage);
90*b1e83836Smrg       return *this;
91*b1e83836Smrg     }
92*b1e83836Smrg 
93*b1e83836Smrg     _Mofunc_base&
94*b1e83836Smrg     operator=(nullptr_t) noexcept
95*b1e83836Smrg     {
96*b1e83836Smrg       _M_manage(_M_storage, nullptr);
97*b1e83836Smrg       _M_manage = _S_empty;
98*b1e83836Smrg       return *this;
99*b1e83836Smrg     }
100*b1e83836Smrg 
101*b1e83836Smrg     ~_Mofunc_base() { _M_manage(_M_storage, nullptr); }
102*b1e83836Smrg 
103*b1e83836Smrg     void
104*b1e83836Smrg     swap(_Mofunc_base& __x) noexcept
105*b1e83836Smrg     {
106*b1e83836Smrg       // Order of operations here is more efficient if __x is empty.
107*b1e83836Smrg       _Storage __s;
108*b1e83836Smrg       __x._M_manage(__s, &__x._M_storage);
109*b1e83836Smrg       _M_manage(__x._M_storage, &_M_storage);
110*b1e83836Smrg       __x._M_manage(_M_storage, &__s);
111*b1e83836Smrg       std::swap(_M_manage, __x._M_manage);
112*b1e83836Smrg     }
113*b1e83836Smrg 
114*b1e83836Smrg     template<typename _Tp, typename _Self>
115*b1e83836Smrg       static _Tp*
116*b1e83836Smrg       _S_access(_Self* __self) noexcept
117*b1e83836Smrg       {
118*b1e83836Smrg 	if constexpr (__stored_locally<remove_const_t<_Tp>>)
119*b1e83836Smrg 	  return static_cast<_Tp*>(__self->_M_storage._M_addr());
120*b1e83836Smrg 	else
121*b1e83836Smrg 	  return static_cast<_Tp*>(__self->_M_storage._M_p);
122*b1e83836Smrg       }
123*b1e83836Smrg 
124*b1e83836Smrg   private:
125*b1e83836Smrg     struct _Storage
126*b1e83836Smrg     {
127*b1e83836Smrg       void*       _M_addr() noexcept       { return &_M_bytes[0]; }
128*b1e83836Smrg       const void* _M_addr() const noexcept { return &_M_bytes[0]; }
129*b1e83836Smrg 
130*b1e83836Smrg       // We want to have enough space to store a simple delegate type.
131*b1e83836Smrg       struct _Delegate { void (_Storage::*__pfm)(); _Storage* __obj; };
132*b1e83836Smrg       union {
133*b1e83836Smrg 	void* _M_p;
134*b1e83836Smrg 	alignas(_Delegate) alignas(void(*)())
135*b1e83836Smrg 	  unsigned char _M_bytes[sizeof(_Delegate)];
136*b1e83836Smrg       };
137*b1e83836Smrg     };
138*b1e83836Smrg 
139*b1e83836Smrg     template<typename _Tp>
140*b1e83836Smrg       static constexpr bool __stored_locally
141*b1e83836Smrg 	= sizeof(_Tp) <= sizeof(_Storage) && alignof(_Tp) <= alignof(_Storage)
142*b1e83836Smrg 	    && is_nothrow_move_constructible_v<_Tp>;
143*b1e83836Smrg 
144*b1e83836Smrg     // A function that either destroys the target object stored in __target,
145*b1e83836Smrg     // or moves the target object from *__src to __target.
146*b1e83836Smrg     using _Manager = void (*)(_Storage& __target, _Storage* __src) noexcept;
147*b1e83836Smrg 
148*b1e83836Smrg     // The no-op manager function for objects with no target.
149*b1e83836Smrg     static void _S_empty(_Storage&, _Storage*) noexcept { }
150*b1e83836Smrg 
151*b1e83836Smrg     // The real manager function for a target object of type _Tp.
152*b1e83836Smrg     template<typename _Tp>
153*b1e83836Smrg       static void
154*b1e83836Smrg       _S_manage(_Storage& __target, _Storage* __src) noexcept
155*b1e83836Smrg       {
156*b1e83836Smrg 	if constexpr (__stored_locally<_Tp>)
157*b1e83836Smrg 	  {
158*b1e83836Smrg 	    if (__src)
159*b1e83836Smrg 	      {
160*b1e83836Smrg 		_Tp* __rval = static_cast<_Tp*>(__src->_M_addr());
161*b1e83836Smrg 		::new (__target._M_addr()) _Tp(std::move(*__rval));
162*b1e83836Smrg 		__rval->~_Tp();
163*b1e83836Smrg 	      }
164*b1e83836Smrg 	    else
165*b1e83836Smrg 	      static_cast<_Tp*>(__target._M_addr())->~_Tp();
166*b1e83836Smrg 	  }
167*b1e83836Smrg 	else
168*b1e83836Smrg 	  {
169*b1e83836Smrg 	    if (__src)
170*b1e83836Smrg 	      __target._M_p = __src->_M_p;
171*b1e83836Smrg 	    else
172*b1e83836Smrg 	      delete static_cast<_Tp*>(__target._M_p);
173*b1e83836Smrg 	  }
174*b1e83836Smrg       }
175*b1e83836Smrg 
176*b1e83836Smrg     _Storage _M_storage;
177*b1e83836Smrg     _Manager _M_manage;
178*b1e83836Smrg   };
179*b1e83836Smrg 
180*b1e83836Smrg   template<typename _Tp>
181*b1e83836Smrg     inline constexpr bool __is_move_only_function_v = false;
182*b1e83836Smrg   template<typename _Tp>
183*b1e83836Smrg     constexpr bool __is_move_only_function_v<move_only_function<_Tp>> = true;
184*b1e83836Smrg   /// @endcond
185*b1e83836Smrg 
186*b1e83836Smrg _GLIBCXX_END_NAMESPACE_VERSION
187*b1e83836Smrg } // namespace std
188*b1e83836Smrg 
189*b1e83836Smrg #include "mofunc_impl.h"
190*b1e83836Smrg #define _GLIBCXX_MOF_CV const
191*b1e83836Smrg #include "mofunc_impl.h"
192*b1e83836Smrg #define _GLIBCXX_MOF_REF &
193*b1e83836Smrg #include "mofunc_impl.h"
194*b1e83836Smrg #define _GLIBCXX_MOF_REF &&
195*b1e83836Smrg #include "mofunc_impl.h"
196*b1e83836Smrg #define _GLIBCXX_MOF_CV const
197*b1e83836Smrg #define _GLIBCXX_MOF_REF &
198*b1e83836Smrg #include "mofunc_impl.h"
199*b1e83836Smrg #define _GLIBCXX_MOF_CV const
200*b1e83836Smrg #define _GLIBCXX_MOF_REF &&
201*b1e83836Smrg #include "mofunc_impl.h"
202*b1e83836Smrg 
203*b1e83836Smrg #endif // C++23
204*b1e83836Smrg #endif // _GLIBCXX_MOVE_ONLY_FUNCTION_H
205