drop V0 of EliasFanoEncoder
[folly.git] / folly / Range.h
index f556986544a54ccbee21d5bb30a5535626333df3..c34d5cfe601efd766d7c43b3181422a02eae4686 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2014 Facebook, Inc.
+ * Copyright 2015 Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 
 #include <folly/Portability.h>
 #include <folly/FBString.h>
+#include <folly/SpookyHashV2.h>
+
 #include <algorithm>
 #include <boost/operators.hpp>
+#include <climits>
 #include <cstring>
 #include <glog/logging.h>
 #include <iosfwd>
@@ -121,6 +124,23 @@ value_before(Iter i) {
   return *--i;
 }
 
+/*
+ * Use IsCharPointer<T>::type to enable const char* or char*.
+ * Use IsCharPointer<T>::const_type to enable only const char*.
+ */
+template <class T> struct IsCharPointer {};
+
+template <>
+struct IsCharPointer<char*> {
+  typedef int type;
+};
+
+template <>
+struct IsCharPointer<const char*> {
+  typedef int const_type;
+  typedef int type;
+};
+
 } // namespace detail
 
 /**
@@ -163,32 +183,35 @@ public:
   static const size_type npos;
 
   // Works for all iterators
-  Range() : b_(), e_() {
+  constexpr Range() : b_(), e_() {
   }
 
+  constexpr Range(const Range&) = default;
+  constexpr Range(Range&&) = default;
+
 public:
   // Works for all iterators
-  Range(Iter start, Iter end) : b_(start), e_(end) {
+  constexpr Range(Iter start, Iter end) : b_(start), e_(end) {
   }
 
   // Works only for random-access iterators
-  Range(Iter start, size_t size)
+  constexpr 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)
+  template <class T = Iter, typename detail::IsCharPointer<T>::type = 0>
+  constexpr /* implicit */ Range(Iter str)
       : b_(str), e_(str + strlen(str)) {}
 #else
-  // Works only for Range<const char*>
+  template <class T = Iter, typename detail::IsCharPointer<T>::type = 0>
   /* implicit */ Range(Iter str)
       : b_(str), e_(str + strlen(str)) {}
 #endif
-  // Works only for Range<const char*>
+  template <class T = Iter, typename detail::IsCharPointer<T>::const_type = 0>
   /* implicit */ Range(const std::string& str)
       : b_(str.data()), e_(b_ + str.size()) {}
 
-  // Works only for Range<const char*>
+  template <class T = Iter, typename detail::IsCharPointer<T>::const_type = 0>
   Range(const std::string& str, std::string::size_type startFrom) {
     if (UNLIKELY(startFrom > str.size())) {
       throw std::out_of_range("index out of range");
@@ -196,7 +219,8 @@ public:
     b_ = str.data() + startFrom;
     e_ = str.data() + str.size();
   }
-  // Works only for Range<const char*>
+
+  template <class T = Iter, typename detail::IsCharPointer<T>::const_type = 0>
   Range(const std::string& str,
         std::string::size_type startFrom,
         std::string::size_type size) {
@@ -210,23 +234,18 @@ public:
       e_ = b_ + size;
     }
   }
-  Range(const Range<Iter>& str,
-        size_t startFrom,
-        size_t size) {
-    if (UNLIKELY(startFrom > str.size())) {
-      throw std::out_of_range("index out of range");
-    }
-    b_ = str.b_ + startFrom;
-    if (str.size() - startFrom < size) {
-      e_ = str.e_;
-    } else {
-      e_ = b_ + size;
-    }
-  }
-  // Works only for Range<const char*>
+
+  Range(const Range& other,
+        size_type first,
+        size_type length = npos)
+      : Range(other.subpiece(first, length))
+    { }
+
+  template <class T = Iter, typename detail::IsCharPointer<T>::const_type = 0>
   /* implicit */ Range(const fbstring& str)
     : b_(str.data()), e_(b_ + str.size()) { }
-  // Works only for Range<const char*>
+
+  template <class T = Iter, typename detail::IsCharPointer<T>::const_type = 0>
   Range(const fbstring& str, fbstring::size_type startFrom) {
     if (UNLIKELY(startFrom > str.size())) {
       throw std::out_of_range("index out of range");
@@ -234,7 +253,8 @@ public:
     b_ = str.data() + startFrom;
     e_ = str.data() + str.size();
   }
-  // Works only for Range<const char*>
+
+  template <class T = Iter, typename detail::IsCharPointer<T>::const_type = 0>
   Range(const fbstring& str, fbstring::size_type startFrom,
         fbstring::size_type size) {
     if (UNLIKELY(startFrom > str.size())) {
@@ -291,7 +311,7 @@ public:
   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)
+  constexpr /* implicit */ Range(const Range<OtherIter>& other)
     : b_(other.begin()),
       e_(other.end()) {
   }
@@ -302,11 +322,14 @@ public:
     (!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)
+  constexpr explicit Range(const Range<OtherIter>& other)
     : b_(other.begin()),
       e_(other.end()) {
   }
 
+  Range& operator=(const Range& rhs) & = default;
+  Range& operator=(Range&& rhs) & = default;
+
   void clear() {
     b_ = Iter();
     e_ = Iter();
@@ -358,10 +381,10 @@ public:
     assert(b_ < e_);
     return detail::value_before(e_);
   }
-  // Works only for Range<const char*>
+  // Works only for Range<const char*> and Range<char*>
   std::string str() const { return std::string(b_, size()); }
   std::string toString() const { return str(); }
-  // Works only for Range<const char*>
+  // Works only for Range<const char*> and Range<char*>
   fbstring fbstr() const { return fbstring(b_, size()); }
   fbstring toFbstring() const { return fbstr(); }
 
@@ -369,13 +392,19 @@ public:
     return const_range_type(*this);
   };
 
-  // Works only for Range<const char*> (and Range<char*>)
+  // Works only for Range<const char*> and Range<char*>
   int compare(const const_range_type& o) const {
     const size_type tsize = this->size();
     const size_type osize = o.size();
     const size_type msize = std::min(tsize, osize);
     int r = traits_type::compare(data(), o.data(), msize);
-    if (r == 0) r = tsize - osize;
+    if (r == 0 && tsize != osize) {
+      // We check the signed bit of the subtraction and bit shift it
+      // to produce either 0 or 2. The subtraction yields the
+      // comparison values of either -1 or 1.
+      r = (static_cast<int>(
+             (osize - tsize) >> (CHAR_BIT * sizeof(size_t) - 1)) << 1) - 1;
+    }
     return r;
   }
 
@@ -399,7 +428,12 @@ public:
     return b_[i];
   }
 
