nuclear@3: /************************************************************************************ nuclear@3: nuclear@3: PublicHeader: OVR.h nuclear@3: Filename : OVR_Allocator.h nuclear@3: Content : Installable memory allocator nuclear@3: Created : September 19, 2012 nuclear@3: Notes : nuclear@3: nuclear@3: Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved. nuclear@3: nuclear@3: Use of this software is subject to the terms of the Oculus license nuclear@3: agreement provided at the time of installation or download, or which nuclear@3: otherwise accompanies this software in either electronic or hard copy form. nuclear@3: nuclear@3: ************************************************************************************/ nuclear@3: nuclear@3: #ifndef OVR_Allocator_h nuclear@3: #define OVR_Allocator_h nuclear@3: nuclear@3: #include "OVR_Types.h" nuclear@3: nuclear@3: //----------------------------------------------------------------------------------- nuclear@3: nuclear@3: // ***** Disable template-unfriendly MS VC++ warnings nuclear@3: #if defined(OVR_CC_MSVC) nuclear@3: // Pragma to prevent long name warnings in in VC++ nuclear@3: #pragma warning(disable : 4503) nuclear@3: #pragma warning(disable : 4786) nuclear@3: // In MSVC 7.1, warning about placement new POD default initializer nuclear@3: #pragma warning(disable : 4345) nuclear@3: #endif nuclear@3: nuclear@3: // Un-define new so that placement constructors work nuclear@3: #undef new nuclear@3: nuclear@3: nuclear@3: //----------------------------------------------------------------------------------- nuclear@3: // ***** Placement new overrides nuclear@3: nuclear@3: // Calls constructor on own memory created with "new(ptr) type" nuclear@3: #ifndef __PLACEMENT_NEW_INLINE nuclear@3: #define __PLACEMENT_NEW_INLINE nuclear@3: nuclear@3: # if defined(OVR_CC_MWERKS) || defined(OVR_CC_BORLAND) || defined(OVR_CC_GNU) nuclear@3: # include nuclear@3: # else nuclear@3: // Useful on MSVC nuclear@3: OVR_FORCE_INLINE void* operator new (OVR::UPInt n, void *ptr) { OVR_UNUSED(n); return ptr; } nuclear@3: OVR_FORCE_INLINE void operator delete (void *, void *) { } nuclear@3: # endif nuclear@3: nuclear@3: #endif // __PLACEMENT_NEW_INLINE nuclear@3: nuclear@3: nuclear@3: nuclear@3: //------------------------------------------------------------------------ nuclear@3: // ***** Macros to redefine class new/delete operators nuclear@3: nuclear@3: // Types specifically declared to allow disambiguation of address in nuclear@3: // class member operator new. nuclear@3: nuclear@3: #define OVR_MEMORY_REDEFINE_NEW_IMPL(class_name, check_delete) \ nuclear@3: void* operator new(UPInt sz) \ nuclear@3: { void *p = OVR_ALLOC_DEBUG(sz, __FILE__, __LINE__); return p; } \ nuclear@3: void* operator new(UPInt sz, const char* file, int line) \ nuclear@3: { void* p = OVR_ALLOC_DEBUG(sz, file, line); OVR_UNUSED2(file, line); return p; } \ nuclear@3: void operator delete(void *p) \ nuclear@3: { check_delete(class_name, p); OVR_FREE(p); } \ nuclear@3: void operator delete(void *p, const char*, int) \ nuclear@3: { check_delete(class_name, p); OVR_FREE(p); } nuclear@3: nuclear@3: #define OVR_MEMORY_DEFINE_PLACEMENT_NEW \ nuclear@3: void* operator new (UPInt n, void *ptr) { OVR_UNUSED(n); return ptr; } \ nuclear@3: void operator delete (void *ptr, void *ptr2) { OVR_UNUSED2(ptr,ptr2); } nuclear@3: nuclear@3: nuclear@3: #define OVR_MEMORY_CHECK_DELETE_NONE(class_name, p) nuclear@3: nuclear@3: // Redefined all delete/new operators in a class without custom memory initialization nuclear@3: #define OVR_MEMORY_REDEFINE_NEW(class_name) \ nuclear@3: OVR_MEMORY_REDEFINE_NEW_IMPL(class_name, OVR_MEMORY_CHECK_DELETE_NONE) nuclear@3: nuclear@3: nuclear@3: namespace OVR { nuclear@3: nuclear@3: //----------------------------------------------------------------------------------- nuclear@3: // ***** Construct / Destruct nuclear@3: nuclear@3: // Construct/Destruct functions are useful when new is redefined, as they can nuclear@3: // be called instead of placement new constructors. nuclear@3: nuclear@3: nuclear@3: template nuclear@3: OVR_FORCE_INLINE T* Construct(void *p) nuclear@3: { nuclear@3: return ::new(p) T; nuclear@3: } nuclear@3: nuclear@3: template nuclear@3: OVR_FORCE_INLINE T* Construct(void *p, const T& source) nuclear@3: { nuclear@3: return ::new(p) T(source); nuclear@3: } nuclear@3: nuclear@3: // Same as above, but allows for a different type of constructor. nuclear@3: template nuclear@3: OVR_FORCE_INLINE T* ConstructAlt(void *p, const S& source) nuclear@3: { nuclear@3: return ::new(p) T(source); nuclear@3: } nuclear@3: nuclear@3: template nuclear@3: OVR_FORCE_INLINE T* ConstructAlt(void *p, const S1& src1, const S2& src2) nuclear@3: { nuclear@3: return ::new(p) T(src1, src2); nuclear@3: } nuclear@3: nuclear@3: template nuclear@3: OVR_FORCE_INLINE void ConstructArray(void *p, UPInt count) nuclear@3: { nuclear@3: UByte *pdata = (UByte*)p; nuclear@3: for (UPInt i=0; i< count; ++i, pdata += sizeof(T)) nuclear@3: { nuclear@3: Construct(pdata); nuclear@3: } nuclear@3: } nuclear@3: nuclear@3: template nuclear@3: OVR_FORCE_INLINE void ConstructArray(void *p, UPInt count, const T& source) nuclear@3: { nuclear@3: UByte *pdata = (UByte*)p; nuclear@3: for (UPInt i=0; i< count; ++i, pdata += sizeof(T)) nuclear@3: { nuclear@3: Construct(pdata, source); nuclear@3: } nuclear@3: } nuclear@3: nuclear@3: template nuclear@3: OVR_FORCE_INLINE void Destruct(T *pobj) nuclear@3: { nuclear@3: pobj->~T(); nuclear@3: OVR_UNUSED1(pobj); // Fix incorrect 'unused variable' MSVC warning. nuclear@3: } nuclear@3: nuclear@3: template nuclear@3: OVR_FORCE_INLINE void DestructArray(T *pobj, UPInt count) nuclear@3: { nuclear@3: for (UPInt i=0; i~T(); nuclear@3: } nuclear@3: nuclear@3: nuclear@3: //----------------------------------------------------------------------------------- nuclear@3: // ***** Allocator nuclear@3: nuclear@3: // Allocator defines a memory allocation interface that developers can override nuclear@3: // to to provide memory for OVR; an instance of this class is typically created on nuclear@3: // application startup and passed into System or OVR::System constructor. nuclear@3: // nuclear@3: // nuclear@3: // Users implementing this interface must provide three functions: Alloc, Free, nuclear@3: // and Realloc. Implementations of these functions must honor the requested alignment. nuclear@3: // Although arbitrary alignment requests are possible, requested alignment will nuclear@3: // typically be small, such as 16 bytes or less. nuclear@3: nuclear@3: class Allocator nuclear@3: { nuclear@3: friend class System; nuclear@3: public: nuclear@3: nuclear@3: // *** Standard Alignment Alloc/Free nuclear@3: nuclear@3: // Allocate memory of specified size with default alignment. nuclear@3: // Alloc of size==0 will allocate a tiny block & return a valid pointer; nuclear@3: // this makes it suitable for new operator. nuclear@3: virtual void* Alloc(UPInt size) = 0; nuclear@3: // Same as Alloc, but provides an option of passing debug data. nuclear@3: virtual void* AllocDebug(UPInt size, const char* file, unsigned line) nuclear@3: { OVR_UNUSED2(file, line); return Alloc(size); } nuclear@3: nuclear@3: // Reallocate memory block to a new size, copying data if necessary. Returns the pointer to nuclear@3: // new memory block, which may be the same as original pointer. Will return 0 if reallocation nuclear@3: // failed, in which case previous memory is still valid. nuclear@3: // Realloc to decrease size will never fail. nuclear@3: // Realloc of pointer == 0 is equivalent to Alloc nuclear@3: // Realloc to size == 0, shrinks to the minimal size, pointer remains valid and requires Free(). nuclear@3: virtual void* Realloc(void* p, UPInt newSize) = 0; nuclear@3: nuclear@3: // Frees memory allocated by Alloc/Realloc. nuclear@3: // Free of null pointer is valid and will do nothing. nuclear@3: virtual void Free(void *p) = 0; nuclear@3: nuclear@3: nuclear@3: // *** Standard Alignment Alloc/Free nuclear@3: nuclear@3: // Allocate memory of specified alignment. nuclear@3: // Memory allocated with AllocAligned MUST be freed with FreeAligned. nuclear@3: // Default implementation will delegate to Alloc/Free after doing rounding. nuclear@3: virtual void* AllocAligned(UPInt size, UPInt align); nuclear@3: // Frees memory allocated with AllocAligned. nuclear@3: virtual void FreeAligned(void* p); nuclear@3: nuclear@3: // Returns the pointer to the current globally installed Allocator instance. nuclear@3: // This pointer is used for most of the memory allocations. nuclear@3: static Allocator* GetInstance() { return pInstance; } nuclear@3: nuclear@3: nuclear@3: protected: nuclear@3: // onSystemShutdown is called on the allocator during System::Shutdown. nuclear@3: // At this point, all allocations should've been freed. nuclear@3: virtual void onSystemShutdown() { } nuclear@3: nuclear@3: public: nuclear@3: static void setInstance(Allocator* palloc) nuclear@3: { nuclear@3: OVR_ASSERT((pInstance == 0) || (palloc == 0)); nuclear@3: pInstance = palloc; nuclear@3: } nuclear@3: nuclear@3: private: nuclear@3: nuclear@3: static Allocator* pInstance; nuclear@3: }; nuclear@3: nuclear@3: nuclear@3: nuclear@3: //------------------------------------------------------------------------ nuclear@3: // ***** Allocator_SingletonSupport nuclear@3: nuclear@3: // Allocator_SingletonSupport is a Allocator wrapper class that implements nuclear@3: // the InitSystemSingleton static function, used to create a global singleton nuclear@3: // used for the OVR::System default argument initialization. nuclear@3: // nuclear@3: // End users implementing custom Allocator interface don't need to make use of this base nuclear@3: // class; they can just create an instance of their own class on stack and pass it to System. nuclear@3: nuclear@3: template nuclear@3: class Allocator_SingletonSupport : public Allocator nuclear@3: { nuclear@3: struct AllocContainer nuclear@3: { nuclear@3: UPInt Data[(sizeof(D) + sizeof(UPInt)-1) / sizeof(UPInt)]; nuclear@3: bool Initialized; nuclear@3: AllocContainer() : Initialized(0) { } nuclear@3: }; nuclear@3: nuclear@3: AllocContainer* pContainer; nuclear@3: nuclear@3: public: nuclear@3: Allocator_SingletonSupport() : pContainer(0) { } nuclear@3: nuclear@3: // Creates a singleton instance of this Allocator class used nuclear@3: // on OVR_DEFAULT_ALLOCATOR during System initialization. nuclear@3: static D* InitSystemSingleton() nuclear@3: { nuclear@3: static AllocContainer Container; nuclear@3: OVR_ASSERT(Container.Initialized == false); nuclear@3: nuclear@3: Allocator_SingletonSupport *presult = Construct((void*)Container.Data); nuclear@3: presult->pContainer = &Container; nuclear@3: Container.Initialized = true; nuclear@3: return (D*)presult; nuclear@3: } nuclear@3: nuclear@3: protected: nuclear@3: virtual void onSystemShutdown() nuclear@3: { nuclear@3: Allocator::onSystemShutdown(); nuclear@3: if (pContainer) nuclear@3: { nuclear@3: pContainer->Initialized = false; nuclear@3: Destruct((D*)this); nuclear@3: pContainer = 0; nuclear@3: } nuclear@3: } nuclear@3: }; nuclear@3: nuclear@3: //------------------------------------------------------------------------ nuclear@3: // ***** Default Allocator nuclear@3: nuclear@3: // This allocator is created and used if no other allocator is installed. nuclear@3: // Default allocator delegates to system malloc. nuclear@3: nuclear@3: class DefaultAllocator : public Allocator_SingletonSupport nuclear@3: { nuclear@3: public: nuclear@3: virtual void* Alloc(UPInt size); nuclear@3: virtual void* AllocDebug(UPInt size, const char* file, unsigned line); nuclear@3: virtual void* Realloc(void* p, UPInt newSize); nuclear@3: virtual void Free(void *p); nuclear@3: }; nuclear@3: nuclear@3: nuclear@3: //------------------------------------------------------------------------ nuclear@3: // ***** Memory Allocation Macros nuclear@3: nuclear@3: // These macros should be used for global allocation. In the future, these nuclear@3: // macros will allows allocation to be extended with debug file/line information nuclear@3: // if necessary. nuclear@3: nuclear@3: #define OVR_REALLOC(p,s) OVR::Allocator::GetInstance()->Realloc((p),(s)) nuclear@3: #define OVR_FREE(p) OVR::Allocator::GetInstance()->Free((p)) nuclear@3: #define OVR_ALLOC_ALIGNED(s,a) OVR::Allocator::GetInstance()->AllocAligned((s),(a)) nuclear@3: #define OVR_FREE_ALIGNED(p) OVR::Allocator::GetInstance()->FreeAligned((p)) nuclear@3: nuclear@3: #ifdef OVR_BUILD_DEBUG nuclear@3: #define OVR_ALLOC(s) OVR::Allocator::GetInstance()->AllocDebug((s), __FILE__, __LINE__) nuclear@3: #define OVR_ALLOC_DEBUG(s,f,l) OVR::Allocator::GetInstance()->AllocDebug((s), f, l) nuclear@3: #else nuclear@3: #define OVR_ALLOC(s) OVR::Allocator::GetInstance()->Alloc((s)) nuclear@3: #define OVR_ALLOC_DEBUG(s,f,l) OVR::Allocator::GetInstance()->Alloc((s)) nuclear@3: #endif nuclear@3: nuclear@3: //------------------------------------------------------------------------ nuclear@3: nuclear@3: // Base class that overrides the new and delete operators. nuclear@3: // Deriving from this class, even as a multiple base, incurs no space overhead. nuclear@3: class NewOverrideBase nuclear@3: { nuclear@3: public: nuclear@3: nuclear@3: // Redefine all new & delete operators. nuclear@3: OVR_MEMORY_REDEFINE_NEW(NewOverrideBase) nuclear@3: }; nuclear@3: nuclear@3: nuclear@3: } // OVR nuclear@3: nuclear@3: nuclear@3: // Redefine operator 'new' if necessary. nuclear@3: #if defined(OVR_DEFINE_NEW) nuclear@3: #define new OVR_DEFINE_NEW nuclear@3: #endif nuclear@3: nuclear@3: nuclear@3: #endif // OVR_Memory