00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
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
00082
00083 const char* mti;
00084 #endif
00085 public:
00086 #ifdef CS_MEMORY_TRACKER
00087 AllocatorMalloc() : mti (0) {}
00088 #endif
00089
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
00198
00199
00200
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
00252
00253
00254
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
00283
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
00395
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
00474
00475 const char* mti;
00476 #endif
00477 public:
00478 #ifdef CS_MEMORY_TRACKER
00479 AllocatorNewChar() : mti (0) {}
00480 #endif
00481
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* )
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 }
00728 }
00729
00732 #endif // __CS_CSUTIL_ALLOCATOR_H__