]> git.stg.codes - stg.git/blob - projects/stargazer/actions.h
Add subscriptions (to replace notifiers).
[stg.git] / projects / stargazer / actions.h
1 #pragma once
2
3 // Usage:
4 //
5 // ACTIONS_LIST actionsList;
6 // CLASS myClass;
7 // DATA1 myData1;
8 // DATA2 myData2;
9 //
10 // actionsList.Enqueue(myClass, &CLASS::myMethod1, myData1);
11 // actionsList.Enqueue(myClass, &CLASS::myMethod2, myData2);
12 //
13 // actionsList.InvokeAll();
14
15 #include <vector>
16 #include <functional>
17 #include <mutex>
18
19 // Generalized actor type - a method of some class with one argument
20 template <class ACTIVE_CLASS, typename DATA_TYPE>
21 struct ACTOR
22 {
23     using TYPE = void (ACTIVE_CLASS::*)(DATA_TYPE);
24 };
25
26 // Abstract base action class for polymorphic action invocation
27 class BASE_ACTION
28 {
29 public:
30     virtual ~BASE_ACTION() {}
31     virtual void Invoke() = 0;
32 };
33
34 // Concrete generalized action type - an actor with it's data and owner
35 template <class ACTIVE_CLASS, typename DATA_TYPE>
36 class ACTION : public BASE_ACTION
37 {
38 public:
39     ACTION(ACTIVE_CLASS & ac,
40            typename ACTOR<ACTIVE_CLASS, DATA_TYPE>::TYPE a,
41            DATA_TYPE d)
42         : activeClass(ac), actor(a), data(d) {}
43     void Invoke() override
44     {
45         (activeClass.*actor)(data);
46     }
47 private:
48     ACTION(const ACTION<ACTIVE_CLASS, DATA_TYPE> & rvalue);
49     ACTION<ACTIVE_CLASS, DATA_TYPE> & operator=(const ACTION<ACTIVE_CLASS, DATA_TYPE> & rvalue);
50
51     ACTIVE_CLASS & activeClass;
52     typename ACTOR<ACTIVE_CLASS, DATA_TYPE>::TYPE actor;
53     DATA_TYPE data;
54 };
55
56 // A list of an actions
57 // All methods are thread-safe
58 class ACTIONS_LIST
59 {
60 public:
61     ~ACTIONS_LIST()
62     {
63         std::lock_guard lock(m_mutex);
64         for (auto action : m_list)
65             delete action;
66     }
67
68     auto begin() { std::lock_guard lock(m_mutex); return m_list.begin(); }
69     auto end() { std::lock_guard lock(m_mutex); return m_list.end(); }
70     auto begin() const { std::lock_guard lock(m_mutex); return m_list.begin(); }
71     auto end() const { std::lock_guard lock(m_mutex); return m_list.end(); }
72
73     bool empty() const { std::lock_guard lock(m_mutex); return m_list.empty(); }
74     size_t size() const { std::lock_guard lock(m_mutex); return m_list.size(); }
75     void swap(ACTIONS_LIST & rhs) { std::lock_guard lock(m_mutex); m_list.swap(rhs.m_list); }
76
77     // Add an action to list
78     template <class ACTIVE_CLASS, typename DATA_TYPE>
79     void Enqueue(ACTIVE_CLASS & ac,
80                  typename ACTOR<ACTIVE_CLASS, DATA_TYPE>::TYPE a,
81                  DATA_TYPE d)
82     {
83         std::lock_guard lock(m_mutex);
84         m_list.push_back(new ACTION<ACTIVE_CLASS, DATA_TYPE>(ac, a, d));
85     }
86     // Invoke all actions in the list
87     void InvokeAll()
88     {
89         std::lock_guard lock(m_mutex);
90         for (auto action : m_list)
91             action->Invoke();
92     }
93 private:
94     mutable std::mutex m_mutex;
95     std::vector<BASE_ACTION*> m_list;
96 };