//#     Filename:       VarVec.h
//#
//#     ValVec and PtrVec templates
//#
//#
//#     Author:         John Doug Reynolds
//#     
//#     Creation Date:  May, 1998
//#
//#
//#
//# (c) Copyright The Johns Hopkins University 1998
//# All Rights Reserved
//#
//# The software and information contained herein are proprietary to The
//# Johns Hopkins University, Copyright 1998.  This software is furnished
//# pursuant to a written license agreement and may be used, copied,
//# transmitted, and stored only in accordance with the terms of such
//# license and with the inclusion of the above copyright notice.  This
//# software and information or any other copies thereof may not be
//# provided or otherwise made available to any other person.
//#
//#
//# Modification history:
//#
//# Peter Kunszt, Oct. 1998    Add clear() method to ValVec
//# Peter Kunszt, Feb. 1999    Add keep() method to ValVec
//#
//# Peter Kunszt, Feb. 1999    Add new template LinPool
//# Peter Kunszt, Apr. 1999    Add remove() method to ValVec
//#
//# Peter Kunszt, Jul. 2000    Add VarStr class
//# Peter Kunszt, Aug. 2000    Add VarStrToken class

#ifndef VARVEC_H
#define VARVEC_H

#ifndef _BOUNDS_EXCEPTION

#ifdef SXDB
#   include <sxException.h>
#   define _BOUNDS_EXCEPTION sxBoundsError
#   define _INTERFACE_EXCEPTION sxInterfaceError
#else
#   include <SpatialException.h>
#   define _BOUNDS_EXCEPTION SpatialBoundsError
#   define _INTERFACE_EXCEPTION SpatialInterfaceError
#endif

#endif

#include <sys/types.h>
#include <stdlib.h>
#include <new>
#include <string.h>



/** Dynamic array of arbitrary values

    This is a template for a general-purpose dynamic array.  The array
    grows automatically as needed, but reallocation occurs only when
    the length exceeds the capacity.  The capacity is increased in
    large blocks, the size of which may be optimized.  A fill value may
    be defined, in which case it is used to initialize new elements of
    the array, but not new capacity.  Which is to say that
    initialization is deferred until the array grows into its capacity.
    The public data member, increment_, specifies the amount by which
    the capacity is increased during reallocation.  By default,
    increment_ is zero, which causes the capacity to double upon each
    reallocation.  A non-zero increment_ is simply added to the
    capacity upon each reallocation.  The capacity is extended by this
    amount or by whatever greater amount is necessary to accommodate
    the new length of the array.
*/

