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
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
+++ /dev/null
-/*
- * 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));
-}
-
-//////////////////////////////////////////////////////////////////////
-}
#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>
follyincludedir = $(includedir)/folly
nobase_follyinclude_HEADERS = \
- ApplyTuple.h \
Arena.h \
Arena-inl.h \
Array.h \
executors/ThreadPoolExecutor.h \
executors/ThreadedExecutor.h \
executors/UnboundedBlockingQueue.h \
- executors/QueuedImmediateExecutor.h \
+ functional/ApplyTuple.h \
Demangle.h \
DiscriminatedPtr.h \
DynamicConverter.h \
--- /dev/null
+/*
+ * 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));
+}
+
+//////////////////////////////////////////////////////////////////////
+}
#pragma once
-#include <folly/ApplyTuple.h>
+#include <folly/functional/ApplyTuple.h>
namespace folly {
--- /dev/null
+/*
+ * 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;
+ })));
+}
#include <map>
#include <vector>
-#include <folly/ApplyTuple.h>
+#include <folly/functional/ApplyTuple.h>
#include <folly/gen/String.h>
#include <folly/portability/GTest.h>
+++ /dev/null
-/*
- * 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;
- })));
-}