#ifndef _xbHEAPBASE_
#define _xbHEAPBASE_
/*<<<***************************************************************************
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: xbHeapBase
#Project: xdcBase
////////////////////////////////////////////////////////////////////////////////
#Author: Marc MIRTI MANCINELLI
#History:
<31/08/2013: creation.
12/02/2014: this notice inserted.
***************************************************************************>>>*/

#ifndef _xbBASE_
#	include "xbBase.h"
#endif

#ifdef xbOS_MSWIN
#	include "osdep/mswin/xbODheapLow.h"
#else
#	pragma message("XDCBASE: ERROR: platform not supported")
#endif

class xbEXPORT xbSectLockSimple
{
public:
	xbSectLockSimple()
	{
		m_pSect = NULL;
	}
	xbSectLockSimple(xbSectShareSimple *pSect)
	{
		m_pSect = NULL;
		Lock(pSect);
	}
	~xbSectLockSimple()
	{
		eProtect(Unlock());
	}
	void Lock(xbSectShareSimple *pSect)
	{
		if (m_pSect) Unlock();
		if (pSect) pSect->Lock();
		m_pSect = pSect;
	}
	void Unlock()
	{
		if (!m_pSect) return;
		xbSectShareSimple	*pSect = m_pSect;
		m_pSect = NULL;
		pSect->Unlock();
	}
	bool IsLocked() const {return m_pSect != NULL;}
protected:
	xbSectShareSimple		*m_pSect;
private:
	xbDclNoCopyForObject(xbSectLockSimple);
};


class xbEXPORT xbSectLockSimpleRec
{
public:
	xbSectLockSimpleRec()
	{
		m_pSect = NULL;
	}
	xbSectLockSimpleRec(xbSectShareSimpleRec *pSect)
	{
		m_pSect = NULL;
		Lock(pSect);
	}
	~xbSectLockSimpleRec()
	{
		eProtect(Unlock());
	}
	void Lock(xbSectShareSimpleRec *pSect)
	{
		if (m_pSect) Unlock();
		if (pSect) pSect->Lock();
		m_pSect = pSect;
	}
	void Unlock()
	{
		if (!m_pSect) return;
		xbSectShareSimpleRec	*pSect = m_pSect;
		m_pSect = NULL;
		pSect->Unlock();
	}
	bool IsLocked() const {return m_pSect != NULL;}
protected:
	xbSectShareSimpleRec		*m_pSect;
private:
	xbDclNoCopyForObject(xbSectLockSimpleRec);
};

/*interface _declspec(uuid("{FFE49FAC-A819-41e8-BEAA-3E605B6771E0}"))
	xbEXPORT sIxbHeap:public sIxbBase
{
	typedef bool (xbBase::*CleanerFct)(xbint cByteRequired);

	//sIxbHeap methods
	virtual void	*Alloc(size_t cByte,xbAllocMode AllocMode
#ifdef _xbALLOCDEBUG
		,const char *pszFile,int nLine
#endif
		) = 0;
	virtual void	*ReAlloc(void *ptr,size_t cByte,xbAllocMode AllocMode
#ifdef _xbALLOCDEBUG
		,const char *pszFile,int nLine
#endif
		) = 0;
	virtual void	Free(void *ptr) = 0;
	virtual void	Clear() = 0;
	virtual int64	GetSize() const = 0;
	virtual xbint	GetSize(void *ptr) const = 0;
	virtual bool	IsValid() const = 0;
	virtual bool	IsValid(void *ptr) const = 0; //if IsValid(NULL) returns true -> method not implemented by heap
	virtual bool	Compact() = 0;
	virtual void	DebugDump() const = 0;

	virtual void	SetCleanerFct(xbBase *pCleanerFctOwner,CleanerFct pCleanerFct) = 0;
	virtual bool	RequestCleanerToFreeBytes(xbint cByteRequired) = 0;

	virtual int64	GetBusySize() const = 0;
	virtual xbint	GetAllocCount() const = 0;
};
*/

