Skip to content
Snippets Groups Projects
AlgorithmRegistry.hpp 11.5 KiB
Newer Older
  • Learn to ignore specific revisions
  • /*
     * AlgorithmRegistry.hpp
     *
     *  Created on: 11. 7. 2017
     *	  Author: Jan Travnicek
     */
    
    #ifndef _ALGORITHM_REGISTRY_HPP_
    #define _ALGORITHM_REGISTRY_HPP_
    
    
    #include <alib/functional>
    #include <alib/memory>
    #include <alib/vector>
    #include <alib/string>
    #include <alib/set>
    #include <alib/map>
    #include <alib/tuple>
    #include <alib/algorithm>
    
    #include <exception>
    
    #include <alib/typeinfo>
    
    
    #include <abstraction/OperationAbstraction.hpp>
    
    
    #include <common/ParamQualifiers.hpp>
    #include <common/AlgorithmCategories.hpp>
    
    namespace abstraction {
    
    class AlgorithmRegistry {
    	class Entry {
    	public:
    		virtual std::shared_ptr < abstraction::OperationAbstraction > getAbstraction ( ) const = 0;
    	};
    
    
    	template < class ObjectType, class Return, class ... Params >
    	class MemberImpl : public Entry {
    
    		std::function < Return ( typename std::remove_reference < ObjectType >::type *, Params ... ) > m_callback;
    
    		MemberImpl ( std::function < Return ( typename std::remove_reference < ObjectType >::type *, Params ... ) > callback ) : m_callback ( callback ) {
    
    		}
    
    		virtual std::shared_ptr < abstraction::OperationAbstraction > getAbstraction ( ) const override;
    	};
    
    
    	template < class Return, class ... Params >
    	class EntryImpl : public Entry {
    		std::function < Return ( Params ... ) > m_callback;
    
    	public:
    
    		EntryImpl ( std::function < Return ( Params ... ) > callback ) : m_callback ( callback ) {
    
    		}
    
    		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 < ext::pair < std::string, ext::vector < 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 < ext::pair < std::string, ext::vector < 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;
    	};
    
    
    	enum class MatchType {
    		EXACT,
    		CAST,
    		INCOMPATIBLE
    	};
    
    	template < class ParamType >
    	static ext::tuple < std::string, ext::set < abstraction::ParamQualifiers::ParamQualifier >, std::string > convertParamType ( std::string paramName ) {
    		return ext::make_tuple ( ext::to_string < typename std::decay < ParamType >::type > ( ), abstraction::ParamQualifiers::paramQualifiers < ParamType > ( ), std::move ( paramName ) );
    	}
    
    
    	template < class ... ParamTypes >
    	static ext::vector < ext::tuple < std::string, ext::set < abstraction::ParamQualifiers::ParamQualifier >, std::string > > convertParamTypes ( std::array < std::string, sizeof ... ( ParamTypes ) > paramNames ) {
    
    		/* make unused parameter warning go away in case of sizeof ... ( ParamTypes ) == 0 */
    		( void ) paramNames;
    
    
    		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 ( convertParamType < ParamTypes > ( std::move ( paramNames [ i ++ ] ) ) ), 0 ) ... };
    
    
    		return params;
    	}
    
    	static ext::pair < std::string, ext::set < abstraction::ParamQualifiers::ParamQualifier > > dynamicReturnType ( );
    
    	template < class ReturnType >
    	static ext::pair < std::string, ext::set < abstraction::ParamQualifiers::ParamQualifier > > convertReturnType ( ) {
    		return ext::make_pair ( ext::to_string < typename std::decay < ReturnType >::type > ( ), abstraction::ParamQualifiers::paramQualifiers < ReturnType > ( ) );
    	}
    
    
    	static bool isRegistered ( const std::string & algorithm, const ext::vector < std::string > & templateParams, AlgorithmCategories::AlgorithmCategory category, const ext::vector < ext::tuple < std::string, ext::set < abstraction::ParamQualifiers::ParamQualifier >, std::string > > & params );
    
    	static void registerInternal ( std::string algorithm, ext::vector < std::string > templateParams, AlgorithmCategories::AlgorithmCategory category, ext::pair < std::string, ext::set < abstraction::ParamQualifiers::ParamQualifier > > result, ext::vector < ext::tuple < std::string, ext::set < abstraction::ParamQualifiers::ParamQualifier >, std::string > > params, std::shared_ptr < Entry > value );
    
    	template < class Algo, class ObjectType, class ReturnType, class ... ParamTypes >
    	static void registerMethod ( ReturnType ( ObjectType:: * callback ) ( ParamTypes ... ), std::string methodName, std::array < std::string, sizeof ... ( ParamTypes ) > paramNames ) {
    		AlgorithmCategories::AlgorithmCategory category = AlgorithmCategories::AlgorithmCategory::DEFAULT;
    		std::string algorithm = ext::to_string < Algo > ( ) + "::" + methodName;
    
    		ext::vector < std::string > templateParams;
    
    
    		ext::vector < ext::tuple < std::string, ext::set < abstraction::ParamQualifiers::ParamQualifier >, std::string > > params = convertParamTypes < ParamTypes ... > ( paramNames );
    
    		params.insert ( params.begin ( ), convertParamType < ObjectType & > ( "object" ) );
    
    
    		ext::pair < std::string, ext::set < abstraction::ParamQualifiers::ParamQualifier > > result = convertReturnType < ReturnType > ( );
    
    
    		if ( isRegistered ( algorithm, templateParams, category, params ) )
    
    			throw std::invalid_argument ( "Callback for " + algorithm + " already registered." );
    
    		registerInternal ( std::move ( algorithm ), std::move ( templateParams ), category, std::move ( result ), std::move ( params ), std::make_shared < MemberImpl < ObjectType &, ReturnType, ParamTypes ... > > ( callback ) );
    
    	template < class Algo, class ObjectType, class ReturnType, class ... ParamTypes >
    	static void registerMethod ( ReturnType ( ObjectType:: * callback ) ( ParamTypes ... ) const, std::string methodName, std::array < std::string, sizeof ... ( ParamTypes ) > paramNames ) {
    		AlgorithmCategories::AlgorithmCategory category = AlgorithmCategories::AlgorithmCategory::DEFAULT;
    		std::string algorithm = ext::to_string < Algo > ( ) + "::" + methodName;
    
    		ext::vector < std::string > templateParams;
    
    
    		ext::vector < ext::tuple < std::string, ext::set < abstraction::ParamQualifiers::ParamQualifier >, std::string > > params = convertParamTypes < ParamTypes ... > ( paramNames );
    		params.insert ( params.begin ( ), convertParamType < const ObjectType & > ( "object" ) );
    
    		ext::pair < std::string, ext::set < abstraction::ParamQualifiers::ParamQualifier > > result = convertReturnType < ReturnType > ( );
    
    
    		if ( isRegistered ( algorithm, templateParams, category, params ) )
    
    			throw std::invalid_argument ( "Callback for " + algorithm + " already registered." );
    
    		registerInternal ( std::move ( algorithm ), std::move ( templateParams ), category, std::move ( result ), std::move ( params ), std::make_shared < MemberImpl < const ObjectType &, ReturnType, ParamTypes ... > > ( callback ) );
    
    	template < class Algo, class ReturnType, class ... ParamTypes >
    
    	static void registerAlgorithm ( ReturnType ( * callback ) ( ParamTypes ... ), AlgorithmCategories::AlgorithmCategory category, std::array < std::string, sizeof ... ( ParamTypes ) > paramNames ) {
    
    		std::string algorithm = ext::to_string < Algo > ( );
    
    		ext::vector < std::string > templateParams;
    
    
    		ext::vector < ext::tuple < std::string, ext::set < abstraction::ParamQualifiers::ParamQualifier >, std::string > > params = convertParamTypes < ParamTypes ... > ( paramNames );
    		ext::pair < std::string, ext::set < abstraction::ParamQualifiers::ParamQualifier > > result = convertReturnType < ReturnType > ( );
    
    		if ( isRegistered ( algorithm, templateParams, category, params ) )
    
    			throw std::invalid_argument ( "Callback for " + algorithm + " already registered." );
    
    		registerInternal ( std::move ( algorithm ), std::move ( templateParams ), category, std::move ( result ), std::move ( params ), std::make_shared < EntryImpl < ReturnType, ParamTypes ... > > ( callback ) );
    
    	template < class Algo, class ... ParamTypes >
    	static void registerWrapper ( std::shared_ptr < abstraction::OperationAbstraction > ( * callback ) ( ParamTypes ... ), std::array < std::string, sizeof ... ( ParamTypes ) > paramNames ) {
    		AlgorithmCategories::AlgorithmCategory category = AlgorithmCategories::AlgorithmCategory::DEFAULT;
    
    		std::string algorithm = ext::to_string < Algo > ( );
    
    		ext::vector < std::string > templateParams = ext::get_template_info ( algorithm );
    		algorithm = ext::erase_template_info ( algorithm );
    
    
    		ext::vector < ext::tuple < std::string, ext::set < abstraction::ParamQualifiers::ParamQualifier >, std::string > > params = convertParamTypes < ParamTypes ... > ( paramNames );
    		ext::pair < std::string, ext::set < abstraction::ParamQualifiers::ParamQualifier > > result = dynamicReturnType ( );
    
    		if ( isRegistered ( algorithm, templateParams, category, params ) )
    
    		registerInternal ( std::move ( algorithm ), std::move ( templateParams ), category, std::move ( result ), std::move ( params ), std::make_shared < WrapperImpl < ParamTypes ... > > ( callback ) );
    
    	static std::shared_ptr < abstraction::OperationAbstraction > getAbstraction ( const std::string & name, const ext::vector < std::string > & templateParams, const ext::vector < std::string > & paramTypes, AlgorithmCategories::AlgorithmCategory category );
    
    	static ext::set < ext::pair < std::string, ext::vector < std::string > > > listGroup ( const std::string & group );
    
    	static ext::set < ext::tuple < AlgorithmCategories::AlgorithmCategory, ext::pair < std::string, ext::set < abstraction::ParamQualifiers::ParamQualifier > >, ext::vector < ext::tuple < std::string, ext::set < abstraction::ParamQualifiers::ParamQualifier >, std::string > > > > listOverloads ( const std::string & algorithm, const ext::vector < std::string > & templateParams );
    
    	static ext::set < ext::pair < std::string, ext::vector < std::string > > > list ( );
    
    };
    
    } /* namespace abstraction */
    
    
    #include <abstraction/MemberAbstraction.hpp>
    
    #include <abstraction/AlgorithmAbstraction.hpp>
    
    #include <abstraction/WrapperAbstraction.hpp>
    
    
    namespace abstraction {
    
    
    template < class Object, class Return, class ... Params >
    std::shared_ptr < abstraction::OperationAbstraction > AlgorithmRegistry::MemberImpl < Object, Return, Params ... >::getAbstraction ( ) const {
    	return std::make_shared < abstraction::MemberAbstraction < Object, Return, Params ... > > ( m_callback );
    }
    
    
    template < class Return, class ... Params >
    std::shared_ptr < abstraction::OperationAbstraction > AlgorithmRegistry::EntryImpl < Return, Params ... >::getAbstraction ( ) const {
    	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_ */