proxygen
receiver.h
Go to the documentation of this file.
1 /*
2  * Copyright 2018-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 #pragma once
17 
26 #include <future>
27 
28 namespace folly {
29 namespace pushmi {
30 
31 template <class E, class... VN>
32 class any_receiver {
33  bool done_ = false;
34  union data {
35  void* pobj_ = nullptr;
36  char buffer_[sizeof(std::promise<int>)]; // can hold a std::promise in-situ
37  } data_{};
38  template <class Wrapped>
39  static constexpr bool insitu() noexcept {
40  return sizeof(Wrapped) <= sizeof(data::buffer_) &&
42  }
43  struct vtable {
44  static void s_op(data&, data*) {}
45  static void s_done(data&) {}
46  static void s_error(data&, E) noexcept {
47  std::terminate();
48  }
49  static void s_value(data&, VN...) {}
50  void (*op_)(data&, data*) = vtable::s_op;
51  void (*done_)(data&) = vtable::s_done;
52  void (*error_)(data&, E) noexcept = vtable::s_error;
53  void (*value_)(data&, VN...) = vtable::s_value;
54  };
55  static constexpr vtable const noop_{};
56  vtable const* vptr_ = &noop_;
57  template <class T, class U = std::decay_t<T>>
59  template <class Wrapped>
60  static void check() {
61  static_assert(
62  ReceiveValue<Wrapped, VN...>,
63  "Wrapped receiver must support values of type VN...");
64  static_assert(
65  ReceiveError<Wrapped, std::exception_ptr>,
66  "Wrapped receiver must support std::exception_ptr and be noexcept");
67  static_assert(
68  NothrowInvocable<decltype(::folly::pushmi::set_error), Wrapped, E>,
69  "Wrapped receiver must support E and be noexcept");
70  }
71  template <class Wrapped>
73  struct s {
74  static void op(data& src, data* dst) {
75  if (dst)
76  dst->pobj_ = std::exchange(src.pobj_, nullptr);
77  delete static_cast<Wrapped const*>(src.pobj_);
78  }
79  static void done(data& src) {
80  set_done(*static_cast<Wrapped*>(src.pobj_));
81  }
82  static void error(data& src, E e) noexcept {
83  set_error(*static_cast<Wrapped*>(src.pobj_), std::move(e));
84  }
85  static void value(data& src, VN... vn) {
86  set_value(*static_cast<Wrapped*>(src.pobj_), std::move(vn)...);
87  }
88  };
89  static const vtable vtbl{s::op, s::done, s::error, s::value};
90  data_.pobj_ = new Wrapped(std::move(obj));
91  vptr_ = &vtbl;
92  }
93  template <class Wrapped>
95  struct s {
96  static void op(data& src, data* dst) {
97  if (dst)
98  new (dst->buffer_)
99  Wrapped(std::move(*static_cast<Wrapped*>((void*)src.buffer_)));
100  static_cast<Wrapped const*>((void*)src.buffer_)->~Wrapped();
101  }
102  static void done(data& src) {
103  set_done(*static_cast<Wrapped*>((void*)src.buffer_));
104  }
105  static void error(data& src, E e) noexcept {
106  set_error(*static_cast<Wrapped*>((void*)src.buffer_), std::move(e));
107  }
108  static void value(data& src, VN... vn) {
109  set_value(*static_cast<Wrapped*>((void*)src.buffer_), std::move(vn)...);
110  }
111  };
112  static const vtable vtbl{s::op, s::done, s::error, s::value};
113  new ((void*)data_.buffer_) Wrapped(std::move(obj));
114  vptr_ = &vtbl;
115  }
116 
117  public:
119 
120  any_receiver() = default;
122  that.vptr_->op_(that.data_, &data_);
123  std::swap(that.vptr_, vptr_);
124  }
125  PUSHMI_TEMPLATE(class Wrapped)
126  (requires ReceiveValue<wrapped_t<Wrapped>, VN...>&& ReceiveError<
127  Wrapped,
128  E>)
129  explicit any_receiver(Wrapped obj) noexcept(insitu<Wrapped>())
131  check<Wrapped>();
132  }
134  vptr_->op_(data_, nullptr);
135  }
137  this->~any_receiver();
138  new ((void*)this) any_receiver(std::move(that));
139  return *this;
140  }
141  void value(VN&&... vn) {
142  if (!done_) {
143  // done_ = true;
144  vptr_->value_(data_, (VN &&) vn...);
145  }
146  }
147  void error(E e) noexcept {
148  if (!done_) {
149  done_ = true;
150  vptr_->error_(data_, std::move(e));
151  }
152  }
153  void done() {
154  if (!done_) {
155  done_ = true;
156  vptr_->done_(data_);
157  }
158  }
159 };
160 
161 // Class static definitions:
162 template <class E, class... VN>
163 constexpr
164  typename any_receiver<E, VN...>::vtable const any_receiver<E, VN...>::noop_;
165 
166 template <class VF, class EF, class DF>
167 #if __cpp_concepts
168 requires Invocable<DF&>
169 #endif
170 class receiver<VF, EF, DF> {
171  bool done_ = false;
172  VF vf_;
173  EF ef_;
174  DF df_;
175 
176  static_assert(
177  !detail::is_v<VF, on_error_fn>,
178  "the first parameter is the value implementation, but on_error{} was passed");
179  static_assert(
180  !detail::is_v<EF, on_value_fn>,
181  "the second parameter is the error implementation, but on_value{} was passed");
182  static_assert(
183  NothrowInvocable<EF&, std::exception_ptr>,
184  "error function must be noexcept and support std::exception_ptr");
185 
186  public:
188 
189  receiver() = default;
190  constexpr explicit receiver(VF vf) : receiver(std::move(vf), EF{}, DF{}) {}
191  constexpr explicit receiver(EF ef) : receiver(VF{}, std::move(ef), DF{}) {}
192  constexpr explicit receiver(DF df) : receiver(VF{}, EF{}, std::move(df)) {}
193  constexpr receiver(EF ef, DF df)
194  : done_(false), vf_(), ef_(std::move(ef)), df_(std::move(df)) {}
195  constexpr receiver(VF vf, EF ef, DF df = DF{})
196  : done_(false),
197  vf_(std::move(vf)),
198  ef_(std::move(ef)),
199  df_(std::move(df)) {}
200 
201  PUSHMI_TEMPLATE(class... VN)
202  (requires Invocable<VF&, VN...>)
203  void value(VN&&... vn) {
204  if (done_) {
205  return;
206  }
207  // done_ = true;
208  vf_((VN &&) vn...);
209  }
210  PUSHMI_TEMPLATE(class E)
211  (requires Invocable<EF&, E>)
212  void error(E e) noexcept {
213  static_assert(NothrowInvocable<EF&, E>, "error function must be noexcept");
214  if (!done_) {
215  done_ = true;
216  ef_(std::move(e));
217  }
218  }
219  void done() {
220  if (!done_) {
221  done_ = true;
222  df_();
223  }
224  }
225 };
226 
227 template <
228  PUSHMI_TYPE_CONSTRAINT(Receiver) Data,
229  class DVF,
230  class DEF,
231  class DDF>
232 #if __cpp_concepts
233 requires Invocable<DDF&, Data&>
234 #endif
235 class receiver<Data, DVF, DEF, DDF> {
236  bool done_ = false;
238  DVF vf_;
239  DEF ef_;
240  DDF df_;
241 
242  static_assert(
243  !detail::is_v<DVF, on_error_fn>,
244  "the first parameter is the value implementation, but on_error{} was passed");
245  static_assert(
246  !detail::is_v<DEF, on_value_fn>,
247  "the second parameter is the error implementation, but on_value{} was passed");
248  static_assert(
249  Invocable<DEF, Data&, std::exception_ptr>,
250  "error function must support std::exception_ptr");
251  static_assert(
252  NothrowInvocable<DEF, Data&, std::exception_ptr>,
253  "error function must be noexcept");
254 
255  public:
256  using properties =
258 
259  constexpr explicit receiver(Data d)
260  : receiver(std::move(d), DVF{}, DEF{}, DDF{}) {}
261  constexpr receiver(Data d, DDF df)
262  : done_(false), data_(std::move(d)), vf_(), ef_(), df_(df) {}
263  constexpr receiver(Data d, DEF ef, DDF df = DDF{})
264  : done_(false), data_(std::move(d)), vf_(), ef_(ef), df_(df) {}
265  constexpr receiver(Data d, DVF vf, DEF ef = DEF{}, DDF df = DDF{})
266  : done_(false), data_(std::move(d)), vf_(vf), ef_(ef), df_(df) {}
267 
268  Data& data() {
269  return data_;
270  }
271 
272  PUSHMI_TEMPLATE(class... VN)
273  (requires Invocable<DVF&, Data&, VN...>)
274  void value(VN&&... vn) {
275  if (!done_) {
276  // done_ = true;
277  vf_(data_, (VN &&) vn...);
278  }
279  }
280  PUSHMI_TEMPLATE(class E)
281  (requires Invocable<DEF&, Data&, E>)
282  void error(E e) noexcept {
283  static_assert(
284  NothrowInvocable<DEF&, Data&, E>, "error function must be noexcept");
285  if (!done_) {
286  done_ = true;
287  ef_(data_, std::move(e));
288  }
289  }
290  void done() {
291  if (!done_) {
292  done_ = true;
293  df_(data_);
294  }
295  }
296 };
297 
298 template <>
299 class receiver<> : public receiver<ignoreVF, abortEF, ignoreDF> {
300  public:
301  receiver() = default;
302 };
303 
305  template (class T)
306  concept ReceiverDataArg,
307  Receiver<T> &&
308  not Invocable<T&>
309 );
310 
312 // make_receiver
314  inline auto operator()() const {
315  return receiver<>{};
316  }
317  PUSHMI_TEMPLATE(class VF)
319  lazy::True<>
320  PUSHMI_BROKEN_SUBSUMPTION(PUSHMI_AND not lazy::ReceiverDataArg<VF>)))
321  auto operator()(VF vf) const {
323  }
324  template <class... EFN>
326  return receiver<ignoreVF, on_error_fn<EFN...>, ignoreDF>{std::move(ef)};
327  }
328  template <class... DFN>
330  return receiver<ignoreVF, abortEF, on_done_fn<DFN...>>{std::move(df)};
331  }
332  PUSHMI_TEMPLATE(class VF, class EF)
334  lazy::True<>
336  not lazy::ReceiverDataArg<VF> PUSHMI_AND
337  not lazy::Invocable<EF&>)))
338  auto operator()(VF vf, EF ef) const {
340  }
341  PUSHMI_TEMPLATE(class EF, class DF)
343  lazy::True<> PUSHMI_AND
344  lazy::Invocable<DF&>
345  PUSHMI_BROKEN_SUBSUMPTION(PUSHMI_AND not lazy::ReceiverDataArg<EF>)))
346  auto operator()(EF ef, DF df) const {
348  }
349  PUSHMI_TEMPLATE(class VF, class EF, class DF)
351  lazy::True<> PUSHMI_AND
352  lazy::Invocable<DF&>
353  PUSHMI_BROKEN_SUBSUMPTION(PUSHMI_AND not lazy::ReceiverDataArg<VF>)))
354  auto operator()(VF vf, EF ef, DF df) const {
355  return receiver<VF, EF, DF>{std::move(vf), std::move(ef), std::move(df)};
356  }
357  PUSHMI_TEMPLATE(class Data)
359  lazy::True<> PUSHMI_AND
360  lazy::ReceiverDataArg<Data>))
361  auto operator()(Data d) const {
363  }
364  PUSHMI_TEMPLATE(class Data, class DVF)
366  lazy::True<> PUSHMI_AND
367  lazy::ReceiverDataArg<Data>))
368  auto operator()(Data d, DVF vf) const {
370  }
371  PUSHMI_TEMPLATE(class Data, class... DEFN)
373  lazy::True<> PUSHMI_AND
374  lazy::ReceiverDataArg<Data>))
375  auto operator()(Data d, on_error_fn<DEFN...> ef) const {
376  return receiver<Data, passDVF, on_error_fn<DEFN...>, passDDF>{std::move(d), std::move(ef)};
377  }
378  PUSHMI_TEMPLATE(class Data, class... DDFN)
380  lazy::True<> PUSHMI_AND
381  lazy::ReceiverDataArg<Data>))
382  auto operator()(Data d, on_done_fn<DDFN...> df) const {
383  return receiver<Data, passDVF, passDEF, on_done_fn<DDFN...>>{std::move(d), std::move(df)};
384  }
385  PUSHMI_TEMPLATE(class Data, class DVF, class... DEFN)
387  lazy::True<> PUSHMI_AND
388  lazy::ReceiverDataArg<Data>))
389  auto operator()(Data d, DVF vf, on_error_fn<DEFN...> ef) const {
390  return receiver<Data, DVF, on_error_fn<DEFN...>, passDDF>{std::move(d), std::move(vf), std::move(ef)};
391  }
392  PUSHMI_TEMPLATE(class Data, class DEF, class... DDFN)
394  lazy::True<> PUSHMI_AND
395  lazy::ReceiverDataArg<Data>))
396  auto operator()(Data d, DEF ef, on_done_fn<DDFN...> df) const {
397  return receiver<Data, passDVF, DEF, on_done_fn<DDFN...>>{std::move(d), std::move(ef), std::move(df)};
398  }
399  PUSHMI_TEMPLATE(class Data, class DVF, class DEF, class DDF)
401  lazy::True<> PUSHMI_AND
402  lazy::ReceiverDataArg<Data> PUSHMI_AND
403  lazy::Invocable<DDF&, Data&>))
404  auto operator()(Data d, DVF vf, DEF ef, DDF df) const {
406  }
407 } const make_receiver {};
408 
410 // deduction guides
411 #if __cpp_deduction_guides >= 201703
412 receiver() -> receiver<>;
413 
414 PUSHMI_TEMPLATE(class VF)
416  True<>
417  PUSHMI_BROKEN_SUBSUMPTION(PUSHMI_AND not lazy::Receiver<VF>)))
419 
420 template <class... EFN>
422 
423 template <class... DFN>
424 receiver(on_done_fn<DFN...>) -> receiver<ignoreVF, abortEF, on_done_fn<DFN...>>;
425 
426 PUSHMI_TEMPLATE(class VF, class EF)
428  lazy::True<>
430  not lazy::ReceiverDataArg<VF> PUSHMI_AND
431  not lazy::Invocable<EF&>)))
433 
434 PUSHMI_TEMPLATE(class EF, class DF)
436  lazy::True<> PUSHMI_AND
437  lazy::Invocable<DF&>
438  PUSHMI_BROKEN_SUBSUMPTION(PUSHMI_AND not lazy::ReceiverDataArg<EF>)))
440 
441 PUSHMI_TEMPLATE(class VF, class EF, class DF)
443  lazy::True<> PUSHMI_AND
444  lazy::Invocable<DF&>
445  PUSHMI_BROKEN_SUBSUMPTION(PUSHMI_AND not lazy::ReceiverDataArg<VF>)))
446 receiver(VF, EF, DF) -> receiver<VF, EF, DF>;
447 
448 PUSHMI_TEMPLATE(class Data)
450  lazy::True<> PUSHMI_AND
451  lazy::ReceiverDataArg<Data>))
453 
454 PUSHMI_TEMPLATE(class Data, class DVF)
456  lazy::True<> PUSHMI_AND
457  lazy::ReceiverDataArg<Data>))
459 
460 PUSHMI_TEMPLATE(class Data, class... DEFN)
462  lazy::True<> PUSHMI_AND
463  lazy::ReceiverDataArg<Data>))
464 receiver(Data d, on_error_fn<DEFN...>) ->
465  receiver<Data, passDVF, on_error_fn<DEFN...>, passDDF>;
466 
467 PUSHMI_TEMPLATE(class Data, class... DDFN)
469  lazy::True<> PUSHMI_AND
470  lazy::ReceiverDataArg<Data>))
471 receiver(Data d, on_done_fn<DDFN...>) ->
472  receiver<Data, passDVF, passDEF, on_done_fn<DDFN...>>;
473 
474 PUSHMI_TEMPLATE(class Data, class DVF, class... DEFN)
476  lazy::True<> PUSHMI_AND
477  lazy::ReceiverDataArg<Data>))
478 receiver(Data d, DVF vf, on_error_fn<DEFN...> ef) -> receiver<Data, DVF, on_error_fn<DEFN...>, passDDF>;
479 
480 PUSHMI_TEMPLATE(class Data, class DEF, class... DDFN)
482  lazy::True<> PUSHMI_AND
483  lazy::ReceiverDataArg<Data>
484  PUSHMI_BROKEN_SUBSUMPTION(PUSHMI_AND not lazy::Invocable<DEF&, Data&>)))
485 receiver(Data d, DEF, on_done_fn<DDFN...>) -> receiver<Data, passDVF, DEF, on_done_fn<DDFN...>>;
486 
487 PUSHMI_TEMPLATE(class Data, class DVF, class DEF, class DDF)
489  lazy::True<> PUSHMI_AND
490  lazy::ReceiverDataArg<Data>PUSHMI_AND
491  lazy::Invocable<DDF&, Data&>))
492 receiver(Data d, DVF vf, DEF ef, DDF df) -> receiver<Data, DVF, DEF, DDF>;
493 #endif
494 
495 template<>
497 
498 PUSHMI_TEMPLATE (class T, class In)
499  (requires SenderTo<In, std::promise<T>, is_single<>>)
500 std::future<T> future_from(In in) {
501  std::promise<T> p;
502  auto result = p.get_future();
503  submit(in, std::move(p));
504  return result;
505 }
506 PUSHMI_TEMPLATE (class In)
507  (requires SenderTo<In, std::promise<void>, is_single<>>)
508 std::future<void> future_from(In in) {
509  std::promise<void> p;
510  auto result = p.get_future();
511  submit(in, std::move(p));
512  return result;
513 }
514 
515 } // namespace pushmi
516 } // namespace folly
constexpr receiver(Data d, DEF ef, DDF df=DDF{})
Definition: receiver.h:263
any_receiver(Wrapped obj, std::true_type) noexcept
Definition: receiver.h:94
static constexpr bool insitu() noexcept
Definition: receiver.h:39
std::true_type True
Definition: TypeList.h:82
static void s_done(data &)
Definition: receiver.h:45
constexpr receiver(VF vf, EF ef, DF df=DF{})
Definition: receiver.h:195
auto operator()(on_done_fn< DFN... > df) const
Definition: receiver.h:329
constexpr receiver(Data d, DVF vf, DEF ef=DEF{}, DDF df=DDF{})
Definition: receiver.h:265
any_receiver(any_receiver &&that) noexcept
Definition: receiver.h:121
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
STL namespace.
any_receiver & operator=(any_receiver &&that) noexcept
Definition: receiver.h:136
union folly::pushmi::any_receiver::data data_
PUSHMI_INLINE_VAR constexpr __adl::set_error_fn set_error
void error(E e) noexcept
Definition: receiver.h:147
property_set_insert_t< properties_t< Data >, property_set< is_receiver<>>> properties
Definition: receiver.h:257
vtable const * vptr_
Definition: receiver.h:56
folly::std T
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
requires E e noexcept(noexcept(s.error(std::move(e))))
requires And< SemiMovable< VN >... > &&SemiMovable< E > auto error(E e)
Definition: error.h:48
typename std::enable_if_t< PropertySet< PS0 > &&PropertySet< PS1 >, detail::property_set_insert< PS0, PS1 >>::type property_set_insert_t
Definition: properties.h:153
bool_constant< true > true_type
Definition: gtest-port.h:2210
#define PUSHMI_AND
Definition: concept_def.h:424
static void s_error(data &, E) noexcept
Definition: receiver.h:46
PUSHMI_CONCEPT_DEF(template(class PS) concept Cardinality, has_cardinality_v< PS >)
constexpr auto data(C &c) -> decltype(c.data())
Definition: Access.h:71
#define concept
requires Invocable< VF &, VN... > void value(VN &&...vn)
Definition: receiver.h:203
requires SenderTo< In, std::promise< T >, is_single<> > std::future< T > future_from(In in)
Definition: receiver.h:500
requires ReceiveValue< wrapped_t< Wrapped >, VN... > &&ReceiveError< Wrapped, E > any_receiver(Wrapped obj) noexcept(insitu< Wrapped >())
Definition: receiver.h:129
static void s_value(data &, VN...)
Definition: receiver.h:49
static const char *const value
Definition: Conv.cpp:50
static void s_op(data &, data *)
Definition: receiver.h:44
auto operator()(on_error_fn< EFN... > ef) const
Definition: receiver.h:325
#define PUSHMI_INLINE_VAR
Definition: concept_def.h:60
#define PUSHMI_EXP(...)
Definition: concept_def.h:423
std::integral_constant< bool, B > bool_
Definition: concept_def.h:443
requires requires(detail::apply_impl(std::declval< F >(), std::declval< Tuple >(), detail::tupidxs< Tuple >{}))) const expr decltype(auto) apply(F &&f
requires Invocable< EF &, E > void error(E e) noexcept
Definition: receiver.h:212
T exchange(T &obj, U &&new_value)
Definition: Utility.h:120
PUSHMI_TEMPLATE(class E=std::exception_ptr, class Wrapped)(requires Sender< detail
Definition: executor.h:102
requires PUSHMI_EXP(lazy::True<> PUSHMI_BROKEN_SUBSUMPTION(PUSHMI_AND not lazy::ReceiverDataArg< VF >))) auto operator()(VF vf) const
Definition: receiver.h:318
void(* op_)(data &, data *)
Definition: receiver.h:50
any_receiver(Wrapped obj, std::false_type)
Definition: receiver.h:72
PUSHMI_INLINE_VAR constexpr __adl::set_value_fn set_value
static set< string > s
const
Definition: upload.py:398
std::enable_if_t<!std::is_same< U, any_receiver >::value, U > wrapped_t
Definition: receiver.h:58
requires Invocable< DEF &, Data &, E > void error(E e) noexcept
Definition: receiver.h:282
bool_constant< false > false_type
Definition: gtest-port.h:2209
#define PUSHMI_TYPE_CONSTRAINT(...)
Definition: concept_def.h:420
char buffer_[sizeof(std::promise< int >)]
Definition: receiver.h:36
constexpr receiver(EF ef, DF df)
Definition: receiver.h:193
PUSHMI_INLINE_VAR constexpr __adl::do_submit_fn submit
void swap(SwapTrackingAlloc< T > &, SwapTrackingAlloc< T > &)
Definition: F14TestUtil.h:414
requires Invocable< DVF &, Data &, VN... > void value(VN &&...vn)
Definition: receiver.h:274
#define PUSHMI_BROKEN_SUBSUMPTION(...)
Definition: concept_def.h:419
PUSHMI_INLINE_VAR constexpr struct folly::pushmi::make_receiver_fn make_receiver
requires PUSHMI_EXP(lazy::True<> PUSHMI_AND lazy::ReceiverDataArg< Data >)) auto operator()(Data d) const
Definition: receiver.h:358
void value(VN &&...vn)
Definition: receiver.h:141
static constexpr vtable const noop_
Definition: receiver.h:55
PUSHMI_INLINE_VAR constexpr __adl::set_done_fn set_done