Edit: /usr/include/boost/yap/algorithm.hpp (25305B)
// Copyright (C) 2016-2018 T. Zachary Laine
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_YAP_ALGORITHM_HPP_INCLUDED
#define BOOST_YAP_ALGORITHM_HPP_INCLUDED
#include
#include
#include
#include
#include
namespace boost { namespace yap {
#ifdef BOOST_NO_CONSTEXPR_IF
namespace detail {
template
struct deref_impl
{
constexpr decltype(auto) operator()(Expr && expr)
{
return std::move(*expr.elements[hana::llong_c<0>]);
}
};
template
struct deref_impl
{
constexpr decltype(auto) operator()(Expr && expr)
{
return *expr.elements[hana::llong_c<0>];
}
};
}
#endif
/** "Dereferences" a reference-expression, forwarding its referent to
the caller. */
template
constexpr decltype(auto) deref(Expr && expr)
{
static_assert(
is_expr::value, "deref() is only defined for expressions.");
static_assert(
detail::remove_cv_ref_t::kind == expr_kind::expr_ref,
"deref() is only defined for expr_ref-kind expressions.");
#ifdef BOOST_NO_CONSTEXPR_IF
return detail::deref_impl < Expr,
std::is_rvalue_reference::value &&
!std::is_const>::value >
{}(static_cast(expr));
#else
using namespace hana::literals;
if constexpr (
std::is_rvalue_reference::value &&
!std::is_const>::value) {
return std::move(*expr.elements[0_c]);
} else {
return *expr.elements[0_c];
}
#endif
}
namespace detail {
template
struct lvalue_ref_ith_element
: std::is_lvalue_reference()[hana::llong{}])>
{
};
#ifdef BOOST_NO_CONSTEXPR_IF
template
constexpr decltype(auto) value_impl(T && x);
template<
typename T,
bool IsExprRef,
bool ValueOfTerminalsOnly,
bool TakeValue,
bool IsLvalueRef>
struct value_expr_impl;
template<
typename T,
bool ValueOfTerminalsOnly,
bool TakeValue,
bool IsLvalueRef>
struct value_expr_impl<
T,
true,
ValueOfTerminalsOnly,
TakeValue,
IsLvalueRef>
{
constexpr decltype(auto) operator()(T && x)
{
return ::boost::yap::detail::value_impl(
::boost::yap::deref(static_cast(x)));
}
};
template
struct value_expr_impl
{
constexpr decltype(auto) operator()(T && x)
{
return x.elements[hana::llong_c<0>];
}
};
template
struct value_expr_impl
{
constexpr decltype(auto) operator()(T && x)
{
return std::move(x.elements[hana::llong_c<0>]);
}
};
template
struct value_expr_impl<
T,
false,
ValueOfTerminalsOnly,
false,
IsLvalueRef>
{
constexpr decltype(auto) operator()(T && x)
{
return static_cast(x);
}
};
template
struct value_impl_t
{
constexpr decltype(auto) operator()(T && x)
{
constexpr expr_kind kind = detail::remove_cv_ref_t::kind;
constexpr detail::expr_arity arity = detail::arity_of();
return value_expr_impl < T, kind == expr_kind::expr_ref,
ValueOfTerminalsOnly,
(ValueOfTerminalsOnly && kind == expr_kind::terminal) ||
(!ValueOfTerminalsOnly &&
arity == detail::expr_arity::one),
std::is_lvalue_reference::value ||
detail::lvalue_ref_ith_element<
decltype(x.elements),
0>::value > {}(static_cast(x));
}
};
template
struct value_impl_t
{
constexpr decltype(auto) operator()(T && x)
{
return static_cast(x);
}
};
template
constexpr decltype(auto) value_impl(T && x)
{
return detail::
value_impl_t::value, ValueOfTerminalsOnly>{}(
static_cast(x));
}
#else
template
constexpr decltype(auto) value_impl(T && x)
{
if constexpr (is_expr::value) {
using namespace hana::literals;
constexpr expr_kind kind = remove_cv_ref_t::kind;
constexpr expr_arity arity = arity_of();
if constexpr (kind == expr_kind::expr_ref) {
return value_impl(
::boost::yap::deref(static_cast(x)));
} else if constexpr (
kind == expr_kind::terminal ||
(!ValueOfTerminalsOnly && arity == expr_arity::one)) {
if constexpr (
std::is_lvalue_reference::value ||
detail::
lvalue_ref_ith_element{}) {
return x.elements[0_c];
} else {
return std::move(x.elements[0_c]);
}
} else {
return static_cast(x);
}
} else {
return static_cast(x);
}
}
#endif
}
/** Forwards the sole element of \a x to the caller, possibly calling
deref() first if \a x is a reference expression, or
forwards \a x to the caller unchanged.
More formally:
- If \a x is not an expression, \a x is forwarded to the caller.
- Otherwise, if \a x is a reference expression, the result is
value(deref(x)).
- Otherwise, if \a x is an expression with only one value (a unary
expression or a terminal expression), the result is the forwarded
first element of \a x.
- Otherwise, \a x is forwarded to the caller. */
template
constexpr decltype(auto) value(T && x)
{
return detail::value_impl(static_cast(x));
}
#ifdef BOOST_NO_CONSTEXPR_IF
template
constexpr decltype(auto) get(Expr && expr, I const & i);
namespace detail {
template
struct get_impl;
template
struct get_impl
{
constexpr decltype(auto) operator()(Expr && expr, hana::llong i)
{
return ::boost::yap::get(
::boost::yap::deref(static_cast(expr)), i);
}
};
template
struct get_impl
{
constexpr decltype(auto) operator()(Expr && expr, hana::llong i)
{
return expr.elements[i];
}
};
template
struct get_impl
{
constexpr decltype(auto) operator()(Expr && expr, hana::llong i)
{
return std::move(expr.elements[i]);
}
};
}
#endif
/** Forwards the i-th element of \a expr to the caller. If \a
expr is a reference expression, the result is get(deref(expr),
i).
\note get() is only valid if \a Expr is an expression.
*/
template
constexpr decltype(auto) get(Expr && expr, I const & i)
{
static_assert(
is_expr::value, "get() is only defined for expressions.");
static_assert(
hana::IntegralConstant::value,
"'i' must be an IntegralConstant");
constexpr expr_kind kind = detail::remove_cv_ref_t::kind;
static_assert(
kind == expr_kind::expr_ref ||
(0 <= I::value &&
I::value < decltype(hana::size(expr.elements))::value),
"In get(expr, I), I must be a valid index into expr's tuple "
"elements.");
#ifdef BOOST_NO_CONSTEXPR_IF
return detail::get_impl<
I::value,
Expr,
kind == expr_kind::expr_ref,
std::is_lvalue_reference::value>{}(static_cast(expr), i);
#else
using namespace hana::literals;
if constexpr (kind == expr_kind::expr_ref) {
return ::boost::yap::get(
::boost::yap::deref(static_cast(expr)), i);
} else {
if constexpr (std::is_lvalue_reference::value) {
return expr.elements[i];
} else {
return std::move(expr.elements[i]);
}
}
#endif
}
/** Returns get(expr, boost::hana::llong_c). */
template
constexpr decltype(auto) get_c(Expr && expr)
{
return ::boost::yap::get(static_cast(expr), hana::llong_c);
}
/** Returns the left operand in a binary operator expression.
Equivalent to get(expr, 0_c).
\note left() is only valid if \a Expr is a binary
operator expression.
*/
template
constexpr decltype(auto) left(Expr && expr)
{
using namespace hana::literals;
return ::boost::yap::get(static_cast(expr), 0_c);
constexpr expr_kind kind = detail::remove_cv_ref_t::kind;
static_assert(
kind == expr_kind::expr_ref ||
detail::arity_of() == detail::expr_arity::two,
"left() is only defined for binary expressions.");
}
/** Returns the right operand in a binary operator expression.
Equivalent to get(expr, 1_c).
\note right() is only valid if \a Expr is a binary
operator expression.
*/
template
constexpr decltype(auto) right(Expr && expr)
{
using namespace hana::literals;
return ::boost::yap::get(static_cast(expr), 1_c);
constexpr expr_kind kind = detail::remove_cv_ref_t::kind;
static_assert(
kind == expr_kind::expr_ref ||
detail::arity_of() == detail::expr_arity::two,
"right() is only defined for binary expressions.");
}
/** Returns the condition expression in an if_else expression.
Equivalent to get(expr, 0_c).
\note cond() is only valid if \a Expr is an
expr_kind::if_else expression.
*/
template
constexpr decltype(auto) cond(Expr && expr)
{
using namespace hana::literals;
return ::boost::yap::get(static_cast(expr), 0_c);
constexpr expr_kind kind = detail::remove_cv_ref_t::kind;
static_assert(
kind == expr_kind::expr_ref || kind == expr_kind::if_else,
"cond() is only defined for if_else expressions.");
}
/** Returns the then-expression in an if_else expression.
Equivalent to get(expr, 1_c).
\note then() is only valid if \a Expr is an
expr_kind::if_else expression.
*/
template
constexpr decltype(auto) then(Expr && expr)
{
using namespace hana::literals;
return ::boost::yap::get(static_cast(expr), 1_c);
constexpr expr_kind kind = detail::remove_cv_ref_t::kind;
static_assert(
kind == expr_kind::expr_ref || kind == expr_kind::if_else,
"then() is only defined for if_else expressions.");
}
/** Returns the else-expression in an if_else expression.
Equivalent to get(expr, 2_c).
\note else_() is only valid if \a Expr is an
expr_kind::if_else expression.
*/
template
constexpr decltype(auto) else_(Expr && expr)
{
using namespace hana::literals;
return ::boost::yap::get(static_cast(expr), 2_c);
constexpr expr_kind kind = detail::remove_cv_ref_t::kind;
static_assert(
kind == expr_kind::expr_ref || kind == expr_kind::if_else,
"else_() is only defined for if_else expressions.");
}
/** Returns the callable in a call expression.
Equivalent to get(expr, 0).
\note callable() is only valid if \a Expr is an
expr_kind::call expression.
*/
template
constexpr decltype(auto) callable(Expr && expr)
{
return ::boost::yap::get(static_cast(expr), hana::llong_c<0>);
constexpr expr_kind kind = detail::remove_cv_ref_t::kind;
static_assert(
kind == expr_kind::expr_ref ||
detail::arity_of() == detail::expr_arity::n,
"callable() is only defined for call expressions.");
}
/** Returns the i-th argument expression in a call expression.
Equivalent to get(expr, i + 1).
\note argument() is only valid if \a Expr is an
expr_kind::call expression.
*/
template
constexpr decltype(auto) argument(Expr && expr, hana::llong i)
{
return ::boost::yap::get(
static_cast(expr), hana::llong_c);
constexpr expr_kind kind = detail::remove_cv_ref_t::kind;
static_assert(
kind == expr_kind::expr_ref ||
detail::arity_of() == detail::expr_arity::n,
"argument() is only defined for call expressions.");
static_assert(
kind == expr_kind::expr_ref ||
(0 <= I && I < decltype(hana::size(expr.elements))::value - 1),
"I must be a valid call-expression argument index.");
}
/** Makes a new expression instantiated from the expression template \a
ExprTemplate, of kind \a Kind, with the given values as its
elements.
For each parameter P:
- If P is an expression, P is moved into the result if P is an
rvalue and captured by reference into the result otherwise.
- Otherwise, P is wrapped in a terminal expression.
\note make_expression() is only valid if the number of
parameters passed is appropriate for \a Kind.
*/
template<
template class ExprTemplate,
expr_kind Kind,
typename... T>
constexpr auto make_expression(T &&... t)
{
constexpr detail::expr_arity arity = detail::arity_of();
static_assert(
(arity == detail::expr_arity::one && sizeof...(T) == 1) ||
(arity == detail::expr_arity::two && sizeof...(T) == 2) ||
(arity == detail::expr_arity::three && sizeof...(T) == 3) ||
arity == detail::expr_arity::n,
"The number of parameters passed to make_expression() must "
"match the arity "
"implied by the expr_kind template parameter.");
using tuple_type =
hana::tuple...>;
return ExprTemplate{tuple_type{
detail::make_operand>{}(
static_cast(t))...}};
}
/** Makes a new terminal expression instantiated from the expression
template \a ExprTemplate, with the given value as its sole element.
\note make_terminal() is only valid if \a T is \b not
an expression.
*/
template class ExprTemplate, typename T>
constexpr auto make_terminal(T && t)
{
static_assert(
!is_expr::value,
"make_terminal() is only defined for non expressions.");
using result_type = detail::operand_type_t;
using tuple_type = decltype(std::declval().elements);
return result_type{tuple_type{static_cast(t)}};
}
#ifdef BOOST_NO_CONSTEXPR_IF
namespace detail {
template<
template class ExprTemplate,
typename T,
bool IsExpr>
struct as_expr_impl
{
constexpr decltype(auto) operator()(T && t)
{
return static_cast(t);
}
};
template class ExprTemplate, typename T>
struct as_expr_impl
{
constexpr decltype(auto) operator()(T && t)
{
return make_terminal(static_cast(t));
}
};
}
#endif
/** Returns an expression formed from \a t as follows:
- If \a t is an expression, \a t is forwarded to the caller.
- Otherwise, \a t is wrapped in a terminal expression.
*/
template class ExprTemplate, typename T>
constexpr decltype(auto) as_expr(T && t)
{
#ifdef BOOST_NO_CONSTEXPR_IF
return detail::as_expr_impl::value>{}(
static_cast(t));
#else
if constexpr (is_expr::value) {
return static_cast(t);
} else {
return make_terminal(static_cast(t));
}
#endif
}
/** A callable type that evaluates its contained expression when called.
\see make_expression_function()
*/
template
struct expression_function
{
template
constexpr decltype(auto) operator()(U &&... u)
{
return ::boost::yap::evaluate(expr, static_cast(u)...);
}
Expr expr;
};
namespace detail {
template
struct expression_function_expr
{
static const expr_kind kind = Kind;
Tuple elements;
};
}
/** Returns a callable object that \a expr has been forwarded into. This
is useful for using expressions as function objects.
Lvalue expressions are stored in the result by reference; rvalue
expressions are moved into the result.
\note make_expression_function() is only valid if \a
Expr is an expression.
*/
template
constexpr auto make_expression_function(Expr && expr)
{
static_assert(
is_expr::value,
"make_expression_function() is only defined for expressions.");
using stored_type =
detail::operand_type_t;
return expression_function{
detail::make_operand{}(static_cast(expr))};
}
}}
#include
namespace boost { namespace yap {
/** Returns a transform object that replaces placeholders within an
expression with the given values.
*/
template
constexpr auto replacements(T &&... t)
{
return detail::placeholder_transform_t(static_cast(t)...);
}
/** Returns \a expr with the placeholders replaced by YAP terminals
containing the given values.
\note replace_placeholders(expr, t...) is only valid if
\a expr is an expression, and max_p <= sizeof...(t),
where max_p is the maximum placeholder index in \a expr.
*/
template
constexpr decltype(auto) replace_placeholders(Expr && expr, T &&... t)
{
static_assert(
is_expr::value,
"evaluate() is only defined for expressions.");
return transform(
static_cast(expr), replacements(static_cast(t)...));
}
/** Returns a transform object that evaluates an expression using the
built-in semantics. The transform replaces any placeholders with the
given values.
*/
template
constexpr auto evaluation(T &&... t)
{
return detail::evaluation_transform_t(static_cast(t)...);
}
/** Evaluates \a expr using the built-in semantics, replacing any
placeholders with the given values.
\note evaluate(expr) is only valid if \a expr is an
expression.
*/
template
constexpr decltype(auto) evaluate(Expr && expr, T &&... t)
{
static_assert(
is_expr::value,
"evaluate() is only defined for expressions.");
return transform(
static_cast(expr), evaluation(static_cast(t)...));
}
namespace detail {
template
constexpr auto make_transform_tuple(Transforms &... transforms)
{
return hana::tuple{&transforms...};
}
template
struct transform_
{
template
constexpr decltype(auto) operator()(
Expr && expr, Transform & transform, Transforms &... transforms) const
{
auto transform_tuple =
detail::make_transform_tuple(transform, transforms...);
constexpr expr_kind kind = detail::remove_cv_ref_t::kind;
return detail::
transform_impl{}(
static_cast(expr), transform_tuple);
}
};
}
/** Returns the result of transforming (all or part of) \a expr using
whatever overloads of Transform::operator() match \a
expr.
\note Transformations can do anything: they may have side effects;
they may mutate values; they may mutate types; and they may do any
combination of these.
*/
template
constexpr decltype(auto)
transform(Expr && expr, Transform && transform, Transforms &&... transforms)
{
static_assert(
is_expr::value,
"transform() is only defined for expressions.");
return detail::transform_{}(
static_cast(expr), transform, transforms...);
}
/** Returns the result of transforming \a expr using whichever overload of
Transform::operator() best matches \a expr. If no
overload of Transform::operator() matches, a compile-time
error results.
\note Transformations can do anything: they may have side effects;
they may mutate values; they may mutate types; and they may do any
combination of these.
*/
template
constexpr decltype(auto) transform_strict(
Expr && expr, Transform && transform, Transforms &&... transforms)
{
static_assert(
is_expr::value,
"transform() is only defined for expressions.");
return detail::transform_{}(
static_cast(expr), transform, transforms...);
}
}}
#endif