| 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 | |
| 9 | #include <boost/stl_interfaces/config.hpp> |
| 10 | |
| 11 | #include <type_traits> |
| 12 | |
| 13 | |
| 14 | namespace boost { namespace stl_interfaces { namespace detail { |
| 15 | |
| 16 | template<typename T> |
| 17 | using remove_cvref_t = std::remove_cv_t<std::remove_reference_t<T>>; |
| 18 | |
| 19 | struct pipeable_base; |
| 20 | |
| 21 | #if BOOST_STL_INTERFACES_USE_CONCEPTS |
| 22 | template<typename T> |
| 23 | concept pipeable_ = std::derived_from<T, pipeable_base> && |
| 24 | std::is_object_v<T> && std::copy_constructible<T>; |
| 25 | #else |
| 26 | template<typename T> |
| 27 | constexpr bool pipeable_ = std::is_base_of<pipeable_base, T>::value && |
| 28 | std::is_object<T>::value && std::is_copy_constructible<T>::value; |
| 29 | #endif |
| 30 | |
| 31 | #if BOOST_STL_INTERFACES_USE_CONCEPTS |
| 32 | template<pipeable_ T, pipeable_ U> |
| 33 | #else |
| 34 | template< |
| 35 | typename T, |
| 36 | typename U, |
| 37 | typename Enable = std::enable_if_t<pipeable_<T> && pipeable_<U>>> |
| 38 | #endif |
| 39 | struct view_pipeline; |
| 40 | |
| 41 | struct pipeable_base |
| 42 | { |
| 43 | #if BOOST_STL_INTERFACES_USE_CONCEPTS |
| 44 | template<pipeable_ T, pipeable_ U> |
| 45 | requires std::constructible_from<std::remove_cvref_t<T>, T> && |
| 46 | std::constructible_from<std::remove_cvref_t<U>, U> |
| 47 | #else |
| 48 | template< |
| 49 | typename T, |
| 50 | typename U, |
| 51 | typename Enable = std::enable_if_t< |
| 52 | pipeable_<T> && pipeable_<U> && |
| 53 | std::is_constructible<remove_cvref_t<T>, T>::value && |
| 54 | std::is_constructible<remove_cvref_t<U>, U>::value>> |
| 55 | #endif |
| 56 | friend constexpr auto operator|(T && t, U && u) |
| 57 | { |
| 58 | return view_pipeline<T, U>{(T &&) t, (U &&) u}; |
| 59 | } |
| 60 | }; |
| 61 | |
| 62 | template<typename Derived> |
| 63 | struct pipeable : pipeable_base |
| 64 | { |
| 65 | template<typename R> |
| 66 | friend constexpr auto operator|(R && r, Derived & d) |
| 67 | -> decltype(((Derived &&) d)((R &&) r)) |
| 68 | { |
| 69 | return ((Derived &&) d)((R &&) r); |
| 70 | } |
| 71 | |
| 72 | template<typename R> |
| 73 | friend constexpr auto operator|(R && r, Derived const & d) |
| 74 | -> decltype(((Derived &&) d)((R &&) r)) |
| 75 | { |
| 76 | return ((Derived &&) d)((R &&) r); |
| 77 | } |
| 78 | |
| 79 | template<typename R> |
| 80 | friend constexpr auto operator|(R && r, Derived && d) |
| 81 | -> decltype(((Derived &&) d)((R &&) r)) |
| 82 | { |
| 83 | return ((Derived &&) d)((R &&) r); |
| 84 | } |
| 85 | }; |
| 86 | |
| 87 | #if BOOST_STL_INTERFACES_USE_CONCEPTS |
| 88 | template<pipeable_ T, pipeable_ U> |
| 89 | #else |
| 90 | template<typename T, typename U, typename> |
| 91 | #endif |
| 92 | struct view_pipeline : pipeable<view_pipeline<T, U>> |
| 93 | { |
| 94 | view_pipeline() = default; |
| 95 | |
| 96 | constexpr view_pipeline(T && t, U && u) : |
| 97 | left_(std::move(t)), right_(std::move(u)) |
| 98 | {} |
| 99 | |
| 100 | #if BOOST_STL_INTERFACES_USE_CONCEPTS |
| 101 | template<std::ranges::viewable_range R> |
| 102 | requires std::invocable<T &, R> && |
| 103 | std::invocable<U &, std::invoke_result_t<T &, R>> |
| 104 | constexpr decltype(auto) operator()(R && r) & |
| 105 | #else |
| 106 | template<typename R> |
| 107 | constexpr auto |
| 108 | operator()(R && r) & -> decltype(this->right_(this->left_((R &&) r))) |
| 109 | #endif |
| 110 | { |
| 111 | return right_(left_((R &&) r)); |
| 112 | } |
| 113 | |
| 114 | #if BOOST_STL_INTERFACES_USE_CONCEPTS |
| 115 | template<std::ranges::viewable_range R> |
| 116 | requires std::invocable<T const &, R> && |
| 117 | std::invocable<U const &, std::invoke_result_t<T const &, R>> |
| 118 | constexpr decltype(auto) operator()(R && r) const & |
| 119 | #else |
| 120 | template<typename R> |
| 121 | constexpr auto operator()( |
| 122 | R && r) const & -> decltype(this->right_(this->left_((R &&) r))) |
| 123 | #endif |
| 124 | { |
| 125 | return right_(left_((R &&) r)); |
| 126 | } |
| 127 | |
| 128 | #if BOOST_STL_INTERFACES_USE_CONCEPTS |
| 129 | template<std::ranges::viewable_range R> |
| 130 | requires std::invocable<T, R> && |
| 131 | std::invocable<U, std::invoke_result_t<T, R>> |
| 132 | constexpr decltype(auto) operator()(R && r) && |
| 133 | #else |
| 134 | template<typename R> |
| 135 | constexpr auto operator()(R && r) && -> decltype(std::move( |
| 136 | this->right_)(std::move(this->left_)((R &&) r))) |
| 137 | #endif |
| 138 | { |
| 139 | return std::move(right_)(std::move(left_)((R &&) r)); |
| 140 | } |
| 141 | |
| 142 | T left_; |
| 143 | U right_; |
| 144 | }; |
| 145 | |
| 146 | }}} |
| 147 | |
| 148 | #endif |
| 149 | |