jubilant-funicular
Event.h
1 #ifndef NTA_EVENT_H_INCLUDED
2 #define NTA_EVENT_H_INCLUDED
3 
4 #include <type_traits>
5 
6 #include "nta/Option.h"
7 
8 namespace nta {
12  template<typename RecipientEnum, typename... FuncTypes>
13  class EventTemplate {
14  static_assert(std::is_enum_v<RecipientEnum>,
15  "EventTemplate: RecipientEnum must be enum");
16  static_assert(std::size_t(RecipientEnum::COUNT) != 0,
17  "EventTemplate: RecipientEnum must declare COUNT as the last variant");
18  static_assert(sizeof...(FuncTypes) == std::size_t(RecipientEnum::COUNT),
19  "EventTemplate: Every recipient must have a corresponding function signature");
20  static_assert((std::is_function_v<FuncTypes> && ...),
21  "EventTemplate: Every FuncType should be a function type");
22  private:
23  template<std::size_t idx, typename... Args>
24  void enact_helper(Args&&... args) const {
25  if constexpr (std::is_invocable_v<decltype(std::get<idx>(m_actions).get()),
26  Args...>) {
27  auto func = std::get<idx>(m_actions);
28  if (func) func.unwrap()(std::forward<Args>(args)...);
29  }
30  }
31  template<std::size_t i, typename... Args>
32  void operator_helper(std::size_t e, Args&&... args) const {
33  if (e == i) enact_helper<i>(std::forward<Args>(args)...);
34  else if constexpr (i > 0) operator_helper<i-1>(e,
35  std::forward<Args>(args)...);
36  }
37  template<std::size_t i, typename... Args>
38  void operator2_helper(Args&&... args) const {
39  enact_helper<i>(std::forward<Args>(args)...);
40  if constexpr (i > 0) operator2_helper<i-1>(std::forward<Args>(args)...);
41  }
42 
43  std::tuple<utils::Option<std::function<FuncTypes>>...> m_actions;
44  public:
45  template<RecipientEnum e, typename Func>
46  void define_for(Func&& func) {
47  std::get<std::size_t(e)>(m_actions) = utils::make_some(func);
48  }
49  template<RecipientEnum e>
50  void undefine_for() {
51  std::get<std::size_t(e)>(m_actions).destroy();
52  }
53 
54  template<RecipientEnum e, typename... Args>
55  void enact(Args&&... args) const {
56  static_assert(std::is_invocable_v<decltype(std::get<std::size_t(e)>(m_actions).get()),
57  Args...>,
58  "EventTemplate: Tried calling enact with mismatched enum/args");
59  enact_helper<std::size_t(e)>(std::forward<Args>(args)...);
60  }
61 
62  template<typename... Args>
63  void operator()(RecipientEnum e, Args&&... args) const {
64  operator_helper<sizeof...(FuncTypes)-1>(std::size_t(e),
65  std::forward<Args>(args)...);
66  }
67  template<typename... Args>
68  void operator()(Args&&... args) const {
69  operator2_helper<sizeof...(FuncTypes)-1>(std::forward<Args>(args)...);
70  }
71 
72  using enum_type = RecipientEnum;
73  };
75  template<>
76  class EventTemplate<void> {
77  public:
78  using enum_type = void;
79  };
80 }
81 
82 #endif // NTA_EVENT_H_INCLUDED
nta::utils::make_some
Option< T > make_some(const T &data)
Replacement for calling Option<T>::some()
Definition: Option.h:134
nta
Definition: Animation2D.h:6
nta::EventTemplate
Definition: Event.h:13