2 * Copyright 2015 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.
16 #include <folly/Optional.h>
18 #include <folly/experimental/fibers/FiberManager.h>
19 #include <folly/experimental/fibers/ForEach.h>
21 namespace folly { namespace fibers {
23 template <class InputIterator>
25 typename std::enable_if<
27 typename std::result_of<
28 typename std::iterator_traits<InputIterator>::value_type()>::type, void
32 typename std::result_of<
33 typename std::iterator_traits<InputIterator>::value_type()>::type>
36 collectN(InputIterator first, InputIterator last, size_t n) {
37 typedef typename std::result_of<
38 typename std::iterator_traits<InputIterator>::value_type()>::type Result;
40 assert(std::distance(first, last) >= 0);
41 assert(n <= static_cast<size_t>(std::distance(first, last)));
44 std::vector<std::pair<size_t, Result>> results;
47 folly::Optional<Promise<void>> promise;
49 Context(size_t tasksTodo_) : tasksTodo(tasksTodo_) {
50 this->results.reserve(tasksTodo_);
53 auto context = std::make_shared<Context>(n);
56 [first, last, context](Promise<void> promise) mutable {
57 context->promise = std::move(promise);
58 for (size_t i = 0; first != last; ++i, ++first) {
60 #pragma clang diagnostic push // ignore generalized lambda capture warning
61 #pragma clang diagnostic ignored "-Wc++1y-extensions"
64 [i, context, f = std::move(*first)]() {
67 if (context->tasksTodo == 0) {
70 context->results.emplace_back(i, std::move(result));
72 if (context->tasksTodo == 0) {
75 context->e = std::current_exception();
77 if (--context->tasksTodo == 0) {
78 context->promise->setValue();
82 #pragma clang diagnostic pop
87 if (context->e != std::exception_ptr()) {
88 std::rethrow_exception(context->e);
91 return std::move(context->results);
94 template <class InputIterator>
95 typename std::enable_if<
97 typename std::result_of<
98 typename std::iterator_traits<InputIterator>::value_type()>::type, void
99 >::value, std::vector<size_t>>::type
100 collectN(InputIterator first, InputIterator last, size_t n) {
102 assert(std::distance(first, last) >= 0);
103 assert(n <= static_cast<size_t>(std::distance(first, last)));
106 std::vector<size_t> taskIndices;
107 std::exception_ptr e;
109 folly::Optional<Promise<void>> promise;
111 Context(size_t tasksTodo_) : tasksTodo(tasksTodo_) {
112 this->taskIndices.reserve(tasksTodo_);
115 auto context = std::make_shared<Context>(n);
118 [first, last, context](Promise<void> promise) mutable {
119 context->promise = std::move(promise);
120 for (size_t i = 0; first != last; ++i, ++first) {
122 #pragma clang diagnostic push // ignore generalized lambda capture warning
123 #pragma clang diagnostic ignored "-Wc++1y-extensions"
126 [i, context, f = std::move(*first)]() {
129 if (context->tasksTodo == 0) {
132 context->taskIndices.push_back(i);
134 if (context->tasksTodo == 0) {
137 context->e = std::current_exception();
139 if (--context->tasksTodo == 0) {
140 context->promise->setValue();
144 #pragma clang diagnostic pop
149 if (context->e != std::exception_ptr()) {
150 std::rethrow_exception(context->e);
153 return context->taskIndices;
156 template <class InputIterator>
157 typename std::vector<
158 typename std::enable_if<
160 typename std::result_of<
161 typename std::iterator_traits<InputIterator>::value_type()>::type, void
163 typename std::result_of<
164 typename std::iterator_traits<InputIterator>::value_type()>::type>::type>
165 inline collectAll(InputIterator first, InputIterator last) {
166 typedef typename std::result_of<
167 typename std::iterator_traits<InputIterator>::value_type()>::type Result;
168 size_t n = std::distance(first, last);
169 std::vector<Result> results;
170 std::vector<size_t> order(n);
174 [&results, &order] (size_t id, Result result) {
175 order[id] = results.size();
176 results.emplace_back(std::move(result));
178 assert(results.size() == n);
180 std::vector<Result> orderedResults;
181 orderedResults.reserve(n);
183 for (size_t i = 0; i < n; ++i) {
184 orderedResults.emplace_back(std::move(results[order[i]]));
187 return orderedResults;
190 template <class InputIterator>
191 typename std::enable_if<
193 typename std::result_of<
194 typename std::iterator_traits<InputIterator>::value_type()>::type, void
195 >::value, void>::type
196 inline collectAll(InputIterator first, InputIterator last) {
197 forEach(first, last, [](size_t /* id */) {});
200 template <class InputIterator>
201 typename std::enable_if<
203 typename std::result_of<
204 typename std::iterator_traits<InputIterator>::value_type()>::type, void
208 typename std::result_of<
209 typename std::iterator_traits<InputIterator>::value_type()>::type>
211 inline collectAny(InputIterator first, InputIterator last) {
212 auto result = collectN(first, last, 1);
213 assert(result.size() == 1);
214 return std::move(result[0]);
217 template <class InputIterator>
218 typename std::enable_if<
220 typename std::result_of<
221 typename std::iterator_traits<InputIterator>::value_type()>::type, void
222 >::value, size_t>::type
223 inline collectAny(InputIterator first, InputIterator last) {
224 auto result = collectN(first, last, 1);
225 assert(result.size() == 1);
226 return std::move(result[0]);