bitsquid / foundation / temp_allocator.h

#pragma once

#include "memory.h"

/// A temporary memory allocator that primarily allocates memory from a
/// local stack buffer of size BUFFER_SIZE. If that memory is exhausted it will
/// use the backing allocator (typically a scratch allocator).
///
/// Memory allocated with a TempAllocator does not have to be deallocated. It is
/// automatically deallocated when the TempAllocator is destroyed.
template <int BUFFER_SIZE>
class TempAllocator : public Allocator
{
public:
	/// Creates a new temporary allocator using the specified backing allocator.
	TempAllocator(Allocator &backing = memory_globals::default_scratch_allocator());
	virtual ~TempAllocator();

	virtual void *allocate(uint32_t size, uint32_t align = DEFAULT_ALIGN);
	
	/// Deallocation is a NOP for the TempAllocator. The memory is automatically
	/// deallocated when the TempAllocator is destroyed.
	virtual void deallocate(void *) {}

	/// Returns SIZE_NOT_TRACKED.
	virtual uint32_t allocated_size(void *) {return SIZE_NOT_TRACKED;}

	/// Returns SIZE_NOT_TRACKED.
	virtual uint32_t total_allocated() {return SIZE_NOT_TRACKED;}

private:
	char _buffer[BUFFER_SIZE];	//< Local stack buffer for allocations.
	Allocator &_backing;		//< Backing allocator if local memory is exhausted.
	char *_start;				//< Start of current allocation region
	char *_p;					//< Current allocation pointer.
	char *_end;					//< End of current allocation region
	unsigned _chunk_size;		//< Chunks to allocate from backing allocator
};

// If possible, use one of these predefined sizes for the TempAllocator to avoid
// unnecessary template instantiation.
typedef TempAllocator<64> TempAllocator64;
typedef TempAllocator<128> TempAllocator128;
typedef TempAllocator<256> TempAllocator256;
typedef TempAllocator<512> TempAllocator512;
typedef TempAllocator<1024> TempAllocator1024;
typedef TempAllocator<2048> TempAllocator2048;
typedef TempAllocator<4096> TempAllocator4096;

// ---------------------------------------------------------------
// Inline function implementations
// ---------------------------------------------------------------

template <int BUFFER_SIZE>
TempAllocator<BUFFER_SIZE>::TempAllocator(Allocator &backing) : _backing(backing), _chunk_size(4*1024)
{
	_p = _start = _buffer;
	_end = _start + BUFFER_SIZE;
	*(void **)_start = 0;
	_p += sizeof(void *);
}

template <int BUFFER_SIZE>
TempAllocator<BUFFER_SIZE>::~TempAllocator()
{
	void *p = *(void **)_buffer;
	while (p) {
		void *next = *(void **)p;
		_backing.deallocate(p);
		p = next;
	}
}

template <int BUFFER_SIZE>
void *TempAllocator<BUFFER_SIZE>::allocate(uint32_t size, uint32_t align)
{
	_p = (char *)memory::align_forward(_p, align);
	if (size > _end - _p) {
		uint32_t to_allocate = sizeof(void *) + size + align;
		if (to_allocate < _chunk_size)
			to_allocate = _chunk_size;
		_chunk_size *= 2;
		void *p = _backing.allocate(to_allocate);
		*(void **)_start = p;
		_p = _start = (char *)p;
		_end = _start + to_allocate;
		*(void **)_start = 0;
		_p += sizeof(void *);
		memory::align_forward(p, align);
	}
	void *result = _p;
	_p += size;
	return result;
}
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.