diff --git a/libc/src/__support/CPP/StringView.h b/libc/src/__support/CPP/StringView.h --- a/libc/src/__support/CPP/StringView.h +++ b/libc/src/__support/CPP/StringView.h @@ -122,11 +122,11 @@ } // An equivalent method is not available in std::string_view. - StringView trim(char C) const { + StringView trim(const char C) const { StringView Copy = *this; - while (!Copy.empty() && Copy.front() == C) + while (Copy.starts_with(C)) Copy = Copy.drop_front(); - while (!Copy.empty() && Copy.back() == C) + while (Copy.ends_with(C)) Copy = Copy.drop_back(); return Copy; } @@ -137,6 +137,16 @@ compareMemory(Data, Prefix.Data, Prefix.Len) == 0; } + // Check if this string starts with the given Prefix. + bool starts_with(const char Prefix) const { + return !empty() && front() == Prefix; + } + + // Check if this string ends with the given Prefix. + bool ends_with(const char Suffix) const { + return !empty() && back() == Suffix; + } + // Check if this string ends with the given Suffix. bool ends_with(StringView Suffix) const { return Len >= Suffix.Len && @@ -157,6 +167,20 @@ return StringView(Data + Start, min(N, Len - Start)); } + // Search for the first character matching the character + // + // Returns The index of the first character satisfying the character starting + // from From, or npos if not found. + size_t find_first_of(const char c, size_t From = 0) const noexcept { + StringView S = drop_front(From); + while (!S.empty()) { + if (S.front() == c) + return size() - S.size(); + S = S.drop_front(); + } + return npos; + } + // Search for the first character satisfying the predicate Function // // Returns The index of the first character satisfying Function starting from diff --git a/libc/test/src/__support/CPP/stringview_test.cpp b/libc/test/src/__support/CPP/stringview_test.cpp --- a/libc/test/src/__support/CPP/stringview_test.cpp +++ b/libc/test/src/__support/CPP/stringview_test.cpp @@ -49,17 +49,34 @@ TEST(LlvmLibcStringViewTest, startsWith) { StringView v("abc"); + ASSERT_TRUE(v.starts_with('a')); ASSERT_TRUE(v.starts_with(StringView("a"))); ASSERT_TRUE(v.starts_with(StringView("ab"))); ASSERT_TRUE(v.starts_with(StringView("abc"))); ASSERT_TRUE(v.starts_with(StringView())); ASSERT_TRUE(v.starts_with(StringView(""))); + ASSERT_FALSE(v.starts_with('1')); ASSERT_FALSE(v.starts_with(StringView("123"))); ASSERT_FALSE(v.starts_with(StringView("abd"))); ASSERT_FALSE(v.starts_with(StringView("aaa"))); ASSERT_FALSE(v.starts_with(StringView("abcde"))); } +TEST(LlvmLibcStringViewTest, endsWith) { + StringView v("abc"); + ASSERT_TRUE(v.ends_with('c')); + ASSERT_TRUE(v.ends_with(StringView("c"))); + ASSERT_TRUE(v.ends_with(StringView("bc"))); + ASSERT_TRUE(v.ends_with(StringView("abc"))); + ASSERT_TRUE(v.ends_with(StringView())); + ASSERT_TRUE(v.ends_with(StringView(""))); + ASSERT_FALSE(v.ends_with('1')); + ASSERT_FALSE(v.ends_with(StringView("123"))); + ASSERT_FALSE(v.ends_with(StringView("abd"))); + ASSERT_FALSE(v.ends_with(StringView("aaa"))); + ASSERT_FALSE(v.ends_with(StringView("abcde"))); +} + TEST(LlvmLibcStringViewTest, RemovePrefix) { StringView v("123456789"); @@ -176,3 +193,17 @@ ASSERT_TRUE(Tmp.consume_back("bc")); ASSERT_TRUE(Tmp.equals("a")); } + +TEST(LlvmLibcStringViewTest, FindFirstOf) { + StringView Tmp("abca"); + ASSERT_TRUE(Tmp.find_first_of('a') == 0); + ASSERT_TRUE(Tmp.find_first_of('d') == StringView::npos); + ASSERT_TRUE(Tmp.find_first_of('b') == 1); + ASSERT_TRUE(Tmp.find_first_of('a', 0) == 0); + ASSERT_TRUE(Tmp.find_first_of('b', 1) == 1); + ASSERT_TRUE(Tmp.find_first_of('a', 1) == 3); + ASSERT_TRUE(Tmp.find_first_of('a', 42) == StringView::npos); + ASSERT_FALSE(Tmp.find_first_of('c') == 1); + ASSERT_FALSE(Tmp.find_first_of('c', 0) == 1); + ASSERT_FALSE(Tmp.find_first_of('c', 1) == 1); +}