template<class T> class ValVec {
public:
  /** Destructor. */

  ~ValVec( void );

  /** Default constructor.
      optionally specify initial capacity and
      reallocation increment.  */

  ValVec( size_t capacity = 0, size_t increment = 0 );

  /** Alternate constructor.
      define a fill value in addition to the
      parameters of the default constructor.  class T must have
      well-defined copy semantics.  The fill value does not exist
      unless it is defined.  */

  ValVec( const T &fill, size_t capacity, size_t increment );

  /** Copy constructor.  
      The initial capacity is the current capacity of the duplicated array.  */

  ValVec( const ValVec& );

  /** Assignment/copy operator.
      does not decrease the capacity. */

  ValVec&	operator =( const ValVec& );

  /** Efficient array operator (const version): no bounds checking. */

  const T&	operator ()( size_t index ) const { return vector_[index]; }

  /** Efficient array operator (non-const version): no bounds checking. */

  T&		operator ()( size_t index ) { return vector_[index]; }

  /** Bounds-checking array operator (const version): throws sxBoundsError. */

  const T&	operator []( size_t index ) const;

  /** Bounds-checking array operator (non-const version): throws sxBoundsError.
   */

  T&		operator []( size_t index );

  /** Bounds-adjusting array operator.  Returns the array
      element at the specified index, extending the array as necessary
      to bring it within bounds.  The fill value, if defined, is the
      initializer for any new elements. */

  T&		at( size_t index );

  /** Returns current occupied length of array.
   */

  size_t	length( void ) const { return length_; }

  /** Efficiently insert given element at end of array.
      Avoids redundant initialization of new array element, except for
      when a reallocation is required.  Returns the new length. */

  size_t	append( const T& );

  /** Insert new array elements.  
      Count specifies the number of new elements, and offset specifies
      where in the array to insert them.  By default the new elements
      are appended.  The fill value, if defined, is the initializer
      for the new elements.  offset refers to the end of the array:
      the first new element is located at index (length - offset).
      Returns the new length.  Throws sxBoundsError if offset is
      greater than length. */

  size_t	insert( size_t count, size_t offset = 0 );

  /** Remove array elements.  

      count specifies the number of elements to remove, and offset
      specifies which elements to remove.  By default elements are
      removed from the end of the array.  The unused capacity grows by
      this amount.  offset refers to the end of the array: the first
      removed element is located at index (length - offset - count).
      Returns the new length.  Throws sxBoundsError if (offset+count)
      is greater than length. */

  size_t	cut( size_t count, size_t offset = 0 );

  /** Removes the element specified by offset.
      This is basically a wrapper for the cut method cut(1, length-offset-1) */

  void		remove( size_t offset );

  /** Cut but keep capacity. 
      Just like the cut method, it resets the length of the vector by
      count, but it always starts from the end.  The elements, however
      are not deleted and rebuilt with the default, but rather left as
      they are for the user to reuse. */

  size_t	keep( size_t count );

  /** Return the fill value, defining it if necessary.
      If the fill value is not defined, a default value is created
      using the default constructor for class T.  The returned object
      is an lvalue, to which a new fill value may be assigned. */

  T&		fill( void );

  /** Returns true if the fill value is defined. */

  bool		fillExists( void ) const;

  /** Undefine and destroy the current fill value.
      (if it is defined) */

  void		unsetFill( void );


  /** Reset every value to the fill value. If no fill is
      defined, nothing is done!  */

  void		clear( void );

  /** Do a qsort */

  void		sort( int (*compar)(const void*, const void*) );

  /// Linear growth increment */
  size_t			increment_;
  /// dynamic array of values */
  T				*vector_;
private:
   size_t			length_;	// occupied length of vector
   size_t			capacity_;	// allocated length of vector
   T				*pFill_;	// pointer to fill value
};

/** Dynamic array of pointers

    This is a template for a dynamic array of pointers.  The design is
    very similar to the general-purpose version, ValVec, but
    specialized according to the memory management issues peculiar to
    storing pointers.  This version uses nil as the fill value, which
    cannot be customized or disabled.  By default, the cut method uses
    the delete operator to free pointers as they are removed from the
    array.  Before disposing the array, the destructor clears it out
    with cut.  This behavior is avoided if the pointers are designated
    as external, or shared.  In that case it is entirely up to the
    user to free pointers left dangling by cut.  When copying the
    array, one must choose whether the copy will share with the
    original the objects referenced by the pointers (shallow copy), or
    whether the copy will have its own internal duplicates.

<p>
<b>
           ---------------   WARNING   ---------------
</b>

<p>

    The user must provide a specialization of PtrDup() for every
    polymorphic class that will instantiate this template.  Failure to
    do this may result in unexpected truncation of derived objects.
    The template methods use PtrDup() when duplication of objects is
    required, but duplicating a polymorphic object requires assistance
    from the object itself.  For example, consider class B:

<pre>
 class B { public:
  virtual B* duplicate(void) const = 0;
 };
 inline B* PtrDup(const B *b) { return b ? b->duplicate() : 0; }
</pre>

    To avoid confusion and mistakes, place the specialization
    immediately after the declaration of class B.  If class B does not
    have a duplicator use the following specialization instead:

<pre>
 inline B* PtrDup(const B *b) {
  if (b) throw sxUnimplemented("PtrDup","class B has no duplicator");
  else return 0;
 }
</pre>
*/

