Range<T>::rfind()
authorTom Jackson <tjackson@fb.com>
Wed, 26 Jun 2013 23:53:58 +0000 (16:53 -0700)
committerSara Golemon <sgolemon@fb.com>
Mon, 1 Jul 2013 19:57:43 +0000 (12:57 -0700)
Test Plan: Unit tests

Reviewed By: andrei.alexandrescu@fb.com

FB internal diff: D865951

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

index 188a534abe118b53eb0196ed9a8eee602ba90a53..2c26db07537da0ee1c52a7d4286c9bcec2bce997 100644 (file)
@@ -62,6 +62,15 @@ template <class T>
 size_t qfind(const Range<T> & haystack,
              const typename Range<T>::value_type& needle);
 
+/**
+ * Finds the last occurrence of needle in haystack. The result is the
+ * offset reported to the beginning of haystack, or string::npos if
+ * needle wasn't found.
+ */
+template <class T>
+size_t rfind(const Range<T> & haystack,
+             const typename Range<T>::value_type& needle);
+
 
 /**
  * Finds the first occurrence of any element of needle in
@@ -392,6 +401,10 @@ public:
     return qfind(*this, c);
   }
 
+  size_type rfind(value_type c) const {
+    return folly::rfind(*this, c);
+  }
+
   size_type find(value_type c, size_t pos) const {
     if (pos > size()) return std::string::npos;
     size_type ret = qfind(subpiece(pos), c);
@@ -673,6 +686,17 @@ size_t qfind(const Range<T>& haystack,
   return pos == haystack.end() ? std::string::npos : pos - haystack.data();
 }
 
+template <class T>
+size_t rfind(const Range<T>& haystack,
+             const typename Range<T>::value_type& needle) {
+  for (auto i = haystack.size(); i-- > 0; ) {
+    if (haystack[i] == needle) {
+      return i;
+    }
+  }
+  return std::string::npos;
+}
+
 // specialization for StringPiece
 template <>
 inline size_t qfind(const Range<const char*>& haystack, const char& needle) {
@@ -681,6 +705,13 @@ inline size_t qfind(const Range<const char*>& haystack, const char& needle) {
   return pos == nullptr ? std::string::npos : pos - haystack.data();
 }
 
+template <>
+inline size_t rfind(const Range<const char*>& haystack, const char& needle) {
+  auto pos = static_cast<const char*>(
+    ::memrchr(haystack.data(), needle, haystack.size()));
+  return pos == nullptr ? std::string::npos : pos - haystack.data();
+}
+
 // specialization for ByteRange
 template <>
 inline size_t qfind(const Range<const unsigned char*>& haystack,
@@ -690,6 +721,14 @@ inline size_t qfind(const Range<const unsigned char*>& haystack,
   return pos == nullptr ? std::string::npos : pos - haystack.data();
 }
 
+template <>
+inline size_t rfind(const Range<const unsigned char*>& haystack,
+                    const unsigned char& needle) {
+  auto pos = static_cast<const unsigned char*>(
+    ::memrchr(haystack.data(), needle, haystack.size()));
+  return pos == nullptr ? std::string::npos : pos - haystack.data();
+}
+
 template <class T>
 size_t qfind_first_of(const Range<T>& haystack,
                       const Range<T>& needles) {
index b82ac85f851af62ae23503d858bccfa15d0d3d36..1c2b1f369cde9e074cf7da29518f493e20353b49 100644 (file)
@@ -121,6 +121,16 @@ TEST(StringPiece, All) {
   EXPECT_EQ(s.find('\0'), std::string().find('\0'));
   EXPECT_EQ(s.find('\0'), StringPiece::npos);
 
+  // single char rfinds
+  EXPECT_EQ(s.rfind('b'), 6);
+  EXPECT_EQ(s.rfind('y'), StringPiece::npos);
+  EXPECT_EQ(s.str().rfind('y'), StringPiece::npos);
+  EXPECT_EQ(ByteRange(s).rfind('b'), 6);
+  EXPECT_EQ(ByteRange(s).rfind('y'), StringPiece::npos);
+  // null char
+  EXPECT_EQ(s.rfind('\0'), s.str().rfind('\0'));
+  EXPECT_EQ(s.rfind('\0'), StringPiece::npos);
+
   // find_first_of
   s.reset(foobarbaz, strlen(foobarbaz));
   EXPECT_EQ(s.find_first_of("bar"), 3);