diff --git a/CMakeLists.txt b/CMakeLists.txt index 5a29ae60..1bfa2ca8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -166,6 +166,8 @@ target_sources( lib/utils/log-helper.hpp lib/utils/math-helpers.cpp lib/utils/math-helpers.hpp + lib/utils/message-buffer.hpp + lib/utils/message-dispatcher.hpp lib/utils/mouse-wheel-guard.cpp lib/utils/mouse-wheel-guard.hpp lib/utils/name-dialog.cpp diff --git a/lib/utils/message-buffer.hpp b/lib/utils/message-buffer.hpp new file mode 100644 index 00000000..8d751bff --- /dev/null +++ b/lib/utils/message-buffer.hpp @@ -0,0 +1,42 @@ +#pragma once +#include +#include +#include + +namespace advss { + +template class MessageBuffer { +public: + bool Empty(); + void AppendMessage(const T &); + std::optional ConsumeMessage(); + +private: + std::deque _buffer; + std::mutex _mutex; +}; + +template inline bool MessageBuffer::Empty() +{ + std::lock_guard lock(_mutex); + return _buffer.empty(); +} + +template inline void MessageBuffer::AppendMessage(const T &message) +{ + std::lock_guard lock(_mutex); + _buffer.emplace_back(message); +} + +template inline std::optional MessageBuffer::ConsumeMessage() +{ + std::lock_guard lock(_mutex); + if (_buffer.empty()) { + return {}; + } + T message = _buffer.at(0); + _buffer.pop_front(); + return message; +} + +} // namespace advss diff --git a/lib/utils/message-dispatcher.hpp b/lib/utils/message-dispatcher.hpp new file mode 100644 index 00000000..2f78aa45 --- /dev/null +++ b/lib/utils/message-dispatcher.hpp @@ -0,0 +1,50 @@ +#pragma once +#include "message-buffer.hpp" + +#include +#include +#include + +namespace advss { + +template class MessageDispatcher { +public: + [[nodiscard]] std::shared_ptr> RegisterClient(); + void DispatchMessage(const T &message); + +private: + std::vector>> _clients; + std::mutex _mutex; +}; + +template +inline std::shared_ptr> MessageDispatcher::RegisterClient() +{ + std::lock_guard lock(_mutex); + // Clear expired client buffers + auto isExpired = [](const std::weak_ptr> &ptr) { + return ptr.expired(); + }; + _clients.erase(std::remove_if(_clients.begin(), _clients.end(), + isExpired), + _clients.end()); + // Prepare new buffer for client + auto buffer = std::make_shared>(); + _clients.emplace_back(buffer); + return buffer; +} + +template +inline void MessageDispatcher::DispatchMessage(const T &message) +{ + std::lock_guard lock(_mutex); + for (auto &client_ : _clients) { + auto client = client_.lock(); + if (!client) { + continue; + } + client->AppendMessage(message); + } +} + +} // namespace advss