// TArray.cpp
//
// Copyright 1998 Diehl Graphsoft, Inc.
// All Rights Reserved.
//
// Implements the TSmallArray class.
//
// Started by Sean Flaherty.
//
// SourceSafe information for this version:
//    $Revision: 7 $
//    $Date: 10/27/00 8:21a $
//    $Author: Mfarnan $

#include "StdHeaders.h"	// DO NOT MOVE THIS LINE FROM BEING THE FIRST NON-COMMENT LINE.  [DMB, 10/30/95]

#include <Limits.h>

#if GS_COMP_BUILD
#include "MCMemory.h"
#else
#include "MiniCadCallBacks.h"
#endif

#include "TArray.h"

#undef THIS_FILE
#ifdef TEST
	static char THIS_FILE[] = __FILE__;
#endif


#if defined( USE_SEGMENTS )
	#pragma segment builtins
#endif

#if BUG
short TSmallArrayHandler::NumItems() const
/*
	Returns the number of items
*/
{
	if (this->fDataHandle) {
		ASSERTHANDLE(kSean, fDataHandle, fDataOffset + fNumAllocItems * fDataSize);
		
		if (fFreeMemWhenDone) {
			short *ptr = (short *) (*fDataHandle + fCountOffset);
			ASSERTPOINTER(kSean, ptr, sizeof(short));
			short numCells = *ptr;
			ASSERTN(kSean, fNumUsedItems == (fCountZeroBased) ? numCells+1 : numCells);
		}
		else
			ASSERTN(kSean, fNumAllocItems == fNumUsedItems);
			
	}
	else
		ASSERTN(kSean, fNumUsedItems == 0);
	
	ASSERTN(kSean, fNumUsedItems <= fNumAllocItems);
	return fNumUsedItems;
}
#endif



#if BUG
void* TSmallArrayHandler::GetCellPtr(short cellNum) const
/*
	Returns a pointer to the beginning of the data at cellNum
*/
{
	if (fDataHandle) {
		ASSERTHANDLE(kSean, fDataHandle, fDataOffset + fNumAllocItems * fDataSize);
	
		void* result;
		
		short numberOffCells = this->NumItems();
		
		#ifdef BUG
		if ((cellNum >= numberOffCells || cellNum < 0) && cellNum != kGSMaxSint16) {
#if TEST
			DSTOP((kSean, brief, "cellNum out of range! (cellNum = %i, cellMax = %i)\n", (long) cellNum, (long) this->NumItems() - 1));
#else
			DSTOP((kSean | kNoNetDebug, brief, "cellNum out of range! (cellNum = %i, cellMax = %i)\n", (long) cellNum, (long) this->NumItems() - 1));
#endif
		}
		if (numberOffCells == 0) {
#if TEST
			DSTOP((kSean, brief, "### TSmallArrayHandler::GetCellPtr - There are no items to access!\n"));
#else
			DSTOP((kSean | kNoNetDebug, brief, "### TSmallArrayHandler::GetCellPtr - There are no items to access!\n"));
#endif
		}
		#endif

		if (cellNum >= numberOffCells)
			cellNum =  numberOffCells - 1;
		else if (cellNum < 0)
			cellNum = 0;
		result = (*this->fDataHandle + this->fDataOffset + cellNum*fDataSize);
		
		#ifdef BUG
		if (((long)result)%2){
			DMSG((brief, kSean, "TSmallArray of elements which cause an odd address on 68000 processors!!"));
		}
		#endif
		
		ASSERTPOINTER(kSean, result, fDataSize);
		return result;
	}
	
	return nil;
}
#endif

#ifdef BUG
void TSmallArrayHandler::WriteArray() const
{
	DMSG((kEveryone, "dataSize = %i\n", fDataSize));
	DMSG((kEveryone, "dataOff = %i\n", fDataOffset));
	DMSG((kEveryone, "countOff = %i\n", fCountOffset));
	DMSG((kEveryone, "NumItems = %i\n", this->NumItems()));
}
#endif

