move ApplyTuple to functional/
authorJames Sedgwick <jsedgwick@fb.com>
Thu, 19 Oct 2017 14:45:51 +0000 (07:45 -0700)
committerFacebook Github Bot <facebook-github-bot@users.noreply.github.com>
Thu, 19 Oct 2017 15:02:41 +0000 (08:02 -0700)
Summary: as above

Reviewed By: yfeldblum

Differential Revision: D6086563

fbshipit-source-id: ab7f50ba46ebd1dbef6438f956258b2fbb13cb5c

CMakeLists.txt
folly/ApplyTuple.h [deleted file]
folly/Hash.h
folly/Makefile.am
folly/functional/ApplyTuple.h [new file with mode: 0644]
folly/functional/Partial.h
folly/functional/test/ApplyTupleTest.cpp [new file with mode: 0644]
folly/gen/test/StringTest.cpp
folly/test/ApplyTupleTest.cpp [deleted file]

index cdc992a..68fdc28 100755 (executable)
@@ -358,6 +358,9 @@ if (BUILD_TESTS)
     DIRECTORY fibers/test/
       TEST fibers_test SOURCES FibersTest.cpp
 
+    DIRECTORY functional/test/
+      TEST apply_tuple_test SOURCES ApplyTupleTest.cpp
+
     DIRECTORY futures/test/
       TEST barrier_test SOURCES BarrierTest.cpp
       TEST callback_lifetime_test SOURCES CallbackLifetimeTest.cpp
@@ -474,7 +477,6 @@ if (BUILD_TESTS)
 
     DIRECTORY test/
       TEST ahm_int_stress_test SOURCES AHMIntStressTest.cpp
-      TEST apply_tuple_test SOURCES ApplyTupleTest.cpp
       TEST arena_test SOURCES ArenaTest.cpp
       TEST arena_smartptr_test SOURCES ArenaSmartPtrTest.cpp
       TEST array_test SOURCES ArrayTest.cpp
diff --git a/folly/ApplyTuple.h b/folly/ApplyTuple.h
deleted file mode 100644 (file)
index cce6fec..0000000
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * Copyright 2017 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Defines a function folly::applyTuple, which takes a function and a
- * std::tuple of arguments and calls the function with those
- * arguments.
- *
- * Example:
- *
- *    int x = folly::applyTuple(std::plus<int>(), std::make_tuple(12, 12));
- *    ASSERT(x == 24);
- */
-
-#pragma once
-
-#include <functional>
-#include <tuple>
-#include <utility>
-
-#include <folly/Utility.h>
-
-namespace folly {
-
-//////////////////////////////////////////////////////////////////////
-
-namespace detail {
-namespace apply_tuple {
-
-inline constexpr std::size_t sum() {
-  return 0;
-}
-template <typename... Args>
-inline constexpr std::size_t sum(std::size_t v1, Args... vs) {
-  return v1 + sum(vs...);
-}
-
-template <typename... Tuples>
-struct TupleSizeSum {
-  static constexpr auto value = sum(std::tuple_size<Tuples>::value...);
-};
-
-template <typename... Tuples>
-using MakeIndexSequenceFromTuple = folly::make_index_sequence<
-    TupleSizeSum<typename std::decay<Tuples>::type...>::value>;
-
-// This is to allow using this with pointers to member functions,
-// where the first argument in the tuple will be the this pointer.
-template <class F>
-inline constexpr F&& makeCallable(F&& f) {
-  return std::forward<F>(f);
-}
-template <class M, class C>
-inline constexpr auto makeCallable(M(C::*d)) -> decltype(std::mem_fn(d)) {
-  return std::mem_fn(d);
-}
-
-template <class F, class Tuple, std::size_t... Indexes>
-inline constexpr auto call(F&& f, Tuple&& t, folly::index_sequence<Indexes...>)
-    -> decltype(
-        std::forward<F>(f)(std::get<Indexes>(std::forward<Tuple>(t))...)) {
-  return std::forward<F>(f)(std::get<Indexes>(std::forward<Tuple>(t))...);
-}
-
-template <class Tuple, std::size_t... Indexes>
-inline constexpr auto forwardTuple(Tuple&& t, folly::index_sequence<Indexes...>)
-    -> decltype(
-        std::forward_as_tuple(std::get<Indexes>(std::forward<Tuple>(t))...)) {
-  return std::forward_as_tuple(std::get<Indexes>(std::forward<Tuple>(t))...);
-}
-
-} // namespace apply_tuple
-} // namespace detail
-
-//////////////////////////////////////////////////////////////////////
-
-/**
- * Invoke a callable object with a set of arguments passed as a tuple, or a
- *     series of tuples
- *
- * Example: the following lines are equivalent
- *     func(1, 2, 3, "foo");
- *     applyTuple(func, std::make_tuple(1, 2, 3, "foo"));
- *     applyTuple(func, std::make_tuple(1, 2), std::make_tuple(3, "foo"));
- */
-
-template <class F, class... Tuples>
-inline constexpr auto applyTuple(F&& f, Tuples&&... t)
-    -> decltype(detail::apply_tuple::call(
-        detail::apply_tuple::makeCallable(std::forward<F>(f)),
-        std::tuple_cat(detail::apply_tuple::forwardTuple(
-            std::forward<Tuples>(t),
-            detail::apply_tuple::MakeIndexSequenceFromTuple<Tuples>{})...),
-        detail::apply_tuple::MakeIndexSequenceFromTuple<Tuples...>{})) {
-  return detail::apply_tuple::call(
-      detail::apply_tuple::makeCallable(std::forward<F>(f)),
-      std::tuple_cat(detail::apply_tuple::forwardTuple(
-          std::forward<Tuples>(t),
-          detail::apply_tuple::MakeIndexSequenceFromTuple<Tuples>{})...),
-      detail::apply_tuple::MakeIndexSequenceFromTuple<Tuples...>{});
-}
-
-namespace detail {
-namespace apply_tuple {
-
-template <class F>
-class Uncurry {
- public:
-  explicit Uncurry(F&& func) : func_(std::move(func)) {}
-  explicit Uncurry(const F& func) : func_(func) {}
-
-  template <class Tuple>
-  auto operator()(Tuple&& tuple) const
-      -> decltype(applyTuple(std::declval<F>(), std::forward<Tuple>(tuple))) {
-    return applyTuple(func_, std::forward<Tuple>(tuple));
-  }
-
- private:
-  F func_;
-};
-} // namespace apply_tuple
-} // namespace detail
-
-/**
- * Wraps a function taking N arguments into a function which accepts a tuple of
- * N arguments. Note: This function will also accept an std::pair if N == 2.
- *
- * For example, given the below code:
- *
- *    std::vector<std::tuple<int, int, int>> rows = ...;
- *    auto test = [](std::tuple<int, int, int>& row) {
- *      return std::get<0>(row) * std::get<1>(row) * std::get<2>(row) == 24;
- *    };
- *    auto found = std::find_if(rows.begin(), rows.end(), test);
- *
- *
- * 'test' could be rewritten as:
- *
- *    auto test =
- *        folly::uncurry([](int a, int b, int c) { return a * b * c == 24; });
- *
- */
-template <class F>
-auto uncurry(F&& f)
-    -> detail::apply_tuple::Uncurry<typename std::decay<F>::type> {
-  return detail::apply_tuple::Uncurry<typename std::decay<F>::type>(
-      std::forward<F>(f));
-}
-
-//////////////////////////////////////////////////////////////////////
-}
index 410d272..5253975 100644 (file)
@@ -24,8 +24,8 @@
 #include <type_traits>
 #include <utility>
 
