From 876d97e9c767fbfffdabfdb3b8fd0e99e9fb67a0 Mon Sep 17 00:00:00 2001
From: Jan Travnicek <Jan.Travnicek@fit.cvut.cz>
Date: Wed, 12 Aug 2015 23:01:01 +0200
Subject: [PATCH] promoting double dispatch using castApi

---
 .../src/arbology/exact/ExactSubtreeMatch.cpp  |  8 +--
 .../src/arbology/exact/ExactSubtreeMatch.h    |  2 +-
 .../src/regexp/transform/RegExpAlternate.cpp  |  4 +-
 .../src/regexp/transform/RegExpAlternate.h    |  2 +-
 .../regexp/transform/RegExpConcatenate.cpp    |  4 +-
 .../src/regexp/transform/RegExpConcatenate.h  |  2 +-
 .../stringology/exact/ExactFactorMatch.cpp    |  2 +-
 .../src/stringology/exact/ExactFactorMatch.h  |  2 +-
 .../transform/RegExpConcatenateTest.cpp       |  4 +-
 alib2data/src/CastApi.hpp                     | 25 ++++++++
 alib2data/src/common/multipleDispatch.hpp     | 59 +++++++++++++++++++
 11 files changed, 99 insertions(+), 15 deletions(-)

diff --git a/alib2algo/src/arbology/exact/ExactSubtreeMatch.cpp b/alib2algo/src/arbology/exact/ExactSubtreeMatch.cpp
index 08b61e361d..f711c038fe 100644
--- a/alib2algo/src/arbology/exact/ExactSubtreeMatch.cpp
+++ b/alib2algo/src/arbology/exact/ExactSubtreeMatch.cpp
@@ -64,7 +64,7 @@ std::set<unsigned> ExactSubtreeMatch::match(const tree::UnrankedTree& subject, c
 	return occ;
 }
 