#ifdef BUG
void TSmallArrayHandler::CheckArrayValues() const
{
		if (!this->fDataHandle)
			DMSG((brief, kSean, "### TSmallArrayHandler::CheckArrayValues - No data handle!\n"));
		else {
			ASSERTHANDLE(kSean, fDataHandle, fDataOffset + fNumAllocItems * fDataSize);

			if (this->fDataSize < 0L){
				DMSG((kEveryone, "fDataSize < 0!\n"));
			}
				
			size_t hSz;
			
			GS_GetHandleSize(gCBP, this->fDataHandle, hSz);

			if (this->fDataOffset < sizeof(short) || (size_t)this->fDataOffset > hSz){
				DMSG((kEveryone, "Illegal dataOff: %i\n", this->fDataOffset));
			}
			if (this->fCountOffset < 0L || (size_t)this->fCountOffset > (hSz - sizeof(short))){
				DMSG((kEveryone, "Illegal countOff: %i\n", this->fCountOffset));
			}
			if (this->NumItems() < 0){
				DMSG((kEveryone, "Number of items is < 0!\n"));
			}
			size_t spaceNeeded = this->NumItems() * this->fDataSize;
			if (spaceNeeded > (hSz - this->fDataOffset)){
				DMSG((kEveryone, "Handle is not large enough to hold %i items(items stored = %i)\n", (long) this->NumItems(), spaceNeeded / this->fDataSize));
			}
		#if !Lyndsey
			if (hSz > (size_t)(fNumUsedItems * fDataSize + this->fDataOffset)) {
				DMSG((kEveryone, "SpaceNeeded: %ld, hSize: %ld, fDataOffset: %ld, space available: %ld\n", spaceNeeded, hSz, this->fDataOffset, hSz - this->fDataOffset));
				DMSG((kEveryone, "Handle is larger than necessary to hold %i items(items stored = %i)\n", (long) this->NumItems(), spaceNeeded / this->fDataSize));
				//debugstr("Handle larger than necessary!!");
			}
		#endif
		}
}
#endif

TSmallArrayHandler::TSmallArrayHandler(long dataSz, long dataOff, long countOff, Bool8 zeroBasedCount, short numCells, Bool8 growGeometrically)
{
//	The following check is no longer needed since we don't support 680x0 processors anymore. -CS, 7/8/99
//	DSTOP((dataSz%2, brief, kSean, "TSmallArray constructed with odd data size - 68000 incompatible!!!"));

	this->fFreeMemWhenDone = true;
	this->fNumAllocItems = numCells;
//	this->fNumUsedItems = numCells;

	this->fDataHandle = GS_NewHandle(gCBP, numCells * dataSz + dataOff);

	this->fDataSize = dataSz;
	this->fDataOffset = dataOff;
	this->fCountOffset = countOff;
	this->fCountZeroBased = zeroBasedCount;
	this->SetCount(0);
	this->fGrowGeometrically = growGeometrically;

	ASSERTHANDLE(kSean, fDataHandle, fDataOffset + fNumAllocItems * fDataSize);
	#ifdef BUG
		this->CheckArrayValues();
	#endif
}

TSmallArrayHandler::TSmallArrayHandler(GSHandle dataH, long dataSz, long dataOff, long countOff, Bool8 zeroBasedCount)
{
	fDataHandle = dataH;
	fDataSize = dataSz;
	fDataOffset = dataOff;
	fCountOffset = countOff;
	fCountZeroBased = zeroBasedCount;
	fFreeMemWhenDone = false;
	fGrowGeometrically = false;

	short numCells = *((short *) (*fDataHandle + fCountOffset));
	fNumUsedItems = (fCountZeroBased) ? numCells+1 : numCells;
	fNumAllocItems = fNumUsedItems;
	
	ASSERTHANDLE(kSean, fDataHandle, fDataOffset + fNumAllocItems * fDataSize);
	
	#ifdef BUG
	this->CheckArrayValues();
	#endif
}

TSmallArrayHandler::~TSmallArrayHandler()
{
	if (this->fFreeMemWhenDone && this->fDataHandle)
		GS_DisposeHandle(gCBP, this->fDataHandle);
}


