executor.h 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505
  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 <chrono>
  18. #include <functional>
  19. #include <folly/experimental/pushmi/receiver.h>
  20. namespace pushmi {
  21. namespace detail {
  22. template <class T, template <class...> class C>
  23. using not_is_t = std::enable_if_t<!is_v<std::decay_t<T>, C>, std::decay_t<T>>;
  24. } // namespace detail
  25. //
  26. // define types for executors
  27. namespace detail {
  28. template <class T>
  29. using not_any_executor_ref_t = not_is_t<T, any_executor_ref>;
  30. } // namespace detail
  31. template<class E>
  32. struct any_executor_ref {
  33. private:
  34. using This = any_executor_ref;
  35. void* pobj_;
  36. struct vtable {
  37. void (*submit_)(void*, void*);
  38. } const *vptr_;
  39. template <class T>
  40. using wrapped_t = detail::not_any_executor_ref_t<T>;
  41. public:
  42. using properties = property_set<is_sender<>, is_executor<>, is_single<>>;
  43. any_executor_ref() = delete;
  44. any_executor_ref(const any_executor_ref&) = default;
  45. PUSHMI_TEMPLATE (class Wrapped)
  46. (requires Sender<wrapped_t<Wrapped>, is_executor<>, is_single<>>)
  47. // (requires SenderTo<wrapped_t<Wrapped>, any_receiver<E, This>>)
  48. any_executor_ref(Wrapped& w) {
  49. // This can't be a requirement because it asks if submit(w, any_receiver<E,T>)
  50. // is well-formed (where T is an alias for any_executor_ref). If w
  51. // has a submit that is constrained with SingleReceiver<any_receiver<E,T>, T'&, E'>, that
  52. // will ask whether value(any_receiver<E,T>, T'&) is well-formed. And *that* will
  53. // ask whether T'& is convertible to T. That brings us right back to this
  54. // constructor. Constraint recursion!
  55. static_assert(
  56. SenderTo<Wrapped, any_receiver<E,This>>,
  57. "Expecting to be passed a Sender that can send to a SingleReceiver"
  58. " that accpets a value of type This and an error of type E");
  59. struct s {
  60. static void submit(void* pobj, void* s) {
  61. return ::pushmi::submit(
  62. *static_cast<Wrapped*>(pobj),
  63. std::move(*static_cast<any_receiver<E,This>*>(s)));
  64. }
  65. };
  66. static const vtable vtbl{s::submit};
  67. pobj_ = std::addressof(w);
  68. vptr_ = &vtbl;
  69. }
  70. any_executor_ref executor() { return *this; }
  71. template<class SingleReceiver>
  72. void submit(SingleReceiver&& sa) {
  73. // static_assert(
  74. // ConvertibleTo<SingleReceiver, any_receiver<E, This>>,
  75. // "requires any_receiver<E, any_executor_ref<E>>");
  76. any_receiver<E, This> s{(SingleReceiver&&) sa};
  77. vptr_->submit_(pobj_, &s);
  78. }
  79. };
  80. ////////////////////////////////////////////////////////////////////////////////
  81. // make_any_executor_ref
  82. template <
  83. class E = std::exception_ptr>
  84. auto make_any_executor_ref() {
  85. return any_executor_ref<E>{};
  86. }
  87. PUSHMI_TEMPLATE (
  88. class E = std::exception_ptr,
  89. class Wrapped)
  90. (requires Sender<detail::not_any_executor_ref_t<Wrapped>, is_executor<>, is_single<>>)
  91. auto make_any_executor_ref(Wrapped& w) {
  92. return any_executor_ref<E>{w};
  93. }
  94. ////////////////////////////////////////////////////////////////////////////////
  95. // deduction guides
  96. #if __cpp_deduction_guides >= 201703
  97. any_executor_ref() ->
  98. any_executor_ref<
  99. std::exception_ptr>;
  100. PUSHMI_TEMPLATE (class Wrapped)
  101. (requires Sender<detail::not_any_executor_ref_t<Wrapped>, is_executor<>, is_single<>>)
  102. any_executor_ref(Wrapped&) ->
  103. any_executor_ref<
  104. std::exception_ptr>;
  105. #endif
  106. namespace detail {
  107. template<class E>
  108. using any_executor_base =
  109. any_single_sender<E, any_executor_ref<E>>;
  110. template<class T, class E>
  111. using not_any_executor =
  112. std::enable_if_t<
  113. !std::is_base_of<any_executor_base<E>, std::decay_t<T>>::value,
  114. std::decay_t<T>>;
  115. } // namespace detail
  116. template <class E>
  117. struct any_executor : detail::any_executor_base<E> {
  118. constexpr any_executor() = default;
  119. using properties = property_set<is_sender<>, is_executor<>, is_single<>>;
  120. using detail::any_executor_base<E>::any_executor_base;
  121. };
  122. ////////////////////////////////////////////////////////////////////////////////
  123. // make_any_executor
  124. template <
  125. class E = std::exception_ptr>
  126. auto make_any_executor() -> any_executor<E> {
  127. return any_executor<E>{};
  128. }
  129. PUSHMI_TEMPLATE(
  130. class E = std::exception_ptr,
  131. class Wrapped)
  132. (requires SenderTo<
  133. detail::not_any_executor<Wrapped, E>,
  134. any_receiver<E, any_executor_ref<E>>>)
  135. auto make_any_executor(Wrapped w) -> any_executor<E> {
  136. return any_executor<E>{std::move(w)};
  137. }
  138. ////////////////////////////////////////////////////////////////////////////////
  139. // deduction guides
  140. #if __cpp_deduction_guides >= 201703
  141. any_executor() ->
  142. any_executor<
  143. std::exception_ptr>;
  144. PUSHMI_TEMPLATE(class Wrapped)
  145. (requires SenderTo<
  146. detail::not_any_executor<
  147. Wrapped,
  148. std::exception_ptr>,
  149. any_receiver<
  150. std::exception_ptr,
  151. any_executor_ref<
  152. std::exception_ptr>>>)
  153. any_executor(Wrapped) ->
  154. any_executor<
  155. std::exception_ptr>;
  156. #endif
  157. //
  158. // define types for constrained executors
  159. namespace detail {
  160. template <class T>
  161. using not_any_constrained_executor_ref_t = not_is_t<T, any_constrained_executor_ref>;
  162. } // namespace detail
  163. template<class E, class CV>
  164. struct any_constrained_executor_ref {
  165. private:
  166. using This = any_constrained_executor_ref;
  167. void* pobj_;
  168. struct vtable {
  169. CV (*top_)(void*);
  170. void (*submit_)(void*, CV, void*);
  171. } const *vptr_;
  172. template <class T>
  173. using wrapped_t = detail::not_any_constrained_executor_ref_t<T>;
  174. public:
  175. using properties = property_set<is_constrained<>, is_executor<>, is_single<>>;
  176. any_constrained_executor_ref() = delete;
  177. any_constrained_executor_ref(const any_constrained_executor_ref&) = default;
  178. PUSHMI_TEMPLATE (class Wrapped)
  179. (requires ConstrainedSender<wrapped_t<Wrapped>, is_single<>>)
  180. // (requires ConstrainedSenderTo<wrapped_t<Wrapped>, any_receiver<E,This>>)
  181. any_constrained_executor_ref(Wrapped& w) {
  182. // This can't be a requirement because it asks if submit(w, top(w), any_receiver<E,T>)
  183. // is well-formed (where T is an alias for any_constrained_executor_ref). If w
  184. // has a submit that is constrained with ReceiveValue<any_receiver<E,T>, T'&>, that
  185. // will ask whether value(any_receiver<E,T>, T'&) is well-formed. And *that* will
  186. // ask whether T'& is convertible to T. That brings us right back to this
  187. // constructor. Constraint recursion!
  188. static_assert(
  189. ConstrainedSenderTo<Wrapped, any_receiver<E,This>>,
  190. "Expecting to be passed a ConstrainedSender that can send to a SingleReceiver"
  191. " that accpets a value of type This and an error of type E");
  192. struct s {
  193. static CV top(void* pobj) {
  194. return ::pushmi::top(*static_cast<Wrapped*>(pobj));
  195. }
  196. static void submit(void* pobj, CV cv, void* s) {
  197. return ::pushmi::submit(
  198. *static_cast<Wrapped*>(pobj),
  199. cv,
  200. std::move(*static_cast<any_receiver<E,This>*>(s)));
  201. }
  202. };
  203. static const vtable vtbl{s::top, s::submit};
  204. pobj_ = std::addressof(w);
  205. vptr_ = &vtbl;
  206. }
  207. CV top() {
  208. return vptr_->top_(pobj_);
  209. }
  210. any_constrained_executor_ref executor() { return *this; }
  211. template<class SingleReceiver>
  212. void submit(CV cv, SingleReceiver&& sa) {
  213. // static_assert(
  214. // ConvertibleTo<SingleReceiver, any_receiver<E, This>>,
  215. // "requires any_receiver<E, any_constrained_executor_ref<E, TP>>");
  216. any_receiver<E, This> s{(SingleReceiver&&) sa};
  217. vptr_->submit_(pobj_, cv, &s);
  218. }
  219. };
  220. ////////////////////////////////////////////////////////////////////////////////
  221. // make_any_constrained_executor_ref
  222. template <
  223. class E = std::exception_ptr,
  224. class CV = std::ptrdiff_t>
  225. auto make_any_constrained_executor_ref() {
  226. return any_constrained_executor_ref<E, CV>{};
  227. }
  228. PUSHMI_TEMPLATE (
  229. class E = std::exception_ptr,
  230. class Wrapped)
  231. (requires ConstrainedSender<detail::not_any_constrained_executor_ref_t<Wrapped>, is_single<>>)
  232. auto make_any_constrained_executor_ref(Wrapped& w) {
  233. return any_constrained_executor_ref<E, constraint_t<Wrapped>>{w};
  234. }
  235. ////////////////////////////////////////////////////////////////////////////////
  236. // deduction guides
  237. #if __cpp_deduction_guides >= 201703
  238. any_constrained_executor_ref() ->
  239. any_constrained_executor_ref<
  240. std::exception_ptr,
  241. std::ptrdiff_t>;
  242. PUSHMI_TEMPLATE (class Wrapped)
  243. (requires ConstrainedSender<detail::not_any_constrained_executor_ref_t<Wrapped>, is_single<>>)
  244. any_constrained_executor_ref(Wrapped&) ->
  245. any_constrained_executor_ref<
  246. std::exception_ptr,
  247. constraint_t<Wrapped>>;
  248. #endif
  249. namespace detail {
  250. template<class E, class CV>
  251. using any_constrained_executor_base =
  252. any_constrained_single_sender<E, CV, any_constrained_executor_ref<E, CV>>;
  253. template<class T, class E, class CV>
  254. using not_any_constrained_executor =
  255. std::enable_if_t<
  256. !std::is_base_of<any_constrained_executor_base<E, CV>, std::decay_t<T>>::value,
  257. std::decay_t<T>>;
  258. } // namespace detail
  259. template <class E, class CV>
  260. struct any_constrained_executor : detail::any_constrained_executor_base<E, CV> {
  261. using properties = property_set<is_constrained<>, is_executor<>, is_single<>>;
  262. constexpr any_constrained_executor() = default;
  263. using detail::any_constrained_executor_base<E, CV>::any_constrained_executor_base;
  264. };
  265. ////////////////////////////////////////////////////////////////////////////////
  266. // make_any_constrained_executor
  267. template <
  268. class E = std::exception_ptr,
  269. class CV = std::ptrdiff_t>
  270. auto make_any_constrained_executor() -> any_constrained_executor<E, CV> {
  271. return any_constrained_executor<E, CV>{};
  272. }
  273. PUSHMI_TEMPLATE(
  274. class E = std::exception_ptr,
  275. class Wrapped)
  276. (requires ConstrainedSenderTo<
  277. detail::not_any_constrained_executor<Wrapped, E, constraint_t<Wrapped>>,
  278. any_receiver<E, any_constrained_executor_ref<E, constraint_t<Wrapped>>>>)
  279. auto make_any_constrained_executor(Wrapped w) -> any_constrained_executor<E, constraint_t<Wrapped>> {
  280. return any_constrained_executor<E, constraint_t<Wrapped>>{std::move(w)};
  281. }
  282. ////////////////////////////////////////////////////////////////////////////////
  283. // deduction guides
  284. #if __cpp_deduction_guides >= 201703
  285. any_constrained_executor() ->
  286. any_constrained_executor<
  287. std::exception_ptr,
  288. std::ptrdiff_t>;
  289. PUSHMI_TEMPLATE(class Wrapped)
  290. (requires ConstrainedSenderTo<
  291. detail::not_any_constrained_executor<
  292. Wrapped,
  293. std::exception_ptr,
  294. constraint_t<Wrapped>>,
  295. any_receiver<
  296. std::exception_ptr,
  297. any_constrained_executor_ref<
  298. std::exception_ptr,
  299. constraint_t<Wrapped>>>>)
  300. any_constrained_executor(Wrapped) ->
  301. any_constrained_executor<
  302. std::exception_ptr,
  303. constraint_t<Wrapped>>;
  304. #endif
  305. //
  306. // define types for time executors
  307. namespace detail {
  308. template <class T>
  309. using not_any_time_executor_ref_t = not_is_t<T, any_time_executor_ref>;
  310. } // namespace detail
  311. template<class E, class TP>
  312. struct any_time_executor_ref {
  313. private:
  314. using This = any_time_executor_ref;
  315. void* pobj_;
  316. struct vtable {
  317. TP (*now_)(void*);
  318. void (*submit_)(void*, TP, void*);
  319. } const *vptr_;
  320. template <class T>
  321. using wrapped_t = detail::not_any_time_executor_ref_t<T>;
  322. public:
  323. using properties = property_set<is_time<>, is_executor<>, is_single<>>;
  324. any_time_executor_ref() = delete;
  325. any_time_executor_ref(const any_time_executor_ref&) = default;
  326. PUSHMI_TEMPLATE (class Wrapped)
  327. (requires TimeSender<wrapped_t<Wrapped>, is_single<>>)
  328. // (requires TimeSenderTo<wrapped_t<Wrapped>, receiver<E, This>>)
  329. any_time_executor_ref(Wrapped& w) {
  330. // This can't be a requirement because it asks if submit(w, now(w), any_receiver<E, T>)
  331. // is well-formed (where T is an alias for any_time_executor_ref). If w
  332. // has a submit that is constrained with ReceiverValue<any_receiver<E, T>, T'&>, that
  333. // will ask whether value(any_receiver<E, T>, T'&) is well-formed. And *that* will
  334. // ask whether T'& is convertible to T. That brings us right back to this
  335. // constructor. Constraint recursion!
  336. static_assert(
  337. TimeSenderTo<Wrapped, any_receiver<E, This>>,
  338. "Expecting to be passed a TimeSender that can send to a SingleReceiver"
  339. " that accpets a value of type This and an error of type E");
  340. struct s {
  341. static TP now(void* pobj) {
  342. return ::pushmi::now(*static_cast<Wrapped*>(pobj));
  343. }
  344. static void submit(void* pobj, TP tp, void* s) {
  345. return ::pushmi::submit(
  346. *static_cast<Wrapped*>(pobj),
  347. tp,
  348. std::move(*static_cast<any_receiver<E,This>*>(s)));
  349. }
  350. };
  351. static const vtable vtbl{s::now, s::submit};
  352. pobj_ = std::addressof(w);
  353. vptr_ = &vtbl;
  354. }
  355. std::chrono::system_clock::time_point top() {
  356. return vptr_->now_(pobj_);
  357. }
  358. any_time_executor_ref executor() { return *this; }
  359. template<class SingleReceiver>
  360. void submit(TP tp, SingleReceiver&& sa) {
  361. // static_assert(
  362. // ConvertibleTo<SingleReceiver, any_receiver<E, This>>,
  363. // "requires any_receiver<E, any_time_executor_ref<E, TP>>");
  364. any_receiver<E, This> s{(SingleReceiver&&) sa};
  365. vptr_->submit_(pobj_, tp, &s);
  366. }
  367. };
  368. ////////////////////////////////////////////////////////////////////////////////
  369. // make_any_time_executor_ref
  370. template <
  371. class E = std::exception_ptr,
  372. class TP = std::chrono::system_clock::time_point>
  373. auto make_any_time_executor_ref() {
  374. return any_time_executor_ref<E, TP>{};
  375. }
  376. PUSHMI_TEMPLATE (
  377. class E = std::exception_ptr,
  378. class Wrapped)
  379. (requires TimeSender<detail::not_any_time_executor_ref_t<Wrapped>, is_single<>>)
  380. auto make_any_time_executor_ref(Wrapped& w) {
  381. return any_time_executor_ref<E, time_point_t<Wrapped>>{w};
  382. }
  383. ////////////////////////////////////////////////////////////////////////////////
  384. // deduction guides
  385. #if __cpp_deduction_guides >= 201703
  386. any_time_executor_ref() ->
  387. any_time_executor_ref<
  388. std::exception_ptr,
  389. std::chrono::system_clock::time_point>;
  390. PUSHMI_TEMPLATE (class Wrapped)
  391. (requires TimeSender<detail::not_any_time_executor_ref_t<Wrapped>, is_single<>>)
  392. any_time_executor_ref(Wrapped&) ->
  393. any_time_executor_ref<
  394. std::exception_ptr,
  395. time_point_t<Wrapped>>;
  396. #endif
  397. namespace detail {
  398. template<class E, class TP>
  399. using any_time_executor_base =
  400. any_time_single_sender<E, TP, any_time_executor_ref<E, TP>>;
  401. template<class T, class E, class TP>
  402. using not_any_time_executor =
  403. std::enable_if_t<
  404. !std::is_base_of<any_time_executor_base<E, TP>, std::decay_t<T>>::value,
  405. std::decay_t<T>>;
  406. } // namespace detail
  407. template <class E, class TP>
  408. struct any_time_executor : detail::any_time_executor_base<E, TP> {
  409. using properties = property_set<is_time<>, is_executor<>, is_single<>>;
  410. constexpr any_time_executor() = default;
  411. using detail::any_time_executor_base<E, TP>::any_time_executor_base;
  412. };
  413. ////////////////////////////////////////////////////////////////////////////////
  414. // make_any_time_executor
  415. template <
  416. class E = std::exception_ptr,
  417. class TP = std::chrono::system_clock::time_point>
  418. auto make_any_time_executor() -> any_time_executor<E, TP> {
  419. return any_time_executor<E, TP>{};
  420. }
  421. PUSHMI_TEMPLATE(
  422. class E = std::exception_ptr,
  423. class Wrapped)
  424. (requires TimeSenderTo<
  425. detail::not_any_time_executor<Wrapped, E, time_point_t<Wrapped>>,
  426. any_receiver<E, any_time_executor_ref<E, time_point_t<Wrapped>>>>)
  427. auto make_any_time_executor(Wrapped w) -> any_time_executor<E, time_point_t<Wrapped>> {
  428. return any_time_executor<E, time_point_t<Wrapped>>{std::move(w)};
  429. }
  430. ////////////////////////////////////////////////////////////////////////////////
  431. // deduction guides
  432. #if __cpp_deduction_guides >= 201703
  433. any_time_executor() ->
  434. any_time_executor<
  435. std::exception_ptr,
  436. std::chrono::system_clock::time_point>;
  437. PUSHMI_TEMPLATE(class Wrapped)
  438. (requires TimeSenderTo<
  439. detail::not_any_time_executor<
  440. Wrapped,
  441. std::exception_ptr,
  442. time_point_t<Wrapped>>,
  443. any_receiver<
  444. std::exception_ptr,
  445. any_time_executor_ref<
  446. std::exception_ptr,
  447. time_point_t<Wrapped>>>>)
  448. any_time_executor(Wrapped) ->
  449. any_time_executor<
  450. std::exception_ptr,
  451. time_point_t<Wrapped>>;
  452. #endif
  453. } // namespace pushmi