/* * 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_ */