proxygen
ForeachTest.cpp
Go to the documentation of this file.
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 
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 
29 
30 using namespace folly;
31 using namespace folly::detail;
32 
33 namespace folly {
34 namespace test {
35 
37  public:
38  TestRValueConstruct() = default;
40  this->constructed_from_rvalue = true;
41  }
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 
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 
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  }
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) {
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 
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) {
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 }
std::atomic< int64_t > sum(0)
#define FOR_EACH_KV(k, v, c)
Definition: Foreach.h:197
auto begin(const TestAdlIterable &instance)
Definition: ForeachTest.cpp:59
void testMap()
constexpr auto loop_continue
Definition: Foreach.h:98
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
double val
Definition: String.cpp:273
TestRValueConstruct(const TestRValueConstruct &)
Definition: ForeachTest.cpp:42
#define FOR_EACH_R(i, c)
Definition: Foreach.h:156
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
requires E e noexcept(noexcept(s.error(std::move(e))))
tuple make_tuple()
Definition: gtest-tuple.h:675
std::vector< int > vec
Definition: ForeachTest.cpp:53
int current
constexpr Range< Iter > range(Iter first, Iter last)
Definition: Range.h:1114
Definition: Traits.h:588
std::random_access_iterator_tag iterator_category
Definition: ForeachTest.cpp:77
#define FOR_EACH_ENUMERATE(count, i, c)
Definition: Foreach.h:170
#define EXPECT_TRUE(condition)
Definition: gtest.h:1859
#define FOR_EACH(i, c)
Definition: Foreach.h:143
TestRValueConstruct(TestRValueConstruct &&) noexcept
Definition: ForeachTest.cpp:39
const char * string
Definition: Conv.cpp:212
uint64_t value(const typename LockFreeRingBuffer< T, Atom >::Cursor &rbcursor)
#define EXPECT_FALSE(condition)
Definition: gtest.h:1862
decltype(auto) FOLLY_CPP14_CONSTEXPR fetch(Sequence &&sequence, Index &&index)
Definition: Foreach-inl.h:322
void ForEach(const Container &c, Functor functor)
#define FOR_EACH_RANGE_R(i, begin, end)
Definition: Foreach.h:324
TEST(SequencedExecutor, CPUThreadPoolExecutor)
constexpr auto loop_break
Definition: Foreach.h:97
FOLLY_CPP14_CONSTEXPR Func for_each(Sequence &&sequence, Func func)
Definition: Foreach-inl.h:314
auto end(const TestAdlIterable &instance)
Definition: ForeachTest.cpp:65
std::vector< int > values(1'000)