Back to home page

EIC code displayed by LXR

 
 

    


Warning, file /include/boost/hana/functional/infix.hpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*!
0002 @file
0003 Defines `boost::hana::infix`.
0004 
0005 Copyright Louis Dionne 2013-2022
0006 Distributed under the Boost Software License, Version 1.0.
0007 (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
0008  */
0009 
0010 #ifndef BOOST_HANA_FUNCTIONAL_INFIX_HPP
0011 #define BOOST_HANA_FUNCTIONAL_INFIX_HPP
0012 
0013 #include <boost/hana/config.hpp>
0014 #include <boost/hana/detail/decay.hpp>
0015 #include <boost/hana/functional/partial.hpp>
0016 #include <boost/hana/functional/reverse_partial.hpp>
0017 
0018 #include <type_traits>
0019 #include <utility>
0020 
0021 
0022 namespace boost { namespace hana {
0023     //! @ingroup group-functional
0024     //! Return an equivalent function that can also be applied in infix
0025     //! notation.
0026     //!
0027     //! Specifically, `infix(f)` is an object such that:
0028     //! @code
0029     //!     infix(f)(x1, ..., xn) == f(x1, ..., xn)
0030     //!     x ^infix(f)^ y == f(x, y)
0031     //! @endcode
0032     //!
0033     //! Hence, the returned function can still be applied using the usual
0034     //! function call syntax, but it also gains the ability to be applied in
0035     //! infix notation. The infix syntax allows a great deal of expressiveness,
0036     //! especially when used in combination with some higher order algorithms.
0037     //! Since `operator^` is left-associative, `x ^infix(f)^ y` is actually
0038     //! parsed as `(x ^infix(f))^ y`. However, for flexibility, the order in
0039     //! which both arguments are applied in infix notation does not matter.
0040     //! Hence, it is always the case that
0041     //! @code
0042     //!     (x ^ infix(f)) ^ y == x ^ (infix(f) ^ y)
0043     //! @endcode
0044     //!
0045     //! However, note that applying more than one argument in infix
0046     //! notation to the same side of the operator will result in a
0047     //! compile-time assertion:
0048     //! @code
0049     //!     (infix(f) ^ x) ^ y; // compile-time assertion
0050     //!     y ^ (x ^ infix(f)); // compile-time assertion
0051     //! @endcode
0052     //!
0053     //! Additionally, a function created with `infix` may be partially applied
0054     //! in infix notation. Specifically,
0055     //! @code
0056     //!     (x ^ infix(f))(y1, ..., yn) == f(x, y1, ..., yn)
0057     //!     (infix(f) ^ y)(x1, ..., xn) == f(x1, ..., xn, y)
0058     //! @endcode
0059     //!
0060     //! @internal
0061     //! ### Rationales
0062     //! 1. The `^` operator was chosen because it is left-associative and
0063     //!    has a low enough priority so that most expressions will render
0064     //!    the expected behavior.
0065     //! 2. The operator can't be customimzed because that would require more
0066     //!    sophistication in the implementation; I want to keep it as simple
0067     //!    as possible. There is also an advantage in having a uniform syntax
0068     //!    for infix application.
0069     //! @endinternal
0070     //!
0071     //! @param f
0072     //! The function which gains the ability to be applied in infix notation.
0073     //! The function must be at least binary; a compile-time error will be
0074     //! triggered otherwise.
0075     //!
0076     //! ### Example
0077     //! @include example/functional/infix.cpp
0078 #ifdef BOOST_HANA_DOXYGEN_INVOKED
0079     constexpr auto infix = [](auto f) {
0080         return unspecified;
0081     };
0082 #else
0083     namespace infix_detail {
0084         // This needs to be in the same namespace as `operator^` so it can be
0085         // found by ADL.
0086         template <bool left, bool right, typename F>
0087         struct infix_t {
0088             F f;
0089 
0090             template <typename ...X>
0091             constexpr decltype(auto) operator()(X&& ...x) const&
0092             { return f(static_cast<X&&>(x)...); }
0093 
0094             template <typename ...X>
0095             constexpr decltype(auto) operator()(X&& ...x) &
0096             { return f(static_cast<X&&>(x)...); }
0097 
0098             template <typename ...X>
0099             constexpr decltype(auto) operator()(X&& ...x) &&
0100             { return std::move(f)(static_cast<X&&>(x)...); }
0101         };
0102 
0103         template <bool left, bool right>
0104         struct make_infix {
0105             template <typename F>
0106             constexpr infix_t<left, right, typename detail::decay<F>::type>
0107             operator()(F&& f) const { return {static_cast<F&&>(f)}; }
0108         };
0109 
0110         template <bool left, bool right>
0111         struct Infix;
0112         struct Object;
0113 
0114         template <typename T>
0115         struct dispatch { using type = Object; };
0116 
0117         template <bool left, bool right, typename F>
0118         struct dispatch<infix_t<left, right, F>> {
0119             using type = Infix<left, right>;
0120         };
0121 
0122         template <typename, typename>
0123         struct bind_infix;
0124 
0125         // infix(f) ^ y
0126         template <>
0127         struct bind_infix<Infix<false, false>, Object> {
0128             template <typename F, typename Y>
0129             static constexpr decltype(auto) apply(F&& f, Y&& y) {
0130                 return make_infix<false, true>{}(
0131                     hana::reverse_partial(
0132                         static_cast<F&&>(f), static_cast<Y&&>(y)
0133                     )
0134                 );
0135             }
0136         };
0137 
0138         // (x^infix(f)) ^ y
0139         template <>
0140         struct bind_infix<Infix<true, false>, Object> {
0141             template <typename F, typename Y>
0142             static constexpr decltype(auto) apply(F&& f, Y&& y) {
0143                 return static_cast<F&&>(f)(static_cast<Y&&>(y));
0144             }
0145         };
0146 
0147         // x ^ infix(f)
0148         template <>
0149         struct bind_infix<Object, Infix<false, false>> {
0150             template <typename X, typename F>
0151             static constexpr decltype(auto) apply(X&& x, F&& f) {
0152                 return make_infix<true, false>{}(
0153                     hana::partial(static_cast<F&&>(f), static_cast<X&&>(x))
0154                 );
0155             }
0156         };
0157 
0158         // x ^ (infix(f)^y)
0159         template <>
0160         struct bind_infix<Object, Infix<false, true>> {
0161             template <typename X, typename F>
0162             static constexpr decltype(auto) apply(X&& x, F&& f) {
0163                 return static_cast<F&&>(f)(static_cast<X&&>(x));
0164             }
0165         };
0166 
0167         template <typename T>
0168         using strip = typename std::remove_cv<
0169             typename std::remove_reference<T>::type
0170         >::type;
0171 
0172         template <typename X, typename Y>
0173         constexpr decltype(auto) operator^(X&& x, Y&& y) {
0174             return bind_infix<
0175                 typename dispatch<strip<X>>::type,
0176                 typename dispatch<strip<Y>>::type
0177             >::apply(static_cast<X&&>(x), static_cast<Y&&>(y));
0178         }
0179     } // end namespace infix_detail
0180 
0181     BOOST_HANA_INLINE_VARIABLE constexpr infix_detail::make_infix<false, false> infix{};
0182 #endif
0183 }} // end namespace boost::hana
0184 
0185 #endif // !BOOST_HANA_FUNCTIONAL_INFIX_HPP