class xbEXPORT xbBaseHeap:public xbBase //,public sIxbHeap
{
	//TODO: here : break on a particular allocation number for debug.
public:
	typedef bool (xbBase::*CleanerFct)(xbint cByteRequired);

	xbBaseHeap(const char *pszDbgName);
	virtual ~xbBaseHeap();

	void			SetName(const char *pszDbgName,...);
	const char	*GetName() const {return m_szDbgName;}

/*	//sIxbBase methods
	virtual bool GetInterface(REFIID riid, void **ppInterf)
	{
		xbImplInterface(sIxbHeap);

		return xbBase::GetInterface(riid,ppInterf);
	}
*/
	//sIxbHeap methods
	virtual bool Compact() {return false;}
	virtual void DebugDump() const {};

	virtual void SetCleanerFct(xbBase *pCleanerFctOwner,CleanerFct pCleanerFct) 
	{
		m_pCleanerFctOwner=pCleanerFctOwner;
		m_pCleanerFct=pCleanerFct;
	}
	virtual bool RequestCleanerToFreeBytes(size_t cByteRequired);
	virtual int64	GetSize() const
	{
		return m_cByteAlloc;
	}
	virtual xbint	GetAllocCount() const
	{
		return m_cAlloc;
	}
protected:
	void				resetAllocInfo()
	{
		m_cAlloc = 0;
		m_cByteAlloc = 0;
	}

#ifdef _xbALLOCDEBUG
	void addAllocDebugBreak(uint allocId);
	uint				addAlloc(xbint cByte)
#else
	void				addAlloc(xbint cByte)
#endif
	{
		m_cAlloc++;
		m_cByteAlloc+=cByte;
#ifdef _xbALLOCDEBUG
		m_cAllocOp++;
#	ifdef _xbALLOCDEBUG_CHECKSTEP
		if ((m_cAllocOp % _xbALLOCDEBUG_CHECKSTEP) == 0)
			IsValid();
#	endif
		addAllocDebugBreak(m_cAllocOp);
		return m_cAllocOp;
#endif
	}
	void				subAlloc(xbint cByte)
	{
		m_cAlloc--;
		m_cByteAlloc-=cByte;
		xbAssert(m_cAlloc >= 0 && m_cByteAlloc >= 0);
	}

#ifdef _xbALLOCDEBUG
	uint				m_cAllocOp;
#endif
	xbint				m_cAlloc;
	int64				m_cByteAlloc;
protected:
	char				m_szDbgName[128];
	CleanerFct			m_pCleanerFct;
	xbBase				*m_pCleanerFctOwner;
private:
	xbDclNoNewForObject(xbBaseHeap);
	xbDclNoCopyForObject(xbBaseHeap);
};

#	define _xbHEAPALIGNREF		sizeof(void*)
#	define _xbHEAPALIGN(val)	(((val+_xbHEAPALIGNREF-1)/_xbHEAPALIGNREF)*_xbHEAPALIGNREF)

#	ifdef _xbALLOCDEBUG_OVERFLOW
#		define _xbDEBUGHEAP_HDRLEN	16
#		define _xbDEBUGHEAP_HDRSTR	"MMM-xbHeap-Start"

#		define _xbDEBUGHEAP_ENDLEN	16
#		define _xbDEBUGHEAP_ENDSTR	"MMM--xbHeap--End"

#		define _xbDEBUGHEAP_DELSTR	"MMM-xbHeap-Del!!"

#		define _xbALLOCDEBUG_SPACEINIT
		extern char	xbDebugHeap_SpaceUninit;
		extern char xbDebugHeap_SpaceFreed;
#	else
#		define _xbDEBUGHEAP_HDRLEN	0

#		define _xbDEBUGHEAP_ENDLEN	0
#	endif

#	ifdef _xbALLOCDEBUG
	struct _xbDebugAllocSt
	{
		const char	*m_pszFile;
		int			m_nLine;
		uint		m_cAllocOp;
		const xbBaseHeap	*m_pAllocHeap;
	};
xbEXPORT const char *_xbDebugFileEntry(const char *pszFile);
#	endif

