diff options
Diffstat (limited to 'Runtime/Containers/GrowingRingbuffer.h')
-rw-r--r-- | Runtime/Containers/GrowingRingbuffer.h | 121 |
1 files changed, 121 insertions, 0 deletions
diff --git a/Runtime/Containers/GrowingRingbuffer.h b/Runtime/Containers/GrowingRingbuffer.h new file mode 100644 index 0000000..c4af135 --- /dev/null +++ b/Runtime/Containers/GrowingRingbuffer.h @@ -0,0 +1,121 @@ +#ifndef RUNTIME_CONTAINERS_GROWINGRINGBUFFER_H +#define RUNTIME_CONTAINERS_GROWINGRINGBUFFER_H + +#include "Ringbuffer.h" +#include "Runtime/Allocator/MemoryMacros.h" +#include "Runtime/Threads/AtomicOps.h" + +// -------------------------------------------------------------------- +// A Ringbuffer with the ability to grow +// Concurrently supports one consumer and one producer +// +// The functions in this class should be synchronized with +// Ringbuffer to fit Ringbuffer template functions. +// -------------------------------------------------------------------- +class GrowingRingbuffer +{ +public: + GrowingRingbuffer(MemLabelId label, UInt32 maxSize, UInt32 initialSize = 1024) + : m_Label(label) + , m_MinSize(initialSize) + , m_MaxSize(maxSize) + { + InitializeBuffers(); + } + + ~GrowingRingbuffer() { DeleteBuffers(); } + + void* WritePtr(UInt32* nBytes) const; + void WritePtrUpdate(void* writePtr, UInt32 nBytesWritten); + + const void* ReadPtr(UInt32* nBytes) const; + void ReadPtrUpdate(const void* readPtr, UInt32 nBytesRead); + + UInt32 GetAllocatedSize() const { return m_AllocatedSize; } + UInt32 GetAvailableSize() const { return m_AvailableSize; } + UInt32 GetFreeSize() const { return m_MaxSize - m_AvailableSize; } + UInt32 GetSize() const { return m_MaxSize; } + + void Reset(); + +private: + void InitializeBuffers(); + void DeleteBuffers(); + + struct RingbufferLink:public Ringbuffer + { + RingbufferLink(MemLabelId label, UInt32 size) : Ringbuffer(label, size) , next(NULL) { } + RingbufferLink* volatile next; + }; + + UInt32 m_MaxSize; + UInt32 m_MinSize; + MemLabelId m_Label; + volatile UInt32 m_AllocatedSize; + volatile UInt32 m_AvailableSize; + RingbufferLink* volatile m_ReadBuffer; + RingbufferLink* volatile m_WriteBuffer; +}; + +inline void GrowingRingbuffer::InitializeBuffers() +{ + m_WriteBuffer = m_ReadBuffer = new RingbufferLink(m_Label, m_MinSize); + m_AllocatedSize = m_ReadBuffer->GetSize(); + m_AvailableSize = 0; +} + +inline void GrowingRingbuffer::DeleteBuffers() +{ + RingbufferLink* buffer = m_ReadBuffer; + while (buffer) + { + RingbufferLink* current = buffer; + buffer = current->next; + delete current; + } +} + +inline void GrowingRingbuffer::Reset() +{ + DeleteBuffers(); + InitializeBuffers(); +} + +FORCE_INLINE void* GrowingRingbuffer::WritePtr(UInt32* nBytes) const +{ + *nBytes = std::min(*nBytes, GetFreeSize()); + return m_WriteBuffer->WritePtr(nBytes); +} + +FORCE_INLINE const void* GrowingRingbuffer::ReadPtr(UInt32* nBytes) const +{ + return m_ReadBuffer->ReadPtr(nBytes); +} + +FORCE_INLINE void GrowingRingbuffer::WritePtrUpdate(void* writePtr, UInt32 nBytesWritten) +{ + m_WriteBuffer->WritePtrUpdate(writePtr, nBytesWritten); + AtomicAdd((volatile int*) &m_AvailableSize, nBytesWritten); + if (m_WriteBuffer->GetFreeSize() == 0 && GetFreeSize() > 0) + { + RingbufferLink* emptyBuffer = new RingbufferLink(m_Label, m_AllocatedSize); + m_WriteBuffer->next = emptyBuffer; + m_WriteBuffer = emptyBuffer; + AtomicAdd((volatile int*) &m_AllocatedSize, emptyBuffer->GetSize()); + } +} + +FORCE_INLINE void GrowingRingbuffer::ReadPtrUpdate(const void* readPtr, UInt32 nBytesRead) +{ + m_ReadBuffer->ReadPtrUpdate(readPtr, nBytesRead); + AtomicSub((volatile int*) &m_AvailableSize, nBytesRead); + if (m_ReadBuffer->next && m_ReadBuffer->GetAvailableSize() == 0) + { + AtomicSub((volatile int*) &m_AllocatedSize, m_ReadBuffer->GetSize()); + RingbufferLink* emptyBuffer = m_ReadBuffer; + m_ReadBuffer = m_ReadBuffer->next; + delete emptyBuffer; + } +} + +#endif // RUNTIME_CONTAINERS_GROWINGRINGBUFFER_H |