/* * WrapperAbstraction.hpp * * Created on: 11. 7. 2017 * Author: Jan Travnicek */ #ifndef _WRAPPER_ABSTRACTION_HPP_ #define _WRAPPER_ABSTRACTION_HPP_ #include <abstraction/OperationAbstraction.hpp> #include <optional> namespace abstraction { class UnspecifiedType { }; template < class ... ParamTypes > class BaseWrapperAbstraction : public OperationAbstraction { std::function < std::shared_ptr < OperationAbstraction > ( ParamTypes ... ) > m_WrapperFinder; std::shared_ptr < OperationAbstraction > m_abstraction; ext::array < std::pair < std::shared_ptr < OperationAbstraction >, bool >, sizeof ... ( ParamTypes ) > m_params; protected: void evalAbstractionFunction ( ) { m_abstraction = abstraction::apply < ParamTypes ... > ( m_WrapperFinder, m_params ); } std::shared_ptr < OperationAbstraction > & getAbstraction ( ) { return m_abstraction; } const std::shared_ptr < OperationAbstraction > & getAbstraction ( ) const { return m_abstraction; } void attachInputsToAbstraction ( ) { for ( size_t index = 0; index < sizeof ... ( ParamTypes ); ++ index ) if ( ! this->m_abstraction->attachInput ( m_params [ index ].first, index, m_params [ index ].second, true ) ) throw std::invalid_argument ( "Can't connect param " + this->m_abstraction->getParamType ( index ) + " at " + ext::to_string ( index ) + " of wrapped algorithm with result of type " + m_params [ index ].first->getReturnType ( ) + "." ); } public: BaseWrapperAbstraction ( std::function < std::shared_ptr < OperationAbstraction > ( ParamTypes ... ) > wrapperFinder ) : m_WrapperFinder ( std::move ( wrapperFinder ) ) { for ( size_t i = 0; i < sizeof ... ( ParamTypes ); ++ i ) { m_params [ i ].first = nullptr; m_params [ i ].second = false; } } private: bool attachInput ( const std::shared_ptr < OperationAbstraction > & input, size_t index, bool move, bool checkInput ) override { if ( index >= m_params.size ( ) ) throw std::invalid_argument ( "Parameter index " + ext::to_string ( index ) + " out of bounds."); if ( input == nullptr ) return false; if ( checkInput && ! this->checkInput ( input, index ) ) return false; m_params [ index ].first = input; m_params [ index ].second = move; return true; } bool detachInput ( size_t index ) override { if ( index >= m_params.size ( ) ) throw std::invalid_argument ( "Parameter index " + ext::to_string ( index ) + " out of bounds."); m_params [ index ].first = nullptr; m_params [ index ].second = false; return true; } bool checkInput ( const std::shared_ptr < OperationAbstraction > & input, size_t index ) const override { return abstraction::checkInput < ValueInterface < std::decay_t < ParamTypes > > ... > ( input, index ); } public: bool inputsAttached ( ) const override { for ( const std::pair < std::shared_ptr < OperationAbstraction >, bool > & param : m_params ) if ( ! param.first ) return false; return true; } public: bool eval ( ) override { if ( ! inputsAttached ( ) ) return false; if ( this->evaluated ( ) ) return true; for ( const std::pair < std::shared_ptr < OperationAbstraction >, bool > & param : m_params ) if ( ! param.first->eval ( ) ) return false; return this->run ( ); } size_t numberOfParams ( ) const override { return sizeof ... ( ParamTypes ); } bool evaluated ( ) const override { return ( bool ) m_abstraction && m_abstraction->evaluated ( ); } ext::type_index getParamTypeIndex ( size_t index ) const override { return abstraction::paramType < ParamTypes ... > ( index ); } ext::set < abstraction::ParamQualifiers::ParamQualifier > getParamTypeQualifiers ( size_t index ) const override { return abstraction::paramTypeQualifiers < ParamTypes ... > ( index ); } std::shared_ptr < abstraction::OperationAbstraction > getProxyAbstraction ( ) override { if ( this->evaluated ( ) ) return this->m_abstraction->getProxyAbstraction ( ); else throw std::domain_error ( "Proxy abstraction not avaiable before evaluation." ); } std::shared_ptr < abstraction::OperationAbstraction > getVariableOperationAbstraction ( ) override { if ( this->evaluated ( ) ) return this->getAbstraction ( )->getProxyAbstraction ( )->getVariableOperationAbstraction ( ); else throw std::domain_error ( "Variable deduction not available before evaluation." ); } }; template < class ReturnType, class ... ParamTypes > class WrapperAbstraction : public BaseWrapperAbstraction < ParamTypes ... > { public: WrapperAbstraction ( std::function < std::shared_ptr < OperationAbstraction > ( ParamTypes ... ) > wrapperFinder ) : BaseWrapperAbstraction < ParamTypes ... > ( wrapperFinder ) { } bool run ( ) override { this->evalAbstractionFunction ( ); if ( this->getAbstraction ( )->getReturnTypeIndex ( ) != this->getReturnTypeIndex ( ) ) throw std::domain_error ( "Expected and provided types do not match" ); this->attachInputsToAbstraction ( ); return this->getAbstraction ( )->eval ( ); } ext::type_index getReturnTypeIndex ( ) const override { return ext::type_index ( typeid ( ReturnType ) ); } ext::set < abstraction::ParamQualifiers::ParamQualifier > getReturnTypeQualifiers ( ) const override { return abstraction::ParamQualifiers::paramQualifiers < ReturnType > ( ); } }; template < class ... ParamTypes > class WrapperAbstraction < UnspecifiedType, ParamTypes ... > : public BaseWrapperAbstraction < ParamTypes ... > { public: WrapperAbstraction ( std::function < std::shared_ptr < OperationAbstraction > ( ParamTypes ... ) > wrapperFinder ) : BaseWrapperAbstraction < ParamTypes ... > ( wrapperFinder ) { } bool run ( ) override { this->evalAbstractionFunction ( ); this->attachInputsToAbstraction ( ); return this->getAbstraction ( )->eval ( ); } ext::type_index getReturnTypeIndex ( ) const override { if ( this->evaluated ( ) ) return this->getAbstraction ( )->getProxyAbstraction ( )->getReturnTypeIndex ( ); else throw std::domain_error ( "Return type unknown before evaluation." ); } ext::set < abstraction::ParamQualifiers::ParamQualifier > getReturnTypeQualifiers ( ) const override { if ( this->evaluated ( ) ) return this->getAbstraction ( )->getProxyAbstraction ( )->getReturnTypeQualifiers ( ); else throw std::domain_error ( "Return type qualifiers unknown before evaluation." ); } }; } /* namespace abstraction */ #endif /* _WRAPPER_ABSTRACTION_HPP_ */