19#ifndef HEDGEHOG_CX_DEFROSTER_H_ 
   20#define HEDGEHOG_CX_DEFROSTER_H_ 
   26#include "../tools/type_nodes_map_array.h" 
   27#include "../tools/concepts.h" 
   46template<
class DynGraphType, 
class name_t, 
class report_t, 
class adjacencyMatrix_t, 
class registeredNodesName_t, 
class inputMap_t, 
class outputMap_t>
 
   51  report_t 
const report_; 
 
   52  adjacencyMatrix_t 
const adjacencyMatrix_; 
 
   53  registeredNodesName_t 
const registeredNodesName_; 
 
   54  inputMap_t 
const inputMap_; 
 
   55  outputMap_t 
const outputMap_; 
 
   69      report_t 
const &report,
 
   70      adjacencyMatrix_t 
const &adjacencyMatrix,
 
   71      registeredNodesName_t 
const ®isteredNodesName,
 
   72      inputMap_t 
const &inputMap,
 
   73      outputMap_t 
const &outputMap)
 
   77        adjacencyMatrix_(adjacencyMatrix),
 
   78        registeredNodesName_(registeredNodesName),
 
   80        outputMap_(outputMap) {}
 
   83  constexpr virtual ~Defroster() = 
default;
 
   87  [[nodiscard]] std::string graphName()
 const { 
return std::string(name_.data()); }
 
   91  [[nodiscard]] 
constexpr bool isValid()
 const { 
return isValid_; }
 
   95  [[nodiscard]] std::string report()
 const { 
return std::string(report_.data()); }
 
  105  template<
