/*<<<***************************************************************************
The MIT License (MIT)

Copyright(C) 2013 - 2015 Marc Mirti Mancinelli, Christophe Lardau and Philippe Pamart (xdcube.org)

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

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.
////////////////////////////////////////////////////////////////////////////////
#Title: xbHeap
#Project: xdcBase
////////////////////////////////////////////////////////////////////////////////
#Author: Marc MIRTI MANCINELLI
#History:
<12/02/2014: creation.
12/02/2014: this notice inserted.
***************************************************************************>>>*/
#include "stdafx.h"

#define xbHEAPINTERNALS
#include "xbHeap.h"
//#include "xbException.h"

#pragma warning(push)
#pragma warning(disable: 4311)
////////////////////////////////////////////////////////////////////////////////////////////
// crt heap
////////////////////////////////////////////////////////////////////////////////////////////
xbllCrtHeap::xbllCrtHeap(bool /*bMT*/,xbCtorMode CtorMode)
{
//	m_cAlloc = 0;
	m_bCreated = false;
	if (CtorMode == xbCtor_CallCreate) Create();
}

void xbllCrtHeap::Create()
{
	if (m_bCreated) return;

//	m_cAlloc = 0;
	m_bCreated = true;
}

void xbllCrtHeap::Destroy()
{
	if (!m_bCreated) return;
/*#ifdef _xbHEAPDEBUG
	if (m_cAlloc!=0)
	{
		xbDbgHeapOutput("xbllCrtHeap()::~xbllCrtHeap() : %ld allocations not freed !",
			m_cAlloc);
	}
#endif*/
	m_bCreated = false;
//	m_cAlloc = 0;
}

void *xbllCrtHeap::Alloc(size_t cByte,xbOpMode opmode)
{
	if (!m_bCreated) 
		xbThrowEsysLow("xbllCrtHeap()::Alloc() : heap not created");
//	if (cByte <= 0) 
//		xbThrowEsysLowFmt("xbllCrtHeap()::Alloc(cByte=%ld) : size to allocate is invalid",cByte);
	void *ret = ::malloc(cByte);
/*	if (ret) m_cAlloc++;
	else*/ if (!ret && opmode == xbOp_Required) 
		xbThrowEsysLowFmt("xbllCrtHeap()::Alloc(cByte=%ld) : malloc failure",cByte);
	return ret;
}

void *xbllCrtHeap::ReAlloc(void *ptr,size_t cByte,xbOpMode opmode)
{
	if (!m_bCreated) 
		xbThrowEsysLow("xbllCrtHeap()::ReAlloc() : heap not created");
//	if (cByte <= 0) 
//		xbThrowEsysLowFmt("xbllCrtHeap()::ReAlloc(cByte=%ld) : size to allocate is invalid",cByte);
	if (!ptr)
		return Alloc(cByte);

	void *ret = ::realloc(ptr,cByte);
	if (!ret && opmode == xbOp_Required) 
		xbThrowEsysLowFmt("xbllCrtHeap()::ReAlloc(cByte=%ld) : realloc failure",cByte);
	return ret;
}

void xbllCrtHeap::Free(void *ptr)
{
	if (!m_bCreated) 
		xbThrowEsysLow("xbllCrtHeap()::Free() : heap not created");
	if (!xbMustBe(ptr)) return;
	::free(ptr);
//	xbMustBe((--m_cAlloc) >= 0);
}

xbllCrtHeap::~xbllCrtHeap()
{
	eProtect(Destroy());
}


////////////////////////////////////////////////////////////////////////////////////////////
// brix default heap
////////////////////////////////////////////////////////////////////////////////////////////
#if defined(xbHEAPRELEASECHECK) || defined(_DEBUG)
#	define _xbCHECKBLOCK(pBlock)	_checkBlock(pBlock)
#else
#	define _xbCHECKBLOCK(pBlock)
#endif

//#define	xbSEGCELLS_BYCOUNTERDEC	5
#define	xbSEGCELLS_BYCOUNTERDEC	4

#define xbREGISTER register

#if defined(xbHEAPRELEASECHECK) || defined(_DEBUG)
void	xbSegHeap::_checkBlock(void *pBloc) const
{
	if (!_isValid(pBloc))
	{
		DebugDump();
		xbThrowEsehFmt("xbSegHeap(%s)::_checkBlock(%p) : trying to manipulate an invalid bloc",GetName(),pBloc);
	}
}
#endif

xbSegHeap::xbSegHeap(const char * pszDbgName, xbint cByteCell, xbint cByteSeg, 
					 xbint cByteMax, xbCtorMode CtorMode)
:xbBaseHeap(pszDbgName),m_MainHeap(false,xbCtor_NoOp)
{
//	m_Share.DeadLockOrderFinal();
	m_pFirstSeg = NULL;
	m_bCreated = false;
	m_cByteCellAsked = cByteCell;
	m_cByteSegAsked = cByteSeg;
	m_cByteMaxAsked = cByteMax;
	if (CtorMode == xbCtor_CallCreate) 
		Create();
}

xbSegHeap::xbSegHeap(const char * pszDbgName, xbCtorMode CtorMode)
:xbBaseHeap(pszDbgName),m_MainHeap(false,xbCtor_NoOp)
{
//	m_Share.DeadLockOrderFinal();
	m_pFirstSeg = NULL;
	m_bCreated = false;
	m_bSegToLock = false;
	m_cByteCellAsked = 0;
	m_cByteSegAsked = 0;
	m_cByteMaxAsked = 0;
	if (CtorMode == xbCtor_CallCreate) 
		Create();
}

xbSegHeap::~xbSegHeap()
{
	eProtect(Destroy());
}

void	xbSegHeap::SetParams(xbint cByteCell, xbint cByteSeg, xbint cByteMax)
{
	Destroy();
	if (cByteCell <= sizeof(_CellFreeHeader)) 
		xbThrowEsysLowFmt("xbSegHeap(%s)::SetParams() : cByteCell asked = %d, must be > %d",
			GetName(),cByteCell,sizeof(_CellFreeHeader));
	m_cByteCellAsked = cByteCell;
	m_cByteSegAsked = cByteSeg;
	m_cByteMaxAsked = cByteMax;
}

void	xbSegHeap::GetParams(xbint *pcByteCell, xbint *pcByteSeg, xbint *pcByteMax, bool bReal) const
{
//	xbSectLockSimpleRec Lck(&m_Share);
	if (pcByteCell)
		*pcByteCell = bReal?m_cByteCell:m_cByteCellAsked;
	if (pcByteSeg)
		*pcByteSeg = bReal?m_cByteSeg:m_cByteSegAsked;
	if (pcByteMax)
		*pcByteMax = bReal?m_cSegMax * m_cByteSeg:m_cByteMaxAsked;
}

int64	xbSegHeap::GetBusySize() const
{
//	xbSectLockSimpleRec Lck(&m_Share);
	return int64(m_cByteSegBusy);
	//return int64(m_cSeg) * m_cByteSeg;
}

xbint xbSegHeap::GetSegmentCount() const
{
//	xbSectLockSimpleRec Lck(&m_Share);
	return m_cSeg;
}

xbint xbSegHeap::GetFreeSegmentCount() const
{
//	xbSectLockSimpleRec Lck(&m_Share);
	return m_cSegFree;
}

void xbSegHeap::Create()
{
	if (m_bCreated) return;

#ifdef xbUSEVIRTUALHEAP
	#ifdef XDCBASE_X64
		if (m_cByteCellAsked <= 0) 
			m_cByteCellAsked = 96 - sizeof(_CellPhysHeader);
		if (m_cByteSegAsked <= 0) 
			m_cByteSegAsked = 65536 * 48; //3Mo
//			m_cByteSegAsked = 65536 * 16; //1Mo
	#else
		if (m_cByteCellAsked <= 0) 
			m_cByteCellAsked = 64 - sizeof(_CellPhysHeader);
		if (m_cByteSegAsked <= 0) 
			m_cByteSegAsked = 65536 * 32; //2Mo
//			m_cByteSegAsked = 65536 * 4; //256Ko
	#endif
#else
	#ifdef XDCBASE_X64
		if (m_cByteCellAsked <= 0) 
			m_cByteCellAsked = 96 - sizeof(_CellPhysHeader);
		if (m_cByteSegAsked <= 0) 
			m_cByteSegAsked = 65536 * 4; //256Ko
	#else
		if (m_cByteCellAsked <= 0) 
			m_cByteCellAsked = 64 - sizeof(_CellPhysHeader);
		if (m_cByteSegAsked <= 0) 
			m_cByteSegAsked = 65536 * 2; //128Ko
	#endif
#endif

	if (m_cByteCellAsked <= sizeof(_CellFreeHeader)) 
		xbThrowEsysLowFmt("xbSegHeap(%s)::Create() : cByteCell asked = %d, must be > %d",
		GetName(),m_cByteCellAsked,sizeof(_CellFreeHeader));

	m_cByteCell = _xbHEAPALIGN(m_cByteCellAsked+xbSEGHEAP_HDRLEN+xbSEGHEAP_ENDLEN);

#ifdef xbUSEVIRTUALHEAP
	ulong cByteGran = m_MainHeap.GetGranularity();
	m_cByteSegAsked = (m_cByteSegAsked/cByteGran)*cByteGran;
#endif

	m_cCellPerSeg = (m_cByteSegAsked-sizeof(_SegHeader)) / m_cByteCell;
	if (m_cCellPerSeg < 12 || m_cCellPerSeg > 32768) 
		xbThrowEsysLowFmt("xbSegHeap(%s)::Create() : m_cCellPerSeg = %d, must be >= 12 and <= 32768",
		GetName(),m_cCellPerSeg);

	m_cByteCellMaxInSeg = m_cCellPerSeg * m_cByteCell;
	m_cCellCounter = (m_cCellPerSeg + (1<<xbSEGCELLS_BYCOUNTERDEC) - 1) >> xbSEGCELLS_BYCOUNTERDEC;

	if (m_cByteMaxAsked<=0) m_cSegMax = 0; 
	else m_cSegMax = (m_cByteMaxAsked + m_cByteCellMaxInSeg - 1) / m_cByteCellMaxInSeg;

	if (m_cSegMax <= 0)
//		m_cCellMinToAllocAlone = (m_cCellPerSeg * 3) / 4;
		m_cCellMinToAllocAlone = m_cCellPerSeg / 2;
	else 
		m_cCellMinToAllocAlone = m_cCellPerSeg;

	m_cByteSeg = sizeof(_SegHeader) + m_cByteCellMaxInSeg;
	m_cSegFree = 0;
	m_cSeg = 0;
	m_cByteSegBusy = 0;
	m_cSegCreated = 0;
	m_cBigBlock = 0;
	m_cSegLocked = 0;
	m_cSegLockedError = 0;
	m_MainHeap.Create();
#ifdef xbUSEVIRTUALHEAP
	size_t cByteMem = m_cCellPerSeg * sizeof(*m_ppCellFree) + m_cCellCounter * sizeof(*m_pcCellFree);
	BYTE *pMem = (BYTE*)m_MainHeap.Alloc((cByteMem + cByteGran-1)/cByteGran*cByteGran);
	memset(pMem,0,cByteMem);
	m_ppCellFree = (_CellFreeHeader**)pMem;
	m_pcCellFree = (xbuint*)(pMem + m_cCellPerSeg * sizeof(*m_ppCellFree));
#else
	m_ppCellFree = (_CellFreeHeader**)m_MainHeap.Alloc(m_cCellPerSeg * sizeof(*m_ppCellFree));
	memset(m_ppCellFree,0,m_cCellPerSeg * sizeof(*m_ppCellFree));
	try
	{
		m_pcCellFree = (xbuint*)m_MainHeap.Alloc(m_cCellCounter * sizeof(*m_pcCellFree));
		memset(m_pcCellFree,0,m_cCellCounter * sizeof(*m_pcCellFree));
	}
	catch(...)
	{
		m_MainHeap.Free(m_ppCellFree);
		throw;
	}
#endif
	m_bCreated = true;
}

