/*
 * Copyright (c) 2012-2025 Daniele Bartolini et al.
 * SPDX-License-Identifier: MIT
 */

#pragma once

#include "core/memory/allocator.h"

namespace crown
{
/// Allocates fixed-size memory blocks from a fixed memory pool.
/// The backing allocator is used to allocate the memory pool.
///
/// @ingroup Memory
struct PoolAllocator : public Allocator
{
	Allocator &_backing;

	void *_start;
	void *_freelist;
	u32 _block_size;
	u32 _block_align;

	u32 _num_allocations;
	u32 _allocated_size;

	/// Uses @a backing to allocate the memory pool for containing exactly
	/// @a num_blocks blocks of @a block_size size each aligned to @a block_align.
	PoolAllocator(Allocator &backing, u32 num_blocks, u32 block_size, u32 block_align = Allocator::DEFAULT_ALIGN);

	///
	~PoolAllocator();

	/// Allocates a block of memory from the memory pool.
	/// @note
	/// The @a size and @a align must match those passed to PoolAllocator::PoolAllocator()
	void *allocate(u32 size, u32 align = Allocator::DEFAULT_ALIGN) override;

	/// @copydoc Allocator::deallocate()
	void deallocate(void *data) override;

	/// @copydoc Allocator::allocated_size()
	u32 allocated_size(const void * /*ptr*/) override
	{
		return SIZE_NOT_TRACKED;
	}

	/// @copydoc Allocator::total_allocated()
	u32 total_allocated() override;
};

} // namespace crown
