Baton - minimalist inter-thread notification
[folly.git] / folly / Range.h
index 85a554c5919d9289555e7df437de2c80c869683a..1d3d0dd0dd3c7693af96749249f6abbfdd6d79b2 100644 (file)
 #include <stdexcept>
 #include <type_traits>
 #include <boost/operators.hpp>
+
+// libc++ doesn't provide this header
+#if !FOLLY_USE_LIBCPP
+// This file appears in two locations: inside fbcode and in the
+// libstdc++ source code (when embedding fbstring as std::string).
+// To aid in this schizophrenic use, two macros are defined in
+// c++config.h:
+//   _LIBSTDCXX_FBSTRING - Set inside libstdc++.  This is useful to
+//      gate use inside fbcode v. libstdc++
 #include <bits/c++config.h>
+#endif
+
 #include "folly/CpuId.h"
 #include "folly/Traits.h"
 #include "folly/Likely.h"
@@ -49,9 +60,10 @@ template <class T> class Range;
  * as Boyer-Moore. On the upside, it does not do any upfront
  * preprocessing and does not allocate memory.
  */
-template <class T>
+template <class T, class Comp = std::equal_to<typename Range<T>::value_type>>
 inline size_t qfind(const Range<T> & haystack,
-                    const Range<T> & needle);
+                    const Range<T> & needle,
+                    Comp eq = Comp());
 
 /**
  * Finds the first occurrence of needle in haystack. The result is the
@@ -150,9 +162,15 @@ public:
   Range(Iter start, size_t size)
       : b_(start), e_(start + size) { }
 
+#if FOLLY_HAVE_CONSTEXPR_STRLEN
+  // Works only for Range<const char*>
+  /* implicit */ constexpr Range(Iter str)
+      : b_(str), e_(str + strlen(str)) {}
+#else
   // Works only for Range<const char*>
   /* implicit */ Range(Iter str)
-      : b_(str), e_(b_ + strlen(str)) {}
+      : b_(str), e_(str + strlen(str)) {}
+#endif
   // Works only for Range<const char*>
   /* implicit */ Range(const std::string& str)
       : b_(str.data()), e_(b_ + str.size()) {}
@@ -448,6 +466,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_;
 };
@@ -627,7 +687,7 @@ namespace detail {
 size_t qfind_first_byte_of_nosse(const StringPiece& haystack,
                                  const StringPiece& needles);
 
-#if FOLLY_HAVE_EMMINTRIN_H
+#if FOLLY_HAVE_EMMINTRIN_H && __GNUC_PREREQ(4, 6)
 size_t qfind_first_byte_of_sse42(const StringPiece& haystack,
                                  const StringPiece& needles);
 
@@ -673,12 +733,6 @@ struct AsciiCaseInsensitive {
 extern const AsciiCaseSensitive asciiCaseSensitive;
 extern const AsciiCaseInsensitive asciiCaseInsensitive;
 
-template <class T>
-size_t qfind(const Range<T>& haystack,
-             const Range<T>& needle) {
-  return qfind(haystack, needle, asciiCaseSensitive);
-}
-
 template <class T>
 size_t qfind(const Range<T>& haystack,
              const typename Range<T>::value_type& needle) {
@@ -705,7 +759,7 @@ inline size_t qfind(const Range<const char*>& haystack, const char& needle) {
   return pos == nullptr ? std::string::npos : pos - haystack.data();
 }
 
-#ifdef _GNU_SOURCE // memrchr is a GNU extension
+#if FOLLY_HAVE_MEMRCHR
 template <>
 inline size_t rfind(const Range<const char*>& haystack, const char& needle) {
   auto pos = static_cast<const char*>(
@@ -723,7 +777,7 @@ inline size_t qfind(const Range<const unsigned char*>& haystack,
   return pos == nullptr ? std::string::npos : pos - haystack.data();
 }
 
-#ifdef _GNU_SOURCE // memrchr is a GNU extension
+#if FOLLY_HAVE_MEMRCHR
 template <>
 inline size_t rfind(const Range<const unsigned char*>& haystack,
                     const unsigned char& needle) {