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.