indirect(), for making pointers out of refs
authorTom Jackson <tjackson@fb.com>
Thu, 29 Jan 2015 18:22:59 +0000 (10:22 -0800)
committerwoo <woo@fb.com>
Mon, 2 Feb 2015 21:14:18 +0000 (13:14 -0800)
Test Plan: Unit tests

Reviewed By: ajaymenon@fb.com

Subscribers: trunkagent, folly-diffs@

FB internal diff: D1808023

Signature: t1:1808023:1422410709:8db2d73d5b4c0c2eab563643e5fa1557ebfd4730

folly/gen/Base-inl.h
folly/gen/Base.h
folly/gen/test/BaseTest.cpp

index faaa92ac6d4040cc82f434bb2e2d251d7ae0087e..083cf979b0f030051e75a2e72e49893bb0bfab26 100644 (file)
@@ -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
 
 /**
@@ -1965,6 +2017,8 @@ static const detail::Cycle cycle;
 
 static const detail::Dereference dereference;
 
+static const detail::Indirect indirect;
+
 inline detail::Take take(size_t count) {
   return detail::Take(count);
 }
index bbae117a505ddb822d442e4cfb96e079b90a96b7..12d917edac6a3bed58f9907f2f056fdc4fd39d11 100644 (file)
@@ -342,6 +342,8 @@ class Batch;
 
 class Dereference;
 
+class Indirect;
+
 /*
  * Sinks
  */
index 2ff11c83eb7feb580692108027c5d2d316abe76a..2b99f15704c293f07b9f5b30fca30f2a919804cc 100644 (file)
@@ -124,7 +124,7 @@ TEST(Gen, Member) {
           | sum);
   EXPECT_EQ(10 * (1 + 10) / 2,
             from(counters)
-          | mapped([](const Counter& c) { return &c; })
+          | indirect
           | member(&Counter::count)
           | sum);
   EXPECT_EQ(10 * (2 + 11) / 2,
@@ -133,7 +133,7 @@ TEST(Gen, Member) {
           | sum);
   EXPECT_EQ(10 * (3 + 12) / 2,
             from(counters)
-          | mapped([](Counter& c) { return &c; })
+          | indirect
           | member(&Counter::incr)
           | sum);
   EXPECT_EQ(10 * (3 + 12) / 2,
@@ -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) {
   using std::runtime_error;
   EXPECT_THROW(from({"1", "a", "3"})