Skip to content

Commit

Permalink
-added string_utils overloads which are safe to use with temporary st…
Browse files Browse the repository at this point in the history
…rings;

-updated clang-format;
  • Loading branch information
kamchatka-volcano committed Jan 14, 2023
1 parent e71c5be commit 7a5f6eb
Show file tree
Hide file tree
Showing 3 changed files with 151 additions and 7 deletions.
1 change: 1 addition & 0 deletions .clang-format
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ BraceWrapping:
BeforeElse: true
BeforeLambdaBody: true
BeforeWhile: true
BeforeCatch: true
BreakBeforeBraces: Custom
BreakBeforeBinaryOperators: None
BreakInheritanceList: AfterComma
Expand Down
74 changes: 67 additions & 7 deletions include/sfun/string_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,10 @@ inline char toupper(char ch)
return static_cast<char>(std::toupper(static_cast<unsigned char>(ch)));
}

inline std::string_view trimFront(std::string_view str)
template<typename T, std::enable_if_t<std::is_convertible_v<T, std::string_view>>* = nullptr>
inline std::string_view trimFront(const T& strVal)
{
auto str = std::string_view{strVal};
auto it = std::find_if(
str.begin(),
str.end(),
Expand All @@ -91,8 +93,15 @@ inline std::string_view trimFront(std::string_view str)
return str.substr(static_cast<std::size_t>(firstNotBlank));
}

inline std::string_view trimBack(std::string_view str)
inline std::string trimFront(std::string&& str)
{
return std::string{trimFront(std::string_view{str})};
}

template<typename T, std::enable_if_t<std::is_convertible_v<T, std::string_view>>* = nullptr>
inline std::string_view trimBack(const T& strVal)
{
auto str = std::string_view{strVal};
auto it = std::find_if(
str.rbegin(),
str.rend(),
Expand All @@ -105,13 +114,27 @@ inline std::string_view trimBack(std::string_view str)
return str.substr(0, static_cast<std::size_t>(lastNotBlank));
}

inline std::string_view trim(std::string_view str)
inline std::string trimBack(std::string&& str)
{
return std::string{trimBack(std::string_view{str})};
}

template<typename T, std::enable_if_t<std::is_convertible_v<T, std::string_view>>* = nullptr>
inline std::string_view trim(const T& strVal)
{
auto str = std::string_view{strVal};
return trimBack(trimFront(str));
}

inline std::vector<std::string_view> split(std::string_view str, std::string_view delim = " ", bool trimmed = true)
inline std::string trim(std::string&& str)
{
return std::string{trim(std::string_view{str})};
}

template<typename T, std::enable_if_t<std::is_convertible_v<T, std::string_view>>* = nullptr>
inline std::vector<std::string_view> split(const T& strVal, std::string_view delim = " ", bool trimmed = true)
{
auto str = std::string_view{strVal};
if (delim.empty() || str.empty())
return std::vector<std::string_view>{str};

Expand All @@ -133,6 +156,21 @@ inline std::vector<std::string_view> split(std::string_view str, std::string_vie
return result;
}

inline std::vector<std::string> split(std::string&& str, std::string_view delim = " ", bool trimmed = true)
{
auto stringViewList = split(std::string_view{str}, delim, trimmed);
auto stringList = std::vector<std::string>{};
std::transform(
stringViewList.begin(),
stringViewList.end(),
std::back_inserter(stringList),
[](const std::string_view& view)
{
return std::string{view};
});
return stringList;
}

inline std::string replace(std::string str, std::string_view subStr, std::string_view val)
{
if (subStr.empty())
Expand Down Expand Up @@ -197,26 +235,48 @@ inline bool endsWith(std::string_view str, std::string_view val)
return std::distance(res, str.end()) == static_cast<std::ptrdiff_t>(val.size());
}

inline std::string_view before(std::string_view str, std::string_view val)
template<typename T, std::enable_if_t<std::is_convertible_v<T, std::string_view>>* = nullptr>
inline std::string_view before(const T& strVal, std::string_view val)
{
auto str = std::string_view{strVal};
auto res = str.find(val);
if (res == std::string_view::npos)
return str;
return {str.data(), res};
}

inline std::string_view after(std::string_view str, std::string_view val)
inline std::string before(std::string&& str, std::string_view val)
{
return std::string{before(std::string_view{str}, val)};
}

template<typename T, std::enable_if_t<std::is_convertible_v<T, std::string_view>>* = nullptr>
inline std::string_view after(const T& strVal, std::string_view val)
{
auto str = std::string_view{strVal};
auto res = str.find(val);
if (res == std::string_view::npos)
return {};
return {std::next(str.data(), static_cast<std::ptrdiff_t>(res + val.size())), str.size() - (res + val.size())};
}

inline std::string_view between(std::string_view str, std::string_view afterStr, std::string_view beforeStr)
inline std::string after(std::string&& str, std::string_view val)
{
return std::string{after(std::string_view{str}, val)};
}

template<typename T, std::enable_if_t<std::is_convertible_v<T, std::string_view>>* = nullptr>
inline std::string_view between(const T& strVal, std::string_view afterStr, std::string_view beforeStr)
{
auto str = std::string_view{strVal};
return before(after(str, afterStr), beforeStr);
}

inline std::string between(std::string&& str, std::string_view afterStr, std::string_view beforeStr)
{
return std::string{between(std::string_view{str}, afterStr, beforeStr)};
}

} //namespace sfun

#endif //SFUN_STRING_UTILS_H
83 changes: 83 additions & 0 deletions tests/test_string.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,18 @@ TEST(String, TrimFront)
EXPECT_EQ(trimFront(" \n \t "), "");
EXPECT_EQ(trimFront("\n\t"), "");
EXPECT_EQ(trimFront(""), "");

auto str = [](auto strVal)
{
return std::string{strVal};
};
EXPECT_EQ(trimFront(str(" Hello world")), "Hello world");
EXPECT_EQ(trimFront(str(" Hello world ")), "Hello world ");
EXPECT_EQ(trimFront(str(" \n\t Hello world")), "Hello world");
EXPECT_EQ(trimFront(str("Hello world ")), "Hello world ");
EXPECT_EQ(trimFront(str(" \n \t ")), "");
EXPECT_EQ(trimFront(str("\n\t")), "");
EXPECT_EQ(trimFront(str("")), "");
}

TEST(String, TrimBack)
Expand All @@ -22,6 +34,17 @@ TEST(String, TrimBack)
EXPECT_EQ(trimBack(" \n \t "), "");
EXPECT_EQ(trimBack("\n\t"), "");
EXPECT_EQ(trimBack(""), "");

auto str = [](auto strVal)
{
return std::string{strVal};
};
EXPECT_EQ(trimBack(str("Hello world ")), "Hello world");
EXPECT_EQ(trimBack(str(" Hello world ")), " Hello world");
EXPECT_EQ(trimBack(str("Hello world \n\t")), "Hello world");
EXPECT_EQ(trimBack(str(" \n \t ")), "");
EXPECT_EQ(trimBack(str("\n\t")), "");
EXPECT_EQ(trimBack(str("")), "");
}

