/*	XDynArray.h
 *
 *		This is my custom classes for manipulating a dynamic array
 *	of objects. As this is pretty common, yet the 'dynarray' standard
 *	C++ class is not declared for either VC++, Metrowerks C++, or
 *	the GNU C++ library, I'm doing the minimum functionality I need here.
 */

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

  YAAF is Copyright 1997-1999 by William Woody.

  Redistribution and use in source and binary forms, with or without 
  modification, are permitted provided that the following conditions 
  are met:

  Redistributions of source code must retain the above copyright notice, 
  this list of conditions and the following disclaimer.

  Neither the name of the copyright holder or other contributors may
  be used to promote products derived from this software without
  specific written prior permission.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 
  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 
  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 
  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 
  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 
  SOFTWARE.
  
  Contact:   woody@alumni.caltech.edu
  Web page:  http://www.pandawave.com/yaaf/

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

#ifndef PandaWave_XDYNARRAY
#define PandaWave_XDYNARRAY

#include <XConfig.h>
#include <stdlib.h>

/**@name Support--Dynamic Array Processing
 *
 *		These routines and templates provide for dynamic array handling
 *	in the YAAF library. I'm considering depreciating these classes,
 *	as their use within the YAAF library is currently pretty minimal.
 *	Instead, you may consider using the C++ STL library if you need
 *	the functionality provided in these classes.
 *
 *		If you don't want me to depreciate these classes, you may want
 *	to drop me a line at woody@alumni.caltech.edu.  Thanks.
 */
 
//@{

/************************************************************************/
/*																		*/
/*	Basic Array Code													*/
/*																		*/
/************************************************************************/

/*$	XGArray
 *
 *		Array of objects. This knows how to manage an array (of fixed
 *	sized objects), grow the array, shrink the array, etc.
 *
 *		This forms the code base for the dynamic array stuff later, and
 *	is internal to the YAAF libraries.
 *
 *		The reason for this class is simple: by moving as much of the
 *	common array processing for handling dynamic arrays into this class,
 *	I hope to reduce the size of the footprint used by the various
 *	array templates, and thus reduce code size.
 */

class XGArray {
	public:
								XGArray();
		virtual					~XGArray();
		
		/*
		 *	External interface
		 */
		
		
		void					Delete(long);
		void					DeleteAll(void);
		void					SetLength(long);
		
		
		/*$	XGArray::Length
		 *
		 *		This returns the number of elements in this array.
		 */
		
		long					Length(void) const
									{
										return fLength;
									}					
	protected:
		/*
		 *	Hidden elements
		 */
		
		void					Copy(const XGArray &);
		void					InsertElement(long, void *);
		
		/*
		 *	Virtual overrides for element maintanance
		 */
		
		virtual void			ChangeArray(long size, long copy) = 0;
		virtual	void			CopyArray(long dest, long src) = 0;
		virtual void			CopyElement(long, const void *) = 0;
		virtual void			*GetElement(long) const = 0;

		long					fLength;
		long					fAlloc;
};

/*$	XGSizeArray
 *
 *		This deals with arrays of objects which have no constructors,
 *	no virtual tables, no destructors, and default copy semantics. In
 *	short, this deals with simple objects. This is also an internal
 *	class to the dynamic array classes, but provided the common semantics
 *	for handling structures which can be safely copied by copying their
 *	memory contents.
 *
 *		Better here than expanded eight ways from sunday in the templates.
 */

class XGSizeArray : public XGArray {
	public:
								XGSizeArray(size_t s);
		virtual					~XGSizeArray();
		
	protected:
		virtual void			ChangeArray(long size, long copy);
		virtual	void			CopyArray(long dest, long src);
		virtual void			CopyElement(long, const void *);
		virtual void			*GetElement(long) const;

		unsigned char			*fArray;
		size_t					fSize;
};


/************************************************************************/
/*																		*/
/*	Templates															*/
/*																		*/
/************************************************************************/

/*
 *	Template declaration; must be native alignment to the program
 *	I'm compiling. This also means that I don't expose the template
 *	as in-line code across libraries with different structure alignments
 */

/*$	XGDynArray
 *
 *		This is the definition of a dynamic array template. This version
 *	of the template expands to the largest memory footprint, but also
 *	calls the constructor and destructors of the items stored in the array,
 *	as well as using the copy method of the object. This version is for
 *	storing arrays of C++ objects.
 */

