stabilize build system: depends, installer, boost/bdb fixes, cross targets groundwork
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
/*!
|
||||
@file
|
||||
Defines `boost::hana::always`.
|
||||
|
||||
@copyright Louis Dionne 2013-2017
|
||||
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_ALWAYS_HPP
|
||||
#define BOOST_HANA_FUNCTIONAL_ALWAYS_HPP
|
||||
|
||||
#include <boost/hana/config.hpp>
|
||||
#include <boost/hana/detail/create.hpp>
|
||||
|
||||
#include <utility>
|
||||
|
||||
|
||||
BOOST_HANA_NAMESPACE_BEGIN
|
||||
//! @ingroup group-functional
|
||||
//! Return a constant function returning `x` regardless of the
|
||||
//! argument(s) it is invoked with.
|
||||
//!
|
||||
//! Specifically, `always(x)` is a function such that
|
||||
//! @code
|
||||
//! always(x)(y...) == x
|
||||
//! @endcode
|
||||
//! for any `y...`. A copy of `x` is made and it is owned by the
|
||||
//! `always(x)` function. When `always(x)` is called, it will return
|
||||
//! a reference to the `x` it owns. This reference is valid as long
|
||||
//! as `always(x)` is in scope.
|
||||
//!
|
||||
//!
|
||||
//! ### Example
|
||||
//! @include example/functional/always.cpp
|
||||
#ifdef BOOST_HANA_DOXYGEN_INVOKED
|
||||
constexpr auto always = [](auto&& x) {
|
||||
return [perfect-capture](auto const& ...y) -> decltype(auto) {
|
||||
return forwarded(x);
|
||||
};
|
||||
};
|
||||
#else
|
||||
template <typename T>
|
||||
struct _always {
|
||||
T val_;
|
||||
|
||||
template <typename ...Args>
|
||||
constexpr T const& operator()(Args const& ...) const&
|
||||
{ return val_; }
|
||||
|
||||
template <typename ...Args>
|
||||
constexpr T& operator()(Args const& ...) &
|
||||
{ return val_; }
|
||||
|
||||
template <typename ...Args>
|
||||
constexpr T operator()(Args const& ...) &&
|
||||
{ return std::move(val_); }
|
||||
};
|
||||
|
||||
constexpr detail::create<_always> always{};
|
||||
#endif
|
||||
BOOST_HANA_NAMESPACE_END
|
||||
|
||||
#endif // !BOOST_HANA_FUNCTIONAL_ALWAYS_HPP
|
||||
@@ -0,0 +1,85 @@
|
||||
/*!
|
||||
@file
|
||||
Defines `boost::hana::apply`.
|
||||
|
||||
@copyright Louis Dionne 2013-2017
|
||||
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_APPLY_HPP
|
||||
#define BOOST_HANA_FUNCTIONAL_APPLY_HPP
|
||||
|
||||
#include <boost/hana/config.hpp>
|
||||
|
||||
|
||||
BOOST_HANA_NAMESPACE_BEGIN
|
||||
//! @ingroup group-functional
|
||||
//! Invokes a Callable with the given arguments.
|
||||
//!
|
||||
//! This is equivalent to [std::invoke][1] that will be added in C++17.
|
||||
//! However, `apply` is a function object instead of a function, which
|
||||
//! makes it possible to pass it to higher-order algorithms.
|
||||
//!
|
||||
//!
|
||||
//! @param f
|
||||
//! A [Callable][2] to be invoked with the given arguments.
|
||||
//!
|
||||
//! @param x...
|
||||
//! The arguments to call `f` with. The number of `x...` must match the
|
||||
//! arity of `f`.
|
||||
//!
|
||||
//!
|
||||
//! Example
|
||||
//! -------
|
||||
//! @include example/functional/apply.cpp
|
||||
//!
|
||||
//! [1]: http://en.cppreference.com/w/cpp/utility/functional/invoke
|
||||
//! [2]: http://en.cppreference.com/w/cpp/concept/Callable
|
||||
#ifdef BOOST_HANA_DOXYGEN_INVOKED
|
||||
constexpr auto apply = [](auto&& f, auto&& ...x) -> decltype(auto) {
|
||||
return forwarded(f)(forwarded(x)...);
|
||||
};
|
||||
#else
|
||||
struct apply_t {
|
||||
template <typename F, typename... Args>
|
||||
constexpr auto operator()(F&& f, Args&&... args) const ->
|
||||
decltype(static_cast<F&&>(f)(static_cast<Args&&>(args)...))
|
||||
{
|
||||
return static_cast<F&&>(f)(static_cast<Args&&>(args)...);
|
||||
}
|
||||
|
||||
template <typename Base, typename T, typename Derived>
|
||||
constexpr auto operator()(T Base::*pmd, Derived&& ref) const ->
|
||||
decltype(static_cast<Derived&&>(ref).*pmd)
|
||||
{
|
||||
return static_cast<Derived&&>(ref).*pmd;
|
||||
}
|
||||
|
||||
template <typename PMD, typename Pointer>
|
||||
constexpr auto operator()(PMD pmd, Pointer&& ptr) const ->
|
||||
decltype((*static_cast<Pointer&&>(ptr)).*pmd)
|
||||
{
|
||||
return (*static_cast<Pointer&&>(ptr)).*pmd;
|
||||
}
|
||||
|
||||
template <typename Base, typename T, typename Derived, typename... Args>
|
||||
constexpr auto operator()(T Base::*pmf, Derived&& ref, Args&&... args) const ->
|
||||
decltype((static_cast<Derived&&>(ref).*pmf)(static_cast<Args&&>(args)...))
|
||||
{
|
||||
return (static_cast<Derived&&>(ref).*pmf)(static_cast<Args&&>(args)...);
|
||||
}
|
||||
|
||||
template <typename PMF, typename Pointer, typename... Args>
|
||||
constexpr auto operator()(PMF pmf, Pointer&& ptr, Args&& ...args) const ->
|
||||
decltype(((*static_cast<Pointer&&>(ptr)).*pmf)(static_cast<Args&&>(args)...))
|
||||
{
|
||||
return ((*static_cast<Pointer&&>(ptr)).*pmf)(static_cast<Args&&>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
constexpr apply_t apply{};
|
||||
#endif
|
||||
BOOST_HANA_NAMESPACE_END
|
||||
|
||||
#endif // !BOOST_HANA_FUNCTIONAL_APPLY_HPP
|
||||
@@ -0,0 +1,141 @@
|
||||
/*!
|
||||
@file
|
||||
Defines `boost::hana::arg`.
|
||||
|
||||
@copyright Louis Dionne 2013-2017
|
||||
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_ARG_HPP
|
||||
#define BOOST_HANA_FUNCTIONAL_ARG_HPP
|
||||
|
||||
#include <boost/hana/config.hpp>
|
||||
|
||||
#include <cstddef>
|
||||
#include <type_traits>
|
||||
|
||||
|
||||
BOOST_HANA_NAMESPACE_BEGIN
|
||||
//! @ingroup group-functional
|
||||
//! Return the `n`th passed argument.
|
||||
//!
|
||||
//! Specifically, `arg<n>(x1, ..., xn, ..., xm)` is equivalent to `xn`.
|
||||
//! Note that indexing starts at 1, so `arg<1>` returns the 1st argument,
|
||||
//! `arg<2>` the 2nd and so on. Using `arg<0>` is an error. Passing
|
||||
//! less than `n` arguments to `arg<n>` is also an error.
|
||||
//!
|
||||
//!
|
||||
//! @tparam n
|
||||
//! An unsigned integer representing the argument to return. `n` must be
|
||||
//! positive (meaning nonzero).
|
||||
//!
|
||||
//! @param x1, ..., xm
|
||||
//! A variadic pack of arguments from which the `n`th one is returned.
|
||||
//!
|
||||
//!
|
||||
//! @internal
|
||||
//! ### Discussion: could `n` be dynamic?
|
||||
//! We could have chosen `arg` to be used like `arg(n)(x...)` instead of
|
||||
//! `arg<n>(x...)`. Provided all the arguments were of the same type, it
|
||||
//! would then be possible for `n` to only be known at runtime. However,
|
||||
//! we would then lose the ability to assert the in-boundedness of `n`
|
||||
//! statically.
|
||||
//!
|
||||
//! ### Rationale for `n` being a non-type template parameter
|
||||
//! I claim that the only interesting use case is with a compile-time
|
||||
//! `n`, which means that the usage would become `arg(int_<n>)(x...)`,
|
||||
//! which is more cumbersome to write than `arg<n>(x...)`. This is open
|
||||
//! for discussion.
|
||||
//! @endinternal
|
||||
//!
|
||||
//! ### Example
|
||||
//! @include example/functional/arg.cpp
|
||||
#ifdef BOOST_HANA_DOXYGEN_INVOKED
|
||||
template <std::size_t n>
|
||||
constexpr auto arg = [](auto&& x1, ..., auto&& xm) -> decltype(auto) {
|
||||
return forwarded(xn);
|
||||
};
|
||||
#else
|
||||
template <std::size_t n, typename = void>
|
||||
struct arg_t;
|
||||
|
||||
template <>
|
||||
struct arg_t<1> {
|
||||
template <typename X1, typename ...Xn>
|
||||
constexpr X1 operator()(X1&& x1, Xn&& ...) const
|
||||
{ return static_cast<X1&&>(x1); }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct arg_t<2> {
|
||||
template <typename X1, typename X2, typename ...Xn>
|
||||
constexpr X2 operator()(X1&&, X2&& x2, Xn&& ...) const
|
||||
{ return static_cast<X2&&>(x2); }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct arg_t<3> {
|
||||
template <typename X1, typename X2, typename X3, typename ...Xn>
|
||||
constexpr X3 operator()(X1&&, X2&&, X3&& x3, Xn&& ...) const
|
||||
{ return static_cast<X3&&>(x3); }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct arg_t<4> {
|
||||
template <typename X1, typename X2, typename X3, typename X4, typename ...Xn>
|
||||
constexpr X4 operator()(X1&&, X2&&, X3&&, X4&& x4, Xn&& ...) const
|
||||
{ return static_cast<X4&&>(x4); }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct arg_t<5> {
|
||||
template <typename X1, typename X2, typename X3, typename X4,
|
||||
typename X5, typename ...Xn>
|
||||
constexpr X5 operator()(X1&&, X2&&, X3&&, X4&&, X5&& x5, Xn&& ...) const
|
||||
{ return static_cast<X5&&>(x5); }
|
||||
};
|
||||
|
||||
template <std::size_t n, typename>
|
||||
struct arg_t {
|
||||
static_assert(n > 0,
|
||||
"invalid usage of boost::hana::arg<n> with n == 0");
|
||||
|
||||
template <typename X1, typename X2, typename X3, typename X4,
|
||||
typename X5, typename ...Xn>
|
||||
constexpr decltype(auto)
|
||||
operator()(X1&&, X2&&, X3&&, X4&&, X5&&, Xn&& ...xn) const {
|
||||
static_assert(sizeof...(xn) >= n - 5,
|
||||
"invalid usage of boost::hana::arg<n> with too few arguments");
|
||||
|
||||
// Since compilers will typically try to continue for a bit after
|
||||
// an error/static assertion, we must avoid sending the compiler
|
||||
// in a very long computation if n == 0.
|
||||
return arg_t<n == 0 ? 1 : n - 5>{}(static_cast<Xn&&>(xn)...);
|
||||
}
|
||||
};
|
||||
|
||||
template <std::size_t n>
|
||||
struct arg_t<n, std::enable_if_t<(n > 25)>> {
|
||||
template <
|
||||
typename X1, typename X2, typename X3, typename X4, typename X5,
|
||||
typename X6, typename X7, typename X8, typename X9, typename X10,
|
||||
typename X11, typename X12, typename X13, typename X14, typename X15,
|
||||
typename X16, typename X17, typename X18, typename X19, typename X20,
|
||||
typename X21, typename X22, typename X23, typename X24, typename X25,
|
||||
typename ...Xn>
|
||||
constexpr decltype(auto)
|
||||
operator()(X1&&, X2&&, X3&&, X4&&, X5&&,
|
||||
X6&&, X7&&, X8&&, X9&&, X10&&,
|
||||
X11&&, X12&&, X13&&, X14&&, X15&&,
|
||||
X16&&, X17&&, X18&&, X19&&, X20&&,
|
||||
X21&&, X22&&, X23&&, X24&&, X25&&, Xn&& ...xn) const
|
||||
{ return arg_t<n - 25>{}(static_cast<Xn&&>(xn)...); }
|
||||
};
|
||||
|
||||
template <std::size_t n>
|
||||
constexpr arg_t<n> arg{};
|
||||
#endif
|
||||
BOOST_HANA_NAMESPACE_END
|
||||
|
||||
#endif // !BOOST_HANA_FUNCTIONAL_ARG_HPP
|
||||
@@ -0,0 +1,112 @@
|
||||
/*!
|
||||
@file
|
||||
Defines `boost::hana::capture`.
|
||||
|
||||
@copyright Louis Dionne 2013-2017
|
||||
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_CAPTURE_HPP
|
||||
#define BOOST_HANA_FUNCTIONAL_CAPTURE_HPP
|
||||
|
||||
#include <boost/hana/basic_tuple.hpp>
|
||||
#include <boost/hana/config.hpp>
|
||||
#include <boost/hana/detail/decay.hpp>
|
||||
#include <boost/hana/functional/partial.hpp>
|
||||
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
|
||||
|
||||
BOOST_HANA_NAMESPACE_BEGIN
|
||||
//! @ingroup group-functional
|
||||
//! Create a function capturing the given variables.
|
||||
//!
|
||||
//! Given 0 or more variables, `capture` creates a closure that can be
|
||||
//! used to partially apply a function. This is very similar to `partial`,
|
||||
//! except that `capture` allows the partially applied function to be
|
||||
//! specified later. Specifically, `capture(vars...)` is a function object
|
||||
//! taking a function `f` and returning `f` partially applied to `vars...`.
|
||||
//! In other words,
|
||||
//! @code
|
||||
//! capture(vars...)(f)(args...) == f(vars..., args...)
|
||||
//! @endcode
|
||||
//!
|
||||
//! @note
|
||||
//! The arity of `f` must match the total number of arguments passed to
|
||||
//! it, i.e. `sizeof...(vars) + sizeof...(args)`.
|
||||
//!
|
||||
//!
|
||||
//! Example
|
||||
//! -------
|
||||
//! @include example/functional/capture.cpp
|
||||
#ifdef BOOST_HANA_DOXYGEN_INVOKED
|
||||
constexpr auto capture = [](auto&& ...variables) {
|
||||
return [perfect-capture](auto&& f) {
|
||||
return [perfect-capture](auto&& ...args) -> decltype(auto) {
|
||||
return forwarded(f)(forwarded(variables)..., forwarded(args)...);
|
||||
};
|
||||
};
|
||||
};
|
||||
#else
|
||||
namespace detail {
|
||||
template <typename F, typename Closure, std::size_t ...i>
|
||||
constexpr auto apply_capture(F&& f, Closure&& closure, std::index_sequence<i...>) {
|
||||
return hana::partial(static_cast<F&&>(f),
|
||||
hana::at_c<i>(static_cast<Closure&&>(closure).storage_)...
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ...X>
|
||||
struct capture_t;
|
||||
|
||||
struct make_capture_t {
|
||||
struct secret { };
|
||||
template <typename ...X>
|
||||
constexpr capture_t<typename detail::decay<X>::type...>
|
||||
operator()(X&& ...x) const {
|
||||
return {secret{}, static_cast<X&&>(x)...};
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ...X>
|
||||
struct capture_t {
|
||||
template <typename ...Y>
|
||||
constexpr capture_t(make_capture_t::secret, Y&& ...y)
|
||||
: storage_{static_cast<Y&&>(y)...}
|
||||
{ }
|
||||
|
||||
basic_tuple<X...> storage_;
|
||||
|
||||
template <typename F>
|
||||
constexpr auto operator()(F&& f) const& {
|
||||
return detail::apply_capture(
|
||||
static_cast<F&&>(f), *this,
|
||||
std::make_index_sequence<sizeof...(X)>{}
|
||||
);
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
constexpr auto operator()(F&& f) & {
|
||||
return detail::apply_capture(
|
||||
static_cast<F&&>(f), *this,
|
||||
std::make_index_sequence<sizeof...(X)>{}
|
||||
);
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
constexpr auto operator()(F&& f) && {
|
||||
return detail::apply_capture(
|
||||
static_cast<F&&>(f), static_cast<capture_t&&>(*this),
|
||||
std::make_index_sequence<sizeof...(X)>{}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
constexpr make_capture_t capture{};
|
||||
#endif
|
||||
BOOST_HANA_NAMESPACE_END
|
||||
|
||||
#endif // !BOOST_HANA_FUNCTIONAL_CAPTURE_HPP
|
||||
@@ -0,0 +1,108 @@
|
||||
/*!
|
||||
@file
|
||||
Defines `boost::hana::compose`.
|
||||
|
||||
@copyright Louis Dionne 2013-2017
|
||||
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_COMPOSE_HPP
|
||||
#define BOOST_HANA_FUNCTIONAL_COMPOSE_HPP
|
||||
|
||||
#include <boost/hana/config.hpp>
|
||||
#include <boost/hana/detail/create.hpp>
|
||||
#include <boost/hana/detail/variadic/foldl1.hpp>
|
||||
|
||||
#include <utility>
|
||||
|
||||
|
||||
BOOST_HANA_NAMESPACE_BEGIN
|
||||
//! @ingroup group-functional
|
||||
//! Return the composition of two functions or more.
|
||||
//!
|
||||
//! `compose` is defined inductively. When given more than two functions,
|
||||
//! `compose(f, g, h...)` is equivalent to `compose(f, compose(g, h...))`.
|
||||
//! When given two functions, `compose(f, g)` is a function such that
|
||||
//! @code
|
||||
//! compose(f, g)(x, y...) == f(g(x), y...)
|
||||
//! @endcode
|
||||
//!
|
||||
//! If you need composition of the form `f(g(x, y...))`, use `demux` instead.
|
||||
//!
|
||||
//! @note
|
||||
//! `compose` is an associative operation; `compose(f, compose(g, h))`
|
||||
//! is equivalent to `compose(compose(f, g), h)`.
|
||||
//!
|
||||
//! @internal
|
||||
//! ### Proof of associativity
|
||||
//!
|
||||
//! @code
|
||||
//! compose(f, compose(g, h))(x, xs...) == f(compose(g, h)(x), xs...)
|
||||
//! == f(g(h(x)), xs...)
|
||||
//!
|
||||
//! compose(compose(f, g), h)(x, xs...) == compose(f, g)(h(x), xs...)
|
||||
//! == f(g(h(x)), xs...)
|
||||
//! @endcode
|
||||
//! @endinternal
|
||||
//!
|
||||
//! ### Example
|
||||
//! @include example/functional/compose.cpp
|
||||
#ifdef BOOST_HANA_DOXYGEN_INVOKED
|
||||
constexpr auto compose = [](auto&& f1, auto&& f2, ..., auto&& fn) {
|
||||
return [perfect-capture](auto&& x, auto&& ...xs) -> decltype(auto) {
|
||||
return forwarded(f1)(
|
||||
forwarded(f2)(
|
||||
...
|
||||
forwarded(fn)(forwarded(x))
|
||||
),
|
||||
forwarded(xs)...
|
||||
);
|
||||
}
|
||||
};
|
||||
#else
|
||||
template <typename F, typename G>
|
||||
struct _compose {
|
||||
F f; G g;
|
||||
|
||||
template <typename X, typename ...Xs>
|
||||
constexpr decltype(auto) operator()(X&& x, Xs&& ...xs) const& {
|
||||
return f(
|
||||
g(static_cast<X&&>(x)),
|
||||
static_cast<Xs&&>(xs)...
|
||||
);
|
||||
}
|
||||
|
||||
template <typename X, typename ...Xs>
|
||||
constexpr decltype(auto) operator()(X&& x, Xs&& ...xs) & {
|
||||
return f(
|
||||
g(static_cast<X&&>(x)),
|
||||
static_cast<Xs&&>(xs)...
|
||||
);
|
||||
}
|
||||
|
||||
template <typename X, typename ...Xs>
|
||||
constexpr decltype(auto) operator()(X&& x, Xs&& ...xs) && {
|
||||
return std::move(f)(
|
||||
std::move(g)(static_cast<X&&>(x)),
|
||||
static_cast<Xs&&>(xs)...
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
struct _make_compose {
|
||||
template <typename F, typename G, typename ...H>
|
||||
constexpr decltype(auto) operator()(F&& f, G&& g, H&& ...h) const {
|
||||
return detail::variadic::foldl1(detail::create<_compose>{},
|
||||
static_cast<F&&>(f),
|
||||
static_cast<G&&>(g),
|
||||
static_cast<H&&>(h)...
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
constexpr _make_compose compose{};
|
||||
#endif
|
||||
BOOST_HANA_NAMESPACE_END
|
||||
|
||||
#endif // !BOOST_HANA_FUNCTIONAL_COMPOSE_HPP
|
||||
@@ -0,0 +1,170 @@
|
||||
/*!
|
||||
@file
|
||||
Defines `boost::hana::curry`.
|
||||
|
||||
@copyright Louis Dionne 2013-2017
|
||||
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_CURRY_HPP
|
||||
#define BOOST_HANA_FUNCTIONAL_CURRY_HPP
|
||||
|
||||
#include <boost/hana/config.hpp>
|
||||
#include <boost/hana/detail/decay.hpp>
|
||||
#include <boost/hana/functional/apply.hpp>
|
||||
#include <boost/hana/functional/partial.hpp>
|
||||
|
||||
#include <cstddef>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
|
||||
BOOST_HANA_NAMESPACE_BEGIN
|
||||
//! @ingroup group-functional
|
||||
//! Curry a function up to the given number of arguments.
|
||||
//!
|
||||
//! [Currying][Wikipedia.currying] is a technique in which we consider a
|
||||
//! function taking multiple arguments (or, equivalently, a tuple of
|
||||
//! arguments), and turn it into a function which takes a single argument
|
||||
//! and returns a function to handle the remaining arguments. To help
|
||||
//! visualize, let's denote the type of a function `f` which takes
|
||||
//! arguments of types `X1, ..., Xn` and returns a `R` as
|
||||
//! @code
|
||||
//! (X1, ..., Xn) -> R
|
||||
//! @endcode
|
||||
//!
|
||||
//! Then, currying is the process of taking `f` and turning it into an
|
||||
//! equivalent function (call it `g`) of type
|
||||
//! @code
|
||||
//! X1 -> (X2 -> (... -> (Xn -> R)))
|
||||
//! @endcode
|
||||
//!
|
||||
//! This gives us the following equivalence, where `x1`, ..., `xn` are
|
||||
//! objects of type `X1`, ..., `Xn` respectively:
|
||||
//! @code
|
||||
//! f(x1, ..., xn) == g(x1)...(xn)
|
||||
//! @endcode
|
||||
//!
|
||||
//! Currying can be useful in several situations, especially when working
|
||||
//! with higher-order functions.
|
||||
//!
|
||||
//! This `curry` utility is an implementation of currying in C++.
|
||||
//! Specifically, `curry<n>(f)` is a function such that
|
||||
//! @code
|
||||
//! curry<n>(f)(x1)...(xn) == f(x1, ..., xn)
|
||||
//! @endcode
|
||||
//!
|
||||
//! Note that the `n` has to be specified explicitly because the existence
|
||||
//! of functions with variadic arguments in C++ make it impossible to know
|
||||
//! when currying should stop.
|
||||
//!
|
||||
//! Unlike usual currying, this implementation also allows a curried
|
||||
//! function to be called with several arguments at a time. Hence, the
|
||||
//! following always holds
|
||||
//! @code
|
||||
//! curry<n>(f)(x1, ..., xk) == curry<n - k>(f)(x1)...(xk)
|
||||
//! @endcode
|
||||
//!
|
||||
//! Of course, this requires `k` to be less than or equal to `n`; failure
|
||||
//! to satisfy this will trigger a static assertion. This syntax is
|
||||
//! supported because it makes curried functions usable where normal
|
||||
//! functions are expected.
|
||||
//!
|
||||
//! Another "extension" is that `curry<0>(f)` is supported: `curry<0>(f)`
|
||||
//! is a nullary function; whereas the classical definition for currying
|
||||
//! seems to leave this case undefined, as nullary functions don't make
|
||||
//! much sense in purely functional languages.
|
||||
//!
|
||||
//!
|
||||
//! Example
|
||||
//! -------
|
||||
//! @include example/functional/curry.cpp
|
||||
//!
|
||||
//!
|
||||
//! [Wikipedia.currying]: http://en.wikipedia.org/wiki/Currying
|
||||
#ifdef BOOST_HANA_DOXYGEN_INVOKED
|
||||
template <std::size_t n>
|
||||
constexpr auto curry = [](auto&& f) {
|
||||
return [perfect-capture](auto&& x1) {
|
||||
return [perfect-capture](auto&& x2) {
|
||||
...
|
||||
return [perfect-capture](auto&& xn) -> decltype(auto) {
|
||||
return forwarded(f)(
|
||||
forwarded(x1), forwarded(x2), ..., forwarded(xn)
|
||||
);
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
#else
|
||||
template <std::size_t n, typename F>
|
||||
struct curry_t;
|
||||
|
||||
template <std::size_t n>
|
||||
struct make_curry_t {
|
||||
template <typename F>
|
||||
constexpr curry_t<n, typename detail::decay<F>::type>
|
||||
operator()(F&& f) const { return {static_cast<F&&>(f)}; }
|
||||
};
|
||||
|
||||
template <std::size_t n>
|
||||
constexpr make_curry_t<n> curry{};
|
||||
|
||||
namespace curry_detail {
|
||||
template <std::size_t n>
|
||||
constexpr make_curry_t<n> curry_or_call{};
|
||||
|
||||
template <>
|
||||
constexpr auto curry_or_call<0> = apply;
|
||||
}
|
||||
|
||||
template <std::size_t n, typename F>
|
||||
struct curry_t {
|
||||
F f;
|
||||
|
||||
template <typename ...X>
|
||||
constexpr decltype(auto) operator()(X&& ...x) const& {
|
||||
static_assert(sizeof...(x) <= n,
|
||||
"too many arguments provided to boost::hana::curry");
|
||||
return curry_detail::curry_or_call<n - sizeof...(x)>(
|
||||
partial(f, static_cast<X&&>(x)...)
|
||||
);
|
||||
}
|
||||
|
||||
template <typename ...X>
|
||||
constexpr decltype(auto) operator()(X&& ...x) & {
|
||||
static_assert(sizeof...(x) <= n,
|
||||
"too many arguments provided to boost::hana::curry");
|
||||
return curry_detail::curry_or_call<n - sizeof...(x)>(
|
||||
partial(f, static_cast<X&&>(x)...)
|
||||
);
|
||||
}
|
||||
|
||||
template <typename ...X>
|
||||
constexpr decltype(auto) operator()(X&& ...x) && {
|
||||
static_assert(sizeof...(x) <= n,
|
||||
"too many arguments provided to boost::hana::curry");
|
||||
return curry_detail::curry_or_call<n - sizeof...(x)>(
|
||||
partial(std::move(f), static_cast<X&&>(x)...)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename F>
|
||||
struct curry_t<0, F> {
|
||||
F f;
|
||||
|
||||
constexpr decltype(auto) operator()() const&
|
||||
{ return f(); }
|
||||
|
||||
constexpr decltype(auto) operator()() &
|
||||
{ return f(); }
|
||||
|
||||
constexpr decltype(auto) operator()() &&
|
||||
{ return std::move(f)(); }
|
||||
};
|
||||
#endif
|
||||
BOOST_HANA_NAMESPACE_END
|
||||
|
||||
#endif // !BOOST_HANA_FUNCTIONAL_CURRY_HPP
|
||||
@@ -0,0 +1,269 @@
|
||||
/*!
|
||||
@file
|
||||
Defines `boost::hana::demux`.
|
||||
|
||||
@copyright Louis Dionne 2013-2017
|
||||
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_DEMUX_HPP
|
||||
#define BOOST_HANA_FUNCTIONAL_DEMUX_HPP
|
||||
|
||||
#include <boost/hana/basic_tuple.hpp>
|
||||
#include <boost/hana/config.hpp>
|
||||
#include <boost/hana/detail/decay.hpp>
|
||||
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
|
||||
|
||||
BOOST_HANA_NAMESPACE_BEGIN
|
||||
//! @ingroup group-functional
|
||||
//! Invoke a function with the results of invoking other functions
|
||||
//! on its arguments.
|
||||
//!
|
||||
//! Specifically, `demux(f)(g...)` is a function such that
|
||||
//! @code
|
||||
//! demux(f)(g...)(x...) == f(g(x...)...)
|
||||
//! @endcode
|
||||
//!
|
||||
//! Each `g` is called with all the arguments, and then `f` is called
|
||||
//! with the result of each `g`. Hence, the arity of `f` must match
|
||||
//! the number of `g`s.
|
||||
//!
|
||||
//! This is called `demux` because of a vague similarity between this
|
||||
//! device and a demultiplexer in signal processing. `demux` takes what
|
||||
//! can be seen as a continuation (`f`), a bunch of functions to split a
|
||||
//! signal (`g...`) and zero or more arguments representing the signal
|
||||
//! (`x...`). Then, it calls the continuation with the result of
|
||||
//! splitting the signal with whatever functions where given.
|
||||
//!
|
||||
//! @note
|
||||
//! When used with two functions only, `demux` is associative. In other
|
||||
//! words (and noting `demux(f, g) = demux(f)(g)` to ease the notation),
|
||||
//! it is true that `demux(demux(f, g), h) == demux(f, demux(g, h))`.
|
||||
//!
|
||||
//!
|
||||
//! Signature
|
||||
//! ---------
|
||||
//! The signature of `demux` is
|
||||
//! \f[
|
||||
//! \mathtt{demux} :
|
||||
//! (B_1 \times \dotsb \times B_n \to C)
|
||||
//! \to ((A_1 \times \dotsb \times A_n \to B_1)
|
||||
//! \times \dotsb
|
||||
//! \times (A_1 \times \dotsb \times A_n \to B_n))
|
||||
//! \to (A_1 \times \dotsb \times A_n \to C)
|
||||
//! \f]
|
||||
//!
|
||||
//! This can be rewritten more tersely as
|
||||
//! \f[
|
||||
//! \mathtt{demux} :
|
||||
//! \left(\prod_{i=1}^n B_i \to C \right)
|
||||
//! \to \prod_{j=1}^n \left(\prod_{i=1}^n A_i \to B_j \right)
|
||||
//! \to \left(\prod_{i=1}^n A_i \to C \right)
|
||||
//! \f]
|
||||
//!
|
||||
//!
|
||||
//! Link with normal composition
|
||||
//! ----------------------------
|
||||
//! The signature of `compose` is
|
||||
//! \f[
|
||||
//! \mathtt{compose} : (B \to C) \times (A \to B) \to (A \to C)
|
||||
//! \f]
|
||||
//!
|
||||
//! A valid observation is that this coincides exactly with the type
|
||||
//! of `demux` when used with a single unary function. Actually, both
|
||||
//! functions are equivalent:
|
||||
//! @code
|
||||
//! demux(f)(g)(x) == compose(f, g)(x)
|
||||
//! @endcode
|
||||
//!
|
||||
//! However, let's now consider the curried version of `compose`,
|
||||
//! `curry<2>(compose)`:
|
||||
//! \f[
|
||||
//! \mathtt{curry_2(compose)} : (B \to C) \to ((A \to B) \to (A \to C))
|
||||
//! \f]
|
||||
//!
|
||||
//! For the rest of this explanation, we'll just consider the curried
|
||||
//! version of `compose` and so we'll use `compose` instead of
|
||||
//! `curry<2>(compose)` to lighten the notation. With currying, we can
|
||||
//! now consider `compose` applied to itself:
|
||||
//! \f[
|
||||
//! \mathtt{compose(compose, compose)} :
|
||||
//! (B \to C) \to (A_1 \to A_2 \to B) \to (A_1 \to A_2 \to C)
|
||||
//! \f]
|
||||
//!
|
||||
//! If we uncurry deeply the above expression, we obtain
|
||||
//! \f[
|
||||
//! \mathtt{compose(compose, compose)} :
|
||||
//! (B \to C) \times (A_1 \times A_2 \to B) \to (A_1 \times A_2 \to C)
|
||||
//! \f]
|
||||
//!
|
||||
//! This signature is exactly the same as that of `demux` when given a
|
||||
//! single binary function, and indeed they are equivalent definitions.
|
||||
//! We can also generalize this further by considering
|
||||
//! `compose(compose(compose, compose), compose)`:
|
||||
//! \f[
|
||||
//! \mathtt{compose(compose(compose, compose), compose)} :
|
||||
//! (B \to C) \to (A_1 \to A_2 \to A_3 \to B)
|
||||
//! \to (A_1 \to A_2 \to A_3 \to C)
|
||||
//! \f]
|
||||
//!
|
||||
//! which uncurries to
|
||||
//! \f[
|
||||
//! \mathtt{compose(compose(compose, compose), compose)} :
|
||||
//! (B \to C) \times (A_1 \times A_2 \times A_3 \to B)
|
||||
//! \to (A_1 \times A_2 \times A_3 \to C)
|
||||
//! \f]
|
||||
//!
|
||||
//! This signature is exactly the same as that of `demux` when given a
|
||||
//! single ternary function. Hence, for a single n-ary function `g`,
|
||||
//! `demux(f)(g)` is equivalent to the n-times composition of `compose`
|
||||
//! with itself, applied to `g` and `f`:
|
||||
//! @code
|
||||
//! demux(f)(g) == fold_left([compose, ..., compose], id, compose)(g, f)
|
||||
//! // ^^^^^^^^^^^^^^^^^^^^^ n times
|
||||
//! @endcode
|
||||
//!
|
||||
//! More information on this insight can be seen [here][1]. Also, I'm
|
||||
//! not sure how this insight could be generalized to more than one
|
||||
//! function `g`, or if that is even possible.
|
||||
//!
|
||||
//!
|
||||
//! Proof of associativity in the binary case
|
||||
//! -----------------------------------------
|
||||
//! As explained above, `demux` is associative when it is used with
|
||||
//! two functions only. Indeed, given functions `f`, `g` and `h` with
|
||||
//! suitable signatures, we have
|
||||
//! @code
|
||||
//! demux(f)(demux(g)(h))(x...) == f(demux(g)(h)(x...))
|
||||
//! == f(g(h(x...)))
|
||||
//! @endcode
|
||||
//!
|
||||
//! On the other hand, we have
|
||||
//! @code
|
||||
//! demux(demux(f)(g))(h)(x...) == demux(f)(g)(h(x...))
|
||||
//! == f(g(h(x...)))
|
||||
//! @endcode
|
||||
//!
|
||||
//! and hence `demux` is associative in the binary case.
|
||||
//!
|
||||
//!
|
||||
//! Example
|
||||
//! -------
|
||||
//! @include example/functional/demux.cpp
|
||||
//!
|
||||
//! [1]: http://stackoverflow.com/q/5821089/627587
|
||||
#ifdef BOOST_HANA_DOXYGEN_INVOKED
|
||||
constexpr auto demux = [](auto&& f) {
|
||||
return [perfect-capture](auto&& ...g) {
|
||||
return [perfect-capture](auto&& ...x) -> decltype(auto) {
|
||||
// x... can't be forwarded unless there is a single g
|
||||
// function, or that could cause double-moves.
|
||||
return forwarded(f)(forwarded(g)(x...)...);
|
||||
};
|
||||
};
|
||||
};
|
||||
#else
|
||||
template <typename F>
|
||||
struct pre_demux_t;
|
||||
|
||||
struct make_pre_demux_t {
|
||||
struct secret { };
|
||||
template <typename F>
|
||||
constexpr pre_demux_t<typename detail::decay<F>::type> operator()(F&& f) const {
|
||||
return {static_cast<F&&>(f)};
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Indices, typename F, typename ...G>
|
||||
struct demux_t;
|
||||
|
||||
template <typename F>
|
||||
struct pre_demux_t {
|
||||
F f;
|
||||
|
||||
template <typename ...G>
|
||||
constexpr demux_t<std::make_index_sequence<sizeof...(G)>, F,
|
||||
typename detail::decay<G>::type...>
|
||||
operator()(G&& ...g) const& {
|
||||
return {make_pre_demux_t::secret{}, this->f, static_cast<G&&>(g)...};
|
||||
}
|
||||
|
||||
template <typename ...G>
|
||||
constexpr demux_t<std::make_index_sequence<sizeof...(G)>, F,
|
||||
typename detail::decay<G>::type...>
|
||||
operator()(G&& ...g) && {
|
||||
return {make_pre_demux_t::secret{}, static_cast<F&&>(this->f), static_cast<G&&>(g)...};
|
||||
}
|
||||
};
|
||||
|
||||
template <std::size_t ...n, typename F, typename ...G>
|
||||
struct demux_t<std::index_sequence<n...>, F, G...> {
|
||||
template <typename ...T>
|
||||
constexpr demux_t(make_pre_demux_t::secret, T&& ...t)
|
||||
: storage_{static_cast<T&&>(t)...}
|
||||
{ }
|
||||
|
||||
basic_tuple<F, G...> storage_;
|
||||
|
||||
template <typename ...X>
|
||||
constexpr decltype(auto) operator()(X&& ...x) const& {
|
||||
return hana::at_c<0>(storage_)(
|
||||
hana::at_c<n+1>(storage_)(x...)...
|
||||
);
|
||||
}
|
||||
|
||||
template <typename ...X>
|
||||
constexpr decltype(auto) operator()(X&& ...x) & {
|
||||
return hana::at_c<0>(storage_)(
|
||||
hana::at_c<n+1>(storage_)(x...)...
|
||||
);
|
||||
}
|
||||
|
||||
template <typename ...X>
|
||||
constexpr decltype(auto) operator()(X&& ...x) && {
|
||||
return static_cast<F&&>(hana::at_c<0>(storage_))(
|
||||
static_cast<G&&>(hana::at_c<n+1>(storage_))(x...)...
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename F, typename G>
|
||||
struct demux_t<std::index_sequence<0>, F, G> {
|
||||
template <typename ...T>
|
||||
constexpr demux_t(make_pre_demux_t::secret, T&& ...t)
|
||||
: storage_{static_cast<T&&>(t)...}
|
||||
{ }
|
||||
|
||||
basic_tuple<F, G> storage_;
|
||||
|
||||
template <typename ...X>
|
||||
constexpr decltype(auto) operator()(X&& ...x) const& {
|
||||
return hana::at_c<0>(storage_)(
|
||||
hana::at_c<1>(storage_)(static_cast<X&&>(x)...)
|
||||
);
|
||||
}
|
||||
|
||||
template <typename ...X>
|
||||
constexpr decltype(auto) operator()(X&& ...x) & {
|
||||
return hana::at_c<0>(storage_)(
|
||||
hana::at_c<1>(storage_)(static_cast<X&&>(x)...)
|
||||
);
|
||||
}
|
||||
|
||||
template <typename ...X>
|
||||
constexpr decltype(auto) operator()(X&& ...x) && {
|
||||
return static_cast<F&&>(hana::at_c<0>(storage_))(
|
||||
static_cast<G&&>(hana::at_c<1>(storage_))(static_cast<X&&>(x)...)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
constexpr make_pre_demux_t demux{};
|
||||
#endif
|
||||
BOOST_HANA_NAMESPACE_END
|
||||
|
||||
#endif // !BOOST_HANA_FUNCTIONAL_DEMUX_HPP
|
||||
@@ -0,0 +1,83 @@
|
||||
/*!
|
||||
@file
|
||||
Defines `boost::hana::fix`.
|
||||
|
||||
@copyright Louis Dionne 2013-2017
|
||||
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_FIX_HPP
|
||||
#define BOOST_HANA_FUNCTIONAL_FIX_HPP
|
||||
|
||||
#include <boost/hana/config.hpp>
|
||||
#include <boost/hana/detail/create.hpp>
|
||||
|
||||
#include <utility>
|
||||
|
||||
|
||||
BOOST_HANA_NAMESPACE_BEGIN
|
||||
//! @ingroup group-functional
|
||||
//! Return a function computing the fixed point of a function.
|
||||
//!
|
||||
//! `fix` is an implementation of the [Y-combinator][], also called the
|
||||
//! fixed-point combinator. It encodes the idea of recursion, and in fact
|
||||
//! any recursive function can be written in terms of it.
|
||||
//!
|
||||
//! Specifically, `fix(f)` is a function such that
|
||||
//! @code
|
||||
//! fix(f)(x...) == f(fix(f), x...)
|
||||
//! @endcode
|
||||
//!
|
||||
//! This definition allows `f` to use its first argument as a continuation
|
||||
//! to call itself recursively. Indeed, if `f` calls its first argument
|
||||
//! with `y...`, it is equivalent to calling `f(fix(f), y...)` per the
|
||||
//! above equation.
|
||||
//!
|
||||
//! Most of the time, it is more convenient and efficient to define
|
||||
//! recursive functions without using a fixed-point combinator. However,
|
||||
//! there are some cases where `fix` provides either more flexibility
|
||||
//! (e.g. the ability to change the callback inside `f`) or makes it
|
||||
//! possible to write functions that couldn't be defined recursively
|
||||
//! otherwise.
|
||||
//!
|
||||
//! @param f
|
||||
//! A function called as `f(self, x...)`, where `x...` are the arguments
|
||||
//! in the `fix(f)(x...)` expression and `self` is `fix(f)`.
|
||||
//!
|
||||
//! ### Example
|
||||
//! @include example/functional/fix.cpp
|
||||
//!
|
||||
//! [Y-combinator]: http://en.wikipedia.org/wiki/Fixed-point_combinator
|
||||
#ifdef BOOST_HANA_DOXYGEN_INVOKED
|
||||
constexpr auto fix = [](auto&& f) {
|
||||
return [perfect-capture](auto&& ...x) -> decltype(auto) {
|
||||
return forwarded(f)(fix(f), forwarded(x)...);
|
||||
};
|
||||
};
|
||||
#else
|
||||
template <typename F>
|
||||
struct fix_t;
|
||||
|
||||
constexpr detail::create<fix_t> fix{};
|
||||
|
||||
template <typename F>
|
||||
struct fix_t {
|
||||
F f;
|
||||
|
||||
template <typename ...X>
|
||||
constexpr decltype(auto) operator()(X&& ...x) const&
|
||||
{ return f(fix(f), static_cast<X&&>(x)...); }
|
||||
|
||||
template <typename ...X>
|
||||
constexpr decltype(auto) operator()(X&& ...x) &
|
||||
{ return f(fix(f), static_cast<X&&>(x)...); }
|
||||
|
||||
template <typename ...X>
|
||||
constexpr decltype(auto) operator()(X&& ...x) &&
|
||||
{ return std::move(f)(fix(f), static_cast<X&&>(x)...); }
|
||||
};
|
||||
#endif
|
||||
BOOST_HANA_NAMESPACE_END
|
||||
|
||||
#endif // !BOOST_HANA_FUNCTIONAL_FIX_HPP
|
||||
@@ -0,0 +1,73 @@
|
||||
/*!
|
||||
@file
|
||||
Defines `boost::hana::flip`.
|
||||
|
||||
@copyright Louis Dionne 2013-2017
|
||||
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_FLIP_HPP
|
||||
#define BOOST_HANA_FUNCTIONAL_FLIP_HPP
|
||||
|
||||
#include <boost/hana/config.hpp>
|
||||
#include <boost/hana/detail/create.hpp>
|
||||
|
||||
#include <utility>
|
||||
|
||||
|
||||
BOOST_HANA_NAMESPACE_BEGIN
|
||||
//! @ingroup group-functional
|
||||
//! Invoke a function with its two first arguments reversed.
|
||||
//!
|
||||
//! Specifically, `flip(f)` is a function such that
|
||||
//! @code
|
||||
//! flip(f)(x, y, z...) == f(y, x, z...)
|
||||
//! @endcode
|
||||
//!
|
||||
//! ### Example
|
||||
//! @include example/functional/flip.cpp
|
||||
#ifdef BOOST_HANA_DOXYGEN_INVOKED
|
||||
constexpr auto flip = [](auto&& f) {
|
||||
return [perfect-capture](auto&& x, auto&& y, auto&& ...z) -> decltype(auto) {
|
||||
return forwarded(f)(forwarded(y), forwarded(x), forwarded(z)...);
|
||||
};
|
||||
};
|
||||
#else
|
||||
template <typename F>
|
||||
struct flip_t {
|
||||
F f;
|
||||
|
||||
template <typename X, typename Y, typename ...Z>
|
||||
constexpr decltype(auto) operator()(X&& x, Y&& y, Z&& ...z) const& {
|
||||
return f(
|
||||
static_cast<Y&&>(y),
|
||||
static_cast<X&&>(x),
|
||||
static_cast<Z&&>(z)...
|
||||
);
|
||||
}
|
||||
|
||||
template <typename X, typename Y, typename ...Z>
|
||||
constexpr decltype(auto) operator()(X&& x, Y&& y, Z&& ...z) & {
|
||||
return f(
|
||||
static_cast<Y&&>(y),
|
||||
static_cast<X&&>(x),
|
||||
static_cast<Z&&>(z)...
|
||||
);
|
||||
}
|
||||
|
||||
template <typename X, typename Y, typename ...Z>
|
||||
constexpr decltype(auto) operator()(X&& x, Y&& y, Z&& ...z) && {
|
||||
return std::move(f)(
|
||||
static_cast<Y&&>(y),
|
||||
static_cast<X&&>(x),
|
||||
static_cast<Z&&>(z)...
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
constexpr detail::create<flip_t> flip{};
|
||||
#endif
|
||||
BOOST_HANA_NAMESPACE_END
|
||||
|
||||
#endif // !BOOST_HANA_FUNCTIONAL_FLIP_HPP
|
||||
@@ -0,0 +1,38 @@
|
||||
/*!
|
||||
@file
|
||||
Defines `boost::hana::id`.
|
||||
|
||||
@copyright Louis Dionne 2013-2017
|
||||
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_ID_HPP
|
||||
#define BOOST_HANA_FUNCTIONAL_ID_HPP
|
||||
|
||||
#include <boost/hana/config.hpp>
|
||||
|
||||
|
||||
BOOST_HANA_NAMESPACE_BEGIN
|
||||
//! @ingroup group-functional
|
||||
//! The identity function -- returns its argument unchanged.
|
||||
//!
|
||||
//! ### Example
|
||||
//! @include example/functional/id.cpp
|
||||
#ifdef BOOST_HANA_DOXYGEN_INVOKED
|
||||
constexpr auto id = [](auto&& x) -> decltype(auto) {
|
||||
return forwarded(x);
|
||||
};
|
||||
#else
|
||||
struct id_t {
|
||||
template <typename T>
|
||||
constexpr T operator()(T&& t) const {
|
||||
return static_cast<T&&>(t);
|
||||
}
|
||||
};
|
||||
|
||||
constexpr id_t id{};
|
||||
#endif
|
||||
BOOST_HANA_NAMESPACE_END
|
||||
|
||||
#endif // !BOOST_HANA_FUNCTIONAL_ID_HPP
|
||||
@@ -0,0 +1,185 @@
|
||||
/*!
|
||||
@file
|
||||
Defines `boost::hana::infix`.
|
||||
|
||||
@copyright Louis Dionne 2013-2017
|
||||
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
|
||||
@@ -0,0 +1,201 @@
|
||||
/*!
|
||||
@file
|
||||
Defines `boost::hana::iterate`.
|
||||
|
||||
@copyright Louis Dionne 2013-2017
|
||||
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_ITERATE_HPP
|
||||
#define BOOST_HANA_FUNCTIONAL_ITERATE_HPP
|
||||
|
||||
#include <boost/hana/config.hpp>
|
||||
#include <boost/hana/core/when.hpp>
|
||||
#include <boost/hana/functional/partial.hpp>
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
|
||||
BOOST_HANA_NAMESPACE_BEGIN
|
||||
//! @ingroup group-functional
|
||||
//! Applies another function `n` times to its argument.
|
||||
//!
|
||||
//! Given a function `f` and an argument `x`, `iterate<n>(f, x)` returns
|
||||
//! the result of applying `f` `n` times to its argument. In other words,
|
||||
//! @code
|
||||
//! iterate<n>(f, x) == f(f( ... f(x)))
|
||||
//! ^^^^^^^^^^ n times total
|
||||
//! @endcode
|
||||
//!
|
||||
//! If `n == 0`, `iterate<n>(f, x)` returns the `x` argument unchanged
|
||||
//! and `f` is never applied. It is important to note that the function
|
||||
//! passed to `iterate<n>` must be a unary function. Indeed, since `f`
|
||||
//! will be called with the result of the previous `f` application, it
|
||||
//! may only take a single argument.
|
||||
//!
|
||||
//! In addition to what's documented above, `iterate` can also be
|
||||
//! partially applied to the function argument out-of-the-box. In
|
||||
//! other words, `iterate<n>(f)` is a function object applying `f`
|
||||
//! `n` times to the argument it is called with, which means that
|
||||
//! @code
|
||||
//! iterate<n>(f)(x) == iterate<n>(f, x)
|
||||
//! @endcode
|
||||
//!
|
||||
//! This is provided for convenience, and it turns out to be especially
|
||||
//! useful in conjunction with higher-order algorithms.
|
||||
//!
|
||||
//!
|
||||
//! Signature
|
||||
//! ---------
|
||||
//! Given a function \f$ f : T \to T \f$ and `x` and argument of data
|
||||
//! type `T`, the signature is
|
||||
//! \f$
|
||||
//! \mathtt{iterate_n} : (T \to T) \times T \to T
|
||||
//! \f$
|
||||
//!
|
||||
//! @tparam n
|
||||
//! An unsigned integer representing the number of times that `f`
|
||||
//! should be applied to its argument.
|
||||
//!
|
||||
//! @param f
|
||||
//! A function to apply `n` times to its argument.
|
||||
//!
|
||||
//! @param x
|
||||
//! The initial value to call `f` with.
|
||||
//!
|
||||
//!
|
||||
//! Example
|
||||
//! -------
|
||||
//! @include example/functional/iterate.cpp
|
||||
#ifdef BOOST_HANA_DOXYGEN_INVOKED
|
||||
template <std::size_t n>
|
||||
constexpr auto iterate = [](auto&& f) {
|
||||
return [perfect-capture](auto&& x) -> decltype(auto) {
|
||||
return f(f( ... f(forwarded(x))));
|
||||
};
|
||||
};
|
||||
#else
|
||||
template <std::size_t n, typename = when<true>>
|
||||
struct iterate_t;
|
||||
|
||||
template <>
|
||||
struct iterate_t<0> {
|
||||
template <typename F, typename X>
|
||||
constexpr X operator()(F&&, X&& x) const
|
||||
{ return static_cast<X&&>(x); }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct iterate_t<1> {
|
||||
template <typename F, typename X>
|
||||
constexpr decltype(auto) operator()(F&& f, X&& x) const {
|
||||
return f(static_cast<X&&>(x));
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct iterate_t<2> {
|
||||
template <typename F, typename X>
|
||||
constexpr decltype(auto) operator()(F&& f, X&& x) const {
|
||||
return f(f(static_cast<X&&>(x)));
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct iterate_t<3> {
|
||||
template <typename F, typename X>
|
||||
constexpr decltype(auto) operator()(F&& f, X&& x) const {
|
||||
return f(f(f(static_cast<X&&>(x))));
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct iterate_t<4> {
|
||||
template <typename F, typename X>
|
||||
constexpr decltype(auto) operator()(F&& f, X&& x) const {
|
||||
return f(f(f(f(static_cast<X&&>(x)))));
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct iterate_t<5> {
|
||||
template <typename F, typename X>
|
||||
constexpr decltype(auto) operator()(F&& f, X&& x) const {
|
||||
return f(f(f(f(f(static_cast<X&&>(x))))));
|
||||
}
|
||||
};
|
||||
|
||||
template <std::size_t n>
|
||||
struct iterate_t<n, when<(n >= 6) && (n < 12)>> {
|
||||
template <typename F, typename X>
|
||||
constexpr decltype(auto) operator()(F&& f, X&& x) const {
|
||||
return iterate_t<n - 6>{}(f,
|
||||
f(f(f(f(f(f(static_cast<X&&>(x)))))))
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
template <std::size_t n>
|
||||
struct iterate_t<n, when<(n >= 12) && (n < 24)>> {
|
||||
template <typename F, typename X>
|
||||
constexpr decltype(auto) operator()(F&& f, X&& x) const {
|
||||
return iterate_t<n - 12>{}(f,
|
||||
f(f(f(f(f(f(f(f(f(f(f(f(
|
||||
static_cast<X&&>(x)
|
||||
))))))))))))
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
template <std::size_t n>
|
||||
struct iterate_t<n, when<(n >= 24) && (n < 48)>> {
|
||||
template <typename F, typename X>
|
||||
constexpr decltype(auto) operator()(F&& f, X&& x) const {
|
||||
return iterate_t<n - 24>{}(f,
|
||||
f(f(f(f(f(f(f(f(f(f(f(f(
|
||||
f(f(f(f(f(f(f(f(f(f(f(f(
|
||||
static_cast<X&&>(x)
|
||||
))))))))))))
|
||||
))))))))))))
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
template <std::size_t n>
|
||||
struct iterate_t<n, when<(n >= 48)>> {
|
||||
template <typename F, typename X>
|
||||
constexpr decltype(auto) operator()(F&& f, X&& x) const {
|
||||
return iterate_t<n - 48>{}(f,
|
||||
f(f(f(f(f(f(f(f(f(f(f(f(
|
||||
f(f(f(f(f(f(f(f(f(f(f(f(
|
||||
f(f(f(f(f(f(f(f(f(f(f(f(
|
||||
f(f(f(f(f(f(f(f(f(f(f(f(
|
||||
static_cast<X&&>(x)
|
||||
))))))))))))
|
||||
))))))))))))
|
||||
))))))))))))
|
||||
))))))))))))
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
template <std::size_t n>
|
||||
struct make_iterate_t {
|
||||
template <typename F>
|
||||
constexpr decltype(auto) operator()(F&& f) const
|
||||
{ return hana::partial(iterate_t<n>{}, static_cast<F&&>(f)); }
|
||||
|
||||
template <typename F, typename X>
|
||||
constexpr decltype(auto) operator()(F&& f, X&& x) const {
|
||||
return iterate_t<n>{}(static_cast<F&&>(f),
|
||||
static_cast<X&&>(x));
|
||||
}
|
||||
};
|
||||
|
||||
template <std::size_t n>
|
||||
constexpr make_iterate_t<n> iterate{};
|
||||
#endif
|
||||
BOOST_HANA_NAMESPACE_END
|
||||
|
||||
#endif // !BOOST_HANA_FUNCTIONAL_ITERATE_HPP
|
||||
@@ -0,0 +1,114 @@
|
||||
/*!
|
||||
@file
|
||||
Defines `boost::hana::lockstep`.
|
||||
|
||||
@copyright Louis Dionne 2013-2017
|
||||
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_LOCKSTEP_HPP
|
||||
#define BOOST_HANA_FUNCTIONAL_LOCKSTEP_HPP
|
||||
|
||||
#include <boost/hana/basic_tuple.hpp>
|
||||
#include <boost/hana/config.hpp>
|
||||
#include <boost/hana/detail/decay.hpp>
|
||||
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
|
||||
|
||||
BOOST_HANA_NAMESPACE_BEGIN
|
||||
//! @ingroup group-functional
|
||||
//! Invoke a function with the result of invoking other functions on its
|
||||
//! arguments, in lockstep.
|
||||
//!
|
||||
//! Specifically, `lockstep(f)(g1, ..., gN)` is a function such that
|
||||
//! @code
|
||||
//! lockstep(f)(g1, ..., gN)(x1, ..., xN) == f(g1(x1), ..., gN(xN))
|
||||
//! @endcode
|
||||
//!
|
||||
//! Since each `g` is invoked on its corresponding argument in lockstep,
|
||||
//! the number of arguments must match the number of `g`s.
|
||||
//!
|
||||
//!
|
||||
//! Example
|
||||
//! -------
|
||||
//! @include example/functional/lockstep.cpp
|
||||
#ifdef BOOST_HANA_DOXYGEN_INVOKED
|
||||
constexpr auto lockstep = [](auto&& f, auto&& ...g) {
|
||||
return [perfect-capture](auto&& ...x) -> decltype(auto) {
|
||||
return forwarded(f)(forwarded(g)(forwarded(x))...);
|
||||
};
|
||||
};
|
||||
#else
|
||||
template <typename Indices, typename F, typename ...G>
|
||||
struct lockstep_t;
|
||||
|
||||
template <typename F>
|
||||
struct pre_lockstep_t;
|
||||
|
||||
struct make_pre_lockstep_t {
|
||||
struct secret { };
|
||||
template <typename F>
|
||||
constexpr pre_lockstep_t<typename detail::decay<F>::type> operator()(F&& f) const {
|
||||
return {static_cast<F&&>(f)};
|
||||
}
|
||||
};
|
||||
|
||||
template <std::size_t ...n, typename F, typename ...G>
|
||||
struct lockstep_t<std::index_sequence<n...>, F, G...> {
|
||||
template <typename ...T>
|
||||
constexpr lockstep_t(make_pre_lockstep_t::secret, T&& ...t)
|
||||
: storage_{static_cast<T&&>(t)...}
|
||||
{ }
|
||||
|
||||
basic_tuple<F, G...> storage_;
|
||||
|
||||
template <typename ...X>
|
||||
constexpr decltype(auto) operator()(X&& ...x) const& {
|
||||
return hana::at_c<0>(storage_)(
|
||||
hana::at_c<n+1>(storage_)(static_cast<X&&>(x))...
|
||||
);
|
||||
}
|
||||
|
||||
template <typename ...X>
|
||||
constexpr decltype(auto) operator()(X&& ...x) & {
|
||||
return hana::at_c<0>(storage_)(
|
||||
hana::at_c<n+1>(storage_)(static_cast<X&&>(x))...
|
||||
);
|
||||
}
|
||||
|
||||
template <typename ...X>
|
||||
constexpr decltype(auto) operator()(X&& ...x) && {
|
||||
return static_cast<F&&>(hana::at_c<0>(storage_))(
|
||||
static_cast<G&&>(hana::at_c<n+1>(storage_))(static_cast<X&&>(x))...
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename F>
|
||||
struct pre_lockstep_t {
|
||||
F f;
|
||||
|
||||
template <typename ...G>
|
||||
constexpr lockstep_t<std::make_index_sequence<sizeof...(G)>, F,
|
||||
typename detail::decay<G>::type...>
|
||||
operator()(G&& ...g) const& {
|
||||
return {make_pre_lockstep_t::secret{}, this->f, static_cast<G&&>(g)...};
|
||||
}
|
||||
|
||||
template <typename ...G>
|
||||
constexpr lockstep_t<std::make_index_sequence<sizeof...(G)>, F,
|
||||
typename detail::decay<G>::type...>
|
||||
operator()(G&& ...g) && {
|
||||
return {make_pre_lockstep_t::secret{}, static_cast<F&&>(this->f),
|
||||
static_cast<G&&>(g)...};
|
||||
}
|
||||
};
|
||||
|
||||
constexpr make_pre_lockstep_t lockstep{};
|
||||
#endif
|
||||
BOOST_HANA_NAMESPACE_END
|
||||
|
||||
#endif // !BOOST_HANA_FUNCTIONAL_LOCKSTEP_HPP
|
||||
@@ -0,0 +1,83 @@
|
||||
/*!
|
||||
@file
|
||||
Defines `boost::hana::on`.
|
||||
|
||||
@copyright Louis Dionne 2013-2017
|
||||
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_ON_HPP
|
||||
#define BOOST_HANA_FUNCTIONAL_ON_HPP
|
||||
|
||||
#include <boost/hana/config.hpp>
|
||||
#include <boost/hana/detail/create.hpp>
|
||||
#include <boost/hana/functional/infix.hpp>
|
||||
|
||||
#include <utility>
|
||||
|
||||
|
||||
BOOST_HANA_NAMESPACE_BEGIN
|
||||
//! @ingroup group-functional
|
||||
//! Invoke a function with the result of invoking another function on
|
||||
//! each argument.
|
||||
//!
|
||||
//! Specifically, `on(f, g)` is a function such that
|
||||
//! @code
|
||||
//! on(f, g)(x...) == f(g(x)...)
|
||||
//! @endcode
|
||||
//!
|
||||
//! For convenience, `on` also supports infix application as provided
|
||||
//! by `infix`.
|
||||
//!
|
||||
//!
|
||||
//! @note
|
||||
//! `on` is associative, i.e. `on(f, on(g, h))` is equivalent to
|
||||
//! `on(on(f, g), h)`.
|
||||
//!
|
||||
//! @internal
|
||||
//! ### Proof of associativity
|
||||
//!
|
||||
//! @code
|
||||
//! on(f, on(g, h))(xs...) == f(on(g, h)(xs)...)
|
||||
//! == f(g(h(xs))...)
|
||||
//!
|
||||
//! on(on(f, g), h)(xs...) == on(f, g)(h(xs)...)
|
||||
//! == f(g(h(xs))...)
|
||||
//! @endcode
|
||||
//! @endinternal
|
||||
//!
|
||||
//!
|
||||
//! ### Example
|
||||
//! @include example/functional/on.cpp
|
||||
#ifdef BOOST_HANA_DOXYGEN_INVOKED
|
||||
constexpr auto on = infix([](auto&& f, auto&& g) {
|
||||
return [perfect-capture](auto&& ...x) -> decltype(auto) {
|
||||
return forwarded(f)(g(forwarded(x))...);
|
||||
};
|
||||
});
|
||||
#else
|
||||
template <typename F, typename G>
|
||||
struct on_t {
|
||||
F f; G g;
|
||||
template <typename ...X>
|
||||
constexpr decltype(auto) operator()(X&& ...x) const& {
|
||||
return f(g(static_cast<X&&>(x))...);
|
||||
}
|
||||
|
||||
template <typename ...X>
|
||||
constexpr decltype(auto) operator()(X&& ...x) & {
|
||||
return f(g(static_cast<X&&>(x))...);
|
||||
}
|
||||
|
||||
template <typename ...X>
|
||||
constexpr decltype(auto) operator()(X&& ...x) && {
|
||||
return std::move(f)(g(static_cast<X&&>(x))...);
|
||||
}
|
||||
};
|
||||
|
||||
constexpr auto on = infix(detail::create<on_t>{});
|
||||
#endif
|
||||
BOOST_HANA_NAMESPACE_END
|
||||
|
||||
#endif // !BOOST_HANA_FUNCTIONAL_ON_HPP
|
||||
@@ -0,0 +1,88 @@
|
||||
/*!
|
||||
@file
|
||||
Defines `boost::hana::overload`.
|
||||
|
||||
@copyright Louis Dionne 2013-2017
|
||||
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_OVERLOAD_HPP
|
||||
#define BOOST_HANA_FUNCTIONAL_OVERLOAD_HPP
|
||||
|
||||
#include <boost/hana/config.hpp>
|
||||
#include <boost/hana/detail/decay.hpp>
|
||||
|
||||
|
||||
BOOST_HANA_NAMESPACE_BEGIN
|
||||
//! @ingroup group-functional
|
||||
//! Pick one of several functions to call based on overload resolution.
|
||||
//!
|
||||
//! Specifically, `overload(f1, f2, ..., fn)` is a function object such
|
||||
//! that
|
||||
//! @code
|
||||
//! overload(f1, f2, ..., fn)(x...) == fk(x...)
|
||||
//! @endcode
|
||||
//!
|
||||
//! where `fk` is the function of `f1, ..., fn` that would be called if
|
||||
//! overload resolution was performed amongst that set of functions only.
|
||||
//! If more than one function `fk` would be picked by overload resolution,
|
||||
//! then the call is ambiguous.
|
||||
//!
|
||||
//! ### Example
|
||||
//! @include example/functional/overload.cpp
|
||||
#ifdef BOOST_HANA_DOXYGEN_INVOKED
|
||||
constexpr auto overload = [](auto&& f1, auto&& f2, ..., auto&& fn) {
|
||||
return [perfect-capture](auto&& ...x) -> decltype(auto) {
|
||||
return forwarded(fk)(forwarded(x)...);
|
||||
};
|
||||
};
|
||||
#else
|
||||
template <typename F, typename ...G>
|
||||
struct overload_t
|
||||
: overload_t<F>::type
|
||||
, overload_t<G...>::type
|
||||
{
|
||||
using type = overload_t;
|
||||
using overload_t<F>::type::operator();
|
||||
using overload_t<G...>::type::operator();
|
||||
|
||||
template <typename F_, typename ...G_>
|
||||
constexpr explicit overload_t(F_&& f, G_&& ...g)
|
||||
: overload_t<F>::type(static_cast<F_&&>(f))
|
||||
, overload_t<G...>::type(static_cast<G_&&>(g)...)
|
||||
{ }
|
||||
};
|
||||
|
||||
template <typename F>
|
||||
struct overload_t<F> { using type = F; };
|
||||
|
||||
template <typename R, typename ...Args>
|
||||
struct overload_t<R(*)(Args...)> {
|
||||
using type = overload_t;
|
||||
R (*fptr_)(Args...);
|
||||
|
||||
explicit constexpr overload_t(R (*fp)(Args...))
|
||||
: fptr_(fp)
|
||||
{ }
|
||||
|
||||
constexpr R operator()(Args ...args) const
|
||||
{ return fptr_(static_cast<Args&&>(args)...); }
|
||||
};
|
||||
|
||||
struct make_overload_t {
|
||||
template <typename ...F,
|
||||
typename Overload = typename overload_t<
|
||||
typename detail::decay<F>::type...
|
||||
>::type
|
||||
>
|
||||
constexpr Overload operator()(F&& ...f) const {
|
||||
return Overload(static_cast<F&&>(f)...);
|
||||
}
|
||||
};
|
||||
|
||||
constexpr make_overload_t overload{};
|
||||
#endif
|
||||
BOOST_HANA_NAMESPACE_END
|
||||
|
||||
#endif // !BOOST_HANA_FUNCTIONAL_OVERLOAD_HPP
|
||||
@@ -0,0 +1,110 @@
|
||||
/*!
|
||||
@file
|
||||
Defines `boost::hana::overload_linearly`.
|
||||
|
||||
@copyright Louis Dionne 2013-2017
|
||||
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_OVERLOAD_LINEARLY_HPP
|
||||
#define BOOST_HANA_FUNCTIONAL_OVERLOAD_LINEARLY_HPP
|
||||
|
||||
#include <boost/hana/config.hpp>
|
||||
#include <boost/hana/detail/decay.hpp>
|
||||
|
||||
#include <utility>
|
||||
|
||||
|
||||
BOOST_HANA_NAMESPACE_BEGIN
|
||||
//! @ingroup group-functional
|
||||
//! Call the first function that produces a valid call expression.
|
||||
//!
|
||||
//! Given functions `f1, ..., fn`, `overload_linearly(f1, ..., fn)` is
|
||||
//! a new function that calls the first `fk` producing a valid call
|
||||
//! expression with the given arguments. Specifically,
|
||||
//! @code
|
||||
//! overload_linearly(f1, ..., fn)(args...) == fk(args...)
|
||||
//! @endcode
|
||||
//!
|
||||
//! where `fk` is the _first_ function such that `fk(args...)` is a valid
|
||||
//! expression.
|
||||
//!
|
||||
//!
|
||||
//! Example
|
||||
//! -------
|
||||
//! @include example/functional/overload_linearly.cpp
|
||||
#ifdef BOOST_HANA_DOXYGEN_INVOKED
|
||||
constexpr auto overload_linearly = [](auto&& f1, auto&& f2, ..., auto&& fn) {
|
||||
return [perfect-capture](auto&& ...x) -> decltype(auto) {
|
||||
return forwarded(fk)(forwarded(x)...);
|
||||
};
|
||||
};
|
||||
#else
|
||||
template <typename F, typename G>
|
||||
struct overload_linearly_t {
|
||||
F f;
|
||||
G g;
|
||||
|
||||
private:
|
||||
template <typename ...Args, typename =
|
||||
decltype(std::declval<F const&>()(std::declval<Args>()...))>
|
||||
constexpr F const& which(int) const& { return f; }
|
||||
|
||||
template <typename ...Args, typename =
|
||||
decltype(std::declval<F&>()(std::declval<Args>()...))>
|
||||
constexpr F& which(int) & { return f; }
|
||||
|
||||
template <typename ...Args, typename =
|
||||
decltype(std::declval<F&&>()(std::declval<Args>()...))>
|
||||
constexpr F which(int) && { return static_cast<F&&>(f); }
|
||||
|
||||
template <typename ...Args>
|
||||
constexpr G const& which(long) const& { return g; }
|
||||
|
||||
template <typename ...Args>
|
||||
constexpr G& which(long) & { return g; }
|
||||
|
||||
template <typename ...Args>
|
||||
constexpr G which(long) && { return static_cast<G&&>(g); }
|
||||
|
||||
public:
|
||||
template <typename ...Args>
|
||||
constexpr decltype(auto) operator()(Args&& ...args) const&
|
||||
{ return which<Args...>(int{})(static_cast<Args&&>(args)...); }
|
||||
|
||||
template <typename ...Args>
|
||||
constexpr decltype(auto) operator()(Args&& ...args) &
|
||||
{ return which<Args...>(int{})(static_cast<Args&&>(args)...); }
|
||||
|
||||
template <typename ...Args>
|
||||
constexpr decltype(auto) operator()(Args&& ...args) &&
|
||||
{ return which<Args...>(int{})(static_cast<Args&&>(args)...); }
|
||||
};
|
||||
|
||||
struct make_overload_linearly_t {
|
||||
template <typename F, typename G>
|
||||
constexpr overload_linearly_t<
|
||||
typename detail::decay<F>::type,
|
||||
typename detail::decay<G>::type
|
||||
> operator()(F&& f, G&& g) const {
|
||||
return {static_cast<F&&>(f), static_cast<G&&>(g)};
|
||||
}
|
||||
|
||||
template <typename F, typename G, typename ...H>
|
||||
constexpr decltype(auto) operator()(F&& f, G&& g, H&& ...h) const {
|
||||
return (*this)(static_cast<F&&>(f),
|
||||
(*this)(static_cast<G&&>(g), static_cast<H&&>(h)...));
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
constexpr typename detail::decay<F>::type operator()(F&& f) const {
|
||||
return static_cast<F&&>(f);
|
||||
}
|
||||
};
|
||||
|
||||
constexpr make_overload_linearly_t overload_linearly{};
|
||||
#endif
|
||||
BOOST_HANA_NAMESPACE_END
|
||||
|
||||
#endif // !BOOST_HANA_FUNCTIONAL_OVERLOAD_LINEARLY_HPP
|
||||
@@ -0,0 +1,105 @@
|
||||
/*!
|
||||
@file
|
||||
Defines `boost::hana::partial`.
|
||||
|
||||
@copyright Louis Dionne 2013-2017
|
||||
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_PARTIAL_HPP
|
||||
#define BOOST_HANA_FUNCTIONAL_PARTIAL_HPP
|
||||
|
||||
#include <boost/hana/basic_tuple.hpp>
|
||||
#include <boost/hana/config.hpp>
|
||||
#include <boost/hana/detail/decay.hpp>
|
||||
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
|
||||
|
||||
BOOST_HANA_NAMESPACE_BEGIN
|
||||
//! @ingroup group-functional
|
||||
//! Partially apply a function to some arguments.
|
||||
//!
|
||||
//! Given a function `f` and some arguments, `partial` returns a new
|
||||
//! function corresponding to the partially applied function `f`. This
|
||||
//! allows providing some arguments to a function and letting the rest
|
||||
//! of the arguments be provided later. Specifically, `partial(f, x...)`
|
||||
//! is a function such that
|
||||
//! @code
|
||||
//! partial(f, x...)(y...) == f(x..., y...)
|
||||
//! @endcode
|
||||
//!
|
||||
//! @note
|
||||
//! The arity of `f` must match the total number of arguments passed to
|
||||
//! it, i.e. `sizeof...(x) + sizeof...(y)`.
|
||||
//!
|
||||
//!
|
||||
//! Example
|
||||
//! -------
|
||||
//! @include example/functional/partial.cpp
|
||||
#ifdef BOOST_HANA_DOXYGEN_INVOKED
|
||||
constexpr auto partial = [](auto&& f, auto&& ...x) {
|
||||
return [perfect-capture](auto&& ...y) -> decltype(auto) {
|
||||
return forwarded(f)(forwarded(x)..., forwarded(y)...);
|
||||
};
|
||||
};
|
||||
#else
|
||||
template <typename Indices, typename F, typename ...X>
|
||||
struct partial_t;
|
||||
|
||||
struct make_partial_t {
|
||||
struct secret { };
|
||||
template <typename F, typename ...X>
|
||||
constexpr partial_t<
|
||||
std::make_index_sequence<sizeof...(X)>,
|
||||
typename detail::decay<F>::type,
|
||||
typename detail::decay<X>::type...
|
||||
>
|
||||
operator()(F&& f, X&& ...x) const {
|
||||
return {secret{}, static_cast<F&&>(f), static_cast<X&&>(x)...};
|
||||
}
|
||||
};
|
||||
|
||||
template <std::size_t ...n, typename F, typename ...X>
|
||||
struct partial_t<std::index_sequence<n...>, F, X...> {
|
||||
partial_t() = default;
|
||||
|
||||
template <typename ...T>
|
||||
constexpr partial_t(make_partial_t::secret, T&& ...t)
|
||||
: storage_{static_cast<T&&>(t)...}
|
||||
{ }
|
||||
|
||||
basic_tuple<F, X...> storage_;
|
||||
|
||||
template <typename ...Y>
|
||||
constexpr decltype(auto) operator()(Y&& ...y) const& {
|
||||
return hana::at_c<0>(storage_)(
|
||||
hana::at_c<n+1>(storage_)...,
|
||||
static_cast<Y&&>(y)...
|
||||
);
|
||||
}
|
||||
|
||||
template <typename ...Y>
|
||||
constexpr decltype(auto) operator()(Y&& ...y) & {
|
||||
return hana::at_c<0>(storage_)(
|
||||
hana::at_c<n+1>(storage_)...,
|
||||
static_cast<Y&&>(y)...
|
||||
);
|
||||
}
|
||||
|
||||
template <typename ...Y>
|
||||
constexpr decltype(auto) operator()(Y&& ...y) && {
|
||||
return static_cast<F&&>(hana::at_c<0>(storage_))(
|
||||
static_cast<X&&>(hana::at_c<n+1>(storage_))...,
|
||||
static_cast<Y&&>(y)...
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
constexpr make_partial_t partial{};
|
||||
#endif
|
||||
BOOST_HANA_NAMESPACE_END
|
||||
|
||||
#endif // !BOOST_HANA_FUNCTIONAL_PARTIAL_HPP
|
||||
@@ -0,0 +1,263 @@
|
||||
/*!
|
||||
@file
|
||||
Defines `boost::hana::_`.
|
||||
|
||||
@copyright Louis Dionne 2013-2017
|
||||
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_PLACEHOLDER_HPP
|
||||
#define BOOST_HANA_FUNCTIONAL_PLACEHOLDER_HPP
|
||||
|
||||
#include <boost/hana/basic_tuple.hpp>
|
||||
#include <boost/hana/config.hpp>
|
||||
#include <boost/hana/detail/create.hpp>
|
||||
#include <boost/hana/detail/decay.hpp>
|
||||
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
|
||||
|
||||
BOOST_HANA_NAMESPACE_BEGIN
|
||||
//! @ingroup group-functional
|
||||
//! Create simple functions representing C++ operators inline.
|
||||
//!
|
||||
//! Specifically, `_` is an object used as a placeholder to build
|
||||
//! function objects representing calls to C++ operators. It works
|
||||
//! by overloading the operators between `_` and any object so that
|
||||
//! they return a function object which actually calls the corresponding
|
||||
//! operator on its argument(s). Hence, for any supported operator `@`:
|
||||
//! @code
|
||||
//! (_ @ _)(x, y) == x @ y
|
||||
//! @endcode
|
||||
//!
|
||||
//! Operators may also be partially applied to one argument inline:
|
||||
//! @code
|
||||
//! (x @ _)(y) == x @ y
|
||||
//! (_ @ y)(x) == x @ y
|
||||
//! @endcode
|
||||
//!
|
||||
//! When invoked with more arguments than required, functions created with
|
||||
//! `_` will discard the superfluous instead of triggering an error:
|
||||
//! @code
|
||||
//! (_ @ _)(x, y, z...) == x @ y
|
||||
//! @endcode
|
||||
//!
|
||||
//! This makes functions created with `_` easier to use in higher-order
|
||||
//! algorithms, which sometime provide more information than necessary
|
||||
//! to their callbacks.
|
||||
//!
|
||||
//! ### Supported operators
|
||||
//! - Arithmetic: binary `+`, binary `-`, `/`, `*`, `%`, unary `+`, unary `-`
|
||||
//! - Bitwise: `~`, `&`, `|`, `^`, `<<`, `>>`
|
||||
//! - Comparison: `==`, `!=`, `<`, `<=`, `>`, `>=`
|
||||
//! - %Logical: `||`, `&&`, `!`
|
||||
//! - Member access: `*` (dereference), `[]` (array subscript)
|
||||
//! - Other: `()` (function call)
|
||||
//!
|
||||
//! More complex functionality like the ability to compose placeholders
|
||||
//! into larger function objects inline are not supported. This is on
|
||||
//! purpose; you should either use C++14 generic lambdas or a library
|
||||
//! like [Boost.Phoenix][] if you need bigger guns. The goal here is
|
||||
//! to save you a couple of characters in simple situations.
|
||||
//!
|
||||
//! ### Example
|
||||
//! @include example/functional/placeholder.cpp
|
||||
//!
|
||||
//! [Boost.Phoenix]: http://www.boost.org/doc/libs/release/libs/phoenix/doc/html/index.html
|
||||
#ifdef BOOST_HANA_DOXYGEN_INVOKED
|
||||
constexpr unspecified _{};
|
||||
#else
|
||||
namespace placeholder_detail {
|
||||
template <typename I>
|
||||
struct subscript {
|
||||
I i;
|
||||
|
||||
template <typename Xs, typename ...Z>
|
||||
constexpr auto operator()(Xs&& xs, Z const& ...) const&
|
||||
-> decltype(static_cast<Xs&&>(xs)[i])
|
||||
{ return static_cast<Xs&&>(xs)[i]; }
|
||||
|
||||
template <typename Xs, typename ...Z>
|
||||
constexpr auto operator()(Xs&& xs, Z const& ...) &
|
||||
-> decltype(static_cast<Xs&&>(xs)[i])
|
||||
{ return static_cast<Xs&&>(xs)[i]; }
|
||||
|
||||
template <typename Xs, typename ...Z>
|
||||
constexpr auto operator()(Xs&& xs, Z const& ...) &&
|
||||
-> decltype(static_cast<Xs&&>(xs)[std::declval<I>()])
|
||||
{ return static_cast<Xs&&>(xs)[std::move(i)]; }
|
||||
};
|
||||
|
||||
template <typename F, typename Xs, std::size_t ...i>
|
||||
constexpr decltype(auto) invoke_impl(F&& f, Xs&& xs, std::index_sequence<i...>) {
|
||||
return static_cast<F&&>(f)(hana::at_c<i>(static_cast<Xs&&>(xs).storage_)...);
|
||||
}
|
||||
|
||||
template <typename ...X>
|
||||
struct invoke;
|
||||
|
||||
struct placeholder {
|
||||
struct secret { };
|
||||
|
||||
template <typename X>
|
||||
constexpr decltype(auto) operator[](X&& x) const
|
||||
{ return detail::create<subscript>{}(static_cast<X&&>(x)); }
|
||||
|
||||
template <typename ...X>
|
||||
constexpr invoke<typename detail::decay<X>::type...>
|
||||
operator()(X&& ...x) const {
|
||||
return {secret{}, static_cast<X&&>(x)...};
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ...X>
|
||||
struct invoke {
|
||||
template <typename ...Y>
|
||||
constexpr invoke(placeholder::secret, Y&& ...y)
|
||||
: storage_{static_cast<Y&&>(y)...}
|
||||
{ }
|
||||
|
||||
basic_tuple<X...> storage_;
|
||||
|
||||
template <typename F, typename ...Z>
|
||||
constexpr auto operator()(F&& f, Z const& ...) const& -> decltype(
|
||||
static_cast<F&&>(f)(std::declval<X const&>()...)
|
||||
) {
|
||||
return invoke_impl(static_cast<F&&>(f), *this,
|
||||
std::make_index_sequence<sizeof...(X)>{});
|
||||
}
|
||||
|
||||
template <typename F, typename ...Z>
|
||||
constexpr auto operator()(F&& f, Z const& ...) & -> decltype(
|
||||
static_cast<F&&>(f)(std::declval<X&>()...)
|
||||
) {
|
||||
return invoke_impl(static_cast<F&&>(f), *this,
|
||||
std::make_index_sequence<sizeof...(X)>{});
|
||||
}
|
||||
|
||||
template <typename F, typename ...Z>
|
||||
constexpr auto operator()(F&& f, Z const& ...) && -> decltype(
|
||||
static_cast<F&&>(f)(std::declval<X&&>()...)
|
||||
) {
|
||||
return invoke_impl(static_cast<F&&>(f), static_cast<invoke&&>(*this),
|
||||
std::make_index_sequence<sizeof...(X)>{});
|
||||
}
|
||||
};
|
||||
|
||||
#define BOOST_HANA_PLACEHOLDER_BINARY_OP(op, op_name) \
|
||||
template <typename X> \
|
||||
struct op_name ## _left { \
|
||||
X x; \
|
||||
\
|
||||
template <typename Y, typename ...Z> \
|
||||
constexpr auto operator()(Y&& y, Z const& ...) const& -> decltype( \
|
||||
std::declval<X const&>() op static_cast<Y&&>(y)) \
|
||||
{ return x op static_cast<Y&&>(y); } \
|
||||
\
|
||||
template <typename Y, typename ...Z> \
|
||||
constexpr auto operator()(Y&& y, Z const& ...) & -> decltype( \
|
||||
std::declval<X&>() op static_cast<Y&&>(y)) \
|
||||
{ return x op static_cast<Y&&>(y); } \
|
||||
\
|
||||
template <typename Y, typename ...Z> \
|
||||
constexpr auto operator()(Y&& y, Z const& ...) && -> decltype( \
|
||||
std::declval<X>() op static_cast<Y&&>(y)) \
|
||||
{ return std::move(x) op static_cast<Y&&>(y); } \
|
||||
}; \
|
||||
\
|
||||
template <typename Y> \
|
||||
struct op_name ## _right { \
|
||||
Y y; \
|
||||
\
|
||||
template <typename X, typename ...Z> \
|
||||
constexpr auto operator()(X&& x, Z const& ...) const& -> decltype( \
|
||||
static_cast<X&&>(x) op std::declval<Y const&>()) \
|
||||
{ return static_cast<X&&>(x) op y; } \
|
||||
\
|
||||
template <typename X, typename ...Z> \
|
||||
constexpr auto operator()(X&& x, Z const& ...) & -> decltype( \
|
||||
static_cast<X&&>(x) op std::declval<Y&>()) \
|
||||
{ return static_cast<X&&>(x) op y; } \
|
||||
\
|
||||
template <typename X, typename ...Z> \
|
||||
constexpr auto operator()(X&& x, Z const& ...) && -> decltype( \
|
||||
static_cast<X&&>(x) op std::declval<Y>()) \
|
||||
{ return static_cast<X&&>(x) op std::move(y); } \
|
||||
}; \
|
||||
\
|
||||
struct op_name { \
|
||||
template <typename X, typename Y, typename ...Z> \
|
||||
constexpr auto operator()(X&& x, Y&& y, Z const& ...) const -> decltype(\
|
||||
static_cast<X&&>(x) op static_cast<Y&&>(y)) \
|
||||
{ return static_cast<X&&>(x) op static_cast<Y&&>(y); } \
|
||||
}; \
|
||||
\
|
||||
template <typename X> \
|
||||
constexpr decltype(auto) operator op (X&& x, placeholder) \
|
||||
{ return detail::create<op_name ## _left>{}(static_cast<X&&>(x)); } \
|
||||
\
|
||||
template <typename Y> \
|
||||
constexpr decltype(auto) operator op (placeholder, Y&& y) \
|
||||
{ return detail::create<op_name ## _right>{}(static_cast<Y&&>(y)); } \
|
||||
\
|
||||
inline constexpr decltype(auto) operator op (placeholder, placeholder) \
|
||||
{ return op_name{}; } \
|
||||
/**/
|
||||
|
||||
#define BOOST_HANA_PLACEHOLDER_UNARY_OP(op, op_name) \
|
||||
struct op_name { \
|
||||
template <typename X, typename ...Z> \
|
||||
constexpr auto operator()(X&& x, Z const& ...) const \
|
||||
-> decltype(op static_cast<X&&>(x)) \
|
||||
{ return op static_cast<X&&>(x); } \
|
||||
}; \
|
||||
\
|
||||
inline constexpr decltype(auto) operator op (placeholder) \
|
||||
{ return op_name{}; } \
|
||||
/**/
|
||||
// Arithmetic
|
||||
BOOST_HANA_PLACEHOLDER_UNARY_OP(+, unary_plus)
|
||||
BOOST_HANA_PLACEHOLDER_UNARY_OP(-, unary_minus)
|
||||
BOOST_HANA_PLACEHOLDER_BINARY_OP(+, plus)
|
||||
BOOST_HANA_PLACEHOLDER_BINARY_OP(-, minus)
|
||||
BOOST_HANA_PLACEHOLDER_BINARY_OP(*, times)
|
||||
BOOST_HANA_PLACEHOLDER_BINARY_OP(/, divide)
|
||||
BOOST_HANA_PLACEHOLDER_BINARY_OP(%, modulo)
|
||||
|
||||
// Bitwise
|
||||
BOOST_HANA_PLACEHOLDER_UNARY_OP(~, bitwise_not)
|
||||
BOOST_HANA_PLACEHOLDER_BINARY_OP(&, bitwise_and)
|
||||
BOOST_HANA_PLACEHOLDER_BINARY_OP(|, bitwise_or)
|
||||
BOOST_HANA_PLACEHOLDER_BINARY_OP(^, bitwise_xor)
|
||||
BOOST_HANA_PLACEHOLDER_BINARY_OP(<<, left_shift)
|
||||
BOOST_HANA_PLACEHOLDER_BINARY_OP(>>, right_shift)
|
||||
|
||||
// Comparison
|
||||
BOOST_HANA_PLACEHOLDER_BINARY_OP(==, equal)
|
||||
BOOST_HANA_PLACEHOLDER_BINARY_OP(!=, not_equal)
|
||||
BOOST_HANA_PLACEHOLDER_BINARY_OP(<, less)
|
||||
BOOST_HANA_PLACEHOLDER_BINARY_OP(<=, less_equal)
|
||||
BOOST_HANA_PLACEHOLDER_BINARY_OP(>, greater)
|
||||
BOOST_HANA_PLACEHOLDER_BINARY_OP(>=, greater_equal)
|
||||
|
||||
// Logical
|
||||
BOOST_HANA_PLACEHOLDER_BINARY_OP(||, logical_or)
|
||||
BOOST_HANA_PLACEHOLDER_BINARY_OP(&&, logical_and)
|
||||
BOOST_HANA_PLACEHOLDER_UNARY_OP(!, logical_not)
|
||||
|
||||
// Member access (array subscript is a member function)
|
||||
BOOST_HANA_PLACEHOLDER_UNARY_OP(*, dereference)
|
||||
|
||||
// Other (function call is a member function)
|
||||
|
||||
#undef BOOST_HANA_PREFIX_PLACEHOLDER_OP
|
||||
#undef BOOST_HANA_BINARY_PLACEHOLDER_OP
|
||||
} // end namespace placeholder_detail
|
||||
|
||||
constexpr placeholder_detail::placeholder _{};
|
||||
#endif
|
||||
BOOST_HANA_NAMESPACE_END
|
||||
|
||||
#endif // !BOOST_HANA_FUNCTIONAL_PLACEHOLDER_HPP
|
||||
@@ -0,0 +1,103 @@
|
||||
/*!
|
||||
@file
|
||||
Defines `boost::hana::reverse_partial`.
|
||||
|
||||
@copyright Louis Dionne 2013-2017
|
||||
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_REVERSE_PARTIAL_HPP
|
||||
#define BOOST_HANA_FUNCTIONAL_REVERSE_PARTIAL_HPP
|
||||
|
||||
#include <boost/hana/basic_tuple.hpp>
|
||||
#include <boost/hana/config.hpp>
|
||||
#include <boost/hana/detail/decay.hpp>
|
||||
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
|
||||
|
||||
BOOST_HANA_NAMESPACE_BEGIN
|
||||
//! @ingroup group-functional
|
||||
//! Partially apply a function to some arguments.
|
||||
//!
|
||||
//! Given a function `f` and some arguments, `reverse_partial` returns a
|
||||
//! new function corresponding to `f` whose last arguments are partially
|
||||
//! applied. Specifically, `reverse_partial(f, x...)` is a function such
|
||||
//! that
|
||||
//! @code
|
||||
//! reverse_partial(f, x...)(y...) == f(y..., x...)
|
||||
//! @endcode
|
||||
//!
|
||||
//! @note
|
||||
//! The arity of `f` must match the total number of arguments passed to
|
||||
//! it, i.e. `sizeof...(x) + sizeof...(y)`.
|
||||
//!
|
||||
//!
|
||||
//! Example
|
||||
//! -------
|
||||
//! @include example/functional/reverse_partial.cpp
|
||||
#ifdef BOOST_HANA_DOXYGEN_INVOKED
|
||||
constexpr auto reverse_partial = [](auto&& f, auto&& ...x) {
|
||||
return [perfect-capture](auto&& ...y) -> decltype(auto) {
|
||||
return forwarded(f)(forwarded(y)..., forwarded(x)...);
|
||||
};
|
||||
};
|
||||
#else
|
||||
template <typename Indices, typename F, typename ...X>
|
||||
struct reverse_partial_t;
|
||||
|
||||
struct make_reverse_partial_t {
|
||||
struct secret { };
|
||||
template <typename F, typename ...X>
|
||||
constexpr reverse_partial_t<
|
||||
std::make_index_sequence<sizeof...(X)>,
|
||||
typename detail::decay<F>::type,
|
||||
typename detail::decay<X>::type...
|
||||
> operator()(F&& f, X&& ...x) const {
|
||||
return {secret{}, static_cast<F&&>(f), static_cast<X&&>(x)...};
|
||||
}
|
||||
};
|
||||
|
||||
template <std::size_t ...n, typename F, typename ...X>
|
||||
struct reverse_partial_t<std::index_sequence<n...>, F, X...> {
|
||||
reverse_partial_t() = default;
|
||||
|
||||
template <typename ...T>
|
||||
constexpr reverse_partial_t(make_reverse_partial_t::secret, T&& ...t)
|
||||
: storage_{static_cast<T&&>(t)...}
|
||||
{ }
|
||||
|
||||
basic_tuple<F, X...> storage_;
|
||||
|
||||
template <typename ...Y>
|
||||
constexpr decltype(auto) operator()(Y&& ...y) const& {
|
||||
return hana::at_c<0>(storage_)(
|
||||
static_cast<Y&&>(y)...,
|
||||
hana::at_c<n+1>(storage_)...
|
||||
);
|
||||
}
|
||||
|
||||
template <typename ...Y>
|
||||
constexpr decltype(auto) operator()(Y&& ...y) & {
|
||||
return hana::at_c<0>(storage_)(
|
||||
static_cast<Y&&>(y)...,
|
||||
hana::at_c<n+1>(storage_)...
|
||||
);
|
||||
}
|
||||
|
||||
template <typename ...Y>
|
||||
constexpr decltype(auto) operator()(Y&& ...y) && {
|
||||
return static_cast<F&&>(hana::at_c<0>(storage_))(
|
||||
static_cast<Y&&>(y)...,
|
||||
static_cast<X&&>(hana::at_c<n+1>(storage_))...
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
constexpr make_reverse_partial_t reverse_partial{};
|
||||
#endif
|
||||
BOOST_HANA_NAMESPACE_END
|
||||
|
||||
#endif // !BOOST_HANA_FUNCTIONAL_REVERSE_PARTIAL_HPP
|
||||
Reference in New Issue
Block a user