Rocket.Chat.ReactNative/ios/Pods/boost-for-react-native/boost/hana/functional/infix.hpp

186 lines
6.5 KiB
C++

/*!
@file
Defines `boost::hana::infix`.
@copyright Louis Dionne 2013-2016
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
*/
#ifndef BOOST_HANA_FUNCTIONAL_INFIX_HPP
#define BOOST_HANA_FUNCTIONAL_INFIX_HPP
#include <boost/hana/config.hpp>
#include <boost/hana/detail/decay.hpp>
#include <boost/hana/functional/partial.hpp>
#include <boost/hana/functional/reverse_partial.hpp>
#include <type_traits>
#include <utility>
BOOST_HANA_NAMESPACE_BEGIN
//! @ingroup group-functional
//! Return an equivalent function that can also be applied in infix
//! notation.
//!
//! Specifically, `infix(f)` is an object such that:
//! @code
//! infix(f)(x1, ..., xn) == f(x1, ..., xn)
//! x ^infix(f)^ y == f(x, y)
//! @endcode
//!
//! Hence, the returned function can still be applied using the usual
//! function call syntax, but it also gains the ability to be applied in
//! infix notation. The infix syntax allows a great deal of expressiveness,
//! especially when used in combination with some higher order algorithms.
//! Since `operator^` is left-associative, `x ^infix(f)^ y` is actually
//! parsed as `(x ^infix(f))^ y`. However, for flexibility, the order in
//! which both arguments are applied in infix notation does not matter.
//! Hence, it is always the case that
//! @code
//! (x ^ infix(f)) ^ y == x ^ (infix(f) ^ y)
//! @endcode
//!
//! However, note that applying more than one argument in infix
//! notation to the same side of the operator will result in a
//! compile-time assertion:
//! @code
//! (infix(f) ^ x) ^ y; // compile-time assertion
//! y ^ (x ^ infix(f)); // compile-time assertion
//! @endcode
//!
//! Additionally, a function created with `infix` may be partially applied
//! in infix notation. Specifically,
//! @code
//! (x ^ infix(f))(y1, ..., yn) == f(x, y1, ..., yn)
//! (infix(f) ^ y)(x1, ..., xn) == f(x1, ..., xn, y)
//! @endcode
//!
//! @internal
//! ### Rationales
//! 1. The `^` operator was chosen because it is left-associative and
//! has a low enough priority so that most expressions will render
//! the expected behavior.
//! 2. The operator can't be customimzed because that would require more
//! sophistication in the implementation; I want to keep it as simple
//! as possible. There is also an advantage in having a uniform syntax
//! for infix application.
//! @endinternal
//!
//! @param f
//! The function which gains the ability to be applied in infix notation.
//! The function must be at least binary; a compile-time error will be
//! triggered otherwise.
//!
//! ### Example
//! @include example/functional/infix.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
constexpr auto infix = [](auto f) {
return unspecified;
};
#else
namespace infix_detail {
// This needs to be in the same namespace as `operator^` so it can be
// found by ADL.
template <bool left, bool right, typename F>
struct infix_t {
F f;
template <typename ...X>
constexpr decltype(auto) operator()(X&& ...x) const&
{ return f(static_cast<X&&>(x)...); }
template <typename ...X>
constexpr decltype(auto) operator()(X&& ...x) &
{ return f(static_cast<X&&>(x)...); }
template <typename ...X>
constexpr decltype(auto) operator()(X&& ...x) &&
{ return std::move(f)(static_cast<X&&>(x)...); }
};
template <bool left, bool right>
struct make_infix {
template <typename F>
constexpr infix_t<left, right, typename detail::decay<F>::type>
operator()(F&& f) const { return {static_cast<F&&>(f)}; }
};
template <bool left, bool right>
struct Infix;
struct Object;
template <typename T>
struct dispatch { using type = Object; };
template <bool left, bool right, typename F>
struct dispatch<infix_t<left, right, F>> {
using type = Infix<left, right>;
};
template <typename, typename>
struct bind_infix;
// infix(f) ^ y
template <>
struct bind_infix<Infix<false, false>, Object> {
template <typename F, typename Y>
static constexpr decltype(auto) apply(F&& f, Y&& y) {
return make_infix<false, true>{}(
hana::reverse_partial(
static_cast<F&&>(f), static_cast<Y&&>(y)
)
);
}
};
// (x^infix(f)) ^ y
template <>
struct bind_infix<Infix<true, false>, Object> {
template <typename F, typename Y>
static constexpr decltype(auto) apply(F&& f, Y&& y) {
return static_cast<F&&>(f)(static_cast<Y&&>(y));
}
};
// x ^ infix(f)
template <>
struct bind_infix<Object, Infix<false, false>> {
template <typename X, typename F>
static constexpr decltype(auto) apply(X&& x, F&& f) {
return make_infix<true, false>{}(
hana::partial(static_cast<F&&>(f), static_cast<X&&>(x))
);
}
};
// x ^ (infix(f)^y)
template <>
struct bind_infix<Object, Infix<false, true>> {
template <typename X, typename F>
static constexpr decltype(auto) apply(X&& x, F&& f) {
return static_cast<F&&>(f)(static_cast<X&&>(x));
}
};
template <typename T>
using strip = typename std::remove_cv<
typename std::remove_reference<T>::type
>::type;
template <typename X, typename Y>
constexpr decltype(auto) operator^(X&& x, Y&& y) {
return bind_infix<
typename dispatch<strip<X>>::type,
typename dispatch<strip<Y>>::type
>::apply(static_cast<X&&>(x), static_cast<Y&&>(y));
}
} // end namespace infix_detail
constexpr infix_detail::make_infix<false, false> infix{};
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FUNCTIONAL_INFIX_HPP