rev |
line source |
nuclear@3
|
1 /************************************************************************************
|
nuclear@3
|
2
|
nuclear@3
|
3 PublicHeader: OVR.h
|
nuclear@3
|
4 Filename : OVR_Allocator.h
|
nuclear@3
|
5 Content : Installable memory allocator
|
nuclear@3
|
6 Created : September 19, 2012
|
nuclear@3
|
7 Notes :
|
nuclear@3
|
8
|
nuclear@3
|
9 Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
|
nuclear@3
|
10
|
nuclear@3
|
11 Use of this software is subject to the terms of the Oculus license
|
nuclear@3
|
12 agreement provided at the time of installation or download, or which
|
nuclear@3
|
13 otherwise accompanies this software in either electronic or hard copy form.
|
nuclear@3
|
14
|
nuclear@3
|
15 ************************************************************************************/
|
nuclear@3
|
16
|
nuclear@3
|
17 #ifndef OVR_Allocator_h
|
nuclear@3
|
18 #define OVR_Allocator_h
|
nuclear@3
|
19
|
nuclear@3
|
20 #include "OVR_Types.h"
|
nuclear@3
|
21
|
nuclear@3
|
22 //-----------------------------------------------------------------------------------
|
nuclear@3
|
23
|
nuclear@3
|
24 // ***** Disable template-unfriendly MS VC++ warnings
|
nuclear@3
|
25 #if defined(OVR_CC_MSVC)
|
nuclear@3
|
26 // Pragma to prevent long name warnings in in VC++
|
nuclear@3
|
27 #pragma warning(disable : 4503)
|
nuclear@3
|
28 #pragma warning(disable : 4786)
|
nuclear@3
|
29 // In MSVC 7.1, warning about placement new POD default initializer
|
nuclear@3
|
30 #pragma warning(disable : 4345)
|
nuclear@3
|
31 #endif
|
nuclear@3
|
32
|
nuclear@3
|
33 // Un-define new so that placement constructors work
|
nuclear@3
|
34 #undef new
|
nuclear@3
|
35
|
nuclear@3
|
36
|
nuclear@3
|
37 //-----------------------------------------------------------------------------------
|
nuclear@3
|
38 // ***** Placement new overrides
|
nuclear@3
|
39
|
nuclear@3
|
40 // Calls constructor on own memory created with "new(ptr) type"
|
nuclear@3
|
41 #ifndef __PLACEMENT_NEW_INLINE
|
nuclear@3
|
42 #define __PLACEMENT_NEW_INLINE
|
nuclear@3
|
43
|
nuclear@3
|
44 # if defined(OVR_CC_MWERKS) || defined(OVR_CC_BORLAND) || defined(OVR_CC_GNU)
|
nuclear@3
|
45 # include <new>
|
nuclear@3
|
46 # else
|
nuclear@3
|
47 // Useful on MSVC
|
nuclear@3
|
48 OVR_FORCE_INLINE void* operator new (OVR::UPInt n, void *ptr) { OVR_UNUSED(n); return ptr; }
|
nuclear@3
|
49 OVR_FORCE_INLINE void operator delete (void *, void *) { }
|
nuclear@3
|
50 # endif
|
nuclear@3
|
51
|
nuclear@3
|
52 #endif // __PLACEMENT_NEW_INLINE
|
nuclear@3
|
53
|
nuclear@3
|
54
|
nuclear@3
|
55
|
nuclear@3
|
56 //------------------------------------------------------------------------
|
nuclear@3
|
57 // ***** Macros to redefine class new/delete operators
|
nuclear@3
|
58
|
nuclear@3
|
59 // Types specifically declared to allow disambiguation of address in
|
nuclear@3
|
60 // class member operator new.
|
nuclear@3
|
61
|
nuclear@3
|
62 #define OVR_MEMORY_REDEFINE_NEW_IMPL(class_name, check_delete) \
|
nuclear@3
|
63 void* operator new(UPInt sz) \
|
nuclear@3
|
64 { void *p = OVR_ALLOC_DEBUG(sz, __FILE__, __LINE__); return p; } \
|
nuclear@3
|
65 void* operator new(UPInt sz, const char* file, int line) \
|
nuclear@3
|
66 { void* p = OVR_ALLOC_DEBUG(sz, file, line); OVR_UNUSED2(file, line); return p; } \
|
nuclear@3
|
67 void operator delete(void *p) \
|
nuclear@3
|
68 { check_delete(class_name, p); OVR_FREE(p); } \
|
nuclear@3
|
69 void operator delete(void *p, const char*, int) \
|
nuclear@3
|
70 { check_delete(class_name, p); OVR_FREE(p); }
|
nuclear@3
|
71
|
nuclear@3
|
72 #define OVR_MEMORY_DEFINE_PLACEMENT_NEW \
|
nuclear@3
|
73 void* operator new (UPInt n, void *ptr) { OVR_UNUSED(n); return ptr; } \
|
nuclear@3
|
74 void operator delete (void *ptr, void *ptr2) { OVR_UNUSED2(ptr,ptr2); }
|
nuclear@3
|
75
|
nuclear@3
|
76
|
nuclear@3
|
77 #define OVR_MEMORY_CHECK_DELETE_NONE(class_name, p)
|
nuclear@3
|
78
|
nuclear@3
|
79 // Redefined all delete/new operators in a class without custom memory initialization
|
nuclear@3
|
80 #define OVR_MEMORY_REDEFINE_NEW(class_name) \
|
nuclear@3
|
81 OVR_MEMORY_REDEFINE_NEW_IMPL(class_name, OVR_MEMORY_CHECK_DELETE_NONE)
|
nuclear@3
|
82
|
nuclear@3
|
83
|
nuclear@3
|
84 namespace OVR {
|
nuclear@3
|
85
|
nuclear@3
|
86 //-----------------------------------------------------------------------------------
|
nuclear@3
|
87 // ***** Construct / Destruct
|
nuclear@3
|
88
|
nuclear@3
|
89 // Construct/Destruct functions are useful when new is redefined, as they can
|
nuclear@3
|
90 // be called instead of placement new constructors.
|
nuclear@3
|
91
|
nuclear@3
|
92
|
nuclear@3
|
93 template <class T>
|
nuclear@3
|
94 OVR_FORCE_INLINE T* Construct(void *p)
|
nuclear@3
|
95 {
|
nuclear@3
|
96 return ::new(p) T;
|
nuclear@3
|
97 }
|
nuclear@3
|
98
|
nuclear@3
|
99 template <class T>
|
nuclear@3
|
100 OVR_FORCE_INLINE T* Construct(void *p, const T& source)
|
nuclear@3
|
101 {
|
nuclear@3
|
102 return ::new(p) T(source);
|
nuclear@3
|
103 }
|
nuclear@3
|
104
|
nuclear@3
|
105 // Same as above, but allows for a different type of constructor.
|
nuclear@3
|
106 template <class T, class S>
|
nuclear@3
|
107 OVR_FORCE_INLINE T* ConstructAlt(void *p, const S& source)
|
nuclear@3
|
108 {
|
nuclear@3
|
109 return ::new(p) T(source);
|
nuclear@3
|
110 }
|
nuclear@3
|
111
|
nuclear@3
|
112 template <class T, class S1, class S2>
|
nuclear@3
|
113 OVR_FORCE_INLINE T* ConstructAlt(void *p, const S1& src1, const S2& src2)
|
nuclear@3
|
114 {
|
nuclear@3
|
115 return ::new(p) T(src1, src2);
|
nuclear@3
|
116 }
|
nuclear@3
|
117
|
nuclear@3
|
118 template <class T>
|
nuclear@3
|
119 OVR_FORCE_INLINE void ConstructArray(void *p, UPInt count)
|
nuclear@3
|
120 {
|
nuclear@3
|
121 UByte *pdata = (UByte*)p;
|
nuclear@3
|
122 for (UPInt i=0; i< count; ++i, pdata += sizeof(T))
|
nuclear@3
|
123 {
|
nuclear@3
|
124 Construct<T>(pdata);
|
nuclear@3
|
125 }
|
nuclear@3
|
126 }
|
nuclear@3
|
127
|
nuclear@3
|
128 template <class T>
|
nuclear@3
|
129 OVR_FORCE_INLINE void ConstructArray(void *p, UPInt count, const T& source)
|
nuclear@3
|
130 {
|
nuclear@3
|
131 UByte *pdata = (UByte*)p;
|
nuclear@3
|
132 for (UPInt i=0; i< count; ++i, pdata += sizeof(T))
|
nuclear@3
|
133 {
|
nuclear@3
|
134 Construct<T>(pdata, source);
|
nuclear@3
|
135 }
|
nuclear@3
|
136 }
|
nuclear@3
|
137
|
nuclear@3
|
138 template <class T>
|
nuclear@3
|
139 OVR_FORCE_INLINE void Destruct(T *pobj)
|
nuclear@3
|
140 {
|
nuclear@3
|
141 pobj->~T();
|
nuclear@3
|
142 OVR_UNUSED1(pobj); // Fix incorrect 'unused variable' MSVC warning.
|
nuclear@3
|
143 }
|
nuclear@3
|
144
|
nuclear@3
|
145 template <class T>
|
nuclear@3
|
146 OVR_FORCE_INLINE void DestructArray(T *pobj, UPInt count)
|
nuclear@3
|
147 {
|
nuclear@3
|
148 for (UPInt i=0; i<count; ++i, ++pobj)
|
nuclear@3
|
149 pobj->~T();
|
nuclear@3
|
150 }
|
nuclear@3
|
151
|
nuclear@3
|
152
|
nuclear@3
|
153 //-----------------------------------------------------------------------------------
|
nuclear@3
|
154 // ***** Allocator
|
nuclear@3
|
155
|
nuclear@3
|
156 // Allocator defines a memory allocation interface that developers can override
|
nuclear@3
|
157 // to to provide memory for OVR; an instance of this class is typically created on
|
nuclear@3
|
158 // application startup and passed into System or OVR::System constructor.
|
nuclear@3
|
159 //
|
nuclear@3
|
160 //
|
nuclear@3
|
161 // Users implementing this interface must provide three functions: Alloc, Free,
|
nuclear@3
|
162 // and Realloc. Implementations of these functions must honor the requested alignment.
|
nuclear@3
|
163 // Although arbitrary alignment requests are possible, requested alignment will
|
nuclear@3
|
164 // typically be small, such as 16 bytes or less.
|
nuclear@3
|
165
|
nuclear@3
|
166 class Allocator
|
nuclear@3
|
167 {
|
nuclear@3
|
168 friend class System;
|
nuclear@3
|
169 public:
|
nuclear@3
|
170
|
nuclear@3
|
171 // *** Standard Alignment Alloc/Free
|
nuclear@3
|
172
|
nuclear@3
|
173 // Allocate memory of specified size with default alignment.
|
nuclear@3
|
174 // Alloc of size==0 will allocate a tiny block & return a valid pointer;
|
nuclear@3
|
175 // this makes it suitable for new operator.
|
nuclear@3
|
176 virtual void* Alloc(UPInt size) = 0;
|
nuclear@3
|
177 // Same as Alloc, but provides an option of passing debug data.
|
nuclear@3
|
178 virtual void* AllocDebug(UPInt size, const char* file, unsigned line)
|
nuclear@3
|
179 { OVR_UNUSED2(file, line); return Alloc(size); }
|
nuclear@3
|
180
|
nuclear@3
|
181 // Reallocate memory block to a new size, copying data if necessary. Returns the pointer to
|
nuclear@3
|
182 // new memory block, which may be the same as original pointer. Will return 0 if reallocation
|
nuclear@3
|
183 // failed, in which case previous memory is still valid.
|
nuclear@3
|
184 // Realloc to decrease size will never fail.
|
nuclear@3
|
185 // Realloc of pointer == 0 is equivalent to Alloc
|
nuclear@3
|
186 // Realloc to size == 0, shrinks to the minimal size, pointer remains valid and requires Free().
|
nuclear@3
|
187 virtual void* Realloc(void* p, UPInt newSize) = 0;
|
nuclear@3
|
188
|
nuclear@3
|
189 // Frees memory allocated by Alloc/Realloc.
|
nuclear@3
|
190 // Free of null pointer is valid and will do nothing.
|
nuclear@3
|
191 virtual void Free(void *p) = 0;
|
nuclear@3
|
192
|
nuclear@3
|
193
|
nuclear@3
|
194 // *** Standard Alignment Alloc/Free
|
nuclear@3
|
195
|
nuclear@3
|
196 // Allocate memory of specified alignment.
|
nuclear@3
|
197 // Memory allocated with AllocAligned MUST be freed with FreeAligned.
|
nuclear@3
|
198 // Default implementation will delegate to Alloc/Free after doing rounding.
|
nuclear@3
|
199 virtual void* AllocAligned(UPInt size, UPInt align);
|
nuclear@3
|
200 // Frees memory allocated with AllocAligned.
|
nuclear@3
|
201 virtual void FreeAligned(void* p);
|
nuclear@3
|
202
|
nuclear@3
|
203 // Returns the pointer to the current globally installed Allocator instance.
|
nuclear@3
|
204 // This pointer is used for most of the memory allocations.
|
nuclear@3
|
205 static Allocator* GetInstance() { return pInstance; }
|
nuclear@3
|
206
|
nuclear@3
|
207
|
nuclear@3
|
208 protected:
|
nuclear@3
|
209 // onSystemShutdown is called on the allocator during System::Shutdown.
|
nuclear@3
|
210 // At this point, all allocations should've been freed.
|
nuclear@3
|
211 virtual void onSystemShutdown() { }
|
nuclear@3
|
212
|
nuclear@3
|
213 public:
|
nuclear@3
|
214 static void setInstance(Allocator* palloc)
|
nuclear@3
|
215 {
|
nuclear@3
|
216 OVR_ASSERT((pInstance == 0) || (palloc == 0));
|
nuclear@3
|
217 pInstance = palloc;
|
nuclear@3
|
218 }
|
nuclear@3
|
219
|
nuclear@3
|
220 private:
|
nuclear@3
|
221
|
nuclear@3
|
222 static Allocator* pInstance;
|
nuclear@3
|
223 };
|
nuclear@3
|
224
|
nuclear@3
|
225
|
nuclear@3
|
226
|
nuclear@3
|
227 //------------------------------------------------------------------------
|
nuclear@3
|
228 // ***** Allocator_SingletonSupport
|
nuclear@3
|
229
|
nuclear@3
|
230 // Allocator_SingletonSupport is a Allocator wrapper class that implements
|
nuclear@3
|
231 // the InitSystemSingleton static function, used to create a global singleton
|
nuclear@3
|
232 // used for the OVR::System default argument initialization.
|
nuclear@3
|
233 //
|
nuclear@3
|
234 // End users implementing custom Allocator interface don't need to make use of this base
|
nuclear@3
|
235 // class; they can just create an instance of their own class on stack and pass it to System.
|
nuclear@3
|
236
|
nuclear@3
|
237 template<class D>
|
nuclear@3
|
238 class Allocator_SingletonSupport : public Allocator
|
nuclear@3
|
239 {
|
nuclear@3
|
240 struct AllocContainer
|
nuclear@3
|
241 {
|
nuclear@3
|
242 UPInt Data[(sizeof(D) + sizeof(UPInt)-1) / sizeof(UPInt)];
|
nuclear@3
|
243 bool Initialized;
|
nuclear@3
|
244 AllocContainer() : Initialized(0) { }
|
nuclear@3
|
245 };
|
nuclear@3
|
246
|
nuclear@3
|
247 AllocContainer* pContainer;
|
nuclear@3
|
248
|
nuclear@3
|
249 public:
|
nuclear@3
|
250 Allocator_SingletonSupport() : pContainer(0) { }
|
nuclear@3
|
251
|
nuclear@3
|
252 // Creates a singleton instance of this Allocator class used
|
nuclear@3
|
253 // on OVR_DEFAULT_ALLOCATOR during System initialization.
|
nuclear@3
|
254 static D* InitSystemSingleton()
|
nuclear@3
|
255 {
|
nuclear@3
|
256 static AllocContainer Container;
|
nuclear@3
|
257 OVR_ASSERT(Container.Initialized == false);
|
nuclear@3
|
258
|
nuclear@3
|
259 Allocator_SingletonSupport<D> *presult = Construct<D>((void*)Container.Data);
|
nuclear@3
|
260 presult->pContainer = &Container;
|
nuclear@3
|
261 Container.Initialized = true;
|
nuclear@3
|
262 return (D*)presult;
|
nuclear@3
|
263 }
|
nuclear@3
|
264
|
nuclear@3
|
265 protected:
|
nuclear@3
|
266 virtual void onSystemShutdown()
|
nuclear@3
|
267 {
|
nuclear@3
|
268 Allocator::onSystemShutdown();
|
nuclear@3
|
269 if (pContainer)
|
nuclear@3
|
270 {
|
nuclear@3
|
271 pContainer->Initialized = false;
|
nuclear@3
|
272 Destruct((D*)this);
|
nuclear@3
|
273 pContainer = 0;
|
nuclear@3
|
274 }
|
nuclear@3
|
275 }
|
nuclear@3
|
276 };
|
nuclear@3
|
277
|
nuclear@3
|
278 //------------------------------------------------------------------------
|
nuclear@3
|
279 // ***** Default Allocator
|
nuclear@3
|
280
|
nuclear@3
|
281 // This allocator is created and used if no other allocator is installed.
|
nuclear@3
|
282 // Default allocator delegates to system malloc.
|
nuclear@3
|
283
|
nuclear@3
|
284 class DefaultAllocator : public Allocator_SingletonSupport<DefaultAllocator>
|
nuclear@3
|
285 {
|
nuclear@3
|
286 public:
|
nuclear@3
|
287 virtual void* Alloc(UPInt size);
|
nuclear@3
|
288 virtual void* AllocDebug(UPInt size, const char* file, unsigned line);
|
nuclear@3
|
289 virtual void* Realloc(void* p, UPInt newSize);
|
nuclear@3
|
290 virtual void Free(void *p);
|
nuclear@3
|
291 };
|
nuclear@3
|
292
|
nuclear@3
|
293
|
nuclear@3
|
294 //------------------------------------------------------------------------
|
nuclear@3
|
295 // ***** Memory Allocation Macros
|
nuclear@3
|
296
|
nuclear@3
|
297 // These macros should be used for global allocation. In the future, these
|
nuclear@3
|
298 // macros will allows allocation to be extended with debug file/line information
|
nuclear@3
|
299 // if necessary.
|
nuclear@3
|
300
|
nuclear@3
|
301 #define OVR_REALLOC(p,s) OVR::Allocator::GetInstance()->Realloc((p),(s))
|
nuclear@3
|
302 #define OVR_FREE(p) OVR::Allocator::GetInstance()->Free((p))
|
nuclear@3
|
303 #define OVR_ALLOC_ALIGNED(s,a) OVR::Allocator::GetInstance()->AllocAligned((s),(a))
|
nuclear@3
|
304 #define OVR_FREE_ALIGNED(p) OVR::Allocator::GetInstance()->FreeAligned((p))
|
nuclear@3
|
305
|
nuclear@3
|
306 #ifdef OVR_BUILD_DEBUG
|
nuclear@3
|
307 #define OVR_ALLOC(s) OVR::Allocator::GetInstance()->AllocDebug((s), __FILE__, __LINE__)
|
nuclear@3
|
308 #define OVR_ALLOC_DEBUG(s,f,l) OVR::Allocator::GetInstance()->AllocDebug((s), f, l)
|
nuclear@3
|
309 #else
|
nuclear@3
|
310 #define OVR_ALLOC(s) OVR::Allocator::GetInstance()->Alloc((s))
|
nuclear@3
|
311 #define OVR_ALLOC_DEBUG(s,f,l) OVR::Allocator::GetInstance()->Alloc((s))
|
nuclear@3
|
312 #endif
|
nuclear@3
|
313
|
nuclear@3
|
314 //------------------------------------------------------------------------
|
nuclear@3
|
315
|
nuclear@3
|
316 // Base class that overrides the new and delete operators.
|
nuclear@3
|
317 // Deriving from this class, even as a multiple base, incurs no space overhead.
|
nuclear@3
|
318 class NewOverrideBase
|
nuclear@3
|
319 {
|
nuclear@3
|
320 public:
|
nuclear@3
|
321
|
nuclear@3
|
322 // Redefine all new & delete operators.
|
nuclear@3
|
323 OVR_MEMORY_REDEFINE_NEW(NewOverrideBase)
|
nuclear@3
|
324 };
|
nuclear@3
|
325
|
nuclear@3
|
326
|
nuclear@3
|
327 } // OVR
|
nuclear@3
|
328
|
nuclear@3
|
329
|
nuclear@3
|
330 // Redefine operator 'new' if necessary.
|
nuclear@3
|
331 #if defined(OVR_DEFINE_NEW)
|
nuclear@3
|
332 #define new OVR_DEFINE_NEW
|
nuclear@3
|
333 #endif
|
nuclear@3
|
334
|
nuclear@3
|
335
|
nuclear@3
|
336 #endif // OVR_Memory
|