libstdc++
bits/binders.h
1 // Implementation of std::move_only_function, std::copyable_function
2 // and std::function_ref -*- C++ -*-
3 
4 // Copyright The GNU Toolchain Authors.
5 //
6 // This file is part of the GNU ISO C++ Library. This library is free
7 // software; you can redistribute it and/or modify it under the
8 // terms of the GNU General Public License as published by the
9 // Free Software Foundation; either version 3, or (at your option)
10 // any later version.
11 
12 // This library is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
16 
17 // Under Section 7 of GPL version 3, you are granted additional
18 // permissions described in the GCC Runtime Library Exception, version
19 // 3.1, as published by the Free Software Foundation.
20 
21 // You should have received a copy of the GNU General Public License and
22 // a copy of the GCC Runtime Library Exception along with this program;
23 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
24 // <http://www.gnu.org/licenses/>.
25 
26 /** @file include/bits/binder.h
27  * This is an internal header file, included by other library headers.
28  * Do not attempt to use it directly. @headername{functional}
29  */
30 
31 #ifndef _GLIBCXX_BINDERS_H
32 #define _GLIBCXX_BINDERS_H 1
33 
34 #ifdef _GLIBCXX_SYSHDR
35 #pragma GCC system_header
36 #endif
37 
38 #if __cplusplus >= 202002L
39 
40 #include <bits/invoke.h>
41 #include <bits/move.h>
42 
43 namespace std _GLIBCXX_VISIBILITY(default)
44 {
45 _GLIBCXX_BEGIN_NAMESPACE_VERSION
46 
47  template<size_t, typename _Tp>
48  struct _Indexed_bound_arg
49  {
50  [[no_unique_address]] _Tp _M_val;
51  };
52 
53  template<typename... _IndexedArgs>
54  struct _Bound_arg_storage : _IndexedArgs...
55  {
56  template<bool _Back, typename _Fd, typename _Self, typename... _CallArgs>
57  static constexpr
58  decltype(auto)
59  _S_apply(_Fd&& __fd, _Self&& __self, _CallArgs&&... __call_args)
60  {
61  if constexpr (_Back)
62  return std::__invoke(std::forward<_Fd>(__fd),
63  std::forward<_CallArgs>(__call_args)...,
64  __like_t<_Self, _IndexedArgs>(__self)._M_val...);
65  else
66  return std::__invoke(std::forward<_Fd>(__fd),
67  __like_t<_Self, _IndexedArgs>(__self)._M_val...,
68  std::forward<_CallArgs>(__call_args)...);
69  }
70  };
71 
72  template<typename... _BoundArgs, typename... _Args>
73  constexpr auto
74  __make_bound_args(_Args&&... __args)
75  {
76  if constexpr (sizeof...(_BoundArgs) == 1)
77  // pack has one element, so return copy of arg
78  return (_BoundArgs(std::forward<_Args>(__args)), ...);
79  else
80  {
81  auto __impl = [&]<size_t... _Inds>(index_sequence<_Inds...>)
82  {
83  return _Bound_arg_storage<_Indexed_bound_arg<_Inds, _BoundArgs>...>
84  { {_BoundArgs(std::forward<_Args>(__args))}... };
85  };
86  return __impl(index_sequence_for<_BoundArgs...>());
87  }
88  }
89 
90  template<bool _Back, typename _Fd, typename... _BoundArgs>
91  class _Binder
92  {
93  template<typename _Self, typename... _CallArgs>
94  using _Result_t = __conditional_t<
95  _Back,
96  invoke_result<__like_t<_Self, _Fd>,
97  _CallArgs..., __like_t<_Self, _BoundArgs>...>,
98  invoke_result<__like_t<_Self, _Fd>,
99  __like_t<_Self, _BoundArgs>..., _CallArgs...>>::type;
100 
101  template<typename _Self, typename... _CallArgs>
102  static consteval bool
103  _S_noexcept_invocable()
104  {
105  if constexpr (_Back)
106  return is_nothrow_invocable_v< __like_t<_Self, _Fd>,
107  _CallArgs..., __like_t<_Self, _BoundArgs>...>;
108  else
109  return is_nothrow_invocable_v<__like_t<_Self, _Fd>,
110  __like_t<_Self, _BoundArgs>..., _CallArgs...>;
111  }
112 
113  public:
114  static_assert(is_move_constructible_v<_Fd>);
115  static_assert((is_move_constructible_v<_BoundArgs> && ...));
116 
117  // First parameter is to ensure this constructor is never used
118  // instead of the copy/move constructor.
119  template<typename _Fn, typename... _Args>
120  explicit constexpr
121  _Binder(int, _Fn&& __fn, _Args&&... __args)
122  noexcept(__and_<is_nothrow_constructible<_Fd, _Fn>,
123  is_nothrow_constructible<_BoundArgs, _Args>...>::value)
124  : _M_fd(std::forward<_Fn>(__fn)),
125  _M_bound_args(__make_bound_args<_BoundArgs...>(std::forward<_Args>(__args)...))
126  { static_assert(sizeof...(_Args) == sizeof...(_BoundArgs)); }
127 
128 #if _GLIBCXX_EXPLICIT_THIS_PARAMETER
129 # pragma GCC diagnostic push
130 # pragma GCC diagnostic ignored "-Wc++23-extensions" // deducing this
131  template<typename _Self, typename... _CallArgs>
132  constexpr _Result_t<_Self, _CallArgs...>
133  operator()(this _Self&& __self, _CallArgs&&... __call_args)
134  noexcept(_S_noexcept_invocable<_Self, _CallArgs...>())
135  {
136  return _S_call(__like_t<_Self, _Binder>(__self),
137  std::forward<_CallArgs>(__call_args)...);
138  }
139 # pragma GCC diagnostic pop
140 #else
141  template<typename... _CallArgs>
142  requires true
143  constexpr _Result_t<_Binder&, _CallArgs...>
144  operator()(_CallArgs&&... __call_args) &
145  noexcept(_S_noexcept_invocable<_Binder&, _CallArgs...>())
146  {
147  return _S_call(*this, std::forward<_CallArgs>(__call_args)...);
148  }
149 
150  template<typename... _CallArgs>
151  requires true
152  constexpr _Result_t<const _Binder&, _CallArgs...>
153  operator()(_CallArgs&&... __call_args) const &
154  noexcept(_S_noexcept_invocable<const _Binder&, _CallArgs...>())
155  {
156  return _S_call(*this, std::forward<_CallArgs>(__call_args)...);
157  }
158 
159  template<typename... _CallArgs>
160  requires true
161  constexpr _Result_t<_Binder&&, _CallArgs...>
162  operator()(_CallArgs&&... __call_args) &&
163  noexcept(_S_noexcept_invocable<_Binder&&, _CallArgs...>())
164  {
165  return _S_call(std::move(*this),
166  std::forward<_CallArgs>(__call_args)...);
167  }
168 
169  template<typename... _CallArgs>
170  requires true
171  constexpr _Result_t<const _Binder&&, _CallArgs...>
172  operator()(_CallArgs&&... __call_args) const &&
173  noexcept(_S_noexcept_invocable<const _Binder&&, _CallArgs...>())
174  {
175  return _S_call(std::move(*this),
176  std::forward<_CallArgs>(__call_args)...);
177  }
178 
179  template<typename... _CallArgs>
180  void operator()(_CallArgs&&...) & = delete;
181 
182  template<typename... _CallArgs>
183  void operator()(_CallArgs&&...) const & = delete;
184 
185  template<typename... _CallArgs>
186  void operator()(_CallArgs&&...) && = delete;
187 
188  template<typename... _CallArgs>
189  void operator()(_CallArgs&&...) const && = delete;
190 #endif
191 
192  template<typename _Tp, typename... _CallArgs>
193  static constexpr
194  decltype(auto)
195  _S_call(_Tp&& __g, _CallArgs&&... __call_args)
196  {
197  if constexpr (sizeof...(_BoundArgs) > 1)
198  return _BoundArgsStorage::template _S_apply<_Back>(
199  std::forward<_Tp>(__g)._M_fd,
200  std::forward<_Tp>(__g)._M_bound_args,
201  std::forward<_CallArgs>(__call_args)...);
202  else if constexpr (sizeof...(_BoundArgs) == 0)
203  return std::__invoke(std::forward<_Tp>(__g)._M_fd,
204  std::forward<_CallArgs>(__call_args)...);
205  else if constexpr (_Back) // sizeof...(_BoundArgs) == 1
206  return std::__invoke(std::forward<_Tp>(__g)._M_fd,
207  std::forward<_CallArgs>(__call_args)...,
208  std::forward<_Tp>(__g)._M_bound_args);
209  else // !_Back && sizeof...(_BoundArgs) == 1
210  return std::__invoke(std::forward<_Tp>(__g)._M_fd,
211  std::forward<_Tp>(__g)._M_bound_args,
212  std::forward<_CallArgs>(__call_args)...);
213  }
214 
215  private:
216  using _BoundArgsStorage
217  // _BoundArgs are required to be move-constructible, so this is valid.
218  = decltype(__make_bound_args<_BoundArgs...>(std::declval<_BoundArgs>()...));
219 
220  [[no_unique_address]] _Fd _M_fd;
221  [[no_unique_address]] _BoundArgsStorage _M_bound_args;
222  };
223 
224  template<typename _Fn, typename... _Args>
225  using _Bind_front_t = _Binder<false, decay_t<_Fn>, decay_t<_Args>...>;
226 
227  // for zero bounds args behavior of bind_front and bind_back is the same,
228  // so reuse _Bind_front_t, i.e. _Binder<false, ...>
229  template<typename _Fn, typename... _Args>
230  using _Bind_back_t
231  = _Binder<(sizeof...(_Args) > 0), decay_t<_Fn>, decay_t<_Args>...>;
232 
233 _GLIBCXX_END_NAMESPACE_VERSION
234 } // namespace std
235 
236 #endif // __cplusplus >= 202002L
237 #endif // _GLIBCXX_BINDERS_H
typename decay< _Tp >::type decay_t
Alias template for decay.
Definition: type_traits:2938
auto declval() noexcept -> decltype(__declval< _Tp >(0))
Definition: type_traits:2716
constexpr __invoke_result< _Callable, _Args... >::type __invoke(_Callable &&__fn, _Args &&... __args) noexcept(__is_nothrow_invocable< _Callable, _Args... >::value)
Invoke a callable object.
Definition: invoke.h:92
constexpr std::remove_reference< _Tp >::type && move(_Tp &&__t) noexcept
Convert a value to an rvalue.
Definition: move.h:138
constexpr _Tp && forward(typename std::remove_reference< _Tp >::type &__t) noexcept
Forward an lvalue.
Definition: move.h:72
ISO C++ entities toplevel namespace is std.
integer_sequence< size_t, _Idx... > index_sequence
Alias template index_sequence.
Definition: utility.h:164