11#include <boost/range/join.hpp>
20 namespace detail::FanIn {
21 template<
class AccessorType>
22 struct AccessorTypeHelper {};
24 template<scalar_accessor AccessorType>
25 struct AccessorTypeHelper<AccessorType> {
26 using type = ScalarRegisterAccessor<typename AccessorType::value_type>;
27 using out_type = ScalarOutput<typename AccessorType::value_type>;
28 using acc_type = ScalarAccessor<typename AccessorType::value_type>;
30 template<array_accessor AccessorType>
31 struct AccessorTypeHelper<AccessorType> {
32 using type = OneDRegisterAccessor<typename AccessorType::value_type>;
33 using out_type = ArrayOutput<typename AccessorType::value_type>;
34 using acc_type = ArrayAccessor<typename AccessorType::value_type>;
55 template<push_input AccessorType>
56 class FanIn :
public detail::FanIn::AccessorTypeHelper<AccessorType>::out_type {
58 using AbstractorType = detail::FanIn::AccessorTypeHelper<AccessorType>::type;
61 std::function<
value_type(TransferElementID,
const std::map<TransferElementID, AbstractorType>&)>;
62 using out_type = detail::FanIn::AccessorTypeHelper<AccessorType>::out_type;
82 AggregatorType aggregator,
const std::unordered_set<std::string>& tags = {});
97 FanIn(
VariableGroup* owner, std::string name, std::initializer_list<std::string> additionalNames, std::string unit,
98 const std::string& description,
AggregatorType aggregator,
const std::unordered_set<std::string>& tags = {});
131 using out_type::write;
132 using out_type::writeDestructively;
133 using out_type::writeIfDifferent;
134 using out_type::setAndWrite;
135 using out_type::read;
136 using out_type::readNonBlocking;
137 using out_type::readLatest;
138 using out_type::isReadOnly;
139 using out_type::isReadable;
140 using out_type::isWriteable;
146 Inputs(
VariableGroup* owner,
FanIn& output, std::string name,
auto additionalNames, std::string unit,
148 const std::unordered_set<std::string>& tags = {});
150 const AccessorType&
get(
const TransferElementID&
id)
const;
152 bool has(
const TransferElementID&
id)
const;
184 template<user_type U>
188 : NDRegisterAccessorDecorator<U>(target), _fanIn(fanIn) {}
190 void doPostRead(TransferType type,
bool updateDataBuffer)
override;
208 template<user_type UserType>
211 template<user_type UserType>
214 template<user_type UserType>
217 template<user_type UserType>
220 static constexpr auto fanInKeepLastValue = [](
auto id,
const auto& map) {
return map.at(
id); };
225 template<push_input AccessorType>
227 AggregatorType aggregator,
const std::unordered_set<std::string>& tags)
228 :
detail::
FanIn::AccessorTypeHelper<AccessorType>::
out_type(owner, name, unit, description, tags),
229 _inputs(owner, *this, name, std::span<std::string>{}, unit, description, aggregator, tags) {}
233 template<push_input AccessorType>
235 std::string unit,
const std::string& description,
AggregatorType aggregator,
236 const std::unordered_set<std::string>& tags)
237 :
detail::
FanIn::AccessorTypeHelper<AccessorType>::
out_type(owner, name, unit, description, tags),
238 _inputs(owner, *this, name, additionalNames, unit, description, aggregator, tags) {}
242 template<push_input AccessorType>
246 other._inputs._additionalNames, other._inputs._unit,
"", other._inputs._aggregator};
255 template<push_input AccessorType>
258 return _inputs._accessorMap | std::views::values |
259 std::views::transform([](
const auto* p) ->
const auto& {
return *p; });
264 template<push_input AccessorType>
267 return _inputs._accessorMap | std::views::values | std::views::transform([](
auto* p) ->
auto& {
return *p; });
273 template<push_input AccessorType>
275 std::string unit,
const std::string& description,
AggregatorType aggregator,
276 const std::unordered_set<std::string>& tags)
277 :
VariableGroup(owner,
".", description, tags), _name(std::move(name)), _unit(std::move(unit)),
278 _additionalNames(additionalNames.begin(), additionalNames.end()), _aggregator(aggregator), _output(&output) {}
282 template<push_input AccessorType>
284 assert(_output !=
nullptr);
286 std::list<std::string> inputNames;
288 auto nodes = _output->getModel().getNodes();
292 for(
auto& node : nodes) {
299 auto qualifiedName = node->getModel().getFullyQualifiedPath();
300 inputNames.emplace_back(qualifiedName +
"/__FanInNode_" + std::to_string(index) +
"__");
301 node->setMetaData(inputNames.back());
305 for(
auto& name : boost::join(inputNames, _additionalNames)) {
306 _inputs.emplace_back(
this, name,
"",
"");
312 template<push_input AccessorType>
314 if(!_accessorMap.empty()) {
321 auto deco = boost::make_shared<TrackingDecorator<typename AccessorType::value_type>>(
input.getImpl(), *
this);
322 input.NDRegisterAccessorAbstractor<typename AccessorType::value_type>::replace(deco);
331 template<push_input AccessorType>
333 if(_accessorMap.empty()) {
334 throw ChimeraTK::logic_error(
"FanIn::get() called too early, prepare() has not yet been called.");
337 return *(_accessorMap.at(
id));
342 template<push_input AccessorType>
344 if(_accessorMap.empty()) {
345 throw ChimeraTK::logic_error(
"FanIn::get() called too early, prepare() has not yet been called.");
348 return _accessorMap.contains(
id);
353 template<push_input AccessorType>
355 assert(_output !=
nullptr);
357 _lastUpdate = change;
361 if(_output->getVersionNumber() == VersionNumber{nullptr}) {
362 for(
const auto& [
id, inp] : _abstractorMap) {
363 if(inp.getVersionNumber() == VersionNumber{
nullptr}) {
369 if(type != UpdateType::ACCEPT) {
370 *_output = _aggregator(change, _abstractorMap);
373 if(_output->getVersionNumber() == VersionNumber{nullptr} && _hasValidator && type != UpdateType::POST_READ) {
374 ++_nInitialValuesValidated;
375 if(_nInitialValuesValidated <
_inputs.size()) {
382 if(!_hasValidator || type != UpdateType::POST_READ) {
390 template<push_input AccessorType>
391 template<user_type U>
393 NDRegisterAccessorDecorator<U>::doPostRead(type, updateDataBuffer);
394 if(updateDataBuffer) {
395 _fanIn.processUpdate(this->getId(), UpdateType::POST_READ);
401 template<push_input AccessorType>
402 template<user_type U>
404 assert(_fanIn._hasValidator);
405 _fanIn.processUpdate(this->getId(), UpdateType::REJECT);
410 template<push_input AccessorType>
411 template<user_type U>
413 assert(_fanIn._hasValidator);
414 _fanIn.processUpdate(this->getId(), UpdateType::ACCEPT);
418 template<push_input AccessorType>
419 template<user_type U>
421 _fanIn._hasValidator =
true;
std::string _name
The name of this instance.
Special accessor allows multiple incoming connections to the same logical process variable.
bool hasInput(const TransferElementID &id) const
Check whether the given TransferElementID identifies an internal input.
detail::FanIn::AccessorTypeHelper< AccessorType >::out_type out_type
FanIn(FanIn &&other) noexcept
FanIn(VariableGroup *owner, std::string name, std::string unit, const std::string &description, AggregatorType aggregator, const std::unordered_set< std::string > &tags={})
Construct FanIn.
FanIn(const FanIn &other)=delete
typename AccessorType::value_type value_type
const AbstractorType & input(const TransferElementID &id) const
Return the internal input accessor for the given TransferElementID.
auto inputs()
Return iterable range of all internal input accessors.
FanIn(VariableGroup *owner, std::string name, std::initializer_list< std::string > additionalNames, std::string unit, const std::string &description, AggregatorType aggregator, const std::unordered_set< std::string > &tags={})
Construct FanIn with additional inputs.
std::function< value_type(TransferElementID, const std::map< TransferElementID, AbstractorType > &)> AggregatorType
void replace(FanIn &&other)
FanIn & operator=(const FanIn &other)=delete
detail::FanIn::AccessorTypeHelper< AccessorType >::type AbstractorType
FanIn & operator=(FanIn &&other) noexcept
auto inputs() const
Return iterable range of all internal input accessors.
Adds features required for inversion of control to an accessor.
VariableGroup()=default
Default constructor: Allows late initialisation of VariableGroups (e.g.
Class describing a node of a variable network.
InvalidityTracer application module.