adding Promise::await
[folly.git] / folly / experimental / fibers / ForEach-inl.h
1 /*
2  * Copyright 2016 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 #include <folly/experimental/fibers/FiberManager.h>
17
18 namespace folly {
19 namespace fibers {
20
21 namespace {
22
23 template <class F, class G>
24 typename std::enable_if<
25     !std::is_same<typename std::result_of<F()>::type, void>::value,
26     void>::type inline callFuncs(F&& f, G&& g, size_t id) {
27   g(id, f());
28 }
29
30 template <class F, class G>
31 typename std::enable_if<
32     std::is_same<typename std::result_of<F()>::type, void>::value,
33     void>::type inline callFuncs(F&& f, G&& g, size_t id) {
34   f();
35   g(id);
36 }
37
38 } // anonymous namespace
39
40 template <class InputIterator, class F>
41 inline void forEach(InputIterator first, InputIterator last, F&& f) {
42   if (first == last) {
43     return;
44   }
45
46   typedef typename std::iterator_traits<InputIterator>::value_type FuncType;
47
48   size_t tasksTodo = 1;
49   std::exception_ptr e;
50   Baton baton;
51
52 #ifdef __clang__
53 #pragma clang diagnostic push // ignore generalized lambda capture warning
54 #pragma clang diagnostic ignored "-Wc++1y-extensions"
55 #endif
56   auto taskFunc = [&tasksTodo, &e, &f, &baton](size_t id, FuncType&& func) {
57     return [
58       id,
59       &tasksTodo,
60       &e,
61       &f,
62       &baton,
63       func_ = std::forward<FuncType>(func)
64     ]() mutable {
65       try {
66         callFuncs(std::forward<FuncType>(func_), f, id);
67       } catch (...) {
68         e = std::current_exception();
69       }
70       if (--tasksTodo == 0) {
71         baton.post();
72       }
73     };
74   };
75 #ifdef __clang__
76 #pragma clang diagnostic pop
77 #endif
78
79   auto firstTask = first;
80   ++first;
81
82   for (size_t i = 1; first != last; ++i, ++first, ++tasksTodo) {
83     addTask(taskFunc(i, std::move(*first)));
84   }
85
86   taskFunc(0, std::move(*firstTask))();
87   baton.wait();
88
89   if (e != std::exception_ptr()) {
90     std::rethrow_exception(e);
91   }
92 }
93 }
94 } // folly::fibers