X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=folly%2Ftest%2FFunctionTest.cpp;h=34217a2c825d028e318ed940cdfb5cfd61920dc2;hb=b71a1b76b3dd7d63bc1d27ed292ddb604fdd9388;hp=7c5159c9ae0873f28ac1b8e5dd209fefbbb435a6;hpb=5022d5469d551c2a62d367792da9453392c464fa;p=folly.git diff --git a/folly/test/FunctionTest.cpp b/folly/test/FunctionTest.cpp index 7c5159c9..34217a2c 100644 --- a/folly/test/FunctionTest.cpp +++ b/folly/test/FunctionTest.cpp @@ -1,5 +1,5 @@ /* - * 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. @@ -14,12 +14,13 @@ * limitations under the License. */ +#include #include #include #include -#include +#include using folly::Function; @@ -49,8 +50,131 @@ struct Functor { return oldvalue; } }; + +template +void deduceArgs(Function) {} + +struct CallableButNotCopyable { + CallableButNotCopyable() {} + CallableButNotCopyable(CallableButNotCopyable const&) = delete; + CallableButNotCopyable(CallableButNotCopyable&&) = delete; + CallableButNotCopyable& operator=(CallableButNotCopyable const&) = delete; + CallableButNotCopyable& operator=(CallableButNotCopyable&&) = delete; + template + void operator()(Args&&...) const {} +}; + } // namespace +// TEST ===================================================================== +// Test constructibility and non-constructibility for some tricky conversions +static_assert( + !std::is_assignable, CallableButNotCopyable>::value, + ""); +static_assert( + !std::is_constructible, CallableButNotCopyable&>::value, + ""); +static_assert( + !std::is_constructible, CallableButNotCopyable>:: + value, + ""); +static_assert( + !std::is_constructible, CallableButNotCopyable&>:: + value, + ""); + +static_assert( + !std::is_assignable, CallableButNotCopyable>::value, + ""); +static_assert( + !std::is_assignable, CallableButNotCopyable&>::value, + ""); +static_assert( + !std::is_assignable, CallableButNotCopyable>::value, + ""); +static_assert( + !std::is_assignable, CallableButNotCopyable&>::value, + ""); + +static_assert( + std::is_constructible, Function>::value, + ""); +static_assert( + !std::is_constructible, Function>::value, + ""); +static_assert( + std::is_constructible, Function>:: + value, + ""); +static_assert( + !std::is_constructible, Function>:: + value, + ""); +static_assert( + !std::is_constructible, Function&>:: + value, + ""); +static_assert( + !std::is_constructible, Function&>:: + value, + ""); +static_assert( + !std::is_constructible, Function&>:: + value, + ""); +static_assert( + !std::is_constructible, Function&>:: + value, + ""); + +static_assert( + std::is_assignable, Function>::value, + ""); +static_assert( + !std::is_assignable, Function>::value, + ""); +static_assert( + std::is_assignable, Function>::value, + ""); +static_assert( + !std::is_assignable, Function>:: + value, + ""); +static_assert( + !std::is_assignable, Function&>::value, + ""); +static_assert( + !std::is_assignable, Function&>::value, + ""); +static_assert( + !std::is_assignable, Function&>:: + value, + ""); +static_assert( + !std::is_assignable, Function&>:: + value, + ""); + +static_assert( + std::is_nothrow_constructible< + Function, + Function>::value, + ""); +static_assert( + !std::is_nothrow_constructible< + Function, + Function>::value, + ""); +static_assert( + std::is_nothrow_assignable, Function>:: + value, + ""); +static_assert( + !std::is_nothrow_assignable< + Function, + Function>::value, + ""); + // TEST ===================================================================== // InvokeFunctor & InvokeReference @@ -96,13 +220,15 @@ TEST(Function, Emptiness_T) { Function 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 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 = {}; @@ -187,14 +313,19 @@ TEST(Function, Bind) { // NonCopyableLambda TEST(Function, NonCopyableLambda) { - auto unique_ptr_int = folly::make_unique(900); + auto unique_ptr_int = std::make_unique(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& up) mutable { return ++*up; }, + [fooData](std::unique_ptr& up) mutable { + (void)fooData; + return ++*up; + }, std::move(unique_ptr_int)); EXPECT_EQ(901, functor()); @@ -453,7 +584,7 @@ TEST(Function, CaptureCopyMoveCount) { Function 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(); @@ -465,7 +596,7 @@ TEST(Function, CaptureCopyMoveCount) { Function 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 @@ -813,6 +944,80 @@ TEST(Function, asStdFunction_args_const) { EXPECT_EQ(1, i); } +// TEST ===================================================================== +// asSharedProxy_* + +TEST(Function, asSharedProxy_void) { + int i = 0; + folly::Function 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 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 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 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 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 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 foo; @@ -843,9 +1048,54 @@ TEST(Function, EmptyAfterConstCast) { EXPECT_FALSE(func2); } -TEST(Function, SelfMoveAssign) { - Function f = [] { return 0; }; +TEST(Function, SelfStdSwap) { + Function 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 f = [] { return 42; }; Function& 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{[] {}}); + deduceArgs(Function{[](int, float) {}}); + deduceArgs(Function{[](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(lx))); + EXPECT_FALSE(noexcept(Function(ly))); +} + +TEST(Function, Bug_T23346238) { + const Function nullfun; }