This is an automated email from the ASF dual-hosted git repository.
junrushao pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tvm-ffi.git
The following commit(s) were added to refs/heads/main by this push:
new 02d1a96 feat: add starts_with and ends_with to String (#388)
02d1a96 is described below
commit 02d1a9600ac195fc320fe10fe42c978bcdb5e727
Author: Guan-Ming (Wesley) Chiu <[email protected]>
AuthorDate: Fri Jan 9 15:36:26 2026 +0800
feat: add starts_with and ends_with to String (#388)
## Why
String pattern matching is essential for validation and parsing in
compiler infrastructure. Users currently lack efficient prefix/suffix
checking methods.
## How
- Add `starts_with(prefix)` method supporting String, const char*, and
raw pointer with length
- Add `ends_with(suffix)` method with same overload variants
- Add tests
---
include/tvm/ffi/string.h | 70 ++++++++++++++++++++++++++++++++++++++++++++++++
tests/cpp/test_string.cc | 46 +++++++++++++++++++++++++++++++
2 files changed, 116 insertions(+)
diff --git a/include/tvm/ffi/string.h b/include/tvm/ffi/string.h
index 59addfa..9c1057a 100644
--- a/include/tvm/ffi/string.h
+++ b/include/tvm/ffi/string.h
@@ -655,6 +655,76 @@ class String {
return String(data() + pos, rcount);
}
+ /*!
+ * \brief Check if the string starts with a prefix
+ * \param prefix The prefix to check for
+ * \return true if the string starts with prefix, false otherwise
+ */
+ bool starts_with(const String& prefix) const { return
starts_with(prefix.data(), prefix.size()); }
+
+ /*!
+ * \brief Check if the string starts with a prefix
+ * \param prefix The prefix to check for
+ * \return true if the string starts with prefix, false otherwise
+ */
+ bool starts_with(std::string_view prefix) const {
+ return starts_with(prefix.data(), prefix.size());
+ }
+
+ /*!
+ * \brief Check if the string starts with a prefix
+ * \param prefix The prefix to check for
+ * \return true if the string starts with prefix, false otherwise
+ */
+ bool starts_with(const char* prefix) const { return starts_with(prefix,
std::strlen(prefix)); }
+
+ /*!
+ * \brief Check if the string starts with a prefix
+ * \param prefix The prefix to check for
+ * \param count The length of the prefix
+ * \return true if the string starts with prefix, false otherwise
+ */
+ bool starts_with(const char* prefix, size_t count) const {
+ if (count > size()) {
+ return false;
+ }
+ return std::memcmp(data(), prefix, count) == 0;
+ }
+
+ /*!
+ * \brief Check if the string ends with a suffix
+ * \param suffix The suffix to check for
+ * \return true if the string ends with suffix, false otherwise
+ */
+ bool ends_with(const String& suffix) const { return ends_with(suffix.data(),
suffix.size()); }
+
+ /*!
+ * \brief Check if the string ends with a suffix
+ * \param suffix The suffix to check for
+ * \return true if the string ends with suffix, false otherwise
+ */
+ bool ends_with(std::string_view suffix) const { return
ends_with(suffix.data(), suffix.size()); }
+
+ /*!
+ * \brief Check if the string ends with a suffix
+ * \param suffix The suffix to check for
+ * \return true if the string ends with suffix, false otherwise
+ */
+ bool ends_with(const char* suffix) const { return ends_with(suffix,
std::strlen(suffix)); }
+
+ /*!
+ * \brief Check if the string ends with a suffix
+ * \param suffix The suffix to check for
+ * \param count The length of the suffix
+ * \return true if the string ends with suffix, false otherwise
+ */
+ bool ends_with(const char* suffix, size_t count) const {
+ if (count > size()) {
+ return false;
+ }
+ return std::memcmp(data() + size() - count, suffix, count) == 0;
+ }
+
/*!
* \brief Convert String to an std::string object
*
diff --git a/tests/cpp/test_string.cc b/tests/cpp/test_string.cc
index afcb651..020cc41 100644
--- a/tests/cpp/test_string.cc
+++ b/tests/cpp/test_string.cc
@@ -482,4 +482,50 @@ TEST(String, Substr) {
EXPECT_THROW(empty.substr(1), std::out_of_range);
}
+TEST(String, StartsWith) {
+ String s{"hello world"};
+ EXPECT_TRUE(s.starts_with("hello"));
+ EXPECT_TRUE(s.starts_with("h"));
+ EXPECT_TRUE(s.starts_with(""));
+ EXPECT_TRUE(s.starts_with(String{"hello"}));
+ EXPECT_TRUE(s.starts_with(std::string_view{"hello"}));
+ EXPECT_FALSE(s.starts_with("world"));
+ EXPECT_FALSE(s.starts_with("Hello"));
+ EXPECT_FALSE(s.starts_with("hello world extra"));
+ EXPECT_FALSE(s.starts_with(std::string_view{"world"}));
+
+ String empty{""};
+ EXPECT_TRUE(empty.starts_with(""));
+ EXPECT_TRUE(empty.starts_with(std::string_view{""}));
+ EXPECT_FALSE(empty.starts_with("x"));
+
+ String single{"x"};
+ EXPECT_TRUE(single.starts_with("x"));
+ EXPECT_TRUE(single.starts_with(""));
+ EXPECT_FALSE(single.starts_with("xy"));
+}
+
+TEST(String, EndsWith) {
+ String s{"hello world"};
+ EXPECT_TRUE(s.ends_with("world"));
+ EXPECT_TRUE(s.ends_with("d"));
+ EXPECT_TRUE(s.ends_with(""));
+ EXPECT_TRUE(s.ends_with(String{"world"}));
+ EXPECT_TRUE(s.ends_with(std::string_view{"world"}));
+ EXPECT_FALSE(s.ends_with("hello"));
+ EXPECT_FALSE(s.ends_with("World"));
+ EXPECT_FALSE(s.ends_with("extra hello world"));
+ EXPECT_FALSE(s.ends_with(std::string_view{"hello"}));
+
+ String empty{""};
+ EXPECT_TRUE(empty.ends_with(""));
+ EXPECT_TRUE(empty.ends_with(std::string_view{""}));
+ EXPECT_FALSE(empty.ends_with("x"));
+
+ String single{"x"};
+ EXPECT_TRUE(single.ends_with("x"));
+ EXPECT_TRUE(single.ends_with(""));
+ EXPECT_FALSE(single.ends_with("yx"));
+}
+
} // namespace