1 | //===-- unique_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-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "unique_function.h" |
10 | #include "gtest/gtest.h" |
11 | |
12 | using namespace orc_rt; |
13 | |
14 | TEST(UniqueFunctionTest, Basic) { |
15 | unique_function<int(int, int)> Sum = [](int A, int B) { return A + B; }; |
16 | EXPECT_EQ(Sum(1, 2), 3); |
17 | |
18 | unique_function<int(int, int)> Sum2 = std::move(Sum); |
19 | EXPECT_EQ(Sum2(1, 2), 3); |
20 | |
21 | unique_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 = unique_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 = unique_function<int(int, int)>(); |
33 | EXPECT_FALSE(Sum2); |
34 | |
35 | // Make sure we can forward through l-value reference parameters. |
36 | unique_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 with |
42 | // move-only types. |
43 | unique_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 | unique_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 | |
70 | TEST(UniqueFunctionTest, Captures) { |
71 | long A = 1, B = 2, C = 3, D = 4, E = 5; |
72 | |
73 | unique_function<long()> Tmp; |
74 | |
75 | unique_function<long()> C1 = [A]() { return A; }; |
76 | EXPECT_EQ(C1(), 1); |
77 | Tmp = std::move(t&: C1); |
78 | EXPECT_EQ(Tmp(), 1); |
79 | |
80 | unique_function<long()> C2 = [A, B]() { return A + B; }; |
81 | EXPECT_EQ(C2(), 3); |
82 | Tmp = std::move(t&: C2); |
83 | EXPECT_EQ(Tmp(), 3); |
84 | |
85 | unique_function<long()> C3 = [A, B, C]() { return A + B + C; }; |
86 | EXPECT_EQ(C3(), 6); |
87 | Tmp = std::move(t&: C3); |
88 | EXPECT_EQ(Tmp(), 6); |
89 | |
90 | unique_function<long()> C4 = [A, B, C, D]() { return A + B + C + D; }; |
91 | EXPECT_EQ(C4(), 10); |
92 | Tmp = std::move(t&: C4); |
93 | EXPECT_EQ(Tmp(), 10); |
94 | |
95 | unique_function<long()> C5 = [A, B, C, D, E]() { return A + B + C + D + E; }; |
96 | EXPECT_EQ(C5(), 15); |
97 | Tmp = std::move(t&: C5); |
98 | EXPECT_EQ(Tmp(), 15); |
99 | } |
100 | |
101 | TEST(UniqueFunctionTest, MoveOnly) { |
102 | struct SmallCallable { |
103 | std::unique_ptr<int> A = std::make_unique<int>(args: 1); |
104 | int operator()(int B) { return *A + B; } |
105 | }; |
106 | |
107 | unique_function<int(int)> Small = SmallCallable(); |
108 | EXPECT_EQ(Small(2), 3); |
109 | unique_function<int(int)> Small2 = std::move(t&: Small); |
110 | EXPECT_EQ(Small2(2), 3); |
111 | } |
112 | |
113 | TEST(UniqueFunctionTest, CountForwardingCopies) { |
114 | struct CopyCounter { |
115 | int &CopyCount; |
116 | |
117 | CopyCounter(int &CopyCount) : CopyCount(CopyCount) {} |
118 | CopyCounter(const CopyCounter &Arg) : CopyCount(Arg.CopyCount) { |
119 | ++CopyCount; |
120 | } |
121 | }; |
122 | |
123 | unique_function<void(CopyCounter)> ByValF = [](CopyCounter) {}; |
124 | int CopyCount = 0; |
125 | ByValF(CopyCounter(CopyCount)); |
126 | EXPECT_EQ(1, CopyCount); |
127 | |
128 | CopyCount = 0; |
129 | { |
130 | CopyCounter Counter{CopyCount}; |
131 | ByValF(Counter); |
132 | } |
133 | EXPECT_EQ(2, CopyCount); |
134 | |
135 | // Check that we don't generate a copy at all when we can bind a reference all |
136 | // the way down, even if that reference could *in theory* allow copies. |
137 | unique_function<void(const CopyCounter &)> ByRefF = [](const CopyCounter &) { |
138 | }; |
139 | CopyCount = 0; |
140 | ByRefF(CopyCounter(CopyCount)); |
141 | EXPECT_EQ(0, CopyCount); |
142 | |
143 | CopyCount = 0; |
144 | { |
145 | CopyCounter Counter{CopyCount}; |
146 | ByRefF(Counter); |
147 | } |
148 | EXPECT_EQ(0, CopyCount); |
149 | |
150 | // If we use a reference, we can make a stronger guarantee that *no* copy |
151 | // occurs. |
152 | struct Uncopyable { |
153 | Uncopyable() = default; |
154 | Uncopyable(const Uncopyable &) = delete; |
155 | }; |
156 | unique_function<void(const Uncopyable &)> UncopyableF = |
157 | [](const Uncopyable &) {}; |
158 | UncopyableF(Uncopyable()); |
159 | Uncopyable X; |
160 | UncopyableF(X); |
161 | } |
162 | |
163 | TEST(UniqueFunctionTest, BooleanConversion) { |
164 | unique_function<void()> D; |
165 | EXPECT_FALSE(D); |
166 | |
167 | unique_function<void()> F = []() {}; |
168 | EXPECT_TRUE(F); |
169 | } |
170 | |