#include "folly/Portability.h"
#include "folly/FBString.h"
-#include <glog/logging.h>
#include <algorithm>
+#include <boost/operators.hpp>
#include <cstring>
+#include <glog/logging.h>
#include <iosfwd>
-#include <string>
#include <stdexcept>
+#include <string>
#include <type_traits>
-#include <boost/operators.hpp>
-// libc++ doesn't provide this header
-#if !FOLLY_USE_LIBCPP
+// libc++ doesn't provide this header, nor does msvc
+#ifdef FOLLY_HAVE_BITS_CXXCONFIG_H
// 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
// Works only for Range<const char*>
/* implicit */ Range(const std::string& str)
: b_(str.data()), e_(b_ + str.size()) {}
+
// Works only for Range<const char*>
Range(const std::string& str, std::string::size_type startFrom) {
if (UNLIKELY(startFrom > str.size())) {
// direction.
template <class OtherIter, typename std::enable_if<
(std::is_same<Iter, const unsigned char*>::value &&
- std::is_same<OtherIter, const char*>::value), int>::type = 0>
+ (std::is_same<OtherIter, const char*>::value ||
+ std::is_same<OtherIter, char*>::value)), int>::type = 0>
/* implicit */ Range(const Range<OtherIter>& other)
: b_(reinterpret_cast<const unsigned char*>(other.begin())),
e_(reinterpret_cast<const unsigned char*>(other.end())) {
}
+ template <class OtherIter, typename std::enable_if<
+ (std::is_same<Iter, unsigned char*>::value &&
+ std::is_same<OtherIter, char*>::value), int>::type = 0>
+ /* implicit */ Range(const Range<OtherIter>& other)
+ : b_(reinterpret_cast<unsigned char*>(other.begin())),
+ e_(reinterpret_cast<unsigned char*>(other.end())) {
+ }
+
template <class OtherIter, typename std::enable_if<
(std::is_same<Iter, const char*>::value &&
- std::is_same<OtherIter, const unsigned char*>::value), int>::type = 0>
+ (std::is_same<OtherIter, const unsigned char*>::value ||
+ std::is_same<OtherIter, unsigned char*>::value)), int>::type = 0>
explicit Range(const Range<OtherIter>& other)
: b_(reinterpret_cast<const char*>(other.begin())),
e_(reinterpret_cast<const char*>(other.end())) {
}
+ template <class OtherIter, typename std::enable_if<
+ (std::is_same<Iter, char*>::value &&
+ std::is_same<OtherIter, unsigned char*>::value), int>::type = 0>
+ explicit Range(const Range<OtherIter>& other)
+ : b_(reinterpret_cast<char*>(other.begin())),
+ e_(reinterpret_cast<char*>(other.end())) {
+ }
+
+ // Allow implicit conversion from Range<From> to Range<To> if From is
+ // implicitly convertible to To.
+ template <class OtherIter, typename std::enable_if<
+ (!std::is_same<Iter, OtherIter>::value &&
+ std::is_convertible<OtherIter, Iter>::value), int>::type = 0>
+ /* implicit */ Range(const Range<OtherIter>& other)
+ : b_(other.begin()),
+ e_(other.end()) {
+ }
+
+ // Allow explicit conversion from Range<From> to Range<To> if From is
+ // explicitly convertible to To.
+ template <class OtherIter, typename std::enable_if<
+ (!std::is_same<Iter, OtherIter>::value &&
+ !std::is_convertible<OtherIter, Iter>::value &&
+ std::is_constructible<Iter, const OtherIter&>::value), int>::type = 0>
+ explicit Range(const Range<OtherIter>& other)
+ : b_(other.begin()),
+ e_(other.end()) {
+ }
+
void clear() {
b_ = Iter();
e_ = Iter();
return find(c, pos);
}
+ /**
+ * Determine whether the range contains the given subrange or item.
+ *
+ * Note: Call find() directly if the index is needed.
+ */
+ bool contains(const Range& other) const {
+ return find(other) != std::string::npos;
+ }
+
+ bool contains(const value_type& other) const {
+ return find(other) != std::string::npos;
+ }
+
void swap(Range& rhs) {
std::swap(b_, rhs.b_);
std::swap(e_, rhs.e_);
* folly::StringPiece s("sample string for split_next");
* auto p = s.split_step(' ');
*
- * // prints "sample"
+ * // prints "string for split_next"
* cout << s << endl;
*
- * // prints "string for split_next"
+ * // prints "sample"
* cout << p << endl;
*
* Example 2:
* Create a range from two iterators, with type deduction.
*/
template <class Iter>
-Range<Iter> makeRange(Iter first, Iter last) {
+Range<Iter> range(Iter first, Iter last) {
return Range<Iter>(first, last);
}
+/*
+ * Creates a range to reference the contents of a contiguous-storage container.
+ */
+// Use pointers for types with '.data()' member
+template <class Collection,
+ class T = typename std::remove_pointer<
+ decltype(std::declval<Collection>().data())>::type>
+Range<T*> range(Collection&& v) {
+ return Range<T*>(v.data(), v.data() + v.size());
+}
+
+template <class T, size_t n>
+Range<T*> range(T (&array)[n]) {
+ return Range<T*>(array, array + n);
+}
+
typedef Range<const char*> StringPiece;
+typedef Range<char*> MutableStringPiece;
typedef Range<const unsigned char*> ByteRange;
+typedef Range<unsigned char*> MutableByteRange;
std::ostream& operator<<(std::ostream& os, const StringPiece& piece);
}
};
+/**
+ * Check if two ascii characters are case insensitive equal.
+ * The difference between the lower/upper case characters are the 6-th bit.
+ * We also check they are alpha chars, in case of xor = 32.
+ */
struct AsciiCaseInsensitive {
bool operator()(char lhs, char rhs) const {
- return toupper(lhs) == toupper(rhs);
+ char k = lhs ^ rhs;
+ if (k == 0) return true;
+ if (k != 32) return false;
+ k = lhs | rhs;
+ return (k >= 'a' && k <= 'z');
}
};