diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 18:07:22 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 18:07:22 +0000 |
commit | c04dcc2e7d834218ef2d4194331e383402495ae1 (patch) | |
tree | 7333e38d10d75386e60f336b80c2443c1166031d /xbmc/utils/RingBuffer.cpp | |
parent | Initial commit. (diff) | |
download | kodi-c04dcc2e7d834218ef2d4194331e383402495ae1.tar.xz kodi-c04dcc2e7d834218ef2d4194331e383402495ae1.zip |
Adding upstream version 2:20.4+dfsg.upstream/2%20.4+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'xbmc/utils/RingBuffer.cpp')
-rw-r--r-- | xbmc/utils/RingBuffer.cpp | 245 |
1 files changed, 245 insertions, 0 deletions
diff --git a/xbmc/utils/RingBuffer.cpp b/xbmc/utils/RingBuffer.cpp new file mode 100644 index 0000000..454f1f9 --- /dev/null +++ b/xbmc/utils/RingBuffer.cpp @@ -0,0 +1,245 @@ +/* + * Copyright (C) 2010-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "RingBuffer.h" + +#include <algorithm> +#include <cstdlib> +#include <cstring> +#include <mutex> + +/* Constructor */ +CRingBuffer::CRingBuffer() +{ + m_buffer = NULL; + m_size = 0; + m_readPtr = 0; + m_writePtr = 0; + m_fillCount = 0; +} + +/* Destructor */ +CRingBuffer::~CRingBuffer() +{ + Destroy(); +} + +/* Create a ring buffer with the specified 'size' */ +bool CRingBuffer::Create(unsigned int size) +{ + std::unique_lock<CCriticalSection> lock(m_critSection); + m_buffer = (char*)malloc(size); + if (m_buffer != NULL) + { + m_size = size; + return true; + } + return false; +} + +/* Free the ring buffer and set all values to NULL or 0 */ +void CRingBuffer::Destroy() +{ + std::unique_lock<CCriticalSection> lock(m_critSection); + if (m_buffer != NULL) + { + free(m_buffer); + m_buffer = NULL; + } + m_size = 0; + m_readPtr = 0; + m_writePtr = 0; + m_fillCount = 0; +} + +/* Clear the ring buffer */ +void CRingBuffer::Clear() +{ + std::unique_lock<CCriticalSection> lock(m_critSection); + m_readPtr = 0; + m_writePtr = 0; + m_fillCount = 0; +} + +/* Read in data from the ring buffer to the supplied buffer 'buf'. The amount + * read in is specified by 'size'. + */ +bool CRingBuffer::ReadData(char *buf, unsigned int size) +{ + std::unique_lock<CCriticalSection> lock(m_critSection); + if (size > m_fillCount) + { + return false; + } + if (size + m_readPtr > m_size) + { + unsigned int chunk = m_size - m_readPtr; + memcpy(buf, m_buffer + m_readPtr, chunk); + memcpy(buf + chunk, m_buffer, size - chunk); + m_readPtr = size - chunk; + } + else + { + memcpy(buf, m_buffer + m_readPtr, size); + m_readPtr += size; + } + if (m_readPtr == m_size) + m_readPtr = 0; + m_fillCount -= size; + return true; +} + +/* Read in data from the ring buffer to another ring buffer object specified by + * 'rBuf'. + */ +bool CRingBuffer::ReadData(CRingBuffer &rBuf, unsigned int size) +{ + std::unique_lock<CCriticalSection> lock(m_critSection); + if (rBuf.getBuffer() == NULL) + rBuf.Create(size); + + bool bOk = size <= rBuf.getMaxWriteSize() && size <= getMaxReadSize(); + if (bOk) + { + unsigned int chunksize = std::min(size, m_size - m_readPtr); + bOk = rBuf.WriteData(&getBuffer()[m_readPtr], chunksize); + if (bOk && chunksize < size) + bOk = rBuf.WriteData(&getBuffer()[0], size - chunksize); + if (bOk) + SkipBytes(size); + } + + return bOk; +} + +/* Write data to ring buffer from buffer specified in 'buf'. Amount read in is + * specified by 'size'. + */ +bool CRingBuffer::WriteData(const char *buf, unsigned int size) +{ + std::unique_lock<CCriticalSection> lock(m_critSection); + if (size > m_size - m_fillCount) + { + return false; + } + if (size + m_writePtr > m_size) + { + unsigned int chunk = m_size - m_writePtr; + memcpy(m_buffer + m_writePtr, buf, chunk); + memcpy(m_buffer, buf + chunk, size - chunk); + m_writePtr = size - chunk; + } + else + { + memcpy(m_buffer + m_writePtr, buf, size); + m_writePtr += size; + } + if (m_writePtr == m_size) + m_writePtr = 0; + m_fillCount += size; + return true; +} + +/* Write data to ring buffer from another ring buffer object specified by + * 'rBuf'. + */ +bool CRingBuffer::WriteData(CRingBuffer &rBuf, unsigned int size) +{ + std::unique_lock<CCriticalSection> lock(m_critSection); + if (m_buffer == NULL) + Create(size); + + bool bOk = size <= rBuf.getMaxReadSize() && size <= getMaxWriteSize(); + if (bOk) + { + unsigned int readpos = rBuf.getReadPtr(); + unsigned int chunksize = std::min(size, rBuf.getSize() - readpos); + bOk = WriteData(&rBuf.getBuffer()[readpos], chunksize); + if (bOk && chunksize < size) + bOk = WriteData(&rBuf.getBuffer()[0], size - chunksize); + } + + return bOk; +} + +/* Skip bytes in buffer to be read */ +bool CRingBuffer::SkipBytes(int skipSize) +{ + std::unique_lock<CCriticalSection> lock(m_critSection); + if (skipSize < 0) + { + return false; // skipping backwards is not supported + } + + unsigned int size = skipSize; + if (size > m_fillCount) + { + return false; + } + if (size + m_readPtr > m_size) + { + unsigned int chunk = m_size - m_readPtr; + m_readPtr = size - chunk; + } + else + { + m_readPtr += size; + } + if (m_readPtr == m_size) + m_readPtr = 0; + m_fillCount -= size; + return true; +} + +/* Append all content from ring buffer 'rBuf' to this ring buffer */ +bool CRingBuffer::Append(CRingBuffer &rBuf) +{ + return WriteData(rBuf, rBuf.getMaxReadSize()); +} + +/* Copy all content from ring buffer 'rBuf' to this ring buffer overwriting any existing data */ +bool CRingBuffer::Copy(CRingBuffer &rBuf) +{ + Clear(); + return Append(rBuf); +} + +/* Our various 'get' methods */ +char *CRingBuffer::getBuffer() +{ + return m_buffer; +} + +unsigned int CRingBuffer::getSize() +{ + std::unique_lock<CCriticalSection> lock(m_critSection); + return m_size; +} + +unsigned int CRingBuffer::getReadPtr() const +{ + return m_readPtr; +} + +unsigned int CRingBuffer::getWritePtr() +{ + std::unique_lock<CCriticalSection> lock(m_critSection); + return m_writePtr; +} + +unsigned int CRingBuffer::getMaxReadSize() +{ + std::unique_lock<CCriticalSection> lock(m_critSection); + return m_fillCount; +} + +unsigned int CRingBuffer::getMaxWriteSize() +{ + std::unique_lock<CCriticalSection> lock(m_critSection); + return m_size - m_fillCount; +} |