323 lines
8.5 KiB
C++
323 lines
8.5 KiB
C++
#pragma once
|
|
|
|
#include "tl/detail/prologue.h"
|
|
#include <cstddef>
|
|
#include "tl/path_system.h"
|
|
#include "tl/rel_path_view.h"
|
|
#include "tl/detail/path_view_base.h"
|
|
#include "tl/plain_crash.h"
|
|
#include "tl/format.h"
|
|
|
|
namespace tl
|
|
{
|
|
|
|
template<typename PathSystems> class abs_path;
|
|
template<typename PathSystems> class abs_path_view;
|
|
template<typename PathSystems> struct path_view_key_less;
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template<typename PathSystems>
|
|
class abs_path_view : public detail::path_system::path_view_base
|
|
{
|
|
template<typename T> friend class rel_path_view;
|
|
|
|
public:
|
|
using rel_path_view_type = rel_path_view<PathSystems>;
|
|
|
|
abs_path_view() noexcept;
|
|
abs_path_view(int pathSystemId, tl::span<const string> elements) noexcept;
|
|
|
|
abs_path_view(const abs_path_view& other) noexcept;
|
|
|
|
// operators
|
|
abs_path_view& operator=(const abs_path_view& other) noexcept;
|
|
|
|
bool operator==(const abs_path_view& other) const noexcept;
|
|
bool operator!=(const abs_path_view& other) const noexcept;
|
|
|
|
auto operator<=>(const abs_path_view& other) const noexcept;
|
|
|
|
void swap(abs_path_view& other) noexcept;
|
|
|
|
void clear() noexcept;
|
|
string str() const noexcept;
|
|
eastl::string eastl_str() const noexcept;
|
|
std::string std_str() const noexcept;
|
|
|
|
rel_path_view<PathSystems> subpath(size_t idx, int count = 0) const noexcept;
|
|
abs_path_view parent() const noexcept;
|
|
abs_path_view parent(size_t levels) const noexcept;
|
|
bool is_prefix_of(const abs_path_view& path) const noexcept;
|
|
|
|
//This only works if `this` is a prefix of `to`, in other words, only if the resultant path can be expressed as a view of the `to` path
|
|
// This is true when going from a parent to a subfolder
|
|
//Example:
|
|
//Good: ("/a/b/c").prefix_path_to("/a/b/c/d") == ("d")
|
|
//Bad: ("/a/b/c").prefix_path_to("/a/b") == ("") will assert and return empty. It should return ".." but it cannot
|
|
|
|
|
|
rel_path_view<PathSystems> prefix_path_to(const abs_path_view& to) const noexcept;
|
|
|
|
|
|
template <typename T>
|
|
bool is() const noexcept;
|
|
bool is_valid() const noexcept;
|
|
|
|
private:
|
|
int m_pathSystemId = -1;
|
|
friend class abs_path<PathSystems>;
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
namespace tl
|
|
{
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template <typename PathSystems>
|
|
abs_path_view<PathSystems>::abs_path_view() noexcept
|
|
{
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template <typename PathSystems>
|
|
abs_path_view<PathSystems>::abs_path_view(int pathSystemId, tl::span<const string> elements) noexcept
|
|
: path_view_base(elements)
|
|
, m_pathSystemId(pathSystemId)
|
|
{
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template <typename PathSystems>
|
|
abs_path_view<PathSystems>::abs_path_view(const abs_path_view& other) noexcept
|
|
: path_view_base(other)
|
|
, m_pathSystemId(other.m_pathSystemId)
|
|
{
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
template <typename PathSystems>
|
|
abs_path_view<PathSystems>& abs_path_view<PathSystems>::operator=(const abs_path_view& other) noexcept
|
|
{
|
|
m_elements = other.m_elements;
|
|
m_hash = other.m_hash;
|
|
m_pathSystemId = other.m_pathSystemId;
|
|
return *this;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template <typename PathSystems>
|
|
bool abs_path_view<PathSystems>::operator==(const abs_path_view& 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_view<PathSystems>::operator!=(const abs_path_view& other) const noexcept
|
|
{
|
|
return !(*this == other);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template <typename PathSystems>
|
|
void abs_path_view<PathSystems>::clear() noexcept
|
|
{
|
|
m_elements = {};
|
|
m_hash = 0;
|
|
m_pathSystemId = -1;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template<class PathSystems>
|
|
string abs_path_view<PathSystems>::str() const noexcept
|
|
{
|
|
if (!is_valid() && this->empty())
|
|
return {};
|
|
|
|
return PathSystems::template format_abs<string>(m_pathSystemId, this->m_elements);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template<class PathSystems>
|
|
eastl::string abs_path_view<PathSystems>::eastl_str() const noexcept
|
|
{
|
|
if (!is_valid() && this->empty())
|
|
return {};
|
|
|
|
return PathSystems::template format_abs<eastl::string>(m_pathSystemId, this->m_elements);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template<class PathSystems>
|
|
std::string abs_path_view<PathSystems>::std_str() const noexcept
|
|
{
|
|
if (!is_valid() && this->empty())
|
|
return {};
|
|
|
|
return PathSystems::template format_abs<std::string>(m_pathSystemId, this->m_elements);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template <typename PathSystems>
|
|
rel_path_view<PathSystems> abs_path_view<PathSystems>::subpath(size_t idx, int count /* = 0 */) const noexcept
|
|
{
|
|
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())
|
|
return rel_path_view<PathSystems>(tl::span(this->m_elements.begin() + idx, this->m_elements.begin() + idx + count));
|
|
|
|
return {};
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template <typename PathSystems>
|
|
abs_path_view<PathSystems> abs_path_view<PathSystems>::parent() const noexcept
|
|
{
|
|
if (this->empty())
|
|
{
|
|
TL_PLAIN_FAIL("Invalid path");
|
|
return {};
|
|
}
|
|
|
|
abs_path_view p = *this;
|
|
p.pop_back();
|
|
|
|
if (!PathSystems::validate_abs_path(p.m_pathSystemId, p.m_elements))
|
|
{
|
|
TL_PLAIN_FAIL("Invalid path");
|
|
return {};
|
|
}
|
|
|
|
return p;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template <typename PathSystems>
|
|
abs_path_view<PathSystems> abs_path_view<PathSystems>::parent(size_t levels) const noexcept
|
|
{
|
|
if (this->empty() || this->size() <= levels)
|
|
{
|
|
TL_PLAIN_FAIL("Invalid path");
|
|
return {};
|
|
}
|
|
|
|
abs_path_view<PathSystems> p = *this;
|
|
p.shrink(p.size() - levels);
|
|
|
|
return p;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template<class PathSystems>
|
|
template <typename T>
|
|
bool abs_path_view<PathSystems>::is() const noexcept
|
|
{
|
|
return PathSystems::template is<T>(m_pathSystemId);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template<class PathSystems>
|
|
bool abs_path_view<PathSystems>::is_valid() const noexcept
|
|
{
|
|
return m_pathSystemId >= 0;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template<class PathSystems>
|
|
bool abs_path_view<PathSystems>::is_prefix_of(const abs_path_view& 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)[i] != path[i])
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template<class PathSystems>
|
|
rel_path_view<PathSystems> abs_path_view<PathSystems>::prefix_path_to(const abs_path_view& to) const noexcept
|
|
{
|
|
if (this->empty())
|
|
return rel_path_view<PathSystems>(to.m_elements);
|
|
|
|
if (!is_prefix_of(to))
|
|
{
|
|
TL_PLAIN_FAIL("Invalid path");
|
|
return {};
|
|
}
|
|
|
|
return rel_path_view<PathSystems>(tl::span(to.m_elements.begin() + size(), to.m_elements.end()));
|
|
}
|
|
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template <class PathSystems>
|
|
struct std::formatter<tl::abs_path_view<PathSystems>>
|
|
{
|
|
constexpr auto parse(format_parse_context& ctx) noexcept { return ctx.begin(); }
|
|
auto format(const tl::abs_path_view<PathSystems>& p, std::format_context& ctx) const
|
|
{
|
|
return format_to(ctx.out(), "{}", p.str());
|
|
}
|
|
};
|
|
|
|
template <typename T>
|
|
struct std::hash<tl::abs_path_view<T>>
|
|
{
|
|
std::size_t operator()(const tl::abs_path_view<T>& p) const
|
|
{
|
|
return p.hash();
|
|
}
|
|
};
|
|
|
|
|
|
template <typename T>
|
|
struct eastl::hash<tl::abs_path_view<T>>
|
|
{
|
|
std::size_t operator()(const tl::abs_path_view<T>& p) const
|
|
{
|
|
return p.hash();
|
|
}
|
|
};
|
|
|