Add startsWith, endsWith, removePrefix, removeSuffix to folly::Range
authorTudor Bosman <tudorb@fb.com>
Thu, 19 Dec 2013 16:31:40 +0000 (08:31 -0800)
committerJordan DeLong <jdelong@fb.com>
Fri, 20 Dec 2013 21:07:41 +0000 (13:07 -0800)
Summary:
Yes, I know about boost::starts_with, but I think the convenience is worth it.
Also, I've written then equivalent of removePrefix / removeSuffix way too
many times.

Test Plan: test added

Reviewed By: andrei.alexandrescu@fb.com

FB internal diff: D1106425

folly/Range.h
folly/test/RangeTest.cpp

index 2041d29b38134422afdcfacc2c25cefef4636dbc..5466c6d6b8d611f067b0fd4bbcfa9f8b06a78763 100644 (file)
@@ -455,6 +455,48 @@ public:
     std::swap(e_, rhs.e_);
   }
 
+  /**
+   * Does this Range start with another range?
+   */
+  bool startsWith(const Range& other) const {
+    return size() >= other.size() && subpiece(0, other.size()) == other;
+  }
+  bool startsWith(value_type c) const {
+    return !empty() && front() == c;
+  }
+
+  /**
+   * Does this Range end with another range?
+   */
+  bool endsWith(const Range& other) const {
+    return size() >= other.size() && subpiece(size() - other.size()) == other;
+  }
+  bool endsWith(value_type c) const {
+    return !empty() && back() == c;
+  }
+
+  /**
+   * Remove the given prefix and return true if the range starts with the given
+   * prefix; return false otherwise.
+   */
+  bool removePrefix(const Range& prefix) {
+    return startsWith(prefix) && (b_ += prefix.size(), true);
+  }
+  bool removePrefix(value_type prefix) {
+    return startsWith(prefix) && (++b_, true);
+  }
+
+  /**
+   * Remove the given suffix and return true if the range ends with the given
+   * suffix; return false otherwise.
+   */
+  bool removeSuffix(const Range& suffix) {
+    return endsWith(suffix) && (e_ -= suffix.size(), true);
+  }
+  bool removeSuffix(value_type suffix) {
+    return endsWith(suffix) && (--e_, true);
+  }
+
 private:
   Iter b_, e_;
 };
index 79698893e7b3bcbea8ae36cc90f0456500c8ff03..7859b6b8697c0920aa2035ace1962c1904046f1f 100644 (file)
@@ -302,6 +302,126 @@ TEST(StringPiece, Constexpr) {
 }
 #endif
 
+TEST(StringPiece, Prefix) {
+  StringPiece a("hello");
+  EXPECT_TRUE(a.startsWith(""));
+  EXPECT_TRUE(a.startsWith("h"));
+  EXPECT_TRUE(a.startsWith('h'));
+  EXPECT_TRUE(a.startsWith("hello"));
+  EXPECT_FALSE(a.startsWith("hellox"));
+  EXPECT_FALSE(a.startsWith('x'));
+  EXPECT_FALSE(a.startsWith("x"));
+
+  {
+    auto b = a;
+    EXPECT_TRUE(b.removePrefix(""));
+    EXPECT_EQ("hello", b);
+  }
+  {
+    auto b = a;
+    EXPECT_TRUE(b.removePrefix("h"));
+    EXPECT_EQ("ello", b);
+  }
+  {
+    auto b = a;
+    EXPECT_TRUE(b.removePrefix('h'));
+    EXPECT_EQ("ello", b);
+  }
+  {
+    auto b = a;
+    EXPECT_TRUE(b.removePrefix("hello"));
+    EXPECT_EQ("", b);
+  }
+  {
+    auto b = a;
+    EXPECT_FALSE(b.removePrefix("hellox"));
+    EXPECT_EQ("hello", b);
+  }
+  {
+    auto b = a;
+    EXPECT_FALSE(b.removePrefix("x"));
+    EXPECT_EQ("hello", b);
+  }
+  {
+    auto b = a;
+    EXPECT_FALSE(b.removePrefix('x'));
+    EXPECT_EQ("hello", b);
+  }
+}
+
+TEST(StringPiece, Suffix) {
+  StringPiece a("hello");
+  EXPECT_TRUE(a.endsWith(""));
+  EXPECT_TRUE(a.endsWith("o"));
+  EXPECT_TRUE(a.endsWith('o'));
+  EXPECT_TRUE(a.endsWith("hello"));
+  EXPECT_FALSE(a.endsWith("xhello"));
+  EXPECT_FALSE(a.endsWith("x"));
+  EXPECT_FALSE(a.endsWith('x'));
+
+  {
+    auto b = a;
+    EXPECT_TRUE(b.removeSuffix(""));
+    EXPECT_EQ("hello", b);
+  }
+  {
+    auto b = a;
+    EXPECT_TRUE(b.removeSuffix("o"));
+    EXPECT_EQ("hell", b);
+  }
+  {
+    auto b = a;
+    EXPECT_TRUE(b.removeSuffix('o'));
+    EXPECT_EQ("hell", b);
+  }
+  {
+    auto b = a;
+    EXPECT_TRUE(b.removeSuffix("hello"));
+    EXPECT_EQ("", b);
+  }
+  {
+    auto b = a;
+    EXPECT_FALSE(b.removeSuffix("xhello"));
+    EXPECT_EQ("hello", b);
+  }
+  {
+    auto b = a;
+    EXPECT_FALSE(b.removeSuffix("x"));
+    EXPECT_EQ("hello", b);
+  }
+  {
+    auto b = a;
+    EXPECT_FALSE(b.removeSuffix('x'));
+    EXPECT_EQ("hello", b);
+  }
+}
+
+TEST(StringPiece, PrefixEmpty) {
+  StringPiece a;
+  EXPECT_TRUE(a.startsWith(""));
+  EXPECT_FALSE(a.startsWith("a"));
+  EXPECT_FALSE(a.startsWith('a'));
+  EXPECT_TRUE(a.removePrefix(""));
+  EXPECT_EQ("", a);
+  EXPECT_FALSE(a.removePrefix("a"));
+  EXPECT_EQ("", a);
+  EXPECT_FALSE(a.removePrefix('a'));
+  EXPECT_EQ("", a);
+}
+
+TEST(StringPiece, SuffixEmpty) {
+  StringPiece a;
+  EXPECT_TRUE(a.endsWith(""));
+  EXPECT_FALSE(a.endsWith("a"));
+  EXPECT_FALSE(a.endsWith('a'));
+  EXPECT_TRUE(a.removeSuffix(""));
+  EXPECT_EQ("", a);
+  EXPECT_FALSE(a.removeSuffix("a"));
+  EXPECT_EQ("", a);
+  EXPECT_FALSE(a.removeSuffix('a'));
+  EXPECT_EQ("", a);
+}
+
 TEST(qfind, UInt32_Ranges) {
   vector<uint32_t> a({1, 2, 3, 260, 5});
   vector<uint32_t> b({2, 3, 4});
@@ -494,3 +614,4 @@ TYPED_TEST(NeedleFinderTest, NoSegFault) {
     }
   }
 }
+