| 404 | } |
| 405 | |
| 406 | ElementVec GraphElement::topologicalSort() const |
| 407 | { |
| 408 | // Calculate a topological order of the children, using Kahn's algorithm |
| 409 | // to avoid recursion. |
| 410 | // |
| 411 | // Running time: O(numNodes + numEdges). |
| 412 | |
| 413 | const ElementVec& children = getChildren(); |
| 414 | |
| 415 | // Calculate in-degrees for all children. |
| 416 | std::unordered_map<ElementPtr, size_t> inDegree(children.size()); |
| 417 | std::deque<ElementPtr> childQueue; |
| 418 | for (ElementPtr child : children) |
| 419 | { |
| 420 | size_t connectionCount = 0; |
| 421 | for (size_t i = 0; i < child->getUpstreamEdgeCount(); ++i) |
| 422 | { |
| 423 | Edge upstreamEdge = child->getUpstreamEdge(i); |
| 424 | if (upstreamEdge) |
| 425 | { |
| 426 | if (upstreamEdge.getUpstreamElement()) |
| 427 | { |
| 428 | ElementPtr elem = upstreamEdge.getUpstreamElement()->getParent(); |
| 429 | if (elem == child->getParent()) |
| 430 | { |
| 431 | connectionCount++; |
| 432 | } |
| 433 | } |
| 434 | } |
| 435 | } |
| 436 | |
| 437 | inDegree[child] = connectionCount; |
| 438 | |
| 439 | // Enqueue children with in-degree 0. |
| 440 | if (connectionCount == 0) |
| 441 | { |
| 442 | childQueue.push_back(child); |
| 443 | } |
| 444 | } |
| 445 | |
| 446 | ElementVec result; |
| 447 | while (!childQueue.empty()) |
| 448 | { |
| 449 | // Pop the queue and add to topological order. |
| 450 | ElementPtr child = childQueue.front(); |
| 451 | childQueue.pop_front(); |
| 452 | result.push_back(child); |
| 453 | |
| 454 | // Find connected nodes and decrease their in-degree, |
| 455 | // adding node to the queue if in-degrees becomes 0. |
| 456 | if (child->isA<Node>()) |
| 457 | { |
| 458 | for (PortElementPtr port : child->asA<Node>()->getDownstreamPorts()) |
| 459 | { |
| 460 | const ElementPtr downstreamElem = port->isA<Output>() ? port : port->getParent(); |
| 461 | if (inDegree[downstreamElem] > 1) |
| 462 | { |
| 463 | inDegree[downstreamElem]--; |
no test coverage detected