1 | // |
2 | // Redistribution and use in source and binary forms, with or without |
3 | // modification, are permitted provided that the following conditions |
4 | // are met: |
5 | // * Redistributions of source code must retain the above copyright |
6 | // notice, this list of conditions and the following disclaimer. |
7 | // * Redistributions in binary form must reproduce the above copyright |
8 | // notice, this list of conditions and the following disclaimer in the |
9 | // documentation and/or other materials provided with the distribution. |
10 | // * Neither the name of NVIDIA CORPORATION nor the names of its |
11 | // contributors may be used to endorse or promote products derived |
12 | // from this software without specific prior written permission. |
13 | // |
14 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY |
15 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
16 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
17 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
18 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
19 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
20 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
21 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
22 | // OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
23 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
24 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
25 | // |
26 | // Copyright (c) 2008-2021 NVIDIA Corporation. All rights reserved. |
27 | // Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. |
28 | // Copyright (c) 2001-2004 NovodeX AG. All rights reserved. |
29 | |
30 | #ifndef PSFOUNDATION_PSALLOCATOR_H |
31 | #define PSFOUNDATION_PSALLOCATOR_H |
32 | |
33 | #include "foundation/PxAllocatorCallback.h" |
34 | #include "foundation/PxAssert.h" |
35 | #include "PxFoundation.h" |
36 | #include "Ps.h" |
37 | |
38 | #if(PX_WINDOWS_FAMILY || PX_XBOXONE || PX_XBOX_SERIES_X) |
39 | #include <exception> |
40 | #if(_MSC_VER >= 1923) |
41 | #include <typeinfo> |
42 | #else |
43 | #include <typeinfo.h> |
44 | #endif |
45 | #endif |
46 | #if(PX_APPLE_FAMILY) |
47 | #include <typeinfo> |
48 | #endif |
49 | |
50 | #include <new> |
51 | |
52 | // Allocation macros going through user allocator |
53 | #if PX_CHECKED |
54 | #define PX_ALLOC(n, name) physx::shdfnd::NamedAllocator(name).allocate(n, __FILE__, __LINE__) |
55 | #else |
56 | #define PX_ALLOC(n, name) physx::shdfnd::NonTrackingAllocator().allocate(n, __FILE__, __LINE__) |
57 | #endif |
58 | #define PX_ALLOC_TEMP(n, name) PX_ALLOC(n, name) |
59 | #define PX_FREE(x) physx::shdfnd::NonTrackingAllocator().deallocate(x) |
60 | #define PX_FREE_AND_RESET(x) \ |
61 | { \ |
62 | PX_FREE(x); \ |
63 | x = 0; \ |
64 | } |
65 | |
66 | // The following macros support plain-old-types and classes derived from UserAllocated. |
67 | #define PX_NEW(T) new (physx::shdfnd::ReflectionAllocator<T>(), __FILE__, __LINE__) T |
68 | #define PX_NEW_TEMP(T) PX_NEW(T) |
69 | #define PX_DELETE(x) delete x |
70 | #define PX_DELETE_AND_RESET(x) \ |
71 | { \ |
72 | PX_DELETE(x); \ |
73 | x = 0; \ |
74 | } |
75 | #define PX_DELETE_POD(x) \ |
76 | { \ |
77 | PX_FREE(x); \ |
78 | x = 0; \ |
79 | } |
80 | #define PX_DELETE_ARRAY(x) \ |
81 | { \ |
82 | PX_DELETE([] x); \ |
83 | x = 0; \ |
84 | } |
85 | |
86 | // aligned allocation |
87 | #define PX_ALIGNED16_ALLOC(n) physx::shdfnd::AlignedAllocator<16>().allocate(n, __FILE__, __LINE__) |
88 | #define PX_ALIGNED16_FREE(x) physx::shdfnd::AlignedAllocator<16>().deallocate(x) |
89 | |
90 | //! placement new macro to make it easy to spot bad use of 'new' |
91 | #define PX_PLACEMENT_NEW(p, T) new (p) T |
92 | |
93 | #if PX_DEBUG || PX_CHECKED |
94 | #define PX_USE_NAMED_ALLOCATOR 1 |
95 | #else |
96 | #define PX_USE_NAMED_ALLOCATOR 0 |
97 | #endif |
98 | |
99 | // Don't use inline for alloca !!! |
100 | #if PX_WINDOWS_FAMILY |
101 | #include <malloc.h> |
102 | #define PxAlloca(x) _alloca(x) |
103 | #elif PX_LINUX || PX_ANDROID |
104 | #include <malloc.h> |
105 | #define PxAlloca(x) alloca(x) |
106 | #elif PX_APPLE_FAMILY |
107 | #include <alloca.h> |
108 | #define PxAlloca(x) alloca(x) |
109 | #elif PX_PS4 |
110 | #include <memory.h> |
111 | #define PxAlloca(x) alloca(x) |
112 | #elif PX_XBOXONE |
113 | #include <malloc.h> |
114 | #define PxAlloca(x) alloca(x) |
115 | #elif PX_XBOX_SERIES_X |
116 | #include <malloc.h> |
117 | #define PxAlloca(x) alloca(x) |
118 | #elif PX_SWITCH |
119 | #include <malloc.h> |
120 | #define PxAlloca(x) alloca(x) |
121 | #endif |
122 | |
123 | #define PxAllocaAligned(x, alignment) ((size_t(PxAlloca(x + alignment)) + (alignment - 1)) & ~size_t(alignment - 1)) |
124 | |
125 | namespace physx |
126 | { |
127 | namespace shdfnd |
128 | { |
129 | |
130 | PX_FOUNDATION_API PxAllocatorCallback& getAllocator(); |
131 | |
132 | /** |
133 | Allocator used to access the global PxAllocatorCallback instance without providing additional information. |
134 | */ |
135 | |
136 | class PX_FOUNDATION_API Allocator |
137 | { |
138 | public: |
139 | Allocator(const char* = 0) |
140 | { |
141 | } |
142 | void* allocate(size_t size, const char* file, int line); |
143 | void deallocate(void* ptr); |
144 | }; |
145 | |
146 | /* |
147 | * Bootstrap allocator using malloc/free. |
148 | * Don't use unless your objects get allocated before foundation is initialized. |
149 | */ |
150 | class RawAllocator |
151 | { |
152 | public: |
153 | RawAllocator(const char* = 0) |
154 | { |
155 | } |
156 | void* allocate(size_t size, const char*, int) |
157 | { |
158 | // malloc returns valid pointer for size==0, no need to check |
159 | return ::malloc(size: size); |
160 | } |
161 | void deallocate(void* ptr) |
162 | { |
163 | // free(0) is guaranteed to have no side effect, no need to check |
164 | ::free(ptr: ptr); |
165 | } |
166 | }; |
167 | |
168 | /* |
169 | * Allocator that simply calls straight back to the application without tracking. |
170 | * This is used by the heap (Foundation::mNamedAllocMap) that tracks allocations |
171 | * because it needs to be able to grow as a result of an allocation. |
172 | * Making the hash table re-entrant to deal with this may not make sense. |
173 | */ |
174 | class NonTrackingAllocator |
175 | { |
176 | public: |
177 | PX_FORCE_INLINE NonTrackingAllocator(const char* = 0) |
178 | { |
179 | } |
180 | PX_FORCE_INLINE void* allocate(size_t size, const char* file, int line) |
181 | { |
182 | return !size ? 0 : getAllocator().allocate(size, typeName: "NonTrackedAlloc" , filename: file, line); |
183 | } |
184 | PX_FORCE_INLINE void deallocate(void* ptr) |
185 | { |
186 | if(ptr) |
187 | getAllocator().deallocate(ptr); |
188 | } |
189 | }; |
190 | |
191 | /* |
192 | \brief Virtual allocator callback used to provide run-time defined allocators to foundation types like Array or Bitmap. |
193 | This is used by VirtualAllocator |
194 | */ |
195 | class VirtualAllocatorCallback |
196 | { |
197 | public: |
198 | VirtualAllocatorCallback() |
199 | { |
200 | } |
201 | virtual ~VirtualAllocatorCallback() |
202 | { |
203 | } |
204 | virtual void* allocate(const size_t size, const char* file, const int line) = 0; |
205 | virtual void deallocate(void* ptr) = 0; |
206 | }; |
207 | |
208 | /* |
209 | \brief Virtual allocator to be used by foundation types to provide run-time defined allocators. |
210 | Due to the fact that Array extends its allocator, rather than contains a reference/pointer to it, the VirtualAllocator |
211 | must |
212 | be a concrete type containing a pointer to a virtual callback. The callback may not be available at instantiation time, |
213 | therefore |
214 | methods are provided to set the callback later. |
215 | */ |
216 | class VirtualAllocator |
217 | { |
218 | public: |
219 | VirtualAllocator(VirtualAllocatorCallback* callback = NULL) : mCallback(callback) |
220 | { |
221 | } |
222 | |
223 | void* allocate(const size_t size, const char* file, const int line) |
224 | { |
225 | PX_ASSERT(mCallback); |
226 | if(size) |
227 | return mCallback->allocate(size, file, line); |
228 | return NULL; |
229 | } |
230 | void deallocate(void* ptr) |
231 | { |
232 | PX_ASSERT(mCallback); |
233 | if(ptr) |
234 | mCallback->deallocate(ptr); |
235 | } |
236 | |
237 | void setCallback(VirtualAllocatorCallback* callback) |
238 | { |
239 | mCallback = callback; |
240 | } |
241 | VirtualAllocatorCallback* getCallback() |
242 | { |
243 | return mCallback; |
244 | } |
245 | |
246 | private: |
247 | VirtualAllocatorCallback* mCallback; |
248 | VirtualAllocator& operator=(const VirtualAllocator&); |
249 | }; |
250 | |
251 | #if PX_USE_NAMED_ALLOCATOR // can be slow, so only use in debug/checked |
252 | class PX_FOUNDATION_API NamedAllocator |
253 | { |
254 | public: |
255 | NamedAllocator(const PxEMPTY); |
256 | NamedAllocator(const char* name = 0); // todo: should not have default argument! |
257 | NamedAllocator(const NamedAllocator&); |
258 | ~NamedAllocator(); |
259 | NamedAllocator& operator=(const NamedAllocator&); |
260 | void* allocate(size_t size, const char* filename, int line); |
261 | void deallocate(void* ptr); |
262 | }; |
263 | #else |
264 | class NamedAllocator; |
265 | #endif // PX_DEBUG |
266 | |
267 | /** |
268 | Allocator used to access the global PxAllocatorCallback instance using a static name derived from T. |
269 | */ |
270 | |
271 | template <typename T> |
272 | class ReflectionAllocator |
273 | { |
274 | static const char* getName() |
275 | { |
276 | if(!PxGetFoundation().getReportAllocationNames()) |
277 | return "<allocation names disabled>" ; |
278 | #if PX_GCC_FAMILY |
279 | return __PRETTY_FUNCTION__; |
280 | #else |
281 | // name() calls malloc(), raw_name() wouldn't |
282 | return typeid(T).name(); |
283 | #endif |
284 | } |
285 | |
286 | public: |
287 | ReflectionAllocator(const PxEMPTY) |
288 | { |
289 | } |
290 | ReflectionAllocator(const char* = 0) |
291 | { |
292 | } |
293 | inline ReflectionAllocator(const ReflectionAllocator&) |
294 | { |
295 | } |
296 | void* allocate(size_t size, const char* filename, int line) |
297 | { |
298 | return size ? getAllocator().allocate(size, typeName: getName(), filename, line) : 0; |
299 | } |
300 | void deallocate(void* ptr) |
301 | { |
302 | if(ptr) |
303 | getAllocator().deallocate(ptr); |
304 | } |
305 | }; |
306 | |
307 | template <typename T> |
308 | struct AllocatorTraits |
309 | { |
310 | #if PX_USE_NAMED_ALLOCATOR |
311 | typedef NamedAllocator Type; |
312 | #else |
313 | typedef ReflectionAllocator<T> Type; |
314 | #endif |
315 | }; |
316 | |
317 | // if you get a build error here, you are trying to PX_NEW a class |
318 | // that is neither plain-old-type nor derived from UserAllocated |
319 | template <typename T, typename X> |
320 | union EnableIfPod |
321 | { |
322 | int i; |
323 | T t; |
324 | typedef X Type; |
325 | }; |
326 | |
327 | } // namespace shdfnd |
328 | } // namespace physx |
329 | |
330 | // Global placement new for ReflectionAllocator templated by |
331 | // plain-old-type. Allows using PX_NEW for pointers and built-in-types. |
332 | // |
333 | // ATTENTION: You need to use PX_DELETE_POD or PX_FREE to deallocate |
334 | // memory, not PX_DELETE. PX_DELETE_POD redirects to PX_FREE. |
335 | // |
336 | // Rationale: PX_DELETE uses global operator delete(void*), which we dont' want to overload. |
337 | // Any other definition of PX_DELETE couldn't support array syntax 'PX_DELETE([]a);'. |
338 | // PX_DELETE_POD was preferred over PX_DELETE_ARRAY because it is used |
339 | // less often and applies to both single instances and arrays. |
340 | template <typename T> |
341 | PX_INLINE void* operator new(size_t size, physx::shdfnd::ReflectionAllocator<T> alloc, const char* fileName, |
342 | typename physx::shdfnd::EnableIfPod<T, int>::Type line) |
343 | { |
344 | return alloc.allocate(size, fileName, line); |
345 | } |
346 | |
347 | template <typename T> |
348 | PX_INLINE void* operator new [](size_t size, physx::shdfnd::ReflectionAllocator<T> alloc, const char* fileName, |
349 | typename physx::shdfnd::EnableIfPod<T, int>::Type line) |
350 | { return alloc.allocate(size, fileName, line); } |
351 | |
352 | // If construction after placement new throws, this placement delete is being called. |
353 | template <typename T> |
354 | PX_INLINE void operator delete(void* ptr, physx::shdfnd::ReflectionAllocator<T> alloc, const char* fileName, |
355 | typename physx::shdfnd::EnableIfPod<T, int>::Type line) |
356 | { |
357 | PX_UNUSED(fileName); |
358 | PX_UNUSED(line); |
359 | |
360 | alloc.deallocate(ptr); |
361 | } |
362 | |
363 | // If construction after placement new throws, this placement delete is being called. |
364 | template <typename T> |
365 | PX_INLINE void operator delete [](void* ptr, physx::shdfnd::ReflectionAllocator<T> alloc, const char* fileName, |
366 | typename physx::shdfnd::EnableIfPod<T, int>::Type line) |
367 | { |
368 | PX_UNUSED(fileName); |
369 | PX_UNUSED(line); |
370 | |
371 | alloc.deallocate(ptr); |
372 | } |
373 | |
374 | #endif // #ifndef PSFOUNDATION_PSALLOCATOR_H |
375 | |