Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 21 additions & 8 deletions Sources/Overload/OvTools/include/OvTools/Utils/String.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,17 @@
namespace OvTools::Utils
{
/*
* Handle random numbers generation
* Helper class for string manipulation
*/
class String
{
public:
struct TrimOptions
{
const bool left = true;
const bool right = true;
};

/**
* Disabled constructor
*/
Expand All @@ -39,11 +45,18 @@ 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<bool(std::string)> 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<bool(std::string)> p_isAvailable);

/**
* 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
*/
static void Trim(std::string& p_str, const TrimOptions p_trimOptions = {});
};
}
}
6 changes: 3 additions & 3 deletions Sources/Overload/OvTools/src/OvTools/Filesystem/IniFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
*/

#include "OvTools/Filesystem/IniFile.h"
#include "OvTools/Utils/String.h"

#include <filesystem>
#include <fstream>

OvTools::Filesystem::IniFile::IniFile(const std::string& p_filePath) : m_filePath(p_filePath)
Expand Down Expand Up @@ -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);
RegisterPair(ExtractKeyAndValue(currentLine));
}
}
Expand Down Expand Up @@ -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");
}
}
100 changes: 56 additions & 44 deletions Sources/Overload/OvTools/src/OvTools/Utils/String.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,48 +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<bool(std::string)> 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<uint32_t>(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<uint32_t>(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);
}
}