extension_operators.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
  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/boosters.h>
  18. #include <folly/experimental/pushmi/detail/functional.h>
  19. #include <folly/experimental/pushmi/detail/if_constexpr.h>
  20. #include <folly/experimental/pushmi/flow_many_sender.h>
  21. #include <folly/experimental/pushmi/flow_receiver.h>
  22. #include <folly/experimental/pushmi/flow_single_sender.h>
  23. #include <folly/experimental/pushmi/many_sender.h>
  24. #include <folly/experimental/pushmi/piping.h>
  25. #include <folly/experimental/pushmi/receiver.h>
  26. #include <folly/experimental/pushmi/single_sender.h>
  27. #include <folly/experimental/pushmi/time_single_sender.h>
  28. #include <tuple>
  29. namespace pushmi {
  30. #if __cpp_lib_apply >= 201603
  31. using std::apply;
  32. #else
  33. namespace detail {
  34. PUSHMI_TEMPLATE(class F, class Tuple, std::size_t... Is)
  35. (requires requires(pushmi::invoke(
  36. std::declval<F>(),
  37. std::get<Is>(std::declval<Tuple>())...)))
  38. constexpr decltype(auto) apply_impl(
  39. F&& f,
  40. Tuple&& t,
  41. std::index_sequence<Is...>) {
  42. return pushmi::invoke((F &&) f, std::get<Is>((Tuple &&) t)...);
  43. }
  44. template <class Tuple_, class Tuple = std::remove_reference_t<Tuple_>>
  45. using tupidxs = std::make_index_sequence<std::tuple_size<Tuple>::value>;
  46. } // namespace detail
  47. PUSHMI_TEMPLATE(class F, class Tuple)
  48. (requires requires(detail::apply_impl(
  49. std::declval<F>(),
  50. std::declval<Tuple>(),
  51. detail::tupidxs<Tuple>{})))
  52. constexpr decltype(auto) apply(F&& f, Tuple&& t) {
  53. return detail::apply_impl((F &&) f, (Tuple &&) t, detail::tupidxs<Tuple>{});
  54. }
  55. #endif
  56. namespace detail {
  57. template <class Cardinality, bool IsFlow = false>
  58. struct make_receiver;
  59. template <>
  60. struct make_receiver<is_single<>> : construct_deduced<receiver> {};
  61. template <>
  62. struct make_receiver<is_many<>> : construct_deduced<receiver> {};
  63. template <>
  64. struct make_receiver<is_single<>, true> : construct_deduced<flow_receiver> {};
  65. template <>
  66. struct make_receiver<is_many<>, true> : construct_deduced<flow_receiver> {};
  67. template <class Cardinality, bool IsFlow>
  68. struct receiver_from_impl {
  69. using MakeReceiver = make_receiver<Cardinality, IsFlow>;
  70. template <class... AN>
  71. using receiver_type = pushmi::invoke_result_t<MakeReceiver&, AN...>;
  72. PUSHMI_TEMPLATE(class... Ts)
  73. (requires Invocable<MakeReceiver, Ts...>)
  74. auto operator()(
  75. std::tuple<Ts...> args) const {
  76. return pushmi::apply(MakeReceiver(), std::move(args));
  77. }
  78. PUSHMI_TEMPLATE(
  79. class... Ts,
  80. class... Fns,
  81. class This = std::enable_if_t<sizeof...(Fns) != 0, receiver_from_impl>)
  82. (requires And<SemiMovable<Fns>...>&& Invocable<MakeReceiver, Ts...>&&
  83. Invocable<
  84. This,
  85. pushmi::invoke_result_t<MakeReceiver, Ts...>,
  86. Fns...>)
  87. auto operator()(std::tuple<Ts...> args, Fns... fns) const {
  88. return This()(This()(std::move(args)), std::move(fns)...);
  89. }
  90. PUSHMI_TEMPLATE(class Out, class... Fns)
  91. (requires Receiver<Out>&& And<SemiMovable<Fns>...>)
  92. auto operator()(
  93. Out out,
  94. Fns... fns) const {
  95. return MakeReceiver()(std::move(out), std::move(fns)...);
  96. }
  97. };
  98. template <PUSHMI_TYPE_CONSTRAINT(Sender) In>
  99. using receiver_from_fn = receiver_from_impl<
  100. property_set_index_t<properties_t<In>, is_single<>>,
  101. property_query_v<properties_t<In>, is_flow<>>>;
  102. template <PUSHMI_TYPE_CONSTRAINT(Sender) In, class... AN>
  103. using receiver_type_t =
  104. typename receiver_from_fn<In>::template receiver_type<AN...>;
  105. template <class In, class FN>
  106. struct submit_transform_out_1 {
  107. FN fn_;
  108. PUSHMI_TEMPLATE(class Out)
  109. (requires Receiver<Out>&& Invocable<FN, Out>&&
  110. SenderTo<In, pushmi::invoke_result_t<const FN&, Out>>)
  111. void operator()(In& in, Out out) const {
  112. ::pushmi::submit(in, fn_(std::move(out)));
  113. }
  114. };
  115. template <class In, class FN>
  116. struct submit_transform_out_2 {
  117. FN fn_;
  118. PUSHMI_TEMPLATE(class CV, class Out)
  119. (requires Receiver<Out>&& Invocable<FN, Out>&&
  120. ConstrainedSenderTo<In, pushmi::invoke_result_t<const FN&, Out>>)
  121. void operator()(In& in, CV cv, Out out) const {
  122. ::pushmi::submit(in, cv, fn_(std::move(out)));
  123. }
  124. };
  125. template <class In, class SDSF>
  126. struct submit_transform_out_3 {
  127. SDSF sdsf_;
  128. PUSHMI_TEMPLATE(class Out)
  129. (requires Receiver<Out>&& Invocable<const SDSF&, In&, Out>)
  130. void operator()(In& in, Out out) const {
  131. sdsf_(in, std::move(out));
  132. }
  133. };
  134. template <class In, class TSDSF>
  135. struct submit_transform_out_4 {
  136. TSDSF tsdsf_;
  137. PUSHMI_TEMPLATE(class CV, class Out)
  138. (requires Receiver<Out>&& Invocable<const TSDSF&, In&, CV, Out>)
  139. void operator()(In& in, CV cv, Out out) const {
  140. tsdsf_(in, cv, std::move(out));
  141. }
  142. };
  143. PUSHMI_TEMPLATE(class In, class FN)
  144. (requires Sender<In>&& SemiMovable<FN> PUSHMI_BROKEN_SUBSUMPTION(
  145. &&not ConstrainedSender<In>))
  146. auto submit_transform_out(FN fn) {
  147. return on_submit(submit_transform_out_1<In, FN>{std::move(fn)});
  148. }
  149. PUSHMI_TEMPLATE(class In, class FN)
  150. (requires ConstrainedSender<In>&& SemiMovable<FN>)
  151. auto submit_transform_out(
  152. FN fn) {
  153. return submit_transform_out_2<In, FN>{std::move(fn)};
  154. }
  155. PUSHMI_TEMPLATE(class In, class SDSF, class TSDSF)
  156. (requires Sender<In>&& SemiMovable<SDSF>&& SemiMovable<TSDSF>
  157. PUSHMI_BROKEN_SUBSUMPTION(
  158. &&not ConstrainedSender<
  159. In>))
  160. auto submit_transform_out(SDSF sdsf, TSDSF) {
  161. return submit_transform_out_3<In, SDSF>{std::move(sdsf)};
  162. }
  163. PUSHMI_TEMPLATE(class In, class SDSF, class TSDSF)
  164. (requires ConstrainedSender<In>&& SemiMovable<SDSF>&&
  165. SemiMovable<TSDSF>)
  166. auto submit_transform_out(SDSF, TSDSF tsdsf) {
  167. return submit_transform_out_4<In, TSDSF>{std::move(tsdsf)};
  168. }
  169. template <
  170. class Cardinality,
  171. bool IsConstrained = false,
  172. bool IsTime = false,
  173. bool IsFlow = false>
  174. struct make_sender;
  175. template <>
  176. struct make_sender<is_single<>> : construct_deduced<single_sender> {};
  177. template <>
  178. struct make_sender<is_many<>> : construct_deduced<many_sender> {};
  179. template <>
  180. struct make_sender<is_single<>, false, false, true>
  181. : construct_deduced<flow_single_sender> {};
  182. template <>
  183. struct make_sender<is_many<>, false, false, true>
  184. : construct_deduced<flow_many_sender> {};
  185. template <>
  186. struct make_sender<is_single<>, true, true, false>
  187. : construct_deduced<time_single_sender> {};
  188. template <>
  189. struct make_sender<is_single<>, true, false, false>
  190. : construct_deduced<constrained_single_sender> {};
  191. PUSHMI_INLINE_VAR constexpr struct sender_from_fn {
  192. PUSHMI_TEMPLATE(class In, class... FN)
  193. (requires Sender<In>)
  194. auto operator()(In in, FN&&... fn) const {
  195. using MakeSender = make_sender<
  196. property_set_index_t<properties_t<In>, is_single<>>,
  197. property_query_v<properties_t<In>, is_constrained<>>,
  198. property_query_v<properties_t<In>, is_time<>>,
  199. property_query_v<properties_t<In>, is_flow<>>>;
  200. return MakeSender{}(std::move(in), (FN &&) fn...);
  201. }
  202. } const sender_from{};
  203. PUSHMI_TEMPLATE(
  204. class In,
  205. class Out,
  206. bool SenderRequires,
  207. bool SingleSenderRequires,
  208. bool TimeSingleSenderRequires)
  209. (requires Sender<In>&& Receiver<Out>)constexpr bool sender_requires_from() {
  210. PUSHMI_IF_CONSTEXPR_RETURN(((bool)TimeSenderTo<In, Out>)(
  211. return TimeSingleSenderRequires;
  212. ) else (
  213. PUSHMI_IF_CONSTEXPR_RETURN(((bool)SenderTo<In, Out>)(
  214. return SingleSenderRequires;
  215. ) else (
  216. PUSHMI_IF_CONSTEXPR_RETURN(((bool) SenderTo<In, Out>)(
  217. return SenderRequires;
  218. ) else (
  219. ))
  220. ))
  221. ))
  222. }
  223. struct set_value_fn {
  224. private:
  225. template <class... VN>
  226. struct impl {
  227. std::tuple<VN...> vn_;
  228. PUSHMI_TEMPLATE(class Out)
  229. (requires ReceiveValue<Out, VN...>)
  230. void operator()(Out out) {
  231. ::pushmi::apply(
  232. ::pushmi::set_value,
  233. std::tuple_cat(std::tuple<Out>{std::move(out)}, std::move(vn_)));
  234. }
  235. };
  236. public:
  237. template <class... VN>
  238. auto operator()(VN&&... vn) const {
  239. return impl<std::decay_t<VN>...>{(VN &&) vn...};
  240. }
  241. };
  242. struct set_error_fn {
  243. private:
  244. template <class E>
  245. struct impl {
  246. E e_;
  247. PUSHMI_TEMPLATE(class Out)
  248. (requires ReceiveError<Out, E>)
  249. void operator()(Out out) {
  250. ::pushmi::set_error(out, std::move(e_));
  251. }
  252. };
  253. public:
  254. PUSHMI_TEMPLATE(class E)
  255. (requires SemiMovable<E>)
  256. auto operator()(E e) const {
  257. return impl<E>{std::move(e)};
  258. }
  259. };
  260. struct set_done_fn {
  261. private:
  262. struct impl {
  263. PUSHMI_TEMPLATE(class Out)
  264. (requires Receiver<Out>)
  265. void operator()(Out out) {
  266. ::pushmi::set_done(out);
  267. }
  268. };
  269. public:
  270. auto operator()() const {
  271. return impl{};
  272. }
  273. };
  274. struct set_starting_fn {
  275. private:
  276. template <class Up>
  277. struct impl {
  278. Up up_;
  279. PUSHMI_TEMPLATE(class Out)
  280. (requires Receiver<Out>)
  281. void operator()(Out out) {
  282. ::pushmi::set_starting(out, std::move(up_));
  283. }
  284. };
  285. public:
  286. PUSHMI_TEMPLATE(class Up)
  287. (requires Receiver<Up>)
  288. auto operator()(Up up) const {
  289. return impl<Up>{std::move(up)};
  290. }
  291. };
  292. struct executor_fn {
  293. private:
  294. struct impl {
  295. PUSHMI_TEMPLATE(class In)
  296. (requires Sender<In>)
  297. auto operator()(In& in) const {
  298. return ::pushmi::executor(in);
  299. }
  300. };
  301. public:
  302. auto operator()() const {
  303. return impl{};
  304. }
  305. };
  306. struct do_submit_fn {
  307. private:
  308. template <class Out>
  309. struct impl {
  310. Out out_;
  311. PUSHMI_TEMPLATE(class In)
  312. (requires SenderTo<In, Out>)
  313. void operator()(In& in) {
  314. ::pushmi::submit(in, std::move(out_));
  315. }
  316. };
  317. template <class TP, class Out>
  318. struct time_impl {
  319. TP tp_;
  320. Out out_;
  321. PUSHMI_TEMPLATE(class In)
  322. (requires TimeSenderTo<In, Out>)
  323. void operator()(In& in) {
  324. ::pushmi::submit(in, std::move(tp_), std::move(out_));
  325. }
  326. };
  327. public:
  328. PUSHMI_TEMPLATE(class Out)
  329. (requires Receiver<Out>)
  330. auto operator()(Out out) const {
  331. return impl<Out>{std::move(out)};
  332. }
  333. PUSHMI_TEMPLATE(class TP, class Out)
  334. (requires Receiver<Out>)
  335. auto operator()(TP tp, Out out) const {
  336. return time_impl<TP, Out>{std::move(tp), std::move(out)};
  337. }
  338. };
  339. struct top_fn {
  340. private:
  341. struct impl {
  342. PUSHMI_TEMPLATE(class In)
  343. (requires ConstrainedSender<In>)
  344. auto operator()(In& in) const {
  345. return ::pushmi::top(in);
  346. }
  347. };
  348. public:
  349. auto operator()() const {
  350. return impl{};
  351. }
  352. };
  353. struct now_fn {
  354. private:
  355. struct impl {
  356. PUSHMI_TEMPLATE(class In)
  357. (requires TimeSender<In>)
  358. auto operator()(In& in) const {
  359. return ::pushmi::now(in);
  360. }
  361. };
  362. public:
  363. auto operator()() const {
  364. return impl{};
  365. }
  366. };
  367. } // namespace detail
  368. namespace extension_operators {
  369. PUSHMI_INLINE_VAR constexpr detail::set_done_fn set_done{};
  370. PUSHMI_INLINE_VAR constexpr detail::set_error_fn set_error{};
  371. PUSHMI_INLINE_VAR constexpr detail::set_value_fn set_value{};
  372. PUSHMI_INLINE_VAR constexpr detail::set_starting_fn set_starting{};
  373. PUSHMI_INLINE_VAR constexpr detail::executor_fn executor{};
  374. PUSHMI_INLINE_VAR constexpr detail::do_submit_fn submit{};
  375. PUSHMI_INLINE_VAR constexpr detail::now_fn now{};
  376. PUSHMI_INLINE_VAR constexpr detail::top_fn top{};
  377. } // namespace extension_operators
  378. } // namespace pushmi