#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"
* 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
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()) {}
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_;
};
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);
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) {
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*>(
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) {