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 14 #ifndef RANGES_V3_CONTAINER_ACTION_HPP 15 #define RANGES_V3_CONTAINER_ACTION_HPP 16 17 #include <type_traits> 18 19 #include <meta/meta.hpp> 20 21 #include <range/v3/range_fwd.hpp> 22 23 #include <range/v3/action/concepts.hpp> 24 #include <range/v3/functional/compose.hpp> 25 #include <range/v3/functional/concepts.hpp> 26 #include <range/v3/functional/invoke.hpp> 27 #include <range/v3/functional/reference_wrapper.hpp> 28 #include <range/v3/functional/pipeable.hpp> 29 #include <range/v3/range/concepts.hpp> 30 #include <range/v3/utility/move.hpp> 31 #include <range/v3/utility/static_const.hpp> 32 33 #include <range/v3/detail/prologue.hpp> 34 35 namespace ranges 36 { 37 /// \addtogroup group-actions 38 /// @{ 39 struct make_action_closure_fn 40 { 41 template<typename Fun> operator ()ranges::make_action_closure_fn42 constexpr actions::action_closure<Fun> operator()(Fun fun) const 43 { 44 return actions::action_closure<Fun>{static_cast<Fun &&>(fun)}; 45 } 46 }; 47 48 /// \sa make_action_closure_fn 49 RANGES_INLINE_VARIABLE(make_action_closure_fn, make_action_closure) 50 51 /// \cond 52 namespace detail 53 { 54 struct action_closure_base_ 55 {}; 56 } 57 /// \endcond 58 59 template(typename ActionFn, typename Rng)( 60 concept (invocable_action_closure_)(ActionFn, Rng), 61 !derived_from<invoke_result_t<ActionFn, Rng>, detail::action_closure_base_> 62 ); 63 template<typename ActionFn, typename Rng> 64 CPP_concept invocable_action_closure = 65 invocable<ActionFn, Rng> && 66 CPP_concept_ref(ranges::invocable_action_closure_, ActionFn, Rng); 67 68 namespace actions 69 { RANGES_STRUCT_WITH_ADL_BARRIER(action_closure_base)70 struct RANGES_STRUCT_WITH_ADL_BARRIER(action_closure_base) 71 : detail::action_closure_base_ 72 { 73 // clang-format off 74 // Piping requires things are passed by value. 75 template(typename Rng, typename ActionFn)( 76 /// \pre 77 requires (!std::is_lvalue_reference<Rng>::value) AND 78 range<Rng> AND invocable_action_closure<ActionFn, Rng &>) 79 friend constexpr auto 80 operator|(Rng && rng, action_closure<ActionFn> act) 81 { 82 return aux::move(static_cast<ActionFn &&>(act)(rng)); 83 } 84 85 #ifndef RANGES_WORKAROUND_CLANG_43400 86 template<typename Rng, typename ActionFn> // ****************************** 87 friend constexpr auto // ****************************** 88 operator|(Rng &, // ********* READ THIS ********** 89 action_closure<ActionFn> const &) // ****** IF YOUR COMPILE ******* 90 -> CPP_broken_friend_ret(Rng)( // ******** BREAKS HERE ********* 91 requires range<Rng>) = delete; // ****************************** 92 // ************************************************************************** 93 // * When piping a range into an action, the range must be moved in. * 94 // ************************************************************************** 95 #endif // RANGES_WORKAROUND_CLANG_43400 96 97 template<typename ActionFn, typename Pipeable> 98 friend constexpr auto operator|(action_closure<ActionFn> act, Pipeable pipe) 99 -> CPP_broken_friend_ret(action_closure<composed<Pipeable, ActionFn>>)( 100 /// \pre 101 requires (is_pipeable_v<Pipeable>)) 102 { 103 return make_action_closure(compose(static_cast<Pipeable &&>(pipe), 104 static_cast<ActionFn &&>(act))); 105 } 106 107 template<typename Rng, typename ActionFn> 108 friend constexpr auto operator|=(Rng & rng, action_closure<ActionFn> act) // 109 -> CPP_broken_friend_ret(Rng &)( 110 /// \pre 111 requires range<Rng> && invocable<ActionFn, Rng &>) 112 { 113 static_cast<ActionFn &&>(act)(rng); 114 return rng; 115 } 116 // clang-format on 117 }; 118 119 #ifdef RANGES_WORKAROUND_CLANG_43400 120 // clang-format off 121 namespace RANGES_ADL_BARRIER_FOR(action_closure_base) 122 { 123 template(typename Rng, typename ActionFn)( // ******************************* 124 requires range<Rng>) // ******************************* 125 constexpr Rng // ********** READ THIS ********** 126 operator|(Rng &, // ******* IF YOUR COMPILE ******* 127 action_closure<ActionFn> const &) // ********* BREAKS HERE ********* 128 = delete; // ******************************* 129 // *************************************************************************** 130 // * When piping a range into an action, the range must be moved in. * 131 // *************************************************************************** 132 } // namespace RANGES_ADL_BARRIER_FOR(action_closure_base) 133 // clang-format on 134 #endif // RANGES_WORKAROUND_CLANG_43400 135 136 template<typename ActionFn> 137 struct RANGES_EMPTY_BASES action_closure 138 : action_closure_base 139 , ActionFn 140 { 141 action_closure() = default; 142 143 constexpr explicit action_closure(ActionFn fn) 144 : ActionFn(static_cast<ActionFn &&>(fn)) 145 {} 146 }; 147 148 /// \cond 149 /// DEPRECATED STUFF 150 struct action_access_ 151 { 152 template<typename Action> 153 struct impl 154 { 155 // clang-format off 156 template<typename... Ts, typename A = Action> 157 static constexpr auto CPP_auto_fun(bind)(Ts &&... ts) 158 ( 159 return A::bind(static_cast<Ts &&>(ts)...) 160 ) 161 // clang-format on 162 }; 163 }; 164 165 using action_access RANGES_DEPRECATED( 166 "action_access and actions::action<> are deprecated. Please " 167 "replace action<> with action_closure<> and discontinue use of " 168 "action_access.") = action_access_; 169 170 template<typename> 171 struct old_action_; 172 173 struct make_action_fn_ 174 { 175 template<typename Fun> 176 constexpr old_action_<Fun> operator()(Fun fun) const 177 { 178 return old_action_<Fun>{static_cast<Fun &&>(fun)}; 179 } 180 }; 181 using make_action_fn RANGES_DEPRECATED( 182 "make_action_fn is deprecated. Please use " 183 "make_action_closure instead.") = make_action_fn_; 184 185 namespace 186 { 187 RANGES_DEPRECATED( 188 "make_action and actions::action<> has been deprecated. Please switch to " 189 "make_action_closure and action::action_closure.") 190 RANGES_INLINE_VAR constexpr auto & make_action = 191 static_const<make_action_fn_>::value; 192 } // namespace 193 194 template<typename Action> 195 struct old_action_ : pipeable_base 196 { 197 private: 198 Action act_; 199 friend pipeable_access; 200 201 public: 202 old_action_() = default; 203 204 constexpr explicit old_action_(Action a) noexcept( 205 std::is_nothrow_move_constructible<Action>::value) 206 : act_(detail::move(a)) 207 {} 208 209 // Calling directly requires things are passed by reference. 210 template(typename Rng, typename... Rest)( 211 /// \pre 212 requires range<Rng> AND invocable<Action const &, Rng &, Rest...>) 213 invoke_result_t<Action const &, Rng &, Rest...> // 214 operator()(Rng & rng, Rest &&... rest) const 215 { 216 return invoke(act_, rng, static_cast<Rest &&>(rest)...); 217 } 218 219 // Currying overload. 220 // clang-format off 221 template(typename... Rest, typename A = Action)( 222 /// \pre 223 requires (sizeof...(Rest) != 0)) 224 auto CPP_auto_fun(operator())(Rest &&... rest)(const) 225 ( 226 return make_action_fn_{}( 227 action_access_::impl<A>::bind(act_, 228 static_cast<Rest &&>(rest)...)) 229 ) 230 // clang-format on 231 }; 232 233 template<typename Action> 234 using action RANGES_DEPRECATED( 235 "The actions::action<> template is deprecated. Please switch to " 236 "action_closure") = old_action_<Action>; 237 /// \endcond 238 } // namespace actions 239 240 template<typename ActionFn> 241 RANGES_INLINE_VAR constexpr bool is_pipeable_v<actions::action_closure<ActionFn>> = 242 true; 243 /// @} 244 } // namespace ranges 245 246 #include <range/v3/detail/epilogue.hpp> 247 248 #endif 249