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/mofunc_impl.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_MOF_CV
31# define _GLIBCXX_MOF_CV
32#endif
33
34#ifdef _GLIBCXX_MOF_REF
35# define _GLIBCXX_MOF_INV_QUALS _GLIBCXX_MOF_CV _GLIBCXX_MOF_REF
36#else
37# define _GLIBCXX_MOF_REF
38# define _GLIBCXX_MOF_INV_QUALS _GLIBCXX_MOF_CV &
39#endif
40
41#define _GLIBCXX_MOF_CV_REF _GLIBCXX_MOF_CV _GLIBCXX_MOF_REF
42
43namespace std _GLIBCXX_VISIBILITY(default)
44{
45_GLIBCXX_BEGIN_NAMESPACE_VERSION
46
47  /**
48   *  @brief Polymorphic function wrapper.
49   *  @ingroup functors
50   *  @since C++23
51   *  @headerfile functional
52   *
53   *  The `std::move_only_function` class template is a call wrapper similar
54   *  to `std::function`, but does not require the stored target function
55   *  to be copyable.
56   *
57   *  It also supports const-qualification, ref-qualification, and
58   *  no-throw guarantees. The qualifications and exception-specification
59   *  of the `move_only_function::operator()` member function are respected
60   *  when invoking the target function.
61   */
62  template<typename _Res, typename... _ArgTypes, bool _Noex>
63    class move_only_function<_Res(_ArgTypes...) _GLIBCXX_MOF_CV
64			       _GLIBCXX_MOF_REF noexcept(_Noex)>
65    : _Mofunc_base
66    {
67      template<typename _Tp>
68	using __callable
69	  = __conditional_t<_Noex,
70			    is_nothrow_invocable_r<_Res, _Tp, _ArgTypes...>,
71			    is_invocable_r<_Res, _Tp, _ArgTypes...>>;
72
73      // [func.wrap.mov.con]/1 is-callable-from<VT>
74      template<typename _Vt>
75	static constexpr bool __is_callable_from
76	  = __and_v<__callable<_Vt _GLIBCXX_MOF_CV_REF>,
77		    __callable<_Vt _GLIBCXX_MOF_INV_QUALS>>;
78
79    public:
80      using result_type = _Res;
81
82      /// Creates an empty object.
83      move_only_function() noexcept { }
84
85      /// Creates an empty object.
86      move_only_function(nullptr_t) noexcept { }
87
88      /// Moves the target object, leaving the source empty.
89      move_only_function(move_only_function&& __x) noexcept
90      : _Mofunc_base(static_cast<_Mofunc_base&&>(__x)),
91	_M_invoke(std::__exchange(__x._M_invoke, nullptr))
92      { }
93
94      /// Stores a target object initialized from the argument.
95      template<typename _Fn, typename _Vt = decay_t<_Fn>>
96	requires (!is_same_v<_Vt, move_only_function>)
97	  && (!__is_in_place_type_v<_Vt>) && __is_callable_from<_Vt>
98	move_only_function(_Fn&& __f) noexcept(_S_nothrow_init<_Vt, _Fn>())
99	{
100	  if constexpr (is_function_v<remove_pointer_t<_Vt>>
101			|| is_member_pointer_v<_Vt>
102			|| __is_move_only_function_v<_Vt>)
103	    {
104	      if (__f == nullptr)
105		return;
106	    }
107	  _M_init<_Vt>(std::forward<_Fn>(__f));
108	  _M_invoke = &_S_invoke<_Vt>;
109	}
110
111      /// Stores a target object initialized from the arguments.
112      template<typename _Tp, typename... _Args>
113	requires is_constructible_v<_Tp, _Args...>
114	  && __is_callable_from<_Tp>
115	explicit
116	move_only_function(in_place_type_t<_Tp>, _Args&&... __args)
117	noexcept(_S_nothrow_init<_Tp, _Args...>())
118	: _M_invoke(&_S_invoke<_Tp>)
119	{
120	  static_assert(is_same_v<decay_t<_Tp>, _Tp>);
121	  _M_init<_Tp>(std::forward<_Args>(__args)...);
122	}
123
124      /// Stores a target object initialized from the arguments.
125      template<typename _Tp, typename _Up, typename... _Args>
126	requires is_constructible_v<_Tp, initializer_list<_Up>&, _Args...>
127	  && __is_callable_from<_Tp>
128	explicit
129	move_only_function(in_place_type_t<_Tp>, initializer_list<_Up> __il,
130			   _Args&&... __args)
131	noexcept(_S_nothrow_init<_Tp, initializer_list<_Up>&, _Args...>())
132	: _M_invoke(&_S_invoke<_Tp>)
133	{
134	  static_assert(is_same_v<decay_t<_Tp>, _Tp>);
135	  _M_init<_Tp>(__il, std::forward<_Args>(__args)...);
136	}
137
138      /// Stores a new target object, leaving `x` empty.
139      move_only_function&
140      operator=(move_only_function&& __x) noexcept
141      {
142	_Mofunc_base::operator=(static_cast<_Mofunc_base&&>(__x));
143	_M_invoke = std::__exchange(__x._M_invoke, nullptr);
144	return *this;
145      }
146
147      /// Destroys the target object (if any).
148      move_only_function&
149      operator=(nullptr_t) noexcept
150      {
151	_Mofunc_base::operator=(nullptr);
152	_M_invoke = nullptr;
153	return *this;
154      }
155
156      /// Stores a new target object, initialized from the argument.
157      template<typename _Fn>
158	requires is_constructible_v<move_only_function, _Fn>
159	move_only_function&
160	operator=(_Fn&& __f)
161	noexcept(is_nothrow_constructible_v<move_only_function, _Fn>)
162	{
163	  move_only_function(std::forward<_Fn>(__f)).swap(*this);
164	  return *this;
165	}
166
167      ~move_only_function() = default;
168
169      /// True if a target object is present, false otherwise.
170      explicit operator bool() const noexcept { return _M_invoke != nullptr; }
171
172      /** Invoke the target object.
173       *
174       * The target object will be invoked using the supplied arguments,
175       * and as an lvalue or rvalue, and as const or non-const, as dictated
176       * by the template arguments of the `move_only_function` specialization.
177       *
178       * @pre Must not be empty.
179       */
180      _Res
181      operator()(_ArgTypes... __args) _GLIBCXX_MOF_CV_REF noexcept(_Noex)
182      {
183	__glibcxx_assert(*this != nullptr);
184	return _M_invoke(this, std::forward<_ArgTypes>(__args)...);
185      }
186
187      /// Exchange the target objects (if any).
188      void
189      swap(move_only_function& __x) noexcept
190      {
191	_Mofunc_base::swap(__x);
192	std::swap(_M_invoke, __x._M_invoke);
193      }
194
195      /// Exchange the target objects (if any).
196      friend void
197      swap(move_only_function& __x, move_only_function& __y) noexcept
198      { __x.swap(__y); }
199
200      /// Check for emptiness by comparing with `nullptr`.
201      friend bool
202      operator==(const move_only_function& __x, nullptr_t) noexcept
203      { return __x._M_invoke == nullptr; }
204
205    private:
206      template<typename _Tp>
207	using __param_t = __conditional_t<is_scalar_v<_Tp>, _Tp, _Tp&&>;
208
209      using _Invoker = _Res (*)(_Mofunc_base _GLIBCXX_MOF_CV*,
210				__param_t<_ArgTypes>...) noexcept(_Noex);
211
212      template<typename _Tp>
213	static _Res
214	_S_invoke(_Mofunc_base _GLIBCXX_MOF_CV* __self,
215		  __param_t<_ArgTypes>... __args) noexcept(_Noex)
216	{
217	  using _TpCv = _Tp _GLIBCXX_MOF_CV;
218	  using _TpInv = _Tp _GLIBCXX_MOF_INV_QUALS;
219	  return std::__invoke_r<_Res>(
220	      std::forward<_TpInv>(*_S_access<_TpCv>(__self)),
221	      std::forward<__param_t<_ArgTypes>>(__args)...);
222	}
223
224      _Invoker _M_invoke = nullptr;
225    };
226
227#undef _GLIBCXX_MOF_CV_REF
228#undef _GLIBCXX_MOF_CV
229#undef _GLIBCXX_MOF_REF
230#undef _GLIBCXX_MOF_INV_QUALS
231
232_GLIBCXX_END_NAMESPACE_VERSION
233} // namespace std
234