ChimeraTK-ApplicationCore 04.06.00
Loading...
Searching...
No Matches
InversionOfControlAccessor.h
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Deutsches Elektronen-Synchrotron DESY, MSK, ChimeraTK Project <chimeratk-support@desy.de>
2// SPDX-License-Identifier: LGPL-3.0-or-later
3#pragma once
4
5#include "Application.h"
6#include "ApplicationModule.h"
7#include "Module.h"
8#include "Utilities.h"
10
11#include <boost/smart_ptr/shared_ptr.hpp>
12
13#include <string>
14
15namespace ChimeraTK {
16
17 /********************************************************************************************************************/
18
22 template<typename Derived>
24 public:
27
33 void setMetaData(const std::optional<std::string>& name, const std::optional<std::string>& unit = {},
34 const std::optional<std::string>& description = {},
35 const std::optional<std::unordered_set<std::string>>& tags = {});
36
39 void addTag(const std::string& tag) { _node.addTag(tag); }
40
43 void addTags(const std::unordered_set<std::string>& tags);
44
46 const std::unordered_set<std::string>& getTags();
47
49 explicit operator VariableNetworkNode() { return _node; }
50 explicit operator VariableNetworkNode() const { return _node; }
51
53 void replace(Derived&& other);
54
56 [[nodiscard]] EntityOwner* getOwner() const { return _node.getOwningModule(); }
57
58 [[nodiscard]] Model::ProcessVariableProxy getModel() const { return _node.getModel(); }
59
60 protected:
62 InversionOfControlAccessor(Module* owner, const std::string& name, VariableDirection direction, std::string unit,
63 size_t nElements, UpdateMode mode, const std::string& description, const std::type_info* valueType,
64 const std::unordered_set<std::string>& tags = {});
65
68
70 [[nodiscard]] std::string completeDescription(EntityOwner* owner, const std::string& description) const;
71
74
76 };
77
78 /********************************************************************************************************************/
79 /********************************************************************************************************************/
80
81 template<typename Derived>
83 if(getOwner() != nullptr) {
84 if(static_cast<Derived*>(this)->_impl != nullptr) {
85 auto* entity = getOwner();
86
87 if(entity != nullptr) {
88 auto* owner = dynamic_cast<Module*>(entity);
89 while(owner->getOwner() != nullptr) {
90 owner = dynamic_cast<Module*>(owner->getOwner());
91 }
92
93 auto* application = dynamic_cast<Application*>(owner);
94 assert(application != nullptr);
95
96 if(application->getLifeCycleState() == LifeCycleState::run) {
97 try {
98 throw ChimeraTK::logic_error(
99 "Variable has been destroyed with active connections while application is "
100 "still running. Maybe the Application did not call shutdown() in its destructor?");
101 }
102 catch(ChimeraTK::logic_error&) {
103 std::terminate();
104 }
105 }
106 }
107 }
108 getOwner()->unregisterAccessor(_node);
109 }
110 if(getModel().isValid()) {
111 try {
112 getModel().removeNode(_node);
113 }
114 catch(ChimeraTK::logic_error& e) {
115 std::cerr << "ChimeraTK::logic_error caught: " << e.what() << std::endl;
116 std::terminate();
117 }
118 }
119 }
120
121 /********************************************************************************************************************/
122
123 template<typename Derived>
124 void InversionOfControlAccessor<Derived>::setMetaData(const std::optional<std::string>& name,
125 const std::optional<std::string>& unit, const std::optional<std::string>& description,
126 const std::optional<std::unordered_set<std::string>>& tags) {
127 std::optional<std::string> description_ = description;
128 if(description.has_value()) {
129 description_ = completeDescription(getOwner(), description.value());
130 }
131 _node.setMetaData(name, unit, description_, tags);
132 }
133
134 /********************************************************************************************************************/
135
136 template<typename Derived>
137 void InversionOfControlAccessor<Derived>::addTags(const std::unordered_set<std::string>& tags) {
138 for(const auto& tag : tags) {
139 _node.addTag(tag);
140 }
141 }
142
143 /********************************************************************************************************************/
144
145 template<typename Derived>
146 const std::unordered_set<std::string>& InversionOfControlAccessor<Derived>::getTags() {
147 return _node.getTags();
148 }
149
150 /********************************************************************************************************************/
151
152 template<typename Derived>
154 if(static_cast<Derived*>(this)->_impl != nullptr || other._impl != nullptr) {
155 try {
156 throw ChimeraTK::logic_error(
157 "Variable has been destroyed with active connections while application is still running");
158 }
159 catch(ChimeraTK::logic_error& ex) {
160 std::terminate();
161 }
162 }
163
164 // remove accessor from owning module
165 if(getOwner() != nullptr) {
166 getOwner()->unregisterAccessor(_node);
167 }
168
169 // remove node from model
170 if(getModel().isValid()) {
171 getModel().removeNode(_node);
172 }
173
174 // transfer the node
175 _node = std::move(other._node);
176 other._node = VariableNetworkNode(); // Make sure the destructor of other sees an invalid node
177
178 // update the app accessor pointer in the node
179 if(_node.getType() == NodeType::Application) {
180 _node.setAppAccessorPointer(static_cast<Derived*>(this));
181 }
182 else {
183 assert(_node.getType() == NodeType::invalid);
184 }
185 // Note: the accessor is registered by the VariableNetworkNode, so we don't have to re-register.
186 }
187
188 /********************************************************************************************************************/
189
190 template<typename Derived>
192 EntityOwner* owner, const std::string& description) const {
193 auto ownerDescription = owner->getFullDescription();
194 if(ownerDescription.empty()) {
195 return description;
196 }
197 if(description.empty()) {
198 return ownerDescription;
199 }
200 return ownerDescription + " - " + description;
201 }
202
203 /********************************************************************************************************************/
204
205 template<typename Derived>
207 VariableDirection direction, std::string unit, size_t nElements, UpdateMode mode, const std::string& description,
208 const std::type_info* valueType, const std::unordered_set<std::string>& tags)
209 : _node(owner, static_cast<Derived*>(this), ChimeraTK::Utilities::raiseIftrailingSlash(name, false), direction, unit,
210 nElements, mode, completeDescription(owner, description), valueType, tags) {
211 static_assert(std::is_base_of<InversionOfControlAccessor<Derived>, Derived>::value,
212 "InversionOfControlAccessor<> must be used in a curiously recurring template pattern!");
213
215
216 owner->registerAccessor(_node);
217 }
218
219 /********************************************************************************************************************/
220
221 template<typename Derived>
223 _node.registerInModel();
224 }
225
226 /********************************************************************************************************************/
227
228} // namespace ChimeraTK
Base class for owners of other EntityOwners (e.g.
Definition EntityOwner.h:38
void registerAccessor(VariableNetworkNode accessor)
Called inside the constructor of Accessor: adds the accessor to the list.
virtual std::string getFullDescription() const =0
Obtain the full description including the full description of the owner.
Adds features required for inversion of control to an accessor.
void setMetaData(const std::optional< std::string > &name, const std::optional< std::string > &unit={}, const std::optional< std::string > &description={}, const std::optional< std::unordered_set< std::string > > &tags={})
Change meta data (name, unit, description and optionally tags).
void replace(Derived &&other)
Replace with other accessor.
EntityOwner * getOwner() const
Return the owning module.
std::string completeDescription(EntityOwner *owner, const std::string &description) const
complete the description with the full description from the owner
void addTags(const std::unordered_set< std::string > &tags)
Add multiple tags.
const std::unordered_set< std::string > & getTags()
Return set of tags.
void registerInModel()
Register the variable in the model.
InversionOfControlAccessor()=default
Default constructor creates a dysfunctional accessor (to be assigned with a real accessor later)
InversionOfControlAccessor(Module *owner, const std::string &name, VariableDirection direction, std::string unit, size_t nElements, UpdateMode mode, const std::string &description, const std::type_info *valueType, const std::unordered_set< std::string > &tags={})
Constructor, only used by child class accessors.
~InversionOfControlAccessor()
Unregister at its owner when deleting.
void addTag(const std::string &tag)
Add a tag.
Model::ProcessVariableProxy getModel() const
Base class for ApplicationModule and DeviceModule, to have a common interface for these module types.
Definition Module.h:21
Class describing a node of a variable network.
Model::ProcessVariableProxy getModel() const
void addTag(const std::string &tag) const
Add a tag.
InvalidityTracer application module.
@ run
Actual run phase with full multi threading.
UpdateMode
Enum to define the update mode of variables.
Definition Flags.h:31
Struct to define the direction of variables.
Definition Flags.h:13