array_vectorexpression.h

Back to Vector expressions

pastel/sys/vector/

// Description: A vector expression for a native array.
// Documentation: vectorexpression.txt

#ifndef PASTELSYS_ARRAY_VECTOREXPRESSION_H
#define PASTELSYS_ARRAY_VECTOREXPRESSION_H

#include "pastel/sys/vector/vectorexpression.h"
#include "pastel/sys/iterator/sparse_iterator.h"

#include <algorithm>

namespace Pastel
{

    template <typename Real, integer N>
    class ConstArray_VectorExpression
        : public VectorExpression<Real, N, ConstArray_VectorExpression<Real, N> >
    {
    public:
        using StorageType = const ConstArray_VectorExpression;

        using ConstIterator = ConstSparseIterator<const Real*>;

        ConstArray_VectorExpression()
            : data_(0)
            , size_(0)
            , stride_(0)
        {
        }

        ConstArray_VectorExpression(
            const Real* data,
            integer size,
            integer stride = 1)
            : data_(data)
            , size_(size)
            , stride_(stride)
        {
            PENSURE_OP(size, >=, 0);
            PENSURE_OP(stride, >=, 0);
            PENSURE2(N == Dynamic || size == N, N, size);
        }

        integer size() const
        {
            return size_;
        }

        bool involves(
            const void* memoryBegin, const void* memoryEnd) const
        {
            return Pastel::memoryOverlaps(
                memoryBegin, memoryEnd,
                data_, data_ + size_ * stride_);
        }

        bool evaluateBeforeAssignment(
            const void* memoryBegin, const void* memoryEnd) const
        {
            return false;
        }

        integer n() const
        {
            return size_;
        }

        void swap(ConstArray_VectorExpression<Real, N>& that)
        {
            std::swap(data_, that.data_);
            std::swap(size_, that.size_);
            std::swap(stride_, that.stride_);
        }

        bool operator==(const ConstArray_VectorExpression& that) const
        {
            return std::equal(begin(), end(), that.begin());
        }

        const Real& operator[](integer index) const
        {
            PENSURE2(index >= 0 && index < size_, 
                index, size_);

            return data_[index * stride_];
        }

        ConstIterator begin() const
        {
            return ConstIterator(data_, stride_);
        }

        ConstIterator end() const
        {
            return ConstIterator(data_ + size_ * stride_, stride_);
        }

    protected:
        // Must be protected for
        // Array_VectorExpression to access

        const Real* data_;
        integer size_;
        integer stride_;
    };

    template <integer N, typename Real>
    ConstArray_VectorExpression<Real, N> 
        constVectorExpression(const Real* data, integer size, integer stride = 1)
    {
        return ConstArray_VectorExpression<Real, N>(data, size, stride);
    }

    template <typename Real, integer N>
    ConstArray_VectorExpression<Real, N> 
        constVectorExpression(const Real (&data)[N])
    {
        return ConstArray_VectorExpression<Real, N>(data, N);
    }

