
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
/*                                                                           */
/*                                                                           */
/*                   MV++ Numerical Matrix/Vector C++ Library                */
/*                             MV++ Version 1.5                              */
/*                                                                           */
/*                                  R. Pozo                                  */
/*               National Institute of Standards and Technology              */
/*                                                                           */
/*                                  NOTICE                                   */
/*                                                                           */
/* Permission to use, copy, modify, and distribute this software and         */
/* its documentation for any purpose and without fee is hereby granted       */
/* provided that this permission notice appear in all copies and             */
/* supporting documentation.                                                 */
/*                                                                           */
/* Neither the Institution (National Institute of Standards and Technology)  */
/* nor the author makes any representations about the suitability of this    */
/* software for any purpose.  This software is provided ``as is''without     */
/* expressed or implied warranty.                                            */
/*                                                                           */
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

//
//      mvvtp.h     Basic templated vector class
//

// modif gérard Rio : 
//  - introduction de la surcharge d'écriture dans la classe MVvecteur
//  - modification de l'indice du type unsigned int au type int et vérification
//    du nombre négatif
//  - modification de la surcharge d'écriture (ajout de l'écriture de la taille)
//    et ajout de la surcharge de lecture en cohérence avec l'écriture déjà existante
//  - introduction de la possibilité de créer un vecteur à la place d'un autre
//    en donnant la référence à l'autre vecteur et un indicateur de non construction
//  - dans le cas ou les tailles à alouer sont nulles, on met en place une procédure spé


#ifndef _MV_VECTOR_TPL_H_
#define _MV_VECTOR_TPL_H_    

#include <iostream>       // for formatted printing of vecteur : GR

#include <stdlib.h>
#ifdef MV_VECTOR_BOUNDS_CHECK
#   include <assert.h>
#endif
#include "Sortie.h"
//#ifdef SYSTEM_MAC_OS_X
//  #include <stringfwd.h> // a priori ce n'est pas portable
//#el
#if defined  SYSTEM_MAC_OS_CARBON
  #include <stringfwd.h> // a priori ce n'est pas portable
#else  
  #include <string.h> // pour le flot en memoire centrale
#endif
#include <string>

#include "mvvind_GR.h"
#include "mvvrf_GR.h"
using namespace std;
template <class TYPE>
class MV_Vector
{                                                                    
    protected:                                                           
           TYPE *p_;
      //     unsigned int dim_;
           int dim_;  // modif GR
           int ref_;  // 0 or 1; does this own its own memory space?
    public: 
    
    // les informations sont le type puis la taille puis les datas 
    friend    istream & operator >> (istream & entree, MV_Vector<TYPE>& vec)
    { // vérification du type
      string type;
      entree >> type;
      if (type != "MV_Vector<>")
        {Sortie (1);
         return entree;
         }
      // passage de la chaine donnant la taille puis lecture de la taille
      int taille;
      entree >> type >> taille; 
      // vérification de la taille sinon changement
      if (vec.size() != taille) vec.newsize(taille);  
      // lecture des données
      for (int i = 0; i< taille; i++)
        entree >> vec.p_[i];
      return entree;      
    };
    // surcharge de l'operator d'ecriture non formatée
    // les informations sont le type puis la taille puis les datas séparées par
    // un espace
    friend  ostream&   operator<<(ostream& s, const MV_Vector<TYPE>& V)
     {
       int N = V.size();
       s << "\n MV_Vector<> taille= " << V.size();
       for (int j=0; j<N; j++)
         s << V(j) << " " ;
       s << endl;
       return s;
      }
       
        /*::::::::::::::::::::::::::*/                                 
        /* Constructors/Destructors */                                 
        /*::::::::::::::::::::::::::*/                                 
                                                                       
    MV_Vector();                             
//    MV_Vector(unsigned int);                             
//    MV_Vector(unsigned int, const TYPE&);   
//    MV_Vector(TYPE*, unsigned int);     
//    MV_Vector(const TYPE*, unsigned int); 
      
    MV_Vector( int);     // modif GR                            
    MV_Vector( int, const TYPE&);     // modif GR    
                                       
    MV_Vector(TYPE*,  int);     // modif GR      
    MV_Vector(const TYPE*,  int);      // modif GR       
    
