Newer
Older
for (IOIndex_t outputIdx = 0; outputIdx < deletedNode->getOrderedChildren().size(); ++outputIdx) {
const auto val = std::make_pair(deletedNode, outputIdx);
const auto iter = std::find(mOutputNodes.cbegin(), mOutputNodes.cend(), val);
if (iter != mOutputNodes.cend()) {
// The first old (removed) output becomes the insertion point for newNode GraphView outputs
if (std::distance(newOutputsInsertionPoint, iter) <= 0) {
newOutputsInsertionPoint = mOutputNodes.erase(iter);
}
else {
mOutputNodes.erase(iter);
}
}
}
// Add parent node outputs that become GraphView output following the removal of the node
// Outputs addition order follows deletedNode inputs order
for (const std::shared_ptr<Node>& parent : deletedNode->getParents()) {
if (mNodes.find(parent) != mNodes.end()) {
IOIndex_t outputIdx = 0;
for (auto orderedChilds : parent->getOrderedChildren()) {
bool noInsideConnection = true;
for (auto ch_ptr : orderedChilds) {
if (mNodes.find(ch_ptr) != mNodes.end()) {
noInsideConnection = false;
break;
}
if (noInsideConnection) {
const auto val = std::make_pair(parent, outputIdx);
if (std::find(mOutputNodes.cbegin(), mOutputNodes.cend(), val) == mOutputNodes.cend()) {
newOutputsInsertionPoint = mOutputNodes.insert(newOutputsInsertionPoint, val);
newOutputsInsertionPoint = std::next(newOutputsInsertionPoint);
}
}
++outputIdx;
std::shared_ptr<Aidge::GraphView> Aidge::GraphView::cloneCallback(NodePtr(*cloneNode)(NodePtr)) const {
std::shared_ptr<GraphView> newGraph = std::make_shared<GraphView>(mName);
// Map for old node -> new node correspondance
std::map<NodePtr, NodePtr> oldToNewNodes;
for (const std::shared_ptr<Node> &node_ptr : mNodes) {
auto clonedNode = cloneNode(node_ptr);
if (clonedNode == nullptr) {
AIDGE_ASSERT(node_ptr->getChildren().size() <= 1, "deleted nodes in GraphView::clone() cannot have multiple children");
AIDGE_ASSERT(node_ptr->nbData() <= 1, "deleted nodes in GraphView::clone() cannot have multiple data input parents");
}
oldToNewNodes[node_ptr] = clonedNode;
// For each node, convert old node -> new node connections
for (auto &oldToNewNode : oldToNewNodes) {
if (oldToNewNode.second == nullptr) {
// Connect parent nodes. Nodes that were removed with cloneNode() are set to nullptr
size_t parentId = 0;
for (auto parent : oldToNewNode.first->inputs()) {
if (parent.first != nullptr) {
while (oldToNewNodes[parent.first] == nullptr) {
// Find next valid parent in line, going backward in the graph
AIDGE_INTERNAL_ASSERT(parent.first->getChildren().size() == 1);
const auto& parents = parent.first->dataInputs();
if (!parents.empty() && parents[0].first != nullptr // a valid parent exists
&& oldToNewNodes.find(parents[0].first) != oldToNewNodes.end()) // parent is in the GraphView
{
parent = parents[0];
}
else {
break;
}
if (oldToNewNodes[parent.first]) {
AIDGE_INTERNAL_ASSERT(oldToNewNodes[parent.first]->nbOutputs() == parent.first->nbOutputs());
oldToNewNodes[parent.first]->addChild(oldToNewNode.second, parent.second, parentId);
}
}
}
// Once connected, add each new nodes to new GraphView
// This has to be done in a second step to ensure that new GraphView inputs/outputs
// are properly set (otherwise, some node's inputs/outputs may be wrongly registered as
// GraphView inputs/outputs because not yet connected to other nodes)
if (oldToNewNodes[mRootNode] != nullptr) {
// Add root node first if is still exists!
newGraph->add(oldToNewNodes[mRootNode], false);
}
for (auto &oldToNewNode : oldToNewNodes) {
if (oldToNewNode.second == nullptr)
continue; // deleted node
newGraph->add(oldToNewNode.second, false);
}
// Update cloned graph inputs/outputs order to match initial graph order
auto newInputNodes = mInputNodes;
for (auto it = newInputNodes.begin(); it != newInputNodes.end(); ) {
// If input node was removed, find next valid input
while (oldToNewNodes[it->first] == nullptr) {
// Removed node should have only one connected output, otherwise cloning is invalid
AIDGE_INTERNAL_ASSERT(it->first->getChildren().size() <= 1);
if (it->first->getChildren().size() == 1) {
auto child = *it->first->getChildren().begin();
std::size_t inputIdx = 0;
for (auto parent : child->getParents()) {
if (parent == it->first) {
it->first = child;
it->second = inputIdx;
found = true;
break;
}
++inputIdx;
}
}
if (!found) {
break;
}
}
if (oldToNewNodes[it->first] == nullptr) {
it = newInputNodes.erase(it);
}
else {
it->first = oldToNewNodes[it->first];
}
newGraph->setOrderedInputs(newInputNodes);
auto newOutputNodes = mOutputNodes;
for (auto it = newOutputNodes.begin(); it != newOutputNodes.end(); ) {
// If output node was removed, find previous valid output
while (oldToNewNodes[it->first] == nullptr) {
// Removed node should have only one connected data input, otherwise cloning is invalid
if (!parents.empty() && parents[0].first != nullptr // a valid parent exists
&& oldToNewNodes.find(parents[0].first) != oldToNewNodes.end()) // parent is in the GraphView
{
*it = parents[0];
}
else {
break;
}
}
if (oldToNewNodes[it->first] == nullptr) {
it = newOutputNodes.erase(it);
}
else {
it->first = oldToNewNodes[it->first];
return newGraph;
}