Refactoring to avoid dynamic casts.

This commit is contained in:
Patrick Lühne 2016-12-07 02:29:48 +01:00
parent 692d3fe83a
commit ebab65e233
Signed by: patrick
GPG Key ID: 05F3611E97A70ABF
11 changed files with 88 additions and 114 deletions

View File

@ -132,6 +132,10 @@ class Expression
template<class T>
bool is() const;
template<class T>
T &as();
template<class T>
const T &as() const;
virtual ExpressionPointer copy();
@ -152,9 +156,6 @@ class Expression
virtual void print(std::ostream &ostream) const = 0;
protected:
static ExpressionPointer moveUpQuantifiers(ExpressionPointer parent, ExpressionPointer &child);
private:
friend void intrusive_ptr_add_ref(Expression *expression);
friend void intrusive_ptr_release(Expression *expression);
@ -172,6 +173,22 @@ bool Expression::is() const
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class T>
T &Expression::as()
{
return dynamic_cast<T &>(*this);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class T>
const T &Expression::as() const
{
return dynamic_cast<const T &>(*this);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
inline void intrusive_ptr_add_ref(Expression *expression)
{
expression->m_referenceCount++;

View File

@ -185,7 +185,7 @@ inline ExpressionPointer NAry<Derived>::simplified()
continue;
}
auto &nAryExpression = dynamic_cast<Derived &>(*argument);
auto &nAryExpression = argument->template as<Derived>();
BOOST_ASSERT(!nAryExpression.arguments().empty());

View File

@ -30,7 +30,7 @@ class Predicate: public ExpressionCRTP<Predicate>
bool isDeclared() const;
ExpressionPointer decomposed(expressions::DerivedPredicates &derivedPredicates) override;
ExpressionPointer decomposed(DerivedPredicates &derivedPredicates) override;
void collectParameters(std::set<VariablePointer> &parameters) override;

View File

@ -55,7 +55,7 @@ class QuantifiedCRTP: public Quantified
ExpressionPointer reduced() override;
ExpressionPointer existentiallyQuantified() override;
ExpressionPointer simplified() override;
ExpressionPointer decomposed(expressions::DerivedPredicates &derivedPredicates) override;
ExpressionPointer decomposed(DerivedPredicates &derivedPredicates) override;
void collectParameters(std::set<VariablePointer> &parameters);
@ -179,7 +179,7 @@ inline ExpressionPointer QuantifiedCRTP<Derived>::simplified()
if (m_argument->expressionType() != Derived::ExpressionType)
return this;
auto &quantifiedExpression = dynamic_cast<Derived &>(*m_argument);
auto &quantifiedExpression = m_argument->template as<Derived>();
// Unify variables
m_variables.insert(m_variables.end(), quantifiedExpression.variables().begin(), quantifiedExpression.variables().end());
@ -195,7 +195,7 @@ inline ExpressionPointer QuantifiedCRTP<Derived>::simplified()
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class Derived>
inline ExpressionPointer QuantifiedCRTP<Derived>::decomposed(expressions::DerivedPredicates &derivedPredicates)
inline ExpressionPointer QuantifiedCRTP<Derived>::decomposed(DerivedPredicates &derivedPredicates)
{
derivedPredicates.emplace_back(new DerivedPredicate());
auto &derivedPredicate = derivedPredicates.back();

View File

@ -54,43 +54,6 @@ ExpressionPointer Expression::existentiallyQuantified()
return this;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ExpressionPointer Expression::moveUpQuantifiers(ExpressionPointer parent, ExpressionPointer &child)
{
BOOST_ASSERT(child);
if (child->is<expressions::Exists>())
{
auto quantifiedExpression = expressions::ExistsPointer(dynamic_cast<expressions::Exists *>(child.get()));
// Move argument up
child = quantifiedExpression->argument();
// Move quantifier up
quantifiedExpression->setArgument(parent);
// Make parent point to the quantifier that has been moved up
return quantifiedExpression;
}
else if (child->is<expressions::ForAll>())
{
auto quantifiedExpression = expressions::ForAllPointer(dynamic_cast<expressions::ForAll *>(child.get()));
// Move argument up
child = quantifiedExpression->argument();
// Move quantifier up
quantifiedExpression->setArgument(parent);
// Make parent point to the quantifier that has been moved up
return quantifiedExpression;
}
return parent;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ExpressionPointer Expression::simplified()
@ -110,11 +73,7 @@ ExpressionPointer Expression::simplified()
ExpressionPointer Expression::negated()
{
if (is<expressions::Not>())
{
auto &notExpression = dynamic_cast<expressions::Not &>(*this);
return notExpression.argument();
}
return as<expressions::Not>().argument();
auto notExpression = expressions::NotPointer(new expressions::Not);
notExpression->setArgument(this);

View File

@ -323,7 +323,7 @@ void TranslatorASP::translateActions() const
{
case Expression::Type::And:
{
const auto &andExpression = dynamic_cast<const expressions::And &>(precondition);
const auto &andExpression = precondition.as<expressions::And>();
std::for_each(andExpression.arguments().cbegin(), andExpression.arguments().cend(),
[&](const auto argument)
@ -360,7 +360,7 @@ void TranslatorASP::translateActions() const
if (effect.expressionType() != Expression::Type::And)
throw output::TranslatorException("only “and” expressions and (negated) predicates supported as action effects currently");
const auto &andExpression = dynamic_cast<const expressions::And &>(effect);
const auto &andExpression = effect.as<expressions::And>();
std::for_each(andExpression.arguments().cbegin(), andExpression.arguments().cend(),
[&](const auto argument)
@ -444,7 +444,7 @@ void translateVariablesBody(output::ColorStream &outputStream, const T &variable
if (variable.type()->expressionType() != Expression::Type::PrimitiveType)
throw output::TranslatorException("only primitive types supported currently");
const auto &type = dynamic_cast<const expressions::PrimitiveType &>(*variable.type());
const auto &type = variable.type()->template as<expressions::PrimitiveType>();
outputStream << output::Function("has") << "("
<< output::Variable(variable.name().c_str()) << ", "
@ -466,7 +466,7 @@ void translateLiteral(output::ColorStream &outputStream, const Expression &liter
// Translate single predicate
if (literal.is<expressions::Predicate>())
{
const auto &predicate = dynamic_cast<const expressions::Predicate &>(literal);
const auto &predicate = literal.as<expressions::Predicate>();
outputStream << output::Keyword("variable") << "(";
translatePredicate(outputStream, predicate);
@ -477,12 +477,12 @@ void translateLiteral(output::ColorStream &outputStream, const Expression &liter
// Assuming that "not" expression may only contain a predicate
else if (literal.is<expressions::Not>())
{
const auto &notExpression = dynamic_cast<const expressions::Not &>(literal);
const auto &notExpression = literal.as<expressions::Not>();
if (notExpression.argument()->expressionType() != Expression::Type::Predicate)
throw output::TranslatorException("only negations of primitive predicates supported as literals currently");
const auto &predicate = dynamic_cast<const expressions::Predicate &>(*notExpression.argument());
const auto &predicate = notExpression.argument()->as<expressions::Predicate>();
outputStream << output::Keyword("variable") << "(";
translatePredicate(outputStream, predicate);
@ -492,7 +492,7 @@ void translateLiteral(output::ColorStream &outputStream, const Expression &liter
}
else if (literal.is<expressions::DerivedPredicate>())
{
const auto &derivedPredicate = dynamic_cast<const expressions::DerivedPredicate &>(literal);
const auto &derivedPredicate = literal.as<expressions::DerivedPredicate>();
/*m_outputStream << output::Keyword("variable") << "(";
this->translatePredicate(predicate);
@ -521,19 +521,19 @@ void translatePredicate(output::ColorStream &outputStream, const expressions::Pr
outputStream << "(" << output::String(predicate.name().c_str());
for (auto i = arguments.cbegin(); i != arguments.cend(); i++)
for (const auto &argument : arguments)
{
outputStream << ", ";
if ((*i)->is<expressions::Constant>())
if (argument->is<expressions::Constant>())
{
const auto &constant = dynamic_cast<const expressions::Constant &>(**i);
const auto &constant = argument->as<expressions::Constant>();
outputStream << output::Keyword("constant") << "(" << output::String(constant.name().c_str()) << ")";
}
else if ((*i)->is<expressions::Variable>())
else if (argument->is<expressions::Variable>())
{
const auto &variable = dynamic_cast<const expressions::Variable &>(**i);
const auto &variable = argument->as<expressions::Variable>();
outputStream << output::Variable(variable.name().c_str());
}
@ -587,7 +587,7 @@ void TranslatorASP::translateInitialState() const
// Translate single predicate
if (fact->is<expressions::Predicate>())
{
const auto &predicate = dynamic_cast<const expressions::Predicate &>(*fact);
const auto &predicate = fact->as<expressions::Predicate>();
m_outputStream << output::Keyword("variable") << "(";
translatePredicate(m_outputStream, predicate);
@ -598,7 +598,7 @@ void TranslatorASP::translateInitialState() const
// Assuming that "not" expression may only contain a predicate
else if (fact->is<expressions::Not>())
{
const auto &notExpression = dynamic_cast<const expressions::Not &>(*fact);
const auto &notExpression = fact->as<expressions::Not>();
if (notExpression.argument()->expressionType() != Expression::Type::Predicate)
throw output::TranslatorException("only negations of simple predicates supported in initial state currently");
@ -642,7 +642,7 @@ void TranslatorASP::translateGoal() const
}
else if (goal.is<expressions::And>())
{
const auto &andExpression = dynamic_cast<const expressions::And &>(goal);
const auto &andExpression = goal.as<expressions::And>();
std::for_each(andExpression.arguments().cbegin(), andExpression.arguments().cend(),
[&](const auto argument)

View File

@ -81,11 +81,11 @@ ExpressionPointer Not::simplified()
m_argument = m_argument->simplified();
if (!m_argument->is<expressions::Not>())
if (!m_argument->is<Not>())
return this;
// Remove double negations
const auto &notExpression = dynamic_cast<expressions::Not &>(*m_argument);
const auto &notExpression = m_argument->as<Not>();
return notExpression.argument();
}
@ -104,7 +104,7 @@ ExpressionPointer Not::decomposed(DerivedPredicates &derivedPredicates)
m_argument = m_argument->decomposed(derivedPredicates);
// Predicates and derived predicates can be directly negated
if (m_argument->is<expressions::Predicate>() || m_argument->is<expressions::DerivedPredicate>())
if (m_argument->is<Predicate>() || m_argument->is<DerivedPredicate>())
return this;
derivedPredicates.emplace_back(new DerivedPredicate());

View File

@ -33,11 +33,9 @@ ExpressionPointer Or::decomposed(DerivedPredicates &derivedPredicates)
Expressions conjunction;
// “and” expressions can directly be inlined into the derived predicate
if (argument->is<expressions::And>())
if (argument->is<And>())
{
const auto &andExpression = dynamic_cast<expressions::And &>(*argument);
conjunction = std::move(andExpression.arguments());
conjunction = std::move(argument->as<And>().arguments());
for (auto &argument : conjunction)
argument = argument->decomposed(derivedPredicates);

View File

@ -156,7 +156,7 @@ bool Predicate::isDeclared() const
////////////////////////////////////////////////////////////////////////////////////////////////////
ExpressionPointer Predicate::decomposed(expressions::DerivedPredicates &)
ExpressionPointer Predicate::decomposed(DerivedPredicates &)
{
// Predicates cannot be further decomposed
return this;

View File

@ -43,7 +43,7 @@ void PredicateDeclaration::parse(Context &context, Domain &domain)
expressionContext.variables.push(&predicate->m_parameters);
// Parse arguments
expressions::Variable::parseTypedDeclarations(context, expressionContext, predicate->m_parameters);
Variable::parseTypedDeclarations(context, expressionContext, predicate->m_parameters);
context.parser.expect<std::string>(")");

View File

@ -52,10 +52,10 @@ TEST_CASE("[PDDL parser] The Blocks World domain is parsed correctly", "[PDDL pa
CHECK(on.name() == "on");
REQUIRE(on.arguments().size() == 2u);
CHECK(on.arguments()[0]->name() == "x");
const auto &onArgument0Type = dynamic_cast<const expressions::PrimitiveType &>(*on.arguments()[0]->type());
const auto &onArgument0Type = on.arguments()[0]->type()->as<expressions::PrimitiveType>();
CHECK(&onArgument0Type == &block);
CHECK(on.arguments()[1]->name() == "y");
const auto &onArgument1Type = dynamic_cast<const expressions::PrimitiveType &>(*on.arguments()[1]->type());
const auto &onArgument1Type = on.arguments()[1]->type()->as<expressions::PrimitiveType>();
CHECK(&onArgument1Type == &block);
const auto &handempty = *domain.predicates()[3];
@ -73,26 +73,26 @@ TEST_CASE("[PDDL parser] The Blocks World domain is parsed correctly", "[PDDL pa
CHECK(pickUp.parameters()[0]->name() == "x");
CHECK(pickUp.parameters()[0]->type() == &block);
const auto &pickUpPre = dynamic_cast<const expressions::And &>(*pickUp.precondition());
const auto &pickUpPre = pickUp.precondition()->as<expressions::And>();
REQUIRE(pickUpPre.arguments().size() == 3u);
const auto &pickUpPre0 = dynamic_cast<const expressions::Predicate &>(*pickUpPre.arguments()[0]);
const auto &pickUpPre0 = pickUpPre.arguments()[0]->as<expressions::Predicate>();
CHECK(pickUpPre0.name() == "clear");
REQUIRE(pickUpPre0.arguments().size() == 1u);
const auto &pickUpPre00 = dynamic_cast<const expressions::Variable &>(*pickUpPre0.arguments()[0]);
const auto &pickUpPre00 = pickUpPre0.arguments()[0]->as<expressions::Variable>();
CHECK(pickUpPre00.name() == "x");
CHECK(pickUpPre00.type() == &block);
CHECK(&pickUpPre00 == pickUp.parameters()[0].get());
const auto &pickUpPre2 = dynamic_cast<const expressions::Predicate &>(*pickUpPre.arguments()[2]);
const auto &pickUpPre2 = pickUpPre.arguments()[2]->as<expressions::Predicate>();
CHECK(pickUpPre2.name() == "handempty");
CHECK(pickUpPre2.arguments().empty());
const auto &pickUpEff = dynamic_cast<const expressions::And &>(*pickUp.effect());
const auto &pickUpEff = pickUp.effect()->as<expressions::And>();
REQUIRE(pickUpEff.arguments().size() == 4u);
const auto &pickUpEff0 = dynamic_cast<const expressions::Not &>(*pickUpEff.arguments()[0]);
const auto &pickUpEff00 = dynamic_cast<const expressions::Predicate &>(*pickUpEff0.argument());
const auto &pickUpEff0 = pickUpEff.arguments()[0]->as<expressions::Not>();
const auto &pickUpEff00 = pickUpEff0.argument()->as<expressions::Predicate>();
CHECK(pickUpEff00.name() == "ontable");
REQUIRE(pickUpEff00.arguments().size() == 1u);
const auto &pickUpEff000 = dynamic_cast<const expressions::Variable &>(*pickUpEff00.arguments()[0]);
const auto &pickUpEff000 = pickUpEff00.arguments()[0]->as<expressions::Variable>();
CHECK(pickUpEff000.name() == "x");
CHECK(pickUpEff000.type() == &block);
}
@ -131,34 +131,34 @@ TEST_CASE("[PDDL parser] A Blocks World problem is parsed correctly", "[PDDL par
const auto &facts = problem.initialState().facts();
REQUIRE(facts.size() == 9u);
const auto &fact0 = dynamic_cast<const expressions::Predicate &>(*facts[0].get());
const auto &fact0 = facts[0].get()->as<expressions::Predicate>();
CHECK(fact0.name() == "clear");
REQUIRE(fact0.arguments().size() == 1u);
const auto &fact00 = dynamic_cast<const expressions::Constant &>(*fact0.arguments()[0]);
const auto &fact00 = fact0.arguments()[0]->as<expressions::Constant>();
CHECK(fact00.name() == "c");
REQUIRE(fact00.type() != nullptr);
CHECK(fact00.type()->name() == "block");
const auto &fact8 = dynamic_cast<const expressions::Predicate &>(*facts[8].get());
const auto &fact8 = facts[8].get()->as<expressions::Predicate>();
CHECK(fact8.name() == "handempty");
REQUIRE(fact8.arguments().size() == 0u);
// Goal
const auto &goal = dynamic_cast<const expressions::And &>(problem.goal());
const auto &goal = problem.goal().as<expressions::And>();
REQUIRE(goal.arguments().size() == 3u);
const auto &goal0 = dynamic_cast<const expressions::Predicate &>(*goal.arguments()[0]);
const auto &goal0 = goal.arguments()[0]->as<expressions::Predicate>();
CHECK(goal0.name() == "on");
REQUIRE(goal0.arguments().size() == 2u);
const auto &goal00 = dynamic_cast<const expressions::Constant &>(*goal0.arguments()[0]);
const auto &goal00 = goal0.arguments()[0]->as<expressions::Constant>();
CHECK(goal00.name() == "d");
const auto &goal01 = dynamic_cast<const expressions::Constant &>(*goal0.arguments()[1]);
const auto &goal01 = goal0.arguments()[1]->as<expressions::Constant>();
CHECK(goal01.name() == "c");
const auto &goal2 = dynamic_cast<const expressions::Predicate &>(*goal.arguments()[2]);
const auto &goal2 = goal.arguments()[2]->as<expressions::Predicate>();
CHECK(goal2.name() == "on");
REQUIRE(goal2.arguments().size() == 2u);
const auto &goal20 = dynamic_cast<const expressions::Constant &>(*goal2.arguments()[0]);
const auto &goal20 = goal2.arguments()[0]->as<expressions::Constant>();
CHECK(goal20.name() == "b");
const auto &goal21 = dynamic_cast<const expressions::Constant &>(*goal2.arguments()[1]);
const auto &goal21 = goal2.arguments()[1]->as<expressions::Constant>();
CHECK(goal21.name() == "a");
}
@ -209,21 +209,21 @@ TEST_CASE("[PDDL parser] The Storage domain is parsed correctly", "[PDDL parser]
CHECK(on.name() == "on");
REQUIRE(on.arguments().size() == 2u);
CHECK(on.arguments()[0]->name() == "c");
const auto &onArgument0Type = dynamic_cast<const expressions::PrimitiveType &>(*on.arguments()[0]->type());
const auto &onArgument0Type = on.arguments()[0]->type()->as<expressions::PrimitiveType>();
CHECK(&onArgument0Type == &crate);
CHECK(on.arguments()[1]->name() == "s");
const auto &onArgument1Type = dynamic_cast<const expressions::PrimitiveType &>(*on.arguments()[1]->type());
const auto &onArgument1Type = on.arguments()[1]->type()->as<expressions::PrimitiveType>();
CHECK(&onArgument1Type == &storearea);
const auto &in = *domain.predicates()[1];
CHECK(in.name() == "in");
REQUIRE(in.arguments().size() == 2u);
CHECK(in.arguments()[0]->name() == "x");
const auto &inArgument0Type = dynamic_cast<const expressions::Either &>(*in.arguments()[0]->type());
const auto &inArgument0Type = in.arguments()[0]->type()->as<expressions::Either>();
REQUIRE(inArgument0Type.arguments().size() == 2u);
const auto &inArgument0Type0 = dynamic_cast<const expressions::PrimitiveType &>(*inArgument0Type.arguments()[0]);
const auto &inArgument0Type0 = inArgument0Type.arguments()[0]->as<expressions::PrimitiveType>();
CHECK(&inArgument0Type0 == &storearea);
const auto &inArgument0Type1 = dynamic_cast<const expressions::PrimitiveType &>(*inArgument0Type.arguments()[1]);
const auto &inArgument0Type1 = inArgument0Type.arguments()[1]->as<expressions::PrimitiveType>();
CHECK(&inArgument0Type1 == &crate);
// Actions
@ -236,22 +236,22 @@ TEST_CASE("[PDDL parser] The Storage domain is parsed correctly", "[PDDL parser]
CHECK(drop.parameters()[3]->name() == "a2");
CHECK(drop.parameters()[3]->type() == &area);
const auto &dropPre = dynamic_cast<const expressions::And &>(*drop.precondition());
const auto &dropPre = drop.precondition()->as<expressions::And>();
REQUIRE(dropPre.arguments().size() == 5u);
const auto &dropPre2 = dynamic_cast<const expressions::Predicate &>(*dropPre.arguments()[2]);
const auto &dropPre2 = dropPre.arguments()[2]->as<expressions::Predicate>();
CHECK(dropPre2.name() == "lifting");
REQUIRE(dropPre2.arguments().size() == 2u);
const auto &dropPre21 = dynamic_cast<const expressions::Variable &>(*dropPre2.arguments()[1]);
const auto &dropPre21 = dropPre2.arguments()[1]->as<expressions::Variable>();
CHECK(dropPre21.name() == "c");
CHECK(dropPre21.type() == &crate);
const auto &dropEff = dynamic_cast<const expressions::And &>(*drop.effect());
const auto &dropEff = drop.effect()->as<expressions::And>();
REQUIRE(dropEff.arguments().size() == 5u);
const auto &dropEff2 = dynamic_cast<const expressions::Not &>(*dropEff.arguments()[2]);
const auto &dropEff20 = dynamic_cast<const expressions::Predicate &>(*dropEff2.argument());
const auto &dropEff2 = dropEff.arguments()[2]->as<expressions::Not>();
const auto &dropEff20 = dropEff2.argument()->as<expressions::Predicate>();
CHECK(dropEff20.name() == "clear");
REQUIRE(dropEff20.arguments().size() == 1u);
const auto &dropEff200 = dynamic_cast<const expressions::Variable &>(*dropEff20.arguments()[0]);
const auto &dropEff200 = dropEff20.arguments()[0]->as<expressions::Variable>();
CHECK(dropEff200.name() == "a1");
CHECK(dropEff200.type() == &storearea);
}
@ -290,31 +290,31 @@ TEST_CASE("[PDDL parser] A Storage problem is parsed correctly", "[PDDL parser]"
const auto &facts = problem.initialState().facts();
REQUIRE(facts.size() == 10u);
const auto &fact0 = dynamic_cast<const expressions::Predicate &>(*facts[0].get());
const auto &fact0 = facts[0].get()->as<expressions::Predicate>();
CHECK(fact0.name() == "in");
REQUIRE(fact0.arguments().size() == 2u);
const auto &fact01 = dynamic_cast<const expressions::Constant &>(*fact0.arguments()[1]);
const auto &fact01 = fact0.arguments()[1]->as<expressions::Constant>();
CHECK(fact01.name() == "depot0");
REQUIRE(fact01.type() != nullptr);
CHECK(fact01.type()->name() == "depot");
const auto &fact9 = dynamic_cast<const expressions::Predicate &>(*facts[9].get());
const auto &fact9 = facts[9].get()->as<expressions::Predicate>();
CHECK(fact9.name() == "available");
REQUIRE(fact9.arguments().size() == 1u);
const auto &fact90 = dynamic_cast<const expressions::Constant &>(*fact9.arguments()[0]);
const auto &fact90 = fact9.arguments()[0]->as<expressions::Constant>();
CHECK(fact90.name() == "hoist0");
REQUIRE(fact90.type() != nullptr);
CHECK(fact90.type()->name() == "hoist");
// Goal
const auto &goal = dynamic_cast<const expressions::And &>(problem.goal());
const auto &goal = problem.goal().as<expressions::And>();
REQUIRE(goal.arguments().size() == 1u);
const auto &goal0 = dynamic_cast<const expressions::Predicate &>(*goal.arguments()[0]);
const auto &goal0 = goal.arguments()[0]->as<expressions::Predicate>();
CHECK(goal0.name() == "in");
REQUIRE(goal0.arguments().size() == 2u);
const auto &goal00 = dynamic_cast<const expressions::Constant &>(*goal0.arguments()[0]);
const auto &goal00 = goal0.arguments()[0]->as<expressions::Constant>();
CHECK(goal00.name() == "crate0");
const auto &goal01 = dynamic_cast<const expressions::Constant &>(*goal0.arguments()[1]);
const auto &goal01 = goal0.arguments()[1]->as<expressions::Constant>();
CHECK(goal01.name() == "depot0");
}