    // reference of an exisiting data structure
    //
//    MV_Vector(TYPE*, unsigned int, MV_Vector_::ref_type i); 
    MV_Vector(TYPE*,  int, MV_Vector_::ref_type i);  // modif GR
    // construction ici réelle
    MV_Vector(const MV_Vector<TYPE>&);
    // construction conditionnelle en fonction de l'indicateur
    // cette construction est moins rapide que la précédente s'il y a vraiment
    // définition d'un nouveau tableau de data (appel de new moin bon)
    MV_Vector(MV_Vector<TYPE>&,MV_Vector_::ref_type i);
    // destructeur 
    ~MV_Vector();                              
                                                                       
        /*::::::::::::::::::::::::::::::::*/                           
        /*  Indices and access operations */                           
        /*::::::::::::::::::::::::::::::::*/                           
                                                                       

//    inline            TYPE&     operator()(unsigned int i)
    inline            TYPE&     operator()(int i) // modif GR
                  {
#                   ifdef MV_VECTOR_BOUNDS_CHECK
//                    assert(i < dim_);
                    assert((i < dim_)||(i>=0));  // modif GR
#                   endif
                    return p_[i];
                  }
//    inline  const  TYPE&    operator()(unsigned int i) const 
    inline  const  TYPE&    operator()( int i) const  // modif GR
                  {
#                   ifdef MV_VECTOR_BOUNDS_CHECK
//                    assert(i < dim_);
                    assert((i < dim_)||(i>=0));  // modif GR
#                   endif
                    return p_[i];
                  }

//    inline        TYPE&     operator[](unsigned int i)
    inline        TYPE&     operator[](int i) // modif GR
                  {
#                   ifdef MV_VECTOR_BOUNDS_CHECK
//                    assert(i < dim_);
                    assert((i < dim_)||(i>=0));  // modif GR
#                   endif
                    return p_[i];
                  }
//    inline      const  TYPE&    operator[](unsigned int i) const 
    inline      const  TYPE&    operator[]( int i) const  // modif GR
                  {
#                   ifdef MV_VECTOR_BOUNDS_CHECK
//                    assert(i < dim_);
                    assert((i < dim_)||(i>=0));  // modif GR
#                   endif
                    return p_[i];
                  }



    inline MV_Vector<TYPE> operator()(const MV_VecIndex &I) ;
    inline MV_Vector<TYPE> operator()(void);
    inline const MV_Vector<TYPE> operator()(void) const;
    inline const MV_Vector<TYPE> operator()(const MV_VecIndex &I) const;

//    inline unsigned int             size() const { return dim_;}
    inline int             size() const { return dim_;}  // modif GR
    inline int                      ref() const { return  ref_;}
    inline int                      null() const {return dim_== 0;}
            //
            // Create a new *uninitalized* vector of size N
            MV_Vector<TYPE> & newsize( int );
                                                                       
        /*::::::::::::::*/                                             
        /*  Assignment  */                                             
        /*::::::::::::::*/                                             
                                                                       
            MV_Vector<TYPE> & operator=(const MV_Vector<TYPE>&);
            MV_Vector<TYPE> & operator=(const TYPE&);



};                                                                     

template <class TYPE>
ostream&   operator<<(ostream& s, const MV_Vector<TYPE>& V)
{
    int N = V.size();
    
    s << "\n MV_Vector<> taille= " << V.size();
    for (int j=0; j<N; j++)
        s << V(j) << " " ;
    s << endl;
        
    return s;
}

// surcharge de l'operateur de lecture
// cohérente avec l'écriture déjà existante
template <class TYPE>
istream & operator >> (istream & entree, MV_Vector<TYPE>& vec)
  { // vérification du type
    string type;
    entree >> type;
    if (type != "MV_Vector<>")
      {Sortie (1);
       return entree;
       }
    // passage de la chaine donnant la taille puis lecture de la taille
    int taille;
    entree >> type >> taille; 
    // vérification de la taille sinon changement
    if (vec.size() != taille) vec.newsize(taille);  
    // lecture des données
    for (int i = 0; i< vec.taille; i++)
        entree >> vec.p_[i];
    return entree;      
  };

template <class TYPE>
MV_Vector<TYPE>::MV_Vector()  : p_(NULL), dim_(0) , ref_(0){}

