CrystalSpace

Public API Reference

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
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           /* 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
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* /*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.0 by doxygen 1.7.6.1