Goose  Artifact [35633b8b6f]

Artifact 35633b8b6f7ee130d0b83588c7377b080d269341cca6e253996a65b6051e2a1b:

  • File bs/ir/decompose.inl — part of check-in [26221286db] at 2019-02-02 16:13:21 on branch trunk — ir: added helpers to make a new vector by dropping elements at the beginning or at the end of a source vector. (user: achavasse size: 2842) [more...]

#ifndef EMPATHY_IR_DECOMPOSE_INL
#define EMPATHY_IR_DECOMPOSE_INL

namespace empathy::ir
{
    template< typename T >
    auto Lit( T&& val )
    {
        return LiteralSpec< T >( forward< T >( val ) );
    }

    template< typename... S >
    auto Vec( S&&... specs )
    {
        return VectorSpec< S... >( forward< S >( specs )... );
    }

    template< typename T >
    bool Decompose( const Term& t, const LiteralSpec< T >& spec )
    {
        const auto* pContent = get_if< T >( &t.content() );
        if( !pContent )
            return false;

        return *pContent == spec.m_val;
    }

    template< typename T >
    optional< reference_wrapper< const T > > Decompose( const Term& t, const Val< T >& spec )
    {
        const auto* pContent = get_if< T >( &t.content() );
        if( !pContent )
            return nullopt;

        return *pContent;
    }

    const Term& Decompose( const Term& t, const SubTerm& spec )
    {
        return t;
    }

    template< size_t IR, size_t IS, typename... S, typename... T >
    bool Decompose( const Vector::container_type< Term >& terms, const tuple< S... >& specs, tuple< T... >& result )
    {
        auto res = Decompose( terms[IS], get< IS >( specs ) );

        if constexpr( is_same_v< decltype( res ), bool > )
        {
            if( !res )
                return false;

            // For specs that are just predicates, we have no result to insert
            // so don't increment the result index.
            if constexpr( IS < ( sizeof... ( S ) - 1 ) )
                return Decompose< IR, IS + 1 >( terms, specs, result );
            else
                return true;
        }
        else if constexpr( is_optional_v< decltype( res ) > )
        {
            if( !res )
                return false;

            get< IR >( result ) = move( *res );

            if constexpr( IS < ( sizeof... ( S ) - 1 ) )
                return Decompose< IR + 1, IS + 1 >( terms, specs, result );
            else
                return true;
        }
        else
        {
            get< IR >( result ) = move( res );

            if constexpr( IS < ( sizeof... ( S ) - 1 ) )
                Decompose< IR + 1, IS + 1 >( terms, specs, result );

            return true;
        }
    }

    template< typename... S >
    optional< typename VectorSpec< S... >::return_type > Decompose( const Term& t, const VectorSpec< S... >& spec )
    {
        const auto* ppVec = get_if< pvec >( &t.content() );
        if( !ppVec )
            return nullopt;

        const auto& terms = ( *ppVec )->terms();
        if( terms.size() != sizeof...( S ) )
            return nullopt;

        typename VectorSpec< S... >::return_type result;
        if( !Decompose< 0, 0 >( terms, spec.m_specs, result ) )
            return nullopt;

        return result;
    }
}

#endif