Added utilty functions to read an entire file.

This commit is contained in:
Patrick 2023-11-19 23:45:35 +01:00
parent 0e90cabb7e
commit ce7a7b15c7
2 changed files with 112 additions and 0 deletions

View File

@ -63,6 +63,60 @@ StreamError Stream::writeString(std::string_view str)
return writeSpan(str.begin(), str.end());
}
StreamError Stream::getTotalLength(std::size_t& outLength)
{
const StreamFeatures features = getFeatures();
if (!features.tell || !features.seek) {
return StreamError::NOT_SUPPORTED;
}
const std::size_t origPos = tell();
if (StreamError error = seek(0, SeekMode::RELATIVE_TO_END); error != StreamError::SUCCESS)
{
return error;
}
outLength = tell();
if (StreamError error = seek(static_cast<std::intptr_t>(origPos)); error != StreamError::SUCCESS)
{
return error;
}
return StreamError::SUCCESS;
}
StreamError Stream::readRest(TypelessBuffer& outBuffer)
{
// first try to allocate everything at once
std::size_t length = 0;
if (StreamError lengthError = getTotalLength(length); lengthError == StreamError::SUCCESS)
{
MIJIN_ASSERT(getFeatures().tell, "How did you find the length if you cannot tell()?");
length -= tell();
outBuffer.resize(length);
if (StreamError error = readRaw(outBuffer.data(), length); error != StreamError::SUCCESS)
{
return error;
}
return StreamError::SUCCESS;
}
// could not determine the size, read chunk-wise
static constexpr std::size_t CHUNK_SIZE = 4096;
std::array<std::byte, CHUNK_SIZE> chunk = {};
while (!isAtEnd())
{
std::size_t bytesRead = 0;
if (StreamError error = readRaw(chunk, true, &bytesRead); error != StreamError::SUCCESS)
{
return error;
}
outBuffer.resize(outBuffer.byteSize() + bytesRead);
std::span<std::byte> bufferBytes = outBuffer.makeSpan<std::byte>();
std::copy_n(chunk.begin(), bytesRead, bufferBytes.end() - static_cast<long>(bytesRead));
}
return StreamError::SUCCESS;
}
FileStream::~FileStream()
{
if (handle) {

View File

@ -7,8 +7,10 @@
#include <cassert>
#include <cstdint>
#include <optional>
#include <ranges>
#include <span>
#include <string>
#include "../container/typeless_buffer.hpp"
namespace mijin
{
@ -76,12 +78,26 @@ public:
return readRaw(std::span(ptr, ptr + bytes), partial, outBytesRead);
}
template<std::ranges::contiguous_range TRange>
inline StreamError readRaw(TRange& range, bool partial = false, std::size_t* outBytesRead = nullptr)
{
const std::size_t bytes = std::distance(range.begin(), range.end()) * sizeof(std::ranges::range_value_t<TRange>);
return readRaw(&*range.begin(), bytes, partial, outBytesRead);
}
inline StreamError writeRaw(const void* data, std::size_t bytes)
{
const std::uint8_t* ptr = static_cast<const std::uint8_t*>(data);
return writeRaw(std::span(ptr, ptr + bytes));
}
template<std::ranges::contiguous_range TRange>
inline StreamError writeRaw(const TRange& range)
{
const std::size_t bytes = std::distance(range.begin(), range.end()) * sizeof(std::ranges::range_value_t<TRange>);
return writeRaw(&*range.begin(), bytes);
}
template<typename T>
inline StreamError read(T& value)
{
@ -123,6 +139,12 @@ public:
StreamError readString(std::string& outString);
StreamError writeString(std::string_view str);
StreamError getTotalLength(std::size_t& outLength);
StreamError readRest(TypelessBuffer& outBuffer);
template<typename TChar = char>
StreamError readAsString(std::basic_string<TChar>& outString);
};
class FileStream : public Stream
@ -180,6 +202,42 @@ public:
// public functions
//
template<typename TChar>
StreamError Stream::readAsString(std::basic_string<TChar>& outString)
{
static_assert(sizeof(TChar) == 1, "Can only read to 8-bit character types (char, unsigned char or char8_t");
// first try to allocate everything at once
std::size_t length = 0;
if (StreamError lengthError = getTotalLength(length); lengthError == StreamError::SUCCESS)
{
MIJIN_ASSERT(getFeatures().tell, "How did you find the length if you cannot tell()?");
length -= tell();
outString.resize(length);
if (StreamError error = readRaw(outString.data(), length); error != StreamError::SUCCESS)
{
return error;
}
return StreamError::SUCCESS;
}
// could not determine the size, read chunk-wise
static constexpr std::size_t CHUNK_SIZE = 4096;
std::array<TChar, CHUNK_SIZE> chunk;
outString.clear();
while (!isAtEnd())
{
std::size_t bytesRead = 0;
if (StreamError error = readRaw(chunk, true, &bytesRead); error != StreamError::SUCCESS)
{
return error;
}
outString.append(chunk.data(), chunk.data() + bytesRead);
}
return StreamError::SUCCESS;
}
} // namespace mijin
#endif // !defined(MIJIN_IO_STREAM_HPP_INCLUDED)