205 lines
5.7 KiB
C++
205 lines
5.7 KiB
C++
/*
|
|
ZAllocWindow.hpp
|
|
Author: James Russell <jcrussell@762studios.com>
|
|
Created: 3/7/2013
|
|
|
|
Purpose:
|
|
|
|
Buffer used to maintain a sliding window of allocations in a buffer. Primary
|
|
use case is sliding packet windows, but could also be used for other forms
|
|
of data.
|
|
|
|
Able to allocate raw memory blocks or perform in-place construction using
|
|
default constructors. Destructor calls can be omitted or performed.
|
|
|
|
License:
|
|
|
|
TODO
|
|
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#ifndef _ZALLOCWINDOW_HPP
|
|
#define _ZALLOCWINDOW_HPP
|
|
|
|
#include <new> // for placement new
|
|
|
|
#include <ZUtil/ZUtilBuild.hpp>
|
|
|
|
/*
|
|
Allocation window class. Operating on a contiguous array of backing memory,
|
|
this will allocate chunks of that memory, increasing the window until the
|
|
entire block would be used.
|
|
|
|
When deallocations are performed, no memory is actually freed from the buffer
|
|
unless the earliest allocation is deallocated, which will shrink the window.
|
|
|
|
As an example, consider the following:
|
|
|
|
buffer.Allocate(A);
|
|
buffer.Allocate(B);
|
|
buffer.Allocate(C);
|
|
buffer.Allocate(D);
|
|
|
|
A large enough buffer would return four pointers and would have the following
|
|
layout (a = allocated flag, d = deallocated flag, f = free memory):
|
|
|
|
+-----------------------------------+
|
|
| a | A | a | B | a | C | a | D | f |
|
|
+-----------------------------------+
|
|
^ ^
|
|
buffer begin buffer end
|
|
|
|
buffer.Deallocate(B);
|
|
|
|
+-----------------------------------+
|
|
| a | A | d | B | a | C | a | D | f |
|
|
+-----------------------------------+
|
|
^ ^
|
|
buffer begin buffer end
|
|
|
|
buffer.Deallocate(A);
|
|
|
|
+-----------------------------------+
|
|
| f | f | f | f | a | C | a | D | f |
|
|
+-----------------------------------+
|
|
^ ^
|
|
buffer begin buffer end
|
|
|
|
Notice that when B was deallocated, no space was actually made available
|
|
in the buffer until A was deallocated. If a further attempt had been made
|
|
to allocate data, it would have returned NULL, indicating that the allocation
|
|
window was full. The only way to free data at that point would have been to
|
|
deallocate the earliest allocation (A, in this case).
|
|
|
|
The allocation window will automatically handle wrapping around when the end
|
|
of the buffer is reached.
|
|
*/
|
|
class ZAllocWindow
|
|
{
|
|
public:
|
|
// c'tor
|
|
ZAllocWindow();
|
|
|
|
// parameterized c'tor
|
|
ZAllocWindow(size_t _buffersize);
|
|
|
|
// d'tor
|
|
~ZAllocWindow();
|
|
|
|
/*
|
|
void* ZAllocWindow::Allocate
|
|
|
|
Allocates a contiguous block of memory from the buffer. If this
|
|
would wrap around such that the previously allocated data (that has
|
|
not been deallocated) would be overwritten, then it returns NULL.
|
|
|
|
An additional 8 bytes are used per allocation from the buffer for
|
|
allocation metadata.
|
|
|
|
This will always return a word aligned pointer.
|
|
|
|
The template version will default construct an object of type T.
|
|
|
|
@param _size - number of bytes to allocate
|
|
@return (void*) - the allocated block of memory (NULL if not possible)
|
|
*/
|
|
void* Allocate(size_t _size);
|
|
template <typename T> T* Allocate()
|
|
{ T* obj = (T*)Allocate(sizeof(T)); return (obj != NULL ? new (obj) T() : NULL); }
|
|
|
|
/*
|
|
void ZAllocWindow::Deallocate
|
|
|
|
Deallocates a previously allocated block of memory from the binary buffer. Since
|
|
allocation is done in a sliding window, this only moves frees up memory if this
|
|
is the oldest currently allocated block of data. Any other data that is deallocated
|
|
will be marked as freed to be made available when the oldest allocated block is freed.
|
|
|
|
The template version will call the destructor for the object.
|
|
|
|
@param _data - the data to be deallocated
|
|
@param _obj - the object to deallocate (destructor is called)
|
|
@return (void)
|
|
*/
|
|
void Deallocate(void* _data);
|
|
template <typename T> void Deallocate(T* _obj)
|
|
{ _obj->~T(); Deallocate((void*)_obj); }
|
|
|
|
/*
|
|
size_t ZAllocWindow::GetAllocCount
|
|
|
|
Gets the current number of allocations out on this allocation window.
|
|
|
|
@return (size_t) - the number of allocations
|
|
*/
|
|
size_t GetAllocCount() const
|
|
{ return NumAllocs; }
|
|
|
|
/*
|
|
void ZAllocWindow::Reset
|
|
|
|
Completely resets the allocation window, completely invalidating all
|
|
existing allocations.
|
|
|
|
@return (void)
|
|
*/
|
|
void Reset();
|
|
|
|
/*
|
|
bool ZAllocWindow::Resize
|
|
|
|
Attempts to resize the buffer. This will fail if data is currently allocated in
|
|
the buffer.
|
|
|
|
The template version will set the buffer to enough room for N objects of type T.
|
|
|
|
@param _newsize - the new desired size of the buffer
|
|
@param _count - the number of objects of type T to resize the buffer for
|
|
@return (bool) - true if able to resize, false otherwise
|
|
*/
|
|
bool Resize(size_t _newsize);
|
|
template <typename T> bool Resize(size_t _count)
|
|
{ return Resize((sizeof(T) + 8) * _count); }
|
|
|
|
/*
|
|
void ZAllocWindow::SetBuffer
|
|
|
|
Sets the backing buffer for this binary buffer. This will fail if data is currently
|
|
allocated in the buffer. If NULL, will release ownership of any previous set buffer
|
|
and allocate a new one equal to the current size.
|
|
|
|
Does not assume ownership of the buffer - will not delete it upon destruction of this
|
|
buffer.
|
|
|
|
@param _buffer - the buffer to use as backing
|
|
@param _buffersize - the size of the buffer being set
|
|
@return (bool) - true if able to use, false otherwise
|
|
*/
|
|
bool SetBuffer(void* _buffer, size_t _buffersize);
|
|
|
|
/*
|
|
size_t ZAllocWindow::Size
|
|
|
|
Returns the current size of the buffer.
|
|
|
|
@return (size_t) - size (in bytes) of the buffer
|
|
*/
|
|
size_t Size() const
|
|
{ return BufferSize; }
|
|
|
|
private:
|
|
DISABLE_COPY_AND_ASSIGN(ZAllocWindow);
|
|
|
|
void* Buffer; // The allocated buffer
|
|
void* Begin; // The (moving) front pointer of the buffer
|
|
void* End; // The (moving) back pointer of the buffer
|
|
|
|
size_t BufferSize; // The current allocated size of the buffer
|
|
bool bOwnsBuffer; // Flag indicating we own the buffer (and should free when done)
|
|
size_t NumAllocs; // The number of allocations we've done
|
|
};
|
|
|
|
#endif
|
|
|