Bool8 TSmallArrayHandler::AppendCells(short numCellsToAppend)
/*
	Adds numCellsToAppend with no data to end of array
*/
{ 
	#if BUG && !_MINICAD_EXTERNAL_ && !_GSESDK_ && !GS_INTERFACE_FACTORING
	if (GSDebug::DebugLevel() > verbose) {
		DMSG((mongo, " --- Adding %i cells.\n", (long) numCellsToAppend));
		this->WriteArray();
	}
	#endif
	
	long dataSize;
	Bool8 validResize;
	
	if (!this->fDataHandle)
		return false;

	#ifdef _MINICAD_
	ASSERTUNLOCKED(kPaul, this->fDataHandle);
	#endif

	ASSERTHANDLE(kSean, fDataHandle, fDataOffset + fNumAllocItems * fDataSize);

	short origNumOfItems = this->NumItems();
	short NewNumOfItems  = origNumOfItems + numCellsToAppend;
	
	if (kGSMaxSint16 - origNumOfItems < origNumOfItems) {
		DMSG((kSean, "### TSmallArrayHandler::AppendCellsAndData - ran out of index space (>kGSMaxSint16 cells)\n"));
		return false;
	}
	
	// Calculate the new data size.

	if (this->fFreeMemWhenDone)
		if (NewNumOfItems > this->fNumAllocItems) {
			
			if ((this->fGrowGeometrically) && (this->fNumAllocItems > 0)) {
				dataSize = this->fDataOffset + ((this->fNumAllocItems * 2) * this->fDataSize);
				DMSG((kMark, "Expanding TSmallArray from %d items to... ", this->fNumAllocItems)); 
			}
			else	
				dataSize = this->fDataOffset + this->fDataSize*(NewNumOfItems + (kBuffSize - (origNumOfItems + numCellsToAppend) % kBuffSize));
			
			ASSERTN(kSean, dataSize >= (this->fDataOffset + fDataSize * numCellsToAppend));
		}
		else
			dataSize = -1L;
	else
		dataSize = this->fDataOffset+this->fDataSize*NewNumOfItems;
	
	// New data size can fit in the existing array.
	
	if (dataSize <= 0L) {
		this->SetCount(NewNumOfItems);
		return true;
	}

	// New data size cannot fit in the existing array - need to expand it.
	
	else {
		ASSERTUNLOCKED(kPaul, this->fDataHandle);
		GS_HUnlock(gCBP, this->fDataHandle);
	
		validResize = GS_SetHandleSize(gCBP, this->fDataHandle, dataSize);
		
		if (validResize) {
			this->SetCount(NewNumOfItems);
			this->fNumAllocItems = (short) ((dataSize - this->fDataOffset) / this->fDataSize);

			if (this->fGrowGeometrically){
				DMSG((kMark, "%d items\n", this->fNumAllocItems)); 
			}
			return true;
		}
		else {
			DMSG((kEveryone, "Could not increase array size.\n"));
		
			return false;
		}
	}
}

Bool8 TSmallArrayHandler::InsertCells(short beforeWhere, short numCells)
/*
	Inserts numCells cells into the array (0 inserts at front)
*/
{
	short prevSize;
	
	if (beforeWhere > this->NumItems() || beforeWhere < 0) {

		DMSG((kEveryone, "Trying to insert cells at illegal point (beforeWhere: %i)\n", (long) beforeWhere));

		return false;
	}
	
	if (numCells <= 0) {
		DMSG((kEveryone, "numCells is <= 0 in InsertCells! (numCells: %i)\n", (long) numCells));
		return false;
	}
	
	prevSize = this->NumItems();
	
	#ifdef _MINICAD_
	ASSERTUNLOCKED(kPaul, this->fDataHandle);
	#endif
	
	if (this->AppendCells(numCells)) {
		// Slide all the past beforeWhere-1 up by fDataSize
		Ptr beforeWherePtr = (Ptr) this->GetCellPtr(beforeWhere);
		#if _MINICAD_
			Mem_Move(beforeWherePtr+(this->fDataSize*numCells), beforeWherePtr, (prevSize-beforeWhere)*this->fDataSize);
		#else
			//The memmove call replaces the BlockMoveData(...) call - required for Altura removal changes. [AAO, 1-29-03]
			memmove(beforeWherePtr+(this->fDataSize*numCells), beforeWherePtr, (prevSize-beforeWhere)*this->fDataSize);
			//BlockMoveData(beforeWherePtr, beforeWherePtr+(this->fDataSize*numCells), (prevSize-beforeWhere)*this->fDataSize);
		#endif
		return true;
	}
	else	
		return false;
}

