-
Notifications
You must be signed in to change notification settings - Fork 494
Reduce pystring usages #2313
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Reduce pystring usages #2313
Changes from all commits
230853f
fc23cca
ad324ce
e906f5a
e57ce09
4d6a859
c7505f1
3339fa4
68957b4
8694cf7
a0c02ec
6a9f8bf
c277336
25f596e
160c1ec
f39f593
9417f9b
f41b7eb
75ba8e1
e84b2b4
d2d5368
92e37dd
0ef5d09
ddd0f48
c226670
6be11f5
42a38f5
2048eb9
e488851
355aa32
ac7647c
27fd8bd
989ac0e
b9d9493
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -110,6 +110,14 @@ inline bool StartsWith(const std::string& str, char prefix) | |
| } | ||
|
|
||
| // Starting from the left, trim the character. | ||
| inline std::string LeftTrim(std::string str, const std::string & prefix) | ||
| { | ||
| size_t first_good_char = str.find_first_not_of(prefix); | ||
| if (first_good_char == std::string::npos) { return str; } | ||
| str.erase(0, first_good_char); | ||
| return str; | ||
| } | ||
|
|
||
| inline std::string LeftTrim(std::string str, char c) | ||
| { | ||
| const auto it = std::find_if(str.begin(), str.end(), [&c](char ch) { return c!=ch; }); | ||
|
|
@@ -126,6 +134,14 @@ inline std::string LeftTrim(std::string str) | |
| } | ||
|
|
||
| // Starting from the right, trim the character. | ||
| inline std::string RightTrim(std::string str, const std::string & suffix) | ||
| { | ||
| size_t last_good_char = str.find_last_not_of(suffix); | ||
| if (last_good_char == std::string::npos) { return str; } | ||
| str.erase(last_good_char + 1); | ||
| return str; | ||
| } | ||
|
|
||
| inline std::string RightTrim(std::string str, char c) | ||
| { | ||
| const auto it = std::find_if(str.rbegin(), str.rend(), [&c](char ch) { return c!=ch; }); | ||
|
|
@@ -149,6 +165,11 @@ inline std::string Trim(std::string str, char c) | |
| } | ||
|
|
||
| // From the left and right, trim all the space characters i.e. space, tabulation, etc. | ||
| inline std::string Trim(std::string str, const std::string & chars) | ||
| { | ||
| return LeftTrim(RightTrim(str, chars), chars); | ||
| } | ||
|
|
||
| inline std::string Trim(std::string str) | ||
| { | ||
| return LeftTrim(RightTrim(str)); | ||
|
|
@@ -249,39 +270,54 @@ inline std::string::size_type ReverseFind(const std::string & subject, const std | |
| return subject.rfind(search); | ||
| } | ||
|
|
||
| // In place replace the 'search' substring by the 'replace' string in 'str'. | ||
| inline bool ReplaceInPlace(std::string & subject, const std::string & search, const std::string & replace) | ||
| // In place replace the 'search' substring by the 'replace' string in 'subject'. Limited by 'count'. | ||
| inline bool ReplaceInPlace(std::string & subject, const std::string & search, const std::string & replace, size_t count) | ||
| { | ||
| if (search.empty()) return false; | ||
| if (search.empty() || count == 0) { return false; } | ||
|
|
||
| bool changed = false; | ||
|
|
||
| size_t pos = 0; | ||
| size_t pos = 0; | ||
| size_t iter = 0; | ||
| while ((pos = subject.find(search, pos)) != std::string::npos) | ||
| { | ||
| if (iter >= count) { break; } | ||
| subject.replace(pos, search.length(), replace); | ||
| pos += replace.length(); | ||
| changed = true; | ||
| ++iter; | ||
| } | ||
|
|
||
| return changed; | ||
| } | ||
|
|
||
| // Replace the 'search' substring by the 'replace' string in 'str'. | ||
| inline std::string Replace(const std::string & subject, const std::string & search, const std::string & replace) | ||
| // In place replace the 'search' substring by the 'replace' string in 'subject'. | ||
| inline bool ReplaceInPlace(std::string & subject, const std::string & search, const std::string & replace) | ||
| { | ||
| return ReplaceInPlace(subject, search, replace, std::string::npos); | ||
| } | ||
|
|
||
| // Replace the 'search' substring by the 'replace' string in 'subject'. Limited by 'count'. | ||
| inline std::string Replace(const std::string & subject, const std::string & search, const std::string & replace, size_t count) | ||
| { | ||
| std::string str{subject}; | ||
| ReplaceInPlace(str, search, replace); | ||
| ReplaceInPlace(str, search, replace, count); | ||
| return str; | ||
| } | ||
|
|
||
| // Replace the 'search' substring by the 'replace' string in 'subject'. | ||
| inline std::string Replace(const std::string & subject, const std::string & search, const std::string & replace) | ||
| { | ||
| return Replace(subject, search, replace, std::string::npos); | ||
| } | ||
|
|
||
| // Check if the 'entry' is in the 'list' using a case insensitive comparison. | ||
| inline bool Contain(const StringVec & list, const std::string & entry) | ||
| { | ||
| const auto it = std::find_if(list.begin(), list.end(), | ||
| [entry](const std::string & ent) | ||
| { | ||
| return Compare(ent.c_str(), entry.c_str()); | ||
| const auto it = std::find_if(list.begin(), list.end(), | ||
| [entry](const std::string & ent) | ||
| { | ||
| return Compare(ent.c_str(), entry.c_str()); | ||
| }); | ||
| return it!=list.end(); | ||
| } | ||
|
|
@@ -290,10 +326,10 @@ inline bool Contain(const StringVec & list, const std::string & entry) | |
| // It returns true if found. | ||
| inline bool Remove(StringVec & list, const std::string & entry) | ||
| { | ||
| const auto it = std::find_if(list.begin(), list.end(), | ||
| [entry](const std::string & ent) | ||
| { | ||
| return Compare(ent.c_str(), entry.c_str()); | ||
| const auto it = std::find_if(list.begin(), list.end(), | ||
| [entry](const std::string & ent) | ||
| { | ||
| return Compare(ent.c_str(), entry.c_str()); | ||
| }); | ||
| if (it!=list.end()) | ||
| { | ||
|
|
@@ -304,6 +340,45 @@ inline bool Remove(StringVec & list, const std::string & entry) | |
| return false; | ||
| } | ||
|
|
||
| // Multiply the 'str' by the 'n' value. | ||
| inline std::string Multiply(const std::string & str, size_t n) | ||
| { | ||
| // Early exit and match pystring::mul behaviour. | ||
| if (n == 0) { return ""; } | ||
| if (n == 1) { return str; } | ||
|
|
||
| if (str.empty()) { return str; } | ||
|
|
||
| std::ostringstream os; | ||
| for(size_t i = 0; i < n; ++i) { os << str; } | ||
| return os.str(); | ||
| } | ||
|
|
||
| // Repeat the 'str' by the 'n' value. | ||
| inline std::string Repeat(const std::string & str, size_t n) | ||
| { | ||
| // Early exit and match pystring::mul behaviour. | ||
| if (n == 0) { return {}; } | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've not benchmarked it but it is possible that under some circumstances we might want to check
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree with you that doing an early check on |
||
| if (n == 1) { return str; } | ||
|
|
||
| if (str.empty()) { return str; } | ||
| const auto str_size = str.size(); | ||
|
|
||
| std::string result; | ||
| result.reserve(str_size * n); | ||
| result = str; | ||
| size_t current = 1; | ||
| while (current * 2 <= n) { | ||
| result += result; | ||
| current *= 2; | ||
| } | ||
| const auto remaining = n - current; | ||
| if (remaining > 0) { | ||
| result += std::string_view(result.data(), str_size * remaining); | ||
| } | ||
| return result; | ||
| } | ||
|
|
||
| } // namespace StringUtils | ||
|
|
||
| #endif // INCLUDED_STRINGUTILS_H | ||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if something like the following might be 'better'/faster
Edited because I nerd sniped myself and ran some performance tests
And again avoid an extra allocation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
might want to call the function Repeat or Repeat_n rather than Multiply.
Note that reserve() can raise an exception if we would go over std::string::max_size() but likely we would run out of memory before that happens.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What a wonderful suggestion. I just want to speak briefly on what I've done so far to get your eyes on it.
Repeat(). Made some small changes for syntax consistency.reserve(). I chose not to throw an exception but I'm open to suggestions. It is a new behaviour compared to the oldpystring::mul.StringUtils::Multiply()usage found in the code base (which was usingpystring::mul()before).Multiply()completely in favour ofRepeat()if that is the desired decision.