From ceb5b4ca37a5d59a0f9b8677745da0e1c9651ce8 Mon Sep 17 00:00:00 2001
From: Jan Travnicek <Jan.Travnicek@fit.cvut.cz>
Date: Tue, 10 Oct 2017 11:51:41 +0200
Subject: [PATCH] allow xml parsing and composing call as algorithm

---
 .../src/abstraction/AlgorithmRegistry.hpp     |  39 ++++
 .../src/abstraction/WrapperAbstraction.hpp    | 168 ++++++++++++++++++
 .../src/registration/AlgoRegistration.hpp     |  12 ++
 alib2xml/src/registration/XmlRegistration.hpp |  26 +++
 4 files changed, 245 insertions(+)
 create mode 100644 alib2common/src/abstraction/WrapperAbstraction.hpp

diff --git a/alib2common/src/abstraction/AlgorithmRegistry.hpp b/alib2common/src/abstraction/AlgorithmRegistry.hpp
index 4553f81b3d..28214049cf 100644
--- a/alib2common/src/abstraction/AlgorithmRegistry.hpp
+++ b/alib2common/src/abstraction/AlgorithmRegistry.hpp
@@ -42,6 +42,17 @@ class AlgorithmRegistry {
 		virtual std::shared_ptr < abstraction::OperationAbstraction > getAbstraction ( ) const override;
 	};
 
+	template < class ... Params >
+	class WrapperImpl : public Entry {
+		std::function < std::shared_ptr < abstraction::OperationAbstraction > ( Params ... ) > m_wrapperFinder;
+
+	public:
+		WrapperImpl ( std::function < std::shared_ptr < abstraction::OperationAbstraction > ( Params ... ) > wrapperFinder ) : m_wrapperFinder ( wrapperFinder ) {
+		}
+
+		virtual std::shared_ptr < abstraction::OperationAbstraction > getAbstraction ( ) const override;
+	};
+
 	static ext::map < std::string, ext::vector < ext::tuple < AlgorithmCategories::AlgorithmCategory, ext::vector < ext::tuple < std::string, ext::set < abstraction::ParamQualifiers::ParamQualifier >, std::string > >, ext::pair < ext::pair < std::string, ext::set < abstraction::ParamQualifiers::ParamQualifier > >, std::shared_ptr < Entry > > > > > & getEntries ( ) {
 		static ext::map < std::string, ext::vector < ext::tuple < AlgorithmCategories::AlgorithmCategory, ext::vector < ext::tuple < std::string, ext::set < abstraction::ParamQualifiers::ParamQualifier >, std::string > >, ext::pair < ext::pair < std::string, ext::set < abstraction::ParamQualifiers::ParamQualifier > >, std::shared_ptr < Entry > > > > > algorithmGroups;
 		return algorithmGroups;
@@ -74,6 +85,28 @@ public:
 		group.push_back ( ext::make_tuple ( category, params, entryValue ) );
 	}
 
+	template < class Algo, class ... ParamTypes >
+	static void registerWrapper ( std::shared_ptr < abstraction::OperationAbstraction > ( * callback ) ( ParamTypes ... ), std::array < std::string, sizeof ... ( ParamTypes ) > paramNames ) {
+		/* make unused parameter warning go away in case of sizeof ... ( ParamTypes ) == 0 */
+		( void ) paramNames;
+
+		AlgorithmCategories::AlgorithmCategory category = AlgorithmCategories::AlgorithmCategory::DEFAULT;
+		std::string algorithm = ext::to_string < Algo > ( );
+
+		ext::vector < ext::tuple < std::string, ext::set < abstraction::ParamQualifiers::ParamQualifier >, std::string > > params;
+		unsigned i = 0; /* the evaluation order in initializer list is actually defined */
+		( void ) std::initializer_list < int > { ( params.push_back ( ext::make_tuple ( ext::to_string < typename std::decay < ParamTypes >::type > ( ), abstraction::ParamQualifiers::paramQualifiers < ParamTypes > ( ), std::move ( paramNames [ i ++ ] ) ) ), 0 ) ... };
+
+		auto & group = getEntries ( ) [ algorithm ];
+		for ( const ext::tuple < AlgorithmCategories::AlgorithmCategory, ext::vector < ext::tuple < std::string, ext::set < abstraction::ParamQualifiers::ParamQualifier >, std::string > >, ext::pair < ext::pair < std::string, ext::set < abstraction::ParamQualifiers::ParamQualifier > >, std::shared_ptr < Entry > > > & entry : group )
+			if ( std::get < 0 > ( entry ) == category && std::get < 1 > ( entry ) == params )
+				return;
+
+		ext::pair < std::string, ext::set < abstraction::ParamQualifiers::ParamQualifier > > result = ext::make_pair ( std::string ( "dynamic return type" ), ext::set < ParamQualifiers::ParamQualifier > { } );
+		ext::pair < ext::pair < std::string, ext::set < abstraction::ParamQualifiers::ParamQualifier > >, std::shared_ptr < Entry > > entryValue = ext::make_pair ( std::move ( result ), std::make_shared < WrapperImpl < ParamTypes ... > > ( callback ) );
+		group.push_back ( ext::make_tuple ( category, params, entryValue ) );
+	}
+
 	static std::shared_ptr < abstraction::OperationAbstraction > getAbstraction ( const std::string & name, const ext::vector < std::string > & paramTypes, AlgorithmCategories::AlgorithmCategory category );
 
 	static ext::set < std::string > listGroup ( const std::string & group );
