Initial commit
This commit is contained in:
205
Include/ZUtil/ZAllocWindow.hpp
Normal file
205
Include/ZUtil/ZAllocWindow.hpp
Normal file
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user