-auto ExactSubtreeMatchUnrankedTreeUnrankedTree = ExactSubtreeMatch::RegistratorWrapper<std::set<unsigned>, tree::UnrankedTree, tree::UnrankedTree>(ExactSubtreeMatch::getInstance(), ExactSubtreeMatch::match);
+auto ExactSubtreeMatchUnrankedTree = ExactSubtreeMatch::RegistratorWrapper<std::set<unsigned>, tree::UnrankedTree>(ExactSubtreeMatch::getInstance(), ExactSubtreeMatch::match);
 
 std::set<unsigned> ExactSubtreeMatch::match(const tree::RankedTree& subject, const tree::RankedTree& pattern) {
 	unsigned i = 0;
@@ -73,7 +73,7 @@ std::set<unsigned> ExactSubtreeMatch::match(const tree::RankedTree& subject, con
 	return occ;
 }
 
-auto ExactSubtreeMatchRankedTreeRankedTree = ExactSubtreeMatch::RegistratorWrapper<std::set<unsigned>, tree::RankedTree, tree::RankedTree>(ExactSubtreeMatch::getInstance(), ExactSubtreeMatch::match);
+auto ExactSubtreeMatchRankedTree = ExactSubtreeMatch::RegistratorWrapper<std::set<unsigned>, tree::RankedTree>(ExactSubtreeMatch::getInstance(), ExactSubtreeMatch::match);
 
 std::set<unsigned> ExactSubtreeMatch::match(const tree::PrefixRankedTree& subject, const tree::PrefixRankedTree& pattern) {
 	std::set<unsigned> occ;
@@ -89,7 +89,7 @@ std::set<unsigned> ExactSubtreeMatch::match(const tree::PrefixRankedTree& subjec
 	return occ;
 }
 
-auto ExactSubtreeMatchPrefixRankedTreePrefixRankedTree = ExactSubtreeMatch::RegistratorWrapper<std::set<unsigned>, tree::PrefixRankedTree, tree::PrefixRankedTree>(ExactSubtreeMatch::getInstance(), ExactSubtreeMatch::match);
+auto ExactSubtreeMatchPrefixRankedTree = ExactSubtreeMatch::RegistratorWrapper<std::set<unsigned>, tree::PrefixRankedTree>(ExactSubtreeMatch::getInstance(), ExactSubtreeMatch::match);
 
 std::set<unsigned> ExactSubtreeMatch::match(const tree::PrefixRankedBarTree& subject, const tree::PrefixRankedBarTree& pattern) {
 	std::set<unsigned> occ;
@@ -105,7 +105,7 @@ std::set<unsigned> ExactSubtreeMatch::match(const tree::PrefixRankedBarTree& sub
 	return occ;
 }
 
-auto ExactSubtreeMatchPrefixRankedBarTreePrefixRankedBarTree = ExactSubtreeMatch::RegistratorWrapper<std::set<unsigned>, tree::PrefixRankedBarTree, tree::PrefixRankedBarTree>(ExactSubtreeMatch::getInstance(), ExactSubtreeMatch::match);
+auto ExactSubtreeMatchPrefixRankedBarTree = ExactSubtreeMatch::RegistratorWrapper<std::set<unsigned>, tree::PrefixRankedBarTree>(ExactSubtreeMatch::getInstance(), ExactSubtreeMatch::match);
 
 } /* namespace exact */
 
diff --git a/alib2algo/src/arbology/exact/ExactSubtreeMatch.h b/alib2algo/src/arbology/exact/ExactSubtreeMatch.h
index ee63da8750..c596fd0419 100644
--- a/alib2algo/src/arbology/exact/ExactSubtreeMatch.h
+++ b/alib2algo/src/arbology/exact/ExactSubtreeMatch.h
@@ -18,7 +18,7 @@ namespace arbology {
 
 namespace exact {
 
-class ExactSubtreeMatch : public std::DoubleDispatch<std::set<unsigned>, tree::TreeBase, tree::TreeBase> {
+class ExactSubtreeMatch : public std::PromotingDoubleDispatch<std::set<unsigned>, tree::TreeBase> {
 public:
 	/**
 	 * Performs conversion.
diff --git a/alib2algo/src/regexp/transform/RegExpAlternate.cpp b/alib2algo/src/regexp/transform/RegExpAlternate.cpp
index 75748fda86..5824eab640 100644
--- a/alib2algo/src/regexp/transform/RegExpAlternate.cpp
+++ b/alib2algo/src/regexp/transform/RegExpAlternate.cpp
@@ -20,7 +20,7 @@ regexp::FormalRegExp RegExpAlternate::alternate(const regexp::FormalRegExp& firs
 	return regexp::FormalRegExp(regexp::FormalRegExpAlternation(first.getRegExp(), second.getRegExp()));
 }
 
-auto RegExpAlternateFormalRegExpFormalRegExp = RegExpAlternate::RegistratorWrapper<regexp::FormalRegExp, regexp::FormalRegExp, regexp::FormalRegExp>(RegExpAlternate::getInstance(), RegExpAlternate::alternate);
+auto RegExpAlternateFormalRegExp = RegExpAlternate::RegistratorWrapper<regexp::FormalRegExp, regexp::FormalRegExp>(RegExpAlternate::getInstance(), RegExpAlternate::alternate);
 
 regexp::UnboundedRegExp RegExpAlternate::alternate(const regexp::UnboundedRegExp& first, const regexp::UnboundedRegExp& second) {
 	regexp::UnboundedRegExpAlternation con;
@@ -29,6 +29,6 @@ regexp::UnboundedRegExp RegExpAlternate::alternate(const regexp::UnboundedRegExp
 	return regexp::UnboundedRegExp(con);
 }
 
-auto RegExpAlternateUnboundedRegExpUnboundedRegExp = RegExpAlternate::RegistratorWrapper<regexp::UnboundedRegExp, regexp::UnboundedRegExp, regexp::UnboundedRegExp>(RegExpAlternate::getInstance(), RegExpAlternate::alternate);
+auto RegExpAlternateUnboundedRegExp = RegExpAlternate::RegistratorWrapper<regexp::UnboundedRegExp, regexp::UnboundedRegExp>(RegExpAlternate::getInstance(), RegExpAlternate::alternate);
 
 } /* namespace regexp */
diff --git a/alib2algo/src/regexp/transform/RegExpAlternate.h b/alib2algo/src/regexp/transform/RegExpAlternate.h
index fda432cce9..b915c1b9f8 100644
--- a/alib2algo/src/regexp/transform/RegExpAlternate.h
+++ b/alib2algo/src/regexp/transform/RegExpAlternate.h
@@ -20,7 +20,7 @@ namespace regexp {
  * Alternates two regexpses
  *
  */
-class RegExpAlternate : public std::DoubleDispatch<regexp::RegExp, regexp::RegExpBase, regexp::RegExpBase> {
+class RegExpAlternate : public std::PromotingDoubleDispatch<regexp::RegExp, regexp::RegExpBase> {
 public:
 	static regexp::RegExp alternate(const regexp::RegExp& first, const regexp::RegExp& second);
 
diff --git a/alib2algo/src/regexp/transform/RegExpConcatenate.cpp b/alib2algo/src/regexp/transform/RegExpConcatenate.cpp
index 514baf7d1a..ddb89264b2 100644
--- a/alib2algo/src/regexp/transform/RegExpConcatenate.cpp
+++ b/alib2algo/src/regexp/transform/RegExpConcatenate.cpp
@@ -20,7 +20,7 @@ regexp::FormalRegExp RegExpConcatenate::concatenate(const regexp::FormalRegExp&
 	return regexp::FormalRegExp(regexp::FormalRegExpConcatenation(first.getRegExp(), second.getRegExp()));
 }
 
-auto RegExpConcatenateFormalRegExpFormalRegExp = RegExpConcatenate::RegistratorWrapper<regexp::FormalRegExp, regexp::FormalRegExp, regexp::FormalRegExp>(RegExpConcatenate::getInstance(), RegExpConcatenate::concatenate);
+auto RegExpConcatenateFormalRegExp = RegExpConcatenate::RegistratorWrapper<regexp::FormalRegExp, regexp::FormalRegExp>(RegExpConcatenate::getInstance(), RegExpConcatenate::concatenate);
 
 regexp::UnboundedRegExp RegExpConcatenate::concatenate(const regexp::UnboundedRegExp& first, const regexp::UnboundedRegExp& second) {
 	regexp::UnboundedRegExpConcatenation con;
@@ -29,6 +29,6 @@ regexp::UnboundedRegExp RegExpConcatenate::concatenate(const regexp::UnboundedRe
 	return regexp::UnboundedRegExp(con);
 }
 
-auto RegExpConcatenateUnboundedRegExpUnboundedRegExp = RegExpConcatenate::RegistratorWrapper<regexp::UnboundedRegExp, regexp::UnboundedRegExp, regexp::UnboundedRegExp>(RegExpConcatenate::getInstance(), RegExpConcatenate::concatenate);
+auto RegExpConcatenateUnboundedRegExp = RegExpConcatenate::RegistratorWrapper<regexp::UnboundedRegExp, regexp::UnboundedRegExp>(RegExpConcatenate::getInstance(), RegExpConcatenate::concatenate);
 
 } /* namespace regexp */
diff --git a/alib2algo/src/regexp/transform/RegExpConcatenate.h b/alib2algo/src/regexp/transform/RegExpConcatenate.h
index 1aa8480440..6738703a3e 100644
--- a/alib2algo/src/regexp/transform/RegExpConcatenate.h
+++ b/alib2algo/src/regexp/transform/RegExpConcatenate.h
@@ -20,7 +20,7 @@ namespace regexp {
  * Concatenates two regexpses
  *
  */
-class RegExpConcatenate : public std::DoubleDispatch<regexp::RegExp, regexp::RegExpBase, regexp::RegExpBase> {
+class RegExpConcatenate : public std::PromotingDoubleDispatch<regexp::RegExp, regexp::RegExpBase> {
 public:
 	static regexp::RegExp concatenate(const regexp::RegExp& first, const regexp::RegExp& second);
 
diff --git a/alib2algo/src/stringology/exact/ExactFactorMatch.cpp b/alib2algo/src/stringology/exact/ExactFactorMatch.cpp
index 2c79217bdf..556983b527 100644
--- a/alib2algo/src/stringology/exact/ExactFactorMatch.cpp
+++ b/alib2algo/src/stringology/exact/ExactFactorMatch.cpp
@@ -33,7 +33,7 @@ std::set<unsigned> ExactFactorMatch::match(const string::LinearString& subject,
 	return occ;
 }
 
-auto ExactFactorMatchLinearStringLinearString = ExactFactorMatch::RegistratorWrapper<std::set<unsigned>, string::LinearString, string::LinearString>(ExactFactorMatch::getInstance(), ExactFactorMatch::match);
+auto ExactFactorMatchLinearString = ExactFactorMatch::RegistratorWrapper<std::set<unsigned>, string::LinearString>(ExactFactorMatch::getInstance(), ExactFactorMatch::match);
 
 } /* namespace exact */
 
diff --git a/alib2algo/src/stringology/exact/ExactFactorMatch.h b/alib2algo/src/stringology/exact/ExactFactorMatch.h
index 451ac76e3d..7cde576a17 100644
--- a/alib2algo/src/stringology/exact/ExactFactorMatch.h
+++ b/alib2algo/src/stringology/exact/ExactFactorMatch.h
@@ -17,7 +17,7 @@ namespace stringology {
 
 namespace exact {
 
-class ExactFactorMatch : public std::DoubleDispatch<std::set<unsigned>, string::StringBase, string::StringBase> {
+class ExactFactorMatch : public std::PromotingDoubleDispatch<std::set<unsigned>, string::StringBase> {
 public:
 	/**
 	 * Performs conversion.
diff --git a/alib2algo/test-src/regexp/transform/RegExpConcatenateTest.cpp b/alib2algo/test-src/regexp/transform/RegExpConcatenateTest.cpp
index 9479a1e7cb..d50d8d4079 100644
--- a/alib2algo/test-src/regexp/transform/RegExpConcatenateTest.cpp
+++ b/alib2algo/test-src/regexp/transform/RegExpConcatenateTest.cpp
@@ -31,7 +31,7 @@ void RegExpConcatenateTest::testRegExpConcatenate() {
 
 		CPPUNIT_ASSERT(re == rer);
 	}
-	/*{ TODO reenable when promoting multiple dispatch is ready
+	{
 		std::string input1 = "(#E a b)";
 		regexp::RegExp re1 = alib::StringDataFactory::fromString<regexp::RegExp>(input1);
 
@@ -62,5 +62,5 @@ void RegExpConcatenateTest::testRegExpConcatenate() {
 		std::cout << re << std::endl;
 		std::cout << rer << std::endl;
 		CPPUNIT_ASSERT(re == rer);
-	}*/
+	}
 }
diff --git a/alib2data/src/CastApi.hpp b/alib2data/src/CastApi.hpp
index 93fa69286f..dc6b942c19 100644
--- a/alib2data/src/CastApi.hpp
+++ b/alib2data/src/CastApi.hpp
@@ -29,6 +29,10 @@ struct castApi {
 				throw std::bad_cast();
 			return res->second(from);
 		}
+
+		bool castAvailable(long long from) {
+			return castFunctions.count(from);
+		}
 	};
 
 	template<class To>
@@ -40,6 +44,11 @@ struct castApi {
 			castFunctions.insert(std::make_pair(From::typeId((const From&) a), [](const alib::ObjectBase& from) { return alib::Object(To((const From&) from)); } ));
 		}
 
+		template<class From>
+		bool test() {
+			int a = 0;
+			return castFunctions.count(From::typeId((const From&) a));
+		}
 	};
 
 private:
@@ -78,6 +87,22 @@ public:
 		}
 	}
 
+	static CastPoolBase& getCastPool(long long typeId) {
+		std::map<long long, CastPoolBase*>::iterator res = castFunctionsById().find(typeId);
+		if(res == castFunctionsById().end()) {
+			throw std::invalid_argument("Casting to type ? not available.");
+		} else {
+			return * res->second;
+		}
+	}
+
+	static bool castAvailable(long long to, long long from) {
+		std::map<long long, CastPoolBase*>::iterator res = castFunctionsById().find(to);
+		if(res == castFunctionsById().end())
+			return false;
+		return res->second->castAvailable(from);
+	}
+
 	template<class To>
 	class CastPoolStringBinder {
 	public:
diff --git a/alib2data/src/common/multipleDispatch.hpp b/alib2data/src/common/multipleDispatch.hpp
index 5d7760807f..ccf5879535 100644
--- a/alib2data/src/common/multipleDispatch.hpp
+++ b/alib2data/src/common/multipleDispatch.hpp
@@ -13,6 +13,8 @@
 #include <map>
 #include <iostream>
 
+#include "../CastApi.hpp"
+
 namespace std {
 
 template<class ReturnType, class FirstParameterType>
@@ -131,6 +133,63 @@ public:
 
 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 
+template<class ReturnType, class ParametersType>
+class PromotingDoubleDispatch {
+public:
+	class RegistratorWrapperBase {
+	public:
+		virtual ReturnType eval(bool firstAttempt, const ParametersType&, const ParametersType&) = 0;
+		virtual bool available(bool firstAttempt, long long first, long long second) = 0;
+	};
+
+private:
+	typedef PromotingDoubleDispatch<ReturnType, ParametersType> SelfType;
+
+	std::map<long long, typename SelfType::RegistratorWrapperBase*> registeredFunctions;
+
+public:
+	template<class RealReturnType, class RealParametersType>
+	class RegistratorWrapper : public RegistratorWrapperBase {
+		std::function<RealReturnType(const RealParametersType&, const RealParametersType&)> callback;
+
+	public:
+		ReturnType eval(bool firstAttempt, const ParametersType& first, const ParametersType& second) {
+			if(firstAttempt) {
+				alib::Object casted = alib::castApi::getCastPool(first.selfTypeId()).cast(second);
+				return ReturnType(callback((const RealParametersType&) first, (const RealParametersType&) casted.getData()));
+			} else {
+				alib::Object casted = alib::castApi::getCastPool(first.selfTypeId()).cast(first);
+				return ReturnType(callback((const RealParametersType&) casted.getData(), (const RealParametersType&) second));
+			}
+		}
+
+		bool available(bool firstAttempt, long long first, long long second) {
+			if(firstAttempt)
+				return alib::castApi::castAvailable(first, second);
+			else
+				return alib::castApi::castAvailable(second, first);
+		}
+
+		RegistratorWrapper(SelfType& pool, RealReturnType(*callback)(const RealParametersType&, const RealParametersType&)) : callback(callback) {
+			int a = 0;
+			pool.registeredFunctions.insert(std::make_pair(RealParametersType::typeId((const RealParametersType&) a), this));
+		}
+	};
+
+	ReturnType dispatch(const ParametersType& first, const ParametersType& second) {
+		typename std::map<long long, RegistratorWrapperBase*>::iterator callback = registeredFunctions.find(first.selfTypeId());
+		if(callback != registeredFunctions.end() && callback->second->available(true, first.selfTypeId(), second.selfTypeId())) return callback->second->eval(true, first, second);
+
+		callback = registeredFunctions.find(second.selfTypeId());
+		if(callback != registeredFunctions.end() && callback->second->available(false, first.selfTypeId(), second.selfTypeId())) return callback->second->eval(false, first, second);
+
+		throw std::bad_function_call();
+	}
+
+};
+
+// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
 template<class ReturnType, class FirstParameterType, class SecondParameterType>
 class DoubleDispatch {
 public:
-- 
GitLab