2#ifndef BmnReaderCacheManager_h
3#define BmnReaderCacheManager_h
14#include <fairlogger/Logger.h>
25template<
size_t SourceBufferSize = 32 * 1024ull,
size_t DestinationBufferSize = 64 * 1024ull>
28 static_assert(SourceBufferSize >= 32 * 1024ull && DestinationBufferSize >= 32 * 1024ull,
29 "Don't reduce buffer sizes too much as you will lose efficiency!");
30 static_assert(SourceBufferSize <= DestinationBufferSize,
31 "For uncompressing, uncompressed buffers are expected to be bigger than compressed buffers!");
55 [[nodiscard]] inline
bool IsOpen() const noexcept;
56 [[nodiscard]] inline
bool IsGood() const noexcept;
57 [[nodiscard]] inline
bool IsEOF() const noexcept;
58 [[nodiscard]] inline int64_t
Tell() noexcept;
74 void Open(const
std::filesystem::path& inputFile, const
std::ios::openmode inputOpenMode);
89 [[nodiscard]] int64_t
Read(
void* dataToFill, int64_t sizeToFill);
135template<
size_t src,
size_t dst>
141template<
size_t src,
size_t dst>
147template<
size_t src,
size_t dst>
153template<
size_t src,
size_t dst>
159template<
size_t src,
size_t dst>
167template<
size_t src,
size_t dst>
176template<
size_t src,
size_t dst>
182template<
size_t src,
size_t dst>
188template<
size_t src,
size_t dst>
194template<
size_t src,
size_t dst>
200template<
size_t src,
size_t dst>
210template<
size_t src,
size_t dst>
223template<
size_t src,
size_t dst>
225 const std::ios::openmode inputOpenMode)
228 if (!std::filesystem::exists(inputFile) || !std::filesystem::is_regular_file(inputFile)) {
229 LOG(error) <<
"`BmnReaderCacheManager<src, dst>::Open` expects an actual existing file! Passed path: "
230 << inputFile <<
'\n';
233 if (fFileBeingProcessed.is_open()) {
234 LOG(warning) <<
"You are about to open a new file in `BmnReaderCacheManager<src, dst>::Open` while the "
235 "previous one wasn't closed - implicitly calling `Close()`!\n";
238 fRemainingFileSizeToRead = (int64_t)std::filesystem::file_size(inputFile);
239 }
catch (
const std::bad_alloc& errorDescription) {
240 LOG(error) <<
"Filesystem failure! Reason: " << errorDescription.what() <<
'\n';
242 }
catch (
const std::filesystem::filesystem_error& errorDescription) {
243 LOG(error) <<
"Filesystem failure! Reason: " << errorDescription.what() <<
'\n';
246 fFileBeingProcessed.open(inputFile, inputOpenMode);
249template<
size_t src,
size_t dst>
252 if (!fFileBeingProcessed.is_open())
254 fCurrentOutputBufferPosition = 0ull;
255 fTotalOutputBufferFilledSize = 0ull;
256 fCurrentInputBufferPosition = 0ull;
257 fTotalInputBufferFilledSize = 0ull;
258 fRemainingFileSizeToRead = -1ll;
259 fFileBeingProcessed.close();
262template<
size_t tSrcSize,
size_t tDstSize>
265 if (!fFileBeingProcessed.is_open()) {
266 LOG(error) <<
"Calling `BmnReaderCacheManager::Read` while the input file is not ready for it!\n";
273 if (sizeToFill <= 0ll) {
274 LOG(error) <<
"Calling `BmnReaderCacheManager::Read` with `sizeToFill < 0`!\n";
277 size_t dataToFillOffset = 0ull;
278 auto fillTheBuffer = [
this, &dataToFillOffset, dataToFill, &sizeToFill]() {
280 size_t unreadBuffer = fTotalOutputBufferFilledSize - fCurrentOutputBufferPosition;
281 size_t bytesToCopy = unreadBuffer > (size_t)sizeToFill ? (
size_t)sizeToFill : unreadBuffer;
282 std::memcpy((uint8_t*)dataToFill + dataToFillOffset, fArchiveOutputBuffer.data() + fCurrentOutputBufferPosition,
284 fCurrentOutputBufferPosition += bytesToCopy;
285 if (fTotalOutputBufferFilledSize == fCurrentOutputBufferPosition) {
286 fCurrentOutputBufferPosition = 0ull;
287 fTotalOutputBufferFilledSize = 0ull;
289 sizeToFill -= (int64_t)bytesToCopy;
290 dataToFillOffset += bytesToCopy;
292 if (fTotalOutputBufferFilledSize - fCurrentOutputBufferPosition > 0)
294 while (sizeToFill > 0ll && !IsEOF()) {
297 if (!UncompressNextDataChunk()) {
298 LOG(error) <<
"Encountered an error while uncompressing in `BmnReaderCacheManager::Read`... breaking "
299 "unhandled read!\nError reason: "
300 << fOwnerArchiveReference.GetLastUncompressErrorDescription() <<
'\n';
306 return (int64_t)dataToFillOffset;
309template<
size_t src,
size_t dst>
312 fFileBeingProcessed.seekg(value);
315template<
size_t src,
size_t dst>
318 if (!fFileBeingProcessed.is_open()) {
319 LOG(warning) <<
"Calling `BmnReaderCacheManager::MoveToDecompressingLocation` while the input file is not "
324 assert(fTotalInputBufferFilledSize + value >= fOwnerArchiveReference.GetNumberOfDecompressedBytes());
326 if ((
size_t)value <= fOwnerArchiveReference.GetNumberOfDecompressedBytes()) {
327 fCurrentOutputBufferPosition =
328 fTotalOutputBufferFilledSize +
value - fOwnerArchiveReference.GetNumberOfDecompressedBytes();
333 if (!UncompressNextDataChunk())
342template<
size_t tSrcSize,
size_t tDstSize>
345 if (!fFileBeingProcessed.good()) {
348 if (fFileBeingProcessed.eof() && fCurrentInputBufferPosition == fTotalInputBufferFilledSize
349 && !fOwnerArchiveReference.IsStreamInGoodState())
351 LOG(error) <<
"Calling `BmnReaderCacheManager::UncompressNextDataChunk` while the stream is not good!\n";
358 bool shouldReadMoreStreamData =
false;
359 if (fCurrentInputBufferPosition != fTotalInputBufferFilledSize) {
362 if (fCurrentInputBufferPosition != 0
363 && (
double)fCurrentInputBufferPosition > 0.75 * (
double)fTotalInputBufferFilledSize)
365 shouldReadMoreStreamData =
true;
368 size_t nextMax = fTotalInputBufferFilledSize - fCurrentInputBufferPosition;
369 std::memmove(fArchiveSourceBuffer.data(),
370 (uint8_t*)fArchiveSourceBuffer.data() + fCurrentInputBufferPosition, nextMax);
371 fTotalInputBufferFilledSize = nextMax;
372 fCurrentInputBufferPosition = 0ull;
375 fCurrentInputBufferPosition = 0ull;
376 fTotalInputBufferFilledSize = 0ull;
377 shouldReadMoreStreamData =
true;
379 if (!fFileBeingProcessed.eof() && shouldReadMoreStreamData) {
381 fFileBeingProcessed.read(
reinterpret_cast<char*
>(fArchiveSourceBuffer.data()) + fTotalInputBufferFilledSize,
382 (int64_t)(tSrcSize - fTotalInputBufferFilledSize));
385 fTotalInputBufferFilledSize += (size_t)fFileBeingProcessed.gcount();
386 fRemainingFileSizeToRead -= fFileBeingProcessed.gcount();
388 size_t noOfUsedBytes = 0ull;
390 fOwnerArchiveReference.Uncompress(fArchiveSourceBuffer.data() + fCurrentInputBufferPosition,
391 fTotalInputBufferFilledSize - fCurrentInputBufferPosition, noOfUsedBytes,
392 fArchiveOutputBuffer.data(), tDstSize, fTotalOutputBufferFilledSize);
393 fCurrentInputBufferPosition += noOfUsedBytes;
397 LOG(error) <<
"Encountered an error while uncompressing in `BmnReaderCacheManager::Read`... breaking unhandled "
398 "read!\nError reason: "
399 << fOwnerArchiveReference.GetLastUncompressErrorDescription() <<
'\n';
constexpr size_t GetSourceBufferSize() const noexcept
bool UncompressNextDataChunk()
bool IsOpen() const noexcept
BmnReaderCacheManager()=delete
size_t fCurrentOutputBufferPosition
BmnReaderCacheManager(const BmnReaderCacheManager &)=delete
BmnReaderCacheManager & operator==(BmnReaderCacheManager &&)=delete
size_t fCurrentInputBufferPosition
bool IsEOF() const noexcept
constexpr size_t GetDestinationBufferSize() const noexcept
size_t GetTotalOutputBufferFilledSize() const noexcept
size_t GetCurrentInputBufferPosition() const noexcept
int64_t fRemainingFileSizeToRead
BmnIArchiveLibRead & fOwnerArchiveReference
size_t GetCurrentOutputBufferPosition() const noexcept
BmnReaderCacheManager(BmnIArchiveLibRead &)
bool IsGood() const noexcept
void Open(const std::filesystem::path &inputFile, const std::ios::openmode inputOpenMode)
constexpr size_t GetSourceBufferSize() const noexcept
BmnReaderCacheManager & operator=(const BmnReaderCacheManager &)=delete
BmnReaderCacheManager(BmnReaderCacheManager &&)=delete
int64_t Read(void *dataToFill, int64_t sizeToFill)
~BmnReaderCacheManager()=default
size_t GetTotalInputBufferFilledSize() const noexcept
size_t fTotalInputBufferFilledSize
std::array< uint8_t, SourceBufferSize > fArchiveSourceBuffer
void MoveToDecompressingLocation(int64_t value)
size_t fTotalOutputBufferFilledSize
std::ifstream fFileBeingProcessed
std::array< uint8_t, DestinationBufferSize > fArchiveOutputBuffer