Commit d6415c69 authored by Tom Jackson's avatar Tom Jackson Committed by woo

indirect(), for making pointers out of refs

Test Plan: Unit tests

Reviewed By: ajaymenon@fb.com

Subscribers: trunkagent, folly-diffs@

FB internal diff: D1808023

Signature: t1:1808023:1422410709:8db2d73d5b4c0c2eab563643e5fa1557ebfd4730
parent 0598f628
...@@ -1854,6 +1854,58 @@ class Dereference : public Operator<Dereference> { ...@@ -1854,6 +1854,58 @@ class Dereference : public Operator<Dereference> {
} }
}; };
/**
* Indirect - For producing a sequence of the addresses of the values in the
* input.
*
* This type is usually used through the 'indirect' static value, like:
*
* auto ptrs = from(refs) | indirect;
*/
class Indirect : public Operator<Indirect> {
public:
Indirect() {}
template <class Value,
class Source,
class Result = typename std::remove_reference<Value>::type*>
class Generator : public GenImpl<Result, Generator<Value, Source, Result>> {
Source source_;
static_assert(!std::is_rvalue_reference<Value>::value,
"Cannot use indirect on an rvalue");
public:
explicit Generator(Source source) : source_(std::move(source)) {}
template <class Body>
void foreach (Body&& body) const {
source_.foreach([&](Value value) {
return body(&value);
});
}
template <class Handler>
bool apply(Handler&& handler) const {
return source_.apply([&](Value value) -> bool {
return handler(&value);
});
}
// not actually infinite, since an empty generator will end the cycles.
static constexpr bool infinite = Source::infinite;
};
template <class Source, class Value, class Gen = Generator<Value, Source>>
Gen compose(GenImpl<Value, Source>&& source) const {
return Gen(std::move(source.self()));
}
template <class Source, class Value, class Gen = Generator<Value, Source>>
Gen compose(const GenImpl<Value, Source>& source) const {
return Gen(source.self());
}
};
} //::detail } //::detail
/** /**
...@@ -1965,6 +2017,8 @@ static const detail::Cycle cycle; ...@@ -1965,6 +2017,8 @@ static const detail::Cycle cycle;
static const detail::Dereference dereference; static const detail::Dereference dereference;
static const detail::Indirect indirect;
inline detail::Take take(size_t count) { inline detail::Take take(size_t count) {
return detail::Take(count); return detail::Take(count);
} }
......
...@@ -342,6 +342,8 @@ class Batch; ...@@ -342,6 +342,8 @@ class Batch;
class Dereference; class Dereference;
class Indirect;
/* /*
* Sinks * Sinks
*/ */
......
...@@ -124,7 +124,7 @@ TEST(Gen, Member) { ...@@ -124,7 +124,7 @@ TEST(Gen, Member) {
| sum); | sum);
EXPECT_EQ(10 * (1 + 10) / 2, EXPECT_EQ(10 * (1 + 10) / 2,
from(counters) from(counters)
| mapped([](const Counter& c) { return &c; }) | indirect
| member(&Counter::count) | member(&Counter::count)
| sum); | sum);
EXPECT_EQ(10 * (2 + 11) / 2, EXPECT_EQ(10 * (2 + 11) / 2,
...@@ -133,7 +133,7 @@ TEST(Gen, Member) { ...@@ -133,7 +133,7 @@ TEST(Gen, Member) {
| sum); | sum);
EXPECT_EQ(10 * (3 + 12) / 2, EXPECT_EQ(10 * (3 + 12) / 2,
from(counters) from(counters)
| mapped([](Counter& c) { return &c; }) | indirect
| member(&Counter::incr) | member(&Counter::incr)
| sum); | sum);
EXPECT_EQ(10 * (3 + 12) / 2, EXPECT_EQ(10 * (3 + 12) / 2,
...@@ -1010,6 +1010,11 @@ TEST(Gen, Dereference) { ...@@ -1010,6 +1010,11 @@ TEST(Gen, Dereference) {
} }
} }
TEST(Gen, Indirect) {
vector<int> vs{1};
EXPECT_EQ(&vs[0], from(vs) | indirect | first);
}
TEST(Gen, Guard) { TEST(Gen, Guard) {
using std::runtime_error; using std::runtime_error;
EXPECT_THROW(from({"1", "a", "3"}) EXPECT_THROW(from({"1", "a", "3"})
......
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