Skip to content

Instantly share code, notes, and snippets.

@DimanNe
Created April 9, 2020 07:15
Show Gist options
  • Save DimanNe/d823bee7608f3c3c8b1aa7adac88d178 to your computer and use it in GitHub Desktop.
Save DimanNe/d823bee7608f3c3c8b1aa7adac88d178 to your computer and use it in GitHub Desktop.
#pragma once
#include <filesystem>
class TPath {
template <class SourceOrIter, class Tp = std::filesystem::path &>
using _EnableIfPathable = std::enable_if_t<std::filesystem::__is_pathable<SourceOrIter>::value, Tp>;
public:
using path = std::filesystem::path;
using value_type = path::value_type;
using string_type = path::string_type;
using format = path::format;
static constexpr value_type preferred_separator = '/';
// ==================================================
TPath(const path &p) noexcept: m_Path(p) {}
TPath(path &&p) noexcept: m_Path(std::move(p)) {}
TPath &operator=(const path &p) {
m_Path = p;
return *this;
}
TPath &operator=(path &&p) {
m_Path = std::move(p);
return *this;
}
operator const path &() const &noexcept {
return m_Path;
}
operator path() && noexcept {
return std::move(m_Path);
}
const path &get_path() const noexcept {
return m_Path;
}
// ==================================================
// constructors and destructor
TPath() noexcept {}
TPath(const TPath &p): m_Path(p.m_Path) {}
TPath(TPath &&p) noexcept: m_Path(std::move(p.m_Path)) {}
TPath(string_type &&s, format = format::auto_format) noexcept: m_Path(std::move(s)) {}
template <class Source, class = _EnableIfPathable<Source, void>>
TPath(const Source &src, format = format::auto_format): m_Path(src) {}
template <class Source, class = _EnableIfPathable<Source, void>>
TPath(const Source &src, const std::locale &loc, format = format::auto_format): m_Path(src, loc) {}
template <class InputIt>
TPath(InputIt first, InputIt last, format fmt = format::auto_format): m_Path(first, last, fmt) {}
template <class InputIt>
TPath(InputIt first, InputIt last, const std::locale &loc, format fmt = format::auto_format):
m_Path(first, last, loc, fmt) {}
~TPath() = default;
// assignments
TPath &operator=(const TPath &p) noexcept {
m_Path = p.m_Path;
return *this;
}
TPath &operator=(TPath &&p) noexcept {
m_Path = std::move(p.m_Path);
return *this;
}
template <class = void>
TPath &operator=(string_type &&s) noexcept {
m_Path = std::move(s);
return *this;
}
template <class Source>
_EnableIfPathable<Source> operator=(const Source &src) {
m_Path = src;
}
TPath &assign(string_type &&s) noexcept {
m_Path = std::move(s);
return *this;
}
template <class InputIt>
TPath &assign(InputIt first, InputIt last) {
m_Path.assign(first, last);
return *this;
}
template <class Source>
_EnableIfPathable<Source> assign(const Source &src) {
m_Path.assign(src);
return *this;
}
// appends
TPath &operator/=(const TPath &p) {
if(p.empty())
return *this;
if(has_filename() && p.is_absolute() == false)
m_Path += preferred_separator;
m_Path += p.native();
return *this;
}
// FIXME: Use _LIBCPP_DIAGNOSE_WARNING to produce a diagnostic when __src
// is known at compile time to be "/' since the user almost certainly intended
// to append a separator instead of overwriting the path with "/"
template <class Source>
_EnableIfPathable<Source> operator/=(const Source &src) {
m_Path /= src;
return *this;
}
template <class Source>
_EnableIfPathable<Source> append(const Source &src) {
m_Path.append(src);
return *this;
}
template <class InputIt>
TPath &append(InputIt first, InputIt last) {
m_Path.append(first, last);
return *this;
}
// concatenation
TPath &operator+=(const TPath &x) {
m_Path += x.m_Path;
return *this;
}
TPath &operator+=(const string_type &x) {
m_Path += x;
return *this;
}
TPath &operator+=(std::string_view x) {
m_Path += x;
return *this;
}
TPath &operator+=(const value_type *x) {
m_Path += x;
return *this;
}
TPath &operator+=(value_type x) {
m_Path += x;
return *this;
}
template <class ECharT>
std::enable_if_t<std::filesystem::__can_convert_char<ECharT>::value, TPath &> operator+=(ECharT x) {
m_Path += x;
return *this;
}
template <class Source>
_EnableIfPathable<Source> operator+=(const Source &x) {
m_Path += x;
return *this;
}
template <class Source>
_EnableIfPathable<Source> concat(const Source &x) {
m_Path.concat(x);
return *this;
}
template <class InputIt>
TPath &concat(InputIt first, InputIt last) {
m_Path.concat(first, last);
return *this;
}
// modifiers
void clear() noexcept {
m_Path.clear();
}
TPath &make_preferred() {
m_Path.make_preferred();
return *this;
}
TPath &remove_filename() {
m_Path.remove_filename();
return *this;
}
TPath &replace_filename(const TPath &replacement) {
m_Path.replace_filename(replacement.m_Path);
return *this;
}
TPath &replace_extension(const TPath &replacement = TPath()) {
m_Path.replace_extension(replacement.m_Path);
return *this;
}
void swap(TPath &Another) noexcept {
m_Path.swap(Another.m_Path);
}
// native format observers
const string_type &native() const noexcept {
return m_Path.native();
}
const value_type *c_str() const noexcept {
return m_Path.c_str();
}
operator string_type() const {
return m_Path;
}
template <class ECharT, class Traits = std::char_traits<ECharT>, class Allocator = std::allocator<ECharT>>
std::basic_string<ECharT, Traits, Allocator> string(const Allocator &a = Allocator()) const {
return m_Path.string<ECharT, Traits, Allocator>(a);
}
std::string string() const {
return m_Path.string();
}
std::wstring wstring() const {
return m_Path.wstring();
}
std::string u8string() const {
return m_Path.u8string();
}
std::u16string u16string() const {
return m_Path.u16string();
}
std::u32string u32string() const {
return m_Path.u32string();
}
// generic format observers
template <class ECharT, class Traits = std::char_traits<ECharT>, class Allocator = std::allocator<ECharT>>
std::basic_string<ECharT, Traits, Allocator> generic_string(const Allocator &__a = Allocator()) const {
return m_Path.generic_string<ECharT, Traits, Allocator>(__a);
}
std::string generic_string() const {
return m_Path.generic_string();
}
std::wstring generic_wstring() const {
return m_Path.generic_wstring();
}
std::string generic_u8string() const {
return m_Path.generic_u8string();
}
std::u16string generic_u16string() const {
return m_Path.generic_u16string();
}
std::u32string generic_u32string() const {
return m_Path.generic_u32string();
}
// compare
int compare(const TPath &p) const noexcept {
return m_Path.compare(p.m_Path);
}
int compare(const string_type &__s) const {
return m_Path.compare(__s);
}
int compare(std::string_view __s) const {
return m_Path.compare(__s);
}
int compare(const value_type *__s) const {
return m_Path.compare(__s);
}
// decomposition
TPath root_name() const {
return m_Path.root_name();
}
TPath root_directory() const {
return m_Path.root_directory();
}
TPath root_path() const {
return m_Path.root_path();
}
TPath relative_path() const {
return m_Path.relative_path();
}
TPath parent_path() const {
return m_Path.parent_path();
}
TPath filename() const {
return m_Path.filename();
}
TPath stem() const {
return m_Path.stem();
}
TPath extension() const {
return m_Path.extension();
}
// query
[[nodiscard]] bool empty() const noexcept {
return m_Path.empty();
}
bool has_root_name() const {
return m_Path.has_root_name();
}
bool has_root_directory() const {
return m_Path.has_root_directory();
}
bool has_root_path() const {
return m_Path.has_root_path();
}
bool has_relative_path() const {
return m_Path.has_relative_path();
}
bool has_parent_path() const {
return m_Path.has_parent_path();
}
bool has_filename() const {
return m_Path.has_filename();
}
bool has_stem() const {
return m_Path.has_stem();
}
bool has_extension() const {
return m_Path.has_extension();
}
bool is_absolute() const {
return m_Path.is_absolute();
}
bool is_relative() const {
return m_Path.is_relative();
}
// relative paths
TPath lexically_normal() const {
return m_Path.lexically_normal();
}
TPath lexically_relative(const TPath &base) const {
return m_Path.lexically_relative(base.m_Path);
}
TPath lexically_proximate(const TPath &base) const {
return m_Path.lexically_proximate(base);
}
// iterators
using iterator = path::iterator;
using const_iterator = path::const_iterator;
iterator begin() const {
return m_Path.begin();
}
iterator end() const {
return m_Path.end();
}
template <class CharT, class Traits>
friend std::basic_ostream<CharT, Traits> &operator<<(std::basic_ostream<CharT, Traits> &os,
const TPath & p) {
os << p.m_Path;
return os;
}
template <class CharT, class Traits>
friend std::basic_istream<CharT, Traits> &operator>>(std::basic_istream<CharT, Traits> &is, TPath &p) {
is >> p.m_Path;
return is;
}
friend bool operator==(const TPath &First, const path &Second) noexcept {
return First.m_Path == Second;
}
friend bool operator!=(const TPath &First, const path &Second) noexcept {
return First.m_Path != Second;
}
friend bool operator<(const TPath &First, const path &Second) noexcept {
return First.m_Path < Second;
}
friend bool operator<=(const TPath &First, const path &Second) noexcept {
return First.m_Path <= Second;
}
friend bool operator>(const TPath &First, const path &Second) noexcept {
return First.m_Path > Second;
}
friend bool operator>=(const TPath &First, const path &Second) noexcept {
return First.m_Path >= Second;
}
// friend TPath operator/(const TPath &First, const TPath &Second) {
// TPath Result(First);
// Result /= Second;
// return Result;
// }
friend TPath operator/(const TPath &First, const path &Second) {
// return First / TPath(Second);
TPath Result(First);
Result /= TPath(Second);
return Result;
}
// friend TPath operator/(const path &First, const TPath &Second) {
// return TPath(First) / Second;
// }
template <class T>
friend _EnableIfPathable<T, TPath> operator/(const TPath &First, T &&Second) {
return First / TPath(std::forward<T>(Second));
}
template <class T>
friend _EnableIfPathable<T, TPath> operator/(const path &First, const TPath &Second) {
return TPath(std::forward<T>(First)) / Second;
}
private:
path m_Path;
};
inline void swap(TPath &First, TPath &Second) noexcept {
First.swap(Second);
}
namespace std {
template <>
struct hash<TPath> {
size_t operator()(const TPath &p) const noexcept {
return std::filesystem::hash_value(p);
}
};
} // namespace std
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment