19#ifndef HEDGEHOG_CX_GRAPH_H_
20#define HEDGEHOG_CX_GRAPH_H_
26#include "../tools/concepts.h"
27#include "../tools/types_nodes_map.h"
29#include "../../src/tools/meta_functions.h"
34#ifndef DOXYGEN_SHOULD_SKIP_THIS
37template<tool::HedgehogDynamicGraphForStaticAnalysis GraphType>
43template<tool::HedgehogDynamicGraphForStaticAnalysis GraphType>
44class Graph :
public Node<GraphType> {
46 std::vector<hh_cx::behavior::AbstractNode const *>
49 std::vector<std::string>
50 registeredNodesName_{};
56 std::vector<std::vector<std::vector<std::string>>>
61 std::vector<AbstractTest<GraphType>
const *> tests_{};
63 std::string report_{};
68 constexpr explicit Graph(std::string
const &name) : hh_cx::Node<GraphType>(name) {}
71 constexpr virtual ~Graph() =
default;
77 [[nodiscard]]
constexpr bool isLinked(
78 hh_cx::behavior::AbstractNode
const *sender,
79 hh_cx::behavior::AbstractNode
const *receiver)
const {
80 return isLinked(nodeId(sender), nodeId(receiver));
87 [[nodiscard]]
constexpr bool isLinked(
88 size_t const senderId,
89 size_t const receiverId)
const {
90 if (senderId >= numberNodesRegistered() || receiverId >= numberNodesRegistered()) {
91 throw (std::runtime_error(
"The node you are trying to get does not exist in the graph."));
93 return !adjacencyMatrix_.at(senderId).at(receiverId).empty();
101 [[nodiscard]]
constexpr bool isROLinked(
102 hh_cx::behavior::AbstractNode
const *sender,
103 hh_cx::behavior::AbstractNode
const *receiver,
104 std::string
const &typeName)
const {
105 return isROLinked(nodeId(sender), nodeId(receiver), typeName);
113 [[nodiscard]]
constexpr bool isROLinked(
114 size_t const senderId,
115 size_t const receiverId,
116 std::string
const &typeName)
const {
117 if (senderId >= numberNodesRegistered() || receiverId >= numberNodesRegistered()) {
118 throw (std::runtime_error(
"The node you are trying to get does not exist in the graph."));
120 auto listROType = ROEdges_.at(senderId).at(receiverId);
121 return std::find(listROType.cbegin(), listROType.cend(), typeName) != listROType.cend();
129 [[nodiscard]]
constexpr bool isConstLinked(
130 hh_cx::behavior::AbstractNode
const *sender,
131 hh_cx::behavior::AbstractNode
const *receiver,
132 std::string
const &typeName)
const {
133 return isConstLinked(nodeId(sender), nodeId(receiver), typeName);
141 [[nodiscard]]
constexpr bool isConstLinked(
142 size_t const senderId,
143 size_t const receiverId,
144 std::string
const &typeName)
const {
145 if (senderId >= numberNodesRegistered() || receiverId >= numberNodesRegistered()) {
146 throw (std::runtime_error(
"The node you are trying to get does not exist in the graph."));
148 auto listConstType = constEdges_.at(senderId).at(receiverId);
149 return std::find(listConstType.cbegin(), listConstType.cend(), typeName) != listConstType.cend();
154 [[nodiscard]]
constexpr std::string
const &report()
const {
return report_; }
158 [[nodiscard]]
constexpr std::vector<hh_cx::behavior::AbstractNode const *>
const ®isteredNodes()
const {
159 return registeredNodes_;
164 [[nodiscard]]
constexpr std::vector<std::string>
const ®isteredNodesName()
const {
165 return registeredNodesName_;
169 [[nodiscard]]
constexpr std::pair<size_t, size_t> maxEdgeSizes()
const {
170 size_t maxNumberEdges = 0, maxEdgeTypeSize = 0;
171 for (
auto const &sender : adjacencyMatrix_) {
172 for (
auto const &receiver : sender) {
173 if (maxNumberEdges < receiver.size()) { maxNumberEdges = receiver.size(); }
174 for (
auto const &outputType : receiver) {
175 if (maxEdgeTypeSize < outputType.size() + 1) { maxEdgeTypeSize = outputType.size() + 1; }
179 return {maxNumberEdges, maxEdgeTypeSize};
184 [[nodiscard]]
constexpr size_t maxNodeNameSize()
const {
185 size_t maxNodeNameSize = 0;
186 for (
auto const &nodeName : registeredNodesName_) {
187 if (nodeName.size() > maxNodeNameSize) { maxNodeNameSize = nodeName.size(); }
189 return maxNodeNameSize;
194 [[nodiscard]]
constexpr std::vector<std::vector<std::vector<std::string>>>
const &adjacencyMatrix()
const {
195 return adjacencyMatrix_;
200 [[nodiscard]]
constexpr tool::TypesNodesMap
const &inputNodes()
const {
return inputNodes_; }
204 [[nodiscard]]
constexpr tool::TypesNodesMap
const &outputNodes()
const {
return outputNodes_; }
210 [[nodiscard]]
constexpr std::vector<std::vector<std::string>>
const &
211 adjacentNodesTypes(hh_cx::behavior::AbstractNode
const *node)
const {
212 return adjacencyMatrix_.at(nodeId(node));
218 [[nodiscard]]
constexpr std::vector<hh_cx::behavior::AbstractNode const *>
219 adjacentNodes(hh_cx::behavior::AbstractNode
const *node)
const {
221 std::vector<hh_cx::behavior::AbstractNode const *> adjacentNodes{};
223 for (
auto const &possibleReceiver : this->registeredNodes_) {
224 if (isLinked(node, possibleReceiver)) {
225 adjacentNodes.push_back(possibleReceiver);
228 return adjacentNodes;
235 [[nodiscard]]
constexpr std::vector<hh_cx::behavior::AbstractNode const *>
236 adjacentNodes(hh_cx::behavior::AbstractNode
const *node, std::string
const &type)
const {
238 std::vector<hh_cx::behavior::AbstractNode const *> adjacentNodes{};
240 for (
auto const &possibleReceiver : this->registeredNodes_) {
241 auto const &connectionTypes = this->adjacencyMatrix_.at(nodeId(node)).at(nodeId(possibleReceiver));
242 if (std::find(connectionTypes.cbegin(), connectionTypes.cend(), type) != connectionTypes.cend()) {
243 adjacentNodes.push_back(possibleReceiver);
248 return adjacentNodes;
253 [[nodiscard]]
constexpr size_t numberNodesRegistered()
const {
return registeredNodes_.size(); }
258 template<tool::HedgehogStaticNode InputNode>
259 constexpr void inputs(InputNode
const &inputNode) {
261 static_assert(std::tuple_size_v<commonTypes> != 0,
262 "The node can not be an input node, at least one of its input types should be the same of "
263 "the graph input types");
265 splitInputNodeRegistration<commonTypes>(inputNode, std::make_index_sequence<std::tuple_size_v<commonTypes>>());
272 template<
class InputType, tool::HedgehogStaticNode InputNode>
273 constexpr void input(InputNode
const &inputNode) {
274 auto typeName = hh::tool::typeToStr<InputType>();
276 hh::tool::isContainedInTuple_v<InputType, typename InputNode::inputs_t> &&
277 hh::tool::isContainedInTuple_v<InputType, typename GraphType::inputs_t>,
278 "The input type is not shared by the node and the graph.");
279 registerNode(&inputNode);
280 inputNodes_.insert(typeName, &inputNode);
286 template<tool::HedgehogStaticNode OutputNode>
287 constexpr void outputs(OutputNode
const &outputNode) {
289 static_assert(std::tuple_size_v<commonTypes> != 0,
290 "The node can not be an output node, at least one of its output types should be the same of "
291 "the graph iouput types");
292 splitOutputNodeRegistration<commonTypes>(outputNode, std::make_index_sequence<std::tuple_size_v<commonTypes>>{});
299 template<
class OutputType, tool::HedgehogStaticNode OutputNode>
300 constexpr void output(OutputNode
const &outputNode) {
301 auto typeName = hh::tool::typeToStr<OutputType>();
303 hh::tool::isContainedInTuple_v<OutputType, typename OutputNode::outputs_t> &&
304 hh::tool::isContainedInTuple_v<OutputType, typename GraphType::outputs_t>,
305 "The output type is not shared by the node and the graph.");
306 registerNode(&outputNode);
307 outputNodes_.insert(typeName, &outputNode);
315 template<tool::HedgehogStaticNode SenderNode, tool::HedgehogStaticNode ReceiverNode>
316 constexpr void edges(SenderNode
const &senderNode, ReceiverNode
const &receiverNode) {
318 static_assert(std::tuple_size_v<commonTypes> != 0,
319 "The edge cannot be created, there is no common type between the nodes.");
321 splitEdgeRegistration<commonTypes>(senderNode,
323 std::make_index_sequence<std::tuple_size_v<commonTypes>>{});
332 template<
class EdgeType, tool::HedgehogStaticNode SenderNode, tool::HedgehogStaticNode ReceiverNode>
333 constexpr void edge(SenderNode &senderNode, ReceiverNode &receiverNode) {
334 using sender_outputs_t =
typename SenderNode::outputs_t;
335 using receiver_inputs_t =
typename ReceiverNode::inputs_t;
336 using ro_receiver_inputs_t =
typename ReceiverNode::ro_type_t;
337 std::string typeName = hh::tool::typeToStr<EdgeType>();
339 hh::tool::isContainedInTuple_v<EdgeType, sender_outputs_t>
340 && hh::tool::isContainedInTuple_v<EdgeType, receiver_inputs_t>,
341 "The edge cannot be created, the type is not part of the sender's outputs or receiver's inputs.");
343 registerNode(&senderNode);
344 registerNode(&receiverNode);
346 adjacencyMatrix_.at(nodeId(&senderNode)).at(nodeId(&receiverNode)).push_back(typeName);
348 if constexpr (hh::tool::isContainedInTuple_v<EdgeType, ro_receiver_inputs_t>) {
349 ROEdges_.at(nodeId(&senderNode)).at(nodeId(&receiverNode)).push_back(typeName);
352 if constexpr (std::is_const_v<EdgeType>) {
353 constEdges_.at(nodeId(&senderNode)).at(nodeId(&receiverNode)).push_back(typeName);
362 requires std::is_base_of_v<hh_cx::behavior::AbstractNode, Node>
363 constexpr size_t nodeId(Node *node)
const {
364 if (std::find(registeredNodes_.cbegin(), registeredNodes_.cend(), node) == registeredNodes_.cend()) {
365 throw (std::runtime_error(
"The node you are trying to get does not exist in the graph."));
368 for (
auto registeredNode : registeredNodes_) {
369 if (registeredNode == node) {
return nodeId; }
378 [[nodiscard]]
constexpr hh_cx::behavior::AbstractNode
const *node(
size_t id)
const {
379 if (
id >= registeredNodes_.size()) {
throw (std::runtime_error(
"The node you are requesting does not exist.")); }
380 else {
return registeredNodes_.at(
id); }
386 template<
class UserTest>
387 requires std::is_base_of_v<AbstractTest<GraphType>, UserTest>
388 constexpr void addTest(UserTest *test) {
390 if (std::find(tests_.cbegin(), tests_.cend(), test) == tests_.cend()) {
391 tests_.push_back(test);
393 report_.append(test->errorMessage());
394 report_.append(
"\n");
400 [[nodiscard]]
constexpr bool isValid()
const {
402 for (
auto const &test : tests_) { ret &= test->isGraphValid(); }
412 template<
class CommonInputs,
class T, std::size_t... Is>
413 constexpr void splitInputNodeRegistration(T
const &node, std::index_sequence<Is...>) {
414 (input<std::tuple_element_t<Is, CommonInputs>>(node), ...);
422 template<
class CommonOutputs,
class T, std::size_t... Is>
423 constexpr void splitOutputNodeRegistration(T
const &node, std::index_sequence<Is...>) {
424 (output<std::tuple_element_t<Is, CommonOutputs>>(node), ...);
434 template<
class CommonTypes,
class S,
class R, std::size_t... Is>
435 constexpr void splitEdgeRegistration(S
const &sender, R
const &receiver, std::index_sequence<Is...>) {
436 (edge<std::tuple_element_t<Is, CommonTypes>>(sender, receiver), ...);
441 constexpr void registerNode(hh_cx::behavior::AbstractNode
const *node) {
442 if (std::find(registeredNodes_.cbegin(), registeredNodes_.cend(), node) == registeredNodes_.cend()) {
444 registeredNodes_.push_back(node);
445 registeredNodesName_.push_back(node->name());
446 adjacencyMatrix_.emplace_back();
447 ROEdges_.emplace_back();
448 constEdges_.emplace_back();
450 for (
auto &sender : adjacencyMatrix_) { sender.resize(registeredNodes_.size()); }
451 for (
auto &sender : ROEdges_) { sender.resize(registeredNodes_.size()); }
452 for (
auto &sender : constEdges_) { sender.resize(registeredNodes_.size()); }
458 constexpr void validateName(hh_cx::behavior::AbstractNode
const *node) {
460 registeredNodes_.cbegin(), registeredNodes_.cend(),
461 [&node](
auto const ®isteredNode) { return node->name() == registeredNode->name(); })) {
462 throw std::runtime_error(
"Another node with the same name has already been registered.");
typename internals::Intersect< Tuple1, Tuple2 >::type Intersect_t
Helper getting the intersection of types between two type tuples.