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