From 3c3887bb198c07b50ad3451f228aadfe6fd25168 Mon Sep 17 00:00:00 2001 From: ShadowNinja Date: Thu, 11 Dec 2014 17:58:50 -0500 Subject: [PATCH] Deduplicate code and use stdlib in string functions --- src/test.cpp | 2 +- src/tile.cpp | 2 +- src/util/string.cpp | 15 +- src/util/string.h | 355 +++++++++++++++++++------------------------- 4 files changed, 162 insertions(+), 212 deletions(-) diff --git a/src/test.cpp b/src/test.cpp index 4cf4460be..a9ec6ffbb 100644 --- a/src/test.cpp +++ b/src/test.cpp @@ -189,7 +189,7 @@ struct TestUtilities: public TestBase str_replace(test_str, "there", "world"); UASSERT(test_str == "Hello world"); test_str = "ThisAisAaAtest"; - str_replace_char(test_str, 'A', ' '); + str_replace(test_str, 'A', ' '); UASSERT(test_str == "This is a test"); UASSERT(string_allowed("hello", "abcdefghijklmno") == true); UASSERT(string_allowed("123", "abcdefghijklmno") == false); diff --git a/src/tile.cpp b/src/tile.cpp index e7e37a4fe..b20aec54a 100644 --- a/src/tile.cpp +++ b/src/tile.cpp @@ -1380,7 +1380,7 @@ bool TextureSource::generateImagePart(std::string part_of_name, return false; } - str_replace_char(part_of_name, '&', '^'); + str_replace(part_of_name, '&', '^'); Strfnd sf(part_of_name); sf.next("{"); std::string imagename_top = sf.next("{"); diff --git a/src/util/string.cpp b/src/util/string.cpp index c590e7e57..1d9560608 100644 --- a/src/util/string.cpp +++ b/src/util/string.cpp @@ -22,15 +22,16 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "numeric.h" #include "log.h" -#include -#include -#include - #include "../sha1.h" #include "../base64.h" #include "../hex.h" #include "../porting.h" +#include +#include +#include +#include + static bool parseHexColorString(const std::string &value, video::SColor &color); static bool parseNamedColorString(const std::string &value, video::SColor &color); @@ -577,3 +578,9 @@ static bool parseNamedColorString(const std::string &value, video::SColor &color return true; } + +void str_replace(std::string &str, char from, char to) +{ + std::replace(str.begin(), str.end(), from, to); +} + diff --git a/src/util/string.h b/src/util/string.h index 52ef8c164..3cb0f7bec 100644 --- a/src/util/string.h +++ b/src/util/string.h @@ -50,40 +50,40 @@ bool parseColorString(const std::string &value, video::SColor &color, bool quiet /** - * Returns a copy of s with spaces inserted at the right hand side to ensure - * that the string is len characters in length. If s is <= len then the - * returned string will be identical to s. + * Returns a copy of \p str with spaces inserted at the right hand side to ensure + * that the string is \p len characters in length. If \p str is <= \p len then the + * returned string will be identical to str. */ -static inline std::string padStringRight(std::string s, size_t len) +inline std::string padStringRight(std::string str, size_t len) { - if (len > s.size()) - s.insert(s.end(), len - s.size(), ' '); + if (len > str.size()) + str.insert(str.end(), len - str.size(), ' '); - return s; + return str; } - /** - * Returns a version of the string s with the first occurrence of a string + * Returns a version of \p str with the first occurrence of a string * contained within ends[] removed from the end of the string. * - * @param s + * @param str * @param ends A NULL- or ""- terminated array of strings to remove from s in - * the copy produced. Note that once one of these strings is removed - * that no further postfixes contained within this array are removed. + * the copy produced. Note that once one of these strings is removed + * that no further postfixes contained within this array are removed. * - * @return If no end could be removed then "" is returned + * @return If no end could be removed then "" is returned. */ -static inline std::string removeStringEnd(const std::string &s, const char *ends[]) +inline std::string removeStringEnd(const std::string &str, + const char *ends[]) { const char **p = ends; for (; *p && (*p)[0] != '\0'; p++) { std::string end = *p; - if(s.size() < end.size()) + if (str.size() < end.size()) continue; - if(s.substr(s.size()-end.size(), end.size()) == end) - return s.substr(0, s.size() - end.size()); + if (str.compare(str.size() - end.size(), end.size(), end) == 0) + return str.substr(0, str.size() - end.size()); } return ""; @@ -91,94 +91,75 @@ static inline std::string removeStringEnd(const std::string &s, const char *ends /** - * Check two wide strings for equivalence. If case_insensitive is true - * then the case of the strings are ignored (default is false). + * Check two strings for equivalence. If \p case_insensitive is true + * then the case of the strings is ignored (default is false). * * @param s1 * @param s2 * @param case_insensitive * @return true if the strings match */ -inline bool str_equal(const std::wstring &s1, const std::wstring &s2, +template +inline bool str_equal(const std::basic_string &s1, + const std::basic_string &s2, bool case_insensitive = false) { - if (case_insensitive) { - if (s1.size() != s2.size()) - return false; + if (!case_insensitive) + return s1 == s2; - for (size_t i = 0; i < s1.size(); ++i) - if(tolower(s1[i]) != tolower(s2[i])) - return false; + if (s1.size() != s2.size()) + return false; - return true; - } + for (size_t i = 0; i < s1.size(); ++i) + if(tolower(s1[i]) != tolower(s2[i])) + return false; - return s1 == s2; + return true; } /** - * Check whether str begins with the string prefix. If the argument - * case_insensitive == true then the check is case insensitve (default - * is false; i.e. case is significant). + * Check whether \p str begins with the string prefix. If \p case_insensitive + * is true then the check is case insensitve (default is false; i.e. case is + * significant). * * @param str * @param prefix * @param case_insensitive - * @return true if the str begins with prefix + * @return true if the str begins with prefix */ -inline bool str_starts_with(const std::wstring &str, const std::wstring &prefix, +template +inline bool str_starts_with(const std::basic_string &str, + const std::basic_string &prefix, bool case_insensitive = false) { if (str.size() < prefix.size()) return false; - if (case_insensitive) { - for (size_t i = 0; i < prefix.size(); ++i) - if (tolower(str[i]) != tolower(prefix[i])) - return false; - } else { - for (size_t i = 0; i < prefix.size(); ++i) - if (str[i] != prefix[i]) - return false; - } + if (!case_insensitive) + return str.compare(0, prefix.size(), prefix) == 0; + for (size_t i = 0; i < prefix.size(); ++i) + if (tolower(str[i]) != tolower(prefix[i])) + return false; return true; } -/** - * Splits a string of wide characters into its component parts separated by - * the character delimiter. - * - * @return a std::vector of the component parts - */ -inline std::vector str_split(const std::wstring &str, - wchar_t delimiter) -{ - std::vector parts; - std::wstringstream sstr(str); - std::wstring part; - - while (std::getline(sstr, part, delimiter)) - parts.push_back(part); - - return parts; -} - - /** * Splits a string into its component parts separated by the character - * delimiter. + * \p delimiter. * - * @return a std::vector of the component parts + * @return An std::vector > of the component parts */ - -inline std::vector str_split(const std::string &str, char delimiter) { - - std::vector parts; - std::stringstream sstr(str); - std::string part; +template +inline std::vector > str_split( + const std::basic_string &str, + T delimiter) +{ + std::vector > parts; + std::basic_stringstream sstr(str); + std::basic_string part; while (std::getline(sstr, part, delimiter)) parts.push_back(part); @@ -188,70 +169,70 @@ inline std::vector str_split(const std::string &str, char delimiter /** - * Return a copy of s converted to all lowercase characters - * @param s + * @param str + * @return A copy of \p str converted to all lowercase characters. */ -inline std::string lowercase(const std::string &s) +inline std::string lowercase(const std::string &str) { std::string s2; - s2.reserve(s.size()); + s2.reserve(str.size()); - for (size_t i = 0; i < s.size(); i++) - s2 += tolower(s[i]); + for (size_t i = 0; i < str.size(); i++) + s2 += tolower(str[i]); return s2; } /** - * Returns a copy of s with leading and trailing whitespace removed. - * @param s + * @param str + * @return A copy of \p str with leading and trailing whitespace removed. */ -inline std::string trim(const std::string &s) +inline std::string trim(const std::string &str) { size_t front = 0; - while (std::isspace(s[front])) + while (std::isspace(str[front])) ++front; - size_t back = s.size(); - while (back > front && std::isspace(s[back-1])) + size_t back = str.size(); + while (back > front && std::isspace(str[back - 1])) --back; - return s.substr(front, back - front); + return str.substr(front, back - front); } /** - * Returns true if s should be regarded as (bool) true. Leading and trailing - * whitespace are ignored; case is ignored. Values that will return - * true are "y", "n", "true" and any number that != 0. - * @param s + * Returns whether \p str should be regarded as (bool) true. Case and leading + * and trailing whitespace are ignored. Values that will return + * true are "y", "yes", "true" and any number that is not 0. + * @param str */ -inline bool is_yes(const std::string &s) +inline bool is_yes(const std::string &str) { - std::string s2 = lowercase(trim(s)); + std::string s2 = lowercase(trim(str)); return s2 == "y" || s2 == "yes" || s2 == "true" || atoi(s2.c_str()) != 0; } /** - * Converts the string s to a signed 32-bit integer. The converted value is - * constrained so that min <= value <= max. + * Converts the string \p str to a signed 32-bit integer. The converted value + * is constrained so that min <= value <= max. * * @see atoi(3) for limitations * - * @param s + * @param str * @param min Range minimum * @param max Range maximum * @return The value converted to a signed 32-bit integer and constrained - * within the range defined by min and max (inclusive) + * within the range defined by min and max (inclusive) */ -inline s32 mystoi(const std::string &s, s32 min, s32 max) +inline s32 mystoi(const std::string &str, s32 min, s32 max) { - s32 i = atoi(s.c_str()); + s32 i = atoi(str.c_str()); if (i < min) i = min; @@ -262,12 +243,10 @@ inline s32 mystoi(const std::string &s, s32 min, s32 max) } -/** - * Returns a 64-bit value reprensented by the string s (decimal). - */ -inline s64 stoi64(const std::string &s) +/// Returns a 64-bit value represented by the string \p str (decimal). +inline s64 stoi64(const std::string &str) { - std::stringstream tmp(s); + std::stringstream tmp(str); s64 t; tmp >> t; return t; @@ -278,41 +257,32 @@ inline s64 stoi64(const std::string &s) /** - * Returns a 32-bit value reprensented by the string s (decimal). - * + * Returns a 32-bit value reprensented by the string \p str (decimal). * @see atoi(3) for further limitations */ -inline s32 mystoi(const std::string &s) +inline s32 mystoi(const std::string &str) { - return atoi(s.c_str()); + return atoi(str.c_str()); } /** - * Returns a 32-bit value reprensented by the wide string s (decimal). - * + * Returns s 32-bit value represented by the wide string \p str (decimal). * @see atoi(3) for further limitations */ -inline s32 mystoi(const std::wstring &s) +inline s32 mystoi(const std::wstring &str) { - return atoi(wide_to_narrow(s).c_str()); + return mystoi(wide_to_narrow(str)); } /** - * Returns a float reprensented by the string s (decimal). - * + * Returns a float reprensented by the string \p str (decimal). * @see atof(3) */ -inline float mystof(const std::string &s) +inline float mystof(const std::string &str) { - // This crap causes a segfault in certain cases on MinGW - /*float f; - std::istringstream ss(s); - ss>>f; - return f;*/ - // This works in that case - return atof(s.c_str()); + return atof(str.c_str()); } //#endif @@ -320,89 +290,66 @@ inline float mystof(const std::string &s) #define stoi mystoi #define stof mystof +// TODO: Replace with C++11 std::to_string. -/** - * Returns a string representing the decimal value of the 32-bit value i - */ -inline std::string itos(s32 i) +/// Returns A string representing the value \p val. +template +inline std::string to_string(T val) { - std::ostringstream o; - o << i; - return o.str(); + std::ostringstream oss; + oss << val; + return oss.str(); } - -/** - * Returns a string representing the decimal value of i of the 64-bit value i - */ -inline std::string i64tos(s64 i) { - std::ostringstream o; - o << i; - return o.str(); -} +/// Returns a string representing the decimal value of the 32-bit value \p i. +inline std::string itos(s32 i) { return to_string(i); } +/// Returns a string representing the decimal value of the 64-bit value \p i. +inline std::string i64tos(s64 i) { return to_string(i); } +/// Returns a string representing the decimal value of the float value \p f. +inline std::string ftos(float f) { return to_string(f); } /** - * Returns a string representing the real number (decimal) float value i - */ -inline std::string ftos(float f) -{ - std::ostringstream o; - o << f; - return o.str(); -} - - -/** - * Replace all occurrences of pattern in str with replacement + * Replace all occurrences of \p pattern in \p str with \p replacement. * - * @param str String to replace pattern with replacement within - * @param pattern The pattern to replace - * @param replacement What to replace the pattern with + * @param str String to replace pattern with replacement within. + * @param pattern The pattern to replace. + * @param replacement What to replace the pattern with. */ -inline void str_replace(std::string &str, std::string const &pattern, - std::string const &replacement) +inline void str_replace(std::string &str, const std::string &pattern, + const std::string &replacement) { std::string::size_type start = str.find(pattern, 0); while (start != str.npos) { str.replace(start, pattern.size(), replacement); - start = str.find(pattern, start+replacement.size()); + start = str.find(pattern, start + replacement.size()); } } /** - * Replace all occurrances of the character from in str with to. + * Replace all occurrences of the character \p from in \p str with \p to. * - * @param str The string to (potentially) modify - * @param from The character in str to replace - * @param to The replacement character + * @param str The string to (potentially) modify. + * @param from The character in str to replace. + * @param to The replacement character. */ -inline void str_replace_char(std::string &str, char from, char to) -{ - for (size_t i = 0; i < str.size(); i++) - if (str[i] == from) - str[i] = to; -} +void str_replace(std::string &str, char from, char to); /** * Check that a string only contains whitelisted characters. This is the * opposite of string_allowed_blacklist(). * - * @param s The string to be checked. + * @param str The string to be checked. * @param allowed_chars A string containing permitted characters. * @return true if the string is allowed, otherwise false. * * @see string_allowed_blacklist() */ -inline bool string_allowed(const std::string &s, const std::string &allowed_chars) +inline bool string_allowed(const std::string &str, const std::string &allowed_chars) { - for (size_t i = 0; i < s.size(); i++) - if (allowed_chars.find(s[i]) == std::string::npos) - return false; - - return true; + return str.find_first_not_of(allowed_chars) == str.npos; } @@ -410,41 +357,38 @@ inline bool string_allowed(const std::string &s, const std::string &allowed_char * Check that a string contains no blacklisted characters. This is the * opposite of string_allowed(). * - * @param s The string to be checked. + * @param str The string to be checked. * @param blacklisted_chars A string containing prohibited characters. * @return true if the string is allowed, otherwise false. * @see string_allowed() */ -inline bool string_allowed_blacklist(const std::string &s, +inline bool string_allowed_blacklist(const std::string &str, const std::string &blacklisted_chars) { - for (size_t i = 0; i < s.size(); i++) - if (blacklisted_chars.find(s[i]) != std::string::npos) - return false; - - return true; + return str.find_first_of(blacklisted_chars) == str.npos; } /** - * Create a string based on 'from' where a newline is forcefully inserted every - * 'rowlen' characters. + * Create a string based on \p from where a newline is forcefully inserted + * every \p row_len characters. * * @note This function does not honour word wraps and blindy inserts a newline - * every rowlen characters whether it breaks a word or not. It is - * intended to be used, for example, showing paths in the GUI + * every \p row_len characters whether it breaks a word or not. It is + * intended to be used for, for example, showing paths in the GUI. * * @param from The string to be wrapped into rows. - * @param rowlen The row length (in characters). + * @param row_len The row length (in characters). * @return A new string with the wrapping applied. */ -inline std::string wrap_rows(const std::string &from, u32 rowlen) +inline std::string wrap_rows(const std::string &from, + unsigned row_len) { std::string to; for (size_t i = 0; i < from.size(); i++) { - if(i != 0 && i % rowlen == 0) + if (i != 0 && i % row_len == 0) to += '\n'; to += from[i]; } @@ -454,49 +398,48 @@ inline std::string wrap_rows(const std::string &from, u32 rowlen) /** - * Removes all \\ from a string that had been escaped (FormSpec strings) + * Removes all backslashes from a string that had been escaped (FormSpec strings) * */ -inline std::string unescape_string(std::string &s) +template +inline std::basic_string unescape_string(std::basic_string &s) { - std::string res; - + std::basic_string res; + for (size_t i = 0; i < s.length(); i++) { - if (s[i] == '\\') - i++; - res += s[i]; + if (s[i] != '\\') + res += s[i]; } - + return res; } /** - * Checks that all characters in tocheck are a decimal digits + * Checks that all characters in \p to_check are a decimal digits. * - * @param tocheck - * @return true if tockcheck is not empty and all characters in tocheck are - * decimal digits, otherwise false + * @param to_check + * @return true if to_check is not empty and all characters in to_check are + * decimal digits, otherwise false */ -inline bool is_number(const std::string &tocheck) +inline bool is_number(const std::string &to_check) { - for (size_t i = 0; i < tocheck.size(); i++) - if (!std::isdigit(tocheck[i])) - return false; + for (size_t i = 0; i < to_check.size(); i++) + if (!std::isdigit(to_check[i])) + return false; - return !tocheck.empty(); + return !to_check.empty(); } /** - * Returns a C-string, either "true" or "false", corresponding to v + * Returns a C-string, either "true" or "false", corresponding to \p val. * - * @return If v == true, then "true" is returned, otherwise "false" + * @return If \p val is true, then "true" is returned, otherwise "false". */ -inline const char *bool_to_cstr(bool v) +inline const char *bool_to_cstr(bool val) { - return v ? "true" : "false"; + return val ? "true" : "false"; } - #endif -- 2.25.1