Files
libsst/Include/ZUtil/ZAllocWindow.hpp
2026-04-03 00:22:39 -05:00

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