Goose  Artifact [215af9ace2]

Artifact 215af9ace215264618214e42d0398f5b7c527ba760d6a2a13b6edf66bf7780e5:

  • File bs/ir/vector.h — part of check-in [6a9c80643f] at 2019-02-20 20:42:30 on branch trunk — Templates: parse template named decls (like regular decls, but with a TExpr instead of a type). (user: achavasse size: 6100)

#ifndef EMPATHY_IR_VECTOR_H
#define EMPATHY_IR_VECTOR_H

namespace empathy::ir
{
    struct Repetition
    {
        Repetition( Term&& t ) :
            m_term( move( t ) )
        {}

        Term m_term;
    };

    class VecLength
    {
        public:
            VecLength( size_t length, bool isVariable ) :
                m_length( length ),
                m_isVariable( isVariable )
            {}

            auto minLength() const { return m_length; }
            auto isVariable() const { return m_isVariable; }

        private:
            size_t  m_length = 0;
            bool    m_isVariable = false;
    };

    class Vector
    {
        public:
            Vector() {}

            template< typename T >
            using container_type = immer::flex_vector< T >;

            const auto& terms() const { return m_terms; }

            template< typename... T >
            static auto Make( T&&... terms )
            {
                immer::vector< Term > v;
                auto vt = v.transient();
                bool faulty = Append( vt, forward< T >( terms )... );

                auto pVec = make_shared< Vector >( vt.persistent(), faulty );

                pVec->setupRepetition( forward< T >( terms )... );

                return pVec;
            }

            template< typename... T >
            static Vector MakeAppend( const Vector& vec, T&&... terms )
            {
                auto v = vec.m_terms;

                auto vt = v.transient();
                bool faulty = Append( vt, forward< T >( terms )... );

                Vector newVec( vt.persistent(), vec.m_faulty || faulty );
                newVec.setupRepetition( forward< T >( terms )... );

                return newVec;
            }

            template< typename... T >
            static Vector MakeConcat( const Vector& vec1, const Vector& vec2 )
            {
                auto v = vec1.m_terms;

                auto vt = v.transient();
                for( auto&& t : vec2.terms() )
                    Append( vt, t );

                return Vector( vt.persistent(), vec1.m_faulty || vec2.m_faulty );
            }

            friend ostream& ToString( ostream& out, const pvec& v );

            template< typename V >
            Vector( V&& terms, bool faulty ) :
                m_terms( forward< V >( terms ) ),
                m_faulty( faulty )
            {}

            template< typename V >
            Vector( V&& terms, Term&& repetition, bool faulty ) :
                m_terms( forward< V >( terms ) ),
                m_repetitionTerm( move( repetition ) ),
                m_faulty( faulty )
            {}

            bool isFaulty() const { return m_faulty; }

            auto length() const { return VecLength( m_terms.size(), !!m_repetitionTerm ); }
            const auto& repetitionTerm() const { return m_repetitionTerm; }

            bool empty() const { return m_terms.empty(); }

            Generator< reference_wrapper< const Term > > forEachTerm() const
            {
                for( auto&& t : terms() )
                    co_yield t;

                if( m_repetitionTerm )
                    co_yield *m_repetitionTerm;
            }

            template< typename F >
            pvec transform( F&& func ) const
            {
                immer::vector< Term > v;
                auto vt = v.transient();

                for( auto&& x : m_terms )
                {
                    auto newX = func( x );
                    if( !newX )
                        return nullptr;
                    vt.push_back( move( *newX ) );
                }

                return make_shared< Vector >( vt.persistent(), m_faulty );
            }

            Vector take( size_t n ) const
            {
                return Vector( m_terms.take( n ), m_faulty );
            }

            Vector drop( size_t n ) const
            {
                return Vector( m_terms.drop( n ), m_faulty );
            }

            template< typename T >
            void setRepetitionTerm( T&& term )
            {
                m_repetitionTerm = forward< T >( term );
            }

            bool operator==( const Vector& rhs ) const;

            const auto& operator[]( size_t i ) const
            {
                return m_terms[i];
            }

        private:
            template< typename V, typename H, typename... T >
            static bool Append( V& vt, H&& head, T&&... tail )
            {
                bool faulty1 = Append( vt, forward< H >( head ) );
                bool faulty2 = Append( vt, forward< T >( tail )... );

                return faulty1 || faulty2;
            }

            template< typename V, typename H >
            static bool Append( V& vt, H&& head )
            {
                if constexpr( !is_same_v< Repetition, remove_constref_t< H > > )
                {
                    bool faulty = head.isFaulty();
                    vt.push_back( forward< H >( head ) );
                    return faulty;
                }
                else
                    return false;
            }

            template< typename V >
            static bool Append( V& vt )
            {
                return false;
            }

            template< typename H, typename... T >
            void setupRepetition( H&& head, T&&... tail )
            {
                if constexpr( is_same_v< Repetition, remove_constref_t< H > > )
                    setupRepetition( forward< H >( head ) );
                else
                    setupRepetition( forward< T >( tail )... );
            }

            template< typename H >
            void setupRepetition( H&& head )
            {
                if constexpr( is_same_v< Repetition, remove_constref_t< H > > )
                    m_repetitionTerm = forward< H >( head ).m_term;
            }

            void setupRepetition()
            {}

            container_type< Term >  m_terms;
            optional< Term >        m_repetitionTerm;
            bool                    m_faulty = false;
    };
}

#endif