2 * Copyright 2014 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 <folly/Benchmark.h>
20 #include <gtest/gtest.h>
26 using namespace folly;
27 using namespace folly::detail;
29 TEST(Foreach, ForEachRvalue) {
30 const char* const hello = "hello";
32 FOR_EACH(it, std::string(hello)) {
35 EXPECT_EQ(strlen(hello), n);
36 FOR_EACH_R(it, std::string(hello)) {
38 EXPECT_EQ(hello[n], *it);
43 TEST(Foreach, ForEachKV) {
44 std::map<std::string, int> testMap;
47 std::string keys = "";
50 FOR_EACH_KV (key, value, testMap) {
55 EXPECT_EQ("abcdef", keys);
57 EXPECT_EQ(2, numEntries);
60 TEST(Foreach, ForEachKVBreak) {
61 std::map<std::string, int> testMap;
64 std::string keys = "";
67 FOR_EACH_KV (key, value, testMap) {
73 EXPECT_EQ("abc", keys);
75 EXPECT_EQ(1, numEntries);
78 TEST(Foreach, ForEachKvWithMultiMap) {
79 std::multimap<std::string, int> testMap;
80 testMap.insert(std::make_pair("abc", 1));
81 testMap.insert(std::make_pair("abc", 2));
82 testMap.insert(std::make_pair("def", 3));
83 std::string keys = "";
86 FOR_EACH_KV (key, value, testMap) {
91 EXPECT_EQ("abcabcdef", keys);
93 EXPECT_EQ(3, numEntries);
96 TEST(Foreach, ForEachEnumerate) {
100 int numIterations = 0;
101 FOR_EACH_ENUMERATE(aa, iter, vv) {
107 EXPECT_EQ(sumIter, 0);
108 EXPECT_EQ(numIterations, 0);
113 FOR_EACH_ENUMERATE(aa, iter, vv) {
118 EXPECT_EQ(sumAA, 3); // 0 + 1 + 2
119 EXPECT_EQ(sumIter, 9); // 1 + 3 + 5
120 EXPECT_EQ(numIterations, 3);
123 TEST(Foreach, ForEachEnumerateBreak) {
127 int numIterations = 0;
132 FOR_EACH_ENUMERATE(aa, iter, vv) {
138 EXPECT_EQ(sumAA, 1); // 0 + 1
139 EXPECT_EQ(sumIter, 3); // 1 + 2
140 EXPECT_EQ(numIterations, 2);
143 TEST(Foreach, ForEachRangeR) {
146 FOR_EACH_RANGE_R (i, 0, 0) {
151 FOR_EACH_RANGE_R (i, 0, -1) {
156 FOR_EACH_RANGE_R (i, 0, 5) {
161 std::list<int> lst = { 0, 1, 2, 3, 4 };
163 FOR_EACH_RANGE_R (i, lst.begin(), lst.end()) {
170 // 1. Benchmark iterating through the man with FOR_EACH, and also assign
171 // iter->first and iter->second to local vars inside the FOR_EACH loop.
172 // 2. Benchmark iterating through the man with FOR_EACH, but use iter->first and
173 // iter->second as is, without assigning to local variables.
174 // 3. Use FOR_EACH_KV loop to iterate through the map.
176 std::map<int, std::string> bmMap; // For use in benchmarks below.
178 void setupBenchmark(int iters) {
180 for (int i = 0; i < iters; ++i) {
181 bmMap[i] = "teststring";
185 BENCHMARK(ForEachKVNoMacroAssign, iters) {
187 std::string sumValues;
190 setupBenchmark(iters);
192 std::string sumValues = "";
195 FOR_EACH (iter, bmMap) {
196 const int k = iter->first;
197 const std::string v = iter->second;
203 BENCHMARK(ForEachKVNoMacroNoAssign, iters) {
205 std::string sumValues;
208 setupBenchmark(iters);
211 FOR_EACH (iter, bmMap) {
212 sumKeys += iter->first;
213 sumValues += iter->second;
217 BENCHMARK(ManualLoopNoAssign, iters) {
219 setupBenchmark(iters);
222 std::string sumValues;
224 for (auto iter = bmMap.begin(); iter != bmMap.end(); ++iter) {
225 sumKeys += iter->first;
226 sumValues += iter->second;
230 BENCHMARK(ForEachKVMacro, iters) {
232 setupBenchmark(iters);
235 std::string sumValues;
237 FOR_EACH_KV (k, v, bmMap) {
243 BENCHMARK(ForEachManual, iters) {
245 for (auto i = 1; i < iters; ++i) {
248 doNotOptimizeAway(sum);
251 BENCHMARK(ForEachRange, iters) {
253 FOR_EACH_RANGE (i, 1, iters) {
256 doNotOptimizeAway(sum);
259 BENCHMARK(ForEachDescendingManual, iters) {
261 for (auto i = iters; i-- > 1; ) {
264 doNotOptimizeAway(sum);
267 BENCHMARK(ForEachRangeR, iters) {
269 FOR_EACH_RANGE_R (i, 1, iters) {
272 doNotOptimizeAway(sum);
275 int main(int argc, char** argv) {
276 testing::InitGoogleTest(&argc, argv);
277 auto r = RUN_ALL_TESTS();