From 3ec51bcb9f9277e955ec400063c88d54e7ae690b Mon Sep 17 00:00:00 2001 From: x12xx12x <44411062+12xx12@users.noreply.github.com> Date: Fri, 17 Jan 2025 17:16:28 +0100 Subject: byte buffer refactor (#5486) * Update ByteBuffer.cpp * Further improvements - more constants - more comments - using smart pointer for memory * More Constants in coordinate writing, Fixed too many bits for mask in y * Changed variable name --- src/ByteBuffer.cpp | 187 ++++++++++++++++++++++++++++++++--------------------- src/ByteBuffer.h | 21 +++--- 2 files changed, 127 insertions(+), 81 deletions(-) diff --git a/src/ByteBuffer.cpp b/src/ByteBuffer.cpp index c5fe0a7c0..1122d6f9c 100644 --- a/src/ByteBuffer.cpp +++ b/src/ByteBuffer.cpp @@ -20,6 +20,53 @@ Unfortunately it is very slow, so it is disabled even for regular DEBUG builds. // #define DEBUG_SINGLE_THREAD_ACCESS +/** Constants encoding some values to reduce the amount of magic numbers */ +namespace VarInt +{ + constexpr unsigned char SEGMENT_BITS = 0x7F; + constexpr unsigned char CONTINUE_BIT = 0x80; + constexpr std::size_t MOVE_BITS = 7; + constexpr std::size_t BYTE_COUNT = 5; // A 32-bit integer can be encoded by at most 5 bytes + constexpr std::size_t BYTE_COUNT_LONG = 10; // A 64-bit integer can be encoded by at most 10 bytes +} + + + + + +namespace Position +{ + // If the bit indicated in the mask is 0, the the matching offset is applied. + constexpr int BIT_MASK_IS_NEGATIVE_XZ = 0x02000000; + constexpr int BIT_MASK_IS_NEGATIVE_Y = 0x0800; + + constexpr int NEGATIVE_OFFSET_XZ = 0x04000000; + constexpr int NEGATIVE_OFFSET_Y = 0x01000; + + // Bit masks when reading the requested bits + constexpr UInt32 BIT_MASK_XZ = 0x03ffffff; // 26 bits + constexpr UInt32 BIT_MASK_Y = 0x0fff; // 12 bits +} + + + + + +namespace XYZPosition +{ + constexpr std::size_t BIT_COUNT_X = 38; + constexpr std::size_t BIT_COUNT_Y = 26; +} + + + + + +namespace XZYPosition +{ + constexpr std::size_t BIT_COUNT_X = 38; + constexpr std::size_t BIT_COUNT_Z = 12; +} @@ -84,10 +131,7 @@ Unfortunately it is very slow, so it is disabled even for regular DEBUG builds. cByteBuffer::cByteBuffer(size_t a_BufferSize) : m_Buffer(new std::byte[a_BufferSize + 1]), - m_BufferSize(a_BufferSize + 1), - m_DataStart(0), - m_WritePos(0), - m_ReadPos(0) + m_BufferSize(a_BufferSize + 1) { // Allocating one byte more than the buffer size requested, so that we can distinguish between // completely-full and completely-empty states @@ -100,8 +144,6 @@ cByteBuffer::cByteBuffer(size_t a_BufferSize) : cByteBuffer::~cByteBuffer() { CheckValid(); - delete[] m_Buffer; - m_Buffer = nullptr; } @@ -114,9 +156,9 @@ bool cByteBuffer::Write(const void * a_Bytes, size_t a_Count) CheckValid(); // Store the current free space for a check after writing: - size_t CurFreeSpace = GetFreeSpace(); + auto CurFreeSpace = GetFreeSpace(); #ifndef NDEBUG - size_t CurReadableSpace = GetReadableSpace(); + auto CurReadableSpace = GetReadableSpace(); size_t WrittenBytes = 0; #endif @@ -125,14 +167,14 @@ bool cByteBuffer::Write(const void * a_Bytes, size_t a_Count) return false; } ASSERT(m_BufferSize >= m_WritePos); - size_t TillEnd = m_BufferSize - m_WritePos; - const char * Bytes = static_cast(a_Bytes); + auto TillEnd = m_BufferSize - m_WritePos; + auto Bytes = static_cast(a_Bytes); if (TillEnd <= a_Count) { // Need to wrap around the ringbuffer end if (TillEnd > 0) { - memcpy(m_Buffer + m_WritePos, Bytes, TillEnd); + memcpy(m_Buffer.get() + m_WritePos, Bytes, TillEnd); Bytes += TillEnd; a_Count -= TillEnd; #ifndef NDEBUG @@ -145,7 +187,7 @@ bool cByteBuffer::Write(const void * a_Bytes, size_t a_Count) // We're guaranteed that we'll fit in a single write op if (a_Count > 0) { - memcpy(m_Buffer + m_WritePos, Bytes, a_Count); + memcpy(m_Buffer.get() + m_WritePos, Bytes, a_Count); m_WritePos += a_Count; #ifndef NDEBUG WrittenBytes += a_Count; @@ -170,12 +212,12 @@ size_t cByteBuffer::GetFreeSpace(void) const // Wrap around the buffer end: ASSERT(m_BufferSize >= m_WritePos); ASSERT((m_BufferSize - m_WritePos + m_DataStart) >= 1); - return m_BufferSize - m_WritePos + m_DataStart - 1; + return m_BufferSize - m_WritePos + m_DataStart - 1; // -1 Offset since the last byte is used to indicate fullness or emptiness. } // Single free space partition: ASSERT(m_BufferSize >= m_WritePos); ASSERT(m_BufferSize - m_WritePos >= 1); - return m_DataStart - m_WritePos - 1; + return m_DataStart - m_WritePos - 1; // -1 Offset since the last byte is used to indicate fullness or emptiness. } @@ -188,7 +230,7 @@ size_t cByteBuffer::GetUsedSpace(void) const CheckValid(); ASSERT(m_BufferSize >= GetFreeSpace()); ASSERT((m_BufferSize - GetFreeSpace()) >= 1); - return m_BufferSize - GetFreeSpace() - 1; + return m_BufferSize - GetFreeSpace() - 1; // -1 Offset since the last byte is used to indicate fullness or emptiness. } @@ -216,7 +258,7 @@ size_t cByteBuffer::GetReadableSpace(void) const bool cByteBuffer::CanBEInt8Represent(int a_Value) { - return (-128 <= a_Value) && (a_Value <= 127); + return (std::numeric_limits::min() <= a_Value) && (a_Value <= std::numeric_limits::max()); } @@ -225,7 +267,7 @@ bool cByteBuffer::CanBEInt8Represent(int a_Value) bool cByteBuffer::CanBEInt16Represent(int a_Value) { - return (-32768 <= a_Value) && (a_Value <= 32767); + return (std::numeric_limits::min() <= a_Value) && (a_Value <= std::numeric_limits::max()); } @@ -420,15 +462,15 @@ bool cByteBuffer::ReadVarInt32(UInt32 & a_Value) CHECK_THREAD CheckValid(); UInt32 Value = 0; - int Shift = 0; - unsigned char b = 0; + std::size_t Shift = 0; + unsigned char CurrentByte = 0; do { NEEDBYTES(1); - ReadBuf(&b, 1); - Value = Value | ((static_cast(b & 0x7f)) << Shift); - Shift += 7; - } while ((b & 0x80) != 0); + ReadBuf(&CurrentByte, 1); + Value |= ((static_cast(CurrentByte & VarInt::SEGMENT_BITS)) << Shift); + Shift += VarInt::MOVE_BITS; + } while ((CurrentByte & VarInt::CONTINUE_BIT) != 0); a_Value = Value; return true; } @@ -448,9 +490,9 @@ bool cByteBuffer::ReadVarInt64(UInt64 & a_Value) { NEEDBYTES(1); ReadBuf(&b, 1); - Value = Value | ((static_cast(b & 0x7f)) << Shift); + Value = Value | ((static_cast(b & VarInt::SEGMENT_BITS)) << Shift); Shift += 7; - } while ((b & 0x80) != 0); + } while ((b & VarInt::CONTINUE_BIT) != 0); a_Value = Value; return true; } @@ -516,14 +558,14 @@ bool cByteBuffer::ReadXYZPosition64(int & a_BlockX, int & a_BlockY, int & a_Bloc } // Convert the 64 received bits into 3 coords: - UInt32 BlockXRaw = (Value >> 38) & 0x03ffffff; // Top 26 bits - UInt32 BlockYRaw = (Value >> 26) & 0x0fff; // Middle 12 bits - UInt32 BlockZRaw = (Value & 0x03ffffff); // Bottom 26 bits + UInt32 BlockXRaw = (Value >> XYZPosition::BIT_COUNT_X) & Position::BIT_MASK_XZ; + UInt32 BlockYRaw = (Value >> XYZPosition::BIT_COUNT_Y) & Position::BIT_MASK_Y; + UInt32 BlockZRaw = (Value & Position::BIT_MASK_XZ); // If the highest bit in the number's range is set, convert the number into negative: - a_BlockX = ((BlockXRaw & 0x02000000) == 0) ? static_cast(BlockXRaw) : -(0x04000000 - static_cast(BlockXRaw)); - a_BlockY = ((BlockYRaw & 0x0800) == 0) ? static_cast(BlockYRaw) : -(0x01000 - static_cast(BlockYRaw)); - a_BlockZ = ((BlockZRaw & 0x02000000) == 0) ? static_cast(BlockZRaw) : -(0x04000000 - static_cast(BlockZRaw)); + a_BlockX = ((BlockXRaw & Position::BIT_MASK_IS_NEGATIVE_XZ) == 0) ? static_cast(BlockXRaw) : -(Position::NEGATIVE_OFFSET_XZ - static_cast(BlockXRaw)); + a_BlockY = ((BlockYRaw & Position::BIT_MASK_IS_NEGATIVE_Y) == 0) ? static_cast(BlockYRaw) : -(Position::NEGATIVE_OFFSET_Y - static_cast(BlockYRaw)); + a_BlockZ = ((BlockZRaw & Position::BIT_MASK_IS_NEGATIVE_XZ) == 0) ? static_cast(BlockZRaw) : -(Position::NEGATIVE_OFFSET_XZ - static_cast(BlockZRaw)); return true; } @@ -550,14 +592,14 @@ bool cByteBuffer::ReadXZYPosition64(int & a_BlockX, int & a_BlockY, int & a_Bloc } // Convert the 64 received bits into 3 coords: - UInt32 BlockXRaw = (Value >> 38) & 0x03ffffff; // Top 26 bits - UInt32 BlockZRaw = (Value >> 12) & 0x03ffffff; // Middle 26 bits - UInt32 BlockYRaw = (Value & 0x0fff); // Bottom 12 bits + UInt32 BlockXRaw = (Value >> XZYPosition::BIT_COUNT_X) & Position::BIT_MASK_XZ; + UInt32 BlockZRaw = (Value >> XZYPosition::BIT_COUNT_Z) & Position::BIT_MASK_XZ; + UInt32 BlockYRaw = (Value & Position::BIT_MASK_Y); // If the highest bit in the number's range is set, convert the number into negative: - a_BlockX = ((BlockXRaw & 0x02000000) == 0) ? static_cast(BlockXRaw) : (static_cast(BlockXRaw) - 0x04000000); - a_BlockY = ((BlockYRaw & 0x0800) == 0) ? static_cast(BlockYRaw) : (static_cast(BlockYRaw) - 0x01000); - a_BlockZ = ((BlockZRaw & 0x02000000) == 0) ? static_cast(BlockZRaw) : (static_cast(BlockZRaw) - 0x04000000); + a_BlockX = ((BlockXRaw & Position::BIT_MASK_IS_NEGATIVE_XZ) == 0) ? static_cast(BlockXRaw) : (static_cast(BlockXRaw) - Position::NEGATIVE_OFFSET_XZ); + a_BlockY = ((BlockYRaw & Position::BIT_MASK_IS_NEGATIVE_Y) == 0) ? static_cast(BlockYRaw) : (static_cast(BlockYRaw) - Position::NEGATIVE_OFFSET_Y); + a_BlockZ = ((BlockZRaw & Position::BIT_MASK_IS_NEGATIVE_XZ) == 0) ? static_cast(BlockZRaw) : (static_cast(BlockZRaw) - Position::NEGATIVE_OFFSET_XZ); return true; } @@ -750,16 +792,17 @@ bool cByteBuffer::WriteVarInt32(UInt32 a_Value) CheckValid(); // A 32-bit integer can be encoded by at most 5 bytes: - unsigned char b[5]; - size_t idx = 0; + std::array Buffer = {}; + std::size_t Pos = 0; do { - b[idx] = (a_Value & 0x7f) | ((a_Value > 0x7f) ? 0x80 : 0x00); - a_Value = a_Value >> 7; - idx++; + // Write to buffer either the raw 7 lsb or the 7 lsb and a bit that indicates the number continues + Buffer[Pos] = ((a_Value & VarInt::SEGMENT_BITS) | ((a_Value > VarInt::SEGMENT_BITS) ? VarInt::CONTINUE_BIT : 0x00)); + a_Value >>= VarInt::MOVE_BITS; + Pos++; } while (a_Value > 0); - return WriteBuf(b, idx); + return WriteBuf(Buffer.data(), Pos); } @@ -772,29 +815,29 @@ bool cByteBuffer::WriteVarInt64(UInt64 a_Value) CheckValid(); // A 64-bit integer can be encoded by at most 10 bytes: - unsigned char b[10]; - size_t idx = 0; + std::array Buffer = {}; + std::size_t Pos = 0; do { - b[idx] = (a_Value & 0x7f) | ((a_Value > 0x7f) ? 0x80 : 0x00); - a_Value = a_Value >> 7; - idx++; + // Write to buffer either the raw 7 lsb or the 7 lsb and a bit that indicates the number continues + Buffer[Pos] = (a_Value & VarInt::SEGMENT_BITS) | ((a_Value > VarInt::SEGMENT_BITS) ? VarInt::CONTINUE_BIT : 0x00); + a_Value = a_Value >> VarInt::MOVE_BITS; + Pos++; } while (a_Value > 0); - return WriteBuf(b, idx); + return WriteBuf(Buffer.data(), Pos); } -bool cByteBuffer::WriteVarUTF8String(const AString & a_Value) +bool cByteBuffer::WriteVarUTF8String(const std::string_view & a_Value) { CHECK_THREAD CheckValid(); PUTBYTES(a_Value.size() + 1); // This is a lower-bound on the bytes that will be actually written. Fail early. - bool res = WriteVarInt32(static_cast(a_Value.size())); - if (!res) + if (!WriteVarInt32(static_cast(a_Value.size()))) { return false; } @@ -810,9 +853,9 @@ bool cByteBuffer::WriteXYZPosition64(Int32 a_BlockX, Int32 a_BlockY, Int32 a_Blo CHECK_THREAD CheckValid(); return WriteBEUInt64( - ((static_cast(a_BlockX) & 0x3FFFFFF) << 38) | - ((static_cast(a_BlockY) & 0xFFF) << 26) | - (static_cast(a_BlockZ) & 0x3FFFFFF) + ((static_cast(a_BlockX) & Position::BIT_MASK_XZ) << XYZPosition::BIT_COUNT_X) | + ((static_cast(a_BlockY) & Position::BIT_MASK_Y) << XYZPosition::BIT_COUNT_Y) | + (static_cast(a_BlockZ) & Position::BIT_MASK_XZ) ); } @@ -825,9 +868,9 @@ bool cByteBuffer::WriteXZYPosition64(Int32 a_BlockX, Int32 a_BlockY, Int32 a_Blo CHECK_THREAD CheckValid(); return WriteBEUInt64( - ((static_cast(a_BlockX) & 0x3FFFFFF) << 38) | - ((static_cast(a_BlockZ) & 0x3FFFFFF) << 12) | - (static_cast(a_BlockY) & 0xFFF) + ((static_cast(a_BlockX) & Position::BIT_MASK_XZ) << XZYPosition::BIT_COUNT_X) | + ((static_cast(a_BlockZ) & Position::BIT_MASK_XZ) << XZYPosition::BIT_COUNT_Z) | + (static_cast(a_BlockY) & Position::BIT_MASK_Y) ); } @@ -840,7 +883,7 @@ bool cByteBuffer::ReadBuf(void * a_Buffer, size_t a_Count) CHECK_THREAD CheckValid(); NEEDBYTES(a_Count); - char * Dst = static_cast(a_Buffer); // So that we can do byte math + auto Dst = static_cast(a_Buffer); // So that we can do byte math ASSERT(m_BufferSize >= m_ReadPos); size_t BytesToEndOfBuffer = m_BufferSize - m_ReadPos; if (BytesToEndOfBuffer <= a_Count) @@ -848,7 +891,7 @@ bool cByteBuffer::ReadBuf(void * a_Buffer, size_t a_Count) // Reading across the ringbuffer end, read the first part and adjust parameters: if (BytesToEndOfBuffer > 0) { - memcpy(Dst, m_Buffer + m_ReadPos, BytesToEndOfBuffer); + memcpy(Dst, m_Buffer.get() + m_ReadPos, BytesToEndOfBuffer); Dst += BytesToEndOfBuffer; a_Count -= BytesToEndOfBuffer; } @@ -858,7 +901,7 @@ bool cByteBuffer::ReadBuf(void * a_Buffer, size_t a_Count) // Read the rest of the bytes in a single read (guaranteed to fit): if (a_Count > 0) { - memcpy(Dst, m_Buffer + m_ReadPos, a_Count); + memcpy(Dst, m_Buffer.get() + m_ReadPos, a_Count); m_ReadPos += a_Count; } return true; @@ -873,13 +916,13 @@ bool cByteBuffer::WriteBuf(const void * a_Buffer, size_t a_Count) CHECK_THREAD CheckValid(); PUTBYTES(a_Count); - const char * Src = static_cast(a_Buffer); // So that we can do byte math + auto Src = static_cast(a_Buffer); // So that we can do byte math ASSERT(m_BufferSize >= m_ReadPos); size_t BytesToEndOfBuffer = m_BufferSize - m_WritePos; if (BytesToEndOfBuffer <= a_Count) { // Reading across the ringbuffer end, read the first part and adjust parameters: - memcpy(m_Buffer + m_WritePos, Src, BytesToEndOfBuffer); + memcpy(m_Buffer.get() + m_WritePos, Src, BytesToEndOfBuffer); Src += BytesToEndOfBuffer; a_Count -= BytesToEndOfBuffer; m_WritePos = 0; @@ -888,7 +931,7 @@ bool cByteBuffer::WriteBuf(const void * a_Buffer, size_t a_Count) // Read the rest of the bytes in a single read (guaranteed to fit): if (a_Count > 0) { - memcpy(m_Buffer + m_WritePos, Src, a_Count); + memcpy(m_Buffer.get() + m_WritePos, Src, a_Count); m_WritePos += a_Count; } return true; @@ -908,7 +951,7 @@ bool cByteBuffer::WriteBuf(size_t a_Count, unsigned char a_Value) if (BytesToEndOfBuffer <= a_Count) { // Reading across the ringbuffer end, read the first part and adjust parameters: - memset(m_Buffer + m_WritePos, a_Value, BytesToEndOfBuffer); + memset(m_Buffer.get() + m_WritePos, a_Value, BytesToEndOfBuffer); a_Count -= BytesToEndOfBuffer; m_WritePos = 0; } @@ -916,7 +959,7 @@ bool cByteBuffer::WriteBuf(size_t a_Count, unsigned char a_Value) // Read the rest of the bytes in a single read (guaranteed to fit): if (a_Count > 0) { - memset(m_Buffer + m_WritePos, a_Value, a_Count); + memset(m_Buffer.get() + m_WritePos, a_Value, a_Count); m_WritePos += a_Count; } return true; @@ -940,7 +983,7 @@ bool cByteBuffer::ReadSome(ContiguousByteBuffer & a_String, size_t a_Count) // Reading across the ringbuffer end, read the first part and adjust parameters: if (BytesToEndOfBuffer > 0) { - a_String.assign(m_Buffer + m_ReadPos, BytesToEndOfBuffer); + a_String.assign(m_Buffer.get() + m_ReadPos, BytesToEndOfBuffer); ASSERT(a_Count >= BytesToEndOfBuffer); a_Count -= BytesToEndOfBuffer; } @@ -950,7 +993,7 @@ bool cByteBuffer::ReadSome(ContiguousByteBuffer & a_String, size_t a_Count) // Read the rest of the bytes in a single read (guaranteed to fit): if (a_Count > 0) { - a_String.append(m_Buffer + m_ReadPos, a_Count); + a_String.append(m_Buffer.get() + m_ReadPos, a_Count); m_ReadPos += a_Count; } return true; @@ -1034,7 +1077,7 @@ void cByteBuffer::ResetRead(void) -void cByteBuffer::ReadAgain(ContiguousByteBuffer & a_Out) +void cByteBuffer::ReadAgain(ContiguousByteBuffer & a_Out) const { // Return the data between m_DataStart and m_ReadPos (the data that has been read but not committed) // Used by ProtoProxy to repeat communication twice, once for parsing and the other time for the remote party @@ -1045,11 +1088,11 @@ void cByteBuffer::ReadAgain(ContiguousByteBuffer & a_Out) { // Across the ringbuffer end, read the first part and adjust next part's start: ASSERT(m_BufferSize >= m_DataStart); - a_Out.append(m_Buffer + m_DataStart, m_BufferSize - m_DataStart); + a_Out.append(m_Buffer.get() + m_DataStart, m_BufferSize - m_DataStart); DataStart = 0; } ASSERT(m_ReadPos >= DataStart); - a_Out.append(m_Buffer + DataStart, m_ReadPos - DataStart); + a_Out.append(m_Buffer.get() + DataStart, m_ReadPos - DataStart); } @@ -1089,7 +1132,7 @@ size_t cByteBuffer::GetVarIntSize(UInt32 a_Value) { // If the value cannot be expressed in 7 bits, it needs to take up another byte Count++; - a_Value >>= 7; + a_Value >>= VarInt::MOVE_BITS; } while (a_Value != 0); return Count; diff --git a/src/ByteBuffer.h b/src/ByteBuffer.h index 664887132..309e7407e 100644 --- a/src/ByteBuffer.h +++ b/src/ByteBuffer.h @@ -32,9 +32,13 @@ class cByteBuffer { public: - cByteBuffer(size_t a_BufferSize); + explicit cByteBuffer(size_t a_BufferSize); ~cByteBuffer(); + /** cByteBuffer should not be copied or moved. Use ReadToByteBuffer instead. */ + cByteBuffer(const cByteBuffer & a_ByteBuffer) = delete; + cByteBuffer(cByteBuffer && a_ByteBuffer) = delete; + /** Writes the bytes specified to the ringbuffer. Returns true if successful, false if not */ bool Write(const void * a_Bytes, size_t a_Count); @@ -111,8 +115,7 @@ public: bool WriteBool (bool a_Value); bool WriteVarInt32 (UInt32 a_Value); bool WriteVarInt64 (UInt64 a_Value); - bool WriteVarUTF8String (const AString & a_Value); // string length as VarInt, then string as UTF-8 - bool WriteLEInt32 (Int32 a_Value); + bool WriteVarUTF8String (const std::string_view & a_Value); // string length as VarInt, then string as UTF-8 bool WriteXYZPosition64 (Int32 a_BlockX, Int32 a_BlockY, Int32 a_BlockZ); bool WriteXZYPosition64 (Int32 a_BlockX, Int32 a_BlockY, Int32 a_BlockZ); @@ -134,7 +137,7 @@ public: /** Reads all available data into a_Data */ void ReadAll(ContiguousByteBuffer & a_Data); - /** Reads the specified number of bytes and writes it into the destinatio bytebuffer. Returns true on success. */ + /** Reads the specified number of bytes and writes it into the destination bytebuffer. Returns true on success. */ bool ReadToByteBuffer(cByteBuffer & a_Dst, size_t a_NumBytes); /** Removes the bytes that have been read from the ringbuffer */ @@ -144,7 +147,7 @@ public: void ResetRead(void); /** Re-reads the data that has been read since the last commit to the current readpos. Used by ProtoProxy to duplicate communication */ - void ReadAgain(ContiguousByteBuffer & a_Out); + void ReadAgain(ContiguousByteBuffer & a_Out) const; /** Checks if the internal state is valid (read and write positions in the correct bounds) using ASSERTs */ void CheckValid(void) const; @@ -154,12 +157,12 @@ public: protected: - std::byte * m_Buffer; + std::unique_ptr m_Buffer; size_t m_BufferSize; // Total size of the ringbuffer - size_t m_DataStart; // Where the data starts in the ringbuffer - size_t m_WritePos; // Where the data ends in the ringbuffer - size_t m_ReadPos; // Where the next read will start in the ringbuffer + size_t m_DataStart = 0; // Where the data starts in the ringbuffer + size_t m_WritePos = 0; // Where the data ends in the ringbuffer + size_t m_ReadPos = 0; // Where the next read will start in the ringbuffer #ifndef NDEBUG /** The ID of the thread currently accessing the object. -- cgit v1.2.3