diff --git a/include/rosa/agent/History.hpp b/include/rosa/agent/History.hpp index 9c7c0ea..7373bad 100644 --- a/include/rosa/agent/History.hpp +++ b/include/rosa/agent/History.hpp @@ -1,292 +1,292 @@ //===-- rosa/agent/History.hpp ----------------------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file rosa/agent/History.hpp /// /// \author David Juhasz (david.juhasz@tuwien.ac.at) /// /// \date 2017 /// /// \brief Definition of *history* *functionality*. /// //===----------------------------------------------------------------------===// #ifndef ROSA_AGENT_HISTORY_HPP #define ROSA_AGENT_HISTORY_HPP #include "rosa/agent/Module.h" #include "rosa/config/config.h" #include "rosa/support/debug.hpp" #include "rosa/support/type_helper.hpp" #include namespace rosa { namespace agent { /// Retention policies defining what a \c rosa::agent::History instance should /// do when the number of recorded entries reached its capacity. enum class HistoryPolicy { SRWF, ///< Stop Recording When Full -- no new entry is recorded when full FIFO ///< First In First Out -- overwrite the earliest entry with a new one }; /// Implements *history* by recording and storing values. /// /// \note Not thread-safe implementation, which should not be a problem as any /// instance of \c rosa::agent::Module is an internal component of a /// \c rosa::Agent, which is the basic unit of concurrency. /// /// \tparam T type of values to store /// \tparam N number of values to store at most /// \tparam P retention policy to follow when capacity is reached /// /// \invariant The size of the underlying \c std::array is `N + 1`:\code /// max_size() == N + 1 && N == max_size() - 1 /// \endcode template class History : public Module, private std::array { // Bring into scope inherited functions that are used. using std::array::max_size; using std::array::operator[]; /// The index of the first data element in the circular buffer. size_t Data; /// The index of the first empty slot in the circular buffer. size_t Space; public: /// Creates an instances by initializing the indices for the circular buffer. History(void) noexcept : Data(0), Space(0) {} /// Destroys \p this object. ~History(void) = default; /// Tells the retention policy applied to \p this object. /// /// \return \c rosa::agent::History::P static constexpr HistoryPolicy policyOfHistory(void) noexcept { return P; } /// Tells how many entries may be recorded by \c this object. /// /// \note The number of entries that are actually recorded may be smaller. /// /// \return \c rosa::agent::History::N static constexpr size_t lengthOfHistory(void) noexcept { return N; } /// Tells how many entries are currently recorded by \p this object. /// /// \return number of entries currently recorded by \p this object. /// /// \post The returned value cannot be larger than the capacity of \p this /// object:\code /// 0 <= numberOfEntries() && numberOfEntries <= lengthOfHistory() /// \endcode - inline size_t numberOfEntries(void) const noexcept { + size_t numberOfEntries(void) const noexcept { return Data <= Space ? Space - Data : max_size() - Data + Space; } /// Tells if \p this object has not recorded anything yet. /// /// \return if \p this object has no entries recorded - inline bool empty(void) const noexcept { return numberOfEntries() == 0; } + bool empty(void) const noexcept { return numberOfEntries() == 0; } /// Gives a constant lvalue reference to an entry stored in \p this object. /// /// \note The recorded entries are indexed starting from the latest one. /// /// \param I the index at which the stored entry to take from /// /// \pre \p I is a valid index:\code /// 0 <= I && I <= numberOfEntries() /// \endcode const T &entry(const size_t I = 0) const noexcept { ASSERT(0 <= I && I < numberOfEntries()); // Boundary check. // Position counted back from the last recorded entry. typename std::make_signed::type Pos = Space - (1 + I); // Actual index wrapped around to the end of the buffer if negative. return (*this)[Pos >= 0 ? Pos : max_size() + Pos]; } private: /// Tells if the circular buffer is full. /// /// \return if the circular buffer is full. - inline bool full(void) const noexcept { return numberOfEntries() == N; } + bool full(void) const noexcept { return numberOfEntries() == N; } /// Pushes a new entry into the circular buffer. /// /// \note The earliest entry gets overwritten if the buffer is full. /// /// \param V value to push into the buffer void pushBack(const T &V) noexcept { // Store value to the first empty slot and step Space index. (*this)[Space] = V; Space = (Space + 1) % max_size(); if (Data == Space) { // Buffer was full, step Data index. Data = (Data + 1) % max_size(); } } public: /// Adds a new entry to \p this object and tells if the operation was /// successful. /// /// \note Success of the operation depends on the actual policy. /// /// \param V value to store /// /// \return if \p V was successfully stored bool addEntry(const T &V) noexcept { switch (P) { default: ROSA_CRITICAL("unkown HistoryPolicy"); case HistoryPolicy::SRWF: if (full()) { return false; } // \note Fall through to FIFO which unconditionally pushes the new entry. case HistoryPolicy::FIFO: // FIFO and SRWF not full. pushBack(V); return true; } } /// Tells the trend set by the entries recorded by \p this object. /// /// The number of steps to go back when calculating the trend is defined as /// argument to the function. /// /// \note The number of steps that can be made is limited by the number of /// entries recorded by \p this object. /// /// \note The function is made a template only to be able to use /// \c std::enable_if. /// /// \tparam X always use the default! /// /// \param D number of steps to go back in *history* /// /// \return trend set by analyzed entries /// /// \pre Statically, \p this object stores signed arithmetic values:\code /// std::is_arithmetic::value && std::is_signed::value /// \endcode Dynamically, \p D is a valid number of steps to take:\code /// 0 <= D && D < N /// \endcode template typename std::enable_if< std::is_arithmetic::value && std::is_signed::value, X>::type trend(const size_t D = N - 1) const noexcept { STATIC_ASSERT((std::is_same::value), "not default template arg"); ASSERT(0 <= D && D < N); // Boundary check. if (numberOfEntries() < 2 || D < 1) { // No entries for computing trend. return {}; // Zero element of \p T } else { // Here at least two entries. // \c S is the number of steps that can be done. const size_t S = std::min(numberOfEntries() - 1, D); size_t I = S; // Compute trend with linear regression. size_t SumIndices = 0; T SumEntries = {}; T SumSquareEntries = {}; T SumProduct = {}; while (I > 0) { // \note Indexing for the regression starts in the past. const size_t Index = S - I; const T Entry = entry(--I); SumIndices += Index; SumEntries += Entry; SumSquareEntries += Entry * Entry; SumProduct += Entry * Index; } return (SumProduct * S - SumEntries * SumIndices) / (SumSquareEntries * S - SumEntries * SumEntries); } } /// Tells the average absolute difference between consequtive entries recorded /// by \p this object /// The number of steps to go back when calculating the average is defined as /// argument to the function. /// /// \note The number of steps that can be made is limited by the number of /// entries recorded by \p this object. /// /// \note The function is made a template only to be able to use /// \c std::enable_if. /// /// \tparam X always use the default! /// /// \param D number of steps to go back in *history* /// /// \pre Statically, \p this object stores arithmetic values:\code /// std::is_arithmetic::value /// \endcode Dynamically, \p D is a valid number of steps to take:\code /// 0 <= D && D < N /// \endcode template typename std::enable_if::value, unsigned_t>::type averageAbsDiff(const size_t D = N - 1) const noexcept { STATIC_ASSERT((std::is_same::value), "not default template arg"); ASSERT(0 <= D && D < N); // Boundary check. if (numberOfEntries() < 2 || D < 1) { // No difference to average. return {}; // Zero element of \p T } else { // Here at least two entries. // \c S is the number of steps that can be done. const size_t S = std::min(numberOfEntries() - 1, D); // Sum up differences as non-negative values only, hence using an // unsigned variable for that. unsigned_t Diffs = {}; // Init to zero. // Count down entry indices and sum up all the absolute differences. size_t I = S; T Last = entry(I); while (I > 0) { T Next = entry(--I); Diffs += Last < Next ? Next - Last : Last - Next; Last = Next; } // Return the average of the summed differences. return Diffs / S; } } }; /// Adds a new entry to a \c rosa::agent::History instance. /// /// \note The result of \c rosa::agent::History::addEntry is ignored. /// /// \tparam T type of values stored in \p H /// \tparam N number of values \p H is able to store /// \tparam P retention policy followed by \p H when capacity is reached /// /// \param H to add a new entry to /// \param V value to add to \p H /// /// \return \p H after adding \p V to it template History &operator<<(History &H, const T &V) noexcept { H.addEntry(V); return H; } } // End namespace agent } // End namespace rosa #endif // ROSA_AGENT_HISTORY_HPP diff --git a/include/rosa/core/MessageMatcher.hpp b/include/rosa/core/MessageMatcher.hpp index 0b79096..1b4e549 100644 --- a/include/rosa/core/MessageMatcher.hpp +++ b/include/rosa/core/MessageMatcher.hpp @@ -1,201 +1,201 @@ //===-- rosa/core/MessageMatcher.hpp ----------------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file rosa/core/MessageMatcher.hpp /// /// \author David Juhasz (david.juhasz@tuwien.ac.at) /// /// \date 2017 /// /// \brief Facilities for checking and matching types of values stored in /// \c rosa::Message instances. /// //===----------------------------------------------------------------------===// #ifndef ROSA_CORE_MESSAGEMATCHER_HPP #define ROSA_CORE_MESSAGEMATCHER_HPP #include "rosa/core/Message.hpp" #include namespace rosa { /// Provides features to type-check a \c rosa::Message instance and extract /// stored values from it into an \c std::tuple instance with matching type /// arguments. /// /// \tparam List \c rosa::TypeList to check the stored values against template struct MessageMatcher; /// Definition of \c rosa::MessageMatcher for non-empty lists of types, like /// \c rosa::Message itself. /// /// \tparam Type first mandatory type /// \tparam Types any further types template struct MessageMatcher> { /// \c rosa::Token associated to the given \c rosa::TypeList. static constexpr Token T = TypeToken::Value; /// Tells if the values stored in a \c rosa::Message instance are matching /// types given as \c rosa::TypeList, considering /// \c rosa::AtomConstant instead of \c rosa::AtomValue. /// /// \param Msg \c rosa::Message to match /// /// \return whether the types of values stored in \p Msg matches /// \c rosa::TypeList static inline bool doesStronglyMatch(const Message &Msg) noexcept; /// Gives a \c std::tuple with references to the values stored in a /// type-matching instance of \c rosa::Message. /// /// \param Msg \c rosa::Message to extract values from /// /// \return \c std::tuple with references to the values stored in \p Msg /// /// \pre Types of the values stored in \p Msg matches /// \c rosa::TypeList:\code /// doesStronglyMatch(Msg) /// \endcode static inline std::tuple extractedValues(const Message &Msg) noexcept; }; /// Turns a list of types into a \c rosa::TypeList for \c rosa::MessageMatcher. template using MsgMatcher = MessageMatcher>; /// Nested namespace with implementation for features of /// \c rosa::MessageMatcher, consider it private. namespace { /// \defgroup MessageMatcherImpl /// /// An implementation of type-checking and value extraction for /// \c rosa::MessageMatcher. /// ///@{ /// Template declaration of \c MessageMatcherImpl. /// /// \tparam List \c rosa::TypeList to match against template struct MessageMatcherImpl; /// Specialization for \c rosa::EmptyTypeList. template <> struct MessageMatcherImpl { - static inline bool doesStronglyMatchFrom(const Message &Msg, - const size_t Pos) noexcept { + static bool doesStronglyMatchFrom(const Message &Msg, + const size_t Pos) noexcept { // Matching EmptyTypeList only if reached the end of the stored types. return Pos == Msg.Size; } - static inline std::tuple<> extractedValuesFrom(const Message &Msg, - const size_t Pos) noexcept { + static std::tuple<> extractedValuesFrom(const Message &Msg, + const size_t Pos) noexcept { // It is valid to extract an empty list only if we reached the end of // stored values. ASSERT(doesStronglyMatchFrom(Msg, Pos)); return std::tie(); } }; /// Specialization for \c rosa::AtomValue in the head. template struct MessageMatcherImpl, Ts...>> { - static inline bool doesHeadStronglyMatchAt(const Message &Msg, - const size_t Pos) noexcept { + static bool doesHeadStronglyMatchAt(const Message &Msg, + const size_t Pos) noexcept { // Matching a \c rosa::AtomConstant in the head if there is a type stored at // \p Pos, the stored type is \c rosa::AtomValue, and the corresponding // value matches the \c rosa::AtomValue \p V. return Pos < Msg.Size && Msg.isTypeAt(Pos) && Msg.valueAt(Pos) == V; } - static inline bool doesStronglyMatchFrom(const Message &Msg, - const size_t Pos) noexcept { + static bool doesStronglyMatchFrom(const Message &Msg, + const size_t Pos) noexcept { // Matching a non-empty list if the head is matching and the rest of the // list is matching. return doesHeadStronglyMatchAt(Msg, Pos) && MessageMatcherImpl>::doesStronglyMatchFrom(Msg, Pos + 1); } - static inline std::tuple &, const Ts &...> + static std::tuple &, const Ts &...> extractedValuesFrom(const Message &Msg, const size_t Pos) noexcept { // Extracting for a non-empty list with a matching \c rosa::AtomConstant in // the head by getting the encoded \c rosa::AtomConstant and concatenating // it with values extracted for the rest of the list. ASSERT(doesHeadStronglyMatchAt(Msg, Pos)); return std::tuple_cat( std::tie(AtomConstant::Value), MessageMatcherImpl>::extractedValuesFrom(Msg, Pos + 1)); } }; /// Definition for the general case when a regular built-in type (not a /// \c rosa::AtomConstant) is in the head. template struct MessageMatcherImpl> { - static inline bool doesHeadStronglyMatchAt(const Message &Msg, - const size_t Pos) noexcept { + static bool doesHeadStronglyMatchAt(const Message &Msg, + const size_t Pos) noexcept { // Matching the head if there is a type stored at \p Pos, and the stored // type is \p T. return Pos < Msg.Size && Msg.isTypeAt(Pos); } - static inline bool doesStronglyMatchFrom(const Message &Msg, - const size_t Pos) noexcept { + static bool doesStronglyMatchFrom(const Message &Msg, + const size_t Pos) noexcept { // Matching a non-empty list if the head is matching and the rest of the // list is matching. return doesHeadStronglyMatchAt(Msg, Pos) && MessageMatcherImpl>::doesStronglyMatchFrom(Msg, Pos + 1); } - static inline std::tuple + static std::tuple extractedValuesFrom(const Message &Msg, const size_t Pos) noexcept { // Extracting for a non-empty list with a matching head by getting the // value for the head and concatenating it with values extracted for the // rest of the list. ASSERT(doesHeadStronglyMatchAt(Msg, Pos)); return std::tuple_cat( std::tie(Msg.valueAt(Pos)), MessageMatcherImpl>::extractedValuesFrom(Msg, Pos + 1)); } }; ///@} } // End namespace template bool MessageMatcher>::doesStronglyMatch( const Message &Msg) noexcept { // \note Fail quick on \c rosa::MessageMatcher::T, then match against list // with squashed integers the way \c rosa::Token is generated. return T == Msg.T && MessageMatcherImpl>::Type>::doesStronglyMatchFrom(Msg, 0); } template std::tuple MessageMatcher>::extractedValues( const Message &Msg) noexcept { ASSERT(doesStronglyMatch(Msg)); // \note Match against a list with squashed integers as \c rosa::Token is // generated. return MessageMatcherImpl>::Type>::extractedValuesFrom(Msg, 0); } } // End namespace rosa #endif // ROSA_CORE_MESSAGEMATCHER_HPP diff --git a/include/rosa/core/MessagingSystem.hpp b/include/rosa/core/MessagingSystem.hpp index b0bab8b..cb81c44 100644 --- a/include/rosa/core/MessagingSystem.hpp +++ b/include/rosa/core/MessagingSystem.hpp @@ -1,188 +1,186 @@ //===-- rosa/core/MessagingSystem.hpp ---------------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file rosa/core/MessagingSystem.hpp /// /// \author David Juhasz (david.juhasz@tuwien.ac.at) /// /// \date 2017 /// /// \brief Declaration of an interface extending \c rosa::System with messaging. /// //===----------------------------------------------------------------------===// #ifndef ROSA_CORE_MESSAGINGSYSTEM_HPP #define ROSA_CORE_MESSAGINGSYSTEM_HPP #include "rosa/core/AgentHandle.hpp" #include "rosa/core/System.hpp" #include "rosa/support/atom.hpp" namespace rosa { /// Extends the \c rosa::System interface with features to create \c rosa::Agent /// instancess and register \c rosa::Message objects for them. class MessagingSystem : public System { friend class AgentHandle; ///< \c rosa::AgentHandle is our friend. public: /// Returns an object implementing the \c rosa::MessagingSystem interface. /// /// \param Name name of the new instance /// /// \return \c std::unique_ptr for the new instance of /// \c rosa::MessagingSystem static std::unique_ptr createSystem(const std::string &Name) noexcept; private: /// Kind for categorizing \c rosa::Unit instances as *agents*. static constexpr AtomValue AgentKind = atom("agent"); protected: /// Creates a new instance. /// /// \note Protected constructor restricts instantiation for subclasses. MessagingSystem(void) noexcept = default; protected: /// Creates a \c rosa::Agent instance owned by \p this object and returns a /// \c rosa::AgentHandle for it. /// /// \tparam T type of the actual \c rosa::Agent to instantiate /// \tparam Funs types of the functions to instantiate \c rosa::Agent with /// /// \note \c rosa::Agent requires at least one function for its constructor, /// but derived classes may do not need that. That's the reason of allowing /// zero \p Funs for this template function. /// /// \param Name name of the new \c rosa::Unit instance /// \param Fs functions to instantiate \c rosa::Unit with /// /// \pre Statically, \p T is a subclass of \c rosa::Agent:\code /// std::is_base_of::value /// \endcode template AgentHandle createAgent(const std::string &Name, Funs &&... Fs); /// Gives the references \c rosa::Agent instance for a \c rosa::AgentHandle. /// /// \note Intended for derived classes to be able to inspect /// \c rosa::AgentHandle instances. /// /// \param H \c rosa::AgentHandle to take the referenced \c rosa::Agent from /// /// \return reference to the \c rosa::Agent instance from \p H - static inline Agent &unwrapAgent(const AgentHandle &H) noexcept { - return H.A; - } + static Agent &unwrapAgent(const AgentHandle &H) noexcept { return H.A; } /// Gives the owning \c rosa::MessagingSystem of a \c rosa::Agent instance /// for a \c rosa::AgentHandle. /// /// \note Intended for for derived classes to be able to inspect /// \c rosa::AgentHandle instances. /// /// \param H \c rosa::AgentHandle to take the owning /// \c rosa::MessagingSystem from /// /// \return reference to the \c rosa::MessagingSystem owning the /// \c rosa::Agent instance from \p H - static inline MessagingSystem &unwrapSystem(const AgentHandle &H) noexcept { + static MessagingSystem &unwrapSystem(const AgentHandle &H) noexcept { return H.S; } public: /// Sends a \c rosa::message_t instance to the \c rosa::Agent instance /// referred by a \c rosa::AgentHandle. /// /// \note If the given \c rosa::Message object cannot be handled by the /// referred \c rosa::Agent instance, the \c rosa::Message object is simply /// ignored. /// /// \param H refers to the \c rosa::Agent instance to send to /// \param M message to send /// /// \pre The referred \c rosa::Agent instance is owned by \p this object and /// also registered: \code /// &unwrapSystem(H) == this && isUnitRegistered(unwrapAgent(H)) /// \endcode virtual void send(const AgentHandle &H, message_t &&M) noexcept = 0; /// Sends a message -- created from given constant lvalue references -- /// to the \c rosa::Agent instance referred by a \c rosa::AgentHandle. /// /// \note If the given \c rosa::Message object cannot be handled by the /// referred \c rosa::Agent instance, the \c rosa::Message object is simply /// ignored. /// /// \note The message must consists of at least one value. /// /// \tparam Type type of the first mandatory value /// \tparam Types types of any further values /// /// \param H refers to the \c rosa::Agent instance to send to /// \param T the first value to include in the message /// \param Ts optional further values to include in the message /// /// \pre The referred \c rosa::Agent instance is owned by \p this object and /// also registered: \code /// &unwrapSystem(H) == this && isUnitRegistered(unwrapAgent(H)) /// \endcode template void send(const AgentHandle &H, const Type &T, const Types &... Ts) noexcept; /// Sends a message -- created from given rvalue references -- /// to the \c rosa::Agent instance referred by a \c rosa::AgentHandle. /// /// \note If the given \c rosa::Message object cannot be handled by the /// referred \c rosa::Agent instance, the \c rosa::Message object is simply /// ignored. /// /// \note The message must consists of at least one value. /// /// \tparam Type type of the first mandatory value /// \tparam Types types of any further values /// /// \param H refers to the \c rosa::Agent instance to send to /// \param T the first value to include in the message /// \param Ts optional further values to include in the message /// /// \pre The referred \c rosa::Agent instance is owned by \p this object and /// also registered: \code /// &unwrapSystem(H) == this && isUnitRegistered(unwrapAgent(H)) /// \endcode template void send(const AgentHandle &H, Type &&T, Types &&... Ts) noexcept; }; template AgentHandle MessagingSystem::createAgent(const std::string &Name, Funs &&... Fs) { STATIC_ASSERT((std::is_base_of::value), "not an Agent"); Agent &A = createUnit([&](const id_t Id, MessagingSystem &S) noexcept { return new T(AgentKind, Id, Name, S, std::move(Fs)...); }); return {A}; } template void MessagingSystem::send(const AgentHandle &H, const Type &T, const Types &... Ts) noexcept { send(H, Message::create(T, Ts...)); } template void MessagingSystem::send(const AgentHandle &H, Type &&T, Types &&... Ts) noexcept { send(H, Message::create(std::move(T), std::move(Ts)...)); } } // End namespace rosa #endif // ROSA_CORE_MESSAGINGSYSTEM_HPP diff --git a/lib/core/MessagingSystemImpl.hpp b/lib/core/MessagingSystemImpl.hpp index c472216..2370837 100644 --- a/lib/core/MessagingSystemImpl.hpp +++ b/lib/core/MessagingSystemImpl.hpp @@ -1,105 +1,103 @@ //===-- core/MessagingSystemImpl.hpp ----------------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file core/MessagingSystemImpl.hpp /// /// \author David Juhasz (david.juhasz@tuwien.ac.at) /// /// \date 2017 /// /// \brief Declaration of a basic implementation of the \c rosa::MessagingSystem /// interface. /// //===----------------------------------------------------------------------===// #ifndef ROSA_LIB_CORE_MESSAGINGSYSTEMIMPL_HPP #define ROSA_LIB_CORE_MESSAGINGSYSTEMIMPL_HPP #include "SystemImpl.hpp" #include "rosa/core/MessagingSystem.hpp" namespace rosa { /// Implements \c rosa::MessagingSystem by extending \c rosa::SystemImpl with /// adding a simple implementation of sending messages: directly invoking /// \c rosa::Agent instances with given \c rosa::Message objects. /// /// \note Keep in mind that sending a \c rosa::Message object with this /// implementation translates into a direct function call. class MessagingSystemImpl : public MessagingSystem, public SystemImpl { /// Alies for the base-class \c rosa::SystemImpl. using Base = SystemImpl; public: /// Creates an instance. /// /// \param Name name of the new instance MessagingSystemImpl(const std::string &Name) noexcept; protected: /// \defgroup \c rosa::MessagingSystemImpl call forwardings /// /// \note Simply forwarding calls to implementations provided by /// \c rosa::MessagingSystem::Base for the \c rosa::System interface. /// /// \todo How could we use the inherited implementations in a simpler way? ///@{ - inline id_t nextId(void) noexcept override { return Base::nextId(); } + id_t nextId(void) noexcept override { return Base::nextId(); } - inline bool isSystemCleaned(void) const noexcept override { + bool isSystemCleaned(void) const noexcept override { return Base::isSystemCleaned(); } - inline void markCleaned(void) noexcept override { Base::markCleaned(); } + void markCleaned(void) noexcept override { Base::markCleaned(); } - inline void registerUnit(Unit &U) noexcept override { Base::registerUnit(U); } + void registerUnit(Unit &U) noexcept override { Base::registerUnit(U); } - inline void destroyUnit(Unit &U) noexcept override { Base::destroyUnit(U); } + void destroyUnit(Unit &U) noexcept override { Base::destroyUnit(U); } - inline bool isUnitRegistered(const Unit &U) const noexcept override { + bool isUnitRegistered(const Unit &U) const noexcept override { return Base::isUnitRegistered(U); } public: - inline const std::string &name(void) const noexcept override { - return Base::name(); - } + const std::string &name(void) const noexcept override { return Base::name(); } - inline size_t numberOfConstructedUnits(void) const noexcept override { + size_t numberOfConstructedUnits(void) const noexcept override { return Base::numberOfConstructedUnits(); } - inline size_t numberOfLiveUnits(void) const noexcept override { + size_t numberOfLiveUnits(void) const noexcept override { return Base::numberOfLiveUnits(); } - inline bool empty(void) const noexcept override { return Base::empty(); } + bool empty(void) const noexcept override { return Base::empty(); } ///@} /// Sends a \c rosa::message_t instance to the \c rosa::Agent instance /// referred by a \c rosa::AgentHandle -- by directly invoking the /// \c rosa::Agent instance with the \c rosa::Message object. /// /// \note If the given \c rosa::Message object cannot be handled by the /// referred \c rosa::Agent instance, the \c rosa::Message object is simply /// ignored. /// /// \param H refers to the \c rosa::Agent instance to send to /// \param M message to send /// /// \pre The referred \c rosa::Agent instance is owned by \p this object and /// also registered: \code /// &unwrapSystem(H) == this && isUnitRegistered(unwrapAgent(H)) /// \endcode void send(const AgentHandle &H, message_t &&M) noexcept override; }; } // End namespace rosa #endif // ROSA_LIB_CORE_MESSAGINGSYSTEMIMPL_HPP