#pragma once #include #include #include #include #include #include namespace clap { namespace helpers { /** Simple heap allocator which ensures alignment. */ class Heap { public: explicit Heap(uint32_t initialSize = 4096) { reserve(initialSize); } ~Heap() { std::free(_base); } Heap(const Heap &) = delete; Heap(Heap &&) = delete; Heap &operator=(const Heap &) = delete; Heap &operator=(Heap &&) = delete; void reserve(const size_t heapSize) { if (heapSize <= _size) return; auto *const ptr = static_cast(std::realloc(_base, heapSize)); if (!ptr) throw std::bad_alloc(); _base = ptr; _size = heapSize; } void clear() { _brk = 0; } void *tryAllocate(uint32_t align, uint32_t size) { assert(_brk <= _size); void *ptr = _base + _brk; size_t space = _size - _brk; if (!std::align(align, size, ptr, space)) return nullptr; auto offset = static_cast(ptr) - _base; _brk = offset + size; std::memset(ptr, 0, size); return ptr; } void *allocate(uint32_t align, uint32_t size) { assert(_brk <= _size); if (size + _brk > _size) reserve(_size * 2); auto ptr = tryAllocate(align, size); assert(ptr); return ptr; } void *ptrFromBase(size_t offset) const { assert(offset <= _brk && "out of range"); return static_cast(_base) + offset; } size_t offsetFromBase(const void *ptr) const { assert(ptr >= _base && "ptr before heap's base"); size_t offset = static_cast(ptr) - _base; assert(offset < _size && "ptr after heap's end"); return offset; } size_t size() const { return _size; } bool empty() const { return _brk == 0; } private: size_t _size = 0; size_t _brk = 0; uint8_t *_base = nullptr; }; }} // namespace clap::helpers