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.
19 #include <folly/experimental/fibers/FiberManager.h>
21 namespace folly { namespace fibers {
24 TaskIterator<T>::TaskIterator(TaskIterator&& other) noexcept
25 : context_(std::move(other.context_)),
30 TaskIterator<T>::TaskIterator(std::shared_ptr<Context> context)
31 : context_(std::move(context)),
37 inline bool TaskIterator<T>::hasCompleted() const {
38 return context_->tasksConsumed < context_->results.size();
42 inline bool TaskIterator<T>::hasPending() const {
43 return !context_.unique();
47 inline bool TaskIterator<T>::hasNext() const {
48 return hasPending() || hasCompleted();
52 folly::Try<T> TaskIterator<T>::awaitNextResult() {
53 assert(hasCompleted() || hasPending());
56 size_t i = context_->tasksConsumed++;
57 id_ = context_->results[i].first;
58 return std::move(context_->results[i].second);
62 inline T TaskIterator<T>::awaitNext() {
63 return std::move(awaitNextResult().value());
67 inline void TaskIterator<void>::awaitNext() {
68 awaitNextResult().value();
72 inline void TaskIterator<T>::reserve(size_t n) {
73 size_t tasksReady = context_->results.size() - context_->tasksConsumed;
75 // we don't need to do anything if there are already n or more tasks complete
76 // or if we have no tasks left to execute.
77 if (!hasPending() || tasksReady >= n) {
82 size_t tasksLeft = context_->totalTasks - context_->results.size();
83 n = std::min(n, tasksLeft);
86 [this, n](Promise<void> promise) {
87 context_->tasksToFulfillPromise = n;
88 context_->promise.assign(std::move(promise));
93 inline size_t TaskIterator<T>::getTaskID() const {
98 template <class InputIterator>
99 TaskIterator<typename std::result_of<
100 typename std::iterator_traits<InputIterator>::value_type()>::type>
101 addTasks(InputIterator first, InputIterator last) {
102 typedef typename std::result_of<
103 typename std::iterator_traits<InputIterator>::value_type()>::type
105 typedef TaskIterator<ResultType> IteratorType;
107 auto context = std::make_shared<typename IteratorType::Context>();
108 context->totalTasks = std::distance(first, last);
109 context->results.reserve(context->totalTasks);
111 for (size_t i = 0; first != last; ++i, ++first) {
113 #pragma clang diagnostic push // ignore generalized lambda capture warning
114 #pragma clang diagnostic ignored "-Wc++1y-extensions"
117 [i, context, f = std::move(*first)]() {
118 context->results.emplace_back(i, folly::makeTryFunction(std::move(f)));
120 // Check for awaiting iterator.
121 if (context->promise.hasValue()) {
122 if (--context->tasksToFulfillPromise == 0) {
123 context->promise->setValue();
124 context->promise.clear();
130 #pragma clang diagnostic pop
134 return IteratorType(std::move(context));