range(), for making Range<T*> from arrays and std::vector
authorTom Jackson <tjackson@fb.com>
Wed, 12 Mar 2014 23:31:41 +0000 (16:31 -0700)
committerSara Golemon <sgolemon@fb.com>
Tue, 18 Mar 2014 21:14:22 +0000 (14:14 -0700)
Summary: So people can more easily write functions which take contiguous values from memory.

Test Plan: Unit tests

Reviewed By: tudorb@fb.com

FB internal diff: D1217809

folly/Range.h
folly/gen/test/BaseBenchmark.cpp
folly/gen/test/BaseTest.cpp
folly/json.cpp
folly/test/DynamicConverterTest.cpp
folly/test/RangeTest.cpp

index e4d42a4dc6bba634249b9115ae48fff7a702f642..b4e76deeaef14a784b80bcdeafaf225f9ccf4222 100644 (file)
 
 #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
@@ -174,6 +174,7 @@ public:
   // 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())) {
@@ -650,10 +651,26 @@ void swap(Range<T>& lhs, Range<T>& rhs) {
  * 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;
index 26009743fceee9c2641cd2bed8a10cc7517d5034..a7b095af880b419cca61a2a67c9a140afe61ab3c 100644 (file)
@@ -19,8 +19,8 @@
 #include "folly/Benchmark.h"
 #include "folly/gen/Base.h"
 
-using namespace folly;
 using namespace folly::gen;
+using folly::fbstring;
 using std::pair;
 using std::set;
 using std::vector;
@@ -339,6 +339,6 @@ BENCHMARK(Sample, iters) {
 
 int main(int argc, char *argv[]) {
   google::ParseCommandLineFlags(&argc, &argv, true);
-  runBenchmarks();
+  folly::runBenchmarks();
   return 0;
 }
index 3a0b500ca93e2eb3b6073f437a83e1a151d42f5d..6f58e732a49c03c911621a8ab56041e425d4e32e 100644 (file)
@@ -189,13 +189,13 @@ TEST(Gen, Seq) {
 TEST(Gen, Range) {
   // cover the fenceposts of the loop unrolling
   for (int n = 1; n < 100; ++n) {
-    EXPECT_EQ(range(0, n) | count, n);
+    EXPECT_EQ(gen::range(0, n) | count, n);
   }
 }
 
 TEST(Gen, FromIterators) {
   vector<int> source {2, 3, 5, 7, 11};
-  auto gen = from(makeRange(source.begin() + 1, source.end() - 1));
+  auto gen = from(folly::range(source.begin() + 1, source.end() - 1));
   EXPECT_EQ(3 * 5 * 7, gen | product);
 }
 
@@ -618,7 +618,7 @@ TEST(Gen, Any) {
   EXPECT_FALSE(seq(0, 10) | any([](int i) { return i == 11; }));
 
   EXPECT_TRUE(from({1}) | any);
-  EXPECT_FALSE(range(0, 0) | any);
+  EXPECT_FALSE(gen::range(0, 0) | any);
   EXPECT_FALSE(from({1}) | take(0) | any);
 }
 
index 24ce2b298f982fb19b7e5d3a360065d1bd3988b6..5ca57d475b31b5249370d033ff27e5a2c2ae8f1f 100644 (file)
@@ -216,7 +216,7 @@ private:
     indent();
     newline();
     (*this)(a[0]);
-    for (auto& val : makeRange(boost::next(a.begin()), a.end())) {
+    for (auto& val : range(boost::next(a.begin()), a.end())) {
       out_ += ',';
       newline();
       (*this)(val);
@@ -509,7 +509,7 @@ dynamic parseNumber(Input& in) {
     auto expPart = in.skipDigits();
     end = expPart.end();
   }
-  auto fullNum = makeRange(integral.begin(), end);
+  auto fullNum = range(integral.begin(), end);
 
   auto val = to<double>(fullNum);
   return val;
index 59d9006c7d12d5e68a9df866483c4faf657d6462..4a8648aa707d98bd2565de27b8ed698e041e19f7 100644 (file)
@@ -341,8 +341,8 @@ TEST(DynamicConverter, construct) {
 
   {
     vector<int> vi { 2, 3, 4, 5 };
-    auto c = std::make_pair(makeRange(vi.begin(), vi.begin() + 3),
-                            makeRange(vi.begin() + 1, vi.begin() + 4));
+    auto c = std::make_pair(range(vi.begin(), vi.begin() + 3),
+                            range(vi.begin() + 1, vi.begin() + 4));
     dynamic d = { { 2, 3, 4 }, { 3, 4, 5 } };
     EXPECT_EQ(d, toDynamic(c));
   }
index faec886660dc15748403aaf86644ceefef7fa7fe..e9a56b2c07cbc49871ed34644655f649d0274d40 100644 (file)
 
 #include "folly/Range.h"
 
-#include <limits>
+#include <array>
+#include <boost/range/concepts.hpp>
 #include <cstdlib>
-#include <string>
+#include <gtest/gtest.h>
 #include <iterator>
+#include <limits>
+#include <string>
 #include <sys/mman.h>
-#include <boost/range/concepts.hpp>
-#include <gtest/gtest.h>
+#include <vector>
 
 namespace folly { namespace detail {
 
@@ -922,3 +924,37 @@ TEST(NonConstTest, StringPiece) {
     MutableByteRange r2(sp);
   }
 }
+
+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));
+  Range<const int*> r2 = range(std::forward<C>(x));
+  Range<const int*> r3 = range(cx);
+  Range<const int*> r5 = range(std::move(cx));
+  EXPECT_EQ(r1.begin(), &x[0]);
+  EXPECT_EQ(r1.end(), &x[n]);
+  EXPECT_EQ(n, r1.size());
+  EXPECT_EQ(n, r2.size());
+  EXPECT_EQ(n, r3.size());
+  EXPECT_EQ(n, r5.size());
+}
+
+TEST(RangeFunc, Vector) {
+  std::vector<int> x;
+  testRangeFunc(x, 0);
+  x.push_back(2);
+  testRangeFunc(x, 1);
+  testRangeFunc(std::vector<int>{1, 2}, 2);
+}
+
+TEST(RangeFunc, Array) {
+  std::array<int, 3> x;
+  testRangeFunc(x, 3);
+}
+
+TEST(RangeFunc, CArray) {
+  int x[] {1, 2, 3, 4};
+  testRangeFunc(x, 4);
+}