#pragma once #include "prelude/string.hpp" #include class File { public: enum class Mode { WRITE, READ, }; private: File(FILE* handle, Mode mode) : m_handle(handle), m_mode(mode) {} public: static File Open(const StringView& filename, Mode mode) { StringBuilder sb; switch(mode) { case Mode::WRITE: sb.Append('w'); break; case Mode::READ: sb.Append('r'); break; } FILE* handle = fopen(filename.c_str(), sb.c_str()); return File(handle, mode); } private: inline bool Writable() const { return m_mode == File::Mode::WRITE; } inline bool Readable() const { return m_mode == File::Mode::READ; } public: bool Write(const StringView& content) { assert(Writable() && "attempt to write to a file in read only mode"); if (fwrite(content.c_str(), sizeof(char), content.size - 1, m_handle) == 0) { return false; } return true; } public: StringView ReadAll(bool* status = nullptr) { auto fail = [&]() -> StringView { if (status) *status = false; return {}; }; if (status) *status = true; assert(Readable() && "attempt to read from a file in write only mode"); if (fseek(m_handle, 0, SEEK_END) != 0) return fail(); auto size = ftell(m_handle); if (size == -1 && status) return fail(); StringBuilder sb; sb.ensure_extra(size); size_t wrote = fread(sb.data, sizeof(char), size, m_handle); if (wrote == 0) return fail(); sb.size = wrote; return sb.view(); } private: FILE* m_handle; Mode m_mode; };