//
// LiDIA - a library for computational number theory
//   Copyright (c) 1994, 1995 by the LiDIA Group
//
// File        : p_vector.h
// Author      : Werner Backes (WB), Thorsten Lauer (TL)
// Last change : WB/TL, May 09 1996, 
//                      initial version, previously 
//                      class bigint_lattice_gensys/basis
//               WB/TL, Jul 27 1996, 
//                      new template class p_vector, p_vector_SP initial version
//                      - p_vector
//                        -> template class used to work with pointers to
//                           a template datatype
//                      - p_vector_SP
//                        -> see above, user defined scalarproduct with
//                           pointer to function
//               WB/TL, Aug 06 1996, removed several bugs, specialized
//                                   versions of p_vector for bigint/bigfloat 
//
//
#ifndef __p_vector_h__
#define __p_vector_h__

//
// Special include format for compatibility with MAC's
//
#if defined(HAVE_MAC_DIRS) || defined(__MWERKS__)
#include <LiDIA:bigint.h>
#include <LiDIA:bigfloat.h>
#else
#include <LiDIA/bigint.h>
#include <LiDIA/bigfloat.h>
#endif

//
// Define for gcc 2.7.0 or higher
// !!! new ansi standard !!!
//
#if defined(__GNUC__) && __GNUC__ == 2 && __GNUC_MINOR__ > 6
#define cl(x)
#define fcl(x) register lidia_size_t x
#else
#define cl(x) lidia_size_t x
#define fcl(x) x
#endif

#ifdef NO_P_VECTOR_INLINE
#define P_VECTOR_INLINE 
#else
#define P_VECTOR_INLINE inline
#endif

//
// class p_vector
// ~~~~~~~~~~~~~~
//
// template class for vector operations
// using pointer to the data type
// size of vector is stored in vectsize
//
// requirements for the data - type :
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// arith. Operators : +, -, *
// other Operators  : =
// and integer - zero assignment
// specialized for bigint and bigfloat
//
template <class T>
class p_vector;

#ifdef __GNUC__

class p_vector<bigint> 
{
  protected :
    cl(counter);
    bigint*  tempPT;    
    bigint   tempT;

  public :
    lidia_size_t  vectsize;

    p_vector() { vectsize=0; };
    p_vector(lidia_size_t size) { vectsize=size; };
    ~p_vector() { };

    void assign(bigint*, bigint*);
    void assign_zero(bigint*);
    void add(bigint*, bigint*, bigint*);
    void subtract(bigint*, bigint*, bigint*);
    void scalmul(bigint*, const bigint, bigint*);
    void scalsub(bigint*, bigint*, const bigint, bigint*);
    void scalprod(bigint&, bigint*, bigint*);
    void swap(bigint*&, bigint*&);
};

//
// Specialization of p_vector for the class bigfloat
//
class p_vector<bigfloat> 
{
  protected :
    cl(counter);
    bigfloat*  tempPT;    
    bigfloat   tempT;

  public :
    lidia_size_t  vectsize;

    p_vector() { vectsize=0; };
    p_vector(lidia_size_t size) { vectsize=size; };
    ~p_vector() { };

    void assign(bigfloat*, bigfloat*);
    void assign_zero(bigfloat*);
    void add(bigfloat*, bigfloat*, bigfloat*);
    void subtract(bigfloat*, bigfloat*, bigfloat*);
    void scalmul(bigfloat*, const bigfloat, bigfloat*);
    void scalsub(bigfloat*, bigfloat*, const bigfloat, bigfloat*);
    void scalprod(bigfloat&, bigfloat*, bigfloat*);
    void swap(bigfloat*&, bigfloat*&);
};

#endif

//
// Template Code 
//
template <class T>
class p_vector 
{
  protected :
    cl(counter);
    T*  tempPT;    
    T   tempT;

  public :
    lidia_size_t  vectsize;

    p_vector() { vectsize=0; };
    p_vector(lidia_size_t size) { vectsize=size; };
    ~p_vector() { };

    void assign(T*, T*);
    void assign_zero(T*);
    void add(T*, T*, T*);
    void subtract(T*, T*, T*);
    void scalmul(T*, const T, T*);
    void scalsub(T*, T*, const T, T*);
    void scalprod(T&, T*, T*);
    void swap(T*&, T*&);
};

#ifndef NO_P_VECTOR_INLINE
#include <LiDIA/p_vector.c>
#endif

//
// class p_vector_SP
// ~~~~~~~~~~~~~~~~~
//
// template class derived from class p_vector
// with the same functionality but allows to
// define a scalarproduct by giving a pointer
// to a function :
// void (*scal_prod_T)(T&, T*, T*, lidia_size_t)
//
template <class T>
class p_vector_SP:public p_vector<T>
{
  protected :
    void (*scal_prod_T)(T&, T*, T*, lidia_size_t);
  public :
    p_vector_SP():p_vector<T>() { scal_prod_T=NULL; };
    p_vector_SP(lidia_size_t size):p_vector<T>(size) { scal_prod_T=NULL; };
    p_vector_SP(void (*spT)(T&, T*, T*, lidia_size_t), 
		lidia_size_t size=0):p_vector<T>(size) { scal_prod_T=spT; };
    ~p_vector_SP() { };


    inline void set_pointer(void (*spT)(T&, T*, T*, lidia_size_t))
    {  
      scal_prod_T=spT; 
    };

    inline void scalprod(T& res, T* a, T * b)
    {
      (*scal_prod_T)(res, a, b, vectsize);
    };
};

#endif
