123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463 |
- /*
- * Copyright 2011-present Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- #include <folly/container/Foreach.h>
- #include <array>
- #include <initializer_list>
- #include <iterator>
- #include <list>
- #include <map>
- #include <string>
- #include <tuple>
- #include <vector>
- #include <folly/portability/GTest.h>
- using namespace folly;
- using namespace folly::detail;
- namespace folly {
- namespace test {
- class TestRValueConstruct {
- public:
- TestRValueConstruct() = default;
- TestRValueConstruct(TestRValueConstruct&&) noexcept {
- this->constructed_from_rvalue = true;
- }
- TestRValueConstruct(const TestRValueConstruct&) {
- this->constructed_from_rvalue = false;
- }
- TestRValueConstruct& operator=(const TestRValueConstruct&) = delete;
- TestRValueConstruct& operator=(TestRValueConstruct&&) = delete;
- bool constructed_from_rvalue{false};
- };
- class TestAdlIterable {
- public:
- std::vector<int> vec{0, 1, 2, 3};
- };
- auto begin(TestAdlIterable& instance) {
- return instance.vec.begin();
- }
- auto begin(const TestAdlIterable& instance) {
- return instance.vec.begin();
- }
- auto end(TestAdlIterable& instance) {
- return instance.vec.end();
- }
- auto end(const TestAdlIterable& instance) {
- return instance.vec.end();
- }
- class TestBothIndexingAndIter {
- public:
- class Iterator {
- public:
- using difference_type = std::size_t;
- using value_type = int;
- using pointer = int*;
- using reference = int&;
- using iterator_category = std::random_access_iterator_tag;
- int& operator*() {
- return this->val;
- }
- Iterator operator+(int) {
- return *this;
- }
- explicit Iterator(int& val_in) : val{val_in} {}
- int& val;
- };
- auto begin() {
- this->called_begin = true;
- return Iterator{val};
- }
- auto end() {
- return Iterator{val};
- }
- int& operator[](int) {
- return this->val;
- }
- int val{0};
- bool called_begin = false;
- };
- } // namespace test
- } // namespace folly
- TEST(Foreach, ForEachFunctionBasic) {
- auto range = std::make_tuple(1, 2, 3);
- auto result_range = std::vector<int>{};
- auto correct_result_range = std::vector<int>{1, 2, 3};
- folly::for_each(range, [&](auto ele) { result_range.push_back(ele); });
- EXPECT_TRUE(std::equal(
- result_range.begin(), result_range.end(), correct_result_range.begin()));
- }
- TEST(Foreach, ForEachFunctionBasicRuntimeOneArg) {
- auto range = std::vector<int>{1, 2, 3};
- auto current = 0;
- folly::for_each(range, [&](auto ele) {
- if (current == 0) {
- EXPECT_EQ(ele, 1);
- } else if (current == 1) {
- EXPECT_EQ(ele, 2);
- } else {
- EXPECT_EQ(ele, 3);
- }
- ++current;
- });
- }
- TEST(Foreach, ForEachFunctionBasicRuntimeTwoArg) {
- auto range = std::vector<int>{1, 2, 3};
- folly::for_each(range, [](auto ele, auto index) {
- EXPECT_TRUE(index < 3);
- if (index == 0) {
- EXPECT_EQ(ele, 1);
- } else if (index == 1) {
- EXPECT_EQ(ele, 2);
- } else if (index == 2) {
- EXPECT_EQ(ele, 3);
- }
- });
- }
- TEST(Foreach, ForEachFunctionBasicRuntimeThreeArg) {
- auto range = std::list<int>{1, 2, 3};
- auto result_range = std::list<int>{1, 3};
- folly::for_each(range, [&](auto ele, auto, auto iter) {
- if (ele == 2) {
- range.erase(iter);
- }
- });
- EXPECT_TRUE(std::equal(range.begin(), range.end(), result_range.begin()));
- }
- TEST(Foreach, ForEachFunctionBasicTupleOneArg) {
- auto range = std::make_tuple(1, 2, 3);
- auto current = 0;
- folly::for_each(range, [&](auto ele) {
- if (current == 0) {
- EXPECT_EQ(ele, 1);
- } else if (current == 1) {
- EXPECT_EQ(ele, 2);
- } else {
- EXPECT_EQ(ele, 3);
- }
- ++current;
- });
- }
- TEST(Foreach, ForEachFunctionBasicTupleTwoArg) {
- auto range = std::make_tuple(1, 2, 3);
- folly::for_each(range, [](auto ele, auto index) {
- EXPECT_TRUE(index < 3);
- if (index == 0) {
- EXPECT_EQ(ele, 1);
- } else if (index == 1) {
- EXPECT_EQ(ele, 2);
- } else if (index == 2) {
- EXPECT_EQ(ele, 3);
- }
- });
- }
- TEST(Foreach, ForEachFunctionBreakRuntimeOneArg) {
- auto range = std::vector<int>{1, 2, 3};
- auto iterations = 0;
- folly::for_each(range, [&](auto) {
- ++iterations;
- if (iterations == 1) {
- return folly::loop_break;
- }
- return folly::loop_continue;
- });
- EXPECT_EQ(iterations, 1);
- }
- TEST(Foreach, ForEachFunctionBreakRuntimeTwoArg) {
- auto range = std::vector<int>{1, 2, 3};
- auto iterations = 0;
- folly::for_each(range, [&](auto, auto index) {
- ++iterations;
- if (index == 1) {
- return folly::loop_break;
- }
- return folly::loop_continue;
- });
- EXPECT_EQ(iterations, 2);
- }
- TEST(Foreach, ForEachFunctionBreakRuntimeThreeArg) {
- auto range = std::vector<int>{1, 2, 3};
- auto iterations = 0;
- folly::for_each(range, [&](auto, auto index, auto) {
- ++iterations;
- if (index == 1) {
- return folly::loop_break;
- }
- return folly::loop_continue;
- });
- EXPECT_EQ(iterations, 2);
- }
- TEST(Foreach, ForEachFunctionBreakTupleOneArg) {
- auto range = std::vector<int>{1, 2, 3};
- auto iterations = 0;
- folly::for_each(range, [&](auto) {
- ++iterations;
- if (iterations == 1) {
- return folly::loop_break;
- }
- return folly::loop_continue;
- });
- EXPECT_EQ(iterations, 1);
- }
- TEST(Foreach, ForEachFunctionBreakTupleTwoArg) {
- auto range = std::vector<int>{1, 2, 3};
- auto iterations = 0;
- folly::for_each(range, [&](auto, auto index) {
- ++iterations;
- if (index == 1) {
- return folly::loop_break;
- }
- return folly::loop_continue;
- });
- EXPECT_EQ(iterations, 2);
- }
- TEST(Foreach, ForEachFunctionArray) {
- auto range = std::array<int, 3>{{1, 2, 3}};
- auto iterations = 0;
- folly::for_each(range, [&](auto, auto index) {
- ++iterations;
- if (index == 1) {
- return folly::loop_break;
- }
- return folly::loop_continue;
- });
- EXPECT_EQ(iterations, 2);
- }
- TEST(Foreach, ForEachFunctionInitializerListBasic) {
- folly::for_each(std::initializer_list<int>{1, 2, 3}, [](auto ele) { ++ele; });
- }
- TEST(Foreach, ForEachFunctionTestForward) {
- using folly::test::TestRValueConstruct;
- auto range_one = std::vector<TestRValueConstruct>{};
- range_one.resize(3);
- folly::for_each(std::move(range_one), [](auto ele) {
- EXPECT_FALSE(ele.constructed_from_rvalue);
- });
- folly::for_each(
- std::make_tuple(TestRValueConstruct{}, TestRValueConstruct{}),
- [](auto ele) { EXPECT_TRUE(ele.constructed_from_rvalue); });
- }
- TEST(Foreach, ForEachFunctionAdlIterable) {
- auto range = test::TestAdlIterable{};
- auto iterations = 0;
- folly::for_each(range, [&](auto ele, auto index) {
- ++iterations;
- EXPECT_EQ(ele, index);
- });
- EXPECT_EQ(iterations, 4);
- }
- TEST(ForEach, FetchRandomAccessIterator) {
- auto vec = std::vector<int>{1, 2, 3};
- auto& second = folly::fetch(vec, 1);
- EXPECT_EQ(second, 2);
- second = 3;
- EXPECT_EQ(second, 3);
- }
- TEST(ForEach, FetchIndexing) {
- auto mp = std::map<int, int>{{1, 2}};
- auto& ele = folly::fetch(mp, 1);
- EXPECT_EQ(ele, 2);
- ele = 3;
- EXPECT_EQ(ele, 3);
- }
- TEST(ForEach, FetchTuple) {
- auto mp = std::make_tuple(1, 2, 3);
- auto& ele = folly::fetch(mp, std::integral_constant<int, 1>{});
- EXPECT_EQ(ele, 2);
- ele = 3;
- EXPECT_EQ(ele, 3);
- }
- TEST(ForEach, FetchTestPreferIterator) {
- auto range = test::TestBothIndexingAndIter{};
- auto& ele = folly::fetch(range, 0);
- EXPECT_TRUE(range.called_begin);
- EXPECT_EQ(ele, 0);
- ele = 2;
- EXPECT_EQ(folly::fetch(range, 0), 2);
- }
- TEST(Foreach, ForEachRvalue) {
- const char* const hello = "hello";
- int n = 0;
- FOR_EACH (it, std::string(hello)) { ++n; }
- EXPECT_EQ(strlen(hello), n);
- FOR_EACH_R (it, std::string(hello)) {
- --n;
- EXPECT_EQ(hello[n], *it);
- }
- EXPECT_EQ(0, n);
- }
- TEST(Foreach, ForEachNested) {
- const std::string hello = "hello";
- size_t n = 0;
- FOR_EACH (i, hello) {
- FOR_EACH (j, hello) { ++n; }
- }
- auto len = hello.size();
- EXPECT_EQ(len * len, n);
- }
- TEST(Foreach, ForEachKV) {
- std::map<std::string, int> testMap;
- testMap["abc"] = 1;
- testMap["def"] = 2;
- std::string keys = "";
- int values = 0;
- int numEntries = 0;
- FOR_EACH_KV (key, value, testMap) {
- keys += key;
- values += value;
- ++numEntries;
- }
- EXPECT_EQ("abcdef", keys);
- EXPECT_EQ(3, values);
- EXPECT_EQ(2, numEntries);
- }
- TEST(Foreach, ForEachKVBreak) {
- std::map<std::string, int> testMap;
- testMap["abc"] = 1;
- testMap["def"] = 2;
- std::string keys = "";
- int values = 0;
- int numEntries = 0;
- FOR_EACH_KV (key, value, testMap) {
- keys += key;
- values += value;
- ++numEntries;
- break;
- }
- EXPECT_EQ("abc", keys);
- EXPECT_EQ(1, values);
- EXPECT_EQ(1, numEntries);
- }
- TEST(Foreach, ForEachKvWithMultiMap) {
- std::multimap<std::string, int> testMap;
- testMap.insert(std::make_pair("abc", 1));
- testMap.insert(std::make_pair("abc", 2));
- testMap.insert(std::make_pair("def", 3));
- std::string keys = "";
- int values = 0;
- int numEntries = 0;
- FOR_EACH_KV (key, value, testMap) {
- keys += key;
- values += value;
- ++numEntries;
- }
- EXPECT_EQ("abcabcdef", keys);
- EXPECT_EQ(6, values);
- EXPECT_EQ(3, numEntries);
- }
- TEST(Foreach, ForEachEnumerate) {
- std::vector<int> vv;
- int sumAA = 0;
- int sumIter = 0;
- int numIterations = 0;
- FOR_EACH_ENUMERATE (aa, iter, vv) {
- sumAA += aa;
- sumIter += *iter;
- ++numIterations;
- }
- EXPECT_EQ(sumAA, 0);
- EXPECT_EQ(sumIter, 0);
- EXPECT_EQ(numIterations, 0);
- vv.push_back(1);
- vv.push_back(3);
- vv.push_back(5);
- FOR_EACH_ENUMERATE (aa, iter, vv) {
- sumAA += aa;
- sumIter += *iter;
- ++numIterations;
- }
- EXPECT_EQ(sumAA, 3); // 0 + 1 + 2
- EXPECT_EQ(sumIter, 9); // 1 + 3 + 5
- EXPECT_EQ(numIterations, 3);
- }
- TEST(Foreach, ForEachEnumerateBreak) {
- std::vector<int> vv;
- int sumAA = 0;
- int sumIter = 0;
- int numIterations = 0;
- vv.push_back(1);
- vv.push_back(2);
- vv.push_back(4);
- vv.push_back(8);
- FOR_EACH_ENUMERATE (aa, iter, vv) {
- sumAA += aa;
- sumIter += *iter;
- ++numIterations;
- if (aa == 1) {
- break;
- }
- }
- EXPECT_EQ(sumAA, 1); // 0 + 1
- EXPECT_EQ(sumIter, 3); // 1 + 2
- EXPECT_EQ(numIterations, 2);
- }
- TEST(Foreach, ForEachRangeR) {
- int sum = 0;
- FOR_EACH_RANGE_R (i, 0, 0) { sum += i; }
- EXPECT_EQ(0, sum);
- FOR_EACH_RANGE_R (i, 0, -1) { sum += i; }
- EXPECT_EQ(0, sum);
- FOR_EACH_RANGE_R (i, 0, 5) { sum += i; }
- EXPECT_EQ(10, sum);
- std::list<int> lst = {0, 1, 2, 3, 4};
- sum = 0;
- FOR_EACH_RANGE_R (i, lst.begin(), lst.end()) { sum += *i; }
- EXPECT_EQ(10, sum);
- }
|