384 lines
12 KiB
C++
384 lines
12 KiB
C++
#pragma once
|
|
|
|
#include "tl/detail/prologue.h"
|
|
#include <EASTL/fixed_vector.h>
|
|
#include "tl/string.h"
|
|
#include "tl/string.h"
|
|
|
|
namespace tl
|
|
{
|
|
namespace detail
|
|
{
|
|
namespace path_system
|
|
{
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template<typename T>
|
|
void simple_format_rel_path(T& o_buffer, const tl::vector<string>& members, const char* separator) noexcept;
|
|
template<typename T>
|
|
void simple_format_abs_path(T& o_buffer, const tl::vector<string>& members, const char* root_tag, const char* separator) noexcept;
|
|
|
|
inline bool find_next_separator(const char* const* separators_begin, const char* const* separators_end, const char*& io_startIt, const char* end, const char*& io_endIt) noexcept;
|
|
|
|
inline tl::vector<string> simple_parse_path(const char* path, const char* root_tag, const tl::vector<const char*>& separators) noexcept;
|
|
|
|
inline bool simple_match_prefix(const char* path, const char* prefix) noexcept;
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template<int Index, typename... Tail>
|
|
struct path_system_getter
|
|
{
|
|
template<typename T>
|
|
static T format_absolute(int type_idx, const tl::vector<string>& members) noexcept;
|
|
static void parse_absolute(tl::vector<string>& o_elements, int type_idx, const char* path, size_t size) noexcept;
|
|
static int deduce_system_type(const char* path, size_t size) noexcept;
|
|
static bool validate_abs_path(int type_idx, const tl::vector<string>& members) noexcept;
|
|
};
|
|
|
|
// specialization if Head element exists
|
|
template<int Index, typename Head, typename... Tail>
|
|
struct path_system_getter<Index, Head, Tail...>
|
|
{
|
|
template<typename T>
|
|
static T format_absolute(int type_idx, const tl::vector<string>& members) noexcept;
|
|
static void parse_absolute(tl::vector<string>& o_elements, int type_idx, const char* path, size_t size) noexcept;
|
|
static int deduce_system_type(const char* path, size_t size) noexcept;
|
|
static bool validate_abs_path(int type_idx, const tl::vector<string>& members) noexcept;
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template<typename... Tail>
|
|
struct path_systems_getter
|
|
{
|
|
static tl::vector<tl::vector<const char*>> get_all_parse_separators() noexcept;
|
|
};
|
|
|
|
template<typename Head, typename... Tail>
|
|
struct path_systems_getter<Head, Tail...>
|
|
{
|
|
static tl::vector<tl::vector<const char*>> get_all_parse_separators() noexcept;
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template<int Index, typename TypeToCheck, typename... Tail>
|
|
struct path_system_type_checker
|
|
{
|
|
static bool is(int type_idx) noexcept;
|
|
};
|
|
|
|
// specialization if Head element exists
|
|
template<int Index, typename TypeToCheck, typename Head, typename... Tail>
|
|
struct path_system_type_checker<Index, TypeToCheck, Head, Tail...>
|
|
{
|
|
static bool is(int type_idx) noexcept;
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template<typename parse_separators, typename format_separator>
|
|
struct base_path_system
|
|
{
|
|
static const tl::vector<const char*>& get_parse_separators() noexcept;
|
|
static const char* get_format_separator() noexcept;
|
|
|
|
static string format_relative(const tl::vector<string>& members) noexcept;
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
namespace tl
|
|
{
|
|
namespace detail
|
|
{
|
|
namespace path_system
|
|
{
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template<typename T>
|
|
void simple_format_rel_path(T& o_buffer, const tl::vector<string>& members, const char* separator) noexcept
|
|
{
|
|
//calculate the size to reserve
|
|
size_t totalSize = 0;
|
|
for (const string& el: members)
|
|
totalSize += el.size() + 1; //+1 for the separator
|
|
totalSize -= members.empty() ? 0 : 1;//remove the last separator
|
|
|
|
o_buffer.reserve(totalSize);
|
|
|
|
//append the elements and separator
|
|
const size_t pathSize = members.size();
|
|
for (size_t j = 0; j < pathSize; j++)
|
|
{
|
|
const string& member = members[j];
|
|
o_buffer.append(member.data(), member.size());
|
|
if (j < pathSize - 1)
|
|
o_buffer.append(separator);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template<typename T>
|
|
void simple_format_abs_path(T& o_buffer, const tl::vector<string>& members, const char* root_tag, const char* separator) noexcept
|
|
{
|
|
o_buffer.append(root_tag);
|
|
detail::path_system::simple_format_rel_path(o_buffer, members, separator);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
inline bool find_next_separator(const char* const* separators_begin, const char* const* separators_end, const char*& io_startIt, const char* end, const char*& io_endIt) noexcept
|
|
{
|
|
const size_t str_size = end - io_startIt;
|
|
const char* bestStartIt = nullptr;
|
|
const char* bestSeparator = nullptr;
|
|
for (const char* const* separator_ptr = separators_begin; separator_ptr != separators_end; separator_ptr++)
|
|
{
|
|
const char* it = ascii::strnstr(io_startIt, *separator_ptr, str_size);
|
|
if (it != nullptr && (bestStartIt == nullptr || it < bestStartIt))
|
|
{
|
|
bestStartIt = it;
|
|
bestSeparator = *separator_ptr;
|
|
}
|
|
}
|
|
|
|
if (bestStartIt)
|
|
{
|
|
io_startIt = bestStartIt;
|
|
io_endIt = io_startIt + strlen(bestSeparator);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
inline void simple_parse_path(tl::vector<string>& o_elements, const char* path, size_t size, const char* root_tag, const tl::vector<const char*>& separators) noexcept
|
|
{
|
|
const char* pathIt = path;
|
|
const char* start = path;
|
|
const char* end = start + size;
|
|
|
|
// parse root
|
|
if (root_tag)
|
|
{
|
|
const char* tagIt = root_tag;
|
|
for (; *tagIt; ++tagIt, ++pathIt)
|
|
{
|
|
if (*tagIt != *pathIt)
|
|
break;
|
|
}
|
|
// matched root
|
|
if (!(*tagIt))
|
|
start = pathIt;
|
|
|
|
// if not start over again
|
|
else
|
|
{
|
|
pathIt = path;
|
|
start = path;
|
|
}
|
|
}
|
|
|
|
const char* const* separators_begin = separators.data();
|
|
const char* const* separators_end = separators_begin + separators.size();
|
|
|
|
// parse the rest of the path
|
|
tl::fixed_vector<string, 64> elements;
|
|
while (*start != 0)
|
|
{
|
|
const char* sepStart = start;
|
|
const char* sepEnd = nullptr;
|
|
|
|
bool matchedSeparator = detail::path_system::find_next_separator(separators_begin, separators_end, sepStart, end, sepEnd);
|
|
// if has matched separator
|
|
if (matchedSeparator)
|
|
{
|
|
if (sepStart > start)
|
|
elements.emplace_back(start, sepStart);
|
|
|
|
start = sepEnd;
|
|
}
|
|
else
|
|
{
|
|
//get the remainder of the string
|
|
if (*start != 0)
|
|
elements.emplace_back(start);
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
//now reserve the space and move into final place
|
|
o_elements.clear();
|
|
o_elements.reserve(elements.size());
|
|
for (string& element : elements)
|
|
o_elements.emplace_back(std::move(element));
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
inline bool simple_match_prefix(const char* path, size_t size, const char* prefix) noexcept
|
|
{
|
|
const size_t prefix_length = strlen(prefix);
|
|
if (prefix_length > size)
|
|
return false;
|
|
return strncmp(path, prefix, prefix_length) == 0;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template<int Index, typename... Tail>
|
|
template<typename T>
|
|
T path_system_getter<Index, Tail...>::format_absolute(int /*type_idx*/, const tl::vector<string>& /*members*/) noexcept
|
|
{
|
|
TL_PLAIN_FAIL("Failed to format path. Invalid type.");
|
|
return {};
|
|
}
|
|
|
|
template<int Index, typename... Tail>
|
|
void path_system_getter<Index, Tail...>::parse_absolute(tl::vector<string>& /*o_elements*/, int /*type_idx*/, const char* /*path*/, size_t /* size */) noexcept
|
|
{
|
|
TL_PLAIN_FAIL("Failed parsing absolute path. Invalid type.");
|
|
}
|
|
|
|
template<int Index, typename... Tail>
|
|
int path_system_getter<Index, Tail...>::deduce_system_type(const char* /*path*/, size_t /* size */) noexcept
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
template<int Index, typename... Tail>
|
|
bool path_system_getter<Index, Tail...>::validate_abs_path(int /*type_idx*/, const tl::vector<string>& /*members*/) noexcept
|
|
{
|
|
TL_PLAIN_FAIL("Failed validating path system. Invalid type.");
|
|
return false;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template<int Index, typename Head, typename... Tail>
|
|
template<typename T>
|
|
T path_system_getter<Index, Head, Tail...>::format_absolute(int type_idx, const tl::vector<string>& members) noexcept
|
|
{
|
|
if (type_idx == Index)
|
|
return Head::template format_absolute<T>(members);
|
|
|
|
return path_system_getter<Index + 1, Tail...>::template format_absolute<T>(type_idx, members);
|
|
}
|
|
|
|
template<int Index, typename Head, typename... Tail>
|
|
void path_system_getter<Index, Head, Tail...>::parse_absolute(tl::vector<string>& o_elements, int type_idx, const char* path, size_t size) noexcept
|
|
{
|
|
if (type_idx == Index)
|
|
{
|
|
Head::parse_absolute(o_elements, path, size);
|
|
return;
|
|
}
|
|
path_system_getter<Index + 1, Tail...>::parse_absolute(o_elements, type_idx, path, size);
|
|
}
|
|
|
|
|
|
template<int Index, typename Head, typename... Tail>
|
|
int path_system_getter<Index, Head, Tail...>::deduce_system_type(const char* path, size_t size) noexcept
|
|
{
|
|
if (Head::match(path, size))
|
|
return Index;
|
|
|
|
return path_system_getter<Index + 1, Tail...>::deduce_system_type(path, size);
|
|
}
|
|
|
|
template<int Index, typename Head, typename... Tail>
|
|
bool path_system_getter<Index, Head, Tail...>::validate_abs_path(int type_idx, const tl::vector<string>& members) noexcept
|
|
{
|
|
if (type_idx == Index)
|
|
return Head::validate_abs_path(members);
|
|
|
|
return path_system_getter<Index + 1, Tail...>::validate_abs_path(type_idx, members);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template<typename... Tail>
|
|
tl::vector<tl::vector<const char*>> path_systems_getter<Tail...>::get_all_parse_separators() noexcept
|
|
{
|
|
return tl::vector<tl::vector<const char*>>();
|
|
}
|
|
|
|
template<typename Head, typename... Tail>
|
|
tl::vector<tl::vector<const char*>> path_systems_getter<Head, Tail...>::get_all_parse_separators() noexcept
|
|
{
|
|
tl::vector<tl::vector<const char*>> separators_array;
|
|
separators_array.reserve(32);
|
|
separators_array.push_back(Head::get_parse_separators());
|
|
|
|
tl::vector<tl::vector<const char*>> tail_separators_array = path_systems_getter<Tail...>::get_all_parse_separators();
|
|
std::copy(tail_separators_array.begin(), tail_separators_array.end(), std::back_inserter(separators_array));
|
|
|
|
return separators_array;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template<int Index, typename TypeToCheck, typename... Tail>
|
|
bool path_system_type_checker<Index, TypeToCheck, Tail...>::is(int type_idx) noexcept
|
|
{
|
|
TL_PLAIN_FAIL("Failed checking path type.");
|
|
return false;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template<int Index, typename TypeToCheck, typename Head, typename... Tail>
|
|
bool path_system_type_checker<Index, TypeToCheck, Head, Tail...>::is(int type_idx) noexcept
|
|
{
|
|
if (type_idx == Index)
|
|
return std::is_same_v<Head, TypeToCheck>;
|
|
|
|
return path_system_type_checker<Index + 1, TypeToCheck, Tail...>::is(type_idx);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template<typename parse_separators, typename format_separator>
|
|
const tl::vector<const char*>& base_path_system<parse_separators, format_separator>::get_parse_separators() noexcept
|
|
{
|
|
return parse_separators::vector();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template<typename parse_separators, typename format_separator>
|
|
string base_path_system<parse_separators, format_separator>::format_relative(const tl::vector<string>& members) noexcept
|
|
{
|
|
eastl::string buffer;
|
|
buffer.reserve(8192);
|
|
detail::path_system::simple_format_rel_path(buffer, members, format_separator::value());
|
|
if (buffer.data())
|
|
return string(buffer.data(), buffer.size());
|
|
|
|
return string();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
}
|
|
}
|
|
}
|