First
This commit is contained in:
@@ -0,0 +1,150 @@
|
||||
|
||||
#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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user