//===-- core/SystemImpl.hpp -------------------------------------*- C++ -*-===//
//
//                                 The RoSA Framework
//
//===----------------------------------------------------------------------===//
///
/// \file core/SystemImpl.hpp
///
/// \author David Juhasz (david.juhasz@tuwien.ac.at)
///
/// \date 2017
///
/// \brief Declaration of a basic implementation of the \c rosa::System
/// interface.
///
//===----------------------------------------------------------------------===//

#ifndef ROSA_LIB_CORE_SYSTEMIMPL_HPP
#define ROSA_LIB_CORE_SYSTEMIMPL_HPP

#include "rosa/core/SystemBase.hpp"

#include <mutex>
#include <unordered_set>

namespace rosa {

/// A basic implementation of the \c rosa::System interface, which is based on
/// \c rosa::SystemBase and simply stores \c rosa::Unit instances in a set.
class SystemImpl : public SystemBase {
public:
  /// Creates a new instance.
  ///
  /// \param Name name of the new instance
  SystemImpl(const std::string &Name) noexcept;

  /// Destroys \p this object.
  ///
  /// \note The destructor deallocates internal resources and marks \p this
  /// object cleaned.
  ///
  /// \pre No live \c rosa::Unit instances are managed by \p this object:\code
  /// empty()
  /// \endcode
  ~SystemImpl(void);

private:
  /// Stores references for the registered \c rosa::Unit instances.
  std::unordered_set<Unit *> Units;

  /// Provides mutual exclusion when modifying \c rosa::Unit instances.
  std::mutex RegisterMutex;

protected:
  /// Registers a \c rosa::Unit instance to \p this object.
  ///
  /// \param U \c rosa::Unit to register
  ///
  /// \pre \p this object has not yet been marked as cleaned and \p U is not
  /// registered yet:\code
  /// !isSystemCleaned() && !isUnitRegistered(U)
  /// \endcode
  ///
  /// \post \p U is registered:\code
  /// isUnitRegistered(U)
  /// \endcode
  void registerUnit(Unit &U) noexcept override;

  /// Unregisters and destroys a registered \c rosa::Unit instance.
  ///
  /// \param U \c rosa::Unit to destroy
  ///
  /// \pre \p U is registered:\code
  /// isUnitRegistered(U)
  /// \endcode
  ///
  /// \post \p U is not registered:\code
  /// !isUnitRegistered(U)
  /// \endcode Moreover, \p U is destroyed.
  void destroyUnit(Unit &U) noexcept override;

  /// Tells if a \c rosa::Unit is registered in \p this object.
  ///
  /// \param U \c rosa::Unit to check
  ///
  /// \return whether \p U is registered in \p this object
  bool isUnitRegistered(const Unit &U) const noexcept override;

public:
  /// 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 \c rosa::Unit instances alive
  size_t numberOfLiveUnits(void) const noexcept override;

  /// Tells if \p this object has no live \c rosa::Unit instances.
  ///
  /// \return whether \p this object has any live \c rosa::Unit instances
  bool empty(void) const noexcept override;
};

} // End namespace rosa

#endif // ROSA_LIB_CORE_SYSTEMIMPL_HPP
