Making 'just()' reference arguments like 'from()' (fixed)
authorTom Jackson <tjackson@fb.com>
Wed, 11 Feb 2015 23:42:11 +0000 (15:42 -0800)
committerSara Golemon <sgolemon@fb.com>
Thu, 12 Feb 2015 16:55:08 +0000 (08:55 -0800)
Summary: That is, for all inputs except r-values. Now with support for GCC.

Test Plan: Run tests

Reviewed By: ajaymenon@fb.com

Subscribers: moharrami, trunkagent, folly-diffs@, yfeldblum

FB internal diff: D1822339

Signature: t1:1822339:1423683482:027871549d69017a7a23a675025851a0b876ad77

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

index 083cf979b0f030051e75a2e72e49893bb0bfab26..d4b68ebf68cf703550438149fe2b461406cc323b 100644 (file)
@@ -328,13 +328,32 @@ class Empty : public GenImpl<Value, Empty<Value>> {
   void foreach(Body&&) const {}
 };
 
-template<class Value>
-class Just : public GenImpl<const Value&, Just<Value>> {
+template <class Value>
+class SingleReference : public GenImpl<Value&, SingleReference<Value>> {
+  static_assert(!std::is_reference<Value>::value,
+                "SingleReference requires non-ref types");
+  Value* ptr_;
+ public:
+  explicit SingleReference(Value& ref) : ptr_(&ref) {}
+
+  template <class Handler>
+  bool apply(Handler&& handler) const {
+    return handler(*ptr_);
+  }
+
+  template <class Body>
+  void foreach(Body&& body) const {
+    body(*ptr_);
+  }
+};
+
+template <class Value>
+class SingleCopy : public GenImpl<const Value&, SingleCopy<Value>> {
   static_assert(!std::is_reference<Value>::value,
-                "Just requires non-ref types");
-  const Value value_;
+                "SingleCopy requires non-ref types");
+  Value value_;
  public:
-  explicit Just(Value value) : value_(std::forward<Value>(value)) {}
+  explicit SingleCopy(Value value) : value_(std::forward<Value>(value)) {}
 
   template <class Handler>
   bool apply(Handler&& handler) const {
index 12d917edac6a3bed58f9907f2f056fdc4fd39d11..6b96097be1cfa79aef4558e825499450c7ad7651 100644 (file)
@@ -297,7 +297,10 @@ template<class Value>
 class Empty;
 
 template<class Value>
-class Just;
+class SingleReference;
+
+template<class Value>
+class SingleCopy;
 
 /*
  * Operators
@@ -482,14 +485,19 @@ Yield generator(Source&& source) {
 /*
  * empty() - for producing empty sequences.
  */
-template<class Value>
+template <class Value>
 detail::Empty<Value> empty() {
   return {};
 }
 
-template<class Value>
-detail::Just<Value> just(Value value) {
-  return detail::Just<Value>(std::move(value));
+template <
+    class Value,
+    class Just = typename std::conditional<
+        std::is_reference<Value>::value,
+        detail::SingleReference<typename std::remove_reference<Value>::type>,
+        detail::SingleCopy<Value>>::type>
+Just just(Value&& value) {
+  return Just(std::forward<Value>(value));
 }
 
 /*
index 666acb16d1e356c6a192ce177bb2af899cb6d931..06f1af012edc4dcadee6f49e082161221b34be76 100644 (file)
@@ -136,7 +136,7 @@ class Sub : public Operator<Sub<Sink>> {
             class Source,
             class Result =
                 decltype(std::declval<Sink>().compose(std::declval<Source>())),
-            class Just = Just<typename std::decay<Result>::type>>
+            class Just = SingleCopy<typename std::decay<Result>::type>>
   Just compose(const GenImpl<Value, Source>& source) const {
     return Just(source | sink_);
   }
index 2b99f15704c293f07b9f5b30fca30f2a919804cc..33b39bf5d5fe53939ad942fc31dbd5c633b8a6f0 100644 (file)
@@ -1073,6 +1073,31 @@ TEST(Gen, BatchMove) {
   EXPECT_EQ(expected, actual);
 }
 
+TEST(Gen, Just) {
+  {
+    int x = 3;
+    auto j = just(x);
+    EXPECT_EQ(&x, j | indirect | first);
+    x = 4;
+    EXPECT_EQ(4, j | first);
+  }
+  {
+    int x = 3;
+    const int& cx = x;
+    auto j = just(cx);
+    EXPECT_EQ(&x, j | indirect | first);
+    x = 5;
+    EXPECT_EQ(5, j | first);
+  }
+  {
+    int x = 3;
+    auto j = just(std::move(x));
+    EXPECT_NE(&x, j | indirect | first);
+    x = 5;
+    EXPECT_EQ(3, j | first);
+  }
+}
+
 int main(int argc, char *argv[]) {
   testing::InitGoogleTest(&argc, argv);
   gflags::ParseCommandLineFlags(&argc, &argv, true);