#pragma once #include #include "tl/detail/prologue.h" #include #include "tl/string.h" #include "tl/string.h" namespace tl { namespace detail { namespace path_system { ////////////////////////////////////////////////////////////////////////// template void simple_format_rel_path(T& o_buffer, tl::span members, const char* separator) noexcept; template void simple_format_abs_path(T& o_buffer, tl::span 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 simple_parse_path(const char* path, const char* root_tag, const tl::vector& separators) noexcept; inline bool simple_match_prefix(const char* path, const char* prefix) noexcept; ////////////////////////////////////////////////////////////////////////// template struct path_system_getter { template static T format_abs(int type_idx, tl::span members) noexcept; static void parse_abs(tl::vector& 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 members) noexcept; }; // specialization if Head element exists template struct path_system_getter { template static T format_abs(int type_idx, tl::span members) noexcept; static void parse_abs(tl::vector& 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 members) noexcept; }; ////////////////////////////////////////////////////////////////////////// template struct path_systems_getter { static tl::vector> get_all_parse_separators() noexcept; }; template struct path_systems_getter { static tl::vector> get_all_parse_separators() noexcept; }; ////////////////////////////////////////////////////////////////////////// template struct path_system_type_checker { static bool is(int type_idx) noexcept; }; // specialization if Head element exists template struct path_system_type_checker { static bool is(int type_idx) noexcept; }; ////////////////////////////////////////////////////////////////////////// template struct base_path_system { static const tl::vector& get_parse_separators() noexcept; static const char* get_format_separator() noexcept; template static T format_rel(tl::span members) noexcept; }; ////////////////////////////////////////////////////////////////////////// } } } ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// namespace tl { namespace detail { namespace path_system { ////////////////////////////////////////////////////////////////////////// template void simple_format_rel_path(T& o_buffer, tl::span 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 members, const char* separator) noexcept { tl::fixed_string temp; simple_format_rel_path(temp, members, separator); o_buffer = string(temp); } ////////////////////////////////////////////////////////////////////////// template void simple_format_abs_path(T& o_buffer, tl::span 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& o_elements, const char* path, size_t size, const char* root_tag, const tl::vector& 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 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 template T path_system_getter::format_abs(int /*type_idx*/, tl::span /*members*/) noexcept { TL_PLAIN_FAIL("Failed to format path. Invalid type."); return {}; } template void path_system_getter::parse_abs(tl::vector& /*o_elements*/, int /*type_idx*/, const char* /*path*/, size_t /* size */) noexcept { TL_PLAIN_FAIL("Failed parsing abs path. Invalid type."); } template int path_system_getter::deduce_system_type(const char* /*path*/, size_t /* size */) noexcept { return -1; } template bool path_system_getter::validate_abs_path(int /*type_idx*/, tl::span /*members*/) noexcept { TL_PLAIN_FAIL("Failed validating path system. Invalid type."); return false; } ////////////////////////////////////////////////////////////////////////// template template T path_system_getter::format_abs(int type_idx, tl::span members) noexcept { if (type_idx == Index) return Head::template format_abs(members); return path_system_getter::template format_abs(type_idx, members); } template void path_system_getter::parse_abs(tl::vector& 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::parse_abs(o_elements, type_idx, path, size); } template int path_system_getter::deduce_system_type(const char* path, size_t size) noexcept { if (Head::match(path, size)) return Index; return path_system_getter::deduce_system_type(path, size); } template bool path_system_getter::validate_abs_path(int type_idx, tl::span members) noexcept { if (type_idx == Index) return Head::validate_abs_path(members); return path_system_getter::validate_abs_path(type_idx, members); } ////////////////////////////////////////////////////////////////////////// template tl::vector> path_systems_getter::get_all_parse_separators() noexcept { return tl::vector>(); } template tl::vector> path_systems_getter::get_all_parse_separators() noexcept { tl::vector> separators_array; separators_array.reserve(32); separators_array.push_back(Head::get_parse_separators()); tl::vector> tail_separators_array = path_systems_getter::get_all_parse_separators(); std::copy(tail_separators_array.begin(), tail_separators_array.end(), std::back_inserter(separators_array)); return separators_array; } ////////////////////////////////////////////////////////////////////////// template bool path_system_type_checker::is(int type_idx) noexcept { TL_PLAIN_FAIL("Failed checking path type."); return false; } ////////////////////////////////////////////////////////////////////////// template bool path_system_type_checker::is(int type_idx) noexcept { if (type_idx == Index) return std::is_same_v; return path_system_type_checker::is(type_idx); } ////////////////////////////////////////////////////////////////////////// template const tl::vector& base_path_system::get_parse_separators() noexcept { return parse_separators::vector(); } ////////////////////////////////////////////////////////////////////////// template template T base_path_system::format_rel(tl::span members) noexcept { T string; detail::path_system::simple_format_rel_path(string, members, format_separator::value()); return string; } ////////////////////////////////////////////////////////////////////////// } } }