Page MenuHomePhorge

MessageHandler.hpp
No OneTemporary

Size
5 KB
Referenced Files
None
Subscribers
None

MessageHandler.hpp

/***************************************************************************//**
*
* \file rosa/core/MessageHandler.hpp
*
* \author David Juhasz (david.juhasz@tuwien.ac.at)
*
* \date 2017
*
* \brief Facility for combining `rosa::Invoker` instances and applying
* `rosa::Message` intances to them.
*
******************************************************************************/
#ifndef ROSA_CORE_MESSAGEHANDLER_HPP
#define ROSA_CORE_MESSAGEHANDLER_HPP
#include "rosa/core/Invoker.hpp"
#include "rosa/support/log.h"
#include <vector>
namespace rosa {
/// Handles `rosa::Message` instances.
///
/// A `rosa::MessageHandler` stores `rosa::Invoker` instances and tries to
/// apply `rosa::Message` objects to them in the order of definition.The first
/// matching `rosa::Invoker` instance is invoked with the `rosa::Message`
/// object, after which handling of that `rosa::Message` object is completed.
///
/// For example, consider the following snippet: \code
/// rosa::MessageHandler {
/// rosa::Invoker::F<uint8_t>([](uint8_t) { /* ... */ }),
/// rosa::Invoker::F<uint8_t>([](uint8_t) { /* Never invoked */ })
/// };
/// \endcode
/// Applying a `rosa::Message` with `rosa::TypeList<uint8_t>` invokes the first
/// function, and the second function would never be invoked because any
/// matching `rosa::Message` object had already been handled by the first one.
class MessageHandler {
/// Type alias to bring `rosa::Invoker::invoker_t` to the local scope.
using invoker_t = Invoker::invoker_t;
/// Type alias for a `std::vector` storing `rosa::Invoker` instances.
using invokers_t = std::vector<invoker_t>;
/// Stores `rosa::Invoker` instances.
const invokers_t Invokers;
/// Creates a container with `rosa::Invoker` instances from functions.
///
/// \tparam Fun type of the mandatory first function
/// \tparam Funs types of further functions
///
/// \param F the mandatory first function
/// \param Fs optional further functions
///
/// \return `invokers_t` object storing `rosa::Invoker` instances created
/// from the `F` and `Fs...`
template <typename Fun, typename... Funs>
static inline invokers_t createInvokers(Fun &&F, Funs &&... Fs) noexcept;
/// Updates an `invokers_t` object with a new `rosa::Invoker` instance and
/// handles further functions recursively.
///
/// \tparam Fun type of the first function
/// \tparam Funs types of further functions
///
/// \param I `invokers_t` to update
/// \param Pos index at which to store the new `rosa::Invoker` instance
/// \param F function to wrap and store into `I` at index `Pos`
/// \param Fs further functions to handle later
///
/// \pre `Pos` is a valid index:\code
/// Pos < I.size()
/// \endcode
template <typename Fun, typename... Funs>
static inline void wrapFun(invokers_t &I, const size_t Pos, Fun &&F,
Funs &&... Fs) noexcept;
/// Terminal case for the template `rosa::MessageHandler::wrapFun`.
///
/// \param I `invokers_t` which is now complete
/// \param Pos size of `I`
///
/// \pre `Pos` is the size of `I`:\code
/// Pos == I.size();
/// \endcode
static inline void wrapFun(invokers_t &I, const size_t Pos) noexcept;
public:
/// Creates an instance.
///
/// The constructor stores the given functions into the new
/// `rosa::MessageHandler` instance.
///
/// \tparam Fun type of the mandatory first function
/// \tparam Funs types of further functions
///
/// \param F the first function to store
/// \param Fs optional further functions to store
template<typename Fun, typename... Funs>
MessageHandler(Fun &&F, Funs &&... Fs) noexcept;
/// Destroys `this` object.
virtual ~MessageHandler(void);
/// Tells if a `rosa::Message` object can be handled by `this` object.
///
/// \param Msg `rosa::Message`to check
///
/// \return whether `this` object stores a `rosa::Invoker` instance that can
/// handle `Msg`
bool canHandle(const Message &Msg) const noexcept;
/// Applies a `rosa::Message` object to the first stored `rosa::Invoker` that
/// can handle it, and tells if there was any.
///
/// \note This operator finds the first applicable `rosa::Invoker` and invokes
/// it with the given `rosa::Message` object, while the member function
/// `rosa::MessageHandler::canHandle` only checks if there is any
/// `rosa::Invoker` that can be invoked with `rosa::Message` object.
///
/// \param Msg `rosa::Message` to use in invoking a matching `rosa::Invoker`
///
/// \return whether there was a matching `rosa::Invoker` found and invoked
/// with `Msg`.
bool operator()(const Message &Msg) const noexcept;
};
template <typename Fun, typename... Funs>
MessageHandler::MessageHandler(Fun &&F, Funs &&... Fs) noexcept
: Invokers(createInvokers(std::move(F), std::move(Fs)...)) {
LOG_TRACE("MessageHandler is created");
}
template <typename Fun, typename... Funs>
MessageHandler::invokers_t
MessageHandler::createInvokers(Fun &&F, Funs &&... Fs) noexcept {
// Create a container with the required size and get all the functions
// wrapped.
invokers_t I(1 + sizeof...(Funs));
wrapFun(I, 0, std::move(F), std::move(Fs)...);
return I;
}
template <typename Fun, typename... Funs>
void MessageHandler::wrapFun(invokers_t &I, const size_t Pos, Fun &&F,
Funs &&... Fs) noexcept {
ASSERT(Pos < I.size()); // Sanity check.
// Wrap the current function and continue with the rest.
I[Pos] = Invoker::wrap(std::move(F));
wrapFun(I, Pos + 1, std::move(Fs)...);
}
void MessageHandler::wrapFun(invokers_t &I, const size_t Pos) noexcept {
ASSERT(Pos == I.size()); // Sanity check.
// Nothing to do here.
}
} // End namespace rosa
#endif // ROSA_CORE_MESSAGEHANDLER_HPP

File Metadata

Mime Type
text/x-c++
Expires
Sun, Jul 12, 2:08 PM (1 d, 2 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
328488
Default Alt Text
MessageHandler.hpp (5 KB)

Event Timeline