X-Git-Url: https://git.stg.codes/stg.git/blobdiff_plain/bc6cac0e474dfe2feb4983aef98f99e23a98ffc4..1c529746ff07312e30e76fd933c628c658e3c77d:/include/stg/subscriptions.h diff --git a/include/stg/subscriptions.h b/include/stg/subscriptions.h new file mode 100644 index 00000000..1486e62d --- /dev/null +++ b/include/stg/subscriptions.h @@ -0,0 +1,84 @@ +#pragma once + +#include +#include +#include + +namespace STG +{ + +template +class Subscriptions +{ + public: + using Callback = std::function; + using Callbacks = std::list; + + 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 + Connection add(F&& f) + { + std::lock_guard lock(m_mutex); + return Connection(*this, m_callbacks.insert(m_callbacks.end(), Callback(std::forward(f)))); + } + + template + Connection add(C& c, void (C::*m)(T2s...)) + { + return add([&c, m](Ts&&... values){ (c.*m)(std::forward(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; +}; + +}