AuroraRuntime/Source/IO/FS/FSCompress.cpp
Jamie Reece Wilson 83f34b0c47 [*] I was right. String views are [mostly] pointless (*)
03:28:55:638  17>2 of 53388 functions (<0.1%) were compiled, the rest were copied from previous compilation.
03:28:55:638  17>  0 functions were new in current compilation
03:28:55:638  17>  65 functions had inline decision re-evaluated but remain unchanged
03:28:56:749  17>Finished generating code

the header of const AuString & is the same as std::string_view therefore nothing changes. in fact, we still need to alloc strings a bunch of times for a zero terminated string. worse, <c++20 always allocs each time we want to access a hashmap with o(1) lookup, making small hashmaps kinda pointless when we always have to alloc+copy (thx std)

perhaps this will help some language binders
2024-04-19 05:58:08 +01:00

266 lines
8.1 KiB
C++

/***
Copyright (C) 2023 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: FSCompress.cpp
Date: 2023-1-26
Author: Reece
***/
#include <Source/RuntimeInternal.hpp>
#include "FS.hpp"
#include "FS.Generic.hpp"
#include <Source/Time/Time.hpp>
namespace Aurora::IO::FS
{
static const AuUInt64 kFileCopyBlock = 0xFFFF * 4; // 64KiB
static auto const kCompressionType = AuCompression::ECompressionType::eZSTD;
static const AuString kStringSuffix = ".zst";
static bool CompressEx2(const AuROString &path, const AuROString &suffix, AuCompression::ECompressionType type, AuInt8 level, bool bCheck)
{
static const auto kCompressionReadChunks = kFileCopyBlock;
if (suffix.empty())
{
SysPushErrorInvalidArgPos2();
return {};
}
if (bCheck)
{
if (AuEndsWith(path, suffix))
{
SysPushErrorIO("File path (\"{}\") ends in {}, yet was requested to be compressed. A user or a developer is probably being stupid.", path, suffix);
return false;
}
}
auto pFileSrc = OpenReadShared(path, EFileAdvisoryLockLevel::eBlockWrite);
if (!pFileSrc)
{
SysPushErrorIO("Couldn't open compression source path: {}", path);
return {};
}
AuString fullA(AuString(path) + AuString(suffix));
auto qwLength = pFileSrc->GetLength();
if (!qwLength)
{
pFileSrc->Close();
return AuFS::Relink(path, fullA);
}
auto pFileDest = OpenWriteShared(fullA, EFileAdvisoryLockLevel::eBlockReadWrite);
if (!pFileDest)
{
SysPushErrorIO("Couldn't open compression destination path: {}{}", path, suffix);
return {};
}
if (pFileDest->GetLength())
{
SysPushErrorIO("File ({}) exists", path);
return {};
}
auto pFileStream = AuMakeShared<AuIO::FS::FileReader>(pFileSrc);
SysCheckNotNullMemory(pFileStream, {});
auto pDestStream = AuMakeShared<AuIO::FS::FileWriter>(pFileDest);
SysCheckNotNullMemory(pDestStream, {});
AuCompression::CompressInfo compress { type };
compress.uCompressionLevel = level;
compress.uInternalStreamSize = kCompressionReadChunks * 2;
auto pCompressor = AuCompression::CompressorUnique(pFileStream, compress);
if (!pCompressor)
{
SysPushErrorMemory("no compressor");
return {};
}
AuUInt64 qwTotalRead {};
{
AuByteBuffer tempMemory(kCompressionReadChunks);
if (!tempMemory)
{
SysPushErrorMemory();
return {};
}
for (AuUInt64 i = 0; i < qwLength; i += 0 /*kCompressionReadChunks*/)
{
auto [read, written] = pCompressor->Ingest(kCompressionReadChunks);
i += read;
if (read == 0)
{
break;
}
qwTotalRead += read;
bool bAnyWritten {};
while (auto uBytes = pCompressor->Read(tempMemory))
{
tempMemory.writePtr += uBytes;
bAnyWritten = true;
AuUInt idc {};
if (AuIO::WriteAll(pDestStream.get(), { tempMemory, idc }) != AuIO::EStreamError::eErrorNone)
{
SysPushErrorIO("AuIO::WriteAll failed");
return {};
}
tempMemory.writePtr = tempMemory.base;
tempMemory.readPtr = tempMemory.base;
}
// zstd u ok?
// if i remove this, we get no data at all.
// even if i try to displace this to above `->Finish()` we still get nothing
// preemptively flushing fixes everything /shrug
pCompressor->Flush();
}
pCompressor->Finish();
while (auto uBytes = pCompressor->Read(tempMemory))
{
tempMemory.writePtr += uBytes;
AuUInt idc {};
if (AuIO::WriteAll(pDestStream.get(), { tempMemory, idc }) != AuIO::EStreamError::eErrorNone)
{
SysPushErrorIO("AuIO::WriteAll failed");
return {};
}
tempMemory.writePtr = tempMemory.base;
tempMemory.readPtr = tempMemory.base;
}
}
return qwTotalRead == qwLength;
}
AUKN_SYM bool CompressEx(const AuROString &path, const AuROString &suffix, AuCompression::ECompressionType type, AuInt8 level)
{
return CompressEx2(path, kStringSuffix, kCompressionType, level, false);
}
AUKN_SYM bool Compress(const AuROString &path, AuInt8 level)
{
return CompressEx2(path, kStringSuffix, kCompressionType, level, true);
}
AUKN_SYM bool DecompressEx(const AuROString &path, const AuROString &suffix, AuCompression::ECompressionType type)
{
static const auto kCompressionReadChunks = kFileCopyBlock;
if (suffix.empty())
{
SysPushErrorInvalidArgPos2();
return {};
}
AuString fullA(AuString(path) + AuString(suffix));
auto pFileSrc = OpenReadShared(fullA, EFileAdvisoryLockLevel::eBlockWrite);
if (!pFileSrc)
{
SysPushErrorIO("Couldn't open compression source path: {}{}", path, suffix);
return {};
}
auto qwLength = pFileSrc->GetLength();
if (!qwLength)
{
pFileSrc->Close();
return AuFS::Relink(fullA, path);
}
auto pFileDest = OpenWriteShared(path, EFileAdvisoryLockLevel::eBlockReadWrite);
if (!pFileDest)
{
SysPushErrorIO("Couldn't open decompression destination path: {}", path);
return {};
}
if (pFileDest->GetLength())
{
SysPushErrorIO("File exists path: {}", path);
return {};
}
auto pFileStream = AuMakeShared<AuIO::FS::FileReader>(pFileSrc);
if (!pFileStream)
{
SysPushErrorMemory();
return {};
}
auto pDestStream = AuMakeShared<AuIO::FS::FileWriter>(pFileDest);
if (!pDestStream)
{
SysPushErrorMemory();
return {};
}
AuCompression::DecompressInfo decompress{ type };
decompress.uInternalStreamSize = kCompressionReadChunks * 5;
auto pDecompressor = AuCompression::DecompressorUnique(pFileStream, decompress);
if (!pDecompressor)
{
SysPushErrorMemory("no decompressor");
return {};
}
AuUInt64 qwTotalRead {};
{
AuByteBuffer tempMemory(kCompressionReadChunks);
if (!tempMemory)
{
SysPushErrorMemory();
return {};
}
for (AuUInt64 i = 0; i < qwLength; i += 0 /*kCompressionReadChunks*/)
{
auto [read, written] = pDecompressor->Ingest(kCompressionReadChunks);
i += read;
if (read == 0)
{
break;
}
qwTotalRead += read;
while (auto uBytes = pDecompressor->Read(tempMemory))
{
tempMemory.writePtr += uBytes;
AuUInt idc {};
if (AuIO::WriteAll(pDestStream.get(), { tempMemory, idc }) != AuIO::EStreamError::eErrorNone)
{
SysPushErrorIO("AuIO::WriteAll failed");
return {};
}
tempMemory.writePtr = tempMemory.base;
tempMemory.readPtr = tempMemory.base;
}
}
}
return qwTotalRead == qwLength;
}
AUKN_SYM bool Decompress(const AuROString &path)
{
return DecompressEx(path, kStringSuffix, kCompressionType);
}
}