Bool8 TSmallArrayHandler::InsertCellAndData(short beforeWhere, const void* cellData)
/*
	Inserts one cell anywhere in the array (0 inserts at front), and sets it to data in cellData
*/
{
	if (this->InsertCells(beforeWhere, 1)) {
		memcpy(this->GetCellPtr(beforeWhere), cellData, (size_t) this->fDataSize);
		return true;
	}
	else	
		return false;
}

void TSmallArrayHandler::DeleteCells(short firstCell, short numCells)
/*
	Deletes numCell cells starting at firstCell
*/
{
	if (numCells <  0 || numCells > (this->NumItems()-firstCell)) {
		DMSG((kEveryone, "numCells is out of bounds in DeleteCells (numCells: %i)\n", (long) numCells));
		return;
	}
	
	if (firstCell < 0 || firstCell >= this->NumItems()) {
		if (this->NumItems() != 0){
			DMSG((kEveryone, "firstCell is out of bounds in DeleteCells (firstCell: %i)\n", (long) firstCell));
		}
		return;
	}
	
	if (this->fDataHandle) {
		ASSERTHANDLE(kSean, fDataHandle, fDataOffset + fNumAllocItems * fDataSize);

		long numItems = this->NumItems();
		Ptr firstCellPtr = (Ptr) this->GetCellPtr(firstCell);
		ASSERTPOINTER(kSean, firstCellPtr, fDataSize*numCells);
		const size_t numMoveBytes = (numItems-(firstCell+numCells))*this->fDataSize;
		if (numMoveBytes > 0) {
			#if _MINICAD_
				Mem_Move(firstCellPtr, firstCellPtr + numCells*this->fDataSize, numMoveBytes);
			#else
				//The memmove call replaces the BlockMoveData(...) call - required for Altura removal changes. [AAO, 1-29-03]
				memmove(firstCellPtr, firstCellPtr + numCells*this->fDataSize, numMoveBytes);
				//BlockMoveData(firstCellPtr + numCells*this->fDataSize, firstCellPtr, numMoveBytes);
			#endif
		}
		if (!this->fFreeMemWhenDone || ((numItems / kBuffSize) != (numItems - numCells) / kBuffSize)) {
			long numAllocCells;
			
			if (this->fFreeMemWhenDone) {
				numAllocCells = ((numItems - numCells) / kBuffSize + 1) * kBuffSize;
			}
			else 
				numAllocCells = numItems - numCells;
			
			size_t newHandleSize = this->fDataOffset + this->fDataSize * numAllocCells;

			GS_ReduceHandleSize(gCBP, this->fDataHandle, newHandleSize); // Handle ALWAYS gets smaller
			
			ASSERTN(kSean, numAllocCells >= (numItems - numCells));
			ASSERTN(kSean, (size_t)numAllocCells == (newHandleSize - this->fDataOffset) / this->fDataSize);
			fNumAllocItems = (short)numAllocCells;
		}
		
		ASSERTHANDLE(kSean, fDataHandle, fDataOffset + fNumAllocItems * fDataSize);
		this->SetCount((short)numItems-numCells);
	}
}


void TSmallArrayHandler::SortArray(QSortCompareFunc CompFunc)
{
	GS_HLock(gCBP, this->GetDataHandle());
	short numItems =  this->NumItems();
	if (numItems >0) qsort(this->GetCellPtr(0), numItems, (size_t) fDataSize, CompFunc);
	
#if !GS_INTERFACE_FACTORING && defined(_MINICAD_)
	ASSERTN(kSean, !HandleIsPurgeable(this->GetDataHandle()));
#endif

	GS_HUnlock(gCBP, this->GetDataHandle());
}



