transform.h 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  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/flow_receiver.h>
  18. #include <folly/experimental/pushmi/o/extension_operators.h>
  19. #include <folly/experimental/pushmi/o/submit.h>
  20. #include <folly/experimental/pushmi/receiver.h>
  21. namespace pushmi {
  22. namespace detail {
  23. template <class F, class Tag, bool IsFlow = false>
  24. struct transform_on;
  25. template <class F>
  26. struct transform_on<F, is_single<>> {
  27. F f_;
  28. transform_on() = default;
  29. constexpr explicit transform_on(F f) : f_(std::move(f)) {}
  30. struct value_fn {
  31. F f_;
  32. value_fn() = default;
  33. constexpr explicit value_fn(F f) : f_(std::move(f)) {}
  34. template <class Out, class V0, class... VN>
  35. auto operator()(Out& out, V0&& v0, VN&&... vn) {
  36. using Result = ::pushmi::invoke_result_t<F, V0, VN...>;
  37. static_assert(
  38. ::pushmi::SemiMovable<Result>,
  39. "none of the functions supplied to transform can convert this value");
  40. static_assert(
  41. ::pushmi::ReceiveValue<Out, Result>,
  42. "Result of value transform cannot be delivered to Out");
  43. ::pushmi::set_value(out, f_((V0 &&) v0, (VN &&) vn...));
  44. }
  45. };
  46. template <class Out>
  47. auto operator()(Out out) const {
  48. return ::pushmi::make_receiver(std::move(out), value_fn{f_});
  49. }
  50. };
  51. template <class F>
  52. struct transform_on<F, is_single<>, true> {
  53. F f_;
  54. transform_on() = default;
  55. constexpr explicit transform_on(F f) : f_(std::move(f)) {}
  56. template <class Out>
  57. auto operator()(Out out) const {
  58. return make_flow_single(std::move(out), on_value(*this));
  59. }
  60. template <class Out, class V0, class... VN>
  61. auto operator()(Out& out, V0&& v0, VN&&... vn) {
  62. using Result = ::pushmi::invoke_result_t<F, V0, VN...>;
  63. static_assert(
  64. ::pushmi::SemiMovable<Result>,
  65. "none of the functions supplied to transform can convert this value");
  66. static_assert(
  67. ::pushmi::Flow<Out> && ::pushmi::ReceiveValue<Out, Result>,
  68. "Result of value transform cannot be delivered to Out");
  69. ::pushmi::set_value(out, f_((V0 &&) v0, (VN &&) vn...));
  70. }
  71. };
  72. template <class F>
  73. struct transform_on<F, is_many<>> {
  74. F f_;
  75. transform_on() = default;
  76. constexpr explicit transform_on(F f) : f_(std::move(f)) {}
  77. template <class Out>
  78. auto operator()(Out out) const {
  79. return ::pushmi::make_receiver(std::move(out), on_value(*this));
  80. }
  81. template <class Out, class V0, class... VN>
  82. auto operator()(Out& out, V0&& v0, VN&&... vn) {
  83. using Result = ::pushmi::invoke_result_t<F, V0, VN...>;
  84. static_assert(
  85. ::pushmi::SemiMovable<Result>,
  86. "none of the functions supplied to transform can convert this value");
  87. static_assert(
  88. ::pushmi::ReceiveValue<Out, Result>,
  89. "Result of value transform cannot be delivered to Out");
  90. ::pushmi::set_value(out, f_((V0 &&) v0, (VN &&) vn...));
  91. }
  92. };
  93. template <class F>
  94. struct transform_on<F, is_many<>, true> {
  95. F f_;
  96. transform_on() = default;
  97. constexpr explicit transform_on(F f) : f_(std::move(f)) {}
  98. template <class Out>
  99. auto operator()(Out out) const {
  100. return make_flow_receiver(std::move(out), on_value(*this));
  101. }
  102. template <class Out, class V0, class... VN>
  103. auto operator()(Out& out, V0&& v0, VN&&... vn) {
  104. using Result = ::pushmi::invoke_result_t<F, V0, VN...>;
  105. static_assert(
  106. ::pushmi::SemiMovable<Result>,
  107. "none of the functions supplied to transform can convert this value");
  108. static_assert(
  109. ::pushmi::Flow<Out> && ::pushmi::ReceiveValue<Out, Result>,
  110. "Result of value transform cannot be delivered to Out");
  111. ::pushmi::set_value(out, f_((V0 &&) v0, (VN &&) vn...));
  112. }
  113. };
  114. struct transform_fn {
  115. private:
  116. template <class F>
  117. struct impl {
  118. F f_;
  119. PUSHMI_TEMPLATE(class In)
  120. (requires Sender<In>)
  121. auto operator()(In in) const {
  122. using Cardinality = property_set_index_t<properties_t<In>, is_single<>>;
  123. return ::pushmi::detail::sender_from(
  124. std::move(in),
  125. ::pushmi::detail::submit_transform_out<In>(
  126. // copy 'f_' to allow multiple calls to connect to multiple 'in'
  127. transform_on<
  128. F,
  129. Cardinality,
  130. property_query_v<properties_t<In>, is_flow<>>>{f_}));
  131. }
  132. };
  133. public:
  134. template <class... FN>
  135. auto operator()(FN... fn) const {
  136. auto f = ::pushmi::overload(std::move(fn)...);
  137. using F = decltype(f);
  138. return impl<F>{std::move(f)};
  139. }
  140. };
  141. } // namespace detail
  142. namespace operators {
  143. PUSHMI_INLINE_VAR constexpr detail::transform_fn transform{};
  144. } // namespace operators
  145. } // namespace pushmi