https://gcc.gnu.org/g:b2adb7712cc57920d7d791c185dbf88e83b885c2
commit r16-3574-gb2adb7712cc57920d7d791c185dbf88e83b885c2 Author: Tomasz Kamiński <tkami...@redhat.com> Date: Mon Sep 1 14:28:17 2025 +0200 libstdc++: Move _Binder and related aliases to separate file. bits/binders.h is already mapped in libstdc++-v3/doc/doxygen/stdheader.cc. libstdc++-v3/ChangeLog: * include/Makefile.am: Add bits/binders.h * include/Makefile.in: Add bits/binders.h * include/std/functional (std::_Indexed_bound_arg, std::_Binder) (std::__make_bound_args, std::_Bind_front_t, std::_Bind_back_t): Moved to bits/binders.h file, that is now included. * include/bits/binders.h: New file. Reviewed-by: Patrick Palka <ppa...@redhat.com> Reviewed-by: Jonathan Wakely <jwak...@redhat.com> Signed-off-by: Tomasz Kamiński <tkami...@redhat.com> Diff: --- libstdc++-v3/include/Makefile.am | 1 + libstdc++-v3/include/Makefile.in | 1 + libstdc++-v3/include/bits/binders.h | 234 ++++++++++++++++++++++++++++++++++++ libstdc++-v3/include/std/functional | 187 +--------------------------- 4 files changed, 237 insertions(+), 186 deletions(-) diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am index 6f5946970a89..0b0cbe2d3faf 100644 --- a/libstdc++-v3/include/Makefile.am +++ b/libstdc++-v3/include/Makefile.am @@ -191,6 +191,7 @@ bits_headers = \ ${bits_srcdir}/basic_ios.tcc \ ${bits_srcdir}/basic_string.h \ ${bits_srcdir}/basic_string.tcc \ + ${bits_srcdir}/binders.h \ ${bits_srcdir}/charconv.h \ ${bits_srcdir}/chrono.h \ ${bits_srcdir}/chrono_io.h \ diff --git a/libstdc++-v3/include/Makefile.in b/libstdc++-v3/include/Makefile.in index 4b5917ebb4ae..e3a6d5f13905 100644 --- a/libstdc++-v3/include/Makefile.in +++ b/libstdc++-v3/include/Makefile.in @@ -544,6 +544,7 @@ bits_freestanding = \ @GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/basic_ios.tcc \ @GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/basic_string.h \ @GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/basic_string.tcc \ +@GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/binders.h \ @GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/charconv.h \ @GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/chrono.h \ @GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/chrono_io.h \ diff --git a/libstdc++-v3/include/bits/binders.h b/libstdc++-v3/include/bits/binders.h new file mode 100644 index 000000000000..c324bf51481c --- /dev/null +++ b/libstdc++-v3/include/bits/binders.h @@ -0,0 +1,234 @@ +// 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 +// <http://www.gnu.org/licenses/>. + +/** @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 <bits/invoke.h> +#include <bits/move.h> + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + template<size_t, typename _Tp> + struct _Indexed_bound_arg + { + [[no_unique_address]] _Tp _M_val; + }; + + template<typename... _IndexedArgs> + struct _Bound_arg_storage : _IndexedArgs... + { + template<bool _Back, typename _Fd, typename _Self, typename... _CallArgs> + 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<typename... _BoundArgs, typename... _Args> + 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 = [&]<size_t... _Inds>(index_sequence<_Inds...>) + { + return _Bound_arg_storage<_Indexed_bound_arg<_Inds, _BoundArgs>...> + { {_BoundArgs(std::forward<_Args>(__args))}... }; + }; + return __impl(index_sequence_for<_BoundArgs...>()); + } + } + + template<bool _Back, typename _Fd, typename... _BoundArgs> + class _Binder + { + template<typename _Self, typename... _CallArgs> + 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<typename _Self, typename... _CallArgs> + 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<typename _Fn, typename... _Args> + explicit constexpr + _Binder(int, _Fn&& __fn, _Args&&... __args) + noexcept(__and_<is_nothrow_constructible<_Fd, _Fn>, + 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<typename _Self, typename... _CallArgs> + 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<typename... _CallArgs> + 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<typename... _CallArgs> + requires true + constexpr _Result_t<const _Binder&, _CallArgs...> + operator()(_CallArgs&&... __call_args) const & + noexcept(_S_noexcept_invocable<const _Binder&, _CallArgs...>()) + { + return _S_call(*this, std::forward<_CallArgs>(__call_args)...); + } + + template<typename... _CallArgs> + 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<typename... _CallArgs> + requires true + constexpr _Result_t<const _Binder&&, _CallArgs...> + operator()(_CallArgs&&... __call_args) const && + noexcept(_S_noexcept_invocable<const _Binder&&, _CallArgs...>()) + { + return _S_call(std::move(*this), + std::forward<_CallArgs>(__call_args)...); + } + + template<typename... _CallArgs> + void operator()(_CallArgs&&...) & = delete; + + template<typename... _CallArgs> + void operator()(_CallArgs&&...) const & = delete; + + template<typename... _CallArgs> + void operator()(_CallArgs&&...) && = delete; + + template<typename... _CallArgs> + void operator()(_CallArgs&&...) const && = delete; +#endif + + private: + using _BoundArgsStorage + // _BoundArgs are required to be move-constructible, so this is valid. + = decltype(__make_bound_args<_BoundArgs...>(std::declval<_BoundArgs>()...)); + + template<typename _Tp, typename... _CallArgs> + 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)...); + } + + [[no_unique_address]] _Fd _M_fd; + [[no_unique_address]] _BoundArgsStorage _M_bound_args; + }; + + template<typename _Fn, typename... _Args> + using _Bind_front_t = _Binder<false, decay_t<_Fn>, 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<false, ...> + template<typename _Fn, typename... _Args> + 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 diff --git a/libstdc++-v3/include/std/functional b/libstdc++-v3/include/std/functional index ad2397613f41..5b329daf184e 100644 --- a/libstdc++-v3/include/std/functional +++ b/libstdc++-v3/include/std/functional @@ -84,6 +84,7 @@ # include <bits/stl_algobase.h> // std::search #endif #if __cplusplus >= 202002L +# include <bits/binders.h> # include <bits/ranges_cmp.h> // std::identity, ranges::equal_to etc. # include <compare> #endif @@ -921,192 +922,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION std::forward<_BoundArgs>(__args)...); } -#if __cplusplus >= 202002L - template<size_t, typename _Tp> - struct _Indexed_bound_arg - { - [[no_unique_address]] _Tp _M_val; - }; - - template<typename... _IndexedArgs> - struct _Bound_arg_storage : _IndexedArgs... - { - template<bool _Back, typename _Fd, typename _Self, typename... _CallArgs> - 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<typename... _BoundArgs, typename... _Args> - 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 = [&]<size_t... _Inds>(index_sequence<_Inds...>) - { - return _Bound_arg_storage<_Indexed_bound_arg<_Inds, _BoundArgs>...> - { {_BoundArgs(std::forward<_Args>(__args))}... }; - }; - return __impl(index_sequence_for<_BoundArgs...>()); - } - } - - template<bool _Back, typename _Fd, typename... _BoundArgs> - class _Binder - { - template<typename _Self, typename... _CallArgs> - 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<typename _Self, typename... _CallArgs> - 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<typename _Fn, typename... _Args> - explicit constexpr - _Binder(int, _Fn&& __fn, _Args&&... __args) - noexcept(__and_<is_nothrow_constructible<_Fd, _Fn>, - 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<typename _Self, typename... _CallArgs> - 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<typename... _CallArgs> - 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<typename... _CallArgs> - requires true - constexpr _Result_t<const _Binder&, _CallArgs...> - operator()(_CallArgs&&... __call_args) const & - noexcept(_S_noexcept_invocable<const _Binder&, _CallArgs...>()) - { - return _S_call(*this, std::forward<_CallArgs>(__call_args)...); - } - - template<typename... _CallArgs> - 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<typename... _CallArgs> - requires true - constexpr _Result_t<const _Binder&&, _CallArgs...> - operator()(_CallArgs&&... __call_args) const && - noexcept(_S_noexcept_invocable<const _Binder&&, _CallArgs...>()) - { - return _S_call(std::move(*this), - std::forward<_CallArgs>(__call_args)...); - } - - template<typename... _CallArgs> - void operator()(_CallArgs&&...) & = delete; - - template<typename... _CallArgs> - void operator()(_CallArgs&&...) const & = delete; - - template<typename... _CallArgs> - void operator()(_CallArgs&&...) && = delete; - - template<typename... _CallArgs> - void operator()(_CallArgs&&...) const && = delete; -#endif - - private: - using _BoundArgsStorage - // _BoundArgs are required to be move-constructible, so this is valid. - = decltype(__make_bound_args<_BoundArgs...>(std::declval<_BoundArgs>()...)); - - template<typename _Tp, typename... _CallArgs> - 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)...); - - } - - [[no_unique_address]] _Fd _M_fd; - [[no_unique_address]] _BoundArgsStorage _M_bound_args; - }; - - template<typename _Fn, typename... _Args> - using _Bind_front_t = _Binder<false, decay_t<_Fn>, 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<false, ...> - template<typename _Fn, typename... _Args> - using _Bind_back_t - = _Binder<(sizeof...(_Args) > 0), decay_t<_Fn>, decay_t<_Args>...>; -#endif // __cplusplus >= 202002L - #ifdef __cpp_lib_bind_front // C++ >= 20 /** Create call wrapper by partial application of arguments to function. *