Skip to content
Snippets Groups Projects
ValueHolder.hpp 3.26 KiB
Newer Older
  • Learn to ignore specific revisions
  • #include <ext/memory>
    #include <ext/typeindex>
    #include <ext/typeinfo>
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    #include <abstraction/ValueHolderInterface.hpp>
    
    
    #include <core/type_util.hpp>
    #include <core/type_details.hpp>
    
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    namespace abstraction {
    
    template < class Type >
    
    class ValueImpl : public ValueHolderInterface < std::decay_t < Type > > {
    	std::optional < std::decay_t < Type > > m_data;
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    
    public:
    	using ValueHolderInterface < Type >::ValueHolderInterface;
    
    
    	void setValue ( const Type & data ) override {
    
    		m_data = std::move ( const_cast < Type && > ( data ) );
    
    	Type && getValue ( ) override {
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    		return std::move ( m_data.value ( ) );
    	}
    
    
    	const Type & getValue ( ) const override {
    		return m_data.value ( );
    	}
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    };
    
    template < class Type >
    
    class ReferenceImpl : public ValueHolderInterface < Type > {
    	std::optional < std::reference_wrapper < Type > > m_data;
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    
    public:
    	using ValueHolderInterface < Type >::ValueHolderInterface;
    
    
    	void setValue ( const Type & data ) override {
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    		m_data = std::reference_wrapper < Type > ( const_cast < Type & > ( data ) );
    	}
    
    
    	Type && getValue ( ) override {
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    		return std::move ( m_data->get ( ) );
    	}
    
    
    	const Type & getValue ( ) const override {
    		return m_data->get ( );
    	}
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    };
    
    template < class Type >
    
    class ValueHolder : public std::conditional_t < std::is_reference_v < Type >, ReferenceImpl < std::decay_t < Type > >, ValueImpl < std::decay_t < Type > > > {
    	bool m_isTemporary;
    
    	abstraction::TypeQualifiers::TypeQualifierSet getTypeQualifiers ( ) const override;
    
    	core::type_details getActualType ( ) const override;
    
    	core::type_details getDeclaredType ( ) const override;
    
    	bool isTemporary ( ) const override {
    		return m_isTemporary;
    
    	std::unique_ptr < abstraction::Value > asValue ( bool move, bool temporary ) override;
    
    	ValueHolder ( Type && value, bool temporary );
    
    template < class Type >
    abstraction::TypeQualifiers::TypeQualifierSet ValueHolder < Type >::getTypeQualifiers ( ) const {
    	return abstraction::TypeQualifiers::typeQualifiers < Type > ( );
    }
    
    template < class Type >
    core::type_details ValueHolder < Type >::getActualType ( ) const {
    	return core::type_details::get ( this->getValue ( ) );
    }
    
    template < class Type >
    core::type_details ValueHolder < Type >::getDeclaredType ( ) const {
    	return core::type_details::get < std::decay_t < Type > > ( );
    }
    
    template < class Type >
    std::unique_ptr < abstraction::Value > ValueHolder < Type >::asValue ( bool move, bool temporary ) {
    	if constexpr ( std::is_abstract_v < std::decay_t < Type > > )
    		throw std::domain_error ( "Cannot declare value of abstract class." );
    	else if constexpr ( ! std::is_assignable_v < std::decay_t < Type > &, std::decay_t < Type > > )
    		throw std::domain_error ( "Cannot assign value." );
    	else
    		return std::make_unique < abstraction::ValueHolder < std::decay_t < Type > > > ( retrieveValue < std::decay_t < Type > > ( this->shared_from_this ( ), move ), temporary );
    }
    
    template < class Type >
    ValueHolder < Type >::ValueHolder ( Type && value, bool temporary ) : m_isTemporary ( temporary ) {
    
    	if ( TypeQualifiers::isLvalueRef ( abstraction::TypeQualifiers::typeQualifiers < Type > ( ) ) && m_isTemporary )
    
    		throw std::domain_error ( "Lvalue references cannot be temporaries." );
    
    	this->setValue ( std::forward < Type > ( value ) );
    }
    
    } /* namespace abstraction */