csutil/allocator.h Source File (Crystal Space 2.0 Public API Reference)

| ## Public API Reference

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

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__