1
0
Fork 0

Avoid dynamic_cast<..>

This commit is contained in:
Joris van Rantwijk 2023-05-13 15:22:21 +02:00
parent dd452f73da
commit a9010855a5
1 changed files with 44 additions and 29 deletions

View File

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