2023-04-03 08:57:51 +00:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <cstdio>
|
|
|
|
#include <string>
|
|
|
|
|
|
|
|
#include "misc.h"
|
|
|
|
|
|
|
|
static void try_close(FILE* file);
|
|
|
|
|
|
|
|
class File {
|
|
|
|
public:
|
|
|
|
// https://stackoverflow.com/a/2173764
|
|
|
|
File(const File&) = delete;
|
|
|
|
File& operator=(const File&) = delete;
|
|
|
|
|
2023-04-10 14:06:27 +00:00
|
|
|
inline File(File&& other) {
|
2023-04-03 08:57:51 +00:00
|
|
|
try_close(this->_file);
|
|
|
|
this->_file = other._file;
|
|
|
|
other._file = nullptr;
|
|
|
|
}
|
2023-04-10 14:06:27 +00:00
|
|
|
inline File& operator=(File&& other) {
|
2023-04-03 08:57:51 +00:00
|
|
|
if (this == &other) {
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
try_close(this->_file);
|
|
|
|
this->_file = other._file;
|
|
|
|
other._file = nullptr;
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
File(const char* __restrict path, const char* __restrict mode) {
|
|
|
|
using namespace std::string_literals;
|
|
|
|
|
|
|
|
this->_file = fopen(path, mode);
|
|
|
|
if (!this->_file) {
|
|
|
|
throw_system_error("fopen("s + quote(path) + ')');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
~File() {
|
|
|
|
try_close(this->_file);
|
|
|
|
}
|
|
|
|
|
|
|
|
void write(const char* data, size_t length) {
|
|
|
|
if (fwrite(data, 1, length, this->_file) != length) {
|
|
|
|
throw_system_error("fwrite()");
|
|
|
|
}
|
|
|
|
}
|
2023-04-10 14:06:27 +00:00
|
|
|
inline void write(const std::string& str) {
|
2023-04-03 08:57:51 +00:00
|
|
|
this->write(str.data(), str.size());
|
|
|
|
}
|
|
|
|
inline constexpr FILE* get() const noexcept {
|
|
|
|
return this->_file;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
FILE* _file = nullptr;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void try_close(FILE* file) {
|
|
|
|
if (file && fclose(file)) {
|
|
|
|
perror("Failed to close a file: fclose()");
|
|
|
|
}
|
|
|
|
}
|