template<class T> class PtrVec {
public:
  /** Destructor. */

  ~PtrVec( void );

  /** Default constructor.
      optionally specify initial capacity, reallocation increment, and
      whether the pointers are internal. */

  PtrVec( bool internal=true, size_t capacity=0, size_t increment=0 );

  /** Copy constructor.
      optionally specify either a shallow copy or an internalized copy
      (the default).  The initial capacity is the current capacity of
      the duplicated array. */

  PtrVec( const PtrVec&, bool internalize = true );

  /** Copy method. does not decrease the capacity.  The copy is
      shallow if internalize is false; otherwise the referenced
      objects are duplicated and the copy is internal, in which case
      class T must have well-defined copy semantics. */

  PtrVec&	copy( const PtrVec&, bool internalize );

  /** Assignment/copy operator. does not decrease the capacity.  This
      is not a shallow copy, so class T must have well-defined copy
      semantics. */

  PtrVec&	operator =( const PtrVec &obj ) { return copy(obj,true); }

  /** Efficient array operator (const version): no bounds checking. */

  const T*&	operator ()( size_t index ) const { return (const T*&) vector_[index]; }

  /** Efficient array operator (non-const version): no bounds checking. */

  T*&		operator ()( size_t index ) { return vector_[index]; }

  /** Bounds-checking array operator (const version): throws sxBoundsError. */

  const T*&	operator []( size_t index ) const;

  /** Bounds-checking array operator (non-const version): throws sxBoundsError.
   */

  T*&		operator []( size_t index );

  /** Bounds-adjusting array operator.  Returns the array
      element at the specified index, extending the array as necessary
      to bring it within bounds.  Any new elements are set to nil. */

  T*&		at( size_t index );

  /** Returns current occupied length of array. */

  size_t	length( void ) const { return length_; }

  /** Return the number of non-NULL entries in vector.
      NOTE: this is different from length(), which also counts NULL pointers.
  */

  size_t	entries( void ) const;

  /** Append: efficiently insert given element at end of array.
      Avoids redundant initialization of new array element, except for
      when a reallocation is required.  Returns the new length. */

  size_t	append( T* );

  /** Insert new array elements.  

      count specifies the number of new elements, and offset specifies
      where in the array to insert them.  By default the new elements
      are appended.  The new elements are initialized with the nil
      pointer value.  offset refers to the end of the array: the first
      new element is located at index (length - offset).  Returns the
      new length.  Throws sxBoundsError if offset is greater than
      length. */

  size_t	insert( size_t count, size_t offset = 0 );

  /** Return the index of the next available empty slot. */

   size_t	nextEmpty();

  /** Add a new array element in the first available empty slot.  
      This should be used when the ordering of elements is not
      important and empty slots are to be minimized.  Returns the
      index of the newly inserted element. */

  size_t	add( T* );

  /** Return the index of the given element. (If it exists in
      the array, else return -1.) */

  int  	index( const T* );

  /** Remove array elements.  
      count specifies the number of elements to remove, and offset
      specifies which elements to remove.  By default elements are
      removed from the end of the array.  The unused capacity grows by
      this amount.  offset refers to the end of the array: the first
      removed element is located at index (length - offset - count).
      Returns the new length.  Throws sxBoundsError if (offset+count)
      is greater than length. */

  size_t	cut( size_t count, size_t offset = 0 );

  /** Removes the element specified by offset.
      This is basically a wrapper for the cut method 
      <pre>
      cut(1, length-offset-1)
      <pre>
  */

  void		remove( size_t offset );

  /** Replace external pointers with internal
      copies of the referenced objects.  class T must have
      well-defined copy semantics.  Does nothing if already internal. */

  void		internalize( void );

  /** Change status of pointers to external.
      Beware that internalize does not undo this; once the pointers
      are designated external they cannot just be re-designated as
      internal.  Confusion on this point will yield dangling pointers. */

  void		externalize( void );

  /** internal method: returns true if the pointers are internal. */

  bool		internal( void ) const;

  /// linear growth increment
  size_t			increment_;
  /// dynamic array of pointers
  T				**vector_;
private:
  bool				internal_;	// delete dangling pointers
  size_t			length_;	// occupied length of vector
  size_t			capacity_;	// allocated length of vector
};