/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////

//----------------------------------------------------------------------------------------

#if BUG
void* TLargeArrayHandler::GetCellPtr(LargeArrayIndex cellNum) const
/*
	Returns a pointer to the beginning of the data at cellNum
*/
{
	if (fDataHandle) {
		ASSERTHANDLE(kSean, fDataHandle, fDataOffset + fNumAllocItems * fDataSize);
	
		Ptr result;
		#ifdef BUG
		if ((cellNum >= this->NumItems() || cellNum < 0) && cellNum != ULONG_MAX) {
			DSTOP((kSean, brief, "cellNum out of range! (cellNum = %i, cellMax = %i)\n", cellNum, this->NumItems() - 1));
		}
		if (this->NumItems() == 0) {
			DSTOP((kSean, brief, "There are no items to access!\n"));
		}
		#endif

		if (cellNum >= this->NumItems())
			cellNum = this->NumItems()-1;
		else if (cellNum < 0)
			cellNum = 0;
		result = (Ptr) (*this->fDataHandle + fDataOffset + cellNum*fDataSize);
		
		#ifdef BUG
		if (((long)result)%2){
			DMSG((brief, kSean, "TLargeArray of elements which cause an odd address on 68000 processors!!"));
		}
		#endif
		
		ASSERTPOINTER(kSean, result, fDataSize);
		return result;
	}
	
	return nil;
}
#endif

//----------------------------------------------------------------------------------------

#ifdef BUG
void TLargeArrayHandler::WriteArray() const
{
	DMSG((kEveryone, "dataSize = %i\n", fDataSize));
	DMSG((kEveryone, "dataOff = %i\n", fDataOffset));
	DMSG((kEveryone, "countOff = %i\n", fCountOffset));
	DMSG((kEveryone, "NumItems = %i\n", this->NumItems()));
}
#endif

//----------------------------------------------------------------------------------------

#ifdef BUG
void TLargeArrayHandler::CheckArrayValues() const
{
		if (!this->fDataHandle)
			DSTOP((kSean, "TLargeArrayHandler::CheckArrayValues - No data handle!\n"));
		else {
			ASSERTHANDLE(kSean, fDataHandle, fDataOffset + fNumAllocItems * fDataSize);

			if (this->fDataSize < 0L)
				DSTOP((kSean, "fDataSize < 0!\n"));
				
			size_t hSz;
			GS_GetHandleSize(gCBP, this->fDataHandle, hSz);

			if (this->fDataOffset < sizeof(long) || (size_t)this->fDataOffset > hSz){
				DMSG((kEveryone, "Illegal dataOff: %i\n", this->fDataOffset));
			}
			if (this->fCountOffset < 0L || (size_t)this->fCountOffset > (hSz - sizeof(long))){
				DMSG((kEveryone, "Illegal countOff: %i\n", this->fCountOffset));
			}
			if (this->NumItems() < 0){
				DSTOP((kSean, "Number of items is < 0!\n"));
			}
			size_t spaceNeeded = this->NumItems() * this->fDataSize;
			if (spaceNeeded > (hSz - fDataOffset))
				DSTOP((kSean, "Handle is not large enough to hold %i items(items stored = %i)\n", this->NumItems(), spaceNeeded / this->fDataSize));
			
			if (hSz > (fNumUsedItems * fDataSize + fDataOffset)) {
				// XXX: not sure if these should be a DSTOP or a DMSG
				DMSG((kSean, "SpaceNeeded: %ld, hSize: %ld, space available: %ld\n", spaceNeeded, hSz, hSz));
				DMSG((kSean, "Handle is larger than necessary to hold %i items(items stored = %i)\n", this->NumItems(), spaceNeeded / this->fDataSize));
			}
		}
}
#endif

//----------------------------------------------------------------------------------------

