00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #pragma once
00013
00015 #include "nvsgcommon.h"
00016
00017
00018
00019
00020
00021
00022
00023
00024 #pragma warning(disable:4291)
00025
00026 #include <algorithm>
00027 #include <vector>
00028 #if defined( ALLOCATION_COUNTER )
00029 #include <map>
00030 #endif
00031 #include "nvutil/Singleton.h"
00032 #include "nvutil/Trace.h"
00033
00034 namespace nvutil
00035 {
00037 class Chunk
00038 {
00039 public:
00041 Chunk(size_t blockSize);
00042
00044 bool operator==(const Chunk& rhs) const;
00045 bool operator!=(const Chunk& rhs) const;
00046
00048 void * alloc();
00049 void dealloc(void * p);
00051 void freeMemory();
00052
00054 unsigned char blocksAvailable() const;
00056 bool isUnused() const;
00058 bool isInsideBounds(void * p) const;
00059
00060 private:
00062 enum { numBlocks = 255 };
00063
00065 void init();
00066
00068 void * lowerBound() const;
00069 void * upperBound() const;
00070
00071 unsigned char * m_rawMem;
00072
00074 size_t m_blockSize;
00075 size_t m_chunkSize;
00076
00077 unsigned char m_firstAvailableBlock;
00078 unsigned char m_blocksAvailable;
00079 };
00080
00082 class FixedAllocator
00083 {
00084 public:
00086 FixedAllocator();
00087
00089 ~FixedAllocator();
00090
00092 void * alloc();
00093
00095 void dealloc(void * p);
00096
00098 void init ( size_t blockSize );
00099
00100 private:
00101 size_t m_blockSize;
00102
00103 typedef std::vector< Chunk > Chunks;
00104 Chunks m_chunks;
00105
00106 Chunk * m_lastAlloc;
00107 Chunk * m_lastDealloc;
00108 };
00109
00110
00112
00113 * It manages the efficient allocation of small objects by using an array of \c FixedAllocator objects, one for
00114 * each small size up to \c maxBlockSize. Allocations larger than that size are redirected to the standard
00115 * allocation \c ::new. */
00116 class Allocator
00117 {
00118 public:
00120
00121 Allocator();
00122
00124
00125 ~Allocator();
00126
00128
00129 void * alloc( size_t size
00130 );
00131
00132 #ifdef _DEBUG
00133
00134
00136 void * alloc( size_t size
00137 , const char * src
00138 , unsigned int ln
00139 );
00140 #endif
00141
00143
00145 void dealloc( void * p
00146 , size_t size
00147 );
00148
00149 private:
00151 void * __alloc(size_t size);
00152
00153 private:
00154
00155
00156 enum { maxBlockSize = 256 };
00157
00158
00159 FixedAllocator m_allocTbl[maxBlockSize];
00160
00161
00162 #ifdef _DEBUG
00163 struct DbgAllocInfo
00164 {
00165 void * p;
00166 std::string source;
00167 unsigned int ln;
00168
00169
00170 bool operator==(void * _p) const { return p==_p; }
00171 bool operator!=(void * _p) const { return p!=_p; }
00172 };
00173
00174 std::vector<DbgAllocInfo> m_dbgAllocInfos;
00175
00176
00177 struct LeakWarning
00178 {
00179 void operator()(const DbgAllocInfo& allocInfo) const
00180 {
00181 std::string str;
00182 char cPtr[sizeof(void*)*2+1];
00183 sprintf(cPtr, "%p", allocInfo.p);
00184 char cLine[20];
00185 sprintf(cLine, "%d", allocInfo.ln);
00186
00187 str = "****Memory Leak Detected*** Source: ";
00188 str += allocInfo.source;
00189 str += ", Line: ";
00190 str += cLine;
00191 str += ", Ptr: 0x";
00192 str += cPtr;
00193 str += "\n";
00194 traceDebugOutput()(str.c_str());
00195 }
00196 };
00197 #endif
00198 #if defined( ALLOCATION_COUNTER )
00199 std::map<size_t,size_t> m_allocSizeMap;
00200 #endif
00201 };
00202
00203 inline void * Allocator::alloc(size_t size)
00204 {
00205 __ASSERT(!"WARNING: Bypassing leak detection in debug mode!\n");
00206 return __alloc(size);
00207 }
00208
00209 #ifdef _DEBUG
00210 inline void * Allocator::alloc(size_t size, const char* src, unsigned int ln)
00211 {
00212 DbgAllocInfo allocInfo;
00213
00214 allocInfo.p = __alloc(size);
00215 allocInfo.source = src;
00216 allocInfo.ln = ln;
00217 m_dbgAllocInfos.push_back(allocInfo);
00218 return allocInfo.p;
00219 }
00220 #endif
00221
00222 inline void Allocator::dealloc(void *p, size_t size)
00223 {
00224 #ifdef _DEBUG
00225 m_dbgAllocInfos.erase(std::remove(m_dbgAllocInfos.begin(), m_dbgAllocInfos.end(), p), m_dbgAllocInfos.end());
00226 #endif
00227 if ( size <= maxBlockSize )
00228 {
00229 m_allocTbl[size-1].dealloc(p);
00230 }
00231 else
00232 {
00233 ::operator delete(p);
00234 }
00235 }
00236
00237 inline void * Allocator::__alloc(size_t size)
00238 {
00239 #if defined( ALLOCATION_COUNTER )
00240 m_allocSizeMap[size]++;
00241 #endif
00242
00243 return (size<=maxBlockSize) ? m_allocTbl[size-1].alloc() : ::operator new(size);
00244 }
00245
00246
00248
00254 class IAllocator
00255 {
00256 public:
00258 typedef Singleton<Allocator> theAllocator;
00259
00261
00263 IAllocator() {}
00265 virtual ~IAllocator() {}
00266
00268
00270 NVSG_API void * operator new( size_t size
00271 );
00272 #ifdef _DEBUG
00273
00274
00277 NVSG_API void * operator new( size_t size
00278 , const char * src
00279 , unsigned int ln
00280 );
00281 #endif
00282
00283
00289 NVSG_API void * operator new( size_t size
00290 , void * p
00291 );
00293
00294 NVSG_API void operator delete( void * p
00295 , size_t size
00296 );
00297 };
00298
00299
00300
00301
00302
00303
00309 inline void Chunk::init()
00310 {
00311 m_rawMem = ::new unsigned char[m_chunkSize];
00312
00313 m_firstAvailableBlock = 0;
00314 m_blocksAvailable = numBlocks;
00315
00316 unsigned char * p = m_rawMem;
00317 for ( unsigned char i=0; i!=numBlocks; p+=m_blockSize )
00318 {
00319
00320 *p = ++i;
00321 }
00322 }
00323
00329 inline void Chunk::freeMemory()
00330 {
00331
00332 __ASSERT(isUnused());
00333 ::delete[] m_rawMem;
00334 }
00335
00341 inline void * Chunk::alloc()
00342 {
00343 if ( !m_blocksAvailable )
00344 {
00345
00346 return NULL;
00347 }
00348
00349 unsigned char * p = &m_rawMem[m_firstAvailableBlock*m_blockSize];
00350
00351 m_firstAvailableBlock = *p;
00352
00353 --m_blocksAvailable;
00354
00355 return (void *)p;
00356 }
00357
00363 inline void Chunk::dealloc(void * p)
00364 {
00365 unsigned char * ptr = (unsigned char*)p;
00366
00367
00368 __ASSERT(ptr>=m_rawMem);
00369 __ASSERT(ptr<&m_rawMem[m_chunkSize]);
00370
00371 __ASSERT(!((ptr-m_rawMem)%m_blockSize));
00372
00373 *ptr = m_firstAvailableBlock;
00374 m_firstAvailableBlock = (unsigned char)((ptr - m_rawMem) / m_blockSize);
00375
00376
00377 __ASSERT(m_firstAvailableBlock==((ptr-m_rawMem)/m_blockSize));
00378 ++m_blocksAvailable;
00379 }
00380
00386 inline bool Chunk::operator==(const Chunk& rhs) const
00387 {
00388
00389 #ifdef _DEBUG
00390 if ( m_rawMem==rhs.m_rawMem )
00391 {
00392 __ASSERT( m_blockSize == rhs.m_blockSize
00393 && m_firstAvailableBlock==rhs.m_firstAvailableBlock
00394 && m_blocksAvailable==rhs.m_blocksAvailable );
00395 }
00396 #endif
00397
00398 return ( m_rawMem==rhs.m_rawMem );
00399 }
00400
00406 inline bool Chunk::operator!=(const Chunk& rhs) const
00407 {
00408 return !operator==(rhs);
00409 }
00410
00416 inline unsigned char Chunk::blocksAvailable() const
00417 {
00418 return m_blocksAvailable;
00419 }
00420
00426 inline bool Chunk::isInsideBounds(void * p) const
00427 {
00428 return p>=lowerBound() && p<upperBound();
00429 }
00430
00436 inline bool Chunk::isUnused() const
00437 {
00438 return m_blocksAvailable==numBlocks;
00439 }
00440
00446 inline void * Chunk::lowerBound() const
00447 {
00448 return (void*)m_rawMem;
00449 }
00450
00456 inline void * Chunk::upperBound() const
00457 {
00458 return (void*)&m_rawMem[m_chunkSize];
00459 }
00460
00466 inline void FixedAllocator::init(size_t blockSize)
00467 {
00468 m_blockSize = blockSize;
00469 }
00470
00476 inline void * IAllocator::operator new(size_t size)
00477 {
00478 return theAllocator::instance()->alloc(size);
00479 }
00480
00481 #ifdef _DEBUG
00482
00483 inline void * IAllocator::operator new(size_t size, const char * src, unsigned int ln)
00484 {
00485 return theAllocator::instance()->alloc(size, src, ln);
00486 }
00487 #endif
00488
00494 inline void * IAllocator::operator new(size_t size, void * p)
00495 {
00496
00497
00498
00499 __ASSERT(p);
00500 return p;
00501 }
00502
00508 inline void IAllocator::operator delete(void * p, size_t size)
00509 {
00510 theAllocator::instance()->dealloc(p, size);
00511 }
00512
00513 }
00514