/** Dynamic linear pool of objects.

    This is a template for a dynamic pool of objects.  The design is
    very similar to the dynamic array of pointers.  A pool is defined
    to be an array of pointers to preallocated default objects.
    Whenever a new object is needed, it can be accessed from the pool
    with the use() member function.  The size of the pool extends
    automatically if its initial limit is reached.  This pool is a
    linear pool, i.e. we can rely upon their index to be sequential.
    So in order to return a specific object into the pool's disposal,
    all objects having larger indices have to be free (like a reverse
    LIFO - last out first back). The free member function returns
    objects to the pool's disposal. Upon destruction, all pool objects
    are destroyed using their destructor.  It does not make sense to
    have a copy constructor or assignment op.
*/

template<class T> class LinPool {
public:
  /**  Destructor. */

  ~LinPool( void );

  /** Default constructor.
      optionally specify initial capacity,
      reallocation increment, and whether the pointers are internal.
  */

  LinPool( size_t capacity=0, size_t increment=0 );

  /** Efficient array operator (const version): no bounds checking. */

  const T*&	operator ()( size_t index ) const { return (const T*&) vector_[index]; }

  /** Efficient array operator (non-const version): no bounds checking. */

  T*&		operator ()( size_t index ) { return vector_[index]; }

  /** Bounds-checking array operator (const version): throws sxBoundsError. */

  const T*&	operator []( size_t index ) const;

  /** Bounds-checking array operator (non-const version): throws sxBoundsError.
   */

  T*&		operator []( size_t index );

  /** Use Method. Bounds-adjusting operator that returns the pool
      element as an lvalue to be used by the user. It is a combination
      of append() and at() of VarVec and PtrVec.  If the bounds of the
      pool array are reached, it is extended by increment_.
  */

  T*&		use( void );

  /** Returns current occupied length of the pool. */

  size_t	length( void ) const { return length_; }

  /** Declare pool objects as free for new use.
      If no argument is given, all elements are free to use again.
      Else, the number of elements specified is freed up from the end. */

  size_t	free( size_t count = 0) { return (length_ = count ? length_ - count : 0); }

  /// linear growth increment
  size_t			increment_;
  /// dynamic array of pointers
  T				**vector_;
private:
  size_t			length_;	// occupied length of vector
  size_t			capacity_;	// allocated length of vector
};



//#     Filename:       VarVecDef.h
//#
//#     Definitions for ValVec and PtrVec templates
//#
//#
//#     Author:         John Doug Reynolds
//#     
//#     Date:           May, 1998
//#
//#
//#
//# (c) Copyright The Johns Hopkins University 1998
//# All Rights Reserved
//#
//# The software and information contained herein are proprietary to The
//# Johns Hopkins University, Copyright 1998.  This software is furnished
//# pursuant to a written license agreement and may be used, copied,
//# transmitted, and stored only in accordance with the terms of such
//# license and with the inclusion of the above copyright notice.  This
//# software and information or any other copies thereof may not be
//# provided or otherwise made available to any other person.
//#
//#
//# Modification history:
//#
//# Peter Kunszt, Oct. 1998    Add clear() method to ValVec
//# Peter Kunszt, Feb. 1999    Add keep() method to ValVec
//#
//# Peter Kunszt, Feb. 1999    Add new template LinPool
//# Peter Kunszt, Apr. 1999    Add remove() method to ValVec
//# Peter Kunszt, Jul. 2000    Add new class VarStr

// This file defines the templates declared in VarVec.h, and should
// not be treated like a normal header file.  Include this file only
// in source modules where template instantiation will occur.

/* --- ValVec methods ------------------------------------------------------ */

// destructor

template<class T>
ValVec<T>::~ValVec( void )
{
   if ( vector_ ) {
      for ( size_t i = 0; i < capacity_; ++i ) vector_[i].~T();
      free( vector_ );
   }
   if ( pFill_ ) delete pFill_;
}

// default constructor