@@ -86,6 +119,7 @@ public:
 } /* namespace abstraction */
 
 #include <abstraction/AlgorithmAbstraction.hpp>
+#include <abstraction/WrapperAbstraction.hpp>
 
 namespace abstraction {
 
@@ -94,6 +128,11 @@ std::shared_ptr < abstraction::OperationAbstraction > AlgorithmRegistry::EntryIm
 	return std::make_shared < abstraction::AlgorithmAbstraction < Return, Params ... > > ( m_callback );
 }
 
+template < class ... Params >
+std::shared_ptr < abstraction::OperationAbstraction > AlgorithmRegistry::WrapperImpl < Params ... >::getAbstraction ( ) const {
+	return std::make_shared < abstraction::WrapperAbstraction < Params ... > > ( m_wrapperFinder );
+}
+
 } /* namespace abstraction */
 
 #endif /* _ALGORITHM_REGISTRY_HPP_ */
diff --git a/alib2common/src/abstraction/WrapperAbstraction.hpp b/alib2common/src/abstraction/WrapperAbstraction.hpp
new file mode 100644
index 0000000000..a11ff0fbd4
--- /dev/null
+++ b/alib2common/src/abstraction/WrapperAbstraction.hpp
@@ -0,0 +1,168 @@
+/*
+ * WrapperAbstraction.hpp
+ *
+ *  Created on: 11. 7. 2017
+ *	  Author: Jan Travnicek
+ */
+
+#ifndef _WRAPPER_ABSTRACTION_HPP_
+#define _WRAPPER_ABSTRACTION_HPP_
+
+#include <abstraction/OperationAbstraction.hpp>
+
+namespace abstraction {
+
+template < class ... ParamTypes >
+class WrapperAbstraction : public OperationAbstraction {
+	std::function < std::shared_ptr < OperationAbstraction > ( ParamTypes ... ) > m_WrapperFinder;
+
+	ext::variant < void, std::shared_ptr < OperationAbstraction > > m_data;
+
+protected:
+	ext::tuple < std::shared_ptr < ValueProvider < ParamTypes > > ... > m_params;
+	std::array < bool, sizeof ... ( ParamTypes ) > m_moves;
+
+public:
+	WrapperAbstraction ( std::function < std::shared_ptr < OperationAbstraction > ( ParamTypes ... ) > wrapperFinder ) : m_WrapperFinder ( wrapperFinder ) {
+		for ( unsigned i = 0; i < sizeof ... ( ParamTypes ); ++ i )
+			m_moves [ i ] = false;
+	}
+
+private:
+	virtual bool attachInput ( const std::shared_ptr < OperationAbstraction > & input, unsigned index, bool move ) override {
+		if ( index >= m_moves.size ( ) )
+			throw exception::CommonException ( "Parameter index out of bounds.");
+
+		auto attachCallback = [ & ] ( auto & param ) {
+			if ( param != nullptr )
+				return false;
+
+			typename std::decay < decltype ( param )>::type validData = std::dynamic_pointer_cast < typename std::decay < decltype ( param ) >::type::element_type > ( input->getProxyAbstraction ( ) );
+			if ( validData ) {
+				m_moves [ index ] = move;
+				param = validData;
+				return true;
+			} else {
+				return false;
+			}
+		};
+
+		return ext::call_on_nth < bool > ( m_params, index, attachCallback );
+	}
+
+	virtual bool detachInput ( unsigned index ) override {
+		if ( index >= m_moves.size ( ) )
+			throw exception::CommonException ( "Parameter index out of bounds.");
+
+		m_moves [ index ] = false;
+
+		auto detachCallback = [ & ] ( auto & param ) {
+			param = nullptr;
+			return true;
+		};
+
+		return ext::call_on_nth < bool > ( m_params, index, detachCallback );
+	}
+
+public:
+	virtual bool inputsReady ( ) const override {
+		auto readyCallback = [ ] ( const auto & param ) {
+			return ( bool ) param && param->isReady ( );
+		};
+
+		return ext::all_of ( m_params, readyCallback );
+	}
+
+	virtual bool inputsAttached ( ) const override {
+		auto attachedCallback = [ ] ( const auto & param ) {
+			return ( bool ) param;
+		};
+
+		return ext::all_of ( m_params, attachedCallback );
+	}
+
+private:
+	template < typename ... Ts, size_t ... Indexes >
+	inline void finder_helper ( const ext::tuple < Ts ... > & params, const std::array < bool, sizeof ... ( Indexes ) > moves, std::index_sequence < Indexes ... > ) {
+		/* make unused parameter warning go away in case of sizeof ... ( Ts ) == 0 */
+		( void ) params;
+		( void ) moves;
+
+		m_data = m_WrapperFinder ( std::get < Indexes > ( params )->getValue ( std::get < Indexes > ( moves ) ) ... );
+	}
+
+public:
+	virtual bool run ( ) override {
+		if ( m_data.is < void > ( ) )
+			this->finder_helper ( this->m_params, this->m_moves, std::make_index_sequence < sizeof ... ( ParamTypes ) > { } );
+
+		auto getParam = [ & ] ( auto & param ) {
+			return std::dynamic_pointer_cast < abstraction::OperationAbstraction > ( param );
+		};
+
+		std::shared_ptr < OperationAbstraction > abstraction = m_data.template get < std::shared_ptr < OperationAbstraction > > ( );
+		for ( unsigned index = 0; index < sizeof ... ( ParamTypes ); ++ index )
+			abstraction->attachInput ( ext::call_on_nth < std::shared_ptr < abstraction::OperationAbstraction > > ( m_params, index, getParam ), index, m_moves [ index ] );
+
+		return m_data.template get < std::shared_ptr < OperationAbstraction > > ( )->run ( );
+	}
+
+	virtual bool eval ( ) override {
+		if ( ! inputsAttached ( ) )
+			return false;
+
+		if ( this->cached ( ) )
+			return true;
+
+		auto evalCallback = [ ] ( const auto & param ) {
+			return param->eval ( );
+		};
+
+		if ( ! ext::all_of ( m_params, evalCallback ) )
+			return false;
+
+		return this->run ( );
+	}
+
+	virtual unsigned numberOfParams ( ) const override {
+		return sizeof ... ( ParamTypes );
+	}
+
+	bool isReady ( ) const override {
+		return m_data.template is < std::shared_ptr < OperationAbstraction > > ( ) && m_data.template get < std::shared_ptr < OperationAbstraction > > ( )->isReady ( );
+	}
+
+	virtual bool cached ( ) const override {
+		return isReady ( );
+	}
+
+	virtual ext::type_index getParamTypeIndex ( unsigned index ) const override {
+		auto callback = [ & ] ( auto & param ) {
+			return ext::type_index ( typeid ( typename std::decay < decltype ( param ) >::type::element_type::return_type ) );
+		};
+		return ext::call_on_nth < ext::type_index > ( m_params, index, callback );
+	}
+
+	virtual ext::type_index getReturnTypeIndex ( ) const override {
+		return getRuntimeReturnTypeIndex ( );
+	}
+
+	virtual ext::type_index getRuntimeReturnTypeIndex ( ) const override {
+		if ( isReady ( ) )
+			return m_data.template get < std::shared_ptr < OperationAbstraction > > ( )->getProxyAbstraction ( )->getRuntimeReturnTypeIndex ( );
+		else
+			throw exception::CommonException ( "Runtime type unknown before evaluation." );
+	}
+
+	virtual std::shared_ptr < abstraction::OperationAbstraction > getProxyAbstraction ( ) override {
+		if ( isReady ( ) )
+			return m_data.template get < std::shared_ptr < OperationAbstraction > > ( )->getProxyAbstraction ( );
+		else
+			throw exception::CommonException ( "Runtime type unknown before evaluation." );
+	}
+
+};
+
+} /* namespace abstraction */
+
+#endif /* _WRAPPER_ABSTRACTION_HPP_ */
diff --git a/alib2common/src/registration/AlgoRegistration.hpp b/alib2common/src/registration/AlgoRegistration.hpp
index 23a4927288..24a0946041 100644
--- a/alib2common/src/registration/AlgoRegistration.hpp
+++ b/alib2common/src/registration/AlgoRegistration.hpp
@@ -46,6 +46,18 @@ public:
 	}
 };
 
