Chandler Carruth | e8529c2 | 2016-08-19 02:07:51 +0000 | [diff] [blame] | 1 | //===- STLExtrasTest.cpp - Unit tests for STL extras ----------------------===// |
| 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/STLExtras.h" |
| 11 | #include "gtest/gtest.h" |
| 12 | |
Zachary Turner | 4f20a0a | 2016-09-30 15:43:59 +0000 | [diff] [blame] | 13 | #include <vector> |
| 14 | |
Chandler Carruth | e8529c2 | 2016-08-19 02:07:51 +0000 | [diff] [blame] | 15 | using namespace llvm; |
| 16 | |
| 17 | namespace { |
| 18 | |
| 19 | int f(rank<0>) { return 0; } |
| 20 | int f(rank<1>) { return 1; } |
| 21 | int f(rank<2>) { return 2; } |
| 22 | int f(rank<4>) { return 4; } |
| 23 | |
| 24 | TEST(STLExtrasTest, Rank) { |
| 25 | // We shouldn't get ambiguities and should select the overload of the same |
| 26 | // rank as the argument. |
| 27 | EXPECT_EQ(0, f(rank<0>())); |
| 28 | EXPECT_EQ(1, f(rank<1>())); |
| 29 | EXPECT_EQ(2, f(rank<2>())); |
| 30 | |
| 31 | // This overload is missing so we end up back at 2. |
| 32 | EXPECT_EQ(2, f(rank<3>())); |
| 33 | |
| 34 | // But going past 3 should work fine. |
| 35 | EXPECT_EQ(4, f(rank<4>())); |
| 36 | |
| 37 | // And we can even go higher and just fall back to the last overload. |
| 38 | EXPECT_EQ(4, f(rank<5>())); |
| 39 | EXPECT_EQ(4, f(rank<6>())); |
| 40 | } |
| 41 | |
Zachary Turner | aa0a562 | 2016-10-05 16:54:09 +0000 | [diff] [blame] | 42 | TEST(STLExtrasTest, EnumerateLValue) { |
| 43 | // Test that a simple LValue can be enumerated and gives correct results with |
| 44 | // multiple types, including the empty container. |
Zachary Turner | 4f20a0a | 2016-09-30 15:43:59 +0000 | [diff] [blame] | 45 | std::vector<char> foo = {'a', 'b', 'c'}; |
Zachary Turner | aad1583 | 2016-10-05 17:04:36 +0000 | [diff] [blame] | 46 | typedef std::pair<std::size_t, char> CharPairType; |
| 47 | std::vector<CharPairType> CharResults; |
Zachary Turner | 4f20a0a | 2016-09-30 15:43:59 +0000 | [diff] [blame] | 48 | |
| 49 | for (auto X : llvm::enumerate(foo)) { |
Zachary Turner | aa0a562 | 2016-10-05 16:54:09 +0000 | [diff] [blame] | 50 | CharResults.emplace_back(X.Index, X.Value); |
Zachary Turner | 4f20a0a | 2016-09-30 15:43:59 +0000 | [diff] [blame] | 51 | } |
Zachary Turner | aa0a562 | 2016-10-05 16:54:09 +0000 | [diff] [blame] | 52 | ASSERT_EQ(3u, CharResults.size()); |
Zachary Turner | aad1583 | 2016-10-05 17:04:36 +0000 | [diff] [blame] | 53 | EXPECT_EQ(CharPairType(0u, 'a'), CharResults[0]); |
| 54 | EXPECT_EQ(CharPairType(1u, 'b'), CharResults[1]); |
| 55 | EXPECT_EQ(CharPairType(2u, 'c'), CharResults[2]); |
Zachary Turner | 4f20a0a | 2016-09-30 15:43:59 +0000 | [diff] [blame] | 56 | |
Zachary Turner | aa0a562 | 2016-10-05 16:54:09 +0000 | [diff] [blame] | 57 | // Test a const range of a different type. |
Zachary Turner | aad1583 | 2016-10-05 17:04:36 +0000 | [diff] [blame] | 58 | typedef std::pair<std::size_t, int> IntPairType; |
| 59 | std::vector<IntPairType> IntResults; |
Zachary Turner | aa0a562 | 2016-10-05 16:54:09 +0000 | [diff] [blame] | 60 | const std::vector<int> bar = {1, 2, 3}; |
Zachary Turner | 4f20a0a | 2016-09-30 15:43:59 +0000 | [diff] [blame] | 61 | for (auto X : llvm::enumerate(bar)) { |
Zachary Turner | aa0a562 | 2016-10-05 16:54:09 +0000 | [diff] [blame] | 62 | IntResults.emplace_back(X.Index, X.Value); |
Zachary Turner | 4f20a0a | 2016-09-30 15:43:59 +0000 | [diff] [blame] | 63 | } |
Zachary Turner | aa0a562 | 2016-10-05 16:54:09 +0000 | [diff] [blame] | 64 | ASSERT_EQ(3u, IntResults.size()); |
Zachary Turner | aad1583 | 2016-10-05 17:04:36 +0000 | [diff] [blame] | 65 | EXPECT_EQ(IntPairType(0u, 1), IntResults[0]); |
| 66 | EXPECT_EQ(IntPairType(1u, 2), IntResults[1]); |
| 67 | EXPECT_EQ(IntPairType(2u, 3), IntResults[2]); |
Zachary Turner | 4f20a0a | 2016-09-30 15:43:59 +0000 | [diff] [blame] | 68 | |
Zachary Turner | aa0a562 | 2016-10-05 16:54:09 +0000 | [diff] [blame] | 69 | // Test an empty range. |
| 70 | IntResults.clear(); |
Zachary Turner | 4f20a0a | 2016-09-30 15:43:59 +0000 | [diff] [blame] | 71 | const std::vector<int> baz; |
| 72 | for (auto X : llvm::enumerate(baz)) { |
Zachary Turner | aa0a562 | 2016-10-05 16:54:09 +0000 | [diff] [blame] | 73 | IntResults.emplace_back(X.Index, X.Value); |
Zachary Turner | 4f20a0a | 2016-09-30 15:43:59 +0000 | [diff] [blame] | 74 | } |
Zachary Turner | aa0a562 | 2016-10-05 16:54:09 +0000 | [diff] [blame] | 75 | EXPECT_TRUE(IntResults.empty()); |
Zachary Turner | 4f20a0a | 2016-09-30 15:43:59 +0000 | [diff] [blame] | 76 | } |
| 77 | |
Zachary Turner | aa0a562 | 2016-10-05 16:54:09 +0000 | [diff] [blame] | 78 | TEST(STLExtrasTest, EnumerateModifyLValue) { |
| 79 | // Test that you can modify the underlying entries of an lvalue range through |
| 80 | // the enumeration iterator. |
Zachary Turner | 4f20a0a | 2016-09-30 15:43:59 +0000 | [diff] [blame] | 81 | std::vector<char> foo = {'a', 'b', 'c'}; |
| 82 | |
| 83 | for (auto X : llvm::enumerate(foo)) { |
| 84 | ++X.Value; |
| 85 | } |
Zachary Turner | 4f20a0a | 2016-09-30 15:43:59 +0000 | [diff] [blame] | 86 | EXPECT_EQ('b', foo[0]); |
| 87 | EXPECT_EQ('c', foo[1]); |
| 88 | EXPECT_EQ('d', foo[2]); |
| 89 | } |
Zachary Turner | aa0a562 | 2016-10-05 16:54:09 +0000 | [diff] [blame] | 90 | |
| 91 | TEST(STLExtrasTest, EnumerateRValueRef) { |
| 92 | // Test that an rvalue can be enumerated. |
Zachary Turner | aad1583 | 2016-10-05 17:04:36 +0000 | [diff] [blame] | 93 | typedef std::pair<std::size_t, int> PairType; |
| 94 | std::vector<PairType> Results; |
Zachary Turner | aa0a562 | 2016-10-05 16:54:09 +0000 | [diff] [blame] | 95 | |
| 96 | auto Enumerator = llvm::enumerate(std::vector<int>{1, 2, 3}); |
| 97 | |
| 98 | for (auto X : llvm::enumerate(std::vector<int>{1, 2, 3})) { |
| 99 | Results.emplace_back(X.Index, X.Value); |
| 100 | } |
| 101 | |
| 102 | ASSERT_EQ(3u, Results.size()); |
Zachary Turner | aad1583 | 2016-10-05 17:04:36 +0000 | [diff] [blame] | 103 | EXPECT_EQ(PairType(0u, 1), Results[0]); |
| 104 | EXPECT_EQ(PairType(1u, 2), Results[1]); |
| 105 | EXPECT_EQ(PairType(2u, 3), Results[2]); |
Zachary Turner | aa0a562 | 2016-10-05 16:54:09 +0000 | [diff] [blame] | 106 | } |
| 107 | |
| 108 | TEST(STLExtrasTest, EnumerateModifyRValue) { |
| 109 | // Test that when enumerating an rvalue, modification still works (even if |
| 110 | // this isn't terribly useful, it at least shows that we haven't snuck an |
| 111 | // extra const in there somewhere. |
Zachary Turner | aad1583 | 2016-10-05 17:04:36 +0000 | [diff] [blame] | 112 | typedef std::pair<std::size_t, char> PairType; |
| 113 | std::vector<PairType> Results; |
Zachary Turner | aa0a562 | 2016-10-05 16:54:09 +0000 | [diff] [blame] | 114 | |
| 115 | for (auto X : llvm::enumerate(std::vector<char>{'1', '2', '3'})) { |
| 116 | ++X.Value; |
| 117 | Results.emplace_back(X.Index, X.Value); |
| 118 | } |
| 119 | |
| 120 | ASSERT_EQ(3u, Results.size()); |
Zachary Turner | aad1583 | 2016-10-05 17:04:36 +0000 | [diff] [blame] | 121 | EXPECT_EQ(PairType(0u, '2'), Results[0]); |
| 122 | EXPECT_EQ(PairType(1u, '3'), Results[1]); |
| 123 | EXPECT_EQ(PairType(2u, '4'), Results[2]); |
Zachary Turner | aa0a562 | 2016-10-05 16:54:09 +0000 | [diff] [blame] | 124 | } |
| 125 | |
| 126 | template <bool B> struct CanMove {}; |
| 127 | template <> struct CanMove<false> { |
| 128 | CanMove(CanMove &&) = delete; |
| 129 | |
| 130 | CanMove() = default; |
| 131 | CanMove(const CanMove &) = default; |
| 132 | }; |
| 133 | |
| 134 | template <bool B> struct CanCopy {}; |
| 135 | template <> struct CanCopy<false> { |
| 136 | CanCopy(const CanCopy &) = delete; |
| 137 | |
| 138 | CanCopy() = default; |
Reid Kleckner | b0311b2 | 2016-10-05 21:44:46 +0000 | [diff] [blame] | 139 | // FIXME: Use '= default' when we drop MSVC 2013. |
Reid Kleckner | 6f83e8b | 2016-10-05 21:46:56 +0000 | [diff] [blame] | 140 | CanCopy(CanCopy &&) {} |
Zachary Turner | aa0a562 | 2016-10-05 16:54:09 +0000 | [diff] [blame] | 141 | }; |
| 142 | |
| 143 | template <bool Moveable, bool Copyable> |
| 144 | struct Range : CanMove<Moveable>, CanCopy<Copyable> { |
| 145 | explicit Range(int &C, int &M, int &D) : C(C), M(M), D(D) {} |
| 146 | Range(const Range &R) : CanCopy<Copyable>(R), C(R.C), M(R.M), D(R.D) { ++C; } |
| 147 | Range(Range &&R) : CanMove<Moveable>(std::move(R)), C(R.C), M(R.M), D(R.D) { |
| 148 | ++M; |
| 149 | } |
| 150 | ~Range() { ++D; } |
| 151 | |
| 152 | int &C; |
| 153 | int &M; |
| 154 | int &D; |
| 155 | |
| 156 | int *begin() { return nullptr; } |
| 157 | int *end() { return nullptr; } |
| 158 | }; |
| 159 | |
| 160 | TEST(STLExtrasTest, EnumerateLifetimeSemantics) { |
| 161 | // Test that when enumerating lvalues and rvalues, there are no surprise |
| 162 | // copies or moves. |
| 163 | |
| 164 | // With an rvalue, it should not be destroyed until the end of the scope. |
| 165 | int Copies = 0; |
| 166 | int Moves = 0; |
| 167 | int Destructors = 0; |
| 168 | { |
| 169 | auto E1 = enumerate(Range<true, false>(Copies, Moves, Destructors)); |
| 170 | // Doesn't compile. rvalue ranges must be moveable. |
| 171 | // auto E2 = enumerate(Range<false, true>(Copies, Moves, Destructors)); |
| 172 | EXPECT_EQ(0, Copies); |
| 173 | EXPECT_EQ(1, Moves); |
| 174 | EXPECT_EQ(1, Destructors); |
| 175 | } |
| 176 | EXPECT_EQ(0, Copies); |
| 177 | EXPECT_EQ(1, Moves); |
| 178 | EXPECT_EQ(2, Destructors); |
| 179 | |
| 180 | Copies = Moves = Destructors = 0; |
| 181 | // With an lvalue, it should not be destroyed even after the end of the scope. |
| 182 | // lvalue ranges need be neither copyable nor moveable. |
| 183 | Range<false, false> R(Copies, Moves, Destructors); |
| 184 | { |
| 185 | auto Enumerator = enumerate(R); |
| 186 | (void)Enumerator; |
| 187 | EXPECT_EQ(0, Copies); |
| 188 | EXPECT_EQ(0, Moves); |
| 189 | EXPECT_EQ(0, Destructors); |
| 190 | } |
| 191 | EXPECT_EQ(0, Copies); |
| 192 | EXPECT_EQ(0, Moves); |
| 193 | EXPECT_EQ(0, Destructors); |
| 194 | } |
Zachary Turner | 3174bde | 2016-10-10 16:44:09 +0000 | [diff] [blame^] | 195 | |
| 196 | TEST(STLExtrasTest, ApplyTuple) { |
| 197 | auto T = std::make_tuple(1, 3, 7); |
| 198 | auto U = llvm::apply( |
| 199 | [](int A, int B, int C) { return std::make_tuple(A - B, B - C, C - A); }, |
| 200 | T); |
| 201 | |
| 202 | EXPECT_EQ(-2, std::get<0>(U)); |
| 203 | EXPECT_EQ(-4, std::get<1>(U)); |
| 204 | EXPECT_EQ(6, std::get<2>(U)); |
| 205 | |
| 206 | auto V = llvm::apply( |
| 207 | [](int A, int B, int C) { |
| 208 | return std::make_tuple(std::make_pair(A, char('A' + A)), |
| 209 | std::make_pair(B, char('A' + B)), |
| 210 | std::make_pair(C, char('A' + C))); |
| 211 | }, |
| 212 | T); |
| 213 | |
| 214 | EXPECT_EQ(std::make_pair(1, 'B'), std::get<0>(V)); |
| 215 | EXPECT_EQ(std::make_pair(3, 'D'), std::get<1>(V)); |
| 216 | EXPECT_EQ(std::make_pair(7, 'H'), std::get<2>(V)); |
| 217 | } |
| 218 | |
| 219 | class apply_variadic { |
| 220 | static int apply_one(int X) { return X + 1; } |
| 221 | static char apply_one(char C) { return C + 1; } |
| 222 | static StringRef apply_one(StringRef S) { return S.drop_back(); } |
| 223 | |
| 224 | public: |
| 225 | template <typename... Ts> |
| 226 | auto operator()(Ts &&... Items) |
| 227 | -> decltype(std::make_tuple(apply_one(Items)...)) { |
| 228 | return std::make_tuple(apply_one(Items)...); |
| 229 | } |
| 230 | }; |
| 231 | |
| 232 | TEST(STLExtrasTest, ApplyTupleVariadic) { |
| 233 | auto Items = std::make_tuple(1, llvm::StringRef("Test"), 'X'); |
| 234 | auto Values = apply(apply_variadic(), Items); |
| 235 | |
| 236 | EXPECT_EQ(2, std::get<0>(Values)); |
| 237 | EXPECT_EQ("Tes", std::get<1>(Values)); |
| 238 | EXPECT_EQ('Y', std::get<2>(Values)); |
| 239 | } |
Chandler Carruth | e8529c2 | 2016-08-19 02:07:51 +0000 | [diff] [blame] | 240 | } |