Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages
blockallocator.h
Go to the documentation of this file.00001 /* 00002 Crystal Space Generic Object Block Allocator 00003 Copyright (C)2005 by Eric sunshine <sunshine@sunshineco.com> 00004 00005 This library is free software; you can redistribute it and/or 00006 modify it under the terms of the GNU Library General Public 00007 License as published by the Free Software Foundation; either 00008 version 2 of the License, or (at your option) any later version. 00009 00010 This library is distributed in the hope that it will be useful, 00011 but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 Library General Public License for more details. 00014 00015 You should have received a copy of the GNU Library General Public 00016 License along with this library; if not, write to the Free 00017 Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00018 */ 00019 #ifndef __CSUTIL_BLOCK_ALLOCATOR_H__ 00020 #define __CSUTIL_BLOCK_ALLOCATOR_H__ 00021 00026 #include "csextern.h" 00027 #include "csutil/array.h" 00028 #include "csutil/bitarray.h" 00029 #include "csutil/sysfunc.h" 00030 00031 // hack: work around problems caused by #defining 'new' 00032 #if defined(CS_EXTENSIVE_MEMDEBUG) || defined(CS_MEMORY_TRACKER) 00033 # undef new 00034 #endif 00035 #include <new> 00036 00037 #ifdef CS_MEMORY_TRACKER 00038 #include "csutil/memdebug.h" 00039 #include <typeinfo> 00040 #endif 00041 00046 class csBlockAllocatorNormalBlockPolicy 00047 { 00048 public: 00052 static inline uint8* AllocBlock (size_t blocksize) 00053 { 00054 return (uint8*)malloc(blocksize); 00055 } 00056 00061 static inline void FreeBlock(uint8* p) 00062 { 00063 free (p); 00064 } 00065 }; 00066 00072 template <size_t A = 1> 00073 class csBlockAllocatorAlignPolicy 00074 { 00075 public: 00079 static inline uint8* AllocBlock(size_t blocksize) 00080 { 00081 return (uint8*)csAlignedMalloc (blocksize, A); 00082 } 00083 00088 static inline void FreeBlock(uint8* p) 00089 { 00090 csAlignedFree (p); 00091 } 00092 }; 00093 00094 #ifdef CS_MEMORY_TRACKER 00095 00100 class csBlockAllocatorMTBlockPolicy 00101 { 00102 public: 00106 static inline uint8* AllocBlock (size_t blocksize) const 00107 { 00108 char buf[255]; 00109 sprintf (buf, "csBlockAllocator<%s>", typeid (T).name()); 00110 int32* ptr = (int32*)malloc (blocksize + sizeof (int32)*2); 00111 *ptr++ = (int32)mtiRegisterAlloc (blocksize, buf); 00112 *ptr++ = blocksize; 00113 return (uint8*)ptr; 00114 } 00115 00120 static inline void FreeBlock(uint8* p) const 00121 { 00122 int32* ptr = ((int32*)p)-2; 00123 mtiRegisterFree ((csMemTrackerInfo*)*ptr, (size_t)ptr[1]); 00124 free (ptr); 00125 } 00126 }; 00127 #endif 00128 00149 #ifdef CS_MEMORY_TRACKER 00150 template <class T, class BlockPolicy = csBlockAllocatorMTBlockPolicy> 00151 #else 00152 template <class T, class BlockPolicy = csBlockAllocatorNormalBlockPolicy> 00153 #endif 00154 class csBlockAllocator 00155 { 00156 protected: // 'protected' allows access by test-suite. 00157 struct FreeNode 00158 { 00159 FreeNode* next; 00160 }; 00161 00162 struct BlockKey 00163 { 00164 uint8 const* addr; 00165 size_t blocksize; 00166 BlockKey(uint8 const* p, size_t n) : addr(p), blocksize(n) {} 00167 }; 00168 00169 csArray<uint8*> blocks; // List of allocated blocks; sorted by address. 00170 size_t size; // Number of elements per block. 00171 size_t elsize; // Element size; >= sizeof(void*). 00172 size_t blocksize; // Size in bytes per block. 00173 FreeNode* freenode; // Head of the chain of free nodes. 00174 bool pedantic; // Warn about nodes not explicitly freed. 00175 bool insideDisposeAll; // Flag to ignore calls to Compact() and 00176 // Free() if they're called recursively 00177 // while disposing the entire allocation set. 00178 // Recursive calls to Alloc() will signal an 00179 // assertion failure. 00180 00187 static int FuzzyCmp(uint8* const& block, BlockKey const& k) 00188 { 00189 return (block + k.blocksize <= k.addr ? -1 : (block > k.addr ? 1 : 0)); 00190 } 00191 00195 size_t FindBlock(void const* m) const 00196 { 00197 return blocks.FindSortedKey( 00198 csArrayCmp<uint8*,BlockKey>(BlockKey((uint8*)m, blocksize), FuzzyCmp)); 00199 } 00200 00206 uint8* AllocBlock() const 00207 { 00208 uint8* block = BlockPolicy::AllocBlock(blocksize); 00209 00210 // Build the free-node chain (all nodes are free in the new block). 00211 FreeNode* nextfree = 0; 00212 uint8* node = block + (size - 1) * elsize; 00213 for ( ; node >= block; node -= elsize) 00214 { 00215 FreeNode* slot = (FreeNode*)node; 00216 slot->next = nextfree; 00217 nextfree = slot; 00218 } 00219 CS_ASSERT((uint8*)nextfree == block); 00220 return block; 00221 } 00222 00226 void FreeBlock(uint8* p) const 00227 { 00228 BlockPolicy::FreeBlock(p); 00229 } 00230 00234 void DestroyObject(T* p, bool warn = false) const 00235 { 00236 p->~T(); 00237 if (warn) 00238 { 00239 #ifdef CS_DEBUG 00240 csPrintfErr("NOTIFY: csBlockAllocator(%p) destroying potentially leaked " 00241 "object at %p.\n", (void*)this, (void*)p); 00242 #endif 00243 } 00244 #ifdef CS_BLOCKALLOC_DEBUG 00245 memset (p, 0xfb, elsize); 00246 #endif 00247 } 00248 00253 csBitArray GetAllocationMap() const 00254 { 00255 csBitArray mask(size * blocks.GetSize()); 00256 mask.FlipAllBits(); 00257 for (FreeNode* p = freenode; p != 0; p = p->next) 00258 { 00259 size_t const n = FindBlock(p); 00260 CS_ASSERT(n != csArrayItemNotFound); 00261 size_t const slot = ((uint8*)p - blocks[n]) / elsize; // Slot in block. 00262 mask.ClearBit(n * size + slot); 00263 } 00264 return mask; 00265 } 00266 00272 void DisposeAll(bool warn_unfreed) 00273 { 00274 insideDisposeAll = true; 00275 csBitArray const mask(GetAllocationMap()); 00276 size_t node = 0; 00277 for (size_t b = 0, bN = blocks.GetSize(); b < bN; b++) 00278 { 00279 for (uint8 *p = blocks[b], *pN = p + blocksize; p < pN; p += elsize) 00280 if (mask.IsBitSet(node++)) 00281 DestroyObject((T*)p, warn_unfreed); 00282 FreeBlock(blocks[b]); 00283 } 00284 blocks.DeleteAll(); 00285 freenode = 0; 00286 insideDisposeAll = false; 00287 } 00288 00289 public: 00311 csBlockAllocator(size_t nelem = 32, bool warn_unfreed = false) : 00312 size(nelem), elsize(sizeof(T)), freenode(0), pedantic(warn_unfreed), 00313 insideDisposeAll(false) 00314 { 00315 if (elsize < sizeof (FreeNode)) 00316 elsize = sizeof (FreeNode); 00317 blocksize = elsize * size; 00318 } 00319 00323 ~csBlockAllocator() 00324 { 00325 DisposeAll(pedantic); 00326 } 00327 00333 void Empty() 00334 { 00335 DisposeAll(false); 00336 } 00337 00342 void Compact() 00343 { 00344 if (insideDisposeAll) return; 00345 00346 bool compacted = false; 00347 csBitArray mask(GetAllocationMap()); 00348 for (size_t b = blocks.GetSize(); b-- > 0; ) 00349 { 00350 size_t const node = b * size; 00351 if (!mask.AreSomeBitsSet(node, size)) 00352 { 00353 FreeBlock(blocks[b]); 00354 blocks.DeleteIndex(b); 00355 mask.Delete(node, size); 00356 compacted = true; 00357 } 00358 } 00359 00360 // If blocks were deleted, then free-node chain broke, so rebuild it. 00361 if (compacted) 00362 { 00363 FreeNode* nextfree = 0; 00364 size_t const bN = blocks.GetSize(); 00365 size_t node = bN * size; 00366 for (size_t b = bN; b-- > 0; ) 00367 { 00368 uint8* const p0 = blocks[b]; 00369 for (uint8* p = p0 + (size - 1) * elsize; p >= p0; p -= elsize) 00370 { 00371 if (!mask.IsBitSet(--node)) 00372 { 00373 FreeNode* slot = (FreeNode*)p; 00374 slot->next = nextfree; 00375 nextfree = slot; 00376 } 00377 } 00378 } 00379 freenode = nextfree; 00380 } 00381 } 00382 00386 T* Alloc() 00387 { 00388 if (insideDisposeAll) 00389 { 00390 csPrintfErr("ERROR: csBlockAllocator(%p) tried to allocate memory while inside DisposeAll()", (void*)this); 00391 CS_ASSERT(false); 00392 } 00393 00394 if (freenode == 0) 00395 { 00396 uint8* p = AllocBlock(); 00397 blocks.InsertSorted(p); 00398 freenode = (FreeNode*)p; 00399 } 00400 void* const node = freenode; 00401 freenode = freenode->next; 00402 return new (node) T; 00403 } 00404 00408 void Free(T* p) 00409 { 00410 if (p != 0 && !insideDisposeAll) 00411 { 00412 CS_ASSERT(FindBlock(p) != csArrayItemNotFound); 00413 DestroyObject(p, false); 00414 FreeNode* f = (FreeNode*)p; 00415 f->next = freenode; 00416 freenode = f; 00417 } 00418 } 00420 size_t GetBlockElements() const { return size; } 00421 }; 00422 00423 #if defined(CS_EXTENSIVE_MEMDEBUG) || defined(CS_MEMORY_TRACKER) 00424 # define new CS_EXTENSIVE_MEMDEBUG_NEW 00425 #endif 00426 00427 #endif // __CSUTIL_BLOCK_ALLOCATOR_H__
Generated for Crystal Space by doxygen 1.4.4