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