| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366 |
- #pragma once
- #undef min
- #undef max
- #include <atomic>
- namespace BansheeEngine
- {
- class MemoryAllocatorBase;
- /**
- * @brief Thread safe class used for storing total number of memory allocations and deallocations,
- * primarily for statistic purposes.
- */
- class MemoryCounter
- {
- public:
- static BS_UTILITY_EXPORT UINT64 getNumAllocs()
- {
- return Allocs;
- }
- static BS_UTILITY_EXPORT UINT64 getNumFrees()
- {
- return Frees;
- }
-
- private:
- friend class MemoryAllocatorBase;
- // Threadlocal data can't be exported, so some magic to make it accessible from MemoryAllocator
- static BS_UTILITY_EXPORT void incAllocCount() { Allocs++; }
- static BS_UTILITY_EXPORT void incFreeCount() { Frees++; }
- static BS_THREADLOCAL UINT64 Allocs;
- static BS_THREADLOCAL UINT64 Frees;
- };
- /**
- * @brief Base class all memory allocators need to inherit. Provides
- * allocation and free counting.
- */
- class MemoryAllocatorBase
- {
- protected:
- static void incAllocCount() { MemoryCounter::incAllocCount(); }
- static void incFreeCount() { MemoryCounter::incFreeCount(); }
- };
- /**
- * @brief Memory allocator providing a generic implementation.
- * Specialize for specific categories as needed.
- *
- * @note For example you might implement a pool allocator for specific types in order
- * to reduce allocation overhead. By default standard malloc/free are used.
- */
- template<class T>
- class MemoryAllocator : public MemoryAllocatorBase
- {
- public:
- static inline void* allocate(size_t bytes)
- {
- #if BS_PROFILING_ENABLED
- incAllocCount();
- #endif
- return malloc(bytes);
- }
- static inline void* allocateArray(size_t bytes, UINT32 count)
- {
- #if BS_PROFILING_ENABLED
- incAllocCount();
- #endif
- return malloc(bytes * count);
- }
- static inline void free(void* ptr)
- {
- #if BS_PROFILING_ENABLED
- incFreeCount();
- #endif
- ::free(ptr);
- }
- static inline void freeArray(void* ptr, UINT32 count)
- {
- #if BS_PROFILING_ENABLED
- incFreeCount();
- #endif
- ::free(ptr);
- }
- };
- /**
- * @brief General allocator provided by the OS. Use for persistent long term allocations,
- * and allocations that don't happen often.
- */
- class GenAlloc
- { };
- /**
- * @brief Allocates the specified number of bytes.
- */
- template<class Alloc>
- inline void* bs_alloc(UINT32 count)
- {
- return MemoryAllocator<Alloc>::allocate(count);
- }
- /**
- * @brief Allocates enough bytes to hold the specified type, but doesn't construct it.
- */
- template<class T, class Alloc>
- inline T* bs_alloc()
- {
- return (T*)MemoryAllocator<Alloc>::allocate(sizeof(T));
- }
- /**
- * @brief Creates and constructs an array of "count" elements.
- */
- template<class T, class Alloc>
- inline T* bs_newN(UINT32 count)
- {
- T* ptr = (T*)MemoryAllocator<Alloc>::allocateArray(sizeof(T), count);
- for(unsigned int i = 0; i < count; i++)
- new ((void*)&ptr[i]) T;
- return ptr;
- }
- /**
- * @brief Create a new object with the specified allocator and the specified parameters.
- */
- template<class Type, class Alloc, class... Args>
- Type* bs_new(Args &&...args)
- {
- return new (bs_alloc<Alloc>(sizeof(Type))) Type(std::forward<Args>(args)...);
- }
- /**
- * @brief Frees all the bytes allocated at the specified location.
- */
- template<class Alloc>
- inline void bs_free(void* ptr)
- {
- MemoryAllocator<Alloc>::free(ptr);
- }
- /**
- * @brief Destructs and frees the specified object.
- */
- template<class T, class Alloc = GenAlloc>
- inline void bs_delete(T* ptr)
- {
- (ptr)->~T();
- MemoryAllocator<Alloc>::free(ptr);
- }
- /**
- * @brief Destructs and frees the specified array of objects.
- */
- template<class T, class Alloc = GenAlloc>
- inline void bs_deleteN(T* ptr, UINT32 count)
- {
- for(unsigned int i = 0; i < count; i++)
- ptr[i].~T();
- MemoryAllocator<Alloc>::freeArray(ptr, count);
- }
- /*****************************************************************************/
- /* Default versions of all alloc/free/new/delete methods which call GenAlloc */
- /*****************************************************************************/
- /**
- * @brief Allocates the specified number of bytes.
- */
- inline void* bs_alloc(UINT32 count)
- {
- return MemoryAllocator<GenAlloc>::allocate(count);
- }
- /**
- * @brief Allocates enough bytes to hold the specified type, but doesn't construct it.
- */
- template<class T>
- inline T* bs_alloc()
- {
- return (T*)MemoryAllocator<GenAlloc>::allocate(sizeof(T));
- }
- /**
- * @brief Creates and constructs an array of "count" elements.
- */
- template<class T>
- inline T* bs_newN(UINT32 count)
- {
- T* ptr = (T*)MemoryAllocator<GenAlloc>::allocateArray(sizeof(T), count);
- for(unsigned int i = 0; i < count; i++)
- new ((void*)&ptr[i]) T;
- return ptr;
- }
- /**
- * @brief Create a new object with the specified allocator and the specified parameters.
- */
- template<class Type, class... Args>
- Type* bs_new(Args &&...args)
- {
- return new (bs_alloc<GenAlloc>(sizeof(Type))) Type(std::forward<Args>(args)...);
- }
- /**
- * @brief Frees all the bytes allocated at the specified location.
- */
- inline void bs_free(void* ptr)
- {
- MemoryAllocator<GenAlloc>::free(ptr);
- }
- /************************************************************************/
- /* MACRO VERSIONS */
- /* You will almost always want to use the template versions but in some */
- /* cases (private destructor) it is not possible. In which case you may */
- /* use these instead. */
- /************************************************************************/
- #define BS_PVT_DELETE(T, ptr) \
- (ptr)->~T(); \
- MemoryAllocator<GenAlloc>::free(ptr);
- #define BS_PVT_DELETE_A(T, ptr, Alloc) \
- (ptr)->~T(); \
- MemoryAllocator<Alloc>::free(ptr);
- }
- namespace BansheeEngine
- {
- /**
- * @brief Allocator for the standard library that internally uses Banshee
- * memory allocator.
- */
- template <class T, class Alloc = GenAlloc>
- class StdAlloc
- {
- public:
- // Type definitions
- typedef T value_type;
- typedef T* pointer;
- typedef const T* const_pointer;
- typedef T& reference;
- typedef const T& const_reference;
- typedef std::size_t size_type;
- typedef std::ptrdiff_t difference_type;
- /**
- * @brief Rebind allocator to type U
- */
- template <class U>
- struct rebind
- {
- typedef StdAlloc<U, Alloc> other;
- };
- StdAlloc() throw()
- { }
- StdAlloc(const StdAlloc&) throw()
- { }
- template <class U>
- StdAlloc (const StdAlloc<U, Alloc>&) throw()
- { }
- ~StdAlloc() throw()
- { }
- /**
- * @brief Return address of value.
- */
- pointer address (reference value) const
- {
- return &value;
- }
- /**
- * @brief Return address of value.
- */
- const_pointer address (const_reference value) const
- {
- return &value;
- }
- /**
- * @brief Return maximum number of elements that can be allocated.
- */
- size_type max_size () const throw()
- {
- return std::numeric_limits<std::size_t>::max() / sizeof(T);
- }
- /**
- * @brief Allocate but don't initialize number elements of type T.
- */
- pointer allocate (size_type num, const void* = 0)
- {
- pointer ret = (pointer)(bs_alloc<Alloc>((UINT32)num*sizeof(T)));
- return ret;
- }
- /**
- * @brief Initialize elements of allocated storage p with value "value".
- */
- void construct (pointer p, const T& value)
- {
- new((void*)p)T(value);
- }
- /**
- * @brief Destroy elements of initialized storage p.
- */
- void destroy (pointer p)
- {
- p->~T();
- }
- /**
- * @brief Deallocate storage p of deleted elements.
- */
- void deallocate (pointer p, size_type num)
- {
- bs_free<Alloc>((void*)p);
- }
- };
- /**
- * @brief Return that all specializations of this allocator are interchangeable.
- */
- template <class T1, class T2, class Alloc>
- bool operator== (const StdAlloc<T1, Alloc>&,
- const StdAlloc<T2, Alloc>&) throw() {
- return true;
- }
- /**
- * @brief Return that all specializations of this allocator are interchangeable.
- */
- template <class T1, class T2, class Alloc>
- bool operator!= (const StdAlloc<T1, Alloc>&,
- const StdAlloc<T2, Alloc>&) throw() {
- return false;
- }
- }
- #include "BsMemStack.h"
- #include "BsGlobalFrameAlloc.h"
- #include "BsMemAllocProfiler.h"
|