/* Array.H: simple array template class */

#ifndef _VRML_ARRAY_H_
#define _VRML_ARRAY_H_

#include <iostream.h>

template<class T>
class array {
protected:
  T *s;
  int chunksz;

  // copies the used source string elements 
  void copy(const array& src)
    {
      s = new T[src.size];
      for (int i=0; i<src.size; i++)
	s[i] = src.s[i];
      allocsz = src.size;
      chunksz = src.chunksz;
      size = src.size;
    }

  // reallocates s so it can contain extra extra elements.
  void expand(int extra)  
    {
      T *t = new T[allocsz+=extra]; 
      for (int i=0; i<size; i++) 
	t[i] = s[i]; 
      delete[] s; 
      s = t; 
    }

  // initializes an array with 'len' elements pointed to by t.
public:		// public because Assoc<> wouldn't find it on Irix6.2
  void init (int len, T *t)
    {
      if (len > 0) {
	s = new T[len];
	chunksz = len;

	if (t) {	// copy the elements if there are given any
	  for (int i=0; i<len; i++) 
	    s[i] = t[i];
	  size = len;
	}
      }
    }

public:
  // number of array elements in use (the actual number of array cells may be higher)
  int size, allocsz;

  // constructor, if the array needs to be expanded for appending elements, it
  // will be expanded by len elements at once (chunksz).
  array(int len =0, T *t =0)
    {
      s = 0;
      chunksz = len;
      allocsz = len;
      size = 0;
      if (len>0) init(len, t);
    }

  // copy constructor
  array(const array& src) 	{ copy(src); }

  // assignement: the source string elements are copied
  array& operator=(const array& src)   
    {
      if (this != &src) {
	delete [] s;
	copy(src);
      }
      return *this;
    }

  // destructor: also calls the destructor for the array elements.
  virtual ~array()              	{ delete [] s; }

  // returns the i-th element, no range checking. Reference returned is only
  // valid until the next expansion.
  inline T& operator[](int i) 	const 	{ return s[i]; }

  // appends an element to the end of the array, size is increased by one. 
  // Returns a reference to the new element. The returned reference is only
  // valid until the next time the array is expanded.
  inline T& append(const T& elem)
    {
      if (size >= allocsz) {
	if (chunksz != 0)
	  expand(chunksz);
	else if (size>15)
	  expand(size);
	else
	  expand(1);
      }
      s[size++] = elem;
      return s[size-1];
    }

  // reserves 'extra' array cells at the end of the array. To be filled in by
  // the user. size is increased by 'extra'.
  inline void grow(int extra)  
    {
      if (size+extra > allocsz) expand(size+extra-allocsz); 
      size += extra; 
    }

  friend ostream& operator<<(ostream& s, array& ar)
    {
      s << '[';
      for (int i=0; i<ar.size; i++)
	s << (i==0 ? " " : ", ") << ar.s[i];
      return s << " ]";
    }

  friend ostream& operator<<(ostream& s, array *ar) { return ar ? operator<<(s, *ar) : (s << "NULL"); }
};

#endif /*_VRML_ARRAY_H_*/
