crange, and range const overloads
authorYedidya Feldblum <yfeldblum@fb.com>
Tue, 7 Nov 2017 01:29:12 +0000 (17:29 -0800)
committerFacebook Github Bot <facebook-github-bot@users.noreply.github.com>
Tue, 7 Nov 2017 01:37:57 +0000 (17:37 -0800)
Summary:
[Folly] `crange`, and `range` `const` overloads.

Instead of using universal reference for `range` overloads, bifurcate explicitly between `&` and `const&` overloads. The `&` overloads return `Range<T*>` while the `const&` overloads return `Range<T const*>`.

Add `crange` overloads, which may accept non-`const` arguments but will return `Range<T const*>` results anyway.

Reviewed By: ot

Differential Revision: D6242038

fbshipit-source-id: bc373c3288ea88792f04b49a372262d12204b586

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

index 6a8161d..228a8d5 100644 (file)
@@ -1012,22 +1012,43 @@ constexpr Range<Iter> range(Iter first, Iter 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>
-constexpr Range<T*> range(Collection&& v) {
-  return Range<T*>(v.data(), v.data() + v.size());
+template <class Collection>
+constexpr auto range(Collection& v) -> Range<decltype(v.data())> {
+  return Range<decltype(v.data())>(v.data(), v.data() + v.size());
+}
+template <class Collection>
+constexpr auto range(Collection const& v) -> Range<decltype(v.data())> {
+  return Range<decltype(v.data())>(v.data(), v.data() + v.size());
+}
+template <class Collection>
+constexpr auto crange(Collection const& v) -> Range<decltype(v.data())> {
+  return Range<decltype(v.data())>(v.data(), v.data() + v.size());
 }
 
 template <class T, size_t n>
 constexpr Range<T*> range(T (&array)[n]) {
   return Range<T*>(array, array + n);
 }
+template <class T, size_t n>
+constexpr Range<T const*> range(T const (&array)[n]) {
+  return Range<T const*>(array, array + n);
+}
+template <class T, size_t n>
+constexpr Range<T const*> crange(T const (&array)[n]) {
+  return Range<T const*>(array, array + n);
+}
 
 template <class T, size_t n>
-constexpr Range<const T*> range(const std::array<T, n>& array) {
-  return Range<const T*>{array};
+constexpr Range<T*> range(std::array<T, n>& array) {
+  return Range<T*>{array};
+}
+template <class T, size_t n>
+constexpr Range<T const*> range(std::array<T, n> const& array) {
+  return Range<T const*>{array};
+}
+template <class T, size_t n>
+constexpr Range<T const*> crange(std::array<T, n> const& array) {
+  return Range<T const*>{array};
 }
 
 typedef Range<const char*> StringPiece;
index db8b60e..dbe8d88 100644 (file)
@@ -30,6 +30,7 @@
 #include <boost/algorithm/string/trim.hpp>
 #include <boost/range/concepts.hpp>
 
+#include <folly/portability/GMock.h>
 #include <folly/portability/GTest.h>
 #include <folly/portability/Memory.h>
 #include <folly/portability/SysMman.h>
@@ -1091,7 +1092,9 @@ template <class C>
 void testRangeFunc(C&& x, size_t n) {
   const auto& cx = x;
   // type, conversion checks
-  Range<int*> r1 = range(std::forward<C>(x));
+  using R1Iter =
+      _t<std::conditional<_t<std::is_reference<C>>::value, int*, int const*>>;
+  Range<R1Iter> r1 = range(std::forward<C>(x));
   Range<const int*> r2 = range(std::forward<C>(x));
   Range<const int*> r3 = range(cx);
   Range<const int*> r5 = range(std::move(cx));
@@ -1177,6 +1180,57 @@ TEST(RangeFunc, ConstexprCollection) {
   EXPECT_EQ(2, numCollRangeSize);
 }
 
+TEST(CRangeFunc, CArray) {
+  int numArray[4] = {3, 17, 1, 9};
+  auto const numArrayRange = crange(numArray);
+  EXPECT_TRUE(
+      (std::is_same<int const*, decltype(numArrayRange)::iterator>::value));
+  EXPECT_THAT(numArrayRange, testing::ElementsAreArray(numArray));
+}
+
+TEST(CRangeFunc, StdArray) {
+  std::array<int, 4> numArray = {{3, 17, 1, 9}};
+  auto const numArrayRange = crange(numArray);
+  EXPECT_TRUE(
+      (std::is_same<int const*, decltype(numArrayRange)::iterator>::value));
+  EXPECT_THAT(numArrayRange, testing::ElementsAreArray(numArray));
+}
+
+TEST(CRangeFunc, StdArrayZero) {
+  std::array<int, 0> numArray = {};
+  auto const numArrayRange = crange(numArray);
+  EXPECT_TRUE(
+      (std::is_same<int const*, decltype(numArrayRange)::iterator>::value));
+  EXPECT_THAT(numArrayRange, testing::ElementsAreArray(numArray));
+}
+
+TEST(CRangeFunc, Collection) {
+  class IntCollection {
+   public:
+    constexpr IntCollection(int* d, size_t s) : data_(d), size_(s) {}
+    constexpr int* data() {
+      return data_;
+    }
+    constexpr int const* data() const {
+      return data_;
+    }
+    constexpr size_t size() const {
+      return size_;
+    }
+
+   private:
+    int* data_;
+    size_t size_;
+  };
+  int numArray[4] = {3, 17, 1, 9};
+  auto numPtr = static_cast<int*>(numArray);
+  auto numColl = IntCollection(numPtr + 1, 2);
+  auto const numCollRange = crange(numColl);
+  EXPECT_TRUE(
+      (std::is_same<int const*, decltype(numCollRange)::iterator>::value));
+  EXPECT_THAT(numCollRange, testing::ElementsAreArray({17, 1}));
+}
+
 std::string get_rand_str(
     size_t size,
     std::uniform_int_distribution<>& dist,