//
//  Vector.hh 
//
//  A template class definition file for a vector(one-dimensional array)
//  class with index bounds checking.
//
//  Jonathan Mohr
//  1998 June 17
//

// $Id: Vector.hh,v 1.1 1998/06/18 16:35:06 mohrj Exp mohrj $

#include <assert.h>
#include <iostream.h>

#ifndef __VECTOR__HH
#define __VECTOR__HH

template <class IndexType, class BaseData>
class Vector
{
public:

  //  Default constructor
  Vector( BaseData * data = 0, IndexType lo = 0, IndexType hi = 0 );

  //  Constructor with specified low and high indices
  Vector( IndexType lo, IndexType hi );

  //  Copy constructor
  Vector( const Vector<IndexType, BaseData> & initVector );

  //  Destructor (virtual)
  virtual ~Vector();

  //  Indexing
  virtual
  BaseData &
  operator [] ( IndexType i ) const;

  //  Assignment (Vector copying)
  virtual
  Vector< IndexType, BaseData > &
  operator = (const Vector< IndexType, BaseData > & initVector );

  //  Dot Product (the sum of the pairwise products of two vectors) 
  BaseData 
  DotProduct(const Vector< IndexType, BaseData > & otherVector );

  //  Accessors

  //  This function is useful in the SharingMatrix model in which a pointer
  //  is used as an alias for a row of data in another Matrix, thus sharing
  //  memory.
  BaseData * DataPtr() const;

  IndexType LowIndex() const;
  IndexType HighIndex() const;

protected:

  BaseData * dataPtr;
  IndexType  loIndex, hiIndex;

  virtual bool outOfRange( IndexType i ) const;
};


//
//  Constructors
//

template <class IndexType, class BaseData>
Vector<IndexType, BaseData>::
Vector( BaseData * data, IndexType lo, IndexType hi )
  : dataPtr( data ),
    loIndex( lo ),
    hiIndex( hi )
{
  // This constructor DOES NOT allocate any memory, since it is invoked
  // either as the default constructor (all parameters are zero)
  // or by being called from a derived class such as Row or SharedRow
  // which use aliasing, not memory allocation.
}


template <class IndexType, class BaseData>
Vector<IndexType, BaseData>::
Vector( IndexType lo, IndexType hi )
  : dataPtr( 0 ),
    loIndex( lo ),
    hiIndex( hi )
{
  assert( lo <= hi );
  dataPtr = new BaseData[ hi - lo + 1 ];
  assert( dataPtr != 0 );
}


template <class IndexType, class BaseData>
Vector<IndexType, BaseData>::
Vector( const Vector<IndexType, BaseData> & initVector )
  : dataPtr( 0 ),
    loIndex( initVector.loIndex ),
    hiIndex( initVector.hiIndex )
{
   if ( initVector.dataPtr )	// check that initVector has data
   {  
	dataPtr = new BaseData[ hiIndex - loIndex + 1 ];
	assert( dataPtr != 0 );

	for ( int i = 0; i <= hiIndex - loIndex; i++ )
	   dataPtr[i] = initVector.dataPtr[i];
   }
}


//
//  Destructor
//

template <class IndexType, class BaseData>
Vector<IndexType, BaseData>::
~Vector()
{
  delete [] dataPtr;
}


//  Indexing

template <class IndexType, class BaseData>
BaseData &
Vector<IndexType, BaseData>::
operator [] ( IndexType i ) const
{
  assert( ! outOfRange( i ));

  return ( dataPtr[ i - loIndex ] );
}


//  Assignment

template <class IndexType, class BaseData>
Vector<IndexType, BaseData> &
Vector<IndexType, BaseData>::
operator = (const Vector< IndexType, BaseData > &initVector )
{
  delete [] dataPtr;

  loIndex = initVector.loIndex;
  hiIndex = initVector.hiIndex;

  dataPtr = new BaseData[ hiIndex - loIndex + 1 ];
  assert(dataPtr != 0);

  // Copy the elements of 'initVector' to this Vector.
  for ( int i = 0; i <= hiIndex - loIndex; i++ )
	 dataPtr[ i ] = initVector.dataPtr[ i ];

  return (*this);
}

//  Dot Product (the sum of the pairwise products of two vectors)
template <class IndexType, class BaseData>
BaseData 
Vector<IndexType, BaseData>:: 
DotProduct(const Vector< IndexType, BaseData > & otherVector )
{
  // Vectors must be conformable.
  assert( hiIndex - loIndex == otherVector.hiIndex - otherVector.loIndex );

  BaseData sum = 0;

  for ( int i = 0; i <= hiIndex - loIndex; i++ )
	 sum += dataPtr[ i ] * otherVector.dataPtr[ i ];

  return sum;
}

//  Data member accessors

template <class IndexType, class BaseData>
BaseData *
Vector<IndexType, BaseData>::
DataPtr() const
{
  return dataPtr;
}


template <class IndexType, class BaseData>
IndexType
Vector<IndexType, BaseData>::
LowIndex() const
{
  return loIndex;
}


template <class IndexType, class BaseData>
IndexType
Vector<IndexType, BaseData>::
HighIndex() const
{
  return hiIndex;
}


//  Utility function

template <class IndexType, class BaseData>
bool
Vector<IndexType, BaseData>::
outOfRange( IndexType i ) const
{
  if (( i < loIndex ) || ( i > hiIndex ))
  {
	 cerr << "Index " << i << " out of range.\n";
	 return (true);
  }
  else
	 return (false);
}

#endif

