diff --git a/include/AutomatableModel.h b/include/AutomatableModel.h index a92bd5191..93550e33f 100644 --- a/include/AutomatableModel.h +++ b/include/AutomatableModel.h @@ -92,18 +92,25 @@ public: virtual void accept(ConstModelVisitor& v) const = 0; public: - //! Return this class casted to Target, or nullptr if impossible + /** + @brief Return this class casted to Target + @test AutomatableModelTest.cpp + @param doThrow throw an assertion if the cast fails, instead of + returning a nullptr + @return the casted class if Target is the exact or a base class of + *this, nullptr otherwise + */ template - Target* dcast(bool doThrow = false) + Target* dynamicCast(bool doThrow = false) { DCastVisitor vis; accept(vis); if(doThrow && !vis.result) Q_ASSERT(false); return vis.result; } - //! Return this class casted to const Target, or nullptr if impossible + //! const overload, see overloaded function template - const Target* dcast(bool doThrow = false) const + const Target* dynamicCast(bool doThrow = false) const { ConstDCastVisitor vis; accept(vis); if(doThrow && !vis.result) Q_ASSERT(false); @@ -312,6 +319,7 @@ protected: private: + // dynamicCast implementation template struct DCastVisitor : public ModelVisitor { @@ -319,6 +327,7 @@ private: void visit(Target& tar) { result = &tar; } }; + // dynamicCast implementation template struct ConstDCastVisitor : public ConstModelVisitor { diff --git a/include/ModelVisitor.h b/include/ModelVisitor.h index 59d1df0c6..6411d0702 100644 --- a/include/ModelVisitor.h +++ b/include/ModelVisitor.h @@ -25,6 +25,7 @@ #ifndef MODELVISITOR_H #define MODELVISITOR_H +class AutomatableModel; class BoolModel; class IntModel; class FloatModel; @@ -32,21 +33,28 @@ class ComboBoxModel; class ModelVisitor { + template + void up(ModelType& m) { visit(static_cast(m)); } public: - virtual void visit(BoolModel& ) {} - virtual void visit(IntModel& ) {} - virtual void visit(FloatModel& ) {} - virtual void visit(ComboBoxModel& ) {} + virtual void visit(AutomatableModel& ) {} + virtual void visit(BoolModel& m); + virtual void visit(IntModel& ); + virtual void visit(FloatModel& ); + virtual void visit(ComboBoxModel& ); virtual ~ModelVisitor(); }; class ConstModelVisitor { + template + void up(const ModelType& m) { + visit(static_cast(m)); } public: - virtual void visit(const BoolModel& ) {} - virtual void visit(const IntModel& ) {} - virtual void visit(const FloatModel& ) {} - virtual void visit(const ComboBoxModel& ) {} + virtual void visit(const AutomatableModel& ) {} + virtual void visit(const BoolModel& m); + virtual void visit(const IntModel& m); + virtual void visit(const FloatModel& m); + virtual void visit(const ComboBoxModel& m); virtual ~ConstModelVisitor(); }; diff --git a/src/core/ModelVisitor.cpp b/src/core/ModelVisitor.cpp index 11a8fc1b1..48065c57e 100644 --- a/src/core/ModelVisitor.cpp +++ b/src/core/ModelVisitor.cpp @@ -24,5 +24,18 @@ #include "ModelVisitor.h" +#include "AutomatableModel.h" +#include "ComboBoxModel.h" + +void ModelVisitor::visit(BoolModel &m) { up(m); } +void ModelVisitor::visit(IntModel &m) { up(m); } +void ModelVisitor::visit(FloatModel &m) { up(m); } +void ModelVisitor::visit(ComboBoxModel &m) { up(m); } + +void ConstModelVisitor::visit(const BoolModel &m) { up(m); } +void ConstModelVisitor::visit(const IntModel &m) { up(m); } +void ConstModelVisitor::visit(const FloatModel &m) { up(m); } +void ConstModelVisitor::visit(const ComboBoxModel &m) { up(m); } + ModelVisitor::~ModelVisitor() {} ConstModelVisitor::~ConstModelVisitor() {} diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index c39f8e56e..ddebe116c 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -14,6 +14,7 @@ ADD_EXECUTABLE(tests QTestSuite $ + src/core/AutomatableModelTest.cpp src/core/ProjectVersionTest.cpp src/core/RelativePathsTest.cpp diff --git a/tests/src/core/AutomatableModelTest.cpp b/tests/src/core/AutomatableModelTest.cpp new file mode 100644 index 000000000..9bc19d7e8 --- /dev/null +++ b/tests/src/core/AutomatableModelTest.cpp @@ -0,0 +1,53 @@ +/* + * AutomatableModelTest.cpp + * + * Copyright (c) 2019-2019 Johannes Lorenz + * + * This file is part of LMMS - https://lmms.io + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + */ + +#include "QTestSuite.h" + +#include "AutomatableModel.h" +#include "ComboBoxModel.h" + +class AutomatableModelTest : QTestSuite +{ + Q_OBJECT + +private slots: + void CastTests() + { + ComboBoxModel comboModel; + AutomatableModel* amPtr = &comboModel; + QCOMPARE(nullptr, amPtr->dynamicCast()); + QVERIFY(nullptr != amPtr->dynamicCast()); + QVERIFY(nullptr != amPtr->dynamicCast()); + QVERIFY(nullptr != amPtr->dynamicCast()); + + IntModel intModel; + IntModel* imPtr = &intModel; + QCOMPARE(nullptr, imPtr->dynamicCast()); + QVERIFY(nullptr != imPtr->dynamicCast()); + QVERIFY(nullptr != imPtr->dynamicCast()); + QCOMPARE(nullptr, imPtr->dynamicCast()); + } +} AutomatableModelTests; + +#include "AutomatableModelTest.moc"