/*
- * Copyright 2016 Facebook, Inc.
+ * 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.
* limitations under the License.
*/
+#include <array>
#include <cstdarg>
#include <folly/Function.h>
#include <folly/Memory.h>
-#include <gtest/gtest.h>
+#include <folly/portability/GTest.h>
using folly::Function;
return oldvalue;
}
};
+
+template <typename Ret, typename... Args>
+void deduceArgs(Function<Ret(Args...)>) {}
+
+struct CallableButNotCopyable {
+ CallableButNotCopyable() {}
+ CallableButNotCopyable(CallableButNotCopyable const&) = delete;
+ CallableButNotCopyable(CallableButNotCopyable&&) = delete;
+ CallableButNotCopyable& operator=(CallableButNotCopyable const&) = delete;
+ CallableButNotCopyable& operator=(CallableButNotCopyable&&) = delete;
+ template <class... Args>
+ void operator()(Args&&...) const {}
+};
+
} // namespace
+// TEST =====================================================================
+// Test constructibility and non-constructibility for some tricky conversions
+static_assert(
+ !std::is_assignable<Function<void()>, CallableButNotCopyable>::value,
+ "");
+static_assert(
+ !std::is_constructible<Function<void()>, CallableButNotCopyable&>::value,
+ "");
+static_assert(
+ !std::is_constructible<Function<void() const>, CallableButNotCopyable>::
+ value,
+ "");
+static_assert(
+ !std::is_constructible<Function<void() const>, CallableButNotCopyable&>::
+ value,
+ "");
+
+static_assert(
+ !std::is_assignable<Function<void()>, CallableButNotCopyable>::value,
+ "");
+static_assert(
+ !std::is_assignable<Function<void()>, CallableButNotCopyable&>::value,
+ "");
+static_assert(
+ !std::is_assignable<Function<void() const>, CallableButNotCopyable>::value,
+ "");
+static_assert(
+ !std::is_assignable<Function<void() const>, CallableButNotCopyable&>::value,
+ "");
+
+static_assert(
+ std::is_constructible<Function<int(int)>, Function<int(int) const>>::value,
+ "");
+static_assert(
+ !std::is_constructible<Function<int(int) const>, Function<int(int)>>::value,
+ "");
+static_assert(
+ std::is_constructible<Function<int(short)>, Function<short(int) const>>::
+ value,
+ "");
+static_assert(
+ !std::is_constructible<Function<int(short) const>, Function<short(int)>>::
+ value,
+ "");
+static_assert(
+ !std::is_constructible<Function<int(int)>, Function<int(int) const>&>::
+ value,
+ "");
+static_assert(
+ !std::is_constructible<Function<int(int) const>, Function<int(int)>&>::
+ value,
+ "");
+static_assert(
+ !std::is_constructible<Function<int(short)>, Function<short(int) const>&>::
+ value,
+ "");
+static_assert(
+ !std::is_constructible<Function<int(short) const>, Function<short(int)>&>::
+ value,
+ "");
+
+static_assert(
+ std::is_assignable<Function<int(int)>, Function<int(int) const>>::value,
+ "");
+static_assert(
+ !std::is_assignable<Function<int(int) const>, Function<int(int)>>::value,
+ "");
+static_assert(
+ std::is_assignable<Function<int(short)>, Function<short(int) const>>::value,
+ "");
+static_assert(
+ !std::is_assignable<Function<int(short) const>, Function<short(int)>>::
+ value,
+ "");
+static_assert(
+ !std::is_assignable<Function<int(int)>, Function<int(int) const>&>::value,
+ "");
+static_assert(
+ !std::is_assignable<Function<int(int) const>, Function<int(int)>&>::value,
+ "");
+static_assert(
+ !std::is_assignable<Function<int(short)>, Function<short(int) const>&>::
+ value,
+ "");
+static_assert(
+ !std::is_assignable<Function<int(short) const>, Function<short(int)>&>::
+ value,
+ "");
+
+static_assert(
+ std::is_nothrow_constructible<
+ Function<int(int)>,
+ Function<int(int) const>>::value,
+ "");
+static_assert(
+ !std::is_nothrow_constructible<
+ Function<int(short)>,
+ Function<short(int) const>>::value,
+ "");
+static_assert(
+ std::is_nothrow_assignable<Function<int(int)>, Function<int(int) const>>::
+ value,
+ "");
+static_assert(
+ !std::is_nothrow_assignable<
+ Function<int(short)>,
+ Function<short(int) const>>::value,
+ "");
+
// TEST =====================================================================
// InvokeFunctor & InvokeReference
Function<int(int)> g([](int x) { return x + 1; });
EXPECT_NE(g, nullptr);
EXPECT_NE(nullptr, g);
- EXPECT_TRUE(g);
+ // Explicitly convert to bool to work around
+ // https://github.com/google/googletest/issues/429
+ EXPECT_TRUE(bool(g));
EXPECT_EQ(100, g(99));
Function<int(int)> h(&func_int_int_add_25);
EXPECT_NE(h, nullptr);
EXPECT_NE(nullptr, h);
- EXPECT_TRUE(h);
+ EXPECT_TRUE(bool(h));
EXPECT_EQ(125, h(100));
h = {};
// NonCopyableLambda
TEST(Function, NonCopyableLambda) {
- auto unique_ptr_int = folly::make_unique<int>(900);
+ auto unique_ptr_int = std::make_unique<int>(900);
EXPECT_EQ(900, *unique_ptr_int);
- char fooData[64] = {0};
- EXPECT_EQ(0, fooData[0]); // suppress gcc warning about fooData not being used
+ struct {
+ char data[64];
+ } fooData = {{0}};
+ (void)fooData; // suppress gcc warning about fooData not being used
auto functor = std::bind(
- [fooData](std::unique_ptr<int>& up) mutable { return ++*up; },
+ [fooData](std::unique_ptr<int>& up) mutable {
+ (void)fooData;
+ return ++*up;
+ },
std::move(unique_ptr_int));
EXPECT_EQ(901, functor());
Function<size_t(void)> uf1 = std::move(lambda1);
// Max copies: 0. Max copy+moves: 2.
- EXPECT_LE(cmt.moveCount() + cmt.copyCount(), 2);
+ EXPECT_LE(cmt.moveCount() + cmt.copyCount(), 3);
EXPECT_LE(cmt.copyCount(), 0);
cmt.resetCounters();
Function<size_t(void)> uf2 = lambda2;
// Max copies: 1. Max copy+moves: 2.
- EXPECT_LE(cmt.moveCount() + cmt.copyCount(), 2);
+ EXPECT_LE(cmt.moveCount() + cmt.copyCount(), 3);
EXPECT_LE(cmt.copyCount(), 1);
// Invoking Function must not make copies/moves of the callable
EXPECT_EQ(1, i);
}
+// TEST =====================================================================
+// asSharedProxy_*
+
+TEST(Function, asSharedProxy_void) {
+ int i = 0;
+ folly::Function<void()> f = [&i] { ++i; };
+ auto sp = std::move(f).asSharedProxy();
+ auto spcopy = sp;
+ sp();
+ EXPECT_EQ(1, i);
+ spcopy();
+ EXPECT_EQ(2, i);
+}
+
+TEST(Function, asSharedProxy_void_const) {
+ int i = 0;
+ folly::Function<void() const> f = [&i] { ++i; };
+ auto sp = std::move(f).asSharedProxy();
+ auto spcopy = sp;
+ sp();
+ EXPECT_EQ(1, i);
+ spcopy();
+ EXPECT_EQ(2, i);
+}
+
+TEST(Function, asSharedProxy_return) {
+ folly::Function<int()> f = [i = 0]() mutable {
+ ++i;
+ return i;
+ };
+ auto sp = std::move(f).asSharedProxy();
+ auto spcopy = sp;
+ EXPECT_EQ(1, sp());
+ EXPECT_EQ(2, spcopy());
+}
+
+TEST(Function, asSharedProxy_return_const) {
+ int i = 0;
+ folly::Function<int() const> f = [&i] {
+ ++i;
+ return i;
+ };
+ auto sp = std::move(f).asSharedProxy();
+ auto spcopy = sp;
+ EXPECT_EQ(1, sp());
+ EXPECT_EQ(2, spcopy());
+}
+
+TEST(Function, asSharedProxy_args) {
+ int i = 0;
+ folly::Function<int(int, int)> f = [&](int x, int y) mutable {
+ ++i;
+ return x + y * 2;
+ };
+ auto sp = std::move(f).asSharedProxy();
+ auto spcopy = sp;
+ EXPECT_EQ(120, sp(100, 10));
+ EXPECT_EQ(1, i);
+ EXPECT_EQ(120, spcopy(100, 10));
+ EXPECT_EQ(2, i);
+}
+
+TEST(Function, asSharedProxy_args_const) {
+ int i = 0;
+ folly::Function<int(int, int) const> f = [&i](int x, int y) {
+ ++i;
+ return x * 100 + y * 10 + i;
+ };
+ auto sp = std::move(f).asSharedProxy();
+ auto spcopy = sp;
+ EXPECT_EQ(561, sp(5, 6));
+ EXPECT_EQ(562, spcopy(5, 6));
+}
+
TEST(Function, NoAllocatedMemoryAfterMove) {
Functor<int, 100> foo;
EXPECT_FALSE(func2);
}
-TEST(Function, SelfMoveAssign) {
- Function<int()> f = [] { return 0; };
+TEST(Function, SelfStdSwap) {
+ Function<int()> f = [] { return 42; };
+ f.swap(f);
+ EXPECT_TRUE(bool(f));
+ EXPECT_EQ(42, f());
+ std::swap(f, f);
+ EXPECT_TRUE(bool(f));
+ EXPECT_EQ(42, f());
+ folly::swap(f, f);
+ EXPECT_TRUE(bool(f));
+ EXPECT_EQ(42, f());
+}
+
+TEST(Function, SelfMove) {
+ Function<int()> f = [] { return 42; };
Function<int()>& g = f;
- f = std::move(g);
- EXPECT_TRUE(f);
+ f = std::move(g); // shouldn't crash!
+ (void)bool(f); // valid but unspecified state
+ f = [] { return 43; };
+ EXPECT_TRUE(bool(f));
+ EXPECT_EQ(43, f());
+}
+
+TEST(Function, DeducableArguments) {
+ deduceArgs(Function<void()>{[] {}});
+ deduceArgs(Function<void(int, float)>{[](int, float) {}});
+ deduceArgs(Function<int(int, float)>{[](int i, float) { return i; }});
+}
+
+TEST(Function, CtorWithCopy) {
+ struct X {
+ X() {}
+ X(X const&) noexcept(true) {}
+ X& operator=(X const&) = default;
+ };
+ struct Y {
+ Y() {}
+ Y(Y const&) noexcept(false) {}
+ Y(Y&&) noexcept(true) {}
+ Y& operator=(Y&&) = default;
+ Y& operator=(Y const&) = default;
+ };
+ auto lx = [x = X()]{};
+ auto ly = [y = Y()]{};
+ EXPECT_TRUE(noexcept(Function<void()>(lx)));
+ EXPECT_FALSE(noexcept(Function<void()>(ly)));
+}
+
+TEST(Function, Bug_T23346238) {
+ const Function<void()> nullfun;
}