void xbSegHeap::Destroy()
{
	if (!m_bCreated) return;

	{
		xbSectLockSimpleRec Lck(&m_Share);
		if (m_cAlloc > 0)
		{
			DebugDump();
			xbDbgHeapOutput("xbSegHeap(%s)::Destroy() : %d allocations not freed (total size: %I64d) !",
				GetName(),m_cAlloc,m_cByteAlloc);
		}
		xbAssert(m_cAlloc == 0);
		Clear();	
#ifdef xbUSEVIRTUALHEAP
		if (m_bSegToLock)
		{
			size_t cByteGran = m_MainHeap.GetGranularity();
			size_t cByteMem = m_cCellPerSeg * sizeof(*m_ppCellFree) + m_cCellCounter * sizeof(*m_pcCellFree);
			m_MainHeap.Vunlock(m_ppCellFree,(cByteMem + cByteGran-1)/cByteGran*cByteGran);
		}
#endif
		m_MainHeap.Free(m_ppCellFree);
#ifndef xbUSEVIRTUALHEAP
		m_MainHeap.Free(m_pcCellFree);
#endif
		m_ppCellFree = NULL;
		m_pcCellFree = NULL;
		m_MainHeap.Destroy();
		resetAllocInfo();
		m_bCreated = false;
		m_pFirstSeg = NULL;
	}
}


void	xbSegHeap::Clear()
{
	xbSectLockSimpleRec Lck(&m_Share);

	if (!m_pFirstSeg) 
		return;
	_SegHeader *pSeg = (_SegHeader*)m_pFirstSeg,*pNextSeg;
	while(pSeg)
	{
		pNextSeg = pSeg->m_pNext;
		if (pSeg->m_segMode & xbSEGHEAPMODE_LOCKED)
			segUnlock(pSeg,xbint(PtrToLong(pSeg->m_pEnd) - PtrToLong(pSeg)));
		m_MainHeap.Free(pSeg);
		pSeg = pNextSeg;
	}
	m_pFirstSeg = NULL;
	m_cSegFree = 0;
	m_cSeg = 0;
	m_cByteSegBusy = 0;
	m_cSegCreated = 0;
	m_cBigBlock = 0;
	m_cSegLocked = 0;
	m_cSegLockedError = 0;
	memset(m_ppCellFree,0,m_cCellPerSeg * sizeof(*m_ppCellFree));
	memset(m_pcCellFree,0,m_cCellCounter * sizeof(*m_pcCellFree));
	resetAllocInfo();
}

xbint	xbSegHeap::GetBigBlockCount() const
{
	return m_cBigBlock;
}

xbint	xbSegHeap::GetSegmentCreatedCount() const
{
	return m_cSegCreated;
}

xbint	xbSegHeap::GetSegmentLockedCount() const
{
	return m_cSegLocked;
}

xbint	xbSegHeap::GetSegmentLockedErrorCount() const
{
	return m_cSegLockedError;
}

bool	xbSegHeap::GetSegmentToLock() const
{
	return m_bSegToLock;
}

void	xbSegHeap::SetSegmentToLock(bool bFlg)
{
	xbSectLockSimpleRec Lck(&m_Share);
	if (m_bSegToLock == bFlg)
		return;
	m_bSegToLock = bFlg;
	if (!m_bCreated)
		return;

	if (bFlg)
	{
		size_t cByteGran = m_MainHeap.GetGranularity();
		size_t cByteMem = m_cCellPerSeg * sizeof(*m_ppCellFree) + m_cCellCounter * sizeof(*m_pcCellFree);
		if (!m_MainHeap.Vlock(m_ppCellFree,(cByteMem + cByteGran-1)/cByteGran*cByteGran))
		{
			m_bSegToLock = false;
			xbThrowEsysLowFmt(xbHR_LAST,"xbSegHeap(%s)::SetSegToLock() : Vlock failed",GetName());
		}
	}
	else
	{
		size_t cByteGran = m_MainHeap.GetGranularity();
		size_t cByteMem = m_cCellPerSeg * sizeof(*m_ppCellFree) + m_cCellCounter * sizeof(*m_pcCellFree);
		m_MainHeap.Vunlock(m_ppCellFree,(cByteMem + cByteGran-1)/cByteGran*cByteGran);
	}

	if (!m_pFirstSeg) 
		return;
	_SegHeader *pSeg = (_SegHeader*)m_pFirstSeg;
	while(pSeg)
	{
		if (bFlg)
		{
			if (!(pSeg->m_segMode & xbSEGHEAPMODE_LOCKED))
				segLock(pSeg,xbint(xbNptr(pSeg->m_pEnd) - xbNptr(pSeg)));
		}
		else
		{
			if (pSeg->m_segMode & xbSEGHEAPMODE_LOCKED)
				segUnlock(pSeg,xbint(xbNptr(pSeg->m_pEnd) - xbNptr(pSeg)));
		}
		pSeg = pSeg->m_pNext;
	}
}

