siplasplas
function.hpp
1 #ifndef SIPLASPLAS_TYPEERASURE_FUNCTION_HPP
2 #define SIPLASPLAS_TYPEERASURE_FUNCTION_HPP
3 
4 #include "simpleany.hpp"
5 #include "anyarg.hpp"
6 #include "invoke.hpp"
7 #include "anystorage/deadpool.hpp"
8 #include "anystorage/fixedsize.hpp"
9 #include <siplasplas/utility/function_traits.hpp>
10 #include <siplasplas/utility/staticif.hpp>
11 #include <siplasplas/utility/compiles.hpp>
12 #include <siplasplas/utility/exception.hpp>
13 
14 namespace cpp
15 {
16 
17 namespace typeerasure
18 {
19 
57 template<typename Storage, typename ArgsStorage = Storage, typename ReturnStorage = Storage>
58 class Function
59 {
60 public:
61  Function() = default;
62  Function(const Function&) = default;
63 
74  template<typename Callable, typename = std::enable_if_t<
75  !std::is_same<std::decay_t<Callable>, Function>::value
76  >>
77  Function(Callable&& callable) :
78  _invoke{Invoke<std::decay_t<Callable>>{std::forward<Callable>(callable)}}
79  {}
80 
84  bool empty() const
85  {
86  return _invoke.empty();
87  }
88 
97  template<typename Callable, typename... Args>
98  static Function<Storage> create(Args&&... args)
99  {
100  return Function<Storage>{meta::identity<Callable>(), std::forward<Args>(args)...};
101  }
102 
113  template<typename... Args>
115  {
117 
118  AnyArg argsArray[] = {std::forward<Args>(args)..., AnyArg(nullptr)};
119  return _invoke.template get<InvokeInterface>().invoke(std::begin(argsArray));
120  }
121 
132  template<typename... Args>
133  SimpleAny<ReturnStorage> operator()(Args&&... args) const
134  {
136 
137  AnyArg argsArray[] = {std::forward<Args>(args)..., AnyArg(nullptr)};
138  return _invoke.template get<InvokeInterface>().invoke(std::begin(argsArray));
139  }
140 
149  template<typename ArgsVector>
150  SimpleAny<ReturnStorage> invoke(ArgsVector&& args)
151  {
153 
154  return _invoke.template get<InvokeInterface>().invoke(std::forward<ArgsVector>(args));
155  }
156 
165  template<typename ArgsVector>
166  SimpleAny<ReturnStorage> invoke(ArgsVector&& args) const
167  {
169 
170  return _invoke.template get<InvokeInterface>().invoke(std::forward<ArgsVector>(args));
171  }
172 
182  {
184 
185  return _invoke.template get<InvokeInterface>().invoke(args);
186  }
187 
197  {
199 
200  return _invoke.template get<InvokeInterface>().invoke(args);
201  }
202 
203  Function& operator=(const Function&) = default;
204  Function& operator=(Function&&) = default;
205 
209  template<typename Callable, typename = std::enable_if_t<
210  !std::is_same<std::decay_t<Callable>, Function>::value
211  >>
212  Function& operator=(Callable&& callable)
213  {
214  _invoke = Invoke<std::decay_t<Callable>>{std::forward<Callable>(callable)};
215  return *this;
216  }
217 
222  cpp::FunctionKind kind() const
223  {
224  return _invoke.template get<InvokeInterface>().kind();
225  }
226 
234  template<typename T>
235  const T& get() const
236  {
237  return _invoke.template get<InvokeInterface>().template get<T>();
238  }
239 
247  template<typename T>
248  T& get()
249  {
250  return _invoke.template get<InvokeInterface>().template get<T>();
251  }
252 
253 private:
254  template<typename Callable, typename... Args>
255  Function(meta::identity<Callable>, Args&&... args) :
256  _invoke{Invoke<Callable>{std::forward<Args>(args)...}}
257  {}
258 
259  class InvokeInterface
260  {
261  public:
262  virtual ~InvokeInterface() = default;
263  virtual SimpleAny<ReturnStorage> invoke(std::vector<AnyArg>&& args) = 0;
264  virtual SimpleAny<ReturnStorage> invoke(std::vector<AnyArg>&& args) const = 0;
265  virtual SimpleAny<ReturnStorage> invoke(std::vector<AnyArg>& args) = 0;
266  virtual SimpleAny<ReturnStorage> invoke(std::vector<AnyArg>& args) const = 0;
267  virtual SimpleAny<ReturnStorage> invoke(AnyArg* args) = 0;
268  virtual SimpleAny<ReturnStorage> invoke(AnyArg* args) const = 0;
269  virtual SimpleAny<ReturnStorage> invoke(std::vector<SimpleAny<ArgsStorage>>&& args) = 0;
270  virtual SimpleAny<ReturnStorage> invoke(std::vector<SimpleAny<ArgsStorage>>&& args) const = 0;
271  virtual SimpleAny<ReturnStorage> invoke(std::vector<SimpleAny<ArgsStorage>>& args) = 0;
272  virtual SimpleAny<ReturnStorage> invoke(std::vector<SimpleAny<ArgsStorage>>& args) const = 0;
274  virtual SimpleAny<ReturnStorage> invoke(SimpleAny<ArgsStorage>* args) const = 0;
275 
276  virtual void* getObject() = 0;
277  virtual const void* getObject() const = 0;
278  virtual cpp::FunctionKind kind() const = 0;
279  virtual cpp::typeerasure::TypeInfo typeInfo() const = 0;
280 
281  template<typename T>
282  const T& get() const
283  {
284  SIPLASPLAS_ASSERT(typeInfo() == cpp::typeerasure::TypeInfo::get<std::decay_t<T>>())(
285  "Callable is of type {}, not {}",
286  typeInfo().typeName(),
287  ctti::type_id<std::decay_t<T>>().name()
288  );
289 
290  return *reinterpret_cast<const T*>(getObject());
291  }
292 
293  template<typename T>
294  T& get()
295  {
296  SIPLASPLAS_ASSERT(typeInfo() == cpp::typeerasure::TypeInfo::get<std::decay_t<T>>())(
297  "Callable is of type {}, not {}",
298  typeInfo().typeName(),
299  ctti::type_id<std::decay_t<T>>().name()
300  );
301 
302  return *reinterpret_cast<T*>(getObject());
303  }
304  };
305 
306  template<typename Callable>
307  class Invoke : public InvokeInterface
308  {
309  public:
310  // Mark it explicitly non default constructible to make std::is_default_constructible
311  // and our concept classes work. Else, Callable construction expression should be evaluated,
312  // yielding a "default constructible" Invoke class, but giving a compilation error when a non-default
313  // constructible callable ctor is invoked
314  Invoke() = delete;
315 
316  template<typename... Args>
317  Invoke(Args&&... args) :
318  _callable{std::forward<Args>(args)...}
319  {}
320 
321  SimpleAny<ReturnStorage> invoke(std::vector<AnyArg>&& args) override
322  {
323  return doInvoke(std::move(args));
324  }
325 
326  SimpleAny<ReturnStorage> invoke(std::vector<AnyArg>&& args) const override
327  {
328  return doInvoke(std::move(args));
329  }
330 
331  SimpleAny<ReturnStorage> invoke(std::vector<AnyArg>& args) override
332  {
333  return doInvoke(args);
334  }
335 
336  SimpleAny<ReturnStorage> invoke(std::vector<AnyArg>& args) const override
337  {
338  return doInvoke(args);
339  }
340 
341  SimpleAny<ReturnStorage> invoke(AnyArg* args) override
342  {
343  return doInvoke(args);
344  }
345 
346  SimpleAny<ReturnStorage> invoke(AnyArg* args) const override
347  {
348  return doInvoke(args);
349  }
350 
351  SimpleAny<ReturnStorage> invoke(std::vector<SimpleAny<ArgsStorage>>&& args) override
352  {
353  return doInvoke(std::move(args));
354  }
355 
356  SimpleAny<ReturnStorage> invoke(std::vector<SimpleAny<ArgsStorage>>&& args) const override
357  {
358  return doInvoke(std::move(args));
359  }
360 
361  SimpleAny<ReturnStorage> invoke(std::vector<SimpleAny<ArgsStorage>>& args) override
362  {
363  return doInvoke(args);
364  }
365 
366  SimpleAny<ReturnStorage> invoke(std::vector<SimpleAny<ArgsStorage>>& args) const override
367  {
368  return doInvoke(args);
369  }
370 
372  {
373  return doInvoke(args);
374  }
375 
377  {
378  return doInvoke(args);
379  }
380 
381  template<typename Args>
382  SimpleAny<ReturnStorage> doInvoke(Args&& args)
383  {
384  return doInvoke(_callable, std::forward<Args>(args));
385  }
386 
387  template<typename Args>
388  SimpleAny<ReturnStorage> doInvoke(Args&& args) const
389  {
390  return doInvoke(_callable, std::forward<Args>(args));
391  }
392 
393 #define SIPLASPLAS_FUNCTION_INVOKE_EXPRESSION cpp::typeerasure::invoke(identity(std::forward<Callable_>(callable)), identity(std::forward<Args>(args)))
394 
395  template<typename Callable_, typename Args>
396  static SimpleAny<ReturnStorage> doInvoke(Callable_&& callable, Args&& args)
397  {
398  return cpp::staticIf<!(cpp::function_kind<Callable>() == cpp::FunctionKind::MEMBER_FUNCTION && std::is_const<std::remove_reference_t<Args>>::value)>([&](auto identity) -> SimpleAny<ReturnStorage>
399  {
400  return cpp::staticIf<std::is_void<decltype(SIPLASPLAS_FUNCTION_INVOKE_EXPRESSION)>::value>([&](auto identity) -> SimpleAny<ReturnStorage>
401  {
402  SIPLASPLAS_FUNCTION_INVOKE_EXPRESSION;
404  }).Else([&](auto identity) -> SimpleAny<ReturnStorage>
405  {
406  return SIPLASPLAS_FUNCTION_INVOKE_EXPRESSION;
407  });
408  })
409  .Else([](auto) -> SimpleAny<ReturnStorage>
410  {
411  throw cpp::exception<std::runtime_error>(
412  "Cannot invoke a non-const member function with a const vector of arguments"
413  );
414  });
415 
416  }
417 
418 #undef SIPLASPLAS_FUNCTION_INVOKE_EXPRESSION
419 
420  void* getObject() override
421  {
422  return &_callable;
423  }
424 
425  const void* getObject() const override
426  {
427  return &_callable;
428  }
429 
430  cpp::FunctionKind kind() const override
431  {
432  return cpp::function_kind<Callable>();
433  }
434 
435  cpp::typeerasure::TypeInfo typeInfo() const override
436  {
437  return cpp::typeerasure::TypeInfo::get<Callable>();
438  }
439 
440  private:
441  Callable _callable;
442  };
443 
444  SimpleAny32 _invoke;
445 };
446 
447 
453 
459 
465 
471 
472 }
473 
474 }
475 #endif // SIPLASPLAS_TYPEERASURE_FUNCTION_HPP
Function(Callable &&callable)
Constructs a Function from a Callable object.
Definition: function.hpp:77
Definition: meta.hpp:31
Definition: messaging.hpp:8
#define SIPLASPLAS_ASSERT_FALSE(...)
Defines a false assertion.
Definition: assert.hpp:432
Represents a type erased function call argument.
Definition: anyarg.hpp:31
bool empty() const
Checks if the object is empty (No callable assigned)
Definition: function.hpp:84
constexpr auto begin(const Sequence &sequence)
Returns an iterator pointing to the beginning of a sequence.
Definition: algorithm.hpp:62
SimpleAny< ReturnStorage > invoke(ArgsVector &&args)
Invokes the callable with the given arguments The arguments are passed as a vector of SimpleAny...
Definition: function.hpp:150
Implements a type-erased value container with minimal value semantics requirements.
Definition: simpleany.hpp:15
Contains minimal information to execute the value semantics operations of a type. ...
Definition: typeinfo.hpp:115
bool empty() const
Checks whether the any has an object hosted in or if is empty.
Definition: simpleany.hpp:401
SimpleAny< ReturnStorage > invoke(AnyArg *args) const
Invokes the callable with the given arguments The arguments are passed as a vector of SimpleAny...
Definition: function.hpp:196
SimpleAny< ReturnStorage > operator()(Args &&... args) const
Invokes the callable with the given arguments.
Definition: function.hpp:133
Function & operator=(Callable &&callable)
Assigns a new callable to the function.
Definition: function.hpp:212
static Function< Storage > create(Args &&... args)
Creates a Function by instancing in-place the given callable.
Definition: function.hpp:98
SimpleAny< ReturnStorage > invoke(ArgsVector &&args) const
Invokes the callable with the given arguments The arguments are passed as a vector of SimpleAny...
Definition: function.hpp:166
static constexpr TypeInfo get()
Returns the type information of type T.
Definition: typeinfo.hpp:232
#define SIPLASPLAS_ASSERT(...)
Defines an assertion expression.
Definition: assert.hpp:229
SimpleAny< ReturnStorage > invoke(AnyArg *args)
Invokes the callable with the given arguments The arguments are passed as a vector of SimpleAny...
Definition: function.hpp:181
cpp::FunctionKind kind() const
Returns the function kind (free function, pointer to member function, functor, etc) of the callable...
Definition: function.hpp:222
Stores a type-erased callable of any signature and kind.
Definition: function.hpp:58
SimpleAny< ReturnStorage > operator()(Args &&... args)
Invokes the callable with the given arguments.
Definition: function.hpp:114