parselink-old/include/parselink/utility/file.h

134 lines
3.2 KiB
C++

//-----------------------------------------------------------------------------
// ___ __ _ _
// / _ \__ _ _ __ ___ ___ / /(_)_ __ | | __
// / /_)/ _` | '__/ __|/ _ \/ / | | '_ \| |/ /
// / ___/ (_| | | \__ \ __/ /__| | | | | <
// \/ \__,_|_| |___/\___\____/_|_| |_|_|\_\ .
//
//-----------------------------------------------------------------------------
// Author: Kurt Sassenrath
// Module: Utility
//
// Utility wrappers for dealing with files.
//
// Copyright (c) 2023 Kurt Sassenrath.
//
// License TBD.
//-----------------------------------------------------------------------------
#ifndef utility_file_8b49e5e471a7c3e5
#define utility_file_8b49e5e471a7c3e5
#include <fmt/format.h>
#include <tl/expected.hpp>
#include <algorithm>
#include <fcntl.h>
#include <system_error>
#include <unistd.h>
#include <vector>
namespace parselink {
namespace utility {
namespace file {
struct [[nodiscard]] handle {
constexpr handle() noexcept = default;
constexpr handle(int fd) noexcept
: fd_(fd) {
if (fd_ < 0) fd_ = -errno;
}
constexpr handle(handle const&) noexcept = delete;
constexpr handle(handle&& other) noexcept
: fd_(other.fd_) {
other.fd_ = -1;
}
constexpr handle& operator=(handle const&) noexcept = delete;
constexpr handle& operator=(handle&& other) noexcept {
close();
fd_ = other.fd_;
return *this;
}
constexpr operator bool() const noexcept { return fd_ >= 0; }
constexpr int operator*() const noexcept { return fd_; }
void close() {
if (*this) {
::close(fd_);
fd_ = -1;
}
}
int fd_{-1};
};
inline tl::expected<handle, std::error_code> open(
std::string_view path, int flags) noexcept {
handle file(::open(std::string{path}.c_str(), flags));
if (file) {
return file;
} else {
return tl::make_unexpected(
std::make_error_code(static_cast<std::errc>(-*file)));
}
}
inline tl::expected<std::vector<std::byte>, std::error_code> read_some(
handle file, std::size_t amount) noexcept {
std::vector<std::byte> data;
if (!file) {
return tl::make_unexpected(
std::make_error_code(static_cast<std::errc>(-*file)));
}
data.resize(amount);
auto amt_read = ::read(*file, data.data(), amount);
if (amt_read < data.size()) {
data.resize(amt_read);
}
return data;
}
template <typename T>
requires(std::is_trivially_default_constructible_v<T> && sizeof(T) == 1)
inline tl::expected<std::vector<T>, std::error_code> read(
handle file) noexcept {
std::vector<T> data;
if (!file) {
return tl::make_unexpected(
std::make_error_code(static_cast<std::errc>(-*file)));
}
auto cur = lseek(*file, 0, SEEK_CUR);
auto end = lseek(*file, 0, SEEK_END);
std::size_t amount = end - cur;
lseek(*file, SEEK_SET, cur);
data.resize(amount);
auto amt_read = ::read(*file, data.data(), amount);
if (amt_read < data.size()) {
data.resize(amt_read);
}
return data;
}
} // namespace file
} // namespace utility
} // namespace parselink
#endif // utility_file_8b49e5e471a7c3e5