template <class TYPE>
//MV_Vector<TYPE>::MV_Vector(unsigned int n) : p_(new TYPE[n]), dim_(n), 
// a priori si n est négatif new ramènera une erreur
//MV_Vector<TYPE>::MV_Vector( int n) : p_(new TYPE[n]), dim_(n), // modif 1 GR
MV_Vector<TYPE>::MV_Vector( int n) :  dim_(n), // modif 2 GR
            ref_(0)
{ if (n!= 0)
   {p_ = new TYPE[n];
    if (p_ == NULL)
    {
        cerr << "Error: NULL pointer in MV_Vector(int) constructor " << endl;
        cerr << "       Most likely out of memory... " << endl;
        Sortie(1);
    }
    }
  else
    p_=NULL;  // ajout car new ne fait pas bien son boulot !!  
}

template <class TYPE>
//MV_Vector<TYPE>::MV_Vector(unsigned int n, const TYPE& v) : 
MV_Vector<TYPE>::MV_Vector( int n, const TYPE& v) :  // modif 1 GR
//        p_(new TYPE[n]), dim_(n), ref_(0)
         dim_(n), ref_(0)   // modif 2 GR
{
   if (n!= 0)
   { p_ = new TYPE[n];
    if (p_ == NULL)
    {
        cerr << "Error: NULL pointer in MV_Vector(int) constructor " << endl;
        cerr << "       Most likely out of memory... " << endl;
        Sortie(1);
    }
    for (int i=0; i<n; i++)
        p_[i] = v;
    }
  else
    p_=NULL;  // ajout car new ne fait pas bien son boulot !!  
        
}

// operators and member functions
//




template <class TYPE>
MV_Vector<TYPE>& MV_Vector<TYPE>::operator=(const TYPE & m) 
{
#ifdef TRACE_VEC
    cout << "> MV_Vector<TYPE>::operator=(const TYPE & m)  " << endl;
#endif

    // unroll loops to depth of length 4

    int N = this->size();

    int Nminus4 = N-4;
    int i;

    for (i=0; i<Nminus4; )
    {
        p_[i++] = m;
        p_[i++] = m;
        p_[i++] = m;
        p_[i++] = m;
    }

    for (; i<N; p_[i++] = m) ;  // finish off last piece...

#ifdef TRACE_VEC
    cout << "< MV_Vector<TYPE>::operator=(const TYPE & m)  " << endl;
#endif
    return *this;
}

template <class TYPE>
//MV_Vector<TYPE>& MV_Vector<TYPE>::newsize(unsigned int n)
MV_Vector<TYPE>& MV_Vector<TYPE>::newsize( int n)  // modif GR
{
#ifdef TRACE_VEC
 //   cout << "> MV_Vector<TYPE>::newsize(unsigned int n) " << endl;
    cout << "> MV_Vector<TYPE>::newsize( int n) " << endl;
#endif
    if (ref_ )                  // is this structure just a pointer?
    {
        {
            cerr << "MV_Vector::newsize can't operator on references.\n";
            Sortie(1);
        }
    }
    else
    if (dim_ != n )                     // only delete and new if
    {                                   // the size of memory is really
        if (p_) delete [] p_;           // changing, otherwise just
        p_ = new TYPE[n];               // copy in place.
        if (p_ == NULL)
        {
            cerr << "Error : NULL pointer in operator= " << endl;
            Sortie(1);
        }
        dim_ = n;
    }

#ifdef TRACE_VEC
 //   cout << "< MV_Vector<TYPE>::newsize(unsigned int n) " << endl;
    cout << "< MV_Vector<TYPE>::newsize( int n) " << endl;
#endif

    return *this;
}


    

template <class TYPE>
MV_Vector<TYPE>& MV_Vector<TYPE>::operator=(const MV_Vector<TYPE> & m) 
{

    int N = m.dim_;
    int i;

    if (ref_ )                  // is this structure just a pointer?
    {
        if (dim_ != m.dim_)     // check conformance,
        {
            cerr << "MV_VectorRef::operator=  non-conformant assignment.\n";
            Sortie(1);
        }

        // handle overlapping matrix references
        if ((m.p_ + m.dim_) >= p_)
        {
            // overlap case, copy backwards to avoid overwriting results
            for (i= N-1; i>=0; i--)
                p_[i] = m.p_[i];
        }
        else
        {
            for (i=0; i<N; i++)
                p_[i] = m.p_[i];
        }
                
    }
    else
    {
        newsize(N);

        // no need to test for overlap, since this region is new
        for (i =0; i< N; i++)       // careful not to use bcopy()
            p_[i] = m.p_[i];                // here, but TYPE::operator= TYPE.
    }
    return *this;   
}

