/* * AlgorithmRegistry.cpp * * Created on: 19. 8. 2017 * Author: Jan Travnicek */ #include <abstraction/AlgorithmRegistry.hpp> #include <abstraction/CastRegistry.hpp> #include <global/GlobalData.h> #include <foreach> namespace abstraction { ext::pair < std::string, ext::set < abstraction::ParamQualifiers::ParamQualifier > > AlgorithmRegistry::dynamicReturnType ( ) { return ext::make_pair ( std::string ( "dynamic return type" ), ext::set < ParamQualifiers::ParamQualifier > { } ); } bool AlgorithmRegistry::isRegistered ( const std::string & algorithm, AlgorithmCategories::AlgorithmCategory category, const ext::vector < ext::tuple < std::string, ext::set < abstraction::ParamQualifiers::ParamQualifier >, std::string > > & params ) { 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 true; return false; } void AlgorithmRegistry::registerInternal ( std::string algorithm, 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 ) { auto & group = getEntries ( ) [ algorithm ]; ext::pair < ext::pair < std::string, ext::set < abstraction::ParamQualifiers::ParamQualifier > >, std::shared_ptr < Entry > > entryValue = ext::make_pair ( std::move ( result ), std::move ( value ) ); group.push_back ( ext::make_tuple ( category, std::move ( params ), entryValue ) ); } std::shared_ptr < abstraction::OperationAbstraction > AlgorithmRegistry::getAbstraction ( const std::string & name, const ext::vector < std::string > & paramTypes, AlgorithmCategories::AlgorithmCategory ) { auto group = getEntries ( ).find ( name ); if ( group == getEntries ( ).end ( ) ) { for ( auto iter = getEntries ( ).begin ( ); iter != getEntries ( ).end ( ); ++ iter ) { if ( ext::is_same_type ( name, iter->first ) ) { if ( group == getEntries ( ).end ( ) ) group = iter; else throw exception::CommonException ( "Name " + name + " is ambigous " ); } } } if ( group == getEntries ( ).end ( ) ) throw exception::CommonException ( "Entry " + name + " not available" ); auto incompatibleLambda = [ ] ( const ext::tuple < MatchType, std::string, ext::set < abstraction::ParamQualifiers::ParamQualifier > > & compatibility ) { return std::get < 0 > ( compatibility ) == MatchType::INCOMPATIBLE; }; auto castLambda = [ ] ( const ext::tuple < MatchType, std::string, ext::set < abstraction::ParamQualifiers::ParamQualifier > > & compatibility ) { return std::get < 0 > ( compatibility ) == MatchType::CAST; }; auto exactLambda = [ ] ( const ext::tuple < MatchType, std::string, ext::set < abstraction::ParamQualifiers::ParamQualifier > > & compatibility ) { return std::get < 0 > ( compatibility ) == MatchType::EXACT; }; // determine how one can actually map what we have ( paramTypes ) as params to what is available as overloads ( group->second ) std::vector < std::pair < ext::vector < ext::tuple < MatchType, std::string, ext::set < abstraction::ParamQualifiers::ParamQualifier > > >, std::pair < std::pair < std::string, ext::set < abstraction::ParamQualifiers::ParamQualifier > >, std::shared_ptr < Entry > > > > compatibilityData; 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->second ) { if ( std::get < 1 > ( entry ).size ( ) != paramTypes.size ( ) ) continue; ext::vector < ext::tuple < MatchType, std::string, ext::set < abstraction::ParamQualifiers::ParamQualifier > > > compatibilityVector; for ( unsigned i = 0; i < paramTypes.size ( ); ++ i ) { MatchType matchType; if ( std::get < 0 > ( std::get < 1 > ( entry ) [ i ] ) == paramTypes [ i ] ) { matchType = MatchType::EXACT; } else if ( abstraction::CastRegistry::castAvailable ( std::get < 0 > ( std::get < 1 > ( entry ) [ i ] ), paramTypes [ i ] ) ) { matchType = MatchType::CAST; } else { matchType = MatchType::INCOMPATIBLE; } compatibilityVector.push_back ( ext::make_tuple ( matchType, std::get < 0 > ( std::get < 1 > ( entry ) [ i ] ), std::get < 1 > ( std::get < 1 > ( entry ) [ i ] ) ) ); } // clear incompatibilities are fitered out if ( std::none_of ( compatibilityVector.begin ( ), compatibilityVector.end ( ), incompatibleLambda ) ) compatibilityData.push_back ( std::make_pair ( std::move ( compatibilityVector ), std::get < 2 > ( entry ) ) ); } // remaining compatible overloads are examined per parameter and the best option is remembered as overload index that achieved it ext::vector < ext::set < unsigned > > winnerList; for ( unsigned i = 0; i < paramTypes.size ( ); ++ i ) { ext::set < unsigned > best; unsigned overload = 0; for ( const std::pair < ext::vector < ext::tuple < MatchType, std::string, ext::set < abstraction::ParamQualifiers::ParamQualifier > > >, std::pair < std::pair < std::string, ext::set < abstraction::ParamQualifiers::ParamQualifier > >, std::shared_ptr < Entry > > > & data : compatibilityData ) { if ( exactLambda ( data.first [ i ] ) ) best.insert ( overload ); ++ overload; } if ( best.size ( ) > 0 ) { winnerList.push_back ( std::move ( best ) ); continue; } overload = 0; for ( const std::pair < ext::vector < ext::tuple < MatchType, std::string, ext::set < abstraction::ParamQualifiers::ParamQualifier > > >, std::pair < std::pair < std::string, ext::set < abstraction::ParamQualifiers::ParamQualifier > >, std::shared_ptr < Entry > > > & data : compatibilityData ) { if ( castLambda ( data.first [ i ] ) ) best.insert ( overload ); ++ overload; } winnerList.push_back ( std::move ( best ) ); } // intersection of everything together finds indexes which are better or of the same quality for all params over all overloads ext::set < unsigned > winner { ext::sequence < unsigned > ( 0 ).begin ( ), ext::sequence < unsigned > ( compatibilityData.size ( ) ).end ( ) }; for ( const ext::set < unsigned > & best : winnerList ) { ext::set < unsigned > filtered; std::set_intersection ( winner.begin ( ), winner.end ( ), best.begin ( ), best.end ( ), std::inserter ( filtered, filtered.end ( ) ) ); winner = std::move ( filtered ); } // if there is a sinle winner, return it std::shared_ptr < Entry > best; if ( winner.size ( ) == 1 ) { best = compatibilityData [ * winner.begin ( ) ].second.second; } else if ( winner.size ( ) > 1 ) { std::stringstream ss; ss << paramTypes; // throw exception::CommonException ( "Entry overload " + ss.str ( ) + " ambiguous." ); FIXME make better overload select algorithm best = compatibilityData [ * winner.begin ( ) ].second.second; if(common::GlobalData::verbose) common::Streams::err << "Entry overload " + ss.str ( ) + " ambiguous. First selected." << std::endl; } else { std::stringstream ss; ss << paramTypes; throw exception::CommonException ( "Entry overload " + ss.str ( ) + " not available." ); } return best->getAbstraction ( ); } ext::set < std::string > AlgorithmRegistry::listGroup ( const std::string & group ) { ext::set < std::string > res; for ( const std::pair < const 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 > > > > > & entry : getEntries ( ) ) if ( entry.first.find ( group ) == 0 ) //found at the begining res.insert ( entry.first ); return res; } 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 > > > > AlgorithmRegistry::listOverloads ( const std::string & algorithm ) { auto group = getEntries ( ).find ( algorithm ); if ( group == getEntries ( ).end ( ) ) throw exception::CommonException ( "Entry " + algorithm + " not available" ); 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 > > > > res; 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 > > > & overloads : group->second ) res.insert ( ext::make_tuple ( std::get < 0 > ( overloads ), std::get < 2 > ( overloads ).first, std::get < 1 > ( overloads ) ) ); return res; } ext::set < std::string > AlgorithmRegistry::list ( ) { ext::set < std::string > res; for ( const std::pair < const 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 > > > > > & entry : getEntries ( ) ) res.insert ( entry.first ); return res; } } /* namespace abstraction */