1 | /* |
2 | * Copyright 2011-present Facebook, Inc. |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. |
6 | * You may obtain a copy of the License at |
7 | * |
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | * |
10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. |
15 | */ |
16 | |
17 | #include <folly/container/Foreach.h> |
18 | |
19 | #include <array> |
20 | #include <initializer_list> |
21 | #include <iterator> |
22 | #include <list> |
23 | #include <map> |
24 | #include <string> |
25 | #include <tuple> |
26 | #include <vector> |
27 | |
28 | #include <folly/portability/GTest.h> |
29 | |
30 | using namespace folly; |
31 | using namespace folly::detail; |
32 | |
33 | namespace folly { |
34 | namespace test { |
35 | |
36 | class TestRValueConstruct { |
37 | public: |
38 | TestRValueConstruct() = default; |
39 | TestRValueConstruct(TestRValueConstruct&&) noexcept { |
40 | this->constructed_from_rvalue = true; |
41 | } |
42 | TestRValueConstruct(const TestRValueConstruct&) { |
43 | this->constructed_from_rvalue = false; |
44 | } |
45 | TestRValueConstruct& operator=(const TestRValueConstruct&) = delete; |
46 | TestRValueConstruct& operator=(TestRValueConstruct&&) = delete; |
47 | |
48 | bool constructed_from_rvalue{false}; |
49 | }; |
50 | |
51 | class TestAdlIterable { |
52 | public: |
53 | std::vector<int> vec{0, 1, 2, 3}; |
54 | }; |
55 | |
56 | auto begin(TestAdlIterable& instance) { |
57 | return instance.vec.begin(); |
58 | } |
59 | auto begin(const TestAdlIterable& instance) { |
60 | return instance.vec.begin(); |
61 | } |
62 | auto end(TestAdlIterable& instance) { |
63 | return instance.vec.end(); |
64 | } |
65 | auto end(const TestAdlIterable& instance) { |
66 | return instance.vec.end(); |
67 | } |
68 | |
69 | class TestBothIndexingAndIter { |
70 | public: |
71 | class Iterator { |
72 | public: |
73 | using difference_type = std::size_t; |
74 | using value_type = int; |
75 | using pointer = int*; |
76 | using reference = int&; |
77 | using iterator_category = std::random_access_iterator_tag; |
78 | int& operator*() { |
79 | return this->val; |
80 | } |
81 | Iterator operator+(int) { |
82 | return *this; |
83 | } |
84 | explicit Iterator(int& val_in) : val{val_in} {} |
85 | int& val; |
86 | }; |
87 | auto begin() { |
88 | this->called_begin = true; |
89 | return Iterator{val}; |
90 | } |
91 | auto end() { |
92 | return Iterator{val}; |
93 | } |
94 | int& operator[](int) { |
95 | return this->val; |
96 | } |
97 | |
98 | int val{0}; |
99 | bool called_begin = false; |
100 | }; |
101 | } // namespace test |
102 | } // namespace folly |
103 | |
104 | TEST(Foreach, ForEachFunctionBasic) { |
105 | auto range = std::make_tuple(1, 2, 3); |
106 | auto result_range = std::vector<int>{}; |
107 | auto correct_result_range = std::vector<int>{1, 2, 3}; |
108 | |
109 | folly::for_each(range, [&](auto ele) { result_range.push_back(ele); }); |
110 | |
111 | EXPECT_TRUE(std::equal( |
112 | result_range.begin(), result_range.end(), correct_result_range.begin())); |
113 | } |
114 | |
115 | TEST(Foreach, ForEachFunctionBasicRuntimeOneArg) { |
116 | auto range = std::vector<int>{1, 2, 3}; |
117 | auto current = 0; |
118 | folly::for_each(range, [&](auto ele) { |
119 | if (current == 0) { |
120 | EXPECT_EQ(ele, 1); |
121 | } else if (current == 1) { |
122 | EXPECT_EQ(ele, 2); |
123 | } else { |
124 | EXPECT_EQ(ele, 3); |
125 | } |
126 | ++current; |
127 | }); |
128 | } |
129 | |
130 | TEST(Foreach, ForEachFunctionBasicRuntimeTwoArg) { |
131 | auto range = std::vector<int>{1, 2, 3}; |
132 | folly::for_each(range, [](auto ele, auto index) { |
133 | EXPECT_TRUE(index < 3); |
134 | if (index == 0) { |
135 | EXPECT_EQ(ele, 1); |
136 | } else if (index == 1) { |
137 | EXPECT_EQ(ele, 2); |
138 | } else if (index == 2) { |
139 | EXPECT_EQ(ele, 3); |
140 | } |
141 | }); |
142 | } |
143 | |
144 | TEST(Foreach, ForEachFunctionBasicRuntimeThreeArg) { |
145 | auto range = std::list<int>{1, 2, 3}; |
146 | auto result_range = std::list<int>{1, 3}; |
147 | folly::for_each(range, [&](auto ele, auto, auto iter) { |
148 | if (ele == 2) { |
149 | range.erase(iter); |
150 | } |
151 | }); |
152 | EXPECT_TRUE(std::equal(range.begin(), range.end(), result_range.begin())); |
153 | } |
154 | |
155 | TEST(Foreach, ForEachFunctionBasicTupleOneArg) { |
156 | auto range = std::make_tuple(1, 2, 3); |
157 | auto current = 0; |
158 | folly::for_each(range, [&](auto ele) { |
159 | if (current == 0) { |
160 | EXPECT_EQ(ele, 1); |
161 | } else if (current == 1) { |
162 | EXPECT_EQ(ele, 2); |
163 | } else { |
164 | EXPECT_EQ(ele, 3); |
165 | } |
166 | ++current; |
167 | }); |
168 | } |
169 | |
170 | TEST(Foreach, ForEachFunctionBasicTupleTwoArg) { |
171 | auto range = std::make_tuple(1, 2, 3); |
172 | folly::for_each(range, [](auto ele, auto index) { |
173 | EXPECT_TRUE(index < 3); |
174 | if (index == 0) { |
175 | EXPECT_EQ(ele, 1); |
176 | } else if (index == 1) { |
177 | EXPECT_EQ(ele, 2); |
178 | } else if (index == 2) { |
179 | EXPECT_EQ(ele, 3); |
180 | } |
181 | }); |
182 | } |
183 | |
184 | TEST(Foreach, ForEachFunctionBreakRuntimeOneArg) { |
185 | auto range = std::vector<int>{1, 2, 3}; |
186 | auto iterations = 0; |
187 | folly::for_each(range, [&](auto) { |
188 | ++iterations; |
189 | if (iterations == 1) { |
190 | return folly::loop_break; |
191 | } |
192 | return folly::loop_continue; |
193 | }); |
194 | EXPECT_EQ(iterations, 1); |
195 | } |
196 | |
197 | TEST(Foreach, ForEachFunctionBreakRuntimeTwoArg) { |
198 | auto range = std::vector<int>{1, 2, 3}; |
199 | auto iterations = 0; |
200 | folly::for_each(range, [&](auto, auto index) { |
201 | ++iterations; |
202 | if (index == 1) { |
203 | return folly::loop_break; |
204 | } |
205 | return folly::loop_continue; |
206 | }); |
207 | EXPECT_EQ(iterations, 2); |
208 | } |
209 | |
210 | TEST(Foreach, ForEachFunctionBreakRuntimeThreeArg) { |
211 | auto range = std::vector<int>{1, 2, 3}; |
212 | auto iterations = 0; |
213 | folly::for_each(range, [&](auto, auto index, auto) { |
214 | ++iterations; |
215 | if (index == 1) { |
216 | return folly::loop_break; |
217 | } |
218 | return folly::loop_continue; |
219 | }); |
220 | EXPECT_EQ(iterations, 2); |
221 | } |
222 | |
223 | TEST(Foreach, ForEachFunctionBreakTupleOneArg) { |
224 | auto range = std::vector<int>{1, 2, 3}; |
225 | auto iterations = 0; |
226 | folly::for_each(range, [&](auto) { |
227 | ++iterations; |
228 | if (iterations == 1) { |
229 | return folly::loop_break; |
230 | } |
231 | return folly::loop_continue; |
232 | }); |
233 | EXPECT_EQ(iterations, 1); |
234 | } |
235 | |
236 | TEST(Foreach, ForEachFunctionBreakTupleTwoArg) { |
237 | auto range = std::vector<int>{1, 2, 3}; |
238 | auto iterations = 0; |
239 | folly::for_each(range, [&](auto, auto index) { |
240 | ++iterations; |
241 | if (index == 1) { |
242 | return folly::loop_break; |
243 | } |
244 | return folly::loop_continue; |
245 | }); |
246 | EXPECT_EQ(iterations, 2); |
247 | } |
248 | |
249 | TEST(Foreach, ForEachFunctionArray) { |
250 | auto range = std::array<int, 3>{{1, 2, 3}}; |
251 | auto iterations = 0; |
252 | folly::for_each(range, [&](auto, auto index) { |
253 | ++iterations; |
254 | if (index == 1) { |
255 | return folly::loop_break; |
256 | } |
257 | return folly::loop_continue; |
258 | }); |
259 | EXPECT_EQ(iterations, 2); |
260 | } |
261 | |
262 | TEST(Foreach, ForEachFunctionInitializerListBasic) { |
263 | folly::for_each(std::initializer_list<int>{1, 2, 3}, [](auto ele) { ++ele; }); |
264 | } |
265 | |
266 | TEST(Foreach, ForEachFunctionTestForward) { |
267 | using folly::test::TestRValueConstruct; |
268 | auto range_one = std::vector<TestRValueConstruct>{}; |
269 | range_one.resize(3); |
270 | |
271 | folly::for_each(std::move(range_one), [](auto ele) { |
272 | EXPECT_FALSE(ele.constructed_from_rvalue); |
273 | }); |
274 | |
275 | folly::for_each( |
276 | std::make_tuple(TestRValueConstruct{}, TestRValueConstruct{}), |
277 | [](auto ele) { EXPECT_TRUE(ele.constructed_from_rvalue); }); |
278 | } |
279 | |
280 | TEST(Foreach, ForEachFunctionAdlIterable) { |
281 | auto range = test::TestAdlIterable{}; |
282 | auto iterations = 0; |
283 | folly::for_each(range, [&](auto ele, auto index) { |
284 | ++iterations; |
285 | EXPECT_EQ(ele, index); |
286 | }); |
287 | EXPECT_EQ(iterations, 4); |
288 | } |
289 | |
290 | TEST(ForEach, FetchRandomAccessIterator) { |
291 | auto vec = std::vector<int>{1, 2, 3}; |
292 | auto& second = folly::fetch(vec, 1); |
293 | EXPECT_EQ(second, 2); |
294 | second = 3; |
295 | EXPECT_EQ(second, 3); |
296 | } |
297 | |
298 | TEST(ForEach, FetchIndexing) { |
299 | auto mp = std::map<int, int>{{1, 2}}; |
300 | auto& ele = folly::fetch(mp, 1); |
301 | EXPECT_EQ(ele, 2); |
302 | ele = 3; |
303 | EXPECT_EQ(ele, 3); |
304 | } |
305 | |
306 | TEST(ForEach, FetchTuple) { |
307 | auto mp = std::make_tuple(1, 2, 3); |
308 | auto& ele = folly::fetch(mp, std::integral_constant<int, 1>{}); |
309 | EXPECT_EQ(ele, 2); |
310 | ele = 3; |
311 | EXPECT_EQ(ele, 3); |
312 | } |
313 | |
314 | TEST(ForEach, FetchTestPreferIterator) { |
315 | auto range = test::TestBothIndexingAndIter{}; |
316 | auto& ele = folly::fetch(range, 0); |
317 | EXPECT_TRUE(range.called_begin); |
318 | EXPECT_EQ(ele, 0); |
319 | ele = 2; |
320 | EXPECT_EQ(folly::fetch(range, 0), 2); |
321 | } |
322 | |
323 | TEST(Foreach, ForEachRvalue) { |
324 | const char* const hello = "hello" ; |
325 | int n = 0; |
326 | FOR_EACH (it, std::string(hello)) { ++n; } |
327 | EXPECT_EQ(strlen(hello), n); |
328 | FOR_EACH_R (it, std::string(hello)) { |
329 | --n; |
330 | EXPECT_EQ(hello[n], *it); |
331 | } |
332 | EXPECT_EQ(0, n); |
333 | } |
334 | |
335 | TEST(Foreach, ForEachNested) { |
336 | const std::string hello = "hello" ; |
337 | size_t n = 0; |
338 | FOR_EACH (i, hello) { |
339 | FOR_EACH (j, hello) { ++n; } |
340 | } |
341 | auto len = hello.size(); |
342 | EXPECT_EQ(len * len, n); |
343 | } |
344 | |
345 | TEST(Foreach, ForEachKV) { |
346 | std::map<std::string, int> testMap; |
347 | testMap["abc" ] = 1; |
348 | testMap["def" ] = 2; |
349 | std::string keys = "" ; |
350 | int values = 0; |
351 | int numEntries = 0; |
352 | FOR_EACH_KV (key, value, testMap) { |
353 | keys += key; |
354 | values += value; |
355 | ++numEntries; |
356 | } |
357 | EXPECT_EQ("abcdef" , keys); |
358 | EXPECT_EQ(3, values); |
359 | EXPECT_EQ(2, numEntries); |
360 | } |
361 | |
362 | TEST(Foreach, ForEachKVBreak) { |
363 | std::map<std::string, int> testMap; |
364 | testMap["abc" ] = 1; |
365 | testMap["def" ] = 2; |
366 | std::string keys = "" ; |
367 | int values = 0; |
368 | int numEntries = 0; |
369 | FOR_EACH_KV (key, value, testMap) { |
370 | keys += key; |
371 | values += value; |
372 | ++numEntries; |
373 | break; |
374 | } |
375 | EXPECT_EQ("abc" , keys); |
376 | EXPECT_EQ(1, values); |
377 | EXPECT_EQ(1, numEntries); |
378 | } |
379 | |
380 | TEST(Foreach, ForEachKvWithMultiMap) { |
381 | std::multimap<std::string, int> testMap; |
382 | testMap.insert(std::make_pair("abc" , 1)); |
383 | testMap.insert(std::make_pair("abc" , 2)); |
384 | testMap.insert(std::make_pair("def" , 3)); |
385 | std::string keys = "" ; |
386 | int values = 0; |
387 | int numEntries = 0; |
388 | FOR_EACH_KV (key, value, testMap) { |
389 | keys += key; |
390 | values += value; |
391 | ++numEntries; |
392 | } |
393 | EXPECT_EQ("abcabcdef" , keys); |
394 | EXPECT_EQ(6, values); |
395 | EXPECT_EQ(3, numEntries); |
396 | } |
397 | |
398 | TEST(Foreach, ForEachEnumerate) { |
399 | std::vector<int> vv; |
400 | int sumAA = 0; |
401 | int sumIter = 0; |
402 | int numIterations = 0; |
403 | FOR_EACH_ENUMERATE (aa, iter, vv) { |
404 | sumAA += aa; |
405 | sumIter += *iter; |
406 | ++numIterations; |
407 | } |
408 | EXPECT_EQ(sumAA, 0); |
409 | EXPECT_EQ(sumIter, 0); |
410 | EXPECT_EQ(numIterations, 0); |
411 | |
412 | vv.push_back(1); |
413 | vv.push_back(3); |
414 | vv.push_back(5); |
415 | FOR_EACH_ENUMERATE (aa, iter, vv) { |
416 | sumAA += aa; |
417 | sumIter += *iter; |
418 | ++numIterations; |
419 | } |
420 | EXPECT_EQ(sumAA, 3); // 0 + 1 + 2 |
421 | EXPECT_EQ(sumIter, 9); // 1 + 3 + 5 |
422 | EXPECT_EQ(numIterations, 3); |
423 | } |
424 | |
425 | TEST(Foreach, ForEachEnumerateBreak) { |
426 | std::vector<int> vv; |
427 | int sumAA = 0; |
428 | int sumIter = 0; |
429 | int numIterations = 0; |
430 | vv.push_back(1); |
431 | vv.push_back(2); |
432 | vv.push_back(4); |
433 | vv.push_back(8); |
434 | FOR_EACH_ENUMERATE (aa, iter, vv) { |
435 | sumAA += aa; |
436 | sumIter += *iter; |
437 | ++numIterations; |
438 | if (aa == 1) { |
439 | break; |
440 | } |
441 | } |
442 | EXPECT_EQ(sumAA, 1); // 0 + 1 |
443 | EXPECT_EQ(sumIter, 3); // 1 + 2 |
444 | EXPECT_EQ(numIterations, 2); |
445 | } |
446 | |
447 | TEST(Foreach, ForEachRangeR) { |
448 | int sum = 0; |
449 | |
450 | FOR_EACH_RANGE_R (i, 0, 0) { sum += i; } |
451 | EXPECT_EQ(0, sum); |
452 | |
453 | FOR_EACH_RANGE_R (i, 0, -1) { sum += i; } |
454 | EXPECT_EQ(0, sum); |
455 | |
456 | FOR_EACH_RANGE_R (i, 0, 5) { sum += i; } |
457 | EXPECT_EQ(10, sum); |
458 | |
459 | std::list<int> lst = {0, 1, 2, 3, 4}; |
460 | sum = 0; |
461 | FOR_EACH_RANGE_R (i, lst.begin(), lst.end()) { sum += *i; } |
462 | EXPECT_EQ(10, sum); |
463 | } |
464 | |