Created
April 9, 2020 07:15
-
-
Save DimanNe/d823bee7608f3c3c8b1aa7adac88d178 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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