diff --git a/doc/src/parser_helper.dox b/doc/src/parser_helper.dox index 19bedc5..44669c7 100644 --- a/doc/src/parser_helper.dox +++ b/doc/src/parser_helper.dox @@ -15,7 +15,7 @@ Functions located in this helper support the convertion between string and follo Please note in C++, \c bool is integral type but we list it individually because parser will treat it specially. For \c bool type, parser will try doing convertion between it and \c "true" \c "false" string. -(\b case-sensitive. It means that \c true will only be converted to \c "true" and \c "TRUE" can not be recognised.) +(\b case-insensitive. It means that \c true can be converted from \c "true", \c "True" or \c "TRUE".) \section parser_helper__try_parse Try Parse @@ -31,6 +31,7 @@ YYCC::ParserHelper::TryParse(YYCC_U8("123"), val); YYCC::ParserHelper::TryParse(YYCC_U8("7fff"), val, 16); \endcode +For floating point type, this function allows caller to specify extra argument providing the format of given number string (\c std::chars_format). For integral type, this function allows caller to specify extra argument providing the base of given number string. \section parser_helper__parse Parse @@ -45,8 +46,8 @@ There is an example: uint32_t val = YYCC::ParserHelper::Parse(YYCC_U8("123")); \endcode -Please note, for integral types, there is no base argument in #Parse. -Please use #TryParse instead. +For integral and floating point value, +it has same extra argument with #TryParse to provide more number infomation. Using this function is dangerous if the validation of your input is important. In this case, please use #TryParse instead. @@ -63,6 +64,11 @@ There is an example: auto result = YYCC::ParserHelper::ToString(UINT32_C(114)); \endcode +For floating point type, this function allows caller to specify extra arguments +which provides the format (\c std::chars_format) and precision when getting string representation. +For integral type, this function allows caller to specify extra argument +providing the base of number when getting string representation. + \section parser_helper__notes Notes All functions within this helper are implementated by standard library functions. diff --git a/doc/src/string_helper.dox b/doc/src/string_helper.dox index fcca7c4..f7e26bb 100644 --- a/doc/src/string_helper.dox +++ b/doc/src/string_helper.dox @@ -38,8 +38,8 @@ and second overload will return empty string when formatter failed. YYCC::StringHelper provide 2 functions for programmer do string replacement: \code -void Replace(yycc_u8string&, const yycc_char8_t*, const yycc_char8_t*); -yycc_u8string Replace(const yycc_char8_t*, const yycc_char8_t*, const yycc_char8_t*); +void Replace(yycc_u8string&, const yycc_u8string_view&, const yycc_u8string_view&); +yycc_u8string Replace(const yycc_u8string_view&, const yycc_u8string_view&, const yycc_u8string_view&); \endcode The first overload will do replacement in given string container directly. @@ -47,9 +47,9 @@ The second overload will produce a copy of original string and do replacement on #Replace has special treatments for following scenarios: -\li If given string is empty or nullptr, the return value will be empty. -\li If the character sequence to be replaced is nullptr or empty string, no replacement will happen. -\li If the character sequence will be replaced into string is nullptr or empty, it will simply delete found character sequence from given string. +\li If given string is empty, the return value will be empty. +\li If the character sequence to be replaced is empty string, no replacement will happen. +\li If the character sequence will be replaced into string is or empty, it will simply delete found character sequence from given string. \section string_helper__join Join @@ -95,10 +95,18 @@ auto joined_string = YYCC::StringHelper::Join( \subsection string_helper__join__specialized Specialized Join Function Despite universal join function, -YYCC::StringHelper also provide some specialized join functions for commonly used types. -Current we support following join function: +YYCC::StringHelper also provide a specialized join functions for standard library container. +For example, the code written above can be written in following code by using this specialized overload. +The first two argument is just the begin and end iterator. +However, you must make sure that we can dereference it and then implicitly convert it to yycc_u8string_view. +Otherwise this overload will throw template error. -\li \c std::vector: With an extra option which allow join it with reversed order. +\code +std::vector data { + YYCC_U8(""), YYCC_U8("1"), YYCC_U8("2"), YYCC_U8("") +}; +auto joined_string = YYCC::StringHelper::Join(data.begin(), data.end(), decilmer); +\endcode \section string_helper__lower_upper Lower Upper @@ -106,11 +114,11 @@ String helper provides Python-like string lower and upper function. Both lower and upper function have 2 overloads: \code -yycc_u8string Lower(const yycc_char8_t*); +yycc_u8string Lower(const yycc_u8string_view&); void Lower(yycc_u8string&); \endcode -First overload accepts a NULL-terminated string as argument and return a \b copy whose content are all the lower case of original string. +First overload accepts a string view as argument and return a \b copy whose content are all the lower case of original string. Second overload accepts a mutable string container as argument and will make all characters stored in it become their lower case. You can choose on of them for your flavor and requirements. Upper also has similar 2 overloads. @@ -121,19 +129,19 @@ String helper provides Python-like string split function. It has 2 types for you: \code -std::vector Split(const yycc_u8string_view&, const yycc_char8_t*); -std::vector SplitView(const yycc_u8string_view&, const yycc_char8_t*); +std::vector Split(const yycc_u8string_view&, const yycc_u8string_view&); +std::vector SplitView(const yycc_u8string_view&, const yycc_u8string_view&); \endcode All these overloads take a string view as the first argument representing the string need to be split. -The second argument is a raw string pointer representing the decilmer for splitting. +The second argument is a string view representing the decilmer for splitting. The only difference between these 2 split function are overt according to their names. The first split function will return a list of copied string as its split result. The second split function will return a list of string view as its split result, and it will keep valid as long as the life time of your given string view argument. It also means that the last overload will cost less memory if you don't need the copy of original string. -If the source string (the string need to be split) is empty, or the decilmer is \c nullptr or empty, +If the source string (the string need to be split) is empty, or the decilmer is empty, the result will only has 1 item and this item is source string itself. There is no way that these methods return an empty list, except the code is buggy. diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b050eac..29b9dc6 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -56,12 +56,9 @@ PRIVATE $<$:DbgHelp.lib> ) # Setup C++ standard -set_target_properties(YYCCommonplace -PROPERTIES - CXX_STANDARD 17 - CXX_STANDARD_REQUIRED 17 - CXX_EXTENSION OFF -) +target_compile_features(YYCCommonplace PUBLIC cxx_std_17) +set_target_properties(YYCCommonplace PROPERTIES CXX_EXTENSION OFF) +# Setup macros target_compile_definitions(YYCCommonplace # Debug macro should populate to child projects PUBLIC diff --git a/src/DialogHelper.cpp b/src/DialogHelper.cpp index 7aad925..e8f87a0 100644 --- a/src/DialogHelper.cpp +++ b/src/DialogHelper.cpp @@ -40,7 +40,8 @@ namespace YYCC::DialogHelper { return false; // convert pattern and join them - yycc_u8string joined_modes(YYCC::StringHelper::Join(it.second, YYCC_U8(";"))); + const auto& filter_modes = it.second; + yycc_u8string joined_modes(YYCC::StringHelper::Join(filter_modes.begin(), filter_modes.end(), YYCC_U8(";"))); WinFileFilters::WinFilterModes modes; if (!YYCC::EncodingHelper::UTF8ToWchar(joined_modes, modes)) return false; diff --git a/src/ParserHelper.hpp b/src/ParserHelper.hpp index 3054c72..a41d25e 100644 --- a/src/ParserHelper.hpp +++ b/src/ParserHelper.hpp @@ -2,6 +2,7 @@ #include "YYCCInternal.hpp" #include "EncodingHelper.hpp" +#include "StringHelper.hpp" #include #include #include @@ -17,7 +18,7 @@ namespace YYCC::ParserHelper { // Reference: https://zh.cppreference.com/w/cpp/utility/from_chars - + /** * @brief Try parsing given string to floating point types. * @tparam _Ty The type derived from floating point type. @@ -25,14 +26,15 @@ namespace YYCC::ParserHelper { * @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 TryParse(const yycc_u8string_view& strl, _Ty& num) { + bool TryParse(const yycc_u8string_view& strl, _Ty& num, std::chars_format fmt = std::chars_format::general) { auto [ptr, ec] = std::from_chars( EncodingHelper::ToOrdinary(strl.data()), EncodingHelper::ToOrdinary(strl.data() + strl.size()), - num, std::chars_format::general + num, fmt ); if (ec == std::errc()) { // check whether the full string is matched @@ -50,12 +52,12 @@ namespace YYCC::ParserHelper { } /** * @brief Try parsing given string to integral types. - * @tparam _Ty The type derived from integral type. + * @tparam _Ty 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). + * @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<_Ty, bool>, int> = 0> @@ -82,7 +84,7 @@ namespace YYCC::ParserHelper { /** * @brief Try parsing given string to bool types. * @tparam _Ty The type derived from bool type. - * @param[in] strl The string need to be parsed ("true" or "false"). + * @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. @@ -90,22 +92,58 @@ namespace YYCC::ParserHelper { */ template, int> = 0> bool TryParse(const yycc_u8string_view& strl, _Ty& num) { + // get lower case + yycc_u8string lower_case(strl); + YYCC::StringHelper::Lower(lower_case); + // compare result if (strl == YYCC_U8("true")) num = true; else if (strl == YYCC_U8("false")) num = false; else return false; return true; } - + /** - * @brief Parse given string to arithmetic types. - * @tparam _Ty The type derived from arithmetic type. + * @brief Parse given string to floating point types. + * @tparam _Ty 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. */ - template, int> = 0> + template, int> = 0> + _Ty Parse(const yycc_u8string_view& strl, std::chars_format fmt = std::chars_format::general) { + _Ty ret; + TryParse(strl, ret, fmt); + return ret; + } + /** + * @brief Parse given string to integral type types. + * @tparam _Ty 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. + */ + template && !std::is_same_v<_Ty, bool>, int> = 0> + _Ty Parse(const yycc_u8string_view& strl, int base = 10) { + _Ty ret; + TryParse(strl, ret, base); + return ret; + } + /** + * @brief Parse given string to bool types. + * @tparam _Ty 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. + */ + template, int> = 0> _Ty Parse(const yycc_u8string_view& strl) { _Ty ret; TryParse(strl, ret); @@ -115,18 +153,21 @@ namespace YYCC::ParserHelper { // Reference: https://en.cppreference.com/w/cpp/utility/to_chars /** - * @brief Return a string version of given arithmetic value. - * @tparam _Ty The type derived from arithmetic type. - * @param[in] num The value getting string version. - * @return The string version of given value. + * @brief Return the string representation of given floating point value. + * @tparam _Ty The type derived from floating point type. + * @param[in] num The value need to get string representation. + * @param[in] fmt The floating point format used when getting string representation. + * @param[in] precision The floating point precision used when getting string representation. + * @return The string representation of given value. */ - template && !std::is_same_v<_Ty, bool>, int> = 0> - yycc_u8string ToString(_Ty num) { + template, int> = 0> + yycc_u8string ToString(_Ty num, std::chars_format fmt = std::chars_format::general, int precision = 6) { + // default precision = 6 is gotten from: https://en.cppreference.com/w/c/io/fprintf std::array buffer; auto [ptr, ec] = std::to_chars( EncodingHelper::ToOrdinary(buffer.data()), EncodingHelper::ToOrdinary(buffer.data() + buffer.size()), - num + num, fmt, precision ); if (ec == std::errc()) { return yycc_u8string(buffer.data(), EncodingHelper::ToUTF8(ptr) - buffer.data()); @@ -140,10 +181,36 @@ namespace YYCC::ParserHelper { } } /** - * @brief Return a string version of given bool value. + * @brief Return the string representation of given integral value. + * @tparam _Ty The type derived from integral type except bool type. + * @param[in] num The value need to get string representation. + * @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<_Ty, bool>, int> = 0> + yycc_u8string ToString(_Ty num, int base = 10) { + std::array buffer; + auto [ptr, ec] = std::to_chars( + EncodingHelper::ToOrdinary(buffer.data()), + EncodingHelper::ToOrdinary(buffer.data() + buffer.size()), + num, base + ); + if (ec == std::errc()) { + return yycc_u8string(buffer.data(), EncodingHelper::ToUTF8(ptr) - buffer.data()); + } else if (ec == std::errc::value_too_large) { + // too short buffer + // this should not happened + throw std::out_of_range("ToString() buffer is not sufficient."); + } else { + // unreachable + throw std::runtime_error("unreachable code."); + } + } + /** + * @brief Return the string representation of given bool value. * @tparam _Ty The type derived from bool type. - * @param[in] num The value getting string version. - * @return The string version of given value ("true" or "false"). + * @param[in] num The value need to get string representation. + * @return The string representation of given value ("true" or "false"). */ template, int> = 0> yycc_u8string ToString(_Ty num) { diff --git a/src/StringHelper.cpp b/src/StringHelper.cpp index 82d2b26..d0dfe0c 100644 --- a/src/StringHelper.cpp +++ b/src/StringHelper.cpp @@ -23,9 +23,9 @@ namespace YYCC::StringHelper { // the return value is desired char count without NULL terminal. // minus number means error int count = std::vsnprintf( - nullptr, - 0, - EncodingHelper::ToOrdinary(format), + nullptr, + 0, + EncodingHelper::ToOrdinary(format), args1 ); if (count < 0) { @@ -41,8 +41,8 @@ namespace YYCC::StringHelper { strl.resize(count); int write_result = std::vsnprintf( EncodingHelper::ToOrdinary(strl.data()), - strl.size() + 1, - EncodingHelper::ToOrdinary(format), + strl.size() + 1, + EncodingHelper::ToOrdinary(format), args2 ); va_end(args2); @@ -81,12 +81,10 @@ namespace YYCC::StringHelper { #pragma region Replace - void Replace(yycc_u8string& strl, const yycc_char8_t* _from_strl, const yycc_char8_t* _to_strl) { + void Replace(yycc_u8string& strl, const yycc_u8string_view& _from_strl, const yycc_u8string_view& _to_strl) { // Reference: https://stackoverflow.com/questions/3418231/replace-part-of-a-string-with-another-string - + // check requirements - // from string and to string should not be nullptr. - if (_from_strl == nullptr || _to_strl == nullptr) return; // from string should not be empty yycc_u8string from_strl(_from_strl); yycc_u8string to_strl(_to_strl); @@ -100,14 +98,10 @@ namespace YYCC::StringHelper { } } - yycc_u8string Replace(const yycc_char8_t* _strl, const yycc_char8_t* _from_strl, const yycc_char8_t* _to_strl) { + yycc_u8string Replace(const yycc_u8string_view& _strl, const yycc_u8string_view& _from_strl, const yycc_u8string_view& _to_strl) { // prepare result - yycc_u8string strl; - // if given string is not nullptr, assign it and process it. - if (_strl != nullptr) { - strl = _strl; - Replace(strl, _from_strl, _to_strl); - } + yycc_u8string strl(_strl); + Replace(strl, _from_strl, _to_strl); // return value return strl; } @@ -116,7 +110,7 @@ namespace YYCC::StringHelper { #pragma region Join - yycc_u8string Join(JoinDataProvider fct_data, const yycc_char8_t* decilmer) { + yycc_u8string Join(JoinDataProvider fct_data, const yycc_u8string_view& decilmer) { yycc_u8string ret; bool is_first = true; yycc_u8string_view element; @@ -126,9 +120,8 @@ namespace YYCC::StringHelper { // insert decilmer if (is_first) is_first = false; else { - // only insert non-nullptr decilmer. - if (decilmer != nullptr) - ret.append(decilmer); + // append decilmer. + ret.append(decilmer); } // insert element if it is not empty @@ -139,32 +132,6 @@ namespace YYCC::StringHelper { return ret; } - yycc_u8string Join(const std::vector& data, const yycc_char8_t* decilmer, bool reversed) { - if (reversed) { - auto iter = data.crbegin(); - auto stop = data.crend(); - return Join([&iter, &stop](yycc_u8string_view& view) -> bool { - // if we reach tail, return false - if (iter == stop) return false; - // otherwise fetch data, inc iterator and return. - view = *iter; - ++iter; - return true; - }, decilmer); - } else { - auto iter = data.cbegin(); - auto stop = data.cend(); - return Join([&iter, &stop](yycc_u8string_view& view) -> bool { - // if we reach tail, return nullptr - if (iter == stop) return false; - // otherwise fetch data, inc iterator and return. - view = *iter; - ++iter; - return true; - }, decilmer); - } - } - #pragma endregion #pragma region Upper Lower @@ -183,24 +150,13 @@ namespace YYCC::StringHelper { ); } - yycc_u8string Lower(const yycc_char8_t* strl) { - yycc_u8string ret; - if (strl == nullptr) return ret; - else ret = strl; - Lower(ret); - return ret; - } - void Lower(yycc_u8string& strl) { GeneralStringLowerUpper(strl); } - yycc_u8string Upper(const yycc_char8_t* strl) { - // same as Lower, just replace char transform function. - yycc_u8string ret; - if (strl == nullptr) return ret; - else ret = strl; - Upper(ret); + yycc_u8string Lower(const yycc_u8string_view& strl) { + yycc_u8string ret(strl); + Lower(ret); return ret; } @@ -208,16 +164,24 @@ namespace YYCC::StringHelper { GeneralStringLowerUpper(strl); } + yycc_u8string Upper(const yycc_u8string_view& strl) { + // same as Lower, just replace char transform function. + yycc_u8string ret(strl); + Upper(ret); + return ret; + } + #pragma endregion #pragma region Split - std::vector Split(const yycc_u8string_view& strl, const yycc_char8_t* _decilmer) { + std::vector Split(const yycc_u8string_view& strl, const yycc_u8string_view& _decilmer) { // call split view auto view_result = SplitView(strl, _decilmer); // copy string view result to string std::vector elems; + elems.reserve(view_result.size()); for (const auto& strl_view : view_result) { elems.emplace_back(yycc_u8string(strl_view)); } @@ -225,17 +189,17 @@ namespace YYCC::StringHelper { return elems; } - std::vector SplitView(const yycc_u8string_view& strl, const yycc_char8_t* _decilmer) { + std::vector SplitView(const yycc_u8string_view& strl, const yycc_u8string_view& _decilmer) { // Reference: // https://stackoverflow.com/questions/14265581/parse-split-a-string-in-c-using-string-delimiter-standard-c - + // prepare return value std::vector elems; - // if string need to be splitted is empty, return original string (empty item). - // if decilmer is nullptr, or decilmer is zero length, return original string. - yycc_u8string decilmer; - if (strl.empty() || _decilmer == nullptr || (decilmer = _decilmer, decilmer.empty())) { + // if string need to be splitted is empty, return original string (empty string). + // if decilmer is empty, return original string. + yycc_u8string decilmer(_decilmer); + if (strl.empty() || decilmer.empty()) { elems.emplace_back(strl); return elems; } diff --git a/src/StringHelper.hpp b/src/StringHelper.hpp index f5bf314..e6834c0 100644 --- a/src/StringHelper.hpp +++ b/src/StringHelper.hpp @@ -54,7 +54,7 @@ namespace YYCC::StringHelper { * @param[in] _from_strl The \e old string. * @param[in] _to_strl The \e new string. */ - void Replace(yycc_u8string& strl, const yycc_char8_t* _from_strl, const yycc_char8_t* _to_strl); + void Replace(yycc_u8string& strl, const yycc_u8string_view& _from_strl, const yycc_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 @@ -62,7 +62,7 @@ namespace YYCC::StringHelper { * @param[in] _to_strl The \e new string. * @return The result of replacement. */ - yycc_u8string Replace(const yycc_char8_t* _strl, const yycc_char8_t* _from_strl, const yycc_char8_t* _to_strl); + yycc_u8string Replace(const yycc_u8string_view& _strl, const yycc_u8string_view& _from_strl, const yycc_u8string_view& _to_strl); /** * @brief The data provider of general join function. @@ -85,38 +85,51 @@ namespace YYCC::StringHelper { * @param[in] decilmer The decilmer used for joining. * @return The result string of joining. */ - yycc_u8string Join(JoinDataProvider fct_data, const yycc_char8_t* decilmer); + yycc_u8string Join(JoinDataProvider fct_data, const yycc_u8string_view& decilmer); /** - * @brief Specialized join function for \c std::vector. - * @param[in] data The list to be joined. + * @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 yycc_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] decilmer The decilmer used for joining. - * @param[in] reversed True if this list should be joined in reversed order. * @return The result string of joining. */ - yycc_u8string Join(const std::vector& data, const yycc_char8_t* decilmer, bool reversed = false); + template + yycc_u8string Join(InputIt first, InputIt last, const yycc_u8string_view& decilmer) { + return Join([&first, &last](yycc_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; + }, decilmer); + } - /** - * @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. - */ - yycc_u8string Lower(const yycc_char8_t* strl); /** * @brief Convert given string to lowercase. * @param[in,out] strl The string to be lowercase. */ void Lower(yycc_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. + * @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. */ - yycc_u8string Upper(const yycc_char8_t* strl); + yycc_u8string Lower(const yycc_u8string_view& strl); /** * @brief Convert given string to uppercase. * @param[in,out] strl The string to be uppercase. */ void Upper(yycc_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. + */ + yycc_u8string Upper(const yycc_u8string_view& strl); /** * @brief Split given string with specified decilmer. @@ -125,10 +138,10 @@ namespace YYCC::StringHelper { * @return * The split result. * \par - * If given string is empty, or decilmer is nullptr or empty, + * If given string or decilmer are empty, * the result container will only contain 1 entry which is equal to given string. */ - std::vector Split(const yycc_u8string_view& strl, const yycc_char8_t* _decilmer); + std::vector Split(const yycc_u8string_view& strl, const yycc_u8string_view& _decilmer); /** * @brief Split given string with specified decilmer as string view. * @param[in] strl The string need to be splitting. @@ -137,10 +150,10 @@ namespace YYCC::StringHelper { * The split result with string view format. * This will not produce any copy of original string. * \par - * If given string is empty, or decilmer is nullptr or empty, + * If given string or decilmer are empty, * the result container will only contain 1 entry which is equal to given string. * @see Split(const yycc_u8string_view&, const yycc_char8_t*) */ - std::vector SplitView(const yycc_u8string_view& strl, const yycc_char8_t* _decilmer); + std::vector SplitView(const yycc_u8string_view& strl, const yycc_u8string_view& _decilmer); } diff --git a/testbench/CMakeLists.txt b/testbench/CMakeLists.txt index db1135f..68805f4 100644 --- a/testbench/CMakeLists.txt +++ b/testbench/CMakeLists.txt @@ -15,12 +15,8 @@ PRIVATE YYCCommonplace ) # Setup C++ standard -set_target_properties(YYCCTestbench -PROPERTIES - CXX_STANDARD 17 - CXX_STANDARD_REQUIRED 17 - CXX_EXTENSION OFF -) +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 diff --git a/testbench/main.cpp b/testbench/main.cpp index 1d1b591..b49c2b0 100644 --- a/testbench/main.cpp +++ b/testbench/main.cpp @@ -195,17 +195,13 @@ namespace YYCCTestbench { Assert(test_replace == YYCC_U8("aaddcc"), YYCC_U8("YYCC::StringHelper::Replace")); test_replace = YYCC::StringHelper::Replace(YYCC_U8("aabbcc"), YYCC_U8("zz"), YYCC_U8("yy")); // no replace Assert(test_replace == YYCC_U8("aabbcc"), YYCC_U8("YYCC::StringHelper::Replace")); - test_replace = YYCC::StringHelper::Replace(YYCC_U8("aabbcc"), YYCC_U8(""), YYCC_U8("zz")); // empty finding - Assert(test_replace == YYCC_U8("aabbcc"), YYCC_U8("YYCC::StringHelper::Replace")); - test_replace = YYCC::StringHelper::Replace(YYCC_U8("aabbcc"), nullptr, YYCC_U8("zz")); // nullptr finding + test_replace = YYCC::StringHelper::Replace(YYCC_U8("aabbcc"), YYCC::yycc_u8string_view(), YYCC_U8("zz")); // empty finding Assert(test_replace == YYCC_U8("aabbcc"), YYCC_U8("YYCC::StringHelper::Replace")); test_replace = YYCC::StringHelper::Replace(YYCC_U8("aaaabbaa"), YYCC_U8("aa"), YYCC_U8("")); // no replaced string Assert(test_replace == YYCC_U8("bb"), YYCC_U8("YYCC::StringHelper::Replace")); test_replace = YYCC::StringHelper::Replace(YYCC_U8("aaxcc"), YYCC_U8("x"), YYCC_U8("yx")); // nested replacing Assert(test_replace == YYCC_U8("aayxcc"), YYCC_U8("YYCC::StringHelper::Replace")); - test_replace = YYCC::StringHelper::Replace(YYCC_U8(""), YYCC_U8(""), YYCC_U8("xy")); // empty source string - Assert(test_replace == YYCC_U8(""), YYCC_U8("YYCC::StringHelper::Replace")); - test_replace = YYCC::StringHelper::Replace(nullptr, YYCC_U8(""), YYCC_U8("xy")); // nullptr source string + test_replace = YYCC::StringHelper::Replace(YYCC::yycc_u8string_view(), YYCC_U8(""), YYCC_U8("xy")); // empty source string Assert(test_replace == YYCC_U8(""), YYCC_U8("YYCC::StringHelper::Replace")); // Test Upper / Lower @@ -218,10 +214,8 @@ namespace YYCCTestbench { std::vector test_join_container { YYCC_U8(""), YYCC_U8("1"), YYCC_U8("2"), YYCC_U8("") }; - auto test_join = YYCC::StringHelper::Join(test_join_container, YYCC_U8(", ")); + auto test_join = YYCC::StringHelper::Join(test_join_container.begin(), test_join_container.end(), YYCC_U8(", ")); Assert(test_join == YYCC_U8(", 1, 2, "), YYCC_U8("YYCC::StringHelper::Join")); - test_join = YYCC::StringHelper::Join(test_join_container, YYCC_U8(", "), true); - Assert(test_join == YYCC_U8(", 2, 1, "), YYCC_U8("YYCC::StringHelper::Join")); // Test Split auto test_split = YYCC::StringHelper::Split(YYCC_U8(", 1, 2, "), YYCC_U8(", ")); // normal @@ -233,7 +227,7 @@ namespace YYCCTestbench { test_split = YYCC::StringHelper::Split(YYCC_U8("test"), YYCC_U8("-")); // no matched decilmer Assert(test_split.size() == 1u, YYCC_U8("YYCC::StringHelper::Split")); Assert(test_split[0] == YYCC_U8("test"), YYCC_U8("YYCC::StringHelper::Split")); - test_split = YYCC::StringHelper::Split(YYCC_U8("test"), YYCC_U8("")); // empty decilmer + test_split = YYCC::StringHelper::Split(YYCC_U8("test"), YYCC::yycc_u8string_view()); // empty decilmer Assert(test_split.size() == 1u, YYCC_U8("YYCC::StringHelper::Split")); Assert(test_split[0] == YYCC_U8("test"), YYCC_U8("YYCC::StringHelper::Split")); test_split = YYCC::StringHelper::Split(YYCC::yycc_u8string_view(), YYCC_U8("")); // empty source string @@ -245,12 +239,12 @@ namespace YYCCTestbench { static void ParserTestbench() { // Test success TryParse -#define TEST_MACRO(type_t, value, string_value) { \ +#define TEST_MACRO(type_t, value, string_value, ...) { \ YYCC::yycc_u8string cache_string(YYCC_U8(string_value)); \ type_t cache; \ - Assert(YYCC::ParserHelper::TryParse(cache_string, cache) && cache == value, YYCC_U8("YYCC::StringHelper::TryParse<" #type_t ">")); \ + Assert(YYCC::ParserHelper::TryParse(cache_string, cache, __VA_ARGS__) && cache == value, YYCC_U8("YYCC::StringHelper::TryParse<" #type_t ">")); \ } - + TEST_MACRO(int8_t, INT8_C(-61), "-61"); TEST_MACRO(uint8_t, UINT8_C(200), "200"); TEST_MACRO(int16_t, INT16_C(6161), "6161"); @@ -259,33 +253,38 @@ namespace YYCCTestbench { TEST_MACRO(uint32_t, UINT32_C(4294967293), "4294967293"); TEST_MACRO(int64_t, INT64_C(616161616161), "616161616161"); TEST_MACRO(uint64_t, UINT64_C(9223372036854775807), "9223372036854775807"); + TEST_MACRO(uint32_t, UINT32_C(0xffff), "ffff", 16); + TEST_MACRO(float, 1.0f, "1.0"); + TEST_MACRO(double, 1.0, "1.0"); TEST_MACRO(bool, true, "true"); #undef TEST_MACRO // Test failed TryParse -#define TEST_MACRO(type_t, value, string_value) { \ +#define TEST_MACRO(type_t, string_value, ...) { \ YYCC::yycc_u8string cache_string(YYCC_U8(string_value)); \ type_t cache; \ - Assert(!YYCC::ParserHelper::TryParse(cache_string, cache), YYCC_U8("YYCC::StringHelper::TryParse<" #type_t ">")); \ + Assert(!YYCC::ParserHelper::TryParse(cache_string, cache, __VA_ARGS__), YYCC_U8("YYCC::StringHelper::TryParse<" #type_t ">")); \ } - TEST_MACRO(int8_t, INT8_C(-61), "6161"); - TEST_MACRO(uint8_t, UINT8_C(200), "32800"); - TEST_MACRO(int16_t, INT16_C(6161), "61616161"); - TEST_MACRO(uint16_t, UINT16_C(32800), "4294967293"); - TEST_MACRO(int32_t, INT32_C(61616161), "616161616161"); - TEST_MACRO(uint32_t, UINT32_C(4294967293), "9223372036854775807"); - TEST_MACRO(int64_t, INT64_C(616161616161), "616161616161616161616161"); - TEST_MACRO(uint64_t, UINT64_C(9223372036854775807), "92233720368547758079223372036854775807"); - TEST_MACRO(bool, true, "hello, world!"); + TEST_MACRO(int8_t, "6161"); + TEST_MACRO(uint8_t, "32800"); + TEST_MACRO(int16_t, "61616161"); + TEST_MACRO(uint16_t, "4294967293"); + TEST_MACRO(int32_t, "616161616161"); + TEST_MACRO(uint32_t, "9223372036854775807"); + TEST_MACRO(int64_t, "616161616161616161616161"); + TEST_MACRO(uint64_t, "92233720368547758079223372036854775807"); + TEST_MACRO(float, "1e40"); + TEST_MACRO(double, "1e114514"); + TEST_MACRO(bool, "hello, world!"); #undef TEST_MACRO // Test ToString -#define TEST_MACRO(type_t, value, string_value) { \ +#define TEST_MACRO(type_t, value, string_value, ...) { \ type_t cache = value; \ - YYCC::yycc_u8string ret(YYCC::ParserHelper::ToString(cache)); \ + YYCC::yycc_u8string ret(YYCC::ParserHelper::ToString(cache, __VA_ARGS__)); \ Assert(ret == YYCC_U8(string_value), YYCC_U8("YYCC::StringHelper::ToString<" #type_t ">")); \ } @@ -297,10 +296,13 @@ namespace YYCCTestbench { TEST_MACRO(uint32_t, UINT32_C(4294967293), "4294967293"); TEST_MACRO(int64_t, INT64_C(616161616161), "616161616161"); TEST_MACRO(uint64_t, UINT64_C(9223372036854775807), "9223372036854775807"); + TEST_MACRO(uint32_t, UINT32_C(0xffff), "ffff", 16); + TEST_MACRO(float, 1.0f, "1.0", std::chars_format::fixed, 1); + TEST_MACRO(double, 1.0, "1.0", std::chars_format::fixed, 1); TEST_MACRO(bool, true, "true"); - #undef TEST_MACRO + } static void DialogTestbench() { @@ -416,7 +418,7 @@ namespace YYCCTestbench { #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())); + YYCC::yycc_u8string test_joined_path(YYCC::StringHelper::Join(c_UTF8TestStrTable.begin(), c_UTF8TestStrTable.end(), decilmer)); Assert(test_slashed_path == test_joined_path, YYCC_U8("YYCC::StdPatch::ToStdPath, YYCC::StdPatch::ToUTF8Path")); @@ -574,8 +576,8 @@ namespace YYCCTestbench { // init option context TestArgParser test; -#define PREPARE_DATA(...) char* test_argv[] = { __VA_ARGS__ }; \ -auto al = YYCC::ArgParser::ArgumentList::CreateFromStd(sizeof(test_argv) / sizeof(char*), test_argv); +#define PREPARE_DATA(...) const char* test_argv[] = { __VA_ARGS__ }; \ +auto al = YYCC::ArgParser::ArgumentList::CreateFromStd(sizeof(test_argv) / sizeof(char*), const_cast(test_argv)); // normal test {