Embedded Template Library  1.0
delegate.h
Go to the documentation of this file.
1 
3 /******************************************************************************
4 The MIT License(MIT)
5 
6 Embedded Template Library.
7 https://github.com/ETLCPP/etl
8 https://www.etlcpp.com
9 
10 Copyright(c) 2019 jwellbelove
11 
12 Permission is hereby granted, free of charge, to any person obtaining a copy
13 of this software and associated documentation files(the "Software"), to deal
14 in the Software without restriction, including without limitation the rights
15 to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
16 copies of the Software, and to permit persons to whom the Software is
17 furnished to do so, subject to the following conditions :
18 
19 The above copyright notice and this permission notice shall be included in all
20 copies or substantial portions of the Software.
21 
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
25 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 SOFTWARE.
29 ******************************************************************************/
30 
31 /******************************************************************************
32 
33 Copyright (C) 2017 by Sergey A Kryukov: derived work
34 http://www.SAKryukov.org
35 http://www.codeproject.com/Members/SAKryukov
36 
37 Based on original work by Sergey Ryazanov:
38 "The Impossibly Fast C++ Delegates", 18 Jul 2005
39 https://www.codeproject.com/articles/11015/the-impossibly-fast-c-delegates
40 
41 MIT license:
42 http://en.wikipedia.org/wiki/MIT_License
43 
44 Original publication: https://www.codeproject.com/Articles/1170503/The-Impossibly-Fast-Cplusplus-Delegates-Fixed
45 
46 ******************************************************************************/
47 
48 #ifndef ETL_DELEGATE_INCLUDED
49 #define ETL_DELEGATE_INCLUDED
50 
51 #include "platform.h"
52 #include "error_handler.h"
53 #include "exception.h"
54 #include "type_traits.h"
55 
56 #if ETL_CPP11_SUPPORTED == 0
57 #error NOT SUPPORTED FOR C++03 OR BELOW
58 #endif
59 
60 #undef ETL_FILE
61 #define ETL_FILE "51"
62 
63 namespace etl
64 {
65  //***************************************************************************
67  //***************************************************************************
69  {
70  public:
71 
72  delegate_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
73  : exception(reason_, file_name_, line_number_)
74  {
75  }
76  };
77 
78  //***************************************************************************
80  //***************************************************************************
82  {
83  public:
84 
85  delegate_uninitialised(string_type file_name_, numeric_type line_number_)
86  : delegate_exception(ETL_ERROR_TEXT("delegate:uninitialised", ETL_FILE"A"), file_name_, line_number_)
87  {
88  }
89  };
90 
91  template <typename T> class delegate;
92 
93  template <typename TReturn, typename... TParams>
94  class delegate<TReturn(TParams...)> final
95  {
96  public:
97 
98  //*************************************************************************
100  //*************************************************************************
101  delegate() = default;
102 
103  //*************************************************************************
104  // Copy constructor.
105  //*************************************************************************
106  delegate(const delegate& other) = default;
107 
108  //*************************************************************************
109  // Constructor from lambda or functor.
110  //*************************************************************************
111  template <typename TLambda, typename = typename etl::enable_if<etl::is_class<TLambda>::value, void>::type>
112  delegate(const TLambda& instance)
113  {
114  assign((void*)(&instance), lambda_stub<TLambda>);
115  }
116 
117  //*************************************************************************
119  //*************************************************************************
120  template <TReturn(*Method)(TParams...)>
121  constexpr static delegate create()
122  {
123  return delegate(ETL_NULLPTR, function_stub<Method>);
124  }
125 
126  //*************************************************************************
128  //*************************************************************************
129  template <typename TLambda, typename = typename etl::enable_if<etl::is_class<TLambda>::value, void>::type>
130  constexpr static delegate create(const TLambda& instance)
131  {
132  return delegate((void*)(&instance), lambda_stub<TLambda>);
133  }
134 
135  //*************************************************************************
137  //*************************************************************************
138  template <typename T, TReturn(T::*Method)(TParams...)>
139  constexpr static delegate create(T& instance)
140  {
141  return delegate((void*)(&instance), method_stub<T, Method>);
142  }
143 
144  //*************************************************************************
147  //*************************************************************************
148  template <typename T, TReturn(T::*Method)(TParams...)>
149  static delegate create(T&& instance) = delete;
150 
151  //*************************************************************************
153  //*************************************************************************
154  template <typename T, TReturn(T::*Method)(TParams...) const>
155  constexpr static delegate create(const T& instance)
156  {
157  return delegate((void*)(&instance), const_method_stub<T, Method>);
158  }
159 
160  //*************************************************************************
162  //*************************************************************************
163  template <typename T, TReturn(T::*Method)(TParams...) const>
164  constexpr static delegate create(T&& instance) = delete;
165 
166  //*************************************************************************
168  //*************************************************************************
169  template <typename T, T& Instance, TReturn(T::*Method)(TParams...)>
170  constexpr static delegate create()
171  {
172  return delegate(method_instance_stub<T, Instance, Method>);
173  }
174 
175  //*************************************************************************
177  //*************************************************************************
178  template <typename T, T const& Instance, TReturn(T::*Method)(TParams...) const>
179  constexpr static delegate create()
180  {
181  return delegate(const_method_instance_stub<T, Instance, Method>);
182  }
183 
184 #if !defined(ETL_COMPILER_GCC)
185  //*************************************************************************
188  //*************************************************************************
189  template <typename T, T& Instance>
190  constexpr static delegate create()
191  {
192  return delegate(operator_instance_stub<T, Instance>);
193  }
194 #endif
195 
196  //*************************************************************************
198  //*************************************************************************
199  TReturn operator()(TParams... args) const
200  {
201  ETL_ASSERT(is_valid(), ETL_ERROR(delegate_uninitialised));
202 
203  return (*invocation.stub)(invocation.object, args...);
204  }
205 
206  //*************************************************************************
208  //*************************************************************************
209  delegate& operator =(const delegate& rhs) = default;
210 
211  //*************************************************************************
213  //*************************************************************************
214  template <typename TLambda, typename = typename etl::enable_if<etl::is_class<TLambda>::value, void>::type>
215  delegate& operator =(const TLambda& instance)
216  {
217  assign((void*)(&instance), lambda_stub<TLambda>);
218  return *this;
219  }
220 
221  //*************************************************************************
223  //*************************************************************************
224  bool operator == (const delegate& rhs) const
225  {
226  return invocation == rhs.invocation;
227  }
228 
229  //*************************************************************************
231  //*************************************************************************
232  bool operator != (const delegate& rhs) const
233  {
234  return invocation != rhs.invocation;
235  }
236 
237  //*************************************************************************
239  //*************************************************************************
240  bool is_valid() const
241  {
242  return invocation.stub != ETL_NULLPTR;
243  }
244 
245  //*************************************************************************
247  //*************************************************************************
248  operator bool() const
249  {
250  return is_valid();
251  }
252 
253  private:
254 
255  using stub_type = TReturn(*)(void* object, TParams...);
256 
257  //*************************************************************************
259  //*************************************************************************
260  struct invocation_element
261  {
262  invocation_element() = default;
263 
264  //***********************************************************************
265  constexpr invocation_element(void* object_, stub_type stub_)
266  : object(object_)
267  , stub(stub_)
268  {
269  }
270 
271  //***********************************************************************
272  bool operator ==(const invocation_element& rhs) const
273  {
274  return (rhs.stub == stub) && (rhs.object == object);
275  }
276 
277  //***********************************************************************
278  bool operator !=(const invocation_element& rhs) const
279  {
280  return (rhs.stub != stub) || (rhs.object != object);
281  }
282 
283  //***********************************************************************
284  void* object = ETL_NULLPTR;
285  stub_type stub = ETL_NULLPTR;
286  };
287 
288  //*************************************************************************
290  //*************************************************************************
291  constexpr delegate(void* object, stub_type stub)
292  : invocation(object, stub)
293  {
294  }
295 
296  //*************************************************************************
298  //*************************************************************************
299  constexpr delegate(stub_type stub)
300  : invocation(ETL_NULLPTR, stub)
301  {
302  }
303 
304  //*************************************************************************
306  //*************************************************************************
307  void assign(void* object, stub_type stub)
308  {
309  invocation.object = object;
310  invocation.stub = stub;
311  }
312 
313  //*************************************************************************
315  //*************************************************************************
316  template <typename T, TReturn(T::*Method)(TParams...)>
317  static TReturn method_stub(void* object, TParams... params)
318  {
319  T* p = static_cast<T*>(object);
320  return (p->*Method)(params...);
321  }
322 
323  //*************************************************************************
325  //*************************************************************************
326  template <typename T, TReturn(T::*Method)(TParams...) const>
327  static TReturn const_method_stub(void* object, TParams... params)
328  {
329  T* const p = static_cast<T*>(object);
330  return (p->*Method)(params...);
331  }
332 
333  //*************************************************************************
335  //*************************************************************************
336  template <typename T, T& Instance, TReturn(T::*Method)(TParams...)>
337  static TReturn method_instance_stub(void*, TParams... params)
338  {
339  return (Instance.*Method)(params...);
340  }
341 
342  //*************************************************************************
344  //*************************************************************************
345  template <typename T, const T& Instance, TReturn(T::*Method)(TParams...) const>
346  static TReturn const_method_instance_stub(void*, TParams... params)
347  {
348  return (Instance.*Method)(params...);
349  }
350 
351 #if !defined(ETL_COMPILER_GCC)
352  //*************************************************************************
354  //*************************************************************************
355  template <typename T, T& Instance>
356  static TReturn operator_instance_stub(void*, TParams... params)
357  {
358  return Instance.operator()(params...);
359  }
360 #endif
361 
362  //*************************************************************************
364  //*************************************************************************
365  template <TReturn(*Method)(TParams...)>
366  static TReturn function_stub(void*, TParams... params)
367  {
368  return (Method)(params...);
369  }
370 
371  //*************************************************************************
373  //*************************************************************************
374  template <typename TLambda>
375  static TReturn lambda_stub(void* object, TParams... arg)
376  {
377  TLambda* p = static_cast<TLambda*>(object);
378  return (p->operator())(arg...);
379  }
380 
381  //*************************************************************************
383  //*************************************************************************
384  invocation_element invocation;
385  };
386 }
387 
388 #undef ETL_FILE
389 
390 #endif
constexpr static delegate create(T &instance)
Create from instance method (Run time).
Definition: delegate.h:139
constexpr static delegate create(T &&instance)=delete
Disable create from rvalue instance method (Run time).
static delegate create(T &&instance)=delete
constexpr static delegate create(const T &instance)
Create from const instance method (Run time).
Definition: delegate.h:155
constexpr static delegate create()
Create from function (Compile time).
Definition: delegate.h:121
TReturn operator()(TParams... args) const
Execute the delegate.
Definition: delegate.h:199
delegate()=default
Default constructor.
bool is_valid() const
Returns true if the delegate is valid.
Definition: delegate.h:240
constexpr static delegate create()
Definition: delegate.h:190
constexpr static delegate create()
Create from instance method (Compile time).
Definition: delegate.h:170
constexpr static delegate create(const TLambda &instance)
Create from Lambda or Functor.
Definition: delegate.h:130
The base class for delegate exceptions.
Definition: delegate.h:69
The exception thrown when the delegate is uninitialised.
Definition: delegate.h:82
Definition: delegate.h:91
#define ETL_ASSERT(b, e)
Definition: error_handler.h:290
exception(string_type reason_, string_type file_, numeric_type line_)
Constructor.
Definition: exception.h:67
Definition: exception.h:47
Definition: absolute.h:37
bool operator!=(const etl::array< T, SIZE > &lhs, const etl::array< T, SIZE > &rhs)
Definition: array.h:594
bool operator==(const etl::array< T, SIZE > &lhs, const etl::array< T, SIZE > &rhs)
Definition: array.h:582