#ifndef _xbHEAP_
#define _xbHEAP_
/*<<<***************************************************************************
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:
<10/02/2014: creation.
12/02/2014: this notice inserted.
***************************************************************************>>>*/

#ifndef _xbHEAPBASE_
#	include "xbHeapBase.h"
#endif

#define xbUSEVIRTUALHEAP
//#define xbUSECRTHEAP

#ifdef _xbALLOCDEBUG
#	define	xbSEGHEAP_HDRLEN	(sizeof(_CellPhysHeader)+sizeof(_xbDebugAllocSt)+_xbDEBUGHEAP_HDRLEN)
#else
#	define	xbSEGHEAP_HDRLEN	(sizeof(_CellPhysHeader)+_xbDEBUGHEAP_HDRLEN)
#endif
#define	xbSEGHEAP_ENDLEN	(_xbDEBUGHEAP_ENDLEN)

class xbEXPORT xbllCrtHeap
{
public:
	xbllCrtHeap(bool bMT,xbCtorMode CtorMode);
	virtual ~xbllCrtHeap();
	void	Create();
	void	Destroy();

	void *Alloc(size_t cByte,xbOpMode opmode=xbOp_Required);
	void *ReAlloc(void *ptr,size_t cByte,xbOpMode opmode=xbOp_Required);
	void Free(void *ptr);
	bool Compact();

private:
	bool	m_bCreated;
//	int		m_cAlloc;

	xbDclNoNewForObject(xbllCrtHeap);
	xbDclNoCopyForObject(xbllCrtHeap);
};

class xbEXPORT xbSegHeap:public xbBaseHeap
{
public:
	xbSegHeap(const char *pszDbgName, xbint cByteCell, xbint cByteSeg = 0, xbint cByteMax = 0,
		xbCtorMode CtorMode = xbCtor_CallCreate);
	xbSegHeap(const char *pszDbgName, xbCtorMode CtorMode = xbCtor_CallCreate);
	virtual ~xbSegHeap();

	void	SetParams(xbint cByteCell, xbint cByteSeg, xbint cByteMax);
	void	GetParams(xbint *pcByteCell, xbint *pcByteSeg, xbint *pcByteMax, bool bReal = true) const;
	void	Create();
	void	Destroy();

	//sIxbHeap methods
	/*virtual*/ void	*Alloc(size_t cByte,xbAllocMode AllocMode
#ifdef _xbALLOCDEBUG
		,const char *pszFile,int nLine
#endif
		);
	/*virtual*/ void	*ReAlloc(void *ptr,size_t cByte,xbAllocMode AllocMode
#ifdef _xbALLOCDEBUG
		,const char *pszFile,int nLine
#endif
		);
	/*virtual*/ char *AllocString(const char *pszStr
#ifdef _xbALLOCDEBUG
		,const char *pszFile,int nLine
#endif
		);
	/*virtual*/ void	Free(void *ptr);

	virtual void	Clear();
	virtual xbint	GetSize(void *ptr) const;
	virtual int64	GetSize() const
	{
		return xbBaseHeap::GetSize();
	}
	virtual bool	IsValid() const;
	virtual bool	IsValid(void *ptr) const;
	virtual bool	Compact();
	virtual void	DebugDump() const;
	virtual int64	GetBusySize() const;

	xbint GetSegmentCount() const;
	xbint GetFreeSegmentCount() const;
	xbint GetSegmentCreatedCount() const;
	xbint GetBigBlockCount() const;

	xbint GetSegmentLockedErrorCount() const;
	xbint GetSegmentLockedCount() const;
	bool GetSegmentToLock() const;
	void SetSegmentToLock(bool bFlg);

	bool IsCreated() const {return m_bCreated;}

	size_t SizeAlign(size_t cByte)
	{
		return (cByte+xbSEGHEAP_HDRLEN+xbSEGHEAP_ENDLEN+m_cByteCell-1) / m_cByteCell * m_cByteCell;
	}
protected:

	struct _CellPhysHeader;
	struct _SegHeader
	{
#ifdef XDCBASE_X64
#define xbSEGHEAPMODE_BIGBLOCK	0x00000001
#define xbSEGHEAPMODE_LOCKED	0x00000002
		ulong				m_cBuzyBlock;
		ulong				m_segMode;
#else
#define xbSEGHEAPMODE_BIGBLOCK	0x0001
#define xbSEGHEAPMODE_LOCKED	0x0002
		ushort				m_cBuzyBlock;
		ushort				m_segMode;
#endif
		_SegHeader			*m_pNext;
		_SegHeader			*m_pPrev;
		_CellPhysHeader		*m_pEnd;
	};

	struct _CellPhysHeader
	{
		_CellPhysHeader		*m_sNext;
		_CellPhysHeader		*m_pPrev;
		_SegHeader			*m_pSeg;
	};

	struct _CellFreeHeader
	{
		_CellFreeHeader		*m_pNext;
		_CellFreeHeader		*m_pPrev;
		_SegHeader			*m_pSeg;
		xbint				m_cCell;
	};

	mutable xbSectShareSimpleRec	m_Share;
#ifdef	xbUSEVIRTUALHEAP
		xbllVirtualHeap			m_MainHeap;
#else
	#ifdef	xbUSECRTHEAP
		xbllCrtHeap				m_MainHeap;
	#else
		xbllSysHeap				m_MainHeap;
	#endif
#endif
	bool					m_bCreated;
	bool					m_bSegToLock;

	//Params set by SetParams().
	xbint				m_cByteCellAsked;
	xbint				m_cByteSegAsked;
	xbint				m_cByteMaxAsked;

	//Calculated params from previous params.
	xbint				m_cCellPerSeg;
	xbint				m_cCellMinToAllocAlone;
	xbint				m_cByteCell;
	xbint				m_cByteCellMaxInSeg;
	xbint				m_cByteSeg;
	xbint				m_cSegMax;
	xbint				m_cCellCounter;

	//Execution status params
	xbint					m_cSeg,m_cSegFree;
	_SegHeader				*m_pFirstSeg;
	_CellFreeHeader			**m_ppCellFree;
	xbuint					*m_pcCellFree;
	xbint					m_cByteSegBusy;

	xbint					m_cSegCreated,m_cBigBlock,m_cSegLocked,m_cSegLockedError;

	bool					_isValid(void *pBloc) const;

#if defined(xbHEAPRELEASECHECK) || defined(_DEBUG)
	void					_checkBlock(void *pBloc) const;
#endif

	xbint bigBlockAlign(xbint sz) const
	{
		return ((sz+m_cByteSeg-1)/m_cByteSeg)*m_cByteSeg;
	}

	void segLock(_SegHeader *pSeg,xbint cByte);
	void segUnlock(_SegHeader *pSeg,xbint cByte);

private:
	xbDclNoNewForObject(xbSegHeap);
	xbDclNoCopyForObject(xbSegHeap);
};

#endif