-#include <folly/ApplyTuple.h>
 #include <folly/Bits.h>
+#include <folly/functional/ApplyTuple.h>
 #include <folly/hash/SpookyHashV1.h>
 #include <folly/hash/SpookyHashV2.h>
 
index ce29ac0..0b48eab 100644 (file)
@@ -27,7 +27,6 @@ lib_LTLIBRARIES = \
 follyincludedir = $(includedir)/folly
 
 nobase_follyinclude_HEADERS = \
-       ApplyTuple.h \
        Arena.h \
        Arena-inl.h \
        Array.h \
@@ -106,7 +105,7 @@ nobase_follyinclude_HEADERS = \
        executors/ThreadPoolExecutor.h \
        executors/ThreadedExecutor.h \
        executors/UnboundedBlockingQueue.h \
-       executors/QueuedImmediateExecutor.h \
+       functional/ApplyTuple.h \
        Demangle.h \
        DiscriminatedPtr.h \
        DynamicConverter.h \
diff --git a/folly/functional/ApplyTuple.h b/folly/functional/ApplyTuple.h
new file mode 100644 (file)
index 0000000..cce6fec
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * Copyright 2017 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Defines a function folly::applyTuple, which takes a function and a
+ * std::tuple of arguments and calls the function with those
+ * arguments.
+ *
+ * Example:
+ *
+ *    int x = folly::applyTuple(std::plus<int>(), std::make_tuple(12, 12));
+ *    ASSERT(x == 24);
+ */
+
+#pragma once
+
+#include <functional>
+#include <tuple>
+#include <utility>
+
+#include <folly/Utility.h>
+
+namespace folly {
+
+//////////////////////////////////////////////////////////////////////
+
+namespace detail {
+namespace apply_tuple {
+
+inline constexpr std::size_t sum() {
+  return 0;
+}
+template <typename... Args>
+inline constexpr std::size_t sum(std::size_t v1, Args... vs) {
+  return v1 + sum(vs...);
+}
+
+template <typename... Tuples>
+struct TupleSizeSum {
+  static constexpr auto value = sum(std::tuple_size<Tuples>::value...);
+};
+
+template <typename... Tuples>
+using MakeIndexSequenceFromTuple = folly::make_index_sequence<
+    TupleSizeSum<typename std::decay<Tuples>::type...>::value>;
+
+// This is to allow using this with pointers to member functions,
+// where the first argument in the tuple will be the this pointer.
+template <class F>
+inline constexpr F&& makeCallable(F&& f) {
+  return std::forward<F>(f);
+}
+template <class M, class C>
+inline constexpr auto makeCallable(M(C::*d)) -> decltype(std::mem_fn(d)) {
+  return std::mem_fn(d);
+}
+
+template <class F, class Tuple, std::size_t... Indexes>
+inline constexpr auto call(F&& f, Tuple&& t, folly::index_sequence<Indexes...>)
+    -> decltype(
+        std::forward<F>(f)(std::get<Indexes>(std::forward<Tuple>(t))...)) {
+  return std::forward<F>(f)(std::get<Indexes>(std::forward<Tuple>(t))...);
+}
+
+template <class Tuple, std::size_t... Indexes>
+inline constexpr auto forwardTuple(Tuple&& t, folly::index_sequence<Indexes...>)
+    -> decltype(
+        std::forward_as_tuple(std::get<Indexes>(std::forward<Tuple>(t))...)) {
+  return std::forward_as_tuple(std::get<Indexes>(std::forward<Tuple>(t))...);
+}
+
+} // namespace apply_tuple
+} // namespace detail
+
+//////////////////////////////////////////////////////////////////////
+
+/**
+ * Invoke a callable object with a set of arguments passed as a tuple, or a
+ *     series of tuples
+ *
+ * Example: the following lines are equivalent
+ *     func(1, 2, 3, "foo");
+ *     applyTuple(func, std::make_tuple(1, 2, 3, "foo"));
+ *     applyTuple(func, std::make_tuple(1, 2), std::make_tuple(3, "foo"));
+ */
+
+template <class F, class... Tuples>
+inline constexpr auto applyTuple(F&& f, Tuples&&... t)
+    -> decltype(detail::apply_tuple::call(
+        detail::apply_tuple::makeCallable(std::forward<F>(f)),
+        std::tuple_cat(detail::apply_tuple::forwardTuple(
+            std::forward<Tuples>(t),
+            detail::apply_tuple::MakeIndexSequenceFromTuple<Tuples>{})...),
+        detail::apply_tuple::MakeIndexSequenceFromTuple<Tuples...>{})) {
+  return detail::apply_tuple::call(
+      detail::apply_tuple::makeCallable(std::forward<F>(f)),
+      std::tuple_cat(detail::apply_tuple::forwardTuple(
+          std::forward<Tuples>(t),
+          detail::apply_tuple::MakeIndexSequenceFromTuple<Tuples>{})...),
+      detail::apply_tuple::MakeIndexSequenceFromTuple<Tuples...>{});
+}
+
+namespace detail {
+namespace apply_tuple {
+
+template <class F>
+class Uncurry {
+ public:
+  explicit Uncurry(F&& func) : func_(std::move(func)) {}
+  explicit Uncurry(const F& func) : func_(func) {}
+
+  template <class Tuple>
+  auto operator()(Tuple&& tuple) const
+      -> decltype(applyTuple(std::declval<F>(), std::forward<Tuple>(tuple))) {
+    return applyTuple(func_, std::forward<Tuple>(tuple));
+  }
+
+ private:
+  F func_;
+};
+} // namespace apply_tuple
+} // namespace detail
+
+/**
+ * Wraps a function taking N arguments into a function which accepts a tuple of
+ * N arguments. Note: This function will also accept an std::pair if N == 2.
+ *
+ * For example, given the below code:
+ *
+ *    std::vector<std::tuple<int, int, int>> rows = ...;
+ *    auto test = [](std::tuple<int, int, int>& row) {
+ *      return std::get<0>(row) * std::get<1>(row) * std::get<2>(row) == 24;
+ *    };
+ *    auto found = std::find_if(rows.begin(), rows.end(), test);
+ *
+ *
+ * 'test' could be rewritten as:
+ *
+ *    auto test =
+ *        folly::uncurry([](int a, int b, int c) { return a * b * c == 24; });
+ *
+ */
+template <class F>
+auto uncurry(F&& f)
+    -> detail::apply_tuple::Uncurry<typename std::decay<F>::type> {
+  return detail::apply_tuple::Uncurry<typename std::decay<F>::type>(
+      std::forward<F>(f));
+}
+
+//////////////////////////////////////////////////////////////////////
+}
index b391452..650a394 100644 (file)
@@ -16,7 +16,7 @@
 
 #pragma once
 
