pipeable_view.hpp 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. // Copyright (C) 2022 T. Zachary Laine
  2. //
  3. // Distributed under the Boost Software License, Version 1.0. (See
  4. // accompanying file LICENSE_1_0.txt or copy at
  5. // http://www.boost.org/LICENSE_1_0.txt)
  6. #ifndef BOOST_STL_INTERFACES_DETAIL_PIPEABLE_VIEW_HPP
  7. #define BOOST_STL_INTERFACES_DETAIL_PIPEABLE_VIEW_HPP
  8. #include <boost/stl_interfaces/config.hpp>
  9. #include <type_traits>
  10. namespace boost { namespace stl_interfaces { namespace detail {
  11. template<typename T>
  12. using remove_cvref_t = std::remove_cv_t<std::remove_reference_t<T>>;
  13. struct pipeable_base;
  14. #if BOOST_STL_INTERFACES_USE_CONCEPTS
  15. template<typename T>
  16. concept pipeable_ = std::derived_from<T, pipeable_base> &&
  17. std::is_object_v<T> && std::copy_constructible<T>;
  18. #else
  19. template<typename T>
  20. constexpr bool pipeable_ = std::is_base_of<pipeable_base, T>::value &&
  21. std::is_object<T>::value && std::is_copy_constructible<T>::value;
  22. #endif
  23. #if BOOST_STL_INTERFACES_USE_CONCEPTS
  24. template<pipeable_ T, pipeable_ U>
  25. #else
  26. template<
  27. typename T,
  28. typename U,
  29. typename Enable = std::enable_if_t<pipeable_<T> && pipeable_<U>>>
  30. #endif
  31. struct view_pipeline;
  32. struct pipeable_base
  33. {
  34. #if BOOST_STL_INTERFACES_USE_CONCEPTS
  35. template<pipeable_ T, pipeable_ U>
  36. requires std::constructible_from<std::remove_cvref_t<T>, T> &&
  37. std::constructible_from<std::remove_cvref_t<U>, U>
  38. #else
  39. template<
  40. typename T,
  41. typename U,
  42. typename Enable = std::enable_if_t<
  43. pipeable_<T> && pipeable_<U> &&
  44. std::is_constructible<remove_cvref_t<T>, T>::value &&
  45. std::is_constructible<remove_cvref_t<U>, U>::value>>
  46. #endif
  47. friend constexpr auto operator|(T && t, U && u)
  48. {
  49. return view_pipeline<T, U>{(T &&) t, (U &&) u};
  50. }
  51. };
  52. template<typename Derived>
  53. struct pipeable : pipeable_base
  54. {
  55. template<typename R>
  56. friend constexpr auto operator|(R && r, Derived & d)
  57. -> decltype(((Derived &&) d)((R &&) r))
  58. {
  59. return ((Derived &&) d)((R &&) r);
  60. }
  61. template<typename R>
  62. friend constexpr auto operator|(R && r, Derived const & d)
  63. -> decltype(((Derived &&) d)((R &&) r))
  64. {
  65. return ((Derived &&) d)((R &&) r);
  66. }
  67. template<typename R>
  68. friend constexpr auto operator|(R && r, Derived && d)
  69. -> decltype(((Derived &&) d)((R &&) r))
  70. {
  71. return ((Derived &&) d)((R &&) r);
  72. }
  73. };
  74. #if BOOST_STL_INTERFACES_USE_CONCEPTS
  75. template<pipeable_ T, pipeable_ U>
  76. #else
  77. template<typename T, typename U, typename>
  78. #endif
  79. struct view_pipeline : pipeable<view_pipeline<T, U>>
  80. {
  81. view_pipeline() = default;
  82. constexpr view_pipeline(T && t, U && u) :
  83. left_(std::move(t)), right_(std::move(u))
  84. {}
  85. #if BOOST_STL_INTERFACES_USE_CONCEPTS
  86. template<std::ranges::viewable_range R>
  87. requires std::invocable<T &, R> &&
  88. std::invocable<U &, std::invoke_result_t<T &, R>>
  89. constexpr decltype(auto) operator()(R && r) &
  90. #else
  91. template<typename R>
  92. constexpr auto
  93. operator()(R && r) & -> decltype(this->right_(this->left_((R &&) r)))
  94. #endif
  95. {
  96. return right_(left_((R &&) r));
  97. }
  98. #if BOOST_STL_INTERFACES_USE_CONCEPTS
  99. template<std::ranges::viewable_range R>
  100. requires std::invocable<T const &, R> &&
  101. std::invocable<U const &, std::invoke_result_t<T const &, R>>
  102. constexpr decltype(auto) operator()(R && r) const &
  103. #else
  104. template<typename R>
  105. constexpr auto operator()(
  106. R && r) const & -> decltype(this->right_(this->left_((R &&) r)))
  107. #endif
  108. {
  109. return right_(left_((R &&) r));
  110. }
  111. #if BOOST_STL_INTERFACES_USE_CONCEPTS
  112. template<std::ranges::viewable_range R>
  113. requires std::invocable<T, R> &&
  114. std::invocable<U, std::invoke_result_t<T, R>>
  115. constexpr decltype(auto) operator()(R && r) &&
  116. #else
  117. template<typename R>
  118. constexpr auto operator()(R && r) && -> decltype(std::move(
  119. this->right_)(std::move(this->left_)((R &&) r)))
  120. #endif
  121. {
  122. return std::move(right_)(std::move(left_)((R &&) r));
  123. }
  124. T left_;
  125. U right_;
  126. };
  127. }}}
  128. #endif