Better support for folly::Range with non-const iterators underneath
authorTudor Bosman <tudorb@fb.com>
Thu, 20 Feb 2014 21:20:00 +0000 (13:20 -0800)
committerDave Watson <davejwatson@fb.com>
Fri, 21 Feb 2014 21:40:49 +0000 (13:40 -0800)
Summary:
Implicitly construct Range<To> from Range<From> if From is implicitly
convertible to To.

Explicitly construct Range<To> from Range<From> if To is (explicitly)
constructible from From.

Add special-cases for Range<char*>, Range<unsigned char*> similar to the
ones for Range<const char*>, Range<const unsigned char*>.

Test Plan: test added

Reviewed By: philipp@fb.com

FB internal diff: D1182999

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

index f692b75a04db51acf9c49f2e60aaac56d0e7266f..e4d42a4dc6bba634249b9115ae48fff7a702f642 100644 (file)
@@ -240,20 +240,59 @@ public:
   // direction.
   template <class OtherIter, typename std::enable_if<
       (std::is_same<Iter, const unsigned char*>::value &&
   // 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())) {
   }
 
   /* 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 &&
   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())) {
   }
 
   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();
   void clear() {
     b_ = Iter();
     e_ = Iter();
@@ -616,7 +655,9 @@ Range<Iter> makeRange(Iter first, Iter last) {
 }
 
 typedef Range<const char*> StringPiece;
 }
 
 typedef Range<const char*> StringPiece;
+typedef Range<char*> MutableStringPiece;
 typedef Range<const unsigned char*> ByteRange;
 typedef Range<const unsigned char*> ByteRange;
+typedef Range<unsigned char*> MutableByteRange;
 
 std::ostream& operator<<(std::ostream& os, const StringPiece& piece);
 
 
 std::ostream& operator<<(std::ostream& os, const StringPiece& piece);
 
index ee6a0e1bc86989641c427236d9449b1c9272fe5c..faec886660dc15748403aaf86644ceefef7fa7fe 100644 (file)
@@ -908,3 +908,17 @@ TYPED_TEST(NeedleFinderTest, NoSegFault) {
   }
 }
 
   }
 }
 
+TEST(NonConstTest, StringPiece) {
+  std::string hello("hello");
+  MutableStringPiece sp(&hello.front(), hello.size());
+  sp[0] = 'x';
+  EXPECT_EQ("xello", hello);
+  {
+    StringPiece s(sp);
+    EXPECT_EQ("xello", s);
+  }
+  {
+    ByteRange r1(sp);
+    MutableByteRange r2(sp);
+  }
+}