[InstCombine] Signed saturation tests. NFC
[llvm-complete.git] / unittests / ADT / FunctionExtrasTest.cpp
blobbbbb045cb14abf743fa27d80409542b33d26b9ca
1 //===- FunctionExtrasTest.cpp - Unit tests for function type erasure ------===//
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 //===----------------------------------------------------------------------===//
9 #include "llvm/ADT/FunctionExtras.h"
10 #include "gtest/gtest.h"
12 #include <memory>
14 using namespace llvm;
16 namespace {
18 TEST(UniqueFunctionTest, Basic) {
19 unique_function<int(int, int)> Sum = [](int A, int B) { return A + B; };
20 EXPECT_EQ(Sum(1, 2), 3);
22 unique_function<int(int, int)> Sum2 = std::move(Sum);
23 EXPECT_EQ(Sum2(1, 2), 3);
25 unique_function<int(int, int)> Sum3 = [](int A, int B) { return A + B; };
26 Sum2 = std::move(Sum3);
27 EXPECT_EQ(Sum2(1, 2), 3);
29 Sum2 = unique_function<int(int, int)>([](int A, int B) { return A + B; });
30 EXPECT_EQ(Sum2(1, 2), 3);
32 // Explicit self-move test.
33 *&Sum2 = std::move(Sum2);
34 EXPECT_EQ(Sum2(1, 2), 3);
36 Sum2 = unique_function<int(int, int)>();
37 EXPECT_FALSE(Sum2);
39 // Make sure we can forward through l-value reference parameters.
40 unique_function<void(int &)> Inc = [](int &X) { ++X; };
41 int X = 42;
42 Inc(X);
43 EXPECT_EQ(X, 43);
45 // Make sure we can forward through r-value reference parameters with
46 // move-only types.
47 unique_function<int(std::unique_ptr<int> &&)> ReadAndDeallocByRef =
48 [](std::unique_ptr<int> &&Ptr) {
49 int V = *Ptr;
50 Ptr.reset();
51 return V;
53 std::unique_ptr<int> Ptr{new int(13)};
54 EXPECT_EQ(ReadAndDeallocByRef(std::move(Ptr)), 13);
55 EXPECT_FALSE((bool)Ptr);
57 // Make sure we can pass a move-only temporary as opposed to a local variable.
58 EXPECT_EQ(ReadAndDeallocByRef(std::unique_ptr<int>(new int(42))), 42);
60 // Make sure we can pass a move-only type by-value.
61 unique_function<int(std::unique_ptr<int>)> ReadAndDeallocByVal =
62 [](std::unique_ptr<int> Ptr) {
63 int V = *Ptr;
64 Ptr.reset();
65 return V;
67 Ptr.reset(new int(13));
68 EXPECT_EQ(ReadAndDeallocByVal(std::move(Ptr)), 13);
69 EXPECT_FALSE((bool)Ptr);
71 EXPECT_EQ(ReadAndDeallocByVal(std::unique_ptr<int>(new int(42))), 42);
74 TEST(UniqueFunctionTest, Captures) {
75 long A = 1, B = 2, C = 3, D = 4, E = 5;
77 unique_function<long()> Tmp;
79 unique_function<long()> C1 = [A]() { return A; };
80 EXPECT_EQ(C1(), 1);
81 Tmp = std::move(C1);
82 EXPECT_EQ(Tmp(), 1);
84 unique_function<long()> C2 = [A, B]() { return A + B; };
85 EXPECT_EQ(C2(), 3);
86 Tmp = std::move(C2);
87 EXPECT_EQ(Tmp(), 3);
89 unique_function<long()> C3 = [A, B, C]() { return A + B + C; };
90 EXPECT_EQ(C3(), 6);
91 Tmp = std::move(C3);
92 EXPECT_EQ(Tmp(), 6);
94 unique_function<long()> C4 = [A, B, C, D]() { return A + B + C + D; };
95 EXPECT_EQ(C4(), 10);
96 Tmp = std::move(C4);
97 EXPECT_EQ(Tmp(), 10);
99 unique_function<long()> C5 = [A, B, C, D, E]() { return A + B + C + D + E; };
100 EXPECT_EQ(C5(), 15);
101 Tmp = std::move(C5);
102 EXPECT_EQ(Tmp(), 15);
105 TEST(UniqueFunctionTest, MoveOnly) {
106 struct SmallCallable {
107 std::unique_ptr<int> A{new int(1)};
109 int operator()(int B) { return *A + B; }
111 unique_function<int(int)> Small = SmallCallable();
112 EXPECT_EQ(Small(2), 3);
113 unique_function<int(int)> Small2 = std::move(Small);
114 EXPECT_EQ(Small2(2), 3);
116 struct LargeCallable {
117 std::unique_ptr<int> A{new int(1)};
118 std::unique_ptr<int> B{new int(2)};
119 std::unique_ptr<int> C{new int(3)};
120 std::unique_ptr<int> D{new int(4)};
121 std::unique_ptr<int> E{new int(5)};
123 int operator()() { return *A + *B + *C + *D + *E; }
125 unique_function<int()> Large = LargeCallable();
126 EXPECT_EQ(Large(), 15);
127 unique_function<int()> Large2 = std::move(Large);
128 EXPECT_EQ(Large2(), 15);
131 TEST(UniqueFunctionTest, CountForwardingCopies) {
132 struct CopyCounter {
133 int &CopyCount;
135 CopyCounter(int &CopyCount) : CopyCount(CopyCount) {}
136 CopyCounter(const CopyCounter &Arg) : CopyCount(Arg.CopyCount) {
137 ++CopyCount;
141 unique_function<void(CopyCounter)> ByValF = [](CopyCounter) {};
142 int CopyCount = 0;
143 ByValF(CopyCounter(CopyCount));
144 EXPECT_EQ(1, CopyCount);
146 CopyCount = 0;
148 CopyCounter Counter{CopyCount};
149 ByValF(Counter);
151 EXPECT_EQ(2, CopyCount);
153 // Check that we don't generate a copy at all when we can bind a reference all
154 // the way down, even if that reference could *in theory* allow copies.
155 unique_function<void(const CopyCounter &)> ByRefF = [](const CopyCounter &) {
157 CopyCount = 0;
158 ByRefF(CopyCounter(CopyCount));
159 EXPECT_EQ(0, CopyCount);
161 CopyCount = 0;
163 CopyCounter Counter{CopyCount};
164 ByRefF(Counter);
166 EXPECT_EQ(0, CopyCount);
168 // If we use a reference, we can make a stronger guarantee that *no* copy
169 // occurs.
170 struct Uncopyable {
171 Uncopyable() = default;
172 Uncopyable(const Uncopyable &) = delete;
174 unique_function<void(const Uncopyable &)> UncopyableF =
175 [](const Uncopyable &) {};
176 UncopyableF(Uncopyable());
177 Uncopyable X;
178 UncopyableF(X);
181 TEST(UniqueFunctionTest, CountForwardingMoves) {
182 struct MoveCounter {
183 int &MoveCount;
185 MoveCounter(int &MoveCount) : MoveCount(MoveCount) {}
186 MoveCounter(MoveCounter &&Arg) : MoveCount(Arg.MoveCount) { ++MoveCount; }
189 unique_function<void(MoveCounter)> ByValF = [](MoveCounter) {};
190 int MoveCount = 0;
191 ByValF(MoveCounter(MoveCount));
192 EXPECT_EQ(1, MoveCount);
194 MoveCount = 0;
196 MoveCounter Counter{MoveCount};
197 ByValF(std::move(Counter));
199 EXPECT_EQ(2, MoveCount);
201 // Check that when we use an r-value reference we get no spurious copies.
202 unique_function<void(MoveCounter &&)> ByRefF = [](MoveCounter &&) {};
203 MoveCount = 0;
204 ByRefF(MoveCounter(MoveCount));
205 EXPECT_EQ(0, MoveCount);
207 MoveCount = 0;
209 MoveCounter Counter{MoveCount};
210 ByRefF(std::move(Counter));
212 EXPECT_EQ(0, MoveCount);
214 // If we use an r-value reference we can in fact make a stronger guarantee
215 // with an unmovable type.
216 struct Unmovable {
217 Unmovable() = default;
218 Unmovable(Unmovable &&) = delete;
220 unique_function<void(const Unmovable &)> UnmovableF = [](const Unmovable &) {
222 UnmovableF(Unmovable());
223 Unmovable X;
224 UnmovableF(X);
227 } // anonymous namespace