@@ -39,51 +39,152 @@ TEST(STLExtrasTest, Rank) {
39
39
EXPECT_EQ (4 , f (rank<6 >()));
40
40
}
41
41
42
- TEST (STLExtrasTest, Enumerate) {
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.
43
45
std::vector<char > foo = {' a' , ' b' , ' c' };
44
-
45
- std::vector<std::pair<std::size_t , char >> results;
46
+ std::vector<std::pair<std::size_t , char >> CharResults;
46
47
47
48
for (auto X : llvm::enumerate (foo)) {
48
- results. push_back ( std::make_pair ( X.Index , X.Value ) );
49
+ CharResults. emplace_back ( X.Index , X.Value );
49
50
}
50
- ASSERT_EQ (3u , results.size ());
51
- EXPECT_EQ (0u , results[0 ].first );
52
- EXPECT_EQ (' a' , results[0 ].second );
53
- EXPECT_EQ (1u , results[1 ].first );
54
- EXPECT_EQ (' b' , results[1 ].second );
55
- EXPECT_EQ (2u , results[2 ].first );
56
- EXPECT_EQ (' c' , results[2 ].second );
57
-
58
- results.clear ();
59
- const std::vector<int > bar = {' 1' , ' 2' , ' 3' };
51
+ ASSERT_EQ (3u , CharResults.size ());
52
+ EXPECT_EQ (std::make_pair (0u , ' a' ), CharResults[0 ]);
53
+ EXPECT_EQ (std::make_pair (1u , ' b' ), CharResults[1 ]);
54
+ EXPECT_EQ (std::make_pair (2u , ' c' ), CharResults[2 ]);
55
+
56
+ // Test a const range of a different type.
57
+ std::vector<std::pair<std::size_t , int >> IntResults;
58
+ const std::vector<int > bar = {1 , 2 , 3 };
60
59
for (auto X : llvm::enumerate (bar)) {
61
- results. push_back ( std::make_pair ( X.Index , X.Value ) );
60
+ IntResults. emplace_back ( X.Index , X.Value );
62
61
}
63
- EXPECT_EQ (0u , results[0 ].first );
64
- EXPECT_EQ (' 1' , results[0 ].second );
65
- EXPECT_EQ (1u , results[1 ].first );
66
- EXPECT_EQ (' 2' , results[1 ].second );
67
- EXPECT_EQ (2u , results[2 ].first );
68
- EXPECT_EQ (' 3' , results[2 ].second );
69
-
70
- results.clear ();
62
+ ASSERT_EQ (3u , IntResults.size ());
63
+ EXPECT_EQ (std::make_pair (0u , 1 ), IntResults[0 ]);
64
+ EXPECT_EQ (std::make_pair (1u , 2 ), IntResults[1 ]);
65
+ EXPECT_EQ (std::make_pair (2u , 3 ), IntResults[2 ]);
66
+
67
+ // Test an empty range.
68
+ IntResults.clear ();
71
69
const std::vector<int > baz;
72
70
for (auto X : llvm::enumerate (baz)) {
73
- results. push_back ( std::make_pair ( X.Index , X.Value ) );
71
+ IntResults. emplace_back ( X.Index , X.Value );
74
72
}
75
- EXPECT_TRUE (baz .empty ());
73
+ EXPECT_TRUE (IntResults .empty ());
76
74
}
77
75
78
- TEST (STLExtrasTest, EnumerateModify) {
76
+ TEST (STLExtrasTest, EnumerateModifyLValue) {
77
+ // Test that you can modify the underlying entries of an lvalue range through
78
+ // the enumeration iterator.
79
79
std::vector<char > foo = {' a' , ' b' , ' c' };
80
80
81
81
for (auto X : llvm::enumerate (foo)) {
82
82
++X.Value ;
83
83
}
84
-
85
84
EXPECT_EQ (' b' , foo[0 ]);
86
85
EXPECT_EQ (' c' , foo[1 ]);
87
86
EXPECT_EQ (' d' , foo[2 ]);
88
87
}
88
+
89
+ TEST (STLExtrasTest, EnumerateRValueRef) {
90
+ // Test that an rvalue can be enumerated.
91
+ std::vector<std::pair<std::size_t , int >> Results;
92
+
93
+ auto Enumerator = llvm::enumerate (std::vector<int >{1 , 2 , 3 });
94
+
95
+ for (auto X : llvm::enumerate (std::vector<int >{1 , 2 , 3 })) {
96
+ Results.emplace_back (X.Index , X.Value );
97
+ }
98
+
99
+ ASSERT_EQ (3u , Results.size ());
100
+ EXPECT_EQ (std::make_pair (0u , 1 ), Results[0 ]);
101
+ EXPECT_EQ (std::make_pair (1u , 2 ), Results[1 ]);
102
+ EXPECT_EQ (std::make_pair (2u , 3 ), Results[2 ]);
103
+ }
104
+
105
+ TEST (STLExtrasTest, EnumerateModifyRValue) {
106
+ // Test that when enumerating an rvalue, modification still works (even if
107
+ // this isn't terribly useful, it at least shows that we haven't snuck an
108
+ // extra const in there somewhere.
109
+ std::vector<std::pair<std::size_t , char >> Results;
110
+
111
+ for (auto X : llvm::enumerate (std::vector<char >{' 1' , ' 2' , ' 3' })) {
112
+ ++X.Value ;
113
+ Results.emplace_back (X.Index , X.Value );
114
+ }
115
+
116
+ ASSERT_EQ (3u , Results.size ());
117
+ EXPECT_EQ (std::make_pair (0u , ' 2' ), Results[0 ]);
118
+ EXPECT_EQ (std::make_pair (1u , ' 3' ), Results[1 ]);
119
+ EXPECT_EQ (std::make_pair (2u , ' 4' ), Results[2 ]);
120
+ }
121
+
122
+ template <bool B> struct CanMove {};
123
+ template <> struct CanMove <false > {
124
+ CanMove (CanMove &&) = delete ;
125
+
126
+ CanMove () = default ;
127
+ CanMove (const CanMove &) = default ;
128
+ };
129
+
130
+ template <bool B> struct CanCopy {};
131
+ template <> struct CanCopy <false > {
132
+ CanCopy (const CanCopy &) = delete ;
133
+
134
+ CanCopy () = default ;
135
+ CanCopy (CanCopy &&) = default ;
136
+ };
137
+
138
+ template <bool Moveable, bool Copyable>
139
+ struct Range : CanMove<Moveable>, CanCopy<Copyable> {
140
+ explicit Range (int &C, int &M, int &D) : C(C), M(M), D(D) {}
141
+ Range (const Range &R) : CanCopy<Copyable>(R), C(R.C), M(R.M), D(R.D) { ++C; }
142
+ Range (Range &&R) : CanMove<Moveable>(std::move(R)), C(R.C), M(R.M), D(R.D) {
143
+ ++M;
144
+ }
145
+ ~Range () { ++D; }
146
+
147
+ int &C;
148
+ int &M;
149
+ int &D;
150
+
151
+ int *begin () { return nullptr ; }
152
+ int *end () { return nullptr ; }
153
+ };
154
+
155
+ TEST (STLExtrasTest, EnumerateLifetimeSemantics) {
156
+ // Test that when enumerating lvalues and rvalues, there are no surprise
157
+ // copies or moves.
158
+
159
+ // With an rvalue, it should not be destroyed until the end of the scope.
160
+ int Copies = 0 ;
161
+ int Moves = 0 ;
162
+ int Destructors = 0 ;
163
+ {
164
+ auto E1 = enumerate(Range<true , false >(Copies, Moves, Destructors));
165
+ // Doesn't compile. rvalue ranges must be moveable.
166
+ // auto E2 = enumerate(Range<false, true>(Copies, Moves, Destructors));
167
+ EXPECT_EQ (0 , Copies);
168
+ EXPECT_EQ (1 , Moves);
169
+ EXPECT_EQ (1 , Destructors);
170
+ }
171
+ EXPECT_EQ (0 , Copies);
172
+ EXPECT_EQ (1 , Moves);
173
+ EXPECT_EQ (2 , Destructors);
174
+
175
+ Copies = Moves = Destructors = 0 ;
176
+ // With an lvalue, it should not be destroyed even after the end of the scope.
177
+ // lvalue ranges need be neither copyable nor moveable.
178
+ Range<false , false > R (Copies, Moves, Destructors);
179
+ {
180
+ auto Enumerator = enumerate(R);
181
+ (void )Enumerator;
182
+ EXPECT_EQ (0 , Copies);
183
+ EXPECT_EQ (0 , Moves);
184
+ EXPECT_EQ (0 , Destructors);
185
+ }
186
+ EXPECT_EQ (0 , Copies);
187
+ EXPECT_EQ (0 , Moves);
188
+ EXPECT_EQ (0 , Destructors);
189
+ }
89
190
}
0 commit comments