Files
FS/include/fs/BufferedSource.inl
jeanlemotan b344afa9fe First
2024-07-02 18:12:23 +02:00

151 lines
3.6 KiB
C++

#include "fs/BufferedSource.h"
#include <algorithm>
namespace fs
{
//////////////////////////////////////////////////////////////////////////
template< typename SourceType>
BufferedSource<SourceType>::BufferedSource(SourceType source, size_t bufferSize)
: m_source(std::move(source))
{
if (bufferSize < 8)
bufferSize = 8;
m_buffer.reserve(bufferSize);
}
//////////////////////////////////////////////////////////////////////////
template< typename SourceType>
tl::optional<Error> BufferedSource<SourceType>::getLastError() const
{
tl::optional<Error> error = m_optLastError;
m_optLastError = tl::nullopt;
return error;
}
//////////////////////////////////////////////////////////////////////////
template< typename SourceType>
size_t BufferedSource<SourceType>::read(tl::span<uint8_t> data)
{
if (data.empty() || m_endOfSource)
return 0;
auto bufferPtr = data.data();
size_t totalSize = 0;
size_t pendingSize = data.size();
while (pendingSize)
{
if (m_buffer.empty() || m_bufferOffset >= m_buffer.size())
{
m_buffer.resize_uninitialized(m_buffer.capacity());
m_bufferStartOffset = m_source.tell();
m_bufferOffset = 0;
const size_t readSize = m_source.read(m_buffer);
m_buffer.resize_uninitialized(readSize);
if (readSize == 0)
{
m_optLastError = m_source.getLastError();
m_endOfSource = !m_optLastError.has_value(); //no error? then EOS
return totalSize;
}
}
TL_ASSERT(m_buffer.size());
TL_ASSERT(m_buffer.size() > m_bufferOffset);
const size_t frameSize = tl::min(m_buffer.size() - m_bufferOffset, pendingSize);
TL_ASSERT(frameSize);
memcpy(bufferPtr, m_buffer.data() + m_bufferOffset, frameSize);
bufferPtr += frameSize;
TL_ASSERT(data.size() >= frameSize);
pendingSize -= frameSize;
totalSize += frameSize;
TL_ASSERT(totalSize <= data.size());
m_bufferOffset += frameSize;
}
m_endOfSource = tell() >= getSize();
return totalSize;
}
//////////////////////////////////////////////////////////////////////////
template< typename SourceType>
void BufferedSource<SourceType>::seekBeg(uint64_t offset)
{
offset = tl::min(offset, m_source.getSize());
if (offset < m_bufferStartOffset || offset >= m_bufferStartOffset + m_buffer.size())
{
m_source.seekBeg(offset);
m_optLastError = m_source.getLastError();
m_buffer.clear();
m_bufferOffset = 0;
m_bufferStartOffset = m_source.tell();
}
else
m_bufferOffset = offset - m_bufferStartOffset;
m_endOfSource = tell() >= getSize();
}
//////////////////////////////////////////////////////////////////////////
template< typename SourceType>
void BufferedSource<SourceType>::seekRel(int64_t offset)
{
if (!offset)
return;
if (offset != 0)
{
int64_t newOffset = tell();
newOffset += offset;
newOffset = tl::max<int64_t>(newOffset, 0);
seekBeg(static_cast<uint64_t>(tl::min<int64_t>(newOffset, getSize())));
}
}
//////////////////////////////////////////////////////////////////////////
template< typename SourceType>
uint64_t BufferedSource<SourceType>::tell() const
{
return m_bufferStartOffset + m_bufferOffset;
}
//////////////////////////////////////////////////////////////////////////
template< typename SourceType>
uint64_t BufferedSource<SourceType>::getSize() const
{
return m_source.getSize();
}
//////////////////////////////////////////////////////////////////////////
template< typename SourceType>
bool BufferedSource<SourceType>::isEOS() const
{
return m_endOfSource;
}
//////////////////////////////////////////////////////////////////////////
template< typename SourceType>
size_t BufferedSource<SourceType>::getPreferredBufferSize() const
{
return m_buffer.size();
}
}