TEST(String, Trim)
Expand All @@ -33,6 +56,18 @@ TEST(String, Trim)
EXPECT_EQ(trim(" \n\t "), "");
EXPECT_EQ(trim("\n\t"), "");
EXPECT_EQ(trim(""), "");

auto str = [](auto strVal)
{
return std::string{strVal};
};
EXPECT_EQ(trim(str(" Hello world")), "Hello world");
EXPECT_EQ(trim(str(" Hello world ")), "Hello world");
EXPECT_EQ(trim(str("Hello world ")), "Hello world");
EXPECT_EQ(trim(str(" \n\t Hello world")), "Hello world");
EXPECT_EQ(trim(str(" \n\t ")), "");
EXPECT_EQ(trim(str("\n\t")), "");
EXPECT_EQ(trim(str("")), "");
}

TEST(String, Split)
Expand All @@ -46,6 +81,20 @@ TEST(String, Split)
EXPECT_EQ(split(""), (std::vector<std::string_view>{""}));
EXPECT_EQ(split("hello world", ""), (std::vector<std::string_view>{"hello world"}));
EXPECT_EQ(split("", ""), (std::vector<std::string_view>{""}));

auto str = [](auto strVal)
{
return std::string{strVal};
};
EXPECT_EQ(split(str("hello world")), (std::vector<std::string>{"hello", "world"}));
EXPECT_EQ(split(str("hello world"), ","), (std::vector<std::string>{"hello world"}));
EXPECT_EQ(split(str("hello world, nice weather"), ","), (std::vector<std::string>{"hello world", "nice weather"}));
EXPECT_EQ(
split(str("hello world\n, nice weather"), ",", false),
(std::vector<std::string>{"hello world\n", " nice weather"}));
EXPECT_EQ(split(str("")), (std::vector<std::string>{""}));
EXPECT_EQ(split(str("hello world"), ""), (std::vector<std::string>{"hello world"}));
EXPECT_EQ(split(str(""), ""), (std::vector<std::string>{""}));
}

