Skip to content

Commit

Permalink
Bit of SimpleFileIO cleanup.
Browse files Browse the repository at this point in the history
  • Loading branch information
coornio committed Nov 23, 2024
1 parent 88dafd6 commit 9866549
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 102 deletions.
6 changes: 6 additions & 0 deletions src/Assistants/Concepts.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,9 @@ concept arithmetic = std::is_arithmetic_v<T>;

template<class T>
concept ar_pointer = std::is_pointer_v<T> && std::is_arithmetic_v<std::remove_pointer_t<T>>;

template <typename T>
concept ContiguousContainer = requires(const T & c) {
{ std::data(c) } -> std::same_as<const typename T::value_type*>;
{ std::size(c) } -> std::convertible_to<std::size_t>;
};
6 changes: 3 additions & 3 deletions src/Assistants/HomeDirManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,12 @@ void HomeDirManager::clearCachedFileData() noexcept {
bool HomeDirManager::validateGameFile(const Path gamePath) noexcept {
std::error_code error;

if (!::doesFileExist(gamePath, &error) || error) {
if (!::doesFileExist(gamePath, error) || error) {
blog.newEntry(BLOG::WARN, "Path is ineligible: {}", error.message());
return false;
}

const auto fileSize{ ::getFileSize(gamePath, &error) };
const auto fileSize{ ::getFileSize(gamePath, error) };
if (error) {
blog.newEntry(BLOG::WARN, "Path is ineligible: {}", error.message());
return false;
Expand All @@ -92,7 +92,7 @@ bool HomeDirManager::validateGameFile(const Path gamePath) noexcept {
return false;
}

mFileData = std::move(::readFileData(gamePath, &error));
mFileData = std::move(::readFileData(gamePath, error));
if (error) {
blog.newEntry(BLOG::WARN, "Path is ineligible: {}", error.message());
return false;
Expand Down
187 changes: 98 additions & 89 deletions src/Assistants/SimpleFileIO.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,81 +9,73 @@
#include <span>
#include <vector>
#include <fstream>
#include <concepts>
#include <filesystem>
#include <type_traits>

#include "Typedefs.hpp"
#include "Concepts.hpp"

/*==================================================================*/

[[maybe_unused]] inline auto getFileModTime(
const Path& filePath,
std::error_code* const ioError = nullptr
) noexcept {
std::error_code error;
const auto modifiedTime{ std::filesystem::last_write_time(filePath, error) };
if (error && ioError) { *ioError = error; }
return modifiedTime;
[[maybe_unused]]
inline auto getFileModTime(const Path& filePath, std::error_code& ioError) noexcept {
ioError.clear();
return std::filesystem::last_write_time(filePath, ioError);
}

[[maybe_unused]] inline auto getFileSize(
const Path& filePath,
std::error_code* const ioError = nullptr
) noexcept {
std::error_code error;
const auto fileSize{ std::filesystem::file_size(filePath, error) };
if (error && ioError) { *ioError = error; }
return fileSize;
[[maybe_unused]]
inline auto getFileModTime(const Path& filePath) noexcept {
std::error_code ioError;
return getFileModTime(filePath, ioError);
}

[[maybe_unused]]
inline auto getFileSize(const Path& filePath, std::error_code& ioError) noexcept {
ioError.clear();
return std::filesystem::file_size(filePath, ioError);
}

[[maybe_unused]]
inline auto getFileSize(const Path& filePath) noexcept {
std::error_code ioError;
return getFileSize(filePath, ioError);
}

/*==================================================================*/

[[maybe_unused]] inline auto doesPathExist(
const Path& filePath,
std::error_code* const ioError = nullptr
) noexcept {
std::error_code error;
[[maybe_unused]]
inline bool doesPathExist(const Path& filePath, std::error_code& ioError) noexcept {
ioError.clear();
return std::filesystem::exists(filePath, ioError);
}

// Check if the path doesn't lead anywhere
if (!std::filesystem::exists(filePath, error) || error) {
if (ioError) { *ioError = error; }
return false;
} else {
return true;
}
[[maybe_unused]]
inline auto doesPathExist(const Path& filePath) noexcept {
std::error_code ioError;
return doesPathExist(filePath, ioError);
}

[[maybe_unused]] inline auto doesFileExist(
const Path& filePath,
std::error_code* const ioError = nullptr
) noexcept {
std::error_code error;
[[maybe_unused]]
inline bool doesFileExist(const Path& filePath, std::error_code& ioError) noexcept {
ioError.clear();
return std::filesystem::is_regular_file(filePath, ioError);
}

// Check if the path doesn't lead to a regular file
if (!std::filesystem::is_regular_file(filePath, error) || error) {
if (ioError) { *ioError = error; }
return false;
} else {
return true;
}
[[maybe_unused]]
inline auto doesFileExist(const Path& filePath) noexcept {
std::error_code ioError;
return doesFileExist(filePath, ioError);
}

/*==================================================================*/

[[maybe_unused]] inline auto readFileData(
const Path& filePath,
std::error_code* const ioError = nullptr
) noexcept {
std::vector<char> fileData{};
std::error_code error;
[[maybe_unused]]
inline auto readFileData(const Path& filePath, std::error_code& ioError) noexcept {
using charVec = std::vector<char>;
charVec fileData{};

// Attempt first file mod time fetch
const auto fileModStampBegin{ ::getFileModTime(filePath, &error) };
if (error) {
if (ioError) { *ioError = error; }
fileData.clear(); return fileData;
}
const auto fileModStampBegin{ ::getFileModTime(filePath, ioError) };
if (ioError) { return charVec{}; }

std::ifstream ifs(filePath, std::ios::binary);

Expand All @@ -93,78 +85,87 @@
// Attempt to read data into vector
fileData.assign(std::istreambuf_iterator(ifs), {});
} catch (const std::exception&) {
if (ioError) { *ioError = std::make_error_code(std::errc::not_enough_memory); }
fileData.clear(); return fileData;
ioError = std::make_error_code(std::errc::not_enough_memory);
return charVec{};
}
// Check if the stream failed to reach EOF safely
if (!ifs.good()) {
if (ioError) { *ioError = std::make_error_code(std::errc::io_error); }
fileData.clear(); return fileData;
ioError = std::make_error_code(std::errc::io_error);
return charVec{};
}
} else {
if (ioError) {
*ioError = std::make_error_code(std::errc::permission_denied);
fileData.clear(); return fileData;
}
ioError = std::make_error_code(std::errc::permission_denied);
return charVec{};
}

// Attempt second file mod time fetch
const auto fileModStampEnd{ ::getFileModTime(filePath, &error) };
if (error) {
if (ioError) { *ioError = error; }
fileData.clear(); return fileData;
}
const auto fileModStampEnd{ ::getFileModTime(filePath, ioError) };
if (ioError) { return charVec{}; }

// Compare times to ensure no modification occurred during read
if (fileModStampBegin != fileModStampEnd) {
if (ioError) { *ioError = std::make_error_code(std::errc::interrupted); }
fileData.clear(); return fileData;
ioError = std::make_error_code(std::errc::interrupted);
return charVec{};
} else {
return fileData;
}
}

[[maybe_unused]]
inline auto readFileData(const Path& filePath) noexcept {
std::error_code ioError;
return readFileData(filePath, ioError);
}

/*==================================================================*/

[[maybe_unused]] inline bool writeFileData(
const Path& filePath,
const void* fileData,
const usz fileSize,
std::error_code* const ioError = nullptr
) noexcept {
[[maybe_unused]]
inline bool writeFileData(const Path& filePath, const void* fileData, const usz fileSize, std::error_code& ioError) noexcept {
std::ofstream ofs(filePath, std::ios::binary);

if (!ofs) { // failed to open file stream
if (ioError) { *ioError = std::make_error_code(std::errc::permission_denied); }
ioError = std::make_error_code(std::errc::permission_denied);
return false;
}

ofs.write(reinterpret_cast<const char*>(fileData), fileSize);

if (!ofs.good()) { // failed to write all data
if (ioError) { *ioError = std::make_error_code(std::errc::io_error); }
ioError = std::make_error_code(std::errc::io_error);
return false;
} else {
return true;
}
}

[[maybe_unused]]
inline auto writeFileData(const Path& filePath, const void* fileData, const usz fileSize) noexcept {
std::error_code ioError;
return writeFileData(filePath, fileData, fileSize, ioError);
}

/*==================================================================*/

template <typename T>
concept ContiguousContainer = requires(const T& c) {
{ std::data(c) } -> std::same_as<const typename T::value_type*>;
{ std::size(c) } -> std::convertible_to<std::size_t>;
};
template <typename T> requires ContiguousContainer<T>
[[maybe_unused]]
inline bool writeFileData(const Path& filePath, const T& fileData, std::error_code& ioError) noexcept {
using typeT = decltype(std::data(fileData));
using elemT = std::remove_cv_t<std::remove_pointer_t<typeT>>;

return writeFileData(
filePath, fileData.data(),
fileData.size() * sizeof(elemT),
ioError
);
}

template <typename T> requires ContiguousContainer<T>
[[maybe_unused]] inline bool writeFileData(
const Path& filePath, const T& fileData,
std::error_code* const ioError = nullptr
) noexcept {
[[maybe_unused]]
inline bool writeFileData(const Path& filePath, const T& fileData) noexcept {
using typeT = decltype(std::data(fileData));
using elemT = std::remove_cv_t<std::remove_pointer_t<typeT>>;

std::error_code ioError;
return writeFileData(
filePath, fileData.data(),
fileData.size() * sizeof(elemT),
Expand All @@ -173,10 +174,18 @@ template <typename T> requires ContiguousContainer<T>
}

template <typename T, usz N>
[[maybe_unused]] inline bool writeFileData(
const Path& filePath, const T(&fileData)[N],
std::error_code* const ioError = nullptr
) noexcept {
[[maybe_unused]]
inline bool writeFileData(const Path& filePath, const T(&fileData)[N], std::error_code& ioError) noexcept {
return writeFileData(
filePath, fileData,
N * sizeof(T), ioError
);
}

template <typename T, usz N>
[[maybe_unused]]
inline bool writeFileData(const Path& filePath, const T(&fileData)[N]) noexcept {
std::error_code ioError;
return writeFileData(
filePath, fileData,
N * sizeof(T), ioError
Expand Down
20 changes: 10 additions & 10 deletions src/Systems/CHIP8/Chip8_CoreInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ bool Chip8_CoreInterface::setPermaRegs(const u32 X) noexcept {
const auto path{ *sPermaRegsPath / HDM->getFileSHA1() };
std::error_code error_code;

const bool fileExists{ doesFileExist(path, &error_code) };
const bool fileExists{ doesFileExist(path, error_code) };
if (error_code) {
blog.newEntry(BLOG::ERROR, "Path is ineligible: \"{}\" [{}]",
path.string(), error_code.message()
Expand All @@ -249,10 +249,10 @@ bool Chip8_CoreInterface::setPermaRegs(const u32 X) noexcept {
}

if (fileExists) {
auto regsData{ readFileData(path, &error_code) };
auto regsData{ readFileData(path, error_code) };

if (error_code) {
blog.newEntry(BLOG::ERROR, "File IO error: \"{}\" [{}]",
blog.newEntry(BLOG::ERROR, "File IO error: \"{}\" [{}]",
path.string(), error_code.message()
);
return false;
Expand All @@ -267,8 +267,8 @@ bool Chip8_CoreInterface::setPermaRegs(const u32 X) noexcept {
regsData.resize(mRegisterV.size());
std::copy_n(mRegisterV.begin(), X, regsData.begin());

if (!writeFileData(path, regsData, &error_code)) {
blog.newEntry(BLOG::ERROR, "File IO error: \"{}\" [{}]",
if (!writeFileData(path, regsData, error_code)) {
blog.newEntry(BLOG::ERROR, "File IO error: \"{}\" [{}]",
path.string(), error_code.message()
);
return false;
Expand All @@ -279,8 +279,8 @@ bool Chip8_CoreInterface::setPermaRegs(const u32 X) noexcept {
char regsData[sizeof(mRegisterV)]{};
std::copy_n(mRegisterV.begin(), X, regsData);

if (!writeFileData(path, regsData, &error_code)) {
blog.newEntry(BLOG::ERROR, "File IO error: \"{}\" [{}]",
if (!writeFileData(path, regsData, error_code)) {
blog.newEntry(BLOG::ERROR, "File IO error: \"{}\" [{}]",
path.string(), error_code.message()
);
return false;
Expand All @@ -294,7 +294,7 @@ bool Chip8_CoreInterface::getPermaRegs(const u32 X) noexcept {
const auto path{ *sPermaRegsPath / HDM->getFileSHA1() };
std::error_code error_code;

const bool fileExists{ doesFileExist(path, &error_code) };
const bool fileExists{ doesFileExist(path, error_code) };
if (error_code) {
blog.newEntry(BLOG::ERROR, "Path is ineligible: \"{}\" [{}]",
path.string(), error_code.message()
Expand All @@ -303,10 +303,10 @@ bool Chip8_CoreInterface::getPermaRegs(const u32 X) noexcept {
}

if (fileExists) {
auto regsData{ readFileData(path, &error_code) };
auto regsData{ readFileData(path, error_code) };

if (error_code) {
blog.newEntry(BLOG::ERROR, "File IO error: \"{}\" [{}]",
blog.newEntry(BLOG::ERROR, "File IO error: \"{}\" [{}]",
path.string(), error_code.message()
);
return false;
Expand Down

0 comments on commit 9866549

Please sign in to comment.