From 1aa78cdab6bc8ecd4448b1b75ee3181ee8f3f519 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Wed, 25 Feb 2026 13:11:01 -0500 Subject: [PATCH] clusterlin: adopt STL ranges algorithms (refactor) --- src/cluster_linearize.h | 9 ++++---- src/test/fuzz/txgraph.cpp | 15 +++++++------- src/txgraph.cpp | 43 ++++++++++++++++++++------------------- 3 files changed, 35 insertions(+), 32 deletions(-) diff --git a/src/cluster_linearize.h b/src/cluster_linearize.h index 1bf3d475f10..4da4703fe86 100644 --- a/src/cluster_linearize.h +++ b/src/cluster_linearize.h @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -316,7 +317,7 @@ public: { DepGraphIndex old_len = list.size(); for (auto i : select) list.push_back(i); - std::sort(list.begin() + old_len, list.end(), [&](DepGraphIndex a, DepGraphIndex b) noexcept { + std::ranges::sort(std::span{list}.subspan(old_len), [&](DepGraphIndex a, DepGraphIndex b) noexcept { const auto a_anc_count = entries[a].ancestors.Count(); const auto b_anc_count = entries[b].ancestors.Count(); if (a_anc_count != b_anc_count) return a_anc_count < b_anc_count; @@ -1618,7 +1619,7 @@ public: for (auto chunk_idx : m_chunk_idxs) { ret.push_back(m_set_info[chunk_idx].feerate); } - std::sort(ret.begin(), ret.end(), std::greater>{}); + std::ranges::sort(ret, std::greater>{}); return ret; } @@ -1647,8 +1648,8 @@ public: } } } - std::sort(expected_dependencies.begin(), expected_dependencies.end()); - std::sort(all_dependencies.begin(), all_dependencies.end()); + std::ranges::sort(expected_dependencies); + std::ranges::sort(all_dependencies); assert(expected_dependencies == all_dependencies); // diff --git a/src/test/fuzz/txgraph.cpp b/src/test/fuzz/txgraph.cpp index e3eb0dd18fe..88091fb00ba 100644 --- a/src/test/fuzz/txgraph.cpp +++ b/src/test/fuzz/txgraph.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -433,7 +434,7 @@ FUZZ_TARGET(txgraph) assert(num_tx == sim.GetTransactionCount()); // Sort by feerate only, since violating topological constraints within same-feerate // chunks won't affect diagram comparisons. - std::sort(chunk_feerates.begin(), chunk_feerates.end(), std::greater>{}); + std::ranges::sort(chunk_feerates, std::greater>{}); return chunk_feerates; }; @@ -1006,7 +1007,7 @@ FUZZ_TARGET(txgraph) for (auto i : cluster) sizes.push_back(top_sim.graph.FeeRate(i).size); auto sum_sizes = std::accumulate(sizes.begin(), sizes.end(), uint64_t{0}); // Sort from large to small. - std::sort(sizes.begin(), sizes.end(), std::greater{}); + std::ranges::sort(sizes, std::greater{}); // In the worst case, only the smallest transactions are removed. while (sizes.size() > max_cluster_count || sum_sizes > max_cluster_size) { sum_sizes -= sizes.back(); @@ -1075,8 +1076,8 @@ FUZZ_TARGET(txgraph) auto cmp = [&](SimTxGraph::Pos a, SimTxGraph::Pos b) noexcept { return real->CompareMainOrder(*sims[0].GetRef(a), *sims[0].GetRef(b)) < 0; }; - std::sort(vec1.begin(), vec1.end(), cmp); - std::sort(vec2.begin(), vec2.end(), cmp); + std::ranges::sort(vec1, cmp); + std::ranges::sort(vec2, cmp); // Verify the resulting orderings are identical. This could only fail if the ordering was // not total. @@ -1199,7 +1200,7 @@ FUZZ_TARGET(txgraph) auto cmp_redo = [&](SimTxGraph::Pos a, SimTxGraph::Pos b) noexcept { return real_redo->CompareMainOrder(*txobjects_redo[a], *txobjects_redo[b]) < 0; }; - std::sort(vec_redo.begin(), vec_redo.end(), cmp_redo); + std::ranges::sort(vec_redo, cmp_redo); // Compare with the ordering we got from real. assert(vec1 == vec_redo); } @@ -1274,8 +1275,8 @@ FUZZ_TARGET(txgraph) // std::set_difference can be used on them below. The exact ordering does not matter // here, but it has to be consistent with the one used in main_real_diagram and // stage_real_diagram). - std::sort(main_cmp_diagram.begin(), main_cmp_diagram.end(), std::greater>{}); - std::sort(stage_cmp_diagram.begin(), stage_cmp_diagram.end(), std::greater>{}); + std::ranges::sort(main_cmp_diagram, std::greater>{}); + std::ranges::sort(stage_cmp_diagram, std::greater>{}); // Find the chunks that appear in main_diagram but are missing from main_cmp_diagram. // This is allowed, because GetMainStagingDiagrams omits clusters in main unaffected // by staging. diff --git a/src/txgraph.cpp b/src/txgraph.cpp index 8993947a9fe..39a8a8814ab 100644 --- a/src/txgraph.cpp +++ b/src/txgraph.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -1212,8 +1213,8 @@ std::vector TxGraphImpl::GetConflicts() const noexcept } } // Deduplicate the result (the same Cluster may appear multiple times). - std::sort(ret.begin(), ret.end(), [](Cluster* a, Cluster* b) noexcept { return CompareClusters(a, b) < 0; }); - ret.erase(std::unique(ret.begin(), ret.end()), ret.end()); + std::ranges::sort(ret, [](Cluster* a, Cluster* b) noexcept { return CompareClusters(a, b) < 0; }); + ret.erase(std::ranges::unique(ret).begin(), ret.end()); return ret; } @@ -1558,7 +1559,7 @@ void SingletonClusterImpl::Merge(TxGraphImpl&, int, Cluster&) noexcept void GenericClusterImpl::ApplyDependencies(TxGraphImpl& graph, int level, std::span> to_apply) noexcept { // Sort the list of dependencies to apply by child, so those can be applied in batch. - std::sort(to_apply.begin(), to_apply.end(), [](auto& a, auto& b) { return a.second < b.second; }); + std::ranges::sort(to_apply, [](auto& a, auto& b) { return a.second < b.second; }); // Iterate over groups of to-be-added dependencies with the same child. auto it = to_apply.begin(); while (it != to_apply.end()) { @@ -1720,7 +1721,7 @@ void TxGraphImpl::ApplyRemovals(int up_to_level) noexcept } } // Group the set of to-be-removed entries by Cluster::m_sequence. - std::sort(to_remove.begin(), to_remove.end(), [&](GraphIndex a, GraphIndex b) noexcept { + std::ranges::sort(to_remove, [&](GraphIndex a, GraphIndex b) noexcept { Cluster* cluster_a = m_entries[a].m_locator[level].cluster; Cluster* cluster_b = m_entries[b].m_locator[level].cluster; return CompareClusters(cluster_a, cluster_b) < 0; @@ -1791,7 +1792,7 @@ void TxGraphImpl::Compact() noexcept // ones get processed first. This means earlier-processed GraphIndexes will not cause moving of // later-processed ones during the "swap with end of m_entries" step below (which might // invalidate them). - std::sort(m_unlinked.begin(), m_unlinked.end(), std::greater{}); + std::ranges::sort(m_unlinked, std::greater{}); std::vector affected_main; auto last = GraphIndex(-1); @@ -1817,7 +1818,7 @@ void TxGraphImpl::Compact() noexcept // Update the affected clusters, to fixup Entry::m_main_max_chunk_fallback values which may // have become outdated due to the compaction above. - std::sort(affected_main.begin(), affected_main.end()); + std::ranges::sort(affected_main); affected_main.erase(std::unique(affected_main.begin(), affected_main.end()), affected_main.end()); for (Cluster* cluster : affected_main) { cluster->Updated(*this, /*level=*/0, /*rename=*/true); @@ -1901,10 +1902,10 @@ void TxGraphImpl::GroupClusters(int level) noexcept } // Sort and deduplicate an_clusters, so we end up with a sorted list of all involved Clusters // to which dependencies apply, or which are oversized. - std::sort(an_clusters.begin(), an_clusters.end(), [](auto& a, auto& b) noexcept { return a.second < b.second; }); - an_clusters.erase(std::unique(an_clusters.begin(), an_clusters.end()), an_clusters.end()); + std::ranges::sort(an_clusters, [](auto& a, auto& b) noexcept { return a.second < b.second; }); + an_clusters.erase(std::ranges::unique(an_clusters).begin(), an_clusters.end()); // Sort an_deps by applying the same order to the involved child cluster. - std::sort(an_deps.begin(), an_deps.end(), [&](auto& a, auto& b) noexcept { return a.second < b.second; }); + std::ranges::sort(an_deps, [&](auto& a, auto& b) noexcept { return a.second < b.second; }); // Run the union-find algorithm to find partitions of the input Clusters which need to be // grouped together. See https://en.wikipedia.org/wiki/Disjoint-set_data_structure. @@ -2017,8 +2018,8 @@ void TxGraphImpl::GroupClusters(int level) noexcept // Sort both an_clusters and an_deps by sequence number of the representative of the // partition they are in, grouping all those applying to the same partition together. - std::sort(an_deps.begin(), an_deps.end(), [](auto& a, auto& b) noexcept { return a.second < b.second; }); - std::sort(an_clusters.begin(), an_clusters.end(), [](auto& a, auto& b) noexcept { return a.second < b.second; }); + std::ranges::sort(an_deps, [](auto& a, auto& b) noexcept { return a.second < b.second; }); + std::ranges::sort(an_clusters, [](auto& a, auto& b) noexcept { return a.second < b.second; }); // Translate the resulting cluster groups to the m_group_data structure, and the dependencies // back to m_deps_to_add. @@ -2489,7 +2490,7 @@ std::vector TxGraphImpl::GetAncestorsUnion(std::span ret; @@ -2522,7 +2523,7 @@ std::vector TxGraphImpl::GetDescendantsUnion(std::span ret; @@ -2796,7 +2797,7 @@ TxGraph::GraphIndex TxGraphImpl::CountDistinctClusters(std::span, std::vector> TxGraphImpl::GetMainStagin } } // Sort both by decreasing feerate to obtain diagrams, and return them. - std::sort(main_feerates.begin(), main_feerates.end(), std::greater>{}); - std::sort(staging_feerates.begin(), staging_feerates.end(), std::greater>{}); + std::ranges::sort(main_feerates, std::greater>{}); + std::ranges::sort(staging_feerates, std::greater>{}); return std::make_pair(std::move(main_feerates), std::move(staging_feerates)); } @@ -3401,7 +3402,7 @@ std::vector TxGraphImpl::Trim() noexcept // 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; }); + std::ranges::sort(trim_data, [](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(), @@ -3410,7 +3411,7 @@ std::vector TxGraphImpl::Trim() noexcept // 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; }); + std::ranges::sort(deps_by_child, [](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. @@ -3434,7 +3435,7 @@ std::vector TxGraphImpl::Trim() noexcept // Construct deps_by_parent, sorted by parent transaction GraphIndex. The order will not be // changed anymore after this. deps_by_parent = deps_by_child; - std::sort(deps_by_parent.begin(), deps_by_parent.end(), [](auto& a, auto& b) noexcept { return a.first < b.first; }); + std::ranges::sort(deps_by_parent, [](auto& a, auto& b) noexcept { return a.first < b.first; }); // Fill m_children_offset and m_children_count in trim_data. Because of the sort above, all // dependencies involving the same parent are grouped together, so a single linear scan // suffices. @@ -3482,8 +3483,8 @@ std::vector TxGraphImpl::Trim() noexcept Assume(chl == entry.m_index); current_deps.push_back(find_fn(&*locate_fn(par))); } - std::sort(current_deps.begin(), current_deps.end()); - current_deps.erase(std::unique(current_deps.begin(), current_deps.end()), current_deps.end()); + std::ranges::sort(current_deps); + current_deps.erase(std::ranges::unique(current_deps).begin(), current_deps.end()); // Compute resource counts. uint32_t new_count = 1;