OverviewFilesCommitsIssuesDocsReleasesPeers

proc-nodes / src / core / linear_allocator.h

94 lines · c ref:
#ifndef PROC_NODES_LINEAR_ALLOCATOR_H
#define PROC_NODES_LINEAR_ALLOCATOR_H

#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <godot_cpp/templates/vector.hpp>

namespace godot {

// Fast bump allocator. All allocations freed at once via reset().
// Used for temporary data during graph evaluation.
class LinearAllocator {
	static constexpr size_t BLOCK_SIZE = 64 * 1024; // 64KB blocks

	struct Block {
		uint8_t *data;
		size_t capacity;
	};

	Vector<Block> blocks;
	int current_block = -1;
	size_t current_offset = 0;

	void grow() {
		Block b;
		b.capacity = BLOCK_SIZE;
		b.data = static_cast<uint8_t *>(memalloc(BLOCK_SIZE));
		blocks.push_back(b);
		current_block = blocks.size() - 1;
		current_offset = 0;
	}

public:
	LinearAllocator() = default;

	~LinearAllocator() {
		for (int i = 0; i < blocks.size(); i++) {
			memfree(blocks[i].data);
		}
	}

	void *alloc(size_t p_size, size_t p_align = 16) {
		if (p_size == 0) {
			return nullptr;
		}

		// Handle oversized allocations
		if (p_size > BLOCK_SIZE / 2) {
			Block b;
			b.capacity = p_size;
			b.data = static_cast<uint8_t *>(memalloc(p_size));
			blocks.push_back(b);
			return b.data;
		}

		if (current_block < 0) {
			grow();
		}

		// Align offset
		size_t aligned = (current_offset + p_align - 1) & ~(p_align - 1);

		if (aligned + p_size > blocks[current_block].capacity) {
			grow();
			aligned = 0;
		}

		void *ptr = blocks[current_block].data + aligned;
		current_offset = aligned + p_size;
		return ptr;
	}

	template <typename T, typename... Args>
	T *construct(Args &&...args) {
		void *mem = alloc(sizeof(T), alignof(T));
		return new (mem) T(static_cast<Args &&>(args)...);
	}

	// Free ALL allocations at once
	void reset() {
		current_block = blocks.size() > 0 ? 0 : -1;
		current_offset = 0;
	}

	// Disallow copy
	LinearAllocator(const LinearAllocator &) = delete;
	LinearAllocator &operator=(const LinearAllocator &) = delete;
};

} // namespace godot

#endif // PROC_NODES_LINEAR_ALLOCATOR_H