]> git.stg.codes - stg.git/blobdiff - include/stg/subscriptions.h
Add subscriptions (to replace notifiers).
[stg.git] / include / stg / subscriptions.h
diff --git a/include/stg/subscriptions.h b/include/stg/subscriptions.h
new file mode 100644 (file)
index 0000000..1486e62
--- /dev/null
@@ -0,0 +1,84 @@
+#pragma once
+
+#include <list>
+#include <functional>
+#include <mutex>
+
+namespace STG
+{
+
+template <typename... Ts>
+class Subscriptions
+{
+    public:
+        using Callback = std::function<void (Ts...)>;
+        using Callbacks = std::list<Callback>;
+
+        class Connection
+        {
+            public:
+                Connection(Subscriptions& s, typename Callbacks::iterator i) noexcept
+                    : m_subscriptions(s), m_iterator(i), m_connected(true)
+                {}
+                ~Connection()
+                {
+                    disconnect();
+                }
+
+                void disconnect() noexcept
+                {
+                    if (!m_connected)
+                        return;
+                    m_subscriptions.remove(m_iterator);
+                    m_connected = false;
+                }
+            private:
+                Subscriptions& m_subscriptions;
+                typename Callbacks::iterator m_iterator;
+                bool m_connected;
+        };
+
+        template <typename F>
+        Connection add(F&& f)
+        {
+            std::lock_guard lock(m_mutex);
+            return Connection(*this, m_callbacks.insert(m_callbacks.end(), Callback(std::forward<F>(f))));
+        }
+
+        template <typename C, typename... T2s>
+        Connection add(C& c, void (C::*m)(T2s...))
+        {
+            return add([&c, m](Ts&&... values){ (c.*m)(std::forward<Ts>(values)...); });
+        }
+
+        void remove(typename Callbacks::iterator i)
+        {
+            std::lock_guard lock(m_mutex);
+            m_callbacks.erase(i);
+        }
+
+        void notify(Ts&&... values)
+        {
+            std::lock_guard lock(m_mutex);
+            for (auto& cb : m_callbacks)
+                cb(values...);
+        }
+
+        bool empty() const noexcept
+        {
+            std::lock_guard lock(m_mutex);
+            return m_callbacks.empty();
+        }
+
+        size_t size() const noexcept
+        {
+            std::lock_guard lock(m_mutex);
+            return m_callbacks.size();
+        }
+
+    private:
+        mutable std::mutex m_mutex;
+        Callbacks m_callbacks;
+};
+
+}