pipeable.hpp 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. /// \file
  2. // Range v3 library
  3. //
  4. // Copyright Eric Niebler 2013-present
  5. //
  6. // Use, modification and distribution is subject to the
  7. // Boost Software License, Version 1.0. (See accompanying
  8. // file LICENSE_1_0.txt or copy at
  9. // http://www.boost.org/LICENSE_1_0.txt)
  10. //
  11. // Project home: https://github.com/ericniebler/range-v3
  12. //
  13. #ifndef RANGES_V3_FUNCTIONAL_PIPEABLE_HPP
  14. #define RANGES_V3_FUNCTIONAL_PIPEABLE_HPP
  15. #include <concepts/concepts.hpp>
  16. #include <range/v3/range_fwd.hpp>
  17. #include <range/v3/functional/compose.hpp>
  18. #include <range/v3/functional/concepts.hpp>
  19. #include <range/v3/utility/static_const.hpp>
  20. #include <range/v3/detail/prologue.hpp>
  21. namespace ranges
  22. {
  23. /// \addtogroup group-functional
  24. /// @{
  25. struct pipeable_base;
  26. template<typename T>
  27. RANGES_INLINE_VAR constexpr bool is_pipeable_v = META_IS_BASE_OF(pipeable_base, T);
  28. template<typename T>
  29. RANGES_INLINE_VAR constexpr bool is_pipeable_v<T &> = META_IS_BASE_OF(pipeable_base,
  30. T);
  31. template<typename T>
  32. RANGES_INLINE_VAR constexpr bool is_pipeable_v<T &&> = META_IS_BASE_OF(pipeable_base,
  33. T);
  34. template<typename T>
  35. using is_pipeable = meta::bool_<is_pipeable_v<T>>;
  36. struct make_pipeable_fn
  37. {
  38. template<typename Fun, typename PipeableBase = pipeable_base>
  39. constexpr auto operator()(Fun fun) const
  40. {
  41. struct local
  42. : Fun
  43. , PipeableBase
  44. {
  45. constexpr explicit local(Fun && f)
  46. : Fun(static_cast<Fun &&>(f))
  47. {}
  48. };
  49. return local{static_cast<Fun &&>(fun)};
  50. }
  51. };
  52. /// \ingroup group-functional
  53. /// \sa `make_pipeable_fn`
  54. RANGES_INLINE_VARIABLE(make_pipeable_fn, make_pipeable)
  55. struct pipeable_access
  56. {
  57. template<typename Pipeable>
  58. struct impl : Pipeable
  59. {
  60. using Pipeable::pipe;
  61. };
  62. };
  63. struct pipeable_base
  64. {
  65. private:
  66. friend pipeable_access;
  67. // Evaluate the pipe with an argument
  68. template(typename Arg, typename Pipe)(
  69. requires (!is_pipeable_v<Arg>) AND is_pipeable_v<Pipe> AND
  70. invocable<Pipe, Arg>) // clang-format off
  71. friend constexpr auto operator|(Arg &&arg, Pipe pipe) // clang-format off
  72. {
  73. return static_cast<Pipe &&>(pipe)(static_cast<Arg &&>(arg));
  74. }
  75. // Compose two pipes
  76. template(typename Pipe0, typename Pipe1)(
  77. requires is_pipeable_v<Pipe0> AND is_pipeable_v<Pipe1>) // clang-format off
  78. friend constexpr auto operator|(Pipe0 pipe0, Pipe1 pipe1) // clang-format on
  79. {
  80. return make_pipeable(compose(detail::move(pipe1), detail::move(pipe0)));
  81. }
  82. template<typename Arg, typename Pipe>
  83. friend auto operator|=(Arg & arg, Pipe pipe) //
  84. -> CPP_broken_friend_ret(Arg &)(
  85. requires (is_pipeable_v<Pipe>) &&
  86. (!is_pipeable_v<Arg>) && invocable<Pipe, Arg &>)
  87. {
  88. static_cast<Pipe &&>(pipe)(arg);
  89. return arg;
  90. }
  91. // Default Pipe behavior just passes the argument to the pipe's function call
  92. // operator
  93. // clang-format off
  94. template<typename Arg, typename Pipe>
  95. static constexpr auto CPP_auto_fun(pipe)(Arg && arg, Pipe p)
  96. (
  97. return static_cast<Pipe &&>(p)(static_cast<Arg &&>(arg))
  98. )
  99. // clang-format on
  100. };
  101. template<typename>
  102. using pipeable RANGES_DEPRECATED("Please use pipeable_base instead") = pipeable_base;
  103. /// \endcond
  104. /// @}
  105. } // namespace ranges
  106. #include <range/v3/detail/epilogue.hpp>
  107. #endif