template <class TYPE>
//MV_Vector<TYPE>::MV_Vector(const MV_Vector<TYPE> & m) : p_(new TYPE[m.dim_]), 
MV_Vector<TYPE>::MV_Vector(const MV_Vector<TYPE> & m) :  // modif 2 GR 
    dim_(m.dim_) , ref_(0) , p_(NULL) // gerard: ajout de p_(NULL)
{ if (m.dim_ != 0)
   {p_ = new TYPE[m.dim_];
    if (p_ == NULL)
    {
        cerr << "Error:  Null pointer in MV_Vector(const MV_Vector&); " << endl;
        Sortie(1);
    }

    int N = m.dim_;

    for (int i=0; i<N; i++)
        p_[i] = m.p_[i];
   };
}


// note that ref() is initalized with i rather than 1.
// this is so compilers will not generate a warning that i was
// not used in the construction.  (MV_Vector::ref_type is an enum that
// can *only* have the value of 1.
//
template <class TYPE>
//MV_Vector<TYPE>::MV_Vector(TYPE* d, unsigned int n, MV_Vector_::ref_type i) : 
MV_Vector<TYPE>::MV_Vector(TYPE* d,  int n, MV_Vector_::ref_type i) : // modif GR
        p_(d), dim_(n) , ref_(i) 
      {
         #  ifdef MV_VECTOR_BOUNDS_CHECK
              assert(n < 0);  // modif GR
         #  endif
       }

template <class TYPE>
//MV_Vector<TYPE>::MV_Vector(TYPE* d, unsigned int n) : p_(new TYPE[n]), 
//MV_Vector<TYPE>::MV_Vector(TYPE* d,  int n) : p_(new TYPE[n]), // modif 1 GR
MV_Vector<TYPE>::MV_Vector(TYPE* d,  int n) :  // modif 2 GR
// a priori si n est négatif l'opérateur new renvera une erreur
      dim_(n) , ref_(0)
{ if (n != 0)
   {p_ = new TYPE[n];
    if (p_ == NULL)
    {
        cerr << "Error: Null pointer in MV_Vector(TYPE*, int) " << endl;
        Sortie(1);
    }
    for (int i=0; i<n; i++)
        p_[i] = d[i];
   }
  else
    p_=NULL;  // ajout car new ne fait pas bien son boulot !!  

}

// construction conditionnelle en fonction de l'indicateur
// cette construction est moins rapide que la précédente s'il y a vraiment
// définition d'un nouveau tableau de data (appel de new moin bon)
template <class TYPE>
MV_Vector<TYPE>::MV_Vector(MV_Vector<TYPE>& B ,MV_Vector_::ref_type i) :
         p_(B.p_),dim_(B.dim_) , ref_(i) 
      { // le vecteur est construit en fonction du cas donné par ref_
        if (ref_ != 1)
          // cas avec construction
         { p_ = new TYPE[dim_];
           for (int i=0; i<dim_; i++)
             p_[i] = B.p_[i];
          }   
        // sinon le pointeur p_ est déjà bien positionné
      
         #  ifdef MV_VECTOR_BOUNDS_CHECK
              assert(n < 0);  // modif GR
         #  endif
       }

template <class TYPE>
//MV_Vector<TYPE>::MV_Vector(const TYPE* d, unsigned int n) : p_(new TYPE[n]), 
//MV_Vector<TYPE>::MV_Vector(const TYPE* d, int n) : p_(new TYPE[n]), // modif 1 GR
MV_Vector<TYPE>::MV_Vector(const TYPE* d, int n) : // modif 2 GR
// a priori si n est négatif l'opérateur new renvera une erreur
      dim_(n) , ref_(0)
{if (n != 0)
   {p_=new TYPE[n]; 
    if (p_ == NULL)
    {
        cerr << "Error: Null pointer in MV_Vector(TYPE*, int) " << endl;
        Sortie(1);
    }
    for (int i=0; i<n; i++)
        p_[i] = d[i];
   }
  else
    p_=NULL;  // ajout car new ne fait pas bien son boulot !!  

}

