182 lines
4.5 KiB
C++
182 lines
4.5 KiB
C++
|
|
#pragma once
|
|
|
|
#if !defined(MIJIN_IO_STREAM_HPP_INCLUDED)
|
|
#define MIJIN_IO_STREAM_HPP_INCLUDED 1
|
|
|
|
#include <cassert>
|
|
#include <cstdint>
|
|
#include <optional>
|
|
#include <span>
|
|
#include <string>
|
|
|
|
namespace mijin
|
|
{
|
|
|
|
//
|
|
// public defines
|
|
//
|
|
|
|
//
|
|
// public constants
|
|
//
|
|
|
|
//
|
|
// public types
|
|
//
|
|
|
|
enum class SeekMode
|
|
{
|
|
ABSOLUTE,
|
|
RELATIVE,
|
|
RELATIVE_TO_END
|
|
};
|
|
|
|
struct StreamFeatures
|
|
{
|
|
bool read : 1 = false;
|
|
bool write : 1 = false;
|
|
bool tell : 1 = false;
|
|
bool seek : 1 = false;
|
|
};
|
|
|
|
enum class FileOpenMode
|
|
{
|
|
READ,
|
|
WRITE,
|
|
APPEND,
|
|
READ_WRITE
|
|
};
|
|
|
|
enum class StreamError
|
|
{
|
|
SUCCESS,
|
|
IO_ERROR,
|
|
UNKNOWN_ERROR
|
|
};
|
|
|
|
class Stream
|
|
{
|
|
public:
|
|
virtual ~Stream() = default;
|
|
|
|
public:
|
|
virtual StreamError readRaw(std::span<std::uint8_t> buffer, bool partial = false, std::size_t* outBytesRead = nullptr) = 0;
|
|
virtual StreamError writeRaw(std::span<const std::uint8_t> buffer) = 0;
|
|
virtual std::size_t tell() = 0;
|
|
virtual StreamError seek(std::intptr_t pos, SeekMode seekMode = SeekMode::ABSOLUTE) = 0;
|
|
virtual void flush();
|
|
virtual bool isAtEnd() = 0;
|
|
virtual StreamFeatures getFeatures() = 0;
|
|
|
|
inline StreamError readRaw(void* outData, std::size_t bytes, bool partial = false, std::size_t* outBytesRead = nullptr)
|
|
{
|
|
std::uint8_t* ptr = static_cast<std::uint8_t*>(outData);
|
|
return readRaw(std::span(ptr, ptr + 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<typename T>
|
|
inline StreamError read(T& value)
|
|
{
|
|
return readRaw(&value, sizeof(T));
|
|
}
|
|
|
|
template<typename T>
|
|
inline StreamError readSpan(T& values)
|
|
{
|
|
auto asSpan = std::span(values);
|
|
return readRaw(asSpan.data(), asSpan.size_bytes());
|
|
}
|
|
|
|
template<typename TItBegin, typename TItEnd>
|
|
inline StreamError readSpan(TItBegin&& begin, TItEnd&& end)
|
|
{
|
|
auto asSpan = std::span(std::forward<TItBegin>(begin), std::forward<TItEnd>(end));
|
|
return readRaw(asSpan.data(), asSpan.size_bytes());
|
|
}
|
|
|
|
template<typename T>
|
|
inline StreamError write(const T& value)
|
|
{
|
|
return writeRaw(&value, sizeof(T));
|
|
}
|
|
|
|
template<typename T>
|
|
inline StreamError writeSpan(const T& values)
|
|
{
|
|
auto asSpan = std::span(values);
|
|
return writeRaw(asSpan.data(), asSpan.size_bytes());
|
|
}
|
|
|
|
template<typename TItBegin, typename TItEnd>
|
|
inline StreamError writeSpan(TItBegin&& begin, TItEnd&& end)
|
|
{
|
|
return writeSpan(std::span(std::forward<TItBegin>(begin), std::forward<TItEnd>(end)));
|
|
}
|
|
|
|
StreamError readString(std::string& outString);
|
|
StreamError writeString(std::string_view str);
|
|
};
|
|
|
|
class FileStream : public Stream
|
|
{
|
|
private:
|
|
std::FILE* handle = nullptr; // TODO: wrap in gsl::owner<>
|
|
FileOpenMode mode;
|
|
std::size_t length = 0;
|
|
public:
|
|
~FileStream() override;
|
|
|
|
StreamError open(const char* path, FileOpenMode mode_);
|
|
void close();
|
|
[[nodiscard]] inline bool isOpen() const { return handle != nullptr; }
|
|
|
|
// Stream overrides
|
|
StreamError readRaw(std::span<std::uint8_t> buffer, bool partial = false, std::size_t* outBytesRead = nullptr) override;
|
|
StreamError writeRaw(std::span<const std::uint8_t> buffer) override;
|
|
std::size_t tell() override;
|
|
StreamError seek(std::intptr_t pos, SeekMode seekMode = SeekMode::ABSOLUTE) override;
|
|
void flush() override;
|
|
bool isAtEnd() override;
|
|
StreamFeatures getFeatures() override;
|
|
};
|
|
|
|
class MemoryStream : public Stream
|
|
{
|
|
private:
|
|
std::span<std::uint8_t> data_;
|
|
std::size_t pos_ = 0;
|
|
bool canWrite_ = false;
|
|
public:
|
|
void openRW(std::span<std::uint8_t> data);
|
|
void openRO(std::span<const std::uint8_t> data);
|
|
void close();
|
|
[[nodiscard]] inline bool isOpen() const { return data_.data() != nullptr; }
|
|
[[nodiscard]] inline std::size_t availableBytes() const {
|
|
assert(isOpen());
|
|
return data_.size() - pos_;
|
|
}
|
|
|
|
// Stream overrides
|
|
StreamError readRaw(std::span<std::uint8_t> buffer, bool partial = false, std::size_t* outBytesRead = nullptr) override;
|
|
StreamError writeRaw(std::span<const std::uint8_t> buffer) override;
|
|
std::size_t tell() override;
|
|
StreamError seek(std::intptr_t pos, SeekMode seekMode = SeekMode::ABSOLUTE) override;
|
|
bool isAtEnd() override;
|
|
StreamFeatures getFeatures() override;
|
|
};
|
|
|
|
//
|
|
// public functions
|
|
//
|
|
|
|
} // namespace mijin
|
|
|
|
#endif // !defined(MIJIN_IO_STREAM_HPP_INCLUDED)
|