Files
TL/include/tl/detail/path_system_utils.h
T
2024-07-10 11:52:47 +02:00

394 lines
12 KiB
C++

#pragma once
#include <EASTL/fixed_string.h>
#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, tl::span<const string> members, const char* separator) noexcept;
template<typename T>
void simple_format_abs_path(T& o_buffer, tl::span<const 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_abs(int type_idx, tl::span<const string> members) noexcept;
static void parse_abs(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, tl::span<const 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_abs(int type_idx, tl::span<const string> members) noexcept;
static void parse_abs(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, tl::span<const 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;
template<typename T>
static T format_rel(tl::span<const string> members) noexcept;
};
//////////////////////////////////////////////////////////////////////////
}
}
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
namespace tl
{
namespace detail
{
namespace path_system
{
//////////////////////////////////////////////////////////////////////////
template<typename T>
void simple_format_rel_path(T& o_buffer, tl::span<const 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<>
inline void simple_format_rel_path(string& o_buffer, tl::span<const string> members, const char* separator) noexcept
{
tl::fixed_string<char, 1024> temp;
simple_format_rel_path(temp, members, separator);
o_buffer = string(temp);
}
//////////////////////////////////////////////////////////////////////////
template<typename T>
void simple_format_abs_path(T& o_buffer, tl::span<const 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_abs(int /*type_idx*/, tl::span<const 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_abs(tl::vector<string>& /*o_elements*/, int /*type_idx*/, const char* /*path*/, size_t /* size */) noexcept
{
TL_PLAIN_FAIL("Failed parsing abs 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*/, tl::span<const 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_abs(int type_idx, tl::span<const string> members) noexcept
{
if (type_idx == Index)
return Head::template format_abs<T>(members);
return path_system_getter<Index + 1, Tail...>::template format_abs<T>(type_idx, members);
}
template<int Index, typename Head, typename... Tail>
void path_system_getter<Index, Head, Tail...>::parse_abs(tl::vector<string>& o_elements, int type_idx, const char* path, size_t size) noexcept
{
if (type_idx == Index)
{
Head::parse_abs(o_elements, path, size);
return;
}
path_system_getter<Index + 1, Tail...>::parse_abs(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, tl::span<const 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>
template<typename T>
T base_path_system<parse_separators, format_separator>::format_rel(tl::span<const string> members) noexcept
{
T string;
detail::path_system::simple_format_rel_path(string, members, format_separator::value());
return string;
}
//////////////////////////////////////////////////////////////////////////
}
}
}