include/foundation/PxAllocator.h

File members: include/foundation/PxAllocator.h

// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//  * Redistributions of source code must retain the above copyright
//    notice, this list of conditions and the following disclaimer.
//  * Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in the
//    documentation and/or other materials provided with the distribution.
//  * Neither the name of NVIDIA CORPORATION nor the names of its
//    contributors may be used to endorse or promote products derived
//    from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Copyright (c) 2008-2023 NVIDIA Corporation. All rights reserved.
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.

#ifndef PX_ALLOCATOR_H
#define PX_ALLOCATOR_H

#include "foundation/PxAllocatorCallback.h"
#include "foundation/PxAssert.h"
#include "foundation/PxFoundation.h"
#include "foundation/Px.h"

#if PX_VC
#pragma warning(push)
#pragma warning(disable : 4577)
#endif

#if PX_WINDOWS_FAMILY
    #include <exception>
#if(_MSC_VER >= 1923)
    #include <typeinfo>
#else
    #include <typeinfo.h>
#endif
#endif
#if(PX_APPLE_FAMILY)
    #include <typeinfo>
#endif

#include <new>

#if PX_VC
#pragma warning(pop)
#endif

// PT: the rules are simple:
// - PX_ALLOC/PX_ALLOCATE/PX_FREE is similar to malloc/free. Use that for POD/anything that doesn't need ctor/dtor.
// - PX_NEW/PX_DELETE is similar to new/delete. Use that for anything that needs a ctor/dtor.
// - Everything goes through the user allocator.
// - Inherit from PxUserAllocated to PX_NEW something. Do it even on small classes, it's free.
// - You cannot PX_NEW a POD. Use PX_ALLOC.

#define PX_ALLOC(n, name) physx::PxAllocator().allocate(n, PX_FL)

// PT: use this one to reduce the amount of visible reinterpret_cast
#define PX_ALLOCATE(type, count, name)  reinterpret_cast<type*>(PX_ALLOC(count*sizeof(type), name))

#define PX_FREE(x)                          \
    if(x)                                   \
    {                                       \
        physx::PxAllocator().deallocate(x); \
        x = NULL;                           \
    }

#define PX_FREE_THIS    physx::PxAllocator().deallocate(this)

#define PX_NEW(T)               new (physx::PxReflectionAllocator<T>(), PX_FL) T
#define PX_PLACEMENT_NEW(p, T)  new (p) T
#define PX_DELETE_THIS          delete this
#define PX_DELETE(x)            if(x)   { delete x;     x = NULL;   }
#define PX_DELETE_ARRAY(x)      if(x)   { delete []x;   x = NULL;   }
#define PX_RELEASE(x)           if(x)   { x->release(); x = NULL;   }

#if !PX_DOXYGEN
namespace physx
{
#endif
    class PxAllocator
    {
    public:
        PX_FORCE_INLINE PxAllocator(const char* = NULL){}

        PX_FORCE_INLINE void*   allocate(size_t size, const char* file, int line)
        {
            return size ? PxGetBroadcastAllocator()->allocate(size, "", file, line) : NULL;
        }

        PX_FORCE_INLINE void    deallocate(void* ptr)
        {
            if(ptr)
                PxGetBroadcastAllocator()->deallocate(ptr);
        }
    };

    class PxRawAllocator
    {
    public:
        PxRawAllocator(const char* = 0) {}

        PX_FORCE_INLINE void*   allocate(size_t size, const char*, int)
        {
            // malloc returns valid pointer for size==0, no need to check
            return ::malloc(size);
        }

        PX_FORCE_INLINE void    deallocate(void* ptr)
        {
            // free(0) is guaranteed to have no side effect, no need to check
            ::free(ptr);
        }
    };

    class PxVirtualAllocatorCallback
    {
    public:
        PxVirtualAllocatorCallback()            {}
        virtual ~PxVirtualAllocatorCallback()   {}

        virtual void*   allocate(const size_t size, const int group, const char* file, const int line) = 0;
        virtual void    deallocate(void* ptr) = 0;
    };

    class PxVirtualAllocator
    {
    public:
        PxVirtualAllocator(PxVirtualAllocatorCallback* callback = NULL, const int group = 0) : mCallback(callback), mGroup(group)   {}

        PX_FORCE_INLINE void* allocate(const size_t size, const char* file, const int line)
        {
            PX_ASSERT(mCallback);
            if (size)
                return mCallback->allocate(size, mGroup, file, line);
            return NULL;
        }

        PX_FORCE_INLINE void deallocate(void* ptr)
        {
            PX_ASSERT(mCallback);
            if (ptr)
                mCallback->deallocate(ptr);
        }

        void setCallback(PxVirtualAllocatorCallback* callback)
        {
            mCallback = callback;
        }

        PxVirtualAllocatorCallback* getCallback()
        {
            return mCallback;
        }

    private:
        PxVirtualAllocatorCallback* mCallback;
        const int mGroup;
        PxVirtualAllocator& operator=(const PxVirtualAllocator&);
    };

    template <typename T>
    class PxReflectionAllocator
    {
        static const char* getName(bool reportAllocationNames)
        {
            if(!reportAllocationNames)
                return "<allocation names disabled>";
#if PX_GCC_FAMILY
            return __PRETTY_FUNCTION__;
#else
            // name() calls malloc(), raw_name() wouldn't
            return typeid(T).name();
#endif
        }

    public:
        PxReflectionAllocator(const PxEMPTY)    {}
        PxReflectionAllocator(const char* = 0)  {}

        inline PxReflectionAllocator(const PxReflectionAllocator&)  {}

        PX_FORCE_INLINE void*   allocate(size_t size, const char* filename, int line)
        {
            if(!size)
                return NULL;

            bool reportAllocationNames;
            PxAllocatorCallback* cb = PxGetBroadcastAllocator(&reportAllocationNames);

            return cb->allocate(size, getName(reportAllocationNames), filename, line);
        }

        PX_FORCE_INLINE void    deallocate(void* ptr)
        {
            if(ptr)
                PxGetBroadcastAllocator()->deallocate(ptr);
        }
    };

    template <typename T>
    struct PxAllocatorTraits
    {
        typedef PxReflectionAllocator<T> Type;
    };

#if !PX_DOXYGEN
} // namespace physx
#endif

#endif