Skip to content

Commit

Permalink
range(), for making Range<T*> from arrays and std::vector
Browse files Browse the repository at this point in the history
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
  • Loading branch information
ddrcoder authored and sgolemon committed Mar 18, 2014
1 parent 0016266 commit d9c79af
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 17 deletions.
25 changes: 21 additions & 4 deletions folly/Range.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,14 @@

#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
Expand Down Expand Up @@ -174,6 +174,7 @@ class Range : private boost::totally_ordered<Range<Iter> > {
// 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())) {
Expand Down Expand Up @@ -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;
Expand Down
4 changes: 2 additions & 2 deletions folly/gen/test/BaseBenchmark.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -339,6 +339,6 @@ BENCHMARK(Sample, iters) {

int main(int argc, char *argv[]) {
google::ParseCommandLineFlags(&argc, &argv, true);
runBenchmarks();
folly::runBenchmarks();
return 0;
}
6 changes: 3 additions & 3 deletions folly/gen/test/BaseTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down Expand Up @@ -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);
}

Expand Down
4 changes: 2 additions & 2 deletions folly/json.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ struct Printer {
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);
Expand Down Expand Up @@ -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;
Expand Down
4 changes: 2 additions & 2 deletions folly/test/DynamicConverterTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
Expand Down
44 changes: 40 additions & 4 deletions folly/test/RangeTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,15 @@

#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 {

Expand Down Expand Up @@ -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);
}

0 comments on commit d9c79af

Please sign in to comment.