diff --git a/examples/simple/simple.cpp b/examples/simple/simple.cpp index 8e55581..0a718cc 100644 --- a/examples/simple/simple.cpp +++ b/examples/simple/simple.cpp @@ -1,29 +1,54 @@ /******************************************************************************* * * File: simple.cpp * * Contents: A very simple example to use 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/support/log.h" #include "rosa/support/terminal_colors.h" #include using namespace rosa; using namespace rosa::terminal; +// A dummy implementation of System. +class MySystem : public System { +public: + MySystem(const std::string &Name) : System(Name) {} + + // Has the base-class to create a Unit instance. + Unit &createMyUnit(const std::string &Name = std::string()) { + return createUnit([](const size_t Id, const std::string &N, + System &S) { return new Unit(Id, N, S); }, + Name); + } + + // Has the base-class to destroy the Unit instance. + void destroyMyUnit(Unit &U) { + destroyUnit(U); + } +}; + int main(void) { LOG_INFO_STREAM << library_string() << " -- " << Color::Red << "simple example" << Color::Default << std::endl; - Unit Unit1, Unit2("Second"), Unit3; - LOG_TRACE_STREAM << "Dumping Unit2" << std::endl << Unit2 << std::endl; + + MySystem S("Sys"); + Unit &Unit1 = S.createMyUnit(), &Unit2 = S.createMyUnit("Second"), + &Unit3 = S.createMyUnit(); + S.destroyMyUnit(Unit1); + S.destroyMyUnit(Unit3); + LOG_INFO_STREAM << "Dumping Unit2" << std::endl << Unit2 << std::endl; + S.destroyMyUnit(Unit2); return 0; } diff --git a/include/rosa/core/System.h b/include/rosa/core/System.h new file mode 100644 index 0000000..71e1b64 --- /dev/null +++ b/include/rosa/core/System.h @@ -0,0 +1,82 @@ +/******************************************************************************* + * + * File: System.h + * + * 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 + +#include +#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. +class System { +public: + // Signature of creator functions for Units. + using UnitCreator = Unit *(*)(const size_t, const std::string&, System&); + +protected: + // Protected ctor, only subclasses can instantiate. + System(const std::string &Name) noexcept; + + // Dtor. Only an empty System can be destroyed. + // PRE: empty() + virtual ~System(void); + + // Creates a Unit instance with the given UnitCreator, using the given Name + // if any, and registers the new Unit instance. + Unit &createUnit(UnitCreator C, + const std::string &Name = std::string()) noexcept; + + // Unregisters and destroys the given Unit. + // PRE: Units.find(&U) != Units.end() + void destroyUnit(Unit &U) noexcept; + +public: + // The textual name of the System. + const std::string Name; + +private: + // Number of Units constructed in the system. + // NOTE: Should never decrement! + std::atomic CountUnits; + + // Container for keeping reference of registered Units. + std::unordered_set Units; + + // Used to provide mutual exclusion when modifying Units. + std::mutex RegisterMutex; + +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. + size_t numberOfLiveUnits(void) const noexcept; + + // Returns if the System has no live Units. + bool empty(void) const noexcept; +}; + +} // End namespace rosa + +#endif // ROSA_CORE_SYSTEM_H + diff --git a/include/rosa/core/Unit.h b/include/rosa/core/Unit.h index c2c43ba..7c5fb8f 100644 --- a/include/rosa/core/Unit.h +++ b/include/rosa/core/Unit.h @@ -1,59 +1,76 @@ /******************************************************************************* * * 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 #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 { -private: - // Number of Units constructed in the system. - static std::atomic CountUnits; - - // Number of live units, those having been constructed and not yet destroyed. - static std::atomic LiveUnits; - public: // System-assigned unique identifier of the Unit instance, // based on the static member field CountUnits. - const uint64_t Id; + 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 std::string &Name = std::string()) noexcept; + Unit(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) noexcept; + // 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 &unit); +std::ostream &operator<<(std::ostream &os, const Unit &U); } // End namespace rosa #endif // ROSA_CORE_UNIT_H diff --git a/lib/core/CMakeLists.txt b/lib/core/CMakeLists.txt index abd427d..2f4d488 100644 --- a/lib/core/CMakeLists.txt +++ b/lib/core/CMakeLists.txt @@ -1,6 +1,7 @@ add_library(ROSACore Unit.cpp + System.cpp ) ROSA_add_library_dependencies(ROSACore ROSASupport) diff --git a/lib/core/System.cpp b/lib/core/System.cpp new file mode 100644 index 0000000..1474070 --- /dev/null +++ b/lib/core/System.cpp @@ -0,0 +1,75 @@ +/******************************************************************************* + * + * File: System.cpp + * + * Contents: Implementation of System base-class. + * + * Copyright 2017 + * + * Author: David Juhasz (david.juhasz@tuwien.ac.at) + * + ******************************************************************************/ + +#include "rosa/core/System.h" +#include "rosa/core/Unit.h" +#include "rosa/config/config.h" +#include "rosa/support/debug.hpp" +#include "rosa/support/log.h" + +namespace rosa { + +System::System(const std::string &Name) noexcept : Name(Name), + CountUnits(0) { + LOG_TRACE("Creating System (" + Name + ")"); +} + +System::~System(void) { + LOG_TRACE("Destroying System (" + Name + ")"); + if (!empty()) { + ROSA_CRITICAL("Trying to destroy a non-empty System"); + } +} + +Unit &System::createUnit(UnitCreator C, const std::string &Name) noexcept { + const uint64_t Id = ++CountUnits; + const std::string N = Name.empty() ? "Unit_" + std::to_string(Id) : Name; + Unit *U = C(Id, N, *this); + // Scope protected container access. + { + // Obtain exclusive access and instert the Unit. + std::lock_guard L(RegisterMutex); + auto result = Units.insert(U); + if (!result.second) { + ROSA_CRITICAL("Could not register Unit"); + } + } + LOG_TRACE("Unit created and registered (" + U->FullName + ")"); + return *U; +} + +void System::destroyUnit(Unit &U) noexcept { + ASSERT(Units.find(&U) != Units.end()); + LOG_TRACE("Destroying Unit (" + U.FullName + ")"); + // Scope protected container access. + { + // Obtain exclusive access and remove the Unit. + std::lock_guard L(RegisterMutex); + auto result = Units.erase(&U); + // NOTE: This case is catched by assertion when that is enabled. + if (!result) { + ROSA_CRITICAL("Trying to remove unregistered Unit"); + } + } + delete &U; +} + +size_t System::numberOfConstructedUnits(void) const noexcept { + return CountUnits; +} + +size_t System::numberOfLiveUnits(void) const noexcept { return Units.size(); } + +bool System::empty(void) const noexcept { return numberOfLiveUnits() == 0; } + +} // End namespace rosa + diff --git a/lib/core/Unit.cpp b/lib/core/Unit.cpp index a9fc962..bda3e1e 100644 --- a/lib/core/Unit.cpp +++ b/lib/core/Unit.cpp @@ -1,52 +1,49 @@ /******************************************************************************* * * 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/support/debug.hpp" #include "rosa/support/log.h" namespace rosa { -// Zero-initialized definitions of static members. -// NOTE: Initialization is not atomic. -std::atomic Unit::CountUnits(0); -std::atomic Unit::LiveUnits(0); - -// Ctor. Incrementing static counters and initializing member fields. -Unit::Unit(const std::string &Name) noexcept - : Id(++CountUnits), - Name(Name.empty() ? "Unit_" + std::to_string(Id) : Name) { - LOG_TRACE("Constructing Unit (" + this->Name + ")"); - ++LiveUnits; +// 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 + ")"); } -// Dtor. Decrementing static live counter. -Unit::~Unit(void) noexcept { - LOG_TRACE("Destroying Unit (" + Name + ")"); - --LiveUnits; - ASSERT(LiveUnits >= 0); +// Dtor. +Unit::~Unit(void) noexcept { 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 (" + Name + ")"); - return "[Unit] " + Name; + LOG_TRACE("Dumping Unit (" + FullName + ")"); + return "[Unit] " + FullName; } -std::ostream &operator<<(std::ostream &os, const Unit &unit) { - os << unit.dump(); +std::ostream &operator<<(std::ostream &os, const Unit &U) { + os << U.dump(); return os; } } // End namespace rosa