2 * Copyright 2016 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.
23 TaskIterator<T>::TaskIterator(TaskIterator&& other) noexcept
24 : context_(std::move(other.context_)), id_(other.id_), fm_(other.fm_) {}
27 inline bool TaskIterator<T>::hasCompleted() const {
28 return context_->tasksConsumed < context_->results.size();
32 inline bool TaskIterator<T>::hasPending() const {
33 return !context_.unique();
37 inline bool TaskIterator<T>::hasNext() const {
38 return hasPending() || hasCompleted();
42 folly::Try<T> TaskIterator<T>::awaitNextResult() {
43 assert(hasCompleted() || hasPending());
46 size_t i = context_->tasksConsumed++;
47 id_ = context_->results[i].first;
48 return std::move(context_->results[i].second);
52 inline T TaskIterator<T>::awaitNext() {
53 return std::move(awaitNextResult().value());
57 inline void TaskIterator<void>::awaitNext() {
58 awaitNextResult().value();
62 inline void TaskIterator<T>::reserve(size_t n) {
63 size_t tasksReady = context_->results.size() - context_->tasksConsumed;
65 // we don't need to do anything if there are already n or more tasks complete
66 // or if we have no tasks left to execute.
67 if (!hasPending() || tasksReady >= n) {
72 size_t tasksLeft = context_->totalTasks - context_->results.size();
73 n = std::min(n, tasksLeft);
75 await([this, n](Promise<void> promise) {
76 context_->tasksToFulfillPromise = n;
77 context_->promise.assign(std::move(promise));
82 inline size_t TaskIterator<T>::getTaskID() const {
83 assert(id_ != static_cast<size_t>(-1));
89 void TaskIterator<T>::addTask(F&& func) {
91 std::is_convertible<typename std::result_of<F()>::type, T>::value,
92 "TaskIterator<T>: T must be convertible from func()'s return type");
94 auto taskId = context_->totalTasks++;
97 [ taskId, context = context_, func = std::forward<F>(func) ]() mutable {
98 context->results.emplace_back(
99 taskId, folly::makeTryWith(std::move(func)));
101 // Check for awaiting iterator.
102 if (context->promise.hasValue()) {
103 if (--context->tasksToFulfillPromise == 0) {
104 context->promise->setValue();
105 context->promise.clear();
111 template <class InputIterator>
112 TaskIterator<typename std::result_of<
113 typename std::iterator_traits<InputIterator>::value_type()>::type>
114 addTasks(InputIterator first, InputIterator last) {
115 typedef typename std::result_of<
116 typename std::iterator_traits<InputIterator>::value_type()>::type
118 typedef TaskIterator<ResultType> IteratorType;
120 IteratorType iterator;
122 for (; first != last; ++first) {
123 iterator.addTask(std::move(*first));
126 iterator.context_->results.reserve(iterator.context_->totalTasks);
128 return std::move(iterator);