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 00032 namespace CS 00033 { 00034 namespace Memory 00035 { 00076 class AllocatorMalloc 00077 { 00078 #ifdef CS_MEMORY_TRACKER 00080 const char* mti; 00081 #endif 00082 public: 00083 #ifdef CS_MEMORY_TRACKER 00084 AllocatorMalloc() : mti (0) {} 00085 #endif 00087 CS_ATTRIBUTE_MALLOC void* Alloc (const size_t n) 00088 { 00089 #ifdef CS_MEMORY_TRACKER 00090 size_t* p = (size_t*)cs_malloc (n); 00091 if (mti) CS::Debug::MemTracker::RegisterAlloc (p, n, mti); 00092 return p; 00093 #else 00094 return cs_malloc (n); 00095 #endif 00096 } 00098 void Free (void* p) 00099 { 00100 #ifdef CS_MEMORY_TRACKER 00101 CS::Debug::MemTracker::RegisterFree (p); 00102 #endif 00103 cs_free (p); 00104 } 00106 void* Realloc (void* p, size_t newSize) 00107 { 00108 #ifdef CS_MEMORY_TRACKER 00109 if (p == 0) return Alloc (newSize); 00110 size_t* np = (size_t*)cs_realloc (p, newSize); 00111 CS::Debug::MemTracker::UpdateSize (p, np, newSize); 00112 return np; 00113 #else 00114 return cs_realloc (p, newSize); 00115 #endif 00116 } 00118 void SetMemTrackerInfo (const char* info) 00119 { 00120 #ifdef CS_MEMORY_TRACKER 00121 mti = info; 00122 #else 00123 (void)info; 00124 #endif 00125 } 00126 }; 00127 00147 template<typename T, size_t N, class ExcessAllocator = AllocatorMalloc, 00148 bool SingleAllocation = false> 00149 class LocalBufferAllocator : public ExcessAllocator 00150 { 00151 static const size_t localSize = N * sizeof (T); 00152 static const uint8 freePattern = 0xfa; 00153 static const uint8 newlyAllocatedSalt = 0xac; 00154 uint8 localBuf[localSize + (SingleAllocation ? 0 : 1)]; 00155 public: 00156 LocalBufferAllocator () 00157 { 00158 if (SingleAllocation) 00159 { 00160 #ifdef CS_DEBUG 00161 memset (localBuf, freePattern, localSize); 00162 #endif 00163 } 00164 else 00165 localBuf[localSize] = 0; 00166 } 00167 LocalBufferAllocator (const ExcessAllocator& xalloc) : 00168 ExcessAllocator (xalloc) 00169 { 00170 if (SingleAllocation) 00171 { 00172 #ifdef CS_DEBUG 00173 memset (localBuf, freePattern, localSize); 00174 #endif 00175 } 00176 else 00177 localBuf[localSize] = 0; 00178 } 00179 T* Alloc (size_t allocSize) 00180 { 00181 if (SingleAllocation) 00182 { 00183 #ifdef CS_DEBUG 00184 /* Verify that the local buffer consists entirely of the "local 00185 buffer unallocated" pattern. (Not 100% safe since a valid 00186 allocated buffer may be coincidentally filled with just that 00187 pattern, but let's just assume that it's unlikely.) */ 00188 bool validPattern = true; 00189 for (size_t n = 0; n < localSize; n++) 00190 { 00191 if (localBuf[n] != freePattern) 00192 { 00193 validPattern = false; 00194 break; 00195 } 00196 } 00197 CS_ASSERT_MSG("This LocalBufferAllocator only allows one allocation " 00198 "a time!", validPattern); 00199 memset (localBuf, newlyAllocatedSalt, localSize); 00200 #endif 00201 if (allocSize <= localSize) 00202 return (T*)localBuf; 00203 else 00204 { 00205 void* p = ExcessAllocator::Alloc (allocSize); 00206 return (T*)p; 00207 } 00208 } 00209 else 00210 { 00211 void* p; 00212 if ((allocSize <= localSize) && !localBuf[localSize]) 00213 { 00214 localBuf[localSize] = 1; 00215 p = localBuf; 00216 #ifdef CS_DEBUG 00217 memset (p, newlyAllocatedSalt, allocSize); 00218 #endif 00219 } 00220 else 00221 { 00222 p = ExcessAllocator::Alloc (allocSize); 00223 } 00224 return (T*)p; 00225 } 00226 } 00227 00228 void Free (T* mem) 00229 { 00230 if (SingleAllocation) 00231 { 00232 if (mem != (T*)localBuf) 00233 ExcessAllocator::Free (mem); 00234 else 00235 { 00236 #ifdef CS_DEBUG 00237 /* Verify that the local buffer does entirely consist of the "local 00238 buffer unallocated" pattern. (Not 100% safe since a valid 00239 allocated buffer may be coincidentally filled with just that 00240 pattern, but let's just assume that it's unlikely.) */ 00241 bool validPattern = true; 00242 for (size_t n = 0; n < localSize; n++) 00243 { 00244 if (localBuf[n] != freePattern) 00245 { 00246 validPattern = false; 00247 break; 00248 } 00249 } 00250 CS_ASSERT_MSG("Free() without prior allocation", !validPattern); 00251 #endif 00252 } 00253 #ifdef CS_DEBUG 00254 memset (localBuf, freePattern, localSize); 00255 #endif 00256 } 00257 else 00258 { 00259 if (mem != (T*)localBuf) 00260 ExcessAllocator::Free (mem); 00261 else 00262 { 00263 localBuf[localSize] = 0; 00264 } 00265 } 00266 } 00267 00268 // The 'relevantcount' parameter should be the number of items 00269 // in the old array that are initialized. 00270 void* Realloc (void* p, size_t newSize) 00271 { 00272 if (p == 0) return Alloc (newSize); 00273 if (p == localBuf) 00274 { 00275 if (newSize <= localSize) 00276 return p; 00277 else 00278 { 00279 p = ExcessAllocator::Alloc (newSize); 00280 memcpy (p, localBuf, localSize); 00281 #ifdef CS_DEBUG 00282 memset (localBuf, freePattern, localSize); 00283 #endif 00284 if (!SingleAllocation) localBuf[localSize] = 0; 00285 return p; 00286 } 00287 } 00288 else 00289 { 00290 if ((newSize <= localSize) && !localBuf[localSize]) 00291 { 00292 memcpy (localBuf, p, newSize); 00293 ExcessAllocator::Free (p); 00294 if (!SingleAllocation) localBuf[localSize] = 1; 00295 return localBuf; 00296 } 00297 else 00298 return ExcessAllocator::Realloc (p, newSize); 00299 } 00300 } 00301 00302 using ExcessAllocator::SetMemTrackerInfo; 00303 }; 00304 00310 template <size_t A = 1> 00311 class AllocatorAlign 00312 { 00313 public: 00317 static inline CS_ATTRIBUTE_MALLOC void* Alloc (size_t size) 00318 { 00319 return AlignedMalloc (size, A); 00320 } 00321 00326 static inline void Free (void* p) 00327 { 00328 AlignedFree (p); 00329 } 00330 00331 void* Realloc (void* p, size_t newSize) 00332 { 00333 return AlignedRealloc (p, newSize, A); 00334 } 00335 00336 void SetMemTrackerInfo (const char* info) 00337 { 00338 (void)info; 00339 } 00340 }; 00341 00347 template<bool Reallocatable = true> 00348 class AllocatorNewChar 00349 { 00350 #ifdef CS_MEMORY_TRACKER 00352 const char* mti; 00353 #endif 00354 public: 00355 #ifdef CS_MEMORY_TRACKER 00356 AllocatorNewChar() : mti (0) {} 00357 #endif 00359 CS_ATTRIBUTE_MALLOC void* Alloc (const size_t n) 00360 { 00361 if (!Reallocatable) 00362 { 00363 char* p = new char[n]; 00364 #ifdef CS_MEMORY_TRACKER 00365 if (mti) CS::Debug::MemTracker::RegisterAlloc (p, n, mti); 00366 #endif 00367 return p; 00368 } 00369 size_t* p = (size_t*)new char[n + sizeof (size_t)]; 00370 *p = n; 00371 p++; 00372 #ifdef CS_MEMORY_TRACKER 00373 if (mti) CS::Debug::MemTracker::RegisterAlloc (p, n, mti); 00374 #endif 00375 return p; 00376 } 00378 void Free (void* p) 00379 { 00380 #ifdef CS_MEMORY_TRACKER 00381 CS::Debug::MemTracker::RegisterFree (p); 00382 #endif 00383 if (!Reallocatable) 00384 { 00385 delete[] (char*)p; 00386 return; 00387 } 00388 size_t* x = (size_t*)p; 00389 x--; 00390 delete[] (char*)x; 00391 } 00393 void* Realloc (void* p, size_t newSize) 00394 { 00395 if (!Reallocatable) return 0; 00396 00397 if (p == 0) return Alloc (newSize); 00398 size_t* x = (size_t*)p; 00399 x--; 00400 size_t oldSize = *x; 00401 size_t* np = (size_t*)Alloc (newSize); 00402 if (newSize < oldSize) 00403 memcpy (np, p, newSize); 00404 else 00405 memcpy (np, p, oldSize); 00406 Free (p); 00407 #ifdef CS_MEMORY_TRACKER 00408 if (mti) CS::Debug::MemTracker::UpdateSize (p, np, newSize); 00409 #endif 00410 return np; 00411 } 00413 void SetMemTrackerInfo (const char* info) 00414 { 00415 #ifdef CS_MEMORY_TRACKER 00416 if (!Reallocatable) return; 00417 mti = info; 00418 #else 00419 (void)info; 00420 #endif 00421 } 00422 }; 00423 00434 template<typename T> 00435 class AllocatorNew 00436 { 00437 public: 00439 CS_ATTRIBUTE_MALLOC void* Alloc (const size_t n) 00440 { 00441 return new T[((n + sizeof(T) - 1) / sizeof(T)) * sizeof(T)]; 00442 } 00444 void Free (void* p) 00445 { 00446 delete[] (T*)p; 00447 } 00449 void* Realloc (void* p, size_t newSize) 00450 { 00451 CS_ASSERT_MSG("Realloc() called on AllocatorNew", false); 00452 return 0; 00453 } 00455 void SetMemTrackerInfo (const char* /*info*/) 00456 { 00457 } 00458 }; 00459 00460 00466 template<typename T, typename Allocator> 00467 struct AllocatorPointerWrapper : public Allocator 00468 { 00470 T* p; 00471 00472 AllocatorPointerWrapper () {} 00473 AllocatorPointerWrapper (const Allocator& alloc) : 00474 Allocator (alloc) {} 00475 AllocatorPointerWrapper (T* p) : p (p) {} 00476 AllocatorPointerWrapper (const Allocator& alloc, T* p) : 00477 Allocator (alloc), p (p) {} 00478 }; 00479 00484 class AllocatorMallocPlatform 00485 { 00486 public: 00488 CS_ATTRIBUTE_MALLOC void* Alloc (const size_t n) 00489 { 00490 return malloc (n); 00491 } 00493 void Free (void* p) 00494 { 00495 free (p); 00496 } 00498 void* Realloc (void* p, size_t newSize) 00499 { 00500 return realloc (p, newSize); 00501 } 00503 void SetMemTrackerInfo (const char* info) 00504 { 00505 (void)info; 00506 } 00507 }; 00508 } // namespace Memory 00509 } // namespace CS 00510 00513 #endif // __CS_CSUTIL_ALLOCATOR_H__
Generated for Crystal Space 1.4.0 by doxygen 1.5.8