Goose  Artifact [cdbd8ebfc1]

Artifact cdbd8ebfc173903d75a2142c2add32b66e80ca75cd143258f10c59598eb81bd9:

  • File bs/builtins/builders/lifecycle_manager.inl — part of check-in [32f94cd2e1] at 2023-08-02 21:46:53 on branch trunk — Implemented forall statement (user: zlodo size: 4145)

#ifndef GOOSE_BUILTINS_BUILDERS_LIFECYCLE_MANAGER_INL
#define GOOSE_BUILTINS_BUILDERS_LIFECYCLE_MANAGER_INL

namespace goose::builtins
{
    template< class C >
    void LifeCycleManager< C >::endLifetimeScope( Context& c )
    {
        destroyCurrentLifetimeScopeValues( c );
        --m_lifetimeScopeLevels;
    }

    template< class C >
    void LifeCycleManager< C >::destroyCurrentLifetimeScopeValues( const Context& c )
    {
        auto it = m_liveValuesList.begin();
        while( it != m_liveValuesList.end() )
        {
            if( it->m_lifetimeScopeLevel < m_lifetimeScopeLevels )
                break;

            if( !destroyLiveValue( c, it->m_value ) )
            {
                m_liveValuesList.clear();
                crtp().poison();
                return;
            }

            it = m_liveValuesList.erase( it );
        }
    }

    template< class C >
    bool LifeCycleManager< C >::destroyAllLiveValues( const Context& c )
    {
        for( auto it = m_liveValuesList.begin(); it != m_liveValuesList.end(); ++it )
        {
            if( !destroyLiveValue( c, it->m_value ) )
            {
                m_liveValuesList.clear();
                crtp().poison();
                return false;
            }
        }

        return true;
    }

    template< class C >
    bool LifeCycleManager< C >::destroyAllLiveValuesFromBreakScope( const Context& c, uint32_t breakScopeLevel )
    {
        for( auto it = m_liveValuesList.begin(); it != m_liveValuesList.end(); ++it )
        {
            if( it->m_breakableScopeLevel < breakScopeLevel )
                return true;

            if( !destroyLiveValue( c, it->m_value ) )
            {
                m_liveValuesList.clear();
                crtp().poison();
                return false;
            }
        }

        return true;
    }

    template< class C >
    bool LifeCycleManager< C >::destroyAllLiveValuesFromContinueScope( const Context& c, uint32_t continueScopeLevel )
    {
        for( auto it = m_liveValuesList.begin(); it != m_liveValuesList.end(); ++it )
        {
            if( it->m_continuableScopeLevel < continueScopeLevel )
                return true;

            if( !destroyLiveValue( c, it->m_value ) )
            {
                m_liveValuesList.clear();
                crtp().poison();
                return false;
            }
        }

        return true;
    }

    template< class C >
    bool LifeCycleManager< C >::destroyLiveValue( const Context& c, const Value& v, source_location sloc )
    {
        if( v.isPoison() )
        {
            crtp().poison();
            return false;
        }

        DiagnosticsContext dc( v.locationId(), "When invoking DestroyValue." );
        auto result = InvokeOverloadSet( c, c.env()->extDestroyValue(),
            MakeClosedTuple( v ), Location::Create( sloc ) );

        if( result.isPoison() )
        {
            crtp().poison();
            return false;
        }

        if( !result.isConstant() )
            crtp().append( move( result ) );

        return true;
    }

    template< class C >
    void LifeCycleManager< C >::extendValueLifetime( uint32_t index )
    {
        // Find the live value.
        auto it = find_if( m_liveValuesList.begin(), m_liveValuesList.end(),
            [&]( auto&& lv )
            {
                return lv.m_index == index;
            } );

        if( it == m_liveValuesList.end() )
            return;

        --it->m_lifetimeScopeLevel;

        // Look for the last value that belongs to the parent lifetime scope, if any.
        auto last = find_if( it, m_liveValuesList.end(),
            [&]( auto&& lv )
            {
                return lv.m_lifetimeScopeLevel < it->m_lifetimeScopeLevel;
            } );

        // Reinsert the value just after the last value of the parent scope (the one we
        // just found), like it would be if it was inserted in that lifetime scope in the first
        // place.
        auto lvToExtend = move( *it );
        m_liveValuesList.erase( it );

        m_liveValuesList.emplace( last, move( lvToExtend ) );
    }
}

#endif