diff --git a/doc/src/std_patch.dox b/doc/src/std_patch.dox index ed9f98f..9a6b0e4 100644 --- a/doc/src/std_patch.dox +++ b/doc/src/std_patch.dox @@ -3,6 +3,41 @@ namespace YYCC::StdPatch { \page std_patch Standard Library Patch +\section std_patch__starts_with_ends_with Starts With & Ends With + +\c std::basic_string::starts_with and \c std::basic_string::ends_with (also available in \c std::basic_string_view) +are functions introduced in C++ 20 and unavailable in C++ 17. +YYCC::StdPatch provides a patch for these function in C++ 17 environment. +Please note these implementations are following implementation instruction presented by CppReference website. +And it should have the same performance with vanilla functions because Microsoft STL use the same way to implement. +These implementations will not fallback to vanilla function even they are available. +Because their performance are good. + +To use these functions, you just need to call them like corresponding vanilla functions. +Our implementations provide all necessary overloads. +The only thing you need to do is provide the string self as the first argument, +because our implementations can not be inserted as a class member of string. +There is an example: + +\code +YYCC::StdPatch::StartsWith(YYCC_U8("aabbcc"), YYCC_U8("aa")); +YYCC::StdPatch::EndsWith(YYCC_U8("aabbcc"), YYCC_U8("cc")); +\endcode + +\section std_patch__contains Contains + +\c Contains function in standard library ordered and unordered successive container are also introduced in C++ 20. +YYCC::StdPatch provides a patch for this function in C++ 17 environment. + +Please note this implementation will fallback to vanilla function if it is available. +Because our implementation is a remedy (there is no way to use public class member to have the same performance of vanilla function). +There is an example about how to use it: + +\code +std::set test { 1, 5 }; +YYCC::StdPatch::Contains(test, static_cast(5)); +\endcode + \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, diff --git a/doc/src/win_fct_helper.dox b/doc/src/win_fct_helper.dox index 6b17eb0..eaa6246 100644 --- a/doc/src/win_fct_helper.dox +++ b/doc/src/win_fct_helper.dox @@ -15,6 +15,9 @@ Currently this namespace has following functions: \li #GetModuleFileName: Get the path to module in file system by given handle. \li #GetLocalAppData: Get the path inside \%LOCALAPPDATA\% \li #IsValidCodePage: Check whether given code page number is valid. +\li #CopyFile: The UTF8 version of Win32 \c CopyFile. +\li #MoveFile: The UTF8 version of Win32 \c MoveFile. +\li #DeleteFile: The UTF8 version of Win32 \c DeleteFile. */ } \ No newline at end of file diff --git a/src/ExceptionHelper.cpp b/src/ExceptionHelper.cpp index 83888dc..b43c084 100644 --- a/src/ExceptionHelper.cpp +++ b/src/ExceptionHelper.cpp @@ -459,7 +459,7 @@ namespace YYCC::ExceptionHelper { if (!YYCC::WinFctHelper::GetModuleFileName(NULL, u8_process_path)) return false; // extract file name from full path by std::filesystem::path - std::filesystem::path process_path(StdPatch::ToStdPath(u8_process_path.c_str())); + std::filesystem::path process_path(StdPatch::ToStdPath(u8_process_path)); u8_process_name = StdPatch::ToUTF8Path(process_path.filename()); } // then get process id @@ -478,7 +478,7 @@ namespace YYCC::ExceptionHelper { if (!WinFctHelper::GetLocalAppData(u8_localappdata_path)) return false; // convert to std::filesystem::path - std::filesystem::path crash_report_path(StdPatch::ToStdPath(u8_localappdata_path.c_str())); + std::filesystem::path crash_report_path(StdPatch::ToStdPath(u8_localappdata_path)); // slash into crash report folder crash_report_path /= StdPatch::ToStdPath(YYCC_U8("CrashDumps")); // use create function to make sure it is existing @@ -486,8 +486,8 @@ namespace YYCC::ExceptionHelper { // build log path and coredump path // build std::filesystem::path first - std::filesystem::path log_filepath = crash_report_path / StdPatch::ToStdPath(u8_log_filename.c_str()); - std::filesystem::path coredump_filepath = crash_report_path / StdPatch::ToStdPath(u8_coredump_filename.c_str()); + std::filesystem::path log_filepath = crash_report_path / StdPatch::ToStdPath(u8_log_filename); + std::filesystem::path coredump_filepath = crash_report_path / StdPatch::ToStdPath(u8_coredump_filename); // output to result log_path = StdPatch::ToUTF8Path(log_filepath); coredump_path = StdPatch::ToUTF8Path(coredump_filepath); diff --git a/src/StdPatch.hpp b/src/StdPatch.hpp index a2f2a6c..1cfddf0 100644 --- a/src/StdPatch.hpp +++ b/src/StdPatch.hpp @@ -77,7 +77,7 @@ namespace YYCC::StdPatch { */ 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); + 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 diff --git a/testbench/main.cpp b/testbench/main.cpp index ca1b542..1d1b591 100644 --- a/testbench/main.cpp +++ b/testbench/main.cpp @@ -1,5 +1,7 @@ #include #include +#include +#include namespace Console = YYCC::ConsoleHelper; @@ -342,11 +344,12 @@ namespace YYCCTestbench { MessageBoxW( NULL, YYCC::EncodingHelper::UTF8ToWchar( - YYCC::StringHelper::Printf(YYCC_U8("Log generated:\nLog path: %s\nCore dump path: %s"), log_path.c_str(), coredump_path.c_str()) - ).c_str(), + YYCC::StringHelper::Printf(YYCC_U8("Log generated:\nLog path: %s\nCore dump path: %s"), log_path.c_str(), coredump_path.c_str()) + ).c_str(), L"Fatal Error", MB_OK + MB_ICONERROR ); - }); + } + ); // Perform a div zero exception. #if defined (YYCC_DEBUG_UE_FILTER) @@ -355,8 +358,7 @@ namespace YYCCTestbench { // all of code normally inside of main or WinMain here... int i = 1, j = 0; int k = i / j; - } - __except (YYCC::ExceptionHelper::DebugCallUExceptionImpl(GetExceptionInformation())) { + } __except (YYCC::ExceptionHelper::DebugCallUExceptionImpl(GetExceptionInformation())) { OutputDebugStringW(L"executed filter function\n"); } #else @@ -388,31 +390,52 @@ namespace YYCCTestbench { Assert(YYCC::WinFctHelper::GetLocalAppData(test_localappdata_path), YYCC_U8("YYCC::WinFctHelper::GetLocalAppData")); Console::FormatLine(YYCC_U8("Local AppData: %s"), test_localappdata_path.c_str()); - Assert(YYCC::WinFctHelper::IsValidCodePage(static_cast(1252)) == true, YYCC_U8("YYCC::WinFctHelper::IsValidCodePage")); - Assert(YYCC::WinFctHelper::IsValidCodePage(static_cast(114514)) == false, YYCC_U8("YYCC::WinFctHelper::IsValidCodePage")); + Assert(YYCC::WinFctHelper::IsValidCodePage(static_cast(1252)), YYCC_U8("YYCC::WinFctHelper::IsValidCodePage")); + Assert(!YYCC::WinFctHelper::IsValidCodePage(static_cast(114514)), YYCC_U8("YYCC::WinFctHelper::IsValidCodePage")); + + // MARK: There is no testbench for MoveFile, CopyFile DeleteFile. + // Because they can operate file system files. + // And may cause test environment entering unstable status. #endif } static void StdPatch() { + // Std Path + std::filesystem::path test_path; for (const auto& strl : c_UTF8TestStrTable) { - test_path /= YYCC::StdPatch::ToStdPath(strl.c_str()); - } + test_path /= YYCC::StdPatch::ToStdPath(strl); + } YYCC::yycc_u8string test_slashed_path(YYCC::StdPatch::ToUTF8Path(test_path)); #if YYCC_OS == YYCC_OS_WINDOWS std::wstring wdecilmer(1u, std::filesystem::path::preferred_separator); - YYCC::yycc_u8string decilmer(YYCC::EncodingHelper::WcharToUTF8(wdecilmer.c_str())); + YYCC::yycc_u8string decilmer(YYCC::EncodingHelper::WcharToUTF8(wdecilmer)); #else YYCC::yycc_u8string decilmer(1u, std::filesystem::path::preferred_separator); #endif YYCC::yycc_u8string test_joined_path(YYCC::StringHelper::Join(c_UTF8TestStrTable, decilmer.c_str())); - Assert(test_slashed_path == test_joined_path, YYCC_U8("YYCC::StdPatch")); + Assert(test_slashed_path == test_joined_path, YYCC_U8("YYCC::StdPatch::ToStdPath, YYCC::StdPatch::ToUTF8Path")); -} + // StartsWith, EndsWith + YYCC::yycc_u8string test_starts_ends_with(YYCC_U8("aaabbbccc")); + Assert(YYCC::StdPatch::StartsWith(test_starts_ends_with, YYCC_U8("aaa")), YYCC_U8("YYCC::StdPatch::StartsWith")); + Assert(!YYCC::StdPatch::StartsWith(test_starts_ends_with, YYCC_U8("ccc")), YYCC_U8("YYCC::StdPatch::StartsWith")); + Assert(!YYCC::StdPatch::EndsWith(test_starts_ends_with, YYCC_U8("aaa")), YYCC_U8("YYCC::StdPatch::EndsWith")); + Assert(YYCC::StdPatch::EndsWith(test_starts_ends_with, YYCC_U8("ccc")), YYCC_U8("YYCC::StdPatch::EndsWith")); + + // Contains + std::set test_set { 1, 2, 3, 4, 6, 7 }; + Assert(YYCC::StdPatch::Contains(test_set, static_cast(1)), YYCC_U8("YYCC::StdPatch::Contains")); + Assert(!YYCC::StdPatch::Contains(test_set, static_cast(5)), YYCC_U8("YYCC::StdPatch::Contains")); + std::map test_map { { 1, 1.0f }, { 4, 4.0f } }; + Assert(YYCC::StdPatch::Contains(test_map, static_cast(1)), YYCC_U8("YYCC::StdPatch::Contains")); + Assert(!YYCC::StdPatch::Contains(test_map, static_cast(5)), YYCC_U8("YYCC::StdPatch::Contains")); + + } enum class TestEnum : int8_t { Test1, Test2, Test3