You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1267 lines
40 KiB
C++

// XTPCustomHeap.h: *** template definition.
//
// This file is a part of the XTREME TOOLKIT PRO MFC class library.
// (c)1998-2012 Codejock Software, All Rights Reserved.
//
// THIS SOURCE FILE IS THE PROPERTY OF CODEJOCK SOFTWARE AND IS NOT TO BE
// RE-DISTRIBUTED BY ANY MEANS WHATSOEVER WITHOUT THE EXPRESSED WRITTEN
// CONSENT OF CODEJOCK SOFTWARE.
//
// THIS SOURCE CODE CAN ONLY BE USED UNDER THE TERMS AND CONDITIONS OUTLINED
// IN THE XTREME TOOLKIT PRO LICENSE AGREEMENT. CODEJOCK SOFTWARE GRANTS TO
// YOU (ONE SOFTWARE DEVELOPER) THE LIMITED RIGHT TO USE THIS SOFTWARE ON A
// SINGLE COMPUTER.
//
// CONTACT INFORMATION:
// support@codejock.com
// http://www.codejock.com
//
/////////////////////////////////////////////////////////////////////////////
//{{AFX_CODEJOCK_PRIVATE
#if !defined(_XTPCUSTOMHEAP_H__)
#define _XTPCUSTOMHEAP_H__
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
//}}AFX_CODEJOCK_PRIVATE
#include "XTPVC80Helpers.h"
//{{AFX_CODEJOCK_PRIVATE
#define XTP_EXPORT_PARAMS_NO
typedef enum _XTP_HEAP_INFORMATION_CLASS
{
xtpHeapCompatibilityInformation
}
XTP_HEAP_INFORMATION_CLASS;
//}}AFX_CODEJOCK_PRIVATE
//===========================================================================
// Summary:
// This function enables features for a specified heap.
// Parameters:
// hHeapHandle - [in] Handle to the heap where information is to be set.
// This handle is returned by either the HeapCreate or
// GetProcessHeap function.
//
// pHeapInformation - [in] Heap information buffer. The format of this data
// depends on the HeapCompatibilityInformation class.
//
// nHeapInformationLength - [in] Size of the pHeapInformation buffer, in bytes.
// Remarks:
// This function is a wrapper to HeapSetInformation windows API function.
// If HeapSetInformation is not supported by windows, this function exits
// without any actions.
// Returns:
// If the function succeeds, the return value is nonzero
// If the function fails, the return value is 0 (zero). To get extended
// error information, call GetLastError.
// If HeapSetInformation is not supported by windows return value is also TRUE.
// See Also:
// HeapSetInformation, XTPHeapSetLowFragmentation
//===========================================================================
AFX_INLINE BOOL XTPHeapSetCompatibilityInformation(HANDLE hHeapHandle, PVOID pHeapInformation, ULONG_PTR nHeapInformationLength)
{
#ifdef _WIN32_WCE
return TRUE; // Not supported;
#else
typedef BOOL (WINAPI *PFNHEAPSETINFORMATION)(HANDLE HeapHandle, XTP_HEAP_INFORMATION_CLASS eHICls, PVOID HeapInformation, ULONG_PTR HeapInformationLength);
HMODULE hKernel = ::GetModuleHandle(_T("KERNEL32.DLL"));
ASSERT(NULL != hKernel);
if (NULL != hKernel)
{
PFNHEAPSETINFORMATION pfHeapSetInformation = (PFNHEAPSETINFORMATION)::GetProcAddress(hKernel, "HeapSetInformation");
if (NULL != pfHeapSetInformation)
{
return pfHeapSetInformation(hHeapHandle, xtpHeapCompatibilityInformation,
pHeapInformation, nHeapInformationLength);
}
}
return TRUE; // Not supported;
#endif
}
//===========================================================================
// Summary:
// Call this member to enable "Low-fragmentation Heap" (LFH) feature for
// a given heap.
// Parameters:
// hHeapHandle - [in] Handle to the heap where information is to be set.
// This handle is returned by either the HeapCreate or
// GetProcessHeap function.
// Remarks:
// This function is a wrapper to HeapSetInformation windows API function.
// If HeapSetInformation is not supported by windows, this function exits
// without any actions.
// Returns:
// If the function succeeds, the return value is nonzero
// If the function fails, the return value is 0 (zero). To get extended
// error information, call GetLastError.
// If HeapSetInformation is not supported by windows return value is also TRUE.
// See Also:
// HeapSetInformation, XTPHeapSetCompatibilityInformation
//===========================================================================
AFX_INLINE BOOL XTPHeapSetLowFragmentation(HANDLE hHeapHandle)
{
// LFH mode does not enabled under debugger,
// only under 'clear' run.
ULONG uHI = 2;
return XTPHeapSetCompatibilityInformation(hHeapHandle, &uHI, sizeof(uHI));
}
//===========================================================================
// Summary:
// This template class used as a base class for allocators which can use
// a custom (separate) heap. Each allocator use own heap or standard heap.
// To use custom heap set ms_bUseCustomHeap member to TRUE.
// Parameters:
// _TData - This class must contain following static members for allocator:
//
// struct allocatorClassData
// {
// static HANDLE ms_hCustomHeap; // handle to the custom heap
// static LONG ms_dwRefs; // allocated blocks count;
// static BOOL ms_bLFHEnabled; // report is LFH enabled for custom heap;
// static BOOL ms_bUseCustomHeap; // Define does allocator use custom heap or default heap;
// };
// See Also:
// XTP_DECLARE_HEAP_ALLOCATOR, XTP_IMPLEMENT_HEAP_ALLOCATOR,
// CXTPHeapObjectT
//===========================================================================
template<class _TData>
class CXTPHeapAllocatorT : public _TData
{
public:
//{{AFX_CODEJOCK_PRIVATE
typedef _TData TData;
//}}AFX_CODEJOCK_PRIVATE
//*** Allocator Interface ***
//-----------------------------------------------------------------------
// Summary:
// Allocate memory block of nBytes size.
// Returns:
// A pointer to allocated block or NULL.
// See Also:
// Free_mem
//-----------------------------------------------------------------------
static void* AFX_CDECL Alloc_mem(size_t nBytes)
{
InterlockedIncrement(&ms_dwRefs); //ms_dwRefs++;
if (ms_bUseCustomHeap)
{
CreateHeapIfNeed();
return ::HeapAlloc(ms_hCustomHeap, 0, nBytes);
}
else
{
#ifdef _DEBUG
return DEBUG_NEW char[nBytes];
#else
return new char[nBytes];
#endif
}
};
//-----------------------------------------------------------------------
// Summary:
// Free memory block previously allocated by Alloc_mem.
// Parameters:
// p - [in] Pointer to a memory block.
// See Also:
// Alloc_mem
//-----------------------------------------------------------------------
static void AFX_CDECL Free_mem(void* p)
{
LONG nRefs = 0;
if (ms_dwRefs)
nRefs = InterlockedDecrement(&ms_dwRefs); //ms_dwRefs--;
if (ms_bUseCustomHeap)
{
VERIFY(::HeapFree(ms_hCustomHeap, 0, p));
if (nRefs == 0)
ClearHeap();
}
else
{
delete p;
}
};
//*** Implementation ***
//{{AFX_CODEJOCK_PRIVATE
CXTPHeapAllocatorT()
{
};
virtual ~CXTPHeapAllocatorT()
{
// When other static objects use this allocator,
// they may be destroyed later (and free memory later)
// Each static object, which use this allocator,
// should check ms_dwRefs and destroy heap if no more refs.
if (ms_dwRefs == 0)
ClearHeap();
};
static void AFX_CDECL CreateHeapIfNeed()
{
if (!ms_hCustomHeap)
{
ms_hCustomHeap = ::HeapCreate(0, 0, 0);
ASSERT(ms_hCustomHeap);
ms_bLFHEnabled = XTPHeapSetLowFragmentation(ms_hCustomHeap);
}
}
static void AFX_CDECL ClearHeap()
{
ASSERT(ms_dwRefs == 0);
if (ms_hCustomHeap)
VERIFY(::HeapDestroy(ms_hCustomHeap));
ms_hCustomHeap = NULL;
}
//}}AFX_CODEJOCK_PRIVATE
};
//{{AFX_CODEJOCK_PRIVATE
#define XTP_DECLARE_HEAP_ALLOCATOR_(allocatorClass, EXPORT_PARAMS) \
struct EXPORT_PARAMS allocatorClass##Data \
{ \
static HANDLE ms_hCustomHeap; \
static LONG ms_dwRefs; \
static BOOL ms_bLFHEnabled; \
static BOOL ms_bUseCustomHeap; \
}; \
class EXPORT_PARAMS allocatorClass : public CXTPHeapAllocatorT<allocatorClass##Data> {};
//}}AFX_CODEJOCK_PRIVATE
//===========================================================================
// Summary:
// This macros used to declare allocator class derived from CXTPHeapAllocatorT
// which can use default or custom (separate) heap.
// Such allocator can be used as parameter for CXTPHeapObjectT template or
// for other cases.
// Parameters:
// allocatorClass - [in] Name of the allocator class.
// Remarks:
// Used together with XTP_IMPLEMENT_HEAP_ALLOCATOR macro.
// Example:
// <code>
//
// // probably in header (*.h) file:
// XTP_DECLARE_HEAP_ALLOCATOR(CXTPReportRowAllocator)
//
// // in implementation (*.cpp) file:
// XTP_IMPLEMENT_HEAP_ALLOCATOR(CXTPReportRowAllocator)
//
// </code>
// See Also:
// XTP_IMPLEMENT_HEAP_ALLOCATOR, CXTPHeapAllocatorT, CXTPHeapObjectT
//===========================================================================
#define XTP_DECLARE_HEAP_ALLOCATOR(allocatorClass) XTP_DECLARE_HEAP_ALLOCATOR_(allocatorClass, XTP_EXPORT_PARAMS_NO)
//===========================================================================
// Summary:
// This macros used to implement allocator class previously declared by
// XTP_DECLARE_HEAP_ALLOCATOR macro.
// Such allocator can be used as parameter for CXTPHeapObjectT template or
// for other cases.
// Parameters:
// allocatorClass - [in] Name of the allocator class.
// bUseCustomHeap - [in] Set as TRUE to enable custom heap by default for this allocator and FALSE to disable.
// Remarks:
// Used together with XTP_DECLARE_HEAP_ALLOCATOR macro.
// Example:
// <code>
//
// // probably in header (*.h) file:
// XTP_DECLARE_HEAP_ALLOCATOR(CXTPReportRowAllocator)
//
// // in implementation (*.cpp) file:
// XTP_IMPLEMENT_HEAP_ALLOCATOR(CXTPReportRowAllocator)
//
// </code>
// See Also:
// XTP_DECLARE_HEAP_ALLOCATOR, CXTPHeapAllocatorT, CXTPHeapObjectT
//===========================================================================
#define XTP_IMPLEMENT_HEAP_ALLOCATOR(allocatorClass, bUseCustomHeap) \
HANDLE allocatorClass##Data::ms_hCustomHeap = NULL; \
LONG allocatorClass##Data::ms_dwRefs = 0; \
BOOL allocatorClass##Data::ms_bLFHEnabled = FALSE; \
BOOL allocatorClass##Data::ms_bUseCustomHeap = bUseCustomHeap; \
allocatorClass g_obj##allocatorClass;
//===========================================================================
// Summary:
// This template class used as a helper class to override new/delete
// operators and use custom heap allocators inside them.
// Parameters:
// _TObject - A base class;
// _TAllocator - An allocator class name;
//
// Example:
// <code>
//
// // *** Allocator must be declared (and implemented)
// // probably in header (*.h) file:
// XTP_DECLARE_HEAP_ALLOCATOR(CMyCustomHeapAllocator)
//
// // in implementation (*.cpp) file:
// XTP_IMPLEMENT_HEAP_ALLOCATOR(CMyCustomHeapAllocator, TRUE)
//
// // To enable custom heap allocations use second parameter in
// // XTP_IMPLEMENT_HEAP_ALLOCATOR macro or set corresponding flag
// // on initialization, before any allocations:
// //
// CMyCustomHeapAllocator::ms_bUseCustomHeap = TRUE;
//
// //*** One way to use:
// class CMyClass : public CXTPHeapObjectT<CMyClassBase, CMyCustomHeapAllocator>
// {
// // ...
// };
// CMyClass* pMyClassObj = new CMyClass();
//
//
// //*** Other way to use:
// class CMyClass : public CMyClassBase
// {
// // ...
// };
//
// class CMyClass_heap : public CXTPHeapObjectT<CMyClass, CMyCustomHeapAllocator>
// {
// };
// CMyClass* pMyClassObj = new CMyClass_heap();
// </code>
//
// See Also:
// XTP_DECLARE_HEAP_ALLOCATOR, XTP_IMPLEMENT_HEAP_ALLOCATOR,
//===========================================================================
template<class _TObject, class _TAllocator>
class CXTPHeapObjectT : public _TObject
{
public:
//{{AFX_CODEJOCK_PRIVATE
typedef _TObject TObject;
typedef _TAllocator TAllocator;
//}}AFX_CODEJOCK_PRIVATE
//-----------------------------------------------------------------------
// Summary:
// Allocate memory block of nSize bytes.
// Returns:
// A pointer to allocated block or NULL.
// See Also:
// operator delete
//-----------------------------------------------------------------------
void* PASCAL operator new(size_t nSize)
{
if (TAllocator::ms_bUseCustomHeap)
return TAllocator::Alloc_mem(nSize);
else
{
InterlockedIncrement(&TAllocator::ms_dwRefs); //TAllocator::ms_dwRefs++;
return ::operator new(nSize);
}
}
//-----------------------------------------------------------------------
// Summary:
// Free memory block previously allocated by operator new.
// Parameters:
// p - [in] Pointer to a memory block.
// See Also:
// operator new
//-----------------------------------------------------------------------
void PASCAL operator delete(void* p)
{
if (TAllocator::ms_bUseCustomHeap)
TAllocator::Free_mem(p);
else
{
InterlockedDecrement(&TAllocator::ms_dwRefs); //TAllocator::ms_dwRefs--;
::operator delete(p);
}
}
//{{AFX_CODEJOCK_PRIVATE
//void* PASCAL operator new(size_t, void* p) {return p;} // default is fine as is
#if _MSC_VER >= 1200
void PASCAL operator delete(void* p, void* pPlace)
{
if (TAllocator::ms_bUseCustomHeap)
operator delete(p);
else
{
InterlockedDecrement(&TAllocator::ms_dwRefs); //TAllocator::ms_dwRefs--;
::operator delete(p, pPlace);
}
}
#endif
#if defined(_DEBUG) && !defined(_AFX_NO_DEBUG_CRT)
// for file name/line number tracking using DEBUG_NEW
void* PASCAL operator new(size_t nSize, LPCSTR lpszFileName, int nLine)
{
if (TAllocator::ms_bUseCustomHeap)
return operator new(nSize);
else
{
InterlockedIncrement(&TAllocator::ms_dwRefs); //TAllocator::ms_dwRefs++;
return ::operator new(nSize, lpszFileName, nLine);
}
}
#if _MSC_VER >= 1200
void PASCAL operator delete(void *p, LPCSTR lpszFileName, int nLine)
{
if (TAllocator::ms_bUseCustomHeap)
operator delete(p);
else
{
InterlockedDecrement(&TAllocator::ms_dwRefs); //TAllocator::ms_dwRefs--;
::operator delete(p, lpszFileName, nLine);
}
}
#endif
#endif
//}}AFX_CODEJOCK_PRIVATE
};
//===========================================================================
// Summary:
// This class used to store strings. It automatically allocate/deallocate
// memory for string data.
// Remarks:
// Override _AllocStringData, _FreeStringData to change default memory allocation.
// See Also:
// CXTPHeapStringT, XTP_DECLARE_HEAP_ALLOCATOR, CXTPHeapAllocatorT
//===========================================================================
class _XTP_EXT_CLASS CXTPHeapString
{
public:
//-----------------------------------------------------------------------
// Summary:
// Default object constructor.
// See Also:
// ~CXTPHeapString
//-----------------------------------------------------------------------
CXTPHeapString()
{
m_nStrLen = 0;
m_pcszString = NULL;
}
//-----------------------------------------------------------------------
// Summary:
// Object constructor.
// Parameters:
// pcszString - [in] Pointer to a source string.
// See Also:
// ~CXTPHeapString
//-----------------------------------------------------------------------
CXTPHeapString(LPCTSTR pcszString)
{
m_nStrLen = 0;
m_pcszString = NULL;
SetString(pcszString);
}
//-----------------------------------------------------------------------
// Summary:
// Default object destructor.
// See Also:
// CXTPHeapString
//-----------------------------------------------------------------------
virtual ~CXTPHeapString()
{
_FreeStringData();
}
//-----------------------------------------------------------------------
// Summary:
// Use this function to determine is string empty.
// Returns:
// TRUE if stored string is empty, FALSE otherwise.
//-----------------------------------------------------------------------
virtual BOOL IsEmpty() const
{
return !m_pcszString || m_nStrLen == 0;
}
//-----------------------------------------------------------------------
// Summary:
// Assign new string value.
// Parameters:
// pcszString - [in] Pointer to a source string.
// Returns:
// Stored string value.
//-----------------------------------------------------------------------
LPCTSTR operator=(LPCTSTR pcszString)
{
SetString(pcszString);
return m_pcszString ? m_pcszString : _T("");
}
//-----------------------------------------------------------------------
// Summary:
// Determine are strings equal.
// Parameters:
// pcszString - [in] Pointer to a string to compare.
// Returns:
// TRUE if strings are equal, FALSE otherwise.
//-----------------------------------------------------------------------
BOOL operator==(LPCTSTR pcszString) const
{
return 0 == _tcscmp((LPCTSTR)*this, pcszString);
}
//-----------------------------------------------------------------------
// Summary:
// Determine are strings different.
// Parameters:
// pcszString - [in] Pointer to a string to compare.
// Returns:
// TRUE if strings are different, FALSE otherwise.
//-----------------------------------------------------------------------
BOOL operator!=(LPCTSTR pcszString) const
{
return 0 != _tcscmp((LPCTSTR)*this, pcszString);
}
//-----------------------------------------------------------------------
// Summary:
// operator LPCTSTR.
// Returns:
// Pointer to a stored string.
//-----------------------------------------------------------------------
operator LPCTSTR() const
{
return m_pcszString ? m_pcszString : _T("");
}
//-----------------------------------------------------------------------
// Summary:
// operator CString.
// Returns:
// A CString object which contains stored string.
//-----------------------------------------------------------------------
operator CString() const
{
return CString(m_pcszString ? m_pcszString : _T(""));
}
//-----------------------------------------------------------------------
// Summary:
// Allocates a BSTR from stored string data..
// Returns:
// The newly allocated string.
//-----------------------------------------------------------------------
virtual BSTR AllocSysString() const
{
CString str(m_pcszString ? m_pcszString : _T(""));
return str.AllocSysString();
}
//-----------------------------------------------------------------------
// Summary:
// Use this method to set new string value.
// Parameters:
// pcszString - [in] Pointer to a source string.
//-----------------------------------------------------------------------
virtual void SetString(LPCTSTR pcszString)
{
if (!pcszString || *pcszString == 0)
{
_FreeStringData();
return;
}
int nNewStrLen = (int)_tcslen(pcszString);
if (nNewStrLen <= m_nStrLen && m_pcszString)
{
STRCPY_S(m_pcszString, m_nStrLen + 1, pcszString);
}
else
{
_FreeStringData();
_AllocStringData(nNewStrLen);
if (m_pcszString)
STRCPY_S(m_pcszString, m_nStrLen + 1, pcszString);
}
}
protected:
//-----------------------------------------------------------------------
// Summary:
// This method is used to allocate string data buffer.
// Parameters:
// nNewStrLen - [in] New string length without null character.
//-----------------------------------------------------------------------
virtual void _AllocStringData(int nNewStrLen)
{
ASSERT(m_pcszString == NULL);
m_nStrLen = nNewStrLen;
m_pcszString = new TCHAR[nNewStrLen + 1];
}
//-----------------------------------------------------------------------
// Summary:
// This method is used to free string data buffer previously allocated
// in _AllocStringData.
//-----------------------------------------------------------------------
virtual void _FreeStringData()
{
if (m_pcszString)
delete m_pcszString;
m_pcszString = NULL;
m_nStrLen = 0;
}
int m_nStrLen; // Stored string length (without null character).
LPTSTR m_pcszString; // Pointer to a stored string (or NULL).
};
//===========================================================================
// Summary:
// This template used to store strings using different allocators.
// Remarks:
// String data stored in default or separate (custom) heap.
// Specially useful for VC 6.0 instead of CString, because
// CString Release implementation allocates data using some cache
// and data is not deallocated when CString destroyed.
// See Also:
// CXTPHeapString, XTP_DECLARE_HEAP_ALLOCATOR, CXTPHeapAllocatorT
//===========================================================================
template<class _TAllocator>
class CXTPHeapStringT : public CXTPHeapString
{
public:
//{{AFX_CODEJOCK_PRIVATE
typedef _TAllocator TAllocator;
//}}AFX_CODEJOCK_PRIVATE
//-----------------------------------------------------------------------
// Summary:
// Default object constructor.
// Parameters:
// pcszString - [in] Pointer to a source string.
// See Also:
// ~CXTPHeapStringT
//-----------------------------------------------------------------------
CXTPHeapStringT(LPCTSTR pcszString = _T(""))
{
SetString(pcszString);
}
//-----------------------------------------------------------------------
// Summary:
// Default object destructor.
// See Also:
// CXTPHeapString
//-----------------------------------------------------------------------
virtual ~CXTPHeapStringT()
{
_FreeStringData();
}
//-----------------------------------------------------------------------
// Summary:
// Assign new string value.
// Parameters:
// pcszString - [in] Pointer to a source string.
// Returns:
// Stored string value.
//-----------------------------------------------------------------------
LPCTSTR operator=(LPCTSTR pcszString)
{
SetString(pcszString);
return m_pcszString ? m_pcszString : _T("");
}
//-----------------------------------------------------------------------
// Summary:
// Determine are strings equal.
// Parameters:
// pcszString - [in] Pointer to a string to compare.
// Returns:
// TRUE if strings are equal, FALSE otherwise.
//-----------------------------------------------------------------------
BOOL operator==(LPCTSTR pcszString) const
{
return 0 == _tcscmp((LPCTSTR)*this, pcszString);
}
//-----------------------------------------------------------------------
// Summary:
// Determine are strings different.
// Parameters:
// pcszString - [in] Pointer to a string to compare.
// Returns:
// TRUE if strings are different, FALSE otherwise.
//-----------------------------------------------------------------------
BOOL operator!=(LPCTSTR pcszString) const
{
return 0 != _tcscmp((LPCTSTR)*this, pcszString);
}
//-----------------------------------------------------------------------
// Summary:
// operator LPCTSTR.
// Returns:
// Pointer to a stored string.
//-----------------------------------------------------------------------
operator LPCTSTR() const
{
return m_pcszString ? m_pcszString : _T("");
}
//-----------------------------------------------------------------------
// Summary:
// operator CString.
// Returns:
// A CString object which contains stored string.
//-----------------------------------------------------------------------
operator CString() const
{
return CString(m_pcszString ? m_pcszString : _T(""));
}
protected:
//-----------------------------------------------------------------------
// Summary:
// This method is used to allocate string data buffer.
// Parameters:
// nNewStrLen - [in] New string length without null character.
//-----------------------------------------------------------------------
virtual void _AllocStringData(int nNewStrLen)
{
ASSERT(m_pcszString == NULL);
m_nStrLen = nNewStrLen;
m_pcszString = (LPTSTR)TAllocator::Alloc_mem((nNewStrLen + 1) * sizeof(TCHAR));
}
//-----------------------------------------------------------------------
// Summary:
// This method is used to free string data buffer previously allocated
// in _AllocStringData.
//-----------------------------------------------------------------------
virtual void _FreeStringData()
{
if (m_pcszString)
TAllocator::Free_mem(m_pcszString);
m_pcszString = NULL;
m_nStrLen = 0;
}
};
/////////////////////////////////////////////////////////////////////////////
//{{AFX_CODEJOCK_PRIVATE
struct XTP_BATCHALLOC_OBJ_HEADER;
struct XTP_BATCHALLOC_BLOCK_HEADER
{
LONG m_dwRefs;
#ifdef _DEBUG
DWORD m_dwObjCount;
DWORD m_dwObjSize; // for debug
#endif
XTP_BATCHALLOC_OBJ_HEADER* pFreeList;
XTP_BATCHALLOC_BLOCK_HEADER* pPrev;
XTP_BATCHALLOC_BLOCK_HEADER* pNext;
};
struct XTP_BATCHALLOC_OBJ_HEADER
{
XTP_BATCHALLOC_BLOCK_HEADER* pBlockHeader;
XTP_BATCHALLOC_OBJ_HEADER* pNextFree;
void* GetData()
{
BYTE* pData = (BYTE*)this;
pData += sizeof(XTP_BATCHALLOC_OBJ_HEADER);
return pData;
}
static XTP_BATCHALLOC_OBJ_HEADER* GetHeader(void* pData)
{
BYTE* pBlockData = (BYTE*)pData;
pBlockData -= sizeof(XTP_BATCHALLOC_OBJ_HEADER);
return (XTP_BATCHALLOC_OBJ_HEADER*)pBlockData;
}
};
template<class _TAllocator, class _TBatchAllocData>
class CXTPBatchAllocManagerT : public _TBatchAllocData
{
public:
//{{ AFX_CODEJOCK_PRIVATE
typedef _TBatchAllocData TBatchAllocData;
typedef _TAllocator TAllocator;
//}} AFX_CODEJOCK_PRIVATE
virtual ~CXTPBatchAllocManagerT()
{
// all data must be deallocated before
ASSERT(m_pBusyBlocks == NULL);
FreeExtraData();
ASSERT(m_pFreeBlocks == NULL);
// This static object destructor may be called later than allocator destructor.
if (TAllocator::ms_dwRefs == 0)
TAllocator::ClearHeap();
}
AFX_INLINE static int AFX_CDECL _Round4(int nSize)
{
int nDiv = nSize / 4;
int nMod = nSize % 4;
int nSizeQ4 = (nDiv + (nMod ? 1 : 0)) * 4;
return nSizeQ4;
}
static void* AFX_CDECL AllocData(size_t nSize)
{
if (!m_pFreeBlocks)
{
int nObjSize = _Round4((int)nSize + sizeof(XTP_BATCHALLOC_OBJ_HEADER));
int nBlockDataSize = sizeof(XTP_BATCHALLOC_BLOCK_HEADER) +
m_nBlockSize * nObjSize;
BYTE* pBlockData = (BYTE*)_TAllocator::Alloc_mem(nBlockDataSize);
if (!pBlockData)
return NULL;
XTP_BATCHALLOC_BLOCK_HEADER* pBlockHdr = (XTP_BATCHALLOC_BLOCK_HEADER*)pBlockData;
ZeroMemory(pBlockHdr, sizeof(XTP_BATCHALLOC_BLOCK_HEADER));
pBlockHdr->m_dwRefs = 0;
#ifdef _DEBUG
pBlockHdr->m_dwObjCount = m_nBlockSize;
pBlockHdr->m_dwObjSize = (DWORD)nSize;
#endif
//---------
m_pFreeBlocks = pBlockHdr;
XTP_BATCHALLOC_OBJ_HEADER* pObjHdr = NULL;
pBlockData = pBlockData + sizeof(XTP_BATCHALLOC_BLOCK_HEADER);
pBlockHdr->pFreeList = (XTP_BATCHALLOC_OBJ_HEADER*)pBlockData;
for (int i = 0; i < m_nBlockSize; i++)
{
pObjHdr = (XTP_BATCHALLOC_OBJ_HEADER*)pBlockData;
//ZeroMemory(pObjHdr, sizeof(XTP_BATCHALLOC_OBJ_HEADER));
pBlockData += nObjSize;
pObjHdr->pBlockHeader = pBlockHdr;
pObjHdr->pNextFree = (XTP_BATCHALLOC_OBJ_HEADER*)pBlockData;
}
if (pObjHdr) pObjHdr->pNextFree = NULL;
}
ASSERT(m_pFreeBlocks && m_pFreeBlocks->pFreeList);
if (!m_pFreeBlocks || !m_pFreeBlocks->pFreeList)
return NULL;
ASSERT(m_pFreeBlocks->m_dwObjSize == (DWORD)nSize);
void* pData = m_pFreeBlocks->pFreeList->GetData();
m_pFreeBlocks->m_dwRefs++;
m_dwAllocatedObjects++;
XTP_BATCHALLOC_OBJ_HEADER* pNextFree = m_pFreeBlocks->pFreeList->pNextFree;
m_pFreeBlocks->pFreeList->pNextFree = NULL;
m_pFreeBlocks->pFreeList = pNextFree;
// no more free objects, move to busy blocks
if (!pNextFree)
{
XTP_BATCHALLOC_BLOCK_HEADER* pNewBusyBlock = m_pFreeBlocks;
m_pFreeBlocks = m_pFreeBlocks->pPrev ? m_pFreeBlocks->pPrev : m_pFreeBlocks->pNext;
if (m_pFreeBlocks)
m_pFreeBlocks->pPrev = pNewBusyBlock->pPrev;
pNewBusyBlock->pNext = m_pBusyBlocks;
pNewBusyBlock->pPrev = m_pBusyBlocks ? m_pBusyBlocks->pPrev : NULL;
if (m_pBusyBlocks)
m_pBusyBlocks->pPrev = pNewBusyBlock;
m_pBusyBlocks = pNewBusyBlock;
}
return pData;
}
static void AFX_CDECL FreeData(void* pObj)
{
if (!pObj)
return;
XTP_BATCHALLOC_OBJ_HEADER* pObjHdr = XTP_BATCHALLOC_OBJ_HEADER::GetHeader(pObj);
pObjHdr->pNextFree = pObjHdr->pBlockHeader->pFreeList;
pObjHdr->pBlockHeader->pFreeList = pObjHdr;
pObjHdr->pBlockHeader->m_dwRefs--;
m_dwAllocatedObjects--;
// was busy block, move to free list
if (pObjHdr->pNextFree == NULL)
{
XTP_BATCHALLOC_BLOCK_HEADER* pNewFreeBlock = pObjHdr->pBlockHeader;
if (pNewFreeBlock->pPrev)
pNewFreeBlock->pPrev->pNext = pNewFreeBlock->pNext;
if (pNewFreeBlock->pNext)
pNewFreeBlock->pNext->pPrev = pNewFreeBlock->pPrev;
if (m_pBusyBlocks == pNewFreeBlock)
m_pBusyBlocks = pNewFreeBlock->pPrev ? pNewFreeBlock->pPrev : pNewFreeBlock->pNext;
pNewFreeBlock->pNext = m_pFreeBlocks;
pNewFreeBlock->pPrev = m_pFreeBlocks ? m_pFreeBlocks->pPrev : NULL;
if (m_pFreeBlocks)
m_pFreeBlocks->pPrev = pNewFreeBlock;
m_pFreeBlocks = pNewFreeBlock;
}
// block is totally free, destroy block
if (pObjHdr->pBlockHeader->m_dwRefs == 0 && m_bDestroyEmptyBlocksOnFree)
{
XTP_BATCHALLOC_BLOCK_HEADER* pEmptyBlock = pObjHdr->pBlockHeader;
XTP_BATCHALLOC_BLOCK_HEADER* pIsNextFree = pEmptyBlock->pPrev ? pEmptyBlock->pPrev : pEmptyBlock->pNext;
BOOL bLast = (m_pFreeBlocks == pEmptyBlock) && pIsNextFree;
// do not destroy last free block
if (!bLast || m_bDestroyLastEmptyBlockOnFree)
{
if (pEmptyBlock->pPrev)
pEmptyBlock->pPrev->pNext = pEmptyBlock->pNext;
if (pEmptyBlock->pNext)
pEmptyBlock->pNext->pPrev = pEmptyBlock->pPrev;
if (m_pFreeBlocks == pEmptyBlock)
m_pFreeBlocks = pEmptyBlock->pPrev ? pEmptyBlock->pPrev : pEmptyBlock->pNext;
_TAllocator::Free_mem(pEmptyBlock);
}
}
// if (m_dwAllocatedObjects == 0)
// FreeExtraData();
}
public:
static void AFX_CDECL FreeExtraData()
{
XTP_BATCHALLOC_BLOCK_HEADER* pBlock = m_pFreeBlocks;
while (pBlock && pBlock->pPrev)
{
pBlock = pBlock->pPrev;
}
while (pBlock)
{
// block is totally free, destroy block
if (pBlock->m_dwRefs == 0)
{
XTP_BATCHALLOC_BLOCK_HEADER* pEmptyBlock = pBlock;
if (pEmptyBlock->pPrev)
pEmptyBlock->pPrev->pNext = pEmptyBlock->pNext;
if (pEmptyBlock->pNext)
pEmptyBlock->pNext->pPrev = pEmptyBlock->pPrev;
if (m_pFreeBlocks == pEmptyBlock)
m_pFreeBlocks = pEmptyBlock->pPrev ? pEmptyBlock->pPrev : pEmptyBlock->pNext;
pBlock = pBlock->pNext;
TAllocator::Free_mem(pEmptyBlock);
}
else
{
pBlock = pBlock->pNext;
}
}
}
};
//}}AFX_CODEJOCK_PRIVATE
//===========================================================================
// Summary:
// This template class used as a helper class to override new/delete
// operators and use batch allocation inside them.
// Batch allocation means that memory allocated not for one object only,
// but for many objects at one time (for 1024 objects by default).
// Next allocations take memory from this big block. New blocks allocated
// when necessary. This increase performance and reduce heap fragmentation.
// Batch allocation mechanism responsible for allocation/deallocation
// blocks of memory from heap and internally organize free/busy lists of
// memory pieces. When object deleted, its memory stored in free list and
// used for new objects.
// When all memory pieces from block free, it may be deallocated from
// heap automatically (this depends on options in _TBatchAllocData)
// or by FreeExtraData call,
//
// Parameters:
// _TObject - A base class;
// _TAllocator - An allocator class name; by default _TObject::TAllocator is used.
// _TBatchAllocData - This class must contain following static members for allocator:
//
// struct BatchAllocData
// {
// static BOOL m_bEnableBatchAllocation; // Define is Batch Allocation enabled;
// static LONG m_dwAllocatedObjects; // allocated blocks count;
//
// static BOOL m_bDestroyEmptyBlocksOnFree; // if TRUE - completely free blocks will be deallocated on free objects, otherwise they will stay in free list.
// static BOOL m_bDestroyLastEmptyBlockOnFree; // if TRUE - last completely free block will be deallocated on free objects, otherwise it will stay in free list.
//
// static int m_nBlockSize; // Count of objects in block.
// protected:
// static XTP_BATCHALLOC_BLOCK_HEADER* m_pFreeBlocks; // List of blocks which have free pieces.
// static XTP_BATCHALLOC_BLOCK_HEADER* m_pBusyBlocks; // List of blocks which have not free pieces.
// };
//
// Example:
// <code>
//
// // *** Batch data must be declared (and implemented)
// // probably in header (*.h) file:
// XTP_DECLARE_BATCH_ALLOC_OBJ_DATA(CBatchReportRecord_Data);
// class CBatchReportRecord : public CXTPBatchAllocObjT<CXTPReportRecord, CBatchReportRecord_Data>
// {
// // ...
// };
//
// // in implementation (*.cpp) file:
// XTP_IMPLEMENT_BATCH_ALLOC_OBJ_DATA(CBatchReportRecord_Data, CBatchReportRecord, TRUE);
//
// // To enable Batch allocations use second parameter in
// // XTP_IMPLEMENT_BATCH_ALLOC_OBJ_DATA macro or set corresponding flag
// // on initialization, before any allocations:
// //
// CMyCustomHeapAllocator::ms_bUseCustomHeap = TRUE;
//
// //*** How to use:
// CBatchReportRecord* pMyClassObj = new CBatchReportRecord();
//
//</code>
//
// See Also:
// XTP_DECLARE_BATCH_ALLOC_OBJ_DATA, XTP_IMPLEMENT_BATCH_ALLOC_OBJ_DATA,
//===========================================================================
template<class _TObject, class _TBatchAllocData, class _TAllocator = _TObject::TAllocator >
class CXTPBatchAllocObjT : public _TObject
{
public:
//{{AFX_CODEJOCK_PRIVATE
typedef _TObject TObject;
typedef _TBatchAllocData TBatchAllocData;
typedef _TAllocator TAllocator;
typedef CXTPBatchAllocManagerT<_TAllocator, _TBatchAllocData > TBlockMan;
//}}AFX_CODEJOCK_PRIVATE
public:
//-----------------------------------------------------------------------
// Summary:
// This member function check all blocks and deallocate which are
// completely free.
// See Also:
// _TBatchAllocData
//-----------------------------------------------------------------------
static void AFX_CDECL FreeExtraData() {
TBlockMan::FreeExtraData();
}
//-----------------------------------------------------------------------
// Summary:
// Allocate memory block of nSize bytes.
// Returns:
// A pointer to allocated block or NULL.
// See Also:
// operator delete
//-----------------------------------------------------------------------
void* PASCAL operator new(size_t nSize)
{
if (TBlockMan::m_bBatchAllocationEnabled)
return TBlockMan::AllocData(nSize);
else
return _TObject::operator new(nSize);
}
//-----------------------------------------------------------------------
// Summary:
// Free memory block previously allocated by operator new.
// Parameters:
// p - [in] Pointer to a memory block.
// See Also:
// operator new
//-----------------------------------------------------------------------
void PASCAL operator delete(void* p)
{
if (TBlockMan::m_bBatchAllocationEnabled)
TBlockMan::FreeData(p);
else
_TObject::operator delete(p);
}
//{{AFX_CODEJOCK_PRIVATE
//void* PASCAL operator new(size_t, void* p) {return p;} // default is fine as is
#if _MSC_VER >= 1200
void PASCAL operator delete(void* p, void* pPlace)
{
if (TBlockMan::m_bBatchAllocationEnabled)
TBlockMan::FreeData(p);
else
_TObject::operator delete(p, pPlace);
}
#endif
#if defined(_DEBUG) && !defined(_AFX_NO_DEBUG_CRT)
// for file name/line number tracking using DEBUG_NEW
void* PASCAL operator new(size_t nSize, LPCSTR lpszFileName, int nLine)
{
if (TBlockMan::m_bBatchAllocationEnabled)
return operator new(nSize);
else
return _TObject::operator new(nSize, lpszFileName, nLine);
}
#if _MSC_VER >= 1200
void PASCAL operator delete(void *p, LPCSTR lpszFileName, int nLine)
{
if (TBlockMan::m_bBatchAllocationEnabled)
operator delete(p);
else
_TObject::operator delete(p, lpszFileName, nLine);
}
#endif
#endif
//}}AFX_CODEJOCK_PRIVATE
};
//{{AFX_CODEJOCK_PRIVATE
#define XTP_DECLARE_BATCH_ALLOC_OBJ_DATA_(dataClass, EXPORT_PARAMS) \
struct EXPORT_PARAMS dataClass \
{ \
static BOOL m_bBatchAllocationEnabled; \
static LONG m_dwAllocatedObjects; \
static BOOL m_bDestroyEmptyBlocksOnFree; \
static BOOL m_bDestroyLastEmptyBlockOnFree; \
static int m_nBlockSize; \
\
static BOOL AFX_CDECL IsDataEmpty() { return !m_pFreeBlocks && !m_pBusyBlocks; }; \
protected: \
static XTP_BATCHALLOC_BLOCK_HEADER* m_pFreeBlocks; \
static XTP_BATCHALLOC_BLOCK_HEADER* m_pBusyBlocks; \
};
//}}AFX_CODEJOCK_PRIVATE
//===========================================================================
// Summary:
// This macros used to declare Batch allocation data which used with
// CXTPBatchAllocObjT template.
// Parameters:
// dataClass - [in] Name of the Batch allocation data class.
// Remarks:
// Used together with XTP_IMPLEMENT_BATCH_ALLOC_OBJ_DATA macro.
// Example:
// <code>
//
// XTP_DECLARE_BATCH_ALLOC_OBJ_DATA(CBatchReportRecord_Data);
// class CBatchReportRecord : public CXTPBatchAllocObjT<CXTPReportRecord, CBatchReportRecord_Data>
// {
// // ...
// };
//
// // in implementation (*.cpp) file:
// XTP_IMPLEMENT_BATCH_ALLOC_OBJ_DATA(CBatchReportRecord_Data, CBatchReportRecord, TRUE);
//
// </code>
// See Also:
// XTP_IMPLEMENT_HEAP_ALLOCATOR, CXTPHeapAllocatorT, CXTPBatchAllocObjT
//===========================================================================
#define XTP_DECLARE_BATCH_ALLOC_OBJ_DATA(dataClass) XTP_DECLARE_BATCH_ALLOC_OBJ_DATA_(dataClass, XTP_EXPORT_PARAMS_NO)
//===========================================================================
// Summary:
// This macros used to declare Batch allocation data which used with
// CXTPBatchAllocObjT template.
// Parameters:
// dataClass - [in] Name of the Batch allocation data class.
// objClass - [in] Name of the object class for Batch allocation.
// batchAllocEnabled - [in] Set as TRUE to enable Batch allocation by default for this object and FALSE to disable.
// Remarks:
// Used together with XTP_DECLARE_BATCH_ALLOC_OBJ_DATA macro.
// Example:
// <code>
//
// XTP_DECLARE_BATCH_ALLOC_OBJ_DATA(CBatchReportRecord_Data);
// class CBatchReportRecord : public CXTPBatchAllocObjT<CXTPReportRecord, CBatchReportRecord_Data>
// {
// // ...
// };
//
// // in implementation (*.cpp) file:
// XTP_IMPLEMENT_BATCH_ALLOC_OBJ_DATA(CBatchReportRecord_Data, CBatchReportRecord, TRUE);
//
// </code>
// See Also:
// XTP_DECLARE_BATCH_ALLOC_OBJ_DATA, CXTPHeapAllocatorT, CXTPBatchAllocObjT
//===========================================================================
#define XTP_IMPLEMENT_BATCH_ALLOC_OBJ_DATA(dataClass, objClass, batchAllocEnabled) \
BOOL dataClass::m_bBatchAllocationEnabled = batchAllocEnabled; \
LONG dataClass::m_dwAllocatedObjects = 0; \
int dataClass::m_nBlockSize = 1024; \
BOOL dataClass::m_bDestroyEmptyBlocksOnFree = FALSE; \
BOOL dataClass::m_bDestroyLastEmptyBlockOnFree = FALSE; \
XTP_BATCHALLOC_BLOCK_HEADER* dataClass::m_pFreeBlocks = NULL; \
XTP_BATCHALLOC_BLOCK_HEADER* dataClass::m_pBusyBlocks = NULL; \
objClass::TBlockMan gs_##objClass##_BlocksManager;
#endif // !defined(_XTPCUSTOMHEAP_H__)