// 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 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 {}; //}}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: // // // // probably in header (*.h) file: // XTP_DECLARE_HEAP_ALLOCATOR(CXTPReportRowAllocator) // // // in implementation (*.cpp) file: // XTP_IMPLEMENT_HEAP_ALLOCATOR(CXTPReportRowAllocator) // // // 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: // // // // probably in header (*.h) file: // XTP_DECLARE_HEAP_ALLOCATOR(CXTPReportRowAllocator) // // // in implementation (*.cpp) file: // XTP_IMPLEMENT_HEAP_ALLOCATOR(CXTPReportRowAllocator) // // // 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: // // // // *** 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 // { // // ... // }; // CMyClass* pMyClassObj = new CMyClass(); // // // //*** Other way to use: // class CMyClass : public CMyClassBase // { // // ... // }; // // class CMyClass_heap : public CXTPHeapObjectT // { // }; // CMyClass* pMyClassObj = new CMyClass_heap(); // // // See Also: // XTP_DECLARE_HEAP_ALLOCATOR, XTP_IMPLEMENT_HEAP_ALLOCATOR, //=========================================================================== template 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 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 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: // // // // *** Batch data must be declared (and implemented) // // probably in header (*.h) file: // XTP_DECLARE_BATCH_ALLOC_OBJ_DATA(CBatchReportRecord_Data); // class CBatchReportRecord : public CXTPBatchAllocObjT // { // // ... // }; // // // 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(); // // // // See Also: // XTP_DECLARE_BATCH_ALLOC_OBJ_DATA, XTP_IMPLEMENT_BATCH_ALLOC_OBJ_DATA, //=========================================================================== template 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: // // // XTP_DECLARE_BATCH_ALLOC_OBJ_DATA(CBatchReportRecord_Data); // class CBatchReportRecord : public CXTPBatchAllocObjT // { // // ... // }; // // // in implementation (*.cpp) file: // XTP_IMPLEMENT_BATCH_ALLOC_OBJ_DATA(CBatchReportRecord_Data, CBatchReportRecord, TRUE); // // // 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: // // // XTP_DECLARE_BATCH_ALLOC_OBJ_DATA(CBatchReportRecord_Data); // class CBatchReportRecord : public CXTPBatchAllocObjT // { // // ... // }; // // // in implementation (*.cpp) file: // XTP_IMPLEMENT_BATCH_ALLOC_OBJ_DATA(CBatchReportRecord_Data, CBatchReportRecord, TRUE); // // // 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__)