diff --git a/include/rosa/core/System.hpp b/include/rosa/core/System.hpp index 3ea3fab..4c47fd4 100644 --- a/include/rosa/core/System.hpp +++ b/include/rosa/core/System.hpp @@ -1,135 +1,135 @@ /******************************************************************************* * * File: System.hpp * - * Contents: Declaration of System base-class. + * Contents: Declaration of System interface. * * Copyright 2017 * * Author: David Juhasz (david.juhasz@tuwien.ac.at) * ******************************************************************************/ #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. +// Base interface for actual agent-systems, the class provides facilities to +// keep track of Units of the system. +// NOTE: Any subclasses are 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 SystemBase +// implenenting a base feature-set. class System { public: + // Type alias for Ids used by the System to identify Units. + using id_t = size_t; + // Signature of creator functions for Units. 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; + System(void) noexcept = default; // 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); + // Dtor. + // NOTE: Any implementation makes sure that only a cleaned System can be + // destroyed. + virtual ~System(void) = default; protected: + // Tells the next Id to be used for a newly created Unit. + // NOTE: Never returs nthe same value twice. + virtual id_t nextId(void) noexcept = 0; - // 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; + // Tells if the System has been marked clean and ready for destruction. + virtual bool isSystemCleaned(void) const noexcept = 0; - // 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 - template - T &createUnit(UnitCreator C) noexcept; + // Marks the System cleaned. Can be called only once when the System does not + // have any live Units. + // PRE: !isSystemCleaned() && empty() + // POST: isSystemCleaned() + virtual void markCleaned(void) noexcept = 0; // 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; + // 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. + // STATIC PRE: std::is_base_of::value + // PRE: !isSystemCleaned() + template + T &createUnit(UnitCreator C) noexcept; public: + // Tells the textual name of the System. + // NOTE: The returned reference remains valid as long as the originating + // System is not destroyed. + virtual const std::string &name(void) const noexcept = 0; + // Returns the number of Units constructed in the System so far, // including those being already destroyed. - size_t numberOfConstructedUnits(void) const noexcept; + virtual size_t numberOfConstructedUnits(void) const noexcept = 0; // 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 + ")"); + if (isSystemCleaned()) { + ROSA_CRITICAL("Trying to create a Unit in a cleaned System (" + name() + + ")"); } - const uint64_t Id = ++CountUnits; + const id_t Id = nextId(); T *U = C(Id, *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 new file mode 100644 index 0000000..a076353 --- /dev/null +++ b/include/rosa/core/SystemBase.hpp @@ -0,0 +1,80 @@ +/******************************************************************************* + * + * File: SystemBase.hpp + * + * Contents: Declaration of the base implementation of the System interface. + * + * Copyright 2017 + * + * Author: David Juhasz (david.juhasz@tuwien.ac.at) + * + ******************************************************************************/ + +#ifndef ROSA_CORE_SYSTEMBASE_HPP +#define ROSA_CORE_SYSTEMBASE_HPP + +#include "rosa/core/System.hpp" + +#include + +namespace rosa { + +// Base implementation of the System interface, that provides only the name of +// the System, identifiers for Units, and marking the System cleaned for +// destruction. +// NOTE: Actual implementations of the System and derived interfaces are +// supposed to inherit from this base implementation. +class SystemBase : public System { +protected: + // Protected ctor, only subclasses can instantiate. + SystemBase(const std::string &Name) noexcept; + +public: + // Dtor. + // PRE: isSystemCleaned() + ~SystemBase(void); + +protected: + // 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 a referene to the Name field. + const std::string &name(void) const noexcept override; + +protected: + // Tells the next Id to be used for a newly created Unit while + // incrementing the value in field CountUnits. + // NOTE: This is the only function modifying the member field CountUnits. + id_t nextId(void) noexcept override; + + // Returns the value of SystemCleaned flag. + bool isSystemCleaned(void) const noexcept override; + + // Sets SystemCleaned flag. + // PRE: !isSystemCleaned() && empty() + // POST: isSystemCleaned + void markCleaned(void) noexcept override; + + // Returns the number of Units constructed in the System so far, + // including those being already destroyed. + size_t numberOfConstructedUnits(void) const noexcept override; +}; + +} // End namespace rosa + +#endif // ROSA_LIB_CORE_SYSTEMBASE_HPP + diff --git a/lib/core/CMakeLists.txt b/lib/core/CMakeLists.txt index 55fc488..ca1162d 100644 --- a/lib/core/CMakeLists.txt +++ b/lib/core/CMakeLists.txt @@ -1,11 +1,12 @@ add_library(ROSACore Unit.cpp System.cpp + SystemBase.cpp SystemImpl.cpp Message.cpp Invoker.cpp MessageHandler.cpp ) ROSA_add_library_dependencies(ROSACore ROSASupport) diff --git a/lib/core/System.cpp b/lib/core/System.cpp index 626835e..14996f8 100644 --- a/lib/core/System.cpp +++ b/lib/core/System.cpp @@ -1,54 +1,24 @@ /******************************************************************************* * * File: System.cpp * - * Contents: Implementation of System base-class. + * Contents: Implementation of System interface. * * Copyright 2017 * * Author: David Juhasz (david.juhasz@tuwien.ac.at) * ******************************************************************************/ #include "rosa/core/System.hpp" #include "SystemImpl.hpp" -#include "rosa/core/Unit.h" - 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"); - } -} - -size_t System::numberOfConstructedUnits(void) const noexcept { - return CountUnits; -} - } // End namespace rosa diff --git a/lib/core/System.cpp b/lib/core/SystemBase.cpp similarity index 51% copy from lib/core/System.cpp copy to lib/core/SystemBase.cpp index 626835e..a0efac8 100644 --- a/lib/core/System.cpp +++ b/lib/core/SystemBase.cpp @@ -1,54 +1,59 @@ /******************************************************************************* * - * File: System.cpp + * File: SystemBase.cpp * - * Contents: Implementation of System base-class. + * Contents: Implementation of SystemBase. * * Copyright 2017 * * Author: David Juhasz (david.juhasz@tuwien.ac.at) * ******************************************************************************/ -#include "rosa/core/System.hpp" - -#include "SystemImpl.hpp" - -#include "rosa/core/Unit.h" +#include "rosa/core/SystemBase.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) { +SystemBase::SystemBase(const std::string &Name) noexcept + : Name(Name), + CountUnits(0), + SystemCleaned(false) { LOG_TRACE("Creating System (" + Name + ")"); } -System::~System(void) { - LOG_TRACE("Destroying System (" + Name + ")"); +SystemBase::~SystemBase(void) { if (!SystemCleaned) { - ROSA_CRITICAL("Trying to destroy a uncleaned System (" + Name + ")"); + ROSA_CRITICAL("Trying to destroy an uncleaned System (" + Name + ")"); } + LOG_TRACE("Destroying System (" + Name + ")"); +} + +const std::string &SystemBase::name() const noexcept { + return Name; +} + +System::id_t SystemBase::nextId(void) noexcept { + return ++CountUnits; +} + +bool SystemBase::isSystemCleaned(void) const noexcept { + return SystemCleaned; } -void System::markCleaned(void) noexcept { +void SystemBase::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"); } } -size_t System::numberOfConstructedUnits(void) const noexcept { +size_t SystemBase::numberOfConstructedUnits(void) const noexcept { return CountUnits; } } // End namespace rosa diff --git a/lib/core/SystemImpl.cpp b/lib/core/SystemImpl.cpp index 3339938..062db70 100644 --- a/lib/core/SystemImpl.cpp +++ b/lib/core/SystemImpl.cpp @@ -1,71 +1,66 @@ /******************************************************************************* * * File: SystemImpl.cpp * - * Contents: Definition of the SystemImpl class. + * Contents: Implementation of the SystemImpl class. * * Copyright 2017 * * Author: David Juhasz (david.juhasz@tuwien.ac.at) * ******************************************************************************/ #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(const std::string &Name) noexcept : SystemBase(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.hpp b/lib/core/SystemImpl.hpp index ce2dc81..a50315d 100644 --- a/lib/core/SystemImpl.hpp +++ b/lib/core/SystemImpl.hpp @@ -1,64 +1,67 @@ /******************************************************************************* * * 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_HPP // NOLINT #define ROSA_LIB_CORE_SYSTEMIMPL_HPP -#include "rosa/core/System.hpp" +#include "rosa/core/SystemBase.hpp" #include #include namespace rosa { // A basic implementation of the System interface, which simply stores Units in // a set. -class SystemImpl : public System { +class SystemImpl : public SystemBase { public: + // Ctor. SystemImpl(const std::string &Name) noexcept; + // Dtor. + // PRE: empty() ~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_HPP diff --git a/lib/core/Unit.cpp b/lib/core/Unit.cpp index 5968020..a768590 100644 --- a/lib/core/Unit.cpp +++ b/lib/core/Unit.cpp @@ -1,54 +1,54 @@ /******************************************************************************* * * 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.hpp" #include "rosa/support/debug.hpp" #include "rosa/support/log.h" namespace rosa { // Ctor. Initializing member fields. 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) { + 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 + ")"); } // 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