proxygen
WhenN-inl.h
Go to the documentation of this file.
1 /*
2  * Copyright 2014-present 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/Optional.h>
17 
19 #include <folly/fibers/ForEach.h>
20 
21 namespace folly {
22 namespace fibers {
23 
24 template <class InputIterator>
25 typename std::vector<typename std::enable_if<
26  !std::is_same<
28  typename std::iterator_traits<InputIterator>::value_type>,
29  void>::value,
30  typename std::pair<
31  size_t,
33  typename std::iterator_traits<InputIterator>::value_type>>>::type>
34 collectN(InputIterator first, InputIterator last, size_t n) {
35  typedef invoke_result_t<
36  typename std::iterator_traits<InputIterator>::value_type>
37  Result;
38  assert(n > 0);
39  assert(std::distance(first, last) >= 0);
40  assert(n <= static_cast<size_t>(std::distance(first, last)));
41 
42  struct Context {
43  std::vector<std::pair<size_t, Result>> results;
44  size_t tasksTodo;
45  std::exception_ptr e;
47 
48  Context(size_t tasksTodo_) : tasksTodo(tasksTodo_) {
49  this->results.reserve(tasksTodo_);
50  }
51  };
52  auto context = std::make_shared<Context>(n);
53 
54  await([first, last, context](Promise<void> promise) mutable {
55  context->promise = std::move(promise);
56  for (size_t i = 0; first != last; ++i, ++first) {
57  addTask([i, context, f = std::move(*first)]() {
58  try {
59  auto result = f();
60  if (context->tasksTodo == 0) {
61  return;
62  }
63  context->results.emplace_back(i, std::move(result));
64  } catch (...) {
65  if (context->tasksTodo == 0) {
66  return;
67  }
68  context->e = std::current_exception();
69  }
70  if (--context->tasksTodo == 0) {
71  context->promise->setValue();
72  }
73  });
74  }
75  });
76 
77  if (context->e != std::exception_ptr()) {
78  std::rethrow_exception(context->e);
79  }
80 
81  return std::move(context->results);
82 }
83 
84 template <class InputIterator>
85 typename std::enable_if<
86  std::is_same<
88  typename std::iterator_traits<InputIterator>::value_type>,
89  void>::value,
90  std::vector<size_t>>::type
91 collectN(InputIterator first, InputIterator last, size_t n) {
92  assert(n > 0);
93  assert(std::distance(first, last) >= 0);
94  assert(n <= static_cast<size_t>(std::distance(first, last)));
95 
96  struct Context {
97  std::vector<size_t> taskIndices;
98  std::exception_ptr e;
99  size_t tasksTodo;
101 
102  Context(size_t tasksTodo_) : tasksTodo(tasksTodo_) {
103  this->taskIndices.reserve(tasksTodo_);
104  }
105  };
106  auto context = std::make_shared<Context>(n);
107 
108  await([first, last, context](Promise<void> promise) mutable {
109  context->promise = std::move(promise);
110  for (size_t i = 0; first != last; ++i, ++first) {
111  addTask([i, context, f = std::move(*first)]() {
112  try {
113  f();
114  if (context->tasksTodo == 0) {
115  return;
116  }
117  context->taskIndices.push_back(i);
118  } catch (...) {
119  if (context->tasksTodo == 0) {
120  return;
121  }
122  context->e = std::current_exception();
123  }
124  if (--context->tasksTodo == 0) {
125  context->promise->setValue();
126  }
127  });
128  }
129  });
130 
131  if (context->e != std::exception_ptr()) {
132  std::rethrow_exception(context->e);
133  }
134 
135  return context->taskIndices;
136 }
137 
138 template <class InputIterator>
139 typename std::vector<
140  typename std::enable_if<
141  !std::is_same<
143  typename std::iterator_traits<InputIterator>::value_type>,
144  void>::value,
146  typename std::iterator_traits<InputIterator>::value_type>>::
147  type> inline collectAll(InputIterator first, InputIterator last) {
148  typedef invoke_result_t<
149  typename std::iterator_traits<InputIterator>::value_type>
150  Result;
151  size_t n = size_t(std::distance(first, last));
152  std::vector<Result> results;
153  std::vector<size_t> order(n);
154  results.reserve(n);
155 
156  forEach(first, last, [&results, &order](size_t id, Result result) {
157  order[id] = results.size();
158  results.emplace_back(std::move(result));
159  });
160  assert(results.size() == n);
161 
162  std::vector<Result> orderedResults;
163  orderedResults.reserve(n);
164 
165  for (size_t i = 0; i < n; ++i) {
166  orderedResults.emplace_back(std::move(results[order[i]]));
167  }
168 
169  return orderedResults;
170 }
171 
172 template <class InputIterator>
173 typename std::enable_if<
174  std::is_same<
176  typename std::iterator_traits<InputIterator>::value_type>,
177  void>::value,
178  void>::type inline collectAll(InputIterator first, InputIterator last) {
179  forEach(first, last, [](size_t /* id */) {});
180 }
181 
182 template <class InputIterator>
183 typename std::enable_if<
184  !std::is_same<
186  typename std::iterator_traits<InputIterator>::value_type>,
187  void>::value,
188  typename std::pair<
189  size_t,
191  typename std::iterator_traits<InputIterator>::value_type>>>::
192  type inline collectAny(InputIterator first, InputIterator last) {
193  auto result = collectN(first, last, 1);
194  assert(result.size() == 1);
195  return std::move(result[0]);
196 }
197 
198 template <class InputIterator>
199 typename std::enable_if<
200  std::is_same<
202  typename std::iterator_traits<InputIterator>::value_type>,
203  void>::value,
204  size_t>::type inline collectAny(InputIterator first, InputIterator last) {
205  auto result = collectN(first, last, 1);
206  assert(result.size() == 1);
207  return std::move(result[0]);
208 }
209 } // namespace fibers
210 } // namespace folly
std::enable_if< !std::is_same< invoke_result_t< typename std::iterator_traits< InputIterator >::value_type >, void >::value, typename std::pair< size_t, invoke_result_t< typename std::iterator_traits< InputIterator >::value_type > > >::type collectAny(InputIterator first, InputIterator last)
Definition: WhenN-inl.h:192
std::vector< typename std::enable_if< !std::is_same< invoke_result_t< typename std::iterator_traits< InputIterator >::value_type >, void >::value, invoke_result_t< typename std::iterator_traits< InputIterator >::value_type > >::type > collectAll(InputIterator first, InputIterator last)
Definition: WhenN-inl.h:147
auto f
typename invoke_result< F, Args... >::type invoke_result_t
Definition: Invoke.h:142
PskType type
context
Definition: CMakeCache.txt:563
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
std::vector< typename std::enable_if< !std::is_same< invoke_result_t< typename std::iterator_traits< InputIterator >::value_type >, void >::value, typename std::pair< size_t, invoke_result_t< typename std::iterator_traits< InputIterator >::value_type > > >::type > collectN(InputIterator first, InputIterator last, size_t n)
Definition: WhenN-inl.h:34
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
void forEach(InputIterator first, InputIterator last, F &&f)
Definition: ForEach-inl.h:41
void addTask(F &&func)
uint64_t value(const typename LockFreeRingBuffer< T, Atom >::Cursor &rbcursor)
int order
constexpr detail::First first
Definition: Base-inl.h:2553
FirstArgOf< F >::type::value_type await(F &&func)