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