diff options
author | Derek Mauro <dmauro@google.com> | 2023-10-20 09:21:26 -0700 |
---|---|---|
committer | Copybara-Service <copybara-worker@google.com> | 2023-10-20 09:22:00 -0700 |
commit | 0f110600fcd84bd99e559eaf88b8ab5b4c32cce0 (patch) | |
tree | efb2ce1cd33d152802dca75ad18dd4c617185d8a | |
parent | 03786143361db9d8581cb02ed1c5027d732b62fc (diff) |
absl::string_view: Add support for starts_with() and ends_with()
when targeting at least C++20
These methods were added to C++20, so they are not available in
earlier language standards. Users requiring compatibility prior to C++20
should use absl::StartsWith() and absl::EndsWith() from
//absl/strings/match.h.
Most users are not affected by this change. By default when targeting at least
C++20 absl::string_view will be an alias for std::string_view. Only users
that have modified //absl/base/options.h will see this change.
PiperOrigin-RevId: 575238435
Change-Id: I7b03fde02c987b30b88c794640c2a616851997d1
-rw-r--r-- | absl/strings/string_view.h | 54 | ||||
-rw-r--r-- | absl/strings/string_view_test.cc | 70 |
2 files changed, 123 insertions, 1 deletions
diff --git a/absl/strings/string_view.h b/absl/strings/string_view.h index eae11b2a..f88b05b6 100644 --- a/absl/strings/string_view.h +++ b/absl/strings/string_view.h @@ -506,7 +506,7 @@ class string_view { // Overload of `string_view::find_first_of()` for finding a substring of a // different C-style string `s` within the `string_view`. size_type find_first_of(const char* s, size_type pos, - size_type count) const { + size_type count) const { return find_first_of(string_view(s, count), pos); } @@ -590,6 +590,58 @@ class string_view { return find_last_not_of(string_view(s), pos); } +#if ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L + // string_view::starts_with() + // + // Returns true if the `string_view` starts with the prefix `s`. + // + // This method only exists when targeting at least C++20. + // If support for C++ prior to C++20 is required, use `absl::StartsWith()` + // from `//absl/strings/match.h` for compatibility. + constexpr bool starts_with(string_view s) const noexcept { + return s.empty() || + (size() >= s.size() && + ABSL_INTERNAL_STRING_VIEW_MEMCMP(data(), s.data(), s.size()) == 0); + } + + // Overload of `string_view::starts_with()` that returns true if `c` is the + // first character of the `string_view`. + constexpr bool starts_with(char c) const noexcept { + return !empty() && front() == c; + } + + // Overload of `string_view::starts_with()` that returns true if the + // `string_view` starts with the C-style prefix `s`. + constexpr bool starts_with(const char* s) const { + return starts_with(string_view(s)); + } + + // string_view::ends_with() + // + // Returns true if the `string_view` ends with the suffix `s`. + // + // This method only exists when targeting at least C++20. + // If support for C++ prior to C++20 is required, use `absl::EndsWith()` + // from `//absl/strings/match.h` for compatibility. + constexpr bool ends_with(string_view s) const noexcept { + return s.empty() || (size() >= s.size() && ABSL_INTERNAL_STRING_VIEW_MEMCMP( + data() + (size() - s.size()), + s.data(), s.size()) == 0); + } + + // Overload of `string_view::ends_with()` that returns true if `c` is the + // last character of the `string_view`. + constexpr bool ends_with(char c) const noexcept { + return !empty() && back() == c; + } + + // Overload of `string_view::ends_with()` that returns true if the + // `string_view` ends with the C-style suffix `s`. + constexpr bool ends_with(const char* s) const { + return ends_with(string_view(s)); + } +#endif // ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L + private: // The constructor from std::string delegates to this constructor. // See the comment on that constructor for the rationale. diff --git a/absl/strings/string_view_test.cc b/absl/strings/string_view_test.cc index 642989b1..5b1eb01a 100644 --- a/absl/strings/string_view_test.cc +++ b/absl/strings/string_view_test.cc @@ -951,6 +951,76 @@ TEST(StringViewTest, At) { #endif } +#if ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L +TEST(StringViewTest, StartsWith) { + const absl::string_view a("foobar"); + const absl::string_view b("123\0abc", 7); + const absl::string_view e; + EXPECT_TRUE(a.starts_with(a)); + EXPECT_TRUE(a.starts_with("foo")); + EXPECT_TRUE(a.starts_with('f')); + EXPECT_TRUE(a.starts_with(e)); + EXPECT_TRUE(b.starts_with(b)); + EXPECT_TRUE(b.starts_with('1')); + EXPECT_TRUE(b.starts_with(e)); + EXPECT_TRUE(e.starts_with("")); + EXPECT_FALSE(a.starts_with(b)); + EXPECT_FALSE(b.starts_with(a)); + EXPECT_FALSE(e.starts_with(a)); + EXPECT_FALSE(a.starts_with('r')); + EXPECT_FALSE(a.starts_with('\0')); + EXPECT_FALSE(e.starts_with('r')); + EXPECT_FALSE(e.starts_with('\0')); + + // Test that constexpr compiles. + constexpr absl::string_view kFooBar("foobar"); + constexpr absl::string_view kFoo("foo"); + constexpr absl::string_view kBar("bar"); + constexpr bool k1 = kFooBar.starts_with(kFoo); + EXPECT_TRUE(k1); + constexpr bool k2 = kFooBar.starts_with(kBar); + EXPECT_FALSE(k2); + constexpr bool k3 = kFooBar.starts_with('f'); + EXPECT_TRUE(k3); + constexpr bool k4 = kFooBar.starts_with("fo"); + EXPECT_TRUE(k4); +} + +TEST(StringViewTest, EndsWith) { + const absl::string_view a("foobar"); + const absl::string_view b("123\0abc", 7); + const absl::string_view e; + EXPECT_TRUE(a.ends_with(a)); + EXPECT_TRUE(a.ends_with('r')); + EXPECT_TRUE(a.ends_with("bar")); + EXPECT_TRUE(a.ends_with(e)); + EXPECT_TRUE(b.ends_with(b)); + EXPECT_TRUE(b.ends_with('c')); + EXPECT_TRUE(b.ends_with(e)); + EXPECT_TRUE(e.ends_with("")); + EXPECT_FALSE(a.ends_with(b)); + EXPECT_FALSE(b.ends_with(a)); + EXPECT_FALSE(e.ends_with(a)); + EXPECT_FALSE(a.ends_with('f')); + EXPECT_FALSE(a.ends_with('\0')); + EXPECT_FALSE(e.ends_with('r')); + EXPECT_FALSE(e.ends_with('\0')); + + // Test that constexpr compiles. + constexpr absl::string_view kFooBar("foobar"); + constexpr absl::string_view kFoo("foo"); + constexpr absl::string_view kBar("bar"); + constexpr bool k1 = kFooBar.ends_with(kFoo); + EXPECT_FALSE(k1); + constexpr bool k2 = kFooBar.ends_with(kBar); + EXPECT_TRUE(k2); + constexpr bool k3 = kFooBar.ends_with('r'); + EXPECT_TRUE(k3); + constexpr bool k4 = kFooBar.ends_with("ar"); + EXPECT_TRUE(k4); +} +#endif // ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L + struct MyCharAlloc : std::allocator<char> {}; TEST(StringViewTest, ExplicitConversionOperator) { |