summaryrefslogtreecommitdiff
path: root/Runtime/Containers/Ringbuffer.h
diff options
context:
space:
mode:
authorchai <chaifix@163.com>2019-08-14 22:50:43 +0800
committerchai <chaifix@163.com>2019-08-14 22:50:43 +0800
commit15740faf9fe9fe4be08965098bbf2947e096aeeb (patch)
treea730ec236656cc8cab5b13f088adfaed6bb218fb /Runtime/Containers/Ringbuffer.h
+Unity Runtime codeHEADmaster
Diffstat (limited to 'Runtime/Containers/Ringbuffer.h')
-rw-r--r--Runtime/Containers/Ringbuffer.h94
1 files changed, 94 insertions, 0 deletions
diff --git a/Runtime/Containers/Ringbuffer.h b/Runtime/Containers/Ringbuffer.h
new file mode 100644
index 0000000..7a34b5e
--- /dev/null
+++ b/Runtime/Containers/Ringbuffer.h
@@ -0,0 +1,94 @@
+#ifndef RUNTIME_CONTAINERS_RINGBUFFER_H
+#define RUNTIME_CONTAINERS_RINGBUFFER_H
+
+#include "Runtime/Allocator/MemoryMacros.h"
+#include "Runtime/Allocator/tlsf/tlsfbits.h"
+#include "Runtime/Threads/AtomicOps.h"
+
+// --------------------------------------------------------------------
+// Ringbuffer
+// Concurrently supports one consumer and one producer
+// --------------------------------------------------------------------
+class Ringbuffer
+{
+public:
+ Ringbuffer(void* memory, UInt32 size);
+ Ringbuffer(MemLabelId label, UInt32 size);
+
+ ~Ringbuffer();
+
+ void* WritePtr(UInt32* nBytes) const { return Ptr(m_Put, GetFreeSize(), nBytes); }
+ void WritePtrUpdate(void* writePtr, UInt32 nBytesWritten);
+
+ const void* ReadPtr(UInt32* nBytes) const { return Ptr(m_Get, GetAvailableSize(), nBytes); }
+ void ReadPtrUpdate(const void* readPtr, UInt32 nBytesRead);
+
+ UInt32 GetSize() const { return m_Size; }
+ UInt32 GetFreeSize() const { return m_Size - GetAvailableSize(); }
+ UInt32 GetAvailableSize() const { return m_Put - m_Get; }
+ UInt32 GetAllocatedSize() const { return GetAvailableSize(); }
+
+ void Reset() { m_Get = m_Put = 0; }
+
+protected:
+ void* Ptr(UInt32 position, UInt32 availableBytes, UInt32* nBytes) const;
+
+protected:
+ char* m_Buffer;
+ bool m_OwnMemory;
+ MemLabelId m_OwnMemoryLabel;
+ UInt32 m_Size;
+ volatile UInt32 m_Get;
+ volatile UInt32 m_Put;
+};
+
+// ---------------------------------------------------------------------------
+inline Ringbuffer::Ringbuffer(void* memory, UInt32 size)
+: m_Get(0)
+, m_Put(0)
+{
+ m_Size = 1 << tlsf_fls(size); // use the biggest 2^n size that fits
+ m_Buffer = reinterpret_cast<char*>(memory);
+ m_OwnMemory = false;
+}
+
+inline Ringbuffer::Ringbuffer(MemLabelId label, UInt32 size)
+: m_Get(0)
+, m_Put(0)
+{
+ AssertBreak(size >> 31 == 0);
+ m_Size = 1 << tlsf_fls(size*2 - 1); // make sure we have _at least_ 'size' bytes
+ m_Buffer = reinterpret_cast<char*>(UNITY_MALLOC(label, m_Size));
+ m_OwnMemory = true;
+ m_OwnMemoryLabel = label;
+}
+
+inline Ringbuffer::~Ringbuffer()
+{
+ if (m_OwnMemory)
+ UNITY_FREE(m_OwnMemoryLabel, m_Buffer);
+}
+
+FORCE_INLINE void Ringbuffer::WritePtrUpdate(void* writePtr, UInt32 nBytesWritten)
+{
+ int result = AtomicAdd((volatile int*)&m_Put, nBytesWritten);
+ AssertBreak(writePtr == &m_Buffer[(result - nBytesWritten) & (m_Size - 1)]);
+}
+
+FORCE_INLINE void Ringbuffer::ReadPtrUpdate(const void* readPtr, UInt32 nBytesRead)
+{
+ int result = AtomicAdd((volatile int*)&m_Get, nBytesRead);
+ AssertBreak(readPtr == &m_Buffer[(result - nBytesRead) & (m_Size - 1)]);
+}
+
+FORCE_INLINE void* Ringbuffer::Ptr(UInt32 position, UInt32 bytesAvailable, UInt32* nBytesPtr) const
+{
+ UInt32& nBytes = *nBytesPtr;
+ UInt32 index = position & (m_Size - 1);
+ UInt32 spaceUntilEnd = m_Size - index;
+ UInt32 continousBytesAvailable = std::min(bytesAvailable, spaceUntilEnd);
+ nBytes = std::min(nBytes, continousBytesAvailable);
+ return &m_Buffer[index];
+}
+
+#endif // RUNTIME_CONTAINERS_RINGBUFFER_H