template <class T> class XGDynArray : public XGArray {
	public:
		
		/*$	XGDynArray::XGDynArray
		 *
		 *		Constructs an empty array.
		 */
		
								XGDynArray()
									{
										fArray = NULL;
									}
									
		/*$	XGDynArray::~XGDynArray
		 *
		 *		Destroys this object, as well as destroying the dynamic
		 *	array of objects by calling each destructor.
		 */
		
		virtual					~XGDynArray()
									{
										if (fArray) delete[] fArray;
									}
		
		/*$	XGDynArray::operator =
		 *
		 *		Copies the contents of this array to another array,
		 *	destroying the old array and using the copy operator to
		 *	move the array elements.
		 */
		
		const XGDynArray<T>		&operator = (const XGDynArray<T> &old)
									{
										Copy(old);
										return *this;
									}
	
		/*
		 *	Element access
		 */
		
		/*$	XGDynArray::Insert
		 *
		 *		This inserts the specified element at the location given.
		 *	The index is a zero-based index; if #i# is zero, this inserts
		 *	at the beginning. If #i# is the length, appends to the end.
		 */
		
		void					Insert(long i, const T& t)
									{
										InsertElement(i,(void *)&t);
									}
		
		/*$	XGDynArray::operator +=
		 *
		 *		This appends the specified item to the end of the array.
		 *	This is functionally equivalent to array.Insert(array.Length(),item);
		 */
		
		XGDynArray<T> &			operator += (const T&t)
									{
										Insert(fLength,t);
										return *this;
									}
		
		/*$	XGDynArray::operator []
		 *
		 *		This returns a reference to the specified item.
		 *	As this is a reference, you can use this on the LHS of
		 *	an expression:  array[i] = obj;
		 */
		
		T &						operator [](long l) const
									{
										return fArray[l];
									}
		
	protected:
		/*
		 *	Item access. These overrides provide the base XGArray
		 *	class it's underlying copy engine.
		 */
		
		void					ChangeArray(long newsize, long copy)
									{
										T *array;
										long i;
										
										if (newsize) array = new T[newsize];
										else array = NULL;
										for (i = 0; i < copy; i++) {
											array[i] = fArray[i];
										}
										if (fArray) delete[] fArray;
										fArray = array;
									}
		void					CopyArray(long dest, long src)
									{
										fArray[dest] = fArray[src];
									}
		void					CopyElement(long dest, const void *ptr)
									{
										fArray[dest] = *((const T *)ptr);
									}
		void					*GetElement(long i) const
									{
										return (void *)(fArray + i);
									}
	
	private:
		T						*fArray;
};

/*$	XGPDynArray
 *
 *		Dynamic array to pointers to things. This maintains an array of pointers,
 *	rather than to objects. This is derived from the XGSizeArray class, making
 *	for a much smaller footprint.
 */

template <class T> class XGPDynArray : public XGSizeArray {
	public:
	
		/*$ XGPDynArray::XGPDynArray
		 *
		 *		Ths constructs an empty array.
		 */
		
								XGPDynArray() : XGSizeArray(sizeof(T *))
									{
									}
		
		/*$	XGPDynArray::~XGPDynArray
		 *
		 *		This destroys this array, releasing all allocated memory. This
		 *	does *not* destroy the pointers.
		 */
		
		virtual					~XGPDynArray()
									{
									}
		
		
		/*$	XGPDynArray::operator =
		 *
		 *		Copies the contents of this array to another array,
		 *	destroying the old array and copying the pointers.
		 */
		 
		const XGPDynArray<T>	&operator = (const XGPDynArray<T> &old)
									{
										Copy(old);
										return *this;
									}
		
		/*
		 *	Element access
		 */
		
		/*$	XGPDynArray::Insert
		 *
		 *		This inserts the specified pointer at the location given.
		 *	The index is a zero-based index; if i is zero, this inserts
		 *	at the beginning. If i is the length, appends to the end.
		 */
		 
		void					Insert(long i, const T *ptr)
									{
										InsertElement(i,(void *)&ptr);
									}
									
		/*$	XGPDynArray::operator +=
		 *
		 *		This appends the specified pointer to the end of the array.
		 *	This is equivalent to array.Insert(array.Length(),item);
		 */
		
		XGPDynArray<T> &		operator += (const T *t)
									{
										Insert(fLength,t);
										return *this;
									}

		/*$	XGPDynArray::operator []
		 *
		 *		This returns a reference to the specified pointer.
		 *	As this is a reference, you can use this on the LHS of
		 *	an expression:  array[i] = ptr;
		 */
		
		T* &					operator[](long i) const
									{
										return ((T **)fArray)[i];
									}
};

/*$	XGSDynArray
 *
 *		Like the XGPDynArray, but used to deal with arrays of structures
 *	which have no constructors, destructors, etc. This is useful in that
 *	this provides a very small footprint as it can use the memcpy() routine
 *	to copy memory instead of the object's copy operator.
 */

template <class T> class XGSDynArray : public XGSizeArray {
	public:
		
		/*$ XGSDynArray::XGSDynArray
		 *
		 *		Ths constructs an empty array
		 */
		
								XGSDynArray() : XGSizeArray(sizeof(T))
									{
									}
		
		/*$	XGSDynArray::~XGSDynArray
		 *
		 *		This destroys this array, releasing all allocated memory.
		 */
		
		virtual					~XGSDynArray()
									{
									}
		
		/*$	XGSDynArray::operator =
		 *
		 *		Copies the contents of this array to another array,
		 *	destroying the old array and using a memory copy operator to
		 *	move the array elements
		 */
		
		const XGSDynArray<T>	&operator = (const XGSDynArray<T> &old)
									{
										Copy(old);
										return *this;
									}
		
		/*
		 *	Element access
		 */
		
		/*$	XGSDynArray::Insert
		 *
		 *		This inserts the specified pointer at the location given.
		 *	The index is a zero-based index; if i is zero, this inserts
		 *	at the beginning. If i is the length, appends to the end.
		 */
		 
		void					Insert(long i, const T &ptr)
									{
										InsertElement(i,(void *)&ptr);
									}

		/*$	XGSDynArray::operator +=
		 *
		 *		This appends the specified pointer to the end of the array.
		 *	This is equivalent to array.Insert(array.Length(),item);
		 */
		
		XGSDynArray<T> &		operator += (const T &t)
									{
										Insert(fLength,t);
										return *this;
									}

		/*$	XGSDynArray::operator []
		 *
		 *		This returns a reference to the specified pointer
		 *	As this is a reference, you can use this on the LHS of
		 *	an expression:  array[i] = ptr;
		 */
		
		T &						operator[](long i) const
									{
										return ((T *)fArray)[i];
									}
};

//@}

#endif // PandaWave_XDYNARRAY
