qxLib
delegate.inl
Go to the documentation of this file.
1 /**
2 
3  @file delegate.inl
4  @author Khrapov
5  @date 7.01.2024
6  @copyright © Nick Khrapov, 2024. All right reserved.
7 
8 **/
9 
10 namespace qx
11 {
12 
13 namespace details
14 {
15 
16 template<class return_t, class function_t>
18 {
19 public:
20  virtual ~base_invoker() noexcept = default;
21  virtual return_t invoke(const function_t& function) noexcept = 0;
22 };
23 
24 template<class return_t, class function_t, class invoke_function_t>
25 class invoker : public base_invoker<return_t, function_t>
26 {
27 public:
28  invoker(const invoke_function_t& invoke) noexcept : m_InvokeFunction(invoke)
29  {
30  }
31 
32 private:
33  virtual return_t invoke(const function_t& function) noexcept override
34  {
35  return m_InvokeFunction(function);
36  }
37 
38 private:
39  const invoke_function_t& m_InvokeFunction;
40 };
41 
42 } // namespace details
43 
44 template<class derived_t, delegate_return_c return_t, class... args_t>
46 {
47  std::swap(m_Functions, other.m_Functions);
48  std::swap(m_pDelegateAliveMarker, other.m_pDelegateAliveMarker);
49 }
50 
51 template<class derived_t, delegate_return_c return_t, class... args_t>
52 typename base_delegate<derived_t, return_t, args_t...>::base_delegate& base_delegate<derived_t, return_t, args_t...>::
53  operator=(base_delegate&& other) noexcept
54 {
55  std::swap(m_Functions, other.m_Functions);
56  std::swap(m_pDelegateAliveMarker, other.m_pDelegateAliveMarker);
57  return *this;
58 }
59 
60 template<class derived_t, delegate_return_c return_t, class... args_t>
61 template<class... creation_args_t>
62 derived_t base_delegate<derived_t, return_t, args_t...>::create_singlecast(creation_args_t... args) noexcept
63 {
64  derived_t delegate;
65  if constexpr (requires(derived_t d) { d.add_weak(args...); })
66  delegate.add_weak(args...);
67  if constexpr (requires(derived_t d) { d.add_free(args...); })
68  delegate.add_free(args...);
69  else
70  QX_STATIC_ASSERT_NO_INSTANTIATION("No overload that takes these args");
71 
72  return delegate;
73 }
74 
75 template<class derived_t, delegate_return_c return_t, class... args_t>
76 template<callable_c<return_t, args_t...> callable_t>
78  callable_t callable,
79  priority ePriority) noexcept
80 {
81  time_ordered_priority_key key(ePriority);
82  m_Functions.emplace(key, std::move(callable));
83  return key;
84 }
85 
86 template<class derived_t, delegate_return_c return_t, class... args_t>
87 template<callable_c<return_t, args_t...> callable_t>
89  callable_t callable,
90  priority ePriority) noexcept
91 {
92  return add_destruction_callback(time_ordered_priority_key(ePriority), function_type(std::move(callable)));
93 }
94 
95 template<class derived_t, delegate_return_c return_t, class... args_t>
96 template<class object_t>
98  object_t& object,
99  return_t (object_t::*pMethod)(args_t...),
100  priority ePriority) noexcept
101 {
103  time_ordered_priority_key(ePriority),
104  [&object, pMethod](args_t... args)
105  {
106  return (object.*pMethod)(std::forward<args_t>(args)...);
107  });
108 }
109 
110 template<class derived_t, delegate_return_c return_t, class... args_t>
111 template<class object_t>
113  std::weak_ptr<object_t> pWeakObject,
114  return_t (object_t::*pMethod)(args_t...),
115  priority ePriority) noexcept
116 {
117  time_ordered_priority_key key(ePriority);
118  add_weak(
119  key,
120  std::move(pWeakObject),
121  [pMethod](object_t* pObject, args_t... args)
122  {
123  return (pObject->*pMethod)(std::forward<args_t>(args)...);
124  });
125  return key;
126 }
127 
128 template<class derived_t, delegate_return_c return_t, class... args_t>
129 template<class object_t, callable_c<return_t, args_t...> callable_t>
131  std::weak_ptr<object_t> pWeakObject,
132  callable_t callable,
133  priority ePriority) noexcept
134 {
135  time_ordered_priority_key key(ePriority);
136  add_weak(
137  key,
138  std::move(pWeakObject),
139  [callable_ = std::move(callable)](object_t*, args_t... args)
140  {
141  return callable_(std::forward<args_t>(args)...);
142  });
143  return key;
144 }
145 
146 template<class derived_t, delegate_return_c return_t, class... args_t>
148 {
149  return m_Functions.erase(token) == 1;
150 }
151 
152 template<class derived_t, delegate_return_c return_t, class... args_t>
154 {
155  m_Functions.clear();
156 }
157 
158 template<class derived_t, delegate_return_c return_t, class... args_t>
159 template<class invoke_single_t, class invoke_multiple_t>
161  const invoke_single_t& invokeSingle,
162  const invoke_multiple_t& invokeMultiple) const noexcept
163 {
164  if (m_Functions.empty())
165  {
166  if constexpr (std::is_void_v<return_t>)
167  return;
168  else
169  return return_t();
170  }
171 
172  // modifying during iteration protection
173  thread_local container_type tempFunctions;
174  tempFunctions = m_Functions;
175 
177  details::invoker<return_t, function_type, invoke_multiple_t> invokerMultiple(invokeMultiple);
179  if (tempFunctions.size() == 1)
180  invoker = &invokerSingle;
181  else
182  invoker = &invokerMultiple;
183 
184  if constexpr (std::is_void_v<return_t>)
185  {
186  for (const auto& [_, function] : tempFunctions)
187  invoker->invoke(function);
188 
189  return;
190  }
191  else
192  {
193  return_t result;
194  for (const auto& [_, function] : tempFunctions)
195  result = result | invoker->invoke(function);
196 
197  return result;
198  }
199 }
200 
201 template<class derived_t, delegate_return_c return_t, class... args_t>
202 template<class object_t, callable_c<return_t, object_t*, args_t...> callable_t>
204  time_ordered_priority_key key,
205  std::weak_ptr<object_t> pWeakObject,
206  callable_t callable) noexcept
207 {
208  m_Functions.emplace(
209  key,
210  [this, key, pWeakObject, callable_ = std::move(callable)](args_t... args)
211  {
212  if (std::shared_ptr<object_t> pObject = pWeakObject.lock())
213  {
214  return callable_(pObject.get(), std::forward<args_t>(args)...);
215  }
216  else
217  {
218  remove(key);
219  return return_t();
220  }
221  });
222 }
223 
224 template<class derived_t, delegate_return_c return_t, class... args_t>
225 destruction_callback base_delegate<derived_t, return_t, args_t...>::add_destruction_callback(
226  time_ordered_priority_key key,
227  function_type value) noexcept
228 {
229  m_Functions.emplace(key, std::move(value));
230  return [this, key, pDelegateAliveMarker = std::weak_ptr(m_pDelegateAliveMarker)]()
231  {
232  if (!pDelegateAliveMarker.expired())
233  remove(key);
234  };
235 }
236 
237 template<delegate_return_c return_t, class... args_t>
238  requires(sizeof...(args_t) > 0 && (!std::is_void_v<args_t> && ...))
239 return_t delegate<return_t, args_t...>::execute(args_t... args) const noexcept
240 {
241  return this->execute_internal(
242  [&args...](const typename super_type::function_type& function)
243  {
244  return function(std::move(args)...);
245  },
246  [&args...](const typename super_type::function_type& function)
247  {
248  return function(args...);
249  });
250 }
251 
252 template<delegate_return_c return_t>
253 return_t delegate<return_t, void>::execute() const noexcept
254 {
255  return this->execute_internal(
256  [](const typename super_type::function_type& function)
257  {
258  return function();
259  },
260  [](const typename super_type::function_type& function)
261  {
262  return function();
263  });
264 }
265 
266 } // namespace qx
Single or multicast delegate. Use the qx::delegate<> class in your code.
Definition: delegate.h:54
bool remove(delegate_token_type token) noexcept
Remove a callable using its token.
Definition: delegate.inl:147
return_t execute_internal(const invoke_single_t &invokeSingle, const invoke_multiple_t &invokeMultiple) const noexcept
Execute all callables.
Definition: delegate.inl:160
static derived_t create_singlecast(creation_args_t... args) noexcept
Create a singlecast delegate.
Definition: delegate.inl:62
destruction_callback add_destruction_callback(callable_t callable, priority ePriority=priority::normal) noexcept
Add a callable that will be removed from the delegate when its destruction callback is destroyed.
Definition: delegate.inl:88
void clear() noexcept
Clear all the callables in this delegate.
Definition: delegate.inl:153
delegate_token_type add_weak(std::weak_ptr< object_t > pWeakObject, callable_t callable, priority ePriority=priority::normal) noexcept
Add a callable that will be executed only if the appropriate weak object is valid.
Definition: delegate.inl:130
delegate_token_type add_free(callable_t callable, priority ePriority=priority::normal) noexcept
Add a callable without any protection.
Definition: delegate.inl:77
Class for RAII: functor passed in constructor will be called in destructor.
priority
User may use the predefined values or the custom ones, for ex. "normal - 1", this type is supposed to...
Definition: priority.h:26
A structure that can be used as a key in ordered containers so that items are ordered in descending o...
Definition: priority.h:42