Newer
Older
/*
* AlgorithmRegistry.cpp
*
* Created on: 19. 8. 2017
* Author: Jan Travnicek
*/
#include <abstraction/AlgorithmRegistry.hpp>
#include <abstraction/CastRegistry.hpp>
#include <foreach>
namespace abstraction {
std::shared_ptr < abstraction::OperationAbstraction > AlgorithmRegistry::getAbstraction ( const std::string & name, const ext::vector < std::string > & paramTypes, bool & downcast, bool & normalize ) {
auto group = getEntries ( ).find ( name );
if ( group == getEntries ( ).end ( ) ) {
ext::vector < std::string > explodedName = ext::explode ( name, "::" );
for ( auto iter = getEntries ( ).begin ( ); iter != getEntries ( ).end ( ); ++ iter ) {
ext::vector < std::string > explodedCandidate = ext::explode ( iter->first, "::" );
if ( explodedName.size ( ) > explodedCandidate.size ( ) )
continue;
unsigned offset = explodedCandidate.size ( ) - explodedName.size ( );
bool matches = true;
for ( unsigned index = 0; index < explodedName.size ( ); ++ index ) {
if ( explodedName [ index ] == "" )
continue;
if ( explodedName [ index ] != explodedCandidate [ index + offset ] ) {
matches = false;
break;
}
}
if ( matches ) {
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::shared_ptr < Entry > > > compatibilityData;
for ( const std::pair < ext::vector < std::tuple < std::string, ext::set < abstraction::ParamQualifiers::ParamQualifier >, std::string > >, std::shared_ptr < Entry > > & entry : group->second ) {
if ( entry.first.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 > ( entry.first [ i ] ) == paramTypes [ i ] ) {
} else if ( abstraction::CastRegistry::castAvailable ( std::get < 0 > ( entry.first [ i ] ), paramTypes [ i ] ) ) {
matchType = MatchType::CAST;
} else {
matchType = MatchType::INCOMPATIBLE;
}
compatibilityVector.push_back ( ext::make_tuple ( matchType, std::get < 0 > ( entry.first [ i ] ), std::get < 1 > ( entry.first [ i ] ) ) );
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
}
// clear incompatibilities are fitered out
if ( std::none_of ( compatibilityVector.begin ( ), compatibilityVector.end ( ), incompatibleLambda ) )
compatibilityData.push_back ( std::make_pair ( std::move ( compatibilityVector ), entry.second ) );
}
// 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::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::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 std::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;
} else if ( winner.size ( ) > 1 ) {
std::stringstream ss;
ss << paramTypes;
throw exception::CommonException ( "Entry overload " + ss.str ( ) + " ambiguous." );
} else {
std::stringstream ss;
ss << paramTypes;
throw exception::CommonException ( "Entry overload " + ss.str ( ) + " not available." );
}
downcast = best->getDowncast ( );
normalize = best->getNormalize ( );
return best->getAbstraction ( );
}
std::shared_ptr < abstraction::OperationAbstraction > AlgorithmRegistry::getAbstraction ( const std::string & name, const ext::vector < std::string > & paramTypes ) {
bool downcast;
bool normalize;
return getAbstraction ( name, paramTypes, downcast, normalize );
}
void AlgorithmRegistry::listGroup ( const std::string & group ) {
for ( const std::pair < const std::string, ext::vector < std::pair < ext::vector < std::tuple < std::string, ext::set < abstraction::ParamQualifiers::ParamQualifier >, std::string > >, std::shared_ptr < Entry > > > > & entry : getEntries ( ) ) {
if ( entry.first.find ( group ) == 0 ) //found at the begining
std::cout << entry.first << std::endl;
}
}
void AlgorithmRegistry::listOverloads ( const std::string & algorithm ) {
auto group = getEntries ( ).find ( algorithm );
if ( group == getEntries ( ).end ( ) )
throw exception::CommonException ( "Entry " + algorithm + " not available" );
bool first = true;
for ( const std::pair < ext::vector < std::tuple < std::string, ext::set < abstraction::ParamQualifiers::ParamQualifier >, std::string > >, std::shared_ptr < Entry > > & overloads : group->second ) {
for ( const std::tuple < std::string, ext::set < abstraction::ParamQualifiers::ParamQualifier >, std::string > & param : overloads.first ) {
if ( first )
first = false;
else
std::cout << ", ";
if ( std::get < 1 > ( param ).count ( abstraction::ParamQualifiers::ParamQualifier::CONST ) )
std::cout << std::get < 0 > ( param );
if ( std::get < 1 > ( param ).count ( abstraction::ParamQualifiers::ParamQualifier::LREF ) )
if ( std::get < 1 > ( param ).count ( abstraction::ParamQualifiers::ParamQualifier::RREF ) )
std::cout << " " << std::get < 2 > ( param );
}
std::cout << std::endl;
}
}
void AlgorithmRegistry::list ( ) {
for ( const std::pair < const std::string, ext::vector < std::pair < ext::vector < std::tuple < std::string, ext::set < abstraction::ParamQualifiers::ParamQualifier >, std::string > >, std::shared_ptr < Entry > > > > & entry : getEntries ( ) ) {
std::cout << entry.first << std::endl;
}
}
} /* namespace abstraction */