#pragma ident "$Id: Vector.hpp 166 2006-09-30 08:33:51Z architest $"



/**
 * @file Vector.hpp
 * Classes for Vector, both constant and modifiable
 */

#ifndef GPSTK_VECTOR_HPP
#define GPSTK_VECTOR_HPP

//============================================================================
//
//  This file is part of GPSTk, the GPS Toolkit.
//
//  The GPSTk is free software; you can redistribute it and/or modify
//  it under the terms of the GNU Lesser General Public License as published
//  by the Free Software Foundation; either version 2.1 of the License, or
//  any later version.
//
//  The GPSTk is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with GPSTk; if not, write to the Free Software Foundation,
//  Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//  
//  Copyright 2004, The University of Texas at Austin
//
//============================================================================

#include "VectorBase.hpp"

namespace gpstk
{
 /** @addtogroup VectorGroup */
   //@{

// forward declaration
   template <class T> class VectorSlice;

/**
 * This class pretty much duplicates std::valarray<T> except it's fully
 * STL container compliant.  Remember that operators +=, -=, *= and /=
 * are provided by RefVectorBase.
 * 
 * @sa matvectest.cpp for examples
 */
   template <class T>
   class Vector : public RefVectorBase<T, Vector<T> >
   {
   public:
         /// STL value type
      typedef T value_type;
         /// STL reference type
      typedef T& reference;
         /// STL const reference type
      typedef const T& const_reference;
         /// STL iterator type
      typedef T* iterator;
         /// STL const iterator type
      typedef const T* const_iterator;

         /// Default constructor
      Vector() : v(NULL), s(0) {}
         /// Constructor given an initial size.
      Vector(size_t siz) : s(siz)
            //: v(new T[siz]), s(siz)
         {
            v = new T[siz];
            if(!v) {
               VectorException e("Vector(size_t) failed to allocate");
               GPSTK_THROW(e);
            }
         }
         /**
          * Constructor given an initial size and default value for all elements.
          */
      Vector(size_t siz, const T defaultValue) : s(siz)
            //: v(new T[siz]), s(siz)
         {
            v = new T[siz];
            if(!v) {
               VectorException e("Vector<T>(size_t, const T) failed to allocate");
               GPSTK_THROW(e);
            }
            assignFrom(defaultValue);
         }
         /**
          * Copy constructor from a ConstVectorBase type.
          */
      template <class E>
      Vector(const ConstVectorBase<T, E>& r) : s(r.size())
            //: v(new T[r.size()]), s(r.size())
         {
            v = new T[r.size()];
            if(!v) {
               VectorException e("Vector<T>(ConstVectorBase) failed to allocate");
               GPSTK_THROW(e);
            }
            assignFrom(r);
         }
         /**
          * Copy constructor.
          */
      Vector(const Vector& r) : s(r.s)
            //: v(new T[r.s]), s(r.s)
         {
            v = new T[r.s];
            if(!v) {
               VectorException e("Vector(Vector) failed to allocate");
               GPSTK_THROW(e);
            }
            assignFrom(r);
         }
         /**
          * Valarray constructor
          */
      Vector(const std::valarray<T>& r) : s(r.size())
            //: v(new T[r.size()]), s(r.size())
         {
            v = new T[r.size()];
            if(!v) {
               VectorException e("Vector(valarray) failed to allocate");
               GPSTK_THROW(e);
            }
            assignFrom(r);
         }

         /// subvector constructor
      template <class E>
      Vector(const ConstVectorBase<T, E>& vec,
             size_t top,
             size_t num) : v(size_t(0)),s(0)
         {
               // sanity checks...
            if ( top >= vec.size() || 
                 top + num > vec.size())
            {
               VectorException e("Invalid dimensions or size for Vector(VectorBase)");
               GPSTK_THROW(e);
            }
         
            v = new T[num];
            if(!v) {
               VectorException e("Vector(subvector) failed to allocate");
               GPSTK_THROW(e);
            }
            size_t i;
            for(i = 0; i < num; i++)
               v[i] = vec(top+i);
            s = num;
         }
   
