#pragma once #include <optional> #include <ext/memory> #include <ext/typeindex> #include <ext/typeinfo> #include <abstraction/ValueHolderInterface.hpp> #include <core/type_util.hpp> #include <core/type_details.hpp> namespace abstraction { template < class Type > class ValueImpl : public ValueHolderInterface < std::decay_t < Type > > { std::optional < std::decay_t < Type > > m_data; public: using ValueHolderInterface < Type >::ValueHolderInterface; void setValue ( const Type & data ) override { m_data = std::move ( const_cast < Type && > ( data ) ); } Type && getValue ( ) override { return std::move ( m_data.value ( ) ); } const Type & getValue ( ) const override { return m_data.value ( ); } }; template < class Type > class ReferenceImpl : public ValueHolderInterface < Type > { std::optional < std::reference_wrapper < Type > > m_data; public: using ValueHolderInterface < Type >::ValueHolderInterface; void setValue ( const Type & data ) override { m_data = std::reference_wrapper < Type > ( const_cast < Type & > ( data ) ); } Type && getValue ( ) override { return std::move ( m_data->get ( ) ); } const Type & getValue ( ) const override { return m_data->get ( ); } }; 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; public: 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 */