Commit 3f547089 authored by Maximilien Colange's avatar Maximilien Colange

Rework the 'down_cast' macro, closing #196.

* spot/misc/casts.hh: New inline functions and compile-time checks.
* spot/kripke/kripkegraph.hh, spot/ta/taexplicit.cc,
  spot/ta/taproduct.cc, spot/ta/tgtaproduct.cc, spot/taalgos/tgba2ta.cc,
  spot/twa/taatgba.hh, spot/twa/taatgba.cc, spot/twa/twagraph.hh,
  spot/twa/twaproduct.cc, spot/twaalgos/emptiness.cc,
  spot/twaalgos/stutter.cc, spot/ltsmin/ltsmin.cc, tests/core/ikwiad.cc,
  tests/core/ngraph.cc: Remove downcast checks from code.
parent 07a76e4d
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016 Laboratoire de // Copyright (C) 2011-2017 Laboratoire de Recherche et Développement de
// Recherche et Développement de l'Epita (LRDE) // l'Epita (LRDE)
// //
// This file is part of Spot, a model checking library. // This file is part of Spot, a model checking library.
// //
...@@ -42,7 +42,6 @@ namespace spot ...@@ -42,7 +42,6 @@ namespace spot
virtual int compare(const spot::state* other) const override virtual int compare(const spot::state* other) const override
{ {
auto o = down_cast<const kripke_graph_state*>(other); auto o = down_cast<const kripke_graph_state*>(other);
SPOT_ASSERT(o);
// Do not simply return "other - this", it might not fit in an int. // Do not simply return "other - this", it might not fit in an int.
if (o < this) if (o < this)
...@@ -194,7 +193,6 @@ namespace spot ...@@ -194,7 +193,6 @@ namespace spot
succ_iter(const spot::state* st) const override succ_iter(const spot::state* st) const override
{ {
auto s = down_cast<const typename graph_t::state_storage_t*>(st); auto s = down_cast<const typename graph_t::state_storage_t*>(st);
SPOT_ASSERT(s);
SPOT_ASSERT(!s->succ || g_.is_valid_edge(s->succ)); SPOT_ASSERT(!s->succ || g_.is_valid_edge(s->succ));
if (this->iter_cache_) if (this->iter_cache_)
...@@ -213,7 +211,6 @@ namespace spot ...@@ -213,7 +211,6 @@ namespace spot
state_number(const state* st) const state_number(const state* st) const
{ {
auto s = down_cast<const typename graph_t::state_storage_t*>(st); auto s = down_cast<const typename graph_t::state_storage_t*>(st);
SPOT_ASSERT(s);
return s - &g_.state_storage(0); return s - &g_.state_storage(0);
} }
...@@ -245,7 +242,6 @@ namespace spot ...@@ -245,7 +242,6 @@ namespace spot
virtual bdd state_condition(const state* s) const override virtual bdd state_condition(const state* s) const override
{ {
auto gs = down_cast<const kripke_graph_state*>(s); auto gs = down_cast<const kripke_graph_state*>(s);
SPOT_ASSERT(gs);
return gs->cond(); return gs->cond();
} }
......
...@@ -121,7 +121,6 @@ namespace spot ...@@ -121,7 +121,6 @@ namespace spot
if (this == other) if (this == other)
return 0; return 0;
const spins_state* o = down_cast<const spins_state*>(other); const spins_state* o = down_cast<const spins_state*>(other);
assert(o);
if (hash_value < o->hash_value) if (hash_value < o->hash_value)
return -1; return -1;
if (hash_value > o->hash_value) if (hash_value > o->hash_value)
...@@ -182,7 +181,6 @@ namespace spot ...@@ -182,7 +181,6 @@ namespace spot
return 0; return 0;
const spins_compressed_state* o = const spins_compressed_state* o =
down_cast<const spins_compressed_state*>(other); down_cast<const spins_compressed_state*>(other);
assert(o);
if (hash_value < o->hash_value) if (hash_value < o->hash_value)
return -1; return -1;
if (hash_value > o->hash_value) if (hash_value > o->hash_value)
...@@ -833,7 +831,6 @@ namespace spot ...@@ -833,7 +831,6 @@ namespace spot
{ {
const spins_compressed_state* s = const spins_compressed_state* s =
down_cast<const spins_compressed_state*>(st); down_cast<const spins_compressed_state*>(st);
assert(s);
decompress_(s->vars, s->size, uncompressed_, state_size_); decompress_(s->vars, s->size, uncompressed_, state_size_);
vars = uncompressed_; vars = uncompressed_;
...@@ -841,7 +838,6 @@ namespace spot ...@@ -841,7 +838,6 @@ namespace spot
else else
{ {
const spins_state* s = down_cast<const spins_state*>(st); const spins_state* s = down_cast<const spins_state*>(st);
assert(s);
vars = s->vars; vars = s->vars;
} }
return vars; return vars;
......
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2011, 2015-2016 Laboratoire de Recherche et Développement // Copyright (C) 2011, 2015-2017 Laboratoire de Recherche et Développement
// de l'Epita (LRDE). // de l'Epita (LRDE).
// //
// This file is part of Spot, a model checking library. // This file is part of Spot, a model checking library.
...@@ -19,23 +19,127 @@ ...@@ -19,23 +19,127 @@
#pragma once #pragma once
#include <memory>
#include <type_traits>
// We usually write code like // We usually write code like
// subclass* i = down_cast<subclass*>(m); // subtypename* i = down_cast<subtypename*>(m);
// assert(i);
// ... use i ... // ... use i ...
// When NDEBUG is set, the down_cast is a fast static_cast // When NDEBUG is set, the down_cast is a fast static_cast.
// and the assert has no effect.
// Otherwise, the down_cast is a dynamic_cast and may return 0 // Otherwise, the down_cast is a dynamic_cast and may return 0
// on error, which the assert catches. // on error, which is caught by an assert in the down_cast function.
//
// NB: It is valid to use down_cast with non-pointer template argument:
// subtypename& i = down_cast<subtypename&>(m);
// If an error occurs during the cast, an exception is thrown.
//
// NB: down_cast can also be used on shared_ptr.
namespace
{
// A helper struct to check that downcasts are performed down an inheritance
// hierarchy, not between unrelated types.
template<typename Base, typename Derived>
struct is_base_of : std::is_base_of<Base, Derived>
{};
template<typename Base, typename Derived>
struct is_base_of<Base*, Derived*> : is_base_of<Base, Derived>
{};
// Also handle smart pointers.
template<typename Base, typename Derived>
struct is_base_of<std::shared_ptr<Base>, std::shared_ptr<Derived>>
: is_base_of<Base, Derived>
{};
#if NDEBUG // std::is_pointer does not detect smart pointers.
# define down_cast static_cast // Make our own version that detects pointer, plain or smart.
template<typename T>
struct is_pointer : std::is_pointer<T>
{};
template<typename T>
struct is_pointer<std::shared_ptr<T>> : std::true_type
{};
template<typename T, typename U, bool check>
struct _downcast;
// A down-cast on non-pointer type is legitimate, e.g. down_cast<Derived&>(m);
// An error in the dynamic_cast will throw an exception.
template<typename T, typename U>
struct _downcast<T, U, false>
{
static_assert(is_base_of<U, T>::value, "invalid downcast");
static
inline
T
cast(U u)
#ifdef NDEBUG
noexcept
#else #else
# define down_cast dynamic_cast noexcept(is_pointer<T>::value)
#endif #endif
{
#ifdef NDEBUG
return static_cast<T>(u);
#else
return dynamic_cast<T>(u);
#endif
}
};
// A specialization for smart pointer, so that down_cast can be used
// uniformly.
// NB: Use
// auto d = down_cast<std::shared_ptr<T>>(b);
// instead of
// auto d = std::dynamic_pointer_cast<T>(b);
template<typename T, typename U>
struct _downcast<std::shared_ptr<T>, U, false>
{
static_assert(is_base_of<U, std::shared_ptr<T>>::value, "invalid downcast");
#if NDEBUG static
# define down_pointer_cast std::static_pointer_cast inline
std::shared_ptr<T>
cast(U u) noexcept
{
#ifdef NDEBUG
return std::static_pointer_cast<T>(u);
#else #else
# define down_pointer_cast std::dynamic_pointer_cast return std::dynamic_pointer_cast<T>(u);
#endif #endif
}
};
// Pointer type specialization.
// Cast errors are caught by an assertion, no exception is thrown.
template<typename T, typename U>
struct _downcast<T, U, true>
{
static
inline
T
cast(U u) noexcept
{
T t = _downcast<T, U, false>::cast(u);
SPOT_ASSERT(t);
return t;
}
};
} // anonymous namespace
// The actual function to call.
template<typename T, typename U>
inline
T
down_cast(U u)
#ifdef NDEBUG
noexcept
#else
noexcept(is_pointer<T>::value)
#endif
{
return _downcast<T, U, is_pointer<T>::value>::cast(u);
}
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016 Laboratoire // Copyright (C) 2010-2017 Laboratoire de Recherche et Développement de
// de Recherche et Développement de l'Epita (LRDE). // l'Epita (LRDE).
// //
// This file is part of Spot, a model checking library. // This file is part of Spot, a model checking library.
// //
...@@ -230,7 +230,6 @@ namespace spot ...@@ -230,7 +230,6 @@ namespace spot
state_ta_explicit::compare(const spot::state* other) const state_ta_explicit::compare(const spot::state* other) const
{ {
const state_ta_explicit* o = down_cast<const state_ta_explicit*>(other); const state_ta_explicit* o = down_cast<const state_ta_explicit*>(other);
assert(o);
int compare_value = tgba_state_->compare(o->tgba_state_); int compare_value = tgba_state_->compare(o->tgba_state_);
...@@ -362,7 +361,6 @@ namespace spot ...@@ -362,7 +361,6 @@ namespace spot
{ {
auto* s = const_cast<state_ta_explicit*> auto* s = const_cast<state_ta_explicit*>
(down_cast<const state_ta_explicit*>(*it)); (down_cast<const state_ta_explicit*>(*it));
assert(s);
s->free_transitions(); s->free_transitions();
s->get_tgba_state()->destroy(); s->get_tgba_state()->destroy();
delete s; delete s;
...@@ -383,7 +381,6 @@ namespace spot ...@@ -383,7 +381,6 @@ namespace spot
ta_explicit::add_to_initial_states_set(state* state, bdd condition) ta_explicit::add_to_initial_states_set(state* state, bdd condition)
{ {
state_ta_explicit* s = down_cast<state_ta_explicit*>(state); state_ta_explicit* s = down_cast<state_ta_explicit*>(state);
assert(s);
s->set_initial_state(true); s->set_initial_state(true);
if (condition == bddfalse) if (condition == bddfalse)
condition = get_state_condition(s); condition = get_state_condition(s);
...@@ -402,7 +399,6 @@ namespace spot ...@@ -402,7 +399,6 @@ namespace spot
{ {
auto state = auto state =
const_cast<state_ta_explicit*>(down_cast<const state_ta_explicit*>(s)); const_cast<state_ta_explicit*>(down_cast<const state_ta_explicit*>(s));
assert(state);
state->delete_stuttering_and_hole_successors(); state->delete_stuttering_and_hole_successors();
if (state->is_initial_state()) if (state->is_initial_state())
add_to_initial_states_set(state); add_to_initial_states_set(state);
...@@ -435,7 +431,6 @@ namespace spot ...@@ -435,7 +431,6 @@ namespace spot
{ {
const state_ta_explicit* sta = const state_ta_explicit* sta =
down_cast<const state_ta_explicit*>(initial_state); down_cast<const state_ta_explicit*>(initial_state);
assert(sta);
return sta->get_tgba_condition(); return sta->get_tgba_condition();
} }
...@@ -443,7 +438,6 @@ namespace spot ...@@ -443,7 +438,6 @@ namespace spot
ta_explicit::is_accepting_state(const spot::state* s) const ta_explicit::is_accepting_state(const spot::state* s) const
{ {
const state_ta_explicit* sta = down_cast<const state_ta_explicit*>(s); const state_ta_explicit* sta = down_cast<const state_ta_explicit*>(s);
assert(sta);
return sta->is_accepting_state(); return sta->is_accepting_state();
} }
...@@ -451,7 +445,6 @@ namespace spot ...@@ -451,7 +445,6 @@ namespace spot
ta_explicit::is_initial_state(const spot::state* s) const ta_explicit::is_initial_state(const spot::state* s) const
{ {
const state_ta_explicit* sta = down_cast<const state_ta_explicit*>(s); const state_ta_explicit* sta = down_cast<const state_ta_explicit*>(s);
assert(sta);
return sta->is_initial_state(); return sta->is_initial_state();
} }
...@@ -459,7 +452,6 @@ namespace spot ...@@ -459,7 +452,6 @@ namespace spot
ta_explicit::is_livelock_accepting_state(const spot::state* s) const ta_explicit::is_livelock_accepting_state(const spot::state* s) const
{ {
const state_ta_explicit* sta = down_cast<const state_ta_explicit*>(s); const state_ta_explicit* sta = down_cast<const state_ta_explicit*>(s);
assert(sta);
return sta->is_livelock_accepting_state(); return sta->is_livelock_accepting_state();
} }
...@@ -467,7 +459,6 @@ namespace spot ...@@ -467,7 +459,6 @@ namespace spot
ta_explicit::succ_iter(const spot::state* state) const ta_explicit::succ_iter(const spot::state* state) const
{ {
const state_ta_explicit* s = down_cast<const state_ta_explicit*>(state); const state_ta_explicit* s = down_cast<const state_ta_explicit*>(state);
assert(s);
return new ta_explicit_succ_iterator(s); return new ta_explicit_succ_iterator(s);
} }
...@@ -475,7 +466,6 @@ namespace spot ...@@ -475,7 +466,6 @@ namespace spot
ta_explicit::succ_iter(const spot::state* state, bdd condition) const ta_explicit::succ_iter(const spot::state* state, bdd condition) const
{ {
const state_ta_explicit* s = down_cast<const state_ta_explicit*>(state); const state_ta_explicit* s = down_cast<const state_ta_explicit*>(state);
assert(s);
return new ta_explicit_succ_iterator(s, condition); return new ta_explicit_succ_iterator(s, condition);
} }
...@@ -495,7 +485,6 @@ namespace spot ...@@ -495,7 +485,6 @@ namespace spot
ta_explicit::format_state(const spot::state* s) const ta_explicit::format_state(const spot::state* s) const
{ {
const state_ta_explicit* sta = down_cast<const state_ta_explicit*>(s); const state_ta_explicit* sta = down_cast<const state_ta_explicit*>(s);
assert(sta);
if (sta->get_tgba_condition() == bddtrue) if (sta->get_tgba_condition() == bddtrue)
return tgba_->format_state(sta->get_tgba_state()); return tgba_->format_state(sta->get_tgba_state());
......
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2011, 2012, 2014, 2015, 2016 Laboratoire de Recherche // Copyright (C) 2011, 2012, 2014-2017 Laboratoire de Recherche et
// et Développement de l'Epita (LRDE). // Développement de l'Epita (LRDE).
// //
// //
// This file is part of Spot, a model checking library. // This file is part of Spot, a model checking library.
...@@ -38,7 +38,6 @@ namespace spot ...@@ -38,7 +38,6 @@ namespace spot
state_ta_product::compare(const state* other) const state_ta_product::compare(const state* other) const
{ {
const state_ta_product* o = down_cast<const state_ta_product*> (other); const state_ta_product* o = down_cast<const state_ta_product*> (other);
assert(o);
int res = ta_state_->compare(o->get_ta_state()); int res = ta_state_->compare(o->get_ta_state());
if (res != 0) if (res != 0)
return res; return res;
...@@ -298,7 +297,6 @@ namespace spot ...@@ -298,7 +297,6 @@ namespace spot
ta_product::succ_iter(const state* s) const ta_product::succ_iter(const state* s) const
{ {
const state_ta_product* stp = down_cast<const state_ta_product*>(s); const state_ta_product* stp = down_cast<const state_ta_product*>(s);
assert(stp);
return new ta_succ_iterator_product(stp, ta_.get(), kripke_.get()); return new ta_succ_iterator_product(stp, ta_.get(), kripke_.get());
} }
...@@ -307,7 +305,6 @@ namespace spot ...@@ -307,7 +305,6 @@ namespace spot
ta_product::succ_iter(const spot::state* s, bdd changeset) const ta_product::succ_iter(const spot::state* s, bdd changeset) const
{ {
const state_ta_product* stp = down_cast<const state_ta_product*>(s); const state_ta_product* stp = down_cast<const state_ta_product*>(s);
assert(stp);
return new ta_succ_iterator_product_by_changeset(stp, return new ta_succ_iterator_product_by_changeset(stp,
ta_.get(), kripke_.get(), ta_.get(), kripke_.get(),
changeset); changeset);
...@@ -324,7 +321,6 @@ namespace spot ...@@ -324,7 +321,6 @@ namespace spot
ta_product::format_state(const state* state) const ta_product::format_state(const state* state) const
{ {
const state_ta_product* s = down_cast<const state_ta_product*> (state); const state_ta_product* s = down_cast<const state_ta_product*> (state);
assert(s);
return kripke_->format_state(s->get_kripke_state()) + " * \n" return kripke_->format_state(s->get_kripke_state()) + " * \n"
+ ta_->format_state(s->get_ta_state()); + ta_->format_state(s->get_ta_state());
} }
...@@ -333,8 +329,6 @@ namespace spot ...@@ -333,8 +329,6 @@ namespace spot
ta_product::is_accepting_state(const spot::state* s) const ta_product::is_accepting_state(const spot::state* s) const
{ {
const state_ta_product* stp = down_cast<const state_ta_product*> (s); const state_ta_product* stp = down_cast<const state_ta_product*> (s);
assert(stp);
return ta_->is_accepting_state(stp->get_ta_state()); return ta_->is_accepting_state(stp->get_ta_state());
} }
...@@ -342,8 +336,6 @@ namespace spot ...@@ -342,8 +336,6 @@ namespace spot
ta_product::is_livelock_accepting_state(const spot::state* s) const ta_product::is_livelock_accepting_state(const spot::state* s) const
{ {
const state_ta_product* stp = down_cast<const state_ta_product*> (s); const state_ta_product* stp = down_cast<const state_ta_product*> (s);
assert(stp);
return ta_->is_livelock_accepting_state(stp->get_ta_state()); return ta_->is_livelock_accepting_state(stp->get_ta_state());
} }
...@@ -351,7 +343,6 @@ namespace spot ...@@ -351,7 +343,6 @@ namespace spot
ta_product::is_initial_state(const spot::state* s) const ta_product::is_initial_state(const spot::state* s) const
{ {
const state_ta_product* stp = down_cast<const state_ta_product*> (s); const state_ta_product* stp = down_cast<const state_ta_product*> (s);
assert(stp);
const state* ta_s = stp->get_ta_state(); const state* ta_s = stp->get_ta_state();
const state* kr_s = stp->get_kripke_state(); const state* kr_s = stp->get_kripke_state();
...@@ -366,7 +357,6 @@ namespace spot ...@@ -366,7 +357,6 @@ namespace spot
ta_product::is_hole_state_in_ta_component(const spot::state* s) const ta_product::is_hole_state_in_ta_component(const spot::state* s) const
{ {
const state_ta_product* stp = down_cast<const state_ta_product*> (s); const state_ta_product* stp = down_cast<const state_ta_product*> (s);
assert(stp);
ta_succ_iterator* ta_succ_iter = get_ta()->succ_iter(stp->get_ta_state()); ta_succ_iterator* ta_succ_iter = get_ta()->succ_iter(stp->get_ta_state());
bool is_hole_state = ta_succ_iter->done(); bool is_hole_state = ta_succ_iter->done();
delete ta_succ_iter; delete ta_succ_iter;
...@@ -377,7 +367,6 @@ namespace spot ...@@ -377,7 +367,6 @@ namespace spot
ta_product::get_state_condition(const spot::state* s) const ta_product::get_state_condition(const spot::state* s) const
{ {
const state_ta_product* stp = down_cast<const state_ta_product*> (s); const state_ta_product* stp = down_cast<const state_ta_product*> (s);
assert(stp);
const state* ta_s = stp->get_ta_state(); const state* ta_s = stp->get_ta_state();
return ta_->get_state_condition(ta_s); return ta_->get_state_condition(ta_s);
} }
...@@ -387,7 +376,6 @@ namespace spot ...@@ -387,7 +376,6 @@ namespace spot
{ {
const state_ta_product* stp = down_cast<const state_ta_product*> (s); const state_ta_product* stp = down_cast<const state_ta_product*> (s);
assert(stp);
ta_->free_state(stp->get_ta_state()); ta_->free_state(stp->get_ta_state());
delete stp; delete stp;
......
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2012, 2014, 2015 Laboratoire de Recherche et // Copyright (C) 2012, 2014-2017 Laboratoire de Recherche et Développement de
// Développement de l Epita (LRDE). // l Epita (LRDE).
// //
// This file is part of Spot, a model checking library. // This file is part of Spot, a model checking library.
// //
...@@ -61,7 +61,6 @@ namespace spot ...@@ -61,7 +61,6 @@ namespace spot
tgta_product::succ_iter(const state* state) const tgta_product::succ_iter(const state* state) const
{ {
const state_product* s = down_cast<const state_product*> (state); const state_product* s = down_cast<const state_product*> (state);
assert(s);
fixed_size_pool* p = const_cast<fixed_size_pool*> (&pool_); fixed_size_pool* p = const_cast<fixed_size_pool*> (&pool_);
......
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016 Laboratoire de // Copyright (C) 2010-2017 Laboratoire de Recherche et Développement de
// Recherche et Développement de l'Epita (LRDE). // l'Epita (LRDE).
// //
// This file is part of Spot, a model checking library. // This file is part of Spot, a model checking library.
// //
...@@ -313,7 +313,6 @@ namespace spot ...@@ -313,7 +313,6 @@ namespace spot
{ {
auto self_loop_state = const_cast<state_ta_explicit*> auto self_loop_state = const_cast<state_ta_explicit*>
(down_cast<const state_ta_explicit*>(curr)); (down_cast<const state_ta_explicit*>(curr));
assert(self_loop_state);
if (testing_aut->is_accepting_state(self_loop_state) if (testing_aut->is_accepting_state(self_loop_state)
|| (testing_aut->acc().accepting(acc_cond))) || (testing_aut->acc().accepting(acc_cond)))
......
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 // Copyright (C) 2009-2017 Laboratoire de Recherche et Développement de
// Laboratoire de Recherche et Développement de l'Epita (LRDE) // l'Epita (LRDE)
// //
// This file is part of Spot, a model checking library. // This file is part of Spot, a model checking library.
// //
...@@ -62,7 +62,6 @@ namespace spot ...@@ -62,7 +62,6 @@ namespace spot
taa_tgba::succ_iter(const spot::state* state) const taa_tgba::succ_iter(const spot::state* state) const
{ {