From 9f33bfc58ed82cb893a86c48cb5ee56cc85d4814 Mon Sep 17 00:00:00 2001 From: Sepalani Date: Sun, 5 Jan 2025 00:04:28 +0400 Subject: [PATCH] StringUtil: Modernize SplitString and add unit tests --- Source/Core/Common/StringUtil.cpp | 16 ++++++----- Source/Core/Common/StringUtil.h | 2 +- Source/UnitTests/Common/StringUtilTest.cpp | 32 ++++++++++++++++++++++ 3 files changed, 42 insertions(+), 8 deletions(-) diff --git a/Source/Core/Common/StringUtil.cpp b/Source/Core/Common/StringUtil.cpp index 935db75d2f..7671cec6d3 100644 --- a/Source/Core/Common/StringUtil.cpp +++ b/Source/Core/Common/StringUtil.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -356,16 +357,17 @@ std::string PathToFileName(std::string_view path) return file_name + extension; } -std::vector SplitString(const std::string& str, const char delim) +std::vector SplitString(std::string_view sv, const char delim) { - std::istringstream iss(str); - std::vector output(1); + if (sv.empty()) + return {std::string()}; - while (std::getline(iss, *output.rbegin(), delim)) - output.push_back(""); + const std::ranges::split_view string_views(sv, delim); + std::ranges::transform_view strings(string_views, + [](auto&& r) { return std::string(r.data(), r.size()); }); - output.pop_back(); - return output; + // TODO: Use C++23 std::from_range + return {strings.begin(), strings.end()}; } std::string TabsToSpaces(int tab_size, std::string str) diff --git a/Source/Core/Common/StringUtil.h b/Source/Core/Common/StringUtil.h index 8ccc05ee6b..f42ccc0a04 100644 --- a/Source/Core/Common/StringUtil.h +++ b/Source/Core/Common/StringUtil.h @@ -199,7 +199,7 @@ std::from_chars_result FromChars(std::string_view sv, T& value, std::string TabsToSpaces(int tab_size, std::string str); -std::vector SplitString(const std::string& str, char delim); +std::vector SplitString(std::string_view sv, char delim); // "C:/Windows/winhelp.exe" to "C:/Windows/", "winhelp", ".exe" // This requires forward slashes to be used for the path separators, even on Windows. diff --git a/Source/UnitTests/Common/StringUtilTest.cpp b/Source/UnitTests/Common/StringUtilTest.cpp index abf37be585..62bf43878a 100644 --- a/Source/UnitTests/Common/StringUtilTest.cpp +++ b/Source/UnitTests/Common/StringUtilTest.cpp @@ -192,3 +192,35 @@ TEST(StringUtil, SplitPathBackslashesNotRecognizedAsSeparators) } // TODO: add `SplitPath` test coverage for paths containing Windows drives, e.g., "C:". + +TEST(StringUtil, SplitString) +{ + using V = std::vector; + const char d = ','; + EXPECT_EQ(SplitString("", d), V({""})); + EXPECT_EQ(SplitString("a", d), V({"a"})); + EXPECT_EQ(SplitString("ab", d), V({"ab"})); + EXPECT_EQ(SplitString(",", d), V({"", ""})); + EXPECT_EQ(SplitString("a,", d), V({"a", ""})); + EXPECT_EQ(SplitString(",b", d), V({"", "b"})); + EXPECT_EQ(SplitString("a,b", d), V({"a", "b"})); + EXPECT_EQ(SplitString("ab,", d), V({"ab", ""})); + EXPECT_EQ(SplitString(",ab", d), V({"", "ab"})); + EXPECT_EQ(SplitString("ab,,", d), V({"ab", "", ""})); + EXPECT_EQ(SplitString(",ab,", d), V({"", "ab", ""})); + EXPECT_EQ(SplitString(",,ab", d), V({"", "", "ab"})); + EXPECT_EQ(SplitString("a,,", d), V({"a", "", ""})); + EXPECT_EQ(SplitString("a,b,", d), V({"a", "b", ""})); + EXPECT_EQ(SplitString("a,,c", d), V({"a", "", "c"})); + EXPECT_EQ(SplitString(",b,", d), V({"", "b", ""})); + EXPECT_EQ(SplitString(",b,c", d), V({"", "b", "c"})); + EXPECT_EQ(SplitString(",,c", d), V({"", "", "c"})); + EXPECT_EQ(SplitString(",,", d), V({"", "", ""})); + EXPECT_EQ(SplitString("abc", d), V({"abc"})); + EXPECT_EQ(SplitString("a,bc", d), V({"a", "bc"})); + EXPECT_EQ(SplitString("ab,c", d), V({"ab", "c"})); + EXPECT_EQ(SplitString("abc,", d), V({"abc", ""})); + EXPECT_EQ(SplitString(",abc", d), V({"", "abc"})); + EXPECT_EQ(SplitString("abc,,", d), V({"abc", "", ""})); + EXPECT_EQ(SplitString(",,abc", d), V({"", "", "abc"})); +}