stabilize build system: depends, installer, boost/bdb fixes, cross targets groundwork

This commit is contained in:
2026-02-24 18:38:47 +00:00
parent da8c28aaeb
commit 65cb2619a7
13106 changed files with 2484322 additions and 1804 deletions
@@ -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