Skip to content
Snippets Groups Projects
EntityOwner.h 9.19 KiB
Newer Older
// SPDX-FileCopyrightText: Deutsches Elektronen-Synchrotron DESY, MSK, ChimeraTK Project <chimeratk-support@desy.de>
// SPDX-License-Identifier: LGPL-3.0-or-later
#pragma once
#include "Flags.h"
#include "VariableNetworkNode.h"
#include <unordered_set>
#include <string>
  /********************************************************************************************************************/

  class AccessorBase;
  class Module;

  /********************************************************************************************************************/

   *  Convenience type definition which can optionally be used as a shortcut for the type which defines a list of
   *  tags.
   */
  using TAGS = const std::unordered_set<std::string>;

  /********************************************************************************************************************/

   *  Base class for owners of other EntityOwners (e.g. Modules) and Accessors.
   *  FIXME: Unify with Module class (not straight forward!).
  class EntityOwner {
   public:
    /** Constructor: Create EntityOwner by the given name with the given description. The specified list of
     *  tags will be added to all elements directly or indirectly owned by this instance. */
    EntityOwner(std::string name, std::string description, std::unordered_set<std::string> tags = {});

    /** Default constructor just for late initialisation */

    /** Virtual destructor to make the type polymorphic */
    virtual ~EntityOwner() = default;

    /** Move constructor */
    EntityOwner(EntityOwner&& other) noexcept { operator=(std::move(other)); }
    EntityOwner(const EntityOwner& other) = delete;

    /** Move assignment operator */
    EntityOwner& operator=(EntityOwner&& other) noexcept;
    EntityOwner& operator=(const EntityOwner& other) = delete;

    /** Get the name of the module instance */
    const std::string& getName() const { return _name; }

    /** Get the fully qualified name of the module instance, i.e. the name
     * containing all module names further up in the hierarchy. */
    virtual std::string getQualifiedName() const = 0;

    /** Get the description of the module instance */
    const std::string& getDescription() const { return _description; }

    /** Obtain the full description including the full description of the owner.
     */
    virtual std::string getFullDescription() const = 0;

    /** Obtain the list of accessors/variables directly associated with this
     * instance */
    std::list<VariableNetworkNode> getAccessorList() const { return _accessorList; }

    /** Obtain the list of submodules associated with this instance */
    std::list<Module*> getSubmoduleList() const { return _moduleList; }

    /** Obtain the list of accessors/variables associated with this instance and
     * any submodules */
    std::list<VariableNetworkNode> getAccessorListRecursive() const;

    /** Obtain the list of submodules associated with this instance and any
     * submodules */
    std::list<Module*> getSubmoduleListRecursive() const;

    /** Called inside the constructor of Accessor: adds the accessor to the list
     */
    void registerAccessor(VariableNetworkNode accessor);

    /** Called inside the destructor of Accessor: removes the accessor from the
     * list */
    void unregisterAccessor(const VariableNetworkNode& accessor) { _accessorList.remove(accessor); }
    /** Register another module as a sub-module. Will be called automatically by
     * all modules in their constructors. If addTags is set to false, the tags of
     * this EntityOwner will not be set to the module being registered. This is
     * e.g. used in the move-constructor of Module to prevent from altering the
     * tags in the move operation. */
    void registerModule(Module* module, bool addTags = true);

    /** Unregister another module as a sub-module. Will be called automatically by
     * all modules in their destructors. */
    virtual void unregisterModule(Module* module);

    /** Add a tag to all Application-type nodes inside this group. It will recurse
     * into any subgroups. See VariableNetworkNode::addTag() for additional
     * information about tags. */
    void addTag(const std::string& tag);

    /** Print the full hierarchy to stdout. */
    void dump(const std::string& prefix = "") const;

    enum class ModuleType { ApplicationModule, ModuleGroup, VariableGroup, ControlSystem, Device, Invalid };

    /** Return the module type of this module, or in case of a VirtualModule the
     * module type this VirtualModule was derived from. */
    virtual ModuleType getModuleType() const = 0;

    /** Return the current version number which has been received with the last
    virtual VersionNumber getCurrentVersionNumber() const = 0;

    /** Set the current version number. This function is called by the push-type
     * input accessors in their read functions. */
    virtual void setCurrentVersionNumber(VersionNumber versionNumber) = 0;

    /** Return the data validity flag. If any This function will be called by all output accessors in their write
     *  functions. */
    virtual DataValidity getDataValidity() const = 0;

    /** Set the data validity flag to fault and increment the fault counter. This function will be called by all input
     *  accessors when receiving the a faulty update if the previous update was ok. The caller of this function must
     *  ensure that calls to this function are paired to a subsequent call to decrementDataFaultCounter(). */
    virtual void incrementDataFaultCounter() = 0;

    /** Decrement the fault counter and set the data validity flag to ok if the counter has reached 0. This function
     *  will be called by all input accessors when receiving the an ok update if the previous update was faulty. The
     *  caller of this function must ensure that calles to this function are paired to a previous call to
     *  incrementDataFaultCounter(). */
    virtual void decrementDataFaultCounter() = 0;

    /** Use pointer to the module as unique identifier.*/
    virtual std::list<EntityOwner*> getInputModulesRecursively(std::list<EntityOwner*> startList) = 0;
    /** Get the ID of the circular dependency network (0 if none). This information is only available after
     *  the Application has finalised all connections.
     */
    virtual size_t getCircularNetworkHash() const = 0;
    /** Check whether this module has declared that it reached the testable mode. */
    bool hasReachedTestableMode();

    /**
     * Create a variable name which will be automatically connected with a constant value. This can be used when a
     * constant value.
     */
    template<typename T>
    std::string constant(T value);

    /**
     * Prefix for costants created by constant().
     */
    static const std::string namePrefixConstant;

    /** Convert HierarchyModifier into path qualification (for backwards compatibility only!) */
    // Silence annoying warnings here. The calling functions are deprecated as well, it is enoug
    // to get the warning from the callers of that code
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
    static std::string applyHierarchyModifierToName(std::string name, HierarchyModifier hierarchyModifier);
#pragma GCC diagnostic pop
    /** The name of this instance */
    std::string _name;

    /** The description of this instance */
    std::string _description;

    /** List of accessors owned by this instance */
    std::list<VariableNetworkNode> _accessorList;

    /** List of modules owned by this instance */
    std::list<Module*> _moduleList;

    /** List of tags to be added to all accessors and modules inside this module
     */
    std::unordered_set<std::string> _tags;

    /** Flag used by the testable mode to identify whether a thread within the EntityOwner has reached the point where
     *  the testable mode lock is acquired.
     *  @todo This should be moved to a more proper place in the hierarchy (e.g. ModuleImpl) after InternalModule class
     *  has been properly unified with the normal Module class. */
    std::atomic<bool> _testableModeReached{false};
  /********************************************************************************************************************/

  template<typename T>
  std::string EntityOwner::constant(T value) {
    // Make sure every constant has its unique name to avoid differently typed inputs to be connected to the same
    // constant. Note that the template type argument T may not match the expected type by the application, since the
    // type of the constant is determined by the input accessor, not by the type of the value argument of this function.
    // We hence need to use both the type name and a unique counter as part of the name. The unique counter lives inside
    // this template function and hence counts for each type T separately!
    static std::atomic<uint64_t> uid(0);
    return namePrefixConstant + "/" + DataType(typeid(T)).getAsString() + "/" + std::to_string(uid++) + "/" +
        userTypeToUserType<std::string>(value);
  }

  /********************************************************************************************************************/