-#include <folly/ApplyTuple.h>
+#include <folly/functional/ApplyTuple.h>
 
 namespace folly {
 
diff --git a/folly/functional/test/ApplyTupleTest.cpp b/folly/functional/test/ApplyTupleTest.cpp
new file mode 100644 (file)
index 0000000..e661e47
--- /dev/null
@@ -0,0 +1,373 @@
+/*
+ * Copyright 2017 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <iostream>
+
+#include <folly/functional/ApplyTuple.h>
+#include <folly/portability/GTest.h>
+
+#include <array>
+#include <memory>
+
+// this placates visual studio stupidity - see
+// http://stackoverflow.com/questions/5503901
+namespace {}
+
+namespace {
+
+void func(int a, int b, double c) {
+  EXPECT_EQ(a, 1);
+  EXPECT_EQ(b, 2);
+  EXPECT_EQ(c, 3.0);
+}
+
+struct Wat {
+  void func(int a, int b, double c) {
+    ::func(a, b, c);
+  }
+
+  double retVal(int a, double b) {
+    return a + b;
+  }
+
+  Wat() {}
+  Wat(Wat const&) = delete;
+
+  int foo;
+};
+
+struct Overloaded {
+  int func(int) { return 0; }
+  bool func(bool) { return true; }
+};
+
+struct Func {
+  int operator()() const {
+    return 1;
+  }
+};
+
+struct CopyCount {
+  CopyCount() {}
+  CopyCount(CopyCount const&) {
+    std::cout << "copy count copy ctor\n";
+  }
+};
+
+void anotherFunc(CopyCount const&) {}
+
+std::function<void (int, int, double)> makeFunc() {
+  return &func;
+}
+
+struct GuardObjBase {
+  GuardObjBase(GuardObjBase&&) noexcept {}
+  GuardObjBase() {}
+  GuardObjBase(GuardObjBase const&) = delete;
+  GuardObjBase& operator=(GuardObjBase const&) = delete;
+};
+typedef GuardObjBase const& Guard;
+
+template <class F, class Tuple>
+struct GuardObj : GuardObjBase {
+  explicit GuardObj(F&& f, Tuple&& args)
+    : f_(std::forward<F>(f))
+    , args_(std::forward<Tuple>(args))
+  {}
+  GuardObj(GuardObj&& g) noexcept
+    : GuardObjBase(std::move(g))
+    , f_(std::move(g.f_))
+    , args_(std::move(g.args_))
+  {}
+
+  ~GuardObj() {
+    folly::applyTuple(f_, args_);
+  }
+
+  GuardObj(const GuardObj&) = delete;
+  GuardObj& operator=(const GuardObj&) = delete;
+
+ private:
+  F f_;
+  Tuple args_;
+};
+
+template <class F, class... Args>
+GuardObj<typename std::decay<F>::type,std::tuple<Args...>>
+guard(F&& f, Args&&... args) {
+  return GuardObj<typename std::decay<F>::type,std::tuple<Args...>>(
+    std::forward<F>(f),
+    std::tuple<Args...>(std::forward<Args>(args)...)
+  );
+}
+
+struct Mover {
+  Mover() {}
+  Mover(Mover&&) noexcept {}
+  Mover(const Mover&) = delete;
+  Mover& operator=(const Mover&) = delete;
+};
+
+void move_only_func(Mover&&) {}
+
+}
+
+TEST(ApplyTuple, Test) {
+  auto argsTuple = std::make_tuple(1, 2, 3.0);
+  auto func2 = func;
+  folly::applyTuple(func2, argsTuple);
+  folly::applyTuple(func, argsTuple);
+  folly::applyTuple(func, std::make_tuple(1, 2, 3.0));
+  folly::applyTuple(makeFunc(), std::make_tuple(1, 2, 3.0));
+  folly::applyTuple(makeFunc(), argsTuple);
+
+  std::unique_ptr<Wat> wat(new Wat);
+  folly::applyTuple(&Wat::func, std::make_tuple(wat.get(), 1, 2, 3.0));
+  auto argsTuple2 = std::make_tuple(wat.get(), 1, 2, 3.0);
+  folly::applyTuple(&Wat::func, argsTuple2);
+
+  EXPECT_EQ(10.0,
+            folly::applyTuple(&Wat::retVal,
+                              std::make_tuple(wat.get(), 1, 9.0)));
+
+  auto test = guard(func, 1, 2, 3.0);
+  CopyCount cpy;
+  auto test2 = guard(anotherFunc, cpy);
+  auto test3 = guard(anotherFunc, std::cref(cpy));
+
+  Overloaded ovl;
+  EXPECT_EQ(0,
+            folly::applyTuple(
+              static_cast<int (Overloaded::*)(int)>(&Overloaded::func),
+              std::make_tuple(&ovl, 12)));
+  EXPECT_EQ(
+      /* do not code-mode to EXPECT_TRUE */ true,
+      folly::applyTuple(
+          static_cast<bool (Overloaded::*)(bool)>(&Overloaded::func),
+          std::make_tuple(&ovl, false)));
+
+  int x = folly::applyTuple(std::plus<int>(), std::make_tuple(12, 12));
+  EXPECT_EQ(24, x);
+
+  Mover m;
+  folly::applyTuple(move_only_func,
+                    std::forward_as_tuple(std::forward<Mover>(Mover())));
+  const auto tuple3 = std::make_tuple(1, 2, 3.0);
+  folly::applyTuple(func, tuple3);
+}
+
+TEST(ApplyTuple, Mutable) {
+  auto argsTuple = std::make_tuple(1, 2, 3.0);
+
+  folly::applyTuple([](int a, int b, double c) mutable { func(a, b, c); },
+                    argsTuple);
+}
+
+TEST(ApplyTuple, ConstOverloads) {
+  struct ConstOverloaded {
+    ConstOverloaded() {}
+    int operator()() { return 101; }
+    int operator()() const { return 102; }
+  };
+
+  ConstOverloaded covl;
+
+  // call operator()()
+  EXPECT_EQ(folly::applyTuple(covl, std::make_tuple()), 101);
+  EXPECT_EQ(folly::applyTuple(std::ref(covl), std::make_tuple()), 101);
+  EXPECT_EQ(folly::applyTuple(std::move(covl), std::make_tuple()), 101);
+
+  // call operator()() const
+  EXPECT_EQ(folly::applyTuple(const_cast<ConstOverloaded const&>(covl),
+                              std::make_tuple()),
+            102);
+  EXPECT_EQ(folly::applyTuple(std::cref(covl), std::make_tuple()), 102);
+}
+
+TEST(ApplyTuple, RefOverloads) {
+  struct RefOverloaded {
+    RefOverloaded() {}
+    int operator()() & { return 201; }
+    int operator()() const & { return 202; }
+    int operator()() && { return 203; }
+  };
+
+  RefOverloaded rovl;
+
+  // call operator()() &
+  EXPECT_EQ(folly::applyTuple(rovl, std::make_tuple()), 201);
+  EXPECT_EQ(folly::applyTuple(std::ref(rovl), std::make_tuple()), 201);
+
+  // call operator()() const &
+  EXPECT_EQ(folly::applyTuple(const_cast<RefOverloaded const&>(rovl),
+                              std::make_tuple()),
+            202);
+  EXPECT_EQ(folly::applyTuple(std::cref(rovl), std::make_tuple()), 202);
+
+  // call operator()() &&
+  EXPECT_EQ(folly::applyTuple(std::move(rovl), std::make_tuple()), 203);
+}
+
+struct MemberFunc {
+  int x;
+  int getX() const { return x; }
+  void setX(int xx) { x = xx; }
+};
+
+TEST(ApplyTuple, MemberFunction) {
+  MemberFunc mf;
+  mf.x = 123;
+
+  // call getter
+  EXPECT_EQ(folly::applyTuple(&MemberFunc::getX, std::make_tuple(&mf)), 123);
+
+  // call setter
+  folly::applyTuple(&MemberFunc::setX, std::make_tuple(&mf, 234));
+  EXPECT_EQ(mf.x, 234);
+  EXPECT_EQ(folly::applyTuple(&MemberFunc::getX, std::make_tuple(&mf)), 234);
+}
+
+TEST(ApplyTuple, MemberFunctionWithRefWrapper) {
+  MemberFunc mf;
+  mf.x = 234;
+
+  EXPECT_EQ(folly::applyTuple(&MemberFunc::getX, std::make_tuple(std::ref(mf))),
+            234);
+}
+
+TEST(ApplyTuple, MemberFunctionWithConstPointer) {
+  MemberFunc mf;
+  mf.x = 234;
+
+  EXPECT_EQ(
+      folly::applyTuple(&MemberFunc::getX,
+                        std::make_tuple(const_cast<MemberFunc const*>(&mf))),
+      234);
+}
+
+TEST(ApplyTuple, MemberFunctionWithSharedPtr) {
+  MemberFunc mf;
+  mf.x = 234;
+
+  EXPECT_EQ(
+      folly::applyTuple(&MemberFunc::getX,
+                        std::make_tuple(std::make_shared<MemberFunc>(mf))),
+      234);
+}
+
+TEST(ApplyTuple, MemberFunctionWithUniquePtr) {
+  MemberFunc mf;
+  mf.x = 234;
+
+  EXPECT_EQ(folly::applyTuple(&MemberFunc::getX,
+                              std::make_tuple(std::unique_ptr<MemberFunc>(
+                                  new MemberFunc(mf)))),
+            234);
+}
+
+TEST(ApplyTuple, Array) {
+  folly::applyTuple(func, std::array<int, 3>{{1, 2, 3}});
+  folly::applyTuple(func, std::array<double, 3>{{1, 2, 3}});
+}
+
+TEST(ApplyTuple, Pair) {
+  auto add = [](int x, int y) { return x + y; };
+
+  EXPECT_EQ(folly::applyTuple(add, std::pair<int, int>{1200, 34}), 1234);
+}
+
+TEST(ApplyTuple, MultipleTuples) {
+  auto add = [](int x, int y, int z) { return x * 100 + y * 10 + z; };
+
+  EXPECT_EQ(123, folly::applyTuple(add, std::make_tuple(1, 2, 3)));
+  EXPECT_EQ(
+      123, folly::applyTuple(add, std::make_tuple(1, 2, 3), std::make_tuple()));
+  EXPECT_EQ(
+      123, folly::applyTuple(add, std::make_tuple(1, 2), std::make_tuple(3)));
+  EXPECT_EQ(
+      123, folly::applyTuple(add, std::make_tuple(1), std::make_tuple(2, 3)));
+  EXPECT_EQ(
+      123, folly::applyTuple(add, std::make_tuple(), std::make_tuple(1, 2, 3)));
+
+  EXPECT_EQ(
+      123,
+      folly::applyTuple(
+          add, std::make_tuple(1, 2, 3), std::make_tuple(), std::make_tuple()));
+  EXPECT_EQ(
+      123,
+      folly::applyTuple(
+          add, std::make_tuple(1), std::make_tuple(2), std::make_tuple(3)));
+  EXPECT_EQ(
+      123,
+      folly::applyTuple(
+          add, std::make_tuple(1), std::make_tuple(), std::make_tuple(2, 3)));
+}
+
+TEST(ApplyTuple, UncurryCopyMove) {
+  std::string separator = "================================\n";
+  auto formatRow = folly::uncurry([=](std::string a, std::string b) {
+    // capture separator by copy
+    return separator + a + "\n" + b + "\n" + separator;
+  });
+  auto row = std::make_tuple("hello", "world");
+  auto expected = separator + "hello\nworld\n" + separator;
+  EXPECT_EQ(expected, formatRow(row));
+  auto formatRowCopy = formatRow;
+  EXPECT_EQ(expected, formatRowCopy(row));
+  auto formatRowMove = std::move(formatRow);
+  EXPECT_EQ(expected, formatRowMove(row));
+
+  // capture value moved out from formatRow
+  EXPECT_NE(expected, formatRow(row));
+}
+
+TEST(ApplyTuple, Uncurry) {
+  EXPECT_EQ(42, folly::uncurry([](int x, int y) {
+              return x * y;
+            })(std::pair<int, int>(6, 7)));
+  EXPECT_EQ(42, folly::uncurry([](int&& x, int&& y) {
+              return x * y;
+            })(std::pair<int&&, int&&>(6, 7)));
+  EXPECT_EQ(42, folly::uncurry([](int&& x, int&& y) {
+              return x * y;
+            })(std::pair<int&&, int&&>(6, 7)));
+
+  std::string long1 = "a long string exceeding small string size";
+  std::string long2 = "and here is another one!";
+  std::string expected = long1 + long2;
+
+  auto cat = folly::uncurry(
+      [](std::string a, std::string b) { return std::move(a) + std::move(b); });
+
+  EXPECT_EQ(expected, cat(std::make_pair(long1, long2)));
+  EXPECT_FALSE(long1.empty());
+  EXPECT_FALSE(long2.empty());
+  EXPECT_EQ(expected, cat(std::tie(long1, long2)));
+  EXPECT_FALSE(long1.empty());
+  EXPECT_FALSE(long2.empty());
+  EXPECT_EQ(
+      expected, cat(std::forward_as_tuple(std::move(long1), std::move(long2))));
+  EXPECT_TRUE(long1.empty());
+  EXPECT_TRUE(long2.empty());
+}
+
+TEST(ApplyTuple, UncurryStdFind) {
+  std::vector<std::pair<int, int>> v{{1, 9}, {2, 8}, {3, 7}, {4, 6}, {5, 5}};
+  EXPECT_EQ(
+      3, std::count_if(v.begin(), v.end(), folly::uncurry([](int a, int b) {
+                         return b % a == 0;
+                       })));
+}
index 47d76d2..8db23cc 100644 (file)
@@ -18,7 +18,7 @@
 #include <map>
 #include <vector>
 
