880 lines
23 KiB
C++
880 lines
23 KiB
C++
#pragma once
|
|
|
|
#include "tl/detail/prologue.h"
|
|
#include <cstddef>
|
|
#include "tl/path_system.h"
|
|
#include "tl/rel_path.h"
|
|
#include "tl/detail/path_base.h"
|
|
#include "tl/plain_crash.h"
|
|
#include "tl/format.h"
|
|
|
|
namespace tl
|
|
{
|
|
|
|
template<typename PathSystems> class abs_path;
|
|
template<typename PathSystems> struct path_key_less;
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template<typename PathSystems>
|
|
class abs_path : public detail::path_system::path_base<PathSystems>
|
|
{
|
|
template<typename T> friend class rel_path;
|
|
|
|
public:
|
|
using rel_path_type = rel_path<PathSystems>;
|
|
|
|
abs_path() noexcept;
|
|
explicit abs_path(const char* path) noexcept;
|
|
abs_path(const char* path, size_t size) noexcept;
|
|
|
|
template<typename Str> requires (!std::is_same_v<Str, const char*> && !std::is_same_v<Str, char*>)
|
|
explicit abs_path(const Str& path) noexcept;
|
|
|
|
abs_path(const abs_path& other) noexcept;
|
|
abs_path(abs_path&& other) noexcept;
|
|
|
|
// operators
|
|
const string& operator[](size_t idx) const noexcept;
|
|
string& operator[](size_t idx) noexcept;
|
|
|
|
abs_path& operator=(const abs_path& other) noexcept;
|
|
abs_path& operator=(abs_path&& other) noexcept;
|
|
|
|
abs_path& operator=(const char* path) noexcept;
|
|
template<typename Str> requires (!std::is_same_v<Str, const char*> && !std::is_same_v<Str, char*>)
|
|
abs_path& operator=(const Str& path) noexcept;
|
|
|
|
abs_path operator+(const char* path) const noexcept;
|
|
abs_path operator+(const rel_path<PathSystems>& path) const noexcept;
|
|
abs_path operator+(rel_path<PathSystems>&& path) const noexcept;
|
|
template<typename Str> requires (!std::is_same_v<Str, const char*> && !std::is_same_v<Str, char*>)
|
|
abs_path operator+(const Str& path) const noexcept;
|
|
|
|
abs_path& operator+=(const char* path) noexcept;
|
|
abs_path& operator+=(const rel_path<PathSystems>& path) noexcept;
|
|
abs_path& operator+=(rel_path<PathSystems>&& path) noexcept;
|
|
template<typename Str> requires (!std::is_same_v<Str, const char*> && !std::is_same_v<Str, char*>)
|
|
abs_path& operator+=(const Str& path) noexcept;
|
|
|
|
bool operator==(const abs_path& other) const noexcept;
|
|
bool operator!=(const abs_path& other) const noexcept;
|
|
|
|
auto operator<=>(const abs_path& other) const noexcept;
|
|
|
|
void swap(abs_path& other) noexcept;
|
|
|
|
void clear() noexcept;
|
|
string str() const noexcept;
|
|
eastl::string eastl_str() const noexcept;
|
|
std::string std_str() const noexcept;
|
|
|
|
rel_path<PathSystems> subpath(size_t idx, int count = 0) const noexcept;
|
|
abs_path parent() const noexcept;
|
|
abs_path parent(size_t levels) const noexcept;
|
|
rel_path<PathSystems> path_to(const abs_path& to) const noexcept;
|
|
void path_to(rel_path<PathSystems>& dst, const abs_path& to) const noexcept;
|
|
bool is_prefix_of(const abs_path& path) const noexcept;
|
|
|
|
template <typename T>
|
|
bool is() const noexcept;
|
|
bool is_valid() const noexcept;
|
|
|
|
bool push_back(string element) noexcept override;
|
|
const string& front() const noexcept;
|
|
const string& back() const noexcept;
|
|
string& front() noexcept;
|
|
string& back() noexcept;
|
|
|
|
void take_elements(tl::vector<string>&& elements) noexcept override;
|
|
|
|
|
|
//Parses a string.
|
|
// 1st attempt is done to parse it as an absolute path. If it succeeds, it returns the path.
|
|
// 2nd attempt is done to parse it as a relative path and if it succeeds, it returns it as fallbackRoot + relative path. This happens ONLY if the fallbackRoot is valid
|
|
template<typename Str>
|
|
static abs_path from_string(const Str& string, const abs_path& fallbackRoot) noexcept;
|
|
|
|
//Parses a string as an absolute path. If it fails it returns an invalid path.
|
|
template<typename Str>
|
|
static abs_path from_string(const Str& string) noexcept;
|
|
|
|
template<typename Str>
|
|
static bool is_valid_string(const Str& string) noexcept;
|
|
template<typename Str>
|
|
static bool has_valid_tag(const Str& string) noexcept;
|
|
|
|
bool parse(const char* path, size_t size) noexcept;
|
|
|
|
private:
|
|
bool collapse_path() noexcept;
|
|
|
|
int m_pathSystemId = -1;
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
namespace tl
|
|
{
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template <typename PathSystems>
|
|
abs_path<PathSystems>::abs_path() noexcept
|
|
{
|
|
m_pathSystemId = -1;
|
|
this->m_hash = 0;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template <typename PathSystems>
|
|
abs_path<PathSystems>::abs_path(const char* path, size_t size) noexcept
|
|
{
|
|
if (!path)
|
|
TL_PLAIN_CRASH("null path in abs_path constructor");
|
|
|
|
if (parse(path, size) == false)
|
|
TL_PLAIN_FAIL("Failed to parse absolute path");
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template <typename PathSystems>
|
|
abs_path<PathSystems>::abs_path(const char* path) noexcept
|
|
{
|
|
if (!path)
|
|
TL_PLAIN_CRASH("null path in abs_path constructor");
|
|
|
|
if (parse(path, strlen(path)) == false)
|
|
TL_PLAIN_FAIL("Failed to parse absolute path");
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template <typename PathSystems>
|
|
template <typename Str> requires (!std::is_same_v<Str, const char*> && !std::is_same_v<Str, char*>)
|
|
abs_path<PathSystems>::abs_path(const Str& path) noexcept
|
|
{
|
|
if (parse(path.data(), path.size()) == false)
|
|
TL_PLAIN_FAIL("Failed to parse absolute path");
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template <typename PathSystems>
|
|
abs_path<PathSystems>::abs_path(const abs_path& other) noexcept
|
|
: m_pathSystemId(other.m_pathSystemId)
|
|
{
|
|
this->m_elements = other.m_elements;
|
|
this->m_hash = other.m_hash;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template <typename PathSystems>
|
|
abs_path<PathSystems>::abs_path(abs_path&& other) noexcept
|
|
: m_pathSystemId(other.m_pathSystemId)
|
|
{
|
|
this->m_elements = std::move(other.m_elements);
|
|
this->m_hash = other.m_hash;
|
|
other.m_hash = 0;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template <typename PathSystems>
|
|
const string& abs_path<PathSystems>::operator[](size_t idx) const noexcept
|
|
{
|
|
return this->m_elements[idx];
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
template <typename PathSystems>
|
|
string& abs_path<PathSystems>::operator[](size_t idx) noexcept
|
|
{
|
|
this->m_hash = 0;
|
|
return this->m_elements[idx];
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
template <typename PathSystems>
|
|
abs_path<PathSystems>& abs_path<PathSystems>::operator=(const abs_path& other) noexcept
|
|
{
|
|
this->m_elements = other.m_elements;
|
|
this->m_hash = other.m_hash;
|
|
m_pathSystemId = other.m_pathSystemId;
|
|
return *this;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template <typename PathSystems>
|
|
abs_path<PathSystems>& abs_path<PathSystems>::operator=(abs_path&& other) noexcept
|
|
{
|
|
std::swap(this->m_elements, other.m_elements);
|
|
std::swap(this->m_hash, other.m_hash);
|
|
std::swap(m_pathSystemId, other.m_pathSystemId);
|
|
return *this;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template <typename PathSystems>
|
|
template<typename Str> requires (!std::is_same_v<Str, const char*> && !std::is_same_v<Str, char*>)
|
|
abs_path<PathSystems>& abs_path<PathSystems>::operator=(const Str& path) noexcept
|
|
{
|
|
if (parse(path.data(), path.size()) == false)
|
|
TL_PLAIN_FAIL("Failed to parse absolute path");
|
|
|
|
return *this;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template <typename PathSystems>
|
|
abs_path<PathSystems>& abs_path<PathSystems>::operator=(const char* path) noexcept
|
|
{
|
|
if (!path)
|
|
TL_PLAIN_CRASH("null path in abs_path assignment");
|
|
|
|
if (parse(path, strlen(path)) == false)
|
|
TL_PLAIN_FAIL("Failed to parse absolute path");
|
|
|
|
return *this;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
template <typename PathSystems>
|
|
abs_path<PathSystems> abs_path<PathSystems>::operator+(const char* path) const noexcept
|
|
{
|
|
if (path && path[0] != '\0')
|
|
{
|
|
abs_path p;
|
|
p.reserve(this->size() + 1);
|
|
p = *this;
|
|
|
|
p += path;
|
|
return p;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template <typename PathSystems>
|
|
template<typename Str> requires (!std::is_same_v<Str, const char*> && !std::is_same_v<Str, char*>)
|
|
abs_path<PathSystems> abs_path<PathSystems>::operator+(const Str& path) const noexcept
|
|
{
|
|
if (!path.empty())
|
|
{
|
|
abs_path p;
|
|
p.reserve(this->size() + 1);
|
|
p = *this;
|
|
|
|
p += path;
|
|
return p;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template <typename PathSystems>
|
|
abs_path<PathSystems> abs_path<PathSystems>::operator+(const rel_path<PathSystems>& path) const noexcept
|
|
{
|
|
if (!path.empty())
|
|
{
|
|
abs_path p;
|
|
p.reserve(this->size() + 1);
|
|
p = *this;
|
|
|
|
p += path;
|
|
return p;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template <typename PathSystems>
|
|
abs_path<PathSystems> abs_path<PathSystems>::operator+(rel_path<PathSystems>&& path) const noexcept
|
|
{
|
|
if (!path.empty())
|
|
{
|
|
abs_path p;
|
|
p.reserve(this->size() + 1);
|
|
p = *this;
|
|
|
|
p += std::move(path);
|
|
return p;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
template <typename PathSystems>
|
|
abs_path<PathSystems>& abs_path<PathSystems>::operator+=(const char* path) noexcept
|
|
{
|
|
if (m_pathSystemId < 0 && this->empty())
|
|
this->operator=(path);
|
|
else if (path && path[0] != '\0')
|
|
*this += rel_path<PathSystems>(path);
|
|
|
|
return *this;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template <typename PathSystems>
|
|
template<typename Str> requires (!std::is_same_v<Str, const char*> && !std::is_same_v<Str, char*>)
|
|
abs_path<PathSystems>& abs_path<PathSystems>::operator+=(const Str& path) noexcept
|
|
{
|
|
if (m_pathSystemId < 0 && this->empty())
|
|
this->operator=(path);
|
|
else if (!path.empty())
|
|
*this += rel_path<PathSystems>(path);
|
|
|
|
return *this;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template <typename PathSystems>
|
|
abs_path<PathSystems>& abs_path<PathSystems>::operator+=(const rel_path<PathSystems>& path) noexcept
|
|
{
|
|
if (!path.empty())
|
|
{
|
|
//use the move version
|
|
*this += rel_path<PathSystems>(path);
|
|
this->collapse_path();
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template <typename PathSystems>
|
|
abs_path<PathSystems>& abs_path<PathSystems>::operator+=(rel_path<PathSystems>&& path) noexcept
|
|
{
|
|
if (!path.empty())
|
|
{
|
|
this->m_elements.reserve(this->m_elements.size() + path.size());
|
|
for (auto& e : path)
|
|
{
|
|
if (!push_back(std::move(e)))
|
|
return *this;
|
|
}
|
|
this->m_hash = 0;
|
|
this->collapse_path();
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
template <typename PathSystems>
|
|
bool abs_path<PathSystems>::operator==(const abs_path& other) const noexcept
|
|
{
|
|
return (!this->m_hash || !other.m_hash || this->m_hash == other.m_hash) &&
|
|
this->m_pathSystemId == other.m_pathSystemId &&
|
|
this->m_elements == other.m_elements;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template <typename PathSystems>
|
|
bool abs_path<PathSystems>::operator!=(const abs_path& other) const noexcept
|
|
{
|
|
return !(*this == other);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template <typename PathSystems>
|
|
auto abs_path<PathSystems>::operator<=>(const abs_path& other) const noexcept
|
|
{
|
|
// return std::compare_three_way{}(this->m_elements, other.m_elements);
|
|
const size_t sz1 = this->m_elements.size();
|
|
const size_t sz2 = other.m_elements.size();
|
|
for (size_t i = 0; i < sz1 && i < sz2; ++i)
|
|
{
|
|
auto r = this->m_elements[i] <=> other.m_elements[i];
|
|
if (r != decltype(r)::equal)
|
|
return r;
|
|
}
|
|
|
|
return sz1 <=> sz2;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template <typename PathSystems>
|
|
bool abs_path<PathSystems>::parse(const char* path, size_t size) noexcept
|
|
{
|
|
this->clear();
|
|
if (size == 0 || !path || path[0] == 0)
|
|
return true;
|
|
|
|
m_pathSystemId = PathSystems::deduce_system_type(path, size);
|
|
if (m_pathSystemId < 0)
|
|
return false;
|
|
|
|
PathSystems::parse_absolute(this->m_elements, m_pathSystemId, path, size);
|
|
for (const string& element : this->m_elements)
|
|
{
|
|
if (!this->validate_element(element))
|
|
{
|
|
this->clear();
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (collapse_path() == false)
|
|
{
|
|
this->clear();
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template <typename PathSystems>
|
|
bool abs_path<PathSystems>::collapse_path() noexcept
|
|
{
|
|
if (this->empty())
|
|
return is_valid();
|
|
|
|
this->m_hash = 0;
|
|
for (size_t i = 0; i < this->m_elements.size();)
|
|
{
|
|
if (i >= 1 &&
|
|
this->m_elements[i] == path_system::back_t::value() &&
|
|
this->m_elements[i - 1] != path_system::back_t::value())
|
|
{
|
|
this->m_elements.erase(this->m_elements.begin() + i - 1, this->m_elements.begin() + i + 1); //remove the .. and the parent
|
|
i -= 1;
|
|
}
|
|
else if (this->m_elements[i] == path_system::current_t::value())
|
|
this->m_elements.erase(this->m_elements.begin() + i); //remove the .
|
|
else
|
|
i++;
|
|
}
|
|
|
|
if (!PathSystems::validate_abs_path(m_pathSystemId, this->m_elements))
|
|
return false;
|
|
|
|
// if the first element is ".." the collapse failed
|
|
if (!this->m_elements.empty() && this->m_elements[0] == path_system::back_t::value())
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template <typename PathSystems>
|
|
void abs_path<PathSystems>::swap(abs_path& other) noexcept
|
|
{
|
|
std::swap(this->m_elements, other.m_elements);
|
|
std::swap(this->m_hash, other.m_hash);
|
|
std::swap(this->m_pathSystemId, other.m_pathSystemId);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template <typename PathSystems>
|
|
void abs_path<PathSystems>::clear() noexcept
|
|
{
|
|
this->m_elements.resize(0);
|
|
this->m_hash = 0;
|
|
m_pathSystemId = -1;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template<class PathSystems>
|
|
string abs_path<PathSystems>::str() const noexcept
|
|
{
|
|
if (!is_valid() && this->empty())
|
|
return {};
|
|
|
|
return PathSystems::template format_absolute<string>(m_pathSystemId, this->m_elements);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template<class PathSystems>
|
|
eastl::string abs_path<PathSystems>::eastl_str() const noexcept
|
|
{
|
|
if (!is_valid() && this->empty())
|
|
return {};
|
|
|
|
return PathSystems::template format_absolute<eastl::string>(m_pathSystemId, this->m_elements);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template<class PathSystems>
|
|
std::string abs_path<PathSystems>::std_str() const noexcept
|
|
{
|
|
if (!is_valid() && this->empty())
|
|
return {};
|
|
|
|
return PathSystems::template format_absolute<std::string>(m_pathSystemId, this->m_elements);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template <typename PathSystems>
|
|
rel_path<PathSystems> abs_path<PathSystems>::subpath(size_t idx, int count /* = 0 */) const noexcept
|
|
{
|
|
rel_path<PathSystems> dst;
|
|
if (count == 0)
|
|
count = (int)this->size() - (int)idx;
|
|
|
|
if (count < 0)
|
|
count = (int)this->size() - (int)idx + count;
|
|
|
|
if (count > 0 && idx < this->size())
|
|
{
|
|
dst.reserve(count);
|
|
for (int i = 0; i < count; i++)
|
|
dst.push_element(this->m_elements[idx + i]);
|
|
}
|
|
return dst;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template <typename PathSystems>
|
|
abs_path<PathSystems> abs_path<PathSystems>::parent() const noexcept
|
|
{
|
|
if (this->empty())
|
|
{
|
|
TL_PLAIN_FAIL("Invalid path");
|
|
return abs_path();
|
|
}
|
|
|
|
abs_path p = *this;
|
|
|
|
if (p.back() == path_system::back_t::value())
|
|
{
|
|
//do not do a pop_back here!!
|
|
//The parent of '/..' is '/../..'!!!
|
|
p.push_back(path_system::back_t::value());
|
|
}
|
|
else
|
|
p.pop_back();
|
|
|
|
if (!PathSystems::validate_abs_path(p.m_pathSystemId, p.m_elements))
|
|
{
|
|
TL_PLAIN_FAIL("Invalid path");
|
|
return abs_path();
|
|
}
|
|
|
|
return p;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template <typename PathSystems>
|
|
abs_path<PathSystems> abs_path<PathSystems>::parent(size_t levels) const noexcept
|
|
{
|
|
if (this->empty() || this->size() <= levels)
|
|
{
|
|
TL_PLAIN_FAIL("Invalid path");
|
|
return abs_path();
|
|
}
|
|
|
|
abs_path p = *this;
|
|
|
|
if (p.back() == path_system::back_t::value())
|
|
{
|
|
//The parent of '/..' is '/../..'!!!
|
|
while (levels > 0)
|
|
{
|
|
levels--;
|
|
p.push_back(path_system::back_t::value());
|
|
}
|
|
}
|
|
else
|
|
p.shrink(p.size() - levels);
|
|
|
|
if (!PathSystems::validate_abs_path(p.m_pathSystemId, p.m_elements))
|
|
{
|
|
TL_PLAIN_FAIL("Invalid path");
|
|
return abs_path();
|
|
}
|
|
|
|
return p;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template<class PathSystems>
|
|
template <typename T>
|
|
bool abs_path<PathSystems>::is() const noexcept
|
|
{
|
|
return PathSystems::template is<T>(m_pathSystemId);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template<class PathSystems>
|
|
inline bool abs_path<PathSystems>::is_valid() const noexcept
|
|
{
|
|
return m_pathSystemId >= 0;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template<class PathSystems>
|
|
rel_path<PathSystems> abs_path<PathSystems>::path_to(const abs_path& to) const noexcept
|
|
{
|
|
rel_path<PathSystems> path;
|
|
path_to(path, to);
|
|
return path;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template<class PathSystems>
|
|
void abs_path<PathSystems>::path_to(rel_path<PathSystems>& dst, const abs_path& to) const noexcept
|
|
{
|
|
dst.clear();
|
|
|
|
if (this->empty())
|
|
{
|
|
dst.reserve(to.size());
|
|
for (string const& element : to)
|
|
dst.push_element(element);
|
|
}
|
|
else if (to.empty())
|
|
{
|
|
//ms relative path from an absolute path to an empty path should be an empty path
|
|
}
|
|
else
|
|
{
|
|
const size_t count = std::min(this->size(), to.size());
|
|
size_t last = 0;
|
|
for (size_t i = 0; i < count; i++)
|
|
{
|
|
if (this->m_elements[i] != to.m_elements[i])
|
|
break;
|
|
last = i + 1;
|
|
}
|
|
|
|
dst.reserve((this->size() - last) + to.size() - last);
|
|
for (size_t i = last; i < this->size(); i++)
|
|
dst.push_element(path_system::back_t::value());
|
|
|
|
for (size_t i = last; i < to.size(); i++)
|
|
dst.push_element(to.m_elements[i]);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template<class PathSystems>
|
|
bool abs_path<PathSystems>::is_prefix_of(const abs_path& path) const noexcept
|
|
{
|
|
if (m_pathSystemId != path.m_pathSystemId)
|
|
return false;
|
|
|
|
if (this->size() > path.size())
|
|
return false;
|
|
|
|
for (size_t i = 0, _count = this->size(); i < _count; ++i)
|
|
{
|
|
if (this->m_elements[i] != path[i])
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template<class PathSystems>
|
|
void abs_path<PathSystems>::take_elements(tl::vector<string>&& elements) noexcept
|
|
{
|
|
clear();
|
|
if (elements.empty())
|
|
return;
|
|
|
|
m_pathSystemId = PathSystems::deduce_system_type(elements.front().data(), elements.front().size());
|
|
if (m_pathSystemId < 0)
|
|
return;
|
|
|
|
detail::path_system::path_base<PathSystems>::take_elements(std::move(elements));
|
|
|
|
if (collapse_path() == false)
|
|
clear();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template<class PathSystems>
|
|
bool abs_path<PathSystems>::push_back(string element) noexcept
|
|
{
|
|
if (m_pathSystemId < 0)
|
|
{
|
|
TL_PLAIN_ASSERT(this->empty());
|
|
m_pathSystemId = PathSystems::deduce_system_type(element.data(), element.size());
|
|
if (m_pathSystemId < 0)
|
|
return false;
|
|
}
|
|
|
|
const bool is_back_element = element == path_system::back_t::value();
|
|
|
|
if (!detail::path_system::path_base<PathSystems>::push_back(std::move(element)))
|
|
return false;
|
|
|
|
if (is_back_element && collapse_path() == false)
|
|
{
|
|
clear();
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template <typename PathSystems>
|
|
const tl::string& abs_path<PathSystems>::back() const noexcept
|
|
{
|
|
TL_PLAIN_ASSERT(!this->empty());
|
|
return this->m_elements.back();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template <typename PathSystems>
|
|
const tl::string& abs_path<PathSystems>::front() const noexcept
|
|
{
|
|
TL_PLAIN_ASSERT(!this->empty());
|
|
return this->m_elements.front();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template<class PathSystems>
|
|
tl::string& abs_path<PathSystems>::front() noexcept
|
|
{
|
|
TL_PLAIN_ASSERT(!this->empty());
|
|
this->m_hash = 0;
|
|
return this->m_elements.front();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template<class PathSystems>
|
|
tl::string& abs_path<PathSystems>::back() noexcept
|
|
{
|
|
TL_PLAIN_ASSERT(!this->empty());
|
|
this->m_hash = 0;
|
|
return this->m_elements.back();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template<class PathSystems>
|
|
template<typename Str>
|
|
abs_path<PathSystems> abs_path<PathSystems>::from_string(const Str& string, const abs_path& fallbackRoot) noexcept
|
|
{
|
|
abs_path outPath;
|
|
if (outPath.parse(string.data(), string.size()))
|
|
return outPath;
|
|
else if (fallbackRoot.is_valid())
|
|
return fallbackRoot + string;
|
|
else
|
|
return abs_path();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template<class PathSystems>
|
|
template<typename Str>
|
|
abs_path<PathSystems> abs_path<PathSystems>::from_string(const Str& string) noexcept
|
|
{
|
|
abs_path outPath;
|
|
if (outPath.parse(string.data(), string.size()))
|
|
return outPath;
|
|
|
|
return abs_path();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template<class PathSystems>
|
|
template<typename Str>
|
|
bool abs_path<PathSystems>::is_valid_string(const Str& string) noexcept
|
|
{
|
|
abs_path outPath;
|
|
return outPath.parse(string.data(), string.size());
|
|
}
|
|
|
|
template<class PathSystems>
|
|
template<typename Str>
|
|
bool abs_path<PathSystems>::has_valid_tag(const Str& string) noexcept
|
|
{
|
|
if (string.empty())
|
|
return false;
|
|
|
|
const int pathSystemId = PathSystems::deduce_system_type(string.data(), string.size());
|
|
return pathSystemId >= 0;
|
|
}
|
|
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template <class PathSystems>
|
|
struct std::formatter<tl::abs_path<PathSystems>>
|
|
{
|
|
constexpr auto parse(format_parse_context& ctx) noexcept { return ctx.begin(); }
|
|
auto format(const tl::abs_path<PathSystems>& p, std::format_context& ctx) const
|
|
{
|
|
return format_to(ctx.out(), "{}", p.str());
|
|
}
|
|
};
|
|
|
|
template <typename T>
|
|
void swap(tl::abs_path<T>& a, tl::abs_path<T>& b) noexcept
|
|
{
|
|
a.swap(b);
|
|
}
|
|
|
|
template <typename T>
|
|
struct std::hash<tl::abs_path<T>>
|
|
{
|
|
std::size_t operator()(const tl::abs_path<T>& p) const
|
|
{
|
|
return p.hash();
|
|
}
|
|
};
|
|
|
|
|
|
template <typename T>
|
|
struct eastl::hash<tl::abs_path<T>>
|
|
{
|
|
std::size_t operator()(const tl::abs_path<T>& p) const
|
|
{
|
|
return p.hash();
|
|
}
|
|
};
|
|
|