diff options
Diffstat (limited to 'boost/hof')
74 files changed, 10184 insertions, 0 deletions
diff --git a/boost/hof/alias.hpp b/boost/hof/alias.hpp new file mode 100644 index 0000000000..c95cbaf754 --- /dev/null +++ b/boost/hof/alias.hpp @@ -0,0 +1,219 @@ +/*============================================================================= + Copyright (c) 2015 Paul Fultz II + alias.h + 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_HOF_GUARD_ALIAS_H +#define BOOST_HOF_GUARD_ALIAS_H + +#include <boost/hof/returns.hpp> +#include <boost/hof/detail/delegate.hpp> +#include <boost/hof/detail/move.hpp> +#include <boost/hof/detail/holder.hpp> +#include <boost/hof/config.hpp> + +/// alias +/// ===== +/// +/// Description +/// ----------- +/// +/// The `alias` class wraps a type with a new type that can be tagged by the +/// user. This allows defining extra attributes about the type outside of the +/// type itself. There are three different ways the value can be stored: as a +/// member variable, by inheritance, or as a static member variable. The value +/// can be retrieved uniformily using the `alias_value` function. +/// +/// Synopsis +/// -------- +/// +/// // Alias the type using a member variable +/// template<class T, class Tag=void> +/// class alias; +/// +/// // Alias the type by inheriting +/// template<class T, class Tag=void> +/// class alias_inherit; +/// +/// // Alias the type using a static variable +/// template<class T, class Tag=void> +/// class alias_static; +/// +/// // Retrieve tag from alias +/// template<class Alias> +/// class alias_tag; +/// +/// // Check if type has a certian tag +/// template<class T, class Tag> +/// class has_tag; +/// +/// // Retrieve value from alias +/// template<class Alias> +/// constexpr auto alias_value(Alias&&); +/// + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4579) +#endif + +namespace boost { namespace hof { + +template<class T> +struct alias_tag; + +template<class T, class Tag, class=void> +struct has_tag +: std::false_type +{}; + +template<class T, class Tag> +struct has_tag<T, Tag, typename detail::holder< + typename alias_tag<T>::type +>::type> +: std::is_same<typename alias_tag<T>::type, Tag> +{}; + +namespace detail { + +template<class T> +constexpr T& lvalue(T& x) noexcept +{ + return x; +} + +template<class T> +constexpr const T& lvalue(const T& x) noexcept +{ + return x; +} + +} + +#define BOOST_HOF_UNARY_PERFECT_FOREACH(m) \ + m(const&, boost::hof::detail::lvalue) \ + m(&, boost::hof::detail::lvalue) \ + m(&&, boost::hof::move) \ + +template<class T, class Tag=void> +struct alias +{ + T value; + BOOST_HOF_DELEGATE_CONSTRUCTOR(alias, T, value) +}; + +#define BOOST_HOF_DETAIL_ALIAS_GET_VALUE(ref, move) \ +template<class Tag, class T, class... Ts> \ +constexpr auto alias_value(alias<T, Tag> ref a, Ts&&...) BOOST_HOF_RETURNS(move(a.value)) +BOOST_HOF_UNARY_PERFECT_FOREACH(BOOST_HOF_DETAIL_ALIAS_GET_VALUE) + +template<class T, class Tag> +struct alias_tag<alias<T, Tag>> +{ typedef Tag type; }; + + +template<class T, class Tag=void> +struct alias_inherit +#if (defined(__GNUC__) && !defined (__clang__)) +: std::conditional<(std::is_class<T>::value), T, alias<T>>::type +#else +: T +#endif +{ + BOOST_HOF_INHERIT_CONSTRUCTOR(alias_inherit, T) +}; + +#define BOOST_HOF_DETAIL_ALIAS_INHERIT_GET_VALUE(ref, move) \ +template<class Tag, class T, class... Ts, class=typename std::enable_if<(BOOST_HOF_IS_CLASS(T))>::type> \ +constexpr T ref alias_value(alias_inherit<T, Tag> ref a, Ts&&...) BOOST_HOF_RETURNS_DEDUCE_NOEXCEPT(move(a)) \ +{ \ + return move(a); \ +} +BOOST_HOF_UNARY_PERFECT_FOREACH(BOOST_HOF_DETAIL_ALIAS_INHERIT_GET_VALUE) + +template<class T, class Tag> +struct alias_tag<alias_inherit<T, Tag>> +{ typedef Tag type; }; + +namespace detail { + +template<class T, class Tag> +struct alias_static_storage +{ +#ifdef _MSC_VER + // Since we disable the error for 4579 on MSVC, which leaves the static + // member unitialized at runtime, it is, therefore, only safe to use this + // class on types that are empty with constructors that have no possible + // side effects. + static_assert(BOOST_HOF_IS_EMPTY(T) && + BOOST_HOF_IS_LITERAL(T) && + BOOST_HOF_IS_DEFAULT_CONSTRUCTIBLE(T), "In-class initialization is not yet implemented on MSVC"); +#endif + static constexpr T value = T(); +}; + +template<class T, class Tag> +constexpr T alias_static_storage<T, Tag>::value; + +} + +template<class T, class Tag=void> +struct alias_static +{ + template<class... Ts, BOOST_HOF_ENABLE_IF_CONSTRUCTIBLE(T, Ts...)> + constexpr alias_static(Ts&&...) noexcept + {} +}; + +template<class Tag, class T, class... Ts> +constexpr const T& alias_value(const alias_static<T, Tag>&, Ts&&...) noexcept +{ + return detail::alias_static_storage<T, Tag>::value; +} + +template<class T, class Tag> +struct alias_tag<alias_static<T, Tag>> +{ typedef Tag type; }; + +namespace detail { + +template<class T, class Tag> +struct alias_try_inherit +: std::conditional<(BOOST_HOF_IS_CLASS(T) && !BOOST_HOF_IS_FINAL(T) && !BOOST_HOF_IS_POLYMORPHIC(T)), + alias_inherit<T, Tag>, + alias<T, Tag> +> +{}; + +#if BOOST_HOF_HAS_EBO +template<class T, class Tag> +struct alias_empty +: std::conditional<(BOOST_HOF_IS_EMPTY(T)), + typename alias_try_inherit<T, Tag>::type, + alias<T, Tag> +> +{}; +#else +template<class T, class Tag> +struct alias_empty +: std::conditional< + BOOST_HOF_IS_EMPTY(T) && + BOOST_HOF_IS_LITERAL(T) && + BOOST_HOF_IS_DEFAULT_CONSTRUCTIBLE(T), + alias_static<T, Tag>, + alias<T, Tag> +> +{}; +#endif + +} + +}} // namespace boost::hof + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#endif diff --git a/boost/hof/always.hpp b/boost/hof/always.hpp new file mode 100644 index 0000000000..647796fd35 --- /dev/null +++ b/boost/hof/always.hpp @@ -0,0 +1,174 @@ +/*============================================================================= + Copyright (c) 2014 Paul Fultz II + always.h + 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_HOF_GUARD_FUNCTION_ALWAYS_H +#define BOOST_HOF_GUARD_FUNCTION_ALWAYS_H + +#include <boost/hof/detail/delegate.hpp> +#include <boost/hof/detail/unwrap.hpp> +#include <boost/hof/detail/static_const_var.hpp> + +/// always +/// ====== +/// +/// Description +/// ----------- +/// +/// The `always` function returns a function object that will always return +/// the value given to it, no matter what parameters are passed to the +/// function object. The nullary version(i.e. `always(void)`) will return +/// `void`. On compilers, that don't support constexpr functions returning +/// `void`, a private empty type is returned instead. This return type is +/// specified as `BOOST_HOF_ALWAYS_VOID_RETURN`. +/// +/// Synopsis +/// -------- +/// +/// template<class T> +/// constexpr auto always(T value); +/// +/// template<class T> +/// constexpr auto always(void); +/// +/// +/// Semantics +/// --------- +/// +/// assert(always(x)(xs...) == x); +/// +/// Requirements +/// ------------ +/// +/// T must be: +/// +/// * CopyConstructible +/// +/// Example +/// ------- +/// +/// #include <boost/hof.hpp> +/// #include <algorithm> +/// #include <cassert> +/// using namespace boost::hof; +/// +/// int main() { +/// int ten = 10; +/// assert( always(ten)(1,2,3,4,5) == 10 ); +/// } +/// +/// // Count all +/// template<class Iterator, class T> +/// auto count(Iterator first, Iterator last) +/// { +/// return std::count_if(first, last, always(true)); +/// } +/// + + +#ifndef BOOST_HOF_NO_CONSTEXPR_VOID +#if defined(__clang__) && BOOST_HOF_HAS_RELAXED_CONSTEXPR +#define BOOST_HOF_NO_CONSTEXPR_VOID 0 +#else +#define BOOST_HOF_NO_CONSTEXPR_VOID 1 +#endif +#endif + +namespace boost { namespace hof { namespace always_detail { + +template<class T, class=void> +struct always_base +{ + T x; + + BOOST_HOF_DELEGATE_CONSTRUCTOR(always_base, T, x) + + typedef typename detail::unwrap_reference<T>::type result_type; + + template<class... As> + constexpr result_type + operator()(As&&...) const + noexcept(std::is_reference<result_type>::value || BOOST_HOF_IS_NOTHROW_COPY_CONSTRUCTIBLE(result_type)) + { + return this->x; + } +}; + +template<class T> +struct always_base<T, typename std::enable_if<!BOOST_HOF_IS_EMPTY(T)>::type> +{ + T x; + + constexpr always_base(T xp) noexcept(BOOST_HOF_IS_NOTHROW_COPY_CONSTRUCTIBLE(T)) + : x(xp) + {} + + typedef typename detail::unwrap_reference<T>::type result_type; + + template<class... As> + constexpr result_type + operator()(As&&...) const + noexcept(std::is_reference<result_type>::value || BOOST_HOF_IS_NOTHROW_COPY_CONSTRUCTIBLE(result_type)) + { + return this->x; + } +}; + +#if BOOST_HOF_NO_CONSTEXPR_VOID +#define BOOST_HOF_ALWAYS_VOID_RETURN boost::hof::always_detail::always_base<void>::void_ +#else +#define BOOST_HOF_ALWAYS_VOID_RETURN void +#endif + +template<> +struct always_base<void> +{ + + constexpr always_base() noexcept + {} + + struct void_ {}; + + template<class... As> + constexpr BOOST_HOF_ALWAYS_VOID_RETURN + operator()(As&&...) const noexcept + { +#if BOOST_HOF_NO_CONSTEXPR_VOID + return void_(); +#endif + } +}; + +struct always_f +{ + template<class T> + constexpr always_detail::always_base<T> operator()(T x) const noexcept(BOOST_HOF_IS_NOTHROW_COPY_CONSTRUCTIBLE(T)) + { + return always_detail::always_base<T>(x); + } + + constexpr always_detail::always_base<void> operator()() const noexcept + { + return always_detail::always_base<void>(); + } +}; + +struct always_ref_f +{ + template<class T> + constexpr always_detail::always_base<T&> operator()(T& x) const noexcept + { + return always_detail::always_base<T&>(x); + } +}; + +} +BOOST_HOF_DECLARE_STATIC_VAR(always, always_detail::always_f); +BOOST_HOF_DECLARE_STATIC_VAR(always_ref, always_detail::always_ref_f); + +}} // namespace boost::hof + +#endif diff --git a/boost/hof/apply.hpp b/boost/hof/apply.hpp new file mode 100644 index 0000000000..3605a015e9 --- /dev/null +++ b/boost/hof/apply.hpp @@ -0,0 +1,252 @@ +/*============================================================================= + Copyright (c) 2015 Paul Fultz II + apply.h + 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_HOF_GUARD_APPLY_H +#define BOOST_HOF_GUARD_APPLY_H + +/// apply +/// ===== +/// +/// Description +/// ----------- +/// +/// The `apply` function calls the function given to it with its arguments. +/// +/// Synopsis +/// -------- +/// +/// template<class F, class... Ts> +/// constexpr auto apply(F&& f, Ts&&... xs); +/// +/// Semantics +/// --------- +/// +/// assert(apply(f)(xs...) == f(xs...)); +/// assert(fold(apply, f)(x, y, z) == f(x)(y)(z)); +/// +/// Requirements +/// ------------ +/// +/// F must be: +/// +/// * [Invocable](Invocable) +/// +/// Example +/// ------- +/// +/// #include <boost/hof.hpp> +/// #include <cassert> +/// +/// struct sum_f +/// { +/// template<class T, class U> +/// T operator()(T x, U y) const +/// { +/// return x+y; +/// } +/// }; +/// +/// int main() { +/// assert(boost::hof::apply(sum_f(), 1, 2) == 3); +/// } +/// + +#include <boost/hof/detail/result_of.hpp> +#include <boost/hof/detail/forward.hpp> +#include <boost/hof/detail/static_const_var.hpp> + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4003) +#endif + +#define BOOST_HOF_DETAIL_FOREACH_QUAL(m, data) \ + m(, data) \ + m(const, data) \ + m(volatile, data) \ + m(const volatile, data) + +namespace boost { namespace hof { + +namespace detail { +#if BOOST_HOF_HAS_MANUAL_DEDUCTION || BOOST_HOF_NO_EXPRESSION_SFINAE +struct apply_mem_fn +{ + template<class...> + struct convertible_args; + + template<class T, class U, class=void> + struct is_convertible_args + : std::false_type + {}; + + template<class... Ts, class... Us> + struct is_convertible_args< + convertible_args<Ts...>, + convertible_args<Us...>, + typename std::enable_if<( + sizeof...(Ts) == sizeof...(Us) + )>::type + > + : and_<std::is_convertible<Ts, Us>...> + {}; + + template<class From, class To> + struct is_compatible + : std::is_convertible< + typename std::add_pointer<typename std::remove_reference<From>::type>::type, + typename std::add_pointer<typename std::remove_reference<To>::type>::type + > + {}; + +#define BOOST_HOF_APPLY_MEM_FN_CALL(cv, data) \ + template <class R, class Base, class Derived, class... Ts, class... Us, class=typename std::enable_if<and_< \ + is_compatible<Derived, cv Base>, \ + is_convertible_args<convertible_args<Us...>, convertible_args<Ts...>> \ + >::value>::type> \ + constexpr R operator()(R (Base::*mf)(Ts...) cv, Derived&& ref, Us &&... xs) const \ + BOOST_HOF_RETURNS_DEDUCE_NOEXCEPT((BOOST_HOF_FORWARD(Derived)(ref).*mf)(BOOST_HOF_FORWARD(Us)(xs)...)) \ + { \ + return (BOOST_HOF_FORWARD(Derived)(ref).*mf)(BOOST_HOF_FORWARD(Us)(xs)...); \ + } + BOOST_HOF_DETAIL_FOREACH_QUAL(BOOST_HOF_APPLY_MEM_FN_CALL, ~) +}; + +struct apply_mem_data +{ + template<class T, class R> + struct match_qualifier + { typedef R type; }; + +#define BOOST_HOF_APPLY_MEM_DATA_MATCH(cv, ref) \ + template<class T, class R> \ + struct match_qualifier<cv T ref, R> \ + : match_qualifier<T, cv R ref> \ + {}; + + BOOST_HOF_DETAIL_FOREACH_QUAL(BOOST_HOF_APPLY_MEM_DATA_MATCH,&) + BOOST_HOF_DETAIL_FOREACH_QUAL(BOOST_HOF_APPLY_MEM_DATA_MATCH,&&) + + template <class Base, class R, class Derived, class=typename std::enable_if<( + std::is_base_of<Base, typename std::decay<Derived>::type>::value + )>::type> + constexpr typename match_qualifier<Derived, R>::type + operator()(R Base::*pmd, Derived&& ref) const noexcept + { + return BOOST_HOF_FORWARD(Derived)(ref).*pmd; + } +}; + +template<class T, class U=decltype(*std::declval<T>())> +struct apply_deref +{ typedef U type; }; + +#endif + +struct apply_f +{ +#if BOOST_HOF_HAS_MANUAL_DEDUCTION || BOOST_HOF_NO_EXPRESSION_SFINAE + template<class F, class T, class... Ts, class=typename std::enable_if<( + std::is_member_function_pointer<typename std::decay<F>::type>::value + )>::type> + constexpr BOOST_HOF_SFINAE_MANUAL_RESULT(apply_mem_fn, id_<F>, id_<T>, id_<Ts>...) + operator()(F&& f, T&& obj, Ts&&... xs) const BOOST_HOF_SFINAE_MANUAL_RETURNS + ( + apply_mem_fn()(f, BOOST_HOF_FORWARD(T)(obj), BOOST_HOF_FORWARD(Ts)(xs)...) + ); + + template<class F, class T, class... Ts, class U=typename apply_deref<T>::type, class=typename std::enable_if<( + std::is_member_function_pointer<typename std::decay<F>::type>::value + )>::type> + constexpr BOOST_HOF_SFINAE_MANUAL_RESULT(apply_mem_fn, id_<F>, id_<U>, id_<Ts>...) + operator()(F&& f, T&& obj, Ts&&... xs) const BOOST_HOF_SFINAE_MANUAL_RETURNS + ( + apply_mem_fn()(f, *BOOST_HOF_FORWARD(T)(obj), BOOST_HOF_FORWARD(Ts)(xs)...) + ); + + template<class F, class T, class... Ts, class=typename std::enable_if<( + std::is_member_function_pointer<typename std::decay<F>::type>::value + )>::type> + constexpr BOOST_HOF_SFINAE_MANUAL_RESULT(apply_mem_fn, id_<F>, id_<T&>, id_<Ts>...) + operator()(F&& f, const std::reference_wrapper<T>& ref, Ts&&... xs) const BOOST_HOF_SFINAE_MANUAL_RETURNS + ( + apply_mem_fn()(f, ref.get(), BOOST_HOF_FORWARD(Ts)(xs)...) + ); + + template<class F, class T, class=typename std::enable_if<( + std::is_member_object_pointer<typename std::decay<F>::type>::value + )>::type> + constexpr BOOST_HOF_SFINAE_MANUAL_RESULT(apply_mem_data, id_<F>, id_<T>) + operator()(F&& f, T&& obj) const BOOST_HOF_SFINAE_MANUAL_RETURNS + ( + apply_mem_data()(f, BOOST_HOF_FORWARD(T)(obj)) + ); + + template<class F, class T, class U=typename apply_deref<T>::type, class=typename std::enable_if<( + std::is_member_object_pointer<typename std::decay<F>::type>::value + )>::type> + constexpr BOOST_HOF_SFINAE_MANUAL_RESULT(apply_mem_data, id_<F>, id_<U>) + operator()(F&& f, T&& obj) const BOOST_HOF_SFINAE_MANUAL_RETURNS + ( + apply_mem_data()(f, *BOOST_HOF_FORWARD(T)(obj)) + ); + + template<class F, class T, class=typename std::enable_if<( + std::is_member_object_pointer<typename std::decay<F>::type>::value + )>::type> + constexpr BOOST_HOF_SFINAE_MANUAL_RESULT(apply_mem_data, id_<F>, id_<T&>) + operator()(F&& f, const std::reference_wrapper<T>& ref) const BOOST_HOF_SFINAE_MANUAL_RETURNS + ( + apply_mem_data()(f, ref.get()) + ); + +#else + + template <class Base, class T, class Derived> + constexpr auto operator()(T Base::*pmd, Derived&& ref) const + BOOST_HOF_RETURNS(BOOST_HOF_FORWARD(Derived)(ref).*pmd); + + template <class PMD, class Pointer> + constexpr auto operator()(PMD&& pmd, Pointer&& ptr) const + BOOST_HOF_RETURNS((*BOOST_HOF_FORWARD(Pointer)(ptr)).*BOOST_HOF_FORWARD(PMD)(pmd)); + + template <class Base, class T, class Derived> + constexpr auto operator()(T Base::*pmd, const std::reference_wrapper<Derived>& ref) const + BOOST_HOF_RETURNS(ref.get().*pmd); + + template <class Base, class T, class Derived, class... Args> + constexpr auto operator()(T Base::*pmf, Derived&& ref, Args&&... args) const + BOOST_HOF_RETURNS((BOOST_HOF_FORWARD(Derived)(ref).*pmf)(BOOST_HOF_FORWARD(Args)(args)...)); + + template <class PMF, class Pointer, class... Args> + constexpr auto operator()(PMF&& pmf, Pointer&& ptr, Args&&... args) const + BOOST_HOF_RETURNS(((*BOOST_HOF_FORWARD(Pointer)(ptr)).*BOOST_HOF_FORWARD(PMF)(pmf))(BOOST_HOF_FORWARD(Args)(args)...)); + + template <class Base, class T, class Derived, class... Args> + constexpr auto operator()(T Base::*pmf, const std::reference_wrapper<Derived>& ref, Args&&... args) const + BOOST_HOF_RETURNS((ref.get().*pmf)(BOOST_HOF_FORWARD(Args)(args)...)); + +#endif + template<class F, class... Ts> + constexpr BOOST_HOF_SFINAE_MANUAL_RESULT(F, id_<Ts>...) + operator()(F&& f, Ts&&... xs) const BOOST_HOF_SFINAE_MANUAL_RETURNS + ( + f(BOOST_HOF_FORWARD(Ts)(xs)...) + ); +}; + +} + +BOOST_HOF_DECLARE_STATIC_VAR(apply, detail::apply_f); + +}} // namespace boost::hof + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#endif diff --git a/boost/hof/apply_eval.hpp b/boost/hof/apply_eval.hpp new file mode 100644 index 0000000000..2c0c265abf --- /dev/null +++ b/boost/hof/apply_eval.hpp @@ -0,0 +1,156 @@ +/*============================================================================= + Copyright (c) 2015 Paul Fultz II + apply_eval.h + 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_HOF_GUARD_APPLY_EVAL_H +#define BOOST_HOF_GUARD_APPLY_EVAL_H + +/// apply_eval +/// ========== +/// +/// Description +/// ----------- +/// +/// The `apply_eval` function work like [`apply`](/include/boost/hof/apply), except it calls +/// [`eval`](/include/boost/hof/eval) on each of its arguments. Each [`eval`](/include/boost/hof/eval) call is +/// always ordered from left-to-right. +/// +/// Synopsis +/// -------- +/// +/// template<class F, class... Ts> +/// constexpr auto apply_eval(F&& f, Ts&&... xs); +/// +/// Semantics +/// --------- +/// +/// assert(apply_eval(f)(xs...) == f(eval(xs)...)); +/// +/// Requirements +/// ------------ +/// +/// F must be: +/// +/// * [ConstInvocable](ConstInvocable) +/// +/// Ts must be: +/// +/// * [EvaluatableFunctionObject](EvaluatableFunctionObject) +/// +/// Example +/// ------- +/// +/// #include <boost/hof.hpp> +/// #include <cassert> +/// +/// struct sum_f +/// { +/// template<class T, class U> +/// T operator()(T x, U y) const +/// { +/// return x+y; +/// } +/// }; +/// +/// int main() { +/// assert(boost::hof::apply_eval(sum_f(), []{ return 1; }, []{ return 2; }) == 3); +/// } +/// + +#include <boost/hof/config.hpp> +#include <boost/hof/returns.hpp> +#include <boost/hof/detail/forward.hpp> +#include <boost/hof/detail/static_const_var.hpp> +#include <boost/hof/apply.hpp> +#include <boost/hof/eval.hpp> + +#if BOOST_HOF_NO_ORDERED_BRACE_INIT +#include <boost/hof/pack.hpp> +#include <boost/hof/capture.hpp> +#endif + +namespace boost { namespace hof { + +namespace detail { + +#if BOOST_HOF_NO_ORDERED_BRACE_INIT +template<class R, class F, class Pack> +constexpr R eval_ordered(const F& f, Pack&& p) +{ + return p(f); +} + +template<class R, class F, class Pack, class T, class... Ts> +constexpr R eval_ordered(const F& f, Pack&& p, T&& x, Ts&&... xs) +{ + return boost::hof::detail::eval_ordered<R>(f, boost::hof::pack_join(BOOST_HOF_FORWARD(Pack)(p), boost::hof::pack_forward(boost::hof::eval(x))), BOOST_HOF_FORWARD(Ts)(xs)...); +} +#else +template<class R> +struct eval_helper +{ + R result; + + template<class F, class... Ts> + constexpr eval_helper(const F& f, Ts&&... xs) : result(boost::hof::apply(f, BOOST_HOF_FORWARD(Ts)(xs)...)) + {} +}; + +template<> +struct eval_helper<void> +{ + int x; + template<class F, class... Ts> + constexpr eval_helper(const F& f, Ts&&... xs) : x((boost::hof::apply(f, BOOST_HOF_FORWARD(Ts)(xs)...), 0)) + {} +}; +#endif + +struct apply_eval_f +{ + template<class F, class... Ts, class R=decltype( + boost::hof::apply(std::declval<const F&>(), boost::hof::eval(std::declval<Ts>())...) + ), + class=typename std::enable_if<(!std::is_void<R>::value)>::type + > + constexpr R operator()(const F& f, Ts&&... xs) const BOOST_HOF_RETURNS_DEDUCE_NOEXCEPT(boost::hof::apply(f, boost::hof::eval(BOOST_HOF_FORWARD(Ts)(xs))...)) + { + return +#if BOOST_HOF_NO_ORDERED_BRACE_INIT + boost::hof::detail::eval_ordered<R> + (f, boost::hof::pack(), BOOST_HOF_FORWARD(Ts)(xs)...); +#else + boost::hof::detail::eval_helper<R> + {f, boost::hof::eval(BOOST_HOF_FORWARD(Ts)(xs))...}.result; +#endif + } + + template<class F, class... Ts, class R=decltype( + boost::hof::apply(std::declval<const F&>(), boost::hof::eval(std::declval<Ts>())...) + ), + class=typename std::enable_if<(std::is_void<R>::value)>::type + > + constexpr typename detail::holder<Ts...>::type + operator()(const F& f, Ts&&... xs) const BOOST_HOF_RETURNS_DEDUCE_NOEXCEPT(boost::hof::apply(f, boost::hof::eval(BOOST_HOF_FORWARD(Ts)(xs))...)) + { + return (typename detail::holder<Ts...>::type) +#if BOOST_HOF_NO_ORDERED_BRACE_INIT + boost::hof::detail::eval_ordered<R> + (f, boost::hof::pack(), BOOST_HOF_FORWARD(Ts)(xs)...); +#else + boost::hof::detail::eval_helper<R> + {f, boost::hof::eval(BOOST_HOF_FORWARD(Ts)(xs))...}; +#endif + } +}; + +} + +BOOST_HOF_DECLARE_STATIC_VAR(apply_eval, detail::apply_eval_f); + +}} // namespace boost::hof + +#endif diff --git a/boost/hof/arg.hpp b/boost/hof/arg.hpp new file mode 100644 index 0000000000..332789da6e --- /dev/null +++ b/boost/hof/arg.hpp @@ -0,0 +1,126 @@ +/*============================================================================= + Copyright (c) 2014 Paul Fultz II + arg.h + 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_HOF_GUARD_FUNCTION_ARGS_H +#define BOOST_HOF_GUARD_FUNCTION_ARGS_H + +#include <boost/hof/detail/seq.hpp> +#include <boost/hof/returns.hpp> +#include <boost/hof/detail/static_const_var.hpp> +#include <utility> + +/// arg +/// === +/// +/// Description +/// ----------- +/// +/// The `arg` function returns a function object that returns the Nth argument +/// passed to it. It actually starts at 1, so it is not the zero-based index +/// of the argument. +/// +/// Synopsis +/// -------- +/// +/// template<class IntegralConstant> +/// constexpr auto arg(IntegralConstant); +/// +/// template<std::size_t N, class... Ts> +/// constexpr auto arg_c(Ts&&...); +/// +/// +/// Example +/// ------- +/// +/// #include <boost/hof.hpp> +/// #include <cassert> +/// using namespace boost::hof; +/// +/// int main() { +/// assert(arg(std::integral_constant<int, 3>())(1,2,3,4,5) == 3); +/// } +/// + +namespace boost { namespace hof { + +namespace detail { + +template<class T> +struct perfect_ref +{ + typedef T type; + typedef typename std::remove_reference<T>::type value_type; + T&& value; + constexpr perfect_ref(value_type& x) noexcept + : value(BOOST_HOF_FORWARD(T)(x)) + {} +}; + +template<std::size_t N> +struct ignore +{ + template<class T> + constexpr ignore(T&&...) noexcept + {} +}; + +template<std::size_t... N> +struct args_at +{ + template<class T, class... Ts> + constexpr auto operator()(ignore<N>..., T x, Ts...) const + BOOST_HOF_RETURNS(BOOST_HOF_FORWARD(typename T::type)(x.value)); +}; + +template<std::size_t... N> +constexpr args_at<N...> make_args_at(seq<N...>) noexcept +{ + return {}; +} + +template<std::size_t N, class... Ts> +constexpr auto get_args(Ts&&... xs) BOOST_HOF_RETURNS +( + boost::hof::detail::make_args_at(typename gens<N>::type())(nullptr, BOOST_HOF_RETURNS_CONSTRUCT(perfect_ref<Ts>)(xs)...) +); + +template<class T, T N> +struct make_args_f +{ + template<class... Ts, class=typename std::enable_if<(N <= sizeof...(Ts))>::type> + constexpr auto operator()(Ts&&... xs) const BOOST_HOF_RETURNS + ( + boost::hof::detail::get_args<N>(BOOST_HOF_FORWARD(Ts)(xs)...) + ); +}; + +struct arg_f +{ + template<class IntegralConstant> + constexpr make_args_f<std::size_t, IntegralConstant::value> operator()(IntegralConstant) const noexcept + { + return make_args_f<std::size_t, IntegralConstant::value>(); + } +}; + +} +#if BOOST_HOF_HAS_VARIABLE_TEMPLATES +template<std::size_t N> +BOOST_HOF_STATIC_CONSTEXPR detail::make_args_f<std::size_t, N> arg_c = {}; +#else +template<std::size_t N, class... Ts> +constexpr auto arg_c(Ts&&... xs) BOOST_HOF_RETURNS +( + boost::hof::detail::get_args<N>(BOOST_HOF_FORWARD(Ts)(xs)...) +); +#endif + +BOOST_HOF_DECLARE_STATIC_VAR(arg, detail::arg_f); + +}} // namespace boost::hof + +#endif diff --git a/boost/hof/capture.hpp b/boost/hof/capture.hpp new file mode 100644 index 0000000000..8ddeb779ec --- /dev/null +++ b/boost/hof/capture.hpp @@ -0,0 +1,189 @@ +/*============================================================================= + Copyright (c) 2015 Paul Fultz II + capture.h + 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_HOF_GUARD_CAPTURE_H +#define BOOST_HOF_GUARD_CAPTURE_H + +#include <boost/hof/detail/callable_base.hpp> +#include <boost/hof/detail/compressed_pair.hpp> +#include <boost/hof/reveal.hpp> +#include <boost/hof/pack.hpp> +#include <boost/hof/always.hpp> +#include <boost/hof/detail/move.hpp> +#include <boost/hof/detail/result_type.hpp> + +/// capture +/// ======= +/// +/// Description +/// ----------- +/// +/// The `capture` function decorator is used to capture values in a function. +/// It provides more flexibility in capturing than the lambda capture list in +/// C++. It provides a way to do move and perfect capturing. The values +/// captured are prepended to the argument list of the function that will be +/// called. +/// +/// Synopsis +/// -------- +/// +/// // Capture by decaying each value +/// template<class... Ts> +/// constexpr auto capture(Ts&&... xs); +/// +/// // Capture lvalues by reference and rvalue reference by reference +/// template<class... Ts> +/// constexpr auto capture_forward(Ts&&... xs); +/// +/// // Capture lvalues by reference and rvalues by value. +/// template<class... Ts> +/// constexpr auto capture_basic(Ts&&... xs); +/// +/// Semantics +/// --------- +/// +/// assert(capture(xs...)(f)(ys...) == f(xs..., ys...)); +/// +/// +/// Example +/// ------- +/// +/// #include <boost/hof.hpp> +/// #include <cassert> +/// +/// struct sum_f +/// { +/// template<class T, class U> +/// T operator()(T x, U y) const +/// { +/// return x+y; +/// } +/// }; +/// +/// int main() { +/// auto add_one = boost::hof::capture(1)(sum_f()); +/// assert(add_one(2) == 3); +/// } +/// + +namespace boost { namespace hof { + +namespace detail { + +template<class F, class Pack> +struct capture_invoke : detail::compressed_pair<detail::callable_base<F>, Pack>, detail::function_result_type<F> +{ + typedef capture_invoke fit_rewritable1_tag; + typedef detail::compressed_pair<detail::callable_base<F>, Pack> base; + BOOST_HOF_INHERIT_CONSTRUCTOR(capture_invoke, base) + template<class... Ts> + constexpr const detail::callable_base<F>& base_function(Ts&&... xs) const noexcept + { + return this->first(xs...); + } + + template<class... Ts> + constexpr const Pack& get_pack(Ts&&...xs) const noexcept + { + return this->second(xs...); + } + + template<class Failure, class... Ts> + struct unpack_capture_failure + { + template<class... Us> + struct apply + { + typedef typename Failure::template of<Us..., Ts...> type; + }; + }; + + struct capture_failure + { + template<class Failure> + struct apply + { + template<class... Ts> + struct of + : Pack::template apply<unpack_capture_failure<Failure, Ts...>>::type + {}; + }; + }; + + struct failure + : failure_map<capture_failure, detail::callable_base<F>> + {}; + + BOOST_HOF_RETURNS_CLASS(capture_invoke); + + template<class... Ts> + constexpr BOOST_HOF_SFINAE_RESULT + ( + typename result_of<decltype(boost::hof::pack_join), + id_<const Pack&>, + result_of<decltype(boost::hof::pack_forward), id_<Ts>...> + >::type, + id_<detail::callable_base<F>&&> + ) + operator()(Ts&&... xs) const BOOST_HOF_SFINAE_RETURNS + ( + boost::hof::pack_join + ( + BOOST_HOF_MANGLE_CAST(const Pack&)(BOOST_HOF_CONST_THIS->get_pack(xs...)), + boost::hof::pack_forward(BOOST_HOF_FORWARD(Ts)(xs)...) + ) + (BOOST_HOF_RETURNS_C_CAST(detail::callable_base<F>&&)(BOOST_HOF_CONST_THIS->base_function(xs...))) + ); +}; + +template<class Pack> +struct capture_pack : Pack +{ + BOOST_HOF_INHERIT_CONSTRUCTOR(capture_pack, Pack); + + BOOST_HOF_RETURNS_CLASS(capture_pack); + + // TODO: Should use rvalue ref qualifier + template<class F> + constexpr auto operator()(F f) const BOOST_HOF_SFINAE_RETURNS + ( + capture_invoke<F, Pack>(BOOST_HOF_RETURNS_STATIC_CAST(F&&)(f), + BOOST_HOF_RETURNS_C_CAST(Pack&&)( + BOOST_HOF_RETURNS_STATIC_CAST(const Pack&)(*boost::hof::always(BOOST_HOF_CONST_THIS)(f)) + ) + ) + ); +}; + +struct make_capture_pack_f +{ + template<class Pack> + constexpr capture_pack<Pack> operator()(Pack p) const + BOOST_HOF_NOEXCEPT_CONSTRUCTIBLE(capture_pack<Pack>, Pack&&) + { + return capture_pack<Pack>(static_cast<Pack&&>(p)); + } +}; + +template<class F> +struct capture_f +{ + template<class... Ts> + constexpr auto operator()(Ts&&... xs) const BOOST_HOF_RETURNS + ( + BOOST_HOF_RETURNS_CONSTRUCT(make_capture_pack_f)()(BOOST_HOF_RETURNS_CONSTRUCT(F)()(BOOST_HOF_FORWARD(Ts)(xs)...)) + ); +}; +} + +BOOST_HOF_DECLARE_STATIC_VAR(capture_basic, detail::capture_f<detail::pack_basic_f>); +BOOST_HOF_DECLARE_STATIC_VAR(capture_forward, detail::capture_f<detail::pack_forward_f>); +BOOST_HOF_DECLARE_STATIC_VAR(capture, detail::capture_f<detail::pack_f>); + +}} // namespace boost::hof + +#endif diff --git a/boost/hof/combine.hpp b/boost/hof/combine.hpp new file mode 100644 index 0000000000..97c40b0ec4 --- /dev/null +++ b/boost/hof/combine.hpp @@ -0,0 +1,126 @@ +/*============================================================================= + Copyright (c) 2015 Paul Fultz II + combine.h + 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_HOF_GUARD_COMBINE_H +#define BOOST_HOF_GUARD_COMBINE_H + +/// combine +/// ======= +/// +/// Description +/// ----------- +/// +/// The `combine` function adaptor combines several functions together with +/// their arguments. It essentially zips each function with an argument before +/// calling the main function. +/// +/// Synopsis +/// -------- +/// +/// template<class F, class... Gs> +/// constexpr combine_adaptor<F, Gs...> combine(F f, Gs... gs); +/// +/// Semantics +/// --------- +/// +/// assert(combine(f, gs...)(xs...) == f(gs(xs)...)); +/// +/// Requirements +/// ------------ +/// +/// F and Gs must be: +/// +/// * [ConstInvocable](ConstInvocable) +/// * MoveConstructible +/// +/// Example +/// ------- +/// +/// #include <boost/hof.hpp> +/// #include <cassert> +/// #include <tuple> +/// #include <utility> +/// +/// int main() { +/// auto f = boost::hof::combine( +/// boost::hof::construct<std::tuple>(), +/// boost::hof::capture(1)(boost::hof::construct<std::pair>()), +/// boost::hof::capture(2)(boost::hof::construct<std::pair>())); +/// assert(f(3, 7) == std::make_tuple(std::make_pair(1, 3), std::make_pair(2, 7))); +/// } +/// + +#include <boost/hof/pack.hpp> +#include <boost/hof/always.hpp> +#include <boost/hof/detail/callable_base.hpp> +#include <boost/hof/detail/make.hpp> + +namespace boost { namespace hof { namespace detail { + +template<class S, class F, class... Gs> +struct combine_adaptor_base; + +template<std::size_t... Ns, class F, class... Gs> +struct combine_adaptor_base<seq<Ns...>, F, Gs...> +: F, pack_base<seq<Ns...>, Gs...> +{ + typedef pack_base<seq<Ns...>, Gs...> base_type; + + BOOST_HOF_INHERIT_DEFAULT(combine_adaptor_base, base_type, F) + + template<class X, class... Xs, + BOOST_HOF_ENABLE_IF_CONSTRUCTIBLE(F, X), + BOOST_HOF_ENABLE_IF_CONSTRUCTIBLE(base_type, Xs...)> + constexpr combine_adaptor_base(X&& x, Xs&&... xs) + : F(BOOST_HOF_FORWARD(X)(x)), base_type(BOOST_HOF_FORWARD(Xs)(xs)...) + {} + + template<class... Ts> + constexpr const F& base_function(Ts&&... xs) const + { + return boost::hof::always_ref(*this)(xs...); + } + + BOOST_HOF_RETURNS_CLASS(combine_adaptor_base); + +// Result needs to be calculated in a separate class to avoid confusing the +// compiler on MSVC +#if BOOST_HOF_NO_EXPRESSION_SFINAE || BOOST_HOF_HAS_MANUAL_DEDUCTION + template<class... Ts> + struct combine_result + : result_of<const F&, result_of<const Gs&, id_<Ts>>...> + {}; +#endif + + template<class... Ts> +#if BOOST_HOF_NO_EXPRESSION_SFINAE || BOOST_HOF_HAS_MANUAL_DEDUCTION + constexpr typename combine_result<Ts...>::type +#else + constexpr auto +#endif + operator()(Ts&&... xs) const BOOST_HOF_SFINAE_MANUAL_RETURNS + ( + (BOOST_HOF_MANGLE_CAST(const F&)(BOOST_HOF_CONST_THIS->base_function(xs...))) + (boost::hof::alias_value<pack_tag<seq<Ns>, Gs...>, Gs>(*BOOST_HOF_CONST_THIS, xs)(BOOST_HOF_FORWARD(Ts)(xs))...) + ); +}; + +} + +template<class F, class... Gs> +struct combine_adaptor +: detail::combine_adaptor_base<typename detail::gens<sizeof...(Gs)>::type, detail::callable_base<F>, detail::callable_base<Gs>...> +{ + typedef detail::combine_adaptor_base<typename detail::gens<sizeof...(Gs)>::type, detail::callable_base<F>, detail::callable_base<Gs>...> base_type; + BOOST_HOF_INHERIT_CONSTRUCTOR(combine_adaptor, base_type) +}; + +BOOST_HOF_DECLARE_STATIC_VAR(combine, detail::make<combine_adaptor>); + +}} // namespace boost::hof + +#endif diff --git a/boost/hof/compose.hpp b/boost/hof/compose.hpp new file mode 100644 index 0000000000..ec6b611611 --- /dev/null +++ b/boost/hof/compose.hpp @@ -0,0 +1,169 @@ +/*============================================================================= + Copyright (c) 2014 Paul Fultz II + compose.h + 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_HOF_GUARD_FUNCTION_COMPOSE_H +#define BOOST_HOF_GUARD_FUNCTION_COMPOSE_H + +/// compose +/// ======= +/// +/// Description +/// ----------- +/// +/// The `compose` function adaptor provides function composition. It produces +/// a function object that composes a set of functions, ie the output of one +/// function becomes the input of the second function. So, `compose(f, g)(0)` +/// is equivalent to `f(g(0))`. +/// +/// +/// Synopsis +/// -------- +/// +/// template<class... Fs> +/// constexpr compose_adaptor<Fs...> compose(Fs... fs); +/// +/// Semantics +/// --------- +/// +/// assert(compose(f, g)(xs...) == f(g(xs...))); +/// +/// Requirements +/// ------------ +/// +/// Fs must be: +/// +/// * [ConstInvocable](ConstInvocable) +/// * MoveConstructible +/// +/// Example +/// ------- +/// +/// #include <boost/hof.hpp> +/// #include <cassert> +/// using namespace boost::hof; +/// +/// struct increment +/// { +/// template<class T> +/// T operator()(T x) const +/// { +/// return x + 1; +/// } +/// }; +/// +/// struct decrement +/// { +/// template<class T> +/// T operator()(T x) const +/// { +/// return x - 1; +/// } +/// }; +/// +/// int main() { +/// int r = compose(increment(), decrement(), increment())(3); +/// assert(r == 4); +/// } +/// +/// References +/// ---------- +/// +/// * [Function composition](https://en.wikipedia.org/wiki/Function_composition) +/// +/// + +#include <boost/hof/detail/callable_base.hpp> +#include <boost/hof/always.hpp> +#include <boost/hof/detail/delegate.hpp> +#include <boost/hof/detail/compressed_pair.hpp> +#include <boost/hof/detail/join.hpp> +#include <tuple> +#include <boost/hof/detail/move.hpp> +#include <boost/hof/detail/make.hpp> +#include <boost/hof/detail/result_type.hpp> +#include <boost/hof/detail/static_const_var.hpp> + +namespace boost { namespace hof { namespace detail { + +template<class F1, class F2> +struct compose_kernel : detail::compressed_pair<F1, F2>, compose_function_result_type<F1, F2> +{ + typedef detail::compressed_pair<F1, F2> base_type; + + BOOST_HOF_INHERIT_CONSTRUCTOR(compose_kernel, base_type) + + BOOST_HOF_RETURNS_CLASS(compose_kernel); + + template<class... Ts> + constexpr BOOST_HOF_SFINAE_RESULT(const F1&, result_of<const F2&, id_<Ts>...>) + operator()(Ts&&... xs) const BOOST_HOF_SFINAE_RETURNS + ( + BOOST_HOF_MANGLE_CAST(const F1&)(BOOST_HOF_CONST_THIS->first(xs...))( + BOOST_HOF_MANGLE_CAST(const F2&)(BOOST_HOF_CONST_THIS->second(xs...))(BOOST_HOF_FORWARD(Ts)(xs)...) + ) + ); +}; +} + +template<class F, class... Fs> +struct compose_adaptor +: detail::compose_kernel<detail::callable_base<F>, BOOST_HOF_JOIN(compose_adaptor, detail::callable_base<Fs>...)> +{ + typedef compose_adaptor fit_rewritable_tag; + typedef BOOST_HOF_JOIN(compose_adaptor, detail::callable_base<Fs>...) tail; + typedef detail::compose_kernel<detail::callable_base<F>, tail> base_type; + + BOOST_HOF_INHERIT_DEFAULT(compose_adaptor, base_type) + + template<class X, class... Xs, + BOOST_HOF_ENABLE_IF_CONSTRUCTIBLE(detail::callable_base<F>, X), + BOOST_HOF_ENABLE_IF_CONSTRUCTIBLE(tail, Xs...) + > + constexpr compose_adaptor(X&& f1, Xs&& ... fs) + BOOST_HOF_NOEXCEPT(BOOST_HOF_IS_NOTHROW_CONSTRUCTIBLE(base_type, X&&, tail) && BOOST_HOF_IS_NOTHROW_CONSTRUCTIBLE(tail, Xs&&...)) + : base_type(BOOST_HOF_FORWARD(X)(f1), tail(BOOST_HOF_FORWARD(Xs)(fs)...)) + {} + + template<class X, + BOOST_HOF_ENABLE_IF_CONSTRUCTIBLE(detail::callable_base<F>, X) + > + constexpr compose_adaptor(X&& f1) + BOOST_HOF_NOEXCEPT_CONSTRUCTIBLE(base_type, X&&) + : base_type(BOOST_HOF_FORWARD(X)(f1)) + {} +}; + +template<class F> +struct compose_adaptor<F> : detail::callable_base<F> +{ + typedef compose_adaptor fit_rewritable_tag; + + BOOST_HOF_INHERIT_DEFAULT(compose_adaptor, detail::callable_base<F>) + + template<class X, BOOST_HOF_ENABLE_IF_CONVERTIBLE(X, detail::callable_base<F>)> + constexpr compose_adaptor(X&& f1) + BOOST_HOF_NOEXCEPT_CONSTRUCTIBLE(detail::callable_base<F>, X&&) + : detail::callable_base<F>(BOOST_HOF_FORWARD(X)(f1)) + {} + +}; + +template<class F1, class F2> +struct compose_adaptor<F1, F2> +: detail::compose_kernel<detail::callable_base<F1>, detail::callable_base<F2>> +{ + typedef compose_adaptor fit_rewritable_tag; + typedef detail::compose_kernel<detail::callable_base<F1>, detail::callable_base<F2>> base_type; + + BOOST_HOF_INHERIT_CONSTRUCTOR(compose_adaptor, base_type) +}; + +BOOST_HOF_DECLARE_STATIC_VAR(compose, detail::make<compose_adaptor>); + +}} // namespace boost::hof + +#endif diff --git a/boost/hof/config.hpp b/boost/hof/config.hpp new file mode 100644 index 0000000000..77e80e399a --- /dev/null +++ b/boost/hof/config.hpp @@ -0,0 +1,201 @@ +/*============================================================================= + Copyright (c) 2016 Paul Fultz II + config.hpp + 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_HOF_GUARD_CONFIG_HPP +#define BOOST_HOF_GUARD_CONFIG_HPP + +// Unpack has extra checks to ensure that the function will be invoked with +// the sequence. This extra check can help improve error reporting but it can +// slow down compilation. This is enabled by default. +#ifndef BOOST_HOF_CHECK_UNPACK_SEQUENCE +#define BOOST_HOF_CHECK_UNPACK_SEQUENCE 1 +#endif + +// Check for std version +#if __cplusplus >= 201606 +#define BOOST_HOF_HAS_STD_17 1 +#else +#define BOOST_HOF_HAS_STD_17 0 +#endif + +#if __cplusplus >= 201402 +#define BOOST_HOF_HAS_STD_14 1 +#else +#define BOOST_HOF_HAS_STD_14 0 +#endif + +#if __cplusplus >= 201103 +#define BOOST_HOF_HAS_STD_11 1 +#else +#define BOOST_HOF_HAS_STD_11 0 +#endif + + +// This determines if it safe to use inheritance for EBO. On every platform +// except clang, compilers have problems with ambigous base conversion. So +// this configures the library to use a different technique to achieve empty +// optimization. +#ifndef BOOST_HOF_HAS_EBO +#ifdef __clang__ +#define BOOST_HOF_HAS_EBO 1 +#else +#define BOOST_HOF_HAS_EBO 0 +#endif +#endif + +// This configures the library whether expression sfinae can be used to detect +// callability of a function. +#ifndef BOOST_HOF_NO_EXPRESSION_SFINAE +#ifdef _MSC_VER +#define BOOST_HOF_NO_EXPRESSION_SFINAE 1 +#else +#define BOOST_HOF_NO_EXPRESSION_SFINAE 0 +#endif +#endif + +// This configures the library to use manual type deduction in a few places +// where it problematic on a few platforms. +#ifndef BOOST_HOF_HAS_MANUAL_DEDUCTION +#if (defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ < 8) +#define BOOST_HOF_HAS_MANUAL_DEDUCTION 1 +#else +#define BOOST_HOF_HAS_MANUAL_DEDUCTION 0 +#endif +#endif + +// Whether the compiler has relaxed constexpr. +#ifndef BOOST_HOF_HAS_RELAXED_CONSTEXPR +#ifdef __cpp_constexpr +#if __cpp_constexpr >= 201304 +#define BOOST_HOF_HAS_RELAXED_CONSTEXPR 1 +#else +#define BOOST_HOF_HAS_RELAXED_CONSTEXPR 0 +#endif +#else +#define BOOST_HOF_HAS_RELAXED_CONSTEXPR BOOST_HOF_HAS_STD_14 +#endif +#endif + +// Whether the compiler supports generic lambdas +#ifndef BOOST_HOF_HAS_GENERIC_LAMBDA +#if defined(__cpp_generic_lambdas) || defined(_MSC_VER) +#define BOOST_HOF_HAS_GENERIC_LAMBDA 1 +#else +#define BOOST_HOF_HAS_GENERIC_LAMBDA BOOST_HOF_HAS_STD_14 +#endif +#endif + +// Whether the compiler supports constexpr lambdas +#ifndef BOOST_HOF_HAS_CONSTEXPR_LAMBDA +#if defined(__cpp_constexpr) && __cpp_constexpr >= 201603 +#define BOOST_HOF_HAS_CONSTEXPR_LAMBDA 1 +#else +#define BOOST_HOF_HAS_CONSTEXPR_LAMBDA BOOST_HOF_HAS_STD_17 +#endif +#endif + +// Whether the compiler supports inline variables +#ifndef BOOST_HOF_HAS_INLINE_VARIABLES +#if defined(__cpp_inline_variables) +#define BOOST_HOF_HAS_INLINE_VARIABLES 1 +#else +#define BOOST_HOF_HAS_INLINE_VARIABLES BOOST_HOF_HAS_STD_17 +#endif +#endif + +// Whether inline variables defined with lambdas have external linkage. +// Currently, no compiler supports this yet. +#ifndef BOOST_HOF_HAS_INLINE_LAMBDAS +#define BOOST_HOF_HAS_INLINE_LAMBDAS 0 +#endif + +// Whether the compiler supports variable templates +#ifndef BOOST_HOF_HAS_VARIABLE_TEMPLATES +#if defined(__clang__) && __clang_major__ == 3 && __clang_minor__ < 5 +#define BOOST_HOF_HAS_VARIABLE_TEMPLATES 0 +#elif defined(__cpp_variable_templates) +#define BOOST_HOF_HAS_VARIABLE_TEMPLATES 1 +#else +#define BOOST_HOF_HAS_VARIABLE_TEMPLATES BOOST_HOF_HAS_STD_14 +#endif +#endif + +// Whether a constexpr function can use a void return type +#ifndef BOOST_HOF_NO_CONSTEXPR_VOID +#if BOOST_HOF_HAS_RELAXED_CONSTEXPR +#define BOOST_HOF_NO_CONSTEXPR_VOID 0 +#else +#define BOOST_HOF_NO_CONSTEXPR_VOID 1 +#endif +#endif + +// Whether to use template aliases +#ifndef BOOST_HOF_HAS_TEMPLATE_ALIAS +#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ < 8 +#define BOOST_HOF_HAS_TEMPLATE_ALIAS 0 +#else +#define BOOST_HOF_HAS_TEMPLATE_ALIAS 1 +#endif +#endif + +// Whether evaluations of function in brace initialization is ordered from +// left-to-right. +#ifndef BOOST_HOF_NO_ORDERED_BRACE_INIT +#if (defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ < 9) || defined(_MSC_VER) +#define BOOST_HOF_NO_ORDERED_BRACE_INIT 1 +#else +#define BOOST_HOF_NO_ORDERED_BRACE_INIT 0 +#endif +#endif + +// Whether the compiler has trouble mangling some expressions used in +// decltype. +#ifndef BOOST_HOF_HAS_MANGLE_OVERLOAD +#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ < 7 +#define BOOST_HOF_HAS_MANGLE_OVERLOAD 0 +#else +#define BOOST_HOF_HAS_MANGLE_OVERLOAD 1 +#endif +#endif + +// Whether an incomplete 'this' pointer can be used in a trailing decltype. +#ifndef BOOST_HOF_HAS_COMPLETE_DECLTYPE +#if !BOOST_HOF_HAS_MANGLE_OVERLOAD || (defined(__GNUC__) && !defined (__clang__)) +#define BOOST_HOF_HAS_COMPLETE_DECLTYPE 0 +#else +#define BOOST_HOF_HAS_COMPLETE_DECLTYPE 1 +#endif +#endif + +// Whether function will deduce noexcept from an expression +#ifndef BOOST_HOF_HAS_NOEXCEPT_DEDUCTION +#if defined(__GNUC__) && !defined (__clang__) && ((__GNUC__ == 4 && __GNUC_MINOR__ < 8) || (__GNUC__ == 7 && __GNUC_MINOR__ == 1)) +#define BOOST_HOF_HAS_NOEXCEPT_DEDUCTION 0 +#else +#define BOOST_HOF_HAS_NOEXCEPT_DEDUCTION 1 +#endif +#endif + +// Some type expansion failures on gcc 4.6 +#ifndef BOOST_HOF_NO_TYPE_PACK_EXPANSION_IN_TEMPLATE +#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ < 7 +#define BOOST_HOF_NO_TYPE_PACK_EXPANSION_IN_TEMPLATE 1 +#else +#define BOOST_HOF_NO_TYPE_PACK_EXPANSION_IN_TEMPLATE 0 +#endif +#endif + +// Whether to use std::default_constructible, it is a little buggy on gcc 4.6. +#ifndef BOOST_HOF_NO_STD_DEFAULT_CONSTRUCTIBLE +#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ < 7 +#define BOOST_HOF_NO_STD_DEFAULT_CONSTRUCTIBLE 1 +#else +#define BOOST_HOF_NO_STD_DEFAULT_CONSTRUCTIBLE 0 +#endif +#endif + +#endif diff --git a/boost/hof/construct.hpp b/boost/hof/construct.hpp new file mode 100644 index 0000000000..daf9eca42f --- /dev/null +++ b/boost/hof/construct.hpp @@ -0,0 +1,302 @@ +/*============================================================================= + Copyright (c) 2015 Paul Fultz II + construct.h + 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_HOF_GUARD_CONSTRUCT_H +#define BOOST_HOF_GUARD_CONSTRUCT_H + +/// construct +/// ========= +/// +/// Description +/// ----------- +/// +/// The `construct` function returns a function object that will construct the +/// object when the called. A template can also be given, which it will deduce +/// the parameters to the template. The `construct_meta` can be used to +/// construct the object from a metafunction. +/// +/// Synopsis +/// -------- +/// +/// // Construct by decaying each value +/// template<class T> +/// constexpr auto construct(); +/// +/// template<template<class...> class Template> +/// constexpr auto construct(); +/// +/// // Construct by deducing lvalues by reference and rvalue reference by reference +/// template<class T> +/// constexpr auto construct_forward(); +/// +/// template<template<class...> class Template> +/// constexpr auto construct_forward(); +/// +/// // Construct by deducing lvalues by reference and rvalues by value. +/// template<class T> +/// constexpr auto construct_basic(); +/// +/// template<template<class...> class Template> +/// constexpr auto construct_basic(); +/// +/// // Construct by deducing the object from a metafunction +/// template<class MetafunctionClass> +/// constexpr auto construct_meta(); +/// +/// template<template<class...> class MetafunctionTemplate> +/// constexpr auto construct_meta(); +/// +/// Semantics +/// --------- +/// +/// assert(construct<T>()(xs...) == T(xs...)); +/// assert(construct<Template>()(xs...) == Template<decltype(xs)...>(xs...)); +/// assert(construct_meta<MetafunctionClass>()(xs...) == MetafunctionClass::apply<decltype(xs)...>(xs...)); +/// assert(construct_meta<MetafunctionTemplate>()(xs...) == MetafunctionTemplate<decltype(xs)...>::type(xs...)); +/// +/// Requirements +/// ------------ +/// +/// MetafunctionClass must be a: +/// +/// * [MetafunctionClass](MetafunctionClass) +/// +/// MetafunctionTemplate<Ts...> must be a: +/// +/// * [Metafunction](Metafunction) +/// +/// T, Template<Ts..>, MetafunctionClass::apply<Ts...>, and +/// MetafunctionTemplate<Ts...>::type must be: +/// +/// * MoveConstructible +/// +/// Example +/// ------- +/// +/// #include <boost/hof.hpp> +/// #include <cassert> +/// #include <vector> +/// +/// int main() { +/// auto v = boost::hof::construct<std::vector<int>>()(5, 5); +/// assert(v.size() == 5); +/// } +/// + +#include <boost/hof/detail/forward.hpp> +#include <boost/hof/detail/move.hpp> +#include <boost/hof/detail/delegate.hpp> +#include <boost/hof/detail/join.hpp> +#include <boost/hof/detail/remove_rvalue_reference.hpp> +#include <boost/hof/decay.hpp> + +#include <initializer_list> + +namespace boost { namespace hof { + +namespace detail { + +template<class T, class=void> +struct construct_f +{ + typedef typename std::aligned_storage<sizeof(T)>::type storage; + + struct storage_holder + { + storage * s; + storage_holder(storage* x) noexcept : s(x) + {} + + T& data() noexcept + { + return *reinterpret_cast<T*>(s); + } + + ~storage_holder() noexcept(noexcept(std::declval<T>().~T())) + { + this->data().~T(); + } + }; + + constexpr construct_f() noexcept + {} + template<class... Ts, BOOST_HOF_ENABLE_IF_CONSTRUCTIBLE(T, Ts...)> + T operator()(Ts&&... xs) const BOOST_HOF_NOEXCEPT_CONSTRUCTIBLE(T, Ts&&...) + { + storage buffer{}; + new(&buffer) T(BOOST_HOF_FORWARD(Ts)(xs)...); + storage_holder h(&buffer); + return boost::hof::move(h.data()); + } + + template<class X, BOOST_HOF_ENABLE_IF_CONSTRUCTIBLE(T, std::initializer_list<X>&&)> + T operator()(std::initializer_list<X>&& x) const BOOST_HOF_NOEXCEPT_CONSTRUCTIBLE(T, std::initializer_list<X>&&) + { + storage buffer{}; + new(&buffer) T(static_cast<std::initializer_list<X>&&>(x)); + storage_holder h(&buffer); + return h.data(); + } + + template<class X, BOOST_HOF_ENABLE_IF_CONSTRUCTIBLE(T, std::initializer_list<X>&)> + T operator()(std::initializer_list<X>& x) const BOOST_HOF_NOEXCEPT_CONSTRUCTIBLE(T, std::initializer_list<X>&) + { + storage buffer{}; + new(&buffer) T(x); + storage_holder h(&buffer); + return h.data(); + } + + template<class X, BOOST_HOF_ENABLE_IF_CONSTRUCTIBLE(T, const std::initializer_list<X>&)> + T operator()(const std::initializer_list<X>& x) const BOOST_HOF_NOEXCEPT_CONSTRUCTIBLE(T, const std::initializer_list<X>&) + { + storage buffer{}; + new(&buffer) T(x); + storage_holder h(&buffer); + return h.data(); + } +}; + +template<class T> +struct construct_f<T, typename std::enable_if<BOOST_HOF_IS_LITERAL(T)>::type> +{ + constexpr construct_f() noexcept + {} + template<class... Ts, BOOST_HOF_ENABLE_IF_CONSTRUCTIBLE(T, Ts...)> + constexpr T operator()(Ts&&... xs) const noexcept + { + return T(BOOST_HOF_FORWARD(Ts)(xs)...); + } + + template<class X, BOOST_HOF_ENABLE_IF_CONSTRUCTIBLE(T, std::initializer_list<X>&&)> + constexpr T operator()(std::initializer_list<X>&& x) const noexcept + { + return T(static_cast<std::initializer_list<X>&&>(x)); + } + + template<class X, BOOST_HOF_ENABLE_IF_CONSTRUCTIBLE(T, std::initializer_list<X>&)> + constexpr T operator()(std::initializer_list<X>& x) const noexcept + { + return T(x); + } + + template<class X, BOOST_HOF_ENABLE_IF_CONSTRUCTIBLE(T, const std::initializer_list<X>&)> + constexpr T operator()(const std::initializer_list<X>& x) const noexcept + { + return T(x); + } +}; + +template<template<class...> class Template, template<class...> class D> +struct construct_template_f +{ + constexpr construct_template_f() noexcept + {} + template<class... Ts, class Result=BOOST_HOF_JOIN(Template, typename D<Ts>::type...), + BOOST_HOF_ENABLE_IF_CONSTRUCTIBLE(Result, Ts...)> + constexpr Result operator()(Ts&&... xs) const BOOST_HOF_NOEXCEPT_CONSTRUCTIBLE(Result, Ts&&...) + { + return construct_f<Result>()(BOOST_HOF_FORWARD(Ts)(xs)...); + } +}; + +template<class MetafunctionClass> +struct construct_meta_f +{ + constexpr construct_meta_f() noexcept + {} + + template<class... Ts> + struct apply + : MetafunctionClass::template apply<Ts...> + {}; + + template<class... Ts, + class Metafunction=BOOST_HOF_JOIN(apply, Ts...), + class Result=typename Metafunction::type, + BOOST_HOF_ENABLE_IF_CONSTRUCTIBLE(Result, Ts...)> + constexpr Result operator()(Ts&&... xs) const BOOST_HOF_NOEXCEPT_CONSTRUCTIBLE(Result, Ts&&...) + { + return construct_f<Result>()(BOOST_HOF_FORWARD(Ts)(xs)...); + } +}; + +template<template<class...> class MetafunctionTemplate> +struct construct_meta_template_f +{ + constexpr construct_meta_template_f() noexcept + {} + template<class... Ts, + class Metafunction=BOOST_HOF_JOIN(MetafunctionTemplate, Ts...), + class Result=typename Metafunction::type, + BOOST_HOF_ENABLE_IF_CONSTRUCTIBLE(Result, Ts...)> + constexpr Result operator()(Ts&&... xs) const BOOST_HOF_NOEXCEPT_CONSTRUCTIBLE(Result, Ts&&...) + { + return construct_f<Result>()(BOOST_HOF_FORWARD(Ts)(xs)...); + } +}; + + +template<class T> +struct construct_id +{ + typedef T type; +}; + +} + +template<class T> +constexpr detail::construct_f<T> construct() noexcept +{ + return {}; +} +// These overloads are provide for consistency +template<class T> +constexpr detail::construct_f<T> construct_forward() noexcept +{ + return {}; +} + +template<class T> +constexpr detail::construct_f<T> construct_basic() noexcept +{ + return {}; +} + +template<template<class...> class Template> +constexpr detail::construct_template_f<Template, detail::decay_mf> construct() noexcept +{ + return {}; +} + +template<template<class...> class Template> +constexpr detail::construct_template_f<Template, detail::construct_id> construct_forward() noexcept +{ + return {}; +} + +template<template<class...> class Template> +constexpr detail::construct_template_f<Template, detail::remove_rvalue_reference> construct_basic() noexcept +{ + return {}; +} + +template<class T> +constexpr detail::construct_meta_f<T> construct_meta() noexcept +{ + return {}; +} + +template<template<class...> class Template> +constexpr detail::construct_meta_template_f<Template> construct_meta() noexcept +{ + return {}; +} + +}} // namespace boost::hof + +#endif diff --git a/boost/hof/decay.hpp b/boost/hof/decay.hpp new file mode 100644 index 0000000000..5b67122b67 --- /dev/null +++ b/boost/hof/decay.hpp @@ -0,0 +1,68 @@ +/*============================================================================= + Copyright (c) 2015 Paul Fultz II + decay.h + 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_HOF_GUARD_DECAY_H +#define BOOST_HOF_GUARD_DECAY_H + +/// decay +/// ===== +/// +/// Description +/// ----------- +/// +/// The `decay` function is a unary function object that returns whats given to it after decaying its type. +/// +/// Synopsis +/// -------- +/// +/// struct +/// { +/// template<class T> +/// constexpr typename decay<T>::type operator()(T&& x) const +/// { +/// return boost::hof::forward<T>(x); +/// } +/// } decay; +/// +/// References +/// ---------- +/// +/// * [n3255](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3255.html) - Proposal for `decay_copy` +/// + +#include <boost/hof/detail/delegate.hpp> +#include <boost/hof/detail/unwrap.hpp> +#include <boost/hof/detail/static_const_var.hpp> +#include <boost/hof/detail/forward.hpp> + +namespace boost { namespace hof { namespace detail { + +template<class T> +struct decay_mf +: unwrap_reference<typename std::decay<T>::type> +{}; + +struct decay_f +{ + template< + class T, + class Result=typename unwrap_reference<typename std::decay<T>::type>::type, + class=typename std::enable_if<(BOOST_HOF_IS_CONSTRUCTIBLE(Result, T))>::type + > + constexpr Result operator()(T&& x) const BOOST_HOF_NOEXCEPT_CONSTRUCTIBLE(Result, T&&) + { + return BOOST_HOF_FORWARD(T)(x); + } +}; + +} + +BOOST_HOF_DECLARE_STATIC_VAR(decay, detail::decay_f); + +}} // namespace boost::hof + +#endif diff --git a/boost/hof/decorate.hpp b/boost/hof/decorate.hpp new file mode 100644 index 0000000000..9337b30488 --- /dev/null +++ b/boost/hof/decorate.hpp @@ -0,0 +1,217 @@ +/*============================================================================= + Copyright (c) 2015 Paul Fultz II + decorate.h + 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_HOF_GUARD_DECORATE_H +#define BOOST_HOF_GUARD_DECORATE_H + +/// decorate +/// ======== +/// +/// Description +/// ----------- +/// +/// The `decorate` function adaptor helps create simple function decorators. +/// +/// A function adaptor takes a function and returns a new functions whereas a +/// decorator takes some parameters and returns a function adaptor. The +/// `decorate` function adaptor will return a decorator that returns a +/// function adaptor. Eventually, it will invoke the function with the user- +/// provided parameter and function. +/// +/// Synopsis +/// -------- +/// +/// template<class F> +/// constexpr decorate_adaptor<F> decorate(F f); +/// +/// Semantics +/// --------- +/// +/// assert(decorate(f)(x)(g)(xs...) == f(x, g, xs...)); +/// +/// Requirements +/// ------------ +/// +/// F must be: +/// +/// * [ConstInvocable](ConstInvocable) +/// * MoveConstructible +/// +/// Example +/// ------- +/// +/// #include <boost/hof.hpp> +/// #include <cassert> +/// #include <iostream> +/// #include <string> +/// using namespace boost::hof; +/// +/// struct logger_f +/// { +/// template<class F, class... Ts> +/// auto operator()(const std::string& message, F&& f, Ts&&... xs) const +/// -> decltype(f(std::forward<Ts>(xs)...)) +/// { +/// // Message to print out when the function is called +/// std::cout << message << std::endl; +/// // Call the function +/// return f(std::forward<Ts>(xs)...); +/// } +/// }; +/// // The logger decorator +/// BOOST_HOF_STATIC_FUNCTION(logger) = boost::hof::decorate(logger_f()); +/// +/// struct sum_f +/// { +/// template<class T, class U> +/// T operator()(T x, U y) const +/// { +/// return x+y; +/// } +/// }; +/// +/// BOOST_HOF_STATIC_FUNCTION(sum) = sum_f(); +/// int main() { +/// // Use the logger decorator to print "Calling sum" when the function is called +/// assert(3 == logger("Calling sum")(sum)(1, 2)); +/// } +/// + +#include <boost/hof/reveal.hpp> +#include <boost/hof/detail/delegate.hpp> +#include <boost/hof/detail/move.hpp> +#include <boost/hof/detail/make.hpp> +#include <boost/hof/detail/callable_base.hpp> +#include <boost/hof/detail/static_const_var.hpp> +#include <boost/hof/detail/compressed_pair.hpp> + +namespace boost { namespace hof { namespace detail { + +template<class D, class T, class F> +struct decorator_invoke +// : compressed_pair<compressed_pair<F, T>, D> +: compressed_pair<compressed_pair<D, T>, F> +{ + // typedef compressed_pair<F, T> base; + typedef compressed_pair<compressed_pair<D, T>, F> base; + + BOOST_HOF_INHERIT_CONSTRUCTOR(decorator_invoke, base) + + template<class... Ts> + constexpr const compressed_pair<D, T>& get_pair(Ts&&... xs) const noexcept + { + return this->first(xs...); + } + + template<class... Ts> + constexpr const F& base_function(Ts&&... xs) const noexcept + { + return this->second(xs...); + } + + template<class... Ts> + constexpr const D& get_decorator(Ts&&... xs) const noexcept + { + return this->get_pair(xs...).first(xs...); + } + + template<class... Ts> + constexpr const T& get_data(Ts&&... xs) const noexcept + { + return this->get_pair(xs...).second(xs...); + } + + BOOST_HOF_RETURNS_CLASS(decorator_invoke); + + struct decorator_invoke_failure + { + template<class Failure> + struct apply + { + template<class... Ts> + struct of + : Failure::template of<const T&, const F&, Ts...> + {}; + }; + }; + + struct failure + : failure_map<decorator_invoke_failure, D> + {}; + + template<class... Ts> + constexpr BOOST_HOF_SFINAE_RESULT(const D&, id_<const T&>, id_<const F&>, id_<Ts>...) + operator()(Ts&&... xs) const BOOST_HOF_SFINAE_RETURNS + ( + BOOST_HOF_MANGLE_CAST(const D&)(BOOST_HOF_CONST_THIS->get_decorator(xs...))( + BOOST_HOF_MANGLE_CAST(const T&)(BOOST_HOF_CONST_THIS->get_data(xs...)), + BOOST_HOF_MANGLE_CAST(const F&)(BOOST_HOF_CONST_THIS->base_function(xs...)), + BOOST_HOF_FORWARD(Ts)(xs)... + ) + ); +}; + +template<class D, class T> +struct decoration +: compressed_pair<D, T> +{ + typedef compressed_pair<D, T> base; + BOOST_HOF_INHERIT_CONSTRUCTOR(decoration, base) + + template<class... Ts> + constexpr const D& get_decorator(Ts&&... xs) const noexcept + { + return this->first(xs...); + } + + template<class... Ts> + constexpr const T& get_data(Ts&&... xs) const noexcept + { + return this->second(xs...); + } + + template<class F> + constexpr decorator_invoke<D, T, detail::callable_base<F>> operator()(F f) const + BOOST_HOF_NOEXCEPT(BOOST_HOF_IS_NOTHROW_CONSTRUCTIBLE(decorator_invoke<D, T, detail::callable_base<F>>, compressed_pair<D, T>, detail::callable_base<F>&&)) + { + return decorator_invoke<D, T, detail::callable_base<F>>( + *this, static_cast<detail::callable_base<F>&&>(f) + ); + } +}; + +} + +template<class F> +struct decorate_adaptor : detail::callable_base<F> +{ + typedef decorate_adaptor fit_rewritable1_tag; + typedef detail::callable_base<F> base; + BOOST_HOF_INHERIT_CONSTRUCTOR(decorate_adaptor, detail::callable_base<F>) + + template<class... Ts> + constexpr const base& base_function(Ts&&... xs) const noexcept + { + return boost::hof::always_ref(*this)(xs...); + } + + // TODO: Add predicate for constraints + + template<class T> + constexpr detail::decoration<base, T> operator()(T x) const + BOOST_HOF_NOEXCEPT(BOOST_HOF_IS_NOTHROW_CONSTRUCTIBLE(base, const base&) && BOOST_HOF_IS_NOTHROW_CONSTRUCTIBLE(T, T&&)) + { + return detail::decoration<base, T>(this->base_function(x), static_cast<T&&>(x)); + } + +}; + +BOOST_HOF_DECLARE_STATIC_VAR(decorate, detail::make<decorate_adaptor>); + +}} // namespace boost::hof + +#endif diff --git a/boost/hof/detail/and.hpp b/boost/hof/detail/and.hpp new file mode 100644 index 0000000000..8a7e50a36e --- /dev/null +++ b/boost/hof/detail/and.hpp @@ -0,0 +1,55 @@ +/*============================================================================= + Copyright (c) 2015 Paul Fultz II + and.h + 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_HOF_GUARD_AND_H +#define BOOST_HOF_GUARD_AND_H + +#include <type_traits> +#include <boost/hof/detail/using.hpp> +#include <boost/hof/detail/intrinsics.hpp> + +namespace boost { namespace hof { namespace detail { + +constexpr bool and_c() +{ + return true; +} + +template<class... Ts> +constexpr bool and_c(bool b, Ts... bs) +{ + return b && and_c(bs...); +} + +#ifdef _MSC_VER + +template<class... Ts> +struct and_; + +template<class T, class... Ts> +struct and_<T, Ts...> +: std::integral_constant<bool, (T::value && and_<Ts...>::value)> +{}; + +template<> +struct and_<> +: std::true_type +{}; + +#define BOOST_HOF_AND_UNPACK(Bs) (boost::hof::detail::and_c(Bs...)) +#else +template<bool...> struct bool_seq {}; +template<class... Ts> +BOOST_HOF_USING(and_, std::is_same<bool_seq<Ts::value...>, bool_seq<(Ts::value, true)...>>); + +#define BOOST_HOF_AND_UNPACK(Bs) BOOST_HOF_IS_BASE_OF(boost::hof::detail::bool_seq<Bs...>, boost::hof::detail::bool_seq<(Bs || true)...>) + +#endif + +}}} // namespace boost::hof + +#endif diff --git a/boost/hof/detail/callable_base.hpp b/boost/hof/detail/callable_base.hpp new file mode 100644 index 0000000000..b214043e0b --- /dev/null +++ b/boost/hof/detail/callable_base.hpp @@ -0,0 +1,65 @@ +/*============================================================================= + Copyright (c) 2015 Paul Fultz II + callable_base.h + 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_HOF_GUARD_CALLABLE_BASE_H +#define BOOST_HOF_GUARD_CALLABLE_BASE_H + +#include <boost/hof/detail/delegate.hpp> +#include <boost/hof/detail/result_of.hpp> +#include <boost/hof/apply.hpp> + +#ifndef BOOST_HOF_CALLABLE_BASE_USE_TEMPLATE_ALIAS +#if (defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ < 7) +#define BOOST_HOF_CALLABLE_BASE_USE_TEMPLATE_ALIAS 0 +#else +#define BOOST_HOF_CALLABLE_BASE_USE_TEMPLATE_ALIAS 1 +#endif +#endif + +namespace boost { namespace hof { namespace detail { + +template<class F> +struct non_class_function +{ + F f; + BOOST_HOF_DELEGATE_CONSTRUCTOR(non_class_function, F, f) + + template<class... Ts> + constexpr BOOST_HOF_SFINAE_RESULT(apply_f, id_<F>, id_<Ts>...) + operator()(Ts&&... xs) const BOOST_HOF_SFINAE_RETURNS + ( + boost::hof::apply(f, BOOST_HOF_FORWARD(Ts)(xs)...) + ); +}; + +template<class F> +struct callable_base_type +: std::conditional<(BOOST_HOF_IS_CLASS(F) && !BOOST_HOF_IS_FINAL(F) && !BOOST_HOF_IS_POLYMORPHIC(F)), F, non_class_function<F>> +{}; + +#if BOOST_HOF_CALLABLE_BASE_USE_TEMPLATE_ALIAS +template<class F> +using callable_base = typename callable_base_type<F>::type; +#else +template<class F> +struct callable_base +: callable_base_type<F>::type +{ + typedef typename callable_base_type<F>::type base; + BOOST_HOF_INHERIT_CONSTRUCTOR(callable_base, base) +}; + +template<class F> +struct callable_base_type<callable_base<F>> +: callable_base_type<F> +{}; + +#endif + +}}} // namespace boost::hof + +#endif diff --git a/boost/hof/detail/can_be_called.hpp b/boost/hof/detail/can_be_called.hpp new file mode 100644 index 0000000000..7cf6751da8 --- /dev/null +++ b/boost/hof/detail/can_be_called.hpp @@ -0,0 +1,121 @@ +/*============================================================================= + Copyright (c) 2015 Paul Fultz II + can_be_called.h + 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_HOF_GUARD_CAN_BE_CALLED_H +#define BOOST_HOF_GUARD_CAN_BE_CALLED_H + +#include <boost/hof/config.hpp> +#include <boost/hof/detail/and.hpp> +#include <boost/hof/detail/holder.hpp> +#include <boost/hof/detail/using.hpp> + +namespace boost { namespace hof { namespace detail { + +#if BOOST_HOF_NO_EXPRESSION_SFINAE +struct dont_care +{ + dont_care(...); +}; + +template<class T> +struct never_care +{ + typedef dont_care type; +}; + +struct cant_be_called_type +{}; + +struct no_type +{}; + +template<class F> +struct is_callable_wrapper_fallback +{ + template<class... Ts> + auto operator()(Ts&&...) const + -> decltype(std::declval<F>()(std::declval<Ts>()...)); +}; + +template<class T, class U=typename std::remove_cv<typename std::remove_reference<T>::type>::type> +struct is_callable_wrapper_base +: std::conditional<BOOST_HOF_IS_CLASS(U) && !BOOST_HOF_IS_FINAL(U), U, is_callable_wrapper_fallback<U>> +{}; + +template<class F, class... Ts> +struct is_callable_wrapper : is_callable_wrapper_base<F>::type +{ + is_callable_wrapper(); + typedef cant_be_called_type const &(*pointer_to_function)(typename never_care<Ts>::type...); + operator pointer_to_function() const; +}; + +template<class T> +struct not_ +: std::integral_constant<bool, !T::value> +{}; + +template<class F, class... Ts> +struct can_be_called +: not_<std::is_same<cant_be_called_type, typename std::decay<decltype( + is_callable_wrapper<F, Ts...>()(std::declval<Ts>()...) +)>::type>> +{}; + +template<class F, class... Ts> +struct check_args; + +template<class Res, class... Ts, class... Us> +struct check_args<Res(Us...), Ts...> +: and_<std::is_convertible<Ts, Us>...> +{}; + +template<class Res, class... Ts, class... Us> +struct can_be_called<Res(*)(Us...), Ts...> +: std::conditional<sizeof...(Ts) == sizeof...(Us), + check_args<Res(Us...), Ts...>, + std::false_type +>::type +{}; + +template<class Res, class... Ts, class... Us> +struct can_be_called<Res(Us...), Ts...> +: std::conditional<sizeof...(Ts) == sizeof...(Us), + check_args<Res(Us...), Ts...>, + std::false_type +>::type +{}; + +#else + +template<class T> +T&& called_val() noexcept; + +template<class... Ts> +struct callable_args +{}; + +template<class F, class Args, class=void> +struct can_be_called_impl +: std::false_type +{}; + +template<class F, class... Args> +struct can_be_called_impl<F, callable_args<Args...>, typename detail::holder< + decltype( boost::hof::detail::called_val<F>()(boost::hof::detail::called_val<Args>()...) ) +>::type> +: std::true_type +{}; + +template<class F, class... Ts> +BOOST_HOF_USING(can_be_called, can_be_called_impl<F, detail::callable_args<Ts...>>); + +#endif + +}}} // namespace boost::hof + +#endif diff --git a/boost/hof/detail/compressed_pair.hpp b/boost/hof/detail/compressed_pair.hpp new file mode 100644 index 0000000000..b7c320e2da --- /dev/null +++ b/boost/hof/detail/compressed_pair.hpp @@ -0,0 +1,130 @@ +/*============================================================================= + Copyright (c) 2015 Paul Fultz II + compressed_pair.h + 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_HOF_GUARD_COMPRESSED_PAIR_H +#define BOOST_HOF_GUARD_COMPRESSED_PAIR_H + +#include <boost/hof/detail/delegate.hpp> +#include <boost/hof/detail/move.hpp> +#include <boost/hof/detail/forward.hpp> +#include <boost/hof/config.hpp> +#include <boost/hof/always.hpp> +#include <boost/hof/alias.hpp> + +#ifndef BOOST_HOF_COMPRESSED_PAIR_USE_EBO_WORKAROUND +#define BOOST_HOF_COMPRESSED_PAIR_USE_EBO_WORKAROUND !BOOST_HOF_HAS_EBO +#endif + +namespace boost { namespace hof { namespace detail { + +template<class First, class Second, class=void> +struct compressed_pair; + +template<int I, class T, class U> +struct pair_tag +{}; + +#if BOOST_HOF_COMPRESSED_PAIR_USE_EBO_WORKAROUND + +template<class T, class U> +struct is_same_template +: std::false_type +{}; + +template<template<class...> class X, class... Ts, class... Us> +struct is_same_template<X<Ts...>, X<Us...>> +: std::true_type +{}; + +#if (defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ < 7) + +template<class T, class U> +struct is_related_template +: std::false_type +{}; + +#else + +template<class T, class U> +struct is_related_template +: is_same_template<T, U> +{}; + +#endif + +template<class T, class U> +struct is_related +: std::integral_constant<bool, std::is_base_of<T, U>::value || std::is_base_of<U, T>::value || is_related_template<T, U>::value> +{}; + +template<int I, class T, class U> +struct pair_holder +: std::conditional<( + is_related<T, U>::value), + detail::alias_empty<T, pair_tag<I, T, U>>, + detail::alias_try_inherit<T, pair_tag<I, T, U>> +>::type +{}; +#else +template<int I, class T, class U> +struct pair_holder +: detail::alias_try_inherit<T, pair_tag<I, T, U>> +{}; +#endif + +// TODO: Empty optimizations for MSVC +template< + class First, + class Second +> +struct compressed_pair<First, Second> +: pair_holder<0, First, Second>::type, pair_holder<1, Second, First>::type +{ + typedef typename pair_holder<0, First, Second>::type first_base; + typedef typename pair_holder<1, Second, First>::type second_base; + template<class X, class Y, + BOOST_HOF_ENABLE_IF_CONSTRUCTIBLE(First, X&&), + BOOST_HOF_ENABLE_IF_CONSTRUCTIBLE(Second, Y&&) + > + constexpr compressed_pair(X&& x, Y&& y) + noexcept(BOOST_HOF_IS_NOTHROW_CONSTRUCTIBLE(first_base, X&&) && BOOST_HOF_IS_NOTHROW_CONSTRUCTIBLE(second_base, Y&&)) + : first_base(BOOST_HOF_FORWARD(X)(x)), second_base(BOOST_HOF_FORWARD(Y)(y)) + {} + + BOOST_HOF_INHERIT_DEFAULT(compressed_pair, first_base, second_base) + + template<class Base, class... Xs> + constexpr const Base& get_alias_base(Xs&&... xs) const noexcept + { + return boost::hof::always_ref(*this)(xs...); + } + + template<class... Xs> + constexpr const First& first(Xs&&... xs) const noexcept + { + return boost::hof::alias_value(this->get_alias_base<first_base>(xs...), xs...); + } + + template<class... Xs> + constexpr const Second& second(Xs&&... xs) const noexcept + { + return boost::hof::alias_value(this->get_alias_base<second_base>(xs...), xs...); + } + +}; + +template<class T, class U> +constexpr compressed_pair<T, U> make_compressed_pair(T x, U y) +noexcept(BOOST_HOF_IS_NOTHROW_MOVE_CONSTRUCTIBLE(T) && BOOST_HOF_IS_NOTHROW_MOVE_CONSTRUCTIBLE(U)) +{ + return {static_cast<T&&>(x), static_cast<U&&>(y)}; +} + + +}}} // namespace boost::hof + +#endif diff --git a/boost/hof/detail/constexpr_deduce.hpp b/boost/hof/detail/constexpr_deduce.hpp new file mode 100644 index 0000000000..80bdd5ed8a --- /dev/null +++ b/boost/hof/detail/constexpr_deduce.hpp @@ -0,0 +1,74 @@ +/*============================================================================= + Copyright (c) 2015 Paul Fultz II + constexpr_deduce.h + 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_HOF_GUARD_FUNCTION_CONSTEXPR_DEDUCE_H +#define BOOST_HOF_GUARD_FUNCTION_CONSTEXPR_DEDUCE_H + +#include <boost/hof/config.hpp> + +#define BOOST_HOF_CONST_FOLD(x) (__builtin_constant_p(x) ? (x) : (x)) + +#ifndef BOOST_HOF_HAS_CONST_FOLD +#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ < 7 +#define BOOST_HOF_HAS_CONST_FOLD 0 +#elif defined(__clang__) || defined (__GNUC__) +#define BOOST_HOF_HAS_CONST_FOLD 1 +#else +#define BOOST_HOF_HAS_CONST_FOLD 0 +#endif +#endif + + +namespace boost { namespace hof { + +namespace detail { + +struct constexpr_deduce +{ + constexpr constexpr_deduce() + {} + template<class F> + constexpr operator F() const + { + return F(); + } +}; + +template<class T> +struct constexpr_deduce_unique +{ + constexpr constexpr_deduce_unique() + {} +#if BOOST_HOF_HAS_CONST_FOLD + template<class F> + constexpr operator const F&() const + { + static_assert(BOOST_HOF_IS_EMPTY(F), "Function or lambda expression must be empty"); + return BOOST_HOF_CONST_FOLD(reinterpret_cast<const F&>(static_const_var<T>())); + } +#else + template<class F> + constexpr operator F() const + { + // static_assert(std::is_default_constructible<F>::value, "Function not default constructible"); + return F(); + } +#endif +}; + +}}} // namespace boost::hof + +#define BOOST_HOF_DETAIL_CONSTEXPR_DEDUCE true ? boost::hof::detail::constexpr_deduce() : +#define BOOST_HOF_DETAIL_CONSTEXPR_DEDUCE_UNIQUE(T) true ? boost::hof::detail::constexpr_deduce_unique<T>() : + +#ifdef _MSC_VER +#define BOOST_HOF_DETAIL_MSVC_CONSTEXPR_DEDUCE BOOST_HOF_DETAIL_CONSTEXPR_DEDUCE +#else +#define BOOST_HOF_DETAIL_MSVC_CONSTEXPR_DEDUCE +#endif + +#endif diff --git a/boost/hof/detail/delegate.hpp b/boost/hof/detail/delegate.hpp new file mode 100644 index 0000000000..af2179680d --- /dev/null +++ b/boost/hof/detail/delegate.hpp @@ -0,0 +1,107 @@ +/*============================================================================= + Copyright (c) 2012 Paul Fultz II + delgate.h + 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_HOF_GUARD_FUNCTION_DELGATE_H +#define BOOST_HOF_GUARD_FUNCTION_DELGATE_H + +#include <type_traits> +#include <utility> +#include <boost/hof/config.hpp> +#include <boost/hof/detail/and.hpp> +#include <boost/hof/detail/holder.hpp> +#include <boost/hof/detail/forward.hpp> +#include <boost/hof/detail/using.hpp> +#include <boost/hof/detail/intrinsics.hpp> +#include <boost/hof/detail/noexcept.hpp> + + +#define BOOST_HOF_ENABLE_IF_CONVERTIBLE(...) \ + class=typename std::enable_if<BOOST_HOF_IS_CONVERTIBLE(__VA_ARGS__)>::type + +#define BOOST_HOF_ENABLE_IF_CONVERTIBLE_UNPACK(...) \ + class=typename std::enable_if<BOOST_HOF_AND_UNPACK(BOOST_HOF_IS_CONVERTIBLE(__VA_ARGS__))>::type + +#define BOOST_HOF_ENABLE_IF_BASE_OF(...) \ + class=typename std::enable_if<BOOST_HOF_IS_BASE_OF(__VA_ARGS__)>::type + +#define BOOST_HOF_ENABLE_IF_CONSTRUCTIBLE(...) \ + class=typename std::enable_if<BOOST_HOF_IS_CONSTRUCTIBLE(__VA_ARGS__)>::type + +#define BOOST_HOF_NOEXCEPT_CONSTRUCTIBLE(...) \ + BOOST_HOF_NOEXCEPT(BOOST_HOF_IS_NOTHROW_CONSTRUCTIBLE(__VA_ARGS__)) + +#define BOOST_HOF_INHERIT_DEFAULT(C, ...) \ + template<bool FitPrivateEnableBool_##__LINE__=true, \ + class=typename std::enable_if<FitPrivateEnableBool_##__LINE__ && boost::hof::detail::is_default_constructible_c<__VA_ARGS__>()>::type> \ + constexpr C() BOOST_HOF_NOEXCEPT(boost::hof::detail::is_nothrow_default_constructible_c<__VA_ARGS__>()) {} + +#define BOOST_HOF_INHERIT_DEFAULT_EMPTY(C, ...) \ + template<bool FitPrivateEnableBool_##__LINE__=true, \ + class=typename std::enable_if<FitPrivateEnableBool_##__LINE__ && \ + boost::hof::detail::is_default_constructible_c<__VA_ARGS__>() && BOOST_HOF_IS_EMPTY(__VA_ARGS__) \ + >::type> \ + constexpr C() BOOST_HOF_NOEXCEPT(boost::hof::detail::is_nothrow_default_constructible_c<__VA_ARGS__>()) {} + +#if BOOST_HOF_NO_TYPE_PACK_EXPANSION_IN_TEMPLATE + +#define BOOST_HOF_DELGATE_PRIMITIVE_CONSTRUCTOR(constexpr_, C, T, var) \ + template<class... FitXs, typename boost::hof::detail::enable_if_constructible<C, T, FitXs...>::type = 0> \ + constexpr_ C(FitXs&&... fit_xs) \ + BOOST_HOF_NOEXCEPT_CONSTRUCTIBLE(T, FitXs&&...) \ + : var((FitXs&&)boost::hof::forward<FitXs>(fit_xs)...) {} + +#else +#define BOOST_HOF_DELGATE_PRIMITIVE_CONSTRUCTOR(constexpr_, C, T, var) \ + template<class... FitXs, BOOST_HOF_ENABLE_IF_CONSTRUCTIBLE(T, FitXs&&...)> \ + constexpr_ C(FitXs&&... fit_xs) \ + BOOST_HOF_NOEXCEPT_CONSTRUCTIBLE(T, FitXs&&...) \ + : var(BOOST_HOF_FORWARD(FitXs)(fit_xs)...) {} + +#endif + +#define BOOST_HOF_DELEGATE_CONSTRUCTOR(C, T, var) BOOST_HOF_DELGATE_PRIMITIVE_CONSTRUCTOR(constexpr, C, T, var) + +// Currently its faster to use `BOOST_HOF_DELEGATE_CONSTRUCTOR` than `using +// Base::Base;` +#if 1 +#define BOOST_HOF_INHERIT_CONSTRUCTOR(Derived, Base) BOOST_HOF_DELEGATE_CONSTRUCTOR(Derived, Base, Base) +#else +#define BOOST_HOF_INHERIT_CONSTRUCTOR(Derived, Base) \ + using fit_inherit_base = Base; \ + using fit_inherit_base::fit_inherit_base; \ + Derived()=default; \ + template<class FitX, BOOST_HOF_ENABLE_IF_CONVERTIBLE(FitX, Base)> \ + constexpr Derived(FitX&& fit_x) : Base(BOOST_HOF_FORWARD(FitX)(fit_x)) {} +#endif + +namespace boost { namespace hof { +namespace detail { + +template<class... Xs> +constexpr bool is_nothrow_default_constructible_c() +{ + return BOOST_HOF_AND_UNPACK(BOOST_HOF_IS_NOTHROW_CONSTRUCTIBLE(Xs)); +} + +template<class... Xs> +constexpr bool is_default_constructible_c() +{ + return BOOST_HOF_AND_UNPACK(BOOST_HOF_IS_DEFAULT_CONSTRUCTIBLE(Xs)); +} + +template<class... Xs> +BOOST_HOF_USING(is_default_constructible, std::integral_constant<bool, is_default_constructible_c<Xs...>()>); + +template<class C, class X, class... Xs> +struct enable_if_constructible +: std::enable_if<is_constructible<X, Xs&&...>::value, int> +{}; + +} +}} // namespace boost::hof + +#endif diff --git a/boost/hof/detail/forward.hpp b/boost/hof/detail/forward.hpp new file mode 100644 index 0000000000..729436c4aa --- /dev/null +++ b/boost/hof/detail/forward.hpp @@ -0,0 +1,37 @@ +/*============================================================================= + Copyright (c) 2014 Paul Fultz II + forward.h + 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_HOF_GUARD_FORWARD_H +#define BOOST_HOF_GUARD_FORWARD_H + +#include <utility> + +namespace boost { namespace hof { + +// contexpr-friendly forwarding + +template<typename T> +constexpr T&& forward(typename std::remove_reference<T>::type& t) noexcept +{ return static_cast<T&&>(t); } + + +template<typename T> +constexpr T&& forward(typename std::remove_reference<T>::type&& t) noexcept +{ + static_assert(!std::is_lvalue_reference<T>::value, "T must not be an lvalue reference type"); + return static_cast<T&&>(t); +} + +#if (defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ < 7) || defined(_MSC_VER) +#define BOOST_HOF_FORWARD(...) boost::hof::forward<__VA_ARGS__> +#else +#define BOOST_HOF_FORWARD(...) static_cast<__VA_ARGS__ &&> +#endif + +}} // namespace boost::hof + +#endif diff --git a/boost/hof/detail/holder.hpp b/boost/hof/detail/holder.hpp new file mode 100644 index 0000000000..4a7aed2093 --- /dev/null +++ b/boost/hof/detail/holder.hpp @@ -0,0 +1,27 @@ +/*============================================================================= + Copyright (c) 2014 Paul Fultz II + holder.h + 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_HOF_GUARD_HOLDER_H +#define BOOST_HOF_GUARD_HOLDER_H + +namespace boost { namespace hof { namespace detail { + +template<class... Ts> +struct holder +{ + typedef void type; +}; + +template<template<class...> class T> +struct template_holder +{ + typedef void type; +}; + +}}} // namespace boost::hof + +#endif diff --git a/boost/hof/detail/intrinsics.hpp b/boost/hof/detail/intrinsics.hpp new file mode 100644 index 0000000000..1ace7d6882 --- /dev/null +++ b/boost/hof/detail/intrinsics.hpp @@ -0,0 +1,113 @@ +/*============================================================================= + Copyright (c) 2016 Paul Fultz II + intrinsics.hpp + 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_HOF_GUARD_INTRINSICS_HPP +#define BOOST_HOF_GUARD_INTRINSICS_HPP + +#include <type_traits> +#include <boost/hof/detail/holder.hpp> +#include <boost/hof/config.hpp> + +// *** clang *** +#if defined(__clang__) +// #define BOOST_HOF_IS_CONSTRUCTIBLE(...) std::is_constructible<__VA_ARGS__>::value +// #define BOOST_HOF_IS_NOTHROW_CONSTRUCTIBLE(...) std::is_nothrow_constructible<__VA_ARGS__>::value +// #define BOOST_HOF_IS_CONVERTIBLE(...) std::is_convertible<__VA_ARGS__>::value +#define BOOST_HOF_IS_CONSTRUCTIBLE(...) __is_constructible(__VA_ARGS__) +#define BOOST_HOF_IS_NOTHROW_CONSTRUCTIBLE(...) __is_nothrow_constructible(__VA_ARGS__) +#define BOOST_HOF_IS_CONVERTIBLE(...) __is_convertible_to(__VA_ARGS__) +#define BOOST_HOF_IS_BASE_OF(...) __is_base_of(__VA_ARGS__) +#define BOOST_HOF_IS_CLASS(...) __is_class(__VA_ARGS__) +#define BOOST_HOF_IS_EMPTY(...) __is_empty(__VA_ARGS__) +#define BOOST_HOF_IS_LITERAL(...) __is_literal(__VA_ARGS__) +#define BOOST_HOF_IS_POLYMORPHIC(...) __is_polymorphic(__VA_ARGS__) +#define BOOST_HOF_IS_FINAL(...) __is_final(__VA_ARGS__) +#define BOOST_HOF_IS_NOTHROW_COPY_CONSTRUCTIBLE(...) __has_nothrow_copy(__VA_ARGS__) +// *** gcc *** +#elif defined(__GNUC__) +#define BOOST_HOF_IS_CONSTRUCTIBLE(...) std::is_constructible<__VA_ARGS__>::value +#define BOOST_HOF_IS_NOTHROW_CONSTRUCTIBLE(...) std::is_nothrow_constructible<__VA_ARGS__>::value +#define BOOST_HOF_IS_CONVERTIBLE(...) std::is_convertible<__VA_ARGS__>::value +#define BOOST_HOF_IS_BASE_OF(...) __is_base_of(__VA_ARGS__) +#define BOOST_HOF_IS_CLASS(...) __is_class(__VA_ARGS__) +#define BOOST_HOF_IS_EMPTY(...) __is_empty(__VA_ARGS__) +#define BOOST_HOF_IS_LITERAL(...) __is_literal_type(__VA_ARGS__) +#define BOOST_HOF_IS_POLYMORPHIC(...) __is_polymorphic(__VA_ARGS__) +#define BOOST_HOF_IS_NOTHROW_COPY_CONSTRUCTIBLE(...) __has_nothrow_copy(__VA_ARGS__) +#if __GNUC__ == 4 && __GNUC_MINOR__ < 7 +#define BOOST_HOF_IS_FINAL(...) (false) +#else +#define BOOST_HOF_IS_FINAL(...) __is_final(__VA_ARGS__) +#endif +#define BOOST_HOF_IS_NOTHROW_COPY_CONSTRUCTIBLE(...) __has_nothrow_copy(__VA_ARGS__) +// *** other *** +#else +#define BOOST_HOF_IS_CONSTRUCTIBLE(...) std::is_constructible<__VA_ARGS__>::value +#define BOOST_HOF_IS_NOTHROW_CONSTRUCTIBLE(...) std::is_nothrow_constructible<__VA_ARGS__>::value +#define BOOST_HOF_IS_CONVERTIBLE(...) std::is_convertible<__VA_ARGS__>::value +#define BOOST_HOF_IS_BASE_OF(...) std::is_base_of<__VA_ARGS__>::value +#define BOOST_HOF_IS_CLASS(...) std::is_class<__VA_ARGS__>::value +#define BOOST_HOF_IS_EMPTY(...) std::is_empty<__VA_ARGS__>::value +#define BOOST_HOF_IS_LITERAL(...) std::is_literal_type<__VA_ARGS__>::value +#define BOOST_HOF_IS_POLYMORPHIC(...) std::is_polymorphic<__VA_ARGS__>::value +#if defined(_MSC_VER) +#define BOOST_HOF_IS_NOTHROW_COPY_CONSTRUCTIBLE(...) (std::is_nothrow_copy_constructible<__VA_ARGS__>::value || std::is_reference<__VA_ARGS__>::value) +#else +#define BOOST_HOF_IS_NOTHROW_COPY_CONSTRUCTIBLE(...) std::is_nothrow_copy_constructible<__VA_ARGS__>::value +#endif +#if defined(_MSC_VER) +#define BOOST_HOF_IS_FINAL(...) __is_final(__VA_ARGS__) +#else +#define BOOST_HOF_IS_FINAL(...) (false) +#endif +#endif + +#if BOOST_HOF_NO_STD_DEFAULT_CONSTRUCTIBLE +#define BOOST_HOF_IS_DEFAULT_CONSTRUCTIBLE(...) boost::hof::detail::is_default_constructible_helper<__VA_ARGS__>::value +#else +#define BOOST_HOF_IS_DEFAULT_CONSTRUCTIBLE BOOST_HOF_IS_CONSTRUCTIBLE +#endif + +#define BOOST_HOF_IS_NOTHROW_MOVE_CONSTRUCTIBLE(...) BOOST_HOF_IS_NOTHROW_CONSTRUCTIBLE(__VA_ARGS__, __VA_ARGS__ &&) + +namespace boost { namespace hof { namespace detail { + +template<class T, class=void> +struct is_default_constructible_check +: std::false_type +{}; + +template<class T> +struct is_default_constructible_check<T, typename holder< + decltype(T()) +>::type> +: std::true_type +{}; + +template<class T> +struct is_default_constructible_helper +: std::conditional<(std::is_reference<T>::value), + std::false_type, + is_default_constructible_check<T> +>::type +{}; + +template<class T, class... Xs> +struct is_constructible +: std::is_constructible<T, Xs...> +{}; + +template<class T> +struct is_constructible<T> +: is_default_constructible_helper<T> +{}; + +} + +}} // namespace boost::hof + +#endif diff --git a/boost/hof/detail/join.hpp b/boost/hof/detail/join.hpp new file mode 100644 index 0000000000..23ed8437d3 --- /dev/null +++ b/boost/hof/detail/join.hpp @@ -0,0 +1,43 @@ +/*============================================================================= + Copyright (c) 2012 Paul Fultz II + join.h + 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_HOF_GUARD_FUNCTION_DETAIL_JOIN_H +#define BOOST_HOF_GUARD_FUNCTION_DETAIL_JOIN_H + +#include <boost/hof/detail/holder.hpp> + +namespace boost { namespace hof { namespace detail { + +template<class... Ts> +struct join_args +{}; + +template<template <class...> class T, class Args, class=void> +struct join_impl +{}; + +template<template <class...> class T, class... Args> +struct join_impl<T, join_args<Args...>, typename holder< + T<Args...> +>::type> +{ typedef T<Args...> type; }; + +template<template <class...> class T, class... Args> +struct join +: join_impl<T, join_args<Args...>> +{}; + +}}} // namespace boost::hof + +#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ < 7 +#define BOOST_HOF_JOIN(c, ...) typename boost::hof::detail::join<c, __VA_ARGS__>::type +#else +#define BOOST_HOF_JOIN(c, ...) c<__VA_ARGS__> + +#endif + +#endif diff --git a/boost/hof/detail/make.hpp b/boost/hof/detail/make.hpp new file mode 100644 index 0000000000..791e1283a2 --- /dev/null +++ b/boost/hof/detail/make.hpp @@ -0,0 +1,31 @@ +/*============================================================================= + Copyright (c) 2015 Paul Fultz II + make.h + 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_HOF_GUARD_MAKE_H +#define BOOST_HOF_GUARD_MAKE_H + +#include <boost/hof/detail/move.hpp> +#include <boost/hof/detail/join.hpp> +#include <boost/hof/detail/delegate.hpp> + +namespace boost { namespace hof { namespace detail { + +template<template<class...> class Adaptor> +struct make +{ + constexpr make() noexcept + {} + template<class... Fs, class Result=BOOST_HOF_JOIN(Adaptor, Fs...)> + constexpr Result operator()(Fs... fs) const BOOST_HOF_NOEXCEPT_CONSTRUCTIBLE(Result, Fs&&...) + { + return Result(static_cast<Fs&&>(fs)...); + } +}; + +}}} // namespace boost::hof + +#endif diff --git a/boost/hof/detail/move.hpp b/boost/hof/detail/move.hpp new file mode 100644 index 0000000000..bdbf73ddc7 --- /dev/null +++ b/boost/hof/detail/move.hpp @@ -0,0 +1,24 @@ +/*============================================================================= + Copyright (c) 2014 Paul Fultz II + move.h + 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_HOF_GUARD_MOVE_H +#define BOOST_HOF_GUARD_MOVE_H + +#include <utility> + +namespace boost { namespace hof { + +template<typename T> +constexpr typename std::remove_reference<T>::type&& +move(T&& x) noexcept +{ + return static_cast<typename std::remove_reference<T>::type&&>(x); +} + +}} // namespace boost::hof + +#endif diff --git a/boost/hof/detail/noexcept.hpp b/boost/hof/detail/noexcept.hpp new file mode 100644 index 0000000000..c7078a8b27 --- /dev/null +++ b/boost/hof/detail/noexcept.hpp @@ -0,0 +1,19 @@ +/*============================================================================= + Copyright (c) 2016 Paul Fultz II + noexcept.hpp + 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_HOF_GUARD_DETAIL_NOEXCEPT_HPP +#define BOOST_HOF_GUARD_DETAIL_NOEXCEPT_HPP + +#include <boost/hof/config.hpp> + +#if BOOST_HOF_HAS_NOEXCEPT_DEDUCTION +#define BOOST_HOF_NOEXCEPT(...) noexcept(__VA_ARGS__) +#else +#define BOOST_HOF_NOEXCEPT(...) +#endif + +#endif diff --git a/boost/hof/detail/pp.hpp b/boost/hof/detail/pp.hpp new file mode 100644 index 0000000000..20bc7a960e --- /dev/null +++ b/boost/hof/detail/pp.hpp @@ -0,0 +1,93 @@ +/*============================================================================= + Copyright (c) 2014 Paul Fultz II + pp.h + 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_HOF_GUARD_PP_H +#define BOOST_HOF_GUARD_PP_H + +#define BOOST_HOF_PP_CAT(x, y) BOOST_HOF_PP_PRIMITIVE_CAT(x, y) +#define BOOST_HOF_PP_PRIMITIVE_CAT(x, y) x ## y + +#define BOOST_HOF_PP_SEQ_ITERATE(...) BOOST_HOF_PP_PRIMITIVE_SEQ_ITERATE(__VA_ARGS__) +#define BOOST_HOF_PP_PRIMITIVE_SEQ_ITERATE(...) __VA_ARGS__ ## _END + +// +// BOOST_HOF_PP_NARGS returns the number of args in __VA_ARGS__ +// +#define BOOST_HOF_PP_NARGS(...) \ + BOOST_HOF_PP_DETAIL_NARG((__VA_ARGS__,BOOST_HOF_PP_DETAIL_RSEQ_N())) + +#define BOOST_HOF_PP_DETAIL_NARG(args) \ + BOOST_HOF_PP_DETAIL_ARG_N args + +#define BOOST_HOF_PP_DETAIL_ARG_N( \ + _1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \ + _11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \ + _21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \ + _31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \ + _41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \ + _51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \ + _61,_62,_63,N,...) N +#define BOOST_HOF_PP_DETAIL_RSEQ_N() \ + 63,62,61,60, \ + 59,58,57,56,55,54,53,52,51,50, \ + 49,48,47,46,45,44,43,42,41,40, \ + 39,38,37,36,35,34,33,32,31,30, \ + 29,28,27,26,25,24,23,22,21,20, \ + 19,18,17,16,15,14,13,12,11,10, \ + 9,8,7,6,5,4,3,2,1,0 + + +// +// BOOST_HOF_PP_IS_PAREN is used to detect if the first token is a parenthesis. +// It expands to 1 if it is, otherwise it expands to 0. +// +#define BOOST_HOF_PP_IS_PAREN(x) BOOST_HOF_PP_IS_PAREN_CHECK(BOOST_HOF_PP_IS_PAREN_PROBE x) +#define BOOST_HOF_PP_IS_PAREN_CHECK(...) BOOST_HOF_PP_IS_PAREN_CHECK_N(__VA_ARGS__,0) +#define BOOST_HOF_PP_IS_PAREN_PROBE(...) ~, 1, +#ifndef _MSC_VER +#define BOOST_HOF_PP_IS_PAREN_CHECK_N(x, n, ...) n +#else +// MSVC workarounds +#define BOOST_HOF_PP_IS_PAREN_CHECK_RES(x) x +#define BOOST_HOF_PP_IS_PAREN_CHECK_II(x, n, ...) n +#define BOOST_HOF_PP_IS_PAREN_CHECK_I(x) BOOST_HOF_PP_IS_PAREN_CHECK_RES(BOOST_HOF_PP_IS_PAREN_CHECK_II x) +#define BOOST_HOF_PP_IS_PAREN_CHECK_N(...) BOOST_HOF_PP_IS_PAREN_CHECK_I((__VA_ARGS__)) +#endif + +// +// BOOST_HOF_PP_IS_1 is used to detect if the first token is a 1. +// It expands to 1 if it is, otherwise it expands to 0. +// +#define BOOST_HOF_PP_IS_1(x) BOOST_HOF_PP_IS_PAREN(BOOST_HOF_PP_CAT(BOOST_HOF_PP_IS_1_PROBE_, x)) +#define BOOST_HOF_PP_IS_1_PROBE_1 () + +#define BOOST_HOF_PP_ARGS_IS_SINGLE(...) BOOST_HOF_PP_IS_1(BOOST_HOF_PP_NARGS(__VA_ARGS__)) + +#define BOOST_HOF_PP_EMPTY(...) +#define BOOST_HOF_PP_DEFER(...) __VA_ARGS__ BOOST_HOF_PP_EMPTY() +#define BOOST_HOF_PP_OBSTRUCT(...) __VA_ARGS__ BOOST_HOF_PP_DEFER(BOOST_HOF_PP_EMPTY)() +#define BOOST_HOF_PP_EXPAND(...) __VA_ARGS__ + +#define BOOST_HOF_PP_IIF(c) BOOST_HOF_PP_PRIMITIVE_CAT(BOOST_HOF_PP_IIF_, c) +#define BOOST_HOF_PP_IIF_0(t, ...) __VA_ARGS__ +#define BOOST_HOF_PP_IIF_1(t, ...) t + +#define BOOST_HOF_PP_WALL(...) __VA_ARGS__ + +#define BOOST_HOF_PP_RAIL_IIF(c) BOOST_HOF_PP_PRIMITIVE_CAT(BOOST_HOF_PP_RAIL_IIF_, c) +#define BOOST_HOF_PP_RAIL_IIF_0(t, ...) __VA_ARGS__ +#define BOOST_HOF_PP_RAIL_IIF_1(t, ...) t + +#define BOOST_HOF_PP_RAIL(macro) \ + BOOST_HOF_PP_RAIL_IIF(BOOST_HOF_PP_IS_PAREN(BOOST_HOF_PP_WALL(())))( \ + BOOST_HOF_PP_RAIL_ID BOOST_HOF_PP_OBSTRUCT()()(macro), \ + macro BOOST_HOF_PP_OBSTRUCT() \ + ) + +#define BOOST_HOF_PP_RAIL_ID() BOOST_HOF_PP_RAIL + +#endif diff --git a/boost/hof/detail/recursive_constexpr_depth.hpp b/boost/hof/detail/recursive_constexpr_depth.hpp new file mode 100644 index 0000000000..1f4e630d35 --- /dev/null +++ b/boost/hof/detail/recursive_constexpr_depth.hpp @@ -0,0 +1,19 @@ +/*============================================================================= + Copyright (c) 2016 Paul Fultz II + recursive_constexpr_depth.hpp + 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_HOF_GUARD_RECURSIVE_CONSTEXPR_DEPTH_HPP +#define BOOST_HOF_GUARD_RECURSIVE_CONSTEXPR_DEPTH_HPP + +#ifndef BOOST_HOF_RECURSIVE_CONSTEXPR_DEPTH +#define BOOST_HOF_RECURSIVE_CONSTEXPR_DEPTH 16 +#endif + +namespace boost { namespace hof { + +}} // namespace boost::hof + +#endif diff --git a/boost/hof/detail/remove_rvalue_reference.hpp b/boost/hof/detail/remove_rvalue_reference.hpp new file mode 100644 index 0000000000..7de2879eaf --- /dev/null +++ b/boost/hof/detail/remove_rvalue_reference.hpp @@ -0,0 +1,26 @@ +/*============================================================================= + Copyright (c) 2014 Paul Fultz II + remove_rvalue_reference.h + 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_HOF_GUARD_FUNCTION_REMOVE_RVALUE_REFERENCE_H +#define BOOST_HOF_GUARD_FUNCTION_REMOVE_RVALUE_REFERENCE_H + +namespace boost { namespace hof { namespace detail { + +template<class T> +struct remove_rvalue_reference +{ + typedef T type; +}; + +template<class T> +struct remove_rvalue_reference<T&&> +: remove_rvalue_reference<T> +{}; + +}}} // namespace boost::hof + +#endif diff --git a/boost/hof/detail/result_of.hpp b/boost/hof/detail/result_of.hpp new file mode 100644 index 0000000000..6beccb9d2d --- /dev/null +++ b/boost/hof/detail/result_of.hpp @@ -0,0 +1,82 @@ +/*============================================================================= + Copyright (c) 2015 Paul Fultz II + result_of.h + 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_HOF_GUARD_DETAIL_RESULT_OF_H +#define BOOST_HOF_GUARD_DETAIL_RESULT_OF_H + +#include <boost/hof/returns.hpp> +#include <boost/hof/config.hpp> + +#if BOOST_HOF_HAS_MANUAL_DEDUCTION || BOOST_HOF_NO_EXPRESSION_SFINAE + +#include <boost/hof/detail/and.hpp> +#include <boost/hof/detail/holder.hpp> +#include <boost/hof/detail/can_be_called.hpp> + +namespace boost { namespace hof { namespace detail { + +template<class F, class Args, class=void> +struct result_of_impl {}; + +template<class F, class... Ts> +struct result_of_impl< + F, + holder<Ts...>, + typename std::enable_if<can_be_called<F, typename Ts::type...>::value>::type +> +{ + typedef decltype(std::declval<F>()(std::declval<typename Ts::type>()...)) type; +}; +} + +template<class T> +struct id_ +{ + typedef T type; +}; + +template<class F, class... Ts> +struct result_of +: detail::result_of_impl<F, detail::holder<Ts...>> +{}; + +// template<class F, class... Ts> +// using result_of = detail::result_of_impl<F, detail::holder<Ts...>>; +// using result_of = id_<decltype(std::declval<F>()(std::declval<typename Ts::type>()...))>; + +}} // namespace boost::hof +#endif + +#if BOOST_HOF_NO_EXPRESSION_SFINAE + +#define BOOST_HOF_SFINAE_RESULT(...) typename boost::hof::result_of<__VA_ARGS__>::type +#define BOOST_HOF_SFINAE_RETURNS(...) BOOST_HOF_RETURNS_DEDUCE_NOEXCEPT(__VA_ARGS__) { return __VA_ARGS__; } + +#else + +#define BOOST_HOF_SFINAE_RESULT(...) auto +#define BOOST_HOF_SFINAE_RETURNS BOOST_HOF_RETURNS + +#endif + +#if BOOST_HOF_HAS_MANUAL_DEDUCTION + +#define BOOST_HOF_SFINAE_MANUAL_RESULT(...) typename boost::hof::result_of<__VA_ARGS__>::type +#if BOOST_HOF_HAS_COMPLETE_DECLTYPE && BOOST_HOF_HAS_MANGLE_OVERLOAD +#define BOOST_HOF_SFINAE_MANUAL_RETURNS(...) BOOST_HOF_RETURNS_DEDUCE_NOEXCEPT(__VA_ARGS__) { return (__VA_ARGS__); } +#else +#define BOOST_HOF_SFINAE_MANUAL_RETURNS(...) BOOST_HOF_RETURNS_DEDUCE_NOEXCEPT(__VA_ARGS__) { BOOST_HOF_RETURNS_RETURN(__VA_ARGS__); } +#endif + +#else + +#define BOOST_HOF_SFINAE_MANUAL_RESULT BOOST_HOF_SFINAE_RESULT +#define BOOST_HOF_SFINAE_MANUAL_RETURNS BOOST_HOF_SFINAE_RETURNS + +#endif + +#endif diff --git a/boost/hof/detail/result_type.hpp b/boost/hof/detail/result_type.hpp new file mode 100644 index 0000000000..ce570baab6 --- /dev/null +++ b/boost/hof/detail/result_type.hpp @@ -0,0 +1,43 @@ +/*============================================================================= + Copyright (c) 2016 Paul Fultz II + result_type.hpp + 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_HOF_GUARD_RESULT_TYPE_HPP +#define BOOST_HOF_GUARD_RESULT_TYPE_HPP + +#include <boost/hof/detail/holder.hpp> +#include <utility> + +namespace boost { namespace hof { namespace detail { + +template<class F, class=void> +struct function_result_type +{}; + +template<class F> +struct function_result_type<F, typename holder< + typename F::result_type +>::type> +{ + typedef typename F::result_type result_type; +}; + +template<class F, class G, class=void> +struct compose_function_result_type +: function_result_type<F> +{}; + +template<class F, class G> +struct compose_function_result_type<F, G, typename holder< + decltype(std::declval<F>()(std::declval<typename G::result_type>())) +>::type> +{ + typedef decltype(std::declval<F>()(std::declval<typename G::result_type>())) result_type; +}; + +}}} // namespace boost::hof + +#endif diff --git a/boost/hof/detail/seq.hpp b/boost/hof/detail/seq.hpp new file mode 100644 index 0000000000..9f9f686c1a --- /dev/null +++ b/boost/hof/detail/seq.hpp @@ -0,0 +1,46 @@ +/*============================================================================= + Copyright (c) 2012 Paul Fultz II + seq.h + 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_HOF_GUARD_FUNCTION_DETAIL_SEQ_H +#define BOOST_HOF_GUARD_FUNCTION_DETAIL_SEQ_H + +#include <cstdlib> + +namespace boost { namespace hof { + +namespace detail { + +template<std::size_t ...> +struct seq +{ + typedef seq type; +}; + +template <class, class> +struct merge_seq; + +template <size_t... Xs, size_t... Ys> +struct merge_seq<seq<Xs...>, seq<Ys...>> +: seq<Xs..., (sizeof...(Xs)+Ys)...> +{}; + +template<std::size_t N> +struct gens +: merge_seq< + typename gens<N/2>::type, + typename gens<N - N/2>::type +> +{}; + +template<> struct gens<0> : seq<> {}; +template<> struct gens<1> : seq<0> {}; + + +} +}} // namespace boost::hof + +#endif diff --git a/boost/hof/detail/static_const_var.hpp b/boost/hof/detail/static_const_var.hpp new file mode 100644 index 0000000000..553bd23294 --- /dev/null +++ b/boost/hof/detail/static_const_var.hpp @@ -0,0 +1,68 @@ +/*============================================================================= + Copyright (c) 2015 Paul Fultz II + static_const_var.h + 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_HOF_GUARD_STATIC_CONST_H +#define BOOST_HOF_GUARD_STATIC_CONST_H + +#include <boost/hof/detail/intrinsics.hpp> + +namespace boost { namespace hof { namespace detail { + +template<class T> +struct static_const_storage +{ + static constexpr T value = T(); +}; + +template<class T> +constexpr T static_const_storage<T>::value; + +struct static_const_var_factory +{ + constexpr static_const_var_factory() + {} + + template<class T> + constexpr const T& operator=(const T&) const + { + static_assert(BOOST_HOF_IS_DEFAULT_CONSTRUCTIBLE(T), "Static const variable must be default constructible"); + return static_const_storage<T>::value; + } +}; +} + +template<class T> +constexpr const T& static_const_var() +{ + return detail::static_const_storage<T>::value; +} + + +}} // namespace boost::hof + +#if BOOST_HOF_HAS_RELAXED_CONSTEXPR || defined(_MSC_VER) +#define BOOST_HOF_STATIC_CONSTEXPR const constexpr +#else +#define BOOST_HOF_STATIC_CONSTEXPR static constexpr +#endif + +#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ < 7 +#define BOOST_HOF_STATIC_AUTO_REF extern __attribute__((weak)) constexpr auto +#else +#define BOOST_HOF_STATIC_AUTO_REF static constexpr auto& +#endif + +// On gcc 4.6 use weak variables +#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ < 7 +#define BOOST_HOF_STATIC_CONST_VAR(name) extern __attribute__((weak)) constexpr auto name +#else +#define BOOST_HOF_STATIC_CONST_VAR(name) static constexpr auto& name = boost::hof::detail::static_const_var_factory() +#endif + +#define BOOST_HOF_DECLARE_STATIC_VAR(name, ...) BOOST_HOF_STATIC_CONST_VAR(name) = __VA_ARGS__{} + +#endif diff --git a/boost/hof/detail/unpack_tuple.hpp b/boost/hof/detail/unpack_tuple.hpp new file mode 100644 index 0000000000..19b0e853f8 --- /dev/null +++ b/boost/hof/detail/unpack_tuple.hpp @@ -0,0 +1,98 @@ +/*============================================================================= + Copyright (c) 2016 Paul Fultz II + unpack_tuple.hpp + 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_HOF_GUARD_UNPACK_TUPLE_HPP +#define BOOST_HOF_GUARD_UNPACK_TUPLE_HPP + +#include <boost/hof/unpack_sequence.hpp> +#include <boost/hof/returns.hpp> +#include <boost/hof/detail/forward.hpp> +#include <boost/hof/detail/seq.hpp> +#include <tuple> +#include <array> + +namespace boost { namespace hof { + +namespace detail { + +template<class Sequence> +constexpr typename gens<std::tuple_size<Sequence>::value>::type +make_tuple_gens(const Sequence&) +{ + return {}; +} + +#if (defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ < 7) + +template<std::size_t I, class Tuple> +struct tuple_element_return +: std::tuple_element<I, Tuple> +{}; + +template<std::size_t I, class Tuple> +struct tuple_element_return<I, Tuple&> +: std::add_lvalue_reference<typename tuple_element_return<I, Tuple>::type> +{}; + +template<std::size_t I, class Tuple> +struct tuple_element_return<I, Tuple&&> +: std::add_rvalue_reference<typename tuple_element_return<I, Tuple>::type> +{}; + +template<std::size_t I, class Tuple> +struct tuple_element_return<I, const Tuple> +: std::add_const<typename tuple_element_return<I, Tuple>::type> +{}; + +template< std::size_t I, class Tuple, class R = typename tuple_element_return<I, Tuple&&>::type > +R tuple_get( Tuple&& t ) +{ + return (R&&)(std::get<I>(boost::hof::forward<Tuple>(t))); +} +#define BOOST_HOF_UNPACK_TUPLE_GET boost::hof::detail::tuple_get +#else +#define BOOST_HOF_UNPACK_TUPLE_GET std::get + +#endif + +template<class F, class T, std::size_t ...N> +constexpr auto unpack_tuple(F&& f, T&& t, seq<N...>) BOOST_HOF_RETURNS +( + f( + BOOST_HOF_AUTO_FORWARD(BOOST_HOF_UNPACK_TUPLE_GET<N>(BOOST_HOF_AUTO_FORWARD(t)))... + ) +); + +struct unpack_tuple_apply +{ + template<class F, class S> + constexpr static auto apply(F&& f, S&& t) BOOST_HOF_RETURNS + ( + boost::hof::detail::unpack_tuple(BOOST_HOF_FORWARD(F)(f), BOOST_HOF_FORWARD(S)(t), boost::hof::detail::make_tuple_gens(t)) + ); +}; + +} + +template<class... Ts> +struct unpack_sequence<std::tuple<Ts...>> +: detail::unpack_tuple_apply +{}; + +template<class T, class U> +struct unpack_sequence<std::pair<T, U>> +: detail::unpack_tuple_apply +{}; + +template<class T, std::size_t N> +struct unpack_sequence<std::array<T, N>> +: detail::unpack_tuple_apply +{}; + +}} // namespace boost::hof + +#endif diff --git a/boost/hof/detail/unwrap.hpp b/boost/hof/detail/unwrap.hpp new file mode 100644 index 0000000000..c9361d891e --- /dev/null +++ b/boost/hof/detail/unwrap.hpp @@ -0,0 +1,29 @@ +/*============================================================================= + Copyright (c) 2014 Paul Fultz II + unwrap.h + 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_HOF_GUARD_UNWRAP_H +#define BOOST_HOF_GUARD_UNWRAP_H + +#include <type_traits> +#include <functional> + +namespace boost { namespace hof { namespace detail { + +template <class T> +struct unwrap_reference +{ + typedef T type; +}; +template <class T> +struct unwrap_reference<std::reference_wrapper<T>> +{ + typedef T& type; +}; + +}}} // namespace boost::hof + +#endif diff --git a/boost/hof/detail/using.hpp b/boost/hof/detail/using.hpp new file mode 100644 index 0000000000..1f320d8337 --- /dev/null +++ b/boost/hof/detail/using.hpp @@ -0,0 +1,21 @@ +/*============================================================================= + Copyright (c) 2016 Paul Fultz II + using.hpp + 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_HOF_GUARD_USING_HPP +#define BOOST_HOF_GUARD_USING_HPP + +#include <boost/hof/config.hpp> + +#if BOOST_HOF_HAS_TEMPLATE_ALIAS +#define BOOST_HOF_USING(name, ...) using name = __VA_ARGS__ +#define BOOST_HOF_USING_TYPENAME(name, ...) using name = typename __VA_ARGS__ +#else +#define BOOST_HOF_USING(name, ...) struct name : std::enable_if<true, __VA_ARGS__>::type {} +#define BOOST_HOF_USING_TYPENAME(name, ...) struct name : __VA_ARGS__ {} +#endif + +#endif diff --git a/boost/hof/eval.hpp b/boost/hof/eval.hpp new file mode 100644 index 0000000000..dcfb6b3ab5 --- /dev/null +++ b/boost/hof/eval.hpp @@ -0,0 +1,86 @@ +/*============================================================================= + Copyright (c) 2015 Paul Fultz II + eval.h + 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_HOF_GUARD_EVAL_H +#define BOOST_HOF_GUARD_EVAL_H + +/// eval +/// ==== +/// +/// Description +/// ----------- +/// +/// The `eval` function will evaluate a "thunk". This can be either a nullary +/// function or it can be a unary function that takes the identity function as +/// the first parameter(which is helpful to delay compile-time checking). +/// Also, additional parameters can be passed to `eval` to delay +/// compiliation(so that result can depend on template parameters). +/// +/// Synopsis +/// -------- +/// +/// template<class F, class... Ts> +/// constexpr auto eval(F&& f, Ts&&...); +/// +/// Requirements +/// ------------ +/// +/// F must be: +/// +/// * [EvaluatableFunctionObject](EvaluatableFunctionObject) +/// +/// Example +/// ------- +/// +/// #include <boost/hof.hpp> +/// #include <cassert> +/// +/// int main() { +/// assert(boost::hof::eval([]{ return 3; }) == 3); +/// } +/// +/// References +/// ---------- +/// +/// * [POO51](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0051r2.pdf) - Proposal for C++ +/// Proposal for C++ generic overload function +/// * [static_if](static_if) +/// * [Ordering evaluation of arguments](<Ordering evaluation of arguments>) +/// + +#include <boost/hof/always.hpp> +#include <boost/hof/identity.hpp> +#include <boost/hof/first_of.hpp> +#include <boost/hof/detail/result_of.hpp> + +namespace boost { namespace hof { + +namespace detail { + +struct simple_eval +{ + template<class F, class... Ts> + constexpr BOOST_HOF_SFINAE_RESULT(F) + operator()(F&& f, Ts&&...xs) const BOOST_HOF_SFINAE_RETURNS + (boost::hof::always_ref(f)(xs...)()); +}; + +struct id_eval +{ + template<class F, class... Ts> + constexpr BOOST_HOF_SFINAE_RESULT(F, id_<decltype(boost::hof::identity)>) + operator()(F&& f, Ts&&...xs) const BOOST_HOF_SFINAE_RETURNS + (boost::hof::always_ref(f)(xs...)(boost::hof::identity)); +}; + +} + +BOOST_HOF_DECLARE_STATIC_VAR(eval, boost::hof::first_of_adaptor<detail::simple_eval, detail::id_eval>); + +}} // namespace boost::hof + +#endif diff --git a/boost/hof/first_of.hpp b/boost/hof/first_of.hpp new file mode 100644 index 0000000000..83edf49e6d --- /dev/null +++ b/boost/hof/first_of.hpp @@ -0,0 +1,244 @@ +/*============================================================================= + Copyright (c) 2012 Paul Fultz II + first_of.h + 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_HOF_GUARD_FUNCTION_CONDITIONAL_H +#define BOOST_HOF_GUARD_FUNCTION_CONDITIONAL_H + +/// first_of +/// ======== +/// +/// Description +/// ----------- +/// +/// The `first_of` function adaptor combines several functions together. If +/// the first function can not be called, then it will try to call the next +/// function. This can be very useful when overloading functions using +/// template constraints(such as with `enable_if`). +/// +/// Note: This is different than the [`match`](match.md) function adaptor, which +/// can lead to ambiguities. Instead, `first_of` will call the first function +/// that is callable, regardless if there is another function that could be +/// called as well. +/// +/// Synopsis +/// -------- +/// +/// template<class... Fs> +/// constexpr first_of_adaptor<Fs...> first_of(Fs... fs); +/// +/// Requirements +/// ------------ +/// +/// Fs must be: +/// +/// * [ConstInvocable](ConstInvocable) +/// * MoveConstructible +/// +/// Example +/// ------- +/// +/// #include <boost/hof.hpp> +/// #include <iostream> +/// using namespace boost::hof; +/// +/// struct for_ints +/// { +/// void operator()(int) const +/// { +/// printf("Int\n"); +/// } +/// }; +/// +/// struct for_floats +/// { +/// void operator()(float) const +/// { +/// printf("Float\n"); +/// } +/// }; +/// +/// int main() { +/// first_of(for_ints(), for_floats())(3.0); +/// } +/// +/// This will print `Int` because the `for_floats` function object won't ever be +/// called. Due to the conversion rules in C++, the `for_ints` function can be +/// called on floats, so it is chosen by `first_of` first, even though +/// `for_floats` is a better match. +/// +/// So, the order of the functions in the `first_of_adaptor` are very important +/// to how the function is chosen. +/// +/// References +/// ---------- +/// +/// * [POO51](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0051r2.pdf) - Proposal for C++ +/// Proposal for C++ generic overload function +/// * [Conditional overloading](<Conditional overloading>) +/// + +#include <boost/hof/reveal.hpp> +#include <boost/hof/detail/compressed_pair.hpp> +#include <boost/hof/detail/callable_base.hpp> +#include <boost/hof/detail/delegate.hpp> +#include <boost/hof/detail/join.hpp> +#include <boost/hof/detail/seq.hpp> +#include <boost/hof/detail/make.hpp> +#include <boost/hof/detail/static_const_var.hpp> + +namespace boost { namespace hof { + +namespace detail { + +template<class F1, class F2> +struct basic_first_of_adaptor : F1, F2 +{ + BOOST_HOF_INHERIT_DEFAULT(basic_first_of_adaptor, F1, F2) + + template<class A, class B, + BOOST_HOF_ENABLE_IF_CONVERTIBLE(A, F1), + BOOST_HOF_ENABLE_IF_CONVERTIBLE(B, F2)> + constexpr basic_first_of_adaptor(A&& f1, B&& f2) + noexcept(BOOST_HOF_IS_NOTHROW_CONSTRUCTIBLE(F1, A&&) && BOOST_HOF_IS_NOTHROW_CONSTRUCTIBLE(F2, B&&)) + : F1(BOOST_HOF_FORWARD(A)(f1)), F2(BOOST_HOF_FORWARD(B)(f2)) + {} + + template<class X, + class=typename std::enable_if< + BOOST_HOF_IS_CONVERTIBLE(X, F1) && + BOOST_HOF_IS_DEFAULT_CONSTRUCTIBLE(F2) + >::type> + constexpr basic_first_of_adaptor(X&& x) + BOOST_HOF_NOEXCEPT_CONSTRUCTIBLE(F1, X&&) + : F1(BOOST_HOF_FORWARD(X)(x)) + {} + + template<class... Ts> + struct select + : std::conditional + < + is_invocable<F1, Ts...>::value, + F1, + F2 + > + {}; + + BOOST_HOF_RETURNS_CLASS(basic_first_of_adaptor); + + template<class... Ts, class F=typename select<Ts...>::type> + constexpr BOOST_HOF_SFINAE_RESULT(typename select<Ts...>::type, id_<Ts>...) + operator()(Ts && ... xs) const + BOOST_HOF_SFINAE_RETURNS + ( + BOOST_HOF_RETURNS_STATIC_CAST(const F&)(*BOOST_HOF_CONST_THIS)(BOOST_HOF_FORWARD(Ts)(xs)...) + ); +}; + +template <class F1, class F2> +constexpr const F1& which(std::true_type, const F1& f1, const F2&) noexcept +{ + return f1; +} + +template <class F1, class F2> +constexpr const F2& which(std::false_type, const F1&, const F2& f2) noexcept +{ + return f2; +} + +template<class F1, class F2> +struct conditional_kernel : compressed_pair<F1, F2> +{ + typedef compressed_pair<F1, F2> base; + BOOST_HOF_INHERIT_CONSTRUCTOR(conditional_kernel, base) + + template<class... Ts> + struct select + : std::conditional + < + is_invocable<F1, Ts...>::value, + F1, + F2 + > + {}; + + BOOST_HOF_RETURNS_CLASS(conditional_kernel); + + template<class... Ts, class PickFirst=is_invocable<F1, Ts...>> + constexpr BOOST_HOF_SFINAE_RESULT(typename select<Ts...>::type, id_<Ts>...) + operator()(Ts && ... xs) const + BOOST_HOF_SFINAE_RETURNS + ( + boost::hof::detail::which( + BOOST_HOF_RETURNS_CONSTRUCT(PickFirst)(), + BOOST_HOF_MANGLE_CAST(const F1&)(BOOST_HOF_CONST_THIS->first(xs...)), + BOOST_HOF_MANGLE_CAST(const F2&)(BOOST_HOF_CONST_THIS->second(xs...)) + ) + (BOOST_HOF_FORWARD(Ts)(xs)...) + ); +}; +} + +template<class F, class... Fs> +struct first_of_adaptor +: detail::conditional_kernel<F, BOOST_HOF_JOIN(first_of_adaptor, Fs...) > +{ + typedef first_of_adaptor fit_rewritable_tag; + typedef BOOST_HOF_JOIN(first_of_adaptor, Fs...) kernel_base; + typedef detail::conditional_kernel<F, kernel_base > base; + + BOOST_HOF_INHERIT_DEFAULT(first_of_adaptor, base) + + template<class X, class... Xs, + BOOST_HOF_ENABLE_IF_CONSTRUCTIBLE(base, X, kernel_base), + BOOST_HOF_ENABLE_IF_CONSTRUCTIBLE(kernel_base, Xs...)> + constexpr first_of_adaptor(X&& f1, Xs&& ... fs) + noexcept(BOOST_HOF_IS_NOTHROW_CONSTRUCTIBLE(base, X&&, kernel_base) && BOOST_HOF_IS_NOTHROW_CONSTRUCTIBLE(kernel_base, Xs&&...)) + : base(BOOST_HOF_FORWARD(X)(f1), kernel_base(BOOST_HOF_FORWARD(Xs)(fs)...)) + {} + + template<class X, class... Xs, + BOOST_HOF_ENABLE_IF_CONSTRUCTIBLE(base, X)> + constexpr first_of_adaptor(X&& f1) + BOOST_HOF_NOEXCEPT_CONSTRUCTIBLE(base, X&&) + : base(BOOST_HOF_FORWARD(X)(f1)) + {} + + struct failure + : failure_for<F, Fs...> + {}; +}; + +template<class F> +struct first_of_adaptor<F> : F +{ + typedef first_of_adaptor fit_rewritable_tag; + BOOST_HOF_INHERIT_CONSTRUCTOR(first_of_adaptor, F); + + struct failure + : failure_for<F> + {}; +}; + +template<class F1, class F2> +struct first_of_adaptor<F1, F2> +: detail::conditional_kernel<F1, F2> +{ + typedef detail::conditional_kernel<F1, F2> base; + typedef first_of_adaptor fit_rewritable_tag; + BOOST_HOF_INHERIT_CONSTRUCTOR(first_of_adaptor, base); + + struct failure + : failure_for<F1, F2> + {}; +}; + +BOOST_HOF_DECLARE_STATIC_VAR(first_of, detail::make<first_of_adaptor>); + +}} // namespace boost::hof + +#endif diff --git a/boost/hof/fix.hpp b/boost/hof/fix.hpp new file mode 100644 index 0000000000..24bc8dc789 --- /dev/null +++ b/boost/hof/fix.hpp @@ -0,0 +1,242 @@ +/*============================================================================= + Copyright (c) 2014 Paul Fultz II + fix.h + 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_HOF_GUARD_FUNCTION_FIX_H +#define BOOST_HOF_GUARD_FUNCTION_FIX_H + +/// fix +/// === +/// +/// Description +/// ----------- +/// +/// The `fix` function adaptor implements a fixed-point combinator. This can be +/// used to write recursive functions. +/// +/// When using `constexpr`, a function can recurse to a depth that is defined by +/// `BOOST_HOF_RECURSIVE_CONSTEXPR_DEPTH`(default is 16). There is no limitiation on +/// recursion depth for non-constexpr functions. In addition, due to the +/// eagerness of `constexpr` to instantiation templates, in some cases, an +/// explicit return type must be specified in order to avoid reaching the +/// recursion limits of the compiler. This can be accomplished using +/// [`boost::hof::result`](/include/boost/hof/result): +/// +/// int r = boost::hof::result<int>(factorial)(5); +/// +/// Synopsis +/// -------- +/// +/// template<class F> +/// constexpr fix_adaptor<F> fix(F f); +/// +/// Semantics +/// --------- +/// +/// assert(fix(f)(xs...) == f(fix(f), xs...)); +/// +/// Requirements +/// ------------ +/// +/// F must be: +/// +/// * [ConstFunctionObject](ConstFunctionObject) +/// * MoveConstructible +/// +/// Example +/// ------- +/// +/// #include <boost/hof.hpp> +/// #include <cassert> +/// +/// int main() { +/// auto factorial = boost::hof::fix( +/// [](auto recurse, auto x) -> decltype(x) { +/// return x == 0 ? 1 : x * recurse(x-1); +/// } +/// ); +/// int r = boost::hof::result<int>(factorial)(5); +/// assert(r == 5*4*3*2*1); +/// } +/// +/// References +/// ---------- +/// +/// * [Fixed-point combinator](https://en.wikipedia.org/wiki/Fixed-point_combinator) +/// * [Recursive](Recursive) +/// + +#include <boost/hof/always.hpp> +#include <boost/hof/detail/callable_base.hpp> +#include <boost/hof/reveal.hpp> +#include <boost/hof/detail/delegate.hpp> +#include <boost/hof/detail/move.hpp> +#include <boost/hof/detail/make.hpp> +#include <boost/hof/detail/static_const_var.hpp> +#include <boost/hof/indirect.hpp> +#include <boost/hof/result.hpp> +#include <boost/hof/detail/recursive_constexpr_depth.hpp> + + +namespace boost { namespace hof { + +namespace detail{ + +template<class F> +struct compute_indirect_ref +{ typedef indirect_adaptor<const F*> type; }; + +template<class F> +struct compute_indirect_ref<indirect_adaptor<F*>> +{ typedef indirect_adaptor<F*> type; }; + +template<class F> +constexpr indirect_adaptor<const F*> make_indirect_ref(const F& f) noexcept +{ + return indirect_adaptor<const F*>(&f); +} + +template<class F> +constexpr indirect_adaptor<const F*> make_indirect_ref(const indirect_adaptor<F*>& f) noexcept +{ + return f; +} + +template<class F, class=void> +struct fix_result +{ + template<class... Ts> + struct apply + { + typedef decltype(std::declval<F>()(std::declval<Ts>()...)) type; + }; +}; + +template<class F> +struct fix_result<F, typename holder< + typename F::result_type +>::type> +{ + template<class...> + struct apply + { + typedef typename F::result_type type; + }; + +}; + +template<class F, class Result, int N> +struct fix_adaptor_base : F +{ + BOOST_HOF_INHERIT_CONSTRUCTOR(fix_adaptor_base, F); + + typedef typename compute_indirect_ref<F>::type base_ref_type; + typedef fix_adaptor_base<base_ref_type, Result, N-1> derived; + + + template<class... Ts> + constexpr const F& base_function(Ts&&... xs) const noexcept + { + return boost::hof::always_ref(*this)(xs...); + } + + template<class... Ts> + constexpr derived derived_function(Ts&&... xs) const noexcept + { + return derived(boost::hof::detail::make_indirect_ref(this->base_function(xs...))); + } + + struct fix_failure + { + template<class Failure> + struct apply + { + template<class... Ts> + struct of + : Failure::template of<derived, Ts...> + {}; + }; + }; + + struct failure + : failure_map<fix_failure, F> + {}; + + + BOOST_HOF_RETURNS_CLASS(fix_adaptor_base); + + template<class... Ts> + constexpr BOOST_HOF_SFINAE_RESULT(const F&, id_<derived>, id_<Ts>...) + operator()(Ts&&... xs) const BOOST_HOF_SFINAE_RETURNS + ( + BOOST_HOF_MANGLE_CAST(const F&)(BOOST_HOF_CONST_THIS->base_function(xs...)) + ( + BOOST_HOF_MANGLE_CAST(derived)(BOOST_HOF_CONST_THIS->derived_function(xs...)), + BOOST_HOF_FORWARD(Ts)(xs)... + ) + ); +}; + +template<class F, class Result> +struct fix_adaptor_base<F, Result, 0> : F +{ + BOOST_HOF_INHERIT_CONSTRUCTOR(fix_adaptor_base, F); + + template<class... Ts> + const F& base_function(Ts&&...) const noexcept + { + return *this; + } + + struct fix_failure + { + template<class Failure> + struct apply + { + template<class... Ts> + struct of + : Failure::template of<fix_adaptor_base, Ts...> + {}; + }; + }; + + struct failure + : failure_map<fix_failure, F> + {}; + + + BOOST_HOF_RETURNS_CLASS(fix_adaptor_base); + + template<class... Ts> + typename Result::template apply<fix_adaptor_base, Ts...>::type + operator()(Ts&&... xs) const + { + return this->base_function(xs...)(*this, BOOST_HOF_FORWARD(Ts)(xs)...); + } +}; +} + +template<class F> +struct fix_adaptor : detail::fix_adaptor_base<F, detail::fix_result<F>, BOOST_HOF_RECURSIVE_CONSTEXPR_DEPTH> +{ + typedef fix_adaptor fit_rewritable1_tag; + typedef detail::fix_adaptor_base<F, detail::fix_result<F>, BOOST_HOF_RECURSIVE_CONSTEXPR_DEPTH> base; + BOOST_HOF_INHERIT_CONSTRUCTOR(fix_adaptor, base); +}; + +template<class Result, class F> +struct result_adaptor<Result, fix_adaptor<F>> +: fix_adaptor<result_adaptor<Result, F>> +{ + typedef fix_adaptor<result_adaptor<Result, F>> base; + BOOST_HOF_INHERIT_CONSTRUCTOR(result_adaptor, base) +}; + +BOOST_HOF_DECLARE_STATIC_VAR(fix, detail::make<fix_adaptor>); + +}} // namespace boost::hof + +#endif diff --git a/boost/hof/flip.hpp b/boost/hof/flip.hpp new file mode 100644 index 0000000000..cd7a1f9174 --- /dev/null +++ b/boost/hof/flip.hpp @@ -0,0 +1,107 @@ +/*============================================================================= + Copyright (c) 2015 Paul Fultz II + flip.h + 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_HOF_GUARD_FLIP_H +#define BOOST_HOF_GUARD_FLIP_H + +/// flip +/// ==== +/// +/// Description +/// ----------- +/// +/// The `flip` function adaptor swaps the first two parameters. +/// +/// Synopsis +/// -------- +/// +/// template<class F> +/// flip_adaptor<F> flip(F f); +/// +/// Semantics +/// --------- +/// +/// assert(flip(f)(x, y, xs...) == f(y, x, xs...)); +/// +/// Requirements +/// ------------ +/// +/// F must be at least: +/// +/// * [BinaryInvocable](BinaryInvocable) +/// +/// Or: +/// +/// * [Invocable](Invocable) with more than two argurments +/// +/// And: +/// +/// * MoveConstructible +/// +/// Example +/// ------- +/// +/// #include <boost/hof.hpp> +/// #include <cassert> +/// +/// int main() { +/// int r = boost::hof::flip(boost::hof::_ - boost::hof::_)(2, 5); +/// assert(r == 3); +/// } +/// + +#include <boost/hof/detail/callable_base.hpp> +#include <boost/hof/reveal.hpp> +#include <boost/hof/detail/make.hpp> +#include <boost/hof/detail/static_const_var.hpp> + +namespace boost { namespace hof { + +template<class F> +struct flip_adaptor : detail::callable_base<F> +{ + typedef flip_adaptor fit_rewritable1_tag; + BOOST_HOF_INHERIT_CONSTRUCTOR(flip_adaptor, detail::callable_base<F>); + + template<class... Ts> + constexpr const detail::callable_base<F>& base_function(Ts&&... xs) const + { + return boost::hof::always_ref(*this)(xs...); + } + + struct flip_failure + { + template<class Failure> + struct apply + { + template<class T, class U, class... Ts> + struct of + : Failure::template of<U, T, Ts...> + {}; + }; + }; + + struct failure + : failure_map<flip_failure, detail::callable_base<F>> + {}; + + BOOST_HOF_RETURNS_CLASS(flip_adaptor); + + template<class T, class U, class... Ts> + constexpr BOOST_HOF_SFINAE_RESULT(const detail::callable_base<F>&, id_<U>, id_<T>, id_<Ts>...) + operator()(T&& x, U&& y, Ts&&... xs) const BOOST_HOF_SFINAE_RETURNS + ( + (BOOST_HOF_MANGLE_CAST(const detail::callable_base<F>&)(BOOST_HOF_CONST_THIS->base_function(xs...))) + (BOOST_HOF_FORWARD(U)(y), BOOST_HOF_FORWARD(T)(x), BOOST_HOF_FORWARD(Ts)(xs)...) + ); +}; + +BOOST_HOF_DECLARE_STATIC_VAR(flip, detail::make<flip_adaptor>); + +}} // namespace boost::hof + +#endif diff --git a/boost/hof/flow.hpp b/boost/hof/flow.hpp new file mode 100644 index 0000000000..643189c64c --- /dev/null +++ b/boost/hof/flow.hpp @@ -0,0 +1,166 @@ +/*============================================================================= + Copyright (c) 2015 Paul Fultz II + flow.h + 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_HOF_GUARD_FUNCTION_FLOW_H +#define BOOST_HOF_GUARD_FUNCTION_FLOW_H + +/// flow +/// ==== +/// +/// Description +/// ----------- +/// +/// The `flow` function adaptor provides function composition. It is useful as +/// an alternative to using the pipe operator `|` when chaining functions. It is +/// similiar to [`compose`](compose.md) except the evaluation order is +/// reversed. So, `flow(f, g)(0)` is equivalent to `g(f(0))`. +/// +/// +/// Synopsis +/// -------- +/// +/// template<class... Fs> +/// constexpr flow_adaptor<Fs...> flow(Fs... fs); +/// +/// Semantics +/// --------- +/// +/// assert(flow(f, g)(xs...) == g(f(xs...))); +/// +/// Requirements +/// ------------ +/// +/// Fs must be: +/// +/// * [ConstInvocable](ConstInvocable) +/// * MoveConstructible +/// +/// Example +/// ------- +/// +/// #include <boost/hof.hpp> +/// #include <cassert> +/// using namespace boost::hof; +/// +/// struct increment +/// { +/// template<class T> +/// T operator()(T x) const +/// { +/// return x + 1; +/// } +/// }; +/// +/// struct decrement +/// { +/// template<class T> +/// T operator()(T x) const +/// { +/// return x - 1; +/// } +/// }; +/// +/// int main() { +/// int r = flow(increment(), decrement(), increment())(3); +/// assert(r == 4); +/// } +/// +/// References +/// ---------- +/// +/// * [Function composition](https://en.wikipedia.org/wiki/Function_composition) +/// + +#include <boost/hof/detail/callable_base.hpp> +#include <boost/hof/always.hpp> +#include <boost/hof/detail/delegate.hpp> +#include <boost/hof/detail/compressed_pair.hpp> +#include <boost/hof/detail/join.hpp> +#include <tuple> +#include <boost/hof/detail/move.hpp> +#include <boost/hof/detail/make.hpp> +#include <boost/hof/detail/result_type.hpp> +#include <boost/hof/detail/static_const_var.hpp> + +namespace boost { namespace hof { namespace detail { + +template<class F1, class F2> +struct flow_kernel : detail::compressed_pair<detail::callable_base<F1>, detail::callable_base<F2>>, compose_function_result_type<F2, F1> +{ + typedef detail::compressed_pair<detail::callable_base<F1>, detail::callable_base<F2>> base_type; + + BOOST_HOF_INHERIT_CONSTRUCTOR(flow_kernel, base_type) + + BOOST_HOF_RETURNS_CLASS(flow_kernel); + + template<class... Ts> + constexpr BOOST_HOF_SFINAE_RESULT(const detail::callable_base<F2>&, result_of<const detail::callable_base<F1>&, id_<Ts>...>) + operator()(Ts&&... xs) const BOOST_HOF_SFINAE_RETURNS + ( + BOOST_HOF_MANGLE_CAST(const detail::callable_base<F2>&)(BOOST_HOF_CONST_THIS->second(xs...))( + BOOST_HOF_MANGLE_CAST(const detail::callable_base<F1>&)(BOOST_HOF_CONST_THIS->first(xs...))(BOOST_HOF_FORWARD(Ts)(xs)...) + ) + ); +}; +} + +template<class F, class... Fs> +struct flow_adaptor : detail::flow_kernel<F, BOOST_HOF_JOIN(flow_adaptor, Fs...)> +{ + typedef flow_adaptor fit_rewritable_tag; + typedef BOOST_HOF_JOIN(flow_adaptor, Fs...) tail; + typedef detail::flow_kernel<F, tail> base_type; + + BOOST_HOF_INHERIT_DEFAULT(flow_adaptor, base_type) + + template<class X, class... Xs, + BOOST_HOF_ENABLE_IF_CONSTRUCTIBLE(detail::callable_base<F>, X), + BOOST_HOF_ENABLE_IF_CONSTRUCTIBLE(tail, Xs...) + > + constexpr flow_adaptor(X&& f1, Xs&& ... fs) + BOOST_HOF_NOEXCEPT(BOOST_HOF_IS_NOTHROW_CONSTRUCTIBLE(base_type, X&&, tail) && BOOST_HOF_IS_NOTHROW_CONSTRUCTIBLE(tail, Xs&&...)) + : base_type(BOOST_HOF_FORWARD(X)(f1), tail(BOOST_HOF_FORWARD(Xs)(fs)...)) + {} + + template<class X, + BOOST_HOF_ENABLE_IF_CONSTRUCTIBLE(detail::callable_base<F>, X) + > + constexpr flow_adaptor(X&& f1) + BOOST_HOF_NOEXCEPT_CONSTRUCTIBLE(base_type, X&&) + : base_type(BOOST_HOF_FORWARD(X)(f1)) + {} +}; + +template<class F> +struct flow_adaptor<F> : detail::callable_base<F> +{ + typedef flow_adaptor fit_rewritable_tag; + BOOST_HOF_INHERIT_DEFAULT(flow_adaptor, detail::callable_base<F>) + + template<class X, BOOST_HOF_ENABLE_IF_CONVERTIBLE(X, detail::callable_base<F>)> + constexpr flow_adaptor(X&& f1) + BOOST_HOF_NOEXCEPT_CONSTRUCTIBLE(detail::callable_base<F>, X&&) + : detail::callable_base<F>(BOOST_HOF_FORWARD(X)(f1)) + {} + +}; + +template<class F1, class F2> +struct flow_adaptor<F1, F2> +: detail::flow_kernel<detail::callable_base<F1>, detail::callable_base<F2>> +{ + typedef flow_adaptor fit_rewritable_tag; + typedef detail::flow_kernel<detail::callable_base<F1>, detail::callable_base<F2>> base_type; + + BOOST_HOF_INHERIT_CONSTRUCTOR(flow_adaptor, base_type) +}; + +BOOST_HOF_DECLARE_STATIC_VAR(flow, detail::make<flow_adaptor>); + +}} // namespace boost::hof + +#endif diff --git a/boost/hof/fold.hpp b/boost/hof/fold.hpp new file mode 100644 index 0000000000..cebe7888e9 --- /dev/null +++ b/boost/hof/fold.hpp @@ -0,0 +1,171 @@ +/*============================================================================= + Copyright (c) 2015 Paul Fultz II + fold.h + 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_HOF_GUARD_FOLD_H +#define BOOST_HOF_GUARD_FOLD_H + +/// fold +/// ======== +/// +/// Description +/// ----------- +/// +/// The `fold` function adaptor uses a binary function to apply a +/// [fold](https://en.wikipedia.org/wiki/Fold_%28higher-order_function%29) +/// operation to the arguments passed to the function. Additionally, an +/// optional initial state can be provided, otherwise the first argument is +/// used as the initial state. +/// +/// The arguments to the binary function, take first the state and then the +/// argument. +/// +/// Synopsis +/// -------- +/// +/// template<class F, class State> +/// constexpr fold_adaptor<F, State> fold(F f, State s); +/// +/// template<class F> +/// constexpr fold_adaptor<F> fold(F f); +/// +/// Semantics +/// --------- +/// +/// assert(fold(f, z)() == z); +/// assert(fold(f, z)(x, xs...) == fold(f, f(z, x))(xs...)); +/// assert(fold(f)(x) == x); +/// assert(fold(f)(x, y, xs...) == fold(f)(f(x, y), xs...)); +/// +/// Requirements +/// ------------ +/// +/// State must be: +/// +/// * CopyConstructible +/// +/// F must be: +/// +/// * [BinaryInvocable](BinaryInvocable) +/// * MoveConstructible +/// +/// Example +/// ------- +/// +/// #include <boost/hof.hpp> +/// #include <cassert> +/// +/// struct max_f +/// { +/// template<class T, class U> +/// constexpr T operator()(T x, U y) const +/// { +/// return x > y ? x : y; +/// } +/// }; +/// int main() { +/// assert(boost::hof::fold(max_f())(2, 3, 4, 5) == 5); +/// } +/// +/// References +/// ---------- +/// +/// * [Fold](https://en.wikipedia.org/wiki/Fold_(higher-order_function)) +/// * [Variadic sum](<Variadic sum>) +/// + +#include <boost/hof/detail/callable_base.hpp> +#include <boost/hof/detail/delegate.hpp> +#include <boost/hof/detail/compressed_pair.hpp> +#include <boost/hof/detail/move.hpp> +#include <boost/hof/detail/make.hpp> +#include <boost/hof/detail/static_const_var.hpp> + +namespace boost { namespace hof { namespace detail { + +struct v_fold +{ + BOOST_HOF_RETURNS_CLASS(v_fold); + template<class F, class State, class T, class... Ts> + constexpr BOOST_HOF_SFINAE_MANUAL_RESULT(const v_fold&, id_<const F&>, result_of<const F&, id_<State>, id_<T>>, id_<Ts>...) + operator()(const F& f, State&& state, T&& x, Ts&&... xs) const BOOST_HOF_SFINAE_MANUAL_RETURNS + ( + (*BOOST_HOF_CONST_THIS)(f, f(BOOST_HOF_FORWARD(State)(state), BOOST_HOF_FORWARD(T)(x)), BOOST_HOF_FORWARD(Ts)(xs)...) + ); + + template<class F, class State> + constexpr State operator()(const F&, State&& state) const noexcept + { + return BOOST_HOF_FORWARD(State)(state); + } +}; + +} + +template<class F, class State=void> +struct fold_adaptor +: detail::compressed_pair<detail::callable_base<F>, State> +{ + typedef detail::compressed_pair<detail::callable_base<F>, State> base_type; + BOOST_HOF_INHERIT_CONSTRUCTOR(fold_adaptor, base_type) + + template<class... Ts> + constexpr const detail::callable_base<F>& base_function(Ts&&... xs) const noexcept + { + return this->first(xs...); + } + + template<class... Ts> + constexpr State get_state(Ts&&... xs) const noexcept + { + return this->second(xs...); + } + + BOOST_HOF_RETURNS_CLASS(fold_adaptor); + + template<class... Ts> + constexpr BOOST_HOF_SFINAE_RESULT(detail::v_fold, id_<const detail::callable_base<F>&>, id_<State>, id_<Ts>...) + operator()(Ts&&... xs) const BOOST_HOF_SFINAE_RETURNS + ( + detail::v_fold()( + BOOST_HOF_MANGLE_CAST(const detail::callable_base<F>&)(BOOST_HOF_CONST_THIS->base_function(xs...)), + BOOST_HOF_MANGLE_CAST(State)(BOOST_HOF_CONST_THIS->get_state(xs...)), + BOOST_HOF_FORWARD(Ts)(xs)... + ) + ) +}; + + +template<class F> +struct fold_adaptor<F, void> +: detail::callable_base<F> +{ + BOOST_HOF_INHERIT_CONSTRUCTOR(fold_adaptor, detail::callable_base<F>) + + template<class... Ts> + constexpr const detail::callable_base<F>& base_function(Ts&&... xs) const noexcept + { + return boost::hof::always_ref(*this)(xs...); + } + + BOOST_HOF_RETURNS_CLASS(fold_adaptor); + + template<class... Ts> + constexpr BOOST_HOF_SFINAE_RESULT(detail::v_fold, id_<const detail::callable_base<F>&>, id_<Ts>...) + operator()(Ts&&... xs) const BOOST_HOF_SFINAE_RETURNS + ( + detail::v_fold()( + BOOST_HOF_MANGLE_CAST(const detail::callable_base<F>&)(BOOST_HOF_CONST_THIS->base_function(xs...)), + BOOST_HOF_FORWARD(Ts)(xs)... + ) + ) +}; + +BOOST_HOF_DECLARE_STATIC_VAR(fold, detail::make<fold_adaptor>); + +}} // namespace boost::hof + +#endif diff --git a/boost/hof/function.hpp b/boost/hof/function.hpp new file mode 100644 index 0000000000..6693e8d236 --- /dev/null +++ b/boost/hof/function.hpp @@ -0,0 +1,90 @@ +/*============================================================================= + Copyright (c) 2014 Paul Fultz II + function.h + 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_HOF_GUARD_FUNCTION_FUNCTION_H +#define BOOST_HOF_GUARD_FUNCTION_FUNCTION_H + +/// BOOST_HOF_STATIC_FUNCTION +/// =================== +/// +/// Description +/// ----------- +/// + +/// The `BOOST_HOF_STATIC_FUNCTION` macro allows initializing a function object from a +/// `constexpr` expression. It uses the best practices as outlined in +/// [N4381](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html). +/// This includes using `const` to avoid global state, compile-time +/// initialization of the function object to avoid the [static initialization +/// order fiasco](https://isocpp.org/wiki/faq/ctors#static-init-order), and an +/// external address of the function object that is the same across translation +/// units to avoid possible One-Definition-Rule(ODR) violations. +/// +/// In C++17, this achieved using the `inline` keyword. However, on older +/// compilers it is initialized using a reference to a static member variable. +/// The static member variable is default constructed, as such the user variable +/// is always default constructed regardless of the expression. +/// +/// By default, all functions defined with `BOOST_HOF_STATIC_FUNCTION` use the +/// [`boost::hof::reveal`](/include/boost/hof/reveal) adaptor to improve error messages. +/// +/// Example +/// ------- +/// +/// #include <boost/hof.hpp> +/// #include <cassert> +/// +/// struct sum_f +/// { +/// template<class T, class U> +/// T operator()(T x, U y) const +/// { +/// return x+y; +/// } +/// }; +/// +/// BOOST_HOF_STATIC_FUNCTION(sum) = sum_f(); +/// BOOST_HOF_STATIC_FUNCTION(partial_sum) = boost::hof::partial(sum_f()); +/// +/// int main() { +/// assert(sum(1, 2) == partial_sum(1)(2)); +/// } +/// + +#include <boost/hof/reveal.hpp> +#if !BOOST_HOF_HAS_INLINE_VARIABLES +#include <boost/hof/detail/static_const_var.hpp> +#include <boost/hof/detail/constexpr_deduce.hpp> +#endif + +namespace boost { namespace hof { + +namespace detail { + +struct reveal_static_const_factory +{ + constexpr reveal_static_const_factory() + {} + template<class F> + constexpr reveal_adaptor<F> operator=(const F& f) const + { +#if BOOST_HOF_HAS_INLINE_VARIABLES +#else + static_assert(BOOST_HOF_IS_DEFAULT_CONSTRUCTIBLE(F), "Static functions must be default constructible"); +#endif + return reveal_adaptor<F>(f); + } +}; +}}} // namespace boost::hof + +#if BOOST_HOF_HAS_INLINE_VARIABLES +#define BOOST_HOF_STATIC_FUNCTION(name) inline const constexpr auto name = boost::hof::detail::reveal_static_const_factory() +#else +#define BOOST_HOF_STATIC_FUNCTION(name) BOOST_HOF_STATIC_CONST_VAR(name) = BOOST_HOF_DETAIL_MSVC_CONSTEXPR_DEDUCE boost::hof::detail::reveal_static_const_factory() +#endif + +#endif diff --git a/boost/hof/function_param_limit.hpp b/boost/hof/function_param_limit.hpp new file mode 100644 index 0000000000..cf6e2238c2 --- /dev/null +++ b/boost/hof/function_param_limit.hpp @@ -0,0 +1,57 @@ +/*============================================================================= + Copyright (c) 2016 Paul Fultz II + function_param_limit.hpp + 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_HOF_GUARD_FUNCTION_PARAM_LIMIT_HPP +#define BOOST_HOF_GUARD_FUNCTION_PARAM_LIMIT_HPP + +/// function_param_limit +/// ==================== +/// +/// Description +/// ----------- +/// +/// The `function_param_limit` metafunction retrieves the maximum number of +/// parameters for a function. For function pointers it returns the number of +/// parameters. Everything else, it returns `SIZE_MAX`, but this can be +/// changed by annotating the function with the [`limit`](limit) decorator. +/// +/// This is a type trait that inherits from `std::integral_constant`. +/// +/// Synopsis +/// -------- +/// +/// template<class F> +/// struct function_param_limit +/// : std::integral_constant<std::size_t, ...> +/// {}; +/// +/// See Also +/// -------- +/// +/// * [Partial function evaluation](<Partial function evaluation>) +/// * [limit](limit) +/// + +#include <boost/hof/detail/holder.hpp> +#include <type_traits> +#include <cstdint> + +namespace boost { namespace hof { + +template<class F, class=void> +struct function_param_limit +: std::integral_constant<std::size_t, SIZE_MAX> +{}; + +template<class F> +struct function_param_limit<F, typename detail::holder<typename F::fit_function_param_limit>::type> +: F::fit_function_param_limit +{}; + +}} // namespace boost::hof + +#endif diff --git a/boost/hof/identity.hpp b/boost/hof/identity.hpp new file mode 100644 index 0000000000..0c1f199fb8 --- /dev/null +++ b/boost/hof/identity.hpp @@ -0,0 +1,72 @@ +/*============================================================================= + Copyright (c) 2012 Paul Fultz II + identity.h + 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_HOF_GUARD_FUNCTION_IDENTITY_H +#define BOOST_HOF_GUARD_FUNCTION_IDENTITY_H + +/// identity +/// ======== +/// +/// Description +/// ----------- +/// +/// The `identity` function is an unary function object that returns whats given to it. +/// +/// Semantics +/// --------- +/// +/// assert(identity(x) == x); +/// +/// Synopsis +/// -------- +/// +/// template<class T> +/// constexpr T identity(T&& x); +/// + +#include <utility> +#include <initializer_list> +#include <boost/hof/detail/forward.hpp> +#include <boost/hof/detail/static_const_var.hpp> + +namespace boost { namespace hof { namespace identity_detail { + +struct identity_base +{ + template<class T> + constexpr T operator()(T&& x) const + noexcept(std::is_reference<T>::value || BOOST_HOF_IS_NOTHROW_MOVE_CONSTRUCTIBLE(T)) + { + return BOOST_HOF_FORWARD(T)(x); + } + + template<class T> + constexpr std::initializer_list<T>& operator()(std::initializer_list<T>& x) const noexcept + { + return x; + } + + template<class T> + constexpr const std::initializer_list<T>& operator()(const std::initializer_list<T>& x) const noexcept + { + return x; + } + + template<class T> + constexpr std::initializer_list<T> operator()(std::initializer_list<T>&& x) const noexcept(noexcept(std::initializer_list<T>(std::move(x)))) + { + return BOOST_HOF_FORWARD(std::initializer_list<T>)(x); + } +}; + +} + +BOOST_HOF_DECLARE_STATIC_VAR(identity, identity_detail::identity_base); + +}} // namespace boost::hof + +#endif diff --git a/boost/hof/if.hpp b/boost/hof/if.hpp new file mode 100644 index 0000000000..9eb199f11f --- /dev/null +++ b/boost/hof/if.hpp @@ -0,0 +1,143 @@ +/*============================================================================= + Copyright (c) 2015 Paul Fultz II + if_.h + 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_HOF_GUARD_IF_H +#define BOOST_HOF_GUARD_IF_H + +/// if +/// == +/// +/// Description +/// ----------- +/// +/// The `if_` function decorator makes the function callable if the boolean +/// condition is true. The `if_c` version can be used to give a boolean +/// condition directly(instead of relying on an integral constant). +/// +/// When `if_` is false, the function is not callable. It is a subtitution +/// failure to call the function. +/// +/// Synopsis +/// -------- +/// +/// template<class IntegralConstant> +/// constexpr auto if_(IntegralConstant); +/// +/// template<bool B, class F> +/// constexpr auto if_c(F); +/// +/// Requirements +/// ------------ +/// +/// IntegralConstant must be: +/// +/// * IntegralConstant +/// +/// F must be: +/// +/// * [ConstInvocable](ConstInvocable) +/// * MoveConstructible +/// +/// Example +/// ------- +/// +/// #include <boost/hof.hpp> +/// #include <cassert> +/// +/// struct sum_f +/// { +/// template<class T> +/// int operator()(T x, T y) const +/// { +/// return boost::hof::first_of( +/// boost::hof::if_(std::is_integral<T>())(boost::hof::_ + boost::hof::_), +/// boost::hof::always(0) +/// )(x, y); +/// } +/// }; +/// +/// int main() { +/// assert(sum_f()(1, 2) == 3); +/// assert(sum_f()("", "") == 0); +/// } +/// +/// References +/// ---------- +/// +/// * [static_if](static_if) +/// + +#include <boost/hof/always.hpp> +#include <boost/hof/detail/callable_base.hpp> +#include <boost/hof/detail/forward.hpp> +#include <boost/hof/detail/delegate.hpp> +#include <boost/hof/detail/move.hpp> +#include <boost/hof/detail/static_const_var.hpp> + +namespace boost { namespace hof { + +namespace detail { + +template<class C, class...> +struct if_depend +: C +{}; + +template<bool Cond, class F> +struct if_adaptor : detail::callable_base<F> +{ + BOOST_HOF_INHERIT_CONSTRUCTOR(if_adaptor, detail::callable_base<F>) +}; + +template<class F> +struct if_adaptor<false, F> +{ + template<class... Ts> + constexpr if_adaptor(Ts&&...) noexcept + {} +}; + +template<bool Cond> +struct make_if_f +{ + constexpr make_if_f() noexcept + {} + template<class F> + constexpr if_adaptor<Cond, F> operator()(F f) const BOOST_HOF_NOEXCEPT_CONSTRUCTIBLE(F, F&&) + { + return if_adaptor<Cond, F>(static_cast<F&&>(f)); + } +}; + +struct if_f +{ + constexpr if_f() + {} + template<class Cond, bool B=Cond::type::value> + constexpr make_if_f<B> operator()(Cond) const noexcept + { + return {}; + } +}; + +} +#if BOOST_HOF_HAS_VARIABLE_TEMPLATES +template<bool B> +BOOST_HOF_STATIC_CONSTEXPR detail::make_if_f<B> if_c = {}; +#else +template<bool B, class F> +constexpr detail::if_adaptor<B, F> if_c(F f) BOOST_HOF_NOEXCEPT_CONSTRUCTIBLE(F, F&&) +{ + return detail::if_adaptor<B, F>(static_cast<F&&>(f)); +} +#endif + +BOOST_HOF_DECLARE_STATIC_VAR(if_, detail::if_f); + +}} // namespace boost::hof + +#endif diff --git a/boost/hof/implicit.hpp b/boost/hof/implicit.hpp new file mode 100644 index 0000000000..f6cbc276ea --- /dev/null +++ b/boost/hof/implicit.hpp @@ -0,0 +1,155 @@ +/*============================================================================= + Copyright (c) 2012 Paul Fultz II + implicit.h + 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_HOF_GUARD_FUNCTION_IMPLICIT_H +#define BOOST_HOF_GUARD_FUNCTION_IMPLICIT_H + +/// implicit +/// ======== +/// +/// Description +/// ----------- +/// +/// The `implicit` adaptor is a static function adaptor that uses the type +/// that the return value can be converted to, in order to determine the type +/// of the template parameter. In essence, it will deduce the type for the +/// template parameter using the type of variable the result is assigned to. +/// Since it is a static function adaptor, the function must be default +/// constructible. +/// +/// Synopsis +/// -------- +/// +/// template<template <class...> class F> +/// class implicit<F>; +/// +/// Semantics +/// --------- +/// +/// assert(T(implicit<F>()(xs...)) == F<T>()(xs...)); +/// +/// Requirements +/// ------------ +/// +/// F must be a template class, that is a: +/// +/// * [ConstFunctionObject](ConstFunctionObject) +/// * DefaultConstructible +/// +/// Example +/// ------- +/// +/// #include <boost/hof.hpp> +/// #include <cassert> +/// using namespace boost::hof; +/// +/// template<class T> +/// struct auto_caster +/// { +/// template<class U> +/// T operator()(U x) +/// { +/// return T(x); +/// } +/// }; +/// +/// static constexpr implicit<auto_caster> auto_cast = {}; +/// +/// struct auto_caster_foo +/// { +/// int i; +/// explicit auto_caster_foo(int i_) : i(i_) {} +/// +/// }; +/// +/// int main() { +/// float f = 1.5; +/// int i = auto_cast(f); +/// auto_caster_foo x = auto_cast(1); +/// assert(1 == i); +/// assert(1 == x.i); +/// } +/// + +#include <boost/hof/pack.hpp> +#include <boost/hof/detail/result_of.hpp> + +namespace boost { namespace hof { namespace detail { + +template<class F, class Pack, class X, class=void> +struct is_implicit_callable +: std::false_type +{}; + +#if BOOST_HOF_NO_EXPRESSION_SFINAE +template<class F, class Pack, class X> +struct is_implicit_callable<F, Pack, X, typename std::enable_if< + std::is_convertible<typename result_of<Pack, id_<F>>::type, X>::value +>::type> +: std::true_type +{}; +#else +template<class F, class Pack, class X> +struct is_implicit_callable<F, Pack, X, typename std::enable_if< + std::is_convertible<decltype(std::declval<Pack>()(std::declval<F>())), X>::value +>::type> +: std::true_type +{}; +#endif + +} + + +template<template <class...> class F> +struct implicit +{ + template<class Pack> + struct invoker + { + Pack p; + + constexpr invoker(Pack pp) BOOST_HOF_NOEXCEPT_CONSTRUCTIBLE(Pack, Pack&&) + : p(boost::hof::move(pp)) + {} + + template<class X, class=typename std::enable_if<detail::is_implicit_callable<F<X>, Pack, X>::value>::type> + constexpr operator X() const BOOST_HOF_NOEXCEPT(noexcept(p(F<X>()))) + { + return p(F<X>()); + } + +#if !(defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ < 7) + invoker (const invoker&) = delete; + invoker& operator= (const invoker&) = delete; + + private: + friend struct implicit; + invoker (invoker&&) = default; +#endif + }; + + struct make_invoker + { + template<class Pack> + constexpr invoker<Pack> operator()(Pack p) const BOOST_HOF_NOEXCEPT(noexcept(invoker<Pack>(boost::hof::move(p)))) + { + return invoker<Pack>(boost::hof::move(p)); + } + + }; + + template<class... Ts> + constexpr auto operator()(Ts&&... xs) const + BOOST_HOF_RETURNS + ( + BOOST_HOF_RETURNS_CONSTRUCT(make_invoker)()(boost::hof::pack_basic(BOOST_HOF_FORWARD(Ts)(xs)...)) + ); +}; + +}} // namespace boost::hof + +#endif diff --git a/boost/hof/indirect.hpp b/boost/hof/indirect.hpp new file mode 100644 index 0000000000..975f113fb9 --- /dev/null +++ b/boost/hof/indirect.hpp @@ -0,0 +1,133 @@ +/*============================================================================= + Copyright (c) 2014 Paul Fultz II + indirect.h + 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_HOF_GUARD_FUNCTION_INDIRECT_H +#define BOOST_HOF_GUARD_FUNCTION_INDIRECT_H + +/// indirect +/// ======== +/// +/// Description +/// ----------- +/// +/// The `indirect` function adaptor dereferences the object before calling it. +/// +/// Synopsis +/// -------- +/// +/// template<class F> +/// constexpr indirect_adaptor<F> indirect(F f); +/// +/// Semantics +/// --------- +/// +/// assert(indirect(f)(xs...) == (*f)(xs...)); +/// +/// Requirements +/// ------------ +/// +/// F must be: +/// +/// * MoveConstructible +/// * Dereferenceable +/// +/// Example +/// ------- +/// +/// #include <boost/hof.hpp> +/// #include <cassert> +/// #include <memory> +/// using namespace boost::hof; +/// +/// struct sum +/// { +/// template<class T, class U> +/// T operator()(T x, U y) const +/// { +/// return x+y; +/// } +/// }; +/// +/// int main() { +/// int r = indirect(std::make_unique<sum>())(3,2); +/// assert(r == 5); +/// } +/// + +#include <boost/hof/detail/delegate.hpp> +#include <boost/hof/detail/result_of.hpp> +#include <boost/hof/reveal.hpp> +#include <boost/hof/always.hpp> +#include <boost/hof/detail/move.hpp> +#include <boost/hof/detail/make.hpp> +#include <boost/hof/detail/static_const_var.hpp> + +namespace boost { namespace hof { +// TODO: Support non-classes as well +template<class F> +struct indirect_adaptor : F +{ + typedef indirect_adaptor fit_rewritable1_tag; + BOOST_HOF_INHERIT_CONSTRUCTOR(indirect_adaptor, F); + + template<class... Ts> + constexpr const F& base_function(Ts&&... xs) const noexcept + { + return boost::hof::always_ref(*this)(xs...); + } + + struct failure + : failure_for<decltype(*std::declval<F>())> + {}; + + BOOST_HOF_RETURNS_CLASS(indirect_adaptor); + + template<class... Ts> + constexpr BOOST_HOF_SFINAE_RESULT(decltype(*std::declval<F>()), id_<Ts>...) + operator()(Ts&&... xs) const BOOST_HOF_SFINAE_RETURNS + ( + (*BOOST_HOF_MANGLE_CAST(const F&)(BOOST_HOF_CONST_THIS->base_function(xs...)))(BOOST_HOF_FORWARD(Ts)(xs)...) + ); +}; + +template<class F> +struct indirect_adaptor<F*> +{ + typedef indirect_adaptor fit_rewritable1_tag; + F* f; + constexpr indirect_adaptor() noexcept + {} + + constexpr indirect_adaptor(F* x) noexcept + : f(x) + {} + + template<class... Ts> + constexpr F& base_function(Ts&&...) const noexcept + { + return *f; + } + + struct failure + : failure_for<F> + {}; + + BOOST_HOF_RETURNS_CLASS(indirect_adaptor); + + template<class... Ts> + constexpr BOOST_HOF_SFINAE_RESULT(F, id_<Ts>...) + operator()(Ts&&... xs) const BOOST_HOF_SFINAE_RETURNS + ( + (BOOST_HOF_MANGLE_CAST(F&)(BOOST_HOF_CONST_THIS->base_function(xs...)))(BOOST_HOF_FORWARD(Ts)(xs)...) + ); +}; + +BOOST_HOF_DECLARE_STATIC_VAR(indirect, detail::make<indirect_adaptor>); + +}} // namespace boost::hof + +#endif diff --git a/boost/hof/infix.hpp b/boost/hof/infix.hpp new file mode 100644 index 0000000000..263297d578 --- /dev/null +++ b/boost/hof/infix.hpp @@ -0,0 +1,200 @@ +/*============================================================================= + Copyright (c) 2014 Paul Fultz II + infix.h + 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_HOF_GUARD_FUNCTION_INFIX_H +#define BOOST_HOF_GUARD_FUNCTION_INFIX_H + +/// infix +/// ===== +/// +/// Description +/// ----------- +/// +/// The `infix` function adaptor allows the function to be used as an infix +/// operator. The operator must be placed inside the angle brackets(ie `<` +/// and `>`). +/// +/// Synopsis +/// -------- +/// +/// template<class F> +/// constexpr infix_adaptor<F> infix(F f); +/// +/// Semantics +/// --------- +/// +/// assert(x <infix(f)> y == f(x, y)); +/// +/// Requirements +/// ------------ +/// +/// F must be: +/// +/// * [BinaryInvocable](BinaryInvocable) +/// * MoveConstructible +/// +/// Operator precedence +/// ------------------- +/// +/// Infix operators have the precedence of relational operators. This means +/// operators such as `+` or `*` have higher precedence: +/// +/// assert((x + y <infix(f)> z) == ((x + y) <infix(f)> z)); +/// assert((x * y <infix(f)> z) == ((x * y) <infix(f)> z)); +/// +/// However, operators such as `|` or `==` have lower precedence:: +/// +/// assert((x | y <infix(f)> z) == (x | (y <infix(f)> z))); +/// assert((x == y <infix(f)> z) == (x == (y <infix(f)> z))); +/// +/// Also, infix operators have left-to-right associativity: +/// +/// assert(x <infix(f)> y <infix(g)> z == ((x <infix(f)> y) <infix(g)> z)); +/// +/// Example +/// ------- +/// +/// #include <boost/hof.hpp> +/// #include <cassert> +/// using namespace boost::hof; +/// +/// struct plus_f +/// { +/// template<class T, class U> +/// T operator()(T x, U y) const +/// { +/// return x+y; +/// } +/// }; +/// +/// int main() { +/// constexpr infix_adaptor<plus_f> plus = {}; +/// int r = 3 <plus> 2; +/// assert(r == 5); +/// } +/// + +#include <boost/hof/detail/delegate.hpp> +#include <boost/hof/detail/callable_base.hpp> +#include <boost/hof/always.hpp> +#include <boost/hof/reveal.hpp> +#include <boost/hof/detail/move.hpp> +#include <boost/hof/detail/make.hpp> +#include <boost/hof/detail/static_const_var.hpp> + +namespace boost { namespace hof { + +namespace detail{ +template<class T, class F> +struct postfix_adaptor : F +{ + T x; + + template<class X, class XF> + constexpr postfix_adaptor(X&& xp, XF&& fp) + BOOST_HOF_NOEXCEPT(BOOST_HOF_IS_NOTHROW_CONSTRUCTIBLE(F, XF&&) && BOOST_HOF_IS_NOTHROW_CONSTRUCTIBLE(T, X&&)) + : F(BOOST_HOF_FORWARD(XF)(fp)), x(BOOST_HOF_FORWARD(X)(xp)) + {} + + template<class... Ts> + constexpr const F& base_function(Ts&&... xs) const noexcept + { + return boost::hof::always_ref(*this)(xs...); + } + + BOOST_HOF_RETURNS_CLASS(postfix_adaptor); + + template<class... Ts> + constexpr BOOST_HOF_SFINAE_RESULT(const F&, id_<T&&>, id_<Ts>...) + operator()(Ts&&... xs) const BOOST_HOF_SFINAE_RETURNS + ( + (BOOST_HOF_MANGLE_CAST(const F&)(BOOST_HOF_CONST_THIS->base_function(xs...)))(BOOST_HOF_RETURNS_C_CAST(T&&)(BOOST_HOF_CONST_THIS->x), BOOST_HOF_FORWARD(Ts)(xs)...) + ); + + template<class A> + constexpr BOOST_HOF_SFINAE_RESULT(const F&, id_<T&&>, id_<A>) + operator>(A&& a) const BOOST_HOF_SFINAE_RETURNS + ( + (BOOST_HOF_MANGLE_CAST(const F&)(BOOST_HOF_CONST_THIS->base_function(a)))(BOOST_HOF_RETURNS_C_CAST(T&&)(BOOST_HOF_CONST_THIS->x), BOOST_HOF_FORWARD(A)(a)) + ); +}; + +template<class T, class F> +constexpr postfix_adaptor<T, F> make_postfix_adaptor(T&& x, F f) +BOOST_HOF_NOEXCEPT_CONSTRUCTIBLE(postfix_adaptor<T, F>, T&&, F&&) +{ + return postfix_adaptor<T, F>(BOOST_HOF_FORWARD(T)(x), static_cast<F&&>(f)); +} +} + +template<class F> +struct infix_adaptor : detail::callable_base<F> +{ + typedef infix_adaptor fit_rewritable1_tag; + BOOST_HOF_INHERIT_CONSTRUCTOR(infix_adaptor, detail::callable_base<F>); + + template<class... Ts> + constexpr const detail::callable_base<F>& base_function(Ts&&... xs) const noexcept + { + return boost::hof::always_ref(*this)(xs...); + } + + template<class... Ts> + constexpr const detail::callable_base<F>& infix_base_function(Ts&&... xs) const noexcept + { + return boost::hof::always_ref(*this)(xs...); + } + + BOOST_HOF_RETURNS_CLASS(infix_adaptor); + + template<class... Ts> + constexpr auto operator()(Ts&&... xs) const BOOST_HOF_RETURNS + ( + (BOOST_HOF_MANGLE_CAST(const detail::callable_base<F>&)(BOOST_HOF_CONST_THIS->base_function(xs...)))(BOOST_HOF_FORWARD(Ts)(xs)...) + ); +}; + +template<class T, class F> +constexpr auto operator<(T&& x, const infix_adaptor<F>& i) BOOST_HOF_RETURNS +(detail::make_postfix_adaptor(BOOST_HOF_FORWARD(T)(x), boost::hof::move(i.base_function(x)))); + +// TODO: Operators for static_ + +namespace detail { + +template<class F> +struct static_function_wrapper; + +// Operators for static_function_wrapper adaptor +template<class T, class F> +auto operator<(T&& x, const boost::hof::detail::static_function_wrapper<F>& f) BOOST_HOF_RETURNS +( + detail::make_postfix_adaptor(BOOST_HOF_FORWARD(T)(x), boost::hof::move(f.base_function().infix_base_function())) +); + +template<class F> +struct static_default_function; + +// Operators for static_default_function adaptor +template<class T, class F> +auto operator<(T&& x, const boost::hof::detail::static_default_function<F>&) BOOST_HOF_RETURNS +( + detail::make_postfix_adaptor(BOOST_HOF_FORWARD(T)(x), boost::hof::move(F().infix_base_function())) +); +} +// This overload is needed for gcc +template<class T, class F> +constexpr auto operator<(T&& x, const boost::hof::reveal_adaptor<F>& f) BOOST_HOF_RETURNS +( + detail::make_postfix_adaptor(BOOST_HOF_FORWARD(T)(x), f.infix_base_function()) +); + +BOOST_HOF_DECLARE_STATIC_VAR(infix, detail::make<infix_adaptor>); + +}} // namespace boost::hof + +#endif diff --git a/boost/hof/is_invocable.hpp b/boost/hof/is_invocable.hpp new file mode 100644 index 0000000000..edf736e1b2 --- /dev/null +++ b/boost/hof/is_invocable.hpp @@ -0,0 +1,72 @@ +/*============================================================================= + Copyright (c) 2014 Paul Fultz II + is_invocable.h + 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_HOF_GUARD_IS_CALLABLE_H +#define BOOST_HOF_GUARD_IS_CALLABLE_H + +/// is_invocable +/// =========== +/// +/// Description +/// ----------- +/// +/// The `is_invocable` metafunction checks if the function is callable with +/// certain parameters. +/// +/// Requirements +/// ------------ +/// +/// F must be: +/// +/// * [Invocable](Invocable) +/// +/// Synopsis +/// -------- +/// +/// template<class F, class... Ts> +/// struct is_invocable; +/// +/// Example +/// ------- +/// +/// #include <boost/hof.hpp> +/// using namespace boost::hof; +/// +/// struct is_invocable_class +/// { +/// void operator()(int) const +/// { +/// } +/// }; +/// static_assert(is_invocable<is_invocable_class, int>(), "Not callable"); +/// +/// int main() {} +/// + + +#include <boost/hof/detail/can_be_called.hpp> +#include <boost/hof/apply.hpp> + +namespace boost { namespace hof { + +template<class F, class... Ts> +struct is_invocable +: detail::can_be_called<detail::apply_f, F, Ts...> +{}; + +template<class F, class... Ts, class... Us> +struct is_invocable<F(Ts...), Us...> +{ + static_assert(!std::is_same<F, F>::value, + "The is_invocable<F(Args...)> form is not supported because it is problematic." + "Please use is_invocable<F, Args...> instead." + ); +}; + +}} // namespace boost::hof + +#endif diff --git a/boost/hof/is_unpackable.hpp b/boost/hof/is_unpackable.hpp new file mode 100644 index 0000000000..1f1e0d26cf --- /dev/null +++ b/boost/hof/is_unpackable.hpp @@ -0,0 +1,115 @@ +/*============================================================================= + Copyright (c) 2016 Paul Fultz II + is_unpackable.hpp + 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_HOF_GUARD_IS_UNPACKABLE_HPP +#define BOOST_HOF_GUARD_IS_UNPACKABLE_HPP + +/// is_unpackable +/// ============= +/// +/// This is a trait that can be used to detect whether the type can be called +/// with `unpack`. +/// +/// Synopsis +/// -------- +/// +/// template<class T> +/// struct is_unpackable; +/// +/// Example +/// ------- +/// +/// #include <boost/hof.hpp> +/// #include <cassert> +/// +/// int main() { +/// static_assert(boost::hof::is_unpackable<std::tuple<int>>::value, "Failed"); +/// } +/// + +#include <boost/hof/unpack_sequence.hpp> +#include <boost/hof/is_invocable.hpp> +#include <boost/hof/always.hpp> +#include <boost/hof/detail/static_const_var.hpp> +#include <boost/hof/detail/unpack_tuple.hpp> + +namespace boost { namespace hof { + +namespace detail { + +struct unpack_impl_f +{ + template<class F, class Sequence> + constexpr auto operator()(F&& f, Sequence&& s) const BOOST_HOF_RETURNS + ( + boost::hof::unpack_sequence<typename std::remove_cv<typename std::remove_reference<Sequence>::type>::type>:: + apply(BOOST_HOF_FORWARD(F)(f), BOOST_HOF_FORWARD(Sequence)(s)) + ); +}; + +BOOST_HOF_DECLARE_STATIC_VAR(unpack_impl, unpack_impl_f); + +#if BOOST_HOF_CHECK_UNPACK_SEQUENCE +struct private_unpack_type {}; +template<class Sequence> +struct unpack_impl_result +{ + static_assert(boost::hof::is_invocable<unpack_impl_f, decltype(boost::hof::always(private_unpack_type())), Sequence>::value, + "Unpack is invalid for this sequence. The function used to unpack this sequence is not callable." + ); + typedef decltype(boost::hof::detail::unpack_impl(boost::hof::always(private_unpack_type()), std::declval<Sequence>())) type; +}; + +template<class Sequence> +struct is_proper_sequence +: std::is_same< + private_unpack_type, + typename unpack_impl_result<Sequence>::type +> +{}; +#endif +template<class Sequence, class=void> +struct is_unpackable_impl +: std::true_type +{ +#if BOOST_HOF_CHECK_UNPACK_SEQUENCE + static_assert(is_proper_sequence<Sequence>::value, + "Unpack is invalid for this sequence. The function used to unpack this sequence does not invoke the function." + ); +#endif +}; + +template<class Sequence> +struct is_unpackable_impl<Sequence, typename detail::holder< + typename unpack_sequence<Sequence>::not_unpackable +>::type> +: std::false_type +{}; + +} + +template<class Sequence> +struct is_unpackable +: detail::is_unpackable_impl< + typename std::remove_cv<typename std::remove_reference<Sequence>::type>::type +> +{ +#if BOOST_HOF_CHECK_UNPACK_SEQUENCE +typedef detail::is_unpackable_impl< + typename std::remove_cv<typename std::remove_reference<Sequence>::type>::type +> base; + +typedef std::conditional<base::value, detail::is_proper_sequence<Sequence>, std::true_type> check; +static_assert(check::type::value, + "Unpack is invalid for this sequence. The function used to unpack this sequence does not invoke the function." +); +#endif +}; + +}} // namespace boost::hof + +#endif diff --git a/boost/hof/lambda.hpp b/boost/hof/lambda.hpp new file mode 100644 index 0000000000..cd3517a623 --- /dev/null +++ b/boost/hof/lambda.hpp @@ -0,0 +1,244 @@ +/*============================================================================= + Copyright (c) 2014 Paul Fultz II + lambda.h + 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_HOF_GUARD_FUNCTION_LAMBDA_H +#define BOOST_HOF_GUARD_FUNCTION_LAMBDA_H + +/// BOOST_HOF_STATIC_LAMBDA +/// ================= +/// +/// Description +/// ----------- +/// +/// The `BOOST_HOF_STATIC_LAMBDA` macro allows initializing non-capturing lambdas at +/// compile-time in a `constexpr` expression. +/// +/// Example +/// ------- +/// +/// #include <boost/hof.hpp> +/// #include <cassert> +/// +/// const constexpr auto add_one = BOOST_HOF_STATIC_LAMBDA(int x) +/// { +/// return x + 1; +/// }; +/// +/// int main() { +/// assert(3 == add_one(2)); +/// } +/// +/// BOOST_HOF_STATIC_LAMBDA_FUNCTION +/// ========================== +/// +/// Description +/// ----------- +/// +/// The `BOOST_HOF_STATIC_LAMBDA_FUNCTION` macro allows initializing a global +/// function object that contains non-capturing lambdas. It also ensures that +/// the global function object has a unique address across translation units. +/// This helps prevent possible ODR-violations. +/// +/// By default, all functions defined with `BOOST_HOF_STATIC_LAMBDA_FUNCTION` use +/// the `boost::hof::reveal` adaptor to improve error messages. +/// +/// Example +/// ------- +/// +/// #include <boost/hof.hpp> +/// #include <cassert> +/// +/// BOOST_HOF_STATIC_LAMBDA_FUNCTION(add_one) = [](int x) +/// { +/// return x + 1; +/// }; +/// int main() { +/// assert(3 == add_one(2)); +/// } +/// + +#include <boost/hof/config.hpp> + +// TODO: Move this to a detail header +#if !BOOST_HOF_HAS_CONSTEXPR_LAMBDA || !BOOST_HOF_HAS_INLINE_LAMBDAS + +#include <type_traits> +#include <utility> +#include <boost/hof/detail/result_of.hpp> +#include <boost/hof/reveal.hpp> +#include <boost/hof/detail/constexpr_deduce.hpp> +#include <boost/hof/function.hpp> + + +#ifndef BOOST_HOF_REWRITE_STATIC_LAMBDA +#ifdef _MSC_VER +#define BOOST_HOF_REWRITE_STATIC_LAMBDA 1 +#else +#define BOOST_HOF_REWRITE_STATIC_LAMBDA 0 +#endif +#endif + +namespace boost { namespace hof { + +namespace detail { + +template<class F> +struct static_function_wrapper +{ + // Default constructor necessary for MSVC + constexpr static_function_wrapper() + {} + + static_assert(BOOST_HOF_IS_EMPTY(F), "Function or lambda expression must be empty"); + + struct failure + : failure_for<F> + {}; + + template<class... Ts> + const F& base_function(Ts&&...) const + { + return reinterpret_cast<const F&>(*this); + } + + BOOST_HOF_RETURNS_CLASS(static_function_wrapper); + + template<class... Ts> + BOOST_HOF_SFINAE_RESULT(const F&, id_<Ts>...) + operator()(Ts&&... xs) const BOOST_HOF_SFINAE_RETURNS + ( + BOOST_HOF_RETURNS_REINTERPRET_CAST(const F&)(*BOOST_HOF_CONST_THIS)(BOOST_HOF_FORWARD(Ts)(xs)...) + ); +}; + +struct static_function_wrapper_factor +{ + constexpr static_function_wrapper_factor() + {} + template<class F> + constexpr static_function_wrapper<F> operator= (const F&) const + { + // static_assert(std::is_literal_type<static_function_wrapper<F>>::value, "Function wrapper not a literal type"); + return {}; + } +}; + +#if BOOST_HOF_REWRITE_STATIC_LAMBDA +template<class T, class=void> +struct is_rewritable +: std::false_type +{}; + +template<class T> +struct is_rewritable<T, typename detail::holder< + typename T::fit_rewritable_tag +>::type> +: std::is_same<typename T::fit_rewritable_tag, T> +{}; + +template<class T, class=void> +struct is_rewritable1 +: std::false_type +{}; + +template<class T> +struct is_rewritable1<T, typename detail::holder< + typename T::fit_rewritable1_tag +>::type> +: std::is_same<typename T::fit_rewritable1_tag, T> +{}; + + +template<class T, class=void> +struct rewrite_lambda; + +template<template<class...> class Adaptor, class... Ts> +struct rewrite_lambda<Adaptor<Ts...>, typename std::enable_if< + is_rewritable<Adaptor<Ts...>>::value +>::type> +{ + typedef Adaptor<typename rewrite_lambda<Ts>::type...> type; +}; + +template<template<class...> class Adaptor, class T, class... Ts> +struct rewrite_lambda<Adaptor<T, Ts...>, typename std::enable_if< + is_rewritable1<Adaptor<T, Ts...>>::value +>::type> +{ + typedef Adaptor<typename rewrite_lambda<T>::type, Ts...> type; +}; + +template<class T> +struct rewrite_lambda<T, typename std::enable_if< + std::is_empty<T>::value && + !is_rewritable<T>::value && + !is_rewritable1<T>::value +>::type> +{ + typedef static_function_wrapper<T> type; +}; + +template<class T> +struct rewrite_lambda<T, typename std::enable_if< + !std::is_empty<T>::value && + !is_rewritable<T>::value && + !is_rewritable1<T>::value +>::type> +{ + typedef T type; +}; + +#endif + +template<class T> +struct reveal_static_lambda_function_wrapper_factor +{ + constexpr reveal_static_lambda_function_wrapper_factor() + {} +#if BOOST_HOF_REWRITE_STATIC_LAMBDA + template<class F> + constexpr reveal_adaptor<typename rewrite_lambda<F>::type> + operator=(const F&) const + { + return reveal_adaptor<typename rewrite_lambda<F>::type>(); + } +#elif BOOST_HOF_HAS_CONST_FOLD + template<class F> + constexpr const reveal_adaptor<F>& operator=(const F&) const + { + return reinterpret_cast<const reveal_adaptor<F>&>(static_const_var<T>()); + } +#else + template<class F> + constexpr reveal_adaptor<static_function_wrapper<F>> operator=(const F&) const + { + return {}; + } +#endif +}; + +}}} // namespace boost::hof + +#endif + +#if BOOST_HOF_HAS_CONSTEXPR_LAMBDA +#define BOOST_HOF_STATIC_LAMBDA [] +#else +#define BOOST_HOF_DETAIL_MAKE_STATIC BOOST_HOF_DETAIL_CONSTEXPR_DEDUCE boost::hof::detail::static_function_wrapper_factor() +#define BOOST_HOF_STATIC_LAMBDA BOOST_HOF_DETAIL_MAKE_STATIC = [] +#endif + +#if BOOST_HOF_HAS_INLINE_LAMBDAS +#define BOOST_HOF_STATIC_LAMBDA_FUNCTION BOOST_HOF_STATIC_FUNCTION +#else +#define BOOST_HOF_DETAIL_MAKE_REVEAL_STATIC(T) BOOST_HOF_DETAIL_CONSTEXPR_DEDUCE_UNIQUE(T) boost::hof::detail::reveal_static_lambda_function_wrapper_factor<T>() +#define BOOST_HOF_STATIC_LAMBDA_FUNCTION(name) \ +struct fit_private_static_function_ ## name {}; \ +BOOST_HOF_STATIC_AUTO_REF name = BOOST_HOF_DETAIL_MAKE_REVEAL_STATIC(fit_private_static_function_ ## name) +#endif + +#endif diff --git a/boost/hof/lazy.hpp b/boost/hof/lazy.hpp new file mode 100644 index 0000000000..713e78a87b --- /dev/null +++ b/boost/hof/lazy.hpp @@ -0,0 +1,299 @@ +/*============================================================================= + Copyright (c) 2014 Paul Fultz II + lazy.h + 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_HOF_GUARD_FUNCTION_LAZY_H +#define BOOST_HOF_GUARD_FUNCTION_LAZY_H + +/// lazy +/// ==== +/// +/// Description +/// ----------- +/// +/// The `lazy` function adaptor returns a function object call wrapper for a +/// function. Calling this wrapper is equivalent to invoking the function. It +/// is a simple form of lambda expressions, but is constexpr friendly. By +/// default, `lazy` captures all of its variables by value, just like `bind`. +/// `std::ref` can be used to capture references instead. +/// +/// Ultimately, calling `lazy(f)(x)` is the equivalent to calling +/// `std::bind(f, x)` except the lazy version can be called in a constexpr +/// context, as well. The `lazy` adaptor is compatible with `std::bind`, so +/// most of the time `lazy` and `std::bind` can be used interchangeably. +/// +/// Synopsis +/// -------- +/// +/// template<class F> +/// constexpr lazy_adaptor<F> lazy(F f); +/// +/// Semantics +/// --------- +/// +/// assert(lazy(f)(xs...) == std::bind(f, xs...)) +/// assert(lazy(f)(xs...)() == f(xs...)) +/// assert(lazy(f)(_1)(x) == f(x)) +/// assert(lazy(f)(lazy(g)(_1))(x) == f(g(x))) +/// +/// Requirements +/// ------------ +/// +/// F must be: +/// +/// * [ConstInvocable](ConstInvocable) +/// * MoveConstructible +/// +/// Example +/// ------- +/// +/// #include <boost/hof.hpp> +/// #include <cassert> +/// using namespace boost::hof; +/// +/// int main() { +/// auto add = [](auto x, auto y) { return x+y; }; +/// auto increment = lazy(add)(_1, 1); +/// assert(increment(5) == 6); +/// } +/// +/// References +/// ---------- +/// +/// * [std::bind](http://en.cppreference.com/w/cpp/utility/functional/bind) +/// + +#include <boost/hof/arg.hpp> +#include <boost/hof/first_of.hpp> +#include <boost/hof/always.hpp> +#include <boost/hof/static.hpp> +#include <boost/hof/detail/delegate.hpp> +#include <boost/hof/detail/compressed_pair.hpp> +#include <boost/hof/pack.hpp> +#include <boost/hof/detail/make.hpp> +#include <boost/hof/detail/static_const_var.hpp> +#include <functional> +#include <type_traits> + +namespace boost { namespace hof { + +namespace detail { + +struct placeholder_transformer +{ + template<class T, typename std::enable_if<(std::is_placeholder<T>::value > 0), int>::type = 0> + constexpr detail::make_args_f<std::size_t, std::is_placeholder<T>::value> operator()(const T&) const noexcept + { + return {}; + } +}; + +struct bind_transformer +{ + template<class T, typename std::enable_if<std::is_bind_expression<T>::value, int>::type = 0> + constexpr const T& operator()(const T& x) const noexcept + { + return x; + } +}; + +struct ref_transformer +{ + template<class T> + constexpr auto operator()(std::reference_wrapper<T> x) const + BOOST_HOF_SFINAE_RETURNS(boost::hof::always_ref(x.get())); +}; + +struct id_transformer +{ + template<class T> + constexpr auto operator()(T&& x) const + BOOST_HOF_SFINAE_RETURNS(always_detail::always_base<T>(BOOST_HOF_FORWARD(T)(x))); +}; + +BOOST_HOF_DECLARE_STATIC_VAR(pick_transformer, first_of_adaptor<placeholder_transformer, bind_transformer, ref_transformer, id_transformer>); + +template<class T, class Pack> +constexpr auto lazy_transform(T&& x, const Pack& p) BOOST_HOF_RETURNS +( + p(boost::hof::detail::pick_transformer(BOOST_HOF_FORWARD(T)(x))) +); + +template<class F, class Pack> +struct lazy_unpack +{ + const F& f; + const Pack& p; + + constexpr lazy_unpack(const F& fp, const Pack& pp) noexcept + : f(fp), p(pp) + {} + + template<class... Ts> + constexpr auto operator()(Ts&&... xs) const BOOST_HOF_RETURNS + ( + f(lazy_transform(BOOST_HOF_FORWARD(Ts)(xs), p)...) + ); +}; + +template<class F, class Pack> +constexpr lazy_unpack<F, Pack> make_lazy_unpack(const F& f, const Pack& p) noexcept +{ + return lazy_unpack<F, Pack>(f, p); +} + +template<class F, class Pack> +struct lazy_invoker +: detail::compressed_pair<F, Pack> +{ + typedef detail::compressed_pair<F, Pack> base_type; + typedef lazy_invoker fit_rewritable1_tag; + +#ifdef _MSC_VER + BOOST_HOF_INHERIT_CONSTRUCTOR(lazy_invoker, base_type) +#else + BOOST_HOF_INHERIT_DEFAULT_EMPTY(lazy_invoker, base_type) + + template<class X, class Y, + BOOST_HOF_ENABLE_IF_CONSTRUCTIBLE(base_type, X&&, Y&&) + > + constexpr lazy_invoker(X&& x, Y&& y) + BOOST_HOF_NOEXCEPT_CONSTRUCTIBLE(base_type, X&&, Y&&) + : base_type(BOOST_HOF_FORWARD(X)(x), BOOST_HOF_FORWARD(Y)(y)) + {} +#endif + + template<class... Ts> + constexpr const F& base_function(Ts&&... xs) const noexcept + { + return this->first(xs...); + } + + template<class... Ts> + constexpr const Pack& get_pack(Ts&&... xs) const noexcept + { + return this->second(xs...); + } + + BOOST_HOF_RETURNS_CLASS(lazy_invoker); + + template<class... Ts> + constexpr auto operator()(Ts&&... xs) const BOOST_HOF_RETURNS + ( + BOOST_HOF_MANGLE_CAST(const Pack&)(BOOST_HOF_CONST_THIS->get_pack(xs...))( + boost::hof::detail::make_lazy_unpack( + BOOST_HOF_MANGLE_CAST(const F&)(BOOST_HOF_CONST_THIS->base_function(xs...)), + boost::hof::pack_forward(BOOST_HOF_FORWARD(Ts)(xs)...) + ) + ) + ); +}; + +template<class F, class Pack> +constexpr lazy_invoker<F, Pack> make_lazy_invoker(F f, Pack pack) +BOOST_HOF_NOEXCEPT_CONSTRUCTIBLE(lazy_invoker<F, Pack>, F&&, Pack&&) +{ + return lazy_invoker<F, Pack>(static_cast<F&&>(f), static_cast<Pack&&>(pack)); +} + +template<class F> +struct lazy_nullary_invoker : F +{ + BOOST_HOF_INHERIT_CONSTRUCTOR(lazy_nullary_invoker, F); + + template<class... Ts> + constexpr const F& base_function(Ts&&... xs) const noexcept + { + return boost::hof::always_ref(*this)(xs...); + } + + BOOST_HOF_RETURNS_CLASS(lazy_nullary_invoker); + + template<class... Ts> + constexpr auto operator()(Ts&&... xs) const BOOST_HOF_RETURNS + ( + BOOST_HOF_MANGLE_CAST(const F&)(BOOST_HOF_CONST_THIS->base_function(xs...))() + ); +}; + +template<class F> +constexpr lazy_nullary_invoker<F> make_lazy_nullary_invoker(F f) +BOOST_HOF_NOEXCEPT_CONSTRUCTIBLE(lazy_nullary_invoker<F>, F&&) +{ + return lazy_nullary_invoker<F>(static_cast<F&&>(f)); +} +} + + +template<class F> +struct lazy_adaptor : detail::callable_base<F> +{ + BOOST_HOF_INHERIT_CONSTRUCTOR(lazy_adaptor, detail::callable_base<F>); + + template<class... Ts> + constexpr const detail::callable_base<F>& base_function(Ts&&... xs) const noexcept + { + return boost::hof::always_ref(*this)(xs...); + } + + BOOST_HOF_RETURNS_CLASS(lazy_adaptor); + + template<class T, class... Ts> + constexpr auto operator()(T x, Ts... xs) const BOOST_HOF_RETURNS + ( + boost::hof::detail::make_lazy_invoker(BOOST_HOF_RETURNS_C_CAST(detail::callable_base<F>&&)(BOOST_HOF_CONST_THIS->base_function(x, xs...)), + boost::hof::pack_basic(BOOST_HOF_RETURNS_STATIC_CAST(T&&)(x), BOOST_HOF_RETURNS_STATIC_CAST(Ts&&)(xs)...)) + ); + + // Workaround for gcc 4.7 + template<class Unused=int> + constexpr detail::lazy_nullary_invoker<F> operator()() const + BOOST_HOF_RETURNS_DEDUCE_NOEXCEPT( + boost::hof::detail::make_lazy_nullary_invoker(BOOST_HOF_RETURNS_C_CAST(detail::callable_base<F>&&)( + BOOST_HOF_CONST_THIS->base_function(BOOST_HOF_RETURNS_CONSTRUCT(Unused)()) + )) + ) + { + return boost::hof::detail::make_lazy_nullary_invoker((detail::callable_base<F>&&)( + this->base_function(Unused()) + )); + } + + // TODO: Overloads to use with ref qualifiers + + // template<class... Ts> + // constexpr auto operator()(Ts... xs) const& BOOST_HOF_RETURNS + // ( + // boost::hof::detail::make_lazy_invoker(this->base_function(xs...), + // pack(boost::hof::move(xs)...)) + // ); + + // template<class... Ts> + // constexpr auto operator()(Ts... xs) && BOOST_HOF_RETURNS + // ( + // boost::hof::detail::make_lazy_invoker((F&&)this->base_function(xs...), + // pack(boost::hof::move(xs)...)) + // ); + +}; + +BOOST_HOF_DECLARE_STATIC_VAR(lazy, detail::make<lazy_adaptor>); + +}} // namespace boost::hof + +namespace std { + template<class F, class Pack> + struct is_bind_expression<boost::hof::detail::lazy_invoker<F, Pack>> + : std::true_type + {}; + + template<class F> + struct is_bind_expression<boost::hof::detail::lazy_nullary_invoker<F>> + : std::true_type + {}; +} + +#endif diff --git a/boost/hof/lift.hpp b/boost/hof/lift.hpp new file mode 100644 index 0000000000..0fe6652db7 --- /dev/null +++ b/boost/hof/lift.hpp @@ -0,0 +1,110 @@ +/*============================================================================= + Copyright (c) 2015 Paul Fultz II + lift.h + 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_HOF_GUARD_FUNCTION_LIFT_H +#define BOOST_HOF_GUARD_FUNCTION_LIFT_H + +/// BOOST_HOF_LIFT +/// ======== +/// +/// Description +/// ----------- +/// +/// The macros `BOOST_HOF_LIFT` and `BOOST_HOF_LIFT_CLASS` provide a lift operator that +/// will wrap a template function in a function object so it can be passed to +/// higher-order functions. The `BOOST_HOF_LIFT` macro will wrap the function using +/// a generic lambda. As such, it will not preserve `constexpr`. The +/// `BOOST_HOF_LIFT_CLASS` can be used to declare a class that will wrap function. +/// This will preserve `constexpr` and it can be used on older compilers that +/// don't support generic lambdas yet. +/// +/// Limitation +/// ---------- +/// +/// In C++14, `BOOST_HOF_LIFT` doesn't support `constexpr` due to using a generic +/// lambda. Instead, `BOOST_HOF_LIFT_CLASS` can be used. In C++17, there is no such +/// limitation. +/// +/// Synopsis +/// -------- +/// +/// // Wrap the function in a generic lambda +/// #define BOOST_HOF_LIFT(...) +/// +/// // Declare a class named `name` that will forward to the function +/// #define BOOST_HOF_LIFT_CLASS(name, ...) +/// +/// Example +/// ------- +/// +/// #include <boost/hof.hpp> +/// #include <cassert> +/// #include <algorithm> +/// +/// // Declare the class `max_f` +/// BOOST_HOF_LIFT_CLASS(max_f, std::max); +/// +/// int main() { +/// auto my_max = BOOST_HOF_LIFT(std::max); +/// assert(my_max(3, 4) == std::max(3, 4)); +/// assert(max_f()(3, 4) == std::max(3, 4)); +/// } +/// + +#include <boost/hof/detail/delegate.hpp> +#include <boost/hof/returns.hpp> +#include <boost/hof/lambda.hpp> +#include <boost/hof/detail/forward.hpp> + +namespace boost { namespace hof { namespace detail { + +template<class F, class NoExcept> +struct lift_noexcept : F +{ + BOOST_HOF_INHERIT_CONSTRUCTOR(lift_noexcept, F); + + template<class... Ts> + constexpr auto operator()(Ts&&... xs) const + noexcept(decltype(std::declval<NoExcept>()(BOOST_HOF_FORWARD(Ts)(xs)...)){}) + -> decltype(std::declval<F>()(BOOST_HOF_FORWARD(Ts)(xs)...)) + { return F(*this)(BOOST_HOF_FORWARD(Ts)(xs)...);} +}; + +template<class F, class NoExcept> +constexpr lift_noexcept<F, NoExcept> make_lift_noexcept(F f, NoExcept) +{ + return {f}; +} + +} + +}} // namespace boost::hof + +#define BOOST_HOF_LIFT_IS_NOEXCEPT(...) std::integral_constant<bool, noexcept(decltype(__VA_ARGS__)(__VA_ARGS__))>{} + +#if defined (_MSC_VER) +#define BOOST_HOF_LIFT(...) (BOOST_HOF_STATIC_LAMBDA { BOOST_HOF_LIFT_CLASS(fit_local_lift_t, __VA_ARGS__); return fit_local_lift_t(); }()) +#elif defined (__clang__) +#define BOOST_HOF_LIFT(...) (boost::hof::detail::make_lift_noexcept( \ + BOOST_HOF_STATIC_LAMBDA(auto&&... xs) \ + -> decltype((__VA_ARGS__)(BOOST_HOF_FORWARD(decltype(xs))(xs)...)) \ + { return (__VA_ARGS__)(BOOST_HOF_FORWARD(decltype(xs))(xs)...); }, \ + BOOST_HOF_STATIC_LAMBDA(auto&&... xs) { return BOOST_HOF_LIFT_IS_NOEXCEPT((__VA_ARGS__)(BOOST_HOF_FORWARD(decltype(xs))(xs)...)); } \ +)) +#else +#define BOOST_HOF_LIFT(...) (BOOST_HOF_STATIC_LAMBDA(auto&&... xs) BOOST_HOF_RETURNS((__VA_ARGS__)(BOOST_HOF_FORWARD(decltype(xs))(xs)...))) +#endif + +#define BOOST_HOF_LIFT_CLASS(name, ...) \ +struct name \ +{ \ + template<class... Ts> \ + constexpr auto operator()(Ts&&... xs) const \ + BOOST_HOF_RETURNS((__VA_ARGS__)(BOOST_HOF_FORWARD(Ts)(xs)...)) \ +} + +#endif diff --git a/boost/hof/limit.hpp b/boost/hof/limit.hpp new file mode 100644 index 0000000000..e80356386c --- /dev/null +++ b/boost/hof/limit.hpp @@ -0,0 +1,142 @@ +/*============================================================================= + Copyright (c) 2016 Paul Fultz II + limit.h + 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_HOF_GUARD_LIMIT_H +#define BOOST_HOF_GUARD_LIMIT_H + +/// limit +/// ===== +/// +/// Description +/// ----------- +/// +/// The `limit` function decorator annotates the function with the max number +/// of parameters. The `limit_c` version can be used to give the max number +/// directly(instead of relying on an integral constant). The parameter limit +/// can be read by using the [`function_param_limit`](function_param_limit) +/// trait. Using `limit` is useful to improve error reporting with partially +/// evaluated functions. +/// +/// Synopsis +/// -------- +/// +/// template<class IntegralConstant> +/// constexpr auto limit(IntegralConstant); +/// +/// template<std::size_t N, class F> +/// constexpr auto limit_c(F); +/// +/// Requirements +/// ------------ +/// +/// IntegralConstant must be: +/// +/// * IntegralConstant +/// +/// F must be: +/// +/// * [ConstInvocable](ConstInvocable) +/// * MoveConstructible +/// +/// Example +/// ------- +/// +/// #include <boost/hof.hpp> +/// #include <cassert> +/// using namespace boost::hof; +/// +/// struct sum_f +/// { +/// template<class T> +/// int operator()(T x, T y) const +/// { +/// return x+y; +/// } +/// }; +/// BOOST_HOF_STATIC_FUNCTION(sum) = limit_c<2>(sum_f()); +/// +/// int main() { +/// assert(3 == sum(1, 2)); +/// } +/// +/// See Also +/// -------- +/// +/// * [Partial function evaluation](<Partial function evaluation>) +/// * [function_param_limit](function_param_limit) +/// + +#include <boost/hof/detail/callable_base.hpp> +#include <boost/hof/detail/forward.hpp> +#include <boost/hof/detail/delegate.hpp> +#include <boost/hof/detail/move.hpp> +#include <boost/hof/detail/static_const_var.hpp> +#include <boost/hof/always.hpp> +#include <boost/hof/function_param_limit.hpp> + +namespace boost { namespace hof { + +namespace detail { +// TODO: Make this work with fit_rewritable1_tag +template<std::size_t N, class F> +struct limit_adaptor : detail::callable_base<F> +{ + typedef std::integral_constant<std::size_t, N> fit_function_param_limit; + BOOST_HOF_INHERIT_CONSTRUCTOR(limit_adaptor, detail::callable_base<F>) + + template<class... Ts> + constexpr const detail::callable_base<F>& base_function(Ts&&... xs) const + { + return boost::hof::always_ref(*this)(xs...); + } + + BOOST_HOF_RETURNS_CLASS(limit_adaptor); + + template<class... Ts, class=typename std::enable_if<(sizeof...(Ts) <= N)>::type> + constexpr BOOST_HOF_SFINAE_RESULT(const detail::callable_base<F>&, id_<Ts>...) + operator()(Ts&&... xs) const BOOST_HOF_SFINAE_RETURNS + ( + (BOOST_HOF_MANGLE_CAST(const detail::callable_base<F>&)(BOOST_HOF_CONST_THIS->base_function(xs...))) + (BOOST_HOF_FORWARD(Ts)(xs)...) + ); + +}; + +template<std::size_t N> +struct make_limit_f +{ + constexpr make_limit_f() + {} + template<class F> + constexpr limit_adaptor<N, F> operator()(F f) const + { + return limit_adaptor<N, F>(static_cast<F&&>(f)); + } +}; + +struct limit_f +{ + template<class IntegralConstant, std::size_t N=IntegralConstant::type::value> + constexpr make_limit_f<N> operator()(IntegralConstant) const + { + return {}; + } +}; + +} + +template<std::size_t N, class F> +constexpr detail::limit_adaptor<N, F> limit_c(F f) +{ + return detail::limit_adaptor<N, F>(static_cast<F&&>(f)); +} + +BOOST_HOF_DECLARE_STATIC_VAR(limit, detail::limit_f); + +}} // namespace boost::hof + +#endif diff --git a/boost/hof/match.hpp b/boost/hof/match.hpp new file mode 100644 index 0000000000..abf60194f5 --- /dev/null +++ b/boost/hof/match.hpp @@ -0,0 +1,121 @@ +/*============================================================================= + Copyright (c) 2012 Paul Fultz II + match.h + 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_HOF_GUARD_FUNCTION_OVERLOAD_H +#define BOOST_HOF_GUARD_FUNCTION_OVERLOAD_H + +/// match +/// ===== +/// +/// Description +/// ----------- +/// +/// The `match` function adaptor combines several functions together and +/// resolves which one should be called by using C++ overload resolution. This +/// is different than the [`first_of`](/include/boost/hof/conditional) adaptor which resolves +/// them based on order. +/// +/// Synopsis +/// -------- +/// +/// template<class... Fs> +/// constexpr match_adaptor<Fs...> match(Fs...fs); +/// +/// Requirements +/// ------------ +/// +/// Fs must be: +/// +/// * [ConstInvocable](ConstInvocable) +/// * MoveConstructible +/// +/// Example +/// ------- +/// +/// #include <boost/hof.hpp> +/// using namespace boost::hof; +/// +/// struct int_class +/// { +/// int operator()(int) const +/// { +/// return 1; +/// } +/// }; +/// +/// struct foo +/// {}; +/// +/// struct foo_class +/// { +/// foo operator()(foo) const +/// { +/// return foo(); +/// } +/// }; +/// +/// typedef match_adaptor<int_class, foo_class> fun; +/// +/// static_assert(std::is_same<int, decltype(fun()(1))>::value, "Failed match"); +/// static_assert(std::is_same<foo, decltype(fun()(foo()))>::value, "Failed match"); +/// +/// int main() {} +/// +/// References +/// ---------- +/// +/// * [POO51](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0051r2.pdf) - Proposal for C++ +/// Proposal for C++ generic overload function +/// + +#include <boost/hof/reveal.hpp> +#include <boost/hof/detail/callable_base.hpp> +#include <boost/hof/detail/delegate.hpp> +#include <boost/hof/detail/move.hpp> +#include <boost/hof/detail/make.hpp> +#include <boost/hof/detail/static_const_var.hpp> + +namespace boost { namespace hof { + +template<class...Fs> struct match_adaptor; + +template<class F, class...Fs> +struct match_adaptor<F, Fs...> : detail::callable_base<F>, match_adaptor<Fs...> +{ + typedef match_adaptor<Fs...> base; + typedef match_adaptor fit_rewritable_tag; + + struct failure + : failure_for<detail::callable_base<F>, Fs...> + {}; + + BOOST_HOF_INHERIT_DEFAULT(match_adaptor, detail::callable_base<F>, base); + + template<class X, class... Xs, BOOST_HOF_ENABLE_IF_CONVERTIBLE(X, detail::callable_base<F>), BOOST_HOF_ENABLE_IF_CONSTRUCTIBLE(base, Xs...)> + constexpr match_adaptor(X&& f1, Xs&& ... fs) + : detail::callable_base<F>(BOOST_HOF_FORWARD(X)(f1)), base(BOOST_HOF_FORWARD(Xs)(fs)...) + {} + + using F::operator(); + using base::operator(); +}; + +template<class F> +struct match_adaptor<F> : detail::callable_base<F> +{ + typedef detail::callable_base<F> base; + typedef match_adaptor fit_rewritable_tag; + using F::operator(); + + BOOST_HOF_INHERIT_CONSTRUCTOR(match_adaptor, detail::callable_base<F>); +}; + +BOOST_HOF_DECLARE_STATIC_VAR(match, detail::make<match_adaptor>); + +}} // namespace boost::hof + +#endif diff --git a/boost/hof/mutable.hpp b/boost/hof/mutable.hpp new file mode 100644 index 0000000000..b704c027cf --- /dev/null +++ b/boost/hof/mutable.hpp @@ -0,0 +1,68 @@ +/*============================================================================= + Copyright (c) 2014 Paul Fultz II + mutable.h + 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_HOF_GUARD_FUNCTION_MUTABLE_H +#define BOOST_HOF_GUARD_FUNCTION_MUTABLE_H + +/// mutable +/// ======= +/// +/// Description +/// ----------- +/// +/// The `mutable` function adaptor allows using a non-const function object +/// inside of a const-function object. In Fit, all the function adaptors use +/// `const` call overloads, so if there is a function that has a non-const +/// call operator, it couldn't be used directly. So, `mutable_` allows the +/// function to be used inside of the call operator. +/// +/// NOTE: This function should be used with caution since many functions are +/// copied, so relying on some internal shared state can be error-prone. +/// +/// Synopsis +/// -------- +/// +/// template<class F> +/// mutable_adaptor<F> mutable_(F f) +/// +/// Requirements +/// ------------ +/// +/// F must be: +/// +/// * [MutableFunctionObject](MutableFunctionObject) +/// * MoveConstructible +/// + +#include <boost/hof/detail/result_of.hpp> +#include <boost/hof/detail/delegate.hpp> +#include <boost/hof/detail/move.hpp> +#include <boost/hof/detail/make.hpp> +#include <boost/hof/detail/static_const_var.hpp> + +namespace boost { namespace hof { + +template<class F> +struct mutable_adaptor +{ + mutable F f; + + BOOST_HOF_DELEGATE_CONSTRUCTOR(mutable_adaptor, F, f); + + BOOST_HOF_RETURNS_CLASS(mutable_adaptor); + + template<class... Ts> + BOOST_HOF_SFINAE_RESULT(F, id_<Ts>...) + operator()(Ts&&... xs) const BOOST_HOF_SFINAE_RETURNS(BOOST_HOF_CONST_THIS->f(BOOST_HOF_FORWARD(Ts)(xs)...)); +}; + +BOOST_HOF_DECLARE_STATIC_VAR(mutable_, detail::make<mutable_adaptor>); + +}} // namespace boost::hof + + +#endif diff --git a/boost/hof/pack.hpp b/boost/hof/pack.hpp new file mode 100644 index 0000000000..b0c5b2c206 --- /dev/null +++ b/boost/hof/pack.hpp @@ -0,0 +1,423 @@ +/*============================================================================= + Copyright (c) 2014 Paul Fultz II + pack.h + 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_HOF_GUARD_FUNCTION_PACK_H +#define BOOST_HOF_GUARD_FUNCTION_PACK_H + +/// pack +/// ==== +/// +/// Description +/// ----------- +/// +/// The `pack` function returns a higher order function object that takes a +/// function that will be passed the initial elements. The function object is +/// a sequence that can be unpacked with `unpack_adaptor` as well. Also, +/// `pack_join` can be used to join multiple packs together. +/// +/// Synopsis +/// -------- +/// +/// // Decay everything before capturing +/// template<class... Ts> +/// constexpr auto pack(Ts&&... xs); +/// +/// // Capture lvalues by reference and rvalue reference by reference +/// template<class... Ts> +/// constexpr auto pack_forward(Ts&&... xs); +/// +/// // Capture lvalues by reference and rvalues by value. +/// template<class... Ts> +/// constexpr auto pack_basic(Ts&&... xs); +/// +/// // Join multiple packs together +/// template<class... Ts> +/// constexpr auto pack_join(Ts&&... xs); +/// +/// Semantics +/// --------- +/// +/// assert(pack(xs...)(f) == f(xs...)); +/// assert(unpack(f)(pack(xs...)) == f(xs...)); +/// +/// assert(pack_join(pack(xs...), pack(ys...)) == pack(xs..., ys...)); +/// +/// +/// Example +/// ------- +/// +/// #include <boost/hof.hpp> +/// #include <cassert> +/// using namespace boost::hof; +/// +/// struct sum +/// { +/// template<class T, class U> +/// T operator()(T x, U y) const +/// { +/// return x+y; +/// } +/// }; +/// +/// int main() { +/// int r = pack(3, 2)(sum()); +/// assert(r == 5); +/// } +/// +/// See Also +/// -------- +/// +/// * [unpack](unpack) +/// + +#include <boost/hof/detail/seq.hpp> +#include <boost/hof/detail/delegate.hpp> +#include <boost/hof/detail/remove_rvalue_reference.hpp> +#include <boost/hof/detail/unwrap.hpp> +#include <boost/hof/detail/static_const_var.hpp> +#include <boost/hof/unpack_sequence.hpp> +#include <boost/hof/returns.hpp> +#include <boost/hof/alias.hpp> +#include <boost/hof/decay.hpp> + +namespace boost { namespace hof { namespace detail { + +template<class...> +struct pack_tag +{}; + +template<class T, class Tag> +struct pack_holder +: detail::alias_empty<T, Tag> +{}; + +template<class Seq, class... Ts> +struct pack_base; + +template<class T> +struct is_copyable +: std::integral_constant<bool, ( + BOOST_HOF_IS_CONSTRUCTIBLE(T, const T&) +)> +{}; + +template<class T> +struct is_copyable<T&> +: std::true_type +{}; + +template<class T> +struct is_copyable<T&&> +: std::true_type +{}; + +template<class T, class Tag, class X, class... Ts, typename std::enable_if< + is_copyable<T>::value && !std::is_lvalue_reference<T>::value +, int>::type = 0> +constexpr T pack_get(X&& x, Ts&&... xs) noexcept(BOOST_HOF_IS_NOTHROW_COPY_CONSTRUCTIBLE(T)) +{ + return static_cast<T>(boost::hof::alias_value<Tag, T>(BOOST_HOF_FORWARD(X)(x), xs...)); +} + +template<class T, class Tag, class X, class... Ts, typename std::enable_if< + std::is_lvalue_reference<T>::value +, int>::type = 0> +constexpr T pack_get(X&& x, Ts&&... xs) noexcept +{ + return boost::hof::alias_value<Tag, T>(x, xs...); +} + +template<class T, class Tag, class X, class... Ts, typename std::enable_if< + !is_copyable<T>::value +, int>::type = 0> +constexpr auto pack_get(X&& x, Ts&&... xs) BOOST_HOF_RETURNS +( + boost::hof::alias_value<Tag, T>(BOOST_HOF_FORWARD(X)(x), xs...) +); + +#if (defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ < 7) || defined(_MSC_VER) +template<class... Ts> +struct pack_holder_base +: Ts::type... +{ + template<class... Xs, class=typename std::enable_if<(sizeof...(Xs) == sizeof...(Ts))>::type> + constexpr pack_holder_base(Xs&&... xs) + BOOST_HOF_NOEXCEPT(BOOST_HOF_AND_UNPACK(BOOST_HOF_IS_NOTHROW_CONSTRUCTIBLE(typename Ts::type, Xs&&))) + : Ts::type(BOOST_HOF_FORWARD(Xs)(xs))... + {} +#ifndef _MSC_VER + // BOOST_HOF_INHERIT_DEFAULT(pack_holder_base, typename std::remove_cv<typename std::remove_reference<typename Ts::type>::type>::type...) + BOOST_HOF_INHERIT_DEFAULT(pack_holder_base, typename Ts::type...) +#endif +}; + +template<class T> +struct pack_holder_base<T> +: T::type +{ + typedef typename T::type base; + BOOST_HOF_INHERIT_CONSTRUCTOR(pack_holder_base, base); +}; + +template<class... Ts> +struct pack_holder_builder +{ + template<class T, std::size_t N> + struct apply + : pack_holder<T, pack_tag<seq<N>, Ts...>> + {}; +}; + +template<std::size_t... Ns, class... Ts> +struct pack_base<seq<Ns...>, Ts...> +: pack_holder_base<typename pack_holder_builder<Ts...>::template apply<Ts, Ns>...> +{ + typedef pack_holder_base<typename pack_holder_builder<Ts...>::template apply<Ts, Ns>...> base; + template<class X1, class X2, class... Xs> + constexpr pack_base(X1&& x1, X2&& x2, Xs&&... xs) + BOOST_HOF_NOEXCEPT(BOOST_HOF_IS_NOTHROW_CONSTRUCTIBLE(base, X1&&, X2&&, Xs&...)) + : base(BOOST_HOF_FORWARD(X1)(x1), BOOST_HOF_FORWARD(X2)(x2), BOOST_HOF_FORWARD(Xs)(xs)...) + {} + + template<class X1, typename std::enable_if<(BOOST_HOF_IS_CONSTRUCTIBLE(base, X1)), int>::type = 0> + constexpr pack_base(X1&& x1) + BOOST_HOF_NOEXCEPT(BOOST_HOF_IS_NOTHROW_CONSTRUCTIBLE(base, X1&&)) + : base(BOOST_HOF_FORWARD(X1)(x1)) + {} + + // BOOST_HOF_INHERIT_DEFAULT(pack_base, typename std::remove_cv<typename std::remove_reference<Ts>::type>::type...); + BOOST_HOF_INHERIT_DEFAULT(pack_base, Ts...); + + BOOST_HOF_RETURNS_CLASS(pack_base); + + template<class F> + constexpr auto operator()(F&& f) const BOOST_HOF_RETURNS + ( + f(boost::hof::detail::pack_get<Ts, pack_tag<seq<Ns>, Ts...>>(*BOOST_HOF_CONST_THIS, f)...) + ); + + typedef std::integral_constant<std::size_t, sizeof...(Ts)> fit_function_param_limit; + + template<class F> + struct apply + : F::template apply<Ts...> + {}; +}; + +template<class T> +struct pack_base<seq<0>, T> +: pack_holder_base<pack_holder<T, pack_tag<seq<0>, T>>> +{ + typedef pack_holder_base<pack_holder<T, pack_tag<seq<0>, T>>> base; + + template<class X1, typename std::enable_if<(BOOST_HOF_IS_CONSTRUCTIBLE(base, X1)), int>::type = 0> + constexpr pack_base(X1&& x1) + BOOST_HOF_NOEXCEPT(BOOST_HOF_IS_NOTHROW_CONSTRUCTIBLE(base, X1&&)) + : base(BOOST_HOF_FORWARD(X1)(x1)) + {} + + BOOST_HOF_INHERIT_DEFAULT(pack_base, T); + + BOOST_HOF_RETURNS_CLASS(pack_base); + + template<class F> + constexpr auto operator()(F&& f) const BOOST_HOF_RETURNS + ( + f(boost::hof::detail::pack_get<T, pack_tag<seq<0>, T>>(*BOOST_HOF_CONST_THIS, f)) + ); + + typedef std::integral_constant<std::size_t, 1> fit_function_param_limit; + + template<class F> + struct apply + : F::template apply<T> + {}; +}; + +#else + +template<std::size_t... Ns, class... Ts> +struct pack_base<seq<Ns...>, Ts...> +: pack_holder<Ts, pack_tag<seq<Ns>, Ts...>>::type... +{ + // BOOST_HOF_INHERIT_DEFAULT(pack_base, typename std::remove_cv<typename std::remove_reference<Ts>::type>::type...); + BOOST_HOF_INHERIT_DEFAULT(pack_base, Ts...); + + template<class... Xs, BOOST_HOF_ENABLE_IF_CONVERTIBLE_UNPACK(Xs&&, typename pack_holder<Ts, pack_tag<seq<Ns>, Ts...>>::type)> + constexpr pack_base(Xs&&... xs) + BOOST_HOF_NOEXCEPT(BOOST_HOF_AND_UNPACK(BOOST_HOF_IS_NOTHROW_CONSTRUCTIBLE(typename pack_holder<Ts, pack_tag<seq<Ns>, Ts...>>::type, Xs&&))) + : pack_holder<Ts, pack_tag<seq<Ns>, Ts...>>::type(BOOST_HOF_FORWARD(Xs)(xs))... + {} + + // typedef pack_base<seq<Ns...>, Ts...> self_t; + + BOOST_HOF_RETURNS_CLASS(pack_base); + + template<class F> + constexpr auto operator()(F&& f) const BOOST_HOF_RETURNS + ( + f(boost::hof::detail::pack_get<Ts, pack_tag<seq<Ns>, Ts...>>(*BOOST_HOF_CONST_THIS, f)...) + ); + + typedef std::integral_constant<std::size_t, sizeof...(Ts)> fit_function_param_limit; + + template<class F> + struct apply + : F::template apply<Ts...> + {}; +}; + +#endif + +template<> +struct pack_base<seq<> > +{ + template<class F> + constexpr auto operator()(F&& f) const BOOST_HOF_RETURNS + (f()); + + typedef std::integral_constant<std::size_t, 0> fit_function_param_limit; + + template<class F> + struct apply + : F::template apply<> + {}; +}; + +#define BOOST_HOF_DETAIL_UNPACK_PACK_BASE(ref, move) \ +template<class F, std::size_t... Ns, class... Ts> \ +constexpr auto unpack_pack_base(F&& f, pack_base<seq<Ns...>, Ts...> ref x) \ +BOOST_HOF_RETURNS(f(boost::hof::alias_value<pack_tag<seq<Ns>, Ts...>, Ts>(move(x), f)...)) +BOOST_HOF_UNARY_PERFECT_FOREACH(BOOST_HOF_DETAIL_UNPACK_PACK_BASE) + +template<class P1, class P2> +struct pack_join_base; + +// TODO: Extend to join more than two packs at a time +template<std::size_t... Ns1, class... Ts1, std::size_t... Ns2, class... Ts2> +struct pack_join_base<pack_base<seq<Ns1...>, Ts1...>, pack_base<seq<Ns2...>, Ts2...>> +{ + static constexpr long total_size = sizeof...(Ts1) + sizeof...(Ts2); + typedef pack_base<typename detail::gens<total_size>::type, Ts1..., Ts2...> result_type; + + template<class P1, class P2> + static constexpr result_type call(P1&& p1, P2&& p2) + BOOST_HOF_RETURNS_DEDUCE_NOEXCEPT( + result_type( + boost::hof::detail::pack_get<Ts1, pack_tag<seq<Ns1>, Ts1...>>(BOOST_HOF_FORWARD(P1)(p1))..., + boost::hof::detail::pack_get<Ts2, pack_tag<seq<Ns2>, Ts2...>>(BOOST_HOF_FORWARD(P2)(p2))...) + ) + { + return result_type( + boost::hof::detail::pack_get<Ts1, pack_tag<seq<Ns1>, Ts1...>>(BOOST_HOF_FORWARD(P1)(p1))..., + boost::hof::detail::pack_get<Ts2, pack_tag<seq<Ns2>, Ts2...>>(BOOST_HOF_FORWARD(P2)(p2))...); + } +}; + +template<class P1, class P2> +struct pack_join_result +: pack_join_base< + typename std::remove_cv<typename std::remove_reference<P1>::type>::type, + typename std::remove_cv<typename std::remove_reference<P2>::type>::type +> +{}; + + +struct pack_basic_f +{ + template<class... Ts> + constexpr auto operator()(Ts&&... xs) const BOOST_HOF_RETURNS + ( + pack_base<typename gens<sizeof...(Ts)>::type, typename remove_rvalue_reference<Ts>::type...>(BOOST_HOF_FORWARD(Ts)(xs)...) + ); +}; + +struct pack_forward_f +{ + template<class... Ts> + constexpr auto operator()(Ts&&... xs) const BOOST_HOF_RETURNS + ( + pack_base<typename gens<sizeof...(Ts)>::type, Ts&&...>(BOOST_HOF_FORWARD(Ts)(xs)...) + ); +}; + +struct pack_f +{ + template<class... Ts> + constexpr auto operator()(Ts&&... xs) const BOOST_HOF_RETURNS + ( + pack_basic_f()(boost::hof::decay(BOOST_HOF_FORWARD(Ts)(xs))...) + ); +}; + +template<class P1, class P2> +constexpr typename pack_join_result<P1, P2>::result_type make_pack_join_dual(P1&& p1, P2&& p2) +BOOST_HOF_RETURNS_DEDUCE_NOEXCEPT(pack_join_result<P1, P2>::call(BOOST_HOF_FORWARD(P1)(p1), BOOST_HOF_FORWARD(P2)(p2))) +{ + return pack_join_result<P1, P2>::call(BOOST_HOF_FORWARD(P1)(p1), BOOST_HOF_FORWARD(P2)(p2)); +} + +// Manually compute join return type to make older gcc happy +template<class... Ts> +struct join_type; + +template<class T> +struct join_type<T> +{ + typedef T type; +}; + +template<class T, class... Ts> +struct join_type<T, Ts...> +{ + typedef typename pack_join_result<T, typename join_type<Ts...>::type>::result_type type; +}; + +template<class P1> +constexpr P1 make_pack_join(P1&& p1) BOOST_HOF_NOEXCEPT_CONSTRUCTIBLE(P1, P1&&) +{ + return BOOST_HOF_FORWARD(P1)(p1); +} + +template<class P1, class... Ps> +constexpr typename join_type<P1, Ps...>::type make_pack_join(P1&& p1, Ps&&... ps) +BOOST_HOF_RETURNS_DEDUCE_NOEXCEPT(make_pack_join_dual(BOOST_HOF_FORWARD(P1)(p1), make_pack_join(BOOST_HOF_FORWARD(Ps)(ps)...))) +{ + return make_pack_join_dual(BOOST_HOF_FORWARD(P1)(p1), make_pack_join(BOOST_HOF_FORWARD(Ps)(ps)...)); +} + +struct pack_join_f +{ + + template<class... Ps> + constexpr auto operator()(Ps&&... ps) const BOOST_HOF_RETURNS + ( + make_pack_join(BOOST_HOF_FORWARD(Ps)(ps)...) + ); +}; + +} + +BOOST_HOF_DECLARE_STATIC_VAR(pack_basic, detail::pack_basic_f); +BOOST_HOF_DECLARE_STATIC_VAR(pack_forward, detail::pack_forward_f); +BOOST_HOF_DECLARE_STATIC_VAR(pack, detail::pack_f); + +BOOST_HOF_DECLARE_STATIC_VAR(pack_join, detail::pack_join_f); + +template<class T, class... Ts> +struct unpack_sequence<detail::pack_base<T, Ts...>> +{ + template<class F, class P> + constexpr static auto apply(F&& f, P&& p) BOOST_HOF_RETURNS + ( + boost::hof::detail::unpack_pack_base(BOOST_HOF_FORWARD(F)(f), BOOST_HOF_FORWARD(P)(p)) + ); +}; + +}} // namespace boost::hof + +#endif diff --git a/boost/hof/partial.hpp b/boost/hof/partial.hpp new file mode 100644 index 0000000000..6c1455f663 --- /dev/null +++ b/boost/hof/partial.hpp @@ -0,0 +1,292 @@ +/*============================================================================= + Copyright (c) 2012 Paul Fultz II + partial.h + 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_HOF_GUARD_FUNCTION_PARTIAL_H +#define BOOST_HOF_GUARD_FUNCTION_PARTIAL_H + +/// partial +/// ======== +/// +/// Description +/// ----------- +/// +/// The `partial` function adaptor allows partial application of the function. +/// If the function can not be called with all the parameters, it will return +/// another function. It will repeatedly do this until the function can +/// finally be called. By default, `partial` captures all of its variables by +/// value, just like bind. As such all parameters must be `MoveConstructible` +/// when the function is aprtial application. `std::ref` can be used to +/// capture references instead. +/// +/// Synopsis +/// -------- +/// +/// template<class F> +/// constexpr partial_adaptor<F> partial(F f); +/// +/// Semantics +/// --------- +/// +/// assert(partial(f)(xs...)(ys...) == f(xs..., ys...)); +/// +/// Requirements +/// ------------ +/// +/// F must be: +/// +/// * [ConstInvocable](ConstInvocable) +/// * MoveConstructible +/// +/// Example +/// ------- +/// +/// #include <boost/hof.hpp> +/// #include <cassert> +/// using namespace boost::hof; +/// +/// struct sum +/// { +/// template<class T, class U> +/// T operator()(T x, U y) const +/// { +/// return x+y; +/// } +/// }; +/// +/// int main() { +/// assert(3 == partial(sum())(1)(2)); +/// } +/// +/// References +/// ---------- +/// +/// * [Partial application](https://en.wikipedia.org/wiki/Partial_application) +/// * [Currying](https://en.wikipedia.org/wiki/Currying) +/// + +#include <boost/hof/first_of.hpp> +#include <boost/hof/static.hpp> +#include <boost/hof/pipable.hpp> +#include <boost/hof/detail/make.hpp> +#include <boost/hof/detail/static_const_var.hpp> + + +namespace boost { namespace hof { + +// TODO: Get rid of sequence parameter +// Forward declare partial_adaptor, since it will be used below +template<class F, class Pack=void > +struct partial_adaptor; + +BOOST_HOF_DECLARE_STATIC_VAR(partial, detail::make<partial_adaptor>); + +namespace detail { + +template<class Derived, class F, class Pack> +struct partial_adaptor_invoke +{ + template<class... Ts> + constexpr const F& get_function(Ts&&...) const noexcept + { + return static_cast<const F&>(static_cast<const Derived&>(*this)); + } + + template<class... Ts> + constexpr const Pack& get_pack(Ts&&...) const noexcept + { + return static_cast<const Pack&>(static_cast<const Derived&>(*this)); + } + + BOOST_HOF_RETURNS_CLASS(partial_adaptor_invoke); + + template<class... Ts> + constexpr BOOST_HOF_SFINAE_RESULT + ( + typename result_of<decltype(boost::hof::pack_join), + id_<const Pack&>, + result_of<decltype(boost::hof::pack_forward), id_<Ts>...> + >::type, + id_<F&&> + ) + operator()(Ts&&... xs) const BOOST_HOF_SFINAE_RETURNS + ( + boost::hof::pack_join + ( + BOOST_HOF_MANGLE_CAST(const Pack&)(BOOST_HOF_CONST_THIS->get_pack(xs...)), + boost::hof::pack_forward(BOOST_HOF_FORWARD(Ts)(xs)...) + ) + (BOOST_HOF_RETURNS_C_CAST(F&&)(BOOST_HOF_CONST_THIS->get_function(xs...))) + ); +}; + +#ifdef _MSC_VER +#define BOOST_HOF_PARTIAL_RETURNS(...) -> decltype(__VA_ARGS__) { return (__VA_ARGS__); } +#else +#define BOOST_HOF_PARTIAL_RETURNS BOOST_HOF_SFINAE_RETURNS +#endif + +template<class Derived, class F, class Pack> +struct partial_adaptor_join +{ + template<class... Ts> + constexpr const F& get_function(Ts&&...) const noexcept + { + return static_cast<const F&>(static_cast<const Derived&>(*this)); + } + + template<class... Ts> + constexpr const Pack& get_pack(Ts&&...) const noexcept + { + return static_cast<const Pack&>(static_cast<const Derived&>(*this)); + } + + BOOST_HOF_RETURNS_CLASS(partial_adaptor_join); + + template<class... Ts, class=typename std::enable_if< + ((sizeof...(Ts) + Pack::fit_function_param_limit::value) < function_param_limit<F>::value) + >::type> + constexpr auto operator()(Ts&&... xs) const +#ifdef _MSC_VER + // Workaround ICE on MSVC + noexcept(BOOST_HOF_IS_NOTHROW_CONSTRUCTIBLE(F, F&&) && noexcept(boost::hof::pack_join(std::declval<const Pack&>(), boost::hof::pack(BOOST_HOF_FORWARD(Ts)(xs)...)))) +#endif + BOOST_HOF_PARTIAL_RETURNS + ( + boost::hof::partial + ( + BOOST_HOF_RETURNS_C_CAST(F&&)(BOOST_HOF_CONST_THIS->get_function(xs...)), + boost::hof::pack_join(BOOST_HOF_MANGLE_CAST(const Pack&)(BOOST_HOF_CONST_THIS->get_pack(xs...)), boost::hof::pack(BOOST_HOF_FORWARD(Ts)(xs)...)) + ) + ); +}; + +template<class Derived, class F> +struct partial_adaptor_pack +{ + + constexpr partial_adaptor_pack() noexcept + {} + + template<class... Ts> + constexpr const F& get_function(Ts&&...) const noexcept + { + return static_cast<const F&>(static_cast<const Derived&>(*this)); + } + + BOOST_HOF_RETURNS_CLASS(partial_adaptor_pack); + + template<class... Ts, class=typename std::enable_if< + (sizeof...(Ts) < function_param_limit<F>::value) + >::type> + constexpr auto operator()(Ts&&... xs) const +#ifdef _MSC_VER + // Workaround ICE on MSVC + noexcept(BOOST_HOF_IS_NOTHROW_CONSTRUCTIBLE(F, F&&) && noexcept(boost::hof::pack(BOOST_HOF_FORWARD(Ts)(xs)...))) +#endif + BOOST_HOF_PARTIAL_RETURNS + ( + boost::hof::partial + ( + BOOST_HOF_RETURNS_C_CAST(F&&)(BOOST_HOF_CONST_THIS->get_function(xs...)), + boost::hof::pack(BOOST_HOF_FORWARD(Ts)(xs)...) + ) + ); +}; +template<class F, class Pack> +struct partial_adaptor_base +{ + typedef basic_first_of_adaptor + < + partial_adaptor_invoke<partial_adaptor<F, Pack>, F, Pack>, + partial_adaptor_join<partial_adaptor<F, Pack>, F, Pack> + > type; +}; + +template<class Derived, class F> +struct partial_adaptor_pack_base +{ + typedef basic_first_of_adaptor + < + F, + partial_adaptor_pack<Derived, F> + > type; +}; + +} + +template<class F, class Pack> +struct partial_adaptor : detail::partial_adaptor_base<F, Pack>::type, F, Pack +{ + typedef typename detail::partial_adaptor_base<F, Pack>::type base; + + typedef partial_adaptor fit_rewritable1_tag; + + template<class... Ts> + constexpr const F& base_function(Ts&&...) const noexcept + { + return *this; + } + + constexpr const Pack& get_pack() const noexcept + { + return *this; + } + + using base::operator(); + + BOOST_HOF_INHERIT_DEFAULT(partial_adaptor, base, F, Pack); + + template<class X, class S> + constexpr partial_adaptor(X&& x, S&& seq) + BOOST_HOF_NOEXCEPT(BOOST_HOF_IS_NOTHROW_CONSTRUCTIBLE(F, X&&) && BOOST_HOF_IS_NOTHROW_CONSTRUCTIBLE(Pack, S&&)) + : F(BOOST_HOF_FORWARD(X)(x)), Pack(BOOST_HOF_FORWARD(S)(seq)) + {} +}; + +template<class F> +struct partial_adaptor<F, void> : detail::partial_adaptor_pack_base<partial_adaptor<F, void>, detail::callable_base<F>>::type +{ + typedef typename detail::partial_adaptor_pack_base<partial_adaptor<F, void>, detail::callable_base<F>>::type base; + + typedef partial_adaptor fit_rewritable1_tag; + + template<class... Ts> + constexpr const detail::callable_base<F>& base_function(Ts&&...) const noexcept + { + return *this; + } + + using base::operator(); + + BOOST_HOF_INHERIT_CONSTRUCTOR(partial_adaptor, base); + +}; + +// Make partial_adaptor work with pipable_adaptor by removing its pipableness +template<class F> +struct partial_adaptor<pipable_adaptor<F>, void> +: partial_adaptor<F, void> +{ + typedef partial_adaptor<F, void> base; + + typedef partial_adaptor fit_rewritable1_tag; + BOOST_HOF_INHERIT_CONSTRUCTOR(partial_adaptor, base); +}; + +template<class F> +struct partial_adaptor<static_<pipable_adaptor<F>>, void> +: partial_adaptor<F, void> +{ + typedef partial_adaptor<F, void> base; + + typedef partial_adaptor fit_rewritable1_tag; + + BOOST_HOF_INHERIT_CONSTRUCTOR(partial_adaptor, base); +}; +}} // namespace boost::hof + +#endif diff --git a/boost/hof/pipable.hpp b/boost/hof/pipable.hpp new file mode 100644 index 0000000000..9f699ec9c4 --- /dev/null +++ b/boost/hof/pipable.hpp @@ -0,0 +1,215 @@ +/*============================================================================= + Copyright (c) 2012 Paul Fultz II + pipable.h + 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_HOF_GUARD_FUNCTION_PIPABLE_H +#define BOOST_HOF_GUARD_FUNCTION_PIPABLE_H + +/// pipable +/// ======= +/// +/// Description +/// ----------- +/// +/// The `pipable` function adaptor provides an extension method. The first +/// parameter of the function can be piped into the function using the pipe +/// `|` operator. This can be especially convenient when there are a lot of +/// nested function calls. Functions that are made pipable can still be called +/// the traditional way without piping in the first parameter. +/// +/// Synopsis +/// -------- +/// +/// template<class F> +/// constexpr pipable_adaptor<F> pipable(F f); +/// +/// Semantics +/// --------- +/// +/// assert(x | pipable(f)(ys...) == f(x, ys...)); +/// +/// Requirements +/// ------------ +/// +/// F must be: +/// +/// * [ConstInvocable](ConstInvocable) +/// * MoveConstructible +/// +/// Example +/// ------- +/// +/// #include <boost/hof.hpp> +/// #include <cassert> +/// using namespace boost::hof; +/// +/// struct sum +/// { +/// template<class T, class U> +/// T operator()(T x, U y) const +/// { +/// return x+y; +/// } +/// }; +/// +/// int main() { +/// assert(3 == (1 | pipable(sum())(2))); +/// assert(3 == pipable(sum())(1, 2)); +/// } +/// +/// References +/// ---------- +/// +/// * [Extension methods](<Extension methods>) +/// + +#include <boost/hof/first_of.hpp> +#include <boost/hof/pack.hpp> +#include <boost/hof/detail/delegate.hpp> +#include <boost/hof/detail/move.hpp> +#include <boost/hof/detail/make.hpp> +#include <boost/hof/detail/static_const_var.hpp> +#include <boost/hof/limit.hpp> + +namespace boost { namespace hof { + +template<class F> +struct pipable_adaptor; + +namespace detail { + +template<class F, class Pack> +struct pipe_closure : F, Pack +{ + + template<class X, class P> + constexpr pipe_closure(X&& fp, P&& packp) + BOOST_HOF_NOEXCEPT(BOOST_HOF_IS_NOTHROW_CONSTRUCTIBLE(F, X&&) && BOOST_HOF_IS_NOTHROW_CONSTRUCTIBLE(Pack, P&&)) + : F(BOOST_HOF_FORWARD(X)(fp)), Pack(BOOST_HOF_FORWARD(P)(packp)) + {} + + template<class... Ts> + constexpr const F& base_function(Ts&&...) const noexcept + { + return *this; + } + + template<class... Ts> + constexpr const Pack& get_pack(Ts&&...) const noexcept + { + return *this; + } + + template<class A> + struct invoke + { + A a; + const pipe_closure * self; + template<class X> + constexpr invoke(X&& xp, const pipe_closure * selfp) + BOOST_HOF_NOEXCEPT(BOOST_HOF_IS_NOTHROW_CONSTRUCTIBLE(A, X&&)) + : a(BOOST_HOF_FORWARD(X)(xp)), self(selfp) + {} + + BOOST_HOF_RETURNS_CLASS(invoke); + + template<class... Ts> + constexpr BOOST_HOF_SFINAE_RESULT(const F&, id_<A>, id_<Ts>...) + operator()(Ts&&... xs) const BOOST_HOF_SFINAE_RETURNS + (BOOST_HOF_RETURNS_STATIC_CAST(const F&)(*BOOST_HOF_CONST_THIS->self)(BOOST_HOF_FORWARD(A)(a), BOOST_HOF_FORWARD(Ts)(xs)...)); + }; + + BOOST_HOF_RETURNS_CLASS(pipe_closure); + + template<class A> + constexpr BOOST_HOF_SFINAE_RESULT(const Pack&, id_<invoke<A&&>>) + operator()(A&& a) const BOOST_HOF_SFINAE_RETURNS + (BOOST_HOF_MANGLE_CAST(const Pack&)(BOOST_HOF_CONST_THIS->get_pack(a))(invoke<A&&>(BOOST_HOF_FORWARD(A)(a), BOOST_HOF_CONST_THIS))); +}; + +template<class F, class Pack> +constexpr auto make_pipe_closure(F f, Pack&& p) BOOST_HOF_RETURNS +( + pipe_closure<F, typename std::remove_reference<Pack>::type>(BOOST_HOF_RETURNS_STATIC_CAST(F&&)(f), BOOST_HOF_FORWARD(Pack)(p)) +); + + +template<class Derived, class F> +struct pipe_pack +{ + template<class... Ts> + constexpr const F& get_function(Ts&&...) const noexcept + { + return static_cast<const F&>(static_cast<const Derived&>(*this)); + } + + BOOST_HOF_RETURNS_CLASS(pipe_pack); + + template<class... Ts, class=typename std::enable_if< + (sizeof...(Ts) < function_param_limit<F>::value) + >::type> + constexpr auto operator()(Ts&&... xs) const BOOST_HOF_RETURNS + (make_pipe_closure(BOOST_HOF_RETURNS_C_CAST(F&&)(BOOST_HOF_CONST_THIS->get_function(xs...)), boost::hof::pack_forward(BOOST_HOF_FORWARD(Ts)(xs)...))); +}; + +template<class A, class F, class Pack> +constexpr auto operator|(A&& a, const pipe_closure<F, Pack>& p) BOOST_HOF_RETURNS +(p(BOOST_HOF_FORWARD(A)(a))); + +} + +template<class F> +struct pipable_adaptor +: detail::basic_first_of_adaptor<detail::callable_base<F>, detail::pipe_pack<pipable_adaptor<F>, detail::callable_base<F>> > +{ + typedef detail::basic_first_of_adaptor<detail::callable_base<F>, detail::pipe_pack<pipable_adaptor<F>, detail::callable_base<F>> > base; + typedef pipable_adaptor fit_rewritable_tag; + + BOOST_HOF_INHERIT_CONSTRUCTOR(pipable_adaptor, base); + + constexpr const detail::callable_base<F>& base_function() const noexcept + { + return *this; + } +}; + +template<class A, class F> +constexpr auto operator|(A&& a, const pipable_adaptor<F>& p) BOOST_HOF_RETURNS +(p(BOOST_HOF_FORWARD(A)(a))); + +BOOST_HOF_DECLARE_STATIC_VAR(pipable, detail::make<pipable_adaptor>); + +namespace detail { + +template<class F> +struct static_function_wrapper; + +// Operators for static_function_wrapper adaptor +template<class A, class F> +auto operator|(A&& a, const boost::hof::detail::static_function_wrapper<F>& f) BOOST_HOF_RETURNS +(f(BOOST_HOF_FORWARD(A)(a))); + +template<class F> +struct static_default_function; + +// Operators for static_default_function adaptor +template<class A, class F> +auto operator|(A&& a, const boost::hof::detail::static_default_function<F>& f) BOOST_HOF_RETURNS +(f(BOOST_HOF_FORWARD(A)(a))); + +} + +template<class F> +struct static_; + +// Operators for static_ adaptor +template<class A, class F> +auto operator|(A&& a, static_<F> f) BOOST_HOF_RETURNS +(f.base_function().base_function()(BOOST_HOF_FORWARD(A)(a))); + +}} // namespace boost::hof + +#endif diff --git a/boost/hof/placeholders.hpp b/boost/hof/placeholders.hpp new file mode 100644 index 0000000000..42e4a58b48 --- /dev/null +++ b/boost/hof/placeholders.hpp @@ -0,0 +1,468 @@ +/*============================================================================= + Copyright (c) 2014 Paul Fultz II + placeholders.h + 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_HOF_GUARD_FUNCTION_PLACEHOLDERS_H +#define BOOST_HOF_GUARD_FUNCTION_PLACEHOLDERS_H + +/// placeholders +/// ============ +/// +/// Description +/// ----------- +/// +/// The placeholders provide `std::bind` compatible placeholders that +/// additionally provide basic C++ operators that creates bind expressions. +/// Each bind expression supports `constexpr` function evaluation. +/// +/// Synopsis +/// -------- +/// +/// namespace placeholders { +/// placeholder<1> _1 = {}; +/// placeholder<2> _2 = {}; +/// placeholder<3> _3 = {}; +/// placeholder<4> _4 = {}; +/// placeholder<5> _5 = {}; +/// placeholder<6> _6 = {}; +/// placeholder<7> _7 = {}; +/// placeholder<8> _8 = {}; +/// placeholder<9> _9 = {}; +/// } +/// +/// Operators +/// --------- +/// +/// * Binary operators: +,-,*,/,%,>>,<<,>,<,<=,>=,==,!=,&,^,|,&&,|| +/// * Assign operators: +=,-=,*=,/=,%=,>>=,<<=,&=,|=,^= +/// * Unary operators: !,~,+,-,*,++,-- +/// +/// +/// Example +/// ------- +/// +/// #include <boost/hof.hpp> +/// #include <cassert> +/// using namespace boost::hof; +/// +/// int main() { +/// auto sum = _1 + _2; +/// assert(3 == sum(1, 2)); +/// } +/// +/// +/// unamed placeholder +/// ================== +/// +/// Description +/// ----------- +/// +/// The unamed placeholder can be used to build simple functions from C++ +/// operators. +/// +/// Note: The function produced by the unamed placeholder is not a bind expression. +/// +/// Synopsis +/// -------- +/// +/// namespace placeholders { +/// /* unspecified */ _ = {}; +/// } +/// +/// Example +/// ------- +/// +/// #include <boost/hof.hpp> +/// #include <cassert> +/// using namespace boost::hof; +/// +/// int main() { +/// auto sum = _ + _; +/// assert(3 == sum(1, 2)); +/// } +/// + +#include <boost/hof/returns.hpp> +#include <boost/hof/lazy.hpp> +#include <boost/hof/protect.hpp> + +#if defined(_MSC_VER) && _MSC_VER >= 1910 +#include <boost/hof/detail/pp.hpp> +#endif + +namespace boost { namespace hof { namespace detail { + template<int N> + struct simple_placeholder + {}; +}}} // namespace boost::hof + +namespace std { + template<int N> + struct is_placeholder<boost::hof::detail::simple_placeholder<N>> + : std::integral_constant<int, N> + {}; +} + + +namespace boost { namespace hof { + +#define BOOST_HOF_FOREACH_BINARY_OP(m) \ + m(+, add) \ + m(-, subtract) \ + m(*, multiply) \ + m(/, divide) \ + m(%, remainder) \ + m(>>, shift_right) \ + m(<<, shift_left) \ + m(>, greater_than) \ + m(<, less_than) \ + m(<=, less_than_equal) \ + m(>=, greater_than_equal) \ + m(==, equal) \ + m(!=, not_equal) \ + m(&, bit_and) \ + m(^, xor_) \ + m(|, bit_or) \ + m(&&, and_) \ + m(||, or_) + +#define BOOST_HOF_FOREACH_ASSIGN_OP(m) \ + m(+=, assign_add) \ + m(-=, assign_subtract) \ + m(*=, assign_multiply) \ + m(/=, assign_divide) \ + m(%=, assign_remainder) \ + m(>>=, assign_right_shift) \ + m(<<=, assign_left_shift) \ + m(&=, assign_bit_and) \ + m(|=, assign_bit_or) \ + m(^=, assign_xor) + +#ifndef _MSC_VER +#define BOOST_HOF_FOREACH_UNARY_OP(m) \ + m(!, not_) \ + m(~, compl_) \ + m(+, unary_plus) \ + m(-, unary_subtract) \ + m(*, dereference) \ + m(++, increment) \ + m(--, decrement) +#else +#define BOOST_HOF_FOREACH_UNARY_OP(m) \ + m(!, not_) \ + m(~, compl_) \ + m(+, unary_plus) \ + m(-, unary_subtract) \ + m(*, dereference) +#endif + +namespace operators { + +struct call +{ + template<class F, class... Ts> + constexpr auto operator()(F&& f, Ts&&... xs) const BOOST_HOF_RETURNS + (f(BOOST_HOF_FORWARD(Ts)(xs)...)); +}; + +// MSVC 2017 ICEs on && and || in conxtexpr, so we fallback on bitwise operators +#if defined(_MSC_VER) && _MSC_VER >= 1910 +#define BOOST_HOF_BINARY_OP_SKIP_and_ () +#define BOOST_HOF_BINARY_OP_SKIP_or_ () + +struct and_ +{ + template<class T, class U> + constexpr auto operator()(T&& x, U&& y) const + noexcept(noexcept(BOOST_HOF_FORWARD(T)(x) && BOOST_HOF_FORWARD(U)(y))) + -> decltype(BOOST_HOF_FORWARD(T)(x) && BOOST_HOF_FORWARD(U)(y)) + { return BOOST_HOF_FORWARD(T)(x) & BOOST_HOF_FORWARD(U)(y); } +}; + +struct or_ +{ + template<class T, class U> + constexpr auto operator()(T&& x, U&& y) const + noexcept(noexcept(BOOST_HOF_FORWARD(T)(x) || BOOST_HOF_FORWARD(U)(y))) + -> decltype(BOOST_HOF_FORWARD(T)(x) || BOOST_HOF_FORWARD(U)(y)) + { return BOOST_HOF_FORWARD(T)(x) | BOOST_HOF_FORWARD(U)(y); } +}; + +#define BOOST_HOF_BINARY_OP_IMPL(op, name) \ + struct name \ + { \ + template<class T, class U> \ + BOOST_HOF_USING(ex_failure, decltype(std::declval<T>() op std::declval<U>())); \ + struct failure : as_failure<ex_failure> {}; \ + template<class T, class U> \ + constexpr auto operator()(T&& x, U&& y) const BOOST_HOF_RETURNS \ + (BOOST_HOF_FORWARD(T)(x) op BOOST_HOF_FORWARD(U)(y)); \ + }; + +#define BOOST_HOF_BINARY_OP(op, name) \ + BOOST_HOF_PP_IIF(BOOST_HOF_PP_IS_PAREN(BOOST_HOF_PP_CAT(BOOST_HOF_BINARY_OP_SKIP_, name))) \ + (BOOST_HOF_PP_EMPTY, BOOST_HOF_BINARY_OP_IMPL)(op, name) + +#else + +#define BOOST_HOF_BINARY_OP(op, name) \ + struct name \ + { \ + template<class T, class U> \ + constexpr auto operator()(T&& x, U&& y) const BOOST_HOF_RETURNS \ + (BOOST_HOF_FORWARD(T)(x) op BOOST_HOF_FORWARD(U)(y)); \ + }; + +#endif + +BOOST_HOF_FOREACH_BINARY_OP(BOOST_HOF_BINARY_OP) +BOOST_HOF_FOREACH_ASSIGN_OP(BOOST_HOF_BINARY_OP) + +#define BOOST_HOF_UNARY_OP(op, name) \ + struct name \ + { \ + template<class T> \ + constexpr auto operator()(T&& x) const BOOST_HOF_RETURNS \ + (op(BOOST_HOF_FORWARD(T)(x))); \ + }; + + +BOOST_HOF_FOREACH_UNARY_OP(BOOST_HOF_UNARY_OP) + + +} + +template<int N> +struct placeholder +{ +#if BOOST_HOF_HAS_MANGLE_OVERLOAD + template<class... Ts> + constexpr auto operator()(Ts&&... xs) const BOOST_HOF_RETURNS + ( boost::hof::lazy(operators::call())(detail::simple_placeholder<N>(), BOOST_HOF_FORWARD(Ts)(xs)...) ); +#else + template<class... Ts> + struct result_call + { typedef decltype(boost::hof::lazy(operators::call())(detail::simple_placeholder<N>(), std::declval<Ts>()...)) type; }; + template<class... Ts> + constexpr typename result_call<Ts...>::type operator()(Ts&&... xs) const + { return boost::hof::lazy(operators::call())(detail::simple_placeholder<N>(), BOOST_HOF_FORWARD(Ts)(xs)...); }; + +#endif + +#define BOOST_HOF_PLACEHOLDER_UNARY_OP(op, name) \ + constexpr auto operator op () const BOOST_HOF_RETURNS \ + ( boost::hof::lazy(operators::name())(detail::simple_placeholder<N>()) ); + +BOOST_HOF_FOREACH_UNARY_OP(BOOST_HOF_PLACEHOLDER_UNARY_OP) + +#define BOOST_HOF_PLACEHOLDER_ASSIGN_OP(op, name) \ + template<class T> \ + constexpr auto operator op (T&& x) const BOOST_HOF_RETURNS \ + ( boost::hof::lazy(operators::name())(detail::simple_placeholder<N>(), BOOST_HOF_FORWARD(T)(x)) ); + +BOOST_HOF_FOREACH_ASSIGN_OP(BOOST_HOF_PLACEHOLDER_ASSIGN_OP) + +}; + +#if BOOST_HOF_HAS_MANGLE_OVERLOAD + +#define BOOST_HOF_PLACEHOLDER_BINARY_OP(op, name) \ + template<class T, int N> \ + constexpr inline auto operator op (const placeholder<N>&, T&& x) BOOST_HOF_RETURNS \ + ( boost::hof::lazy(operators::name())(detail::simple_placeholder<N>(), BOOST_HOF_FORWARD(T)(x)) ); \ + template<class T, int N> \ + constexpr inline auto operator op (T&& x, const placeholder<N>&) BOOST_HOF_RETURNS \ + ( boost::hof::lazy(operators::name())(BOOST_HOF_FORWARD(T)(x), detail::simple_placeholder<N>()) ); \ + template<int N, int M> \ + constexpr inline auto operator op (const placeholder<N>&, const placeholder<M>&) BOOST_HOF_RETURNS \ + ( boost::hof::lazy(operators::name())(detail::simple_placeholder<N>(), detail::simple_placeholder<M>()) ); + +#else + +#define BOOST_HOF_PLACEHOLDER_BINARY_OP(op, name) \ + template<class T, class U> \ + struct result_ ## name \ + { typedef decltype(boost::hof::lazy(operators::name())(std::declval<T>(), std::declval<U>())) type; }; \ + template<class T, int N> \ + constexpr inline typename result_ ## name<detail::simple_placeholder<N>, T>::type operator op (const placeholder<N>&, T&& x) \ + { return boost::hof::lazy(operators::name())(detail::simple_placeholder<N>(), BOOST_HOF_FORWARD(T)(x)); } \ + template<class T, int N> \ + constexpr inline typename result_ ## name<T, detail::simple_placeholder<N>>::type operator op (T&& x, const placeholder<N>&) \ + { return boost::hof::lazy(operators::name())(BOOST_HOF_FORWARD(T)(x), detail::simple_placeholder<N>()); } \ + template<int N, int M> \ + constexpr inline typename result_ ## name<detail::simple_placeholder<N>, detail::simple_placeholder<M>>::type operator op (const placeholder<N>&, const placeholder<M>&) \ + { return boost::hof::lazy(operators::name())(detail::simple_placeholder<N>(), detail::simple_placeholder<M>()); } + +#endif + +BOOST_HOF_FOREACH_BINARY_OP(BOOST_HOF_PLACEHOLDER_BINARY_OP) + +namespace placeholders { +BOOST_HOF_DECLARE_STATIC_VAR(_1, placeholder<1>); +BOOST_HOF_DECLARE_STATIC_VAR(_2, placeholder<2>); +BOOST_HOF_DECLARE_STATIC_VAR(_3, placeholder<3>); +BOOST_HOF_DECLARE_STATIC_VAR(_4, placeholder<4>); +BOOST_HOF_DECLARE_STATIC_VAR(_5, placeholder<5>); +BOOST_HOF_DECLARE_STATIC_VAR(_6, placeholder<6>); +BOOST_HOF_DECLARE_STATIC_VAR(_7, placeholder<7>); +BOOST_HOF_DECLARE_STATIC_VAR(_8, placeholder<8>); +BOOST_HOF_DECLARE_STATIC_VAR(_9, placeholder<9>); +} + +using placeholders::_1; +using placeholders::_2; +using placeholders::_3; +using placeholders::_4; +using placeholders::_5; +using placeholders::_6; +using placeholders::_7; +using placeholders::_8; +using placeholders::_9; + +namespace detail { + + + +struct unamed_placeholder +{ +template<class T, class Invoker> +struct partial_ap +{ + T val; + + BOOST_HOF_INHERIT_DEFAULT_EMPTY(partial_ap, T) + + template<class X, class... Xs, BOOST_HOF_ENABLE_IF_CONSTRUCTIBLE(T, X&&, Xs&&...)> + constexpr partial_ap(X&& x, Xs&&... xs) : val(BOOST_HOF_FORWARD(X)(x), BOOST_HOF_FORWARD(Xs)(xs)...) + {} + + BOOST_HOF_RETURNS_CLASS(partial_ap); + + struct partial_ap_failure + { + template<class Failure> + struct apply + { + template<class... Xs> + struct of; + + template<class X> + struct of<X> + : Failure::template of<typename std::add_const<T>::type, X> + {}; + }; + }; + + struct failure + : failure_map<partial_ap_failure, Invoker> + {}; + + template<class X> + constexpr BOOST_HOF_SFINAE_RESULT(const Invoker&, id_<T>, id_<X>) + operator()(X&& x) const BOOST_HOF_SFINAE_RETURNS + ( + Invoker()(BOOST_HOF_CONST_THIS->val, BOOST_HOF_FORWARD(X)(x)) + ); +}; + +template<class Invoker, class T> +static constexpr partial_ap<T, Invoker> make_partial_ap(T&& x) +{ + return {BOOST_HOF_FORWARD(T)(x)}; +} + +template<class Op> +struct left +{ + struct failure + : failure_for<Op> + {}; + template<class T, class X> + constexpr BOOST_HOF_SFINAE_RESULT(const Op&, id_<T>, id_<X>) + operator()(T&& val, X&& x) const BOOST_HOF_SFINAE_RETURNS + (Op()(BOOST_HOF_FORWARD(T)(val), BOOST_HOF_FORWARD(X)(x))); +}; + +template<class Op> +struct right +{ + struct right_failure + { + template<class Failure> + struct apply + { + template<class T, class U, class... Ts> + struct of + : Failure::template of<U, T, Ts...> + {}; + }; + }; + + struct failure + : failure_map<right_failure, Op> + {}; + + template<class T, class X> + constexpr BOOST_HOF_SFINAE_RESULT(const Op&, id_<X>, id_<T>) + operator()(T&& val, X&& x) const BOOST_HOF_SFINAE_RETURNS + (Op()(BOOST_HOF_FORWARD(X)(x), BOOST_HOF_FORWARD(T)(val))); +}; + +#define BOOST_HOF_UNAMED_PLACEHOLDER_UNARY_OP(op, name) \ + constexpr auto operator op () const BOOST_HOF_RETURNS \ + ( operators::name() ); + +BOOST_HOF_FOREACH_UNARY_OP(BOOST_HOF_UNAMED_PLACEHOLDER_UNARY_OP) + +#define BOOST_HOF_UNAMED_PLACEHOLDER_ASSIGN_OP(op, name) \ + template<class T> \ + constexpr auto operator op (const T& x) const BOOST_HOF_RETURNS \ + ( partial_ap<T, left<operators::name>>(x) ); + +BOOST_HOF_FOREACH_ASSIGN_OP(BOOST_HOF_UNAMED_PLACEHOLDER_ASSIGN_OP) +}; +#define BOOST_HOF_UNAMED_PLACEHOLDER_BINARY_OP(op, name) \ + template<class T> \ + constexpr inline auto operator op (const unamed_placeholder&, const T& x) BOOST_HOF_RETURNS \ + ( unamed_placeholder::make_partial_ap<unamed_placeholder::right<operators::name>>(boost::hof::decay(x)) ); \ + template<class T> \ + constexpr inline auto operator op (const T& x, const unamed_placeholder&) BOOST_HOF_RETURNS \ + ( unamed_placeholder::make_partial_ap<unamed_placeholder::left<operators::name>>(boost::hof::decay(x)) ); \ + constexpr inline auto operator op (const unamed_placeholder&, const unamed_placeholder&) BOOST_HOF_RETURNS \ + ( operators::name() ); + +BOOST_HOF_FOREACH_BINARY_OP(BOOST_HOF_UNAMED_PLACEHOLDER_BINARY_OP) +} + +namespace placeholders { +BOOST_HOF_DECLARE_STATIC_VAR(_, detail::unamed_placeholder); +} + +using placeholders::_; + +}} // namespace boost::hof + +namespace std { + template<int N> + struct is_placeholder<boost::hof::placeholder<N>> + : std::integral_constant<int, N> + {}; +} + +namespace boost { + + template<class T> + struct is_placeholder; + + template<int N> + struct is_placeholder<boost::hof::placeholder<N>> + : std::integral_constant<int, N> + {}; + + +} + +#endif diff --git a/boost/hof/proj.hpp b/boost/hof/proj.hpp new file mode 100644 index 0000000000..6469186c87 --- /dev/null +++ b/boost/hof/proj.hpp @@ -0,0 +1,265 @@ +/*============================================================================= + Copyright (c) 2014 Paul Fultz II + proj.h + 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_HOF_GUARD_FUNCTION_ON_H +#define BOOST_HOF_GUARD_FUNCTION_ON_H + +/// proj +/// ==== +/// +/// Description +/// ----------- +/// +/// The `proj` function adaptor applies a projection onto the parameters of +/// another function. This is useful, for example, to define a function for +/// sorting such that the ordering is based off of the value of one of its +/// member fields. +/// +/// Also, if just a projection is given, then the projection will be called +/// for each of its arguments. +/// +/// Note: All projections are always evaluated in order from left-to-right. +/// +/// Synopsis +/// -------- +/// +/// template<class Projection, class F> +/// constexpr proj_adaptor<Projection, F> by(Projection p, F f); +/// +/// template<class Projection> +/// constexpr proj_adaptor<Projection> by(Projection p); +/// +/// Semantics +/// --------- +/// +/// assert(by(p, f)(xs...) == f(p(xs)...)); +/// assert(by(p)(xs...) == p(xs)...); +/// +/// Requirements +/// ------------ +/// +/// Projection must be: +/// +/// * [UnaryInvocable](UnaryInvocable) +/// * MoveConstructible +/// +/// F must be: +/// +/// * [ConstInvocable](ConstInvocable) +/// * MoveConstructible +/// +/// Example +/// ------- +/// +/// #include <boost/hof.hpp> +/// #include <cassert> +/// using namespace boost::hof; +/// +/// struct foo +/// { +/// foo(int x_) : x(x_) +/// {} +/// int x; +/// }; +/// +/// int main() { +/// assert(boost::hof::proj(&foo::x, _ + _)(foo(1), foo(2)) == 3); +/// } +/// +/// References +/// ---------- +/// +/// * [Projections](Projections) +/// * [Variadic print](<Variadic print>) +/// + + + +#include <utility> +#include <boost/hof/always.hpp> +#include <boost/hof/detail/callable_base.hpp> +#include <boost/hof/detail/result_of.hpp> +#include <boost/hof/detail/move.hpp> +#include <boost/hof/detail/make.hpp> +#include <boost/hof/detail/static_const_var.hpp> +#include <boost/hof/detail/compressed_pair.hpp> +#include <boost/hof/detail/result_type.hpp> +#include <boost/hof/apply_eval.hpp> + +namespace boost { namespace hof { + +namespace detail { + +template<class T, class Projection> +struct project_eval +{ + T&& x; + const Projection& p; + + template<class X, class P> + constexpr project_eval(X&& xp, const P& pp) : x(BOOST_HOF_FORWARD(X)(xp)), p(pp) + {} + + constexpr auto operator()() const BOOST_HOF_RETURNS + (p(BOOST_HOF_FORWARD(T)(x))); +}; + +template<class T, class Projection> +constexpr project_eval<T, Projection> make_project_eval(T&& x, const Projection& p) +{ + return project_eval<T, Projection>(BOOST_HOF_FORWARD(T)(x), p); +} + +template<class T, class Projection> +struct project_void_eval +{ + T&& x; + const Projection& p; + + template<class X, class P> + constexpr project_void_eval(X&& xp, const P& pp) : x(BOOST_HOF_FORWARD(X)(xp)), p(pp) + {} + + struct void_ {}; + + constexpr void_ operator()() const + { + return p(BOOST_HOF_FORWARD(T)(x)), void_(); + } +}; + +template<class T, class Projection> +constexpr project_void_eval<T, Projection> make_project_void_eval(T&& x, const Projection& p) +{ + return project_void_eval<T, Projection>(BOOST_HOF_FORWARD(T)(x), p); +} + +template<class Projection, class F, class... Ts, + class R=decltype( + std::declval<const F&>()(std::declval<const Projection&>()(std::declval<Ts>())...) + )> +constexpr R by_eval(const Projection& p, const F& f, Ts&&... xs) +{ + return boost::hof::apply_eval(f, make_project_eval(BOOST_HOF_FORWARD(Ts)(xs), p)...); +} + +#if BOOST_HOF_NO_ORDERED_BRACE_INIT +#define BOOST_HOF_BY_VOID_RETURN BOOST_HOF_ALWAYS_VOID_RETURN +#else +#if BOOST_HOF_NO_CONSTEXPR_VOID +#define BOOST_HOF_BY_VOID_RETURN boost::hof::detail::swallow +#else +#define BOOST_HOF_BY_VOID_RETURN void +#endif +#endif + +template<class Projection, class... Ts> +constexpr BOOST_HOF_ALWAYS_VOID_RETURN by_void_eval(const Projection& p, Ts&&... xs) +{ + return boost::hof::apply_eval(boost::hof::always(), boost::hof::detail::make_project_void_eval(BOOST_HOF_FORWARD(Ts)(xs), p)...); +} + +struct swallow +{ + template<class... Ts> + constexpr swallow(Ts&&...) + {} +}; + +} + +template<class Projection, class F=void> +struct proj_adaptor; + +template<class Projection, class F> +struct proj_adaptor : detail::compressed_pair<detail::callable_base<Projection>, detail::callable_base<F>>, detail::function_result_type<F> +{ + typedef proj_adaptor fit_rewritable_tag; + typedef detail::compressed_pair<detail::callable_base<Projection>, detail::callable_base<F>> base; + template<class... Ts> + constexpr const detail::callable_base<F>& base_function(Ts&&... xs) const + { + return this->second(xs...);; + } + + template<class... Ts> + constexpr const detail::callable_base<Projection>& base_projection(Ts&&... xs) const + { + return this->first(xs...); + } + + struct by_failure + { + template<class Failure> + struct apply + { + template<class... Ts> + struct of + : Failure::template of<decltype(std::declval<detail::callable_base<Projection>>()(std::declval<Ts>()))...> + {}; + }; + }; + + struct failure + : failure_map<by_failure, detail::callable_base<F>> + {}; + + BOOST_HOF_INHERIT_CONSTRUCTOR(proj_adaptor, base) + + BOOST_HOF_RETURNS_CLASS(proj_adaptor); + + template<class... Ts> + constexpr BOOST_HOF_SFINAE_RESULT(const detail::callable_base<F>&, result_of<const detail::callable_base<Projection>&, id_<Ts>>...) + operator()(Ts&&... xs) const BOOST_HOF_SFINAE_RETURNS + ( + boost::hof::detail::by_eval( + BOOST_HOF_MANGLE_CAST(const detail::callable_base<Projection>&)(BOOST_HOF_CONST_THIS->base_projection(xs...)), + BOOST_HOF_MANGLE_CAST(const detail::callable_base<F>&)(BOOST_HOF_CONST_THIS->base_function(xs...)), + BOOST_HOF_FORWARD(Ts)(xs)... + ) + ); +}; + +template<class Projection> +struct proj_adaptor<Projection, void> : detail::callable_base<Projection> +{ + typedef proj_adaptor fit_rewritable1_tag; + template<class... Ts> + constexpr const detail::callable_base<Projection>& base_projection(Ts&&... xs) const + { + return boost::hof::always_ref(*this)(xs...); + } + + BOOST_HOF_INHERIT_DEFAULT(proj_adaptor, detail::callable_base<Projection>) + + template<class P, BOOST_HOF_ENABLE_IF_CONVERTIBLE(P, detail::callable_base<Projection>)> + constexpr proj_adaptor(P&& p) + : detail::callable_base<Projection>(BOOST_HOF_FORWARD(P)(p)) + {} + + BOOST_HOF_RETURNS_CLASS(proj_adaptor); + + template<class... Ts, class=detail::holder<decltype(std::declval<Projection>()(std::declval<Ts>()))...>> + constexpr BOOST_HOF_BY_VOID_RETURN operator()(Ts&&... xs) const + { +#if BOOST_HOF_NO_ORDERED_BRACE_INIT + return boost::hof::detail::by_void_eval(this->base_projection(xs...), BOOST_HOF_FORWARD(Ts)(xs)...); +#else +#if BOOST_HOF_NO_CONSTEXPR_VOID + return +#endif + boost::hof::detail::swallow{ + (this->base_projection(xs...)(BOOST_HOF_FORWARD(Ts)(xs)), 0)... + }; +#endif + } +}; + +BOOST_HOF_DECLARE_STATIC_VAR(proj, detail::make<proj_adaptor>); + +}} // namespace boost::hof +#endif diff --git a/boost/hof/protect.hpp b/boost/hof/protect.hpp new file mode 100644 index 0000000000..78f99a23b5 --- /dev/null +++ b/boost/hof/protect.hpp @@ -0,0 +1,80 @@ +/*============================================================================= + Copyright (c) 2014 Paul Fultz II + protect.h + 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_HOF_GUARD_FUNCTION_PROTECT_H +#define BOOST_HOF_GUARD_FUNCTION_PROTECT_H + +/// protect +/// ======= +/// +/// Description +/// ----------- +/// +/// The `protect` function adaptor can be used to make a bind expression be +/// treated as a normal function instead. Both `bind` and +/// [`lazy`](/include/boost/hof/lazy) eargerly evaluates nested bind expressions. +/// The `protect` adaptor masks the type so `bind` or +/// [`lazy`](/include/boost/hof/lazy) no longer recognizes the function as bind +/// expression and evaluates it. +/// +/// Synopsis +/// -------- +/// +/// template<class F> +/// constexpr protect_adaptor<F> protect(F f); +/// +/// Semantics +/// --------- +/// +/// assert(lazy(f)(protect(lazy(g)(_1)))() == f(lazy(g)(_1))) +/// +/// Requirements +/// ------------ +/// +/// F must be: +/// +/// * [ConstInvocable](ConstInvocable) +/// * MoveConstructible +/// +/// Example +/// ------- +/// +/// #include <boost/hof.hpp> +/// #include <cassert> +/// using namespace boost::hof; +/// +/// int main() { +/// auto lazy_id = lazy(identity)(_1); +/// auto lazy_apply = lazy(apply)(protect(lazy_id), _1); +/// assert(lazy_apply(3) == 3); +/// } +/// +/// See Also +/// -------- +/// +/// * [lazy](lazy) +/// + +#include <utility> +#include <boost/hof/reveal.hpp> +#include <boost/hof/detail/forward.hpp> +#include <boost/hof/detail/make.hpp> +#include <boost/hof/detail/static_const_var.hpp> + +namespace boost { namespace hof { + +template<class F> +struct protect_adaptor : detail::callable_base<F> +{ + typedef protect_adaptor fit_rewritable1_tag; + BOOST_HOF_INHERIT_CONSTRUCTOR(protect_adaptor, detail::callable_base<F>) +}; + +BOOST_HOF_DECLARE_STATIC_VAR(protect, detail::make<protect_adaptor>); + +}} // namespace boost::hof +#endif diff --git a/boost/hof/repeat.hpp b/boost/hof/repeat.hpp new file mode 100644 index 0000000000..e73e43ee06 --- /dev/null +++ b/boost/hof/repeat.hpp @@ -0,0 +1,162 @@ +/*============================================================================= + Copyright (c) 2015 Paul Fultz II + repeat.h + 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_HOF_GUARD_REPEAT_H +#define BOOST_HOF_GUARD_REPEAT_H + +/// repeat +/// ====== +/// +/// Description +/// ----------- +/// +/// The `repeat` function decorator will repeatedly apply a function a given +/// number of times. +/// +/// +/// Synopsis +/// -------- +/// +/// template<class Integral> +/// constexpr auto repeat(Integral); +/// +/// Semantics +/// --------- +/// +/// assert(repeat(std::integral_constant<int, 0>{})(f)(xs...) == f(xs...)); +/// assert(repeat(std::integral_constant<int, 1>{})(f)(xs...) == f(f(xs...))); +/// assert(repeat(0)(f)(xs...) == f(xs...)); +/// assert(repeat(1)(f)(xs...) == f(f(xs...))); +/// +/// Requirements +/// ------------ +/// +/// Integral must be: +/// +/// * Integral +/// +/// Or: +/// +/// * IntegralConstant +/// +/// Example +/// ------- +/// +/// #include <boost/hof.hpp> +/// #include <cassert> +/// +/// struct increment +/// { +/// template<class T> +/// constexpr T operator()(T x) const +/// { +/// return x + 1; +/// } +/// }; +/// +/// int main() { +/// auto increment_by_5 = boost::hof::repeat(std::integral_constant<int, 5>())(increment()); +/// assert(increment_by_5(1) == 6); +/// } +/// + +#include <boost/hof/always.hpp> +#include <boost/hof/detail/delegate.hpp> +#include <boost/hof/detail/result_of.hpp> +#include <boost/hof/detail/move.hpp> +#include <boost/hof/detail/static_const_var.hpp> +#include <boost/hof/decorate.hpp> +#include <boost/hof/first_of.hpp> +#include <boost/hof/detail/recursive_constexpr_depth.hpp> + +namespace boost { namespace hof { namespace detail { + +template<int N> +struct repeater +{ + template<class F, class... Ts> + constexpr BOOST_HOF_SFINAE_RESULT(repeater<N-1>, id_<const F&>, result_of<const F&, id_<Ts>...>) + operator()(const F& f, Ts&&... xs) const BOOST_HOF_SFINAE_RETURNS + ( + repeater<N-1>()(f, f(BOOST_HOF_FORWARD(Ts)(xs)...)) + ); +}; + +template<> +struct repeater<0> +{ + template<class F, class T> + constexpr T operator()(const F&, T&& x) const + BOOST_HOF_RETURNS_DEDUCE_NOEXCEPT(T(x)) + { + return x; + } +}; + +struct repeat_constant_decorator +{ + template<class Integral, class F, class... Ts> + constexpr auto operator()(Integral, const F& f, Ts&&... xs) const BOOST_HOF_RETURNS + ( + detail::repeater<Integral::type::value>() + ( + f, + BOOST_HOF_FORWARD(Ts)(xs)... + ) + ); +}; + +template<int Depth> +struct repeat_integral_decorator +{ + template<class Integral, class F, class T, class... Ts, class Self=repeat_integral_decorator<Depth-1>> + constexpr auto operator()(Integral n, const F& f, T&& x, Ts&&... xs) const BOOST_HOF_RETURNS + ( + (n) ? + Self()(n-1, f, f(BOOST_HOF_FORWARD(T)(x), BOOST_HOF_FORWARD(Ts)(xs)...)) : + BOOST_HOF_FORWARD(T)(x) + ); +}; + +template<> +struct repeat_integral_decorator<0> +{ + template<class Integral, class F, class T, class Self=repeat_integral_decorator<0>> +#if BOOST_HOF_HAS_RELAXED_CONSTEXPR + constexpr +#endif + auto operator()(Integral n, const F& f, T x) const + BOOST_HOF_RETURNS_DEDUCE_NOEXCEPT((n--, f(BOOST_HOF_FORWARD(T)(x)))) + -> decltype(f(BOOST_HOF_FORWARD(T)(x))) + { + while(n > 0) + { + n--; + x = f(BOOST_HOF_FORWARD(T)(x)); + } + return x; + } + // TODO: Add overload for lvalue +}; + +} + +#if BOOST_HOF_HAS_RELAXED_CONSTEXPR +#define BOOST_HOF_REPEAT_CONSTEXPR_DEPTH 1 +#else +#define BOOST_HOF_REPEAT_CONSTEXPR_DEPTH BOOST_HOF_RECURSIVE_CONSTEXPR_DEPTH +#endif + +BOOST_HOF_DECLARE_STATIC_VAR(repeat, decorate_adaptor< + boost::hof::first_of_adaptor< + detail::repeat_constant_decorator, + detail::repeat_integral_decorator<BOOST_HOF_REPEAT_CONSTEXPR_DEPTH> +>>); + +}} // namespace boost::hof + +#endif diff --git a/boost/hof/repeat_while.hpp b/boost/hof/repeat_while.hpp new file mode 100644 index 0000000000..f306b77132 --- /dev/null +++ b/boost/hof/repeat_while.hpp @@ -0,0 +1,181 @@ +/*============================================================================= + Copyright (c) 2015 Paul Fultz II + repeat_while.h + 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_HOF_GUARD_REPEAT_WHILE_H +#define BOOST_HOF_GUARD_REPEAT_WHILE_H + +/// repeat_while +/// ====== +/// +/// Description +/// ----------- +/// +/// The `repeat_while` function decorator will repeatedly apply a function while +/// the predicate returns a boolean that is true. If the predicate returns an +/// `IntergralConstant` then the predicate is only evaluated at compile-time. +/// +/// +/// Synopsis +/// -------- +/// +/// template<class Predicate> +/// constexpr auto repeat_while(Predicate predicate); +/// +/// Requirements +/// ------------ +/// +/// Predicate must be: +/// +/// * [ConstFunctionObject](ConstFunctionObject) +/// * MoveConstructible +/// +/// Example +/// ------- +/// +/// #include <boost/hof.hpp> +/// #include <cassert> +/// +/// struct increment +/// { +/// template<class T> +/// constexpr std::integral_constant<int, T::value + 1> operator()(T) const +/// { +/// return std::integral_constant<int, T::value + 1>(); +/// } +/// }; +/// +/// struct not_6 +/// { +/// template<class T> +/// constexpr std::integral_constant<bool, (T::value != 6)> +/// operator()(T) const +/// { +/// return std::integral_constant<bool, (T::value != 6)>(); +/// } +/// }; +/// +/// typedef std::integral_constant<int, 1> one; +/// typedef std::integral_constant<int, 6> six; +/// +/// int main() { +/// auto increment_until_6 = boost::hof::repeat_while(not_6())(increment()); +/// static_assert(std::is_same<six, decltype(increment_until_6(one()))>::value, "Error"); +/// } +/// + +#include <boost/hof/always.hpp> +#include <boost/hof/detail/delegate.hpp> +#include <boost/hof/detail/result_of.hpp> +#include <boost/hof/detail/move.hpp> +#include <boost/hof/decorate.hpp> +#include <boost/hof/detail/static_const_var.hpp> +#include <boost/hof/first_of.hpp> +#include <boost/hof/detail/recursive_constexpr_depth.hpp> + +namespace boost { namespace hof { namespace detail { + +template<class P, class... Ts> +struct compute_predicate +{ + typedef decltype(std::declval<P>()(std::declval<Ts>()...)) type; +}; + +template<bool B> +struct while_repeater +{ + template<class F, class P, class... Ts> + constexpr BOOST_HOF_SFINAE_RESULT(while_repeater< + compute_predicate<P, typename result_of<const F&, id_<Ts>...>::type>::type::value + >, id_<const F&>, id_<const P&>, result_of<const F&, id_<Ts>...>) + operator()(const F& f, const P& p, Ts&&... xs) const BOOST_HOF_SFINAE_RETURNS + ( + while_repeater< + compute_predicate<P, decltype(f(BOOST_HOF_FORWARD(Ts)(xs)...))>::type::value + >()(f, p, f(BOOST_HOF_FORWARD(Ts)(xs)...)) + ); +}; + +template<> +struct while_repeater<false> +{ + template<class F, class P, class T> + constexpr T operator()(const F&, const P&, T&& x) const + BOOST_HOF_RETURNS_DEDUCE_NOEXCEPT(x) + { + return x; + } +}; + +struct repeat_while_constant_decorator +{ + template<class P, class F, class... Ts> + constexpr auto operator()(const P& p, const F& f, Ts&&... xs) const BOOST_HOF_RETURNS + ( + detail::while_repeater< + detail::compute_predicate<P, decltype(std::declval<F>()(BOOST_HOF_FORWARD(Ts)(xs)...))>::type::value + >() + ( + f, + p, + BOOST_HOF_FORWARD(Ts)(xs)... + ) + ); +}; + +template<int Depth> +struct repeat_while_integral_decorator +{ + template<class P, class F, class T, class... Ts, class Self=repeat_while_integral_decorator<Depth-1>> + constexpr auto operator()(const P& p, const F& f, T&& x, Ts&&... xs) const BOOST_HOF_RETURNS + ( + (p(x, BOOST_HOF_FORWARD(Ts)(xs)...)) ? + Self()( + p, + f, + f(x, BOOST_HOF_FORWARD(Ts)(xs)...) + ) : + BOOST_HOF_FORWARD(T)(x) + ); +}; + +template<> +struct repeat_while_integral_decorator<0> +{ + template<class P, class F, class T, class Self=repeat_while_integral_decorator<0>> +#if BOOST_HOF_HAS_RELAXED_CONSTEXPR + constexpr +#endif + auto operator()(const P& p, const F& f, T x) const + BOOST_HOF_RETURNS_DEDUCE_NOEXCEPT((p(x), f(x))) + -> decltype(f(x)) + { + while(p(x)) + { + // TODO: Should move? + x = f(x); + } + return x; + } +}; +} + +#if BOOST_HOF_HAS_RELAXED_CONSTEXPR +#define BOOST_HOF_REPEAT_WHILE_CONSTEXPR_DEPTH 1 +#else +#define BOOST_HOF_REPEAT_WHILE_CONSTEXPR_DEPTH BOOST_HOF_RECURSIVE_CONSTEXPR_DEPTH +#endif + +BOOST_HOF_DECLARE_STATIC_VAR(repeat_while, decorate_adaptor< + boost::hof::first_of_adaptor< + detail::repeat_while_constant_decorator, + detail::repeat_while_integral_decorator<BOOST_HOF_REPEAT_WHILE_CONSTEXPR_DEPTH> + > +>); + +}} // namespace boost::hof + +#endif diff --git a/boost/hof/result.hpp b/boost/hof/result.hpp new file mode 100644 index 0000000000..e2c1d93dae --- /dev/null +++ b/boost/hof/result.hpp @@ -0,0 +1,135 @@ +/*============================================================================= + Copyright (c) 2014 Paul Fultz II + result.h + 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_HOF_GUARD_RESULT_H +#define BOOST_HOF_GUARD_RESULT_H + +/// result +/// ====== +/// +/// Description +/// ----------- +/// +/// The `result` function adaptor sets the return type for the function, which +/// can be useful when dealing with multiple overloads. Since the return type +/// is no longer dependent on the parameters passed to the function, the +/// `result_adaptor` provides a nested `result_type` that is the return type +/// of the function. +/// +/// Synopsis +/// -------- +/// +/// template<class Result, class F> +/// constexpr result_adaptor<Result, F> result(F f); +/// +/// Requirements +/// ------------ +/// +/// F must be: +/// +/// * [ConstInvocable](ConstInvocable) +/// * MoveConstructible +/// +/// Example +/// ------- +/// +/// #include <boost/hof.hpp> +/// #include <cassert> +/// +/// struct id +/// { +/// template<class T> +/// T operator()(T x) const +/// { +/// return x; +/// } +/// }; +/// +/// int main() { +/// auto int_result = boost::hof::result<int>(id()); +/// static_assert(std::is_same<decltype(int_result(true)), int>::value, "Not the same type"); +/// } +/// + +#include <boost/hof/detail/callable_base.hpp> +#include <boost/hof/is_invocable.hpp> +#include <boost/hof/always.hpp> +#include <boost/hof/reveal.hpp> + +namespace boost { namespace hof { + +template<class Result, class F> +struct result_adaptor : detail::callable_base<F> +{ + BOOST_HOF_INHERIT_CONSTRUCTOR(result_adaptor, detail::callable_base<F>) + + typedef Result result_type; + + struct failure + : failure_for<detail::callable_base<F>> + {}; + + template<class... Ts> + constexpr const detail::callable_base<F>& base_function(Ts&&... xs) const + { + return boost::hof::always_ref(*this)(xs...); + } + + template<class... Ts, class=typename std::enable_if<(boost::hof::is_invocable<F, Ts...>::value)>::type> + constexpr result_type operator()(Ts&&... xs) const + { + return this->base_function(xs...)(BOOST_HOF_FORWARD(Ts)(xs)...); + }; +}; + +template<class F> +struct result_adaptor<void, F> : detail::callable_base<F> +{ + BOOST_HOF_INHERIT_CONSTRUCTOR(result_adaptor, detail::callable_base<F>) + + typedef void result_type; + + template<class... Ts> + constexpr const detail::callable_base<F>& base_function(Ts&&... xs) const + { + return boost::hof::always_ref(*this)(xs...); + } + + template<class... Ts, class=typename std::enable_if<(boost::hof::is_invocable<F, Ts...>::value)>::type> + constexpr typename detail::holder<Ts...>::type operator()(Ts&&... xs) const + { + return (typename detail::holder<Ts...>::type)this->base_function(xs...)(BOOST_HOF_FORWARD(Ts)(xs)...); + }; +}; + +#if BOOST_HOF_HAS_VARIABLE_TEMPLATES +namespace result_detail { +template<class Result> +struct result_f +{ + template<class F> + constexpr result_adaptor<Result, F> operator()(F f) const + { + return result_adaptor<Result, F>(boost::hof::move(f)); + } +}; + +} + +template<class Result> +static constexpr auto result = result_detail::result_f<Result>{}; +#else +template<class Result, class F> +constexpr result_adaptor<Result, F> result(F f) +{ + return result_adaptor<Result, F>(boost::hof::move(f)); +} +#endif + +}} // namespace boost::hof + +#endif diff --git a/boost/hof/returns.hpp b/boost/hof/returns.hpp new file mode 100644 index 0000000000..5360a38314 --- /dev/null +++ b/boost/hof/returns.hpp @@ -0,0 +1,249 @@ +/*============================================================================= + Copyright (c) 2014 Paul Fultz II + returns.h + 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_HOF_GUARD_RETURNS_H +#define BOOST_HOF_GUARD_RETURNS_H + +/// BOOST_HOF_RETURNS +/// =========== +/// +/// Description +/// ----------- +/// +/// The `BOOST_HOF_RETURNS` macro defines the function as the expression +/// equivalence. It does this by deducing `noexcept` and the return type by +/// using a trailing `decltype`. Instead of repeating the expression for the +/// return type, `noexcept` clause and the function body, this macro will +/// reduce the code duplication from that. +/// +/// Note: The expression used to deduce the return the type will also +/// constrain the template function and deduce `noexcept` as well, which is +/// different behaviour than using C++14's return type deduction. +/// +/// Synopsis +/// -------- +/// +/// #define BOOST_HOF_RETURNS(...) +/// +/// +/// Example +/// ------- +/// +/// #include <boost/hof.hpp> +/// #include <cassert> +/// +/// template<class T, class U> +/// auto sum(T x, U y) BOOST_HOF_RETURNS(x+y); +/// +/// int main() { +/// assert(3 == sum(1, 2)); +/// } +/// +/// +/// Incomplete this +/// --------------- +/// +/// Description +/// ----------- +/// +/// On some non-conformant compilers, such as gcc, the `this` variable cannot +/// be used inside the `BOOST_HOF_RETURNS` macro because it is considered an +/// incomplete type. So the following macros are provided to help workaround +/// the issue. +/// +/// +/// Synopsis +/// -------- +/// +/// // Declares the type of the `this` variable +/// #define BOOST_HOF_RETURNS_CLASS(...) +/// // Used to refer to the `this` variable in the BOOST_HOF_RETURNS macro +/// #define BOOST_HOF_THIS +/// // Used to refer to the const `this` variable in the BOOST_HOF_RETURNS macro +/// #define BOOST_HOF_CONST_THIS +/// +/// +/// Example +/// ------- +/// +/// #include <boost/hof.hpp> +/// #include <cassert> +/// +/// struct add_1 +/// { +/// int a; +/// add_1() : a(1) {} +/// +/// BOOST_HOF_RETURNS_CLASS(add_1); +/// +/// template<class T> +/// auto operator()(T x) const +/// BOOST_HOF_RETURNS(x+BOOST_HOF_CONST_THIS->a); +/// }; +/// +/// int main() { +/// assert(3 == add_1()(2)); +/// } +/// +/// +/// Mangling overloads +/// ------------------ +/// +/// Description +/// ----------- +/// +/// On older compilers some operations done in the expressions cannot be +/// properly mangled. These macros help provide workarounds for these +/// operations on older compilers. +/// +/// +/// Synopsis +/// -------- +/// +/// // Explicitly defines the type for name mangling +/// #define BOOST_HOF_MANGLE_CAST(...) +/// // C cast for name mangling +/// #define BOOST_HOF_RETURNS_C_CAST(...) +/// // Reinterpret cast for name mangling +/// #define BOOST_HOF_RETURNS_REINTERPRET_CAST(...) +/// // Static cast for name mangling +/// #define BOOST_HOF_RETURNS_STATIC_CAST(...) +/// // Construction for name mangling +/// #define BOOST_HOF_RETURNS_CONSTRUCT(...) +/// + + +#include <boost/hof/config.hpp> +#include <utility> +#include <boost/hof/detail/forward.hpp> +#include <boost/hof/detail/noexcept.hpp> + +#define BOOST_HOF_EAT(...) +#define BOOST_HOF_REM(...) __VA_ARGS__ + +#if BOOST_HOF_HAS_COMPLETE_DECLTYPE && BOOST_HOF_HAS_MANGLE_OVERLOAD +#ifdef _MSC_VER +// Since decltype can't be used in noexcept on MSVC, we can't check for noexcept +// move constructors. +#define BOOST_HOF_RETURNS_DEDUCE_NOEXCEPT(...) BOOST_HOF_NOEXCEPT(noexcept(__VA_ARGS__)) +#else +#define BOOST_HOF_RETURNS_DEDUCE_NOEXCEPT(...) BOOST_HOF_NOEXCEPT(noexcept(static_cast<decltype(__VA_ARGS__)>(__VA_ARGS__))) +#endif +#define BOOST_HOF_RETURNS(...) \ +BOOST_HOF_RETURNS_DEDUCE_NOEXCEPT(__VA_ARGS__) \ +-> decltype(__VA_ARGS__) { return __VA_ARGS__; } +#define BOOST_HOF_THIS this +#define BOOST_HOF_CONST_THIS this +#define BOOST_HOF_RETURNS_CLASS(...) \ +void fit_returns_class_check() \ +{ \ + static_assert(std::is_same<__VA_ARGS__*, decltype(this)>::value, \ + "Returns class " #__VA_ARGS__ " type doesn't match"); \ +} + +#define BOOST_HOF_MANGLE_CAST(...) BOOST_HOF_REM + +#define BOOST_HOF_RETURNS_C_CAST(...) (__VA_ARGS__) BOOST_HOF_REM +#define BOOST_HOF_RETURNS_REINTERPRET_CAST(...) reinterpret_cast<__VA_ARGS__> +#define BOOST_HOF_RETURNS_STATIC_CAST(...) static_cast<__VA_ARGS__> +#define BOOST_HOF_RETURNS_CONSTRUCT(...) __VA_ARGS__ +#else +#include <boost/hof/detail/pp.hpp> + +#define BOOST_HOF_RETURNS_RETURN(...) return BOOST_HOF_RETURNS_RETURN_X(BOOST_HOF_PP_WALL(__VA_ARGS__)) +#define BOOST_HOF_RETURNS_RETURN_X(...) __VA_ARGS__ + +#ifdef _MSC_VER +// Since decltype can't be used in noexcept on MSVC, we can't check for noexcept +// move constructors. +#define BOOST_HOF_RETURNS_DEDUCE_NOEXCEPT(...) BOOST_HOF_NOEXCEPT(noexcept(BOOST_HOF_RETURNS_DECLTYPE_CONTEXT(__VA_ARGS__))) +#else +#define BOOST_HOF_RETURNS_DEDUCE_NOEXCEPT(...) BOOST_HOF_NOEXCEPT(noexcept(static_cast<decltype(BOOST_HOF_RETURNS_DECLTYPE_CONTEXT(__VA_ARGS__))>(BOOST_HOF_RETURNS_DECLTYPE_CONTEXT(__VA_ARGS__)))) +#endif + +#define BOOST_HOF_RETURNS_DECLTYPE(...) \ +-> decltype(BOOST_HOF_RETURNS_DECLTYPE_CONTEXT(__VA_ARGS__)) + +#define BOOST_HOF_RETURNS_DECLTYPE_CONTEXT(...) BOOST_HOF_RETURNS_DECLTYPE_CONTEXT_X(BOOST_HOF_PP_WALL(__VA_ARGS__)) +#define BOOST_HOF_RETURNS_DECLTYPE_CONTEXT_X(...) __VA_ARGS__ + +#define BOOST_HOF_RETURNS_THAT(...) BOOST_HOF_PP_IIF(BOOST_HOF_PP_IS_PAREN(BOOST_HOF_RETURNS_DECLTYPE_CONTEXT(())))(\ + (boost::hof::detail::check_this<__VA_ARGS__, decltype(this)>(), this), \ + std::declval<__VA_ARGS__>() \ +) + +#define BOOST_HOF_THIS BOOST_HOF_PP_RAIL(BOOST_HOF_RETURNS_THAT)(fit_this_type) +#define BOOST_HOF_CONST_THIS BOOST_HOF_PP_RAIL(BOOST_HOF_RETURNS_THAT)(fit_const_this_type) + +#define BOOST_HOF_RETURNS_CLASS(...) typedef __VA_ARGS__* fit_this_type; typedef const __VA_ARGS__* fit_const_this_type + +#define BOOST_HOF_RETURNS(...) \ +BOOST_HOF_RETURNS_DEDUCE_NOEXCEPT(__VA_ARGS__) \ +BOOST_HOF_RETURNS_DECLTYPE(__VA_ARGS__) \ +{ BOOST_HOF_RETURNS_RETURN(__VA_ARGS__); } + + +namespace boost { namespace hof { namespace detail { +template<class Assumed, class T> +struct check_this +{ + static_assert(std::is_same<T, Assumed>::value, "Incorret BOOST_HOF_THIS or BOOST_HOF_CONST_THIS used."); +}; + +}}} // namespace boost::hof + +#endif + + +#if BOOST_HOF_HAS_MANGLE_OVERLOAD + +#define BOOST_HOF_MANGLE_CAST(...) BOOST_HOF_REM + +#define BOOST_HOF_RETURNS_C_CAST(...) (__VA_ARGS__) BOOST_HOF_REM +#define BOOST_HOF_RETURNS_REINTERPRET_CAST(...) reinterpret_cast<__VA_ARGS__> +#define BOOST_HOF_RETURNS_STATIC_CAST(...) static_cast<__VA_ARGS__> +#define BOOST_HOF_RETURNS_CONSTRUCT(...) __VA_ARGS__ + +#else + +#define BOOST_HOF_RETURNS_DERAIL_MANGLE_CAST(...) BOOST_HOF_PP_IIF(BOOST_HOF_PP_IS_PAREN(BOOST_HOF_RETURNS_DECLTYPE_CONTEXT(())))(\ + BOOST_HOF_REM, \ + std::declval<__VA_ARGS__>() BOOST_HOF_EAT \ +) +#define BOOST_HOF_MANGLE_CAST BOOST_HOF_PP_RAIL(BOOST_HOF_RETURNS_DERAIL_MANGLE_CAST) + + +#define BOOST_HOF_RETURNS_DERAIL_C_CAST(...) BOOST_HOF_PP_IIF(BOOST_HOF_PP_IS_PAREN(BOOST_HOF_RETURNS_DECLTYPE_CONTEXT(())))(\ + (__VA_ARGS__) BOOST_HOF_REM, \ + std::declval<__VA_ARGS__>() BOOST_HOF_EAT \ +) +#define BOOST_HOF_RETURNS_C_CAST BOOST_HOF_PP_RAIL(BOOST_HOF_RETURNS_DERAIL_C_CAST) + + +#define BOOST_HOF_RETURNS_DERAIL_REINTERPRET_CAST(...) BOOST_HOF_PP_IIF(BOOST_HOF_PP_IS_PAREN(BOOST_HOF_RETURNS_DECLTYPE_CONTEXT(())))(\ + reinterpret_cast<__VA_ARGS__>, \ + std::declval<__VA_ARGS__>() BOOST_HOF_EAT \ +) +#define BOOST_HOF_RETURNS_REINTERPRET_CAST BOOST_HOF_PP_RAIL(BOOST_HOF_RETURNS_DERAIL_REINTERPRET_CAST) + +#define BOOST_HOF_RETURNS_DERAIL_STATIC_CAST(...) BOOST_HOF_PP_IIF(BOOST_HOF_PP_IS_PAREN(BOOST_HOF_RETURNS_DECLTYPE_CONTEXT(())))(\ + static_cast<__VA_ARGS__>, \ + std::declval<__VA_ARGS__>() BOOST_HOF_EAT \ +) +#define BOOST_HOF_RETURNS_STATIC_CAST BOOST_HOF_PP_RAIL(BOOST_HOF_RETURNS_DERAIL_STATIC_CAST) + +#define BOOST_HOF_RETURNS_DERAIL_CONSTRUCT(...) BOOST_HOF_PP_IIF(BOOST_HOF_PP_IS_PAREN(BOOST_HOF_RETURNS_DECLTYPE_CONTEXT(())))(\ + __VA_ARGS__, \ + std::declval<__VA_ARGS__>() BOOST_HOF_EAT \ +) +#define BOOST_HOF_RETURNS_CONSTRUCT BOOST_HOF_PP_RAIL(BOOST_HOF_RETURNS_DERAIL_CONSTRUCT) + +#endif + +#define BOOST_HOF_AUTO_FORWARD(...) BOOST_HOF_RETURNS_STATIC_CAST(decltype(__VA_ARGS__))(__VA_ARGS__) + +#endif diff --git a/boost/hof/reveal.hpp b/boost/hof/reveal.hpp new file mode 100644 index 0000000000..d8972b08cb --- /dev/null +++ b/boost/hof/reveal.hpp @@ -0,0 +1,385 @@ +/*============================================================================= + Copyright (c) 2014 Paul Fultz II + reveal.h + 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_HOF_GUARD_FUNCTION_REVEAL_H +#define BOOST_HOF_GUARD_FUNCTION_REVEAL_H + +/// reveal +/// ====== +/// +/// Description +/// ----------- +/// +/// The `reveal` function adaptor helps shows the error messages that get +/// masked on some compilers. Sometimes an error in a function that causes a +/// substitution failure, will remove the function from valid overloads. On +/// compilers without a backtrace for substitution failure, this will mask the +/// error inside the function. The `reveal` adaptor will expose these error +/// messages while still keeping the function SFINAE-friendly. +/// +/// Sample +/// ------ +/// +/// If we take the `print` example from the quick start guide like this: +/// +/// namespace adl { +/// +/// using std::begin; +/// +/// template<class R> +/// auto adl_begin(R&& r) BOOST_HOF_RETURNS(begin(r)); +/// } +/// +/// BOOST_HOF_STATIC_LAMBDA_FUNCTION(for_each_tuple) = [](const auto& sequence, auto f) BOOST_HOF_RETURNS +/// ( +/// boost::hof::unpack(boost::hof::proj(f))(sequence) +/// ); +/// +/// auto print = boost::hof::fix(boost::hof::first_of( +/// [](auto, const auto& x) -> decltype(std::cout << x, void()) +/// { +/// std::cout << x << std::endl; +/// }, +/// [](auto self, const auto& range) -> decltype(self(*adl::adl_begin(range)), void()) +/// { +/// for(const auto& x:range) self(x); +/// }, +/// [](auto self, const auto& tuple) -> decltype(for_each_tuple(tuple, self), void()) +/// { +/// return for_each_tuple(tuple, self); +/// } +/// )); +/// +/// Which prints numbers and vectors: +/// +/// print(5); +/// +/// std::vector<int> v = { 1, 2, 3, 4 }; +/// print(v); +/// +/// However, if we pass a type that can't be printed, we get an error like +/// this: +/// +/// print.cpp:49:5: error: no matching function for call to object of type 'boost::hof::fix_adaptor<boost::hof::first_of_adaptor<(lambda at print.cpp:29:9), (lambda at print.cpp:33:9), (lambda at print.cpp:37:9)> >' +/// print(foo{}); +/// ^~~~~ +/// fix.hpp:158:5: note: candidate template ignored: substitution failure [with Ts = <foo>]: no matching function for call to object of type 'const boost::hof::first_of_adaptor<(lambda at +/// print.cpp:29:9), (lambda at print.cpp:33:9), (lambda at print.cpp:37:9)>' +/// operator()(Ts&&... xs) const BOOST_HOF_SFINAE_RETURNS +/// +/// Which is short and gives very little information why it can't be called. +/// It doesn't even show the overloads that were try. However, using the +/// `reveal` adaptor we can get more info about the error like this: +/// +/// print.cpp:49:5: error: no matching function for call to object of type 'boost::hof::reveal_adaptor<boost::hof::fix_adaptor<boost::hof::first_of_adaptor<(lambda at print.cpp:29:9), (lambda at print.cpp:33:9), +/// (lambda at print.cpp:37:9)> >, boost::hof::fix_adaptor<boost::hof::first_of_adaptor<(lambda at print.cpp:29:9), (lambda at print.cpp:33:9), (lambda at print.cpp:37:9)> > >' +/// boost::hof::reveal(print)(foo{}); +/// ^~~~~~~~~~~~~~~~~~ +/// reveal.hpp:149:20: note: candidate template ignored: substitution failure [with Ts = <foo>, $1 = void]: no matching function for call to object of type '(lambda at print.cpp:29:9)' +/// constexpr auto operator()(Ts&&... xs) const +/// ^ +/// reveal.hpp:149:20: note: candidate template ignored: substitution failure [with Ts = <foo>, $1 = void]: no matching function for call to object of type '(lambda at print.cpp:33:9)' +/// constexpr auto operator()(Ts&&... xs) const +/// ^ +/// reveal.hpp:149:20: note: candidate template ignored: substitution failure [with Ts = <foo>, $1 = void]: no matching function for call to object of type '(lambda at print.cpp:37:9)' +/// constexpr auto operator()(Ts&&... xs) const +/// ^ +/// fix.hpp:158:5: note: candidate template ignored: substitution failure [with Ts = <foo>]: no matching function for call to object of type 'const boost::hof::first_of_adaptor<(lambda at +/// print.cpp:29:9), (lambda at print.cpp:33:9), (lambda at print.cpp:37:9)>' +/// operator()(Ts&&... xs) const BOOST_HOF_SFINAE_RETURNS +/// +/// So now the error has a note for each of the lambda overloads it tried. Of +/// course this can be improved even further by providing custom reporting of +/// failures. +/// +/// Synopsis +/// -------- +/// +/// template<class F> +/// reveal_adaptor<F> reveal(F f); +/// +/// Requirements +/// ------------ +/// +/// F must be: +/// +/// * [ConstInvocable](ConstInvocable) +/// * MoveConstructible +/// +/// Reporting Failures +/// ------------------ +/// +/// By default, `reveal` reports the substitution failure by trying to call +/// the function. However, more detail expressions can be be reported from a +/// template alias by using `as_failure`. This is done by defining a nested +/// `failure` struct in the function object and then inheriting from +/// `as_failure`. Also multiple failures can be reported by using +/// `with_failures`. +/// +/// Synopsis +/// -------- +/// +/// // Report failure by instantiating the Template +/// template<template<class...> class Template> +/// struct as_failure; +/// +/// // Report multiple falures +/// template<class... Failures> +/// struct with_failures; +/// +/// // Report the failure for each function +/// template<class... Fs> +/// struct failure_for; +/// +/// // Get the failure of a function +/// template<class F> +/// struct get_failure; +/// +/// Example +/// ------- +/// +/// #include <boost/hof.hpp> +/// #include <cassert> +/// +/// struct sum_f +/// { +/// template<class T, class U> +/// using sum_failure = decltype(std::declval<T>()+std::declval<U>()); +/// +/// struct failure +/// : boost::hof::as_failure<sum_failure> +/// {}; +/// +/// template<class T, class U> +/// auto operator()(T x, U y) const BOOST_HOF_RETURNS(x+y); +/// }; +/// +/// int main() { +/// assert(sum_f()(1, 2) == 3); +/// } +/// + +#include <boost/hof/always.hpp> +#include <boost/hof/returns.hpp> +#include <boost/hof/is_invocable.hpp> +#include <boost/hof/identity.hpp> +#include <boost/hof/detail/move.hpp> +#include <boost/hof/detail/callable_base.hpp> +#include <boost/hof/detail/delegate.hpp> +#include <boost/hof/detail/holder.hpp> +#include <boost/hof/detail/join.hpp> +#include <boost/hof/detail/make.hpp> +#include <boost/hof/detail/static_const_var.hpp> +#include <boost/hof/detail/using.hpp> + +#ifndef BOOST_HOF_REVEAL_USE_TEMPLATE_ALIAS +#ifdef __clang__ +#define BOOST_HOF_REVEAL_USE_TEMPLATE_ALIAS 1 +#else +#define BOOST_HOF_REVEAL_USE_TEMPLATE_ALIAS 0 +#endif +#endif + +namespace boost { namespace hof { + +namespace detail { + + +template<class T, class=void> +struct has_failure +: std::false_type +{}; + +template<class T> +struct has_failure<T, typename holder< + typename T::failure +>::type> +: std::true_type +{}; + +struct identity_failure +{ + template<class T> + T operator()(T&& x); + + template<class T> + static T&& val(); +#if BOOST_HOF_REVEAL_USE_TEMPLATE_ALIAS + template<template<class...> class Template, class... Ts> + BOOST_HOF_USING(defer, Template<Ts...>); +#else + template<template<class...> class Template, class... Ts> + static auto defer(Ts&&...) -> Template<Ts...>; +#endif + +}; + +} + +template<class F, class=void> +struct get_failure +{ + template<class... Ts> + struct of + { +#if BOOST_HOF_REVEAL_USE_TEMPLATE_ALIAS + template<class Id> + using apply = decltype(Id()(std::declval<F>())(std::declval<Ts>()...)); +#else + template<class Id> + static auto apply(Id id) -> decltype(id(std::declval<F>())(std::declval<Ts>()...)); +#endif + }; +}; + +template<class F> +struct get_failure<F, typename std::enable_if<detail::has_failure<F>::value>::type> +: F::failure +{}; + +template<template<class...> class Template> +struct as_failure +{ + template<class... Ts> + struct of + { +#if BOOST_HOF_REVEAL_USE_TEMPLATE_ALIAS + template<class Id> + using apply = typename Id::template defer<Template, Ts...>; +#else + template<class Id> + static auto apply(Id) -> decltype(Id::template defer<Template, Ts...>()); +#endif + }; +}; + +namespace detail { +template<class Failure, class... Ts> +BOOST_HOF_USING_TYPENAME(apply_failure, Failure::template of<Ts...>); + +template<class F, class Failure> +struct reveal_failure +{ + // Add default constructor to make clang 3.4 happy + constexpr reveal_failure() + {} + // This is just a placeholder to produce a note in the compiler, it is + // never called + template< + class... Ts, + class=typename std::enable_if<(!is_invocable<F, Ts...>::value)>::type + > + constexpr auto operator()(Ts&&... xs) const +#if BOOST_HOF_REVEAL_USE_TEMPLATE_ALIAS + -> typename apply_failure<Failure, Ts...>::template apply<boost::hof::detail::identity_failure>; +#else + -> decltype(apply_failure<Failure, Ts...>::apply(boost::hof::detail::identity_failure())); +#endif +}; + +template<class F, class Failure=get_failure<F>, class=void> +struct traverse_failure +: reveal_failure<F, Failure> +{ + constexpr traverse_failure() + {} +}; + +template<class F, class Failure> +struct traverse_failure<F, Failure, typename holder< + typename Failure::children +>::type> +: Failure::children::template overloads<F> +{ + constexpr traverse_failure() + {} +}; + +template<class Failure, class Transform, class=void> +struct transform_failures +: Transform::template apply<Failure> +{}; + +template<class Failure, class Transform> +struct transform_failures<Failure, Transform, typename holder< + typename Failure::children +>::type> +: Failure::children::template transform<Transform> +{}; + +} + +template<class Failure, class... Failures> +struct failures; + +template<class... Fs> +struct with_failures +{ + typedef BOOST_HOF_JOIN(failures, Fs...) children; +}; + +template<class Failure, class... Failures> +struct failures +{ + template<class Transform> + BOOST_HOF_USING(transform, with_failures<detail::transform_failures<Failure, Transform>, detail::transform_failures<Failures, Transform>...>); + + template<class F, class FailureBase=BOOST_HOF_JOIN(failures, Failures...)> + struct overloads + : detail::traverse_failure<F, Failure>, FailureBase::template overloads<F> + { + constexpr overloads() + {} + using detail::traverse_failure<F, Failure>::operator(); + using FailureBase::template overloads<F>::operator(); + }; +}; + +template<class Failure> +struct failures<Failure> +{ + template<class Transform> + BOOST_HOF_USING(transform, with_failures<detail::transform_failures<Failure, Transform>>); + + template<class F> + BOOST_HOF_USING(overloads, detail::traverse_failure<F, Failure>); +}; + +template<class Transform, class... Fs> +struct failure_map +: with_failures<detail::transform_failures<get_failure<Fs>, Transform>...> +{}; + +template<class... Fs> +struct failure_for +: with_failures<get_failure<Fs>...> +{}; + +template<class F, class Base=detail::callable_base<F>> +struct reveal_adaptor +: detail::traverse_failure<Base>, Base +{ + typedef reveal_adaptor fit_rewritable1_tag; + using detail::traverse_failure<Base>::operator(); + using Base::operator(); + + BOOST_HOF_INHERIT_CONSTRUCTOR(reveal_adaptor, Base); +}; +// Avoid double reveals, it causes problem on gcc 4.6 +template<class F> +struct reveal_adaptor<reveal_adaptor<F>> +: reveal_adaptor<F> +{ + typedef reveal_adaptor fit_rewritable1_tag; + BOOST_HOF_INHERIT_CONSTRUCTOR(reveal_adaptor, reveal_adaptor<F>); +}; + +BOOST_HOF_DECLARE_STATIC_VAR(reveal, detail::make<reveal_adaptor>); + +}} // namespace boost::hof + +#endif diff --git a/boost/hof/reverse_fold.hpp b/boost/hof/reverse_fold.hpp new file mode 100644 index 0000000000..771cb95c41 --- /dev/null +++ b/boost/hof/reverse_fold.hpp @@ -0,0 +1,173 @@ +/*============================================================================= + Copyright (c) 2015 Paul Fultz II + reverse_fold.h + 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_HOF_GUARD_REVERSE_FOLD_H +#define BOOST_HOF_GUARD_REVERSE_FOLD_H + +/// reverse_fold +/// ======== +/// +/// Description +/// ----------- +/// +/// The `reverse_fold` function adaptor uses a binary function to apply a +/// reverse [fold] +/// (https://en.wikipedia.org/wiki/Fold_%28higher-order_function%29)(ie right +/// fold in functional programming terms) operation to the arguments passed to +/// the function. Additionally, an optional initial state can be provided, +/// otherwise the first argument is used as the initial state. +/// +/// The arguments to the binary function, take first the state and then the +/// argument. +/// +/// Synopsis +/// -------- +/// +/// template<class F, class State> +/// constexpr reverse_fold_adaptor<F, State> reverse_fold(F f, State s); +/// +/// template<class F> +/// constexpr reverse_fold_adaptor<F> reverse_fold(F f); +/// +/// Semantics +/// --------- +/// +/// assert(reverse_fold(f, z)() == z); +/// assert(reverse_fold(f, z)(x, xs...) == f(reverse_fold(f, z)(xs...), x)); +/// assert(reverse_fold(f)(x) == x); +/// assert(reverse_fold(f)(x, xs...) == f(reverse_fold(f)(xs...), x)); +/// +/// Requirements +/// ------------ +/// +/// State must be: +/// +/// * CopyConstructible +/// +/// F must be: +/// +/// * [BinaryInvocable](BinaryInvocable) +/// * MoveConstructible +/// +/// Example +/// ------- +/// +/// #include <boost/hof.hpp> +/// #include <cassert> +/// +/// struct max_f +/// { +/// template<class T, class U> +/// constexpr T operator()(T x, U y) const +/// { +/// return x > y ? x : y; +/// } +/// }; +/// +/// int main() { +/// assert(boost::hof::reverse_fold(max_f())(2, 3, 4, 5) == 5); +/// } +/// +/// References +/// ---------- +/// +/// * [Projections](Projections) +/// * [Variadic print](<Variadic print>) +/// + +#include <boost/hof/detail/callable_base.hpp> +#include <boost/hof/detail/delegate.hpp> +#include <boost/hof/detail/compressed_pair.hpp> +#include <boost/hof/detail/move.hpp> +#include <boost/hof/detail/make.hpp> +#include <boost/hof/detail/static_const_var.hpp> + +namespace boost { namespace hof { namespace detail { + +struct v_reverse_fold +{ + BOOST_HOF_RETURNS_CLASS(v_reverse_fold); + template<class F, class State, class T, class... Ts> + constexpr BOOST_HOF_SFINAE_MANUAL_RESULT(const F&, result_of<const v_reverse_fold&, id_<const F&>, id_<State>, id_<Ts>...>, id_<T>) + operator()(const F& f, State&& state, T&& x, Ts&&... xs) const BOOST_HOF_SFINAE_MANUAL_RETURNS + ( + f((*BOOST_HOF_CONST_THIS)(f, BOOST_HOF_FORWARD(State)(state), BOOST_HOF_FORWARD(Ts)(xs)...), BOOST_HOF_FORWARD(T)(x)) + ); + + template<class F, class State> + constexpr State operator()(const F&, State&& state) const noexcept + { + return BOOST_HOF_FORWARD(State)(state); + } +}; + +} + +template<class F, class State=void> +struct reverse_fold_adaptor +: detail::compressed_pair<detail::callable_base<F>, State> +{ + typedef detail::compressed_pair<detail::callable_base<F>, State> base_type; + BOOST_HOF_INHERIT_CONSTRUCTOR(reverse_fold_adaptor, base_type) + + template<class... Ts> + constexpr const detail::callable_base<F>& base_function(Ts&&... xs) const noexcept + { + return this->first(xs...); + } + + template<class... Ts> + constexpr State get_state(Ts&&... xs) const noexcept + { + return this->second(xs...); + } + + BOOST_HOF_RETURNS_CLASS(reverse_fold_adaptor); + + template<class... Ts> + constexpr BOOST_HOF_SFINAE_RESULT(detail::v_reverse_fold, id_<const detail::callable_base<F>&>, id_<State>, id_<Ts>...) + operator()(Ts&&... xs) const BOOST_HOF_SFINAE_RETURNS + ( + detail::v_reverse_fold()( + BOOST_HOF_MANGLE_CAST(const detail::callable_base<F>&)(BOOST_HOF_CONST_THIS->base_function(xs...)), + BOOST_HOF_MANGLE_CAST(State)(BOOST_HOF_CONST_THIS->get_state(xs...)), + BOOST_HOF_FORWARD(Ts)(xs)... + ) + ) +}; + + +template<class F> +struct reverse_fold_adaptor<F, void> +: detail::callable_base<F> +{ + BOOST_HOF_INHERIT_CONSTRUCTOR(reverse_fold_adaptor, detail::callable_base<F>) + + template<class... Ts> + constexpr const detail::callable_base<F>& base_function(Ts&&... xs) const noexcept + { + return boost::hof::always_ref(*this)(xs...); + } + + BOOST_HOF_RETURNS_CLASS(reverse_fold_adaptor); + + template<class... Ts> + constexpr BOOST_HOF_SFINAE_RESULT(detail::v_reverse_fold, id_<const detail::callable_base<F>&>, id_<Ts>...) + operator()(Ts&&... xs) const BOOST_HOF_SFINAE_RETURNS + ( + detail::v_reverse_fold()( + BOOST_HOF_MANGLE_CAST(const detail::callable_base<F>&)(BOOST_HOF_CONST_THIS->base_function(xs...)), + BOOST_HOF_FORWARD(Ts)(xs)... + ) + ) +}; + +BOOST_HOF_DECLARE_STATIC_VAR(reverse_fold, detail::make<reverse_fold_adaptor>); + +}} // namespace boost::hof + +#endif diff --git a/boost/hof/rotate.hpp b/boost/hof/rotate.hpp new file mode 100644 index 0000000000..b288a06c47 --- /dev/null +++ b/boost/hof/rotate.hpp @@ -0,0 +1,101 @@ +/*============================================================================= + Copyright (c) 2015 Paul Fultz II + rotate.h + 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_HOF_GUARD_ROTATE_H +#define BOOST_HOF_GUARD_ROTATE_H + +/// rotate +/// ==== +/// +/// Description +/// ----------- +/// +/// The `rotate` function adaptor moves the first parameter to the last +/// parameter. +/// +/// Synopsis +/// -------- +/// +/// template<class F> +/// rotate_adaptor<F> rotate(F f); +/// +/// Semantics +/// --------- +/// +/// assert(rotate(f)(x, xs...) == f(xs..., x)); +/// +/// Requirements +/// ------------ +/// +/// F must be: +/// +/// * [ConstInvocable](ConstInvocable) +/// * MoveConstructible +/// +/// Example +/// ------- +/// +/// #include <boost/hof.hpp> +/// #include <cassert> +/// +/// int main() { +/// int r = boost::hof::rotate(boost::hof::_ - boost::hof::_)(2, 5); +/// assert(r == 3); +/// } +/// + +#include <boost/hof/detail/result_of.hpp> +#include <boost/hof/reveal.hpp> +#include <boost/hof/detail/make.hpp> +#include <boost/hof/detail/static_const_var.hpp> + +namespace boost { namespace hof { + +template<class F> +struct rotate_adaptor : detail::callable_base<F> +{ + typedef rotate_adaptor fit_rewritable1_tag; + BOOST_HOF_INHERIT_CONSTRUCTOR(rotate_adaptor, detail::callable_base<F>); + + template<class... Ts> + constexpr const detail::callable_base<F>& base_function(Ts&&... xs) const noexcept + { + return boost::hof::always_ref(*this)(xs...); + } + + struct rotate_failure + { + template<class Failure> + struct apply + { + template<class T, class... Ts> + struct of + : Failure::template of<Ts..., T> + {}; + }; + }; + + struct failure + : failure_map<rotate_failure, detail::callable_base<F>> + {}; + + BOOST_HOF_RETURNS_CLASS(rotate_adaptor); + + template<class T, class... Ts> + constexpr BOOST_HOF_SFINAE_RESULT(const detail::callable_base<F>&, id_<Ts>..., id_<T>) + operator()(T&& x, Ts&&... xs) const BOOST_HOF_SFINAE_RETURNS + ( + (BOOST_HOF_MANGLE_CAST(const detail::callable_base<F>&)(BOOST_HOF_CONST_THIS->base_function(xs...))) + (BOOST_HOF_FORWARD(Ts)(xs)..., BOOST_HOF_FORWARD(T)(x)) + ); +}; + +BOOST_HOF_DECLARE_STATIC_VAR(rotate, detail::make<rotate_adaptor>); + +}} // namespace boost::hof + +#endif diff --git a/boost/hof/static.hpp b/boost/hof/static.hpp new file mode 100644 index 0000000000..2539d93de0 --- /dev/null +++ b/boost/hof/static.hpp @@ -0,0 +1,97 @@ +/*============================================================================= + Copyright (c) 2014 Paul Fultz II + static.h + 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_HOF_GUARD_FUNCTION_STATIC_H +#define BOOST_HOF_GUARD_FUNCTION_STATIC_H + +/// static +/// ====== +/// +/// Description +/// ----------- +/// +/// The `static_` adaptor is a static function adaptor that allows any +/// default-constructible function object to be static-initialized. Functions +/// initialized by `static_` cannot be used in `constexpr` functions. If the +/// function needs to be statically initialized and called in a `constexpr` +/// context, then a `constexpr` constructor needs to be used rather than +/// `static_`. +/// +/// Synopsis +/// -------- +/// +/// template<class F> +/// class static_; +/// +/// Requirements +/// ------------ +/// +/// F must be: +/// +/// * [ConstFunctionObject](ConstFunctionObject) +/// * DefaultConstructible +/// +/// Example +/// ------- +/// +/// #include <boost/hof.hpp> +/// #include <cassert> +/// using namespace boost::hof; +/// +/// // In C++ this class can't be static-initialized, because of the non- +/// // trivial default constructor. +/// struct times_function +/// { +/// double factor; +/// times_function() : factor(2) +/// {} +/// template<class T> +/// T operator()(T x) const +/// { +/// return x*factor; +/// } +/// }; +/// +/// static constexpr static_<times_function> times2 = {}; +/// +/// int main() { +/// assert(6 == times2(3)); +/// } +/// + +#include <boost/hof/detail/result_of.hpp> +#include <boost/hof/reveal.hpp> + +namespace boost { namespace hof { + +template<class F> +struct static_ +{ + + struct failure + : failure_for<F> + {}; + + const F& base_function() const + BOOST_HOF_NOEXCEPT_CONSTRUCTIBLE(F) + { + static F f; + return f; + } + + BOOST_HOF_RETURNS_CLASS(static_); + + template<class... Ts> + BOOST_HOF_SFINAE_RESULT(F, id_<Ts>...) + operator()(Ts && ... xs) const + BOOST_HOF_SFINAE_RETURNS(BOOST_HOF_CONST_THIS->base_function()(BOOST_HOF_FORWARD(Ts)(xs)...)); +}; + + +}} // namespace boost::hof + +#endif diff --git a/boost/hof/tap.hpp b/boost/hof/tap.hpp new file mode 100644 index 0000000000..ab265c29ae --- /dev/null +++ b/boost/hof/tap.hpp @@ -0,0 +1,83 @@ +/*============================================================================= + Copyright (c) 2014 Paul Fultz II + tap.h + 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_HOF_GUARD_FUNCTION_TAP_H +#define BOOST_HOF_GUARD_FUNCTION_TAP_H + +/// tap +/// === +/// +/// Description +/// ----------- +/// +/// The `tap` function invokes a function on the first argument passed in and +/// then returns the first argument. This is useful in a chain of pipable +/// function to perform operations on intermediate results. As a result, this +/// function is [`pipable`](/include/boost/hof/pipable). +/// +/// Synopsis +/// -------- +/// +/// template<class T, class F> +/// pipable constexpr T tap(T&& x, const F& f); +/// +/// Requirements +/// ------------ +/// +/// F must be: +/// +/// * [UnaryInvocable](UnaryInvocable) +/// +/// Example +/// ------- +/// +/// #include <boost/hof.hpp> +/// #include <cassert> +/// #include <iostream> +/// using namespace boost::hof; +/// +/// struct sum_f +/// { +/// template<class T, class U> +/// T operator()(T x, U y) const +/// { +/// return x+y; +/// } +/// }; +/// +/// const pipable_adaptor<sum_f> sum = {}; +/// int main() { +/// // Prints 3 +/// int r = 1 | sum(2) | tap([](int i) { std::cout << i; }) | sum(2); +/// assert(r == 5); +/// } +/// + +#include <boost/hof/pipable.hpp> +#include <boost/hof/apply.hpp> +#include <boost/hof/detail/static_const_var.hpp> + +namespace boost { namespace hof { namespace detail { + +struct tap_f +{ + template<class T, class F> + constexpr T operator()(T&& x, const F& f) const + BOOST_HOF_RETURNS_DEDUCE_NOEXCEPT((boost::hof::apply(f, x), BOOST_HOF_FORWARD(T)(x))) + { + return boost::hof::apply(f, x), BOOST_HOF_FORWARD(T)(x); + } +}; + +} + +BOOST_HOF_DECLARE_STATIC_VAR(tap, pipable_adaptor<detail::tap_f>); + + +}} // namespace boost::hof + +#endif diff --git a/boost/hof/unpack.hpp b/boost/hof/unpack.hpp new file mode 100644 index 0000000000..cfbec80e82 --- /dev/null +++ b/boost/hof/unpack.hpp @@ -0,0 +1,181 @@ +/*============================================================================= + Copyright (c) 2015 Paul Fultz II + unpack.h + 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_HOF_GUARD_UNPACK_H +#define BOOST_HOF_GUARD_UNPACK_H + +/// unpack +/// ====== +/// +/// Description +/// ----------- +/// +/// The `unpack` function adaptor takes a sequence and uses the elements of +/// the sequence for the arguments to the function. Multiple sequences can be +/// passed to the function. All elements from each sequence will be passed +/// into the function. +/// +/// +/// Synopsis +/// -------- +/// +/// template<class F> +/// unpack_adaptor<F> unpack(F f); +/// +/// Requirements +/// ------------ +/// +/// F must be: +/// +/// * [ConstInvocable](ConstInvocable) +/// * MoveConstructible +/// +/// Example +/// ------- +/// +/// #include <boost/hof.hpp> +/// #include <cassert> +/// using namespace boost::hof; +/// +/// struct sum +/// { +/// template<class T, class U> +/// T operator()(T x, U y) const +/// { +/// return x+y; +/// } +/// }; +/// +/// int main() { +/// int r = unpack(sum())(std::make_tuple(3,2)); +/// assert(r == 5); +/// } +/// +/// References +/// ---------- +/// +/// * [std::apply](http://en.cppreference.com/w/cpp/utility/apply) - C++17 function to unpack a tuple +/// * [`unpack_sequence`](unpack_sequence) +/// + +#include <boost/hof/unpack_sequence.hpp> +#include <boost/hof/is_unpackable.hpp> +#include <boost/hof/detail/seq.hpp> +#include <boost/hof/capture.hpp> +#include <boost/hof/always.hpp> +#include <boost/hof/reveal.hpp> +#include <boost/hof/detail/and.hpp> +#include <boost/hof/detail/delegate.hpp> +#include <boost/hof/detail/holder.hpp> +#include <boost/hof/detail/move.hpp> +#include <boost/hof/detail/make.hpp> +#include <boost/hof/detail/static_const_var.hpp> + +namespace boost { namespace hof { + +namespace detail { + +template<class F, class Sequence> +constexpr auto unpack_simple(F&& f, Sequence&& s) BOOST_HOF_RETURNS +( + detail::unpack_impl(BOOST_HOF_FORWARD(F)(f), BOOST_HOF_FORWARD(Sequence)(s)) +) + +template<class F, class... Sequences> +constexpr auto unpack_join(F&& f, Sequences&&... s) BOOST_HOF_RETURNS +( + boost::hof::pack_join(unpack_simple(boost::hof::pack_forward, BOOST_HOF_FORWARD(Sequences)(s))...)(BOOST_HOF_FORWARD(F)(f)) +); + +} + +template<class F> +struct unpack_adaptor : detail::callable_base<F> +{ + typedef unpack_adaptor fit_rewritable1_tag; + BOOST_HOF_INHERIT_CONSTRUCTOR(unpack_adaptor, detail::callable_base<F>); + + template<class... Ts> + constexpr const detail::callable_base<F>& base_function(Ts&&... xs) const noexcept + { + return boost::hof::always_ref(*this)(xs...); + } + + struct unpack_failure + { + template<class Failure> + struct apply + { + struct deducer + { + template<class... Ts> + typename Failure::template of<Ts...> operator()(Ts&&...) const; + }; + + template<class T, class=typename std::enable_if<( + is_unpackable<T>::value + )>::type> + static auto deduce(T&& x) + BOOST_HOF_RETURNS + ( + boost::hof::detail::unpack_simple(deducer(), BOOST_HOF_FORWARD(T)(x)) + ); + + template<class T, class... Ts, class=typename std::enable_if<( + is_unpackable<T>::value && BOOST_HOF_AND_UNPACK(is_unpackable<Ts>::value) + )>::type> + static auto deduce(T&& x, Ts&&... xs) BOOST_HOF_RETURNS + ( + boost::hof::detail::unpack_join(deducer(), BOOST_HOF_FORWARD(T)(x), BOOST_HOF_FORWARD(Ts)(xs)...) + ); +#ifdef _MSC_VER + template<class... Ts> + struct nop_failure; + template<class... Ts, class=typename std::enable_if<( + !BOOST_HOF_AND_UNPACK(is_unpackable<Ts>::value) + )>::type> + static as_failure<nop_failure> deduce(Ts&&... xs); +#endif + template<class... Ts> + struct of +#if (defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ < 7) || defined (_MSC_VER) + : std::enable_if<true, decltype(apply::deduce(std::declval<Ts>()...))>::type +#else + : decltype(apply::deduce(std::declval<Ts>()...)) +#endif + {}; + }; + }; + + struct failure + : failure_map<unpack_failure, detail::callable_base<F>> + {}; + + BOOST_HOF_RETURNS_CLASS(unpack_adaptor); + template<class T, class=typename std::enable_if<( + is_unpackable<T>::value + )>::type> + constexpr auto operator()(T&& x) const + BOOST_HOF_RETURNS + ( + boost::hof::detail::unpack_simple(BOOST_HOF_MANGLE_CAST(const detail::callable_base<F>&)(BOOST_HOF_CONST_THIS->base_function(x)), BOOST_HOF_FORWARD(T)(x)) + ); + + template<class T, class... Ts, class=typename std::enable_if<( + is_unpackable<T>::value && BOOST_HOF_AND_UNPACK(is_unpackable<Ts>::value) + )>::type> + constexpr auto operator()(T&& x, Ts&&... xs) const BOOST_HOF_RETURNS + ( + boost::hof::detail::unpack_join(BOOST_HOF_MANGLE_CAST(const detail::callable_base<F>&)(BOOST_HOF_CONST_THIS->base_function(x)), BOOST_HOF_FORWARD(T)(x), BOOST_HOF_FORWARD(Ts)(xs)...) + ); +}; + +BOOST_HOF_DECLARE_STATIC_VAR(unpack, detail::make<unpack_adaptor>); + +}} // namespace boost::hof + +#endif diff --git a/boost/hof/unpack_sequence.hpp b/boost/hof/unpack_sequence.hpp new file mode 100644 index 0000000000..1e6a439f21 --- /dev/null +++ b/boost/hof/unpack_sequence.hpp @@ -0,0 +1,71 @@ +/*============================================================================= + Copyright (c) 2016 Paul Fultz II + unpack_sequence.hpp + 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_HOF_GUARD_UNPACK_SEQUENCE_HPP +#define BOOST_HOF_GUARD_UNPACK_SEQUENCE_HPP + +/// unpack_sequence +/// =============== +/// +/// How to unpack a sequence can be defined by specializing `unpack_sequence`. +/// By default, `std::tuple` is already specialized. To implement this, one +/// needs to provide a static `apply` function which will unpack the sequence +/// to the parameters of the function. +/// +/// Synopsis +/// -------- +/// +/// template<class Sequence, class=void> +/// struct unpack_sequence; +/// +/// Example +/// ------- +/// +/// #include <boost/hof.hpp> +/// #include <cassert> +/// +/// struct my_sequence +/// { +/// int x; +/// int y; +/// }; +/// +/// namespace boost { namespace hof { +/// template<> +/// struct unpack_sequence<my_sequence> +/// { +/// template<class F, class Sequence> +/// constexpr static auto apply(F&& f, Sequence&& s) BOOST_HOF_RETURNS +/// ( +/// f(s.x, s.y) +/// ); +/// }; +/// }} // namespace boost::hof +/// +/// int main() { +/// } +/// +/// See Also +/// -------- +/// +/// * [unpack](unpack) +/// * [is_unpackable](is_unpackable) +/// + +#include <boost/hof/config.hpp> + +namespace boost { namespace hof { + +template<class Sequence, class=void> +struct unpack_sequence +{ + typedef void not_unpackable; +}; + +}} // namespace boost::hof + +#endif diff --git a/boost/hof/version.hpp b/boost/hof/version.hpp new file mode 100644 index 0000000000..824104c62b --- /dev/null +++ b/boost/hof/version.hpp @@ -0,0 +1,16 @@ +/*============================================================================= + Copyright (c) 2016 Paul Fultz II + version.hpp + 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_HOF_GUARD_VERSION_HPP +#define BOOST_HOF_GUARD_VERSION_HPP + +#define BOOST_HOF_VERSION_MAJOR 0 +#define BOOST_HOF_VERSION_MINOR 6 +#define BOOST_HOF_VERSION_PATCH 0 +#define BOOST_HOF_VERSION (((BOOST_HOF_VERSION_MAJOR) << 24) + ((BOOST_HOF_VERSION_MINOR) << 16) + (BOOST_HOF_VERSION_PATCH)) + +#endif |