From a9010855a5362cac6fdfa7e529d248a4a23fbe25 Mon Sep 17 00:00:00 2001 From: Joris van Rantwijk Date: Sat, 13 May 2023 15:22:21 +0200 Subject: [PATCH] Avoid dynamic_cast<..> --- cpp/mwmatching.h | 73 +++++++++++++++++++++++++++++------------------- 1 file changed, 44 insertions(+), 29 deletions(-) diff --git a/cpp/mwmatching.h b/cpp/mwmatching.h index cbf688c..2ff4ba3 100644 --- a/cpp/mwmatching.h +++ b/cpp/mwmatching.h @@ -201,6 +201,9 @@ struct Blossom /** Label S or T if this is a top-level blossom in an alternating tree. */ BlossomLabel label; + /** True if this is an instance of NonTrivialBlossom. */ + const bool is_nontrivial_blossom; + /** Optional edge that attaches this blossom to the alternating tree. */ VertexPair tree_edge; @@ -212,16 +215,32 @@ struct Blossom // TODO : consider storing a copy of the edge instead of pointer const Edge* best_edge; - /** Initialize a trivial (single-vertex) blossom. */ - explicit Blossom(VertexId base_vertex) +protected: + /** Initialize base class. */ + Blossom(VertexId base_vertex, bool is_nontrivial_blossom) : parent(nullptr), base_vertex(base_vertex), label(LABEL_NONE), + is_nontrivial_blossom(is_nontrivial_blossom), best_edge(nullptr) { } - // Dummy virtual method to allow the use of dynamic_cast<>. - virtual ~Blossom() = default; +public: + /** Initialize a trivial (single-vertex) blossom. */ + explicit Blossom(VertexId base_vertex) + : Blossom(base_vertex, false) + { } + + /** + * Cast this Blossom instance to NonTrivialBlossom if possible, + * otherwise return "nullptr". + */ + NonTrivialBlossom* nontrivial() + { + return (is_nontrivial_blossom ? + static_cast*>(this) + : nullptr); + } }; @@ -279,7 +298,7 @@ struct NonTrivialBlossom : public Blossom NonTrivialBlossom( const std::vector*>& subblossoms, const std::deque& edges) - : Blossom(subblossoms.front()->base_vertex), + : Blossom(subblossoms.front()->base_vertex, true), dual_var(0) { assert(subblossoms.size() == edges.size()); @@ -543,11 +562,10 @@ struct MatchingContext template void for_vertices_in_blossom(BlossomT* blossom, Func func) { - NonTrivialBlossomT* ntb = dynamic_cast(blossom); + NonTrivialBlossomT* ntb = blossom->nontrivial(); if (ntb) { // Visit all vertices in the non-trivial blossom. // Use an explicit stack to avoid deep call chains. - // TODO : re-use a global stack instance std::vector stack; stack.push_back(ntb); @@ -556,7 +574,7 @@ struct MatchingContext stack.pop_back(); for (const auto& sub : b->subblossoms) { - ntb = dynamic_cast(sub.blossom); + ntb = sub.blossom->nontrivial(); if (ntb) { stack.push_back(ntb); } else { @@ -673,7 +691,7 @@ struct MatchingContext void lset_new_blossom(BlossomT* blossom) { assert(blossom->best_edge == nullptr); - NonTrivialBlossomT* ntb = dynamic_cast(blossom); + NonTrivialBlossomT* ntb = blossom->nontrivial(); if (ntb) { assert(ntb->best_edge_set.empty()); } @@ -695,7 +713,7 @@ struct MatchingContext blossom->best_edge = edge; } - NonTrivialBlossomT* ntb = dynamic_cast(blossom); + NonTrivialBlossomT* ntb = blossom->nontrivial(); if (ntb) { ntb->best_edge_set.push_back(edge); } @@ -716,8 +734,7 @@ struct MatchingContext for (auto& subblossom_item : blossom->subblossoms) { BlossomT* sub = subblossom_item.blossom; if (sub->label == LABEL_S) { - NonTrivialBlossomT* ntb = - dynamic_cast(sub); + NonTrivialBlossomT* ntb = sub->nontrivial(); if (ntb) { // Take least-slack edge set from this subblossom. blossom->best_edge_set.splice( @@ -1175,14 +1192,14 @@ struct MatchingContext vertex_mate[y] = x; // Augment through any non-trivial subblossoms touching this edge. - NonTrivialBlossomT* bx_nt = dynamic_cast(bx); - if (bx_nt != nullptr) { - rec_stack.emplace(bx_nt, &trivial_blossom[x]); + NonTrivialBlossomT* bx_ntb = bx->nontrivial(); + if (bx_ntb != nullptr) { + rec_stack.emplace(bx_ntb, &trivial_blossom[x]); } - NonTrivialBlossomT* by_nt = dynamic_cast(by); - if (by_nt != nullptr) { - rec_stack.emplace(by_nt, &trivial_blossom[y]); + NonTrivialBlossomT* by_ntb = by->nontrivial(); + if (by_ntb != nullptr) { + rec_stack.emplace(by_ntb, &trivial_blossom[y]); } } @@ -1260,17 +1277,15 @@ struct MatchingContext // Augment any non-trivial blossoms that touch this edge. BlossomT* bx = vertex_top_blossom[x]; - NonTrivialBlossomT* bx_nt = - dynamic_cast(bx); - if (bx_nt != nullptr) { - augment_blossom(bx_nt, &trivial_blossom[x]); + NonTrivialBlossomT* bx_ntb = bx->nontrivial(); + if (bx_ntb != nullptr) { + augment_blossom(bx_ntb, &trivial_blossom[x]); } BlossomT* by = vertex_top_blossom[y]; - NonTrivialBlossomT* by_nt = - dynamic_cast(by); - if (by_nt != nullptr) { - augment_blossom(by_nt, &trivial_blossom[y]); + NonTrivialBlossomT* by_ntb = by->nontrivial(); + if (by_ntb != nullptr) { + augment_blossom(by_ntb, &trivial_blossom[y]); } // Pull this edge into the matching. @@ -1358,12 +1373,12 @@ struct MatchingContext // If "y" is part of a zero-dual blossom, expand it. // This would otherwise likely happen through a zero-delta4 step, // so we can just do it now and avoid a substage. - NonTrivialBlossomT* ntb = dynamic_cast(by); + NonTrivialBlossomT* ntb = by->nontrivial(); while (ntb != nullptr && ntb->dual_var == 0) { expand_unlabeled_blossom(ntb); by = vertex_top_blossom[y]; assert(by->label == LABEL_NONE); - ntb = dynamic_cast(by); + ntb = by->nontrivial(); } // Assign label T to the top-level blossom that contains vertex "y". @@ -1787,7 +1802,7 @@ struct MatchingContext // Examine the current sub-blossom. BlossomT* sub = subblossom_it->blossom; - NonTrivialBlossomT* ntb = dynamic_cast(sub); + NonTrivialBlossomT* ntb = sub->nontrivial(); if (ntb) { // Prepare to descend into this sub-blossom. stack.emplace(std::make_pair(ntb, ntb->subblossoms.begin()));