-#include <folly/ApplyTuple.h>
+#include <folly/functional/ApplyTuple.h>
 #include <folly/gen/String.h>
 #include <folly/portability/GTest.h>
 
diff --git a/folly/test/ApplyTupleTest.cpp b/folly/test/ApplyTupleTest.cpp
deleted file mode 100644 (file)
index a09f807..0000000
+++ /dev/null
@@ -1,373 +0,0 @@
-/*
- * Copyright 2017 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <iostream>
-
-#include <folly/ApplyTuple.h>
-#include <folly/portability/GTest.h>
-
-#include <array>
-#include <memory>
-
-// this placates visual studio stupidity - see
-// http://stackoverflow.com/questions/5503901
-namespace {}
-
-namespace {
-
-void func(int a, int b, double c) {
-  EXPECT_EQ(a, 1);
-  EXPECT_EQ(b, 2);
-  EXPECT_EQ(c, 3.0);
-}
-
-struct Wat {
-  void func(int a, int b, double c) {
-    ::func(a, b, c);
-  }
-
-  double retVal(int a, double b) {
-    return a + b;
-  }
-
-  Wat() {}
-  Wat(Wat const&) = delete;
-
-  int foo;
-};
-
-struct Overloaded {
-  int func(int) { return 0; }
-  bool func(bool) { return true; }
-};
-
-struct Func {
-  int operator()() const {
-    return 1;
-  }
-};
-
-struct CopyCount {
-  CopyCount() {}
-  CopyCount(CopyCount const&) {
-    std::cout << "copy count copy ctor\n";
-  }
-};
-
-void anotherFunc(CopyCount const&) {}
-
-std::function<void (int, int, double)> makeFunc() {
-  return &func;
-}
-
-struct GuardObjBase {
-  GuardObjBase(GuardObjBase&&) noexcept {}
-  GuardObjBase() {}
-  GuardObjBase(GuardObjBase const&) = delete;
-  GuardObjBase& operator=(GuardObjBase const&) = delete;
-};
-typedef GuardObjBase const& Guard;
-
-template <class F, class Tuple>
-struct GuardObj : GuardObjBase {
-  explicit GuardObj(F&& f, Tuple&& args)
-    : f_(std::forward<F>(f))
-    , args_(std::forward<Tuple>(args))
-  {}
-  GuardObj(GuardObj&& g) noexcept
-    : GuardObjBase(std::move(g))
-    , f_(std::move(g.f_))
-    , args_(std::move(g.args_))
-  {}
-
-  ~GuardObj() {
-    folly::applyTuple(f_, args_);
-  }
-
-  GuardObj(const GuardObj&) = delete;
-  GuardObj& operator=(const GuardObj&) = delete;
-
- private:
-  F f_;
-  Tuple args_;
-};
-
-template <class F, class... Args>
-GuardObj<typename std::decay<F>::type,std::tuple<Args...>>
-guard(F&& f, Args&&... args) {
-  return GuardObj<typename std::decay<F>::type,std::tuple<Args...>>(
-    std::forward<F>(f),
-    std::tuple<Args...>(std::forward<Args>(args)...)
-  );
-}
-
-struct Mover {
-  Mover() {}
-  Mover(Mover&&) noexcept {}
-  Mover(const Mover&) = delete;
-  Mover& operator=(const Mover&) = delete;
-};
-
-void move_only_func(Mover&&) {}
-
-}
-
-TEST(ApplyTuple, Test) {
-  auto argsTuple = std::make_tuple(1, 2, 3.0);
-  auto func2 = func;
-  folly::applyTuple(func2, argsTuple);
-  folly::applyTuple(func, argsTuple);
-  folly::applyTuple(func, std::make_tuple(1, 2, 3.0));
-  folly::applyTuple(makeFunc(), std::make_tuple(1, 2, 3.0));
-  folly::applyTuple(makeFunc(), argsTuple);
-
-  std::unique_ptr<Wat> wat(new Wat);
-  folly::applyTuple(&Wat::func, std::make_tuple(wat.get(), 1, 2, 3.0));
-  auto argsTuple2 = std::make_tuple(wat.get(), 1, 2, 3.0);
-  folly::applyTuple(&Wat::func, argsTuple2);
-
-  EXPECT_EQ(10.0,
-            folly::applyTuple(&Wat::retVal,
-                              std::make_tuple(wat.get(), 1, 9.0)));
-
-  auto test = guard(func, 1, 2, 3.0);
-  CopyCount cpy;
-  auto test2 = guard(anotherFunc, cpy);
-  auto test3 = guard(anotherFunc, std::cref(cpy));
-
-  Overloaded ovl;
-  EXPECT_EQ(0,
-            folly::applyTuple(
-              static_cast<int (Overloaded::*)(int)>(&Overloaded::func),
-              std::make_tuple(&ovl, 12)));
-  EXPECT_EQ(
-      /* do not code-mode to EXPECT_TRUE */ true,
-      folly::applyTuple(
-          static_cast<bool (Overloaded::*)(bool)>(&Overloaded::func),
-          std::make_tuple(&ovl, false)));
-
-  int x = folly::applyTuple(std::plus<int>(), std::make_tuple(12, 12));
-  EXPECT_EQ(24, x);
-
-  Mover m;
-  folly::applyTuple(move_only_func,
-                    std::forward_as_tuple(std::forward<Mover>(Mover())));
-  const auto tuple3 = std::make_tuple(1, 2, 3.0);
-  folly::applyTuple(func, tuple3);
-}
-
-TEST(ApplyTuple, Mutable) {
-  auto argsTuple = std::make_tuple(1, 2, 3.0);
-
-  folly::applyTuple([](int a, int b, double c) mutable { func(a, b, c); },
-                    argsTuple);
-}
-
-TEST(ApplyTuple, ConstOverloads) {
-  struct ConstOverloaded {
-    ConstOverloaded() {}
-    int operator()() { return 101; }
-    int operator()() const { return 102; }
-  };
-
-  ConstOverloaded covl;
-
-  // call operator()()
-  EXPECT_EQ(folly::applyTuple(covl, std::make_tuple()), 101);
-  EXPECT_EQ(folly::applyTuple(std::ref(covl), std::make_tuple()), 101);
-  EXPECT_EQ(folly::applyTuple(std::move(covl), std::make_tuple()), 101);
-
-  // call operator()() const
-  EXPECT_EQ(folly::applyTuple(const_cast<ConstOverloaded const&>(covl),
-                              std::make_tuple()),
-            102);
-  EXPECT_EQ(folly::applyTuple(std::cref(covl), std::make_tuple()), 102);
-}
-
-TEST(ApplyTuple, RefOverloads) {
-  struct RefOverloaded {
-    RefOverloaded() {}
-    int operator()() & { return 201; }
-    int operator()() const & { return 202; }
-    int operator()() && { return 203; }
-  };
-
-  RefOverloaded rovl;
-
-  // call operator()() &
-  EXPECT_EQ(folly::applyTuple(rovl, std::make_tuple()), 201);
-  EXPECT_EQ(folly::applyTuple(std::ref(rovl), std::make_tuple()), 201);
-
-  // call operator()() const &
-  EXPECT_EQ(folly::applyTuple(const_cast<RefOverloaded const&>(rovl),
-                              std::make_tuple()),
-            202);
-  EXPECT_EQ(folly::applyTuple(std::cref(rovl), std::make_tuple()), 202);
-
-  // call operator()() &&
-  EXPECT_EQ(folly::applyTuple(std::move(rovl), std::make_tuple()), 203);
-}
-
-struct MemberFunc {
-  int x;
-  int getX() const { return x; }
-  void setX(int xx) { x = xx; }
-};
-
-TEST(ApplyTuple, MemberFunction) {
-  MemberFunc mf;
-  mf.x = 123;
-
-  // call getter
-  EXPECT_EQ(folly::applyTuple(&MemberFunc::getX, std::make_tuple(&mf)), 123);
-
-  // call setter
-  folly::applyTuple(&MemberFunc::setX, std::make_tuple(&mf, 234));
-  EXPECT_EQ(mf.x, 234);
-  EXPECT_EQ(folly::applyTuple(&MemberFunc::getX, std::make_tuple(&mf)), 234);
-}
-
-TEST(ApplyTuple, MemberFunctionWithRefWrapper) {
-  MemberFunc mf;
-  mf.x = 234;
-
-  EXPECT_EQ(folly::applyTuple(&MemberFunc::getX, std::make_tuple(std::ref(mf))),
-            234);
-}
-
-TEST(ApplyTuple, MemberFunctionWithConstPointer) {
-  MemberFunc mf;
-  mf.x = 234;
-
-  EXPECT_EQ(
-      folly::applyTuple(&MemberFunc::getX,
-                        std::make_tuple(const_cast<MemberFunc const*>(&mf))),
-      234);
-}
-
-TEST(ApplyTuple, MemberFunctionWithSharedPtr) {
-  MemberFunc mf;
-  mf.x = 234;
-
-  EXPECT_EQ(
-      folly::applyTuple(&MemberFunc::getX,
-                        std::make_tuple(std::make_shared<MemberFunc>(mf))),
-      234);
-}
-
-TEST(ApplyTuple, MemberFunctionWithUniquePtr) {
-  MemberFunc mf;
-  mf.x = 234;
-
-  EXPECT_EQ(folly::applyTuple(&MemberFunc::getX,
-                              std::make_tuple(std::unique_ptr<MemberFunc>(
-                                  new MemberFunc(mf)))),
-            234);
-}
-
-TEST(ApplyTuple, Array) {
-  folly::applyTuple(func, std::array<int, 3>{{1, 2, 3}});
-  folly::applyTuple(func, std::array<double, 3>{{1, 2, 3}});
-}
-
-TEST(ApplyTuple, Pair) {
-  auto add = [](int x, int y) { return x + y; };
-
-  EXPECT_EQ(folly::applyTuple(add, std::pair<int, int>{1200, 34}), 1234);
-}
-
-TEST(ApplyTuple, MultipleTuples) {
-  auto add = [](int x, int y, int z) { return x * 100 + y * 10 + z; };
-
-  EXPECT_EQ(123, folly::applyTuple(add, std::make_tuple(1, 2, 3)));
-  EXPECT_EQ(
-      123, folly::applyTuple(add, std::make_tuple(1, 2, 3), std::make_tuple()));
-  EXPECT_EQ(
-      123, folly::applyTuple(add, std::make_tuple(1, 2), std::make_tuple(3)));
-  EXPECT_EQ(
-      123, folly::applyTuple(add, std::make_tuple(1), std::make_tuple(2, 3)));
-  EXPECT_EQ(
-      123, folly::applyTuple(add, std::make_tuple(), std::make_tuple(1, 2, 3)));
-
-  EXPECT_EQ(
-      123,
-      folly::applyTuple(
-          add, std::make_tuple(1, 2, 3), std::make_tuple(), std::make_tuple()));
-  EXPECT_EQ(
-      123,
-      folly::applyTuple(
-          add, std::make_tuple(1), std::make_tuple(2), std::make_tuple(3)));
-  EXPECT_EQ(
-      123,
-      folly::applyTuple(
-          add, std::make_tuple(1), std::make_tuple(), std::make_tuple(2, 3)));
-}
-
-TEST(ApplyTuple, UncurryCopyMove) {
-  std::string separator = "================================\n";
-  auto formatRow = folly::uncurry([=](std::string a, std::string b) {
-    // capture separator by copy
-    return separator + a + "\n" + b + "\n" + separator;
-  });
-  auto row = std::make_tuple("hello", "world");
-  auto expected = separator + "hello\nworld\n" + separator;
-  EXPECT_EQ(expected, formatRow(row));
-  auto formatRowCopy = formatRow;
-  EXPECT_EQ(expected, formatRowCopy(row));
-  auto formatRowMove = std::move(formatRow);
-  EXPECT_EQ(expected, formatRowMove(row));
-
-  // capture value moved out from formatRow
-  EXPECT_NE(expected, formatRow(row));
-}
-
-TEST(ApplyTuple, Uncurry) {
-  EXPECT_EQ(42, folly::uncurry([](int x, int y) {
-              return x * y;
-            })(std::pair<int, int>(6, 7)));
-  EXPECT_EQ(42, folly::uncurry([](int&& x, int&& y) {
-              return x * y;
-            })(std::pair<int&&, int&&>(6, 7)));
-  EXPECT_EQ(42, folly::uncurry([](int&& x, int&& y) {
-              return x * y;
-            })(std::pair<int&&, int&&>(6, 7)));
-
-  std::string long1 = "a long string exceeding small string size";
-  std::string long2 = "and here is another one!";
-  std::string expected = long1 + long2;
-
-  auto cat = folly::uncurry(
-      [](std::string a, std::string b) { return std::move(a) + std::move(b); });
-
-  EXPECT_EQ(expected, cat(std::make_pair(long1, long2)));
-  EXPECT_FALSE(long1.empty());
-  EXPECT_FALSE(long2.empty());
-  EXPECT_EQ(expected, cat(std::tie(long1, long2)));
-  EXPECT_FALSE(long1.empty());
-  EXPECT_FALSE(long2.empty());
-  EXPECT_EQ(
-      expected, cat(std::forward_as_tuple(std::move(long1), std::move(long2))));
-  EXPECT_TRUE(long1.empty());
-  EXPECT_TRUE(long2.empty());
-}
-
-TEST(ApplyTuple, UncurryStdFind) {
-  std::vector<std::pair<int, int>> v{{1, 9}, {2, 8}, {3, 7}, {4, 6}, {5, 5}};
-  EXPECT_EQ(
-      3, std::count_if(v.begin(), v.end(), folly::uncurry([](int a, int b) {
-                         return b % a == 0;
-                       })));
-}