1/*============================================================================= 2 Copyright (c) 2014 Paul Fultz II 3 proj.h 4 Distributed under the Boost Software License, Version 1.0. (See accompanying 5 file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6==============================================================================*/ 7 8#ifndef BOOST_HOF_GUARD_FUNCTION_ON_H 9#define BOOST_HOF_GUARD_FUNCTION_ON_H 10 11/// proj 12/// ==== 13/// 14/// Description 15/// ----------- 16/// 17/// The `proj` function adaptor applies a projection onto the parameters of 18/// another function. This is useful, for example, to define a function for 19/// sorting such that the ordering is based off of the value of one of its 20/// member fields. 21/// 22/// Also, if just a projection is given, then the projection will be called 23/// for each of its arguments. 24/// 25/// Note: All projections are always evaluated in order from left-to-right. 26/// 27/// Synopsis 28/// -------- 29/// 30/// template<class Projection, class F> 31/// constexpr proj_adaptor<Projection, F> proj(Projection p, F f); 32/// 33/// template<class Projection> 34/// constexpr proj_adaptor<Projection> proj(Projection p); 35/// 36/// Semantics 37/// --------- 38/// 39/// assert(proj(p, f)(xs...) == f(p(xs)...)); 40/// assert(proj(p)(xs...) == p(xs)...); 41/// 42/// Requirements 43/// ------------ 44/// 45/// Projection must be: 46/// 47/// * [UnaryInvocable](UnaryInvocable) 48/// * MoveConstructible 49/// 50/// F must be: 51/// 52/// * [ConstInvocable](ConstInvocable) 53/// * MoveConstructible 54/// 55/// Example 56/// ------- 57/// 58/// #include <boost/hof.hpp> 59/// #include <cassert> 60/// using namespace boost::hof; 61/// 62/// struct foo 63/// { 64/// foo(int x_) : x(x_) 65/// {} 66/// int x; 67/// }; 68/// 69/// int main() { 70/// assert(boost::hof::proj(&foo::x, _ + _)(foo(1), foo(2)) == 3); 71/// } 72/// 73/// References 74/// ---------- 75/// 76/// * [Projections](Projections) 77/// * [Variadic print](<Variadic print>) 78/// 79 80 81 82#include <utility> 83#include <boost/hof/always.hpp> 84#include <boost/hof/detail/callable_base.hpp> 85#include <boost/hof/detail/result_of.hpp> 86#include <boost/hof/detail/move.hpp> 87#include <boost/hof/detail/make.hpp> 88#include <boost/hof/detail/static_const_var.hpp> 89#include <boost/hof/detail/compressed_pair.hpp> 90#include <boost/hof/detail/result_type.hpp> 91#include <boost/hof/apply_eval.hpp> 92 93namespace boost { namespace hof { 94 95namespace detail { 96 97template<class T, class Projection> 98struct project_eval 99{ 100 T&& x; 101 const Projection& p; 102 103 template<class X, class P> 104 constexpr project_eval(X&& xp, const P& pp) : x(BOOST_HOF_FORWARD(X)(xp)), p(pp) 105 {} 106 107 constexpr auto operator()() const BOOST_HOF_RETURNS 108 (p(BOOST_HOF_FORWARD(T)(x))); 109}; 110 111template<class T, class Projection> 112constexpr project_eval<T, Projection> make_project_eval(T&& x, const Projection& p) 113{ 114 return project_eval<T, Projection>(BOOST_HOF_FORWARD(T)(x), p); 115} 116 117template<class T, class Projection> 118struct project_void_eval 119{ 120 T&& x; 121 const Projection& p; 122 123 template<class X, class P> 124 constexpr project_void_eval(X&& xp, const P& pp) : x(BOOST_HOF_FORWARD(X)(xp)), p(pp) 125 {} 126 127 struct void_ {}; 128 129 constexpr void_ operator()() const 130 { 131 return p(BOOST_HOF_FORWARD(T)(x)), void_(); 132 } 133}; 134 135template<class T, class Projection> 136constexpr project_void_eval<T, Projection> make_project_void_eval(T&& x, const Projection& p) 137{ 138 return project_void_eval<T, Projection>(BOOST_HOF_FORWARD(T)(x), p); 139} 140 141template<class Projection, class F, class... Ts, 142 class R=decltype( 143 std::declval<const F&>()(std::declval<const Projection&>()(std::declval<Ts>())...) 144 )> 145constexpr R by_eval(const Projection& p, const F& f, Ts&&... xs) 146{ 147 return boost::hof::apply_eval(f, make_project_eval(BOOST_HOF_FORWARD(Ts)(xs), p)...); 148} 149 150#if BOOST_HOF_NO_ORDERED_BRACE_INIT 151#define BOOST_HOF_BY_VOID_RETURN BOOST_HOF_ALWAYS_VOID_RETURN 152#else 153#if BOOST_HOF_NO_CONSTEXPR_VOID 154#define BOOST_HOF_BY_VOID_RETURN boost::hof::detail::swallow 155#else 156#define BOOST_HOF_BY_VOID_RETURN void 157#endif 158#endif 159 160template<class Projection, class... Ts> 161constexpr BOOST_HOF_ALWAYS_VOID_RETURN by_void_eval(const Projection& p, Ts&&... xs) 162{ 163 return boost::hof::apply_eval(boost::hof::always(), boost::hof::detail::make_project_void_eval(BOOST_HOF_FORWARD(Ts)(xs), p)...); 164} 165 166struct swallow 167{ 168 template<class... Ts> 169 constexpr swallow(Ts&&...) 170 {} 171}; 172 173} 174 175template<class Projection, class F=void> 176struct proj_adaptor; 177 178template<class Projection, class F> 179struct proj_adaptor : detail::compressed_pair<detail::callable_base<Projection>, detail::callable_base<F>>, detail::function_result_type<F> 180{ 181 typedef proj_adaptor fit_rewritable_tag; 182 typedef detail::compressed_pair<detail::callable_base<Projection>, detail::callable_base<F>> base; 183 template<class... Ts> 184 constexpr const detail::callable_base<F>& base_function(Ts&&... xs) const 185 { 186 return this->second(xs...);; 187 } 188 189 template<class... Ts> 190 constexpr const detail::callable_base<Projection>& base_projection(Ts&&... xs) const 191 { 192 return this->first(xs...); 193 } 194 195 struct by_failure 196 { 197 template<class Failure> 198 struct apply 199 { 200 template<class... Ts> 201 struct of 202 : Failure::template of<decltype(std::declval<detail::callable_base<Projection>>()(std::declval<Ts>()))...> 203 {}; 204 }; 205 }; 206 207 struct failure 208 : failure_map<by_failure, detail::callable_base<F>> 209 {}; 210 211 BOOST_HOF_INHERIT_CONSTRUCTOR(proj_adaptor, base) 212 213 BOOST_HOF_RETURNS_CLASS(proj_adaptor); 214 215 template<class... Ts> 216 constexpr BOOST_HOF_SFINAE_RESULT(const detail::callable_base<F>&, result_of<const detail::callable_base<Projection>&, id_<Ts>>...) 217 operator()(Ts&&... xs) const BOOST_HOF_SFINAE_RETURNS 218 ( 219 boost::hof::detail::by_eval( 220 BOOST_HOF_MANGLE_CAST(const detail::callable_base<Projection>&)(BOOST_HOF_CONST_THIS->base_projection(xs...)), 221 BOOST_HOF_MANGLE_CAST(const detail::callable_base<F>&)(BOOST_HOF_CONST_THIS->base_function(xs...)), 222 BOOST_HOF_FORWARD(Ts)(xs)... 223 ) 224 ); 225}; 226 227template<class Projection> 228struct proj_adaptor<Projection, void> : detail::callable_base<Projection> 229{ 230 typedef proj_adaptor fit_rewritable1_tag; 231 template<class... Ts> 232 constexpr const detail::callable_base<Projection>& base_projection(Ts&&... xs) const 233 { 234 return boost::hof::always_ref(*this)(xs...); 235 } 236 237 BOOST_HOF_INHERIT_DEFAULT(proj_adaptor, detail::callable_base<Projection>) 238 239 template<class P, BOOST_HOF_ENABLE_IF_CONVERTIBLE(P, detail::callable_base<Projection>)> 240 constexpr proj_adaptor(P&& p) 241 : detail::callable_base<Projection>(BOOST_HOF_FORWARD(P)(p)) 242 {} 243 244 BOOST_HOF_RETURNS_CLASS(proj_adaptor); 245 246 template<class... Ts, class=detail::holder<decltype(std::declval<Projection>()(std::declval<Ts>()))...>> 247 constexpr BOOST_HOF_BY_VOID_RETURN operator()(Ts&&... xs) const 248 { 249#if BOOST_HOF_NO_ORDERED_BRACE_INIT 250 return boost::hof::detail::by_void_eval(this->base_projection(xs...), BOOST_HOF_FORWARD(Ts)(xs)...); 251#else 252#if BOOST_HOF_NO_CONSTEXPR_VOID 253 return 254#endif 255 boost::hof::detail::swallow{ 256 (this->base_projection(xs...)(BOOST_HOF_FORWARD(Ts)(xs)), 0)... 257 }; 258#endif 259 } 260}; 261 262BOOST_HOF_DECLARE_STATIC_VAR(proj, detail::make<proj_adaptor>); 263 264}} // namespace boost::hof 265#endif 266