csutil/allocator.h
Go to the documentation of this file.00001 /* 00002 Copyright (C) 2006-2007 by Frank Richter 00003 00004 This library is free software; you can redistribute it and/or 00005 modify it under the terms of the GNU Library General Public 00006 License as published by the Free Software Foundation; either 00007 version 2 of the License, or (at your option) any later version. 00008 00009 This library is distributed in the hope that it will be useful, 00010 but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 Library General Public License for more details. 00013 00014 You should have received a copy of the GNU Library General Public 00015 License along with this library; if not, write to the Free 00016 Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00017 */ 00018 00019 #ifndef __CS_CSUTIL_ALLOCATOR_H__ 00020 #define __CS_CSUTIL_ALLOCATOR_H__ 00021 00026 #include "csutil/alignedalloc.h" 00027 #include "csutil/memdebug.h" 00028 #include "csutil/ref.h" 00029 #include "csutil/threading/mutex.h" 00030 #include "iutil/allocator.h" 00031 00035 namespace CS 00036 { 00037 namespace Memory 00038 { 00079 class AllocatorMalloc 00080 { 00081 #ifdef CS_MEMORY_TRACKER 00083 const char* mti; 00084 #endif 00085 public: 00086 #ifdef CS_MEMORY_TRACKER 00087 AllocatorMalloc() : mti (0) {} 00088 #endif 00090 CS_ATTRIBUTE_MALLOC void* Alloc (const size_t n) 00091 { 00092 #ifdef CS_MEMORY_TRACKER 00093 size_t* p = (size_t*)cs_malloc (n); 00094 if (mti) CS::Debug::MemTracker::RegisterAlloc (p, n, mti); 00095 return p; 00096 #else 00097 return cs_malloc (n); 00098 #endif 00099 } 00101 void Free (void* p) 00102 { 00103 #ifdef CS_MEMORY_TRACKER 00104 CS::Debug::MemTracker::RegisterFree (p); 00105 #endif 00106 cs_free (p); 00107 } 00109 void* Realloc (void* p, size_t newSize) 00110 { 00111 #ifdef CS_MEMORY_TRACKER 00112 if (p == 0) return Alloc (newSize); 00113 size_t* np = (size_t*)cs_realloc (p, newSize); 00114 CS::Debug::MemTracker::UpdateSize (p, np, newSize); 00115 return np; 00116 #else 00117 return cs_realloc (p, newSize); 00118 #endif 00119 } 00121 void SetMemTrackerInfo (const char* info) 00122 { 00123 #ifdef CS_MEMORY_TRACKER 00124 mti = info; 00125 #else 00126 (void)info; 00127 #endif 00128 } 00129 }; 00130 00150 template<typename T, size_t N, class ExcessAllocator = AllocatorMalloc, 00151 bool SingleAllocation = false> 00152 class LocalBufferAllocator : public ExcessAllocator 00153 { 00154 #ifdef CS_DEBUG 00155 void* startThis; 00156 #endif 00157 static const size_t localSize = N * sizeof (T); 00158 static const uint8 freePattern = 0xfa; 00159 static const uint8 newlyAllocatedSalt = 0xac; 00160 uint8 localBuf[localSize + (SingleAllocation ? 0 : 1)]; 00161 public: 00162 LocalBufferAllocator () 00163 { 00164 if (SingleAllocation) 00165 { 00166 #ifdef CS_DEBUG 00167 memset (localBuf, freePattern, localSize); 00168 #endif 00169 } 00170 else 00171 localBuf[localSize] = 0; 00172 #ifdef CS_DEBUG 00173 startThis = this; 00174 #endif 00175 } 00176 LocalBufferAllocator (const ExcessAllocator& xalloc) : 00177 ExcessAllocator (xalloc) 00178 { 00179 if (SingleAllocation) 00180 { 00181 #ifdef CS_DEBUG 00182 memset (localBuf, freePattern, localSize); 00183 #endif 00184 } 00185 else 00186 localBuf[localSize] = 0; 00187 #ifdef CS_DEBUG 00188 startThis = this; 00189 #endif 00190 } 00191 void* Alloc (size_t allocSize) 00192 { 00193 CS_ASSERT(startThis == this); 00194 if (SingleAllocation) 00195 { 00196 #ifdef CS_DEBUG 00197 /* Verify that the local buffer consists entirely of the "local 00198 buffer unallocated" pattern. (Not 100% safe since a valid 00199 allocated buffer may be coincidentally filled with just that 00200 pattern, but let's just assume that it's unlikely.) */ 00201 bool validPattern = true; 00202 for (size_t n = 0; n < localSize; n++) 00203 { 00204 if (localBuf[n] != freePattern) 00205 { 00206 validPattern = false; 00207 break; 00208 } 00209 } 00210 CS_ASSERT_MSG("This LocalBufferAllocator only allows one allocation " 00211 "a time!", validPattern); 00212 memset (localBuf, newlyAllocatedSalt, localSize); 00213 #endif 00214 if (allocSize <= localSize) 00215 return (void*)localBuf; 00216 else 00217 { 00218 void* p = ExcessAllocator::Alloc (allocSize); 00219 return p; 00220 } 00221 } 00222 else 00223 { 00224 void* p; 00225 if ((allocSize <= localSize) && !localBuf[localSize]) 00226 { 00227 localBuf[localSize] = 1; 00228 p = localBuf; 00229 #ifdef CS_DEBUG 00230 memset (p, newlyAllocatedSalt, allocSize); 00231 #endif 00232 } 00233 else 00234 { 00235 p = ExcessAllocator::Alloc (allocSize); 00236 } 00237 return (T*)p; 00238 } 00239 } 00240 00241 void Free (void* mem) 00242 { 00243 CS_ASSERT(startThis == this); 00244 if (SingleAllocation) 00245 { 00246 if (mem != (void*)localBuf) 00247 ExcessAllocator::Free (mem); 00248 else 00249 { 00250 #ifdef CS_DEBUG 00251 /* Verify that the local buffer does entirely consist of the "local 00252 buffer unallocated" pattern. (Not 100% safe since a valid 00253 allocated buffer may be coincidentally filled with just that 00254 pattern, but let's just assume that it's unlikely.) */ 00255 bool validPattern = true; 00256 for (size_t n = 0; n < localSize; n++) 00257 { 00258 if (localBuf[n] != freePattern) 00259 { 00260 validPattern = false; 00261 break; 00262 } 00263 } 00264 CS_ASSERT_MSG("Free() without prior allocation", !validPattern); 00265 #endif 00266 } 00267 #ifdef CS_DEBUG 00268 memset (localBuf, freePattern, localSize); 00269 #endif 00270 } 00271 else 00272 { 00273 if (mem != (void*)localBuf) 00274 ExcessAllocator::Free (mem); 00275 else 00276 { 00277 localBuf[localSize] = 0; 00278 } 00279 } 00280 } 00281 00282 // The 'relevantcount' parameter should be the number of items 00283 // in the old array that are initialized. 00284 void* Realloc (void* p, size_t newSize) 00285 { 00286 CS_ASSERT(startThis == this); 00287 if (p == 0) return Alloc (newSize); 00288 if (p == localBuf) 00289 { 00290 if (newSize <= localSize) 00291 return p; 00292 else 00293 { 00294 p = ExcessAllocator::Alloc (newSize); 00295 memcpy (p, localBuf, localSize); 00296 #ifdef CS_DEBUG 00297 memset (localBuf, freePattern, localSize); 00298 #endif 00299 if (!SingleAllocation) localBuf[localSize] = 0; 00300 return p; 00301 } 00302 } 00303 else 00304 { 00305 if ((newSize <= localSize) && (SingleAllocation || !localBuf[localSize])) 00306 { 00307 memcpy (localBuf, p, newSize); 00308 ExcessAllocator::Free (p); 00309 if (!SingleAllocation) localBuf[localSize] = 1; 00310 return localBuf; 00311 } 00312 else 00313 return ExcessAllocator::Realloc (p, newSize); 00314 } 00315 } 00316 00317 using ExcessAllocator::SetMemTrackerInfo; 00318 }; 00319 00330 template<typename T, size_t N, class ExcessAllocator = AllocatorMalloc, 00331 bool SingleAllocation = false> 00332 class LocalBufferAllocatorUnchecked : public ExcessAllocator 00333 { 00334 static const size_t localSize = N * sizeof (T); 00335 uint8 localBuf[localSize + (SingleAllocation ? 0 : 1)]; 00336 public: 00337 LocalBufferAllocatorUnchecked () 00338 { 00339 if (!SingleAllocation) 00340 localBuf[localSize] = 0; 00341 } 00342 LocalBufferAllocatorUnchecked (const ExcessAllocator& xalloc) : 00343 ExcessAllocator (xalloc) 00344 { 00345 if (!SingleAllocation) 00346 localBuf[localSize] = 0; 00347 } 00348 T* Alloc (size_t allocSize) 00349 { 00350 if (SingleAllocation) 00351 { 00352 if (allocSize <= localSize) 00353 return (T*)localBuf; 00354 else 00355 { 00356 void* p = ExcessAllocator::Alloc (allocSize); 00357 return (T*)p; 00358 } 00359 } 00360 else 00361 { 00362 void* p; 00363 if ((allocSize <= localSize) && !localBuf[localSize]) 00364 { 00365 localBuf[localSize] = 1; 00366 p = localBuf; 00367 } 00368 else 00369 { 00370 p = ExcessAllocator::Alloc (allocSize); 00371 } 00372 return (T*)p; 00373 } 00374 } 00375 00376 void Free (T* mem) 00377 { 00378 if (SingleAllocation) 00379 { 00380 if (mem != (T*)localBuf) 00381 ExcessAllocator::Free (mem); 00382 } 00383 else 00384 { 00385 if (mem != (T*)localBuf) 00386 ExcessAllocator::Free (mem); 00387 else 00388 { 00389 localBuf[localSize] = 0; 00390 } 00391 } 00392 } 00393 00394 // The 'relevantcount' parameter should be the number of items 00395 // in the old array that are initialized. 00396 void* Realloc (void* p, size_t newSize) 00397 { 00398 if (p == 0) return Alloc (newSize); 00399 if (p == localBuf) 00400 { 00401 if (newSize <= localSize) 00402 return p; 00403 else 00404 { 00405 p = ExcessAllocator::Alloc (newSize); 00406 memcpy (p, localBuf, localSize); 00407 if (!SingleAllocation) localBuf[localSize] = 0; 00408 return p; 00409 } 00410 } 00411 else 00412 { 00413 if ((newSize <= localSize) && (SingleAllocation || !localBuf[localSize])) 00414 { 00415 memcpy (localBuf, p, newSize); 00416 ExcessAllocator::Free (p); 00417 if (!SingleAllocation) localBuf[localSize] = 1; 00418 return localBuf; 00419 } 00420 else 00421 return ExcessAllocator::Realloc (p, newSize); 00422 } 00423 } 00424 00425 using ExcessAllocator::SetMemTrackerInfo; 00426 }; 00427 00433 template <size_t A = 1> 00434 class AllocatorAlign 00435 { 00436 public: 00440 static inline CS_ATTRIBUTE_MALLOC void* Alloc (size_t size) 00441 { 00442 return AlignedMalloc (size, A); 00443 } 00444 00449 static inline void Free (void* p) 00450 { 00451 AlignedFree (p); 00452 } 00453 00454 void* Realloc (void* p, size_t newSize) 00455 { 00456 return AlignedRealloc (p, newSize, A); 00457 } 00458 00459 void SetMemTrackerInfo (const char* info) 00460 { 00461 (void)info; 00462 } 00463 }; 00464 00470 template<bool Reallocatable = true> 00471 class AllocatorNewChar 00472 { 00473 #ifdef CS_MEMORY_TRACKER 00475 const char* mti; 00476 #endif 00477 public: 00478 #ifdef CS_MEMORY_TRACKER 00479 AllocatorNewChar() : mti (0) {} 00480 #endif 00482 CS_ATTRIBUTE_MALLOC void* Alloc (const size_t n) 00483 { 00484 if (!Reallocatable) 00485 { 00486 char* p = new char[n]; 00487 #ifdef CS_MEMORY_TRACKER 00488 if (mti) CS::Debug::MemTracker::RegisterAlloc (p, n, mti); 00489 #endif 00490 return p; 00491 } 00492 size_t* p = (size_t*)new char[n + sizeof (size_t)]; 00493 *p = n; 00494 p++; 00495 #ifdef CS_MEMORY_TRACKER 00496 if (mti) CS::Debug::MemTracker::RegisterAlloc (p, n, mti); 00497 #endif 00498 return p; 00499 } 00501 void Free (void* p) 00502 { 00503 #ifdef CS_MEMORY_TRACKER 00504 CS::Debug::MemTracker::RegisterFree (p); 00505 #endif 00506 if (!Reallocatable) 00507 { 00508 delete[] (char*)p; 00509 return; 00510 } 00511 size_t* x = (size_t*)p; 00512 x--; 00513 delete[] (char*)x; 00514 } 00516 void* Realloc (void* p, size_t newSize) 00517 { 00518 if (!Reallocatable) return 0; 00519 00520 if (p == 0) return Alloc (newSize); 00521 size_t* x = (size_t*)p; 00522 x--; 00523 size_t oldSize = *x; 00524 size_t* np = (size_t*)Alloc (newSize); 00525 if (newSize < oldSize) 00526 memcpy (np, p, newSize); 00527 else 00528 memcpy (np, p, oldSize); 00529 Free (p); 00530 #ifdef CS_MEMORY_TRACKER 00531 if (mti) CS::Debug::MemTracker::UpdateSize (p, np, newSize); 00532 #endif 00533 return np; 00534 } 00536 void SetMemTrackerInfo (const char* info) 00537 { 00538 #ifdef CS_MEMORY_TRACKER 00539 if (!Reallocatable) return; 00540 mti = info; 00541 #else 00542 (void)info; 00543 #endif 00544 } 00545 }; 00546 00557 template<typename T> 00558 class AllocatorNew 00559 { 00560 public: 00562 CS_ATTRIBUTE_MALLOC void* Alloc (const size_t n) 00563 { 00564 return new T[((n + sizeof(T) - 1) / sizeof(T)) * sizeof(T)]; 00565 } 00567 void Free (void* p) 00568 { 00569 delete[] (T*)p; 00570 } 00572 void* Realloc (void* p, size_t newSize) 00573 { 00574 CS_ASSERT_MSG("Realloc() called on AllocatorNew", false); 00575 return 0; 00576 } 00578 void SetMemTrackerInfo (const char* /*info*/) 00579 { 00580 } 00581 }; 00582 00583 00589 template<typename T, typename Allocator> 00590 struct AllocatorPointerWrapper : public Allocator 00591 { 00593 T* p; 00594 00595 AllocatorPointerWrapper () {} 00596 AllocatorPointerWrapper (const Allocator& alloc) : 00597 Allocator (alloc) {} 00598 AllocatorPointerWrapper (T* p) : p (p) {} 00599 AllocatorPointerWrapper (const Allocator& alloc, T* p) : 00600 Allocator (alloc), p (p) {} 00601 }; 00602 00607 class AllocatorMallocPlatform 00608 { 00609 public: 00611 CS_ATTRIBUTE_MALLOC void* Alloc (const size_t n) 00612 { 00613 return malloc (n); 00614 } 00616 void Free (void* p) 00617 { 00618 free (p); 00619 } 00621 void* Realloc (void* p, size_t newSize) 00622 { 00623 return realloc (p, newSize); 00624 } 00626 void SetMemTrackerInfo (const char* info) 00627 { 00628 (void)info; 00629 } 00630 }; 00631 00635 template<typename OtherAllocator> 00636 class AllocatorRef 00637 { 00638 OtherAllocator& alloc; 00639 public: 00640 AllocatorRef (OtherAllocator& referencedAlloc) 00641 : alloc (referencedAlloc) {} 00642 00644 CS_ATTRIBUTE_MALLOC void* Alloc (const size_t n) 00645 { return alloc.Alloc (n); } 00647 void Free (void* p) { alloc.Free (p); } 00649 void* Realloc (void* p, size_t newSize) 00650 { return alloc.Realloc (p, newSize); } 00652 void SetMemTrackerInfo (const char* info) 00653 { alloc.SetMemTrackerInfo (info); } 00654 }; 00655 00659 template <class Allocator> 00660 class AllocatorSafe : protected Allocator 00661 { 00662 protected: 00663 typedef Allocator WrappedAllocatorType; 00664 typedef AllocatorSafe<Allocator> AllocatorSafeType; 00666 CS::Threading::RecursiveMutex mutex; 00667 00668 public: 00669 AllocatorSafe () : Allocator () 00670 { 00671 } 00672 00673 template<typename A1> 00674 AllocatorSafe (const A1& a1) : Allocator (a1) 00675 { 00676 } 00677 00678 template<typename A1, typename A2> 00679 AllocatorSafe (const A1& a1, const A2& a2) : Allocator (a1, a2) 00680 { 00681 } 00682 00683 void Free (void* p) 00684 { 00685 CS::Threading::RecursiveMutexScopedLock lock(mutex); 00686 Allocator::Free(p); 00687 } 00688 00689 CS_ATTRIBUTE_MALLOC void* Alloc (const size_t n) 00690 { 00691 CS::Threading::RecursiveMutexScopedLock lock(mutex); 00692 return Allocator::Alloc(n); 00693 } 00694 00695 void* Realloc (void* p, size_t newSize) 00696 { 00697 CS::Threading::RecursiveMutexScopedLock lock(mutex); 00698 return Allocator::Realloc(p, newSize); 00699 } 00700 00701 void SetMemTrackerInfo (const char* info) 00702 { 00703 CS::Threading::RecursiveMutexScopedLock lock(mutex); 00704 Allocator::SetMemTrackerInfo(info); 00705 } 00706 }; 00707 00711 class AllocatorInterface 00712 { 00713 csRef<iAllocator> alloc; 00714 public: 00715 AllocatorInterface (iAllocator* alloc) 00716 : alloc (alloc) {} 00717 00718 CS_ATTRIBUTE_MALLOC void* Alloc (const size_t n) 00719 { return alloc->Alloc (n); } 00720 void Free (void* p) { alloc->Free (p); } 00721 void* Realloc (void* p, size_t newSize) 00722 { return alloc->Realloc (p, newSize); } 00723 void SetMemTrackerInfo (const char* info) 00724 { alloc->SetMemTrackerInfo (info); } 00725 }; 00726 00727 } // namespace Memory 00728 } // namespace CS 00729 00732 #endif // __CS_CSUTIL_ALLOCATOR_H__
Generated for Crystal Space 2.1 by doxygen 1.6.1