void	*xbSegHeap::Alloc(size_t cByte,xbAllocMode AllocMode
#ifdef _xbALLOCDEBUG
		,const char *pszFile,int nLine
#endif
		)
{
//#ifdef _DEBUG
	if (!m_bCreated) 
		xbThrowEsysLowFmt("xbSegHeap(%s)::Alloc() : heap not created",GetName());
//#endif
	xbSectLockSimpleRec Lck(&m_Share);

	if (cByte > xbSIZE_LIMIT) 
		xbThrowEsizeLimitFmt("Memory allocation on heap %s greater than size limit (asked=%d, limit=%d)"
		,GetName(),cByte,xbSIZE_LIMIT);

	xbint		cCellBlock = (xbint)(cByte+xbSEGHEAP_HDRLEN+xbSEGHEAP_ENDLEN+m_cByteCell-1) / m_cByteCell;
	xbint		cByteBlock = cCellBlock * m_cByteCell;
	
#ifdef xbHEAPCOMPLETECHECK
	//Global check of heap before allocation
	IsValid();
#endif

	int cAllocTry = 2;
	_CellPhysHeader	*pAllocatedBlock;
	_SegHeader	*pSegOfAllocatedBlock;
retry_alloc:

	{
		//Look for previously freed block of the size of block to allocate
		_CellFreeHeader **ppCellFreeToUse = NULL;
		xbuint			*pcCellFreeToUse;
		xbint				cCellFreeToUse;
		if (cCellBlock <= m_cCellPerSeg)
		{
			//Search first in free cells counters (32 chained lists by counter).
			// 32 = 1 << xbSEGCELLS_BYCOUNTERDEC = 1 << 5
			xbREGISTER xbint		nCntNo = (cCellBlock-1) >> xbSEGCELLS_BYCOUNTERDEC;
			xbREGISTER xbuint	*pCnt = m_pcCellFree + nCntNo;
			xbREGISTER xbuint	*pCntEnd = m_pcCellFree + m_cCellCounter;

			while(pCnt < pCntEnd) 
			{
				if (*pCnt > 0)
				{
					//If a counter not null is found 
					//-> there is free cells at least of size searched 
					//Search next in the 32 chained list associated to counter found
					xbREGISTER xbint nFreeNo = nCntNo << xbSEGCELLS_BYCOUNTERDEC;
					if (nFreeNo < cCellBlock - 1) nFreeNo = cCellBlock - 1;
	
					xbREGISTER _CellFreeHeader	**ppFree = m_ppCellFree + nFreeNo;
					xbREGISTER _CellFreeHeader	**ppFreeEnd = m_ppCellFree
													+ ((nCntNo+1) << xbSEGCELLS_BYCOUNTERDEC);
					if (ppFreeEnd > m_ppCellFree + m_cCellPerSeg)
						ppFreeEnd = m_ppCellFree + m_cCellPerSeg;
					while(*ppFree == NULL && ppFree < ppFreeEnd) {nFreeNo++;ppFree++;}
					xbAssert(ppFree < ppFreeEnd
						|| (nCntNo << xbSEGCELLS_BYCOUNTERDEC) < cCellBlock - 1);
					if (ppFree < ppFreeEnd)
					{
						ppCellFreeToUse = ppFree;
						pcCellFreeToUse = pCnt;
						cCellFreeToUse = nFreeNo+1;
						xbAssert(cCellFreeToUse >= cCellBlock);
						break;
					}
				}
				nCntNo++;
				pCnt++;
			}
		}

		if (ppCellFreeToUse != NULL)
		{
			_CellFreeHeader	*pCellFreeToUse = *ppCellFreeToUse;
			pSegOfAllocatedBlock = pCellFreeToUse->m_pSeg;
#ifdef _xbHEAPDEBUG
			if (!pSegOfAllocatedBlock)
				xbThrowEsehFmt("xbSegHeap(%s)::Alloc(sz=%d) : Heap corrupted (alloc nb = %d, total sz = %I64d)",
					GetName(),cByte,m_cAlloc,m_cByteAlloc);
			xbAssert(pCellFreeToUse->m_cCell == cCellFreeToUse - 1);
#endif
			pAllocatedBlock = (_CellPhysHeader*)((char*)pCellFreeToUse - xbSEGHEAP_HDRLEN);
			xbAssert(pAllocatedBlock->m_pSeg == NULL);

			//Suppress free cells of chained list of this size
			*ppCellFreeToUse = pCellFreeToUse->m_pNext;
			xbAssert(pCellFreeToUse->m_pPrev == NULL);
			if (pCellFreeToUse->m_pNext) pCellFreeToUse->m_pNext->m_pPrev = NULL;
			xbAssert(*pcCellFreeToUse > 0);
			(*pcCellFreeToUse)--;

			//If free cells found greater than required size, add staying free cells
			// to the chained list of free cells size
			if (cCellBlock < cCellFreeToUse)
			{
				//Update physical chain of cells with new created free cell
				_CellPhysHeader		*pCellPhysStaying = (_CellPhysHeader*)((char*)pAllocatedBlock  
					+ cByteBlock);
				if ((pCellPhysStaying->m_sNext = pAllocatedBlock->m_sNext) 
					!= pSegOfAllocatedBlock->m_pEnd) 
					pCellPhysStaying->m_sNext->m_pPrev = pCellPhysStaying;
#ifdef _xbALLOCDEBUG_SPACEINIT
				if (xbDebugHeap_SpaceFreed != 0)
					memset((char*)pCellPhysStaying+sizeof(_CellPhysHeader),xbDebugHeap_SpaceFreed,xbNptr(pCellPhysStaying->m_sNext) - xbNptr(pCellPhysStaying)-sizeof(_CellPhysHeader));
#endif

				pCellPhysStaying->m_pPrev = pAllocatedBlock;
				pAllocatedBlock->m_sNext = pCellPhysStaying;
				pCellPhysStaying->m_pSeg = NULL;

				//Add staying free cells to chained list of free cells of this size.
				cCellFreeToUse -= cCellBlock + 1;
				m_pcCellFree[cCellFreeToUse >> xbSEGCELLS_BYCOUNTERDEC]++;
				
				pCellFreeToUse = (_CellFreeHeader*)((char*)pCellPhysStaying + xbSEGHEAP_HDRLEN);
				if ((pCellFreeToUse->m_pNext = m_ppCellFree[cCellFreeToUse]) != NULL)
					pCellFreeToUse->m_pNext->m_pPrev = pCellFreeToUse;
				pCellFreeToUse->m_pPrev = NULL;
				pCellFreeToUse->m_pSeg = pSegOfAllocatedBlock;
				pCellFreeToUse->m_cCell = cCellFreeToUse;
				m_ppCellFree[cCellFreeToUse] = pCellFreeToUse;
			}

			pAllocatedBlock->m_pSeg = pSegOfAllocatedBlock;
			goto block_found;
		}
	}

	if (cCellBlock > m_cCellMinToAllocAlone)
	{
		//If block to allocate is greater than segments size
		//allocate it in a separate segment of block size.
		if (m_cSegMax > 0) 
			xbThrowEsysLowFmt("xbSegHeap(%s)::Alloc(cByte=%d) : When heap is limted in size, "
				"it's not possible to allocate a block bigger than segment size. "
				"Segment size is cByteCell(%d)*cCellPerSeg(%d)=%d",GetName(),m_cByteCell,
				m_cCellPerSeg,m_cByteCellMaxInSeg);

		//Allocate new segment to contain block to allocate if possible (limits of MainHeap).
		xbint cByteSeg = bigBlockAlign(sizeof(_SegHeader) + cByteBlock);
		if (!(pSegOfAllocatedBlock = (_SegHeader*)m_MainHeap.Alloc(cByteSeg,xbOp_Optional))) 
		{
			if (RequestCleanerToFreeBytes(cByte)
				&& (--cAllocTry)>=0) goto retry_alloc;
//			DebugDump();
			xbThrowEmemFmt("xbSegHeap(%s)::Alloc(sz=%d) : Heap is full (alloc nb = %d, total sz = %I64d)",
				GetName(),cByte,m_cAlloc,m_cByteAlloc);
		}

		//-> Initialize and add the new segment to the chained segments list.
		pSegOfAllocatedBlock->m_cBuzyBlock = 0;
		pSegOfAllocatedBlock->m_segMode = xbSEGHEAPMODE_BIGBLOCK;
		pSegOfAllocatedBlock->m_pNext = m_pFirstSeg;
		pSegOfAllocatedBlock->m_pPrev = NULL;
		pSegOfAllocatedBlock->m_pEnd = (_CellPhysHeader*)((char*)pSegOfAllocatedBlock + cByteSeg);
		if (m_pFirstSeg) 
		{
			xbAssert(m_pFirstSeg->m_pPrev == NULL);
			m_pFirstSeg->m_pPrev = pSegOfAllocatedBlock;
		}
		m_pFirstSeg = pSegOfAllocatedBlock;
		m_cSegFree++;
		m_cSeg++;
		m_cSegCreated++;
		m_cBigBlock++;
		m_cByteSegBusy += cByteSeg;

		//Initialize space of new segment with the new allocated block 
		pAllocatedBlock = (_CellPhysHeader*)((char*)pSegOfAllocatedBlock + sizeof(_SegHeader));
		pAllocatedBlock->m_pPrev = NULL;
		pAllocatedBlock->m_pSeg = pSegOfAllocatedBlock;
		pAllocatedBlock->m_sNext = pSegOfAllocatedBlock->m_pEnd;

		cByteBlock = cByteSeg - sizeof(_SegHeader);

		if (m_bSegToLock)
			segLock(pSegOfAllocatedBlock,cByteSeg);

		goto block_found;
	}

	//There is no free room in heap -> allocate a new segment
	{
		//Allocate new segment if possible (limits of cSegMax or MainHeap).
		if ((m_cSegMax>0 && m_cSeg>=m_cSegMax) 
			|| !(pSegOfAllocatedBlock = (_SegHeader*)m_MainHeap.Alloc(m_cByteSeg,xbOp_Optional))) 
		{
			if (RequestCleanerToFreeBytes(cByte)
				&& (--cAllocTry)>=0) goto retry_alloc;
//			DebugDump();
			xbThrowEmemFmt("xbSegHeap(%s)::Alloc(sz=%d) : Heap is full (alloc nb = %d, total sz = %I64d)",
				GetName(),cByte,m_cAlloc,m_cByteAlloc);
		}
		//-> Initialize and add the new segment to the chained segments list.
		pSegOfAllocatedBlock->m_cBuzyBlock = 0;
		pSegOfAllocatedBlock->m_segMode = 0;
		pSegOfAllocatedBlock->m_pNext = m_pFirstSeg;
		pSegOfAllocatedBlock->m_pPrev = NULL;
		pSegOfAllocatedBlock->m_pEnd = (_CellPhysHeader*)((char*)pSegOfAllocatedBlock + m_cByteSeg);
		if (m_pFirstSeg) 
		{
			xbAssert(m_pFirstSeg->m_pPrev == NULL);
			m_pFirstSeg->m_pPrev = pSegOfAllocatedBlock;
		}
		m_pFirstSeg = pSegOfAllocatedBlock;
		m_cSegFree++;
		m_cSeg++;
		m_cSegCreated++;
		m_cByteSegBusy += m_cByteSeg;

		if (m_bSegToLock)
			segLock(pSegOfAllocatedBlock,m_cByteSeg);

		//Initialize space of new segment with the new allocated block 
		//and the staying free cells.
		pAllocatedBlock = (_CellPhysHeader*)((char*)pSegOfAllocatedBlock + sizeof(_SegHeader));
		pAllocatedBlock->m_pPrev = NULL;
		pAllocatedBlock->m_pSeg = pSegOfAllocatedBlock;
		if (cCellBlock >= m_cCellPerSeg) 
			pAllocatedBlock->m_sNext = pSegOfAllocatedBlock->m_pEnd;
		else
		{
			//Update physical chain of cells with new created free cell
			_CellPhysHeader		*pCellPhysStaying = (_CellPhysHeader*)((char*)pAllocatedBlock  
				+ cByteBlock);
			pCellPhysStaying->m_sNext = pSegOfAllocatedBlock->m_pEnd;
			pCellPhysStaying->m_pPrev = pAllocatedBlock;
			pAllocatedBlock->m_sNext = pCellPhysStaying;
			pCellPhysStaying->m_pSeg = NULL;

#ifdef _xbALLOCDEBUG_SPACEINIT
			if (xbDebugHeap_SpaceFreed != 0)
				memset((char*)pCellPhysStaying+sizeof(_CellPhysHeader),xbDebugHeap_SpaceFreed,xbNptr(pCellPhysStaying->m_sNext) - xbNptr(pCellPhysStaying)-sizeof(_CellPhysHeader));
#endif
			//Add staying free cells to chained list of free cells of this size.
			xbint cCellFreeStaying = m_cCellPerSeg - cCellBlock - 1;
			m_pcCellFree[cCellFreeStaying >> xbSEGCELLS_BYCOUNTERDEC]++;
			
			_CellFreeHeader *pCellFreeStaying = (_CellFreeHeader*)((char*)pCellPhysStaying + xbSEGHEAP_HDRLEN);
			if ((pCellFreeStaying->m_pNext = m_ppCellFree[cCellFreeStaying]) != NULL)
				pCellFreeStaying->m_pNext->m_pPrev = pCellFreeStaying;
			pCellFreeStaying->m_pPrev = NULL;
			pCellFreeStaying->m_pSeg = pSegOfAllocatedBlock;
			pCellFreeStaying->m_cCell = cCellFreeStaying;
			m_ppCellFree[cCellFreeStaying] = pCellFreeStaying;
		}
	}
	
block_found:
	if ((pSegOfAllocatedBlock->m_cBuzyBlock)++ == 0) 
	{
		m_cSegFree--;
		xbAssert(m_cSegFree>=0);
	}
	
	if (AllocMode == xbAlloc_Init) 
		memset((char*)pAllocatedBlock+sizeof(_CellPhysHeader),0,cByteBlock-sizeof(_CellPhysHeader));
#ifdef _xbALLOCDEBUG_SPACEINIT
	else if (xbDebugHeap_SpaceUninit != 0)
		memset((char*)pAllocatedBlock+sizeof(_CellPhysHeader),xbDebugHeap_SpaceUninit,cByteBlock-sizeof(_CellPhysHeader));
#endif

#ifdef _xbDEBUGHEAP_HDRSTR
	//Mark the start of block with pad string
	memcpy((char*)pAllocatedBlock+xbSEGHEAP_HDRLEN-_xbDEBUGHEAP_HDRLEN,_xbDEBUGHEAP_HDRSTR,_xbDEBUGHEAP_HDRLEN);
#endif

#ifdef _xbDEBUGHEAP_ENDSTR
	//Mark the end of block with pad string
	memcpy((char*)pAllocatedBlock->m_sNext-xbSEGHEAP_ENDLEN,_xbDEBUGHEAP_ENDSTR,_xbDEBUGHEAP_ENDLEN);
#endif

#ifdef _xbALLOCDEBUG
	//Feed debug header with allocation location,
	// and count allocation.
	_xbDebugAllocSt *dbg = (_xbDebugAllocSt*)((char*)pAllocatedBlock+sizeof(_CellPhysHeader));
	dbg->m_pszFile = _xbDebugFileEntry(pszFile);
	dbg->m_nLine = nLine;
	dbg->m_cAllocOp = -1;
	dbg->m_cAllocOp = addAlloc(cByteBlock);
	dbg->m_pAllocHeap = this;
/*	if (nLine == 169)
	{
		if (cByteBlock==112)
			xbRelOutput("alloc trace[GOOD]: "+xbString(pszFile)+": size="+xbString(cByteBlock));
		else
			xbRelOutput("alloc trace[    ]: "+xbString(pszFile)+": size="+xbString(cByteBlock));
	}*/
#else
	addAlloc(cByteBlock);
#endif

#ifdef xbHEAPCOMPLETECHECK
	IsValid();
#endif
	return ((char*)pAllocatedBlock)+xbSEGHEAP_HDRLEN;
}

