2 * Copyright 2017 Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include <folly/Foreach.h>
19 #include <initializer_list>
27 #include <folly/portability/GTest.h>
29 using namespace folly;
30 using namespace folly::detail;
35 class TestRValueConstruct {
37 TestRValueConstruct() = default;
38 TestRValueConstruct(TestRValueConstruct&&) noexcept {
39 this->constructed_from_rvalue = true;
41 TestRValueConstruct(const TestRValueConstruct&) {
42 this->constructed_from_rvalue = false;
44 TestRValueConstruct& operator=(const TestRValueConstruct&) = delete;
45 TestRValueConstruct& operator=(TestRValueConstruct&&) = delete;
47 bool constructed_from_rvalue{false};
50 class TestAdlIterable {
52 std::vector<int> vec{0, 1, 2, 3};
55 auto begin(TestAdlIterable& instance) {
56 return instance.vec.begin();
58 auto begin(const TestAdlIterable& instance) {
59 return instance.vec.begin();
61 auto end(TestAdlIterable& instance) {
62 return instance.vec.end();
64 auto end(const TestAdlIterable& instance) {
65 return instance.vec.end();
68 class TestBothIndexingAndIter {
72 using difference_type = std::size_t;
73 using value_type = int;
75 using reference = int&;
76 using iterator_category = std::random_access_iterator_tag;
80 Iterator operator+(int) {
83 explicit Iterator(int& val_in) : val{val_in} {}
87 this->called_begin = true;
93 int& operator[](int) {
98 bool called_begin = false;
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};
108 folly::for_each(range, [&](auto ele) { result_range.push_back(ele); });
110 EXPECT_TRUE(std::equal(
111 result_range.begin(), result_range.end(), correct_result_range.begin()));
114 TEST(Foreach, ForEachFunctionBasicRuntimeOneArg) {
115 auto range = std::vector<int>{1, 2, 3};
117 folly::for_each(range, [&](auto ele) {
120 } else if (current == 1) {
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);
135 } else if (index == 1) {
137 } else if (index == 2) {
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) {
151 EXPECT_TRUE(std::equal(range.begin(), range.end(), result_range.begin()));
154 TEST(Foreach, ForEachFunctionBasicTupleOneArg) {
155 auto range = std::make_tuple(1, 2, 3);
157 folly::for_each(range, [&](auto ele) {
160 } else if (current == 1) {
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);
175 } else if (index == 1) {
177 } else if (index == 2) {
183 TEST(Foreach, ForEachFunctionBreakRuntimeOneArg) {
184 auto range = std::vector<int>{1, 2, 3};
186 folly::for_each(range, [&](auto) {
188 if (iterations == 1) {
189 return folly::loop_break;
191 return folly::loop_continue;
193 EXPECT_EQ(iterations, 1);
196 TEST(Foreach, ForEachFunctionBreakRuntimeTwoArg) {
197 auto range = std::vector<int>{1, 2, 3};
199 folly::for_each(range, [&](auto, auto index) {
202 return folly::loop_break;
204 return folly::loop_continue;
206 EXPECT_EQ(iterations, 2);
209 TEST(Foreach, ForEachFunctionBreakRuntimeThreeArg) {
210 auto range = std::vector<int>{1, 2, 3};
212 folly::for_each(range, [&](auto, auto index, auto) {
215 return folly::loop_break;
217 return folly::loop_continue;
219 EXPECT_EQ(iterations, 2);
222 TEST(Foreach, ForEachFunctionBreakTupleOneArg) {
223 auto range = std::vector<int>{1, 2, 3};
225 folly::for_each(range, [&](auto) {
227 if (iterations == 1) {
228 return folly::loop_break;
230 return folly::loop_continue;
232 EXPECT_EQ(iterations, 1);
235 TEST(Foreach, ForEachFunctionBreakTupleTwoArg) {
236 auto range = std::vector<int>{1, 2, 3};
238 folly::for_each(range, [&](auto, auto index) {
241 return folly::loop_break;
243 return folly::loop_continue;
245 EXPECT_EQ(iterations, 2);
248 TEST(Foreach, ForEachFunctionArray) {
249 auto range = std::array<int, 3>{{1, 2, 3}};
251 folly::for_each(range, [&](auto, auto index) {
254 return folly::loop_break;
256 return folly::loop_continue;
258 EXPECT_EQ(iterations, 2);
261 TEST(Foreach, ForEachFunctionInitializerListBasic) {
262 folly::for_each(std::initializer_list<int>{1, 2, 3}, [](auto ele) { ++ele; });
265 TEST(Foreach, ForEachFunctionTestForward) {
266 using folly::test::TestRValueConstruct;
267 auto range_one = std::vector<TestRValueConstruct>{};
270 folly::for_each(std::move(range_one), [](auto ele) {
271 EXPECT_FALSE(ele.constructed_from_rvalue);
275 std::make_tuple(TestRValueConstruct{}, TestRValueConstruct{}),
276 [](auto ele) { EXPECT_TRUE(ele.constructed_from_rvalue); });
279 TEST(Foreach, ForEachFunctionAdlIterable) {
280 auto range = test::TestAdlIterable{};
282 folly::for_each(range, [&](auto ele, auto index) {
284 EXPECT_EQ(ele, index);
286 EXPECT_EQ(iterations, 4);
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);
294 EXPECT_EQ(second, 3);
297 TEST(ForEach, FetchIndexing) {
298 auto mp = std::map<int, int>{{1, 2}};
299 auto& ele = folly::fetch(mp, 1);
305 TEST(ForEach, FetchTuple) {
306 auto mp = std::make_tuple(1, 2, 3);
307 auto& ele = folly::fetch(mp, std::integral_constant<int, 1>{});
313 TEST(ForEach, FetchTestPreferIterator) {
314 auto range = test::TestBothIndexingAndIter{};
315 auto& ele = folly::fetch(range, 0);
316 EXPECT_TRUE(range.called_begin);
319 EXPECT_EQ(folly::fetch(range, 0), 2);
322 TEST(Foreach, ForEachRvalue) {
323 const char* const hello = "hello";
325 FOR_EACH(it, std::string(hello)) {
328 EXPECT_EQ(strlen(hello), n);
329 FOR_EACH_R(it, std::string(hello)) {
331 EXPECT_EQ(hello[n], *it);
336 TEST(Foreach, ForEachNested) {
337 const std::string hello = "hello";
344 auto len = hello.size();
345 EXPECT_EQ(len * len, n);
348 TEST(Foreach, ForEachKV) {
349 std::map<std::string, int> testMap;
352 std::string keys = "";
355 FOR_EACH_KV (key, value, testMap) {
360 EXPECT_EQ("abcdef", keys);
361 EXPECT_EQ(3, values);
362 EXPECT_EQ(2, numEntries);
365 TEST(Foreach, ForEachKVBreak) {
366 std::map<std::string, int> testMap;
369 std::string keys = "";
372 FOR_EACH_KV (key, value, testMap) {
378 EXPECT_EQ("abc", keys);
379 EXPECT_EQ(1, values);
380 EXPECT_EQ(1, numEntries);
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 = "";
391 FOR_EACH_KV (key, value, testMap) {
396 EXPECT_EQ("abcabcdef", keys);
397 EXPECT_EQ(6, values);
398 EXPECT_EQ(3, numEntries);
401 TEST(Foreach, ForEachEnumerate) {
405 int numIterations = 0;
406 FOR_EACH_ENUMERATE(aa, iter, vv) {
412 EXPECT_EQ(sumIter, 0);
413 EXPECT_EQ(numIterations, 0);
418 FOR_EACH_ENUMERATE(aa, iter, vv) {
423 EXPECT_EQ(sumAA, 3); // 0 + 1 + 2
424 EXPECT_EQ(sumIter, 9); // 1 + 3 + 5
425 EXPECT_EQ(numIterations, 3);
428 TEST(Foreach, ForEachEnumerateBreak) {
432 int numIterations = 0;
437 FOR_EACH_ENUMERATE(aa, iter, vv) {
443 EXPECT_EQ(sumAA, 1); // 0 + 1
444 EXPECT_EQ(sumIter, 3); // 1 + 2
445 EXPECT_EQ(numIterations, 2);
448 TEST(Foreach, ForEachRangeR) {
451 FOR_EACH_RANGE_R (i, 0, 0) {
456 FOR_EACH_RANGE_R (i, 0, -1) {
461 FOR_EACH_RANGE_R (i, 0, 5) {
466 std::list<int> lst = { 0, 1, 2, 3, 4 };
468 FOR_EACH_RANGE_R (i, lst.begin(), lst.end()) {