From ddb993b049b444f20e42823f09266ed808bd2f6f Mon Sep 17 00:00:00 2001 From: Jan Travnicek <Jan.Travnicek@fit.cvut.cz> Date: Sat, 19 Aug 2017 18:35:05 +0200 Subject: [PATCH] prepare getAbstraction for qualifiers support --- .../src/abstraction/AlgorithmRegistry.hpp | 151 +++++++++++++----- .../abstraction/common/ParamQualifiers.hpp | 36 +++++ 2 files changed, 147 insertions(+), 40 deletions(-) create mode 100644 alib2common/src/abstraction/common/ParamQualifiers.hpp diff --git a/alib2common/src/abstraction/AlgorithmRegistry.hpp b/alib2common/src/abstraction/AlgorithmRegistry.hpp index 886ff17013..4957b35cb6 100644 --- a/alib2common/src/abstraction/AlgorithmRegistry.hpp +++ b/alib2common/src/abstraction/AlgorithmRegistry.hpp @@ -12,11 +12,14 @@ #include <memory> #include <vector> #include <string> +#include <foreach> #include <exception/CommonException.h> #include <abstraction/OperationAbstraction.hpp> #include <abstraction/CastRegistry.hpp> +#include <abstraction/common/ParamQualifiers.hpp> + namespace abstraction { class AlgorithmRegistry { @@ -61,8 +64,8 @@ class AlgorithmRegistry { virtual std::shared_ptr < abstraction::OperationAbstraction > getAbstraction ( ) const override; }; - static ext::map < std::string, ext::map < ext::vector < std::string >, std::unique_ptr < Entry > > > & getEntries ( ) { - static ext::map < std::string, ext::map < ext::vector < std::string >, std::unique_ptr < Entry > > > algorithmGroups; + static ext::map < std::string, ext::vector < std::pair < ext::vector < std::pair < std::string, ext::set < abstraction::ParamQualifiers::ParamQualifier > > >, std::shared_ptr < Entry > > > > & getEntries ( ) { + static ext::map < std::string, ext::vector < std::pair < ext::vector < std::pair < std::string, ext::set < abstraction::ParamQualifiers::ParamQualifier > > >, std::shared_ptr < Entry > > > > algorithmGroups; return algorithmGroups; }; @@ -76,11 +79,16 @@ public: static void registerAlgorithm ( ReturnType ( * callback ) ( ParamTypes ... ), bool downcast, bool normalize ) { std::string algorithm = ext::to_string < Algo > ( ); - ext::vector < std::string > params; - ( void ) std::initializer_list < int > { ( params.push_back ( ext::to_string < typename std::decay < ParamTypes >::type > ( ) ), 0 ) ... }; + ext::vector < std::pair < std::string, ext::set < abstraction::ParamQualifiers::ParamQualifier > > > params; + ( void ) std::initializer_list < int > { ( params.push_back ( std::make_pair ( ext::to_string < typename std::decay < ParamTypes >::type > ( ), abstraction::ParamQualifiers::paramQualifiers < ParamTypes > ( ) ) ), 0 ) ... }; + + auto & group = getEntries ( ) [ algorithm ]; + for ( const std::pair < ext::vector < std::pair < std::string, ext::set < abstraction::ParamQualifiers::ParamQualifier > > >, std::shared_ptr < Entry > > & entry : group ) + if ( entry.first == params ) + throw exception::CommonException ( "Callback for " + algorithm + " already registered." ); - 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." ); + auto entryValue = std::make_pair ( params, std::shared_ptr < Entry > ( new EntryImpl < ReturnType, ParamTypes ... > ( callback, downcast, normalize ) ) ); + group.push_back ( std::move ( entryValue ) ); } static std::shared_ptr < abstraction::OperationAbstraction > getAbstraction ( const std::string & name, const ext::vector < std::string > & paramTypes, bool & downcast, bool & normalize ) { @@ -88,49 +96,100 @@ public: if ( group == getEntries ( ).end ( ) ) throw exception::CommonException ( "Entry " + name + " not available" ); - auto overload = group->second.find ( paramTypes ); - if ( overload == group->second.end ( ) ) { - std::vector < std::pair < std::vector < MatchType >, std::map < ext::vector < std::string >, std::unique_ptr < Entry > >::iterator > > compatibilityData; - for ( auto iter = group->second.begin ( ); iter != group->second.end ( ); ++ iter ) { - if ( iter->first.size ( ) != paramTypes.size ( ) ) - continue; - - std::vector < MatchType > compatibilityVector; - for ( unsigned i = 0; i < paramTypes.size ( ); ++ i ) { - if ( iter->first [ i ] == paramTypes [ i ] ) { - compatibilityVector.push_back ( MatchType::EXACT ); - } else if ( abstraction::CastRegistry::castAvailable ( iter->first [ i ], paramTypes [ i ] ) ) { - compatibilityVector.push_back ( MatchType::CAST ); - } else { - compatibilityVector.push_back ( MatchType::INCOMPATIBLE ); - } + 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::pair < std::string, ext::set < abstraction::ParamQualifiers::ParamQualifier > > >, 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 ( entry.first [ i ].first == paramTypes [ i ] ) { + matchType = MatchType::EXACT; + } else if ( abstraction::CastRegistry::castAvailable ( entry.first [ i ].first, paramTypes [ i ] ) ) { + matchType = MatchType::CAST; + } else { + matchType = MatchType::INCOMPATIBLE; } - if ( std::none_of ( compatibilityVector.begin(), compatibilityVector.end(), [] ( MatchType & matchType ) { return matchType == MatchType::INCOMPATIBLE; } ) ) { - compatibilityData.push_back ( std::make_pair ( std::move ( compatibilityVector ), iter ) ); - } + compatibilityVector.push_back ( ext::make_tuple ( matchType, entry.first [ i ].first, entry.first [ i ].second ) ); + } + + // 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; } - if ( compatibilityData.size ( ) == 1 ) { - overload = compatibilityData [ 0 ].second; - } else if ( compatibilityData.size ( ) > 1 ) { - std::stringstream ss; - ss << paramTypes; + 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 ); - throw exception::CommonException ( "Entry overload " + ss.str ( ) + " ambiguous." ); + ++ 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 ( overload == group->second.end ( ) ) { + + // 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 = overload->second->getDowncast ( ); - normalize = overload->second->getNormalize ( ); + downcast = best->getDowncast ( ); + normalize = best->getNormalize ( ); - return overload->second->getAbstraction ( ); + return best->getAbstraction ( ); } static std::shared_ptr < abstraction::OperationAbstraction > getAbstraction ( const std::string & name, const ext::vector < std::string > & paramTypes ) { @@ -140,7 +199,7 @@ public: } static void listGroup ( const std::string & group ) { - for ( const std::pair < const std::string, ext::map < ext::vector < std::string >, std::unique_ptr < Entry > > > & entry : getEntries ( ) ) { + for ( const std::pair < const std::string, ext::vector < std::pair < ext::vector < std::pair < std::string, ext::set < abstraction::ParamQualifiers::ParamQualifier > > >, std::shared_ptr < Entry > > > > & entry : getEntries ( ) ) { if ( entry.first.find ( group ) == 0 ) //found at the begining std::cout << entry.first << std::endl; } @@ -151,15 +210,27 @@ public: if ( group == getEntries ( ).end ( ) ) throw exception::CommonException ( "Entry " + algorithm + " not available" ); - for ( const std::pair < const ext::vector < std::string >, std::unique_ptr < Entry > > & overloads : group->second ) { - for ( const std::string & param : overloads.first ) { - std::cout << param << " " << std::endl; + for ( const std::pair < ext::vector < std::pair < std::string, ext::set < abstraction::ParamQualifiers::ParamQualifier > > >, std::shared_ptr < Entry > > & overloads : group->second ) { + for ( const std::pair < std::string, ext::set < abstraction::ParamQualifiers::ParamQualifier > > & param : overloads.first ) { + if ( param.second.count ( abstraction::ParamQualifiers::ParamQualifier::CONST ) ) + std::cout << "const "; + + std::cout << param.first; + + if ( param.second.count ( abstraction::ParamQualifiers::ParamQualifier::LREF ) ) + std::cout << " &"; + + if ( param.second.count ( abstraction::ParamQualifiers::ParamQualifier::RREF ) ) + std::cout << " &"; + + std::cout << ", "; } + std::cout << std::endl; } } static void list ( ) { - for ( const std::pair < const std::string, ext::map < ext::vector < std::string >, std::unique_ptr < Entry > > > & entry : getEntries ( ) ) { + for ( const std::pair < const std::string, ext::vector < std::pair < ext::vector < std::pair < std::string, ext::set < abstraction::ParamQualifiers::ParamQualifier > > >, std::shared_ptr < Entry > > > > & entry : getEntries ( ) ) { std::cout << entry.first << std::endl; } } diff --git a/alib2common/src/abstraction/common/ParamQualifiers.hpp b/alib2common/src/abstraction/common/ParamQualifiers.hpp new file mode 100644 index 0000000000..ab729b9dd0 --- /dev/null +++ b/alib2common/src/abstraction/common/ParamQualifiers.hpp @@ -0,0 +1,36 @@ +#ifndef _PARAM_QUALIFIERS_HPP_ +#define _PARAM_QUALIFIERS_HPP_ + +#include <set> +#include <type_traits> + +namespace abstraction { + +class ParamQualifiers { +public: + enum class ParamQualifier { + CONST, + LREF, + RREF, + }; + + template < class Param > + static ext::set < ParamQualifier > paramQualifiers ( ) { + ext::set < ParamQualifier > res; + + if ( std::is_lvalue_reference < Param >::value ) + res.insert ( ParamQualifier::LREF ); + + if ( std::is_rvalue_reference < Param >::value ) + res.insert ( ParamQualifier::RREF ); + + if ( std::is_const < typename std::remove_reference < Param >::type >::value ) + res.insert ( ParamQualifier::CONST ); + + return res; + } +}; + +} /* namespace abstraction */ + +#endif // _PARAM_QUALIFIERS_HPP_ -- GitLab