         /// Destructor
      ~Vector()
         { if (v) delete [] v; }

         /// STL iterator begin
      iterator begin() { return v; }
         /// STL const iterator begin
      const_iterator begin() const { return v; }
         /// STL iterator end
      iterator end() { return v + s; }
         /// STL const iterator end
      const_iterator end() const { return v + s; }
         /// STL front
      value_type front() { return v[s-1]; }
         /// STL const front
      const_reference front() const { return v[s-1];}
         /// STL empty
      bool empty() const { return size == 0; }
         /// STL size
      size_t size() const {return s; }
         /// STL max_size
      size_t max_size() const { return std::numeric_limits<size_t>().max(); }

         /// Non-const operator []
      T& operator[] (size_t i) 
         { return v[i]; }
         /// Const operator []
      T operator[] (size_t i) const
         { return v[i]; }
         /// Non-const operator ()
      T& operator() (size_t i) 
         { return v[i]; }
         /// Const operator ()
      T operator() (size_t i) const
         { return v[i]; }

         /// Like valarray, lets you do vec[slice] to get a VectorSlice.
      VectorSlice<T> operator[] (const std::slice& sli)
         { return VectorSlice<T>(*this, sli); }

         /// *this will be resized if it isn't as large as x.
      Vector& operator=(const Vector& x)
         { resize(x.s); return assignFrom(x); }

         /// *this will be resized if it isn't as large as x.
      template <class E>
      Vector& operator=(const ConstVectorBase<T, E>& x)
         { resize(x.size()); return assignFrom(x); }

         /// *this will be resized if it isn't as large as x.
      Vector& operator=(const std::valarray<T>& x)
         { resize(x.size()); return assignFrom(x); }
         /// Only (*this).size() elements will be assigned.
      Vector& operator=(const T x)
         { return assignFrom(x); }
         /// Only (*this).size() elements will be assigned.
      Vector& operator=(const T* x)
         { return assignFrom(x); }

      /// *this will be cleared and resized as necessary
      inline Vector& operator=(const std::vector<T>& x)
      {
          size_t i;
          size_t vs = x.size();
          (*this).resize(vs);

          for (i = 0; i < vs; i++) 
              (*this)[i] = x[i];

          return (*this); 
      }

         /// Resizes the vector.  if index > size, the vector will be
         /// erased and the contents destroyed.
      Vector& resize(const size_t index)
         { 
            if (index > s)
            {
               if (v)
                  delete [] v;
               v = new T[index];
               if(!v) {
                  VectorException e("Vector.resize(size_t) failed to allocate");
                  GPSTK_THROW(e);
               }
            }
            s = index;
            return *this;
         }

         /// resize with new default value
      Vector& resize(const size_t index, const T defaultValue)
         {
            resize(index);
            size_t i;
            for(i = 0; i < s; i++)
               v[i] = defaultValue;
            return *this;
         }

    /// Returns the concatenation of this Vector and Vector b
    inline Vector operator&&(const Vector &b) 
    {
        size_t i;
        size_t vs = this->size();
        size_t bs = b.size();
        size_t rows = vs + bs;
        Vector<T> toReturn(rows);

        for (i = 0; i < vs; i++)
            toReturn[i] = (*this)[i];

        for (i = 0; i < bs; i++)
            toReturn[i+vs] = b[i];

        return toReturn;
    }

    /// Returns the concatenation of this Vector and a scalar of type T
    inline Vector operator&&(const T &b) 
    {
        size_t i;
        size_t vs = this->size();
        size_t rows = vs + 1;
        Vector<T> toReturn(rows);

        for (i = 0; i < vs; i++)
            toReturn[i] = (*this)[i];

        toReturn[rows - 1] = b;

        return toReturn;
    }

   private:

         // a good optimizer will remove this function call
         // if RANGECHECK isn't defined.  remember that
         // range checking affects EVERY operation
      inline bool rangeCheck(const size_t index) const
         {
#ifdef RANGECHECK
            return (index < s);
#else
            return true;
#endif
         }
   