-  // Works only for Range<const char*>
+  // Do NOT use this function, which was left behind for backwards
+  // compatibility.  Use SpookyHashV2 instead -- it is faster, and produces
+  // a 64-bit hash, which means dramatically fewer collisions in large maps.
+  // (The above advice does not apply if you are targeting a 32-bit system.)
+  //
+  // Works only for Range<const char*> and Range<char*>
   uint32_t hash() const {
     // Taken from fbi/nstring.h:
     //    Quick and dirty bernstein hash...fine for short ascii strings
@@ -434,13 +468,12 @@ public:
     --e_;
   }
 
-  Range subpiece(size_type first,
-                 size_type length = std::string::npos) const {
+  Range subpiece(size_type first, size_type length = npos) const {
     if (UNLIKELY(first > size())) {
       throw std::out_of_range("index out of range");
     }
-    return Range(b_ + first,
-                 std::min<std::string::size_type>(length, size() - first));
+
+    return Range(b_ + first, std::min(length, size() - first));
   }
 
   // string work-alike functions
@@ -803,7 +836,17 @@ typedef Range<char*> MutableStringPiece;
 typedef Range<const unsigned char*> ByteRange;
 typedef Range<unsigned char*> MutableByteRange;
 
-std::ostream& operator<<(std::ostream& os, const StringPiece& piece);
+inline std::ostream& operator<<(std::ostream& os,
+                                const StringPiece piece) {
+  os.write(piece.start(), piece.size());
+  return os;
+}
+
+inline std::ostream& operator<<(std::ostream& os,
+                                const MutableStringPiece piece) {
+  os.write(piece.start(), piece.size());
+  return os;
+}
 
 /**
  * Templated comparison operators
@@ -889,8 +932,9 @@ operator>=(const T& lhs, const U& rhs) {
   return StringPiece(lhs) >= StringPiece(rhs);
 }
 
+// Do NOT use this, use SpookyHashV2 instead, see commment on hash() above.
 struct StringPieceHash {
-  std::size_t operator()(const StringPiece& str) const {
+  std::size_t operator()(const StringPiece str) const {
     return static_cast<std::size_t>(str.hash());
   }
 };
@@ -956,15 +1000,15 @@ size_t qfind(const Range<T>& haystack,
 
 namespace detail {
 
-size_t qfind_first_byte_of_nosse(const StringPiece& haystack,
-                                 const StringPiece& needles);
+size_t qfind_first_byte_of_nosse(const StringPiece haystack,
+                                 const StringPiece needles);
 
 #if FOLLY_HAVE_EMMINTRIN_H && __GNUC_PREREQ(4, 6)
-size_t qfind_first_byte_of_sse42(const StringPiece& haystack,
-                                 const StringPiece& needles);
+size_t qfind_first_byte_of_sse42(const StringPiece haystack,
+                                 const StringPiece needles);
 
-inline size_t qfind_first_byte_of(const StringPiece& haystack,
-                                  const StringPiece& needles) {
+inline size_t qfind_first_byte_of(const StringPiece haystack,
+                                  const StringPiece needles) {
   static auto const qfind_first_byte_of_fn =
     folly::CpuId().sse42() ? qfind_first_byte_of_sse42
                            : qfind_first_byte_of_nosse;
@@ -972,8 +1016,8 @@ inline size_t qfind_first_byte_of(const StringPiece& haystack,
 }
 
 #else
-inline size_t qfind_first_byte_of(const StringPiece& haystack,
-                                  const StringPiece& needles) {
+inline size_t qfind_first_byte_of(const StringPiece haystack,
+                                  const StringPiece needles) {
   return qfind_first_byte_of_nosse(haystack, needles);
 }
 #endif // FOLLY_HAVE_EMMINTRIN_H
@@ -1088,6 +1132,16 @@ inline size_t qfind_first_of(const Range<const unsigned char*>& haystack,
   return detail::qfind_first_byte_of(StringPiece(haystack),
                                      StringPiece(needles));
 }
+
+template<class Key>
+struct hasher;
+
+template <class T> struct hasher<folly::Range<T*>> {
+  size_t operator()(folly::Range<T*> r) const {
+    return hash::SpookyHashV2::Hash64(r.begin(), r.size() * sizeof(T), 0);
+  }
+};
+
 }  // !namespace folly
 
 #pragma GCC diagnostic pop