template<class T>
ValVec<T>::ValVec( size_t capacity, size_t increment )
{
   pFill_ = vector_ = 0;
   increment_ = length_ = capacity_ = 0;
   insert( capacity );
   increment_ = increment;
   length_ = 0;
}

// alternate constructor for defining the fill value

template<class T>
ValVec<T>::ValVec( const T &rFill, size_t capacity, size_t increment )
{
   vector_ = 0;
   increment_ = length_ = capacity_ = 0;
   pFill_ = new T(rFill);
   insert( capacity );
   increment_ = increment;
   length_ = 0;
}

// copy constructor

template<class T>
ValVec<T>::ValVec( const ValVec &orig )
{
   capacity_ = 0;
   pFill_ = vector_ = 0;
   *this = orig;
}

// assignment/copy operator

template<class T>
ValVec<T>&	ValVec<T>::operator =( const ValVec &orig )
{
   if ( &orig == this ) return *this;

   if ( orig.pFill_ )
      if ( pFill_ )
	 *pFill_ = *orig.pFill_;
      else
	 pFill_ = new T(*orig.pFill_);
   else
      if ( pFill_ ) {
	 delete pFill_;
	 pFill_ = 0;
      }

   if ( orig.capacity_ > capacity_ ) {
      increment_ = 1;
      length_ = capacity_;
      insert( orig.capacity_ - capacity_ );
   }

   for ( size_t i = 0; i < orig.length_; ++i ) vector_[i] = orig.vector_[i];

   increment_ = orig.increment_;
   length_ = orig.length_;
   return *this;
}

// bounds-checking array operator (const version)

template<class T>
const T&	ValVec<T>::operator []( size_t index ) const
{
   if ( index >= length_ )
      throw _BOUNDS_EXCEPTION( "ValVec", "vector_", length_, index );
   return vector_[index];
}

// bounds-checking array operator (non-const version)

template<class T>
T&	ValVec<T>::operator []( size_t index )	
{
   if ( index >= length_ )
      throw _BOUNDS_EXCEPTION( "ValVec", "vector_", length_, index );
   return vector_[index];
}

// at method: bounds-adjusting array operator

template<class T>
T&	ValVec<T>::at( size_t index )
{
   if ( index >= length_ ) insert( 1 + index - length_ );
   return vector_[index];
}

// append method: efficiently insert element at end of array

template<class T>
size_t	ValVec<T>::append( const T &t )
{
   (length_ < capacity_ ? vector_[length_++] : at(length_)) = t;
   return length_;
}

// insert method: insert and initialize new array elements

// Warning: if the constructor or destructor for class T throws an
// exception when invoked from this function, the affected vector is
// considered a complete loss and is left dangling.  The ValVec object
// is left in a consistent and usable state: either updated, not
// updated, or empty.  This potential memory leak is unfortunate, but
// I do not know of a better response.

template<class T>
size_t	ValVec<T>::insert( size_t count, size_t offset )
{
   if ( offset > length_ )
      throw _BOUNDS_EXCEPTION("ValVec::insert","offset greater than length");

   size_t newLength	= length_ + count;
   size_t start		= length_ - offset;
   size_t i;

   if ( newLength > capacity_ ) {
      // allocate new vector
      size_t cap = increment_ ? capacity_ + increment_ : 2 * capacity_;
      if ( newLength > cap ) cap = newLength;
      T *vec = (T*) malloc( cap * sizeof(T) );

      // bitwise copy original occupied region into new vector
      if ( length_ ) {
	 memcpy( vec, vector_, start * sizeof(T) );
	 memcpy( vec + start + count, vector_ + start, offset * sizeof(T) );
      }

      // construct newly occupied region with fill or default
      if ( pFill_ )
	 for ( i = 0; i < count; ++i ) ::new(vec+start+i) T(*pFill_);
      else
	 for ( i = 0; i < count; ++i ) ::new(vec+start+i) T;

      // construct new unoccupied region with default
      for ( i = newLength; i < cap; ++i ) ::new(vec+i) T;

      // replace old vector with new vector
      T *oldVec = vector_;
      size_t oldCap = capacity_;
      vector_ = vec;
      capacity_ = cap;

      // destroy original unoccupied region and free discarded vector
      if ( oldVec ) {
	 for ( i = length_; i < oldCap; ++i ) oldVec[i].~T();
	 free( oldVec );
      }
   }
   else if ( count ) {
	   if ( offset ) {
		   try {
			   // destroy obliterated portion of unoccupied region
			   for ( i = 0; i < count; ++i ) vector_[length_+i].~T();

			   // bitwise move displaced portion of occupied region
			   memmove(vector_+start+count, vector_+start, offset * sizeof(T));

			   // construct vacated region with fill or default
			   if ( pFill_ )
				   for ( i = 0; i < count; ++i ) ::new(vector_+start+i) T(*pFill_);
			   else
				   for ( i = 0; i < count; ++i ) ::new(vector_+start+i) T;
		   }
		   catch (...) {
			   vector_ = 0;
			   length_ = capacity_ = 0;
			   throw;
		   }
	   }
	   else if ( pFill_ ) {
		   for ( i = 0; i < count; ++i ) vector_[length_+i] = *pFill_;
	   }
   }

   return length_ = newLength;
}

