/*	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 - Yet another application framework
 *  Copyright (C) 1997, 1998 William Edward Woody
 *  
 *  This library is free software; you can redistribute it
 *  and/or modify it under the terms of the GNU Library
 *  General Public License as published by the Free Software
 *  Foundation; either version 2 of the License, or any
 *  later version.
 *  
 *  This library is distributed in the hope that it will be
 *  useful, but WITHOUT ANY WARRANTY; without even the implied
 *  warranty of MERCHANTABIILITY or FITNESS FOR A PARTICULAR
 *  PURPOSE. See the GNU Library General Public License for
 *  more details.
 *  
 *  You should have received a copy of the GNU Library General
 *  Public License along with this library; if not, write to the
 *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 *  Boston, MA 02111-1307, USA.
 *  
 *  To contact the author, either e-mail me at woody@pandawave.com, 
 *	or write to
 *  
 *          William Edward Woody
 *          In Phase Consulting
 *          1545 Ard Eevin Avenue
 *          Glendale, CA 91202
 *
 *	Or visit us on the web at http://www.pandawave.com
 */

#ifndef PandaWave_XDYNARRAY
#define PandaWave_XDYNARRAY

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

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

/*	@C"XGArray"
 *	@H"XDynArray.h"
 *	@I
 *
 *		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.
 */

class XGArray {
	public:
								XGArray();
		virtual					~XGArray();
		
		/*
		 *	External interface
		 */
		
		
		void					Delete(long);
		void					DeleteAll(void);
		void					SetLength(long);
		
		/*	@G"Public Methods"
		 *	@F"XGArray::Length"
		 *	@I
		 *		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;
};

/*	@C"XGSizeArray"
 *	@H"XDynArray.h"
 *	@I
 *
 *		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
 */

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
 */

/*	@C"XGDynArray"
 *	@D"XGArray"
 *	@H"XDynArray.h"
 *	@I
 *
 *		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:
	
		// @G"Construction/Destruction"
		
		/*	@F"XGDynArray::XGDynArray"
		 *	@I
		 *
		 *		Constructs an empty array.
		 */
		
								XGDynArray()
									{
										fArray = NULL;
									}
									
		/*	@F"XGDynArray::~XGDynArray"
		 *	@I
		 *		Destroys this object, as well as destroying the dynamic
		 *	array of objects by calling each destructor
		 */
		
		virtual					~XGDynArray()
									{
										if (fArray) delete[] fArray;
									}
		
		/*	@F"XGDynArray::operator ="
		 *	@I
		 *		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
		 */
		
		// @G"Element Access"
		
		/*	@F"XGDynArray::Insert"
		 *	@I
		 *		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);
									}
		
		/*	@F"XGDynArray::operator +="
		 *	@I
		 *		This appends the specified item to the end of the array.
		 */
		
		XGDynArray<T> &			operator += (const T&t)
									{
										Insert(fLength,t);
										return *this;
									}
		
		/*	@F"XGDynArray::operator []"
		 *	@I
		 *		This returns a reference to the specified item
		 */
		
		T &						operator [](long l) const
									{
										return fArray[l];
									}
		
	protected:
		/*
		 *	Item access
		 */
		
		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;
};

/*	@C"XGPDynArray"
 *	@D"XGSizeArray"
 *	@H"XDynArray.h"
 *	@I
 *
 *		Dynamic array to pointers to things. This maintains an array of pointers,
 *	rather than to objects.
 */

template <class T> class XGPDynArray : public XGSizeArray {
	public:
	
		// @G"Construction/Destruction"
		
		/* @F"XGPDynArray::XGPDynArray"
		 * @I
		 *		Ths constructs an empty array
		 */
		
								XGPDynArray() : XGSizeArray(sizeof(T *))
									{
									}
		
		/*	@F"XGPDynArray::~XGPDynArray" @I
		 *
		 *		This destroys this array, releasing all allocated memory. This
		 *	does *not* destroy the pointers.
		 */
		
		virtual					~XGPDynArray()
									{
									}
		
		
		/*	@F"XGPDynArray::operator ="
		 *	@I
		 *		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
		 */
		
		// @G"Element Access"
		
		/*	@F"XGPDynArray::Insert"
		 *	@I
		 *		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);
									}
									
		/*	@F"XGPDynArray::operator +="
		 *	@I
		 *		This appends the specified pointer to the end of the array.
		 */
		
		XGPDynArray<T> &		operator += (const T *t)
									{
										Insert(fLength,t);
										return *this;
									}

		/*	@F"XGPDynArray::operator []"
		 *	@I
		 *		This returns a reference to the specified pointer
		 */
		
		T* &					operator[](long i) const
									{
										return ((T **)fArray)[i];
									}
};

/*	@C"XGSDynArray"
 *	@D"XGSizeArray"
 *	@H"XDynArray.h"
 *	@I
 *
 *		Like the XGPDynArray, but used to deal with arrays of structures
 *	which have no constructors, destructors, etc.
 */

template <class T> class XGSDynArray : public XGSizeArray {
	public:
	
		// @G"Construction/Destruction"
		
		/* @F"XGSDynArray::XGSDynArray"
		 * @I
		 *		Ths constructs an empty array
		 */
		
								XGSDynArray() : XGSizeArray(sizeof(T))
									{
									}
		
		/*	@F"XGSDynArray::~XGSDynArray" @I
		 *
		 *		This destroys this array, releasing all allocated memory.
		 */
		
		virtual					~XGSDynArray()
									{
									}
		
		/*	@F"XGSDynArray::operator ="
		 *	@I
		 *		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
		 */
		
		// @G"Element Access"
		
		/*	@F"XGSDynArray::Insert"
		 *	@I
		 *		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);
									}

		/*	@F"XGSDynArray::operator +="
		 *	@I
		 *		This appends the specified pointer to the end of the array.
		 */
		
		XGSDynArray<T> &		operator += (const T &t)
									{
										Insert(fLength,t);
										return *this;
									}

		/*	@F"XGSDynArray::operator []"
		 *	@I
		 *		This returns a reference to the specified pointer
		 */
		
		T &						operator[](long i) const
									{
										return ((T *)fArray)[i];
									}
};

#endif // PandaWave_XDYNARRAY
