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