diff --git a/folly/Range.h b/folly/Range.h index 2041d29b381..5466c6d6b8d 100644 --- a/folly/Range.h +++ b/folly/Range.h @@ -455,6 +455,48 @@ class Range : private boost::totally_ordered > { 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_; }; diff --git a/folly/test/RangeTest.cpp b/folly/test/RangeTest.cpp index 79698893e7b..7859b6b8697 100644 --- a/folly/test/RangeTest.cpp +++ b/folly/test/RangeTest.cpp @@ -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 a({1, 2, 3, 260, 5}); vector b({2, 3, 4}); @@ -494,3 +614,4 @@ TYPED_TEST(NeedleFinderTest, NoSegFault) { } } } +