From 9ff6d1138a11079e23ee9bfb0a258e2453c07d04 Mon Sep 17 00:00:00 2001 From: Jan Travnicek <Jan.Travnicek@fit.cvut.cz> Date: Wed, 15 Oct 2014 22:58:40 +0200 Subject: [PATCH] add same visitor + visitor tests --- alib2data/src/std/visitor.hpp | 67 ++++++++++++++++++++++- alib2data/test-src/std/StdVisitorTest.cpp | 66 +++++++++++++++++++++- alib2data/test-src/std/StdVisitorTest.h | 4 ++ 3 files changed, 132 insertions(+), 5 deletions(-) diff --git a/alib2data/src/std/visitor.hpp b/alib2data/src/std/visitor.hpp index d65eecdfa8..64c7720032 100644 --- a/alib2data/src/std/visitor.hpp +++ b/alib2data/src/std/visitor.hpp @@ -84,13 +84,15 @@ template<> struct const_promoting_helper<> { inline static bool tryPromote(void*, const Desired&, const Base&, const TargetVisitor&) { return false; } }; +class const_promoting_visitor_base {}; + // Visitor template declaration template<typename... Types> class const_promoting_visitor; // specialization for single type template<typename T> -class const_promoting_visitor<T> { +class const_promoting_visitor<T> : public const_promoting_visitor_base { public: virtual void Visit(void*, const T &, const T&) const = 0; @@ -116,6 +118,48 @@ public: } }; +class const_same_visitor_base {}; + +// Visitor template declaration +template<typename... Types> +class const_same_visitor; + +// specialization for single type +template<typename T> +class const_same_visitor<T> : public const_same_visitor_base { +public: + virtual void Visit(void*, const T &, const T&) const = 0; + + template<typename R> + void Visit1(void* userData, const T& first, const R& second) const { + if(dynamic_cast<const T*>(&second)) { + this->Visit(userData, first, dynamic_cast<const T&>(second)); + } else { + throw std::logic_error("Same visitor: Visited types are different."); + } + } +}; + +// specialization for multiple types +template<typename T, typename... Types> +class const_same_visitor<T, Types...> : public const_same_visitor<Types...> { +public: + // promote the function(s) from the base class + using const_same_visitor<Types...>::Visit; + using const_same_visitor<Types...>::Visit1; + + virtual void Visit(void*, const T &, const T&) const = 0; + + template<typename R> + void Visit1(void* userData, const T& first, const R& second) const { + if(dynamic_cast<const T*>(&second)) { + this->Visit(userData, first, dynamic_cast<const T&>(second)); + } else { + throw std::logic_error("Same visitor: Visited types are different."); + } + } +}; + template<typename T, typename... Types> class acceptor_base { public: @@ -125,13 +169,19 @@ public: typedef const_promoting_visitor<Types...> const_promoting_visitor_type; typedef const_promoting_helper<Types...> const_promoting_helper_type; + + typedef const_same_visitor<Types...> const_same_visitor_type; + typedef T base_type; + virtual void Accept(void* userData, visitor<Types...>& visitor) const = 0; 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 void Accept(void* userData, const T& other, const const_same_visitor<Types...>& visitor) const = 0; }; template<typename Derived, typename AcceptorBase, typename Base> @@ -140,6 +190,7 @@ public: virtual void Accept(void* userData, typename AcceptorBase::visitor_type& visitor) const { visitor.Visit(userData, static_cast<const Derived&>(*this)); } + virtual void Accept(void* userData, const typename AcceptorBase::const_visitor_type& visitor) const { visitor.Visit(userData, static_cast<const Derived&>(*this)); } @@ -147,10 +198,20 @@ public: 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 void Accept(void* userData, const typename AcceptorBase::base_type& other, const typename AcceptorBase::const_same_visitor_type& visitor) const { + visitor.template Visit1<typename AcceptorBase::base_type>(userData, static_cast<const Derived&>(*this), other); + } }; +template<class T, class R, + typename std::enable_if< std::is_base_of< const_same_visitor_base, R >::value >::type* = nullptr > +void Accept(void* userData, const T& first, const T& second, const R& visitor) { + first.Accept(userData, second, visitor); +} -template<class T, class R> +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); @@ -159,7 +220,7 @@ void Accept(void* userData, const T& first, const T& second, const R& visitor) { res = second.Accept(userData, first, visitor); if(res) return; - throw std::logic_error("cant promote parameters"); + throw std::logic_error("Promoting visitor: Can't promote one parameter to type of the other."); } } /* namespace std */ diff --git a/alib2data/test-src/std/StdVisitorTest.cpp b/alib2data/test-src/std/StdVisitorTest.cpp index 314c3d0e13..073c523d34 100644 --- a/alib2data/test-src/std/StdVisitorTest.cpp +++ b/alib2data/test-src/std/StdVisitorTest.cpp @@ -200,7 +200,27 @@ public: }; -class TmpVisitor : public VisitableTmpBase::const_promoting_visitor_type { +class TmpVisitor : public VisitableTmpBase::const_visitor_type { + void Visit(void* userData, const Tmp1& first) const { + int& data = *((int*) userData); + data = 1; + std::cout << first << std::endl; + } + + void Visit(void* userData, const Tmp2& first) const { + int& data = *((int*) userData); + data = 2; + std::cout << first << std::endl; + } + + void Visit(void* userData, const Tmp3& first) const { + int& data = *((int*) userData); + data = 3; + std::cout << first << std::endl; + } +}; + +class TmpSameVisitor : public VisitableTmpBase::const_same_visitor_type { void Visit(void* userData, const Tmp1& first, const Tmp1& second) const { int& data = *((int*) userData); data = 1; @@ -220,9 +240,51 @@ class TmpVisitor : public VisitableTmpBase::const_promoting_visitor_type { } }; -void StdVisitorTest::testPromoteVisitor() { +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::cout << first << " " << second << std::endl; + } + + void Visit(void* userData, const Tmp2& first, const Tmp2& second) const { + int& data = *((int*) userData); + data = 2; + std::cout << first << " " << second << std::endl; + } + + void Visit(void* userData, const Tmp3& first, const Tmp3& second) const { + int& data = *((int*) userData); + data = 3; + std::cout << first << " " << second << std::endl; + } +}; + +void StdVisitorTest::testVisitor() { TmpVisitor visitor; + Tmp1 tmp1(2); + + int a = 0; + tmp1.Accept((void*) &a, visitor); + + CPPUNIT_ASSERT(a == 1); +} + +void StdVisitorTest::testSameVisitor() { + TmpSameVisitor visitor; + + Tmp2 tmpA(2); + Tmp2 tmpB(3); + + int a = 0; + Accept((void*) &a, (TmpBase&) tmpA, (TmpBase&) tmpB, visitor); + + CPPUNIT_ASSERT(a == 2); +} +void StdVisitorTest::testPromoteVisitor() { + TmpPromotingVisitor visitor; + Tmp1 tmp1(2); Tmp3 tmp3("3"); diff --git a/alib2data/test-src/std/StdVisitorTest.h b/alib2data/test-src/std/StdVisitorTest.h index da75d57781..bb2890cd70 100644 --- a/alib2data/test-src/std/StdVisitorTest.h +++ b/alib2data/test-src/std/StdVisitorTest.h @@ -7,6 +7,8 @@ class StdVisitorTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( StdVisitorTest ); CPPUNIT_TEST( testPromoteVisitor ); + CPPUNIT_TEST( testSameVisitor ); + CPPUNIT_TEST( testVisitor ); CPPUNIT_TEST_SUITE_END(); public: @@ -14,6 +16,8 @@ public: void tearDown(); void testPromoteVisitor(); + void testSameVisitor(); + void testVisitor(); }; #endif // VISITOR_TEST_H_ -- GitLab