class ...Args>
 
  106  auto map(Args... args)
 const {
 
  107    if constexpr (
sizeof...(args) > 0 && 
sizeof...(args) % 2 != 0) {
 
  108      throw std::runtime_error(
 
  109          "The map function only accepts an even number of parameters as follows: name1, dynNode1, name2, dynNode2...");
 
  111    std::set<std::string> validatedNames{};
 
  112    auto [names, dynNodes] = validateAndSplit(validatedNames, args...);
 
  113    return generateGraph(names, dynNodes);
 
  126  template<
class NodeName, tool::HedgehogConnectableNode Node, 
class ...Args>
 
  127  requires std::is_convertible_v<NodeName, std::string>
 
  128  auto validateAndSplit(
 
  129      std::set<std::string> &setName,
 
  130      NodeName 
const &nodeName, std::shared_ptr<Node> node, Args... args)
 const {
 
  131    bool nameFound = 
false;
 
  132    std::string name = nodeName;
 
  133    for (
size_t nameId = 0; nameId < registeredNodesName_.size() && !nameFound; ++nameId) {
 
  134      if (std::string(registeredNodesName_.at(nameId).data()) == name) { nameFound = 
true; }
 
  137      std::ostringstream oss;
 
  138      oss << 
"The node name identifier \"" << name
 
  139          << 
"\" has not been found in the list of names identifier of static nodes.";
 
  140      throw std::runtime_error(oss.str());
 
  142      if (setName.insert(name).second == 
false) {
 
  143        std::ostringstream oss;
 
  144        oss << 
"The node name identifier \"" << name << 
"\" has already been used to map a dynamic node.";
 
  145        throw std::runtime_error(oss.str());
 
  147      if constexpr (
sizeof...(args) > 0) {
 
  148        auto [names, dynNodes] = validateAndSplit(setName, args...);
 
  149        std::vector<std::string> newNames{nodeName};
 
  150        newNames.insert(newNames.end(), names.cbegin(), names.cend());
 
  151        return std::make_pair(
 
  153            std::tuple_cat(std::tuple<std::shared_ptr<Node>>{node}, dynNodes)
 
  156        if (registeredNodesName_.size() != setName.size()) {
 
  157          std::ostringstream oss;
 
  158          oss << 
"There are static nodes that are not mapped.";
 
  159          throw std::runtime_error(oss.str());
 
  161        return std::make_pair(
 
  162            std::vector<std::string>{nodeName},
 
  163            std::tuple<std::shared_ptr<Node>>{node}
 
  175  template<
class T, 
class U, 
class ...Args>
 
  176  auto validateAndSplit(std::set<std::string> &, T 
const &, U 
const &, Args...)
 const {
 
  177    std::ostringstream oss;
 
  178    oss << 
"The map function has not the rights type, the sequence of types " << hh::tool::typeToStr<T>() << 
" " 
  179        << hh::tool::typeToStr<U>()
 
  180        << 
" has been found";
 
  181    throw std::runtime_error(oss.str());
 
  189  template<
class DynamicNodes>
 
  190  auto generateGraph(std::vector<std::string> 
const &dynamicNameIds,
 
  191                     DynamicNodes 
const &dynamicNodes)
 const {
 
  192    auto graph = std::make_shared<DynGraphType>(this->graphName());
 
  193    std::vector<typename hh_cx::tool::UniqueVariantFromTuple_t<DynamicNodes>> dynamicNodesVariant;
 
  194    populateVariants(dynamicNodes, dynamicNodesVariant);
 
  197    setInputNodes<DynamicNodes>(graph, dynamicNameIds, dynamicNodesVariant);
 
  200    setOutputNodes<DynamicNodes>(graph, dynamicNameIds, dynamicNodesVariant);
 
  203    setEdges<DynamicNodes>(graph, dynamicNameIds, dynamicNodesVariant);
 
  213  template<
class DynamicNodes>
 
  215      std::shared_ptr<DynGraphType> graph,
 
  216      std::vector<std::string> 
const &dynamicNameIds,
 
  217      std::vector<
typename hh_cx::tool::UniqueVariantFromTuple_t<DynamicNodes>> dynamicNodesVariant)
 const {
 
  218    using GraphInputsTuple = 
typename DynGraphType::inputs_t;
 
  221    for (
auto const &inputNodeNameToTypes : inputMap_.mapNodeNameToTypeNames()) {
 
  223      auto staticNameId = inputNodeNameToTypes.first;
 
  224      auto positionDynNode =
 
  226              dynamicNameIds.begin(),
 
  227              std::find(dynamicNameIds.begin(), dynamicNameIds.end(), staticNameId)
 
  229      auto dynamicNode = dynamicNodesVariant.at(positionDynNode);
 
  231      std::visit([&](
auto const &node) {
 
  233        using IntersectionInputTypes =
 
  234            hh::tool::Intersect_t<GraphInputsTuple, 
typename std::remove_reference_t<
decltype(*node)>::inputs_t>;
 
  236        for (
auto const &typeName : inputNodeNameToTypes.second) {
 
  238          if (isTypeNameInTuple<IntersectionInputTypes>(
 
  239              typeName, std::make_index_sequence<std::tuple_size_v<IntersectionInputTypes>>{})
 
  242            setNodeAsGraphInput<IntersectionInputTypes>(
 
  243                typeName, node, graph, std::make_index_sequence<std::tuple_size_v<IntersectionInputTypes>>{}
 
  247            std::ostringstream oss;
 
  248            oss << 
"Problem during mapping: the node " << node->name() << 
" cannot be set as input of the graph " <<
 
  249                graphName() << 
" for the type " << typeName;
 
  250            throw std::runtime_error(oss.str());
 
  262  template<
class DynamicNodes>
 
  264      std::shared_ptr<DynGraphType> graph,
 
  265      std::vector<std::string> 
const &dynamicNameIds,
 
  266      std::vector<
typename hh_cx::tool::UniqueVariantFromTuple_t<DynamicNodes>> dynamicNodesVariant)
 const {
 
  267    using GraphOutputsTuple = 
typename DynGraphType::outputs_t;
 
  269    for (
auto const &outputNodeNameToTypes : outputMap_.mapNodeNameToTypeNames()) {
 
  271      auto staticNameId = outputNodeNameToTypes.first;
 
  272      auto positionDynNode =
 
  274              dynamicNameIds.begin(),
 
  275              std::find(dynamicNameIds.begin(), dynamicNameIds.end(), staticNameId)
 
  277      auto dynamicNode = dynamicNodesVariant.at(positionDynNode);
 
  279      std::visit([&](
auto const &node) {
 
  281        using IntersectionOutputTypes =
 
  282            hh::tool::Intersect_t<GraphOutputsTuple, 
typename std::remove_reference_t<
decltype(*node)>::outputs_t>;
 
  284        for (
auto const &typeName : outputNodeNameToTypes.second) {
 
  286          if (isTypeNameInTuple<IntersectionOutputTypes>(
 
  287              typeName, std::make_index_sequence<std::tuple_size_v<IntersectionOutputTypes>>{})
 
  290            setNodeAsGraphOutput<IntersectionOutputTypes>(
 
  291                typeName, node, graph, std::make_index_sequence<std::tuple_size_v<IntersectionOutputTypes>>{}
 
  295            std::ostringstream oss;
 
  296            oss << 
"Problem during mapping: the node " << node->name() << 
" cannot be set as input of the graph " <<
 
  297                graphName() << 
" for the type " << typeName;
 
  298            throw std::runtime_error(oss.str());
 
  310  template<
class DynamicNodes>
 
  312      std::shared_ptr<DynGraphType> graph,
 
  313      std::vector<std::string> 
const &dynamicNameIds,
 
  314      std::vector<
typename hh_cx::tool::UniqueVariantFromTuple_t<DynamicNodes>> dynamicNodesVariant)
 const {
 
  317    for (
size_t senderId = 0; senderId < adjacencyMatrix_.size(); ++senderId) {
 
  319      auto staticSenderNodeNameId = std::string(registeredNodesName_.at(senderId).data());
 
  321      auto positionSenderDynNode =
 
  323              dynamicNameIds.begin(),
 
  324              std::find(dynamicNameIds.begin(), dynamicNameIds.end(), staticSenderNodeNameId)
 
  326      auto dynamicSenderNodeVariant = dynamicNodesVariant.at(positionSenderDynNode);\
 
  328      std::visit([&](
auto const &dynamicSenderNode) {
 
  330        for (
size_t receiverId = 0; receiverId < adjacencyMatrix_.at(senderId).size(); ++receiverId) {
 
  332          auto staticReceiverNodeNameId = std::string(registeredNodesName_.at(receiverId).data());
 
  334          auto positionReceiverDynNode =
 
  336                  dynamicNameIds.begin(),
 
  337                  std::find(dynamicNameIds.begin(), dynamicNameIds.end(), staticReceiverNodeNameId)
 
  339          auto dynamicReceiverNodeVariant = dynamicNodesVariant.at(positionReceiverDynNode);
 
  341          std::visit([&](
auto const &dynamicReceiverNode) {
 
  343            using commonTypesDynamicNodes =
 
  345                    typename std::remove_reference_t<
decltype(*dynamicSenderNode)>::outputs_t,
 
  346                    typename std::remove_reference_t<
decltype(*dynamicReceiverNode)>::inputs_t>;
 
  349            for (
size_t typeId = 0; typeId < adjacencyMatrix_.at(senderId).at(receiverId).size(); ++typeId) {
 
  350              auto typeName = std::string(adjacencyMatrix_.at(senderId).at(receiverId).at(typeId).data());
 
  351              if (!typeName.empty()) {
 
  353                if (isTypeNameInTuple<commonTypesDynamicNodes>(
 
  354                    typeName, std::make_index_sequence<std::tuple_size_v<commonTypesDynamicNodes>>{})
 
  357                  setEdge<commonTypesDynamicNodes>(
 
  362                      std::make_index_sequence<std::tuple_size_v<commonTypesDynamicNodes>>{}
 
  366                  std::ostringstream oss;
 
  368                      << 
"Problem during mapping: the node " << dynamicSenderNode->name()
 
  369                      << 
" cannot be set linked to " << dynamicReceiverNode->name()
 
  370                      << 
" for the type " << typeName;
 
  371                  throw std::runtime_error(oss.str());
 
  375          }, dynamicReceiverNodeVariant);
 
  377      }, dynamicSenderNodeVariant);
 
  387  template<
size_t Position = 0, 
class Tuple, 
class VectorVariant>
 
  388  void populateVariants(Tuple 
const &tup, VectorVariant &vectorVariant)
 const {
 
  389    if constexpr (Position < std::tuple_size_v<Tuple>) {
 
  390      vectorVariant.emplace_back(std::get<Position>(tup));
 
  391      populateVariants<Position + 1, Tuple, VectorVariant>(tup, vectorVariant);
 
  403  template<
class TupleOfTypes, 
class NodeType, 
class GraphType, 
size_t... Indices>
 
  404  void setNodeAsGraphInput(std::string 
const &typeName,
 
  407                           std::index_sequence<Indices...>)
 const {
 
  408    (setNodeAsGraphInputType<std::tuple_element_t<Indices, TupleOfTypes>>(typeName, node, graph), ...);
 
  418  template<
class T, 
class NodeType, 
class GraphType>
 
  419  void setNodeAsGraphInputType(std::string 
const &typeName, NodeType &node, GraphType &graph)
 const {
 
  420    if (hh::tool::typeToStr<T>() == typeName) { graph->template input<T>(node); }
 
  431  template<
class TupleOfTypes, 
class NodeType, 
class GraphType, 
size_t... Indices>
 
  432  void setNodeAsGraphOutput(std::string 
const &typeName,
 
  435                            std::index_sequence<Indices...>)
 const {
 
  436    (setNodeAsGraphOutputType<std::tuple_element_t<Indices, TupleOfTypes>>(typeName, node, graph), ...);
 
  446  template<
class T, 
class NodeType, 
class GraphType>
 
  447  void setNodeAsGraphOutputType(std::string 
const &typeName, NodeType &node, GraphType &graph)
 const {
 
  448    if (hh::tool::typeToStr<T>() == typeName) { graph->template output<T>(node); }
 
  461  template<
class TupleOfTypes, 
class SenderNodeType, 
class ReceiverNodeType, 
class GraphType, 
size_t... Indices>
 
  462  void setEdge(std::string 
const &typeName,
 
  463               SenderNodeType &sender,
 
  464               ReceiverNodeType &receiver,
 
  466               std::index_sequence<Indices...>)
 const {
 
  467    (setEdgeType<std::tuple_element_t<Indices, TupleOfTypes>>(typeName, sender, receiver, graph), ...);
 
  479  template<
class T, 
class SenderNodeType, 
class ReceiverNodeType, 
class GraphType>
 
  480  void setEdgeType(std::string 
const &typeName,
 
  481                   SenderNodeType &sender,
 
  482                   ReceiverNodeType &receiver,
 
  483                   GraphType &graph)
 const {
 
  484    if (hh::tool::typeToStr<T>() == typeName) { graph->template edge<T>(sender, receiver); }
 
  492  template<
class TupleOfTypes, 
size_t... Indices>
 
  493  [[nodiscard]] 
bool isTypeNameInTuple(std::string 
const &typeName, std::index_sequence<Indices...>)
 const {
 
  494    return (isSameTypeName<std::tuple_element_t<Indices, TupleOfTypes>>(typeName) || ...);
 
  502  [[nodiscard]] 
inline bool isSameTypeName(std::string 
const &typeName)
 const {
 
  503    return hh::tool::typeToStr<T>() == typeName;
 
  611template<auto FctGraph>
 
  612constexpr auto createDefroster() {
 
  614  auto graph = FctGraph();
 
  616      std::is_base_of_v<hh_cx::Graph<
typename decltype(graph)::dynamic_node_t>, 
decltype(graph)>,
 
  617      "The callable given to the createDefroster function should 1) be a constexpr function and 2) return a valid hh_cx::Graph");
 
  618  using DynGraphType = 
typename decltype(graph)::dynamic_node_t;
 
  623      graphNameSize = FctGraph().name().size() + 1,
 
  624      reportSize = FctGraph().report().size() + 1,
 
  625      numberNodes = FctGraph().numberNodesRegistered(),
 
  626      maxNodeNameSize = FctGraph().maxNodeNameSize() + 1,
 
  627      maxNumberEdges = FctGraph().maxEdgeSizes().first,
 
  628      maxEdgeTypeSize = FctGraph().maxEdgeSizes().second,
 
  629      nbTypesInput = FctGraph().inputNodes().nbTypes(),
 
  630      maxTypeSizeInput = FctGraph().inputNodes().maxTypeSize() + 1,
 
  631      maxNumberNodesInput = FctGraph().inputNodes().maxNumberNodes(),
 
  632      maxSizeNameInput = FctGraph().inputNodes().maxSizeName() + 1,
 
  633      nbTypesOutput = FctGraph().outputNodes().nbTypes(),
 
  634      maxTypeSizeOutput = FctGraph().outputNodes().maxTypeSize() + 1,
 
  635      maxNumberNodesOutput = FctGraph().outputNodes().maxNumberNodes(),
 
  636      maxSizeNameOutput = FctGraph().outputNodes().maxSizeName() + 1;
 
  639  auto const &graphName = graph.name();
 
  640  std::array<char, graphNameSize> nameArray;
 
  641  std::copy(graphName.cbegin(), graphName.cend(), nameArray.begin());
 
  642  nameArray.at(graphName.size()) = 
'\0';
 
  645  bool isGraphValid = graph.isValid();
 
  648  auto const &reportString = graph.report();
 
  649  std::array<char, reportSize> reportArray{};
 
  650  std::copy(reportString.begin(), reportString.end(), reportArray.begin());
 
  651  reportArray.at(reportString.size()) = 
'\0';
 
  654  auto const &adjacencyMatrix = graph.adjacencyMatrix();
 
  655  std::array<std::array<std::array<std::array<char, maxEdgeTypeSize>, maxNumberEdges>, numberNodes>, numberNodes>
 
  656      adjacencyMatrixArray{};
 
  658  for (
size_t senderId = 0; senderId < adjacencyMatrix.size(); ++senderId) {
 
  659    for (
size_t receiverId = 0; receiverId < adjacencyMatrix.at(senderId).size(); ++receiverId) {
 
  660      for (
size_t typeId = 0; typeId < adjacencyMatrix.at(senderId).at(receiverId).size(); ++typeId) {
 
  662            adjacencyMatrix.at(senderId).at(receiverId).at(typeId).cbegin(),
 
  663            adjacencyMatrix.at(senderId).at(receiverId).at(typeId).cend(),
 
  664            adjacencyMatrixArray.at(senderId).at(receiverId).at(typeId).begin()
 
  671  std::array<std::array<char, maxNodeNameSize>, numberNodes> registeredNodesNameArray;
 
  672  auto const ®isteredNodesName = graph.registeredNodesName();
 
  673  for (
size_t nodeId = 0; nodeId < numberNodes; ++nodeId) {
 
  675        registeredNodesName.at(nodeId).cbegin(), registeredNodesName.at(nodeId).cend(),
 
  676        registeredNodesNameArray.at(nodeId).begin()
 
  678    registeredNodesNameArray.at(nodeId).at(registeredNodesName.at(nodeId).size()) = 
'\0';
 
  682  auto inputTypeNodesMap = graph.inputNodes();
 
  683  hh_cx::tool::TypeNodesMapArray<nbTypesInput, maxTypeSizeInput, maxNumberNodesInput, maxSizeNameInput>
 
  684      inputTypeNodesMapArray{};
 
  685  for (
size_t typeId = 0; typeId < inputTypeNodesMap.nbTypes(); ++typeId) {
 
  687        inputTypeNodesMap.types().at(typeId).cbegin(), inputTypeNodesMap.types().at(typeId).cend(),
 
  688        inputTypeNodesMapArray.types().at(typeId).begin()
 
  690    for (
size_t nodeId = 0; nodeId < inputTypeNodesMap.nodesName().at(typeId).size(); ++nodeId) {
 
  692          inputTypeNodesMap.nodesName().at(typeId).at(nodeId).cbegin(),
 
  693          inputTypeNodesMap.nodesName().at(typeId).at(nodeId).cend(),
 
  694          inputTypeNodesMapArray.nodes().at(typeId).at(nodeId).begin()
 
  700  auto outputTypeNodesMap = graph.outputNodes();
 
  701  hh_cx::tool::TypeNodesMapArray<nbTypesOutput, maxTypeSizeOutput, maxNumberNodesOutput, maxSizeNameOutput>
 
  702      outputTypeNodesMapArray{};
 
  703  for (
size_t typeId = 0; typeId < outputTypeNodesMap.nbTypes(); ++typeId) {
 
  705        outputTypeNodesMap.types().at(typeId).cbegin(), outputTypeNodesMap.types().at(typeId).cend(),
 
  706        outputTypeNodesMapArray.types().at(typeId).begin()
 
  708    for (
size_t nodeId = 0; nodeId < outputTypeNodesMap.nodesName().at(typeId).size(); ++nodeId) {
 
  710          outputTypeNodesMap.nodesName().at(typeId).at(nodeId).cbegin(),
 
  711          outputTypeNodesMap.nodesName().at(typeId).at(nodeId).cend(),
 
  712          outputTypeNodesMapArray.nodes().at(typeId).at(nodeId).begin()
 
  717  return hh_cx::Defroster<
 
  720      decltype(reportArray),
 
  721      decltype(adjacencyMatrixArray),
 
  722      decltype(registeredNodesNameArray),
 
  723      decltype(inputTypeNodesMapArray),
 
  724      decltype(outputTypeNodesMapArray)
 
  727      isGraphValid, reportArray,
 
  728      adjacencyMatrixArray, registeredNodesNameArray,
 
  729      inputTypeNodesMapArray, outputTypeNodesMapArray);
 
typename internals::Intersect< Tuple1, Tuple2 >::type Intersect_t
Helper getting the intersection of types between two type tuples.