void	*xbSegHeap::ReAlloc(void *pBlock,size_t cByte,xbAllocMode AllocMode
#ifdef _xbALLOCDEBUG
		,const char *pszFile,int nLine
#endif
		)
{
	if (!pBlock)
		return Alloc(cByte,AllocMode
#ifdef _xbALLOCDEBUG
			,pszFile,nLine
#endif
			);
	
//#ifdef _DEBUG
	if (!m_bCreated) 
		xbThrowEsysLowFmt("xbSegHeap(%s)::ReAlloc() : heap not created",GetName());
//#endif
	
	if (cByte > xbSIZE_LIMIT) 
		xbThrowEsizeLimitFmt("Memory allocation on heap %s greater than size limit (asked=%d, limit=%d)"
		,GetName(),cByte,xbSIZE_LIMIT);

	xbint		cCellBlockNew = (xbint)(cByte+xbSEGHEAP_HDRLEN+xbSEGHEAP_ENDLEN+m_cByteCell-1) / m_cByteCell;
	xbint		cByteBlockNew = cCellBlockNew * m_cByteCell;

#ifdef xbHEAPCOMPLETECHECK
	IsValid();
#endif
	
	pBlock = ((char*)pBlock)-xbSEGHEAP_HDRLEN;
	
//	xbSectLockSimpleRec		Lck(&m_Share);
	
	_xbCHECKBLOCK(pBlock);

	_CellPhysHeader	*pReAllocatedBlock = (_CellPhysHeader*)pBlock;
	_SegHeader		*pSegOfReAllocatedBlock = pReAllocatedBlock->m_pSeg;
	xbint			cByteBlock = 
						xbint((xbNptr)(pReAllocatedBlock->m_sNext) - (xbNptr)pReAllocatedBlock);
	xbint			cCellBlock = cByteBlock / m_cByteCell;
	xbAssert(cCellBlock * m_cByteCell == cByteBlock);
	
	if (cByteBlock == cByteBlockNew)
		return ((char*)pBlock)+xbSEGHEAP_HDRLEN;
	
	xbSectLockSimpleRec		Lck(&m_Share);

	if (pReAllocatedBlock->m_sNext == pSegOfReAllocatedBlock->m_pEnd
		&& (char*)pReAllocatedBlock == (char*)pSegOfReAllocatedBlock + sizeof(_SegHeader))
	{
		//Block is alone in its segment -> realloc segment.
		xbint cByteSeg = bigBlockAlign(sizeof(_SegHeader) + cByteBlockNew);
		if (cByteBlock+sizeof(_SegHeader) == cByteSeg) 
			return ((char*)pBlock)+xbSEGHEAP_HDRLEN;

//		bool bBigBLock = (pSegOfReAllocatedBlock->m_segMode & xbSEGHEAPMODE_BIGBLOCK)?true:false;
		xbRdbgAssert((xbNptr(pSegOfReAllocatedBlock->m_pEnd) - xbNptr(pSegOfReAllocatedBlock)) 
			== cByteBlock+sizeof(_SegHeader));

		_SegHeader	*pNewSeg = NULL;
		int cAllocTry = 2;
		while(!pNewSeg)
		{
#ifdef xbUSEVIRTUALHEAP
			if (!(pNewSeg = (_SegHeader*)m_MainHeap.ReAlloc(pSegOfReAllocatedBlock,cByteSeg,cByteBlock+sizeof(_SegHeader),xbOp_Optional))) 
#else
			if (!(pNewSeg = (_SegHeader*)m_MainHeap.ReAlloc(pSegOfReAllocatedBlock,cByteSeg,xbOp_Optional))) 
#endif
			{
				if (!RequestCleanerToFreeBytes(cByte)
					&& (--cAllocTry)>=0)
				{
//					DebugDump();
					xbThrowEmemFmt("xbSegHeap(%s)::ReAlloc(pBlock=%p,sz=%d) : Heap is full (alloc nb = %d, total sz = %I64d)",
						GetName(),(char*)pBlock+xbSEGHEAP_HDRLEN,cByte,m_cAlloc,m_cByteAlloc);
				}
			}
		}
		pNewSeg->m_pEnd = (_CellPhysHeader*)((char*)pNewSeg + cByteSeg);
		if (pNewSeg != pSegOfReAllocatedBlock)
		{
			if (pNewSeg->m_pNext) 
				pNewSeg->m_pNext->m_pPrev = pNewSeg;

			if (pNewSeg->m_pPrev) 
			{
				pNewSeg->m_pPrev->m_pNext = pNewSeg;
				xbAssert(pSegOfReAllocatedBlock != m_pFirstSeg);
			}
			else
			{
				xbAssert(pSegOfReAllocatedBlock == m_pFirstSeg);
				m_pFirstSeg = pNewSeg;
			}
			pSegOfReAllocatedBlock = pNewSeg;
		}
		pReAllocatedBlock = (_CellPhysHeader*)((char*)pSegOfReAllocatedBlock + sizeof(_SegHeader));
		pReAllocatedBlock->m_pPrev = NULL;
		pReAllocatedBlock->m_pSeg = pSegOfReAllocatedBlock;
		pReAllocatedBlock->m_sNext = pSegOfReAllocatedBlock->m_pEnd;

		cByteBlockNew = cByteSeg - sizeof(_SegHeader);
		m_cByteSegBusy += cByteSeg - cByteBlock+sizeof(_SegHeader);
		xbRdbgAssert(m_cByteSegBusy>=0);
		goto realloc_moveblocend;
	}

	//If new size is smaller than current size of block
	//-> free the staying space
	if (cByteBlock > cByteBlockNew)
	{
		//Update physical chain of cells with new free cells inserted
		_CellPhysHeader		*pCellPhysFreed = 
			(_CellPhysHeader*)((char*)pReAllocatedBlock + cByteBlockNew);
		xbint cCellFreed = cCellBlock - cCellBlockNew - 1;

		if ((pCellPhysFreed->m_sNext = pReAllocatedBlock->m_sNext) 
			!= pSegOfReAllocatedBlock->m_pEnd) 
		{
			//If next cells are free cells -> merge with new new free cells
			//before adding it to the chained list.
			if (pCellPhysFreed->m_sNext->m_pSeg)
				pCellPhysFreed->m_sNext->m_pPrev = pCellPhysFreed;
			else
			{
				//Remove the next free cells from chained list of free cells of this size
				//in order to merge them with cells freed
				_CellFreeHeader *pCellFreeToUnlink = (_CellFreeHeader*)((char*)pCellPhysFreed->m_sNext + xbSEGHEAP_HDRLEN);
				if ((pCellPhysFreed->m_sNext = pCellPhysFreed->m_sNext->m_sNext) 
					!= pSegOfReAllocatedBlock->m_pEnd) 
					pCellPhysFreed->m_sNext->m_pPrev = pCellPhysFreed;

				xbint cCellFree = pCellFreeToUnlink->m_cCell;
				xbAssert(pCellFreeToUnlink->m_pSeg == pSegOfReAllocatedBlock);
				xbAssert(cCellFree >= 0 && cCellFree < m_cCellPerSeg);
				m_pcCellFree[cCellFree >> xbSEGCELLS_BYCOUNTERDEC]--;
				xbAssert(m_pcCellFree[cCellFree >> xbSEGCELLS_BYCOUNTERDEC] >= 0);
				if (pCellFreeToUnlink->m_pNext) 
					pCellFreeToUnlink->m_pNext->m_pPrev = pCellFreeToUnlink->m_pPrev;
				if (pCellFreeToUnlink->m_pPrev) 
					pCellFreeToUnlink->m_pPrev->m_pNext = pCellFreeToUnlink->m_pNext;
				else
				{
					xbAssert(m_ppCellFree[cCellFree] == pCellFreeToUnlink);
					m_ppCellFree[cCellFree] = pCellFreeToUnlink->m_pNext;
				}

				cCellFreed += cCellFree + 1;

				//if this check is bad -> 2 following group of free cells -> normaly not possible.
				xbAssert(pCellPhysFreed->m_sNext == pSegOfReAllocatedBlock->m_pEnd || pCellPhysFreed->m_sNext->m_pSeg);
				
			}
		}
		pCellPhysFreed->m_pPrev = pReAllocatedBlock;
		pReAllocatedBlock->m_sNext = pCellPhysFreed;
		pCellPhysFreed->m_pSeg = NULL;

#ifdef _xbALLOCDEBUG_SPACEINIT
		if (xbDebugHeap_SpaceFreed != 0)
			memset((char*)pCellPhysFreed+sizeof(_CellPhysHeader),xbDebugHeap_SpaceFreed,xbNptr(pCellPhysFreed->m_sNext) - xbNptr(pCellPhysFreed)-sizeof(_CellPhysHeader));
#endif

		//Add the new free space to the chained list of free cells of this size
		_CellFreeHeader *pCellFreeFreed = (_CellFreeHeader*)((char*)pCellPhysFreed + xbSEGHEAP_HDRLEN);
		xbAssert(cCellFreed < m_cCellPerSeg);
		m_pcCellFree[cCellFreed >> xbSEGCELLS_BYCOUNTERDEC]++;
		if ((pCellFreeFreed->m_pNext = m_ppCellFree[cCellFreed]) != NULL)
			pCellFreeFreed->m_pNext->m_pPrev = pCellFreeFreed;
		pCellFreeFreed->m_pPrev = NULL;
		pCellFreeFreed->m_pSeg = pSegOfReAllocatedBlock;
		pCellFreeFreed->m_cCell = cCellFreed;
		m_ppCellFree[cCellFreed] = pCellFreeFreed;

		goto realloc_moveblocend;
	}
	
	//The new size is bigger than current block size
	// -> check if it can be expanded in next cells (if cells are free).
	if (cCellBlockNew > m_cCellMinToAllocAlone)
	{
		//Block is too big to be expanded. -> alloc new one.
	#ifdef _xbALLOCDEBUG
		_xbDebugAllocSt *dbg = (_xbDebugAllocSt*)((char*)pBlock+sizeof(_CellPhysHeader));
		void *pNewBloc = Alloc(cByte,AllocMode,/*dbg->m_*/pszFile,/*dbg->m_*/nLine);
	#else
		void *pNewBloc = Alloc(cByte,AllocMode);
	#endif
		memcpy(pNewBloc,((char*)pBlock)+xbSEGHEAP_HDRLEN,cByteBlock - xbSEGHEAP_HDRLEN - xbSEGHEAP_ENDLEN);
		Free(((char*)pBlock)+xbSEGHEAP_HDRLEN);
		return pNewBloc;	
	}

	{
		xbint					cByteUsable = 0;
		{
			_CellPhysHeader		*pCellPhysNextUsable = NULL;
			if (pReAllocatedBlock->m_sNext != pSegOfReAllocatedBlock->m_pEnd 
				&& !pReAllocatedBlock->m_sNext->m_pSeg)
			{
				pCellPhysNextUsable = pReAllocatedBlock->m_sNext;
				cByteUsable = xbint((xbNptr)(pCellPhysNextUsable->m_sNext) - (xbNptr)pCellPhysNextUsable);

				//if this check is bad -> 2 following group of free cells -> normaly not possible.
				xbAssert(pCellPhysNextUsable->m_sNext == pSegOfReAllocatedBlock->m_pEnd 
					|| pCellPhysNextUsable->m_sNext->m_pSeg);
			}

			// -> check if it can be expanded in prev cells (if cells are free and next cells
			// not free or not containing enough space).
			_CellPhysHeader		*pCellPhysPrevUsable = NULL;
			xbint					cBytePrevUsable = 0;
			if (cByteBlockNew > cByteUsable + cByteBlock 
				&& pReAllocatedBlock->m_pPrev != NULL && !pReAllocatedBlock->m_pPrev->m_pSeg)
			{
				pCellPhysPrevUsable = pReAllocatedBlock->m_pPrev;
				cBytePrevUsable = xbint((xbNptr)(pCellPhysPrevUsable->m_sNext) - (xbNptr)pCellPhysPrevUsable);
				if (pCellPhysNextUsable && cBytePrevUsable  + cByteBlock >= cByteBlockNew)
				{
					pCellPhysNextUsable = NULL;
					cByteUsable = 0;
				}

				//if this check is bad -> 2 previous group of free cells -> normaly not possible.
				xbAssert(pCellPhysPrevUsable->m_pPrev == NULL 
					|| pCellPhysPrevUsable->m_pPrev->m_pSeg);
			}

			if (cBytePrevUsable  + cByteBlock + cByteUsable < cByteBlockNew)
			{
				//There is not enough space to expand block, -> allocate it in an other space.
	#ifdef _xbALLOCDEBUG
				_xbDebugAllocSt *dbg = (_xbDebugAllocSt*)((char*)pBlock+sizeof(_CellPhysHeader));
				void *pNewBloc = Alloc(cByte,AllocMode,/*dbg->m_*/pszFile,/*dbg->m_*/nLine);
	#else
				void *pNewBloc = Alloc(cByte,AllocMode);
	#endif
				if (!pNewBloc) return NULL;
				memcpy(pNewBloc,((char*)pBlock)+xbSEGHEAP_HDRLEN,cByteBlock - xbSEGHEAP_HDRLEN - xbSEGHEAP_ENDLEN);
				Free(((char*)pBlock)+xbSEGHEAP_HDRLEN);
				return pNewBloc;	
			}

			if (pCellPhysPrevUsable)
			{
				//Remove the free cells from chained list of free cells of this size
				_CellFreeHeader *pCellFreeToUnlink = 
					(_CellFreeHeader*)((char*)pCellPhysPrevUsable + xbSEGHEAP_HDRLEN);

				xbint cCellFree = pCellFreeToUnlink->m_cCell;
				xbAssert(pCellFreeToUnlink->m_pSeg == pSegOfReAllocatedBlock);
				xbAssert(cCellFree >= 0 && cCellFree < m_cCellPerSeg);
				m_pcCellFree[cCellFree >> xbSEGCELLS_BYCOUNTERDEC]--;
				xbAssert(m_pcCellFree[cCellFree >> xbSEGCELLS_BYCOUNTERDEC] >= 0);
				if (pCellFreeToUnlink->m_pNext) 
					pCellFreeToUnlink->m_pNext->m_pPrev = pCellFreeToUnlink->m_pPrev;
				if (pCellFreeToUnlink->m_pPrev) 
					pCellFreeToUnlink->m_pPrev->m_pNext = pCellFreeToUnlink->m_pNext;
				else
				{
					xbAssert(m_ppCellFree[cCellFree] == pCellFreeToUnlink);
					m_ppCellFree[cCellFree] = pCellFreeToUnlink->m_pNext;
				}
			}

			if (pCellPhysNextUsable)
			{
				//Remove the free cells from chained list of free cells of this size
				_CellFreeHeader *pCellFreeToUnlink = 
					(_CellFreeHeader*)((char*)pCellPhysNextUsable + xbSEGHEAP_HDRLEN);

				xbint cCellFree = pCellFreeToUnlink->m_cCell;
				xbAssert(pCellFreeToUnlink->m_pSeg == pSegOfReAllocatedBlock);
				xbAssert(cCellFree >= 0 && cCellFree < m_cCellPerSeg);
				m_pcCellFree[cCellFree >> xbSEGCELLS_BYCOUNTERDEC]--;
				xbAssert(m_pcCellFree[cCellFree >> xbSEGCELLS_BYCOUNTERDEC] >= 0);
				if (pCellFreeToUnlink->m_pNext) 
					pCellFreeToUnlink->m_pNext->m_pPrev = pCellFreeToUnlink->m_pPrev;
				if (pCellFreeToUnlink->m_pPrev) 
					pCellFreeToUnlink->m_pPrev->m_pNext = pCellFreeToUnlink->m_pNext;
				else
				{
					xbAssert(m_ppCellFree[cCellFree] == pCellFreeToUnlink);
					m_ppCellFree[cCellFree] = pCellFreeToUnlink->m_pNext;
				}

			}

			if (pCellPhysPrevUsable)
			{
				//If prev cells are used, it is necessary to move the block to previous cells. 
				memmove(((char*)pCellPhysPrevUsable)+xbSEGHEAP_HDRLEN,((char*)pReAllocatedBlock)+xbSEGHEAP_HDRLEN,
					cByteBlock - xbSEGHEAP_HDRLEN - xbSEGHEAP_ENDLEN);
				pReAllocatedBlock = pCellPhysPrevUsable;
				pReAllocatedBlock->m_pSeg = pSegOfReAllocatedBlock;
				cByteUsable += cBytePrevUsable;
	#ifdef _xbDEBUGHEAP_HDRSTR
				memcpy((char*)pReAllocatedBlock+xbSEGHEAP_HDRLEN-_xbDEBUGHEAP_HDRLEN,_xbDEBUGHEAP_HDRSTR,_xbDEBUGHEAP_HDRLEN);
	#endif
			}
		}

		_CellPhysHeader		*pCellPhysFreedEnd = 
			(_CellPhysHeader*)((char*)pReAllocatedBlock + cByteBlock + cByteUsable);
		xbAssert(cByteBlockNew <= cByteBlock + cByteUsable);
		if (cByteBlockNew < cByteBlock + cByteUsable)
		{
			//There is free space staying at the end of the expanded block
			// -> Update physical chain of cells with new free cells inserted
			_CellPhysHeader		*pCellPhysFreed = 
				(_CellPhysHeader*)((char*)pReAllocatedBlock + cByteBlockNew);
			xbint cCellFreed = cCellBlock + (cByteUsable - cByteBlockNew) / m_cByteCell - 1;
			xbAssert(cCellFreed >= 0 && cCellFreed < m_cCellPerSeg);

			if ((pCellPhysFreed->m_sNext = pCellPhysFreedEnd) 
				!= pSegOfReAllocatedBlock->m_pEnd) 
			{
				//If next cells are free cells -> merge with new new free cells
				//before adding it to the chained list.
				if (pCellPhysFreedEnd->m_pSeg)
					pCellPhysFreedEnd->m_pPrev = pCellPhysFreed;
				else
				{
					//Remove the next free cells from chained list of free cells of this size
					//in order to merge them with cells freed
					_CellFreeHeader *pCellFreeToUnlink = (_CellFreeHeader*)((char*)pCellPhysFreedEnd + xbSEGHEAP_HDRLEN);
					if ((pCellPhysFreed->m_sNext = pCellPhysFreedEnd->m_sNext) 
						!= pSegOfReAllocatedBlock->m_pEnd) 
						pCellPhysFreed->m_sNext->m_pPrev = pCellPhysFreed;

					xbint cCellFree = pCellFreeToUnlink->m_cCell;
					xbAssert(pCellFreeToUnlink->m_pSeg == pSegOfReAllocatedBlock);
					xbAssert(cCellFree >= 0 && cCellFree < m_cCellPerSeg);
					m_pcCellFree[cCellFree >> xbSEGCELLS_BYCOUNTERDEC]--;
					xbAssert(m_pcCellFree[cCellFree >> xbSEGCELLS_BYCOUNTERDEC] >= 0);
					if (pCellFreeToUnlink->m_pNext) 
						pCellFreeToUnlink->m_pNext->m_pPrev = pCellFreeToUnlink->m_pPrev;
					if (pCellFreeToUnlink->m_pPrev) 
						pCellFreeToUnlink->m_pPrev->m_pNext = pCellFreeToUnlink->m_pNext;
					else
					{
						xbAssert(m_ppCellFree[cCellFree] == pCellFreeToUnlink);
						m_ppCellFree[cCellFree] = pCellFreeToUnlink->m_pNext;
					}

					cCellFreed += cCellFree + 1;

					//if this check is bad -> 2 following group of free cells -> normaly not possible.
					xbAssert(pCellPhysFreed->m_sNext == pSegOfReAllocatedBlock->m_pEnd || pCellPhysFreed->m_sNext->m_pSeg);
					
				}
			}
			pCellPhysFreed->m_pPrev = pReAllocatedBlock;
			pReAllocatedBlock->m_sNext = pCellPhysFreed;
			pCellPhysFreed->m_pSeg = NULL;

#ifdef _xbALLOCDEBUG_SPACEINIT
			if (xbDebugHeap_SpaceFreed != 0)
				memset((char*)pCellPhysFreed+sizeof(_CellPhysHeader),xbDebugHeap_SpaceFreed,xbNptr(pCellPhysFreed->m_sNext) - xbNptr(pCellPhysFreed)-sizeof(_CellPhysHeader));
#endif

			//Add the new free space to the chained list of free cells of this size
			_CellFreeHeader *pCellFreeFreed = (_CellFreeHeader*)((char*)pCellPhysFreed + xbSEGHEAP_HDRLEN);
			xbAssert(cCellFreed >= 0 && cCellFreed < m_cCellPerSeg);
			m_pcCellFree[cCellFreed >> xbSEGCELLS_BYCOUNTERDEC]++;
			if ((pCellFreeFreed->m_pNext = m_ppCellFree[cCellFreed]) != NULL)
				pCellFreeFreed->m_pNext->m_pPrev = pCellFreeFreed;
			pCellFreeFreed->m_pPrev = NULL;
			pCellFreeFreed->m_pSeg = pSegOfReAllocatedBlock;
			pCellFreeFreed->m_cCell = cCellFreed;
			m_ppCellFree[cCellFreed] = pCellFreeFreed;
		}
		else
		{
			//There is NO free space staying at the end of the expanded block
			// -> Only update physical chain of cells with new cells disposition
			if ((pReAllocatedBlock->m_sNext = pCellPhysFreedEnd) 
				!= pSegOfReAllocatedBlock->m_pEnd) 
				pCellPhysFreedEnd->m_pPrev = pReAllocatedBlock;		
		}
	}
	
realloc_moveblocend:
	if (cByteBlockNew > cByteBlock)
	{
		//Initialize new space allocated
		if (AllocMode == xbAlloc_Init) 
			memset((char*)pReAllocatedBlock+cByteBlock - xbSEGHEAP_ENDLEN,0,
			(xbint)((xbNptr)pReAllocatedBlock->m_sNext - (xbNptr)pReAllocatedBlock - cByteBlock 
			- xbSEGHEAP_ENDLEN));
#ifdef _xbALLOCDEBUG_SPACEINIT
		else if (xbDebugHeap_SpaceUninit != 0) 
			memset((char*)pReAllocatedBlock+cByteBlock - xbSEGHEAP_ENDLEN,
			xbDebugHeap_SpaceUninit,
			(xbint)((xbNptr)pReAllocatedBlock->m_sNext - (xbNptr)pReAllocatedBlock - cByteBlock 
			- xbSEGHEAP_ENDLEN));
#endif
	}
#ifdef _xbALLOCDEBUG
	//Feed debug header with new allocation location
	_xbDebugAllocSt *dbg = (_xbDebugAllocSt*)((char*)pReAllocatedBlock+sizeof(_CellPhysHeader));
	dbg->m_pszFile = _xbDebugFileEntry(pszFile);
	dbg->m_nLine = nLine;
	dbg->m_pAllocHeap = this;
#endif
#ifdef _xbDEBUGHEAP_ENDSTR
	memcpy((char*)(pReAllocatedBlock->m_sNext) - xbSEGHEAP_ENDLEN,_xbDEBUGHEAP_ENDSTR,_xbDEBUGHEAP_ENDLEN);
#endif
	m_cByteAlloc += cByteBlockNew - cByteBlock;
#ifdef xbHEAPCOMPLETECHECK
	IsValid();
#endif
	return ((char*)pReAllocatedBlock)+xbSEGHEAP_HDRLEN;
}

