200 void ModuleGroupProxy::informMove(
ModuleGroup& module) {
204 auto currentProps = std::get<VertexProperties::ModuleGroupProperties>(
_d->impl->_graph[
_d->vertex].p);
217 return std::get<VertexProperties::ApplicationModuleProperties>(
_d->impl->_graph[
_d->vertex].p).
name;
223 return _d->impl->
add(
_d->vertex, module);
229 return _d->impl->addVariableNode(*
this, variable, node);
247 return std::get<VertexProperties::ApplicationModuleProperties>(
_d->impl->_graph[
_d->vertex].p).module;
258 auto currentProps = std::get<VertexProperties::ApplicationModuleProperties>(
_d->impl->_graph[
_d->vertex].p);
271 return std::get<VertexProperties::VariableGroupProperties>(
_d->impl->_graph[
_d->vertex].p).
name;
277 return _d->impl->
add(
_d->vertex, module);
283 return _d->impl->addVariableNode(*
this, variable, node);
299 assert(boost::in_degree(currentVertex,
_d->impl->_ownershipView) == 1);
303 boost::source(*boost::in_edges(currentVertex,
_d->impl->_ownershipView).first,
_d->impl->_ownershipView);
317 return std::get<VertexProperties::VariableGroupProperties>(
_d->impl->_graph[
_d->vertex].p).module;
328 auto currentProps = std::get<VertexProperties::VariableGroupProperties>(
_d->impl->_graph[
_d->vertex].p);
341 return std::get<VertexProperties::DeviceModuleProperties>(
_d->impl->_graph[
_d->vertex].p).aliasOrCdd;
347 return std::get<VertexProperties::DeviceModuleProperties>(
_d->impl->_graph[
_d->vertex].p).trigger.lock();
353 return _d->impl->addVariableNode(*
this, variable, node);
358 void DeviceModuleProxy::informMove(
DeviceModule& module) {
362 auto currentProps = std::get<VertexProperties::DeviceModuleProperties>(
_d->impl->_graph[
_d->vertex].p);
366 std::move(currentProps.aliasOrCdd), std::move(currentProps.trigger),
module});
376 return std::get<VertexProperties::ProcessVariableProperties>(
_d->impl->_graph[
_d->vertex].p).name;
382 return std::get<VertexProperties::ProcessVariableProperties>(
_d->impl->_graph[
_d->vertex].p).nodes;
388 return std::get<VertexProperties::ProcessVariableProperties>(
_d->impl->_graph[
_d->vertex].p).tags;
394 auto& tags = std::get<VertexProperties::ProcessVariableProperties>(
_d->impl->_graph[
_d->vertex].p).tags;
405 if(
_d->impl->_graphVisitingLevel != 0) {
406 throw ChimeraTK::logic_error(
"Must not alter the model while iterating/visiting!");
417 auto& nodes = std::get<VertexProperties::ProcessVariableProperties>(
_d->impl->_graph[
_d->vertex].p).nodes;
418 auto it = std::find_if(nodes.begin(), nodes.end(), [&](
auto pn) { return *pn == node; });
419 if(it == nodes.end()) {
425 bool ownershipDeleted{
false};
428 assert(vg !=
nullptr);
431 auto vgm = vg->getModel();
433 for(
const auto& edge :
434 boost::make_iterator_range(boost::edge_range(vgm._d->vertex,
_d->vertex,
_d->impl->_graph))) {
436 boost::remove_edge(edge,
_d->impl->_graph);
437 ownershipDeleted =
true;
445 assert(am !=
nullptr);
446 auto amm = am->getModel();
452 if(!ownershipDeleted) {
453 for(
const auto& edge :
454 boost::make_iterator_range(boost::edge_range(amm._d->vertex,
_d->vertex,
_d->impl->_graph))) {
456 boost::remove_edge(edge,
_d->impl->_graph);
457 ownershipDeleted =
true;
464 assert(ownershipDeleted);
468 bool pvAccessDeleted{
false};
471 for(
const auto& edge :
472 boost::make_iterator_range(boost::edge_range(
_d->vertex, amm._d->vertex,
_d->impl->_graph))) {
474 boost::remove_edge(edge,
_d->impl->_graph);
476 pvAccessDeleted =
true;
484 for(
const auto& edge :
485 boost::make_iterator_range(boost::edge_range(amm._d->vertex,
_d->vertex,
_d->impl->_graph))) {
487 boost::remove_edge(edge,
_d->impl->_graph);
489 pvAccessDeleted =
true;
495 assert(pvAccessDeleted);
500 assert(dm !=
nullptr);
503 auto dmm = dm->getModel();
505 boost::remove_edge(
_d->vertex, dmm._d->vertex,
_d->impl->_graph);
506 boost::remove_edge(dmm._d->vertex,
_d->vertex,
_d->impl->_graph);
512 if(boost::in_degree(
_d->vertex,
_d->impl->_graph) <= 1 && boost::out_degree(
_d->vertex,
_d->impl->_graph) == 0) {
513 assert(boost::in_degree(
_d->vertex,
_d->impl->_graph) == 0 ||
514 _d->impl->_graph[*boost::in_edges(
_d->vertex,
_d->impl->_graph).first].type ==
517 assert(nodes.empty());
519 boost::clear_vertex(
_d->vertex,
_d->impl->_graph);
520 boost::remove_vertex(
_d->vertex,
_d->impl->_graph);
526 catch(std::bad_variant_access&) {
540 return std::get<VertexProperties::DirectoryProperties>(
_d->impl->_graph[
_d->vertex].p).name;
546 return _d->impl->addVariable(
_d->vertex, name);
582 return genericAdd<
VariableGroupProxy, VariableGroup, VertexProperties::VariableGroupProperties,
589 return genericAdd<
DeviceModuleProxy, DeviceModule, VertexProperties::DeviceModuleProperties,
595 template<
typename PROXY,
typename MODULE,
typename PROPS, VertexProperties::Type TYPE>
596 PROXY Impl::genericAdd(
Vertex owner, MODULE& module) {
598 if(_graphVisitingLevel != 0) {
599 throw ChimeraTK::logic_error(
"Must not alter the model while iterating/visiting!");
605 auto* newVertex = boost::add_vertex(_graph);
608 _graph[newVertex].type = TYPE;
609 if constexpr(!std::is_same<MODULE, DeviceModule>::value) {
610 _graph[newVertex].p.emplace<PROPS>(PROPS{
module.getName(), module});
613 auto alias =
module.getDeviceManager().getDeviceAliasOrURI();
614 auto triggerPath =
module.getTriggerPath();
618 if(!triggerPath.empty()) {
623 auto [triggerEdge, triggerSuccess] = boost::add_edge(trigger._d->vertex, newVertex, _graph);
624 assert(triggerSuccess);
628 _graph[newVertex].p.emplace<PROPS>(PROPS{alias, trigger,
module});
632 auto [ownershipEdge, ownershipSuccess] = boost::add_edge(owner, newVertex, _graph);
633 assert(ownershipSuccess);
638 if constexpr(!std::is_same<MODULE, DeviceModule>::value) {
639 directory = addDirectoryRecursive(parentDirectory._d->vertex,
module.getName());
644 directory = parentDirectory;
648 auto [neighbourhoodEdge, neighbourhoodSuccess] = boost::add_edge(newVertex, directory._d->vertex, _graph);
649 assert(neighbourhoodSuccess);
652 return _graph[newVertex].makeProxy<PROXY>(newVertex, shared_from_this());
658 genericRemove(module);
663 void Impl::remove(ApplicationModule& module) {
664 genericRemove(module);
669 void Impl::remove(VariableGroup& module) {
670 genericRemove(module);
675 void Impl::remove(DeviceModule& module) {
676 genericRemove(module);
681 template<
typename MODULE>
682 void Impl::genericRemove(MODULE& module) {
684 if(_graphVisitingLevel != 0) {
685 throw ChimeraTK::logic_error(
"Must not alter the model while iterating/visiting!");
687 auto modelToRemove =
module.getModel();
691 if(!modelToRemove.isValid()) {
696 auto vertexToRemove = modelToRemove._d->vertex;
697 boost::clear_vertex(vertexToRemove, _graph);
698 boost::remove_vertex(vertexToRemove, _graph);
705 template<
typename PROXY>
706 void Impl::addVariableNode(PROXY module,
ProcessVariableProxy& variable, VariableNetworkNode& node) {
708 if(_graphVisitingLevel != 0) {
709 throw ChimeraTK::logic_error(
"Must not alter the model while iterating/visiting!");
711 node.setModel(variable);
714 auto* vertex = variable._d->vertex;
717 auto owningVertex =
module._d->vertex;
720 auto [newOwnershipEdge, success] = boost::add_edge(owningVertex, vertex, _graph);
726 if constexpr(std::is_same<PROXY, ApplicationModuleProxy>::value || std::is_same<PROXY, DeviceModuleProxy>::value) {
727 accessingVertex =
module._d->vertex;
730 static_assert(std::is_same<PROXY, VariableGroupProxy>::value,
"Proxy type cannot have variable nodes.");
731 accessingVertex =
module.getOwningModule()._d->vertex;
735 auto& props = std::get<VertexProperties::ProcessVariableProperties>(_graph[vertex].p);
736 props.nodes.emplace_back(std::make_shared<VariableNetworkNode>(node));
739 const auto& tags = node.getTags();
740 props.tags.insert(tags.begin(), tags.end());
745 std::tie(newEdge, success) = boost::add_edge(accessingVertex, vertex, _graph);
748 std::tie(newEdge, success) = boost::add_edge(vertex, accessingVertex, _graph);
752 _graph[newEdge].pvAccessWithReturnChannel = node.getDirection().withReturn;
759 if(_graphVisitingLevel != 0) {
760 throw ChimeraTK::logic_error(
"Must not alter the model while iterating/visiting!");
763 throw ChimeraTK::logic_error(
"Variable name '" + name +
"' contains illegal characters.");
767 auto existing =
visit(parent, returnProcessVariable, adjacentOutSearch, keepParenthood,
769 if(existing.isValid()) {
774 auto* newVertex = boost::add_vertex(_graph);
778 VertexProperties::ProcessVariableProperties props{name, {}, {}};
779 _graph[newVertex].p.emplace<VertexProperties::ProcessVariableProperties>(props);
782 auto [newEdge, success] = boost::add_edge(parent, newVertex, _graph);
793 if(_graphVisitingLevel != 0) {
794 throw ChimeraTK::logic_error(
"Must not alter the model while iterating/visiting!");
797 throw ChimeraTK::logic_error(
"Variable name '" + name +
"' contains illegal characters.");
801 auto existing =
visit(parent, returnDirectory, adjacentOutSearch, keepParenthood, keepDirectories && keepName(name),
803 if(existing.isValid()) {
808 auto* newVertex = boost::add_vertex(_graph);
812 VertexProperties::DirectoryProperties props{name};
813 _graph[newVertex].p.emplace<VertexProperties::DirectoryProperties>(props);
816 auto [newEdge, success] = boost::add_edge(parent, newVertex, _graph);
820 return _graph[newVertex].makeProxy<
DirectoryProxy>(newVertex, shared_from_this());
827 std::vector<std::string> components;
831 boost::split(components, qualifiedPath, boost::is_any_of(
"/"));
834 auto currentDirectory = _graph[parent].makeProxy<
DirectoryProxy>(parent, shared_from_this());
836 for(
const auto& component : components) {
838 if(component ==
".") {
843 if(component ==
"..") {
844 if(currentDirectory._d->vertex == *boost::vertices(currentDirectory._d->impl->_graph).first) {
845 throw ChimeraTK::logic_error(
"Path component '..' at root directory level found.");
848 assert(currentDirectory.isValid());
854 if(component.empty()) {
860 currentDirectory = currentDirectory.addDirectory(component);
864 return currentDirectory;
869 [[nodiscard]] std::string Impl::getFullyQualifiedPath(
Vertex vertex) {
870 return _graph[vertex].visit([&](
auto props) -> std::string {
873 Vertex currentVertex = vertex;
883 while(currentVertex != *boost::vertices(_graph).first) {
886 auto vis = [&](
auto proxy) {
889 path = proxy.getName() / path;
891 currentVertex = proxy._d->vertex;
896 if constexpr(!useDirectoryHierarchy) {
897 visit(currentVertex, vis, getOwner);
900 visit(currentVertex, vis, getParent);
905 path =
"<disjunct>" / path;
911 auto components = path.getComponents();
913 for(
const auto& component : components) {
914 if(component ==
".") {
917 if(component ==
"..") {
921 if(component ==
"/") {
935 return std::get<VertexProperties::DeviceModuleProperties>(
_d->impl->_graph[
_d->vertex].p).module;