// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_MATRIx_EXP_ABSTRACT_
#ifdef DLIB_MATRIx_EXP_ABSTRACT_

#include "matrix_fwd.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename EXP
        >
    class matrix_exp
    {
        /*!
            REQUIREMENTS ON EXP
                - must be an object that inherits publicly from matrix_exp (this class).

            WHAT THIS OBJECT REPRESENTS
                This object represents an expression that evaluates to a matrix 
                of nr() rows and nc() columns.  
                
                The reason for having an object that represents an expression is that it 
                allows us to use the "expression templates" technique to eliminate the 
                temporary matrix objects that would normally be returned from expressions 
                such as M = A+B+C+D;  Normally each invocation of the + operator would
                construct and return a temporary matrix object but using this technique we 
                can avoid creating all of these temporary objects and receive a large 
                speed boost.

                Note that every time you invoke operator() on this object it recomputes 
                its result which may not be what you want to do.  For example, if you 
                are going to be accessing the same element over and over it might 
                be faster to assign the matrix_exp to a temporary matrix and then 
                use that temporary.


                const_ret_type typedef (defined below)
                    The purpose of the const_ret_type typedef is to allow matrix expressions
                    to return their elements by reference when appropriate.  So const_ret_type 
                    should be one of the following types:
                        - const type
                        - const type& 
        !*/

    public:
        typedef typename EXP::type type;
        typedef typename EXP::const_ret_type const_ret_type;
        typedef typename EXP::mem_manager_type mem_manager_type;
        typedef typename EXP::layout_type layout_type;
        const static long cost = EXP::cost;
        const static long NR = EXP::NR;
        const static long NC = EXP::NC;
        typedef matrix<type,NR,NC, mem_manager_type,layout_type> matrix_type;
        typedef EXP exp_type;

        const_ret_type operator() (
            long r,
            long c
        ) const;
        /*!
            requires
                - 0 <= r < nr()
                - 0 <= c < nc()
            ensures
                - returns ref()(r,c)
                  (i.e. returns the value at the given row and column that would be in
                  the matrix represented by this matrix expression)
        !*/

        const_ret_type operator() (
            long i
        ) const;
        /*!
            requires
                - nc() == 1 || nr() == 1 (i.e. this must be a column or row vector)
                - if (nc() == 1) then
                    - 0 <= i < nr()
                - else
                    - 0 <= i < nc()
            ensures
                - if (nc() == 1) then
                    - returns (*this)(i,0)
                - else
                    - returns (*this)(0,i)
        !*/

        operator const type (
        ) const;
        /*!
            requires
                - nr() == 1
                - nc() == 1
            ensures
                - returns (*this)(0,0)
        !*/

        long nr (
        ) const;
        /*!
            ensures
                - returns the number of rows in this matrix expression. 
        !*/

        long nc (
        ) const; 
        /*!
            ensures
                - returns the number of columns in this matrix expression.
        !*/

        long size (
        ) const;
        /*!
            ensures
                - returns nr()*nc()
        !*/

        template <typename U>
        bool aliases (
            const matrix_exp<U>& item
        ) const;
        /*!
            ensures
                - if (A change to the state of item could cause a change to the state of *this
                      matrix_exp object.  ) then
                    - returns true
                    - This happens when this matrix_exp contains item in some way. 
                - else
                    - returns false
        !*/

        template <typename U>
        bool destructively_aliases (
            const matrix_exp<U>& item
        ) const; 
        /*!
            ensures
                - if (aliases(item)) then 
                    - if (nr() != item.nr() || nc() != item.nc()
                        - returns true
                          (i.e. if this expression has different dimensions than item then
                          we have destructive aliasing)

                    - returns true if the following assignment would evaluate incorrectly:
                      for (long r = 0; r < nr(); ++r)
                        for (long c = 0; c < nc(); ++c)
                          item(r,c) = (*this)(r,c)
                    - That is, if this matrix expression aliases item in such a way that a modification
                      to element item(r,c) causes a change in the value of something other than
                      (*this)(r,c) then this function returns true.  

                    - returns false if none of the above conditions say we should return true
                - else
                    - returns false
        !*/

        inline const exp_type& ref (
        ) const; 
        /*!
            ensures
                - returns a reference to the expression contained in *this.
                  (i.e. returns *static_cast<const exp_type*>(this) )
        !*/

    protected:

        // Only derived classes of matrix_exp may call the matrix_exp constructors.
        matrix_exp(const matrix_exp&); 
        matrix_exp();

    private:
        // no one may ever use the assignment operator on a matrix_exp
        matrix_exp& operator= (const matrix_exp&);
    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_MATRIx_EXP_ABSTRACT_


