diff --git a/examples/basic-system/basic-system.cpp b/examples/basic-system/basic-system.cpp index 4821c52..06fe52a 100644 --- a/examples/basic-system/basic-system.cpp +++ b/examples/basic-system/basic-system.cpp @@ -1,58 +1,66 @@ /******************************************************************************* * * File: basic-system.cpp * * Contents: A simple example on the basic System and Unit classes of the RoSA * Core library. * * Copyright 2017 * * Author: David Juhasz (david.juhasz@tuwien.ac.at) * ******************************************************************************/ #include "rosa/config/version.h" -#include "rosa/core/System.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 System. // NOTE: Since we test System directly here, we need to get access to its // protected members. That we do by imitating to be a decent subclass of // 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([](const size_t Id, const std::string &N, - System &S) { return new Unit(Id, N, S); }, - Name); + ->createUnit([&Name](const size_t Id, System &S) noexcept { + // NOTE: If Name is empty, construct a name with the number of the + // Unit 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 << "simple 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/include/rosa/core/System.h b/include/rosa/core/System.hpp similarity index 79% rename from include/rosa/core/System.h rename to include/rosa/core/System.hpp index 6594af4..0025531 100644 --- a/include/rosa/core/System.h +++ b/include/rosa/core/System.hpp @@ -1,115 +1,133 @@ /******************************************************************************* * - * File: System.h + * File: System.hpp * * Contents: Declaration of System base-class. * * Copyright 2017 * * Author: David Juhasz (david.juhasz@tuwien.ac.at) * ******************************************************************************/ -#ifndef ROSA_CORE_SYSTEM_H -#define ROSA_CORE_SYSTEM_H +#ifndef ROSA_CORE_SYSTEM_HPP +#define ROSA_CORE_SYSTEM_HPP +#include "rosa/config/config.h" +#include "rosa/support/debug.hpp" +#include "rosa/support/log.h" #include #include #include namespace rosa { // Forward declarations. class Unit; // Base-class for actual agent-systems, the class provides facitlities to keep // track of Units of the system. // NOTE: This class and any subclasses are supposed to provide thread-safe // interfaces. class System { public: // Signature of creator functions for Units. - using UnitCreator = Unit *(*)(const size_t, const std::string&, System&); + template + using UnitCreator = std::function; // Returns an object implementing the interface defined by the class. static std::unique_ptr createSystem(const std::string &Name) noexcept; protected: // Protected ctor, only subclasses can instantiate. System(const std::string &Name) noexcept; // No copy and move. System(const System&) = delete; System(System&&) = delete; System &operator=(const System&) = delete; System &operator=(System&&) = delete; public: // Dtor. Only a cleared System can be destroyed. // PRE: SystemCleaned virtual ~System(void); protected: // Sets SystemCleaned flag. Can be called only once and the System must not // have any live Units. // PRE: !SystemCleaned && empty() // POST: SystemCleaned void markCleaned(void) noexcept; // Creates a Unit instance with the given UnitCreator, using the given Name // if any, then registers the new Unit instance by calling the virtual // member function registerUnit. // NOTE: This function handles the member field CountUnits. + // STATIC PRE: std::is_base_of::value // PRE: !SystemCleaned - Unit &createUnit(UnitCreator C, - const std::string &Name = std::string()) noexcept; + template + T &createUnit(UnitCreator C) noexcept; // Registers the given Unit instance to the System. // PRE: !isUnitRegistered(U) // POST: isUnitRegistered(U) virtual void registerUnit(Unit &U) noexcept = 0; // Unregisters and destroys the given Unit. // PRE: isUnitRegistered(U) // POST: !isUnitRegistered(U) && 'U is destroyed' virtual void destroyUnit(Unit &U) noexcept = 0; // Returns if the given Unit is registered in the System. virtual bool isUnitRegistered(const Unit &U) const noexcept = 0; public: // The textual name of the System. const std::string Name; private: // Number of Units constructed in the system. // NOTE: Should never be decremented! std::atomic CountUnits; // Indicates that the System has been cleaned and is ready for destruction. // The field is initialized as 'false' and can be set by the member function // markCleaned. // Subclasses must set the flag upon destroying the System instance, which // indicates to the destructor of the base-class that all the managed // resources has been properly released. std::atomic SystemCleaned; public: - // Returns the number of Units constructed in the System so far, // including those being already destroyed. size_t numberOfConstructedUnits(void) const noexcept; // Returns the number of live Units, that have been constructed and not // destroyed yet. virtual size_t numberOfLiveUnits(void) const noexcept = 0; // Returns if the System has no live Units. virtual bool empty(void) const noexcept = 0; }; +template +T &System::createUnit(UnitCreator C) noexcept { + STATIC_ASSERT((std::is_base_of::value), "not a Unit"); + if (SystemCleaned) { + ROSA_CRITICAL("Trying to create a Unit in an already cleaned System (" + + Name + ")"); + } + const uint64_t Id = ++CountUnits; + T *U = C(Id, *this); + registerUnit(*U); + LOG_TRACE("Unit created and registered (" + U->FullName + ")"); + return *U; +} + } // End namespace rosa -#endif // ROSA_CORE_SYSTEM_H +#endif // ROSA_CORE_SYSTEM_HPP diff --git a/include/rosa/core/Unit.h b/include/rosa/core/Unit.h index 9d2f71f..e949f06 100644 --- a/include/rosa/core/Unit.h +++ b/include/rosa/core/Unit.h @@ -1,76 +1,85 @@ /******************************************************************************* * * File: Unit.h * * Contents: Declaration of Unit base-class. * * Copyright 2017 * * Author: David Juhasz (david.juhasz@tuwien.ac.at) * ******************************************************************************/ #ifndef ROSA_CORE_UNIT_H #define ROSA_CORE_UNIT_H +#include "rosa/support/atom.hpp" #include #include namespace rosa { // Forward declarations. class System; // Base class for every entity in the system that has to be identified and // traced. // NOTE: Life-cycle of Unit instances is supposed to be managed by a System, do // not create and destroy a Unit directly. class Unit { public: + + // Identifies the kind of the Unit. + // NOTE: Kind is dependent on the owning System. + const AtomValue Kind; + // System-assigned unique identifier of the Unit instance, // based on the static member field CountUnits. const size_t Id; // Textual identifier of the Unit instance. Defaults to a text referring to // the Id value of the Unit, unless otherwise defined via a constructor // argument. The Name of a Unit is not necessarily unique in the system. const std::string Name; protected: // The owning System. System &S; public: // Full qualified name of the Unit instance. const std::string FullName; public: // Ctor. - Unit(const size_t Id, const std::string &Name, System &S) noexcept; + // PRE: !Name.empty() + Unit(const AtomValue Kind, const size_t Id, const std::string &Name, + System &S) noexcept; // No copy and move. Unit(const Unit &) = delete; Unit(Unit &&) = delete; Unit &operator=(const Unit &) = delete; Unit &operator=(Unit &&) = delete; // Dtor. virtual ~Unit(void); + // Dumping the object into a string for tracing purposes, + // subclasses are supposed to override this function. + virtual std::string dump(void) const noexcept; + +protected: // Returns a reference to the owning System. // NOTE: Subclasses may override the function to return a reference of a // special System subtype. virtual System &system() const noexcept; - - // Dumping the object into a string for tracing purposes, - // subclasses are supposed to override this function. - virtual std::string dump(void) const noexcept; }; // Helper function dumping the given Unit instance to the given output stream. std::ostream &operator<<(std::ostream &os, const Unit &U); } // End namespace rosa #endif // ROSA_CORE_UNIT_H diff --git a/lib/core/System.cpp b/lib/core/System.cpp index 4d97e23..77ace25 100644 --- a/lib/core/System.cpp +++ b/lib/core/System.cpp @@ -1,68 +1,52 @@ /******************************************************************************* * * File: System.cpp * * Contents: Implementation of System base-class. * * Copyright 2017 * * Author: David Juhasz (david.juhasz@tuwien.ac.at) * ******************************************************************************/ -#include "SystemImpl.h" -#include "rosa/config/config.h" +#include "SystemImpl.hpp" #include "rosa/core/Unit.h" -#include "rosa/core/System.h" -#include "rosa/support/debug.hpp" -#include "rosa/support/log.h" +#include "rosa/core/System.hpp" namespace rosa { std::unique_ptr System::createSystem(const std::string &Name) noexcept { return std::unique_ptr(new SystemImpl(Name)); } System::System(const std::string &Name) noexcept : Name(Name), CountUnits(0), SystemCleaned(false) { LOG_TRACE("Creating System (" + Name + ")"); } System::~System(void) { LOG_TRACE("Destroying System (" + Name + ")"); if (!SystemCleaned) { ROSA_CRITICAL("Trying to destroy a uncleaned System (" + Name + ")"); } } void System::markCleaned(void) noexcept { if (SystemCleaned) { ROSA_CRITICAL("System (" + Name + ") has been already mark cleaned"); } else if (!empty()) { ROSA_CRITICAL("Trying to mark a non-empty System (" + Name + ")"); } else { SystemCleaned = true; LOG_TRACE("System (" + Name + ") is marked clean"); } } -Unit &System::createUnit(UnitCreator C, const std::string &Name) noexcept { - if (SystemCleaned) { - ROSA_CRITICAL("Trying to create a Unit in an already cleaned System (" + - Name + ")"); - } - const uint64_t Id = ++CountUnits; - const std::string N = Name.empty() ? "Unit_" + std::to_string(Id) : Name; - Unit *U = C(Id, N, *this); - registerUnit(*U); - LOG_TRACE("Unit created and registered (" + U->FullName + ")"); - return *U; -} - size_t System::numberOfConstructedUnits(void) const noexcept { return CountUnits; } } // End namespace rosa diff --git a/lib/core/SystemImpl.cpp b/lib/core/SystemImpl.cpp index b3b29b5..97f83d4 100644 --- a/lib/core/SystemImpl.cpp +++ b/lib/core/SystemImpl.cpp @@ -1,68 +1,68 @@ /******************************************************************************* * * File: SystemImpl.cpp * * Contents: Definition of the SystemImpl class * * Copyright 2017 * * Author: David Juhasz (david.juhasz@tuwien.ac.at) * ******************************************************************************/ -#include "SystemImpl.h" +#include "SystemImpl.hpp" #include "rosa/core/Unit.h" #include "rosa/config/config.h" #include "rosa/support/debug.hpp" #include "rosa/support/log.h" namespace rosa { SystemImpl::SystemImpl(const std::string &Name) noexcept : System(Name) {} SystemImpl::~SystemImpl(void) { if (!empty()) { ROSA_CRITICAL("Trying to destroy a non-empty System (" + Name + ")"); } else { markCleaned(); } } void SystemImpl::registerUnit(Unit &U) noexcept { // Obtain exclusive access and instert the Unit. std::lock_guard L(RegisterMutex); auto R = Units.insert(&U); if (!R.second) { ROSA_CRITICAL("Could not register Unit"); } } void SystemImpl::destroyUnit(Unit &U) noexcept { ASSERT(isUnitRegistered(U)); LOG_TRACE("Destroying Unit (" + U.FullName + ")"); // Scope protected container access. { // Obtain exclusive access and remove the Unit. std::lock_guard L(RegisterMutex); auto R = Units.erase(&U); // NOTE: This case is catched by assertion when that is enabled. if (!R) { ROSA_CRITICAL("Trying to remove unregistered Unit"); } } delete &U; } bool SystemImpl::isUnitRegistered(const Unit &U) const noexcept { // NOTE: Casting away constness is safe here. return Units.find(const_cast(&U)) != Units.cend(); } size_t SystemImpl::numberOfLiveUnits(void) const noexcept { return Units.size(); } bool SystemImpl::empty(void) const noexcept { return Units.empty(); } } // End namespace rosa diff --git a/lib/core/SystemImpl.h b/lib/core/SystemImpl.hpp similarity index 88% rename from lib/core/SystemImpl.h rename to lib/core/SystemImpl.hpp index e1f3816..0365336 100644 --- a/lib/core/SystemImpl.h +++ b/lib/core/SystemImpl.hpp @@ -1,61 +1,61 @@ /******************************************************************************* * - * File: SystemImpl.h + * File: SystemImpl.hpp * * Contents: Declaration of a basic implementation of the System interface. * * Copyright 2017 * * Author: David Juhasz (david.juhasz@tuwien.ac.at) * ******************************************************************************/ -#ifndef ROSA_LIB_CORE_SYSTEMIMPL_H -#define ROSA_LIB_CORE_SYSTEMIMPL_H +#ifndef ROSA_LIB_CORE_SYSTEMIMPL_HPP // NOLINT +#define ROSA_LIB_CORE_SYSTEMIMPL_HPP -#include "rosa/core/System.h" +#include "rosa/core/System.hpp" #include #include namespace rosa { class SystemImpl : public System { public: SystemImpl(const std::string &Name) noexcept; ~SystemImpl(void); private: // Container for keeping reference of registered Units. std::unordered_set Units; // Used to provide mutual exclusion when modifying Units. std::mutex RegisterMutex; protected: // Registers the given Unit instance to the System. // PRE: !isUnitRegistered(U) // POST: isUnitRegistered(U) void registerUnit(Unit &U) noexcept override; // Unregisters and destroys the given Unit. // PRE: isUnitRegistered(U) // POST: !isUnitRegistered(U) && 'U is destroyed' void destroyUnit(Unit &U) noexcept override; // Returns if the given Unit is registered in the System. bool isUnitRegistered(const Unit &U) const noexcept override; public: // Returns the number of live Units, that have been constructed and not // destroyed yet. size_t numberOfLiveUnits(void) const noexcept override; // Returns if the System has no live Units. bool empty(void) const noexcept override; }; } // End namespace rosa -#endif // ROSA_LIB_CORE_SYSTEMIMPL_H +#endif // ROSA_LIB_CORE_SYSTEMIMPL_HPP diff --git a/lib/core/Unit.cpp b/lib/core/Unit.cpp index d0a6039..e413cd3 100644 --- a/lib/core/Unit.cpp +++ b/lib/core/Unit.cpp @@ -1,49 +1,53 @@ /******************************************************************************* * * File: Unit.cpp * * Contents: Implementation of Unit base-class. * * Copyright 2017 * * Author: David Juhasz (david.juhasz@tuwien.ac.at) * ******************************************************************************/ #include "rosa/core/Unit.h" -#include "rosa/core/System.h" + +#include "rosa/core/System.hpp" #include "rosa/support/debug.hpp" #include "rosa/support/log.h" namespace rosa { // Ctor. Initializing member fields. -Unit::Unit(const size_t Id, const std::string &Name, System &S) noexcept - : Id(Id), - Name(Name), - S(S), - FullName(Name + "@" + S.Name) { - LOG_TRACE("Constructing Unit (" + FullName + ")"); +Unit::Unit(const AtomValue Kind, const size_t Id, const std::string &Name, + System &S) noexcept : Kind(Kind), + Id(Id), + Name(Name), + S(S), + FullName(Name + "@" + S.Name) { + ASSERT(!Name.empty()); + LOG_TRACE("Constructing Unit (" + FullName + " of kind '" + to_string(Kind) + + "')"); } // Dtor. Unit::~Unit(void) { LOG_TRACE("Destroying Unit (" + FullName + ")"); } -System &Unit::system(void) const noexcept { - return S; -} - // Default dump function, emitting the Name of the Unit. std::string Unit::dump(void) const noexcept { LOG_TRACE("Dumping Unit (" + FullName + ")"); return "[Unit] " + FullName; } +System &Unit::system(void) const noexcept { + return S; +} + std::ostream &operator<<(std::ostream &os, const Unit &U) { os << U.dump(); return os; } } // End namespace rosa