TLargeArrayHandler::TLargeArrayHandler(size_t dataSz, EArrayGrowthMethod growthMethod)
{
	DSTOPIF(dataSz%2, (brief,kSean, "TLargeArray constructed with odd data size - 68000 incompatible!!!"));

	this->fDataSize     = dataSz;
	this->fGrowthMethod = growthMethod;
	this->fCountOffset = 0L;
	this->fDataOffset = sizeof(long);
	fFreeMemWhenDone = true;


	#ifdef _MINICAD_
		this->fDataHandle = GS_NewHandle(gCBP, (kBuffSize * fDataSize + fDataOffset));
	#else
		//The GS_NewHandle(...) call replaces a NewHandle(...) call (GS_NewHandle(...) calls 
        //NewHandleCk(...)) - required for Altura removal changes. [AAO, 1-29-03]
		this->fDataHandle = GS_NewHandle(gCBP, (kBuffSize * fDataSize + fDataOffset));
	#endif

	this->fNumAllocItems = this->fDataHandle ? kBuffSize : 0;
	this->SetCount(0);
	
	#ifdef BUG
		this->CheckArrayValues();
	#endif
}

//---------------------------------------------------------------------------------------

TLargeArrayHandler::TLargeArrayHandler(GSHandle dataH, size_t dataSz, long dataOff, long countOff, 
			Bool8 zeroBasedCount)
{
	DSTOPIF(dataSz%2, (brief, kSean, "TLargeArray constructed with odd data size - 68000 incompatible!!!"));

	fDataSize     = dataSz;
	fGrowthMethod = eOneAtATimeGrowth;
	fDataOffset = dataOff;
	fCountOffset = countOff;
	fCountZeroBased = zeroBasedCount;
	fFreeMemWhenDone = false;

	fDataHandle = dataH;

	long numCells = *((long*) (*fDataHandle + fCountOffset));
	fNumUsedItems = (fCountZeroBased) ? numCells+1 : numCells;
	fNumAllocItems = fNumUsedItems;

	ASSERTHANDLE(kBruce, fDataHandle, fDataOffset + fNumAllocItems * fDataSize);
	
	#ifdef BUG
		this->CheckArrayValues();
	#endif
}

//----------------------------------------------------------------------------------------

TLargeArrayHandler::~TLargeArrayHandler()
{
	if (this->fDataHandle && fFreeMemWhenDone)
		GS_DisposeHandle(gCBP, this->fDataHandle);
}

//----------------------------------------------------------------------------------------