TEST(String, Replace)
Expand Down Expand Up @@ -124,6 +173,16 @@ TEST(String, Before)
EXPECT_EQ(before("hello world", ""), "");
EXPECT_EQ(before("", "moon"), "");
EXPECT_EQ(before("", ""), "");

auto str = [](auto strVal)
{
return std::string{strVal};
};
EXPECT_EQ(before(str("hello world"), "world"), "hello ");
EXPECT_EQ(before(str("hello world"), "moon"), "hello world");
EXPECT_EQ(before(str("hello world"), ""), "");
EXPECT_EQ(before(str(""), "moon"), "");
EXPECT_EQ(before(str(""), ""), "");
}

TEST(String, After)
Expand All @@ -133,6 +192,16 @@ TEST(String, After)
EXPECT_EQ(after("hello world", ""), "hello world");
EXPECT_EQ(after("", "moon"), "");
EXPECT_EQ(after("", ""), "");

auto str = [](auto strVal)
{
return std::string{strVal};
};
EXPECT_EQ(after(str("hello world"), "hello"), " world");
EXPECT_EQ(after(str("hello world"), "moon"), "");
EXPECT_EQ(after(str("hello world"), ""), "hello world");
EXPECT_EQ(after(str(""), "moon"), "");
EXPECT_EQ(after(str(""), ""), "");
}

TEST(String, Between)
Expand All @@ -146,6 +215,20 @@ TEST(String, Between)
EXPECT_EQ(between("", "", "moon"), "");
EXPECT_EQ(between("", "moon", ""), "");
EXPECT_EQ(between("", "", ""), "");

auto str = [](auto strVal)
{
return std::string{strVal};
};
EXPECT_EQ(between(str("hello world!"), "hello", "!"), " world");
EXPECT_EQ(between(str("hello world!"), "hello", "moon"), " world!");
EXPECT_EQ(between(str("hello world!"), "moon", "!"), "");
EXPECT_EQ(between(str("hello world!"), "", "!"), "hello world");
EXPECT_EQ(between(str("hello world!"), "hello", ""), "");
EXPECT_EQ(between(str(""), "hello", "moon"), "");
EXPECT_EQ(between(str(""), "", "moon"), "");
EXPECT_EQ(between(str(""), "moon", ""), "");
EXPECT_EQ(between(str(""), "", ""), "");
}

TEST(String, cctypeWrappers)
Expand Down

0 comments on commit 7a5f6eb

Please sign in to comment.