From 419dfe19f10ed72d895a13213d963553fd74b698 Mon Sep 17 00:00:00 2001 From: Thibaut PONCHON Date: Fri, 14 Feb 2025 16:38:40 -0500 Subject: [PATCH 1/5] Added function to trim leading/trailing whitespaces Trim static method added in OvTools::String and uses an enum for the trim type/direction. Added internal helpers to perform the leading or trailing trim. --- .../OvTools/include/OvTools/Utils/String.h | 27 +++++++++++++++++++ .../src/OvTools/Filesystem/IniFile.cpp | 4 +-- .../OvTools/src/OvTools/Utils/String.cpp | 24 +++++++++++++++++ 3 files changed, 53 insertions(+), 2 deletions(-) diff --git a/Sources/Overload/OvTools/include/OvTools/Utils/String.h b/Sources/Overload/OvTools/include/OvTools/Utils/String.h index 8d5fa0652..f082d191d 100644 --- a/Sources/Overload/OvTools/include/OvTools/Utils/String.h +++ b/Sources/Overload/OvTools/include/OvTools/Utils/String.h @@ -18,6 +18,13 @@ namespace OvTools::Utils class String { public: + enum ETrimType + { + Leading = 1, + Trailing = 2, + TwoWays = 4 // Leading and Trailing + }; + /** * Disabled constructor */ @@ -45,5 +52,25 @@ namespace OvTools::Utils * @param p_isAvailable (A callback that must returning true if the input string is available) */ static std::string GenerateUnique(const std::string& p_source, std::function p_isAvailable); + + /** + * Trim whitespaces from a string in a desired direction (Leading, Trailing or both as TwoWays). + * @param p_str String to trim + * @param p_trimType The desired trim direction, default is Trailing + */ + static void Trim(std::string& p_str, const ETrimType p_trimType = ETrimType::Trailing); + + private: + /** + * Leading trim of whitespaces from a string. + * param p_str String to trim + */ + static void LeadingTrim(std::string& p_str); + + /** + * Trailing trim of whitespaces from a string. + * param p_str String to trim + */ + static void TrailingTrim(std::string& p_str); }; } \ No newline at end of file diff --git a/Sources/Overload/OvTools/src/OvTools/Filesystem/IniFile.cpp b/Sources/Overload/OvTools/src/OvTools/Filesystem/IniFile.cpp index ba374a094..d1932f161 100644 --- a/Sources/Overload/OvTools/src/OvTools/Filesystem/IniFile.cpp +++ b/Sources/Overload/OvTools/src/OvTools/Filesystem/IniFile.cpp @@ -5,8 +5,8 @@ */ #include "OvTools/Filesystem/IniFile.h" +#include "OvTools/Utils/String.h" -#include #include OvTools::Filesystem::IniFile::IniFile(const std::string& p_filePath) : m_filePath(p_filePath) @@ -74,7 +74,7 @@ void OvTools::Filesystem::IniFile::Load() { if (IsValidLine(currentLine)) { - currentLine.erase(std::remove_if(currentLine.begin(), currentLine.end(), isspace), currentLine.end()); + OvTools::Utils::String::Trim(currentLine, OvTools::Utils::String::ETrimType::TwoWays); RegisterPair(ExtractKeyAndValue(currentLine)); } } diff --git a/Sources/Overload/OvTools/src/OvTools/Utils/String.cpp b/Sources/Overload/OvTools/src/OvTools/Utils/String.cpp index 00d56e909..9f285b545 100644 --- a/Sources/Overload/OvTools/src/OvTools/Utils/String.cpp +++ b/Sources/Overload/OvTools/src/OvTools/Utils/String.cpp @@ -78,3 +78,27 @@ std::string OvTools::Utils::String::GenerateUnique(const std::string& p_source, return result; } + +void OvTools::Utils::String::Trim(std::string& p_str, const ETrimType p_trimType) +{ + if (p_trimType & ETrimType::Leading || p_trimType & ETrimType::TwoWays) + { + LeadingTrim(p_str); + } + if (p_trimType & ETrimType::Trailing || p_trimType & ETrimType::TwoWays) + { + TrailingTrim(p_str); + } +} + +void OvTools::Utils::String::LeadingTrim(std::string& p_str) +{ + p_str.erase(p_str.begin(), + std::find_if(p_str.begin(), p_str.end(), [](unsigned char ch) { return !std::isspace(ch); })); +} + +void OvTools::Utils::String::TrailingTrim(std::string& p_str) +{ + p_str.erase(std::find_if(p_str.rbegin(), p_str.rend(), [](unsigned char ch) { return !std::isspace(ch); }).base(), + p_str.end()); +} From e0a8051401de7d9fed688fac4f8b8bf4abc0f8c9 Mon Sep 17 00:00:00 2001 From: Thibaut PONCHON Date: Fri, 14 Feb 2025 17:04:48 -0500 Subject: [PATCH 2/5] Update Sources/Overload/OvTools/src/OvTools/Utils/String.cpp Co-authored-by: Adrien Givry --- Sources/Overload/OvTools/src/OvTools/Utils/String.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Sources/Overload/OvTools/src/OvTools/Utils/String.cpp b/Sources/Overload/OvTools/src/OvTools/Utils/String.cpp index 9f285b545..c20b92d79 100644 --- a/Sources/Overload/OvTools/src/OvTools/Utils/String.cpp +++ b/Sources/Overload/OvTools/src/OvTools/Utils/String.cpp @@ -99,6 +99,5 @@ void OvTools::Utils::String::LeadingTrim(std::string& p_str) void OvTools::Utils::String::TrailingTrim(std::string& p_str) { - p_str.erase(std::find_if(p_str.rbegin(), p_str.rend(), [](unsigned char ch) { return !std::isspace(ch); }).base(), - p_str.end()); + p_str.erase(p_str.find_last_not_of(" \t\n\r\f\v") + 1); } From 3141b803b0f6e9a4245ddf6b42538b71f9a7451c Mon Sep 17 00:00:00 2001 From: Thibaut PONCHON Date: Fri, 14 Feb 2025 17:04:55 -0500 Subject: [PATCH 3/5] Update Sources/Overload/OvTools/src/OvTools/Utils/String.cpp Co-authored-by: Adrien Givry --- Sources/Overload/OvTools/src/OvTools/Utils/String.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Sources/Overload/OvTools/src/OvTools/Utils/String.cpp b/Sources/Overload/OvTools/src/OvTools/Utils/String.cpp index c20b92d79..6f713c3da 100644 --- a/Sources/Overload/OvTools/src/OvTools/Utils/String.cpp +++ b/Sources/Overload/OvTools/src/OvTools/Utils/String.cpp @@ -93,8 +93,7 @@ void OvTools::Utils::String::Trim(std::string& p_str, const ETrimType p_trimType void OvTools::Utils::String::LeadingTrim(std::string& p_str) { - p_str.erase(p_str.begin(), - std::find_if(p_str.begin(), p_str.end(), [](unsigned char ch) { return !std::isspace(ch); })); + p_str.erase(0, p_str.find_first_not_of(" \t\n\r\f\v")); } void OvTools::Utils::String::TrailingTrim(std::string& p_str) From fd1034a5a6830b79a8fed80c57f83df110f4c677 Mon Sep 17 00:00:00 2001 From: Thibaut PONCHON Date: Fri, 14 Feb 2025 17:39:57 -0500 Subject: [PATCH 4/5] Update Trim method to C++20 manipulations --- .../OvTools/include/OvTools/Utils/String.h | 30 +++++-------------- .../src/OvTools/Filesystem/IniFile.cpp | 4 +-- .../OvTools/src/OvTools/Utils/String.cpp | 28 ++++++----------- 3 files changed, 19 insertions(+), 43 deletions(-) diff --git a/Sources/Overload/OvTools/include/OvTools/Utils/String.h b/Sources/Overload/OvTools/include/OvTools/Utils/String.h index f082d191d..1bf331e95 100644 --- a/Sources/Overload/OvTools/include/OvTools/Utils/String.h +++ b/Sources/Overload/OvTools/include/OvTools/Utils/String.h @@ -13,16 +13,15 @@ namespace OvTools::Utils { /* - * Handle random numbers generation + * Helper class for string manipulation */ class String { public: - enum ETrimType + struct TrimOptions { - Leading = 1, - Trailing = 2, - TwoWays = 4 // Leading and Trailing + const bool left = true; + const bool right = true; }; /** @@ -54,23 +53,10 @@ namespace OvTools::Utils static std::string GenerateUnique(const std::string& p_source, std::function p_isAvailable); /** - * Trim whitespaces from a string in a desired direction (Leading, Trailing or both as TwoWays). + * Trim whitespaces from a string with the option to trim the left and right of the string by passing a TrimOptions struct. * @param p_str String to trim - * @param p_trimType The desired trim direction, default is Trailing + * @param p_trimOptions The desired trim options, default is trimming left and right */ - static void Trim(std::string& p_str, const ETrimType p_trimType = ETrimType::Trailing); - - private: - /** - * Leading trim of whitespaces from a string. - * param p_str String to trim - */ - static void LeadingTrim(std::string& p_str); - - /** - * Trailing trim of whitespaces from a string. - * param p_str String to trim - */ - static void TrailingTrim(std::string& p_str); + static void Trim(std::string& p_str, const TrimOptions p_trimOptions = {}); }; -} \ No newline at end of file +} diff --git a/Sources/Overload/OvTools/src/OvTools/Filesystem/IniFile.cpp b/Sources/Overload/OvTools/src/OvTools/Filesystem/IniFile.cpp index d1932f161..610e7403e 100644 --- a/Sources/Overload/OvTools/src/OvTools/Filesystem/IniFile.cpp +++ b/Sources/Overload/OvTools/src/OvTools/Filesystem/IniFile.cpp @@ -74,7 +74,7 @@ void OvTools::Filesystem::IniFile::Load() { if (IsValidLine(currentLine)) { - OvTools::Utils::String::Trim(currentLine, OvTools::Utils::String::ETrimType::TwoWays); + OvTools::Utils::String::Trim(currentLine); RegisterPair(ExtractKeyAndValue(currentLine)); } } @@ -132,4 +132,4 @@ bool OvTools::Filesystem::IniFile::IsValidLine(const std::string & p_attributeLi bool OvTools::Filesystem::IniFile::StringToBoolean(const std::string & p_value) const { return (p_value == "1" || p_value == "T" || p_value == "t" || p_value == "True" || p_value == "true"); -} \ No newline at end of file +} diff --git a/Sources/Overload/OvTools/src/OvTools/Utils/String.cpp b/Sources/Overload/OvTools/src/OvTools/Utils/String.cpp index 6f713c3da..c9f9cb4e2 100644 --- a/Sources/Overload/OvTools/src/OvTools/Utils/String.cpp +++ b/Sources/Overload/OvTools/src/OvTools/Utils/String.cpp @@ -79,24 +79,14 @@ std::string OvTools::Utils::String::GenerateUnique(const std::string& p_source, return result; } -void OvTools::Utils::String::Trim(std::string& p_str, const ETrimType p_trimType) +void OvTools::Utils::String::Trim(std::string& p_str, const TrimOptions p_trimOptions) { - if (p_trimType & ETrimType::Leading || p_trimType & ETrimType::TwoWays) - { - LeadingTrim(p_str); - } - if (p_trimType & ETrimType::Trailing || p_trimType & ETrimType::TwoWays) - { - TrailingTrim(p_str); - } -} - -void OvTools::Utils::String::LeadingTrim(std::string& p_str) -{ - p_str.erase(0, p_str.find_first_not_of(" \t\n\r\f\v")); -} - -void OvTools::Utils::String::TrailingTrim(std::string& p_str) -{ - p_str.erase(p_str.find_last_not_of(" \t\n\r\f\v") + 1); + if (p_trimOptions.left) + { + p_str.erase(0, p_str.find_first_not_of(" \t\n\r\f\v")); + } + if (p_trimOptions.right) + { + p_str.erase(p_str.find_last_not_of(" \t\n\r\f\v") + 1); + } } From b14d69226a3c7264b35c987677379614030238d3 Mon Sep 17 00:00:00 2001 From: Thibaut PONCHON Date: Sat, 15 Feb 2025 08:58:25 -0500 Subject: [PATCH 5/5] Fix format --- .../OvTools/include/OvTools/Utils/String.h | 16 +-- .../src/OvTools/Filesystem/IniFile.cpp | 2 +- .../OvTools/src/OvTools/Utils/String.cpp | 104 +++++++++--------- 3 files changed, 61 insertions(+), 61 deletions(-) diff --git a/Sources/Overload/OvTools/include/OvTools/Utils/String.h b/Sources/Overload/OvTools/include/OvTools/Utils/String.h index 1bf331e95..ab1e45ec0 100644 --- a/Sources/Overload/OvTools/include/OvTools/Utils/String.h +++ b/Sources/Overload/OvTools/include/OvTools/Utils/String.h @@ -13,7 +13,7 @@ namespace OvTools::Utils { /* - * Helper class for string manipulation + * Helper class for string manipulation */ class String { @@ -45,15 +45,15 @@ namespace OvTools::Utils */ static void ReplaceAll(std::string& p_target, const std::string& p_from, const std::string& p_to); - /** - * Generate a unique string satisfying the availability predicate - * @param p_source - * @param p_isAvailable (A callback that must returning true if the input string is available) - */ - static std::string GenerateUnique(const std::string& p_source, std::function p_isAvailable); + /** + * Generate a unique string satisfying the availability predicate + * @param p_source + * @param p_isAvailable (A callback that must returning true if the input string is available) + */ + static std::string GenerateUnique(const std::string& p_source, std::function p_isAvailable); /** - * Trim whitespaces from a string with the option to trim the left and right of the string by passing a TrimOptions struct. + * Trim whitespaces from a string with the option to trim the left and right of the string by passing a TrimOptions struct. * @param p_str String to trim * @param p_trimOptions The desired trim options, default is trimming left and right */ diff --git a/Sources/Overload/OvTools/src/OvTools/Filesystem/IniFile.cpp b/Sources/Overload/OvTools/src/OvTools/Filesystem/IniFile.cpp index 610e7403e..a973b798a 100644 --- a/Sources/Overload/OvTools/src/OvTools/Filesystem/IniFile.cpp +++ b/Sources/Overload/OvTools/src/OvTools/Filesystem/IniFile.cpp @@ -74,7 +74,7 @@ void OvTools::Filesystem::IniFile::Load() { if (IsValidLine(currentLine)) { - OvTools::Utils::String::Trim(currentLine); + OvTools::Utils::String::Trim(currentLine); RegisterPair(ExtractKeyAndValue(currentLine)); } } diff --git a/Sources/Overload/OvTools/src/OvTools/Utils/String.cpp b/Sources/Overload/OvTools/src/OvTools/Utils/String.cpp index c9f9cb4e2..06b9b5765 100644 --- a/Sources/Overload/OvTools/src/OvTools/Utils/String.cpp +++ b/Sources/Overload/OvTools/src/OvTools/Utils/String.cpp @@ -33,60 +33,60 @@ void OvTools::Utils::String::ReplaceAll(std::string& p_target, const std::string std::string OvTools::Utils::String::GenerateUnique(const std::string& p_source, std::function p_isAvailable) { - auto suffixlessSource = p_source; - - auto suffixOpeningParenthesisPos = std::string::npos; - auto suffixClosingParenthesisPos = std::string::npos; - - // Keep track of the current character position when iterating onto `p_source` - auto currentPos = decltype(std::string::npos){p_source.length() - 1}; - - // Here we search for `(` and `)` positions. (Needed to extract the number between those parenthesis) - for (auto it = p_source.rbegin(); it < p_source.rend(); ++it, --currentPos) - { - const auto c = *it; - - if (suffixClosingParenthesisPos == std::string::npos && c == ')') suffixClosingParenthesisPos = currentPos; - if (suffixClosingParenthesisPos != std::string::npos && c == '(') suffixOpeningParenthesisPos = currentPos; - } - - // We need to declare our `counter` here to store the number between found parenthesis OR 1 (In the case no parenthesis, AKA, suffix, has been found) - auto counter = uint32_t{ 1 }; - - // If the two parenthis have been found AND the closing parenthesis is the last character AND there is a space before the opening parenthesis - if (suffixOpeningParenthesisPos != std::string::npos && suffixClosingParenthesisPos == p_source.length() - 1 && suffixOpeningParenthesisPos > 0 && p_source[suffixOpeningParenthesisPos - 1] == ' ') - { - // Extract the string between those parenthesis - const auto between = p_source.substr(suffixOpeningParenthesisPos + 1, suffixClosingParenthesisPos - suffixOpeningParenthesisPos - 1); - - // If the `between` string is composed of digits (AKA, `between` is a number) - if (!between.empty() && std::find_if(between.begin(), between.end(), [](unsigned char c) { return !std::isdigit(c); }) == between.end()) - { - counter = static_cast(std::atoi(between.c_str())); - suffixlessSource = p_source.substr(0, suffixOpeningParenthesisPos - 1); - } - } - - auto result = suffixlessSource; - - // While `result` isn't available, we keep generating new strings - while (!p_isAvailable(result)) - { - // New strings are composed of the `suffixlessSource` (Ex: "Foo (1)" without suffix is "Foo") - result = suffixlessSource + " (" + std::to_string(counter++) + ")"; - } - - return result; + auto suffixlessSource = p_source; + + auto suffixOpeningParenthesisPos = std::string::npos; + auto suffixClosingParenthesisPos = std::string::npos; + + // Keep track of the current character position when iterating onto `p_source` + auto currentPos = decltype(std::string::npos){p_source.length() - 1}; + + // Here we search for `(` and `)` positions. (Needed to extract the number between those parenthesis) + for (auto it = p_source.rbegin(); it < p_source.rend(); ++it, --currentPos) + { + const auto c = *it; + + if (suffixClosingParenthesisPos == std::string::npos && c == ')') suffixClosingParenthesisPos = currentPos; + if (suffixClosingParenthesisPos != std::string::npos && c == '(') suffixOpeningParenthesisPos = currentPos; + } + + // We need to declare our `counter` here to store the number between found parenthesis OR 1 (In the case no parenthesis, AKA, suffix, has been found) + auto counter = uint32_t{ 1 }; + + // If the two parenthis have been found AND the closing parenthesis is the last character AND there is a space before the opening parenthesis + if (suffixOpeningParenthesisPos != std::string::npos && suffixClosingParenthesisPos == p_source.length() - 1 && suffixOpeningParenthesisPos > 0 && p_source[suffixOpeningParenthesisPos - 1] == ' ') + { + // Extract the string between those parenthesis + const auto between = p_source.substr(suffixOpeningParenthesisPos + 1, suffixClosingParenthesisPos - suffixOpeningParenthesisPos - 1); + + // If the `between` string is composed of digits (AKA, `between` is a number) + if (!between.empty() && std::find_if(between.begin(), between.end(), [](unsigned char c) { return !std::isdigit(c); }) == between.end()) + { + counter = static_cast(std::atoi(between.c_str())); + suffixlessSource = p_source.substr(0, suffixOpeningParenthesisPos - 1); + } + } + + auto result = suffixlessSource; + + // While `result` isn't available, we keep generating new strings + while (!p_isAvailable(result)) + { + // New strings are composed of the `suffixlessSource` (Ex: "Foo (1)" without suffix is "Foo") + result = suffixlessSource + " (" + std::to_string(counter++) + ")"; + } + + return result; } void OvTools::Utils::String::Trim(std::string& p_str, const TrimOptions p_trimOptions) { - if (p_trimOptions.left) - { - p_str.erase(0, p_str.find_first_not_of(" \t\n\r\f\v")); - } - if (p_trimOptions.right) - { - p_str.erase(p_str.find_last_not_of(" \t\n\r\f\v") + 1); - } + if (p_trimOptions.left) + { + p_str.erase(0, p_str.find_first_not_of(" \t\n\r\f\v")); + } + if (p_trimOptions.right) + { + p_str.erase(p_str.find_last_not_of(" \t\n\r\f\v") + 1); + } }