void	xbSegHeap::Free(void *pBlock)
{
//#ifdef _DEBUG
	xbRdbgAssert(m_bCreated);
	if (!m_bCreated)
	{
		return;
//		xbThrowEsysLowFmt("xbSegHeap(%s)::Free() : heap not created",GetName());
	}
//#endif
	if (!xbMustBe(pBlock)) return;
	pBlock = ((char*)pBlock)-xbSEGHEAP_HDRLEN;
	
#ifdef xbHEAPCOMPLETECHECK
	IsValid();
#endif
	
	xbSectLockSimpleRec	Lck(&m_Share);
	
	_xbCHECKBLOCK(pBlock);

	_CellPhysHeader	*pFreedBlock = (_CellPhysHeader*)pBlock;
	_SegHeader		*pSegOfFreedBlock = pFreedBlock->m_pSeg;
	xbint				cByteBlock = xbint(xbNptr(pFreedBlock->m_sNext) - xbNptr(pFreedBlock));
	if (!pSegOfFreedBlock || cByteBlock <= 0 /*|| (cByteBlock % m_cByteCell) != 0*/) 
		xbThrowEsehFmt("xbSegHeap(%s)::Free(%08lX) : block already deleted or invalid",GetName(),pBlock);
	
	pSegOfFreedBlock->m_cBuzyBlock--; //Si ça pête ici avec pSegOfFreedBlock == NULL -> c'est que le bloc a déjà été libéré !!
	xbAssert(pSegOfFreedBlock->m_cBuzyBlock>=0);

	if (pSegOfFreedBlock->m_cBuzyBlock<=0)
	{
		//It was the last block used in its segment 
		// -> if there are already 2 free segments in wait 
		// or if segment was allocated only for this block -> delete the segment
		// -> if not -> free block as if there were others blocks used.
//		bool bBigBLock = (pFreedBlock->m_sNext == pSegOfFreedBlock->m_pEnd
//			&& (char*)pFreedBlock == (char*)pSegOfFreedBlock + sizeof(_SegHeader));
		bool bBigBLock = (pSegOfFreedBlock->m_segMode & xbSEGHEAPMODE_BIGBLOCK)?true:false;
		if (m_cSegFree > 1 
			|| bBigBLock)
		{
			//Remove segment from chained list.
			if (pSegOfFreedBlock->m_pNext) 
				pSegOfFreedBlock->m_pNext->m_pPrev = pSegOfFreedBlock->m_pPrev;

			if (pSegOfFreedBlock->m_pPrev)
			{
				pSegOfFreedBlock->m_pPrev->m_pNext = pSegOfFreedBlock->m_pNext;
				xbAssert(pSegOfFreedBlock != m_pFirstSeg);
			}
			else
			{
				xbAssert(pSegOfFreedBlock == m_pFirstSeg);
				m_pFirstSeg = pSegOfFreedBlock->m_pNext;
			}

			//Remove free cells of this segment from chained list 
			//of free cells of this size.
			xbREGISTER _CellPhysHeader *pCellPhys = (_CellPhysHeader*)((char*)pSegOfFreedBlock + sizeof(_SegHeader));
			while(pCellPhys != pSegOfFreedBlock->m_pEnd)
			{
				if (!pCellPhys->m_pSeg)
				{
					_CellFreeHeader *pCellFreeToUnlink = 
						(_CellFreeHeader*)((char*)pCellPhys + xbSEGHEAP_HDRLEN);
					xbint cCellFree = pCellFreeToUnlink->m_cCell;
					xbAssert(pCellFreeToUnlink->m_pSeg == pSegOfFreedBlock);
					xbAssert(cCellFree >= 0 && cCellFree < m_cCellPerSeg);
					m_pcCellFree[cCellFree >> xbSEGCELLS_BYCOUNTERDEC]--;
					xbAssert(m_pcCellFree[cCellFree >> xbSEGCELLS_BYCOUNTERDEC] >= 0);
					if (pCellFreeToUnlink->m_pNext) 
						pCellFreeToUnlink->m_pNext->m_pPrev = pCellFreeToUnlink->m_pPrev;
					if (pCellFreeToUnlink->m_pPrev) 
						pCellFreeToUnlink->m_pPrev->m_pNext = pCellFreeToUnlink->m_pNext;
					else
					{
						xbAssert(m_ppCellFree[cCellFree] == pCellFreeToUnlink);
						m_ppCellFree[cCellFree] = pCellFreeToUnlink->m_pNext;
					}
				}
#ifdef _DEBUG
				else xbAssert(pCellPhys == pFreedBlock);
#endif
				pCellPhys = pCellPhys->m_sNext;
			}

			//Delete segment from MainHeap.
			xbint segSize(xbNptr(pSegOfFreedBlock->m_pEnd) - xbNptr(pSegOfFreedBlock));
			m_cByteSegBusy -= segSize;
			xbRdbgAssert(m_cByteSegBusy>=0);
			if (pSegOfFreedBlock->m_segMode & xbSEGHEAPMODE_LOCKED)
				segUnlock(pSegOfFreedBlock,segSize);
			m_MainHeap.Free(pSegOfFreedBlock);
			if (bBigBLock)
			{
				m_cBigBlock--;
				xbRdbgAssert(m_cBigBlock>=0);
			}
			m_cSeg--;
			goto free_end;
		}

		//... -> if not -> free the block as if there were others blocks used.
		 m_cSegFree++;
	}


	{
		_CellPhysHeader		*pCellPhysEnd = pFreedBlock->m_sNext;
		_CellFreeHeader	*pCellFreeStart;
		xbint				cCellBlock = cByteBlock / m_cByteCell - 1;
		xbAssert(cCellBlock>=0);

		//Merge block to free with previous cells if they are free.
		if (pFreedBlock->m_pPrev 
			&& !(pFreedBlock->m_pPrev->m_pSeg))
		{
			pFreedBlock = pFreedBlock->m_pPrev;
			//if this check is bad -> 2 following group of free cells -> normaly not possible.
			xbAssert(!pFreedBlock->m_pPrev || pFreedBlock->m_pPrev->m_pSeg); 

			//Remove these free cells from chained list of free cells of them size.
			pCellFreeStart = (_CellFreeHeader*)((char*)pFreedBlock + xbSEGHEAP_HDRLEN);
			xbint cCellFree = pCellFreeStart->m_cCell;
			xbAssert(pCellFreeStart->m_pSeg == pSegOfFreedBlock);
			xbAssert(cCellFree >= 0 && cCellFree < m_cCellPerSeg);
			m_pcCellFree[cCellFree >> xbSEGCELLS_BYCOUNTERDEC]--;
			xbAssert(m_pcCellFree[cCellFree >> xbSEGCELLS_BYCOUNTERDEC] >= 0);
			if (pCellFreeStart->m_pNext) 
				pCellFreeStart->m_pNext->m_pPrev = pCellFreeStart->m_pPrev;
			if (pCellFreeStart->m_pPrev) 
				pCellFreeStart->m_pPrev->m_pNext = pCellFreeStart->m_pNext;
			else
			{
				xbAssert(m_ppCellFree[cCellFree] == pCellFreeStart);
				m_ppCellFree[cCellFree] = pCellFreeStart->m_pNext;
			}
			cCellBlock += cCellFree + 1;
		}
		else pCellFreeStart = (_CellFreeHeader*)((char*)pFreedBlock + xbSEGHEAP_HDRLEN);

		//Merge block to free with next cells if they are free.
		if (pCellPhysEnd != pSegOfFreedBlock->m_pEnd && !(pCellPhysEnd->m_pSeg))
		{
			//Remove these free cells from chained list of free cells of them size.
			_CellFreeHeader *pCellFreeToUnlink = (_CellFreeHeader*)((char*)pCellPhysEnd + xbSEGHEAP_HDRLEN);
			xbint cCellFree = pCellFreeToUnlink->m_cCell;
			xbAssert(pCellFreeToUnlink->m_pSeg == pSegOfFreedBlock);
			xbAssert(cCellFree >= 0 && cCellFree < m_cCellPerSeg);
			m_pcCellFree[cCellFree >> xbSEGCELLS_BYCOUNTERDEC]--;
			xbAssert(m_pcCellFree[cCellFree >> xbSEGCELLS_BYCOUNTERDEC] >= 0);
			if (pCellFreeToUnlink->m_pNext) 
				pCellFreeToUnlink->m_pNext->m_pPrev = pCellFreeToUnlink->m_pPrev;
			if (pCellFreeToUnlink->m_pPrev) 
				pCellFreeToUnlink->m_pPrev->m_pNext = pCellFreeToUnlink->m_pNext;
			else
			{
				xbAssert(m_ppCellFree[cCellFree] == pCellFreeToUnlink);
				m_ppCellFree[cCellFree] = pCellFreeToUnlink->m_pNext;
			}

			cCellBlock += cCellFree + 1;
			pCellPhysEnd = pCellPhysEnd->m_sNext;

			//if this check is bad -> 2 following group of free cells -> normaly not possible.
			xbAssert(pCellPhysEnd == pSegOfFreedBlock->m_pEnd || pCellPhysEnd->m_pSeg);
		}

		//Update chained list of physical cells
		xbAssert((char*)pFreedBlock + (cCellBlock+1)*m_cByteCell == (char*)pCellPhysEnd);
		pFreedBlock->m_sNext = pCellPhysEnd;
		if (pCellPhysEnd != pSegOfFreedBlock->m_pEnd) pCellPhysEnd->m_pPrev = pFreedBlock;
		
		//Mark the block as freed
		pFreedBlock->m_pSeg = NULL;
#ifdef _xbALLOCDEBUG_SPACEINIT
		if (xbDebugHeap_SpaceFreed != 0)
			memset((char*)pFreedBlock+sizeof(_CellPhysHeader),xbDebugHeap_SpaceFreed,xbNptr(pFreedBlock->m_sNext) - xbNptr(pFreedBlock)-sizeof(_CellPhysHeader));
#endif
#ifdef _xbDEBUGHEAP_HDRSTR
		//Mark the block as freed with pad string
		memcpy((char*)pBlock+xbSEGHEAP_HDRLEN-_xbDEBUGHEAP_HDRLEN,_xbDEBUGHEAP_DELSTR,_xbDEBUGHEAP_HDRLEN);
#endif

		//Add free cells to chained list of free cells of this size.
		xbAssert(cCellBlock < m_cCellPerSeg);
		m_pcCellFree[cCellBlock >> xbSEGCELLS_BYCOUNTERDEC]++;
		if ((pCellFreeStart->m_pNext = m_ppCellFree[cCellBlock]) != NULL)
			pCellFreeStart->m_pNext->m_pPrev = pCellFreeStart;
		pCellFreeStart->m_pPrev = NULL;
		pCellFreeStart->m_pSeg = pSegOfFreedBlock;
		pCellFreeStart->m_cCell = cCellBlock;
		m_ppCellFree[cCellBlock] = pCellFreeStart;
	}

free_end:
	subAlloc(cByteBlock);
#ifdef xbHEAPCOMPLETECHECK
	IsValid();
#endif
}

