feat: add various functions
- Add Win32 CopyFile, MoveFile, DeleteFile functions in WinFctHelper. - rename FsPathPatch to StdPatch because this namespace will hold all standard library patches in future. - add polyfill for std:basic_string::starts_with, std::basic_string::ends_with std::basic_string_view::starts_with, std::basic_string_view::ends_with in StdPatch. - add polyfill for unordered and ordered associative standard library container's contains function in StdPatch. - documentation and testbench will be fixed in later commits.
This commit is contained in:
parent
33cb284eb7
commit
72a48b703f
|
@ -43,7 +43,7 @@
|
||||||
|
|
||||||
\li \subpage io_helper
|
\li \subpage io_helper
|
||||||
|
|
||||||
\li \subpage fs_path_patch
|
\li \subpage std_patch
|
||||||
|
|
||||||
<B>Advanced Features</B>
|
<B>Advanced Features</B>
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
namespace YYCC::FsPathPatch {
|
namespace YYCC::StdPatch {
|
||||||
/**
|
/**
|
||||||
|
|
||||||
\page fs_path_patch std::filesystem::path Patch
|
\page std_patch Standard Library Patch
|
||||||
|
|
||||||
|
\section std_patch__fs_path std::filesystem::path Patch
|
||||||
|
|
||||||
As you know, the underlying char type of \c std::filesystem::path is \c wchar_t on Windows,
|
As you know, the underlying char type of \c std::filesystem::path is \c wchar_t on Windows,
|
||||||
and in other platforms, it is simple \c char.
|
and in other platforms, it is simple \c char.
|
||||||
|
@ -23,17 +25,17 @@ This patch is served for Windows but also works on other plaftoms.
|
||||||
If you are in Windows, this patch will perform extra operations to achieve goals,
|
If you are in Windows, this patch will perform extra operations to achieve goals,
|
||||||
and in other platforms, they just redirect request to corresponding vanilla C++ functions.
|
and in other platforms, they just redirect request to corresponding vanilla C++ functions.
|
||||||
|
|
||||||
\section fs_path_patch__from_utf8_path Create Path from UTF8 String
|
\subsection std_patch__fs_path__from_utf8_path Create Path from UTF8 String
|
||||||
|
|
||||||
#FromUTF8Path provides this feature.
|
#ToStdPath provides this feature.
|
||||||
It accepts an string pointer to UTF8 string and try to create \c std::filesystem::path from it.
|
It accepts an string pointer to UTF8 string and try to create \c std::filesystem::path from it.
|
||||||
Function will throw exception if encoding convertion or constructor self failed.
|
Function will throw exception if encoding convertion or constructor self failed.
|
||||||
There are some example:
|
There are some example:
|
||||||
|
|
||||||
\code
|
\code
|
||||||
auto foobar_path = YYCC::FsPathPatch::FromUTF8Path(YYCC_U8("/foo/bar"));
|
auto foobar_path = YYCC::StdPatch::ToStdPath(YYCC_U8("/foo/bar"));
|
||||||
auto slashed_path = foobar_path / YYCC::FsPathPatch::FromUTF8Path(YYCC_U8("test"));
|
auto slashed_path = foobar_path / YYCC::StdPatch::ToStdPath(YYCC_U8("test"));
|
||||||
auto replaced_ext = foobar_path.replace_extension(YYCC::FsPathPatch::FromUTF8Path(YYCC_U8(".txt")));
|
auto replaced_ext = foobar_path.replace_extension(YYCC::StdPatch::ToStdPath(YYCC_U8(".txt")));
|
||||||
\endcode
|
\endcode
|
||||||
|
|
||||||
For first line in example, it is obvious that you can create a \c std::filesystem::path from this function.
|
For first line in example, it is obvious that you can create a \c std::filesystem::path from this function.
|
||||||
|
@ -58,17 +60,17 @@ However it is depracted since C++ 20,
|
||||||
because \c std::filesystem::path directly supports UTF8 by \c char8_t since C++ 20.
|
because \c std::filesystem::path directly supports UTF8 by \c char8_t since C++ 20.
|
||||||
Because C++ standard is volatile, we create this function to have an uniform programming experience.
|
Because C++ standard is volatile, we create this function to have an uniform programming experience.
|
||||||
|
|
||||||
\section fs_path_patch__to_utf8_path Extract UTF8 Path String from Path
|
\subsection std_patch__fs_path__to_utf8_path Extract UTF8 Path String from Path
|
||||||
|
|
||||||
#ToUTF8Path provides this feature.
|
#ToUTF8Path provides this feature.
|
||||||
It basically is the reversed operation of #FromUTF8Path.
|
It basically is the reversed operation of #ToStdPath.
|
||||||
It is usually used when you have done all path work in \c std::filesystem::path
|
It is usually used when you have done all path work in \c std::filesystem::path
|
||||||
and want to get the result.
|
and want to get the result.
|
||||||
There is an example:
|
There is an example:
|
||||||
|
|
||||||
\code
|
\code
|
||||||
auto foobar_path = YYCC::FsPathPatch::FromUTF8Path(YYCC_U8("/foo/bar"));
|
auto foobar_path = YYCC::StdPatch::ToStdPath(YYCC_U8("/foo/bar"));
|
||||||
auto result = YYCC::FsPathPatch::ToUTF8Path(foobar_path / YYCC::FsPathPatch::FromUTF8Path(YYCC_U8("test")));
|
auto result = YYCC::StdPatch::ToUTF8Path(foobar_path / YYCC::StdPatch::ToStdPath(YYCC_U8("test")));
|
||||||
\endcode
|
\endcode
|
||||||
|
|
||||||
*/
|
*/
|
|
@ -11,7 +11,7 @@ PRIVATE
|
||||||
DialogHelper.cpp
|
DialogHelper.cpp
|
||||||
EncodingHelper.cpp
|
EncodingHelper.cpp
|
||||||
ExceptionHelper.cpp
|
ExceptionHelper.cpp
|
||||||
FsPathPatch.cpp
|
StdPatch.cpp
|
||||||
IOHelper.cpp
|
IOHelper.cpp
|
||||||
StringHelper.cpp
|
StringHelper.cpp
|
||||||
WinFctHelper.cpp
|
WinFctHelper.cpp
|
||||||
|
@ -32,7 +32,7 @@ FILES
|
||||||
DialogHelper.hpp
|
DialogHelper.hpp
|
||||||
EncodingHelper.hpp
|
EncodingHelper.hpp
|
||||||
ExceptionHelper.hpp
|
ExceptionHelper.hpp
|
||||||
FsPathPatch.hpp
|
StdPatch.hpp
|
||||||
IOHelper.hpp
|
IOHelper.hpp
|
||||||
ParserHelper.hpp
|
ParserHelper.hpp
|
||||||
StringHelper.hpp
|
StringHelper.hpp
|
||||||
|
@ -71,8 +71,12 @@ PRIVATE
|
||||||
$<$<CXX_COMPILER_ID:MSVC>:UNICODE>
|
$<$<CXX_COMPILER_ID:MSVC>:UNICODE>
|
||||||
$<$<CXX_COMPILER_ID:MSVC>:_UNICODE>
|
$<$<CXX_COMPILER_ID:MSVC>:_UNICODE>
|
||||||
)
|
)
|
||||||
# Order build as UTF-8 in MSVC
|
|
||||||
target_compile_options(YYCCommonplace
|
target_compile_options(YYCCommonplace
|
||||||
|
# Enable new __cplusplus macro in MSVC.
|
||||||
|
# Because we use it in header, so we need populate it.
|
||||||
|
PUBLIC
|
||||||
|
$<$<CXX_COMPILER_ID:MSVC>:/Zc:__cplusplus>
|
||||||
|
# Order build as UTF-8 in MSVC
|
||||||
PRIVATE
|
PRIVATE
|
||||||
$<$<CXX_COMPILER_ID:MSVC>:/utf-8>
|
$<$<CXX_COMPILER_ID:MSVC>:/utf-8>
|
||||||
)
|
)
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
#include "StringHelper.hpp"
|
#include "StringHelper.hpp"
|
||||||
#include "IOHelper.hpp"
|
#include "IOHelper.hpp"
|
||||||
#include "EncodingHelper.hpp"
|
#include "EncodingHelper.hpp"
|
||||||
#include "FsPathPatch.hpp"
|
#include "StdPatch.hpp"
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <cstdarg>
|
#include <cstdarg>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
@ -459,8 +459,8 @@ namespace YYCC::ExceptionHelper {
|
||||||
if (!YYCC::WinFctHelper::GetModuleFileName(NULL, u8_process_path))
|
if (!YYCC::WinFctHelper::GetModuleFileName(NULL, u8_process_path))
|
||||||
return false;
|
return false;
|
||||||
// extract file name from full path by std::filesystem::path
|
// extract file name from full path by std::filesystem::path
|
||||||
std::filesystem::path process_path(FsPathPatch::FromUTF8Path(u8_process_path.c_str()));
|
std::filesystem::path process_path(StdPatch::ToStdPath(u8_process_path.c_str()));
|
||||||
u8_process_name = FsPathPatch::ToUTF8Path(process_path.filename());
|
u8_process_name = StdPatch::ToUTF8Path(process_path.filename());
|
||||||
}
|
}
|
||||||
// then get process id
|
// then get process id
|
||||||
DWORD process_id = GetCurrentProcessId();
|
DWORD process_id = GetCurrentProcessId();
|
||||||
|
@ -478,19 +478,19 @@ namespace YYCC::ExceptionHelper {
|
||||||
if (!WinFctHelper::GetLocalAppData(u8_localappdata_path))
|
if (!WinFctHelper::GetLocalAppData(u8_localappdata_path))
|
||||||
return false;
|
return false;
|
||||||
// convert to std::filesystem::path
|
// convert to std::filesystem::path
|
||||||
std::filesystem::path crash_report_path(FsPathPatch::FromUTF8Path(u8_localappdata_path.c_str()));
|
std::filesystem::path crash_report_path(StdPatch::ToStdPath(u8_localappdata_path.c_str()));
|
||||||
// slash into crash report folder
|
// slash into crash report folder
|
||||||
crash_report_path /= FsPathPatch::FromUTF8Path(YYCC_U8("CrashDumps"));
|
crash_report_path /= StdPatch::ToStdPath(YYCC_U8("CrashDumps"));
|
||||||
// use create function to make sure it is existing
|
// use create function to make sure it is existing
|
||||||
std::filesystem::create_directories(crash_report_path);
|
std::filesystem::create_directories(crash_report_path);
|
||||||
|
|
||||||
// build log path and coredump path
|
// build log path and coredump path
|
||||||
// build std::filesystem::path first
|
// build std::filesystem::path first
|
||||||
std::filesystem::path log_filepath = crash_report_path / FsPathPatch::FromUTF8Path(u8_log_filename.c_str());
|
std::filesystem::path log_filepath = crash_report_path / StdPatch::ToStdPath(u8_log_filename.c_str());
|
||||||
std::filesystem::path coredump_filepath = crash_report_path / FsPathPatch::FromUTF8Path(u8_coredump_filename.c_str());
|
std::filesystem::path coredump_filepath = crash_report_path / StdPatch::ToStdPath(u8_coredump_filename.c_str());
|
||||||
// output to result
|
// output to result
|
||||||
log_path = FsPathPatch::ToUTF8Path(log_filepath);
|
log_path = StdPatch::ToUTF8Path(log_filepath);
|
||||||
coredump_path = FsPathPatch::ToUTF8Path(coredump_filepath);
|
coredump_path = StdPatch::ToUTF8Path(coredump_filepath);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,29 +0,0 @@
|
||||||
#pragma once
|
|
||||||
#include "YYCCInternal.hpp"
|
|
||||||
|
|
||||||
#include <filesystem>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief \c std::filesystem::path related patches for UTF8 compatibility
|
|
||||||
* @details
|
|
||||||
* See also \ref fs_path_patch.
|
|
||||||
*/
|
|
||||||
namespace YYCC::FsPathPatch {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @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 FromUTF8Path(const yycc_char8_t* 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.
|
|
||||||
*/
|
|
||||||
yycc_u8string ToUTF8Path(const std::filesystem::path& path);
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,24 +1,24 @@
|
||||||
#include "FsPathPatch.hpp"
|
#include "StdPatch.hpp"
|
||||||
|
|
||||||
#include "EncodingHelper.hpp"
|
#include "EncodingHelper.hpp"
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
namespace YYCC::FsPathPatch {
|
namespace YYCC::StdPatch {
|
||||||
|
|
||||||
std::filesystem::path FromUTF8Path(const yycc_char8_t* u8_path) {
|
std::filesystem::path ToStdPath(const yycc_u8string_view& u8_path) {
|
||||||
#if YYCC_OS == YYCC_OS_WINDOWS
|
#if YYCC_OS == YYCC_OS_WINDOWS
|
||||||
|
|
||||||
// convert path to wchar
|
// convert path to wchar
|
||||||
std::wstring wpath;
|
std::wstring wpath;
|
||||||
if (!YYCC::EncodingHelper::UTF8ToWchar(u8_path, wpath))
|
if (!YYCC::EncodingHelper::UTF8ToWchar(u8_path, wpath))
|
||||||
throw std::invalid_argument("Fail to convert given UTF8 string.");
|
throw std::invalid_argument("Fail to convert given UTF8 string.");
|
||||||
|
|
||||||
// return path with wchar_t ctor
|
// return path with wchar_t ctor
|
||||||
return std::filesystem::path(wpath);
|
return std::filesystem::path(wpath);
|
||||||
|
|
||||||
#else
|
#else
|
||||||
return std::filesystem::path(EncodingHelper::ToOrdinary(u8_path));
|
std::string cache = YYCC::EncodingHelper::ToOrdinary(u8_path);
|
||||||
|
return std::filesystem::path(cache.c_str());
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
216
src/StdPatch.hpp
Normal file
216
src/StdPatch.hpp
Normal file
|
@ -0,0 +1,216 @@
|
||||||
|
#pragma once
|
||||||
|
#include "YYCCInternal.hpp"
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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 {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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 ToStdPath(const yycc_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.
|
||||||
|
*/
|
||||||
|
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<class CharT, class Traits = std::char_traits<CharT>>
|
||||||
|
bool StartsWith(const std::basic_string_view<CharT, Traits>& that, std::basic_string_view<CharT, Traits> sv) noexcept {
|
||||||
|
return std::basic_string_view<CharT, Traits>(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<class CharT, class Traits = std::char_traits<CharT>>
|
||||||
|
bool StartsWith(const std::basic_string_view<CharT, Traits>& 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<class CharT, class Traits = std::char_traits<CharT>>
|
||||||
|
bool StartsWith(const std::basic_string_view<CharT, Traits>& 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<class CharT, class Traits = std::char_traits<CharT>>
|
||||||
|
bool EndsWith(const std::basic_string_view<CharT, Traits>& that, std::basic_string_view<CharT, Traits> sv) noexcept {
|
||||||
|
return that.size() >= sv.size() && that.compare(that.size() - sv.size(), std::basic_string_view<CharT, Traits>::npos, sv);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @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<class CharT, class Traits = std::char_traits<CharT>>
|
||||||
|
bool EndsWith(const std::basic_string_view<CharT, Traits>& 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<class CharT, class Traits = std::char_traits<CharT>>
|
||||||
|
bool EndsWith(const std::basic_string_view<CharT, Traits>& 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<class CharT, class Traits = std::char_traits<CharT>>
|
||||||
|
bool StartsWith(const std::basic_string<CharT, Traits>& that, std::basic_string_view<CharT, Traits> sv) noexcept {
|
||||||
|
return StartsWith(std::basic_string_view<CharT, Traits>(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<class CharT, class Traits = std::char_traits<CharT>>
|
||||||
|
bool StartsWith(const std::basic_string<CharT, Traits>& that, CharT ch) noexcept {
|
||||||
|
return StartsWith(std::basic_string_view<CharT, Traits>(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<class CharT, class Traits = std::char_traits<CharT>>
|
||||||
|
bool StartsWith(const std::basic_string<CharT, Traits>& that, const CharT* s) noexcept {
|
||||||
|
return StartsWith(std::basic_string_view<CharT, Traits>(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<class CharT, class Traits = std::char_traits<CharT>>
|
||||||
|
bool EndsWith(const std::basic_string<CharT, Traits>& that, std::basic_string_view<CharT, Traits> sv) noexcept {
|
||||||
|
return EndsWith(std::basic_string_view<CharT, Traits>(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<class CharT, class Traits = std::char_traits<CharT>>
|
||||||
|
bool EndsWith(const std::basic_string<CharT, Traits>& that, CharT ch) noexcept {
|
||||||
|
return EndsWith(std::basic_string_view<CharT, Traits>(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<class CharT, class Traits = std::char_traits<CharT>>
|
||||||
|
bool EndsWith(const std::basic_string<CharT, Traits>& that, const CharT* s) noexcept {
|
||||||
|
return EndsWith(std::basic_string_view<CharT, Traits>(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<class _TContainer, class _TKey>
|
||||||
|
bool Contains(const _TContainer& container, const _TKey& key) {
|
||||||
|
#if __cplusplus < 202002L
|
||||||
|
return container.find(key) != container.end();
|
||||||
|
#else
|
||||||
|
return container.contains(key);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma endregion
|
||||||
|
|
||||||
|
}
|
|
@ -9,7 +9,7 @@ namespace YYCC::WinFctHelper {
|
||||||
HMODULE GetCurrentModule() {
|
HMODULE GetCurrentModule() {
|
||||||
// Reference: https://stackoverflow.com/questions/557081/how-do-i-get-the-hmodule-for-the-currently-executing-code
|
// Reference: https://stackoverflow.com/questions/557081/how-do-i-get-the-hmodule-for-the-currently-executing-code
|
||||||
HMODULE hModule = NULL;
|
HMODULE hModule = NULL;
|
||||||
GetModuleHandleExW(
|
::GetModuleHandleExW(
|
||||||
GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, // get address and do not inc ref counter.
|
GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, // get address and do not inc ref counter.
|
||||||
(LPCWSTR)GetCurrentModule,
|
(LPCWSTR)GetCurrentModule,
|
||||||
&hModule);
|
&hModule);
|
||||||
|
@ -24,7 +24,7 @@ namespace YYCC::WinFctHelper {
|
||||||
|
|
||||||
// fetch temp folder
|
// fetch temp folder
|
||||||
while (true) {
|
while (true) {
|
||||||
if ((expected_size = GetTempPathW(static_cast<DWORD>(wpath.size()), wpath.data())) == 0) {
|
if ((expected_size = ::GetTempPathW(static_cast<DWORD>(wpath.size()), wpath.data())) == 0) {
|
||||||
// failed, set to empty
|
// failed, set to empty
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -50,13 +50,13 @@ namespace YYCC::WinFctHelper {
|
||||||
DWORD copied_size;
|
DWORD copied_size;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
if ((copied_size = GetModuleFileNameW(hModule, wpath.data(), static_cast<DWORD>(wpath.size()))) == 0) {
|
if ((copied_size = ::GetModuleFileNameW(hModule, wpath.data(), static_cast<DWORD>(wpath.size()))) == 0) {
|
||||||
// failed, return
|
// failed, return
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check insufficient buffer
|
// check insufficient buffer
|
||||||
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
|
if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
|
||||||
// buffer is not enough, enlarge it and try again.
|
// buffer is not enough, enlarge it and try again.
|
||||||
wpath.resize(wpath.size() + MAX_PATH);
|
wpath.resize(wpath.size() + MAX_PATH);
|
||||||
} else {
|
} else {
|
||||||
|
@ -87,7 +87,27 @@ namespace YYCC::WinFctHelper {
|
||||||
|
|
||||||
bool IsValidCodePage(UINT code_page) {
|
bool IsValidCodePage(UINT code_page) {
|
||||||
CPINFOEXW cpinfo;
|
CPINFOEXW cpinfo;
|
||||||
return GetCPInfoExW(code_page, 0, &cpinfo);
|
return ::GetCPInfoExW(code_page, 0, &cpinfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL CopyFile(const yycc_u8string_view& lpExistingFileName, const yycc_u8string_view& lpNewFileName, BOOL bFailIfExists) {
|
||||||
|
std::wstring wExistingFileName, wNewFileName;
|
||||||
|
if (!YYCC::EncodingHelper::UTF8ToWchar(lpExistingFileName, wExistingFileName)) return FALSE;
|
||||||
|
if (!YYCC::EncodingHelper::UTF8ToWchar(lpNewFileName, wNewFileName)) return FALSE;
|
||||||
|
return ::CopyFileW(wExistingFileName.c_str(), wNewFileName.c_str(), bFailIfExists);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL MoveFile(const yycc_u8string_view& lpExistingFileName, const yycc_u8string_view& lpNewFileName) {
|
||||||
|
std::wstring wExistingFileName, wNewFileName;
|
||||||
|
if (!YYCC::EncodingHelper::UTF8ToWchar(lpExistingFileName, wExistingFileName)) return FALSE;
|
||||||
|
if (!YYCC::EncodingHelper::UTF8ToWchar(lpNewFileName, wNewFileName)) return FALSE;
|
||||||
|
return ::MoveFileW(wExistingFileName.c_str(), wNewFileName.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL DeleteFile(const yycc_u8string_view& lpFileName) {
|
||||||
|
std::wstring wFileName;
|
||||||
|
if (!YYCC::EncodingHelper::UTF8ToWchar(lpFileName, wFileName)) return FALSE;
|
||||||
|
return ::DeleteFileW(wFileName.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,6 +64,43 @@ namespace YYCC::WinFctHelper {
|
||||||
*/
|
*/
|
||||||
bool IsValidCodePage(UINT code_page);
|
bool IsValidCodePage(UINT code_page);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Copies an existing file to a new file.
|
||||||
|
* @param lpExistingFileName The name of an existing file.
|
||||||
|
* @param lpNewFileName The name of the new file.
|
||||||
|
* @param bFailIfExists
|
||||||
|
* If this parameter is TRUE and the new file specified by \c lpNewFileName already exists, the function fails.
|
||||||
|
* If this parameter is FALSE and the new file already exists, the function overwrites the existing file and succeeds.
|
||||||
|
* @return
|
||||||
|
* If the function succeeds, the return value is nonzero.
|
||||||
|
* If the function fails, the return value is zero. To get extended error information, call \c GetLastError.
|
||||||
|
* @remarks Same as Windows \c CopyFile: https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-copyfilew
|
||||||
|
*/
|
||||||
|
BOOL CopyFile(const yycc_u8string_view& lpExistingFileName, const yycc_u8string_view& lpNewFileName, BOOL bFailIfExists);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Moves an existing file or a directory, including its children.
|
||||||
|
* @param lpExistingFileName The current name of the file or directory on the local computer.
|
||||||
|
* @param lpNewFileName
|
||||||
|
* The new name for the file or directory. The new name must not already exist.
|
||||||
|
* A new file may be on a different file system or drive. A new directory must be on the same drive.
|
||||||
|
* @return
|
||||||
|
* If the function succeeds, the return value is nonzero.
|
||||||
|
* If the function fails, the return value is zero. To get extended error information, call \c GetLastError.
|
||||||
|
* @remarks Same as Windows \c MoveFile: https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-movefilew
|
||||||
|
*/
|
||||||
|
BOOL MoveFile(const yycc_u8string_view& lpExistingFileName, const yycc_u8string_view& lpNewFileName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Deletes an existing file.
|
||||||
|
* @param lpFileName The name of the file to be deleted.
|
||||||
|
* @return
|
||||||
|
* If the function succeeds, the return value is nonzero.
|
||||||
|
* If the function fails, the return value is zero. To get extended error information, call \c GetLastError.
|
||||||
|
* @remarks Same as Windows \c DeleteFile: https://learn.microsoft.com/e-us/windows/win32/api/winbase/nf-winbase-deletefile
|
||||||
|
*/
|
||||||
|
BOOL DeleteFile(const yycc_u8string_view& lpFileName);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -16,5 +16,8 @@
|
||||||
#undef LoadImage
|
#undef LoadImage
|
||||||
#undef GetTempPath
|
#undef GetTempPath
|
||||||
#undef GetModuleFileName
|
#undef GetModuleFileName
|
||||||
|
#undef CopyFile
|
||||||
|
#undef MoveFile
|
||||||
|
#undef DeleteFile
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -10,7 +10,7 @@
|
||||||
#include "ParserHelper.hpp"
|
#include "ParserHelper.hpp"
|
||||||
#include "IOHelper.hpp"
|
#include "IOHelper.hpp"
|
||||||
#include "WinFctHelper.hpp"
|
#include "WinFctHelper.hpp"
|
||||||
#include "FsPathPatch.hpp"
|
#include "StdPatch.hpp"
|
||||||
#include "ExceptionHelper.hpp"
|
#include "ExceptionHelper.hpp"
|
||||||
|
|
||||||
#include "ConfigManager.hpp"
|
#include "ConfigManager.hpp"
|
||||||
|
|
|
@ -394,13 +394,13 @@ namespace YYCCTestbench {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void FsPathPatch() {
|
static void StdPatch() {
|
||||||
|
|
||||||
std::filesystem::path test_path;
|
std::filesystem::path test_path;
|
||||||
for (const auto& strl : c_UTF8TestStrTable) {
|
for (const auto& strl : c_UTF8TestStrTable) {
|
||||||
test_path /= YYCC::FsPathPatch::FromUTF8Path(strl.c_str());
|
test_path /= YYCC::StdPatch::ToStdPath(strl.c_str());
|
||||||
}
|
}
|
||||||
YYCC::yycc_u8string test_slashed_path(YYCC::FsPathPatch::ToUTF8Path(test_path));
|
YYCC::yycc_u8string test_slashed_path(YYCC::StdPatch::ToUTF8Path(test_path));
|
||||||
|
|
||||||
#if YYCC_OS == YYCC_OS_WINDOWS
|
#if YYCC_OS == YYCC_OS_WINDOWS
|
||||||
std::wstring wdecilmer(1u, std::filesystem::path::preferred_separator);
|
std::wstring wdecilmer(1u, std::filesystem::path::preferred_separator);
|
||||||
|
@ -410,7 +410,7 @@ namespace YYCCTestbench {
|
||||||
#endif
|
#endif
|
||||||
YYCC::yycc_u8string test_joined_path(YYCC::StringHelper::Join(c_UTF8TestStrTable, decilmer.c_str()));
|
YYCC::yycc_u8string test_joined_path(YYCC::StringHelper::Join(c_UTF8TestStrTable, decilmer.c_str()));
|
||||||
|
|
||||||
Assert(test_slashed_path == test_joined_path, YYCC_U8("YYCC::FsPathPatch"));
|
Assert(test_slashed_path == test_joined_path, YYCC_U8("YYCC::StdPatch"));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -630,7 +630,7 @@ int main(int argc, char* argv[]) {
|
||||||
YYCCTestbench::StringTestbench();
|
YYCCTestbench::StringTestbench();
|
||||||
YYCCTestbench::ParserTestbench();
|
YYCCTestbench::ParserTestbench();
|
||||||
YYCCTestbench::WinFctTestbench();
|
YYCCTestbench::WinFctTestbench();
|
||||||
YYCCTestbench::FsPathPatch();
|
YYCCTestbench::StdPatch();
|
||||||
// advanced
|
// advanced
|
||||||
YYCCTestbench::ConfigManagerTestbench();
|
YYCCTestbench::ConfigManagerTestbench();
|
||||||
YYCCTestbench::ArgParserTestbench(argc, argv);
|
YYCCTestbench::ArgParserTestbench(argc, argv);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user