#pragma once #include #include //! Allocator Base class //! subclasses must specify allocation and deallocation class Allocator { public: Allocator(void); Allocator(const Allocator&) = delete; virtual ~Allocator(void); virtual void *alloc_mem(size_t mem_size) = 0; virtual void dealloc_mem(void *memory) = 0; template T *alloc(Ts&&... ts) { void *data = alloc_mem(sizeof(T)); if(!data) return nullptr; return new (data) T(std::forward(ts)...); } template T *valloc(size_t len, Ts&&... ts) { T *data = (T*)alloc_mem(len*sizeof(T)); if(!data) return nullptr; for(unsigned i=0; i(ts)...); return data; } template void dealloc(T*&t) { if(t) { t->~T(); dealloc_mem((void*)t); t = nullptr; } } //Destructor Free Version template void devalloc(T*&t) { if(t) { dealloc_mem(t); t = nullptr; } } template void devalloc(size_t elms, T*&t) { if(t) { for(size_t i=0; i~T(); dealloc_mem(t); t = nullptr; } } virtual void addMemory(void *, size_t mem_size) = 0; //Return true if the current pool cannot allocate n chunks of chunk_size virtual bool lowMemory(unsigned n, size_t chunk_size) const = 0; bool memFree(void *pool) const; //returns number of pools int memPools() const; int freePools() const; unsigned long long totalAlloced() const; struct AllocatorImpl *impl; }; //! the allocator for normal use class AllocatorClass : public Allocator { public: void *alloc_mem(size_t mem_size); void dealloc_mem(void *memory); void addMemory(void *, size_t mem_size); bool lowMemory(unsigned n, size_t chunk_size) const; using Allocator::Allocator; }; typedef AllocatorClass Alloc; //! the dummy allocator, which does not allow any allocation class DummyAllocator : public Allocator { void not_allowed() const { throw "(de)allocation forbidden"; // TODO: std exception } public: void *alloc_mem(size_t ) { return not_allowed(), nullptr; } void dealloc_mem(void* ) { not_allowed(); } // TODO: more functions? void addMemory(void *, size_t ) { not_allowed(); } bool lowMemory(unsigned , size_t ) const { return not_allowed(), true; } using Allocator::Allocator; }; extern DummyAllocator DummyAlloc; /** * General notes on Memory Allocation Within ZynAddSubFX * ----------------------------------------------------- * * - Parameter Objects Are never allocated within the realtime thread * - Effects, notes and note subcomponents must be allocated with an allocator * - 5M Chunks are used to give the allocator the memory it wants * - If there are 3 chunks that are unused then 1 will be deallocated * - The system will request more allocated space if 5x 1MB chunks cannot be * allocated at any given time (this is likely huge overkill, but if this is * satisfied, then a lot of note spamming would be needed to run out of * space) * * - Things will get a bit weird around the effects due to how pointer swaps * occur * * When a new Part instance is provided it may or may not come with some * instrument effects * * Merging blocks is an option, but one that is not going to likely be * implmented too soon, thus all effects need to be reallocated when the * pointer swap occurs * * The old effect is extracted from the manager * * A new one is constructed with a deep copy * * The old one is returned to middleware for deallocation */