diff --git a/examples/agent-modules/agent-modules.cpp b/examples/agent-modules/agent-modules.cpp index 4ec7f59..fc0195d 100644 --- a/examples/agent-modules/agent-modules.cpp +++ b/examples/agent-modules/agent-modules.cpp @@ -1,112 +1,112 @@ //===-- examples/agent-modules/agent-modules.cpp ----------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file examples/agent-modules/agent-modules.cpp /// /// \author David Juhasz (david.juhasz@tuwien.ac.at) /// /// \date 2017 /// -/// \brief A simple example on defining `rosa::Agent` instances using -/// `rosa::agent::Module` object as components. +/// \brief A simple example on defining \c rosa::Agent instances using +/// \c rosa::agent::Module object as components. /// //===----------------------------------------------------------------------===// #include "rosa/agent/Abstraction.hpp" #include "rosa/agent/Confidence.hpp" #include "rosa/config/version.h" #include "rosa/core/Agent.hpp" #include "rosa/core/MessagingSystem.hpp" #include "rosa/support/log.h" #include "rosa/support/terminal_colors.h" #include #include using namespace rosa; using namespace rosa::agent; using namespace rosa::terminal; -/// A dummy wrapper for testing `rosa::MessagingSystem`. +/// A dummy wrapper for testing \c rosa::MessagingSystem. /// -/// \note Since we test `rosa::MessagingSystem` directly here, we need to get +/// \note Since we test \c rosa::MessagingSystem directly here, we need to get /// access to its protected members. That we do by imitating to be a decent -/// subclass of `rosa::MessagingSystem`, while calling protected member +/// subclass of \c rosa::MessagingSystem, while calling protected member /// functions on an object of a type from which we actually don't inherit. struct SystemTester : protected MessagingSystem { template static AgentHandle createMyAgent(MessagingSystem *S, const std::string &Name, Funs &&... Fs) { return ((SystemTester *)S)->createAgent(Name, std::move(Fs)...); } static void destroyMyAgent(MessagingSystem *S, const AgentHandle &H) { ((SystemTester *)S)->destroyUnit(unwrapAgent(H)); } }; -/// A special `rosa::Agent` with its own state. +/// A special \c rosa::Agent with its own state. class MyAgent : public Agent { public: using Tick = AtomConstant; private: enum class Categories { Bad, Normal, Good }; static const std::map CategoryNames; History H; Confidence C; RangeAbstraction A; public: void handler(Tick, uint8_t V) noexcept { - // Record V to the History, then print state info. + // Record \p V to the \c rosa::agent::History, then print state info. H << V; ASSERT(H.entry() == V); // Sanity check. LOG_INFO_STREAM << std::endl << "Next value: " << PRINTABLE(V) << ", confidence: " << C(H) << ", category: " << CategoryNames.at(A(H.entry())) << std::endl; } MyAgent(const AtomValue Kind, const rosa::id_t Id, const std::string &Name, MessagingSystem &S) : Agent(Kind, Id, Name, S, THISMEMBER(handler)), H(), C(5, 20, 1), A({{{10, 14}, Categories::Normal}, {{15, 17}, Categories::Good}, {{18, 19}, Categories::Normal}}, Categories::Bad) {} }; const std::map MyAgent::CategoryNames{ {Categories::Bad, "Bad"}, {Categories::Normal, "Normal"}, {Categories::Good, "Good"}}; int main(void) { LOG_INFO_STREAM << library_string() << " -- " << Color::Red << "agent-modules example" << Color::Default << std::endl; std::unique_ptr S = MessagingSystem::createSystem("Sys"); MessagingSystem *SP = S.get(); AgentHandle A = SystemTester::createMyAgent(SP, "MyAgent"); std::vector Vs{4, 5, 6, 7, 9, 10, 11, 13, 15, 14, 15, 16, 19, 20, 21}; for (auto I = Vs.begin(); I != Vs.end(); ++I) { A.send(MyAgent::Tick::Value, *I); } SystemTester::destroyMyAgent(SP, A); return 0; } diff --git a/examples/basic-system/basic-system.cpp b/examples/basic-system/basic-system.cpp index 4074754..d405a5f 100644 --- a/examples/basic-system/basic-system.cpp +++ b/examples/basic-system/basic-system.cpp @@ -1,75 +1,73 @@ //===-- examples/basic-system/basic-system.cpp ------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file examples/basic-system/basic-system.cpp /// /// \author David Juhasz (david.juhasz@tuwien.ac.at) /// /// \date 2017 /// -/// \brief A simple example on the basic `rosa::System` and `rosa::Unit` +/// \brief A simple example on the basic \c rosa::System and \c rosa::Unit /// classes. /// //===----------------------------------------------------------------------===// #include "rosa/config/version.h" #include "rosa/core/Unit.h" #include "rosa/core/System.hpp" #include "rosa/support/log.h" #include "rosa/support/terminal_colors.h" #include using namespace rosa; using namespace rosa::terminal; -/// A dummy wrapper for testing `rosa::MessagingSystem`. +/// A dummy wrapper for testing \c rosa::System. /// -/// \note Since we test `rosa::MessagingSystem` directly here, we need to get -/// access to its protected members. That we do by imitating to be a decent -/// subclass of `rosa::MessagingSystem`, while calling protected member -/// functions on an object of a type from which we actually don't inherit. +/// \note Since we test \c rosa::System directly here, we need to get access to +/// its protected members. That we do by imitating to be a decent subclass of +/// \c rosa::System, while calling protected member functions on an object of a +/// type from which we actually don't inherit. struct SystemTester : protected System { static constexpr AtomValue UnitKind = atom("unit"); static Unit &createMyUnit(System *S, const std::string &Name = std::string()) { return ((SystemTester *)S) ->createUnit([&Name](const rosa::id_t Id, System &S) noexcept { - // \note If `Name` is empty, construct a name with the number of the - // `rosa::Unit` instance being created right now. const std::string N( Name.empty() ? "Unit_" + std::to_string(S.numberOfConstructedUnits()) : Name); return new Unit(UnitKind, Id, N, S); }); } static void destroyMyUnit(System *S, Unit &U) { ((SystemTester *)S)->destroyUnit(U); } }; int main(void) { LOG_INFO_STREAM << library_string() << " -- " << Color::Red << "basic-system example" << Color::Default << std::endl; std::unique_ptr S = System::createSystem("Sys"); System *SP = S.get(); Unit &Unit1 = SystemTester::createMyUnit(SP), &Unit2 = SystemTester::createMyUnit(SP, "Second"), &Unit3 = SystemTester::createMyUnit(SP); SystemTester::destroyMyUnit(SP, Unit1); SystemTester::destroyMyUnit(SP, Unit3); LOG_INFO_STREAM << "Dumping Unit2" << std::endl << Unit2 << std::endl; SystemTester::destroyMyUnit(SP, Unit2); return 0; } diff --git a/examples/messaging-system/messaging-system.cpp b/examples/messaging-system/messaging-system.cpp index fe01e79..a26b7cb 100644 --- a/examples/messaging-system/messaging-system.cpp +++ b/examples/messaging-system/messaging-system.cpp @@ -1,148 +1,148 @@ //===-- examples/messaging-system/messaging-system.cpp ----------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file examples/messaging-system/messaging-system.cpp /// /// \author David Juhasz (david.juhasz@tuwien.ac.at) /// /// \date 2017 /// -/// \brief A simple example on the `rosa::MessagingSystem` and `rosa::Agent` +/// \brief A simple example on the \c rosa::MessagingSystem and \c rosa::Agent /// classes. //===----------------------------------------------------------------------===// #include "rosa/config/version.h" #include "rosa/core/Agent.hpp" #include "rosa/core/MessagingSystem.hpp" #include "rosa/support/log.h" #include "rosa/support/terminal_colors.h" #include using namespace rosa; using namespace rosa::terminal; -/// A dummy wrapper for testing `rosa::MessagingSystem`. +/// A dummy wrapper for testing \c rosa::MessagingSystem. /// -/// \note Since we test `rosa::MessagingSystem` directly here, we need to get +/// \note Since we test \c rosa::MessagingSystem directly here, we need to get /// access to its protected members. That we do by imitating to be a decent -/// subclass of `rosa::MessagingSystem`, while calling protected member +/// subclass of \c rosa::MessagingSystem, while calling protected member /// functions on an object of a type from which we actually don't inherit. struct SystemTester : protected MessagingSystem { template static AgentHandle createMyAgent(MessagingSystem *S, const std::string &Name, Funs &&... Fs) { return ((SystemTester *)S)->createAgent(Name, std::move(Fs)...); } static void destroyMyAgent(MessagingSystem *S, const AgentHandle &H) { ((SystemTester *)S)->destroyUnit(unwrapAgent(H)); } }; -/// A special `rosa::Agent` subclass with its own state. +/// A special \c rosa::Agent subclass with its own state. class MyAgent : public Agent { public: using Tick = AtomConstant; using Report = AtomConstant; private: size_t Counter; public: void handler(Tick) noexcept { LOG_INFO_STREAM << "MyAgent Tick count: " << ++Counter << std::endl; } MyAgent(const AtomValue Kind, const rosa::id_t Id, const std::string &Name, MessagingSystem &S) : Agent(Kind, Id, Name, S, Invoker::F([this](Report) noexcept { LOG_INFO_STREAM << "MyAgent count: " << Counter << std::endl; }), THISMEMBER(handler)), Counter(0) {} }; int main(void) { LOG_INFO_STREAM << library_string() << " -- " << Color::Red << "messaging-system example" << Color::Default << std::endl; std::unique_ptr S = MessagingSystem::createSystem("Sys"); MessagingSystem *SP = S.get(); LOG_INFO_STREAM << std::endl << std::endl << "** Stateless Agents" << std::endl << std::endl; AgentHandle Agent1 = SystemTester::createMyAgent( SP, "Agent1", Invoker::F([](const std::string &M) noexcept { LOG_INFO("Agent1: " + M); })); using Print = AtomConstant; using Forward = AtomConstant; AgentHandle Agent2 = SystemTester::createMyAgent( SP, "Agent2", Invoker::F([](Print, uint8_t N) noexcept { LOG_INFO("Agent2: " + std::to_string(N)); }), Invoker::F([&Agent1](Forward, uint8_t N) noexcept { if (Agent1) { Agent1.send(std::to_string(N)); } else { LOG_INFO("Agent2 cannot forward: Agent1 is not valid"); } })); LOG_INFO_STREAM << std::endl << "Agent1 is valid: " << bool(Agent1) << std::endl << "Agent2 is valid: " << bool(Agent2) << std::endl; LOG_INFO("Sending a print-message to Agent2..."); SP->send(Agent2, Print::Value, 42); LOG_INFO("Sending a forward-message to Agent2..."); SP->send(Agent2, Forward::Value, 42); LOG_INFO("Sending an unexpected message to Agent2..."); SP->send(Agent2, unit); SystemTester::destroyMyAgent(SP, Agent1); LOG_INFO_STREAM << std::endl << "Agent1 is valid: " << bool(Agent1) << std::endl << "Agent2 is valid: " << bool(Agent2) << std::endl; LOG_INFO("Sending a forward-message to Agent2..."); SP->send(Agent2, Forward::Value, 42); SystemTester::destroyMyAgent(SP, Agent2); LOG_INFO_STREAM << std::endl << std::endl << "** Stateful Agents" << std::endl << std::endl; AgentHandle Agent3 = SystemTester::createMyAgent(SP, "Agent3"); for (size_t I = 0; I < 2; ++I) { LOG_INFO("Sending report-message to Agent3..."); Agent3.send(MyAgent::Report::Value); LOG_INFO("Sending tick-message to Agent3..."); Agent3.send(MyAgent::Tick::Value); } SystemTester::destroyMyAgent(SP, Agent3); LOG_INFO_STREAM << std::endl << std::endl; return 0; } diff --git a/examples/messaging/messaging.cpp b/examples/messaging/messaging.cpp index 9f34c42..7d83013 100644 --- a/examples/messaging/messaging.cpp +++ b/examples/messaging/messaging.cpp @@ -1,146 +1,146 @@ //===-- examples/messaging/messaging.cpp ------------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file examples/messaging/messaging.cpp /// /// \author David Juhasz (david.juhasz@tuwien.ac.at) /// /// \date 2017 /// -/// \brief An example showcasing features related to the `rosa::Message` class. +/// \brief An example showcasing features related to the \c rosa::Message class. /// //===----------------------------------------------------------------------===// #include "rosa/config/version.h" #include "rosa/core/MessageHandler.hpp" #include "rosa/support/log.h" #include "rosa/support/terminal_colors.h" #include using namespace rosa; using namespace rosa::terminal; int main(void) { LOG_INFO_STREAM << library_string() << " -- " << Color::Red << "messaging" << Color::Default << std::endl; auto &Log = LOG_INFO_STREAM << std::endl; // Message interface. auto PMsg = Message::create(1, 2); auto &Msg = *PMsg; Log << "Checking on a 'Message with TypeList<>':" << std::endl << " Size: " << Msg.Size << std::endl << " Pos 0 is uint8_t: " << Msg.isTypeAt(0) << std::endl << " Pos 1 is uint16_t: " << Msg.isTypeAt(1) << std::endl << " Pos 2 is uint32_t: " << Msg.isTypeAt(1) << std::endl << " Value at pos 0: " << PRINTABLE(Msg.valueAt(0)) << std::endl << " Value at pos 1: " << Msg.valueAt(1) << std::endl << std::endl; // MessageMatcher. using MyMatcher = MsgMatcher; Log << "Matching against 'TypeList':" << std::endl << " matching: " << MyMatcher::doesStronglyMatch(Msg) << std::endl; auto Vs = MyMatcher::extractedValues(Msg); Log << " value: '(" << PRINTABLE(std::get<0>(Vs)) << ", " << std::get<1>(Vs) << ")'" << std::endl << std::endl; using MyWrongMatcher = MsgMatcher; Log << "Matching against 'TypeList':" << std::endl << " matching: " << MyWrongMatcher::doesStronglyMatch(Msg) << std::endl << std::endl; using MyAtom = AtomConstant; const MyAtom &A = MyAtom::Value; using MyNAtom = AtomConstant; auto PAMsg = Message::create(A); auto &AMsg = *PAMsg; Log << "Checking on a 'Message with TypeList>':" << std::endl << " Size: " << AMsg.Size << std::endl << " Pos 0 is 'AtomValue': " << AMsg.isTypeAt(0) << std::endl << " Pos 0 is 'AtomConstant': " << AMsg.isTypeAt(0) << std::endl << std::endl; using MyAtomMatcher = MsgMatcher; Log << "Matching against 'TypeList>':" << std::endl << " matching: " << MyAtomMatcher::doesStronglyMatch(AMsg) << std::endl << " value: '(" << to_string(std::get<0>(MyAtomMatcher::extractedValues(AMsg))) << ")'" << std::endl << std::endl; using MyWrongAtomMatcher = MsgMatcher; Log << "Matching against 'TypeList>':" << std::endl << " matching: " << MyWrongAtomMatcher::doesStronglyMatch(AMsg) << std::endl << std::endl; // Invoker. auto IP = Invoker::wrap(Invoker::F([&Log](MyAtom) noexcept->void { Log << "** Handling 'Message with TypeList>'." << std::endl; })); auto &I = *IP; // Get a reference from the pointer. Log << "Invoking a function of signature 'void(AtomConstant) " "noexcept':" << std::endl << " with 'Message with TypeList'" << std::endl << " does Message match Invoker: " << I.match(Msg) << std::endl << " invoking..." << std::endl; I(Msg); Log << " with 'Message with TypeList>'..." << std::endl << " does Message match Invoker: " << I.match(AMsg) << std::endl << " invoking..." << std::endl; I(AMsg); Log << std::endl; // MessageHandler. MessageHandler Handler{ Invoker::F([&Log](uint8_t, uint16_t) { Log << "** Handling 'Message with TypeList'" << std::endl; }), Invoker::F([&Log](MyAtom) { Log << "** Handling 'Message with " "TypeList>'" << std::endl; })}; auto PANMsg = Message::create(MyNAtom::Value); auto &ANMsg = *PANMsg; Log << "Handling Messages with 'MessageHandler " "{ Invoker::F, " "Invoker::F> }':" << std::endl << " 'Message with TypeList'" << std::endl << " can handle: " << Handler.canHandle(Msg) << std::endl << " handling..." << std::endl; Handler(Msg); Log << " 'Message with TypeList>'" << std::endl << " can handle: " << Handler.canHandle(AMsg) << std::endl << " handling..." << std::endl; Handler(AMsg); Log << " 'Message with TypeList>'" << std::endl << " can handle: " << Handler.canHandle(ANMsg) << std::endl << " handling..." << std::endl; Handler(ANMsg); Log << std::endl; Log << "Terminating, destroying automatic variables." << std::endl; return 0; } diff --git a/examples/type-facilities/type-facilities.cpp b/examples/type-facilities/type-facilities.cpp index a189fed..b3ce553 100644 --- a/examples/type-facilities/type-facilities.cpp +++ b/examples/type-facilities/type-facilities.cpp @@ -1,102 +1,102 @@ //===-- examples/type-facilities/type-facilities.cpp ------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file examples/type-facilities/type-facilities.cpp /// /// \author David Juhasz (david.juhasz@tuwien.ac.at) /// /// \date 2017 /// /// \brief An example showcasing various type-related support facilities. /// //===----------------------------------------------------------------------===// #include "rosa/config/version.h" #include "rosa/support/log.h" #include "rosa/support/terminal_colors.h" #include "rosa/support/type_token.hpp" #include using namespace rosa; using namespace rosa::terminal; int main(void) { LOG_INFO_STREAM << library_string() << " -- " << Color::Red << "type facilities" << Color::Default << std::endl; auto &Log = LOG_TRACE_STREAM << std::endl; Log << "NumberOfBuiltinTypes: " << NumberOfBuiltinTypes << std::endl << "TokenBits: " << token::TokenBits << std::endl << "RepresentationBits: " << token::RepresentationBits << std::endl << "MaxTokenizableListSize: " << token::MaxTokenizableListSize << std::endl << std::endl; Log << "Type number information on 'uint8_t':" << std::endl; constexpr TypeNumber TN = TypeNumberOf::Value; Log << " type number: " << PRINTABLE_TN(TN) << std::endl << " size: " << TypeForNumber::Size << std::endl << " name: " << TypeForNumber::Name << std::endl << std::endl; Log << "Type number information on 'std::string':" << std::endl; constexpr TypeNumber TNS = TypeNumberOf::Value; Log << " type number: " << PRINTABLE_TN(TNS) << std::endl << " size: " << TypeForNumber::Size << std::endl << " name: " << TypeForNumber::Name << std::endl << std::endl; Log << "Type number information of AtomConstants:" << std::endl; using Atom1 = AtomConstant; using Atom2 = AtomConstant; Log << " std::is_same::value: " << std::is_same::value << std::endl << " TypeNumberOf::Value: " << PRINTABLE_TN(TypeNumberOf::Value) << std::endl << " TypeNumberOf::Value: " << PRINTABLE_TN(TypeNumberOf::Value) << std::endl << " name: " << TypeForNumber::Value>::Name << std::endl << std::endl; Log << "Type token information on 'TypeList':" << std::endl; - // Token is generated statically. + // \c rosa::Token is generated statically. constexpr Token T = TypeToken::Value; STATIC_ASSERT( (T == TypeListToken>::Value), "alias template definition is wrong"); Token T_ = T; // We need a non-const value for dropping head later. - // Iterate over encoded entries in Token. + // Iterate over encoded entries in \c T_. while (!emptyToken(T_)) { Log << " token: " << PRINTABLE_TOKEN(T_) << std::endl << " valid: " << validToken(T_) << std::endl << " empty: " << emptyToken(T_) << std::endl << " length: " << lengthOfToken(T_) << std::endl << " full size: " << sizeOfValuesOfToken(T_) << std::endl << " head type number: " << PRINTABLE_TN(typeNumberOfHeadOfToken(T_)) << std::endl << " size of head: " << sizeOfHeadOfToken(T_) << std::endl << " name of head: " << nameOfHeadOfToken(T_) << std::endl << " is head uint8_t: " << isHeadOfTokenTheSameType(T_) << std::endl << " is head uint16_t: " << isHeadOfTokenTheSameType(T_) << std::endl << " is head std::string: " << isHeadOfTokenTheSameType(T_) << std::endl << "Dropping head..." << std::endl; dropHeadOfToken(T_); } // Here when Token became empty. Log << " token: " << PRINTABLE_TOKEN(T_) << std::endl << " empty: " << emptyToken(T_) << std::endl; return 0; } diff --git a/include/rosa/agent/Abstraction.hpp b/include/rosa/agent/Abstraction.hpp index cb7330c..c31d0f9 100644 --- a/include/rosa/agent/Abstraction.hpp +++ b/include/rosa/agent/Abstraction.hpp @@ -1,194 +1,194 @@ //===-- rosa/agent/Abstraction.hpp ------------------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file rosa/agent/Abstraction.hpp /// /// \author David Juhasz (david.juhasz@tuwien.ac.at) /// /// \date 2017 /// /// \brief Definition of *abstraction* *functionality*. /// //===----------------------------------------------------------------------===// #ifndef ROSA_AGENT_ABSTRACTION_HPP #define ROSA_AGENT_ABSTRACTION_HPP #include "rosa/agent/Module.h" #include "rosa/support/debug.hpp" #include #include namespace rosa { namespace agent { /// Abstracts values from a type to another one. /// /// \tparam T type to abstract from /// \tparam A type to abstract to template class Abstraction : public Module { protected: /// Value to abstract to by default. const A Default; public: /// Creates an instance. /// /// \param Default value to abstract to by default Abstraction(const A Default) noexcept : Default(Default) {} - /// Destroys `this` object. + /// Destroys \p this object. ~Abstraction(void) = default; - /// Abstracts a value from type `T` to type `A`. + /// Abstracts a value from type \p T to type \p A. /// /// \note The default implementation always returns - /// `rosa::agent::Abstraction::Default`, hence the actual argument is ignored. + /// \c rosa::agent::Abstraction::Default, hence the actual argument is + /// ignored. /// /// \return the abstracted value virtual A operator()(const T &) const noexcept { return Default; } }; -/// Implements `rosa::agent::Abstraction` as a `std::map` from a type to another -/// one. +/// Implements \c rosa::agent::Abstraction as a \c std::map from a type to +/// another one. /// /// \note This implementation is supposed to be used to abstract between /// enumeration types, which is statically enforced. /// /// \tparam T type to abstract from /// \tparam A type to abstract to template class MapAbstraction : public Abstraction, private std::map { // Make sure the actual type arguments are enumerations. STATIC_ASSERT((std::is_enum::value && std::is_enum::value), "mapping not enumerations"); // Bringing into scope inherited members. using Abstraction::Default; using std::map::end; using std::map::find; public: - /// Creates an instance by initializing the underlying `std::map`. + /// Creates an instance by initializing the underlying \c std::map. /// /// \param Map the mapping to do abstraction according to /// \param Default value to abstract to by default MapAbstraction(const std::map &Map, const A Default) noexcept : Abstraction(Default), std::map(Map) {} - /// Destroys `this` object. + /// Destroys \p this object. ~MapAbstraction(void) = default; - /// Abstracts a value from type `T` to type `A` based on the set mapping. + /// Abstracts a value from type \p T to type \p A based on the set mapping. /// /// Results in the value associated by the set mapping to the argument, or - /// `rosa::agent::MapAbstraction::Default` if the actual argument is not + /// \c rosa::agent::MapAbstraction::Default if the actual argument is not /// associated with anything by the set mapping. /// /// \param V value to abstract /// /// \return the abstracted value based on the set mapping A operator()(const T &V) const noexcept override { const auto I = find(V); return I == end() ? Default : *I; } }; -/// Implements `rosa::agent::Abstraction` as a `std::map` from ranges of a type -/// to values of another type. +/// Implements \c rosa::agent::Abstraction as a \c std::map from ranges of a +/// type to values of another type. /// /// \note This implementation is supposed to be used to abstract ranges of /// arithmetic types into enumerations, which is statically enforced. /// -/// \invariant The keys in the underlying `std::map` define valid ranges -/// `(first <= second)` and there are no overlapping ranges defined by the keys. +/// \invariant The keys in the underlying \c std::map define valid ranges +/// such that `first <= second` and there are no overlapping ranges defined by +/// the keys. /// /// \tparam T type to abstract from /// \tparam A type to abstract to template class RangeAbstraction : public Abstraction, private std::map, A> { // Make sure the actual type arguments are matching our expectations. STATIC_ASSERT((std::is_arithmetic::value), "abstracting not arithmetic"); STATIC_ASSERT((std::is_enum::value), "abstracting not to enumeration"); // Bringing into scope inherited members. using Abstraction::Default; using std::map, A>::begin; using std::map, A>::end; using std::map, A>::find; public: - /// Creates an instance by Initializing the unserlying `std::map`. + /// Creates an instance by Initializing the unserlying \c std::map. /// /// \param Map the mapping to do abstraction according to /// \param Default value to abstract to by default /// - /// \pre Each key defines a valid range `(first <= second)` and there are no - /// overlapping ranges defined by the keys. + /// \pre Each key defines a valid range such that `first <= second` and + /// there are no overlapping ranges defined by the keys. RangeAbstraction(const std::map, A> &Map, const A &Default) : Abstraction(Default), std::map, A>(Map) { // Sanity check. ASSERT(std::all_of( begin(), end(), [this](const std::pair, A> &P) { return P.first.first <= P.first.second && std::all_of(++find(P.first), end(), [&P](const std::pair, A> &R) { - // NOTE: Values in Map are sorted. + // \note Values in \c Map are sorted. return P.first.first < P.first.second && P.first.second <= R.first.first || P.first.first == P.first.second && P.first.second < R.first.first; }); })); } - /// Destroys `this` object. + /// Destroys \p this object. ~RangeAbstraction(void) = default; - // Gives a value of type A associated by the underlying map to V of type T, - // or Default if no range containing V is defined. - /// Abstracts a value from type `T` to type `A` based on the set mapping. + /// Abstracts a value from type \p T to type \p A based on the set mapping. /// /// Results in the value associated by the set mapping to the argument, or - /// `rosa::agent::RangeAbstraction::Default` if the actual argument is not + /// \c rosa::agent::RangeAbstraction::Default if the actual argument is not /// included in any of the ranges in the set mapping. /// /// \param V value to abstract /// /// \return the abstracted value based on the set mapping A operator()(const T &V) const noexcept override { auto I = begin(); - bool Found = false; // Indicates if I refers to a matching range. + bool Found = false; // Indicates if \c I refers to a matching range. bool Failed = false; // Indicates if it is pointless to continue searching. while (!Found && !Failed && I != end()) { if (V < I->first.first) { - // No match so far and V is below the next range, never will match. + // No match so far and \p V is below the next range, never will match. // \note Keys are sorted in the map. Failed = true; } else if (I->first.first <= V && V < I->first.second) { // Matching range found. Found = true; } else { // Cannot conclude in this step, move to the next range. ++I; } } ASSERT(!Found || I != end()); return Found ? I->second : Default; } }; } // End namespace agent } // End namespace rosa #endif // ROSA_AGENT_ABSTRACTION_HPP diff --git a/include/rosa/agent/Confidence.hpp b/include/rosa/agent/Confidence.hpp index 48a1f56..dc59e3a 100644 --- a/include/rosa/agent/Confidence.hpp +++ b/include/rosa/agent/Confidence.hpp @@ -1,203 +1,207 @@ //===-- rosa/agent/Confidence.hpp -------------------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file rosa/agent/Confidence.hpp /// /// \author David Juhasz (david.juhasz@tuwien.ac.at) /// /// \date 2017 /// /// \brief Definition of *confidence* *functionality*. /// //===----------------------------------------------------------------------===// #ifndef ROSA_AGENT_CONFIDENCE_HPP #define ROSA_AGENT_CONFIDENCE_HPP #include "rosa/agent/History.hpp" #include "rosa/support/debug.hpp" #include namespace rosa { namespace agent { /// Confidence validator. /// /// Checks the plausibility of given values by validating if a valid region /// contains them. It also capable of checking consistency by validating the -/// rate of change recorded by a `rosa::agent::History` object against a maximal -/// absolute valid rate of change. +/// rate of change recorded by a \c rosa::agent::History object against a +/// maximal absolute valid rate of change. /// /// \tparam T type of values to validate /// /// \note The template is defined only for arithmetic types. /// /// \note The lower bound is inclusive and the upper bound is exclusive. /// /// \invariant The bounds are defined in a meaningful way:\code /// LowerBound <= UpperBound /// \endcode template class Confidence : public Module { // Make sure the actual type argument is an arithmetic type. STATIC_ASSERT(std::is_arithmetic::value, "not arithmetic Confidence"); public: - /// Unsigned type corresponding to `T`. + /// Unsigned type corresponding to \p T. using UT = unsigned_t; - /// The minimal value of type `T`. - /// \note Not exist `V` of type `T` such that `V < Min`. + /// The minimal value of type \p T. + /// \note Not exist \c V of type \p T such that `V < Min`. static constexpr T Min = std::is_integral::value ? std::numeric_limits::min() : std::numeric_limits::lowest(); - /// The maximal value of type `T`. - /// \note Not exist `V` of type `T` such that `V > Max`. + /// The maximal value of type \p T. + /// \note Not exist \c V of type \p T such that `V > Max`. static constexpr T Max = (std::is_integral::value || !std::numeric_limits::has_infinity) ? std::numeric_limits::max() : std::numeric_limits::infinity(); - /// The maximal value of type `UT`. - /// \note Not exist `V` of type `UT` such that `V > UnsignedMax`. + /// The maximal value of type \c UT. + /// \note Not exist \c V of type \c UT such that `V > UnsignedMax`. static constexpr UT UnsignedMax = (std::is_integral::value || !std::numeric_limits::has_infinity) ? std::numeric_limits::max() : std::numeric_limits::infinity(); private: /// The inclusive lower bound for plausibility check. T LowerBound; /// The exclusive upper bound for plausibility check. T UpperBound; /// The maximal absolute rate of change for consistency check. UT ChangeRate; public: /// Creates an instance by setting the validator variables. /// /// \param LowerBound the lower bound for plausability check /// \param UpperBound the upper bound for plausability check /// \param ChangeRate maximal absolute rate of change for consistency check /// /// \pre The bounds are defined in a meaningful way:\code /// LowerBound <= UpperBound /// \endcode Confidence(const T LowerBound = Min, const T UpperBound = Max, const UT ChangeRate = UnsignedMax) noexcept : LowerBound(LowerBound), UpperBound(UpperBound), ChangeRate(ChangeRate) { // Make sure Confidence is created in a valid state. if (LowerBound > UpperBound) { ROSA_CRITICAL("Confidence with LowerBound higher than UpperBound"); } } - /// Destroys `this` object. + /// Destroys \p this object. ~Confidence(void) = default; /// Gives a snapshot of the current state of the validator variables. /// - /// \param [out] LowerBound to copy `rosa::agent::Confidence::LowerBound` into - /// \param [out] UpperBound to copy `rosa::agent::Confidence::UpperBound` into - /// \param [out] ChangeRate to copy `rosa::agent::Confidence::ChangeRate` into + /// \param [out] LowerBound to copy \c rosa::agent::Confidence::LowerBound + /// into + /// \param [out] UpperBound to copy \c rosa::agent::Confidence::UpperBound + /// into + /// \param [out] ChangeRate to copy \c rosa::agent::Confidence::ChangeRate + /// into void getParameters(T &LowerBound, T &UpperBound, UT &ChangeRate) const noexcept { // Copy members to the given references. LowerBound = this->LowerBound; UpperBound = this->UpperBound; ChangeRate = this->ChangeRate; } /// Sets the lower bound for plausability check. /// /// Beyond setting the lower bound, the function also adjusts the upper bound /// to the given lower bound if the new lower bound would be higher than the /// upper bound. /// /// \param LowerBound the new lower bound to set void setLowerBound(const T LowerBound) noexcept { // Adjust UpperBound if necessary, then set LowerBound. if (UpperBound < LowerBound) { UpperBound = LowerBound; } this->LowerBound = LowerBound; } /// Sets the upper bound for plausability check. /// /// Beyond setting the upper bound, the function also adjusts the lower bound /// to the given upper bound if the new upper bound would be lower than the /// lower bound. /// /// \param UpperBound the new upper bound to set void setUpperBound(const T UpperBound) noexcept { // Adjust LowerBound if necessary, then set UpperBound. if (UpperBound < LowerBound) { LowerBound = UpperBound; } this->UpperBound = UpperBound; } /// Sets the maximal rate of change for consistency check. /// /// \param ChangeRate the new rate of change to set void setChangeRate(const UT ChangeRate) noexcept { // Set ChangeRate. this->ChangeRate = ChangeRate; } /// Tells the binary confidence on the plausibility of a value. /// /// \param V value to check /// - /// \return whether `V` is within the range defined by - /// `rosa::agent::Confidence::LowerBound` and - /// `rosa::agent::Confidence::UpperBound`. + /// \return whether \c V is within the range defined by + /// \c rosa::agent::Confidence::LowerBound and + /// \c rosa::agent::Confidence::UpperBound. bool operator()(const T V) const noexcept { - // Return if V is plausible. + // Return if \c V is plausible. return LowerBound <= V && V < UpperBound; } /// Tells the binary confidence on the plausibility and consistency of the - /// last value recorded by a `rosa::agent::History` instance. + /// last value recorded by a \c rosa::agent::History instance. /// /// Consistency of the last value is checked by validating the difference with /// its preceding entry. /// - /// \note The `rosa::agent::History` instance needs to store values of type - /// `T`. + /// \note The \c rosa::agent::History instance needs to store values of type + /// \p T. /// - /// \note An empty `rosa::agent::History` instance results in full confidence. + /// \note An empty \c rosa::agent::History instance results in full + /// confidence. /// - /// \tparam N number of values `H` is able to store - /// \tparam P retention policy followed by `H` when capacity is reached + /// \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 *history* whose last entry to check template bool operator()(const History &H) const noexcept { if (H.empty()) { // No entry to validate. return true; } else { // Validate the last entry and the one step average absolute difference. return (*this)(H.entry()) && H.averageAbsDiff(1) <= ChangeRate; } } }; } // End namespace agent } // End namespace rosa #endif // ROSA_AGENT_CONFIDENCE_HPP diff --git a/include/rosa/agent/History.hpp b/include/rosa/agent/History.hpp index d8e979f..e3279ac 100644 --- a/include/rosa/agent/History.hpp +++ b/include/rosa/agent/History.hpp @@ -1,296 +1,296 @@ //===-- 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 `rosa::agent::History` instance should do -/// when the number of recorded entries reached its capacity. +/// 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 `rosa::agent::Module` is an internal component of a -/// `rosa::Agent`, which is the basic unit of concurrency. +/// 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 `std::array` is `N + 1`:\code +/// \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 `this` object. + /// Destroys \p this object. ~History(void) = default; - /// Tells the retention policy applied to `this` object. + /// Tells the retention policy applied to \p this object. /// - /// \return `rosa::agent::History::P` + /// \return \c rosa::agent::History::P static constexpr HistoryPolicy policyOfHistory(void) noexcept { return P; } - /// Tells how many entries may be recorded by `this` object. + /// Tells how many entries may be recorded by \c this object. /// /// \note The number of entries that are actually recorded may be smaller. /// - /// \return `rosa::agent::History::N` + /// \return \c rosa::agent::History::N static constexpr size_t lengthOfHistory(void) noexcept { return N; } - /// Tells how many entries are currently recorded by `this` object. + /// Tells how many entries are currently recorded by \p this object. /// - /// \return number of entries currently recorded by `this` object. + /// \return number of entries currently recorded by \p this object. /// - /// \post The returned value cannot be larger than the capacity of `this` + /// \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 { return Data <= Space ? Space - Data : max_size() - Data + Space; } - /// Tells if `this` object has not recorded anything yet. + /// Tells if \p this object has not recorded anything yet. /// - /// \return if `this` object has no entries recorded + /// \return if \p this object has no entries recorded inline bool empty(void) const noexcept { return numberOfEntries() == 0; } - /// Gives a constant lvalue reference to an entry stored in `this` object. + /// 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 `I` is a valid index:\code + /// \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; } /// 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 `this` object and tells if the operation was + /// 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 `V` was successfully stored + /// \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 `this` object. + /// 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 `this` object. + /// entries recorded by \p this object. /// /// \note The function is made a template only to be able to use - /// `std::enable_if`. + /// \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, `this` object stores signed arithmetic values:\code + /// \pre Statically, \p this object stores signed arithmetic values:\code /// std::is_arithmetic::value && std::is_signed::value - /// \endcode Dynamically, `D` is a valid number of steps to take:\code + /// \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 T + return {}; // Zero element of \p T } else { // Here at least two entries. - // `S` is the number of steps that can be done. + // \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 `this` object + /// 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 `this` object. + /// entries recorded by \p this object. /// /// \note The function is made a template only to be able to use - /// `std::enable_if`. + /// \c std::enable_if. /// /// \tparam X always use the default! /// /// \param D number of steps to go back in *history* /// - /// \pre Statically, `this` object stores arithmetic values:\code + /// \pre Statically, \p this object stores arithmetic values:\code /// std::is_arithmetic::value - /// \endcode Dynamically, `D` is a valid number of steps to take:\code + /// \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 T + return {}; // Zero element of \p T } else { // Here at least two entries. - // `S` is the number of steps that can be done. + // \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 `rosa::agent::History` instance. +/// Adds a new entry to a \c rosa::agent::History instance. /// -/// \note The result of `rosa::agent::History::addEntry` is ignored. +/// \note The result of \c rosa::agent::History::addEntry is ignored. /// -/// \tparam T type of values stored in `H` -/// \tparam N number of values `H` is able to store -/// \tparam P retention policy followed by `H` when capacity is reached +/// \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 `H` +/// \param V value to add to \p H /// -/// \return `H` after adding `V` to it +/// \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/config/project_path.hpp b/include/rosa/config/project_path.hpp index 8375d0a..91a6629 100644 --- a/include/rosa/config/project_path.hpp +++ b/include/rosa/config/project_path.hpp @@ -1,67 +1,67 @@ //===-- rosa/config/project_path.hpp ----------------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file rosa/config/project_path.hpp /// /// \author David Juhasz (david.juhasz@tuwien.ac.at) /// /// \date 2017 /// /// \brief Facility for compile-time manipulation of paths. /// //===----------------------------------------------------------------------===// #ifndef ROSA_CONFIG_PROJECT_PATH_HPP #define ROSA_CONFIG_PROJECT_PATH_HPP #include "rosa/config/rosa_config.h" #include namespace rosa { /// Nested namespace with implementation of the provided features, /// consider it private. namespace { /// Tells the index of the project-relative part of an absolute path. /// /// \param path absolute path to check /// \param project the absolute path of the project /// \param index number of leading characters already checked and found /// matching /// -/// \return index of the `project`-relative part of `path`; `0` if `path` is not -/// under `project` +/// \return index of the part relative to \c project in \p path; \c 0 if \p path +/// is not under \p project constexpr size_t project_relative_path_index_impl(const char *const path, const char *const project = ROSA_SRC_DIR, const size_t index = 0) { return project[index] == '\0' ? index // Found it. : (path[index] == '\0' || project[index] != path[index]) ? 0 // Path is not under project. : project_relative_path_index_impl( path, project, index + 1); // Continue searching... } } // End namespace /// Tells the index of the project-relative part of an absolute path. /// /// \param path absolute path to check /// -/// \return index of the project-relative part of `path`; `0` if `path` is not -/// under the RoSA siource directory. +/// \return index of the project-relative part of \p path; \c 0 if \p path is +/// not under the RoSA siource directory. constexpr size_t project_relative_path_index(const char * const path) { return project_relative_path_index_impl(path); } } // End namespace rosa #endif // ROSA_CONFIG_PROJECT_PATH_HPP diff --git a/include/rosa/core/AbstractAgent.hpp b/include/rosa/core/AbstractAgent.hpp index f1d4539..96e754a 100644 --- a/include/rosa/core/AbstractAgent.hpp +++ b/include/rosa/core/AbstractAgent.hpp @@ -1,140 +1,140 @@ //===-- rosa/core/AbstractAgent.hpp -----------------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file rosa/core/AbstractAgent.hpp /// /// \author David Juhasz (david.juhasz@tuwien.ac.at) /// /// \date 2017 /// /// \brief Declaration of an abstract interface for *Agents*. /// //===----------------------------------------------------------------------===// #ifndef ROSA_CORE_ABSTRACTAGENT_HPP #define ROSA_CORE_ABSTRACTAGENT_HPP #include "rosa/core/Message.hpp" #include "rosa/core/forward_declarations.h" #include "rosa/support/debug.hpp" #include namespace rosa { /// Abstract class declaring an interface for *Agents*. /// -/// \tparam Ref type of the derived class implementing `rosa::AbstractAgent` for -/// referencing `this` object +/// \tparam Ref type of the derived class implementing \c rosa::AbstractAgent +/// for referencing \p this object /// -/// \note `Ref` is reference for `rosa::AbstractAgent`, whose actual value must -/// be a class derived from `rosa::AbstractAgent`. +/// \note \p Ref is reference for \c rosa::AbstractAgent, whose actual value +/// must be a class derived from \c rosa::AbstractAgent. /// -/// \note It can be statically checked if `Ref` is derived from -/// `rosa::AbstractAgent`, but the static assertion cannot be defined -/// directly in the class body. That is because a class `C` derived from -/// `rosa::AbstractAgent` is not complete when the static assertion in the -/// definition of `rosa::AbstractAgent` would be evaluated. Thus, the static -/// assertion is placed in the constructor of `rosa::AbstractAgent`. +/// \note It can be statically checked if \p Ref is derived from +/// \c rosa::AbstractAgent, but the static assertion cannot be defined +/// directly in the class body. That is because a class \c C derived from +/// \c rosa::AbstractAgent is not complete when the static assertion in the +/// definition of \c rosa::AbstractAgent would be evaluated. Thus, the static +/// assertion is placed in the constructor of \c rosa::AbstractAgent. template class AbstractAgent { protected: - /// Creates a new instance of `rosa::AbstractAgent`. + /// Creates a new instance of \c rosa::AbstractAgent. /// /// \note The constructor is protected, thus restricting class instantiation /// for derived classes only. /// - /// \pre `Ref` is derived from `rosa::AbstractAgent`:\code + /// \pre \p Ref is derived from \c rosa::AbstractAgent:\code /// std::is_base_of, Ref>::value /// \endcode AbstractAgent(void) noexcept; public: - /// Destroys `this` object. + /// Destroys \p this object. virtual ~AbstractAgent(void) = default; - /// Tells if `this` object is in a valid state. + /// Tells if \p this object is in a valid state. /// - /// \return if `this` object is in a valid state + /// \return if \p this object is in a valid state virtual operator bool(void) const noexcept = 0; - /// Tells if a given reference refers to `this` object. + /// Tells if a given reference refers to \p this object. /// /// \param R reference to another object /// - /// \return if `R` refers to `this` object + /// \return if \p R refers to \p this object virtual bool operator==(const Ref &R) const noexcept = 0; - /// Returns a reference to `this` object. + /// Returns a reference to \p this object. /// - /// \return a reference to `this` object + /// \return a reference to \p this object virtual Ref self(void) noexcept = 0; - /// Sends a `rosa::message_t` instance to `this` object. + /// Sends a \c rosa::message_t instance to \p this object. /// /// \param M message to send /// - /// \pre `this` object is in a valid state:\code + /// \pre \p this object is in a valid state:\code /// bool(*this) /// \endcode virtual void sendMessage(message_t &&M) noexcept = 0; /// Sends a message -- created from given constant lvalue references -- to - /// `this` object. + /// \p this object. /// /// \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 T the first value to include in the message /// \param Ts optional further values to include in the message /// - /// \pre `this` object is in a valid state:\code + /// \pre \p this object is in a valid state:\code /// bool(*this) /// \endcode template void send(const Type &T, const Types &... Ts) noexcept; - /// Sends a message -- created from given rvalue references -- to `this` + /// Sends a message -- created from given rvalue references -- to \p this /// object. /// /// \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 T the first value to include in the message /// \param Ts optional further values to include in the message /// - /// \pre `this` object is in a valid state:\code + /// \pre \p this object is in a valid state:\code /// bool(*this) /// \endcode template void send(Type &&T, Types &&... Ts) noexcept; }; template AbstractAgent::AbstractAgent(void) noexcept { STATIC_ASSERT((std::is_base_of, Ref>::value), "not derived Agent"); // Sanity check. } template template void AbstractAgent::send(const Type &T, const Types &... Ts) noexcept { sendMessage(Message::create(T, Ts...)); } template template void AbstractAgent::send(Type &&T, Types &&... Ts) noexcept { sendMessage(Message::create(std::move(T), std::move(Ts)...)); } } // End namespace rosa #endif // ROSA_CORE_ABSTRACTAGENT_HPP diff --git a/include/rosa/core/Agent.hpp b/include/rosa/core/Agent.hpp index 7360f56..457e1f7 100644 --- a/include/rosa/core/Agent.hpp +++ b/include/rosa/core/Agent.hpp @@ -1,113 +1,113 @@ //===-- rosa/core/Agent.hpp -------------------------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file rosa/core/Agent.hpp /// /// \author David Juhasz (david.juhasz@tuwien.ac.at) /// /// \date 2017 /// -/// \brief Declaration of the base `rosa::Agent` class. +/// \brief Declaration of the base \c rosa::Agent class. /// //===----------------------------------------------------------------------===// #ifndef ROSA_CORE_AGENT_HPP #define ROSA_CORE_AGENT_HPP #include "rosa/core/AgentHandle.hpp" #include "rosa/core/MessageHandler.hpp" #include "rosa/core/MessagingSystem.hpp" #include "rosa/core/Unit.h" #include "rosa/support/log.h" namespace rosa { -/// Implements an *Agent* that is a special `rosa::Unit` owned by a -/// `rosa::MessagingSystem`, capable of handling `rosa::Message` instances -/// as `rosa::MessageHandler`, and provides the `rosa::AbstractAgent` interface -/// with `rosa::AgentHandle` as reference type. +/// Implements an *Agent* that is a special \c rosa::Unit owned by a +/// \c rosa::MessagingSystem, capable of handling \c rosa::Message instances +/// as \c rosa::MessageHandler, and provides the \c rosa::AbstractAgent +/// interface with \c rosa::AgentHandle as reference type. class Agent : public Unit, public MessageHandler, public AbstractAgent { - friend class AgentHandle; ///< `rosa::AgentHandle` is our friend. + friend class AgentHandle; ///< \c rosa::AgentHandle is our friend. protected: - /// A handle for `this` object. + /// A handle for \p this object. const AgentHandle Self; public: /// Creates a new instance by instantiating all the base-classes. /// /// \tparam Fun type of the first mandatory function for handling messages /// \tparam Funs types of any further functions for handling messages /// - /// \param Kind kind of the new `rosa::Unit` instance - /// \param Id unique identifier of the new `rosa::Unit` instance - /// \param Name name of the new `rosa::Unit` instance - /// \param S `rosa::MessagingSystem` owning the new instance + /// \param Kind kind of the new \c rosa::Unit instance + /// \param Id unique identifier of the new \c rosa::Unit instance + /// \param Name name of the new \c rosa::Unit instance + /// \param S \c rosa::MessagingSystem owning the new instance /// \param F the first mandatory function for handling messages /// \param Fs optional further functions for handling messages template Agent(const AtomValue Kind, const id_t Id, const std::string &Name, MessagingSystem &S, Fun &&F, Funs &&... Fs); - /// Destroys `this` object. + /// Destroys \p this object. ~Agent(void); - /// Tells if `this` object is in a valid state. + /// Tells if \p this object is in a valid state. /// - /// \note A `rosa::Agent` instance is always valid. + /// \note A \c rosa::Agent instance is always valid. /// - /// \return if `this` object is in a valid state + /// \return if \p this object is in a valid state operator bool(void) const noexcept override; - /// Tells if a given reference refers to `this` object. + /// Tells if a given reference refers to \p this object. /// /// \param H reference to another object /// - /// \return if `H` refers to `this` object + /// \return if \p H refers to \p this object bool operator==(const AgentHandle &H) const noexcept override; - /// Returns a reference to `this` object. + /// Returns a reference to \p this object. /// - /// \return a reference to `this` object + /// \return a reference to \p this object AgentHandle self(void) noexcept override; - /// Sends a given `rosa::message_t` instance to `this` object. + /// Sends a given \c rosa::message_t instance to \p this object. /// /// \param M message to send /// - /// \note Since a `rosa::Agent` instance is always valid, there is no + /// \note Since a \c rosa::Agent instance is always valid, there is no /// precondition for this function. - /// \see rosa::AbstractAgent::sendMessage and + /// \see \c rosa::AbstractAgent::sendMessage and /// `rosa::Agent::operator bool() const` void sendMessage(message_t &&M) noexcept override; - /// Dumps `this` object into a `std::string` for tracing purposes. + /// Dumps \p this object into a \c std::string for tracing purposes. /// - /// \return `string` representing the state of `this` object + /// \return \c std::string representing the state of \p this object std::string dump(void) const noexcept override; protected: - /// Returns a reference to the `rosa::MessagingSystem` owning `this` object. + /// Returns a reference to the \c rosa::MessagingSystem owning \p this object. /// - /// \return reference of `S` + /// \return reference of \c rosa::Unit::S MessagingSystem &system(void) const noexcept override; }; template Agent::Agent(const AtomValue Kind, const id_t Id, const std::string &Name, MessagingSystem &S, Fun &&F, Funs &&... Fs) : Unit(Kind, Id, Name, S), MessageHandler(std::move(F), std::move(Fs)...), Self(*this, /*valid*/ true) { LOG_TRACE("Agent is created."); } } // End namespace rosa #endif // ROSA_CORE_AGENT_HPP diff --git a/include/rosa/core/AgentHandle.hpp b/include/rosa/core/AgentHandle.hpp index 46c3a9a..8aa7ffe 100644 --- a/include/rosa/core/AgentHandle.hpp +++ b/include/rosa/core/AgentHandle.hpp @@ -1,109 +1,110 @@ //===-- rosa/core/AgentHandle.hpp -------------------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file rosa/core/AgentHandle.hpp /// /// \author David Juhasz (david.juhasz@tuwien.ac.at) /// /// \date 2017 /// -/// \brief Declaration of a handle for `rosa::Agent`. +/// \brief Declaration of a handle for \c rosa::Agent. /// //===----------------------------------------------------------------------===// #ifndef ROSA_CORE_AGENTHANDLE_HPP #define ROSA_CORE_AGENTHANDLE_HPP #include "rosa/core/AbstractAgent.hpp" namespace rosa { -/// Wraps an actual `rosa::Agent` to decouple its public interface. +/// Wraps an actual \c rosa::Agent to decouple its public interface. /// \note Such decoupling might be necessary when operating with remote /// *systems*, sometime in the future. class AgentHandle : public AbstractAgent { - /// `rosa::Agent` and `rosa::MessagingSystem` are our friends, they may + /// \c rosa::Agent and \c rosa::MessagingSystem are our friends, they may /// inspect the private member fields of the class. ///@{ friend class Agent; friend class MessagingSystem; ///@} - /// The wrapped `rosa::Agent` instance. + /// The wrapped \c rosa::Agent instance. Agent &A; - /// The `rosa::MessagingSystem` owning `A`. + /// The \c rosa::MessagingSystem owning \c A. MessagingSystem &S; /// Creates a new instance without validating the state of the wrapped - /// `rosa::Agent`. + /// \c rosa::Agent. /// - /// \note Used by a `rosa::Agent` instance to create a reference to itself + /// \note Used by a \c rosa::Agent instance to create a reference to itself /// during construction, when its state is not valid yet. /// - /// \param A `Agent` to wrap + /// \param A \c rosa::Agent to wrap /// /// \note There a second argument, which is ignored, that is only present to /// separate this constructor from the public constructor taking only a - /// `rosa::Agent` to wrap. + /// \c rosa::Agent to wrap. AgentHandle(Agent &A, bool); public: - /// Creates a new instance validating the state of the wrapped `rosa::Agent`. + /// Creates a new instance validating the state of the wrapped \p rosa::Agent. /// - /// \note The wrapped `rosa::Agent` must be in a valid state to instantiate - /// `rosa::AgentHandle` with this constructor. + /// \note The wrapped \c rosa::Agent must be in a valid state to instantiate + /// \c rosa::AgentHandle with this constructor. /// - /// \param A `Agent` to wrap + /// \param A \c rosa::Agent to wrap /// - /// \pre `A` is registered in its owning *system*:\code + /// \pre \p A is registered in its owning *system*:\code /// A.system().isUnitRegistered(A) /// \endcode AgentHandle(Agent &A); - /// Destroys `this` object. + /// Destroys \p this object. /// /// The destructor has nothing to take care of. ~AgentHandle(void) = default; - /// Tells if the wrapped `rosa::Agent` is in a valid state. + /// Tells if the wrapped \c rosa::Agent is in a valid state. /// - /// \note A `rosa::AgentHandler` belongs to a `rosa::MessagingSystem`. Working - /// with a `rosa::AgentHandler` whose originating `rosa::MessagingSystem` has - /// already been destroyed results in *undefined* behavior. + /// \note A \c rosa::AgentHandler belongs to a \c rosa::MessagingSystem. + /// Working with a \c rosa::AgentHandler whose originating + /// \c rosa::MessagingSystem has already been destroyed results in *undefined* + /// behavior. /// - /// \return if the wrapped `rosa::Agent` is in a valid state + /// \return if the wrapped \c rosa::Agent is in a valid state operator bool(void) const noexcept override; - /// Tells if another `rosa::AgentHandle` wraps the same `rosa::Agent` as - /// `this` object. + /// Tells if another \c rosa::AgentHandle wraps the same \c rosa::Agent as + /// \p this object. /// - /// \param H `AgentHandle` whose wrapped `Agent` to check + /// \param H \c rosa::AgentHandle whose wrapped \c rosa::Agent to check /// - /// \return if `H` wraps `A` like `this` object + /// \return if \p H wraps \c A like \p this object bool operator==(const AgentHandle &H) const noexcept override; - /// Returns a reference to the wrapped `rosa::Agent`. + /// Returns a reference to the wrapped \c rosa::Agent. /// - /// \return a reference to `A` + /// \return a reference to \c A AgentHandle self(void) noexcept override; - /// Sends a given `rosa::message_t` instance to the wrapped `rosa::Agent`. + /// Sends a given \c rosa::message_t instance to the wrapped \c rosa::Agent. /// /// \param M message to send /// - /// \pre The wrapped `rosa::Agent` instance is in a valid state:\code + /// \pre The wrapped \c rosa::Agent instance is in a valid state:\code /// bool(*this) /// \endcode void sendMessage(message_t &&M) noexcept override; }; } // End namespace rosa #endif // ROSA_CORE_AGENTHANDLE_HPP diff --git a/include/rosa/core/Invoker.hpp b/include/rosa/core/Invoker.hpp index 9f85bb4..d5703e7 100644 --- a/include/rosa/core/Invoker.hpp +++ b/include/rosa/core/Invoker.hpp @@ -1,269 +1,274 @@ //===-- rosa/core/Invoker.hpp -----------------------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file rosa/core/Invoker.hpp /// /// \author David Juhasz (david.juhasz@tuwien.ac.at) /// /// \date 2017 /// /// \brief Facilities for providing actual arguments for functions as -/// `rosa::Message`objects. +/// \c rosa::Messageobjects. /// //===----------------------------------------------------------------------===// #ifndef ROSA_CORE_INVOKER_HPP #define ROSA_CORE_INVOKER_HPP #include "rosa/core/MessageMatcher.hpp" #include "rosa/support/log.h" #include #include namespace rosa { /// Wraps a function and provides a simple interface to invoke the stored -/// function by passing actual arguments as a `rosa::Message` object. +/// function by passing actual arguments as a \c rosa::Message object. /// -/// \note A `rosa::Invoker` instance is supposed to be owned by a -/// `rosa::MessageHandler` instance, and not being used directly from user code. +/// \note A \c rosa::Invoker instance is supposed to be owned by a +/// \c rosa::MessageHandler instance, and not being used directly from user +/// code. class Invoker { protected: /// Creates an instance. /// /// \note Protected constructor restricts instantiation to derived classes. Invoker(void) noexcept; public: - /// Destroys `this` object. + /// Destroys \p this object. virtual ~Invoker(void); /// Possible results of an invocation. enum class Result { NoMatch, ///< The wrapped function could not be invoked Invoked ///< The wrapped function has been invoked }; - /// Type alias for a smart-pointer for `rosa::Invoker`. + /// Type alias for a smart-pointer for \c rosa::Invoker. using invoker_t = std::unique_ptr; - /// Type alias for `rosa::Invoker::Result`. + /// Type alias for \c rosa::Invoker::Result. using result_t = Result; - /// Tells if a `rosa::Message` object can be used to invoke the function - /// wrapped in `this` object. + /// Tells if a \c rosa::Message object can be used to invoke the function + /// wrapped in \p this object. /// - /// \param Msg `rosa::Message` to check + /// \param Msg \c rosa::Message to check /// - /// \return whether `Msg` can be used to invoke the wrapped function + /// \return whether \p Msg can be used to invoke the wrapped function virtual bool match(const Message &Msg) const noexcept = 0; - /// Tries to invoke the wrapped function with a `rosa::Message` object. + /// Tries to invoke the wrapped function with a \c rosa::Message object. /// - /// The wrapped function is invoked if the actual `rosa::Message` object can + /// The wrapped function is invoked if the actual \c rosa::Message object can /// be used to invoke it. /// - /// \param Msg `rosa::Message` to try to invoke the wrapped function with + /// \param Msg \c rosa::Message to try to invoke the wrapped function with /// - /// \return whether the wrapped function could be invoked with `Msg` + /// \return whether the wrapped function could be invoked with \p Msg virtual result_t operator()(const Message &Msg) const noexcept = 0; - /// Instantiates an implementation of `rosa::Invoker` with the given function. + /// Instantiates an implementation of \c rosa::Invoker with the given + /// function. /// - /// \note As there is no empty `rosa::Message`, no `rosa::Invoker` wraps a + /// \note As there is no empty \c rosa::Message, no \c rosa::Invoker wraps a /// function without any argument. /// /// \tparam T type of the first mandatory argument /// \tparam Ts types of any further arguments /// /// \param F function to wrap /// - /// \return new `invoker_t` object created from the given function + /// \return new \c rosa::Invoker::invoker_t object created from the given + /// function template static invoker_t wrap(std::function &&F) noexcept; /// Convenience template alias for casting callable stuff to function objects /// for wrapping. /// /// \tparam Ts types of arguments /// /// \todo Should make it possible to avoid using an explicit conversion for /// the arguments of wrap. template using F = std::function; /// Convenience template for preparing non-static member functions into /// function objects for wrapping. /// /// \tparam C type whose non-static member the function is /// \tparam Ts types of arguments /// - /// \see THISMEMBER + /// \see \c THISMEMBER template static inline F M(C *O, void (C::*Fun)(Ts...) noexcept) noexcept; }; -/// Convenience preprocessor macro for the typical use of `rosa::Invoker::M`. It -/// can be used inside a class to turn a non-static member function into a +/// Convenience preprocessor macro for the typical use of \c rosa::Invoker::M. +/// It can be used inside a class to turn a non-static member function into a /// function object capturing this pointer, so using the actual object when -/// handling a `rosa::Message`. +/// handling a \c rosa::Message. /// /// \param FUN the non-static member function to wrap /// -/// \note Inside the class `MyClass`, use\code +/// \note Inside the class \c MyClass, use\code /// THISMEMBER(fun) /// \endcode instead of\code /// Invoker::M(this, &MyClass::fun) /// \endcode #define THISMEMBER(FUN) \ Invoker::M(this, &std::decay::type::FUN) -/// Nested namespace with implementation of `rosa::Invoker` and helper +/// Nested namespace with implementation of \c rosa::Invoker and helper /// templates, consider it private. namespace { /// \defgroup Seq /// ///@{ /// Template with an empty struct to store a sequence of numbers in compile time /// as template arguments. template struct Seq {}; /// Sequence generator, the general case when counting down by extending the /// sequence. template struct GenSeq : GenSeq {}; /// Sequence generator, the terminal case when storing the generated sequence -/// into `rosa::Seq`. +/// into \c Seq. template struct GenSeq<0, S...> { using Type = Seq; }; ///@} /// \defgroup InvokerImpl /// -/// Implements the `rosa::Invoker` interface for functions with different +/// Implements the \c rosa::Invoker interface for functions with different /// signatures. /// ///@{ -/// Declaration of `rosa::InvokerImpl` implementing `rosa::Invoker`. +/// Declaration of \c rosa::InvokerImpl implementing \c rosa::Invoker. /// /// \tparam Fun function to wrap template class InvokerImpl; -/// Implementation of `rosa::InvokerImpl` for `std::function`. +/// Implementation of \c rosa::InvokerImpl for \c std::function. /// /// \tparam T type of the first mandatory argument /// \tparam Ts types of further arguments /// -/// \note As there is no empty `rosa::Message`, no `rosa::Invoker` wraps a -/// function without any argument, i.e., no std::function. +/// \note As there is no empty \c rosa::Message, no \c rosa::Invoker wraps a +/// function without any argument, i.e., no +/// \c std::function. template class InvokerImpl> final : public Invoker { /// Type alias for the stored function. using function_t = std::function; /// Type alias for correctly typed argument-tuples as obtained from - /// `rosa::Message`. + /// \c rosa::Message. using args_t = std::tuple; - /// Alias for `rosa::MessageMatcher` for the arguments of the stored function. + /// Alias for \c rosa::MessageMatcher for the arguments of the stored + /// function. using Matcher = MsgMatcher; /// The wrapped function. const function_t F; - /// Invokes `F` by unpacking arguments from a `std::tuple` with the help of - /// the actual template arguments. + /// Invokes \c InvokerImpl::F by unpacking arguments from a \c std::tuple with + /// the help of the actual template arguments. /// - /// \tparam S sequence of numbers indexing `std::tuple` for arguments + /// \tparam S sequence of numbers indexing \c std::tuple for arguments /// - /// \param Args arguments to invoke `F` with + /// \param Args arguments to invoke \c InvokerImpl::F with /// - /// \pre the length of `S` and size of `Args` are matching:\code + /// \pre the length of \p S and size of \p Args are matching:\code /// sizeof...(S) == std::tuple_size::value /// \endcode template inline void invokeFunction(Seq, const args_t &Args) const noexcept; public: /// Creates an instance. /// /// \param F function to wrap /// - /// \pre `F` is valid:\code + /// \pre \p F is valid:\code /// bool(F) /// \endcode InvokerImpl(function_t &&F) noexcept : F(F) { ASSERT(bool(F)); // Sanity check. } - /// Destroys `this` object. + /// Destroys \p this object. ~InvokerImpl(void) = default; - /// Tells if a `rosa::Message` object can be used to invoke the function - /// wrapped in `this` object. + /// Tells if a \c rosa::Message object can be used to invoke the function + /// wrapped in \p this object. /// - /// \param Msg `rosa::Message` to check + /// \param Msg \c rosa::Message to check /// - /// \return whether `Msg` can be used to invoke the wrapped function + /// \return whether \p Msg can be used to invoke the wrapped function bool match(const Message &Msg) const noexcept override { return Matcher::doesStronglyMatch(Msg); }; - /// Tries to invoke the wrapped function with a `rosa::Message` object. + /// Tries to invoke the wrapped function with a \c rosa::Message object. /// - /// The wrapped function is invoked if the actual `rosa::Message` object can + /// The wrapped function is invoked if the actual \c rosa::Message object can /// be used to invoke it. /// - /// \param Msg `rosa::Message` to try to invoke the wrapped function with + /// \param Msg \c rosa::Message to try to invoke the wrapped function with /// - /// \return whether the wrapped function could be invoked with `Msg` + /// \return whether the wrapped function could be invoked with \p Msg result_t operator()(const Message &Msg) const noexcept override { if (match(Msg)) { LOG_TRACE("Invoking with matching arguments"); invokeFunction(typename GenSeq::Type(), Matcher::extractedValues(Msg)); return result_t::Invoked; } else { LOG_TRACE("Tried to invoke with non-matching arguments"); return result_t::NoMatch; } } }; template template void InvokerImpl>::invokeFunction( Seq, const args_t &Args) const noexcept { ASSERT(sizeof...(S) == std::tuple_size::value); // Sanity check. F(std::get(Args)...); } ///@} } // End namespace template Invoker::invoker_t Invoker::wrap(std::function &&F) noexcept { return std::unique_ptr( new InvokerImpl>(std::move(F))); } template Invoker::F Invoker::M(C *O, void (C::*Fun)(Ts...) noexcept) noexcept { return [ O, Fun ](Ts... Vs) noexcept->void { (O->*Fun)(Vs...); }; } } // End namespace rosa #endif // ROSA_CORE_INVOKER_HPP diff --git a/include/rosa/core/Message.hpp b/include/rosa/core/Message.hpp index a2e8927..58e2d2a 100644 --- a/include/rosa/core/Message.hpp +++ b/include/rosa/core/Message.hpp @@ -1,481 +1,483 @@ //===-- rosa/core/Message.hpp -----------------------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file rosa/core/Message.hpp /// /// \author David Juhasz (david.juhasz@tuwien.ac.at) /// /// \date 2017 /// -/// \brief Declaration of `rosa::Message` base-class. +/// \brief Declaration of \c rosa::Message base-class. /// //===----------------------------------------------------------------------===// #ifndef ROSA_CORE_MESSAGE_HPP #define ROSA_CORE_MESSAGE_HPP #include "rosa/support/log.h" #include "rosa/support/type_token.hpp" #include "rosa/core/forward_declarations.h" #include #include namespace rosa { /// *Message* interface. /// /// The interface provides means to check the type of the stored values, but /// actual data is to be managed by derived implementations. /// -/// A `rosa::Message` instance is an immutable data object that obtains its data -/// upon creation and provides only constant references for the stored values. +/// A \c rosa::Message instance is an immutable data object that obtains its +/// data upon creation and provides only constant references for the stored +/// values. /// -/// \note Any reference obtained from a `rosa::Message` instance remains valid -/// only as long as the owning `rosa::Message` object is not destroyed. +/// \note Any reference obtained from a \c rosa::Message instance remains valid +/// only as long as the owning \c rosa::Message object is not destroyed. class Message { protected: /// Creates a new instance. /// /// \note No implementation for empty list. /// /// \tparam Type type of the mandatory first argument /// \tparam Types types of any further arguments /// /// \note the actual arguments are ignored by the constructor it is only /// their type that matters. The actual values are supposed to be handled by - /// any implementation derived from `rosa::Message`. + /// any implementation derived from \c rosa::Message. /// - /// \pre `Type` and `Types` are all built-in types and the number of stored - /// values does not exceed `rosa::token::MaxTokenizableListSize`. + /// \pre \p Type and \p Types are all built-in types and the number of stored + /// values does not exceed \c rosa::token::MaxTokenizableListSize. template Message(const Type &, const Types &...) noexcept; - /// No copying and moving of `rosa::Message` instances. + /// No copying and moving of \c rosa::Message instances. ///@{ Message(const Message &) = delete; Message(Message &&) = delete; Message &operator=(const Message &) = delete; Message &operator=(Message &&) = delete; ///@} public: - /// Creates a `rosa::message_t` object from constant lvalue references. + /// Creates a \c rosa::message_t object from constant lvalue references. /// /// \tparam Type type of the mandatory first argument /// \tparam Types types of any further arguments /// - /// \param T the first value to include in the `rosa::Message` - /// \param Ts optional further values to include in the `rosa::Message` + /// \param T the first value to include in the \c rosa::Message + /// \param Ts optional further values to include in the \c rosa::Message /// - /// \return new `message_t` object created from the given arguments + /// \return new \c rosa::message_t object created from the given arguments template static message_t create(const Type &T, const Types &... Ts) noexcept; - /// Creates a `rosa::message_t` object from rvalue references. + /// Creates a \c rosa::message_t object from rvalue references. /// /// \tparam Type type of the mandatory first argument /// \tparam Types types of any further arguments /// - /// \param T the first value to include in the `rosa::Message` - /// \param Ts optional further values to include in the `rosa::Message` + /// \param T the first value to include in the \c rosa::Message + /// \param Ts optional further values to include in the \c rosa::Message /// - /// \return new `message_t` object created from the given arguments + /// \return new \c rosa::message_t object created from the given arguments template static message_t create(Type &&T, Types &&... Ts) noexcept; - /// Represents the types of the values stored in `this` object. + /// Represents the types of the values stored in \p this object. /// - /// A valid, non-empty `rosa::Token` representing the types of the values - /// stored in `this` object. + /// A valid, non-empty \c rosa::Token representing the types of the values + /// stored in \p this object. const Token T; - /// The number of values stored in `this` object. + /// The number of values stored in \p this object. /// - /// That is the number of types encoded in `T`. + /// That is the number of types encoded in \c rosa::Message::T. const size_t Size; - /// Destroys `this` object. + /// Destroys \p this object. virtual ~Message(void); /// Tells if the value stored at a given index is of a given type. /// - /// \note Any `rosa::AtomConstant` is encoded in `rosa::Token` as - /// the `rosa::AtomValue` wrapped into it. + /// \note Any \c rosa::AtomConstant is encoded in \c rosa::Token as + /// the \c rosa::AtomValue wrapped into it. /// /// \tparam Type type to match against /// - /// \param Pos index the type of the value at is to be matched against `Type` + /// \param Pos index the type of the value at is to be matched against \p Type /// - /// \return if the value at index `Pos` of type `Type` + /// \return if the value at index \p Pos of type \p Type /// - /// \pre `Pos` is a valid index:\code + /// \pre \p Pos is a valid index:\code /// Pos < Size /// \endcode template bool isTypeAt(const size_t Pos) const noexcept; /// Gives a constant reference of a value of a given type stored at a given /// index. /// /// \tparam Type type to give a reference of /// /// \param Pos index to set the reference for /// - /// \return constant reference of `Type` for the value stored at index `Pos` + /// \return constant reference of \p Type for the value stored at index \p Pos /// - /// \pre `Pos` is a valid index and the value at index `Pos` is of type - /// `Type`:\code + /// \pre \p Pos is a valid index and the value at index \p Pos is of type + /// \p Type:\code /// Pos < Size && isTypeAt(Pos) /// \endcode template const Type &valueAt(const size_t Pos) const noexcept; protected: /// Provides an untyped pointer for the value at a given index. /// /// \param Pos index to take a pointer for /// - /// \return untyped pointer for the value stored at index `Pos` + /// \return untyped pointer for the value stored at index \p Pos /// - /// \pre `Pos` is a valid index:\code + /// \pre \p Pos is a valid index:\code /// Pos < Size /// \endcode virtual const void *pointerTo(const size_t Pos) const noexcept = 0; }; -/// Nested namespace with implementation for `rosa::Message`, consider it +/// Nested namespace with implementation for \c rosa::Message, consider it /// private. namespace { -/// Template class for an implementation of `rosa::Message`. +/// Template class for an implementation of \c rosa::Message. /// /// \tparam Types types whose values are to be stored template class LocalMessage; /// Initializes a pre-allocated memory area with values from constant lvalue /// references. /// /// \tparam Types types whose values are to be stored /// /// \param Arena pre-allocated memory area to store values to -/// \param Ts the values to store in `Arena` +/// \param Ts the values to store in \p Arena /// -/// \note `Arena` needs to be a valid pointer to a memory area big enough for -/// values of `Types`. +/// \note \p Arena needs to be a valid pointer to a memory area big enough for +/// values of \p Types. template inline void createMessageElements(void *const Arena, const Types &... Ts) noexcept; /// \defgroup createMessageElement from const lvalue references /// /// Stores values from constant lvalue references into a pre-allocated memory /// area. /// -/// \note To be used by the implementation of `rosa::createMessageElements`. +/// \note To be used by the implementation of \c createMessageElements. /// /// \todo Document these functions. ///@{ /// \note This terminal case is used for both constant lvalue references and /// value references. template inline void createMessageElement(void *const, const std::vector &Offsets) { ASSERT(Pos == Offsets.size()); } template inline void createMessageElement(void *const Arena, const std::vector &Offsets, const Type &T, const Types &... Ts) noexcept { ASSERT(Arena != nullptr && Pos < Offsets.size()); new (static_cast(static_cast(static_cast(Arena) + Offsets[Pos]))) Type(T); createMessageElement(Arena, Offsets, Ts...); } template inline void createMessageElement(void *const Arena, const std::vector &Offsets, const AtomConstant &, const Types &... Ts) noexcept { ASSERT(Arena != nullptr && Pos < Offsets.size()); *static_cast( static_cast(static_cast(Arena) + Offsets[Pos])) = V; createMessageElement(Arena, Offsets, Ts...); } ///@} /// Implementation of the template. /// /// \tparam Type the type of the mandatory first value to store /// \tparam Types types of any further values to store /// /// \param Arena pre-allocated memory area to store values to -/// \param T the first value to store in `Arena`˛ -/// \param Ts optional further values to store in `Arena` +/// \param T the first value to store in \p Arena˛ +/// \param Ts optional further values to store in \p Arena /// -/// \pre `Arena` is not `nullptr`. +/// \pre \p Arena is not \p nullptr. template inline void createMessageElements(void *const Arena, const Type &T, const Types &... Ts) noexcept { ASSERT(Arena != nullptr); createMessageElement<0>(Arena, LocalMessage::Offsets, T, Ts...); } /// Initializes a pre-allocated memory area with values from rvalue references. /// /// \tparam Types types whose values are to be stored /// /// \param Arena pre-allocated memory area to store values to -/// \param Ts the values to store in `Arena` +/// \param Ts the values to store in \p Arena /// -/// \note `Arena` needs to be a valid pointer to a memory area big enough for -/// values of `Types`. +/// \note \p Arena needs to be a valid pointer to a memory area big enough for +/// values of \p Types. template inline void createMessageElements(void *const Arena, Types &&... Ts) noexcept; /// \defgroup createMessageElement from rvalue references /// /// Stores values from rvalue references into a pre-allocated memory area. /// -/// \note To be used by the implementation of `rosa::createMessageElements`. +/// \note To be used by the implementation of \c createMessageElements. /// /// \todo Document these functions. ///@{ template inline void createMessageElement(void *const Arena, const std::vector &Offsets, Type &&T, Types &&... Ts) noexcept { ASSERT(Arena != nullptr && Pos < Offsets.size()); new (static_cast(static_cast( static_cast(Arena) + Offsets[Pos]))) Type(std::move(T)); createMessageElement(Arena, Offsets, std::move(Ts)...); } template inline void createMessageElement(void *const Arena, const std::vector &Offsets, AtomConstant &&, Types &&... Ts) noexcept { ASSERT(Arena != nullptr && Pos < Offsets.size()); *static_cast( static_cast(static_cast(Arena) + Offsets[Pos])) = V; createMessageElement(Arena, Offsets, std::move(Ts)...); } ///@} /// Implementation of the template. /// /// \tparam Type the type of the mandatory first value to store /// \tparam Types types of any further values to store /// /// \param Arena pre-allocated memory area to store values to -/// \param T the first value to store in `Arena`˛ -/// \param Ts optional further values to store in `Arena` +/// \param T the first value to store in \p Arena +/// \param Ts optional further values to store in \p Arena /// -/// \pre `Arena` is not `nullptr`. +/// \pre \p Arena is not \c nullptr. template inline void createMessageElements(void *const Arena, Type &&T, Types &&... Ts) noexcept { ASSERT(Arena != nullptr); createMessageElement<0>(Arena, LocalMessage::Offsets, std::move(T), std::move(Ts)...); } -/// Destroys values allocated by `rosa::createMessageElements`. +/// Destroys values allocated by \c createMessageElements. /// -/// \tparam Type type of the mandatory first value stored in `Arena` -/// \tparam Types futher types whose values are stored in `Arena` +/// \tparam Type type of the mandatory first value stored in \p Arena +/// \tparam Types futher types whose values are stored in \p Arena /// /// \param Arena the memory area to destroy values from /// -/// \note Arena needs to be a valid pointer to a memory area where values of -/// `Types` are stored. +/// \note \p Arena needs to be a valid pointer to a memory area where values of +/// \p Types are stored. template inline void destroyMessageElements(void *const Arena) noexcept; /// \defgroup destroyMessageElement /// /// Destroys values from a memory area. /// -/// \note To be used by the implementation of `rosa::destroyMessageElements`. +/// \note To be used by the implementation of \c destroyMessageElements. /// /// \todo Document these functions. ///@{ template inline void destroyMessageElement(void *const, const std::vector &Offsets) noexcept { ASSERT(Pos == Offsets.size()); } template inline void destroyMessageElement(void *const Arena, const std::vector &Offsets) noexcept { ASSERT(Arena != nullptr && Pos < Offsets.size()); static_cast( static_cast(static_cast(Arena) + Offsets[Pos])) ->~Type(); destroyMessageElement(Arena, Offsets); } ///@} /// Implementation of the template. /// /// \tparam Type the type of the mandatory first value to destroy /// \tparam Types types of any further values to destroy /// /// \param Arena the memory area to destroy values from /// -/// \pre `Arena` is not `nullptr`. +/// \pre \p Arena is not \c nullptr. template inline void destroyMessageElements(void *const Arena) noexcept { ASSERT(Arena != nullptr); destroyMessageElement<0, Type, Types...>( Arena, LocalMessage::Offsets); } -/// Implementation of the template `rosa::LocalMessage` providing facilities for -/// storing values as a `rosa::Message` object. +/// Implementation of the template \c rosa::LocalMessage providing facilities +/// for storing values as a \c rosa::Message object. /// -/// \tparam Type type of the first mandatory value of the `Message` +/// \tparam Type type of the first mandatory value of the \c rosa::Message /// \tparam Types of any further values template class LocalMessage : public Message { public: - /// `rosa::Token` for the stored values. + /// \c rosa::Token for the stored values. /// /// \note Only for compile-time checks! This static member is not defined - /// because it must be the same as `rosa::Message::T`. + /// because it must be the same as \c rosa::Message::T. static constexpr Token ST = TypeToken::type, typename std::decay::type...>::Value; - /// Byte offsets to access stored values in `Arena`. + /// Byte offsets to access stored values in \c LocalMessage::Arena. static const std::vector Offsets; private: /// A BLOB storing all the values one after the other. void *const Arena; - /// Generates byte offsets for accessing values stored in `Arena`. + /// Generates byte offsets for accessing values stored in + /// \c LocalMessage::Arena. /// - /// \return `std::vector` containing byte offsets for accessing values stored - /// in `Arena` + /// \return \c std::vector containing byte offsets for accessing values stored + /// in \c LocalMessage::Arena static std::vector offsets(void) noexcept { Token T = ST; // Need a mutable copy. - const size_t N = lengthOfToken(T); // Number of types encoded in T. - size_t I = 0; // Start indexing from position 0. + const size_t N = lengthOfToken(T); // Number of types encoded in \c T. + size_t I = 0; // Start indexing from position \c 0. std::vector O(N); // Allocate vector of proper size. - O[0] = 0; // First offset is always 0. + O[0] = 0; // First offset is always \c 0. while (I < N - 1) { ASSERT(I + 1 < O.size() && lengthOfToken(T) == N - I); // Calculate next offset based on the previous one. - // \note The offset of the last value is stored at O[N - 1], which is set - // when I == N - 2. Hence the limit of the loop. + // \note The offset of the last value is stored at `O[N - 1]`, which is + // set when `I == N - 2`. Hence the limit of the loop. O[I + 1] = O[I] + sizeOfHeadOfToken(T); dropHeadOfToken(T), ++I; } ASSERT(I + 1 == O.size() && lengthOfToken(T) == 1); return O; } public: /// Creates an instance from constant lvalue references. /// - /// \param T the mandatory first value to store in the `rosa::Message` object - /// \param Ts optional further values to store in the `rosa::Message` object + /// \param T the mandatory first value to store in the \c rosa::Message object + /// \param Ts optional further values to store in the \c rosa::Message object LocalMessage(const Type &T, const Types &... Ts) noexcept : Message(T, Ts...), Arena(::operator new(sizeOfValuesOfToken(ST))) { ASSERT(this->T == ST && Size == Offsets.size() && Arena != nullptr); // Sanity check. createMessageElements(Arena, T, Ts...); } /// Creates an instance from rvalue references. /// - /// \param T the mandatory first value to store in the `rosa::Message` object - /// \param Ts optional further values to store in the `rosa::Message` object + /// \param T the mandatory first value to store in the \c rosa::Message object + /// \param Ts optional further values to store in the \c rosa::Message object LocalMessage(Type &&T, Types &&... Ts) noexcept : Message(T, Ts...), Arena(::operator new(sizeOfValuesOfToken(ST))) { ASSERT(this->T == ST && Size == Offsets.size() && Arena != nullptr); // Sanity check. createMessageElements(Arena, std::move(T), std::move(Ts)...); } - // Destroys `this` object. + // Destroys \p this object. ~LocalMessage(void) { destroyMessageElements(Arena); ::operator delete(Arena); } /// Provides an untyped pointer for the constant value stored at a position. /// /// \param Pos the index of the value to return an untyped pointer for /// - /// \return untyped pointer for the constant value stored at index `Pos` + /// \return untyped pointer for the constant value stored at index \p Pos const void *pointerTo(const size_t Pos) const noexcept override { ASSERT(Pos < Offsets.size()); return static_cast(Arena) + Offsets[Pos]; } }; -// Implementation of the static member field `rosa::LocalMessage::Offsets`. +// Implementation of the static member field \c LocalMessage::Offsets. template const std::vector LocalMessage::Offsets = LocalMessage::offsets(); } // End namespace template Message::Message(const Type &, const Types &...) noexcept : T(TypeToken::type, typename std::decay::type...>::Value), Size(lengthOfToken(T)) { ASSERT(validToken(T) && lengthOfToken(T) == (1 + sizeof...(Types))); // Sanity check. LOG_TRACE("Creating Message with Token(" + to_string(T) + ")"); } /// \note The implementation instantiates a private local template class -/// `LocalMessage`. +/// \c LocalMessage. template message_t Message::create(const Type &T, const Types &... Ts) noexcept { return message_t(new LocalMessage(T, Ts...)); } /// \note The implementation instantiates a private local template class -/// `LocalMessage`. +/// \c LocalMessage. template message_t Message::create(Type &&T, Types &&... Ts) noexcept { return message_t( new LocalMessage(std::move(T), std::move(Ts)...)); } template bool Message::isTypeAt(const size_t Pos) const noexcept { ASSERT(Pos < Size); Token T_ = T; // NOLINT dropNOfToken(T_, Pos); return isHeadOfTokenTheSameType(T_); } template const Type &Message::valueAt(const size_t Pos) const noexcept { ASSERT(Pos < Size && isTypeAt(Pos)); return *static_cast(pointerTo(Pos)); } } // End namespace rosa #endif // ROSA_CORE_MESSAGE_HPP diff --git a/include/rosa/core/MessageHandler.hpp b/include/rosa/core/MessageHandler.hpp index abdc848..452e451 100644 --- a/include/rosa/core/MessageHandler.hpp +++ b/include/rosa/core/MessageHandler.hpp @@ -1,170 +1,170 @@ //===-- rosa/core/MessageHandler.hpp ----------------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \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. +/// \brief Facility for combining \c rosa::Invoker instances and applying +/// \c 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 namespace rosa { -/// Handles `rosa::Message` instances. +/// Handles \c 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. +/// A \c rosa::MessageHandler stores \c rosa::Invoker instances and tries to +/// apply \c rosa::Message objects to them in the order of definition.The first +/// matching \c rosa::Invoker instance is invoked with the \c rosa::Message +/// object, after which handling of that \c rosa::Message object is completed. /// /// For example, consider the following snippet: \code /// rosa::MessageHandler { /// rosa::Invoker::F([](uint8_t) { /* ... */ }), /// rosa::Invoker::F([](uint8_t) { /* Never invoked */ }) /// }; /// \endcode -/// Applying a `rosa::Message` with `rosa::TypeList` 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. +/// Applying a \c rosa::Message with \c rosa::TypeList invokes the +/// first function, and the second function would never be invoked because any +/// matching \c 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. + /// Type alias to bring \c rosa::Invoker::invoker_t to the local scope. using invoker_t = Invoker::invoker_t; - /// Type alias for a `std::vector` storing `rosa::Invoker` instances. + /// Type alias for a \c std::vector storing \c rosa::Invoker instances. using invokers_t = std::vector; - /// Stores `rosa::Invoker` instances. + /// Stores \c rosa::Invoker instances. const invokers_t Invokers; - /// Creates a container with `rosa::Invoker` instances from functions. + /// Creates a container with \c 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...` + /// \return \c rosa::MessageHandler::invokers_t object storing + /// \c rosa::Invoker instances created from the \p F and \p Fs... template 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. + /// Updates an \c rosa::MessageHandler::invokers_t object with a new + /// \c 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 I \c rosa::MessageHandler::invokers_t to update + /// \param Pos index at which to store the new \c rosa::Invoker instance + /// \param F function to wrap and store into \p I at index \p Pos /// \param Fs further functions to handle later /// - /// \pre `Pos` is a valid index:\code + /// \pre \p Pos is a valid index:\code /// Pos < I.size() /// \endcode template static inline void wrapFun(invokers_t &I, const size_t Pos, Fun &&F, Funs &&... Fs) noexcept; - /// Terminal case for the template `rosa::MessageHandler::wrapFun`. + /// Terminal case for the template \c rosa::MessageHandler::wrapFun. /// - /// \param I `invokers_t` which is now complete - /// \param Pos size of `I` + /// \param I \c rosa::MessageHandler::invokers_t which is now complete + /// \param Pos size of \p I /// - /// \pre `Pos` is the size of `I`:\code + /// \pre \p Pos is the size of \p 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. + /// \c 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 MessageHandler(Fun &&F, Funs &&... Fs) noexcept; - /// Destroys `this` object. + /// Destroys \p this object. virtual ~MessageHandler(void); - /// Tells if a `rosa::Message` object can be handled by `this` object. + /// Tells if a \c rosa::Message object can be handled by \p this object. /// - /// \param Msg `rosa::Message`to check + /// \param Msg \c rosa::Message to check /// - /// \return whether `this` object stores a `rosa::Invoker` instance that can - /// handle `Msg` + /// \return whether \p this object stores a \c rosa::Invoker instance that can + /// handle \p 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. + /// Applies a \c rosa::Message object to the first stored \c 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. + /// \note This operator finds the first applicable \c rosa::Invoker and + /// invokes it with the given \c rosa::Message object, while the member + /// function \c rosa::MessageHandler::canHandle only checks if there is any + /// \c rosa::Invoker that can be invoked with a given \c rosa::Message object. /// - /// \param Msg `rosa::Message` to use in invoking a matching `rosa::Invoker` + /// \param Msg \c rosa::Message to use in invoking a matching \c rosa::Invoker /// - /// \return whether there was a matching `rosa::Invoker` found and invoked - /// with `Msg`. + /// \return whether there was a matching \c rosa::Invoker found and invoked + /// with \p Msg bool operator()(const Message &Msg) const noexcept; }; template MessageHandler::MessageHandler(Fun &&F, Funs &&... Fs) noexcept : Invokers(createInvokers(std::move(F), std::move(Fs)...)) { LOG_TRACE("MessageHandler is created"); } template 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 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 diff --git a/include/rosa/core/MessageMatcher.hpp b/include/rosa/core/MessageMatcher.hpp index 74138b1..4407418 100644 --- a/include/rosa/core/MessageMatcher.hpp +++ b/include/rosa/core/MessageMatcher.hpp @@ -1,203 +1,203 @@ //===-- 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 -/// `rosa::Message` instances. +/// \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 `rosa::Message` instance and extract -/// stored values from it into an `std::tuple` instance with matching type +/// 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 `rosa::TypeList` to check the stored values against +/// \tparam List \c rosa::TypeList to check the stored values against template struct MessageMatcher; -/// Definition of `rosa::MessageMatcher` for non-empty lists of types, like -/// `rosa::Message` itself. +/// 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> { - /// `rosa::Token` associated to the give `rosa::TypeList`. + /// \c rosa::Token associated to the given \c rosa::TypeList. static constexpr Token T = TypeToken::Value; - /// Tells if the values stored in a `rosa::Message` instance are matching - /// types given as `rosa::TypeList`, considering - /// `rosa::AtomConstant` instead of `rosa::AtomValue`. + /// 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 `Message` to match + /// \param Msg \c rosa::Message to match /// - /// \return whether the types of values stored in `Msg` matches - /// `rosa::TypeList` + /// \return whether the types of values stored in \p Msg matches + /// \c rosa::TypeList static inline bool doesStronglyMatch(const Message &Msg) noexcept; - /// Gives a `std::tuple` with references to the values stored in a - /// type-matching instance of `rosa::Message`. + /// Gives a \c std::tuple with references to the values stored in a + /// type-matching instance of \c rosa::Message. /// - /// \param Msg `Message` to extract values from + /// \param Msg \c rosa::Message to extract values from /// - /// \return `tuple` with references to the values stored in `Msg` + /// \return \c std::tuple with references to the values stored in \p Msg /// - /// \pre Types of the values stored in `Msg` matches - /// `rosa::TypeList`:\code + /// \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 `rosa::TypeList` for `rosa::MessageMatcher`. +/// 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 `rosa::MessageMatcher`, -/// consider it private. +/// 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 -/// `rosa::MessageMatcher`. +/// \c rosa::MessageMatcher. /// ///@{ -/// Template declaration of `rosa::MessageMatcherImpl. +/// Template declaration of \c MessageMatcherImpl. /// -/// \tparam List `rosa::TypeList` to match against +/// \tparam List \c rosa::TypeList to match against template struct MessageMatcherImpl; -/// Specialization for `rosa::EmptyTypeList`. +/// Specialization for \c rosa::EmptyTypeList. template <> struct MessageMatcherImpl { static inline 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 { // 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 `rosa::AtomValue` in the head. +/// Specialization for \c rosa::AtomValue in the head. template struct MessageMatcherImpl, Ts...>> { static inline bool doesHeadStronglyMatchAt(const Message &Msg, const size_t Pos) noexcept { - // Matching an AtomConstant in the head if there is a type stored at Pos, - // the stored type is AtomValue, and the corresponding value matches the - // AtomValue V. + // 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 { // 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 &...> extractedValuesFrom(const Message &Msg, const size_t Pos) noexcept { - // Extracting for a non-empty list with a matching AtomConstant in the head - // by getting the encoded AtomConstant and concatenating it with values - // extracted for the rest of the list. + // 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 -/// `rosa::AtomConstant`) is in the head. +/// \c rosa::AtomConstant) is in the head. template struct MessageMatcherImpl> { static inline bool doesHeadStronglyMatchAt(const Message &Msg, const size_t Pos) noexcept { - // Matching the head if there is a type stored at Pos, and the stored type - // is T. + // 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 { // 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 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 T, then match against list with squashed integers the - // way `rosa::Token` is generated. + // \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 `rosa::Token` is + // \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 7ce5b53..62d0920 100644 --- a/include/rosa/core/MessagingSystem.hpp +++ b/include/rosa/core/MessagingSystem.hpp @@ -1,189 +1,189 @@ //===-- 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 `rosa::System` with messaging. +/// \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 `rosa::System` interface with features to create `rosa::Agent` -/// instancess and register `rosa::Message` objects for them. +/// 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; ///< `rosa::AgentHandle` is our friend. + friend class AgentHandle; ///< \c rosa::AgentHandle is our friend. public: - /// Returns an object implementing the `rosa::MessagingSystem` interface. + /// Returns an object implementing the \c rosa::MessagingSystem interface. /// /// \param Name name of the new instance /// - /// \return `std::unique_ptr` for the new instance of - /// `rosa::MessagingSystem` + /// \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 `rosa::Unit` instances as *agents*. + /// 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 `rosa::Agent` instance owned by `this` object and returns a - /// `rosa::AgentHandle` for it. + /// 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 `rosa::Agent` to instantiate - /// \tparam Funs types of the functions to instantiate `rosa::Agent` with + /// \tparam T type of the actual \c rosa::Agent to instantiate + /// \tparam Funs types of the functions to instantiate \c rosa::Agent with /// - /// \note `rosa::Agent` requires at least one function for its constructor, + /// \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 `Funs` for this template function. + /// zero \p Funs for this template function. /// - /// \param Name name of the new `rosa::Unit` instance - /// \param Fs functions to instantiate `rosa::Unit` with + /// \param Name name of the new \c rosa::Unit instance + /// \param Fs functions to instantiate \c rosa::Unit with /// - /// \pre Statically, `T` is a subclass of `rosa::Agent`:\code + /// \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 `rosa::Agent` instance for a `rosa::AgentHandle`. + /// Gives the references \c rosa::Agent instance for a \c rosa::AgentHandle. /// /// \note Intended for derived classes to be able to inspect - /// `rosa::AgentHandle` instances. + /// \c rosa::AgentHandle instances. /// - /// \param H `rosa::AgentHandle` to take the referenced `rosa::Agent` from + /// \param H \c rosa::AgentHandle to take the referenced \c rosa::Agent from /// - /// \return reference to the `rosa::Agent` instance from `H` + /// \return reference to the \c rosa::Agent instance from \p H static inline Agent &unwrapAgent(const AgentHandle &H) noexcept { return H.A; } - /// Gives the owning `rosa::MessagingSystem` of a `rosa::Agent` instance - /// for a `rosa::AgentHandle`. + /// 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 - /// `rosa::AgentHandle` instances. + /// \c rosa::AgentHandle instances. /// - /// \param H `rosa::AgentHandle` to take the owning - /// `rosa::MessagingSystem` from + /// \param H \c rosa::AgentHandle to take the owning + /// \c rosa::MessagingSystem from /// - /// \return reference to the `rosa::MessagingSystem` owning the - /// `rosa::agent` instance from `H` + /// \return reference to the \c rosa::MessagingSystem owning the + /// \c rosa::Agent instance from \p H static inline MessagingSystem &unwrapSystem(const AgentHandle &H) noexcept { return H.S; } public: - /// Sends a `rosa::message_t` instance to the `rosa::Agent`instance referred - /// by a `rosa::AgentHandle`. + /// Sends a \c rosa::message_t instance to the \c rosa::Agent instance + /// referred by a \c rosa::AgentHandle. /// - /// \note If the given `rosa::Message` object cannot be handled by the - /// referred `rosa::Agent` instance, the `rosa::Message` object is simply + /// \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 `rosa::Agent` instance to send to + /// \param H refers to the \c rosa::Agent instance to send to /// \param M message to send /// - /// \pre The referred `rosa::Agent` instance is owned by `this` object and + /// \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 `rosa::Agent`instance referred by a `rosa::AgentHandle`. + /// to the \c rosa::Agent instance referred by a \c rosa::AgentHandle. /// - /// \note If the given `rosa::Message` object cannot be handled by the - /// referred `rosa::Agent` instance, the `rosa::Message` object is simply + /// \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 `rosa::Agent` instance to send to + /// \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 `rosa::Agent` instance is owned by `this` object and + /// \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 `rosa::Agent`instance referred by a `rosa::AgentHandle`. + /// to the \c rosa::Agent instance referred by a \c rosa::AgentHandle. /// - /// \note If the given `rosa::Message` object cannot be handled by the - /// referred `rosa::Agent` instance, the `rosa::Message` object is simply + /// \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 `rosa::Agent` instance to send to + /// \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 `rosa::Agent` instance is owned by `this` object and + /// \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/include/rosa/core/System.hpp b/include/rosa/core/System.hpp index f575745..98d6608 100644 --- a/include/rosa/core/System.hpp +++ b/include/rosa/core/System.hpp @@ -1,213 +1,215 @@ //===-- rosa/core/System.hpp ------------------------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file rosa/core/System.hpp /// /// \author David Juhasz (david.juhasz@tuwien.ac.at) /// /// \date 2017 /// /// \brief Declaration of *System* interface. /// //===----------------------------------------------------------------------===// #ifndef ROSA_CORE_SYSTEM_HPP #define ROSA_CORE_SYSTEM_HPP #include "rosa/config/config.h" #include "rosa/core/forward_declarations.h" #include "rosa/support/debug.hpp" #include "rosa/support/log.h" #include #include #include namespace rosa { /// Base interface for actual agent-systems. /// -/// The class provides facilities to keep track of `rosa::Unit` instances owned -/// by `this` `rosa::System`. +/// The class provides facilities to keep track of \c rosa::Unit instances owned +/// by a \c rosa::System. /// /// \note Any subclass is supposed to provide thread-safe implementation. /// /// \note The class declares only an interface to avoid trouble with multiple /// inheritance in various subclasses as in derived interfaces and derived /// implementations. /// -/// \note Actual implementations are supposed to derive from `rosa::SystemBase` +/// \note Actual implementations are supposed to derive from \c rosa::SystemBase /// implenenting a base feature-set. class System { public: - /// Signature of creator functions for `rosa::Unit` instances. + /// Signature of creator functions for \c rosa::Unit instances. /// - /// \tparam T type derived from `rosa::Unit` - /// \tparam S type derived from `rosa::System` + /// \tparam T type derived from \c rosa::Unit + /// \tparam S type derived from \c rosa::System template using UnitCreator = std::function; - /// Returns an object implementing the `rosa::System` interface. + /// Returns an object implementing the \c rosa::System interface. /// /// \param Name name of the new instance /// - /// \return `std::unique_ptr` for a new instance of `rosa::System` + /// \return \c std::unique_ptr for a new instance of \c rosa::System static std::unique_ptr createSystem(const std::string &Name) noexcept; protected: /// Creates an instance. /// - ///\note Protected constructor restricts instantiation for subclasses. + /// \note Protected constructor restricts instantiation for subclasses. System(void) noexcept = default; - /// No copying and moving of `rosa::System`. + /// No copying and moving of \c rosa::System. ///@{ System(const System&) = delete; System(System&&) = delete; System &operator=(const System&) = delete; System &operator=(System&&) = delete; ///@} public: - /// Destroys `this` object. + /// Destroys \p this object. /// - /// \note Any implementation makes sure that a `rosa::System` can be + /// \note Any implementation makes sure that a \c rosa::System can be /// destroyed only if it is marked *cleaned* - /// \see rosa::System::isSystemCleaned + /// \see \c rosa::System::isSystemCleaned virtual ~System(void) = default; protected: /// Tells the next unique identifier to be used for a newly created - /// `rosa::Unit`. + /// \c rosa::Unit. /// - /// \return `id_t` which is unique within the context of `this` object. + /// \return \c rosa::id_t which is unique within the context of \p this + /// object. /// /// \note Never returs the same value twice. virtual id_t nextId(void) noexcept = 0; - /// Tells if `this` object has been marked cleaned and is ready for + /// Tells if \p this object has been marked cleaned and is ready for /// destruction. /// - /// \return if `this` object is marked clean. + /// \return if \p this object is marked clean. virtual bool isSystemCleaned(void) const noexcept = 0; - /// Marks `this` object cleaned. + /// Marks \p this object cleaned. /// /// \note Can be called only once when the System does not have any live - /// `rosa::Unit` instances. + /// \c rosa::Unit instances. /// - /// \pre `this` object has not yet been marked as cleaned and it has no - /// `rosa::Unit` instances registered:\code + /// \pre \p this object has not yet been marked as cleaned and it has no + /// \c rosa::Unit instances registered:\code /// !isSystemCleaned() && empty() /// \endcode /// - /// \post `this` object is marked cleaned:\code + /// \post \p this object is marked cleaned:\code /// isSystemCleaned() /// \encode virtual void markCleaned(void) noexcept = 0; - /// Registers a `rosa::Unit` instance to `this` object. + /// Registers a \c rosa::Unit instance to \p this object. /// - /// \param U `rosa::Unit` to register + /// \param U \c rosa::Unit to register /// - /// \pre `this` object has not yet been marked as cleaned and `U` is not + /// \pre \p this object has not yet been marked as cleaned and \p U is not /// registered yet:\code /// !isSystemCleaned() && !isUnitRegistered(U) /// \endcode /// - /// \post `U` is registered:\code + /// \post \p U is registered:\code /// isUnitRegistered(U) /// \endcode virtual void registerUnit(Unit &U) noexcept = 0; - /// Unregisters and destroys a registered `rosa::Unit` instance. + /// Unregisters and destroys a registered \c rosa::Unit instance. /// - /// \param U `rosa::Unit` to destroy + /// \param U \c rosa::Unit to destroy /// - /// \pre `U` is registered:\code + /// \pre \p U is registered:\code /// isUnitRegistered(U) /// \endcode /// - /// \post `U` is not registered:\code + /// \post \p U is not registered:\code /// !isUnitRegistered(U) - /// \endcode Moreover, `U` is destroyed. + /// \endcode Moreover, \p U is destroyed. virtual void destroyUnit(Unit &U) noexcept = 0; - /// Tells if a `rosa::Unit` is registered in `this` object. + /// Tells if a \c rosa::Unit is registered in \p this object. /// - /// \param U `rosa::Unit` to check + /// \param U \c rosa::Unit to check /// - /// \return whether `U` is registered in `this` object + /// \return whether \p U is registered in \p this object virtual bool isUnitRegistered(const Unit &U) const noexcept = 0; - /// Creates a `rosa::Unit` instance with the given `rosa::System::UnitCreator` - /// and registers the new instance. + /// Creates a \c rosa::Unit instance with the given + /// \c rosa::System::UnitCreator and registers the new instance. /// - /// \tparam T type of the actual `rosa::Unit` to instantiate - /// \tparam S type of the actual `rosa::System` instantiating + /// \tparam T type of the actual \c rosa::Unit to instantiate + /// \tparam S type of the actual \c rosa::System instantiating /// - /// \param C function creating an instance of type `T` + /// \param C function creating an instance of type \p T /// - /// \note `S` must be the actual subclass that wants to instantiate - /// `rosa::Unit`. That cannot be statically enforced, it is the - /// reponsibility of the caller to provide the proper `rosa::System` subclass. + /// \note \p S must be the actual subclass that wants to instantiate + /// \c rosa::Unit. That cannot be statically enforced, it is the + /// reponsibility of the caller to provide the proper \c rosa::System + /// subclass. /// - /// \pre Statically, `T` is a subclass of `rosa::Unit` and `S` is a subclass - /// of `rosa::System`:\code + /// \pre Statically, \p T is a subclass of \c rosa::Unit and \p S is a + /// subclass of \c rosa::System:\code /// std::is_base_of::value && std::is_base_of::value - /// \endcode Dynamically, `this` object has not yet been marked cleaned:\code + /// \endcode Dynamically, \p this object has not yet been marked cleaned:\code /// !isSystemCleaned() /// \endcode template T &createUnit(UnitCreator C) noexcept; public: - /// Tells the name of `this` object + /// Tells the name of \p this object /// - /// \note The returned reference remains valid as long as `this` object is not - /// destroyed. + /// \note The returned reference remains valid as long as \p this object is + /// not destroyed. /// - /// \return name of `this` object + /// \return name of \p this object virtual const std::string &name(void) const noexcept = 0; - /// Tells the number of `rosa::Unit` instances constructed in the context of - /// `this`object so far, including those being already destroyed. + /// Tells the number of \c rosa::Unit instances constructed in the context of + /// \p this object so far, including those being already destroyed. /// - /// \return number of `rosa::Unit`instances created so far + /// \return number of \c rosa::Unit instances created so far virtual size_t numberOfConstructedUnits(void) const noexcept = 0; - /// Tells the number of live `rosa::Unit` instances in the context `this` + /// Tells the number of live \c rosa::Unit instances in the context \p this /// object, those being constructed and not destroyed yet. /// - /// \return number of `rosa::Unit` instances alive + /// \return number of \c rosa::Unit instances alive virtual size_t numberOfLiveUnits(void) const noexcept = 0; - /// Tells if `this` object has no live `rosa::Unit` instances. + /// Tells if \p this object has no live \c rosa::Unit instances. /// - /// \return whether `this` object has any live `rosa::Unit` instances + /// \return whether \p this object has any live \c rosa::Unit instances virtual bool empty(void) const noexcept = 0; }; template T &System::createUnit(UnitCreator C) noexcept { STATIC_ASSERT((std::is_base_of::value), "not a Unit"); STATIC_ASSERT((std::is_base_of::value), "not a System"); if (isSystemCleaned()) { ROSA_CRITICAL("Trying to create a Unit in a cleaned System (" + name() + ")"); } const id_t Id = nextId(); T *U = C(Id, static_cast(*this)); registerUnit(*U); LOG_TRACE("Unit created and registered (" + U->FullName + ")"); return *U; } } // End namespace rosa #endif // ROSA_CORE_SYSTEM_HPP diff --git a/include/rosa/core/SystemBase.hpp b/include/rosa/core/SystemBase.hpp index df861a8..4e50b62 100644 --- a/include/rosa/core/SystemBase.hpp +++ b/include/rosa/core/SystemBase.hpp @@ -1,125 +1,128 @@ //===-- rosa/core/SystemBase.hpp -----------------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file rosa/core/SystemBase.hpp /// /// \author David Juhasz (david.juhasz@tuwien.ac.at) /// /// \date 2017 /// -/// \brief Base implementation of the `rosa::System` interface. +/// \brief Base implementation of the \c rosa::System interface. /// //===----------------------------------------------------------------------===// #ifndef ROSA_CORE_SYSTEMBASE_HPP #define ROSA_CORE_SYSTEMBASE_HPP #include "rosa/core/System.hpp" #include namespace rosa { -/// Base implementation of the `rosa::System` interface. +/// Base implementation of the \c rosa::System interface. /// -/// This implementation provides only *name* for `rosa::System`, identifiers for -/// `rosa::Unit` instances, and marking the `rosa::System` cleaned for +/// This implementation provides only *name* for \c rosa::System, identifiers +/// for \c rosa::Unit instances, and marking the \c rosa::System cleaned for /// destruction. /// -/// \note Actual implementations of `rosa::System` and derived interfaces are +/// \note Actual implementations of \c rosa::System and derived interfaces are /// supposed to inherit from this implementation. class SystemBase : public System { protected: /// Creates an instance. /// /// \note Protected constructor restrict instantiation for subclasses. /// /// \param Name name of the new instance SystemBase(const std::string &Name) noexcept; public: - /// Destroys `this` object. + /// Destroys \p this object. /// - /// \pre `this`object is marked cleaned:\code + /// \pre \p this object is marked cleaned:\code /// isSystemCleaned() /// \endcode ~SystemBase(void); protected: - /// The textual name of `this` object implementing `rosa::System`. + /// The textual name of \p this object implementing \c rosa::System. const std::string Name; private: - /// Number of `rosa::Unit` instances constructed by `this` object. + /// Number of \c rosa::Unit instances constructed by \p this object. /// /// \note Should never be decremented! std::atomic UnitCount; - /// Indicates that `this` object has been cleaned and is ready for + /// Indicates that \p this object has been cleaned and is ready for /// destruction. /// - /// The field is initialized as 'false' and can be set by - /// `rosa::SystemBase::markCleaned`. + /// The field is initialized as \c false and can be set by + /// \c rosa::SystemBase::markCleaned. /// /// \note Subclasses must set the flag upon destructing their instances, which /// indicates to the destructor of the base-class that all the managed /// resources has been properly released. std::atomic SystemIsCleaned; public: - /// Tells the name of `this` object + /// Tells the name of \p this object /// - /// \note The returned reference remains valid as long as `this` object is not - /// destroyed. + /// \note The returned reference remains valid as long as \p this object is + /// not destroyed. /// - /// \return reference to `Name` + /// \return reference to \c rosa::SystemBase::Name const std::string &name(void) const noexcept override; protected: /// Tells the next unique identifier to be used for a newly created - /// `rosa::Unit` and increments the internal counter - /// `rosa::SystemBase::UnitCount`. + /// \c rosa::Unit. + /// + /// The functions takes the current value of the internal counter + /// \c rosa::SystemBase::UnitCount and then increments it. /// /// \note This is the only function modifying - /// `rosa::SystemBase::UnitCount`. + /// \c rosa::SystemBase::UnitCount. /// - /// \return `id_t` which is unique within the context of `this` object. + /// \return \c rosa::id_t which is unique within the context of \p this + /// object. id_t nextId(void) noexcept override; - /// Tells if `this` object has been marked cleaned and is ready for + /// Tells if \p this object has been marked cleaned and is ready for /// destruction. /// - /// \return if `this` object is marked clean. + /// \return if \p this object is marked clean. bool isSystemCleaned(void) const noexcept override; - /// Marks `this` object cleaned by setting - /// `rosa::SystemBase::SystemIsCleaned`. + /// Marks \p this object cleaned by setting + /// \c rosa::SystemBase::SystemIsCleaned. /// /// \note Can be called only once when the System does not have any live - /// `rosa::Unit` instances. + /// \c rosa::Unit instances. /// - /// \pre `this` object has not yet been marked as cleaned and it has no - /// `rosa::Unit` instances registered:\code + /// \pre \p this object has not yet been marked as cleaned and it has no + /// \c rosa::Unit instances registered:\code /// !isSystemCleaned() && empty() /// \endcode /// - /// \post `this` object is marked cleaned:\code + /// \post \p this object is marked cleaned:\code /// isSystemCleaned() /// \encode void markCleaned(void) noexcept override; - /// Tells the number of `rosa::Unit` instances constructed in the context of - /// `this`object so far, including those being already destroyed. + /// Tells the number of \c rosa::Unit instances constructed in the context of + /// \p this object so far, including those being already destroyed. /// - /// \return current value of `rosa::SystemBase::UnitCount` that is the number - /// of `rosa::Unit`instances created so far + /// \return current value of \c rosa::SystemBase::UnitCount that is the number + /// of \c rosa::Unit instances created so far size_t numberOfConstructedUnits(void) const noexcept override; }; } // End namespace rosa #endif // ROSA_LIB_CORE_SYSTEMBASE_HPP diff --git a/include/rosa/core/Unit.h b/include/rosa/core/Unit.h index 0a5b61d..a443b08 100644 --- a/include/rosa/core/Unit.h +++ b/include/rosa/core/Unit.h @@ -1,120 +1,116 @@ //===-- rosa/core/Unit.h ----------------------------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file rosa/core/Unit.h /// /// \author David Juhasz (david.juhasz@tuwien.ac.at) /// /// \date 2017 /// -/// \brief Declaration of `rosa::Unit` base-class. +/// \brief Declaration of \c rosa::Unit base-class. /// //===----------------------------------------------------------------------===// #ifndef ROSA_CORE_UNIT_H #define ROSA_CORE_UNIT_H #include "rosa/support/atom.hpp" #include "rosa/core/forward_declarations.h" #include #include namespace rosa { -/// Base class for every entity in a `rosa::System` that has to be identified +/// Base class for every entity in a \c rosa::System that has to be identified /// and traced. /// -/// \note Life-cycle of `rosa::Unit` instances is supposed to be managed by the -/// `rosa::System` owning the instance, do not create and destroy any -/// `rosa::Unit` directly. +/// \note Life-cycle of \c rosa::Unit instances is supposed to be managed by the +/// \c rosa::System owning the instance, do not create and destroy any +/// \c rosa::Unit directly. class Unit { public: - /// Identifies the *kind* of `this` object. + /// Identifies the *kind* of \p this object. /// - /// \note Kind is dependent on the `rosa::System` owning `this` object. + /// \note Kind is dependent on the \c rosa::System owning \p this object. const AtomValue Kind; - /// Unique identifier for `this` object. + /// Unique identifier for \p this object. /// - /// The unique identifier is assigned by the `rosa::System` owning `this` - /// object and is based on `rosa::System::CountUnits` of the owning - /// `rosa::System`. + /// \note The unique identifier is assigned by the \c rosa::System owning + /// \p this object upon creation. const id_t Id; - /// Textual identifier of `this` object. + /// Textual identifier of \p this object. /// - /// The textual identifier defaults to a text referring to `Id`, unless - /// otherwise defined via an argument for the constructor. - /// - /// \note `Name` of a `rosa::Unit` instance is not necessarily unique in the - /// owning `rosa::System`. + /// \note Textual identifiers of \c rosa::Unit instances are not necessarily + /// unique in their owning \c rosa::System. const std::string Name; protected: - /// The `rosa::System` owning `this` object. + /// The \c rosa::System owning \p this object. System &S; public: - /// Full qualified name of `this` object. + /// Full qualified name of \p this object. const std::string FullName; public: /// Creates a new instnace. /// /// \param Kind the kind of the new instance /// \param Id the unique identifier of the new instance /// \param Name the name of the new instance - /// \param S `rosa::System` owning the new instance + /// \param S \c rosa::System owning the new instance /// - /// \pre `Name` is not empty:\code + /// \pre \p Name is not empty:\code /// !Name.empty() /// \endcode Unit(const AtomValue Kind, const id_t Id, const std::string &Name, System &S) noexcept; - /// No copying and moving of `rosa::Unit` instances is possible. + /// No copying and moving of \c rosa::Unit instances is possible. ///@{ Unit(const Unit &) = delete; Unit(Unit &&) = delete; Unit &operator=(const Unit &) = delete; Unit &operator=(Unit &&) = delete; ///@} - /// Destroys `this` object. + /// Destroys \p this object. virtual ~Unit(void); - /// Dumps `this` object into a `std::string` for tracing purposes. + /// Dumps \p this object into a \c std::string for tracing purposes. /// /// Subclasses are supposed to override this function. /// - /// \return `string` representing the state of `this` object + /// \return \c std::string representing the state of \p this object virtual std::string dump(void) const noexcept; protected: - /// Returns a reference to the `rosa::System` owning `this` object. + /// Returns a reference to the \c rosa::System owning \p this object. /// /// \note Subclasses may override the function to return a reference of a - /// subtype of `rosa::System`. + /// subtype of \c rosa::System. /// - /// \return reference of `S` + /// \return reference of \c rosa::Unit::S virtual System &system() const noexcept; }; -/// Dumps a `rosa::Unit` isntance to a given `std::ostream`. +/// Dumps a \c rosa::Unit instance to a given \c std::ostream. /// /// \param [in,out] OS output stream to dump to -/// \param U `Unit` to dump +/// \param U \c rosa::Unit to dump /// -/// \return `OS` after dumping `U` to it +/// \return \p OS after dumping \p U to it std::ostream &operator<<(std::ostream &OS, const Unit &U); } // End namespace rosa #endif // ROSA_CORE_UNIT_H diff --git a/include/rosa/core/forward_declarations.h b/include/rosa/core/forward_declarations.h index 360aa56..f812700 100644 --- a/include/rosa/core/forward_declarations.h +++ b/include/rosa/core/forward_declarations.h @@ -1,41 +1,41 @@ //===-- rosa/core/forward_declarations.h ------------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file rosa/core/forward_declarations.h /// /// \author David Juhasz (david.juhasz@tuwien.ac.at) /// /// \date 2017 /// /// \brief Necessary forward declarations of types in the *Core* library. /// //===----------------------------------------------------------------------===// #ifndef ROSA_CORE_FORWARD_DECLARATIONS_H #define ROSA_CORE_FORWARD_DECLARATIONS_H #include namespace rosa { // Forward declarations of classes. class Agent; class Message; class MessagingSystem; class System; class Unit; -/// Type alias used for `rosa::Unit` identifiers. +/// Type alias used for \c rosa::Unit identifiers. using id_t = uint64_t; -/// Type of a `std::unique_ptr` for an immutable *Message*, `rosa::Message` +/// Type of a \c std::unique_ptr for an immutable *Message*, \c rosa::Message /// instance. using message_t = std::unique_ptr; } // End namespace rosa #endif // ROSA_CORE_FORWARD_DECLARATIONS_H diff --git a/include/rosa/support/atom.hpp b/include/rosa/support/atom.hpp index 09216d7..6762801 100644 --- a/include/rosa/support/atom.hpp +++ b/include/rosa/support/atom.hpp @@ -1,179 +1,183 @@ //===-- rosa/support/atom.hpp -----------------------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file rosa/support/atom.hpp /// /// \author David Juhasz (david.juhasz@tuwien.ac.at) /// /// \date 2017 /// -/// \brief Facility for `atom`s, short strings statically encoded as integers. +/// \brief Facility for *atoms*, short strings statically encoded as integers. /// -/// \note This implementation is based on the `atom` implementation of CAF. +/// \note This implementation is based on the \c atom implementation of CAF. /// \todo Check license. /// -/// `Atom`s can be used to turn short string literals into statically generated -/// types. The literals may consist of at most `10` non-special characters, legal -/// characters are `_0-9A-Za-z` and the whitespace character. Special characters -/// are turned into whitespace, which may result in different string literals -/// being encoded into the same integer value, if any of those contain at least -/// one special character. +/// *Atoms* can be used to turn short string literals into statically generated +/// types. The literals may consist of at most \c 10 non-special characters, +/// legal characters are \c _0-9A-Za-z and the whitespace character. Special +/// characters are turned into whitespace, which may result in different string +/// literals being encoded into the same integer value, if any of those contain +/// at least one special character. /// /// \note The usage of special characters in the string literals used to create -/// `atoms` cannot be checked by the compiler. +/// *atoms* cannot be checked by the compiler. /// /// Example: /// /// \code /// constexpr AtomValue NameValue = atom("name"); /// using NameAtom = AtomConstant; /// /// [](NameAtom){ std::cout << "Argument of type NameAtom"; }(NameAtom::Value) /// \endcode /// //===----------------------------------------------------------------------===// #ifndef ROSA_SUPPORT_ATOM_HPP #define ROSA_SUPPORT_ATOM_HPP #include "rosa/support/debug.hpp" namespace rosa { /// Maximal length of valid atom strings. constexpr size_t MaxAtomLength = 10; /// Underlying integer type of atom values. using atom_t = uint64_t; -/// Turn `rosa::atom_t` into a strongly typed enumeration. +/// Turn \c rosa::atom_t into a strongly typed enumeration. /// -/// Values of `rosa::atom_t` casted to `rosa::AtomValue` may be used in a +/// Values of \c rosa::atom_t casted to \c rosa::AtomValue may be used in a /// type-safe way. enum class AtomValue : atom_t {}; /// Anonymous namespace with implementational details, consider it private. namespace { +// clang-format off + /// Encodes ASCII characters to 6-bit encoding. constexpr unsigned char AtomEncodingTable[] = { /* ..0 ..1 ..2 ..3 ..4 ..5 ..6 ..7 ..8 ..9 ..A ..B ..C ..D ..E ..F */ /* 0.. */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1.. */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2.. */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 3.. */ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0, 0, 0, 0, 0, 0, /* 4.. */ 0, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, /* 5.. */ 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 0, 0, 0, 0, 37, /* 6.. */ 0, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, /* 7.. */ 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 0, 0, 0, 0, 0}; +// clang-format on + /// Decodes 6-bit characters to ASCII constexpr char AtomDecodingTable[] = " 0123456789" "ABCDEFGHIJKLMNOPQRSTUVWXYZ_" "abcdefghijklmnopqrstuvwxyz"; /// Encodes one character and updates the integer representation. /// /// \param Current an encoded value -/// \param CharCode a character to add to `Current` +/// \param CharCode a character to add to \p Current /// -/// \return `Current` updated with `CharCode` +/// \return \p Current updated with \p CharCode constexpr atom_t nextInterim(atom_t Current, size_t CharCode) { return (Current << 6) | AtomEncodingTable[(CharCode <= 0x7F) ? CharCode : 0]; } -/// Encodes a C-string into an integer value to be used as `rosa::AtomValue`. +/// Encodes a C-string into an integer value to be used as \c rosa::AtomValue. /// /// \param CStr a string to encode -/// \param Interim encoded value to add `CStr` to it +/// \param Interim encoded value to add \p CStr to it /// -/// \return `Interim` updated with `CStr` +/// \return \p Interim updated with \p CStr constexpr atom_t atomValue(const char *CStr, atom_t Interim = 0xF) { return (*CStr == '\0') ? Interim : atomValue(CStr + 1, nextInterim(Interim, static_cast(*CStr))); } } // End namespace -/// Converts a `rosa::AtomValue` into `std::string`. +/// Converts a \c rosa::AtomValue into \c std::string. /// /// \param What value to convert /// -/// \return the `string` encoded in `What` +/// \return \c std::string encoded in \p What std::string to_string(const AtomValue &What); -/// Converts a `std::string` into a `rosa::AtomValue`. +/// Converts a \c std::string into a \c rosa::AtomValue. /// -/// \param S the `string` to convert +/// \param S \c std::string to convert /// -/// \return `AtomValue` representation of `S` +/// \return \c rosa::AtomValue representing \p S AtomValue atom_from_string(const std::string &S); -/// Converts a string-literal into a `rosa::AtomValue`. +/// Converts a string-literal into a \c rosa::AtomValue. /// -/// \tparam Size the length of `Str` +/// \tparam Size the length of \p Str /// /// \param Str the string-literal to convert /// -/// \return `AtomValue` representation of `Str` +/// \return \c rosa::AtomValue representating \p Str /// -/// \pre `Str` is not too long:\code +/// \pre \P Str is not too long:\code /// Size <= MaxAtomLength + 1 /// \endcode template constexpr AtomValue atom(char const (&Str)[Size]) { // Last character is the NULL terminator. STATIC_ASSERT(Size <= MaxAtomLength + 1, "Too many characters in atom definition"); return static_cast(atomValue(Str)); } -/// Lifts a `rosa::AtomValue` to a compile-time constant. +/// Lifts a \c rosa::AtomValue to a compile-time constant. /// -/// \tparam V the `AtomValue` to lift +/// \tparam V \c rosa::AtomValue to lift template struct AtomConstant { - /// Ctor, has to do nothing. + /// Constructor has to do nothing. constexpr AtomConstant(void) {} /// Returns the wrapped value. /// - /// \return `V` + /// \return \p V constexpr operator AtomValue(void) const { return V; } - /// Returns the wrapped value as of type `rosa::atom_t`. + /// Returns the wrapped value as of type \c rosa::atom_t. /// - /// \return `atom_t` value from `V` + /// \return \c rosa::atom_t value from \p V static constexpr atom_t value() { return static_cast(V); } - /// An instance *of this constant* (*not* an `rosa::AtomValue`). + /// An instance *of this constant* (*not* a \c rosa::AtomValue). static const AtomConstant Value; }; -// Implementation of the static member field `Value` of `rosa::AtomConstant`. +// Implementation of the static member field \c rosa::AtomConstant::Value. template const AtomConstant AtomConstant::Value = AtomConstant{}; -/// Converts a `rosa::AtomConstant` into `std::string`. +/// Converts a \c rosa::AtomConstant into \c std::string. /// -/// \tparam V `AtomValue` to convert +/// \tparam V \c rosa::AtomValue to convert /// -/// \note The actual argument of type `const AtomConstant` is ignored -/// because the `AtomValue` to convert is encoded in the type itself. +/// \note The actual argument of type `const rosa::AtomConstant` is ignored +/// because the \c rosa::AtomValue to convert is encoded in the type itself. /// -/// \return the original string encoded in `V` +/// \return the original string encoded in \p V template std::string to_string(const AtomConstant &) { return to_string(V); } } // End namespace rosa #endif // ROSA_SUPPORT_ATOM_HPP diff --git a/include/rosa/support/debug.hpp b/include/rosa/support/debug.hpp index 279ac71..3f7872e 100644 --- a/include/rosa/support/debug.hpp +++ b/include/rosa/support/debug.hpp @@ -1,128 +1,128 @@ //===-- rosa/support/debug.hpp ----------------------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file rosa/support/debug.hpp /// /// \author David Juhasz (david.juhasz@tuwien.ac.at) /// /// \date 2017 /// /// \brief Facility for debugging /// //===----------------------------------------------------------------------===// #ifndef ROSA_SUPPORT_DEBUG_HPP #define ROSA_SUPPORT_DEBUG_HPP #include "rosa/config/config.h" #include "rosa/support/type_helper.hpp" #include "rosa/support/terminal_colors.h" #include #include namespace rosa { /// Returns an output stream to use for debugging. std::ostream &dbgs(void); -/// Prints an `std::array` to an `std::ostream`. +/// Prints a \c std::array to a \c std::ostream. /// -/// \tparam T type of values stored in `A` -/// \tparam Size number of elements in `A` +/// \tparam T type of values stored in \p A +/// \tparam Size number of elements in \p A /// -/// \param [in,out] OS `ostream` to print to -/// \param A `array` to print to `OS` +/// \param [in,out] OS \c std::ostream to print to +/// \param A \c std::array to print to \p OS /// -/// \return `OS` after printing `A` +/// \return \p OS after printing \p A template std::ostream &operator<<(std::ostream &OS, const std::array &A) { OS << '['; for (unsigned I = 0; I < Size; ++I) { if (I) { OS << ','; } OS << PRINTABLE(A[I]); } OS << ']'; return OS; } } // End namespace rosa /// \def ASSERT(stmt) /// \brief Enforces an assertion. /// -/// \note Takes effect only when `ROSA_ENABLE_ASSERTIONS` is defined. +/// \note Takes effect only when \c ROSA_ENABLE_ASSERTIONS is defined. /// -/// Checks if `stmt` evaluates to true. If not, prints an error message about +/// Checks if \p stmt evaluates to true. If not, prints an error message about /// violating the assertion and aborts execution. /// -/// \param stmt statement to evaluate, needs to be convertable to `bool` +/// \param stmt statement to evaluate, needs to be convertable to \c bool #ifndef ROSA_ENABLE_ASSERTIONS #define ASSERT(stmt) ROSA_IGNORE_UNUSED(stmt) #elif defined(ROSA_WINDOWS) #define ASSERT(stmt) \ if (static_cast(stmt) == false) { \ rosa::dbgs() << rosa::terminal::Color::Default << __FILENAME__ << ":" \ << __LINE__ << ": requirement failed: '" << #stmt << "'" \ << std::endl; \ ::abort(); \ } \ ROSA_VOID_STMT #else // defined(ROSA_LINUX) #include #define ASSERT(stmt) \ if (static_cast(stmt) == false) { \ rosa::dbgs() << rosa::terminal::Color::Default << __FILENAME__ << ":" \ << __LINE__ << ": requirement failed: '" << #stmt << "'" \ << std::endl; \ void *array[20]; \ auto bt_size = ::backtrace(array, 20); \ ::backtrace_symbols_fd(array, bt_size, 2); \ ::abort(); \ } \ ROSA_VOID_STMT #endif // defined(ROSA_ENABLE_ASSERTIONS) /// \def DEBUG(X) -/// \brief Executes the given piece of code only if `NDEBUG` is not defined. +/// \brief Executes the given piece of code only if \c NDEBUG is not defined. /// /// \param X the code to execute /// \def DEBUGVAR(V) /// \brief Dumps the given variable to the default debug output. /// /// \param V the variable to dump /// -/// \sa rosa::dbgs() +/// \sa \c rosa::dbgs() #ifndef NDEBUG #define DEBUG(X) \ do { \ X; \ } while (false) #define DEBUGVAR(V) \ do { \ rosa::dbgs() << rosa::terminal::Color::Default << #V << " (" \ << __FILENAME__ << ":" << __LINE__ << "): " << (V) \ << std::endl; \ } while (false) #else // defined(NDEBUG) #define DEBUG(X) ROSA_IGNORE_UNUSED(X) #define DEBUGVAR(X) ROSA_IGNORE_UNUSED(X) #endif // defined(NDEBUG) /// Enforces static assertion. /// /// \param COND the condition to evaluate, must be statically evaluable -/// \param DIAG error message if `COND` does not evaluate to `true` +/// \param DIAG error message if \p COND does not evaluate to \c true #define STATIC_ASSERT(COND, DIAG) static_assert((COND), DIAG) #endif // ROSA_SUPPORT_DEBUG_HPP diff --git a/include/rosa/support/log.h b/include/rosa/support/log.h index 584435e..c616098 100644 --- a/include/rosa/support/log.h +++ b/include/rosa/support/log.h @@ -1,261 +1,261 @@ //===-- rosa/support/log.h --------------------------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file rosa/support/log.h /// /// \author David Juhasz (david.juhasz@tuwien.ac.at) /// /// \date 2017 /// /// \brief Facility for logging. /// /// \note One call for the various logging macros is supposed to be used /// for registering one log entry. That goes natural with the non-stream /// implementations, which accept one string as argument. A more flexible way /// for printing log entries, for example for colorizing text, is to use macros /// providing a log stream. It is important to note, however, that the stream /// obtained from one macro evaluation fits for printing one log entry, without /// nested/overlapping log entry emissions and the entry being closed with a /// newline. Should this simple recommendation not being followed, the result /// becomes hard to read due to missing line breaks and overlapping entries. /// /// \todo Thread-safety is another issue, which need to be addressed for proper /// logging. /// //===----------------------------------------------------------------------===// #ifndef ROSA_SUPPORT_LOG_H #define ROSA_SUPPORT_LOG_H #include "rosa/config/config.h" #include "rosa/support/terminal_colors.h" #include #include /* **************************************************************************** * Log Levels * * ****************************************************************************/ namespace rosa { /// Type-safe definition of log levels, use this in code. /// \note Keep values in sync with the corresponding preprocessor definitions. enum class LogLevel { Error, ///< Log errors only - Warning, ///< Like `rosa::LogLevel::Error` and also log warnings - Info, ///< Like `rosa::LogLevel::Warning` and also log general infos - Debug, ///< Like `rosa::LogLevel::Info` and also log debug infos - Trace, ///< Like `rosa::LogLevel::Debug` and also log trace infos + Warning, ///< Like \c rosa::LogLevel::Error and also log warnings + Info, ///< Like \c rosa::LogLevel::Warning and also log general infos + Debug, ///< Like \c rosa::LogLevel::Info and also log debug infos + Trace, ///< Like \c rosa::LogLevel::Debug and also log trace infos NumLogLevels ///< Number of log levels }; -/// Converts a `rosa::LogLevel` to its textual representation. +/// Converts a \c rosa::LogLevel to its textual representation. /// -/// \param logLevel the `LogLevel` to convert +/// \param logLevel \c rosa::LogLevel to convert /// -/// \return `string` representing `logLevel` +/// \return \c std::string representing \p logLevel /// /// \pre `logLevel` is valid:\code /// logLevel != LogLevel::NumLogLevels /// \endcode std::string logLevelToString(const LogLevel logLevel); -/// Prints colorized tag for the given `rosa::LogLevel`. +/// Prints colorized tag for the given \c rosa::LogLevel. /// -/// \param [in,out] OS `ostream` to print to -/// \param logLevel the `LogLevel` to print tag for +/// \param [in,out] OS \c std::ostream to print to +/// \param logLevel \c rosa::LogLevel to print tag for /// -/// \return `OS` after printing a tag for `logLevel` +/// \return \p OS after printing a tag for \p logLevel /// -/// \pre `logLevel` is valid:\code +/// \pre \p logLevel is valid:\code /// logLevel != LogLevel::NumLogLevels /// \endcode std::ostream &operator<<(std::ostream &OS, const LogLevel logLevel); } // End namespace rosa /// \name Valid log level constants /// \note Only for preprocessor definitions in this file. -/// \note Keep the defintions in sync with the values of `rosa::LogLevel`. +/// \note Keep the defintions in sync with the values of \c rosa::LogLevel. ///@{ #define ROSA_LOG_LEVEL_ERROR \ - 0 ///< Value corresponding to `rosa::LogLevel::Error` + 0 ///< Value corresponding to \c rosa::LogLevel::Error #define ROSA_LOG_LEVEL_WARNING \ - 1 ///< Value corresponding to `rosa::LogLevel::Warning` + 1 ///< Value corresponding to \c rosa::LogLevel::Warning #define ROSA_LOG_LEVEL_INFO \ - 2 ///< Value corresponding to `rosa::LogLevel::Info` + 2 ///< Value corresponding to \c rosa::LogLevel::Info #define ROSA_LOG_LEVEL_DEBUG \ - 3 ///< Value corresponding to `rosa::LogLevel::Debug` + 3 ///< Value corresponding to \c rosa::LogLevel::Debug #define ROSA_LOG_LEVEL_TRACE \ - 4 ///< Value corresponding to `rosa::LogLevel::Trace` + 4 ///< Value corresponding to \c rosa::LogLevel::Trace ///@} /* **************************************************************************** * Logger Implementation * * ****************************************************************************/ /// Stream to print logs to /// /// \todo Make it configurable, e.g. printing into a file. #define ROSA_LOG_OSTREAM std::clog -/// Prints a log message to `ROSA_LOG_OSTREAM`. +/// Prints a log message to \c ROSA_LOG_OSTREAM. /// -/// \param level `LogLevel` of the log entry +/// \param level \c rosa::LogLevel of the log entry /// \param output message to print #define ROSA_LOG_IMPL(level, output) \ do { \ ROSA_LOG_OSTREAM << (level) << " " << __func__ << "@" << __FILENAME__ \ << ":" << __LINE__ << ": " << (output) << std::endl; \ } while (false) /// Returns a stream to print a log message to. /// -/// \param level `LogLevel`of the log entry that is about to be printed +/// \param level \c rosa::LogLevel of the log entry that is about to be printed #define ROSA_LOG_STREAM_IMPL(level) \ ([](void) -> std::ostream & { \ return ROSA_LOG_OSTREAM << (level) << " " << __func__ << "@" \ << __FILENAME__ << ":" << __LINE__ << ": "; \ }()) namespace rosa { -/// Dummy `std::ostream` printing to nowhere. +/// Dummy \c std::ostream printing to nowhere. extern std::ostream LogSink; } // End namespace rosa /// An output stream ignoring all its input. #define ROSA_LOG_STREAM_IGNORE rosa::LogSink /* **************************************************************************** * Logging Interface * * ****************************************************************************/ /// \name Logging interface /// /// Preprocesser macros for convenience. ///@{ /// \def LOG_ERROR_STREAM /// \brief Returns a stream to print a log entry of level -/// `rosa::LogLevel::Error`. +/// \c rosa::LogLevel::Error. /// \note Takes effect only if RoSA is built with a log level not smaller than -/// `rosa::LogLevel::Error`. +/// \c rosa::LogLevel::Error. /// \def LOG_ERROR(output) -/// \brief Prints a log entry of level `rosa::LogLevel::Error`. +/// \brief Prints a log entry of level \c rosa::LogLevel::Error. /// \param output the message to print /// \note Takes effect only if RoSA is built with a log level not smaller than -/// `rosa::LogLevel::Error`. +/// \c rosa::LogLevel::Error. /// \def LOG_WARNING_STREAM /// \brief Returns a stream to print a log entry of level -/// `rosa::LogLevel::Warning`. +/// \c rosa::LogLevel::Warning. /// \note Takes effect only if RoSA is built with a log level not smaller than -/// `rosa::LogLevel::Warning`. +/// \c rosa::LogLevel::Warning. /// \def LOG_WARNING(output) -/// \brief Prints a log entry of level `rosa::LogLevel::Warning`. +/// \brief Prints a log entry of level \c rosa::LogLevel::Warning. /// \param output the message to print /// \note Takes effect only if RoSA is built with a log level not smaller than -/// `rosa::LogLevel::Warning`. +/// \c rosa::LogLevel::Warning. /// \def LOG_INFO_STREAM /// \brief Returns a stream to print a log entry of level -/// `rosa::LogLevel::Info`. +/// \c rosa::LogLevel::Info. /// \note Takes effect only if RoSA is built with a log level not smaller than -/// `rosa::LogLevel::Info`. +/// \c rosa::LogLevel::Info. /// \def LOG_INFO(output) -/// \brief Prints a log entry of level `rosa::LogLevel::Info`. +/// \brief Prints a log entry of level \c rosa::LogLevel::Info. /// \param output the message to print /// \note Takes effect only if RoSA is built with a log level not smaller than -/// `rosa::LogLevel::Info`. +/// \c rosa::LogLevel::Info. /// \def LOG_DEBUG_STREAM /// \brief Returns a stream to print a log entry of level -/// `rosa::LogLevel::Debug`. +/// \c rosa::LogLevel::Debug. /// \note Takes effect only if RoSA is built with a log level not smaller than -/// `rosa::LogLevel::Debug`. +/// \c rosa::LogLevel::Debug. /// \def LOG_DEBUG(output) -/// \brief Prints a log entry of level `rosa::LogLevel::Debug`. +/// \brief Prints a log entry of level \c rosa::LogLevel::Debug. /// \param output the message to print /// \note Takes effect only if RoSA is built with a log level not smaller than -/// `rosa::LogLevel::Debug`. +/// \c rosa::LogLevel::Debug. /// \def LOG_TRACE_STREAM /// \brief Returns a stream to print a log entry of level -/// `rosa::LogLevel::Trace`. +/// \c rosa::LogLevel::Trace. /// \note Takes effect only if RoSA is built with a log level not smaller than -/// `rosa::LogLevel::Trace`. +/// \c rosa::LogLevel::Trace. /// \def LOG_TRACE(output) -/// \brief Prints a log entry of level `rosa::LogLevel::Trace`. +/// \brief Prints a log entry of level \c rosa::LogLevel::Trace. /// \param output the message to print /// \note Takes effect only if RoSA is built with a log level not smaller than -/// `rosa::LogLevel::Trace`. +/// \c rosa::LogLevel::Trace. ///@} // Define logging macros if logging is enabled. #ifdef ROSA_LOG_LEVEL #define LOG_ERROR_STREAM ROSA_LOG_STREAM_IMPL(rosa::LogLevel::Error) #define LOG_ERROR(output) ROSA_LOG_IMPL(rosa::LogLevel::Error, output) #if ROSA_LOG_LEVEL >= ROSA_LOG_LEVEL_WARNING #define LOG_WARNING_STREAM ROSA_LOG_STREAM_IMPL(rosa::LogLevel::Warning) #define LOG_WARNING(output) ROSA_LOG_IMPL(rosa::LogLevel::Warning, output) #endif #if ROSA_LOG_LEVEL >= ROSA_LOG_LEVEL_INFO #define LOG_INFO_STREAM ROSA_LOG_STREAM_IMPL(rosa::LogLevel::Info) #define LOG_INFO(output) ROSA_LOG_IMPL(rosa::LogLevel::Info, output) #endif #if ROSA_LOG_LEVEL >= ROSA_LOG_LEVEL_DEBUG #define LOG_DEBUG_STREAM ROSA_LOG_STREAM_IMPL(rosa::LogLevel::Debug) #define LOG_DEBUG(output) ROSA_LOG_IMPL(rosa::LogLevel::Debug, output) #endif #if ROSA_LOG_LEVEL >= ROSA_LOG_LEVEL_TRACE #define LOG_TRACE_STREAM ROSA_LOG_STREAM_IMPL(rosa::LogLevel::Trace) #define LOG_TRACE(output) ROSA_LOG_IMPL(rosa::LogLevel::Trace, output) #endif #endif // defined ROSA_LOG_LEVEL // Define all disabled logging features as void. #ifndef LOG_ERROR #define LOG_ERROR_STREAM ROSA_LOG_STREAM_IGNORE #define LOG_ERROR(output) ROSA_IGNORE_UNUSED(output) #endif #ifndef LOG_WARNING #define LOG_WARNING_STREAM ROSA_LOG_STREAM_IGNORE #define LOG_WARNING(output) ROSA_IGNORE_UNUSED(output) #endif #ifndef LOG_INFO #define LOG_INFO_STREAM ROSA_LOG_STREAM_IGNORE #define LOG_INFO(output) ROSA_IGNORE_UNUSED(output) #endif #ifndef LOG_DEBUG #define LOG_DEBUG_STREAM ROSA_LOG_STREAM_IGNORE #define LOG_DEBUG(output) ROSA_IGNORE_UNUSED(output) #endif #ifndef LOG_TRACE #define LOG_TRACE_STREAM ROSA_LOG_STREAM_IGNORE #define LOG_TRACE(output) ROSA_IGNORE_UNUSED(output) #endif #endif // ROSA_SUPPORT_LOG_H diff --git a/include/rosa/support/math.hpp b/include/rosa/support/math.hpp index 7abb757..65ed36f 100644 --- a/include/rosa/support/math.hpp +++ b/include/rosa/support/math.hpp @@ -1,36 +1,36 @@ //===-- rosa/support/math.hpp -----------------------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file rosa/support/math.hpp /// /// \author David Juhasz (david.juhasz@tuwien.ac.at) /// /// \date 2017 /// /// \brief Math helpers. /// //===----------------------------------------------------------------------===// #ifndef ROSA_SUPPORT_MATH_HPP #define ROSA_SUPPORT_MATH_HPP #include namespace rosa { /// Computes log base 2 of a number. /// /// \param N the number to compute log base 2 for /// -/// \return log base 2 of `N` +/// \return log base 2 of \p N constexpr size_t log2(const size_t N) { return ((N < 2) ? 1 : 1 + log2(N / 2)); } } // End namespace rosa #endif // ROSA_SUPPORT_MATH_HPP diff --git a/include/rosa/support/squashed_int.hpp b/include/rosa/support/squashed_int.hpp index 868cbd3..017e8fa 100644 --- a/include/rosa/support/squashed_int.hpp +++ b/include/rosa/support/squashed_int.hpp @@ -1,133 +1,134 @@ //===-- rosa/support/squashed_int.hpp ---------------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file rosa/support/squashed_int.hpp /// /// \author David Juhasz (david.juhasz@tuwien.ac.at) /// /// \date 2017 /// /// \brief Facilities for squashing integer types into standard equivalents. /// -/// \note This implementation is partially based on the `squashed_int` +/// \note This implementation is partially based on the \c squashed_int /// implementation of CAF. /// \todo Check license. /// //===----------------------------------------------------------------------===// #ifndef ROSA_SUPPORT_SQUASHED_INT_HPP #define ROSA_SUPPORT_SQUASHED_INT_HPP #include "rosa/support/type_list.hpp" #include "rosa/support/type_pair.hpp" namespace rosa { /// Compile-time list of integer types. /// -/// \note This list is used to select a proper type as `rosa::type_nr_t`, always -/// make sure that `rosa::type_nr_t` remains correct whenever changing the list. +/// \note This list is used to select a proper type as \c rosa::type_nr_t, +/// always make sure that \c rosa::type_nr_t remains correct whenever changing +/// the list. using IntegerTypesBySize = TypeList< // bytes none_t, // 0 TypePair, // 1 TypePair, // 2 none_t, // 3 TypePair, // 4 none_t, // 5 none_t, // 6 none_t, // 7 TypePair // 8 >; -/// Squashes integer types into `[u]int_[8|16|32|64]_t` equivalents. +/// Squashes integer types into \c [u]int_[8|16|32|64]_t equivalents. /// -/// The squashed type for a type `T` can be obtained as \code +/// The squashed type for a type \c T can be obtained as \code /// typename SquashedInt::Type /// \endcode /// /// \tparam T the integer type to squash /// -/// \pre `T` is an integral type:\code +/// \pre \p T is an integral type:\code /// std::is_integral::value /// \endcode template struct SquashedInt { STATIC_ASSERT((std::is_integral::value), "squashing a non-integral type"); using TPair = typename TypeListAt::Type; using Type = typename std::conditional::value, typename TPair::First, typename TPair::Second>::type; }; /// Convenience alias for obtaining a squashed integer type. template using squashed_int_t = typename SquashedInt::Type; /// \defgroup SquashedType /// \brief Squashes a type. /// -/// The squashed type for a type `T` can be obtained as \code +/// The squashed type for a type \c T can be obtained as \code /// typename SquashedType::Type /// \endcode -/// The used type `Type` is squashed with `SquashedInt` if `T` is integral, -/// and remains `T` otherwise. +/// The resulting type is squashed with \c rosa::SquashedInt if \c T is +/// integral, and remains \p T otherwise. ///@{ -/// Definition for the general case, used when `T` is not integral. +/// Definition for the general case, when squashing a non-integral type. /// /// \tparam T the type to squash /// \tparam IsIntegral Always use the default value! template ::value> struct SquashedType { using Type = T; }; -/// Specialization for the case when `T` is integral. +/// Specialization for the case when squashing an integral type. /// /// \tparam T the type to squash template struct SquashedType { using Type = squashed_int_t; }; ///@} /// Convenience alias for obtaining a squashed type. template using squashed_t = typename SquashedType::Type; /// \defgroup SquashedTypeList -/// \brief Squashes a `rosa::TypeList` elementwise. +/// \brief Squashes a \c rosa::TypeList elementwise. /// -/// Replaces all types in a `rosa::TypeList` with their corresponding squashed -/// types by using `rosa::SquashedType`. The squashed `rosa::TypeList` -/// corresponding to `List` can be obtained as \code +/// Replaces all types in a \c rosa::TypeList with their corresponding squashed +/// types by using \c rosa::SquashedType. The squashed \c rosa::TypeList +/// corresponding to \c List can be obtained as \code /// typename SquashedTypeList::Type /// \endcode ///@{ /// Declaration of the template. /// -/// \tparam List `TypeList` to squash +/// \tparam List \c rosa::TypeList to squash template struct SquashedTypeList; -// Specialization for the case of `rosa::EmptyTypeList`. +// Specialization for \c rosa::EmptyTypeList. template <> struct SquashedTypeList { using Type = EmptyTypeList; }; -/// Specialization for non-empty `rosa::TypeList`. +/// Specialization for non-empty \c rosa::TypeList. template struct SquashedTypeList> { using Type = typename TypeListPush< squashed_t, typename SquashedTypeList>::Type>::Type; }; ///@} } // End namespace rosa #endif // ROSA_SUPPORT_SQUASHED_INT_HPP diff --git a/include/rosa/support/terminal_colors.h b/include/rosa/support/terminal_colors.h index aa23501..7d144a2 100644 --- a/include/rosa/support/terminal_colors.h +++ b/include/rosa/support/terminal_colors.h @@ -1,69 +1,71 @@ //===-- rosa/support/terminal_colors.h --------------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file rosa/support/terminal_colors.h /// /// \author David Juhasz (david.juhasz@tuwien.ac.at) /// /// \date 2017 /// /// \brief Facility for printing colorized text to terminals supporting it. /// //===----------------------------------------------------------------------===// #ifndef ROSA_SUPPORT_TERMINAL_COLORS_H #define ROSA_SUPPORT_TERMINAL_COLORS_H #include namespace rosa { /// Encloses entities related to terminal I/O. namespace terminal { /// Text colors for colorizable terminals. enum class Color { Default, Black, Red, Green, Yellow, Blue, Magenta, Cyan, Lightgrey, Darkgrey, Lightred, Lightgreen, Lightyellow, Lightblue, LightMagenta, Lightcyan, White, - NumColors ///< Number of `rosa::terminal::Color` values + NumColors ///< Number of \c rosa::terminal::Color values }; -/// Handles `rosa::terminal::Color` values sent to output streams. +/// Handles \c rosa::terminal::Color values sent to output streams. /// -/// The operator sends terminal commands through `os` to the -/// associated terminal to change text color to `color`. +/// The operator sends terminal commands through \p os to the +/// associated terminal to change text color to \p color. /// -/// \note If `os` is not a terminal output, the terminal commands simply appear +/// \note If \p os is not a terminal output, the terminal commands simply appear /// as text in the stream. /// -/// \param [in,out] os `ostream` to apply `color` to -/// \param color `Color` to apply for `os` +/// \param [in,out] os \c std::ostream to apply \p color to +/// \param color \c rosa::terminal::Color to apply for \p os /// -/// \pre `color` is valid:\code +/// \return \p os after applying \p color to it +/// +/// \pre \p color is valid:\code /// color != Color::NumColors /// \endcoed std::ostream &operator<<(std::ostream &os, const Color color); } // End namespace terminal } // End namespace rosa #endif // ROSA_SUPPORT_TERMINAL_COLORS_H diff --git a/include/rosa/support/type_helper.hpp b/include/rosa/support/type_helper.hpp index 2e4e8a7..ab84689 100644 --- a/include/rosa/support/type_helper.hpp +++ b/include/rosa/support/type_helper.hpp @@ -1,143 +1,143 @@ //===-- rosa/support/type_helper.hpp ----------------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file rosa/support/type_helper.hpp /// /// \author David Juhasz (david.juhasz@tuwien.ac.at) /// /// \date 2017 /// /// \brief Helper facilities for type-related stuff. /// //===----------------------------------------------------------------------===// #ifndef ROSA_SUPPORT_TYPE_HELPER_HPP #define ROSA_SUPPORT_TYPE_HELPER_HPP #include #include namespace rosa { /* ************************************************************************** * * Printable * * ************************************************************************** */ /// \defgroup PrintableType /// -/// A value of type `[u]int8_t` is treated as a character when being put to an +/// A value of type \c [u]int8_t is treated as a character when being put to an /// output stream, which can result in invisible characters being printed. To /// avoid that, such a value needs to be casted to a wider type. It can be done /// by using the following template to find a target type to cast our value to. /// The template also turns enumerations into their underlying types. Moreover, /// any reference type is turned into the referred type and any non-const type /// is turned into their const-qualified type. /// /// \note It is important to remove references before checking /// const-qualification because constant references are not const-qualified /// types. /// -/// The corresponding printable type for a type `T` can be obtained as \code +/// The corresponding printable type for a type \c T can be obtained as \code /// typename PrintableType::Type /// \endcode ///@{ /// Definition for the general case /// /// \tparam T type to cast /// \tparam IsReference always use the default value! /// \tparam IsConst always use the default value! /// \tparam IsEnum always use the default value! template ::value, bool IsConst = std::is_const::value, bool IsEnum = std::is_enum::value> struct PrintableType { using Type = T; }; /// Specialization for reference types. template struct PrintableType { using Type = typename PrintableType::type>::Type; }; /// Specialization for non-reference, non-const types. template struct PrintableType { using Type = typename PrintableType::Type; }; /// Specialization for non-reference, const, enum types. template struct PrintableType { using Type = typename PrintableType::type>::Type; }; -/// Specialization for `const uint8_t`. +/// Specialization for \c const uint8_t. template <> struct PrintableType { using Type = const unsigned int; }; -/// Specialization for `const int8_t`. +/// Specialization for \c const int8_t. template <> struct PrintableType { using Type = const int; }; ///@} -/// Convenience template alias for using `rosa::PrintableType`. +/// Convenience template alias for using \c rosa::PrintableType. template using printable_t = typename PrintableType::Type; /// Casts values to their corresponding printable types. /// /// \param V value to cast #define PRINTABLE(V) static_cast>(V) /* ************************************************************************** * * Unsigned * * ************************************************************************** */ /// \defgroup Unsigned /// \brief Converts integral types to their corresponding unsigned type. /// -/// Provides the unsigned integer type corresponding to `T` if `T` is an -/// integral (except bool) or enumeration type. Keeps `T` otherwise. +/// Provides the unsigned integer type corresponding to \c T` if \c T is an +/// integral (except \c bool) or enumeration type. Keeps \c T otherwise. /// -/// The corresponding unsigned type for a type `T` can be obtained as \code +/// The corresponding unsigned type for a type \c T can be obtained as \code /// typename Unsigned::Type /// \endcode ///@{ -/// Definition for the general case, used when `T` is not integral. +/// Definition for the general case when converting a non-integral type. /// /// \tparam T type to convert /// \tparam IsIntegral always use the default value! template ::value> struct Unsigned { using Type = T; }; -/// Specialization for the case when `T` is integral. +/// Specialization for the case when converting an integral type. template struct Unsigned { using Type = typename std::make_unsigned::type; }; ///@} -/// Convenience template alias for using `rosa::Unsigned`. +/// Convenience template alias for using \c rosa::Unsigned. template using unsigned_t = typename Unsigned::Type; } // End namespace rosa #endif // ROSA_SUPPORT_TYPE_HELPER_HPP diff --git a/include/rosa/support/type_list.hpp b/include/rosa/support/type_list.hpp index 20d0e85..f8c255f 100644 --- a/include/rosa/support/type_list.hpp +++ b/include/rosa/support/type_list.hpp @@ -1,437 +1,453 @@ //===-- rosa/support/type_list.hpp ------------------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file rosa/support/type_list.hpp /// /// \author David Juhasz (david.juhasz@tuwien.ac.at) /// /// \date 2017 /// /// \brief Facilities for types representing lists of types. /// -/// \note This implementation is partially based on the `type_list` +/// \note This implementation is partially based on the \c type_list /// implementation of CAF. /// \todo Check license. /// //===----------------------------------------------------------------------===// #ifndef ROSA_SUPPORT_TYPE_LIST_HPP #define ROSA_SUPPORT_TYPE_LIST_HPP #include "rosa/support/debug.hpp" #include "rosa/support/types.hpp" #include namespace rosa { /// A list of types. /// /// \tparam Ts types to make a list of template struct TypeList { - /// Ctor, needs to do nothing. + /// Constructor, needs to do nothing. constexpr TypeList(void) {} }; -/// The empty `rosa::Typelist`. +/// The empty \c rosa::Typelist. using EmptyTypeList = TypeList<>; /// \defgroup TypeListAtImpl -/// \brief Gets the type at index `Pos` from a list of types. /// -/// \note Only to be used by the implementation of `rosa::TypeListAt`. +/// \brief Gets the type at index \p Pos from a list of types. +/// +/// \note Only to be used by the implementation of \c rosa::TypeListAt. ///@{ /// Declaration of the template. /// /// \tparam Pos index to take the element from /// \tparam Ts types template struct TypeListAtImpl; -/// Definition for the general case when `Pos` is not `0` and there is type in +/// Definition for the general case when \p Pos is not \c 0 and there is type in /// the list. template struct TypeListAtImpl { using Type = typename TypeListAtImpl::Type; }; -/// Specialization for the case when `Pos` is `0`˙. +/// Specialization for the case when \p Pos is \c 0. template struct TypeListAtImpl<0, T, Ts...> { using Type = T; }; /// Specialization for the case when there is no more type. /// -/// In this case, the found type is `rosa::none_t`. +/// In this case, the found type is \c rosa::none_t. template struct TypeListAtImpl { using Type = none_t; }; ///@} /// \defgroup TypeListAt -/// \brief Gets the element at index `Pos` of `List`. +/// +/// \brief Gets the element at index \p Pos of \p List. /// /// -/// The type at index `Pos` in a `rosa::TypeList` `List` can be obtained as +/// The type at index \c Pos in a \c rosa::TypeList \c List can be obtained as /// \code /// typename TypeListAt::Type /// \endcode /// -/// \note The resulting type is `rosa::none_t` if \code +/// \note The resulting type is \c rosa::none_t if \code /// TypeListSize::Value < Pos /// \endcode ///@{ /// Declaration of the template. /// -/// \tparam List `TypeList` to take an element from +/// \tparam List \c rosa::TypeList to take an element from /// \tparam Pos index to take the element from template struct TypeListAt; -/// Implementation using `rosa::TypeListAtImpl`. +/// Implementation using \c rosa::TypeListAtImpl. template struct TypeListAt, Pos> { using Type = typename TypeListAtImpl::Type; }; ///@} /// \defgroup TypeListIndexOfImpl +/// /// \brief Tells the index of the first occurence of a type in a list of types. /// -/// \note Only to be used by the implementation of `rosa::TypeListIndexOf`. +/// \note Only to be used by the implementation of \c rosa::TypeListIndexOf. ///@{ /// Declaration of the template. /// /// \tparam Pos the number types already being checked from the beginning of the /// list /// \tparam X type to search for /// \tparam Ts remaining list of types template struct TypeListIndexOfImpl; /// Specialization for the case when the list is over. /// -/// In this case, the found index is `-1`. +/// In this case, the found index is \c -1. template struct TypeListIndexOfImpl { static constexpr int Value = -1; }; /// Specialization for the case when the first type in the remaining list /// is a match. template struct TypeListIndexOfImpl { static constexpr int Value = Pos; }; /// Implementation for the general case when need to continue looking. template struct TypeListIndexOfImpl { static constexpr int Value = TypeListIndexOfImpl::Value; }; ///@} /// \defgroup TypeListIndexOf -/// \brief Tells the index of the first occurence of type in a `rosa::TypeList`. /// -/// The index of the first occurence of type `T` in `rosa::TypeList` `List` can -/// be obtained as \code +/// \brief Tells the index of the first occurence of type in a +/// \c rosa::TypeList. +/// +/// The index of the first occurence of type \c T in \c rosa::TypeList \c List +/// can be obtained as \code /// TypeListIndexOf::Value /// \endcode /// -/// \note The resulting index is `-1` if `T` is not present in `List`. +/// \note The resulting index is \c -1 if \c T is not present in \c List. ///@{ /// Declaration of the template. /// -/// \tparam List `TypeList` to search in +/// \tparam List \c rosa::TypeList to search in /// \tparam T type to search for template struct TypeListIndexOf; -/// Implementation of the template using `rosa::TypeListIndexOfImpl`. +/// Implementation of the template using \c rosa::TypeListIndexOfImpl. template struct TypeListIndexOf, T> { static constexpr int Value = TypeListIndexOfImpl<0, T, Ts...>::Value; }; ///@} /// \defgroup TypeListHead -/// \brief Gets the first element of a `rosa::TypeList`. /// -/// The first element of a `rosa::TypeList` `List` can be obtained as \code +/// \brief Gets the first element of a \c rosa::TypeList. +/// +/// The first element of a \c rosa::TypeList \c List can be obtained as \code /// typename TypeListHead::Type /// \endcode /// -/// \note The resulting type is `rosa::none_t` if `List` is the -/// `rosa::EmptyTypeList`. +/// \note The resulting type is \c rosa::none_t if \c List is +/// \c rosa::EmptyTypeList. ///@{ /// Declaration of the template. /// -/// \tparam List `TypeList` to get the first element of +/// \tparam List \c rosa::TypeList to get the first element of template struct TypeListHead; -/// Specialization for `rosa::EmptyTypeList`. +/// Specialization for \c rosa::EmptyTypeList. /// -/// In this case, the found type is `rosa::none_t`. +/// In this case, the found type is \c rosa::none_t. template <> struct TypeListHead { using Type = none_t; }; -/// Implementation for a non-empty `rosa::TypeList`. +/// Implementation for a non-empty \c rosa::TypeList. template struct TypeListHead> { using Type = T; }; ///@} /// \defgroup TypeListTail /// -/// \brief Gets the tail of a `rosa::TypeList`. +/// \brief Gets the tail of a \c rosa::TypeList. /// -/// The tail of a `rosa::TypeList` `List`, that is `List` except for its first -/// element, can be obtained as \code +/// The tail of a \c rosa::TypeList \c List, that is \c List except for its +/// first element, can be obtained as \code /// typename TypeListTail::Type /// \endcode /// -/// \note If `List` is the `rosa::EmptyTypeList`, then the resulting type is -/// also `rosa::EmptyTypeList`. +/// \note If \c List is \c rosa::EmptyTypeList, then the resulting type is also +/// \c rosa::EmptyTypeList. ///@{ /// Declaration of the template. /// -/// \tparam List `TypeList` to take the tail of +/// \tparam List \c rosa::TypeList to take the tail of template struct TypeListTail; -/// Specialization for the `rosa::EmptyTypeList`. +/// Specialization for \c rosa::EmptyTypeList. /// -/// In this case, the resulting type is `rosa::EmptyTypeList`. +/// In this case, the resulting type is \c rosa::EmptyTypeList. template <> struct TypeListTail { using Type = EmptyTypeList; }; -/// Implementation for a non-empty `rosa::TypeList`. +/// Implementation for a non-empty \c rosa::TypeList. template struct TypeListTail> { using Type = TypeList; }; ///@} /// \defgroup TypeListPush -/// \brief Extends a `rosa::TypeList` with a type. +/// +/// \brief Extends a \c rosa::TypeList with a type. /// /// Whether the new type is pushed in the front or in the back of the -/// `rosa::TypeList` depends on the order of template arguments, as shown in the -/// following example: \code +/// \c rosa::TypeList depends on the order of template arguments, as shown in +/// the following example: \code /// using List = TypeList /// typename TypeListPush::Type; // TypeList /// typename TypeListPush::Type; // TypeList /// \endcode ///@{ /// Declaration of the template. /// -/// \tparam P a type if `Q` is a `rosa::TypeList`, a `rosa::TypeList` otherwise -/// \tparam Q a type if `P` is a `rosa::TypeList`, a `rosa::TypeList` otherwise +/// \tparam P a type if \p Q is a \c rosa::TypeList, a \c rosa::TypeList +/// otherwise +/// \tparam Q a type if \p P is a \c rosa::TypeList, a \c rosa::TypeList +/// otherwise template struct TypeListPush; /// Implementation for the case when pushing at the back of the -/// `rosa::TypeList`. +/// \c rosa::TypeList. template struct TypeListPush, T> { using Type = TypeList; }; /// Implementation for the case when pushing to the front of the -/// `rosa::TypeList`. +/// \c rosa::TypeList. template struct TypeListPush> { using Type = TypeList; }; ///@} /// \defgroup TypeListDrop -/// \brief Drops some elements from the beginning of a `rosa::TypeList`. /// -/// The first `N` types of a `rosa::TypeList` `List` can be dropped as \code +/// \brief Drops some elements from the beginning of a \c rosa::TypeList. +/// +/// The first \c N types of a \c rosa::TypeList \c List can be dropped as \code /// typename TypeListDrop::Type /// \endcode ///@{ /// Declaration of the template. /// /// \tparam N number of types to drop -/// \tparam List `TypeList` to drop the first `N` element of +/// \tparam List \c rosa::TypeList to drop the first \p N element of template struct TypeListDrop; -/// Specialization for the `rosa::EmptyTypeList`. +/// Specialization for \c rosa::EmptyTypeList. template struct TypeListDrop { using Type = EmptyTypeList; }; -/// Implementation for a non-empty `rosa::TypeList`. +/// Implementation for a non-empty \c rosa::TypeList. template struct TypeListDrop> { using Type = typename std::conditional< N == 0, TypeList, typename TypeListDrop>::Type>::type; }; ///@} /// \defgroup TypeListSize -/// \brief Tells the number of types stored in a `rosa::TypeList`. /// -/// The size of a `rosa::TypeList` `List` can be obtained as \code +/// \brief Tells the number of types stored in a \c rosa::TypeList. +/// +/// The size of a \c rosa::TypeList \c List can be obtained as \code /// TypeListSize::Value /// \endcode ///@{ /// Declaration of the template. /// -/// \tparam List `TypeList` to get the size of +/// \tparam List \c rosa::TypeList to get the size of template struct TypeListSize; /// Implementation of the template. template struct TypeListSize> { static constexpr size_t Value = sizeof...(Ts); }; template constexpr size_t TypeListSize>::Value; ///@} -/// Tests whether a `rosa::TypeList` is empty. +/// Tests whether a \c rosa::TypeList is empty. /// -/// \tparam List the `TypeList` to check +/// \tparam List \c rosa::TypeList to check template struct TypeListEmpty { - /// Denotes whether `List` is an empty `rosa::TypeList` or not. + /// Denotes whether \p List is an empty \c rosa::TypeList or not. static constexpr bool Value = std::is_same::value; }; /// \defgroup TypeListContains -/// \brief Tells if a `rosa::TypeList` contains a type. /// -/// Whether a `rosa::TypeList` `List` contains the type `T` can be checked as +/// \brief Tells if a \c rosa::TypeList contains a given type. +/// +/// Whether a \c rosa::TypeList \c List contains the type \c T can be checked as /// \code /// TypeListContains::Value /// \endcode ///@{ /// Declaration of the template. /// -/// \tparam List `TypeList` to search in +/// \tparam List \c rosa::TypeList to search in /// \tparam T type to search for template struct TypeListContains; /// Implementation of the template. template struct TypeListContains, T> { static constexpr bool Value = std::conditional, T>::Value == -1, std::false_type, std::true_type>::type::value; }; ///@} /// \defgroup TypeListSubsetOf -/// \brief Tells if a `rosa::TypeList` is a subset of another one. /// -/// Whether a `rosa::TypeList` `ListA` is a subset of another `rosa::TypeList` -/// `ListB` can be checked as \code +/// \brief Tells if a \c rosa::TypeList is a subset of another one. +/// +/// Whether a \c rosa::TypeList \c ListA is a subset of another +/// \c rosa::TypeList \c ListB can be checked as \code /// TypeListSubsetOf::Value /// \endcode ///@{ /// Declaration of the template. /// -/// \tparam ListA `TypeList` to check if is a subset of `ListB` -/// \tparam ListB `TypeList` to check if is a superset of `ListA` +/// \tparam ListA \c rosa::TypeList to check if is a subset of \p ListB +/// \tparam ListB \c rosa::TypeList to check if is a superset of \p ListA /// \tparam Fwd always use the default value! template struct TypeListSubsetOf; -/// Specialization for the case when all the elements of the original `ListA` -/// was found in `ListB`. +/// Specialization for the case when all the elements of the original \p ListA +/// was found in \p ListB. template struct TypeListSubsetOf { static constexpr bool Value = true; }; -/// Specializaton for the case when an element of the original `ListA` cannot be -/// found in `ListB`. +/// Specializaton for the case when an element of the original \p ListA cannot +/// be found in \p ListB. template struct TypeListSubsetOf { static constexpr bool Value = false; }; /// Definition for the general case. template struct TypeListSubsetOf, List> : TypeListSubsetOf, List, TypeListContains::Value> {}; ///@} /// \defgroup TypeListFindImpl +/// /// \brief Finds the first type in a list of types that satisfies a predicate. /// -/// \note Only to be used by the implementation of `rosa::TypeListFind`. +/// \note Only to be used by the implementation of \c rosa::TypeListFind. ///@{ /// Declaration of the template. /// /// \tparam Pred the predicate to check types against /// \tparam Ts list of types to check template