Repository: bitcoin/bitcoin
File: src/txgraph.cpp (C++)

Code before:
        // Pick the lower-count root to become a child of the higher-count one.
        // See https://en.wikipedia.org/wiki/Disjoint-set_data_structure#Union_by_size.
        if (rep1->m_uf_count < rep2->m_uf_count) std::swap(rep1, rep2);
        rep2->m_uf_parent = rep1;
        // Add the statistics of arg2 (which is no longer a representative) to those of arg1 (which
        // is now the representative for both).
        rep1->m_uf_size += rep2->m_uf_size;
        rep1->m_uf_count += rep2->m_uf_count;
        return rep1;
    };

    /** Get iterator to TrimTxData entry for a given index. */
    auto locate_fn = [&](GraphIndex index) noexcept {
        auto it = std::lower_bound(trim_data.begin(), trim_data.end(), index, [](TrimTxData& elem, GraphIndex idx) noexcept {
            return elem.m_index < idx;
        });
        Assume(it != trim_data.end() && it->m_index == index);
        return it;
    };

    // For each group of to-be-merged Clusters.
    for (const auto& group_data : clusterset.m_group_data->m_groups) {
        trim_data.clear();
        trim_heap.clear();
        deps_by_child.clear();
        deps_by_parent.clear();

        // Gather trim data and implicit dependency data from all involved Clusters.
        auto cluster_span = std::span{clusterset.m_group_data->m_group_clusters}
                                .subspan(group_data.m_cluster_offset, group_data.m_cluster_count);
        uint64_t size{0};
        for (Cluster* cluster : cluster_span) {
            MakeAcceptable(*cluster, cluster->GetLevel(*this));
            size += cluster->AppendTrimData(trim_data, deps_by_child);
        }
        // If this group of Clusters does not violate any limits, continue to the next group.
        if (trim_data.size() <= m_max_cluster_count && size <= m_max_cluster_size) continue;
        // Sort the trim data by GraphIndex. In what follows, we will treat this sorted vector as
        // a map from GraphIndex to TrimTxData via locate_fn, and its ordering will not change
        // anymore.
        std::sort(trim_data.begin(), trim_data.end(), [](auto& a, auto& b) noexcept { return a.m_index < b.m_index; });

        // Add the explicitly added dependencies to deps_by_child.
        deps_by_child.insert(deps_by_child.end(),
                             clusterset.m_deps_to_add.begin() + group_data.m_deps_offset,
                             clusterset.m_deps_to_add.begin() + group_data.m_deps_offset + group_data.m_deps_count);

        // Sort deps_by_child by child transaction GraphIndex. The order will not be changed
        // anymore after this.
        std::sort(deps_by_child.begin(), deps_by_child.end(), [](auto& a, auto& b) noexcept { return a.second < b.second; });
        // Fill m_parents_count and m_parents_offset in trim_data, as well as m_deps_left, and

Review comment (suggestion):
28ff1be7b5cae0f0674e0d0045da0eee5e9adc6a

Let's me be more confident the cluster wasnt in a needs split state or something.

```Suggestion
            MakeAcceptable(*cluster, cluster->GetLevel(*this));
            Assume(cluster->IsAcceptable());
```

Code after:
        rep1->m_uf_count += rep2->m_uf_count;
        return rep1;
    };

    /** Get iterator to TrimTxData entry for a given index. */
    auto locate_fn = [&](GraphIndex index) noexcept {
        auto it = std::lower_bound(trim_data.begin(), trim_data.end(), index, [](TrimTxData& elem, GraphIndex idx) noexcept {
            return elem.m_index < idx;
        });
        Assume(it != trim_data.end() && it->m_index == index);
        return it;
    };

    // For each group of to-be-merged Clusters.
    for (const auto& group_data : clusterset.m_group_data->m_groups) {
        trim_data.clear();
        trim_heap.clear();
        deps_by_child.clear();
        deps_by_parent.clear();

        // Gather trim data and implicit dependency data from all involved Clusters.
        auto cluster_span = std::span{clusterset.m_group_data->m_group_clusters}
                                .subspan(group_data.m_cluster_offset, group_data.m_cluster_count);
        uint64_t size{0};
        for (Cluster* cluster : cluster_span) {
            MakeAcceptable(*cluster, cluster->GetLevel(*this));
            size += cluster->AppendTrimData(trim_data, deps_by_child);
        }
        // If this group of Clusters does not violate any limits, continue to the next group.
        if (trim_data.size() <= m_max_cluster_count && size <= m_max_cluster_size) continue;
        // Sort the trim data by GraphIndex. In what follows, we will treat this sorted vector as
        // a map from GraphIndex to TrimTxData via locate_fn, and its ordering will not change
        // anymore.
        std::sort(trim_data.begin(), trim_data.end(), [](auto& a, auto& b) noexcept { return a.m_index < b.m_index; });

        // Add the explicitly added dependencies to deps_by_child.
        deps_by_child.insert(deps_by_child.end(),
                             clusterset.m_deps_to_add.begin() + group_data.m_deps_offset,
                             clusterset.m_deps_to_add.begin() + group_data.m_deps_offset + group_data.m_deps_count);

        // Sort deps_by_child by child transaction GraphIndex. The order will not be changed
        // anymore after this.
        std::sort(deps_by_child.begin(), deps_by_child.end(), [](auto& a, auto& b) noexcept { return a.second < b.second; });
        // Fill m_parents_count and m_parents_offset in trim_data, as well as m_deps_left, and
        // initially populate trim_heap. Because of the sort above, all dependencies involving the
        // same child are grouped together, so a single linear scan suffices.
        auto deps_it = deps_by_child.begin();
        for (auto trim_it = trim_data.begin(); trim_it != trim_data.end(); ++trim_it) {
            trim_it->m_parent_offset = deps_it - deps_by_child.begin();
            trim_it->m_deps_left = 0;
            while (deps_it != deps_by_child.end() && deps_it->second == trim_it->m_index) {