         /// The vector
      T* v;
         /// The size of the vector.
      size_t s;
   };
   // end class Vector<T>

/**
 * A slice of Vector<T> that can be modified.  
 * @warning Remember that (VectorSlice = VectorSlice) will
 * assign elements to the VectorSlice, not copy the VectorSlice internal data!
 */
   template <class T>
   class VectorSlice : public RefVectorSliceBase<T, VectorSlice<T> >
   {
   public:
         /// Default constructor
      VectorSlice()
            : v(NULL), s(std::slice(0,0,0))
         { }

         /// Makes a slice of the whole vector
      VectorSlice(Vector<T>& vv)
            : v(&vv), s(std::slice(0,vv.size(),1))
         { }
            
         /// Makes a slice of the vector with the given std::slice.
      VectorSlice(Vector<T>& vv, const std::slice& ss)
            : v(&vv), s(ss)
         { vecSliceCheck(vv.size()); }

         /// Assign the elements of this slice from another vector.
      template <class V>
      VectorSlice& operator=(const ConstVectorBase<T, V>& x)
         { return assignFrom(x); }

         /// Assign the elements of this slice from a valarray.
      VectorSlice& operator=(const std::valarray<T>& x)
         { return assignFrom(x); }

         /// Assign all the elements of this slice to x.
      VectorSlice& operator=(const T x)
         { return assignFrom(x); }

         /// Assign (*this).size() elements from x to (*this).
      VectorSlice& operator=(const T* x)
         { return assignFrom(x); }

         /// Returns the modifiable i'th element of the slice.
      T& operator[] (size_t i) 
         { return (*v)[start() + i * stride()]; }
         /// Returns the const i'th element of the slice.
      T operator[] (size_t i) const
         { return (*v)[start() + i * stride()]; }
         /// Returns the modifiable i'th element of the slice.
      T& operator() (size_t i) 
         { return (*v)[start() + i * stride()]; }
         /// Returns the const i'th element of the slice.
      T operator() (size_t i) const
         { return (*v)[start() + i * stride()]; }

         /// returns the number of elements in the slice
      inline size_t size() const { return s.size(); }
         /// returns the index in the vector of the first element.
      inline size_t start() const { return s.start(); }
         /// returns the number of elements to skip between (*this)[i] and 
         /// (*this)[i+1]
      inline size_t stride() const { return s.stride(); }
   private:
         /// the vector used as a source for the slice
      Vector<T>* v;
         /// the slice specification.
      std::slice s;
   };

/**
 * A Vector<T> slice that doesn't allow modification. 
 */
   template <class T>
   class ConstVectorSlice : public ConstVectorSliceBase<T, ConstVectorSlice<T> >
   {
   public:
         /// default constructor
      ConstVectorSlice()
            : v(NULL), s(std::slice(0,0,0))
         { }

         /// Makes a slice of the whole vector
      ConstVectorSlice(const Vector<T>& vv)
            : v(&vv), s(std::slice(0,vv.size(),1))
         { }
            
         /// Uses the given slice and vector.
      ConstVectorSlice(const Vector<T>& vv, const std::slice& ss)
            : v(&vv), s(ss)
         { vecSliceCheck(vv.size()); }

         /// Returns a const version of the i'th slice element.
      T operator[] (size_t i) const
         { return (*v)[start() + i * stride()]; }
         /// Returns a const version of the i'th slice element.
      T operator() (size_t i) const
         { return (*v)[start() + i * stride()]; }

         /// returns the number of elements in the slice
      inline size_t size() const { return s.size(); }
         /// returns the index in the vector of the first element.
      inline size_t start() const { return s.start(); }
         /// returns the number of elements to skip between (*this)[i] and 
         /// (*this)[i+1]
      inline size_t stride() const { return s.stride(); }

   private:
         /// Vectortor used as a source for this slice.
      const Vector<T>* v;
         /// the slice specification.
      std::slice s;
   };

   //@}

}  // namespace

#include "VectorOperators.hpp"

#endif
