diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2a943e9..8d3ba79 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -14,6 +14,7 @@ PRIVATE yycc/string/reinterpret.cpp yycc/string/op.cpp yycc/rust/panic.cpp + yycc/patch/path.cpp # YYCC/COMHelper.cpp # YYCC/ArgParser.cpp # YYCC/ConfigManager.cpp @@ -57,6 +58,9 @@ FILES yycc/windows/import_guard_tail.hpp yycc/constraint.hpp yycc/constraint/builder.hpp + yycc/patch/path.hpp + yycc/patch/contains.hpp + yycc/patch/starts_ends_with.hpp # # Headers # # Common headers diff --git a/src/YYCCLegacy/StdPatch.cpp b/src/YYCCLegacy/StdPatch.cpp index 04809c5..b0bfe4a 100644 --- a/src/YYCCLegacy/StdPatch.cpp +++ b/src/YYCCLegacy/StdPatch.cpp @@ -6,36 +6,4 @@ namespace YYCC::StdPatch { - std::filesystem::path ToStdPath(const yycc_u8string_view& u8_path) { -#if YYCC_OS == YYCC_OS_WINDOWS - - // convert path to wchar - std::wstring wpath; - if (!YYCC::EncodingHelper::UTF8ToWchar(u8_path, wpath)) - throw std::invalid_argument("Fail to convert given UTF8 string."); - // return path with wchar_t ctor - return std::filesystem::path(wpath); - -#else - std::string cache = YYCC::EncodingHelper::ToOrdinary(u8_path); - return std::filesystem::path(cache.c_str()); -#endif - } - - yycc_u8string ToUTF8Path(const std::filesystem::path& path) { -#if YYCC_OS == YYCC_OS_WINDOWS - - // get and convert to utf8 - yycc_u8string u8_path; - if (!YYCC::EncodingHelper::WcharToUTF8(path.c_str(), u8_path)) - throw std::invalid_argument("Fail to convert to UTF8 string."); - - // return utf8 path - return u8_path; - -#else - return EncodingHelper::ToUTF8(path.string()); -#endif - } - } diff --git a/src/YYCCLegacy/StdPatch.hpp b/src/YYCCLegacy/StdPatch.hpp index 69388e1..d67fdf1 100644 --- a/src/YYCCLegacy/StdPatch.hpp +++ b/src/YYCCLegacy/StdPatch.hpp @@ -5,11 +5,6 @@ #include #include -/** - * @brief \c Standard library related patches for UTF8 compatibility and the limitation of C++ standard version. - * @details - * See also \ref std_patch. -*/ namespace YYCC::StdPatch { /** @@ -28,191 +23,4 @@ namespace YYCC::StdPatch { */ yycc_u8string ToUTF8Path(const std::filesystem::path& path); -#pragma region StartsWith EndsWith - - // Reference: - // https://en.cppreference.com/w/cpp/string/basic_string_view/starts_with - // https://en.cppreference.com/w/cpp/string/basic_string_view/ends_with - // https://en.cppreference.com/w/cpp/string/basic_string/starts_with - // https://en.cppreference.com/w/cpp/string/basic_string/ends_with - -#pragma region String View - - /** - * @brief Checks if the string view begins with the given prefix - * @param[in] that The string view to find. - * @param[in] sv A string view which may be a result of implicit conversion from \c std::basic_string. - * @return True if the string view begins with the provided prefix, false otherwise. - */ - template> - bool StartsWith(const std::basic_string_view& that, std::basic_string_view sv) noexcept { - return std::basic_string_view(that.data(), std::min(that.size(), sv.size())) == sv; - } - /** - * @brief Checks if the string view begins with the given prefix - * @param[in] that The string view to find. - * @param[in] ch A single character. - * @return True if the string view begins with the provided prefix, false otherwise. - */ - template> - bool StartsWith(const std::basic_string_view& that, CharT ch) noexcept { - return !that.empty() && Traits::eq(that.front(), ch); - } - /** - * @brief Checks if the string view begins with the given prefix - * @param[in] that The string view to find. - * @param[in] s A null-terminated character string. - * @return True if the string view begins with the provided prefix, false otherwise. - */ - template> - bool StartsWith(const std::basic_string_view& that, const CharT* s) noexcept { - return StartsWith(that, std::basic_string_view(s)); - } - - /** - * @brief Checks if the string view ends with the given suffix - * @param[in] that The string view to find. - * @param[in] sv A string view which may be a result of implicit conversion from \c std::basic_string. - * @return True if the string view ends with the provided suffix, false otherwise. - */ - template> - bool EndsWith(const std::basic_string_view& that, std::basic_string_view sv) noexcept { - return that.size() >= sv.size() && that.compare(that.size() - sv.size(), std::basic_string_view::npos, sv) == 0; - } - /** - * @brief Checks if the string view ends with the given suffix - * @param[in] that The string view to find. - * @param[in] ch A single character. - * @return True if the string view ends with the provided suffix, false otherwise. - */ - template> - bool EndsWith(const std::basic_string_view& that, CharT ch) noexcept { - return !that.empty() && Traits::eq(that.back(), ch); - } - /** - * @brief Checks if the string view ends with the given suffix - * @param[in] that The string view to find. - * @param[in] s A null-terminated character string. - * @return True if the string view ends with the provided suffix, false otherwise. - */ - template> - bool EndsWith(const std::basic_string_view& that, const CharT* s) noexcept { - return EndsWith(that, std::basic_string_view(s)); - } - -#pragma endregion - -#pragma region String - - /** - * @brief Checks if the string begins with the given prefix - * @param[in] that The string to find. - * @param[in] sv A string view which may be a result of implicit conversion from \c std::basic_string. - * @return True if the string view begins with the provided prefix, false otherwise. - */ - template> - bool StartsWith(const std::basic_string& that, std::basic_string_view sv) noexcept { - return StartsWith(std::basic_string_view(that.data(), that.size()), sv); - } - /** - * @brief Checks if the string begins with the given prefix - * @param[in] that The string to find. - * @param[in] ch A single character. - * @return True if the string view begins with the provided prefix, false otherwise. - */ - template> - bool StartsWith(const std::basic_string& that, CharT ch) noexcept { - return StartsWith(std::basic_string_view(that.data(), that.size()), ch); - } - /** - * @brief Checks if the string begins with the given prefix - * @param[in] that The string to find. - * @param[in] s A null-terminated character string. - * @return True if the string view begins with the provided prefix, false otherwise. - */ - template> - bool StartsWith(const std::basic_string& that, const CharT* s) noexcept { - return StartsWith(std::basic_string_view(that.data(), that.size()), s); - } - - /** - * @brief Checks if the string ends with the given suffix - * @param[in] that The string to find. - * @param[in] sv A string view which may be a result of implicit conversion from \c std::basic_string. - * @return True if the string view ends with the provided suffix, false otherwise. - */ - template> - bool EndsWith(const std::basic_string& that, std::basic_string_view sv) noexcept { - return EndsWith(std::basic_string_view(that.data(), that.size()), sv); - } - /** - * @brief Checks if the string ends with the given suffix - * @param[in] that The string to find. - * @param[in] ch A single character. - * @return True if the string view ends with the provided suffix, false otherwise. - */ - template> - bool EndsWith(const std::basic_string& that, CharT ch) noexcept { - return EndsWith(std::basic_string_view(that.data(), that.size()), ch); - } - /** - * @brief Checks if the string ends with the given suffix - * @param[in] that The string to find. - * @param[in] s A null-terminated character string. - * @return True if the string view ends with the provided suffix, false otherwise. - */ - template> - bool EndsWith(const std::basic_string& that, const CharT* s) noexcept { - return EndsWith(std::basic_string_view(that.data(), that.size()), s); - } - -#pragma endregion - -#pragma endregion - -#pragma region Contain - - /** - * @brief Checks if there is an element with key equivalent to key in the container. - * @details - * The polyfill to \c Contains function of unordered and ordered associative container. - * Because this function only present after C++ 20. - * This function will use our custom polyfill if the version of C++ standard you are using lower than C++ 20. - * Otherwise it will fallback to vanilla standard library function. - * @tparam _TContainer - * The type of container. This container must have \c find() and \c end() member functions. - * @tparam _TKey - * The type of key of container. - * If the container is a set, this type is the type of item in set. - * If the container is a map, this type is the key type of map. - * @param[in] container The reference to container to find. - * @param[in] key Key value of the element to search for - * @return True if there is such an element, otherwise false. - * @remarks - * This template function do not have constraint check. - * If container type has \c find() and \c end() member functions, this template function will be created without any error. - * However, this function should be used for standard library associative container according to its original purpose. - * It means that the type of container usually and should be one of following types: - * \li \c std::set - * \li \c std::multiset - * \li \c std::map - * \li \c std::multimap - * \li \c std::unordered_set - * \li \c std::unordered_multiset - * \li \c std::unordered_map - * \li \c std::unordered_multimap - */ - template - bool Contains(const _TContainer& container, const _TKey& key) { - // __cplusplus macro need special compiler switch enabled when compiling. - // So we use _MSVC_LANG check it instead. -#if __cplusplus >= 202002L || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L) - return container.contains(key); -#else - return container.find(key) != container.end(); -#endif - } - -#pragma endregion - } diff --git a/src/yycc/patch/container.hpp b/src/yycc/patch/container.hpp deleted file mode 100644 index e69de29..0000000 diff --git a/src/yycc/patch/contains.hpp b/src/yycc/patch/contains.hpp new file mode 100644 index 0000000..05ad791 --- /dev/null +++ b/src/yycc/patch/contains.hpp @@ -0,0 +1,45 @@ +#pragma once +#include "../macro/feature_probe.hpp" + +namespace yycc::patch::contains { + + /** + * @brief Checks if there is an element with key equivalent to key in the container. + * @details + * The polyfill to \c contains() function of unordered and ordered associative container. + * Because this function only present after C++ 20. + * This function will use our custom polyfill if the version of C++ standard you are using lower than C++ 20. + * Otherwise it will fallback to vanilla standard library function. + * @tparam TContainer + * The type of container. This container must have \c find() and \c end() member functions. + * @tparam TKey + * The type of key of container. + * If the container is a set, this type is the type of item in set. + * If the container is a map, this type is the key type of map. + * @param[in] container The reference to container to find. + * @param[in] key Key value of the element to search for + * @return True if there is such an element, otherwise false. + * @remarks + * This template function do not have constraint check. + * If container type has \c find() and \c end() member functions, this template function will be created without any error. + * However, this function should be used for standard library associative container according to its original purpose. + * It means that the type of container usually and should be one of following types: + * \li \c std::set + * \li \c std::multiset + * \li \c std::map + * \li \c std::multimap + * \li \c std::unordered_set + * \li \c std::unordered_multiset + * \li \c std::unordered_map + * \li \c std::unordered_multimap + */ + template + bool contains(const TContainer& container, const TKey& key) { +#if defined(YYCC_CPPFEAT_CONTAINS) + return container.contains(key); +#else + return container.find(key) != container.end(); +#endif + } + +} // namespace yycc::patch::container diff --git a/src/yycc/patch/path.cpp b/src/yycc/patch/path.cpp new file mode 100644 index 0000000..1359c75 --- /dev/null +++ b/src/yycc/patch/path.cpp @@ -0,0 +1,48 @@ +#include "path.hpp" +#include "../macro/os_detector.hpp" +#include + +#define NS_YYCC_STRING ::yycc::string + +namespace yycc::patch::path { + + // TODO: Fix this after finish encoding parts. + + // TODO: Add native implementation if C++ support it. + // So we need add feature test macro at the same time. + + std::filesystem::path to_std_path(const NS_YYCC_STRING::u8string_view& u8_path) { +// #if YYCC_OS == YYCC_OS_WINDOWS + +// // convert path to wchar +// std::wstring wpath; +// if (!YYCC::EncodingHelper::UTF8ToWchar(u8_path, wpath)) +// throw std::invalid_argument("Fail to convert given UTF8 string."); +// // return path with wchar_t ctor +// return std::filesystem::path(wpath); + +// #else +// std::string cache = YYCC::EncodingHelper::ToOrdinary(u8_path); +// return std::filesystem::path(cache.c_str()); +// #endif + return std::filesystem::path(); + } + + NS_YYCC_STRING::u8string to_u8string(const std::filesystem::path& path) { +// #if YYCC_OS == YYCC_OS_WINDOWS + +// // get and convert to utf8 +// NS_YYCC_STRING::u8string u8_path; +// if (!YYCC::EncodingHelper::WcharToUTF8(path.c_str(), u8_path)) +// throw std::invalid_argument("Fail to convert to UTF8 string."); + +// // return utf8 path +// return u8_path; + +// #else +// return EncodingHelper::ToUTF8(path.string()); +// #endif + return NS_YYCC_STRING::u8string(); + } + +} diff --git a/src/yycc/patch/path.hpp b/src/yycc/patch/path.hpp index e69de29..87ede4f 100644 --- a/src/yycc/patch/path.hpp +++ b/src/yycc/patch/path.hpp @@ -0,0 +1,32 @@ +#pragma once +#include "../string.hpp" +#include + +#define NS_YYCC_STRING ::yycc::string + +/** + * @brief \c Standard library related patches for UTF8 compatibility and the limitation of C++ standard version. + * @details + * See also \ref std_patch. +*/ +namespace yycc::patch::path { + + /** + * @brief Constructs \c std::filesystem::path from UTF8 path. + * @param[in] u8_path UTF8 path string for building. + * @return \c std::filesystem::path instance. + * @exception std::invalid_argument Fail to parse given UTF8 string (maybe invalid?). + */ + std::filesystem::path to_std_path(const NS_YYCC_STRING::u8string_view& u8_path); + + /** + * @brief Returns the UTF8 representation of given \c std::filesystem::path. + * @param[in] path The \c std::filesystem::path instance converting to UTF8 path. + * @return The UTF8 representation of given \c std::filesystem::path. + * @exception std::invalid_argument Fail to convert to UTF8 string. + */ + NS_YYCC_STRING::u8string to_u8string(const std::filesystem::path& path); + +} // namespace yycc::patch::path + +#undef NS_YYCC_STRING diff --git a/src/yycc/patch/starts_ends_with.hpp b/src/yycc/patch/starts_ends_with.hpp new file mode 100644 index 0000000..67da6fb --- /dev/null +++ b/src/yycc/patch/starts_ends_with.hpp @@ -0,0 +1,203 @@ +#pragma once +#include "../macro/feature_probe.hpp" +#include +#include + +namespace yycc::patch::starts_ends_with { + + // Reference: + // https://en.cppreference.com/w/cpp/string/basic_string_view/starts_with + // https://en.cppreference.com/w/cpp/string/basic_string_view/ends_with + // https://en.cppreference.com/w/cpp/string/basic_string/starts_with + // https://en.cppreference.com/w/cpp/string/basic_string/ends_with + +#pragma region For String View + + /** + * @brief Checks if the string view begins with the given prefix + * @param[in] that The string view to find. + * @param[in] sv A string view which may be a result of implicit conversion from \c std::basic_string. + * @return True if the string view begins with the provided prefix, false otherwise. + */ + template> + bool starts_with(const std::basic_string_view& that, + std::basic_string_view sv) noexcept { +#if defined(YYCC_CPPFEAT_STARTS_ENDS_WITH) + return that.starts_with(sv); +#else + return std::basic_string_view(that.data(), std::min(that.size(), sv.size())) + == sv; +#endif + } + /** + * @brief Checks if the string view begins with the given prefix + * @param[in] that The string view to find. + * @param[in] ch A single character. + * @return True if the string view begins with the provided prefix, false otherwise. + */ + template> + bool starts_with(const std::basic_string_view& that, CharT ch) noexcept { +#if defined(YYCC_CPPFEAT_STARTS_ENDS_WITH) + return that.starts_with(ch); +#else + return !that.empty() && Traits::eq(that.front(), ch); +#endif + } + /** + * @brief Checks if the string view begins with the given prefix + * @param[in] that The string view to find. + * @param[in] s A null-terminated character string. + * @return True if the string view begins with the provided prefix, false otherwise. + */ + template> + bool starts_with(const std::basic_string_view& that, const CharT* s) noexcept { +#if defined(YYCC_CPPFEAT_STARTS_ENDS_WITH) + return that.starts_with(s); +#else + return starts_with(that, std::basic_string_view(s)); +#endif + } + + /** + * @brief Checks if the string view ends with the given suffix + * @param[in] that The string view to find. + * @param[in] sv A string view which may be a result of implicit conversion from \c std::basic_string. + * @return True if the string view ends with the provided suffix, false otherwise. + */ + template> + bool ends_with(const std::basic_string_view& that, + std::basic_string_view sv) noexcept { +#if defined(YYCC_CPPFEAT_STARTS_ENDS_WITH) + return that.ends_with(sv); +#else + return that.size() >= sv.size() + && that.compare(that.size() - sv.size(), + std::basic_string_view::npos, + sv) + == 0; +#endif + } + /** + * @brief Checks if the string view ends with the given suffix + * @param[in] that The string view to find. + * @param[in] ch A single character. + * @return True if the string view ends with the provided suffix, false otherwise. + */ + template> + bool ends_with(const std::basic_string_view& that, CharT ch) noexcept { +#if defined(YYCC_CPPFEAT_STARTS_ENDS_WITH) + return that.ends_with(ch); +#else + return !that.empty() && Traits::eq(that.back(), ch); +#endif + } + /** + * @brief Checks if the string view ends with the given suffix + * @param[in] that The string view to find. + * @param[in] s A null-terminated character string. + * @return True if the string view ends with the provided suffix, false otherwise. + */ + template> + bool ends_with(const std::basic_string_view& that, const CharT* s) noexcept { +#if defined(YYCC_CPPFEAT_STARTS_ENDS_WITH) + return that.ends_with(s); +#else + return ends_with(that, std::basic_string_view(s)); +#endif + } + +#pragma endregion + +#pragma region For String + + /** + * @brief Checks if the string begins with the given prefix + * @param[in] that The string to find. + * @param[in] sv A string view which may be a result of implicit conversion from \c std::basic_string. + * @return True if the string view begins with the provided prefix, false otherwise. + */ + template> + bool starts_with(const std::basic_string& that, + std::basic_string_view sv) noexcept { +#if defined(YYCC_CPPFEAT_STARTS_ENDS_WITH) + return that.starts_with(sv); +#else + return starts_with(std::basic_string_view(that.data(), that.size()), sv); +#endif + } + /** + * @brief Checks if the string begins with the given prefix + * @param[in] that The string to find. + * @param[in] ch A single character. + * @return True if the string view begins with the provided prefix, false otherwise. + */ + template> + bool starts_with(const std::basic_string& that, CharT ch) noexcept { +#if defined(YYCC_CPPFEAT_STARTS_ENDS_WITH) + return that.starts_with(ch); +#else + return starts_with(std::basic_string_view(that.data(), that.size()), ch); +#endif + } + /** + * @brief Checks if the string begins with the given prefix + * @param[in] that The string to find. + * @param[in] s A null-terminated character string. + * @return True if the string view begins with the provided prefix, false otherwise. + */ + template> + bool starts_with(const std::basic_string& that, const CharT* s) noexcept { +#if defined(YYCC_CPPFEAT_STARTS_ENDS_WITH) + return that.starts_with(s); +#else + return starts_with(std::basic_string_view(that.data(), that.size()), s); +#endif + } + + /** + * @brief Checks if the string ends with the given suffix + * @param[in] that The string to find. + * @param[in] sv A string view which may be a result of implicit conversion from \c std::basic_string. + * @return True if the string view ends with the provided suffix, false otherwise. + */ + template> + bool ends_with(const std::basic_string& that, + std::basic_string_view sv) noexcept { +#if defined(YYCC_CPPFEAT_STARTS_ENDS_WITH) + return that.ends_with(sv); +#else + return ends_with(std::basic_string_view(that.data(), that.size()), sv); +#endif + } + /** + * @brief Checks if the string ends with the given suffix + * @param[in] that The string to find. + * @param[in] ch A single character. + * @return True if the string view ends with the provided suffix, false otherwise. + */ + template> + bool ends_with(const std::basic_string& that, CharT ch) noexcept { +#if defined(YYCC_CPPFEAT_STARTS_ENDS_WITH) + return that.ends_with(ch); +#else + return ends_with(std::basic_string_view(that.data(), that.size()), ch); +#endif + } + /** + * @brief Checks if the string ends with the given suffix + * @param[in] that The string to find. + * @param[in] s A null-terminated character string. + * @return True if the string view ends with the provided suffix, false otherwise. + */ + template> + bool ends_with(const std::basic_string& that, const CharT* s) noexcept { +#if defined(YYCC_CPPFEAT_STARTS_ENDS_WITH) + return that.ends_with(s); +#else + return ends_with(std::basic_string_view(that.data(), that.size()), s); +#endif + } + +#pragma endregion + +} // namespace yycc::patch::starts_ends_with diff --git a/src/yycc/patch/string.hpp b/src/yycc/patch/string.hpp deleted file mode 100644 index e69de29..0000000