Embedded Template Library 1.0
delegate_cpp11.h
Go to the documentation of this file.
1
2
3/******************************************************************************
4The MIT License(MIT)
5
6Embedded Template Library.
7https://github.com/ETLCPP/etl
8https://www.etlcpp.com
9
10Copyright(c) 2019 John Wellbelove
11
12Permission is hereby granted, free of charge, to any person obtaining a copy
13of this software and associated documentation files(the "Software"), to deal
14in the Software without restriction, including without limitation the rights
15to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
16copies of the Software, and to permit persons to whom the Software is
17furnished to do so, subject to the following conditions :
18
19The above copyright notice and this permission notice shall be included in all
20copies or substantial portions of the Software.
21
22THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
25AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28SOFTWARE.
29******************************************************************************/
30
31/******************************************************************************
32
33Copyright (C) 2017 by Sergey A Kryukov: derived work
34http://www.SAKryukov.org
35http://www.codeproject.com/Members/SAKryukov
36
37Based on original work by Sergey Ryazanov:
38"The Impossibly Fast C++ Delegates", 18 Jul 2005
39https://www.codeproject.com/articles/11015/the-impossibly-fast-c-delegates
40
41MIT license:
42http://en.wikipedia.org/wiki/MIT_License
43
44Original publication: https://www.codeproject.com/Articles/1170503/The-Impossibly-Fast-Cplusplus-Delegates-Fixed
45
46******************************************************************************/
47
48#ifndef ETL_DELEGATE_CPP11_INCLUDED
49#define ETL_DELEGATE_CPP11_INCLUDED
50
51#include "../platform.h"
52#include "../error_handler.h"
53#include "../exception.h"
54#include "../type_traits.h"
55#include "../utility.h"
56#include "../optional.h"
57
58namespace etl
59{
60 //***************************************************************************
62 //***************************************************************************
63 class delegate_exception : public exception
64 {
65 public:
66
67 delegate_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
68 : exception(reason_, file_name_, line_number_)
69 {
70 }
71 };
72
73 //***************************************************************************
75 //***************************************************************************
76 class delegate_uninitialised : public delegate_exception
77 {
78 public:
79
80 delegate_uninitialised(string_type file_name_, numeric_type line_number_)
81 : delegate_exception(ETL_ERROR_TEXT("delegate:uninitialised", ETL_DELEGATE_FILE_ID"A"), file_name_, line_number_)
82 {
83 }
84 };
85
86 //*************************************************************************
88 //*************************************************************************
89 template <typename T> class delegate;
90
91 //*************************************************************************
93 //*************************************************************************
94 template <typename TReturn, typename... TParams>
95 class delegate<TReturn(TParams...)> final
96 {
97 public:
98
99 //*************************************************************************
101 //*************************************************************************
102 ETL_CONSTEXPR14 delegate()
103 {
104 }
105
106 //*************************************************************************
107 // Copy constructor.
108 //*************************************************************************
109 ETL_CONSTEXPR14 delegate(const delegate& other) = default;
110
111 //*************************************************************************
112 // Construct from lambda or functor.
113 //*************************************************************************
114 template <typename TLambda, typename = etl::enable_if_t<etl::is_class<TLambda>::value && !etl::is_same<etl::delegate<TReturn(TParams...)>, TLambda>::value, void>>
115 ETL_CONSTEXPR14 delegate(TLambda& instance)
116 {
117 assign((void*)(&instance), lambda_stub<TLambda>);
118 }
119
120 //*************************************************************************
121 // Construct from const lambda or functor.
122 //*************************************************************************
123 template <typename TLambda, typename = etl::enable_if_t<etl::is_class<TLambda>::value && !etl::is_same<etl::delegate<TReturn(TParams...)>, TLambda>::value, void>>
124 ETL_CONSTEXPR14 delegate(const TLambda& instance)
125 {
126 assign((void*)(&instance), const_lambda_stub<TLambda>);
127 }
128
129 //*************************************************************************
131 //*************************************************************************
132 template <TReturn(*Method)(TParams...)>
133 ETL_NODISCARD
134 static ETL_CONSTEXPR14 delegate create()
135 {
136 return delegate(ETL_NULLPTR, function_stub<Method>);
137 }
138
139 //*************************************************************************
141 //*************************************************************************
142 template <typename TLambda, typename = etl::enable_if_t<etl::is_class<TLambda>::value && !etl::is_same<etl::delegate<TReturn(TParams...)>, TLambda>::value, void>>
143 ETL_NODISCARD
144 static ETL_CONSTEXPR14 delegate create(TLambda& instance)
145 {
146 return delegate((void*)(&instance), lambda_stub<TLambda>);
147 }
148
149 //*************************************************************************
151 //*************************************************************************
152 template <typename TLambda, typename = etl::enable_if_t<etl::is_class<TLambda>::value && !etl::is_same<etl::delegate<TReturn(TParams...)>, TLambda>::value, void>>
153 ETL_NODISCARD
154 static ETL_CONSTEXPR14 delegate create(const TLambda& instance)
155 {
156 return delegate((void*)(&instance), const_lambda_stub<TLambda>);
157 }
158
159 //*************************************************************************
161 //*************************************************************************
162 template <typename T, TReturn(T::*Method)(TParams...)>
163 ETL_NODISCARD
164 static ETL_CONSTEXPR14 delegate create(T& instance)
165 {
166 return delegate((void*)(&instance), method_stub<T, Method>);
167 }
168
169 //*************************************************************************
172 //*************************************************************************
173 template <typename T, TReturn(T::*Method)(TParams...)>
174 ETL_NODISCARD
175 static ETL_CONSTEXPR14 delegate create(T&& instance) = delete;
176
177 //*************************************************************************
179 //*************************************************************************
180 template <typename T, TReturn(T::*Method)(TParams...) const>
181 ETL_NODISCARD
182 static ETL_CONSTEXPR14 delegate create(const T& instance)
183 {
184 return delegate((void*)(&instance), const_method_stub<T, Method>);
185 }
186
187 //*************************************************************************
189 //*************************************************************************
190 template <typename T, TReturn(T::*Method)(TParams...) const>
191 static ETL_CONSTEXPR14 delegate create(T&& instance) = delete;
192
193 //*************************************************************************
195 //*************************************************************************
196 template <typename T, T& Instance, TReturn(T::*Method)(TParams...)>
197 ETL_NODISCARD
198 static ETL_CONSTEXPR14 delegate create()
199 {
200 return delegate(method_instance_stub<T, Instance, Method>);
201 }
202
203 //*************************************************************************
205 //*************************************************************************
206 template <typename T, T const& Instance, TReturn(T::*Method)(TParams...) const>
207 ETL_NODISCARD
208 static ETL_CONSTEXPR14 delegate create()
209 {
210 return delegate(const_method_instance_stub<T, Instance, Method>);
211 }
212
213#if !(defined(ETL_COMPILER_GCC) && (__GNUC__ <= 8))
214 //*************************************************************************
217 //*************************************************************************
218 template <typename T, T& Instance>
219 ETL_NODISCARD
220 static ETL_CONSTEXPR14 delegate create()
221 {
222 return delegate(operator_instance_stub<T, Instance>);
223 }
224#endif
225
226 //*************************************************************************
228 //*************************************************************************
229 template <TReturn(*Method)(TParams...)>
230 ETL_CONSTEXPR14 void set()
231 {
232 assign(ETL_NULLPTR, function_stub<Method>);
233 }
234
235 //*************************************************************************
237 //*************************************************************************
238 template <typename TLambda, typename = etl::enable_if_t<etl::is_class<TLambda>::value && !etl::is_same<etl::delegate<TReturn(TParams...)>, TLambda>::value, void>>
239 ETL_CONSTEXPR14 void set(TLambda& instance)
240 {
241 assign((void*)(&instance), lambda_stub<TLambda>);
242 }
243
244 //*************************************************************************
246 //*************************************************************************
247 template <typename TLambda, typename = etl::enable_if_t<etl::is_class<TLambda>::value && !etl::is_same<etl::delegate<TReturn(TParams...)>, TLambda>::value, void>>
248 ETL_CONSTEXPR14 void set(const TLambda& instance)
249 {
250 assign((void*)(&instance), const_lambda_stub<TLambda>);
251 }
252
253 //*************************************************************************
255 //*************************************************************************
256 template <typename T, TReturn(T::* Method)(TParams...)>
257 ETL_CONSTEXPR14 void set(T& instance)
258 {
259 assign((void*)(&instance), method_stub<T, Method>);
260 }
261
262 //*************************************************************************
264 //*************************************************************************
265 template <typename T, TReturn(T::* Method)(TParams...) const>
266 ETL_CONSTEXPR14 void set(T& instance)
267 {
268 assign((void*)(&instance), const_method_stub<T, Method>);
269 }
270
271 //*************************************************************************
273 //*************************************************************************
274 template <typename T, T& Instance, TReturn(T::* Method)(TParams...)>
275 ETL_CONSTEXPR14 void set()
276 {
277 assign(ETL_NULLPTR, method_instance_stub<T, Instance, Method>);
278 }
279
280 //*************************************************************************
282 //*************************************************************************
283 template <typename T, T const& Instance, TReturn(T::* Method)(TParams...) const>
284 ETL_CONSTEXPR14 void set()
285 {
286 assign(ETL_NULLPTR, const_method_instance_stub<T, Instance, Method>);
287 }
288
289 //*************************************************************************
291 //*************************************************************************
292 ETL_CONSTEXPR14 void clear()
293 {
294 invocation.clear();
295 }
296
297 //*************************************************************************
299 //*************************************************************************
300 TReturn operator()(TParams... args) const
301 {
302 ETL_ASSERT(is_valid(), ETL_ERROR(delegate_uninitialised));
303
304 return (*invocation.stub)(invocation.object, etl::forward<TParams>(args)...);
305 }
306
307 //*************************************************************************
310 //*************************************************************************
311 template <typename TRet = TReturn>
312 typename etl::enable_if_t<etl::is_same<TRet, void>::value, bool>
313 call_if(TParams... args) const
314 {
315 if (is_valid())
316 {
317 (*invocation.stub)(invocation.object, etl::forward<TParams>(args)...);
318 return true;
319 }
320 else
321 {
322 return false;
323 }
324 }
325
326 //*************************************************************************
329 //*************************************************************************
330 template <typename TRet = TReturn>
331 typename etl::enable_if_t<!etl::is_same<TRet, void>::value, etl::optional<TReturn>>
332 call_if(TParams... args) const
333 {
335
336 if (is_valid())
337 {
338 result = (*invocation.stub)(invocation.object, etl::forward<TParams>(args)...);
339 }
340
341 return result;
342 }
343
344 //*************************************************************************
347 //*************************************************************************
348 template <typename TAlternative>
349 TReturn call_or(TAlternative alternative, TParams... args) const
350 {
351 if (is_valid())
352 {
353 return (*invocation.stub)(invocation.object, etl::forward<TParams>(args)...);
354 }
355 else
356 {
357 return alternative(etl::forward<TParams>(args)...);
358 }
359 }
360
361 //*************************************************************************
364 //*************************************************************************
365 template <TReturn(*Method)(TParams...)>
366 TReturn call_or(TParams... args) const
367 {
368 if (is_valid())
369 {
370 return (*invocation.stub)(invocation.object, etl::forward<TParams>(args)...);
371 }
372 else
373 {
374 return (Method)(etl::forward<TParams>(args)...);
375 }
376 }
377
378 //*************************************************************************
380 //*************************************************************************
381 delegate& operator =(const delegate& rhs) = default;
382
383 //*************************************************************************
385 //*************************************************************************
386 template <typename TLambda, typename = etl::enable_if_t<etl::is_class<TLambda>::value && !etl::is_same<etl::delegate<TReturn(TParams...)>, TLambda>::value, void>>
387 ETL_CONSTEXPR14 delegate& operator =(TLambda& instance)
388 {
389 assign((void*)(&instance), lambda_stub<TLambda>);
390 return *this;
391 }
392
393 //*************************************************************************
395 //*************************************************************************
396 template <typename TLambda, typename = etl::enable_if_t<etl::is_class<TLambda>::value && !etl::is_same<etl::delegate<TReturn(TParams...)>, TLambda>::value, void>>
397 ETL_CONSTEXPR14 delegate& operator =(const TLambda& instance)
398 {
399 assign((void*)(&instance), const_lambda_stub<TLambda>);
400 return *this;
401 }
402
403 //*************************************************************************
405 //*************************************************************************
406 ETL_CONSTEXPR14 bool operator == (const delegate& rhs) const
407 {
408 return invocation == rhs.invocation;
409 }
410
411 //*************************************************************************
413 //*************************************************************************
414 ETL_CONSTEXPR14 bool operator != (const delegate& rhs) const
415 {
416 return invocation != rhs.invocation;
417 }
418
419 //*************************************************************************
421 //*************************************************************************
422 ETL_NODISCARD
423 ETL_CONSTEXPR14 bool is_valid() const
424 {
425 return invocation.stub != ETL_NULLPTR;
426 }
427
428 //*************************************************************************
430 //*************************************************************************
431 ETL_CONSTEXPR14 operator bool() const
432 {
433 return is_valid();
434 }
435
436 private:
437
438 using stub_type = TReturn(*)(void* object, TParams...);
439
440 //*************************************************************************
442 //*************************************************************************
443 struct invocation_element
444 {
445 invocation_element() = default;
446
447 //***********************************************************************
448 ETL_CONSTEXPR14 invocation_element(void* object_, stub_type stub_)
449 : object(object_)
450 , stub(stub_)
451 {
452 }
453
454 //***********************************************************************
455 ETL_CONSTEXPR14 bool operator ==(const invocation_element& rhs) const
456 {
457 return (rhs.stub == stub) && (rhs.object == object);
458 }
459
460 //***********************************************************************
461 ETL_CONSTEXPR14 bool operator !=(const invocation_element& rhs) const
462 {
463 return (rhs.stub != stub) || (rhs.object != object);
464 }
465
466 //***********************************************************************
467 ETL_CONSTEXPR14 void clear()
468 {
469 object = ETL_NULLPTR;
470 stub = ETL_NULLPTR;
471 }
472
473 //***********************************************************************
474 void* object = ETL_NULLPTR;
475 stub_type stub = ETL_NULLPTR;
476 };
477
478 //*************************************************************************
480 //*************************************************************************
481 ETL_CONSTEXPR14 delegate(void* object, stub_type stub)
482 : invocation(object, stub)
483 {
484 }
485
486 //*************************************************************************
488 //*************************************************************************
489 ETL_CONSTEXPR14 delegate(stub_type stub)
490 : invocation(ETL_NULLPTR, stub)
491 {
492 }
493
494 //*************************************************************************
496 //*************************************************************************
497 ETL_CONSTEXPR14 void assign(void* object, stub_type stub)
498 {
499 invocation.object = object;
500 invocation.stub = stub;
501 }
502
503 //*************************************************************************
505 //*************************************************************************
506 template <typename T, TReturn(T::*Method)(TParams...)>
507 static ETL_CONSTEXPR14 TReturn method_stub(void* object, TParams... params)
508 {
509 T* p = static_cast<T*>(object);
510 return (p->*Method)(etl::forward<TParams>(params)...);
511 }
512
513 //*************************************************************************
515 //*************************************************************************
516 template <typename T, TReturn(T::*Method)(TParams...) const>
517 static ETL_CONSTEXPR14 TReturn const_method_stub(void* object, TParams... params)
518 {
519 T* const p = static_cast<T*>(object);
520 return (p->*Method)(etl::forward<TParams>(params)...);
521 }
522
523 //*************************************************************************
525 //*************************************************************************
526 template <typename T, T& Instance, TReturn(T::*Method)(TParams...)>
527 static ETL_CONSTEXPR14 TReturn method_instance_stub(void*, TParams... params)
528 {
529 return (Instance.*Method)(etl::forward<TParams>(params)...);
530 }
531
532 //*************************************************************************
534 //*************************************************************************
535 template <typename T, const T& Instance, TReturn(T::*Method)(TParams...) const>
536 static ETL_CONSTEXPR14 TReturn const_method_instance_stub(void*, TParams... params)
537 {
538 return (Instance.*Method)(etl::forward<TParams>(params)...);
539 }
540
541#if !(defined(ETL_COMPILER_GCC) && (__GNUC__ <= 8))
542 //*************************************************************************
544 //*************************************************************************
545 template <typename T, T& Instance>
546 static ETL_CONSTEXPR14 TReturn operator_instance_stub(void*, TParams... params)
547 {
548 return Instance.operator()(etl::forward<TParams>(params)...);
549 }
550#endif
551
552 //*************************************************************************
554 //*************************************************************************
555 template <TReturn(*Method)(TParams...)>
556 static ETL_CONSTEXPR14 TReturn function_stub(void*, TParams... params)
557 {
558 return (Method)(etl::forward<TParams>(params)...);
559 }
560
561 //*************************************************************************
563 //*************************************************************************
564 template <typename TLambda>
565 static ETL_CONSTEXPR14 TReturn lambda_stub(void* object, TParams... arg)
566 {
567 TLambda* p = static_cast<TLambda*>(object);
568 return (p->operator())(etl::forward<TParams>(arg)...);
569 }
570
571 //*************************************************************************
573 //*************************************************************************
574 template <typename TLambda>
575 static ETL_CONSTEXPR14 TReturn const_lambda_stub(void* object, TParams... arg)
576 {
577 const TLambda* p = static_cast<const TLambda*>(object);
578 return (p->operator())(etl::forward<TParams>(arg)...);
579 }
580
581 //*************************************************************************
583 //*************************************************************************
584 invocation_element invocation;
585 };
586}
587
588#endif
etl::enable_if_t<!etl::is_same< TRet, void >::value, etl::optional< TReturn > > call_if(TParams... args) const
Definition: delegate_cpp11.h:332
TReturn operator()(TParams... args) const
Execute the delegate.
Definition: delegate_cpp11.h:300
etl::enable_if_t< etl::is_same< TRet, void >::value, bool > call_if(TParams... args) const
Definition: delegate_cpp11.h:313
TReturn call_or(TAlternative alternative, TParams... args) const
Definition: delegate_cpp11.h:349
TReturn call_or(TParams... args) const
Definition: delegate_cpp11.h:366
The exception thrown when the delegate is uninitialised.
Definition: delegate_cpp03.h:162
Declaration.
Definition: delegate_cpp03.h:175
Definition: optional.h:108
A templated set implementation that uses a fixed size buffer.
Definition: set.h:2502
#define ETL_ASSERT(b, e)
Definition: error_handler.h:316
ETL_CONSTEXPR exception(string_type reason_, string_type, numeric_type line_)
Constructor.
Definition: exception.h:69
is_same
Definition: type_traits_generator.h:1041
bitset_ext
Definition: absolute.h:38
T * create(Args &&... args)
Creates the object from a type. Variadic parameter constructor.
Definition: variant_pool_generator.h:234
bool operator!=(const etl::array< T, SIZE > &lhs, const etl::array< T, SIZE > &rhs)
Definition: array.h:645
bool operator==(const etl::array< T, SIZE > &lhs, const etl::array< T, SIZE > &rhs)
Definition: array.h:633