// Implementation of std::move_only_function, std::copyable_function // and std::function_ref -*- C++ -*- // Copyright The GNU Toolchain Authors. // // This file is part of the GNU ISO C++ Library. This library is free // software; you can redistribute it and/or modify it under the // terms of the GNU General Public License as published by the // Free Software Foundation; either version 3, or (at your option) // any later version. // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // Under Section 7 of GPL version 3, you are granted additional // permissions described in the GCC Runtime Library Exception, version // 3.1, as published by the Free Software Foundation. // You should have received a copy of the GNU General Public License and // a copy of the GCC Runtime Library Exception along with this program; // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see // . /** @file include/bits/binder.h * This is an internal header file, included by other library headers. * Do not attempt to use it directly. @headername{functional} */ #ifndef _GLIBCXX_BINDERS_H #define _GLIBCXX_BINDERS_H 1 #ifdef _GLIBCXX_SYSHDR #pragma GCC system_header #endif #if __cplusplus >= 202002L #include #include namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION template struct _Indexed_bound_arg { [[no_unique_address]] _Tp _M_val; }; template struct _Bound_arg_storage : _IndexedArgs... { template static constexpr decltype(auto) _S_apply(_Fd&& __fd, _Self&& __self, _CallArgs&&... __call_args) { if constexpr (_Back) return std::__invoke(std::forward<_Fd>(__fd), std::forward<_CallArgs>(__call_args)..., __like_t<_Self, _IndexedArgs>(__self)._M_val...); else return std::__invoke(std::forward<_Fd>(__fd), __like_t<_Self, _IndexedArgs>(__self)._M_val..., std::forward<_CallArgs>(__call_args)...); } }; template constexpr auto __make_bound_args(_Args&&... __args) { if constexpr (sizeof...(_BoundArgs) == 1) // pack has one element, so return copy of arg return (_BoundArgs(std::forward<_Args>(__args)), ...); else { auto __impl = [&](index_sequence<_Inds...>) { return _Bound_arg_storage<_Indexed_bound_arg<_Inds, _BoundArgs>...> { {_BoundArgs(std::forward<_Args>(__args))}... }; }; return __impl(index_sequence_for<_BoundArgs...>()); } } template class _Binder { template using _Result_t = __conditional_t< _Back, invoke_result<__like_t<_Self, _Fd>, _CallArgs..., __like_t<_Self, _BoundArgs>...>, invoke_result<__like_t<_Self, _Fd>, __like_t<_Self, _BoundArgs>..., _CallArgs...>>::type; template static consteval bool _S_noexcept_invocable() { if constexpr (_Back) return is_nothrow_invocable_v< __like_t<_Self, _Fd>, _CallArgs..., __like_t<_Self, _BoundArgs>...>; else return is_nothrow_invocable_v<__like_t<_Self, _Fd>, __like_t<_Self, _BoundArgs>..., _CallArgs...>; } public: static_assert(is_move_constructible_v<_Fd>); static_assert((is_move_constructible_v<_BoundArgs> && ...)); // First parameter is to ensure this constructor is never used // instead of the copy/move constructor. template explicit constexpr _Binder(int, _Fn&& __fn, _Args&&... __args) noexcept(__and_, is_nothrow_constructible<_BoundArgs, _Args>...>::value) : _M_fd(std::forward<_Fn>(__fn)), _M_bound_args(__make_bound_args<_BoundArgs...>(std::forward<_Args>(__args)...)) { static_assert(sizeof...(_Args) == sizeof...(_BoundArgs)); } #if __cpp_explicit_this_parameter template constexpr _Result_t<_Self, _CallArgs...> operator()(this _Self&& __self, _CallArgs&&... __call_args) noexcept(_S_noexcept_invocable<_Self, _CallArgs...>()) { return _S_call(__like_t<_Self, _Binder>(__self), std::forward<_CallArgs>(__call_args)...); } #else template requires true constexpr _Result_t<_Binder&, _CallArgs...> operator()(_CallArgs&&... __call_args) & noexcept(_S_noexcept_invocable<_Binder&, _CallArgs...>()) { return _S_call(*this, std::forward<_CallArgs>(__call_args)...); } template requires true constexpr _Result_t operator()(_CallArgs&&... __call_args) const & noexcept(_S_noexcept_invocable()) { return _S_call(*this, std::forward<_CallArgs>(__call_args)...); } template requires true constexpr _Result_t<_Binder&&, _CallArgs...> operator()(_CallArgs&&... __call_args) && noexcept(_S_noexcept_invocable<_Binder&&, _CallArgs...>()) { return _S_call(std::move(*this), std::forward<_CallArgs>(__call_args)...); } template requires true constexpr _Result_t operator()(_CallArgs&&... __call_args) const && noexcept(_S_noexcept_invocable()) { return _S_call(std::move(*this), std::forward<_CallArgs>(__call_args)...); } template void operator()(_CallArgs&&...) & = delete; template void operator()(_CallArgs&&...) const & = delete; template void operator()(_CallArgs&&...) && = delete; template void operator()(_CallArgs&&...) const && = delete; #endif template static constexpr decltype(auto) _S_call(_Tp&& __g, _CallArgs&&... __call_args) { if constexpr (sizeof...(_BoundArgs) > 1) return _BoundArgsStorage::template _S_apply<_Back>( std::forward<_Tp>(__g)._M_fd, std::forward<_Tp>(__g)._M_bound_args, std::forward<_CallArgs>(__call_args)...); else if constexpr (sizeof...(_BoundArgs) == 0) return std::__invoke(std::forward<_Tp>(__g)._M_fd, std::forward<_CallArgs>(__call_args)...); else if constexpr (_Back) // sizeof...(_BoundArgs) == 1 return std::__invoke(std::forward<_Tp>(__g)._M_fd, std::forward<_CallArgs>(__call_args)..., std::forward<_Tp>(__g)._M_bound_args); else // !_Back && sizeof...(_BoundArgs) == 1 return std::__invoke(std::forward<_Tp>(__g)._M_fd, std::forward<_Tp>(__g)._M_bound_args, std::forward<_CallArgs>(__call_args)...); } private: using _BoundArgsStorage // _BoundArgs are required to be move-constructible, so this is valid. = decltype(__make_bound_args<_BoundArgs...>(std::declval<_BoundArgs>()...)); [[no_unique_address]] _Fd _M_fd; [[no_unique_address]] _BoundArgsStorage _M_bound_args; }; template using _Bind_front_t = _Binder, decay_t<_Args>...>; // for zero bounds args behavior of bind_front and bind_back is the same, // so reuse _Bind_front_t, i.e. _Binder template using _Bind_back_t = _Binder<(sizeof...(_Args) > 0), decay_t<_Fn>, decay_t<_Args>...>; _GLIBCXX_END_NAMESPACE_VERSION } // namespace std #endif // __cplusplus >= 202002L #endif // _GLIBCXX_BINDERS_H