| 2501 | } |
| 2502 | |
| 2503 | std::vector<TxGraph::Ref*> TxGraphImpl::GetDescendantsUnion(std::span<const Ref* const> args, Level level_select) noexcept |
| 2504 | { |
| 2505 | // Apply all dependencies, as the result might be incorrect otherwise. |
| 2506 | size_t level = GetSpecifiedLevel(level_select); |
| 2507 | ApplyDependencies(level); |
| 2508 | // Ancestry cannot be known if unapplied dependencies remain. |
| 2509 | Assume(GetClusterSet(level).m_deps_to_add.empty()); |
| 2510 | |
| 2511 | // Translate args to matches. |
| 2512 | std::vector<std::pair<Cluster*, DepGraphIndex>> matches; |
| 2513 | matches.reserve(args.size()); |
| 2514 | for (auto arg : args) { |
| 2515 | Assume(arg); |
| 2516 | // Skip empty Refs. |
| 2517 | if (GetRefGraph(*arg) == nullptr) continue; |
| 2518 | Assume(GetRefGraph(*arg) == this); |
| 2519 | // Find the Cluster the argument is in, and skip if none is found. |
| 2520 | auto [cluster, cluster_level] = FindClusterAndLevel(GetRefIndex(*arg), level); |
| 2521 | if (cluster == nullptr) continue; |
| 2522 | // Append to matches. |
| 2523 | matches.emplace_back(cluster, m_entries[GetRefIndex(*arg)].m_locator[cluster_level].index); |
| 2524 | } |
| 2525 | // Group by Cluster. |
| 2526 | std::ranges::sort(matches, [](auto& a, auto& b) noexcept { return CompareClusters(a.first, b.first) < 0; }); |
| 2527 | // Dispatch to the Clusters. |
| 2528 | std::span match_span(matches); |
| 2529 | std::vector<TxGraph::Ref*> ret; |
| 2530 | while (!match_span.empty()) { |
| 2531 | match_span.front().first->GetDescendantRefs(*this, match_span, ret); |
| 2532 | } |
| 2533 | return ret; |
| 2534 | } |
| 2535 | |
| 2536 | std::vector<TxGraph::Ref*> TxGraphImpl::GetCluster(const Ref& arg, Level level_select) noexcept |
| 2537 | { |