Skip to content
Snippets Groups Projects
WrapperAbstraction.hpp 5.33 KiB
Newer Older
  • Learn to ignore specific revisions
  • /*
     * WrapperAbstraction.hpp
     *
     *  Created on: 11. 7. 2017
     *	  Author: Jan Travnicek
     */
    
    #ifndef _WRAPPER_ABSTRACTION_HPP_
    #define _WRAPPER_ABSTRACTION_HPP_
    
    #include <abstraction/OperationAbstraction.hpp>
    
    namespace abstraction {
    
    template < class ... ParamTypes >
    class WrapperAbstraction : public OperationAbstraction {
    	std::function < std::shared_ptr < OperationAbstraction > ( ParamTypes ... ) > m_WrapperFinder;
    
    	ext::variant < void, std::shared_ptr < OperationAbstraction > > m_data;
    
    protected:
    	ext::tuple < std::shared_ptr < ValueProvider < ParamTypes > > ... > m_params;
    	std::array < bool, sizeof ... ( ParamTypes ) > m_moves;
    
    public:
    	WrapperAbstraction ( std::function < std::shared_ptr < OperationAbstraction > ( ParamTypes ... ) > wrapperFinder ) : m_WrapperFinder ( wrapperFinder ) {
    		for ( unsigned i = 0; i < sizeof ... ( ParamTypes ); ++ i )
    			m_moves [ i ] = false;
    	}
    
    private:
    	virtual bool attachInput ( const std::shared_ptr < OperationAbstraction > & input, unsigned index, bool move ) override {
    		if ( index >= m_moves.size ( ) )
    
    			throw std::invalid_argument ( "Parameter index " + ext::to_string ( index ) + " out of bounds.");
    
    
    		auto attachCallback = [ & ] ( auto & param ) {
    			if ( param != nullptr )
    				return false;
    
    			typename std::decay < decltype ( param )>::type validData = std::dynamic_pointer_cast < typename std::decay < decltype ( param ) >::type::element_type > ( input->getProxyAbstraction ( ) );
    			if ( validData ) {
    				m_moves [ index ] = move;
    				param = validData;
    				return true;
    			} else {
    				return false;
    			}
    		};
    
    		return ext::call_on_nth < bool > ( m_params, index, attachCallback );
    	}
    
    	virtual bool detachInput ( unsigned index ) override {
    		if ( index >= m_moves.size ( ) )
    
    			throw std::invalid_argument ( "Parameter index " + ext::to_string ( index ) + " out of bounds.");
    
    
    		m_moves [ index ] = false;
    
    		auto detachCallback = [ & ] ( auto & param ) {
    			param = nullptr;
    			return true;
    		};
    
    		return ext::call_on_nth < bool > ( m_params, index, detachCallback );
    	}
    
    public:
    	virtual bool inputsReady ( ) const override {
    		auto readyCallback = [ ] ( const auto & param ) {
    			return ( bool ) param && param->isReady ( );
    		};
    
    		return ext::all_of ( m_params, readyCallback );
    	}
    
    	virtual bool inputsAttached ( ) const override {
    		auto attachedCallback = [ ] ( const auto & param ) {
    			return ( bool ) param;
    		};
    
    		return ext::all_of ( m_params, attachedCallback );
    	}
    
    private:
    	template < typename ... Ts, size_t ... Indexes >
    	inline void finder_helper ( const ext::tuple < Ts ... > & params, const std::array < bool, sizeof ... ( Indexes ) > moves, std::index_sequence < Indexes ... > ) {
    		/* make unused parameter warning go away in case of sizeof ... ( Ts ) == 0 */
    		( void ) params;
    		( void ) moves;
    
    		m_data = m_WrapperFinder ( std::get < Indexes > ( params )->getValue ( std::get < Indexes > ( moves ) ) ... );
    	}
    
    public:
    	virtual bool run ( ) override {
    		if ( m_data.is < void > ( ) )
    			this->finder_helper ( this->m_params, this->m_moves, std::make_index_sequence < sizeof ... ( ParamTypes ) > { } );
    
    		auto getParam = [ & ] ( auto & param ) {
    			return std::dynamic_pointer_cast < abstraction::OperationAbstraction > ( param );
    		};
    
    		std::shared_ptr < OperationAbstraction > abstraction = m_data.template get < std::shared_ptr < OperationAbstraction > > ( );
    		for ( unsigned index = 0; index < sizeof ... ( ParamTypes ); ++ index )
    			abstraction->attachInput ( ext::call_on_nth < std::shared_ptr < abstraction::OperationAbstraction > > ( m_params, index, getParam ), index, m_moves [ index ] );
    
    
    		return abstraction->run ( );
    
    	}
    
    	virtual bool eval ( ) override {
    		if ( ! inputsAttached ( ) )
    			return false;
    
    		if ( this->cached ( ) )
    			return true;
    
    		auto evalCallback = [ ] ( const auto & param ) {
    			return param->eval ( );
    		};
    
    		if ( ! ext::all_of ( m_params, evalCallback ) )
    			return false;
    
    		return this->run ( );
    	}
    
    	virtual unsigned numberOfParams ( ) const override {
    		return sizeof ... ( ParamTypes );
    	}
    
    
    	virtual bool isReady ( ) const override {
    
    		return m_data.template is < std::shared_ptr < OperationAbstraction > > ( ) && m_data.template get < std::shared_ptr < OperationAbstraction > > ( )->isReady ( );
    	}
    
    	virtual bool cached ( ) const override {
    		return isReady ( );
    	}
    
    	virtual ext::type_index getParamTypeIndex ( unsigned index ) const override {
    		auto callback = [ & ] ( auto & param ) {
    			return ext::type_index ( typeid ( typename std::decay < decltype ( param ) >::type::element_type::return_type ) );
    		};
    		return ext::call_on_nth < ext::type_index > ( m_params, index, callback );
    	}
    
    	virtual ext::type_index getReturnTypeIndex ( ) const override {
    		return getRuntimeReturnTypeIndex ( );
    	}
    
    	virtual ext::type_index getRuntimeReturnTypeIndex ( ) const override {
    		if ( isReady ( ) )
    			return m_data.template get < std::shared_ptr < OperationAbstraction > > ( )->getProxyAbstraction ( )->getRuntimeReturnTypeIndex ( );
    		else
    
    			throw std::domain_error ( "Runtime type unknown before evaluation." );
    
    	}
    
    	virtual std::shared_ptr < abstraction::OperationAbstraction > getProxyAbstraction ( ) override {
    		if ( isReady ( ) )
    			return m_data.template get < std::shared_ptr < OperationAbstraction > > ( )->getProxyAbstraction ( );
    		else
    
    			throw std::domain_error ( "Runtime type unknown before evaluation." );
    
    	}
    
    };
    
    } /* namespace abstraction */
    
    #endif /* _WRAPPER_ABSTRACTION_HPP_ */