#ifdef xbHEAPINTERNALS
inline void xbDbgHeapOutput(const char *pMsg,...)
{
#ifdef _xbHEAPDEBUG
	va_list ap;
	va_start(ap,pMsg);

	xbRelOutputLowFmtV(pMsg,ap);
#endif
}
#endif

#ifdef _xbALLOCDEBUG
//#	define xbNew(heap)	new(heap,__FILE__,__LINE__)
#	define xbDnew		new(__FILE__,__LINE__)
#else
//#	define xbNew(heap)	new(heap)
#	define xbDnew		new
#endif

#define xbThrow throw xbDnew
/*
#ifdef _xbALLOCDEBUG
#	define xbDclDnewInHeap(heap) \
	void *operator new(size_t sz,const char *pfile,long line) \
	{ \
		return operator new(sz,&heap,pfile,line); \
	} \
	void *operator new[](size_t sz,const char *pfile,long line) \
	{ \
		return operator new(sz,&heap,pfile,line); \
	}
#else
#	define xbDclDnewInHeap(heap) \
	void *operator new(size_t sz) \
	{ \
		return operator new(sz,&heap); \
	} \
	void *operator new[](size_t sz) \
	{ \
		return operator new(sz,&heap); \
	}
#endif
*/

#ifdef _xbALLOCDEBUG
#	define xbHeapDnewImpl(classname,heap) \
		void *operator new(size_t sz,const char *pfile,long line) \
		{ \
			void *ptr = heap.Alloc(sz,xbAlloc_Default,pfile,line); \
			if (!ptr) \
				xbThrowEmem(#classname "::operator new() : not enougth memory"); \
			return ptr; \
		} \
		void operator delete(void *ptr) \
		{ \
			if (!ptr) return; \
			heap.Free(ptr); \
		} \
		void operator delete[](void *pt) {operator delete(pt);} \
		void operator delete(void *ptr,const char *,long) {operator delete(ptr);} \
		void operator delete[](void *ptr,const char *,long) {operator delete(ptr);}

#	define xbHeapDnewDclOnly(classname) \
		void *operator new(size_t sz,const char *pfile,long line); \
		void operator delete(void *ptr); \
		void operator delete[](void *pt) {operator delete(pt);} \
		void operator delete(void *ptr,const char *,long) {operator delete(ptr);} \
		void operator delete[](void *ptr,const char *,long) {operator delete(ptr);}

#	define xbHeapDnewImplOnly(classname,heap) \
		void *classname::operator new(size_t sz,const char *pfile,long line) \
		{ \
			void *ptr = heap.Alloc(sz,xbAlloc_Default,pfile,line); \
			if (!ptr) \
				xbThrowEmem(#classname "::operator new() : not enougth memory"); \
			return ptr; \
		} \
		void classname::operator delete(void *ptr) \
		{ \
			if (!ptr) return; \
			heap.Free(ptr); \
		}
#else
#	define xbHeapDnewImpl(classname,heap) \
		void *operator new(size_t sz) \
		{ \
			void *ptr = heap.Alloc(sz,xbAlloc_Default); \
			if (!ptr) \
				xbThrowEmem(#classname "::operator new() : not enougth memory"); \
			return ptr; \
		} \
		void operator delete(void *ptr) \
		{ \
			if (!ptr) return; \
			heap.Free(ptr); \
		} \
		void operator delete[](void *pt) {operator delete(pt);}

#	define xbHeapDnewDclOnly(classname) \
		void *operator new(size_t sz); \
		void operator delete(void *ptr); \
		void operator delete[](void *pt) {operator delete(pt);}

#	define xbHeapDnewImplOnly(classname,heap) \
		void *classname::operator new(size_t sz) \
		{ \
			void *ptr = heap.Alloc(sz,xbAlloc_Default); \
			if (!ptr) \
				xbThrowEmem(#classname "::operator new() : not enougth memory"); \
			return ptr; \
		} \
		void classname::operator delete(void *ptr) \
		{ \
			if (!ptr) return; \
			heap.Free(ptr); \
		}
#endif

#endif