// cut method: remove array elements

// Warning: see insert method warning, above, regarding a potential
// memory leak.  The only difference here is that in all cases the
// ValVec object is left empty.

template<class T>
size_t	ValVec<T>::cut( size_t count, size_t offset )
{
   if ( count + offset > length_ )
      throw _BOUNDS_EXCEPTION("ValVec::cut","count+offset greater than length");

   if ( count && offset )
      try {
	 size_t i;
	 T *start = vector_ + length_ - offset - count;

	 // destroy obliterated portion of occupied region
	 for ( i = 0; i < count; ++i ) start[i].~T();

	 // bitwise move displaced portion of occupied region
	 memmove( start, start + count, offset * sizeof(T) );

	 // construct vacated region with default
	 for ( i = 0; i < count; ++i ) ::new(start+offset+i) T;
      }
      catch (...) {
	 vector_ = 0;
	 length_ = capacity_ = 0;
	 throw;
      }

   return length_ -= count;
}

// fill method: create and return default fill value, or return existing value

template<class T>
T&	ValVec<T>::fill( void )
{
   return pFill_ ? *pFill_ : *(pFill_ = new T);
}

// fillExists method: return true if fill value exists

template<class T>
bool	ValVec<T>::fillExists( void ) const
{
	return ( pFill_ == NULL) ? false : true;
}

// unsetFill method: destroy existing fill value

template<class T>
void	ValVec<T>::unsetFill( void )
{
   if ( pFill_ ) {
      delete pFill_;
      pFill_ = 0;
   }
}

// clear method: reset every value to fill value if there is one

template<class T>
void	ValVec<T>::clear( void )
{
   if ( pFill_ ) {
     for(size_t i = 0; i < length_; i++)
       vector_[i] = *pFill_;
   }
}

// clear method: reset every value to fill value if there is one

template<class T>
void	ValVec<T>::sort( int (*compar)(const void*, const void*) )
{
  qsort(vector_, length_, sizeof(T), compar);
}

// keep method: just reset the length by count.

template<class T>
size_t	ValVec<T>::keep( size_t count )
{
   if ( count > length_ )
      throw _BOUNDS_EXCEPTION("ValVec::keep","count greater than length");

  return length_ -= count;
}

// remove method: call cut

template<class T>
void	ValVec<T>::remove( size_t offset )
{
   if ( offset >= length_ )
      throw _BOUNDS_EXCEPTION("ValVec::remove","count greater than length");

   cut(1, length_ - offset - 1);
   return;
}

/* --- PtrVec methods ------------------------------------------------------ */

// destructor

template<class T>
PtrVec<T>::~PtrVec( void )
{
   cut( length_ );
   if ( vector_ ) delete [] vector_;
}

// default constructor