bool	xbSegHeap::IsValid() const
{
	xbSectLockSimpleRec Lck(&m_Share);
	_SegHeader *pSeg = m_pFirstSeg,*pPrevSeg = NULL;
	while(pSeg)
	{
		if (pSeg->m_pPrev != pPrevSeg)
		{
			DebugDump();
			return false;
		}
		xbREGISTER _CellPhysHeader *pSegEnd=pSeg->m_pEnd;
		xbREGISTER _CellPhysHeader *pBlock=
			(_CellPhysHeader*)((char*)pSeg + sizeof(_SegHeader));

		while(pBlock < pSegEnd)
		{
			if (pBlock->m_pSeg && !_isValid(pBlock))
			{
				DebugDump();
				return false;
			}
			pBlock = pBlock->m_sNext;
		}
		if ((void*)pBlock > pSegEnd)
		{
			DebugDump();
			return false;
		}
		pPrevSeg = pSeg;
		pSeg = pSeg->m_pNext;
	}
	return true;
}

bool	xbSegHeap::IsValid(void *pBlockSearched) const
{
	if (!pBlockSearched)
		return false;

	pBlockSearched = ((char*)pBlockSearched)-xbSEGHEAP_HDRLEN;

	xbSectLockSimpleRec Lck(&m_Share);
	_SegHeader *pSeg = m_pFirstSeg,*pPrevSeg = NULL;
	while(pSeg)
	{
		if (pSeg->m_pPrev != pPrevSeg)
		{
			DebugDump();
			return false;
		}
		xbREGISTER _CellPhysHeader *pSegEnd=pSeg->m_pEnd;
		xbREGISTER _CellPhysHeader *pBlock=
			(_CellPhysHeader*)((char*)pSeg + sizeof(_SegHeader));

		if (pBlockSearched < pBlock
			|| pBlockSearched >= pSegEnd)
		{
			pPrevSeg = pSeg;
			pSeg = pSeg->m_pNext;
			continue;
		}
		while(pBlock < pSegEnd)
		{
			if (pBlock->m_pSeg)
			{
#ifdef _xbHEAPDEBUG
				if (!_isValid(pBlock))
				{
					DebugDump();
					return false;
				}
#endif
				if (pBlock == pBlockSearched)
					return true;
			}
			else
			{
				if (pBlock == pBlockSearched)
					return false;
			}
			pBlock = pBlock->m_sNext;
		}
		if ((void*)pBlock > pSegEnd)
		{
			DebugDump();
			return false;
		}
		pPrevSeg = pSeg;
		pSeg = pSeg->m_pNext;
	}
	return false;
}

