From 2d77cf9c80f26e5064749114aac33be71f768ffd Mon Sep 17 00:00:00 2001 From: Rubidium Date: Wed, 17 Jan 2024 06:30:44 +0100 Subject: [PATCH] Codechange: replace StrStartsWith/StrEndsWith with starts_with and ends_with --- src/fileio.cpp | 2 +- src/fios.cpp | 2 +- src/network/core/address.cpp | 2 +- src/network/core/http_curl.cpp | 2 +- src/network/core/http_winhttp.cpp | 2 +- src/network/network_chat_gui.cpp | 2 +- src/network/network_coordinator.cpp | 2 +- src/network/network_gui.cpp | 2 +- src/openttd.cpp | 2 +- src/screenshot.cpp | 2 +- src/script/api/script_text.cpp | 2 +- src/settings.cpp | 4 +- src/string.cpp | 26 ---- src/string_func.h | 2 - src/tests/string_func.cpp | 182 ---------------------------- src/textfile_gui.cpp | 16 +-- 16 files changed, 21 insertions(+), 231 deletions(-) diff --git a/src/fileio.cpp b/src/fileio.cpp index 215da0f36b..089e25e702 100644 --- a/src/fileio.cpp +++ b/src/fileio.cpp @@ -608,7 +608,7 @@ bool TarScanner::AddFile(const std::string &filename, size_t, [[maybe_unused]] c /* Process relative path. * Note: The destination of links must not contain any directory-links. */ std::string dest = (std::filesystem::path(name).remove_filename() /= link).lexically_normal().string(); - if (dest[0] == PATHSEPCHAR || StrStartsWith(dest, "..")) { + if (dest[0] == PATHSEPCHAR || dest.starts_with("..")) { Debug(misc, 5, "Ignoring link pointing outside of data directory: {} -> {}", name, link); break; } diff --git a/src/fios.cpp b/src/fios.cpp index e7bdac1e08..3b7efd822e 100644 --- a/src/fios.cpp +++ b/src/fios.cpp @@ -729,7 +729,7 @@ FiosNumberedSaveName::FiosNumberedSaveName(const std::string &prefix) : prefix(p /* Callback for FiosFileScanner. */ static FiosGetTypeAndNameProc *proc = [](SaveLoadOperation, const std::string &file, const std::string_view ext) { - if (StrEqualsIgnoreCase(ext, ".sav") && StrStartsWith(file, _prefix)) return std::tuple(FIOS_TYPE_FILE, std::string{}); + if (StrEqualsIgnoreCase(ext, ".sav") && file.starts_with(_prefix)) return std::tuple(FIOS_TYPE_FILE, std::string{}); return std::tuple(FIOS_TYPE_INVALID, std::string{}); }; diff --git a/src/network/core/address.cpp b/src/network/core/address.cpp index 525edd511d..62210f0668 100644 --- a/src/network/core/address.cpp +++ b/src/network/core/address.cpp @@ -449,7 +449,7 @@ void NetworkAddress::Listen(int socktype, SocketList *sockets) */ /* static */ ServerAddress ServerAddress::Parse(const std::string &connection_string, uint16_t default_port, CompanyID *company_id) { - if (StrStartsWith(connection_string, "+")) { + if (connection_string.starts_with("+")) { std::string_view invite_code = ParseCompanyFromConnectionString(connection_string, company_id); return ServerAddress(SERVER_ADDRESS_INVITE_CODE, std::string(invite_code)); } diff --git a/src/network/core/http_curl.cpp b/src/network/core/http_curl.cpp index e238a81772..2a363559b0 100644 --- a/src/network/core/http_curl.cpp +++ b/src/network/core/http_curl.cpp @@ -176,7 +176,7 @@ void HttpThread() /* Prepare POST body and URI. */ if (!request->data.empty()) { /* When the payload starts with a '{', it is a JSON payload. */ - if (StrStartsWith(request->data, "{")) { + if (request->data.starts_with("{")) { headers = curl_slist_append(headers, "Content-Type: application/json"); } else { headers = curl_slist_append(headers, "Content-Type: application/x-www-form-urlencoded"); diff --git a/src/network/core/http_winhttp.cpp b/src/network/core/http_winhttp.cpp index 7736dd60f8..9d365f6d17 100644 --- a/src/network/core/http_winhttp.cpp +++ b/src/network/core/http_winhttp.cpp @@ -252,7 +252,7 @@ void NetworkHTTPRequest::Connect() WinHttpSendRequest(this->request, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, reinterpret_cast(this)); } else { /* When the payload starts with a '{', it is a JSON payload. */ - LPCWSTR content_type = StrStartsWith(data, "{") ? L"Content-Type: application/json\r\n" : L"Content-Type: application/x-www-form-urlencoded\r\n"; + LPCWSTR content_type = data.starts_with("{") ? L"Content-Type: application/json\r\n" : L"Content-Type: application/x-www-form-urlencoded\r\n"; WinHttpSendRequest(this->request, content_type, -1, const_cast(data.c_str()), static_cast(data.size()), static_cast(data.size()), reinterpret_cast(this)); } } diff --git a/src/network/network_chat_gui.cpp b/src/network/network_chat_gui.cpp index 321cc4f9ec..c91a74bde6 100644 --- a/src/network/network_chat_gui.cpp +++ b/src/network/network_chat_gui.cpp @@ -408,7 +408,7 @@ struct NetworkChatWindow : public Window { /* Now any match we make on _chat_tab_completion_buf after this, is perfect */ } - if (tb_buf.size() < cur_name.size() && StrStartsWith(cur_name, tb_buf)) { + if (tb_buf.size() < cur_name.size() && cur_name.starts_with(tb_buf)) { /* Save the data it was before completion */ if (!second_scan) _chat_tab_completion_buf = tb->buf; _chat_tab_completion_active = true; diff --git a/src/network/network_coordinator.cpp b/src/network/network_coordinator.cpp index 3aac31d00c..4298b382ef 100644 --- a/src/network/network_coordinator.cpp +++ b/src/network/network_coordinator.cpp @@ -514,7 +514,7 @@ void ClientNetworkCoordinatorSocketHandler::GetListing() */ void ClientNetworkCoordinatorSocketHandler::ConnectToServer(const std::string &invite_code, TCPServerConnecter *connecter) { - assert(StrStartsWith(invite_code, "+")); + assert(invite_code.starts_with("+")); if (this->connecter_pre.find(invite_code) != this->connecter_pre.end()) { /* If someone is hammering the refresh key, one can sent out two diff --git a/src/network/network_gui.cpp b/src/network/network_gui.cpp index 40e2e966ae..8e92835663 100644 --- a/src/network/network_gui.cpp +++ b/src/network/network_gui.cpp @@ -649,7 +649,7 @@ public: tr.top = DrawStringMultiLine(tr, STR_NETWORK_SERVER_LIST_SERVER_VERSION); // server version SetDParamStr(0, sel->connection_string); - StringID invite_or_address = StrStartsWith(sel->connection_string, "+") ? STR_NETWORK_SERVER_LIST_INVITE_CODE : STR_NETWORK_SERVER_LIST_SERVER_ADDRESS; + StringID invite_or_address = sel->connection_string.starts_with("+") ? STR_NETWORK_SERVER_LIST_INVITE_CODE : STR_NETWORK_SERVER_LIST_SERVER_ADDRESS; tr.top = DrawStringMultiLine(tr, invite_or_address); // server address / invite code SetDParam(0, sel->info.start_date); diff --git a/src/openttd.cpp b/src/openttd.cpp index 6f4c35845f..37729c82ca 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -372,7 +372,7 @@ void MakeNewgameSettingsLive() void OpenBrowser(const std::string &url) { /* Make sure we only accept urls that are sure to open a browser. */ - if (StrStartsWith(url, "http://") || StrStartsWith(url, "https://")) { + if (url.starts_with("http://") || url.starts_with("https://")) { OSOpenBrowser(url); } } diff --git a/src/screenshot.cpp b/src/screenshot.cpp index 5b9ce9388b..b57e484bfe 100644 --- a/src/screenshot.cpp +++ b/src/screenshot.cpp @@ -679,7 +679,7 @@ static const char *MakeScreenshotName(const char *default_fn, const char *ext, b } /* Handle user-specified filenames ending in # with automatic numbering */ - if (StrEndsWith(_screenshot_name, "#")) { + if (_screenshot_name.ends_with("#")) { generate = true; _screenshot_name.pop_back(); } diff --git a/src/script/api/script_text.cpp b/src/script/api/script_text.cpp index 834c77e137..d509ddd80c 100644 --- a/src/script/api/script_text.cpp +++ b/src/script/api/script_text.cpp @@ -140,7 +140,7 @@ SQInteger ScriptText::_set(HSQUIRRELVM vm) sq_getstring(vm, 2, &key_string); std::string str = StrMakeValid(key_string); - if (!StrStartsWith(str, "param_") || str.size() > 8) return SQ_ERROR; + if (!str.starts_with("param_") || str.size() > 8) return SQ_ERROR; k = stoi(str.substr(6)); } else if (sq_gettype(vm, 2) == OT_INTEGER) { diff --git a/src/settings.cpp b/src/settings.cpp index 01ad5bdbf6..0dd0a304b1 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -1604,7 +1604,7 @@ static const SettingDesc *GetSettingFromName(const std::string_view name, const for (auto &desc : settings) { const SettingDesc *sd = GetSettingDesc(desc); if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue; - if (StrEndsWith(sd->GetName(), short_name_suffix)) return sd; + if (sd->GetName().ends_with(short_name_suffix)) return sd; } return nullptr; @@ -1633,7 +1633,7 @@ void GetSaveLoadFromSettingTable(SettingTable settings, std::vector &s static const SettingDesc *GetCompanySettingFromName(std::string_view name) { static const std::string_view company_prefix = "company."; - if (StrStartsWith(name, company_prefix)) name.remove_prefix(company_prefix.size()); + if (name.starts_with(company_prefix)) name.remove_prefix(company_prefix.size()); return GetSettingFromName(name, _company_settings); } diff --git a/src/string.cpp b/src/string.cpp index c6b1a154a6..3bc3e223f1 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -291,19 +291,6 @@ void StrTrimInPlace(std::string &str) StrRightTrimInPlace(str); } -/** - * Check whether the given string starts with the given prefix. - * @param str The string to look at. - * @param prefix The prefix to look for. - * @return True iff the begin of the string is the same as the prefix. - */ -bool StrStartsWith(const std::string_view str, const std::string_view prefix) -{ - size_t prefix_len = prefix.size(); - if (str.size() < prefix_len) return false; - return str.compare(0, prefix_len, prefix, 0, prefix_len) == 0; -} - /** * Check whether the given string starts with the given prefix, ignoring case. * @param str The string to look at. @@ -316,19 +303,6 @@ bool StrStartsWithIgnoreCase(std::string_view str, const std::string_view prefix return StrEqualsIgnoreCase(str.substr(0, prefix.size()), prefix); } -/** - * Check whether the given string ends with the given suffix. - * @param str The string to look at. - * @param suffix The suffix to look for. - * @return True iff the end of the string is the same as the suffix. - */ -bool StrEndsWith(const std::string_view str, const std::string_view suffix) -{ - size_t suffix_len = suffix.size(); - if (str.size() < suffix_len) return false; - return str.compare(str.size() - suffix_len, suffix_len, suffix, 0, suffix_len) == 0; -} - /** Case insensitive implementation of the standard character type traits. */ struct CaseInsensitiveCharTraits : public std::char_traits { static bool eq(char c1, char c2) { return toupper(c1) == toupper(c2); } diff --git a/src/string_func.h b/src/string_func.h index bd0e547558..470a8eca3d 100644 --- a/src/string_func.h +++ b/src/string_func.h @@ -30,9 +30,7 @@ bool strtolower(std::string &str, std::string::size_type offs = 0); [[nodiscard]] bool StrValid(const char *str, const char *last) NOACCESS(2); void StrTrimInPlace(std::string &str); -[[nodiscard]] bool StrStartsWith(const std::string_view str, const std::string_view prefix); [[nodiscard]] bool StrStartsWithIgnoreCase(std::string_view str, const std::string_view prefix); -[[nodiscard]] bool StrEndsWith(const std::string_view str, const std::string_view suffix); [[nodiscard]] bool StrEndsWithIgnoreCase(std::string_view str, const std::string_view suffix); [[nodiscard]] int StrCompareIgnoreCase(const std::string_view str1, const std::string_view str2); diff --git a/src/tests/string_func.cpp b/src/tests/string_func.cpp index 17c153cde9..eb61f0bac2 100644 --- a/src/tests/string_func.cpp +++ b/src/tests/string_func.cpp @@ -163,97 +163,6 @@ TEST_CASE("StrEqualsIgnoreCase - std::string_view") /**** String starts with *****/ -TEST_CASE("StrStartsWith - std::string") -{ - /* Everything starts with an empty prefix. */ - CHECK(StrStartsWith(std::string{""}, std::string{""})); - CHECK(StrStartsWith(std::string{"a"}, std::string{""})); - - /* Equal strings. */ - CHECK(StrStartsWith(std::string{"a"}, std::string{"a"})); - CHECK(StrStartsWith(std::string{"A"}, std::string{"A"})); - - /* Starts with same. */ - CHECK(StrStartsWith(std::string{"ab"}, std::string{"a"})); - CHECK(StrStartsWith(std::string{"Ab"}, std::string{"A"})); - - /* Different cases. */ - CHECK(!StrStartsWith(std::string{"a"}, std::string{"A"})); - CHECK(!StrStartsWith(std::string{"A"}, std::string{"a"})); - CHECK(!StrStartsWith(std::string{"ab"}, std::string{"A"})); - CHECK(!StrStartsWith(std::string{"Ab"}, std::string{"a"})); - - /* Does not start the same. */ - CHECK(!StrStartsWith(std::string{""}, std::string{"b"})); - CHECK(!StrStartsWith(std::string{"a"}, std::string{"b"})); - CHECK(!StrStartsWith(std::string{"b"}, std::string{"a"})); - CHECK(!StrStartsWith(std::string{"a"}, std::string{"aa"})); -} - -TEST_CASE("StrStartsWith - char pointer") -{ - CHECK(StrStartsWith("", "")); - CHECK(StrStartsWith("a", "")); - - /* Equal strings. */ - CHECK(StrStartsWith("a", "a")); - CHECK(StrStartsWith("A", "A")); - - /* Starts with same. */ - CHECK(StrStartsWith("ab", "a")); - CHECK(StrStartsWith("Ab", "A")); - - /* Different cases. */ - CHECK(!StrStartsWith("a", "A")); - CHECK(!StrStartsWith("A", "a")); - CHECK(!StrStartsWith("ab", "A")); - CHECK(!StrStartsWith("Ab", "a")); - - /* Does not start the same. */ - CHECK(!StrStartsWith("", "b")); - CHECK(!StrStartsWith("a", "b")); - CHECK(!StrStartsWith("b", "a")); - CHECK(!StrStartsWith("a", "aa")); -} - -TEST_CASE("StrStartsWith - std::string_view") -{ - /* - * With std::string_view the only way to access the data is via .data(), - * which does not guarantee the termination that would be required by - * things such as stricmp/strcasecmp. So, just passing .data() into stricmp - * or strcasecmp would fail if it does not account for the length of the - * view. Thus, contrary to the string/char* tests, this uses the same base - * string but gets different sections to trigger these corner cases. - */ - std::string_view base{"aabAb"}; - - /* Everything starts with an empty prefix. */ - CHECK(StrStartsWith(base.substr(0, 0), base.substr(1, 0))); // Different positions - CHECK(StrStartsWith(base.substr(0, 1), base.substr(0, 0))); - - /* Equals string. */ - CHECK(StrStartsWith(base.substr(0, 1), base.substr(1, 1))); // Different positions - CHECK(StrStartsWith(base.substr(3, 1), base.substr(3, 1))); - - /* Starts with same. */ - CHECK(StrStartsWith(base.substr(1, 2), base.substr(0, 1))); - CHECK(StrStartsWith(base.substr(3, 2), base.substr(3, 1))); - - /* Different cases. */ - CHECK(!StrStartsWith(base.substr(0, 1), base.substr(3, 1))); - CHECK(!StrStartsWith(base.substr(3, 1), base.substr(0, 1))); - CHECK(!StrStartsWith(base.substr(1, 2), base.substr(3, 1))); - CHECK(!StrStartsWith(base.substr(3, 2), base.substr(0, 1))); - - /* Does not start the same. */ - CHECK(!StrStartsWith(base.substr(2, 0), base.substr(2, 1))); - CHECK(!StrStartsWith(base.substr(0, 1), base.substr(2, 1))); - CHECK(!StrStartsWith(base.substr(2, 1), base.substr(0, 1))); - CHECK(!StrStartsWith(base.substr(0, 1), base.substr(0, 2))); -} - - TEST_CASE("StrStartsWithIgnoreCase - std::string") { /* Everything starts with an empty prefix. */ @@ -341,97 +250,6 @@ TEST_CASE("StrStartsWithIgnoreCase - std::string_view") /**** String ends with *****/ -TEST_CASE("StrEndsWith - std::string") -{ - /* Everything ends with an empty prefix. */ - CHECK(StrEndsWith(std::string{""}, std::string{""})); - CHECK(StrEndsWith(std::string{"a"}, std::string{""})); - - /* Equal strings. */ - CHECK(StrEndsWith(std::string{"a"}, std::string{"a"})); - CHECK(StrEndsWith(std::string{"A"}, std::string{"A"})); - - /* Ends with same. */ - CHECK(StrEndsWith(std::string{"ba"}, std::string{"a"})); - CHECK(StrEndsWith(std::string{"bA"}, std::string{"A"})); - - /* Different cases. */ - CHECK(!StrEndsWith(std::string{"a"}, std::string{"A"})); - CHECK(!StrEndsWith(std::string{"A"}, std::string{"a"})); - CHECK(!StrEndsWith(std::string{"ba"}, std::string{"A"})); - CHECK(!StrEndsWith(std::string{"bA"}, std::string{"a"})); - - /* Does not end the same. */ - CHECK(!StrEndsWith(std::string{""}, std::string{"b"})); - CHECK(!StrEndsWith(std::string{"a"}, std::string{"b"})); - CHECK(!StrEndsWith(std::string{"b"}, std::string{"a"})); - CHECK(!StrEndsWith(std::string{"a"}, std::string{"aa"})); -} - -TEST_CASE("StrEndsWith - char pointer") -{ - CHECK(StrEndsWith("", "")); - CHECK(StrEndsWith("a", "")); - - /* Equal strings. */ - CHECK(StrEndsWith("a", "a")); - CHECK(StrEndsWith("A", "A")); - - /* Ends with same. */ - CHECK(StrEndsWith("ba", "a")); - CHECK(StrEndsWith("bA", "A")); - - /* Different cases. */ - CHECK(!StrEndsWith("a", "A")); - CHECK(!StrEndsWith("A", "a")); - CHECK(!StrEndsWith("ba", "A")); - CHECK(!StrEndsWith("bA", "a")); - - /* Does not end the same. */ - CHECK(!StrEndsWith("", "b")); - CHECK(!StrEndsWith("a", "b")); - CHECK(!StrEndsWith("b", "a")); - CHECK(!StrEndsWith("a", "aa")); -} - -TEST_CASE("StrEndsWith - std::string_view") -{ - /* - * With std::string_view the only way to access the data is via .data(), - * which does not guarantee the termination that would be required by - * things such as stricmp/strcasecmp. So, just passing .data() into stricmp - * or strcasecmp would fail if it does not account for the length of the - * view. Thus, contrary to the string/char* tests, this uses the same base - * string but gets different sections to trigger these corner cases. - */ - std::string_view base{"aabAba"}; - - /* Everything ends with an empty prefix. */ - CHECK(StrEndsWith(base.substr(0, 0), base.substr(1, 0))); // Different positions - CHECK(StrEndsWith(base.substr(0, 1), base.substr(0, 0))); - - /* Equals string. */ - CHECK(StrEndsWith(base.substr(0, 1), base.substr(1, 1))); // Different positions - CHECK(StrEndsWith(base.substr(3, 1), base.substr(3, 1))); - - /* Ends with same. */ - CHECK(StrEndsWith(base.substr(4, 2), base.substr(0, 1))); - CHECK(StrEndsWith(base.substr(2, 2), base.substr(3, 1))); - - /* Different cases. */ - CHECK(!StrEndsWith(base.substr(0, 1), base.substr(3, 1))); - CHECK(!StrEndsWith(base.substr(3, 1), base.substr(0, 1))); - CHECK(!StrEndsWith(base.substr(4, 2), base.substr(3, 1))); - CHECK(!StrEndsWith(base.substr(2, 2), base.substr(0, 1))); - - /* Does not end the same. */ - CHECK(!StrEndsWith(base.substr(2, 0), base.substr(2, 1))); - CHECK(!StrEndsWith(base.substr(0, 1), base.substr(2, 1))); - CHECK(!StrEndsWith(base.substr(2, 1), base.substr(0, 1))); - CHECK(!StrEndsWith(base.substr(0, 1), base.substr(0, 2))); -} - - TEST_CASE("StrEndsWithIgnoreCase - std::string") { /* Everything ends with an empty prefix. */ diff --git a/src/textfile_gui.cpp b/src/textfile_gui.cpp index 029cd40ff8..1eff6f5fb6 100644 --- a/src/textfile_gui.cpp +++ b/src/textfile_gui.cpp @@ -177,14 +177,14 @@ enum class HyperlinkType { static HyperlinkType ClassifyHyperlink(const std::string &destination, bool trusted) { if (destination.empty()) return HyperlinkType::Unknown; - if (StrStartsWith(destination, "#")) return HyperlinkType::Internal; + if (destination.starts_with("#")) return HyperlinkType::Internal; /* Only allow external / internal links for sources we trust. */ if (!trusted) return HyperlinkType::Unknown; - if (StrStartsWith(destination, "http://")) return HyperlinkType::Web; - if (StrStartsWith(destination, "https://")) return HyperlinkType::Web; - if (StrStartsWith(destination, "./")) return HyperlinkType::File; + if (destination.starts_with("http://")) return HyperlinkType::Web; + if (destination.starts_with("https://")) return HyperlinkType::Web; + if (destination.starts_with("./")) return HyperlinkType::File; return HyperlinkType::Unknown; } @@ -428,7 +428,7 @@ void TextfileWindow::NavigateHistory(int delta) void TextfileWindow::NavigateToFile(std::string newfile, size_t line) { /* Double-check that the file link begins with ./ as a relative path. */ - if (!StrStartsWith(newfile, "./")) return; + if (!newfile.starts_with("./")) return; /* Get the path portion of the current file path. */ std::string newpath = this->filepath; @@ -783,12 +783,12 @@ static void Xunzip(byte **bufp, size_t *sizep) #if defined(WITH_ZLIB) /* In-place gunzip */ - if (StrEndsWith(textfile, ".gz")) Gunzip((byte**)&buf, &filesize); + if (textfile.ends_with(".gz")) Gunzip((byte**)&buf, &filesize); #endif #if defined(WITH_LIBLZMA) /* In-place xunzip */ - if (StrEndsWith(textfile, ".xz")) Xunzip((byte**)&buf, &filesize); + if (textfile.ends_with(".xz")) Xunzip((byte**)&buf, &filesize); #endif if (buf == nullptr) return; @@ -796,7 +796,7 @@ static void Xunzip(byte **bufp, size_t *sizep) std::string_view sv_buf(buf, filesize); /* Check for the byte-order-mark, and skip it if needed. */ - if (StrStartsWith(sv_buf, "\ufeff")) sv_buf.remove_prefix(3); + if (sv_buf.starts_with("\ufeff")) sv_buf.remove_prefix(3); /* Update the filename. */ this->filepath = textfile;