These casts bother me a bit, I think we could avoid these by adding the abstraction commit before the specialization commit, e.g.
0diff --git a/src/txgraph.cpp b/src/txgraph.cpp
1--- a/src/txgraph.cpp (revision 2ab1b802ad070853777a3c207a4fe49ef32bc978)
2+++ b/src/txgraph.cpp (date 1759773463470)
3@@ -104,6 +104,7 @@
4 using GraphIndex = TxGraph::GraphIndex;
5
6 protected:
7+ using SetType = BitSet<MAX_CLUSTER_COUNT_LIMIT>;
8 /** The quality level of m_linearization. */
9 QualityLevel m_quality{QualityLevel::NONE};
10 /** Which position this Cluster has in Graph::ClusterSet::m_clusters[m_quality]. */
11@@ -157,6 +158,8 @@
12 virtual uint64_t GetTotalTxSize() const noexcept = 0;
13 /** Given a DepGraphIndex into this Cluster, find the corresponding GraphIndex. */
14 virtual GraphIndex GetClusterEntry(DepGraphIndex index) const noexcept = 0;
15+ /** Add dependencies to a given child in this cluster. */
16+ virtual void AddDependencies(SetType parents, DepGraphIndex child) noexcept = 0;
17 /** Figure out what level this Cluster exists at in Graph::m_clustersets. In most cases this
18 * is known by the caller already (see all "int level" arguments below), but not always. */
19 virtual int GetLevel(const TxGraphImpl& graph) const noexcept = 0;
20@@ -262,6 +265,10 @@
21 LinearizationIndex GetTxCount() const noexcept final { return m_linearization.size(); }
22 uint64_t GetTotalTxSize() const noexcept final;
23 GraphIndex GetClusterEntry(DepGraphIndex index) const noexcept final { return m_mapping[index]; }
24+ void AddDependencies(SetType parent, DepGraphIndex child) noexcept
25+ {
26+ m_depgraph.AddDependencies(parent, child);
27+ }
28 int GetLevel(const TxGraphImpl& graph) const noexcept final;
29 void UpdateMapping(DepGraphIndex cluster_idx, GraphIndex graph_idx) noexcept final { m_mapping[cluster_idx] = graph_idx; }
30 void Updated(TxGraphImpl& graph, int level) noexcept final;
31@@ -1128,12 +1135,11 @@
32 // Redistribute the dependencies.
33 for (auto i : m_linearization) {
34 /** The cluster transaction in position i is moved to. */
35- Cluster* new_abstract_cluster = remap[i].first;
36- GenericClusterImpl* new_cluster = static_cast<GenericClusterImpl*>(new_abstract_cluster);
37+ Cluster* new_cluster = remap[i].first;
38 // Copy its parents, translating positions.
39 SetType new_parents;
40 for (auto par : m_depgraph.GetReducedParents(i)) new_parents.Set(remap[par].second);
41- new_cluster->m_depgraph.AddDependencies(new_parents, remap[i].second);
42+ new_cluster->AddDependencies(new_parents, remap[i].second);
43 }
44 // Update all the Locators of moved transactions, and memory usage.
45 for (Cluster* new_cluster : new_clusters) {
The difficulty of extracting it revealed a lack of abstraction that we could fix before doing the abstraction itself.