ChimeraTK-ApplicationCore 04.06.00
Loading...
Searching...
No Matches
Model.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 <ChimeraTK/cppext/finally.hpp>
6#include <ChimeraTK/RegisterPath.h>
7
8#include <boost/algorithm/string/predicate.hpp>
9#include <boost/graph/adjacency_list.hpp>
10#include <boost/graph/breadth_first_search.hpp>
11#include <boost/graph/depth_first_search.hpp>
12#include <boost/graph/filtered_graph.hpp>
13#include <boost/graph/graphviz.hpp>
14#include <boost/graph/transpose_graph.hpp>
15
16#include <atomic>
17#include <map>
18#include <memory>
19#include <utility>
20
21namespace ChimeraTK {
22 // Forward declarations
23 class ModuleGroup;
24 class ApplicationModule;
25 class VariableGroup;
26 class VariableNetworkNode;
27 class DeviceModule;
28 class Module;
29
30 template<typename T>
31 class InversionOfControlAccessor;
32
33} // namespace ChimeraTK
34
36
37 /********************************************************************************************************************/
38
39 // Forward declarations
40
41 class RootProxy;
42 class ModuleGroupProxy;
47 class DirectoryProxy;
48 class Impl;
49
50 template<typename ProxyType>
51 class NonOwningProxy;
52
53 namespace detail {
54 // Define how the boost::adjacency_list is supposed to store edges and vertices internally
55 using OutEdgeListType = boost::multisetS;
56 using VertexListType = boost::listS;
57 } // namespace detail
58
59 // Note: This is effectively a forward-declaration. The type must match the type Graph::vertex_descriptor for the
60 // used Graph type which is only known below. It will be re-aliased below so we get an error if the type mismatches.
61 // This trick is necessary to break the otherwise circular dependency of the VertexProperties class using the Vertex
62 // definition, while the VertexProperties class is necessary to define the Graph bringing the vertex_descriptor.
63 // Since the Vertex type will not depend on the VertexProperties, this is not expected to go wrong.
64 using Vertex =
65 boost::adjacency_list<detail::OutEdgeListType, detail::VertexListType, boost::bidirectionalS>::vertex_descriptor;
66
67 /********************************************************************************************************************/
68
72 class Proxy {
73 public:
78 Proxy() = default;
79
157 template<typename VISITOR, typename... Args>
158 auto visit(VISITOR visitor, Args... args) const;
159
170 [[nodiscard]] std::string getFullyQualifiedPath() const;
171
176 [[nodiscard]] bool isValid() const;
177
178 [[nodiscard]] bool operator==(const Proxy& other) const;
179
180 protected:
181 friend class Impl;
182 friend class RootProxy;
183 friend class ModuleGroupProxy;
185 friend class VariableGroupProxy;
186 friend class DeviceModuleProxy;
188 friend class DirectoryProxy;
189 friend struct VertexProperties;
190
191 template<typename ProxyType>
192 friend class NonOwningProxy;
193
195 struct ProxyData;
196
197 // Proxy(Model::Vertex vertex, const std::shared_ptr<Impl>& impl);
198 explicit Proxy(std::shared_ptr<ProxyData> data);
199
200 std::shared_ptr<ProxyData> _d;
201 };
202
203 /********************************************************************************************************************/
204
210 class RootProxy : public Proxy {
211 public:
213 explicit RootProxy(ModuleGroup& app);
214
218
219 DirectoryProxy addDirectory(const std::string& name);
220 ProcessVariableProxy addVariable(const std::string& name);
221 DirectoryProxy addDirectoryRecursive(const std::string& name);
222
223 void remove(ApplicationModule& module);
224 void remove(ModuleGroup& module);
225
238 template<typename VISITOR>
239 bool visitByPath(std::string_view path, VISITOR visitor) const;
240
241 template<typename... Args>
242 void writeGraphViz(const std::string& filename, Args... args) const;
243
247 explicit operator Model::ModuleGroupProxy();
248
252 explicit operator Model::DirectoryProxy();
253
258 static RootProxy makeRootProxy(const std::shared_ptr<Impl>& impl);
259
260 private:
261 using Proxy::Proxy;
262 friend class Proxy;
263 friend class ModuleGroupProxy;
265 friend class VariableGroupProxy;
266 friend class DeviceModuleProxy;
268 friend class DirectoryProxy;
269 friend struct VertexProperties;
270 };
271
272 /********************************************************************************************************************/
273
274 class ModuleGroupProxy : public Proxy {
275 public:
277 [[nodiscard]] const std::string& getName() const;
278
280 [[nodiscard]] ModuleGroup& getModuleGroup() const;
281
285
286 void remove(ApplicationModule& module);
287 void remove(ModuleGroup& module);
288
289 private:
290 using Proxy::Proxy;
291 friend struct VertexProperties;
292
294 void informMove(ModuleGroup& module);
296 };
297
298 /********************************************************************************************************************/
299
301 public:
303 [[nodiscard]] const std::string& getName() const;
304
306 [[nodiscard]] ApplicationModule& getApplicationModule() const;
307
310 void remove(VariableGroup& module);
311
315 explicit operator Model::VariableGroupProxy();
316
317 private:
318 using Proxy::Proxy;
319 friend struct VertexProperties;
320
322 void informMove(ApplicationModule& module);
324 };
325
326 /********************************************************************************************************************/
327
328 class VariableGroupProxy : public Proxy {
329 public:
331 [[nodiscard]] const std::string& getName() const;
332
334 [[nodiscard]] VariableGroup& getVariableGroup() const;
335
337 [[nodiscard]] ApplicationModuleProxy getOwningModule() const;
338
341 void remove(VariableGroup& module);
342
343 private:
344 using Proxy::Proxy;
345 friend struct VertexProperties;
346
348 void informMove(VariableGroup& group);
350 };
351
352 /********************************************************************************************************************/
353
354 class DeviceModuleProxy : public Proxy {
355 public:
357 [[nodiscard]] const std::string& getAliasOrCdd() const;
358
361 [[nodiscard]] ProcessVariableProxy getTrigger() const;
362
364
365 [[nodiscard]] DeviceModule& getDeviceModule() const;
366
367 private:
368 using Proxy::Proxy;
369 friend struct VertexProperties;
370
372 void informMove(DeviceModule& module);
374 };
375
376 /********************************************************************************************************************/
377
379 public:
381 [[nodiscard]] const std::string& getName() const;
382
384 [[nodiscard]] const std::vector<std::shared_ptr<VariableNetworkNode>>& getNodes() const;
385
387 [[nodiscard]] const std::unordered_set<std::string>& getTags() const;
388
402 template<typename VISITOR>
403 bool visitByPath(std::string_view path, VISITOR visitor) const;
404
405 protected:
406 using Proxy::Proxy;
407 friend struct VertexProperties;
408
410 void addTag(const std::string& tag);
411
413 void removeNode(const VariableNetworkNode& node);
414
418 friend class ChimeraTK::Module;
419
420 template<typename T>
422 };
423
424 /********************************************************************************************************************/
425
426 class DirectoryProxy : public Proxy {
427 public:
429 [[nodiscard]] const std::string& getName() const;
430
442 template<typename VISITOR>
443 bool visitByPath(std::string_view path, VISITOR visitor) const;
444
445 ProcessVariableProxy addVariable(const std::string& name);
446 DirectoryProxy addDirectory(const std::string& name);
447 DirectoryProxy addDirectoryRecursive(const std::string& name);
448
449 private:
450 using Proxy::Proxy;
451 friend struct VertexProperties;
452 };
453
454 /********************************************************************************************************************/
455 /********************************************************************************************************************/
456
465 template<typename ProxyType>
467 public:
469 NonOwningProxy() = default;
470
472 // NOLINTNEXTLINE(google-explicit-constructor)
473 NonOwningProxy(const ProxyType& owningProxy)
474 : _vertex(owningProxy.isValid() ? owningProxy._d->vertex : nullptr),
475 _impl(owningProxy.isValid() ? owningProxy._d->impl : nullptr) {}
476
478 NonOwningProxy& operator=(const ProxyType& owningProxy) {
479 if(owningProxy.isValid()) {
480 _vertex = owningProxy._d->vertex;
481 _impl = owningProxy._d->impl;
482 }
483 else {
484 _vertex = nullptr;
485 _impl.reset();
486 }
487 return *this;
488 }
489
492 ProxyType lock() {
493 ProxyType p;
494 p._d = std::make_shared<Proxy::ProxyData>(_vertex, _impl.lock());
495 return p;
496 }
497
498 private:
499 Model::Vertex _vertex{};
500 std::weak_ptr<Impl> _impl;
501 };
502
503 /********************************************************************************************************************/
504 /********************************************************************************************************************/
505
510 enum class Type {
511 invalid,
512 root,
519 };
521
524 ModuleGroup& module;
525 };
527 std::string name;
528 ModuleGroup& module;
529 };
531 std::string name;
532 ApplicationModule& module;
533 };
535 std::string name;
536 VariableGroup& module;
537 };
544 std::string name;
545 std::vector<std::shared_ptr<VariableNetworkNode>> nodes;
546 std::unordered_set<std::string> tags;
547 };
549 std::string name;
550 };
551
552 // The actual properties struct is stored in a std::variant as it depends on the vertex type
556
557 // Call the visitor and pass the Properties struct matching the current vertex type. The return value of the
558 // visitor will be passed through.
559 template<typename VISITOR>
560 [[nodiscard]] typename std::invoke_result<VISITOR, ApplicationModuleProperties&>::type visit(VISITOR visitor) const;
561
562 // Call the visitor and pass a Proxy matching the current vertex type.The return value of the visitor
563 // will be passed through.
564 template<typename VISITOR>
565 typename std::invoke_result<VISITOR, ApplicationModuleProxy>::type visitProxy(
566 VISITOR visitor, Vertex vertex, const std::shared_ptr<Impl>& impl) const;
567
568 VertexProperties() = default;
569 VertexProperties(const VertexProperties& other) = default;
571 // in-place destroy and construct copy, since std::variant does not have a copy assignment operator.
572 this->~VertexProperties();
573 new(this) VertexProperties(other);
574 return *this;
575 }
576
577 // Make proxy object for the given vertex or return existing proxy from weak pointer.
578 // Note: No checks are made that the given vertex is the right one. Also it is not checked whether the proxy type
579 // is correct, which is used in cases where the vertex can have multiple roles (e.g. root vertex can be RootProxy,
580 // ModuleGroupProxy and DirectoryProxy).
581 template<typename PROXY>
582 PROXY makeProxy(Vertex vertex, const std::shared_ptr<Impl>& impl) const;
583
584 private:
585 // (Weak) pointer to Proxy, stored here (with the vertex) to make sure we use the same Proxy instance whenever
586 // we refer to this vertex. Since the VertexProperties are stored inside the Graph and the Proxy contains a
587 // shared pointer to the Graph, the pointer has to be weak to avoid a shared pointer loop.
588 // This pointer is basically used as a cache for visitProxy() resp. makeProxy(), which needs to be a const
589 // function. Hence this member variable must be made mutable.
590 mutable std::weak_ptr<Proxy::ProxyData> _proxy;
591 };
592
593 /********************************************************************************************************************/
594
599 enum class Type {
600 invalid,
601 pvAccess,
602 ownership,
603 parenthood,
605 trigger
606 };
608
611 };
612
613 /********************************************************************************************************************/
618 /********************************************************************************************************************/
619
620 template<typename PROPERTY_OR_PROXY>
621 constexpr bool isRoot(const PROPERTY_OR_PROXY&) {
622 return std::is_same<PROPERTY_OR_PROXY, VertexProperties::RootProperties>::value ||
623 std::is_same<PROPERTY_OR_PROXY, RootProxy>::value;
624 }
625
626 /********************************************************************************************************************/
627
628 template<typename PROPERTY_OR_PROXY>
629 constexpr bool isModuleGroup(const PROPERTY_OR_PROXY&) {
630 return std::is_same<PROPERTY_OR_PROXY, VertexProperties::ModuleGroupProperties>::value ||
631 std::is_same<PROPERTY_OR_PROXY, ModuleGroupProxy>::value;
632 }
633
634 /********************************************************************************************************************/
635
636 template<typename PROPERTY_OR_PROXY>
637 constexpr bool isApplicationModule(const PROPERTY_OR_PROXY&) {
638 return std::is_same<PROPERTY_OR_PROXY, VertexProperties::ApplicationModuleProperties>::value ||
639 std::is_same<PROPERTY_OR_PROXY, ApplicationModuleProxy>::value;
640 }
641
642 /********************************************************************************************************************/
643
644 template<typename PROPERTY_OR_PROXY>
645 constexpr bool isVariableGroup(const PROPERTY_OR_PROXY&) {
646 return std::is_same<PROPERTY_OR_PROXY, VertexProperties::VariableGroupProperties>::value ||
647 std::is_same<PROPERTY_OR_PROXY, VariableGroupProxy>::value;
648 }
649
650 /********************************************************************************************************************/
651
652 template<typename PROPERTY_OR_PROXY>
653 constexpr bool isDeviceModule(const PROPERTY_OR_PROXY&) {
654 return std::is_same<PROPERTY_OR_PROXY, VertexProperties::DeviceModuleProperties>::value ||
655 std::is_same<PROPERTY_OR_PROXY, DeviceModuleProxy>::value;
656 }
657
658 /********************************************************************************************************************/
659
660 template<typename PROPERTY_OR_PROXY>
661 constexpr bool isVariable(const PROPERTY_OR_PROXY&) {
662 return std::is_same<PROPERTY_OR_PROXY, VertexProperties::ProcessVariableProperties>::value ||
663 std::is_same<PROPERTY_OR_PROXY, ProcessVariableProxy>::value;
664 }
665
666 /********************************************************************************************************************/
667
668 template<typename PROPERTY_OR_PROXY>
669 constexpr bool isDirectory(const PROPERTY_OR_PROXY&) {
670 return std::is_same<PROPERTY_OR_PROXY, VertexProperties::DirectoryProperties>::value ||
671 std::is_same<PROPERTY_OR_PROXY, DirectoryProxy>::value;
672 }
673
674 /********************************************************************************************************************/
675
676 template<typename PROPERTY_OR_PROXY>
677 constexpr bool hasName(const PROPERTY_OR_PROXY&) {
678 return std::is_same<PROPERTY_OR_PROXY, VertexProperties::ModuleGroupProperties>::value ||
679 std::is_same<PROPERTY_OR_PROXY, ModuleGroupProxy>::value ||
680 std::is_same<PROPERTY_OR_PROXY, VertexProperties::ApplicationModuleProperties>::value ||
681 std::is_same<PROPERTY_OR_PROXY, ApplicationModuleProxy>::value ||
682 std::is_same<PROPERTY_OR_PROXY, VertexProperties::VariableGroupProperties>::value ||
683 std::is_same<PROPERTY_OR_PROXY, VariableGroupProxy>::value ||
684 std::is_same<PROPERTY_OR_PROXY, VertexProperties::ProcessVariableProperties>::value ||
685 std::is_same<PROPERTY_OR_PROXY, ProcessVariableProxy>::value ||
686 std::is_same<PROPERTY_OR_PROXY, VertexProperties::DirectoryProperties>::value ||
687 std::is_same<PROPERTY_OR_PROXY, DirectoryProxy>::value;
688 }
689
690 /********************************************************************************************************************/
691
695 using Graph = boost::adjacency_list<detail::OutEdgeListType, detail::VertexListType, boost::bidirectionalS,
697
698 using Vertex = Graph::vertex_descriptor;
699
700 using Edge = Graph::edge_descriptor;
701
702 using EdgeFilteredView = boost::filtered_graph<Graph, std::function<bool(const Edge&)>, boost::keep_all>;
703
704 /********************************************************************************************************************/
705
707 struct SearchType {};
713
715 static constexpr AdjacentSearch adjacentSearch;
716
719 static constexpr AdjacentInSearch adjacentInSearch;
720
723 static constexpr AdjacentOutSearch adjacentOutSearch;
724
726 static constexpr DepthFirstSearch depthFirstSearch;
727
729 static constexpr BreadthFirstSearch breadthFirstSearch;
730
731 /********************************************************************************************************************/
732
733 namespace detail {
737 template<typename T>
738 struct ValueHolder {
740 T get() { return value; }
741 using type = T;
742 };
743
744 template<>
745 struct ValueHolder<void> {
746 void get() {}
747 using type = void;
748 };
749 } // namespace detail
750
751 /********************************************************************************************************************/
752
754 struct SearchOption {};
755
757
759
761 enum class VisitOrderType { in, post };
762 constexpr VisitOrder() = default;
763 constexpr explicit VisitOrder(VisitOrderType t) : SearchOption(), type(t) {}
764
766 };
767
768 template<typename T>
772
777 static constexpr ContinueSearchDisjunctTrees continueSearchDisjunctTrees;
778
781 template<typename T>
782 static constexpr ReturnFirstHitWithValue<T> returnFirstHit(T notFoundValue) {
784 rv.notFoundValue.value = notFoundValue;
785 return rv;
786 }
787
792 return rv;
793 }
794
795 // Calls the visitor before walking along its edges. Default visiting order.
796 static constexpr VisitOrder visitOrderIn{VisitOrder::VisitOrderType::in};
797
798 // Calls the visitor after all edges have been visited. Use together with DFS or BFS to modify the visiting order.
799 static constexpr VisitOrder visitOrderPost{VisitOrder::VisitOrderType::post};
800
801 /********************************************************************************************************************/
802
803 template<typename PROPERTIES>
805 using PropertiesType = PROPERTIES;
806 };
807
808 /********************************************************************************************************************/
809
810 // Forward declaration
811 template<typename FILTER_LHS, typename FILTER_RHS>
812 struct AndSet;
813
814 /********************************************************************************************************************/
815
816 template<typename FILTER_LHS, typename FILTER_RHS>
817 struct OrSet : FILTER_LHS, FILTER_RHS {
818 explicit constexpr OrSet(FILTER_LHS lhs, FILTER_RHS rhs) : FILTER_LHS(lhs), FILTER_RHS(rhs) {}
819
820 [[nodiscard]] bool evalVertexFilter(const typename FILTER_LHS::PropertiesType& e) const {
821 return FILTER_LHS::evalVertexFilter(e) || FILTER_RHS::evalVertexFilter(e);
822 };
823
824 [[nodiscard]] bool evalEdgeFilter(const typename FILTER_LHS::PropertiesType& e) const {
825 return FILTER_LHS::evalEdgeFilter(e) || FILTER_RHS::evalEdgeFilter(e);
826 };
827
828 template<typename FILTER_NEXT_RHS>
829 constexpr auto operator||(const FILTER_NEXT_RHS& rhs) const {
830 return OrSet<OrSet<FILTER_LHS, FILTER_RHS>, FILTER_NEXT_RHS>(*this, rhs);
831 }
832
833 template<typename FILTER_NEXT_RHS>
834 constexpr auto operator&&(const FILTER_NEXT_RHS& rhs) const {
835 return AndSet<OrSet<FILTER_LHS, FILTER_RHS>, FILTER_NEXT_RHS>(*this, rhs);
836 }
837
838 template<typename PROXY>
839 [[nodiscard]] constexpr bool constevalObjecttype() const {
840 return FILTER_LHS::template constevalObjecttype<PROXY>() || FILTER_RHS::template constevalObjecttype<PROXY>();
841 }
842 };
843
844 /********************************************************************************************************************/
845
846 template<typename FILTER_LHS, typename FILTER_RHS>
847 struct AndSet : FILTER_LHS, FILTER_RHS {
848 explicit constexpr AndSet(FILTER_LHS lhs, FILTER_RHS rhs) : FILTER_LHS(lhs), FILTER_RHS(rhs) {}
849
850 [[nodiscard]] bool evalVertexFilter(const typename FILTER_LHS::PropertiesType& e) const {
851 return FILTER_LHS::evalVertexFilter(e) && FILTER_RHS::evalVertexFilter(e);
852 };
853
854 [[nodiscard]] bool evalEdgeFilter(const typename FILTER_LHS::PropertiesType& e) const {
855 return FILTER_LHS::evalEdgeFilter(e) && FILTER_RHS::evalEdgeFilter(e);
856 };
857
858 template<typename FILTER_NEXT_RHS>
859 constexpr auto operator||(const FILTER_NEXT_RHS& rhs) const {
860 return OrSet<AndSet<FILTER_LHS, FILTER_RHS>, FILTER_NEXT_RHS>(*this, rhs);
861 }
862
863 template<typename FILTER_NEXT_RHS>
864 constexpr auto operator&&(const FILTER_NEXT_RHS& rhs) const {
865 return AndSet<AndSet<FILTER_LHS, FILTER_RHS>, FILTER_NEXT_RHS>(*this, rhs);
866 }
867
868 template<typename PROXY>
869 [[nodiscard]] constexpr bool constevalObjecttype() const {
870 return FILTER_LHS::template constevalObjecttype<PROXY>() && FILTER_RHS::template constevalObjecttype<PROXY>();
871 }
872 };
873
874 /********************************************************************************************************************/
875
876 template<typename FILTER>
877 struct EdgeFilter : PropertyFilterTag<EdgeProperties> {
878 explicit constexpr EdgeFilter(FILTER filter) : _filter(filter) {}
879 constexpr EdgeFilter(const EdgeFilter<FILTER>& rhs) noexcept = default;
880 constexpr EdgeFilter(EdgeFilter<FILTER>&& rhs) noexcept = default;
881
882 template<typename FILTER_RHS>
883 constexpr auto operator||(const FILTER_RHS& rhs) const {
884 static_assert(std::is_base_of<PropertyFilterTag<EdgeProperties>, FILTER_RHS>::value,
885 "Logical OR operator || cannot be used on different filter types.");
886 return OrSet(*this, rhs);
887 }
888
889 template<typename FILTER_RHS>
890 constexpr auto operator&&(const FILTER_RHS& rhs) const {
891 static_assert(std::is_base_of<PropertyFilterTag<EdgeProperties>, FILTER_RHS>::value,
892 "Logical AND operator && cannot be used on different filter types.");
893 return AndSet(*this, rhs);
894 }
895
896 [[nodiscard]] bool evalEdgeFilter(const EdgeProperties& e) const { return _filter(e); };
897
898 private:
899 template<typename FILTER_RHS>
900 friend struct EdgeFilter;
901
902 FILTER _filter;
903 };
904
905 /********************************************************************************************************************/
906
907 template<typename FILTER>
908 struct VertexFilter : PropertyFilterTag<VertexProperties> {
909 explicit constexpr VertexFilter(FILTER filter) : _filter(std::move(filter)) {}
910 constexpr VertexFilter(const VertexFilter<FILTER>& rhs) = default;
911 constexpr VertexFilter(VertexFilter<FILTER>&& rhs) noexcept = default;
912
913 template<typename FILTER_RHS>
914 constexpr auto operator||(const FILTER_RHS& rhs) const {
915 static_assert(std::is_base_of<PropertyFilterTag<VertexProperties>, FILTER_RHS>::value,
916 "Logical OR operator || cannot be used on different filter types.");
917 return OrSet(*this, rhs);
918 }
919
920 template<typename FILTER_RHS>
921 constexpr auto operator&&(const FILTER_RHS& rhs) const {
922 static_assert(std::is_base_of<PropertyFilterTag<VertexProperties>, FILTER_RHS>::value,
923 "Logical AND operator && cannot be used on different filter types.");
924 return AndSet(*this, rhs);
925 }
926
927 [[nodiscard]] bool evalVertexFilter(const VertexProperties& e) const { return _filter(e); };
928
929 // Filter on object type in constexpr condition. Will be overridden by ObjecttypeFilter.
930 template<typename PROXY>
931 [[nodiscard]] constexpr bool constevalObjecttype() const {
932 return true;
933 }
934
935 private:
936 template<typename FILTER_RHS>
937 friend struct VertexFilter;
938
939 FILTER _filter;
940 };
941
942 /********************************************************************************************************************/
943
944 [[maybe_unused]] static auto keepAll = [](const auto&) -> bool { return true; };
945 [[maybe_unused]] static auto keepAllEdges = EdgeFilter(keepAll);
946 [[maybe_unused]] static auto keepAllVertices = VertexFilter(keepAll);
947
948 /********************************************************************************************************************/
949 /********************************************************************************************************************/
950
951 template<EdgeProperties::Type RELATIONSHIP>
952 [[maybe_unused]] static constexpr auto relationshipFilter =
953 EdgeFilter([](const EdgeProperties& e) -> bool { return e.type == RELATIONSHIP; });
954
955 /********************************************************************************************************************/
956
957 static constexpr auto keepPvAccess = relationshipFilter<EdgeProperties::Type::pvAccess>;
958 static constexpr auto keepPvAccesWithReturnChannel = Model::EdgeFilter([](const Model::EdgeProperties& edge) -> bool {
959 return edge.type == Model::EdgeProperties::Type::pvAccess && edge.pvAccessWithReturnChannel;
960 });
961 static constexpr auto keepOwnership = relationshipFilter<EdgeProperties::Type::ownership>;
962 static constexpr auto keepParenthood = relationshipFilter<EdgeProperties::Type::parenthood>;
963 static constexpr auto keepNeighbourhood = relationshipFilter<EdgeProperties::Type::neighbourhood>;
964
965 /********************************************************************************************************************/
966 /********************************************************************************************************************/
967
968 namespace detail {
969 template<VertexProperties::Type OBJECTTYPE>
970 [[maybe_unused]] static constexpr auto objecttypeFilterFunctor =
971 [](const VertexProperties& e) -> bool { return e.type == OBJECTTYPE; };
972 } // namespace detail
973
974 /********************************************************************************************************************/
975
976 // FIXME: This _should_ be fine since it is not possible to use those templates
977 // in different compilation units. This is the recommended work-around from the GCC manpage
978 // GCC will complain about base class using internal linkage because of the base class depending
979 // on the type of lambdas which get a different symbol for every compilation unit they are used in
980 // NOLINTNEXTLINE(google-build-namespaces)
981 namespace {
982 template<VertexProperties::Type OBJECTTYPE, typename PROXYTYPE>
983 struct ObjecttypeFilter : VertexFilter<decltype(detail::objecttypeFilterFunctor<OBJECTTYPE>)> {
984 constexpr ObjecttypeFilter()
985 : VertexFilter<decltype(detail::objecttypeFilterFunctor<OBJECTTYPE>)>(
986 detail::objecttypeFilterFunctor<OBJECTTYPE>) {}
987
988 template<typename FILTER_RHS>
989 constexpr auto operator||(const FILTER_RHS& rhs) const {
990 static_assert(std::is_base_of<PropertyFilterTag<VertexProperties>, FILTER_RHS>::value,
991 "Logical OR operator || cannot be used on different filter types.");
992 return OrSet(*this, rhs);
993 }
994
995 template<typename FILTER_RHS>
996 constexpr auto operator&&(const FILTER_RHS& rhs) const {
997 static_assert(std::is_base_of<PropertyFilterTag<VertexProperties>, FILTER_RHS>::value,
998 "Logical AND operator && cannot be used on different filter types.");
999 return AndSet(*this, rhs);
1000 }
1001
1002 template<typename PROXY>
1003 [[nodiscard]] constexpr bool constevalObjecttype() const {
1004 return std::is_same<PROXY, PROXYTYPE>::value;
1005 }
1006 };
1007
1008 /******************************************************************************************************************/
1009 } // namespace
1010
1011 /********************************************************************************************************************/
1012 constexpr static auto keepModuleGroups = ObjecttypeFilter<VertexProperties::Type::moduleGroup, ModuleGroupProxy>();
1013 constexpr static auto keepApplicationModules =
1014 ObjecttypeFilter<VertexProperties::Type::applicationModule, ApplicationModuleProxy>();
1015 constexpr static auto keepVariableGroups =
1016 ObjecttypeFilter<VertexProperties::Type::variableGroup, VariableGroupProxy>();
1017 constexpr static auto keepDeviceModules = ObjecttypeFilter<VertexProperties::Type::deviceModule, DeviceModuleProxy>();
1018 constexpr static auto keepProcessVariables =
1019 ObjecttypeFilter<VertexProperties::Type::processVariable, ProcessVariableProxy>();
1020 constexpr static auto keepDirectories = ObjecttypeFilter<VertexProperties::Type::directory, DirectoryProxy>();
1021
1022 namespace detail {
1026 template<typename VERTEX_FILTER>
1027 constexpr auto findVertexFilterAcceptedProxyType(VERTEX_FILTER vertexFilter) {
1028 if constexpr(vertexFilter.template constevalObjecttype<ModuleGroupProxy>()) {
1029 return ModuleGroupProxy();
1030 }
1031 else if constexpr(vertexFilter.template constevalObjecttype<ApplicationModuleProxy>()) {
1032 return ApplicationModuleProxy();
1033 }
1034 else if constexpr(vertexFilter.template constevalObjecttype<VariableGroupProxy>()) {
1035 return VariableGroupProxy();
1036 }
1037 else if constexpr(vertexFilter.template constevalObjecttype<DeviceModuleProxy>()) {
1038 return DeviceModuleProxy();
1039 }
1040 else if constexpr(vertexFilter.template constevalObjecttype<ProcessVariableProxy>()) {
1041 return ProcessVariableProxy();
1042 }
1043 else if constexpr(vertexFilter.template constevalObjecttype<DirectoryProxy>()) {
1044 return DirectoryProxy();
1045 }
1046 else {
1047 return RootProxy();
1048 }
1049 }
1050
1055 template<typename VISITOR, typename VERTEX_FILTER>
1056 using VisitorReturnType = typename std::invoke_result<VISITOR,
1057 typename std::invoke_result<decltype(detail::findVertexFilterAcceptedProxyType<VERTEX_FILTER>),
1058 VERTEX_FILTER>::type>::type;
1059
1060 } // namespace detail
1061
1062 /********************************************************************************************************************/
1063 /********************************************************************************************************************/
1064
1065 [[maybe_unused]] static auto keepName(const std::string& name) {
1066 return VertexFilter([name](const VertexProperties& e) -> bool {
1067 return e.visit([name](auto props) -> bool {
1068 if constexpr(hasName(props)) {
1069 return props.name == name;
1070 }
1071 else {
1072 return false;
1073 }
1074 });
1075 });
1076 }
1077
1078 /********************************************************************************************************************/
1079
1080 [[maybe_unused]] static auto keepTag(std::string name) {
1081 return VertexFilter([name](const VertexProperties& e) -> bool {
1082 return e.visit([name](auto props) -> bool {
1083 if constexpr(isVariable(props)) {
1084 return props.tags.count(name);
1085 }
1086 else {
1087 return false;
1088 }
1089 });
1090 });
1091 }
1092
1093 /********************************************************************************************************************/
1094 /********************************************************************************************************************/
1095
1096 template<typename A, typename B>
1097 struct CombinedSearchConfig : A, B {
1098 constexpr CombinedSearchConfig(A a, B b) : A(a), B(b) {}
1099 };
1100
1101 /********************************************************************************************************************/
1102
1103 template<typename FIRST, typename... MORE>
1104 constexpr auto combinedSearchConfig(FIRST first, MORE... more) {
1105 if constexpr(sizeof...(more) > 0) {
1106 return CombinedSearchConfig(first, combinedSearchConfig(more...));
1107 }
1108 else {
1109 return first;
1110 }
1111 }
1112
1113 /********************************************************************************************************************/
1114
1115 static constexpr auto ownedModuleGroups = combinedSearchConfig(
1116 ChimeraTK::Model::adjacentOutSearch, ChimeraTK::Model::keepOwnership, ChimeraTK::Model::keepModuleGroups);
1117
1118 static constexpr auto ownedApplicationModules = combinedSearchConfig(
1119 ChimeraTK::Model::adjacentOutSearch, ChimeraTK::Model::keepOwnership, ChimeraTK::Model::keepApplicationModules);
1120
1121 static constexpr auto ownedVariableGroups = combinedSearchConfig(
1122 ChimeraTK::Model::adjacentOutSearch, ChimeraTK::Model::keepOwnership, ChimeraTK::Model::keepVariableGroups);
1123
1124 static constexpr auto ownedVariables = combinedSearchConfig(
1125 ChimeraTK::Model::adjacentOutSearch, ChimeraTK::Model::keepOwnership, ChimeraTK::Model::keepProcessVariables);
1126
1127 static constexpr auto childDirectories = combinedSearchConfig(
1128 ChimeraTK::Model::adjacentOutSearch, ChimeraTK::Model::keepParenthood, ChimeraTK::Model::keepDirectories);
1129
1130 static constexpr auto childVariables = combinedSearchConfig(
1131 ChimeraTK::Model::adjacentOutSearch, ChimeraTK::Model::keepParenthood, ChimeraTK::Model::keepProcessVariables);
1132
1133 static constexpr auto children =
1134 combinedSearchConfig(ChimeraTK::Model::adjacentOutSearch, ChimeraTK::Model::keepParenthood);
1135
1136 static constexpr auto getOwner =
1137 combinedSearchConfig(ChimeraTK::Model::adjacentInSearch, ChimeraTK::Model::keepOwnership);
1138
1139 static constexpr auto getParent =
1140 combinedSearchConfig(ChimeraTK::Model::adjacentInSearch, ChimeraTK::Model::keepParenthood);
1141
1142 static constexpr auto getNeighbourDirectory =
1143 combinedSearchConfig(ChimeraTK::Model::adjacentOutSearch, ChimeraTK::Model::keepNeighbourhood);
1144
1145 static constexpr auto neighbourModules =
1146 combinedSearchConfig(ChimeraTK::Model::adjacentInSearch, ChimeraTK::Model::keepNeighbourhood);
1147
1148 /********************************************************************************************************************/
1149 /********************************************************************************************************************/
1150
1157 static constexpr auto returnModuleGroup = [](auto am) -> ModuleGroupProxy {
1158 if constexpr(isModuleGroup(am)) {
1159 return am;
1160 }
1161 else {
1162 throw ChimeraTK::logic_error("Model: ModuleGroupProxy expected, something else found.");
1163 }
1164 };
1165
1166 /********************************************************************************************************************/
1167
1174 static constexpr auto returnApplicationModule = [](auto am) -> ApplicationModuleProxy {
1175 if constexpr(isApplicationModule(am)) {
1176 return am;
1177 }
1178 else {
1179 throw ChimeraTK::logic_error("Model: ApplicationModuleProxy expected, something else found.");
1180 }
1181 };
1182
1183 /********************************************************************************************************************/
1184
1191 static constexpr auto returnVariableGroup = [](auto am) -> VariableGroupProxy {
1192 if constexpr(isVariableGroup(am)) {
1193 return am;
1194 }
1195 else {
1196 throw ChimeraTK::logic_error("Model: VariableGroupProxy expected, something else found.");
1197 }
1198 };
1199
1200 /********************************************************************************************************************/
1201
1208 static constexpr auto returnProcessVariable = [](auto am) -> ProcessVariableProxy {
1209 if constexpr(isVariable(am)) {
1210 return am;
1211 }
1212 else {
1213 throw ChimeraTK::logic_error("Model: ProcessVariableProxy expected, something else found.");
1214 }
1215 };
1216
1217 /********************************************************************************************************************/
1218
1225 static constexpr auto returnDirectory = [](auto dir) -> DirectoryProxy {
1226 if constexpr(isDirectory(dir) || isRoot(dir)) {
1227 return DirectoryProxy(dir);
1228 }
1229 else {
1230 throw ChimeraTK::logic_error("Model: DirectoryProxy expected, something else found.");
1231 }
1232 };
1233
1234 /********************************************************************************************************************/
1235 /********************************************************************************************************************/
1236
1237 template<typename FIRST, typename... ARGS>
1238 constexpr auto getEdgeFilter([[maybe_unused]] FIRST first, ARGS... args) {
1239 if constexpr(std::is_base_of<PropertyFilterTag<EdgeProperties>, FIRST>::value) {
1240 return first;
1241 }
1242 else if constexpr(sizeof...(args) == 0) {
1243 return keepAllEdges;
1244 }
1245 else {
1246 return getEdgeFilter(args...);
1247 }
1248 }
1249
1250 constexpr auto getEdgeFilter() {
1251 return keepAllEdges;
1252 }
1253
1254 /********************************************************************************************************************/
1255
1256 template<typename FIRST, typename... ARGS>
1257 constexpr auto getVertexFilter([[maybe_unused]] FIRST first, ARGS... args) {
1258 if constexpr(std::is_base_of<PropertyFilterTag<VertexProperties>, FIRST>::value) {
1259 return first;
1260 }
1261 else if constexpr(sizeof...(args) == 0) {
1262 return keepAllVertices;
1263 }
1264 else {
1265 return getVertexFilter(args...);
1266 }
1267 }
1268
1269 constexpr auto getVertexFilter() {
1270 return keepAllVertices;
1271 }
1272
1273 /********************************************************************************************************************/
1274
1275 template<typename SEARCH_TYPE>
1277 using type = SEARCH_TYPE;
1278 };
1279
1280 template<typename FIRST, typename... ARGS>
1281 constexpr auto getSearchType() {
1282 if constexpr(std::is_base_of<SearchType, FIRST>::value) {
1283 return SearchTypeHolder<FIRST>();
1284 }
1285 else if constexpr(sizeof...(ARGS) == 0) {
1286 return adjacentOutSearch;
1287 }
1288 else {
1289 return getSearchType<ARGS...>();
1290 }
1291 }
1292
1293 constexpr auto getSearchType() {
1294 return adjacentOutSearch;
1295 }
1296
1297 /********************************************************************************************************************/
1298
1299 template<typename SEARCH_OPTION_TO_FIND, typename FIRST, typename... ARGS>
1300 constexpr bool hasSearchOption() {
1301 if constexpr(std::is_base_of<SEARCH_OPTION_TO_FIND, FIRST>::value) {
1302 return true;
1303 }
1304 else if constexpr(sizeof...(ARGS) == 0) {
1305 return false;
1306 }
1307 else {
1308 return hasSearchOption<SEARCH_OPTION_TO_FIND, ARGS...>();
1309 }
1310 }
1311
1312 template<typename SEARCH_OPTION_TO_FIND>
1313 constexpr bool hasSearchOption() {
1314 return false;
1315 }
1316
1317 /********************************************************************************************************************/
1318
1319 template<typename SEARCH_OPTION_TO_FIND, typename FIRST, typename... ARGS>
1320 constexpr auto getSearchOption([[maybe_unused]] FIRST first, ARGS... args) {
1321 if constexpr(std::is_base_of<SEARCH_OPTION_TO_FIND, FIRST>::value) {
1322 return first;
1323 }
1324 else if constexpr(sizeof...(ARGS) == 0) {
1325 throw ChimeraTK::logic_error("Model::getSearchOption() called but search option not found!");
1326 }
1327 else {
1328 return getSearchOption<SEARCH_OPTION_TO_FIND, ARGS...>(args...);
1329 }
1330 }
1331
1332 template<typename SEARCH_OPTION_TO_FIND>
1333 constexpr auto getSearchOption() {
1334 throw ChimeraTK::logic_error("Model::getSearchOption() called but search option not found!");
1335 }
1336
1337 /********************************************************************************************************************/
1338
1339 template<typename FIRST, typename... ARGS>
1340 constexpr void checkConfigValidity(FIRST, ARGS... args) {
1341 static_assert(std::is_base_of<PropertyFilterTag<EdgeProperties>, FIRST>::value ||
1342 std::is_base_of<PropertyFilterTag<VertexProperties>, FIRST>::value ||
1343 std::is_base_of<SearchType, FIRST>::value || std::is_base_of<SearchOption, FIRST>::value,
1344 "Wrong type passed in search configuration argument list. Must be ether an EdgeFilter, a VertexFilter, a "
1345 "SearchType or a SearchOption.");
1346 if constexpr(sizeof...(args) > 0) {
1347 checkConfigValidity(args...);
1348 }
1349 }
1350
1351 constexpr void checkConfigValidity() {}
1352
1353 /********************************************************************************************************************/
1354 /********************************************************************************************************************/
1355
1360 class Impl : public std::enable_shared_from_this<Impl> {
1361 friend class Proxy;
1362 friend class RootProxy;
1363 friend class ModuleGroupProxy;
1366 friend class DeviceModuleProxy;
1368 friend class DirectoryProxy;
1369
1370 private:
1371 // convenience functions just redirecting to generic_add.
1372 ModuleGroupProxy add(Model::Vertex owner, ModuleGroup& module);
1375 DeviceModuleProxy add(Model::Vertex owner, DeviceModule& module);
1376
1377 // common implementation to add any object (ModuleGroup, ApplicationModule, VariableGroup or DeviceModule)
1378 template<typename PROXY, typename MODULE, typename PROPS, Model::VertexProperties::Type TYPE>
1379 PROXY genericAdd(Model::Vertex owner, MODULE& module);
1380
1381 // convenience functions just redirecting to generic_remove.
1382 void remove(ModuleGroup& module);
1383 void remove(ApplicationModule& module);
1384 void remove(VariableGroup& module);
1385 void remove(DeviceModule& module);
1386
1387 // Common implementation to remove any object (ModuleGroup, ApplicationModule, VariableGroup or DeviceModule).
1388 // Do not use for ProcessVariables, remove the node from the ProcessVariable instead.
1389 template<typename MODULE>
1390 void genericRemove(MODULE& module);
1391
1392 // Add variable to parent directory if not yet existing. The corresponding proxy is returned even if the variable
1393 // existed before.
1394 ProcessVariableProxy addVariable(Model::Vertex parent, const std::string& name);
1395
1396 // Add directory to parent directory if not yet existing. The corresponding proxy is returned even if the directory
1397 // existed before.
1398 DirectoryProxy addDirectory(Model::Vertex parent, const std::string& name);
1399
1400 // Add directory tree identified by qualifiedPath and return the lowest-level directory. Any components which
1401 // currently do not exists will be created. The function will not fail even if the entire path already exists,
1402 // it will in that case simply return the existing directory.
1403 DirectoryProxy addDirectoryRecursive(Model::Vertex parent, const std::string& qualifiedPath);
1404
1405 // module can be either a ApplicationModuleProxy or a VariableGroupProxy. In case of a VariableGroupProxy, the
1406 // pvAccess-typed edge will connect to the ApplicationModule owning the VariableGroup.
1407 template<typename PROXY>
1408 void addVariableNode(PROXY module, ProcessVariableProxy& variable, VariableNetworkNode& node);
1409
1410 template<typename... Args>
1411 constexpr auto getFilteredGraph(Args... config) const;
1412
1413 template<typename VISITOR, typename... Args>
1414 auto visit(Vertex startVertex, VISITOR visitor, Args... args);
1415
1416 [[nodiscard]] std::string getFullyQualifiedPath(Vertex vertex);
1417
1418 template<typename VISITOR, typename PROXY>
1419 bool visitByPath(std::string_view path, VISITOR visitor, PROXY startProxy);
1420
1421 Model::Graph _graph;
1422
1423 // Counter for bookkeeping whether we are currently visiting (i.e. iterating) the _graph or whether modifying
1424 // the _graph is allowed.
1425 std::atomic<size_t> _graphVisitingLevel{0};
1426
1427 Model::EdgeFilteredView _ownershipView{_graph,
1428 [&](const Model::Edge& edge) -> bool { return _graph[edge].type == Model::EdgeProperties::Type::ownership; },
1429 boost::keep_all()};
1430 };
1431
1432 /********************************************************************************************************************/
1433
1439 std::shared_ptr<Impl> impl;
1440 ProxyData() = default;
1441 ProxyData(Model::Vertex v, std::shared_ptr<Impl> i) : vertex(v), impl(std::move(i)) {}
1442 };
1443
1444 /********************************************************************************************************************/
1445 /********************************************************************************************************************/
1447 /********************************************************************************************************************/
1448 /********************************************************************************************************************/
1449
1450 template<typename VISITOR, typename... Args>
1451 auto Proxy::visit(VISITOR visitor, Args... args) const {
1452 return _d->impl->visit(_d->vertex, visitor, args...);
1453 }
1454
1455 /********************************************************************************************************************/
1456 /********************************************************************************************************************/
1458 /********************************************************************************************************************/
1459 /********************************************************************************************************************/
1460
1461 template<typename... Args>
1462 constexpr auto Impl::getFilteredGraph(Args... config) const {
1463 Model::checkConfigValidity(config...);
1464
1465 auto edgeFilter = Model::getEdgeFilter(config...);
1466
1467 // We cannot pass (non-default constructible) lambdas to the filtered_graph directly, since at least the
1468 // depth_first_search tried to default-construct their types at some point. Also the lifetime of the lambdas needs
1469 // to go beyond the scope of this function, hence we must not capture by reference!
1470 [[maybe_unused]] std::function edgeFilterFunctor = [this, edgeFilter](const Model::Edge& e) -> bool {
1471 Model::EdgeProperties props = _graph[e];
1472 return edgeFilter.evalEdgeFilter(props);
1473 };
1474
1475 // Performance optimisation: Only pass predicates that really do something
1476 constexpr bool filterEdges = !std::is_same<decltype(edgeFilter), decltype(keepAllEdges)>::value;
1477 if constexpr(filterEdges) {
1478 return boost::filtered_graph(_graph, edgeFilterFunctor);
1479 }
1480 else {
1481 return _graph;
1482 }
1483 }
1484
1485 /********************************************************************************************************************/
1486
1487 namespace detail {
1488 // Helper class for Impl::visit()
1489 template<typename BASE, typename VISITOR, typename FILTER, bool RETURN_FIRST_HIT>
1490 struct VisitorHelper : public BASE {
1491 // Call given visitor functor for each vertex (at "discover_vertex"), stop when finishing vertex stopAfterVertex
1492 // (checked in "finish_vertex"). By default, stopAfterVertex is set to an out-of-range index so the search is
1493 // not stopped. The stopping is realised by throwing a DfsVisitor::StopException.
1494 explicit VisitorHelper(VISITOR& visitor, std::shared_ptr<Impl> impl, FILTER& filter, Vertex stopAfterVertex,
1496 : _visitor(visitor), _filter(filter), _stopAfterVertex(stopAfterVertex), _impl(std::move(impl)), _rv(rv),
1497 _visitOrder{visitOrder} {}
1498
1499 // This is a required function by boost::graph - disable naming check
1500 template<class Vertex, class Graph>
1501 // NOLINTNEXTLINE(readability-identifier-naming)
1504 doVisit(v, g);
1505 }
1506 }
1507
1508 // This is a required function by boost::graph - disable naming check
1509 template<class Vertex, class Graph>
1510 // NOLINTNEXTLINE(readability-identifier-naming)
1513 doVisit(v, g);
1514 }
1515 if(v == _stopAfterVertex) {
1516 throw StopException();
1517 }
1518 }
1519
1520 template<class Vertex, class Graph>
1521 void doVisit(Vertex v, Graph& g) {
1522 // apply vertex filter
1523 if(!_filter.evalVertexFilter(g[v])) {
1524 return;
1525 }
1526
1527 if constexpr(RETURN_FIRST_HIT) {
1528 if constexpr(!std::is_same<detail::VisitorReturnType<VISITOR, FILTER>, void>::value) {
1529 _rv.value = g[v].visitProxy(_visitor, v, _impl);
1530 }
1531 else {
1532 g[v].visitProxy(_visitor, v, _impl);
1533 }
1534 throw StopException();
1535 }
1536 else {
1537 g[v].visitProxy(_visitor, v, _impl);
1538 }
1539 }
1540
1541 auto getReturnValue() { return _rv.get(); }
1542
1543 // This exception is just used to trick the boost::depth_first_search() to stop.
1544 class StopException : public std::exception {};
1545
1546 protected:
1547 VISITOR& _visitor;
1548 FILTER& _filter;
1550 std::shared_ptr<Impl> _impl;
1553 };
1554
1555 } // namespace detail
1556
1557 /********************************************************************************************************************/
1558
1559 template<typename VISITOR, typename... Args>
1560 auto Impl::visit(Vertex startVertex, VISITOR visitor, Args... args) {
1561 // increase visiting level to prevent modification while iterating, decrease when leaving this function
1562 _graphVisitingLevel++;
1563 auto decrementVisitingLevel = cppext::finally([&] { _graphVisitingLevel--; });
1564
1565 auto filteredGraph = getFilteredGraph(args...);
1566
1567 auto vertexFilter = Model::getVertexFilter(args...);
1568
1569 // Execute search operation based on selected type
1570 auto typeHolder = Model::getSearchType<Args...>();
1571 using type = typename decltype(typeHolder)::type;
1572 constexpr bool isAdjacent =
1573 std::is_same<AdjacentSearch, type>::value || std::is_base_of<AdjacentSearch, type>::value;
1574 constexpr bool isAdjacentIn =
1575 std::is_same<AdjacentInSearch, type>::value || std::is_base_of<AdjacentInSearch, type>::value;
1576 constexpr bool isAdjacentOut =
1577 std::is_same<AdjacentOutSearch, type>::value || std::is_base_of<AdjacentOutSearch, type>::value;
1578 constexpr bool isDFS =
1579 std::is_same<DepthFirstSearch, type>::value || std::is_base_of<DepthFirstSearch, type>::value;
1580 constexpr bool isBFS =
1581 std::is_same<BreadthFirstSearch, type>::value || std::is_base_of<BreadthFirstSearch, type>::value;
1582
1583 constexpr bool continueDisjunct = Model::hasSearchOption<ContinueSearchDisjunctTrees, Args...>();
1584 constexpr bool returnFirst = Model::hasSearchOption<ReturnFirstHit, Args...>();
1585
1586 // Wrapper for visitor to filter wrong objecttypes in constexpr condition, so the actual visitor does not have
1587 // to work with all proxy types, just the ones which can get past the VisitorFilter.
1588 using VisitorReturnType = detail::VisitorReturnType<VISITOR, decltype(vertexFilter)>;
1589 auto visitorWrapper = [&](auto proxy) -> VisitorReturnType {
1590 if constexpr(vertexFilter.template constevalObjecttype<decltype(proxy)>()) {
1591 return visitor(proxy);
1592 }
1593 // The VertexFilter makes sure that this function is never called with the wrong type, hence if we end up here
1594 // there is a bug in the VertexFilter. Note that this code will get instantiated, just never executed.
1595 throw ChimeraTK::logic_error("We should never end up here...");
1596 };
1597
1598 if constexpr(isAdjacent || isAdjacentOut) {
1599 auto [start, end] = boost::out_edges(startVertex, filteredGraph);
1600 for(auto it = start; it != end; ++it) {
1601 // obtain target vertex of the current outgoing edge (i.e. vertex at the other end of the edge)
1602 auto vtx = target(*it, _graph);
1603
1604 // apply vertex filter
1605 if(!vertexFilter.evalVertexFilter(_graph[vtx])) {
1606 continue;
1607 }
1608
1609 if constexpr(returnFirst) {
1610 return filteredGraph[vtx].visitProxy(visitorWrapper, vtx, shared_from_this());
1611 }
1612 else {
1613 filteredGraph[vtx].visitProxy(visitorWrapper, vtx, shared_from_this());
1614 }
1615 }
1616 }
1617 if constexpr(isAdjacent || isAdjacentIn) {
1618 auto [start, end] = boost::in_edges(startVertex, filteredGraph);
1619 for(auto it = start; it != end; ++it) {
1620 // obtain source vertex of the current incoming edge (i.e. vertex at the other end of the edge)
1621 auto vtx = source(*it, _graph);
1622
1623 // apply vertex filter
1624 if(!vertexFilter.evalVertexFilter(_graph[vtx])) {
1625 continue;
1626 }
1627
1628 if constexpr(returnFirst) {
1629 return filteredGraph[vtx].visitProxy(visitorWrapper, vtx, shared_from_this());
1630 }
1631 else {
1632 filteredGraph[vtx].visitProxy(visitorWrapper, vtx, shared_from_this());
1633 }
1634 }
1635 }
1636 if constexpr(isDFS || isBFS) {
1637 // For DFS: By default stop the search when the start vertex is finished, unless configured otherwise
1638 // For BFS: The search anyway does not continue with disjunct parts, and stopping when the start vertex is
1639 // finished would stop too early (no recursion).
1640 Vertex stopVertex;
1641 if constexpr(continueDisjunct || isBFS) {
1642 stopVertex = std::numeric_limits<Vertex>::max();
1643 }
1644 else {
1645 stopVertex = startVertex;
1646 }
1647
1648 // create visitor object
1649 detail::ValueHolder<detail::VisitorReturnType<decltype(visitorWrapper), decltype(vertexFilter)>> rv;
1650 constexpr bool hasVisitOrderOption = Model::hasSearchOption<VisitOrder, Args...>();
1651 VisitOrder visitOrder;
1652 if constexpr(hasVisitOrderOption) {
1653 visitOrder = Model::getSearchOption<VisitOrder, Args...>(args...);
1654 }
1655 auto visitorObjectFactory = [&]() {
1656 if constexpr(isDFS) {
1657 return detail::VisitorHelper<boost::dfs_visitor<>, decltype(visitorWrapper), decltype(vertexFilter),
1658 returnFirst>(visitorWrapper, shared_from_this(), vertexFilter, stopVertex, rv, visitOrder);
1659 }
1660 else {
1661 return detail::VisitorHelper<boost::bfs_visitor<>, decltype(visitorWrapper), decltype(vertexFilter),
1662 returnFirst>(visitorWrapper, shared_from_this(), vertexFilter, stopVertex, rv, visitOrder);
1663 }
1664 };
1665 auto visitorObject = visitorObjectFactory();
1666
1667 // Prepare a color_map for use with depth_first_search resp. breadth_first_search algorithms.
1668 //
1669 // Default color_map works only for boost::vecS for the vertex container, but we are using boost::listS.
1670 // BOOST documentation is minimalistic in this point. The following solution has been found "experimentally".
1671 //
1672 // The color_map is used by the algorithms (boost::depth_first_search and boost::breadth_first_search) to
1673 // keep track of seen vertices. It is used to store a value of the type boost::default_color_type for each
1674 // vertex, so the map key needs to be some kind of identifier for the vertex.
1675 //
1676 // The default color_map uses the vertex index as a key, which is not possible, because there is no vertex
1677 // index when using boost::listS. The color_map argument has follow the concept "read/write property map".
1678 // associative_property_map implements this concept and can use a std::map as a basis.
1679 //
1680 // The type of the map key (Vertex) was found out more or less by trial and error.
1681 std::map<Vertex, boost::default_color_type> colors;
1682 boost::associative_property_map color_map(colors);
1683
1684 // The try-catch block is just a trick to terminate the search operation early (when stopVertex hs finished)
1685 try {
1686 if constexpr(isDFS) {
1687 boost::depth_first_search(filteredGraph, visitorObject, color_map, startVertex);
1688 }
1689 else {
1690 boost::queue<Vertex> buffer;
1691 boost::breadth_first_search(filteredGraph, startVertex, buffer, visitorObject, color_map);
1692 }
1693 }
1694 catch(typename decltype(visitorObject)::StopException&) {
1695 // Ignore this exception, as it is just to use to trick the boost::depth/breadth_first_search() to stop
1696 }
1697
1698 if constexpr(returnFirst) {
1699 return visitorObject.getReturnValue();
1700 }
1701 }
1702
1703 if constexpr(returnFirst) {
1704 // Nothing found but ReturnFirstHit option specified: return the not-found value
1705 return Model::getSearchOption<ReturnFirstHit, Args...>(args...).notFoundValue.get();
1706 }
1707 }
1708
1709 /********************************************************************************************************************/
1710
1711 template<typename VISITOR, typename PROXY>
1712 bool Impl::visitByPath(std::string_view path, VISITOR visitor, PROXY startProxy) {
1713 // Note: the _graphVisitingLevel is not incremented here, since this visitByPath() function does not use any
1714 // iterators directly. Only when using visit() internally, iterators are used, but visit() increments the counter
1715 // itself.
1716
1717 // remove any redundant "./" at the beginning
1718 while(boost::starts_with(path, "./")) {
1719 path = path.substr(2);
1720 }
1721
1722 // resolve reference to ourself
1723 if(path.empty() || path == ".") {
1724 visitor(startProxy);
1725 return true;
1726 }
1727
1728 // first component is one level up
1729 if(boost::starts_with(path, "../") || path == "..") {
1730 // remove the component from the path
1731 path = (path.size() > 2) ? path.substr(3) : "";
1732
1733 // delegate to our parent proxy
1734 bool found = false;
1735 visit(
1736 startProxy._d->vertex,
1737 [&](auto parent) {
1738 if constexpr(isDirectory(parent) || isRoot(parent)) {
1739 found = parent.visitByPath(path, visitor);
1740 }
1741 else {
1742 assert(false); // directory structure guarantees only directories and the root as parents
1743 }
1744 },
1745 getParent);
1746 return found;
1747 }
1748
1749 // first component refers to root
1750 if(boost::starts_with(path, "/")) {
1751 // remove the leading slash
1752 path = path.substr(1);
1753
1754 // delegate to root proxy
1755 return RootProxy::makeRootProxy(shared_from_this()).visitByPath(path, visitor);
1756 }
1757
1758 // first component is a child
1759 // split by first slash
1760 auto slash = path.find_first_of('/');
1761 auto childName = path.substr(0, slash);
1762 path = (slash < path.length() - 1) ? path.substr(slash + 1) : "";
1763
1764 // delegate to child proxy
1765 bool found = false;
1766 visit(
1767 startProxy._d->vertex,
1768 [&](auto child) {
1769 if constexpr(isDirectory(child) || isVariable(child)) {
1770 if(child.getName() == childName) {
1771 found = child.visitByPath(path, visitor);
1772 }
1773 }
1774 else {
1775 assert(false); // search predicate guarantees only directories and variables
1776 }
1777 },
1778 children);
1779 return found;
1780 }
1781
1782 /********************************************************************************************************************/
1783 /********************************************************************************************************************/
1785 /********************************************************************************************************************/
1786 /********************************************************************************************************************/
1787
1788 template<typename... Args>
1789 void RootProxy::writeGraphViz(const std::string& filename, Args... args) const {
1790 auto filteredGraph = _d->impl->getFilteredGraph(args...);
1791
1792 auto vertexFilter = Model::getVertexFilter(args...);
1793
1794 std::ofstream of(filename);
1795
1796 auto vertexPropWriter = [&](std::ostream& out, const auto& vtx) {
1797 // apply vertex filter
1798 if(!vertexFilter.evalVertexFilter(_d->impl->_graph[vtx])) {
1799 return;
1800 }
1801
1802 _d->impl->_graph[vtx].visit([&](auto prop) {
1803 out << "[";
1804
1805 // Add label depending on type
1806 if constexpr(std::is_same<decltype(prop), VertexProperties::RootProperties>::value) {
1807 out << R"(label="/")";
1808 }
1809 else if constexpr(std::is_same<decltype(prop), VertexProperties::DeviceModuleProperties>::value) {
1810 out << R"(label=")" << prop.aliasOrCdd << R"(")";
1811 }
1812 else if constexpr(!std::is_same<decltype(prop), VertexProperties::InvalidProperties>::value) {
1813 out << R"(label=")" << prop.name << R"(")";
1814 }
1815 else {
1816 throw ChimeraTK::logic_error("Unexpected VertexProperties type");
1817 }
1818
1819 out << ", ";
1820
1821 // Set color depending on type
1822 if constexpr(std::is_same<decltype(prop), VertexProperties::RootProperties>::value) {
1823 out << "color=grey,style=filled";
1824 }
1825 else if constexpr(std::is_same<decltype(prop), VertexProperties::ModuleGroupProperties>::value) {
1826 out << "color=lightskyblue,style=filled";
1827 }
1828 else if constexpr(std::is_same<decltype(prop), VertexProperties::ApplicationModuleProperties>::value) {
1829 out << "color=cyan,style=filled";
1830 }
1831 else if constexpr(std::is_same<decltype(prop), VertexProperties::VariableGroupProperties>::value) {
1832 out << "color=springgreen,style=filled";
1833 }
1834 else if constexpr(std::is_same<decltype(prop), VertexProperties::DeviceModuleProperties>::value) {
1835 out << "color=yellow,style=filled";
1836 }
1837 else if constexpr(std::is_same<decltype(prop), VertexProperties::ProcessVariableProperties>::value) {
1838 out << "color=black";
1839 }
1840 else if constexpr(std::is_same<decltype(prop), VertexProperties::DirectoryProperties>::value) {
1841 out << "color=peachpuff,style=filled";
1842 }
1843 else {
1844 throw ChimeraTK::logic_error("Unexpected VertexProperties type");
1845 }
1846 out << "]";
1847 });
1848 };
1849
1850 auto edgePropWriter = [&](std::ostream& out, const auto& edge) {
1851 out << "[";
1852 switch(_d->impl->_graph[edge].type) {
1853 case EdgeProperties::Type::parenthood: {
1854 out << "color=red, arrowhead=diamond";
1855 break;
1856 }
1857 case EdgeProperties::Type::ownership: {
1858 out << "color=blue, arrowhead=odot";
1859 break;
1860 }
1861 case EdgeProperties::Type::pvAccess: {
1862 out << "color=black";
1863 break;
1864 }
1865 case EdgeProperties::Type::neighbourhood: {
1866 out << "color=olive, arrowhead=tee";
1867 break;
1868 }
1869 case EdgeProperties::Type::trigger: {
1870 out << "color=grey, arrowhead=crow";
1871 break;
1872 }
1873 default: {
1874 throw ChimeraTK::logic_error("Unexpected EdgeProperties type");
1875 }
1876 }
1877 out << "]";
1878 };
1879
1880 // Generate a vertex id map. write_graphviz will use those ids as node ids in the generated graphviz code.
1881 std::map<Vertex, size_t> vertex_ids;
1882 for(auto u : boost::make_iterator_range(vertices(filteredGraph))) {
1883 vertex_ids[u] = vertex_ids.size();
1884 }
1885
1886 // Note that all 3 writers have to be specified to pass the vertex id map, otherwise very weired error messages
1887 // will occur.
1888 boost::write_graphviz(of, filteredGraph, vertexPropWriter, edgePropWriter, boost::default_writer(),
1889 boost::make_assoc_property_map(vertex_ids));
1890 }
1891
1892 /********************************************************************************************************************/
1893
1894 template<typename VISITOR>
1895 bool RootProxy::visitByPath(std::string_view path, VISITOR visitor) const {
1896 return _d->impl->visitByPath(path, visitor, *this);
1897 }
1898
1899 /********************************************************************************************************************/
1900 /********************************************************************************************************************/
1902 /********************************************************************************************************************/
1903 /********************************************************************************************************************/
1904
1905 template<typename VISITOR>
1906 bool DirectoryProxy::visitByPath(std::string_view path, VISITOR visitor) const {
1907 return _d->impl->visitByPath(path, visitor, *this);
1908 }
1909
1910 /********************************************************************************************************************/
1911 /********************************************************************************************************************/
1913 /********************************************************************************************************************/
1914 /********************************************************************************************************************/
1915
1916 template<typename VISITOR>
1917 bool ProcessVariableProxy::visitByPath(std::string_view path, VISITOR visitor) const {
1918 return _d->impl->visitByPath(path, visitor, *this);
1919 }
1920
1921 /********************************************************************************************************************/
1922 /********************************************************************************************************************/
1924 /********************************************************************************************************************/
1925 /********************************************************************************************************************/
1926
1927 template<typename VISITOR>
1928 typename std::invoke_result<VISITOR, VertexProperties::ApplicationModuleProperties&>::type VertexProperties::visit(
1929 VISITOR visitor) const {
1930 switch(type) {
1931 case Type::root: {
1932 return visitor(std::get<RootProperties>(p));
1933 break;
1934 }
1935 case Type::moduleGroup: {
1936 return visitor(std::get<ModuleGroupProperties>(p));
1937 break;
1938 }
1939 case Type::applicationModule: {
1940 return visitor(std::get<ApplicationModuleProperties>(p));
1941 break;
1942 }
1943 case Type::variableGroup: {
1944 return visitor(std::get<VariableGroupProperties>(p));
1945 break;
1946 }
1947 case Type::deviceModule: {
1948 return visitor(std::get<DeviceModuleProperties>(p));
1949 break;
1950 }
1951 case Type::processVariable: {
1952 return visitor(std::get<ProcessVariableProperties>(p));
1953 break;
1954 }
1955 case Type::directory: {
1956 return visitor(std::get<DirectoryProperties>(p));
1957 break;
1958 }
1959 default: {
1960 }
1961 }
1962 throw ChimeraTK::logic_error("VertexProperties::visit() called for invalid-typed vertex.");
1963 }
1964
1965 /********************************************************************************************************************/
1966
1967 template<typename PROXY>
1968 PROXY VertexProperties::makeProxy(Vertex vertex, const std::shared_ptr<Impl>& impl) const {
1969 auto proxyShared = _proxy.lock();
1970 if(!proxyShared) {
1971 proxyShared = std::make_shared<Proxy::ProxyData>(vertex, impl);
1972 _proxy = proxyShared;
1973 }
1974 return PROXY(proxyShared);
1975 }
1976
1977 /********************************************************************************************************************/
1978
1979 template<typename VISITOR>
1980 typename std::invoke_result<VISITOR, ApplicationModuleProxy>::type VertexProperties::visitProxy(
1981 VISITOR visitor, Vertex vertex, const std::shared_ptr<Impl>& impl) const {
1982 switch(type) {
1983 case Type::root: {
1984 return visitor(makeProxy<RootProxy>(vertex, impl));
1985 break;
1986 }
1987 case Type::moduleGroup: {
1988 return visitor(makeProxy<ModuleGroupProxy>(vertex, impl));
1989 break;
1990 }
1991 case Type::applicationModule: {
1992 return visitor(makeProxy<ApplicationModuleProxy>(vertex, impl));
1993 break;
1994 }
1995 case Type::variableGroup: {
1996 return visitor(makeProxy<VariableGroupProxy>(vertex, impl));
1997 break;
1998 }
1999 case Type::deviceModule: {
2000 return visitor(makeProxy<DeviceModuleProxy>(vertex, impl));
2001 break;
2002 }
2003 case Type::processVariable: {
2004 return visitor(makeProxy<ProcessVariableProxy>(vertex, impl));
2005 break;
2006 }
2007 case Type::directory: {
2008 return visitor(makeProxy<DirectoryProxy>(vertex, impl));
2009 break;
2010 }
2011 case Type::invalid: {
2012 }
2013 }
2014 throw ChimeraTK::logic_error("VertexProperties::visitProxy() called for invalid-typed vertex.");
2015 }
2016
2017 /********************************************************************************************************************/
2018
2019} // namespace ChimeraTK::Model
Adds features required for inversion of control to an accessor.
VariableGroupProxy add(VariableGroup &module)
Definition Model.cc:222
void remove(VariableGroup &module)
Definition Model.cc:234
ApplicationModule & getApplicationModule() const
Return the actual ApplicationModule.
Definition Model.cc:246
const std::string & getName() const
Get the name of the ApplicationModule.
Definition Model.cc:216
void addVariable(ProcessVariableProxy &variable, VariableNetworkNode &node)
Definition Model.cc:228
void addVariable(ProcessVariableProxy &variable, VariableNetworkNode &node)
Definition Model.cc:352
ProcessVariableProxy getTrigger() const
Get the ProcessVariableProxy for the trigger.
Definition Model.cc:346
DeviceModule & getDeviceModule() const
Definition Model.cc:934
const std::string & getAliasOrCdd() const
Get the alias or CDD of the device.
Definition Model.cc:340
ProcessVariableProxy addVariable(const std::string &name)
Definition Model.cc:545
const std::string & getName() const
Get the name of the Directory.
Definition Model.cc:539
DirectoryProxy addDirectory(const std::string &name)
Definition Model.cc:551
bool visitByPath(std::string_view path, VISITOR visitor) const
Resolve the given path and call the visitor for the found object.
Definition Model.h:1906
DirectoryProxy addDirectoryRecursive(const std::string &name)
Definition Model.cc:557
Implementation class for the model.
Definition Model.h:1360
ModuleGroupProxy add(ModuleGroup &module)
Definition Model.cc:164
const std::string & getName() const
Get the name of the ModuleGroup.
Definition Model.cc:158
ModuleGroup & getModuleGroup() const
Return the actual ModuleGroup.
Definition Model.cc:194
void remove(ApplicationModule &module)
Definition Model.cc:188
Proxy class which does not keep the ownership of the model.
Definition Model.h:466
NonOwningProxy & operator=(const ProxyType &owningProxy)
Assign non-owning proxy from (owning) proxy.
Definition Model.h:478
ProxyType lock()
Return owning proxy.
Definition Model.h:492
NonOwningProxy()=default
Default constructor creates "empty" non-owning proxy which does not contain a valid proxy.
NonOwningProxy(const ProxyType &owningProxy)
Construct non-owning proxy from (owning) proxy.
Definition Model.h:473
const std::vector< std::shared_ptr< VariableNetworkNode > > & getNodes() const
Return all VariableNetworkNodes for this variable.
Definition Model.cc:381
void addTag(const std::string &tag)
Add tag to this PV. Used by VariableNetworkNode to update the model when tags are added to PVs.
Definition Model.cc:393
const std::string & getName() const
Get the name of the ProcessVariable.
Definition Model.cc:375
void removeNode(const VariableNetworkNode &node)
Remove VariableNetworkNode from the list of nodes. Note: Will invalidate return value of getNodes()!
Definition Model.cc:403
const std::unordered_set< std::string > & getTags() const
Return all tags attached to this variable.
Definition Model.cc:387
bool visitByPath(std::string_view path, VISITOR visitor) const
Resolve the given path and call the visitor for the found object.
Definition Model.h:1917
Base class for the proxies representing objects in the model.
Definition Model.h:72
std::shared_ptr< ProxyData > _d
Definition Model.h:200
bool isValid() const
Check if the model is valid.
Definition Model.cc:31
friend class RootProxy
Definition Model.h:182
bool operator==(const Proxy &other) const
Definition Model.cc:37
auto visit(VISITOR visitor, Args... args) const
Traverse the model using the specified filter and call the visitor functor for each ModuleGroup,...
Definition Model.h:1451
Proxy()=default
The default constructor creates a dysfunctional, empty proxy.
std::string getFullyQualifiedPath() const
Return the fully qualified path.
Definition Model.cc:25
Proxy representing the root of the application model.
Definition Model.h:210
DirectoryProxy addDirectoryRecursive(const std::string &name)
Definition Model.cc:96
ModuleGroupProxy add(ModuleGroup &module)
Definition Model.cc:72
void writeGraphViz(const std::string &filename, Args... args) const
Implementations of RootProxy.
Definition Model.h:1789
void remove(ApplicationModule &module)
Definition Model.cc:117
static RootProxy makeRootProxy(const std::shared_ptr< Impl > &impl)
Create RootProxy assuming the application has been created already (i.e.
Definition Model.cc:135
ProcessVariableProxy addVariable(const std::string &name)
Definition Model.cc:105
DirectoryProxy addDirectory(const std::string &name)
Definition Model.cc:90
bool visitByPath(std::string_view path, VISITOR visitor) const
Resolve the given path and call the visitor for the found object.
Definition Model.h:1895
void remove(VariableGroup &module)
Definition Model.cc:288
VariableGroupProxy add(VariableGroup &module)
Definition Model.cc:276
const std::string & getName() const
Get the name of the VariableGroup.
Definition Model.cc:270
ApplicationModuleProxy getOwningModule() const
Return the owning ApplicationModule (may be indirectly owned in case of nested VariableGroups).
Definition Model.cc:294
VariableGroup & getVariableGroup() const
Return the actual VariableGroup.
Definition Model.cc:316
void addVariable(ProcessVariableProxy &variable, VariableNetworkNode &node)
Definition Model.cc:282
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.
constexpr auto findVertexFilterAcceptedProxyType(VERTEX_FILTER vertexFilter)
Helper function to find one of the Proxy types which will be let through by the given vertex filter.
Definition Model.h:1027
typename std::invoke_result< VISITOR, typename std::invoke_result< decltype(detail::findVertexFilterAcceptedProxyType< VERTEX_FILTER >), VERTEX_FILTER >::type >::type VisitorReturnType
Helper to get the return type of a visitor functor, which accepts any proxy type which can pass the g...
Definition Model.h:1058
boost::multisetS OutEdgeListType
Definition Model.h:55
boost::listS VertexListType
Definition Model.h:56
constexpr ReturnFirstHitWithValue< void > returnFirstHit()
Stop the search after the first hit and return.
Definition Model.h:790
constexpr bool isDirectory(const PROPERTY_OR_PROXY &)
Definition Model.h:669
constexpr bool hasSearchOption()
Definition Model.h:1300
constexpr auto combinedSearchConfig(FIRST first, MORE... more)
Definition Model.h:1104
constexpr bool isVariableGroup(const PROPERTY_OR_PROXY &)
Definition Model.h:645
constexpr bool isApplicationModule(const PROPERTY_OR_PROXY &)
Definition Model.h:637
constexpr bool isDeviceModule(const PROPERTY_OR_PROXY &)
Definition Model.h:653
constexpr bool isModuleGroup(const PROPERTY_OR_PROXY &)
Definition Model.h:629
constexpr bool hasName(const PROPERTY_OR_PROXY &)
Definition Model.h:677
boost::filtered_graph< Graph, std::function< bool(const Edge &)>, boost::keep_all > EdgeFilteredView
Definition Model.h:702
Graph::edge_descriptor Edge
Definition Model.h:700
constexpr auto getVertexFilter()
Definition Model.h:1269
constexpr bool isRoot(const PROPERTY_OR_PROXY &)
Predicates to identify the type of a proxy or a properties struct.
Definition Model.h:621
constexpr auto getSearchOption()
Definition Model.h:1333
constexpr auto getSearchType()
Definition Model.h:1281
constexpr void checkConfigValidity()
Definition Model.h:1351
boost::adjacency_list< detail::OutEdgeListType, detail::VertexListType, boost::bidirectionalS, VertexProperties, EdgeProperties > Graph
Graph type for the model.
Definition Model.h:696
boost::adjacency_list< detail::OutEdgeListType, detail::VertexListType, boost::bidirectionalS >::vertex_descriptor Vertex
Definition Model.h:65
constexpr auto getEdgeFilter()
Definition Model.h:1250
constexpr bool isVariable(const PROPERTY_OR_PROXY &)
Definition Model.h:661
InvalidityTracer application module.
constexpr auto operator&&(const FILTER_NEXT_RHS &rhs) const
Definition Model.h:864
constexpr auto operator||(const FILTER_NEXT_RHS &rhs) const
Definition Model.h:859
bool evalEdgeFilter(const typename FILTER_LHS::PropertiesType &e) const
Definition Model.h:854
bool evalVertexFilter(const typename FILTER_LHS::PropertiesType &e) const
Definition Model.h:850
constexpr AndSet(FILTER_LHS lhs, FILTER_RHS rhs)
Definition Model.h:848
constexpr bool constevalObjecttype() const
Definition Model.h:869
constexpr CombinedSearchConfig(A a, B b)
Definition Model.h:1098
constexpr EdgeFilter(const EdgeFilter< FILTER > &rhs) noexcept=default
constexpr EdgeFilter(EdgeFilter< FILTER > &&rhs) noexcept=default
constexpr auto operator||(const FILTER_RHS &rhs) const
Definition Model.h:883
bool evalEdgeFilter(const EdgeProperties &e) const
Definition Model.h:896
constexpr auto operator&&(const FILTER_RHS &rhs) const
Definition Model.h:890
constexpr EdgeFilter(FILTER filter)
Definition Model.h:878
Information to be stored with each edge.
Definition Model.h:598
@ neighbourhood
Edge represents the PV directory hierarchy. Arrow points towards the sub-directory or PV.
@ parenthood
Edge represents (C++) ownership. Arrow points towards the sub-module or PV.
@ ownership
Edge represents access of an module to a PV. Arrow shows data flow direction (read/write).
@ trigger
Edge points from a module to the directory where its PVs appear without hierarchy modification.
bool pvAccessWithReturnChannel
Can be true only for Type::pvAccess, in which case it indicates the presence of a return channel.
Definition Model.h:610
constexpr OrSet(FILTER_LHS lhs, FILTER_RHS rhs)
Definition Model.h:818
constexpr auto operator&&(const FILTER_NEXT_RHS &rhs) const
Definition Model.h:834
bool evalVertexFilter(const typename FILTER_LHS::PropertiesType &e) const
Definition Model.h:820
constexpr auto operator||(const FILTER_NEXT_RHS &rhs) const
Definition Model.h:829
constexpr bool constevalObjecttype() const
Definition Model.h:839
bool evalEdgeFilter(const typename FILTER_LHS::PropertiesType &e) const
Definition Model.h:824
The data holding struct for the proxy classes.
Definition Model.h:1437
std::shared_ptr< Impl > impl
Definition Model.h:1439
ProxyData(Model::Vertex v, std::shared_ptr< Impl > i)
Definition Model.h:1441
detail::ValueHolder< T > notFoundValue
Definition Model.h:770
Do not use these class definitions, instead use the static instances below.
Definition Model.h:754
Do not use these class definitions, instead use the static instances below.
Definition Model.h:707
bool evalVertexFilter(const VertexProperties &e) const
Definition Model.h:927
constexpr VertexFilter(FILTER filter)
Definition Model.h:909
constexpr VertexFilter(const VertexFilter< FILTER > &rhs)=default
constexpr auto operator||(const FILTER_RHS &rhs) const
Definition Model.h:914
constexpr bool constevalObjecttype() const
Definition Model.h:931
constexpr auto operator&&(const FILTER_RHS &rhs) const
Definition Model.h:921
constexpr VertexFilter(VertexFilter< FILTER > &&rhs) noexcept=default
NonOwningProxy< ProcessVariableProxy > trigger
Definition Model.h:540
std::vector< std::shared_ptr< VariableNetworkNode > > nodes
Definition Model.h:545
This is used to allow default construction of the std::variant.
Definition Model.h:523
Information to be stored with each vertex.
Definition Model.h:509
VertexProperties & operator=(const VertexProperties &other)
Definition Model.h:570
std::variant< InvalidProperties, RootProperties, ModuleGroupProperties, ApplicationModuleProperties, VariableGroupProperties, DeviceModuleProperties, ProcessVariableProperties, DirectoryProperties > p
Definition Model.h:555
std::invoke_result< VISITOR, ApplicationModuleProperties & >::type visit(VISITOR visitor) const
Implementations of VertexProperties.
Definition Model.h:1928
VertexProperties(const VertexProperties &other)=default
PROXY makeProxy(Vertex vertex, const std::shared_ptr< Impl > &impl) const
Definition Model.h:1968
std::invoke_result< VISITOR, ApplicationModuleProxy >::type visitProxy(VISITOR visitor, Vertex vertex, const std::shared_ptr< Impl > &impl) const
Definition Model.h:1980
VisitOrderType type
Definition Model.h:765
constexpr VisitOrder()=default
constexpr VisitOrder(VisitOrderType t)
Definition Model.h:763
Helper to hold values of an arbitrary type including void (in which case no value is held,...
Definition Model.h:738
std::shared_ptr< Impl > _impl
Definition Model.h:1550
void doVisit(Vertex v, Graph &g)
Definition Model.h:1521
void discover_vertex(Vertex v, Graph &g)
Definition Model.h:1502
void finish_vertex(Vertex v, Graph &g)
Definition Model.h:1511
VisitorHelper(VISITOR &visitor, std::shared_ptr< Impl > impl, FILTER &filter, Vertex stopAfterVertex, ValueHolder< detail::VisitorReturnType< VISITOR, FILTER > > &rv, VisitOrder &visitOrder)
Definition Model.h:1494
ValueHolder< detail::VisitorReturnType< VISITOR, FILTER > > & _rv
Definition Model.h:1551