brintos

brintos / llvm-project-archived public Read only

0
0
Text · 6.6 KiB · adec654 Raw
249 lines · cpp
1//===- move_only_function-test.cpp ----------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "orc-rt/move_only_function.h"10#include "gtest/gtest.h"11 12using namespace orc_rt;13 14TEST(MoveOnlyFunctionTest, Basic) {15  move_only_function<int(int, int)> Sum = [](int A, int B) { return A + B; };16  EXPECT_EQ(Sum(1, 2), 3);17 18  move_only_function<int(int, int)> Sum2 = std::move(Sum);19  EXPECT_EQ(Sum2(1, 2), 3);20 21  move_only_function<int(int, int)> Sum3 = [](int A, int B) { return A + B; };22  Sum2 = std::move(Sum3);23  EXPECT_EQ(Sum2(1, 2), 3);24 25  Sum2 = move_only_function<int(int, int)>([](int A, int B) { return A + B; });26  EXPECT_EQ(Sum2(1, 2), 3);27 28  // Explicit self-move test.29  *&Sum2 = std::move(Sum2);30  EXPECT_EQ(Sum2(1, 2), 3);31 32  Sum2 = move_only_function<int(int, int)>();33  EXPECT_FALSE(Sum2);34 35  // Make sure we can forward through l-value reference parameters.36  move_only_function<void(int &)> Inc = [](int &X) { ++X; };37  int X = 42;38  Inc(X);39  EXPECT_EQ(X, 43);40 41  // Make sure we can forward through r-value reference parameters with42  // move-only types.43  move_only_function<int(std::unique_ptr<int> &&)> ReadAndDeallocByRef =44      [](std::unique_ptr<int> &&Ptr) {45        int V = *Ptr;46        Ptr.reset();47        return V;48      };49  std::unique_ptr<int> Ptr{new int(13)};50  EXPECT_EQ(ReadAndDeallocByRef(std::move(Ptr)), 13);51  EXPECT_FALSE((bool)Ptr);52 53  // Make sure we can pass a move-only temporary as opposed to a local variable.54  EXPECT_EQ(ReadAndDeallocByRef(std::unique_ptr<int>(new int(42))), 42);55 56  // Make sure we can pass a move-only type by-value.57  move_only_function<int(std::unique_ptr<int>)> ReadAndDeallocByVal =58      [](std::unique_ptr<int> Ptr) {59        int V = *Ptr;60        Ptr.reset();61        return V;62      };63  Ptr.reset(new int(13));64  EXPECT_EQ(ReadAndDeallocByVal(std::move(Ptr)), 13);65  EXPECT_FALSE((bool)Ptr);66 67  EXPECT_EQ(ReadAndDeallocByVal(std::unique_ptr<int>(new int(42))), 42);68}69 70TEST(MoveOnlyFunctionTest, Captures) {71  long A = 1, B = 2, C = 3, D = 4, E = 5;72 73  move_only_function<long()> Tmp;74 75  move_only_function<long()> C1 = [A]() { return A; };76  EXPECT_EQ(C1(), 1);77  Tmp = std::move(C1);78  EXPECT_EQ(Tmp(), 1);79 80  move_only_function<long()> C2 = [A, B]() { return A + B; };81  EXPECT_EQ(C2(), 3);82  Tmp = std::move(C2);83  EXPECT_EQ(Tmp(), 3);84 85  move_only_function<long()> C3 = [A, B, C]() { return A + B + C; };86  EXPECT_EQ(C3(), 6);87  Tmp = std::move(C3);88  EXPECT_EQ(Tmp(), 6);89 90  move_only_function<long()> C4 = [A, B, C, D]() { return A + B + C + D; };91  EXPECT_EQ(C4(), 10);92  Tmp = std::move(C4);93  EXPECT_EQ(Tmp(), 10);94 95  move_only_function<long()> C5 = [A, B, C, D, E]() {96    return A + B + C + D + E;97  };98  EXPECT_EQ(C5(), 15);99  Tmp = std::move(C5);100  EXPECT_EQ(Tmp(), 15);101 102  // Test capture via lvalue.103  auto Inc = [](int N) { return N + 1; };104  move_only_function<int(int)> C6(Inc);105  EXPECT_EQ(C6(1), 2);106}107 108TEST(MoveOnlyFunctionTest, MoveOnly) {109  struct SmallCallable {110    std::unique_ptr<int> A = std::make_unique<int>(1);111    int operator()(int B) { return *A + B; }112  };113 114  move_only_function<int(int)> Small = SmallCallable();115  EXPECT_EQ(Small(2), 3);116  move_only_function<int(int)> Small2 = std::move(Small);117  EXPECT_EQ(Small2(2), 3);118}119 120TEST(MoveOnlyFunctionTest, CountForwardingCopies) {121  struct CopyCounter {122    int &CopyCount;123 124    CopyCounter(int &CopyCount) : CopyCount(CopyCount) {}125    CopyCounter(const CopyCounter &Arg) : CopyCount(Arg.CopyCount) {126      ++CopyCount;127    }128  };129 130  move_only_function<void(CopyCounter)> ByValF = [](CopyCounter) {};131  int CopyCount = 0;132  ByValF(CopyCounter(CopyCount));133  EXPECT_EQ(1, CopyCount);134 135  CopyCount = 0;136  {137    CopyCounter Counter{CopyCount};138    ByValF(Counter);139  }140  EXPECT_EQ(2, CopyCount);141 142  // Check that we don't generate a copy at all when we can bind a reference all143  // the way down, even if that reference could *in theory* allow copies.144  move_only_function<void(const CopyCounter &)> ByRefF =145      [](const CopyCounter &) {};146  CopyCount = 0;147  ByRefF(CopyCounter(CopyCount));148  EXPECT_EQ(0, CopyCount);149 150  CopyCount = 0;151  {152    CopyCounter Counter{CopyCount};153    ByRefF(Counter);154  }155  EXPECT_EQ(0, CopyCount);156 157  // If we use a reference, we can make a stronger guarantee that *no* copy158  // occurs.159  struct Uncopyable {160    Uncopyable() = default;161    Uncopyable(const Uncopyable &) = delete;162  };163  move_only_function<void(const Uncopyable &)> UncopyableF =164      [](const Uncopyable &) {};165  UncopyableF(Uncopyable());166  Uncopyable X;167  UncopyableF(X);168}169 170TEST(MoveOnlyFunctionTest, BooleanConversion) {171  move_only_function<void()> D;172  EXPECT_FALSE(D);173 174  move_only_function<void()> F = []() {};175  EXPECT_TRUE(F);176}177 178class ConstCallCounter {179public:180  ConstCallCounter(size_t &NonConst, size_t &Const)181      : NonConst(NonConst), Const(Const) {}182  void operator()() { ++NonConst; }183  void operator()() const { ++Const; }184 185private:186  size_t &NonConst;187  size_t &Const;188};189 190TEST(MoveOnlyFunctionTest, Constness) {191  {192    // Non-const move-only-function, non-const callable.193    size_t NonConst = 0;194    size_t Const = 0;195    move_only_function<void()> F(ConstCallCounter(NonConst, Const));196    F();197    EXPECT_EQ(NonConst, 1U);198    EXPECT_EQ(Const, 0U);199  }200 201  {202    // const move-only-function, non-const callable.203    size_t NonConst = 0;204    size_t Const = 0;205    const move_only_function<void()> F(ConstCallCounter(NonConst, Const));206    F();207    EXPECT_EQ(NonConst, 1U);208    EXPECT_EQ(Const, 0U);209  }210 211  {212    // Non-const move-only-function, const callable.213    size_t NonConst = 0;214    size_t Const = 0;215    move_only_function<void() const> F(ConstCallCounter(NonConst, Const));216    F();217    EXPECT_EQ(NonConst, 0U);218    EXPECT_EQ(Const, 1U);219  }220 221  {222    // const move-only-function, const callable.223    size_t NonConst = 0;224    size_t Const = 0;225    const move_only_function<void() const> F(ConstCallCounter(NonConst, Const));226    F();227    EXPECT_EQ(NonConst, 0U);228    EXPECT_EQ(Const, 1U);229  }230}231 232TEST(MoveOnlyFunctionTest, ShouldCopyInitialize) {233  // Check that we don't accidentally move-initialize move_only_functions.234  class ShouldCopy {235  public:236    ShouldCopy(bool &Moved) : Moved(Moved) {}237    ShouldCopy(const ShouldCopy &) = default;238    ShouldCopy(ShouldCopy &&Other) : Moved(Other.Moved) { Moved = true; }239    void operator()() {}240 241  private:242    bool &Moved;243  };244  bool DidMove = false;245  ShouldCopy SC(DidMove);246  move_only_function<void()> F(SC);247  EXPECT_FALSE(DidMove);248}249