/* * AlgorithmRegistry.hpp * * Created on: 11. 7. 2017 * Author: Jan Travnicek */ #ifndef _ALGORITHM_REGISTRY_HPP_ #define _ALGORITHM_REGISTRY_HPP_ #include <functional> #include <memory> #include <vector> #include <string> #include <exception/CommonException.h> #include <abstraction/OperationAbstraction.hpp> namespace abstraction { class AlgorithmRegistry { class Entry { bool m_downcast; bool m_normalize; public: Entry ( bool downcast, bool normalize ) : m_downcast ( downcast ), m_normalize ( normalize ) { } virtual std::shared_ptr < abstraction::OperationAbstraction > getAbstraction ( ) const = 0; bool getDowncast ( ) const { return m_downcast; } bool getNormalize ( ) const { return m_normalize; } }; template < class Return, class ... Params > class EntryImpl : public Entry { std::function < Return ( Params ... ) > m_callback; public: EntryImpl ( std::function < Return ( Params ... ) > callback, bool downcast, bool normalize ) : Entry ( downcast, normalize ), m_callback ( callback ) { } virtual std::shared_ptr < abstraction::OperationAbstraction > getAbstraction ( ) const override; }; template < class Return, class ... Params > class EntryImpl < Return *, Params ... > : public Entry { std::function < Return * ( Params ... ) > m_callback; public: EntryImpl ( std::function < Return * ( Params ... ) > callback, bool downcast, bool normalize ) : Entry ( downcast, normalize ), m_callback ( callback ) { } virtual std::shared_ptr < abstraction::OperationAbstraction > getAbstraction ( ) const override; }; static std::map < std::string, std::map < std::vector < std::type_index >, std::unique_ptr < Entry > > > & getEntries ( ) { static std::map < std::string, std::map < std::vector < std::type_index >, std::unique_ptr < Entry > > > algorithmGroups; return algorithmGroups; }; public: template < class Algo, class ReturnType, class ... ParamTypes > static void registerAlgorithm ( ReturnType ( * callback ) ( ParamTypes ... ), bool downcast, bool normalize ) { std::string algorithm = std::type_name < Algo > ( ); std::vector < std::type_index > params; ( void ) std::initializer_list < int > { ( params.push_back ( std::type_index ( typeid ( typename std::decay < ParamTypes >::type ) ) ), 0 ) ... }; if ( ! getEntries ( ) [ algorithm ].insert ( std::make_pair ( params, std::unique_ptr < Entry > ( new EntryImpl < ReturnType, ParamTypes ... > ( callback, downcast, normalize ) ) ) ).second ) throw ::exception::CommonException ( "Callback for " + algorithm + " already registered." ); } static std::shared_ptr < abstraction::OperationAbstraction > getAbstraction ( std::string name, const std::vector < std::type_index > & paramTypes, bool & downcast, bool & normalize ) { auto group = getEntries ( ).find ( name ); if ( group == getEntries ( ).end ( ) ) throw exception::CommonException ( "Entry " + name + " not available" ); auto overload = group->second.find ( paramTypes ); if ( overload == group->second.end ( ) ) { std::stringstream ss; ss << paramTypes; throw exception::CommonException ( "Entry overload " + ss.str ( ) + " not available" ); } downcast = overload->second->getDowncast ( ); normalize = overload->second->getNormalize ( ); return overload->second->getAbstraction ( ); } static std::shared_ptr < abstraction::OperationAbstraction > getAbstraction ( std::string name, const std::vector < std::type_index > & paramTypes ) { bool downcast; bool normalize; return getAbstraction ( std::move ( name ), paramTypes, downcast, normalize ); } static void listOverloads ( const std::string & algorithm ) { auto group = getEntries ( ).find ( algorithm ); if ( group == getEntries ( ).end ( ) ) throw exception::CommonException ( "Entry " + algorithm + " not available" ); for ( const std::pair < const std::vector < std::type_index >, std::unique_ptr < Entry > > & overloads : group->second ) { for ( const std::type_index & param : overloads.first ) { std::cout << param << " " << std::endl; } } } static void list ( ) { for ( const std::pair < const std::string, std::map < std::vector < std::type_index >, std::unique_ptr < Entry > > > & entry : getEntries ( ) ) { std::cout << entry.first << std::endl; } } }; } /* namespace abstraction */ #include <abstraction/AlgorithmAbstraction.hpp> namespace abstraction { 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 Return, class ... Params > std::shared_ptr < abstraction::OperationAbstraction > AlgorithmRegistry::EntryImpl < Return *, Params ... >::getAbstraction ( ) const { return std::make_shared < abstraction::AlgorithmAbstraction < Return *, Params ... > > ( m_callback ); } } /* namespace abstraction */ #endif /* _ALGORITHM_REGISTRY_HPP_ */