extension_points.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  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 <future>
  18. #include <functional>
  19. #include <folly/experimental/pushmi/forwards.h>
  20. #include <folly/experimental/pushmi/properties.h>
  21. #include <folly/experimental/pushmi/traits.h>
  22. namespace pushmi {
  23. namespace __adl {
  24. //
  25. // support methods on a class reference
  26. //
  27. PUSHMI_TEMPLATE (class S)
  28. (requires requires (std::declval<S&>().done()))
  29. void set_done(S& s) noexcept(noexcept(s.done())) {
  30. s.done();
  31. }
  32. PUSHMI_TEMPLATE (class S, class E)
  33. (requires requires (std::declval<S&>().error(std::declval<E>())))
  34. void set_error(S& s, E e) noexcept(noexcept(s.error(std::move(e)))) {
  35. s.error(std::move(e));
  36. }
  37. PUSHMI_TEMPLATE (class S, class... VN)
  38. (requires requires (std::declval<S&>().value(std::declval<VN&&>()...)))
  39. void set_value(S& s, VN&&... vn) noexcept(noexcept(s.value((VN&&) vn...))) {
  40. s.value((VN&&) vn...);
  41. }
  42. PUSHMI_TEMPLATE (class S, class Up)
  43. (requires requires (std::declval<S&>().starting(std::declval<Up&&>())))
  44. void set_starting(S& s, Up&& up) noexcept(noexcept(s.starting((Up&&) up))) {
  45. s.starting((Up&&) up);
  46. }
  47. PUSHMI_TEMPLATE (class SD)
  48. (requires requires (std::declval<SD&>().executor()))
  49. auto executor(SD& sd) noexcept(noexcept(sd.executor())) {
  50. return sd.executor();
  51. }
  52. PUSHMI_TEMPLATE (class SD, class Out)
  53. (requires requires (
  54. std::declval<SD&>().submit(std::declval<Out>())
  55. ))
  56. void submit(SD& sd, Out out) noexcept(noexcept(sd.submit(std::move(out)))) {
  57. sd.submit(std::move(out));
  58. }
  59. PUSHMI_TEMPLATE (class SD)
  60. (requires requires (std::declval<SD&>().top()))
  61. auto top(SD& sd) noexcept(noexcept(sd.top())) {
  62. return sd.top();
  63. }
  64. PUSHMI_TEMPLATE (class SD, class TP, class Out)
  65. (requires requires (
  66. std::declval<SD&>().submit(
  67. std::declval<TP(&)(TP)>()(top(std::declval<SD&>())),
  68. std::declval<Out>())
  69. ))
  70. void submit(SD& sd, TP tp, Out out)
  71. noexcept(noexcept(sd.submit(std::move(tp), std::move(out)))) {
  72. sd.submit(std::move(tp), std::move(out));
  73. }
  74. //
  75. // support methods on a class pointer
  76. //
  77. PUSHMI_TEMPLATE (class S)
  78. (requires requires (std::declval<S&>()->done()))
  79. void set_done(S& s) noexcept(noexcept(s->done())) {
  80. s->done();
  81. }
  82. PUSHMI_TEMPLATE (class S, class E)
  83. (requires requires (std::declval<S&>()->error(std::declval<E>())))
  84. void set_error(S& s, E e) noexcept(noexcept(s->error(std::move(e)))) {
  85. s->error(std::move(e));
  86. }
  87. PUSHMI_TEMPLATE (class S, class... VN)
  88. (requires requires (std::declval<S&>()->value(std::declval<VN&&>()...)))
  89. void set_value(S& s, VN&&... vn) noexcept(noexcept(s->value((VN&&) vn...))) {
  90. s->value((VN&&) vn...);
  91. }
  92. PUSHMI_TEMPLATE (class S, class Up)
  93. (requires requires (std::declval<S&>()->starting(std::declval<Up&&>())))
  94. void set_starting(S& s, Up&& up) noexcept(noexcept(s->starting((Up&&) up))) {
  95. s->starting((Up&&) up);
  96. }
  97. PUSHMI_TEMPLATE (class SD)
  98. (requires requires (std::declval<SD&>()->executor()))
  99. auto executor(SD& sd) noexcept(noexcept(sd->executor())) {
  100. return sd->executor();
  101. }
  102. PUSHMI_TEMPLATE (class SD, class Out)
  103. (requires requires (std::declval<SD&>()->submit(std::declval<Out>())))
  104. void submit(SD& sd, Out out) noexcept(noexcept(sd->submit(std::move(out)))) {
  105. sd->submit(std::move(out));
  106. }
  107. PUSHMI_TEMPLATE (class SD)
  108. (requires requires (std::declval<SD&>()->top()))
  109. auto top(SD& sd) noexcept(noexcept(sd->top())) {
  110. return sd->top();
  111. }
  112. PUSHMI_TEMPLATE (class SD, class TP, class Out)
  113. (requires requires (
  114. std::declval<SD&>()->submit(
  115. std::declval<TP(&)(TP)>()(top(std::declval<SD&>())),
  116. std::declval<Out>())
  117. ))
  118. void submit(SD& sd, TP tp, Out out)
  119. noexcept(noexcept(sd->submit(std::move(tp), std::move(out)))) {
  120. sd->submit(std::move(tp), std::move(out));
  121. }
  122. //
  123. // support a nullary function as a receiver
  124. //
  125. PUSHMI_TEMPLATE (class S)
  126. (requires Invocable<S&>)
  127. void set_done(S&) noexcept {
  128. }
  129. PUSHMI_TEMPLATE (class S, class E)
  130. (requires Invocable<S&>)
  131. void set_error(S&, E&&) noexcept {
  132. std::abort();
  133. }
  134. PUSHMI_TEMPLATE (class S)
  135. (requires Invocable<S&>)
  136. void set_value(S& s) noexcept(noexcept(s())) {
  137. s();
  138. }
  139. //
  140. // add support for std::promise externally
  141. //
  142. // std::promise does not support the done signal.
  143. // either set_value or set_error must be called
  144. template <class T>
  145. void set_done(std::promise<T>&) noexcept {}
  146. template <class T>
  147. void set_error(std::promise<T>& p, std::exception_ptr e) noexcept {
  148. p.set_exception(std::move(e));
  149. }
  150. template <class T, class E>
  151. void set_error(std::promise<T>& p, E e) noexcept {
  152. p.set_exception(std::make_exception_ptr(std::move(e)));
  153. }
  154. template <class T>
  155. void set_value(std::promise<T>& p, T t) noexcept(noexcept(p.set_value(std::move(t)))) {
  156. p.set_value(std::move(t));
  157. }
  158. inline void set_value(std::promise<void>& p) noexcept(noexcept(p.set_value())) {
  159. p.set_value();
  160. }
  161. //
  162. // support reference_wrapper
  163. //
  164. PUSHMI_TEMPLATE (class S)
  165. (requires requires ( set_done(std::declval<S&>()) ))
  166. void set_done(std::reference_wrapper<S> s) noexcept(
  167. noexcept(set_done(s.get()))) {
  168. set_done(s.get());
  169. }
  170. PUSHMI_TEMPLATE (class S, class E)
  171. (requires requires ( set_error(std::declval<S&>(), std::declval<E>()) ))
  172. void set_error(std::reference_wrapper<S> s, E e) noexcept {
  173. set_error(s.get(), std::move(e));
  174. }
  175. PUSHMI_TEMPLATE (class S, class... VN)
  176. (requires requires ( set_value(std::declval<S&>(), std::declval<VN&&>()...) ))
  177. void set_value(std::reference_wrapper<S> s, VN&&... vn) noexcept(
  178. noexcept(set_value(s.get(), (VN&&) vn...))) {
  179. set_value(s.get(), (VN&&) vn...);
  180. }
  181. PUSHMI_TEMPLATE (class S, class Up)
  182. (requires requires ( set_starting(std::declval<S&>(), std::declval<Up&&>()) ))
  183. void set_starting(std::reference_wrapper<S> s, Up&& up) noexcept(
  184. noexcept(set_starting(s.get(), (Up&&) up))) {
  185. set_starting(s.get(), (Up&&) up);
  186. }
  187. PUSHMI_TEMPLATE (class SD)
  188. (requires requires ( executor(std::declval<SD&>()) ))
  189. auto executor(std::reference_wrapper<SD> sd) noexcept(noexcept(executor(sd.get()))) {
  190. return executor(sd.get());
  191. }
  192. PUSHMI_TEMPLATE (class SD, class Out)
  193. (requires requires ( submit(std::declval<SD&>(), std::declval<Out>()) ))
  194. void submit(std::reference_wrapper<SD> sd, Out out) noexcept(
  195. noexcept(submit(sd.get(), std::move(out)))) {
  196. submit(sd.get(), std::move(out));
  197. }
  198. PUSHMI_TEMPLATE (class SD)
  199. (requires requires ( top(std::declval<SD&>()) ))
  200. auto top(std::reference_wrapper<SD> sd) noexcept(noexcept(top(sd.get()))) {
  201. return top(sd.get());
  202. }
  203. PUSHMI_TEMPLATE (class SD, class TP, class Out)
  204. (requires requires (
  205. submit(
  206. std::declval<SD&>(),
  207. std::declval<TP(&)(TP)>()(top(std::declval<SD&>())),
  208. std::declval<Out>())
  209. ))
  210. void submit(std::reference_wrapper<SD> sd, TP tp, Out out)
  211. noexcept(noexcept(submit(sd.get(), std::move(tp), std::move(out)))) {
  212. submit(sd.get(), std::move(tp), std::move(out));
  213. }
  214. //
  215. // accessors for free functions in this namespace
  216. //
  217. struct set_done_fn {
  218. PUSHMI_TEMPLATE (class S)
  219. (requires requires (
  220. set_done(std::declval<S&>()),
  221. set_error(std::declval<S&>(), std::current_exception())
  222. ))
  223. void operator()(S&& s) const noexcept(noexcept(set_done(s))) {
  224. try {
  225. set_done(s);
  226. } catch (...) {
  227. set_error(s, std::current_exception());
  228. }
  229. }
  230. };
  231. struct set_error_fn {
  232. PUSHMI_TEMPLATE (class S, class E)
  233. (requires requires (
  234. set_error(std::declval<S&>(), std::declval<E>())
  235. ))
  236. void operator()(S&& s, E e) const
  237. noexcept(noexcept(set_error(s, std::move(e)))) {
  238. set_error(s, std::move(e));
  239. }
  240. };
  241. struct set_value_fn {
  242. PUSHMI_TEMPLATE (class S, class... VN)
  243. (requires requires (
  244. set_value(std::declval<S&>(), std::declval<VN&&>()...),
  245. set_error(std::declval<S&>(), std::current_exception())
  246. ))
  247. void operator()(S&& s, VN&&... vn) const
  248. noexcept(noexcept(set_value(s, (VN&&) vn...))) {
  249. try {
  250. set_value(s, (VN&&) vn...);
  251. } catch (...) {
  252. set_error(s, std::current_exception());
  253. }
  254. }
  255. };
  256. struct set_starting_fn {
  257. PUSHMI_TEMPLATE (class S, class Up)
  258. (requires requires (
  259. set_starting(std::declval<S&>(), std::declval<Up&&>()),
  260. set_error(std::declval<S&>(), std::current_exception())
  261. ))
  262. void operator()(S&& s, Up&& up) const
  263. noexcept(noexcept(set_starting(s, (Up&&) up))) {
  264. try {
  265. set_starting(s, (Up&&) up);
  266. } catch (...) {
  267. set_error(s, std::current_exception());
  268. }
  269. }
  270. };
  271. struct get_executor_fn {
  272. PUSHMI_TEMPLATE (class SD)
  273. (requires requires (
  274. executor(std::declval<SD&>())
  275. ))
  276. auto operator()(SD&& sd) const noexcept(noexcept(executor(sd))) {
  277. return executor(sd);
  278. }
  279. };
  280. struct do_submit_fn {
  281. PUSHMI_TEMPLATE (class SD, class Out)
  282. (requires requires (
  283. submit(std::declval<SD&>(), std::declval<Out>())
  284. ))
  285. void operator()(SD&& s, Out out) const
  286. noexcept(noexcept(submit(s, std::move(out)))) {
  287. submit(s, std::move(out));
  288. }
  289. PUSHMI_TEMPLATE (class SD, class Out)
  290. (requires requires (
  291. submit(std::declval<SD&>(), top(std::declval<SD&>()), std::declval<Out>())
  292. ))
  293. void operator()(SD&& s, Out out) const
  294. noexcept(noexcept(submit(s, top(s), std::move(out)))) {
  295. submit(s, top(s), std::move(out));
  296. }
  297. PUSHMI_TEMPLATE (class SD, class TP, class Out)
  298. (requires requires (
  299. submit(
  300. std::declval<SD&>(),
  301. std::declval<TP>(),
  302. std::declval<Out>())
  303. ))
  304. void operator()(SD&& s, TP tp, Out out) const
  305. noexcept(noexcept(submit(s, std::move(tp), std::move(out)))) {
  306. submit(s, std::move(tp), std::move(out));
  307. }
  308. };
  309. struct get_top_fn {
  310. PUSHMI_TEMPLATE (class SD)
  311. (requires requires (
  312. top(std::declval<SD&>())
  313. ))
  314. auto operator()(SD&& sd) const noexcept(noexcept(top(sd))) {
  315. return top(sd);
  316. }
  317. };
  318. } // namespace __adl
  319. PUSHMI_INLINE_VAR constexpr __adl::set_done_fn set_done{};
  320. PUSHMI_INLINE_VAR constexpr __adl::set_error_fn set_error{};
  321. PUSHMI_INLINE_VAR constexpr __adl::set_value_fn set_value{};
  322. PUSHMI_INLINE_VAR constexpr __adl::set_starting_fn set_starting{};
  323. PUSHMI_INLINE_VAR constexpr __adl::get_executor_fn executor{};
  324. PUSHMI_INLINE_VAR constexpr __adl::do_submit_fn submit{};
  325. PUSHMI_INLINE_VAR constexpr __adl::get_top_fn now{};
  326. PUSHMI_INLINE_VAR constexpr __adl::get_top_fn top{};
  327. template<class T>
  328. struct property_set_traits<T, std::enable_if_t<(bool)Invocable<T&> &&
  329. not Valid<T&, __properties_t>>> {
  330. using properties = property_set<is_receiver<>>;
  331. };
  332. template <class T>
  333. struct property_set_traits<std::promise<T>> {
  334. using properties = property_set<is_receiver<>>;
  335. };
  336. template <>
  337. struct property_set_traits<std::promise<void>> {
  338. using properties = property_set<is_receiver<>>;
  339. };
  340. } // namespace pushmi