Commit d9c79af8 authored by Tom Jackson's avatar Tom Jackson Committed by Sara Golemon

range(), for making Range<T*> from arrays and std::vector

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
parent 00162667
...@@ -22,14 +22,14 @@ ...@@ -22,14 +22,14 @@
#include "folly/Portability.h" #include "folly/Portability.h"
#include "folly/FBString.h" #include "folly/FBString.h"
#include <glog/logging.h>
#include <algorithm> #include <algorithm>
#include <boost/operators.hpp>
#include <cstring> #include <cstring>
#include <glog/logging.h>
#include <iosfwd> #include <iosfwd>
#include <string>
#include <stdexcept> #include <stdexcept>
#include <string>
#include <type_traits> #include <type_traits>
#include <boost/operators.hpp>
// libc++ doesn't provide this header // libc++ doesn't provide this header
#if !FOLLY_USE_LIBCPP #if !FOLLY_USE_LIBCPP
...@@ -174,6 +174,7 @@ public: ...@@ -174,6 +174,7 @@ public:
// Works only for Range<const char*> // Works only for Range<const char*>
/* implicit */ Range(const std::string& str) /* implicit */ Range(const std::string& str)
: b_(str.data()), e_(b_ + str.size()) {} : b_(str.data()), e_(b_ + str.size()) {}
// Works only for Range<const char*> // Works only for Range<const char*>
Range(const std::string& str, std::string::size_type startFrom) { Range(const std::string& str, std::string::size_type startFrom) {
if (UNLIKELY(startFrom > str.size())) { if (UNLIKELY(startFrom > str.size())) {
...@@ -650,10 +651,26 @@ void swap(Range<T>& lhs, Range<T>& rhs) { ...@@ -650,10 +651,26 @@ void swap(Range<T>& lhs, Range<T>& rhs) {
* Create a range from two iterators, with type deduction. * Create a range from two iterators, with type deduction.
*/ */
template <class Iter> template <class Iter>
Range<Iter> makeRange(Iter first, Iter last) { Range<Iter> range(Iter first, Iter last) {
return Range<Iter>(first, 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<const char*> StringPiece;
typedef Range<char*> MutableStringPiece; typedef Range<char*> MutableStringPiece;
typedef Range<const unsigned char*> ByteRange; typedef Range<const unsigned char*> ByteRange;
......
...@@ -19,8 +19,8 @@ ...@@ -19,8 +19,8 @@
#include "folly/Benchmark.h" #include "folly/Benchmark.h"
#include "folly/gen/Base.h" #include "folly/gen/Base.h"
using namespace folly;
using namespace folly::gen; using namespace folly::gen;
using folly::fbstring;
using std::pair; using std::pair;
using std::set; using std::set;
using std::vector; using std::vector;
...@@ -339,6 +339,6 @@ BENCHMARK(Sample, iters) { ...@@ -339,6 +339,6 @@ BENCHMARK(Sample, iters) {
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
google::ParseCommandLineFlags(&argc, &argv, true); google::ParseCommandLineFlags(&argc, &argv, true);
runBenchmarks(); folly::runBenchmarks();
return 0; return 0;
} }
...@@ -189,13 +189,13 @@ TEST(Gen, Seq) { ...@@ -189,13 +189,13 @@ TEST(Gen, Seq) {
TEST(Gen, Range) { TEST(Gen, Range) {
// cover the fenceposts of the loop unrolling // cover the fenceposts of the loop unrolling
for (int n = 1; n < 100; ++n) { 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) { TEST(Gen, FromIterators) {
vector<int> source {2, 3, 5, 7, 11}; 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); EXPECT_EQ(3 * 5 * 7, gen | product);
} }
...@@ -618,7 +618,7 @@ TEST(Gen, Any) { ...@@ -618,7 +618,7 @@ TEST(Gen, Any) {
EXPECT_FALSE(seq(0, 10) | any([](int i) { return i == 11; })); EXPECT_FALSE(seq(0, 10) | any([](int i) { return i == 11; }));
EXPECT_TRUE(from({1}) | any); 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); EXPECT_FALSE(from({1}) | take(0) | any);
} }
......
...@@ -216,7 +216,7 @@ private: ...@@ -216,7 +216,7 @@ private:
indent(); indent();
newline(); newline();
(*this)(a[0]); (*this)(a[0]);
for (auto& val : makeRange(boost::next(a.begin()), a.end())) { for (auto& val : range(boost::next(a.begin()), a.end())) {
out_ += ','; out_ += ',';
newline(); newline();
(*this)(val); (*this)(val);
...@@ -509,7 +509,7 @@ dynamic parseNumber(Input& in) { ...@@ -509,7 +509,7 @@ dynamic parseNumber(Input& in) {
auto expPart = in.skipDigits(); auto expPart = in.skipDigits();
end = expPart.end(); end = expPart.end();
} }
auto fullNum = makeRange(integral.begin(), end); auto fullNum = range(integral.begin(), end);
auto val = to<double>(fullNum); auto val = to<double>(fullNum);
return val; return val;
......
...@@ -341,8 +341,8 @@ TEST(DynamicConverter, construct) { ...@@ -341,8 +341,8 @@ TEST(DynamicConverter, construct) {
{ {
vector<int> vi { 2, 3, 4, 5 }; vector<int> vi { 2, 3, 4, 5 };
auto c = std::make_pair(makeRange(vi.begin(), vi.begin() + 3), auto c = std::make_pair(range(vi.begin(), vi.begin() + 3),
makeRange(vi.begin() + 1, vi.begin() + 4)); range(vi.begin() + 1, vi.begin() + 4));
dynamic d = { { 2, 3, 4 }, { 3, 4, 5 } }; dynamic d = { { 2, 3, 4 }, { 3, 4, 5 } };
EXPECT_EQ(d, toDynamic(c)); EXPECT_EQ(d, toDynamic(c));
} }
......
...@@ -19,13 +19,15 @@ ...@@ -19,13 +19,15 @@
#include "folly/Range.h" #include "folly/Range.h"
#include <limits> #include <array>
#include <boost/range/concepts.hpp>
#include <cstdlib> #include <cstdlib>
#include <string> #include <gtest/gtest.h>
#include <iterator> #include <iterator>
#include <limits>
#include <string>
#include <sys/mman.h> #include <sys/mman.h>
#include <boost/range/concepts.hpp> #include <vector>
#include <gtest/gtest.h>
namespace folly { namespace detail { namespace folly { namespace detail {
...@@ -922,3 +924,37 @@ TEST(NonConstTest, StringPiece) { ...@@ -922,3 +924,37 @@ TEST(NonConstTest, StringPiece) {
MutableByteRange r2(sp); 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);
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment