code integration
This commit is contained in:
529
sdi_toolBox_2.x.x/toolBox/sdi_toolBox/desktop/eventBus/bus.h
Normal file
529
sdi_toolBox_2.x.x/toolBox/sdi_toolBox/desktop/eventBus/bus.h
Normal file
@@ -0,0 +1,529 @@
|
||||
/*
|
||||
Copyright (c) 2026 - SD-Innovation S.A.S. - FRANCE
|
||||
*/
|
||||
|
||||
/*
|
||||
ver: 2.x.x - build: 2026-04-28
|
||||
*/
|
||||
|
||||
/*
|
||||
The zlib License
|
||||
|
||||
Copyright (c) 2026 SD-Innovation S.A.S.
|
||||
|
||||
This software is provided ‘as-is’, without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "defs.h"
|
||||
#include "inode.h"
|
||||
#include "message.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <ranges>
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace sdi_toolBox::desktop::eventBus
|
||||
{
|
||||
//--------------------------------------------------------------
|
||||
/**
|
||||
* @class Bus
|
||||
* @brief Central message dispatcher for the event bus system.
|
||||
*
|
||||
* The Bus class is the core component of the event bus architecture.
|
||||
* It manages a routing table that maps message type identifiers to lists
|
||||
* of subscribed nodes, and dispatches messages to the appropriate nodes
|
||||
* when they are emitted or posted.
|
||||
*
|
||||
* Nodes can subscribe to specific message types or to broadcast mode,
|
||||
* in which case they receive all messages regardless of their type.
|
||||
*
|
||||
* The Bus is thread-safe: all operations on the routing table are
|
||||
* protected by an internal mutex.
|
||||
*
|
||||
* @note The Bus is non-copyable and non-movable.
|
||||
* @note The Bus does not take ownership of the nodes it manages.
|
||||
*
|
||||
* @par Example usage:
|
||||
* @code
|
||||
* sdi_toolBox::desktop::eventBus::Bus bus;
|
||||
* sdi_toolBox::desktop::eventBus::Node node(bus);
|
||||
*
|
||||
* node.subscribe(MY_EVENT_TYPE);
|
||||
* bus.emit<MyMessage>(arg1, arg2);
|
||||
*
|
||||
* auto msg = std::dynamic_pointer_cast<MyMessage>(node.popMessage());
|
||||
* @endcode
|
||||
*
|
||||
* @see Node
|
||||
* @see INode
|
||||
* @see Message
|
||||
*/
|
||||
class Bus final
|
||||
{
|
||||
friend class Node; ///< Allow the Node class to access private members
|
||||
|
||||
using VectorNode = std::vector<INode *>;
|
||||
|
||||
public:
|
||||
///@name Construction & Destruction
|
||||
///@{
|
||||
|
||||
/**
|
||||
* @brief Default constructor.
|
||||
*
|
||||
* Initializes the Bus and records the construction timestamp
|
||||
* used as the bus start reference time.
|
||||
*/
|
||||
Bus();
|
||||
|
||||
/**
|
||||
* @brief Default destructor.
|
||||
*/
|
||||
~Bus() = default;
|
||||
|
||||
/**
|
||||
* @brief Copy constructor - deleted.
|
||||
*
|
||||
* The Bus is non-copyable.
|
||||
*/
|
||||
Bus(const Bus &obj) = delete;
|
||||
|
||||
/**
|
||||
* @brief Move constructor - deleted.
|
||||
*
|
||||
* The Bus is non-movable.
|
||||
*/
|
||||
Bus(Bus &&obj) noexcept = delete;
|
||||
|
||||
/**
|
||||
* @brief Copy assignment operator - deleted.
|
||||
*
|
||||
* The Bus is non-copyable.
|
||||
*/
|
||||
Bus &operator=(const Bus &obj) = delete;
|
||||
|
||||
/**
|
||||
* @brief Move assignment operator - deleted.
|
||||
*
|
||||
* The Bus is non-movable.
|
||||
*/
|
||||
Bus &operator=(Bus &&obj) noexcept = delete;
|
||||
|
||||
///@}
|
||||
///@name Subscription Management
|
||||
///@{
|
||||
|
||||
/**
|
||||
* @brief Remove all subscriptions from the routing table.
|
||||
*
|
||||
* Clears both the specific event subscriptions and the broadcast
|
||||
* subscription list. After this call, no node will receive any message
|
||||
* until it re-subscribes.
|
||||
*
|
||||
* @note This operation is thread-safe.
|
||||
*/
|
||||
void clearAllSubscriptions();
|
||||
|
||||
/**
|
||||
* @brief Subscribe a node to a specific message type.
|
||||
*
|
||||
* Registers the given node to receive messages of the specified type.
|
||||
* If the node is already subscribed to this type, this call has no effect
|
||||
* (no duplicates are created).
|
||||
*
|
||||
* @param node Pointer to the node to subscribe. Must not be @c nullptr.
|
||||
* @param eventType The message type identifier to subscribe to.
|
||||
*
|
||||
* @throws std::runtime_error if @p node is @c nullptr.
|
||||
* @note This operation is thread-safe.
|
||||
*/
|
||||
void subscribe(INode *node, MessageTypeID eventType);
|
||||
|
||||
/**
|
||||
* @brief Unsubscribe a node from a specific message type.
|
||||
*
|
||||
* Removes the given node from the list of subscribers for the specified
|
||||
* message type. If the node was not subscribed to this type, this call
|
||||
* has no effect.
|
||||
*
|
||||
* @param node Pointer to the node to unsubscribe. Must not be @c nullptr.
|
||||
* @param eventType The message type identifier to unsubscribe from.
|
||||
*
|
||||
* @throws std::runtime_error if @p node is @c nullptr.
|
||||
* @note This operation is thread-safe.
|
||||
*/
|
||||
void unsubscribe(INode *node, MessageTypeID eventType);
|
||||
|
||||
/**
|
||||
* @brief Unsubscribe a node from all message types and broadcast mode.
|
||||
*
|
||||
* Removes the given node from all specific event subscription lists
|
||||
* and from the broadcast subscription list. This is automatically called
|
||||
* by the Node destructor to ensure no dangling pointers remain in the
|
||||
* routing table.
|
||||
*
|
||||
* @param node Pointer to the node to unsubscribe. Must not be @c nullptr.
|
||||
*
|
||||
* @throws std::runtime_error if @p node is @c nullptr.
|
||||
* @note This operation is thread-safe.
|
||||
*/
|
||||
void unsubscribeFromAll(INode *node);
|
||||
|
||||
/**
|
||||
* @brief Check whether a node is subscribed to a specific message type.
|
||||
*
|
||||
* @param node Pointer to the node to check. Must not be @c nullptr.
|
||||
* @param eventType The message type identifier to check.
|
||||
* @return @c true if the node is subscribed to the given message type,
|
||||
* @c false otherwise.
|
||||
*
|
||||
* @throws std::runtime_error if @p node is @c nullptr.
|
||||
* @note This operation is thread-safe.
|
||||
*/
|
||||
[[nodiscard]] bool isSubscribed(const INode *node, MessageTypeID eventType) const;
|
||||
|
||||
///@}
|
||||
///@name Broadcast management
|
||||
///@{
|
||||
|
||||
/**
|
||||
* @brief Subscribe a node to broadcast mode.
|
||||
*
|
||||
* A node in broadcast mode receives all messages posted to the bus,
|
||||
* regardless of their type. A node can be subscribed to both broadcast
|
||||
* mode and specific message types simultaneously, in which case it will
|
||||
* receive the message twice for matching types.
|
||||
*
|
||||
* @param node Pointer to the node to subscribe. Must not be @c nullptr.
|
||||
*
|
||||
* @throws std::runtime_error if @p node is @c nullptr.
|
||||
* @note This operation is thread-safe.
|
||||
*/
|
||||
void subscribeToBroadcast(INode *node);
|
||||
|
||||
/**
|
||||
* @brief Unsubscribe a node from broadcast mode.
|
||||
*
|
||||
* Removes the given node from the broadcast subscription list.
|
||||
* If the node was not subscribed to broadcast mode, this call has no effect.
|
||||
*
|
||||
* @param node Pointer to the node to unsubscribe. Must not be @c nullptr.
|
||||
*
|
||||
* @throws std::runtime_error if @p node is @c nullptr.
|
||||
* @note This operation is thread-safe.
|
||||
*/
|
||||
void unsubscribeFromBroadcast(INode *node);
|
||||
|
||||
/**
|
||||
* @brief Check whether a node is subscribed to broadcast mode.
|
||||
*
|
||||
* @param node Pointer to the node to check. Must not be @c nullptr.
|
||||
* @return @c true if the node is subscribed to broadcast mode,
|
||||
* @c false otherwise.
|
||||
*
|
||||
* @throws std::runtime_error if @p node is @c nullptr.
|
||||
* @note This operation is thread-safe.
|
||||
*/
|
||||
[[nodiscard]] bool isSubscribedToBroadcast(INode *node) const; // Check if a node is subscribed to broadcast mode
|
||||
|
||||
///@}
|
||||
///@name Message transmission
|
||||
///@{
|
||||
|
||||
/**
|
||||
* @brief Construct and emit a message of type @p T to the bus.
|
||||
*
|
||||
* Creates a new message of type @p T by forwarding the provided arguments
|
||||
* to its constructor, then posts it to the bus via @ref post().
|
||||
*
|
||||
* @tparam T The message type to emit. Must be derived from @ref Message.
|
||||
* @tparam Args Constructor argument types for @p T.
|
||||
* @param args Arguments forwarded to the constructor of @p T.
|
||||
* @return @c true if at least one subscriber received the message,
|
||||
* @c false otherwise.
|
||||
*
|
||||
* @note Enforced at compile time: @p T must derive from @ref Message.
|
||||
* @note This operation is thread-safe.
|
||||
*
|
||||
* @par Example:
|
||||
* @code
|
||||
* bus.emit<MyMessage>(arg1, arg2);
|
||||
* @endcode
|
||||
*/
|
||||
template<class T, class... Args>
|
||||
bool emit(Args &&...args);
|
||||
|
||||
/**
|
||||
* @brief Post an already constructed message to the bus.
|
||||
*
|
||||
* Updates the message timestamp and dispatches it to all nodes subscribed
|
||||
* to the message type, as well as all nodes in broadcast mode.
|
||||
*
|
||||
* @param message Shared pointer to the message to post. Must not be @c nullptr.
|
||||
* @return @c true if at least one specific subscriber received the message,
|
||||
* @c false otherwise.
|
||||
*
|
||||
* @note This operation is thread-safe.
|
||||
* @see emit()
|
||||
*/
|
||||
bool post(const std::shared_ptr<Message> &message) const; // Post a message to the bus
|
||||
|
||||
///@}
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Dispatch a message to all nodes subscribed to its type.
|
||||
* @param eventType The message type identifier.
|
||||
* @param message The message to dispatch.
|
||||
* @return The number of nodes that received the message.
|
||||
*/
|
||||
size_t postMessageToSubscribers(MessageTypeID eventType, const std::shared_ptr<Message> &message) const;
|
||||
|
||||
/**
|
||||
* @brief Dispatch a message to all nodes in broadcast mode.
|
||||
* @param message The message to dispatch.
|
||||
* @return The number of broadcast nodes that received the message.
|
||||
*/
|
||||
size_t postMessageToBroadcastSubscribers(const std::shared_ptr<Message> &message) const;
|
||||
|
||||
/**
|
||||
* @brief Retrieve the subscriber list for a given message type.
|
||||
* @param messageType The message type identifier.
|
||||
* @return Pointer to the vector of subscribed nodes, or @c nullptr if none.
|
||||
*/
|
||||
const VectorNode *getSubscribersForMessageType(MessageTypeID messageType) const; // Get the list of subscribers for a specific message type
|
||||
|
||||
/// @brief Timestamp recorded when the Bus was constructed.
|
||||
TimePoint m_busStartTimestamp;
|
||||
|
||||
/// @brief Internal routing table, protected by a mutex for thread-safe access.
|
||||
struct
|
||||
{
|
||||
mutable std::mutex mtx; ///< Mutex for thread-safe access to the nodes map
|
||||
std::unordered_map<MessageTypeID, VectorNode> nodeList; ///< Map of message type IDs to lists of subscribed nodes
|
||||
std::set<INode *> broadcastNodeList; ///< Set of nodes subscribed to receive all messages (broadcast mode)
|
||||
} m_routingTable;
|
||||
};
|
||||
//--------------------------------------------------------------
|
||||
|
||||
//--------------------------------------------------------------
|
||||
/* Default constructor */
|
||||
inline Bus::Bus()
|
||||
{
|
||||
// Initialization
|
||||
m_busStartTimestamp = std::chrono::steady_clock::now();
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Clear all subscriptions from the bus (remove all nodes from the routing table) */
|
||||
inline void Bus::clearAllSubscriptions()
|
||||
{
|
||||
std::scoped_lock lock(m_routingTable.mtx);
|
||||
|
||||
m_routingTable.nodeList.clear(); // Clear all event subscriptions
|
||||
m_routingTable.broadcastNodeList.clear(); // Clear all broadcast subscriptions
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Subscribe a listener to a specific event type */
|
||||
inline void Bus::subscribe(INode *node, MessageTypeID eventType)
|
||||
{
|
||||
// Sanity check
|
||||
if (!node)
|
||||
throw std::runtime_error("invalid node handle");
|
||||
|
||||
std::scoped_lock lock(m_routingTable.mtx);
|
||||
|
||||
if (!m_routingTable.nodeList.contains(eventType)) // Event type not registered yet, create a new entry with the node
|
||||
{
|
||||
m_routingTable.nodeList[eventType] = { node };
|
||||
}
|
||||
else // Event type already registered, add the node if not already subscribed
|
||||
{
|
||||
auto &nodes = m_routingTable.nodeList.at(eventType);
|
||||
if (std::ranges::find(nodes, node) == nodes.end())
|
||||
{
|
||||
// Node not already subscribed, add it to the list
|
||||
nodes.push_back(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Unsubscribe a listener from a specific event type */
|
||||
inline void Bus::unsubscribe(INode *node, MessageTypeID eventType)
|
||||
{
|
||||
// Sanity check
|
||||
if (!node)
|
||||
throw std::runtime_error("invalid node handle");
|
||||
|
||||
std::scoped_lock lock(m_routingTable.mtx);
|
||||
|
||||
// Event type not recorded, nothing to do
|
||||
if (!m_routingTable.nodeList.contains(eventType))
|
||||
return;
|
||||
|
||||
// Event type registered, remove the listener if subscribed
|
||||
auto &nodes = m_routingTable.nodeList.at(eventType);
|
||||
std::erase(nodes, node);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Unsubscribe a listener from a specific event type */
|
||||
inline void Bus::unsubscribeFromAll(INode *node)
|
||||
{
|
||||
// Sanity check
|
||||
if (!node)
|
||||
throw std::runtime_error("invalid node handle");
|
||||
|
||||
std::scoped_lock lock(m_routingTable.mtx);
|
||||
|
||||
// Iterate through all event types and remove the node from each list
|
||||
for (auto &nodeList : m_routingTable.nodeList | std::views::values)
|
||||
std::erase(nodeList, node);
|
||||
|
||||
// Remove from broadcast subscriptions as well
|
||||
m_routingTable.broadcastNodeList.erase(node);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Check if a listener is subscribed to a specific event type */
|
||||
inline bool Bus::isSubscribed(const INode *node, MessageTypeID eventType) const
|
||||
{
|
||||
// Sanity check
|
||||
if (!node)
|
||||
throw std::runtime_error("invalid node handle");
|
||||
|
||||
std::scoped_lock lock(m_routingTable.mtx);
|
||||
|
||||
// Event type not recorded, node not subscribed
|
||||
if (!m_routingTable.nodeList.contains(eventType))
|
||||
return false;
|
||||
|
||||
// Event type recorded, check if the node is in the list
|
||||
const auto &nodes = m_routingTable.nodeList.at(eventType);
|
||||
return std::ranges::find(nodes, node) != nodes.end();
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Subscribe a node to receive all messages (broadcast mode) */
|
||||
inline void Bus::subscribeToBroadcast(INode *node)
|
||||
{
|
||||
// Sanity check
|
||||
if (!node)
|
||||
throw std::runtime_error("invalid node handle");
|
||||
|
||||
std::scoped_lock lock(m_routingTable.mtx);
|
||||
|
||||
// Add the node to the broadcast nodes set
|
||||
m_routingTable.broadcastNodeList.insert(node);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Unsubscribe a node from broadcast mode */
|
||||
inline void Bus::unsubscribeFromBroadcast(INode *node)
|
||||
{
|
||||
// Sanity check
|
||||
if (!node)
|
||||
throw std::runtime_error("invalid node handle");
|
||||
|
||||
std::scoped_lock lock(m_routingTable.mtx);
|
||||
|
||||
// Remove the node from the broadcast nodes set
|
||||
m_routingTable.broadcastNodeList.erase(node);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Check if a node is subscribed to broadcast mode */
|
||||
inline bool Bus::isSubscribedToBroadcast(INode *node) const
|
||||
{
|
||||
// Sanity check
|
||||
if (!node)
|
||||
throw std::runtime_error("invalid node handle");
|
||||
|
||||
std::scoped_lock lock(m_routingTable.mtx);
|
||||
|
||||
// Check if the node is in the broadcast nodes set
|
||||
return m_routingTable.broadcastNodeList.contains(node);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Emit a message of type T with the given arguments(create a message and post it to the bus) */
|
||||
template<class T, class... Args>
|
||||
bool Bus::emit(Args &&...args)
|
||||
{
|
||||
static_assert(std::derived_from<T, Message>, "T must be derived from IMessage");
|
||||
|
||||
// Create a message of type T with the given arguments
|
||||
auto message = std::make_shared<T>(std::forward<Args>(args)...);
|
||||
|
||||
// Post the message to the bus
|
||||
return post(message);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Post a message to the bus */
|
||||
inline bool Bus::post(const std::shared_ptr<Message> &message) const
|
||||
{
|
||||
std::scoped_lock lock(m_routingTable.mtx);
|
||||
|
||||
// Update message state
|
||||
message->updateTimestamp(); // Update the timestamp of when the message was posted to the bus
|
||||
|
||||
// Post the message to all subscribers of the specific
|
||||
// message type and get the number of subscribers that
|
||||
// received the message
|
||||
const auto subscriberCount = postMessageToSubscribers(message->getMessageTypeID(), message);
|
||||
|
||||
// Post the message to all broadcast subscribers and
|
||||
// get the number of subscribers that received the
|
||||
// message
|
||||
(void)postMessageToBroadcastSubscribers(message);
|
||||
|
||||
return subscriberCount > 0;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Post a message to all subscribers of a specific event type and return the number of subscribers that received the message */
|
||||
inline size_t Bus::postMessageToSubscribers(const MessageTypeID eventType, const std::shared_ptr<Message> &message) const
|
||||
{
|
||||
const auto subscriberList = getSubscribersForMessageType(eventType);
|
||||
if (!subscriberList)
|
||||
return 0;
|
||||
|
||||
for (const auto &node : *subscriberList)
|
||||
node->append(message);
|
||||
|
||||
return subscriberList->size();
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Post a message to all broadcast subscribers and return the number of subscribers that received the message */
|
||||
inline size_t Bus::postMessageToBroadcastSubscribers(const std::shared_ptr<Message> &message) const
|
||||
{
|
||||
for (const auto &node : m_routingTable.broadcastNodeList)
|
||||
node->append(message);
|
||||
|
||||
return m_routingTable.broadcastNodeList.size();
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Get the list of subscribers for a specific message type */
|
||||
inline const Bus::VectorNode *Bus::getSubscribersForMessageType(const MessageTypeID messageType) const
|
||||
{
|
||||
if (!m_routingTable.nodeList.contains(messageType))
|
||||
return nullptr; // No subscribers for this message type
|
||||
|
||||
return &m_routingTable.nodeList.at(messageType);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
} // namespace sdi_toolBox::desktop::eventBus
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
Copyright (c) 2026 - SD-Innovation S.A.S. - FRANCE
|
||||
*/
|
||||
|
||||
/*
|
||||
ver: 2.x.x - build: 2026-04-28
|
||||
*/
|
||||
|
||||
/*
|
||||
The zlib License
|
||||
|
||||
Copyright (c) 2026 SD-Innovation S.A.S.
|
||||
|
||||
This software is provided ‘as-is’, without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
|
||||
//--------------------------------------------------------------
|
||||
namespace sdi_toolBox::desktop::eventBus
|
||||
{
|
||||
using MessageTypeID = uint64_t; ///< Unique identifier for a message type
|
||||
using TimePoint = std::chrono::steady_clock::time_point; ///< Monotonic timestamp type used throughout the event bus
|
||||
//--------------------------------------------------------------
|
||||
} // namespace sdi_toolBox::desktop::eventBus
|
||||
128
sdi_toolBox_2.x.x/toolBox/sdi_toolBox/desktop/eventBus/inode.h
Normal file
128
sdi_toolBox_2.x.x/toolBox/sdi_toolBox/desktop/eventBus/inode.h
Normal file
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
Copyright (c) 2026 - SD-Innovation S.A.S. - FRANCE
|
||||
*/
|
||||
|
||||
/*
|
||||
ver: 2.x.x - build: 2026-04-28
|
||||
*/
|
||||
|
||||
/*
|
||||
The zlib License
|
||||
|
||||
Copyright (c) 2026 SD-Innovation S.A.S.
|
||||
|
||||
This software is provided ‘as-is’, without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "message.h"
|
||||
|
||||
namespace sdi_toolBox::desktop::eventBus
|
||||
{
|
||||
//--------------------------------------------------------------
|
||||
/**
|
||||
* @class INode
|
||||
* @brief Abstract interface representing a subscriber node in the event bus system.
|
||||
*
|
||||
* INode is the base interface that all subscriber nodes must implement to
|
||||
* participate in the event bus. It exposes a single private pure virtual method,
|
||||
* @ref append(), which is called exclusively by the @ref Bus when a message is
|
||||
* dispatched to this node.
|
||||
*
|
||||
* The @ref Bus is declared as a friend class to allow it to invoke @ref append()
|
||||
* without exposing it to the rest of the codebase, enforcing a strict
|
||||
* encapsulation of the message delivery mechanism.
|
||||
*
|
||||
* @note INode is non-copyable and non-movable.
|
||||
* @note Direct instantiation is not possible - this class must be subclassed.
|
||||
* The concrete implementation is provided by @ref Node.
|
||||
*
|
||||
* @see Bus
|
||||
* @see Node
|
||||
* @see Message
|
||||
*/
|
||||
class INode
|
||||
{
|
||||
friend class Bus; ///< Allow the Bus class to access private members
|
||||
|
||||
public:
|
||||
///@name Construction & Destruction
|
||||
///@{
|
||||
|
||||
/**
|
||||
* @brief Default constructor.
|
||||
*/
|
||||
INode() = default;
|
||||
|
||||
/**
|
||||
* @brief Default destructor.
|
||||
*/
|
||||
virtual ~INode() = default;
|
||||
|
||||
/**
|
||||
* @brief Copy constructor - deleted.
|
||||
*
|
||||
* INode is non-copyable.
|
||||
*/
|
||||
INode(const INode &obj) = delete;
|
||||
|
||||
/**
|
||||
* @brief Move constructor - deleted.
|
||||
*
|
||||
* INode is non-movable.
|
||||
*/
|
||||
INode(INode &&obj) noexcept = delete;
|
||||
|
||||
/**
|
||||
* @brief Copy assignment operator - deleted.
|
||||
*
|
||||
* INode is non-copyable.
|
||||
*/
|
||||
INode &operator=(const INode &obj) = delete;
|
||||
|
||||
/**
|
||||
* @brief Move assignment operator - deleted.
|
||||
*
|
||||
* INode is non-movable.
|
||||
*/
|
||||
INode &operator=(INode &&obj) noexcept = delete;
|
||||
|
||||
///@}
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Insert a message into the node's internal message queue.
|
||||
*
|
||||
* This method is called exclusively by the @ref Bus when a message matching
|
||||
* this node's subscriptions (or a broadcast message) is dispatched.
|
||||
* It must be implemented by all concrete subclasses to define how incoming
|
||||
* messages are stored or processed.
|
||||
*
|
||||
* @param message Shared pointer to the message being delivered.
|
||||
*
|
||||
* @note This method is intentionally private and only accessible to @ref Bus
|
||||
* via the friend declaration, preventing external code from injecting
|
||||
* messages directly into a node.
|
||||
*/
|
||||
virtual void append(const std::shared_ptr<Message> &message) = 0;
|
||||
};
|
||||
//--------------------------------------------------------------
|
||||
} // namespace sdi_toolBox::desktop::eventBus
|
||||
195
sdi_toolBox_2.x.x/toolBox/sdi_toolBox/desktop/eventBus/message.h
Normal file
195
sdi_toolBox_2.x.x/toolBox/sdi_toolBox/desktop/eventBus/message.h
Normal file
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
Copyright (c) 2026 - SD-Innovation S.A.S. - FRANCE
|
||||
*/
|
||||
|
||||
/*
|
||||
ver: 2.x.x - build: 2026-04-28
|
||||
*/
|
||||
|
||||
/*
|
||||
The zlib License
|
||||
|
||||
Copyright (c) 2026 SD-Innovation S.A.S.
|
||||
|
||||
This software is provided ‘as-is’, without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "defs.h"
|
||||
|
||||
namespace sdi_toolBox::desktop::eventBus
|
||||
{
|
||||
//--------------------------------------------------------------
|
||||
/**
|
||||
* @class Message
|
||||
* @brief Base class for all messages dispatched through the event bus.
|
||||
*
|
||||
* Every message circulating in the event bus system must derive from this class.
|
||||
* It carries a unique message type identifier (@ref MessageTypeID) used by the
|
||||
* @ref Bus to route the message to the appropriate subscribers, and a timestamp
|
||||
* that is updated when the message is posted to the bus.
|
||||
*
|
||||
* @note The Message class is non-copyable and non-movable.
|
||||
* @note The default constructor is deleted: a @ref MessageTypeID must always
|
||||
* be provided at construction time.
|
||||
* @note The timestamp is set by the @ref Bus internally when @ref Bus::post()
|
||||
* is called; it is not set at construction time.
|
||||
*
|
||||
* @par Example - defining a custom message:
|
||||
* @code
|
||||
* static constexpr sdi_toolBox::desktop::eventBus::MessageTypeID MY_EVENT = 1;
|
||||
*
|
||||
* struct MyMessage : public sdi_toolBox::desktop::eventBus::Message
|
||||
* {
|
||||
* explicit MyMessage(int value)
|
||||
* : Message(MY_EVENT)
|
||||
* , payload(value)
|
||||
* {}
|
||||
* int payload{};
|
||||
* };
|
||||
* @endcode
|
||||
*
|
||||
* @see Bus
|
||||
* @see MessageTypeID
|
||||
* @see TimePoint
|
||||
*/
|
||||
class Message
|
||||
{
|
||||
friend class Bus; ///< Allow the Bus class to access private members
|
||||
|
||||
public:
|
||||
///@name Construction & Destruction
|
||||
///@{
|
||||
|
||||
/**
|
||||
* @brief Default constructor - deleted.
|
||||
*
|
||||
* A @ref MessageTypeID must always be provided at construction time.
|
||||
*/
|
||||
Message() = delete;
|
||||
|
||||
/**
|
||||
* @brief Default destructor.
|
||||
*/
|
||||
virtual ~Message() = default;
|
||||
|
||||
/**
|
||||
* @brief Copy constructor - deleted.
|
||||
*
|
||||
* Message is non-copyable.
|
||||
*/
|
||||
Message(const Message &obj) = delete;
|
||||
|
||||
/**
|
||||
* @brief Move constructor - deleted.
|
||||
*
|
||||
* Message is non-movable.
|
||||
*/
|
||||
Message(Message &&obj) noexcept = delete;
|
||||
|
||||
/**
|
||||
* @brief Copy assignment operator - deleted.
|
||||
*
|
||||
* Message is non-copyable.
|
||||
*/
|
||||
Message &operator=(const Message &obj) = delete;
|
||||
|
||||
/**
|
||||
* @brief Move assignment operator - deleted.
|
||||
*
|
||||
* Message is non-movable.
|
||||
*/
|
||||
Message &operator=(Message &&obj) noexcept = delete;
|
||||
|
||||
/**
|
||||
* @brief Construct a message with the given type identifier.
|
||||
*
|
||||
* @param messageTypeID Unique identifier representing the type of this message.
|
||||
* Used by the @ref Bus to route the message to the correct
|
||||
* subscribers.
|
||||
*/
|
||||
explicit Message(MessageTypeID messageTypeID);
|
||||
|
||||
///@}
|
||||
///@name Accessors
|
||||
///@{
|
||||
|
||||
/**
|
||||
* @brief Get the unique type identifier of this message.
|
||||
*
|
||||
* @return The @ref MessageTypeID assigned at construction time.
|
||||
*/
|
||||
[[nodiscard]] MessageTypeID getMessageTypeID() const;
|
||||
|
||||
/**
|
||||
* @brief Get the timestamp of when this message was posted to the bus.
|
||||
*
|
||||
* The timestamp is recorded by the @ref Bus when @ref Bus::post() is called.
|
||||
* It is left at its default-constructed (zero) value if the message has not
|
||||
* yet been posted.
|
||||
*
|
||||
* @return A @ref TimePoint representing the moment the message was dispatched.
|
||||
* @see Bus::post()
|
||||
*/
|
||||
[[nodiscard]] TimePoint getTimestamp() const;
|
||||
|
||||
///@}
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Update the message timestamp to the current time.
|
||||
*
|
||||
* Called internally by @ref Bus::post() just before the message is dispatched
|
||||
* to subscribers. Not accessible from outside the bus.
|
||||
*/
|
||||
void updateTimestamp();
|
||||
|
||||
MessageTypeID m_messageTypeID; ///< Unique identifier for the message type
|
||||
TimePoint m_messagePostTimestamp{}; ///< Timestamp of when the message was posted to the bus
|
||||
};
|
||||
//--------------------------------------------------------------
|
||||
|
||||
//--------------------------------------------------------------
|
||||
/* Constructor */
|
||||
inline Message::Message(const MessageTypeID messageTypeID)
|
||||
{
|
||||
m_messageTypeID = messageTypeID;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Get the unique identifier for the message type */
|
||||
inline MessageTypeID Message::getMessageTypeID() const
|
||||
{
|
||||
return m_messageTypeID;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Get the timestamp of when the message was posted to the bus */
|
||||
inline TimePoint Message::getTimestamp() const
|
||||
{
|
||||
return m_messagePostTimestamp;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Update the timestamp of when the message was posted to the bus */
|
||||
inline void Message::updateTimestamp()
|
||||
{
|
||||
m_messagePostTimestamp = std::chrono::steady_clock::now();
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
} // namespace sdi_toolBox::desktop::eventBus
|
||||
390
sdi_toolBox_2.x.x/toolBox/sdi_toolBox/desktop/eventBus/node.h
Normal file
390
sdi_toolBox_2.x.x/toolBox/sdi_toolBox/desktop/eventBus/node.h
Normal file
@@ -0,0 +1,390 @@
|
||||
/*
|
||||
Copyright (c) 2026 - SD-Innovation S.A.S. - FRANCE
|
||||
*/
|
||||
|
||||
/*
|
||||
ver: 2.x.x - build: 2026-04-28
|
||||
*/
|
||||
|
||||
/*
|
||||
The zlib License
|
||||
|
||||
Copyright (c) 2026 SD-Innovation S.A.S.
|
||||
|
||||
This software is provided ‘as-is’, without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "bus.h"
|
||||
#include "inode.h"
|
||||
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
|
||||
namespace sdi_toolBox::desktop::eventBus
|
||||
{
|
||||
//--------------------------------------------------------------
|
||||
/**
|
||||
* @class Node
|
||||
* @brief Concrete subscriber node in the event bus system.
|
||||
*
|
||||
* Node is the concrete implementation of @ref INode. It represents a participant
|
||||
* in the event bus that can subscribe to specific message types or to broadcast
|
||||
* mode, emit and post messages through the bus, and consume received messages
|
||||
* from its internal FIFO queue.
|
||||
*
|
||||
* Each Node holds a reference to the @ref Bus it belongs to. Subscriptions and
|
||||
* message transmissions are delegated to the bus. Incoming messages are stored
|
||||
* in an internal thread-safe queue and can be retrieved via @ref popMessage().
|
||||
*
|
||||
* The Node also supports synchronous waiting: a thread can block on
|
||||
* @ref syncWaitForMessage() until at least one message is available in the queue.
|
||||
*
|
||||
* On destruction, the Node automatically unsubscribes from all event types and
|
||||
* broadcast mode, preventing dangling pointers in the bus routing table.
|
||||
*
|
||||
* @note Node is non-copyable and non-movable.
|
||||
* @note A @ref Bus reference must be provided at construction time.
|
||||
* @note The Node does not take ownership of the @ref Bus.
|
||||
*
|
||||
* @par Example usage:
|
||||
* @code
|
||||
* sdi_toolBox::desktop::eventBus::Bus bus;
|
||||
* sdi_toolBox::desktop::eventBus::Node node(bus);
|
||||
*
|
||||
* node.subscribe(MY_EVENT_TYPE);
|
||||
* node.emit<MyMessage>(42);
|
||||
*
|
||||
* node.syncWaitForMessage();
|
||||
* auto msg = std::dynamic_pointer_cast<MyMessage>(node.popMessage());
|
||||
* @endcode
|
||||
*
|
||||
* @see Bus
|
||||
* @see INode
|
||||
* @see Message
|
||||
*/
|
||||
class Node : public INode
|
||||
{
|
||||
public:
|
||||
///@name Construction & Destruction
|
||||
///@{
|
||||
|
||||
Node() = delete; ///< Default constructor - deleted. A @ref Bus reference must be provided.
|
||||
|
||||
/**
|
||||
* @brief Destructor.
|
||||
*
|
||||
* Automatically unsubscribes the node from all specific event types and
|
||||
* broadcast mode via @ref unsubscribeFromAll(), preventing dangling pointers
|
||||
* in the bus routing table. Also notifies any thread blocked in
|
||||
* @ref syncWaitForMessage() to unblock it gracefully.
|
||||
*/
|
||||
virtual ~Node();
|
||||
|
||||
/**
|
||||
* @brief Copy constructor - deleted.
|
||||
*
|
||||
* Node is non-copyable.
|
||||
*/
|
||||
Node(const Node &obj) = delete;
|
||||
|
||||
/**
|
||||
* @brief Move constructor - deleted.
|
||||
*
|
||||
* Node is non-movable.
|
||||
*/
|
||||
Node(Node &&obj) noexcept = delete;
|
||||
|
||||
/**
|
||||
* @brief Copy assignment operator - deleted.
|
||||
*
|
||||
* Node is non-copyable.
|
||||
*/
|
||||
Node &operator=(const Node &obj) = delete;
|
||||
|
||||
/**
|
||||
* @brief Move assignment operator - deleted.
|
||||
*
|
||||
* Node is non-movable.
|
||||
*/
|
||||
Node &operator=(Node &&obj) noexcept = delete;
|
||||
|
||||
/**
|
||||
* @brief Construct a Node attached to the given @ref Bus.
|
||||
*
|
||||
* @param bus Reference to the @ref Bus this node belongs to.
|
||||
* The bus must outlive the node.
|
||||
*/
|
||||
explicit Node(Bus &bus);
|
||||
|
||||
///@}
|
||||
///@name Synchronization
|
||||
///@{
|
||||
|
||||
/**
|
||||
* @brief Block the calling thread until a message is received.
|
||||
*
|
||||
* Suspends the calling thread using an atomic wait until at least one message
|
||||
* has been appended to the node's internal queue by the @ref Bus. This method
|
||||
* is intended for synchronous event-driven patterns where a thread should idle
|
||||
* until work is available.
|
||||
*
|
||||
* @note Returns immediately if a message is already pending in the queue
|
||||
* at the time of the call.
|
||||
* @note If the Node is destroyed while a thread is blocked here, the destructor
|
||||
* triggers a notification to unblock the waiting thread gracefully.
|
||||
* @warning The caller is responsible for checking the queue after this call
|
||||
* returns, as the notification may also be triggered by the destructor
|
||||
* with an empty queue.
|
||||
*/
|
||||
void syncWaitForMessage();
|
||||
|
||||
///@}
|
||||
///@name Subscription Management
|
||||
///@{
|
||||
|
||||
/**
|
||||
* @brief Subscribe this node to a specific message type.
|
||||
*
|
||||
* Delegates to @ref Bus::subscribe(). The node will receive all messages
|
||||
* of the given type posted to the bus. Duplicate subscriptions are ignored.
|
||||
*
|
||||
* @param eventType The message type identifier to subscribe to.
|
||||
* @see Bus::subscribe()
|
||||
*/
|
||||
void subscribe(MessageTypeID eventType);
|
||||
|
||||
/**
|
||||
* @brief Unsubscribe this node from a specific message type.
|
||||
*
|
||||
* Delegates to @ref Bus::unsubscribe(). If the node was not subscribed
|
||||
* to the given type, this call has no effect.
|
||||
*
|
||||
* @param eventType The message type identifier to unsubscribe from.
|
||||
* @see Bus::unsubscribe()
|
||||
*/
|
||||
void unsubscribe(MessageTypeID eventType);
|
||||
|
||||
/**
|
||||
* @brief Unsubscribe this node from all message types and broadcast mode.
|
||||
*
|
||||
* Delegates to @ref Bus::unsubscribeFromAll(). After this call, the node
|
||||
* will no longer receive any messages until it re-subscribes.
|
||||
*
|
||||
* @see Bus::unsubscribeFromAll()
|
||||
*/
|
||||
void unsubscribeFromAll();
|
||||
|
||||
///@}
|
||||
///@name Message Transmission
|
||||
///@{
|
||||
|
||||
/**
|
||||
* @brief Construct and emit a message of type @p T through the bus.
|
||||
*
|
||||
* Forwards the call to @ref Bus::emit(). Creates a new message of type @p T
|
||||
* using the provided arguments and posts it to the bus.
|
||||
*
|
||||
* @tparam T The message type to emit. Must be derived from @ref Message.
|
||||
* @tparam Args Constructor argument types for @p T.
|
||||
* @param args Arguments forwarded to the constructor of @p T.
|
||||
* @return @c true if at least one subscriber received the message,
|
||||
* @c false otherwise.
|
||||
*
|
||||
* @see Bus::emit()
|
||||
*/
|
||||
template<class T, class... Args>
|
||||
bool emit(Args &&...args);
|
||||
|
||||
/**
|
||||
* @brief Post an already constructed message through the bus.
|
||||
*
|
||||
* Forwards the call to @ref Bus::post().
|
||||
*
|
||||
* @param message Shared pointer to the message to post. Must not be @c nullptr.
|
||||
* @return @c true if at least one subscriber received the message,
|
||||
* @c false otherwise.
|
||||
*
|
||||
* @see Bus::post()
|
||||
*/
|
||||
bool post(const std::shared_ptr<Message> &message) const;
|
||||
|
||||
/**
|
||||
* @brief Notify the node that a message has been received.
|
||||
*
|
||||
* Sets the atomic waiting flag to @c true and triggers a wake-up for any
|
||||
* thread blocked in @ref syncWaitForMessage(). Has no effect if the flag
|
||||
* is already set.
|
||||
*/
|
||||
void messageNotify();
|
||||
|
||||
///@}
|
||||
///@name Message queue management
|
||||
///@{
|
||||
|
||||
/**
|
||||
* @brief Get the number of messages currently in the node's queue.
|
||||
*
|
||||
* @return The number of pending messages waiting to be consumed.
|
||||
* @note This operation is thread-safe.
|
||||
*/
|
||||
size_t getMessageCount() const;
|
||||
|
||||
/**
|
||||
* @brief Remove and return the front message from the node's queue (FIFO).
|
||||
*
|
||||
* Retrieves the oldest message in the queue and removes it. If the queue
|
||||
* is empty, returns @c nullptr.
|
||||
*
|
||||
* @return A shared pointer to the front @ref Message, or @c nullptr if the
|
||||
* queue is empty.
|
||||
* @note This operation is thread-safe.
|
||||
*/
|
||||
std::shared_ptr<Message> popMessage(); // Pop a message from the node's message queue (remove and return the front message)
|
||||
|
||||
///@}
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Append a message to the node's internal queue.
|
||||
*
|
||||
* Called exclusively by @ref Bus when dispatching a message to this node.
|
||||
* Pushes the message onto the queue and notifies any thread waiting in
|
||||
* @ref syncWaitForMessage().
|
||||
*
|
||||
* @param message Shared pointer to the message being delivered.
|
||||
*/
|
||||
void append(const std::shared_ptr<Message> &message) override;
|
||||
|
||||
Bus &m_bus; ///< Reference to the event bus
|
||||
std::atomic_bool m_nodeWaitingFlag{ false }; ///< Flag to indicate if the node is waiting for a message (used for synchronous waiting)
|
||||
|
||||
/// @brief Internal message queue, protected by a mutex for thread-safe access.
|
||||
struct
|
||||
{
|
||||
mutable std::mutex mtx; ///< Mutex for thread-safe access to the message queue
|
||||
std::queue<std::shared_ptr<Message>> messageQueue; ///< Queue of messages received by the node
|
||||
} m_busMessages;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------
|
||||
/* Constructor */
|
||||
inline Node::Node(Bus &bus)
|
||||
: m_bus(bus)
|
||||
{
|
||||
// Nothing to do here
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Default destructor */
|
||||
inline Node::~Node()
|
||||
{
|
||||
// Unsubscribe from all event types when the node is destroyed
|
||||
unsubscribeFromAll();
|
||||
|
||||
// Notify the bus that the node is being destroyed (in case it is waiting for a message)
|
||||
messageNotify();
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Synchronously wait for a message to be posted to the bus and received by the node (block the calling thread until a message is received) */
|
||||
inline void Node::syncWaitForMessage()
|
||||
{
|
||||
// Wait until at least one message is received in the node's
|
||||
// message queue
|
||||
m_nodeWaitingFlag = false;
|
||||
m_nodeWaitingFlag.wait(false);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Subscribe to receive messages of a specific event type */
|
||||
inline void Node::subscribe(const MessageTypeID eventType)
|
||||
{
|
||||
m_bus.subscribe(this, eventType);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Unsubscribe from receiving messages of a specific event type */
|
||||
inline void Node::unsubscribe(const MessageTypeID eventType)
|
||||
{
|
||||
m_bus.unsubscribe(this, eventType);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Unsubscribe from receiving messages of all event types */
|
||||
inline void Node::unsubscribeFromAll()
|
||||
{
|
||||
m_bus.unsubscribeFromAll(this);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Emit a message of type T with the given arguments (create a message and post it to the bus) */
|
||||
template<class T, class... Args>
|
||||
bool Node::emit(Args &&...args)
|
||||
{
|
||||
return m_bus.emit<T>(std::forward<Args>(args)...);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Post a message to the bus */
|
||||
inline bool Node::post(const std::shared_ptr<Message> &message) const
|
||||
{
|
||||
return m_bus.post(message);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Get the number of messages in the node's message queue */
|
||||
inline size_t Node::getMessageCount() const
|
||||
{
|
||||
std::scoped_lock lock(m_busMessages.mtx);
|
||||
|
||||
return m_busMessages.messageQueue.size();
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Pop a message from the node's message queue (remove and return the front message) */
|
||||
inline std::shared_ptr<Message> Node::popMessage()
|
||||
{
|
||||
std::scoped_lock lock(m_busMessages.mtx);
|
||||
|
||||
if (m_busMessages.messageQueue.empty())
|
||||
return nullptr; // No messages in the queue
|
||||
|
||||
auto message = m_busMessages.messageQueue.front(); // Get the front message
|
||||
m_busMessages.messageQueue.pop(); // Remove the front message from the queue
|
||||
|
||||
return message; // Return the popped message
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Insert a message into the node's message queue (called by the bus when a message is posted to the bus) */
|
||||
inline void Node::append(const std::shared_ptr<Message> &message)
|
||||
{
|
||||
std::scoped_lock lock(m_busMessages.mtx);
|
||||
|
||||
m_busMessages.messageQueue.push(message);
|
||||
|
||||
// If the node is waiting for a message, notify it that a
|
||||
// message has been received
|
||||
messageNotify();
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Notify the node that a message has been received (used for synchronous waiting) */
|
||||
inline void Node::messageNotify()
|
||||
{
|
||||
if (!m_nodeWaitingFlag.load())
|
||||
{
|
||||
m_nodeWaitingFlag = true;
|
||||
m_nodeWaitingFlag.notify_one();
|
||||
}
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
} // namespace sdi_toolBox::desktop::eventBus
|
||||
Reference in New Issue
Block a user