Home | History | Annotate | Download | only in ADT
      1 //===- FunctionExtrasTest.cpp - Unit tests for function type erasure ------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 
     10 #include "llvm/ADT/FunctionExtras.h"
     11 #include "gtest/gtest.h"
     12 
     13 #include <memory>
     14 
     15 using namespace llvm;
     16 
     17 namespace {
     18 
     19 TEST(UniqueFunctionTest, Basic) {
     20   unique_function<int(int, int)> Sum = [](int A, int B) { return A + B; };
     21   EXPECT_EQ(Sum(1, 2), 3);
     22 
     23   unique_function<int(int, int)> Sum2 = std::move(Sum);
     24   EXPECT_EQ(Sum2(1, 2), 3);
     25 
     26   unique_function<int(int, int)> Sum3 = [](int A, int B) { return A + B; };
     27   Sum2 = std::move(Sum3);
     28   EXPECT_EQ(Sum2(1, 2), 3);
     29 
     30   Sum2 = unique_function<int(int, int)>([](int A, int B) { return A + B; });
     31   EXPECT_EQ(Sum2(1, 2), 3);
     32 
     33   // Explicit self-move test.
     34   *&Sum2 = std::move(Sum2);
     35   EXPECT_EQ(Sum2(1, 2), 3);
     36 
     37   Sum2 = unique_function<int(int, int)>();
     38   EXPECT_FALSE(Sum2);
     39 
     40   // Make sure we can forward through l-value reference parameters.
     41   unique_function<void(int &)> Inc = [](int &X) { ++X; };
     42   int X = 42;
     43   Inc(X);
     44   EXPECT_EQ(X, 43);
     45 
     46   // Make sure we can forward through r-value reference parameters with
     47   // move-only types.
     48   unique_function<int(std::unique_ptr<int> &&)> ReadAndDeallocByRef =
     49       [](std::unique_ptr<int> &&Ptr) {
     50         int V = *Ptr;
     51         Ptr.reset();
     52         return V;
     53       };
     54   std::unique_ptr<int> Ptr{new int(13)};
     55   EXPECT_EQ(ReadAndDeallocByRef(std::move(Ptr)), 13);
     56   EXPECT_FALSE((bool)Ptr);
     57 
     58   // Make sure we can pass a move-only temporary as opposed to a local variable.
     59   EXPECT_EQ(ReadAndDeallocByRef(std::unique_ptr<int>(new int(42))), 42);
     60 
     61   // Make sure we can pass a move-only type by-value.
     62   unique_function<int(std::unique_ptr<int>)> ReadAndDeallocByVal =
     63       [](std::unique_ptr<int> Ptr) {
     64         int V = *Ptr;
     65         Ptr.reset();
     66         return V;
     67       };
     68   Ptr.reset(new int(13));
     69   EXPECT_EQ(ReadAndDeallocByVal(std::move(Ptr)), 13);
     70   EXPECT_FALSE((bool)Ptr);
     71 
     72   EXPECT_EQ(ReadAndDeallocByVal(std::unique_ptr<int>(new int(42))), 42);
     73 }
     74 
     75 TEST(UniqueFunctionTest, Captures) {
     76   long A = 1, B = 2, C = 3, D = 4, E = 5;
     77 
     78   unique_function<long()> Tmp;
     79 
     80   unique_function<long()> C1 = [A]() { return A; };
     81   EXPECT_EQ(C1(), 1);
     82   Tmp = std::move(C1);
     83   EXPECT_EQ(Tmp(), 1);
     84 
     85   unique_function<long()> C2 = [A, B]() { return A + B; };
     86   EXPECT_EQ(C2(), 3);
     87   Tmp = std::move(C2);
     88   EXPECT_EQ(Tmp(), 3);
     89 
     90   unique_function<long()> C3 = [A, B, C]() { return A + B + C; };
     91   EXPECT_EQ(C3(), 6);
     92   Tmp = std::move(C3);
     93   EXPECT_EQ(Tmp(), 6);
     94 
     95   unique_function<long()> C4 = [A, B, C, D]() { return A + B + C + D; };
     96   EXPECT_EQ(C4(), 10);
     97   Tmp = std::move(C4);
     98   EXPECT_EQ(Tmp(), 10);
     99 
    100   unique_function<long()> C5 = [A, B, C, D, E]() { return A + B + C + D + E; };
    101   EXPECT_EQ(C5(), 15);
    102   Tmp = std::move(C5);
    103   EXPECT_EQ(Tmp(), 15);
    104 }
    105 
    106 TEST(UniqueFunctionTest, MoveOnly) {
    107   struct SmallCallable {
    108     std::unique_ptr<int> A{new int(1)};
    109 
    110     int operator()(int B) { return *A + B; }
    111   };
    112   unique_function<int(int)> Small = SmallCallable();
    113   EXPECT_EQ(Small(2), 3);
    114   unique_function<int(int)> Small2 = std::move(Small);
    115   EXPECT_EQ(Small2(2), 3);
    116 
    117   struct LargeCallable {
    118     std::unique_ptr<int> A{new int(1)};
    119     std::unique_ptr<int> B{new int(2)};
    120     std::unique_ptr<int> C{new int(3)};
    121     std::unique_ptr<int> D{new int(4)};
    122     std::unique_ptr<int> E{new int(5)};
    123 
    124     int operator()() { return *A + *B + *C + *D + *E; }
    125   };
    126   unique_function<int()> Large = LargeCallable();
    127   EXPECT_EQ(Large(), 15);
    128   unique_function<int()> Large2 = std::move(Large);
    129   EXPECT_EQ(Large2(), 15);
    130 }
    131 
    132 TEST(UniqueFunctionTest, CountForwardingCopies) {
    133   struct CopyCounter {
    134     int &CopyCount;
    135 
    136     CopyCounter(int &CopyCount) : CopyCount(CopyCount) {}
    137     CopyCounter(const CopyCounter &Arg) : CopyCount(Arg.CopyCount) {
    138       ++CopyCount;
    139     }
    140   };
    141 
    142   unique_function<void(CopyCounter)> ByValF = [](CopyCounter) {};
    143   int CopyCount = 0;
    144   ByValF(CopyCounter(CopyCount));
    145   EXPECT_EQ(1, CopyCount);
    146 
    147   CopyCount = 0;
    148   {
    149     CopyCounter Counter{CopyCount};
    150     ByValF(Counter);
    151   }
    152   EXPECT_EQ(2, CopyCount);
    153 
    154   // Check that we don't generate a copy at all when we can bind a reference all
    155   // the way down, even if that reference could *in theory* allow copies.
    156   unique_function<void(const CopyCounter &)> ByRefF = [](const CopyCounter &) {
    157   };
    158   CopyCount = 0;
    159   ByRefF(CopyCounter(CopyCount));
    160   EXPECT_EQ(0, CopyCount);
    161 
    162   CopyCount = 0;
    163   {
    164     CopyCounter Counter{CopyCount};
    165     ByRefF(Counter);
    166   }
    167   EXPECT_EQ(0, CopyCount);
    168 
    169   // If we use a reference, we can make a stronger guarantee that *no* copy
    170   // occurs.
    171   struct Uncopyable {
    172     Uncopyable() = default;
    173     Uncopyable(const Uncopyable &) = delete;
    174   };
    175   unique_function<void(const Uncopyable &)> UncopyableF =
    176       [](const Uncopyable &) {};
    177   UncopyableF(Uncopyable());
    178   Uncopyable X;
    179   UncopyableF(X);
    180 }
    181 
    182 TEST(UniqueFunctionTest, CountForwardingMoves) {
    183   struct MoveCounter {
    184     int &MoveCount;
    185 
    186     MoveCounter(int &MoveCount) : MoveCount(MoveCount) {}
    187     MoveCounter(MoveCounter &&Arg) : MoveCount(Arg.MoveCount) { ++MoveCount; }
    188   };
    189 
    190   unique_function<void(MoveCounter)> ByValF = [](MoveCounter) {};
    191   int MoveCount = 0;
    192   ByValF(MoveCounter(MoveCount));
    193   EXPECT_EQ(1, MoveCount);
    194 
    195   MoveCount = 0;
    196   {
    197     MoveCounter Counter{MoveCount};
    198     ByValF(std::move(Counter));
    199   }
    200   EXPECT_EQ(2, MoveCount);
    201 
    202   // Check that when we use an r-value reference we get no spurious copies.
    203   unique_function<void(MoveCounter &&)> ByRefF = [](MoveCounter &&) {};
    204   MoveCount = 0;
    205   ByRefF(MoveCounter(MoveCount));
    206   EXPECT_EQ(0, MoveCount);
    207 
    208   MoveCount = 0;
    209   {
    210     MoveCounter Counter{MoveCount};
    211     ByRefF(std::move(Counter));
    212   }
    213   EXPECT_EQ(0, MoveCount);
    214 
    215   // If we use an r-value reference we can in fact make a stronger guarantee
    216   // with an unmovable type.
    217   struct Unmovable {
    218     Unmovable() = default;
    219     Unmovable(Unmovable &&) = delete;
    220   };
    221   unique_function<void(const Unmovable &)> UnmovableF = [](const Unmovable &) {
    222   };
    223   UnmovableF(Unmovable());
    224   Unmovable X;
    225   UnmovableF(X);
    226 }
    227 
    228 } // anonymous namespace
    229