// $Id: array.hh,v 1.2 1996/03/07 20:33:01 aml Exp $

/**************************************************************

Program: array (lib class)

File: array.hh

Version: 1.0

Author: Arlindo Oliveira (aml@ic)

Created:

Modified:

Comments:

****************************************************************/

#ifndef _ARRAY_DOT_HH_
#define _ARRAY_DOT_HH_

#include "utils.hh"

#define DEFAULT_ARRAY_SIZE 5
#define CHECK_ARRAY_BOUNDS 0

#define NEED_SORT 1

template<class T>
class array {
  protected:
    int size;
    int data_allocated;
    T *data; 
  public:
    int cnt; 
    int &n() {return(cnt);}
    T &last() {return(operator[](cnt-1));}
    T &pop() {cnt--; return(operator[](cnt));}
             
/* The HP compiler does not take for loops in inline functions   */
#ifndef hpux 

    array(int isize = DEFAULT_ARRAY_SIZE) {
        cnt = 0;
        size = isize;
        if (isize != 0) {
            data = new T[size];
            data_allocated = 1;
        }
        else {
            data = NULL;
            data_allocated = 0;
        }
    }

    array(const array<T> &right) {
        int i;
        data = new T[right.size];
        size = right.size;
        data_allocated = 1;
        cnt = right.cnt;
        for(i=0; i<size; i++) 
            data[i] = right.data[i];
    }

    void 
    resize(int newsize) {
        T *temp;
        int i;
        
        temp = new T[newsize];
        for(i=0; i<size; i++) 
            temp[i] = data[i];
        if (data_allocated)
            delete [] data;
        size = newsize;
        data = temp;
        data_allocated = 1;
    }
    
#else
    array(int isize = DEFAULT_ARRAY_SIZE);
    array(const array<T> &right) ;
    void resize(int newsize) ;
#endif

    ~array() {if (data_allocated) delete [] data; }

    void operator=(const array<T> &right) {
        int i;
        if (size < right.size) 
            resize(right.size);
        cnt = right.cnt;
        
        for(i=MIN(size,right.size)-1; i>=0; i--) 
            data[i] = right.data[i];
    }
    void operator+=(const T &value) {
#if CHECK_ARRAY_BOUNDS
        if (cnt < 0 || cnt > size)
            internal_error();
#endif
        if (cnt == size) 
            resize(2*size);
        data[cnt++] = value;
    }
    void operator--(int) {cnt--;};
    T &operator[](const int index) {
#if CHECK_ARRAY_BOUNDS
        if (index < 0) internal_error();
#endif
        if (index >= size) {
#if CHECK_ARRAY_BOUNDS
            //internal_error();
#endif
            resize(MAX(2*size,index+DEFAULT_ARRAY_SIZE));
        }
        return(data[index]);
    }

    void sort(int sort_f(const void *f1, const void *d2), int icnt=0) {
        if (icnt)
            qsort(data,icnt,sizeof(T),sort_f);
        else
            qsort(data,cnt,sizeof(T),sort_f);
    }

} ;

#ifndef hpux

template<class T>
ostream &operator<<(ostream &s, array<T> &arr) {
    int i;
    
    s << arr.cnt << "\n";
    for(i=0; i<arr.cnt; i++) 
        s << arr[i] << " ";
    return(s);
} 


template<class T>
int operator<=(const T &elem, array<T> &arr) {
    int i;
    
    for(i=0; i<arr.cnt; i++) 
        if (arr[i] == elem) return(TRUE);
    
    return(FALSE);
} 


template<class T>
ofstream &operator<<(ofstream &s, array<T> &arr) {
    int i;
    
    s << arr.cnt << "\n";
    for(i=0; i<arr.cnt; i++) 
        s << arr[i] << " ";
    return(s);
} 

template<class T>
istream &operator>>(istream &s, array<T> &arr) {
    int i;
    
    
    s >> arr.cnt;
    for(i=0; i<arr.cnt; i++) 
        s >> arr[i];
    return(s);
} 

template<class T>
ifstream &operator>>(ifstream &s, array<T> &arr) {
    int i;
    
    
    s >> arr.cnt;
    for(i=0; i<arr.cnt; i++) 
        s >> arr[i];
    return(s);
} 

#else 


template<class T>
array<T>::array(const array<T> &right) {
  int i;
  data = new T[right.size];
  size = right.size;
  data_allocated = 1;
  cnt = right.cnt;
  for(i=0; i<size; i++) 
    data[i] = right.data[i];
}

template<class T>
array<T>::array(int isize) {
    cnt = 0;
    size = isize;
    if (isize != 0) {
        data = new T[size];
        data_allocated = 1;
    }
    else {
        data = NULL;
        data_allocated = 0;
    }
}

template<class T> 
void array<T>::resize(int newsize) {
    T *temp;
    int i;
    
    temp = new T[newsize];
    for(i=0; i<size; i++) 
        temp[i] = data[i];
    if (data_allocated)
        delete [] data;
    size = newsize;
    data = temp;
    data_allocated = 1;
}

template<class T>
int operator<=(const T &elem, array<T> &arr) ;

template<class T>
ostream &operator<<(ostream &s, array<T> &arr) ;

template<class T>
ofstream &operator<<(ofstream &s, array<T> &arr) ;

template<class T>
istream &operator>>(istream &s, array<T> &arr) ;

template<class T>
ifstream &operator>>(ifstream &s, array<T> &arr) ;

#endif

#endif // _ARRAY_DOT_HH_