Boolean TLargeArrayHandler::AppendCells(LargeArrayIndex numCells)
/*
	Adds numCells with no data to end of array
*/
{ 
	#if BUG && !_MINICAD_EXTERNAL_
	if (GSDebug::DebugLevel() > verbose) {
		DMSG((kMark, " --- Adding %i cells.\n", numCells));
		this->WriteArray();
	}
	#endif
	
	size_t dataSize;
	Boolean validResize;
	
	if (this->fDataHandle) {

		#ifdef _MINICAD_
		ASSERTUNLOCKED(kPaul, this->fDataHandle);
		#endif
	
		ASSERTHANDLE(kSean, fDataHandle, fDataOffset + fNumAllocItems * fDataSize);
	
		LargeArrayIndex nItems = this->NumItems();
		
		if (ULONG_MAX - nItems >= numCells) {
			if (nItems + numCells > this->fNumAllocItems) {

//				size_t maxSize = ULONG_MAX * fDataSize;
				size_t neededSize = 0;

				DMSG((kMark, "Expanding TLargeArray from %d items to... ", this->fNumAllocItems)); 

				switch (this->fGrowthMethod) {

					case eArithmeticGrowth:
						neededSize = this->fDataSize * (nItems + numCells + (kBuffSize - (nItems + numCells) % kBuffSize));
						break;				
						
					case eGeometricGrowth:
//						neededSize = this->fDataSize * (this->fNumAllocItems * 2);
						neededSize = this->fDataSize * (max((long) (this->fNumAllocItems * 1.2), (long) nItems + 10));  // 20% with 10 minimum [MAF 10/20/00]
						break;				

					case eExponentialGrowth:
						neededSize = this->fDataSize * ((this->fNumAllocItems) * (this->fNumAllocItems));
						break;
						
					case eOneAtATimeGrowth:
						neededSize = fDataSize * (nItems + numCells);
						break;

					default:
						DSTOP((kMark, "Invalid TLargeArray growth method: %d\n", this->fGrowthMethod));
						neededSize = 0;
						break;				
				}
				
				dataSize = neededSize + fDataOffset;
				ASSERTN(kSean, dataSize >= (fDataSize * numCells + fDataOffset));
			}
			else
				dataSize = 0;
			
			if (dataSize <= 0L) {
				this->SetCount(nItems + numCells);
				return true;
			}
			else {
				#ifdef _MINICAD_
				ASSERTUNLOCKED(kPaul, this->fDataHandle);
				
				GS_HUnlock(gCBP, this->fDataHandle);
		
				validResize = GS_SetHandleSize(gCBP, this->fDataHandle, dataSize);
				#else
				//The GS_SetHandleSize(...) call replaces a SetHandleSize(...) call (GS_SetHandleSize(...) calls 
        		//SetHandleSizeCk(...)) - required for Altura removal changes. [AAO, 1-29-03]
				GS_SetHandleSize(gCBP, this->fDataHandle, dataSize);

				size_t	dataHandleSize = 0;
				GS_GetHandleSize(gCBP, this->fDataHandle, dataHandleSize);
				validResize = (dataHandleSize == dataSize);
				#endif

				if (validResize) {
					this->SetCount(nItems + numCells);
					this->fNumAllocItems = (LargeArrayIndex) ((dataSize - fDataOffset) / fDataSize);
					DMSG((kMark, "%d items\n", this->fNumAllocItems)); 
					ASSERTN(kSean, fNumUsedItems <= fNumAllocItems);
					return true;
				}
				else {
					DSTOP((kSean, "Could not increase array size.\n"));
					return false;
				}
			}
		}
		else {
			DSTOP((kSean, "TLargeArrayHandler::AppendCellsAndData - ran out of index space (>ULONG_MAX cells)\n"));
			return false;
		}
	}
	else
		return false;
}

//----------------------------------------------------------------------------------------

Boolean TLargeArrayHandler::InsertCells(LargeArrayIndex beforeWhere, LargeArrayIndex numCells)
/*
	Inserts numCells cells into the array (0 inserts at front)
*/
{
	LargeArrayIndex prevSize;
	
	if (beforeWhere > this->NumItems() || beforeWhere < 0) {
		DSTOP((kSean, "Trying to insert cells at illegal point (beforeWhere: %i)\n", beforeWhere));
		return false;
	}
	
	if (numCells <= 0) {
		DSTOP((kSean, "numCells is <= 0 in InsertCells! (numCells: %i)\n", numCells));
		return false;
	}
	
	prevSize = this->NumItems();
	
	#ifdef _MINICAD_
	ASSERTUNLOCKED(kPaul, this->fDataHandle);
	#endif
	
	if (this->AppendCells(numCells)) {
		// Slide all the past beforeWhere-1 up by fDataSize
		Ptr beforeWherePtr = (Ptr) this->GetCellPtr(beforeWhere);

		#if _MINICAD_
			Mem_Move(beforeWherePtr+(this->fDataSize*numCells), beforeWherePtr, (prevSize-beforeWhere)*this->fDataSize);
		#else
			//The memmove call replaces the BlockMoveData(...) call - required for Altura removal changes. [AAO, 1-29-03]
			memmove(beforeWherePtr+(this->fDataSize*numCells), beforeWherePtr, (prevSize-beforeWhere)*this->fDataSize);
			//BlockMoveData(beforeWherePtr, beforeWherePtr+(this->fDataSize*numCells), (prevSize-beforeWhere)*this->fDataSize);
		#endif
		return true;
	}
	else	
		return false;
}

//----------------------------------------------------------------------------------------