    template <typename Real, integer N>
    class Array_VectorExpression
        : public ConstArray_VectorExpression<Real, N>
    {
    private:
        using Base = ConstArray_VectorExpression<Real, N>;
        using Base::data_;
        using Base::size_;
        using Base::stride_;

    public:
        using StorageType = const Array_VectorExpression;

        using Iterator = SparseIterator<Real*>;

        using Base::size;

        Array_VectorExpression()
            : Base()
        {
        }

        Array_VectorExpression(
            const Real* data,
            integer size,
            integer stride = 1)
            : Base(data, size, stride)
        {
            PENSURE_OP(size, >=, 0);
            PENSURE_OP(stride, >=, 0);
            PENSURE2(N == Dynamic || size == N, N, size);
        }

        // The parameter to this function
        // is deliberately not a reference,
        // because the reference could point
        // to this vector.
        void set(Real that) const
        {
            std::fill(begin(), end(), that);
        }

        Iterator begin() const
        {
            return Iterator((Real*)data_, stride_);
        }

        Iterator end() const
        {
            return Iterator((Real*)(data_ + size_ * stride_), stride_);
        }

        const Array_VectorExpression& operator=(Real that) const
        {
            // We accept basic exception safety for performance.
            set(that);

            return *this;
        }

        const Array_VectorExpression& operator=(
            const Array_VectorExpression& that) const
        {
            ENSURE_OP(size(), ==, that.size());

            std::copy(that.begin(), that.end(), begin());

            return *this;
        }

        template <typename ThatReal, integer ThatN, typename Expression>
        const Array_VectorExpression& operator=(
            const VectorExpression<ThatReal, ThatN, Expression>& that) const
        {
            ENSURE_OP(size(), ==, that.size());

            if (that.evaluateBeforeAssignment(
                data_, data_ + size_))
            {
                // In the case we must reallocate, we can
                // as well copy construct, so that there
                // is no redundant initialization.

                // Of course, if the expression involves
                // this vector as a non-trivial subexpression,
                // we must copy construct anyway.

                *this = evaluate(that);
            }
            else
            {                
                // We accept basic exception safety for performance.

                Iterator iter = begin();
                integer n = size();

                for (integer i = 0;i < n;++i)
                {

                    *iter = that[i];
                    ++iter;
                }
            }

            return *this;
        }

        Real& operator[](integer index) const
        {
            PENSURE2(index >= 0 && index < size_, 
                index, size_);

            return (Real&)data_[index * stride_];
        }

        // The parameter to this function
        // is deliberately not a reference,
        // because the reference could point
        // to this vector.
        const Array_VectorExpression& operator+=(const Real that) const
        {
            Iterator iter = begin();
            Iterator iterEnd = end();

            while(iter != iterEnd)
            {

                *iter += that;
                ++iter;
            }

            return *this;
        }

        // The parameter to this function
        // is deliberately not a reference,
        // because the reference could point
        // to this vector.
        const Array_VectorExpression& operator-=(const Real that) const
        {
            Iterator iter = begin();
            Iterator iterEnd = end();

            while(iter != iterEnd)
            {

                *iter -= that;
                ++iter;
            }

            return *this;
        }

        // The parameter to this function
        // is deliberately not a reference,
        // because the reference could point
        // to this vector.
        const Array_VectorExpression& operator*=(const Real that) const
        {
            Iterator iter = begin();
            Iterator iterEnd = end();

            while(iter != iterEnd)
            {

                *iter *= that;
                ++iter;
            }

            return *this;
        }

        // Here the reference is ok because we actually
        // use the parameter's inverse.
        const Array_VectorExpression& operator/=(const Real& that) const
        {
            return (*this *= Pastel::inverse(that));
        }

        template <typename ThatReal, integer ThatN, typename Expression>
        const Array_VectorExpression& operator+=(
            const VectorExpression<ThatReal, ThatN, Expression>& that) const
        {
            PENSURE2(that.size() == size(), that.size(), size());

            if (that.evaluateBeforeAssignment(
                data_, data_ + size_))
            {
                *this += Vector<Real, N>(that);
            }
            else
            {
                Iterator iter = begin();
                integer n = size();

                for (integer i = 0;i < n;++i)
                {

                    *iter += that[i];
                    ++iter;
                }
            }

            return *this;
        }

        template <typename ThatReal, integer ThatN, typename Expression>
        const Array_VectorExpression& operator-=(
            const VectorExpression<ThatReal, ThatN, Expression>& that) const
        {
            PENSURE2(that.size() == size(), that.size(), size());

            if (that.evaluateBeforeAssignment(
                data_, data_ + size_))
            {
                *this -= Vector<Real, N>(that);
            }
            else
            {
                Iterator iter = begin();
                integer n = size();

                for (integer i = 0;i < n;++i)
                {

                    *iter -= that[i];
                    ++iter;
                }
            }

            return *this;
        }

        template <typename ThatReal, integer ThatN, typename Expression>
        const Array_VectorExpression& operator*=(
            const VectorExpression<ThatReal, ThatN, Expression>& that) const
        {
            PENSURE2(that.size() == size(), that.size(), size());

            if (that.evaluateBeforeAssignment(
                data_, data_ + size_))
            {
                *this *= Vector<Real, N>(that);
            }
            else
            {
                Iterator iter = begin();
                integer n = size();

                for (integer i = 0;i < n;++i)
                {

                    *iter *= that[i];
                    ++iter;
                }
            }

            return *this;
        }

        template <typename ThatReal, integer ThatN, typename Expression>
        const Array_VectorExpression& operator/=(
            const VectorExpression<ThatReal, ThatN, Expression>& that) const
        {
            PENSURE2(that.size() == size(), that.size(), size());

            if (that.evaluateBeforeAssignment(
                data_, data_ + size_))
            {
                *this /= Vector<Real, N>(that);
            }
            else
            {
                Iterator iter = begin();
                integer n = size();

                for (integer i = 0;i < n;++i)
                {

                    *iter /= that[i];
                    ++iter;
                }
            }

            return *this;
        }
    };

    template <integer N, typename Real>
    Array_VectorExpression<Real, N> 
        vectorExpression(Real* data, integer size)
    {
        return Array_VectorExpression<Real, N>(data, size);
    }

    template <typename Real, integer N>
    Array_VectorExpression<Real, N> 
        vectorExpression(const Real (&data)[N])
    {
        return Array_VectorExpression<Real, N>(data, N);
    }

}

#endif