From 4f0b3d19d16fc6707f08a006199a53e5e9d77891 Mon Sep 17 00:00:00 2001 From: yyc12345 Date: Fri, 25 Jul 2025 09:35:26 +0800 Subject: [PATCH] refactor: update C++ from 17 to 23 --- .gitignore | 2 +- CMakeLists.txt | 6 +- src/CMakeLists.txt | 70 ++---- src/yycc.hpp | 10 +- src/yycc/constraint/builder.hpp | 51 ++--- src/yycc/macro/feature_probe.hpp | 54 ----- src/yycc/num/parse.hpp | 166 ++------------ src/yycc/num/stringify.hpp | 39 ++-- src/yycc/patch/contains.hpp | 45 ---- src/yycc/patch/expected.hpp | 40 ---- src/yycc/patch/path.cpp | 48 ----- src/yycc/patch/path.hpp | 32 --- src/yycc/patch/starts_ends_with.hpp | 203 ----------------- src/yycc/{rust => }/primitive.hpp | 6 +- src/yycc/rust/num/parse.hpp | 97 --------- src/yycc/rust/num/stringify.hpp | 10 - src/yycc/string.hpp | 47 ---- src/yycc/string/op.cpp | 288 ++++++++++++------------- src/yycc/string/op.hpp | 155 ++++++------- src/yycc/string/reinterpret.cpp | 52 +++-- src/yycc/string/reinterpret.hpp | 23 +- src/yycc/windows/unsafe_suppressor.hpp | 16 -- testbench/CMakeLists.txt | 14 -- 23 files changed, 335 insertions(+), 1139 deletions(-) delete mode 100644 src/yycc/macro/feature_probe.hpp delete mode 100644 src/yycc/patch/contains.hpp delete mode 100644 src/yycc/patch/expected.hpp delete mode 100644 src/yycc/patch/path.cpp delete mode 100644 src/yycc/patch/path.hpp delete mode 100644 src/yycc/patch/starts_ends_with.hpp rename src/yycc/{rust => }/primitive.hpp (82%) delete mode 100644 src/yycc/rust/num/parse.hpp delete mode 100644 src/yycc/rust/num/stringify.hpp delete mode 100644 src/yycc/string.hpp delete mode 100644 src/yycc/windows/unsafe_suppressor.hpp diff --git a/.gitignore b/.gitignore index de21386..c8df3b4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ # -------------------- Output -------------------- out/ -src/YYCC/YYCCVersion.hpp +src/yycc/version.hpp CMakeSettings.json # -------------------- VSCode -------------------- diff --git a/CMakeLists.txt b/CMakeLists.txt index fe8158a..64eda3d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,11 +4,15 @@ project(YYCC LANGUAGES CXX ) +# Setup C++ standard +set(CMAKE_CXX_STANDARD 23) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) + # Provide options option(YYCC_BUILD_TESTBENCH "Build testbench of YYCCommonplace." OFF) option(YYCC_BUILD_DOC "Build document of YYCCommonplace." OFF) option(YYCC_ENFORCE_ICONV "Enforce iconv support for this library (e.g. in MSYS2 environment)." OFF) -option(YYCC_DEBUG_UE_FILTER "YYCC developer used switch for testing Windows unhandled exception filter. Should not set to ON!!!" OFF) # Setup install path from CMake provided install path for convenient use. include(GNUInstallDirs) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index cd84c60..6c23d52 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -14,24 +14,10 @@ PRIVATE yycc/string/reinterpret.cpp yycc/string/op.cpp yycc/rust/panic.cpp - yycc/patch/path.cpp yycc/encoding/stlcvt.cpp yycc/encoding/windows.cpp yycc/encoding/iconv.cpp yycc/encoding/pycodec.cpp - # YYCC/COMHelper.cpp - # YYCC/ArgParser.cpp - # YYCC/ConfigManager.cpp - # YYCC/ConsoleHelper.cpp - # YYCC/DialogHelper.cpp - # YYCC/EncodingHelper.cpp - # YYCC/ExceptionHelper.cpp - # YYCC/StdPatch.cpp - # YYCC/IOHelper.cpp - # YYCC/StringHelper.cpp - # YYCC/WinFctHelper.cpp - # # Natvis (only for MSVC) - # $<$:YYCC.natvis> ) target_sources(YYCCommonplace PUBLIC @@ -40,63 +26,29 @@ FILES # Headers yycc.hpp yycc/version.hpp + yycc/primitive.hpp yycc/prelude/core.hpp yycc/prelude/rust.hpp yycc/macro/version_cmp.hpp - yycc/macro/feature_probe.hpp yycc/macro/os_detector.hpp yycc/macro/endian_detector.hpp yycc/macro/compiler_detector.hpp yycc/macro/class_copy_move.hpp - yycc/string.hpp yycc/string/reinterpret.hpp yycc/string/op.hpp yycc/num/parse.hpp yycc/num/stringify.hpp - yycc/rust/primitive.hpp yycc/rust/panic.hpp yycc/rust/option.hpp yycc/rust/result.hpp - yycc/rust/num/parse.hpp - yycc/rust/num/stringify.hpp - yycc/windows/unsafe_suppressor.hpp yycc/windows/import_guard_head.hpp 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 - yycc/patch/expected.hpp yycc/encoding/stlcvt.hpp yycc/encoding/windows.hpp yycc/encoding/iconv.hpp yycc/encoding/pycodec.hpp - - # # Headers - # # Common headers - # YYCC/Constraints.hpp - # YYCC/COMHelper.hpp - # YYCC/ArgParser.hpp - # YYCC/ConfigManager.hpp - # YYCC/ConsoleHelper.hpp - # YYCC/DialogHelper.hpp - # YYCC/EncodingHelper.hpp - # YYCC/EnumHelper.hpp - # YYCC/ExceptionHelper.hpp - # YYCC/StdPatch.hpp - # YYCC/IOHelper.hpp - # YYCC/ParserHelper.hpp - # YYCC/StringHelper.hpp - # YYCC/WinFctHelper.hpp - # # Windows including guard pair - # YYCC/WinImportPrefix.hpp - # YYCC/WinImportSuffix.hpp - # # Internal - # YYCC/YYCCVersion.hpp - # YYCC/YYCCInternal.hpp - # # Exposed - # YYCCommonplace.hpp ) # Setup header infomations target_include_directories(YYCCommonplace @@ -116,14 +68,9 @@ target_link_libraries(YYCCommonplace PRIVATE $<$:DbgHelp.lib> ) -# Setup C++ standard -target_compile_features(YYCCommonplace PUBLIC cxx_std_17) -set_target_properties(YYCCommonplace PROPERTIES CXX_EXTENSION OFF) # Setup macros target_compile_definitions(YYCCommonplace PUBLIC - # Debug macro. And it should populate to child projects - $<$:YYCC_DEBUG_UE_FILTER> # Iconv environment macro $<$:YYCC_FEAT_ICONV> # OS macro @@ -136,14 +83,21 @@ PUBLIC # Endian macro $<$:YYCC_ENDIAN_LITTLE> $<$:YYCC_ENDIAN_BIG> -PRIVATE - # Unicode charset for private using + # Use Unicode charset on MSVC $<$:UNICODE> $<$:_UNICODE> + # Fix MSVC shit + $<$:_CRT_SECURE_NO_WARNINGS> + $<$:_CRT_SECURE_NO_DEPRECATE> + $<$:_CRT_NONSTDC_NO_WARNINGS> + $<$:_CRT_NONSTDC_NO_DEPRECATE> + # Fix Windows header file shit + $<$:WIN32_LEAN_AND_MEAN> + $<$:NOMINMAX> ) target_compile_options(YYCCommonplace -# Order build as UTF-8 in MSVC -PRIVATE +PUBLIC + # Order build as UTF-8 in MSVC $<$:/utf-8> ) diff --git a/src/yycc.hpp b/src/yycc.hpp index 07adb9e..58ab9ba 100644 --- a/src/yycc.hpp +++ b/src/yycc.hpp @@ -4,11 +4,13 @@ #include "yycc/version.hpp" #include "yycc/macro/version_cmp.hpp" -// Operating System Identifier Macros +// Detect essential macros +// Operating System macros #include "yycc/macro/os_detector.hpp" - -// Windows Shitty Behavior Disable Macros -#include "yycc/windows/unsafe_suppressor.hpp" +// Compiler macros +#include "yycc/macro/compiler_detector.hpp" +// Endian macros +#include "yycc/macro/endian_detector.hpp" // Batch Class Move / Copy Function Macros #include "yycc/macro/class_copy_move.hpp" diff --git a/src/yycc/constraint/builder.hpp b/src/yycc/constraint/builder.hpp index 4593d41..0d2186e 100644 --- a/src/yycc/constraint/builder.hpp +++ b/src/yycc/constraint/builder.hpp @@ -1,10 +1,7 @@ #pragma once #include "../constraint.hpp" -#include "../string.hpp" #include -#define NS_YYCC_STRING ::yycc::string - /// @brief The namespace containing convenient function building common used Constraint instance. namespace yycc::constraint::builder { @@ -15,18 +12,12 @@ namespace yycc::constraint::builder { * @param[in] max_value The maximum value of range (inclusive). * @return The generated constraint instance which can be directly applied. */ - template && !std::is_same_v, int> = 0> + template && !std::is_same_v, int> = 0> Constraint min_max_constraint(T min_value, T max_value) { - if (min_value > max_value) - throw std::invalid_argument("the max value must be equal or greater than min value"); + if (min_value > max_value) throw std::invalid_argument("the max value must be equal or greater than min value"); - auto fn_check = [min_value, max_value](const T& val) -> bool { - return (val <= max_value) && (val >= min_value); - }; - auto fn_clamp = [min_value, max_value](const T& val) -> T { - return std::clamp(val, min_value, max_value); - }; + auto fn_check = [min_value, max_value](const T& val) -> bool { return (val <= max_value) && (val >= min_value); }; + auto fn_clamp = [min_value, max_value](const T& val) -> T { return std::clamp(val, min_value, max_value); }; return Constraint(std::move(fn_check), std::move(fn_clamp)); } @@ -39,16 +30,13 @@ namespace yycc::constraint::builder { */ template, int> = 0> Constraint enum_constraint(const std::initializer_list& il, size_t default_index = 0u) { - if (default_index >= il.size()) - throw std::invalid_argument("the default index must be a valid index in given list"); + if (default_index >= il.size()) throw std::invalid_argument("the default index must be a valid index in given list"); T default_entry = il.begin()[default_index]; std::set entries(il); // TODO: modify it as `contain` once we finish patch namespace. - auto fn_check = [entries](const T& val) -> bool { - return entries.find(val) != entries.end(); - }; + auto fn_check = [entries](const T& val) -> bool { return entries.find(val) != entries.end(); }; auto fn_clamp = [entries, default_entry](const T& val) -> T { if (entries.find(val) != entries.end()) { return val; @@ -65,30 +53,21 @@ namespace yycc::constraint::builder { * @param[in] default_index The index of default value in given list. * @return The generated constraint instance which can be directly applied. */ - inline Constraint strenum_constraint( - const std::initializer_list& il, size_t default_index = 0u) { - if (default_index >= il.size()) - throw std::invalid_argument("the default index must be a valid index in given list"); + inline Constraint strenum_constraint(const std::initializer_list& il, size_t default_index = 0u) { + if (default_index >= il.size()) throw std::invalid_argument("the default index must be a valid index in given list"); - NS_YYCC_STRING::u8string default_entry = NS_YYCC_STRING::u8string(il.begin()[default_index]); - std::set entries; + std::u8string default_entry = std::u8string(il.begin()[default_index]); + std::set entries; for (const auto& i : il) { entries.emplace(i); } - // TODO: modify it as `contain` once we finish patch namespace. - auto fn_check = [entries](const NS_YYCC_STRING::u8string& val) -> bool { - return entries.find(val) != entries.end(); + auto fn_check = [entries](const std::u8string& val) -> bool { return entries.contains(val); }; + auto fn_clamp = [entries, default_entry](const std::u8string& val) -> std::u8string { + if (entries.contains(val)) return val; + else return default_entry; }; - auto fn_clamp = [entries, default_entry]( - const NS_YYCC_STRING::u8string& val) -> NS_YYCC_STRING::u8string { - if (entries.find(val) != entries.end()) { - return val; - } else { - return default_entry; - } - }; - return Constraint(std::move(fn_check), fn_clamp); + return Constraint(std::move(fn_check), fn_clamp); } } // namespace yycc::constraint::builder diff --git a/src/yycc/macro/feature_probe.hpp b/src/yycc/macro/feature_probe.hpp deleted file mode 100644 index 12dded6..0000000 --- a/src/yycc/macro/feature_probe.hpp +++ /dev/null @@ -1,54 +0,0 @@ -#pragma once - -// Hint for C++ feature detection: -// __cplusplus macro need special compiler switch enabled when compiling. -// So we use _MSVC_LANG check it instead. - -// ===== C++ Version ===== - -// Detect C++ 20 -#if __cplusplus >= 202002L || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L) - #define YYCC_CPPFEAT_GE_CPP20 -#endif - -// Detect C++ 23 -#if __cplusplus >= 202302L || (defined(_MSVC_LANG) && _MSVC_LANG >= 202302L) - #define YYCC_CPPFEAT_GE_CPP23 -#endif - -// ===== C++ Features ===== - -// Check whether there is support of UTF8 string system. -#if defined(__cpp_char8_t) || defined(YYCC_CPPFEAT_GE_CPP20) - #define YYCC_CPPFEAT_UTF8 -#endif - -// Check whether there is support of `contains` for `set` and `map` including their varients. -#if defined(YYCC_CPPFEAT_GE_CPP20) - #define YYCC_CPPFEAT_CONTAINS -#endif - -// Check whether there is support of `starts_with` and `ends_with` for `basic_string`. -#if defined(__cpp_lib_starts_ends_with) || defined(YYCC_CPPFEAT_GE_CPP20) - #define YYCC_CPPFEAT_STARTS_ENDS_WITH -#endif - -// Check whether there is support of `std::expected`. -#if defined(__cpp_lib_expected) || defined(YYCC_CPPFEAT_GE_CPP23) - #define YYCC_CPPFEAT_EXPECTED -#endif - -// Check whether there is support of `std::format`. -#if defined(YYCC_CPPFEAT_GE_CPP20) - #define YYCC_CPPFEAT_FORMAT -#endif - -// Check whether there is support of `__VA_OPT__` -#if defined(YYCC_CPPFEAT_GE_CPP20) - #define YYCC_CPPFEAT_VA_OPT -#endif - -// Check whether there is support of `std::stacktrace` and its formatter. -#if (defined(__cpp_lib_starts_ends_with) && defined(__cpp_lib_formatters)) || defined(YYCC_CPPFEAT_GE_CPP23) - #define YYCC_CPPFEAT_STACKTRACE -#endif diff --git a/src/yycc/num/parse.hpp b/src/yycc/num/parse.hpp index 07a0f43..ef2a1dc 100644 --- a/src/yycc/num/parse.hpp +++ b/src/yycc/num/parse.hpp @@ -1,15 +1,14 @@ #pragma once -#include "../patch/expected.hpp" -#include "../string.hpp" #include "../string/op.hpp" #include "../string/reinterpret.hpp" +#include +#include #include #include +#include -#define NS_YYCC_STRING ::yycc::string #define NS_YYCC_STRING_REINTERPRET ::yycc::string::reinterpret #define NS_YYCC_STRING_OP ::yycc::string::op -#define NS_YYCC_PATCH_EXPECTED ::yycc::patch::expected /** * @brief Provides string parsing utilities for converting strings to numeric and boolean values. @@ -20,18 +19,16 @@ */ namespace yycc::num::parse { - /// @private /// @brief The error kind when parsing string into number. enum class ParseError { PartiallyParsed, ///< Only a part of given string was parsed. The whole string may be invalid. InvalidString, ///< Given string is a invalid number string. - OutOfRange, ///< Given string is valid but its value out of the range of given number type. + OutOfRange, ///< Given string is valid but its value out of the range of given number type. }; - /// @private /// @brief The return value of internal parse function which ape `std::expected`. template - using ParseResult = NS_YYCC_PATCH_EXPECTED::Expected; + using ParseResult = std::expected; /** * @private @@ -41,8 +38,9 @@ namespace yycc::num::parse { * @param fmt The floating point format to use * @return ParseResult containing either the parsed value or a ParseError */ - template, int> = 0> - ParseResult priv_parse(const NS_YYCC_STRING::u8string_view& strl, std::chars_format fmt) { + template + requires(std::is_floating_point_v) + ParseResult parse(const std::u8string_view& strl, std::chars_format fmt) { namespace reinterpret = NS_YYCC_STRING_REINTERPRET; T rv; @@ -54,13 +52,13 @@ namespace yycc::num::parse { // Parse completely. // But we need to check whether the whole string was parsed. if (ptr == tail) return rv; - else return ParseError::PartiallyParsed; + else return std::unexpected(ParseError::PartiallyParsed); } else if (ec == std::errc::invalid_argument) { // Given string is invalid - return ParseError::InvalidString; + return std::unexpected(ParseError::InvalidString); } else if (ec == std::errc::result_out_of_range) { // Given string is out of range - return ParseError::OutOfRange; + return std::unexpected(ParseError::OutOfRange); } else { // Unreachable throw std::runtime_error("invalid ec."); @@ -75,8 +73,9 @@ namespace yycc::num::parse { * @param base Numeric base (2-36) * @return ParseResult containing either the parsed value or a ParseError */ - template && !std::is_same_v, int> = 0> - ParseResult priv_parse(const NS_YYCC_STRING::u8string_view& strl, int base) { + template + requires(std::is_integral_v && !std::is_same_v) + ParseResult parse(const std::u8string_view& strl, int base) { namespace reinterpret = NS_YYCC_STRING_REINTERPRET; T rv; @@ -88,13 +87,13 @@ namespace yycc::num::parse { // Parse completely. // But we need to check whether the whole string was parsed. if (ptr == tail) return rv; - else return ParseError::PartiallyParsed; + else return std::unexpected(ParseError::PartiallyParsed); } else if (ec == std::errc::invalid_argument) { // Given string is invalid - return ParseError::InvalidString; + return std::unexpected(ParseError::InvalidString); } else if (ec == std::errc::result_out_of_range) { // Given string is out of range - return ParseError::OutOfRange; + return std::unexpected(ParseError::OutOfRange); } else { // Unreachable throw std::runtime_error("invalid ec."); @@ -108,139 +107,18 @@ namespace yycc::num::parse { * @param strl The UTF-8 string view to parse ("true" or "false", case insensitive) * @return ParseResult containing either the parsed value or a ParseError */ - template, int> = 0> - ParseResult priv_parse(const NS_YYCC_STRING::u8string_view& strl) { + template + requires(std::is_same_v) + ParseResult parse(const std::u8string_view& strl) { // Get lower case auto lower_case = NS_YYCC_STRING_OP::to_lower(strl); // Compare result - if (lower_case == YYCC_U8("true")) return true; - else if (lower_case == YYCC_U8("false")) return false; + if (lower_case == u8"true") return true; + else if (lower_case == u8"false") return false; else return ParseError::InvalidString; } - /** - * @brief Try parsing given string to floating point types. - * @tparam T The type derived from floating point type. - * @param[in] strl The string need to be parsed. - * @param[out] num - * The variable receiving result. - * There is no guarantee that the content is not modified when parsing failed. - * @param[in] fmt The floating point format used when try parsing. - * @return True if success, otherwise false. - */ - template, int> = 0> - bool try_parse(const NS_YYCC_STRING::u8string_view& strl, - T& num, - std::chars_format fmt = std::chars_format::general) { - namespace expected = NS_YYCC_PATCH_EXPECTED; - - auto rv = priv_parse(strl, fmt); - if (expected::is_value(rv)) { - num = expected::get_value(rv); - return true; - } else { - return false; - } - } - /** - * @brief Try parsing given string to integral types. - * @tparam T The type derived from integral type except bool type. - * @param[in] strl The string need to be parsed. - * @param[out] num - * The variable receiving result. - * There is no guarantee that the content is not modified when parsing failed. - * @param[in] base Integer base to use: a value between 2 and 36 (inclusive). - * @return True if success, otherwise false. - */ - template && !std::is_same_v, int> = 0> - bool try_parse(const NS_YYCC_STRING::u8string_view& strl, T& num, int base = 10) { - namespace expected = NS_YYCC_PATCH_EXPECTED; - - auto rv = priv_parse(strl, base); - if (expected::is_value(rv)) { - num = expected::get_value(rv); - return true; - } else { - return false; - } - } - /** - * @brief Try parsing given string to bool types. - * @tparam T The type derived from bool type. - * @param[in] strl The string need to be parsed ("true" or "false", case insensitive). - * @param[out] num - * The variable receiving result. - * There is no guarantee that the content is not modified when parsing failed. - * @return True if success, otherwise false. - */ - template, int> = 0> - bool try_parse(const NS_YYCC_STRING::u8string_view& strl, T& num) { - namespace expected = NS_YYCC_PATCH_EXPECTED; - - auto rv = priv_parse(strl); - if (expected::is_value(rv)) { - num = expected::get_value(rv); - return true; - } else { - return false; - } - } - - /** - * @brief Parse given string to floating point types. - * @tparam T The type derived from floating point type. - * @param[in] strl The string need to be parsed. - * @param[in] fmt The floating point format used when try parsing. - * @return - * The parsing result. - * There is no guarantee about the content of this return value when parsing failed. - * It may be any possible value but usually is its default value. - * @exception std::invalid_argument Can not parse given string. - */ - template, int> = 0> - T parse(const NS_YYCC_STRING::u8string_view& strl, - std::chars_format fmt = std::chars_format::general) { - T rv; - if (try_parse(strl, rv, fmt)) return rv; - else throw std::invalid_argument("can not parse given string"); - } - /** - * @brief Parse given string to integral type types. - * @tparam T The type derived from integral type except bool type. - * @param[in] strl The string need to be parsed. - * @param[in] base Integer base to use: a value between 2 and 36 (inclusive). - * @return - * The parsing result. - * There is no guarantee about the content of this return value when parsing failed. - * It may be any possible value but usually is its default value. - * @exception std::invalid_argument Can not parse given string. - */ - template && !std::is_same_v, int> = 0> - T parse(const NS_YYCC_STRING::u8string_view& strl, int base = 10) { - T rv; - if (try_parse(strl, rv, base)) return rv; - else throw std::invalid_argument("can not parse given string"); - } - /** - * @brief Parse given string to bool types. - * @tparam T The type derived from bool type. - * @param[in] strl The string need to be parsed ("true" or "false", case insensitive). - * @return - * The parsing result. - * There is no guarantee about the content of this return value when parsing failed. - * It may be any possible value but usually is its default value. - * @exception std::invalid_argument Can not parse given string. - */ - template, int> = 0> - T parse(const NS_YYCC_STRING::u8string_view& strl) { - T rv; - if (try_parse(strl, rv)) return rv; - else throw std::invalid_argument("can not parse given string"); - } - } // namespace yycc::num::parse -#undef NS_YYCC_PATCH_EXPECTED #undef NS_YYCC_STRING_OP #undef NS_YYCC_STRING_REINTERPRET -#undef NS_YYCC_STRING diff --git a/src/yycc/num/stringify.hpp b/src/yycc/num/stringify.hpp index 3ae2492..3e05e5b 100644 --- a/src/yycc/num/stringify.hpp +++ b/src/yycc/num/stringify.hpp @@ -1,12 +1,11 @@ #pragma once -#include "../string.hpp" #include "../string/reinterpret.hpp" +#include #include +#include #include #include -#include -#define NS_YYCC_STRING ::yycc::string #define NS_YYCC_STRING_REINTERPRET ::yycc::string::reinterpret /** @@ -25,7 +24,7 @@ namespace yycc::num::stringify { inline constexpr size_t STRINGIFY_BUFFER_SIZE = 64u; /// @private /// @brief Type alias for the buffer used in string conversion. - using StringifyBuffer = std::array; + using StringifyBuffer = std::array; /** * @brief Return the string representation of given floating point value. @@ -35,10 +34,9 @@ namespace yycc::num::stringify { * @param[in] precision The floating point precision used when getting string representation. * @return The string representation of given value. */ - template, int> = 0> - NS_YYCC_STRING::u8string stringify(T num, - std::chars_format fmt = std::chars_format::general, - int precision = 6) { + template + requires(std::is_floating_point_v) + std::u8string stringify(T num, std::chars_format fmt = std::chars_format::general, int precision = 6) { namespace reinterpret = NS_YYCC_STRING_REINTERPRET; StringifyBuffer buffer; @@ -48,8 +46,7 @@ namespace yycc::num::stringify { fmt, precision); if (ec == std::errc()) { - return NS_YYCC_STRING::u8string(buffer.data(), - reinterpret::as_utf8(ptr) - buffer.data()); + return std::u8string(buffer.data(), reinterpret::as_utf8(ptr) - buffer.data()); } else if (ec == std::errc::value_too_large) { // Too short buffer. This should not happen. throw std::out_of_range("stringify() buffer is not sufficient."); @@ -65,18 +62,18 @@ namespace yycc::num::stringify { * @param[in] base Integer base used when getting string representation: a value between 2 and 36 (inclusive). * @return The string representation of given value. */ - template && !std::is_same_v, int> = 0> - NS_YYCC_STRING::u8string stringify(T num, int base = 10) { + template + requires(std::is_integral_v && !std::is_same_v) + std::u8string stringify(T num, int base = 10) { namespace reinterpret = NS_YYCC_STRING_REINTERPRET; - + StringifyBuffer buffer; auto [ptr, ec] = std::to_chars(reinterpret::as_ordinary(buffer.data()), reinterpret::as_ordinary(buffer.data() + buffer.size()), num, base); if (ec == std::errc()) { - return NS_YYCC_STRING::u8string(buffer.data(), - reinterpret::as_utf8(ptr) - buffer.data()); + return std::u8string(buffer.data(), reinterpret::as_utf8(ptr) - buffer.data()); } else if (ec == std::errc::value_too_large) { // Too short buffer. This should not happen. throw std::out_of_range("stringify() buffer is not sufficient."); @@ -91,13 +88,13 @@ namespace yycc::num::stringify { * @param[in] num The value need to get string representation. * @return The string representation of given value ("true" or "false"). */ - template, int> = 0> - NS_YYCC_STRING::u8string stringify(T num) { - if (num) return NS_YYCC_STRING::u8string(YYCC_U8("true")); - else return NS_YYCC_STRING::u8string(YYCC_U8("false")); + template + requires(std::is_same_v) + std::u8string stringify(T num) { + if (num) return std::u8string(u8"true"); + else return std::u8string(u8"false"); } -} // namespace yycc::string::stringify +} // namespace yycc::num::stringify #undef NS_YYCC_STRING_REINTERPRET -#undef NS_YYCC_STRING diff --git a/src/yycc/patch/contains.hpp b/src/yycc/patch/contains.hpp deleted file mode 100644 index 05ad791..0000000 --- a/src/yycc/patch/contains.hpp +++ /dev/null @@ -1,45 +0,0 @@ -#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/expected.hpp b/src/yycc/patch/expected.hpp deleted file mode 100644 index 2ba8126..0000000 --- a/src/yycc/patch/expected.hpp +++ /dev/null @@ -1,40 +0,0 @@ -#pragma once -#include -#include - -/** - * @brief A stupid polyfill for std::expected, - * - * For those C++ standard which do not support std::expected, - * we provide this namespace with a pretty bad but at least working std::expected pplyfill. - * - * The polyfill was done by std::variant. - * - * This namespace is used by this project because this framework must support C++ 17. - */ -namespace yycc::patch::expected { - - template, int> = 0> - using Expected = std::variant; - - template - bool is_value(const Expected& exp) { - return exp.index() == 0u; - } - - template - bool is_error(const Expected& exp) { - return exp.index() == 1u; - } - - template - const TValue& get_value(const Expected& exp) { - return std::get<0>(exp); - } - - template - const TError& get_error(const Expected& exp) { - return std::get<1>(exp); - } - -} diff --git a/src/yycc/patch/path.cpp b/src/yycc/patch/path.cpp deleted file mode 100644 index 883b054..0000000 --- a/src/yycc/patch/path.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#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 defined(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 defined(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 deleted file mode 100644 index 87ede4f..0000000 --- a/src/yycc/patch/path.hpp +++ /dev/null @@ -1,32 +0,0 @@ -#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 deleted file mode 100644 index 67da6fb..0000000 --- a/src/yycc/patch/starts_ends_with.hpp +++ /dev/null @@ -1,203 +0,0 @@ -#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/rust/primitive.hpp b/src/yycc/primitive.hpp similarity index 82% rename from src/yycc/rust/primitive.hpp rename to src/yycc/primitive.hpp index 81f0855..a4ffa83 100644 --- a/src/yycc/rust/primitive.hpp +++ b/src/yycc/primitive.hpp @@ -1,9 +1,9 @@ #pragma once #include #include -#include "../string.hpp" +#include -namespace yycc::rust::primitive { +namespace yycc::primitive { // `bool` is keyword so should not declare it anymore. // `char` is keyword so should not declare it anymore. @@ -23,6 +23,6 @@ namespace yycc::rust::primitive { using f32 = float; using f64 = double; - using str = ::yycc::string::u8string_view; + using str = std::u8string_view; } diff --git a/src/yycc/rust/num/parse.hpp b/src/yycc/rust/num/parse.hpp deleted file mode 100644 index 48dc718..0000000 --- a/src/yycc/rust/num/parse.hpp +++ /dev/null @@ -1,97 +0,0 @@ -#pragma once -#include "../../macro/feature_probe.hpp" -#include "../../num/parse.hpp" -#include "../result.hpp" - -#define NS_YYCC_STRING ::yycc::string -#define NS_YYCC_NUM_PARSE ::yycc::num::parse -#define NS_YYCC_RUST_RESULT ::yycc::rust::result -#define NS_YYCC_PATCH_EXPECTED ::yycc::patch::expected - -/** - * @namespace yycc::rust::parse - * @brief Provides Rust-inspired parsing utilities for converting strings to various types. - * @details - * This namespace contains template functions for parsing strings into different types - * (floating-point, integral, boolean) with Rust-like Result error handling. - */ -namespace yycc::rust::num::parse { - -#if defined(YYCC_CPPFEAT_EXPECTED) - - /// @brief The error type of parsing. - using Error = NS_YYCC_NUM_PARSE::ParseError; - - /// @brief The result type of parsing. - /// @tparam T The expected value type in result. - template - using Result = NS_YYCC_RUST_RESULT::Result; - - /** - * @brief Parses a string into a floating-point value. - * @tparam T Floating-point type to parse into (float, double, etc.) - * @param strl String view to parse - * @param fmt Formatting flags for parsing (default: general) - * @return Result containing either the parsed value or an error - */ - template, int> = 0> - Result parse(const NS_YYCC_STRING::u8string_view& strl, - std::chars_format fmt = std::chars_format::general) { - namespace expected = NS_YYCC_PATCH_EXPECTED; - namespace result = NS_YYCC_RUST_RESULT; - - auto rv = NS_YYCC_NUM_PARSE::priv_parse(strl, fmt); - if (expected::is_value(rv)) { - return result::Ok>(expected::get_value(rv)); - } else { - return result::Err>(expected::get_error(rv)); - } - } - - /** - * @brief Parses a string into an integral value (excluding bool). - * @tparam T Integral type to parse into (int, long, etc.) - * @param strl String view to parse - * @param base Numeric base for parsing (default: 10) - * @return Result containing either the parsed value or an error - */ - template && !std::is_same_v, int> = 0> - Result parse(const NS_YYCC_STRING::u8string_view& strl, int base = 10) { - namespace expected = NS_YYCC_PATCH_EXPECTED; - namespace result = NS_YYCC_RUST_RESULT; - - auto rv = NS_YYCC_NUM_PARSE::priv_parse(strl, base); - if (expected::is_value(rv)) { - return result::Ok>(expected::get_value(rv)); - } else { - return result::Err>(expected::get_error(rv)); - } - } - - /** - * @brief Parses a string into a boolean value. - * @tparam T Must be bool type - * @param strl String view to parse - * @return Result containing either the parsed value or an error - */ - template, int> = 0> - Result parse(const NS_YYCC_STRING::u8string_view& strl) { - namespace expected = NS_YYCC_PATCH_EXPECTED; - namespace result = NS_YYCC_RUST_RESULT; - - auto rv = NS_YYCC_NUM_PARSE::priv_parse(strl); - if (expected::is_value(rv)) { - return result::Ok>(expected::get_value(rv)); - } else { - return result::Err>(expected::get_error(rv)); - } - } - -#endif - -} - -#undef NS_YYCC_PATCH_EXPECTED -#undef NS_YYCC_RUST_RESULT -#undef NS_YYCC_NUM_PARSE -#undef NS_YYCC_STRING diff --git a/src/yycc/rust/num/stringify.hpp b/src/yycc/rust/num/stringify.hpp deleted file mode 100644 index db7b199..0000000 --- a/src/yycc/rust/num/stringify.hpp +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once -#include "../../num/stringify.hpp" - -namespace yycc::rust::num::stringify { - - // There is no modification for legacy "stringify" functions like "parse". - // So we simply expose all functions into this namespace. - using namespace ::yycc::num::stringify; - -} // namespace yycc::rust::stringify diff --git a/src/yycc/string.hpp b/src/yycc/string.hpp deleted file mode 100644 index f1f2f20..0000000 --- a/src/yycc/string.hpp +++ /dev/null @@ -1,47 +0,0 @@ -#pragma once - -// Define the UTF8 char type we used. -// And do a polyfill if no embedded char8_t type. - -#include "macro/feature_probe.hpp" -#include -#include - -namespace yycc::string { - /** - \typedef u8char_t - \brief YYCC UTF8 char type. - \details - This char type is an alias to \c char8_t if your current C++ standard support it. - Otherwise it is defined as unsigned char as C++ 20 stdandard does. - */ - /** - \typedef u8string - \brief YYCC UTF8 string container type. - \details - This type is defined as \c std::basic_string. - It is equal to \c std::u8string if your current C++ standard support it. - */ - /** - \typedef u8string_view - \brief YYCC UTF8 string view type. - \details - This type is defined as \c std::basic_string_view. - It is equal to \c std::u8string_view if your current C++ standard support it. - */ - -#if defined(YYCC_CPPFEAT_UTF8) - using u8char = char8_t; - using u8string = std::u8string; - using u8string_view = std::u8string_view; -#else - using u8char = unsigned char; - using u8string = std::basic_string; - using u8string_view = std::basic_string_view; -#endif - -#define _YYCC_U8(strl) u8 ## strl ///< The assistant macro for YYCC_U8. -#define YYCC_U8(strl) (reinterpret_cast(_YYCC_U8(strl))) ///< The macro for creating UTF8 string literal. See \ref library_encoding. -#define YYCC_U8_CHAR(chr) (static_cast<::yycc::string::u8char>(chr)) ///< The macro for casting ordinary char type into YYCC UTF8 char type. - -} // namespace yycc::string diff --git a/src/yycc/string/op.cpp b/src/yycc/string/op.cpp index 0916321..2087143 100644 --- a/src/yycc/string/op.cpp +++ b/src/yycc/string/op.cpp @@ -1,196 +1,180 @@ #include "op.hpp" #include -#include "reinterpret.hpp" - -#define NS_YYCC_STRING ::yycc::string -#define NS_YYCC_STRING_REINTERPRET ::yycc::string::reinterpret namespace yycc::string::op { #pragma region Printf VPrintf - bool printf(NS_YYCC_STRING::u8string& strl, const NS_YYCC_STRING::u8char* format, ...) { - va_list argptr; - va_start(argptr, format); - bool ret = vprintf(strl, format, argptr); - va_end(argptr); - return ret; - } + template + requires(sizeof(TChar) == sizeof(char)) + static FormatResult> generic_printf(const TChar* format, va_list argptr) { + // Prepare result + std::basic_string rv; - bool vprintf(NS_YYCC_STRING::u8string& strl, const NS_YYCC_STRING::u8char* format, va_list argptr) { - namespace reinterpret = NS_YYCC_STRING_REINTERPRET; + // Check format + if (format == nullptr) return std::unexpected(FormatError::NullFormat); - va_list args1; - va_copy(args1, argptr); - va_list args2; - va_copy(args2, argptr); + // Prepare variable arguments + va_list args1; + va_copy(args1, argptr); + va_list args2; + va_copy(args2, argptr); - // the return value is desired char count without NULL terminal. - // minus number means error - int count = std::vsnprintf( - nullptr, - 0, - reinterpret::as_ordinary(format), - args1 - ); - if (count < 0) { - // invalid length returned by vsnprintf. - return false; - } - va_end(args1); + // The return value is desired char count without NULL terminal. + // Minus number means error. + int count = std::vsnprintf(nullptr, 0, reinterpret_cast(format), args1); + // Check expected size. + if (count < 0) { + // Invalid length returned by vsnprintf. + return std::unexpected(FormatError::NoExpSize); + } + va_end(args1); - // resize std::string to desired count. - // and pass its length + 1 to std::vsnprintf, - // because std::vsnprintf only can write "buf_size - 1" chars with a trailing NULL. - // however std::vsnprintf already have a trailing NULL, so we plus 1 for it. - strl.resize(count); - int write_result = std::vsnprintf( - reinterpret::as_ordinary(strl.data()), - strl.size() + 1, - reinterpret::as_ordinary(format), - args2 - ); - va_end(args2); + // Resize std::string to desired count, and pass its length + 1 to std::vsnprintf, + // Because std::vsnprintf only can write "buf_size - 1" chars with a trailing NULL. + // However std::vsnprintf already have a trailing NULL, so we plus 1 for it. + rv.resize(count); + int write_result = std::vsnprintf(reinterpret_cast(rv.data()), rv.size() + 1, reinterpret_cast(format), args2); + va_end(args2); + // Check written size. + if (write_result < 0 || write_result > count) { + // Invalid write result in vsnprintf. + return std::unexpected(FormatError::BadWrittenSize); + } - if (write_result < 0 || write_result > count) { - // invalid write result in vsnprintf. - return false; - } + // Return value + return rv; + } - return true; - } + FormatResult printf(const char8_t* format, ...) { + va_list argptr; + va_start(argptr, format); + auto rv = vprintf(format, argptr); + va_end(argptr); + return rv; + } - NS_YYCC_STRING::u8string printf(const NS_YYCC_STRING::u8char* format, ...) { - NS_YYCC_STRING::u8string ret; + FormatResult vprintf(const char8_t* format, va_list argptr) { + return generic_printf(format, argptr); + } - va_list argptr; - va_start(argptr, format); - vprintf(ret, format, argptr); - va_end(argptr); + FormatResult printf(const char* format, ...) { + va_list argptr; + va_start(argptr, format); + auto rv = vprintf(format, argptr); + va_end(argptr); + return rv; + } - return ret; - } - - NS_YYCC_STRING::u8string vprintf(const NS_YYCC_STRING::u8char* format, va_list argptr) { - NS_YYCC_STRING::u8string ret; - - va_list argcpy; - va_copy(argcpy, argptr); - vprintf(ret, format, argcpy); - va_end(argcpy); - - return ret; - } + FormatResult vprintf(const char* format, va_list argptr) { + return generic_printf(format, argptr); + } #pragma endregion #pragma region Replace - void replace(NS_YYCC_STRING::u8string& strl, const NS_YYCC_STRING::u8string_view& _from_strl, const NS_YYCC_STRING::u8string_view& _to_strl) { - // Reference: https://stackoverflow.com/questions/3418231/replace-part-of-a-string-with-another-string + void replace(std::u8string& strl, const std::u8string_view& _from_strl, const std::u8string_view& _to_strl) { + // Reference: https://stackoverflow.com/questions/3418231/replace-part-of-a-string-with-another-string - // check requirements - // from string should not be empty - NS_YYCC_STRING::u8string from_strl(_from_strl); - NS_YYCC_STRING::u8string to_strl(_to_strl); - if (from_strl.empty()) return; + // check requirements + // from string should not be empty + std::u8string from_strl(_from_strl); + std::u8string to_strl(_to_strl); + if (from_strl.empty()) return; - // start replace one by one - size_t start_pos = 0; - while ((start_pos = strl.find(from_strl, start_pos)) != NS_YYCC_STRING::u8string::npos) { - strl.replace(start_pos, from_strl.size(), to_strl); - start_pos += to_strl.size(); // In case 'to' contains 'from', like replacing 'x' with 'yx' - } - } + // start replace one by one + size_t start_pos = 0; + while ((start_pos = strl.find(from_strl, start_pos)) != std::u8string::npos) { + strl.replace(start_pos, from_strl.size(), to_strl); + start_pos += to_strl.size(); // In case 'to' contains 'from', like replacing 'x' with 'yx' + } + } - NS_YYCC_STRING::u8string replace(const NS_YYCC_STRING::u8string_view& _strl, const NS_YYCC_STRING::u8string_view& _from_strl, const NS_YYCC_STRING::u8string_view& _to_strl) { - // prepare result - NS_YYCC_STRING::u8string strl(_strl); - replace(strl, _from_strl, _to_strl); - // return value - return strl; - } + std::u8string replace(const std::u8string_view& _strl, const std::u8string_view& _from_strl, const std::u8string_view& _to_strl) { + // prepare result + std::u8string strl(_strl); + replace(strl, _from_strl, _to_strl); + // return value + return strl; + } #pragma endregion #pragma region Join - NS_YYCC_STRING::u8string join(JoinDataProvider fct_data, const NS_YYCC_STRING::u8string_view& delimiter) { - NS_YYCC_STRING::u8string ret; - bool is_first = true; - NS_YYCC_STRING::u8string_view element; + std::u8string join(JoinDataProvider fct_data, const std::u8string_view& delimiter) { + std::u8string ret; + bool is_first = true; + std::u8string_view element; - // fetch element - while (fct_data(element)) { - // insert delimiter - if (is_first) is_first = false; - else { - // append delimiter. - ret.append(delimiter); - } + // fetch element + while (fct_data(element)) { + // insert delimiter + if (is_first) is_first = false; + else { + // append delimiter. + ret.append(delimiter); + } - // insert element if it is not empty - if (!element.empty()) - ret.append(element); - } + // insert element if it is not empty + if (!element.empty()) ret.append(element); + } - return ret; - } + return ret; + } #pragma endregion #pragma region Upper Lower - template - static void generic_lower_upper(NS_YYCC_STRING::u8string& strl) { - // References: - // https://en.cppreference.com/w/cpp/algorithm/transform - // https://en.cppreference.com/w/cpp/string/byte/tolower - std::transform( - strl.cbegin(), strl.cend(), strl.begin(), - [](unsigned char c) -> char { - if constexpr (BIsToLower) return std::tolower(c); - else return std::toupper(c); - } - ); - } + template + static void generic_lower_upper(std::u8string& strl) { + // References: + // https://en.cppreference.com/w/cpp/algorithm/transform + // https://en.cppreference.com/w/cpp/string/byte/tolower + std::transform(strl.cbegin(), strl.cend(), strl.begin(), [](unsigned char c) -> char { + if constexpr (BIsToLower) return std::tolower(c); + else return std::toupper(c); + }); + } - void lower(NS_YYCC_STRING::u8string& strl) { - generic_lower_upper(strl); - } + void lower(std::u8string& strl) { + generic_lower_upper(strl); + } - NS_YYCC_STRING::u8string to_lower(const NS_YYCC_STRING::u8string_view& strl) { - NS_YYCC_STRING::u8string ret(strl); - lower(ret); - return ret; - } + std::u8string to_lower(const std::u8string_view& strl) { + std::u8string ret(strl); + lower(ret); + return ret; + } - void upper(NS_YYCC_STRING::u8string& strl) { - generic_lower_upper(strl); - } + void upper(std::u8string& strl) { + generic_lower_upper(strl); + } - NS_YYCC_STRING::u8string to_upper(const NS_YYCC_STRING::u8string_view& strl) { - // same as Lower, just replace char transform function. - NS_YYCC_STRING::u8string ret(strl); - upper(ret); - return ret; - } + std::u8string to_upper(const std::u8string_view& strl) { + // same as Lower, just replace char transform function. + std::u8string ret(strl); + upper(ret); + return ret; + } #pragma endregion #pragma region Split - std::vector split(const NS_YYCC_STRING::u8string_view& strl, const NS_YYCC_STRING::u8string_view& _delimiter) { + std::vector split(const std::u8string_view& strl, const std::u8string_view& _delimiter) { // Reference: // https://stackoverflow.com/questions/14265581/parse-split-a-string-in-c-using-string-delimiter-standard-c // prepare return value - std::vector elems; + std::vector elems; // if string need to be splitted is empty, return original string (empty string). // if delimiter is empty, return original string. - NS_YYCC_STRING::u8string delimiter(_delimiter); + std::u8string delimiter(_delimiter); if (strl.empty() || delimiter.empty()) { elems.emplace_back(strl); return elems; @@ -198,7 +182,7 @@ namespace yycc::string::op { // start spliting std::size_t previous = 0, current; - while ((current = strl.find(delimiter.c_str(), previous)) != NS_YYCC_STRING::u8string::npos) { + while ((current = strl.find(delimiter.c_str(), previous)) != std::u8string::npos) { elems.emplace_back(strl.substr(previous, current - previous)); previous = current + delimiter.size(); } @@ -209,20 +193,20 @@ namespace yycc::string::op { return elems; } - std::vector split_owned(const NS_YYCC_STRING::u8string_view& strl, const NS_YYCC_STRING::u8string_view& _delimiter) { - // call split view + std::vector split_owned(const std::u8string_view& strl, const std::u8string_view& _delimiter) { + // call split view auto view_result = split(strl, _delimiter); - // copy string view result to string - std::vector elems; - elems.reserve(view_result.size()); - for (const auto& strl_view : view_result) { - elems.emplace_back(NS_YYCC_STRING::u8string(strl_view)); - } - // return copied result - return elems; - } + // copy string view result to string + std::vector elems; + elems.reserve(view_result.size()); + for (const auto& strl_view : view_result) { + elems.emplace_back(std::u8string(strl_view)); + } + // return copied result + return elems; + } #pragma endregion -} +} // namespace yycc::string::op diff --git a/src/yycc/string/op.hpp b/src/yycc/string/op.hpp index 7e93a26..c439ee7 100644 --- a/src/yycc/string/op.hpp +++ b/src/yycc/string/op.hpp @@ -1,65 +1,68 @@ #pragma once +#include +#include #include #include #include -#include "../string.hpp" - -#define NS_YYCC_STRING ::yycc::string +#include namespace yycc::string::op { - /** - * @brief Perform a string formatting operation. - * @param[out] strl - * The string container receiving the result. - * There is no guarantee that the content is not modified when function failed. - * @param[in] format The format string. - * @param[in] ... Argument list of format string. - * @return True if success, otherwise false. - */ - bool printf(NS_YYCC_STRING::u8string& strl, const NS_YYCC_STRING::u8char* format, ...); - /** - * @brief Perform a string formatting operation. - * @param[out] strl - * The string container receiving the result. - * There is no guarantee that the content is not modified when function failed. - * @param[in] format The format string. - * @param[in] argptr Argument list of format string. - * @return True if success, otherwise false. - */ - bool vprintf(NS_YYCC_STRING::u8string& strl, const NS_YYCC_STRING::u8char* format, va_list argptr); - /** - * @brief Perform a string formatting operation. - * @param[in] format The format string. - * @param[in] ... Argument list of format string. - * @return The formatting result. Empty string if error happened. - */ - NS_YYCC_STRING::u8string printf(const NS_YYCC_STRING::u8char* format, ...); - /** - * @brief Perform a string formatting operation. - * @param[in] format The format string. - * @param[in] argptr Argument list of format string. - * @return The formatting result. Empty string if error happened. - */ - NS_YYCC_STRING::u8string vprintf(const NS_YYCC_STRING::u8char* format, va_list argptr); + enum class FormatError { + NullFormat, ///< Given format string is nullptr. + NoExpSize, ///< Fail to fetch the expected size of result. + BadWrittenSize, ///< The written size is different with expected size. + }; - /** + template + using FormatResult = std::expected; + + /** + * @brief Perform an UTF8 string formatting operation. + * @param[in] format The format string. + * @param[in] ... Argument list of format string. + * @return The formatted result, or the fail reason. + */ + FormatResult printf(const char8_t* format, ...); + /** + * @brief Perform an UTF8 string formatting operation. + * @param[in] format The format string. + * @param[in] argptr Argument list of format string. + * @return The formatted result, or the fail reason. + */ + FormatResult vprintf(const char8_t* format, va_list argptr); + /** + * @brief Perform an ordinary string formatting operation. + * @param[in] format The format string. + * @param[in] ... Argument list of format string. + * @return The formatted result, or the fail reason. + */ + FormatResult printf(const char* format, ...); + /** + * @brief Perform an ordinary string formatting operation. + * @param[in] format The format string. + * @param[in] argptr Argument list of format string. + * @return The formatted result, or the fail reason. + */ + FormatResult vprintf(const char* format, va_list argptr); + + /** * @brief Modify given string with all occurrences of substring \e old replaced by \e new. * @param[in,out] strl The string for replacing * @param[in] _from_strl The \e old string. * @param[in] _to_strl The \e new string. */ - void replace(NS_YYCC_STRING::u8string& strl, const NS_YYCC_STRING::u8string_view& _from_strl, const NS_YYCC_STRING::u8string_view& _to_strl); - /** + void replace(std::u8string& strl, const std::u8string_view& _from_strl, const std::u8string_view& _to_strl); + /** * @brief Return a copy with all occurrences of substring \e old replaced by \e new. * @param[in] _strl The string for replacing * @param[in] _from_strl The \e old string. * @param[in] _to_strl The \e new string. * @return The result of replacement. */ - NS_YYCC_STRING::u8string replace(const NS_YYCC_STRING::u8string_view& _strl, const NS_YYCC_STRING::u8string_view& _from_strl, const NS_YYCC_STRING::u8string_view& _to_strl); + std::u8string replace(const std::u8string_view& _strl, const std::u8string_view& _from_strl, const std::u8string_view& _to_strl); - /** + /** * @brief The data provider of general join function. * @details * For programmer using lambda to implement this function pointer: @@ -68,8 +71,8 @@ namespace yycc::string::op { * \li Function return true to continue joining. otherwise return false to stop joining. * The argument content assigned in the calling returning false is not included in join process. */ - using JoinDataProvider = std::function; - /** + using JoinDataProvider = std::function; + /** * @brief Universal join function. * @details * This function use function pointer as a general data provider interface, @@ -80,51 +83,56 @@ namespace yycc::string::op { * @param[in] delimiter The delimiter used for joining. * @return The result string of joining. */ - NS_YYCC_STRING::u8string join(JoinDataProvider fct_data, const NS_YYCC_STRING::u8string_view& delimiter); - /** + std::u8string join(JoinDataProvider fct_data, const std::u8string_view& delimiter); + /** * @brief Specialized join function for standard library container. * @tparam InputIt * Must meet the requirements of LegacyInputIterator. - * It also can be dereferenced and then implicitly converted to NS_YYCC_STRING::u8string_view. + * It also can be dereferenced and then implicitly converted to std::u8string_view. * @param[in] first The beginning of the range of elements to join. * @param[in] last The terminal of the range of elements to join (exclusive). * @param[in] delimiter The delimiter used for joining. * @return The result string of joining. */ - template - NS_YYCC_STRING::u8string join(InputIt first, InputIt last, const NS_YYCC_STRING::u8string_view& delimiter) { - return join([&first, &last](NS_YYCC_STRING::u8string_view& view) -> bool { - // if we reach tail, return false to stop join process - if (first == last) return false; - // otherwise fetch data, inc iterator and return. - view = *first; - ++first; - return true; - }, delimiter); - } + template + std::u8string join(InputIt first, InputIt last, const std::u8string_view& delimiter) { + return join( + [&first, &last](std::u8string_view& view) -> bool { + // if we reach tail, return false to stop join process + if (first == last) return false; + // otherwise fetch data, inc iterator and return. + view = *first; + ++first; + return true; + }, + delimiter); + } - /** + /** * @brief Convert given string to lowercase. * @param[in,out] strl The string to be lowercase. */ - void lower(NS_YYCC_STRING::u8string& strl); - /** + void lower(std::u8string& strl); + /** * @brief Return a copy of the string converted to lowercase. * @param[in] strl The string to be lowercase. * @return The copy of the string converted to lowercase. */ - NS_YYCC_STRING::u8string to_lower(const NS_YYCC_STRING::u8string_view& strl); - /** + std::u8string to_lower(const std::u8string_view& strl); + /** * @brief Convert given string to uppercase. * @param[in,out] strl The string to be uppercase. */ - void upper(NS_YYCC_STRING::u8string& strl); - /** + void upper(std::u8string& strl); + /** * @brief Return a copy of the string converted to uppercase. * @param[in] strl The string to be uppercase. * @return The copy of the string converted to uppercase. */ - NS_YYCC_STRING::u8string to_upper(const NS_YYCC_STRING::u8string_view& strl); + std::u8string to_upper(const std::u8string_view& strl); + + // TODO: + // Add strip, lstrip and rstrip functions. /** * @brief Split given string with specified delimiter as string view. @@ -136,10 +144,10 @@ namespace yycc::string::op { * \par * If given string or delimiter are empty, * the result container will only contain 1 entry which is equal to given string. - * @see Split(const NS_YYCC_STRING::u8string_view&, const NS_YYCC_STRING::u8char*) + * @see Split(const std::u8string_view&, const char8_t*) */ - std::vector split(const NS_YYCC_STRING::u8string_view& strl, const NS_YYCC_STRING::u8string_view& _delimiter); - /** + std::vector split(const std::u8string_view& strl, const std::u8string_view& _delimiter); + /** * @brief Split given string with specified delimiter. * @param[in] strl The string need to be splitting. * @param[in] _delimiter The delimiter for splitting. @@ -149,9 +157,10 @@ namespace yycc::string::op { * If given string or delimiter are empty, * the result container will only contain 1 entry which is equal to given string. */ - std::vector split_owned(const NS_YYCC_STRING::u8string_view& strl, const NS_YYCC_STRING::u8string_view& _delimiter); - // undefined lazy_split(const NS_YYCC_STRING::u8string_view& strl, const NS_YYCC_STRING::u8string_view& _delimiter); + std::vector split_owned(const std::u8string_view& strl, const std::u8string_view& _delimiter); -} + // TODO: + // Add lazy_split(const std::u8string_view& strl, const std::u8string_view& _delimiter); + // Once we add it, we need redirect all split function into it. -#undef NS_YYCC_STRING +} // namespace yycc::string::op diff --git a/src/yycc/string/reinterpret.cpp b/src/yycc/string/reinterpret.cpp index a7dd798..8f9e859 100644 --- a/src/yycc/string/reinterpret.cpp +++ b/src/yycc/string/reinterpret.cpp @@ -1,33 +1,31 @@ #include "reinterpret.hpp" -#define NS_YYCC_STRING ::yycc::string - namespace yycc::string::reinterpret { - const NS_YYCC_STRING::u8char* as_utf8(const char* src) { - return reinterpret_cast(src); - } - NS_YYCC_STRING::u8char* as_utf8(char* src) { - return reinterpret_cast(src); - } - NS_YYCC_STRING::u8string as_utf8(const std::string_view& src) { - return NS_YYCC_STRING::u8string(reinterpret_cast(src.data()), src.size()); - } - NS_YYCC_STRING::u8string_view as_utf8_view(const std::string_view& src) { - return NS_YYCC_STRING::u8string_view(reinterpret_cast(src.data()), src.size()); - } + const char8_t* as_utf8(const char* src) { + return reinterpret_cast(src); + } + char8_t* as_utf8(char* src) { + return reinterpret_cast(src); + } + std::u8string as_utf8(const std::string_view& src) { + return std::u8string(reinterpret_cast(src.data()), src.size()); + } + std::u8string_view as_utf8_view(const std::string_view& src) { + return std::u8string_view(reinterpret_cast(src.data()), src.size()); + } - const char* as_ordinary(const NS_YYCC_STRING::u8char* src) { - return reinterpret_cast(src); - } - char* as_ordinary(NS_YYCC_STRING::u8char* src) { - return reinterpret_cast(src); - } - std::string as_ordinary(const NS_YYCC_STRING::u8string_view& src) { - return std::string(reinterpret_cast(src.data()), src.size()); - } - std::string_view as_ordinary_view(const NS_YYCC_STRING::u8string_view& src) { - return std::string_view(reinterpret_cast(src.data()), src.size()); - } + const char* as_ordinary(const char8_t* src) { + return reinterpret_cast(src); + } + char* as_ordinary(char8_t* src) { + return reinterpret_cast(src); + } + std::string as_ordinary(const std::u8string_view& src) { + return std::string(reinterpret_cast(src.data()), src.size()); + } + std::string_view as_ordinary_view(const std::u8string_view& src) { + return std::string_view(reinterpret_cast(src.data()), src.size()); + } -} +} // namespace yycc::string::reinterpret diff --git a/src/yycc/string/reinterpret.hpp b/src/yycc/string/reinterpret.hpp index e2d454b..f5acb1e 100644 --- a/src/yycc/string/reinterpret.hpp +++ b/src/yycc/string/reinterpret.hpp @@ -1,7 +1,6 @@ #pragma once -#include "../string.hpp" - -#define NS_YYCC_STRING ::yycc::string +#include +#include /** * @brief Provides utilities for reinterpretation between UTF-8 and ordinary string types. @@ -17,51 +16,49 @@ namespace yycc::string::reinterpret { * @param src Source ordinary string * @return Pointer to UTF-8 encoded string */ - const NS_YYCC_STRING::u8char* as_utf8(const char* src); + const char8_t* as_utf8(const char* src); /** * @brief Reinterpret ordinary C-string as an UTF-8 string (non-const version). * @param src Source ordinary string * @return Pointer to UTF-8 encoded string */ - NS_YYCC_STRING::u8char* as_utf8(char* src); + char8_t* as_utf8(char* src); /** * @brief Reinterpret ordinary string view to copied UTF-8 string. * @param src Source ordinary string view * @return UTF-8 encoded string */ - NS_YYCC_STRING::u8string as_utf8(const std::string_view& src); + std::u8string as_utf8(const std::string_view& src); /** * @brief Reinterpret ordinary string view to UTF-8 string view. * @param src Source ordinary string view * @return UTF-8 encoded string view */ - NS_YYCC_STRING::u8string_view as_utf8_view(const std::string_view& src); + std::u8string_view as_utf8_view(const std::string_view& src); /** * @brief Reinterpret UTF-8 C-string to ordinary string (const version). * @param src Source UTF-8 string * @return Pointer to ordinary string */ - const char* as_ordinary(const NS_YYCC_STRING::u8char* src); + const char* as_ordinary(const char8_t* src); /** * @brief Reinterpret UTF-8 C-string to ordinary string (non-const version). * @param src Source UTF-8 string * @return Pointer to ordinary string */ - char* as_ordinary(NS_YYCC_STRING::u8char* src); + char* as_ordinary(char8_t* src); /** * @brief Reinterpret UTF-8 string view to ordinary string. * @param src Source UTF-8 string view * @return Ordinary string */ - std::string as_ordinary(const NS_YYCC_STRING::u8string_view& src); + std::string as_ordinary(const std::u8string_view& src); /** * @brief Reinterpret UTF-8 string view to ordinary string view * @param src Source UTF-8 string view * @return Ordinary string view */ - std::string_view as_ordinary_view(const NS_YYCC_STRING::u8string_view& src); + std::string_view as_ordinary_view(const std::u8string_view& src); } - -#undef NS_YYCC_STRING diff --git a/src/yycc/windows/unsafe_suppressor.hpp b/src/yycc/windows/unsafe_suppressor.hpp deleted file mode 100644 index b177bdb..0000000 --- a/src/yycc/windows/unsafe_suppressor.hpp +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once -#include "../macro/os_detector.hpp" - -// If we are in Windows, -// we need add 2 macros to disable Windows shitty warnings and errors of -// depracted functions and not secure functions. -#if defined(YYCC_OS_WINDOWS) - -#if !defined(_CRT_SECURE_NO_WARNINGS) -#define _CRT_SECURE_NO_WARNINGS -#endif -#if !defined(_CRT_NONSTDC_NO_DEPRECATE) -#define _CRT_NONSTDC_NO_DEPRECATE -#endif - -#endif diff --git a/testbench/CMakeLists.txt b/testbench/CMakeLists.txt index 08c99b5..b004aff 100644 --- a/testbench/CMakeLists.txt +++ b/testbench/CMakeLists.txt @@ -34,20 +34,6 @@ PRIVATE YYCCommonplace GTest::gtest_main ) -# Setup C++ standard -target_compile_features(YYCCTestbench PUBLIC cxx_std_17) -set_target_properties(YYCCTestbench PROPERTIES CXX_EXTENSION OFF) -# Order Unicode charset for private using -target_compile_definitions(YYCCTestbench -PRIVATE - $<$:UNICODE> - $<$:_UNICODE> -) -# Order build as UTF-8 in MSVC -target_compile_options(YYCCTestbench -PRIVATE - $<$:/utf-8> -) # Discover all test include(GoogleTest)