From 5266186fcf3021cfcbe376d163679e6e4d17ec4c Mon Sep 17 00:00:00 2001 From: Jan Travnicek <Jan.Travnicek@fit.cvut.cz> Date: Sun, 23 Nov 2014 13:00:39 +0100 Subject: [PATCH] promoting visitor shall keep parameters order --- alib2data/src/std/visitor.hpp | 83 +++++++++++++++++++---- alib2data/test-src/std/StdTest.h | 17 +++++ alib2data/test-src/std/StdVisitorTest.cpp | 23 ++++--- 3 files changed, 102 insertions(+), 21 deletions(-) diff --git a/alib2data/src/std/visitor.hpp b/alib2data/src/std/visitor.hpp index fbce284704..2dcba5923d 100644 --- a/alib2data/src/std/visitor.hpp +++ b/alib2data/src/std/visitor.hpp @@ -61,28 +61,52 @@ class const_promoting_helper; template<typename Tested, typename... Other> struct const_promoting_helper<Tested, Other...> { + // variant 1 is swaping first and second argument because it came swaped template<class Desired, class Base, class TargetVisitor, typename std::enable_if< std::is_constructible<Desired, Tested>::value >::type* = nullptr > - inline static bool tryPromote(void* userData, const Desired& first, const Base& second, const TargetVisitor& visitor) { + inline static bool tryPromote1(void* userData, const Desired& first, const Base& second, const TargetVisitor& visitor) { + if(dynamic_cast<const Tested*>(&second)) { + //if(Tested::template typeId<Tested>() == second.selfTypeId()) { //TODO on g++-4.9 uncomment + visitor.Visit(userData, Desired(static_cast<const Tested&>(second)), first); + return true; + } else { + return const_promoting_helper<Other...>::tryPromote1(userData, first, second, visitor); + } + } + + template<class Desired, class Base, class TargetVisitor, + typename std::enable_if< ! std::is_constructible<Desired, Tested>::value >::type* = nullptr > + inline static bool tryPromote1(void* userData, const Desired& first, const Base& second, const TargetVisitor& visitor) { + return const_promoting_helper<Other...>::tryPromote1(userData, first, second, visitor); + } + + // variant 2 is not swaping first and second argument because it did not came swaped + template<class Desired, class Base, class TargetVisitor, + typename std::enable_if< std::is_constructible<Desired, Tested>::value >::type* = nullptr > + inline static bool tryPromote2(void* userData, const Desired& first, const Base& second, const TargetVisitor& visitor) { if(dynamic_cast<const Tested*>(&second)) { //if(Tested::template typeId<Tested>() == second.selfTypeId()) { //TODO on g++-4.9 uncomment visitor.Visit(userData, first, Desired(static_cast<const Tested&>(second))); return true; } else { - return const_promoting_helper<Other...>::tryPromote(userData, first, second, visitor); + return const_promoting_helper<Other...>::tryPromote2(userData, first, second, visitor); } } template<class Desired, class Base, class TargetVisitor, typename std::enable_if< ! std::is_constructible<Desired, Tested>::value >::type* = nullptr > - inline static bool tryPromote(void* userData, const Desired& first, const Base& second, const TargetVisitor& visitor) { - return const_promoting_helper<Other...>::tryPromote(userData, first, second, visitor); + inline static bool tryPromote2(void* userData, const Desired& first, const Base& second, const TargetVisitor& visitor) { + return const_promoting_helper<Other...>::tryPromote2(userData, first, second, visitor); } }; template<> struct const_promoting_helper<> { + + template<class Desired, class Base, class TargetVisitor> + inline static bool tryPromote1(void*, const Desired&, const Base&, const TargetVisitor&) { return false; } + template<class Desired, class Base, class TargetVisitor> - inline static bool tryPromote(void*, const Desired&, const Base&, const TargetVisitor&) { return false; } + inline static bool tryPromote2(void*, const Desired&, const Base&, const TargetVisitor&) { return false; } }; class const_promoting_visitor_base {}; @@ -97,14 +121,27 @@ class const_promoting_visitor<T> : public const_promoting_visitor_base { public: virtual void Visit(void*, const T &, const T&) const = 0; + // variant 1 is swaping first and second argument because it came swaped template<typename R, typename promoting_helper_type> bool Visit1(void* userData, const T& first, const R& second) const { + if(dynamic_cast<const T*>(&second)) { + //if(T::template typeId<T>() == second.selfTypeId()) { //TODO on g++-4.9 uncomment + this->Visit(userData, static_cast<const T&>(second), first); + return true; + } else { + return promoting_helper_type::tryPromote1( userData, first, second, *this ); + } + } + + // variant 2 is not swaping first and second argument because it did not came swaped + template<typename R, typename promoting_helper_type> + bool Visit2(void* userData, const T& first, const R& second) const { if(dynamic_cast<const T*>(&second)) { //if(T::template typeId<T>() == second.selfTypeId()) { //TODO on g++-4.9 uncomment this->Visit(userData, first, static_cast<const T&>(second)); return true; } else { - return promoting_helper_type::tryPromote( userData, first, second, *this ); + return promoting_helper_type::tryPromote2( userData, first, second, *this ); } } }; @@ -116,17 +153,31 @@ public: // promote the function(s) from the base class using const_promoting_visitor<Types...>::Visit; using const_promoting_visitor<Types...>::Visit1; + using const_promoting_visitor<Types...>::Visit2; virtual void Visit(void*, const T &, const T&) const = 0; + // variant 1 is swaping first and second argument because it came swaped template<typename R, typename promoting_helper_type> bool Visit1(void* userData, const T& first, const R& second) const { + if(dynamic_cast<const T*>(&second)) { + //if(T::template typeId<T>() == second.selfTypeId()) { //TODO on g++-4.9 uncomment + this->Visit(userData, static_cast<const T&>(second), first); + return true; + } else { + return promoting_helper_type::tryPromote1( userData, first, second, *this ); + } + } + + // variant 2 is not swaping first and second argument because it did not came swaped + template<typename R, typename promoting_helper_type> + bool Visit2(void* userData, const T& first, const R& second) const { if(dynamic_cast<const T*>(&second)) { //if(T::template typeId<T>() == second.selfTypeId()) { //TODO on g++-4.9 uncomment this->Visit(userData, first, static_cast<const T&>(second)); return true; } else { - return promoting_helper_type::tryPromote( userData, first, second, *this ); + return promoting_helper_type::tryPromote2( userData, first, second, *this ); } } }; @@ -194,7 +245,7 @@ public: virtual void Accept(void* userData, const const_visitor<Types...>& visitor) const = 0; - virtual bool Accept(void* userData, const T& other, const const_promoting_visitor<Types...>& visitor) const = 0; + virtual bool Accept(void* userData, const T& other, const const_promoting_visitor<Types...>& visitor, bool swap) const = 0; virtual void Accept(void* userData, const T& other, const const_same_visitor<Types...>& visitor) const = 0; }; @@ -210,8 +261,14 @@ public: visitor.Visit(userData, static_cast<const Derived&>(*this)); } - virtual bool Accept(void* userData, const typename AcceptorBase::base_type& other, const typename AcceptorBase::const_promoting_visitor_type& visitor) const { - return visitor.template Visit1<typename AcceptorBase::base_type, typename AcceptorBase::const_promoting_helper_type>(userData, static_cast<const Derived&>(*this), other); + virtual bool Accept(void* userData, const typename AcceptorBase::base_type& other, const typename AcceptorBase::const_promoting_visitor_type& visitor, bool swap) const { + if(swap) { + // variant 1 is swaping first and second argument because it came swaped + return visitor.template Visit1<typename AcceptorBase::base_type, typename AcceptorBase::const_promoting_helper_type>(userData, static_cast<const Derived&>(*this), other); + } else { + // variant 2 is not swaping first and second argument because it did not came swaped + return visitor.template Visit2<typename AcceptorBase::base_type, typename AcceptorBase::const_promoting_helper_type>(userData, static_cast<const Derived&>(*this), other); + } } virtual void Accept(void* userData, const typename AcceptorBase::base_type& other, const typename AcceptorBase::const_same_visitor_type& visitor) const { @@ -229,10 +286,12 @@ template<class T, class R, typename std::enable_if< std::is_base_of< const_promoting_visitor_base, R >::value >::type* = nullptr > void Accept(void* userData, const T& first, const T& second, const R& visitor) { bool res; - res = first.Accept(userData, second, visitor); + // variant 2 is swaping first and second argument because it come swaped + res = first.Accept(userData, second, visitor, false); if(res) return; - res = second.Accept(userData, first, visitor); + // variant 1 is not swaping first and second argument because it did not come swaped + res = second.Accept(userData, first, visitor, true); if(res) return; throw std::logic_error("Promoting visitor: Can't promote one parameter to type of the other."); diff --git a/alib2data/test-src/std/StdTest.h b/alib2data/test-src/std/StdTest.h index cfd048cc5b..20f727dd4c 100644 --- a/alib2data/test-src/std/StdTest.h +++ b/alib2data/test-src/std/StdTest.h @@ -2,6 +2,7 @@ #define VARIANT_TEST_H_ #include <cppunit/extensions/HelperMacros.h> +#include "std/compare.hpp" class StdTest : public CppUnit::TestFixture { @@ -11,6 +12,7 @@ class StdTest : public CppUnit::TestFixture CPPUNIT_TEST( testVariantSet ); CPPUNIT_TEST_SUITE_END(); +public: struct test { int * holder; @@ -43,6 +45,10 @@ struct test { return *(this->holder) == *(other.holder); } + int compare(const test& other) const { + return *(this->holder) - *(other.holder); + } + friend std::ostream& operator<<(std::ostream& out, const test& other) { out << *(other.holder); return out; @@ -64,4 +70,15 @@ public: void testVariantSet(); }; +namespace std { + +template<> +struct compare<StdTest::test> { + int operator()(const StdTest::test& first, const StdTest::test& second) { + return first.compare(second); + } +}; + +} /* namespace std */ + #endif // VARIANT_TEST_H_ diff --git a/alib2data/test-src/std/StdVisitorTest.cpp b/alib2data/test-src/std/StdVisitorTest.cpp index 2d275a47fb..8496191a40 100644 --- a/alib2data/test-src/std/StdVisitorTest.cpp +++ b/alib2data/test-src/std/StdVisitorTest.cpp @@ -206,20 +206,20 @@ class TmpSameVisitor : public VisitableTmpBase::const_same_visitor_type { class TmpPromotingVisitor : public VisitableTmpBase::const_promoting_visitor_type { void Visit(void* userData, const Tmp1& first, const Tmp1& second) const { - int& data = *((int*) userData); - data = 1; + std::string& data = *((std::string*) userData); + data = std::to_string(first.getData()) + " " + std::to_string(second.getData()); std::cout << first << " " << second << std::endl; } void Visit(void* userData, const Tmp2& first, const Tmp2& second) const { - int& data = *((int*) userData); - data = 2; + std::string& data = *((std::string*) userData); + data = std::to_string(first.getData()) + " " + std::to_string(second.getData()); std::cout << first << " " << second << std::endl; } void Visit(void* userData, const Tmp3& first, const Tmp3& second) const { - int& data = *((int*) userData); - data = 3; + std::string& data = *((std::string*) userData); + data = first.getData() + " " + second.getData(); std::cout << first << " " << second << std::endl; } }; @@ -249,11 +249,16 @@ void StdVisitorTest::testSameVisitor() { void StdVisitorTest::testPromoteVisitor() { TmpPromotingVisitor visitor; - Tmp1 tmp1(2); + Tmp1 tmp1(1); Tmp3 tmp3("3"); - int a = 0; + std::string a = ""; Accept((void*) &a, (TmpBase&) tmp1, (TmpBase&) tmp3, visitor); - CPPUNIT_ASSERT(a == 3); + CPPUNIT_ASSERT(a == "1 3"); + + std::string b = ""; + Accept((void*) &b, (TmpBase&) tmp3, (TmpBase&) tmp1, visitor); + + CPPUNIT_ASSERT(b == "3 1"); } -- GitLab