xbint		xbSegHeap::GetSize(void *pBlock) const
{
	xbSectLockSimpleRec Lck(&m_Share);

	pBlock = ((char*)pBlock)-xbSEGHEAP_HDRLEN;
	_xbCHECKBLOCK(pBlock);

	_CellPhysHeader	*pReAllocatedBlock = (_CellPhysHeader*)pBlock;
	return (xbint)((xbNptr)pReAllocatedBlock->m_sNext - (xbNptr)pReAllocatedBlock - xbSEGHEAP_HDRLEN - xbSEGHEAP_ENDLEN);
}

bool	xbSegHeap::_isValid(void *pBlock) const
{
	char *pUserBlock = ((char*)pBlock)+xbSEGHEAP_HDRLEN;
#ifdef _xbALLOCDEBUG
	_xbDebugAllocSt *dbg = (_xbDebugAllocSt*)((char*)pBlock+sizeof(_CellPhysHeader));
	if (dbg->m_pAllocHeap != this)
	{
		try
		{
			if (!dbg->m_pszFile || ::IsBadStringPtrA(dbg->m_pszFile,DBGFILE_SZMAX))
				xbDbgHeapOutput(
					"²\t "
					"?? %08lX(%d) :(%u) "
					"[PB]xbSegHeap(%s): Block (%p) not in this heap !!: phys=%p, next=%p, size=%d [seg=%p, heap=%s]",
					dbg->m_pszFile,dbg->m_nLine,dbg->m_cAllocOp,
					m_szDbgName,(char*)pBlock+xbSEGHEAP_HDRLEN,
					pBlock,((_CellPhysHeader*)pBlock)->m_sNext,
					xbint( (xbNptr) (((_CellPhysHeader*)pBlock)->m_sNext) - (xbNptr)pBlock),
					((_CellPhysHeader*)pBlock)->m_pSeg,
					(dbg->m_pAllocHeap && IsBadReadPtr(dbg->m_pAllocHeap,sizeof(xbBaseHeap))?dbg->m_pAllocHeap->GetName():"???"));
			else
				xbDbgHeapOutput(
					"²\t "
					"%s(%d) :(%u) "
					"[PB]xbSegHeap(%s): Block (%p) not in this heap !!: phys=%p, next=%p, size=%d [seg=%p, heap=%s]",
					dbg->m_pszFile,dbg->m_nLine,dbg->m_cAllocOp,
					m_szDbgName,(char*)pBlock+xbSEGHEAP_HDRLEN,
					pBlock,((_CellPhysHeader*)pBlock)->m_sNext,
					xbint( (xbNptr) (((_CellPhysHeader*)pBlock)->m_sNext) - (xbNptr)pBlock),
					((_CellPhysHeader*)pBlock)->m_pSeg,
					(dbg->m_pAllocHeap && IsBadReadPtr(dbg->m_pAllocHeap,sizeof(xbBaseHeap))?dbg->m_pAllocHeap->GetName():"???"));
		}
		catch(...)
		{
			xbDbgHeapOutput(
				"²\t "
				"SCRATCHED!! [PB]xbSegHeap(%s): Block (%p) not in this heap !!: phys=%p, next=%p, size=%d [seg=%p]",
				m_szDbgName,(char*)pBlock+xbSEGHEAP_HDRLEN,
				pBlock,((_CellPhysHeader*)pBlock)->m_sNext,
				xbint((xbNptr)((_CellPhysHeader*)pBlock)->m_sNext - (xbNptr)pBlock),((_CellPhysHeader*)pBlock)->m_pSeg);
		}
	}
#endif
	if (!m_pFirstSeg) 
	{
		xbDbgHeapOutput("xbSegHeap(%s)::IsValid(void *pBlock=%p) : Heap empty, block is not in this heap",
			GetName(),pUserBlock);
		return false;
	}
#ifdef _xbDEBUGHEAP_DELSTR
	if (memcmp((char*)pBlock+xbSEGHEAP_HDRLEN-_xbDEBUGHEAP_HDRLEN, _xbDEBUGHEAP_DELSTR, _xbDEBUGHEAP_HDRLEN)
		==0)
	{
		xbDbgHeapOutput("xbSegHeap(%s)::IsValid(void *pBlock=%p) : Block already deleted",
			GetName(),pUserBlock);
		return false;
	}
#endif
#ifdef _xbDEBUGHEAP_HDRSTR
	if (memcmp((char*)pBlock+xbSEGHEAP_HDRLEN-_xbDEBUGHEAP_HDRLEN, _xbDEBUGHEAP_HDRSTR, _xbDEBUGHEAP_HDRLEN)
		!=0)
		xbDbgHeapOutput("xbSegHeap(%s)::IsValid(void *pBlock=%p) : Block header scratched",
			GetName(),pUserBlock);
#endif
	
	_SegHeader *pSegOfBlock = (_SegHeader*)((_CellPhysHeader*)pBlock)->m_pSeg;
	if (!pSegOfBlock)
	{
		xbDbgHeapOutput("xbSegHeap(%s)::IsValid(void *pBlock=%p) : Invalid block (segment of block is NULL)",
			GetName(),pUserBlock);
		return false;
	}
	if (!((_CellPhysHeader*)pBlock)->m_sNext
		|| pBlock >= ((_CellPhysHeader*)pBlock)->m_sNext)
	{
		xbDbgHeapOutput("xbSegHeap(%s)::IsValid(void *pBlock=%p) : Invalid block (segment=%p,next block=%p,block start=%p)",
			GetName(),pUserBlock,pSegOfBlock,((_CellPhysHeader*)pBlock)->m_sNext,pBlock);
		return false;
	}
	
	_SegHeader *pMatchSeg = m_pFirstSeg;
	while (pMatchSeg && pMatchSeg != pSegOfBlock) pMatchSeg = pMatchSeg->m_pNext;
	if (!pMatchSeg)
	{
		xbDbgHeapOutput("xbSegHeap(%s)::IsValid(void *pBlock=%p) : block is not in this heap (segment=%p not in segment list of this heap)",
			GetName(),pUserBlock,pSegOfBlock);
		return false;
	}
	
	if (pBlock < (void*)((char*)pSegOfBlock + sizeof(_SegHeader)) 
		|| pBlock >= pSegOfBlock->m_pEnd 
		|| (void*)((_CellPhysHeader*)pBlock)->m_sNext > pSegOfBlock->m_pEnd)
	{
		
		xbDbgHeapOutput("xbSegHeap(%s)::IsValid(void *pBlock=%p) : Offset of block (seg_start=%p,seg_end=%p,nextbloc=%p)",
			GetName(),pUserBlock,pSegOfBlock+1,pSegOfBlock->m_pEnd,
			((_CellPhysHeader*)pBlock)->m_sNext);
		return false;
	}
#ifdef _xbDEBUGHEAP_ENDSTR
	if (memcmp((char*)((_CellPhysHeader*)pBlock)->m_sNext-xbSEGHEAP_ENDLEN, _xbDEBUGHEAP_ENDSTR, xbSEGHEAP_ENDLEN))
		xbDbgHeapOutput("xbSegHeap(%s)::IsValid(void *pBlock=%p) : Block footer scratched (nextbloc=%p)",
			GetName(),pUserBlock,((_CellPhysHeader*)pBlock)->m_sNext);
#endif
	return true;
}

