single_sender.h 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. #pragma once
  2. /*
  3. * Copyright 2018-present Facebook, Inc.
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. #include <folly/experimental/pushmi/receiver.h>
  18. #include <folly/experimental/pushmi/executor.h>
  19. #include <folly/experimental/pushmi/trampoline.h>
  20. namespace pushmi {
  21. template <class E, class... VN>
  22. class any_single_sender {
  23. union data {
  24. void* pobj_ = nullptr;
  25. char buffer_[sizeof(std::tuple<VN...>)]; // can hold a V in-situ
  26. } data_{};
  27. template <class Wrapped>
  28. static constexpr bool insitu() {
  29. return sizeof(Wrapped) <= sizeof(data::buffer_) &&
  30. std::is_nothrow_move_constructible<Wrapped>::value;
  31. }
  32. struct vtable {
  33. static void s_op(data&, data*) {}
  34. static any_executor<E> s_executor(data&) {
  35. return {};
  36. }
  37. static void s_submit(data&, any_receiver<E, VN...>) {}
  38. void (*op_)(data&, data*) = vtable::s_op;
  39. any_executor<E> (*executor_)(data&) = vtable::s_executor;
  40. void (*submit_)(data&, any_receiver<E, VN...>) = vtable::s_submit;
  41. };
  42. static constexpr vtable const noop_{};
  43. vtable const* vptr_ = &noop_;
  44. template <class Wrapped>
  45. any_single_sender(Wrapped obj, std::false_type) : any_single_sender() {
  46. struct s {
  47. static void op(data& src, data* dst) {
  48. if (dst)
  49. dst->pobj_ = std::exchange(src.pobj_, nullptr);
  50. delete static_cast<Wrapped const*>(src.pobj_);
  51. }
  52. static any_executor<E> executor(data& src) {
  53. return any_executor<E>{
  54. ::pushmi::executor(*static_cast<Wrapped*>(src.pobj_))};
  55. }
  56. static void submit(data& src, any_receiver<E, VN...> out) {
  57. ::pushmi::submit(*static_cast<Wrapped*>(src.pobj_), std::move(out));
  58. }
  59. };
  60. static const vtable vtbl{s::op, s::executor, s::submit};
  61. data_.pobj_ = new Wrapped(std::move(obj));
  62. vptr_ = &vtbl;
  63. }
  64. template <class Wrapped>
  65. any_single_sender(Wrapped obj, std::true_type) noexcept
  66. : any_single_sender() {
  67. struct s {
  68. static void op(data& src, data* dst) {
  69. if (dst)
  70. new (dst->buffer_)
  71. Wrapped(std::move(*static_cast<Wrapped*>((void*)src.buffer_)));
  72. static_cast<Wrapped const*>((void*)src.buffer_)->~Wrapped();
  73. }
  74. static any_executor<E> executor(data& src) {
  75. return any_executor<E>{
  76. ::pushmi::executor(*static_cast<Wrapped*>((void*)src.buffer_))};
  77. }
  78. static void submit(data& src, any_receiver<E, VN...> out) {
  79. ::pushmi::submit(
  80. *static_cast<Wrapped*>((void*)src.buffer_), std::move(out));
  81. }
  82. };
  83. static const vtable vtbl{s::op, s::executor, s::submit};
  84. new (data_.buffer_) Wrapped(std::move(obj));
  85. vptr_ = &vtbl;
  86. }
  87. template <class T, class U = std::decay_t<T>>
  88. using wrapped_t =
  89. std::enable_if_t<!std::is_same<U, any_single_sender>::value, U>;
  90. public:
  91. using properties = property_set<is_sender<>, is_single<>>;
  92. any_single_sender() = default;
  93. any_single_sender(any_single_sender&& that) noexcept : any_single_sender() {
  94. that.vptr_->op_(that.data_, &data_);
  95. std::swap(that.vptr_, vptr_);
  96. }
  97. PUSHMI_TEMPLATE(class Wrapped)
  98. (requires SenderTo<
  99. wrapped_t<Wrapped>,
  100. any_receiver<
  101. E,
  102. VN...>>)
  103. explicit any_single_sender(Wrapped obj) noexcept(insitu<Wrapped>())
  104. : any_single_sender{std::move(obj), bool_<insitu<Wrapped>()>{}} {}
  105. ~any_single_sender() {
  106. vptr_->op_(data_, nullptr);
  107. }
  108. any_single_sender& operator=(any_single_sender&& that) noexcept {
  109. this->~any_single_sender();
  110. new ((void*)this) any_single_sender(std::move(that));
  111. return *this;
  112. }
  113. any_executor<E> executor() {
  114. return vptr_->executor_(data_);
  115. }
  116. void submit(any_receiver<E, VN...> out) {
  117. vptr_->submit_(data_, std::move(out));
  118. }
  119. };
  120. // Class static definitions:
  121. template <class E, class... VN>
  122. constexpr typename any_single_sender<E, VN...>::vtable const
  123. any_single_sender<E, VN...>::noop_;
  124. template <class SF, class EXF>
  125. class single_sender<SF, EXF> {
  126. SF sf_;
  127. EXF exf_;
  128. public:
  129. using properties = property_set<is_sender<>, is_single<>>;
  130. constexpr single_sender() = default;
  131. constexpr explicit single_sender(SF sf) : sf_(std::move(sf)) {}
  132. constexpr single_sender(SF sf, EXF exf)
  133. : sf_(std::move(sf)), exf_(std::move(exf)) {}
  134. auto executor() {
  135. return exf_();
  136. }
  137. PUSHMI_TEMPLATE(class Out)
  138. (requires PUSHMI_EXP(lazy::Receiver<Out> PUSHMI_AND
  139. lazy::Invocable<SF&, Out>))
  140. void submit(Out out) {
  141. sf_(std::move(out));
  142. }
  143. };
  144. template <
  145. PUSHMI_TYPE_CONSTRAINT(Sender<is_single<>>) Data,
  146. class DSF,
  147. class DEXF>
  148. class single_sender<Data, DSF, DEXF> {
  149. Data data_;
  150. DSF sf_;
  151. DEXF exf_;
  152. public:
  153. using properties = property_set_insert_t<
  154. properties_t<Data>,
  155. property_set<is_sender<>, is_single<>>>;
  156. constexpr single_sender() = default;
  157. constexpr explicit single_sender(Data data) : data_(std::move(data)) {}
  158. constexpr single_sender(Data data, DSF sf)
  159. : data_(std::move(data)), sf_(std::move(sf)) {}
  160. constexpr single_sender(Data data, DSF sf, DEXF exf)
  161. : data_(std::move(data)), sf_(std::move(sf)), exf_(std::move(exf)) {}
  162. auto executor() {
  163. return exf_(data_);
  164. }
  165. PUSHMI_TEMPLATE(class Out)
  166. (requires PUSHMI_EXP(
  167. lazy::Receiver<Out> PUSHMI_AND
  168. lazy::Invocable<DSF&, Data&, Out>))
  169. void submit(Out out) {
  170. sf_(data_, std::move(out));
  171. }
  172. };
  173. template <>
  174. class single_sender<> : public single_sender<ignoreSF, trampolineEXF> {
  175. public:
  176. single_sender() = default;
  177. };
  178. ////////////////////////////////////////////////////////////////////////////////
  179. // make_single_sender
  180. PUSHMI_INLINE_VAR constexpr struct make_single_sender_fn {
  181. inline auto operator()() const {
  182. return single_sender<ignoreSF, trampolineEXF>{};
  183. }
  184. PUSHMI_TEMPLATE(class SF)
  185. (requires True<> PUSHMI_BROKEN_SUBSUMPTION(&&not Sender<SF>))
  186. auto operator()(SF sf) const {
  187. return single_sender<SF, trampolineEXF>{std::move(sf)};
  188. }
  189. PUSHMI_TEMPLATE(class SF, class EXF)
  190. (requires True<>&& Invocable<EXF&> PUSHMI_BROKEN_SUBSUMPTION(
  191. &&not Sender<SF>))
  192. auto operator()(SF sf, EXF exf) const {
  193. return single_sender<SF, EXF>{std::move(sf), std::move(exf)};
  194. }
  195. PUSHMI_TEMPLATE(class Data)
  196. (requires True<>&& Sender<Data, is_single<>>)
  197. auto operator()(Data d) const {
  198. return single_sender<Data, passDSF, passDEXF>{std::move(d)};
  199. }
  200. PUSHMI_TEMPLATE(class Data, class DSF)
  201. (requires Sender<Data, is_single<>>)
  202. auto operator()(Data d, DSF sf) const {
  203. return single_sender<Data, DSF, passDEXF>{std::move(d), std::move(sf)};
  204. }
  205. PUSHMI_TEMPLATE(class Data, class DSF, class DEXF)
  206. (requires Sender<Data, is_single<>>&& Invocable<DEXF&, Data&>)
  207. auto operator()(Data d, DSF sf, DEXF exf) const {
  208. return single_sender<Data, DSF, DEXF>{
  209. std::move(d), std::move(sf), std::move(exf)};
  210. }
  211. } const make_single_sender{};
  212. ////////////////////////////////////////////////////////////////////////////////
  213. // deduction guides
  214. #if __cpp_deduction_guides >= 201703
  215. single_sender() -> single_sender<ignoreSF, trampolineEXF>;
  216. PUSHMI_TEMPLATE(class SF)
  217. (requires True<> PUSHMI_BROKEN_SUBSUMPTION(&& not Sender<SF>))
  218. single_sender(SF) -> single_sender<SF, trampolineEXF>;
  219. PUSHMI_TEMPLATE(class SF, class EXF)
  220. (requires True<> && Invocable<EXF&>
  221. PUSHMI_BROKEN_SUBSUMPTION(&& not Sender<SF>))
  222. single_sender(SF, EXF) -> single_sender<SF, EXF>;
  223. PUSHMI_TEMPLATE(class Data)
  224. (requires True<> && Sender<Data, is_single<>>)
  225. single_sender(Data) -> single_sender<Data, passDSF, passDEXF>;
  226. PUSHMI_TEMPLATE(class Data, class DSF)
  227. (requires Sender<Data, is_single<>>)
  228. single_sender(Data, DSF) -> single_sender<Data, DSF, passDEXF>;
  229. PUSHMI_TEMPLATE(class Data, class DSF, class DEXF)
  230. (requires Sender<Data, is_single<>> && Invocable<DEXF&, Data&>)
  231. single_sender(Data, DSF, DEXF) -> single_sender<Data, DSF, DEXF>;
  232. #endif
  233. template<>
  234. struct construct_deduced<single_sender> : make_single_sender_fn {};
  235. } // namespace pushmi