for_each.h 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  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/o/extension_operators.h>
  18. #include <folly/experimental/pushmi/o/submit.h>
  19. namespace pushmi {
  20. namespace detail {
  21. struct for_each_fn {
  22. private:
  23. template <class... PN>
  24. struct subset {
  25. using properties = property_set<PN...>;
  26. };
  27. template <class In, class Out>
  28. struct Pull : Out {
  29. explicit Pull(Out out) : Out(std::move(out)) {}
  30. using properties =
  31. property_set_insert_t<properties_t<Out>, property_set<is_flow<>>>;
  32. std::function<void(std::ptrdiff_t)> pull;
  33. template <class V>
  34. void value(V&& v) {
  35. ::pushmi::set_value(static_cast<Out&>(*this), (V &&) v);
  36. pull(1);
  37. }
  38. PUSHMI_TEMPLATE(class Up)
  39. (requires Receiver<Up>)
  40. void starting(Up up) {
  41. pull = [up = std::move(up)](std::ptrdiff_t requested) mutable {
  42. ::pushmi::set_value(up, requested);
  43. };
  44. pull(1);
  45. }
  46. PUSHMI_TEMPLATE(class Up)
  47. (requires ReceiveValue<Up>)
  48. void starting(Up) {}
  49. };
  50. template <class... AN>
  51. struct fn {
  52. std::tuple<AN...> args_;
  53. PUSHMI_TEMPLATE(class In)
  54. (requires Sender<In>&& Flow<In>&& Many<In>)
  55. In operator()(In in) {
  56. auto out{::pushmi::detail::receiver_from_fn<subset<
  57. is_sender<>,
  58. property_set_index_t<properties_t<In>, is_single<>>>>()(
  59. std::move(args_))};
  60. using Out = decltype(out);
  61. ::pushmi::submit(
  62. in,
  63. ::pushmi::detail::receiver_from_fn<In>()(
  64. Pull<In, Out>{std::move(out)}));
  65. return in;
  66. }
  67. PUSHMI_TEMPLATE(class In)
  68. (requires Sender<In>&& Constrained<In>&& Flow<In>&& Many<In>)
  69. In operator()(In in) {
  70. auto out{::pushmi::detail::receiver_from_fn<subset<
  71. is_sender<>,
  72. property_set_index_t<properties_t<In>, is_single<>>>>()(
  73. std::move(args_))};
  74. using Out = decltype(out);
  75. ::pushmi::submit(
  76. in,
  77. ::pushmi::top(in),
  78. ::pushmi::detail::receiver_from_fn<In>()(
  79. Pull<In, Out>{std::move(out)}));
  80. return in;
  81. }
  82. };
  83. public:
  84. template <class... AN>
  85. auto operator()(AN&&... an) const {
  86. return for_each_fn::fn<AN...>{{(AN &&) an...}};
  87. }
  88. };
  89. } // namespace detail
  90. namespace operators {
  91. PUSHMI_INLINE_VAR constexpr detail::for_each_fn for_each{};
  92. } // namespace operators
  93. } // namespace pushmi