template<class T>
PtrVec<T>::PtrVec( bool internal, size_t capacity, size_t increment )
{
   length_ = capacity_ = 0;
   increment_ = increment;
   internal_ = internal;
   if(capacity) {
     vector_ = new T* [capacity];
     for(size_t i = 0; i < capacity; i++) vector_[i] = NULL;
   } else {
     vector_ = NULL;
   }
   capacity_ = capacity;
}

// copy constructor

template<class T>
PtrVec<T>::PtrVec( const PtrVec &obj, bool internalize )
{
   vector_ = 0;
   length_ = capacity_ = 0;
   copy( obj, internalize );
}

// copy method: make either local or shared copy of external pointers

template<class T>
PtrVec<T>&	PtrVec<T>::copy( const PtrVec &obj, bool internalize )
{
   if ( &obj == this ) {
      if ( internalize != internal_ )
	 throw _INTERFACE_EXCEPTION("PtrVec::copy"
			,"attempt to ex/in-ternalize by self-assignment");
      return *this;
   }

   cut( length_ );
   increment_ = obj.increment_;
   internal_ = internalize;

   if ( obj.capacity_ > capacity_ ) {
      if ( vector_ ) delete [] vector_;
      capacity_ = 0;
      vector_ = new T* [obj.capacity_];
      for(size_t j = 0; j < obj.capacity_; j++) vector_[j] = NULL;
      capacity_ = obj.capacity_;
   }

   if ( internalize ) {
      for ( size_t i = 0; i < obj.length_; ++i )
	 vector_[i] = PtrDup( obj.vector_[i] );
   } else
      memcpy( vector_, obj.vector_, obj.length_ * sizeof(T*) );

   length_ = obj.length_;
   return *this;
}

// bounds-checking array operator (const version)

template<class T>
const T*&	PtrVec<T>::operator []( size_t index ) const
{
   if ( index >= length_ )
      throw _BOUNDS_EXCEPTION( "PtrVec", "vector_", length_, index );
   return (const T*&) vector_[index];
}

// bounds-checking array operator (non-const version)

template<class T>
T*&	PtrVec<T>::operator []( size_t index )	
{
   if ( index >= length_ )
      throw _BOUNDS_EXCEPTION( "PtrVec", "vector_", length_, index );
   return vector_[index];
}

// at method: bounds-adjusting array operator

template<class T>
T*&	PtrVec<T>::at( size_t index )
{
   if ( index >= length_ ) insert( 1 + index - length_ );
   return vector_[index];
}

// entries method: return the number of non-NULL entries in vector
// NOTE: this is different from length(), which also counts NULL pointers.

template<class T>
size_t	PtrVec<T>::entries( void ) const
{
  size_t i, nEntries = 0;
  for( i = 0; i < length_; i++ )
    if( vector_[i] )
      nEntries++;
  return nEntries;
}

// append method: efficiently insert element at end of array

template<class T>
size_t	PtrVec<T>::append( T *t )
{
   (length_ < capacity_ ? vector_[length_++] : at(length_)) = t;
   return length_;
}

// insert method: insert and initialize new array elements

template<class T>
size_t	PtrVec<T>::insert( size_t count, size_t offset )
{
   if ( offset > length_ )
      throw _BOUNDS_EXCEPTION("PtrVec::insert","offset greater than length");

   size_t newLength	= length_ + count;
   size_t start		= length_ - offset;

   if ( newLength > capacity_ ) {
      size_t cap = increment_ ? capacity_ + increment_ : 2 * capacity_;
      if ( newLength > cap ) cap = newLength;
      T **vec = new T* [cap];
      for(size_t j = 0; j < cap; j++) vec[j] = NULL;
      if ( vector_ ) {
	 memcpy( vec, vector_, start * sizeof(T*) );
	 memcpy( vec + start + count, vector_ + start, offset * sizeof(T*) );
	 delete [] vector_;
      }
      capacity_ = cap;
      vector_ = vec;
   }
   else if ( count )
      memmove( vector_ + start + count, vector_ + start, offset * sizeof(T*) );

   memset( vector_ + start, 0, count * sizeof(T*) );

   return length_ = newLength;
}


// nextEmpty method: return index of next available (empty) slot in vector.

