/*	@doc INTERNAL
 *
 *	@module _ARRAY.H  Generic Array Class |
 *	
 *	This module declares a generic array class for constant sized
 *	elements (although the elements themselves may be of any size).
 *
 *	Original Author: <nl>
 *		Christian Fortini
 *
 *	History: <nl>
 *		6/25/95	alexgo	Cleanup and Commenting
 *
 *	Copyright (c) 1995-1997, Microsoft Corporation. All rights reserved.
 */

#ifndef _ARRAY_H
#define _ARRAY_H

class CFormatRunPtr;

/*
 *	ArrayFlag
 *
 *	@enum	Defines flags used with the array class
 */
enum tagArrayFlag
{
	AF_KEEPMEM		= 1,	//@emem Don't delete any memory 
	AF_DELETEMEM	= 2,	//@emem Delete as much memory as possible
};

//@type ArrayFlag | flags controlling the usage of generic arrays 
//(and specifically how memory is handled)
typedef enum tagArrayFlag ArrayFlag;


/*
 *	CArrayBase
 *	
 * 	@class	The CArrayBase class implements a generic array class.  It should
 *	never be used directly; use the type-safe template, <c CArray>, instead.
 *
 *	@devnote There are exactly two legal states for an array: empty or not.
 *	If an array is empty, the following must be true:
 *
 *		<md CArrayBase::_prgel> == NULL; <nl>
 *		<md CArrayBase::_cel> == 0; <nl>
 *		<md CArrayBase::_celMax> == 0;
 *
 *	Otherwise, the following must be true:
 *
 *		<md CArrayBase::_prgel> != NULL; <nl>
 *		<md CArrayBase::_cel> <lt>= <md CArrayBase::_celMax>; <nl>
 *		<md CArrayBase::_celMax> <gt> 0;
 *
 *	
 *	An array starts empty, transitions to not-empty as elements are inserted
 *  and will transistion back to empty if all of the array elements are 
 *	removed.
 *
 */
class CArrayBase
{
//@access Public Methods
public:

#ifdef DEBUG
	BOOL	Invariant() const;		//@cmember Validates state consistentency
	void*	Elem(LONG iel) const;	//@cmember Get ptr to <p iel>'th run
#else
	void*	Elem(LONG iel) const {return _prgel + iel*_cbElem;}
#endif
	
	CArrayBase (LONG cbElem);		//@cmember Constructor
	~CArrayBase () {Clear(AF_DELETEMEM);}

	void 	Clear (ArrayFlag flag);	//@cmember Delete all runs in array
	LONG 	Count() const {return _cel;}//@cmember Get count of runs in array
									//@cmember Remove <p celFree> runs from
									// array, starting at run <p ielFirst>
	void 	Remove(LONG ielFirst, LONG celFree);
									//@cmember Replace runs <p iel> through
									// <p iel+cel-1> with runs from <p par>
	BOOL	Replace (LONG iel, LONG cel, CArrayBase *par);
	
	LONG 	Size() const {return _cbElem;}//@cmember Get size of a run			

//@access Protected Methods
protected:
	void* 	ArAdd (LONG cel, LONG *pielIns);	//@cmember Add <p cel> runs
	void* 	ArInsert(LONG iel, LONG celIns);	//@cmember Insert <p celIns>
												// runs

//@access Protected Data
protected:
	char*	_prgel;		//@cmember Pointer to actual array data
	LONG 	_cel;	  	//@cmember Count of used entries in array
	LONG	_celMax;	//@cmember Count of allocated entries in array
	LONG	_cbElem;	//@cmember Byte count of an individual array element
};

/*
 *	CArray
 *
 *	@class
 *		An inline template class providing type-safe access to CArrayBase
 *
 *	@tcarg class | ELEM | the class or struct to be used as array elements
 */

template <class ELEM> 
class CArray : public CArrayBase
{
//@access Public Methods
public:
	
	CArray ()								//@cmember Constructor
		: CArrayBase(sizeof(ELEM))
	{}
	
	ELEM *	Elem(LONG iel) const			//@cmember Get ptr to <p iel>'th
	{										// element
		return (ELEM *)CArrayBase::Elem(iel);
	}
	
	ELEM& 	GetAt(LONG iel) const			//@cmember Get <p iel>'th element
	{
		return *(ELEM *)CArrayBase::Elem(iel);
	}
	
	ELEM* 	Add (LONG cel, LONG *pielIns)	//@cmember Adds <p cel> elements						
	{										// to end of array
		return (ELEM*)ArAdd(cel, pielIns);
	}

	ELEM* 	Insert (LONG iel, LONG celIns)	//@cmember Insert <p celIns>
	{										// elements at index <p iel>
		return (ELEM*)ArInsert(iel, celIns);
	}

};

#endif