@@ -453,6 +453,8 @@ class TxGraphImpl final : public TxGraph
453453 std::vector<Ref*> GetCluster (const Ref& arg, bool main_only = false ) noexcept final ;
454454 std::vector<Ref*> GetAncestors (const Ref& arg, bool main_only = false ) noexcept final ;
455455 std::vector<Ref*> GetDescendants (const Ref& arg, bool main_only = false ) noexcept final ;
456+ std::vector<Ref*> GetAncestorsUnion (std::span<const Ref* const > args, bool main_only = false ) noexcept final ;
457+ std::vector<Ref*> GetDescendantsUnion (std::span<const Ref* const > args, bool main_only = false ) noexcept final ;
456458 GraphIndex GetTransactionCount (bool main_only = false ) noexcept final ;
457459 bool IsOversized (bool main_only = false ) noexcept final ;
458460 std::strong_ordering CompareMainOrder (const Ref& a, const Ref& b) noexcept final ;
@@ -1581,6 +1583,70 @@ std::vector<TxGraph::Ref*> TxGraphImpl::GetDescendants(const Ref& arg, bool main
15811583 return ret;
15821584}
15831585
1586+ std::vector<TxGraph::Ref*> TxGraphImpl::GetAncestorsUnion (std::span<const Ref* const > args, bool main_only) noexcept
1587+ {
1588+ // Apply all dependencies, as the result might be incorrect otherwise.
1589+ size_t level = GetSpecifiedLevel (main_only);
1590+ ApplyDependencies (level);
1591+ // Ancestry cannot be known if unapplied dependencies remain.
1592+ Assume (GetClusterSet (level).m_deps_to_add .empty ());
1593+
1594+ // Translate args to matches.
1595+ std::vector<std::pair<Cluster*, DepGraphIndex>> matches;
1596+ matches.reserve (args.size ());
1597+ for (auto arg : args) {
1598+ // Skip empty Refs.
1599+ if (GetRefGraph (*arg) == nullptr ) continue ;
1600+ Assume (GetRefGraph (*arg) == this );
1601+ // Find the Cluster the argument is in, and skip if none is found.
1602+ auto cluster = FindCluster (GetRefIndex (*arg), level);
1603+ if (cluster == nullptr ) continue ;
1604+ // Append to matches.
1605+ matches.emplace_back (cluster, m_entries[GetRefIndex (*arg)].m_locator [cluster->m_level ].index );
1606+ }
1607+ // Group by Cluster.
1608+ std::sort (matches.begin (), matches.end (), [](auto & a, auto & b) noexcept { return std::less{}(a.first , b.first ); });
1609+ // Dispatch to the Clusters.
1610+ std::span match_span (matches);
1611+ std::vector<TxGraph::Ref*> ret;
1612+ while (!match_span.empty ()) {
1613+ match_span.front ().first ->GetAncestorRefs (*this , match_span, ret);
1614+ }
1615+ return ret;
1616+ }
1617+
1618+ std::vector<TxGraph::Ref*> TxGraphImpl::GetDescendantsUnion (std::span<const Ref* const > args, bool main_only) noexcept
1619+ {
1620+ // Apply all dependencies, as the result might be incorrect otherwise.
1621+ size_t level = GetSpecifiedLevel (main_only);
1622+ ApplyDependencies (level);
1623+ // Ancestry cannot be known if unapplied dependencies remain.
1624+ Assume (GetClusterSet (level).m_deps_to_add .empty ());
1625+
1626+ // Translate args to matches.
1627+ std::vector<std::pair<Cluster*, DepGraphIndex>> matches;
1628+ matches.reserve (args.size ());
1629+ for (auto arg : args) {
1630+ // Skip empty Refs.
1631+ if (GetRefGraph (*arg) == nullptr ) continue ;
1632+ Assume (GetRefGraph (*arg) == this );
1633+ // Find the Cluster the argument is in, and skip if none is found.
1634+ auto cluster = FindCluster (GetRefIndex (*arg), level);
1635+ if (cluster == nullptr ) continue ;
1636+ // Append to matches.
1637+ matches.emplace_back (cluster, m_entries[GetRefIndex (*arg)].m_locator [cluster->m_level ].index );
1638+ }
1639+ // Group by Cluster.
1640+ std::sort (matches.begin (), matches.end (), [](auto & a, auto & b) noexcept { return std::less{}(a.first , b.first ); });
1641+ // Dispatch to the Clusters.
1642+ std::span match_span (matches);
1643+ std::vector<TxGraph::Ref*> ret;
1644+ while (!match_span.empty ()) {
1645+ match_span.front ().first ->GetDescendantRefs (*this , match_span, ret);
1646+ }
1647+ return ret;
1648+ }
1649+
15841650std::vector<TxGraph::Ref*> TxGraphImpl::GetCluster (const Ref& arg, bool main_only) noexcept
15851651{
15861652 // Return the empty vector if the Ref is empty (which may be indicative of the transaction
0 commit comments