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