template <class TYPE>
MV_Vector<TYPE> MV_Vector<TYPE>::operator()(void)
{
    return MV_Vector<TYPE>(p_, dim_, MV_Vector_::ref);
}

template <class TYPE>
const MV_Vector<TYPE> MV_Vector<TYPE>::operator()(void) const
{
    return MV_Vector<TYPE>(p_, dim_, MV_Vector_::ref);
}

template <class TYPE>
MV_Vector<TYPE> MV_Vector<TYPE>::operator()(const MV_VecIndex &I) 
{
    // default parameters
    if (I.all())
        return MV_Vector<TYPE>(p_, dim_, MV_Vector_::ref);
    else
    {
    // check that index is not out of bounds
    //
        if ( I.end() >= dim_)
        {
            cerr << "MV_VecIndex: (" << I.start() << ":" << I.end() << 
                ") too big for matrix (0:" << dim_ - 1 << ") " << endl;
            Sortie(1);
        }
        return MV_Vector<TYPE>(p_+ I.start(), I.end() - I.start() + 1,
            MV_Vector_::ref);
    }
}

template <class TYPE>
const MV_Vector<TYPE> MV_Vector<TYPE>::operator()(const MV_VecIndex &I) const
{
    // check that index is not out of bounds
    //
    if ( I.end() >= dim_)
    {
        cerr << "MV_VecIndex: (" << I.start() << ":" << I.end() << 
                ") too big for matrix (0:" << dim_ - 1 << ") " << endl;
        Sortie(1);
    }
    return MV_Vector<TYPE>(p_+ I.start(), I.end() - I.start() + 1,
            MV_Vector_::ref);
}

template <class TYPE>
MV_Vector<TYPE>::~MV_Vector()
{
        if (p_ && !ref_ ) delete [] p_;
}


template <class TYPE>
class FMV_Vector : public MV_Vector<TYPE>
{                                                                      
    public:                                                            
//        FMV_Vector(unsigned int n) : MV_Vector<TYPE>(n) {}
        FMV_Vector( int n) : MV_Vector<TYPE>(n) {}
        FMV_Vector<TYPE>& operator=(const FMV_Vector<TYPE>& m);
        FMV_Vector<TYPE>& operator=(const TYPE& m);
};

template <class TYPE>
FMV_Vector<TYPE>& FMV_Vector<TYPE>::operator=( const FMV_Vector<TYPE>& m)
{

#ifdef TRACE_VEC
    cout << "> FMV_Vector<TYPE>::operator=( const FMV_Vector<TYPE>& m)" << endl;
#endif

    int N = m.dim_;



    if (this->ref_ )                  // is this structure just a pointer?
    {
        if (this->dim_ != m.dim_)     // check conformance,
        {
            cerr << "MV_VectorRef::operator=  non-conformant assignment.\n";
            Sortie(1);
        }
    }
    else if ( this->dim_ != m.dim_ )      // resize only if necessary
       this->newsize(N);

    memmove(this->p_, m.p_, N * sizeof(TYPE));

#ifdef TRACE_VEC
    cout << "< FMV_Vector<TYPE>::operator=( const FMV_Vector<TYPE>& m)" << endl;
#endif

    return *this;   
}

template <class TYPE>
FMV_Vector<TYPE>& FMV_Vector<TYPE>::operator=(const TYPE & m) 
{
#ifdef TRACE_VEC
    cout << "> FMV_Vector<TYPE>::operator=(const TYPE & m)  " << endl;
#endif

    // unroll loops to depth of length 4

    int N = this->size();

    int Nminus4 = N-4;
    int i;

    for (i=0; i<Nminus4; )
    {
        this->p_[i++] = m;
        this->p_[i++] = m;
        this->p_[i++] = m;
        this->p_[i++] = m;
    }

    for (; i<N; this->p_[i++] = m);   // finish off last piece...

#ifdef TRACE_VEC
    cout << "< FMV_Vector<TYPE>::operator=(const TYPE & m)  " << endl;
#endif
    return *this;
}


#include "mvblas_GR.h"

#endif 
// _MV_VECTOR_TPL_H_

