Home | History | Annotate | Line # | Download | only in bits
      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 
     43 namespace 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