151 lines
4.3 KiB
C++
151 lines
4.3 KiB
C++
#pragma once
|
|
|
|
#include <string>
|
|
#include <stdexcept>
|
|
#include <filesystem>
|
|
|
|
namespace io {
|
|
using file_time_type = std::filesystem::file_time_type;
|
|
|
|
/// @brief Access violation error
|
|
class access_error : public std::runtime_error {
|
|
public:
|
|
access_error(const std::string& msg) : std::runtime_error(msg) {
|
|
}
|
|
};
|
|
|
|
/// @brief std::filesystem::path project-specific alternative having
|
|
/// `entry_point:path` scheme and solving std::filesystem::path problems:
|
|
/// - implicit std::string conversions depending on compiler
|
|
/// - unicode path construction must be done with std::filesystem::u8path
|
|
class path {
|
|
public:
|
|
path() = default;
|
|
|
|
path(std::string str) : str(std::move(str)) {
|
|
colonPos = this->str.find(':');
|
|
|
|
size_t len = this->str.length();
|
|
for (size_t i = 0; i < len; i++) {
|
|
if (this->str[i] == '\\') {
|
|
this->str[i] = '/';
|
|
}
|
|
}
|
|
}
|
|
|
|
path(const char* str) : path(std::string(str)) {}
|
|
|
|
bool operator==(const std::string& other) const {
|
|
return str == other;
|
|
}
|
|
|
|
bool operator<(const path& other) const {
|
|
return str < other.str;
|
|
}
|
|
|
|
bool operator==(const path& other) const {
|
|
return str == other.str;
|
|
}
|
|
|
|
bool operator==(const char* other) const {
|
|
return str == other;
|
|
}
|
|
|
|
path operator/(const char* child) const {
|
|
if (str.empty() || str[str.length()-1] == ':') {
|
|
return str + std::string(child);
|
|
}
|
|
return str + "/" + std::string(child);
|
|
}
|
|
|
|
path operator/(const std::string& child) const {
|
|
if (str.empty() || str[str.length()-1] == ':') {
|
|
return str + child;
|
|
}
|
|
return str + "/" + child;
|
|
}
|
|
|
|
path operator/(std::string_view child) const {
|
|
if (str.empty() || str[str.length()-1] == ':') {
|
|
return str + std::string(child);
|
|
}
|
|
return str + "/" + std::string(child);
|
|
}
|
|
|
|
path operator/(const path& child) const {
|
|
if (str.empty() || str[str.length()-1] == ':') {
|
|
return str + child.pathPart();
|
|
}
|
|
return str + "/" + child.pathPart();
|
|
}
|
|
|
|
std::string pathPart() const {
|
|
if (colonPos == std::string::npos) {
|
|
return str;
|
|
}
|
|
return str.substr(colonPos + 1);
|
|
}
|
|
|
|
std::string name() const {
|
|
size_t slashpos = str.rfind('/');
|
|
if (slashpos == std::string::npos) {
|
|
return colonPos == std::string::npos ? str
|
|
: str.substr(colonPos + 1);
|
|
}
|
|
return str.substr(slashpos + 1);
|
|
}
|
|
|
|
std::string stem() const {
|
|
return name().substr(0, name().rfind('.'));
|
|
}
|
|
|
|
/// @brief Get extension
|
|
std::string extension() const {
|
|
size_t slashpos = str.rfind('/');
|
|
size_t dotpos = str.rfind('.');
|
|
if (dotpos == std::string::npos ||
|
|
(slashpos != std::string::npos && dotpos < slashpos)) {
|
|
return "";
|
|
}
|
|
return str.substr(dotpos);
|
|
}
|
|
|
|
/// @brief Get entry point
|
|
std::string entryPoint() const {
|
|
checkValid();
|
|
return str.substr(0, colonPos);
|
|
}
|
|
|
|
/// @brief Get parent path
|
|
path parent() const;
|
|
|
|
path normalized() const;
|
|
|
|
std::string string() const {
|
|
return str;
|
|
}
|
|
|
|
/// @brief Check if path is not initialized with 'entry_point:path'
|
|
bool empty() const {
|
|
return str.empty();
|
|
}
|
|
|
|
bool emptyOrInvalid() const {
|
|
return str.empty() || colonPos == std::string::npos;
|
|
}
|
|
private:
|
|
/// @brief UTF-8 string contains entry_point:path or empty string
|
|
std::string str;
|
|
/// @brief Precalculated position of colon character
|
|
size_t colonPos = std::string::npos;
|
|
|
|
void checkValid() const;
|
|
};
|
|
|
|
class PathsGenerator {
|
|
public:
|
|
virtual ~PathsGenerator() = default;
|
|
virtual bool next(path& dst) = 0;
|
|
};
|
|
}
|