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 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
|
// Copyright 2015, Tobias Hermann and the FunctionalPlus contributors.
// https://github.com/Dobiasd/FunctionalPlus
// 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)
#pragma once
#include <tuple>
#include <utility>
#include <fplus/internal/invoke.hpp>
namespace fplus
{
namespace internal
{
// source: https://codereview.stackexchange.com/a/63893
// note: the code in the link above is called with the arguments in reverse order
template <typename... Fs>
class compose_impl
{
static constexpr std::size_t size = sizeof...(Fs);
static_assert(size > 1,
"Invalid number of functions to compose, minimum is two.");
public:
compose_impl(Fs&&... fs) : _functionTuple(std::forward<Fs>(fs)...)
{
}
template <typename... Ts>
auto operator()(Ts&&... ts) const
{
return _apply(std::integral_constant<std::size_t, 0>{},
std::forward<Ts>(ts)...);
}
private:
template <std::size_t N, typename... Ts>
auto _apply(std::integral_constant<std::size_t, N>, Ts&&... ts) const
{
return _apply(std::integral_constant<std::size_t, N + 1>{},
std::get<N>(_functionTuple)(std::forward<Ts>(ts)...));
}
template <typename... Ts>
auto _apply(std::integral_constant<std::size_t, size - 1>, Ts&&... ts) const
{
return internal::invoke(std::get<size - 1>(_functionTuple),
std::forward<Ts>(ts)...);
}
std::tuple<Fs...> _functionTuple;
};
// Is BinaryLift really correct?
template <typename Tuple, typename BinaryLift>
auto compose_binary_lift_impl(std::integral_constant<std::size_t, 1>,
const Tuple& tup,
const BinaryLift& lifter)
{
return lifter(std::get<0>(tup), std::get<1>(tup));
}
template <std::size_t N, typename Tuple, typename BinaryLift>
auto compose_binary_lift_impl(std::integral_constant<std::size_t, N>,
const Tuple& tup,
const BinaryLift& lifter)
{
return lifter(
compose_binary_lift_impl(
std::integral_constant<std::size_t, N - 1>{}, tup, lifter),
std::get<N>(tup));
}
template <typename BinaryLift, typename... Callables>
auto compose_binary_lift(const BinaryLift& lifter, Callables&&... args)
{
static_assert(sizeof...(Callables) > 1,
"Invalid number of functions to compose, minimum is two.");
const auto tup = std::forward_as_tuple(std::forward<Callables>(args)...);
return compose_binary_lift_impl(
std::integral_constant<std::size_t, sizeof...(Callables) - 1>{},
tup,
lifter);
}
// concentrate asserts in this method. Lambda is provided by the library.
template <typename Lambda, typename F, typename G>
auto logical_binary_op(Lambda op, F f, G g)
{
// Perfect-forwarding might move twice, if we add a requirement on F and G,
// that might not be an issue.
return [op, f, g](auto x) {
internal::trigger_static_asserts<internal::unary_function_tag,
F,
decltype(x)>();
internal::trigger_static_asserts<internal::unary_function_tag,
G,
decltype(x)>();
using FRes = std::decay_t<internal::invoke_result_t<F, decltype(x)>>;
using GRes = std::decay_t<internal::invoke_result_t<G, decltype(x)>>;
static_assert(std::is_same<FRes, bool>::value, "Must return bool.");
static_assert(std::is_same<GRes, bool>::value, "Must return bool.");
return op(f, g, x);
};
}
}
}
|