Newer
Older
/*
* AlgorithmRegistry.cpp
*
* Created on: 19. 8. 2017
* Author: Jan Travnicek
*/
#include <registry/AlgorithmRegistry.hpp>
#include <registry/CastRegistry.hpp>
#include <alib/foreach>
#include <alib/typeinfo>
bool AlgorithmRegistry::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 ) {
auto & group = getEntries ( ) [ ext::make_pair ( algorithm, templateParams ) ];
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, 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 ) {
auto & group = getEntries ( ) [ ext::make_pair ( std::move ( algorithm ), std::move ( templateParams ) ) ];
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 > & templateParams, const ext::vector < std::string > & paramTypes, AlgorithmCategories::AlgorithmCategory ) {
auto group = getEntries ( ).find ( ext::make_pair ( name, templateParams ) );
if ( group == getEntries ( ).end ( ) ) {
for ( auto iter = getEntries ( ).begin ( ); iter != getEntries ( ).end ( ); ++ iter ) {
if ( ext::is_same_type ( name, iter->first.first ) && ext::are_same_types ( templateParams, iter->first.second ) ) {
if ( group == getEntries ( ).end ( ) )
group = iter;
throw std::invalid_argument ( "Name " + name + " is ambigous " );
else
throw std::invalid_argument ( "Templated name " + name + " < " + ext::to_string ( templateParams ) + " > is ambigous " );
if ( group == getEntries ( ).end ( ) ) {
if ( templateParams.size ( ) == 0 )
throw std::invalid_argument ( "Entry " + name + " not available" );
else
throw std::invalid_argument ( "Templated entry " + name + " < " + ext::to_string ( templateParams ) + " > 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 ] ) {
} 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 ) {
// throw std::invalid_argument ( "Entry overload " + ext::to_string ( paramTypes ) + " 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;*/
if ( templateParams.size ( ) == 0 )
throw std::invalid_argument ( "Entry overload " + name + " " + ext::to_string ( paramTypes ) + " not available" );
else
throw std::invalid_argument ( "Templated entry overload " + name + " < " + ext::to_string ( templateParams ) + " > " + ext::to_string ( paramTypes ) + " not available" );
}
return best->getAbstraction ( );
}
ext::set < ext::pair < std::string, ext::vector < std::string > > > AlgorithmRegistry::listGroup ( const std::string & group ) {
ext::set < ext::pair < std::string, ext::vector < std::string > > > res;
for ( const std::pair < const 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 > > > > > & entry : getEntries ( ) )
if ( entry.first.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, const ext::vector < std::string > & templateParams ) {
auto group = getEntries ( ).find ( ext::make_pair ( algorithm, templateParams ) );
if ( group == getEntries ( ).end ( ) ) {
if ( templateParams.size ( ) == 0 )
throw std::invalid_argument ( "Entry " + algorithm + " not available" );
else
throw std::invalid_argument ( "Templated entry " + algorithm + " < " + ext::to_string ( templateParams ) + " > 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 ) ) );
ext::set < ext::pair < std::string, ext::vector < std::string > > > AlgorithmRegistry::list ( ) {
ext::set < ext::pair < std::string, ext::vector < std::string > > > res;
for ( const std::pair < const 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 > > > > > & entry : getEntries ( ) )
}
} /* namespace abstraction */