+template < class Algorithm, class ... ParameterTypes >
+class WrapperRegister : public AlgoRegister {
+public:
+	template < class ... ParamNames >
+	WrapperRegister ( std::shared_ptr < abstraction::OperationAbstraction > ( * callback ) ( ParameterTypes ... ), ParamNames ... paramNames ) {
+		std::array < std::string, sizeof ... ( ParameterTypes ) > parameterNames = generateNames < sizeof ... ( ParameterTypes ) > ( paramNames ... );
+
+		abstraction::AlgorithmRegistry::registerWrapper < Algorithm, ParameterTypes ... > ( callback, std::move ( parameterNames ) );
+	}
+
+};
+
 } /* namespace registration */
 
 #endif // _ALGO_REGISTRATION_HPP_
diff --git a/alib2xml/src/registration/XmlRegistration.hpp b/alib2xml/src/registration/XmlRegistration.hpp
index 2ae0b0d286..2348e266e9 100644
--- a/alib2xml/src/registration/XmlRegistration.hpp
+++ b/alib2xml/src/registration/XmlRegistration.hpp
@@ -6,6 +6,30 @@
 #include <abstraction/XmlComposerRegistry.hpp>
 #include <abstraction/XmlParserRegistry.hpp>
 
+#include <abstraction/XmlRegistry.h>
+#include <abstraction/AlgorithmRegistry.hpp>
+
+namespace xml {
+
+class Parse {
+public:
+	static std::shared_ptr < abstraction::OperationAbstraction > abstractionFromTokens ( ext::deque < sax::Token > && tokens ) {
+		return abstraction::XmlRegistry::getXmlParserAbstraction ( tokens [ 0 ].getData ( ) );
+	}
+
+};
+
+class Compose {
+public:
+	template < class Type >
+	static std::shared_ptr < abstraction::OperationAbstraction > abstractionFromType ( const Type & ) {
+		return abstraction::XmlRegistry::getXmlComposerAbstraction ( ext::to_string < Type > ( ) );
+	}
+
+};
+
+} /* namespace xml */
+
 namespace registration {
 
 template < class Group, class Type >
@@ -15,6 +39,7 @@ public:
 		alib::xmlApi < Group >::template registerXmlReader < Type > ( );
 
 		abstraction::XmlParserRegistry::registerXmlParser < Type > ( );
+		abstraction::AlgorithmRegistry::registerWrapper < xml::Parse, ext::deque < sax::Token > && > ( xml::Parse::abstractionFromTokens, std::array < std::string, 1 > { } );
 	}
 };
 
@@ -25,6 +50,7 @@ public:
 		alib::xmlApi < Group >::template registerXmlWriter < Type > ( );
 
 		abstraction::XmlComposerRegistry::registerXmlComposer < Type > ( );
+		abstraction::AlgorithmRegistry::registerWrapper < xml::Compose, const Type & > ( xml::Compose::abstractionFromType, std::array < std::string, 1 > { } );
 	}
 };
 
-- 
GitLab