diff --git a/src/tll/util/string.h b/src/tll/util/string.h index 70b8be8d..f165062f 100644 --- a/src/tll/util/string.h +++ b/src/tll/util/string.h @@ -14,6 +14,11 @@ namespace tll { +inline std::string_view string_view_from_c(const char *base, int len) +{ + return { base, (len < 0)?strlen(base):len }; +} + namespace util { inline bool printable(char c) { return c >= 0x20 && c < 0x7f; } @@ -31,14 +36,25 @@ inline std::string_view strip(std::string_view s, std::string_view chars = " ") return s; } -} // namespace util +template +struct sep_helper; -inline std::string_view string_view_from_c(const char *base, int len) +template +struct sep_helper { - return { base, (len < 0)?strlen(base):len }; -} + static constexpr bool match(char c) + { + return c == C || sep_helper::match(c); + } +}; + +template <> +struct sep_helper<> +{ + static constexpr bool match(char c) { return false; } +}; -template +template struct split_helperT { std::string_view data; @@ -64,7 +80,7 @@ struct split_helperT { if (ptr >= data_end) return data_end; - for (; ptr + 1 < data_end && *ptr != Sep; ptr++) {} + for (; ptr + 1 < data_end && !sep_helper::match(*ptr); ptr++) {} return ptr; } @@ -72,7 +88,7 @@ struct split_helperT { if (ptr <= data_begin) return data_begin; - for (; ptr > data_begin && *(ptr - 1) != Sep; ptr--) {} + for (; ptr > data_begin && !sep_helper::match(*(ptr - 1)); ptr--) {} return ptr; } @@ -110,17 +126,17 @@ struct split_helperT iterator end() const { return iterator(data.begin(), data.end() + 1, data.end() + 1); } }; -template -inline split_helperT split(std::string_view s) +template +inline split_helperT split(std::string_view s) { return { s }; } -template -inline T & splitl(T & r, std::string_view s) +template +inline auto & split_append(T & r, std::string_view s, bool Skip = false) { using string_type = typename T::value_type; - for (auto i : split(s)) { + for (auto i : split(s)) { if (Skip && i.empty()) continue; r.push_back(string_type(i)); // Explicit constructor for std::string containers @@ -128,13 +144,28 @@ inline T & splitl(T & r, std::string_view s) return r; } -template -inline std::vector splitv(std::string_view s) +template +inline std::vector splitv(std::string_view s, bool skip = false) { std::vector r; - return std::move(splitl(r, s)); + return std::move(split_append(r, s, skip)); } +} // namespace util + +template +using split_helperT = util::split_helperT; + +// Old functions for backward compatibility +template +inline auto split(std::string_view s) { return util::split(s); } + +template +inline T & splitl(T & r, std::string_view s) { return util::split_append(r, s, Skip); } + +template +inline auto splitv(std::string_view s) { return util::splitv(s, Skip); } + } // namespace tll #endif//_TLL_UTIL_STRING_H diff --git a/test/test_util.cc b/test/test_util.cc index 465f3a3a..deccb0c6 100644 --- a/test/test_util.cc +++ b/test/test_util.cc @@ -55,10 +55,11 @@ TEST(Util, SplitT) typedef std::list list; EXPECT_EQ(splitL(""), list{""}); EXPECT_EQ(splitL(""), list{}); - EXPECT_EQ(splitL(","), (list{"", ""})); - EXPECT_EQ(splitL(","), list{}); EXPECT_EQ(splitL("a"), (list{"a"})); EXPECT_EQ(splitL("a"), (list{"a"})); + + EXPECT_EQ(splitL(","), (list{"", ""})); + EXPECT_EQ(splitL(","), list{}); EXPECT_EQ(splitL("a,"), (list{"a", ""})); EXPECT_EQ(splitL("a,"), (list{"a"})); EXPECT_EQ(splitL(",b"), (list{"", "b"})); @@ -67,6 +68,12 @@ TEST(Util, SplitT) EXPECT_EQ(splitL("a,b"), (list{"a", "b"})); EXPECT_EQ(splitL("a,,b"), (list{"a", "", "b"})); EXPECT_EQ(splitL("a,,b"), (list{"a", "b"})); + + typedef std::vector vector; + + EXPECT_EQ((tll::util::splitv<','>("a,;b")), (vector{"a", ";b"})); + EXPECT_EQ((tll::util::splitv<',', ';'>("a,;b")), (vector{"a", "", "b"})); + EXPECT_EQ((tll::util::splitv<',', ';'>("a,;b", true)), (vector{"a", "b"})); } TEST(Util, SplitIter)