git-svn-id: https://free-cad.svn.sourceforge.net/svnroot/free-cad/trunk@5000 e8eeb9e2-ec13-0410-a4a9-efa5cf37419d
335 lines
11 KiB
C++
335 lines
11 KiB
C++
// Wild Magic Source Code
|
|
// David Eberly
|
|
// http://www.geometrictools.com
|
|
// Copyright (c) 1998-2007
|
|
//
|
|
// This library is free software; you can redistribute it and/or modify it
|
|
// under the terms of the GNU Lesser General Public License as published by
|
|
// the Free Software Foundation; either version 2.1 of the License, or (at
|
|
// your option) any later version. The license is available for reading at
|
|
// either of the locations:
|
|
// http://www.gnu.org/copyleft/lgpl.html
|
|
// http://www.geometrictools.com/License/WildMagicLicense.pdf
|
|
// The license applies to versions 0 through 4 of Wild Magic.
|
|
//
|
|
// Version: 4.0.0 (2006/06/28)
|
|
|
|
#include "Wm4FoundationPCH.h"
|
|
|
|
#ifdef WM4_MEMORY_MANAGER
|
|
|
|
// Enable this #define if you want to trap mismatches of new/delete[] or
|
|
// new[]/delete. Xcode 2.3 has mismatches of this form in its STL. For
|
|
// example, Program::Load creates a std::ifstream called kIStr. At the end
|
|
// of that function call, kIStr.close() triggers an assert in the function
|
|
// Memory::Deallocate because pkBlock->IsArray is 'false' but 'bIsArray' is
|
|
// true. This implies a mismatch of new/delete[].
|
|
//#define WM4_ENABLE_NEW_DELETE_MISMATCH_ASSERT
|
|
|
|
// Enable this #define the consistency checks in Memory::GenerateReport.
|
|
// Xcode 2.3 triggers the last assert in this function. It appears that
|
|
// Xcode's standard libraries have lots of leaks.
|
|
//#define WM4_ENABLE_CONSISTENCY_CHECK
|
|
|
|
#include <cassert>
|
|
#include <cstdlib>
|
|
#include <fstream>
|
|
#include "Wm4Memory.h"
|
|
using namespace Wm4;
|
|
|
|
size_t Memory::ms_uiNumNewCalls = 0;
|
|
size_t Memory::ms_uiNumDeleteCalls = 0;
|
|
size_t Memory::ms_uiMaxAllowedBytes = 0;
|
|
size_t Memory::ms_uiNumBlocks = 0;
|
|
size_t Memory::ms_uiNumBytes = 0;
|
|
Memory::Block* Memory::ms_pkHead = 0;
|
|
Memory::Block* Memory::ms_pkTail = 0;
|
|
bool Memory::ms_bTrackSizes = false;
|
|
size_t Memory::ms_uiMaxAllocatedBytes = 0;
|
|
size_t Memory::ms_uiMaxBlockSize = 0;
|
|
size_t Memory::ms_auiHistogram[32] =
|
|
{
|
|
0,0,0,0,0,0,0,0,
|
|
0,0,0,0,0,0,0,0,
|
|
0,0,0,0,0,0,0,0,
|
|
0,0,0,0,0,0,0,0
|
|
};
|
|
|
|
//----------------------------------------------------------------------------
|
|
void* Memory::Allocate (size_t uiSize, char* acFile, unsigned int uiLine,
|
|
bool bIsArray)
|
|
{
|
|
ms_uiNumNewCalls++;
|
|
|
|
// The 'assert' used to be enabled to trap attempts to allocate zero
|
|
// bytes. However, the DirectX function D3DXCheckNewDelete may pass in
|
|
// a value of zero.
|
|
// assert(uiSize > 0);
|
|
|
|
// Allocate additional storage for the block header information.
|
|
size_t uiExtendedSize = sizeof(Block) + uiSize;
|
|
char* pcAddr = (char*)malloc(uiExtendedSize);
|
|
|
|
// Save the allocation information.
|
|
Block* pkBlock = (Block*)pcAddr;
|
|
pkBlock->Size = uiSize;
|
|
pkBlock->File = acFile;
|
|
pkBlock->Line = uiLine;
|
|
pkBlock->IsArray = bIsArray;
|
|
InsertBlock(pkBlock);
|
|
|
|
// Move the pointer to the start of what the user expects from 'new'.
|
|
pcAddr += sizeof(Block);
|
|
|
|
// Keep track of number of allocated blocks and bytes.
|
|
ms_uiNumBlocks++;
|
|
ms_uiNumBytes += uiSize;
|
|
|
|
if (ms_uiMaxAllowedBytes > 0 && ms_uiNumBytes > ms_uiMaxAllowedBytes)
|
|
{
|
|
// The allocation has exceeded the maximum number of bytes.
|
|
assert(false);
|
|
}
|
|
|
|
// Keep track of the maximum number of bytes allocated.
|
|
if (ms_uiNumBytes > ms_uiMaxAllocatedBytes)
|
|
{
|
|
ms_uiMaxAllocatedBytes = ms_uiNumBytes;
|
|
}
|
|
|
|
// Keep track of the distribution of sizes for allocations.
|
|
if (ms_bTrackSizes)
|
|
{
|
|
// Keep track of the largest block ever allocated.
|
|
if (uiSize > ms_uiMaxBlockSize)
|
|
{
|
|
ms_uiMaxBlockSize = uiSize;
|
|
}
|
|
|
|
unsigned int uiTwoPowerI = 1;
|
|
int i;
|
|
for (i = 0; i <= 30; i++, uiTwoPowerI <<= 1)
|
|
{
|
|
if (uiSize <= uiTwoPowerI)
|
|
{
|
|
ms_auiHistogram[i]++;
|
|
break;
|
|
}
|
|
}
|
|
if (i == 31)
|
|
{
|
|
ms_auiHistogram[i]++;
|
|
}
|
|
}
|
|
|
|
return (void*)pcAddr;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void Memory::Deallocate (char* pcAddr, bool bIsArray)
|
|
{
|
|
ms_uiNumDeleteCalls++;
|
|
|
|
if (!pcAddr)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Move the pointer to the start of the actual allocated block.
|
|
pcAddr -= sizeof(Block);
|
|
|
|
// Get the allocation information and remove the block. The removal
|
|
// only modifies the Prev and Next pointers, so the block information is
|
|
// accessible after the call.
|
|
Block* pkBlock = (Block*)pcAddr;
|
|
RemoveBlock(pkBlock);
|
|
|
|
#ifdef WM4_ENABLE_NEW_DELETE_MISMATCH_ASSERT
|
|
// Check for correct pairing of new/delete or new[]/delete[].
|
|
assert(pkBlock->IsArray == bIsArray);
|
|
#endif
|
|
|
|
// Keep track of number of allocated blocks and bytes. If the number of
|
|
// blocks is zero at this time, a delete has been called twice on the
|
|
// same pointer. If the number of bytes is too small at this time, some
|
|
// internal problem has occurred within this class and needs to be
|
|
// diagnosed.
|
|
assert(ms_uiNumBlocks > 0 && ms_uiNumBytes >= pkBlock->Size);
|
|
ms_uiNumBlocks--;
|
|
ms_uiNumBytes -= pkBlock->Size;
|
|
|
|
// Deallocate the memory block.
|
|
free(pcAddr);
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void Memory::InsertBlock (Block* pkBlock)
|
|
{
|
|
// New blocks are inserted at the tail of the doubly linked list.
|
|
if (ms_pkTail)
|
|
{
|
|
pkBlock->Prev = ms_pkTail;
|
|
pkBlock->Next = 0;
|
|
ms_pkTail->Next = pkBlock;
|
|
ms_pkTail = pkBlock;
|
|
}
|
|
else
|
|
{
|
|
pkBlock->Prev = 0;
|
|
pkBlock->Next = 0;
|
|
ms_pkHead = pkBlock;
|
|
ms_pkTail = pkBlock;
|
|
}
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void Memory::RemoveBlock (Block* pkBlock)
|
|
{
|
|
if (pkBlock->Prev)
|
|
{
|
|
pkBlock->Prev->Next = pkBlock->Next;
|
|
}
|
|
else
|
|
{
|
|
ms_pkHead = pkBlock->Next;
|
|
}
|
|
|
|
if (pkBlock->Next)
|
|
{
|
|
pkBlock->Next->Prev = pkBlock->Prev;
|
|
}
|
|
else
|
|
{
|
|
ms_pkTail = pkBlock->Prev;
|
|
}
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void Memory::GenerateReport (const char* acFilename)
|
|
{
|
|
std::ofstream kOStr(acFilename);
|
|
assert(kOStr);
|
|
if (!kOStr)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Total calls.
|
|
kOStr << "Total number of 'new' calls = "
|
|
<< (unsigned int)ms_uiNumNewCalls << std::endl;
|
|
kOStr << "Total number of 'delete' calls = "
|
|
<< (unsigned int)ms_uiNumDeleteCalls << std::endl;
|
|
kOStr << "Maximum number of allocated bytes = "
|
|
<< (unsigned int)ms_uiMaxAllocatedBytes << std::endl << std::endl;
|
|
|
|
// Remaining counts.
|
|
kOStr << "Remaining number of blocks = "
|
|
<< (unsigned int)ms_uiNumBlocks << std::endl;
|
|
kOStr << "Remaining number of bytes = "
|
|
<< (unsigned int)ms_uiNumBytes << std::endl << std::endl;
|
|
|
|
// Count the blocks and bytes from known and unknown sources.
|
|
size_t uiNumKnownBlocks = 0;
|
|
size_t uiNumKnownBytes = 0;
|
|
size_t uiNumUnknownBlocks = 0;
|
|
size_t uiNumUnknownBytes = 0;
|
|
Block* pkBlock = ms_pkHead;
|
|
while (pkBlock)
|
|
{
|
|
if (pkBlock->File)
|
|
{
|
|
uiNumKnownBlocks++;
|
|
uiNumKnownBytes += pkBlock->Size;
|
|
}
|
|
else
|
|
{
|
|
uiNumUnknownBlocks++;
|
|
uiNumUnknownBytes += pkBlock->Size;
|
|
}
|
|
pkBlock = pkBlock->Next;
|
|
}
|
|
|
|
#ifdef WM4_ENABLE_CONSISTENCY_CHECK
|
|
// consistency check
|
|
assert(uiNumKnownBlocks + uiNumUnknownBlocks == ms_uiNumBlocks);
|
|
assert(uiNumKnownBytes + uiNumUnknownBytes == ms_uiNumBytes);
|
|
#endif
|
|
|
|
kOStr << "Remaining number of known blocks = "
|
|
<< (unsigned int)uiNumKnownBlocks << std::endl;
|
|
kOStr << "Remaining number of known bytes = "
|
|
<< (unsigned int)uiNumKnownBytes << std::endl << std::endl;
|
|
|
|
kOStr << "Remaining number of unknown blocks = "
|
|
<< (unsigned int)uiNumUnknownBlocks << std::endl;
|
|
kOStr << "Remaining number of unknown bytes = "
|
|
<< (unsigned int)uiNumUnknownBytes << std::endl << std::endl;
|
|
|
|
// Report the information for each block.
|
|
pkBlock = ms_pkHead;
|
|
size_t uiIndex = 0;
|
|
while (pkBlock)
|
|
{
|
|
kOStr << "block = " << (unsigned int)uiIndex << std::endl;
|
|
kOStr << "size = " << (unsigned int)pkBlock->Size << std::endl;
|
|
if (pkBlock->File)
|
|
{
|
|
kOStr << "file = " << pkBlock->File << std::endl;
|
|
kOStr << "line = " << pkBlock->Line << std::endl;
|
|
}
|
|
else
|
|
{
|
|
kOStr << "file = unknown" << std::endl;
|
|
kOStr << "line = unknown" << std::endl;
|
|
}
|
|
kOStr << "array = " << pkBlock->IsArray << std::endl << std::endl;
|
|
pkBlock = pkBlock->Next;
|
|
uiIndex++;
|
|
}
|
|
kOStr.close();
|
|
|
|
#ifdef WM4_ENABLE_CONSISTENCY_CHECK
|
|
// consistency check
|
|
assert(uiIndex == ms_uiNumBlocks);
|
|
#endif
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void* operator new (size_t uiSize)
|
|
{
|
|
return Memory::Allocate(uiSize,0,0,false);
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void* operator new[](size_t uiSize)
|
|
{
|
|
return Memory::Allocate(uiSize,0,0,true);
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void* operator new (size_t uiSize, char* acFile, unsigned int uiLine)
|
|
{
|
|
return Memory::Allocate(uiSize,acFile,uiLine,false);
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void* operator new[] (size_t uiSize, char* acFile, unsigned int uiLine)
|
|
{
|
|
return Memory::Allocate(uiSize,acFile,uiLine,true);
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void operator delete (void* pvAddr)
|
|
{
|
|
Memory::Deallocate((char*)pvAddr,false);
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void operator delete[] (void* pvAddr)
|
|
{
|
|
Memory::Deallocate((char*)pvAddr,true);
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void operator delete (void* pvAddr, char*, unsigned int)
|
|
{
|
|
Memory::Deallocate((char*)pvAddr,false);
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void operator delete[] (void* pvAddr, char*, unsigned int)
|
|
{
|
|
Memory::Deallocate((char*)pvAddr,true);
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
|
|
#endif
|