bool	xbSegHeap::Compact()
{
#ifdef xbHEAPCOMPLETECHECK
	IsValid();
#endif
	
	xbSectLockSimpleRec	Lck(&m_Share);

	if (m_cSegFree <= 0) 
		return m_MainHeap.Compact();

	_SegHeader *pSeg = m_pFirstSeg,*pNextSeg;
	while (pSeg) 
	{
		if (pSeg->m_cBuzyBlock != 0)
		{
			pSeg = pSeg->m_pNext;
			continue;
		}

		pNextSeg = pSeg->m_pNext;
		//Remove segment from chained list.
		if (pSeg->m_pNext) 
			pSeg->m_pNext->m_pPrev = pSeg->m_pPrev;
		if (pSeg->m_pPrev)
		{
			pSeg->m_pPrev->m_pNext = pSeg->m_pNext;
			xbRdbgAssert(pSeg != m_pFirstSeg);
		}
		else
		{
			xbRdbgAssert(pSeg == m_pFirstSeg);
			m_pFirstSeg = pSeg->m_pNext;
		}

		//Remove free cells of this segment from chained list 
		//of free cells of this size.
		xbREGISTER _CellPhysHeader *pCellPhys = (_CellPhysHeader*)((char*)pSeg + sizeof(_SegHeader));
		long						cCellDel = 0;
		while(pCellPhys != pSeg->m_pEnd)
		{
			xbAssert(!pCellPhys->m_pSeg); // -> segment freed contains busy cells !!!

			_CellFreeHeader *pCellFreeToUnlink = 
				(_CellFreeHeader*)((char*)pCellPhys + xbSEGHEAP_HDRLEN);
			xbint cCellFree = pCellFreeToUnlink->m_cCell;
			xbAssert(pCellFreeToUnlink->m_pSeg == pSeg);
			xbAssert(cCellFree >= 0 && cCellFree < m_cCellPerSeg);
			m_pcCellFree[cCellFree >> xbSEGCELLS_BYCOUNTERDEC]--;
			xbAssert(m_pcCellFree[cCellFree >> xbSEGCELLS_BYCOUNTERDEC] >= 0);
			if (pCellFreeToUnlink->m_pNext) 
				pCellFreeToUnlink->m_pNext->m_pPrev = pCellFreeToUnlink->m_pPrev;
			if (pCellFreeToUnlink->m_pPrev) 
				pCellFreeToUnlink->m_pPrev->m_pNext = pCellFreeToUnlink->m_pNext;
			else
			{
				xbAssert(m_ppCellFree[cCellFree] == pCellFreeToUnlink);
				m_ppCellFree[cCellFree] = pCellFreeToUnlink->m_pNext;
			}
			cCellDel++;

			pCellPhys = pCellPhys->m_sNext;
		}
		xbAssert(cCellDel == 1); // -> should contain only one block of free cells

		xbint segSize(xbNptr(pSeg->m_pEnd) - xbNptr(pSeg));
		m_cByteSegBusy -= segSize;
		xbRdbgAssert(m_cByteSegBusy>=0);
		//Delete segment from MainHeap.
		if (pSeg->m_segMode & xbSEGHEAPMODE_BIGBLOCK)
		{
			m_cBigBlock--;
			xbRdbgAssert(m_cBigBlock>=0);
		}
		if (pSeg->m_segMode & xbSEGHEAPMODE_LOCKED)
			segUnlock(pSeg,segSize);
		m_MainHeap.Free(pSeg);
		m_cSeg--;
#ifdef _DEBUG
		m_cSegFree--;
#endif
		pSeg = pNextSeg;
	}
	xbAssert(m_cSegFree == 0);
	m_cSegFree = 0;

	m_MainHeap.Compact();

	return true;
}

void	xbSegHeap::DebugDump() const
{
#ifdef _xbHEAPDEBUG
	xbSectLockSimpleRec Lck(&m_Share);

	if (!m_pFirstSeg) return;
	
	xbDbgHeapOutput("xbSegHeap(%s,cByteCell=%d,cCellPerSeg=%d,cSegMax=%d)::DebugDump()\n{ alloc nb = %d, total sz = %I64d",
		GetName(),m_cByteCell,m_cCellPerSeg,m_cSegMax,m_cAlloc,m_cByteAlloc);

	xbint		cAlloc=0;
	int64	cByteAlloc=0;

	_SegHeader *pSeg = (_SegHeader*)m_pFirstSeg,*pPrevSeg = NULL;
	while(pSeg)
	{
		xbDbgHeapOutput("²\tSEGMENT(%p) : start=%p, end=%p, size=%d, buzy blocks=%d",
			pSeg,pSeg+1,pSeg->m_pEnd,m_cByteCellMaxInSeg,pSeg->m_cBuzyBlock);
		if (pPrevSeg != pSeg->m_pPrev)
		{
			xbDbgHeapOutput("Segment(%p) with bad previous ptr(actual=%p, normally=%p)",
				pSeg,pSeg->m_pPrev,pPrevSeg);
		}
		xbREGISTER _CellPhysHeader *pSegEnd=(_CellPhysHeader*)pSeg->m_pEnd;
		xbREGISTER _CellPhysHeader *pBlock=(_CellPhysHeader*)(pSeg+1);
		while(pBlock < pSegEnd)
		{
			if (!pBlock->m_pSeg) 
			{
//				xbDbgHeapOutput("²\t -> Freed block (%p) : phys=%p, next=%p, size=%d",
//					(char*)pBlock+xbSEGHEAP_HDRLEN,pBlock,pBlock->m_sNext,
//					xbint((xbNptr)pBlock->m_sNext - (xbNptr)pBlock));
			}
			else 
			{
#	ifdef _xbALLOCDEBUG
				_xbDebugAllocSt *dbg = (_xbDebugAllocSt*)((char*)pBlock+sizeof(_CellPhysHeader));
#	endif
				try
				{
#					ifdef _xbALLOCDEBUG
					if (!dbg->m_pszFile || ::IsBadStringPtrA(dbg->m_pszFile,DBGFILE_SZMAX))
						xbDbgHeapOutput(
							"²\t "
							"?? %08lX(%d) :(%u) "
							"Busy block (%p) : phys=%p, next=%p, size=%d [seg=%p]",
							dbg->m_pszFile,dbg->m_nLine,dbg->m_cAllocOp,
							(char*)pBlock+xbSEGHEAP_HDRLEN,pBlock,pBlock->m_sNext,
							xbint((xbNptr)pBlock->m_sNext - (xbNptr)pBlock),pBlock->m_pSeg);
					else
#					endif
						xbDbgHeapOutput(
							"²\t "
#					ifdef _xbALLOCDEBUG
							"%s(%d) :(%u) "
#					endif
							"Busy block (%p) : phys=%p, next=%p, size=%d [seg=%p]",
#					ifdef _xbALLOCDEBUG
							dbg->m_pszFile,dbg->m_nLine,dbg->m_cAllocOp,
#					endif
							(char*)pBlock+xbSEGHEAP_HDRLEN,pBlock,pBlock->m_sNext,
							xbint((xbNptr)pBlock->m_sNext - (xbNptr)pBlock),pBlock->m_pSeg);
					
					_isValid(pBlock);
				}
				catch(...)
				{
					xbDbgHeapOutput(
						"²\t "
					"SCRATCHED!! busy block (%p) : phys=%p, next=%p, size=%d [seg=%p]",
					(char*)pBlock+xbSEGHEAP_HDRLEN,pBlock,pBlock->m_sNext,
					xbint((xbNptr)pBlock->m_sNext - (xbNptr)pBlock),pBlock->m_pSeg);
				}

				cByteAlloc += (xbint)((xbNptr)pBlock->m_sNext - (xbNptr)pBlock);
				cAlloc++;
			}
			pBlock = pBlock->m_sNext;
		}
		if (pBlock > pSegEnd)
		{
			xbDbgHeapOutput("Segment(%p) : block outside of this segment (block=%p, segment end=%p) !",
				pSeg,pBlock,pSegEnd);
			break;
		}
		pPrevSeg = pSeg;
		pSeg = pSeg->m_pNext;
	}
	xbDbgHeapOutput("} alloc cAlloc = %d, alloc cByteAlloc = %I64d",cAlloc,cByteAlloc);
#endif
}

void xbSegHeap::segLock(_SegHeader *pSeg,xbint cByte)
{
	xbRdbgAssert(!(pSeg->m_segMode & xbSEGHEAPMODE_LOCKED));
	if (!m_MainHeap.Vlock(pSeg,cByte))
	{
		m_cSegLockedError++;
		return;
	}
	m_cSegLocked++;
	pSeg->m_segMode |= xbSEGHEAPMODE_LOCKED;
}

void xbSegHeap::segUnlock(_SegHeader *pSeg,xbint cByte)
{
	xbRdbgAssert(pSeg->m_segMode & xbSEGHEAPMODE_LOCKED);
	if (!m_MainHeap.Vunlock(pSeg,cByte))
		return;
	pSeg->m_segMode &= ~xbSEGHEAPMODE_LOCKED;
	m_cSegLocked--;
	xbRdbgAssert(m_cSegLocked>=0);
}


char *xbSegHeap::AllocString(const char *pszStr
#ifdef _xbALLOCDEBUG
		,const char *pszFile,int nLine
#endif
		)
{
	size_t len = strlen(pszStr);
	char *newStr = (char*)Alloc(len+1,xbAlloc_Default
#ifdef _xbALLOCDEBUG
		,pszFile,nLine
#endif
		);
	
	if (!newStr)
		return NULL;

	xbStrncpy(newStr,pszStr,len);
	newStr[len] = 0;
	return newStr;
}

#pragma warning(pop)
