#include "fs/BufferedSource.h" #include namespace fs { ////////////////////////////////////////////////////////////////////////// template< typename SourceType> BufferedSource::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 BufferedSource::getLastError() const { tl::optional error = m_optLastError; m_optLastError = tl::nullopt; return error; } ////////////////////////////////////////////////////////////////////////// template< typename SourceType> size_t BufferedSource::read(tl::span 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::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::seekRel(int64_t offset) { if (!offset) return; if (offset != 0) { int64_t newOffset = tell(); newOffset += offset; newOffset = tl::max(newOffset, 0); seekBeg(static_cast(tl::min(newOffset, getSize()))); } } ////////////////////////////////////////////////////////////////////////// template< typename SourceType> uint64_t BufferedSource::tell() const { return m_bufferStartOffset + m_bufferOffset; } ////////////////////////////////////////////////////////////////////////// template< typename SourceType> uint64_t BufferedSource::getSize() const { return m_source.getSize(); } ////////////////////////////////////////////////////////////////////////// template< typename SourceType> bool BufferedSource::isEOS() const { return m_endOfSource; } ////////////////////////////////////////////////////////////////////////// template< typename SourceType> size_t BufferedSource::getPreferredBufferSize() const { return m_buffer.size(); } }