Embedded Template Library 1.0
Loading...
Searching...
No Matches
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 "../function_traits.h"
56#include "../utility.h"
57#include "../optional.h"
58
59namespace etl
60{
61 //***************************************************************************
63 //***************************************************************************
64 class delegate_exception : public exception
65 {
66 public:
67
68 delegate_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
69 : exception(reason_, file_name_, line_number_)
70 {
71 }
72 };
73
74 //***************************************************************************
76 //***************************************************************************
77 class delegate_uninitialised : public delegate_exception
78 {
79 public:
80
81 delegate_uninitialised(string_type file_name_, numeric_type line_number_)
82 : delegate_exception(ETL_ERROR_TEXT("delegate:uninitialised", ETL_DELEGATE_FILE_ID"A"), file_name_, line_number_)
83 {
84 }
85 };
86
87 //*****************************************************************
90 //*****************************************************************
91 struct delegate_tag
92 {
93 };
94
95 //***************************************************************************
97 //***************************************************************************
98 template <typename T>
99 struct is_delegate : etl::bool_constant<etl::is_base_of<delegate_tag, T>::value>
100 {
101 };
102
103#if ETL_USING_CPP17
104 template <typename T>
105 inline constexpr bool is_delegate_v = is_delegate<T>::value;
106#endif
107
108 //*************************************************************************
110 //*************************************************************************
111 template <typename T>
112 class delegate;
113
114 //*************************************************************************
116 //*************************************************************************
117 template <typename TReturn, typename... TParams>
118 class delegate<TReturn(TParams...)> final : public delegate_tag
119 {
120 public:
121
122 //*************************************************************************
124 //*************************************************************************
125 ETL_CONSTEXPR14 delegate()
126 {
127 }
128
129 //*************************************************************************
130 // Copy constructor.
131 //*************************************************************************
132 ETL_CONSTEXPR14 delegate(const delegate& other) = default;
133
134 //*************************************************************************
135 // Construct from lambda or functor.
136 //*************************************************************************
138 ETL_CONSTEXPR14 delegate(TLambda& instance)
139 {
140 assign((void*)(&instance), lambda_stub<TLambda>);
141 }
142
143 //*************************************************************************
144 // Construct from const lambda or functor.
145 //*************************************************************************
146 template <typename TLambda, typename = etl::enable_if_t<etl::is_class<TLambda>::value && !is_delegate<TLambda>::value, void>>
147 ETL_CONSTEXPR14 delegate(const TLambda& instance)
148 {
149 assign((void*)(&instance), const_lambda_stub<TLambda>);
150 }
151
152 //*************************************************************************
153 // Delete construction from rvalue reference lambda or functor.
154 //*************************************************************************
155 template <typename TLambda, typename = etl::enable_if_t<etl::is_class<TLambda>::value && !etl::is_same<etl::delegate<TReturn(TParams...)>, TLambda>::value, void>>
156 ETL_CONSTEXPR14 delegate(TLambda&& instance) = delete;
157
158 //*************************************************************************
160 //*************************************************************************
161 template <TReturn(*Method)(TParams...)>
162 ETL_NODISCARD
163 static ETL_CONSTEXPR14 delegate create()
164 {
165 return delegate(ETL_NULLPTR, function_stub<Method>);
166 }
167
168 //*************************************************************************
170 //*************************************************************************
172 ETL_NODISCARD
173 static ETL_CONSTEXPR14 delegate create(TLambda& instance)
174 {
175 return delegate((void*)(&instance), lambda_stub<TLambda>);
176 }
177
178 //*************************************************************************
180 //*************************************************************************
182 ETL_NODISCARD
183 static ETL_CONSTEXPR14 delegate create(const TLambda& instance)
184 {
185 return delegate((void*)(&instance), const_lambda_stub<TLambda>);
186 }
187
188 //*************************************************************************
190 //*************************************************************************
191 template <typename T, TReturn(T::*Method)(TParams...)>
192 ETL_NODISCARD
193 static ETL_CONSTEXPR14 delegate create(T& instance)
194 {
195 return delegate((void*)(&instance), method_stub<T, Method>);
196 }
197
198 //*************************************************************************
201 //*************************************************************************
202 template <typename T, TReturn(T::*Method)(TParams...)>
203 ETL_NODISCARD
204 static ETL_CONSTEXPR14 delegate create(T&& instance) = delete;
205
206 //*************************************************************************
208 //*************************************************************************
209 template <typename T, TReturn(T::*Method)(TParams...) const>
210 ETL_NODISCARD
211 static ETL_CONSTEXPR14 delegate create(const T& instance)
212 {
213 return delegate((void*)(&instance), const_method_stub<T, Method>);
214 }
215
216 //*************************************************************************
218 //*************************************************************************
219 template <typename T, TReturn(T::*Method)(TParams...) const>
220 static ETL_CONSTEXPR14 delegate create(T&& instance) = delete;
221
222 //*************************************************************************
224 //*************************************************************************
225 template <typename T, T& Instance, TReturn(T::*Method)(TParams...)>
226 ETL_NODISCARD
227 static ETL_CONSTEXPR14 delegate create()
228 {
230 }
231
232 //*************************************************************************
235 //*************************************************************************
236 template <typename T, TReturn(T::* Method)(TParams...), T& Instance>
237 ETL_NODISCARD
238 static ETL_CONSTEXPR14 delegate create()
239 {
241 }
242
243 //*************************************************************************
245 //*************************************************************************
246 template <typename T, T const& Instance, TReturn(T::*Method)(TParams...) const>
247 ETL_NODISCARD
252
253 //*************************************************************************
256 //*************************************************************************
257 template <typename T, TReturn(T::* Method)(TParams...) const, T const& Instance>
258 ETL_NODISCARD
263
264#if !(defined(ETL_COMPILER_GCC) && (__GNUC__ <= 8))
265 //*************************************************************************
268 //*************************************************************************
269 template <typename T, T& Instance>
270 ETL_NODISCARD
271 static ETL_CONSTEXPR14 delegate create()
272 {
274 }
275#endif
276
277 //*************************************************************************
279 //*************************************************************************
280 template <TReturn(*Method)(TParams...)>
281 ETL_CONSTEXPR14 void set()
282 {
283 assign(ETL_NULLPTR, function_stub<Method>);
284 }
285
286 //*************************************************************************
288 //*************************************************************************
290 ETL_CONSTEXPR14 void set(TLambda& instance)
291 {
292 assign((void*)(&instance), lambda_stub<TLambda>);
293 }
294
295 //*************************************************************************
297 //*************************************************************************
299 ETL_CONSTEXPR14 void set(const TLambda& instance)
300 {
301 assign((void*)(&instance), const_lambda_stub<TLambda>);
302 }
303
304 //*************************************************************************
306 //*************************************************************************
307 template <typename T, TReturn(T::* Method)(TParams...)>
308 ETL_CONSTEXPR14 void set(T& instance)
309 {
310 assign((void*)(&instance), method_stub<T, Method>);
311 }
312
313 //*************************************************************************
315 //*************************************************************************
316 template <typename T, TReturn(T::* Method)(TParams...) const>
317 ETL_CONSTEXPR14 void set(T& instance)
318 {
319 assign((void*)(&instance), const_method_stub<T, Method>);
320 }
321
322 //*************************************************************************
324 //*************************************************************************
325 template <typename T, T& Instance, TReturn(T::* Method)(TParams...)>
326 ETL_CONSTEXPR14 void set()
327 {
329 }
330
331 //*************************************************************************
334 //*************************************************************************
335 template <typename T, TReturn(T::* Method)(TParams...), T& Instance>
336 ETL_CONSTEXPR14 void set()
337 {
339 }
340
341 //*************************************************************************
343 //*************************************************************************
344 template <typename T, T const& Instance, TReturn(T::* Method)(TParams...) const>
345 ETL_CONSTEXPR14 void set()
346 {
348 }
349
350 //*************************************************************************
353 //*************************************************************************
354 template <typename T, TReturn(T::* Method)(TParams...) const, T const& Instance>
355 ETL_CONSTEXPR14 void set()
356 {
358 }
359
360 //*************************************************************************
362 //*************************************************************************
363 ETL_CONSTEXPR14 void clear()
364 {
365 invocation.clear();
366 }
367
368 //*************************************************************************
370 //*************************************************************************
372 {
373 ETL_ASSERT(is_valid(), ETL_ERROR(delegate_uninitialised));
374
375 return (*invocation.stub)(invocation.object, etl::forward<TParams>(args)...);
376 }
377
378 //*************************************************************************
381 //*************************************************************************
382 template <typename TRet = TReturn>
383 ETL_CONSTEXPR14
386 {
387 if (is_valid())
388 {
389 (*invocation.stub)(invocation.object, etl::forward<TParams>(args)...);
390 return true;
391 }
392 else
393 {
394 return false;
395 }
396 }
397
398 //*************************************************************************
401 //*************************************************************************
402 template <typename TRet = TReturn>
403 ETL_CONSTEXPR14
406 {
408
409 if (is_valid())
410 {
411 result = (*invocation.stub)(invocation.object, etl::forward<TParams>(args)...);
412 }
413
414 return result;
415 }
416
417 //*************************************************************************
420 //*************************************************************************
421 template <typename TAlternative>
423 {
424 if (is_valid())
425 {
426 return (*invocation.stub)(invocation.object, etl::forward<TParams>(args)...);
427 }
428 else
429 {
431 }
432 }
433
434 //*************************************************************************
437 //*************************************************************************
438 template <TReturn(*Method)(TParams...)>
440 {
441 if (is_valid())
442 {
443 return (*invocation.stub)(invocation.object, etl::forward<TParams>(args)...);
444 }
445 else
446 {
447 return (Method)(etl::forward<TParams>(args)...);
448 }
449 }
450
451 //*************************************************************************
453 //*************************************************************************
454 delegate& operator =(const delegate& rhs) = default;
455
456 //*************************************************************************
458 //*************************************************************************
460 ETL_CONSTEXPR14 delegate& operator =(TLambda& instance)
461 {
462 assign((void*)(&instance), lambda_stub<TLambda>);
463 return *this;
464 }
465
466 //*************************************************************************
468 //*************************************************************************
470 ETL_CONSTEXPR14 delegate& operator =(const TLambda& instance)
471 {
472 assign((void*)(&instance), const_lambda_stub<TLambda>);
473 return *this;
474 }
475
476 //*************************************************************************
478 //*************************************************************************
479 ETL_NODISCARD
480 ETL_CONSTEXPR14 bool operator == (const delegate& rhs) const
481 {
482 return invocation == rhs.invocation;
483 }
484
485 //*************************************************************************
487 //*************************************************************************
488 ETL_CONSTEXPR14 bool operator != (const delegate& rhs) const
489 {
490 return invocation != rhs.invocation;
491 }
492
493 //*************************************************************************
495 //*************************************************************************
496 ETL_NODISCARD
497 ETL_CONSTEXPR14 bool is_valid() const
498 {
499 return invocation.stub != ETL_NULLPTR;
500 }
501
502 //*************************************************************************
504 //*************************************************************************
505 ETL_NODISCARD
506 ETL_CONSTEXPR14 operator bool() const
507 {
508 return is_valid();
509 }
510
511 private:
512
513 using stub_type = TReturn(*)(void* object, TParams...);
514
515 //*************************************************************************
517 //*************************************************************************
518 struct invocation_element
519 {
520 invocation_element() = default;
521
522 //***********************************************************************
523 ETL_CONSTEXPR14 invocation_element(void* object_, stub_type stub_)
524 : object(object_)
525 , stub(stub_)
526 {
527 }
528
529 //***********************************************************************
530 ETL_CONSTEXPR14 bool operator ==(const invocation_element& rhs) const
531 {
532 return (rhs.stub == stub) && (rhs.object == object);
533 }
534
535 //***********************************************************************
536 ETL_CONSTEXPR14 bool operator !=(const invocation_element& rhs) const
537 {
538 return (rhs.stub != stub) || (rhs.object != object);
539 }
540
541 //***********************************************************************
542 ETL_CONSTEXPR14 void clear()
543 {
544 object = ETL_NULLPTR;
545 stub = ETL_NULLPTR;
546 }
547
548 //***********************************************************************
549 void* object = ETL_NULLPTR;
550 stub_type stub = ETL_NULLPTR;
551 };
552
553 //*************************************************************************
555 //*************************************************************************
556 ETL_CONSTEXPR14 delegate(void* object, stub_type stub)
557 : invocation(object, stub)
558 {
559 }
560
561 //*************************************************************************
563 //*************************************************************************
564 ETL_CONSTEXPR14 delegate(stub_type stub)
565 : invocation(ETL_NULLPTR, stub)
566 {
567 }
568
569 //*************************************************************************
571 //*************************************************************************
572 ETL_CONSTEXPR14 void assign(void* object, stub_type stub)
573 {
574 invocation.object = object;
575 invocation.stub = stub;
576 }
577
578 //*************************************************************************
580 //*************************************************************************
581 template <typename T, TReturn(T::*Method)(TParams...)>
582 static ETL_CONSTEXPR14 TReturn method_stub(void* object, TParams... params)
583 {
584 T* p = static_cast<T*>(object);
585 return (p->*Method)(etl::forward<TParams>(params)...);
586 }
587
588 //*************************************************************************
590 //*************************************************************************
591 template <typename T, TReturn(T::*Method)(TParams...) const>
592 static ETL_CONSTEXPR14 TReturn const_method_stub(void* object, TParams... params)
593 {
594 T* const p = static_cast<T*>(object);
595 return (p->*Method)(etl::forward<TParams>(params)...);
596 }
597
598 //*************************************************************************
600 //*************************************************************************
601 template <typename T, TReturn(T::*Method)(TParams...), T& Instance>
602 static ETL_CONSTEXPR14 TReturn method_instance_stub(void*, TParams... params)
603 {
604 return (Instance.*Method)(etl::forward<TParams>(params)...);
605 }
606
607 //*************************************************************************
609 //*************************************************************************
610 template <typename T, TReturn(T::*Method)(TParams...) const, const T& Instance>
611 static ETL_CONSTEXPR14 TReturn const_method_instance_stub(void*, TParams... params)
612 {
613 return (Instance.*Method)(etl::forward<TParams>(params)...);
614 }
615
616#if !(defined(ETL_COMPILER_GCC) && (__GNUC__ <= 8))
617 //*************************************************************************
619 //*************************************************************************
620 template <typename T, T& Instance>
621 static ETL_CONSTEXPR14 TReturn operator_instance_stub(void*, TParams... params)
622 {
623 return Instance.operator()(etl::forward<TParams>(params)...);
624 }
625#endif
626
627 //*************************************************************************
629 //*************************************************************************
630 template <TReturn(*Method)(TParams...)>
631 static ETL_CONSTEXPR14 TReturn function_stub(void*, TParams... params)
632 {
633 return (Method)(etl::forward<TParams>(params)...);
634 }
635
636 //*************************************************************************
638 //*************************************************************************
639 template <typename TLambda>
640 static ETL_CONSTEXPR14 TReturn lambda_stub(void* object, TParams... arg)
641 {
642 TLambda* p = static_cast<TLambda*>(object);
643 return (p->operator())(etl::forward<TParams>(arg)...);
644 }
645
646 //*************************************************************************
648 //*************************************************************************
649 template <typename TLambda>
650 static ETL_CONSTEXPR14 TReturn const_lambda_stub(void* object, TParams... arg)
651 {
652 const TLambda* p = static_cast<const TLambda*>(object);
653 return (p->operator())(etl::forward<TParams>(arg)...);
654 }
655
656 //*************************************************************************
658 //*************************************************************************
659 invocation_element invocation;
660 };
661
662#if ETL_USING_CPP17
663 //*************************************************************************
665 //*************************************************************************
666 template <auto Function>
667 ETL_NODISCARD
668 constexpr auto make_delegate() ETL_NOEXCEPT
669 {
670 using function_type = typename etl::function_traits<decltype(Function)>::function_type;
671
672 return etl::delegate<function_type>::template create<Function>();
673 }
674
675 //*************************************************************************
677 //*************************************************************************
678 template <typename TLambda, typename = etl::enable_if_t<etl::is_class<TLambda>::value, void>>
679 ETL_NODISCARD
680 constexpr auto make_delegate(TLambda& instance) ETL_NOEXCEPT
681 {
682 using function_type = typename etl::function_traits<decltype(&TLambda::operator())>::function_type;
683
684 return etl::delegate<function_type>(instance);
685 }
686
687 //*************************************************************************
689 //*************************************************************************
690 template <typename T, T& Instance>
691 ETL_NODISCARD
692 constexpr auto make_delegate() ETL_NOEXCEPT
693 {
694 using function_type = typename etl::function_traits<decltype(&T::operator())>::function_type;
695
696 return etl::delegate<function_type>::template create<T, Instance>();
697 }
698
699 //*************************************************************************
701 //*************************************************************************
702 template <typename T, auto Method, T& Instance, typename = etl::enable_if_t<!etl::function_traits<decltype(Method)>::is_const>>
703 ETL_NODISCARD
704 constexpr auto make_delegate() ETL_NOEXCEPT
705 {
706 using function_type = typename etl::function_traits<decltype(Method)>::function_type;
707
708 return etl::delegate<function_type>::template create<T, Method, Instance>();
709 }
710
711 //*************************************************************************
713 //*************************************************************************
714 template <typename T, auto Method, const T& Instance, typename = etl::enable_if_t<etl::function_traits<decltype(Method)>::is_const>>
715 ETL_NODISCARD
716 constexpr auto make_delegate() ETL_NOEXCEPT
717 {
718 using function_type = typename etl::function_traits<decltype(Method)>::function_type;
719
720 return etl::delegate<function_type>::template create<T, Method, Instance>();
721 }
722
723 //*************************************************************************
725 //*************************************************************************
726 template <typename T, auto Method>
727 ETL_NODISCARD
728 constexpr auto make_delegate(T& instance) ETL_NOEXCEPT
729 {
730 using function_type = typename etl::function_traits<decltype(Method)>::function_type;
731
732 return etl::delegate<function_type>::template create<T, Method>(instance);
733 }
734
735 //*************************************************************************
737 //*************************************************************************
738 template <typename T, auto Method>
739 ETL_NODISCARD
740 constexpr auto make_delegate(const T& instance) ETL_NOEXCEPT
741 {
742 using function_type = typename etl::function_traits<decltype(Method)>::function_type;
743
744 return etl::delegate<function_type>::template create<T, Method>(instance);
745 }
746#endif
747}
748
749#endif
ETL_CONSTEXPR14 void set()
Set from function (Compile time).
Definition delegate_cpp11.h:281
static ETL_NODISCARD ETL_CONSTEXPR14 delegate create(const TLambda &instance)
Create from const Lambda or Functor.
Definition delegate_cpp11.h:183
static ETL_NODISCARD ETL_CONSTEXPR14 delegate create()
Definition delegate_cpp11.h:271
ETL_CONSTEXPR14 etl::enable_if_t< etl::is_same< TRet, void >::value, bool > call_if(TParams... args) const
Definition delegate_cpp11.h:385
ETL_CONSTEXPR14 void set(const TLambda &instance)
Set from const Lambda or Functor.
Definition delegate_cpp11.h:299
ETL_CONSTEXPR14 void set(TLambda &instance)
Set from Lambda or Functor.
Definition delegate_cpp11.h:290
ETL_CONSTEXPR14 delegate()
Default constructor.
Definition delegate_cpp11.h:125
TReturn operator()(TParams... args) const
Execute the delegate.
Definition delegate_cpp11.h:371
ETL_CONSTEXPR14 void clear()
Clear the delegate.
Definition delegate_cpp11.h:363
TReturn call_or(TAlternative alternative, TParams... args) const
Definition delegate_cpp11.h:422
TReturn call_or(TParams... args) const
Definition delegate_cpp11.h:439
static ETL_NODISCARD ETL_CONSTEXPR14 delegate create(TLambda &instance)
Create from Lambda or Functor.
Definition delegate_cpp11.h:173
ETL_CONSTEXPR14 etl::enable_if_t<!etl::is_same< TRet, void >::value, etl::optional< TReturn > > call_if(TParams... args) const
Definition delegate_cpp11.h:405
ETL_NODISCARD ETL_CONSTEXPR14 bool is_valid() const
Returns true if the delegate is valid.
Definition delegate_cpp11.h:497
static ETL_NODISCARD ETL_CONSTEXPR14 delegate create()
Create from function (Compile time).
Definition delegate_cpp11.h:163
The exception thrown when the delegate is uninitialised.
Definition delegate_cpp03.h:162
Declaration.
Definition delegate_cpp03.h:191
A templated set implementation that uses a fixed size buffer.
Definition set.h:2548
ETL_CONSTEXPR14 bool operator==(const etl::expected< TValue, TError > &lhs, const etl::expected< TValue2, TError2 > &rhs)
Equivalence operators.
Definition expected.h:968
#define ETL_ASSERT(b, e)
Definition error_handler.h:356
ETL_CONSTEXPR exception(string_type reason_, string_type, numeric_type line_)
Constructor.
Definition exception.h:69
is_same
Definition type_traits_generator.h:1036
bitset_ext
Definition absolute.h:38
T * create(Args &&... args)
Creates the object from a type. Variadic parameter constructor.
Definition variant_pool_generator.h:348
bool operator!=(const etl::array< T, SIZE > &lhs, const etl::array< T, SIZE > &rhs)
Definition array.h:654
bool operator==(const etl::array< T, SIZE > &lhs, const etl::array< T, SIZE > &rhs)
Definition array.h:642
Definition type_traits_generator.h:844
Definition delegate_cpp03.h:176
is_delegate
Definition delegate_cpp03.h:184
pair holds two objects of arbitrary type
Definition utility.h:164