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. */
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<WeightType>* 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<WeightType>* nontrivial()
{
return (is_nontrivial_blossom ?
static_cast<NonTrivialBlossom<WeightType>*>(this)
: nullptr);
}
};
@ -279,7 +298,7 @@ struct NonTrivialBlossom : public Blossom<WeightType>
NonTrivialBlossom(
const std::vector<Blossom<WeightType>*>& subblossoms,
const std::deque<VertexPair>& edges)
: Blossom<WeightType>(subblossoms.front()->base_vertex),
: Blossom<WeightType>(subblossoms.front()->base_vertex, true),
dual_var(0)
{
assert(subblossoms.size() == edges.size());
@ -543,11 +562,10 @@ struct MatchingContext
template <typename Func>
void for_vertices_in_blossom(BlossomT* blossom, Func func)
{
NonTrivialBlossomT* ntb = dynamic_cast<NonTrivialBlossomT*>(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<NonTrivialBlossomT*> stack;
stack.push_back(ntb);
@ -556,7 +574,7 @@ struct MatchingContext
stack.pop_back();
for (const auto& sub : b->subblossoms) {
ntb = dynamic_cast<NonTrivialBlossomT*>(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<NonTrivialBlossomT*>(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<NonTrivialBlossomT*>(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<NonTrivialBlossomT*>(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<NonTrivialBlossomT*>(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<NonTrivialBlossomT*>(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<NonTrivialBlossomT*>(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<NonTrivialBlossomT*>(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<NonTrivialBlossomT*>(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<NonTrivialBlossomT*>(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<NonTrivialBlossomT*>(sub);
NonTrivialBlossomT* ntb = sub->nontrivial();
if (ntb) {
// Prepare to descend into this sub-blossom.
stack.emplace(std::make_pair(ntb, ntb->subblossoms.begin()));