Fixed FileStream move semantics.
This commit is contained in:
@@ -313,16 +313,36 @@ StreamError Stream::copyTo(Stream& other)
|
||||
return StreamError::SUCCESS;
|
||||
}
|
||||
|
||||
FileStream::~FileStream()
|
||||
FileStream::FileStream(FileStream&& other) MIJIN_NOEXCEPT
|
||||
: handle_(std::exchange(other.handle_, nullptr)), mode_(other.mode_), length_(other.length_)
|
||||
{
|
||||
if (handle) {
|
||||
|
||||
}
|
||||
|
||||
FileStream::~FileStream() noexcept
|
||||
{
|
||||
if (handle_) {
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
StreamError FileStream::open(const char* path, FileOpenMode mode_)
|
||||
FileStream& FileStream::operator=(FileStream&& other) MIJIN_NOEXCEPT
|
||||
{
|
||||
mode = mode_;
|
||||
if (this != &other)
|
||||
{
|
||||
if (handle_) {
|
||||
close();
|
||||
}
|
||||
handle_ = std::exchange(other.handle_, nullptr);
|
||||
mode_ = other.mode_;
|
||||
length_ = other.length_;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
StreamError FileStream::open(const char* path, FileOpenMode mode)
|
||||
{
|
||||
mode_ = mode;
|
||||
|
||||
const char* modeStr; // NOLINT(cppcoreguidelines-init-variables)
|
||||
switch (mode_)
|
||||
@@ -343,18 +363,18 @@ StreamError FileStream::open(const char* path, FileOpenMode mode_)
|
||||
MIJIN_FATAL("Invalid value for mode.");
|
||||
return StreamError::UNKNOWN_ERROR;
|
||||
}
|
||||
handle = std::fopen(path, modeStr); // NOLINT(cppcoreguidelines-owning-memory)
|
||||
if (!handle && mode_ == FileOpenMode::READ_WRITE) {
|
||||
handle = std::fopen(path, "w+b"); // NOLINT(cppcoreguidelines-owning-memory)
|
||||
handle_ = std::fopen(path, modeStr); // NOLINT(cppcoreguidelines-owning-memory)
|
||||
if (!handle_ && mode_ == FileOpenMode::READ_WRITE) {
|
||||
handle_ = std::fopen(path, "w+b"); // NOLINT(cppcoreguidelines-owning-memory)
|
||||
}
|
||||
if (!handle) {
|
||||
if (!handle_) {
|
||||
return StreamError::IO_ERROR;
|
||||
}
|
||||
|
||||
int result = std::fseek(handle, 0, SEEK_END);
|
||||
int result = std::fseek(handle_, 0, SEEK_END);
|
||||
MIJIN_ASSERT(result == 0, "fseek failed.");
|
||||
length = std::ftell(handle);
|
||||
result = std::fseek(handle, 0, SEEK_SET);
|
||||
length_ = std::ftell(handle_);
|
||||
result = std::fseek(handle_, 0, SEEK_SET);
|
||||
MIJIN_ASSERT(result == 0, "fseek failed.");
|
||||
|
||||
return StreamError::SUCCESS;
|
||||
@@ -362,19 +382,19 @@ StreamError FileStream::open(const char* path, FileOpenMode mode_)
|
||||
|
||||
void FileStream::close()
|
||||
{
|
||||
MIJIN_ASSERT(handle != nullptr, "FileStream is not open.");
|
||||
[[maybe_unused]] const int result = std::fclose(handle); // NOLINT(cppcoreguidelines-owning-memory)
|
||||
MIJIN_ASSERT(handle_ != nullptr, "FileStream is not open.");
|
||||
[[maybe_unused]] const int result = std::fclose(handle_); // NOLINT(cppcoreguidelines-owning-memory)
|
||||
MIJIN_ASSERT(result == 0, "fclose failed.");
|
||||
handle = nullptr;
|
||||
handle_ = nullptr;
|
||||
}
|
||||
|
||||
StreamError FileStream::readRaw(std::span<std::uint8_t> buffer, const ReadOptions& options, std::size_t* outBytesRead)
|
||||
{
|
||||
MIJIN_ASSERT(handle != nullptr, "FileStream is not open.");
|
||||
MIJIN_ASSERT(mode == FileOpenMode::READ || mode == FileOpenMode::READ_WRITE, "Cannot read from this stream");
|
||||
MIJIN_ASSERT(handle_ != nullptr, "FileStream is not open.");
|
||||
MIJIN_ASSERT(mode_ == FileOpenMode::READ || mode_ == FileOpenMode::READ_WRITE, "Cannot read from this stream");
|
||||
|
||||
const std::size_t readBytes = std::fread(buffer.data(), 1, buffer.size(), handle);
|
||||
if (std::ferror(handle)) {
|
||||
const std::size_t readBytes = std::fread(buffer.data(), 1, buffer.size(), handle_);
|
||||
if (std::ferror(handle_)) {
|
||||
return StreamError::IO_ERROR;
|
||||
}
|
||||
if (!options.partial && readBytes < buffer.size()) {
|
||||
@@ -395,28 +415,28 @@ StreamError FileStream::readRaw(std::span<std::uint8_t> buffer, const ReadOption
|
||||
|
||||
StreamError FileStream::writeRaw(std::span<const std::uint8_t> buffer)
|
||||
{
|
||||
MIJIN_ASSERT(handle != nullptr, "FileStream is not open.");
|
||||
MIJIN_ASSERT(mode == FileOpenMode::WRITE || mode == FileOpenMode::READ_WRITE || mode == FileOpenMode::APPEND,
|
||||
MIJIN_ASSERT(handle_ != nullptr, "FileStream is not open.");
|
||||
MIJIN_ASSERT(mode_ == FileOpenMode::WRITE || mode_ == FileOpenMode::READ_WRITE || mode_ == FileOpenMode::APPEND,
|
||||
"Cannot write to this stream");
|
||||
|
||||
const std::size_t written = std::fwrite(buffer.data(), 1, buffer.size(), handle);
|
||||
if (written != buffer.size() || std::ferror(handle)) {
|
||||
const std::size_t written = std::fwrite(buffer.data(), 1, buffer.size(), handle_);
|
||||
if (written != buffer.size() || std::ferror(handle_)) {
|
||||
return StreamError::IO_ERROR;
|
||||
}
|
||||
|
||||
length = std::max<std::size_t>(length, std::ftell(handle));
|
||||
length_ = std::max<std::size_t>(length_, std::ftell(handle_));
|
||||
return StreamError::SUCCESS;
|
||||
}
|
||||
|
||||
std::size_t FileStream::tell()
|
||||
{
|
||||
MIJIN_ASSERT(handle != nullptr, "FileStream is not open.");
|
||||
return std::ftell(handle);
|
||||
MIJIN_ASSERT(handle_ != nullptr, "FileStream is not open.");
|
||||
return std::ftell(handle_);
|
||||
}
|
||||
|
||||
StreamError FileStream::seek(std::intptr_t pos, SeekMode seekMode)
|
||||
{
|
||||
MIJIN_ASSERT(handle != nullptr, "FileStream is not open.");
|
||||
MIJIN_ASSERT(handle_ != nullptr, "FileStream is not open.");
|
||||
int origin; // NOLINT(cppcoreguidelines-init-variables)
|
||||
switch (seekMode)
|
||||
{
|
||||
@@ -433,8 +453,8 @@ StreamError FileStream::seek(std::intptr_t pos, SeekMode seekMode)
|
||||
MIJIN_ERROR("Invalid value passed as seekMode!");
|
||||
return StreamError::UNKNOWN_ERROR;
|
||||
}
|
||||
const int result = std::fseek(handle, static_cast<long>(pos), origin);
|
||||
if (result != 0 || std::ferror(handle)) {
|
||||
const int result = std::fseek(handle_, static_cast<long>(pos), origin);
|
||||
if (result != 0 || std::ferror(handle_)) {
|
||||
return StreamError::IO_ERROR;
|
||||
}
|
||||
return StreamError::SUCCESS;
|
||||
@@ -442,30 +462,30 @@ StreamError FileStream::seek(std::intptr_t pos, SeekMode seekMode)
|
||||
|
||||
void FileStream::flush()
|
||||
{
|
||||
[[maybe_unused]] const int result = std::fflush(handle);
|
||||
[[maybe_unused]] const int result = std::fflush(handle_);
|
||||
MIJIN_ASSERT(result == 0, "fflush failed.");
|
||||
}
|
||||
|
||||
bool FileStream::isAtEnd()
|
||||
{
|
||||
MIJIN_ASSERT(handle != nullptr, "FileStream is not open.");
|
||||
MIJIN_ASSERT(handle_ != nullptr, "FileStream is not open.");
|
||||
|
||||
(void) std::fgetc(handle);
|
||||
if (std::feof(handle)) {
|
||||
(void) std::fgetc(handle_);
|
||||
if (std::feof(handle_)) {
|
||||
return true;
|
||||
}
|
||||
[[maybe_unused]] const int result = std::fseek(handle, -1, SEEK_CUR);
|
||||
[[maybe_unused]] const int result = std::fseek(handle_, -1, SEEK_CUR);
|
||||
MIJIN_ASSERT(result == 0, "fseek failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
StreamFeatures FileStream::getFeatures()
|
||||
{
|
||||
if (handle)
|
||||
if (handle_)
|
||||
{
|
||||
return {
|
||||
.read = (mode == FileOpenMode::READ || mode == FileOpenMode::READ_WRITE),
|
||||
.write = (mode == FileOpenMode::WRITE || mode == FileOpenMode::APPEND || mode == FileOpenMode::READ_WRITE),
|
||||
.read = (mode_ == FileOpenMode::READ || mode_ == FileOpenMode::READ_WRITE),
|
||||
.write = (mode_ == FileOpenMode::WRITE || mode_ == FileOpenMode::APPEND || mode_ == FileOpenMode::READ_WRITE),
|
||||
.tell = true,
|
||||
.seek = true,
|
||||
.readOptions = {
|
||||
|
||||
@@ -306,18 +306,24 @@ public:
|
||||
class FileStream : public Stream
|
||||
{
|
||||
private:
|
||||
std::FILE* handle = nullptr; // TODO: wrap in gsl::owner<>
|
||||
FileOpenMode mode;
|
||||
std::size_t length = 0;
|
||||
std::FILE* handle_ = nullptr; // TODO: wrap in gsl::owner<>
|
||||
FileOpenMode mode_;
|
||||
std::size_t length_ = 0;
|
||||
public:
|
||||
~FileStream() override;
|
||||
FileStream() = default;
|
||||
FileStream(const FileStream&) = delete;
|
||||
FileStream(FileStream&& other) MIJIN_NOEXCEPT;
|
||||
~FileStream() noexcept override;
|
||||
|
||||
StreamError open(const char* path, FileOpenMode mode_);
|
||||
inline StreamError open(const std::string& path, FileOpenMode mode_) {
|
||||
return open(path.c_str(), mode_);
|
||||
FileStream& operator=(const FileStream&) = delete;
|
||||
FileStream& operator=(FileStream&& other) MIJIN_NOEXCEPT;
|
||||
|
||||
StreamError open(const char* path, FileOpenMode mode);
|
||||
inline StreamError open(const std::string& path, FileOpenMode mode) {
|
||||
return open(path.c_str(), mode);
|
||||
}
|
||||
void close();
|
||||
[[nodiscard]] inline bool isOpen() const { return handle != nullptr; }
|
||||
[[nodiscard]] inline bool isOpen() const { return handle_ != nullptr; }
|
||||
|
||||
// Stream overrides
|
||||
StreamError readRaw(std::span<std::uint8_t> buffer, const ReadOptions& options = {}, std::size_t* outBytesRead = nullptr) override;
|
||||
@@ -337,22 +343,45 @@ private:
|
||||
bool canWrite_ = false;
|
||||
public:
|
||||
void openRW(std::span<std::uint8_t> data);
|
||||
template<typename TConcrete>
|
||||
void openRW(const MixinMemoryView<TConcrete>& memoryView) {
|
||||
openRW(memoryView.makeSpan<std::uint8_t>());
|
||||
}
|
||||
template<typename T>
|
||||
void openRO(std::span<T> data) {
|
||||
openROImpl(data.data(), data.size_bytes());
|
||||
}
|
||||
template<typename TChar>
|
||||
inline void openRO(std::basic_string_view<TChar> stringView) {
|
||||
void openRO(std::basic_string_view<TChar> stringView) {
|
||||
openROImpl(stringView.data(), stringView.size() * sizeof(TChar));
|
||||
}
|
||||
template<typename TConcrete>
|
||||
void openRO(const MixinMemoryView<TConcrete>& memoryView) {
|
||||
openRO(memoryView.makeSpan<const std::uint8_t>());
|
||||
}
|
||||
void close();
|
||||
[[nodiscard]] inline bool isOpen() const { return data_.data() != nullptr; }
|
||||
[[nodiscard]] inline std::size_t availableBytes() const
|
||||
[[nodiscard]] bool isOpen() const { return data_.data() != nullptr; }
|
||||
[[nodiscard]] std::size_t availableBytes() const
|
||||
{
|
||||
MIJIN_ASSERT(isOpen(), "MemoryStream is not open.");
|
||||
return data_.size() - pos_;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
std::span<std::uint8_t> data() const
|
||||
{
|
||||
MIJIN_ASSERT(isOpen(), "MemoryStream is not open.");
|
||||
MIJIN_ASSERT(canWrite_, "MemoryStream is read-only.");
|
||||
return data_;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
std::span<const std::uint8_t> constData() const
|
||||
{
|
||||
MIJIN_ASSERT(isOpen(), "MemoryStream is not open.");
|
||||
return data_;
|
||||
}
|
||||
|
||||
// Stream overrides
|
||||
StreamError readRaw(std::span<std::uint8_t> buffer, const ReadOptions& options = {}, std::size_t* outBytesRead = nullptr) override;
|
||||
StreamError writeRaw(std::span<const std::uint8_t> buffer) override;
|
||||
|
||||
Reference in New Issue
Block a user