]> git.stg.codes - stg.git/blob - include/stg/subscriptions.h
Complete replacement notifiers with subscriptions.
[stg.git] / include / stg / subscriptions.h
1 #pragma once
2
3 #include <list>
4 #include <functional>
5 #include <mutex>
6
7 namespace STG
8 {
9
10 class Connection
11 {
12     public:
13         Connection() = default;
14
15         Connection(const Connection&) = delete;
16         Connection& operator=(const Connection&) = delete;
17         Connection(Connection&&) = default;
18         Connection& operator=(Connection&&) = default;
19
20         Connection(const std::function<void ()>& f) noexcept : m_disconnect(f) {}
21         void disconnect() noexcept
22         {
23             if (!m_disconnect)
24                 return;
25             m_disconnect();
26             m_disconnect = {};
27         }
28     private:
29         std::function<void ()> m_disconnect;
30 };
31
32 class ScopedConnection
33 {
34     public:
35         ScopedConnection() = default;
36
37         ScopedConnection(const ScopedConnection&) = delete;
38         ScopedConnection& operator=(const ScopedConnection&) = delete;
39         ScopedConnection(ScopedConnection&&) = default;
40         ScopedConnection& operator=(ScopedConnection&&) = default;
41
42         ScopedConnection(Connection c) noexcept : m_conn(std::move(c)) {}
43         ~ScopedConnection() { disconnect(); }
44
45         void disconnect() noexcept { m_conn.disconnect(); }
46
47     private:
48         Connection m_conn;
49 };
50
51 template <typename... Ts>
52 class Subscriptions
53 {
54     public:
55         using Callback = std::function<void (const Ts&...)>;
56         using Callbacks = std::list<Callback>;
57
58         Connection makeConn(typename Callbacks::iterator i) noexcept
59         {
60             return Connection([this, i](){ remove(i); });
61         }
62
63         template <typename F>
64         Connection add(F&& f)
65         {
66             std::lock_guard lock(m_mutex);
67             return makeConn(m_callbacks.insert(m_callbacks.end(), Callback(std::forward<F>(f))));
68         }
69
70         template <typename C, typename... T2s>
71         Connection add(C& c, void (C::*m)(T2s...))
72         {
73             return add([&c, m](const Ts&... values){ (c.*m)(values...); });
74         }
75
76         void remove(typename Callbacks::iterator i)
77         {
78             std::lock_guard lock(m_mutex);
79             m_callbacks.erase(i);
80         }
81
82         void notify(const Ts&... values)
83         {
84             std::lock_guard lock(m_mutex);
85             for (auto& cb : m_callbacks)
86                 cb(values...);
87         }
88
89         bool empty() const noexcept
90         {
91             std::lock_guard lock(m_mutex);
92             return m_callbacks.empty();
93         }
94
95         size_t size() const noexcept
96         {
97             std::lock_guard lock(m_mutex);
98             return m_callbacks.size();
99         }
100
101     private:
102         mutable std::mutex m_mutex;
103         Callbacks m_callbacks;
104 };
105
106 }