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/container/Foreach.h>
20 #include <initializer_list>
28 #include <folly/portability/GTest.h>
30 using namespace folly;
31 using namespace folly::detail;
36 class TestRValueConstruct {
38 TestRValueConstruct() = default;
39 TestRValueConstruct(TestRValueConstruct&&) noexcept {
40 this->constructed_from_rvalue = true;
42 TestRValueConstruct(const TestRValueConstruct&) {
43 this->constructed_from_rvalue = false;
45 TestRValueConstruct& operator=(const TestRValueConstruct&) = delete;
46 TestRValueConstruct& operator=(TestRValueConstruct&&) = delete;
48 bool constructed_from_rvalue{false};
51 class TestAdlIterable {
53 std::vector<int> vec{0, 1, 2, 3};
56 auto begin(TestAdlIterable& instance) {
57 return instance.vec.begin();
59 auto begin(const TestAdlIterable& instance) {
60 return instance.vec.begin();
62 auto end(TestAdlIterable& instance) {
63 return instance.vec.end();
65 auto end(const TestAdlIterable& instance) {
66 return instance.vec.end();
69 class TestBothIndexingAndIter {
73 using difference_type = std::size_t;
74 using value_type = int;
76 using reference = int&;
77 using iterator_category = std::random_access_iterator_tag;
81 Iterator operator+(int) {
84 explicit Iterator(int& val_in) : val{val_in} {}
88 this->called_begin = true;
94 int& operator[](int) {
99 bool called_begin = false;
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};
109 folly::for_each(range, [&](auto ele) { result_range.push_back(ele); });
111 EXPECT_TRUE(std::equal(
112 result_range.begin(), result_range.end(), correct_result_range.begin()));
115 TEST(Foreach, ForEachFunctionBasicRuntimeOneArg) {
116 auto range = std::vector<int>{1, 2, 3};
118 folly::for_each(range, [&](auto ele) {
121 } else if (current == 1) {
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);
136 } else if (index == 1) {
138 } else if (index == 2) {
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) {
152 EXPECT_TRUE(std::equal(range.begin(), range.end(), result_range.begin()));
155 TEST(Foreach, ForEachFunctionBasicTupleOneArg) {
156 auto range = std::make_tuple(1, 2, 3);
158 folly::for_each(range, [&](auto ele) {
161 } else if (current == 1) {
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);
176 } else if (index == 1) {
178 } else if (index == 2) {
184 TEST(Foreach, ForEachFunctionBreakRuntimeOneArg) {
185 auto range = std::vector<int>{1, 2, 3};
187 folly::for_each(range, [&](auto) {
189 if (iterations == 1) {
190 return folly::loop_break;
192 return folly::loop_continue;
194 EXPECT_EQ(iterations, 1);
197 TEST(Foreach, ForEachFunctionBreakRuntimeTwoArg) {
198 auto range = std::vector<int>{1, 2, 3};
200 folly::for_each(range, [&](auto, auto index) {
203 return folly::loop_break;
205 return folly::loop_continue;
207 EXPECT_EQ(iterations, 2);
210 TEST(Foreach, ForEachFunctionBreakRuntimeThreeArg) {
211 auto range = std::vector<int>{1, 2, 3};
213 folly::for_each(range, [&](auto, auto index, auto) {
216 return folly::loop_break;
218 return folly::loop_continue;
220 EXPECT_EQ(iterations, 2);
223 TEST(Foreach, ForEachFunctionBreakTupleOneArg) {
224 auto range = std::vector<int>{1, 2, 3};
226 folly::for_each(range, [&](auto) {
228 if (iterations == 1) {
229 return folly::loop_break;
231 return folly::loop_continue;
233 EXPECT_EQ(iterations, 1);
236 TEST(Foreach, ForEachFunctionBreakTupleTwoArg) {
237 auto range = std::vector<int>{1, 2, 3};
239 folly::for_each(range, [&](auto, auto index) {
242 return folly::loop_break;
244 return folly::loop_continue;
246 EXPECT_EQ(iterations, 2);
249 TEST(Foreach, ForEachFunctionArray) {
250 auto range = std::array<int, 3>{{1, 2, 3}};
252 folly::for_each(range, [&](auto, auto index) {
255 return folly::loop_break;
257 return folly::loop_continue;
259 EXPECT_EQ(iterations, 2);
262 TEST(Foreach, ForEachFunctionInitializerListBasic) {
263 folly::for_each(std::initializer_list<int>{1, 2, 3}, [](auto ele) { ++ele; });
266 TEST(Foreach, ForEachFunctionTestForward) {
267 using folly::test::TestRValueConstruct;
268 auto range_one = std::vector<TestRValueConstruct>{};
271 folly::for_each(std::move(range_one), [](auto ele) {
272 EXPECT_FALSE(ele.constructed_from_rvalue);
276 std::make_tuple(TestRValueConstruct{}, TestRValueConstruct{}),
277 [](auto ele) { EXPECT_TRUE(ele.constructed_from_rvalue); });
280 TEST(Foreach, ForEachFunctionAdlIterable) {
281 auto range = test::TestAdlIterable{};
283 folly::for_each(range, [&](auto ele, auto index) {
285 EXPECT_EQ(ele, index);
287 EXPECT_EQ(iterations, 4);
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);
295 EXPECT_EQ(second, 3);
298 TEST(ForEach, FetchIndexing) {
299 auto mp = std::map<int, int>{{1, 2}};
300 auto& ele = folly::fetch(mp, 1);
306 TEST(ForEach, FetchTuple) {
307 auto mp = std::make_tuple(1, 2, 3);
308 auto& ele = folly::fetch(mp, std::integral_constant<int, 1>{});
314 TEST(ForEach, FetchTestPreferIterator) {
315 auto range = test::TestBothIndexingAndIter{};
316 auto& ele = folly::fetch(range, 0);
317 EXPECT_TRUE(range.called_begin);
320 EXPECT_EQ(folly::fetch(range, 0), 2);
323 TEST(Foreach, ForEachRvalue) {
324 const char* const hello = "hello";
326 FOR_EACH(it, std::string(hello)) {
329 EXPECT_EQ(strlen(hello), n);
330 FOR_EACH_R(it, std::string(hello)) {
332 EXPECT_EQ(hello[n], *it);
337 TEST(Foreach, ForEachNested) {
338 const std::string hello = "hello";
345 auto len = hello.size();
346 EXPECT_EQ(len * len, n);
349 TEST(Foreach, ForEachKV) {
350 std::map<std::string, int> testMap;
353 std::string keys = "";
356 FOR_EACH_KV (key, value, testMap) {
361 EXPECT_EQ("abcdef", keys);
362 EXPECT_EQ(3, values);
363 EXPECT_EQ(2, numEntries);
366 TEST(Foreach, ForEachKVBreak) {
367 std::map<std::string, int> testMap;
370 std::string keys = "";
373 FOR_EACH_KV (key, value, testMap) {
379 EXPECT_EQ("abc", keys);
380 EXPECT_EQ(1, values);
381 EXPECT_EQ(1, numEntries);
384 TEST(Foreach, ForEachKvWithMultiMap) {
385 std::multimap<std::string, int> testMap;
386 testMap.insert(std::make_pair("abc", 1));
387 testMap.insert(std::make_pair("abc", 2));
388 testMap.insert(std::make_pair("def", 3));
389 std::string keys = "";
392 FOR_EACH_KV (key, value, testMap) {
397 EXPECT_EQ("abcabcdef", keys);
398 EXPECT_EQ(6, values);
399 EXPECT_EQ(3, numEntries);
402 TEST(Foreach, ForEachEnumerate) {
406 int numIterations = 0;
407 FOR_EACH_ENUMERATE(aa, iter, vv) {
413 EXPECT_EQ(sumIter, 0);
414 EXPECT_EQ(numIterations, 0);
419 FOR_EACH_ENUMERATE(aa, iter, vv) {
424 EXPECT_EQ(sumAA, 3); // 0 + 1 + 2
425 EXPECT_EQ(sumIter, 9); // 1 + 3 + 5
426 EXPECT_EQ(numIterations, 3);
429 TEST(Foreach, ForEachEnumerateBreak) {
433 int numIterations = 0;
438 FOR_EACH_ENUMERATE(aa, iter, vv) {
446 EXPECT_EQ(sumAA, 1); // 0 + 1
447 EXPECT_EQ(sumIter, 3); // 1 + 2
448 EXPECT_EQ(numIterations, 2);
451 TEST(Foreach, ForEachRangeR) {
454 FOR_EACH_RANGE_R (i, 0, 0) {
459 FOR_EACH_RANGE_R (i, 0, -1) {
464 FOR_EACH_RANGE_R (i, 0, 5) {
469 std::list<int> lst = { 0, 1, 2, 3, 4 };
471 FOR_EACH_RANGE_R (i, lst.begin(), lst.end()) {