diff --git a/alib2data/src/common/multipleDispatch.hpp b/alib2data/src/common/multipleDispatch.hpp new file mode 100644 index 0000000000000000000000000000000000000000..5d7760807f6372ceb5bc56f8ffb22f7d1b7cabe7 --- /dev/null +++ b/alib2data/src/common/multipleDispatch.hpp @@ -0,0 +1,212 @@ +/* + * multipleDispatch.hpp + * + * Created on: Apr 05, 2014 + * Author: Jan Travnicek + */ + +#ifndef MULTIPLE_DISPATCH_H_ +#define MULTIPLE_DISPATCH_H_ + +#include <stdexcept> +#include <functional> +#include <map> +#include <iostream> + +namespace std { + +template<class ReturnType, class FirstParameterType> +class SingleDispatch { +public: + class RegistratorWrapperBase { + public: + virtual ReturnType eval(const FirstParameterType&) = 0; + + }; + +private: + typedef SingleDispatch<ReturnType, FirstParameterType> SelfType; + + std::map<long long, typename SelfType::RegistratorWrapperBase*> registeredFunctions; + +public: + template<class RealReturnType, class RealFirstParameterType> + class RegistratorWrapper : public RegistratorWrapperBase { + std::function<RealReturnType(const RealFirstParameterType&)> callback; + + public: + ReturnType eval(const FirstParameterType& first) { + return ReturnType(callback((const RealFirstParameterType&) first)); + } + + RegistratorWrapper(SelfType& pool, RealReturnType(*callback)(const RealFirstParameterType&)) : callback(callback) { + int a = 0; + pool.registeredFunctions.insert(std::make_pair(RealFirstParameterType::typeId((const RealFirstParameterType&) a), this)); + } + }; + + ReturnType dispatch(const FirstParameterType& first) { + typename std::map<long long, RegistratorWrapperBase*>::iterator callback = registeredFunctions.find(first.selfTypeId()); + if(callback == registeredFunctions.end()) throw std::bad_function_call(); + return callback->second->eval(first); + } + +}; + +template<class ReturnType, class StaticParamType, class FirstParameterType> +class SingleDispatchFirstStaticParam { +public: + class RegistratorWrapperBase { + public: + virtual ReturnType eval(StaticParamType&, const FirstParameterType&) = 0; + + }; + +private: + typedef SingleDispatchFirstStaticParam<ReturnType, StaticParamType, FirstParameterType> SelfType; + + std::map<long long, typename SelfType::RegistratorWrapperBase*> registeredFunctions; + +public: + template<class RealReturnType, class RealFirstParameterType> + class RegistratorWrapper : public RegistratorWrapperBase { + std::function<RealReturnType(StaticParamType&, const RealFirstParameterType&)> callback; + + public: + ReturnType eval(StaticParamType& res, const FirstParameterType& first) { + return ReturnType(callback(res, (const RealFirstParameterType&) first)); + } + + RegistratorWrapper(SelfType& pool, RealReturnType(*callback)(StaticParamType&, const RealFirstParameterType&)) : callback(callback) { + int a = 0; + pool.registeredFunctions.insert(std::make_pair(RealFirstParameterType::typeId((const RealFirstParameterType&) a), this)); + } + }; + + ReturnType dispatch(StaticParamType& res, const FirstParameterType& first) { + typename std::map<long long, RegistratorWrapperBase*>::iterator callback = registeredFunctions.find(first.selfTypeId()); + if(callback == registeredFunctions.end()) throw std::bad_function_call(); + return callback->second->eval(res, first); + } + +}; + +template<class ReturnType, class FirstParameterType, class StaticParamType> +class SingleDispatchLastStaticParam { +public: + class RegistratorWrapperBase { + public: + virtual ReturnType eval(const FirstParameterType&, StaticParamType&) = 0; + + }; + +private: + typedef SingleDispatchLastStaticParam<ReturnType, FirstParameterType, StaticParamType> SelfType; + + std::map<long long, typename SelfType::RegistratorWrapperBase*> registeredFunctions; + +public: + template<class RealReturnType, class RealFirstParameterType> + class RegistratorWrapper : public RegistratorWrapperBase { + std::function<RealReturnType(const RealFirstParameterType&, StaticParamType&)> callback; + + public: + ReturnType eval(const FirstParameterType& first, StaticParamType& res) { + return ReturnType(callback((const RealFirstParameterType&) first, res)); + } + + RegistratorWrapper(SelfType& pool, RealReturnType(*callback)(const RealFirstParameterType&, StaticParamType&)) : callback(callback) { + int a = 0; + pool.registeredFunctions.insert(std::make_pair(RealFirstParameterType::typeId((const RealFirstParameterType&) a), this)); + } + }; + + ReturnType dispatch(const FirstParameterType& first, StaticParamType& res) { + typename std::map<long long, RegistratorWrapperBase*>::iterator callback = registeredFunctions.find(first.selfTypeId()); + if(callback == registeredFunctions.end()) throw std::bad_function_call(); + return callback->second->eval(first, res); + } + +}; + +// -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +template<class ReturnType, class FirstParameterType, class SecondParameterType> +class DoubleDispatch { +public: + class RegistratorWrapperBase { + public: + virtual ReturnType eval(const FirstParameterType&, const SecondParameterType&) = 0; + + }; + +private: + typedef DoubleDispatch<ReturnType, FirstParameterType, SecondParameterType> SelfType; + + std::map<std::pair<long long, long long>, typename SelfType::RegistratorWrapperBase*> registeredFunctions; + +public: + template<class RealReturnType, class RealFirstParameterType, class RealSecondParameterType> + class RegistratorWrapper : public RegistratorWrapperBase { + std::function<RealReturnType(const RealFirstParameterType&, const RealSecondParameterType&)> callback; + + public: + ReturnType eval(const FirstParameterType& first, const SecondParameterType& second) { + return ReturnType(callback((const RealFirstParameterType&) first, (const RealSecondParameterType&) second)); + } + + RegistratorWrapper(SelfType& pool, RealReturnType(*callback)(const RealFirstParameterType&, const RealSecondParameterType&)) : callback(callback) { + int a = 0; + pool.registeredFunctions.insert(std::make_pair(std::make_pair(RealFirstParameterType::typeId((const RealFirstParameterType&) a), RealSecondParameterType::typeId((const RealSecondParameterType&) a)), this)); + } + }; + + ReturnType dispatch(const FirstParameterType& first, const SecondParameterType& second) { + typename std::map<std::pair<long long, long long>, RegistratorWrapperBase*>::iterator callback = registeredFunctions.find(std::make_pair(first.selfTypeId(), second.selfTypeId())); + if(callback == registeredFunctions.end()) throw std::bad_function_call(); + return callback->second->eval(first, second); + } + +}; + +template<class ReturnType, class StaticParamType, class FirstParameterType, class SecondParameterType> +class DoubleDispatchFirstStaticParam { +public: + class RegistratorWrapperBase { + public: + virtual ReturnType eval(StaticParamType&, const FirstParameterType&, const SecondParameterType&) = 0; + + }; + +private: + typedef DoubleDispatchFirstStaticParam<ReturnType, StaticParamType, FirstParameterType, SecondParameterType> SelfType; + + std::map<std::pair<long long, long long>, typename SelfType::RegistratorWrapperBase*> registeredFunctions; + +public: + template<class RealReturnType, class RealFirstParameterType, class RealSecondParameterType> + class RegistratorWrapper : public RegistratorWrapperBase { + std::function<RealReturnType(StaticParamType&, const RealFirstParameterType&, const RealSecondParameterType&)> callback; + + public: + ReturnType eval(StaticParamType& res, const FirstParameterType& first, const SecondParameterType& second) { + return ReturnType(callback(res, (const RealFirstParameterType&) first, (const SecondParameterType&) second)); + } + + RegistratorWrapper(SelfType& pool, RealReturnType(*callback)(StaticParamType&, const RealFirstParameterType&, const RealSecondParameterType&)) : callback(callback) { + int a = 0; + pool.registeredFunctions.insert(std::make_pair(std::make_pair(RealFirstParameterType::typeId((const RealFirstParameterType&) a), RealSecondParameterType::typeId((const RealSecondParameterType&) a)), this)); + } + }; + + ReturnType dispatch(StaticParamType& res, const FirstParameterType& first, const SecondParameterType& second) { + typename std::map<std::pair<long long, long long>, RegistratorWrapperBase*>::iterator callback = registeredFunctions.find(std::make_pair(first.selfTypeId(), first.selfTypeId())); + if(callback == registeredFunctions.end()) throw std::bad_function_call(); + return callback->second->eval(res, first, second); + } + +}; + +} /* namespace std */ + +#endif /* MULTIPLE_DISPATCH_H_ */ diff --git a/alib2data/test-src/common/DispatchTest.cpp b/alib2data/test-src/common/DispatchTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..05b4007860274db76c0101e4f8194d4245ff66e0 --- /dev/null +++ b/alib2data/test-src/common/DispatchTest.cpp @@ -0,0 +1,264 @@ +#include "DispatchTest.h" +#include "common/multipleDispatch.hpp" +#include "common/base.hpp" +#include <set> +#include <string> + +CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( DispatchTest, "std" ); +CPPUNIT_TEST_SUITE_REGISTRATION( DispatchTest ); + +void DispatchTest::setUp() { +} + +void DispatchTest::tearDown() { +} + +namespace dispatch { + +class TmpBase : public alib::base<TmpBase> { +}; + +class Tmp1 : public TmpBase { + int data; +public: + Tmp1(int data) : data(data) { + + } + + TmpBase* clone() const { + return new Tmp1(*this); + } + + TmpBase* plunder() && { + return new Tmp1(*this); + } + + virtual int compare(const TmpBase& other) const { + return -other.compare(*this); + } + + virtual int compare(const Tmp1& other) const { + return this->data - other.data; + } + + virtual void operator>>(std::ostream& os) const { + os << "Tmp1(" << data << ")"; + } + + virtual operator std::string() const { + return "Tmp1(" + std::to_string(data) + ")"; + } + + virtual int selfTypeId() const { + return typeId(*this); + } + + int getData() const { + return data; + } + +}; + +class Tmp2 : public TmpBase { + double data; +public: + Tmp2(double data) : data(data) { + + } + + Tmp2(const Tmp1& other) : data(other.getData()) { + + } + + TmpBase* clone() const { + return new Tmp2(*this); + } + + TmpBase* plunder() && { + return new Tmp2(*this); + } + + virtual int compare(const TmpBase& other) const { + return -other.compare(*this); + } + + virtual int compare(const Tmp2& other) const { + return this->data - other.data; + } + + virtual void operator>>(std::ostream& os) const { + os << "Tmp2(" << data << ")"; + } + + virtual operator std::string() const { + return "Tmp2(" + std::to_string(data) + ")"; + } + + virtual int selfTypeId() const { + return typeId(*this); + } + + double getData() const { + return data; + } + +}; + +class Tmp3 : public TmpBase { + std::string data; +public: + Tmp3(const std::string& data) : data(data) { + + } + + Tmp3(const Tmp1& other) : data(std::to_string(other.getData())) { + + } + + Tmp3(const Tmp2& other) : data(std::to_string(other.getData())) { + + } + + TmpBase* clone() const { + return new Tmp3(*this); + } + + TmpBase* plunder() && { + return new Tmp3(*this); + } + + virtual int compare(const TmpBase& other) const { + return -other.compare(*this); + } + + virtual int compare(const Tmp3& other) const { + return this->data.compare(other.data); + } + + virtual void operator>>(std::ostream& os) const { + os << "Tmp3(" << data << ")"; + } + + virtual operator std::string() const { + return "Tmp3(" + data + ")"; + } + + virtual int selfTypeId() const { + return typeId(*this); + } + + const std::string& getData() const { + return data; + } + +}; + +// ------------------------------------------------------------------------------------------------------------------------------------------------------- + +class TmpVisitor : public std::SingleDispatch<int, TmpBase> { +public: + static int eval(const Tmp2& first) { + std::cout << first << std::endl; + return 2; + } + + static int eval(const Tmp3& first) { + std::cout << first << std::endl; + return 3; + } + + static int eval(const TmpBase& first) { + return getInstance().dispatch(first); + } + + static TmpVisitor& getInstance() { + static TmpVisitor res; + return res; + } +}; + +int TmpVisitorExtensionTmp1(const Tmp1& first) { + std::cout << first << std::endl; + return 1; +} + +TmpVisitor::RegistratorWrapper<int, Tmp1> TmpVisitorTmp1 = TmpVisitor::RegistratorWrapper<int, Tmp1>(TmpVisitor::getInstance(), TmpVisitorExtensionTmp1); +TmpVisitor::RegistratorWrapper<int, Tmp2> TmpVisitorTmp2 = TmpVisitor::RegistratorWrapper<int, Tmp2>(TmpVisitor::getInstance(), TmpVisitor::eval); +TmpVisitor::RegistratorWrapper<int, Tmp3> TmpVisitorTmp3 = TmpVisitor::RegistratorWrapper<int, Tmp3>(TmpVisitor::getInstance(), TmpVisitor::eval); + +} /* namespace dispatch */ + +void DispatchTest::testDispatch() { + dispatch::Tmp1 tmp1(2); + + int a = dispatch::TmpVisitor::eval(tmp1); + CPPUNIT_ASSERT(a == 1); + + a = dispatch::TmpVisitor::eval((dispatch::TmpBase&) tmp1); + CPPUNIT_ASSERT(a == 1); + + dispatch::Tmp2 tmp2(3.3); + + a = dispatch::TmpVisitor::eval(tmp2); + CPPUNIT_ASSERT(a == 2); + + a = dispatch::TmpVisitor::eval((dispatch::TmpBase&) tmp2); + CPPUNIT_ASSERT(a == 2); +} + +namespace dispatch { + +// ------------------------------------------------------------------------------------------------------------------------------------------------------- + +class TmpVisitor2 : public std::SingleDispatchFirstStaticParam<void, int, TmpBase> { +public: + static void eval(int& res, const Tmp2& first) { + std::cout << first << std::endl; + res = 2; + } + + static void eval(int& res, const Tmp3& first) { + std::cout << first << std::endl; + res = 3; + } + + static void eval(int& res, const TmpBase& first) { + getInstance().dispatch(res, first); + } + + static TmpVisitor2& getInstance() { + static TmpVisitor2 res; + return res; + } +}; + +void TmpVisitor2ExtensionTmp1(int& res, const Tmp1& first) { + std::cout << first << std::endl; + res = 1; +} + +TmpVisitor2::RegistratorWrapper<void, Tmp1> TmpVisitor2Tmp1 = TmpVisitor2::RegistratorWrapper<void, Tmp1>(TmpVisitor2::getInstance(), TmpVisitor2ExtensionTmp1); +TmpVisitor2::RegistratorWrapper<void, Tmp2> TmpVisitor2Tmp2 = TmpVisitor2::RegistratorWrapper<void, Tmp2>(TmpVisitor2::getInstance(), TmpVisitor2::eval); +TmpVisitor2::RegistratorWrapper<void, Tmp3> TmpVisitor2Tmp3 = TmpVisitor2::RegistratorWrapper<void, Tmp3>(TmpVisitor2::getInstance(), TmpVisitor2::eval); + +} /* namespace dispatch */ + +void DispatchTest::testDispatch2() { + dispatch::Tmp1 tmp1(2); + + int a; + dispatch::TmpVisitor2::eval(a, tmp1); + CPPUNIT_ASSERT(a == 1); + + dispatch::TmpVisitor2::eval(a, (dispatch::TmpBase&) tmp1); + CPPUNIT_ASSERT(a == 1); + + dispatch::Tmp2 tmp2(3.3); + + dispatch::TmpVisitor2::eval(a, tmp2); + CPPUNIT_ASSERT(a == 2); + + dispatch::TmpVisitor2::eval(a, (dispatch::TmpBase&) tmp2); + CPPUNIT_ASSERT(a == 2); +} + diff --git a/alib2data/test-src/common/DispatchTest.h b/alib2data/test-src/common/DispatchTest.h new file mode 100644 index 0000000000000000000000000000000000000000..e15276c6edd9b32248cb122046a0a5b0c9223695 --- /dev/null +++ b/alib2data/test-src/common/DispatchTest.h @@ -0,0 +1,21 @@ +#ifndef DISPATCH_TEST_H_ +#define DISPATCH_TEST_H_ + +#include <cppunit/extensions/HelperMacros.h> + +class DispatchTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE( DispatchTest ); + CPPUNIT_TEST( testDispatch ); + CPPUNIT_TEST( testDispatch2 ); + CPPUNIT_TEST_SUITE_END(); + +public: + void setUp(); + void tearDown(); + + void testDispatch(); + void testDispatch2(); +}; + +#endif // DISPATCH_TEST_H_ diff --git a/alib2data/test-src/common/VisitorTest.cpp b/alib2data/test-src/common/VisitorTest.cpp index ba91b9d3c45a3f16aff2b1c815e9410d2575a02c..e39a1d9091d5880aafd192b5c60ef7f134c72bca 100644 --- a/alib2data/test-src/common/VisitorTest.cpp +++ b/alib2data/test-src/common/VisitorTest.cpp @@ -13,6 +13,8 @@ void VisitorTest::setUp() { void VisitorTest::tearDown() { } +namespace visitor { + class Tmp1; class Tmp2; class Tmp3; @@ -221,10 +223,12 @@ class TmpPromotingVisitor : public VisitableTmpBase::const_promoting_visitor_typ } }; +} /* namespace visitor */ + void VisitorTest::testVisitor() { - TmpVisitor visitor; + visitor::TmpVisitor visitor; - Tmp1 tmp1(2); + visitor::Tmp1 tmp1(2); int a = 0; tmp1.Accept((void*) &a, visitor); @@ -233,30 +237,30 @@ void VisitorTest::testVisitor() { } void VisitorTest::testSameVisitor() { - TmpSameVisitor visitor; + visitor::TmpSameVisitor visitor; - Tmp2 tmpA(2); - Tmp2 tmpB(3); + visitor::Tmp2 tmpA(2); + visitor::Tmp2 tmpB(3); int a = 0; - Accept((void*) &a, (TmpBase&) tmpA, (TmpBase&) tmpB, visitor); + Accept((void*) &a, (visitor::TmpBase&) tmpA, (visitor::TmpBase&) tmpB, visitor); CPPUNIT_ASSERT(a == 2); } void VisitorTest::testPromoteVisitor() { - TmpPromotingVisitor visitor; + visitor::TmpPromotingVisitor visitor; - Tmp1 tmp1(1); - Tmp3 tmp3("3"); + visitor::Tmp1 tmp1(1); + visitor::Tmp3 tmp3("3"); std::string a = ""; - Accept((void*) &a, (TmpBase&) tmp1, (TmpBase&) tmp3, visitor); + Accept((void*) &a, (visitor::TmpBase&) tmp1, (visitor::TmpBase&) tmp3, visitor); CPPUNIT_ASSERT(a == "1 3"); std::string b = ""; - Accept((void*) &b, (TmpBase&) tmp3, (TmpBase&) tmp1, visitor); + Accept((void*) &b, (visitor::TmpBase&) tmp3, (visitor::TmpBase&) tmp1, visitor); CPPUNIT_ASSERT(b == "3 1"); }