template<class T>
size_t	PtrVec<T>::nextEmpty()
{
  size_t empty;
  for( empty = 0; empty < length_; empty++ )
    if( vector_[empty] == NULL )
      break;
  return empty;
}

 
// add method: add given element into first available empty slot.

template<class T>
size_t	PtrVec<T>::add( T *t )
{
  size_t index;
  if( (index = nextEmpty()) == length_ ) 
    append( t );
  else
    vector_[index] = t;
  return index;
}

// index method: return the index of the given element if it exists in the
//               array, else return -1.

template<class T>
int   	PtrVec<T>::index( const T *t )
{
  size_t index;
  for( index = 0; index < length_; index++ )
    if( vector_[index] == t )
      return index;
  return -1;
}

// cut method: remove array elements

template<class T>
size_t	PtrVec<T>::cut( size_t count, size_t offset )
{
   if ( count + offset > length_ )
      throw _BOUNDS_EXCEPTION("PtrVec::cut","count+offset greater than length");

   if ( count ) {
      T **start = vector_ + length_ - offset - count;
      if ( internal_ )
	 for ( size_t i = 0; i < count; ++i ) if ( start[i] ) delete start[i];
      memmove( start, start + count, offset * sizeof(T*) );
   }

   return length_ -= count;
}

// remove method: call cut

template<class T>
void	PtrVec<T>::remove( size_t offset )
{
   if ( offset >= length_ )
      throw _BOUNDS_EXCEPTION("PtrVec::remove","count greater than length");

   cut(1, length_ - offset - 1);
   return;
}

// internalize method: replace shared pointers with local copies

template<class T>
void	PtrVec<T>::internalize( void )
{
   if ( ! internal_ ) {
      for ( size_t i = 0; i < length_; ++i )
	 vector_[i] = PtrDup( vector_[i] );
      internal_ = true;
   }
}

// externalize method: change status of pointers from local to shared

template<class T>
void	PtrVec<T>::externalize( void )
{
   internal_ = false;
}

// internal method: return true if pointers are local

template<class T>
bool	PtrVec<T>::internal( void ) const
{
   return internal_;
}


/* --- LinPool methods ----------------------------------------------------- */

// destructor

template<class T>
LinPool<T>::~LinPool( void )
{
  // delete all objects from pool capacity
  for ( size_t i = 0; i < capacity_; ++i )
    if ( vector_[i] ) delete vector_[i]; // failsafe - if someone deletes above

  if ( vector_ ) delete [] vector_;
}

// default constructor

template<class T>
LinPool<T>::LinPool( size_t capacity, size_t increment )
{
   length_ = capacity_ = 0;
   increment_ = increment;
   vector_ = capacity ? new T* [capacity] : 0;
   capacity_ = capacity;
   // generate new objects for the capacity
   for ( size_t i = 0; i < capacity; i++ )
     vector_[i] = new T;
}

// bounds-checking array operator (const version)

template<class T>
const T*&	LinPool<T>::operator []( size_t index ) const
{
   if ( index >= length_ )
      throw _BOUNDS_EXCEPTION( "LinPool", "vector_", length_, index );
   return (const T*&) vector_[index];
}

// bounds-checking array operator (non-const version)

template<class T>
T*&	LinPool<T>::operator []( size_t index )	
{
   if ( index >= length_ )
      throw _BOUNDS_EXCEPTION( "LinPool", "vector_", length_, index );
   return vector_[index];
}

// use method: bounds-adjusting function

template<class T>
T*&	LinPool<T>::use( void )
{
  if(length_ == capacity_) { // last element reached, extend!
    size_t cap = increment_ ? capacity_ + increment_ : 2 * capacity_;
    T **vec = new T* [cap];
    if ( vector_ ) {
      memcpy( vec, vector_, capacity_ * sizeof(T*) );
      delete [] vector_;
    }
    for( size_t i = capacity_; i < cap; i++)
      vec[i] = new T;
    capacity_ = cap;
    vector_ = vec;
  }
  return vector_[length_++];
}


#endif /* VARVEC_H */
