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