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