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.