Revision control

++ // Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
++ // Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
++ // SPDX-FileCopyrightText: Copyright (c) 2008-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
++ // SPDX-License-Identifier: Apache-2.0
++
++ #ifndef PX_BROADCAST_H
++ #define PX_BROADCAST_H
++
++ #include "foundation/PxInlineArray.h"
++ #include "foundation/PxSimpleTypes.h"
++ #include "foundation/PxErrorCallback.h"
++
++ #if !PX_DOXYGEN
++ namespace physx
++ {
++ #endif
++
++ /**
++ \brief Abstract listener class that listens to allocation and deallocation events from the
++ foundation memory system.
++
++ <b>Threading:</b> All methods of this class should be thread safe as it can be called from the user thread
++ or the physics processing thread(s).
++ */
++ class PxAllocationListener
++ {
++ public:
++ /**
++ \brief callback when memory is allocated.
++ \param size Size of the allocation in bytes.
++ \param typeName Type this data is being allocated for.
++ \param filename File the allocation came from.
++ \param line the allocation came from.
++ \param allocatedMemory memory that will be returned from the allocation.
++ */
++ virtual void onAllocation(size_t size, const char* typeName, const char* filename, int line,
++ void* allocatedMemory) = 0;
++
++ /**
++ \brief callback when memory is deallocated.
++ \param allocatedMemory memory just before allocation.
++ */
++ virtual void onDeallocation(void* allocatedMemory) = 0;
++
++ protected:
++ virtual ~PxAllocationListener()
++ {
++ }
++ };
++
++ /**
++ \brief Broadcast class implementation, registering listeners.
++
++ <b>Threading:</b> All methods of this class should be thread safe as it can be called from the user thread
++ or the physics processing thread(s). There is not internal locking
++ */
++ template <class Listener, class Base>
++ class PxBroadcast : public Base
++ {
++ public:
++ static const uint32_t MAX_NB_LISTENERS = 16;
++
++ /**
++ \brief The default constructor.
++ */
++ PxBroadcast()
++ {
++ }
++
++ /**
++ \brief Register new listener.
++
++ \note It is NOT SAFE to register and deregister listeners while allocations may be taking place.
++ moreover, there is no thread safety to registration/deregistration.
++
++ \param listener Listener to register.
++ */
++ void registerListener(Listener& listener)
++ {
++ if(mListeners.size() < MAX_NB_LISTENERS)
++ mListeners.pushBack(&listener);
++ }
++
++ /**
++ \brief Deregister an existing listener.
++
++ \note It is NOT SAFE to register and deregister listeners while allocations may be taking place.
++ moreover, there is no thread safety to registration/deregistration.
++
++ \param listener Listener to deregister.
++ */
++ void deregisterListener(Listener& listener)
++ {
++ mListeners.findAndReplaceWithLast(&listener);
++ }
++
++ /**
++ \brief Get number of registered listeners.
++
++ \return Number of listeners.
++ */
++ uint32_t getNbListeners() const
++ {
++ return mListeners.size();
++ }
++
++ /**
++ \brief Get an existing listener from given index.
++
++ \param index Index of the listener.
++ \return Listener on given index.
++ */
++ Listener& getListener(uint32_t index)
++ {
++ PX_ASSERT(index <= mListeners.size());
++ return *mListeners[index];
++ }
++
++ protected:
++ virtual ~PxBroadcast()
++ {
++ }
++
++ physx::PxInlineArray<Listener*, MAX_NB_LISTENERS, physx::PxAllocator> mListeners;
++ };
++
++ /**
++ \brief Abstract base class for an application defined memory allocator that allows an external listener
++ to audit the memory allocations.
++ */
++ class PxBroadcastingAllocator : public PxBroadcast<PxAllocationListener, PxAllocatorCallback>
++ {
++ PX_NOCOPY(PxBroadcastingAllocator)
++
++ public:
++ /**
++ \brief The default constructor.
++ */
++ PxBroadcastingAllocator(PxAllocatorCallback& allocator, PxErrorCallback& error) : mAllocator(allocator), mError(error)
++ {
++ mListeners.clear();
++ }
++
++ /**
++ \brief The default constructor.
++ */
++ virtual ~PxBroadcastingAllocator()
++ {
++ mListeners.clear();
++ }
++
++ /**
++ \brief Allocates size bytes of memory, which must be 16-byte aligned.
++
++ This method should never return NULL. If you run out of memory, then
++ you should terminate the app or take some other appropriate action.
++
++ <b>Threading:</b> This function should be thread safe as it can be called in the context of the user thread
++ and physics processing thread(s).
++
++ \param size Number of bytes to allocate.
++ \param typeName Name of the datatype that is being allocated
++ \param filename The source file which allocated the memory
++ \param line The source line which allocated the memory
++ \return The allocated block of memory.
++ */
++ void* allocate(size_t size, const char* typeName, const char* filename, int line)
++ {
++ void* mem = mAllocator.allocate(size, typeName, filename, line);
++
++ if(!mem)
++ {
++ mError.reportError(PxErrorCode::eABORT, "User allocator returned NULL.", filename, line);
++ return NULL;
++ }
++
++ if((size_t(mem) & 15))
++ {
++ mError.reportError(PxErrorCode::eABORT, "Allocations must be 16-byte aligned.", filename, line);
++ return NULL;
++ }
++
++ for(uint32_t i = 0; i < mListeners.size(); i++)
++ mListeners[i]->onAllocation(size, typeName, filename, line, mem);
++
++ return mem;
++ }
++
++ /**
++ \brief Frees memory previously allocated by allocate().
++
++ <b>Threading:</b> This function should be thread safe as it can be called in the context of the user thread
++ and physics processing thread(s).
++
++ \param ptr Memory to free.
++ */
++ void deallocate(void* ptr)
++ {
++ for(uint32_t i = 0; i < mListeners.size(); i++)
++ {
++ mListeners[i]->onDeallocation(ptr);
++ }
++ mAllocator.deallocate(ptr);
++ }
++
++ private:
++ PxAllocatorCallback& mAllocator;
++ PxErrorCallback& mError;
++ };
++
++ /**
++ \brief Abstract base class for an application defined error callback that allows an external listener
++ to report errors.
++ */
++ class PxBroadcastingErrorCallback : public PxBroadcast<PxErrorCallback, PxErrorCallback>
++ {
++ PX_NOCOPY(PxBroadcastingErrorCallback)
++ public:
++ /**
++ \brief The default constructor.
++ */
++ PxBroadcastingErrorCallback(PxErrorCallback& errorCallback)
++ {
++ registerListener(errorCallback);
++ }
++
++ /**
++ \brief The default destructor.
++ */
++ virtual ~PxBroadcastingErrorCallback()
++ {
++ mListeners.clear();
++ }
++
++ /**
++ \brief Reports an error code.
++ \param code Error code, see #PxErrorCode
++ \param message Message to display.
++ \param file File error occured in.
++ \param line Line number error occured on.
++ */
++ void reportError(PxErrorCode::Enum code, const char* message, const char* file, int line)
++ {
++ for(uint32_t i = 0; i < mListeners.size(); i++)
++ mListeners[i]->reportError(code, message, file, line);
++ }
++ };
++ #if !PX_DOXYGEN
++ } // namespace physx
++ #endif
++
++ #endif
++