Boolean TLargeArrayHandler::InsertCellAndData(LargeArrayIndex beforeWhere, const void* cellData)
/*
	Inserts one cell anywhere in the array (0 inserts at front), and sets it to data in cellData
*/
{
	if (this->InsertCells(beforeWhere, 1)) {
		memcpy(this->GetCellPtr(beforeWhere), cellData, (size_t) this->fDataSize);
		return true;
	}
	else	
		return false;
}

//----------------------------------------------------------------------------------------

void TLargeArrayHandler::DeleteCells(LargeArrayIndex firstCell, LargeArrayIndex numCells)
//
//	Deletes numCell cells starting at firstCell
//
{
	if ((numCells ==  0) && (this->NumItems() == 0))
		return;

	if (numCells <  0 || numCells > (this->NumItems()-firstCell)) {
		DSTOP((kSean, "numCells is out of bounds in DeleteCells (numCells: %i)", numCells));
		return;
	}
	
	if (firstCell < 0 || firstCell >= this->NumItems()) {
		DSTOP((kSean, "firstCell is out of bounds in DeleteCells (firstCell: %i)", firstCell));
		return;
	}
	
	if (this->fDataHandle) {
		ASSERTHANDLE(kSean, fDataHandle, fDataOffset + fNumAllocItems * fDataSize);

		LargeArrayIndex numItems = this->NumItems();
		Ptr firstCellPtr = (Ptr) this->GetCellPtr(firstCell);
		ASSERTPOINTER(kSean, firstCellPtr, fDataSize*numCells);
		Size numMoveBytes = (numItems-(firstCell+numCells))*this->fDataSize;
		if (numMoveBytes > 0)
		{
		#if _MINICAD_
			Mem_Move(firstCellPtr, firstCellPtr + numCells*this->fDataSize, numMoveBytes);
		#else
			//The memmove call replaces the BlockMoveData(...) call - required for Altura removal changes. [AAO, 1-29-03]
			memmove(firstCellPtr, firstCellPtr + numCells*this->fDataSize, numMoveBytes);
			//BlockMoveData(firstCellPtr + numCells*this->fDataSize, firstCellPtr, numMoveBytes);
		#endif			
		}
			
		if (! fFreeMemWhenDone ||
			((numItems / kBuffSize) != (numItems - numCells) / kBuffSize)) 
		{
			LargeArrayIndex numAllocCells;
			
			if (fFreeMemWhenDone)
				numAllocCells = ((numItems - numCells) / kBuffSize + 1) * kBuffSize;
			else
				numAllocCells = numItems - numCells;

			size_t newHandleSize = fDataOffset + fDataSize * numAllocCells;
			#ifdef _MINICAD_
			ReduceHandleSizeCk(fDataHandle, newHandleSize); // Handle ALWAYS gets smaller
			#else
			//The GS_SetHandleSize(...) call replaces a SetHandleSize(...) call (GS_SetHandleSize(...) calls 
        	//SetHandleSizeCk(...)) - required for Altura removal changes. [AAO, 1-29-03]
			GS_SetHandleSize(gCBP, fDataHandle, newHandleSize); // Handle ALWAYS gets smaller
			#endif
			
			ASSERTN(kSean, numAllocCells >= (numItems - numCells));
			ASSERTN(kSean, numAllocCells == (newHandleSize - fDataOffset) / this->fDataSize);
			fNumAllocItems = numAllocCells;
		}
		
		ASSERTHANDLE(kSean, fDataHandle, fDataOffset + fNumAllocItems * fDataSize);
		this->SetCount(numItems-numCells);
	}
}

#ifdef _MINICAD_
void TLargeArrayHandler::SortArray(QSortCompareFunc CompFunc)
{
	GS_HLock(gCBP, this->GetDataHandle());
	LargeArrayIndex numItems =  this->NumItems();
	if (numItems >0) qsort(this->GetCellPtr(0), numItems, (size_t) fDataSize, CompFunc);

#if !GS_INTERFACE_FACTORING && defined(_MINICAD_)
	ASSERTN(kSean, !HandleIsPurgeable(this->GetDataHandle()));
#endif

	GS_HUnlock(gCBP, this->GetDataHandle());
}
#endif
